|
|
1.1.1.3 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 Microsoft Corporation. ! 5: * All rights reserved. ! 6: * This source code is only intended as a supplement to ! 7: * Microsoft Development Tools and/or WinHelp documentation. ! 8: * See these sources for detailed information regarding the ! 9: * Microsoft samples programs. ! 10: \******************************************************************************/ ! 11: 1.1 root 12: /****************************************************************************\ 13: * MODULE: sidclean.c 14: * 15: * NT never deletes SIDs, so the name of this sample is most 16: * accurately be intrepreted as "Clean up SID ownership and 17: * ACE's that relate to SIDs that still (and always will) 18: * exist, but for which the corresponding user account has been 19: * deleted" 20: * 21: * 22: * PURPOSE: Demonstrate some of the Win32 security api(s), and provide a 23: * sample of how a utility could be written that recovers 24: * on-disk resources remaining allocated to deleted user 25: * accounts. The on-disk resources recovered are 1) Files that 26: * are still owned by accounts that have been deleted are 27: * assigned ownership to the account logged on when this sample 28: * is run, and 2) ACE's for deleted accounts are edited 29: * (deleted) out of the ACLs of files to which the deleted 30: * accounts had been granted authorizations (eg., Read access) 31: * 32: * It may be that running this sample as a utility has no 33: * practical value in many environments, as the number of files 34: * belonging to deleted user accounts will often be quite 35: * small, and the number of bytes recovered on disk by editing 36: * out ACEs for deleted accounts may well not be worth the time 37: * it takes to run this sample. The time it takes to run this 38: * sample may be quite significant when processing an entire 39: * hard disk or partition 40: * 41: * This sample is not a supported utility 42: * 43: * 44: * TO RUN: You must log on using an account, such as Administrator, that 45: * has the priviledges to take file ownership and edit ACls 46: * 47: * The ACL editing part of this sample can only be excercised for 48: * files on a partition that has ACLs NT processes: NTFS 49: * 50: * Typical test scenario: Create a user account or two, log on 51: * as each of these accounts in turn, while logged on for each 52: * account, go to an NTFS partition, create a couple of files 53: * so the test accounts each own a few files, use the file 54: * manager to edit permissions for those files so that each 55: * test user has some authorities (e.g., Read) explicitly 56: * granted for those files. Logon as Administrator, authorize 57: * each test user to a few Administrator-owned files. Delete 58: * the test accounts. Run the sample in the directories where 59: * you put the files the test accounts owned or were authorized 60: * to 61: * 62: * 63: * OVERALL APPROACH: The command line interface is kept inflexible to simplify 64: * it's parsing in this sample. The user must pass in a switch 65: * argument, a directory spec, and a file search pattern 66: * 67: * The sample positions the current directory (of the process the 68: * sample runs in) to the dir spec, and uses FindFirstFile and 69: * FindNextFile to walk through the directory specified looking 70: * for files that match the file pattern specified 71: * 72: * The switch argument can cause subdirectories to be searched 73: * recursively 74: * 75: * The switch argument lets the user choose only to take 76: * ownerships, only to edit ACLs, do both, or do neither, in 77: * which case the sample merely reports on what ownerships 78: * would have been taken, and what ACE's would have been 79: * deleted 80: * 81: * As the directories are walked, each file that matches the 82: * file pattern is processed right then 83: * 84: * Note that we process files in a directory, and we also process 85: * the directory itself that contains the files. We process 86: * directories because they can also be owned by deleted 87: * accounts, or could have ACEs that will no longer be used 88: * 89: * Note also that we process all directories that we check for 90: * files, regardless of the spelling of the directory name 91: * 92: * Counters are kept of file ownerships taken, ACEs deleted and 93: * total files checked, to print a summary line at the end of 94: * the run 95: * 96: * The sample considers it perfectly acceptable if 0 files match 97: * the file pattern for the entire run 98: * 99: * 100: * FUNCTIONS: DoMatchingFilesInOneDir 101: * 102: * Look in one dir or sub-dir for files that match the file 103: * pattern. For each match call DoOneFileOrDir 104: * 105: * DoAllDirsInOneDir 106: * 107: * For all the sub-dirs in a dir, set the current directory to be 108: * that directory, check for files that match the file pattern, 109: * and if any match, call DoMatchingFilesInOneDir to process 110: * those. Then reset the current directory 111: * 112: * GetFullFileOrDirName 113: * 114: * Get the full name of the file or dir for simplified processing 115: * (and for display on the console) 116: * 117: * DoOneFileOrDir 118: * 119: * Get the file's SD (Security Descriptor), and call 120: * TakeOwnershipIfAppropriate and/or DeleteACEsAsAppropriate as 121: * needed 122: * 123: * TakeOwnershipIfAppropriate 124: * 125: * Get the owning SID of the file from the file's SD that 126: * DoOneFileOrDir passed in, check that SID to see if the 127: * account is deleted. If so, edit into the file's SD a new 128: * owning SID (the SID of the process running the sample). 129: * Then write the modified file SD to disk 130: * 131: * DeleteACEsAsAppropriate 132: * 133: * Get the DACL of the file from the file's SD that 134: * DoOneFileOrDir passed in. Walk through the ACE list for 135: * that DACL, checking each ACE to see what SID the ACE refers 136: * to. For the SID referred to, check to see if the account is 137: * deleted. If so, delete that ACE from the DACL. When all 138: * ACE's have been examined, write the new DACL into the file's 139: * SD. Then write the modified file SD to disk 140: * 141: * GetProcessSid 142: * 143: * Retrieve into a global variable the SID of the user account 144: * logged on when this sample is run. This is the SID used by 145: * TakeOwnershipIfAppropriate 146: * 1.1.1.3 ! root 147: * NOTE: This routine has the notable side-effect on the access ! 148: * token of the curent process of enabling two privileges: ! 149: * SeTakeOwnershipPrivilege, and SeSecurityPrivilege. ! 150: * SeTakeOwnershipPrivilege is needed to ensure we can take ! 151: * ownership in spite of any DACL on the file. ! 152: * SeSecurityPrivilege is needed to work with SACLs ! 153: * 1.1 root 154: * CrackArgs 155: * 156: * Process the command line, cracking (parsing/decoding) the 157: * switch argument into boolean global variables (see below). 158: * Call DisplayHelp if anything illegal is found in the command 159: * line, or if the user asked for help 160: * 161: * DisplayHelp 162: * 163: * Display help text on the console 164: * 165: * 166: * GLOBAL VARS: 167: * BOOL bTakeOwnership 168: * BOOL bEditACLs 169: * BOOL bRecurse 170: * BOOL bJustCount 171: * 172: * These store the values the user specified on the command 173: * line's first argument (the switches argument). 174: * Respectively, they record whether we are to do the 175: * processing to Take Ownerships, Edit ACLs, whether we are to 176: * recurse into all subdirectories, and whether we are just 177: * counting up what would be processed (in which case we take 178: * no ownerships and edit no ACLs) 179: * 180: * DWORD dwFilesChecked 181: * DWORD dwFilesOwned 182: * DWORD dwACEsDeleted 183: * 184: * These count, respecively, the total files we checked, the 185: * number of files we took ownership of (or would have if we 186: * had not been told only to count), and the number of ACEs we 187: * deleted (or would have if we had not been told only to 188: * count). Note that the total number of files checked does 189: * not include files in the directories we process that do not 190: * match the file pattern 191: * 192: * Note, however, that we process directories regardless of 193: * whether they match the file pattern 194: * 195: * UCHAR ucProcessSIDBuf 196: * PSID psidProcessOwnerSID 197: * 198: * These store the SID of the account logged on as this sample 199: * runs, and a pointer to that SID 200: * 201: \****************************************************************************/ 202: 203: 204: /****************************************************************************\ 205: * INCLUDES, DEFINES, TYPEDEFS 206: \****************************************************************************/ 1.1.1.2 root 207: #define STRICT 1.1 root 208: #include <windows.h> 209: #include <stdio.h> 210: #include <string.h> 1.1.1.2 root 211: #include <stdlib.h> 1.1 root 212: 213: #define PERR(api) printf("%s: Error %d from %s on line %d\n", \ 214: __FILE__, GetLastError(), api, __LINE__); 215: #define PMSG(msg) printf("%s line %d: %s\n", \ 216: __FILE__, __LINE__, msg); 217: 218: #define PrintAppStyleAPIError(ApiTxt,MsgTxt) { \ 219: DWORD dwLastError; \ 220: dwLastError = GetLastError(); \ 221: switch (dwLastError) \ 222: { case ERROR_FILE_NOT_FOUND : \ 223: printf("\nFile not found (%s) line %d",MsgTxt,__LINE__); \ 224: break; \ 225: case ERROR_INVALID_NAME : \ 226: printf("\nInvalid name (%s) line %d",MsgTxt,__LINE__); \ 227: break; \ 228: case ERROR_PATH_NOT_FOUND : \ 229: printf("\nError path not found (%s) line %d",MsgTxt,__LINE__); \ 230: break; \ 231: case ERROR_SHARING_VIOLATION : \ 232: printf("\nSharing violation - shut down net and/or stop other sessions (%s) line %d",MsgTxt,__LINE__); \ 233: break; \ 234: case ERROR_ACCESS_DENIED : \ 235: printf("\nAccess denied (%s) line %d",MsgTxt,__LINE__); \ 236: break; \ 237: default : \ 238: printf("\n" #ApiTxt " - unexpected return code=%d (%s) line %d",dwLastError,MsgTxt,__LINE__); \ 239: break; \ 240: } \ 241: } 242: 243: /****************************************************************************\ 244: * GLOBAL VARIABLES 245: \****************************************************************************/ 246: 247: BOOL bTakeOwnership = FALSE; 248: BOOL bEditACLs = FALSE; 249: BOOL bRecurse = FALSE; 250: BOOL bJustCount = FALSE; 251: 252: DWORD dwFilesChecked = 0; 253: DWORD dwFilesOwned = 0; 254: DWORD dwACEsDeleted = 0; 255: 1.1.1.2 root 256: PSID psidProcessOwnerSID; 1.1 root 257: 258: 259: /****************************************************************************\ 260: * FUNCTION PROTOTYPES 261: \****************************************************************************/ 262: 263: BOOL DoMatchingFilesInOneDir(HANDLE hFound, 264: WIN32_FIND_DATA ffdFoundData); 265: BOOL DoAllDirsInOneDir(char *FilePattern); 266: BOOL GetFullFileOrDirName(LPTSTR lpszFileName); 267: BOOL DoOneFileOrDir(LPTSTR lpszFullName); 268: BOOL TakeOwnershipIfAppropriate(PSECURITY_DESCRIPTOR psdFileSD, 269: LPTSTR lpszFullName); 270: BOOL DeleteACEsAsAppropriate (PSECURITY_DESCRIPTOR psdFileSD, 271: LPTSTR lpszFullName); 272: BOOL GetProcessSid(VOID); 273: BOOL CrackArgs(UINT argc, char *argv[]); 274: VOID DisplayHelp(VOID); 275: 276: /****************************************************************************\ 277: * 278: * FUNCTION: Main 279: * 280: \****************************************************************************/ 281: 282: UINT main(UINT argc, char *argv[]) 283: { 284: WIN32_FIND_DATA ffdFoundData; 285: HANDLE hFound; 286: #define SZ_NAME_BUF MAX_PATH 287: UCHAR ucPathBuf[SZ_NAME_BUF]; 288: LPTSTR lpszFullName = (LPTSTR)&ucPathBuf; 289: 290: /**************************************************************************\ 291: * 292: * Store the process's SID in a global variable for later use (in taking 293: * ownership). 294: * 295: \**************************************************************************/ 296: 297: if (!GetProcessSid()) 298: { PERR("Can't proceed without process SID - see earlier error messages"); 299: return(1); 300: } 301: 302: if (!CrackArgs(argc,argv)) 303: return(1); 304: 305: /**************************************************************************\ 306: * 307: * CrackArgs has set our global processing switches, and proven argv[2] and 308: * argv[3] are our non-blank dir-spec and file-pattern strings. Now we 309: * must see that the file-spec is acceptable to the Win32 api's. Argv[2] 310: * is the file-spec to pass to SetCurrentDirectory, and argv[3] is the 311: * file-pattern to pass to FindFirstFile 312: * 313: * First we have to expand the dir-spec in argv[2], because if we set the 314: * current directory to it before expansion,the expansion will have a 315: * different result if argv[2] is something like ..\.. 316: * 317: \**************************************************************************/ 318: 319: strcpy(lpszFullName,argv[2]); 320: 321: if (!GetFullFileOrDirName(lpszFullName)) 1.1.1.2 root 322: { PERR("Failed to expand to full name the 2nd argument (directory specification)"); 1.1 root 323: return(1); 324: } 325: 326: /**************************************************************************\ 327: * 328: * Now we pass the un-expanded argv[2] to SetCurrentDirectory for validity 329: * checking. GetFullPathName (called by GetFullFileOrDirName) does not 330: * validity check 331: * 332: \**************************************************************************/ 333: 334: if (!SetCurrentDirectory(argv[2])) 335: { PrintAppStyleAPIError(SetCurrentDirectory,"2nd argument (directory specification)"); 336: return(1); 337: } 338: 339: /**************************************************************************\ 340: * 341: * We begin processing with the current directory, using the expanded form we 342: * got before. We have to use the expanded form, because if we set to 343: * ..\.. and then try to process the string ..\.. as a dir name, instead of 344: * processing the dir two levels up from where we are we'll process the dir 345: * four levels up 346: * 347: \**************************************************************************/ 348: 349: if (!DoOneFileOrDir(lpszFullName)) 350: return(1); 351: 352: /**************************************************************************\ 353: * 354: * It's OK to get no hits. The files-checked counter will show how many 355: * files we looked at, and it's OK to look at 0 356: * 357: * On the else branch, Argv[3] has been verified, and we have a good handle. 358: * We now pass to DoMatchingFilesInOneDir for processing the handle and 359: * found data we just got from FindFirstFile 360: * 361: \**************************************************************************/ 362: 363: hFound = FindFirstFile(argv[3], 364: (LPWIN32_FIND_DATA)&ffdFoundData); 365: if ((HANDLE)(-1) == hFound) 366: { if (GetLastError() != ERROR_FILE_NOT_FOUND) 367: { PrintAppStyleAPIError(FindFirstFile,"3rd argument"); 368: return(1); 369: } 370: } 371: else if (!DoMatchingFilesInOneDir(hFound,ffdFoundData)) 372: return(1); 373: 374: /**************************************************************************\ 375: * 376: * Pass the original file pattern for recursive calling to DoAllDirsInOneDir 377: * 378: \**************************************************************************/ 379: 380: if (!DoAllDirsInOneDir(argv[3])) 381: return(1); 382: 383: if (bJustCount) 384: printf("\nChecked %d files, would have taken ownership of %d files, would have deleted %d ACEs\n", 385: dwFilesChecked,dwFilesOwned,dwACEsDeleted); 386: else 387: printf("\nChecked %d files, took ownership of %d files, deleted %d ACEs\n", 388: dwFilesChecked,dwFilesOwned,dwACEsDeleted); 389: 1.1.1.2 root 390: free(psidProcessOwnerSID); 391: 1.1 root 392: return(0); 393: } 394: 395: /****************************************************************************\ 396: * 397: * FUNCTION: DoMatchingFilesInOneDir 398: * 399: \****************************************************************************/ 400: 401: BOOL DoMatchingFilesInOneDir(HANDLE hFound, 402: WIN32_FIND_DATA ffdFoundData) 403: { 404: BOOL bDoneWithHandle = FALSE; 405: 406: /**************************************************************************\ 407: * 408: * Process all files referred to by the handle, but not including 409: * directories, because directories are handled with separate calls to 410: * DoOneFileOrDir. Such separate calls are made as we are setting the 411: * current directory to be the directory to be processed 412: * 413: \**************************************************************************/ 414: 415: while (!bDoneWithHandle) 416: { 417: if (!(FILE_ATTRIBUTE_DIRECTORY & ffdFoundData.dwFileAttributes)) 418: { 419: if (!DoOneFileOrDir(ffdFoundData.cFileName)) 420: return(FALSE); 421: } 422: 423: if (!FindNextFile(hFound, 424: (LPWIN32_FIND_DATA)&ffdFoundData)) 425: if (GetLastError() == ERROR_NO_MORE_FILES) 426: bDoneWithHandle = TRUE; 427: else 428: { PrintAppStyleAPIError(FindNextFile,"on FindNext"); 429: return(FALSE); 430: } 431: } 432: } 433: 434: /****************************************************************************\ 435: * 436: * FUNCTION: DoAllDirsInOneDir 437: * 438: \****************************************************************************/ 439: 440: BOOL DoAllDirsInOneDir(char *FilePattern) 441: { 442: HANDLE hFound; 443: WIN32_FIND_DATA ffdFoundData; 444: BOOL bDoneWithHandle = FALSE; 445: 446: /**************************************************************************\ 447: * 448: * If not recursing into dirs, simply return 449: * 450: \**************************************************************************/ 451: 452: if (!bRecurse) 453: return TRUE; 454: 455: /**************************************************************************\ 456: * 457: * Since we are recursing, get a handle that points to entire directory, and 458: * walk the handle picking off only directories to recurse into 459: * 460: \**************************************************************************/ 461: 462: hFound = FindFirstFile("*.*", 463: (LPWIN32_FIND_DATA)&ffdFoundData); 464: if ((HANDLE)(-1) == hFound) 465: { PrintAppStyleAPIError(FindFirstFile,"on dir *.* FindFirst"); 466: return(FALSE); 467: } 468: 469: while (!bDoneWithHandle) 470: { 471: /************************************************************************\ 472: * 473: * We only do dirs here, and we only do directories with textual names 474: * (i.e., not "." and not "..") 475: * 476: \************************************************************************/ 477: 478: if ( (FILE_ATTRIBUTE_DIRECTORY & ffdFoundData.dwFileAttributes) 479: && (0 != strcmp("." ,ffdFoundData.cFileName)) 480: && (0 != strcmp("..",ffdFoundData.cFileName))) 481: { 482: HANDLE hFile2; 483: WIN32_FIND_DATA ffdFound2; 484: 485: /**********************************************************************\ 486: * 487: * We begin processing the new current directory by processing it itself, 488: * then setting the current dir to be the dir itself 489: * 490: \**********************************************************************/ 491: 492: if (!DoOneFileOrDir(ffdFoundData.cFileName)) 493: return(FALSE); 494: 495: if (!SetCurrentDirectory(ffdFoundData.cFileName)) 496: { PrintAppStyleAPIError(SetCurrentDirectory,"recursive set"); 497: return(FALSE); 498: } 499: 500: /**********************************************************************\ 501: * 502: * It's OK to get no hits. The files-checked counter will show how many 503: * files we looked at, and it's OK to look at 0 504: * 505: \**********************************************************************/ 506: 507: hFile2 = FindFirstFile(FilePattern, 508: (LPWIN32_FIND_DATA)&ffdFound2); 509: if ((HANDLE)(-1) == hFile2) 510: { if (GetLastError() != ERROR_FILE_NOT_FOUND) 511: { PrintAppStyleAPIError(FindFirstFile,"during recursion"); 512: return(FALSE); 513: } 514: } 515: else if (!DoMatchingFilesInOneDir(hFile2,ffdFound2)) 516: return(FALSE); 517: 518: if (!DoAllDirsInOneDir(FilePattern)) 519: return(FALSE); 520: 521: if (!SetCurrentDirectory("..")) 522: { PrintAppStyleAPIError(SetCurrentDirectory,"un-recursive set"); 523: return(FALSE); 524: } 525: } 526: 527: /************************************************************************\ 528: * 529: * Get next recursion candidate (file or dir at this point, however at loop 530: * top files are screened out) 531: * 532: \************************************************************************/ 533: 534: if (!FindNextFile(hFound, 535: (LPWIN32_FIND_DATA)&ffdFoundData)) 536: if (GetLastError() == ERROR_NO_MORE_FILES) 537: bDoneWithHandle = TRUE; 538: else 539: { PrintAppStyleAPIError(FindNextFile,"on dir *.* FindNext"); 540: return(FALSE); 541: } 542: } 543: return(TRUE); 544: } 545: 546: /****************************************************************************\ 547: * 548: * FUNCTION: GetFullFileOrDirName 549: * 550: \****************************************************************************/ 551: 552: BOOL GetFullFileOrDirName(LPTSTR lpszFileName) 553: { 554: UCHAR ucPathBuf[SZ_NAME_BUF]; 555: DWORD dwSzReturned; 556: LPTSTR lpszLastNamePart; 557: LPTSTR lpszFullName; 558: 559: dwSzReturned = GetFullPathName 560: (lpszFileName, 561: (DWORD)SZ_NAME_BUF, 562: (LPTSTR)&ucPathBuf, 563: (LPTSTR *)&lpszLastNamePart); 564: if (0 == dwSzReturned) 565: switch (GetLastError()) 566: { case ERROR_INVALID_NAME : 567: printf("\nError invalid file full-name (on GetFullPathName)"); 568: return(FALSE); 569: default : 570: PERR("GetFullPathName - unexpected return code"); 571: return(FALSE); 572: } 573: 574: if (dwSzReturned > SZ_NAME_BUF) 575: { PERR("GetFullPathName - buffer too small"); 576: return(FALSE); 577: } 578: 579: lpszFullName = CharLower((LPTSTR)&ucPathBuf); 580: 581: if (!lpszFullName) 582: { PERR("CharLower failure"); 583: return(FALSE); 584: } 585: 586: /**************************************************************************\ 587: * 588: * Copy the expanded and upper-case-shifted name to the buffer pointed to by 589: * the input argument 590: * 591: \**************************************************************************/ 592: 593: strcpy(lpszFileName,lpszFullName); 594: } 595: 596: /****************************************************************************\ 597: * 598: * FUNCTION: DoOneFileOrDir 599: * 600: \****************************************************************************/ 601: 602: BOOL DoOneFileOrDir(LPTSTR lpszFullName) 603: { 1.1.1.3 ! root 604: #define SZ_REL_SD_BUF 1000 ! 605: #define SZ_ABS_SD_BUF 500 ! 606: #define SZ_DACL_BUF 500 ! 607: #define SZ_SACL_BUF 500 ! 608: #define SZ_SID_OWN_BUF 500 ! 609: #define SZ_SID_PG_BUF 500 ! 610: UCHAR ucBuf [SZ_REL_SD_BUF]; ! 611: UCHAR ucBufAbs [SZ_ABS_SD_BUF]; ! 612: UCHAR ucBufDacl [SZ_DACL_BUF]; ! 613: UCHAR ucBufSacl [SZ_SACL_BUF]; ! 614: UCHAR ucBufCtrl [sizeof(PSECURITY_DESCRIPTOR_CONTROL)]; ! 615: UCHAR ucBufSidOwn [SZ_SID_OWN_BUF]; ! 616: UCHAR ucBufSidPG [SZ_SID_PG_BUF]; ! 617: DWORD dwSDLength = SZ_REL_SD_BUF; ! 618: DWORD dwDACLLength = SZ_DACL_BUF; ! 619: DWORD dwSACLLength = SZ_SACL_BUF; ! 620: DWORD dwSidOwnLength = SZ_SID_OWN_BUF; ! 621: DWORD dwSidPGLength = SZ_SID_PG_BUF; 1.1 root 622: DWORD dwSDLengthNeeded; 1.1.1.3 ! root 623: PSECURITY_DESCRIPTOR psdSrelFileSD = (PSECURITY_DESCRIPTOR)&ucBuf; ! 624: PSECURITY_DESCRIPTOR psdAbsFileSD = (PSECURITY_DESCRIPTOR)&ucBufAbs; ! 625: PSECURITY_DESCRIPTOR_CONTROL psdcCtrl = (PSECURITY_DESCRIPTOR_CONTROL)&ucBufCtrl; ! 626: PACL paclDacl = (PACL)&ucBufDacl; ! 627: PACL paclSacl = (PACL)&ucBufSacl; ! 628: PSID psidSidOwn = (PSID)&ucBufSidOwn; ! 629: PSID psidSidPG = (PSID)&ucBufSidPG; ! 630: BOOL bDaclPresent; ! 631: BOOL bDaclDefaulted; ! 632: BOOL bSaclPresent; ! 633: BOOL bSaclDefaulted; ! 634: BOOL bOwnerDefaulted; ! 635: BOOL bGroupDefaulted; ! 636: BOOL bSDSelfRelative; ! 637: DWORD dwRevision; 1.1 root 638: 639: if (!GetFullFileOrDirName(lpszFullName)) 640: return(FALSE); 641: 642: /**************************************************************************\ 643: * 644: * Now the input argument's name is accurate: it is expanded and lower-case 645: * 646: \**************************************************************************/ 647: 648: printf("\nChecking %s",lpszFullName); 649: 650: dwFilesChecked++; 651: 652: if (!GetFileSecurity 653: (lpszFullName, 1.1.1.3 ! root 654: (SECURITY_INFORMATION)( OWNER_SECURITY_INFORMATION ! 655: | GROUP_SECURITY_INFORMATION ! 656: | DACL_SECURITY_INFORMATION ! 657: | SACL_SECURITY_INFORMATION), ! 658: psdSrelFileSD, 1.1 root 659: dwSDLength, 660: (LPDWORD)&dwSDLengthNeeded)) 661: { PERR("GetFileSecurity"); 662: return(FALSE); 663: } 664: 665: /**************************************************************************\ 666: * 667: * This validity check is here for demonstration pruposes. It's not likely a 668: * real app would need to check the validity of this returned SD. The 669: * validity check APIs are more intended to check validity after app code 670: * has manipulated the structure and is about to hand it back to the system 671: * 672: \**************************************************************************/ 673: 1.1.1.3 ! root 674: if (!IsValidSecurityDescriptor(psdSrelFileSD)) ! 675: { PERR("IsValidSecurityDescriptor said bad SD"); ! 676: return(FALSE); ! 677: } ! 678: ! 679: /**************************************************************************\ ! 680: * ! 681: * Build File SD in absolute format for potential later modification ! 682: * ! 683: * First Initialize a new SD, which is by definition in absolute format ! 684: * ! 685: * Then Set in the fields from the relative format SD we just fetched ! 686: * ! 687: \**************************************************************************/ ! 688: ! 689: if (!InitializeSecurityDescriptor(psdAbsFileSD, ! 690: SECURITY_DESCRIPTOR_REVISION)) ! 691: { PERR("InitializeSecurityDescriptor"); ! 692: return FALSE; ! 693: } ! 694: ! 695: /**************************************************************************\ ! 696: * ! 697: * Get Control from relative format File SD ! 698: * ! 699: * This control info isn't much queried in the code that follows, as the ! 700: * Get/Set calls are more convienent in this case, but it does give us a ! 701: * change to verify that the SD is in relative format ! 702: * ! 703: \**************************************************************************/ ! 704: ! 705: if (!GetSecurityDescriptorControl(psdSrelFileSD, ! 706: psdcCtrl, ! 707: &dwRevision)) ! 708: { PERR("GetSecurityDescriptorControl"); ! 709: return FALSE; ! 710: } ! 711: ! 712: bSDSelfRelative = (SE_SELF_RELATIVE & *psdcCtrl); ! 713: ! 714: /**************************************************************************\ ! 715: * ! 716: * Set DACL into absolute format File SD ! 717: * ! 718: * Note that it is possible that a NULL DACL has been explictly specified. ! 719: * If so the Get/Set call pair will correctly map that into the absolute ! 720: * format SD ! 721: * ! 722: * The next if statement isn't necessary, it simply shows the relationship ! 723: * between SE_DACL_PRESENT and SE_DACL_DEFAULTED, and lets you trace ! 724: * through with the debugger ! 725: * ! 726: \**************************************************************************/ ! 727: ! 728: if (bDaclPresent = (SE_DACL_PRESENT & *psdcCtrl)) ! 729: { // SE_DACL_DEFAULTED ignored if SE_DACL_PRESENT not set ! 730: bDaclDefaulted = (SE_DACL_DEFAULTED & *psdcCtrl); ! 731: } ! 732: else ! 733: { // No DACL at all ! 734: } ! 735: ! 736: if (!GetSecurityDescriptorDacl(psdSrelFileSD, ! 737: &bDaclPresent, // fDaclPresent flag ! 738: &paclDacl, ! 739: &bDaclDefaulted)) // is/is not a default DACL ! 740: { PERR("GetSecurityDescriptorDacl"); ! 741: return FALSE; ! 742: } ! 743: if (!SetSecurityDescriptorDacl(psdAbsFileSD, ! 744: bDaclPresent, // fDaclPresent flag ! 745: paclDacl, ! 746: bDaclDefaulted)) // is/is not a default DACL ! 747: { PERR("SetSecurityDescriptorDacl"); ! 748: return FALSE; ! 749: } ! 750: ! 751: /**************************************************************************\ ! 752: * ! 753: * Set SACL into absolute format File SD ! 754: * ! 755: * Note that it is possible that a NULL SACL has been explictly specified. ! 756: * If so the Get/Set call pair will correctly map that into the absolute ! 757: * format SD ! 758: * ! 759: * The next if statement isn't necessary, it simply shows the relationship ! 760: * between SE_SACL_PRESENT and SE_SACL_DEFAULTED, and lets you trace ! 761: * through with the debugger ! 762: * ! 763: \**************************************************************************/ ! 764: ! 765: if (bSaclPresent = (SE_SACL_PRESENT & *psdcCtrl)) ! 766: { // SE_SACL_DEFAULTED ignored if SE_SACL_PRESENT not set ! 767: bSaclDefaulted = (SE_SACL_DEFAULTED & *psdcCtrl); ! 768: } ! 769: else ! 770: { // No SACL at all ! 771: } ! 772: ! 773: if (!GetSecurityDescriptorSacl(psdSrelFileSD, ! 774: &bSaclPresent, // fSaclPresent flag ! 775: &paclSacl, ! 776: &bSaclDefaulted)) // is/is not a default SACL ! 777: { PERR("GetSecurityDescriptorSacl"); ! 778: return FALSE; ! 779: } ! 780: if (!SetSecurityDescriptorSacl(psdAbsFileSD, ! 781: bSaclPresent, // fSaclPresent flag ! 782: paclSacl, ! 783: bSaclDefaulted)) // is/is not a default SACL ! 784: { PERR("SetSecurityDescriptorSacl"); ! 785: return FALSE; ! 786: } ! 787: ! 788: /**************************************************************************\ ! 789: * ! 790: * Set Owner into absolute format File SD ! 791: * ! 792: * The next if statement isn't necessary, it simply let's you trace through ! 793: * with the debugger ! 794: * ! 795: \**************************************************************************/ ! 796: ! 797: bOwnerDefaulted = (SE_OWNER_DEFAULTED & *psdcCtrl); ! 798: ! 799: if (!GetSecurityDescriptorOwner(psdSrelFileSD, ! 800: &psidSidOwn, ! 801: &bOwnerDefaulted)) // is/is not a default Owner ! 802: { PERR("GetSecurityDescriptorOwner"); ! 803: return FALSE; ! 804: } ! 805: if (!SetSecurityDescriptorOwner(psdAbsFileSD, ! 806: psidSidOwn, ! 807: bOwnerDefaulted)) // is/is not a default Owner ! 808: { PERR("SetSecurityDescriptorOwner"); ! 809: return FALSE; ! 810: } ! 811: ! 812: /**************************************************************************\ ! 813: * ! 814: * Set Group into absolute format File SD ! 815: * ! 816: * The next if statement isn't necessary, it simply let's you trace through ! 817: * with the debugger ! 818: * ! 819: \**************************************************************************/ ! 820: ! 821: bGroupDefaulted = (SE_GROUP_DEFAULTED & *psdcCtrl); ! 822: ! 823: if (!GetSecurityDescriptorGroup(psdSrelFileSD, ! 824: &psidSidOwn, ! 825: &bGroupDefaulted)) // is/is not a default Group ! 826: { PERR("GetSecurityDescriptorGroup"); ! 827: return FALSE; ! 828: } ! 829: if (!SetSecurityDescriptorGroup(psdAbsFileSD, ! 830: psidSidOwn, ! 831: bGroupDefaulted)) // is/is not a default Group ! 832: { PERR("SetSecurityDescriptorGroup"); ! 833: return FALSE; ! 834: } ! 835: ! 836: /**************************************************************************\ ! 837: * ! 838: * This validity check is here for demonstration pruposes. It's not likely a ! 839: * real app would need to check the validity of the SD after it was just ! 840: * built into absolute format. The validity check APIs are more intended ! 841: * to check validity after app code has manipulated the structure and is ! 842: * about to hand it back to the system ! 843: * ! 844: * One thing to notice is that IsValidSecurityDescriptor will succeed on both ! 845: * self-relative and absolute format SDs. However, some other api's, such ! 846: * as SetSecurityDescriptorOwner, require the SD to be in a certain format, ! 847: * and will give a return code of Invalid SD if the SD passed to the api is ! 848: * valid, but in the wrong format. In other words, when an api such as ! 849: * SetSecurityDescriptorOwner gives the retun code Invalid SD, this doesn't ! 850: * mean the SD passed in was necessarily invalid. It might have been in ! 851: * the wrong format ! 852: * ! 853: \**************************************************************************/ ! 854: ! 855: if (!IsValidSecurityDescriptor(psdAbsFileSD)) 1.1 root 856: { PERR("IsValidSecurityDescriptor said bad SD"); 857: return(FALSE); 858: } 859: 860: if (bTakeOwnership) 1.1.1.3 ! root 861: if (!TakeOwnershipIfAppropriate(psdAbsFileSD,lpszFullName)) 1.1 root 862: return(FALSE); 863: 864: if (bEditACLs) 1.1.1.3 ! root 865: if (!DeleteACEsAsAppropriate (psdAbsFileSD,lpszFullName)) 1.1 root 866: return(FALSE); 867: 868: return(TRUE); 869: } 870: 871: /****************************************************************************\ 872: * 873: * FUNCTION: TakeOwnershipIfAppropriate 874: * 875: \****************************************************************************/ 876: 877: BOOL TakeOwnershipIfAppropriate(PSECURITY_DESCRIPTOR psdFileSD, 878: LPTSTR lpszFullName) 879: { 880: PSID psidFileOwnerSID; 881: { 882: BOOL bOwnerDefaulted; 883: 884: if (!GetSecurityDescriptorOwner 885: (psdFileSD, 886: (PSID *)&psidFileOwnerSID, 887: (LPBOOL)&bOwnerDefaulted)) 888: { PERR("GetSecurityDescriptorOwner"); 889: return(FALSE); 890: } 891: 892: /************************************************************************\ 893: * 894: * This validity check is here for demonstration pruposes. It's not likely 895: * a real app would need to check the validity of this returned SID. The 896: * validity check APIs are more intended to check validity after app code 897: * has manipulated the structure and is about to hand it back to the 898: * system 899: * 900: \************************************************************************/ 901: 902: if (!IsValidSid(psidFileOwnerSID)) 903: { PERR("IsValidSid said bad SID!"); 904: return(FALSE); 905: } 906: } 907: 908: { 909: DWORD dwLastError = NO_ERROR; 910: #define SZ_ACCT_NAME_BUF 1000 911: UCHAR ucNameBuf [SZ_ACCT_NAME_BUF]; 912: DWORD dwNameLength = SZ_ACCT_NAME_BUF; 913: #define SZ_DMN_NAME_BUF 1000 914: UCHAR ucDomainNmBuf [SZ_DMN_NAME_BUF ]; 915: DWORD dwDNameLength = SZ_DMN_NAME_BUF ; 916: SID_NAME_USE peAcctNameUse; 917: 918: if (!LookupAccountSid 919: ((LPTSTR)"", // Look on local machine 920: psidFileOwnerSID, 921: (LPTSTR)&ucNameBuf, 922: (LPDWORD)&dwNameLength, 923: (LPTSTR)&ucDomainNmBuf, 924: (LPDWORD)&dwDNameLength, 925: (PSID_NAME_USE)&peAcctNameUse)) 926: { dwLastError = GetLastError(); 927: if (ERROR_NONE_MAPPED != dwLastError) 928: { PERR("LookupAccountSID"); 929: return(FALSE); 930: } 931: } 932: 933: /************************************************************************\ 934: * 935: * If deleted account, take ownership. This routine's caller checked the 936: * global switches that said we are in take ownership mode 937: * 938: * In some cases, the account lookup will fail with ERROR_NONE_MAPPED, 939: * meaning there is no deleted account mapped to the SID, in which case 940: * we also take ownership 941: * 942: * We check that first to avoid referencing peAcctNameUse, which in that 943: * case is not set 944: * 945: \************************************************************************/ 946: 947: if ( (ERROR_NONE_MAPPED == dwLastError) 948: || (SidTypeDeletedAccount == peAcctNameUse)) 949: { 950: dwFilesOwned++; 951: 952: if (bJustCount) 953: { printf(" - would have taken ownership"); 954: return(TRUE); 955: } 956: else 957: { 958: /********************************************************************\ 959: * 960: * Modify the SD in virtual memory. No check on the new owning SID 961: * here, because we validity checked it when we fetched it in 962: * GetProcessSid 963: * 964: \********************************************************************/ 965: 966: if (!SetSecurityDescriptorOwner 967: (psdFileSD, 968: psidProcessOwnerSID, 969: FALSE)) // New owner explicitly specified 970: { PERR("SetSecurityDescriptorOwner"); 971: return(FALSE); 972: } 973: 974: /********************************************************************\ 975: * 976: * This validity check is something a real app might actually like to 977: * do. We manupulated the SD, so before we write it back out to the 978: * file system, a check is worth considering. 979: * 980: \********************************************************************/ 981: 982: if (!IsValidSecurityDescriptor(psdFileSD)) 983: { PERR("IsValidSecurityDescriptor said bad SD"); 984: return(FALSE); 985: } 986: 987: /********************************************************************\ 988: * 989: * Modify the SD on the hard disk 990: * 991: \********************************************************************/ 992: 993: if (!SetFileSecurity 994: (lpszFullName, 995: (SECURITY_INFORMATION)OWNER_SECURITY_INFORMATION, 996: psdFileSD)) 997: { PERR("SetFileSecurity"); 998: return(FALSE); 999: } 1000: 1001: printf(" - took ownership"); 1002: } 1003: } 1004: } 1005: 1006: return(TRUE); 1007: 1008: } 1009: 1010: /****************************************************************************\ 1011: * 1012: * FUNCTION: DeleteACEsAsAppropriate 1013: * 1014: \****************************************************************************/ 1015: 1016: BOOL DeleteACEsAsAppropriate(PSECURITY_DESCRIPTOR psdFileSD, 1017: LPTSTR lpszFullName) 1018: { 1019: PACL paclFile; 1020: BOOL bHasACL; 1021: BOOL bOwnerDefaulted; 1022: DWORD dwAcl_i; 1023: DWORD dwACEsDeletedBeforeNow; 1024: 1025: ACL_SIZE_INFORMATION asiAclSize; 1026: DWORD dwBufLength = sizeof(asiAclSize); 1027: ACCESS_ALLOWED_ACE *paaAllowedAce; 1028: 1029: if (!GetSecurityDescriptorDacl(psdFileSD, 1030: (LPBOOL)&bHasACL, 1031: (PACL *)&paclFile, 1032: (LPBOOL)&bOwnerDefaulted)) 1033: { PERR("GetSecurityDescriptorDacl"); 1034: return(FALSE); 1035: } 1036: 1037: if (!bHasACL) // No ACL to process, so OK, return 1038: return(TRUE); 1039: 1040: /**************************************************************************\ 1041: * 1042: * This validity check is here for demonstration pruposes. It's not likely a 1043: * real app would need to check the validity of this returned ACL. The 1044: * validity check APIs are more intended to check validity after app code 1045: * has manipulated the structure and is about to hand it back to the system 1046: * 1047: \**************************************************************************/ 1048: 1049: if (!IsValidAcl(paclFile)) 1050: { PERR("IsValidAcl said bad ACL!"); 1051: return(FALSE); 1052: } 1053: 1054: if (!GetAclInformation(paclFile, 1055: (LPVOID)&asiAclSize, 1056: (DWORD)dwBufLength, 1057: (ACL_INFORMATION_CLASS)AclSizeInformation)) 1058: { PERR("GetAclInformation"); 1059: return(FALSE); 1060: } 1061: 1062: dwACEsDeletedBeforeNow = dwACEsDeleted; 1063: 1064: /**************************************************************************\ 1065: * 1066: * We loop through in reverse order, because that's simpler, given that we 1067: * potentially delete ACEs as we loop through. If started at 0 and went 1068: * up, if we deleted the 0th ACE, then the 1th ACE would become the 0th, 1069: * and we'd have to check the 0th ACE again 1070: * 1071: \**************************************************************************/ 1072: 1073: for (dwAcl_i = asiAclSize.AceCount-1; ((int)dwAcl_i) >= 0; dwAcl_i--) 1074: { 1075: /************************************************************************\ 1076: * 1077: * It doesn't matter for this sample that we don't yet know the ACE type, 1078: * because they all start with the header field and that's what we need 1079: * 1080: \************************************************************************/ 1081: 1082: if (!GetAce(paclFile, 1083: dwAcl_i, 1084: (LPVOID *)&paaAllowedAce)) 1085: { PERR("GetAce"); 1086: return(FALSE); 1087: } 1088: 1089: /************************************************************************\ 1090: * 1091: * There are only four Ace Types pre-defined, so this next check is 1092: * redundant in a real app, but useful as a sanity check and a 1093: * demonstration in a sample 1094: * 1095: \************************************************************************/ 1096: 1097: if (!( (paaAllowedAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 1098: ||(paaAllowedAce->Header.AceType == ACCESS_DENIED_ACE_TYPE ) 1099: ||(paaAllowedAce->Header.AceType == SYSTEM_AUDIT_ACE_TYPE ) 1100: ||(paaAllowedAce->Header.AceType == SYSTEM_ALARM_ACE_TYPE ))) 1101: { PERR("Invalid AceType"); 1102: return(FALSE); 1103: } 1104: 1105: { // Find SID of ACE, check if acct deleted 1106: 1107: UCHAR ucNameBuf [SZ_ACCT_NAME_BUF]; 1108: DWORD dwNameLength = SZ_ACCT_NAME_BUF; 1109: UCHAR ucDomainNmBuf [SZ_DMN_NAME_BUF]; 1110: DWORD dwDNameLength = SZ_DMN_NAME_BUF; 1111: SID_NAME_USE peAcctNameUse; 1112: DWORD dwLastError = NO_ERROR; 1113: 1114: /**********************************************************************\ 1115: * 1116: * This validity check is here for demonstration pruposes. It's not 1117: * likely a real app would need to check the validity of the SID 1118: * contained in the returned ACL. The validity check APIs are more 1119: * intended to check validity after app code has manipulated the 1120: * structure and is about to hand it back to the system 1121: * 1122: \**********************************************************************/ 1123: 1124: if (!IsValidSid((PSID)&(paaAllowedAce->SidStart))) 1.1.1.2 root 1125: { PERR("IsValidSid said bad SID!"); 1126: return(FALSE); 1127: } 1.1 root 1128: 1129: if (!LookupAccountSid 1130: ((LPTSTR)"", // Look on local machine 1131: (PSID)&(paaAllowedAce->SidStart), 1132: (LPTSTR)&ucNameBuf, 1133: (LPDWORD)&dwNameLength, 1134: (LPTSTR)&ucDomainNmBuf, 1135: (LPDWORD)&dwDNameLength, 1136: (PSID_NAME_USE)&peAcctNameUse)) 1137: { dwLastError = GetLastError(); 1138: if (ERROR_NONE_MAPPED != dwLastError) 1139: { PERR("LookupAccountSID"); 1140: return(FALSE); 1141: } 1142: } 1143: 1144: if ( (ERROR_NONE_MAPPED == dwLastError) 1145: || (SidTypeDeletedAccount == peAcctNameUse)) 1146: { 1147: dwACEsDeleted++; 1148: 1149: if (bJustCount) 1150: { printf(" - would have edited ACL"); 1151: return(TRUE); 1152: } 1153: 1154: if (!DeleteAce(paclFile,dwAcl_i)) 1155: { PERR("DeleteAce"); 1156: return(FALSE); 1157: } 1158: } 1159: } 1160: } 1161: 1162: if (dwACEsDeletedBeforeNow < dwACEsDeleted) 1163: { 1164: /************************************************************************\ 1165: * 1166: * This validity check is something a real app might actually like to do. 1167: * We manupulated the ACL, so before we write it back into an SD, a check 1168: * is worth considering 1169: * 1170: \************************************************************************/ 1171: 1172: if (!IsValidAcl(paclFile)) 1173: { PERR("IsValidAcl said bad ACL!"); 1174: return(FALSE); 1175: } 1176: 1177: /************************************************************************\ 1178: * 1179: * Modify the SD in virtual memory 1180: * 1181: \************************************************************************/ 1182: 1183: if (!SetSecurityDescriptorDacl 1184: (psdFileSD, 1185: TRUE, // Yes, set the DACL 1186: paclFile, 1187: FALSE)) // New DACL explicitly specified 1188: { PERR("SetSecurityDescriptorDacl"); 1189: return(FALSE); 1190: } 1191: 1192: /************************************************************************\ 1193: * 1194: * This validity check is something a real app might actually like to do. 1195: * We manupulated the SD, so before we write it back out to the file 1196: * system, a check is worth considering 1197: * 1198: \************************************************************************/ 1199: 1200: if (!IsValidSecurityDescriptor(psdFileSD)) 1201: { PERR("IsValidSecurityDescriptor said bad SD"); 1202: return(FALSE); 1203: } 1204: 1205: /************************************************************************\ 1206: * 1207: * Modify the SD on the hard disk 1208: * 1209: \************************************************************************/ 1210: 1211: if (!SetFileSecurity 1212: (lpszFullName, 1213: (SECURITY_INFORMATION)DACL_SECURITY_INFORMATION, 1214: psdFileSD)) 1215: { PERR("SetFileSecurity"); 1216: return(FALSE); 1217: } 1218: 1219: printf(" - edited ACL"); 1220: } 1221: 1222: return(TRUE); 1223: 1224: } 1225: 1226: /****************************************************************************\ 1227: * 1228: * FUNCTION: GetProcessSid 1229: * 1230: \****************************************************************************/ 1231: 1232: BOOL GetProcessSid(VOID) 1233: { 1234: HANDLE hProcess; 1235: PSECURITY_DESCRIPTOR psdProcessSD; 1236: PSID psidProcessOwnerSIDTemp; 1237: 1.1.1.3 ! root 1238: UCHAR ucBuf [SZ_REL_SD_BUF]; ! 1239: DWORD dwSDLength = SZ_REL_SD_BUF; 1.1 root 1240: DWORD dwSDLengthNeeded; 1241: BOOL bOwnerDefaulted; 1242: 1243: hProcess = GetCurrentProcess(); 1244: 1245: if (!hProcess) 1.1.1.2 root 1246: { PERR("GetCurrentProcess"); 1247: return(FALSE); 1248: } 1.1 root 1249: 1250: psdProcessSD = (PSECURITY_DESCRIPTOR)ucBuf; 1251: 1252: if (!GetKernelObjectSecurity 1253: (hProcess, 1254: (SECURITY_INFORMATION)(OWNER_SECURITY_INFORMATION), 1255: psdProcessSD, 1256: dwSDLength, 1257: (LPDWORD)&dwSDLengthNeeded)) 1.1.1.2 root 1258: { PERR("GetKernelObjectSecurity on current process handle"); 1259: return(FALSE); 1260: } 1.1 root 1261: 1262: /**************************************************************************\ 1263: * 1264: * This validity check is here for demonstration purposes. It's not likely a 1265: * real app would need to check the validity of this returned SD. The 1266: * validity check APIs are more intended to check validity after app code 1267: * has manipulated the structure and is about to hand it back to the system 1268: * 1269: \**************************************************************************/ 1270: 1271: if (!IsValidSecurityDescriptor(psdProcessSD)) 1272: { PERR("IsValidSecurityDescriptor said bad SD"); 1273: return(FALSE); 1274: } 1275: 1276: if (!GetSecurityDescriptorOwner 1277: (psdProcessSD, 1278: (PSID *)&psidProcessOwnerSIDTemp, 1279: (LPBOOL)&bOwnerDefaulted)) 1.1.1.2 root 1280: { PERR("GetSecurityDescriptorOwner of current process"); 1281: return(FALSE); 1282: } 1.1 root 1283: 1284: /**************************************************************************\ 1285: * 1286: * This validity check is here for demonstration pruposes. It's not likely a 1287: * real app would need to check the validity of this returned SID. The 1288: * validity check APIs are more intended to check validity after app code 1289: * has manipulated the structure and is about to hand it back to the system 1290: * 1291: \**************************************************************************/ 1292: 1293: if (!IsValidSid(psidProcessOwnerSIDTemp)) 1.1.1.2 root 1294: { PERR("IsValidSid said bad process SID!"); 1295: return(FALSE); 1296: } 1.1 root 1297: 1298: /**************************************************************************\ 1299: * 1300: * On the other hand, we are about to call GetLengthSid on the returned SID, 1301: * and calling GetLengthSid with an invalid SID is a bad idea, since then 1302: * GetLengthSid's result is undefined, and an undefined result is hard to 1.1.1.2 root 1303: * handle cleanly. So, even in a real app, the above check on SID validity 1304: * is a good idea to ensure the result GetLengthSid returns is valid 1.1 root 1305: * 1.1.1.2 root 1306: * It should be clear that the reason why the CopySid below is needed is that 1307: * in the current routine the SID of the current process is on the stack 1308: * (in the SD structure), so we have to copy the SID to static storage 1309: * before the current routine returns 1.1 root 1310: * 1311: \**************************************************************************/ 1312: 1.1.1.2 root 1313: { DWORD dwSIDLengthNeeded; 1314: 1315: dwSIDLengthNeeded = GetLengthSid(psidProcessOwnerSIDTemp); 1.1 root 1316: 1.1.1.2 root 1317: psidProcessOwnerSID = malloc(dwSIDLengthNeeded); 1318: 1319: if (NULL == psidProcessOwnerSID) 1320: PERR("GetProcessSid - ran out of heap space"); 1321: 1322: if (!CopySid(dwSIDLengthNeeded, 1323: psidProcessOwnerSID, 1324: psidProcessOwnerSIDTemp)) 1.1 root 1325: { PERR("CopySid"); 1326: return(FALSE); 1327: } 1.1.1.2 root 1328: } 1329: 1.1 root 1330: 1331: /**************************************************************************\ 1332: * 1333: * This validity check is here for demonstration pruposes only (see above). 1334: * 1335: \**************************************************************************/ 1336: 1337: if (!IsValidSid(psidProcessOwnerSID)) 1.1.1.2 root 1338: { PERR("IsValidSid said bad process SID!"); 1339: return(FALSE); 1340: } 1.1.1.3 ! root 1341: ! 1342: ! 1343: /**************************************************************************\ ! 1344: * ! 1345: * Now ensure that two privileges are enabled in the access token of the ! 1346: * current process ! 1347: * ! 1348: \**************************************************************************/ ! 1349: ! 1350: { HANDLE hAccessToken; ! 1351: LUID luidPrivilegeLUID; ! 1352: TOKEN_PRIVILEGES tpTokenPrivilege; ! 1353: ! 1354: if (!OpenProcessToken(hProcess, ! 1355: TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ! 1356: &hAccessToken)) ! 1357: { PERR("OpenProcessToken"); ! 1358: return(FALSE); ! 1359: } ! 1360: ! 1361: /************************************************************************\ ! 1362: * ! 1363: * Get LUID of SeTakeOwnershipPrivilege privilege ! 1364: * ! 1365: \************************************************************************/ ! 1366: ! 1367: if (!LookupPrivilegeValue(NULL, ! 1368: "SeTakeOwnershipPrivilege", ! 1369: &luidPrivilegeLUID)) ! 1370: { PERR("LookupPrivilegeValue"); ! 1371: printf("\nThe above error means you need to use User Manager (menu item"); ! 1372: printf("\n Policies\\UserRights) to turn on the 'Take ownership of...' "); ! 1373: printf("\n privilege, log off, log back on"); ! 1374: return(FALSE); ! 1375: } ! 1376: ! 1377: /************************************************************************\ ! 1378: * ! 1379: * Enable the SeTakeOwnershipPrivilege privilege using the LUID just ! 1380: * obtained ! 1381: * ! 1382: \************************************************************************/ ! 1383: ! 1384: tpTokenPrivilege.PrivilegeCount = 1; ! 1385: tpTokenPrivilege.Privileges[0].Luid = luidPrivilegeLUID; ! 1386: tpTokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; ! 1387: ! 1388: AdjustTokenPrivileges (hAccessToken, ! 1389: FALSE, // Do not disable all ! 1390: &tpTokenPrivilege, ! 1391: sizeof(TOKEN_PRIVILEGES), ! 1392: NULL, // Ignore previous info ! 1393: NULL); // Ignore previous info ! 1394: ! 1395: if ( GetLastError() != NO_ERROR ) ! 1396: { PERR("AdjustTokenPrivileges"); ! 1397: return(FALSE); ! 1398: } ! 1399: ! 1400: /************************************************************************\ ! 1401: * ! 1402: * Get LUID of SeSecurityPrivilege privilege ! 1403: * ! 1404: \************************************************************************/ ! 1405: ! 1406: if (!LookupPrivilegeValue(NULL, ! 1407: "SeSecurityPrivilege", ! 1408: &luidPrivilegeLUID)) ! 1409: { PERR("LookupPrivilegeValue"); ! 1410: printf("\nThe above error means you need to log on as an Administrator"); ! 1411: return(FALSE); ! 1412: } ! 1413: ! 1414: /************************************************************************\ ! 1415: * ! 1416: * Enable the SeSecurityPrivilege privilege using the LUID just ! 1417: * obtained ! 1418: * ! 1419: \************************************************************************/ ! 1420: ! 1421: tpTokenPrivilege.PrivilegeCount = 1; ! 1422: tpTokenPrivilege.Privileges[0].Luid = luidPrivilegeLUID; ! 1423: tpTokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; ! 1424: ! 1425: AdjustTokenPrivileges (hAccessToken, ! 1426: FALSE, // Do not disable all ! 1427: &tpTokenPrivilege, ! 1428: sizeof(TOKEN_PRIVILEGES), ! 1429: NULL, // Ignore previous info ! 1430: NULL); // Ignore previous info ! 1431: ! 1432: if ( GetLastError() != NO_ERROR ) ! 1433: { PERR("AdjustTokenPrivileges"); ! 1434: return(FALSE); ! 1435: } ! 1436: ! 1437: } ! 1438: ! 1439: return(TRUE); ! 1440: 1.1 root 1441: } 1442: 1443: /****************************************************************************\ 1444: * 1445: * FUNCTION: CrackArgs 1446: * 1447: \****************************************************************************/ 1448: 1449: BOOL CrackArgs(UINT argc, char *argv[]) 1450: { 1451: char *p; 1452: 1453: /**************************************************************************\ 1454: * 1455: * There must be three arguments 1456: * 1457: \**************************************************************************/ 1458: 1459: if (argc != 4) 1460: { DisplayHelp(); 1461: return(FALSE); 1462: } 1463: 1464: p=argv[1]; 1465: 1466: /**************************************************************************\ 1467: * 1468: * The switch argument must be 2-5 chars long 1469: * 1470: \**************************************************************************/ 1471: 1472: if ((strlen(p) < 2) || (strlen(p) > 5)) 1473: { DisplayHelp(); 1474: return(FALSE); 1475: } 1476: 1477: /**************************************************************************\ 1478: * 1479: * The first char in the switch argument must be / 1480: * 1481: \**************************************************************************/ 1482: 1483: if ('/' != *p) 1484: { DisplayHelp(); 1485: return(FALSE); 1486: } 1487: 1488: /**************************************************************************\ 1489: * 1490: * Chars 2-5 of the switch argument must be O or A or R or C 1491: * 1492: \**************************************************************************/ 1493: 1494: for (p=p+1; *p; p++) 1495: switch (*p) 1496: { case 'o': 1497: case 'O': 1498: bTakeOwnership = TRUE; 1499: break; 1500: case 'a': 1501: case 'A': 1502: bEditACLs = TRUE; 1503: break; 1504: case 'r': 1505: case 'R': 1506: bRecurse = TRUE; 1507: break; 1508: case 'c': 1509: case 'C': 1510: bJustCount = TRUE; 1511: break; 1512: default : 1513: DisplayHelp(); 1514: return(FALSE); 1515: } 1516: 1517: /**************************************************************************\ 1518: * 1519: * Have to say one of O or A 1520: * 1521: \**************************************************************************/ 1522: 1523: if (!(bTakeOwnership || bEditACLs)) 1524: { DisplayHelp(); 1525: return(FALSE); 1526: } 1527: 1528: return(TRUE); 1529: } 1530: 1531: /****************************************************************************\ 1532: * 1533: * FUNCTION: DisplayHelp 1534: * 1535: \****************************************************************************/ 1536: 1537: VOID DisplayHelp(VOID) 1538: { 1539: printf("\nTo run type SIDCLEAN and 3 parameters. Syntax:"); 1540: printf("\n SIDCLEAN /roah dirspec filepattern"); 1541: printf("\n /r Recursively process subdirectories"); 1542: printf("\n /o For any files matching filepattern: Take ownership if"); 1543: printf("\n file currently owned by any deleted SID"); 1544: printf("\n /a For any files matching filepattern: Edit ACL, deleting"); 1545: printf("\n ACEs associated with any deleted SID"); 1546: printf("\n /c Overrides /o and /a, causes counts of /a or /o actions that"); 1547: printf("\n would take place if /c not used. Counts always displayed"); 1548: printf("\n /h Override other switch values, just display this message\n"); 1549: printf("\n . and .. syntax allowed in dirspec"); 1550: printf("\n * and ? wildcards allowed in filepattern"); 1551: printf("\n Switch letters can be in any order, upper or lower case"); 1552: printf("\nExamples:"); 1553: printf("\n SIDCLEAN /o . *.* Take ownership of all files (but not subdirs) in "); 1554: printf("\n current dir that are owned by any deleted SID"); 1555: printf("\n SIDCLEAN /a . *.* For any file in current dir (but not subdirs), delete"); 1556: printf("\n any ACL info that is associated with any deleted SID"); 1557: printf("\n SIDCLEAN /ro . *.* Same as first example, but also recursively process"); 1558: printf("\n subdirectories"); 1559: printf("\n SIDCLEAN /ar . *.* Same as second example, but also recursively process"); 1560: printf("\n subdirectories"); 1561: printf("\n SIDCLEAN /O \\ *.* Same as first example, but process files in root"); 1562: printf("\n of current drive"); 1563: printf("\n SIDCLEAN /oC .. *.* Same as first example, but looks at files in dir"); 1564: printf("\n containing current dir, processes nothing, just counts"); 1565: printf("\n SIDCLEAN /A d:\\ *.* Same as second example, but process files in root"); 1566: printf("\n of D: drive"); 1567: printf("\n SIDCLEAN Displays this message"); 1568: printf("\n SIDCLEAN /h Displays this message (so do ? -? /? -h -H /H)\n"); 1569: printf("\nThis utility must be run while logged on as Administrator\n"); 1570: 1571: return; 1572: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.