|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2001
//
// File: razacl.c
//
// Contents:
//
// History: 4/16/2001 richardw Created
//----------------------------------------------------------------------------
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <sddl.h>
#include <lm.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
UNICODE_STRING SddlFile ; UNICODE_STRING SourceDir ; UNICODE_STRING RootDir ; UNICODE_STRING ExtraDirs[] ;
BOOL Background ; BOOL DoShares ; BOOL CreateSddl ; BOOL Force ; DWORD DebugFlag ; BOOL AddSelf ; BOOL DoSacl ;
SECURITY_INFORMATION SecurityInfo ;
typedef DWORD (NTAPI FS_WALK_CALLBACK)( PVOID Parameter, PWSTR File );
typedef struct _FS_ENGINE_STATS {
ULONG Files ; ULONG Directories ; ULONG EngineErrors ; ULONG CallbackErrors ; } FS_ENGINE_STATS, * PFS_ENGINE_STATS ;
typedef FS_WALK_CALLBACK * PFS_WALK_CALLBACK ;
typedef struct _FS_WALK_CONTROL {
PVOID Parameter ; PFS_WALK_CALLBACK Callback ; ULONG Options ;
PFS_ENGINE_STATS Stats ; HANDLE Search ; WCHAR CurrentPath[ MAX_PATH ]; WCHAR SearchPath[ MAX_PATH ]; WCHAR FilePath[ MAX_PATH ]; } FS_WALK_CONTROL, * PFS_WALK_CONTROL ;
typedef struct _PARAM { LPSTR Argument ; ULONG Flags ; PVOID Value ; PVOID Default ; } PARAM, * PPARAM ;
#define PARAM_TYPE_STRING 0x00000001
#define PARAM_TYPE_ULONG 0x00000002
#define PARAM_TYPE_BOOL 0x00000003
#define PARAM_TYPE_MASK 0x0000FFFF
#define PARAM_TYPE_SINGLE 0x00010000 // Single value
#define PARAM_TYPE_COMMA 0x00020000 // Comma separated multi value
#define PARAM_TYPE_OPTIONAL 0x00040000 // Optional value
#define PARAM_TYPE_REQUIRED 0x00080000 // Required argument
#define PARAM_TYPE_HIDDEN 0x00100000 // Not dumped during help
#define PARAM_TYPE_MULTIPLE 0x00200000 // Can be specified multiple times
#define PARAM_TYPE_FOUND 0x10000000 // Found during arg scan
PARAM Parameters[] = { { "background", PARAM_TYPE_BOOL, &Background, (PVOID) FALSE }, { "sddlfile", PARAM_TYPE_STRING | PARAM_TYPE_REQUIRED, &SddlFile, (PVOID) NULL }, { "shares", PARAM_TYPE_BOOL | PARAM_TYPE_SINGLE | PARAM_TYPE_OPTIONAL, &DoShares, (PVOID) NULL }, { "source", PARAM_TYPE_STRING | PARAM_TYPE_SINGLE, &SourceDir, (PVOID) NULL }, { "createsddl", PARAM_TYPE_BOOL | PARAM_TYPE_SINGLE | PARAM_TYPE_OPTIONAL, &CreateSddl, (PVOID) NULL }, { "root", PARAM_TYPE_STRING | PARAM_TYPE_REQUIRED, &RootDir, (PVOID) NULL }, { "force", PARAM_TYPE_BOOL | PARAM_TYPE_SINGLE | PARAM_TYPE_OPTIONAL, &Force, (PVOID) NULL }, { "debug", PARAM_TYPE_ULONG | PARAM_TYPE_HIDDEN, &DebugFlag, (PVOID) NULL }, { "addself", PARAM_TYPE_BOOL | PARAM_TYPE_SINGLE | PARAM_TYPE_OPTIONAL, &AddSelf, (PVOID) TRUE }, { "sacl", PARAM_TYPE_BOOL | PARAM_TYPE_SINGLE | PARAM_TYPE_OPTIONAL, &DoSacl, (PVOID) NULL }
};
#define ARGSET ( (sizeof ( Parameters ) / sizeof( PARAM ) ) )
VOID DECLSPEC_NORETURN Usage( char * Me ) { int i ; printf("%s - usage\n", Me); for ( i = 0 ; i < ARGSET ; i++ ) { if ( ( Parameters[ i ].Flags & PARAM_TYPE_HIDDEN ) == 0 ) { printf("\t/%s%s\n", Parameters[i].Argument, Parameters[ i ].Flags & PARAM_TYPE_SINGLE ? "" : ":value" ); } } exit(1); }
VOID FatalError( PWSTR Message, DWORD Error, PWSTR Object ) { if ( Object ) { fprintf( stderr, "Fatal error %d while working on object %ws\n", Error, Object ); fputws( Message, stderr ); fputws( L"\n", stderr );
} else { fprintf( stderr, "Fatal error %d, %s\n", Error, Message ); } exit( Error );
}
VOID DoParam( int argc, char * argv[] ) { int i ; int j ; PSTR Arg ; PSTR Colon; PSTR Format ; BOOL Bail = FALSE ;
//
// Initialize Defaults:
//
for ( j = 0 ; j < ARGSET ; j++ ) { switch ( Parameters[ j ].Flags & PARAM_TYPE_MASK ) { case PARAM_TYPE_STRING: if ( Parameters[ j ].Default ) { RtlInitUnicodeString( (PUNICODE_STRING) Parameters[ j ].Value, (LPWSTR) Parameters[ j ].Default );
} else { ZeroMemory( Parameters[ j ].Value, sizeof( UNICODE_STRING ) ); } break;
case PARAM_TYPE_ULONG: * ((PULONG) Parameters[ j ].Value) = (ULONG) ((ULONG_PTR) Parameters[ j ].Default ); break;
case PARAM_TYPE_BOOL: * ((PBOOL) Parameters[ j ].Value) = (BOOL) ((ULONG_PTR) Parameters[ j ].Default ); break;
default: break;
}
}
for ( i = 1 ; i < argc ; i++ ) { Arg=argv[i];
if ( (*Arg == '/') || (*Arg == '-') ) {
Arg++ ;
Colon = strchr( Arg, ':' );
if ( Colon ) { *Colon = '\0'; }
//
// Scan through the possible arguments
//
for ( j = 0 ; j < ARGSET ; j++ ) { if ( _stricmp( Arg, Parameters[ j ].Argument ) == 0 ) { //
// Found a parameter that matched. Now, check the supplied type:
//
if ( ( Parameters[ j ].Flags & PARAM_TYPE_FOUND ) && ! ( Parameters[ j ].Flags & PARAM_TYPE_MULTIPLE ) ) { printf("%s can be specified only once\n", Arg ); Usage( argv[0] ); }
if ( Colon ) { *Colon++ = ':' ; }
if ( ( (Parameters[ j ].Flags & PARAM_TYPE_OPTIONAL) == 0 ) && ( ( Colon == NULL ) || ( *Colon == '\0' ) ) ) { printf("%s needs a value with it\n", Arg ); Usage( argv[0] );
}
if ( ( Colon != NULL ) && ( Parameters[ j ].Flags & PARAM_TYPE_SINGLE ) ) { printf("%s takes no value\n", Arg ); Usage( argv[0] ); }
switch ( Parameters[ j ].Flags & PARAM_TYPE_MASK ) { case PARAM_TYPE_STRING:
if ( !RtlCreateUnicodeStringFromAsciiz( (PUNICODE_STRING) Parameters[ j ].Value, Colon ) ) { printf("out of memory\n"); Usage( argv[0] ); } break;
case PARAM_TYPE_ULONG:
if ( !Colon ) { *((PULONG) Parameters[ j ].Value) = 0 ; } else { Format = "%ul" ;
if ( *Colon == '0' ) { //
// Possible different base.
//
if ( *(Colon + 1 ) ) { switch ( *(Colon + 1) ) { case 'x': Format = "%x" ; break;
case 'X': Format = "%X" ; break;
default: Format = "%ul" ; break;
} }
}
sscanf( Colon, Format, Parameters[ j ].Value ); } break;
case PARAM_TYPE_BOOL: if ( !Colon ) { *((PBOOL) Parameters[ j ].Value ) = TRUE ; } else { if ( *Colon == '1' ) { *((PBOOL) Parameters[ j ].Value ) = TRUE ; } else { *((PBOOL) Parameters[ j ].Value ) = FALSE ; } } break; default: Usage( argv[ 0 ] ); }
Parameters[ j ].Flags |= PARAM_TYPE_FOUND ;
break; // break out of for loop
}
} if ( j == ARGSET ) { printf("-%s unrecognized\n", Arg ); Usage( argv[ 0 ] ); }
} else { printf("%s unexpected\n", Arg ); Usage( argv[0] ); }
}
//
// Validate input:
//
Bail = FALSE ;
for ( j = 0 ; j < ARGSET ; j++ ) { if ( (Parameters[ j ].Flags & PARAM_TYPE_REQUIRED) ) { if ( ! ( Parameters[ j ].Flags & PARAM_TYPE_FOUND ) ) { printf(" /%s missing\n", Parameters[ j ].Argument ); Bail = TRUE ;
}
}
}
if ( Bail ) { Usage( argv[ 0 ] ); }
}
BOOL CheckRootFileSystem( VOID ) { WCHAR Volume[ 8 ]; WCHAR Temp[ MAX_PATH ]; DWORD Size ; DWORD FsFlags ;
if ( RootDir.Buffer[ 1 ] == L':' ) { Volume[ 0 ] = RootDir.Buffer[ 0 ]; Volume[ 1 ] = RootDir.Buffer[ 1 ]; } else { Size = MAX_PATH ;
GetCurrentDirectory( MAX_PATH, Temp );
Volume[ 0 ] = Temp[ 0 ]; Volume[ 1 ] = Temp[ 1 ];
}
Volume[ 2 ] = L'\\'; Volume[ 3 ] = L'\0';
if ( GetVolumeInformation( Volume, NULL, 0, NULL, &Size, &FsFlags, Temp, MAX_PATH ) ) { if ( FsFlags & FS_PERSISTENT_ACLS ) { return TRUE ; } }
return FALSE ; }
PWSTR GetTargetOfReparse( PWSTR ReparsePoint ) { HANDLE Handle ; NTSTATUS Status ; OBJECT_ATTRIBUTES ObjA ; UNICODE_STRING UnicodeName ; NTSTATUS IgnoreStatus ; IO_STATUS_BLOCK IoStatusBlock ; PWSTR Target = NULL ;
FILE_DISPOSITION_INFORMATION Disposition;
PREPARSE_DATA_BUFFER ReparseBufferHeader = NULL; PCHAR ReparseBuffer = NULL; ULONG ReparsePointTag = IO_REPARSE_TAG_RESERVED_ZERO; USHORT ReparseDataLength = 0; ULONG DesiredAccess ; ULONG CreateOptions ;
IgnoreStatus = RtlDosPathNameToNtPathName_U( ReparsePoint, &UnicodeName, NULL, NULL );
if ( !NT_SUCCESS( IgnoreStatus ) ) { return NULL ; }
InitializeObjectAttributes( &ObjA, &UnicodeName, OBJ_CASE_INSENSITIVE, NULL, NULL );
DesiredAccess = FILE_READ_DATA | SYNCHRONIZE; CreateOptions = FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT;
//
// Open the reparse point for query.
//
Status = NtOpenFile( &Handle, DesiredAccess, &ObjA, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, CreateOptions );
RtlFreeHeap( RtlProcessHeap(), 0, UnicodeName.Buffer );
if ( !NT_SUCCESS( Status ) ) { return NULL ; }
ReparseDataLength = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; ReparseBuffer = RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, ReparseDataLength );
if (ReparseBuffer == NULL) {
FatalError( L"No memory", ERROR_OUTOFMEMORY, ReparsePoint ); }
//
// Now go and get the data.
//
Status = NtFsControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_GET_REPARSE_POINT, // no input buffer
NULL, // input buffer length
0, (PVOID)ReparseBuffer, ReparseDataLength );
//
// Close the file and free the buffer.
//
NtClose( Handle );
//
// Display the buffer.
//
ReparseBufferHeader = (PREPARSE_DATA_BUFFER)ReparseBuffer;
if ((ReparseBufferHeader->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) || (ReparseBufferHeader->ReparseTag == IO_REPARSE_TAG_SYMBOLIC_LINK)) {
if ( DebugFlag ) { UNICODE_STRING NtLinkValue ;
NtLinkValue.Buffer = &ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer[ 0 ]; NtLinkValue.Length = ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameLength; NtLinkValue.MaximumLength = NtLinkValue.Length ;
printf("base path is %wZ\n", &NtLinkValue ); }
Target = LocalAlloc( LMEM_FIXED, (ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameLength + 1) * sizeof( WCHAR ) );
if ( Target ) { RtlCopyMemory( Target, &ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer[ ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof( WCHAR ) + 1 ], ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameLength ); }
}
else { }
//
// Free the buffer.
//
RtlFreeHeap( RtlProcessHeap(), 0, ReparseBufferHeader );
return Target ; }
PSECURITY_DESCRIPTOR GetRootSecurity( VOID ) { HANDLE hRoot ; NTSTATUS Status ; BOOLEAN WasEnabled ; PSECURITY_DESCRIPTOR psd ; ULONG Size ; SECURITY_INFORMATION si ; ACCESS_MASK access ; DWORD Returned ;
si = DACL_SECURITY_INFORMATION ; access = READ_CONTROL ;
if ( DoSacl ) { Status = RtlAdjustPrivilege( SE_SECURITY_PRIVILEGE, TRUE, FALSE, &WasEnabled );
if ( NT_SUCCESS( Status ) ) { si |= SACL_SECURITY_INFORMATION ; access |= ACCESS_SYSTEM_SECURITY ; } }
Size = 0 ; psd = NULL ;
GetFileSecurity( RootDir.Buffer, si, NULL, 0, &Size );
psd = LocalAlloc( LMEM_FIXED, Size );
if ( !GetFileSecurity( RootDir.Buffer, si, psd, Size, &Size ) ) { FatalError( L"Could not read security descriptor", GetLastError(), RootDir.Buffer );
}
return psd ; }
DWORD WriteSddlFile( VOID ) { PSECURITY_DESCRIPTOR psd ; ULONG Size ; LPSTR AnsiStringSD ; ULONG AnsiStringSDLen ; HANDLE hSddlFile ; CHAR Term[ 2 ] = { 0x0d, 0x0a };
psd = GetRootSecurity();
if ( !ConvertSecurityDescriptorToStringSecurityDescriptorA( psd, 1, DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, &AnsiStringSD, &AnsiStringSDLen ) ) {
FatalError( L"Cannot convert security descriptor to string\n", GetLastError(), NULL );
}
hSddlFile = CreateFile( SddlFile.Buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if ( hSddlFile == INVALID_HANDLE_VALUE ) { FatalError( L"Cannot write security descriptor to file", GetLastError(), SddlFile.Buffer );
}
WriteFile( hSddlFile, AnsiStringSD, AnsiStringSDLen, &Size, NULL );
LocalFree( AnsiStringSD );
WriteFile( hSddlFile, Term, sizeof(Term), &Size, NULL );
CloseHandle( hSddlFile );
return 0;
}
PSECURITY_DESCRIPTOR InsertMe( PSECURITY_DESCRIPTOR old, ACCESS_MASK AccessRequired ) { DWORD Size ; PACL OldAcl ; PACL NewAcl ; BOOL Present ; BOOL Ignored ; ACL_SIZE_INFORMATION AclSize ; PSID Me = NULL ; HANDLE hToken ; UCHAR Scratch[ SECURITY_MAX_SID_SIZE + sizeof( TOKEN_USER ) ]; PTOKEN_USER User ; PACCESS_ALLOWED_ACE NewAce ; PACCESS_ALLOWED_ACE OldAce ; PSECURITY_DESCRIPTOR psd ;
if ( OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ) ) { if ( GetTokenInformation( hToken, TokenUser, Scratch, sizeof( Scratch ), &Size ) ) { User = (PTOKEN_USER) Scratch ;
Me = User->User.Sid ; } CloseHandle( hToken ); }
if ( !Me ) { return NULL ; }
GetSecurityDescriptorDacl(old, &Present, &OldAcl, &Ignored ); if ( !Present ) { return NULL ; }
GetAclInformation( OldAcl, &AclSize, sizeof( AclSize ), AclSizeInformation );
NewAcl = LocalAlloc(LMEM_FIXED, AclSize.AclBytesInUse + (sizeof( ACCESS_ALLOWED_ACE ) + GetLengthSid( Me )));
if ( !NewAcl ) { return NULL ; }
InitializeAcl( NewAcl, AclSize.AclBytesInUse + (sizeof( ACCESS_ALLOWED_ACE ) + GetLengthSid( Me ) ), ACL_REVISION );
AddAccessAllowedAce( NewAcl, ACL_REVISION, AccessRequired, Me );
FindFirstFreeAce( NewAcl, &NewAce );
GetAce( OldAcl, 0, &OldAce );
CopyMemory( NewAce, OldAce, AclSize.AclBytesInUse - sizeof( ACL ));
NewAcl->AceCount += (USHORT) AclSize.AceCount ;
psd = LocalAlloc(LMEM_FIXED, sizeof( SECURITY_DESCRIPTOR ) );
if ( psd ) { InitializeSecurityDescriptor( psd, SECURITY_DESCRIPTOR_REVISION );
SetSecurityDescriptorDacl(psd, TRUE, NewAcl, FALSE ); }
return psd ;
}
//+---------------------------------------------------------------------------
//
// Function: ReadSecurityDescriptor
//
// Synopsis:
//
// Arguments: [SddlFileName] --
//
// Returns:
//
// Notes:
//
//----------------------------------------------------------------------------
PSECURITY_DESCRIPTOR ReadSecurityDescriptor( PWSTR SddlFileName ) {
HANDLE hFile ; PSECURITY_DESCRIPTOR psd ; ULONG Size ; ULONG SizeRead ; PUCHAR Buffer ; PSECURITY_DESCRIPTOR psdNew ;
hFile = CreateFileW( SddlFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile == INVALID_HANDLE_VALUE ) { FatalError( L"Unable to read ACL file", GetLastError(), SddlFile.Buffer );
}
Size = GetFileSize( hFile, NULL );
if ( Size == (DWORD) -1 ) { FatalError( L"ACL file corrupt, too large", 0, NULL );
}
Buffer = LocalAlloc( LMEM_FIXED, Size + 1 );
if ( !Buffer ) { FatalError( L"Out of memory", GetLastError(), NULL );
}
if ( !ReadFile( hFile, Buffer, Size, &SizeRead, NULL ) ) { FatalError( L"Unable to read ACL file", GetLastError(), SddlFile.Buffer );
}
CloseHandle( hFile );
Buffer[ Size ] = '\0';
while ( ( Buffer[ Size - 1 ] == 0x0a ) || ( Buffer[ Size - 1 ] == 0x0d ) || ( Buffer[ Size - 1 ] == 0x1a ) ) { Buffer[ Size - 1 ] = '\0' ; Size-- ;
}
if ( !ConvertStringSecurityDescriptorToSecurityDescriptorA( Buffer, 1, &psd, &Size ) ) {
FatalError( L"ACL file is corrupt", GetLastError(), SddlFile.Buffer ); }
LocalFree( Buffer );
if ( AddSelf ) { //
// Need to merge in a sid for "me"
//
psdNew = InsertMe( psd, FILE_ALL_ACCESS );
if ( psdNew ) { LocalFree( psd ); psd = psdNew ; } }
return psd ;
}
BOOL WalkCallback( PVOID Parameter, PWSTR Path ) {
return SetFileSecurity( Path, SecurityInfo, Parameter );
}
BOOL WalkEngine( PFS_WALK_CONTROL Control ) { PFS_WALK_CONTROL NewControl ; WIN32_FIND_DATA FindData ; PWSTR Scan; BOOL CallbackStatus ; DWORD Status ; DWORD FileTest ; DWORD Limit ; PSECURITY_DESCRIPTOR psd = NULL ; //
// First, check for an override file:
//
if ( wcslen( Control->CurrentPath ) > MAX_PATH - 7 ) { return FALSE ; }
wcsncpy( Control->SearchPath, Control->CurrentPath, MAX_PATH ); wcscat( Control->SearchPath, L"acl.txt" );
FileTest = GetFileAttributes( Control->SearchPath ); if ( FileTest != (DWORD) -1 ) { //
// File exists. Load it and use it for all files from here on down
//
psd = ReadSecurityDescriptor( Control->SearchPath );
if ( psd ) { Control->Parameter = psd ; }
}
wcscpy( Control->SearchPath, Control->CurrentPath ); wcscat( Control->SearchPath, L"*.*" );
Control->Search = FindFirstFile( Control->SearchPath, &FindData );
if ( Control->Search ) { wcscpy( Control->FilePath, Control->CurrentPath); Scan = &Control->FilePath[ wcslen( Control->FilePath ) ]; // one char past trailing backslash
Limit = MAX_PATH - wcslen( Control->FilePath );
do {
if ( wcslen( FindData.cFileName ) > Limit ) { Control->Stats->EngineErrors++ ; fprintf(stderr, "File '%ws' in directory '%ws' exceeds maximum length", FindData.cFileName, Control->CurrentPath ); continue; } wcscpy( Scan, FindData.cFileName );
if ( wcscmp( Scan,L".." ) == 0 ) { //
// always immediately skip the parent link
//
continue; }
CallbackStatus = Control->Callback( Control->Parameter, Control->FilePath );
if ( !CallbackStatus ) { Control->Stats->CallbackErrors ++ ; }
if ( wcscmp( Scan, L".") == 0 ) { //
// allow for processing the current directory,
// but do not recurse...
//
continue;
}
if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { //
// Time to recurse (we do depth first, it's easier)
//
Control->Stats->Directories++ ;
NewControl = LocalAlloc( LMEM_FIXED, sizeof( FS_WALK_CONTROL ) );
if ( NewControl ) { NewControl->Callback = Control->Callback ; NewControl->Parameter = Control->Parameter ; NewControl->Options = Control->Options ; NewControl->Stats = Control->Stats ;
wcscpy(NewControl->CurrentPath, Control->FilePath ); wcscat(NewControl->CurrentPath, L"\\");
WalkEngine( NewControl );
LocalFree( NewControl );
} else {
Control->Stats->EngineErrors ++ ; }
} else { Control->Stats->Files++ ;
}
} while ( FindNextFile( Control->Search, &FindData ) );
FindClose( Control->Search );
} else { Control->Stats->EngineErrors++ ; }
if ( psd ) { LocalFree( psd ); }
return TRUE ;
}
BOOL WalkTree( PWSTR StartPath, ULONG Options, PFS_WALK_CALLBACK Callback, PVOID Parameter ) {
PFS_WALK_CONTROL Control ; FS_ENGINE_STATS Stats ; PWSTR Scan;
Control = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof( FS_WALK_CONTROL ) );
if ( !Control ) { return FALSE ;
}
ZeroMemory( &Stats, sizeof( Stats ) );
Control->Callback = Callback ; Control->Parameter = Parameter ; Control->Options = 0 ; Control->Stats = &Stats ;
wcscpy( Control->CurrentPath, StartPath ); Scan = &Control->CurrentPath[ wcslen( Control->CurrentPath ) - 1 ]; if ( *Scan != L'\\' ) { Scan++ ; *Scan = L'\\';
}
if ( !Callback( Parameter, StartPath ) ) { Stats.CallbackErrors++ ; }
Stats.Directories = 1;
WalkEngine(Control);
if ( DebugFlag ) { printf("Directories \t%d\n", Stats.Directories ); printf("Files \t%d\n", Stats.Files ); printf("EngineErrors\t%d\n", Stats.EngineErrors ); printf("CallbackErrors\t%d\n", Stats.CallbackErrors );
}
return TRUE ; }
BOOL UpdateAcls( VOID ) {
PSECURITY_DESCRIPTOR psd ; NTSTATUS Status ; SECURITY_INFORMATION si ; SECURITY_DESCRIPTOR_CONTROL control ; ULONG ignored; BOOLEAN WasEnabled ;
psd = ReadSecurityDescriptor( SddlFile.Buffer );
if ( !psd ) { return FALSE ;
}
RtlGetControlSecurityDescriptor(psd,&control,&ignored);
si = 0 ;
if ( control & SE_DACL_PRESENT ) { si |= DACL_SECURITY_INFORMATION ;
}
if ( control & SE_SACL_PRESENT ) {
Status = RtlAdjustPrivilege( SE_SECURITY_PRIVILEGE, TRUE, FALSE, &WasEnabled );
if ( NT_SUCCESS( Status ) ) { si |= SACL_SECURITY_INFORMATION ; } }
SecurityInfo = si ;
printf("Updating ACLs from %ws for tree %ws\n", SddlFile.Buffer, RootDir.Buffer );
WalkTree(RootDir.Buffer, 0, WalkCallback, psd );
return TRUE ; }
BOOL TestAcl( VOID ) { PSECURITY_DESCRIPTOR Current ; PSECURITY_DESCRIPTOR Stored ; PACL CurrentAcl ; PACL StoredAcl ; ULONG CurrentLength ; ULONG StoredLength ; BOOL Match = FALSE ; NTSTATUS Status ; BOOLEAN Present ; BOOLEAN Defaulted ; ACL_SIZE_INFORMATION AclSize ;
Stored = ReadSecurityDescriptor( SddlFile.Buffer );
Status = RtlGetDaclSecurityDescriptor(Stored,&Present,&StoredAcl,&Defaulted);
if ( !NT_SUCCESS( Status ) ) { return FALSE ; }
Current = GetRootSecurity();
Status = RtlGetDaclSecurityDescriptor(Current,&Present,&CurrentAcl,&Defaulted); if ( !NT_SUCCESS( Status ) || (CurrentAcl == NULL) ) { return FALSE ; }
Status = RtlQueryInformationAcl(StoredAcl,&AclSize,sizeof(AclSize),AclSizeInformation);
if ( !NT_SUCCESS( Status ) ) { return FALSE ; }
StoredLength = AclSize.AclBytesInUse ;
Status = RtlQueryInformationAcl( CurrentAcl,&AclSize,sizeof(AclSize), AclSizeInformation );
if ( !NT_SUCCESS( Status ) ) { return FALSE ; }
CurrentLength = AclSize.AclBytesInUse;
if ( CurrentLength == StoredLength ) { Match = RtlEqualMemory( CurrentAcl, StoredAcl, CurrentLength ); }
LocalFree( Stored ); LocalFree( Current );
return Match ;
}
int __cdecl main (int argc, char *argv[]) {
DoParam( argc, argv );
if ( DebugFlag ) { printf("SDDL File \t%ws\n", SddlFile.Buffer ); printf("Root Dir \t%ws\n", RootDir.Buffer );
}
if ( CreateSddl ) { WriteSddlFile(); return 0 ; }
if ( !CheckRootFileSystem() ) { printf("Volume does not support ACLs\n" ); return 0 ; }
if ( !Force ) { if ( TestAcl() ) { if ( DebugFlag ) { printf("ACL is up-to-date\n" ); } return 0 ;
}
}
UpdateAcls();
}
|