Leaked source code of windows server 2003
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.

1936 lines
52 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. {
  532. SC_LOG1(ERROR, "ScCreateScManagerObject: ScGetPrivilege Failed %d\n", ntstatus);
  533. return(ntstatus);
  534. }
  535. ntstatus = ScCreateUserSecurityObject(
  536. NULL, // Parent SD
  537. AceData,
  538. SC_MANAGER_OBJECT_ACES,
  539. LocalSystemSid,
  540. LocalSystemSid,
  541. TRUE, // IsDirectoryObject
  542. TRUE, // UseImpersonationToken
  543. &ScManagerObjectMapping,
  544. &ScManagerSd
  545. );
  546. #undef SC_MANAGER_OBJECT_ACES
  547. if (! NT_SUCCESS(ntstatus)) {
  548. SC_LOG(
  549. ERROR,
  550. "ScCreateScManagerObject: ScCreateUserSecurityObject failed " FORMAT_NTSTATUS "\n",
  551. ntstatus
  552. );
  553. }
  554. ScReleasePrivilege();
  555. return RtlNtStatusToDosError(ntstatus);
  556. }
  557. DWORD
  558. ScGetSaclParameters(
  559. OUT PACCESS_MASK AuditAccessMask,
  560. OUT PUCHAR AuditAceFlags
  561. )
  562. /*++
  563. Routine Description:
  564. Read registry to determine the access-mask and audit ACE flags
  565. to use when adding a SACL on a service object.
  566. Arguments:
  567. AuditAccessMask - pointer to
  568. AuditAceFlags - pointer to
  569. Return Value:
  570. NTSTATUS - Standard Nt Result Code
  571. Notes:
  572. --*/
  573. {
  574. DWORD dwError = NO_ERROR;
  575. DWORD dwValueType;
  576. ACCESS_MASK AccessMask = 0;
  577. DWORD AceFlags = 0;
  578. DWORD dwSize;
  579. HKEY hkeyAuditParams = 0;
  580. ASSERT( sizeof(ACCESS_MASK) == sizeof(DWORD) );
  581. dwSize = sizeof(DWORD);
  582. //
  583. // open the base auditing key
  584. //
  585. dwError = ScRegOpenKeyExW(
  586. HKEY_LOCAL_MACHINE,
  587. L"SYSTEM\\CurrentControlSet\\Control\\LSA\\audit\\Services",
  588. REG_OPTION_NON_VOLATILE,
  589. KEY_READ,
  590. &hkeyAuditParams
  591. );
  592. if ( dwError != NO_ERROR ) {
  593. if ((dwError == ERROR_FILE_NOT_FOUND) ||
  594. (dwError == ERROR_PATH_NOT_FOUND))
  595. {
  596. dwError = NO_ERROR;
  597. }
  598. goto Cleanup;
  599. }
  600. //
  601. // get the access-mask
  602. //
  603. dwError = ScRegQueryValueExW(
  604. hkeyAuditParams,
  605. L"DefaultAuditMask",
  606. NULL,
  607. &dwValueType,
  608. (LPBYTE) &AccessMask,
  609. &dwSize
  610. );
  611. if ( dwError != NO_ERROR ) {
  612. if ((dwError == ERROR_FILE_NOT_FOUND) ||
  613. (dwError == ERROR_PATH_NOT_FOUND))
  614. {
  615. dwError = NO_ERROR;
  616. }
  617. goto Cleanup;
  618. }
  619. if ( ( dwValueType != REG_DWORD ) || ( dwSize != sizeof(DWORD) ) ) {
  620. dwError = ERROR_INVALID_DATA;
  621. goto Cleanup;
  622. }
  623. //
  624. // get the ACE flag
  625. //
  626. dwError = ScRegQueryValueExW(
  627. hkeyAuditParams,
  628. L"DefaultAuditAceFlags",
  629. NULL,
  630. &dwValueType,
  631. (LPBYTE) &AceFlags,
  632. &dwSize
  633. );
  634. if ( dwError != NO_ERROR ) {
  635. if ((dwError == ERROR_FILE_NOT_FOUND) ||
  636. (dwError == ERROR_PATH_NOT_FOUND))
  637. {
  638. dwError = NO_ERROR;
  639. AceFlags = SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG;
  640. }
  641. goto Cleanup;
  642. }
  643. if ( ( dwValueType != REG_DWORD ) || ( dwSize != sizeof(DWORD) ) ) {
  644. dwError = ERROR_INVALID_DATA;
  645. goto Cleanup;
  646. }
  647. Cleanup:
  648. if ( dwError == NO_ERROR ) {
  649. *AuditAccessMask = AccessMask;
  650. *AuditAceFlags = (UCHAR) AceFlags;
  651. } else {
  652. *AuditAccessMask = 0;
  653. *AuditAceFlags = 0;
  654. }
  655. if ( hkeyAuditParams != 0 ) {
  656. ScRegCloseKey( hkeyAuditParams );
  657. }
  658. return dwError;
  659. }
  660. DWORD
  661. ScCreateScServiceObject(
  662. OUT PSECURITY_DESCRIPTOR *ServiceSd
  663. )
  664. /*++
  665. Routine Description:
  666. This function creates the security descriptor which represents
  667. the Service object.
  668. Arguments:
  669. ServiceSd - Returns service object security descriptor.
  670. Return Value:
  671. Returns values from calls to:
  672. ScCreateUserSecurityObject
  673. --*/
  674. {
  675. NTSTATUS ntstatus = STATUS_SUCCESS;
  676. UINT NumAces = 0;
  677. ACCESS_MASK AuditAccessMask = 0;
  678. UCHAR AuditAceFlags = 0;
  679. ULONG Privilege = SE_SECURITY_PRIVILEGE;
  680. BOOLEAN Impersonating = FALSE;
  681. DWORD dwError = NO_ERROR;
  682. //
  683. // Authenticated users have read access.
  684. // Local system has service start/stop and all read access.
  685. // Power user has service start and all read access (Workstation and Server).
  686. // Admin and SystemOp (DC) are allowed all access.
  687. //
  688. #define SC_SERVICE_OBJECT_ACES 5 // Number of ACEs
  689. SC_ACE_DATA AceData[SC_SERVICE_OBJECT_ACES] = {
  690. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  691. GENERIC_READ | GENERIC_EXECUTE,
  692. &LocalSystemSid},
  693. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  694. GENERIC_ALL,
  695. &AliasAdminsSid},
  696. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  697. GENERIC_READ | SERVICE_USER_DEFINED_CONTROL,
  698. &AuthenticatedUserSid},
  699. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  700. 0,
  701. 0},
  702. {SYSTEM_AUDIT_ACE_TYPE, 0, 0,
  703. 0,
  704. &WorldSid}
  705. };
  706. //
  707. // do not include the last ACE (the audit ACE) for now
  708. //
  709. NumAces = SC_SERVICE_OBJECT_ACES - 1;
  710. switch(USER_SHARED_DATA->NtProductType)
  711. {
  712. case NtProductWinNt:
  713. case NtProductServer:
  714. //
  715. // Power users are only on Workstation and Server
  716. //
  717. AceData[SC_SERVICE_OBJECT_ACES - 2].Mask = GENERIC_READ | GENERIC_EXECUTE;
  718. AceData[SC_SERVICE_OBJECT_ACES - 2].Sid = &AliasPowerUsersSid;
  719. break;
  720. case NtProductLanManNt:
  721. //
  722. // System Ops (Server Operators) are only on a DC
  723. //
  724. AceData[SC_SERVICE_OBJECT_ACES - 2].Mask = GENERIC_ALL;
  725. AceData[SC_SERVICE_OBJECT_ACES - 2].Sid = &AliasSystemOpsSid;
  726. break;
  727. default:
  728. //
  729. // A new product type has been added -- add code to cover it
  730. //
  731. SC_ASSERT(FALSE);
  732. break;
  733. }
  734. //
  735. // get the access-mask and ACE flags to use for the audit ACE.
  736. //
  737. dwError = ScGetSaclParameters(
  738. &AuditAccessMask,
  739. &AuditAceFlags
  740. );
  741. if ( dwError == NO_ERROR ) {
  742. if ( AuditAccessMask && AuditAceFlags ) {
  743. AceData[NumAces].Mask = AuditAccessMask;
  744. AceData[NumAces].AceFlags = AuditAceFlags;
  745. NumAces += 1;
  746. //
  747. // need SE_SECURITY_PRIVILEGE privilege to create SD with a SACL
  748. //
  749. dwError = ScGetPrivilege(1, &Privilege);
  750. if (dwError != NO_ERROR) {
  751. goto Cleanup;
  752. }
  753. Impersonating = TRUE;
  754. }
  755. ntstatus = ScCreateUserSecurityObject(
  756. ScManagerSd, // ParentSD
  757. AceData,
  758. NumAces,
  759. LocalSystemSid,
  760. LocalSystemSid,
  761. FALSE, // IsDirectoryObject
  762. Impersonating, // UseImpersonationToken
  763. &ScServiceObjectMapping,
  764. ServiceSd
  765. );
  766. dwError = RtlNtStatusToDosError(ntstatus);
  767. if ( Impersonating ) {
  768. ScReleasePrivilege();
  769. }
  770. }
  771. #undef SC_SERVICE_OBJECT_ACES
  772. Cleanup:
  773. return dwError;
  774. }
  775. DWORD
  776. ScGrantAccess(
  777. IN OUT LPSC_HANDLE_STRUCT ContextHandle,
  778. IN ACCESS_MASK DesiredAccess
  779. )
  780. /*++
  781. Routine Description:
  782. This function is called when a new service is created. It validates
  783. the access desired by the caller for the new service handle and
  784. computes the granted access to be stored in the context handle
  785. structure. Since this is object creation, all requested accesses,
  786. except for ACCESS_SYSTEM_SECURITY, are granted automatically.
  787. Arguments:
  788. DesiredAccess - Supplies the client requested desired access.
  789. ContextHandle - On return, the granted access is written back to this
  790. location if this call succeeds.
  791. Return Value:
  792. Returns values from calls to the following, mapped to Win32 error codes:
  793. ScPrivilegeCheckAndAudit
  794. --*/
  795. {
  796. NTSTATUS Status = STATUS_SUCCESS;
  797. ACCESS_MASK AccessToGrant = DesiredAccess;
  798. //
  799. // If MAXIMUM_ALLOWED is requested, add GENERIC_ALL
  800. //
  801. if (AccessToGrant & MAXIMUM_ALLOWED) {
  802. AccessToGrant &= ~MAXIMUM_ALLOWED;
  803. AccessToGrant |= GENERIC_ALL;
  804. }
  805. //
  806. // If ACCESS_SYSTEM_SECURITY is requested, check that we have
  807. // SE_SECURITY_PRIVILEGE.
  808. //
  809. if (AccessToGrant & ACCESS_SYSTEM_SECURITY) {
  810. Status = ScPrivilegeCheckAndAudit(
  811. SE_SECURITY_PRIVILEGE, // check for this privilege
  812. ContextHandle, // client's handle to the object
  813. // (used for auditing only)
  814. DesiredAccess // (used for auditing only)
  815. );
  816. }
  817. if (NT_SUCCESS(Status)) {
  818. //
  819. // Map the generic bits to specific and standard bits.
  820. //
  821. RtlMapGenericMask(
  822. &AccessToGrant,
  823. &ScServiceObjectMapping
  824. );
  825. //
  826. // Return the computed access mask.
  827. //
  828. ContextHandle->AccessGranted = AccessToGrant;
  829. }
  830. return(RtlNtStatusToDosError(Status));
  831. }
  832. NTSTATUS
  833. ScPrivilegeCheckAndAudit(
  834. IN ULONG PrivilegeId,
  835. IN PVOID ObjectHandle,
  836. IN ACCESS_MASK DesiredAccess
  837. )
  838. /*++
  839. Routine Description:
  840. This function is only called from ScGrantAccess. It checks if the given
  841. well known privilege is enabled for an impersonated client. It also
  842. generates an audit for the attempt to use the privilege.
  843. Arguments:
  844. PrivilegeId - Specifies the well known Privilege Id
  845. ObjectHandle - Client's handle to the object (used for auditing)
  846. DesiredAccess - Access that the client requested to the object (used
  847. for auditing)
  848. Return Value:
  849. NTSTATUS - Standard Nt Result Code
  850. STATUS_SUCCESS - The call completed successfully and the client
  851. is either trusted or has the necessary privilege enabled.
  852. STATUS_PRIVILEGE_NOT_HELD - The client does not have the necessary
  853. privilege.
  854. --*/
  855. {
  856. NTSTATUS Status, SecondaryStatus;
  857. HANDLE ClientToken = NULL;
  858. //
  859. // Impersonate the client.
  860. //
  861. Status = I_RpcMapWin32Status(RpcImpersonateClient( NULL ));
  862. if (NT_SUCCESS(Status)) {
  863. //
  864. // Open the current thread's impersonation token (if any).
  865. //
  866. Status = NtOpenThreadToken(
  867. NtCurrentThread(),
  868. TOKEN_QUERY,
  869. TRUE,
  870. &ClientToken
  871. );
  872. if (NT_SUCCESS(Status)) {
  873. PRIVILEGE_SET Privilege;
  874. BOOLEAN PrivilegeHeld = FALSE;
  875. UNICODE_STRING Subsystem;
  876. //
  877. // OK, we have a token open. Now check for the specified privilege.
  878. // On return, PrivilegeHeld indicates whether the client has the
  879. // privilege, and whether we will allow the operation to succeed.
  880. //
  881. Privilege.PrivilegeCount = 1;
  882. Privilege.Control = PRIVILEGE_SET_ALL_NECESSARY;
  883. Privilege.Privilege[0].Luid = RtlConvertLongToLuid(PrivilegeId);
  884. Privilege.Privilege[0].Attributes = 0;
  885. Status = NtPrivilegeCheck(
  886. ClientToken,
  887. &Privilege,
  888. &PrivilegeHeld
  889. );
  890. SC_ASSERT(NT_SUCCESS(Status));
  891. //
  892. // Audit the attempt to use the privilege.
  893. //
  894. RtlInitUnicodeString(&Subsystem, SC_MANAGER_AUDIT_NAME);
  895. Status = NtPrivilegeObjectAuditAlarm(
  896. &Subsystem, // Subsystem name
  897. PrivilegeHeld ? ObjectHandle : NULL,
  898. // Object handle, to display in
  899. // the audit log
  900. ClientToken, // Client's token
  901. DesiredAccess, // Access desired by client
  902. &Privilege, // Privileges attempted to use
  903. PrivilegeHeld // Whether access was granted
  904. );
  905. SC_ASSERT(NT_SUCCESS(Status));
  906. if ( !PrivilegeHeld ) {
  907. Status = STATUS_PRIVILEGE_NOT_HELD;
  908. }
  909. //
  910. // Close the client token.
  911. //
  912. SecondaryStatus = NtClose( ClientToken );
  913. ASSERT(NT_SUCCESS(SecondaryStatus));
  914. }
  915. //
  916. // Stop impersonating the client.
  917. //
  918. SecondaryStatus = I_RpcMapWin32Status(RpcRevertToSelf());
  919. }
  920. return Status;
  921. }
  922. DWORD
  923. ScAccessValidate(
  924. IN OUT LPSC_HANDLE_STRUCT ContextHandle,
  925. IN ACCESS_MASK DesiredAccess
  926. )
  927. /*++
  928. Routine Description:
  929. This function is called due to an open request. It validates the
  930. desired access based on the object type specified in the context
  931. handle structure. If the requested access is granted, it is
  932. written into the context handle structure.
  933. Arguments:
  934. ContextHandle - Supplies a pointer to the context handle structure
  935. which contains information about the object. On return, the
  936. granted access is written back to this structure if this
  937. call succeeds.
  938. DesiredAccess - Supplies the client requested desired access.
  939. Return Value:
  940. ERROR_GEN_FAILURE - Object type is unrecognizable. An internal
  941. error has occured.
  942. Returns values from calls to:
  943. ScAccessCheckAndAudit
  944. Notes:
  945. The supplied ContextHandle must be verified to be valid (i.e., non-NULL)
  946. BEFORE calling this routine.
  947. --*/
  948. {
  949. ACCESS_MASK RequestedAccess = DesiredAccess;
  950. if (ContextHandle->Signature == SC_SIGNATURE) {
  951. //
  952. // Map the generic bits to specific and standard bits.
  953. //
  954. RtlMapGenericMask(&RequestedAccess, &ScManagerObjectMapping);
  955. //
  956. // Check to see if requested access is granted to client
  957. //
  958. return ScAccessCheckAndAudit(
  959. (LPWSTR) SC_MANAGER_AUDIT_NAME,
  960. (LPWSTR) SC_MANAGER_OBJECT_TYPE_NAME,
  961. ContextHandle->Type.ScManagerObject.DatabaseName,
  962. ContextHandle,
  963. ScManagerSd,
  964. RequestedAccess,
  965. &ScManagerObjectMapping
  966. );
  967. }
  968. else if (ContextHandle->Signature == SERVICE_SIGNATURE) {
  969. //
  970. // Special-case the status access check instead of adding the right
  971. // for the service to set its own status to the service's default SD
  972. // because of the following reasons:
  973. //
  974. // 1. This check is tighter -- since an SC_HANDLE can be used
  975. // remotely, this prevents SetServiceStatus from now being
  976. // called remotely because the LUIDs won't match.
  977. //
  978. // 2. Modifying the SD would require lots of extra work for SDs
  979. // that are stored in the registry -- the SCM would have to
  980. // detect that there's no SERVICE_SET_STATUS access ACL on
  981. // the SD and add it (also in calls to SetServiceObjectSecurity).
  982. //
  983. // Note that if the user specifies extraneous access bits (i.e.,
  984. // SERVICE_SET_STATUS & <other bits>), it will be rejected by the
  985. // ScAccessCheckAndAudit call below.
  986. //
  987. if (DesiredAccess == SERVICE_SET_STATUS) {
  988. DWORD dwError = ScStatusAccessCheck(ContextHandle->Type.ScServiceObject.ServiceRecord);
  989. if (dwError == NO_ERROR) {
  990. ContextHandle->AccessGranted = SERVICE_SET_STATUS;
  991. }
  992. return dwError;
  993. }
  994. //
  995. // Map the generic bits to specific and standard bits.
  996. //
  997. RtlMapGenericMask(&RequestedAccess, &ScServiceObjectMapping);
  998. //
  999. // Check to see if requested access is granted to client
  1000. //
  1001. return ScAccessCheckAndAudit(
  1002. (LPWSTR) SC_MANAGER_AUDIT_NAME,
  1003. (LPWSTR) SC_SERVICE_OBJECT_TYPE_NAME,
  1004. ContextHandle->Type.ScServiceObject.ServiceRecord->ServiceName,
  1005. ContextHandle,
  1006. ContextHandle->Type.ScServiceObject.ServiceRecord->ServiceSd,
  1007. RequestedAccess,
  1008. &ScServiceObjectMapping
  1009. );
  1010. }
  1011. else {
  1012. //
  1013. // Unknown object type. This should not happen!
  1014. //
  1015. SC_LOG(ERROR, "ScAccessValidate: Unknown object type, signature=0x%08lx\n",
  1016. ContextHandle->Signature);
  1017. ASSERT(FALSE);
  1018. return ERROR_GEN_FAILURE;
  1019. }
  1020. }
  1021. DWORD
  1022. ScAccessCheckAndAudit(
  1023. IN LPWSTR SubsystemName,
  1024. IN LPWSTR ObjectTypeName,
  1025. IN LPWSTR ObjectName,
  1026. IN OUT LPSC_HANDLE_STRUCT ContextHandle,
  1027. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1028. IN ACCESS_MASK DesiredAccess,
  1029. IN PGENERIC_MAPPING GenericMapping
  1030. )
  1031. /*++
  1032. Routine Description:
  1033. This function impersonates the caller so that it can perform access
  1034. validation using NtAccessCheckAndAuditAlarm; and reverts back to
  1035. itself before returning.
  1036. Arguments:
  1037. SubsystemName - Supplies a name string identifying the subsystem
  1038. calling this routine.
  1039. ObjectTypeName - Supplies the name of the type of the object being
  1040. accessed.
  1041. ObjectName - Supplies the name of the object being accessed.
  1042. ContextHandle - Supplies the context handle to the object. On return, if
  1043. this call succeeds, the granted access is written to the AccessGranted
  1044. field of this structure, and the SC_HANDLE_GENERATE_ON_CLOSE bit of the
  1045. Flags field indicates whether NtCloseAuditAlarm must be called when
  1046. this handle is closed.
  1047. SecurityDescriptor - A pointer to the Security Descriptor against which
  1048. acccess is to be checked.
  1049. DesiredAccess - Supplies desired acccess mask. This mask must have been
  1050. previously mapped to contain no generic accesses.
  1051. GenericMapping - Supplies a pointer to the generic mapping associated
  1052. with this object type.
  1053. Return Value:
  1054. NT status mapped to Win32 errors.
  1055. --*/
  1056. {
  1057. NTSTATUS NtStatus;
  1058. RPC_STATUS RpcStatus;
  1059. UNICODE_STRING Subsystem;
  1060. UNICODE_STRING ObjectType;
  1061. UNICODE_STRING Object;
  1062. BOOLEAN GenerateOnClose;
  1063. NTSTATUS AccessStatus;
  1064. RtlInitUnicodeString(&Subsystem, SubsystemName);
  1065. RtlInitUnicodeString(&ObjectType, ObjectTypeName);
  1066. RtlInitUnicodeString(&Object, ObjectName);
  1067. if ((RpcStatus = RpcImpersonateClient(NULL)) != RPC_S_OK)
  1068. {
  1069. SC_LOG1(ERROR, "ScAccessCheckAndAudit: Failed to impersonate client " FORMAT_RPC_STATUS "\n",
  1070. RpcStatus);
  1071. ScLogEvent(
  1072. NEVENT_CALL_TO_FUNCTION_FAILED,
  1073. SC_RPC_IMPERSONATE,
  1074. RpcStatus
  1075. );
  1076. return RpcStatus;
  1077. }
  1078. NtStatus = NtAccessCheckAndAuditAlarm(
  1079. &Subsystem,
  1080. (PVOID) ContextHandle,
  1081. &ObjectType,
  1082. &Object,
  1083. SecurityDescriptor,
  1084. DesiredAccess,
  1085. GenericMapping,
  1086. FALSE,
  1087. &ContextHandle->AccessGranted, // return access granted
  1088. &AccessStatus,
  1089. &GenerateOnClose
  1090. );
  1091. if ((RpcStatus = RpcRevertToSelf()) != RPC_S_OK)
  1092. {
  1093. SC_LOG(ERROR, "ScAccessCheckAndAudit: Fail to revert to self %08lx\n",
  1094. RpcStatus);
  1095. ScLogEvent(
  1096. NEVENT_CALL_TO_FUNCTION_FAILED,
  1097. SC_RPC_REVERT,
  1098. RpcStatus
  1099. );
  1100. ASSERT(FALSE);
  1101. return RpcStatus;
  1102. }
  1103. if (!NT_SUCCESS(NtStatus))
  1104. {
  1105. if (NtStatus != STATUS_ACCESS_DENIED)
  1106. {
  1107. SC_LOG1(ERROR,
  1108. "ScAccessCheckAndAudit: Error calling NtAccessCheckAndAuditAlarm "
  1109. FORMAT_NTSTATUS "\n",
  1110. NtStatus);
  1111. }
  1112. return RtlNtStatusToDosError(NtStatus);
  1113. }
  1114. if (GenerateOnClose)
  1115. {
  1116. ContextHandle->Flags |= SC_HANDLE_GENERATE_ON_CLOSE;
  1117. }
  1118. if (AccessStatus != STATUS_SUCCESS)
  1119. {
  1120. SC_LOG(SECURITY, "ScAccessCheckAndAudit: Access status is %08lx\n", AccessStatus);
  1121. return RtlNtStatusToDosError(AccessStatus);
  1122. }
  1123. SC_LOG(SECURITY, "ScAccessCheckAndAudit: Object name %ws\n", ObjectName);
  1124. SC_LOG(SECURITY, " Granted access %08lx\n", ContextHandle->AccessGranted);
  1125. return NO_ERROR;
  1126. }
  1127. DWORD
  1128. ScStatusAccessCheck(
  1129. IN LPSERVICE_RECORD lpServiceRecord OPTIONAL
  1130. )
  1131. {
  1132. RPC_STATUS RpcStatus;
  1133. DWORD dwStatus;
  1134. HANDLE hThreadToken = NULL;
  1135. SC_ASSERT(lpServiceRecord == NULL || ScServiceRecordLock.Have());
  1136. //
  1137. // If OpenService is called for SERVICE_SET_STATUS access on a
  1138. // service that's not running, the ImageRecord will be NULL
  1139. //
  1140. if (lpServiceRecord != NULL && lpServiceRecord->ImageRecord == NULL)
  1141. {
  1142. return ERROR_SERVICE_NOT_ACTIVE;
  1143. }
  1144. RpcStatus = RpcImpersonateClient(NULL);
  1145. if (RpcStatus != RPC_S_OK)
  1146. {
  1147. SC_LOG1(ERROR,
  1148. "ScStatusAccessCheck: Failed to impersonate client " FORMAT_RPC_STATUS "\n",
  1149. RpcStatus);
  1150. ScLogEvent(
  1151. NEVENT_CALL_TO_FUNCTION_FAILED,
  1152. SC_RPC_IMPERSONATE,
  1153. RpcStatus
  1154. );
  1155. return RpcStatus;
  1156. }
  1157. if (!OpenThreadToken(GetCurrentThread(),
  1158. TOKEN_QUERY,
  1159. TRUE, // Open as self
  1160. &hThreadToken))
  1161. {
  1162. dwStatus = GetLastError();
  1163. SC_LOG1(ERROR,
  1164. "ScStatusAccessCheck: OpenThreadToken FAILED %d\n",
  1165. dwStatus);
  1166. }
  1167. else
  1168. {
  1169. TOKEN_STATISTICS TokenStats;
  1170. if (!GetTokenInformation(hThreadToken,
  1171. TokenStatistics, // Information wanted
  1172. &TokenStats,
  1173. sizeof(TokenStats), // Buffer size
  1174. &dwStatus)) // Size required
  1175. {
  1176. dwStatus = GetLastError();
  1177. SC_LOG1(ERROR,
  1178. "ScCreateImageRecord: GetTokenInformation FAILED %d\n",
  1179. dwStatus);
  1180. }
  1181. else
  1182. {
  1183. LUID SystemLuid = SYSTEM_LUID;
  1184. if (RtlEqualLuid(&TokenStats.AuthenticationId,
  1185. lpServiceRecord ? &lpServiceRecord->ImageRecord->AccountLuid :
  1186. &SystemLuid))
  1187. {
  1188. dwStatus = NO_ERROR;
  1189. }
  1190. else
  1191. {
  1192. dwStatus = ERROR_ACCESS_DENIED;
  1193. }
  1194. }
  1195. CloseHandle(hThreadToken);
  1196. }
  1197. RpcStatus = RpcRevertToSelf();
  1198. if (RpcStatus != RPC_S_OK)
  1199. {
  1200. SC_LOG(ERROR,
  1201. "ScStatusAccessCheck: Fail to revert to self %08lx\n",
  1202. RpcStatus);
  1203. ScLogEvent(
  1204. NEVENT_CALL_TO_FUNCTION_FAILED,
  1205. SC_RPC_REVERT,
  1206. RpcStatus
  1207. );
  1208. ASSERT(FALSE);
  1209. return RpcStatus;
  1210. }
  1211. return dwStatus;
  1212. }
  1213. DWORD
  1214. ScGetPrivilege(
  1215. IN DWORD numPrivileges,
  1216. IN PULONG pulPrivileges
  1217. )
  1218. /*++
  1219. Routine Description:
  1220. This function alters the privilege level for the current thread.
  1221. It does this by duplicating the token for the current thread, and then
  1222. applying the new privileges to that new token, then the current thread
  1223. impersonates with that new token.
  1224. Privileges can be relinquished by calling ScReleasePrivilege().
  1225. Arguments:
  1226. numPrivileges - This is a count of the number of privileges in the
  1227. array of privileges.
  1228. pulPrivileges - This is a pointer to the array of privileges that are
  1229. desired. This is an array of ULONGs.
  1230. Return Value:
  1231. NO_ERROR - If the operation was completely successful.
  1232. Otherwise, it returns mapped return codes from the various NT
  1233. functions that are called.
  1234. --*/
  1235. {
  1236. DWORD status;
  1237. NTSTATUS ntStatus;
  1238. HANDLE newToken;
  1239. OBJECT_ATTRIBUTES Obja;
  1240. SECURITY_QUALITY_OF_SERVICE SecurityQofS;
  1241. ULONG returnLen;
  1242. PTOKEN_PRIVILEGES pTokenPrivilege = NULL;
  1243. DWORD i;
  1244. //
  1245. // Initialize the Privileges Structure
  1246. //
  1247. pTokenPrivilege = (PTOKEN_PRIVILEGES) LocalAlloc(
  1248. LMEM_FIXED,
  1249. sizeof(TOKEN_PRIVILEGES) +
  1250. (sizeof(LUID_AND_ATTRIBUTES) *
  1251. numPrivileges)
  1252. );
  1253. if (pTokenPrivilege == NULL) {
  1254. status = GetLastError();
  1255. SC_LOG(ERROR,"ScGetPrivilege:LocalAlloc Failed %d\n", status);
  1256. return(status);
  1257. }
  1258. pTokenPrivilege->PrivilegeCount = numPrivileges;
  1259. for (i = 0; i < numPrivileges; i++) {
  1260. pTokenPrivilege->Privileges[i].Luid = RtlConvertLongToLuid(
  1261. pulPrivileges[i]);
  1262. pTokenPrivilege->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED;
  1263. }
  1264. //
  1265. // Initialize Object Attribute Structure.
  1266. //
  1267. InitializeObjectAttributes(&Obja,NULL,0L,NULL,NULL);
  1268. //
  1269. // Initialize Security Quality Of Service Structure
  1270. //
  1271. SecurityQofS.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  1272. SecurityQofS.ImpersonationLevel = SecurityImpersonation;
  1273. SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
  1274. SecurityQofS.EffectiveOnly = FALSE;
  1275. Obja.SecurityQualityOfService = &SecurityQofS;
  1276. //
  1277. // Duplicate our Process Token
  1278. //
  1279. ntStatus = NtDuplicateToken(
  1280. g_hProcessToken,
  1281. TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1282. &Obja,
  1283. FALSE, // Duplicate the entire token
  1284. TokenImpersonation, // TokenType
  1285. &newToken); // Duplicate token
  1286. if (!NT_SUCCESS(ntStatus)) {
  1287. SC_LOG(ERROR, "ScGetPrivilege: NtDuplicateToken Failed "
  1288. "FORMAT_NTSTATUS" "\n", ntStatus);
  1289. LocalFree(pTokenPrivilege);
  1290. return(RtlNtStatusToDosError(ntStatus));
  1291. }
  1292. //
  1293. // Add new privileges
  1294. //
  1295. ntStatus = NtAdjustPrivilegesToken(
  1296. newToken, // TokenHandle
  1297. FALSE, // DisableAllPrivileges
  1298. pTokenPrivilege, // NewState
  1299. 0, // Size of previous state buffer
  1300. NULL, // No info on previous state
  1301. &returnLen); // numBytes required for buffer.
  1302. if (!NT_SUCCESS(ntStatus)) {
  1303. SC_LOG(ERROR, "ScGetPrivilege: NtAdjustPrivilegesToken Failed "
  1304. "FORMAT_NTSTATUS" "\n", ntStatus);
  1305. LocalFree(pTokenPrivilege);
  1306. NtClose(newToken);
  1307. return(RtlNtStatusToDosError(ntStatus));
  1308. }
  1309. //
  1310. // Begin impersonating with the new token
  1311. //
  1312. ntStatus = NtSetInformationThread(
  1313. NtCurrentThread(),
  1314. ThreadImpersonationToken,
  1315. (PVOID)&newToken,
  1316. (ULONG)sizeof(HANDLE));
  1317. if (!NT_SUCCESS(ntStatus)) {
  1318. SC_LOG(ERROR, "ScGetPrivilege: NtAdjustPrivilegesToken Failed "
  1319. "FORMAT_NTSTATUS" "\n", ntStatus);
  1320. LocalFree(pTokenPrivilege);
  1321. NtClose(newToken);
  1322. return(RtlNtStatusToDosError(ntStatus));
  1323. }
  1324. LocalFree(pTokenPrivilege);
  1325. NtClose(newToken);
  1326. return(NO_ERROR);
  1327. }
  1328. DWORD
  1329. ScReleasePrivilege(
  1330. VOID
  1331. )
  1332. /*++
  1333. Routine Description:
  1334. This function relinquishes privileges obtained by calling ScGetPrivilege().
  1335. Arguments:
  1336. none
  1337. Return Value:
  1338. NO_ERROR - If the operation was completely successful.
  1339. Otherwise, it returns mapped return codes from the various NT
  1340. functions that are called.
  1341. --*/
  1342. {
  1343. NTSTATUS ntStatus;
  1344. HANDLE NewToken;
  1345. //
  1346. // Revert To Self.
  1347. //
  1348. NewToken = NULL;
  1349. ntStatus = NtSetInformationThread(
  1350. NtCurrentThread(),
  1351. ThreadImpersonationToken,
  1352. (PVOID)&NewToken,
  1353. (ULONG)sizeof(HANDLE));
  1354. if ( !NT_SUCCESS(ntStatus) ) {
  1355. return(RtlNtStatusToDosError(ntStatus));
  1356. }
  1357. return(NO_ERROR);
  1358. }
  1359. DWORD
  1360. ScGetClientSid(
  1361. OUT PTOKEN_USER *UserInfo
  1362. )
  1363. /*++
  1364. Routine Description:
  1365. This function looks up the SID of the API caller by impersonating
  1366. the caller.
  1367. Arguments:
  1368. UserInfo - Receives a pointer to a buffer allocated by this routine
  1369. which contains the TOKEN_USER information of the caller.
  1370. Return Value:
  1371. Returns the NT error mapped to Win32
  1372. --*/
  1373. {
  1374. DWORD status;
  1375. NTSTATUS ntstatus;
  1376. RPC_STATUS rpcstatus;
  1377. HANDLE CurrentThreadToken = NULL;
  1378. DWORD UserInfoSize;
  1379. *UserInfo = NULL;
  1380. if ((rpcstatus = RpcImpersonateClient(NULL)) != RPC_S_OK)
  1381. {
  1382. SC_LOG1(
  1383. ERROR,
  1384. "ScGetUserSid: Failed to impersonate client " FORMAT_RPC_STATUS "\n",
  1385. rpcstatus
  1386. );
  1387. ScLogEvent(
  1388. NEVENT_CALL_TO_FUNCTION_FAILED,
  1389. SC_RPC_IMPERSONATE,
  1390. rpcstatus
  1391. );
  1392. return ((DWORD) rpcstatus);
  1393. }
  1394. ntstatus = NtOpenThreadToken(
  1395. NtCurrentThread(),
  1396. TOKEN_QUERY,
  1397. TRUE, // Use service controller's security
  1398. // context to open thread token
  1399. &CurrentThreadToken
  1400. );
  1401. status = RtlNtStatusToDosError(ntstatus);
  1402. if (! NT_SUCCESS(ntstatus)) {
  1403. SC_LOG1(ERROR, "ScGetUserSid: NtOpenThreadToken failed "
  1404. FORMAT_NTSTATUS "\n", ntstatus);
  1405. goto Cleanup;
  1406. }
  1407. //
  1408. // Call NtQueryInformationToken the first time with 0 input size to
  1409. // get size of returned information.
  1410. //
  1411. ntstatus = NtQueryInformationToken(
  1412. CurrentThreadToken,
  1413. TokenUser, // User information class
  1414. (PVOID) *UserInfo, // Output
  1415. 0,
  1416. &UserInfoSize
  1417. );
  1418. if (ntstatus != STATUS_BUFFER_TOO_SMALL) {
  1419. SC_LOG1(ERROR, "ScGetUserSid: NtQueryInformationToken failed "
  1420. FORMAT_NTSTATUS ". Expected BUFFER_TOO_SMALL.\n", ntstatus);
  1421. status = RtlNtStatusToDosError(ntstatus);
  1422. goto Cleanup;
  1423. }
  1424. //
  1425. // Allocate buffer of returned size
  1426. //
  1427. *UserInfo = (PTOKEN_USER)LocalAlloc(
  1428. LMEM_ZEROINIT,
  1429. (UINT) UserInfoSize
  1430. );
  1431. if (*UserInfo == NULL) {
  1432. SC_LOG1(ERROR, "ScGetUserSid: LocalAlloc failed " FORMAT_DWORD
  1433. "\n", GetLastError());
  1434. status = ERROR_NOT_ENOUGH_MEMORY;
  1435. goto Cleanup;
  1436. }
  1437. //
  1438. // Call NtQueryInformationToken again with the correct buffer size.
  1439. //
  1440. ntstatus = NtQueryInformationToken(
  1441. CurrentThreadToken,
  1442. TokenUser, // User information class
  1443. (PVOID) *UserInfo, // Output
  1444. UserInfoSize,
  1445. &UserInfoSize
  1446. );
  1447. status = RtlNtStatusToDosError(ntstatus);
  1448. if (! NT_SUCCESS(ntstatus)) {
  1449. SC_LOG1(ERROR, "ScGetUserSid: NtQueryInformationToken failed "
  1450. FORMAT_NTSTATUS "\n", ntstatus);
  1451. LocalFree(*UserInfo);
  1452. *UserInfo = NULL;
  1453. }
  1454. Cleanup:
  1455. if (CurrentThreadToken != NULL)
  1456. {
  1457. NtClose(CurrentThreadToken);
  1458. }
  1459. if ((rpcstatus = RpcRevertToSelf()) != RPC_S_OK)
  1460. {
  1461. SC_LOG1(
  1462. ERROR,
  1463. "ScGetUserSid: Failed to revert to self " FORMAT_RPC_STATUS "\n",
  1464. rpcstatus
  1465. );
  1466. ScLogEvent(
  1467. NEVENT_CALL_TO_FUNCTION_FAILED,
  1468. SC_RPC_REVERT,
  1469. rpcstatus
  1470. );
  1471. SC_ASSERT(FALSE);
  1472. return ((DWORD) rpcstatus);
  1473. }
  1474. return status;
  1475. }