Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1340 lines
31 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2001
  5. //
  6. // File: razacl.c
  7. //
  8. // Contents:
  9. //
  10. // History: 4/16/2001 richardw Created
  11. //----------------------------------------------------------------------------
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <sddl.h>
  17. #include <lm.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. UNICODE_STRING SddlFile ;
  22. UNICODE_STRING SourceDir ;
  23. UNICODE_STRING RootDir ;
  24. UNICODE_STRING ExtraDirs[] ;
  25. BOOL Background ;
  26. BOOL DoShares ;
  27. BOOL CreateSddl ;
  28. BOOL Force ;
  29. DWORD DebugFlag ;
  30. BOOL AddSelf ;
  31. BOOL DoSacl ;
  32. SECURITY_INFORMATION SecurityInfo ;
  33. typedef DWORD
  34. (NTAPI FS_WALK_CALLBACK)(
  35. PVOID Parameter,
  36. PWSTR File
  37. );
  38. typedef struct _FS_ENGINE_STATS {
  39. ULONG Files ;
  40. ULONG Directories ;
  41. ULONG EngineErrors ;
  42. ULONG CallbackErrors ;
  43. } FS_ENGINE_STATS, * PFS_ENGINE_STATS ;
  44. typedef FS_WALK_CALLBACK * PFS_WALK_CALLBACK ;
  45. typedef struct _FS_WALK_CONTROL {
  46. PVOID Parameter ;
  47. PFS_WALK_CALLBACK Callback ;
  48. ULONG Options ;
  49. PFS_ENGINE_STATS Stats ;
  50. HANDLE Search ;
  51. WCHAR CurrentPath[ MAX_PATH ];
  52. WCHAR SearchPath[ MAX_PATH ];
  53. WCHAR FilePath[ MAX_PATH ];
  54. } FS_WALK_CONTROL, * PFS_WALK_CONTROL ;
  55. typedef struct _PARAM {
  56. LPSTR Argument ;
  57. ULONG Flags ;
  58. PVOID Value ;
  59. PVOID Default ;
  60. } PARAM, * PPARAM ;
  61. #define PARAM_TYPE_STRING 0x00000001
  62. #define PARAM_TYPE_ULONG 0x00000002
  63. #define PARAM_TYPE_BOOL 0x00000003
  64. #define PARAM_TYPE_MASK 0x0000FFFF
  65. #define PARAM_TYPE_SINGLE 0x00010000 // Single value
  66. #define PARAM_TYPE_COMMA 0x00020000 // Comma separated multi value
  67. #define PARAM_TYPE_OPTIONAL 0x00040000 // Optional value
  68. #define PARAM_TYPE_REQUIRED 0x00080000 // Required argument
  69. #define PARAM_TYPE_HIDDEN 0x00100000 // Not dumped during help
  70. #define PARAM_TYPE_MULTIPLE 0x00200000 // Can be specified multiple times
  71. #define PARAM_TYPE_FOUND 0x10000000 // Found during arg scan
  72. PARAM Parameters[] = {
  73. { "background", PARAM_TYPE_BOOL, &Background, (PVOID) FALSE },
  74. { "sddlfile", PARAM_TYPE_STRING | PARAM_TYPE_REQUIRED, &SddlFile, (PVOID) NULL },
  75. { "shares", PARAM_TYPE_BOOL | PARAM_TYPE_SINGLE | PARAM_TYPE_OPTIONAL, &DoShares, (PVOID) NULL },
  76. { "source", PARAM_TYPE_STRING | PARAM_TYPE_SINGLE, &SourceDir, (PVOID) NULL },
  77. { "createsddl", PARAM_TYPE_BOOL | PARAM_TYPE_SINGLE | PARAM_TYPE_OPTIONAL, &CreateSddl, (PVOID) NULL },
  78. { "root", PARAM_TYPE_STRING | PARAM_TYPE_REQUIRED, &RootDir, (PVOID) NULL },
  79. { "force", PARAM_TYPE_BOOL | PARAM_TYPE_SINGLE | PARAM_TYPE_OPTIONAL, &Force, (PVOID) NULL },
  80. { "debug", PARAM_TYPE_ULONG | PARAM_TYPE_HIDDEN, &DebugFlag, (PVOID) NULL },
  81. { "addself", PARAM_TYPE_BOOL | PARAM_TYPE_SINGLE | PARAM_TYPE_OPTIONAL, &AddSelf, (PVOID) TRUE },
  82. { "sacl", PARAM_TYPE_BOOL | PARAM_TYPE_SINGLE | PARAM_TYPE_OPTIONAL, &DoSacl, (PVOID) NULL }
  83. };
  84. #define ARGSET ( (sizeof ( Parameters ) / sizeof( PARAM ) ) )
  85. VOID
  86. DECLSPEC_NORETURN
  87. Usage(
  88. char * Me
  89. )
  90. {
  91. int i ;
  92. printf("%s - usage\n", Me);
  93. for ( i = 0 ; i < ARGSET ; i++ )
  94. {
  95. if ( ( Parameters[ i ].Flags & PARAM_TYPE_HIDDEN ) == 0 )
  96. {
  97. printf("\t/%s%s\n", Parameters[i].Argument,
  98. Parameters[ i ].Flags & PARAM_TYPE_SINGLE ? "" : ":value" );
  99. }
  100. }
  101. exit(1);
  102. }
  103. VOID
  104. FatalError(
  105. PWSTR Message,
  106. DWORD Error,
  107. PWSTR Object
  108. )
  109. {
  110. if ( Object )
  111. {
  112. fprintf( stderr, "Fatal error %d while working on object %ws\n",
  113. Error, Object );
  114. fputws( Message, stderr );
  115. fputws( L"\n", stderr );
  116. }
  117. else
  118. {
  119. fprintf( stderr, "Fatal error %d, %s\n", Error, Message );
  120. }
  121. exit( Error );
  122. }
  123. VOID
  124. DoParam(
  125. int argc,
  126. char * argv[]
  127. )
  128. {
  129. int i ;
  130. int j ;
  131. PSTR Arg ;
  132. PSTR Colon;
  133. PSTR Format ;
  134. BOOL Bail = FALSE ;
  135. //
  136. // Initialize Defaults:
  137. //
  138. for ( j = 0 ; j < ARGSET ; j++ )
  139. {
  140. switch ( Parameters[ j ].Flags & PARAM_TYPE_MASK )
  141. {
  142. case PARAM_TYPE_STRING:
  143. if ( Parameters[ j ].Default )
  144. {
  145. RtlInitUnicodeString( (PUNICODE_STRING) Parameters[ j ].Value,
  146. (LPWSTR) Parameters[ j ].Default );
  147. }
  148. else
  149. {
  150. ZeroMemory( Parameters[ j ].Value, sizeof( UNICODE_STRING ) );
  151. }
  152. break;
  153. case PARAM_TYPE_ULONG:
  154. * ((PULONG) Parameters[ j ].Value) = (ULONG) ((ULONG_PTR) Parameters[ j ].Default );
  155. break;
  156. case PARAM_TYPE_BOOL:
  157. * ((PBOOL) Parameters[ j ].Value) = (BOOL) ((ULONG_PTR) Parameters[ j ].Default );
  158. break;
  159. default:
  160. break;
  161. }
  162. }
  163. for ( i = 1 ; i < argc ; i++ )
  164. {
  165. Arg=argv[i];
  166. if ( (*Arg == '/') ||
  167. (*Arg == '-') )
  168. {
  169. Arg++ ;
  170. Colon = strchr( Arg, ':' );
  171. if ( Colon )
  172. {
  173. *Colon = '\0';
  174. }
  175. //
  176. // Scan through the possible arguments
  177. //
  178. for ( j = 0 ; j < ARGSET ; j++ )
  179. {
  180. if ( _stricmp( Arg, Parameters[ j ].Argument ) == 0 )
  181. {
  182. //
  183. // Found a parameter that matched. Now, check the supplied type:
  184. //
  185. if ( ( Parameters[ j ].Flags & PARAM_TYPE_FOUND ) &&
  186. ! ( Parameters[ j ].Flags & PARAM_TYPE_MULTIPLE ) )
  187. {
  188. printf("%s can be specified only once\n", Arg );
  189. Usage( argv[0] );
  190. }
  191. if ( Colon )
  192. {
  193. *Colon++ = ':' ;
  194. }
  195. if ( ( (Parameters[ j ].Flags & PARAM_TYPE_OPTIONAL) == 0 ) &&
  196. ( ( Colon == NULL ) || ( *Colon == '\0' ) ) )
  197. {
  198. printf("%s needs a value with it\n", Arg );
  199. Usage( argv[0] );
  200. }
  201. if ( ( Colon != NULL ) &&
  202. ( Parameters[ j ].Flags & PARAM_TYPE_SINGLE ) )
  203. {
  204. printf("%s takes no value\n", Arg );
  205. Usage( argv[0] );
  206. }
  207. switch ( Parameters[ j ].Flags & PARAM_TYPE_MASK )
  208. {
  209. case PARAM_TYPE_STRING:
  210. if ( !RtlCreateUnicodeStringFromAsciiz(
  211. (PUNICODE_STRING) Parameters[ j ].Value,
  212. Colon ) )
  213. {
  214. printf("out of memory\n");
  215. Usage( argv[0] );
  216. }
  217. break;
  218. case PARAM_TYPE_ULONG:
  219. if ( !Colon )
  220. {
  221. *((PULONG) Parameters[ j ].Value) = 0 ;
  222. }
  223. else
  224. {
  225. Format = "%ul" ;
  226. if ( *Colon == '0' )
  227. {
  228. //
  229. // Possible different base.
  230. //
  231. if ( *(Colon + 1 ) )
  232. {
  233. switch ( *(Colon + 1) )
  234. {
  235. case 'x':
  236. Format = "%x" ;
  237. break;
  238. case 'X':
  239. Format = "%X" ;
  240. break;
  241. default:
  242. Format = "%ul" ;
  243. break;
  244. }
  245. }
  246. }
  247. sscanf( Colon, Format, Parameters[ j ].Value );
  248. }
  249. break;
  250. case PARAM_TYPE_BOOL:
  251. if ( !Colon )
  252. {
  253. *((PBOOL) Parameters[ j ].Value ) = TRUE ;
  254. }
  255. else
  256. {
  257. if ( *Colon == '1' )
  258. {
  259. *((PBOOL) Parameters[ j ].Value ) = TRUE ;
  260. }
  261. else
  262. {
  263. *((PBOOL) Parameters[ j ].Value ) = FALSE ;
  264. }
  265. }
  266. break;
  267. default:
  268. Usage( argv[ 0 ] );
  269. }
  270. Parameters[ j ].Flags |= PARAM_TYPE_FOUND ;
  271. break; // break out of for loop
  272. }
  273. }
  274. if ( j == ARGSET )
  275. {
  276. printf("-%s unrecognized\n", Arg );
  277. Usage( argv[ 0 ] );
  278. }
  279. }
  280. else
  281. {
  282. printf("%s unexpected\n", Arg );
  283. Usage( argv[0] );
  284. }
  285. }
  286. //
  287. // Validate input:
  288. //
  289. Bail = FALSE ;
  290. for ( j = 0 ; j < ARGSET ; j++ )
  291. {
  292. if ( (Parameters[ j ].Flags & PARAM_TYPE_REQUIRED) )
  293. {
  294. if ( ! ( Parameters[ j ].Flags & PARAM_TYPE_FOUND ) )
  295. {
  296. printf(" /%s missing\n", Parameters[ j ].Argument );
  297. Bail = TRUE ;
  298. }
  299. }
  300. }
  301. if ( Bail )
  302. {
  303. Usage( argv[ 0 ] );
  304. }
  305. }
  306. BOOL
  307. CheckRootFileSystem(
  308. VOID
  309. )
  310. {
  311. WCHAR Volume[ 8 ];
  312. WCHAR Temp[ MAX_PATH ];
  313. DWORD Size ;
  314. DWORD FsFlags ;
  315. if ( RootDir.Buffer[ 1 ] == L':' )
  316. {
  317. Volume[ 0 ] = RootDir.Buffer[ 0 ];
  318. Volume[ 1 ] = RootDir.Buffer[ 1 ];
  319. }
  320. else
  321. {
  322. Size = MAX_PATH ;
  323. GetCurrentDirectory( MAX_PATH, Temp );
  324. Volume[ 0 ] = Temp[ 0 ];
  325. Volume[ 1 ] = Temp[ 1 ];
  326. }
  327. Volume[ 2 ] = L'\\';
  328. Volume[ 3 ] = L'\0';
  329. if ( GetVolumeInformation(
  330. Volume,
  331. NULL,
  332. 0,
  333. NULL,
  334. &Size,
  335. &FsFlags,
  336. Temp,
  337. MAX_PATH ) )
  338. {
  339. if ( FsFlags & FS_PERSISTENT_ACLS )
  340. {
  341. return TRUE ;
  342. }
  343. }
  344. return FALSE ;
  345. }
  346. PWSTR
  347. GetTargetOfReparse(
  348. PWSTR ReparsePoint
  349. )
  350. {
  351. HANDLE Handle ;
  352. NTSTATUS Status ;
  353. OBJECT_ATTRIBUTES ObjA ;
  354. UNICODE_STRING UnicodeName ;
  355. NTSTATUS IgnoreStatus ;
  356. IO_STATUS_BLOCK IoStatusBlock ;
  357. PWSTR Target = NULL ;
  358. FILE_DISPOSITION_INFORMATION Disposition;
  359. PREPARSE_DATA_BUFFER ReparseBufferHeader = NULL;
  360. PCHAR ReparseBuffer = NULL;
  361. ULONG ReparsePointTag = IO_REPARSE_TAG_RESERVED_ZERO;
  362. USHORT ReparseDataLength = 0;
  363. ULONG DesiredAccess ;
  364. ULONG CreateOptions ;
  365. IgnoreStatus = RtlDosPathNameToNtPathName_U(
  366. ReparsePoint,
  367. &UnicodeName,
  368. NULL,
  369. NULL
  370. );
  371. if ( !NT_SUCCESS( IgnoreStatus ) )
  372. {
  373. return NULL ;
  374. }
  375. InitializeObjectAttributes(
  376. &ObjA,
  377. &UnicodeName,
  378. OBJ_CASE_INSENSITIVE,
  379. NULL,
  380. NULL
  381. );
  382. DesiredAccess = FILE_READ_DATA | SYNCHRONIZE;
  383. CreateOptions = FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT;
  384. //
  385. // Open the reparse point for query.
  386. //
  387. Status = NtOpenFile(
  388. &Handle,
  389. DesiredAccess,
  390. &ObjA,
  391. &IoStatusBlock,
  392. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  393. CreateOptions
  394. );
  395. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeName.Buffer );
  396. if ( !NT_SUCCESS( Status ) )
  397. {
  398. return NULL ;
  399. }
  400. ReparseDataLength = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
  401. ReparseBuffer = RtlAllocateHeap(
  402. RtlProcessHeap(),
  403. HEAP_ZERO_MEMORY,
  404. ReparseDataLength
  405. );
  406. if (ReparseBuffer == NULL) {
  407. FatalError( L"No memory", ERROR_OUTOFMEMORY, ReparsePoint );
  408. }
  409. //
  410. // Now go and get the data.
  411. //
  412. Status = NtFsControlFile(
  413. Handle,
  414. NULL,
  415. NULL,
  416. NULL,
  417. &IoStatusBlock,
  418. FSCTL_GET_REPARSE_POINT, // no input buffer
  419. NULL, // input buffer length
  420. 0,
  421. (PVOID)ReparseBuffer,
  422. ReparseDataLength
  423. );
  424. //
  425. // Close the file and free the buffer.
  426. //
  427. NtClose( Handle );
  428. //
  429. // Display the buffer.
  430. //
  431. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)ReparseBuffer;
  432. if ((ReparseBufferHeader->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) ||
  433. (ReparseBufferHeader->ReparseTag == IO_REPARSE_TAG_SYMBOLIC_LINK)) {
  434. if ( DebugFlag )
  435. {
  436. UNICODE_STRING NtLinkValue ;
  437. NtLinkValue.Buffer = &ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer[ 0 ];
  438. NtLinkValue.Length = ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameLength;
  439. NtLinkValue.MaximumLength = NtLinkValue.Length ;
  440. printf("base path is %wZ\n", &NtLinkValue );
  441. }
  442. Target = LocalAlloc( LMEM_FIXED,
  443. (ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameLength + 1) * sizeof( WCHAR ) );
  444. if ( Target )
  445. {
  446. RtlCopyMemory(
  447. Target,
  448. &ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer[ ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof( WCHAR ) + 1 ],
  449. ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameLength
  450. );
  451. }
  452. }
  453. else {
  454. }
  455. //
  456. // Free the buffer.
  457. //
  458. RtlFreeHeap( RtlProcessHeap(), 0, ReparseBufferHeader );
  459. return Target ;
  460. }
  461. PSECURITY_DESCRIPTOR
  462. GetRootSecurity(
  463. VOID
  464. )
  465. {
  466. HANDLE hRoot ;
  467. NTSTATUS Status ;
  468. BOOLEAN WasEnabled ;
  469. PSECURITY_DESCRIPTOR psd ;
  470. ULONG Size ;
  471. SECURITY_INFORMATION si ;
  472. ACCESS_MASK access ;
  473. DWORD Returned ;
  474. si = DACL_SECURITY_INFORMATION ;
  475. access = READ_CONTROL ;
  476. if ( DoSacl )
  477. {
  478. Status = RtlAdjustPrivilege(
  479. SE_SECURITY_PRIVILEGE,
  480. TRUE,
  481. FALSE,
  482. &WasEnabled );
  483. if ( NT_SUCCESS( Status ) )
  484. {
  485. si |= SACL_SECURITY_INFORMATION ;
  486. access |= ACCESS_SYSTEM_SECURITY ;
  487. }
  488. }
  489. Size = 0 ;
  490. psd = NULL ;
  491. GetFileSecurity(
  492. RootDir.Buffer,
  493. si,
  494. NULL,
  495. 0,
  496. &Size );
  497. psd = LocalAlloc( LMEM_FIXED, Size );
  498. if ( !GetFileSecurity(
  499. RootDir.Buffer,
  500. si,
  501. psd,
  502. Size,
  503. &Size ) )
  504. {
  505. FatalError( L"Could not read security descriptor",
  506. GetLastError(),
  507. RootDir.Buffer );
  508. }
  509. return psd ;
  510. }
  511. DWORD
  512. WriteSddlFile(
  513. VOID
  514. )
  515. {
  516. PSECURITY_DESCRIPTOR psd ;
  517. ULONG Size ;
  518. LPSTR AnsiStringSD ;
  519. ULONG AnsiStringSDLen ;
  520. HANDLE hSddlFile ;
  521. CHAR Term[ 2 ] = { 0x0d, 0x0a };
  522. psd = GetRootSecurity();
  523. if ( !ConvertSecurityDescriptorToStringSecurityDescriptorA(
  524. psd,
  525. 1,
  526. DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
  527. &AnsiStringSD,
  528. &AnsiStringSDLen ) )
  529. {
  530. FatalError( L"Cannot convert security descriptor to string\n",
  531. GetLastError(),
  532. NULL );
  533. }
  534. hSddlFile = CreateFile(
  535. SddlFile.Buffer,
  536. GENERIC_WRITE,
  537. 0,
  538. NULL,
  539. CREATE_ALWAYS,
  540. FILE_ATTRIBUTE_NORMAL,
  541. NULL );
  542. if ( hSddlFile == INVALID_HANDLE_VALUE )
  543. {
  544. FatalError(
  545. L"Cannot write security descriptor to file",
  546. GetLastError(),
  547. SddlFile.Buffer );
  548. }
  549. WriteFile(
  550. hSddlFile,
  551. AnsiStringSD,
  552. AnsiStringSDLen,
  553. &Size,
  554. NULL );
  555. LocalFree( AnsiStringSD );
  556. WriteFile(
  557. hSddlFile,
  558. Term, sizeof(Term),
  559. &Size, NULL );
  560. CloseHandle( hSddlFile );
  561. return 0;
  562. }
  563. PSECURITY_DESCRIPTOR
  564. InsertMe(
  565. PSECURITY_DESCRIPTOR old,
  566. ACCESS_MASK AccessRequired
  567. )
  568. {
  569. DWORD Size ;
  570. PACL OldAcl ;
  571. PACL NewAcl ;
  572. BOOL Present ;
  573. BOOL Ignored ;
  574. ACL_SIZE_INFORMATION AclSize ;
  575. PSID Me = NULL ;
  576. HANDLE hToken ;
  577. UCHAR Scratch[ SECURITY_MAX_SID_SIZE + sizeof( TOKEN_USER ) ];
  578. PTOKEN_USER User ;
  579. PACCESS_ALLOWED_ACE NewAce ;
  580. PACCESS_ALLOWED_ACE OldAce ;
  581. PSECURITY_DESCRIPTOR psd ;
  582. if ( OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ) )
  583. {
  584. if ( GetTokenInformation( hToken, TokenUser, Scratch, sizeof( Scratch ), &Size ) )
  585. {
  586. User = (PTOKEN_USER) Scratch ;
  587. Me = User->User.Sid ;
  588. }
  589. CloseHandle( hToken );
  590. }
  591. if ( !Me )
  592. {
  593. return NULL ;
  594. }
  595. GetSecurityDescriptorDacl(old, &Present, &OldAcl, &Ignored );
  596. if ( !Present )
  597. {
  598. return NULL ;
  599. }
  600. GetAclInformation( OldAcl, &AclSize, sizeof( AclSize ), AclSizeInformation );
  601. NewAcl = LocalAlloc(LMEM_FIXED, AclSize.AclBytesInUse + (sizeof( ACCESS_ALLOWED_ACE ) + GetLengthSid( Me )));
  602. if ( !NewAcl )
  603. {
  604. return NULL ;
  605. }
  606. InitializeAcl( NewAcl, AclSize.AclBytesInUse + (sizeof( ACCESS_ALLOWED_ACE ) + GetLengthSid( Me ) ), ACL_REVISION );
  607. AddAccessAllowedAce( NewAcl, ACL_REVISION, AccessRequired, Me );
  608. FindFirstFreeAce( NewAcl, &NewAce );
  609. GetAce( OldAcl, 0, &OldAce );
  610. CopyMemory( NewAce, OldAce, AclSize.AclBytesInUse - sizeof( ACL ));
  611. NewAcl->AceCount += (USHORT) AclSize.AceCount ;
  612. psd = LocalAlloc(LMEM_FIXED, sizeof( SECURITY_DESCRIPTOR ) );
  613. if ( psd )
  614. {
  615. InitializeSecurityDescriptor( psd, SECURITY_DESCRIPTOR_REVISION );
  616. SetSecurityDescriptorDacl(psd, TRUE, NewAcl, FALSE );
  617. }
  618. return psd ;
  619. }
  620. //+---------------------------------------------------------------------------
  621. //
  622. // Function: ReadSecurityDescriptor
  623. //
  624. // Synopsis:
  625. //
  626. // Arguments: [SddlFileName] --
  627. //
  628. // Returns:
  629. //
  630. // Notes:
  631. //
  632. //----------------------------------------------------------------------------
  633. PSECURITY_DESCRIPTOR
  634. ReadSecurityDescriptor(
  635. PWSTR SddlFileName
  636. )
  637. {
  638. HANDLE hFile ;
  639. PSECURITY_DESCRIPTOR psd ;
  640. ULONG Size ;
  641. ULONG SizeRead ;
  642. PUCHAR Buffer ;
  643. PSECURITY_DESCRIPTOR psdNew ;
  644. hFile = CreateFileW(
  645. SddlFileName,
  646. GENERIC_READ,
  647. FILE_SHARE_READ | FILE_SHARE_DELETE,
  648. NULL,
  649. OPEN_EXISTING,
  650. FILE_ATTRIBUTE_NORMAL,
  651. NULL );
  652. if ( hFile == INVALID_HANDLE_VALUE )
  653. {
  654. FatalError(
  655. L"Unable to read ACL file",
  656. GetLastError(),
  657. SddlFile.Buffer );
  658. }
  659. Size = GetFileSize( hFile, NULL );
  660. if ( Size == (DWORD) -1 )
  661. {
  662. FatalError(
  663. L"ACL file corrupt, too large",
  664. 0,
  665. NULL );
  666. }
  667. Buffer = LocalAlloc( LMEM_FIXED, Size + 1 );
  668. if ( !Buffer )
  669. {
  670. FatalError(
  671. L"Out of memory",
  672. GetLastError(),
  673. NULL );
  674. }
  675. if ( !ReadFile( hFile, Buffer, Size, &SizeRead, NULL ) )
  676. {
  677. FatalError(
  678. L"Unable to read ACL file",
  679. GetLastError(),
  680. SddlFile.Buffer );
  681. }
  682. CloseHandle( hFile );
  683. Buffer[ Size ] = '\0';
  684. while ( ( Buffer[ Size - 1 ] == 0x0a ) ||
  685. ( Buffer[ Size - 1 ] == 0x0d ) ||
  686. ( Buffer[ Size - 1 ] == 0x1a ) )
  687. {
  688. Buffer[ Size - 1 ] = '\0' ;
  689. Size-- ;
  690. }
  691. if ( !ConvertStringSecurityDescriptorToSecurityDescriptorA(
  692. Buffer,
  693. 1,
  694. &psd,
  695. &Size ) )
  696. {
  697. FatalError(
  698. L"ACL file is corrupt",
  699. GetLastError(),
  700. SddlFile.Buffer );
  701. }
  702. LocalFree( Buffer );
  703. if ( AddSelf )
  704. {
  705. //
  706. // Need to merge in a sid for "me"
  707. //
  708. psdNew = InsertMe( psd, FILE_ALL_ACCESS );
  709. if ( psdNew )
  710. {
  711. LocalFree( psd );
  712. psd = psdNew ;
  713. }
  714. }
  715. return psd ;
  716. }
  717. BOOL
  718. WalkCallback(
  719. PVOID Parameter,
  720. PWSTR Path
  721. )
  722. {
  723. return SetFileSecurity(
  724. Path,
  725. SecurityInfo,
  726. Parameter );
  727. }
  728. BOOL
  729. WalkEngine(
  730. PFS_WALK_CONTROL Control
  731. )
  732. {
  733. PFS_WALK_CONTROL NewControl ;
  734. WIN32_FIND_DATA FindData ;
  735. PWSTR Scan;
  736. BOOL CallbackStatus ;
  737. DWORD Status ;
  738. DWORD FileTest ;
  739. DWORD Limit ;
  740. PSECURITY_DESCRIPTOR psd = NULL ;
  741. //
  742. // First, check for an override file:
  743. //
  744. if ( wcslen( Control->CurrentPath ) > MAX_PATH - 7 )
  745. {
  746. return FALSE ;
  747. }
  748. wcsncpy( Control->SearchPath, Control->CurrentPath, MAX_PATH );
  749. wcscat( Control->SearchPath, L"acl.txt" );
  750. FileTest = GetFileAttributes( Control->SearchPath );
  751. if ( FileTest != (DWORD) -1 )
  752. {
  753. //
  754. // File exists. Load it and use it for all files from here on down
  755. //
  756. psd = ReadSecurityDescriptor( Control->SearchPath );
  757. if ( psd )
  758. {
  759. Control->Parameter = psd ;
  760. }
  761. }
  762. wcscpy( Control->SearchPath, Control->CurrentPath );
  763. wcscat( Control->SearchPath, L"*.*" );
  764. Control->Search = FindFirstFile( Control->SearchPath, &FindData );
  765. if ( Control->Search )
  766. {
  767. wcscpy( Control->FilePath, Control->CurrentPath);
  768. Scan = &Control->FilePath[ wcslen( Control->FilePath ) ]; // one char past trailing backslash
  769. Limit = MAX_PATH - wcslen( Control->FilePath );
  770. do
  771. {
  772. if ( wcslen( FindData.cFileName ) > Limit )
  773. {
  774. Control->Stats->EngineErrors++ ;
  775. fprintf(stderr, "File '%ws' in directory '%ws' exceeds maximum length",
  776. FindData.cFileName, Control->CurrentPath );
  777. continue;
  778. }
  779. wcscpy( Scan, FindData.cFileName );
  780. if ( wcscmp( Scan,L".." ) == 0 )
  781. {
  782. //
  783. // always immediately skip the parent link
  784. //
  785. continue;
  786. }
  787. CallbackStatus = Control->Callback(
  788. Control->Parameter,
  789. Control->FilePath );
  790. if ( !CallbackStatus )
  791. {
  792. Control->Stats->CallbackErrors ++ ;
  793. }
  794. if ( wcscmp( Scan, L".") == 0 )
  795. {
  796. //
  797. // allow for processing the current directory,
  798. // but do not recurse...
  799. //
  800. continue;
  801. }
  802. if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  803. {
  804. //
  805. // Time to recurse (we do depth first, it's easier)
  806. //
  807. Control->Stats->Directories++ ;
  808. NewControl = LocalAlloc( LMEM_FIXED, sizeof( FS_WALK_CONTROL ) );
  809. if ( NewControl )
  810. {
  811. NewControl->Callback = Control->Callback ;
  812. NewControl->Parameter = Control->Parameter ;
  813. NewControl->Options = Control->Options ;
  814. NewControl->Stats = Control->Stats ;
  815. wcscpy(NewControl->CurrentPath, Control->FilePath );
  816. wcscat(NewControl->CurrentPath, L"\\");
  817. WalkEngine( NewControl );
  818. LocalFree( NewControl );
  819. }
  820. else
  821. {
  822. Control->Stats->EngineErrors ++ ;
  823. }
  824. }
  825. else
  826. {
  827. Control->Stats->Files++ ;
  828. }
  829. } while ( FindNextFile( Control->Search, &FindData ) );
  830. FindClose( Control->Search );
  831. }
  832. else
  833. {
  834. Control->Stats->EngineErrors++ ;
  835. }
  836. if ( psd )
  837. {
  838. LocalFree( psd );
  839. }
  840. return TRUE ;
  841. }
  842. BOOL
  843. WalkTree(
  844. PWSTR StartPath,
  845. ULONG Options,
  846. PFS_WALK_CALLBACK Callback,
  847. PVOID Parameter
  848. )
  849. {
  850. PFS_WALK_CONTROL Control ;
  851. FS_ENGINE_STATS Stats ;
  852. PWSTR Scan;
  853. Control = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof( FS_WALK_CONTROL ) );
  854. if ( !Control )
  855. {
  856. return FALSE ;
  857. }
  858. ZeroMemory( &Stats, sizeof( Stats ) );
  859. Control->Callback = Callback ;
  860. Control->Parameter = Parameter ;
  861. Control->Options = 0 ;
  862. Control->Stats = &Stats ;
  863. wcscpy( Control->CurrentPath, StartPath );
  864. Scan = &Control->CurrentPath[ wcslen( Control->CurrentPath ) - 1 ];
  865. if ( *Scan != L'\\' )
  866. {
  867. Scan++ ;
  868. *Scan = L'\\';
  869. }
  870. if ( !Callback( Parameter, StartPath ) )
  871. {
  872. Stats.CallbackErrors++ ;
  873. }
  874. Stats.Directories = 1;
  875. WalkEngine(Control);
  876. if ( DebugFlag )
  877. {
  878. printf("Directories \t%d\n", Stats.Directories );
  879. printf("Files \t%d\n", Stats.Files );
  880. printf("EngineErrors\t%d\n", Stats.EngineErrors );
  881. printf("CallbackErrors\t%d\n", Stats.CallbackErrors );
  882. }
  883. return TRUE ;
  884. }
  885. BOOL
  886. UpdateAcls(
  887. VOID
  888. )
  889. {
  890. PSECURITY_DESCRIPTOR psd ;
  891. NTSTATUS Status ;
  892. SECURITY_INFORMATION si ;
  893. SECURITY_DESCRIPTOR_CONTROL control ;
  894. ULONG ignored;
  895. BOOLEAN WasEnabled ;
  896. psd = ReadSecurityDescriptor( SddlFile.Buffer );
  897. if ( !psd )
  898. {
  899. return FALSE ;
  900. }
  901. RtlGetControlSecurityDescriptor(psd,&control,&ignored);
  902. si = 0 ;
  903. if ( control & SE_DACL_PRESENT )
  904. {
  905. si |= DACL_SECURITY_INFORMATION ;
  906. }
  907. if ( control & SE_SACL_PRESENT )
  908. {
  909. Status = RtlAdjustPrivilege(
  910. SE_SECURITY_PRIVILEGE,
  911. TRUE,
  912. FALSE,
  913. &WasEnabled );
  914. if ( NT_SUCCESS( Status ) )
  915. {
  916. si |= SACL_SECURITY_INFORMATION ;
  917. }
  918. }
  919. SecurityInfo = si ;
  920. printf("Updating ACLs from %ws for tree %ws\n",
  921. SddlFile.Buffer, RootDir.Buffer );
  922. WalkTree(RootDir.Buffer, 0, WalkCallback, psd );
  923. return TRUE ;
  924. }
  925. BOOL
  926. TestAcl(
  927. VOID
  928. )
  929. {
  930. PSECURITY_DESCRIPTOR Current ;
  931. PSECURITY_DESCRIPTOR Stored ;
  932. PACL CurrentAcl ;
  933. PACL StoredAcl ;
  934. ULONG CurrentLength ;
  935. ULONG StoredLength ;
  936. BOOL Match = FALSE ;
  937. NTSTATUS Status ;
  938. BOOLEAN Present ;
  939. BOOLEAN Defaulted ;
  940. ACL_SIZE_INFORMATION AclSize ;
  941. Stored = ReadSecurityDescriptor( SddlFile.Buffer );
  942. Status = RtlGetDaclSecurityDescriptor(Stored,&Present,&StoredAcl,&Defaulted);
  943. if ( !NT_SUCCESS( Status ) )
  944. {
  945. return FALSE ;
  946. }
  947. Current = GetRootSecurity();
  948. Status = RtlGetDaclSecurityDescriptor(Current,&Present,&CurrentAcl,&Defaulted);
  949. if ( !NT_SUCCESS( Status ) || (CurrentAcl == NULL) )
  950. {
  951. return FALSE ;
  952. }
  953. Status = RtlQueryInformationAcl(StoredAcl,&AclSize,sizeof(AclSize),AclSizeInformation);
  954. if ( !NT_SUCCESS( Status ) )
  955. {
  956. return FALSE ;
  957. }
  958. StoredLength = AclSize.AclBytesInUse ;
  959. Status = RtlQueryInformationAcl( CurrentAcl,&AclSize,sizeof(AclSize), AclSizeInformation );
  960. if ( !NT_SUCCESS( Status ) )
  961. {
  962. return FALSE ;
  963. }
  964. CurrentLength = AclSize.AclBytesInUse;
  965. if ( CurrentLength == StoredLength )
  966. {
  967. Match = RtlEqualMemory(
  968. CurrentAcl,
  969. StoredAcl,
  970. CurrentLength );
  971. }
  972. LocalFree( Stored );
  973. LocalFree( Current );
  974. return Match ;
  975. }
  976. int __cdecl main (int argc, char *argv[])
  977. {
  978. DoParam( argc, argv );
  979. if ( DebugFlag )
  980. {
  981. printf("SDDL File \t%ws\n", SddlFile.Buffer );
  982. printf("Root Dir \t%ws\n", RootDir.Buffer );
  983. }
  984. if ( CreateSddl )
  985. {
  986. WriteSddlFile();
  987. return 0 ;
  988. }
  989. if ( !CheckRootFileSystem() )
  990. {
  991. printf("Volume does not support ACLs\n" );
  992. return 0 ;
  993. }
  994. if ( !Force )
  995. {
  996. if ( TestAcl() )
  997. {
  998. if ( DebugFlag )
  999. {
  1000. printf("ACL is up-to-date\n" );
  1001. }
  1002. return 0 ;
  1003. }
  1004. }
  1005. UpdateAcls();
  1006. }