/*++ Copyright (c) 1997 Microsoft Corporation Module Name: eclient.c Abstract: EFS RPC client code. Author: Robert Gu (RobertG) Aug, 1997 Environment: Revision History: --*/ #include #include #include #include #include #include // prototypes for MIDL user functions #include #include #include #include #include #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; }