Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1340 lines
31 KiB

//+---------------------------------------------------------------------------
//
// 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();
}