454 lines
10 KiB
C
454 lines
10 KiB
C
|
|
/*************************************************************************
|
|
*
|
|
* dirwalk.c
|
|
*
|
|
* Walk a tree setting ACL's on an NT system.
|
|
*
|
|
* Copyright Microsoft, 1998
|
|
*
|
|
*
|
|
*
|
|
*************************************************************************/
|
|
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <process.h>
|
|
|
|
#include <winsta.h>
|
|
#include <syslib.h>
|
|
|
|
#include "security.h"
|
|
|
|
#if DBG
|
|
ULONG
|
|
DbgPrint(
|
|
PCH Format,
|
|
...
|
|
);
|
|
#define DBGPRINT(x) DbgPrint x
|
|
#if DBGTRACE
|
|
#define TRACE0(x) DbgPrint x
|
|
#define TRACE1(x) DbgPrint x
|
|
#else
|
|
#define TRACE0(x)
|
|
#define TRACE1(x)
|
|
#endif
|
|
#else
|
|
#define DBGPRINT(x)
|
|
#define TRACE0(x)
|
|
#define TRACE1(x)
|
|
#endif
|
|
|
|
|
|
// Global variables
|
|
PWCHAR gpAvoidDir = NULL;
|
|
|
|
CRITICAL_SECTION SyslibCritSect;
|
|
|
|
|
|
typedef BOOLEAN (CALLBACK* NODEPROC)( PWCHAR, PWIN32_FIND_DATAW, DWORD, DWORD );
|
|
|
|
BOOLEAN
|
|
EnumerateDirectory(
|
|
PWCHAR pRoot,
|
|
DWORD Level,
|
|
NODEPROC pProc
|
|
);
|
|
|
|
BOOLEAN
|
|
NodeEnumProc(
|
|
PWCHAR pParent,
|
|
PWIN32_FIND_DATA p,
|
|
DWORD Level,
|
|
DWORD Index
|
|
);
|
|
|
|
PWCHAR
|
|
AddWildCard(
|
|
PWCHAR pRoot
|
|
);
|
|
|
|
PWCHAR
|
|
AddBackSlash(
|
|
PWCHAR pRoot
|
|
);
|
|
|
|
FILE_RESULT
|
|
xxxProcessFile(
|
|
PWCHAR pParent,
|
|
PWIN32_FIND_DATAW p,
|
|
DWORD Level,
|
|
DWORD Index
|
|
);
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* CtxGetSyslibCritSect
|
|
*
|
|
* Returns the library global critical section pointer.
|
|
* Critical section will be initialised if necessary
|
|
*
|
|
* ENTRY:
|
|
* VOID - Caller must ensure that only one threads a times calls this
|
|
* function. The function will not itself guarantie mutual exclusion.
|
|
* EXIT:
|
|
* Pointer to critical section. NULL if failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
|
|
PCRITICAL_SECTION
|
|
CtxGetSyslibCritSect(void)
|
|
{
|
|
static BOOLEAN fInitialized = FALSE;
|
|
NTSTATUS Status;
|
|
|
|
if( !fInitialized ){
|
|
|
|
Status = RtlInitializeCriticalSection(&SyslibCritSect);
|
|
if (NT_SUCCESS(Status)) {
|
|
fInitialized = TRUE;
|
|
}else{
|
|
return NULL;
|
|
}
|
|
|
|
}
|
|
return(&SyslibCritSect);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* SetFileTree
|
|
*
|
|
* Walk the given tree calling the processing function for each node.
|
|
*
|
|
* ENTRY:
|
|
* pRoot (input)
|
|
* Full WIN32 path to directory to walk
|
|
*
|
|
* pVoidDir (input)
|
|
*
|
|
* EXIT:
|
|
* STATUS_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN
|
|
SetFileTree(
|
|
PWCHAR pRoot,
|
|
PWCHAR pAvoidDir
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
PWCHAR pRootNew;
|
|
static BOOLEAN fInitialized = FALSE;
|
|
PRTL_CRITICAL_SECTION pLock = CtxGetSyslibCritSect();
|
|
|
|
// if critical section could not be created, do nothing.
|
|
|
|
if (pLock == NULL) {
|
|
return FALSE;
|
|
}
|
|
DBGPRINT(( "entering SetFileTree(pRoot=%ws,pAvoidDir=%ws)\n", pRoot, pAvoidDir ));
|
|
|
|
EnterCriticalSection(pLock);
|
|
// If this is the console make sure the user hasn't changed
|
|
|
|
if ((NtCurrentPeb()->SessionId == 0) && fInitialized) {
|
|
CheckUserSid();
|
|
|
|
} else if ( !fInitialized ) {
|
|
fInitialized = TRUE;
|
|
if ( !InitSecurity() ) {
|
|
DBGPRINT(( "problem initializing security; we're outta here.\n" ));
|
|
LeaveCriticalSection(pLock);
|
|
return( 1 ); // (non-zero for error...)// Should be return FALSE!?
|
|
}
|
|
}
|
|
LeaveCriticalSection(pLock);
|
|
|
|
gpAvoidDir = pAvoidDir;
|
|
|
|
// be sure to apply security to root directory
|
|
pRootNew = AddBackSlash(pRoot);
|
|
if(pRootNew) {
|
|
DBGPRINT(( "processing file %ws\n", pRootNew ));
|
|
xxxProcessFile(pRootNew, NULL, 0, 0);
|
|
LocalFree(pRootNew);
|
|
}
|
|
|
|
rc = EnumerateDirectory( pRoot, 0, NodeEnumProc );
|
|
DBGPRINT(( "leaving SetFileTree()\n" ));
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* EnumerateDirectory
|
|
*
|
|
* Walk the given directory calling the processing function for each file.
|
|
*
|
|
* ENTRY:
|
|
* pRoot (input)
|
|
* Full WIN32 path to directory to walk
|
|
*
|
|
* Level (input)
|
|
* Level we are in a given tree. Useful for formating output
|
|
*
|
|
* pProc (input)
|
|
* Procedure to call for each non-directory file
|
|
*
|
|
* EXIT:
|
|
* STATUS_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN
|
|
EnumerateDirectory(
|
|
PWCHAR pRoot,
|
|
DWORD Level,
|
|
NODEPROC pProc
|
|
)
|
|
{
|
|
BOOL rc;
|
|
DWORD Result;
|
|
HANDLE hf;
|
|
DWORD Index;
|
|
WIN32_FIND_DATA Data;
|
|
PWCHAR pRootNew;
|
|
|
|
DBGPRINT(( "entering EnumerateDirectory(pRoot=%ws,Level=%ld,pProc=NodeEnumProc)\n",pRoot,Level ));
|
|
|
|
if( pRoot == NULL ) {
|
|
DBGPRINT(( "leaving EnumerateDirectory(), return=FALSE\n" ));
|
|
return( FALSE );
|
|
}
|
|
|
|
// Make sure it is not one we want to avoid
|
|
if( gpAvoidDir ) {
|
|
DWORD Len = wcslen( gpAvoidDir );
|
|
|
|
if( _wcsnicmp( pRoot, gpAvoidDir, Len ) == 0 ) {
|
|
DBGPRINT(( "leaving EnumerateDirectory(), return=FALSE\n" ));
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
pRootNew = AddWildCard( pRoot );
|
|
if( pRootNew == NULL ) {
|
|
DBGPRINT(( "leaving EnumerateDirectory(), return=FALSE\n" ));
|
|
return( FALSE );
|
|
}
|
|
|
|
Index = 0;
|
|
|
|
DBGPRINT(("FindFirstFileW: %ws\n",pRootNew));
|
|
|
|
hf = FindFirstFileW(
|
|
pRootNew,
|
|
&Data
|
|
);
|
|
|
|
if( hf == INVALID_HANDLE_VALUE ) {
|
|
DBGPRINT(("EnumerateDirectory: Error %d opening root %ws\n",GetLastError(),pRootNew));
|
|
LocalFree( pRootNew );
|
|
DBGPRINT(( "leaving EnumerateDirectory(), return=FALSE\n" ));
|
|
return(FALSE);
|
|
}
|
|
|
|
while( 1 ) {
|
|
|
|
// pass the parent without the wildcard added
|
|
pProc( pRoot, &Data, Level, Index );
|
|
|
|
rc = FindNextFile(
|
|
hf,
|
|
&Data
|
|
);
|
|
|
|
if( !rc ) {
|
|
Result = GetLastError();
|
|
if( Result == ERROR_NO_MORE_FILES ) {
|
|
FindClose( hf );
|
|
LocalFree( pRootNew );
|
|
DBGPRINT(( "leaving EnumerateDirectory(), return=TRUE\n" ));
|
|
return( TRUE );
|
|
}
|
|
else {
|
|
DBGPRINT(("EnumerateDirectory: Error %d, Index 0x%x\n",Result,Index));
|
|
FindClose( hf );
|
|
LocalFree( pRootNew );
|
|
DBGPRINT(( "leaving EnumerateDirectory(), return=FALSE\n" ));
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
Index++;
|
|
}
|
|
|
|
// UNREACHABLE.
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* NodeEnumProc
|
|
*
|
|
* Process the enumerated file
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* STATUS_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN
|
|
NodeEnumProc(
|
|
PWCHAR pParent,
|
|
PWIN32_FIND_DATAW p,
|
|
DWORD Level,
|
|
DWORD Index
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
PWCHAR pParentNew;
|
|
DWORD ParentCount, ChildCount;
|
|
|
|
//
|
|
// We must append the directory to our parent path to get the
|
|
// new full path.
|
|
//
|
|
|
|
ParentCount = wcslen( pParent );
|
|
ChildCount = wcslen( p->cFileName );
|
|
|
|
pParentNew = LocalAlloc( LMEM_FIXED, (ParentCount + ChildCount + 2)*sizeof(WCHAR) );
|
|
|
|
if( pParentNew == NULL ) return( FALSE );
|
|
|
|
wcscpy( pParentNew, pParent );
|
|
wcscat( pParentNew, L"\\" );
|
|
wcscat( pParentNew, p->cFileName );
|
|
|
|
if( p->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
|
|
|
|
// Skip "." and ".."
|
|
if( wcscmp( L".", p->cFileName ) == 0 ) {
|
|
LocalFree( pParentNew );
|
|
return( TRUE );
|
|
}
|
|
|
|
if( wcscmp( L"..", p->cFileName ) == 0 ) {
|
|
LocalFree( pParentNew );
|
|
return( TRUE );
|
|
}
|
|
|
|
TRACE0(("%ws:\n",pParentNew));
|
|
|
|
xxxProcessFile( pParentNew, p, Level, Index );
|
|
|
|
// For directories, we recurse
|
|
rc = EnumerateDirectory( pParentNew, Level+1, NodeEnumProc );
|
|
|
|
LocalFree( pParentNew );
|
|
|
|
return( rc );
|
|
}
|
|
|
|
TRACE0(("%ws\n",pParentNew));
|
|
|
|
xxxProcessFile( pParentNew, p, Level, Index );
|
|
|
|
LocalFree( pParentNew );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* AddWildCard
|
|
*
|
|
* Add the wild card search specifier
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* STATUS_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
PWCHAR
|
|
AddWildCard(
|
|
PWCHAR pRoot
|
|
)
|
|
{
|
|
DWORD Count;
|
|
PWCHAR pNew;
|
|
PWCHAR WildCard = L"\\*";
|
|
|
|
Count = wcslen( pRoot );
|
|
pNew = LocalAlloc( LMEM_FIXED, (Count + wcslen(WildCard) + 1)*sizeof(WCHAR) );
|
|
|
|
if( pNew == NULL ) {
|
|
return( NULL );
|
|
}
|
|
|
|
wcscpy( pNew, pRoot );
|
|
wcscat( pNew, WildCard );
|
|
|
|
return( pNew );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* AddBackSlash
|
|
*
|
|
* Add the backslash character to path
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* STATUS_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
PWCHAR
|
|
AddBackSlash(
|
|
PWCHAR pRoot
|
|
)
|
|
{
|
|
DWORD Count;
|
|
PWCHAR pNew;
|
|
PWCHAR BackSlash = L"\\";
|
|
|
|
Count = wcslen( pRoot );
|
|
pNew = LocalAlloc( LMEM_FIXED, (Count + wcslen(BackSlash) + 1)*sizeof(WCHAR) );
|
|
|
|
if( pNew == NULL ) {
|
|
return( NULL );
|
|
}
|
|
|
|
wcscpy( pNew, pRoot );
|
|
|
|
// only add backslash if string doesn't already have it
|
|
if(*(pRoot+Count-1) != L'\\')
|
|
wcscat( pNew, BackSlash );
|
|
|
|
return( pNew );
|
|
}
|
|
|
|
|