Windows NT 4.0 source code leak
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.

6581 lines
161 KiB

4 years ago
  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. DuplicateTokenEx(
  67. HANDLE hExistingToken,
  68. DWORD dwDesiredAccess,
  69. LPSECURITY_ATTRIBUTES lpTokenAttributes,
  70. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
  71. TOKEN_TYPE TokenType,
  72. PHANDLE phNewToken)
  73. /*++
  74. Routine Description:
  75. Create a new token that is a duplicate of an existing token. This API
  76. more fully exposes NtDuplicateToken .
  77. Arguments:
  78. hExistingToken - Is a handle to a token already open for
  79. TOKEN_DUPLICATE access.
  80. dwDesiredAccess - desired access rights to the new token, e.g.
  81. TOKEN_DUPLICATE, TOKEN_IMPERSONATE, etc.
  82. lpTokenAttributes - Desired security attributes for the new token.
  83. ImpersonationLevel - Supplies the impersonation level of the new token.
  84. TokenType - One of TokenImpersonation or TokenPrimary.
  85. phNewToken - Returns the handle to the new token.
  86. Return Value:
  87. Returns TRUE for success, FALSE for failure. Extended error status
  88. is available using GetLastError.
  89. --*/
  90. {
  91. OBJECT_ATTRIBUTES ObjA;
  92. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  93. PSECURITY_DESCRIPTOR SecurityDescriptor;
  94. NTSTATUS Status;
  95. ULONG Attributes;
  96. SecurityQualityOfService.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  97. SecurityQualityOfService.ImpersonationLevel = ImpersonationLevel;
  98. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  99. SecurityQualityOfService.EffectiveOnly = FALSE;
  100. if (lpTokenAttributes)
  101. {
  102. SecurityDescriptor = lpTokenAttributes->lpSecurityDescriptor;
  103. if (lpTokenAttributes->bInheritHandle)
  104. {
  105. Attributes = OBJ_INHERIT;
  106. }
  107. else
  108. {
  109. Attributes = 0;
  110. }
  111. }
  112. else
  113. {
  114. SecurityDescriptor = NULL;
  115. Attributes = 0;
  116. }
  117. InitializeObjectAttributes(
  118. &ObjA,
  119. NULL,
  120. Attributes,
  121. NULL,
  122. SecurityDescriptor
  123. );
  124. ObjA.SecurityQualityOfService = &SecurityQualityOfService;
  125. Status = NtDuplicateToken(
  126. hExistingToken,
  127. dwDesiredAccess,
  128. &ObjA,
  129. FALSE,
  130. TokenType,
  131. phNewToken
  132. );
  133. if ( !NT_SUCCESS( Status ) ) {
  134. BaseSetLastNTError(Status);
  135. return FALSE;
  136. }
  137. return( TRUE );
  138. }
  139. BOOL
  140. APIENTRY
  141. AllocateLocallyUniqueId(
  142. PLUID Luid
  143. )
  144. /*++
  145. Routine Description:
  146. Allocates a locally unique ID (LUID).
  147. Arguments:
  148. Luid - Supplies a pointer used to return the LUID.
  149. Return Value:
  150. Returns TRUE for success, FALSE for failure. Extended error status
  151. is available using GetLastError.
  152. --*/
  153. { NTSTATUS Status;
  154. Status = NtAllocateLocallyUniqueId( Luid );
  155. if ( !NT_SUCCESS( Status )) {
  156. BaseSetLastNTError( Status );
  157. return( FALSE );
  158. }
  159. return( TRUE );
  160. }
  161. BOOL
  162. APIENTRY
  163. AccessCheck (
  164. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  165. HANDLE ClientToken,
  166. DWORD DesiredAccess,
  167. PGENERIC_MAPPING GenericMapping,
  168. PPRIVILEGE_SET PrivilegeSet,
  169. LPDWORD PrivilegeSetLength,
  170. LPDWORD GrantedAccess,
  171. LPBOOL AccessStatus
  172. )
  173. /*++
  174. Routine Description:
  175. This routine compares the input Security Descriptor against the
  176. input token and indicates by its return value if access is granted
  177. or denied. If access is granted then the desired access mask
  178. becomes the granted access mask for the object.
  179. The semantics of the access check routine is described in the DSA
  180. Security Architecture workbook. Note that during an access check
  181. only the discretionary ACL is examined.
  182. Arguments:
  183. SecurityDescriptor - Supplies the security descriptor protecting the object
  184. being accessed
  185. ClientToken - Supplies the handle of the user's token.
  186. DesiredAccess - Supplies the desired access mask.
  187. GenericMapping - Supplies the generic mapping associated with this
  188. object type.
  189. PrivilegeSet - A pointer to a buffer that upon return will contain
  190. any privileges that were used to perform the access validation.
  191. If no privileges were used, the buffer will contain a privilege
  192. set consisting of zero privileges.
  193. PrivilegeSetLength - The size of the PrivilegeSet buffer in bytes.
  194. GrantedAccess - Returns an access mask describing the granted access.
  195. AccessStatus - Status value that may be returned indicating the
  196. reason why access was denied. Routines should avoid hardcoding a
  197. return value of STATUS_ACCESS_DENIED so that a different value can
  198. be returned when mandatory access control is implemented.
  199. Return Value:
  200. Returns TRUE for success, FALSE for failure. Extended error status
  201. is available using GetLastError.
  202. --*/
  203. {
  204. NTSTATUS Status;
  205. NTSTATUS RealStatus;
  206. Status = NtAccessCheck (
  207. pSecurityDescriptor,
  208. ClientToken,
  209. DesiredAccess,
  210. GenericMapping,
  211. PrivilegeSet,
  212. PrivilegeSetLength,
  213. GrantedAccess,
  214. &RealStatus
  215. );
  216. if ( !NT_SUCCESS(Status) ) {
  217. BaseSetLastNTError(Status);
  218. return FALSE;
  219. }
  220. if ( !NT_SUCCESS( RealStatus ) ) {
  221. BaseSetLastNTError( RealStatus );
  222. *AccessStatus = FALSE;
  223. return( TRUE );
  224. }
  225. *AccessStatus = TRUE;
  226. return TRUE;
  227. }
  228. BOOL
  229. APIENTRY
  230. OpenProcessToken (
  231. HANDLE ProcessHandle,
  232. DWORD DesiredAccess,
  233. PHANDLE TokenHandle
  234. )
  235. /*++
  236. Routine Description:
  237. Open a token object associated with a process and return a handle
  238. that may be used to access that token.
  239. Arguments:
  240. ProcessHandle - Specifies the process whose token is to be
  241. opened.
  242. DesiredAccess - Is an access mask indicating which access types
  243. are desired to the token. These access types are reconciled
  244. with the Discretionary Access Control list of the token to
  245. determine whether the accesses will be granted or denied.
  246. TokenHandle - Receives the handle of the newly opened token.
  247. Return Value:
  248. Returns TRUE for success, FALSE for failure. Extended error status
  249. is available using GetLastError.
  250. --*/
  251. {
  252. NTSTATUS Status;
  253. Status = NtOpenProcessToken (
  254. ProcessHandle,
  255. DesiredAccess,
  256. TokenHandle
  257. );
  258. if ( !NT_SUCCESS(Status) ) {
  259. BaseSetLastNTError(Status);
  260. return FALSE;
  261. }
  262. return TRUE;
  263. }
  264. BOOL
  265. APIENTRY
  266. OpenThreadToken (
  267. HANDLE ThreadHandle,
  268. DWORD DesiredAccess,
  269. BOOL OpenAsSelf,
  270. PHANDLE TokenHandle
  271. )
  272. /*++
  273. Routine Description:
  274. Open a token object associated with a thread and return a handle that
  275. may be used to access that token.
  276. Arguments:
  277. ThreadHandle - Specifies the thread whose token is to be opened.
  278. DesiredAccess - Is an access mask indicating which access types
  279. are desired to the token. These access types are reconciled
  280. with the Discretionary Access Control list of the token to
  281. determine whether the accesses will be granted or denied.
  282. OpenAsSelf - Is a boolean value indicating whether the access should
  283. be made using the calling thread's current security context, which
  284. may be that of a client if impersonating, or using the caller's
  285. process-level security context. A value of FALSE indicates the
  286. caller's current context should be used un-modified. A value of
  287. TRUE indicates the request should be fulfilled using the process
  288. level security context.
  289. This parameter is necessary to allow a server process to open
  290. a client's token when the client specified IDENTIFICATION level
  291. impersonation. In this case, the caller would not be able to
  292. open the client's token using the client's context (because you
  293. can't create executive level objects using IDENTIFICATION level
  294. impersonation).
  295. TokenHandle - Receives the handle of the newly opened token.
  296. Return Value:
  297. Returns TRUE for success, FALSE for failure. Extended error status
  298. is available using GetLastError.
  299. --*/
  300. {
  301. NTSTATUS Status;
  302. Status = NtOpenThreadToken (
  303. ThreadHandle,
  304. DesiredAccess,
  305. (BOOLEAN)OpenAsSelf,
  306. TokenHandle
  307. );
  308. if ( !NT_SUCCESS(Status) ) {
  309. BaseSetLastNTError(Status);
  310. return FALSE;
  311. }
  312. return TRUE;
  313. }
  314. BOOL
  315. APIENTRY
  316. GetTokenInformation (
  317. HANDLE TokenHandle,
  318. TOKEN_INFORMATION_CLASS TokenInformationClass,
  319. PVOID TokenInformation,
  320. DWORD TokenInformationLength,
  321. PDWORD ReturnLength
  322. )
  323. /*++
  324. Routine Description:
  325. Retrieve information about a specified token.
  326. Arguments:
  327. TokenHandle - Provides a handle to the token to operate on.
  328. TokenInformationClass - The token information class about which
  329. to retrieve information.
  330. TokenInformation - The buffer to receive the requested class of
  331. information. The buffer must be aligned on at least a
  332. longword boundary. The actual structures returned are
  333. dependent upon the information class requested, as defined in
  334. the TokenInformationClass parameter description.
  335. TokenInformation Format By Information Class:
  336. TokenUser => TOKEN_USER data structure. TOKEN_QUERY
  337. access is needed to retrieve this information about a
  338. token.
  339. TokenGroups => TOKEN_GROUPS data structure. TOKEN_QUERY
  340. access is needed to retrieve this information about a
  341. token.
  342. TokenPrivileges => TOKEN_PRIVILEGES data structure.
  343. TOKEN_QUERY access is needed to retrieve this information
  344. about a token.
  345. TokenOwner => TOKEN_OWNER data structure. TOKEN_QUERY
  346. access is needed to retrieve this information about a
  347. token.
  348. TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure.
  349. TOKEN_QUERY access is needed to retrieve this information
  350. about a token.
  351. TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure.
  352. TOKEN_QUERY access is needed to retrieve this information
  353. about a token.
  354. TokenSource => TOKEN_SOURCE data structure.
  355. TOKEN_QUERY_SOURCE access is needed to retrieve this
  356. information about a token.
  357. TokenType => TOKEN_TYPE data structure.
  358. TOKEN_QUERY access is needed to retrieve this information
  359. about a token.
  360. TokenStatistics => TOKEN_STATISTICS data structure.
  361. TOKEN_QUERY access is needed to retrieve this
  362. information about a token.
  363. TokenInformationLength - Indicates the length, in bytes, of the
  364. TokenInformation buffer.
  365. ReturnLength - This parameter receives the actual length of the
  366. requested information. If this value is larger than that
  367. provided by the TokenInformationLength parameter, then the
  368. buffer provided to receive the requested information is not
  369. large enough to hold that data and no data is returned.
  370. If the queried class is TokenDefaultDacl and there is no
  371. default Dacl established for the token, then the return
  372. length will be returned as zero, and no data will be returned.
  373. Return Value:
  374. Returns TRUE for success, FALSE for failure. Extended error status
  375. is available using GetLastError.
  376. --*/
  377. {
  378. NTSTATUS Status;
  379. Status = NtQueryInformationToken (
  380. TokenHandle,
  381. TokenInformationClass,
  382. TokenInformation,
  383. TokenInformationLength,
  384. ReturnLength
  385. );
  386. if ( !NT_SUCCESS(Status) ) {
  387. BaseSetLastNTError(Status);
  388. return FALSE;
  389. }
  390. return TRUE;
  391. }
  392. BOOL
  393. APIENTRY
  394. SetTokenInformation (
  395. HANDLE TokenHandle,
  396. TOKEN_INFORMATION_CLASS TokenInformationClass,
  397. PVOID TokenInformation,
  398. DWORD TokenInformationLength
  399. )
  400. /*++
  401. Routine Description:
  402. Modify information in a specified token.
  403. Arguments:
  404. TokenHandle - Provides a handle to the token to operate on.
  405. TokenInformationClass - The token information class being set.
  406. TokenInformation - The buffer containing the new values for the
  407. specified class of information. The buffer must be aligned
  408. on at least a longword boundary. The actual structures
  409. provided are dependent upon the information class specified,
  410. as defined in the TokenInformationClass parameter
  411. description.
  412. TokenInformation Format By Information Class:
  413. TokenUser => This value is not a valid value for this API.
  414. The User ID may not be replaced.
  415. TokenGroups => This value is not a valid value for this
  416. API. The Group IDs may not be replaced. However, groups
  417. may be enabled and disabled using NtAdjustGroupsToken().
  418. TokenPrivileges => This value is not a valid value for
  419. this API. Privilege information may not be replaced.
  420. However, privileges may be explicitly enabled and disabled
  421. using the NtAdjustPrivilegesToken API.
  422. TokenOwner => TOKEN_OWNER data structure.
  423. TOKEN_ADJUST_DEFAULT access is needed to replace this
  424. information in a token. The owner values that may be
  425. specified are restricted to the user and group IDs with an
  426. attribute indicating they may be assigned as the owner of
  427. objects.
  428. TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure.
  429. TOKEN_ADJUST_DEFAULT access is needed to replace this
  430. information in a token. The primary group values that may
  431. be specified are restricted to be one of the group IDs
  432. already in the token.
  433. TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure.
  434. TOKEN_ADJUST_DEFAULT access is needed to replace this
  435. information in a token. The ACL provided as a new default
  436. discretionary ACL is not validated for structural
  437. correctness or consistency.
  438. TokenSource => This value is not a valid value for this
  439. API. The source name and context handle may not be
  440. replaced.
  441. TokenStatistics => This value is not a valid value for this
  442. API. The statistics of a token are read-only.
  443. TokenInformationLength - Indicates the length, in bytes, of the
  444. TokenInformation buffer. This is only the length of the primary
  445. buffer. All extensions of the primary buffer are self describing.
  446. Return Value:
  447. Returns TRUE for success, FALSE for failure. Extended error status
  448. is available using GetLastError.
  449. --*/
  450. {
  451. NTSTATUS Status;
  452. Status = NtSetInformationToken (
  453. TokenHandle,
  454. TokenInformationClass,
  455. TokenInformation,
  456. TokenInformationLength
  457. );
  458. if ( !NT_SUCCESS(Status) ) {
  459. BaseSetLastNTError(Status);
  460. return FALSE;
  461. }
  462. return TRUE;
  463. }
  464. BOOL
  465. APIENTRY
  466. AdjustTokenPrivileges (
  467. HANDLE TokenHandle,
  468. BOOL DisableAllPrivileges,
  469. PTOKEN_PRIVILEGES NewState,
  470. DWORD BufferLength,
  471. PTOKEN_PRIVILEGES PreviousState,
  472. PDWORD ReturnLength
  473. )
  474. /*++
  475. Routine Description:
  476. This routine is used to disable or enable privileges in the
  477. specified token. The absence of some of the privileges listed to
  478. be changed won't effect the successful modification of the
  479. privileges that are in the token. The previous enabled/disabled
  480. state of changed privileges may optionally be capture (for
  481. resetting later).
  482. TOKEN_ADJUST_PRIVILEGES access is required to enable or disable
  483. privileges in a token.
  484. Arguments:
  485. TokenHandle - Provides a handle to the token to operate on.
  486. DisableAllPrivileges - This boolean parameter may be
  487. used to disable all privileges assigned to the token. If
  488. this parameter is specified as TRUE, then the NewState parameter is
  489. ignored.
  490. NewState - This (optional) parameter points to a TOKEN_PRIVILEGES
  491. data structure containing the privileges whose states are to
  492. be adjusted (disabled or enabled). Only the Enabled flag of
  493. the attributes associated with each privilege is used. It
  494. provides the new value that is to be assigned to the privilege
  495. in the token.
  496. BufferLength - This optional parameter indicates the length (in
  497. bytes) of the PreviousState buffer. This value must be
  498. provided if the PreviousState parameter is provided.
  499. PreviousState - This (optional) parameter points to a buffer to
  500. receive the state of any privileges actually changed by this
  501. request. This information is formated as a TOKEN_PRIVILEGES
  502. data structure which may be passed as the NewState parameter
  503. in a subsequent call to this routine to restore the original
  504. state of those privilges. TOKEN_QUERY access is needed to use
  505. this parameter.
  506. If this buffer does not contain enough space to receive the
  507. complete list of modified privileges, then no privilege
  508. states are changed and STATUS_BUFFER_TOO_SMALL is returned.
  509. In this case, the ReturnLength OUT parameter will
  510. contain the actual number of bytes needed to hold the
  511. information.
  512. ReturnLength - Indicates the actual number of bytes needed to
  513. contain the previous privilege state information. This
  514. parameter is ignored if the PreviousState argument is not
  515. passed.
  516. Return Value:
  517. Returns TRUE for success, FALSE for failure. Extended error status
  518. is available using GetLastError.
  519. --*/
  520. {
  521. NTSTATUS Status;
  522. Status = NtAdjustPrivilegesToken (
  523. TokenHandle,
  524. (BOOLEAN)DisableAllPrivileges,
  525. NewState,
  526. BufferLength,
  527. PreviousState,
  528. ReturnLength
  529. );
  530. //
  531. // We need to set last error even for success because that
  532. // is the only way to tell if the api successfully assigned
  533. // all privileges. That is, STATUS_NOT_ALL_ASSIGNED is a
  534. // Success severity level.
  535. //
  536. BaseSetLastNTError(Status);
  537. if ( !NT_SUCCESS(Status) ) {
  538. return FALSE;
  539. }
  540. return TRUE;
  541. }
  542. BOOL
  543. APIENTRY
  544. AdjustTokenGroups (
  545. HANDLE TokenHandle,
  546. BOOL ResetToDefault,
  547. PTOKEN_GROUPS NewState,
  548. DWORD BufferLength,
  549. PTOKEN_GROUPS PreviousState,
  550. PDWORD ReturnLength
  551. )
  552. /*++
  553. Routine Description:
  554. This routine is used to disable or enable groups in the specified
  555. token. The absence of some of the groups listed to be changed
  556. won't effect the successful modification of the groups that are in
  557. the token. The previous enabled/disabled state of changed groups
  558. may optionally be capture (for resetting later).
  559. TOKEN_ADJUST_GROUPS access is required to enable or disable groups
  560. in a token
  561. Note that mandatory groups can not be disabled. An attempt
  562. disable any mandatory groups will cause the call to fail, leaving
  563. the state of all groups unchanged.
  564. Arguments:
  565. TokenHandle - Provides a handle to the token to operate on.
  566. ResetToDefault - The parameter indicates whether all the groups
  567. in the token are to be reset to their default enabled/disabled
  568. state.
  569. NewState - This parameter points to a TOKEN_GROUPS data structure
  570. containing the groups whose states are to be adjusted
  571. (disabled or enabled). Only the Enabled flag of the
  572. attributes associated with each group is used. It provides
  573. the new value that is to be assigned to the group in the
  574. token. If the ResetToDefault argument is specified as TRUE,
  575. then this argument is ignored. Otherwise, it must be passed.
  576. BufferLength - This optional parameter indicates the length (in
  577. bytes) of the PreviousState buffer. This value must be
  578. provided if the PreviousState parameter is provided.
  579. PreviousState - This (optional) parameter points to a buffer to
  580. receive the state of any groups actually changed by this
  581. request. This information is formated as a TOKEN_GROUPS data
  582. structure which may be passed as the NewState parameter in a
  583. subsequent call to NtAdjustGroups to restore the original state
  584. of those groups. TOKEN_QUERY access is needed to use this
  585. parameter.
  586. If this buffer does not contain enough space to receive the
  587. complete list of modified groups, then no group states are
  588. changed and STATUS_BUFFER_TOO_SMALL is returned. In this
  589. case, the ReturnLength return parameter will contain the
  590. actual number of bytes needed to hold the information.
  591. ReturnLength - Indicates the actual number of bytes needed to
  592. contain the previous group state information.
  593. This parameter is ignored if the PreviousState argument is not
  594. passed.
  595. Return Value:
  596. Returns TRUE for success, FALSE for failure. Extended error status
  597. is available using GetLastError.
  598. --*/
  599. {
  600. NTSTATUS Status;
  601. Status = NtAdjustGroupsToken (
  602. TokenHandle,
  603. (BOOLEAN)ResetToDefault,
  604. NewState,
  605. BufferLength,
  606. PreviousState,
  607. ReturnLength
  608. );
  609. //
  610. // We need to set last error even for success because that
  611. // is the only way to tell if the api successfully assigned
  612. // all groups. That is, STATUS_NOT_ALL_ASSIGNED is a
  613. // Success severity level.
  614. //
  615. BaseSetLastNTError(Status);
  616. if ( !NT_SUCCESS(Status) ) {
  617. return FALSE;
  618. }
  619. return TRUE;
  620. }
  621. BOOL
  622. APIENTRY
  623. PrivilegeCheck (
  624. HANDLE ClientToken,
  625. PPRIVILEGE_SET RequiredPrivileges,
  626. LPBOOL pfResult
  627. )
  628. /*++
  629. Routine Description:
  630. This routine tests the caller's client's security context to see if it
  631. contains the specified privileges.
  632. This API requires the caller have SeSecurityPrivilege privilege.
  633. The test for this privilege is always against the primary token of
  634. the calling process, not the impersonation token of the thread.
  635. Arguments:
  636. ClientToken - A handle to a token object representing a client
  637. attempting access. This handle must be obtained from a
  638. communication session layer, such as from an LPC Port or Local
  639. Named Pipe, to prevent possible security policy violations.
  640. RequiredPrivileges - Points to a set of privileges. The client's
  641. security context is to be checked to see which of the specified
  642. privileges are present. The results will be indicated in the
  643. attributes associated with each privilege. Note that
  644. flags in this parameter indicate whether all the privileges listed
  645. are needed, or any of the privileges.
  646. pfResult - Receives a boolean flag indicating whether the client
  647. has all the specified privileges or not. A value of TRUE
  648. indicates the client has all the specified privileges.
  649. Otherwise a value of FALSE is returned.
  650. Return Value:
  651. Returns TRUE for success, FALSE for failure. Extended error status
  652. is available using GetLastError.
  653. --*/
  654. {
  655. NTSTATUS Status;
  656. BOOLEAN Result;
  657. Status = NtPrivilegeCheck (
  658. ClientToken,
  659. RequiredPrivileges,
  660. &Result
  661. );
  662. *pfResult = Result;
  663. if ( !NT_SUCCESS(Status) ) {
  664. BaseSetLastNTError(Status);
  665. return FALSE;
  666. }
  667. return TRUE;
  668. }
  669. BOOL
  670. APIENTRY
  671. AccessCheckAndAuditAlarmW(
  672. LPCWSTR SubsystemName,
  673. PVOID HandleId,
  674. LPWSTR ObjectTypeName,
  675. LPWSTR ObjectName,
  676. PSECURITY_DESCRIPTOR SecurityDescriptor,
  677. DWORD DesiredAccess,
  678. PGENERIC_MAPPING GenericMapping,
  679. BOOL ObjectCreation,
  680. LPDWORD GrantedAccess,
  681. LPBOOL AccessStatus,
  682. LPBOOL pfGenerateOnClose
  683. )
  684. /*++
  685. Routine Description:
  686. This routine compares the input Security Descriptor against the
  687. caller's impersonation token and indicates if access is granted or
  688. denied. If access is granted then the desired access mask becomes
  689. the granted access mask for the object. The semantics of the
  690. access check routine is described in the DSA Security Architecture
  691. workbook.
  692. This routine will also generate any necessary audit messages as a
  693. result of the access attempt.
  694. Arguments:
  695. SubsystemName - Supplies a name string identifying the subsystem
  696. calling the routine.
  697. HandleId - A unique value that will be used to represent the client's
  698. handle to the object. This value is ignored (and may be re-used)
  699. if the access is denied.
  700. ObjectTypeName - Supplies the name of the type of the object being
  701. created or accessed.
  702. ObjectName - Supplies the name of the object being created or accessed.
  703. SecurityDescriptor - A pointer to the Security Descriptor against which
  704. acccess is to be checked.
  705. DesiredAccess - The desired acccess mask. This mask must have been
  706. previously mapped to contain no generic accesses.
  707. GenericMapping - Supplies a pointer to the generic mapping associated
  708. with this object type.
  709. ObjectCreation - A boolean flag indicated whether the access will
  710. result in a new object being created if granted. A value of TRUE
  711. indicates an object will be created, FALSE indicates an existing
  712. object will be opened.
  713. GrantedAccess - Receives a masking indicating which accesses have been
  714. granted (only valid on success).
  715. AccessStatus - Receives an indication of the success or failure of the
  716. access check. If access is granted, STATUS_SUCCESS is returned.
  717. If access is denied, a value appropriate for return to the client
  718. is returned. This will be STATUS_ACCESS_DENIED or, when mandatory
  719. access controls are implemented, STATUS_OBJECT_NOT_FOUND.
  720. pfGenerateOnClose - Points to a boolean that is set by the audity
  721. generation routine and must be passed to ObjectCloseAuditAlarm
  722. when the object handle is closed.
  723. Return Value:
  724. Returns TRUE for success, FALSE for failure. Extended error status
  725. is available using GetLastError.
  726. --*/
  727. {
  728. NTSTATUS Status;
  729. NTSTATUS RealAccessStatus;
  730. BOOLEAN GenerateOnClose;
  731. UNICODE_STRING Subsystem;
  732. UNICODE_STRING ObjectType;
  733. UNICODE_STRING Object;
  734. RtlInitUnicodeString(
  735. &Subsystem,
  736. SubsystemName
  737. );
  738. RtlInitUnicodeString(
  739. &ObjectType,
  740. ObjectTypeName
  741. );
  742. RtlInitUnicodeString(
  743. &Object,
  744. ObjectName
  745. );
  746. Status = NtAccessCheckAndAuditAlarm (
  747. &Subsystem,
  748. HandleId,
  749. &ObjectType,
  750. &Object,
  751. SecurityDescriptor,
  752. DesiredAccess,
  753. GenericMapping,
  754. (BOOLEAN)ObjectCreation,
  755. GrantedAccess,
  756. &RealAccessStatus,
  757. &GenerateOnClose
  758. );
  759. *pfGenerateOnClose = (BOOL)GenerateOnClose;
  760. if ( !NT_SUCCESS(Status) ) {
  761. BaseSetLastNTError(Status);
  762. return FALSE;
  763. }
  764. if ( !NT_SUCCESS( RealAccessStatus )) {
  765. *AccessStatus = FALSE;
  766. BaseSetLastNTError( RealAccessStatus );
  767. return( TRUE );
  768. }
  769. *AccessStatus = TRUE;
  770. return TRUE;
  771. }
  772. BOOL
  773. APIENTRY
  774. AccessCheckAndAuditAlarmA (
  775. LPCSTR SubsystemName,
  776. PVOID HandleId,
  777. LPSTR ObjectTypeName,
  778. LPSTR ObjectName,
  779. PSECURITY_DESCRIPTOR SecurityDescriptor,
  780. DWORD DesiredAccess,
  781. PGENERIC_MAPPING GenericMapping,
  782. BOOL ObjectCreation,
  783. LPDWORD GrantedAccess,
  784. LPBOOL AccessStatus,
  785. LPBOOL pfGenerateOnClose
  786. )
  787. /*++
  788. Routine Description:
  789. ANSI Thunk to AccessCheckAndAuditAlarmW
  790. --*/
  791. {
  792. PUNICODE_STRING ObjectNameW;
  793. ANSI_STRING AnsiString;
  794. UNICODE_STRING SubsystemNameW;
  795. UNICODE_STRING ObjectTypeNameW;
  796. NTSTATUS Status;
  797. BOOL RVal;
  798. ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
  799. RtlInitAnsiString(&AnsiString,SubsystemName);
  800. Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
  801. if ( !NT_SUCCESS(Status) ) {
  802. BaseSetLastNTError(Status);
  803. return FALSE;
  804. }
  805. RtlInitAnsiString(&AnsiString,ObjectTypeName);
  806. Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
  807. if ( !NT_SUCCESS(Status) ) {
  808. RtlFreeUnicodeString( &SubsystemNameW );
  809. BaseSetLastNTError(Status);
  810. return FALSE;
  811. }
  812. //
  813. // Convert the object name string, but don't allocate memory to
  814. // do it, since we've got the space in the TEB available.
  815. //
  816. RtlInitAnsiString(&AnsiString,ObjectName);
  817. Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
  818. if ( !NT_SUCCESS(Status) ) {
  819. RtlFreeUnicodeString( &SubsystemNameW );
  820. RtlFreeUnicodeString( &ObjectTypeNameW );
  821. BaseSetLastNTError(Status);
  822. return FALSE;
  823. }
  824. RVal = AccessCheckAndAuditAlarmW (
  825. (LPCWSTR)SubsystemNameW.Buffer,
  826. HandleId,
  827. ObjectTypeNameW.Buffer,
  828. ObjectNameW->Buffer,
  829. SecurityDescriptor,
  830. DesiredAccess,
  831. GenericMapping,
  832. ObjectCreation,
  833. GrantedAccess,
  834. AccessStatus,
  835. pfGenerateOnClose
  836. );
  837. RtlFreeUnicodeString( &SubsystemNameW );
  838. RtlFreeUnicodeString( &ObjectTypeNameW );
  839. return( RVal );
  840. }
  841. BOOL
  842. APIENTRY
  843. ObjectOpenAuditAlarmA (
  844. LPCSTR SubsystemName,
  845. PVOID HandleId,
  846. LPSTR ObjectTypeName,
  847. LPSTR ObjectName,
  848. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  849. HANDLE ClientToken,
  850. DWORD DesiredAccess,
  851. DWORD GrantedAccess,
  852. PPRIVILEGE_SET Privileges OPTIONAL,
  853. BOOL ObjectCreation,
  854. BOOL AccessGranted,
  855. LPBOOL GenerateOnClose
  856. )
  857. /*++
  858. Routine Description:
  859. ANSI Thunk to ObjectOpenAuditAlarmW
  860. --*/
  861. {
  862. PUNICODE_STRING ObjectNameW;
  863. ANSI_STRING AnsiString;
  864. UNICODE_STRING SubsystemNameW;
  865. UNICODE_STRING ObjectTypeNameW;
  866. NTSTATUS Status;
  867. BOOL RVal;
  868. ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;
  869. RtlInitAnsiString(&AnsiString,SubsystemName);
  870. Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
  871. if ( !NT_SUCCESS(Status) ) {
  872. BaseSetLastNTError(Status);
  873. return FALSE;
  874. }
  875. RtlInitAnsiString(&AnsiString,ObjectTypeName);
  876. Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);
  877. if ( !NT_SUCCESS(Status) ) {
  878. RtlFreeUnicodeString( &SubsystemNameW );
  879. BaseSetLastNTError(Status);
  880. return FALSE;
  881. }
  882. //
  883. // Convert the object name string, but don't allocate memory to
  884. // do it, since we've got the space in the TEB available.
  885. //
  886. RtlInitAnsiString(&AnsiString,ObjectName);
  887. Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);
  888. if ( !NT_SUCCESS(Status) ) {
  889. RtlFreeUnicodeString( &SubsystemNameW );
  890. RtlFreeUnicodeString( &ObjectTypeNameW );
  891. BaseSetLastNTError(Status);
  892. return FALSE;
  893. }
  894. RVal = ObjectOpenAuditAlarmW (
  895. (LPCWSTR)SubsystemNameW.Buffer,
  896. HandleId,
  897. ObjectTypeNameW.Buffer,
  898. ObjectNameW->Buffer,
  899. pSecurityDescriptor,
  900. ClientToken,
  901. DesiredAccess,
  902. GrantedAccess,
  903. Privileges,
  904. ObjectCreation,
  905. AccessGranted,
  906. GenerateOnClose
  907. );
  908. RtlFreeUnicodeString( &SubsystemNameW );
  909. RtlFreeUnicodeString( &ObjectTypeNameW );
  910. return( RVal );
  911. }
  912. BOOL
  913. APIENTRY
  914. ObjectOpenAuditAlarmW (
  915. LPCWSTR SubsystemName,
  916. PVOID HandleId,
  917. LPWSTR ObjectTypeName,
  918. LPWSTR ObjectName,
  919. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  920. HANDLE ClientToken,
  921. DWORD DesiredAccess,
  922. DWORD GrantedAccess,
  923. PPRIVILEGE_SET Privileges OPTIONAL,
  924. BOOL ObjectCreation,
  925. BOOL AccessGranted,
  926. LPBOOL GenerateOnClose
  927. )
  928. /*++
  929. Routine Description:
  930. This routine is used to generate audit and alarm messages when an
  931. attempt is made to access an existing protected subsystem object or
  932. create a new one. This routine may result in several messages being
  933. generated and sent to Port objects. This may result in a significant
  934. latency before returning. Design of routines that must call this
  935. routine must take this potential latency into account. This may have
  936. an impact on the approach taken for data structure mutex locking, for
  937. example.
  938. This routine may not be able to generate a complete audit record
  939. due to memory restrictions.
  940. This API requires the caller have SeSecurityPrivilege privilege.
  941. The test for this privilege is always against the primary token of
  942. the calling process, not the impersonation token of the thread.
  943. Arguments:
  944. SubsystemName - Supplies a name string identifying the
  945. subsystem calling the routine.
  946. HandleId - A unique value representing the client's handle to the
  947. object. If the access attempt was not successful (AccessGranted is
  948. FALSE), then this parameter is ignored.
  949. ObjectTypeName - Supplies the name of the type of object being
  950. accessed.
  951. ObjectName - Supplies the name of the object the client
  952. accessed or attempted to access.
  953. pSecurityDescriptor - An optional pointer to the security
  954. descriptor of the object being accessed.
  955. ClientToken - A handle to a token object representing the client that
  956. requested the operation. This handle must be obtained from a
  957. communication session layer, such as from an LPC Port or Local
  958. Named Pipe, to prevent possible security policy violations.
  959. DesiredAccess - The desired access mask. This mask must have been
  960. previously mapped to contain no generic accesses.
  961. GrantedAccess - The mask of accesses that were actually granted.
  962. Privileges - Optionally points to a set of privileges that were
  963. required for the access attempt. Those privileges that were held
  964. by the subject are marked using the UsedForAccess flag of the
  965. attributes associated with each privilege.
  966. ObjectCreation - A boolean flag indicating whether the access will
  967. result in a new object being created if granted. A value of TRUE
  968. indicates an object will be created, FALSE indicates an existing
  969. object will be opened.
  970. AccessGranted - Indicates whether the requested access was granted or
  971. not. A value of TRUE indicates the access was granted. A value of
  972. FALSE indicates the access was not granted.
  973. GenerateOnClose - Points to a boolean that is set by the audit
  974. generation routine and must be passed to NtCloseObjectAuditAlarm()
  975. when the object handle is closed.
  976. Return Value:
  977. Returns TRUE for success, FALSE for failure. Extended error status
  978. is available using GetLastError.
  979. --*/
  980. {
  981. NTSTATUS Status;
  982. UNICODE_STRING Subsystem;
  983. UNICODE_STRING ObjectType;
  984. UNICODE_STRING Object;
  985. RtlInitUnicodeString(
  986. &Subsystem,
  987. SubsystemName
  988. );
  989. RtlInitUnicodeString(
  990. &ObjectType,
  991. ObjectTypeName
  992. );
  993. RtlInitUnicodeString(
  994. &Object,
  995. ObjectName
  996. );
  997. Status = NtOpenObjectAuditAlarm (
  998. &Subsystem,
  999. &HandleId,
  1000. &ObjectType,
  1001. &Object,
  1002. pSecurityDescriptor,
  1003. ClientToken,
  1004. DesiredAccess,
  1005. GrantedAccess,
  1006. Privileges,
  1007. (BOOLEAN)ObjectCreation,
  1008. (BOOLEAN)AccessGranted,
  1009. (PBOOLEAN)GenerateOnClose
  1010. );
  1011. if ( !NT_SUCCESS(Status) ) {
  1012. BaseSetLastNTError(Status);
  1013. return FALSE;
  1014. }
  1015. return TRUE;
  1016. }
  1017. BOOL
  1018. APIENTRY
  1019. ObjectPrivilegeAuditAlarmA (
  1020. LPCSTR SubsystemName,
  1021. PVOID HandleId,
  1022. HANDLE ClientToken,
  1023. DWORD DesiredAccess,
  1024. PPRIVILEGE_SET Privileges,
  1025. BOOL AccessGranted
  1026. )
  1027. /*++
  1028. Routine Description:
  1029. ANSI Thunk to ObjectPrivilegeAuditAlarmW
  1030. --*/
  1031. {
  1032. PUNICODE_STRING SubsystemNameW;
  1033. ANSI_STRING AnsiString;
  1034. NTSTATUS Status;
  1035. BOOL RVal;
  1036. SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;
  1037. //
  1038. // Convert the object name string, but don't allocate memory to
  1039. // do it, since we've got the space in the TEB available.
  1040. //
  1041. RtlInitAnsiString(&AnsiString,SubsystemName);
  1042. Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);
  1043. if ( !NT_SUCCESS(Status) ) {
  1044. BaseSetLastNTError(Status);
  1045. return FALSE;
  1046. }
  1047. RVal = ObjectPrivilegeAuditAlarmW (
  1048. (LPCWSTR)SubsystemNameW->Buffer,
  1049. HandleId,
  1050. ClientToken,
  1051. DesiredAccess,
  1052. Privileges,
  1053. AccessGranted
  1054. );
  1055. return( RVal );
  1056. }
  1057. BOOL
  1058. APIENTRY
  1059. ObjectPrivilegeAuditAlarmW (
  1060. LPCWSTR SubsystemName,
  1061. PVOID HandleId,
  1062. HANDLE ClientToken,
  1063. DWORD DesiredAccess,
  1064. PPRIVILEGE_SET Privileges,
  1065. BOOL AccessGranted
  1066. )
  1067. /*++
  1068. Routine Description:
  1069. This routine is used to generate audit and alarm messages when an
  1070. attempt is made to perform privileged operations on a protected
  1071. subsystem object after the object is already opened. This routine
  1072. may result in several messages being generated and sent to Port
  1073. objects. This may result in a significant latency before
  1074. returning. Design of routines that must call this routine must
  1075. take this potential latency into account. This may have an impact
  1076. on the approach taken for data structure mutex locking, for
  1077. example.
  1078. This API requires the caller have SeSecurityPrivilege privilege.
  1079. The test for this privilege is always against the primary token of
  1080. the calling process, allowing the caller to be impersonating a
  1081. client during the call with no ill effects.
  1082. Arguments:
  1083. SubsystemName - Supplies a name string identifying the subsystem
  1084. calling the routine.
  1085. HandleId - A unique value representing the client's handle to the
  1086. object.
  1087. ClientToken - A handle to a token object representing the client that
  1088. requested the operation. This handle must be obtained from a
  1089. communication session layer, such as from an LPC Port or Local
  1090. Named Pipe, to prevent possible security policy violations.
  1091. DesiredAccess - The desired access mask. This mask must have been
  1092. previously mapped to contain no generic accesses.
  1093. Privileges - The set of privileges required for the requested
  1094. operation. Those privileges that were held by the subject are
  1095. marked using the UsedForAccess flag of the attributes
  1096. associated with each privilege.
  1097. AccessGranted - Indicates whether the requested access was granted or
  1098. not. A value of TRUE indicates the access was granted. A value of
  1099. FALSE indicates the access was not granted.
  1100. Return value:
  1101. Returns TRUE for success, FALSE for failure. Extended error status
  1102. is available using GetLastError.
  1103. --*/
  1104. {
  1105. NTSTATUS Status;
  1106. UNICODE_STRING Subsystem;
  1107. RtlInitUnicodeString(
  1108. &Subsystem,
  1109. SubsystemName
  1110. );
  1111. Status = NtPrivilegeObjectAuditAlarm (
  1112. &Subsystem,
  1113. HandleId,
  1114. ClientToken,
  1115. DesiredAccess,
  1116. Privileges,
  1117. (BOOLEAN)AccessGranted
  1118. );
  1119. if ( !NT_SUCCESS(Status) ) {
  1120. BaseSetLastNTError(Status);
  1121. return FALSE;
  1122. }
  1123. return TRUE;
  1124. }
  1125. BOOL
  1126. APIENTRY
  1127. ObjectCloseAuditAlarmA (
  1128. LPCSTR SubsystemName,
  1129. PVOID HandleId,
  1130. BOOL GenerateOnClose
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. ANSI Thunk to ObjectCloseAuditAlarmW
  1135. --*/
  1136. {
  1137. PUNICODE_STRING SubsystemNameW;
  1138. NTSTATUS Status;
  1139. ANSI_STRING AnsiString;
  1140. SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;
  1141. //
  1142. // Convert the object name string, but don't allocate memory to
  1143. // do it, since we've got the space in the TEB available.
  1144. //
  1145. RtlInitAnsiString(&AnsiString,SubsystemName);
  1146. Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);
  1147. if ( !NT_SUCCESS(Status) ) {
  1148. BaseSetLastNTError(Status);
  1149. return FALSE;
  1150. }
  1151. return ObjectCloseAuditAlarmW (
  1152. (LPCWSTR)SubsystemNameW->Buffer,
  1153. HandleId,
  1154. GenerateOnClose
  1155. );
  1156. }
  1157. BOOL
  1158. APIENTRY
  1159. ObjectCloseAuditAlarmW (
  1160. LPCWSTR SubsystemName,
  1161. PVOID HandleId,
  1162. BOOL GenerateOnClose
  1163. )
  1164. /*++
  1165. Routine Description:
  1166. This routine is used to generate audit and alarm messages when a handle
  1167. to a protected subsystem object is deleted. This routine may result in
  1168. several messages being generated and sent to Port objects. This may
  1169. result in a significant latency before returning. Design of routines
  1170. that must call this routine must take this potential latency into
  1171. account. This may have an impact on the approach taken for data
  1172. structure mutex locking, for example.
  1173. This API requires the caller have SeSecurityPrivilege privilege. The test
  1174. for this privilege is always against the primary token of the calling
  1175. process, allowing the caller to be impersonating a client during the
  1176. call with no ill effects.
  1177. Arguments:
  1178. SubsystemName - Supplies a name string identifying the subsystem
  1179. calling the routine.
  1180. HandleId - A unique value representing the client's handle to the
  1181. object.
  1182. GenerateOnClose - Is a boolean value returned from a corresponding
  1183. AccessCheckAndAuditAlarm() call or ObjectOpenAuditAlarm() call
  1184. when the object handle was created.
  1185. Return value:
  1186. Returns TRUE for success, FALSE for failure. Extended error status
  1187. is available using GetLastError.
  1188. --*/
  1189. {
  1190. NTSTATUS Status;
  1191. UNICODE_STRING Subsystem;
  1192. RtlInitUnicodeString( &Subsystem, SubsystemName );
  1193. Status = NtCloseObjectAuditAlarm (
  1194. &Subsystem,
  1195. HandleId,
  1196. (BOOLEAN)GenerateOnClose
  1197. );
  1198. if ( !NT_SUCCESS(Status) ) {
  1199. BaseSetLastNTError(Status);
  1200. return FALSE;
  1201. }
  1202. return TRUE;
  1203. }
  1204. BOOL
  1205. APIENTRY
  1206. ObjectDeleteAuditAlarmA (
  1207. LPCSTR SubsystemName,
  1208. PVOID HandleId,
  1209. BOOL GenerateOnClose
  1210. )
  1211. /*++
  1212. Routine Description:
  1213. ANSI Thunk to ObjectDeleteAuditAlarmW
  1214. --*/
  1215. {
  1216. PUNICODE_STRING SubsystemNameW;
  1217. NTSTATUS Status;
  1218. ANSI_STRING AnsiString;
  1219. SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;
  1220. //
  1221. // Convert the object name string, but don't allocate memory to
  1222. // do it, since we've got the space in the TEB available.
  1223. //
  1224. RtlInitAnsiString(&AnsiString,SubsystemName);
  1225. Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);
  1226. if ( !NT_SUCCESS(Status) ) {
  1227. BaseSetLastNTError(Status);
  1228. return FALSE;
  1229. }
  1230. return ObjectDeleteAuditAlarmW (
  1231. (LPCWSTR)SubsystemNameW->Buffer,
  1232. HandleId,
  1233. GenerateOnClose
  1234. );
  1235. }
  1236. BOOL
  1237. APIENTRY
  1238. ObjectDeleteAuditAlarmW (
  1239. LPCWSTR SubsystemName,
  1240. PVOID HandleId,
  1241. BOOL GenerateOnClose
  1242. )
  1243. /*++
  1244. Routine Description:
  1245. This routine is used to generate audit and alarm messages when an object
  1246. in a protected subsystem is deleted. This routine may result in
  1247. several messages being generated and sent to Port objects. This may
  1248. result in a significant latency before returning. Design of routines
  1249. that must call this routine must take this potential latency into
  1250. account. This may have an impact on the approach taken for data
  1251. structure mutex locking, for example.
  1252. This API requires the caller have SeSecurityPrivilege privilege. The test
  1253. for this privilege is always against the primary token of the calling
  1254. process, allowing the caller to be impersonating a client during the
  1255. call with no ill effects.
  1256. Arguments:
  1257. SubsystemName - Supplies a name string identifying the subsystem
  1258. calling the routine.
  1259. HandleId - A unique value representing the client's handle to the
  1260. object.
  1261. GenerateOnClose - Is a boolean value returned from a corresponding
  1262. AccessCheckAndAuditAlarm() call or ObjectOpenAuditAlarm() call
  1263. when the object handle was created.
  1264. Return value:
  1265. Returns TRUE for success, FALSE for failure. Extended error status
  1266. is available using GetLastError.
  1267. --*/
  1268. {
  1269. NTSTATUS Status;
  1270. UNICODE_STRING Subsystem;
  1271. RtlInitUnicodeString( &Subsystem, SubsystemName );
  1272. Status = NtDeleteObjectAuditAlarm (
  1273. &Subsystem,
  1274. HandleId,
  1275. (BOOLEAN)GenerateOnClose
  1276. );
  1277. if ( !NT_SUCCESS(Status) ) {
  1278. BaseSetLastNTError(Status);
  1279. return FALSE;
  1280. }
  1281. return TRUE;
  1282. }
  1283. BOOL
  1284. APIENTRY
  1285. PrivilegedServiceAuditAlarmA (
  1286. LPCSTR SubsystemName,
  1287. LPCSTR ServiceName,
  1288. HANDLE ClientToken,
  1289. PPRIVILEGE_SET Privileges,
  1290. BOOL AccessGranted
  1291. )
  1292. /*++
  1293. Routine Description:
  1294. ANSI Thunk to PrivilegedServiceAuditAlarmW
  1295. --*/
  1296. {
  1297. PUNICODE_STRING ServiceNameW;
  1298. UNICODE_STRING SubsystemNameW;
  1299. ANSI_STRING AnsiString;
  1300. NTSTATUS Status;
  1301. BOOL RVal;
  1302. ServiceNameW = &NtCurrentTeb()->StaticUnicodeString;
  1303. //
  1304. // Convert the object name string, but don't allocate memory to
  1305. // do it, since we've got the space in the TEB available.
  1306. //
  1307. RtlInitAnsiString(&AnsiString,ServiceName);
  1308. Status = RtlAnsiStringToUnicodeString(ServiceNameW,&AnsiString,FALSE);
  1309. if ( !NT_SUCCESS(Status) ) {
  1310. BaseSetLastNTError(Status);
  1311. return FALSE;
  1312. }
  1313. RtlInitAnsiString(&AnsiString,SubsystemName);
  1314. Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);
  1315. if ( !NT_SUCCESS(Status) ) {
  1316. BaseSetLastNTError(Status);
  1317. return FALSE;
  1318. }
  1319. RVal = PrivilegedServiceAuditAlarmW (
  1320. (LPCWSTR)SubsystemNameW.Buffer,
  1321. (LPCWSTR)ServiceNameW->Buffer,
  1322. ClientToken,
  1323. Privileges,
  1324. AccessGranted
  1325. );
  1326. RtlFreeUnicodeString( &SubsystemNameW );
  1327. return( RVal );
  1328. }
  1329. BOOL
  1330. APIENTRY
  1331. PrivilegedServiceAuditAlarmW (
  1332. LPCWSTR SubsystemName,
  1333. LPCWSTR ServiceName,
  1334. HANDLE ClientToken,
  1335. PPRIVILEGE_SET Privileges,
  1336. BOOL AccessGranted
  1337. )
  1338. /*++
  1339. Routine Description:
  1340. This routine is used to generate audit and alarm messages when an
  1341. attempt is made to perform privileged system service operations. This
  1342. routine may result in several messages being generated and sent to Port
  1343. objects. This may result in a significant latency before returning.
  1344. Design of routines that must call this routine must take this potential
  1345. latency into account. This may have an impact on the approach taken
  1346. for data structure mutex locking, for example.
  1347. This API requires the caller have SeSecurityPrivilege privilege. The test
  1348. for this privilege is always against the primary token of the calling
  1349. process, allowing the caller to be impersonating a client during the
  1350. call with no ill effects
  1351. Arguments:
  1352. SubsystemName - Supplies a name string identifying the subsystem
  1353. calling the routine.
  1354. ServiceName - Supplies a name of the privileged subsystem service. For
  1355. example, "RESET RUNTIME LOCAL SECURITY POLICY" might be specified
  1356. by a Local Security Authority service used to update the local
  1357. security policy database.
  1358. ClientToken - A handle to a token object representing the client that
  1359. requested the operation. This handle must be obtained from a
  1360. communication session layer, such as from an LPC Port or Local
  1361. Named Pipe, to prevent possible security policy violations.
  1362. Privileges - Points to a set of privileges required to perform the
  1363. privileged operation. Those privileges that were held by the
  1364. subject are marked using the UsedForAccess flag of the
  1365. attributes associated with each privilege.
  1366. AccessGranted - Indicates whether the requested access was granted or
  1367. not. A value of TRUE indicates the access was granted. A value of
  1368. FALSE indicates the access was not granted.
  1369. Return value:
  1370. Returns TRUE for success, FALSE for failure. Extended error status
  1371. is available using GetLastError.
  1372. --*/
  1373. {
  1374. NTSTATUS Status;
  1375. UNICODE_STRING Subsystem;
  1376. UNICODE_STRING Service;
  1377. RtlInitUnicodeString( &Subsystem, SubsystemName );
  1378. RtlInitUnicodeString( &Service, ServiceName );
  1379. Status = NtPrivilegedServiceAuditAlarm (
  1380. &Subsystem,
  1381. &Service,
  1382. ClientToken,
  1383. Privileges,
  1384. (BOOLEAN)AccessGranted
  1385. );
  1386. if ( !NT_SUCCESS(Status) ) {
  1387. BaseSetLastNTError(Status);
  1388. return FALSE;
  1389. }
  1390. return TRUE;
  1391. }
  1392. BOOL
  1393. APIENTRY
  1394. IsValidSid (
  1395. PSID pSid
  1396. )
  1397. /*++
  1398. Routine Description:
  1399. This procedure validates an SID's structure.
  1400. Arguments:
  1401. pSid - Pointer to the SID structure to validate.
  1402. Return Value:
  1403. BOOLEAN - TRUE if the structure of pSid is valid.
  1404. --*/
  1405. {
  1406. return (BOOL) RtlValidSid (
  1407. pSid
  1408. );
  1409. }
  1410. BOOL
  1411. APIENTRY
  1412. EqualSid (
  1413. PSID pSid1,
  1414. PSID pSid2
  1415. )
  1416. /*++
  1417. Routine Description:
  1418. This procedure tests two SID values for equality.
  1419. Arguments:
  1420. pSid1, pSid2 - Supply pointers to the two SID values to compare.
  1421. The SID structures are assumed to be valid.
  1422. Return Value:
  1423. BOOLEAN - TRUE if the value of pSid1 is equal to pSid2, and FALSE
  1424. otherwise.
  1425. --*/
  1426. {
  1427. return (BOOL) RtlEqualSid (
  1428. pSid1,
  1429. pSid2
  1430. );
  1431. }
  1432. BOOL
  1433. APIENTRY
  1434. EqualPrefixSid (
  1435. PSID pSid1,
  1436. PSID pSid2
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. This procedure tests two SID prefix values for equality.
  1441. An SID prefix is the entire SID except for the last sub-authority
  1442. value.
  1443. Arguments:
  1444. pSid1, pSid2 - Supply pointers to the two SID values to compare.
  1445. The SID structures are assumed to be valid.
  1446. Return Value:
  1447. BOOLEAN - TRUE if the prefix value of pSid1 is equal to pSid2, and
  1448. FALSE otherwise.
  1449. --*/
  1450. {
  1451. return (BOOL) RtlEqualPrefixSid (
  1452. pSid1,
  1453. pSid2
  1454. );
  1455. }
  1456. DWORD
  1457. APIENTRY
  1458. GetSidLengthRequired (
  1459. UCHAR nSubAuthorityCount
  1460. )
  1461. /*++
  1462. Routine Description:
  1463. This routine returns the length, in bytes, required to store an SID
  1464. with the specified number of Sub-Authorities.
  1465. Arguments:
  1466. nSubAuthorityCount - The number of sub-authorities to be stored in
  1467. the SID.
  1468. Return Value:
  1469. DWORD - The length, in bytes, required to store the SID.
  1470. --*/
  1471. {
  1472. return RtlLengthRequiredSid (
  1473. nSubAuthorityCount
  1474. );
  1475. }
  1476. BOOL
  1477. APIENTRY
  1478. InitializeSid (
  1479. PSID Sid,
  1480. PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
  1481. BYTE nSubAuthorityCount
  1482. )
  1483. /*++
  1484. Routine Description:
  1485. This function initializes an SID data structure. It does not,
  1486. however, set the sub-authority values. This must be done
  1487. separately.
  1488. Arguments:
  1489. Sid - Pointer to the SID data structure to initialize.
  1490. pIdentifierAuthority - Pointer to the Identifier Authority value
  1491. to set in the SID.
  1492. nSubAuthorityCount - The number of sub-authorities that will be
  1493. placed in the SID (a separate action).
  1494. Return Value:
  1495. None
  1496. --*/
  1497. {
  1498. NTSTATUS Status;
  1499. Status = RtlInitializeSid (
  1500. Sid,
  1501. pIdentifierAuthority,
  1502. nSubAuthorityCount
  1503. );
  1504. if ( !NT_SUCCESS( Status )) {
  1505. BaseSetLastNTError( Status );
  1506. return( FALSE );
  1507. }
  1508. return( TRUE );
  1509. }
  1510. PVOID
  1511. APIENTRY
  1512. FreeSid(
  1513. PSID pSid
  1514. )
  1515. /*++
  1516. Routine Description:
  1517. This function is used to free a SID previously allocated using
  1518. AllocateAndInitializeSid().
  1519. Arguments:
  1520. Sid - Pointer to the SID to free.
  1521. Return Value:
  1522. None.
  1523. --*/
  1524. {
  1525. return(RtlFreeSid( pSid ));
  1526. }
  1527. BOOL
  1528. APIENTRY
  1529. AllocateAndInitializeSid (
  1530. PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
  1531. BYTE nSubAuthorityCount,
  1532. DWORD nSubAuthority0,
  1533. DWORD nSubAuthority1,
  1534. DWORD nSubAuthority2,
  1535. DWORD nSubAuthority3,
  1536. DWORD nSubAuthority4,
  1537. DWORD nSubAuthority5,
  1538. DWORD nSubAuthority6,
  1539. DWORD nSubAuthority7,
  1540. PSID *pSid
  1541. )
  1542. /*++
  1543. Routine Description:
  1544. This function allocates and initializes a sid with the specified
  1545. number of sub-authorities (up to 8). A sid allocated with this
  1546. routine must be freed using FreeSid().
  1547. Arguments:
  1548. pIdentifierAuthority - Pointer to the Identifier Authority value to
  1549. set in the SID.
  1550. nSubAuthorityCount - The number of sub-authorities to place in the SID.
  1551. This also identifies how many of the SubAuthorityN parameters
  1552. have meaningful values. This must contain a value from 0 through
  1553. 8.
  1554. nSubAuthority0-7 - Provides the corresponding sub-authority value to
  1555. place in the SID. For example, a SubAuthorityCount value of 3
  1556. indicates that SubAuthority0, SubAuthority1, and SubAuthority0
  1557. have meaningful values and the rest are to be ignored.
  1558. Sid - Receives a pointer to the allocated and initialized SID data
  1559. structure.
  1560. Return Value:
  1561. ERROR_NO_MEMORY - The attempt to allocate memory for the SID
  1562. failed.
  1563. ERROR_INVALID_SID - The number of sub-authorities specified did
  1564. not fall in the valid range for this api (0 through 8).
  1565. --*/
  1566. {
  1567. NTSTATUS Status;
  1568. Status = RtlAllocateAndInitializeSid (
  1569. pIdentifierAuthority,
  1570. (UCHAR)nSubAuthorityCount,
  1571. (ULONG)nSubAuthority0,
  1572. (ULONG)nSubAuthority1,
  1573. (ULONG)nSubAuthority2,
  1574. (ULONG)nSubAuthority3,
  1575. (ULONG)nSubAuthority4,
  1576. (ULONG)nSubAuthority5,
  1577. (ULONG)nSubAuthority6,
  1578. (ULONG)nSubAuthority7,
  1579. pSid
  1580. );
  1581. if ( !NT_SUCCESS( Status )) {
  1582. BaseSetLastNTError( Status );
  1583. return( FALSE );
  1584. }
  1585. return( TRUE );
  1586. }
  1587. PSID_IDENTIFIER_AUTHORITY
  1588. GetSidIdentifierAuthority (
  1589. PSID pSid
  1590. )
  1591. /*++
  1592. Routine Description:
  1593. This function returns the address of an SID's IdentifierAuthority field.
  1594. Arguments:
  1595. Sid - Pointer to the SID data structure.
  1596. Return Value:
  1597. Address of an SID's Identifier Authority field.
  1598. --*/
  1599. {
  1600. return RtlIdentifierAuthoritySid (
  1601. pSid
  1602. );
  1603. }
  1604. PDWORD
  1605. GetSidSubAuthority (
  1606. PSID pSid,
  1607. DWORD nSubAuthority
  1608. )
  1609. /*++
  1610. Routine Description:
  1611. This function returns the address of a sub-authority array element of
  1612. an SID.
  1613. Arguments:
  1614. pSid - Pointer to the SID data structure.
  1615. nSubAuthority - An index indicating which sub-authority is being
  1616. specified. This value is not compared against the number of
  1617. sub-authorities in the SID for validity.
  1618. Return Value:
  1619. Address of a relative ID within the SID.
  1620. --*/
  1621. {
  1622. return RtlSubAuthoritySid (
  1623. pSid,
  1624. nSubAuthority
  1625. );
  1626. }
  1627. PUCHAR
  1628. GetSidSubAuthorityCount (
  1629. PSID pSid
  1630. )
  1631. /*++
  1632. Routine Description:
  1633. This function returns the address of the sub-authority count field of
  1634. an SID.
  1635. Arguments:
  1636. pSid - Pointer to the SID data structure.
  1637. Return Value:
  1638. Address of the sub-authority count field of an SID.
  1639. --*/
  1640. {
  1641. return RtlSubAuthorityCountSid (
  1642. pSid
  1643. );
  1644. }
  1645. DWORD
  1646. APIENTRY
  1647. GetLengthSid (
  1648. PSID pSid
  1649. )
  1650. /*++
  1651. Routine Description:
  1652. This routine returns the length, in bytes, of a structurally valid SID.
  1653. Arguments:
  1654. pSid - Points to the SID whose length is to be returned. The
  1655. SID's structure is assumed to be valid.
  1656. Return Value:
  1657. DWORD - The length, in bytes, of the SID.
  1658. --*/
  1659. {
  1660. return RtlLengthSid (
  1661. pSid
  1662. );
  1663. }
  1664. BOOL
  1665. APIENTRY
  1666. CopySid (
  1667. DWORD nDestinationSidLength,
  1668. PSID pDestinationSid,
  1669. PSID pSourceSid
  1670. )
  1671. /*++
  1672. Routine Description:
  1673. This routine copies the value of the source SID to the destination
  1674. SID.
  1675. Arguments:
  1676. nDestinationSidLength - Indicates the length, in bytes, of the
  1677. destination SID buffer.
  1678. pDestinationSid - Pointer to a buffer to receive a copy of the
  1679. source Sid value.
  1680. pSourceSid - Supplies the Sid value to be copied.
  1681. Return Value:
  1682. Returns TRUE for success, FALSE for failure. Extended error status
  1683. is available using GetLastError.
  1684. --*/
  1685. {
  1686. NTSTATUS Status;
  1687. Status = RtlCopySid (
  1688. nDestinationSidLength,
  1689. pDestinationSid,
  1690. pSourceSid
  1691. );
  1692. if ( !NT_SUCCESS(Status) ) {
  1693. BaseSetLastNTError(Status);
  1694. return FALSE;
  1695. }
  1696. return TRUE;
  1697. }
  1698. BOOL
  1699. APIENTRY
  1700. AreAllAccessesGranted (
  1701. DWORD GrantedAccess,
  1702. DWORD DesiredAccess
  1703. )
  1704. /*++
  1705. Routine Description:
  1706. This routine is used to check a desired access mask against a
  1707. granted access mask.
  1708. Arguments:
  1709. GrantedAccess - Specifies the granted access mask.
  1710. DesiredAccess - Specifies the desired access mask.
  1711. Return Value:
  1712. BOOL - TRUE if the GrantedAccess mask has all the bits set that
  1713. the DesiredAccess mask has set. That is, TRUE is returned if
  1714. all of the desired accesses have been granted.
  1715. --*/
  1716. {
  1717. return (BOOL) RtlAreAllAccessesGranted (
  1718. GrantedAccess,
  1719. DesiredAccess
  1720. );
  1721. }
  1722. BOOL
  1723. APIENTRY
  1724. AreAnyAccessesGranted (
  1725. DWORD GrantedAccess,
  1726. DWORD DesiredAccess
  1727. )
  1728. /*++
  1729. Routine Description:
  1730. This routine is used to test whether any of a set of desired
  1731. accesses are granted by a granted access mask.
  1732. Arguments:
  1733. GrantedAccess - Specifies the granted access mask.
  1734. DesiredAccess - Specifies the desired access mask.
  1735. Return Value:
  1736. BOOL - TRUE if the GrantedAccess mask contains any of the bits
  1737. specified in the DesiredAccess mask. That is, if any of the
  1738. desired accesses have been granted, TRUE is returned.
  1739. --*/
  1740. {
  1741. return (BOOL) RtlAreAnyAccessesGranted (
  1742. GrantedAccess,
  1743. DesiredAccess
  1744. );
  1745. }
  1746. VOID
  1747. APIENTRY
  1748. MapGenericMask (
  1749. PDWORD AccessMask,
  1750. PGENERIC_MAPPING GenericMapping
  1751. )
  1752. /*++
  1753. Routine Description:
  1754. This routine maps all generic accesses in the provided access mask
  1755. to specific and standard accesses according to the provided
  1756. GenericMapping. The resulting mask will not have any of the
  1757. generic bits set (GenericRead, GenericWrite, GenericExecute, or
  1758. GenericAll) or any undefined bits set, but may have any other bit
  1759. set. If bits other than the generic bits are provided on input,
  1760. they will not be cleared bt the mapping.
  1761. Arguments:
  1762. AccessMask - Points to the access mask to be mapped.
  1763. GenericMapping - The mapping of generic to specific and standard
  1764. access types.
  1765. Return Value:
  1766. None.
  1767. --*/
  1768. {
  1769. RtlMapGenericMask (
  1770. AccessMask,
  1771. GenericMapping
  1772. );
  1773. }
  1774. BOOL
  1775. APIENTRY
  1776. IsValidAcl (
  1777. PACL pAcl
  1778. )
  1779. /*++
  1780. Routine Description:
  1781. This procedure validates an ACL.
  1782. This involves validating the revision level of the ACL and ensuring
  1783. that the number of ACEs specified in the AceCount fit in the space
  1784. specified by the AclSize field of the ACL header.
  1785. Arguments:
  1786. pAcl - Pointer to the ACL structure to validate.
  1787. Return Value:
  1788. BOOLEAN - TRUE if the structure of Acl is valid.
  1789. --*/
  1790. {
  1791. return (BOOL) RtlValidAcl (
  1792. pAcl
  1793. );
  1794. }
  1795. BOOL
  1796. APIENTRY
  1797. InitializeAcl (
  1798. PACL pAcl,
  1799. DWORD nAclLength,
  1800. DWORD dwAclRevision
  1801. )
  1802. /*++
  1803. Routine Description:
  1804. InitializeAcl creates a new ACL in the caller supplied memory
  1805. buffer. The ACL contains zero ACEs; therefore, it is an empty ACL
  1806. as opposed to a nonexistent ACL. That is, if the ACL is now set
  1807. to an object it will implicitly deny access to everyone.
  1808. Arguments:
  1809. pAcl - Supplies the buffer containing the ACL being initialized
  1810. nAclLength - Supplies the length of the ace buffer in bytes
  1811. dwAclRevision - Supplies the revision for this Acl
  1812. Return Value:
  1813. Returns TRUE for success, FALSE for failure. Extended error status
  1814. is available using GetLastError.
  1815. --*/
  1816. {
  1817. NTSTATUS Status;
  1818. Status = RtlCreateAcl (
  1819. pAcl,
  1820. nAclLength,
  1821. dwAclRevision
  1822. );
  1823. if ( !NT_SUCCESS(Status) ) {
  1824. BaseSetLastNTError(Status);
  1825. return FALSE;
  1826. }
  1827. return TRUE;
  1828. }
  1829. BOOL
  1830. APIENTRY
  1831. GetAclInformation (
  1832. PACL pAcl,
  1833. PVOID pAclInformation,
  1834. DWORD nAclInformationLength,
  1835. ACL_INFORMATION_CLASS dwAclInformationClass
  1836. )
  1837. /*++
  1838. Routine Description:
  1839. This routine returns to the caller information about an ACL. The requested
  1840. information can be AclRevisionInformation, or AclSizeInformation.
  1841. Arguments:
  1842. pAcl - Supplies the Acl being examined
  1843. pAclInformation - Supplies the buffer to receive the information
  1844. being requested
  1845. nAclInformationLength - Supplies the length of the AclInformation
  1846. buffer in bytes
  1847. dwAclInformationClass - Supplies the type of information being
  1848. requested
  1849. Return Value:
  1850. Returns TRUE for success, FALSE for failure. Extended error status
  1851. is available using GetLastError.
  1852. --*/
  1853. {
  1854. NTSTATUS Status;
  1855. Status = RtlQueryInformationAcl (
  1856. pAcl,
  1857. pAclInformation,
  1858. nAclInformationLength,
  1859. dwAclInformationClass
  1860. );
  1861. if ( !NT_SUCCESS(Status) ) {
  1862. BaseSetLastNTError(Status);
  1863. return FALSE;
  1864. }
  1865. return TRUE;
  1866. }
  1867. BOOL
  1868. APIENTRY
  1869. SetAclInformation (
  1870. PACL pAcl,
  1871. PVOID pAclInformation,
  1872. DWORD nAclInformationLength,
  1873. ACL_INFORMATION_CLASS dwAclInformationClass
  1874. )
  1875. /*++
  1876. Routine Description:
  1877. This routine sets the state of an ACL. For now only the revision
  1878. level can be set and for now only a revision level of 1 is accepted
  1879. so this procedure is rather simple
  1880. Arguments:
  1881. pAcl - Supplies the Acl being altered
  1882. pAclInformation - Supplies the buffer containing the information
  1883. being set
  1884. nAclInformationLength - Supplies the length of the Acl information
  1885. buffer
  1886. dwAclInformationClass - Supplies the type of information begin set
  1887. Return Value:
  1888. Returns TRUE for success, FALSE for failure. Extended error status
  1889. is available using GetLastError.
  1890. --*/
  1891. {
  1892. NTSTATUS Status;
  1893. Status = RtlSetInformationAcl (
  1894. pAcl,
  1895. pAclInformation,
  1896. nAclInformationLength,
  1897. dwAclInformationClass
  1898. );
  1899. if ( !NT_SUCCESS(Status) ) {
  1900. BaseSetLastNTError(Status);
  1901. return FALSE;
  1902. }
  1903. return TRUE;
  1904. }
  1905. BOOL
  1906. APIENTRY
  1907. AddAce (
  1908. PACL pAcl,
  1909. DWORD dwAceRevision,
  1910. DWORD dwStartingAceIndex,
  1911. PVOID pAceList,
  1912. DWORD nAceListLength
  1913. )
  1914. /*++
  1915. Routine Description:
  1916. This routine adds a string of ACEs to an ACL.
  1917. Arguments:
  1918. pAcl - Supplies the Acl being modified
  1919. dwAceRevision - Supplies the Acl/Ace revision of the ACE being
  1920. added
  1921. dwStartingAceIndex - Supplies the ACE index which will be the
  1922. index of the first ace inserted in the acl. 0 for the
  1923. beginning of the list and MAXULONG for the end of the list.
  1924. pAceList - Supplies the list of Aces to be added to the Acl
  1925. nAceListLength - Supplies the size, in bytes, of the AceList
  1926. buffer
  1927. Return Value:
  1928. Returns TRUE for success, FALSE for failure. Extended error status
  1929. is available using GetLastError.
  1930. --*/
  1931. {
  1932. NTSTATUS Status;
  1933. Status = RtlAddAce (
  1934. pAcl,
  1935. dwAceRevision,
  1936. dwStartingAceIndex,
  1937. pAceList,
  1938. nAceListLength
  1939. );
  1940. if ( !NT_SUCCESS(Status) ) {
  1941. BaseSetLastNTError(Status);
  1942. return FALSE;
  1943. }
  1944. return TRUE;
  1945. }
  1946. BOOL
  1947. APIENTRY
  1948. DeleteAce (
  1949. PACL pAcl,
  1950. DWORD dwAceIndex
  1951. )
  1952. /*++
  1953. Routine Description:
  1954. This routine deletes one ACE from an ACL.
  1955. Arguments:
  1956. pAcl - Supplies the Acl being modified
  1957. dwAceIndex - Supplies the index of the Ace to delete.
  1958. Return Value:
  1959. Returns TRUE for success, FALSE for failure. Extended error status
  1960. is available using GetLastError.
  1961. --*/
  1962. {
  1963. NTSTATUS Status;
  1964. Status = RtlDeleteAce (
  1965. pAcl,
  1966. dwAceIndex
  1967. );
  1968. if ( !NT_SUCCESS(Status) ) {
  1969. BaseSetLastNTError(Status);
  1970. return FALSE;
  1971. }
  1972. return TRUE;
  1973. }
  1974. BOOL
  1975. APIENTRY
  1976. GetAce (
  1977. PACL pAcl,
  1978. DWORD dwAceIndex,
  1979. PVOID *pAce
  1980. )
  1981. /*++
  1982. Routine Description:
  1983. This routine returns a pointer to an ACE in an ACl referenced by
  1984. ACE index
  1985. Arguments:
  1986. pAcl - Supplies the ACL being queried
  1987. dwAceIndex - Supplies the Ace index to locate
  1988. pAce - Receives the address of the ACE within the ACL
  1989. Return Value:
  1990. Returns TRUE for success, FALSE for failure. Extended error status
  1991. is available using GetLastError.
  1992. --*/
  1993. {
  1994. NTSTATUS Status;
  1995. Status = RtlGetAce (
  1996. pAcl,
  1997. dwAceIndex,
  1998. pAce
  1999. );
  2000. if ( !NT_SUCCESS(Status) ) {
  2001. BaseSetLastNTError(Status);
  2002. return FALSE;
  2003. }
  2004. return TRUE;
  2005. }
  2006. BOOL
  2007. APIENTRY
  2008. AddAccessAllowedAce (
  2009. PACL pAcl,
  2010. DWORD dwAceRevision,
  2011. DWORD AccessMask,
  2012. PSID pSid
  2013. )
  2014. /*++
  2015. Routine Description:
  2016. This routine adds an ACCESS_ALLOWED ACE to an ACL. This is
  2017. expected to be a common form of ACL modification.
  2018. A very bland ACE header is placed in the ACE. It provides no
  2019. inheritance and no ACE flags.
  2020. Arguments:
  2021. PAcl - Supplies the Acl being modified
  2022. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  2023. AccessMask - The mask of accesses to be granted to the specified SID.
  2024. pSid - Pointer to the SID being granted access.
  2025. Return Value:
  2026. Returns TRUE for success, FALSE for failure. Extended error status
  2027. is available using GetLastError.
  2028. --*/
  2029. {
  2030. NTSTATUS Status;
  2031. Status = RtlAddAccessAllowedAce (
  2032. pAcl,
  2033. dwAceRevision,
  2034. AccessMask,
  2035. pSid
  2036. );
  2037. if ( !NT_SUCCESS(Status) ) {
  2038. BaseSetLastNTError(Status);
  2039. return FALSE;
  2040. }
  2041. return TRUE;
  2042. }
  2043. BOOL
  2044. APIENTRY
  2045. AddAccessDeniedAce (
  2046. PACL pAcl,
  2047. DWORD dwAceRevision,
  2048. DWORD AccessMask,
  2049. PSID pSid
  2050. )
  2051. /*++
  2052. Routine Description:
  2053. This routine adds an ACCESS_DENIED ACE to an ACL. This is
  2054. expected to be a common form of ACL modification.
  2055. A very bland ACE header is placed in the ACE. It provides no
  2056. inheritance and no ACE flags.
  2057. Arguments:
  2058. pAcl - Supplies the Acl being modified
  2059. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  2060. AccessMask - The mask of accesses to be denied to the specified SID.
  2061. pSid - Pointer to the SID being denied access.
  2062. Return Value:
  2063. Returns TRUE for success, FALSE for failure. Extended error status
  2064. is available using GetLastError.
  2065. --*/
  2066. {
  2067. NTSTATUS Status;
  2068. Status = RtlAddAccessDeniedAce (
  2069. pAcl,
  2070. dwAceRevision,
  2071. AccessMask,
  2072. pSid
  2073. );
  2074. if ( !NT_SUCCESS(Status) ) {
  2075. BaseSetLastNTError(Status);
  2076. return FALSE;
  2077. }
  2078. return TRUE;
  2079. }
  2080. BOOL
  2081. APIENTRY
  2082. AddAuditAccessAce(
  2083. PACL pAcl,
  2084. DWORD dwAceRevision,
  2085. DWORD dwAccessMask,
  2086. PSID pSid,
  2087. BOOL bAuditSuccess,
  2088. BOOL bAuditFailure
  2089. )
  2090. /*++
  2091. Routine Description:
  2092. This routine adds a SYSTEM_AUDIT ACE to an ACL. This is
  2093. expected to be a common form of ACL modification.
  2094. A very bland ACE header is placed in the ACE. It provides no
  2095. inheritance.
  2096. Parameters are used to indicate whether auditing is to be performed
  2097. on success, failure, or both.
  2098. Arguments:
  2099. pAcl - Supplies the Acl being modified
  2100. dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
  2101. dwAccessMask - The mask of accesses to be denied to the specified SID.
  2102. pSid - Pointer to the SID to be audited.
  2103. bAuditSuccess - If TRUE, indicates successful access attempts are to be
  2104. audited.
  2105. bAuditFailure - If TRUE, indicated failed access attempts are to be
  2106. audited.
  2107. Return Value:
  2108. Returns TRUE for success, FALSE for failure. Extended error status
  2109. is available using GetLastError.
  2110. --*/
  2111. {
  2112. NTSTATUS Status;
  2113. Status = RtlAddAuditAccessAce (
  2114. pAcl,
  2115. dwAceRevision,
  2116. dwAccessMask,
  2117. pSid,
  2118. (BOOLEAN)bAuditSuccess,
  2119. (BOOLEAN)bAuditFailure
  2120. );
  2121. if ( !NT_SUCCESS(Status) ) {
  2122. BaseSetLastNTError(Status);
  2123. return FALSE;
  2124. }
  2125. return TRUE;
  2126. }
  2127. BOOL
  2128. APIENTRY
  2129. FindFirstFreeAce (
  2130. PACL pAcl,
  2131. PVOID *pAce
  2132. )
  2133. /*++
  2134. Routine Description:
  2135. This routine returns a pointer to the first free byte in an Acl
  2136. or NULL if the acl is ill-formed. If the Acl is full then the
  2137. return pointer is to the byte immediately following the acl, and
  2138. TRUE will be returned.
  2139. Arguments:
  2140. pAcl - Supplies a pointer to the Acl to examine
  2141. pAce - Receives a pointer to the first free position in the Acl
  2142. Return Value:
  2143. Returns TRUE for success, FALSE for failure. Extended error status
  2144. is available using GetLastError.
  2145. --*/
  2146. {
  2147. return (BOOL) RtlFirstFreeAce (
  2148. pAcl,
  2149. pAce
  2150. );
  2151. }
  2152. BOOL
  2153. APIENTRY
  2154. InitializeSecurityDescriptor (
  2155. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2156. DWORD dwRevision
  2157. )
  2158. /*++
  2159. Routine Description:
  2160. This procedure initializes a new "absolute format" security descriptor.
  2161. After the procedure call the security descriptor is initialized with no
  2162. system ACL, no discretionary ACL, no owner, no primary group and
  2163. all control flags set to false (null).
  2164. Arguments:
  2165. pSecurityDescriptor - Supplies the security descriptor to
  2166. initialize.
  2167. dwRevision - Provides the revision level to assign to the security
  2168. descriptor. This should be one (1) for this release.
  2169. Return Value:
  2170. Returns TRUE for success, FALSE for failure. Extended error status
  2171. is available using GetLastError.
  2172. --*/
  2173. {
  2174. NTSTATUS Status;
  2175. Status = RtlCreateSecurityDescriptor (
  2176. pSecurityDescriptor,
  2177. dwRevision
  2178. );
  2179. if ( !NT_SUCCESS(Status) ) {
  2180. BaseSetLastNTError(Status);
  2181. return FALSE;
  2182. }
  2183. return TRUE;
  2184. }
  2185. BOOL
  2186. APIENTRY
  2187. IsValidSecurityDescriptor (
  2188. PSECURITY_DESCRIPTOR pSecurityDescriptor
  2189. )
  2190. /*++
  2191. Routine Description:
  2192. This procedure validates a SecurityDescriptor's structure. This
  2193. involves validating the revision levels of each component of the
  2194. security descriptor.
  2195. Arguments:
  2196. pSecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
  2197. to validate.
  2198. Return Value:
  2199. BOOL - TRUE if the structure of SecurityDescriptor is valid.
  2200. --*/
  2201. {
  2202. if (!RtlValidSecurityDescriptor ( pSecurityDescriptor )) {
  2203. BaseSetLastNTError( STATUS_INVALID_SECURITY_DESCR );
  2204. return( FALSE );
  2205. }
  2206. return( TRUE );
  2207. }
  2208. DWORD
  2209. APIENTRY
  2210. GetSecurityDescriptorLength (
  2211. PSECURITY_DESCRIPTOR pSecurityDescriptor
  2212. )
  2213. /*++
  2214. Routine Description:
  2215. This routine returns the length, in bytes, necessary to capture a
  2216. structurally valid SECURITY_DESCRIPTOR. The length includes the length
  2217. of all associated data structures (like SIDs and ACLs). The length also
  2218. takes into account the alignment requirements of each component.
  2219. The minimum length of a security descriptor (one which has no associated
  2220. SIDs or ACLs) is SECURITY_DESCRIPTOR_MIN_LENGTH.
  2221. Arguments:
  2222. pSecurityDescriptor - Points to the SECURITY_DESCRIPTOR whose
  2223. length is to be returned. The SECURITY_DESCRIPTOR's structure
  2224. is assumed to be valid.
  2225. Return Value:
  2226. DWORD - The length, in bytes, of the SECURITY_DESCRIPTOR.
  2227. --*/
  2228. {
  2229. return RtlLengthSecurityDescriptor (
  2230. pSecurityDescriptor
  2231. );
  2232. }
  2233. BOOL
  2234. APIENTRY
  2235. GetSecurityDescriptorControl (
  2236. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2237. PSECURITY_DESCRIPTOR_CONTROL pControl,
  2238. LPDWORD lpdwRevision
  2239. )
  2240. /*++
  2241. Routine Description:
  2242. This procedure retrieves the control information from a security descriptor.
  2243. Arguments:
  2244. pSecurityDescriptor - Supplies the security descriptor.
  2245. pControl - Receives the control information.
  2246. lpdwRevision - Receives the revision of the security descriptor.
  2247. This value will always be returned, even if an error is
  2248. returned by this routine.
  2249. Return Value:
  2250. Returns TRUE for success, FALSE for failure. Extended error status
  2251. is available using GetLastError.
  2252. --*/
  2253. {
  2254. NTSTATUS Status;
  2255. Status = RtlGetControlSecurityDescriptor (
  2256. pSecurityDescriptor,
  2257. pControl,
  2258. lpdwRevision
  2259. );
  2260. if ( !NT_SUCCESS(Status) ) {
  2261. BaseSetLastNTError(Status);
  2262. return FALSE;
  2263. }
  2264. return TRUE;
  2265. }
  2266. BOOL
  2267. APIENTRY
  2268. SetSecurityDescriptorDacl (
  2269. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2270. BOOL bDaclPresent,
  2271. PACL pDacl OPTIONAL,
  2272. BOOL bDaclDefaulted OPTIONAL
  2273. )
  2274. /*++
  2275. Routine Description:
  2276. This procedure sets the discretionary ACL information of an absolute
  2277. format security descriptor. If there is already a discretionary ACL
  2278. present in the security descriptor, it is superseded.
  2279. Arguments:
  2280. pSecurityDescriptor - Supplies the security descriptor to be which
  2281. the discretionary ACL is to be added.
  2282. bDaclPresent - If FALSE, indicates the DaclPresent flag in the
  2283. security descriptor should be set to FALSE. In this case, the
  2284. remaining optional parameters are ignored. Otherwise, the
  2285. DaclPresent control flag in the security descriptor is set to
  2286. TRUE and the remaining optional parameters are not ignored.
  2287. pDacl - Supplies the discretionary ACL for the security
  2288. descriptor. If this optional parameter is not passed, then a
  2289. null ACL is assigned to the security descriptor. A null
  2290. discretionary ACL unconditionally grants access. The ACL is
  2291. referenced by, not copied into, by the security descriptor.
  2292. bDaclDefaulted - When set, indicates the discretionary ACL was
  2293. picked up from some default mechanism (rather than explicitly
  2294. specified by a user). This value is set in the DaclDefaulted
  2295. control flag in the security descriptor. If this optional
  2296. parameter is not passed, then the DaclDefaulted flag will be
  2297. cleared.
  2298. Return Value:
  2299. Returns TRUE for success, FALSE for failure. Extended error status
  2300. is available using GetLastError.
  2301. --*/
  2302. {
  2303. NTSTATUS Status;
  2304. Status = RtlSetDaclSecurityDescriptor (
  2305. pSecurityDescriptor,
  2306. (BOOLEAN)bDaclPresent,
  2307. pDacl,
  2308. (BOOLEAN)bDaclDefaulted
  2309. );
  2310. if ( !NT_SUCCESS(Status) ) {
  2311. BaseSetLastNTError(Status);
  2312. return FALSE;
  2313. }
  2314. return TRUE;
  2315. }
  2316. BOOL
  2317. APIENTRY
  2318. GetSecurityDescriptorDacl (
  2319. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2320. LPBOOL lpbDaclPresent,
  2321. PACL *pDacl,
  2322. LPBOOL lpbDaclDefaulted
  2323. )
  2324. /*++
  2325. Routine Description:
  2326. This procedure retrieves the discretionary ACL information of a
  2327. security descriptor.
  2328. Arguments:
  2329. pSecurityDescriptor - Supplies the security descriptor.
  2330. lpbDaclPresent - If TRUE, indicates that the security descriptor
  2331. does contain a discretionary ACL. In this case, the
  2332. remaining OUT parameters will receive valid values.
  2333. Otherwise, the security descriptor does not contain a
  2334. discretionary ACL and the remaining OUT parameters will not
  2335. receive valid values.
  2336. pDacl - This value is returned only if the value returned for the
  2337. DaclPresent flag is TRUE. In this case, the Dacl parameter
  2338. receives the address of the security descriptor's
  2339. discretionary ACL. If this value is returned as null, then
  2340. the security descriptor has a null discretionary ACL.
  2341. lpbDaclDefaulted - This value is returned only if the value
  2342. returned for the DaclPresent flag is TRUE. In this case, the
  2343. DaclDefaulted parameter receives the value of the security
  2344. descriptor's DaclDefaulted control flag.
  2345. Return Value:
  2346. Returns TRUE for success, FALSE for failure. Extended error status
  2347. is available using GetLastError.
  2348. --*/
  2349. {
  2350. NTSTATUS Status;
  2351. BOOLEAN DaclPresent, DaclDefaulted;
  2352. Status = RtlGetDaclSecurityDescriptor (
  2353. pSecurityDescriptor,
  2354. &DaclPresent,
  2355. pDacl,
  2356. &DaclDefaulted
  2357. );
  2358. *lpbDaclPresent = (BOOL)DaclPresent;
  2359. *lpbDaclDefaulted = (BOOL)DaclDefaulted;
  2360. if ( !NT_SUCCESS(Status) ) {
  2361. BaseSetLastNTError(Status);
  2362. return FALSE;
  2363. }
  2364. return TRUE;
  2365. }
  2366. BOOL
  2367. APIENTRY
  2368. SetSecurityDescriptorSacl (
  2369. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2370. BOOL bSaclPresent,
  2371. PACL pSacl OPTIONAL,
  2372. BOOL bSaclDefaulted
  2373. )
  2374. /*++
  2375. Routine Description:
  2376. This procedure sets the system ACL information of an absolute security
  2377. descriptor. If there is already a system ACL present in the
  2378. security descriptor, it is superseded.
  2379. Arguments:
  2380. pSecurityDescriptor - Supplies the security descriptor to be which
  2381. the system ACL is to be added.
  2382. bSaclPresent - If FALSE, indicates the SaclPresent flag in the
  2383. security descriptor should be set to FALSE. In this case,
  2384. the remaining optional parameters are ignored. Otherwise,
  2385. the SaclPresent control flag in the security descriptor is
  2386. set to TRUE and the remaining optional parameters are not
  2387. ignored.
  2388. pSacl - Supplies the system ACL for the security descriptor. If
  2389. this optional parameter is not passed, then a null ACL is
  2390. assigned to the security descriptor. The ACL is referenced
  2391. by, not copied into, by the security descriptor.
  2392. bSaclDefaulted - When set, indicates the system ACL was picked up
  2393. from some default mechanism (rather than explicitly specified
  2394. by a user). This value is set in the SaclDefaulted control
  2395. flag in the security descriptor. If this optional parameter
  2396. is not passed, then the SaclDefaulted flag will be cleared.
  2397. Return Value:
  2398. Returns TRUE for success, FALSE for failure. Extended error status
  2399. is available using GetLastError.
  2400. --*/
  2401. {
  2402. NTSTATUS Status;
  2403. Status = RtlSetSaclSecurityDescriptor (
  2404. pSecurityDescriptor,
  2405. (BOOLEAN)bSaclPresent,
  2406. pSacl,
  2407. (BOOLEAN)bSaclDefaulted
  2408. );
  2409. if ( !NT_SUCCESS(Status) ) {
  2410. BaseSetLastNTError(Status);
  2411. return FALSE;
  2412. }
  2413. return TRUE;
  2414. }
  2415. BOOL
  2416. APIENTRY
  2417. GetSecurityDescriptorSacl (
  2418. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2419. LPBOOL lpbSaclPresent,
  2420. PACL *pSacl,
  2421. LPBOOL lpbSaclDefaulted
  2422. )
  2423. /*++
  2424. Routine Description:
  2425. This procedure retrieves the system ACL information of a security
  2426. descriptor.
  2427. Arguments:
  2428. pSecurityDescriptor - Supplies the security descriptor.
  2429. lpbSaclPresent - If TRUE, indicates that the security descriptor
  2430. does contain a system ACL. In this case, the remaining OUT
  2431. parameters will receive valid values. Otherwise, the
  2432. security descriptor does not contain a system ACL and the
  2433. remaining OUT parameters will not receive valid values.
  2434. pSacl - This value is returned only if the value returned for the
  2435. SaclPresent flag is TRUE. In this case, the Sacl parameter
  2436. receives the address of the security descriptor's system ACL.
  2437. If this value is returned as null, then the security
  2438. descriptor has a null system ACL.
  2439. lpbSaclDefaulted - This value is returned only if the value
  2440. returned for the SaclPresent flag is TRUE. In this case, the
  2441. SaclDefaulted parameter receives the value of the security
  2442. descriptor's SaclDefaulted control flag.
  2443. Return Value:
  2444. Returns TRUE for success, FALSE for failure. Extended error status
  2445. is available using GetLastError.
  2446. --*/
  2447. {
  2448. NTSTATUS Status;
  2449. BOOLEAN SaclPresent, SaclDefaulted;
  2450. Status = RtlGetSaclSecurityDescriptor (
  2451. pSecurityDescriptor,
  2452. &SaclPresent,
  2453. pSacl,
  2454. &SaclDefaulted
  2455. );
  2456. *lpbSaclPresent = (BOOL)SaclPresent;
  2457. *lpbSaclDefaulted = (BOOL)SaclDefaulted;
  2458. if ( !NT_SUCCESS(Status) ) {
  2459. BaseSetLastNTError(Status);
  2460. return FALSE;
  2461. }
  2462. return TRUE;
  2463. }
  2464. BOOL
  2465. APIENTRY
  2466. SetSecurityDescriptorOwner (
  2467. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2468. PSID pOwner OPTIONAL,
  2469. BOOL bOwnerDefaulted OPTIONAL
  2470. )
  2471. /*++
  2472. Routine Description:
  2473. This procedure sets the owner information of an absolute security
  2474. descriptor. If there is already an owner present in the security
  2475. descriptor, it is superseded.
  2476. Arguments:
  2477. pSecurityDescriptor - Supplies the security descriptor in which
  2478. the owner is to be set. If the security descriptor already
  2479. includes an owner, it will be superseded by the new owner.
  2480. pOwner - Supplies the owner SID for the security descriptor. If
  2481. this optional parameter is not passed, then the owner is
  2482. cleared (indicating the security descriptor has no owner).
  2483. The SID is referenced by, not copied into, the security
  2484. descriptor.
  2485. bOwnerDefaulted - When set, indicates the owner was picked up from
  2486. some default mechanism (rather than explicitly specified by a
  2487. user). This value is set in the OwnerDefaulted control flag
  2488. in the security descriptor. If this optional parameter is
  2489. not passed, then the SaclDefaulted flag will be cleared.
  2490. Return Value:
  2491. Returns TRUE for success, FALSE for failure. Extended error status
  2492. is available using GetLastError.
  2493. --*/
  2494. {
  2495. NTSTATUS Status;
  2496. Status = RtlSetOwnerSecurityDescriptor (
  2497. pSecurityDescriptor,
  2498. pOwner,
  2499. (BOOLEAN)bOwnerDefaulted
  2500. );
  2501. if ( !NT_SUCCESS(Status) ) {
  2502. BaseSetLastNTError(Status);
  2503. return FALSE;
  2504. }
  2505. return TRUE;
  2506. }
  2507. BOOL
  2508. APIENTRY
  2509. GetSecurityDescriptorOwner (
  2510. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2511. PSID *pOwner,
  2512. LPBOOL lpbOwnerDefaulted
  2513. )
  2514. /*++
  2515. Routine Description:
  2516. This procedure retrieves the owner information of a security
  2517. descriptor.
  2518. Arguments:
  2519. pSecurityDescriptor - Supplies the security descriptor.
  2520. pOwner - Receives a pointer to the owner SID. If the security
  2521. descriptor does not currently contain an owner, then this
  2522. value will be returned as null. In this case, the remaining
  2523. OUT parameters are not given valid return values. Otherwise,
  2524. this parameter points to an SID and the remaining OUT
  2525. parameters are provided valid return values.
  2526. lpbOwnerDefaulted - This value is returned only if the value
  2527. returned for the Owner parameter is not null. In this case,
  2528. the OwnerDefaulted parameter receives the value of the
  2529. security descriptor's OwnerDefaulted control flag.
  2530. Return Value:
  2531. Returns TRUE for success, FALSE for failure. Extended error status
  2532. is available using GetLastError.
  2533. --*/
  2534. {
  2535. NTSTATUS Status;
  2536. BOOLEAN OwnerDefaulted;
  2537. Status = RtlGetOwnerSecurityDescriptor (
  2538. pSecurityDescriptor,
  2539. pOwner,
  2540. &OwnerDefaulted
  2541. );
  2542. *lpbOwnerDefaulted = (BOOL)OwnerDefaulted;
  2543. if ( !NT_SUCCESS(Status) ) {
  2544. BaseSetLastNTError(Status);
  2545. return FALSE;
  2546. }
  2547. return TRUE;
  2548. }
  2549. BOOL
  2550. APIENTRY
  2551. SetSecurityDescriptorGroup (
  2552. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2553. PSID pGroup OPTIONAL,
  2554. BOOL bGroupDefaulted OPTIONAL
  2555. )
  2556. /*++
  2557. Routine Description:
  2558. This procedure sets the primary group information of an absolute security
  2559. descriptor. If there is already an primary group present in the
  2560. security descriptor, it is superseded.
  2561. Arguments:
  2562. pSecurityDescriptor - Supplies the security descriptor in which
  2563. the primary group is to be set. If the security descriptor
  2564. already includes a primary group, it will be superseded by
  2565. the new group.
  2566. pGroup - Supplies the primary group SID for the security
  2567. descriptor. If this optional parameter is not passed, then
  2568. the primary group is cleared (indicating the security
  2569. descriptor has no primary group). The SID is referenced by,
  2570. not copied into, the security descriptor.
  2571. bGroupDefaulted - When set, indicates the owner was picked up from
  2572. some default mechanism (rather than explicitly specified by a
  2573. user). This value is set in the OwnerDefaulted control flag
  2574. in the security descriptor. If this optional parameter is
  2575. not passed, then the SaclDefaulted flag will be cleared.
  2576. Return Value:
  2577. Returns TRUE for success, FALSE for failure. Extended error status
  2578. is available using GetLastError.
  2579. --*/
  2580. {
  2581. NTSTATUS Status;
  2582. Status = RtlSetGroupSecurityDescriptor (
  2583. pSecurityDescriptor,
  2584. pGroup,
  2585. (BOOLEAN)bGroupDefaulted
  2586. );
  2587. if ( !NT_SUCCESS(Status) ) {
  2588. BaseSetLastNTError(Status);
  2589. return FALSE;
  2590. }
  2591. return TRUE;
  2592. }
  2593. BOOL
  2594. APIENTRY
  2595. GetSecurityDescriptorGroup (
  2596. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2597. PSID *pGroup,
  2598. LPBOOL lpbGroupDefaulted
  2599. )
  2600. /*++
  2601. Routine Description:
  2602. This procedure retrieves the primary group information of a
  2603. security descriptor.
  2604. Arguments:
  2605. pSecurityDescriptor - Supplies the security descriptor.
  2606. pGroup - Receives a pointer to the primary group SID. If the
  2607. security descriptor does not currently contain a primary
  2608. group, then this value will be returned as null. In this
  2609. case, the remaining OUT parameters are not given valid return
  2610. values. Otherwise, this parameter points to an SID and the
  2611. remaining OUT parameters are provided valid return values.
  2612. lpbGroupDefaulted - This value is returned only if the value
  2613. returned for the Group parameter is not null. In this case,
  2614. the GroupDefaulted parameter receives the value of the
  2615. security descriptor's GroupDefaulted control flag.
  2616. Return Value:
  2617. Returns TRUE for success, FALSE for failure. Extended error status
  2618. is available using GetLastError.
  2619. --*/
  2620. {
  2621. NTSTATUS Status;
  2622. BOOLEAN GroupDefaulted;
  2623. Status = RtlGetGroupSecurityDescriptor (
  2624. pSecurityDescriptor,
  2625. pGroup,
  2626. &GroupDefaulted
  2627. );
  2628. *lpbGroupDefaulted = GroupDefaulted;
  2629. if ( !NT_SUCCESS(Status) ) {
  2630. BaseSetLastNTError(Status);
  2631. return FALSE;
  2632. }
  2633. return TRUE;
  2634. }
  2635. BOOL
  2636. APIENTRY
  2637. CreatePrivateObjectSecurity (
  2638. PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
  2639. PSECURITY_DESCRIPTOR CreatorDescriptor OPTIONAL,
  2640. PSECURITY_DESCRIPTOR * NewDescriptor,
  2641. BOOL IsDirectoryObject,
  2642. HANDLE Token,
  2643. PGENERIC_MAPPING GenericMapping
  2644. )
  2645. /*++
  2646. Routine Description:
  2647. The procedure is used to allocpate and initialize a self-relative
  2648. Security Descriptor for a new protected server's object. It is called
  2649. when a new protected server object is being created. The generated
  2650. security descriptor will be in self-relative form.
  2651. This procedure, called only from user mode, is used to establish a
  2652. security descriptor for a new protected server's object. When no
  2653. longer needed, this descriptor must be freed using
  2654. DestroyPrivateObjectSecurity().
  2655. Arguments:
  2656. ParentDescriptor - Supplies the Security Descriptor for the parent
  2657. directory under which a new object is being created. If there is
  2658. no parent directory, then this argument is specified as NULL.
  2659. CreatorDescriptor - (Optionally) Points to a security descriptor
  2660. presented by the creator of the object. If the creator of the
  2661. object did not explicitly pass security information for the new
  2662. object, then a null pointer should be passed.
  2663. NewDescriptor - Points to a pointer that is to be made to point to the
  2664. newly allocated self-relative security descriptor.
  2665. IsDirectoryObject - Specifies if the new object is going to be a
  2666. directory object. A value of TRUE indicates the object is a
  2667. container of other objects.
  2668. Token - Supplies the token for the client on whose behalf the
  2669. object is being created. If it is an impersonation token,
  2670. then it must be at SecurityIdentification level or higher. If
  2671. it is not an impersonation token, the operation proceeds
  2672. normally.
  2673. A client token is used to retrieve default security
  2674. information for the new object, such as default owner, primary
  2675. group, and discretionary access control. The token must be
  2676. open for TOKEN_QUERY access.
  2677. GenericMapping - Supplies a pointer to a generic mapping array denoting
  2678. the mapping between each generic right to specific rights.
  2679. Return Value:
  2680. Returns TRUE for success, FALSE for failure. Extended error status
  2681. is available using GetLastError.
  2682. --*/
  2683. {
  2684. NTSTATUS Status;
  2685. Status = RtlNewSecurityObject (
  2686. ParentDescriptor,
  2687. CreatorDescriptor,
  2688. NewDescriptor,
  2689. (BOOLEAN)IsDirectoryObject,
  2690. Token,
  2691. GenericMapping
  2692. );
  2693. if ( !NT_SUCCESS(Status) ) {
  2694. BaseSetLastNTError(Status);
  2695. return FALSE;
  2696. }
  2697. return TRUE;
  2698. }
  2699. BOOL
  2700. APIENTRY
  2701. SetPrivateObjectSecurity (
  2702. SECURITY_INFORMATION SecurityInformation,
  2703. PSECURITY_DESCRIPTOR ModificationDescriptor,
  2704. PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
  2705. PGENERIC_MAPPING GenericMapping,
  2706. HANDLE Token OPTIONAL
  2707. )
  2708. /*++
  2709. Routine Description:
  2710. Modify an object's existing self-relative form security descriptor.
  2711. This procedure, called only from user mode, is used to update a
  2712. security descriptor on an existing protected server's object. It
  2713. applies changes requested by a new security descriptor to the existing
  2714. security descriptor. If necessary, this routine will allocate
  2715. additional memory to produce a larger security descriptor. All access
  2716. checking is expected to be done before calling this routine. This
  2717. includes checking for WRITE_OWNER, WRITE_DAC, and privilege to assign a
  2718. system ACL as appropriate.
  2719. The caller of this routine must not be impersonating a client.
  2720. Arguments:
  2721. SecurityInformation - Indicates which security information is
  2722. to be applied to the object. The value(s) to be assigned are
  2723. passed in the ModificationDescriptor parameter.
  2724. ModificationDescriptor - Supplies the input security descriptor to be
  2725. applied to the object. The caller of this routine is expected
  2726. to probe and capture the passed security descriptor before calling
  2727. and release it after calling.
  2728. ObjectsSecurityDescriptor - Supplies the address of a pointer to
  2729. the objects security descriptor that is going to be altered by
  2730. this procedure. This security descriptor must be in self-
  2731. relative form or an error will be returned.
  2732. GenericMapping - This argument provides the mapping of generic to
  2733. specific/standard access types for the object being accessed.
  2734. This mapping structure is expected to be safe to access
  2735. (i.e., captured if necessary) prior to be passed to this routine.
  2736. Token - (optionally) Supplies the token for the client on whose
  2737. behalf the security is being modified. This parameter is only
  2738. required to ensure that the client has provided a legitimate
  2739. value for a new owner SID. The token must be open for
  2740. TOKEN_QUERY access.
  2741. Return Value:
  2742. Returns TRUE for success, FALSE for failure. Extended error status
  2743. is available using GetLastError.
  2744. --*/
  2745. {
  2746. NTSTATUS Status;
  2747. Status = RtlSetSecurityObject (
  2748. SecurityInformation,
  2749. ModificationDescriptor,
  2750. ObjectsSecurityDescriptor,
  2751. GenericMapping,
  2752. Token
  2753. );
  2754. if ( !NT_SUCCESS(Status) ) {
  2755. BaseSetLastNTError(Status);
  2756. return FALSE;
  2757. }
  2758. return TRUE;
  2759. }
  2760. BOOL
  2761. APIENTRY
  2762. GetPrivateObjectSecurity (
  2763. PSECURITY_DESCRIPTOR ObjectDescriptor,
  2764. SECURITY_INFORMATION SecurityInformation,
  2765. PSECURITY_DESCRIPTOR ResultantDescriptor,
  2766. DWORD DescriptorLength,
  2767. PDWORD ReturnLength
  2768. )
  2769. /*++
  2770. Routine Description:
  2771. Query information from a protected server object's existing security
  2772. descriptor.
  2773. This procedure, called only from user mode, is used to retrieve
  2774. information from a security descriptor on an existing protected
  2775. server's object. All access checking is expected to be done before
  2776. calling this routine. This includes checking for READ_CONTROL, and
  2777. privilege to read a system ACL as appropriate.
  2778. Arguments:
  2779. ObjectDescriptor - Points to a pointer to a security descriptor to be
  2780. queried.
  2781. SecurityInformation - Identifies the security information being
  2782. requested.
  2783. ResultantDescriptor - Points to buffer to receive the resultant
  2784. security descriptor. The resultant security descriptor will
  2785. contain all information requested by the SecurityInformation
  2786. parameter.
  2787. DescriptorLength - Is an unsigned integer which indicates the length,
  2788. in bytes, of the buffer provided to receive the resultant
  2789. descriptor.
  2790. ReturnLength - Receives an unsigned integer indicating the actual
  2791. number of bytes needed in the ResultantDescriptor to store the
  2792. requested information. If the value returned is greater than the
  2793. value passed via the DescriptorLength parameter, then
  2794. STATUS_BUFFER_TOO_SMALL is returned and no information is returned.
  2795. Return Value:
  2796. Returns TRUE for success, FALSE for failure. Extended error status
  2797. is available using GetLastError.
  2798. --*/
  2799. {
  2800. NTSTATUS Status;
  2801. Status = RtlQuerySecurityObject (
  2802. ObjectDescriptor,
  2803. SecurityInformation,
  2804. ResultantDescriptor,
  2805. DescriptorLength,
  2806. ReturnLength
  2807. );
  2808. if ( !NT_SUCCESS(Status) ) {
  2809. BaseSetLastNTError(Status);
  2810. return FALSE;
  2811. }
  2812. return TRUE;
  2813. }
  2814. BOOL
  2815. APIENTRY
  2816. DestroyPrivateObjectSecurity (
  2817. PSECURITY_DESCRIPTOR * ObjectDescriptor
  2818. )
  2819. /*++
  2820. Routine Description:
  2821. Delete a protected server object's security descriptor.
  2822. This procedure, called only from user mode, is used to delete a
  2823. security descriptor associated with a protected server's object. This
  2824. routine will normally be called by a protected server during object
  2825. deletion. The input descriptor is expected to be one created via
  2826. a call to CreatePrivateObjectSecurity.
  2827. Arguments:
  2828. ObjectDescriptor - Points to a pointer to a security descriptor to be
  2829. deleted.
  2830. Return Value:
  2831. Returns TRUE for success, FALSE for failure. Extended error status
  2832. is available using GetLastError.
  2833. --*/
  2834. {
  2835. NTSTATUS Status;
  2836. Status = RtlDeleteSecurityObject (
  2837. ObjectDescriptor
  2838. );
  2839. if ( !NT_SUCCESS(Status) ) {
  2840. BaseSetLastNTError(Status);
  2841. return FALSE;
  2842. }
  2843. return TRUE;
  2844. }
  2845. BOOL
  2846. APIENTRY
  2847. MakeSelfRelativeSD (
  2848. PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
  2849. PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
  2850. LPDWORD lpdwBufferLength
  2851. )
  2852. /*++
  2853. Routine Description:
  2854. Converts a security descriptor in absolute form to one in self-relative
  2855. form.
  2856. Arguments:
  2857. pAbsoluteSecurityDescriptor - Pointer to an absolute format
  2858. security descriptor. This descriptor will not be modified.
  2859. pSelfRelativeSecurityDescriptor - Pointer to a buffer that will
  2860. contain the returned self-relative security descriptor.
  2861. lpdwBufferLength - Supplies the length of the buffer. If the
  2862. supplied buffer is not large enough to hold the self-relative
  2863. security descriptor, an error will be returned, and this field
  2864. will return the minimum size required.
  2865. Return Value:
  2866. Returns TRUE for success, FALSE for failure. Extended error status
  2867. is available using GetLastError.
  2868. --*/
  2869. {
  2870. NTSTATUS Status;
  2871. Status = RtlAbsoluteToSelfRelativeSD (
  2872. pAbsoluteSecurityDescriptor,
  2873. pSelfRelativeSecurityDescriptor,
  2874. lpdwBufferLength
  2875. );
  2876. if ( !NT_SUCCESS(Status) ) {
  2877. BaseSetLastNTError(Status);
  2878. return FALSE;
  2879. }
  2880. return TRUE;
  2881. }
  2882. BOOL
  2883. APIENTRY
  2884. MakeAbsoluteSD (
  2885. PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
  2886. PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
  2887. LPDWORD lpdwAbsoluteSecurityDescriptorSize,
  2888. PACL pDacl,
  2889. LPDWORD lpdwDaclSize,
  2890. PACL pSacl,
  2891. LPDWORD lpdwSaclSize,
  2892. PSID pOwner,
  2893. LPDWORD lpdwOwnerSize,
  2894. PSID pPrimaryGroup,
  2895. LPDWORD lpdwPrimaryGroupSize
  2896. )
  2897. /*++
  2898. Routine Description:
  2899. Converts a security descriptor from self-relative format to absolute
  2900. format
  2901. Arguments:
  2902. pSecurityDescriptor - Supplies a pointer to a security descriptor
  2903. in Self-Relative format
  2904. pAbsoluteSecurityDescriptor - A pointer to a buffer in which will
  2905. be placed the main body of the Absolute format security
  2906. descriptor.
  2907. lpdwAbsoluteSecurityDescriptorSize - The size in bytes of the
  2908. buffer pointed to by pAbsoluteSecurityDescriptor.
  2909. pDacl - Supplies a pointer to a buffer that will contain the Dacl
  2910. of the output descriptor. This pointer will be referenced by,
  2911. not copied into, the output descriptor.
  2912. lpdwDaclSize - Supplies the size of the buffer pointed to by Dacl.
  2913. In case of error, it will return the minimum size necessary to
  2914. contain the Dacl.
  2915. pSacl - Supplies a pointer to a buffer that will contain the Sacl
  2916. of the output descriptor. This pointer will be referenced by,
  2917. not copied into, the output descriptor.
  2918. lpdwSaclSize - Supplies the size of the buffer pointed to by Sacl.
  2919. In case of error, it will return the minimum size necessary to
  2920. contain the Sacl.
  2921. pOwner - Supplies a pointer to a buffer that will contain the
  2922. Owner of the output descriptor. This pointer will be
  2923. referenced by, not copied into, the output descriptor.
  2924. lpdwOwnerSize - Supplies the size of the buffer pointed to by
  2925. Owner. In case of error, it will return the minimum size
  2926. necessary to contain the Owner.
  2927. pPrimaryGroup - Supplies a pointer to a buffer that will contain
  2928. the PrimaryGroup of the output descriptor. This pointer will
  2929. be referenced by, not copied into, the output descriptor.
  2930. lpdwPrimaryGroupSize - Supplies the size of the buffer pointed to
  2931. by PrimaryGroup. In case of error, it will return the minimum
  2932. size necessary to contain the PrimaryGroup.
  2933. Return Value:
  2934. Returns TRUE for success, FALSE for failure. Extended error status
  2935. is available using GetLastError.
  2936. --*/
  2937. {
  2938. NTSTATUS Status;
  2939. Status = RtlSelfRelativeToAbsoluteSD (
  2940. pSelfRelativeSecurityDescriptor,
  2941. pAbsoluteSecurityDescriptor,
  2942. lpdwAbsoluteSecurityDescriptorSize,
  2943. pDacl,
  2944. lpdwDaclSize,
  2945. pSacl,
  2946. lpdwSaclSize,
  2947. pOwner,
  2948. lpdwOwnerSize,
  2949. pPrimaryGroup,
  2950. lpdwPrimaryGroupSize
  2951. );
  2952. if ( !NT_SUCCESS(Status) ) {
  2953. BaseSetLastNTError(Status);
  2954. return FALSE;
  2955. }
  2956. return TRUE;
  2957. }
  2958. VOID
  2959. SetSecurityAccessMask(
  2960. IN SECURITY_INFORMATION SecurityInformation,
  2961. OUT LPDWORD DesiredAccess
  2962. )
  2963. /*++
  2964. Routine Description:
  2965. This routine builds an access mask representing the accesses necessary
  2966. to set the object security information specified in the SecurityInformation
  2967. parameter. While it is not difficult to determine this information,
  2968. the use of a single routine to generate it will ensure minimal impact
  2969. when the security information associated with an object is extended in
  2970. the future (to include mandatory access control information).
  2971. Arguments:
  2972. SecurityInformation - Identifies the object's security information to be
  2973. modified.
  2974. DesiredAccess - Points to an access mask to be set to represent the
  2975. accesses necessary to modify the information specified in the
  2976. SecurityInformation parameter.
  2977. Return Value:
  2978. None.
  2979. --*/
  2980. {
  2981. //
  2982. // Figure out accesses needed to perform the indicated operation(s).
  2983. //
  2984. (*DesiredAccess) = 0;
  2985. if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
  2986. (SecurityInformation & GROUP_SECURITY_INFORMATION) ) {
  2987. (*DesiredAccess) |= WRITE_OWNER;
  2988. }
  2989. if (SecurityInformation & DACL_SECURITY_INFORMATION) {
  2990. (*DesiredAccess) |= WRITE_DAC;
  2991. }
  2992. if (SecurityInformation & SACL_SECURITY_INFORMATION) {
  2993. (*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
  2994. }
  2995. return;
  2996. }
  2997. VOID
  2998. QuerySecurityAccessMask(
  2999. IN SECURITY_INFORMATION SecurityInformation,
  3000. OUT LPDWORD DesiredAccess
  3001. )
  3002. /*++
  3003. Routine Description:
  3004. This routine builds an access mask representing the accesses necessary
  3005. to query the object security information specified in the
  3006. SecurityInformation parameter. While it is not difficult to determine
  3007. this information, the use of a single routine to generate it will ensure
  3008. minimal impact when the security information associated with an object is
  3009. extended in the future (to include mandatory access control information).
  3010. Arguments:
  3011. SecurityInformation - Identifies the object's security information to be
  3012. queried.
  3013. DesiredAccess - Points to an access mask to be set to represent the
  3014. accesses necessary to query the information specified in the
  3015. SecurityInformation parameter.
  3016. Return Value:
  3017. None.
  3018. --*/
  3019. {
  3020. //
  3021. // Figure out accesses needed to perform the indicated operation(s).
  3022. //
  3023. (*DesiredAccess) = 0;
  3024. if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
  3025. (SecurityInformation & GROUP_SECURITY_INFORMATION) ||
  3026. (SecurityInformation & DACL_SECURITY_INFORMATION)) {
  3027. (*DesiredAccess) |= READ_CONTROL;
  3028. }
  3029. if ((SecurityInformation & SACL_SECURITY_INFORMATION)) {
  3030. (*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
  3031. }
  3032. return;
  3033. }
  3034. BOOL
  3035. APIENTRY
  3036. SetFileSecurityW(
  3037. LPCWSTR lpFileName,
  3038. SECURITY_INFORMATION SecurityInformation,
  3039. PSECURITY_DESCRIPTOR pSecurityDescriptor
  3040. )
  3041. /*++
  3042. Routine Description:
  3043. This API can be used to set the security of a file or directory
  3044. (process, file, event, etc.). This call is only successful if the
  3045. following conditions are met:
  3046. o If the object's owner or group is to be set, the caller must
  3047. have WRITE_OWNER permission or have SeTakeOwnershipPrivilege.
  3048. o If the object's DACL is to be set, the caller must have
  3049. WRITE_DAC permission or be the object's owner.
  3050. o If the object's SACL is to be set, the caller must have
  3051. SeSecurityPrivilege.
  3052. Arguments:
  3053. lpFileName - Supplies the file name of the file to open. Depending on
  3054. the value of the FailIfExists parameter, this name may or may
  3055. not already exist.
  3056. SecurityInformation - A pointer to information describing the
  3057. contents of the Security Descriptor.
  3058. pSecurityDescriptor - A pointer to a well formed Security
  3059. Descriptor.
  3060. Return Value:
  3061. TRUE - The operation was successful.
  3062. FALSE/NULL - The operation failed. Extended error status is available
  3063. using GetLastError.
  3064. --*/
  3065. {
  3066. NTSTATUS Status;
  3067. HANDLE FileHandle;
  3068. ACCESS_MASK DesiredAccess;
  3069. OBJECT_ATTRIBUTES Obja;
  3070. UNICODE_STRING FileName;
  3071. BOOLEAN TranslationStatus;
  3072. RTL_RELATIVE_NAME RelativeName;
  3073. IO_STATUS_BLOCK IoStatusBlock;
  3074. PVOID FreeBuffer;
  3075. SetSecurityAccessMask(
  3076. SecurityInformation,
  3077. &DesiredAccess
  3078. );
  3079. TranslationStatus = RtlDosPathNameToNtPathName_U(
  3080. lpFileName,
  3081. &FileName,
  3082. NULL,
  3083. &RelativeName
  3084. );
  3085. if ( !TranslationStatus ) {
  3086. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  3087. return FALSE;
  3088. }
  3089. FreeBuffer = FileName.Buffer;
  3090. if ( RelativeName.RelativeName.Length ) {
  3091. FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  3092. }
  3093. else {
  3094. RelativeName.ContainingDirectory = NULL;
  3095. }
  3096. InitializeObjectAttributes(
  3097. &Obja,
  3098. &FileName,
  3099. OBJ_CASE_INSENSITIVE,
  3100. RelativeName.ContainingDirectory,
  3101. NULL
  3102. );
  3103. Status = NtOpenFile(
  3104. &FileHandle,
  3105. DesiredAccess,
  3106. &Obja,
  3107. &IoStatusBlock,
  3108. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3109. 0
  3110. );
  3111. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  3112. if ( !NT_SUCCESS( Status ) ) {
  3113. BaseSetLastNTError( Status );
  3114. return FALSE;
  3115. }
  3116. Status = NtSetSecurityObject(
  3117. FileHandle,
  3118. SecurityInformation,
  3119. pSecurityDescriptor
  3120. );
  3121. NtClose(FileHandle);
  3122. if (!NT_SUCCESS(Status)) {
  3123. BaseSetLastNTError(Status);
  3124. return FALSE;
  3125. }
  3126. return TRUE;
  3127. }
  3128. BOOL
  3129. APIENTRY
  3130. SetFileSecurityA(
  3131. LPCSTR lpFileName,
  3132. SECURITY_INFORMATION SecurityInformation,
  3133. PSECURITY_DESCRIPTOR pSecurityDescriptor
  3134. )
  3135. /*++
  3136. Routine Description:
  3137. ANSI thunk to SetFileSecurityW
  3138. --*/
  3139. {
  3140. PUNICODE_STRING Unicode;
  3141. ANSI_STRING AnsiString;
  3142. NTSTATUS Status;
  3143. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  3144. RtlInitAnsiString(&AnsiString,lpFileName);
  3145. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  3146. if ( !NT_SUCCESS(Status) ) {
  3147. BaseSetLastNTError(Status);
  3148. return FALSE;
  3149. }
  3150. return ( SetFileSecurityW( (LPCWSTR)Unicode->Buffer,
  3151. SecurityInformation,
  3152. pSecurityDescriptor
  3153. )
  3154. );
  3155. }
  3156. BOOL
  3157. APIENTRY
  3158. GetFileSecurityW(
  3159. LPCWSTR lpFileName,
  3160. SECURITY_INFORMATION RequestedInformation,
  3161. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3162. DWORD nLength,
  3163. LPDWORD lpnLengthNeeded
  3164. )
  3165. /*++
  3166. Routine Description:
  3167. This API returns top the caller a copy of the security descriptor
  3168. protecting a file or directory. Based on the caller's access
  3169. rights and privileges, this procedure will return a security
  3170. descriptor containing the requested security descriptor fields.
  3171. To read the handle's security descriptor the caller must be
  3172. granted READ_CONTROL access or be the owner of the object. In
  3173. addition, the caller must have SeSecurityPrivilege privilege to
  3174. read the system ACL.
  3175. Arguments:
  3176. lpFileName - Represents the name of the file or directory whose
  3177. security is being retrieved.
  3178. RequestedInformation - A pointer to the security information being
  3179. requested.
  3180. pSecurityDescriptor - A pointer to the buffer to receive a copy of
  3181. the secrity descriptor protecting the object that the caller
  3182. has the rigth to view. The security descriptor is returned in
  3183. self-relative format.
  3184. nLength - The size, in bytes, of the security descriptor buffer.
  3185. lpnLengthNeeded - A pointer to the variable to receive the number
  3186. of bytes needed to store the complete secruity descriptor. If
  3187. returned number of bytes is less than or equal to nLength then
  3188. the entire security descriptor is returned in the output
  3189. buffer, otherwise none of the descriptor is returned.
  3190. Return Value:
  3191. TRUE is returned for success, FALSE if access is denied or if the
  3192. buffer is too small to hold the security descriptor.
  3193. --*/
  3194. {
  3195. NTSTATUS Status;
  3196. HANDLE FileHandle;
  3197. ACCESS_MASK DesiredAccess;
  3198. OBJECT_ATTRIBUTES Obja;
  3199. UNICODE_STRING FileName;
  3200. BOOLEAN TranslationStatus;
  3201. RTL_RELATIVE_NAME RelativeName;
  3202. IO_STATUS_BLOCK IoStatusBlock;
  3203. PVOID FreeBuffer;
  3204. QuerySecurityAccessMask(
  3205. RequestedInformation,
  3206. &DesiredAccess
  3207. );
  3208. TranslationStatus = RtlDosPathNameToNtPathName_U(
  3209. lpFileName,
  3210. &FileName,
  3211. NULL,
  3212. &RelativeName
  3213. );
  3214. if ( !TranslationStatus ) {
  3215. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  3216. return FALSE;
  3217. }
  3218. FreeBuffer = FileName.Buffer;
  3219. if ( RelativeName.RelativeName.Length ) {
  3220. FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  3221. }
  3222. else {
  3223. RelativeName.ContainingDirectory = NULL;
  3224. }
  3225. InitializeObjectAttributes(
  3226. &Obja,
  3227. &FileName,
  3228. OBJ_CASE_INSENSITIVE,
  3229. RelativeName.ContainingDirectory,
  3230. NULL
  3231. );
  3232. Status = NtOpenFile(
  3233. &FileHandle,
  3234. DesiredAccess,
  3235. &Obja,
  3236. &IoStatusBlock,
  3237. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3238. 0
  3239. );
  3240. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  3241. if (NT_SUCCESS(Status)) {
  3242. Status = NtQuerySecurityObject(
  3243. FileHandle,
  3244. RequestedInformation,
  3245. pSecurityDescriptor,
  3246. nLength,
  3247. lpnLengthNeeded
  3248. );
  3249. NtClose(FileHandle);
  3250. }
  3251. if (!NT_SUCCESS(Status)) {
  3252. BaseSetLastNTError(Status);
  3253. return FALSE;
  3254. }
  3255. return TRUE;
  3256. }
  3257. BOOL
  3258. APIENTRY
  3259. GetFileSecurityA(
  3260. LPCSTR lpFileName,
  3261. SECURITY_INFORMATION RequestedInformation,
  3262. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3263. DWORD nLength,
  3264. LPDWORD lpnLengthNeeded
  3265. )
  3266. /*++
  3267. Routine Description:
  3268. ANSI thunk to GetFileSecurityW
  3269. --*/
  3270. {
  3271. PUNICODE_STRING Unicode;
  3272. ANSI_STRING AnsiString;
  3273. NTSTATUS Status;
  3274. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  3275. RtlInitAnsiString(&AnsiString,lpFileName);
  3276. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  3277. if ( !NT_SUCCESS(Status) ) {
  3278. BaseSetLastNTError(Status);
  3279. return FALSE;
  3280. }
  3281. return ( GetFileSecurityW( (LPCWSTR)Unicode->Buffer,
  3282. RequestedInformation,
  3283. pSecurityDescriptor,
  3284. nLength,
  3285. lpnLengthNeeded
  3286. )
  3287. );
  3288. }
  3289. BOOL
  3290. APIENTRY
  3291. SetKernelObjectSecurity (
  3292. HANDLE Handle,
  3293. SECURITY_INFORMATION SecurityInformation,
  3294. PSECURITY_DESCRIPTOR SecurityDescriptor
  3295. )
  3296. /*++
  3297. Routine Description:
  3298. This API can be used to set the security of a kernel object
  3299. (process, file, event, etc.). This call is only successful if the
  3300. following conditions are met:
  3301. o If the object's owner or group is to be set, the caller must
  3302. have WRITE_OWNER permission or have SeTakeOwnershipPrivilege.
  3303. o If the object's DACL is to be set, the caller must have
  3304. WRITE_DAC permission or be the object's owner.
  3305. o If the object's SACL is to be set, the caller must have
  3306. SeSecurityPrivilege.
  3307. Arguments:
  3308. Handle - Represents a handle of a kernel object.
  3309. SecurityInformation - A pointer to information describing the
  3310. contents of the Security Descriptor.
  3311. pSecurityDescriptor - A pointer to a well formed Security
  3312. Descriptor.
  3313. Return Value:
  3314. Returns TRUE for success, FALSE for failure. Extended error status
  3315. is available using GetLastError.
  3316. --*/
  3317. {
  3318. NTSTATUS Status;
  3319. Status = NtSetSecurityObject(
  3320. Handle,
  3321. SecurityInformation,
  3322. SecurityDescriptor
  3323. );
  3324. if ( !NT_SUCCESS(Status) ) {
  3325. BaseSetLastNTError(Status);
  3326. return FALSE;
  3327. }
  3328. return TRUE;
  3329. }
  3330. BOOL
  3331. APIENTRY
  3332. GetKernelObjectSecurity (
  3333. HANDLE Handle,
  3334. SECURITY_INFORMATION RequestedInformation,
  3335. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  3336. DWORD nLength,
  3337. LPDWORD lpnLengthNeeded
  3338. )
  3339. /*++
  3340. Routine Description:
  3341. This API returns top the caller a copy of the security descriptor
  3342. protecting a kernel object. Based on the caller's access rights
  3343. and privileges, this procedure will return a security descriptor
  3344. containing the requested security descriptor fields. To read the
  3345. handle's security descriptor the caller must be granted
  3346. READ_CONTROL access or be the owner of the object. In addition,
  3347. the caller must have SeSecurityPrivilege privilege to read the
  3348. system ACL.
  3349. Arguments:
  3350. Handle - Represents a handle of a kernel object.
  3351. RequestedInformation - A pointer to the security information being
  3352. requested.
  3353. pSecurityDescriptor - A pointer to the buffer to receive a copy of
  3354. the secrity descriptor protecting the object that the caller
  3355. has the rigth to view. The security descriptor is returned in
  3356. self-relative format.
  3357. nLength - The size, in bytes, of the security descriptor buffer.
  3358. lpnLengthNeeded - A pointer to the variable to receive the number
  3359. of bytes needed to store the complete secruity descriptor. If
  3360. returned number of bytes is less than or equal to nLength then
  3361. the entire security descriptor is returned in the output
  3362. buffer, otherwise none of the descriptor is returned.
  3363. Return Value:
  3364. return-value - Description of conditions needed to return value. - or -
  3365. None.
  3366. --*/
  3367. {
  3368. NTSTATUS Status;
  3369. Status = NtQuerySecurityObject(
  3370. Handle,
  3371. RequestedInformation,
  3372. pSecurityDescriptor,
  3373. nLength,
  3374. lpnLengthNeeded
  3375. );
  3376. if ( !NT_SUCCESS(Status) ) {
  3377. BaseSetLastNTError(Status);
  3378. return FALSE;
  3379. }
  3380. return TRUE;
  3381. }
  3382. BOOL
  3383. APIENTRY
  3384. ImpersonateNamedPipeClient(
  3385. IN HANDLE hNamedPipe
  3386. )
  3387. /*++
  3388. Routine Description:
  3389. Impersonate a named pipe client application.
  3390. Arguments:
  3391. hNamedPipe - Handle to a named pipe.
  3392. Return Value:
  3393. Returns TRUE for success, FALSE for failure. Extended error status
  3394. is available using GetLastError.
  3395. --*/
  3396. {
  3397. NTSTATUS Status;
  3398. IO_STATUS_BLOCK IoStatusBlock;
  3399. Status = NtFsControlFile(
  3400. hNamedPipe,
  3401. NULL,
  3402. NULL,
  3403. NULL,
  3404. &IoStatusBlock,
  3405. FSCTL_PIPE_IMPERSONATE,
  3406. NULL,
  3407. 0,
  3408. NULL,
  3409. 0
  3410. );
  3411. if ( !NT_SUCCESS(Status) ) {
  3412. BaseSetLastNTError(Status);
  3413. return FALSE;
  3414. }
  3415. return TRUE;
  3416. }
  3417. BOOL
  3418. APIENTRY
  3419. ImpersonateSelf(
  3420. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  3421. )
  3422. /*++
  3423. Routine Description:
  3424. This routine may be used to obtain an Impersonation token representing
  3425. your own process's context. This may be useful for enabling a privilege
  3426. for a single thread rather than for the entire process; or changing
  3427. the default DACL for a single thread.
  3428. The token is assigned to the callers thread.
  3429. Arguments:
  3430. ImpersonationLevel - The level to make the impersonation token.
  3431. Return Value:
  3432. Returns TRUE for success, FALSE for failure. Extended error status
  3433. is available using GetLastError.
  3434. --*/
  3435. {
  3436. NTSTATUS Status;
  3437. Status = RtlImpersonateSelf( ImpersonationLevel );
  3438. if ( !NT_SUCCESS(Status) ) {
  3439. BaseSetLastNTError(Status);
  3440. return FALSE;
  3441. }
  3442. return TRUE;
  3443. }
  3444. BOOL
  3445. APIENTRY
  3446. RevertToSelf (
  3447. VOID
  3448. )
  3449. /*++
  3450. Routine Description:
  3451. Terminate impersonation of a named pipe client application.
  3452. Arguments:
  3453. None.
  3454. Return Value:
  3455. Returns TRUE for success, FALSE for failure. Extended error status
  3456. is available using GetLastError.
  3457. --*/
  3458. {
  3459. HANDLE NewToken;
  3460. NTSTATUS Status;
  3461. NewToken = NULL;
  3462. Status = NtSetInformationThread(
  3463. NtCurrentThread(),
  3464. ThreadImpersonationToken,
  3465. (PVOID)&NewToken,
  3466. (ULONG)sizeof(HANDLE)
  3467. );
  3468. if ( !NT_SUCCESS(Status) ) {
  3469. BaseSetLastNTError(Status);
  3470. return FALSE;
  3471. }
  3472. return TRUE;
  3473. }
  3474. BOOL
  3475. APIENTRY
  3476. SetThreadToken (
  3477. PHANDLE Thread,
  3478. HANDLE Token
  3479. )
  3480. /*++
  3481. Routine Description:
  3482. Assigns the specified impersonation token to the specified
  3483. thread.
  3484. Arguments:
  3485. Thread - Specifies the thread whose token is to be assigned.
  3486. If NULL is specified, then the caller's thread is assumed.
  3487. Token - The token to assign. Must be open for TOKEN_IMPERSONATE
  3488. access. If null, then causes the specified thread to stop
  3489. impersonating.
  3490. Return Value:
  3491. Returns TRUE for success, FALSE for failure. Extended error status
  3492. is available using GetLastError.
  3493. --*/
  3494. {
  3495. NTSTATUS Status;
  3496. HANDLE TargetThread;
  3497. if (ARGUMENT_PRESENT(Thread)) {
  3498. TargetThread = (*Thread);
  3499. } else {
  3500. TargetThread = NtCurrentThread();
  3501. }
  3502. Status = NtSetInformationThread(
  3503. TargetThread,
  3504. ThreadImpersonationToken,
  3505. (PVOID)&Token,
  3506. (ULONG)sizeof(HANDLE)
  3507. );
  3508. if ( !NT_SUCCESS(Status) ) {
  3509. BaseSetLastNTError(Status);
  3510. return FALSE;
  3511. }
  3512. return TRUE;
  3513. }
  3514. BOOL
  3515. APIENTRY
  3516. LookupAccountNameA(
  3517. LPCSTR lpSystemName,
  3518. LPCSTR lpAccountName,
  3519. PSID Sid,
  3520. LPDWORD cbSid,
  3521. LPSTR ReferencedDomainName,
  3522. LPDWORD cbReferencedDomainName,
  3523. PSID_NAME_USE peUse
  3524. )
  3525. /*++
  3526. Routine Description:
  3527. ANSI Thunk to LookupAccountNameW
  3528. Arguments:
  3529. lpSystemName - Supplies the name of the system at which the lookup
  3530. is to be performed. If the null string is provided, the local
  3531. system is assumed.
  3532. lpAccountName - Supplies the account name.
  3533. Sid - Returns the SID corresponding to the passed account name.
  3534. cbSid - Supplies the size of the buffer passed in for Sid. If
  3535. the buffer size is not big enough, this parameter will
  3536. return the size necessary to hold the output Sid.
  3537. ReferencedDomainName - Returns the name of the domain in which the
  3538. name was found.
  3539. cbReferencedDomainName - Supplies the size (in Ansi characters) of the
  3540. ReferencedDomainName buffer. If the buffer size is not large
  3541. enough, this parameter will return the size necessary to hold
  3542. the null-terminated output domain name. If the buffer size is
  3543. large enough, tis parameter will return the size (in Ansi characters,
  3544. excluding the terminating null) of the Referenced Domain name.
  3545. peUse - Returns an enumerated type indicating the type of the
  3546. account.
  3547. Return Value:
  3548. BOOL - TRUE is returned if successful, else FALSE.
  3549. --*/
  3550. {
  3551. UNICODE_STRING Unicode;
  3552. UNICODE_STRING TmpUnicode;
  3553. ANSI_STRING AnsiString;
  3554. PWSTR WReferencedDomainName = NULL;
  3555. UNICODE_STRING SystemName;
  3556. PWSTR pSystemName = NULL;
  3557. NTSTATUS Status;
  3558. BOOL rc = TRUE;
  3559. DWORD cbInitReferencedDomainName;
  3560. Unicode.Buffer = NULL;
  3561. SystemName.Buffer = NULL;
  3562. //
  3563. // Save the original buffer size
  3564. //
  3565. cbInitReferencedDomainName = *cbReferencedDomainName;
  3566. //
  3567. // Convert the passed lpAccountName to a WCHAR string to be
  3568. // passed to the ..W routine. Note that we cannot use the
  3569. // StaticUnicodeString in the Thread Environment Block because
  3570. // this is used by LdrpWalkImportDescriptor, called from the
  3571. // client RPC stub code of the LsaOpenPolicy() call in
  3572. // LookupAccountNameW.
  3573. //
  3574. RtlInitAnsiString( &AnsiString, lpAccountName );
  3575. Status = RtlAnsiStringToUnicodeString( &Unicode, &AnsiString, TRUE );
  3576. if (!NT_SUCCESS(Status)) {
  3577. rc = FALSE;
  3578. }
  3579. //
  3580. // Allocate a temporary buffer for ReferencedDomainName that
  3581. // is twice as large as what was passed to adjust for the
  3582. // intermediate conversion to a WCHAR string.
  3583. //
  3584. if (rc) {
  3585. WReferencedDomainName = LocalAlloc(
  3586. LMEM_FIXED,
  3587. sizeof(WCHAR) * (*cbReferencedDomainName)
  3588. );
  3589. if (WReferencedDomainName == NULL) {
  3590. Status = STATUS_NO_MEMORY;
  3591. rc = FALSE;
  3592. }
  3593. }
  3594. //
  3595. // If the target system name is non NULL, convert it to Unicode
  3596. //
  3597. if (rc) {
  3598. if ( ARGUMENT_PRESENT( lpSystemName ) ) {
  3599. RtlInitAnsiString( &AnsiString, lpSystemName );
  3600. Status = RtlAnsiStringToUnicodeString( &SystemName, &AnsiString, TRUE );
  3601. if (!NT_SUCCESS(Status)) {
  3602. rc = FALSE;
  3603. }
  3604. pSystemName = SystemName.Buffer;
  3605. }
  3606. }
  3607. //
  3608. // Lookup the Account Sid and obtain its Unicode Account Name.
  3609. //
  3610. if (rc) {
  3611. rc = LookupAccountNameW(
  3612. (LPCWSTR)pSystemName,
  3613. (LPCWSTR)Unicode.Buffer,
  3614. Sid,
  3615. cbSid,
  3616. WReferencedDomainName,
  3617. cbReferencedDomainName,
  3618. peUse
  3619. );
  3620. }
  3621. if ( SystemName.Buffer != NULL ) {
  3622. RtlFreeUnicodeString( &SystemName );
  3623. }
  3624. //
  3625. // Convert the returned null-terminated WCHAR string
  3626. // back to a null-terminated CHAR string.
  3627. //
  3628. if (rc) {
  3629. RtlInitUnicodeString( &TmpUnicode, WReferencedDomainName );
  3630. AnsiString.Buffer = ReferencedDomainName;
  3631. //
  3632. // Watch for 16-bit overflow of MaximumLength
  3633. //
  3634. if (cbInitReferencedDomainName <= (DWORD) 65535) {
  3635. AnsiString.MaximumLength = (USHORT) cbInitReferencedDomainName;
  3636. } else {
  3637. AnsiString.MaximumLength = (USHORT) 65535;
  3638. }
  3639. Status = RtlUnicodeStringToAnsiString( &AnsiString, &TmpUnicode, FALSE );
  3640. if ( NT_SUCCESS( Status )) {
  3641. ReferencedDomainName[AnsiString.Length] = 0;
  3642. } else {
  3643. rc = FALSE;
  3644. }
  3645. }
  3646. if ( WReferencedDomainName != NULL) {
  3647. LocalFree( WReferencedDomainName );
  3648. }
  3649. if (Unicode.Buffer != NULL) {
  3650. RtlFreeUnicodeString(&Unicode);
  3651. }
  3652. if (!NT_SUCCESS(Status)) {
  3653. BaseSetLastNTError( Status );
  3654. }
  3655. return( rc );
  3656. }
  3657. BOOL
  3658. APIENTRY
  3659. LookupAccountNameW(
  3660. LPCWSTR lpSystemName,
  3661. LPCWSTR lpAccountName,
  3662. PSID Sid,
  3663. LPDWORD cbSid,
  3664. LPWSTR ReferencedDomainName,
  3665. LPDWORD cbReferencedDomainName,
  3666. PSID_NAME_USE peUse
  3667. )
  3668. /*++
  3669. Routine Description:
  3670. Translates a passed name into an account SID. It will also return
  3671. the name and SID of the first domain in which this name was found.
  3672. Arguments:
  3673. lpSystemName - Supplies the name of the system at which the lookup
  3674. is to be performed. If the null string is provided, the local
  3675. system is assumed.
  3676. lpAccountName - Supplies the account name.
  3677. Sid - Returns the SID corresponding to the passed account name.
  3678. cbSid - Supplies the size of the buffer passed in for Sid. If
  3679. the buffer size is not big enough, this parameter will
  3680. return the size necessary to hold the output Sid.
  3681. ReferencedDomainName - Returns the name of the domain in which the
  3682. name was found.
  3683. cbReferencedDomainName - Supplies the size (in Wide characters) of the
  3684. ReferencedDomainName buffer. If the buffer size is not large
  3685. enough, this parameter will return the size necessary to hold
  3686. the null-terminated output domain name. If the buffer size is
  3687. large enough, tis parameter will return the size (in Ansi characters,
  3688. excluding the terminating null) of the Referenced Domain name.
  3689. peUse - Returns an enumerated type inidicating the type of the
  3690. account.
  3691. Return Value:
  3692. BOOL - TRUE is returned if successful, else FALSE.
  3693. --*/
  3694. {
  3695. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  3696. OBJECT_ATTRIBUTES ObjectAttributes;
  3697. LSA_HANDLE PolicyHandle;
  3698. NTSTATUS Status;
  3699. NTSTATUS TmpStatus;
  3700. UNICODE_STRING Name;
  3701. PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
  3702. PLSA_TRANSLATED_SID TranslatedSid = NULL;
  3703. PSID ReturnedDomainSid;
  3704. UCHAR nSubAuthorities;
  3705. UNICODE_STRING TmpString;
  3706. DWORD ReturnedDomainNameSize;
  3707. DWORD SidLengthRequired;
  3708. BOOL Rc;
  3709. UNICODE_STRING SystemName;
  3710. PUNICODE_STRING pSystemName = NULL;
  3711. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  3712. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  3713. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  3714. SecurityQualityOfService.EffectiveOnly = FALSE;
  3715. //
  3716. // Set up the object attributes prior to opening the LSA.
  3717. //
  3718. InitializeObjectAttributes(
  3719. &ObjectAttributes,
  3720. NULL,
  3721. 0L,
  3722. NULL,
  3723. NULL
  3724. );
  3725. //
  3726. // The InitializeObjectAttributes macro presently stores NULL for
  3727. // the SecurityQualityOfService field, so we must manually copy that
  3728. // structure for now.
  3729. //
  3730. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  3731. if ( ARGUMENT_PRESENT( lpSystemName )) {
  3732. RtlInitUnicodeString( &SystemName, lpSystemName );
  3733. pSystemName = &SystemName;
  3734. }
  3735. //
  3736. // Open the LSA Policy Database for the target system. This is the
  3737. // starting point for the Name Lookup operation.
  3738. //
  3739. Status = LsaOpenPolicy(
  3740. pSystemName,
  3741. &ObjectAttributes,
  3742. POLICY_LOOKUP_NAMES,
  3743. &PolicyHandle
  3744. );
  3745. if ( !NT_SUCCESS( Status )) {
  3746. BaseSetLastNTError( Status );
  3747. return( FALSE );
  3748. }
  3749. RtlInitUnicodeString( &Name, lpAccountName );
  3750. //
  3751. // Attempt to translate the Name to a Sid.
  3752. //
  3753. Status = LsaLookupNames(
  3754. PolicyHandle,
  3755. 1,
  3756. &Name,
  3757. &ReferencedDomains,
  3758. &TranslatedSid
  3759. );
  3760. //
  3761. // Close the Policy Handle, which is not needed after here.
  3762. //
  3763. TmpStatus = LsaClose( PolicyHandle );
  3764. ASSERT( NT_SUCCESS( TmpStatus ));
  3765. //
  3766. // If an error was returned, check specifically for STATUS_NONE_MAPPED.
  3767. // In this case, we may need to dispose of the returned Referenced Domain
  3768. // List and Translated Sid structures. For all other errors,
  3769. // LsaLookupNames() frees these structures prior to exit.
  3770. //
  3771. if ( !NT_SUCCESS( Status )) {
  3772. if (Status == STATUS_NONE_MAPPED) {
  3773. if (ReferencedDomains != NULL) {
  3774. TmpStatus = LsaFreeMemory( ReferencedDomains );
  3775. ASSERT( NT_SUCCESS( TmpStatus ));
  3776. }
  3777. if (TranslatedSid != NULL) {
  3778. TmpStatus = LsaFreeMemory( TranslatedSid );
  3779. ASSERT( NT_SUCCESS( TmpStatus ));
  3780. }
  3781. }
  3782. BaseSetLastNTError( Status );
  3783. return( FALSE );
  3784. }
  3785. //
  3786. // The Name was successfully translated. There should be exactly
  3787. // one Referenced Domain and its DomainIndex should be zero.
  3788. //
  3789. ASSERT ( TranslatedSid->DomainIndex == 0 );
  3790. ASSERT ( ReferencedDomains != NULL);
  3791. ASSERT ( ReferencedDomains->Domains != NULL );
  3792. //
  3793. // Calculate the lengths of the returned Sid and Domain Name (in Wide
  3794. // Characters, excluding null).
  3795. //
  3796. ReturnedDomainNameSize =
  3797. (ReferencedDomains->Domains->Name.Length / sizeof(WCHAR));
  3798. ReturnedDomainSid = ReferencedDomains->Domains[ TranslatedSid->DomainIndex ].Sid;
  3799. nSubAuthorities = (*GetSidSubAuthorityCount( ReturnedDomainSid )) + (UCHAR)1;
  3800. SidLengthRequired = GetSidLengthRequired( nSubAuthorities );
  3801. //
  3802. // Check if buffer sizes are too small. For the returned domain,
  3803. // the size in Wide characters provided must allow for the null
  3804. // terminator that will be appended to the returned name.
  3805. //
  3806. if ( (SidLengthRequired > *cbSid) ||
  3807. (ReturnedDomainNameSize + 1 > *cbReferencedDomainName)
  3808. ) {
  3809. //
  3810. // One or both buffers are too small. Return sizes required for
  3811. // both buffers.
  3812. //
  3813. *cbSid = SidLengthRequired;
  3814. *cbReferencedDomainName = ReturnedDomainNameSize + 1;
  3815. BaseSetLastNTError( STATUS_BUFFER_TOO_SMALL );
  3816. Rc = FALSE;
  3817. } else {
  3818. //
  3819. // The provided buffers are large enough. Build the SID in the
  3820. // return buffer by combining the Domain Sid returned by
  3821. // LsaLookupNames() with the Relative Id returned. The final SID
  3822. // will have one more SubAuthority than the Domain Sid.
  3823. //
  3824. CopySid( *cbSid, Sid, ReturnedDomainSid );
  3825. *GetSidSubAuthorityCount( Sid ) = nSubAuthorities;
  3826. *GetSidSubAuthority( Sid, (DWORD)(nSubAuthorities - 1) ) = TranslatedSid->RelativeId;
  3827. //
  3828. // Copy the Domain Name into the return buffer and NULL terminate it.
  3829. //
  3830. TmpString.Buffer = ReferencedDomainName;
  3831. TmpString.Length = 0;
  3832. //
  3833. // Watch for overflow of 16-bit name length
  3834. //
  3835. if (*cbReferencedDomainName < (DWORD) 32767) {
  3836. TmpString.MaximumLength = (USHORT)((*cbReferencedDomainName) * sizeof(WCHAR));
  3837. } else {
  3838. TmpString.MaximumLength = (USHORT) 65534;
  3839. }
  3840. RtlCopyUnicodeString( &TmpString, &ReferencedDomains->Domains->Name );
  3841. TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;
  3842. //
  3843. // Copy the Sid Use field.
  3844. //
  3845. *peUse = TranslatedSid->Use;
  3846. //
  3847. // Return the size (in Wide Characters, excluding the terminating
  3848. // null) of the returned Referenced Domain Name.
  3849. //
  3850. *cbReferencedDomainName = ReturnedDomainNameSize;
  3851. Rc = TRUE;
  3852. }
  3853. //
  3854. // If necessary, free the structures returned by the LsaLookupNames()
  3855. // function.
  3856. //
  3857. if (ReferencedDomains != NULL) {
  3858. Status = LsaFreeMemory( ReferencedDomains );
  3859. ASSERT( NT_SUCCESS( Status ));
  3860. }
  3861. if (TranslatedSid != NULL) {
  3862. Status = LsaFreeMemory( TranslatedSid );
  3863. ASSERT( NT_SUCCESS( Status ));
  3864. }
  3865. return( Rc );
  3866. }
  3867. BOOL
  3868. APIENTRY
  3869. LookupAccountSidA(
  3870. LPCSTR lpSystemName,
  3871. PSID lpSid,
  3872. LPSTR lpName,
  3873. LPDWORD cbName,
  3874. LPSTR lpReferencedDomainName,
  3875. LPDWORD cbReferencedDomainName,
  3876. PSID_NAME_USE peUse
  3877. )
  3878. /*++
  3879. Routine Description:
  3880. ANSI Thunk to LookupAccountSidW
  3881. Arguments:
  3882. lpSystemName - Supplies the name of the system at which the lookup
  3883. is to be performed. If the null string is provided, the local
  3884. system is assumed.
  3885. lpSid - Supplies the account Sid.
  3886. lpName - Returns the name corresponding to the passed account SID.
  3887. cbName - Supplies the size (in Ansi characters) of the buffer passed in for
  3888. lpName. This size must allow one character for the null terminator
  3889. that will be appended to the returned name. If the buffer size is not
  3890. large enough, this parameter will return the size necessary to hold
  3891. the null-terminated output name. If the buffer size is large enough,
  3892. this parameter will return the size (in Ansi characters, excluding
  3893. the null terminator) of the name returned.
  3894. lpReferencedDomainName - Returns the name of the domain in which the
  3895. name was found.
  3896. cbReferencedDomainName - Supplies the size (in Ansi characters) of the
  3897. ReferencedDomainName buffer. This size must allow one charcter for the
  3898. null terminator that will be appended to the returned name. If the
  3899. buffer size is not large enough, this parameter will return the size
  3900. necessary to hold the output null-terminated domain name. If the
  3901. buffer size is large enough, the size of the returned name, excluding
  3902. the terminating null will be returned.
  3903. peUse - Returns an enumerated type indicating the type of the
  3904. account.
  3905. Return Value:
  3906. BOOL - TRUE if successful, else FALSE.
  3907. --*/
  3908. {
  3909. NTSTATUS Status;
  3910. LPWSTR WName = NULL;
  3911. LPWSTR WReferencedDomainName = NULL;
  3912. BOOL BoolStatus;
  3913. ANSI_STRING AnsiString;
  3914. UNICODE_STRING UnicodeString;
  3915. UNICODE_STRING SystemName;
  3916. PWSTR pSystemName = NULL;
  3917. DWORD cbInitName, cbInitReferencedDomainName;
  3918. //
  3919. // Save the original buffer sizes specified for the returned account Name
  3920. // and Referenced Domain Name.
  3921. //
  3922. cbInitName = *cbName;
  3923. cbInitReferencedDomainName = *cbReferencedDomainName;
  3924. //
  3925. // Construct temporary buffers for the Name and Domain information
  3926. // that are twice the size of those passed in to adjust for the
  3927. // intermediate conversion to WCHAR strings.
  3928. //
  3929. if ( *cbName > 0 ) {
  3930. WName = LocalAlloc( LMEM_FIXED, (*cbName) * sizeof(WCHAR));
  3931. }
  3932. if ( *cbReferencedDomainName > 0 ) {
  3933. WReferencedDomainName =
  3934. LocalAlloc( LMEM_FIXED, (*cbReferencedDomainName) * sizeof(WCHAR));
  3935. }
  3936. if ( ARGUMENT_PRESENT( lpSystemName ) ) {
  3937. RtlInitAnsiString( &AnsiString, lpSystemName );
  3938. RtlAnsiStringToUnicodeString( &SystemName, &AnsiString, TRUE );
  3939. pSystemName = SystemName.Buffer;
  3940. }
  3941. BoolStatus = LookupAccountSidW(
  3942. (LPCWSTR)pSystemName,
  3943. lpSid,
  3944. WName,
  3945. cbName,
  3946. WReferencedDomainName,
  3947. cbReferencedDomainName,
  3948. peUse
  3949. );
  3950. if ( ARGUMENT_PRESENT( lpSystemName ) ) {
  3951. RtlFreeUnicodeString( &SystemName );
  3952. }
  3953. if ( BoolStatus ) {
  3954. //
  3955. // Copy the Name and DomainName information into the passed CHAR
  3956. // buffers.
  3957. //
  3958. if ( ARGUMENT_PRESENT(lpName) ) {
  3959. AnsiString.Buffer = lpName;
  3960. //
  3961. // Watch for 16-bit overflow on buffer size. Clamp size to
  3962. // 16 bits if necessary.
  3963. //
  3964. if (cbInitName <= (DWORD) 65535) {
  3965. AnsiString.MaximumLength = (USHORT) cbInitName;
  3966. } else {
  3967. AnsiString.MaximumLength = (USHORT) 65535;
  3968. }
  3969. RtlInitUnicodeString( &UnicodeString, WName );
  3970. Status = RtlUnicodeStringToAnsiString( &AnsiString,
  3971. &UnicodeString,
  3972. FALSE );
  3973. ASSERT(NT_SUCCESS(Status));
  3974. AnsiString.Buffer[AnsiString.Length] = 0;
  3975. }
  3976. if ( ARGUMENT_PRESENT(lpReferencedDomainName) ) {
  3977. AnsiString.Buffer = lpReferencedDomainName;
  3978. //
  3979. // Watch for 16-bit overflow on buffer size. Clamp size to
  3980. // 16 bits if necessary.
  3981. //
  3982. if (cbInitReferencedDomainName <= (DWORD) 65535) {
  3983. AnsiString.MaximumLength = (USHORT) cbInitReferencedDomainName;
  3984. } else {
  3985. AnsiString.MaximumLength = (USHORT) 65535;
  3986. }
  3987. RtlInitUnicodeString( &UnicodeString, WReferencedDomainName );
  3988. Status = RtlUnicodeStringToAnsiString( &AnsiString,
  3989. &UnicodeString,
  3990. FALSE );
  3991. ASSERT(NT_SUCCESS(Status));
  3992. AnsiString.Buffer[AnsiString.Length] = 0;
  3993. }
  3994. }
  3995. if (ARGUMENT_PRESENT(WName)) {
  3996. LocalFree( WName );
  3997. }
  3998. if (ARGUMENT_PRESENT(WReferencedDomainName)) {
  3999. LocalFree( WReferencedDomainName );
  4000. }
  4001. return( BoolStatus );
  4002. }
  4003. BOOL
  4004. APIENTRY
  4005. LookupAccountSidW(
  4006. LPCWSTR lpSystemName,
  4007. PSID lpSid,
  4008. LPWSTR lpName,
  4009. LPDWORD cbName,
  4010. LPWSTR lpReferencedDomainName,
  4011. LPDWORD cbReferencedDomainName,
  4012. PSID_NAME_USE peUse
  4013. )
  4014. /*++
  4015. Routine Description:
  4016. Translates a passed SID into an account name. It will also return
  4017. the name and SID of the first domain in which this SID was found.
  4018. Arguments:
  4019. lpSystemName - Supplies the name of the system at which the lookup
  4020. is to be performed. If the null string is provided, the local
  4021. system is assumed.
  4022. lpSid - Supplies the account Sid.
  4023. lpName - Returns the name corresponding to the passed account SID.
  4024. cbName - Supplies the size (in Wide characters) of the buffer passed in for
  4025. lpName. This size must allow one character for the null terminator
  4026. that will be appended to the returned name. If the buffer size is not
  4027. large enough, this parameter will return the size necessary to hold
  4028. the null-terminated output name. If the buffer size is large enough,
  4029. this parameter will return the size (in Ansi characters, excluding
  4030. the null terminator) of the name returned.
  4031. lpReferencedDomainName - Returns the name of the domain in which the
  4032. name was found.
  4033. cbReferencedDomainName - Supplies the size (in Wide characters) of the
  4034. ReferencedDomainName buffer. This size must allow one charcter for the
  4035. null terminator that will be appended to the returned name. If the
  4036. buffer size is not large enough, this parameter will return the size
  4037. necessary to hold the output null-terminated domain name. If the
  4038. buffer size is large enough, the size of the returned name, excluding
  4039. the terminating null will be returned.
  4040. peUse - Returns an enumerated type inidicating the type of the
  4041. account.
  4042. Return Value:
  4043. BOOL - TRUE if successful, else FALSE.
  4044. --*/
  4045. {
  4046. PLSA_TRANSLATED_NAME Names;
  4047. OBJECT_ATTRIBUTES ObjectAttributes;
  4048. LSA_HANDLE PolicyHandle;
  4049. PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains;
  4050. DWORD ReturnedDomainNameSize;
  4051. DWORD ReturnedNameSize;
  4052. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  4053. NTSTATUS Status;
  4054. UNICODE_STRING TmpString;
  4055. NTSTATUS TmpStatus;
  4056. UNICODE_STRING SystemName;
  4057. PUNICODE_STRING pSystemName = NULL;
  4058. BOOLEAN Rc = FALSE;
  4059. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  4060. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  4061. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  4062. SecurityQualityOfService.EffectiveOnly = FALSE;
  4063. //
  4064. // Set up the object attributes prior to opening the LSA.
  4065. //
  4066. InitializeObjectAttributes(
  4067. &ObjectAttributes,
  4068. NULL,
  4069. 0L,
  4070. NULL,
  4071. NULL
  4072. );
  4073. //
  4074. // The InitializeObjectAttributes macro presently stores NULL for
  4075. // the SecurityQualityOfService field, so we must manually copy that
  4076. // structure for now.
  4077. //
  4078. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  4079. if ( ARGUMENT_PRESENT( lpSystemName )) {
  4080. RtlInitUnicodeString( &SystemName, lpSystemName );
  4081. pSystemName = &SystemName;
  4082. }
  4083. Status = LsaOpenPolicy(
  4084. pSystemName,
  4085. &ObjectAttributes,
  4086. POLICY_LOOKUP_NAMES,
  4087. &PolicyHandle
  4088. );
  4089. if ( !NT_SUCCESS( Status )) {
  4090. BaseSetLastNTError( Status );
  4091. return( FALSE );
  4092. }
  4093. Status = LsaLookupSids(
  4094. PolicyHandle,
  4095. 1,
  4096. &lpSid,
  4097. &ReferencedDomains,
  4098. &Names
  4099. );
  4100. TmpStatus = LsaClose( PolicyHandle );
  4101. if (!NT_SUCCESS( TmpStatus )) {
  4102. RpcSsDestroyClientContext( &PolicyHandle );
  4103. }
  4104. //
  4105. // If an error was returned, check specifically for STATUS_NONE_MAPPED.
  4106. // In this case, we may need to dispose of the returned Referenced Domain
  4107. // List and Names structures. For all other errors, LsaLookupSids()
  4108. // frees these structures prior to exit.
  4109. //
  4110. if ( !NT_SUCCESS( Status )) {
  4111. if (Status == STATUS_NONE_MAPPED) {
  4112. if (ReferencedDomains != NULL) {
  4113. TmpStatus = LsaFreeMemory( ReferencedDomains );
  4114. ASSERT( NT_SUCCESS( TmpStatus ));
  4115. }
  4116. if (Names != NULL) {
  4117. TmpStatus = LsaFreeMemory( Names );
  4118. ASSERT( NT_SUCCESS( TmpStatus ));
  4119. }
  4120. }
  4121. BaseSetLastNTError( Status );
  4122. return( FALSE );
  4123. }
  4124. //
  4125. // The Sid was successfully translated. There should be exactly
  4126. // one Referenced Domain and its DomainIndex should be zero.
  4127. //
  4128. ReturnedNameSize = (Names->Name.Length / sizeof(WCHAR));
  4129. ASSERT(Names->DomainIndex == 0);
  4130. ASSERT(ReferencedDomains != NULL);
  4131. ASSERT(ReferencedDomains->Domains != NULL);
  4132. ReturnedDomainNameSize = (ReferencedDomains->Domains->Name.Length / sizeof(WCHAR));
  4133. //
  4134. // Check if buffer sizes for the Name and Referenced Domain Name are too
  4135. // small. The sizes in Wide characters provided must allow for the null
  4136. // terminator that will be appended to the returned names.
  4137. //
  4138. if ((ReturnedNameSize + 1 > *cbName) ||
  4139. (ReturnedDomainNameSize + 1 > *cbReferencedDomainName)) {
  4140. //
  4141. // One or both buffers are too small. Return sizes required for
  4142. // both buffers, allowing one character for the null terminator.
  4143. //
  4144. *cbReferencedDomainName = ReturnedDomainNameSize + 1;
  4145. *cbName = ReturnedNameSize + 1;
  4146. BaseSetLastNTError( STATUS_BUFFER_TOO_SMALL );
  4147. Rc = FALSE;
  4148. } else {
  4149. //
  4150. // Both buffers are of sufficient size. Copy in the Name
  4151. // information and add NULL terminators.
  4152. //
  4153. TmpString.Buffer = lpName;
  4154. TmpString.Length = 0;
  4155. //
  4156. // Watch for 16-bit overflow on buffer size. Clamp size to
  4157. // 16 bits if necessary.
  4158. //
  4159. if (*cbName <= 32766) {
  4160. TmpString.MaximumLength = (USHORT)((*cbName) * sizeof(WCHAR));
  4161. } else {
  4162. TmpString.MaximumLength = (USHORT) 65532;
  4163. }
  4164. if ((*cbName) > 0) {
  4165. RtlCopyUnicodeString( &TmpString, &Names->Name );
  4166. TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;
  4167. }
  4168. //
  4169. // Copy in the Referenced Domain information.
  4170. //
  4171. TmpString.Buffer = lpReferencedDomainName;
  4172. TmpString.Length = 0;
  4173. //
  4174. // Watch for 16-bit overflow on buffer size. Clamp size to
  4175. // 16 bits if necessary.
  4176. //
  4177. if (*cbReferencedDomainName <= 32767) {
  4178. TmpString.MaximumLength = (USHORT)((*cbReferencedDomainName) * sizeof(WCHAR));
  4179. } else {
  4180. TmpString.MaximumLength = (USHORT) 65534;
  4181. }
  4182. RtlCopyUnicodeString( &TmpString, &ReferencedDomains->Domains->Name );
  4183. TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;
  4184. //
  4185. // Return the sizes (in Wide Characters, excluding the terminating
  4186. // null) of the name and domain name.
  4187. //
  4188. *cbReferencedDomainName = ReturnedDomainNameSize;
  4189. *cbName = ReturnedNameSize;
  4190. // Copy in the Use field.
  4191. //
  4192. *peUse = Names->Use;
  4193. Rc = TRUE;
  4194. }
  4195. //
  4196. // If necessary, free output buffers returned by LsaLookupSids
  4197. //
  4198. if (Names != NULL) {
  4199. Status = LsaFreeMemory( Names );
  4200. ASSERT( NT_SUCCESS( Status ));
  4201. }
  4202. if (ReferencedDomains != NULL) {
  4203. Status = LsaFreeMemory( ReferencedDomains );
  4204. ASSERT( NT_SUCCESS( Status ));
  4205. }
  4206. return(Rc);
  4207. }
  4208. BOOL
  4209. APIENTRY
  4210. LookupPrivilegeValueA(
  4211. LPCSTR lpSystemName,
  4212. LPCSTR lpName,
  4213. PLUID lpLuid
  4214. )
  4215. /*++
  4216. Routine Description:
  4217. ANSI Thunk to LookupPrivilegeValueW().
  4218. Arguments:
  4219. Return Value:
  4220. --*/
  4221. {
  4222. NTSTATUS Status;
  4223. UNICODE_STRING USystemName, UName;
  4224. ANSI_STRING ASystemName, AName;
  4225. BOOL bool;
  4226. RtlInitAnsiString( &ASystemName, lpSystemName );
  4227. RtlInitAnsiString( &AName, lpName );
  4228. USystemName.Buffer = NULL;
  4229. UName.Buffer = NULL;
  4230. Status = RtlAnsiStringToUnicodeString( &USystemName, &ASystemName, TRUE );
  4231. if (NT_SUCCESS(Status)) {
  4232. Status = RtlAnsiStringToUnicodeString( &UName, &AName, TRUE );
  4233. if (NT_SUCCESS(Status)) {
  4234. bool = LookupPrivilegeValueW( (LPCWSTR)USystemName.Buffer,
  4235. (LPCWSTR)UName.Buffer,
  4236. lpLuid
  4237. );
  4238. RtlFreeUnicodeString( &UName );
  4239. }
  4240. RtlFreeUnicodeString( &USystemName );
  4241. }
  4242. if (!NT_SUCCESS(Status)) {
  4243. BaseSetLastNTError( Status );
  4244. return( FALSE );
  4245. }
  4246. return(bool);
  4247. }
  4248. BOOL
  4249. APIENTRY
  4250. LookupPrivilegeValueW(
  4251. LPCWSTR lpSystemName,
  4252. LPCWSTR lpName,
  4253. PLUID lpLuid
  4254. )
  4255. /*++
  4256. Routine Description:
  4257. This function retrieves the value used on the target system
  4258. to locally represent the specified privilege. The privilege
  4259. is specified by programmatic name.
  4260. Arguments:
  4261. lpSystemName - Supplies the name of the system at which the lookup
  4262. is to be performed. If the null string is provided, the local
  4263. system is assumed.
  4264. lpName - provides the privilege's programmatic name.
  4265. lpLuid - Receives the locally unique ID the privilege is known by on the
  4266. target machine.
  4267. Return Value:
  4268. --*/
  4269. {
  4270. NTSTATUS Status,
  4271. TmpStatus;
  4272. LSA_HANDLE PolicyHandle;
  4273. OBJECT_ATTRIBUTES ObjectAttributes;
  4274. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  4275. UNICODE_STRING USystemName,
  4276. UName;
  4277. PUNICODE_STRING SystemName = NULL;
  4278. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  4279. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  4280. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  4281. SecurityQualityOfService.EffectiveOnly = FALSE;
  4282. //
  4283. // Set up the object attributes prior to opening the LSA.
  4284. //
  4285. InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
  4286. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  4287. if ( ARGUMENT_PRESENT( lpSystemName )) {
  4288. RtlInitUnicodeString( &USystemName, lpSystemName );
  4289. SystemName = &USystemName;
  4290. }
  4291. Status = LsaOpenPolicy(
  4292. SystemName,
  4293. &ObjectAttributes,
  4294. POLICY_LOOKUP_NAMES,
  4295. &PolicyHandle
  4296. );
  4297. if ( !NT_SUCCESS( Status )) {
  4298. BaseSetLastNTError( Status );
  4299. return( FALSE );
  4300. }
  4301. RtlInitUnicodeString( &UName, lpName );
  4302. Status = LsaLookupPrivilegeValue( PolicyHandle, &UName, lpLuid );
  4303. TmpStatus = LsaClose( PolicyHandle );
  4304. ASSERT( NT_SUCCESS( TmpStatus ));
  4305. if ( !NT_SUCCESS( Status )) {
  4306. BaseSetLastNTError( Status );
  4307. return( FALSE );
  4308. }
  4309. return(TRUE);
  4310. }
  4311. BOOL
  4312. APIENTRY
  4313. LookupPrivilegeNameA(
  4314. LPCSTR lpSystemName,
  4315. PLUID lpLuid,
  4316. LPSTR lpName,
  4317. LPDWORD cchName
  4318. )
  4319. /*++
  4320. Routine Description:
  4321. ANSI Thunk to LookupPrivilegeValueW().
  4322. Arguments:
  4323. Return Value:
  4324. --*/
  4325. {
  4326. NTSTATUS Status;
  4327. ANSI_STRING AnsiName;
  4328. LPWSTR UnicodeBuffer;
  4329. UNICODE_STRING UnicodeString;
  4330. ANSI_STRING AnsiSystemName;
  4331. UNICODE_STRING UnicodeSystemName;
  4332. DWORD LengthRequired;
  4333. //
  4334. // Convert the passed SystemName to Unicode. Let the Rtl function
  4335. // allocate the memory we need.
  4336. //
  4337. RtlInitAnsiString( &AnsiSystemName, lpSystemName );
  4338. Status = RtlAnsiStringToUnicodeString( &UnicodeSystemName, &AnsiSystemName, TRUE );
  4339. if (!NT_SUCCESS( Status )) {
  4340. BaseSetLastNTError( Status );
  4341. return( FALSE );
  4342. }
  4343. //
  4344. // Make sure we don't exceed the limits of a unicode string.
  4345. //
  4346. if (*cchName > 0xFFFC) {
  4347. *cchName = 0xFFFC;
  4348. }
  4349. UnicodeBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, *cchName * sizeof(WCHAR) );
  4350. if (UnicodeBuffer == NULL) {
  4351. RtlFreeUnicodeString( &UnicodeSystemName );
  4352. BaseSetLastNTError( STATUS_NO_MEMORY );
  4353. return( FALSE );
  4354. }
  4355. //
  4356. // Don't pass in cchName, since it will be overwritten by LookupPrivilegeNameW,
  4357. // and we need it later.
  4358. //
  4359. LengthRequired = *cchName;
  4360. if (!LookupPrivilegeNameW( (LPCWSTR)UnicodeSystemName.Buffer,
  4361. lpLuid,
  4362. UnicodeBuffer,
  4363. &LengthRequired
  4364. )) {
  4365. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  4366. RtlFreeUnicodeString( &UnicodeSystemName );
  4367. *cchName = LengthRequired;
  4368. return(FALSE);
  4369. }
  4370. //
  4371. // Now convert back to ANSI for the caller
  4372. //
  4373. RtlInitUnicodeString(&UnicodeString, UnicodeBuffer);
  4374. AnsiName.Buffer = lpName;
  4375. AnsiName.Length = 0;
  4376. AnsiName.MaximumLength = (USHORT)*cchName;
  4377. Status = RtlUnicodeStringToAnsiString(&AnsiName, &UnicodeString, FALSE);
  4378. ASSERT( NT_SUCCESS( Status ));
  4379. *cchName = AnsiName.Length;
  4380. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  4381. RtlFreeUnicodeString( &UnicodeSystemName );
  4382. return(TRUE);
  4383. }
  4384. BOOL
  4385. APIENTRY
  4386. LookupPrivilegeNameW(
  4387. LPCWSTR lpSystemName,
  4388. PLUID lpLuid,
  4389. LPWSTR lpName,
  4390. LPDWORD cchName
  4391. )
  4392. /*++
  4393. Routine Description:
  4394. This function returns the programmatic name corresponding to
  4395. the privilege represented on the target system by the provided
  4396. LUID.
  4397. Arguments:
  4398. lpSystemName - Supplies the name of the system at which the lookup
  4399. is to be performed. If the null string is provided, the local
  4400. system is assumed.
  4401. lpLuid - is the locally unique ID the privilege is known by on the
  4402. target machine.
  4403. lpName - Receives the privilege's programmatic name.
  4404. cchName - indicates how large the buffer is (in characters). This
  4405. count does not include the null-terminator that is added at the
  4406. end of the string.
  4407. Return Value:
  4408. --*/
  4409. {
  4410. NTSTATUS Status,
  4411. TmpStatus;
  4412. LSA_HANDLE PolicyHandle;
  4413. OBJECT_ATTRIBUTES ObjectAttributes;
  4414. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  4415. UNICODE_STRING USystemName;
  4416. PUNICODE_STRING SystemName,
  4417. UName;
  4418. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  4419. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  4420. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  4421. SecurityQualityOfService.EffectiveOnly = FALSE;
  4422. //
  4423. // Set up the object attributes prior to opening the LSA.
  4424. //
  4425. InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
  4426. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  4427. SystemName = NULL;
  4428. if ( ARGUMENT_PRESENT( lpSystemName )) {
  4429. RtlInitUnicodeString( &USystemName, lpSystemName );
  4430. SystemName = &USystemName;
  4431. }
  4432. Status = LsaOpenPolicy(
  4433. SystemName,
  4434. &ObjectAttributes,
  4435. POLICY_LOOKUP_NAMES,
  4436. &PolicyHandle
  4437. );
  4438. if ( !NT_SUCCESS( Status )) {
  4439. BaseSetLastNTError( Status );
  4440. return( FALSE );
  4441. }
  4442. UName = NULL;
  4443. Status = LsaLookupPrivilegeName( PolicyHandle,lpLuid, &UName );
  4444. if (NT_SUCCESS(Status) ) {
  4445. if ((DWORD)UName->Length + sizeof( WCHAR) > (*cchName) * sizeof( WCHAR )) {
  4446. Status = STATUS_BUFFER_TOO_SMALL;
  4447. (*cchName) = ( UName->Length + sizeof( WCHAR) ) / sizeof( WCHAR );
  4448. } else {
  4449. RtlMoveMemory( lpName, UName->Buffer, UName->Length );
  4450. lpName[UName->Length/sizeof(WCHAR)] = 0; // NULL terminate it
  4451. (*cchName) = UName->Length / sizeof( WCHAR );
  4452. }
  4453. LsaFreeMemory( UName->Buffer );
  4454. LsaFreeMemory( UName );
  4455. }
  4456. TmpStatus = LsaClose( PolicyHandle );
  4457. ASSERT( NT_SUCCESS( TmpStatus ));
  4458. if ( !NT_SUCCESS( Status )) {
  4459. BaseSetLastNTError( Status );
  4460. return( FALSE );
  4461. }
  4462. return(TRUE);
  4463. }
  4464. BOOL
  4465. APIENTRY
  4466. LookupPrivilegeDisplayNameA(
  4467. LPCSTR lpSystemName,
  4468. LPCSTR lpName,
  4469. LPSTR lpDisplayName,
  4470. LPDWORD cchDisplayName,
  4471. LPDWORD lpLanguageId
  4472. )
  4473. /*++
  4474. Routine Description:
  4475. ANSI Thunk to LookupPrivilegeValueW().
  4476. Arguments:
  4477. Return Value:
  4478. --*/
  4479. {
  4480. NTSTATUS Status;
  4481. UNICODE_STRING UnicodeSystemName;
  4482. UNICODE_STRING UnicodeString;
  4483. UNICODE_STRING UnicodeName;
  4484. ANSI_STRING AnsiSystemName;
  4485. ANSI_STRING AnsiDisplayName;
  4486. ANSI_STRING AnsiName;
  4487. LPWSTR UnicodeBuffer;
  4488. DWORD RequiredLength;
  4489. RtlInitAnsiString( &AnsiSystemName, lpSystemName );
  4490. Status = RtlAnsiStringToUnicodeString( &UnicodeSystemName, &AnsiSystemName, TRUE );
  4491. if (!NT_SUCCESS( Status )) {
  4492. BaseSetLastNTError( Status );
  4493. return( FALSE );
  4494. }
  4495. //
  4496. // Make sure we don't exceed that limits of a unicode string.
  4497. //
  4498. if (*cchDisplayName > 0xFFFC) {
  4499. *cchDisplayName = 0xFFFC;
  4500. }
  4501. UnicodeBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, *cchDisplayName * sizeof(WCHAR));
  4502. if (UnicodeBuffer == NULL) {
  4503. RtlFreeUnicodeString( &UnicodeSystemName );
  4504. BaseSetLastNTError( STATUS_NO_MEMORY );
  4505. return( FALSE );
  4506. }
  4507. RtlInitAnsiString( &AnsiName, lpName );
  4508. Status = RtlAnsiStringToUnicodeString( &UnicodeName, &AnsiName, TRUE );
  4509. if (!NT_SUCCESS( Status )) {
  4510. RtlFreeUnicodeString( &UnicodeSystemName );
  4511. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  4512. BaseSetLastNTError( Status );
  4513. return( FALSE );
  4514. }
  4515. RequiredLength = *cchDisplayName;
  4516. if (! LookupPrivilegeDisplayNameW( (LPCWSTR)UnicodeSystemName.Buffer,
  4517. (LPCWSTR)UnicodeName.Buffer,
  4518. UnicodeBuffer,
  4519. &RequiredLength,
  4520. lpLanguageId
  4521. )) {
  4522. //
  4523. // No need to set last error here, we can assume the W routine did so.
  4524. //
  4525. *cchDisplayName = RequiredLength;
  4526. RtlFreeUnicodeString( &UnicodeSystemName );
  4527. RtlFreeUnicodeString( &UnicodeName );
  4528. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  4529. return( FALSE );
  4530. }
  4531. //
  4532. // Now convert back to ANSI for the caller
  4533. //
  4534. RtlInitUnicodeString( &UnicodeString, UnicodeBuffer );
  4535. AnsiDisplayName.Buffer = lpDisplayName;
  4536. AnsiDisplayName.Length = 0;
  4537. AnsiDisplayName.MaximumLength = (USHORT)(*cchDisplayName);
  4538. Status = RtlUnicodeStringToAnsiString( &AnsiDisplayName, &UnicodeString, FALSE );
  4539. ASSERT( NT_SUCCESS( Status ));
  4540. *cchDisplayName = AnsiDisplayName.Length;
  4541. RtlFreeUnicodeString( &UnicodeSystemName );
  4542. RtlFreeUnicodeString( &UnicodeName );
  4543. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  4544. return( TRUE );
  4545. }
  4546. BOOL
  4547. APIENTRY
  4548. LookupPrivilegeDisplayNameW(
  4549. LPCWSTR lpSystemName,
  4550. LPCWSTR lpName,
  4551. LPWSTR lpDisplayName,
  4552. LPDWORD cchDisplayName,
  4553. LPDWORD lpLanguageId
  4554. )
  4555. /*++
  4556. Routine Description:
  4557. This function retrieves a displayable name representing the
  4558. specified privilege.
  4559. Arguments:
  4560. lpSystemName - Supplies the name of the system at which the lookup
  4561. is to be performed. If the null string is provided, the local
  4562. system is assumed.
  4563. lpName - provides the privilege's programmatic name.
  4564. lpDisplayName - Receives the privilege's displayable name.
  4565. cchDisplayName - indicates how large the buffer is (in characters). This
  4566. count does not include the null-terminator that is added at the
  4567. end of the string.
  4568. lpLanguageId - Receives the language of the returned displayable
  4569. name.
  4570. Return Value:
  4571. --*/
  4572. {
  4573. NTSTATUS Status,
  4574. TmpStatus;
  4575. LSA_HANDLE PolicyHandle;
  4576. OBJECT_ATTRIBUTES ObjectAttributes;
  4577. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  4578. UNICODE_STRING USystemName,
  4579. UName;
  4580. PUNICODE_STRING SystemName,
  4581. UDisplayName;
  4582. SHORT LanguageId;
  4583. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  4584. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  4585. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  4586. SecurityQualityOfService.EffectiveOnly = FALSE;
  4587. //
  4588. // Set up the object attributes prior to opening the LSA.
  4589. //
  4590. InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
  4591. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  4592. SystemName = NULL;
  4593. if ( ARGUMENT_PRESENT( lpSystemName )) {
  4594. RtlInitUnicodeString( &USystemName, lpSystemName );
  4595. SystemName = &USystemName;
  4596. }
  4597. Status = LsaOpenPolicy(
  4598. SystemName,
  4599. &ObjectAttributes,
  4600. POLICY_LOOKUP_NAMES,
  4601. &PolicyHandle
  4602. );
  4603. if ( !NT_SUCCESS( Status )) {
  4604. BaseSetLastNTError( Status );
  4605. return( FALSE );
  4606. }
  4607. RtlInitUnicodeString( &UName, lpName );
  4608. UDisplayName = NULL;
  4609. Status = LsaLookupPrivilegeDisplayName( PolicyHandle,
  4610. &UName,
  4611. &UDisplayName,
  4612. &LanguageId
  4613. );
  4614. (*lpLanguageId) = LanguageId;
  4615. if (NT_SUCCESS(Status)) {
  4616. if (UDisplayName->Length + sizeof(WCHAR) > (*cchDisplayName) * sizeof(WCHAR)) {
  4617. Status = STATUS_BUFFER_TOO_SMALL;
  4618. (*cchDisplayName) = (UDisplayName->Length + sizeof( WCHAR )) / sizeof( WCHAR );
  4619. } else {
  4620. RtlMoveMemory( lpDisplayName,
  4621. UDisplayName->Buffer,
  4622. UDisplayName->Length
  4623. );
  4624. lpDisplayName[UDisplayName->Length/sizeof(WCHAR)] = 0; // Null terminate it.
  4625. (*cchDisplayName) = UDisplayName->Length / sizeof( WCHAR );
  4626. }
  4627. LsaFreeMemory( UDisplayName->Buffer );
  4628. LsaFreeMemory( UDisplayName );
  4629. }
  4630. TmpStatus = LsaClose( PolicyHandle );
  4631. ASSERT( NT_SUCCESS( TmpStatus ));
  4632. if ( !NT_SUCCESS( Status )) {
  4633. BaseSetLastNTError( Status );
  4634. return( FALSE );
  4635. }
  4636. return(TRUE);
  4637. }
  4638. /////////////////////////////////////////////////////////////////////////////
  4639. // //
  4640. // Private Routines //
  4641. // //
  4642. /////////////////////////////////////////////////////////////////////////////
  4643. VOID
  4644. SepFormatAccountSid(
  4645. PSID Sid,
  4646. LPWSTR OutputBuffer
  4647. )
  4648. {
  4649. UCHAR Buffer[128];
  4650. UCHAR TmpBuffer[128];
  4651. ANSI_STRING AccountName;
  4652. UCHAR i;
  4653. ULONG Tmp;
  4654. UNICODE_STRING OutputString;
  4655. PISID iSid;
  4656. NTSTATUS Status;
  4657. //
  4658. // Do everything as ANSI for the time being, and then
  4659. // convert to wide-char at the bottom.
  4660. //
  4661. // We need to do this until we have more complete c-runtime support
  4662. // for w-char strings.
  4663. //
  4664. iSid = (PISID) Sid;
  4665. OutputString.Buffer = OutputBuffer;
  4666. OutputString.MaximumLength = 127;
  4667. Buffer[0] = 0;
  4668. TmpBuffer[0] = 0;
  4669. AccountName.MaximumLength = 127;
  4670. AccountName.Length = (USHORT)((GetLengthSid( Sid ) > MAXUSHORT) ? MAXUSHORT : GetLengthSid( Sid ));
  4671. AccountName.Buffer = Buffer;
  4672. sprintf(TmpBuffer, "S-%u-", (USHORT)iSid->Revision );
  4673. lstrcpy(Buffer, TmpBuffer);
  4674. if ( (iSid->IdentifierAuthority.Value[0] != 0) ||
  4675. (iSid->IdentifierAuthority.Value[1] != 0) ){
  4676. sprintf(TmpBuffer, "0x%02hx%02hx%02hx%02hx%02hx%02hx",
  4677. (USHORT)iSid->IdentifierAuthority.Value[0],
  4678. (USHORT)iSid->IdentifierAuthority.Value[1],
  4679. (USHORT)iSid->IdentifierAuthority.Value[2],
  4680. (USHORT)iSid->IdentifierAuthority.Value[3],
  4681. (USHORT)iSid->IdentifierAuthority.Value[4],
  4682. (USHORT)iSid->IdentifierAuthority.Value[5] );
  4683. lstrcat(Buffer, TmpBuffer);
  4684. } else {
  4685. Tmp = (ULONG)iSid->IdentifierAuthority.Value[5] +
  4686. (ULONG)(iSid->IdentifierAuthority.Value[4] << 8) +
  4687. (ULONG)(iSid->IdentifierAuthority.Value[3] << 16) +
  4688. (ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
  4689. sprintf(TmpBuffer, "%lu", Tmp);
  4690. lstrcat(Buffer, TmpBuffer);
  4691. }
  4692. for (i=0;i<iSid->SubAuthorityCount ;i++ ) {
  4693. sprintf(TmpBuffer, "-%lu", iSid->SubAuthority[i]);
  4694. lstrcat(Buffer, TmpBuffer);
  4695. }
  4696. Status = RtlAnsiStringToUnicodeString( &OutputString, &AccountName, FALSE );
  4697. ASSERT( NT_SUCCESS( Status ));
  4698. return;
  4699. }