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

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