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.

10241 lines
275 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. security.c
  5. Abstract:
  6. This module implements Object Security APIs for Win32
  7. Author:
  8. Jim Anderson (JimA) 01-Jul-1991
  9. Robert Reichel (RobertRe) 01-Jan-92
  10. Revision History:
  11. --*/
  12. #include "advapi.h"
  13. #include <ntlsa.h>
  14. #include <rpc.h>
  15. #include <rpcndr.h>
  16. #include <stdio.h>
  17. #define LSADEFINED
  18. /////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // Private Routine Prototypes //
  21. // //
  22. /////////////////////////////////////////////////////////////////////////////
  23. VOID
  24. SepFormatAccountSid(
  25. PSID iSid,
  26. LPWSTR OutputBuffer
  27. );
  28. /////////////////////////////////////////////////////////////////////////////
  29. // //
  30. // Exported Routines //
  31. // //
  32. /////////////////////////////////////////////////////////////////////////////
  33. BOOL
  34. APIENTRY
  35. DuplicateToken(
  36. HANDLE ExistingTokenHandle,
  37. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
  38. PHANDLE DuplicateTokenHandle
  39. )
  40. /*++
  41. Routine Description:
  42. Create a new token that is a duplicate of an existing token. The
  43. new token will be an impersonation token of the supplied level.
  44. Arguments:
  45. ExistingTokenHandle - Is a handle to a token already open for
  46. TOKEN_DUPLICATE access.
  47. ImpersonationLevel - Supplies the impersonation level of the new
  48. token.
  49. DuplicateTokenHandle - Returns the handle to the new token. The
  50. handle will have TOKEN_IMPERSONATE and TOKEN_QUERY access to
  51. the new token.
  52. Return Value:
  53. Returns TRUE for success, FALSE for failure. Extended error status
  54. is available using GetLastError.
  55. --*/
  56. {
  57. return( DuplicateTokenEx( ExistingTokenHandle,
  58. TOKEN_IMPERSONATE | TOKEN_QUERY,
  59. NULL,
  60. ImpersonationLevel,
  61. TokenImpersonation,
  62. DuplicateTokenHandle
  63. ) );
  64. }
  65. BOOL
  66. APIENTRY
  67. DuplicateTokenEx(
  68. HANDLE hExistingToken,
  69. DWORD dwDesiredAccess,
  70. LPSECURITY_ATTRIBUTES lpTokenAttributes,
  71. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
  72. TOKEN_TYPE TokenType,
  73. PHANDLE phNewToken)
  74. /*++
  75. Routine Description:
  76. Create a new token that is a duplicate of an existing token. This API
  77. more fully exposes NtDuplicateToken .
  78. Arguments:
  79. hExistingToken - Is a handle to a token already open for
  80. TOKEN_DUPLICATE access.
  81. dwDesiredAccess - desired access rights to the new token, e.g.
  82. TOKEN_DUPLICATE, TOKEN_IMPERSONATE, etc.
  83. lpTokenAttributes - Desired security attributes for the new token.
  84. ImpersonationLevel - Supplies the impersonation level of the new token.
  85. TokenType - One of TokenImpersonation or TokenPrimary.
  86. phNewToken - Returns the handle to the new token.
  87. Return Value:
  88. Returns TRUE for success, FALSE for failure. Extended error status
  89. is available using GetLastError.
  90. --*/
  91. {
  92. OBJECT_ATTRIBUTES ObjA;
  93. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  94. PSECURITY_DESCRIPTOR SecurityDescriptor;
  95. NTSTATUS Status;
  96. ULONG Attributes;
  97. SecurityQualityOfService.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  98. SecurityQualityOfService.ImpersonationLevel = ImpersonationLevel;
  99. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  100. SecurityQualityOfService.EffectiveOnly = FALSE;
  101. if (lpTokenAttributes)
  102. {
  103. SecurityDescriptor = lpTokenAttributes->lpSecurityDescriptor;
  104. if (lpTokenAttributes->bInheritHandle)
  105. {
  106. Attributes = OBJ_INHERIT;
  107. }
  108. else
  109. {
  110. Attributes = 0;
  111. }
  112. }
  113. else
  114. {
  115. SecurityDescriptor = NULL;
  116. Attributes = 0;
  117. }
  118. InitializeObjectAttributes(
  119. &ObjA,
  120. NULL,
  121. Attributes,
  122. NULL,
  123. SecurityDescriptor
  124. );
  125. ObjA.SecurityQualityOfService = &SecurityQualityOfService;
  126. Status = NtDuplicateToken(
  127. hExistingToken,
  128. dwDesiredAccess,
  129. &ObjA,
  130. FALSE,
  131. TokenType,
  132. phNewToken
  133. );
  134. if ( !NT_SUCCESS( Status ) ) {
  135. BaseSetLastNTError(Status);
  136. return FALSE;
  137. }
  138. return( TRUE );
  139. }
  140. BOOL
  141. APIENTRY
  142. AllocateLocallyUniqueId(
  143. PLUID Luid
  144. )
  145. /*++
  146. Routine Description:
  147. Allocates a locally unique ID (LUID).
  148. Arguments:
  149. Luid - Supplies a pointer used to return the LUID.
  150. Return Value:
  151. Returns TRUE for success, FALSE for failure. Extended error status
  152. is available using GetLastError.
  153. --*/
  154. { NTSTATUS Status;
  155. Status = NtAllocateLocallyUniqueId( Luid );
  156. if ( !NT_SUCCESS( Status )) {
  157. BaseSetLastNTError( Status );
  158. return( FALSE );
  159. }
  160. return( TRUE );
  161. }
  162. BOOL
  163. APIENTRY
  164. AccessCheck (
  165. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  166. HANDLE ClientToken,
  167. DWORD DesiredAccess,
  168. PGENERIC_MAPPING GenericMapping,
  169. PPRIVILEGE_SET PrivilegeSet,
  170. LPDWORD PrivilegeSetLength,
  171. LPDWORD GrantedAccess,
  172. LPBOOL AccessStatus
  173. )
  174. /*++
  175. Routine Description:
  176. This routine compares the input Security Descriptor against the
  177. input token and indicates by its return value if access is granted
  178. or denied. If access is granted then the desired access mask
  179. becomes the granted access mask for the object.
  180. The semantics of the access check routine is described in the DSA
  181. Security Architecture workbook. Note that during an access check
  182. only the discretionary ACL is examined.
  183. Arguments:
  184. SecurityDescriptor - Supplies the security descriptor protecting the object
  185. being accessed
  186. ClientToken - Supplies the handle of the user's token.
  187. DesiredAccess - Supplies the desired access mask.
  188. GenericMapping - Supplies the generic mapping associated with this
  189. object type.
  190. PrivilegeSet - A pointer to a buffer that upon return will contain
  191. any privileges that were used to perform the access validation.
  192. If no privileges were used, the buffer will contain a privilege
  193. set consisting of zero privileges.
  194. PrivilegeSetLength - The size of the PrivilegeSet buffer in bytes.
  195. GrantedAccess - Returns an access mask describing the granted access.
  196. AccessStatus - Status value that may be returned indicating the
  197. reason why access was denied. Routines should avoid hardcoding a
  198. return value of STATUS_ACCESS_DENIED so that a different value can
  199. be returned when mandatory access control is implemented.
  200. Return Value:
  201. Returns TRUE for success, FALSE for failure. Extended error status
  202. is available using GetLastError.
  203. --*/
  204. {
  205. NTSTATUS Status;
  206. NTSTATUS RealStatus;
  207. Status = NtAccessCheck (
  208. pSecurityDescriptor,
  209. ClientToken,
  210. DesiredAccess,
  211. GenericMapping,
  212. PrivilegeSet,
  213. PrivilegeSetLength,
  214. GrantedAccess,
  215. &RealStatus
  216. );
  217. if ( !NT_SUCCESS(Status) ) {
  218. BaseSetLastNTError(Status);
  219. return FALSE;
  220. }
  221. if ( !NT_SUCCESS( RealStatus ) ) {
  222. BaseSetLastNTError( RealStatus );
  223. *AccessStatus = FALSE;
  224. return( TRUE );
  225. }
  226. *AccessStatus = TRUE;
  227. return TRUE;
  228. }
  229. BOOL
  230. APIENTRY
  231. AccessCheckByType (
  232. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  233. PSID PrincipalSelfSid,
  234. HANDLE ClientToken,
  235. DWORD DesiredAccess,
  236. POBJECT_TYPE_LIST ObjectTypeList,
  237. DWORD ObjectTypeListLength,
  238. PGENERIC_MAPPING GenericMapping,
  239. PPRIVILEGE_SET PrivilegeSet,
  240. LPDWORD PrivilegeSetLength,
  241. LPDWORD GrantedAccess,
  242. LPBOOL AccessStatus
  243. )
  244. /*++
  245. Routine Description:
  246. This routine compares the input Security Descriptor against the
  247. input token and indicates by its return value if access is granted
  248. or denied. If access is granted then the desired access mask
  249. becomes the granted access mask for the object.
  250. The semantics of the access check routine is described in the DSA
  251. Security Architecture workbook. Note that during an access check
  252. only the discretionary ACL is examined.
  253. Arguments:
  254. SecurityDescriptor - Supplies the security descriptor protecting the object
  255. being accessed
  256. PrincipalSelfSid - If the object being access checked is an object which
  257. represents a principal (e.g., a user object), this parameter should
  258. be the SID of the object. Any ACE containing the constant
  259. PRINCIPAL_SELF_SID is replaced by this SID.
  260. The parameter should be NULL if the object does not represent a principal.
  261. ClientToken - Supplies the handle of the user's token.
  262. DesiredAccess - Supplies the desired access mask.
  263. ObjectTypeList - Supplies a list of GUIDs representing the object (and
  264. sub-objects) being accessed. If no list is present, AccessCheckByType
  265. behaves identically to AccessCheck.
  266. ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
  267. GenericMapping - Supplies the generic mapping associated with this
  268. object type.
  269. PrivilegeSet - A pointer to a buffer that upon return will contain
  270. any privileges that were used to perform the access validation.
  271. If no privileges were used, the buffer will contain a privilege
  272. set consisting of zero privileges.
  273. PrivilegeSetLength - The size of the PrivilegeSet buffer in bytes.
  274. GrantedAccess - Returns an access mask describing the granted access.
  275. AccessStatus - Status value that may be returned indicating the
  276. reason why access was denied. Routines should avoid hardcoding a
  277. return value of STATUS_ACCESS_DENIED so that a different value can
  278. be returned when mandatory access control is implemented.
  279. Return Value:
  280. Returns TRUE for success, FALSE for failure. Extended error status
  281. is available using GetLastError.
  282. --*/
  283. {
  284. NTSTATUS Status;
  285. NTSTATUS RealStatus;
  286. Status = NtAccessCheckByType (
  287. pSecurityDescriptor,
  288. PrincipalSelfSid,
  289. ClientToken,
  290. DesiredAccess,
  291. ObjectTypeList,
  292. ObjectTypeListLength,
  293. GenericMapping,
  294. PrivilegeSet,
  295. PrivilegeSetLength,
  296. GrantedAccess,
  297. &RealStatus
  298. );
  299. if ( !NT_SUCCESS(Status) ) {
  300. BaseSetLastNTError(Status);
  301. return FALSE;
  302. }
  303. if ( !NT_SUCCESS( RealStatus ) ) {
  304. BaseSetLastNTError( RealStatus );
  305. *AccessStatus = FALSE;
  306. return( TRUE );
  307. }
  308. *AccessStatus = TRUE;
  309. return TRUE;
  310. }
  311. BOOL
  312. APIENTRY
  313. AccessCheckByTypeResultList (
  314. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  315. PSID PrincipalSelfSid,
  316. HANDLE ClientToken,
  317. DWORD DesiredAccess,
  318. POBJECT_TYPE_LIST ObjectTypeList,
  319. DWORD ObjectTypeListLength,
  320. PGENERIC_MAPPING GenericMapping,
  321. PPRIVILEGE_SET PrivilegeSet,
  322. LPDWORD PrivilegeSetLength,
  323. LPDWORD GrantedAccessList,
  324. LPDWORD AccessStatusList
  325. )
  326. /*++
  327. Routine Description:
  328. This routine compares the input Security Descriptor against the
  329. input token and indicates by its return value if access is granted
  330. or denied. If access is granted then the desired access mask
  331. becomes the granted access mask for the object.
  332. The semantics of the access check routine is described in the DSA
  333. Security Architecture workbook. Note that during an access check
  334. only the discretionary ACL is examined.
  335. Arguments:
  336. SecurityDescriptor - Supplies the security descriptor protecting the object
  337. being accessed
  338. PrincipalSelfSid - If the object being access checked is an object which
  339. represents a principal (e.g., a user object), this parameter should
  340. be the SID of the object. Any ACE containing the constant
  341. PRINCIPAL_SELF_SID is replaced by this SID.
  342. The parameter should be NULL if the object does not represent a principal.
  343. ClientToken - Supplies the handle of the user's token.
  344. DesiredAccess - Supplies the desired access mask.
  345. ObjectTypeList - Supplies a list of GUIDs representing the object (and
  346. sub-objects) being accessed. If no list is present, AccessCheckByType
  347. behaves identically to AccessCheck.
  348. ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
  349. GenericMapping - Supplies the generic mapping associated with this
  350. object type.
  351. PrivilegeSet - A pointer to a buffer that upon return will contain
  352. any privileges that were used to perform the access validation.
  353. If no privileges were used, the buffer will contain a privilege
  354. set consisting of zero privileges.
  355. PrivilegeSetLength - The size of the PrivilegeSet buffer in bytes.
  356. GrantedAccessList - Returns an access mask describing the granted access.
  357. AccessStatusList - Status value that may be returned indicating the
  358. reason why access was denied. Routines should avoid hardcoding a
  359. return value of STATUS_ACCESS_DENIED so that a different value can
  360. be returned when mandatory access control is implemented.
  361. Return Value:
  362. Returns TRUE for success, FALSE for failure. Extended error status
  363. is available using GetLastError.
  364. --*/
  365. {
  366. NTSTATUS Status;
  367. NTSTATUS RealStatus;
  368. ULONG i;
  369. ASSERT (sizeof(NTSTATUS) == sizeof(DWORD) );
  370. Status = NtAccessCheckByTypeResultList (
  371. pSecurityDescriptor,
  372. PrincipalSelfSid,
  373. ClientToken,
  374. DesiredAccess,
  375. ObjectTypeList,
  376. ObjectTypeListLength,
  377. GenericMapping,
  378. PrivilegeSet,
  379. PrivilegeSetLength,
  380. GrantedAccessList,
  381. (PNTSTATUS)AccessStatusList
  382. );
  383. if ( !NT_SUCCESS(Status) ) {
  384. BaseSetLastNTError(Status);
  385. return FALSE;
  386. }
  387. //
  388. // Loop converting the array of NT status codes to WIN status codes.
  389. //
  390. for ( i=0; i<ObjectTypeListLength; i++ ) {
  391. if ( AccessStatusList[i] == STATUS_SUCCESS ) {
  392. AccessStatusList[i] = NO_ERROR;
  393. } else {
  394. AccessStatusList[i] = RtlNtStatusToDosError( AccessStatusList[i] );
  395. }
  396. }
  397. return TRUE;
  398. }
  399. BOOL
  400. APIENTRY
  401. OpenProcessToken (
  402. HANDLE ProcessHandle,
  403. DWORD DesiredAccess,
  404. PHANDLE TokenHandle
  405. )
  406. /*++
  407. Routine Description:
  408. Open a token object associated with a process and return a handle
  409. that may be used to access that token.
  410. Arguments:
  411. ProcessHandle - Specifies the process whose token is to be
  412. opened.
  413. DesiredAccess - Is an access mask indicating which access types
  414. are desired to the token. These access types are reconciled
  415. with the Discretionary Access Control list of the token to
  416. determine whether the accesses will be granted or denied.
  417. TokenHandle - Receives the handle of the newly opened token.
  418. Return Value:
  419. Returns TRUE for success, FALSE for failure. Extended error status
  420. is available using GetLastError.
  421. --*/
  422. {
  423. NTSTATUS Status;
  424. Status = NtOpenProcessToken (
  425. ProcessHandle,
  426. DesiredAccess,
  427. TokenHandle
  428. );
  429. if ( !NT_SUCCESS(Status) ) {
  430. BaseSetLastNTError(Status);
  431. return FALSE;
  432. }
  433. return TRUE;
  434. }
  435. BOOL
  436. APIENTRY
  437. OpenThreadToken (
  438. HANDLE ThreadHandle,
  439. DWORD DesiredAccess,
  440. BOOL OpenAsSelf,
  441. PHANDLE TokenHandle
  442. )
  443. /*++
  444. Routine Description:
  445. Open a token object associated with a thread and return a handle that
  446. may be used to access that token.
  447. Arguments:
  448. ThreadHandle - Specifies the thread whose token is to be opened.
  449. DesiredAccess - Is an access mask indicating which access types
  450. are desired to the token. These access types are reconciled
  451. with the Discretionary Access Control list of the token to
  452. determine whether the accesses will be granted or denied.
  453. OpenAsSelf - Is a boolean value indicating whether the access should
  454. be made using the calling thread's current security context, which
  455. may be that of a client if impersonating, or using the caller's
  456. process-level security context. A value of FALSE indicates the
  457. caller's current context should be used un-modified. A value of
  458. TRUE indicates the request should be fulfilled using the process
  459. level security context.
  460. This parameter is necessary to allow a server process to open
  461. a client's token when the client specified IDENTIFICATION level
  462. impersonation. In this case, the caller would not be able to
  463. open the client's token using the client's context (because you
  464. can't create executive level objects using IDENTIFICATION level
  465. impersonation).
  466. TokenHandle - Receives the handle of the newly opened token.
  467. Return Value:
  468. Returns TRUE for success, FALSE for failure. Extended error status
  469. is available using GetLastError.
  470. --*/
  471. {
  472. NTSTATUS Status;
  473. Status = NtOpenThreadToken (
  474. ThreadHandle,
  475. DesiredAccess,
  476. (BOOLEAN)OpenAsSelf,
  477. TokenHandle
  478. );
  479. if ( !NT_SUCCESS(Status) ) {
  480. BaseSetLastNTError(Status);
  481. return FALSE;
  482. }
  483. return TRUE;
  484. }
  485. BOOL
  486. APIENTRY
  487. GetTokenInformation (
  488. HANDLE TokenHandle,
  489. TOKEN_INFORMATION_CLASS TokenInformationClass,
  490. PVOID TokenInformation,
  491. DWORD TokenInformationLength,
  492. PDWORD ReturnLength
  493. )
  494. /*++
  495. Routine Description:
  496. Retrieve information about a specified token.
  497. Arguments:
  498. TokenHandle - Provides a handle to the token to operate on.
  499. TokenInformationClass - The token information class about which
  500. to retrieve information.
  501. TokenInformation - The buffer to receive the requested class of
  502. information. The buffer must be aligned on at least a
  503. longword boundary. The actual structures returned are
  504. dependent upon the information class requested, as defined in
  505. the TokenInformationClass parameter description.
  506. TokenInformation Format By Information Class:
  507. TokenUser => TOKEN_USER data structure. TOKEN_QUERY
  508. access is needed to retrieve this information about a
  509. token.
  510. TokenGroups => TOKEN_GROUPS data structure. TOKEN_QUERY
  511. access is needed to retrieve this information about a
  512. token.
  513. TokenPrivileges => TOKEN_PRIVILEGES data structure.
  514. TOKEN_QUERY access is needed to retrieve this information
  515. about a token.
  516. TokenOwner => TOKEN_OWNER data structure. TOKEN_QUERY
  517. access is needed to retrieve this information about a
  518. token.
  519. TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure.
  520. TOKEN_QUERY access is needed to retrieve this information
  521. about a token.
  522. TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure.
  523. TOKEN_QUERY access is needed to retrieve this information
  524. about a token.
  525. TokenSource => TOKEN_SOURCE data structure.
  526. TOKEN_QUERY_SOURCE access is needed to retrieve this
  527. information about a token.
  528. TokenType => TOKEN_TYPE data structure.
  529. TOKEN_QUERY access is needed to retrieve this information
  530. about a token.
  531. TokenStatistics => TOKEN_STATISTICS data structure.
  532. TOKEN_QUERY access is needed to retrieve this
  533. information about a token.
  534. TokenSessionId => ULONG. TOKEN_QUERY access is needed to
  535. query the Session ID of the token.
  536. TokenInformationLength - Indicates the length, in bytes, of the
  537. TokenInformation buffer.
  538. ReturnLength - This parameter receives the actual length of the
  539. requested information. If this value is larger than that
  540. provided by the TokenInformationLength parameter, then the
  541. buffer provided to receive the requested information is not
  542. large enough to hold that data and no data is returned.
  543. If the queried class is TokenDefaultDacl and there is no
  544. default Dacl established for the token, then the return
  545. length will be returned as zero, and no data will be returned.
  546. Return Value:
  547. Returns TRUE for success, FALSE for failure. Extended error status
  548. is available using GetLastError.
  549. --*/
  550. {
  551. NTSTATUS Status;
  552. Status = NtQueryInformationToken (
  553. TokenHandle,
  554. TokenInformationClass,
  555. TokenInformation,
  556. TokenInformationLength,
  557. ReturnLength
  558. );
  559. if ( !NT_SUCCESS(Status) ) {
  560. BaseSetLastNTError(Status);
  561. return FALSE;
  562. }
  563. return TRUE;
  564. }
  565. BOOL
  566. APIENTRY
  567. SetTokenInformation (
  568. HANDLE TokenHandle,
  569. TOKEN_INFORMATION_CLASS TokenInformationClass,
  570. PVOID TokenInformation,
  571. DWORD TokenInformationLength
  572. )
  573. /*++
  574. Routine Description:
  575. Modify information in a specified token.
  576. Arguments:
  577. TokenHandle - Provides a handle to the token to operate on.
  578. TokenInformationClass - The token information class being set.
  579. TokenInformation - The buffer containing the new values for the
  580. specified class of information. The buffer must be aligned
  581. on at least a longword boundary. The actual structures
  582. provided are dependent upon the information class specified,
  583. as defined in the TokenInformationClass parameter
  584. description.
  585. TokenInformation Format By Information Class:
  586. TokenUser => This value is not a valid value for this API.
  587. The User ID may not be replaced.
  588. TokenGroups => This value is not a valid value for this
  589. API. The Group IDs may not be replaced. However, groups
  590. may be enabled and disabled using NtAdjustGroupsToken().
  591. TokenPrivileges => This value is not a valid value for
  592. this API. Privilege information may not be replaced.
  593. However, privileges may be explicitly enabled and disabled
  594. using the NtAdjustPrivilegesToken API.
  595. TokenOwner => TOKEN_OWNER data structure.
  596. TOKEN_ADJUST_DEFAULT access is needed to replace this
  597. information in a token. The owner values that may be
  598. specified are restricted to the user and group IDs with an
  599. attribute indicating they may be assigned as the owner of
  600. objects.
  601. TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure.
  602. TOKEN_ADJUST_DEFAULT access is needed to replace this
  603. information in a token. The primary group values that may
  604. be specified are restricted to be one of the group IDs
  605. already in the token.
  606. TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure.
  607. TOKEN_ADJUST_DEFAULT access is needed to replace this
  608. information in a token. The ACL provided as a new default
  609. discretionary ACL is not validated for structural
  610. correctness or consistency.
  611. TokenSource => This value is not a valid value for this
  612. API. The source name and context handle may not be
  613. replaced.
  614. TokenStatistics => This value is not a valid value for this
  615. API. The statistics of a token are read-only.
  616. TokenSessionId => ULONG to set the token session. Must have
  617. TOKEN_ADJUST_SESSIONID and TCB privilege.
  618. TokenSessionReference => ULONG. Must be zero. Must have
  619. TCB privilege to dereference the logon session. This info class
  620. will remove a reference for the logon session, and mark the token
  621. as not referencing the session.
  622. TokenInformationLength - Indicates the length, in bytes, of the
  623. TokenInformation buffer. This is only the length of the primary
  624. buffer. All extensions of the primary buffer are self describing.
  625. Return Value:
  626. Returns TRUE for success, FALSE for failure. Extended error status
  627. is available using GetLastError.
  628. --*/
  629. {
  630. NTSTATUS Status;
  631. Status = NtSetInformationToken (
  632. TokenHandle,
  633. TokenInformationClass,
  634. TokenInformation,
  635. TokenInformationLength
  636. );
  637. if ( !NT_SUCCESS(Status) ) {
  638. BaseSetLastNTError(Status);
  639. return FALSE;
  640. }
  641. return TRUE;
  642. }
  643. BOOL
  644. APIENTRY
  645. AdjustTokenPrivileges (
  646. HANDLE TokenHandle,
  647. BOOL DisableAllPrivileges,
  648. PTOKEN_PRIVILEGES NewState,
  649. DWORD BufferLength,
  650. PTOKEN_PRIVILEGES PreviousState,
  651. PDWORD ReturnLength
  652. )
  653. /*++
  654. Routine Description:
  655. This routine is used to disable or enable privileges in the
  656. specified token. The absence of some of the privileges listed to
  657. be changed won't effect the successful modification of the
  658. privileges that are in the token. The previous enabled/disabled
  659. state of changed privileges may optionally be capture (for
  660. resetting later).
  661. TOKEN_ADJUST_PRIVILEGES access is required to enable or disable
  662. privileges in a token.
  663. Arguments:
  664. TokenHandle - Provides a handle to the token to operate on.
  665. DisableAllPrivileges - This boolean parameter may be
  666. used to disable all privileges assigned to the token. If
  667. this parameter is specified as TRUE, then the NewState parameter is
  668. ignored.
  669. NewState - This (optional) parameter points to a TOKEN_PRIVILEGES
  670. data structure containing the privileges whose states are to
  671. be adjusted (disabled or enabled). Only the Enabled flag of
  672. the attributes associated with each privilege is used. It
  673. provides the new value that is to be assigned to the privilege
  674. in the token.
  675. BufferLength - This optional parameter indicates the length (in
  676. bytes) of the PreviousState buffer. This value must be
  677. provided if the PreviousState parameter is provided.
  678. PreviousState - This (optional) parameter points to a buffer to
  679. receive the state of any privileges actually changed by this
  680. request. This information is formated as a TOKEN_PRIVILEGES
  681. data structure which may be passed as the NewState parameter
  682. in a subsequent call to this routine to restore the original
  683. state of those privilges. TOKEN_QUERY access is needed to use
  684. this parameter.
  685. If this buffer does not contain enough space to receive the
  686. complete list of modified privileges, then no privilege
  687. states are changed and STATUS_BUFFER_TOO_SMALL is returned.
  688. In this case, the ReturnLength OUT parameter will
  689. contain the actual number of bytes needed to hold the
  690. information.
  691. ReturnLength - Indicates the actual number of bytes needed to
  692. contain the previous privilege state information. This
  693. parameter is ignored if the PreviousState argument is not
  694. passed.
  695. Return Value:
  696. Returns TRUE for success, FALSE for failure. Extended error status
  697. is available using GetLastError.
  698. --*/
  699. {
  700. NTSTATUS Status;
  701. Status = NtAdjustPrivilegesToken (
  702. TokenHandle,
  703. (BOOLEAN)DisableAllPrivileges,
  704. NewState,
  705. BufferLength,
  706. PreviousState,
  707. ReturnLength
  708. );
  709. //
  710. // We need to set last error even for success because that
  711. // is the only way to tell if the api successfully assigned
  712. // all privileges. That is, STATUS_NOT_ALL_ASSIGNED is a
  713. // Success severity level.
  714. //
  715. BaseSetLastNTError(Status);
  716. if ( !NT_SUCCESS(Status) ) {
  717. return FALSE;
  718. }
  719. return TRUE;
  720. }
  721. BOOL
  722. APIENTRY
  723. AdjustTokenGroups (
  724. HANDLE TokenHandle,
  725. BOOL ResetToDefault,
  726. PTOKEN_GROUPS NewState,
  727. DWORD BufferLength,
  728. PTOKEN_GROUPS PreviousState,
  729. PDWORD ReturnLength
  730. )
  731. /*++
  732. Routine Description:
  733. This routine is used to disable or enable groups in the specified
  734. token. The absence of some of the groups listed to be changed
  735. won't effect the successful modification of the groups that are in
  736. the token. The previous enabled/disabled state of changed groups
  737. may optionally be capture (for resetting later).
  738. TOKEN_ADJUST_GROUPS access is required to enable or disable groups
  739. in a token
  740. Note that mandatory groups can not be disabled. An attempt
  741. disable any mandatory groups will cause the call to fail, leaving
  742. the state of all groups unchanged.
  743. Arguments:
  744. TokenHandle - Provides a handle to the token to operate on.
  745. ResetToDefault - The parameter indicates whether all the groups
  746. in the token are to be reset to their default enabled/disabled
  747. state.
  748. NewState - This parameter points to a TOKEN_GROUPS data structure
  749. containing the groups whose states are to be adjusted
  750. (disabled or enabled). Only the Enabled flag of the
  751. attributes associated with each group is used. It provides
  752. the new value that is to be assigned to the group in the
  753. token. If the ResetToDefault argument is specified as TRUE,
  754. then this argument is ignored. Otherwise, it must be passed.
  755. BufferLength - This optional parameter indicates the length (in
  756. bytes) of the PreviousState buffer. This value must be
  757. provided if the PreviousState parameter is provided.
  758. PreviousState - This (optional) parameter points to a buffer to
  759. receive the state of any groups actually changed by this
  760. request. This information is formated as a TOKEN_GROUPS data
  761. structure which may be passed as the NewState parameter in a
  762. subsequent call to NtAdjustGroups to restore the original state
  763. of those groups. TOKEN_QUERY access is needed to use this
  764. parameter.
  765. If this buffer does not contain enough space to receive the
  766. complete list of modified groups, then no group states are
  767. changed and STATUS_BUFFER_TOO_SMALL is returned. In this
  768. case, the ReturnLength return parameter will contain the
  769. actual number of bytes needed to hold the information.
  770. ReturnLength - Indicates the actual number of bytes needed to
  771. contain the previous group state information.
  772. This parameter is ignored if the PreviousState argument is not
  773. passed.
  774. Return Value:
  775. Returns TRUE for success, FALSE for failure. Extended error status
  776. is available using GetLastError.
  777. --*/
  778. {
  779. NTSTATUS Status;
  780. Status = NtAdjustGroupsToken (
  781. TokenHandle,
  782. (BOOLEAN)ResetToDefault,
  783. NewState,
  784. BufferLength,
  785. PreviousState,
  786. ReturnLength
  787. );
  788. //
  789. // We need to set last error even for success because that
  790. // is the only way to tell if the api successfully assigned
  791. // all groups. That is, STATUS_NOT_ALL_ASSIGNED is a
  792. // Success severity level.
  793. //
  794. BaseSetLastNTError(Status);
  795. if ( !NT_SUCCESS(Status) ) {
  796. return FALSE;
  797. }
  798. return TRUE;
  799. }
  800. BOOL
  801. APIENTRY
  802. PrivilegeCheck (
  803. HANDLE ClientToken,
  804. PPRIVILEGE_SET RequiredPrivileges,
  805. LPBOOL pfResult
  806. )
  807. /*++
  808. Routine Description:
  809. This routine tests the caller's client's security context to see if it
  810. contains the specified privileges.
  811. Arguments:
  812. ClientToken - A handle to a token object representing a client
  813. attempting access. This handle must be obtained from a
  814. communication session layer, such as from an LPC Port or Local
  815. Named Pipe, to prevent possible security policy violations.
  816. RequiredPrivileges - Points to a set of privileges. The client's
  817. security context is to be checked to see which of the specified
  818. privileges are present. The results will be indicated in the
  819. attributes associated with each privilege. Note that
  820. flags in this parameter indicate whether all the privileges listed
  821. are needed, or any of the privileges.
  822. pfResult - Receives a boolean flag indicating whether the client
  823. has all the specified privileges or not. A value of TRUE
  824. indicates the client has all the specified privileges.
  825. Otherwise a value of FALSE is returned.
  826. Return Value:
  827. Returns TRUE for success, FALSE for failure. Extended error status
  828. is available using GetLastError.
  829. --*/
  830. {
  831. NTSTATUS Status;
  832. BOOLEAN Result = FALSE;
  833. Status = NtPrivilegeCheck (
  834. ClientToken,
  835. RequiredPrivileges,
  836. &Result
  837. );
  838. *pfResult = Result;
  839. if ( !NT_SUCCESS(Status) ) {
  840. BaseSetLastNTError(Status);
  841. return FALSE;
  842. }
  843. return TRUE;
  844. }
  845. BOOL
  846. APIENTRY
  847. AccessCheckAndAuditAlarmW(
  848. LPCWSTR SubsystemName,
  849. PVOID HandleId,
  850. LPWSTR ObjectTypeName,
  851. LPWSTR ObjectName,
  852. PSECURITY_DESCRIPTOR SecurityDescriptor,
  853. DWORD DesiredAccess,
  854. PGENERIC_MAPPING GenericMapping,
  855. BOOL ObjectCreation,
  856. LPDWORD GrantedAccess,
  857. LPBOOL AccessStatus,
  858. LPBOOL pfGenerateOnClose
  859. )
  860. /*++
  861. Routine Description:
  862. This routine compares the input Security Descriptor against the
  863. caller's impersonation token and indicates if access is granted or
  864. denied. If access is granted then the desired access mask becomes
  865. the granted access mask for the object. The semantics of the
  866. access check routine is described in the DSA Security Architecture
  867. workbook.
  868. This routine will also generate any necessary audit messages as a
  869. result of the access attempt.
  870. Arguments:
  871. SubsystemName - Supplies a name string identifying the subsystem
  872. calling the routine.
  873. HandleId - A unique value that will be used to represent the client's
  874. handle to the object. This value is ignored (and may be re-used)
  875. if the access is denied.
  876. ObjectTypeName - Supplies the name of the type of the object being
  877. created or accessed.
  878. ObjectName - Supplies the name of the object being created or accessed.
  879. SecurityDescriptor - A pointer to the Security Descriptor against which
  880. acccess is to be checked.
  881. DesiredAccess - The desired acccess mask. This mask must have been
  882. previously mapped to contain no generic accesses.
  883. GenericMapping - Supplies a pointer to the generic mapping associated
  884. with this object type.
  885. ObjectCreation - A boolean flag indicated whether the access will
  886. result in a new object being created if granted. A value of TRUE
  887. indicates an object will be created, FALSE indicates an existing
  888. object will be opened.
  889. GrantedAccess - Receives a masking indicating which accesses have been
  890. granted (only valid on success).
  891. AccessStatus - Receives an indication of the success or failure of the
  892. access check. If access is granted, STATUS_SUCCESS is returned.
  893. If access is denied, a value appropriate for return to the client
  894. is returned. This will be STATUS_ACCESS_DENIED or, when mandatory
  895. access controls are implemented, STATUS_OBJECT_NOT_FOUND.
  896. pfGenerateOnClose - Points to a boolean that is set by the audity
  897. generation routine and must be passed to ObjectCloseAuditAlarm
  898. when the object handle is closed.
  899. Return Value:
  900. Returns TRUE for success, FALSE for failure. Extended error status
  901. is available using GetLastError.
  902. --*/
  903. {
  904. NTSTATUS Status;
  905. NTSTATUS RealAccessStatus;
  906. BOOLEAN GenerateOnClose = FALSE;
  907. UNICODE_STRING Subsystem;
  908. UNICODE_STRING ObjectType;
  909. UNICODE_STRING Object;
  910. RtlInitUnicodeString(
  911. &Subsystem,
  912. SubsystemName
  913. );
  914. RtlInitUnicodeString(
  915. &ObjectType,
  916. ObjectTypeName
  917. );
  918. RtlInitUnicodeString(
  919. &Object,
  920. ObjectName
  921. );
  922. Status = NtAccessCheckAndAuditAlarm (
  923. &Subsystem,
  924. HandleId,
  925. &ObjectType,
  926. &Object,
  927. SecurityDescriptor,
  928. DesiredAccess,
  929. GenericMapping,
  930. (BOOLEAN)ObjectCreation,
  931. GrantedAccess,
  932. &RealAccessStatus,
  933. &GenerateOnClose
  934. );
  935. *pfGenerateOnClose = (BOOL)GenerateOnClose;
  936. if ( !NT_SUCCESS(Status) ) {
  937. BaseSetLastNTError(Status);
  938. return FALSE;
  939. }
  940. if ( !NT_SUCCESS( RealAccessStatus )) {
  941. *AccessStatus = FALSE;
  942. BaseSetLastNTError( RealAccessStatus );
  943. return( TRUE );
  944. }
  945. *AccessStatus = TRUE;
  946. return TRUE;
  947. }
  948. BOOL
  949. APIENTRY
  950. AccessCheckByTypeAndAuditAlarmW (
  951. LPCWSTR SubsystemName,
  952. LPVOID HandleId,
  953. LPCWSTR ObjectTypeName,
  954. LPCWSTR ObjectName,
  955. PSECURITY_DESCRIPTOR SecurityDescriptor,
  956. PSID PrincipalSelfSid,
  957. DWORD DesiredAccess,
  958. AUDIT_EVENT_TYPE AuditType,
  959. DWORD Flags,
  960. POBJECT_TYPE_LIST ObjectTypeList,
  961. DWORD ObjectTypeListLength,
  962. PGENERIC_MAPPING GenericMapping,
  963. BOOL ObjectCreation,
  964. LPDWORD GrantedAccess,
  965. LPBOOL AccessStatus,
  966. LPBOOL pfGenerateOnClose
  967. )
  968. /*++
  969. Routine Description:
  970. This routine compares the input Security Descriptor against the
  971. caller's impersonation token and indicates if access is granted or
  972. denied. If access is granted then the desired access mask becomes
  973. the granted access mask for the object. The semantics of the
  974. access check routine is described in the DSA Security Architecture
  975. workbook.
  976. This routine will also generate any necessary audit messages as a
  977. result of the access attempt.
  978. Arguments:
  979. SubsystemName - Supplies a name string identifying the subsystem
  980. calling the routine.
  981. HandleId - A unique value that will be used to represent the client's
  982. handle to the object. This value is ignored (and may be re-used)
  983. if the access is denied.
  984. ObjectTypeName - Supplies the name of the type of the object being
  985. created or accessed.
  986. ObjectName - Supplies the name of the object being created or accessed.
  987. SecurityDescriptor - A pointer to the Security Descriptor against which
  988. acccess is to be checked.
  989. PrincipalSelfSid - If the object being access checked is an object which
  990. represents a principal (e.g., a user object), this parameter should
  991. be the SID of the object. Any ACE containing the constant
  992. PRINCIPAL_SELF_SID is replaced by this SID.
  993. The parameter should be NULL if the object does not represent a principal.
  994. DesiredAccess - The desired acccess mask. This mask must have been
  995. previously mapped to contain no generic accesses.
  996. AuditType - Specifies the type of audit to be generated. Valid values
  997. are: AuditEventObjectAccess and AuditEventDirectoryServiceAccess.
  998. Flags - Flags modifying the execution of the API:
  999. AUDIT_ALLOW_NO_PRIVILEGE - If the caller does not have AuditPrivilege,
  1000. the call will silently continue to check access and will
  1001. generate no audit.
  1002. ObjectTypeList - Supplies a list of GUIDs representing the object (and
  1003. sub-objects) being accessed. If no list is present, AccessCheckByType
  1004. behaves identically to AccessCheck.
  1005. ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
  1006. GenericMapping - Supplies a pointer to the generic mapping associated
  1007. with this object type.
  1008. ObjectCreation - A boolean flag indicated whether the access will
  1009. result in a new object being created if granted. A value of TRUE
  1010. indicates an object will be created, FALSE indicates an existing
  1011. object will be opened.
  1012. GrantedAccess - Receives a masking indicating which accesses have been
  1013. granted (only valid on success).
  1014. AccessStatus - Receives an indication of the success or failure of the
  1015. access check. If access is granted, STATUS_SUCCESS is returned.
  1016. If access is denied, a value appropriate for return to the client
  1017. is returned. This will be STATUS_ACCESS_DENIED or, when mandatory
  1018. access controls are implemented, STATUS_OBJECT_NOT_FOUND.
  1019. pfGenerateOnClose - Points to a boolean that is set by the audity
  1020. generation routine and must be passed to ObjectCloseAuditAlarm
  1021. when the object handle is closed.
  1022. Return Value:
  1023. Returns TRUE for success, FALSE for failure. Extended error status
  1024. is available using GetLastError.
  1025. --*/
  1026. {
  1027. NTSTATUS Status;
  1028. NTSTATUS RealAccessStatus;
  1029. BOOLEAN GenerateOnClose = FALSE;
  1030. UNICODE_STRING Subsystem;
  1031. UNICODE_STRING ObjectType;
  1032. UNICODE_STRING Object;
  1033. RtlInitUnicodeString(
  1034. &Subsystem,
  1035. SubsystemName
  1036. );
  1037. RtlInitUnicodeString(
  1038. &ObjectType,
  1039. ObjectTypeName
  1040. );
  1041. RtlInitUnicodeString(
  1042. &Object,
  1043. ObjectName
  1044. );
  1045. Status = NtAccessCheckByTypeAndAuditAlarm (
  1046. &Subsystem,
  1047. HandleId,
  1048. &ObjectType,
  1049. &Object,
  1050. SecurityDescriptor,
  1051. PrincipalSelfSid,
  1052. DesiredAccess,
  1053. AuditType,
  1054. Flags,
  1055. ObjectTypeList,
  1056. ObjectTypeListLength,
  1057. GenericMapping,
  1058. (BOOLEAN)ObjectCreation,
  1059. GrantedAccess,
  1060. &RealAccessStatus,
  1061. &GenerateOnClose
  1062. );
  1063. *pfGenerateOnClose = (BOOL)GenerateOnClose;
  1064. if ( !NT_SUCCESS(Status) ) {
  1065. BaseSetLastNTError(Status);
  1066. return FALSE;
  1067. }
  1068. if ( !NT_SUCCESS( RealAccessStatus )) {
  1069. *AccessStatus = FALSE;
  1070. BaseSetLastNTError( RealAccessStatus );
  1071. return( TRUE );
  1072. }
  1073. *AccessStatus = TRUE;
  1074. return TRUE;
  1075. }
  1076. BOOL
  1077. APIENTRY
  1078. AccessCheckByTypeResultListAndAuditAlarmW (
  1079. LPCWSTR SubsystemName,
  1080. LPVOID HandleId,
  1081. LPCWSTR ObjectTypeName,
  1082. LPCWSTR ObjectName,
  1083. PSECURITY_DESCRIPTOR SecurityDescriptor,
  1084. PSID PrincipalSelfSid,
  1085. DWORD DesiredAccess,
  1086. AUDIT_EVENT_TYPE AuditType,
  1087. DWORD Flags,
  1088. POBJECT_TYPE_LIST ObjectTypeList,
  1089. DWORD ObjectTypeListLength,
  1090. PGENERIC_MAPPING GenericMapping,
  1091. BOOL ObjectCreation,
  1092. LPDWORD GrantedAccessList,
  1093. LPDWORD AccessStatusList,
  1094. LPBOOL pfGenerateOnClose
  1095. )
  1096. /*++
  1097. Routine Description:
  1098. This routine compares the input Security Descriptor against the
  1099. caller's impersonation token and indicates if access is granted or
  1100. denied. If access is granted then the desired access mask becomes
  1101. the granted access mask for the object. The semantics of the
  1102. access check routine is described in the DSA Security Architecture
  1103. workbook.
  1104. This routine will also generate any necessary audit messages as a
  1105. result of the access attempt.
  1106. Arguments:
  1107. SubsystemName - Supplies a name string identifying the subsystem
  1108. calling the routine.
  1109. HandleId - A unique value that will be used to represent the client's
  1110. handle to the object. This value is ignored (and may be re-used)
  1111. if the access is denied.
  1112. ObjectTypeName - Supplies the name of the type of the object being
  1113. created or accessed.
  1114. ObjectName - Supplies the name of the object being created or accessed.
  1115. SecurityDescriptor - A pointer to the Security Descriptor against which
  1116. acccess is to be checked.
  1117. PrincipalSelfSid - If the object being access checked is an object which
  1118. represents a principal (e.g., a user object), this parameter should
  1119. be the SID of the object. Any ACE containing the constant
  1120. PRINCIPAL_SELF_SID is replaced by this SID.
  1121. The parameter should be NULL if the object does not represent a principal.
  1122. DesiredAccess - The desired acccess mask. This mask must have been
  1123. previously mapped to contain no generic accesses.
  1124. AuditType - Specifies the type of audit to be generated. Valid values
  1125. are: AuditEventObjectAccess and AuditEventDirectoryServiceAccess.
  1126. Flags - Flags modifying the execution of the API:
  1127. AUDIT_ALLOW_NO_PRIVILEGE - If the called does not have AuditPrivilege,
  1128. the call will silently continue to check access and will
  1129. generate no audit.
  1130. ObjectTypeList - Supplies a list of GUIDs representing the object (and
  1131. sub-objects) being accessed. If no list is present, AccessCheckByType
  1132. behaves identically to AccessCheck.
  1133. ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
  1134. GenericMapping - Supplies a pointer to the generic mapping associated
  1135. with this object type.
  1136. ObjectCreation - A boolean flag indicated whether the access will
  1137. result in a new object being created if granted. A value of TRUE
  1138. indicates an object will be created, FALSE indicates an existing
  1139. object will be opened.
  1140. GrantedAccessList - Returns an access mask describing the granted access.
  1141. AccessStatusList - Status value that may be returned indicating the
  1142. reason why access was denied. Routines should avoid hardcoding a
  1143. return value of STATUS_ACCESS_DENIED so that a different value can
  1144. be returned when mandatory access control is implemented.
  1145. pfGenerateOnClose - Points to a boolean that is set by the audity
  1146. generation routine and must be passed to ObjectCloseAuditAlarm
  1147. when the object handle is closed.
  1148. Return Value:
  1149. Returns TRUE for success, FALSE for failure. Extended error status
  1150. is available using GetLastError.
  1151. --*/
  1152. {
  1153. NTSTATUS Status;
  1154. NTSTATUS RealAccessStatus;
  1155. BOOLEAN GenerateOnClose = FALSE;
  1156. UNICODE_STRING Subsystem;
  1157. UNICODE_STRING ObjectType;
  1158. UNICODE_STRING Object;
  1159. ULONG i;
  1160. RtlInitUnicodeString(
  1161. &Subsystem,
  1162. SubsystemName
  1163. );
  1164. RtlInitUnicodeString(
  1165. &ObjectType,
  1166. ObjectTypeName
  1167. );
  1168. RtlInitUnicodeString(
  1169. &Object,
  1170. ObjectName
  1171. );
  1172. Status = NtAccessCheckByTypeResultListAndAuditAlarm (
  1173. &Subsystem,
  1174. HandleId,
  1175. &ObjectType,
  1176. &Object,
  1177. SecurityDescriptor,
  1178. PrincipalSelfSid,
  1179. DesiredAccess,
  1180. AuditType,
  1181. Flags,
  1182. ObjectTypeList,
  1183. ObjectTypeListLength,
  1184. GenericMapping,
  1185. (BOOLEAN)ObjectCreation,
  1186. GrantedAccessList,
  1187. AccessStatusList,
  1188. &GenerateOnClose
  1189. );
  1190. *pfGenerateOnClose = (BOOL)GenerateOnClose;
  1191. if ( !NT_SUCCESS(Status) ) {
  1192. BaseSetLastNTError(Status);
  1193. return FALSE;
  1194. }
  1195. //
  1196. // Loop converting the array of NT status codes to WIN status codes.
  1197. //
  1198. for ( i=0; i<ObjectTypeListLength; i++ ) {
  1199. if ( AccessStatusList[i] == STATUS_SUCCESS ) {
  1200. AccessStatusList[i] = NO_ERROR;
  1201. } else {
  1202. AccessStatusList[i] = RtlNtStatusToDosError( AccessStatusList[i] );
  1203. }
  1204. }
  1205. return TRUE;
  1206. }
  1207. BOOL
  1208. APIENTRY
  1209. AccessCheckByTypeResultListAndAuditAlarmByHandleW (
  1210. LPCWSTR SubsystemName,
  1211. LPVOID HandleId,
  1212. HANDLE ClientToken,
  1213. LPCWSTR ObjectTypeName,
  1214. LPCWSTR ObjectName,
  1215. PSECURITY_DESCRIPTOR SecurityDescriptor,
  1216. PSID PrincipalSelfSid,
  1217. DWORD DesiredAccess,
  1218. AUDIT_EVENT_TYPE AuditType,
  1219. DWORD Flags,
  1220. POBJECT_TYPE_LIST ObjectTypeList,
  1221. DWORD ObjectTypeListLength,
  1222. PGENERIC_MAPPING GenericMapping,
  1223. BOOL ObjectCreation,
  1224. LPDWORD GrantedAccessList,
  1225. LPDWORD AccessStatusList,
  1226. LPBOOL pfGenerateOnClose
  1227. )
  1228. /*++
  1229. Routine Description:
  1230. This routine compares the input Security Descriptor against the
  1231. caller's impersonation token and indicates if access is granted or
  1232. denied. If access is granted then the desired access mask becomes
  1233. the granted access mask for the object. The semantics of the
  1234. access check routine is described in the DSA Security Architecture
  1235. workbook.
  1236. This routine will also generate any necessary audit messages as a
  1237. result of the access attempt.
  1238. Arguments:
  1239. SubsystemName - Supplies a name string identifying the subsystem
  1240. calling the routine.
  1241. HandleId - A unique value that will be used to represent the client's
  1242. handle to the object. This value is ignored (and may be re-used)
  1243. if the access is denied.
  1244. ClientToken - A handle to a token object representing the client that
  1245. requested the operation. This handle must be obtained from a
  1246. communication session layer, such as from an LPC Port or Local
  1247. Named Pipe, to prevent possible security policy violations.
  1248. ObjectTypeName - Supplies the name of the type of the object being
  1249. created or accessed.
  1250. ObjectName - Supplies the name of the object being created or accessed.
  1251. SecurityDescriptor - A pointer to the Security Descriptor against which
  1252. acccess is to be checked.
  1253. PrincipalSelfSid - If the object being access checked is an object which
  1254. represents a principal (e.g., a user object), this parameter should
  1255. be the SID of the object. Any ACE containing the constant
  1256. PRINCIPAL_SELF_SID is replaced by this SID.
  1257. The parameter should be NULL if the object does not represent a principal.
  1258. DesiredAccess - The desired acccess mask. This mask must have been
  1259. previously mapped to contain no generic accesses.
  1260. AuditType - Specifies the type of audit to be generated. Valid values
  1261. are: AuditEventObjectAccess and AuditEventDirectoryServiceAccess.
  1262. Flags - Flags modifying the execution of the API:
  1263. AUDIT_ALLOW_NO_PRIVILEGE - If the called does not have AuditPrivilege,
  1264. the call will silently continue to check access and will
  1265. generate no audit.
  1266. ObjectTypeList - Supplies a list of GUIDs representing the object (and
  1267. sub-objects) being accessed. If no list is present, AccessCheckByType
  1268. behaves identically to AccessCheck.
  1269. ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
  1270. GenericMapping - Supplies a pointer to the generic mapping associated
  1271. with this object type.
  1272. ObjectCreation - A boolean flag indicated whether the access will
  1273. result in a new object being created if granted. A value of TRUE
  1274. indicates an object will be created, FALSE indicates an existing
  1275. object will be opened.
  1276. GrantedAccessList - Returns an access mask describing the granted access.
  1277. AccessStatusList - Status value that may be returned indicating the
  1278. reason why access was denied. Routines should avoid hardcoding a
  1279. return value of STATUS_ACCESS_DENIED so that a different value can
  1280. be returned when mandatory access control is implemented.
  1281. pfGenerateOnClose - Points to a boolean that is set by the audity
  1282. generation routine and must be passed to ObjectCloseAuditAlarm
  1283. when the object handle is closed.
  1284. Return Value:
  1285. Returns TRUE for success, FALSE for failure. Extended error status
  1286. is available using GetLastError.
  1287. --*/
  1288. {
  1289. NTSTATUS Status;
  1290. NTSTATUS RealAccessStatus;
  1291. BOOLEAN GenerateOnClose = FALSE;
  1292. UNICODE_STRING Subsystem;
  1293. UNICODE_STRING ObjectType;
  1294. UNICODE_STRING Object;
  1295. ULONG i;
  1296. RtlInitUnicodeString(
  1297. &Subsystem,
  1298. SubsystemName
  1299. );
  1300. RtlInitUnicodeString(
  1301. &ObjectType,
  1302. ObjectTypeName
  1303. );
  1304. RtlInitUnicodeString(
  1305. &Object,
  1306. ObjectName
  1307. );
  1308. Status = NtAccessCheckByTypeResultListAndAuditAlarmByHandle (
  1309. &Subsystem,
  1310. HandleId,
  1311. ClientToken,
  1312. &ObjectType,
  1313. &Object,
  1314. SecurityDescriptor,
  1315. PrincipalSelfSid,
  1316. DesiredAccess,
  1317. AuditType,
  1318. Flags,
  1319. ObjectTypeList,
  1320. ObjectTypeListLength,
  1321. GenericMapping,
  1322. (BOOLEAN)ObjectCreation,
  1323. GrantedAccessList,
  1324. AccessStatusList,
  1325. &GenerateOnClose
  1326. );
  1327. *pfGenerateOnClose = (BOOL)GenerateOnClose;
  1328. if ( !NT_SUCCESS(Status) ) {
  1329. BaseSetLastNTError(Status);
  1330. return FALSE;
  1331. }
  1332. //
  1333. // Loop converting the array of NT status codes to WIN status codes.
  1334. //
  1335. for ( i=0; i<ObjectTypeListLength; i++ ) {
  1336. if ( AccessStatusList[i] == STATUS_SUCCESS ) {
  1337. AccessStatusList[i] = NO_ERROR;
  1338. } else {
  1339. AccessStatusList[i] = RtlNtStatusToDosError( AccessStatusList[i] );
  1340. }
  1341. }
  1342. return TRUE;
  1343. }
  1344. BOOL
  1345. APIENTRY
  1346. AccessCheckAndAuditAlarmA (
  1347. LPCSTR SubsystemName,
  1348. PVOID HandleId,
  1349. LPSTR ObjectTypeName,
  1350. LPSTR ObjectName,
  1351. PSECURITY_DESCRIPTOR SecurityDescriptor,
  1352. DWORD DesiredAccess,
  1353. PGENERIC_MAPPING GenericMapping,
  1354. BOOL ObjectCreation,
  1355. LPDWORD GrantedAccess,
  1356. LPBOOL AccessStatus,
  1357. LPBOOL pfGenerateOnClose
  1358. )
  1359. /*++
  1360. Routine Description:
  1361. ANSI Thunk to AccessCheckAndAuditAlarmW
  1362. --*/
  1363. {
  1364. PUNICODE_STRING ObjectNameW;
  1365. ANSI_STRING AnsiString;
  1366. UNICODE_STRING SubsystemNameW;
  1367. UNICODE_STRING ObjectTypeNameW;
  1368. NTSTATUS Status;
  1369. BOOL RVal;
  1370. ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
  1371. RtlInitAnsiString(&AnsiString,SubsystemName);
  1372. Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
  1373. if ( !NT_SUCCESS(Status) ) {
  1374. BaseSetLastNTError(Status);
  1375. return FALSE;
  1376. }
  1377. RtlInitAnsiString(&AnsiString,ObjectTypeName);
  1378. Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
  1379. if ( !NT_SUCCESS(Status) ) {
  1380. RtlFreeUnicodeString( &SubsystemNameW );
  1381. BaseSetLastNTError(Status);
  1382. return FALSE;
  1383. }
  1384. //
  1385. // Convert the object name string, but don't allocate memory to
  1386. // do it, since we've got the space in the TEB available.
  1387. //
  1388. RtlInitAnsiString(&AnsiString,ObjectName);
  1389. Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
  1390. if ( !NT_SUCCESS(Status) ) {
  1391. RtlFreeUnicodeString( &SubsystemNameW );
  1392. RtlFreeUnicodeString( &ObjectTypeNameW );
  1393. BaseSetLastNTError(Status);
  1394. return FALSE;
  1395. }
  1396. RVal = AccessCheckAndAuditAlarmW (
  1397. (LPCWSTR)SubsystemNameW.Buffer,
  1398. HandleId,
  1399. ObjectTypeNameW.Buffer,
  1400. ObjectNameW->Buffer,
  1401. SecurityDescriptor,
  1402. DesiredAccess,
  1403. GenericMapping,
  1404. ObjectCreation,
  1405. GrantedAccess,
  1406. AccessStatus,
  1407. pfGenerateOnClose
  1408. );
  1409. RtlFreeUnicodeString( &SubsystemNameW );
  1410. RtlFreeUnicodeString( &ObjectTypeNameW );
  1411. return( RVal );
  1412. }
  1413. BOOL
  1414. APIENTRY
  1415. AccessCheckByTypeAndAuditAlarmA (
  1416. LPCSTR SubsystemName,
  1417. PVOID HandleId,
  1418. LPCSTR ObjectTypeName,
  1419. LPCSTR ObjectName,
  1420. PSECURITY_DESCRIPTOR SecurityDescriptor,
  1421. PSID PrincipalSelfSid,
  1422. DWORD DesiredAccess,
  1423. AUDIT_EVENT_TYPE AuditType,
  1424. DWORD Flags,
  1425. POBJECT_TYPE_LIST ObjectTypeList,
  1426. DWORD ObjectTypeListLength,
  1427. PGENERIC_MAPPING GenericMapping,
  1428. BOOL ObjectCreation,
  1429. LPDWORD GrantedAccess,
  1430. LPBOOL AccessStatus,
  1431. LPBOOL pfGenerateOnClose
  1432. )
  1433. /*++
  1434. Routine Description:
  1435. ANSI Thunk to AccessCheckByTypeAndAuditAlarmW
  1436. --*/
  1437. {
  1438. PUNICODE_STRING ObjectNameW;
  1439. ANSI_STRING AnsiString;
  1440. UNICODE_STRING SubsystemNameW;
  1441. UNICODE_STRING ObjectTypeNameW;
  1442. NTSTATUS Status;
  1443. BOOL RVal;
  1444. ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
  1445. RtlInitAnsiString(&AnsiString,SubsystemName);
  1446. Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
  1447. if ( !NT_SUCCESS(Status) ) {
  1448. BaseSetLastNTError(Status);
  1449. return FALSE;
  1450. }
  1451. RtlInitAnsiString(&AnsiString,ObjectTypeName);
  1452. Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
  1453. if ( !NT_SUCCESS(Status) ) {
  1454. RtlFreeUnicodeString( &SubsystemNameW );
  1455. BaseSetLastNTError(Status);
  1456. return FALSE;
  1457. }
  1458. //
  1459. // Convert the object name string, but don't allocate memory to
  1460. // do it, since we've got the space in the TEB available.
  1461. //
  1462. RtlInitAnsiString(&AnsiString,ObjectName);
  1463. Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
  1464. if ( !NT_SUCCESS(Status) ) {
  1465. RtlFreeUnicodeString( &SubsystemNameW );
  1466. RtlFreeUnicodeString( &ObjectTypeNameW );
  1467. BaseSetLastNTError(Status);
  1468. return FALSE;
  1469. }
  1470. RVal = AccessCheckByTypeAndAuditAlarmW (
  1471. (LPCWSTR)SubsystemNameW.Buffer,
  1472. HandleId,
  1473. ObjectTypeNameW.Buffer,
  1474. ObjectNameW->Buffer,
  1475. SecurityDescriptor,
  1476. PrincipalSelfSid,
  1477. DesiredAccess,
  1478. AuditType,
  1479. Flags,
  1480. ObjectTypeList,
  1481. ObjectTypeListLength,
  1482. GenericMapping,
  1483. ObjectCreation,
  1484. GrantedAccess,
  1485. AccessStatus,
  1486. pfGenerateOnClose
  1487. );
  1488. RtlFreeUnicodeString( &SubsystemNameW );
  1489. RtlFreeUnicodeString( &ObjectTypeNameW );
  1490. return( RVal );
  1491. }
  1492. WINADVAPI
  1493. BOOL
  1494. WINAPI
  1495. AccessCheckByTypeResultListAndAuditAlarmA (
  1496. LPCSTR SubsystemName,
  1497. LPVOID HandleId,
  1498. LPCSTR ObjectTypeName,
  1499. LPCSTR ObjectName,
  1500. PSECURITY_DESCRIPTOR SecurityDescriptor,
  1501. PSID PrincipalSelfSid,
  1502. DWORD DesiredAccess,
  1503. AUDIT_EVENT_TYPE AuditType,
  1504. DWORD Flags,
  1505. POBJECT_TYPE_LIST ObjectTypeList,
  1506. DWORD ObjectTypeListLength,
  1507. PGENERIC_MAPPING GenericMapping,
  1508. BOOL ObjectCreation,
  1509. LPDWORD GrantedAccess,
  1510. LPDWORD AccessStatusList,
  1511. LPBOOL pfGenerateOnClose
  1512. )
  1513. /*++
  1514. Routine Description:
  1515. ANSI Thunk to AccessCheckByTypeResultListAndAuditAlarmW
  1516. --*/
  1517. {
  1518. PUNICODE_STRING ObjectNameW;
  1519. ANSI_STRING AnsiString;
  1520. UNICODE_STRING SubsystemNameW;
  1521. UNICODE_STRING ObjectTypeNameW;
  1522. NTSTATUS Status;
  1523. BOOL RVal;
  1524. ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
  1525. RtlInitAnsiString(&AnsiString,SubsystemName);
  1526. Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
  1527. if ( !NT_SUCCESS(Status) ) {
  1528. BaseSetLastNTError(Status);
  1529. return FALSE;
  1530. }
  1531. RtlInitAnsiString(&AnsiString,ObjectTypeName);
  1532. Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
  1533. if ( !NT_SUCCESS(Status) ) {
  1534. RtlFreeUnicodeString( &SubsystemNameW );
  1535. BaseSetLastNTError(Status);
  1536. return FALSE;
  1537. }
  1538. //
  1539. // Convert the object name string, but don't allocate memory to
  1540. // do it, since we've got the space in the TEB available.
  1541. //
  1542. RtlInitAnsiString(&AnsiString,ObjectName);
  1543. Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
  1544. if ( !NT_SUCCESS(Status) ) {
  1545. RtlFreeUnicodeString( &SubsystemNameW );
  1546. RtlFreeUnicodeString( &ObjectTypeNameW );
  1547. BaseSetLastNTError(Status);
  1548. return FALSE;
  1549. }
  1550. RVal = AccessCheckByTypeResultListAndAuditAlarmW (
  1551. (LPCWSTR)SubsystemNameW.Buffer,
  1552. HandleId,
  1553. ObjectTypeNameW.Buffer,
  1554. ObjectNameW->Buffer,
  1555. SecurityDescriptor,
  1556. PrincipalSelfSid,
  1557. DesiredAccess,
  1558. AuditType,
  1559. Flags,
  1560. ObjectTypeList,
  1561. ObjectTypeListLength,
  1562. GenericMapping,
  1563. ObjectCreation,
  1564. GrantedAccess,
  1565. AccessStatusList,
  1566. pfGenerateOnClose
  1567. );
  1568. RtlFreeUnicodeString( &SubsystemNameW );
  1569. RtlFreeUnicodeString( &ObjectTypeNameW );
  1570. return( RVal );
  1571. }
  1572. WINADVAPI
  1573. BOOL
  1574. WINAPI
  1575. AccessCheckByTypeResultListAndAuditAlarmByHandleA (
  1576. LPCSTR SubsystemName,
  1577. LPVOID HandleId,
  1578. HANDLE ClientToken,
  1579. LPCSTR ObjectTypeName,
  1580. LPCSTR ObjectName,
  1581. PSECURITY_DESCRIPTOR SecurityDescriptor,
  1582. PSID PrincipalSelfSid,
  1583. DWORD DesiredAccess,
  1584. AUDIT_EVENT_TYPE AuditType,
  1585. DWORD Flags,
  1586. POBJECT_TYPE_LIST ObjectTypeList,
  1587. DWORD ObjectTypeListLength,
  1588. PGENERIC_MAPPING GenericMapping,
  1589. BOOL ObjectCreation,
  1590. LPDWORD GrantedAccess,
  1591. LPDWORD AccessStatusList,
  1592. LPBOOL pfGenerateOnClose
  1593. )
  1594. /*++
  1595. Routine Description:
  1596. ANSI Thunk to AccessCheckByTypeResultListAndAuditAlarmW
  1597. --*/
  1598. {
  1599. PUNICODE_STRING ObjectNameW;
  1600. ANSI_STRING AnsiString;
  1601. UNICODE_STRING SubsystemNameW;
  1602. UNICODE_STRING ObjectTypeNameW;
  1603. NTSTATUS Status;
  1604. BOOL RVal;
  1605. ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
  1606. RtlInitAnsiString(&AnsiString,SubsystemName);
  1607. Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
  1608. if ( !NT_SUCCESS(Status) ) {
  1609. BaseSetLastNTError(Status);
  1610. return FALSE;
  1611. }
  1612. RtlInitAnsiString(&AnsiString,ObjectTypeName);
  1613. Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
  1614. if ( !NT_SUCCESS(Status) ) {
  1615. RtlFreeUnicodeString( &SubsystemNameW );
  1616. BaseSetLastNTError(Status);
  1617. return FALSE;
  1618. }
  1619. //
  1620. // Convert the object name string, but don't allocate memory to
  1621. // do it, since we've got the space in the TEB available.
  1622. //
  1623. RtlInitAnsiString(&AnsiString,ObjectName);
  1624. Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
  1625. if ( !NT_SUCCESS(Status) ) {
  1626. RtlFreeUnicodeString( &SubsystemNameW );
  1627. RtlFreeUnicodeString( &ObjectTypeNameW );
  1628. BaseSetLastNTError(Status);
  1629. return FALSE;
  1630. }
  1631. RVal = AccessCheckByTypeResultListAndAuditAlarmByHandleW (
  1632. (LPCWSTR)SubsystemNameW.Buffer,
  1633. HandleId,
  1634. ClientToken,
  1635. ObjectTypeNameW.Buffer,
  1636. ObjectNameW->Buffer,
  1637. SecurityDescriptor,
  1638. PrincipalSelfSid,
  1639. DesiredAccess,
  1640. AuditType,
  1641. Flags,
  1642. ObjectTypeList,
  1643. ObjectTypeListLength,
  1644. GenericMapping,
  1645. ObjectCreation,
  1646. GrantedAccess,
  1647. AccessStatusList,
  1648. pfGenerateOnClose
  1649. );
  1650. RtlFreeUnicodeString( &SubsystemNameW );
  1651. RtlFreeUnicodeString( &ObjectTypeNameW );
  1652. return( RVal );
  1653. }
  1654. BOOL
  1655. APIENTRY
  1656. ObjectOpenAuditAlarmA (
  1657. LPCSTR SubsystemName,
  1658. PVOID HandleId,
  1659. LPSTR ObjectTypeName,
  1660. LPSTR ObjectName,
  1661. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1662. HANDLE ClientToken,
  1663. DWORD DesiredAccess,
  1664. DWORD GrantedAccess,
  1665. PPRIVILEGE_SET Privileges OPTIONAL,
  1666. BOOL ObjectCreation,
  1667. BOOL AccessGranted,
  1668. LPBOOL GenerateOnClose
  1669. )
  1670. /*++
  1671. Routine Description:
  1672. ANSI Thunk to ObjectOpenAuditAlarmW
  1673. --*/
  1674. {
  1675. PUNICODE_STRING ObjectNameW;
  1676. ANSI_STRING AnsiString;
  1677. UNICODE_STRING SubsystemNameW;
  1678. UNICODE_STRING ObjectTypeNameW;
  1679. NTSTATUS Status;
  1680. BOOL RVal;
  1681. ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
  1682. RtlInitAnsiString(&AnsiString,SubsystemName);
  1683. Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
  1684. if ( !NT_SUCCESS(Status) ) {
  1685. BaseSetLastNTError(Status);
  1686. return FALSE;
  1687. }
  1688. RtlInitAnsiString(&AnsiString,ObjectTypeName);
  1689. Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
  1690. if ( !NT_SUCCESS(Status) ) {
  1691. RtlFreeUnicodeString( &SubsystemNameW );
  1692. BaseSetLastNTError(Status);
  1693. return FALSE;
  1694. }
  1695. //
  1696. // Convert the object name string, but don't allocate memory to
  1697. // do it, since we've got the space in the TEB available.
  1698. //
  1699. RtlInitAnsiString(&AnsiString,ObjectName);
  1700. Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
  1701. if ( !NT_SUCCESS(Status) ) {
  1702. RtlFreeUnicodeString( &SubsystemNameW );
  1703. RtlFreeUnicodeString( &ObjectTypeNameW );
  1704. BaseSetLastNTError(Status);
  1705. return FALSE;
  1706. }
  1707. RVal = ObjectOpenAuditAlarmW (
  1708. (LPCWSTR)SubsystemNameW.Buffer,
  1709. HandleId,
  1710. ObjectTypeNameW.Buffer,
  1711. ObjectNameW->Buffer,
  1712. pSecurityDescriptor,
  1713. ClientToken,
  1714. DesiredAccess,
  1715. GrantedAccess,
  1716. Privileges,
  1717. ObjectCreation,
  1718. AccessGranted,
  1719. GenerateOnClose
  1720. );
  1721. RtlFreeUnicodeString( &SubsystemNameW );
  1722. RtlFreeUnicodeString( &ObjectTypeNameW );
  1723. return( RVal );
  1724. }
  1725. BOOL
  1726. APIENTRY
  1727. ObjectOpenAuditAlarmW (
  1728. LPCWSTR SubsystemName,
  1729. PVOID HandleId,
  1730. LPWSTR ObjectTypeName,
  1731. LPWSTR ObjectName,
  1732. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1733. HANDLE ClientToken,
  1734. DWORD DesiredAccess,
  1735. DWORD GrantedAccess,
  1736. PPRIVILEGE_SET Privileges OPTIONAL,
  1737. BOOL ObjectCreation,
  1738. BOOL AccessGranted,
  1739. LPBOOL GenerateOnClose
  1740. )
  1741. /*++
  1742. Routine Description:
  1743. This routine is used to generate audit and alarm messages when an
  1744. attempt is made to access an existing protected subsystem object or
  1745. create a new one. This routine may result in several messages being
  1746. generated and sent to Port objects. This may result in a significant
  1747. latency before returning. Design of routines that must call this
  1748. routine must take this potential latency into account. This may have
  1749. an impact on the approach taken for data structure mutex locking, for
  1750. example.
  1751. This routine may not be able to generate a complete audit record
  1752. due to memory restrictions.
  1753. This API requires the caller have SeSecurityPrivilege privilege.
  1754. The test for this privilege is always against the primary token of
  1755. the calling process, not the impersonation token of the thread.
  1756. Arguments:
  1757. SubsystemName - Supplies a name string identifying the
  1758. subsystem calling the routine.
  1759. HandleId - A unique value representing the client's handle to the
  1760. object. If the access attempt was not successful (AccessGranted is
  1761. FALSE), then this parameter is ignored.
  1762. ObjectTypeName - Supplies the name of the type of object being
  1763. accessed.
  1764. ObjectName - Supplies the name of the object the client
  1765. accessed or attempted to access.
  1766. pSecurityDescriptor - An optional pointer to the security
  1767. descriptor of the object being accessed.
  1768. ClientToken - A handle to a token object representing the client that
  1769. requested the operation. This handle must be obtained from a
  1770. communication session layer, such as from an LPC Port or Local
  1771. Named Pipe, to prevent possible security policy violations.
  1772. DesiredAccess - The desired access mask. This mask must have been
  1773. previously mapped to contain no generic accesses.
  1774. GrantedAccess - The mask of accesses that were actually granted.
  1775. Privileges - Optionally points to a set of privileges that were
  1776. required for the access attempt. Those privileges that were held
  1777. by the subject are marked using the UsedForAccess flag of the
  1778. attributes associated with each privilege.
  1779. ObjectCreation - A boolean flag indicating whether the access will
  1780. result in a new object being created if granted. A value of TRUE
  1781. indicates an object will be created, FALSE indicates an existing
  1782. object will be opened.
  1783. AccessGranted - Indicates whether the requested access was granted or
  1784. not. A value of TRUE indicates the access was granted. A value of
  1785. FALSE indicates the access was not granted.
  1786. GenerateOnClose - Points to a boolean that is set by the audit
  1787. generation routine and must be passed to NtCloseObjectAuditAlarm()
  1788. when the object handle is closed.
  1789. Return Value:
  1790. Returns TRUE for success, FALSE for failure. Extended error status
  1791. is available using GetLastError.
  1792. --*/
  1793. {
  1794. NTSTATUS Status;
  1795. UNICODE_STRING Subsystem;
  1796. UNICODE_STRING ObjectType;
  1797. UNICODE_STRING Object;
  1798. RtlInitUnicodeString(
  1799. &Subsystem,
  1800. SubsystemName
  1801. );
  1802. RtlInitUnicodeString(
  1803. &ObjectType,
  1804. ObjectTypeName
  1805. );
  1806. RtlInitUnicodeString(
  1807. &Object,
  1808. ObjectName
  1809. );
  1810. Status = NtOpenObjectAuditAlarm (
  1811. &Subsystem,
  1812. &HandleId,
  1813. &ObjectType,
  1814. &Object,
  1815. pSecurityDescriptor,
  1816. ClientToken,
  1817. DesiredAccess,
  1818. GrantedAccess,
  1819. Privileges,
  1820. (BOOLEAN)ObjectCreation,
  1821. (BOOLEAN)AccessGranted,
  1822. (PBOOLEAN)GenerateOnClose
  1823. );
  1824. if ( !NT_SUCCESS(Status) ) {
  1825. BaseSetLastNTError(Status);
  1826. return FALSE;
  1827. }
  1828. return TRUE;
  1829. }
  1830. BOOL
  1831. APIENTRY
  1832. ObjectPrivilegeAuditAlarmA (
  1833. LPCSTR SubsystemName,
  1834. PVOID HandleId,
  1835. HANDLE ClientToken,
  1836. DWORD DesiredAccess,
  1837. PPRIVILEGE_SET Privileges,
  1838. BOOL AccessGranted
  1839. )
  1840. /*++
  1841. Routine Description:
  1842. ANSI Thunk to ObjectPrivilegeAuditAlarmW
  1843. --*/
  1844. {
  1845. PUNICODE_STRING SubsystemNameW;
  1846. ANSI_STRING AnsiString;
  1847. NTSTATUS Status;
  1848. BOOL RVal;
  1849. SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;
  1850. //
  1851. // Convert the object name string, but don't allocate memory to
  1852. // do it, since we've got the space in the TEB available.
  1853. //
  1854. RtlInitAnsiString(&AnsiString,SubsystemName);
  1855. Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);
  1856. if ( !NT_SUCCESS(Status) ) {
  1857. BaseSetLastNTError(Status);
  1858. return FALSE;
  1859. }
  1860. RVal = ObjectPrivilegeAuditAlarmW (
  1861. (LPCWSTR)SubsystemNameW->Buffer,
  1862. HandleId,
  1863. ClientToken,
  1864. DesiredAccess,
  1865. Privileges,
  1866. AccessGranted
  1867. );
  1868. return( RVal );
  1869. }
  1870. BOOL
  1871. APIENTRY
  1872. ObjectPrivilegeAuditAlarmW (
  1873. LPCWSTR SubsystemName,
  1874. PVOID HandleId,
  1875. HANDLE ClientToken,
  1876. DWORD DesiredAccess,
  1877. PPRIVILEGE_SET Privileges,
  1878. BOOL AccessGranted
  1879. )
  1880. /*++
  1881. Routine Description:
  1882. This routine is used to generate audit and alarm messages when an
  1883. attempt is made to perform privileged operations on a protected
  1884. subsystem object after the object is already opened. This routine
  1885. may result in several messages being generated and sent to Port
  1886. objects. This may result in a significant latency before
  1887. returning. Design of routines that must call this routine must
  1888. take this potential latency into account. This may have an impact
  1889. on the approach taken for data structure mutex locking, for
  1890. example.
  1891. This API requires the caller have SeSecurityPrivilege privilege.
  1892. The test for this privilege is always against the primary token of
  1893. the calling process, allowing the caller to be impersonating a
  1894. client during the call with no ill effects.
  1895. Arguments:
  1896. SubsystemName - Supplies a name string identifying the subsystem
  1897. calling the routine.
  1898. HandleId - A unique value representing the client's handle to the
  1899. object.
  1900. ClientToken - A handle to a token object representing the client that
  1901. requested the operation. This handle must be obtained from a
  1902. communication session layer, such as from an LPC Port or Local
  1903. Named Pipe, to prevent possible security policy violations.
  1904. DesiredAccess - The desired access mask. This mask must have been
  1905. previously mapped to contain no generic accesses.
  1906. Privileges - The set of privileges required for the requested
  1907. operation. Those privileges that were held by the subject are
  1908. marked using the UsedForAccess flag of the attributes
  1909. associated with each privilege.
  1910. AccessGranted - Indicates whether the requested access was granted or
  1911. not. A value of TRUE indicates the access was granted. A value of
  1912. FALSE indicates the access was not granted.
  1913. Return value:
  1914. Returns TRUE for success, FALSE for failure. Extended error status
  1915. is available using GetLastError.
  1916. --*/
  1917. {
  1918. NTSTATUS Status;
  1919. UNICODE_STRING Subsystem;
  1920. RtlInitUnicodeString(
  1921. &Subsystem,
  1922. SubsystemName
  1923. );
  1924. Status = NtPrivilegeObjectAuditAlarm (
  1925. &Subsystem,
  1926. HandleId,
  1927. ClientToken,
  1928. DesiredAccess,
  1929. Privileges,
  1930. (BOOLEAN)AccessGranted
  1931. );
  1932. if ( !NT_SUCCESS(Status) ) {
  1933. BaseSetLastNTError(Status);
  1934. return FALSE;
  1935. }
  1936. return TRUE;
  1937. }
  1938. BOOL
  1939. APIENTRY
  1940. ObjectCloseAuditAlarmA (
  1941. LPCSTR SubsystemName,
  1942. PVOID HandleId,
  1943. BOOL GenerateOnClose
  1944. )
  1945. /*++
  1946. Routine Description:
  1947. ANSI Thunk to ObjectCloseAuditAlarmW
  1948. --*/
  1949. {
  1950. PUNICODE_STRING SubsystemNameW;
  1951. NTSTATUS Status;
  1952. ANSI_STRING AnsiString;
  1953. SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;
  1954. //
  1955. // Convert the object name string, but don't allocate memory to
  1956. // do it, since we've got the space in the TEB available.
  1957. //
  1958. RtlInitAnsiString(&AnsiString,SubsystemName);
  1959. Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);
  1960. if ( !NT_SUCCESS(Status) ) {
  1961. BaseSetLastNTError(Status);
  1962. return FALSE;
  1963. }
  1964. return ObjectCloseAuditAlarmW (
  1965. (LPCWSTR)SubsystemNameW->Buffer,
  1966. HandleId,
  1967. GenerateOnClose
  1968. );
  1969. }
  1970. BOOL
  1971. APIENTRY
  1972. ObjectCloseAuditAlarmW (
  1973. LPCWSTR SubsystemName,
  1974. PVOID HandleId,
  1975. BOOL GenerateOnClose
  1976. )
  1977. /*++
  1978. Routine Description:
  1979. This routine is used to generate audit and alarm messages when a handle
  1980. to a protected subsystem object is deleted. This routine may result in
  1981. several messages being generated and sent to Port objects. This may
  1982. result in a significant latency before returning. Design of routines
  1983. that must call this routine must take this potential latency into
  1984. account. This may have an impact on the approach taken for data
  1985. structure mutex locking, for example.
  1986. This API requires the caller have SeSecurityPrivilege privilege. The test
  1987. for this privilege is always against the primary token of the calling
  1988. process, allowing the caller to be impersonating a client during the
  1989. call with no ill effects.
  1990. Arguments:
  1991. SubsystemName - Supplies a name string identifying the subsystem
  1992. calling the routine.
  1993. HandleId - A unique value representing the client's handle to the
  1994. object.
  1995. GenerateOnClose - Is a boolean value returned from a corresponding
  1996. AccessCheckAndAuditAlarm() call or ObjectOpenAuditAlarm() call
  1997. when the object handle was created.
  1998. Return value:
  1999. Returns TRUE for success, FALSE for failure. Extended error status
  2000. is available using GetLastError.
  2001. --*/
  2002. {
  2003. NTSTATUS Status;
  2004. UNICODE_STRING Subsystem;
  2005. RtlInitUnicodeString( &Subsystem, SubsystemName );
  2006. Status = NtCloseObjectAuditAlarm (
  2007. &Subsystem,
  2008. HandleId,
  2009. (BOOLEAN)GenerateOnClose
  2010. );
  2011. if ( !NT_SUCCESS(Status) ) {
  2012. BaseSetLastNTError(Status);
  2013. return FALSE;
  2014. }
  2015. return TRUE;
  2016. }
  2017. BOOL
  2018. APIENTRY
  2019. ObjectDeleteAuditAlarmA (
  2020. LPCSTR SubsystemName,
  2021. PVOID HandleId,
  2022. BOOL GenerateOnClose
  2023. )
  2024. /*++
  2025. Routine Description:
  2026. ANSI Thunk to ObjectDeleteAuditAlarmW
  2027. --*/
  2028. {
  2029. PUNICODE_STRING SubsystemNameW;
  2030. NTSTATUS Status;
  2031. ANSI_STRING AnsiString;
  2032. SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;
  2033. //
  2034. // Convert the object name string, but don't allocate memory to
  2035. // do it, since we've got the space in the TEB available.
  2036. //
  2037. RtlInitAnsiString(&AnsiString,SubsystemName);
  2038. Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);
  2039. if ( !NT_SUCCESS(Status) ) {
  2040. BaseSetLastNTError(Status);
  2041. return FALSE;
  2042. }
  2043. return ObjectDeleteAuditAlarmW (
  2044. (LPCWSTR)SubsystemNameW->Buffer,
  2045. HandleId,
  2046. GenerateOnClose
  2047. );
  2048. }
  2049. BOOL
  2050. APIENTRY
  2051. ObjectDeleteAuditAlarmW (
  2052. LPCWSTR SubsystemName,
  2053. PVOID HandleId,
  2054. BOOL GenerateOnClose
  2055. )
  2056. /*++
  2057. Routine Description:
  2058. This routine is used to generate audit and alarm messages when an object
  2059. in a protected subsystem is deleted. This routine may result in
  2060. several messages being generated and sent to Port objects. This may
  2061. result in a significant latency before returning. Design of routines
  2062. that must call this routine must take this potential latency into
  2063. account. This may have an impact on the approach taken for data
  2064. structure mutex locking, for example.
  2065. This API requires the caller have SeSecurityPrivilege privilege. The test
  2066. for this privilege is always against the primary token of the calling
  2067. process, allowing the caller to be impersonating a client during the
  2068. call with no ill effects.
  2069. Arguments:
  2070. SubsystemName - Supplies a name string identifying the subsystem
  2071. calling the routine.
  2072. HandleId - A unique value representing the client's handle to the
  2073. object.
  2074. GenerateOnClose - Is a boolean value returned from a corresponding
  2075. AccessCheckAndAuditAlarm() call or ObjectOpenAuditAlarm() call
  2076. when the object handle was created.
  2077. Return value:
  2078. Returns TRUE for success, FALSE for failure. Extended error status
  2079. is available using GetLastError.
  2080. --*/
  2081. {
  2082. NTSTATUS Status;
  2083. UNICODE_STRING Subsystem;
  2084. RtlInitUnicodeString( &Subsystem, SubsystemName );
  2085. Status = NtDeleteObjectAuditAlarm (
  2086. &Subsystem,
  2087. HandleId,
  2088. (BOOLEAN)GenerateOnClose
  2089. );
  2090. if ( !NT_SUCCESS(Status) ) {
  2091. BaseSetLastNTError(Status);
  2092. return FALSE;
  2093. }
  2094. return TRUE;
  2095. }
  2096. BOOL
  2097. APIENTRY
  2098. PrivilegedServiceAuditAlarmA (
  2099. LPCSTR SubsystemName,
  2100. LPCSTR ServiceName,
  2101. HANDLE ClientToken,
  2102. PPRIVILEGE_SET Privileges,
  2103. BOOL AccessGranted
  2104. )
  2105. /*++
  2106. Routine Description:
  2107. ANSI Thunk to PrivilegedServiceAuditAlarmW
  2108. --*/
  2109. {
  2110. PUNICODE_STRING ServiceNameW;
  2111. UNICODE_STRING SubsystemNameW;
  2112. ANSI_STRING AnsiString;
  2113. NTSTATUS Status;
  2114. BOOL RVal;
  2115. ServiceNameW = &NtCurrentTeb()->StaticUnicodeString;
  2116. //
  2117. // Convert the object name string, but don't allocate memory to
  2118. // do it, since we've got the space in the TEB available.
  2119. //
  2120. RtlInitAnsiString(&AnsiString,ServiceName);
  2121. Status = RtlAnsiStringToUnicodeString(ServiceNameW,&AnsiString,FALSE);
  2122. if ( !NT_SUCCESS(Status) ) {
  2123. BaseSetLastNTError(Status);
  2124. return FALSE;
  2125. }
  2126. RtlInitAnsiString(&AnsiString,SubsystemName);
  2127. Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
  2128. if ( !NT_SUCCESS(Status) ) {
  2129. BaseSetLastNTError(Status);
  2130. return FALSE;
  2131. }
  2132. RVal = PrivilegedServiceAuditAlarmW (
  2133. (LPCWSTR)SubsystemNameW.Buffer,
  2134. (LPCWSTR)ServiceNameW->Buffer,
  2135. ClientToken,
  2136. Privileges,
  2137. AccessGranted
  2138. );
  2139. RtlFreeUnicodeString( &SubsystemNameW );
  2140. return( RVal );
  2141. }
  2142. BOOL
  2143. APIENTRY
  2144. PrivilegedServiceAuditAlarmW (
  2145. LPCWSTR SubsystemName,
  2146. LPCWSTR ServiceName,
  2147. HANDLE ClientToken,
  2148. PPRIVILEGE_SET Privileges,
  2149. BOOL AccessGranted
  2150. )
  2151. /*++
  2152. Routine Description:
  2153. This routine is used to generate audit and alarm messages when an
  2154. attempt is made to perform privileged system service operations. This
  2155. routine may result in several messages being generated and sent to Port
  2156. objects. This may result in a significant latency before returning.
  2157. Design of routines that must call this routine must take this potential
  2158. latency into account. This may have an impact on the approach taken
  2159. for data structure mutex locking, for example.
  2160. This API requires the caller have SeSecurityPrivilege privilege. The test
  2161. for this privilege is always against the primary token of the calling
  2162. process, allowing the caller to be impersonating a client during the
  2163. call with no ill effects
  2164. Arguments:
  2165. SubsystemName - Supplies a name string identifying the subsystem
  2166. calling the routine.
  2167. ServiceName - Supplies a name of the privileged subsystem service. For
  2168. example, "RESET RUNTIME LOCAL SECURITY POLICY" might be specified
  2169. by a Local Security Authority service used to update the local
  2170. security policy database.
  2171. ClientToken - A handle to a token object representing the client that
  2172. requested the operation. This handle must be obtained from a
  2173. communication session layer, such as from an LPC Port or Local
  2174. Named Pipe, to prevent possible security policy violations.
  2175. Privileges - Points to a set of privileges required to perform the
  2176. privileged operation. Those privileges that were held by the
  2177. subject are marked using the UsedForAccess flag of the
  2178. attributes associated with each privilege.
  2179. AccessGranted - Indicates whether the requested access was granted or
  2180. not. A value of TRUE indicates the access was granted. A value of
  2181. FALSE indicates the access was not granted.
  2182. Return value:
  2183. Returns TRUE for success, FALSE for failure. Extended error status
  2184. is available using GetLastError.
  2185. --*/
  2186. {
  2187. NTSTATUS Status;
  2188. UNICODE_STRING Subsystem;
  2189. UNICODE_STRING Service;
  2190. RtlInitUnicodeString( &Subsystem, SubsystemName );
  2191. RtlInitUnicodeString( &Service, ServiceName );
  2192. Status = NtPrivilegedServiceAuditAlarm (
  2193. &Subsystem,
  2194. &Service,
  2195. ClientToken,
  2196. Privileges,
  2197. (BOOLEAN)AccessGranted
  2198. );
  2199. if ( !NT_SUCCESS(Status) ) {
  2200. BaseSetLastNTError(Status);
  2201. return FALSE;
  2202. }
  2203. return TRUE;
  2204. }
  2205. BOOL
  2206. APIENTRY
  2207. IsValidSid (
  2208. PSID pSid
  2209. )
  2210. /*++
  2211. Routine Description:
  2212. This procedure validates an SID's structure.
  2213. Arguments:
  2214. pSid - Pointer to the SID structure to validate.
  2215. Return Value:
  2216. BOOLEAN - TRUE if the structure of pSid is valid.
  2217. --*/
  2218. {
  2219. if ( !RtlValidSid ( pSid ) ) {
  2220. SetLastError(ERROR_INVALID_SID);
  2221. return FALSE;
  2222. }
  2223. return TRUE;
  2224. }
  2225. BOOL
  2226. APIENTRY
  2227. EqualSid (
  2228. PSID pSid1,
  2229. PSID pSid2
  2230. )
  2231. /*++
  2232. Routine Description:
  2233. This procedure tests two SID values for equality.
  2234. Arguments:
  2235. pSid1, pSid2 - Supply pointers to the two SID values to compare.
  2236. The SID structures are assumed to be valid.
  2237. Return Value:
  2238. BOOLEAN - TRUE if the value of pSid1 is equal to pSid2, and FALSE
  2239. otherwise.
  2240. --*/
  2241. {
  2242. SetLastError(0);
  2243. return (BOOL) RtlEqualSid (
  2244. pSid1,
  2245. pSid2
  2246. );
  2247. }
  2248. BOOL
  2249. APIENTRY
  2250. EqualPrefixSid (
  2251. PSID pSid1,
  2252. PSID pSid2
  2253. )
  2254. /*++
  2255. Routine Description:
  2256. This procedure tests two SID prefix values for equality.
  2257. An SID prefix is the entire SID except for the last sub-authority
  2258. value.
  2259. Arguments:
  2260. pSid1, pSid2 - Supply pointers to the two SID values to compare.
  2261. The SID structures are assumed to be valid.
  2262. Return Value:
  2263. BOOLEAN - TRUE if the prefix value of pSid1 is equal to pSid2, and
  2264. FALSE otherwise.
  2265. --*/
  2266. {
  2267. SetLastError(0);
  2268. return (BOOL) RtlEqualPrefixSid (
  2269. pSid1,
  2270. pSid2
  2271. );
  2272. }
  2273. DWORD
  2274. APIENTRY
  2275. GetSidLengthRequired (
  2276. UCHAR nSubAuthorityCount
  2277. )
  2278. /*++
  2279. Routine Description:
  2280. This routine returns the length, in bytes, required to store an SID
  2281. with the specified number of Sub-Authorities.
  2282. Arguments:
  2283. nSubAuthorityCount - The number of sub-authorities to be stored in
  2284. the SID.
  2285. Return Value:
  2286. DWORD - The length, in bytes, required to store the SID.
  2287. --*/
  2288. {
  2289. return RtlLengthRequiredSid (
  2290. nSubAuthorityCount
  2291. );
  2292. }
  2293. BOOL
  2294. APIENTRY
  2295. InitializeSid (
  2296. PSID Sid,
  2297. PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
  2298. BYTE nSubAuthorityCount
  2299. )
  2300. /*++
  2301. Routine Description:
  2302. This function initializes an SID data structure. It does not,
  2303. however, set the sub-authority values. This must be done
  2304. separately.
  2305. Arguments:
  2306. Sid - Pointer to the SID data structure to initialize.
  2307. pIdentifierAuthority - Pointer to the Identifier Authority value
  2308. to set in the SID.
  2309. nSubAuthorityCount - The number of sub-authorities that will be
  2310. placed in the SID (a separate action).
  2311. Return Value:
  2312. None
  2313. --*/
  2314. {
  2315. NTSTATUS Status;
  2316. Status = RtlInitializeSid (
  2317. Sid,
  2318. pIdentifierAuthority,
  2319. nSubAuthorityCount
  2320. );
  2321. if ( !NT_SUCCESS( Status )) {
  2322. BaseSetLastNTError( Status );
  2323. return( FALSE );
  2324. }
  2325. return( TRUE );
  2326. }
  2327. PVOID
  2328. APIENTRY
  2329. FreeSid(
  2330. PSID pSid
  2331. )
  2332. /*++
  2333. Routine Description:
  2334. This function is used to free a SID previously allocated using
  2335. AllocateAndInitializeSid().
  2336. Arguments:
  2337. Sid - Pointer to the SID to free.
  2338. Return Value:
  2339. None.
  2340. --*/
  2341. {
  2342. return(RtlFreeSid( pSid ));
  2343. }
  2344. BOOL
  2345. APIENTRY
  2346. AllocateAndInitializeSid (
  2347. PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
  2348. BYTE nSubAuthorityCount,
  2349. DWORD nSubAuthority0,
  2350. DWORD nSubAuthority1,
  2351. DWORD nSubAuthority2,
  2352. DWORD nSubAuthority3,
  2353. DWORD nSubAuthority4,
  2354. DWORD nSubAuthority5,
  2355. DWORD nSubAuthority6,
  2356. DWORD nSubAuthority7,
  2357. PSID *pSid
  2358. )
  2359. /*++
  2360. Routine Description:
  2361. This function allocates and initializes a sid with the specified
  2362. number of sub-authorities (up to 8). A sid allocated with this
  2363. routine must be freed using FreeSid().
  2364. Arguments:
  2365. pIdentifierAuthority - Pointer to the Identifier Authority value to
  2366. set in the SID.
  2367. nSubAuthorityCount - The number of sub-authorities to place in the SID.
  2368. This also identifies how many of the SubAuthorityN parameters
  2369. have meaningful values. This must contain a value from 0 through
  2370. 8.
  2371. nSubAuthority0-7 - Provides the corresponding sub-authority value to
  2372. place in the SID. For example, a SubAuthorityCount value of 3
  2373. indicates that SubAuthority0, SubAuthority1, and SubAuthority0
  2374. have meaningful values and the rest are to be ignored.
  2375. Sid - Receives a pointer to the allocated and initialized SID data
  2376. structure.
  2377. Return Value:
  2378. ERROR_NO_MEMORY - The attempt to allocate memory for the SID
  2379. failed.
  2380. ERROR_INVALID_SID - The number of sub-authorities specified did
  2381. not fall in the valid range for this api (0 through 8).
  2382. --*/
  2383. {
  2384. NTSTATUS Status;
  2385. Status = RtlAllocateAndInitializeSid (
  2386. pIdentifierAuthority,
  2387. (UCHAR)nSubAuthorityCount,
  2388. (ULONG)nSubAuthority0,
  2389. (ULONG)nSubAuthority1,
  2390. (ULONG)nSubAuthority2,
  2391. (ULONG)nSubAuthority3,
  2392. (ULONG)nSubAuthority4,
  2393. (ULONG)nSubAuthority5,
  2394. (ULONG)nSubAuthority6,
  2395. (ULONG)nSubAuthority7,
  2396. pSid
  2397. );
  2398. if ( !NT_SUCCESS( Status )) {
  2399. BaseSetLastNTError( Status );
  2400. return( FALSE );
  2401. }
  2402. return( TRUE );
  2403. }
  2404. PSID_IDENTIFIER_AUTHORITY
  2405. GetSidIdentifierAuthority (
  2406. PSID pSid
  2407. )
  2408. /*++
  2409. Routine Description:
  2410. This function returns the address of an SID's IdentifierAuthority field.
  2411. Arguments:
  2412. Sid - Pointer to the SID data structure.
  2413. Return Value:
  2414. Address of an SID's Identifier Authority field.
  2415. --*/
  2416. {
  2417. SetLastError(0);
  2418. return RtlIdentifierAuthoritySid (
  2419. pSid
  2420. );
  2421. }
  2422. PDWORD
  2423. GetSidSubAuthority (
  2424. PSID pSid,
  2425. DWORD nSubAuthority
  2426. )
  2427. /*++
  2428. Routine Description:
  2429. This function returns the address of a sub-authority array element of
  2430. an SID.
  2431. Arguments:
  2432. pSid - Pointer to the SID data structure.
  2433. nSubAuthority - An index indicating which sub-authority is being
  2434. specified. This value is not compared against the number of
  2435. sub-authorities in the SID for validity.
  2436. Return Value:
  2437. Address of a relative ID within the SID.
  2438. --*/
  2439. {
  2440. SetLastError(0);
  2441. return RtlSubAuthoritySid (
  2442. pSid,
  2443. nSubAuthority
  2444. );
  2445. }
  2446. PUCHAR
  2447. GetSidSubAuthorityCount (
  2448. PSID pSid
  2449. )
  2450. /*++
  2451. Routine Description:
  2452. This function returns the address of the sub-authority count field of
  2453. an SID.
  2454. Arguments:
  2455. pSid - Pointer to the SID data structure.
  2456. Return Value:
  2457. Address of the sub-authority count field of an SID.
  2458. --*/
  2459. {
  2460. SetLastError(0);
  2461. return RtlSubAuthorityCountSid (
  2462. pSid
  2463. );
  2464. }
  2465. DWORD
  2466. APIENTRY
  2467. GetLengthSid (
  2468. PSID pSid
  2469. )
  2470. /*++
  2471. Routine Description:
  2472. This routine returns the length, in bytes, of a structurally valid SID.
  2473. Arguments:
  2474. pSid - Points to the SID whose length is to be returned. The
  2475. SID's structure is assumed to be valid.
  2476. Return Value:
  2477. DWORD - The length, in bytes, of the SID.
  2478. --*/
  2479. {
  2480. SetLastError(0);
  2481. return RtlLengthSid (
  2482. pSid
  2483. );
  2484. }
  2485. BOOL
  2486. APIENTRY
  2487. CopySid (
  2488. DWORD nDestinationSidLength,
  2489. PSID pDestinationSid,
  2490. PSID pSourceSid
  2491. )
  2492. /*++
  2493. Routine Description:
  2494. This routine copies the value of the source SID to the destination
  2495. SID.
  2496. Arguments:
  2497. nDestinationSidLength - Indicates the length, in bytes, of the
  2498. destination SID buffer.
  2499. pDestinationSid - Pointer to a buffer to receive a copy of the
  2500. source Sid value.
  2501. pSourceSid - Supplies the Sid value to be copied.
  2502. Return Value:
  2503. Returns TRUE for success, FALSE for failure. Extended error status
  2504. is available using GetLastError.
  2505. --*/
  2506. {
  2507. NTSTATUS Status;
  2508. Status = RtlCopySid (
  2509. nDestinationSidLength,
  2510. pDestinationSid,
  2511. pSourceSid
  2512. );
  2513. if ( !NT_SUCCESS(Status) ) {
  2514. BaseSetLastNTError(Status);
  2515. return FALSE;
  2516. }
  2517. return TRUE;
  2518. }
  2519. BOOL
  2520. APIENTRY
  2521. AreAllAccessesGranted (
  2522. DWORD GrantedAccess,
  2523. DWORD DesiredAccess
  2524. )
  2525. /*++
  2526. Routine Description:
  2527. This routine is used to check a desired access mask against a
  2528. granted access mask.
  2529. Arguments:
  2530. GrantedAccess - Specifies the granted access mask.
  2531. DesiredAccess - Specifies the desired access mask.
  2532. Return Value:
  2533. BOOL - TRUE if the GrantedAccess mask has all the bits set that
  2534. the DesiredAccess mask has set. That is, TRUE is returned if
  2535. all of the desired accesses have been granted.
  2536. --*/
  2537. {
  2538. return (BOOL) RtlAreAllAccessesGranted (
  2539. GrantedAccess,
  2540. DesiredAccess
  2541. );
  2542. }
  2543. BOOL
  2544. APIENTRY
  2545. AreAnyAccessesGranted (
  2546. DWORD GrantedAccess,
  2547. DWORD DesiredAccess
  2548. )
  2549. /*++
  2550. Routine Description:
  2551. This routine is used to test whether any of a set of desired
  2552. accesses are granted by a granted access mask.
  2553. Arguments:
  2554. GrantedAccess - Specifies the granted access mask.
  2555. DesiredAccess - Specifies the desired access mask.
  2556. Return Value:
  2557. BOOL - TRUE if the GrantedAccess mask contains any of the bits
  2558. specified in the DesiredAccess mask. That is, if any of the
  2559. desired accesses have been granted, TRUE is returned.
  2560. --*/
  2561. {
  2562. return (BOOL) RtlAreAnyAccessesGranted (
  2563. GrantedAccess,
  2564. DesiredAccess
  2565. );
  2566. }
  2567. VOID
  2568. APIENTRY
  2569. MapGenericMask (
  2570. PDWORD AccessMask,
  2571. PGENERIC_MAPPING GenericMapping
  2572. )
  2573. /*++
  2574. Routine Description:
  2575. This routine maps all generic accesses in the provided access mask
  2576. to specific and standard accesses according to the provided
  2577. GenericMapping. The resulting mask will not have any of the
  2578. generic bits set (GenericRead, GenericWrite, GenericExecute, or
  2579. GenericAll) or any undefined bits set, but may have any other bit
  2580. set. If bits other than the generic bits are provided on input,
  2581. they will not be cleared bt the mapping.
  2582. Arguments:
  2583. AccessMask - Points to the access mask to be mapped.
  2584. GenericMapping - The mapping of generic to specific and standard
  2585. access types.
  2586. Return Value:
  2587. None.
  2588. --*/
  2589. {
  2590. RtlMapGenericMask (
  2591. AccessMask,
  2592. GenericMapping
  2593. );
  2594. }
  2595. BOOL
  2596. APIENTRY
  2597. IsValidAcl (
  2598. PACL pAcl
  2599. )
  2600. /*++
  2601. Routine Description:
  2602. This procedure validates an ACL.
  2603. This involves validating the revision level of the ACL and ensuring
  2604. that the number of ACEs specified in the AceCount fit in the space
  2605. specified by the AclSize field of the ACL header.
  2606. Arguments:
  2607. pAcl - Pointer to the ACL structure to validate.
  2608. Return Value:
  2609. BOOLEAN - TRUE if the structure of Acl is valid.
  2610. --*/
  2611. {
  2612. if ( !RtlValidAcl( pAcl ) ) {
  2613. SetLastError(ERROR_INVALID_ACL);
  2614. return FALSE;
  2615. }
  2616. return TRUE;
  2617. }
  2618. BOOL
  2619. APIENTRY
  2620. InitializeAcl (
  2621. PACL pAcl,
  2622. DWORD nAclLength,
  2623. DWORD dwAclRevision
  2624. )
  2625. /*++
  2626. Routine Description:
  2627. InitializeAcl creates a new ACL in the caller supplied memory
  2628. buffer. The ACL contains zero ACEs; therefore, it is an empty ACL
  2629. as opposed to a nonexistent ACL. That is, if the ACL is now set
  2630. to an object it will implicitly deny access to everyone.
  2631. Arguments:
  2632. pAcl - Supplies the buffer containing the ACL being initialized
  2633. nAclLength - Supplies the length of the ace buffer in bytes
  2634. dwAclRevision - Supplies the revision for this Acl
  2635. Return Value:
  2636. Returns TRUE for success, FALSE for failure. Extended error status
  2637. is available using GetLastError.
  2638. --*/
  2639. {
  2640. NTSTATUS Status;
  2641. Status = RtlCreateAcl (
  2642. pAcl,
  2643. nAclLength,
  2644. dwAclRevision
  2645. );
  2646. if ( !NT_SUCCESS(Status) ) {
  2647. BaseSetLastNTError(Status);
  2648. return FALSE;
  2649. }
  2650. return TRUE;
  2651. }
  2652. BOOL
  2653. APIENTRY
  2654. GetAclInformation (
  2655. PACL pAcl,
  2656. PVOID pAclInformation,
  2657. DWORD nAclInformationLength,
  2658. ACL_INFORMATION_CLASS dwAclInformationClass
  2659. )
  2660. /*++
  2661. Routine Description:
  2662. This routine returns to the caller information about an ACL. The requested
  2663. information can be AclRevisionInformation, or AclSizeInformation.
  2664. Arguments:
  2665. pAcl - Supplies the Acl being examined
  2666. pAclInformation - Supplies the buffer to receive the information
  2667. being requested
  2668. nAclInformationLength - Supplies the length of the AclInformation
  2669. buffer in bytes
  2670. dwAclInformationClass - Supplies the type of information being
  2671. requested
  2672. Return Value:
  2673. Returns TRUE for success, FALSE for failure. Extended error status
  2674. is available using GetLastError.
  2675. --*/
  2676. {
  2677. NTSTATUS Status;
  2678. Status = RtlQueryInformationAcl (
  2679. pAcl,
  2680. pAclInformation,
  2681. nAclInformationLength,
  2682. dwAclInformationClass
  2683. );
  2684. if ( !NT_SUCCESS(Status) ) {
  2685. BaseSetLastNTError(Status);
  2686. return FALSE;
  2687. }
  2688. return TRUE;
  2689. }
  2690. BOOL
  2691. APIENTRY
  2692. SetAclInformation (
  2693. PACL pAcl,
  2694. PVOID pAclInformation,
  2695. DWORD nAclInformationLength,
  2696. ACL_INFORMATION_CLASS dwAclInformationClass
  2697. )
  2698. /*++
  2699. Routine Description:
  2700. This routine sets the state of an ACL. For now only the revision
  2701. level can be set and for now only a revision level of 1 is accepted
  2702. so this procedure is rather simple
  2703. Arguments:
  2704. pAcl - Supplies the Acl being altered
  2705. pAclInformation - Supplies the buffer containing the information
  2706. being set
  2707. nAclInformationLength - Supplies the length of the Acl information
  2708. buffer
  2709. dwAclInformationClass - Supplies the type of information begin set
  2710. Return Value:
  2711. Returns TRUE for success, FALSE for failure. Extended error status
  2712. is available using GetLastError.
  2713. --*/
  2714. {
  2715. NTSTATUS Status;
  2716. Status = RtlSetInformationAcl (
  2717. pAcl,
  2718. pAclInformation,
  2719. nAclInformationLength,
  2720. dwAclInformationClass
  2721. );
  2722. if ( !NT_SUCCESS(Status) ) {
  2723. BaseSetLastNTError(Status);
  2724. return FALSE;
  2725. }
  2726. return TRUE;
  2727. }
  2728. BOOL
  2729. APIENTRY
  2730. AddAce (
  2731. PACL pAcl,
  2732. DWORD dwAceRevision,
  2733. DWORD dwStartingAceIndex,
  2734. PVOID pAceList,
  2735. DWORD nAceListLength
  2736. )
  2737. /*++
  2738. Routine Description:
  2739. This routine adds a string of ACEs to an ACL.
  2740. Arguments:
  2741. pAcl - Supplies the Acl being modified
  2742. dwAceRevision - Supplies the Acl/Ace revision of the ACE being
  2743. added
  2744. dwStartingAceIndex - Supplies the ACE index which will be the
  2745. index of the first ace inserted in the acl. 0 for the
  2746. beginning of the list and MAXULONG for the end of the list.
  2747. pAceList - Supplies the list of Aces to be added to the Acl
  2748. nAceListLength - Supplies the size, in bytes, of the AceList
  2749. buffer
  2750. Return Value:
  2751. Returns TRUE for success, FALSE for failure. Extended error status
  2752. is available using GetLastError.
  2753. --*/
  2754. {
  2755. NTSTATUS Status;
  2756. Status = RtlAddAce (
  2757. pAcl,
  2758. dwAceRevision,
  2759. dwStartingAceIndex,
  2760. pAceList,
  2761. nAceListLength
  2762. );
  2763. if ( !NT_SUCCESS(Status) ) {
  2764. BaseSetLastNTError(Status);
  2765. return FALSE;
  2766. }
  2767. return TRUE;
  2768. }
  2769. BOOL
  2770. APIENTRY
  2771. DeleteAce (
  2772. PACL pAcl,
  2773. DWORD dwAceIndex
  2774. )
  2775. /*++
  2776. Routine Description:
  2777. This routine deletes one ACE from an ACL.
  2778. Arguments:
  2779. pAcl - Supplies the Acl being modified
  2780. dwAceIndex - Supplies the index of the Ace to delete.
  2781. Return Value:
  2782. Returns TRUE for success, FALSE for failure. Extended error status
  2783. is available using GetLastError.
  2784. --*/
  2785. {
  2786. NTSTATUS Status;
  2787. Status = RtlDeleteAce (
  2788. pAcl,
  2789. dwAceIndex
  2790. );
  2791. if ( !NT_SUCCESS(Status) ) {
  2792. BaseSetLastNTError(Status);
  2793. return FALSE;
  2794. }
  2795. return TRUE;
  2796. }
  2797. BOOL
  2798. APIENTRY
  2799. GetAce (
  2800. PACL pAcl,
  2801. DWORD dwAceIndex,
  2802. PVOID *pAce
  2803. )
  2804. /*++
  2805. Routine Description:
  2806. This routine returns a pointer to an ACE in an ACl referenced by
  2807. ACE index
  2808. Arguments:
  2809. pAcl - Supplies the ACL being queried
  2810. dwAceIndex - Supplies the Ace index to locate
  2811. pAce - Receives the address of the ACE within the ACL
  2812. Return Value:
  2813. Returns TRUE for success, FALSE for failure. Extended error status
  2814. is available using GetLastError.
  2815. --*/
  2816. {
  2817. NTSTATUS Status;
  2818. Status = RtlGetAce (
  2819. pAcl,
  2820. dwAceIndex,
  2821. pAce
  2822. );
  2823. if ( !NT_SUCCESS(Status) ) {
  2824. BaseSetLastNTError(Status);
  2825. return FALSE;
  2826. }
  2827. return TRUE;
  2828. }
  2829. BOOL
  2830. APIENTRY
  2831. AddAccessAllowedAce (
  2832. PACL pAcl,
  2833. DWORD dwAceRevision,
  2834. DWORD AccessMask,
  2835. PSID pSid
  2836. )
  2837. /*++
  2838. Routine Description:
  2839. This routine adds an ACCESS_ALLOWED ACE to an ACL. This is
  2840. expected to be a common form of ACL modification.
  2841. A very bland ACE header is placed in the ACE. It provides no
  2842. inheritance and no ACE flags.
  2843. Arguments:
  2844. PAcl - Supplies the Acl being modified
  2845. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  2846. AccessMask - The mask of accesses to be granted to the specified SID.
  2847. pSid - Pointer to the SID being granted access.
  2848. Return Value:
  2849. Returns TRUE for success, FALSE for failure. Extended error status
  2850. is available using GetLastError.
  2851. --*/
  2852. {
  2853. NTSTATUS Status;
  2854. Status = RtlAddAccessAllowedAce (
  2855. pAcl,
  2856. dwAceRevision,
  2857. AccessMask,
  2858. pSid
  2859. );
  2860. if ( !NT_SUCCESS(Status) ) {
  2861. BaseSetLastNTError(Status);
  2862. return FALSE;
  2863. }
  2864. return TRUE;
  2865. }
  2866. BOOL
  2867. APIENTRY
  2868. AddAccessAllowedAceEx (
  2869. PACL pAcl,
  2870. DWORD dwAceRevision,
  2871. DWORD AceFlags,
  2872. DWORD AccessMask,
  2873. PSID pSid
  2874. )
  2875. /*++
  2876. Routine Description:
  2877. This routine adds an ACCESS_ALLOWED ACE to an ACL. This is
  2878. expected to be a common form of ACL modification.
  2879. A very bland ACE header is placed in the ACE. The AceFlags and
  2880. inheritance are specified by the AceFlags parameter.
  2881. Arguments:
  2882. PAcl - Supplies the Acl being modified
  2883. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  2884. AceFlags - Supplies the inherit flags for the ACE.
  2885. AccessMask - The mask of accesses to be granted to the specified SID.
  2886. pSid - Pointer to the SID being granted access.
  2887. Return Value:
  2888. Returns TRUE for success, FALSE for failure. Extended error status
  2889. is available using GetLastError.
  2890. --*/
  2891. {
  2892. NTSTATUS Status;
  2893. Status = RtlAddAccessAllowedAceEx (
  2894. pAcl,
  2895. dwAceRevision,
  2896. AceFlags,
  2897. AccessMask,
  2898. pSid
  2899. );
  2900. if ( !NT_SUCCESS(Status) ) {
  2901. if ( Status == STATUS_INVALID_PARAMETER ) {
  2902. SetLastError( ERROR_INVALID_FLAGS );
  2903. } else {
  2904. BaseSetLastNTError(Status);
  2905. }
  2906. return FALSE;
  2907. }
  2908. return TRUE;
  2909. }
  2910. BOOL
  2911. APIENTRY
  2912. AddAccessDeniedAce (
  2913. PACL pAcl,
  2914. DWORD dwAceRevision,
  2915. DWORD AccessMask,
  2916. PSID pSid
  2917. )
  2918. /*++
  2919. Routine Description:
  2920. This routine adds an ACCESS_DENIED ACE to an ACL. This is
  2921. expected to be a common form of ACL modification.
  2922. A very bland ACE header is placed in the ACE. It provides no
  2923. inheritance and no ACE flags.
  2924. Arguments:
  2925. pAcl - Supplies the Acl being modified
  2926. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  2927. AccessMask - The mask of accesses to be denied to the specified SID.
  2928. pSid - Pointer to the SID being denied access.
  2929. Return Value:
  2930. Returns TRUE for success, FALSE for failure. Extended error status
  2931. is available using GetLastError.
  2932. --*/
  2933. {
  2934. NTSTATUS Status;
  2935. Status = RtlAddAccessDeniedAce (
  2936. pAcl,
  2937. dwAceRevision,
  2938. AccessMask,
  2939. pSid
  2940. );
  2941. if ( !NT_SUCCESS(Status) ) {
  2942. BaseSetLastNTError(Status);
  2943. return FALSE;
  2944. }
  2945. return TRUE;
  2946. }
  2947. BOOL
  2948. APIENTRY
  2949. AddAccessDeniedAceEx (
  2950. PACL pAcl,
  2951. DWORD dwAceRevision,
  2952. DWORD AceFlags,
  2953. DWORD AccessMask,
  2954. PSID pSid
  2955. )
  2956. /*++
  2957. Routine Description:
  2958. This routine adds an ACCESS_DENIED ACE to an ACL. This is
  2959. expected to be a common form of ACL modification.
  2960. A very bland ACE header is placed in the ACE. The AceFlags and
  2961. inheritance are specified by the AceFlags parameter.
  2962. Arguments:
  2963. pAcl - Supplies the Acl being modified
  2964. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  2965. AceFlags - Supplies the inherit flags for the ACE.
  2966. AccessMask - The mask of accesses to be denied to the specified SID.
  2967. pSid - Pointer to the SID being denied access.
  2968. Return Value:
  2969. Returns TRUE for success, FALSE for failure. Extended error status
  2970. is available using GetLastError.
  2971. --*/
  2972. {
  2973. NTSTATUS Status;
  2974. Status = RtlAddAccessDeniedAceEx (
  2975. pAcl,
  2976. dwAceRevision,
  2977. AceFlags,
  2978. AccessMask,
  2979. pSid
  2980. );
  2981. if ( !NT_SUCCESS(Status) ) {
  2982. if ( Status == STATUS_INVALID_PARAMETER ) {
  2983. SetLastError( ERROR_INVALID_FLAGS );
  2984. } else {
  2985. BaseSetLastNTError(Status);
  2986. }
  2987. return FALSE;
  2988. }
  2989. return TRUE;
  2990. }
  2991. BOOL
  2992. APIENTRY
  2993. AddAuditAccessAce(
  2994. PACL pAcl,
  2995. DWORD dwAceRevision,
  2996. DWORD dwAccessMask,
  2997. PSID pSid,
  2998. BOOL bAuditSuccess,
  2999. BOOL bAuditFailure
  3000. )
  3001. /*++
  3002. Routine Description:
  3003. This routine adds a SYSTEM_AUDIT ACE to an ACL. This is
  3004. expected to be a common form of ACL modification.
  3005. A very bland ACE header is placed in the ACE. It provides no
  3006. inheritance.
  3007. Parameters are used to indicate whether auditing is to be performed
  3008. on success, failure, or both.
  3009. Arguments:
  3010. pAcl - Supplies the Acl being modified
  3011. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  3012. dwAccessMask - The mask of accesses to be denied to the specified SID.
  3013. pSid - Pointer to the SID to be audited.
  3014. bAuditSuccess - If TRUE, indicates successful access attempts are to be
  3015. audited.
  3016. bAuditFailure - If TRUE, indicated failed access attempts are to be
  3017. audited.
  3018. Return Value:
  3019. Returns TRUE for success, FALSE for failure. Extended error status
  3020. is available using GetLastError.
  3021. --*/
  3022. {
  3023. NTSTATUS Status;
  3024. Status = RtlAddAuditAccessAce (
  3025. pAcl,
  3026. dwAceRevision,
  3027. dwAccessMask,
  3028. pSid,
  3029. (BOOLEAN)bAuditSuccess,
  3030. (BOOLEAN)bAuditFailure
  3031. );
  3032. if ( !NT_SUCCESS(Status) ) {
  3033. BaseSetLastNTError(Status);
  3034. return FALSE;
  3035. }
  3036. return TRUE;
  3037. }
  3038. BOOL
  3039. APIENTRY
  3040. AddAuditAccessAceEx(
  3041. PACL pAcl,
  3042. DWORD dwAceRevision,
  3043. DWORD AceFlags,
  3044. DWORD dwAccessMask,
  3045. PSID pSid,
  3046. BOOL bAuditSuccess,
  3047. BOOL bAuditFailure
  3048. )
  3049. /*++
  3050. Routine Description:
  3051. This routine adds a SYSTEM_AUDIT ACE to an ACL. This is
  3052. expected to be a common form of ACL modification.
  3053. A very bland ACE header is placed in the ACE. The AceFlags and
  3054. inheritance are specified by the AceFlags parameter.
  3055. Parameters are used to indicate whether auditing is to be performed
  3056. on success, failure, or both.
  3057. Arguments:
  3058. pAcl - Supplies the Acl being modified
  3059. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  3060. AceFlags - Supplies the inherit flags for the ACE.
  3061. dwAccessMask - The mask of accesses to be denied to the specified SID.
  3062. pSid - Pointer to the SID to be audited.
  3063. bAuditSuccess - If TRUE, indicates successful access attempts are to be
  3064. audited.
  3065. bAuditFailure - If TRUE, indicated failed access attempts are to be
  3066. audited.
  3067. Return Value:
  3068. Returns TRUE for success, FALSE for failure. Extended error status
  3069. is available using GetLastError.
  3070. --*/
  3071. {
  3072. NTSTATUS Status;
  3073. Status = RtlAddAuditAccessAceEx (
  3074. pAcl,
  3075. dwAceRevision,
  3076. AceFlags,
  3077. dwAccessMask,
  3078. pSid,
  3079. (BOOLEAN)bAuditSuccess,
  3080. (BOOLEAN)bAuditFailure
  3081. );
  3082. if ( !NT_SUCCESS(Status) ) {
  3083. if ( Status == STATUS_INVALID_PARAMETER ) {
  3084. SetLastError( ERROR_INVALID_FLAGS );
  3085. } else {
  3086. BaseSetLastNTError(Status);
  3087. }
  3088. return FALSE;
  3089. }
  3090. return TRUE;
  3091. }
  3092. BOOL
  3093. APIENTRY
  3094. AddAccessAllowedObjectAce (
  3095. PACL pAcl,
  3096. DWORD dwAceRevision,
  3097. DWORD AceFlags,
  3098. DWORD AccessMask,
  3099. GUID *ObjectTypeGuid,
  3100. GUID *InheritedObjectTypeGuid,
  3101. PSID pSid
  3102. )
  3103. /*++
  3104. Routine Description:
  3105. This routine adds an ACCESS_ALLOWED_OBJECT ACE to an ACL. This is
  3106. expected to be a common form of ACL modification.
  3107. A very bland ACE header is placed in the ACE.
  3108. Arguments:
  3109. PAcl - Supplies the Acl being modified
  3110. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  3111. AceFlags - Supplies the inherit flags for the ACE.
  3112. AccessMask - The mask of accesses to be granted to the specified SID.
  3113. ObjectTypeGuid - Supplies the GUID of the object this ACE applies to.
  3114. If NULL, no object type GUID is placed in the ACE.
  3115. InheritedObjectTypeGuid - Supplies the GUID of the object type that will
  3116. inherit this ACE. If NULL, no inherited object type GUID is placed in
  3117. the ACE.
  3118. pSid - Pointer to the SID being granted access.
  3119. Return Value:
  3120. Returns TRUE for success, FALSE for failure. Extended error status
  3121. is available using GetLastError.
  3122. --*/
  3123. {
  3124. NTSTATUS Status;
  3125. Status = RtlAddAccessAllowedObjectAce (
  3126. pAcl,
  3127. dwAceRevision,
  3128. AceFlags,
  3129. AccessMask,
  3130. ObjectTypeGuid,
  3131. InheritedObjectTypeGuid,
  3132. pSid
  3133. );
  3134. if ( !NT_SUCCESS(Status) ) {
  3135. if ( Status == STATUS_INVALID_PARAMETER ) {
  3136. SetLastError( ERROR_INVALID_FLAGS );
  3137. } else {
  3138. BaseSetLastNTError(Status);
  3139. }
  3140. return FALSE;
  3141. }
  3142. return TRUE;
  3143. }
  3144. BOOL
  3145. APIENTRY
  3146. AddAccessDeniedObjectAce (
  3147. PACL pAcl,
  3148. DWORD dwAceRevision,
  3149. DWORD AceFlags,
  3150. DWORD AccessMask,
  3151. GUID *ObjectTypeGuid,
  3152. GUID *InheritedObjectTypeGuid,
  3153. PSID pSid
  3154. )
  3155. /*++
  3156. Routine Description:
  3157. This routine adds an ACCESS_DENIED_OBJECT ACE to an ACL. This is
  3158. expected to be a common form of ACL modification.
  3159. A very bland ACE header is placed in the ACE.
  3160. Arguments:
  3161. PAcl - Supplies the Acl being modified
  3162. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  3163. AceFlags - Supplies the inherit flags for the ACE.
  3164. AccessMask - The mask of accesses to be granted to the specified SID.
  3165. ObjectTypeGuid - Supplies the GUID of the object this ACE applies to.
  3166. If NULL, no object type GUID is placed in the ACE.
  3167. InheritedObjectTypeGuid - Supplies the GUID of the object type that will
  3168. inherit this ACE. If NULL, no inherited object type GUID is placed in
  3169. the ACE.
  3170. pSid - Pointer to the SID being denied access.
  3171. Return Value:
  3172. Returns TRUE for success, FALSE for failure. Extended error status
  3173. is available using GetLastError.
  3174. --*/
  3175. {
  3176. NTSTATUS Status;
  3177. Status = RtlAddAccessDeniedObjectAce (
  3178. pAcl,
  3179. dwAceRevision,
  3180. AceFlags,
  3181. AccessMask,
  3182. ObjectTypeGuid,
  3183. InheritedObjectTypeGuid,
  3184. pSid
  3185. );
  3186. if ( !NT_SUCCESS(Status) ) {
  3187. if ( Status == STATUS_INVALID_PARAMETER ) {
  3188. SetLastError( ERROR_INVALID_FLAGS );
  3189. } else {
  3190. BaseSetLastNTError(Status);
  3191. }
  3192. return FALSE;
  3193. }
  3194. return TRUE;
  3195. }
  3196. BOOL
  3197. APIENTRY
  3198. AddAuditAccessObjectAce(
  3199. PACL pAcl,
  3200. DWORD dwAceRevision,
  3201. DWORD AceFlags,
  3202. DWORD dwAccessMask,
  3203. GUID *ObjectTypeGuid,
  3204. GUID *InheritedObjectTypeGuid,
  3205. PSID pSid,
  3206. BOOL bAuditSuccess,
  3207. BOOL bAuditFailure
  3208. )
  3209. /*++
  3210. Routine Description:
  3211. This routine adds a SYSTEM_AUDIT_OBJECT_ACE to an ACL. This is
  3212. expected to be a common form of ACL modification.
  3213. A very bland ACE header is placed in the ACE. The AceFlags and
  3214. inheritance are specified by the AceFlags parameter.
  3215. Parameters are used to indicate whether auditing is to be performed
  3216. on success, failure, or both.
  3217. Arguments:
  3218. pAcl - Supplies the Acl being modified
  3219. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  3220. AceFlags - Supplies the inherit flags for the ACE.
  3221. dwAccessMask - The mask of accesses to be denied to the specified SID.
  3222. ObjectTypeGuid - Supplies the GUID of the object this ACE applies to.
  3223. If NULL, no object type GUID is placed in the ACE.
  3224. InheritedObjectTypeGuid - Supplies the GUID of the object type that will
  3225. inherit this ACE. If NULL, no inherited object type GUID is placed in
  3226. the ACE.
  3227. pSid - Pointer to the SID to be audited.
  3228. bAuditSuccess - If TRUE, indicates successful access attempts are to be
  3229. audited.
  3230. bAuditFailure - If TRUE, indicated failed access attempts are to be
  3231. audited.
  3232. Return Value:
  3233. Returns TRUE for success, FALSE for failure. Extended error status
  3234. is available using GetLastError.
  3235. --*/
  3236. {
  3237. NTSTATUS Status;
  3238. Status = RtlAddAuditAccessObjectAce (
  3239. pAcl,
  3240. dwAceRevision,
  3241. AceFlags,
  3242. dwAccessMask,
  3243. ObjectTypeGuid,
  3244. InheritedObjectTypeGuid,
  3245. pSid,
  3246. (BOOLEAN)bAuditSuccess,
  3247. (BOOLEAN)bAuditFailure
  3248. );
  3249. if ( !NT_SUCCESS(Status) ) {
  3250. if ( Status == STATUS_INVALID_PARAMETER ) {
  3251. SetLastError( ERROR_INVALID_FLAGS );
  3252. } else {
  3253. BaseSetLastNTError(Status);
  3254. }
  3255. return FALSE;
  3256. }
  3257. return TRUE;
  3258. }
  3259. BOOL
  3260. APIENTRY
  3261. FindFirstFreeAce (
  3262. PACL pAcl,
  3263. PVOID *pAce
  3264. )
  3265. /*++
  3266. Routine Description:
  3267. This routine returns a pointer to the first free byte in an Acl
  3268. or NULL if the acl is ill-formed. If the Acl is full then the
  3269. return pointer is to the byte immediately following the acl, and
  3270. TRUE will be returned.
  3271. Arguments:
  3272. pAcl - Supplies a pointer to the Acl to examine
  3273. pAce - Receives a pointer to the first free position in the Acl
  3274. Return Value:
  3275. Returns TRUE for success, FALSE for failure. Extended error status
  3276. is available using GetLastError.
  3277. --*/
  3278. {
  3279. if ( !RtlFirstFreeAce( pAcl, pAce ) ) {
  3280. SetLastError(ERROR_INVALID_ACL);
  3281. return FALSE;
  3282. }
  3283. return TRUE;
  3284. }
  3285. BOOL
  3286. APIENTRY
  3287. InitializeSecurityDescriptor (
  3288. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3289. DWORD dwRevision
  3290. )
  3291. /*++
  3292. Routine Description:
  3293. This procedure initializes a new "absolute format" security descriptor.
  3294. After the procedure call the security descriptor is initialized with no
  3295. system ACL, no discretionary ACL, no owner, no primary group and
  3296. all control flags set to false (null).
  3297. Arguments:
  3298. pSecurityDescriptor - Supplies the security descriptor to
  3299. initialize.
  3300. dwRevision - Provides the revision level to assign to the security
  3301. descriptor. This should be one (1) for this release.
  3302. Return Value:
  3303. Returns TRUE for success, FALSE for failure. Extended error status
  3304. is available using GetLastError.
  3305. --*/
  3306. {
  3307. NTSTATUS Status;
  3308. Status = RtlCreateSecurityDescriptor (
  3309. pSecurityDescriptor,
  3310. dwRevision
  3311. );
  3312. if ( !NT_SUCCESS(Status) ) {
  3313. BaseSetLastNTError(Status);
  3314. return FALSE;
  3315. }
  3316. return TRUE;
  3317. }
  3318. BOOL
  3319. APIENTRY
  3320. IsValidSecurityDescriptor (
  3321. PSECURITY_DESCRIPTOR pSecurityDescriptor
  3322. )
  3323. /*++
  3324. Routine Description:
  3325. This procedure validates a SecurityDescriptor's structure. This
  3326. involves validating the revision levels of each component of the
  3327. security descriptor.
  3328. Arguments:
  3329. pSecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
  3330. to validate.
  3331. Return Value:
  3332. BOOL - TRUE if the structure of SecurityDescriptor is valid.
  3333. --*/
  3334. {
  3335. if (!RtlValidSecurityDescriptor ( pSecurityDescriptor )) {
  3336. BaseSetLastNTError( STATUS_INVALID_SECURITY_DESCR );
  3337. return( FALSE );
  3338. }
  3339. return( TRUE );
  3340. }
  3341. DWORD
  3342. APIENTRY
  3343. GetSecurityDescriptorLength (
  3344. PSECURITY_DESCRIPTOR pSecurityDescriptor
  3345. )
  3346. /*++
  3347. Routine Description:
  3348. This routine returns the length, in bytes, necessary to capture a
  3349. structurally valid SECURITY_DESCRIPTOR. The length includes the length
  3350. of all associated data structures (like SIDs and ACLs). The length also
  3351. takes into account the alignment requirements of each component.
  3352. The minimum length of a security descriptor (one which has no associated
  3353. SIDs or ACLs) is SECURITY_DESCRIPTOR_MIN_LENGTH.
  3354. Arguments:
  3355. pSecurityDescriptor - Points to the SECURITY_DESCRIPTOR whose
  3356. length is to be returned. The SECURITY_DESCRIPTOR's structure
  3357. is assumed to be valid.
  3358. Return Value:
  3359. DWORD - The length, in bytes, of the SECURITY_DESCRIPTOR.
  3360. --*/
  3361. {
  3362. return RtlLengthSecurityDescriptor (
  3363. pSecurityDescriptor
  3364. );
  3365. }
  3366. BOOL
  3367. APIENTRY
  3368. GetSecurityDescriptorControl (
  3369. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3370. PSECURITY_DESCRIPTOR_CONTROL pControl,
  3371. LPDWORD lpdwRevision
  3372. )
  3373. /*++
  3374. Routine Description:
  3375. This procedure retrieves the control information from a security descriptor.
  3376. Arguments:
  3377. pSecurityDescriptor - Supplies the security descriptor.
  3378. pControl - Receives the control information.
  3379. lpdwRevision - Receives the revision of the security descriptor.
  3380. This value will always be returned, even if an error is
  3381. returned by this routine.
  3382. Return Value:
  3383. Returns TRUE for success, FALSE for failure. Extended error status
  3384. is available using GetLastError.
  3385. --*/
  3386. {
  3387. NTSTATUS Status;
  3388. Status = RtlGetControlSecurityDescriptor (
  3389. pSecurityDescriptor,
  3390. pControl,
  3391. lpdwRevision
  3392. );
  3393. if ( !NT_SUCCESS(Status) ) {
  3394. BaseSetLastNTError(Status);
  3395. return FALSE;
  3396. }
  3397. return TRUE;
  3398. }
  3399. BOOL
  3400. APIENTRY
  3401. SetSecurityDescriptorControl (
  3402. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3403. SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
  3404. SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet
  3405. )
  3406. /*++
  3407. Routine Description:
  3408. This procedure sets the control information in a security descriptor.
  3409. For instance,
  3410. SetSecurityDescriptorControl( &SecDesc,
  3411. SE_DACL_PROTECTED,
  3412. SE_DACL_PROTECTED );
  3413. marks the DACL on the security descriptor as protected. And
  3414. SetSecurityDescriptorControl( &SecDesc,
  3415. SE_DACL_PROTECTED,
  3416. 0 );
  3417. marks the DACL as not protected.
  3418. Arguments:
  3419. pSecurityDescriptor - Supplies the security descriptor.
  3420. ControlBitsOfInterest - A mask of the control bits being changed, set,
  3421. or reset by this call. The mask is the logical OR of one or more of
  3422. the following flags:
  3423. SE_DACL_UNTRUSTED
  3424. SE_SERVER_SECURITY
  3425. SE_DACL_AUTO_INHERIT_REQ
  3426. SE_SACL_AUTO_INHERIT_REQ
  3427. SE_DACL_AUTO_INHERITED
  3428. SE_SACL_AUTO_INHERITED
  3429. SE_DACL_PROTECTED
  3430. SE_SACL_PROTECTED
  3431. ControlBitsToSet - A mask indicating what the bits specified by ControlBitsOfInterest
  3432. should be set to.
  3433. Return Value:
  3434. Returns TRUE for success, FALSE for failure. Extended error status
  3435. is available using GetLastError.
  3436. --*/
  3437. {
  3438. NTSTATUS Status;
  3439. Status = RtlSetControlSecurityDescriptor (
  3440. pSecurityDescriptor,
  3441. ControlBitsOfInterest,
  3442. ControlBitsToSet );
  3443. if ( !NT_SUCCESS(Status) ) {
  3444. BaseSetLastNTError(Status);
  3445. return FALSE;
  3446. }
  3447. return TRUE;
  3448. }
  3449. BOOL
  3450. APIENTRY
  3451. SetSecurityDescriptorDacl (
  3452. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3453. BOOL bDaclPresent,
  3454. PACL pDacl OPTIONAL,
  3455. BOOL bDaclDefaulted OPTIONAL
  3456. )
  3457. /*++
  3458. Routine Description:
  3459. This procedure sets the discretionary ACL information of an absolute
  3460. format security descriptor. If there is already a discretionary ACL
  3461. present in the security descriptor, it is superseded.
  3462. Arguments:
  3463. pSecurityDescriptor - Supplies the security descriptor to be which
  3464. the discretionary ACL is to be added.
  3465. bDaclPresent - If FALSE, indicates the DaclPresent flag in the
  3466. security descriptor should be set to FALSE. In this case, the
  3467. remaining optional parameters are ignored. Otherwise, the
  3468. DaclPresent control flag in the security descriptor is set to
  3469. TRUE and the remaining optional parameters are not ignored.
  3470. pDacl - Supplies the discretionary ACL for the security
  3471. descriptor. If this optional parameter is not passed, then a
  3472. null ACL is assigned to the security descriptor. A null
  3473. discretionary ACL unconditionally grants access. The ACL is
  3474. referenced by, not copied into, by the security descriptor.
  3475. bDaclDefaulted - When set, indicates the discretionary ACL was
  3476. picked up from some default mechanism (rather than explicitly
  3477. specified by a user). This value is set in the DaclDefaulted
  3478. control flag in the security descriptor. If this optional
  3479. parameter is not passed, then the DaclDefaulted flag will be
  3480. cleared.
  3481. Return Value:
  3482. Returns TRUE for success, FALSE for failure. Extended error status
  3483. is available using GetLastError.
  3484. --*/
  3485. {
  3486. NTSTATUS Status;
  3487. Status = RtlSetDaclSecurityDescriptor (
  3488. pSecurityDescriptor,
  3489. (BOOLEAN)bDaclPresent,
  3490. pDacl,
  3491. (BOOLEAN)bDaclDefaulted
  3492. );
  3493. if ( !NT_SUCCESS(Status) ) {
  3494. BaseSetLastNTError(Status);
  3495. return FALSE;
  3496. }
  3497. return TRUE;
  3498. }
  3499. BOOL
  3500. APIENTRY
  3501. GetSecurityDescriptorDacl (
  3502. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3503. LPBOOL lpbDaclPresent,
  3504. PACL *pDacl,
  3505. LPBOOL lpbDaclDefaulted
  3506. )
  3507. /*++
  3508. Routine Description:
  3509. This procedure retrieves the discretionary ACL information of a
  3510. security descriptor.
  3511. Arguments:
  3512. pSecurityDescriptor - Supplies the security descriptor.
  3513. lpbDaclPresent - If TRUE, indicates that the security descriptor
  3514. does contain a discretionary ACL. In this case, the
  3515. remaining OUT parameters will receive valid values.
  3516. Otherwise, the security descriptor does not contain a
  3517. discretionary ACL and the remaining OUT parameters will not
  3518. receive valid values.
  3519. pDacl - This value is returned only if the value returned for the
  3520. DaclPresent flag is TRUE. In this case, the Dacl parameter
  3521. receives the address of the security descriptor's
  3522. discretionary ACL. If this value is returned as null, then
  3523. the security descriptor has a null discretionary ACL.
  3524. lpbDaclDefaulted - This value is returned only if the value
  3525. returned for the DaclPresent flag is TRUE. In this case, the
  3526. DaclDefaulted parameter receives the value of the security
  3527. descriptor's DaclDefaulted control flag.
  3528. Return Value:
  3529. Returns TRUE for success, FALSE for failure. Extended error status
  3530. is available using GetLastError.
  3531. --*/
  3532. {
  3533. NTSTATUS Status;
  3534. BOOLEAN DaclPresent, DaclDefaulted;
  3535. Status = RtlGetDaclSecurityDescriptor (
  3536. pSecurityDescriptor,
  3537. &DaclPresent,
  3538. pDacl,
  3539. &DaclDefaulted
  3540. );
  3541. if ( !NT_SUCCESS(Status) ) {
  3542. BaseSetLastNTError(Status);
  3543. return FALSE;
  3544. } else {
  3545. *lpbDaclPresent = (BOOL)DaclPresent;
  3546. *lpbDaclDefaulted = (BOOL)DaclDefaulted;
  3547. }
  3548. return TRUE;
  3549. }
  3550. BOOL
  3551. APIENTRY
  3552. SetSecurityDescriptorSacl (
  3553. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3554. BOOL bSaclPresent,
  3555. PACL pSacl OPTIONAL,
  3556. BOOL bSaclDefaulted
  3557. )
  3558. /*++
  3559. Routine Description:
  3560. This procedure sets the system ACL information of an absolute security
  3561. descriptor. If there is already a system ACL present in the
  3562. security descriptor, it is superseded.
  3563. Arguments:
  3564. pSecurityDescriptor - Supplies the security descriptor to be which
  3565. the system ACL is to be added.
  3566. bSaclPresent - If FALSE, indicates the SaclPresent flag in the
  3567. security descriptor should be set to FALSE. In this case,
  3568. the remaining optional parameters are ignored. Otherwise,
  3569. the SaclPresent control flag in the security descriptor is
  3570. set to TRUE and the remaining optional parameters are not
  3571. ignored.
  3572. pSacl - Supplies the system ACL for the security descriptor. If
  3573. this optional parameter is not passed, then a null ACL is
  3574. assigned to the security descriptor. The ACL is referenced
  3575. by, not copied into, by the security descriptor.
  3576. bSaclDefaulted - When set, indicates the system ACL was picked up
  3577. from some default mechanism (rather than explicitly specified
  3578. by a user). This value is set in the SaclDefaulted control
  3579. flag in the security descriptor. If this optional parameter
  3580. is not passed, then the SaclDefaulted flag will be cleared.
  3581. Return Value:
  3582. Returns TRUE for success, FALSE for failure. Extended error status
  3583. is available using GetLastError.
  3584. --*/
  3585. {
  3586. NTSTATUS Status;
  3587. Status = RtlSetSaclSecurityDescriptor (
  3588. pSecurityDescriptor,
  3589. (BOOLEAN)bSaclPresent,
  3590. pSacl,
  3591. (BOOLEAN)bSaclDefaulted
  3592. );
  3593. if ( !NT_SUCCESS(Status) ) {
  3594. BaseSetLastNTError(Status);
  3595. return FALSE;
  3596. }
  3597. return TRUE;
  3598. }
  3599. BOOL
  3600. APIENTRY
  3601. GetSecurityDescriptorSacl (
  3602. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3603. LPBOOL lpbSaclPresent,
  3604. PACL *pSacl,
  3605. LPBOOL lpbSaclDefaulted
  3606. )
  3607. /*++
  3608. Routine Description:
  3609. This procedure retrieves the system ACL information of a security
  3610. descriptor.
  3611. Arguments:
  3612. pSecurityDescriptor - Supplies the security descriptor.
  3613. lpbSaclPresent - If TRUE, indicates that the security descriptor
  3614. does contain a system ACL. In this case, the remaining OUT
  3615. parameters will receive valid values. Otherwise, the
  3616. security descriptor does not contain a system ACL and the
  3617. remaining OUT parameters will not receive valid values.
  3618. pSacl - This value is returned only if the value returned for the
  3619. SaclPresent flag is TRUE. In this case, the Sacl parameter
  3620. receives the address of the security descriptor's system ACL.
  3621. If this value is returned as null, then the security
  3622. descriptor has a null system ACL.
  3623. lpbSaclDefaulted - This value is returned only if the value
  3624. returned for the SaclPresent flag is TRUE. In this case, the
  3625. SaclDefaulted parameter receives the value of the security
  3626. descriptor's SaclDefaulted control flag.
  3627. Return Value:
  3628. Returns TRUE for success, FALSE for failure. Extended error status
  3629. is available using GetLastError.
  3630. --*/
  3631. {
  3632. NTSTATUS Status;
  3633. BOOLEAN SaclPresent, SaclDefaulted;
  3634. Status = RtlGetSaclSecurityDescriptor (
  3635. pSecurityDescriptor,
  3636. &SaclPresent,
  3637. pSacl,
  3638. &SaclDefaulted
  3639. );
  3640. if ( !NT_SUCCESS(Status) ) {
  3641. BaseSetLastNTError(Status);
  3642. return FALSE;
  3643. } else {
  3644. *lpbSaclPresent = (BOOL)SaclPresent;
  3645. *lpbSaclDefaulted = (BOOL)SaclDefaulted;
  3646. }
  3647. return TRUE;
  3648. }
  3649. BOOL
  3650. APIENTRY
  3651. SetSecurityDescriptorOwner (
  3652. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3653. PSID pOwner OPTIONAL,
  3654. BOOL bOwnerDefaulted OPTIONAL
  3655. )
  3656. /*++
  3657. Routine Description:
  3658. This procedure sets the owner information of an absolute security
  3659. descriptor. If there is already an owner present in the security
  3660. descriptor, it is superseded.
  3661. Arguments:
  3662. pSecurityDescriptor - Supplies the security descriptor in which
  3663. the owner is to be set. If the security descriptor already
  3664. includes an owner, it will be superseded by the new owner.
  3665. pOwner - Supplies the owner SID for the security descriptor. If
  3666. this optional parameter is not passed, then the owner is
  3667. cleared (indicating the security descriptor has no owner).
  3668. The SID is referenced by, not copied into, the security
  3669. descriptor.
  3670. bOwnerDefaulted - When set, indicates the owner was picked up from
  3671. some default mechanism (rather than explicitly specified by a
  3672. user). This value is set in the OwnerDefaulted control flag
  3673. in the security descriptor. If this optional parameter is
  3674. not passed, then the SaclDefaulted flag will be cleared.
  3675. Return Value:
  3676. Returns TRUE for success, FALSE for failure. Extended error status
  3677. is available using GetLastError.
  3678. --*/
  3679. {
  3680. NTSTATUS Status;
  3681. Status = RtlSetOwnerSecurityDescriptor (
  3682. pSecurityDescriptor,
  3683. pOwner,
  3684. (BOOLEAN)bOwnerDefaulted
  3685. );
  3686. if ( !NT_SUCCESS(Status) ) {
  3687. BaseSetLastNTError(Status);
  3688. return FALSE;
  3689. }
  3690. return TRUE;
  3691. }
  3692. BOOL
  3693. APIENTRY
  3694. GetSecurityDescriptorOwner (
  3695. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3696. PSID *pOwner,
  3697. LPBOOL lpbOwnerDefaulted
  3698. )
  3699. /*++
  3700. Routine Description:
  3701. This procedure retrieves the owner information of a security
  3702. descriptor.
  3703. Arguments:
  3704. pSecurityDescriptor - Supplies the security descriptor.
  3705. pOwner - Receives a pointer to the owner SID. If the security
  3706. descriptor does not currently contain an owner, then this
  3707. value will be returned as null. In this case, the remaining
  3708. OUT parameters are not given valid return values. Otherwise,
  3709. this parameter points to an SID and the remaining OUT
  3710. parameters are provided valid return values.
  3711. lpbOwnerDefaulted - This value is returned only if the value
  3712. returned for the Owner parameter is not null. In this case,
  3713. the OwnerDefaulted parameter receives the value of the
  3714. security descriptor's OwnerDefaulted control flag.
  3715. Return Value:
  3716. Returns TRUE for success, FALSE for failure. Extended error status
  3717. is available using GetLastError.
  3718. --*/
  3719. {
  3720. NTSTATUS Status;
  3721. BOOLEAN OwnerDefaulted;
  3722. Status = RtlGetOwnerSecurityDescriptor (
  3723. pSecurityDescriptor,
  3724. pOwner,
  3725. &OwnerDefaulted
  3726. );
  3727. if ( !NT_SUCCESS(Status) ) {
  3728. BaseSetLastNTError(Status);
  3729. return FALSE;
  3730. } else {
  3731. *lpbOwnerDefaulted = (BOOL)OwnerDefaulted;
  3732. }
  3733. return TRUE;
  3734. }
  3735. BOOL
  3736. APIENTRY
  3737. SetSecurityDescriptorGroup (
  3738. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3739. PSID pGroup OPTIONAL,
  3740. BOOL bGroupDefaulted OPTIONAL
  3741. )
  3742. /*++
  3743. Routine Description:
  3744. This procedure sets the primary group information of an absolute security
  3745. descriptor. If there is already an primary group present in the
  3746. security descriptor, it is superseded.
  3747. Arguments:
  3748. pSecurityDescriptor - Supplies the security descriptor in which
  3749. the primary group is to be set. If the security descriptor
  3750. already includes a primary group, it will be superseded by
  3751. the new group.
  3752. pGroup - Supplies the primary group SID for the security
  3753. descriptor. If this optional parameter is not passed, then
  3754. the primary group is cleared (indicating the security
  3755. descriptor has no primary group). The SID is referenced by,
  3756. not copied into, the security descriptor.
  3757. bGroupDefaulted - When set, indicates the owner was picked up from
  3758. some default mechanism (rather than explicitly specified by a
  3759. user). This value is set in the OwnerDefaulted control flag
  3760. in the security descriptor. If this optional parameter is
  3761. not passed, then the SaclDefaulted flag will be cleared.
  3762. Return Value:
  3763. Returns TRUE for success, FALSE for failure. Extended error status
  3764. is available using GetLastError.
  3765. --*/
  3766. {
  3767. NTSTATUS Status;
  3768. Status = RtlSetGroupSecurityDescriptor (
  3769. pSecurityDescriptor,
  3770. pGroup,
  3771. (BOOLEAN)bGroupDefaulted
  3772. );
  3773. if ( !NT_SUCCESS(Status) ) {
  3774. BaseSetLastNTError(Status);
  3775. return FALSE;
  3776. }
  3777. return TRUE;
  3778. }
  3779. BOOL
  3780. APIENTRY
  3781. GetSecurityDescriptorGroup (
  3782. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3783. PSID *pGroup,
  3784. LPBOOL lpbGroupDefaulted
  3785. )
  3786. /*++
  3787. Routine Description:
  3788. This procedure retrieves the primary group information of a
  3789. security descriptor.
  3790. Arguments:
  3791. pSecurityDescriptor - Supplies the security descriptor.
  3792. pGroup - Receives a pointer to the primary group SID. If the
  3793. security descriptor does not currently contain a primary
  3794. group, then this value will be returned as null. In this
  3795. case, the remaining OUT parameters are not given valid return
  3796. values. Otherwise, this parameter points to an SID and the
  3797. remaining OUT parameters are provided valid return values.
  3798. lpbGroupDefaulted - This value is returned only if the value
  3799. returned for the Group parameter is not null. In this case,
  3800. the GroupDefaulted parameter receives the value of the
  3801. security descriptor's GroupDefaulted control flag.
  3802. Return Value:
  3803. Returns TRUE for success, FALSE for failure. Extended error status
  3804. is available using GetLastError.
  3805. --*/
  3806. {
  3807. NTSTATUS Status;
  3808. BOOLEAN GroupDefaulted;
  3809. Status = RtlGetGroupSecurityDescriptor (
  3810. pSecurityDescriptor,
  3811. pGroup,
  3812. &GroupDefaulted
  3813. );
  3814. if ( !NT_SUCCESS(Status) ) {
  3815. BaseSetLastNTError(Status);
  3816. return FALSE;
  3817. } else {
  3818. *lpbGroupDefaulted = GroupDefaulted;
  3819. }
  3820. return TRUE;
  3821. }
  3822. BOOL
  3823. APIENTRY
  3824. CreatePrivateObjectSecurity (
  3825. PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
  3826. PSECURITY_DESCRIPTOR CreatorDescriptor OPTIONAL,
  3827. PSECURITY_DESCRIPTOR * NewDescriptor,
  3828. BOOL IsDirectoryObject,
  3829. HANDLE Token,
  3830. PGENERIC_MAPPING GenericMapping
  3831. )
  3832. /*++
  3833. Routine Description:
  3834. The procedure is used to allocpate and initialize a self-relative
  3835. Security Descriptor for a new protected server's object. It is called
  3836. when a new protected server object is being created. The generated
  3837. security descriptor will be in self-relative form.
  3838. This procedure, called only from user mode, is used to establish a
  3839. security descriptor for a new protected server's object. When no
  3840. longer needed, this descriptor must be freed using
  3841. DestroyPrivateObjectSecurity().
  3842. Arguments:
  3843. ParentDescriptor - Supplies the Security Descriptor for the parent
  3844. directory under which a new object is being created. If there is
  3845. no parent directory, then this argument is specified as NULL.
  3846. CreatorDescriptor - (Optionally) Points to a security descriptor
  3847. presented by the creator of the object. If the creator of the
  3848. object did not explicitly pass security information for the new
  3849. object, then a null pointer should be passed.
  3850. NewDescriptor - Points to a pointer that is to be made to point to the
  3851. newly allocated self-relative security descriptor.
  3852. IsDirectoryObject - Specifies if the new object is going to be a
  3853. directory object. A value of TRUE indicates the object is a
  3854. container of other objects.
  3855. Token - Supplies the token for the client on whose behalf the
  3856. object is being created. If it is an impersonation token,
  3857. then it must be at SecurityIdentification level or higher. If
  3858. it is not an impersonation token, the operation proceeds
  3859. normally.
  3860. A client token is used to retrieve default security
  3861. information for the new object, such as default owner, primary
  3862. group, and discretionary access control. The token must be
  3863. open for TOKEN_QUERY access.
  3864. GenericMapping - Supplies a pointer to a generic mapping array denoting
  3865. the mapping between each generic right to specific rights.
  3866. Return Value:
  3867. Returns TRUE for success, FALSE for failure. Extended error status
  3868. is available using GetLastError.
  3869. --*/
  3870. {
  3871. NTSTATUS Status;
  3872. Status = RtlNewSecurityObject (
  3873. ParentDescriptor,
  3874. CreatorDescriptor,
  3875. NewDescriptor,
  3876. (BOOLEAN)IsDirectoryObject,
  3877. Token,
  3878. GenericMapping
  3879. );
  3880. if ( !NT_SUCCESS(Status) ) {
  3881. BaseSetLastNTError(Status);
  3882. return FALSE;
  3883. }
  3884. return TRUE;
  3885. }
  3886. BOOL
  3887. APIENTRY
  3888. ConvertToAutoInheritPrivateObjectSecurity(
  3889. PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
  3890. PSECURITY_DESCRIPTOR CurrentSecurityDescriptor,
  3891. PSECURITY_DESCRIPTOR *NewSecurityDescriptor,
  3892. GUID *ObjectType,
  3893. BOOLEAN IsDirectoryObject,
  3894. PGENERIC_MAPPING GenericMapping
  3895. )
  3896. /*++
  3897. Routine Description:
  3898. This is a converts a security descriptor whose ACLs are not marked
  3899. as AutoInherit to a security descriptor whose ACLs are marked as
  3900. AutoInherit.
  3901. The resultant security descriptor has appropriate ACEs marked as
  3902. INHERITED_ACE if the ACE was apparently inherited from the ParentDescriptor.
  3903. If the ACL is apparently not inherited from the ParentDescriptor, the
  3904. ACL in the resultant security descriptor is marked as SE_xACL_PROTECTED.
  3905. This routine takes into account the various mechanisms for creating an
  3906. inherited ACL:
  3907. 1) It was inherited via NT 3.x or 4.x ACL inheritance when the
  3908. object was created.
  3909. 2) The subsequent parent or child ACL was re-written by the ACL editor
  3910. (which perversely modifies the ACL to a semantically equivalent but
  3911. different form).
  3912. 3) It was inherited by asking the ACL editor (File Manager/Explorer) to
  3913. "Replace permissions on existing files/directories".
  3914. 4) It was inherited via cacls.exe.
  3915. If the ACLs in the resultant security descriptor are not marked as protected, the
  3916. resultant ACL is composed of two sets of ACEs: the non-inherited ACEs followed by the
  3917. inherited ACEs. The inherited ACEs are computed by called CreatePrivateObjectSecurityEx
  3918. using the ParentDescriptor. The non-inherited ACEs are those ACEs (or parts of ACEs)
  3919. from the original CurrentSecurityDescriptor that were not inherited from the parent.
  3920. When building the resultant NewSecurityDescriptor, care is taken to not change the
  3921. semantics of the security descriptor. As such, allow and deny ACEs are never moved
  3922. in relation to one another. If such movement is needed (for instance to place all
  3923. non-inherited ACEs at the front of an ACL), the ACL is marked as protected to prevent
  3924. the semantic change.
  3925. ACEs in the original CurrentSecurityDescriptor are matched with ACEs in a computed
  3926. inherited security descriptor to determine which ACEs were inherited. During the
  3927. comparision there is no requirement of a one to one match. For instance, one ACL
  3928. might use separate ACEs to grant a user read and write access while the other ACL
  3929. might use only one ACE to grant the same access. Or one ACL might grant the user
  3930. the same access twice and the other might grant the user that access only once. Or
  3931. one ACL might combine the container inherit and object inherit ACE into a single ACE.
  3932. In all these case, equivalent ACE combinations are deemed equivalent.
  3933. No security checks are made in this routine. The resultant security descriptor
  3934. is equivalent to the new security descriptor, so the caller needs no permission to
  3935. update the security descriptor to the new form.
  3936. The Owner and Group field of the CurrentSecurityDescriptor is maintained.
  3937. This routine support revision 2 and revision 4 ACLs. It does not support compound
  3938. ACEs.
  3939. Arguments:
  3940. ParentDescriptor - Supplies the Security Descriptor for the parent
  3941. directory under which a object exists. If there is
  3942. no parent directory, then this argument is specified as NULL.
  3943. CurrentSecurityDescriptor - Supplies a pointer to the objects security descriptor
  3944. that is going to be altered by this procedure.
  3945. NewSecurityDescriptor Points to a pointer that is to be made to point to the
  3946. newly allocated self-relative security descriptor. When no
  3947. longer needed, this descriptor must be freed using
  3948. DestroyPrivateObjectSecurity().
  3949. ObjectType - GUID of the object type being created. If the object being
  3950. created has no GUID associated with it, then this argument is
  3951. specified as NULL.
  3952. IsDirectoryObject - Specifies if the object is a
  3953. directory object. A value of TRUE indicates the object is a
  3954. container of other objects.
  3955. GenericMapping - Supplies a pointer to a generic mapping array denoting
  3956. the mapping between each generic right to specific rights.
  3957. Return Value:
  3958. Returns TRUE for success, FALSE for failure. Extended error status
  3959. is available using GetLastError.
  3960. --*/
  3961. {
  3962. NTSTATUS Status;
  3963. Status = RtlConvertToAutoInheritSecurityObject(
  3964. ParentDescriptor,
  3965. CurrentSecurityDescriptor,
  3966. NewSecurityDescriptor,
  3967. ObjectType,
  3968. IsDirectoryObject,
  3969. GenericMapping ) ;
  3970. if ( !NT_SUCCESS(Status) ) {
  3971. BaseSetLastNTError(Status);
  3972. return FALSE;
  3973. }
  3974. return TRUE;
  3975. }
  3976. BOOL
  3977. APIENTRY
  3978. CreatePrivateObjectSecurityEx (
  3979. PSECURITY_DESCRIPTOR ParentDescriptor,
  3980. PSECURITY_DESCRIPTOR CreatorDescriptor,
  3981. PSECURITY_DESCRIPTOR * NewDescriptor,
  3982. GUID *ObjectType,
  3983. BOOL IsContainerObject,
  3984. ULONG AutoInheritFlags,
  3985. HANDLE Token,
  3986. PGENERIC_MAPPING GenericMapping
  3987. )
  3988. /*++
  3989. Routine Description:
  3990. The procedure is used to allocate and initialize a self-relative
  3991. Security Descriptor for a new protected server's object. It is called
  3992. when a new protected server object is being created. The generated
  3993. security descriptor will be in self-relative form.
  3994. This procedure, called only from user mode, is used to establish a
  3995. security descriptor for a new protected server's object.
  3996. Arguments:
  3997. ParentDescriptor - Supplies the Security Descriptor for the parent
  3998. directory under which a new object is being created. If there is
  3999. no parent directory, then this argument is specified as NULL.
  4000. CreatorDescriptor - (Optionally) Points to a security descriptor
  4001. presented by the creator of the object. If the creator of the
  4002. object did not explicitly pass security information for the new
  4003. object, then a null pointer should be passed.
  4004. NewDescriptor - Points to a pointer that is to be made to point to the
  4005. newly allocated self-relative security descriptor. When no
  4006. longer needed, this descriptor must be freed using
  4007. DestroyPrivateObjectSecurity().
  4008. ObjectType - GUID of the object type being created. If the object being
  4009. created has no GUID associated with it, then this argument is
  4010. specified as NULL.
  4011. IsContainerObject - Specifies if the new object is going to be a
  4012. container object. A value of TRUE indicates the object is a
  4013. container of other objects.
  4014. AutoInheritFlags - Controls automatic inheritance of ACES from the Parent
  4015. Descriptor. Valid values are a bits mask of the logical OR of
  4016. one or more of the following bits:
  4017. SEF_DACL_AUTO_INHERIT - If set, inherit ACEs from the
  4018. DACL ParentDescriptor are inherited to NewDescriptor in addition
  4019. to any explicit ACEs specified by the CreatorDescriptor.
  4020. SEF_SACL_AUTO_INHERIT - If set, inherit ACEs from the
  4021. SACL ParentDescriptor are inherited to NewDescriptor in addition
  4022. to any explicit ACEs specified by the CreatorDescriptor.
  4023. SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT - If set, the CreatorDescriptor
  4024. is the default descriptor for ObjectType. As such, the
  4025. CreatorDescriptor will be ignored if any ObjectType specific
  4026. ACEs are inherited from the parent. If not such ACEs are inherited,
  4027. the CreatorDescriptor is handled as though this flag were not
  4028. specified.
  4029. SEF_AVOID_PRIVILEGE_CHECK - If set, no privilege checking is done by this
  4030. routine. This flag is useful while implementing automatic inheritance
  4031. to avoid checking privileges on each child updated.
  4032. SEF_AVOID_OWNER_CHECK - If set, no owner checking is done by this routine.
  4033. SEF_DEFAULT_OWNER_FROM_PARENT - If set, the owner of NewDescriptor will
  4034. default to the owner from ParentDescriptor. If not set, the owner
  4035. of NewDescriptor will default to the user specified in Token.
  4036. In either case, the owner of NewDescriptor is set to the owner from
  4037. the CreatorDescriptor if that field is specified.
  4038. SEF_DEFAULT_GROUP_FROM_PARENT - If set, the group of NewDescriptor will
  4039. default to the group from ParentDescriptor. If not set, the group
  4040. of NewDescriptor will default to the group specified in Token.
  4041. In either case, the group of NewDescriptor is set to the group from
  4042. the CreatorDescriptor if that field is specified.
  4043. Token - Supplies the token for the client on whose behalf the
  4044. object is being created. If it is an impersonation token,
  4045. then it must be at SecurityIdentification level or higher. If
  4046. it is not an impersonation token, the operation proceeds
  4047. normally.
  4048. A client token is used to retrieve default security
  4049. information for the new object, such as default owner, primary
  4050. group, and discretionary access control. The token must be
  4051. open for TOKEN_QUERY access.
  4052. GenericMapping - Supplies a pointer to a generic mapping array denoting
  4053. the mapping between each generic right to specific rights.
  4054. Return Value:
  4055. Returns TRUE for success, FALSE for failure. Extended error status
  4056. is available using GetLastError.
  4057. --*/
  4058. {
  4059. NTSTATUS Status;
  4060. Status = RtlNewSecurityObjectEx (
  4061. ParentDescriptor,
  4062. CreatorDescriptor,
  4063. NewDescriptor,
  4064. ObjectType,
  4065. (BOOLEAN)IsContainerObject,
  4066. AutoInheritFlags,
  4067. Token,
  4068. GenericMapping
  4069. );
  4070. if ( !NT_SUCCESS(Status) ) {
  4071. BaseSetLastNTError(Status);
  4072. return FALSE;
  4073. }
  4074. return TRUE;
  4075. }
  4076. BOOL
  4077. APIENTRY
  4078. CreatePrivateObjectSecurityWithMultipleInheritance (
  4079. PSECURITY_DESCRIPTOR ParentDescriptor,
  4080. PSECURITY_DESCRIPTOR CreatorDescriptor,
  4081. PSECURITY_DESCRIPTOR * NewDescriptor,
  4082. GUID **ObjectTypes,
  4083. ULONG GuidCount,
  4084. BOOL IsContainerObject,
  4085. ULONG AutoInheritFlags,
  4086. HANDLE Token,
  4087. PGENERIC_MAPPING GenericMapping
  4088. )
  4089. /*++
  4090. Routine Description:
  4091. The procedure is used to allocate and initialize a self-relative
  4092. Security Descriptor for a new protected server's object. It is called
  4093. when a new protected server object is being created. The generated
  4094. security descriptor will be in self-relative form.
  4095. This procedure, called only from user mode, is used to establish a
  4096. security descriptor for a new protected server's object.
  4097. Arguments:
  4098. ParentDescriptor - Supplies the Security Descriptor for the parent
  4099. directory under which a new object is being created. If there is
  4100. no parent directory, then this argument is specified as NULL.
  4101. CreatorDescriptor - (Optionally) Points to a security descriptor
  4102. presented by the creator of the object. If the creator of the
  4103. object did not explicitly pass security information for the new
  4104. object, then a null pointer should be passed.
  4105. NewDescriptor - Points to a pointer that is to be made to point to the
  4106. newly allocated self-relative security descriptor. When no
  4107. longer needed, this descriptor must be freed using
  4108. DestroyPrivateObjectSecurity().
  4109. ObjectTypes - List of GUIDs of the object type being created. If the object being
  4110. created has no GUID associated with it, then this argument is
  4111. specified as NULL.
  4112. GuidCount - Number of guids present in the list.
  4113. IsContainerObject - Specifies if the new object is going to be a
  4114. container object. A value of TRUE indicates the object is a
  4115. container of other objects.
  4116. AutoInheritFlags - Controls automatic inheritance of ACES from the Parent
  4117. Descriptor. Valid values are a bits mask of the logical OR of
  4118. one or more of the following bits:
  4119. SEF_DACL_AUTO_INHERIT - If set, inherit ACEs from the
  4120. DACL ParentDescriptor are inherited to NewDescriptor in addition
  4121. to any explicit ACEs specified by the CreatorDescriptor.
  4122. SEF_SACL_AUTO_INHERIT - If set, inherit ACEs from the
  4123. SACL ParentDescriptor are inherited to NewDescriptor in addition
  4124. to any explicit ACEs specified by the CreatorDescriptor.
  4125. SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT - If set, the CreatorDescriptor
  4126. is the default descriptor for ObjectType. As such, the
  4127. CreatorDescriptor will be ignored if any ObjectType specific
  4128. ACEs are inherited from the parent. If not such ACEs are inherited,
  4129. the CreatorDescriptor is handled as though this flag were not
  4130. specified.
  4131. SEF_AVOID_PRIVILEGE_CHECK - If set, no privilege checking is done by this
  4132. routine. This flag is useful while implementing automatic inheritance
  4133. to avoid checking privileges on each child updated.
  4134. SEF_AVOID_OWNER_CHECK - If set, no owner checking is done by this routine.
  4135. SEF_DEFAULT_OWNER_FROM_PARENT - If set, the owner of NewDescriptor will
  4136. default to the owner from ParentDescriptor. If not set, the owner
  4137. of NewDescriptor will default to the user specified in Token.
  4138. In either case, the owner of NewDescriptor is set to the owner from
  4139. the CreatorDescriptor if that field is specified.
  4140. SEF_DEFAULT_GROUP_FROM_PARENT - If set, the group of NewDescriptor will
  4141. default to the group from ParentDescriptor. If not set, the group
  4142. of NewDescriptor will default to the group specified in Token.
  4143. In either case, the group of NewDescriptor is set to the group from
  4144. the CreatorDescriptor if that field is specified.
  4145. Token - Supplies the token for the client on whose behalf the
  4146. object is being created. If it is an impersonation token,
  4147. then it must be at SecurityIdentification level or higher. If
  4148. it is not an impersonation token, the operation proceeds
  4149. normally.
  4150. A client token is used to retrieve default security
  4151. information for the new object, such as default owner, primary
  4152. group, and discretionary access control. The token must be
  4153. open for TOKEN_QUERY access.
  4154. GenericMapping - Supplies a pointer to a generic mapping array denoting
  4155. the mapping between each generic right to specific rights.
  4156. Return Value:
  4157. Returns TRUE for success, FALSE for failure. Extended error status
  4158. is available using GetLastError.
  4159. --*/
  4160. {
  4161. NTSTATUS Status;
  4162. Status = RtlNewSecurityObjectWithMultipleInheritance (
  4163. ParentDescriptor,
  4164. CreatorDescriptor,
  4165. NewDescriptor,
  4166. ObjectTypes,
  4167. GuidCount,
  4168. (BOOLEAN)IsContainerObject,
  4169. AutoInheritFlags,
  4170. Token,
  4171. GenericMapping
  4172. );
  4173. if ( !NT_SUCCESS(Status) ) {
  4174. BaseSetLastNTError(Status);
  4175. return FALSE;
  4176. }
  4177. return TRUE;
  4178. }
  4179. BOOL
  4180. APIENTRY
  4181. SetPrivateObjectSecurity (
  4182. SECURITY_INFORMATION SecurityInformation,
  4183. PSECURITY_DESCRIPTOR ModificationDescriptor,
  4184. PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
  4185. PGENERIC_MAPPING GenericMapping,
  4186. HANDLE Token OPTIONAL
  4187. )
  4188. /*++
  4189. Routine Description:
  4190. Modify an object's existing self-relative form security descriptor.
  4191. This procedure, called only from user mode, is used to update a
  4192. security descriptor on an existing protected server's object. It
  4193. applies changes requested by a new security descriptor to the existing
  4194. security descriptor. If necessary, this routine will allocate
  4195. additional memory to produce a larger security descriptor. All access
  4196. checking is expected to be done before calling this routine. This
  4197. includes checking for WRITE_OWNER, WRITE_DAC, and privilege to assign a
  4198. system ACL as appropriate.
  4199. The caller of this routine must not be impersonating a client.
  4200. Arguments:
  4201. SecurityInformation - Indicates which security information is
  4202. to be applied to the object. The value(s) to be assigned are
  4203. passed in the ModificationDescriptor parameter.
  4204. ModificationDescriptor - Supplies the input security descriptor to be
  4205. applied to the object. The caller of this routine is expected
  4206. to probe and capture the passed security descriptor before calling
  4207. and release it after calling.
  4208. ObjectsSecurityDescriptor - Supplies the address of a pointer to
  4209. the objects security descriptor that is going to be altered by
  4210. this procedure. This security descriptor must be in self-
  4211. relative form or an error will be returned.
  4212. GenericMapping - This argument provides the mapping of generic to
  4213. specific/standard access types for the object being accessed.
  4214. This mapping structure is expected to be safe to access
  4215. (i.e., captured if necessary) prior to be passed to this routine.
  4216. Token - (optionally) Supplies the token for the client on whose
  4217. behalf the security is being modified. This parameter is only
  4218. required to ensure that the client has provided a legitimate
  4219. value for a new owner SID. The token must be open for
  4220. TOKEN_QUERY access.
  4221. Return Value:
  4222. Returns TRUE for success, FALSE for failure. Extended error status
  4223. is available using GetLastError.
  4224. --*/
  4225. {
  4226. NTSTATUS Status;
  4227. Status = RtlSetSecurityObject (
  4228. SecurityInformation,
  4229. ModificationDescriptor,
  4230. ObjectsSecurityDescriptor,
  4231. GenericMapping,
  4232. Token
  4233. );
  4234. if ( !NT_SUCCESS(Status) ) {
  4235. BaseSetLastNTError(Status);
  4236. return FALSE;
  4237. }
  4238. return TRUE;
  4239. }
  4240. BOOL
  4241. APIENTRY
  4242. SetPrivateObjectSecurityEx (
  4243. SECURITY_INFORMATION SecurityInformation,
  4244. PSECURITY_DESCRIPTOR ModificationDescriptor,
  4245. PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
  4246. ULONG AutoInheritFlags,
  4247. PGENERIC_MAPPING GenericMapping,
  4248. HANDLE Token OPTIONAL
  4249. )
  4250. /*++
  4251. Routine Description:
  4252. Modify an object's existing self-relative form security descriptor.
  4253. This procedure, called only from user mode, is used to update a
  4254. security descriptor on an existing protected server's object. It
  4255. applies changes requested by a new security descriptor to the existing
  4256. security descriptor. If necessary, this routine will allocate
  4257. additional memory to produce a larger security descriptor. All access
  4258. checking is expected to be done before calling this routine. This
  4259. includes checking for WRITE_OWNER, WRITE_DAC, and privilege to assign a
  4260. system ACL as appropriate.
  4261. The caller of this routine must not be impersonating a client.
  4262. Arguments:
  4263. SecurityInformation - Indicates which security information is
  4264. to be applied to the object. The value(s) to be assigned are
  4265. passed in the ModificationDescriptor parameter.
  4266. ModificationDescriptor - Supplies the input security descriptor to be
  4267. applied to the object. The caller of this routine is expected
  4268. to probe and capture the passed security descriptor before calling
  4269. and release it after calling.
  4270. ObjectsSecurityDescriptor - Supplies the address of a pointer to
  4271. the objects security descriptor that is going to be altered by
  4272. this procedure. This security descriptor must be in self-
  4273. relative form or an error will be returned.
  4274. AutoInheritFlags - Controls automatic inheritance of ACES.
  4275. Valid values are a bits mask of the logical OR of
  4276. one or more of the following bits:
  4277. SEF_DACL_AUTO_INHERIT - If set, inherited ACEs from the
  4278. DACL in the ObjectsSecurityDescriptor are preserved and inherited ACEs from
  4279. the ModificationDescriptor are ignored. Inherited ACEs are not supposed
  4280. to be modified; so preserving them across this call is appropriate.
  4281. If a protected server does not itself implement auto inheritance, it should
  4282. not set this bit. The caller of the protected server may implement
  4283. auto inheritance and my indeed be modifying inherited ACEs.
  4284. SEF_SACL_AUTO_INHERIT - If set, inherited ACEs from the
  4285. SACL in the ObjectsSecurityDescriptor are preserved and inherited ACEs from
  4286. the ModificationDescriptor are ignored. Inherited ACEs are not supposed
  4287. to be modified; so preserving them across this call is appropriate.
  4288. If a protected server does not itself implement auto inheritance, it should
  4289. not set this bit. The caller of the protected server may implement
  4290. auto inheritance and my indeed be modifying inherited ACEs.
  4291. GenericMapping - This argument provides the mapping of generic to
  4292. specific/standard access types for the object being accessed.
  4293. This mapping structure is expected to be safe to access
  4294. (i.e., captured if necessary) prior to be passed to this routine.
  4295. Token - (optionally) Supplies the token for the client on whose
  4296. behalf the security is being modified. This parameter is only
  4297. required to ensure that the client has provided a legitimate
  4298. value for a new owner SID. The token must be open for
  4299. TOKEN_QUERY access.
  4300. Return Value:
  4301. Returns TRUE for success, FALSE for failure. Extended error status
  4302. is available using GetLastError.
  4303. --*/
  4304. {
  4305. NTSTATUS Status;
  4306. Status = RtlSetSecurityObjectEx (
  4307. SecurityInformation,
  4308. ModificationDescriptor,
  4309. ObjectsSecurityDescriptor,
  4310. AutoInheritFlags,
  4311. GenericMapping,
  4312. Token
  4313. );
  4314. if ( !NT_SUCCESS(Status) ) {
  4315. BaseSetLastNTError(Status);
  4316. return FALSE;
  4317. }
  4318. return TRUE;
  4319. }
  4320. BOOL
  4321. APIENTRY
  4322. GetPrivateObjectSecurity (
  4323. PSECURITY_DESCRIPTOR ObjectDescriptor,
  4324. SECURITY_INFORMATION SecurityInformation,
  4325. PSECURITY_DESCRIPTOR ResultantDescriptor,
  4326. DWORD DescriptorLength,
  4327. PDWORD ReturnLength
  4328. )
  4329. /*++
  4330. Routine Description:
  4331. Query information from a protected server object's existing security
  4332. descriptor.
  4333. This procedure, called only from user mode, is used to retrieve
  4334. information from a security descriptor on an existing protected
  4335. server's object. All access checking is expected to be done before
  4336. calling this routine. This includes checking for READ_CONTROL, and
  4337. privilege to read a system ACL as appropriate.
  4338. Arguments:
  4339. ObjectDescriptor - Points to a pointer to a security descriptor to be
  4340. queried.
  4341. SecurityInformation - Identifies the security information being
  4342. requested.
  4343. ResultantDescriptor - Points to buffer to receive the resultant
  4344. security descriptor. The resultant security descriptor will
  4345. contain all information requested by the SecurityInformation
  4346. parameter.
  4347. DescriptorLength - Is an unsigned integer which indicates the length,
  4348. in bytes, of the buffer provided to receive the resultant
  4349. descriptor.
  4350. ReturnLength - Receives an unsigned integer indicating the actual
  4351. number of bytes needed in the ResultantDescriptor to store the
  4352. requested information. If the value returned is greater than the
  4353. value passed via the DescriptorLength parameter, then
  4354. STATUS_BUFFER_TOO_SMALL is returned and no information is returned.
  4355. Return Value:
  4356. Returns TRUE for success, FALSE for failure. Extended error status
  4357. is available using GetLastError.
  4358. --*/
  4359. {
  4360. NTSTATUS Status;
  4361. Status = RtlQuerySecurityObject (
  4362. ObjectDescriptor,
  4363. SecurityInformation,
  4364. ResultantDescriptor,
  4365. DescriptorLength,
  4366. ReturnLength
  4367. );
  4368. if ( !NT_SUCCESS(Status) ) {
  4369. BaseSetLastNTError(Status);
  4370. return FALSE;
  4371. }
  4372. return TRUE;
  4373. }
  4374. BOOL
  4375. APIENTRY
  4376. DestroyPrivateObjectSecurity (
  4377. PSECURITY_DESCRIPTOR * ObjectDescriptor
  4378. )
  4379. /*++
  4380. Routine Description:
  4381. Delete a protected server object's security descriptor.
  4382. This procedure, called only from user mode, is used to delete a
  4383. security descriptor associated with a protected server's object. This
  4384. routine will normally be called by a protected server during object
  4385. deletion. The input descriptor is expected to be one created via
  4386. a call to CreatePrivateObjectSecurity.
  4387. Arguments:
  4388. ObjectDescriptor - Points to a pointer to a security descriptor to be
  4389. deleted.
  4390. Return Value:
  4391. Returns TRUE for success, FALSE for failure. Extended error status
  4392. is available using GetLastError.
  4393. --*/
  4394. {
  4395. NTSTATUS Status;
  4396. Status = RtlDeleteSecurityObject (
  4397. ObjectDescriptor
  4398. );
  4399. if ( !NT_SUCCESS(Status) ) {
  4400. BaseSetLastNTError(Status);
  4401. return FALSE;
  4402. }
  4403. return TRUE;
  4404. }
  4405. BOOL
  4406. APIENTRY
  4407. MakeSelfRelativeSD (
  4408. PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
  4409. PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
  4410. LPDWORD lpdwBufferLength
  4411. )
  4412. /*++
  4413. Routine Description:
  4414. Converts a security descriptor in absolute form to one in self-relative
  4415. form.
  4416. Arguments:
  4417. pAbsoluteSecurityDescriptor - Pointer to an absolute format
  4418. security descriptor. This descriptor will not be modified.
  4419. pSelfRelativeSecurityDescriptor - Pointer to a buffer that will
  4420. contain the returned self-relative security descriptor.
  4421. lpdwBufferLength - Supplies the length of the buffer. If the
  4422. supplied buffer is not large enough to hold the self-relative
  4423. security descriptor, an error will be returned, and this field
  4424. will return the minimum size required.
  4425. Return Value:
  4426. Returns TRUE for success, FALSE for failure. Extended error status
  4427. is available using GetLastError.
  4428. --*/
  4429. {
  4430. NTSTATUS Status;
  4431. Status = RtlAbsoluteToSelfRelativeSD (
  4432. pAbsoluteSecurityDescriptor,
  4433. pSelfRelativeSecurityDescriptor,
  4434. lpdwBufferLength
  4435. );
  4436. if ( !NT_SUCCESS(Status) ) {
  4437. BaseSetLastNTError(Status);
  4438. return FALSE;
  4439. }
  4440. return TRUE;
  4441. }
  4442. BOOL
  4443. APIENTRY
  4444. MakeAbsoluteSD (
  4445. PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
  4446. PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
  4447. LPDWORD lpdwAbsoluteSecurityDescriptorSize,
  4448. PACL pDacl,
  4449. LPDWORD lpdwDaclSize,
  4450. PACL pSacl,
  4451. LPDWORD lpdwSaclSize,
  4452. PSID pOwner,
  4453. LPDWORD lpdwOwnerSize,
  4454. PSID pPrimaryGroup,
  4455. LPDWORD lpdwPrimaryGroupSize
  4456. )
  4457. /*++
  4458. Routine Description:
  4459. Converts a security descriptor from self-relative format to absolute
  4460. format
  4461. Arguments:
  4462. pSecurityDescriptor - Supplies a pointer to a security descriptor
  4463. in Self-Relative format
  4464. pAbsoluteSecurityDescriptor - A pointer to a buffer in which will
  4465. be placed the main body of the Absolute format security
  4466. descriptor.
  4467. lpdwAbsoluteSecurityDescriptorSize - The size in bytes of the
  4468. buffer pointed to by pAbsoluteSecurityDescriptor.
  4469. pDacl - Supplies a pointer to a buffer that will contain the Dacl
  4470. of the output descriptor. This pointer will be referenced by,
  4471. not copied into, the output descriptor.
  4472. lpdwDaclSize - Supplies the size of the buffer pointed to by Dacl.
  4473. In case of error, it will return the minimum size necessary to
  4474. contain the Dacl.
  4475. pSacl - Supplies a pointer to a buffer that will contain the Sacl
  4476. of the output descriptor. This pointer will be referenced by,
  4477. not copied into, the output descriptor.
  4478. lpdwSaclSize - Supplies the size of the buffer pointed to by Sacl.
  4479. In case of error, it will return the minimum size necessary to
  4480. contain the Sacl.
  4481. pOwner - Supplies a pointer to a buffer that will contain the
  4482. Owner of the output descriptor. This pointer will be
  4483. referenced by, not copied into, the output descriptor.
  4484. lpdwOwnerSize - Supplies the size of the buffer pointed to by
  4485. Owner. In case of error, it will return the minimum size
  4486. necessary to contain the Owner.
  4487. pPrimaryGroup - Supplies a pointer to a buffer that will contain
  4488. the PrimaryGroup of the output descriptor. This pointer will
  4489. be referenced by, not copied into, the output descriptor.
  4490. lpdwPrimaryGroupSize - Supplies the size of the buffer pointed to
  4491. by PrimaryGroup. In case of error, it will return the minimum
  4492. size necessary to contain the PrimaryGroup.
  4493. Return Value:
  4494. Returns TRUE for success, FALSE for failure. Extended error status
  4495. is available using GetLastError.
  4496. --*/
  4497. {
  4498. NTSTATUS Status;
  4499. Status = RtlSelfRelativeToAbsoluteSD (
  4500. pSelfRelativeSecurityDescriptor,
  4501. pAbsoluteSecurityDescriptor,
  4502. lpdwAbsoluteSecurityDescriptorSize,
  4503. pDacl,
  4504. lpdwDaclSize,
  4505. pSacl,
  4506. lpdwSaclSize,
  4507. pOwner,
  4508. lpdwOwnerSize,
  4509. pPrimaryGroup,
  4510. lpdwPrimaryGroupSize
  4511. );
  4512. if ( !NT_SUCCESS(Status) ) {
  4513. BaseSetLastNTError(Status);
  4514. return FALSE;
  4515. }
  4516. return TRUE;
  4517. }
  4518. VOID
  4519. SetSecurityAccessMask(
  4520. IN SECURITY_INFORMATION SecurityInformation,
  4521. OUT LPDWORD DesiredAccess
  4522. )
  4523. /*++
  4524. Routine Description:
  4525. This routine builds an access mask representing the accesses necessary
  4526. to set the object security information specified in the SecurityInformation
  4527. parameter. While it is not difficult to determine this information,
  4528. the use of a single routine to generate it will ensure minimal impact
  4529. when the security information associated with an object is extended in
  4530. the future (to include mandatory access control information).
  4531. Arguments:
  4532. SecurityInformation - Identifies the object's security information to be
  4533. modified.
  4534. DesiredAccess - Points to an access mask to be set to represent the
  4535. accesses necessary to modify the information specified in the
  4536. SecurityInformation parameter.
  4537. Return Value:
  4538. None.
  4539. --*/
  4540. {
  4541. //
  4542. // Figure out accesses needed to perform the indicated operation(s).
  4543. //
  4544. (*DesiredAccess) = 0;
  4545. if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
  4546. (SecurityInformation & GROUP_SECURITY_INFORMATION) ) {
  4547. (*DesiredAccess) |= WRITE_OWNER;
  4548. }
  4549. if (SecurityInformation & DACL_SECURITY_INFORMATION) {
  4550. (*DesiredAccess) |= WRITE_DAC;
  4551. }
  4552. if (SecurityInformation & SACL_SECURITY_INFORMATION) {
  4553. (*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
  4554. }
  4555. return;
  4556. }
  4557. VOID
  4558. QuerySecurityAccessMask(
  4559. IN SECURITY_INFORMATION SecurityInformation,
  4560. OUT LPDWORD DesiredAccess
  4561. )
  4562. /*++
  4563. Routine Description:
  4564. This routine builds an access mask representing the accesses necessary
  4565. to query the object security information specified in the
  4566. SecurityInformation parameter. While it is not difficult to determine
  4567. this information, the use of a single routine to generate it will ensure
  4568. minimal impact when the security information associated with an object is
  4569. extended in the future (to include mandatory access control information).
  4570. Arguments:
  4571. SecurityInformation - Identifies the object's security information to be
  4572. queried.
  4573. DesiredAccess - Points to an access mask to be set to represent the
  4574. accesses necessary to query the information specified in the
  4575. SecurityInformation parameter.
  4576. Return Value:
  4577. None.
  4578. --*/
  4579. {
  4580. //
  4581. // Figure out accesses needed to perform the indicated operation(s).
  4582. //
  4583. (*DesiredAccess) = 0;
  4584. if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
  4585. (SecurityInformation & GROUP_SECURITY_INFORMATION) ||
  4586. (SecurityInformation & DACL_SECURITY_INFORMATION)) {
  4587. (*DesiredAccess) |= READ_CONTROL;
  4588. }
  4589. if ((SecurityInformation & SACL_SECURITY_INFORMATION)) {
  4590. (*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
  4591. }
  4592. return;
  4593. }
  4594. BOOL
  4595. APIENTRY
  4596. SetFileSecurityW(
  4597. LPCWSTR lpFileName,
  4598. SECURITY_INFORMATION SecurityInformation,
  4599. PSECURITY_DESCRIPTOR pSecurityDescriptor
  4600. )
  4601. /*++
  4602. Routine Description:
  4603. This API can be used to set the security of a file or directory
  4604. (process, file, event, etc.). This call is only successful if the
  4605. following conditions are met:
  4606. o If the object's owner or group is to be set, the caller must
  4607. have WRITE_OWNER permission or have SeTakeOwnershipPrivilege.
  4608. o If the object's DACL is to be set, the caller must have
  4609. WRITE_DAC permission or be the object's owner.
  4610. o If the object's SACL is to be set, the caller must have
  4611. SeSecurityPrivilege.
  4612. Arguments:
  4613. lpFileName - Supplies the file name of the file to open. Depending on
  4614. the value of the FailIfExists parameter, this name may or may
  4615. not already exist.
  4616. SecurityInformation - A pointer to information describing the
  4617. contents of the Security Descriptor.
  4618. pSecurityDescriptor - A pointer to a well formed Security
  4619. Descriptor.
  4620. Return Value:
  4621. TRUE - The operation was successful.
  4622. FALSE/NULL - The operation failed. Extended error status is available
  4623. using GetLastError.
  4624. --*/
  4625. {
  4626. NTSTATUS Status;
  4627. HANDLE FileHandle;
  4628. ACCESS_MASK DesiredAccess;
  4629. OBJECT_ATTRIBUTES Obja;
  4630. UNICODE_STRING FileName;
  4631. BOOLEAN TranslationStatus;
  4632. RTL_RELATIVE_NAME_U RelativeName;
  4633. IO_STATUS_BLOCK IoStatusBlock;
  4634. PVOID FreeBuffer;
  4635. SetSecurityAccessMask(
  4636. SecurityInformation,
  4637. &DesiredAccess
  4638. );
  4639. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  4640. lpFileName,
  4641. &FileName,
  4642. NULL,
  4643. &RelativeName
  4644. );
  4645. if ( !TranslationStatus ) {
  4646. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  4647. return FALSE;
  4648. }
  4649. FreeBuffer = FileName.Buffer;
  4650. if ( RelativeName.RelativeName.Length ) {
  4651. FileName = RelativeName.RelativeName;
  4652. }
  4653. else {
  4654. RelativeName.ContainingDirectory = NULL;
  4655. }
  4656. InitializeObjectAttributes(
  4657. &Obja,
  4658. &FileName,
  4659. OBJ_CASE_INSENSITIVE,
  4660. RelativeName.ContainingDirectory,
  4661. NULL
  4662. );
  4663. //
  4664. // Notice that FILE_OPEN_REPARSE_POINT inhibits the reparse behavior. Thus, the
  4665. // security will always be set, as before, in the file denoted by the name.
  4666. //
  4667. Status = NtOpenFile(
  4668. &FileHandle,
  4669. DesiredAccess,
  4670. &Obja,
  4671. &IoStatusBlock,
  4672. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  4673. FILE_OPEN_REPARSE_POINT
  4674. );
  4675. //
  4676. // Back-level file systems may not support the FILE_OPEN_REPARSE_POINT
  4677. // flag. We treat this case explicitly.
  4678. //
  4679. if ( Status == STATUS_INVALID_PARAMETER ) {
  4680. //
  4681. // Open without inhibiting the reparse behavior.
  4682. //
  4683. Status = NtOpenFile(
  4684. &FileHandle,
  4685. DesiredAccess,
  4686. &Obja,
  4687. &IoStatusBlock,
  4688. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  4689. 0
  4690. );
  4691. }
  4692. RtlReleaseRelativeName(&RelativeName);
  4693. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  4694. if ( !NT_SUCCESS( Status ) ) {
  4695. BaseSetLastNTError( Status );
  4696. return FALSE;
  4697. }
  4698. Status = NtSetSecurityObject(
  4699. FileHandle,
  4700. SecurityInformation,
  4701. pSecurityDescriptor
  4702. );
  4703. NtClose(FileHandle);
  4704. if (!NT_SUCCESS(Status)) {
  4705. BaseSetLastNTError(Status);
  4706. return FALSE;
  4707. }
  4708. return TRUE;
  4709. }
  4710. BOOL
  4711. APIENTRY
  4712. SetFileSecurityA(
  4713. LPCSTR lpFileName,
  4714. SECURITY_INFORMATION SecurityInformation,
  4715. PSECURITY_DESCRIPTOR pSecurityDescriptor
  4716. )
  4717. /*++
  4718. Routine Description:
  4719. ANSI thunk to SetFileSecurityW
  4720. --*/
  4721. {
  4722. PUNICODE_STRING Unicode;
  4723. ANSI_STRING AnsiString;
  4724. NTSTATUS Status;
  4725. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  4726. RtlInitAnsiString(&AnsiString,lpFileName);
  4727. if (AreFileApisANSI()) {
  4728. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  4729. } else {
  4730. Status = RtlOemStringToUnicodeString(Unicode,&AnsiString,FALSE);
  4731. }
  4732. if ( !NT_SUCCESS(Status) ) {
  4733. BaseSetLastNTError(Status);
  4734. return FALSE;
  4735. }
  4736. return ( SetFileSecurityW( (LPCWSTR)Unicode->Buffer,
  4737. SecurityInformation,
  4738. pSecurityDescriptor
  4739. )
  4740. );
  4741. }
  4742. BOOL
  4743. APIENTRY
  4744. GetFileSecurityW(
  4745. LPCWSTR lpFileName,
  4746. SECURITY_INFORMATION RequestedInformation,
  4747. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  4748. DWORD nLength,
  4749. LPDWORD lpnLengthNeeded
  4750. )
  4751. /*++
  4752. Routine Description:
  4753. This API returns top the caller a copy of the security descriptor
  4754. protecting a file or directory. Based on the caller's access
  4755. rights and privileges, this procedure will return a security
  4756. descriptor containing the requested security descriptor fields.
  4757. To read the handle's security descriptor the caller must be
  4758. granted READ_CONTROL access or be the owner of the object. In
  4759. addition, the caller must have SeSecurityPrivilege privilege to
  4760. read the system ACL.
  4761. Arguments:
  4762. lpFileName - Represents the name of the file or directory whose
  4763. security is being retrieved.
  4764. RequestedInformation - A pointer to the security information being
  4765. requested.
  4766. pSecurityDescriptor - A pointer to the buffer to receive a copy of
  4767. the secrity descriptor protecting the object that the caller
  4768. has the rigth to view. The security descriptor is returned in
  4769. self-relative format.
  4770. nLength - The size, in bytes, of the security descriptor buffer.
  4771. lpnLengthNeeded - A pointer to the variable to receive the number
  4772. of bytes needed to store the complete secruity descriptor. If
  4773. returned number of bytes is less than or equal to nLength then
  4774. the entire security descriptor is returned in the output
  4775. buffer, otherwise none of the descriptor is returned.
  4776. Return Value:
  4777. TRUE is returned for success, FALSE if access is denied or if the
  4778. buffer is too small to hold the security descriptor.
  4779. --*/
  4780. {
  4781. NTSTATUS Status;
  4782. HANDLE FileHandle;
  4783. ACCESS_MASK DesiredAccess;
  4784. OBJECT_ATTRIBUTES Obja;
  4785. UNICODE_STRING FileName;
  4786. BOOLEAN TranslationStatus;
  4787. RTL_RELATIVE_NAME_U RelativeName;
  4788. IO_STATUS_BLOCK IoStatusBlock;
  4789. PVOID FreeBuffer;
  4790. QuerySecurityAccessMask(
  4791. RequestedInformation,
  4792. &DesiredAccess
  4793. );
  4794. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  4795. lpFileName,
  4796. &FileName,
  4797. NULL,
  4798. &RelativeName
  4799. );
  4800. if ( !TranslationStatus ) {
  4801. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  4802. return FALSE;
  4803. }
  4804. FreeBuffer = FileName.Buffer;
  4805. if ( RelativeName.RelativeName.Length ) {
  4806. FileName = RelativeName.RelativeName;
  4807. }
  4808. else {
  4809. RelativeName.ContainingDirectory = NULL;
  4810. }
  4811. InitializeObjectAttributes(
  4812. &Obja,
  4813. &FileName,
  4814. OBJ_CASE_INSENSITIVE,
  4815. RelativeName.ContainingDirectory,
  4816. NULL
  4817. );
  4818. //
  4819. // Notice that FILE_OPEN_REPARSE_POINT inhibits the reparse behavior. Thus, the
  4820. // security will always be set, as before, in the file denoted by the name.
  4821. //
  4822. Status = NtOpenFile(
  4823. &FileHandle,
  4824. DesiredAccess,
  4825. &Obja,
  4826. &IoStatusBlock,
  4827. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  4828. FILE_OPEN_REPARSE_POINT
  4829. );
  4830. //
  4831. // Back-level file systems may not support the FILE_OPEN_REPARSE_POINT
  4832. // flag. We treat this case explicitly.
  4833. //
  4834. if ( Status == STATUS_INVALID_PARAMETER ) {
  4835. //
  4836. // Open without inhibiting the reparse behavior.
  4837. //
  4838. Status = NtOpenFile(
  4839. &FileHandle,
  4840. DesiredAccess,
  4841. &Obja,
  4842. &IoStatusBlock,
  4843. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  4844. 0
  4845. );
  4846. }
  4847. RtlReleaseRelativeName(&RelativeName);
  4848. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  4849. if (NT_SUCCESS(Status)) {
  4850. Status = NtQuerySecurityObject(
  4851. FileHandle,
  4852. RequestedInformation,
  4853. pSecurityDescriptor,
  4854. nLength,
  4855. lpnLengthNeeded
  4856. );
  4857. NtClose(FileHandle);
  4858. }
  4859. if (!NT_SUCCESS(Status)) {
  4860. BaseSetLastNTError(Status);
  4861. return FALSE;
  4862. }
  4863. return TRUE;
  4864. }
  4865. BOOL
  4866. APIENTRY
  4867. GetFileSecurityA(
  4868. LPCSTR lpFileName,
  4869. SECURITY_INFORMATION RequestedInformation,
  4870. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  4871. DWORD nLength,
  4872. LPDWORD lpnLengthNeeded
  4873. )
  4874. /*++
  4875. Routine Description:
  4876. ANSI thunk to GetFileSecurityW
  4877. --*/
  4878. {
  4879. PUNICODE_STRING Unicode;
  4880. ANSI_STRING AnsiString;
  4881. NTSTATUS Status;
  4882. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  4883. RtlInitAnsiString(&AnsiString,lpFileName);
  4884. if (AreFileApisANSI()) {
  4885. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  4886. } else {
  4887. Status = RtlOemStringToUnicodeString(Unicode,&AnsiString,FALSE);
  4888. }
  4889. if ( !NT_SUCCESS(Status) ) {
  4890. BaseSetLastNTError(Status);
  4891. return FALSE;
  4892. }
  4893. return ( GetFileSecurityW( (LPCWSTR)Unicode->Buffer,
  4894. RequestedInformation,
  4895. pSecurityDescriptor,
  4896. nLength,
  4897. lpnLengthNeeded
  4898. )
  4899. );
  4900. }
  4901. BOOL
  4902. APIENTRY
  4903. SetKernelObjectSecurity (
  4904. HANDLE Handle,
  4905. SECURITY_INFORMATION SecurityInformation,
  4906. PSECURITY_DESCRIPTOR SecurityDescriptor
  4907. )
  4908. /*++
  4909. Routine Description:
  4910. This API can be used to set the security of a kernel object
  4911. (process, file, event, etc.). This call is only successful if the
  4912. following conditions are met:
  4913. o If the object's owner or group is to be set, the caller must
  4914. have WRITE_OWNER permission or have SeTakeOwnershipPrivilege.
  4915. o If the object's DACL is to be set, the caller must have
  4916. WRITE_DAC permission or be the object's owner.
  4917. o If the object's SACL is to be set, the caller must have
  4918. SeSecurityPrivilege.
  4919. Arguments:
  4920. Handle - Represents a handle of a kernel object.
  4921. SecurityInformation - A pointer to information describing the
  4922. contents of the Security Descriptor.
  4923. pSecurityDescriptor - A pointer to a well formed Security
  4924. Descriptor.
  4925. Return Value:
  4926. Returns TRUE for success, FALSE for failure. Extended error status
  4927. is available using GetLastError.
  4928. --*/
  4929. {
  4930. NTSTATUS Status;
  4931. Status = NtSetSecurityObject(
  4932. Handle,
  4933. SecurityInformation,
  4934. SecurityDescriptor
  4935. );
  4936. if ( !NT_SUCCESS(Status) ) {
  4937. BaseSetLastNTError(Status);
  4938. return FALSE;
  4939. }
  4940. return TRUE;
  4941. }
  4942. BOOL
  4943. APIENTRY
  4944. GetKernelObjectSecurity (
  4945. HANDLE Handle,
  4946. SECURITY_INFORMATION RequestedInformation,
  4947. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  4948. DWORD nLength,
  4949. LPDWORD lpnLengthNeeded
  4950. )
  4951. /*++
  4952. Routine Description:
  4953. This API returns top the caller a copy of the security descriptor
  4954. protecting a kernel object. Based on the caller's access rights
  4955. and privileges, this procedure will return a security descriptor
  4956. containing the requested security descriptor fields. To read the
  4957. handle's security descriptor the caller must be granted
  4958. READ_CONTROL access or be the owner of the object. In addition,
  4959. the caller must have SeSecurityPrivilege privilege to read the
  4960. system ACL.
  4961. Arguments:
  4962. Handle - Represents a handle of a kernel object.
  4963. RequestedInformation - A pointer to the security information being
  4964. requested.
  4965. pSecurityDescriptor - A pointer to the buffer to receive a copy of
  4966. the secrity descriptor protecting the object that the caller
  4967. has the rigth to view. The security descriptor is returned in
  4968. self-relative format.
  4969. nLength - The size, in bytes, of the security descriptor buffer.
  4970. lpnLengthNeeded - A pointer to the variable to receive the number
  4971. of bytes needed to store the complete secruity descriptor. If
  4972. returned number of bytes is less than or equal to nLength then
  4973. the entire security descriptor is returned in the output
  4974. buffer, otherwise none of the descriptor is returned.
  4975. Return Value:
  4976. return-value - Description of conditions needed to return value. - or -
  4977. None.
  4978. --*/
  4979. {
  4980. NTSTATUS Status;
  4981. Status = NtQuerySecurityObject(
  4982. Handle,
  4983. RequestedInformation,
  4984. pSecurityDescriptor,
  4985. nLength,
  4986. lpnLengthNeeded
  4987. );
  4988. if ( !NT_SUCCESS(Status) ) {
  4989. BaseSetLastNTError(Status);
  4990. return FALSE;
  4991. }
  4992. return TRUE;
  4993. }
  4994. BOOL
  4995. APIENTRY
  4996. ImpersonateNamedPipeClient(
  4997. IN HANDLE hNamedPipe
  4998. )
  4999. /*++
  5000. Routine Description:
  5001. Impersonate a named pipe client application.
  5002. Arguments:
  5003. hNamedPipe - Handle to a named pipe.
  5004. Return Value:
  5005. Returns TRUE for success, FALSE for failure. Extended error status
  5006. is available using GetLastError.
  5007. --*/
  5008. {
  5009. NTSTATUS Status;
  5010. IO_STATUS_BLOCK IoStatusBlock;
  5011. Status = NtFsControlFile(
  5012. hNamedPipe,
  5013. NULL,
  5014. NULL,
  5015. NULL,
  5016. &IoStatusBlock,
  5017. FSCTL_PIPE_IMPERSONATE,
  5018. NULL,
  5019. 0,
  5020. NULL,
  5021. 0
  5022. );
  5023. if ( !NT_SUCCESS(Status) ) {
  5024. BaseSetLastNTError(Status);
  5025. return FALSE;
  5026. }
  5027. return TRUE;
  5028. }
  5029. BOOL
  5030. APIENTRY
  5031. ImpersonateSelf(
  5032. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  5033. )
  5034. /*++
  5035. Routine Description:
  5036. This routine may be used to obtain an Impersonation token representing
  5037. your own process's context. This may be useful for enabling a privilege
  5038. for a single thread rather than for the entire process; or changing
  5039. the default DACL for a single thread.
  5040. The token is assigned to the callers thread.
  5041. Arguments:
  5042. ImpersonationLevel - The level to make the impersonation token.
  5043. Return Value:
  5044. Returns TRUE for success, FALSE for failure. Extended error status
  5045. is available using GetLastError.
  5046. --*/
  5047. {
  5048. NTSTATUS Status;
  5049. Status = RtlImpersonateSelf( ImpersonationLevel );
  5050. if ( !NT_SUCCESS(Status) ) {
  5051. BaseSetLastNTError(Status);
  5052. return FALSE;
  5053. }
  5054. return TRUE;
  5055. }
  5056. BOOL
  5057. APIENTRY
  5058. RevertToSelf (
  5059. VOID
  5060. )
  5061. /*++
  5062. Routine Description:
  5063. Terminate impersonation of a named pipe client application.
  5064. Arguments:
  5065. None.
  5066. Return Value:
  5067. Returns TRUE for success, FALSE for failure. Extended error status
  5068. is available using GetLastError.
  5069. --*/
  5070. {
  5071. HANDLE NewToken;
  5072. NTSTATUS Status;
  5073. NewToken = NULL;
  5074. Status = NtSetInformationThread(
  5075. NtCurrentThread(),
  5076. ThreadImpersonationToken,
  5077. (PVOID)&NewToken,
  5078. (ULONG)sizeof(HANDLE)
  5079. );
  5080. if ( !NT_SUCCESS(Status) ) {
  5081. BaseSetLastNTError(Status);
  5082. return FALSE;
  5083. }
  5084. return TRUE;
  5085. }
  5086. BOOL
  5087. APIENTRY
  5088. SetThreadToken (
  5089. PHANDLE Thread,
  5090. HANDLE Token
  5091. )
  5092. /*++
  5093. Routine Description:
  5094. Assigns the specified impersonation token to the specified
  5095. thread.
  5096. Arguments:
  5097. Thread - Specifies the thread whose token is to be assigned.
  5098. If NULL is specified, then the caller's thread is assumed.
  5099. Token - The token to assign. Must be open for TOKEN_IMPERSONATE
  5100. access. If null, then causes the specified thread to stop
  5101. impersonating.
  5102. Return Value:
  5103. Returns TRUE for success, FALSE for failure. Extended error status
  5104. is available using GetLastError.
  5105. --*/
  5106. {
  5107. NTSTATUS Status;
  5108. HANDLE TargetThread;
  5109. if (ARGUMENT_PRESENT(Thread)) {
  5110. TargetThread = (*Thread);
  5111. } else {
  5112. TargetThread = NtCurrentThread();
  5113. }
  5114. Status = NtSetInformationThread(
  5115. TargetThread,
  5116. ThreadImpersonationToken,
  5117. (PVOID)&Token,
  5118. (ULONG)sizeof(HANDLE)
  5119. );
  5120. if ( !NT_SUCCESS(Status) ) {
  5121. BaseSetLastNTError(Status);
  5122. return FALSE;
  5123. }
  5124. return TRUE;
  5125. }
  5126. BOOL
  5127. LookupAccountNameInternal(
  5128. LPCWSTR lpSystemName,
  5129. LPCWSTR lpAccountName,
  5130. PSID Sid,
  5131. LPDWORD cbSid,
  5132. LPWSTR ReferencedDomainName,
  5133. LPDWORD cchReferencedDomainName,
  5134. PSID_NAME_USE peUse,
  5135. BOOL fUnicode
  5136. )
  5137. /*++
  5138. Routine Description:
  5139. Translates a passed name into an account SID. It will also return
  5140. the name and SID of the first domain in which this name was found.
  5141. Arguments:
  5142. lpSystemName - Supplies the name of the system at which the lookup
  5143. is to be performed. If the null string is provided, the local
  5144. system is assumed.
  5145. lpAccountName - Supplies the account name.
  5146. Sid - Returns the SID corresponding to the passed account name.
  5147. cbSid - Supplies the size of the buffer passed in for Sid. If
  5148. the buffer size is not big enough, this parameter will
  5149. return the size necessary to hold the output Sid.
  5150. ReferencedDomainName - Returns the name of the domain in which the
  5151. name was found.
  5152. cchReferencedDomainName - Supplies the size (in Wide characters) of the
  5153. ReferencedDomainName buffer. If the buffer size is not large
  5154. enough, this parameter will return the size necessary to hold
  5155. the null-terminated output domain name. If the buffer size is
  5156. large enough, tis parameter will return the size (in Ansi characters,
  5157. excluding the terminating null) of the Referenced Domain name.
  5158. peUse - Returns an enumerated type inidicating the type of the
  5159. account.
  5160. fUnicode - indicates whether the caller wants a count of unicode or
  5161. ansi characters.
  5162. Return Value:
  5163. BOOL - TRUE is returned if successful, else FALSE.
  5164. --*/
  5165. {
  5166. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  5167. OBJECT_ATTRIBUTES ObjectAttributes;
  5168. LSA_HANDLE PolicyHandle;
  5169. NTSTATUS Status;
  5170. NTSTATUS TmpStatus;
  5171. UNICODE_STRING Name;
  5172. PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
  5173. PLSA_TRANSLATED_SID2 TranslatedSid = NULL;
  5174. PSID ReturnedDomainSid;
  5175. UCHAR nSubAuthorities;
  5176. UNICODE_STRING TmpString;
  5177. DWORD ReturnedDomainNameSize;
  5178. DWORD SidLengthRequired;
  5179. BOOL Rc;
  5180. UNICODE_STRING SystemName;
  5181. PUNICODE_STRING pSystemName = NULL;
  5182. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  5183. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  5184. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  5185. SecurityQualityOfService.EffectiveOnly = FALSE;
  5186. //
  5187. // Set up the object attributes prior to opening the LSA.
  5188. //
  5189. InitializeObjectAttributes(
  5190. &ObjectAttributes,
  5191. NULL,
  5192. 0L,
  5193. NULL,
  5194. NULL
  5195. );
  5196. //
  5197. // The InitializeObjectAttributes macro presently stores NULL for
  5198. // the SecurityQualityOfService field, so we must manually copy that
  5199. // structure for now.
  5200. //
  5201. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  5202. if ( ARGUMENT_PRESENT( lpSystemName )) {
  5203. RtlInitUnicodeString( &SystemName, lpSystemName );
  5204. pSystemName = &SystemName;
  5205. }
  5206. //
  5207. // Open the LSA Policy Database for the target system. This is the
  5208. // starting point for the Name Lookup operation.
  5209. //
  5210. Status = LsaOpenPolicy(
  5211. pSystemName,
  5212. &ObjectAttributes,
  5213. POLICY_LOOKUP_NAMES,
  5214. &PolicyHandle
  5215. );
  5216. if ( !NT_SUCCESS( Status )) {
  5217. BaseSetLastNTError( Status );
  5218. return( FALSE );
  5219. }
  5220. RtlInitUnicodeString( &Name, lpAccountName );
  5221. //
  5222. // Attempt to translate the Name to a Sid.
  5223. //
  5224. Status = LsaLookupNames2(
  5225. PolicyHandle,
  5226. 0, // Flags
  5227. 1,
  5228. &Name,
  5229. &ReferencedDomains,
  5230. &TranslatedSid
  5231. );
  5232. #if DBG
  5233. //
  5234. // This code is useful for tracking down components that call Lookup code
  5235. // before the system is initialized
  5236. //
  5237. // ASSERT( Status != STATUS_INVALID_SERVER_STATE );
  5238. if ( Status == STATUS_INVALID_SERVER_STATE ) {
  5239. DbgPrint( "Process: %lu, Thread: %lu\n", GetCurrentProcessId(), GetCurrentThreadId() );
  5240. }
  5241. #endif
  5242. //
  5243. // Close the Policy Handle, which is not needed after here.
  5244. //
  5245. TmpStatus = LsaClose( PolicyHandle );
  5246. // ASSERT( NT_SUCCESS( TmpStatus ));
  5247. //
  5248. // If an error was returned, check specifically for STATUS_NONE_MAPPED.
  5249. // In this case, we may need to dispose of the returned Referenced Domain
  5250. // List and Translated Sid structures. For all other errors,
  5251. // LsaLookupNames() frees these structures prior to exit.
  5252. //
  5253. if ( !NT_SUCCESS( Status )) {
  5254. if (Status == STATUS_NONE_MAPPED) {
  5255. if (ReferencedDomains != NULL) {
  5256. TmpStatus = LsaFreeMemory( ReferencedDomains );
  5257. ASSERT( NT_SUCCESS( TmpStatus ));
  5258. }
  5259. if (TranslatedSid != NULL) {
  5260. TmpStatus = LsaFreeMemory( TranslatedSid );
  5261. ASSERT( NT_SUCCESS( TmpStatus ));
  5262. }
  5263. }
  5264. BaseSetLastNTError( Status );
  5265. return( FALSE );
  5266. }
  5267. //
  5268. // The Name was successfully translated. There should be exactly
  5269. // one Referenced Domain and its DomainIndex should be zero.
  5270. //
  5271. ASSERT ( TranslatedSid->DomainIndex == 0 );
  5272. ASSERT ( ReferencedDomains != NULL);
  5273. ASSERT ( ReferencedDomains->Domains != NULL );
  5274. //
  5275. // Calculate the lengths of the returned Sid and Domain Name (in Wide
  5276. // Characters, excluding null).
  5277. //
  5278. if ( !fUnicode ) {
  5279. RtlUnicodeToMultiByteSize(&ReturnedDomainNameSize,
  5280. ReferencedDomains->Domains->Name.Buffer,
  5281. ReferencedDomains->Domains->Name.Length);
  5282. } else {
  5283. ReturnedDomainNameSize = (ReferencedDomains->Domains->Name.Length / sizeof(WCHAR));
  5284. }
  5285. SidLengthRequired = RtlLengthSid( TranslatedSid->Sid );
  5286. //
  5287. // Check if buffer sizes are too small. For the returned domain,
  5288. // the size in Wide characters provided must allow for the null
  5289. // terminator that will be appended to the returned name.
  5290. //
  5291. if ( (SidLengthRequired > *cbSid) ||
  5292. (ReturnedDomainNameSize + 1 > *cchReferencedDomainName)
  5293. ) {
  5294. //
  5295. // One or both buffers are too small. Return sizes required for
  5296. // both buffers.
  5297. //
  5298. *cbSid = SidLengthRequired;
  5299. *cchReferencedDomainName = ReturnedDomainNameSize + 1;
  5300. BaseSetLastNTError( STATUS_BUFFER_TOO_SMALL );
  5301. Rc = FALSE;
  5302. } else {
  5303. //
  5304. // The provided buffers are large enough.
  5305. //
  5306. CopySid( *cbSid, Sid, TranslatedSid->Sid );
  5307. //
  5308. // Copy the Domain Name into the return buffer and NULL terminate it.
  5309. //
  5310. TmpString.Buffer = ReferencedDomainName;
  5311. TmpString.Length = 0;
  5312. //
  5313. // Watch for overflow of 16-bit name length
  5314. //
  5315. if (*cchReferencedDomainName < (DWORD) MAXSHORT) {
  5316. TmpString.MaximumLength = (USHORT)((*cchReferencedDomainName) * sizeof(WCHAR));
  5317. } else {
  5318. TmpString.MaximumLength = (USHORT) MAXUSHORT -1;
  5319. }
  5320. RtlCopyUnicodeString( &TmpString, &ReferencedDomains->Domains->Name );
  5321. TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;
  5322. //
  5323. // Copy the Sid Use field.
  5324. //
  5325. *peUse = TranslatedSid->Use;
  5326. //
  5327. // Return the size (in Wide Characters, excluding the terminating
  5328. // null) of the returned Referenced Domain Name.
  5329. //
  5330. *cchReferencedDomainName = ReturnedDomainNameSize;
  5331. Rc = TRUE;
  5332. }
  5333. //
  5334. // If necessary, free the structures returned by the LsaLookupNames()
  5335. // function.
  5336. //
  5337. if (ReferencedDomains != NULL) {
  5338. Status = LsaFreeMemory( ReferencedDomains );
  5339. ASSERT( NT_SUCCESS( Status ));
  5340. }
  5341. if (TranslatedSid != NULL) {
  5342. Status = LsaFreeMemory( TranslatedSid );
  5343. ASSERT( NT_SUCCESS( Status ));
  5344. }
  5345. return( Rc );
  5346. }
  5347. BOOL
  5348. APIENTRY
  5349. LookupAccountNameA(
  5350. LPCSTR lpSystemName,
  5351. LPCSTR lpAccountName,
  5352. PSID Sid,
  5353. LPDWORD cbSid,
  5354. LPSTR ReferencedDomainName,
  5355. LPDWORD cchReferencedDomainName,
  5356. PSID_NAME_USE peUse
  5357. )
  5358. /*++
  5359. Routine Description:
  5360. ANSI Thunk to LookupAccountNameW
  5361. Arguments:
  5362. lpSystemName - Supplies the name of the system at which the lookup
  5363. is to be performed. If the null string is provided, the local
  5364. system is assumed.
  5365. lpAccountName - Supplies the account name.
  5366. Sid - Returns the SID corresponding to the passed account name.
  5367. cbSid - Supplies the size of the buffer passed in for Sid. If
  5368. the buffer size is not big enough, this parameter will
  5369. return the size necessary to hold the output Sid.
  5370. ReferencedDomainName - Returns the name of the domain in which the
  5371. name was found.
  5372. cchReferencedDomainName - Supplies the size (in Ansi characters) of the
  5373. ReferencedDomainName buffer. If the buffer size is not large
  5374. enough, this parameter will return the size necessary to hold
  5375. the null-terminated output domain name. If the buffer size is
  5376. large enough, tis parameter will return the size (in Ansi characters,
  5377. excluding the terminating null) of the Referenced Domain name.
  5378. peUse - Returns an enumerated type indicating the type of the
  5379. account.
  5380. Return Value:
  5381. BOOL - TRUE is returned if successful, else FALSE.
  5382. --*/
  5383. {
  5384. UNICODE_STRING Unicode;
  5385. UNICODE_STRING TmpUnicode;
  5386. ANSI_STRING AnsiString;
  5387. PWSTR WReferencedDomainName = NULL;
  5388. UNICODE_STRING SystemName;
  5389. PWSTR pSystemName = NULL;
  5390. NTSTATUS Status;
  5391. BOOL rc = TRUE;
  5392. DWORD cchInitReferencedDomainName;
  5393. Unicode.Buffer = NULL;
  5394. SystemName.Buffer = NULL;
  5395. //
  5396. // Save the original buffer size
  5397. //
  5398. cchInitReferencedDomainName = *cchReferencedDomainName;
  5399. //
  5400. // Convert the passed lpAccountName to a WCHAR string to be
  5401. // passed to the ..W routine. Note that we cannot use the
  5402. // StaticUnicodeString in the Thread Environment Block because
  5403. // this is used by LdrpWalkImportDescriptor, called from the
  5404. // client RPC stub code of the LsaOpenPolicy() call in
  5405. // LookupAccountNameW.
  5406. //
  5407. RtlInitAnsiString( &AnsiString, lpAccountName );
  5408. Status = RtlAnsiStringToUnicodeString( &Unicode, &AnsiString, TRUE );
  5409. if (!NT_SUCCESS(Status)) {
  5410. rc = FALSE;
  5411. }
  5412. //
  5413. // Allocate a temporary buffer for ReferencedDomainName that
  5414. // is twice as large as what was passed to adjust for the
  5415. // intermediate conversion to a WCHAR string.
  5416. //
  5417. if (rc) {
  5418. WReferencedDomainName = LocalAlloc(
  5419. LMEM_FIXED,
  5420. sizeof(WCHAR) * (*cchReferencedDomainName)
  5421. );
  5422. if (WReferencedDomainName == NULL) {
  5423. Status = STATUS_NO_MEMORY;
  5424. rc = FALSE;
  5425. }
  5426. }
  5427. //
  5428. // If the target system name is non NULL, convert it to Unicode
  5429. //
  5430. if (rc) {
  5431. if ( ARGUMENT_PRESENT( lpSystemName ) ) {
  5432. RtlInitAnsiString( &AnsiString, lpSystemName );
  5433. Status = RtlAnsiStringToUnicodeString( &SystemName, &AnsiString, TRUE );
  5434. if (!NT_SUCCESS(Status)) {
  5435. rc = FALSE;
  5436. }
  5437. pSystemName = SystemName.Buffer;
  5438. }
  5439. }
  5440. //
  5441. // Lookup the Account Sid and obtain its Unicode Account Name.
  5442. //
  5443. if (rc) {
  5444. rc = LookupAccountNameInternal(
  5445. (LPCWSTR)pSystemName,
  5446. (LPCWSTR)Unicode.Buffer,
  5447. Sid,
  5448. cbSid,
  5449. WReferencedDomainName,
  5450. cchReferencedDomainName,
  5451. peUse,
  5452. FALSE // not unicode
  5453. );
  5454. }
  5455. if ( SystemName.Buffer != NULL ) {
  5456. RtlFreeUnicodeString( &SystemName );
  5457. }
  5458. //
  5459. // Convert the returned null-terminated WCHAR string
  5460. // back to a null-terminated CHAR string.
  5461. //
  5462. if (rc) {
  5463. RtlInitUnicodeString( &TmpUnicode, WReferencedDomainName );
  5464. AnsiString.Buffer = ReferencedDomainName;
  5465. //
  5466. // Watch for 16-bit overflow of MaximumLength
  5467. //
  5468. if (cchInitReferencedDomainName <= (DWORD) MAXUSHORT) {
  5469. AnsiString.MaximumLength = (USHORT) cchInitReferencedDomainName;
  5470. } else {
  5471. AnsiString.MaximumLength = (USHORT) MAXUSHORT;
  5472. }
  5473. Status = RtlUnicodeStringToAnsiString( &AnsiString, &TmpUnicode, FALSE );
  5474. if ( NT_SUCCESS( Status )) {
  5475. ReferencedDomainName[AnsiString.Length] = 0;
  5476. } else {
  5477. rc = FALSE;
  5478. }
  5479. }
  5480. if ( WReferencedDomainName != NULL) {
  5481. LocalFree( WReferencedDomainName );
  5482. }
  5483. if (Unicode.Buffer != NULL) {
  5484. RtlFreeUnicodeString(&Unicode);
  5485. }
  5486. if (!NT_SUCCESS(Status)) {
  5487. BaseSetLastNTError( Status );
  5488. }
  5489. return( rc );
  5490. }
  5491. BOOL
  5492. APIENTRY
  5493. LookupAccountNameW(
  5494. LPCWSTR lpSystemName,
  5495. LPCWSTR lpAccountName,
  5496. PSID Sid,
  5497. LPDWORD cbSid,
  5498. LPWSTR ReferencedDomainName,
  5499. LPDWORD cchReferencedDomainName,
  5500. PSID_NAME_USE peUse
  5501. )
  5502. /*++
  5503. Routine Description:
  5504. Translates a passed name into an account SID. It will also return
  5505. the name and SID of the first domain in which this name was found.
  5506. Arguments:
  5507. lpSystemName - Supplies the name of the system at which the lookup
  5508. is to be performed. If the null string is provided, the local
  5509. system is assumed.
  5510. lpAccountName - Supplies the account name.
  5511. Sid - Returns the SID corresponding to the passed account name.
  5512. cbSid - Supplies the size of the buffer passed in for Sid. If
  5513. the buffer size is not big enough, this parameter will
  5514. return the size necessary to hold the output Sid.
  5515. ReferencedDomainName - Returns the name of the domain in which the
  5516. name was found.
  5517. cchReferencedDomainName - Supplies the size (in Wide characters) of the
  5518. ReferencedDomainName buffer. If the buffer size is not large
  5519. enough, this parameter will return the size necessary to hold
  5520. the null-terminated output domain name. If the buffer size is
  5521. large enough, tis parameter will return the size (in Ansi characters,
  5522. excluding the terminating null) of the Referenced Domain name.
  5523. peUse - Returns an enumerated type inidicating the type of the
  5524. account.
  5525. Return Value:
  5526. BOOL - TRUE is returned if successful, else FALSE.
  5527. --*/
  5528. {
  5529. return(LookupAccountNameInternal( lpSystemName,
  5530. lpAccountName,
  5531. Sid,
  5532. cbSid,
  5533. ReferencedDomainName,
  5534. cchReferencedDomainName,
  5535. peUse,
  5536. TRUE // Unicode
  5537. ) );
  5538. }
  5539. BOOL
  5540. APIENTRY
  5541. LookupAccountSidInternal(
  5542. LPCWSTR lpSystemName,
  5543. PSID lpSid,
  5544. LPWSTR lpName,
  5545. LPDWORD cchName,
  5546. LPWSTR lpReferencedDomainName,
  5547. LPDWORD cchReferencedDomainName,
  5548. PSID_NAME_USE peUse,
  5549. BOOL fUnicode
  5550. )
  5551. /*++
  5552. Routine Description:
  5553. Translates a passed SID into an account name. It will also return
  5554. the name and SID of the first domain in which this SID was found.
  5555. Arguments:
  5556. lpSystemName - Supplies the name of the system at which the lookup
  5557. is to be performed. If the null string is provided, the local
  5558. system is assumed.
  5559. lpSid - Supplies the account Sid.
  5560. lpName - Returns the name corresponding to the passed account SID.
  5561. cchName - Supplies the size (in Wide characters) of the buffer passed in for
  5562. lpName. This size must allow one character for the null terminator
  5563. that will be appended to the returned name. If the buffer size is not
  5564. large enough, this parameter will return the size necessary to hold
  5565. the null-terminated output name. If the buffer size is large enough,
  5566. this parameter will return the size (in Ansi characters, excluding
  5567. the null terminator) of the name returned.
  5568. lpReferencedDomainName - Returns the name of the domain in which the
  5569. name was found.
  5570. cchReferencedDomainName - Supplies the size (in Wide characters) of the
  5571. ReferencedDomainName buffer. This size must allow one charcter for the
  5572. null terminator that will be appended to the returned name. If the
  5573. buffer size is not large enough, this parameter will return the size
  5574. necessary to hold the output null-terminated domain name. If the
  5575. buffer size is large enough, the size of the returned name, excluding
  5576. the terminating null will be returned.
  5577. peUse - Returns an enumerated type inidicating the type of the
  5578. account.
  5579. fUnicode - indicates whether the caller wants a count of unicode or
  5580. ansi characters.
  5581. Return Value:
  5582. BOOL - TRUE if successful, else FALSE.
  5583. --*/
  5584. {
  5585. PLSA_TRANSLATED_NAME Names;
  5586. OBJECT_ATTRIBUTES ObjectAttributes;
  5587. LSA_HANDLE PolicyHandle;
  5588. PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains;
  5589. DWORD ReturnedDomainNameSize;
  5590. DWORD ReturnedNameSize;
  5591. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  5592. NTSTATUS Status;
  5593. UNICODE_STRING TmpString;
  5594. NTSTATUS TmpStatus;
  5595. UNICODE_STRING SystemName;
  5596. PUNICODE_STRING pSystemName = NULL;
  5597. BOOLEAN Rc = FALSE;
  5598. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  5599. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  5600. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  5601. SecurityQualityOfService.EffectiveOnly = FALSE;
  5602. //
  5603. // Set up the object attributes prior to opening the LSA.
  5604. //
  5605. InitializeObjectAttributes(
  5606. &ObjectAttributes,
  5607. NULL,
  5608. 0L,
  5609. NULL,
  5610. NULL
  5611. );
  5612. //
  5613. // The InitializeObjectAttributes macro presently stores NULL for
  5614. // the SecurityQualityOfService field, so we must manually copy that
  5615. // structure for now.
  5616. //
  5617. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  5618. if ( ARGUMENT_PRESENT( lpSystemName )) {
  5619. RtlInitUnicodeString( &SystemName, lpSystemName );
  5620. pSystemName = &SystemName;
  5621. }
  5622. Status = LsaOpenPolicy(
  5623. pSystemName,
  5624. &ObjectAttributes,
  5625. POLICY_LOOKUP_NAMES,
  5626. &PolicyHandle
  5627. );
  5628. if ( !NT_SUCCESS( Status )) {
  5629. BaseSetLastNTError( Status );
  5630. return( FALSE );
  5631. }
  5632. Status = LsaLookupSids(
  5633. PolicyHandle,
  5634. 1,
  5635. &lpSid,
  5636. &ReferencedDomains,
  5637. &Names
  5638. );
  5639. #if DBG
  5640. //
  5641. // This code is useful for tracking down components that call Lookup code
  5642. // before the system is initialized
  5643. //
  5644. // ASSERT( Status != STATUS_INVALID_SERVER_STATE );
  5645. if ( Status == STATUS_INVALID_SERVER_STATE ) {
  5646. DbgPrint( "Process: %lu, Thread: %lu\n", GetCurrentProcessId(), GetCurrentThreadId() );
  5647. }
  5648. #endif
  5649. TmpStatus = LsaClose( PolicyHandle );
  5650. //
  5651. // If an error was returned, check specifically for STATUS_NONE_MAPPED.
  5652. // In this case, we may need to dispose of the returned Referenced Domain
  5653. // List and Names structures. For all other errors, LsaLookupSids()
  5654. // frees these structures prior to exit.
  5655. //
  5656. if ( !NT_SUCCESS( Status )) {
  5657. if (Status == STATUS_NONE_MAPPED) {
  5658. if (ReferencedDomains != NULL) {
  5659. TmpStatus = LsaFreeMemory( ReferencedDomains );
  5660. ASSERT( NT_SUCCESS( TmpStatus ));
  5661. }
  5662. if (Names != NULL) {
  5663. TmpStatus = LsaFreeMemory( Names );
  5664. ASSERT( NT_SUCCESS( TmpStatus ));
  5665. }
  5666. }
  5667. BaseSetLastNTError( Status );
  5668. return( FALSE );
  5669. }
  5670. //
  5671. // The Sid was successfully translated. There should be exactly
  5672. // one Referenced Domain and its DomainIndex should be zero.
  5673. //
  5674. ASSERT(Names->DomainIndex == 0);
  5675. ASSERT(ReferencedDomains != NULL);
  5676. ASSERT(ReferencedDomains->Domains != NULL);
  5677. if ( ! fUnicode ) {
  5678. RtlUnicodeToMultiByteSize(&ReturnedNameSize,
  5679. Names->Name.Buffer,
  5680. Names->Name.Length);
  5681. RtlUnicodeToMultiByteSize(&ReturnedDomainNameSize,
  5682. ReferencedDomains->Domains->Name.Buffer,
  5683. ReferencedDomains->Domains->Name.Length);
  5684. } else {
  5685. ReturnedNameSize = (Names->Name.Length / sizeof(WCHAR));
  5686. ReturnedDomainNameSize = (ReferencedDomains->Domains->Name.Length / sizeof(WCHAR));
  5687. }
  5688. //
  5689. // Check if buffer sizes for the Name and Referenced Domain Name are too
  5690. // small. The sizes in Wide characters provided must allow for the null
  5691. // terminator that will be appended to the returned names.
  5692. //
  5693. if ((ReturnedNameSize + 1 > *cchName) ||
  5694. (ReturnedDomainNameSize + 1 > *cchReferencedDomainName)) {
  5695. //
  5696. // One or both buffers are too small. Return sizes required for
  5697. // both buffers, allowing one character for the null terminator.
  5698. //
  5699. *cchReferencedDomainName = ReturnedDomainNameSize + 1;
  5700. *cchName = ReturnedNameSize + 1;
  5701. BaseSetLastNTError( STATUS_BUFFER_TOO_SMALL );
  5702. Rc = FALSE;
  5703. } else {
  5704. //
  5705. // Both buffers are of sufficient size. Copy in the Name
  5706. // information and add NULL terminators.
  5707. //
  5708. TmpString.Buffer = lpName;
  5709. TmpString.Length = 0;
  5710. //
  5711. // Watch for 16-bit overflow on buffer size. Clamp size to
  5712. // 16 bits if necessary.
  5713. //
  5714. if (*cchName <= MAXSHORT) {
  5715. TmpString.MaximumLength = (USHORT)((*cchName) * sizeof(WCHAR));
  5716. } else {
  5717. TmpString.MaximumLength = (USHORT) MAXUSHORT -1;
  5718. }
  5719. if ((*cchName) > 0) {
  5720. RtlCopyUnicodeString( &TmpString, &Names->Name );
  5721. TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;
  5722. }
  5723. //
  5724. // Copy in the Referenced Domain information.
  5725. //
  5726. TmpString.Buffer = lpReferencedDomainName;
  5727. TmpString.Length = 0;
  5728. //
  5729. // Watch for 16-bit overflow on buffer size. Clamp size to
  5730. // 16 bits if necessary.
  5731. //
  5732. if (*cchReferencedDomainName <= MAXSHORT) {
  5733. TmpString.MaximumLength = (USHORT)((*cchReferencedDomainName) * sizeof(WCHAR));
  5734. } else {
  5735. TmpString.MaximumLength = (USHORT) MAXUSHORT -1;
  5736. }
  5737. RtlCopyUnicodeString( &TmpString, &ReferencedDomains->Domains->Name );
  5738. TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;
  5739. //
  5740. // Return the sizes (in Wide Characters, excluding the terminating
  5741. // null) of the name and domain name.
  5742. //
  5743. *cchReferencedDomainName = ReturnedDomainNameSize;
  5744. *cchName = ReturnedNameSize;
  5745. // Copy in the Use field.
  5746. //
  5747. *peUse = Names->Use;
  5748. Rc = TRUE;
  5749. }
  5750. //
  5751. // If necessary, free output buffers returned by LsaLookupSids
  5752. //
  5753. if (Names != NULL) {
  5754. Status = LsaFreeMemory( Names );
  5755. ASSERT( NT_SUCCESS( Status ));
  5756. }
  5757. if (ReferencedDomains != NULL) {
  5758. Status = LsaFreeMemory( ReferencedDomains );
  5759. ASSERT( NT_SUCCESS( Status ));
  5760. }
  5761. return(Rc);
  5762. }
  5763. BOOL
  5764. APIENTRY
  5765. LookupAccountSidA(
  5766. LPCSTR lpSystemName,
  5767. PSID lpSid,
  5768. LPSTR lpName,
  5769. LPDWORD cchName,
  5770. LPSTR lpReferencedDomainName,
  5771. LPDWORD cchReferencedDomainName,
  5772. PSID_NAME_USE peUse
  5773. )
  5774. /*++
  5775. Routine Description:
  5776. ANSI Thunk to LookupAccountSidW
  5777. Arguments:
  5778. lpSystemName - Supplies the name of the system at which the lookup
  5779. is to be performed. If the null string is provided, the local
  5780. system is assumed.
  5781. lpSid - Supplies the account Sid.
  5782. lpName - Returns the name corresponding to the passed account SID.
  5783. cchName - Supplies the size (in Ansi characters) of the buffer passed in for
  5784. lpName. This size must allow one character for the null terminator
  5785. that will be appended to the returned name. If the buffer size is not
  5786. large enough, this parameter will return the size necessary to hold
  5787. the null-terminated output name. If the buffer size is large enough,
  5788. this parameter will return the size (in Ansi characters, excluding
  5789. the null terminator) of the name returned.
  5790. lpReferencedDomainName - Returns the name of the domain in which the
  5791. name was found.
  5792. cchReferencedDomainName - Supplies the size (in Ansi characters) of the
  5793. ReferencedDomainName buffer. This size must allow one charcter for the
  5794. null terminator that will be appended to the returned name. If the
  5795. buffer size is not large enough, this parameter will return the size
  5796. necessary to hold the output null-terminated domain name. If the
  5797. buffer size is large enough, the size of the returned name, excluding
  5798. the terminating null will be returned.
  5799. peUse - Returns an enumerated type indicating the type of the
  5800. account.
  5801. Return Value:
  5802. BOOL - TRUE if successful, else FALSE.
  5803. --*/
  5804. {
  5805. NTSTATUS Status;
  5806. LPWSTR WName = NULL;
  5807. LPWSTR WReferencedDomainName = NULL;
  5808. BOOL BoolStatus;
  5809. ANSI_STRING AnsiString;
  5810. UNICODE_STRING UnicodeString;
  5811. UNICODE_STRING SystemName;
  5812. PWSTR pSystemName = NULL;
  5813. DWORD cchInitName, cchInitReferencedDomainName;
  5814. //
  5815. // Save the original buffer sizes specified for the returned account Name
  5816. // and Referenced Domain Name.
  5817. //
  5818. cchInitName = *cchName;
  5819. cchInitReferencedDomainName = *cchReferencedDomainName;
  5820. //
  5821. // Construct temporary buffers for the Name and Domain information
  5822. // that are twice the size of those passed in to adjust for the
  5823. // intermediate conversion to WCHAR strings.
  5824. //
  5825. if ( *cchName > 0 ) {
  5826. WName = LocalAlloc( LMEM_FIXED, (*cchName) * sizeof(WCHAR));
  5827. if ( !WName )
  5828. {
  5829. SetLastError( ERROR_OUTOFMEMORY );
  5830. return FALSE ;
  5831. }
  5832. }
  5833. if ( *cchReferencedDomainName > 0 ) {
  5834. WReferencedDomainName =
  5835. LocalAlloc( LMEM_FIXED, (*cchReferencedDomainName) * sizeof(WCHAR));
  5836. if ( !WReferencedDomainName )
  5837. {
  5838. if ( WName )
  5839. {
  5840. LocalFree( WName );
  5841. }
  5842. SetLastError( ERROR_OUTOFMEMORY );
  5843. return FALSE ;
  5844. }
  5845. }
  5846. if ( ARGUMENT_PRESENT( lpSystemName ) ) {
  5847. RtlInitAnsiString( &AnsiString, lpSystemName );
  5848. RtlAnsiStringToUnicodeString( &SystemName, &AnsiString, TRUE );
  5849. pSystemName = SystemName.Buffer;
  5850. }
  5851. BoolStatus = LookupAccountSidInternal(
  5852. (LPCWSTR)pSystemName,
  5853. lpSid,
  5854. WName,
  5855. cchName,
  5856. WReferencedDomainName,
  5857. cchReferencedDomainName,
  5858. peUse,
  5859. FALSE // not unicode
  5860. );
  5861. if ( ARGUMENT_PRESENT( lpSystemName ) ) {
  5862. RtlFreeUnicodeString( &SystemName );
  5863. }
  5864. if ( BoolStatus ) {
  5865. //
  5866. // Copy the Name and DomainName information into the passed CHAR
  5867. // buffers.
  5868. //
  5869. if ( ARGUMENT_PRESENT(lpName) ) {
  5870. AnsiString.Buffer = lpName;
  5871. //
  5872. // Watch for 16-bit overflow on buffer size. Clamp size to
  5873. // 16 bits if necessary.
  5874. //
  5875. if (cchInitName <= (DWORD) MAXUSHORT) {
  5876. AnsiString.MaximumLength = (USHORT) cchInitName;
  5877. } else {
  5878. AnsiString.MaximumLength = (USHORT) MAXUSHORT;
  5879. }
  5880. RtlInitUnicodeString( &UnicodeString, WName );
  5881. Status = RtlUnicodeStringToAnsiString( &AnsiString,
  5882. &UnicodeString,
  5883. FALSE );
  5884. ASSERT(NT_SUCCESS(Status));
  5885. AnsiString.Buffer[AnsiString.Length] = 0;
  5886. }
  5887. if ( ARGUMENT_PRESENT(lpReferencedDomainName) ) {
  5888. AnsiString.Buffer = lpReferencedDomainName;
  5889. //
  5890. // Watch for 16-bit overflow on buffer size. Clamp size to
  5891. // 16 bits if necessary.
  5892. //
  5893. if (cchInitReferencedDomainName <= (DWORD) MAXUSHORT) {
  5894. AnsiString.MaximumLength = (USHORT) cchInitReferencedDomainName;
  5895. } else {
  5896. AnsiString.MaximumLength = (USHORT) MAXUSHORT;
  5897. }
  5898. RtlInitUnicodeString( &UnicodeString, WReferencedDomainName );
  5899. Status = RtlUnicodeStringToAnsiString( &AnsiString,
  5900. &UnicodeString,
  5901. FALSE );
  5902. ASSERT(NT_SUCCESS(Status));
  5903. AnsiString.Buffer[AnsiString.Length] = 0;
  5904. }
  5905. }
  5906. if (ARGUMENT_PRESENT(WName)) {
  5907. LocalFree( WName );
  5908. }
  5909. if (ARGUMENT_PRESENT(WReferencedDomainName)) {
  5910. LocalFree( WReferencedDomainName );
  5911. }
  5912. return( BoolStatus );
  5913. }
  5914. BOOL
  5915. APIENTRY
  5916. LookupAccountSidW(
  5917. LPCWSTR lpSystemName,
  5918. PSID lpSid,
  5919. LPWSTR lpName,
  5920. LPDWORD cchName,
  5921. LPWSTR lpReferencedDomainName,
  5922. LPDWORD cchReferencedDomainName,
  5923. PSID_NAME_USE peUse
  5924. )
  5925. /*++
  5926. Routine Description:
  5927. Translates a passed SID into an account name. It will also return
  5928. the name and SID of the first domain in which this SID was found.
  5929. Arguments:
  5930. lpSystemName - Supplies the name of the system at which the lookup
  5931. is to be performed. If the null string is provided, the local
  5932. system is assumed.
  5933. lpSid - Supplies the account Sid.
  5934. lpName - Returns the name corresponding to the passed account SID.
  5935. cchName - Supplies the size (in Wide characters) of the buffer passed in for
  5936. lpName. This size must allow one character for the null terminator
  5937. that will be appended to the returned name. If the buffer size is not
  5938. large enough, this parameter will return the size necessary to hold
  5939. the null-terminated output name. If the buffer size is large enough,
  5940. this parameter will return the size (in Ansi characters, excluding
  5941. the null terminator) of the name returned.
  5942. lpReferencedDomainName - Returns the name of the domain in which the
  5943. name was found.
  5944. cchReferencedDomainName - Supplies the size (in Wide characters) of the
  5945. ReferencedDomainName buffer. This size must allow one charcter for the
  5946. null terminator that will be appended to the returned name. If the
  5947. buffer size is not large enough, this parameter will return the size
  5948. necessary to hold the output null-terminated domain name. If the
  5949. buffer size is large enough, the size of the returned name, excluding
  5950. the terminating null will be returned.
  5951. peUse - Returns an enumerated type inidicating the type of the
  5952. account.
  5953. Return Value:
  5954. BOOL - TRUE if successful, else FALSE.
  5955. --*/
  5956. {
  5957. return(LookupAccountSidInternal(
  5958. lpSystemName,
  5959. lpSid,
  5960. lpName,
  5961. cchName,
  5962. lpReferencedDomainName,
  5963. cchReferencedDomainName,
  5964. peUse,
  5965. TRUE // Unicode
  5966. ));
  5967. }
  5968. BOOL
  5969. APIENTRY
  5970. LookupPrivilegeValueA(
  5971. LPCSTR lpSystemName,
  5972. LPCSTR lpName,
  5973. PLUID lpLuid
  5974. )
  5975. /*++
  5976. Routine Description:
  5977. ANSI Thunk to LookupPrivilegeValueW().
  5978. Arguments:
  5979. Return Value:
  5980. --*/
  5981. {
  5982. NTSTATUS Status;
  5983. UNICODE_STRING USystemName, UName;
  5984. ANSI_STRING ASystemName, AName;
  5985. BOOL bool;
  5986. RtlInitAnsiString( &ASystemName, lpSystemName );
  5987. RtlInitAnsiString( &AName, lpName );
  5988. USystemName.Buffer = NULL;
  5989. UName.Buffer = NULL;
  5990. Status = RtlAnsiStringToUnicodeString( &USystemName, &ASystemName, TRUE );
  5991. if (NT_SUCCESS(Status)) {
  5992. Status = RtlAnsiStringToUnicodeString( &UName, &AName, TRUE );
  5993. if (NT_SUCCESS(Status)) {
  5994. bool = LookupPrivilegeValueW( (LPCWSTR)USystemName.Buffer,
  5995. (LPCWSTR)UName.Buffer,
  5996. lpLuid
  5997. );
  5998. RtlFreeUnicodeString( &UName );
  5999. }
  6000. RtlFreeUnicodeString( &USystemName );
  6001. }
  6002. if (!NT_SUCCESS(Status)) {
  6003. BaseSetLastNTError( Status );
  6004. return( FALSE );
  6005. }
  6006. return(bool);
  6007. }
  6008. BOOL
  6009. APIENTRY
  6010. LookupPrivilegeValueW(
  6011. LPCWSTR lpSystemName,
  6012. LPCWSTR lpName,
  6013. PLUID lpLuid
  6014. )
  6015. /*++
  6016. Routine Description:
  6017. This function retrieves the value used on the target system
  6018. to locally represent the specified privilege. The privilege
  6019. is specified by programmatic name.
  6020. Arguments:
  6021. lpSystemName - Supplies the name of the system at which the lookup
  6022. is to be performed. If the null string is provided, the local
  6023. system is assumed.
  6024. lpName - provides the privilege's programmatic name.
  6025. lpLuid - Receives the locally unique ID the privilege is known by on the
  6026. target machine.
  6027. Return Value:
  6028. --*/
  6029. {
  6030. NTSTATUS Status,
  6031. TmpStatus;
  6032. LSA_HANDLE PolicyHandle;
  6033. OBJECT_ATTRIBUTES ObjectAttributes;
  6034. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  6035. UNICODE_STRING USystemName,
  6036. UName;
  6037. PUNICODE_STRING SystemName = NULL;
  6038. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  6039. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  6040. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  6041. SecurityQualityOfService.EffectiveOnly = FALSE;
  6042. //
  6043. // Set up the object attributes prior to opening the LSA.
  6044. //
  6045. InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
  6046. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  6047. if ( ARGUMENT_PRESENT( lpSystemName )) {
  6048. RtlInitUnicodeString( &USystemName, lpSystemName );
  6049. SystemName = &USystemName;
  6050. }
  6051. Status = LsaOpenPolicy(
  6052. SystemName,
  6053. &ObjectAttributes,
  6054. POLICY_LOOKUP_NAMES,
  6055. &PolicyHandle
  6056. );
  6057. if ( !NT_SUCCESS( Status )) {
  6058. BaseSetLastNTError( Status );
  6059. return( FALSE );
  6060. }
  6061. RtlInitUnicodeString( &UName, lpName );
  6062. Status = LsaLookupPrivilegeValue( PolicyHandle, &UName, lpLuid );
  6063. TmpStatus = LsaClose( PolicyHandle );
  6064. // ASSERT( NT_SUCCESS( TmpStatus ));
  6065. if ( !NT_SUCCESS( Status )) {
  6066. BaseSetLastNTError( Status );
  6067. return( FALSE );
  6068. }
  6069. return(TRUE);
  6070. }
  6071. BOOL
  6072. APIENTRY
  6073. LookupPrivilegeNameA(
  6074. LPCSTR lpSystemName,
  6075. PLUID lpLuid,
  6076. LPSTR lpName,
  6077. LPDWORD cchName
  6078. )
  6079. /*++
  6080. Routine Description:
  6081. ANSI Thunk to LookupPrivilegeValueW().
  6082. Arguments:
  6083. Return Value:
  6084. --*/
  6085. {
  6086. NTSTATUS Status;
  6087. ANSI_STRING AnsiName;
  6088. LPWSTR UnicodeBuffer;
  6089. UNICODE_STRING UnicodeString;
  6090. ANSI_STRING AnsiSystemName;
  6091. UNICODE_STRING UnicodeSystemName;
  6092. DWORD LengthRequired;
  6093. //
  6094. // Convert the passed SystemName to Unicode. Let the Rtl function
  6095. // allocate the memory we need.
  6096. //
  6097. RtlInitAnsiString( &AnsiSystemName, lpSystemName );
  6098. Status = RtlAnsiStringToUnicodeString( &UnicodeSystemName, &AnsiSystemName, TRUE );
  6099. if (!NT_SUCCESS( Status )) {
  6100. BaseSetLastNTError( Status );
  6101. return( FALSE );
  6102. }
  6103. //
  6104. // Make sure we don't exceed the limits of a unicode string.
  6105. //
  6106. if (*cchName > 0xFFFC) {
  6107. *cchName = 0xFFFC;
  6108. }
  6109. UnicodeBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, *cchName * sizeof(WCHAR) );
  6110. if (UnicodeBuffer == NULL) {
  6111. RtlFreeUnicodeString( &UnicodeSystemName );
  6112. BaseSetLastNTError( STATUS_NO_MEMORY );
  6113. return( FALSE );
  6114. }
  6115. //
  6116. // Don't pass in cchName, since it will be overwritten by LookupPrivilegeNameW,
  6117. // and we need it later.
  6118. //
  6119. LengthRequired = *cchName;
  6120. if (!LookupPrivilegeNameW( (LPCWSTR)UnicodeSystemName.Buffer,
  6121. lpLuid,
  6122. UnicodeBuffer,
  6123. &LengthRequired
  6124. )) {
  6125. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  6126. RtlFreeUnicodeString( &UnicodeSystemName );
  6127. *cchName = LengthRequired;
  6128. return(FALSE);
  6129. }
  6130. //
  6131. // Now convert back to ANSI for the caller
  6132. //
  6133. RtlInitUnicodeString(&UnicodeString, UnicodeBuffer);
  6134. AnsiName.Buffer = lpName;
  6135. AnsiName.Length = 0;
  6136. AnsiName.MaximumLength = (USHORT)*cchName;
  6137. Status = RtlUnicodeStringToAnsiString(&AnsiName, &UnicodeString, FALSE);
  6138. ASSERT( NT_SUCCESS( Status ));
  6139. *cchName = AnsiName.Length;
  6140. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  6141. RtlFreeUnicodeString( &UnicodeSystemName );
  6142. return(TRUE);
  6143. }
  6144. BOOL
  6145. APIENTRY
  6146. LookupPrivilegeNameW(
  6147. LPCWSTR lpSystemName,
  6148. PLUID lpLuid,
  6149. LPWSTR lpName,
  6150. LPDWORD cchName
  6151. )
  6152. /*++
  6153. Routine Description:
  6154. This function returns the programmatic name corresponding to
  6155. the privilege represented on the target system by the provided
  6156. LUID.
  6157. Arguments:
  6158. lpSystemName - Supplies the name of the system at which the lookup
  6159. is to be performed. If the null string is provided, the local
  6160. system is assumed.
  6161. lpLuid - is the locally unique ID the privilege is known by on the
  6162. target machine.
  6163. lpName - Receives the privilege's programmatic name.
  6164. cchName - indicates how large the buffer is (in characters). This
  6165. count does not include the null-terminator that is added at the
  6166. end of the string.
  6167. Return Value:
  6168. --*/
  6169. {
  6170. NTSTATUS Status,
  6171. TmpStatus;
  6172. LSA_HANDLE PolicyHandle;
  6173. OBJECT_ATTRIBUTES ObjectAttributes;
  6174. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  6175. UNICODE_STRING USystemName;
  6176. PUNICODE_STRING SystemName,
  6177. UName;
  6178. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  6179. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  6180. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  6181. SecurityQualityOfService.EffectiveOnly = FALSE;
  6182. //
  6183. // Set up the object attributes prior to opening the LSA.
  6184. //
  6185. InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
  6186. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  6187. SystemName = NULL;
  6188. if ( ARGUMENT_PRESENT( lpSystemName )) {
  6189. RtlInitUnicodeString( &USystemName, lpSystemName );
  6190. SystemName = &USystemName;
  6191. }
  6192. Status = LsaOpenPolicy(
  6193. SystemName,
  6194. &ObjectAttributes,
  6195. POLICY_LOOKUP_NAMES,
  6196. &PolicyHandle
  6197. );
  6198. if ( !NT_SUCCESS( Status )) {
  6199. BaseSetLastNTError( Status );
  6200. return( FALSE );
  6201. }
  6202. UName = NULL;
  6203. Status = LsaLookupPrivilegeName( PolicyHandle,lpLuid, &UName );
  6204. if (NT_SUCCESS(Status) ) {
  6205. if ((DWORD)UName->Length + sizeof( WCHAR) > (*cchName) * sizeof( WCHAR )) {
  6206. Status = STATUS_BUFFER_TOO_SMALL;
  6207. (*cchName) = ( UName->Length + sizeof( WCHAR) ) / sizeof( WCHAR );
  6208. } else {
  6209. RtlMoveMemory( lpName, UName->Buffer, UName->Length );
  6210. lpName[UName->Length/sizeof(WCHAR)] = 0; // NULL terminate it
  6211. (*cchName) = UName->Length / sizeof( WCHAR );
  6212. }
  6213. LsaFreeMemory( UName->Buffer );
  6214. LsaFreeMemory( UName );
  6215. }
  6216. TmpStatus = LsaClose( PolicyHandle );
  6217. // ASSERT( NT_SUCCESS( TmpStatus ));
  6218. if ( !NT_SUCCESS( Status )) {
  6219. BaseSetLastNTError( Status );
  6220. return( FALSE );
  6221. }
  6222. return(TRUE);
  6223. }
  6224. BOOL
  6225. APIENTRY
  6226. LookupPrivilegeDisplayNameA(
  6227. LPCSTR lpSystemName,
  6228. LPCSTR lpName,
  6229. LPSTR lpDisplayName,
  6230. LPDWORD cchDisplayName,
  6231. LPDWORD lpLanguageId
  6232. )
  6233. /*++
  6234. Routine Description:
  6235. ANSI Thunk to LookupPrivilegeValueW().
  6236. Arguments:
  6237. Return Value:
  6238. --*/
  6239. {
  6240. NTSTATUS Status;
  6241. UNICODE_STRING UnicodeSystemName;
  6242. UNICODE_STRING UnicodeString;
  6243. UNICODE_STRING UnicodeName;
  6244. ANSI_STRING AnsiSystemName;
  6245. ANSI_STRING AnsiDisplayName;
  6246. ANSI_STRING AnsiName;
  6247. LPWSTR UnicodeBuffer;
  6248. DWORD RequiredLength;
  6249. RtlInitAnsiString( &AnsiSystemName, lpSystemName );
  6250. Status = RtlAnsiStringToUnicodeString( &UnicodeSystemName, &AnsiSystemName, TRUE );
  6251. if (!NT_SUCCESS( Status )) {
  6252. BaseSetLastNTError( Status );
  6253. return( FALSE );
  6254. }
  6255. //
  6256. // Make sure we don't exceed that limits of a unicode string.
  6257. //
  6258. if (*cchDisplayName > 0xFFFC) {
  6259. *cchDisplayName = 0xFFFC;
  6260. }
  6261. UnicodeBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, *cchDisplayName * sizeof(WCHAR));
  6262. if (UnicodeBuffer == NULL) {
  6263. RtlFreeUnicodeString( &UnicodeSystemName );
  6264. BaseSetLastNTError( STATUS_NO_MEMORY );
  6265. return( FALSE );
  6266. }
  6267. RtlInitAnsiString( &AnsiName, lpName );
  6268. Status = RtlAnsiStringToUnicodeString( &UnicodeName, &AnsiName, TRUE );
  6269. if (!NT_SUCCESS( Status )) {
  6270. RtlFreeUnicodeString( &UnicodeSystemName );
  6271. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  6272. BaseSetLastNTError( Status );
  6273. return( FALSE );
  6274. }
  6275. RequiredLength = *cchDisplayName;
  6276. if (! LookupPrivilegeDisplayNameW( (LPCWSTR)UnicodeSystemName.Buffer,
  6277. (LPCWSTR)UnicodeName.Buffer,
  6278. UnicodeBuffer,
  6279. &RequiredLength,
  6280. lpLanguageId
  6281. )) {
  6282. //
  6283. // No need to set last error here, we can assume the W routine did so.
  6284. //
  6285. *cchDisplayName = RequiredLength;
  6286. RtlFreeUnicodeString( &UnicodeSystemName );
  6287. RtlFreeUnicodeString( &UnicodeName );
  6288. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  6289. return( FALSE );
  6290. }
  6291. //
  6292. // Now convert back to ANSI for the caller
  6293. //
  6294. RtlInitUnicodeString( &UnicodeString, UnicodeBuffer );
  6295. AnsiDisplayName.Buffer = lpDisplayName;
  6296. AnsiDisplayName.Length = 0;
  6297. AnsiDisplayName.MaximumLength = (USHORT)(*cchDisplayName);
  6298. Status = RtlUnicodeStringToAnsiString( &AnsiDisplayName, &UnicodeString, FALSE );
  6299. ASSERT( NT_SUCCESS( Status ));
  6300. *cchDisplayName = AnsiDisplayName.Length;
  6301. RtlFreeUnicodeString( &UnicodeSystemName );
  6302. RtlFreeUnicodeString( &UnicodeName );
  6303. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  6304. return( TRUE );
  6305. }
  6306. BOOL
  6307. APIENTRY
  6308. LookupPrivilegeDisplayNameW(
  6309. LPCWSTR lpSystemName,
  6310. LPCWSTR lpName,
  6311. LPWSTR lpDisplayName,
  6312. LPDWORD cchDisplayName,
  6313. LPDWORD lpLanguageId
  6314. )
  6315. /*++
  6316. Routine Description:
  6317. This function retrieves a displayable name representing the
  6318. specified privilege.
  6319. Arguments:
  6320. lpSystemName - Supplies the name of the system at which the lookup
  6321. is to be performed. If the null string is provided, the local
  6322. system is assumed.
  6323. lpName - provides the privilege's programmatic name.
  6324. lpDisplayName - Receives the privilege's displayable name.
  6325. cchDisplayName - indicates how large the buffer is (in characters). This
  6326. count does not include the null-terminator that is added at the
  6327. end of the string.
  6328. lpLanguageId - Receives the language of the returned displayable
  6329. name.
  6330. Return Value:
  6331. --*/
  6332. {
  6333. NTSTATUS Status,
  6334. TmpStatus;
  6335. LSA_HANDLE PolicyHandle;
  6336. OBJECT_ATTRIBUTES ObjectAttributes;
  6337. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  6338. UNICODE_STRING USystemName,
  6339. UName;
  6340. PUNICODE_STRING SystemName,
  6341. UDisplayName;
  6342. SHORT LanguageId;
  6343. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  6344. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  6345. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  6346. SecurityQualityOfService.EffectiveOnly = FALSE;
  6347. //
  6348. // Set up the object attributes prior to opening the LSA.
  6349. //
  6350. InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
  6351. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  6352. SystemName = NULL;
  6353. if ( ARGUMENT_PRESENT( lpSystemName )) {
  6354. RtlInitUnicodeString( &USystemName, lpSystemName );
  6355. SystemName = &USystemName;
  6356. }
  6357. Status = LsaOpenPolicy(
  6358. SystemName,
  6359. &ObjectAttributes,
  6360. POLICY_LOOKUP_NAMES,
  6361. &PolicyHandle
  6362. );
  6363. if ( !NT_SUCCESS( Status )) {
  6364. BaseSetLastNTError( Status );
  6365. return( FALSE );
  6366. }
  6367. RtlInitUnicodeString( &UName, lpName );
  6368. UDisplayName = NULL;
  6369. Status = LsaLookupPrivilegeDisplayName( PolicyHandle,
  6370. &UName,
  6371. &UDisplayName,
  6372. &LanguageId
  6373. );
  6374. (*lpLanguageId) = LanguageId;
  6375. if (NT_SUCCESS(Status)) {
  6376. if (UDisplayName->Length + sizeof(WCHAR) > (*cchDisplayName) * sizeof(WCHAR)) {
  6377. Status = STATUS_BUFFER_TOO_SMALL;
  6378. (*cchDisplayName) = (UDisplayName->Length + sizeof( WCHAR )) / sizeof( WCHAR );
  6379. } else {
  6380. RtlMoveMemory( lpDisplayName,
  6381. UDisplayName->Buffer,
  6382. UDisplayName->Length
  6383. );
  6384. lpDisplayName[UDisplayName->Length/sizeof(WCHAR)] = 0; // Null terminate it.
  6385. (*cchDisplayName) = UDisplayName->Length / sizeof( WCHAR );
  6386. }
  6387. LsaFreeMemory( UDisplayName->Buffer );
  6388. LsaFreeMemory( UDisplayName );
  6389. }
  6390. TmpStatus = LsaClose( PolicyHandle );
  6391. // ASSERT( NT_SUCCESS( TmpStatus ));
  6392. if ( !NT_SUCCESS( Status )) {
  6393. BaseSetLastNTError( Status );
  6394. return( FALSE );
  6395. }
  6396. return(TRUE);
  6397. }
  6398. BOOL
  6399. APIENTRY
  6400. ImpersonateAnonymousToken(
  6401. IN HANDLE ThreadHandle
  6402. )
  6403. /*++
  6404. Routine Description:
  6405. Win32 wrapper for NtImpersonateAnonymousToken();
  6406. Impersonates the system's anonymous logon token on this thread.
  6407. Arguments:
  6408. ThreadHandle - Handle to the thread to do the impersonation.
  6409. Return Value:
  6410. TRUE for success, FALSE for failure.
  6411. Call GetLastError() for more information.
  6412. --*/
  6413. {
  6414. NTSTATUS Status;
  6415. Status = NtImpersonateAnonymousToken(
  6416. ThreadHandle
  6417. );
  6418. if ( !NT_SUCCESS( Status )) {
  6419. BaseSetLastNTError( Status );
  6420. return( FALSE );
  6421. } else {
  6422. return( TRUE );
  6423. }
  6424. }
  6425. /////////////////////////////////////////////////////////////////////////////
  6426. // //
  6427. // Private Routines //
  6428. // //
  6429. /////////////////////////////////////////////////////////////////////////////
  6430. VOID
  6431. SepFormatAccountSid(
  6432. PSID Sid,
  6433. LPWSTR OutputBuffer
  6434. )
  6435. {
  6436. UCHAR Buffer[128];
  6437. UCHAR TmpBuffer[128];
  6438. ANSI_STRING AccountName;
  6439. UCHAR i;
  6440. ULONG Tmp;
  6441. UNICODE_STRING OutputString;
  6442. PISID iSid;
  6443. NTSTATUS Status;
  6444. //
  6445. // Do everything as ANSI for the time being, and then
  6446. // convert to wide-char at the bottom.
  6447. //
  6448. // We need to do this until we have more complete c-runtime support
  6449. // for w-char strings.
  6450. //
  6451. iSid = (PISID) Sid;
  6452. OutputString.Buffer = OutputBuffer;
  6453. OutputString.MaximumLength = 127;
  6454. Buffer[0] = 0;
  6455. TmpBuffer[0] = 0;
  6456. AccountName.MaximumLength = 127;
  6457. AccountName.Length = (USHORT)((GetLengthSid( Sid ) > MAXUSHORT) ? MAXUSHORT : GetLengthSid( Sid ));
  6458. AccountName.Buffer = Buffer;
  6459. sprintf(TmpBuffer, "S-%u-", (USHORT)iSid->Revision );
  6460. lstrcpy(Buffer, TmpBuffer);
  6461. if ( (iSid->IdentifierAuthority.Value[0] != 0) ||
  6462. (iSid->IdentifierAuthority.Value[1] != 0) ){
  6463. sprintf(TmpBuffer, "0x%02hx%02hx%02hx%02hx%02hx%02hx",
  6464. (USHORT)iSid->IdentifierAuthority.Value[0],
  6465. (USHORT)iSid->IdentifierAuthority.Value[1],
  6466. (USHORT)iSid->IdentifierAuthority.Value[2],
  6467. (USHORT)iSid->IdentifierAuthority.Value[3],
  6468. (USHORT)iSid->IdentifierAuthority.Value[4],
  6469. (USHORT)iSid->IdentifierAuthority.Value[5] );
  6470. lstrcat(Buffer, TmpBuffer);
  6471. } else {
  6472. Tmp = (ULONG)iSid->IdentifierAuthority.Value[5] +
  6473. (ULONG)(iSid->IdentifierAuthority.Value[4] << 8) +
  6474. (ULONG)(iSid->IdentifierAuthority.Value[3] << 16) +
  6475. (ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
  6476. sprintf(TmpBuffer, "%lu", Tmp);
  6477. lstrcat(Buffer, TmpBuffer);
  6478. }
  6479. for (i=0;i<iSid->SubAuthorityCount ;i++ ) {
  6480. sprintf(TmpBuffer, "-%lu", iSid->SubAuthority[i]);
  6481. lstrcat(Buffer, TmpBuffer);
  6482. }
  6483. Status = RtlAnsiStringToUnicodeString( &OutputString, &AccountName, FALSE );
  6484. ASSERT( NT_SUCCESS( Status ));
  6485. return;
  6486. }
  6487. BOOL
  6488. APIENTRY
  6489. CreateRestrictedToken(
  6490. IN HANDLE ExistingTokenHandle,
  6491. IN DWORD Flags,
  6492. IN DWORD DisableSidCount,
  6493. IN PSID_AND_ATTRIBUTES SidsToDisable OPTIONAL,
  6494. IN DWORD DeletePrivilegeCount,
  6495. IN PLUID_AND_ATTRIBUTES PrivilegesToDelete OPTIONAL,
  6496. IN DWORD RestrictedSidCount,
  6497. IN PSID_AND_ATTRIBUTES SidsToRestrict OPTIONAL,
  6498. OUT PHANDLE NewTokenHandle
  6499. )
  6500. {
  6501. NTSTATUS Status;
  6502. PTOKEN_GROUPS DisabledSids = NULL;
  6503. PTOKEN_PRIVILEGES DeletedPrivileges = NULL;
  6504. PTOKEN_GROUPS RestrictedSids = NULL;
  6505. //
  6506. // Convert the input parameters into the native NT format
  6507. //
  6508. if (DisableSidCount != 0) {
  6509. if (SidsToDisable == NULL) {
  6510. Status = STATUS_INVALID_PARAMETER;
  6511. goto Cleanup;
  6512. }
  6513. DisabledSids = (PTOKEN_GROUPS) LocalAlloc(0,sizeof(TOKEN_GROUPS) +
  6514. (DisableSidCount - 1) * sizeof(SID_AND_ATTRIBUTES) );
  6515. if (DisabledSids == NULL)
  6516. {
  6517. Status = STATUS_INSUFFICIENT_RESOURCES;
  6518. goto Cleanup;
  6519. }
  6520. DisabledSids->GroupCount = DisableSidCount;
  6521. RtlCopyMemory(
  6522. DisabledSids->Groups,
  6523. SidsToDisable,
  6524. DisableSidCount * sizeof(SID_AND_ATTRIBUTES)
  6525. );
  6526. }
  6527. if (DeletePrivilegeCount != 0) {
  6528. if (PrivilegesToDelete == NULL) {
  6529. Status = STATUS_INVALID_PARAMETER;
  6530. goto Cleanup;
  6531. }
  6532. DeletedPrivileges = (PTOKEN_PRIVILEGES) LocalAlloc(0,sizeof(TOKEN_PRIVILEGES) +
  6533. (DeletePrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES) );
  6534. if (DeletedPrivileges == NULL)
  6535. {
  6536. Status = STATUS_INSUFFICIENT_RESOURCES;
  6537. goto Cleanup;
  6538. }
  6539. DeletedPrivileges->PrivilegeCount = DeletePrivilegeCount;
  6540. RtlCopyMemory(
  6541. DeletedPrivileges->Privileges,
  6542. PrivilegesToDelete,
  6543. DeletePrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)
  6544. );
  6545. }
  6546. if (RestrictedSidCount != 0) {
  6547. if (SidsToRestrict == NULL) {
  6548. Status = STATUS_INVALID_PARAMETER;
  6549. goto Cleanup;
  6550. }
  6551. RestrictedSids = (PTOKEN_GROUPS) LocalAlloc(0,sizeof(TOKEN_GROUPS) +
  6552. (RestrictedSidCount - 1) * sizeof(SID_AND_ATTRIBUTES) );
  6553. if (RestrictedSids == NULL)
  6554. {
  6555. Status = STATUS_INSUFFICIENT_RESOURCES;
  6556. goto Cleanup;
  6557. }
  6558. RestrictedSids->GroupCount = RestrictedSidCount;
  6559. RtlCopyMemory(
  6560. RestrictedSids->Groups,
  6561. SidsToRestrict,
  6562. RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)
  6563. );
  6564. }
  6565. Status = NtFilterToken(
  6566. ExistingTokenHandle,
  6567. Flags,
  6568. DisabledSids,
  6569. DeletedPrivileges,
  6570. RestrictedSids,
  6571. NewTokenHandle
  6572. );
  6573. Cleanup:
  6574. if (DisabledSids != NULL) {
  6575. LocalFree(DisabledSids);
  6576. }
  6577. if (DeletedPrivileges != NULL) {
  6578. LocalFree(DeletedPrivileges);
  6579. }
  6580. if (RestrictedSids != NULL) {
  6581. LocalFree(RestrictedSids);
  6582. }
  6583. if (!NT_SUCCESS(Status)) {
  6584. BaseSetLastNTError( Status );
  6585. return(FALSE);
  6586. }
  6587. return(TRUE);
  6588. }
  6589. BOOL
  6590. APIENTRY
  6591. IsTokenRestricted(
  6592. IN HANDLE TokenHandle
  6593. )
  6594. {
  6595. PTOKEN_GROUPS RestrictedSids = NULL;
  6596. ULONG ReturnLength;
  6597. NTSTATUS Status;
  6598. BOOL Result = FALSE;
  6599. Status = NtQueryInformationToken(
  6600. TokenHandle,
  6601. TokenRestrictedSids,
  6602. NULL,
  6603. 0,
  6604. &ReturnLength
  6605. );
  6606. if (Status != STATUS_BUFFER_TOO_SMALL)
  6607. {
  6608. BaseSetLastNTError(Status);
  6609. return(FALSE);
  6610. }
  6611. RestrictedSids = (PTOKEN_GROUPS) LocalAlloc(0, ReturnLength);
  6612. if (RestrictedSids == NULL)
  6613. {
  6614. SetLastError(ERROR_OUTOFMEMORY);
  6615. return(FALSE);
  6616. }
  6617. Status = NtQueryInformationToken(
  6618. TokenHandle,
  6619. TokenRestrictedSids,
  6620. RestrictedSids,
  6621. ReturnLength,
  6622. &ReturnLength
  6623. );
  6624. if (NT_SUCCESS(Status))
  6625. {
  6626. if (RestrictedSids->GroupCount != 0)
  6627. {
  6628. Result = TRUE;
  6629. }
  6630. }
  6631. else
  6632. {
  6633. BaseSetLastNTError(Status);
  6634. }
  6635. LocalFree(RestrictedSids);
  6636. return(Result);
  6637. }
  6638. BOOL
  6639. APIENTRY
  6640. CheckTokenMembership(
  6641. IN HANDLE TokenHandle OPTIONAL,
  6642. IN PSID SidToCheck,
  6643. OUT PBOOL IsMember
  6644. )
  6645. /*++
  6646. Routine Description:
  6647. This function checks to see whether the specified sid is enabled in
  6648. the specified token.
  6649. Arguments:
  6650. TokenHandle - If present, this token is checked for the sid. If not
  6651. present then the current effective token will be used. This must
  6652. be an impersonation token.
  6653. SidToCheck - The sid to check for presence in the token
  6654. IsMember - If the sid is enabled in the token, contains TRUE otherwise
  6655. false.
  6656. Return Value:
  6657. TRUE - The API completed successfully. It does not indicate that the
  6658. sid is a member of the token.
  6659. FALSE - The API failed. A more detailed status code can be retrieved
  6660. via GetLastError()
  6661. --*/
  6662. {
  6663. HANDLE ProcessToken = NULL;
  6664. HANDLE EffectiveToken = NULL;
  6665. NTSTATUS Status = STATUS_SUCCESS;
  6666. PISECURITY_DESCRIPTOR SecDesc = NULL;
  6667. ULONG SecurityDescriptorSize;
  6668. GENERIC_MAPPING GenericMapping = {
  6669. STANDARD_RIGHTS_READ,
  6670. STANDARD_RIGHTS_EXECUTE,
  6671. STANDARD_RIGHTS_WRITE,
  6672. STANDARD_RIGHTS_ALL };
  6673. //
  6674. // The size of the privilege set needs to contain the set itself plus
  6675. // any privileges that may be used. The privileges that are used
  6676. // are SeTakeOwnership and SeSecurity, plus one for good measure
  6677. //
  6678. BYTE PrivilegeSetBuffer[sizeof(PRIVILEGE_SET) + 3*sizeof(LUID_AND_ATTRIBUTES)];
  6679. PPRIVILEGE_SET PrivilegeSet = (PPRIVILEGE_SET) PrivilegeSetBuffer;
  6680. ULONG PrivilegeSetLength = sizeof(PrivilegeSetBuffer);
  6681. ACCESS_MASK AccessGranted = 0;
  6682. NTSTATUS AccessStatus = 0;
  6683. PACL Dacl = NULL;
  6684. #define MEMBER_ACCESS 1
  6685. *IsMember = FALSE;
  6686. //
  6687. // Get a handle to the token
  6688. //
  6689. if (ARGUMENT_PRESENT(TokenHandle))
  6690. {
  6691. EffectiveToken = TokenHandle;
  6692. }
  6693. else
  6694. {
  6695. Status = NtOpenThreadToken(
  6696. NtCurrentThread(),
  6697. TOKEN_QUERY,
  6698. FALSE, // don't open as self
  6699. &EffectiveToken
  6700. );
  6701. //
  6702. // if there is no thread token, try the process token
  6703. //
  6704. if (Status == STATUS_NO_TOKEN)
  6705. {
  6706. Status = NtOpenProcessToken(
  6707. NtCurrentProcess(),
  6708. TOKEN_QUERY | TOKEN_DUPLICATE,
  6709. &ProcessToken
  6710. );
  6711. //
  6712. // If we have a process token, we need to convert it to an
  6713. // impersonation token
  6714. //
  6715. if (NT_SUCCESS(Status))
  6716. {
  6717. BOOL Result;
  6718. Result = DuplicateToken(
  6719. ProcessToken,
  6720. SecurityImpersonation,
  6721. &EffectiveToken
  6722. );
  6723. CloseHandle(ProcessToken);
  6724. if (!Result)
  6725. {
  6726. return(FALSE);
  6727. }
  6728. }
  6729. }
  6730. if (!NT_SUCCESS(Status))
  6731. {
  6732. goto Cleanup;
  6733. }
  6734. }
  6735. //
  6736. // Construct a security descriptor to pass to access check
  6737. //
  6738. //
  6739. // The size is equal to the size of an SD + twice the length of the SID
  6740. // (for owner and group) + size of the DACL = sizeof ACL + size of the
  6741. // ACE, which is an ACE + length of
  6742. // ths SID.
  6743. //
  6744. SecurityDescriptorSize = sizeof(SECURITY_DESCRIPTOR) +
  6745. sizeof(ACCESS_ALLOWED_ACE) +
  6746. sizeof(ACL) +
  6747. 3 * RtlLengthSid(SidToCheck);
  6748. SecDesc = (PISECURITY_DESCRIPTOR) LocalAlloc(LMEM_ZEROINIT, SecurityDescriptorSize );
  6749. if (SecDesc == NULL)
  6750. {
  6751. Status = STATUS_INSUFFICIENT_RESOURCES;
  6752. goto Cleanup;
  6753. }
  6754. Dacl = (PACL) (SecDesc + 1);
  6755. RtlCreateSecurityDescriptor(
  6756. SecDesc,
  6757. SECURITY_DESCRIPTOR_REVISION
  6758. );
  6759. //
  6760. // Fill in fields of security descriptor
  6761. //
  6762. RtlSetOwnerSecurityDescriptor(
  6763. SecDesc,
  6764. SidToCheck,
  6765. FALSE
  6766. );
  6767. RtlSetGroupSecurityDescriptor(
  6768. SecDesc,
  6769. SidToCheck,
  6770. FALSE
  6771. );
  6772. Status = RtlCreateAcl(
  6773. Dacl,
  6774. SecurityDescriptorSize - sizeof(SECURITY_DESCRIPTOR),
  6775. ACL_REVISION
  6776. );
  6777. if (!NT_SUCCESS(Status))
  6778. {
  6779. goto Cleanup;
  6780. }
  6781. Status = RtlAddAccessAllowedAce(
  6782. Dacl,
  6783. ACL_REVISION,
  6784. MEMBER_ACCESS,
  6785. SidToCheck
  6786. );
  6787. if (!NT_SUCCESS(Status))
  6788. {
  6789. goto Cleanup;
  6790. }
  6791. //
  6792. // Set the DACL on the security descriptor
  6793. //
  6794. Status = RtlSetDaclSecurityDescriptor(
  6795. SecDesc,
  6796. TRUE, // DACL present
  6797. Dacl,
  6798. FALSE // not defaulted
  6799. );
  6800. if (!NT_SUCCESS(Status))
  6801. {
  6802. goto Cleanup;
  6803. }
  6804. Status = NtAccessCheck(
  6805. SecDesc,
  6806. EffectiveToken,
  6807. MEMBER_ACCESS,
  6808. &GenericMapping,
  6809. PrivilegeSet,
  6810. &PrivilegeSetLength,
  6811. &AccessGranted,
  6812. &AccessStatus
  6813. );
  6814. if (!NT_SUCCESS(Status))
  6815. {
  6816. goto Cleanup;
  6817. }
  6818. //
  6819. // if the access check failed, then the sid is not a member of the
  6820. // token
  6821. //
  6822. if ((AccessStatus == STATUS_SUCCESS) && (AccessGranted == MEMBER_ACCESS))
  6823. {
  6824. *IsMember = TRUE;
  6825. }
  6826. Cleanup:
  6827. if (!ARGUMENT_PRESENT(TokenHandle) && (EffectiveToken != NULL))
  6828. {
  6829. (VOID) NtClose(EffectiveToken);
  6830. }
  6831. if (SecDesc != NULL)
  6832. {
  6833. LocalFree(SecDesc);
  6834. }
  6835. if (!NT_SUCCESS(Status))
  6836. {
  6837. BaseSetLastNTError(Status);
  6838. return(FALSE);
  6839. }
  6840. else
  6841. {
  6842. return(TRUE);
  6843. }
  6844. }
  6845. BOOL
  6846. APIENTRY
  6847. MakeAbsoluteSD2 (
  6848. PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
  6849. LPDWORD lpdwBufferSize
  6850. )
  6851. /*++
  6852. Routine Description:
  6853. Converts a security descriptor from self-relative format to absolute
  6854. format
  6855. Arguments:
  6856. pSelfRelativeSecurityDescriptor - Supplies a pointer to a security descriptor
  6857. in Self-Relative format
  6858. lpdwBufferSize - The size in bytes of the
  6859. buffer pointed to by pSelfRelativeSecurityDescriptor.
  6860. Return Value:
  6861. Returns TRUE for success, FALSE for failure. Extended error status
  6862. is available using GetLastError.
  6863. --*/
  6864. {
  6865. NTSTATUS Status;
  6866. Status = RtlSelfRelativeToAbsoluteSD2 (
  6867. pSelfRelativeSecurityDescriptor,
  6868. lpdwBufferSize
  6869. );
  6870. //
  6871. // MakeAbsoluteSD2() has the same prototype as
  6872. // RtlSelfRelativeToAbsoluteSD2() so the parameters check
  6873. // returns the same parameter order if the caller passes invalid parameter.
  6874. //
  6875. if ( !NT_SUCCESS(Status) ) {
  6876. BaseSetLastNTError(Status);
  6877. return FALSE;
  6878. }
  6879. return TRUE;
  6880. } // MakeAbsoluteSD2()
  6881. DWORD
  6882. APIENTRY
  6883. GetSecurityDescriptorRMControl(
  6884. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  6885. OUT PUCHAR RMControl
  6886. )
  6887. /*++
  6888. Routine Description:
  6889. This procedure returns the RM Control flags from a SecurityDescriptor if
  6890. SE_RM_CONTROL_VALID flags is present in the control field.
  6891. Arguments:
  6892. SecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
  6893. RMControl - Returns the flags in the SecurityDescriptor if
  6894. SE_RM_CONTROL_VALID is set in the control bits of the
  6895. SecurityDescriptor.
  6896. Return Value:
  6897. ERROR_INVALID_DATA if the SE_RM_CONTROL_VALID flag is not present in
  6898. the security descriptor
  6899. ERROR_SUCCESS otherwise
  6900. --*/
  6901. {
  6902. BOOLEAN Result;
  6903. Result = RtlGetSecurityDescriptorRMControl(
  6904. SecurityDescriptor,
  6905. RMControl
  6906. );
  6907. if (FALSE == Result)
  6908. {
  6909. return ERROR_INVALID_DATA;
  6910. }
  6911. return ERROR_SUCCESS;
  6912. }
  6913. DWORD
  6914. APIENTRY
  6915. SetSecurityDescriptorRMControl(
  6916. IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
  6917. IN PUCHAR RMControl OPTIONAL
  6918. )
  6919. /*++
  6920. Routine Description:
  6921. This procedure sets the RM Control flag in the control field of
  6922. SecurityDescriptor and sets Sbz1 to the the byte to which RMContol point
  6923. If RMControl is NULL then the bits are cleared.
  6924. Arguments:
  6925. SecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
  6926. RMControl - Pointer to the flags to set. If NULL then the bits
  6927. are cleared.
  6928. Return Value: ERROR_SUCCESS
  6929. --*/
  6930. {
  6931. RtlSetSecurityDescriptorRMControl(
  6932. SecurityDescriptor,
  6933. RMControl
  6934. );
  6935. return ERROR_SUCCESS;
  6936. }
  6937. //
  6938. // Datatypes for identifying and constructing well known sids
  6939. //
  6940. //
  6941. // N.B When adding a new well known security principal, all that is
  6942. // necessary is to update one of the domain tables below. For example,
  6943. // if adding a new domain group, add an entry to AccountDomainSids
  6944. // with the new RID and the new WELL_KNOWN_SID_TYPE enumeration. If
  6945. // the addition would create two entries with the same RID then determine
  6946. // if a new table is required to contain SIDs with a common subauthority.
  6947. //
  6948. #define NELEMENTS(x) sizeof(x)/sizeof((x)[0])
  6949. typedef struct
  6950. {
  6951. ULONG Rid;
  6952. WELL_KNOWN_SID_TYPE Type;
  6953. } WELL_KNOWN_RID_ARRAY;
  6954. WELL_KNOWN_RID_ARRAY NullAuthoritySids[] =
  6955. {
  6956. {SECURITY_NULL_RID, WinNullSid}
  6957. };
  6958. WELL_KNOWN_RID_ARRAY WorldAuthoritySids[] =
  6959. {
  6960. {SECURITY_WORLD_RID, WinWorldSid}
  6961. };
  6962. WELL_KNOWN_RID_ARRAY LocalAuthoritySids[] =
  6963. {
  6964. {SECURITY_LOCAL_RID, WinLocalSid}
  6965. };
  6966. WELL_KNOWN_RID_ARRAY CreatorOwnerAuthoritySids[] =
  6967. {
  6968. {SECURITY_CREATOR_OWNER_RID, WinCreatorOwnerSid},
  6969. {SECURITY_CREATOR_GROUP_RID, WinCreatorGroupSid},
  6970. {SECURITY_CREATOR_OWNER_SERVER_RID, WinCreatorOwnerServerSid},
  6971. {SECURITY_CREATOR_GROUP_SERVER_RID, WinCreatorGroupServerSid}
  6972. };
  6973. WELL_KNOWN_RID_ARRAY NtAuthoritySids[] =
  6974. {
  6975. {SECURITY_DIALUP_RID, WinDialupSid},
  6976. {SECURITY_NETWORK_RID, WinNetworkSid},
  6977. {SECURITY_BATCH_RID, WinBatchSid},
  6978. {SECURITY_INTERACTIVE_RID, WinInteractiveSid},
  6979. {SECURITY_SERVICE_RID, WinServiceSid},
  6980. {SECURITY_ANONYMOUS_LOGON_RID, WinAnonymousSid},
  6981. {SECURITY_PROXY_RID, WinProxySid},
  6982. {SECURITY_ENTERPRISE_CONTROLLERS_RID, WinEnterpriseControllersSid},
  6983. {SECURITY_PRINCIPAL_SELF_RID, WinSelfSid},
  6984. {SECURITY_AUTHENTICATED_USER_RID, WinAuthenticatedUserSid},
  6985. {SECURITY_RESTRICTED_CODE_RID, WinRestrictedCodeSid},
  6986. {SECURITY_TERMINAL_SERVER_RID, WinTerminalServerSid},
  6987. {SECURITY_REMOTE_LOGON_RID, WinRemoteLogonIdSid},
  6988. {SECURITY_THIS_ORGANIZATION_RID, WinThisOrganizationSid},
  6989. {SECURITY_OTHER_ORGANIZATION_RID, WinOtherOrganizationSid},
  6990. //
  6991. // N.B. The Logon IDs SID is special in that it has three subauth's.
  6992. // IsWellKnownSid() special cases this, CreateWellKnownSid doesn't accept
  6993. // WinLogonIdsSid
  6994. //
  6995. // {SECURITY_LOGON_IDS_RID, WinLogonIdsSid},
  6996. {SECURITY_LOCAL_SYSTEM_RID, WinLocalSystemSid},
  6997. {SECURITY_LOCAL_SERVICE_RID, WinLocalServiceSid},
  6998. {SECURITY_NETWORK_SERVICE_RID, WinNetworkServiceSid},
  6999. {SECURITY_BUILTIN_DOMAIN_RID, WinBuiltinDomainSid},
  7000. };
  7001. WELL_KNOWN_RID_ARRAY BuiltinDomainSids[] =
  7002. {
  7003. {DOMAIN_ALIAS_RID_ADMINS, WinBuiltinAdministratorsSid},
  7004. {DOMAIN_ALIAS_RID_USERS, WinBuiltinUsersSid},
  7005. {DOMAIN_ALIAS_RID_GUESTS, WinBuiltinGuestsSid},
  7006. {DOMAIN_ALIAS_RID_POWER_USERS, WinBuiltinPowerUsersSid},
  7007. {DOMAIN_ALIAS_RID_ACCOUNT_OPS, WinBuiltinAccountOperatorsSid},
  7008. {DOMAIN_ALIAS_RID_SYSTEM_OPS, WinBuiltinSystemOperatorsSid},
  7009. {DOMAIN_ALIAS_RID_PRINT_OPS, WinBuiltinPrintOperatorsSid},
  7010. {DOMAIN_ALIAS_RID_BACKUP_OPS, WinBuiltinBackupOperatorsSid},
  7011. {DOMAIN_ALIAS_RID_REPLICATOR, WinBuiltinReplicatorSid},
  7012. {DOMAIN_ALIAS_RID_PREW2KCOMPACCESS, WinBuiltinPreWindows2000CompatibleAccessSid},
  7013. {DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS, WinBuiltinRemoteDesktopUsersSid},
  7014. {DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS, WinBuiltinNetworkConfigurationOperatorsSid},
  7015. {DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS, WinBuiltinIncomingForestTrustBuildersSid},
  7016. {DOMAIN_ALIAS_RID_MONITORING_USERS, WinBuiltinPerfMonitoringUsersSid},
  7017. {DOMAIN_ALIAS_RID_LOGGING_USERS, WinBuiltinPerfLoggingUsersSid},
  7018. {DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS, WinBuiltinAuthorizationAccessSid},
  7019. {DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS, WinBuiltinTerminalServerLicenseServersSid},
  7020. };
  7021. WELL_KNOWN_RID_ARRAY AccountDomainSids[] =
  7022. {
  7023. {DOMAIN_USER_RID_ADMIN, WinAccountAdministratorSid},
  7024. {DOMAIN_USER_RID_GUEST, WinAccountGuestSid},
  7025. {DOMAIN_USER_RID_KRBTGT, WinAccountKrbtgtSid},
  7026. {DOMAIN_GROUP_RID_ADMINS, WinAccountDomainAdminsSid},
  7027. {DOMAIN_GROUP_RID_USERS, WinAccountDomainUsersSid},
  7028. {DOMAIN_GROUP_RID_GUESTS, WinAccountDomainGuestsSid},
  7029. {DOMAIN_GROUP_RID_COMPUTERS, WinAccountComputersSid},
  7030. {DOMAIN_GROUP_RID_CONTROLLERS, WinAccountControllersSid},
  7031. {DOMAIN_GROUP_RID_CERT_ADMINS, WinAccountCertAdminsSid},
  7032. {DOMAIN_GROUP_RID_SCHEMA_ADMINS, WinAccountSchemaAdminsSid},
  7033. {DOMAIN_GROUP_RID_ENTERPRISE_ADMINS, WinAccountEnterpriseAdminsSid},
  7034. {DOMAIN_GROUP_RID_POLICY_ADMINS, WinAccountPolicyAdminsSid},
  7035. {DOMAIN_ALIAS_RID_RAS_SERVERS, WinAccountRasAndIasServersSid},
  7036. };
  7037. WELL_KNOWN_RID_ARRAY SecurityPackageSids[] =
  7038. {
  7039. {SECURITY_PACKAGE_NTLM_RID, WinNTLMAuthenticationSid},
  7040. {SECURITY_PACKAGE_DIGEST_RID, WinDigestAuthenticationSid},
  7041. {SECURITY_PACKAGE_SCHANNEL_RID, WinSChannelAuthenticationSid},
  7042. };
  7043. typedef struct
  7044. {
  7045. SID_IDENTIFIER_AUTHORITY Authority;
  7046. WELL_KNOWN_RID_ARRAY* WellKnownRids;
  7047. ULONG Count;
  7048. } WELL_KNOWN_AUTHORITIES_TYPE;
  7049. //
  7050. // WARNING! Do not change the numbering here without changing the order
  7051. // of the KnownAuthoritiesAndDomains table. There should never be a reason
  7052. // to change the ordering.
  7053. //
  7054. #define AUTHORITY_INDEX_START 0
  7055. #define NULL_AUTHORITY_INDEX 0
  7056. #define WORLD_AUTHORITY_INDEX 1
  7057. #define LOCAL_AUTHORITY_INDEX 2
  7058. #define CREATOR_OWNER_AUTHORITY_INDEX 3
  7059. #define NT_AUTHORITY_INDEX 4
  7060. #define AUTHORITY_INDEX_SENTINEL 5
  7061. #define BUILTIN_DOMAIN_INDEX 5
  7062. #define ACCOUNT_DOMAIN_INDEX 6
  7063. #define SECURITY_PACKAGE_INDEX 7
  7064. WELL_KNOWN_AUTHORITIES_TYPE KnownAuthoritiesAndDomains[] =
  7065. {
  7066. {SECURITY_NULL_SID_AUTHORITY, NullAuthoritySids, NELEMENTS(NullAuthoritySids)},
  7067. {SECURITY_WORLD_SID_AUTHORITY, WorldAuthoritySids, NELEMENTS(WorldAuthoritySids)},
  7068. {SECURITY_LOCAL_SID_AUTHORITY, LocalAuthoritySids, NELEMENTS(LocalAuthoritySids)},
  7069. {SECURITY_CREATOR_SID_AUTHORITY, CreatorOwnerAuthoritySids, NELEMENTS(CreatorOwnerAuthoritySids)},
  7070. {SECURITY_NT_AUTHORITY, NtAuthoritySids, NELEMENTS(NtAuthoritySids)},
  7071. {SECURITY_NT_AUTHORITY, BuiltinDomainSids, NELEMENTS(BuiltinDomainSids)},
  7072. {SECURITY_NT_AUTHORITY, AccountDomainSids, NELEMENTS(AccountDomainSids)},
  7073. {SECURITY_NT_AUTHORITY, SecurityPackageSids, NELEMENTS(SecurityPackageSids)},
  7074. };
  7075. WINADVAPI
  7076. BOOL
  7077. WINAPI
  7078. IsWellKnownSid (
  7079. IN PSID pSid,
  7080. IN WELL_KNOWN_SID_TYPE WellKnownSidType
  7081. )
  7082. /*++
  7083. Routine Description:
  7084. This routine determines is pSID is the well known SID specified.
  7085. It is purely runtime routine (that is, it makes no network or kernel
  7086. calls).
  7087. Parameters:
  7088. pSid -- the SID to inspect
  7089. WellKnownSidType - the well known SID to check for
  7090. Return Values
  7091. TRUE is the SID matches the well known SID,
  7092. FALSE otherwise
  7093. --*/
  7094. {
  7095. ULONG i;
  7096. BOOL fFound = FALSE;
  7097. WELL_KNOWN_SID_TYPE Type;
  7098. SID_IDENTIFIER_AUTHORITY *pAuthority = NULL;
  7099. WELL_KNOWN_RID_ARRAY *RidArray = NULL;
  7100. UCHAR SubAuthCount = 0;
  7101. ULONG RidArrayCount;
  7102. #define IS_EQUAL_AUTHORITY(x, y) \
  7103. RtlEqualMemory((x),(y),sizeof(SID_IDENTIFIER_AUTHORITY))
  7104. //
  7105. // Guard against bad parameters
  7106. //
  7107. if (!RtlValidSid(pSid)) {
  7108. return FALSE;
  7109. }
  7110. pAuthority = GetSidIdentifierAuthority(pSid);
  7111. if (NULL == pAuthority) {
  7112. return FALSE;
  7113. }
  7114. SubAuthCount = *RtlSubAuthorityCountSid(pSid);
  7115. if (SubAuthCount == 0) {
  7116. //
  7117. // Only one such known sid -- the Nt Authority domain sid has no
  7118. // sub auth's
  7119. //
  7120. if ( IS_EQUAL_AUTHORITY(pAuthority,
  7121. &KnownAuthoritiesAndDomains[NT_AUTHORITY_INDEX].Authority) ) {
  7122. fFound = TRUE;
  7123. Type = WinNtAuthoritySid;
  7124. }
  7125. } else if (SubAuthCount == 1) {
  7126. //
  7127. // Try the known authorities that aren't domains
  7128. //
  7129. for ( i = AUTHORITY_INDEX_START; i < AUTHORITY_INDEX_SENTINEL; i++) {
  7130. if (IS_EQUAL_AUTHORITY(pAuthority,
  7131. &KnownAuthoritiesAndDomains[i].Authority)) {
  7132. RidArray = KnownAuthoritiesAndDomains[i].WellKnownRids;
  7133. RidArrayCount = KnownAuthoritiesAndDomains[i].Count;
  7134. break;
  7135. }
  7136. }
  7137. } else if (SubAuthCount > 1) {
  7138. //
  7139. // Try the domains (builtin and account)
  7140. //
  7141. if ( IS_EQUAL_AUTHORITY(pAuthority,
  7142. &KnownAuthoritiesAndDomains[NT_AUTHORITY_INDEX].Authority) ) {
  7143. ULONG FirstSubAuth = *RtlSubAuthoritySid(pSid, 0);
  7144. if ( (FirstSubAuth == SECURITY_BUILTIN_DOMAIN_RID)
  7145. && (SubAuthCount == 2) ) {
  7146. // Builtin domain sids always have 2 sub auth's: the builtin
  7147. // RID and the principal RID
  7148. RidArray = BuiltinDomainSids;
  7149. RidArrayCount = NELEMENTS(BuiltinDomainSids);
  7150. } else if ((FirstSubAuth == SECURITY_NT_NON_UNIQUE)
  7151. && (SubAuthCount == SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT+2)){
  7152. // These account domains have
  7153. // 1 subauth for the SECURITY_NT_NON_UNIQUE,
  7154. // 1 for the principal and
  7155. // SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT for the domain portion
  7156. RidArray = AccountDomainSids;
  7157. RidArrayCount = NELEMENTS(AccountDomainSids);
  7158. } else if ( (FirstSubAuth == SECURITY_LOGON_IDS_RID)
  7159. && (SubAuthCount == SECURITY_LOGON_IDS_RID_COUNT)) {
  7160. //
  7161. // This is the special LogonId sid S-1-5-5-X-Y
  7162. //
  7163. fFound = TRUE;
  7164. Type = WinLogonIdsSid;
  7165. } else if ( (FirstSubAuth == SECURITY_PACKAGE_BASE_RID)
  7166. && (SubAuthCount == SECURITY_PACKAGE_RID_COUNT)) {
  7167. //
  7168. // This is the special security package sid S-1-5-0x40-X
  7169. //
  7170. RidArray = SecurityPackageSids;
  7171. RidArrayCount = NELEMENTS(SecurityPackageSids);
  7172. }
  7173. }
  7174. }
  7175. //
  7176. // If we matched for authority or domain, try to match RID
  7177. //
  7178. if ( RidArray ) {
  7179. ULONG Rid;
  7180. ASSERT(SubAuthCount > 0);
  7181. Rid = *RtlSubAuthoritySid(pSid, SubAuthCount - 1);
  7182. for (i = 0; i < RidArrayCount; i++) {
  7183. if (Rid == RidArray[i].Rid) {
  7184. fFound = TRUE;
  7185. Type = RidArray[i].Type;
  7186. break;
  7187. }
  7188. }
  7189. }
  7190. if (fFound && (Type == WellKnownSidType)) {
  7191. fFound = TRUE;
  7192. } else {
  7193. fFound = FALSE;
  7194. }
  7195. return fFound;
  7196. }
  7197. WINADVAPI
  7198. BOOL
  7199. WINAPI
  7200. CreateWellKnownSid(
  7201. IN WELL_KNOWN_SID_TYPE WellKnownSidType,
  7202. IN PSID pDomainSid OPTIONAL,
  7203. OUT PSID pSid,
  7204. IN OUT DWORD *cbSid
  7205. )
  7206. /*++
  7207. Routine Description:
  7208. This routines creates the SID of a well known principal.
  7209. Parameters:
  7210. WellKnownSidType - the well known account sid that the caller desires
  7211. pDomainSid - if the WellKnownSidType is an SID from an Account domain, this
  7212. value can be set; if not set and the WellKnownSidType is from
  7213. an Account domain, error STATUS_INVALID_PARAMETER is returned.
  7214. If the WellKnownSidType is not from an Account domain, this
  7215. parameter is ignored.
  7216. pSID - a client allocated buffer
  7217. cbSid - the number of bytes pointed to by pSID
  7218. Return Values
  7219. TRUE if WellKnownSidType is understood and pSID points to a buffer large
  7220. enough to hold the SID
  7221. FALSE otherwise
  7222. --*/
  7223. {
  7224. BOOL fFound = FALSE;
  7225. ULONG Rid;
  7226. ULONG i, j;
  7227. ULONG SizeRequired;
  7228. NTSTATUS Status;
  7229. UCHAR SubAuthCount;
  7230. if (pDomainSid && !RtlValidSid(pDomainSid)) {
  7231. SetLastError(ERROR_INVALID_PARAMETER);
  7232. return FALSE;
  7233. }
  7234. if (IsBadWritePtr(cbSid, sizeof(*cbSid))) {
  7235. SetLastError(ERROR_INVALID_PARAMETER);
  7236. return FALSE;
  7237. }
  7238. // special case -- can't create this one
  7239. if (WinLogonIdsSid == WellKnownSidType) {
  7240. SetLastError(ERROR_INVALID_PARAMETER);
  7241. return FALSE;
  7242. }
  7243. //
  7244. // Find the requested type
  7245. //
  7246. for (i = 0; i < NELEMENTS(KnownAuthoritiesAndDomains); i++) {
  7247. for (j = 0; j < KnownAuthoritiesAndDomains[i].Count; j++) {
  7248. if (WellKnownSidType == KnownAuthoritiesAndDomains[i].WellKnownRids[j].Type){
  7249. Rid = KnownAuthoritiesAndDomains[i].WellKnownRids[j].Rid;
  7250. fFound = TRUE;
  7251. break;
  7252. }
  7253. }
  7254. if (fFound) {
  7255. break;
  7256. }
  7257. }
  7258. // special case since the NtAuthority domain doesn't have any sub auth's
  7259. if (!fFound && (WellKnownSidType == WinNtAuthoritySid)) {
  7260. i = NT_AUTHORITY_INDEX;
  7261. fFound = TRUE;
  7262. }
  7263. if (!fFound) {
  7264. SetLastError(ERROR_INVALID_PARAMETER);
  7265. return FALSE;
  7266. }
  7267. //
  7268. // Determine how much space we need
  7269. //
  7270. switch (i) {
  7271. case NULL_AUTHORITY_INDEX:
  7272. case WORLD_AUTHORITY_INDEX:
  7273. case LOCAL_AUTHORITY_INDEX:
  7274. case CREATOR_OWNER_AUTHORITY_INDEX:
  7275. case NT_AUTHORITY_INDEX:
  7276. if (WellKnownSidType == WinNtAuthoritySid) {
  7277. SubAuthCount = 0;
  7278. } else {
  7279. SubAuthCount = 1;
  7280. }
  7281. break;
  7282. case SECURITY_PACKAGE_INDEX:
  7283. SubAuthCount = SECURITY_PACKAGE_RID_COUNT;
  7284. break;
  7285. case BUILTIN_DOMAIN_INDEX:
  7286. SubAuthCount = 2;
  7287. break;
  7288. case ACCOUNT_DOMAIN_INDEX:
  7289. if (NULL == pDomainSid) {
  7290. SetLastError(ERROR_INVALID_PARAMETER);
  7291. return FALSE;
  7292. }
  7293. SubAuthCount = *RtlSubAuthorityCountSid(pDomainSid);
  7294. if (SubAuthCount == SID_MAX_SUB_AUTHORITIES) {
  7295. SetLastError(ERROR_INVALID_PARAMETER);
  7296. return FALSE;
  7297. }
  7298. // Add for the RID
  7299. SubAuthCount++;
  7300. break;
  7301. default:
  7302. ASSERT(!"Invalid index");
  7303. }
  7304. //
  7305. // Make sure we have enough space
  7306. //
  7307. SizeRequired = GetSidLengthRequired(SubAuthCount);
  7308. if (*cbSid < SizeRequired) {
  7309. *cbSid = SizeRequired;
  7310. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  7311. return FALSE;
  7312. }
  7313. *cbSid = SizeRequired;
  7314. if (IsBadWritePtr(pSid, SizeRequired)) {
  7315. SetLastError(ERROR_INVALID_PARAMETER);
  7316. return FALSE;
  7317. }
  7318. //
  7319. // Fill the sid in
  7320. //
  7321. switch (i) {
  7322. case ACCOUNT_DOMAIN_INDEX:
  7323. Status = RtlCopySid(*cbSid, pSid, pDomainSid);
  7324. if (NT_SUCCESS(Status)) {
  7325. (*RtlSubAuthorityCountSid(pSid))++;
  7326. }
  7327. break;
  7328. case BUILTIN_DOMAIN_INDEX:
  7329. case NULL_AUTHORITY_INDEX:
  7330. case WORLD_AUTHORITY_INDEX:
  7331. case LOCAL_AUTHORITY_INDEX:
  7332. case CREATOR_OWNER_AUTHORITY_INDEX:
  7333. case NT_AUTHORITY_INDEX:
  7334. case SECURITY_PACKAGE_INDEX:
  7335. Status = RtlInitializeSid(pSid,
  7336. &KnownAuthoritiesAndDomains[i].Authority,
  7337. SubAuthCount);
  7338. if (NT_SUCCESS(Status)) {
  7339. if (i == BUILTIN_DOMAIN_INDEX) {
  7340. ASSERT(SubAuthCount > 1);
  7341. *RtlSubAuthoritySid(pSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
  7342. } else if (i == SECURITY_PACKAGE_INDEX) {
  7343. ASSERT(SubAuthCount == 2);
  7344. *RtlSubAuthoritySid(pSid, 0) = SECURITY_PACKAGE_BASE_RID;
  7345. }
  7346. }
  7347. break;
  7348. default:
  7349. ASSERT(!"Invalid index");
  7350. }
  7351. if (!NT_SUCCESS(Status)) {
  7352. BaseSetLastNTError(Status);
  7353. return FALSE;
  7354. }
  7355. //
  7356. // Append the Rid
  7357. //
  7358. if (SubAuthCount > 0) {
  7359. *RtlSubAuthoritySid(pSid, SubAuthCount-1) = Rid;
  7360. }
  7361. return TRUE;
  7362. }
  7363. WINADVAPI
  7364. BOOL
  7365. WINAPI
  7366. GetWindowsAccountDomainSid(
  7367. IN PSID pSid,
  7368. IN OUT PSID pDomainSid OPTIONAL,
  7369. OUT DWORD* cbDomainSid
  7370. )
  7371. /*++
  7372. Routine Description:
  7373. This routine returns the domain portion of pSid, if any if the SID is
  7374. from an account domain. If the SID is not from an account domain, then
  7375. ERROR_NON_ACCOUNT_SID is returned.
  7376. Parameters:
  7377. pSid -- the SID from which to extract the domain portion
  7378. pDomainSid -- the domain portion of pSid; caller must allocate buffer
  7379. cbDomainSid -- the number of bytes pointed to by pDomainSid; if
  7380. insufficient, this value will be set to the number of
  7381. bytes required.
  7382. Return Values
  7383. TRUE if a domain portion could be extracted and placed into pDomainSid
  7384. FALSE otherwise; win32 errors are
  7385. ERROR_INVALID_SID
  7386. ERROR_INVALID_PARAMETER
  7387. ERROR_NON_ACCOUNT_SID
  7388. ERROR_INSUFFICIENT_BUFFER
  7389. --*/
  7390. {
  7391. NTSTATUS Status;
  7392. ULONG SizeRequired;
  7393. UCHAR SubAuthCount;
  7394. UCHAR DomainSubAuthCount = 0;
  7395. BOOL fRecognized = FALSE;
  7396. ULONG i;
  7397. if (!RtlValidSid(pSid)) {
  7398. SetLastError(ERROR_INVALID_SID);
  7399. return FALSE;
  7400. }
  7401. if (cbDomainSid == NULL) {
  7402. SetLastError(ERROR_INVALID_PARAMETER);
  7403. return FALSE;
  7404. }
  7405. if ( IS_EQUAL_AUTHORITY(RtlIdentifierAuthoritySid(pSid),
  7406. &KnownAuthoritiesAndDomains[NT_AUTHORITY_INDEX].Authority)) {
  7407. SubAuthCount = *RtlSubAuthorityCountSid(pSid);
  7408. if (SubAuthCount > SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT) {
  7409. ULONG FirstSubAuth;
  7410. FirstSubAuth = *RtlSubAuthoritySid(pSid, 0);
  7411. if ( (SECURITY_NT_NON_UNIQUE == FirstSubAuth) ) {
  7412. // This is an NT Account Domain
  7413. DomainSubAuthCount = SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT+1;
  7414. fRecognized = TRUE;
  7415. }
  7416. }
  7417. }
  7418. if (!fRecognized) {
  7419. SetLastError(ERROR_NON_ACCOUNT_SID);
  7420. return FALSE;
  7421. }
  7422. SizeRequired = RtlLengthRequiredSid(DomainSubAuthCount);
  7423. if (*cbDomainSid < SizeRequired) {
  7424. *cbDomainSid = SizeRequired;
  7425. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  7426. return FALSE;
  7427. }
  7428. *cbDomainSid = SizeRequired;
  7429. if (IsBadWritePtr(pDomainSid, SizeRequired)) {
  7430. SetLastError(ERROR_INVALID_PARAMETER);
  7431. return FALSE;
  7432. }
  7433. Status = RtlInitializeSid(pDomainSid,
  7434. RtlIdentifierAuthoritySid(pSid),
  7435. DomainSubAuthCount);
  7436. if (!NT_SUCCESS(Status)) {
  7437. BaseSetLastNTError(Status);
  7438. return FALSE;
  7439. }
  7440. for (i = 0; i < DomainSubAuthCount; i++) {
  7441. *RtlSubAuthoritySid(pDomainSid, i) = *RtlSubAuthoritySid(pSid,i);
  7442. }
  7443. return TRUE;
  7444. }
  7445. WINADVAPI
  7446. BOOL
  7447. WINAPI
  7448. EqualDomainSid(
  7449. IN PSID pSid1,
  7450. IN PSID pSid2,
  7451. OUT BOOL *pfEqual
  7452. )
  7453. /*++
  7454. Routine Description:
  7455. This routine determines if either
  7456. 1) Both sids are the same domain SID
  7457. 2) One SID is from the other SID's domain
  7458. The "domains" recognized are BUILTIN and NT account domains
  7459. Parameters:
  7460. pSid1 -- the first SID
  7461. pSid2 -- the second SID
  7462. pfEqual -- on success, set to TRUE if the domain portions are equal
  7463. Return Values
  7464. TRUE if the SID's are recognized (are either from an account domain or
  7465. the BUILTIN domain).
  7466. FALSE otherwise
  7467. Win32 Errors:
  7468. ERROR_NON_DOMAIN_SID
  7469. ERROR_REVISION_MISMATCH
  7470. ERROR_INVALID_PARAMETER
  7471. ERROR_INVALID_SID
  7472. --*/
  7473. {
  7474. ULONG i;
  7475. SID *ISid1 = pSid1;
  7476. SID *ISid2 = pSid2;
  7477. BYTE Buffer1[SECURITY_MAX_SID_SIZE];
  7478. PSID BuiltinDomainSid = (PSID) Buffer1;
  7479. BYTE Buffer2[SECURITY_MAX_SID_SIZE];
  7480. PSID pDomainSid1 = (PSID) Buffer2;
  7481. BYTE Buffer3[SECURITY_MAX_SID_SIZE];
  7482. PSID pDomainSid2 = (PSID) Buffer3;
  7483. ULONG Size;
  7484. if ( !RtlValidSid(pSid1) || !RtlValidSid(pSid2) ) {
  7485. SetLastError(ERROR_INVALID_SID);
  7486. return FALSE;
  7487. }
  7488. if (NULL == pfEqual) {
  7489. SetLastError(ERROR_INVALID_PARAMETER);
  7490. return FALSE;
  7491. }
  7492. if ( ISid1->Revision != ISid2->Revision ) {
  7493. SetLastError(ERROR_REVISION_MISMATCH);
  7494. return FALSE;
  7495. }
  7496. // Create the builtin SID
  7497. Size = sizeof(Buffer1);
  7498. if (!CreateWellKnownSid(WinBuiltinDomainSid, NULL, BuiltinDomainSid, &Size)) {
  7499. // LastError is set
  7500. return FALSE;
  7501. }
  7502. // Extract the first SID's domain portion if any
  7503. Size = sizeof(Buffer2);
  7504. if (!GetWindowsAccountDomainSid(pSid1, pDomainSid1, &Size)) {
  7505. // The SID is not an account domain SID -- try for builtin
  7506. pDomainSid1 = NULL;
  7507. if ( (IS_EQUAL_AUTHORITY(RtlIdentifierAuthoritySid(pSid1), &KnownAuthoritiesAndDomains[NT_AUTHORITY_INDEX].Authority))
  7508. && (*RtlSubAuthorityCountSid(pSid1) > 0)
  7509. && (*RtlSubAuthoritySid(pSid1, 0) == SECURITY_BUILTIN_DOMAIN_RID)) {
  7510. pDomainSid1 = BuiltinDomainSid;
  7511. }
  7512. }
  7513. if (NULL == pDomainSid1) {
  7514. SetLastError(ERROR_NON_DOMAIN_SID);
  7515. return FALSE;
  7516. }
  7517. Size = sizeof(Buffer3);
  7518. if (!GetWindowsAccountDomainSid(pSid2, pDomainSid2, &Size)) {
  7519. // The SID is not an account domain SID -- try for builtin
  7520. pDomainSid2 = NULL;
  7521. if ( (IS_EQUAL_AUTHORITY(RtlIdentifierAuthoritySid(pSid2), &KnownAuthoritiesAndDomains[NT_AUTHORITY_INDEX].Authority))
  7522. && (*RtlSubAuthorityCountSid(pSid2) > 0)
  7523. && (*RtlSubAuthoritySid(pSid2, 0) == SECURITY_BUILTIN_DOMAIN_RID)) {
  7524. pDomainSid2 = BuiltinDomainSid;
  7525. }
  7526. }
  7527. if (NULL == pDomainSid2) {
  7528. SetLastError(ERROR_NON_DOMAIN_SID);
  7529. return FALSE;
  7530. }
  7531. *pfEqual = EqualSid(pDomainSid1, pDomainSid2);
  7532. return TRUE;
  7533. }