Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

735 lines
18 KiB

  1. /*++
  2. Copyright (c) 1990,91 Microsoft Corporation
  3. Module Name:
  4. RpcServ.c
  5. Abstract:
  6. This file contains commonly used server-side RPC functions,
  7. such as starting and stoping RPC servers.
  8. Author:
  9. Dan Lafferty danl 09-May-1991
  10. Environment:
  11. User Mode - Win32
  12. Revision History:
  13. 09-May-1991 Danl
  14. Created
  15. 03-July-1991 JimK
  16. Copied from a net-specific file.
  17. 18-Feb-1992 Danl
  18. Added support for multiple endpoints & interfaces per server.
  19. 10-Nov-1993 Danl
  20. Wait for RPC calls to complete before returning from
  21. RpcServerUnregisterIf. Also, do a WaitServerListen after
  22. calling StopServerListen (when the last server shuts down).
  23. Now this is similar to RpcServer functions in netlib.
  24. 29-Jun-1995 RichardW
  25. Read an alternative ACL from a key in the registry, if one exists.
  26. This ACL is used to protect the named pipe.
  27. --*/
  28. //
  29. // INCLUDES
  30. //
  31. // These must be included first:
  32. #include <nt.h> // DbgPrint
  33. #include <ntrtl.h> // DbgPrint
  34. #include <windef.h> // win32 typedefs
  35. #include <rpc.h> // rpc prototypes
  36. #include <ntrpcp.h>
  37. #include <nturtl.h> // needed for winbase.h
  38. #include <winbase.h> // LocalAlloc
  39. // These may be included in any order:
  40. #include <stdlib.h> // for wcscpy wcscat
  41. #include <tstr.h> // WCSSIZE
  42. #define NT_PIPE_PREFIX_W L"\\PIPE\\"
  43. #define NT_PIPE_SD_PREFIX_W L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\SecurePipeServers\\"
  44. static
  45. PWSTR RpcpSecurablePipes[] = {
  46. L"eventlog" // Eventlog server
  47. };
  48. //
  49. // GLOBALS
  50. //
  51. static CRITICAL_SECTION RpcpCriticalSection;
  52. static DWORD RpcpNumInstances;
  53. DWORD
  54. RpcpInitRpcServer(
  55. VOID
  56. )
  57. /*++
  58. Routine Description:
  59. This function initializes the critical section used to protect the
  60. global server handle and instance count.
  61. Arguments:
  62. none
  63. Return Value:
  64. none
  65. --*/
  66. {
  67. InitializeCriticalSection(&RpcpCriticalSection);
  68. RpcpNumInstances = 0;
  69. return(0);
  70. }
  71. #pragma warning(push)
  72. #pragma warning(disable:4701)
  73. NTSTATUS
  74. RpcpReadSDFromRegistry(
  75. IN LPWSTR InterfaceName,
  76. OUT PSECURITY_DESCRIPTOR * pSDToUse)
  77. /*++
  78. Routine Description:
  79. This function checks the registry in the magic place to see if an extra
  80. ACL has been defined for the pipe being passed in. If there is one, it
  81. is translated to a NP acl, then returned. If there isn't one, or if
  82. something goes wrong, an NULL acl is returned.
  83. Arguments:
  84. InterfaceName name of the pipe to check for, e.g. winreg, etc.
  85. pSDToUse returned a pointer to the security decriptor to use.
  86. Return Value:
  87. STATUS_SUCCESS,
  88. STATUS_NO_MEMORY,
  89. Possible other errors from registry apis.
  90. --*/
  91. {
  92. HANDLE hKey;
  93. OBJECT_ATTRIBUTES ObjAttr;
  94. UNICODE_STRING UniString;
  95. PWSTR PipeKey;
  96. NTSTATUS Status;
  97. PSECURITY_DESCRIPTOR pSD;
  98. ULONG cbNeeded;
  99. ACL_SIZE_INFORMATION AclSize;
  100. ULONG AceIndex;
  101. ACCESS_MASK NewMask;
  102. PACCESS_ALLOWED_ACE pAce;
  103. PACL pAcl;
  104. BOOLEAN DaclPresent;
  105. BOOLEAN DaclDefaulted;
  106. UNICODE_STRING Interface;
  107. UNICODE_STRING Allowed;
  108. ULONG i;
  109. BOOLEAN PipeNameOk;
  110. PSECURITY_DESCRIPTOR pNewSD;
  111. PACL pNewAcl;
  112. *pSDToUse = NULL;
  113. RtlInitUnicodeString( &Interface, InterfaceName );
  114. PipeNameOk = FALSE;
  115. for ( i = 0 ; i < sizeof( RpcpSecurablePipes ) / sizeof(PWSTR) ; i++ )
  116. {
  117. RtlInitUnicodeString( &Allowed, RpcpSecurablePipes[i] );
  118. if ( RtlCompareUnicodeString( &Allowed, &Interface, TRUE ) == 0 )
  119. {
  120. PipeNameOk = TRUE;
  121. break;
  122. }
  123. }
  124. if ( PipeNameOk )
  125. {
  126. PipeKey = RtlAllocateHeap(RtlProcessHeap(), 0,
  127. sizeof(NT_PIPE_SD_PREFIX_W) + WCSSIZE(InterfaceName) );
  128. if (!PipeKey)
  129. {
  130. return(STATUS_NO_MEMORY);
  131. }
  132. wcscpy(PipeKey, NT_PIPE_SD_PREFIX_W);
  133. wcscat(PipeKey, InterfaceName);
  134. RtlInitUnicodeString(&UniString, PipeKey);
  135. InitializeObjectAttributes( &ObjAttr,
  136. &UniString,
  137. OBJ_CASE_INSENSITIVE,
  138. NULL, NULL);
  139. Status = NtOpenKey( &hKey,
  140. KEY_READ,
  141. &ObjAttr);
  142. RtlFreeHeap(RtlProcessHeap(), 0, PipeKey);
  143. }
  144. else
  145. {
  146. //
  147. // This is not one of the interfaces that we allow to be secured
  148. // in this fashion. Fake and error,
  149. //
  150. Status = STATUS_OBJECT_NAME_NOT_FOUND ;
  151. }
  152. //
  153. // In general, most times we won't find this key
  154. //
  155. if (!NT_SUCCESS(Status))
  156. {
  157. if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) ||
  158. (Status == STATUS_OBJECT_PATH_NOT_FOUND) )
  159. {
  160. *pSDToUse = NULL;
  161. return(STATUS_SUCCESS);
  162. }
  163. return(Status);
  164. }
  165. //
  166. // Son of a gun, someone has established security for this pipe.
  167. //
  168. pSD = NULL;
  169. cbNeeded = 0;
  170. Status = NtQuerySecurityObject(
  171. hKey,
  172. DACL_SECURITY_INFORMATION,
  173. NULL,
  174. 0,
  175. &cbNeeded );
  176. if (Status == STATUS_BUFFER_TOO_SMALL)
  177. {
  178. pSD = RtlAllocateHeap(RtlProcessHeap(), 0, cbNeeded);
  179. if (pSD)
  180. {
  181. Status = NtQuerySecurityObject(
  182. hKey,
  183. DACL_SECURITY_INFORMATION,
  184. pSD,
  185. cbNeeded,
  186. &cbNeeded );
  187. //
  188. // One way or the other, we are done with the key handle
  189. //
  190. NtClose(hKey);
  191. if (NT_SUCCESS(Status))
  192. {
  193. //
  194. // Now, the tricky part. There is no 1-1 mapping of Key
  195. // permissions to Pipe permissions. So, we do it here.
  196. // We walk the DACL, and examine each ACE. We build a new
  197. // access mask for each ACE, and set the flags as follows:
  198. //
  199. // if (KEY_READ) GENERIC_READ
  200. // if (KEY_WRITE) GENERIC_WRITE
  201. //
  202. Status = RtlGetDaclSecurityDescriptor(
  203. pSD,
  204. &DaclPresent,
  205. &pAcl,
  206. &DaclDefaulted);
  207. //
  208. // If this failed, or there is no DACL present, then
  209. // we're in trouble.
  210. //
  211. if (!NT_SUCCESS(Status) || !DaclPresent)
  212. {
  213. goto GetSDFromKey_BadAcl;
  214. }
  215. Status = RtlQueryInformationAcl(pAcl,
  216. &AclSize,
  217. sizeof(AclSize),
  218. AclSizeInformation);
  219. if (!NT_SUCCESS(Status))
  220. {
  221. goto GetSDFromKey_BadAcl;
  222. }
  223. for (AceIndex = 0; AceIndex < AclSize.AceCount ; AceIndex++ )
  224. {
  225. NewMask = 0;
  226. Status = RtlGetAce( pAcl,
  227. AceIndex,
  228. & pAce);
  229. //
  230. // We don't care what kind of ACE it is, since we
  231. // are just mapping the access types, and the access
  232. // mask is always at a constant position.
  233. //
  234. if (NT_SUCCESS(Status))
  235. {
  236. if ((pAce->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) &&
  237. (pAce->Header.AceType != ACCESS_DENIED_ACE_TYPE))
  238. {
  239. //
  240. // Must be an audit or random ACE type. Skip it.
  241. //
  242. continue;
  243. }
  244. if (pAce->Mask & KEY_READ)
  245. {
  246. NewMask |= GENERIC_READ;
  247. }
  248. if (pAce->Mask & KEY_WRITE)
  249. {
  250. NewMask |= GENERIC_WRITE;
  251. }
  252. pAce->Mask = NewMask;
  253. }
  254. else
  255. {
  256. //
  257. // Panic: Bad ACL?
  258. //
  259. goto GetSDFromKey_BadAcl;
  260. }
  261. }
  262. //
  263. // BUGBUG: RPC does not understand self-relative SDs, so
  264. // we have to turn this into an absolute for them to turn
  265. // back into a self relative.
  266. //
  267. pNewSD = RtlAllocateHeap(RtlProcessHeap(), 0, cbNeeded);
  268. if (!pNewSD)
  269. {
  270. goto GetSDFromKey_BadAcl;
  271. }
  272. InitializeSecurityDescriptor( pNewSD,
  273. SECURITY_DESCRIPTOR_REVISION);
  274. pNewAcl = (PACL) (((PUCHAR) pNewSD) +
  275. sizeof(SECURITY_DESCRIPTOR) );
  276. RtlCopyMemory(pNewAcl, pAcl, AclSize.AclBytesInUse);
  277. SetSecurityDescriptorDacl(pNewSD, TRUE, pNewAcl, FALSE);
  278. RtlFreeHeap(RtlProcessHeap(), 0, pSD);
  279. *pSDToUse = pNewSD;
  280. return(Status);
  281. }
  282. }
  283. return(STATUS_NO_MEMORY);
  284. }
  285. else
  286. {
  287. //
  288. // Failed to read SD:
  289. //
  290. NtClose(hKey);
  291. GetSDFromKey_BadAcl:
  292. //
  293. // Free the SD that we have allocated
  294. //
  295. if (pSD)
  296. {
  297. RtlFreeHeap(RtlProcessHeap(), 0, pSD);
  298. }
  299. //
  300. // Key exists, but there is no security descriptor, or it is unreadable
  301. // for whatever reason.
  302. //
  303. pSD = RtlAllocateHeap(RtlProcessHeap(), 0,
  304. sizeof(SECURITY_DESCRIPTOR) );
  305. if (pSD)
  306. {
  307. InitializeSecurityDescriptor( pSD,
  308. SECURITY_DESCRIPTOR_REVISION );
  309. if (SetSecurityDescriptorDacl (
  310. pSD,
  311. TRUE, // Dacl present
  312. NULL, // NULL Dacl
  313. FALSE // Not defaulted
  314. ) )
  315. {
  316. *pSDToUse = pSD;
  317. return(STATUS_SUCCESS);
  318. }
  319. }
  320. return(STATUS_NO_MEMORY);
  321. }
  322. }
  323. #pragma warning(pop)
  324. NTSTATUS
  325. RpcpAddInterface(
  326. IN LPWSTR InterfaceName,
  327. IN RPC_IF_HANDLE InterfaceSpecification
  328. )
  329. /*++
  330. Routine Description:
  331. Starts an RPC Server, adds the address (or port/pipe), and adds the
  332. interface (dispatch table).
  333. Arguments:
  334. InterfaceName - points to the name of the interface.
  335. InterfaceSpecification - Supplies the interface handle for the
  336. interface which we wish to add.
  337. Return Value:
  338. NT_SUCCESS - Indicates the server was successfully started.
  339. STATUS_NO_MEMORY - An attempt to allocate memory has failed.
  340. Other - Status values that may be returned by:
  341. RpcServerRegisterIf()
  342. RpcServerUseProtseqEp()
  343. , or any RPC error codes, or any windows error codes that
  344. can be returned by LocalAlloc.
  345. --*/
  346. {
  347. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  348. RPC_STATUS RpcStatus;
  349. LPWSTR Endpoint = NULL;
  350. BOOL Bool;
  351. NTSTATUS Status;
  352. // We need to concatenate \pipe\ to the front of the interface name.
  353. Endpoint = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(NT_PIPE_PREFIX_W) + WCSSIZE(InterfaceName));
  354. if (Endpoint == 0) {
  355. return(STATUS_NO_MEMORY);
  356. }
  357. wcscpy(Endpoint, NT_PIPE_PREFIX_W );
  358. wcscat(Endpoint,InterfaceName);
  359. //
  360. // Croft up a security descriptor that will grant everyone
  361. // all access to the object (basically, no security)
  362. //
  363. // We do this by putting in a NULL Dacl.
  364. //
  365. // BUGBUG: rpc should copy the security descriptor,
  366. // Since it currently doesn't, simply allocate it for now and
  367. // leave it around forever.
  368. //
  369. Status = RpcpReadSDFromRegistry(InterfaceName, &SecurityDescriptor);
  370. if (!NT_SUCCESS(Status)) {
  371. ASSERT(Endpoint);
  372. LocalFree(Endpoint);
  373. return(Status);
  374. }
  375. // Ignore the second argument for now.
  376. RpcStatus = RpcServerUseProtseqEpW(L"ncacn_np", 10, Endpoint, SecurityDescriptor);
  377. // If RpcpStartRpcServer and then RpcpStopRpcServer have already
  378. // been called, the endpoint will have already been added but not
  379. // removed (because there is no way to do it). If the endpoint is
  380. // already there, it is ok.
  381. if ( (RpcStatus != RPC_S_OK)
  382. && (RpcStatus != RPC_S_DUPLICATE_ENDPOINT)) {
  383. #if DBG
  384. DbgPrint("RpcServerUseProtseqW failed! rpcstatus = %u\n",RpcStatus);
  385. #endif
  386. goto CleanExit;
  387. }
  388. RpcStatus = RpcServerRegisterIf(InterfaceSpecification, 0, 0);
  389. CleanExit:
  390. if ( Endpoint != NULL ) {
  391. LocalFree(Endpoint);
  392. }
  393. if ( SecurityDescriptor != NULL ) {
  394. LocalFree(SecurityDescriptor);
  395. }
  396. return( I_RpcMapWin32Status(RpcStatus) );
  397. }
  398. NTSTATUS
  399. RpcpStartRpcServer(
  400. IN LPWSTR InterfaceName,
  401. IN RPC_IF_HANDLE InterfaceSpecification
  402. )
  403. /*++
  404. Routine Description:
  405. Starts an RPC Server, adds the address (or port/pipe), and adds the
  406. interface (dispatch table).
  407. Arguments:
  408. InterfaceName - points to the name of the interface.
  409. InterfaceSpecification - Supplies the interface handle for the
  410. interface which we wish to add.
  411. Return Value:
  412. NT_SUCCESS - Indicates the server was successfully started.
  413. STATUS_NO_MEMORY - An attempt to allocate memory has failed.
  414. Other - Status values that may be returned by:
  415. RpcServerRegisterIf()
  416. RpcServerUseProtseqEp()
  417. , or any RPC error codes, or any windows error codes that
  418. can be returned by LocalAlloc.
  419. --*/
  420. {
  421. RPC_STATUS RpcStatus;
  422. EnterCriticalSection(&RpcpCriticalSection);
  423. RpcStatus = RpcpAddInterface( InterfaceName,
  424. InterfaceSpecification );
  425. if ( RpcStatus != RPC_S_OK ) {
  426. LeaveCriticalSection(&RpcpCriticalSection);
  427. return( I_RpcMapWin32Status(RpcStatus) );
  428. }
  429. RpcpNumInstances++;
  430. if (RpcpNumInstances == 1) {
  431. // The first argument specifies the minimum number of threads to
  432. // be created to handle calls; the second argument specifies the
  433. // maximum number of concurrent calls allowed. The last argument
  434. // indicates not to wait.
  435. RpcStatus = RpcServerListen(1,12345, 1);
  436. if ( RpcStatus == RPC_S_ALREADY_LISTENING ) {
  437. RpcStatus = RPC_S_OK;
  438. }
  439. }
  440. LeaveCriticalSection(&RpcpCriticalSection);
  441. return( I_RpcMapWin32Status(RpcStatus) );
  442. }
  443. NTSTATUS
  444. RpcpDeleteInterface(
  445. IN RPC_IF_HANDLE InterfaceSpecification
  446. )
  447. /*++
  448. Routine Description:
  449. Deletes the interface. This is likely
  450. to be caused by an invalid handle. If an attempt to add the same
  451. interface or address again, then an error will be generated at that
  452. time.
  453. Arguments:
  454. InterfaceSpecification - A handle for the interface that is to be removed.
  455. Return Value:
  456. NERR_Success, or any RPC error codes that can be returned from
  457. RpcServerUnregisterIf.
  458. --*/
  459. {
  460. RPC_STATUS RpcStatus;
  461. RpcStatus = RpcServerUnregisterIf(InterfaceSpecification, 0, 1);
  462. return( I_RpcMapWin32Status(RpcStatus) );
  463. }
  464. NTSTATUS
  465. RpcpStopRpcServer(
  466. IN RPC_IF_HANDLE InterfaceSpecification
  467. )
  468. /*++
  469. Routine Description:
  470. Deletes the interface. This is likely
  471. to be caused by an invalid handle. If an attempt to add the same
  472. interface or address again, then an error will be generated at that
  473. time.
  474. Arguments:
  475. InterfaceSpecification - A handle for the interface that is to be removed.
  476. Return Value:
  477. NERR_Success, or any RPC error codes that can be returned from
  478. RpcServerUnregisterIf.
  479. --*/
  480. {
  481. RPC_STATUS RpcStatus;
  482. RpcStatus = RpcServerUnregisterIf(InterfaceSpecification, 0, 1);
  483. EnterCriticalSection(&RpcpCriticalSection);
  484. RpcpNumInstances--;
  485. if (RpcpNumInstances == 0)
  486. {
  487. //
  488. // Return value needs to be from RpcServerUnregisterIf() to maintain
  489. // semantics, so the return values from these are ignored.
  490. //
  491. RpcMgmtStopServerListening(0);
  492. RpcMgmtWaitServerListen();
  493. }
  494. LeaveCriticalSection(&RpcpCriticalSection);
  495. return (I_RpcMapWin32Status(RpcStatus));
  496. }
  497. NTSTATUS
  498. RpcpStopRpcServerEx(
  499. IN RPC_IF_HANDLE InterfaceSpecification
  500. )
  501. /*++
  502. Routine Description:
  503. Deletes the interface and close all context handles associated with it.
  504. This can only be called on interfaces that use strict context handles
  505. (RPC will assert and return an error otherwise).
  506. Arguments:
  507. InterfaceSpecification - A handle for the interface that is to be removed.
  508. Return Value:
  509. NERR_Success, or any RPC error codes that can be returned from
  510. RpcServerUnregisterIfEx.
  511. --*/
  512. {
  513. RPC_STATUS RpcStatus;
  514. RpcStatus = RpcServerUnregisterIfEx(InterfaceSpecification, 0, 1);
  515. EnterCriticalSection(&RpcpCriticalSection);
  516. RpcpNumInstances--;
  517. if (RpcpNumInstances == 0)
  518. {
  519. //
  520. // Return value needs to be from RpcServerUnregisterIfEx() to
  521. // maintain semantics, so the return values from these are ignored.
  522. //
  523. RpcMgmtStopServerListening(0);
  524. RpcMgmtWaitServerListen();
  525. }
  526. LeaveCriticalSection(&RpcpCriticalSection);
  527. return (I_RpcMapWin32Status(RpcStatus));
  528. }