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.

1754 lines
47 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. scsec.cxx
  5. Abstract:
  6. This module contains security related routines:
  7. RQueryServiceObjectSecurity
  8. RSetServiceObjectSecurity
  9. ScCreateScManagerObject
  10. ScCreateScServiceObject
  11. ScGrantAccess
  12. ScPrivilegeCheckAndAudit
  13. ScAccessValidate
  14. ScAccessCheckAndAudit
  15. ScGetPrivilege
  16. ScReleasePrivilege
  17. Author:
  18. Rita Wong (ritaw) 10-Mar-1992
  19. Environment:
  20. Calls NT native APIs.
  21. Revision History:
  22. 10-Mar-1992 ritaw
  23. created
  24. 16-Apr-1992 JohnRo
  25. Process services which are marked for delete accordingly.
  26. 06-Aug-1992 Danl
  27. Fixed a debug print statement. It indicated it was from the
  28. ScLoadDeviceDriver function - rather than in ScGetPrivilege.
  29. 21-Jan-1995 AnirudhS
  30. Added ScGrantAccess and ScPrivilegeCheckAndAudit.
  31. --*/
  32. #include "precomp.hxx"
  33. #include "scconfig.h" // ScOpenServiceConfigKey
  34. #include "scsec.h" // Object names and security functions
  35. #include "control.h" // SERVICE_SET_STATUS
  36. #include "account.h" // ScLookupServiceAccount
  37. #include "align.h" // ROUND_UP_COUNT
  38. #define PRIVILEGE_BUF_SIZE 512
  39. //-------------------------------------------------------------------//
  40. // //
  41. // Static global variables //
  42. // //
  43. //-------------------------------------------------------------------//
  44. //
  45. // Security descriptor of the SCManager objects to control user accesses
  46. // to the Service Control Manager and its database.
  47. //
  48. PSECURITY_DESCRIPTOR ScManagerSd;
  49. //
  50. // Structure that describes the mapping of Generic access rights to
  51. // object specific access rights for the ScManager object.
  52. //
  53. GENERIC_MAPPING ScManagerObjectMapping = {
  54. STANDARD_RIGHTS_READ | // Generic read
  55. SC_MANAGER_ENUMERATE_SERVICE |
  56. SC_MANAGER_QUERY_LOCK_STATUS,
  57. STANDARD_RIGHTS_WRITE | // Generic write
  58. SC_MANAGER_CREATE_SERVICE |
  59. SC_MANAGER_MODIFY_BOOT_CONFIG,
  60. STANDARD_RIGHTS_EXECUTE | // Generic execute
  61. SC_MANAGER_CONNECT |
  62. SC_MANAGER_LOCK,
  63. SC_MANAGER_ALL_ACCESS // Generic all
  64. };
  65. //
  66. // Structure that describes the mapping of generic access rights to
  67. // object specific access rights for the Service object.
  68. //
  69. GENERIC_MAPPING ScServiceObjectMapping = {
  70. STANDARD_RIGHTS_READ | // Generic read
  71. SERVICE_QUERY_CONFIG |
  72. SERVICE_QUERY_STATUS |
  73. SERVICE_ENUMERATE_DEPENDENTS |
  74. SERVICE_INTERROGATE,
  75. STANDARD_RIGHTS_WRITE | // Generic write
  76. SERVICE_CHANGE_CONFIG,
  77. STANDARD_RIGHTS_EXECUTE | // Generic execute
  78. SERVICE_START |
  79. SERVICE_STOP |
  80. SERVICE_PAUSE_CONTINUE |
  81. SERVICE_USER_DEFINED_CONTROL,
  82. SERVICE_ALL_ACCESS // Generic all
  83. };
  84. //-------------------------------------------------------------------//
  85. // //
  86. // Functions //
  87. // //
  88. //-------------------------------------------------------------------//
  89. DWORD
  90. RQueryServiceObjectSecurity(
  91. IN SC_RPC_HANDLE hService,
  92. IN SECURITY_INFORMATION dwSecurityInformation,
  93. OUT LPBYTE lpSecurityDescriptor,
  94. IN DWORD cbBufSize,
  95. OUT LPDWORD pcbBytesNeeded
  96. )
  97. /*++
  98. Routine Description:
  99. This is the worker function for QueryServiceObjectSecurity API.
  100. It returns the security descriptor information of a service
  101. object.
  102. Arguments:
  103. hService - Supplies the context handle to an existing service object.
  104. dwSecurityInformation - Supplies the bitwise flags describing the
  105. security information being queried.
  106. lpSecurityInformation - Supplies the output buffer from the user
  107. which security descriptor information will be written to on
  108. return.
  109. cbBufSize - Supplies the size of lpSecurityInformation buffer.
  110. pcbBytesNeeded - Returns the number of bytes needed of the
  111. lpSecurityInformation buffer to get all the requested
  112. information.
  113. Return Value:
  114. NO_ERROR - The operation was successful.
  115. ERROR_INVALID_HANDLE - The specified handle was invalid.
  116. ERROR_ACCESS_DENIED - The specified handle was not opened for
  117. either READ_CONTROL or ACCESS_SYSTEM_SECURITY
  118. access.
  119. ERROR_INVALID_PARAMETER - The dwSecurityInformation parameter is
  120. invalid.
  121. ERROR_INSUFFICIENT_BUFFER - The specified output buffer is smaller
  122. than the required size returned in pcbBytesNeeded. None of
  123. the security descriptor is returned.
  124. Note:
  125. It is expected that the RPC Stub functions will find the following
  126. parameter problems:
  127. Bad pointers for lpSecurityDescriptor, and pcbBytesNeeded.
  128. --*/
  129. {
  130. NTSTATUS ntstatus;
  131. ACCESS_MASK DesiredAccess = 0;
  132. PSECURITY_DESCRIPTOR ServiceSd;
  133. DWORD ServiceSdSize = 0;
  134. //
  135. // Check the handle.
  136. //
  137. if (!ScIsValidServiceHandle(hService))
  138. {
  139. return ERROR_INVALID_HANDLE;
  140. }
  141. //
  142. // Check the validity of dwSecurityInformation
  143. //
  144. if ((dwSecurityInformation == 0) ||
  145. ((dwSecurityInformation &
  146. (OWNER_SECURITY_INFORMATION |
  147. GROUP_SECURITY_INFORMATION |
  148. DACL_SECURITY_INFORMATION |
  149. SACL_SECURITY_INFORMATION)) != dwSecurityInformation))
  150. {
  151. return ERROR_INVALID_PARAMETER;
  152. }
  153. //
  154. // Set the desired access based on the requested SecurityInformation
  155. //
  156. if (dwSecurityInformation & SACL_SECURITY_INFORMATION) {
  157. DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  158. }
  159. if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
  160. OWNER_SECURITY_INFORMATION |
  161. GROUP_SECURITY_INFORMATION)) {
  162. DesiredAccess |= READ_CONTROL;
  163. }
  164. //
  165. // Was the handle opened for the requested access?
  166. //
  167. if (! RtlAreAllAccessesGranted(
  168. ((LPSC_HANDLE_STRUCT)hService)->AccessGranted,
  169. DesiredAccess
  170. )) {
  171. return ERROR_ACCESS_DENIED;
  172. }
  173. //
  174. //
  175. RtlZeroMemory(lpSecurityDescriptor, cbBufSize);
  176. //
  177. // Get the database lock for reading
  178. //
  179. CServiceRecordSharedLock RLock;
  180. //
  181. // The most up-to-date service security descriptor is always kept in
  182. // the service record.
  183. //
  184. ServiceSd =
  185. ((LPSC_HANDLE_STRUCT)hService)->Type.ScServiceObject.ServiceRecord->ServiceSd;
  186. //
  187. // Retrieve the appropriate security information from ServiceSd
  188. // and place it in the user supplied buffer.
  189. //
  190. ntstatus = RtlQuerySecurityObject(
  191. ServiceSd,
  192. dwSecurityInformation,
  193. (PSECURITY_DESCRIPTOR) lpSecurityDescriptor,
  194. cbBufSize,
  195. &ServiceSdSize
  196. );
  197. if (! NT_SUCCESS(ntstatus)) {
  198. if (ntstatus == STATUS_BAD_DESCRIPTOR_FORMAT) {
  199. //
  200. // Internal error: our security descriptor is bad!
  201. //
  202. SC_LOG0(ERROR,
  203. "RQueryServiceObjectSecurity: Our security descriptor is bad!\n");
  204. ASSERT(FALSE);
  205. return ERROR_GEN_FAILURE;
  206. }
  207. else if (ntstatus == STATUS_BUFFER_TOO_SMALL) {
  208. //
  209. // Return the required size to the user
  210. //
  211. *pcbBytesNeeded = ServiceSdSize;
  212. return ERROR_INSUFFICIENT_BUFFER;
  213. }
  214. else {
  215. return RtlNtStatusToDosError(ntstatus);
  216. }
  217. }
  218. //
  219. // Return the required size to the user
  220. //
  221. *pcbBytesNeeded = ServiceSdSize;
  222. return NO_ERROR;
  223. }
  224. DWORD
  225. RSetServiceObjectSecurity(
  226. IN SC_RPC_HANDLE hService,
  227. IN SECURITY_INFORMATION dwSecurityInformation,
  228. IN LPBYTE lpSecurityDescriptor,
  229. IN DWORD cbBufSize
  230. )
  231. /*++
  232. Routine Description:
  233. This is the worker function for SetServiceObjectSecurity API.
  234. It modifies the security descriptor information of a service
  235. object.
  236. Arguments:
  237. hService - Supplies the context handle to the service.
  238. dwSecurityInformation - Supplies the bitwise flags of security
  239. information being queried.
  240. lpSecurityInformation - Supplies a buffer which contains a
  241. well-formed self-relative security descriptor.
  242. cbBufSize - Supplies the size of lpSecurityInformation buffer.
  243. Return Value:
  244. NO_ERROR - The operation was successful.
  245. ERROR_INVALID_HANDLE - The specified handle was invalid.
  246. ERROR_ACCESS_DENIED - The specified handle was not opened for
  247. either WRITE_OWNER, WRITE_DAC, or ACCESS_SYSTEM_SECURITY
  248. access.
  249. ERROR_INVALID_PARAMETER - The lpSecurityDescriptor or dwSecurityInformation
  250. parameter is invalid.
  251. Note:
  252. It is expected that the RPC Stub functions will find the following
  253. parameter problems:
  254. Bad pointers for lpSecurityDescriptor.
  255. --*/
  256. {
  257. DWORD status;
  258. NTSTATUS ntstatus;
  259. RPC_STATUS rpcstatus;
  260. ACCESS_MASK DesiredAccess = 0;
  261. LPSERVICE_RECORD serviceRecord;
  262. HANDLE ClientTokenHandle = NULL;
  263. LPBYTE lpTempSD = lpSecurityDescriptor;
  264. UNREFERENCED_PARAMETER(cbBufSize); // for RPC marshalling code
  265. //
  266. // Check the handle.
  267. //
  268. if (!ScIsValidServiceHandle(hService))
  269. {
  270. return ERROR_INVALID_HANDLE;
  271. }
  272. //
  273. // Silently ignore flags we don't understand that may come
  274. // from higher-level object managers.
  275. //
  276. dwSecurityInformation &= (OWNER_SECURITY_INFORMATION |
  277. GROUP_SECURITY_INFORMATION |
  278. DACL_SECURITY_INFORMATION |
  279. SACL_SECURITY_INFORMATION);
  280. if (dwSecurityInformation == 0)
  281. {
  282. return NO_ERROR;
  283. }
  284. #ifdef _WIN64
  285. if (PtrToUlong(lpSecurityDescriptor) & (sizeof(PVOID) - 1))
  286. {
  287. //
  288. // SD isn't properly aligned. Alloc an aligned heap buffer
  289. // and copy it in to fix things up.
  290. //
  291. lpTempSD = (LPBYTE) LocalAlloc(LMEM_FIXED, cbBufSize);
  292. if (lpTempSD == NULL)
  293. {
  294. status = ERROR_NOT_ENOUGH_MEMORY;
  295. goto CleanExit;
  296. }
  297. RtlCopyMemory(lpTempSD, lpSecurityDescriptor, cbBufSize);
  298. }
  299. #endif // _WIN64
  300. //
  301. // Check the validity of lpSecurityInformation
  302. //
  303. if (! RtlValidRelativeSecurityDescriptor(
  304. (PSECURITY_DESCRIPTOR) lpTempSD,
  305. cbBufSize,
  306. dwSecurityInformation
  307. ))
  308. {
  309. status = ERROR_INVALID_PARAMETER;
  310. goto CleanExit;
  311. }
  312. //
  313. // Set the desired access based on the specified SecurityInformation
  314. //
  315. if (dwSecurityInformation & SACL_SECURITY_INFORMATION) {
  316. DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  317. }
  318. if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION |
  319. GROUP_SECURITY_INFORMATION)) {
  320. DesiredAccess |= WRITE_OWNER;
  321. }
  322. if (dwSecurityInformation & DACL_SECURITY_INFORMATION) {
  323. DesiredAccess |= WRITE_DAC;
  324. }
  325. //
  326. // Make sure the specified fields are present in the provided
  327. // security descriptor.
  328. // Security descriptors must have owner and group fields.
  329. //
  330. if (dwSecurityInformation & OWNER_SECURITY_INFORMATION)
  331. {
  332. if (((PISECURITY_DESCRIPTOR_RELATIVE) lpTempSD)->Owner == 0)
  333. {
  334. status = ERROR_INVALID_PARAMETER;
  335. goto CleanExit;
  336. }
  337. }
  338. if (dwSecurityInformation & GROUP_SECURITY_INFORMATION)
  339. {
  340. if (((PISECURITY_DESCRIPTOR_RELATIVE) lpTempSD)->Group == 0)
  341. {
  342. status = ERROR_INVALID_PARAMETER;
  343. goto CleanExit;
  344. }
  345. }
  346. //
  347. // Was the handle opened for the requested access?
  348. //
  349. if (! RtlAreAllAccessesGranted(
  350. ((LPSC_HANDLE_STRUCT)hService)->AccessGranted,
  351. DesiredAccess
  352. ))
  353. {
  354. status = ERROR_ACCESS_DENIED;
  355. goto CleanExit;
  356. }
  357. //
  358. // Is this service marked for delete?
  359. //
  360. serviceRecord =
  361. ((LPSC_HANDLE_STRUCT)hService)->Type.ScServiceObject.ServiceRecord;
  362. SC_ASSERT( serviceRecord != NULL );
  363. if (DELETE_FLAG_IS_SET(serviceRecord))
  364. {
  365. status = ERROR_SERVICE_MARKED_FOR_DELETE;
  366. goto CleanExit;
  367. }
  368. //
  369. // If caller wants to replace the owner, get a handle to the impersonation
  370. // token.
  371. //
  372. if (dwSecurityInformation & OWNER_SECURITY_INFORMATION)
  373. {
  374. if ((rpcstatus = RpcImpersonateClient(NULL)) != RPC_S_OK)
  375. {
  376. SC_LOG1(
  377. ERROR,
  378. "RSetServiceObjectSecurity: Failed to impersonate client " FORMAT_RPC_STATUS "\n",
  379. rpcstatus
  380. );
  381. ScLogEvent(
  382. NEVENT_CALL_TO_FUNCTION_FAILED,
  383. SC_RPC_IMPERSONATE,
  384. rpcstatus
  385. );
  386. status = rpcstatus;
  387. goto CleanExit;
  388. }
  389. ntstatus = NtOpenThreadToken(
  390. NtCurrentThread(),
  391. TOKEN_QUERY,
  392. TRUE, // OpenAsSelf
  393. &ClientTokenHandle
  394. );
  395. //
  396. // Stop impersonating the client
  397. //
  398. if ((rpcstatus = RpcRevertToSelf()) != RPC_S_OK) {
  399. SC_LOG1(
  400. ERROR,
  401. "RSetServiceObjectSecurity: Failed to revert to self " FORMAT_RPC_STATUS "\n",
  402. rpcstatus
  403. );
  404. ScLogEvent(
  405. NEVENT_CALL_TO_FUNCTION_FAILED,
  406. SC_RPC_REVERT,
  407. rpcstatus
  408. );
  409. ASSERT(FALSE);
  410. status = rpcstatus;
  411. goto CleanExit;
  412. }
  413. if (! NT_SUCCESS(ntstatus))
  414. {
  415. SC_LOG(ERROR,
  416. "RSetServiceObjectSecurity: NtOpenThreadToken failed %08lx\n",
  417. ntstatus);
  418. status = RtlNtStatusToDosError(ntstatus);
  419. goto CleanExit;
  420. }
  421. }
  422. {
  423. CServiceRecordExclusiveLock RLock;
  424. //
  425. // Replace the service security descriptor with the appropriate
  426. // security information specified in the caller supplied security
  427. // descriptor. This routine may reallocate the memory needed to
  428. // contain the new service security descriptor.
  429. //
  430. ntstatus = RtlSetSecurityObject(
  431. dwSecurityInformation,
  432. (PSECURITY_DESCRIPTOR) lpTempSD,
  433. &serviceRecord->ServiceSd,
  434. &ScServiceObjectMapping,
  435. ClientTokenHandle
  436. );
  437. status = RtlNtStatusToDosError(ntstatus);
  438. if (! NT_SUCCESS(ntstatus))
  439. {
  440. SC_LOG1(ERROR,
  441. "RSetServiceObjectSecurity: RtlSetSecurityObject failed %08lx\n",
  442. ntstatus);
  443. }
  444. else
  445. {
  446. HKEY ServiceKey;
  447. //
  448. // Write new security descriptor to the registry
  449. //
  450. status = ScOpenServiceConfigKey(
  451. serviceRecord->ServiceName,
  452. KEY_WRITE,
  453. FALSE,
  454. &ServiceKey
  455. );
  456. if (status == NO_ERROR)
  457. {
  458. status = ScWriteSd(
  459. ServiceKey,
  460. serviceRecord->ServiceSd
  461. );
  462. if (status != NO_ERROR)
  463. {
  464. SC_LOG1(ERROR,
  465. "RSetServiceObjectSecurity: ScWriteSd failed %lu\n",
  466. status);
  467. }
  468. ScRegFlushKey(ServiceKey);
  469. ScRegCloseKey(ServiceKey);
  470. }
  471. }
  472. }
  473. CleanExit:
  474. #ifdef _WIN64
  475. if (lpTempSD != lpSecurityDescriptor)
  476. {
  477. LocalFree(lpTempSD);
  478. }
  479. #endif // _WIN64
  480. if (ClientTokenHandle != NULL)
  481. {
  482. NtClose(ClientTokenHandle);
  483. }
  484. return status;
  485. }
  486. DWORD
  487. ScCreateScManagerObject(
  488. VOID
  489. )
  490. /*++
  491. Routine Description:
  492. This function creates the security descriptor which represents
  493. the ScManager object for both the "ServiceActive" and
  494. "ServicesFailed" databases.
  495. Arguments:
  496. None.
  497. Return Value:
  498. Returns values from calls to:
  499. ScCreateUserSecurityObject
  500. --*/
  501. {
  502. NTSTATUS ntstatus;
  503. ULONG Privilege = SE_SECURITY_PRIVILEGE;
  504. //
  505. // World has SC_MANAGER_CONNECT access and GENERIC_READ access.
  506. // Local admins are allowed GENERIC_ALL access.
  507. //
  508. #define SC_MANAGER_OBJECT_ACES 5 // Number of ACEs in this DACL
  509. SC_ACE_DATA AceData[SC_MANAGER_OBJECT_ACES] = {
  510. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  511. SC_MANAGER_CONNECT |
  512. GENERIC_READ, &AuthenticatedUserSid},
  513. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  514. SC_MANAGER_CONNECT |
  515. GENERIC_READ |
  516. SC_MANAGER_MODIFY_BOOT_CONFIG, &LocalSystemSid},
  517. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  518. GENERIC_ALL, &AliasAdminsSid},
  519. {SYSTEM_AUDIT_ACE_TYPE, 0, FAILED_ACCESS_ACE_FLAG,
  520. GENERIC_ALL, &WorldSid},
  521. {SYSTEM_AUDIT_ACE_TYPE, INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE,
  522. FAILED_ACCESS_ACE_FLAG,
  523. GENERIC_ALL, &WorldSid}
  524. };
  525. //
  526. // You need to have SE_SECURITY_PRIVILEGE privilege to create the SD with a
  527. // SACL
  528. //
  529. ntstatus = ScGetPrivilege(1, &Privilege);
  530. if (ntstatus != NO_ERROR) {
  531. SC_LOG1(ERROR, "ScCreateScManagerObject: ScGetPrivilege Failed %d\n",
  532. ntstatus);
  533. RevertToSelf();
  534. return(ntstatus);
  535. }
  536. ntstatus = ScCreateUserSecurityObject(
  537. NULL, // Parent SD
  538. AceData,
  539. SC_MANAGER_OBJECT_ACES,
  540. LocalSystemSid,
  541. LocalSystemSid,
  542. TRUE, // IsDirectoryObject
  543. TRUE, // UseImpersonationToken
  544. &ScManagerObjectMapping,
  545. &ScManagerSd
  546. );
  547. #undef SC_MANAGER_OBJECT_ACES
  548. if (! NT_SUCCESS(ntstatus)) {
  549. SC_LOG(
  550. ERROR,
  551. "ScCreateScManagerObject: ScCreateUserSecurityObject failed " FORMAT_NTSTATUS "\n",
  552. ntstatus
  553. );
  554. }
  555. ScReleasePrivilege();
  556. return RtlNtStatusToDosError(ntstatus);
  557. }
  558. DWORD
  559. ScCreateScServiceObject(
  560. OUT PSECURITY_DESCRIPTOR *ServiceSd
  561. )
  562. /*++
  563. Routine Description:
  564. This function creates the security descriptor which represents
  565. the Service object.
  566. Arguments:
  567. ServiceSd - Returns service object security descriptor.
  568. Return Value:
  569. Returns values from calls to:
  570. ScCreateUserSecurityObject
  571. --*/
  572. {
  573. NTSTATUS ntstatus;
  574. //
  575. // Authenticated users have read access.
  576. // Local system has service start/stop and all read access.
  577. // Power user has service start and all read access (Workstation and Server).
  578. // Admin and SystemOp (DC) are allowed all access.
  579. //
  580. #define SC_SERVICE_OBJECT_ACES 4 // Number of ACEs in this DACL
  581. SC_ACE_DATA AceData[SC_SERVICE_OBJECT_ACES] = {
  582. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  583. GENERIC_READ | GENERIC_EXECUTE,
  584. &LocalSystemSid},
  585. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  586. GENERIC_ALL,
  587. &AliasAdminsSid},
  588. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  589. GENERIC_READ | SERVICE_USER_DEFINED_CONTROL,
  590. &AuthenticatedUserSid},
  591. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  592. 0,
  593. 0}
  594. };
  595. switch(USER_SHARED_DATA->NtProductType)
  596. {
  597. case NtProductWinNt:
  598. case NtProductServer:
  599. //
  600. // Power users are only on Workstation and Server
  601. //
  602. AceData[SC_SERVICE_OBJECT_ACES - 1].Mask = GENERIC_READ | GENERIC_EXECUTE;
  603. AceData[SC_SERVICE_OBJECT_ACES - 1].Sid = &AliasPowerUsersSid;
  604. break;
  605. case NtProductLanManNt:
  606. //
  607. // System Ops (Server Operators) are only on a DC
  608. //
  609. AceData[SC_SERVICE_OBJECT_ACES - 1].Mask = GENERIC_ALL;
  610. AceData[SC_SERVICE_OBJECT_ACES - 1].Sid = &AliasSystemOpsSid;
  611. break;
  612. default:
  613. //
  614. // A new product type has been added -- add code to cover it
  615. //
  616. SC_ASSERT(FALSE);
  617. break;
  618. }
  619. ntstatus = ScCreateUserSecurityObject(
  620. ScManagerSd, // ParentSD
  621. AceData,
  622. SC_SERVICE_OBJECT_ACES,
  623. LocalSystemSid,
  624. LocalSystemSid,
  625. FALSE, // IsDirectoryObject
  626. FALSE, // UseImpersonationToken
  627. &ScServiceObjectMapping,
  628. ServiceSd
  629. );
  630. #undef SC_SERVICE_OBJECT_ACES
  631. return RtlNtStatusToDosError(ntstatus);
  632. }
  633. DWORD
  634. ScGrantAccess(
  635. IN OUT LPSC_HANDLE_STRUCT ContextHandle,
  636. IN ACCESS_MASK DesiredAccess
  637. )
  638. /*++
  639. Routine Description:
  640. This function is called when a new service is created. It validates
  641. the access desired by the caller for the new service handle and
  642. computes the granted access to be stored in the context handle
  643. structure. Since this is object creation, all requested accesses,
  644. except for ACCESS_SYSTEM_SECURITY, are granted automatically.
  645. Arguments:
  646. DesiredAccess - Supplies the client requested desired access.
  647. ContextHandle - On return, the granted access is written back to this
  648. location if this call succeeds.
  649. Return Value:
  650. Returns values from calls to the following, mapped to Win32 error codes:
  651. ScPrivilegeCheckAndAudit
  652. --*/
  653. {
  654. NTSTATUS Status = STATUS_SUCCESS;
  655. ACCESS_MASK AccessToGrant = DesiredAccess;
  656. //
  657. // If MAXIMUM_ALLOWED is requested, add GENERIC_ALL
  658. //
  659. if (AccessToGrant & MAXIMUM_ALLOWED) {
  660. AccessToGrant &= ~MAXIMUM_ALLOWED;
  661. AccessToGrant |= GENERIC_ALL;
  662. }
  663. //
  664. // If ACCESS_SYSTEM_SECURITY is requested, check that we have
  665. // SE_SECURITY_PRIVILEGE.
  666. //
  667. if (AccessToGrant & ACCESS_SYSTEM_SECURITY) {
  668. Status = ScPrivilegeCheckAndAudit(
  669. SE_SECURITY_PRIVILEGE, // check for this privilege
  670. ContextHandle, // client's handle to the object
  671. // (used for auditing only)
  672. DesiredAccess // (used for auditing only)
  673. );
  674. }
  675. if (NT_SUCCESS(Status)) {
  676. //
  677. // Map the generic bits to specific and standard bits.
  678. //
  679. RtlMapGenericMask(
  680. &AccessToGrant,
  681. &ScServiceObjectMapping
  682. );
  683. //
  684. // Return the computed access mask.
  685. //
  686. ContextHandle->AccessGranted = AccessToGrant;
  687. }
  688. return(RtlNtStatusToDosError(Status));
  689. }
  690. NTSTATUS
  691. ScPrivilegeCheckAndAudit(
  692. IN ULONG PrivilegeId,
  693. IN PVOID ObjectHandle,
  694. IN ACCESS_MASK DesiredAccess
  695. )
  696. /*++
  697. Routine Description:
  698. This function is only called from ScGrantAccess. It checks if the given
  699. well known privilege is enabled for an impersonated client. It also
  700. generates an audit for the attempt to use the privilege.
  701. Arguments:
  702. PrivilegeId - Specifies the well known Privilege Id
  703. ObjectHandle - Client's handle to the object (used for auditing)
  704. DesiredAccess - Access that the client requested to the object (used
  705. for auditing)
  706. Return Value:
  707. NTSTATUS - Standard Nt Result Code
  708. STATUS_SUCCESS - The call completed successfully and the client
  709. is either trusted or has the necessary privilege enabled.
  710. STATUS_PRIVILEGE_NOT_HELD - The client does not have the necessary
  711. privilege.
  712. --*/
  713. {
  714. NTSTATUS Status, SecondaryStatus;
  715. HANDLE ClientToken = NULL;
  716. //
  717. // Impersonate the client.
  718. //
  719. Status = I_RpcMapWin32Status(RpcImpersonateClient( NULL ));
  720. if (NT_SUCCESS(Status)) {
  721. //
  722. // Open the current thread's impersonation token (if any).
  723. //
  724. Status = NtOpenThreadToken(
  725. NtCurrentThread(),
  726. TOKEN_QUERY,
  727. TRUE,
  728. &ClientToken
  729. );
  730. if (NT_SUCCESS(Status)) {
  731. PRIVILEGE_SET Privilege;
  732. BOOLEAN PrivilegeHeld = FALSE;
  733. UNICODE_STRING Subsystem;
  734. //
  735. // OK, we have a token open. Now check for the specified privilege.
  736. // On return, PrivilegeHeld indicates whether the client has the
  737. // privilege, and whether we will allow the operation to succeed.
  738. //
  739. Privilege.PrivilegeCount = 1;
  740. Privilege.Control = PRIVILEGE_SET_ALL_NECESSARY;
  741. Privilege.Privilege[0].Luid = RtlConvertLongToLuid(PrivilegeId);
  742. Privilege.Privilege[0].Attributes = 0;
  743. Status = NtPrivilegeCheck(
  744. ClientToken,
  745. &Privilege,
  746. &PrivilegeHeld
  747. );
  748. SC_ASSERT(NT_SUCCESS(Status));
  749. //
  750. // Audit the attempt to use the privilege.
  751. //
  752. RtlInitUnicodeString(&Subsystem, SC_MANAGER_AUDIT_NAME);
  753. Status = NtPrivilegeObjectAuditAlarm(
  754. &Subsystem, // Subsystem name
  755. PrivilegeHeld ? ObjectHandle : NULL,
  756. // Object handle, to display in
  757. // the audit log
  758. ClientToken, // Client's token
  759. DesiredAccess, // Access desired by client
  760. &Privilege, // Privileges attempted to use
  761. PrivilegeHeld // Whether access was granted
  762. );
  763. SC_ASSERT(NT_SUCCESS(Status));
  764. if ( !PrivilegeHeld ) {
  765. Status = STATUS_PRIVILEGE_NOT_HELD;
  766. }
  767. //
  768. // Close the client token.
  769. //
  770. SecondaryStatus = NtClose( ClientToken );
  771. ASSERT(NT_SUCCESS(SecondaryStatus));
  772. }
  773. //
  774. // Stop impersonating the client.
  775. //
  776. SecondaryStatus = I_RpcMapWin32Status(RpcRevertToSelf());
  777. }
  778. return Status;
  779. }
  780. DWORD
  781. ScAccessValidate(
  782. IN OUT LPSC_HANDLE_STRUCT ContextHandle,
  783. IN ACCESS_MASK DesiredAccess
  784. )
  785. /*++
  786. Routine Description:
  787. This function is called due to an open request. It validates the
  788. desired access based on the object type specified in the context
  789. handle structure. If the requested access is granted, it is
  790. written into the context handle structure.
  791. Arguments:
  792. ContextHandle - Supplies a pointer to the context handle structure
  793. which contains information about the object. On return, the
  794. granted access is written back to this structure if this
  795. call succeeds.
  796. DesiredAccess - Supplies the client requested desired access.
  797. Return Value:
  798. ERROR_GEN_FAILURE - Object type is unrecognizable. An internal
  799. error has occured.
  800. Returns values from calls to:
  801. ScAccessCheckAndAudit
  802. Notes:
  803. The supplied ContextHandle must be verified to be valid (i.e., non-NULL)
  804. BEFORE calling this routine.
  805. --*/
  806. {
  807. ACCESS_MASK RequestedAccess = DesiredAccess;
  808. if (ContextHandle->Signature == SC_SIGNATURE) {
  809. //
  810. // Map the generic bits to specific and standard bits.
  811. //
  812. RtlMapGenericMask(&RequestedAccess, &ScManagerObjectMapping);
  813. //
  814. // Check to see if requested access is granted to client
  815. //
  816. return ScAccessCheckAndAudit(
  817. (LPWSTR) SC_MANAGER_AUDIT_NAME,
  818. (LPWSTR) SC_MANAGER_OBJECT_TYPE_NAME,
  819. ContextHandle->Type.ScManagerObject.DatabaseName,
  820. ContextHandle,
  821. ScManagerSd,
  822. RequestedAccess,
  823. &ScManagerObjectMapping
  824. );
  825. }
  826. else if (ContextHandle->Signature == SERVICE_SIGNATURE) {
  827. //
  828. // Special-case the status access check instead of adding the right
  829. // for the service to set its own status to the service's default SD
  830. // because of the following reasons:
  831. //
  832. // 1. This check is tighter -- since an SC_HANDLE can be used
  833. // remotely, this prevents SetServiceStatus from now being
  834. // called remotely because the LUIDs won't match.
  835. //
  836. // 2. Modifying the SD would require lots of extra work for SDs
  837. // that are stored in the registry -- the SCM would have to
  838. // detect that there's no SERVICE_SET_STATUS access ACL on
  839. // the SD and add it (also in calls to SetServiceObjectSecurity).
  840. //
  841. // Note that if the user specifies extraneous access bits (i.e.,
  842. // SERVICE_SET_STATUS & <other bits>), it will be rejected by the
  843. // ScAccessCheckAndAudit call below.
  844. //
  845. if (DesiredAccess == SERVICE_SET_STATUS) {
  846. DWORD dwError = ScStatusAccessCheck(ContextHandle->Type.ScServiceObject.ServiceRecord);
  847. if (dwError == NO_ERROR) {
  848. ContextHandle->AccessGranted = SERVICE_SET_STATUS;
  849. }
  850. return dwError;
  851. }
  852. //
  853. // Map the generic bits to specific and standard bits.
  854. //
  855. RtlMapGenericMask(&RequestedAccess, &ScServiceObjectMapping);
  856. //
  857. // Check to see if requested access is granted to client
  858. //
  859. return ScAccessCheckAndAudit(
  860. (LPWSTR) SC_MANAGER_AUDIT_NAME,
  861. (LPWSTR) SC_SERVICE_OBJECT_TYPE_NAME,
  862. ContextHandle->Type.ScServiceObject.ServiceRecord->ServiceName,
  863. ContextHandle,
  864. ContextHandle->Type.ScServiceObject.ServiceRecord->ServiceSd,
  865. RequestedAccess,
  866. &ScServiceObjectMapping
  867. );
  868. }
  869. else {
  870. //
  871. // Unknown object type. This should not happen!
  872. //
  873. SC_LOG(ERROR, "ScAccessValidate: Unknown object type, signature=0x%08lx\n",
  874. ContextHandle->Signature);
  875. ASSERT(FALSE);
  876. return ERROR_GEN_FAILURE;
  877. }
  878. }
  879. DWORD
  880. ScAccessCheckAndAudit(
  881. IN LPWSTR SubsystemName,
  882. IN LPWSTR ObjectTypeName,
  883. IN LPWSTR ObjectName,
  884. IN OUT LPSC_HANDLE_STRUCT ContextHandle,
  885. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  886. IN ACCESS_MASK DesiredAccess,
  887. IN PGENERIC_MAPPING GenericMapping
  888. )
  889. /*++
  890. Routine Description:
  891. This function impersonates the caller so that it can perform access
  892. validation using NtAccessCheckAndAuditAlarm; and reverts back to
  893. itself before returning.
  894. Arguments:
  895. SubsystemName - Supplies a name string identifying the subsystem
  896. calling this routine.
  897. ObjectTypeName - Supplies the name of the type of the object being
  898. accessed.
  899. ObjectName - Supplies the name of the object being accessed.
  900. ContextHandle - Supplies the context handle to the object. On return, if
  901. this call succeeds, the granted access is written to the AccessGranted
  902. field of this structure, and the SC_HANDLE_GENERATE_ON_CLOSE bit of the
  903. Flags field indicates whether NtCloseAuditAlarm must be called when
  904. this handle is closed.
  905. SecurityDescriptor - A pointer to the Security Descriptor against which
  906. acccess is to be checked.
  907. DesiredAccess - Supplies desired acccess mask. This mask must have been
  908. previously mapped to contain no generic accesses.
  909. GenericMapping - Supplies a pointer to the generic mapping associated
  910. with this object type.
  911. Return Value:
  912. NT status mapped to Win32 errors.
  913. --*/
  914. {
  915. NTSTATUS NtStatus;
  916. RPC_STATUS RpcStatus;
  917. UNICODE_STRING Subsystem;
  918. UNICODE_STRING ObjectType;
  919. UNICODE_STRING Object;
  920. BOOLEAN GenerateOnClose;
  921. NTSTATUS AccessStatus;
  922. RtlInitUnicodeString(&Subsystem, SubsystemName);
  923. RtlInitUnicodeString(&ObjectType, ObjectTypeName);
  924. RtlInitUnicodeString(&Object, ObjectName);
  925. if ((RpcStatus = RpcImpersonateClient(NULL)) != RPC_S_OK)
  926. {
  927. SC_LOG1(ERROR, "ScAccessCheckAndAudit: Failed to impersonate client " FORMAT_RPC_STATUS "\n",
  928. RpcStatus);
  929. ScLogEvent(
  930. NEVENT_CALL_TO_FUNCTION_FAILED,
  931. SC_RPC_IMPERSONATE,
  932. RpcStatus
  933. );
  934. return RpcStatus;
  935. }
  936. NtStatus = NtAccessCheckAndAuditAlarm(
  937. &Subsystem,
  938. (PVOID) ContextHandle,
  939. &ObjectType,
  940. &Object,
  941. SecurityDescriptor,
  942. DesiredAccess,
  943. GenericMapping,
  944. FALSE,
  945. &ContextHandle->AccessGranted, // return access granted
  946. &AccessStatus,
  947. &GenerateOnClose
  948. );
  949. if ((RpcStatus = RpcRevertToSelf()) != RPC_S_OK)
  950. {
  951. SC_LOG(ERROR, "ScAccessCheckAndAudit: Fail to revert to self %08lx\n",
  952. RpcStatus);
  953. ScLogEvent(
  954. NEVENT_CALL_TO_FUNCTION_FAILED,
  955. SC_RPC_REVERT,
  956. RpcStatus
  957. );
  958. ASSERT(FALSE);
  959. return RpcStatus;
  960. }
  961. if (! NT_SUCCESS(NtStatus)) {
  962. if (NtStatus != STATUS_ACCESS_DENIED) {
  963. SC_LOG1(
  964. ERROR,
  965. "ScAccessCheckAndAudit: Error calling NtAccessCheckAndAuditAlarm " FORMAT_NTSTATUS "\n",
  966. NtStatus
  967. );
  968. }
  969. return ERROR_ACCESS_DENIED;
  970. }
  971. if (GenerateOnClose)
  972. {
  973. ContextHandle->Flags |= SC_HANDLE_GENERATE_ON_CLOSE;
  974. }
  975. if (AccessStatus != STATUS_SUCCESS) {
  976. SC_LOG(SECURITY, "ScAccessCheckAndAudit: Access status is %08lx\n",
  977. AccessStatus);
  978. return ERROR_ACCESS_DENIED;
  979. }
  980. SC_LOG(SECURITY, "ScAccessCheckAndAudit: Object name %ws\n", ObjectName);
  981. SC_LOG(SECURITY, " Granted access %08lx\n",
  982. ContextHandle->AccessGranted);
  983. return NO_ERROR;
  984. }
  985. DWORD
  986. ScStatusAccessCheck(
  987. IN LPSERVICE_RECORD lpServiceRecord OPTIONAL
  988. )
  989. {
  990. RPC_STATUS RpcStatus;
  991. DWORD dwStatus;
  992. HANDLE hThreadToken = NULL;
  993. SC_ASSERT(lpServiceRecord == NULL || ScServiceRecordLock.Have());
  994. //
  995. // If OpenService is called for SERVICE_SET_STATUS access on a
  996. // service that's not running, the ImageRecord will be NULL
  997. //
  998. if (lpServiceRecord != NULL && lpServiceRecord->ImageRecord == NULL)
  999. {
  1000. return ERROR_SERVICE_NOT_ACTIVE;
  1001. }
  1002. RpcStatus = RpcImpersonateClient(NULL);
  1003. if (RpcStatus != RPC_S_OK)
  1004. {
  1005. SC_LOG1(ERROR,
  1006. "ScStatusAccessCheck: Failed to impersonate client " FORMAT_RPC_STATUS "\n",
  1007. RpcStatus);
  1008. ScLogEvent(
  1009. NEVENT_CALL_TO_FUNCTION_FAILED,
  1010. SC_RPC_IMPERSONATE,
  1011. RpcStatus
  1012. );
  1013. return RpcStatus;
  1014. }
  1015. if (!OpenThreadToken(GetCurrentThread(),
  1016. TOKEN_QUERY,
  1017. TRUE, // Open as self
  1018. &hThreadToken))
  1019. {
  1020. dwStatus = GetLastError();
  1021. SC_LOG1(ERROR,
  1022. "ScStatusAccessCheck: OpenThreadToken FAILED %d\n",
  1023. dwStatus);
  1024. }
  1025. else
  1026. {
  1027. TOKEN_STATISTICS TokenStats;
  1028. if (!GetTokenInformation(hThreadToken,
  1029. TokenStatistics, // Information wanted
  1030. &TokenStats,
  1031. sizeof(TokenStats), // Buffer size
  1032. &dwStatus)) // Size required
  1033. {
  1034. dwStatus = GetLastError();
  1035. SC_LOG1(ERROR,
  1036. "ScCreateImageRecord: GetTokenInformation FAILED %d\n",
  1037. dwStatus);
  1038. }
  1039. else
  1040. {
  1041. LUID SystemLuid = SYSTEM_LUID;
  1042. if (RtlEqualLuid(&TokenStats.AuthenticationId,
  1043. lpServiceRecord ? &lpServiceRecord->ImageRecord->AccountLuid :
  1044. &SystemLuid))
  1045. {
  1046. dwStatus = NO_ERROR;
  1047. }
  1048. else
  1049. {
  1050. dwStatus = ERROR_ACCESS_DENIED;
  1051. }
  1052. }
  1053. CloseHandle(hThreadToken);
  1054. }
  1055. RpcStatus = RpcRevertToSelf();
  1056. if (RpcStatus != RPC_S_OK)
  1057. {
  1058. SC_LOG(ERROR,
  1059. "ScStatusAccessCheck: Fail to revert to self %08lx\n",
  1060. RpcStatus);
  1061. ScLogEvent(
  1062. NEVENT_CALL_TO_FUNCTION_FAILED,
  1063. SC_RPC_REVERT,
  1064. RpcStatus
  1065. );
  1066. ASSERT(FALSE);
  1067. return RpcStatus;
  1068. }
  1069. return dwStatus;
  1070. }
  1071. DWORD
  1072. ScGetPrivilege(
  1073. IN DWORD numPrivileges,
  1074. IN PULONG pulPrivileges
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. This function alters the privilege level for the current thread.
  1079. It does this by duplicating the token for the current thread, and then
  1080. applying the new privileges to that new token, then the current thread
  1081. impersonates with that new token.
  1082. Privileges can be relinquished by calling ScReleasePrivilege().
  1083. Arguments:
  1084. numPrivileges - This is a count of the number of privileges in the
  1085. array of privileges.
  1086. pulPrivileges - This is a pointer to the array of privileges that are
  1087. desired. This is an array of ULONGs.
  1088. Return Value:
  1089. NO_ERROR - If the operation was completely successful.
  1090. Otherwise, it returns mapped return codes from the various NT
  1091. functions that are called.
  1092. --*/
  1093. {
  1094. DWORD status;
  1095. NTSTATUS ntStatus;
  1096. HANDLE ourToken;
  1097. HANDLE newToken;
  1098. OBJECT_ATTRIBUTES Obja;
  1099. SECURITY_QUALITY_OF_SERVICE SecurityQofS;
  1100. ULONG returnLen;
  1101. PTOKEN_PRIVILEGES pTokenPrivilege = NULL;
  1102. DWORD i;
  1103. //
  1104. // Initialize the Privileges Structure
  1105. //
  1106. pTokenPrivilege = (PTOKEN_PRIVILEGES) LocalAlloc(
  1107. LMEM_FIXED,
  1108. sizeof(TOKEN_PRIVILEGES) +
  1109. (sizeof(LUID_AND_ATTRIBUTES) *
  1110. numPrivileges)
  1111. );
  1112. if (pTokenPrivilege == NULL) {
  1113. status = GetLastError();
  1114. SC_LOG(ERROR,"ScGetPrivilege:LocalAlloc Failed %d\n", status);
  1115. return(status);
  1116. }
  1117. pTokenPrivilege->PrivilegeCount = numPrivileges;
  1118. for (i = 0; i < numPrivileges; i++) {
  1119. pTokenPrivilege->Privileges[i].Luid = RtlConvertLongToLuid(
  1120. pulPrivileges[i]);
  1121. pTokenPrivilege->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED;
  1122. }
  1123. //
  1124. // Initialize Object Attribute Structure.
  1125. //
  1126. InitializeObjectAttributes(&Obja,NULL,0L,NULL,NULL);
  1127. //
  1128. // Initialize Security Quality Of Service Structure
  1129. //
  1130. SecurityQofS.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  1131. SecurityQofS.ImpersonationLevel = SecurityImpersonation;
  1132. SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
  1133. SecurityQofS.EffectiveOnly = FALSE;
  1134. Obja.SecurityQualityOfService = &SecurityQofS;
  1135. //
  1136. // Open our own Token
  1137. //
  1138. ntStatus = NtOpenProcessToken(
  1139. NtCurrentProcess(),
  1140. TOKEN_DUPLICATE,
  1141. &ourToken);
  1142. if (!NT_SUCCESS(ntStatus)) {
  1143. SC_LOG(ERROR, "ScGetPrivilege: NtOpenThreadToken Failed "
  1144. "FORMAT_NTSTATUS" "\n", ntStatus);
  1145. LocalFree(pTokenPrivilege);
  1146. return(RtlNtStatusToDosError(ntStatus));
  1147. }
  1148. //
  1149. // Duplicate that Token
  1150. //
  1151. ntStatus = NtDuplicateToken(
  1152. ourToken,
  1153. TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1154. &Obja,
  1155. FALSE, // Duplicate the entire token
  1156. TokenImpersonation, // TokenType
  1157. &newToken); // Duplicate token
  1158. if (!NT_SUCCESS(ntStatus)) {
  1159. SC_LOG(ERROR, "ScGetPrivilege: NtDuplicateToken Failed "
  1160. "FORMAT_NTSTATUS" "\n", ntStatus);
  1161. LocalFree(pTokenPrivilege);
  1162. NtClose(ourToken);
  1163. return(RtlNtStatusToDosError(ntStatus));
  1164. }
  1165. //
  1166. // Add new privileges
  1167. //
  1168. ntStatus = NtAdjustPrivilegesToken(
  1169. newToken, // TokenHandle
  1170. FALSE, // DisableAllPrivileges
  1171. pTokenPrivilege, // NewState
  1172. 0, // Size of previous state buffer
  1173. NULL, // No info on previous state
  1174. &returnLen); // numBytes required for buffer.
  1175. if (!NT_SUCCESS(ntStatus)) {
  1176. SC_LOG(ERROR, "ScGetPrivilege: NtAdjustPrivilegesToken Failed "
  1177. "FORMAT_NTSTATUS" "\n", ntStatus);
  1178. LocalFree(pTokenPrivilege);
  1179. NtClose(ourToken);
  1180. NtClose(newToken);
  1181. return(RtlNtStatusToDosError(ntStatus));
  1182. }
  1183. //
  1184. // Begin impersonating with the new token
  1185. //
  1186. ntStatus = NtSetInformationThread(
  1187. NtCurrentThread(),
  1188. ThreadImpersonationToken,
  1189. (PVOID)&newToken,
  1190. (ULONG)sizeof(HANDLE));
  1191. if (!NT_SUCCESS(ntStatus)) {
  1192. SC_LOG(ERROR, "ScGetPrivilege: NtAdjustPrivilegesToken Failed "
  1193. "FORMAT_NTSTATUS" "\n", ntStatus);
  1194. LocalFree(pTokenPrivilege);
  1195. NtClose(ourToken);
  1196. NtClose(newToken);
  1197. return(RtlNtStatusToDosError(ntStatus));
  1198. }
  1199. LocalFree(pTokenPrivilege);
  1200. NtClose(ourToken);
  1201. NtClose(newToken);
  1202. return(NO_ERROR);
  1203. }
  1204. DWORD
  1205. ScReleasePrivilege(
  1206. VOID
  1207. )
  1208. /*++
  1209. Routine Description:
  1210. This function relinquishes privileges obtained by calling ScGetPrivilege().
  1211. Arguments:
  1212. none
  1213. Return Value:
  1214. NO_ERROR - If the operation was completely successful.
  1215. Otherwise, it returns mapped return codes from the various NT
  1216. functions that are called.
  1217. --*/
  1218. {
  1219. NTSTATUS ntStatus;
  1220. HANDLE NewToken;
  1221. //
  1222. // Revert To Self.
  1223. //
  1224. NewToken = NULL;
  1225. ntStatus = NtSetInformationThread(
  1226. NtCurrentThread(),
  1227. ThreadImpersonationToken,
  1228. (PVOID)&NewToken,
  1229. (ULONG)sizeof(HANDLE));
  1230. if ( !NT_SUCCESS(ntStatus) ) {
  1231. return(RtlNtStatusToDosError(ntStatus));
  1232. }
  1233. return(NO_ERROR);
  1234. }
  1235. DWORD
  1236. ScGetClientSid(
  1237. OUT PTOKEN_USER *UserInfo
  1238. )
  1239. /*++
  1240. Routine Description:
  1241. This function looks up the SID of the API caller by impersonating
  1242. the caller.
  1243. Arguments:
  1244. UserInfo - Receives a pointer to a buffer allocated by this routine
  1245. which contains the TOKEN_USER information of the caller.
  1246. Return Value:
  1247. Returns the NT error mapped to Win32
  1248. --*/
  1249. {
  1250. DWORD status;
  1251. NTSTATUS ntstatus;
  1252. RPC_STATUS rpcstatus;
  1253. HANDLE CurrentThreadToken = NULL;
  1254. DWORD UserInfoSize;
  1255. *UserInfo = NULL;
  1256. if ((rpcstatus = RpcImpersonateClient(NULL)) != RPC_S_OK)
  1257. {
  1258. SC_LOG1(
  1259. ERROR,
  1260. "ScGetUserSid: Failed to impersonate client " FORMAT_RPC_STATUS "\n",
  1261. rpcstatus
  1262. );
  1263. ScLogEvent(
  1264. NEVENT_CALL_TO_FUNCTION_FAILED,
  1265. SC_RPC_IMPERSONATE,
  1266. rpcstatus
  1267. );
  1268. return ((DWORD) rpcstatus);
  1269. }
  1270. ntstatus = NtOpenThreadToken(
  1271. NtCurrentThread(),
  1272. TOKEN_QUERY,
  1273. TRUE, // Use service controller's security
  1274. // context to open thread token
  1275. &CurrentThreadToken
  1276. );
  1277. status = RtlNtStatusToDosError(ntstatus);
  1278. if (! NT_SUCCESS(ntstatus)) {
  1279. SC_LOG1(ERROR, "ScGetUserSid: NtOpenThreadToken failed "
  1280. FORMAT_NTSTATUS "\n", ntstatus);
  1281. goto Cleanup;
  1282. }
  1283. //
  1284. // Call NtQueryInformationToken the first time with 0 input size to
  1285. // get size of returned information.
  1286. //
  1287. ntstatus = NtQueryInformationToken(
  1288. CurrentThreadToken,
  1289. TokenUser, // User information class
  1290. (PVOID) *UserInfo, // Output
  1291. 0,
  1292. &UserInfoSize
  1293. );
  1294. if (ntstatus != STATUS_BUFFER_TOO_SMALL) {
  1295. SC_LOG1(ERROR, "ScGetUserSid: NtQueryInformationToken failed "
  1296. FORMAT_NTSTATUS ". Expected BUFFER_TOO_SMALL.\n", ntstatus);
  1297. status = RtlNtStatusToDosError(ntstatus);
  1298. goto Cleanup;
  1299. }
  1300. //
  1301. // Allocate buffer of returned size
  1302. //
  1303. *UserInfo = (PTOKEN_USER)LocalAlloc(
  1304. LMEM_ZEROINIT,
  1305. (UINT) UserInfoSize
  1306. );
  1307. if (*UserInfo == NULL) {
  1308. SC_LOG1(ERROR, "ScGetUserSid: LocalAlloc failed " FORMAT_DWORD
  1309. "\n", GetLastError());
  1310. status = ERROR_NOT_ENOUGH_MEMORY;
  1311. goto Cleanup;
  1312. }
  1313. //
  1314. // Call NtQueryInformationToken again with the correct buffer size.
  1315. //
  1316. ntstatus = NtQueryInformationToken(
  1317. CurrentThreadToken,
  1318. TokenUser, // User information class
  1319. (PVOID) *UserInfo, // Output
  1320. UserInfoSize,
  1321. &UserInfoSize
  1322. );
  1323. status = RtlNtStatusToDosError(ntstatus);
  1324. if (! NT_SUCCESS(ntstatus)) {
  1325. SC_LOG1(ERROR, "ScGetUserSid: NtQueryInformationToken failed "
  1326. FORMAT_NTSTATUS "\n", ntstatus);
  1327. LocalFree(*UserInfo);
  1328. *UserInfo = NULL;
  1329. }
  1330. Cleanup:
  1331. if (CurrentThreadToken != NULL)
  1332. {
  1333. NtClose(CurrentThreadToken);
  1334. }
  1335. if ((rpcstatus = RpcRevertToSelf()) != RPC_S_OK)
  1336. {
  1337. SC_LOG1(
  1338. ERROR,
  1339. "ScGetUserSid: Failed to revert to self " FORMAT_RPC_STATUS "\n",
  1340. rpcstatus
  1341. );
  1342. ScLogEvent(
  1343. NEVENT_CALL_TO_FUNCTION_FAILED,
  1344. SC_RPC_REVERT,
  1345. rpcstatus
  1346. );
  1347. SC_ASSERT(FALSE);
  1348. return ((DWORD) rpcstatus);
  1349. }
  1350. return status;
  1351. }