windows-nt/Source/XPSP1/NT/termsrv/syslib/dirwalk.c
2020-09-26 16:20:57 +08:00

454 lines
9.6 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 );
}