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

2765 lines
82 KiB

  1. /*++
  2. Copyright (c) 1990 - 1995 Microsoft Corporation
  3. Module Name:
  4. security.c
  5. Abstract:
  6. This module interfaces with the security system
  7. Author:
  8. Andrew Bell (andrewbe) June 1992
  9. Revision History:
  10. --*/
  11. #include <precomp.h>
  12. /******************************************************************************
  13. The printing security model
  14. ---------------------------
  15. In printing we define a hierarchy of three objects:
  16. SERVER
  17. / \
  18. / \
  19. / ...
  20. /
  21. PRINTER
  22. / \
  23. / \
  24. / ...
  25. /
  26. DOCUMENT
  27. The following types of operation may be performed on each of these objects:
  28. SERVER: Install/Deinstall Driver
  29. Create Printer
  30. Enumerate Printers
  31. PRINTER: Pause/Resume
  32. Delete
  33. Connect to/Disconnect
  34. Set
  35. Enumerate Documents
  36. DOCUMENT: Pause/Resume
  37. Delete
  38. Set Attributes
  39. For product LanMan NT, five classes of user are defined, and,
  40. for Windows NT, four classes are defined.
  41. The following privileges are assigned to each class:
  42. Administrators
  43. Print Operators
  44. System Operators
  45. Power Users
  46. Owners
  47. Everyone (World)
  48. ******************************************************************************/
  49. #define DBGCHK( Condition, ErrorInfo ) \
  50. if( Condition ) DBGMSG( DBG_WARNING, ErrorInfo )
  51. #define TOKENLENGTH( Token ) ( *( ( (PDWORD)Token ) - 1 ) )
  52. /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  53. Came from \\orville\razzle\src\private\newsam\server\bldsam3.c
  54. >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
  55. GENERIC_MAPPING GenericMapping[SPOOLER_OBJECT_COUNT] =
  56. {
  57. { SERVER_READ, SERVER_WRITE, SERVER_EXECUTE, SERVER_ALL_ACCESS },
  58. { PRINTER_READ, PRINTER_WRITE, PRINTER_EXECUTE, PRINTER_ALL_ACCESS },
  59. { JOB_READ, JOB_WRITE, JOB_EXECUTE, JOB_ALL_ACCESS }
  60. };
  61. /* !!! Should these be translatable??? */
  62. LPWSTR ObjectTypeName[SPOOLER_OBJECT_COUNT] =
  63. {
  64. L"Server", L"Printer", L"Document"
  65. };
  66. WCHAR *szSpooler = L"Spooler";
  67. LUID AuditValue;
  68. PSECURITY_DESCRIPTOR pServerSecurityDescriptor;
  69. LUID gLoadDriverPrivilegeLuid;
  70. PSID pLocalSystemSid;
  71. PSID pGuestsSid;
  72. PSID pNetworkLogonSid;
  73. BOOL ServerGenerateOnClose; /* Do we need this for the server? */
  74. #if DBG
  75. #define DBG_ACCESS_TYPE_SERVER_ALL_ACCESS 0
  76. #define DBG_ACCESS_TYPE_SERVER_READ 1
  77. #define DBG_ACCESS_TYPE_SERVER_WRITE 2
  78. #define DBG_ACCESS_TYPE_SERVER_EXECUTE 3
  79. #define DBG_ACCESS_TYPE_PRINTER_ALL_ACCESS 4
  80. #define DBG_ACCESS_TYPE_PRINTER_READ 5
  81. #define DBG_ACCESS_TYPE_PRINTER_WRITE 6
  82. #define DBG_ACCESS_TYPE_PRINTER_EXECUTE 7
  83. #define DBG_ACCESS_TYPE_JOB_ALL_ACCESS 8
  84. #define DBG_ACCESS_TYPE_JOB_READ 9
  85. #define DBG_ACCESS_TYPE_JOB_WRITE 10
  86. #define DBG_ACCESS_TYPE_JOB_EXECUTE 11
  87. #define DBG_ACCESS_TYPE_PRINTER_ACCESS_USE 12
  88. #define DBG_ACCESS_TYPE_PRINTER_ACCESS_ADMINISTER 13
  89. #define DBG_ACCESS_TYPE_SERVER_ACCESS_ENUMERATE 14
  90. #define DBG_ACCESS_TYPE_SERVER_ACCESS_ADMINISTER 15
  91. #define DBG_ACCESS_TYPE_JOB_ACCESS_ADMINISTER 16
  92. #define DBG_ACCESS_TYPE_DELETE 17
  93. #define DBG_ACCESS_TYPE_WRITE_DAC 18
  94. #define DBG_ACCESS_TYPE_WRITE_OWNER 19
  95. #define DBG_ACCESS_TYPE_ACCESS_SYSTEM_SECURITY 20
  96. // These two should come last:
  97. #define DBG_ACCESS_TYPE_UNKNOWN 21
  98. #define DBG_ACCESS_TYPE_COUNT 22
  99. typedef struct _DBG_ACCESS_TYPE_MAPPING
  100. {
  101. DWORD Type;
  102. LPWSTR Name;
  103. }
  104. DBG_ACCESS_TYPE_MAPPING, *PDBG_ACCESS_TYPE_MAPPING;
  105. DBG_ACCESS_TYPE_MAPPING DbgAccessTypeMapping[DBG_ACCESS_TYPE_COUNT] =
  106. {
  107. { SERVER_ALL_ACCESS, L"SERVER_ALL_ACCESS" },
  108. { SERVER_READ, L"SERVER_READ" },
  109. { SERVER_WRITE, L"SERVER_WRITE" },
  110. { SERVER_EXECUTE, L"SERVER_EXECUTE" },
  111. { PRINTER_ALL_ACCESS, L"PRINTER_ALL_ACCESS" },
  112. { PRINTER_READ, L"PRINTER_READ" },
  113. { PRINTER_WRITE, L"PRINTER_WRITE" },
  114. { PRINTER_EXECUTE, L"PRINTER_EXECUTE" },
  115. { JOB_ALL_ACCESS, L"JOB_ALL_ACCESS" },
  116. { JOB_READ, L"JOB_READ" },
  117. { JOB_WRITE, L"JOB_WRITE" },
  118. { JOB_EXECUTE, L"JOB_EXECUTE" },
  119. { PRINTER_ACCESS_USE, L"PRINTER_ACCESS_USE" },
  120. { PRINTER_ACCESS_ADMINISTER, L"PRINTER_ACCESS_ADMINISTER" },
  121. { SERVER_ACCESS_ENUMERATE, L"SERVER_ACCESS_ENUMERATE" },
  122. { SERVER_ACCESS_ADMINISTER, L"SERVER_ACCESS_ADMINISTER" },
  123. { JOB_ACCESS_ADMINISTER, L"JOB_ACCESS_ADMINISTER" },
  124. { DELETE, L"DELETE" },
  125. { WRITE_DAC, L"WRITE_DAC" },
  126. { WRITE_OWNER, L"WRITE_OWNER" },
  127. { ACCESS_SYSTEM_SECURITY, L"ACCESS_SYSTEM_SECURITY" },
  128. { 0, L"UNKNOWN" }
  129. };
  130. LPWSTR DbgGetAccessTypeName( DWORD AccessType )
  131. {
  132. PDBG_ACCESS_TYPE_MAPPING pMapping;
  133. DWORD i;
  134. pMapping = DbgAccessTypeMapping;
  135. i = 0;
  136. while( ( i < ( DBG_ACCESS_TYPE_COUNT - 1 ) ) && ( pMapping[i].Type != AccessType ) )
  137. i++;
  138. return pMapping[i].Name;
  139. }
  140. #endif /* DBG */
  141. BOOL
  142. BuildJobOwnerSecurityDescriptor(
  143. IN HANDLE hToken,
  144. OUT PSECURITY_DESCRIPTOR *ppSD
  145. );
  146. VOID
  147. DestroyJobOwnerSecurityDescriptor(
  148. IN PSECURITY_DESCRIPTOR pSD
  149. );
  150. BOOL
  151. SetRequiredPrivileges(
  152. IN HANDLE TokenHandle,
  153. OUT PTOKEN_PRIVILEGES *ppPreviousTokenPrivileges,
  154. OUT PDWORD pPreviousTokenPrivilegesLength
  155. );
  156. BOOL
  157. ResetRequiredPrivileges(
  158. IN HANDLE TokenHandle,
  159. IN PTOKEN_PRIVILEGES pPreviousTokenPrivileges,
  160. IN DWORD PreviousTokenPrivilegesLength
  161. );
  162. PSECURITY_DESCRIPTOR
  163. AllocateLocalSD(
  164. PSECURITY_DESCRIPTOR pSystemAllocatedSD
  165. );
  166. DWORD
  167. GetHackOutAce(
  168. PACL pDacl
  169. );
  170. #define MAX_ACE 20
  171. #if DBG
  172. typedef struct _STANDARD_ACE {
  173. ACE_HEADER Header;
  174. ACCESS_MASK Mask;
  175. PSID Sid;
  176. } STANDARD_ACE;
  177. typedef STANDARD_ACE *PSTANDARD_ACE;
  178. //
  179. // The following macros used by DumpAcl(), these macros and DumpAcl() are
  180. // stolen from private\ntos\se\ctaccess.c (written by robertre) for
  181. // debugging purposes.
  182. //
  183. //
  184. // Returns a pointer to the first Ace in an Acl (even if the Acl is empty).
  185. //
  186. #define FirstAce(Acl) ((PVOID)((LPBYTE)(Acl) + sizeof(ACL)))
  187. //
  188. // Returns a pointer to the next Ace in a sequence (even if the input
  189. // Ace is the one in the sequence).
  190. //
  191. #define NextAce(Ace) ((PVOID)((LPBYTE)(Ace) + ((PACE_HEADER)(Ace))->AceSize))
  192. VOID
  193. DumpAcl(
  194. IN PACL Acl
  195. );
  196. #endif //if DBG
  197. /* Dummy access mask which will never be checked, but required
  198. * by the ACL editor, so that Document Properties is not undefined
  199. * for containers (i.e. printers).
  200. * This mask alone must not be used for any other ACE, since it
  201. * will be used to find the no-inherit ACE which propagates
  202. * onto printers.
  203. */
  204. #define DUMMY_ACE_ACCESS_MASK READ_CONTROL
  205. /* CreateServerSecurityDescriptor
  206. *
  207. * Arguments: None
  208. *
  209. * Return: The security descriptor returned by BuildPrintObjectProtection.
  210. *
  211. */
  212. PSECURITY_DESCRIPTOR
  213. CreateServerSecurityDescriptor(
  214. VOID
  215. )
  216. {
  217. DWORD ObjectType = SPOOLER_OBJECT_SERVER;
  218. NT_PRODUCT_TYPE NtProductType;
  219. PSID AceSid[MAX_ACE]; // Don't expect more than MAX_ACE ACEs in any of these.
  220. ACCESS_MASK AceMask[MAX_ACE]; // Access masks corresponding to Sids
  221. BYTE InheritFlags[MAX_ACE]; //
  222. UCHAR AceType[MAX_ACE];
  223. DWORD AceCount;
  224. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  225. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  226. SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  227. PSID WorldSid = NULL;
  228. PSID AdminsAliasSid = NULL;
  229. PSID PrintOpsAliasSid = NULL;
  230. PSID SystemOpsAliasSid = NULL;
  231. PSID PowerUsersAliasSid = NULL;
  232. PSID CreatorOwnerSid = NULL;
  233. PSECURITY_DESCRIPTOR ServerSD = NULL;
  234. BOOL OK;
  235. //
  236. // Printer SD
  237. //
  238. AceCount = 0;
  239. /* Creator-Owner SID: */
  240. OK = AllocateAndInitializeSid( &CreatorSidAuthority, 1,
  241. SECURITY_CREATOR_OWNER_RID,
  242. 0, 0, 0, 0, 0, 0, 0,
  243. &CreatorOwnerSid );
  244. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  245. if ( !OK ) {
  246. goto CleanUp;
  247. }
  248. /* The following is a dummy ACE needed for the ACL editor.
  249. * Note this is a gross hack, and will result in two ACEs
  250. * being propagated onto printers when they are created,
  251. * one of which must be deleted.
  252. */
  253. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  254. AceSid[AceCount] = CreatorOwnerSid;
  255. AceMask[AceCount] = DUMMY_ACE_ACCESS_MASK;
  256. InheritFlags[AceCount] = INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE;
  257. AceCount++;
  258. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  259. AceSid[AceCount] = CreatorOwnerSid;
  260. AceMask[AceCount] = GENERIC_ALL;
  261. InheritFlags[AceCount] = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
  262. AceCount++;
  263. /* World SID */
  264. OK = AllocateAndInitializeSid( &WorldSidAuthority, 1,
  265. SECURITY_WORLD_RID,
  266. 0, 0, 0, 0, 0, 0, 0,
  267. &WorldSid );
  268. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  269. if ( !OK ) {
  270. goto CleanUp;
  271. }
  272. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  273. AceSid[AceCount] = WorldSid;
  274. AceMask[AceCount] = SERVER_EXECUTE;
  275. InheritFlags[AceCount] = 0;
  276. AceCount++;
  277. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  278. AceSid[AceCount] = WorldSid;
  279. AceMask[AceCount] = GENERIC_EXECUTE;
  280. InheritFlags[AceCount] = INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE;
  281. AceCount++;
  282. /* Admins alias SID */
  283. OK = AllocateAndInitializeSid( &NtAuthority, 2,
  284. SECURITY_BUILTIN_DOMAIN_RID,
  285. DOMAIN_ALIAS_RID_ADMINS,
  286. 0, 0, 0, 0, 0, 0,
  287. &AdminsAliasSid );
  288. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  289. if ( !OK ) {
  290. goto CleanUp;
  291. }
  292. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  293. AceSid[AceCount] = AdminsAliasSid;
  294. AceMask[AceCount] = SERVER_ALL_ACCESS;
  295. InheritFlags[AceCount] = 0;
  296. AceCount++;
  297. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  298. AceSid[AceCount] = AdminsAliasSid;
  299. AceMask[AceCount] = GENERIC_ALL;
  300. InheritFlags[AceCount] = INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
  301. AceCount++;
  302. OK = RtlGetNtProductType( &NtProductType );
  303. DBGCHK( !OK, ( "Couldn't get product type" ) );
  304. if ( !OK ) {
  305. goto CleanUp;
  306. }
  307. switch (NtProductType) {
  308. case NtProductLanManNt:
  309. // case NtProductMember:
  310. /* Print Ops alias SID */
  311. OK = AllocateAndInitializeSid( &NtAuthority, 2,
  312. SECURITY_BUILTIN_DOMAIN_RID,
  313. DOMAIN_ALIAS_RID_PRINT_OPS,
  314. 0, 0, 0, 0, 0, 0,
  315. &PrintOpsAliasSid );
  316. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  317. if ( !OK ) {
  318. goto CleanUp;
  319. }
  320. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  321. AceSid[AceCount] = PrintOpsAliasSid;
  322. AceMask[AceCount] = SERVER_ALL_ACCESS;
  323. InheritFlags[AceCount] = 0;
  324. AceCount++;
  325. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  326. AceSid[AceCount] = PrintOpsAliasSid;
  327. AceMask[AceCount] = GENERIC_ALL;
  328. InheritFlags[AceCount] = INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
  329. AceCount++;
  330. /* System Ops alias SID */
  331. OK = AllocateAndInitializeSid( &NtAuthority, 2,
  332. SECURITY_BUILTIN_DOMAIN_RID,
  333. DOMAIN_ALIAS_RID_SYSTEM_OPS,
  334. 0, 0, 0, 0, 0, 0,
  335. &SystemOpsAliasSid );
  336. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  337. if ( !OK ) {
  338. goto CleanUp;
  339. }
  340. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  341. AceSid[AceCount] = SystemOpsAliasSid;
  342. AceMask[AceCount] = SERVER_ALL_ACCESS;
  343. InheritFlags[AceCount] = 0;
  344. AceCount++;
  345. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  346. AceSid[AceCount] = SystemOpsAliasSid;
  347. AceMask[AceCount] = GENERIC_ALL;
  348. InheritFlags[AceCount] = INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
  349. AceCount++;
  350. break;
  351. case NtProductWinNt:
  352. default:
  353. {
  354. OSVERSIONINFOEX OsVersion = {0};
  355. OsVersion.dwOSVersionInfoSize = sizeof(OsVersion);
  356. //
  357. // Whistler Personal does not have the Power Users group.
  358. //
  359. if (GetVersionEx((LPOSVERSIONINFO)&OsVersion) &&
  360. !(OsVersion.wProductType==VER_NT_WORKSTATION && OsVersion.wSuiteMask & VER_SUITE_PERSONAL)) {
  361. OK = AllocateAndInitializeSid( &NtAuthority, 2,
  362. SECURITY_BUILTIN_DOMAIN_RID,
  363. DOMAIN_ALIAS_RID_POWER_USERS,
  364. 0, 0, 0, 0, 0, 0,
  365. &PowerUsersAliasSid );
  366. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  367. if ( !OK ) {
  368. goto CleanUp;
  369. }
  370. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  371. AceSid[AceCount] = PowerUsersAliasSid;
  372. AceMask[AceCount] = SERVER_ALL_ACCESS;
  373. InheritFlags[AceCount] = 0;
  374. AceCount++;
  375. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  376. AceSid[AceCount] = PowerUsersAliasSid;
  377. AceMask[AceCount] = GENERIC_ALL;
  378. InheritFlags[AceCount] = INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
  379. AceCount++;
  380. }
  381. }
  382. break;
  383. }
  384. DBGCHK( ( AceCount > MAX_ACE ), ( "ACE count exceeded" ) );
  385. if ( AceCount > MAX_ACE ) {
  386. goto CleanUp;
  387. }
  388. OK = BuildPrintObjectProtection( AceType,
  389. AceCount,
  390. AceSid,
  391. AceMask,
  392. InheritFlags,
  393. AdminsAliasSid,
  394. AdminsAliasSid,
  395. &GenericMapping[ObjectType],
  396. &ServerSD );
  397. DBGCHK( !OK, ( "BuildPrintObjectProtection failed" ) );
  398. CleanUp:
  399. if (WorldSid) {
  400. FreeSid( WorldSid );
  401. }
  402. if (AdminsAliasSid) {
  403. FreeSid( AdminsAliasSid );
  404. }
  405. if (CreatorOwnerSid) {
  406. FreeSid( CreatorOwnerSid );
  407. }
  408. if (PrintOpsAliasSid) {
  409. FreeSid( PrintOpsAliasSid );
  410. }
  411. if (SystemOpsAliasSid) {
  412. FreeSid( SystemOpsAliasSid );
  413. }
  414. if (PowerUsersAliasSid) {
  415. FreeSid( PowerUsersAliasSid );
  416. }
  417. pServerSecurityDescriptor = ServerSD;
  418. return ServerSD;
  419. }
  420. /* CreatePrinterSecurityDescriptor
  421. *
  422. * Creates a default security descriptor for a printer by inheritance
  423. * of the access flags in the local spooler's security descriptor.
  424. * The resulting descriptor is allocated from the process' heap
  425. * and should be freed by DeletePrinterSecurityDescriptor.
  426. *
  427. * Argument: pCreatorSecurityDescriptor - if the creator supplies
  428. * a security descriptor, this should point to it. Otherwise
  429. * it should be NULL.
  430. *
  431. * Return: The printer's security descriptor
  432. *
  433. */
  434. PSECURITY_DESCRIPTOR
  435. CreatePrinterSecurityDescriptor(
  436. PSECURITY_DESCRIPTOR pCreatorSecurityDescriptor
  437. )
  438. {
  439. HANDLE ClientToken;
  440. PSECURITY_DESCRIPTOR pPrivateObjectSecurity;
  441. PSECURITY_DESCRIPTOR pPrinterSecurityDescriptor;
  442. DWORD ObjectType = SPOOLER_OBJECT_PRINTER;
  443. BOOL OK;
  444. HANDLE hToken;
  445. BOOL DaclPresent;
  446. PACL pDacl;
  447. BOOL DaclDefaulted = FALSE;
  448. DWORD HackOutAce;
  449. if( GetTokenHandle( &ClientToken ) )
  450. {
  451. hToken = RevertToPrinterSelf( );
  452. OK = CreatePrivateObjectSecurity( pServerSecurityDescriptor,
  453. pCreatorSecurityDescriptor,
  454. &pPrivateObjectSecurity,
  455. TRUE, // This is a container
  456. ClientToken,
  457. &GenericMapping[ObjectType] );
  458. ImpersonatePrinterClient( hToken );
  459. CloseHandle(ClientToken);
  460. DBGCHK( !OK, ( "CreatePrivateObjectSecurity failed: Error %d", GetLastError() ) );
  461. if( !OK )
  462. return NULL;
  463. pPrinterSecurityDescriptor = pPrivateObjectSecurity;
  464. if( !pCreatorSecurityDescriptor )
  465. {
  466. GetSecurityDescriptorDacl( pPrinterSecurityDescriptor,
  467. &DaclPresent,
  468. &pDacl,
  469. &DaclDefaulted );
  470. /* HACK HACK HACK HACK HACK
  471. *
  472. * We defined an extra ACE for the benefit of the ACL editor.
  473. * This is container-inherit,
  474. * and we want it to propagate onto documents.
  475. * However, this means it will also propagate onto printers,
  476. * which we definitely don't want.
  477. */
  478. HackOutAce = GetHackOutAce( pDacl );
  479. if( HackOutAce != (DWORD)-1 )
  480. DeleteAce( pDacl, HackOutAce );
  481. #if DBG
  482. if( MODULE_DEBUG & DBG_SECURITY ){
  483. DBGMSG( DBG_SECURITY, ( "Printer security descriptor DACL:\n" ));
  484. DumpAcl( pDacl );
  485. }
  486. #endif /* DBG */
  487. }
  488. }
  489. else
  490. {
  491. OK = FALSE;
  492. }
  493. return ( OK ? pPrinterSecurityDescriptor : NULL );
  494. }
  495. /*
  496. *
  497. */
  498. DWORD GetHackOutAce( PACL pDacl )
  499. {
  500. DWORD i;
  501. PACCESS_ALLOWED_ACE pAce;
  502. BOOL OK = TRUE;
  503. i = 0;
  504. while( OK )
  505. {
  506. OK = GetAce( pDacl, i, (LPVOID *)&pAce );
  507. DBGCHK( !OK, ( "Failed to get ACE. Error %d", GetLastError() ) );
  508. /* Find the dummy ace that isn't inherit-only:
  509. */
  510. if( OK && ( pAce->Mask == DUMMY_ACE_ACCESS_MASK )
  511. &&( !( pAce->Header.AceFlags & INHERIT_ONLY_ACE ) ) )
  512. return i;
  513. }
  514. return (DWORD)-1;
  515. }
  516. /* SetPrinterSecurityDescriptor
  517. *
  518. * Arguments:
  519. *
  520. * SecurityInformation - Type of security information to be applied,
  521. * typically DACL_SECURITY_INFORMATION. (This is a 32-bit array.)
  522. *
  523. * pModificationDescriptor - A pointer to a pointer to a security
  524. * descriptor to be applied to the previous descriptor.
  525. *
  526. * pObjectSecurityDescriptor - The previous descriptor which is to be
  527. * modified.
  528. *
  529. *
  530. * Return:
  531. *
  532. * Boolean indicating success or otherwise.
  533. *
  534. */
  535. BOOL
  536. SetPrinterSecurityDescriptor(
  537. SECURITY_INFORMATION SecurityInformation,
  538. PSECURITY_DESCRIPTOR pModificationDescriptor,
  539. PSECURITY_DESCRIPTOR *ppObjectsSecurityDescriptor
  540. )
  541. {
  542. HANDLE ClientToken;
  543. DWORD ObjectType = SPOOLER_OBJECT_PRINTER;
  544. BOOL OK = FALSE;
  545. HANDLE hToken;
  546. if( GetTokenHandle( &ClientToken ) )
  547. {
  548. /* SetPrivateObjectSecurity should not be called when we are
  549. * impersonating a client, since it may need to allocate memory:
  550. */
  551. hToken = RevertToPrinterSelf( );
  552. OK = SetPrivateObjectSecurity( SecurityInformation,
  553. pModificationDescriptor,
  554. ppObjectsSecurityDescriptor,
  555. &GenericMapping[ObjectType],
  556. ClientToken );
  557. ImpersonatePrinterClient( hToken );
  558. DBGCHK( !OK, ( "SetPrivateObjectSecurity failed: Error %d", GetLastError() ) );
  559. CloseHandle(ClientToken);
  560. }
  561. return OK;
  562. }
  563. /* CreateDocumentSecurityDescriptor
  564. *
  565. * Creates a default security descriptor for a document by inheritance
  566. * of the access flags in the supplied printer security descriptor.
  567. * The resulting descriptor is allocated from the process' heap
  568. * and should be freed by DeleteDocumentSecurityDescriptor.
  569. *
  570. * Argument: The printer's security descriptor
  571. *
  572. * Return: The document's security descriptor
  573. *
  574. */
  575. PSECURITY_DESCRIPTOR
  576. CreateDocumentSecurityDescriptor(
  577. PSECURITY_DESCRIPTOR pPrinterSecurityDescriptor
  578. )
  579. {
  580. HANDLE ClientToken;
  581. PSECURITY_DESCRIPTOR pPrivateObjectSecurity;
  582. PSECURITY_DESCRIPTOR pDocumentSecurityDescriptor;
  583. PSECURITY_DESCRIPTOR pSD = NULL;
  584. DWORD ObjectType = SPOOLER_OBJECT_DOCUMENT;
  585. BOOL OK = FALSE;
  586. HANDLE hToken;
  587. if( GetTokenHandle( &ClientToken ) )
  588. {
  589. hToken = RevertToPrinterSelf( );
  590. //
  591. // The function CreateDocumentSecurityDescriptor does not preserve
  592. // the last error correctly. If CreatePrivateObjectSecurityEx fails,
  593. // it sets the last error. But after that,
  594. //
  595. OK = BuildJobOwnerSecurityDescriptor(ClientToken, &pSD) &&
  596. CreatePrivateObjectSecurityEx(pPrinterSecurityDescriptor,
  597. pSD,
  598. &pPrivateObjectSecurity,
  599. NULL,
  600. FALSE, // This is not a container
  601. SEF_DACL_AUTO_INHERIT | SEF_SACL_AUTO_INHERIT,
  602. ClientToken,
  603. &GenericMapping[ObjectType] );
  604. DestroyJobOwnerSecurityDescriptor(pSD);
  605. ImpersonatePrinterClient( hToken );
  606. CloseHandle(ClientToken);
  607. DBGCHK( !OK, ( "CreatePrivateObjectSecurity failed: Error %d", GetLastError() ) );
  608. if( !OK )
  609. return NULL;
  610. pDocumentSecurityDescriptor = pPrivateObjectSecurity;
  611. #if DBG
  612. if( MODULE_DEBUG & DBG_SECURITY )
  613. {
  614. BOOL DaclPresent;
  615. PACL pDacl;
  616. BOOL DaclDefaulted = FALSE;
  617. GetSecurityDescriptorDacl( pDocumentSecurityDescriptor,
  618. &DaclPresent,
  619. &pDacl,
  620. &DaclDefaulted );
  621. DBGMSG( DBG_SECURITY, ( "Document security descriptor DACL:\n" ));
  622. DumpAcl( pDacl );
  623. }
  624. #endif /* DBG */
  625. }
  626. else
  627. {
  628. OK = FALSE;
  629. }
  630. return ( OK ? pDocumentSecurityDescriptor : NULL );
  631. }
  632. /*
  633. *
  634. */
  635. BOOL DeletePrinterSecurity(
  636. PINIPRINTER pIniPrinter
  637. )
  638. {
  639. BOOL OK;
  640. OK = DestroyPrivateObjectSecurity( &pIniPrinter->pSecurityDescriptor );
  641. pIniPrinter->pSecurityDescriptor = NULL;
  642. DBGCHK( !OK, ( "DestroyPrivateObjectSecurity failed. Error %d", GetLastError() ) );
  643. return OK;
  644. }
  645. /*
  646. *
  647. */
  648. BOOL DeleteDocumentSecurity(
  649. PINIJOB pIniJob
  650. )
  651. {
  652. BOOL OK;
  653. OK = DestroyPrivateObjectSecurity( &pIniJob->pSecurityDescriptor );
  654. DBGCHK( !OK, ( "DestroyPrivateObjectSecurity failed. Error %d", GetLastError() ) );
  655. OK = ObjectCloseAuditAlarm( szSpooler, pIniJob,
  656. pIniJob->GenerateOnClose );
  657. DBGCHK( !OK, ( "ObjectCloseAuditAlarm failed. Error %d", GetLastError() ) );
  658. return OK;
  659. }
  660. #ifdef OLDSTUFF
  661. /* AllocateLocalSD
  662. *
  663. * Makes a copy of a security descriptor, allocating it out of the local heap.
  664. * The source descriptor MUST be in self-relative format.
  665. *
  666. * Argument
  667. *
  668. * pSourceSD - Pointer to a self-relative security descriptor
  669. *
  670. *
  671. * Returns
  672. *
  673. * A pointer to a locally allocated security descriptor.
  674. *
  675. * If the function fails to allocate the memory, NULL is returned.
  676. *
  677. * Note, if an invalid security descriptor is passed to
  678. * GetSecurityDescriptorLength, the return value is undefined,
  679. * therefore the caller should ensure that the source is valid.
  680. */
  681. PSECURITY_DESCRIPTOR AllocateLocalSD( PSECURITY_DESCRIPTOR pSourceSD )
  682. {
  683. DWORD Length;
  684. PSECURITY_DESCRIPTOR pLocalSD;
  685. Length = GetSecurityDescriptorLength( pSourceSD );
  686. pLocalSD = AllocSplMem( Length );
  687. if( pLocalSD )
  688. {
  689. memcpy( pLocalSD, pSourceSD, Length );
  690. }
  691. return pLocalSD;
  692. }
  693. #endif /* OLDSTUFF */
  694. //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  695. BOOL
  696. BuildPrintObjectProtection(
  697. IN PUCHAR AceType,
  698. IN DWORD AceCount,
  699. IN PSID *AceSid,
  700. IN ACCESS_MASK *AceMask,
  701. IN BYTE *InheritFlags,
  702. IN PSID OwnerSid,
  703. IN PSID GroupSid,
  704. IN PGENERIC_MAPPING GenericMap,
  705. OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor
  706. )
  707. /*++
  708. Routine Description:
  709. This routine builds a self-relative security descriptor ready
  710. to be applied to one of the print manager objects.
  711. If so indicated, a pointer to the last RID of the SID in the last
  712. ACE of the DACL is returned and a flag set indicating that the RID
  713. must be replaced before the security descriptor is applied to an object.
  714. This is to support USER object protection, which must grant some
  715. access to the user represented by the object.
  716. The SACL of each of these objects will be set to:
  717. Audit
  718. Success | Fail
  719. WORLD
  720. (Write | Delete | WriteDacl | AccessSystemSecurity)
  721. Arguments:
  722. AceType - Array of AceTypes.
  723. Must be ACCESS_ALLOWED_ACE_TYPE or ACCESS_DENIED_ACE_TYPE.
  724. AceCount - The number of ACEs to be included in the DACL.
  725. AceSid - Points to an array of SIDs to be granted access by the DACL.
  726. If the target SAM object is a User object, then the last entry
  727. in this array is expected to be the SID of an account within the
  728. domain with the last RID not yet set. The RID will be set during
  729. actual account creation.
  730. AceMask - Points to an array of accesses to be granted by the DACL.
  731. The n'th entry of this array corresponds to the n'th entry of
  732. the AceSid array. These masks should not include any generic
  733. access types.
  734. InheritFlags - Pointer to an array of inherit flags.
  735. The n'th entry of this array corresponds to the n'th entry of
  736. the AceSid array.
  737. OwnerSid - The SID of the owner to be assigned to the descriptor.
  738. GroupSid - The SID of the group to be assigned to the descriptor.
  739. GenericMap - Points to a generic mapping for the target object type.
  740. ppSecurityDescriptor - Receives a pointer to the security descriptor.
  741. This will be allcated from the process' heap, not the spooler's,
  742. and should therefore be freed with LocalFree().
  743. IN DWORD AceCount,
  744. IN PSID *AceSid,
  745. IN ACCESS_MASK *AceMask,
  746. IN BYTE *InheritFlags,
  747. IN PSID OwnerSid,
  748. IN PSID GroupSid,
  749. IN PGENERIC_MAPPING GenericMap,
  750. OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor
  751. Return Value:
  752. TBS.
  753. --*/
  754. {
  755. SECURITY_DESCRIPTOR Absolute;
  756. PSECURITY_DESCRIPTOR Relative = NULL;
  757. PACL TmpAcl= NULL;
  758. PACCESS_ALLOWED_ACE TmpAce;
  759. DWORD SDLength;
  760. DWORD DaclLength;
  761. DWORD i;
  762. BOOL bReturn = FALSE;
  763. //
  764. // The approach is to set up an absolute security descriptor that
  765. // looks like what we want and then copy it to make a self-relative
  766. // security descriptor.
  767. //
  768. if (InitializeSecurityDescriptor( &Absolute,
  769. SECURITY_DESCRIPTOR_REVISION1 ) &&
  770. SetSecurityDescriptorOwner( &Absolute, OwnerSid, FALSE ) &&
  771. SetSecurityDescriptorGroup( &Absolute, GroupSid, FALSE ) ) {
  772. //
  773. // Discretionary ACL
  774. //
  775. // Calculate its length,
  776. // Allocate it,
  777. // Initialize it,
  778. // Add each ACE
  779. // Set ACE as InheritOnly if necessary
  780. // Add it to the security descriptor
  781. //
  782. DaclLength = (DWORD)sizeof(ACL);
  783. for (i=0; i<AceCount; i++) {
  784. DaclLength += GetLengthSid( AceSid[i] ) +
  785. (DWORD)sizeof(ACCESS_ALLOWED_ACE) -
  786. (DWORD)sizeof(DWORD); //Subtract out SidStart field length
  787. }
  788. TmpAcl = AllocSplMem( DaclLength );
  789. if (TmpAcl && InitializeAcl( TmpAcl, DaclLength, ACL_REVISION2 )) {
  790. BOOL bLoop = TRUE;
  791. for (i=0; bLoop && i < AceCount; i++)
  792. {
  793. if( AceType[i] == ACCESS_ALLOWED_ACE_TYPE ) {
  794. bLoop = AddAccessAllowedAce ( TmpAcl, ACL_REVISION2, AceMask[i], AceSid[i] );
  795. } else {
  796. bLoop = AddAccessDeniedAce ( TmpAcl, ACL_REVISION2, AceMask[i], AceSid[i] );
  797. }
  798. if (bLoop) {
  799. if (InheritFlags[i] != 0)
  800. {
  801. if ( bLoop = GetAce( TmpAcl, i, (LPVOID *)&TmpAce )) {
  802. TmpAce->Header.AceFlags = InheritFlags[i];
  803. }
  804. }
  805. }
  806. }
  807. if (bLoop) {
  808. #if DBG
  809. DBGMSG( DBG_SECURITY, ( "Server security descriptor DACL:\n" ) );
  810. DumpAcl(TmpAcl);
  811. #endif /* DBG */
  812. if (SetSecurityDescriptorDacl (&Absolute, TRUE, TmpAcl, FALSE )) {
  813. //
  814. // Convert the Security Descriptor to Self-Relative
  815. //
  816. // Get the length needed
  817. // Allocate that much memory
  818. // Copy it
  819. // Free the generated absolute ACLs
  820. //
  821. SDLength = GetSecurityDescriptorLength( &Absolute );
  822. Relative = LocalAlloc( 0, SDLength );
  823. if (Relative) {
  824. bReturn = MakeSelfRelativeSD(&Absolute, Relative, &SDLength );
  825. }
  826. }
  827. }
  828. }
  829. }
  830. if (bReturn) {
  831. *ppSecurityDescriptor = Relative;
  832. } else {
  833. *ppSecurityDescriptor = NULL;
  834. if (Relative) {
  835. LocalFree(Relative);
  836. }
  837. }
  838. if (TmpAcl){
  839. FreeSplMem(TmpAcl);
  840. }
  841. return(bReturn);
  842. }
  843. BOOL
  844. ValidateObjectAccess(
  845. IN DWORD ObjectType,
  846. IN ACCESS_MASK DesiredAccess,
  847. IN LPVOID ObjectHandle,
  848. OUT PACCESS_MASK pGrantedAccess,
  849. IN PINISPOOLER pIniSpooler
  850. )
  851. /*++
  852. Routine Description:
  853. Arguments:
  854. ObjectType - SPOOLER_OBJECT_* value, which is an index into the global
  855. mapping for spooler objects.
  856. DesiredAccess - The type of access requested.
  857. ObjectHandle - If ObjectType == SPOOLER_OBJECT_PRINTER, this must be
  858. a printer handle, if SPOOLER_OBJECT_DOCUMENT, a pointer to a INIJOB
  859. structure. For SPOOLER_OBJECT_SERVER this is ignored.
  860. Return Value:
  861. TRUE if requested access is granted.
  862. --*/
  863. {
  864. LPWSTR pObjectName;
  865. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  866. PSPOOL pSpool = NULL;
  867. PINIPRINTER pIniPrinter;
  868. PINIJOB pIniJob;
  869. HANDLE ClientToken;
  870. BOOL AccessCheckOK;
  871. BOOL OK;
  872. BOOL AccessStatus = TRUE;
  873. ACCESS_MASK MappedDesiredAccess;
  874. DWORD GrantedAccess = 0;
  875. PBOOL pGenerateOnClose;
  876. BYTE PrivilegeSetBuffer[256];
  877. DWORD PrivilegeSetBufferLength = 256;
  878. PPRIVILEGE_SET pPrivilegeSet;
  879. BOOL HackForNoImpersonationToken = FALSE;
  880. DWORD dwRetCode;
  881. PTOKEN_PRIVILEGES pPreviousTokenPrivileges;
  882. DWORD PreviousTokenPrivilegesLength;
  883. //
  884. // Some Print Providers may not require Security
  885. //
  886. if ( (pIniSpooler->SpoolerFlags & SPL_SECURITY_CHECK) == FALSE ) return TRUE;
  887. switch( ObjectType )
  888. {
  889. case SPOOLER_OBJECT_SERVER:
  890. case SPOOLER_OBJECT_XCV:
  891. if( ObjectHandle )
  892. pSpool = ObjectHandle;
  893. ObjectHandle = pIniSpooler;
  894. pObjectName = pIniSpooler->pMachineName;
  895. pSecurityDescriptor = pServerSecurityDescriptor;
  896. pGenerateOnClose = &ServerGenerateOnClose;
  897. break;
  898. case SPOOLER_OBJECT_PRINTER:
  899. pSpool = ObjectHandle;
  900. pIniPrinter = pSpool->pIniPrinter;
  901. pObjectName = pIniPrinter->pName;
  902. pSecurityDescriptor = pIniPrinter->pSecurityDescriptor;
  903. pGenerateOnClose = &pSpool->GenerateOnClose;
  904. break;
  905. case SPOOLER_OBJECT_DOCUMENT:
  906. pIniJob = (PINIJOB)ObjectHandle;
  907. pObjectName = pIniJob->pDocument;
  908. pSecurityDescriptor = pIniJob->pSecurityDescriptor;
  909. pGenerateOnClose = &pIniJob->GenerateOnClose;
  910. break;
  911. }
  912. MapGenericToSpecificAccess( ObjectType, DesiredAccess, &MappedDesiredAccess );
  913. if (!(OK = GetTokenHandle(&ClientToken))) {
  914. if (pGrantedAccess) {
  915. *pGrantedAccess = 0;
  916. }
  917. return(FALSE);
  918. }
  919. if (MappedDesiredAccess & ACCESS_SYSTEM_SECURITY) {
  920. if (!SetRequiredPrivileges( ClientToken,
  921. &pPreviousTokenPrivileges,
  922. &PreviousTokenPrivilegesLength
  923. )) {
  924. if (pGrantedAccess) {
  925. *pGrantedAccess = 0;
  926. }
  927. CloseHandle(ClientToken);
  928. return(FALSE);
  929. }
  930. }
  931. pPrivilegeSet = (PPRIVILEGE_SET)PrivilegeSetBuffer;
  932. /* Call AccessCheck followed by ObjectOpenAuditAlarm rather than
  933. * AccessCheckAndAuditAlarm, because we may need to enable
  934. * SeSecurityPrivilege in order to check for ACCESS_SYSTEM_SECURITY
  935. * privilege. We must ensure that the security access-checking
  936. * API has the actual token whose security privilege we have enabled.
  937. * AccessCheckAndAuditAlarm is no good for this, because it opens
  938. * the client's token again, which may not have the privilege enabled.
  939. */
  940. AccessCheckOK = AccessCheck( pSecurityDescriptor,
  941. ClientToken,
  942. MappedDesiredAccess,
  943. &GenericMapping[ObjectType],
  944. pPrivilegeSet,
  945. &PrivilegeSetBufferLength,
  946. &GrantedAccess,
  947. &AccessStatus );
  948. if (!AccessCheckOK) {
  949. if (GetLastError() == ERROR_NO_IMPERSONATION_TOKEN) {
  950. DBGMSG(DBG_TRACE, ("No impersonation token. Access will be granted.\n"));
  951. HackForNoImpersonationToken = TRUE;
  952. dwRetCode = ERROR_SUCCESS;
  953. GrantedAccess = MappedDesiredAccess;
  954. } else {
  955. dwRetCode = GetLastError();
  956. }
  957. pPrivilegeSet = NULL;
  958. } else {
  959. if (!AccessStatus) {
  960. dwRetCode = GetLastError();
  961. }
  962. }
  963. OK = ObjectOpenAuditAlarm( szSpooler,
  964. ObjectHandle,
  965. ObjectTypeName[ObjectType],
  966. pObjectName,
  967. pSecurityDescriptor,
  968. ClientToken,
  969. MappedDesiredAccess,
  970. GrantedAccess,
  971. pPrivilegeSet,
  972. FALSE, /* No new object creation */
  973. AccessStatus,
  974. pGenerateOnClose );
  975. if( MappedDesiredAccess & ACCESS_SYSTEM_SECURITY )
  976. ResetRequiredPrivileges( ClientToken,
  977. pPreviousTokenPrivileges,
  978. PreviousTokenPrivilegesLength );
  979. if( !pSpool )
  980. ObjectCloseAuditAlarm( szSpooler, ObjectHandle, *pGenerateOnClose );
  981. //
  982. // Allowing power users to install printer drivers or other dlls into the
  983. // trusted component base is a security hole. We now require that administrators
  984. // and power users have the load driver privilege present in the token in order
  985. // to be able to preform administrative tasks on the spooler. See bug 352856
  986. // for more details.
  987. //
  988. if (AccessCheckOK &&
  989. AccessStatus &&
  990. ObjectType == SPOOLER_OBJECT_SERVER &&
  991. GrantedAccess & SERVER_ACCESS_ADMINISTER)
  992. {
  993. BOOL bPrivPresent;
  994. DWORD Attributes;
  995. dwRetCode = CheckPrivilegePresent(ClientToken,
  996. &gLoadDriverPrivilegeLuid,
  997. &bPrivPresent,
  998. &Attributes);
  999. if (dwRetCode == ERROR_SUCCESS)
  1000. {
  1001. //
  1002. // The reason why we check if the load driver privilege is present and
  1003. // not present AND enabled is the following. Let's assume you have been
  1004. // granted the privilege to load drivers.
  1005. // When you logon on interactively SeLoadDriverPrivilege is enabled.
  1006. // When you logon on via the secondary logon (runas which calls
  1007. // CreateProcessWithLogonW) then the privilege is disabled. We do not want
  1008. // to have inconsistent behavior regarding administering the spooler server.
  1009. //
  1010. if (!bPrivPresent)
  1011. {
  1012. //
  1013. // The caller has been granted SERVER_ACCESS_ADMINISTER permission but
  1014. // the caller doesn't have the privilege to load drivers. We do not
  1015. // grant the desired access in this case.
  1016. //
  1017. GrantedAccess = 0;
  1018. AccessStatus = FALSE;
  1019. dwRetCode = ERROR_ACCESS_DENIED;
  1020. }
  1021. }
  1022. else
  1023. {
  1024. //
  1025. // We cannot determine if the privilege is held, so we need to fail
  1026. // the AccessCheck function.
  1027. //
  1028. GrantedAccess = 0;
  1029. AccessCheckOK = FALSE;
  1030. dwRetCode = GetLastError();
  1031. }
  1032. }
  1033. CloseHandle (ClientToken);
  1034. if( pGrantedAccess )
  1035. *pGrantedAccess = GrantedAccess;
  1036. //
  1037. // we do the setlasterror here because we may have failed the AccessCheck
  1038. // or we succeeded but are denied access but the ObjectOpenAuditAlarm went
  1039. // thru smoothly and now there is no error code to return on the function
  1040. // so we specify the dwRetCode if we did fail.
  1041. //
  1042. if (!AccessCheckOK || !AccessStatus) {
  1043. SetLastError(dwRetCode);
  1044. }
  1045. return ( ( OK && AccessCheckOK && AccessStatus ) || HackForNoImpersonationToken );
  1046. }
  1047. /* AccessGranted
  1048. *
  1049. * Checks whether the desired access is granted, by comparing the GrantedAccess
  1050. * mask pointed to by pSpool.
  1051. *
  1052. * Parameters
  1053. *
  1054. * ObjectType - SPOOLER_OBJECT_* value, which is an index into the global
  1055. * mapping for spooler objects. This will not be SPOOLER_OBJECT_DOCUMENT,
  1056. * since we don't have document handles. It could potentially be
  1057. * SPOOLER_OBJECT_SERVER.
  1058. *
  1059. * DesiredAccess - The type of access requested.
  1060. *
  1061. * pSpool - A pointer to the SPOOL structure
  1062. *
  1063. * Returns
  1064. *
  1065. * TRUE - Access is granted
  1066. * FALSE - Access is not granted
  1067. */
  1068. BOOL
  1069. AccessGranted(
  1070. DWORD ObjectType,
  1071. ACCESS_MASK DesiredAccess,
  1072. PSPOOL pSpool
  1073. )
  1074. {
  1075. if ( (pSpool->pIniSpooler->SpoolerFlags & SPL_SECURITY_CHECK) == FALSE ) return TRUE;
  1076. MapGenericMask( &DesiredAccess,
  1077. &GenericMapping[ObjectType] );
  1078. return AreAllAccessesGranted( pSpool->GrantedAccess, DesiredAccess );
  1079. }
  1080. // Stolen from windows\base\username.c
  1081. // !!! Must close the handle that is returned
  1082. BOOL
  1083. GetTokenHandle(
  1084. PHANDLE pTokenHandle
  1085. )
  1086. {
  1087. if (!OpenThreadToken(GetCurrentThread(),
  1088. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1089. TRUE,
  1090. pTokenHandle)) {
  1091. if (GetLastError() == ERROR_NO_TOKEN) {
  1092. // This means we are not impersonating anybody.
  1093. // Instead, lets get the token out of the process.
  1094. if (!OpenProcessToken(GetCurrentProcess(),
  1095. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1096. pTokenHandle)) {
  1097. return FALSE;
  1098. }
  1099. } else
  1100. return FALSE;
  1101. }
  1102. return TRUE;
  1103. }
  1104. VOID MapGenericToSpecificAccess(
  1105. DWORD ObjectType,
  1106. DWORD GenericAccess,
  1107. PDWORD pSpecificAccess
  1108. )
  1109. {
  1110. *pSpecificAccess = GenericAccess;
  1111. MapGenericMask( pSpecificAccess,
  1112. &GenericMapping[ObjectType] );
  1113. }
  1114. /* GetSecurityInformation
  1115. *
  1116. * Fills in the security information with a mask specifying the contents
  1117. * of the security descriptor.
  1118. *
  1119. * Parameters
  1120. *
  1121. * pSecurityDescriptor - A pointer to a security descriptor
  1122. * that the caller wishes to set. This may be NULL.
  1123. *
  1124. * pSecurityInformation - A pointer to a buffer to receive
  1125. * the security information flags.
  1126. *
  1127. *
  1128. * Warning: This is an egregious hack.
  1129. * We need to find out what is being set so we can verify the caller
  1130. * has the required privileges.
  1131. * There's no way an app like Print Manager can tell us what bits
  1132. * of the security descriptor it wants to set.
  1133. *
  1134. * The following flags may be set:
  1135. *
  1136. * OWNER_SECURITY_INFORMATION
  1137. * GROUP_SECURITY_INFORMATION
  1138. * DACL_SECURITY_INFORMATION
  1139. * SACL_SECURITY_INFORMATION
  1140. *
  1141. * Returns
  1142. *
  1143. * TRUE - No errors occurred
  1144. * FALSE - An error occurred
  1145. *
  1146. */
  1147. BOOL
  1148. GetSecurityInformation(
  1149. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1150. PSECURITY_INFORMATION pSecurityInformation
  1151. )
  1152. {
  1153. SECURITY_INFORMATION SecurityInformation = 0;
  1154. BOOL Defaulted;
  1155. PSID pSidOwner;
  1156. PSID pSidGroup;
  1157. BOOL DaclPresent;
  1158. PACL pDacl;
  1159. BOOL SaclPresent;
  1160. PACL pSacl;
  1161. BOOL rc = TRUE;
  1162. if( pSecurityDescriptor
  1163. && IsValidSecurityDescriptor( pSecurityDescriptor ) )
  1164. {
  1165. if( GetSecurityDescriptorOwner( pSecurityDescriptor, &pSidOwner, &Defaulted )
  1166. && GetSecurityDescriptorGroup( pSecurityDescriptor, &pSidGroup, &Defaulted )
  1167. && GetSecurityDescriptorDacl( pSecurityDescriptor, &DaclPresent, &pDacl, &Defaulted )
  1168. && GetSecurityDescriptorSacl( pSecurityDescriptor, &SaclPresent, &pSacl, &Defaulted ) )
  1169. {
  1170. if( pSidOwner )
  1171. SecurityInformation |= OWNER_SECURITY_INFORMATION;
  1172. if( pSidGroup )
  1173. SecurityInformation |= GROUP_SECURITY_INFORMATION;
  1174. if( DaclPresent )
  1175. SecurityInformation |= DACL_SECURITY_INFORMATION;
  1176. if( SaclPresent )
  1177. SecurityInformation |= SACL_SECURITY_INFORMATION;
  1178. }
  1179. else
  1180. rc = FALSE;
  1181. }else {
  1182. DBGMSG(DBG_TRACE, ("Either NULL pSecurityDescriptor or !IsValidSecurityDescriptor %.8x\n", pSecurityDescriptor));
  1183. rc = FALSE;
  1184. }
  1185. DBGMSG( DBG_TRACE, ("GetSecurityInformation returns %d with SecurityInformation = %08x\n", rc, SecurityInformation) );
  1186. *pSecurityInformation = SecurityInformation;
  1187. return rc;
  1188. }
  1189. /* GetPrivilegeRequired
  1190. *
  1191. * Returns a mask containing the privileges required to set the specified
  1192. * security information.
  1193. *
  1194. * Parameter
  1195. *
  1196. * SecurityInformation - Flags specifying the security information
  1197. * that the caller wishes to set. This may be 0.
  1198. *
  1199. * Returns
  1200. *
  1201. * An access mask specifying the privileges required.
  1202. *
  1203. */
  1204. ACCESS_MASK
  1205. GetPrivilegeRequired(
  1206. SECURITY_INFORMATION SecurityInformation
  1207. )
  1208. {
  1209. ACCESS_MASK PrivilegeRequired = 0;
  1210. if( SecurityInformation & OWNER_SECURITY_INFORMATION )
  1211. PrivilegeRequired |= WRITE_OWNER;
  1212. if( SecurityInformation & GROUP_SECURITY_INFORMATION )
  1213. PrivilegeRequired |= WRITE_OWNER;
  1214. if( SecurityInformation & DACL_SECURITY_INFORMATION )
  1215. PrivilegeRequired |= WRITE_DAC;
  1216. if( SecurityInformation & SACL_SECURITY_INFORMATION )
  1217. PrivilegeRequired |= ACCESS_SYSTEM_SECURITY;
  1218. return PrivilegeRequired;
  1219. }
  1220. /* BuildPartialSecurityDescriptor
  1221. *
  1222. * Creates a copy of the source security descriptor, omitting those
  1223. * parts of the descriptor which the AccessGranted mask doesn't give
  1224. * read access to.
  1225. *
  1226. * Parameters
  1227. *
  1228. * AccessMask - Defines the permissions held by the client.
  1229. * This may include READ_CONTROL or ACCESS_SYSTEM_SECURITY.
  1230. *
  1231. * pSourceSecurityDescriptor - A pointer to the security descriptor
  1232. * upon which the partial security descriptor will be based.
  1233. * Its Owner, Group, DACL and SACL will be copied appropriately,
  1234. *
  1235. * ppPartialSecurityDescriptor - A pointer to a variable which
  1236. * will receive the address of the newly created descriptor.
  1237. * If the AccessMask parameter contains neither READ_CONTROL
  1238. * nor ACCESS_SYSTEM_SECURITY, the descriptor will be empty.
  1239. * The descriptor will be in self-relative format, and must
  1240. * be freed by the caller using FreeSplMem().
  1241. *
  1242. * pPartialSecurityDescriptorLength - A pointer to a variable
  1243. * to receive the length of the security descriptor.
  1244. * This should be passed as the second parameter to FreeSplMem()
  1245. * when the descriptor is freed.
  1246. *
  1247. * Returns
  1248. *
  1249. * TRUE - No error was detected
  1250. * FALSE - An error was detected
  1251. *
  1252. */
  1253. BOOL
  1254. BuildPartialSecurityDescriptor(
  1255. ACCESS_MASK AccessGranted,
  1256. PSECURITY_DESCRIPTOR pSourceSecurityDescriptor,
  1257. PSECURITY_DESCRIPTOR *ppPartialSecurityDescriptor,
  1258. PDWORD pPartialSecurityDescriptorLength
  1259. )
  1260. {
  1261. SECURITY_DESCRIPTOR AbsolutePartialSecurityDescriptor;
  1262. BOOL Defaulted = FALSE;
  1263. PSID pOwnerSid = NULL;
  1264. PSID pGroupSid = NULL;
  1265. BOOL DaclPresent = FALSE;
  1266. PACL pDacl = NULL;
  1267. BOOL SaclPresent = FALSE;
  1268. PACL pSacl = NULL;
  1269. BOOL ErrorOccurred = FALSE;
  1270. DWORD Length = 0;
  1271. PSECURITY_DESCRIPTOR pSelfRelativePartialSecurityDescriptor = NULL;
  1272. /* When we've initialized the security descriptor,
  1273. * it will have no owner, no primary group, no DACL and no SACL:
  1274. */
  1275. if( InitializeSecurityDescriptor( &AbsolutePartialSecurityDescriptor,
  1276. SECURITY_DESCRIPTOR_REVISION1 ) )
  1277. {
  1278. /* If the caller has READ_CONTROL permission,
  1279. * set the Owner, Group and DACL:
  1280. */
  1281. if( AreAllAccessesGranted( AccessGranted, READ_CONTROL ) )
  1282. {
  1283. if( GetSecurityDescriptorOwner( pSourceSecurityDescriptor,
  1284. &pOwnerSid, &Defaulted ) )
  1285. SetSecurityDescriptorOwner( &AbsolutePartialSecurityDescriptor,
  1286. pOwnerSid, Defaulted );
  1287. else
  1288. ErrorOccurred = TRUE;
  1289. if( GetSecurityDescriptorGroup( pSourceSecurityDescriptor,
  1290. &pGroupSid, &Defaulted ) )
  1291. SetSecurityDescriptorGroup( &AbsolutePartialSecurityDescriptor,
  1292. pGroupSid, Defaulted );
  1293. else
  1294. ErrorOccurred = TRUE;
  1295. if( GetSecurityDescriptorDacl( pSourceSecurityDescriptor,
  1296. &DaclPresent, &pDacl, &Defaulted ) )
  1297. SetSecurityDescriptorDacl( &AbsolutePartialSecurityDescriptor,
  1298. DaclPresent, pDacl, Defaulted );
  1299. else
  1300. ErrorOccurred = TRUE;
  1301. }
  1302. /* If the caller has ACCESS_SYSTEM_SECURITY permission,
  1303. * set the SACL:
  1304. */
  1305. if( AreAllAccessesGranted( AccessGranted, ACCESS_SYSTEM_SECURITY ) )
  1306. {
  1307. if( GetSecurityDescriptorSacl( pSourceSecurityDescriptor,
  1308. &SaclPresent, &pSacl, &Defaulted ) )
  1309. SetSecurityDescriptorSacl( &AbsolutePartialSecurityDescriptor,
  1310. SaclPresent, pSacl, Defaulted );
  1311. else
  1312. ErrorOccurred = TRUE;
  1313. }
  1314. if( !ErrorOccurred )
  1315. {
  1316. Length = 0;
  1317. if( !MakeSelfRelativeSD( &AbsolutePartialSecurityDescriptor,
  1318. pSelfRelativePartialSecurityDescriptor,
  1319. &Length ) )
  1320. {
  1321. if( GetLastError( ) == ERROR_INSUFFICIENT_BUFFER )
  1322. {
  1323. pSelfRelativePartialSecurityDescriptor = AllocSplMem( Length );
  1324. if( !pSelfRelativePartialSecurityDescriptor
  1325. || !MakeSelfRelativeSD( &AbsolutePartialSecurityDescriptor,
  1326. pSelfRelativePartialSecurityDescriptor,
  1327. &Length ) )
  1328. {
  1329. ErrorOccurred = TRUE;
  1330. }
  1331. }
  1332. else
  1333. {
  1334. ErrorOccurred = TRUE;
  1335. DBGMSG(DBG_WARNING, ("MakeSelfRelativeSD failed: Error %d\n",
  1336. GetLastError()));
  1337. }
  1338. }
  1339. else
  1340. {
  1341. DBGMSG(DBG_WARNING, ("Expected MakeSelfRelativeSD to fail!\n"));
  1342. }
  1343. }
  1344. }
  1345. else
  1346. ErrorOccurred = TRUE;
  1347. if( !ErrorOccurred )
  1348. {
  1349. *ppPartialSecurityDescriptor = pSelfRelativePartialSecurityDescriptor;
  1350. *pPartialSecurityDescriptorLength = Length;
  1351. }
  1352. return !ErrorOccurred;
  1353. }
  1354. BOOL
  1355. SetRequiredPrivileges(
  1356. IN HANDLE TokenHandle,
  1357. OUT PTOKEN_PRIVILEGES *ppPreviousTokenPrivileges,
  1358. OUT PDWORD pPreviousTokenPrivilegesLength
  1359. )
  1360. /*++
  1361. Routine Description:
  1362. Arguments:
  1363. TokenHandle - A token associated with the current thread or process
  1364. ppPreviousTokenPrivileges - This will be filled with the address of the
  1365. buffer allocated to hold the previously existing privileges for this
  1366. process or thread.
  1367. pPreviousTokenPrivilegesLength - This will be filled with the length of the
  1368. buffer allocated.
  1369. Return Value:
  1370. TRUE if successful.
  1371. --*/
  1372. {
  1373. /* Make enough room for TOKEN_PRIVILEGES with an array of 2 Privileges
  1374. * (there's 1 by default):
  1375. */
  1376. #define PRIV_SECURITY 0
  1377. #define PRIV_COUNT 1
  1378. LUID SecurityValue;
  1379. BYTE TokenPrivilegesBuffer[ sizeof( TOKEN_PRIVILEGES ) +
  1380. ( ( PRIV_COUNT - 1 ) *
  1381. sizeof( LUID_AND_ATTRIBUTES ) ) ];
  1382. PTOKEN_PRIVILEGES pTokenPrivileges;
  1383. DWORD FirstTryBufferLength = 256;
  1384. DWORD BytesNeeded;
  1385. //
  1386. // First, assert Audit privilege
  1387. //
  1388. memset( &SecurityValue, 0, sizeof SecurityValue );
  1389. if( !LookupPrivilegeValue( NULL, SE_SECURITY_NAME, &SecurityValue ) )
  1390. {
  1391. DBGMSG( DBG_WARNING,
  1392. ( "LookupPrivilegeValue failed: Error %d\n", GetLastError( ) ) );
  1393. return FALSE;
  1394. }
  1395. /* Allocate a buffer of a reasonable length to hold the current privileges,
  1396. * so we can restore them later:
  1397. */
  1398. *pPreviousTokenPrivilegesLength = FirstTryBufferLength;
  1399. if( !( *ppPreviousTokenPrivileges = AllocSplMem( FirstTryBufferLength ) ) )
  1400. return FALSE;
  1401. memset( &TokenPrivilegesBuffer, 0, sizeof TokenPrivilegesBuffer );
  1402. pTokenPrivileges = (PTOKEN_PRIVILEGES)&TokenPrivilegesBuffer;
  1403. /*
  1404. * Set up the privilege set we will need
  1405. */
  1406. pTokenPrivileges->PrivilegeCount = PRIV_COUNT;
  1407. pTokenPrivileges->Privileges[PRIV_SECURITY].Luid = SecurityValue;
  1408. pTokenPrivileges->Privileges[PRIV_SECURITY].Attributes = SE_PRIVILEGE_ENABLED;
  1409. if (!AdjustTokenPrivileges( TokenHandle,
  1410. FALSE,
  1411. pTokenPrivileges,
  1412. *pPreviousTokenPrivilegesLength,
  1413. *ppPreviousTokenPrivileges,
  1414. &BytesNeeded )) {
  1415. if( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  1416. {
  1417. *pPreviousTokenPrivilegesLength = BytesNeeded;
  1418. *ppPreviousTokenPrivileges = ReallocSplMem(
  1419. *ppPreviousTokenPrivileges,
  1420. 0,
  1421. *pPreviousTokenPrivilegesLength );
  1422. if( *ppPreviousTokenPrivileges )
  1423. {
  1424. if (!AdjustTokenPrivileges( TokenHandle,
  1425. FALSE,
  1426. pTokenPrivileges,
  1427. *pPreviousTokenPrivilegesLength,
  1428. *ppPreviousTokenPrivileges,
  1429. &BytesNeeded )) {
  1430. DBGMSG( DBG_WARNING, ("AdjustTokenPrivileges failed: Error %d\n", GetLastError()));
  1431. goto Fail;
  1432. }
  1433. }
  1434. else
  1435. {
  1436. *pPreviousTokenPrivilegesLength = 0;
  1437. goto Fail;
  1438. }
  1439. }
  1440. else
  1441. {
  1442. DBGMSG( DBG_WARNING, ("AdjustTokenPrivileges failed: Error %d\n", GetLastError()));
  1443. goto Fail;
  1444. }
  1445. }
  1446. return TRUE;
  1447. Fail:
  1448. if (*ppPreviousTokenPrivileges) {
  1449. FreeSplMem(*ppPreviousTokenPrivileges);
  1450. }
  1451. return FALSE;
  1452. }
  1453. BOOL
  1454. ResetRequiredPrivileges(
  1455. IN HANDLE TokenHandle,
  1456. IN PTOKEN_PRIVILEGES pPreviousTokenPrivileges,
  1457. IN DWORD PreviousTokenPrivilegesLength
  1458. )
  1459. /*++
  1460. Routine Description:
  1461. Arguments:
  1462. TokenHandle - A token associated with the current thread or process
  1463. pPreviousTokenPrivileges - The address of the buffer holding the previous
  1464. privileges to be reinstated.
  1465. PreviousTokenPrivilegesLength - Length of the buffer for deallocation.
  1466. Return Value:
  1467. TRUE if successful.
  1468. --*/
  1469. {
  1470. BOOL OK;
  1471. OK = AdjustTokenPrivileges ( TokenHandle,
  1472. FALSE,
  1473. pPreviousTokenPrivileges,
  1474. 0,
  1475. NULL,
  1476. NULL );
  1477. FreeSplMem( pPreviousTokenPrivileges );
  1478. return OK;
  1479. }
  1480. /* CreateEverybodySecurityDescriptor
  1481. *
  1482. * Creates a security descriptor giving everyone access
  1483. *
  1484. * Arguments: None
  1485. *
  1486. * Return: The security descriptor returned by BuildPrintObjectProtection.
  1487. *
  1488. */
  1489. #undef MAX_ACE
  1490. #define MAX_ACE 5
  1491. #define DBGCHK( Condition, ErrorInfo ) \
  1492. if( Condition ) DBGMSG( DBG_WARNING, ErrorInfo )
  1493. PSECURITY_DESCRIPTOR
  1494. CreateEverybodySecurityDescriptor(
  1495. VOID
  1496. )
  1497. {
  1498. UCHAR AceType[MAX_ACE];
  1499. PSID AceSid[MAX_ACE]; // Don't expect more than MAX_ACE ACEs in any of these.
  1500. DWORD AceCount;
  1501. //
  1502. // For Code optimization we replace 5 individaul
  1503. // SID_IDENTIFIER_AUTHORITY with an array of
  1504. // SID_IDENTIFIER_AUTHORITYs
  1505. // where
  1506. // SidAuthority[0] = UserSidAuthority
  1507. // SidAuthority[1] = PowerSidAuthority
  1508. // SidAuthority[2] = CreatorSidAuthority
  1509. // SidAuthority[3] = SystemSidAuthority
  1510. // SidAuthority[4] = AdminSidAuthority
  1511. //
  1512. SID_IDENTIFIER_AUTHORITY SidAuthority[MAX_ACE] = {
  1513. SECURITY_NT_AUTHORITY,
  1514. SECURITY_NT_AUTHORITY,
  1515. SECURITY_CREATOR_SID_AUTHORITY,
  1516. SECURITY_NT_AUTHORITY,
  1517. SECURITY_NT_AUTHORITY
  1518. };
  1519. //
  1520. // For code optimization we replace 5 individual Sids with
  1521. // an array of Sids
  1522. // where
  1523. // Sid[0] = UserSid
  1524. // Sid[1] = PowerSid
  1525. // Sid[2] = CreatorSid
  1526. // Sid[3] = SystemSid
  1527. // Sid[4] = AdminSid
  1528. //
  1529. PSID Sids[MAX_ACE] = {NULL,NULL,NULL,NULL,NULL};
  1530. //
  1531. // Access masks corresponding to Sids
  1532. //
  1533. ACCESS_MASK AceMask[MAX_ACE] = {
  1534. (FILE_GENERIC_EXECUTE | SYNCHRONIZE | FILE_GENERIC_WRITE | FILE_GENERIC_READ) &
  1535. ~READ_CONTROL & ~FILE_WRITE_ATTRIBUTES &
  1536. ~FILE_WRITE_EA&~FILE_READ_DATA&~FILE_LIST_DIRECTORY ,
  1537. (FILE_GENERIC_EXECUTE | SYNCHRONIZE | FILE_GENERIC_WRITE | FILE_GENERIC_READ) &
  1538. ~READ_CONTROL & ~FILE_WRITE_ATTRIBUTES &
  1539. ~FILE_WRITE_EA&~FILE_READ_DATA&~FILE_LIST_DIRECTORY ,
  1540. STANDARD_RIGHTS_ALL | FILE_GENERIC_EXECUTE | FILE_GENERIC_WRITE |
  1541. FILE_GENERIC_READ | FILE_ALL_ACCESS ,
  1542. STANDARD_RIGHTS_ALL | FILE_GENERIC_EXECUTE | FILE_GENERIC_WRITE |
  1543. FILE_GENERIC_READ | FILE_ALL_ACCESS ,
  1544. STANDARD_RIGHTS_ALL | FILE_GENERIC_EXECUTE | FILE_GENERIC_WRITE |
  1545. FILE_GENERIC_READ | FILE_ALL_ACCESS ,
  1546. };
  1547. //
  1548. // SubAuthorities leading to the proper Group
  1549. //
  1550. DWORD SubAuthorities[3*MAX_ACE] = {
  1551. 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_USERS ,
  1552. 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_POWER_USERS ,
  1553. 1 , SECURITY_CREATOR_OWNER_RID , 0 ,
  1554. 1 , SECURITY_LOCAL_SYSTEM_RID , 0 ,
  1555. 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_ADMINS
  1556. };
  1557. //
  1558. // CONTAINER_INHERIT_ACE -> This folder and subfolders
  1559. // OBJECT_INHERIT_ACE -> Files
  1560. //
  1561. BYTE InheritFlags[MAX_ACE] = {
  1562. CONTAINER_INHERIT_ACE,
  1563. CONTAINER_INHERIT_ACE,
  1564. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  1565. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  1566. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
  1567. };
  1568. PSECURITY_DESCRIPTOR ServerSD = NULL;
  1569. //
  1570. // Printer SD
  1571. //
  1572. for(AceCount = 0;
  1573. ( (AceCount < MAX_ACE) &&
  1574. AllocateAndInitializeSid(&SidAuthority[AceCount],
  1575. (BYTE)SubAuthorities[AceCount*3],
  1576. SubAuthorities[AceCount*3+1],
  1577. SubAuthorities[AceCount*3+2],
  1578. 0, 0, 0, 0, 0, 0,
  1579. &Sids[AceCount]));
  1580. AceCount++)
  1581. {
  1582. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  1583. AceSid[AceCount] = Sids[AceCount];
  1584. }
  1585. if(AceCount == MAX_ACE)
  1586. {
  1587. if(!BuildPrintObjectProtection( AceType,
  1588. AceCount,
  1589. AceSid,
  1590. AceMask,
  1591. InheritFlags,
  1592. NULL,
  1593. NULL,
  1594. NULL,
  1595. &ServerSD ) )
  1596. {
  1597. DBGMSG( DBG_WARNING,( "Couldn't buidl Print Object protection" ) );
  1598. ServerSD = NULL;
  1599. }
  1600. }
  1601. else
  1602. {
  1603. DBGMSG( DBG_WARNING,( "Couldn't Allocate and initialize SIDs" ) );
  1604. }
  1605. for(AceCount=0;AceCount<MAX_ACE;AceCount++)
  1606. {
  1607. if(Sids[AceCount])
  1608. FreeSid( Sids[AceCount] );
  1609. }
  1610. return ServerSD;
  1611. }
  1612. /* CreateDriversShareSecurityDescriptor
  1613. *
  1614. * Creates a security descriptor for the drivers$ share.
  1615. * This reflects the security descriptor applied to the print server,
  1616. * in that Everyone is given GENERIC_READ | GENERIC_EXECUTE,
  1617. * and everyone with SERVER_ACCESS_ADMINISTER (Administrators,
  1618. * Power Users etc.) is given GENERIC_ALL access to the share,
  1619. *
  1620. * If in future releases we support changes to the print server
  1621. * security descriptor (e.g. allowing the ability to deny
  1622. * SERVER_ACCESS_ENUMERATE), this routine will have to become more
  1623. * sophisticated, as the access to the share will probably need
  1624. * to be modified accordingly.
  1625. *
  1626. * Arguments: None
  1627. *
  1628. * Return: The security descriptor returned by BuildPrintObjectProtection.
  1629. *
  1630. */
  1631. #undef MAX_ACE
  1632. #define MAX_ACE 20
  1633. #define DBGCHK( Condition, ErrorInfo ) \
  1634. if( Condition ) DBGMSG( DBG_WARNING, ErrorInfo )
  1635. PSECURITY_DESCRIPTOR
  1636. CreateDriversShareSecurityDescriptor(
  1637. VOID
  1638. )
  1639. {
  1640. DWORD ObjectType = SPOOLER_OBJECT_SERVER;
  1641. NT_PRODUCT_TYPE NtProductType;
  1642. PSID AceSid[MAX_ACE]; // Don't expect more than MAX_ACE ACEs in any of these.
  1643. ACCESS_MASK AceMask[MAX_ACE]; // Access masks corresponding to Sids
  1644. BYTE InheritFlags[MAX_ACE]; //
  1645. UCHAR AceType[MAX_ACE];
  1646. DWORD AceCount;
  1647. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1648. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1649. SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  1650. PSID WorldSid = NULL;
  1651. PSID AdminsAliasSid = NULL;
  1652. PSID PrintOpsAliasSid = NULL;
  1653. PSID SystemOpsAliasSid = NULL;
  1654. PSID PowerUsersAliasSid = NULL;
  1655. PSID CreatorOwnerSid = NULL;
  1656. PSECURITY_DESCRIPTOR pDriversShareSD = NULL;
  1657. BOOL OK;
  1658. //
  1659. // Printer SD
  1660. //
  1661. AceCount = 0;
  1662. /* Creator-Owner SID: */
  1663. OK = AllocateAndInitializeSid( &CreatorSidAuthority, 1,
  1664. SECURITY_CREATOR_OWNER_RID,
  1665. 0, 0, 0, 0, 0, 0, 0,
  1666. &CreatorOwnerSid );
  1667. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  1668. if ( !OK ) {
  1669. goto CleanUp;
  1670. }
  1671. /* World SID */
  1672. OK = AllocateAndInitializeSid( &WorldSidAuthority, 1,
  1673. SECURITY_WORLD_RID,
  1674. 0, 0, 0, 0, 0, 0, 0,
  1675. &WorldSid );
  1676. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  1677. if ( !OK ) {
  1678. goto CleanUp;
  1679. }
  1680. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  1681. AceSid[AceCount] = WorldSid;
  1682. AceMask[AceCount] = GENERIC_READ | GENERIC_EXECUTE;
  1683. InheritFlags[AceCount] = 0;
  1684. AceCount++;
  1685. /* Admins alias SID */
  1686. OK = AllocateAndInitializeSid( &NtAuthority, 2,
  1687. SECURITY_BUILTIN_DOMAIN_RID,
  1688. DOMAIN_ALIAS_RID_ADMINS,
  1689. 0, 0, 0, 0, 0, 0,
  1690. &AdminsAliasSid );
  1691. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  1692. if ( !OK ) {
  1693. goto CleanUp;
  1694. }
  1695. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  1696. AceSid[AceCount] = AdminsAliasSid;
  1697. AceMask[AceCount] = GENERIC_ALL;
  1698. InheritFlags[AceCount] = 0;
  1699. AceCount++;
  1700. OK = RtlGetNtProductType( &NtProductType );
  1701. DBGCHK( !OK, ( "Couldn't get product type" ) );
  1702. if (NtProductType == NtProductLanManNt) {
  1703. /* Print Ops alias SID */
  1704. OK = AllocateAndInitializeSid( &NtAuthority, 2,
  1705. SECURITY_BUILTIN_DOMAIN_RID,
  1706. DOMAIN_ALIAS_RID_PRINT_OPS,
  1707. 0, 0, 0, 0, 0, 0,
  1708. &PrintOpsAliasSid );
  1709. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  1710. if ( !OK ) {
  1711. goto CleanUp;
  1712. }
  1713. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  1714. AceSid[AceCount] = PrintOpsAliasSid;
  1715. AceMask[AceCount] = GENERIC_ALL;
  1716. InheritFlags[AceCount] = 0;
  1717. AceCount++;
  1718. /* System Ops alias SID */
  1719. OK = AllocateAndInitializeSid( &NtAuthority, 2,
  1720. SECURITY_BUILTIN_DOMAIN_RID,
  1721. DOMAIN_ALIAS_RID_SYSTEM_OPS,
  1722. 0, 0, 0, 0, 0, 0,
  1723. &SystemOpsAliasSid );
  1724. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  1725. if ( !OK ) {
  1726. goto CleanUp;
  1727. }
  1728. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  1729. AceSid[AceCount] = SystemOpsAliasSid;
  1730. AceMask[AceCount] = GENERIC_ALL;
  1731. InheritFlags[AceCount] = 0;
  1732. AceCount++;
  1733. } else {
  1734. //
  1735. // LanManNT product
  1736. //
  1737. OK = AllocateAndInitializeSid( &NtAuthority, 2,
  1738. SECURITY_BUILTIN_DOMAIN_RID,
  1739. DOMAIN_ALIAS_RID_POWER_USERS,
  1740. 0, 0, 0, 0, 0, 0,
  1741. &PowerUsersAliasSid );
  1742. DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) );
  1743. if ( !OK ) {
  1744. goto CleanUp;
  1745. }
  1746. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  1747. AceSid[AceCount] = PowerUsersAliasSid;
  1748. AceMask[AceCount] = GENERIC_ALL;
  1749. InheritFlags[AceCount] = 0;
  1750. AceCount++;
  1751. }
  1752. DBGCHK( ( AceCount > MAX_ACE ), ( "ACE count exceeded" ) );
  1753. OK = BuildPrintObjectProtection( AceType,
  1754. AceCount,
  1755. AceSid,
  1756. AceMask,
  1757. InheritFlags,
  1758. AdminsAliasSid,
  1759. AdminsAliasSid,
  1760. &GenericMapping[ObjectType],
  1761. &pDriversShareSD );
  1762. CleanUp:
  1763. if (WorldSid) {
  1764. FreeSid( WorldSid );
  1765. }
  1766. if (AdminsAliasSid) {
  1767. FreeSid( AdminsAliasSid );
  1768. }
  1769. if (CreatorOwnerSid) {
  1770. FreeSid( CreatorOwnerSid );
  1771. }
  1772. if (PrintOpsAliasSid) {
  1773. FreeSid( PrintOpsAliasSid );
  1774. }
  1775. if (SystemOpsAliasSid) {
  1776. FreeSid( SystemOpsAliasSid );
  1777. }
  1778. if (PowerUsersAliasSid) {
  1779. FreeSid( PowerUsersAliasSid );
  1780. }
  1781. return pDriversShareSD;
  1782. }
  1783. #if DBG
  1784. VOID
  1785. DumpAcl(
  1786. IN PACL Acl
  1787. )
  1788. /*++
  1789. Routine Description:
  1790. This routine dumps via (NetpDbgPrint) an Acl for debug purposes. It is
  1791. specialized to dump standard aces.
  1792. Arguments:
  1793. Acl - Supplies the Acl to dump
  1794. Return Value:
  1795. None
  1796. --*/
  1797. {
  1798. DWORD i;
  1799. PSTANDARD_ACE Ace;
  1800. if( MODULE_DEBUG & DBG_SECURITY ) {
  1801. DBGMSG( DBG_SECURITY, ( " DumpAcl @%08lx\n", Acl ));
  1802. //
  1803. // Check if the Acl is null
  1804. //
  1805. if (Acl == NULL) {
  1806. return;
  1807. }
  1808. //
  1809. // Dump the Acl header
  1810. //
  1811. DBGMSG( DBG_SECURITY,
  1812. ( " Revision: %02x, Size: %04x, AceCount: %04x\n",
  1813. Acl->AclRevision, Acl->AclSize, Acl->AceCount ));
  1814. //
  1815. // Now for each Ace we want do dump it
  1816. //
  1817. for (i = 0, Ace = FirstAce(Acl);
  1818. i < Acl->AceCount;
  1819. i++, Ace = NextAce(Ace) ) {
  1820. //
  1821. // print out the ace header
  1822. //
  1823. DBGMSG( DBG_SECURITY, ( " AceHeader: %08lx\n", *(PDWORD)Ace ));
  1824. //
  1825. // special case on the standard ace types
  1826. //
  1827. if ((Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) ||
  1828. (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE) ||
  1829. (Ace->Header.AceType == SYSTEM_AUDIT_ACE_TYPE) ||
  1830. (Ace->Header.AceType == SYSTEM_ALARM_ACE_TYPE)) {
  1831. //
  1832. // The following array is indexed by ace types and must
  1833. // follow the allowed, denied, audit, alarm seqeuence
  1834. //
  1835. static LPSTR AceTypes[] = { "Access Allowed",
  1836. "Access Denied ",
  1837. "System Audit ",
  1838. "System Alarm "
  1839. };
  1840. DBGMSG( DBG_SECURITY,
  1841. ( " %s Access Mask: %08lx\n",
  1842. AceTypes[Ace->Header.AceType], Ace->Mask ));
  1843. } else {
  1844. DBGMSG( DBG_SECURITY, (" Unknown Ace Type\n" ));
  1845. }
  1846. DBGMSG( DBG_SECURITY,
  1847. ( " AceSize = %d\n AceFlags = ", Ace->Header.AceSize ));
  1848. if (Ace->Header.AceFlags & OBJECT_INHERIT_ACE) {
  1849. DBGMSG( DBG_SECURITY, ( " OBJECT_INHERIT_ACE\n" ));
  1850. DBGMSG( DBG_SECURITY, ( " " ));
  1851. }
  1852. if (Ace->Header.AceFlags & CONTAINER_INHERIT_ACE) {
  1853. DBGMSG( DBG_SECURITY, ( " CONTAINER_INHERIT_ACE\n" ));
  1854. DBGMSG( DBG_SECURITY, ( " " ));
  1855. }
  1856. if (Ace->Header.AceFlags & NO_PROPAGATE_INHERIT_ACE) {
  1857. DBGMSG( DBG_SECURITY, ( " NO_PROPAGATE_INHERIT_ACE\n" ));
  1858. DBGMSG( DBG_SECURITY, ( " " ));
  1859. }
  1860. if (Ace->Header.AceFlags & INHERIT_ONLY_ACE) {
  1861. DBGMSG( DBG_SECURITY, ( " INHERIT_ONLY_ACE\n" ));
  1862. DBGMSG( DBG_SECURITY, ( " " ));
  1863. }
  1864. if (Ace->Header.AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG) {
  1865. DBGMSG( DBG_SECURITY, ( " SUCCESSFUL_ACCESS_ACE_FLAG\n" ));
  1866. DBGMSG( DBG_SECURITY, ( " " ));
  1867. }
  1868. if (Ace->Header.AceFlags & FAILED_ACCESS_ACE_FLAG) {
  1869. DBGMSG( DBG_SECURITY, ( " FAILED_ACCESS_ACE_FLAG\n" ));
  1870. DBGMSG( DBG_SECURITY, ( " " ));
  1871. }
  1872. DBGMSG( DBG_SECURITY, ( "\n" ));
  1873. }
  1874. }
  1875. }
  1876. #endif // if DBG
  1877. /*++
  1878. Routine Name
  1879. BuildJobOwnerSecurityDescriptor
  1880. Routine Description:
  1881. This routine builds a SD that will be passed as CreatorDescriptor argument to
  1882. CreatePrivateObjectSecurityEx. The SD on any new job will be created using
  1883. the SD returned by this function and will inherit from the SD from the print
  1884. queue.
  1885. BuildJobOwnerSecurityDescriptor --> SD Print queue SD
  1886. \ /
  1887. \ / Inheritance
  1888. \ /
  1889. Job SD
  1890. The SD created in this function will have as owner the user from the
  1891. hToken argument. (The user impersonated by the thread from where we have the
  1892. hToken). The ACL grants full access on the job to the local system.
  1893. The reason why we need this special SD is the following. If you remove the
  1894. creatorowner from the print queue SD and no user has manage docs permissions
  1895. CreatePrivateObjectSecurity won't find any inheritable ACEs in the parent.
  1896. Thus it grants full permissions to the owner and to the local system. This
  1897. leads to a random behavior where according to the UI the user should not be
  1898. able to manage his docs, but the SD on the job will grant manage docs rights.
  1899. We don't want that. We want the local system to have full privileges on the job
  1900. and the user who submitted the job should be granted permissions only if:
  1901. - the user has manage doc rights
  1902. - creator owner is present in the print queue SD
  1903. Arguments:
  1904. hToken - impersonation token of the user who creates a new job
  1905. ppSD - pointer to recieve SD
  1906. Return Value:
  1907. Win32 error code
  1908. --*/
  1909. BOOL
  1910. BuildJobOwnerSecurityDescriptor(
  1911. IN HANDLE hToken,
  1912. OUT PSECURITY_DESCRIPTOR *ppSD
  1913. )
  1914. {
  1915. DWORD Error = ERROR_INVALID_PARAMETER;
  1916. if (hToken && ppSD)
  1917. {
  1918. PVOID pUserInfo = NULL;
  1919. DWORD cbUserInfo = 0;
  1920. //
  1921. // Get the owner from the thread token
  1922. //
  1923. Error = GetTokenInformation(hToken,
  1924. TokenUser,
  1925. NULL,
  1926. 0,
  1927. &cbUserInfo) ? ERROR_SUCCESS : GetLastError();
  1928. //
  1929. // Allocate buffer and try getting the owner again
  1930. //
  1931. if (Error == ERROR_INSUFFICIENT_BUFFER)
  1932. {
  1933. if (pUserInfo = AllocSplMem(cbUserInfo))
  1934. {
  1935. Error = GetTokenInformation(hToken,
  1936. TokenUser,
  1937. pUserInfo,
  1938. cbUserInfo,
  1939. &cbUserInfo) ? ERROR_SUCCESS : GetLastError();
  1940. }
  1941. else
  1942. {
  1943. Error = GetLastError();
  1944. }
  1945. }
  1946. //
  1947. // Build the SD. We grant read control to the owner of the job
  1948. //
  1949. if (Error == ERROR_SUCCESS)
  1950. {
  1951. DWORD ObjectType = SPOOLER_OBJECT_DOCUMENT;
  1952. PSID AceSid[2];
  1953. ACCESS_MASK AceMask[2];
  1954. BYTE InheritFlags[2];
  1955. UCHAR AceType[2];
  1956. DWORD AceCount = 0;
  1957. PSID pUserSid;
  1958. pUserSid = ((((TOKEN_USER *)pUserInfo)->User)).Sid;
  1959. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  1960. AceSid[AceCount] = ((((TOKEN_USER *)pUserInfo)->User)).Sid;
  1961. AceMask[AceCount] = JOB_READ;
  1962. InheritFlags[AceCount] = 0;
  1963. AceCount++;
  1964. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  1965. AceSid[AceCount] = pLocalSystemSid;
  1966. AceMask[AceCount] = JOB_ALL_ACCESS;
  1967. InheritFlags[AceCount] = 0;
  1968. AceCount++;
  1969. Error = BuildPrintObjectProtection(AceType,
  1970. AceCount,
  1971. AceSid,
  1972. AceMask,
  1973. InheritFlags,
  1974. pUserSid,
  1975. NULL,
  1976. &GenericMapping[ObjectType],
  1977. ppSD) ? ERROR_SUCCESS : GetLastError();
  1978. }
  1979. FreeSplMem(pUserInfo);
  1980. }
  1981. SetLastError(Error);
  1982. return Error == ERROR_SUCCESS;
  1983. }
  1984. /*++
  1985. Routine Name
  1986. DestroyJobOwnerSecurityDescriptor
  1987. Routine Description:
  1988. This routine frees a SD allocated by CreatejobOwnerSecurityDescriptor
  1989. Arguments:
  1990. pSD - pointer to SD
  1991. Return Value:
  1992. None
  1993. --*/
  1994. VOID
  1995. DestroyJobOwnerSecurityDescriptor(
  1996. IN PSECURITY_DESCRIPTOR pSD
  1997. )
  1998. {
  1999. if (pSD)
  2000. {
  2001. LocalFree(pSD);
  2002. }
  2003. }
  2004. /*++
  2005. Routine Name
  2006. InitializeSecurityStructures
  2007. Routine Description:
  2008. This routine initializes security structures.
  2009. Arguments:
  2010. None
  2011. Return Value:
  2012. TRUE - function succeeded
  2013. FALSE - function failed, GetLastError() returns the reason
  2014. --*/
  2015. BOOL
  2016. InitializeSecurityStructures(
  2017. VOID
  2018. )
  2019. {
  2020. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  2021. return !!CreateServerSecurityDescriptor() &&
  2022. LookupPrivilegeValue(NULL,
  2023. SE_LOAD_DRIVER_NAME,
  2024. &gLoadDriverPrivilegeLuid) &&
  2025. AllocateAndInitializeSid(&NtAuthority,
  2026. 1,
  2027. SECURITY_LOCAL_SYSTEM_RID,
  2028. 0, 0, 0, 0, 0, 0, 0,
  2029. &pLocalSystemSid) &&
  2030. AllocateAndInitializeSid(&NtAuthority,
  2031. 1,
  2032. SECURITY_NETWORK_RID,
  2033. 0, 0, 0, 0, 0, 0, 0,
  2034. &pNetworkLogonSid) &&
  2035. AllocateAndInitializeSid(&NtAuthority,
  2036. 2,
  2037. SECURITY_BUILTIN_DOMAIN_RID,
  2038. DOMAIN_ALIAS_RID_GUESTS,
  2039. 0, 0, 0, 0, 0, 0,
  2040. &pGuestsSid);
  2041. }
  2042. /*++
  2043. Routine Name
  2044. PrincipalIsRemoteGuest
  2045. Routine Description:
  2046. This routine checks whether remote guest is present in a token.
  2047. Remote guest = network + guest
  2048. Arguments:
  2049. hToken - handle to token, NULL is ok (see CheckTokenMemberShip)
  2050. pbRemoteGuest - pointer to receive BOOL. true means remote guest
  2051. Return Value:
  2052. ERROR_SUCCESS - pbRemoteGuest is reliable
  2053. other win32 error code, do not use pbRemoteGuest
  2054. --*/
  2055. DWORD
  2056. PrincipalIsRemoteGuest(
  2057. IN HANDLE hToken,
  2058. OUT BOOL *pbRemoteGuest
  2059. )
  2060. {
  2061. DWORD Error = ERROR_INVALID_PARAMETER;
  2062. if (pbRemoteGuest)
  2063. {
  2064. BOOL bNetwork = FALSE;
  2065. BOOL bGuests = FALSE;
  2066. if (CheckTokenMembership(hToken, pNetworkLogonSid, &bNetwork) &&
  2067. CheckTokenMembership(hToken, pGuestsSid, &bGuests))
  2068. {
  2069. *pbRemoteGuest = bNetwork && bGuests;
  2070. Error = ERROR_SUCCESS;
  2071. }
  2072. else
  2073. {
  2074. *pbRemoteGuest = FALSE;
  2075. Error = GetLastError();
  2076. }
  2077. }
  2078. return Error;
  2079. }
  2080. /*++
  2081. Routine Name
  2082. CheckPrivilegePresent
  2083. Routine Description:
  2084. This routine checks if a certain privilege is present in a token
  2085. Arguments:
  2086. hToken - thread or process token
  2087. pLuid - pointer to luid for the privilege to be searched for
  2088. pbPresent - will be set to true is the privilege is present in the token
  2089. pAttributes - will be set to the attributes of the privilege. It is a mask
  2090. indicating if the privilege is disabled, enabled, enabled by
  2091. default.
  2092. Return Value:
  2093. ERROR_SUCCESS - the function executed successfully and the caller can use
  2094. pbPresent and pAttributes
  2095. other Win32 error
  2096. --*/
  2097. DWORD
  2098. CheckPrivilegePresent(
  2099. IN HANDLE hToken,
  2100. IN PLUID pLuid,
  2101. IN LPBOOL pbPresent,
  2102. IN LPDWORD pAttributes OPTIONAL
  2103. )
  2104. {
  2105. DWORD Error = ERROR_INVALID_PARAMETER;
  2106. PVOID pPrivInfo = NULL;
  2107. DWORD cbPrivInfo = kGuessTokenPrivileges;
  2108. if (pLuid && pbPresent)
  2109. {
  2110. *pbPresent = FALSE;
  2111. pPrivInfo = AllocSplMem(cbPrivInfo);
  2112. Error = pPrivInfo ? ERROR_SUCCESS : GetLastError();
  2113. if (Error == ERROR_SUCCESS)
  2114. {
  2115. Error = GetTokenInformation(hToken,
  2116. TokenPrivileges,
  2117. pPrivInfo,
  2118. cbPrivInfo,
  2119. &cbPrivInfo) ? ERROR_SUCCESS : GetLastError();
  2120. }
  2121. //
  2122. // Reallocate buffer and try getting the privileges
  2123. //
  2124. if (Error == ERROR_INSUFFICIENT_BUFFER)
  2125. {
  2126. FreeSplMem(pPrivInfo);
  2127. pPrivInfo = AllocSplMem(cbPrivInfo);
  2128. Error = pPrivInfo ? ERROR_SUCCESS : GetLastError();
  2129. if (Error == ERROR_SUCCESS)
  2130. {
  2131. Error = GetTokenInformation(hToken,
  2132. TokenPrivileges,
  2133. pPrivInfo,
  2134. cbPrivInfo,
  2135. &cbPrivInfo) ? ERROR_SUCCESS : GetLastError();
  2136. }
  2137. }
  2138. if (Error == ERROR_SUCCESS)
  2139. {
  2140. TOKEN_PRIVILEGES *pTokenPrivileges = (TOKEN_PRIVILEGES *)pPrivInfo;
  2141. DWORD uCount;
  2142. //
  2143. // Search the privilege in the list of privileges present in the token
  2144. //
  2145. for (uCount = 0; uCount < pTokenPrivileges->PrivilegeCount; uCount++)
  2146. {
  2147. if (pTokenPrivileges->Privileges[uCount].Luid.HighPart == pLuid->HighPart &&
  2148. pTokenPrivileges->Privileges[uCount].Luid.LowPart == pLuid->LowPart)
  2149. {
  2150. //
  2151. // We found the privilege
  2152. //
  2153. *pbPresent = TRUE;
  2154. if (pAttributes)
  2155. {
  2156. *pAttributes = pTokenPrivileges->Privileges[uCount].Attributes;
  2157. }
  2158. break;
  2159. }
  2160. }
  2161. }
  2162. FreeSplMem(pPrivInfo);
  2163. }
  2164. return Error;
  2165. }