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.

1976 lines
46 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. obdir.c
  5. Abstract:
  6. Utility to obtain a directory of Object Manager Directories for NT.
  7. Author:
  8. Darryl E. Havens (DarrylH) 9-Nov-1990
  9. Revision History:
  10. --*/
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <windows.h>
  18. #include <malloc.h>
  19. #include <ntlsa.h>
  20. #define BUFFERSIZE 1024
  21. #define Error(N,S) { \
  22. printf(#S); \
  23. printf(" Error %08lX\n", S); \
  24. }
  25. typedef struct _TYPEINFO {
  26. PWSTR pszName;
  27. char * * AccessRights;
  28. DWORD NumberRights;
  29. } TYPEINFO, * PTYPEINFO;
  30. ////////////////////////////////////////////////////////
  31. // //
  32. // Internal Prototypes //
  33. // //
  34. ////////////////////////////////////////////////////////
  35. BOOLEAN
  36. EnableAllPrivileges(
  37. VOID
  38. );
  39. VOID
  40. QueryDirectory(
  41. IN PSTRING DirectoryName
  42. );
  43. NTSTATUS
  44. OpenObject(
  45. IN HANDLE Root,
  46. IN PWCHAR Type,
  47. IN PWCHAR Name,
  48. IN ACCESS_MASK DesiredAccess,
  49. OUT PHANDLE Object
  50. );
  51. VOID
  52. OpenAndDisplaySacl(
  53. IN HANDLE Root,
  54. IN PWCHAR Type,
  55. IN PWCHAR Name
  56. );
  57. VOID
  58. QueryAndDisplaySacl(
  59. IN HANDLE Object,
  60. IN PWSTR Type
  61. );
  62. NTSTATUS
  63. DisplaySacl(
  64. PSECURITY_DESCRIPTOR SD,
  65. IN PWSTR Type
  66. );
  67. VOID
  68. OpenAndDisplayDacl(
  69. IN HANDLE Root,
  70. IN PWCHAR Type,
  71. IN PWCHAR Name
  72. );
  73. VOID
  74. QueryAndDisplayDacl(
  75. IN HANDLE Object,
  76. IN PWSTR Type
  77. );
  78. NTSTATUS
  79. DisplayDacl(
  80. PSECURITY_DESCRIPTOR SD,
  81. IN PWSTR Type
  82. );
  83. VOID
  84. DumpAce(
  85. PACE_HEADER Ace,
  86. BOOLEAN AclIsDacl,
  87. PTYPEINFO TypeInfo
  88. );
  89. VOID
  90. DumpStandardAceInfo(
  91. PACE_HEADER Ace,
  92. BOOLEAN AclIsDacl,
  93. PTYPEINFO TypeInfo
  94. );
  95. VOID
  96. DisplaySid(
  97. IN PSID Sid
  98. );
  99. VOID
  100. ConnectToLsa( VOID );
  101. VOID
  102. Usage( VOID );
  103. ////////////////////////////////////////////////////////
  104. // //
  105. // Global Variables //
  106. // //
  107. ////////////////////////////////////////////////////////
  108. UCHAR
  109. Buffer[BUFFERSIZE];
  110. LSA_HANDLE
  111. LsaHandle;
  112. BOOLEAN
  113. CompoundLineOutput = FALSE;
  114. DumpDacl = FALSE; // May be changed by command parameter
  115. DumpDaclFull = FALSE; // May be changed by command parameter
  116. DumpSacl = FALSE; // May be changed by command parameter
  117. DumpSaclFull = FALSE; // May be changed by command parameter
  118. char * AccessMask[] = { "Delete", "ReadControl", "WriteDac", "WriteOwner",
  119. "Synch", "", "", "",
  120. "Sacl", "MaxAllowed", "", "",
  121. "GenericAll", "GenericExec", "GenericWrite", "GenericRead"};
  122. char * TokenRights[] = {"AssignPrimary", "Duplicate", "Impersonate", "Query",
  123. "QuerySource", "AdjustPriv", "AdjustGroup", "AdjustDef" };
  124. char * KeyRights[] = { "QueryValue", "SetValue", "CreateSubKey", "EnumSubKey",
  125. "Notify", "CreateLink", "", "" };
  126. char * EventRights[] = {"QueryState", "ModifyState" };
  127. char * MutantRights[]={ "QueryState" };
  128. char * SemaphoreRights[] = { "QueryState", "ModifyState" };
  129. char * TimerRights[] = {"QueryState", "ModifyState" };
  130. char * ProfileRights[]={"Control"};
  131. char * ProcessRights[]={"Terminate", "CreateThread", "", "VMOp",
  132. "VMRead", "VMWrite", "DupHandle", "CreateProcess",
  133. "SetQuota", "SetInfo", "QueryInfo", "SetPort" };
  134. char * ThreadRights[] ={"Terminate", "Suspend", "Alert", "GetContext",
  135. "SetContext", "SetInfo", "QueryInfo", "SetToken",
  136. "Impersonate", "DirectImpersonate" };
  137. char * SectionRights[]={"Query", "MapWrite", "MapRead", "MapExecute",
  138. "Extend"};
  139. char * FileRights[] = { "Read/List", "Write/Add", "Append/SubDir/CreatePipe", "ReadEA",
  140. "WriteEA", "Execute/Traverse", "DelChild", "ReadAttr",
  141. "WriteAttr"};
  142. char * PortRights[] = { "Connect" };
  143. char * DirRights[] = { "Query", "Traverse", "Create", "CreateSubdir" };
  144. char * SymLinkRights[]={"Query" };
  145. char * WinstaRights[]={ "EnumDesktops", "ReadAttr", "Clipboard", "CreateDesktop",
  146. "WriteAttr", "GlobalAtom", "ExitWindows", "",
  147. "Enumerate", "ReadScreen" };
  148. char * DesktopRights[]={"ReadObjects", "CreateWindow", "CreateMenu", "HookControl",
  149. "JournalRecord", "JournalPlayback", "Enumerate", "WriteObjects",
  150. "SwitchDesktop" };
  151. char * CompletionRights[] = { "Query", "Modify" };
  152. char * ChannelRights[] = { "ReadMessage", "WriteMessage", "Query", "SetInfo" };
  153. char * JobRights[] = { "AssignProcess", "SetAttr", "Query", "Terminate", "SetSecAttr" };
  154. #define TYPE_NONE 0
  155. #define TYPE_EVENT 1
  156. #define TYPE_SECTION 2
  157. #define TYPE_FILE 3
  158. #define TYPE_PORT 4
  159. #define TYPE_DIRECTORY 5
  160. #define TYPE_LINK 6
  161. #define TYPE_MUTANT 7
  162. #define TYPE_WINSTA 8
  163. #define TYPE_SEM 9
  164. #define TYPE_KEY 10
  165. #define TYPE_TOKEN 11
  166. #define TYPE_PROCESS 12
  167. #define TYPE_THREAD 13
  168. #define TYPE_DESKTOP 14
  169. #define TYPE_COMPLETE 15
  170. #define TYPE_CHANNEL 16
  171. #define TYPE_TIMER 17
  172. #define TYPE_JOB 18
  173. #define TYPE_WPORT 19
  174. #define TYPE_MAX 20
  175. LPWSTR pszTypeNames[TYPE_MAX] = { L"None", L"Event", L"Section", L"File",
  176. L"Port", L"Directory", L"SymbolicLink",
  177. L"Mutant", L"WindowStation", L"Semaphore",
  178. L"Key", L"Token", L"Process", L"Thread",
  179. L"Desktop", L"IoCompletion", L"Channel",
  180. L"Timer", L"Job", L"WaitablePort" };
  181. TYPEINFO TypeNames[TYPE_MAX] = {
  182. { L"Unknown", NULL, 0 },
  183. { L"Event", EventRights, 2 },
  184. { L"Section", SectionRights, 5 },
  185. { L"File", FileRights, 9 },
  186. { L"Port", PortRights, 1 },
  187. { L"Directory", DirRights, 4 },
  188. { L"SymbolicLink", SymLinkRights, 1 },
  189. { L"Mutant", MutantRights, 2 },
  190. { L"WindowStation", WinstaRights, 10 },
  191. { L"Semaphore", SemaphoreRights, 2 },
  192. { L"Key", KeyRights, 6 },
  193. { L"Token", TokenRights, 8 },
  194. { L"Process", ProcessRights, 12 },
  195. { L"Thread", ThreadRights, 10 },
  196. { L"Desktop", DesktopRights, 10 },
  197. { L"IoCompletion", CompletionRights, 2 },
  198. { L"Channel", ChannelRights, 4 },
  199. { L"Timer", TimerRights, 2 },
  200. { L"Job", JobRights, 5 },
  201. { L"WaitablePort", PortRights, 1 }
  202. };
  203. DWORD
  204. GetObjectTypeIndex(
  205. PWSTR TypeName )
  206. {
  207. DWORD i;
  208. for ( i = 1 ; i < TYPE_MAX ; i++ )
  209. {
  210. if (_wcsicmp( TypeNames[i].pszName, TypeName ) == 0 )
  211. {
  212. return( i );
  213. }
  214. }
  215. return( 0 );
  216. }
  217. VOID
  218. DisplayFlags(
  219. ULONG Flags,
  220. ULONG FlagLimit,
  221. char *flagset[],
  222. ULONG Indent,
  223. ULONG LineBreak,
  224. ULONG BufferSize,
  225. UCHAR * buffer)
  226. {
  227. char * offset;
  228. char * limit ;
  229. char * linelimit ;
  230. DWORD mask, test, i, flagsize ;
  231. DWORD scratch;
  232. if ( LineBreak > BufferSize )
  233. {
  234. strcpy( (CHAR *)buffer, "Invalid Parameter");
  235. return;
  236. }
  237. mask = 0;
  238. offset = (CHAR *) buffer;
  239. test = 1;
  240. limit = offset + BufferSize ;
  241. if ( LineBreak )
  242. {
  243. linelimit = offset + LineBreak ;
  244. }
  245. else
  246. {
  247. linelimit = limit ;
  248. }
  249. if ( linelimit > limit )
  250. {
  251. linelimit = limit ;
  252. }
  253. memset(offset, ' ', Indent);
  254. offset += Indent ;
  255. if (!Flags) {
  256. strcpy( offset, "None");
  257. return;
  258. }
  259. for ( i = 0 ; i < FlagLimit ; i++ )
  260. {
  261. if ( ( Flags & test ) != 0 )
  262. {
  263. //
  264. // Found a flag set in the flag word. Try to write the text
  265. // form into the buffer
  266. //
  267. flagsize = strlen( flagset[ i ] );
  268. if ( offset + flagsize + 2 > limit )
  269. {
  270. return;
  271. }
  272. if ( offset + flagsize + 2 > linelimit )
  273. {
  274. //
  275. // Need to do a linebreak:
  276. //
  277. *offset++ = '\r';
  278. *offset++ = '\n';
  279. if ( LineBreak )
  280. {
  281. linelimit = offset + LineBreak ;
  282. }
  283. else
  284. {
  285. linelimit = limit ;
  286. }
  287. if ( linelimit > limit )
  288. {
  289. linelimit = limit ;
  290. }
  291. memset(offset, ' ', Indent);
  292. offset += Indent ;
  293. if ( offset + flagsize + 2 > linelimit )
  294. {
  295. *offset++ = '\0';
  296. return;
  297. }
  298. }
  299. CopyMemory( offset, flagset[ i ], flagsize );
  300. offset += flagsize ;
  301. mask |= test;
  302. if ( ( Flags & (~mask) ) != 0 )
  303. {
  304. *offset++ = ' ' ;
  305. }
  306. }
  307. test <<= 1 ;
  308. }
  309. *offset = '\0';
  310. }
  311. ////////////////////////////////////////////////////////
  312. // //
  313. // Routines //
  314. // //
  315. ////////////////////////////////////////////////////////
  316. VOID
  317. __cdecl main(
  318. int argc,
  319. char *argv[]
  320. )
  321. {
  322. STRING
  323. String;
  324. int
  325. arg;
  326. char
  327. *s;
  328. BOOLEAN
  329. DirectoryNameArg;
  330. //
  331. // process any qualifiers
  332. //
  333. // All arguments are considered qualifiers until we reach a backslash ("\").
  334. // If we reach a backslash, then that argument is accepted as the last argument
  335. // and it is expected to the the name of the directory to be listed.
  336. //
  337. DirectoryNameArg = FALSE;
  338. arg = 1;
  339. while (arg < argc) {
  340. s = argv[arg];
  341. if (*s == '\\') {
  342. DirectoryNameArg = TRUE;
  343. break; // break out of while loop
  344. }
  345. if (*s != '/') {
  346. Usage();
  347. return;
  348. }
  349. s++;
  350. if (*s == 'd') {
  351. //
  352. // Dump DACL qualifier
  353. //
  354. if (DumpDaclFull == TRUE) {
  355. printf("\n\n Conflicting qualifiers: /d and /D\n");
  356. Usage();
  357. return;
  358. }
  359. DumpDacl = TRUE;
  360. DumpDaclFull = FALSE;
  361. CompoundLineOutput = TRUE;
  362. } else if (*s == 'D') {
  363. //
  364. // Dump DACL qualifier
  365. //
  366. if ((DumpDacl== TRUE) && (DumpDaclFull == FALSE)) {
  367. printf("\n\n Conflicting qualifiers: /d and /D\n");
  368. Usage();
  369. return;
  370. }
  371. DumpDacl = TRUE;
  372. DumpDaclFull = TRUE;
  373. CompoundLineOutput = TRUE;
  374. } else if (*s == 's') {
  375. //
  376. // Dump SACL qualifier
  377. //
  378. if (DumpSaclFull == TRUE) {
  379. printf("\n\n Conflicting qualifiers: /s and /S\n");
  380. Usage();
  381. return;
  382. }
  383. DumpSacl = TRUE;
  384. DumpSaclFull = FALSE;
  385. CompoundLineOutput = TRUE;
  386. } else if (*s == 'S') {
  387. //
  388. // Dump SACL qualifier
  389. //
  390. if ((DumpSacl== TRUE) && (DumpSaclFull == FALSE)) {
  391. printf("\n\n Conflicting qualifiers: /s and /S\n");
  392. Usage();
  393. return;
  394. }
  395. DumpSacl = TRUE;
  396. DumpSaclFull = TRUE;
  397. CompoundLineOutput = TRUE;
  398. } else {
  399. Usage();
  400. return;
  401. }
  402. arg++;
  403. } // end_while
  404. if (DumpDacl || DumpSacl) {
  405. ConnectToLsa();
  406. }
  407. //
  408. // Set up the name of the directory to list
  409. //
  410. if (!DirectoryNameArg) {
  411. RtlInitString( &String, "\\" );
  412. } else {
  413. RtlInitString( &String, argv[arg] );
  414. }
  415. if (EnableAllPrivileges()) {
  416. QueryDirectory( &String );
  417. }
  418. }
  419. WCHAR LinkTargetBuffer[ 1024 ];
  420. typedef struct _DIR_ENTRY {
  421. PWSTR Name;
  422. PWSTR Type;
  423. } DIR_ENTRY, *PDIR_ENTRY;
  424. #define MAX_DIR_ENTRIES 1024
  425. ULONG NumberOfDirEntries;
  426. DIR_ENTRY DirEntries[ MAX_DIR_ENTRIES ];
  427. int
  428. __cdecl
  429. CompareDirEntry(
  430. void const *p1,
  431. void const *p2
  432. )
  433. {
  434. return _wcsicmp( ((PDIR_ENTRY)p1)->Name, ((PDIR_ENTRY)p2)->Name );
  435. }
  436. VOID
  437. QueryDirectory(
  438. IN PSTRING DirectoryName
  439. )
  440. //
  441. // DumpDacl and DumpSacl are expected to be set prior to calling this routine.
  442. //
  443. {
  444. NTSTATUS Status;
  445. HANDLE DirectoryHandle, LinkHandle;
  446. ULONG Context = 0;
  447. ULONG i, ReturnedLength;
  448. UNICODE_STRING LinkTarget;
  449. POBJECT_DIRECTORY_INFORMATION DirInfo;
  450. POBJECT_NAME_INFORMATION NameInfo;
  451. OBJECT_ATTRIBUTES Attributes;
  452. UNICODE_STRING UnicodeString;
  453. ACCESS_MASK ExtraAccess = 0;
  454. UNICODE_STRING Match = { 0 };
  455. UNICODE_STRING Separators = { 0 };
  456. USHORT Offset ;
  457. ULONG DisplayedEntries = 0 ;
  458. BOOLEAN PrefixMatch = FALSE ;
  459. BOOLEAN SuffixMatch = FALSE ;
  460. ULONG ObjectNameLength ;
  461. BOOL PrefixMatched, SuffixMatched ;
  462. //
  463. // Perform initial setup
  464. //
  465. RtlZeroMemory( Buffer, BUFFERSIZE );
  466. if (DumpDacl) {
  467. ExtraAccess |= READ_CONTROL;
  468. }
  469. if (DumpSacl) {
  470. ExtraAccess |= ACCESS_SYSTEM_SECURITY;
  471. }
  472. //
  473. // Open the directory for list directory access
  474. //
  475. Status = RtlAnsiStringToUnicodeString( &UnicodeString,
  476. DirectoryName,
  477. TRUE );
  478. ASSERT( NT_SUCCESS( Status ) );
  479. InitializeObjectAttributes( &Attributes,
  480. &UnicodeString,
  481. OBJ_CASE_INSENSITIVE,
  482. NULL,
  483. NULL );
  484. Status = NtOpenDirectoryObject( &DirectoryHandle,
  485. DIRECTORY_QUERY | ExtraAccess,
  486. &Attributes
  487. );
  488. if ( ( Status == STATUS_OBJECT_TYPE_MISMATCH ) ||
  489. ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) ||
  490. ( Status == STATUS_OBJECT_PATH_NOT_FOUND ) ) {
  491. RtlInitUnicodeString( &Separators, L"\\" );
  492. Status = RtlFindCharInUnicodeString(
  493. RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END,
  494. &UnicodeString,
  495. &Separators,
  496. &Offset );
  497. if ( NT_SUCCESS( Status ) )
  498. {
  499. UnicodeString.Length = Offset ;
  500. RtlInitUnicodeString( &Match, UnicodeString.Buffer + ((Offset + 2) / sizeof( WCHAR ) ) );
  501. if ( Match.Buffer[ 0 ] == L'*' )
  502. {
  503. Match.Buffer++ ;
  504. Match.Length -= sizeof( WCHAR );
  505. SuffixMatch = TRUE ;
  506. }
  507. if ( Match.Buffer[ Match.Length / sizeof( WCHAR ) - 1 ] == L'*' )
  508. {
  509. Match.Buffer[ Match.Length / sizeof( WCHAR ) - 1 ] = L'\0';
  510. Match.Length -= sizeof( WCHAR );
  511. PrefixMatch = TRUE ;
  512. }
  513. if ( PrefixMatch && SuffixMatch )
  514. {
  515. printf("Too complicated a search\n" );
  516. return;
  517. }
  518. #if DBG
  519. printf("Searching for %c%ws%c\n",
  520. (SuffixMatch ? '*' : ' '), Match.Buffer, (PrefixMatch ? '*' : ' ') );
  521. #endif
  522. Status = NtOpenDirectoryObject( &DirectoryHandle,
  523. DIRECTORY_QUERY | ExtraAccess,
  524. &Attributes );
  525. }
  526. }
  527. if (!NT_SUCCESS( Status )) {
  528. if (Status == STATUS_OBJECT_TYPE_MISMATCH) {
  529. printf( "%Z is not a valid Object Directory Object name\n",
  530. DirectoryName );
  531. }
  532. else {
  533. Error( OpenDirectory, Status );
  534. }
  535. return;
  536. }
  537. //
  538. // Get the actual name of the object directory object.
  539. //
  540. NameInfo = (POBJECT_NAME_INFORMATION) &Buffer[0];
  541. if (!NT_SUCCESS( Status = NtQueryObject( DirectoryHandle,
  542. ObjectNameInformation,
  543. NameInfo,
  544. BUFFERSIZE,
  545. (PULONG) NULL ) )) {
  546. printf( "Unexpected error obtaining actual object directory name\n" );
  547. printf( "Error was: %X\n", Status );
  548. return;
  549. }
  550. //
  551. // Output initial informational message
  552. //
  553. printf( "Directory of: %wZ\n", &NameInfo->Name );
  554. if ( Match.Length == 0 )
  555. {
  556. if (DumpDacl) {
  557. QueryAndDisplayDacl( DirectoryHandle, L"Directory" );
  558. }
  559. if (DumpSacl) {
  560. QueryAndDisplaySacl( DirectoryHandle, L"Directory" );
  561. }
  562. printf( "\n" );
  563. }
  564. //
  565. // Query the entire directory in one sweep
  566. //
  567. NumberOfDirEntries = 0;
  568. for (Status = NtQueryDirectoryObject( DirectoryHandle,
  569. &Buffer,
  570. BUFFERSIZE,
  571. FALSE,
  572. FALSE,
  573. &Context,
  574. &ReturnedLength );
  575. NT_SUCCESS( Status );
  576. Status = NtQueryDirectoryObject( DirectoryHandle,
  577. &Buffer,
  578. BUFFERSIZE,
  579. FALSE,
  580. FALSE,
  581. &Context,
  582. &ReturnedLength ) ) {
  583. //
  584. // Check the status of the operation.
  585. //
  586. if (!NT_SUCCESS( Status )) {
  587. if (Status != STATUS_NO_MORE_FILES) {
  588. Error( Status, Status );
  589. }
  590. break;
  591. }
  592. //
  593. // For every record in the buffer type out the directory information
  594. //
  595. //
  596. // Point to the first record in the buffer, we are guaranteed to have
  597. // one otherwise Status would have been No More Files
  598. //
  599. DirInfo = (POBJECT_DIRECTORY_INFORMATION) &Buffer[0];
  600. while (TRUE) {
  601. //
  602. // Check if there is another record. If there isn't, then get out
  603. // of the loop now
  604. //
  605. if (DirInfo->Name.Length == 0) {
  606. break;
  607. }
  608. //
  609. // Print out information about the file
  610. //
  611. if (NumberOfDirEntries >= MAX_DIR_ENTRIES) {
  612. printf( "OBJDIR: Too many directory entries.\n" );
  613. exit( 1 );
  614. }
  615. DirEntries[ NumberOfDirEntries ].Name = RtlAllocateHeap( RtlProcessHeap(),
  616. HEAP_ZERO_MEMORY,
  617. DirInfo->Name.Length +
  618. sizeof( UNICODE_NULL )
  619. );
  620. DirEntries[ NumberOfDirEntries ].Type = RtlAllocateHeap( RtlProcessHeap(),
  621. HEAP_ZERO_MEMORY,
  622. DirInfo->TypeName.Length +
  623. sizeof( UNICODE_NULL )
  624. );
  625. memmove( DirEntries[ NumberOfDirEntries ].Name,
  626. DirInfo->Name.Buffer,
  627. DirInfo->Name.Length
  628. );
  629. memmove( DirEntries[ NumberOfDirEntries ].Type,
  630. DirInfo->TypeName.Buffer,
  631. DirInfo->TypeName.Length
  632. );
  633. NumberOfDirEntries++;
  634. //
  635. // There is another record so advance DirInfo to the next entry
  636. //
  637. DirInfo = (POBJECT_DIRECTORY_INFORMATION) (((PUCHAR) DirInfo) +
  638. sizeof( OBJECT_DIRECTORY_INFORMATION ) );
  639. }
  640. RtlZeroMemory( Buffer, BUFFERSIZE );
  641. }
  642. qsort( DirEntries,
  643. NumberOfDirEntries,
  644. sizeof( DIR_ENTRY ),
  645. CompareDirEntry
  646. );
  647. for (i=0; i<NumberOfDirEntries; i++) {
  648. if ( Match.Length )
  649. {
  650. ObjectNameLength = wcslen( DirEntries[ i ].Name );
  651. if ( PrefixMatch )
  652. {
  653. PrefixMatched = _wcsnicmp( DirEntries[ i ].Name,
  654. Match.Buffer,
  655. Match.Length / sizeof( WCHAR ) ) == 0 ;
  656. }
  657. if ( SuffixMatch )
  658. {
  659. if ( ObjectNameLength >= Match.Length / sizeof( WCHAR ) )
  660. {
  661. SuffixMatched =
  662. _wcsnicmp( DirEntries[ i ].Name + ( ObjectNameLength - (Match.Length / sizeof( WCHAR ) )),
  663. Match.Buffer,
  664. Match.Length / sizeof( WCHAR) ) == 0 ;
  665. }
  666. else
  667. {
  668. SuffixMatched = FALSE ;
  669. }
  670. }
  671. if ( SuffixMatch && !SuffixMatched )
  672. {
  673. continue;
  674. }
  675. if ( PrefixMatch && !PrefixMatched )
  676. {
  677. continue;
  678. }
  679. if ( (!SuffixMatch) && (!PrefixMatch) &&
  680. _wcsicmp( Match.Buffer, DirEntries[ i ].Name ) )
  681. {
  682. continue;
  683. }
  684. }
  685. DisplayedEntries++ ;
  686. printf( "%-32ws ", DirEntries[ i ].Name);
  687. if (CompoundLineOutput) {
  688. printf("\n ");
  689. }
  690. printf( "%ws", DirEntries[ i ].Type );
  691. if (!wcscmp( DirEntries[ i ].Type, L"SymbolicLink" )) {
  692. RtlInitUnicodeString( &UnicodeString, DirEntries[ i ].Name );
  693. InitializeObjectAttributes( &Attributes,
  694. &UnicodeString,
  695. OBJ_CASE_INSENSITIVE,
  696. DirectoryHandle,
  697. NULL );
  698. Status = NtOpenSymbolicLinkObject( &LinkHandle,
  699. SYMBOLIC_LINK_QUERY,
  700. &Attributes
  701. );
  702. if (NT_SUCCESS( Status )) {
  703. LinkTarget.Buffer = LinkTargetBuffer;
  704. LinkTarget.Length = 0;
  705. LinkTarget.MaximumLength = sizeof( LinkTargetBuffer );
  706. Status = NtQuerySymbolicLinkObject( LinkHandle,
  707. &LinkTarget,
  708. NULL
  709. );
  710. NtClose( LinkHandle );
  711. }
  712. if (!NT_SUCCESS( Status )) {
  713. printf( " - unable to query link target (Status == %09X)\n", Status );
  714. }
  715. else {
  716. printf( " - %wZ\n", &LinkTarget );
  717. }
  718. }
  719. else {
  720. printf( "\n" );
  721. }
  722. if (DumpDacl) {
  723. OpenAndDisplayDacl( DirectoryHandle, DirEntries[ i ].Type, DirEntries[ i ].Name);
  724. }
  725. if (DumpSacl) {
  726. OpenAndDisplaySacl( DirectoryHandle, DirEntries[ i ].Type, DirEntries[ i ].Name);
  727. }
  728. }
  729. //
  730. // Output final messages
  731. //
  732. if ( Match.Length != 0 )
  733. {
  734. if ( DisplayedEntries == 0 )
  735. {
  736. printf("not found\n" );
  737. }
  738. else if ( DisplayedEntries == 1 )
  739. {
  740. printf("\n1 entry\n" );
  741. }
  742. else
  743. {
  744. printf("\n%ld entries\n", DisplayedEntries );
  745. }
  746. }
  747. else
  748. {
  749. if (NumberOfDirEntries == 0) {
  750. printf( "no entries\n" );
  751. }
  752. else
  753. if (NumberOfDirEntries == 1) {
  754. printf( "\n1 entry\n" );
  755. }
  756. else {
  757. printf( "\n%ld entries\n", NumberOfDirEntries );
  758. }
  759. }
  760. //
  761. // Now close the directory object
  762. //
  763. (VOID) NtClose( DirectoryHandle );
  764. //
  765. // And return to our caller
  766. //
  767. return;
  768. }
  769. BOOLEAN
  770. EnableAllPrivileges(
  771. VOID
  772. )
  773. /*++
  774. Routine Description:
  775. This routine enables all privileges in the token.
  776. If we are being asked to dump SACLs then we will check
  777. to make sure we have SE_SECURITY_PRIVILEGE enabled too.
  778. Arguments:
  779. None.
  780. Return Value:
  781. None.
  782. --*/
  783. {
  784. HANDLE Token;
  785. ULONG ReturnLength, Index;
  786. PTOKEN_PRIVILEGES NewState;
  787. BOOLEAN Result;
  788. LUID SecurityPrivilege;
  789. SecurityPrivilege =
  790. RtlConvertLongToLuid(SE_SECURITY_PRIVILEGE);
  791. Token = NULL;
  792. NewState = NULL;
  793. Result = (OpenProcessToken( GetCurrentProcess(),
  794. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  795. &Token
  796. ) ? 1 : 0);
  797. if (Result) {
  798. ReturnLength = 4096;
  799. NewState = malloc( ReturnLength );
  800. Result = (BOOLEAN)(NewState != NULL);
  801. if (Result) {
  802. Result = (GetTokenInformation( Token, // TokenHandle
  803. TokenPrivileges, // TokenInformationClass
  804. NewState, // TokenInformation
  805. ReturnLength, // TokenInformationLength
  806. &ReturnLength // ReturnLength
  807. ) ? 1 : 0);
  808. if (Result) {
  809. //
  810. // Set the state settings so that all privileges are enabled...
  811. //
  812. if (DumpSacl) {
  813. Result = FALSE;
  814. }
  815. if (NewState->PrivilegeCount > 0) {
  816. for (Index = 0; Index < NewState->PrivilegeCount; Index++ ) {
  817. NewState->Privileges[Index].Attributes = SE_PRIVILEGE_ENABLED;
  818. if (RtlEqualLuid(&NewState->Privileges[Index].Luid, &SecurityPrivilege )) {
  819. Result = TRUE;
  820. }
  821. }
  822. }
  823. if (!Result) {
  824. // Don't have privilege to dump SACL
  825. ASSERT(DumpSacl);
  826. printf("\n\n You do not have sufficient privilege to display SACLs.\n\n");
  827. }
  828. else {
  829. Result = (AdjustTokenPrivileges( Token, // TokenHandle
  830. FALSE, // DisableAllPrivileges
  831. NewState, // NewState (OPTIONAL)
  832. ReturnLength, // BufferLength
  833. NULL, // PreviousState (OPTIONAL)
  834. &ReturnLength // ReturnLength
  835. ) ? 1 : 0);
  836. if (!Result) {
  837. DbgPrint( "AdjustTokenPrivileges( %lx ) failed - %u\n", Token, GetLastError() );
  838. }
  839. }
  840. }
  841. else {
  842. DbgPrint( "GetTokenInformation( %lx ) failed - %u\n", Token, GetLastError() );
  843. }
  844. }
  845. else {
  846. DbgPrint( "malloc( %lx ) failed - %u\n", ReturnLength, GetLastError() );
  847. }
  848. }
  849. else {
  850. DbgPrint( "OpenProcessToken( %lx ) failed - %u\n", GetCurrentProcess(), GetLastError() );
  851. }
  852. if (NewState != NULL) {
  853. free( NewState );
  854. }
  855. if (Token != NULL) {
  856. CloseHandle( Token );
  857. }
  858. return( Result );
  859. }
  860. NTSTATUS
  861. OpenObject(
  862. IN HANDLE Root,
  863. IN PWCHAR Type,
  864. IN PWCHAR Name,
  865. IN ACCESS_MASK DesiredAccess,
  866. OUT PHANDLE Object
  867. )
  868. {
  869. NTSTATUS
  870. Status,
  871. IgnoreStatus;
  872. UNICODE_STRING
  873. UnicodeName;
  874. OBJECT_ATTRIBUTES
  875. Attributes;
  876. IO_STATUS_BLOCK
  877. Iosb;
  878. RtlInitUnicodeString( &UnicodeName, Name );
  879. InitializeObjectAttributes( &Attributes, &UnicodeName, OBJ_CASE_INSENSITIVE, Root, NULL );
  880. //
  881. // This is effectively a big switch statement of object types
  882. // that we know how to open...
  883. //
  884. if (!wcscmp( Type, L"SymbolicLink" )) {
  885. Status = NtOpenSymbolicLinkObject( Object, DesiredAccess, &Attributes );
  886. } else if (!wcscmp( Type, L"Device" )) {
  887. Status = NtOpenFile( Object, DesiredAccess, &Attributes, &Iosb, 0, 0 );
  888. } else if (!wcscmp( Type, L"Event" )) {
  889. Status = NtOpenEvent( Object, DesiredAccess, &Attributes );
  890. } else if (!wcscmp( Type, L"EventPair" )) {
  891. Status = NtOpenEventPair( Object, DesiredAccess, &Attributes );
  892. } else if (!wcscmp( Type, L"Mutant" )) {
  893. Status = NtOpenMutant( Object, DesiredAccess, &Attributes );
  894. } else if (!wcscmp( Type, L"Timer" )) {
  895. Status = NtOpenTimer( Object, DesiredAccess, &Attributes );
  896. } else if (!wcscmp( Type, L"Semaphore" )) {
  897. Status = NtOpenSemaphore( Object, DesiredAccess, &Attributes );
  898. } else if (!wcscmp( Type, L"Section" )) {
  899. Status = NtOpenSection( Object, DesiredAccess, &Attributes );
  900. } else if (!wcscmp( Type, L"Directory" )) {
  901. Status = NtOpenDirectoryObject( Object, DesiredAccess, &Attributes );
  902. } else if (!wcscmp( Type, L"Process" )) {
  903. Status = NtOpenProcess( Object, DesiredAccess, &Attributes, NULL );
  904. } else if (!wcscmp( Type, L"Job" )) {
  905. Status = NtOpenJobObject( Object, DesiredAccess, &Attributes );
  906. } else if (!wcscmp( Type, L"WindowStation" )) {
  907. *Object = OpenWindowStationW( Name, FALSE, DesiredAccess );
  908. if (*Object)
  909. {
  910. Status = STATUS_SUCCESS;
  911. }
  912. else
  913. {
  914. Status = STATUS_ACCESS_DENIED;
  915. }
  916. } else if (!wcscmp( Type, L"Desktop" )) {
  917. *Object = OpenDesktopW( Name, 0, FALSE, DesiredAccess );
  918. if (*Object)
  919. {
  920. Status = STATUS_SUCCESS;
  921. }
  922. else
  923. {
  924. Status = STATUS_ACCESS_DENIED;
  925. }
  926. } else {
  927. //
  928. // this utility doesn't yet support opening this type of object
  929. //
  930. Status = STATUS_NOT_SUPPORTED;
  931. }
  932. return(Status);
  933. }
  934. VOID
  935. OpenAndDisplaySacl(
  936. IN HANDLE Root,
  937. IN PWCHAR Type,
  938. IN PWCHAR Name
  939. )
  940. {
  941. NTSTATUS
  942. Status,
  943. IgnoreStatus;
  944. HANDLE
  945. Object;
  946. Status = OpenObject( Root, Type, Name, ACCESS_SYSTEM_SECURITY, &Object);
  947. if (NT_SUCCESS(Status)) {
  948. QueryAndDisplaySacl( Object, Type );
  949. IgnoreStatus = NtClose( Object );
  950. ASSERT(NT_SUCCESS(IgnoreStatus));
  951. }
  952. if (!NT_SUCCESS(Status)) {
  953. if (Status == STATUS_NOT_SUPPORTED) {
  954. printf(" Utility doesn't yet query SACLs for this type of object.\n\n");
  955. } else {
  956. printf(" Error attempting to query SACL: 0x%lx.\n\n", Status);
  957. }
  958. }
  959. return;
  960. }
  961. VOID
  962. QueryAndDisplaySacl(
  963. IN HANDLE Object,
  964. IN PWSTR Type
  965. )
  966. {
  967. NTSTATUS
  968. Status;
  969. PSECURITY_DESCRIPTOR
  970. SD;
  971. ULONG
  972. LengthNeeded,
  973. TypeIndex ;
  974. Status = NtQuerySecurityObject( Object,
  975. SACL_SECURITY_INFORMATION,
  976. NULL,
  977. 0,
  978. &LengthNeeded
  979. );
  980. ASSERT(!NT_SUCCESS(Status));
  981. if (Status == STATUS_BUFFER_TOO_SMALL) {
  982. SD = RtlAllocateHeap( RtlProcessHeap(), 0, LengthNeeded );
  983. if (SD == NULL) {
  984. Status = STATUS_NO_MEMORY;
  985. } else {
  986. Status = NtQuerySecurityObject( Object,
  987. SACL_SECURITY_INFORMATION,
  988. SD,
  989. LengthNeeded,
  990. &LengthNeeded
  991. );
  992. if (NT_SUCCESS(Status)) {
  993. //
  994. // Display the SACL
  995. //
  996. Status = DisplaySacl( SD, Type );
  997. }
  998. }
  999. }
  1000. return;
  1001. }
  1002. NTSTATUS
  1003. DisplaySacl(
  1004. PSECURITY_DESCRIPTOR SD,
  1005. PWSTR Type
  1006. )
  1007. /*++
  1008. Routine Description:
  1009. This function dumps out a SACL
  1010. If an error status is returned, then the caller is responsible
  1011. for printing a message.
  1012. --*/
  1013. {
  1014. NTSTATUS
  1015. Status;
  1016. BOOLEAN
  1017. AclPresent,
  1018. AclDefaulted;
  1019. PACL
  1020. Acl;
  1021. ACL_SIZE_INFORMATION
  1022. AclInfo;
  1023. ULONG
  1024. i;
  1025. PACE_HEADER
  1026. Ace;
  1027. ULONG TypeIndex ;
  1028. TypeIndex = GetObjectTypeIndex( Type );
  1029. Status = RtlGetSaclSecurityDescriptor ( SD, &AclPresent, &Acl, &AclDefaulted );
  1030. if (NT_SUCCESS(Status)) {
  1031. printf(" SACL - ");
  1032. if (!AclPresent) {
  1033. printf("No SACL present on object\n");
  1034. } else {
  1035. if (AclDefaulted) {
  1036. printf("SACL Defaulted flag set\n ");
  1037. }
  1038. if (Acl == NULL) {
  1039. printf("NULL SACL - no auditing performed.\n");
  1040. } else {
  1041. Status = RtlQueryInformationAcl ( Acl,
  1042. &AclInfo,
  1043. sizeof(ACL_SIZE_INFORMATION),
  1044. AclSizeInformation);
  1045. ASSERT(NT_SUCCESS(Status));
  1046. if (AclInfo.AceCount == 0) {
  1047. printf("No ACEs in ACL, Auditing performed.\n");
  1048. } else {
  1049. printf("\n");
  1050. for (i=0; i<AclInfo.AceCount; i++) {
  1051. Status = RtlGetAce( Acl, i, &Ace );
  1052. ASSERT(NT_SUCCESS(Status));
  1053. printf(" Ace[%2d] - ", i);
  1054. DumpAce( Ace, FALSE, &TypeNames[ TypeIndex ] );
  1055. printf("\n");
  1056. }
  1057. }
  1058. }
  1059. }
  1060. }
  1061. printf("\n");
  1062. return(Status);
  1063. }
  1064. VOID
  1065. OpenAndDisplayDacl(
  1066. IN HANDLE Root,
  1067. IN PWCHAR Type,
  1068. IN PWCHAR Name
  1069. )
  1070. {
  1071. NTSTATUS
  1072. Status,
  1073. IgnoreStatus;
  1074. HANDLE
  1075. Object;
  1076. ULONG TypeIndex ;
  1077. Status = OpenObject( Root, Type, Name, READ_CONTROL, &Object);
  1078. if (NT_SUCCESS(Status)) {
  1079. QueryAndDisplayDacl( Object, Type );
  1080. IgnoreStatus = NtClose( Object );
  1081. ASSERT(NT_SUCCESS(IgnoreStatus));
  1082. }
  1083. if (!NT_SUCCESS(Status)) {
  1084. if (Status == STATUS_ACCESS_DENIED) {
  1085. printf(" Protection on object prevented querying the DACL.\n\n");
  1086. } else if (Status == STATUS_NOT_SUPPORTED) {
  1087. printf(" Utility doesn't yet query DACLs for this type of object.\n\n");
  1088. } else {
  1089. printf(" Error attempting to query DACL: 0x%lx.\n\n", Status);
  1090. }
  1091. }
  1092. return;
  1093. }
  1094. VOID
  1095. QueryAndDisplayDacl(
  1096. IN HANDLE Object,
  1097. IN PWSTR Type
  1098. )
  1099. {
  1100. NTSTATUS
  1101. Status;
  1102. PSECURITY_DESCRIPTOR
  1103. SD;
  1104. ULONG
  1105. LengthNeeded;
  1106. Status = NtQuerySecurityObject( Object,
  1107. DACL_SECURITY_INFORMATION,
  1108. NULL,
  1109. 0,
  1110. &LengthNeeded
  1111. );
  1112. ASSERT(!NT_SUCCESS(Status));
  1113. if (Status == STATUS_BUFFER_TOO_SMALL) {
  1114. SD = RtlAllocateHeap( RtlProcessHeap(), 0, LengthNeeded );
  1115. if (SD == NULL) {
  1116. Status = STATUS_NO_MEMORY;
  1117. } else {
  1118. Status = NtQuerySecurityObject( Object,
  1119. DACL_SECURITY_INFORMATION,
  1120. SD,
  1121. LengthNeeded,
  1122. &LengthNeeded
  1123. );
  1124. if (NT_SUCCESS(Status)) {
  1125. //
  1126. // Display the DACL
  1127. //
  1128. Status = DisplayDacl( SD, Type );
  1129. }
  1130. }
  1131. }
  1132. return;
  1133. }
  1134. NTSTATUS
  1135. DisplayDacl(
  1136. PSECURITY_DESCRIPTOR SD,
  1137. PWSTR Type
  1138. )
  1139. /*++
  1140. Routine Description:
  1141. This function dumps out a DACL
  1142. If an error status is returned, then the caller is responsible
  1143. for printing a message.
  1144. --*/
  1145. {
  1146. NTSTATUS
  1147. Status;
  1148. BOOLEAN
  1149. AclPresent,
  1150. AclDefaulted;
  1151. PACL
  1152. Acl;
  1153. ACL_SIZE_INFORMATION
  1154. AclInfo;
  1155. ULONG
  1156. i;
  1157. PACE_HEADER
  1158. Ace;
  1159. ULONG TypeIndex ;
  1160. TypeIndex = GetObjectTypeIndex( Type );
  1161. Status = RtlGetDaclSecurityDescriptor ( SD, &AclPresent, &Acl, &AclDefaulted );
  1162. if (NT_SUCCESS(Status)) {
  1163. printf(" DACL - ");
  1164. if (!AclPresent) {
  1165. printf("No DACL present on object\n");
  1166. } else {
  1167. if (AclDefaulted) {
  1168. printf("DACL Defaulted flag set\n ");
  1169. }
  1170. if (Acl == NULL) {
  1171. printf("NULL DACL - grants all access to Everyone\n");
  1172. } else {
  1173. Status = RtlQueryInformationAcl ( Acl,
  1174. &AclInfo,
  1175. sizeof(ACL_SIZE_INFORMATION),
  1176. AclSizeInformation);
  1177. ASSERT(NT_SUCCESS(Status));
  1178. if (AclInfo.AceCount == 0) {
  1179. printf("No ACEs in ACL, Denies all access to everyone\n");
  1180. } else {
  1181. printf("\n");
  1182. for (i=0; i<AclInfo.AceCount; i++) {
  1183. Status = RtlGetAce( Acl, i, &Ace );
  1184. ASSERT(NT_SUCCESS(Status));
  1185. printf(" Ace[%2d] - ", i);
  1186. DumpAce( Ace, TRUE, &TypeNames[ TypeIndex ] );
  1187. printf("\n");
  1188. }
  1189. }
  1190. }
  1191. }
  1192. }
  1193. printf("\n");
  1194. return(Status);
  1195. }
  1196. VOID
  1197. DumpAce(
  1198. PACE_HEADER Ace,
  1199. BOOLEAN AclIsDacl,
  1200. PTYPEINFO TypeInfo
  1201. )
  1202. /*++
  1203. Routine Description:
  1204. This function displays a single ACE
  1205. Arguments:
  1206. Ace - Points to an ACE.
  1207. AclIsDacl - TRUE if acl is a DACL. False if acl is an SACL.
  1208. Return Value:
  1209. None.
  1210. --*/
  1211. {
  1212. if ((Ace->AceFlags & INHERIT_ONLY_ACE) != 0) {
  1213. printf("Inherit Only - ");
  1214. }
  1215. switch (Ace->AceType) {
  1216. case ACCESS_ALLOWED_ACE_TYPE:
  1217. printf("Grant -");
  1218. DumpStandardAceInfo(Ace, AclIsDacl, TypeInfo);
  1219. break;
  1220. case ACCESS_DENIED_ACE_TYPE:
  1221. printf("Deny -");
  1222. DumpStandardAceInfo(Ace, AclIsDacl, TypeInfo);
  1223. break;
  1224. case SYSTEM_AUDIT_ACE_TYPE:
  1225. printf("Audit ");
  1226. DumpStandardAceInfo(Ace, AclIsDacl, TypeInfo);
  1227. break;
  1228. default:
  1229. printf(" ** Unknown ACE Type **");
  1230. }
  1231. return;
  1232. }
  1233. VOID
  1234. DumpStandardAceInfo(
  1235. PACE_HEADER Ace,
  1236. BOOLEAN AclIsDacl,
  1237. PTYPEINFO TypeInfo
  1238. )
  1239. /*++
  1240. Routine Description:
  1241. This function dumps out the standard information for a single ACE.
  1242. Arguments:
  1243. Ace - Points to an ACE_HEADER. The ACE must be one of the known types.
  1244. AclIsDacl - TRUE if acl is a DACL. False if acl is an SACL.
  1245. Return Value:
  1246. None.
  1247. --*/
  1248. {
  1249. PACCESS_ALLOWED_ACE
  1250. Local;
  1251. ACCESS_MASK
  1252. Specific;
  1253. CHAR FlagBuffer[ 256 ];
  1254. //
  1255. // WARNING -
  1256. //
  1257. // It is assumed that all the known ACE types have their ACCESS_MASK
  1258. // and SID fields in the same location as the ACCESS_ALLOWED_ACE.
  1259. //
  1260. Local = (PACCESS_ALLOWED_ACE)(Ace);
  1261. if (Ace->AceType == SYSTEM_AUDIT_ACE_TYPE) {
  1262. printf("[");
  1263. if (Ace->AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG) {
  1264. printf("S");
  1265. if (Ace->AceFlags & FAILED_ACCESS_ACE_FLAG) {
  1266. printf(",F");
  1267. }
  1268. } else if (Ace->AceFlags & FAILED_ACCESS_ACE_FLAG) {
  1269. printf(" ,F");
  1270. } else {
  1271. printf("Neither Success nor Failure flag set]");
  1272. return;
  1273. }
  1274. printf("] -");
  1275. }
  1276. printf(" 0x%lx - ", Local->Mask );
  1277. DisplaySid( (PSID)(&Local->SidStart) );
  1278. //
  1279. // Everything else is only printed for FULL displays
  1280. if (AclIsDacl && !DumpDaclFull) {
  1281. return;
  1282. }
  1283. if (!AclIsDacl && !DumpSaclFull) {
  1284. return;
  1285. }
  1286. //
  1287. // Print the inheritance
  1288. //
  1289. printf("\n Inherit: ");
  1290. if ((Ace->AceFlags & INHERIT_ONLY_ACE) != 0) {
  1291. printf("IO ");
  1292. }
  1293. if ((Ace->AceFlags & OBJECT_INHERIT_ACE) != 0) {
  1294. printf("OI ");
  1295. }
  1296. if ((Ace->AceFlags & CONTAINER_INHERIT_ACE) != 0) {
  1297. printf("CI ");
  1298. }
  1299. if ((Ace->AceFlags & NO_PROPAGATE_INHERIT_ACE) != 0) {
  1300. printf("NPI");
  1301. }
  1302. //
  1303. // Print the accesses
  1304. //
  1305. Specific = (Local->Mask & 0xFFFF);
  1306. printf("\n Access: 0x%04lX", Specific);
  1307. if ( TypeInfo->NumberRights )
  1308. {
  1309. DisplayFlags(
  1310. Specific,
  1311. TypeInfo->NumberRights,
  1312. TypeInfo->AccessRights,
  1313. 38,
  1314. 80,
  1315. sizeof( Buffer ),
  1316. (PUCHAR) Buffer );
  1317. printf("\n%s\n ", Buffer);
  1318. }
  1319. if (Local->Mask != Specific) {
  1320. printf(" and (");
  1321. }
  1322. if ((Local->Mask & DELETE) != 0) {
  1323. printf(" D");
  1324. }
  1325. if ((Local->Mask & READ_CONTROL) != 0) {
  1326. printf(" RCtl");
  1327. }
  1328. if ((Local->Mask & WRITE_OWNER) != 0) {
  1329. printf(" WOwn");
  1330. }
  1331. if ((Local->Mask & WRITE_DAC) != 0) {
  1332. printf(" WDacl");
  1333. }
  1334. if ((Local->Mask & SYNCHRONIZE) != 0) {
  1335. printf(" Synch");
  1336. }
  1337. if ((Local->Mask & GENERIC_READ) != 0) {
  1338. printf(" R");
  1339. }
  1340. if ((Local->Mask & GENERIC_WRITE) != 0) {
  1341. printf(" W");
  1342. }
  1343. if ((Local->Mask & GENERIC_EXECUTE) != 0) {
  1344. printf(" E");
  1345. }
  1346. if ((Local->Mask & GENERIC_ALL) != 0) {
  1347. printf(" ALL");
  1348. }
  1349. if ((Local->Mask & ACCESS_SYSTEM_SECURITY) != 0) {
  1350. printf(" ACC_SYS_SEC");
  1351. }
  1352. if ((Local->Mask & MAXIMUM_ALLOWED) != 0) {
  1353. printf(" MAX_ALLOWED");
  1354. }
  1355. if (Local->Mask != Specific) {
  1356. printf(" )");
  1357. }
  1358. printf("\n");
  1359. return;
  1360. }
  1361. VOID
  1362. DisplaySid(
  1363. IN PSID Sid
  1364. )
  1365. /*++
  1366. Routine Description:
  1367. This function calls LSA to lookup a SID and displays the result.
  1368. Arguments:
  1369. Sid
  1370. Return Value:
  1371. None.
  1372. --*/
  1373. {
  1374. NTSTATUS
  1375. Status;
  1376. PLSA_REFERENCED_DOMAIN_LIST
  1377. ReferencedDomains;
  1378. PLSA_TRANSLATED_NAME
  1379. SidName;
  1380. ULONG
  1381. DomainIndex;
  1382. UNICODE_STRING
  1383. SidString;
  1384. if (LsaHandle == NULL) {
  1385. printf("Can't call LSA to lookup sid");
  1386. return;
  1387. }
  1388. Status = LsaLookupSids(
  1389. LsaHandle,
  1390. 1,
  1391. &Sid,
  1392. &ReferencedDomains,
  1393. &SidName
  1394. );
  1395. if (!NT_SUCCESS(Status)) {
  1396. RtlConvertSidToUnicodeString( &SidString, Sid, TRUE );
  1397. printf("%ws (Unable to translate)", SidString.Buffer );
  1398. RtlFreeUnicodeString( &SidString );
  1399. return;
  1400. }
  1401. DomainIndex = SidName[0].DomainIndex;
  1402. printf("%wZ", &ReferencedDomains->Domains[DomainIndex].Name );
  1403. if (ReferencedDomains->Domains[DomainIndex].Name.Length != 0) {
  1404. printf("\\");
  1405. }
  1406. printf("%wZ", &SidName[0].Name );
  1407. LsaFreeMemory( ReferencedDomains );
  1408. LsaFreeMemory( SidName );
  1409. return;
  1410. }
  1411. VOID
  1412. ConnectToLsa( VOID )
  1413. /*++
  1414. Routine Description:
  1415. This function connects to LSA in preparation for expected SID
  1416. lookup calls.
  1417. --*/
  1418. {
  1419. NTSTATUS
  1420. Status;
  1421. OBJECT_ATTRIBUTES
  1422. ObjectAttributes;
  1423. InitializeObjectAttributes( &ObjectAttributes, NULL, 0, 0, NULL );
  1424. LsaHandle = NULL;
  1425. Status = LsaOpenPolicy(
  1426. NULL, // SystemName
  1427. &ObjectAttributes,
  1428. POLICY_LOOKUP_NAMES, // DesiredAccess
  1429. &LsaHandle
  1430. );
  1431. if (!NT_SUCCESS(Status)) {
  1432. LsaHandle = NULL;
  1433. }
  1434. return;
  1435. }
  1436. VOID
  1437. Usage(VOID)
  1438. {
  1439. printf("\n\n"
  1440. " Usage:\n"
  1441. " objdir [/d | /D] [/s | /S] [<dir_name>]\n\n"
  1442. " Where:\n"
  1443. " /d - causes DACLs to be displayed in short form.\n\n"
  1444. " /D - causes DACLs to be displayed in long form.\n\n"
  1445. " /s - causes SACLs to be displayed in short form.\n\n"
  1446. " /S - causes SACLs to be displayed in long form.\n\n"
  1447. " <dir_name> - is the name of the directory you\n"
  1448. " would like to see displayed. Default\n"
  1449. " is the root directory.\n\n"
  1450. " Examples:\n"
  1451. " objdir /d\n"
  1452. " - displays dacls of objects in root directory\n\n"
  1453. " objdir \\DosDevices\n"
  1454. " - displays objects in \\DosDevices\n\n"
  1455. " objdir /d \\BaseNamedObjects\n"
  1456. " - displays dacls of objects in \\BaseNamedObjects\n\n"
  1457. " objdir /s /d \\Windows\n"
  1458. " - displays sacls and dacls of objects in \\Windowss\n\n"
  1459. " objdir /d \\Windows\\Windowstations\\Service*\n"
  1460. " - displays dacls of all windowstations beginning with 'service'\n\n"
  1461. " objdir \\Global??\\w*\n"
  1462. " - displays objects starting with w in \\Global??\n\n"
  1463. );
  1464. return;
  1465. }