📄 pathproc.c
字号:
/*
* Copyright (c) 2004 Security Architects Corporation. All rights reserved.
*
* Module Name:
*
* pathproc.c
*
* Abstract:
*
* This module implements various pathname handling routines.
*
* Author:
*
* Eugene Tsyrklevich 19-Feb-2004
*
* Revision History:
*
* None.
*/
#include "pathproc.h"
#include "procname.h"
#include "policy.h"
#include "learn.h"
#include "log.h"
/*
* ResolveFilename() XXX rewrite
*
* Description:
* Get canonical name for a file by resolving symbolic links.
*
* Parameters:
* szFileName - filename to resolve.
* szResult - output buffer.
* szResultSize - size of an output buffer.
*
* Returns:
* TRUE to indicate success, FALSE if failed.
*/
BOOLEAN
ResolveFilename(IN PCHAR szFileName, OUT PCHAR szResult, IN USHORT szResultSize)
{
CHAR *p, c;
OBJECT_ATTRIBUTES oa;
ANSI_STRING FileNameAnsi;
UNICODE_STRING FileNameUnicode;
HANDLE hLink;
NTSTATUS rc;
int NumberOfLinks = 0;
WCHAR buffer[chMAX_PATH];
CHAR buffer2[chMAX_PATH];
restart:
*szResult = '\0';
if (szFileName[0] == '\\' && szFileName[1] == '\\')
szFileName++;
/* move to the end of the object name */
for (p = szFileName; *p != '\0'; p++)
;
/* process the object name from end to the beginning */
while (p != szFileName)
{
/* find the last slash */
if (*p != '\\' && *p != '\0')
{
p--;
continue;
}
c = *p;
*p = '\0';
RtlInitAnsiString(&FileNameAnsi, szFileName);
RtlAnsiStringToUnicodeString(&FileNameUnicode, &FileNameAnsi, TRUE);
InitializeObjectAttributes(&oa, &FileNameUnicode, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
rc = ZwOpenSymbolicLinkObject(&hLink, GENERIC_READ, &oa);
if (NT_SUCCESS(rc))
{
UNICODE_STRING target;
ANSI_STRING targeta;
target.Buffer = buffer;
target.MaximumLength = bMAX_PATH;
target.Length = 0;
rc = ZwQuerySymbolicLinkObject(hLink, &target, NULL);
ZwClose(hLink);
if (NT_SUCCESS(rc))
{
targeta.Length = 0;
targeta.MaximumLength = szResultSize;
targeta.Buffer = szResult;
RtlUnicodeStringToAnsiString(&targeta, &target, FALSE);
targeta.Buffer[targeta.Length] = '\0';
//XXX szResultSize -= targeta.Length;
RtlFreeUnicodeString(&FileNameUnicode);
*p = c;
//XXX can we have circular links?
if (NumberOfLinks++ < MAX_NUMBER_OF_LINKS)
{
strncat(szResult, p, szResultSize);
// if (NumberOfLinks > 1)
// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("ResolveFilename: NumberOfLinks=%d. Resolved %s to %s. Restarting.\n", NumberOfLinks, szFileName, szResult));
/*
* switch szFileName to a different buffer. we cannot reuse szFileName buffer
* since the resolved link might end up being longer than the original buffer
*/
szFileName = (PCHAR) buffer2;
strcpy(szFileName, szResult);
goto restart;
}
LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("ResolveFilename: NumberOfLinks=%d. bailing out. %s\n", NumberOfLinks, szResult));
break;
}
}
RtlFreeUnicodeString(&FileNameUnicode);
*p-- = c;
}
strncat(szResult, p, szResultSize);
// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("ResolveFilename: name=%s number of links=%d\n", szResult, NumberOfLinks));
return TRUE;
}
BOOLEAN
ResolveFilenameW(IN PUNICODE_STRING szFileName, OUT PCHAR szResult, IN USHORT szResultSize)
{
WCHAR *p, c;
OBJECT_ATTRIBUTES oa;
ANSI_STRING FileNameAnsi;
UNICODE_STRING FileNameUnicode;
HANDLE hLink;
NTSTATUS rc;
int NumberOfLinks = 0;
WCHAR buffer[chMAX_PATH];
USHORT OriginalLength;
UNICODE_STRING target;
ANSI_STRING targeta;
ASSERT(szFileName);
ASSERT(szResult);
OriginalLength = szFileName->Length;
restart:
*szResult = '\0';
/* move to the end of the object name */
p = (PWCHAR) ((PCHAR)szFileName->Buffer + szFileName->Length);
/* process the object name from end to the beginning */
while (p != szFileName->Buffer)
{
/* find the last slash */
// p = wcsrchr(p, L'\\');
/*
if (p == NULL)
{
p = szFileName->Buffer;
break;
}
*/
if (*p != L'\\' && *p != L'\0')
{
p--;
continue;
}
c = *p;
*p = L'\0';
// szFileName->Length = OriginalLength - (p - szFileName->Buffer);
// RtlInitAnsiString(&FileNameAnsi, szFileName);
// RtlAnsiStringToUnicodeString(&FileNameUnicode, &FileNameAnsi, TRUE);
// InitializeObjectAttributes(&oa, &FileNameUnicode, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
InitializeObjectAttributes(&oa, szFileName, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
rc = ZwOpenSymbolicLinkObject(&hLink, GENERIC_READ, &oa);
if (! NT_SUCCESS(rc))
{
*p-- = c;
continue;
}
target.Buffer = buffer;
target.MaximumLength = bMAX_PATH;
target.Length = 0;
rc = ZwQuerySymbolicLinkObject(hLink, &target, NULL);
ZwClose(hLink);
if (! NT_SUCCESS(rc))
{
*p-- = c;
continue;
}
*p = c;
//XXX can we have circular links?
if (NumberOfLinks++ < MAX_NUMBER_OF_LINKS)
{
wcscat(buffer, p);
RtlInitUnicodeString(szFileName, buffer);
goto restart;
}
LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("ResolveFilename: NumberOfLinks=%d. bailing out. %s\n", NumberOfLinks, szResult));
break;
}
// wcscat(szResult, p);
// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("ResolveFilename: name=%s number of links=%d\n", szResult, NumberOfLinks));
return TRUE;
}
/*
* GetPathFromOA()
*
* Description:
* Resolve an object handle to an object name.
*
* Parameters:
* ObjectAttributes - opaque structure describing an object handle.
* OutBuffer - output buffer where an object name will be saved to.
* OutBufferSize - size of an output buffer.
* ResolveLinks - do symbolic links need to be resolved?
*
* Returns:
* TRUE to indicate success, FALSE if failed.
*/
#define FINISH_GetPathFromOA(msg) \
do { \
LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, msg); \
return FALSE; \
} while(0)
BOOLEAN
GetPathFromOA(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PCHAR OutBuffer, IN USHORT OutBufferSize, IN BOOLEAN ResolveLinks)
{
NTSTATUS rc;
PVOID Object = NULL;
ULONG len;
CHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + bMAX_PATH];
POBJECT_NAME_INFORMATION pONI = (POBJECT_NAME_INFORMATION) Buffer;
BOOLEAN ret = FALSE;
UNICODE_STRING ObjectName;
PUNICODE_STRING pusFilename = NULL;
ANSI_STRING name;
if (! ARGUMENT_PRESENT(ObjectAttributes) || OutBuffer == NULL)
return(FALSE);
try
{
if (KeGetPreviousMode() != KernelMode)
ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
if (ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES))
FINISH_GetPathFromOA(("GetPathFromOA: Invalid ObjectAttributes length %d\n", ObjectAttributes->Length));
if (! ARGUMENT_PRESENT(ObjectAttributes->ObjectName) )
return FALSE;
if (KeGetPreviousMode() != KernelMode)
{
ProbeForRead(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), sizeof(ULONG));
ObjectName = ProbeAndReadUnicodeString(ObjectAttributes->ObjectName);
}
else
{
ObjectName = *ObjectAttributes->ObjectName;
}
if (ObjectName.Length == 0)
return FALSE;
if (((ObjectName.Length & (sizeof(WCHAR) - 1)) != 0) ||
(ObjectName.Length > bMAX_PATH - sizeof(WCHAR)) )
FINISH_GetPathFromOA(("GetPathFromOA: invalid wchar string length = %d\n", ObjectName.Length));
if (KeGetPreviousMode() != KernelMode)
ProbeForRead(ObjectName.Buffer, ObjectName.Length, sizeof(WCHAR));
}
except(EXCEPTION_EXECUTE_HANDLER)
{
NTSTATUS status = GetExceptionCode();
LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("GetPathFromOA(): caught an exception. status = 0x%x\n", status));
return FALSE;
}
pusFilename = &ObjectName;
/*
* is the filename referenced in relation to some directory?
* if so, append the filename to a specified directory name
*/
if (ARGUMENT_PRESENT(ObjectAttributes->RootDirectory))
{
if (! NT_SUCCESS( ObReferenceObjectByHandle(ObjectAttributes->RootDirectory, 0, 0,
KernelMode, &Object, NULL) ))
{
FINISH_GetPathFromOA(("GetPathFromOA(): ObReferenceObjectByHandle() failed. Object = %x\n", Object));
}
if (Object == NULL)
{
FINISH_GetPathFromOA(("GetPathFromOA(): Object = NULL\n"));
}
if (! NT_SUCCESS( ObQueryNameString(Object, pONI, bMAX_PATH, &len) ))
{
ObDereferenceObject(Object);
FINISH_GetPathFromOA(("GetPathFromOA(): ObQueryNameString() failed\n"));
}
ObDereferenceObject(Object);
Object = NULL;
/* extracted directory name */
pusFilename = &pONI->Name;
/* is the directory name too long? */
if (pusFilename->Length >= bMAX_PATH - sizeof(WCHAR))
FINISH_GetPathFromOA(("GetPathFromOA(): directory name is too long\n"));
/*
* pusFilename points to a buffer of MAX_PATH size, ObQueryNameString() sets MaximumLength to the length
* of the directory name, we need to reset this back to MAX_PATH to be able to append a filename
* (reusing the same buffer)
*/
pusFilename->MaximumLength = bMAX_PATH;
if (pusFilename->Buffer[ (pusFilename->Length / sizeof(WCHAR)) - 1 ] != L'\\')
{
pusFilename->Buffer[ pusFilename->Length / sizeof(WCHAR) ] = L'\\';
pusFilename->Length += sizeof(WCHAR);
}
if (RtlAppendUnicodeStringToString(pusFilename, ObjectAttributes->ObjectName) == STATUS_BUFFER_TOO_SMALL)
{
LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("GetPathFromOA: 1 %S\n", pusFilename->Buffer));
LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("GetPathFromOA: 2 %S\n", ObjectAttributes->ObjectName->Buffer));
FINISH_GetPathFromOA(("GetPathFromOA(): RtlAppendUnicodeStringToString() = STATUS_BUFFER_TOO_SMALL\n"));
}
}
if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&name, pusFilename, TRUE)))
{
if (ResolveLinks == TRUE)
{
ret = ResolveFilename(name.Buffer, OutBuffer, OutBufferSize);
}
else
{
if (name.Length >= OutBufferSize - 1)
{
LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("GetPathFromOA: Pathname too long %d\n", name.Length));
OutBuffer[0] = 0;
ret = FALSE;
}
else
{
strcpy(OutBuffer, name.Buffer);
ret = TRUE;
}
}
RtlFreeAnsiString(&name);
}
// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("%d GetPathFromOA: %s (%S)\n", (ULONG) PsGetCurrentProcessId(), OutBuffer, pusFilename->Buffer));
return ret;
}
BOOLEAN
GetPathFromOAW(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PCHAR OutBuffer, IN USHORT OutBufferSize, IN BOOLEAN ResolveLinks)
{
NTSTATUS rc;
PVOID Object = NULL;
ULONG len;
CHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + bMAX_PATH];
POBJECT_NAME_INFORMATION pONI = (POBJECT_NAME_INFORMATION) Buffer;
BOOLEAN ret = FALSE;
UNICODE_STRING ObjectName;
PUNICODE_STRING pusFilename = NULL;
ANSI_STRING name;
if (! ARGUMENT_PRESENT(ObjectAttributes) || OutBuffer == NULL)
return(FALSE);
try
{
if (KeGetPreviousMode() != KernelMode)
ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
if (ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES))
FINISH_GetPathFromOA(("GetPathFromOA: Invalid ObjectAttributes length %d\n", ObjectAttributes->Length));
if (! ARGUMENT_PRESENT(ObjectAttributes->ObjectName) )
return FALSE;
if (KeGetPreviousMode() != KernelMode)
{
ProbeForRead(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), sizeof(ULONG));
ObjectName = ProbeAndReadUnicodeString(ObjectAttributes->ObjectName);
}
else
{
ObjectName = *ObjectAttributes->ObjectName;
}
if (ObjectName.Length == 0)
return FALSE;
if (((ObjectName.Length & (sizeof(WCHAR) - 1)) != 0) ||
(ObjectName.Length > bMAX_PATH - sizeof(WCHAR)) )
FINISH_GetPathFromOA(("GetPathFromOA: invalid wchar string length = %d\n", ObjectName.Length));
if (KeGetPreviousMode() != KernelMode)
ProbeForRead(ObjectName.Buffer, ObjectName.Length, sizeof(WCHAR));
}
except(EXCEPTION_EXECUTE_HANDLER)
{
NTSTATUS status = GetExceptionCode();
LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("GetPathFromOA(): caught an exception. status = 0x%x\n", status));
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -