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

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: }

unix.superglobalmegacorp.com

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