Annotation of mstools/samples/sidcln/sidclean.c, revision 1.1

1.1     ! root        1: /****************************************************************************\
        !             2: *
        !             3: * MODULE:       sidclean.c
        !             4: *
        !             5: *               NT never deletes SIDs, so the name of this sample is most
        !             6: *                 accurately be intrepreted as "Clean up SID ownership and
        !             7: *                 ACE's that relate to SIDs that still (and always will)
        !             8: *                 exist, but for which the corresponding user account has been
        !             9: *                 deleted"
        !            10: *
        !            11: *
        !            12: * PURPOSE:      Demonstrate some of the Win32 security api(s), and provide a
        !            13: *                 sample of how a utility could be written that recovers
        !            14: *                 on-disk resources remaining allocated to deleted user
        !            15: *                 accounts.  The on-disk resources recovered are 1) Files that
        !            16: *                 are still owned by accounts that have been deleted are
        !            17: *                 assigned ownership to the account logged on when this sample
        !            18: *                 is run, and 2) ACE's for deleted accounts are edited
        !            19: *                 (deleted) out of the ACLs of files to which the deleted
        !            20: *                 accounts had been granted authorizations (eg., Read access)
        !            21: *
        !            22: *               It may be that running this sample as a utility has no
        !            23: *                 practical value in many environments, as the number of files
        !            24: *                 belonging to deleted user accounts will often be quite
        !            25: *                 small, and the number of bytes recovered on disk by editing
        !            26: *                 out ACEs for deleted accounts may well not be worth the time
        !            27: *                 it takes to run this sample.  The time it takes to run this
        !            28: *                 sample may be quite significant when processing an entire
        !            29: *                 hard disk or partition
        !            30: *
        !            31: *               This sample is not a supported utility
        !            32: *
        !            33: *
        !            34: * TO RUN:       You must log on using an account, such as Administrator, that
        !            35: *                 has the priviledges to take file ownership and edit ACls
        !            36: *
        !            37: *               The ACL editing part of this sample can only be excercised for
        !            38: *                 files on a partition that has ACLs NT processes:  NTFS
        !            39: *
        !            40: *               Typical test scenario:  Create a user account or two, log on
        !            41: *                 as each of these accounts in turn, while logged on for each
        !            42: *                 account, go to an NTFS partition, create a couple of files
        !            43: *                 so the test accounts each own a few files, use the file
        !            44: *                 manager to edit permissions for those files so that each
        !            45: *                 test user has some authorities (e.g., Read) explicitly
        !            46: *                 granted for those files.  Logon as Administrator, authorize
        !            47: *                 each test user to a few Administrator-owned files.  Delete
        !            48: *                 the test accounts.  Run the sample in the directories where
        !            49: *                 you put the files the test accounts owned or were authorized
        !            50: *                 to
        !            51: *
        !            52: *
        !            53: * OVERALL APPROACH: The command line interface is kept inflexible to simplify
        !            54: *                 it's parsing in this sample.  The user must pass in a switch
        !            55: *                 argument, a directory spec, and a file search pattern
        !            56: *
        !            57: *               The sample positions the current directory (of the process the
        !            58: *                 sample runs in) to the dir spec, and uses FindFirstFile and
        !            59: *                 FindNextFile to walk through the directory specified looking
        !            60: *                 for files that match the file pattern specified
        !            61: *
        !            62: *               The switch argument can cause subdirectories to be searched
        !            63: *                 recursively
        !            64: *
        !            65: *               The switch argument lets the user choose only to take
        !            66: *                 ownerships, only to edit ACLs, do both, or do neither, in
        !            67: *                 which case the sample merely reports on what ownerships
        !            68: *                 would have been taken, and what ACE's would have been
        !            69: *                 deleted
        !            70: *
        !            71: *               As the directories are walked, each file that matches the
        !            72: *                 file pattern is processed right then
        !            73: *
        !            74: *               Note that we process files in a directory, and we also process
        !            75: *                 the directory itself that contains the files.  We process
        !            76: *                 directories because they can also be owned by deleted
        !            77: *                 accounts, or could have ACEs that will no longer be used
        !            78: *
        !            79: *               Note also that we process all directories that we check for
        !            80: *                 files, regardless of the spelling of the directory name
        !            81: *
        !            82: *               Counters are kept of file ownerships taken, ACEs deleted and
        !            83: *                 total files checked, to print a summary line at the end of
        !            84: *                 the run
        !            85: *
        !            86: *               The sample considers it perfectly acceptable if 0 files match
        !            87: *                 the file pattern for the entire run
        !            88: *
        !            89: *
        !            90: * FUNCTIONS:  DoMatchingFilesInOneDir
        !            91: *
        !            92: *               Look in one dir or sub-dir for files that match the file
        !            93: *                 pattern.  For each match call DoOneFileOrDir
        !            94: *
        !            95: *             DoAllDirsInOneDir
        !            96: *
        !            97: *               For all the sub-dirs in a dir, set the current directory to be
        !            98: *                 that directory, check for files that match the file pattern,
        !            99: *                 and if any match, call DoMatchingFilesInOneDir to process
        !           100: *                 those.  Then reset the current directory
        !           101: *
        !           102: *             GetFullFileOrDirName
        !           103: *
        !           104: *               Get the full name of the file or dir for simplified processing
        !           105: *                 (and for display on the console)
        !           106: *
        !           107: *             DoOneFileOrDir
        !           108: *
        !           109: *               Get the file's SD (Security Descriptor), and call
        !           110: *                 TakeOwnershipIfAppropriate and/or DeleteACEsAsAppropriate as
        !           111: *                 needed
        !           112: *
        !           113: *             TakeOwnershipIfAppropriate
        !           114: *
        !           115: *               Get the owning SID of the file from the file's SD that
        !           116: *                 DoOneFileOrDir passed in, check that SID to see if the
        !           117: *                 account is deleted.  If so, edit into the file's SD a new
        !           118: *                 owning SID (the SID of the process running the sample).
        !           119: *                 Then write the modified file SD to disk
        !           120: *
        !           121: *             DeleteACEsAsAppropriate
        !           122: *
        !           123: *               Get the DACL of the file from the file's SD that
        !           124: *                 DoOneFileOrDir passed in.  Walk through the ACE list for
        !           125: *                 that DACL, checking each ACE to see what SID the ACE refers
        !           126: *                 to.  For the SID referred to, check to see if the account is
        !           127: *                 deleted.  If so, delete that ACE from the DACL.  When all
        !           128: *                 ACE's have been examined, write the new DACL into the file's
        !           129: *                 SD.  Then write the modified file SD to disk
        !           130: *
        !           131: *             GetProcessSid
        !           132: *
        !           133: *               Retrieve into a global variable the SID of the user account
        !           134: *                 logged on when this sample is run.  This is the SID used by
        !           135: *                 TakeOwnershipIfAppropriate
        !           136: *
        !           137: *             CrackArgs
        !           138: *
        !           139: *               Process the command line, cracking (parsing/decoding) the
        !           140: *                 switch argument into boolean global variables (see below).
        !           141: *                 Call DisplayHelp if anything illegal is found in the command
        !           142: *                 line, or if the user asked for help
        !           143: *
        !           144: *             DisplayHelp
        !           145: *
        !           146: *               Display help text on the console
        !           147: *
        !           148: *
        !           149: * GLOBAL VARS:
        !           150: *             BOOL  bTakeOwnership
        !           151: *             BOOL  bEditACLs
        !           152: *             BOOL  bRecurse
        !           153: *             BOOL  bJustCount
        !           154: *
        !           155: *               These store the values the user specified on the command
        !           156: *                 line's first argument (the switches argument).
        !           157: *                 Respectively, they record whether we are to do the
        !           158: *                 processing to Take Ownerships, Edit ACLs, whether we are to
        !           159: *                 recurse into all subdirectories, and whether we are just
        !           160: *                 counting up what would be processed (in which case we take
        !           161: *                 no ownerships and edit no ACLs)
        !           162: *
        !           163: *             DWORD dwFilesChecked
        !           164: *             DWORD dwFilesOwned
        !           165: *             DWORD dwACEsDeleted
        !           166: *
        !           167: *               These count, respecively, the total files we checked, the
        !           168: *                 number of files we took ownership of (or would have if we
        !           169: *                 had not been told only to count), and the number of ACEs we
        !           170: *                 deleted (or would have if we had not been told only to
        !           171: *                 count).  Note that the total number of files checked does
        !           172: *                 not include files in the directories we process that do not
        !           173: *                 match the file pattern
        !           174: *
        !           175: *               Note, however, that we process directories regardless of
        !           176: *                 whether they match the file pattern
        !           177: *
        !           178: *             UCHAR ucProcessSIDBuf
        !           179: *             PSID  psidProcessOwnerSID
        !           180: *
        !           181: *               These store the SID of the account logged on as this sample
        !           182: *                 runs, and a pointer to that SID
        !           183: *
        !           184: \****************************************************************************/
        !           185: 
        !           186: 
        !           187: /****************************************************************************\
        !           188: *  INCLUDES, DEFINES, TYPEDEFS
        !           189: \****************************************************************************/
        !           190: #include <windows.h>
        !           191: #include <stdio.h>
        !           192: #include <string.h>
        !           193: 
        !           194: #define PERR(api) printf("%s: Error %d from %s on line %d\n",  \
        !           195:     __FILE__, GetLastError(), api, __LINE__);
        !           196: #define PMSG(msg) printf("%s line %d: %s\n",  \
        !           197:     __FILE__, __LINE__, msg);
        !           198: 
        !           199: #define PrintAppStyleAPIError(ApiTxt,MsgTxt) {                     \
        !           200:   DWORD dwLastError;                                               \
        !           201:   dwLastError = GetLastError();                                    \
        !           202:   switch (dwLastError)                                             \
        !           203:   { case ERROR_FILE_NOT_FOUND :                                    \
        !           204:       printf("\nFile not found (%s) line %d",MsgTxt,__LINE__);     \
        !           205:       break;                                                       \
        !           206:     case ERROR_INVALID_NAME   :                                    \
        !           207:       printf("\nInvalid name (%s) line %d",MsgTxt,__LINE__);       \
        !           208:       break;                                                       \
        !           209:     case ERROR_PATH_NOT_FOUND :                                    \
        !           210:       printf("\nError path not found (%s) line %d",MsgTxt,__LINE__); \
        !           211:       break;                                                       \
        !           212:     case ERROR_SHARING_VIOLATION :                                 \
        !           213:       printf("\nSharing violation - shut down net and/or stop other sessions (%s) line %d",MsgTxt,__LINE__); \
        !           214:       break;                                                       \
        !           215:     case ERROR_ACCESS_DENIED  :                                    \
        !           216:       printf("\nAccess denied (%s) line %d",MsgTxt,__LINE__);      \
        !           217:       break;                                                       \
        !           218:     default                   :                                    \
        !           219:       printf("\n" #ApiTxt " - unexpected return code=%d (%s) line %d",dwLastError,MsgTxt,__LINE__); \
        !           220:       break;                                                       \
        !           221:   }                                                                \
        !           222:   }
        !           223: 
        !           224: /****************************************************************************\
        !           225: * GLOBAL VARIABLES
        !           226: \****************************************************************************/
        !           227: 
        !           228: BOOL  bTakeOwnership  = FALSE;
        !           229: BOOL  bEditACLs       = FALSE;
        !           230: BOOL  bRecurse        = FALSE;
        !           231: BOOL  bJustCount      = FALSE;
        !           232: 
        !           233: DWORD dwFilesChecked  = 0;
        !           234: DWORD dwFilesOwned    = 0;
        !           235: DWORD dwACEsDeleted   = 0;
        !           236: 
        !           237: #define                                      SZ_PROCESS_SID_BUF  16
        !           238: UCHAR                        ucProcessSIDBuf[SZ_PROCESS_SID_BUF];
        !           239: PSID  psidProcessOwnerSID = &ucProcessSIDBuf;
        !           240:            //  Why we allocate 16 bytes is explained in GetProcessSid
        !           241: 
        !           242: 
        !           243: /****************************************************************************\
        !           244: * FUNCTION PROTOTYPES
        !           245: \****************************************************************************/
        !           246: 
        !           247: BOOL DoMatchingFilesInOneDir(HANDLE          hFound,
        !           248:                              WIN32_FIND_DATA ffdFoundData);
        !           249: BOOL DoAllDirsInOneDir(char *FilePattern);
        !           250: BOOL GetFullFileOrDirName(LPTSTR lpszFileName);
        !           251: BOOL DoOneFileOrDir(LPTSTR lpszFullName);
        !           252: BOOL TakeOwnershipIfAppropriate(PSECURITY_DESCRIPTOR psdFileSD,
        !           253:                                 LPTSTR  lpszFullName);
        !           254: BOOL DeleteACEsAsAppropriate   (PSECURITY_DESCRIPTOR psdFileSD,
        !           255:                                 LPTSTR  lpszFullName);
        !           256: BOOL GetProcessSid(VOID);
        !           257: BOOL CrackArgs(UINT argc, char *argv[]);
        !           258: VOID DisplayHelp(VOID);
        !           259: 
        !           260: /****************************************************************************\
        !           261: *
        !           262: * FUNCTION: Main
        !           263: *
        !           264: \****************************************************************************/
        !           265: 
        !           266: UINT main(UINT argc, char *argv[])
        !           267: {
        !           268:   WIN32_FIND_DATA ffdFoundData;
        !           269:   HANDLE          hFound;
        !           270:   #define                   SZ_NAME_BUF MAX_PATH
        !           271:   UCHAR           ucPathBuf[SZ_NAME_BUF];
        !           272:   LPTSTR          lpszFullName = (LPTSTR)&ucPathBuf;
        !           273: 
        !           274:   /**************************************************************************\
        !           275:   *
        !           276:   * Store the process's SID in a global variable for later use (in taking
        !           277:   *   ownership).
        !           278:   *
        !           279:   \**************************************************************************/
        !           280: 
        !           281:   if (!GetProcessSid())
        !           282:   { PERR("Can't proceed without process SID - see earlier error messages");
        !           283:     return(1);
        !           284:   }
        !           285: 
        !           286:   if (!CrackArgs(argc,argv))
        !           287:     return(1);
        !           288: 
        !           289:   /**************************************************************************\
        !           290:   *
        !           291:   * CrackArgs has set our global processing switches, and proven argv[2] and
        !           292:   *   argv[3] are our non-blank dir-spec and file-pattern strings.  Now we
        !           293:   *   must see that the file-spec is acceptable to the Win32 api's.  Argv[2]
        !           294:   *   is the file-spec to pass to SetCurrentDirectory, and argv[3] is the
        !           295:   *   file-pattern to pass to FindFirstFile
        !           296:   *
        !           297:   * First we have to expand the dir-spec in argv[2], because if we set the
        !           298:   *   current directory to it before expansion,the expansion will have a
        !           299:   *   different result if argv[2] is something like ..\..
        !           300:   *
        !           301:   \**************************************************************************/
        !           302: 
        !           303:   strcpy(lpszFullName,argv[2]);
        !           304: 
        !           305:   if (!GetFullFileOrDirName(lpszFullName))
        !           306:   { PMSG("Failed to expand to full name the 2nd argument (directory specification)");
        !           307:     return(1);
        !           308:   }
        !           309: 
        !           310:   /**************************************************************************\
        !           311:   *
        !           312:   * Now we pass the un-expanded argv[2] to SetCurrentDirectory for validity
        !           313:   *   checking.  GetFullPathName (called by GetFullFileOrDirName) does not
        !           314:   *   validity check
        !           315:   *
        !           316:   \**************************************************************************/
        !           317: 
        !           318:   if (!SetCurrentDirectory(argv[2]))
        !           319:   { PrintAppStyleAPIError(SetCurrentDirectory,"2nd argument (directory specification)");
        !           320:     return(1);
        !           321:   }
        !           322: 
        !           323:   /**************************************************************************\
        !           324:   *
        !           325:   * We begin processing with the current directory, using the expanded form we
        !           326:   *   got before.  We have to use the expanded form, because if we set to
        !           327:   *   ..\.. and then try to process the string ..\.. as a dir name, instead of
        !           328:   *   processing the dir two levels up from where we are we'll process the dir
        !           329:   *   four levels up
        !           330:   *
        !           331:   \**************************************************************************/
        !           332: 
        !           333:   if (!DoOneFileOrDir(lpszFullName))
        !           334:     return(1);
        !           335: 
        !           336:   /**************************************************************************\
        !           337:   *
        !           338:   * It's OK to get no hits.  The files-checked counter will show how many
        !           339:   *   files we looked at, and it's OK to look at 0
        !           340:   *
        !           341:   * On the else branch, Argv[3] has been verified, and we have a good handle.
        !           342:   *   We now pass to DoMatchingFilesInOneDir for processing the handle and
        !           343:   *   found data we just got from FindFirstFile
        !           344:   *
        !           345:   \**************************************************************************/
        !           346: 
        !           347:   hFound = FindFirstFile(argv[3],
        !           348:                          (LPWIN32_FIND_DATA)&ffdFoundData);
        !           349:   if ((HANDLE)(-1) == hFound)
        !           350:   { if (GetLastError() != ERROR_FILE_NOT_FOUND)
        !           351:     { PrintAppStyleAPIError(FindFirstFile,"3rd argument");
        !           352:       return(1);
        !           353:     }
        !           354:   }
        !           355:   else if (!DoMatchingFilesInOneDir(hFound,ffdFoundData))
        !           356:     return(1);
        !           357: 
        !           358:   /**************************************************************************\
        !           359:   *
        !           360:   * Pass the original file pattern for recursive calling to DoAllDirsInOneDir
        !           361:   *
        !           362:   \**************************************************************************/
        !           363: 
        !           364:   if (!DoAllDirsInOneDir(argv[3]))
        !           365:     return(1);
        !           366: 
        !           367:   if (bJustCount)
        !           368:     printf("\nChecked %d files, would have taken ownership of %d files, would have deleted %d ACEs\n",
        !           369:            dwFilesChecked,dwFilesOwned,dwACEsDeleted);
        !           370:   else
        !           371:     printf("\nChecked %d files, took ownership of %d files, deleted %d ACEs\n",
        !           372:            dwFilesChecked,dwFilesOwned,dwACEsDeleted);
        !           373: 
        !           374:   return(0);
        !           375: }
        !           376: 
        !           377: /****************************************************************************\
        !           378: *
        !           379: * FUNCTION: DoMatchingFilesInOneDir
        !           380: *
        !           381: \****************************************************************************/
        !           382: 
        !           383: BOOL DoMatchingFilesInOneDir(HANDLE          hFound,
        !           384:                              WIN32_FIND_DATA ffdFoundData)
        !           385: {
        !           386:   BOOL bDoneWithHandle = FALSE;
        !           387: 
        !           388:   /**************************************************************************\
        !           389:   *
        !           390:   * Process all files referred to by the handle, but not including
        !           391:   *   directories, because directories are handled with separate calls to
        !           392:   *   DoOneFileOrDir.  Such separate calls are made as we are setting the
        !           393:   *   current directory to be the directory to be processed
        !           394:   *
        !           395:   \**************************************************************************/
        !           396: 
        !           397:   while (!bDoneWithHandle)
        !           398:   {
        !           399:     if (!(FILE_ATTRIBUTE_DIRECTORY & ffdFoundData.dwFileAttributes))
        !           400:     {
        !           401:       if (!DoOneFileOrDir(ffdFoundData.cFileName))
        !           402:         return(FALSE);
        !           403:     }
        !           404: 
        !           405:     if (!FindNextFile(hFound,
        !           406:                       (LPWIN32_FIND_DATA)&ffdFoundData))
        !           407:       if (GetLastError() == ERROR_NO_MORE_FILES)
        !           408:         bDoneWithHandle = TRUE;
        !           409:       else
        !           410:       { PrintAppStyleAPIError(FindNextFile,"on FindNext");
        !           411:         return(FALSE);
        !           412:       }
        !           413:   }
        !           414: }
        !           415: 
        !           416: /****************************************************************************\
        !           417: *
        !           418: * FUNCTION: DoAllDirsInOneDir
        !           419: *
        !           420: \****************************************************************************/
        !           421: 
        !           422: BOOL DoAllDirsInOneDir(char *FilePattern)
        !           423: {
        !           424:   HANDLE          hFound;
        !           425:   WIN32_FIND_DATA ffdFoundData;
        !           426:   BOOL            bDoneWithHandle = FALSE;
        !           427: 
        !           428:   /**************************************************************************\
        !           429:   *
        !           430:   * If not recursing into dirs, simply return
        !           431:   *
        !           432:   \**************************************************************************/
        !           433: 
        !           434:   if (!bRecurse)
        !           435:     return TRUE;
        !           436: 
        !           437:   /**************************************************************************\
        !           438:   *
        !           439:   * Since we are recursing, get a handle that points to entire directory, and
        !           440:   *   walk the handle picking off only directories to recurse into
        !           441:   *
        !           442:   \**************************************************************************/
        !           443: 
        !           444:   hFound = FindFirstFile("*.*",
        !           445:                          (LPWIN32_FIND_DATA)&ffdFoundData);
        !           446:   if ((HANDLE)(-1) == hFound)
        !           447:   { PrintAppStyleAPIError(FindFirstFile,"on dir *.* FindFirst");
        !           448:     return(FALSE);
        !           449:   }
        !           450: 
        !           451:   while (!bDoneWithHandle)
        !           452:   {
        !           453:     /************************************************************************\
        !           454:     *
        !           455:     * We only do dirs here, and we only do directories with textual names
        !           456:     *   (i.e., not "." and not "..")
        !           457:     *
        !           458:     \************************************************************************/
        !           459: 
        !           460:     if (   (FILE_ATTRIBUTE_DIRECTORY & ffdFoundData.dwFileAttributes)
        !           461:         && (0 != strcmp("." ,ffdFoundData.cFileName))
        !           462:         && (0 != strcmp("..",ffdFoundData.cFileName)))
        !           463:     {
        !           464:       HANDLE          hFile2;
        !           465:       WIN32_FIND_DATA ffdFound2;
        !           466: 
        !           467:       /**********************************************************************\
        !           468:       *
        !           469:       * We begin processing the new current directory by processing it itself,
        !           470:       *   then setting the current dir to be the dir itself
        !           471:       *
        !           472:       \**********************************************************************/
        !           473: 
        !           474:       if (!DoOneFileOrDir(ffdFoundData.cFileName))
        !           475:         return(FALSE);
        !           476: 
        !           477:       if (!SetCurrentDirectory(ffdFoundData.cFileName))
        !           478:       { PrintAppStyleAPIError(SetCurrentDirectory,"recursive set");
        !           479:         return(FALSE);
        !           480:       }
        !           481: 
        !           482:       /**********************************************************************\
        !           483:       *
        !           484:       * It's OK to get no hits.  The files-checked counter will show how many
        !           485:       *   files we looked at, and it's OK to look at 0
        !           486:       *
        !           487:       \**********************************************************************/
        !           488: 
        !           489:       hFile2 = FindFirstFile(FilePattern,
        !           490:                              (LPWIN32_FIND_DATA)&ffdFound2);
        !           491:       if ((HANDLE)(-1) == hFile2)
        !           492:       { if (GetLastError() != ERROR_FILE_NOT_FOUND)
        !           493:         { PrintAppStyleAPIError(FindFirstFile,"during recursion");
        !           494:           return(FALSE);
        !           495:         }
        !           496:       }
        !           497:       else if (!DoMatchingFilesInOneDir(hFile2,ffdFound2))
        !           498:         return(FALSE);
        !           499: 
        !           500:       if (!DoAllDirsInOneDir(FilePattern))
        !           501:         return(FALSE);
        !           502: 
        !           503:       if (!SetCurrentDirectory(".."))
        !           504:       { PrintAppStyleAPIError(SetCurrentDirectory,"un-recursive set");
        !           505:         return(FALSE);
        !           506:       }
        !           507:     }
        !           508: 
        !           509:     /************************************************************************\
        !           510:     *
        !           511:     * Get next recursion candidate (file or dir at this point, however at loop
        !           512:     *   top files are screened out)
        !           513:     *
        !           514:     \************************************************************************/
        !           515: 
        !           516:     if (!FindNextFile(hFound,
        !           517:                       (LPWIN32_FIND_DATA)&ffdFoundData))
        !           518:       if (GetLastError() == ERROR_NO_MORE_FILES)
        !           519:         bDoneWithHandle = TRUE;
        !           520:       else
        !           521:       { PrintAppStyleAPIError(FindNextFile,"on dir *.* FindNext");
        !           522:         return(FALSE);
        !           523:       }
        !           524:   }
        !           525:   return(TRUE);
        !           526: }
        !           527: 
        !           528: /****************************************************************************\
        !           529: *
        !           530: * FUNCTION: GetFullFileOrDirName
        !           531: *
        !           532: \****************************************************************************/
        !           533: 
        !           534: BOOL GetFullFileOrDirName(LPTSTR lpszFileName)
        !           535: {
        !           536:   UCHAR   ucPathBuf[SZ_NAME_BUF];
        !           537:   DWORD   dwSzReturned;
        !           538:   LPTSTR  lpszLastNamePart;
        !           539:   LPTSTR  lpszFullName;
        !           540: 
        !           541:   dwSzReturned = GetFullPathName
        !           542:                    (lpszFileName,
        !           543:                     (DWORD)SZ_NAME_BUF,
        !           544:                     (LPTSTR)&ucPathBuf,
        !           545:                     (LPTSTR *)&lpszLastNamePart);
        !           546:   if (0 == dwSzReturned)
        !           547:     switch (GetLastError())
        !           548:     { case ERROR_INVALID_NAME   :
        !           549:         printf("\nError invalid file full-name (on GetFullPathName)");
        !           550:         return(FALSE);
        !           551:       default                   :
        !           552:         PERR("GetFullPathName - unexpected return code");
        !           553:         return(FALSE);
        !           554:     }
        !           555: 
        !           556:   if (dwSzReturned > SZ_NAME_BUF)
        !           557:   { PERR("GetFullPathName - buffer too small");
        !           558:     return(FALSE);
        !           559:   }
        !           560: 
        !           561:   lpszFullName = CharLower((LPTSTR)&ucPathBuf);
        !           562: 
        !           563:   if (!lpszFullName)
        !           564:   { PERR("CharLower failure");
        !           565:     return(FALSE);
        !           566:   }
        !           567: 
        !           568:   /**************************************************************************\
        !           569:   *
        !           570:   * Copy the expanded and upper-case-shifted name to the buffer pointed to by
        !           571:   *   the input argument
        !           572:   *
        !           573:   \**************************************************************************/
        !           574: 
        !           575:   strcpy(lpszFileName,lpszFullName);
        !           576: }
        !           577: 
        !           578: /****************************************************************************\
        !           579: *
        !           580: * FUNCTION: DoOneFileOrDir
        !           581: *
        !           582: \****************************************************************************/
        !           583: 
        !           584: BOOL DoOneFileOrDir(LPTSTR lpszFullName)
        !           585: {
        !           586:   #define                           SZ_SD_BUF 1000
        !           587:   UCHAR                ucBuf       [SZ_SD_BUF];
        !           588:   DWORD                dwSDLength = SZ_SD_BUF;
        !           589:   DWORD                dwSDLengthNeeded;
        !           590:   PSECURITY_DESCRIPTOR psdFileSD;
        !           591: 
        !           592:   if (!GetFullFileOrDirName(lpszFullName))
        !           593:     return(FALSE);
        !           594: 
        !           595:   /**************************************************************************\
        !           596:   *
        !           597:   * Now the input argument's name is accurate:  it is expanded and lower-case
        !           598:   *
        !           599:   \**************************************************************************/
        !           600: 
        !           601:   printf("\nChecking %s",lpszFullName);
        !           602: 
        !           603:   dwFilesChecked++;
        !           604: 
        !           605:   psdFileSD = (PSECURITY_DESCRIPTOR)&ucBuf;
        !           606: 
        !           607:   if (!GetFileSecurity
        !           608:         (lpszFullName,
        !           609:          (SECURITY_INFORMATION)(OWNER_SECURITY_INFORMATION
        !           610:                                | DACL_SECURITY_INFORMATION),
        !           611:          psdFileSD,
        !           612:          dwSDLength,
        !           613:          (LPDWORD)&dwSDLengthNeeded))
        !           614:   { PERR("GetFileSecurity");
        !           615:     return(FALSE);
        !           616:   }
        !           617: 
        !           618:   /**************************************************************************\
        !           619:   *
        !           620:   * This validity check is here for demonstration pruposes.  It's not likely a
        !           621:   *   real app would need to check the validity of this returned SD.  The
        !           622:   *   validity check APIs are more intended to check validity after app code
        !           623:   *   has manipulated the structure and is about to hand it back to the system
        !           624:   *
        !           625:   \**************************************************************************/
        !           626: 
        !           627:   if (!IsValidSecurityDescriptor(psdFileSD))
        !           628:   { PERR("IsValidSecurityDescriptor said bad SD");
        !           629:     return(FALSE);
        !           630:   }
        !           631: 
        !           632:   if (bTakeOwnership)
        !           633:     if (!TakeOwnershipIfAppropriate(psdFileSD,lpszFullName))
        !           634:       return(FALSE);
        !           635: 
        !           636:   if (bEditACLs)
        !           637:     if (!DeleteACEsAsAppropriate   (psdFileSD,lpszFullName))
        !           638:       return(FALSE);
        !           639: 
        !           640:   return(TRUE);
        !           641: }
        !           642: 
        !           643: /****************************************************************************\
        !           644: *
        !           645: * FUNCTION: TakeOwnershipIfAppropriate
        !           646: *
        !           647: \****************************************************************************/
        !           648: 
        !           649: BOOL TakeOwnershipIfAppropriate(PSECURITY_DESCRIPTOR psdFileSD,
        !           650:                                 LPTSTR  lpszFullName)
        !           651: {
        !           652:   PSID psidFileOwnerSID;
        !           653:   {
        !           654:     BOOL  bOwnerDefaulted;
        !           655: 
        !           656:     if (!GetSecurityDescriptorOwner
        !           657:            (psdFileSD,
        !           658:             (PSID *)&psidFileOwnerSID,
        !           659:             (LPBOOL)&bOwnerDefaulted))
        !           660:     { PERR("GetSecurityDescriptorOwner");
        !           661:       return(FALSE);
        !           662:     }
        !           663: 
        !           664:     /************************************************************************\
        !           665:     *
        !           666:     * This validity check is here for demonstration pruposes.  It's not likely
        !           667:     *   a real app would need to check the validity of this returned SID.  The
        !           668:     *   validity check APIs are more intended to check validity after app code
        !           669:     *   has manipulated the structure and is about to hand it back to the
        !           670:     *   system
        !           671:     *
        !           672:     \************************************************************************/
        !           673: 
        !           674:     if (!IsValidSid(psidFileOwnerSID))
        !           675:     { PERR("IsValidSid said bad SID!");
        !           676:       return(FALSE);
        !           677:     }
        !           678:   }
        !           679: 
        !           680:   {
        !           681:     DWORD        dwLastError   = NO_ERROR;
        !           682:     #define                      SZ_ACCT_NAME_BUF 1000
        !           683:     UCHAR        ucNameBuf      [SZ_ACCT_NAME_BUF];
        !           684:     DWORD        dwNameLength  = SZ_ACCT_NAME_BUF;
        !           685:     #define                      SZ_DMN_NAME_BUF  1000
        !           686:     UCHAR        ucDomainNmBuf  [SZ_DMN_NAME_BUF ];
        !           687:     DWORD        dwDNameLength = SZ_DMN_NAME_BUF ;
        !           688:     SID_NAME_USE peAcctNameUse;
        !           689: 
        !           690:     if (!LookupAccountSid
        !           691:            ((LPTSTR)"",             // Look on local machine
        !           692:            psidFileOwnerSID,
        !           693:            (LPTSTR)&ucNameBuf,
        !           694:            (LPDWORD)&dwNameLength,
        !           695:            (LPTSTR)&ucDomainNmBuf,
        !           696:            (LPDWORD)&dwDNameLength,
        !           697:            (PSID_NAME_USE)&peAcctNameUse))
        !           698:     { dwLastError = GetLastError();
        !           699:       if (ERROR_NONE_MAPPED != dwLastError)
        !           700:       { PERR("LookupAccountSID");
        !           701:         return(FALSE);
        !           702:       }
        !           703:     }
        !           704: 
        !           705:     /************************************************************************\
        !           706:     *
        !           707:     * If deleted account, take ownership.  This routine's caller checked the
        !           708:     *   global switches that said we are in take ownership mode
        !           709:     *
        !           710:     * In some cases, the account lookup will fail with ERROR_NONE_MAPPED,
        !           711:     *   meaning there is no deleted account mapped to the SID, in which case
        !           712:     *   we also take ownership
        !           713:     *
        !           714:     *   We check that first to avoid referencing peAcctNameUse, which in that
        !           715:     *     case is not set
        !           716:     *
        !           717:     \************************************************************************/
        !           718: 
        !           719:     if (  (ERROR_NONE_MAPPED == dwLastError)
        !           720:        || (SidTypeDeletedAccount == peAcctNameUse))
        !           721:     {
        !           722:       dwFilesOwned++;
        !           723: 
        !           724:       if (bJustCount)
        !           725:       { printf(" - would have taken ownership");
        !           726:         return(TRUE);
        !           727:       }
        !           728:       else
        !           729:       {
        !           730:         /********************************************************************\
        !           731:         *
        !           732:         * Modify the SD in virtual memory.  No check on the new owning SID
        !           733:         *   here, because we validity checked it when we fetched it in
        !           734:         *   GetProcessSid
        !           735:         *
        !           736:         \********************************************************************/
        !           737: 
        !           738:         if (!SetSecurityDescriptorOwner
        !           739:                (psdFileSD,
        !           740:                 psidProcessOwnerSID,
        !           741:                 FALSE))               // New owner explicitly specified
        !           742:         { PERR("SetSecurityDescriptorOwner");
        !           743:           return(FALSE);
        !           744:         }
        !           745: 
        !           746:         /********************************************************************\
        !           747:         *
        !           748:         *  This validity check is something a real app might actually like to
        !           749:         *    do.  We manupulated the SD, so before we write it back out to the
        !           750:         *    file system, a check is worth considering.
        !           751:         *
        !           752:         \********************************************************************/
        !           753: 
        !           754:         if (!IsValidSecurityDescriptor(psdFileSD))
        !           755:         { PERR("IsValidSecurityDescriptor said bad SD");
        !           756:           return(FALSE);
        !           757:         }
        !           758: 
        !           759:         /********************************************************************\
        !           760:         *
        !           761:         * Modify the SD on the hard disk
        !           762:         *
        !           763:         \********************************************************************/
        !           764: 
        !           765:         if (!SetFileSecurity
        !           766:                (lpszFullName,
        !           767:                 (SECURITY_INFORMATION)OWNER_SECURITY_INFORMATION,
        !           768:                 psdFileSD))
        !           769:         { PERR("SetFileSecurity");
        !           770:           return(FALSE);
        !           771:         }
        !           772: 
        !           773:         printf(" - took ownership");
        !           774:       }
        !           775:     }
        !           776:   }
        !           777: 
        !           778:   return(TRUE);
        !           779: 
        !           780: }
        !           781: 
        !           782: /****************************************************************************\
        !           783: *
        !           784: * FUNCTION: DeleteACEsAsAppropriate
        !           785: *
        !           786: \****************************************************************************/
        !           787: 
        !           788: BOOL DeleteACEsAsAppropriate(PSECURITY_DESCRIPTOR psdFileSD,
        !           789:                              LPTSTR  lpszFullName)
        !           790: {
        !           791:   PACL                 paclFile;
        !           792:   BOOL                 bHasACL;
        !           793:   BOOL                 bOwnerDefaulted;
        !           794:   DWORD                dwAcl_i;
        !           795:   DWORD                dwACEsDeletedBeforeNow;
        !           796: 
        !           797:   ACL_SIZE_INFORMATION                      asiAclSize;
        !           798:   DWORD                dwBufLength = sizeof(asiAclSize);
        !           799:   ACCESS_ALLOWED_ACE   *paaAllowedAce;
        !           800: 
        !           801:   if (!GetSecurityDescriptorDacl(psdFileSD,
        !           802:                                  (LPBOOL)&bHasACL,
        !           803:                                  (PACL *)&paclFile,
        !           804:                                  (LPBOOL)&bOwnerDefaulted))
        !           805:   { PERR("GetSecurityDescriptorDacl");
        !           806:     return(FALSE);
        !           807:   }
        !           808: 
        !           809:   if (!bHasACL)  // No ACL to process, so OK, return
        !           810:     return(TRUE);
        !           811: 
        !           812:   /**************************************************************************\
        !           813:   *
        !           814:   * This validity check is here for demonstration pruposes.  It's not likely a
        !           815:   *   real app would need to check the validity of this returned ACL.  The
        !           816:   *   validity check APIs are more intended to check validity after app code
        !           817:   *   has manipulated the structure and is about to hand it back to the system
        !           818:   *
        !           819:   \**************************************************************************/
        !           820: 
        !           821:   if (!IsValidAcl(paclFile))
        !           822:   { PERR("IsValidAcl said bad ACL!");
        !           823:     return(FALSE);
        !           824:   }
        !           825: 
        !           826:   if (!GetAclInformation(paclFile,
        !           827:                          (LPVOID)&asiAclSize,
        !           828:                          (DWORD)dwBufLength,
        !           829:                          (ACL_INFORMATION_CLASS)AclSizeInformation))
        !           830:   { PERR("GetAclInformation");
        !           831:     return(FALSE);
        !           832:   }
        !           833: 
        !           834:   dwACEsDeletedBeforeNow = dwACEsDeleted;
        !           835: 
        !           836:   /**************************************************************************\
        !           837:   *
        !           838:   * We loop through in reverse order, because that's simpler, given that we
        !           839:   *   potentially delete ACEs as we loop through.  If started at 0 and went
        !           840:   *   up, if we deleted the 0th ACE, then the 1th ACE would become the 0th,
        !           841:   *   and we'd have to check the 0th ACE again
        !           842:   *
        !           843:   \**************************************************************************/
        !           844: 
        !           845:   for (dwAcl_i = asiAclSize.AceCount-1;  ((int)dwAcl_i) >= 0;  dwAcl_i--)
        !           846:   {
        !           847:     /************************************************************************\
        !           848:     *
        !           849:     * It doesn't matter for this sample that we don't yet know the ACE type,
        !           850:     *   because they all start with the header field and that's what we need
        !           851:     *
        !           852:     \************************************************************************/
        !           853: 
        !           854:     if (!GetAce(paclFile,
        !           855:                 dwAcl_i,
        !           856:                 (LPVOID *)&paaAllowedAce))
        !           857:     { PERR("GetAce");
        !           858:       return(FALSE);
        !           859:     }
        !           860: 
        !           861:     /************************************************************************\
        !           862:     *
        !           863:     * There are only four Ace Types pre-defined, so this next check is
        !           864:     *   redundant in a real app, but useful as a sanity check and a
        !           865:     *   demonstration in a sample
        !           866:     *
        !           867:     \************************************************************************/
        !           868: 
        !           869:     if (!( (paaAllowedAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
        !           870:          ||(paaAllowedAce->Header.AceType == ACCESS_DENIED_ACE_TYPE )
        !           871:          ||(paaAllowedAce->Header.AceType == SYSTEM_AUDIT_ACE_TYPE  )
        !           872:          ||(paaAllowedAce->Header.AceType == SYSTEM_ALARM_ACE_TYPE  )))
        !           873:     { PERR("Invalid AceType");
        !           874:       return(FALSE);
        !           875:     }
        !           876: 
        !           877:     { // Find SID of ACE, check if acct deleted
        !           878: 
        !           879:       UCHAR        ucNameBuf      [SZ_ACCT_NAME_BUF];
        !           880:       DWORD        dwNameLength  = SZ_ACCT_NAME_BUF;
        !           881:       UCHAR        ucDomainNmBuf  [SZ_DMN_NAME_BUF];
        !           882:       DWORD        dwDNameLength = SZ_DMN_NAME_BUF;
        !           883:       SID_NAME_USE peAcctNameUse;
        !           884:       DWORD        dwLastError   = NO_ERROR;
        !           885: 
        !           886:       /**********************************************************************\
        !           887:       *
        !           888:       * This validity check is here for demonstration pruposes.  It's not
        !           889:       *   likely a real app would need to check the validity of the SID
        !           890:       *   contained in the returned ACL.  The validity check APIs are more
        !           891:       *   intended to check validity after app code has manipulated the
        !           892:       *   structure and is about to hand it back to the system
        !           893:       *
        !           894:       \**********************************************************************/
        !           895: 
        !           896:       if (!IsValidSid((PSID)&(paaAllowedAce->SidStart)))
        !           897:         { PERR("IsValidSid said bad SID!");
        !           898:           return(FALSE);
        !           899:         }
        !           900: 
        !           901:       if (!LookupAccountSid
        !           902:              ((LPTSTR)"",         // Look on local machine
        !           903:              (PSID)&(paaAllowedAce->SidStart),
        !           904:              (LPTSTR)&ucNameBuf,
        !           905:              (LPDWORD)&dwNameLength,
        !           906:              (LPTSTR)&ucDomainNmBuf,
        !           907:              (LPDWORD)&dwDNameLength,
        !           908:              (PSID_NAME_USE)&peAcctNameUse))
        !           909:       { dwLastError = GetLastError();
        !           910:         if (ERROR_NONE_MAPPED != dwLastError)
        !           911:         { PERR("LookupAccountSID");
        !           912:           return(FALSE);
        !           913:         }
        !           914:       }
        !           915: 
        !           916:       if (  (ERROR_NONE_MAPPED == dwLastError)
        !           917:          || (SidTypeDeletedAccount == peAcctNameUse))
        !           918:       {
        !           919:         dwACEsDeleted++;
        !           920: 
        !           921:         if (bJustCount)
        !           922:         { printf(" - would have edited ACL");
        !           923:           return(TRUE);
        !           924:         }
        !           925: 
        !           926:         if (!DeleteAce(paclFile,dwAcl_i))
        !           927:         { PERR("DeleteAce");
        !           928:           return(FALSE);
        !           929:         }
        !           930:       }
        !           931:     }
        !           932:   }
        !           933: 
        !           934:   if (dwACEsDeletedBeforeNow < dwACEsDeleted)
        !           935:   {
        !           936:     /************************************************************************\
        !           937:     *
        !           938:     * This validity check is something a real app might actually like to do.
        !           939:     *   We manupulated the ACL, so before we write it back into an SD, a check
        !           940:     *   is worth considering
        !           941:     *
        !           942:     \************************************************************************/
        !           943: 
        !           944:     if (!IsValidAcl(paclFile))
        !           945:     { PERR("IsValidAcl said bad ACL!");
        !           946:       return(FALSE);
        !           947:     }
        !           948: 
        !           949:     /************************************************************************\
        !           950:     *
        !           951:     * Modify the SD in virtual memory
        !           952:     *
        !           953:     \************************************************************************/
        !           954: 
        !           955:     if (!SetSecurityDescriptorDacl
        !           956:            (psdFileSD,
        !           957:             TRUE,                 // Yes, set the DACL
        !           958:             paclFile,
        !           959:             FALSE))               // New DACL explicitly specified
        !           960:     { PERR("SetSecurityDescriptorDacl");
        !           961:       return(FALSE);
        !           962:     }
        !           963: 
        !           964:     /************************************************************************\
        !           965:     *
        !           966:     * This validity check is something a real app might actually like to do.
        !           967:     *   We manupulated the SD, so before we write it back out to the file
        !           968:     *   system, a check is worth considering
        !           969:     *
        !           970:     \************************************************************************/
        !           971: 
        !           972:     if (!IsValidSecurityDescriptor(psdFileSD))
        !           973:     { PERR("IsValidSecurityDescriptor said bad SD");
        !           974:       return(FALSE);
        !           975:     }
        !           976: 
        !           977:     /************************************************************************\
        !           978:     *
        !           979:     * Modify the SD on the hard disk
        !           980:     *
        !           981:     \************************************************************************/
        !           982: 
        !           983:     if (!SetFileSecurity
        !           984:            (lpszFullName,
        !           985:             (SECURITY_INFORMATION)DACL_SECURITY_INFORMATION,
        !           986:             psdFileSD))
        !           987:     { PERR("SetFileSecurity");
        !           988:       return(FALSE);
        !           989:     }
        !           990: 
        !           991:     printf(" - edited ACL");
        !           992:   }
        !           993: 
        !           994:   return(TRUE);
        !           995: 
        !           996: }
        !           997: 
        !           998: /****************************************************************************\
        !           999: *
        !          1000: * FUNCTION: GetProcessSid
        !          1001: *
        !          1002: \****************************************************************************/
        !          1003: 
        !          1004: BOOL GetProcessSid(VOID)
        !          1005: {
        !          1006:   HANDLE               hProcess;
        !          1007:   PSECURITY_DESCRIPTOR psdProcessSD;
        !          1008:   PSID                 psidProcessOwnerSIDTemp;
        !          1009: 
        !          1010:   UCHAR                ucBuf       [SZ_SD_BUF];
        !          1011:   DWORD                dwSDLength = SZ_SD_BUF;
        !          1012:   DWORD                dwSDLengthNeeded;
        !          1013:   BOOL                 bOwnerDefaulted;
        !          1014: 
        !          1015:   hProcess = GetCurrentProcess();
        !          1016: 
        !          1017:   if (!hProcess)
        !          1018:     { PERR("GetCurrentProcess");
        !          1019:       return(FALSE);
        !          1020:     }
        !          1021: 
        !          1022:   psdProcessSD = (PSECURITY_DESCRIPTOR)ucBuf;
        !          1023: 
        !          1024:   if (!GetKernelObjectSecurity
        !          1025:          (hProcess,
        !          1026:           (SECURITY_INFORMATION)(OWNER_SECURITY_INFORMATION),
        !          1027:           psdProcessSD,
        !          1028:           dwSDLength,
        !          1029:           (LPDWORD)&dwSDLengthNeeded))
        !          1030:     { PERR("GetKernelObjectSecurity on current process handle");
        !          1031:       return(FALSE);
        !          1032:     }
        !          1033: 
        !          1034:   /**************************************************************************\
        !          1035:   *
        !          1036:   * This validity check is here for demonstration purposes.  It's not likely a
        !          1037:   *   real app would need to check the validity of this returned SD.  The
        !          1038:   *   validity check APIs are more intended to check validity after app code
        !          1039:   *   has manipulated the structure and is about to hand it back to the system
        !          1040:   *
        !          1041:   \**************************************************************************/
        !          1042: 
        !          1043:   if (!IsValidSecurityDescriptor(psdProcessSD))
        !          1044:   { PERR("IsValidSecurityDescriptor said bad SD");
        !          1045:     return(FALSE);
        !          1046:   }
        !          1047: 
        !          1048:   if (!GetSecurityDescriptorOwner
        !          1049:          (psdProcessSD,
        !          1050:           (PSID *)&psidProcessOwnerSIDTemp,
        !          1051:           (LPBOOL)&bOwnerDefaulted))
        !          1052:     { PERR("GetSecurityDescriptorOwner of current process");
        !          1053:       return(FALSE);
        !          1054:     }
        !          1055: 
        !          1056:   /**************************************************************************\
        !          1057:   *
        !          1058:   * This validity check is here for demonstration pruposes.  It's not likely a
        !          1059:   *   real app would need to check the validity of this returned SID.  The
        !          1060:   *   validity check APIs are more intended to check validity after app code
        !          1061:   *   has manipulated the structure and is about to hand it back to the system
        !          1062:   *
        !          1063:   \**************************************************************************/
        !          1064: 
        !          1065:   if (!IsValidSid(psidProcessOwnerSIDTemp))
        !          1066:     { PERR("IsValidSid said bad process SID!");
        !          1067:       return(FALSE);
        !          1068:     }
        !          1069: 
        !          1070:   /**************************************************************************\
        !          1071:   *
        !          1072:   * On the other hand, we are about to call GetLengthSid on the returned SID,
        !          1073:   *   and calling GetLengthSid with an invalid SID is a bad idea, since then
        !          1074:   *   GetLengthSid's result is undefined, and an undefined result is hard to
        !          1075:   *   handle cleanly
        !          1076:   *
        !          1077:   * An app that handles a lot of SIDs would probably call GetLengthSid on the
        !          1078:   *   SIDs it retrieves, then VirtualAlloc or malloc storage to hold copies of
        !          1079:   *   the SIDs (when holding copies is necessary).  Since this sample only
        !          1080:   *   needs to hold one retrieved SID for any length of time, it's simpler to
        !          1081:   *   statically allocate the size needed, and only use the call to
        !          1082:   *   GetLengthSid to verify that the static area is large enough.  The static
        !          1083:   *   area will always be large enough unless perhaps something in the SID
        !          1084:   *   data structures changes in a future build of NT.  So, SZ_PROCESS_SID_BUF
        !          1085:   *   is defined to be 16 simply because that's the value we know GetLengthSid
        !          1086:   *   returns in this case (we know it's 16 by examining the value using the
        !          1087:   *   debugger during app development).
        !          1088:   *
        !          1089:   \**************************************************************************/
        !          1090: 
        !          1091:   if (SZ_PROCESS_SID_BUF < GetLengthSid(psidProcessOwnerSIDTemp))
        !          1092:     { PERR("Can't do CopySid because buffer too small");
        !          1093:       return(FALSE);
        !          1094:     }
        !          1095: 
        !          1096:   if (!CopySid((DWORD)SZ_PROCESS_SID_BUF,
        !          1097:                psidProcessOwnerSID,
        !          1098:                psidProcessOwnerSIDTemp))
        !          1099:     { PERR("CopySid");
        !          1100:       return(FALSE);
        !          1101:     }
        !          1102: 
        !          1103:   /**************************************************************************\
        !          1104:   *
        !          1105:   * This validity check is here for demonstration pruposes only (see above).
        !          1106:   *
        !          1107:   \**************************************************************************/
        !          1108: 
        !          1109:   if (!IsValidSid(psidProcessOwnerSID))
        !          1110:     { PERR("IsValidSid said bad process SID!");
        !          1111:       return(FALSE);
        !          1112:     }
        !          1113: }
        !          1114: 
        !          1115: /****************************************************************************\
        !          1116: *
        !          1117: * FUNCTION: CrackArgs
        !          1118: *
        !          1119: \****************************************************************************/
        !          1120: 
        !          1121: BOOL CrackArgs(UINT argc, char *argv[])
        !          1122: {
        !          1123:   char *p;
        !          1124: 
        !          1125:   /**************************************************************************\
        !          1126:   *
        !          1127:   * There must be three arguments
        !          1128:   *
        !          1129:   \**************************************************************************/
        !          1130: 
        !          1131:   if (argc != 4)
        !          1132:   { DisplayHelp();
        !          1133:     return(FALSE);
        !          1134:   }
        !          1135: 
        !          1136:   p=argv[1];
        !          1137: 
        !          1138:   /**************************************************************************\
        !          1139:   *
        !          1140:   * The switch argument must be 2-5 chars long
        !          1141:   *
        !          1142:   \**************************************************************************/
        !          1143: 
        !          1144:   if ((strlen(p) < 2) || (strlen(p) > 5))
        !          1145:   { DisplayHelp();
        !          1146:     return(FALSE);
        !          1147:   }
        !          1148: 
        !          1149:   /**************************************************************************\
        !          1150:   *
        !          1151:   * The first char in the switch argument must be /
        !          1152:   *
        !          1153:   \**************************************************************************/
        !          1154: 
        !          1155:   if ('/' != *p)
        !          1156:   { DisplayHelp();
        !          1157:     return(FALSE);
        !          1158:   }
        !          1159: 
        !          1160:   /**************************************************************************\
        !          1161:   *
        !          1162:   * Chars 2-5 of the switch argument must be O or A or R or C
        !          1163:   *
        !          1164:   \**************************************************************************/
        !          1165: 
        !          1166:   for (p=p+1; *p; p++)
        !          1167:     switch (*p)
        !          1168:     { case 'o':
        !          1169:       case 'O':
        !          1170:         bTakeOwnership = TRUE;
        !          1171:         break;
        !          1172:       case 'a':
        !          1173:       case 'A':
        !          1174:         bEditACLs      = TRUE;
        !          1175:         break;
        !          1176:       case 'r':
        !          1177:       case 'R':
        !          1178:         bRecurse       = TRUE;
        !          1179:         break;
        !          1180:       case 'c':
        !          1181:       case 'C':
        !          1182:         bJustCount     = TRUE;
        !          1183:         break;
        !          1184:       default :
        !          1185:         DisplayHelp();
        !          1186:         return(FALSE);
        !          1187:     }
        !          1188: 
        !          1189:   /**************************************************************************\
        !          1190:   *
        !          1191:   * Have to say one of O or A
        !          1192:   *
        !          1193:   \**************************************************************************/
        !          1194: 
        !          1195:   if (!(bTakeOwnership || bEditACLs))
        !          1196:   { DisplayHelp();
        !          1197:     return(FALSE);
        !          1198:   }
        !          1199: 
        !          1200:   return(TRUE);
        !          1201: }
        !          1202: 
        !          1203: /****************************************************************************\
        !          1204: *
        !          1205: * FUNCTION: DisplayHelp
        !          1206: *
        !          1207: \****************************************************************************/
        !          1208: 
        !          1209: VOID DisplayHelp(VOID)
        !          1210: {
        !          1211:   printf("\nTo run type SIDCLEAN and 3 parameters.  Syntax:");
        !          1212:   printf("\n  SIDCLEAN /roah dirspec filepattern");
        !          1213:   printf("\n           /r    Recursively process subdirectories");
        !          1214:   printf("\n           /o    For any files matching filepattern: Take ownership if");
        !          1215:   printf("\n                   file currently owned by any deleted SID");
        !          1216:   printf("\n           /a    For any files matching filepattern: Edit ACL, deleting");
        !          1217:   printf("\n                   ACEs associated with any deleted SID");
        !          1218:   printf("\n           /c    Overrides /o and /a, causes counts of /a or /o actions that");
        !          1219:   printf("\n                   would take place if /c not used.  Counts always displayed");
        !          1220:   printf("\n           /h    Override other switch values, just display this message\n");
        !          1221:   printf("\n                 . and .. syntax allowed in dirspec");
        !          1222:   printf("\n                 * and ? wildcards allowed in filepattern");
        !          1223:   printf("\n                 Switch letters can be in any order, upper or lower case");
        !          1224:   printf("\nExamples:");
        !          1225:   printf("\n  SIDCLEAN /o  .  *.*  Take ownership of all files (but not subdirs) in ");
        !          1226:   printf("\n                         current dir that are owned by any deleted SID");
        !          1227:   printf("\n  SIDCLEAN /a  .  *.*  For any file in current dir (but not subdirs), delete");
        !          1228:   printf("\n                         any ACL info that is associated with any deleted SID");
        !          1229:   printf("\n  SIDCLEAN /ro .  *.*  Same as first  example, but also recursively process");
        !          1230:   printf("\n                         subdirectories");
        !          1231:   printf("\n  SIDCLEAN /ar .  *.*  Same as second example, but also recursively process");
        !          1232:   printf("\n                         subdirectories");
        !          1233:   printf("\n  SIDCLEAN /O  \\  *.*  Same as first  example, but process files in root");
        !          1234:   printf("\n                         of current drive");
        !          1235:   printf("\n  SIDCLEAN /oC .. *.*  Same as first  example, but looks at files in dir");
        !          1236:   printf("\n                         containing current dir, processes nothing, just counts");
        !          1237:   printf("\n  SIDCLEAN /A d:\\ *.*  Same as second example, but process files in root");
        !          1238:   printf("\n                         of D: drive");
        !          1239:   printf("\n  SIDCLEAN             Displays this message");
        !          1240:   printf("\n  SIDCLEAN /h          Displays this message (so do ? -? /? -h -H /H)\n");
        !          1241:   printf("\nThis utility must be run while logged on as Administrator\n");
        !          1242: 
        !          1243:   return;
        !          1244: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.