|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
eclient.c
Abstract:
EFS RPC client code.
Author:
Robert Gu (RobertG) Aug, 1997
Environment:
Revision History:
--*/
#include <string.h>
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <ntrpcp.h> // prototypes for MIDL user functions
#include <wincrypt.h>
#include <efsrpc.h>
#include <efsstruc.h>
#include <dfsfsctl.h>
#include <rpcasync.h>
#define WEBPROV L"Web Client Network"
#define DAVHEADER 0x01
//
// Internal prototypes
//
void __RPC_FAR EfsPipeAlloc( char __RPC_FAR * State, unsigned long ReqSize, unsigned char __RPC_FAR * __RPC_FAR * Buf, unsigned long __RPC_FAR * RealSize );
void __RPC_FAR EfsPipeRead ( char __RPC_FAR * State, unsigned char __RPC_FAR * DataBuf, unsigned long ByteCount );
void __RPC_FAR EfsPipeWrite ( char __RPC_FAR * State, unsigned char __RPC_FAR * DataBuf, unsigned long ByteRequested, unsigned long *ByteFromCaller );
DWORD GetFullName( LPCWSTR FileName, LPWSTR *FullName, LPWSTR *ServerName, ULONG Flags, DWORD dwCreationDistribution, DWORD dwAttributes, PSECURITY_DESCRIPTOR pRelativeSD, BOOL bInheritHandle );
DWORD EnablePrivilege( ULONG Flags, HANDLE *TokenHandle, PTOKEN_PRIVILEGES *OldPrivs );
VOID RestorePrivilege( HANDLE *TokenHandle, PTOKEN_PRIVILEGES *OldPrivs );
DWORD EnablePrivilege( ULONG Flags, HANDLE *TokenHandle, PTOKEN_PRIVILEGES *OldPrivs ) {
TOKEN_PRIVILEGES Privs; DWORD RetCode = ERROR_SUCCESS;
BOOL b; DWORD ReturnLength;
*TokenHandle = NULL; *OldPrivs = NULL;
*OldPrivs = ( TOKEN_PRIVILEGES *) RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( TOKEN_PRIVILEGES ) );
if ( *OldPrivs == NULL ){
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// We're impersonating, use the thread token.
//
b = OpenThreadToken( GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, TokenHandle );
if (!b) { b = OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, TokenHandle ); }
if ( b ) {
//
// We've got a token handle
//
//
// If we're doing a create for import, enable restore privilege,
// otherwise enable backup privilege.
//
Privs.PrivilegeCount = 1; Privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if ( !(Flags & CREATE_FOR_IMPORT) ){
Privs.Privileges[0].Luid = RtlConvertLongToLuid(SE_BACKUP_PRIVILEGE);
} else {
Privs.Privileges[0].Luid = RtlConvertLongToLuid(SE_RESTORE_PRIVILEGE); }
ReturnLength = sizeof( TOKEN_PRIVILEGES );
(VOID) AdjustTokenPrivileges ( *TokenHandle, FALSE, &Privs, sizeof( TOKEN_PRIVILEGES ), *OldPrivs, &ReturnLength );
if ( ERROR_SUCCESS != (RetCode = GetLastError()) ) {
//
// Privilege adjust failed
//
CloseHandle( *TokenHandle ); *TokenHandle = NULL; RtlFreeHeap( RtlProcessHeap(), 0, *OldPrivs ); *OldPrivs = NULL;
}
} else { *TokenHandle = NULL; RtlFreeHeap( RtlProcessHeap(), 0, *OldPrivs ); *OldPrivs = NULL; }
return RetCode; }
VOID RestorePrivilege( HANDLE *TokenHandle, PTOKEN_PRIVILEGES *OldPrivs ) { if (!TokenHandle || !OldPrivs || !(*TokenHandle) || !(*OldPrivs)) { return; } (VOID) AdjustTokenPrivileges ( *TokenHandle, FALSE, *OldPrivs, 0, NULL, NULL );
CloseHandle( *TokenHandle ); *TokenHandle = 0; RtlFreeHeap( RtlProcessHeap(), 0, *OldPrivs ); *OldPrivs = NULL; }
DWORD EfsOpenFileRawRPCClient( IN LPCWSTR FileName, IN ULONG Flags, OUT PVOID * Context )
/*++
Routine Description:
This routine is the client side of EfsOpenFileRaw. It establishes the connection to the server. And then call the server to finish the task.
Arguments:
FileName -- File name of the file to be exported
Flags -- Indicating if open for export or import; for directory or file.
Context - Export context to be used by READ operation later. Caller should pass this back in ReadRaw().
Return Value:
Result of the operation.
--*/ { DWORD RetCode; handle_t binding_h; NTSTATUS Status; PEXIMPORT_CONTEXT_HANDLE RawContext; LPWSTR FullName; LPWSTR Server; HANDLE TokenHandle; PTOKEN_PRIVILEGES OldPrivs;
*Context = NULL; RetCode = GetFullName( FileName, &FullName, &Server, Flags, 0, 0, NULL, FALSE );
if ( RetCode == ERROR_SUCCESS ){
(VOID) EnablePrivilege( Flags, &TokenHandle, &OldPrivs );
Status = RpcpBindRpc ( Server, L"lsarpc", L"security=Impersonation static true", &binding_h );
if (NT_SUCCESS(Status)){ RpcTryExcept { RetCode = EfsRpcOpenFileRaw( binding_h, &RawContext, FullName, Flags ); if ( ERROR_SUCCESS == RetCode ){
//
// Send the context handle back to the user
//
*Context = (PVOID) RawContext; } } RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { RetCode = RpcExceptionCode(); } RpcEndExcept;
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h ); } else { RetCode = RtlNtStatusToDosError( Status ); }
RestorePrivilege( &TokenHandle, &OldPrivs );
RtlFreeHeap( RtlProcessHeap(), 0, FullName ); RtlFreeHeap( RtlProcessHeap(), 0, Server ); }
return RetCode; }
VOID EfsCloseFileRawRPCClient( IN PVOID Context ) /*++
Routine Description:
This routine is the client side of EfsCloseFileRaw.
Arguments:
Context - Export/Import context used by READ/WRITE raw data.
Return Value:
None.
--*/ {
PEXIMPORT_CONTEXT_HANDLE phContext;
phContext = (PEXIMPORT_CONTEXT_HANDLE) Context; RpcTryExcept { EfsRpcCloseRaw( &phContext );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { } RpcEndExcept;
}
DWORD EfsReadFileRawRPCClient( IN PFE_EXPORT_FUNC ExportCallback, IN PVOID CallbackContext, IN PVOID Context ) /*++
Routine Description:
This routine is the client side of EfsReadFileRaw.
Arguments:
ExportCallback - Caller provided callback function.
CallbackContext - Caller's context.
Context - Export context used by READ raw data.
Return Value:
None. */ { PEXIMPORT_CONTEXT_HANDLE phContext; EFS_EXIM_STATE Pipe_State; EFS_EXIM_PIPE ExportPipe; DWORD RetCode;
if ( NULL == Context){ return ERROR_ACCESS_DENIED; }
phContext = ( PEXIMPORT_CONTEXT_HANDLE ) Context;
//
// Try to allocate a reasonable size buffer. The size can be fine tuned later, but should
// at least one page plus 4K. FSCTL_OUTPUT_LESS_LENGTH should be n * page size.
// FSCTL_OUTPUT_MIN_LENGTH can be fine tuned later. It should be at least one page
// plus 4K.
//
Pipe_State.BufLength = FSCTL_OUTPUT_INITIAL_LENGTH; Pipe_State.WorkBuf = NULL;
while ( !Pipe_State.WorkBuf && (Pipe_State.BufLength >= FSCTL_OUTPUT_MIN_LENGTH) ){
Pipe_State.WorkBuf = RtlAllocateHeap( RtlProcessHeap(), 0, Pipe_State.BufLength ); if ( !Pipe_State.WorkBuf ){
//
// Memory allocation failed.
// Try smaller allocation.
//
Pipe_State.BufLength -= FSCTL_OUTPUT_LESS_LENGTH;
}
} if (!Pipe_State.WorkBuf){ return ERROR_OUTOFMEMORY; }
Pipe_State.ExImCallback = (PVOID) ExportCallback; Pipe_State.CallbackContext = CallbackContext; Pipe_State.Status = NO_ERROR; ExportPipe.state = (char *) &Pipe_State; ExportPipe.alloc = EfsPipeAlloc; ExportPipe.pull = NULL; ExportPipe.push = EfsPipeRead;
RpcTryExcept{
RetCode = EfsRpcReadFileRaw( phContext, &ExportPipe );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { if ( NO_ERROR == Pipe_State.Status ){ RetCode = RpcExceptionCode(); } else { RetCode = Pipe_State.Status; } } RpcEndExcept;
RtlFreeHeap( RtlProcessHeap(), 0, Pipe_State.WorkBuf );
return RetCode; }
DWORD EfsWriteFileRawRPCClient( IN PFE_IMPORT_FUNC ImportCallback, IN PVOID CallbackContext, IN PVOID Context ) /*++
Routine Description:
This routine is the client side of EfsWriteFileRaw.
Arguments:
ImportCallback - Caller provided callback function.
CallbackContext - Caller's context.
Context - Import context used by WRITE raw data.
Return Value:
None. */ { PEXIMPORT_CONTEXT_HANDLE phContext; EFS_EXIM_STATE Pipe_State; EFS_EXIM_PIPE ImportPipe; DWORD RetCode;
HANDLE TokenHandle; PTOKEN_PRIVILEGES OldPrivs;
if ( NULL == Context){ return ERROR_ACCESS_DENIED; } phContext = ( PEXIMPORT_CONTEXT_HANDLE ) Context;
//
// Try to allocate a reasonable size buffer. The size can be fine tuned later, but should
// at least one page plus 4K. FSCTL_OUTPUT_LESS_LENGTH should be n * page size.
// FSCTL_OUTPUT_MIN_LENGTH can be fine tuned later. It should be at least one page
// plus 4K.
//
Pipe_State.BufLength = FSCTL_OUTPUT_INITIAL_LENGTH; Pipe_State.WorkBuf = RtlAllocateHeap( RtlProcessHeap(), 0, Pipe_State.BufLength );
if (!Pipe_State.WorkBuf){ return ERROR_OUTOFMEMORY; }
Pipe_State.ExImCallback = (PVOID) ImportCallback; Pipe_State.CallbackContext = CallbackContext; Pipe_State.Status = NO_ERROR; ImportPipe.state = (char *) &Pipe_State; ImportPipe.alloc = EfsPipeAlloc; ImportPipe.pull = EfsPipeWrite; ImportPipe.push = NULL;
(VOID) EnablePrivilege( CREATE_FOR_IMPORT, &TokenHandle, &OldPrivs );
RpcTryExcept{ RetCode = EfsRpcWriteFileRaw( phContext, &ImportPipe );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { if ( NO_ERROR == Pipe_State.Status ){ RetCode = RpcExceptionCode(); } else { RetCode = Pipe_State.Status; } } RpcEndExcept;
RestorePrivilege( &TokenHandle, &OldPrivs );
RtlFreeHeap( RtlProcessHeap(), 0, Pipe_State.WorkBuf );
return RetCode; }
void __RPC_FAR EfsPipeAlloc( char __RPC_FAR * State, unsigned long ReqSize, unsigned char __RPC_FAR * __RPC_FAR * Buf, unsigned long __RPC_FAR * RealSize ) /*++
Routine Description:
This routine is required by the RPC pipe. It allocates the memory for the push and pull routines.
Arguments:
State - Pipe status.
ReqSize - Required buffer sixe in bytes.
Buf - Buffer pointer.
RealSize - Size of allocated buffer in bytes.
Return Value:
None. */ {
PEFS_EXIM_STATE Pipe_State = (PEFS_EXIM_STATE) State; //
// If error had occured, this is the chance to tell the RPC LIB to
// stop the pipe work.
//
if ( NO_ERROR != Pipe_State->Status){ *RealSize = 0; *Buf = NULL; } else { if ( ReqSize > Pipe_State->BufLength ){ *RealSize = Pipe_State->BufLength; } else { *RealSize = ReqSize; } *Buf = Pipe_State->WorkBuf; }
}
void __RPC_FAR EfsPipeRead ( char __RPC_FAR * State, unsigned char __RPC_FAR * DataBuf, unsigned long ByteCount ) /*++
Routine Description:
This routine is called by the RPC pipe. It send the exported data to the caller.
Arguments:
State - Pipe status.
DataBuf - Buffer pointer.
ByteCount - Number of bytes to be sent out.
Return Value:
None. */ { DWORD HResult; PEFS_EXIM_STATE Pipe_State = (PEFS_EXIM_STATE) State; PFE_EXPORT_FUNC ExportCallback; PVOID CallbackContext;
ExportCallback = Pipe_State->ExImCallback; CallbackContext = Pipe_State->CallbackContext; HResult = (*ExportCallback)( DataBuf, CallbackContext, ByteCount); if ( NO_ERROR != HResult ){ Pipe_State->Status = HResult; } }
void __RPC_FAR EfsPipeWrite ( char __RPC_FAR * State, unsigned char __RPC_FAR * DataBuf, unsigned long ByteRequested, unsigned long *ByteFromCaller ) /*++
Routine Description:
This routine is called by the RPC pipe. It send the exported data to the caller.
Arguments:
State - Pipe status.
DataBuf - Buffer pointer.
ByteRequested - Number of bytes requested to write to the pipe.
ByteFromCaller - Number of bytes available for writing to the pipe.
Return Value:
None.
*/ { DWORD HResult; PEFS_EXIM_STATE Pipe_State = (PEFS_EXIM_STATE) State; PFE_IMPORT_FUNC ImportCallback; PVOID CallbackContext;
ImportCallback = Pipe_State->ExImCallback; CallbackContext = Pipe_State->CallbackContext; *ByteFromCaller = ByteRequested; HResult = (*ImportCallback)( DataBuf, CallbackContext, ByteFromCaller); if ( NO_ERROR != HResult ){ Pipe_State->Status = HResult; } }
DWORD EfsEncryptFileRPCClient( UNICODE_STRING *FullFileNameU ) /*++
Routine Description:
This routine is the client side of Encryption API. It establishes the connection to the server. And then call the server to finish the task.
Arguments:
FullFileNameU - Supplies the name of the file to be encrypted.
Return Value:
ERROR_SUCCESS on success, other on failure.
--*/ {
DWORD RetCode; handle_t binding_h; NTSTATUS Status; LPWSTR FullName; LPWSTR Server;
RetCode = GetFullName( FullFileNameU->Buffer, &FullName, &Server, 0, 0, 0, NULL, FALSE );
if ( RetCode == ERROR_SUCCESS ){ Status = RpcpBindRpc ( Server, L"lsarpc", 0, &binding_h );
if (NT_SUCCESS(Status)){ RpcTryExcept { RetCode = EfsRpcEncryptFileSrv( binding_h, FullName ); } RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { RetCode = RpcExceptionCode(); } RpcEndExcept;
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h ); } else { RetCode = RtlNtStatusToDosError( Status ); } RtlFreeHeap( RtlProcessHeap(), 0, FullName ); RtlFreeHeap( RtlProcessHeap(), 0, Server ); }
return RetCode; }
DWORD EfsDecryptFileRPCClient( UNICODE_STRING *FullFileNameU, DWORD dwRecovery ) /*++
Routine Description:
This routine is the client side of Decryption API. It establishes the connection to the server. And then call the server to finish the task.
Arguments:
FullFileNameU - Supplies the name of the file to be encrypted.
Return Value:
ERROR_SUCCESS on success, other on failure.
--*/ {
DWORD RetCode; handle_t binding_h; NTSTATUS Status; LPWSTR FullName; LPWSTR Server;
RetCode = GetFullName( FullFileNameU->Buffer, &FullName, &Server, 0, 0, 0, NULL, FALSE );
if ( RetCode == ERROR_SUCCESS ){ Status = RpcpBindRpc ( Server, L"lsarpc", 0, &binding_h );
if (NT_SUCCESS(Status)){ RpcTryExcept { RetCode = EfsRpcDecryptFileSrv( binding_h, FullName, dwRecovery ); } RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { RetCode = RpcExceptionCode(); } RpcEndExcept; //
// Free the binding handle
//
RpcpUnbindRpc( binding_h ); } else { RetCode = RtlNtStatusToDosError( Status ); } RtlFreeHeap( RtlProcessHeap(), 0, FullName ); RtlFreeHeap( RtlProcessHeap(), 0, Server ); }
return RetCode; }
DWORD GetFullName( LPCWSTR FileName, LPWSTR *FullName, LPWSTR *ServerName, ULONG Flags, DWORD dwCreationDistribution, DWORD dwAttributes, PSECURITY_DESCRIPTOR pRelativeSD, BOOL bInheritHandle ) /*++
Routine Description:
This routine will extract the server name and the file UNC name from the passed in file name.
Arguments:
FileName - Supplies the name of the file to be parsed. FullName - File name used on the server. ServerName - The server machine name where the file lives. Flags - Indicates if the object is a directory or a file. CREATE_FOR_DIR for directory. dwCreationDistribution - How the file should be created. dwAtrributes - The attributes for creating a new object. pRelativeSD - Security Descriptor. bInheritHandle - If the file to be created should inherit the security.
Return Value:
ERROR_SUCCESS on success, other on failure.
--*/ {
HANDLE FileHdl = 0; HANDLE DriverHandle; UNICODE_STRING DfsDriverName; DWORD RetCode = ERROR_SUCCESS; LPWSTR TmpFullName; DWORD FullNameLength; DWORD FileNameLength;
OBJECT_ATTRIBUTES Obja; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING FileNtName; NTSTATUS NtStatus; BOOL b = TRUE; DWORD FileAttributes = 0; DWORD CreationDistribution = 0; DWORD CreateOptions = 0; ULONG ii, jj; BOOL GotRoot; WCHAR *PathName; UINT DriveType; PFILE_NAME_INFORMATION FileNameInfo; WCHAR WorkBuffer[MAX_PATH+4]; DWORD BufSize; DWORD BufferLength;
NETRESOURCEW RemotePathResource; NETRESOURCEW *pNetInfo;
FileNameLength = wcslen(FileName);
BufferLength = (FileNameLength + 1) <= MAX_PATH ? (MAX_PATH + 1) * sizeof(WCHAR) : (FileNameLength + 1) * sizeof (WCHAR); PathName = (WCHAR *) RtlAllocateHeap( RtlProcessHeap(), 0, BufferLength );
if ( !PathName ) { return ERROR_NOT_ENOUGH_MEMORY; }
GotRoot = GetVolumePathNameW( FileName, PathName, BufferLength );
if (!GotRoot) { RetCode = GetLastError(); RtlFreeHeap( RtlProcessHeap(), 0, PathName ); return RetCode; }
DriveType = GetDriveTypeW(PathName); RtlFreeHeap( RtlProcessHeap(), 0, PathName );
if (DriveType == DRIVE_REMOTE){
if ((Flags & CREATE_FOR_IMPORT) || (dwAttributes !=0) ) {
//
// Called from OpenRaw or DuplicateInfo.
// Use NtCreateFile()
//
FileAttributes = GetFileAttributesW( FileName );
if (dwAttributes) {
//
// From dup
//
if (-1 != FileAttributes) {
//
// File existed
//
if ( dwCreationDistribution == CREATE_NEW ){ return ERROR_FILE_EXISTS; }
CreationDistribution = FILE_OPEN; if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if ((Flags & CREATE_FOR_DIR) == 0) { return ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH; } CreateOptions |= FILE_DIRECTORY_FILE; } } else {
//
// Destination not existing
//
CreationDistribution = FILE_CREATE; if (Flags & CREATE_FOR_DIR) { CreateOptions |= FILE_DIRECTORY_FILE; dwAttributes |= FILE_ATTRIBUTE_DIRECTORY; } else { CreateOptions |= FILE_NO_COMPRESSION; }
}
} else {
//
// From OpenRaw import
//
dwAttributes = FILE_ATTRIBUTE_NORMAL; CreateOptions = FILE_OPEN_FOR_BACKUP_INTENT;
if (-1 == FileAttributes) {
CreationDistribution = FILE_CREATE; if (Flags & CREATE_FOR_DIR) { CreateOptions |= FILE_DIRECTORY_FILE; dwAttributes |= FILE_ATTRIBUTE_DIRECTORY; } else { CreateOptions |= FILE_NO_COMPRESSION; }
} else {
//
// File already existing
//
CreationDistribution = FILE_OPEN; if (Flags & CREATE_FOR_DIR) { CreateOptions |= FILE_DIRECTORY_FILE; dwAttributes |= FILE_ATTRIBUTE_DIRECTORY; } }
}
RtlInitUnicodeString( &FileNtName, NULL );
b = RtlDosPathNameToNtPathName_U( FileName, &FileNtName, NULL, NULL );
if (b) {
dwAttributes &= ~(FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_READONLY); InitializeObjectAttributes( &Obja, &FileNtName, bInheritHandle ? OBJ_INHERIT | OBJ_CASE_INSENSITIVE : OBJ_CASE_INSENSITIVE, 0, pRelativeSD? ((PEFS_RPC_BLOB)pRelativeSD)->pbData:NULL ); NtStatus = NtCreateFile( &FileHdl, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &Obja, &IoStatusBlock, NULL, dwAttributes, 0, CreationDistribution, CreateOptions, NULL, 0 );
RtlFreeHeap( RtlProcessHeap(), 0, FileNtName.Buffer );
if (!NT_SUCCESS(NtStatus)) { return (RtlNtStatusToDosError( NtStatus )); } }
} else {
FileHdl = CreateFileW( FileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); if (INVALID_HANDLE_VALUE == FileHdl) { RetCode = GetLastError(); return RetCode; }
}
FileNameInfo = (PFILE_NAME_INFORMATION) WorkBuffer; BufSize = sizeof (WorkBuffer);
do {
NtStatus = NtQueryInformationFile( FileHdl, &IoStatusBlock, FileNameInfo, BufSize, FileNameInformation ); if ( NtStatus == STATUS_BUFFER_OVERFLOW || NtStatus == STATUS_BUFFER_TOO_SMALL ) {
BufSize *= 2; if (FileNameInfo != (PFILE_NAME_INFORMATION)WorkBuffer) { RtlFreeHeap( RtlProcessHeap(), 0, FileNameInfo ); } FileNameInfo = (PFILE_NAME_INFORMATION) RtlAllocateHeap( RtlProcessHeap(), 0, BufSize ); if (!FileNameInfo) { CloseHandle(FileHdl); return ERROR_NOT_ENOUGH_MEMORY; }
} } while (NtStatus == STATUS_BUFFER_OVERFLOW || NtStatus == STATUS_BUFFER_TOO_SMALL);
CloseHandle(FileHdl); if (!NT_SUCCESS(NtStatus)) { if (FileNameInfo != (PFILE_NAME_INFORMATION)WorkBuffer) { RtlFreeHeap( RtlProcessHeap(), 0, FileNameInfo ); return RtlNtStatusToDosError(NtStatus); } }
//
// We got the UNC name
//
*FullName = RtlAllocateHeap( RtlProcessHeap(), 0, FileNameInfo->FileNameLength+2*sizeof (WCHAR) ); *ServerName = RtlAllocateHeap( RtlProcessHeap(), 0, ( MAX_PATH + 1) * sizeof (WCHAR) );
if ( (NULL == *FullName) || (NULL == *ServerName) ){ if ( *FullName ){ RtlFreeHeap( RtlProcessHeap(), 0, *FullName ); *FullName = NULL; } if ( *ServerName ){ RtlFreeHeap( RtlProcessHeap(), 0, *ServerName ); *ServerName = NULL; }
if (FileNameInfo != (PFILE_NAME_INFORMATION)WorkBuffer) { RtlFreeHeap( RtlProcessHeap(), 0, FileNameInfo ); } return ERROR_NOT_ENOUGH_MEMORY; }
} else {
//
// The path is local
//
*FullName = RtlAllocateHeap( RtlProcessHeap(), 0, (FileNameLength + 1) * sizeof (WCHAR) ); *ServerName = RtlAllocateHeap( RtlProcessHeap(), 0, 8 * sizeof (WCHAR) );
//
// Use . for local case.
//
if ( (NULL == *FullName) || (NULL == *ServerName) ){ if ( *FullName ){ RtlFreeHeap( RtlProcessHeap(), 0, *FullName ); *FullName = NULL; } if ( *ServerName ){ RtlFreeHeap( RtlProcessHeap(), 0, *ServerName ); *ServerName = NULL; } return ERROR_NOT_ENOUGH_MEMORY; }
wcscpy ( *ServerName, L"."); wcscpy ( *FullName, FileName); return ERROR_SUCCESS;
}
//
// Let's get the UNC server and path name
//
FullNameLength = FileNameInfo->FileNameLength; ii = jj = 0;
while ( (FileNameInfo->FileName)[ jj ] == L'\\' ) { jj ++; } while ( jj < FullNameLength/sizeof(WCHAR) && ((FileNameInfo->FileName)[ jj ] != L'\\') ){ (*ServerName)[ii++] = (FileNameInfo->FileName)[ jj++ ]; } (*ServerName)[ii] = 0;
if (FileNameInfo->FileName[0] == L'\\' && FileNameInfo->FileName[1] != L'\\' ) {
//
// NtQueryInformationFile returns \server\share\...
//
(*FullName)[0] = L'\\'; wcsncpy( &((*FullName)[1]), &FileNameInfo->FileName[0], FullNameLength/sizeof(WCHAR) ); (*FullName)[1+FullNameLength/sizeof(WCHAR)] = 0; } else{
//
// Just in case we get \\server\share\...
//
wcsncpy( &((*FullName)[0]), &FileNameInfo->FileName[0], FullNameLength/sizeof(WCHAR) ); (*FullName)[FullNameLength/sizeof(WCHAR)] = 0; }
if (FileNameInfo != (PFILE_NAME_INFORMATION)WorkBuffer) { RtlFreeHeap( RtlProcessHeap(), 0, FileNameInfo ); }
//
// Let's see if the path is a WEB DAV path or not
//
BufSize = 1024; //If not enough, we will allocate more
pNetInfo = (NETRESOURCEW *) RtlAllocateHeap( RtlProcessHeap(), 0, BufSize );
//
// If we can't decide if the path is WEBDAV path, we assume not.
// Error will be returned later if it turns out to be a WEBDAV Share.
//
if (pNetInfo) { LPWSTR lpSysName;
RemotePathResource.dwScope = RESOURCE_CONNECTED; RemotePathResource.dwType = RESOURCETYPE_DISK; RemotePathResource.dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC; RemotePathResource.dwUsage = 0; RemotePathResource.lpLocalName = NULL; RemotePathResource.lpRemoteName = *FullName; RemotePathResource.lpComment = NULL; RemotePathResource.lpProvider = NULL; RetCode = WNetGetResourceInformationW ( &RemotePathResource, // network resource
(LPVOID) pNetInfo, // information buffer
(LPDWORD) &BufSize, // size of information buffer
&lpSysName ); if (RetCode == ERROR_MORE_DATA) {
//
// This is not likely to happen
//
RtlFreeHeap( RtlProcessHeap(), 0, pNetInfo );
pNetInfo = (NETRESOURCEW *) RtlAllocateHeap( RtlProcessHeap(), 0, BufSize ); if (pNetInfo) {
RetCode = WNetGetResourceInformationW ( &RemotePathResource, // network resource
(LPVOID) pNetInfo, // information buffer
(LPDWORD) &BufSize, // size of information buffer
&lpSysName );
}
}
if (ERROR_SUCCESS == RetCode) {
//
// Check to see if the provider is WEBDAV
//
if (!wcscmp(WEBPROV, pNetInfo->lpProvider)){
//
// This is the WEBDAV. Let's redo the name.
//
RtlFreeHeap( RtlProcessHeap(), 0, *FullName ); *FullName = RtlAllocateHeap( RtlProcessHeap(), 0, (FileNameLength + 3) * sizeof (WCHAR) ); //
// Use . for local case.
//
wcscpy ( *ServerName, L"."); (*FullName)[0] = DAVHEADER; (*FullName)[1] = 0; wcscat ( *FullName, FileName); return ERROR_SUCCESS;
}
}
} //
// This is a workaround.
// Let's see if this could be a DFS name
//
RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME); InitializeObjectAttributes( &Obja, &DfsDriverName, OBJ_CASE_INSENSITIVE, NULL, NULL ); NtStatus = NtCreateFile( &DriverHandle, SYNCHRONIZE, &Obja, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
if ( NT_SUCCESS( NtStatus ) ){
//
// DfsDriver opened successfully
//
TmpFullName = RtlAllocateHeap( RtlProcessHeap(), 0, FullNameLength + 2*sizeof (WCHAR) );
if (TmpFullName) {
NtStatus = NtFsControlFile( DriverHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_DFS_GET_SERVER_NAME, *FullName, FullNameLength + 2*sizeof (WCHAR) , TmpFullName, FullNameLength + 2* sizeof (WCHAR) ); if ( STATUS_BUFFER_OVERFLOW == NtStatus ){ FullNameLength = *(ULONG *)TmpFullName + sizeof (WCHAR); RtlFreeHeap( RtlProcessHeap(), 0, TmpFullName ); TmpFullName = RtlAllocateHeap( RtlProcessHeap(), 0, FullNameLength ); if (NULL == TmpFullName){
//
// Remember this is just a workaround.
// Let's assume this is not DFS path. If it is, it will fail later anyway.
//
NtClose( DriverHandle ); return ERROR_SUCCESS; } NtStatus = NtFsControlFile( DriverHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_DFS_GET_SERVER_NAME, *FullName, FullNameLength + 2*sizeof (WCHAR) , TmpFullName, FullNameLength ); }
if ( NT_SUCCESS( NtStatus ) ){ //
// The name is a DFS file name. Use the name in the TmpFullName
//
RtlFreeHeap( RtlProcessHeap(), 0, *FullName ); *FullName = TmpFullName;
//
// Reset the server name
//
ii = jj = 0; while ( (*FullName)[ jj ] == L'\\' ) { jj ++; } while ( ((*FullName)[ jj ]) && ((*FullName)[ jj ] != L'\\') ){ (*ServerName)[ii++] = (*FullName)[ jj++ ]; } (*ServerName)[ii] = 0; } else {
//
// Not a DFS name
//
RtlFreeHeap( RtlProcessHeap(), 0, TmpFullName );
}
}
NtClose( DriverHandle ); }
return ERROR_SUCCESS;
}
//
// Beta 2 API
//
DWORD EfsAddUsersRPCClient( IN LPCWSTR lpFileName, IN PENCRYPTION_CERTIFICATE_LIST pEncryptionCertificates ) /*++
Routine Description:
description-of-function.
Arguments:
argument-name - Supplies | Returns description of argument. . .
Return Value:
return-value - Description of conditions needed to return value. - or - None.
--*/
{ DWORD RetCode; handle_t binding_h; NTSTATUS Status; LPWSTR FullName; LPWSTR Server;
RetCode = GetFullName( lpFileName, &FullName, &Server, 0, 0, 0, NULL, FALSE );
if ( RetCode == ERROR_SUCCESS ) { Status = RpcpBindRpc ( Server, L"lsarpc", 0, &binding_h );
if (NT_SUCCESS(Status)){ RpcTryExcept { RetCode = EfsRpcAddUsersToFile( binding_h, FullName, pEncryptionCertificates ); } RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { RetCode = RpcExceptionCode(); } RpcEndExcept;
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h ); } else { RetCode = RtlNtStatusToDosError( Status ); } RtlFreeHeap( RtlProcessHeap(), 0, FullName ); RtlFreeHeap( RtlProcessHeap(), 0, Server ); }
return RetCode; }
DWORD EfsRemoveUsersRPCClient( IN LPCWSTR lpFileName, IN PENCRYPTION_CERTIFICATE_HASH_LIST pHashes ) /*++
Routine Description:
description-of-function.
Arguments:
argument-name - Supplies | Returns description of argument. . .
Return Value:
return-value - Description of conditions needed to return value. - or - None.
--*/
{
DWORD RetCode; handle_t binding_h; NTSTATUS Status; LPWSTR FullName; LPWSTR Server;
RetCode = GetFullName( lpFileName, &FullName, &Server, 0, 0, 0, NULL, FALSE );
if ( RetCode == ERROR_SUCCESS ){ Status = RpcpBindRpc ( Server, L"lsarpc", 0, &binding_h );
if (NT_SUCCESS(Status)){ RpcTryExcept { RetCode = EfsRpcRemoveUsersFromFile( binding_h, FullName, pHashes ); } RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { RetCode = RpcExceptionCode(); } RpcEndExcept;
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h );
} else {
RetCode = RtlNtStatusToDosError( Status ); } RtlFreeHeap( RtlProcessHeap(), 0, FullName ); RtlFreeHeap( RtlProcessHeap(), 0, Server ); }
return RetCode; }
DWORD EfsQueryRecoveryAgentsRPCClient( IN LPCWSTR lpFileName, OUT PENCRYPTION_CERTIFICATE_HASH_LIST * pRecoveryAgents )
/*++
Routine Description:
description-of-function.
Arguments:
argument-name - Supplies | Returns description of argument. . .
Return Value:
return-value - Description of conditions needed to return value. - or - None.
--*/
{
DWORD RetCode; handle_t binding_h; NTSTATUS Status; LPWSTR FullName; LPWSTR Server;
//
// Clear out this parameter, or RPC will choke on the server
// side.
//
*pRecoveryAgents = NULL;
RetCode = GetFullName( lpFileName, &FullName, &Server, 0, 0, 0, NULL, FALSE );
if ( RetCode == ERROR_SUCCESS ){ Status = RpcpBindRpc ( Server, L"lsarpc", 0, &binding_h );
if (NT_SUCCESS(Status)){ RpcTryExcept { RetCode = EfsRpcQueryRecoveryAgents( binding_h, FullName, pRecoveryAgents ); } RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { RetCode = RpcExceptionCode(); } RpcEndExcept;
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h );
} else {
RetCode = RtlNtStatusToDosError( Status ); } RtlFreeHeap( RtlProcessHeap(), 0, FullName ); RtlFreeHeap( RtlProcessHeap(), 0, Server ); }
return RetCode; }
DWORD EfsQueryUsersRPCClient( IN LPCWSTR lpFileName, OUT PENCRYPTION_CERTIFICATE_HASH_LIST * pUsers )
/*++
Routine Description:
description-of-function.
Arguments:
argument-name - Supplies | Returns description of argument. . .
Return Value:
return-value - Description of conditions needed to return value. - or - None.
--*/
{ DWORD RetCode; handle_t binding_h; NTSTATUS Status; LPWSTR FullName; LPWSTR Server;
//
// Clear out this parameter, or RPC will choke on the server
// side.
//
*pUsers = NULL;
RetCode = GetFullName( lpFileName, &FullName, &Server, 0, 0, 0, NULL, FALSE );
if ( RetCode == ERROR_SUCCESS ){
Status = RpcpBindRpc ( Server, L"lsarpc", 0, &binding_h );
if (NT_SUCCESS(Status)){ RpcTryExcept { RetCode = EfsRpcQueryUsersOnFile( binding_h, FullName, pUsers ); } RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { RetCode = RpcExceptionCode(); } RpcEndExcept;
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h );
} else {
RetCode = RtlNtStatusToDosError( Status ); } RtlFreeHeap( RtlProcessHeap(), 0, FullName ); RtlFreeHeap( RtlProcessHeap(), 0, Server ); }
return RetCode; }
DWORD EfsSetEncryptionKeyRPCClient( IN PENCRYPTION_CERTIFICATE pEncryptionCertificate ) { DWORD RetCode; handle_t binding_h; NTSTATUS Status; WCHAR ServerName[3 ];
wcscpy(&ServerName[0], L".");
Status = RpcpBindRpc ( &ServerName[0], L"lsarpc", 0, &binding_h );
if (NT_SUCCESS(Status)){ RpcTryExcept {
RetCode = EfsRpcSetFileEncryptionKey( binding_h, pEncryptionCertificate );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { RetCode = RpcExceptionCode(); } RpcEndExcept;
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h );
} else {
RetCode = RtlNtStatusToDosError( Status ); }
return RetCode; }
DWORD EfsDuplicateEncryptionInfoRPCClient( IN LPCWSTR lpSrcFileName, IN LPCWSTR lpDestFileName, IN DWORD dwCreationDistribution, IN DWORD dwAttributes, IN PEFS_RPC_BLOB pRelativeSD, IN BOOL bInheritHandle ) { DWORD RetCode; handle_t binding_h; NTSTATUS Status; LPWSTR SrcServer; LPWSTR DestServer;
LPWSTR FullSrcName; LPWSTR FullDestName; DWORD FileAttribute; DWORD Flags = 0;
RetCode = GetFullName( lpSrcFileName, &FullSrcName, &SrcServer, 0, 0, 0, NULL, FALSE );
if (RetCode == ERROR_SUCCESS) {
FileAttribute = GetFileAttributesW(lpSrcFileName); if (-1 != FileAttribute) { if (FileAttribute & FILE_ATTRIBUTE_DIRECTORY) { Flags = CREATE_FOR_DIR; } }
if (dwAttributes == 0) { FileAttribute = FILE_ATTRIBUTE_NORMAL; } else { FileAttribute = dwAttributes; }
RetCode = GetFullName( lpDestFileName, &FullDestName, &DestServer, Flags, dwCreationDistribution, FileAttribute, pRelativeSD, bInheritHandle );
if (RetCode == ERROR_SUCCESS) {
BOOL SamePC = TRUE;
//
// Only do this if they're on the same server.
//
SamePC = (_wcsicmp( SrcServer, DestServer ) == 0); if (!SamePC) {
//
// Check loopback case.
//
if ((wcscmp( SrcServer, L".") == 0) || (wcscmp( DestServer, L".") == 0)){
WCHAR MyComputerName[( MAX_COMPUTERNAME_LENGTH + 1) * sizeof (WCHAR)]; DWORD WorkBufferLength = MAX_COMPUTERNAME_LENGTH + 1; BOOL b; b = GetComputerNameW( MyComputerName, &WorkBufferLength ); if (b) { if (wcscmp( SrcServer, L".") == 0) { SamePC = (_wcsicmp( MyComputerName, DestServer ) == 0); } else { SamePC = (_wcsicmp( MyComputerName, SrcServer ) == 0); } }
} }
if (SamePC) {
Status = RpcpBindRpc ( SrcServer, L"lsarpc", 0, &binding_h );
if (NT_SUCCESS(Status)){ RpcTryExcept {
RetCode = EfsRpcDuplicateEncryptionInfoFile( binding_h, FullSrcName, FullDestName, dwCreationDistribution, dwAttributes, pRelativeSD, bInheritHandle );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { RetCode = RpcExceptionCode(); } RpcEndExcept;
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h );
} else {
RetCode = RtlNtStatusToDosError( Status ); }
} else {
RetCode = ERROR_INVALID_PARAMETER; }
RtlFreeHeap( RtlProcessHeap(), 0, FullDestName ); RtlFreeHeap( RtlProcessHeap(), 0, DestServer ); }
if ((RetCode != ERROR_SUCCESS) && (RetCode != ERROR_FILE_EXISTS) && (CREATE_NEW == dwCreationDistribution)) {
//
// Let's delete the file. This is the best effort. No return code is to be
// checked.
//
DeleteFileW(lpDestFileName);
}
RtlFreeHeap( RtlProcessHeap(), 0, FullSrcName ); RtlFreeHeap( RtlProcessHeap(), 0, SrcServer ); }
return RetCode; }
DWORD EfsFileKeyInfoRPCClient( IN LPCWSTR lpFileName, IN DWORD InfoClass, OUT PEFS_RPC_BLOB *KeyInfo ) {
DWORD RetCode; handle_t binding_h; NTSTATUS Status; LPWSTR FullName; LPWSTR Server; //
// Clear out this parameter, or RPC will choke on the server
// side.
//
*KeyInfo = NULL; RetCode = GetFullName( lpFileName, &FullName, &Server, 0, 0, 0, NULL, FALSE ); if ( RetCode == ERROR_SUCCESS ){ Status = RpcpBindRpc ( Server, L"lsarpc", 0, &binding_h ); if (NT_SUCCESS(Status)){ RpcTryExcept { RetCode = EfsRpcFileKeyInfo( binding_h, FullName, InfoClass, KeyInfo ); } RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) { RetCode = RpcExceptionCode(); } RpcEndExcept; //
// Free the binding handle
//
RpcpUnbindRpc( binding_h ); } else { RetCode = RtlNtStatusToDosError( Status ); } RtlFreeHeap( RtlProcessHeap(), 0, FullName ); RtlFreeHeap( RtlProcessHeap(), 0, Server ); } return RetCode; }
|