You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2126 lines
51 KiB
2126 lines
51 KiB
/*++
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
eserver.c
|
|
|
|
Abstract:
|
|
|
|
EFS RPC server code.
|
|
|
|
Author:
|
|
|
|
Robert Gu (RobertG) Aug, 1997
|
|
|
|
Environment:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define UNICODE
|
|
|
|
#include <string.h>
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <ntrpcp.h> // prototypes for MIDL user functions
|
|
#include <lsapch2.h>
|
|
#include <efsrpc.h>
|
|
#include <efsstruc.h>
|
|
#include <lm.h>
|
|
#include "efssrv.hxx"
|
|
#include <rpcasync.h>
|
|
|
|
#define PATHTOOLONG (5*1024)
|
|
#define TOOMANYUSER (500)
|
|
#define SDTOOBIG (260*1024)
|
|
|
|
extern BOOLEAN EfsPersonalVer;
|
|
extern BOOLEAN EfsDisabled;
|
|
|
|
long GetLocalFileName(
|
|
LPCWSTR FileName,
|
|
LPWSTR *LocalFileName,
|
|
WORD *Flag
|
|
);
|
|
|
|
BOOL EfsShareDecline(
|
|
LPCWSTR FileName,
|
|
BOOL VerifyShareAccess,
|
|
DWORD dwDesiredAccess
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check to see if the FileName is a UNC name and if the user could access the share.
|
|
|
|
Arguments:
|
|
|
|
FileName -- File UNC name.
|
|
|
|
VerifyShareAccess -- if we need to verify the access.
|
|
|
|
dwDesiredAccess -- Desired access.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if the user can't access the file.
|
|
|
|
--*/
|
|
{
|
|
BOOL b = TRUE;
|
|
DWORD FileNameLength = (DWORD) wcslen(FileName);
|
|
|
|
if (FileNameLength >= 3) {
|
|
if ((FileName[0] == L'\\') && (FileName[1] == L'\\' )) {
|
|
|
|
//
|
|
// Check if somebody play the trick \\?\
|
|
//
|
|
|
|
if ((FileName[2] != L'?')) {
|
|
|
|
//
|
|
// This is a UNC name. If bad name passed in , we will catch later.
|
|
//
|
|
|
|
b = FALSE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// A RPC attack. Do not give good error, such as ERROR_INVALID_PARAMETER.
|
|
// Just return ACCESS_DENIED.
|
|
//
|
|
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
|
|
}
|
|
} else {
|
|
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
|
|
}
|
|
} else {
|
|
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
|
|
}
|
|
|
|
if (!b && VerifyShareAccess) {
|
|
|
|
LPWSTR NetFileName = NULL;
|
|
HANDLE hFile;
|
|
|
|
if ( FileNameLength >= MAX_PATH ) {
|
|
|
|
//
|
|
// We need \\?\UNC\server\share\dir\file format to open the file.
|
|
//
|
|
|
|
NetFileName = LsapAllocateLsaHeap( (FileNameLength + 8) * sizeof (WCHAR) );
|
|
if (!NetFileName) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return TRUE;
|
|
}
|
|
|
|
wcscpy(NetFileName, L"\\\\?\\UNC");
|
|
wcscat(NetFileName, &FileName[1]);
|
|
|
|
} else {
|
|
|
|
NetFileName = (LPWSTR) FileName;
|
|
|
|
}
|
|
|
|
//
|
|
// Testing for access rights
|
|
//
|
|
|
|
hFile = CreateFile(
|
|
NetFileName,
|
|
dwDesiredAccess,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_BACKUP_SEMANTICS, // In case this is a directory
|
|
NULL
|
|
);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
|
|
|
|
CloseHandle( hFile );
|
|
|
|
} else {
|
|
|
|
b = TRUE;
|
|
|
|
}
|
|
|
|
if (NetFileName != FileName) {
|
|
LsapFreeLsaHeap( NetFileName );
|
|
}
|
|
|
|
}
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
BOOL EfsCheckForNetSession(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check to see if the session is from network
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
TRUE if the session is network session.
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
HANDLE TokenHandle;
|
|
ULONG ReturnLength;
|
|
BOOL b = FALSE;
|
|
BYTE PefBuffer[1024];
|
|
|
|
Status = NtOpenThreadToken(
|
|
NtCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE, // OpenAsSelf
|
|
&TokenHandle
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
|
|
Status = NtQueryInformationToken (
|
|
TokenHandle,
|
|
TokenGroups,
|
|
PefBuffer,
|
|
sizeof (PefBuffer),
|
|
&ReturnLength
|
|
);
|
|
|
|
if (NT_SUCCESS( Status ) || (Status == STATUS_BUFFER_TOO_SMALL)) {
|
|
|
|
PTOKEN_GROUPS pGroups = NULL;
|
|
PTOKEN_GROUPS pAllocGroups = NULL;
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
pGroups = (PTOKEN_GROUPS) PefBuffer;
|
|
|
|
} else {
|
|
|
|
pAllocGroups = (PTOKEN_GROUPS)LsapAllocateLsaHeap( ReturnLength );
|
|
|
|
if (pAllocGroups) {
|
|
|
|
Status = NtQueryInformationToken (
|
|
TokenHandle,
|
|
TokenGroups,
|
|
pAllocGroups,
|
|
ReturnLength,
|
|
&ReturnLength
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
pGroups = pAllocGroups;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (pGroups) {
|
|
|
|
//
|
|
// Search the network SID. Looks like this SID tends to appear at the
|
|
// end of the list. We search from back to the first.
|
|
//
|
|
|
|
int SidIndex;
|
|
|
|
for ( SidIndex = (int)(pGroups->GroupCount - 1); SidIndex >= 0; SidIndex--) {
|
|
if (RtlEqualSid(LsapNetworkSid, pGroups->Groups[SidIndex].Sid)) {
|
|
b = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Playing safe here. Any failure in this routine will assume net session.
|
|
//
|
|
|
|
b = TRUE;
|
|
|
|
}
|
|
|
|
if (pAllocGroups) {
|
|
LsapFreeLsaHeap( pAllocGroups );
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Playing safe here. Any failure in this routine will assume net session.
|
|
//
|
|
|
|
b = TRUE;
|
|
|
|
}
|
|
|
|
NtClose( TokenHandle );
|
|
|
|
} else {
|
|
|
|
//
|
|
// Playing safe here. Any failure in this routine will assume net session.
|
|
//
|
|
|
|
b = TRUE;
|
|
|
|
}
|
|
|
|
return( b );
|
|
}
|
|
|
|
long EfsRpcOpenFileRaw(
|
|
handle_t binding_h,
|
|
PPEXIMPORT_CONTEXT_HANDLE pphContext,
|
|
wchar_t __RPC_FAR *FileName,
|
|
long Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RPC Stub code for EFS Server EfsOpenFileRaw()
|
|
|
|
Arguments:
|
|
|
|
binding_h -- Binding handle.
|
|
|
|
pphContext -- RPC context handle.
|
|
|
|
FileName -- Target file name.
|
|
|
|
Flags -- Flags of the open request.
|
|
|
|
Return Value:
|
|
|
|
Result of the operation.
|
|
|
|
--*/
|
|
{
|
|
DWORD hResult;
|
|
LPWSTR LocalFileName;
|
|
BOOL NetSession = TRUE;
|
|
WORD WebDavPath;
|
|
|
|
if (EfsPersonalVer) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
if (EfsDisabled) {
|
|
return ERROR_EFS_DISABLED;
|
|
}
|
|
if ((pphContext == NULL) && (FileName == NULL)) {
|
|
|
|
//
|
|
// Possible RPC attack, don't tell the caller that the parameter is wrong.
|
|
//
|
|
|
|
//return ERROR_INVALID_PARAMETER;
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
|
|
*pphContext = (PEXIMPORT_CONTEXT_HANDLE) NULL;
|
|
hResult = GetLocalFileName(
|
|
FileName,
|
|
&LocalFileName,
|
|
&WebDavPath
|
|
);
|
|
|
|
if (hResult){
|
|
DebugLog((DEB_ERROR, "EfsRpcOpenFileRaw: GetLocalFileName failed, Error = (%x)\n" ,hResult ));
|
|
return hResult;
|
|
}
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult != RPC_S_OK) {
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
DebugLog((DEB_ERROR, "EfsRpcOpenFileRaw: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
return( hResult );
|
|
}
|
|
|
|
if (NetSession = EfsCheckForNetSession()) {
|
|
|
|
if (EfsShareDecline(FileName, FALSE, 0 )) {
|
|
|
|
hResult = GetLastError();
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_ERROR, "EfsRpcOpenFileRaw: EfsShareDecline failed, Error = (%x)\n" ,GetLastError() ));
|
|
return hResult;
|
|
|
|
}
|
|
}
|
|
|
|
hResult = EfsOpenFileRaw(
|
|
FileName,
|
|
LocalFileName,
|
|
NetSession,
|
|
Flags,
|
|
pphContext
|
|
);
|
|
|
|
RpcRevertToSelf();
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return hResult;
|
|
}
|
|
|
|
void EfsRpcCloseRaw(
|
|
PPEXIMPORT_CONTEXT_HANDLE pphContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RPC Stub code for EFS Server EfsCloseRaw()
|
|
|
|
Arguments:
|
|
|
|
pphContext -- RPC context handle.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
if ( *pphContext &&
|
|
(((PEXPORT_CONTEXT) *pphContext)->ContextID == EFS_CONTEXT_ID)){
|
|
EfsCloseFileRaw( *pphContext );
|
|
*pphContext = NULL;
|
|
}
|
|
}
|
|
|
|
void __RPC_USER
|
|
PEXIMPORT_CONTEXT_HANDLE_rundown(
|
|
PEXIMPORT_CONTEXT_HANDLE phContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Standard RPC Context Run Down Routine
|
|
|
|
Arguments:
|
|
|
|
phContext -- RPC context handle.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
EfsCloseFileRaw( phContext );
|
|
}
|
|
|
|
long EfsRpcReadFileRaw(
|
|
PEXIMPORT_CONTEXT_HANDLE phContext,
|
|
EFS_EXIM_PIPE __RPC_FAR *EfsOutPipe
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RPC Stub code for EFS Server EfsReadFileRaw
|
|
|
|
Arguments:
|
|
|
|
phContext -- Context handle.
|
|
EfsOutPipe -- Pipe handle.
|
|
|
|
Return Value:
|
|
|
|
The result of operation.
|
|
|
|
--*/
|
|
{
|
|
if ((EfsOutPipe == NULL) || (phContext == NULL)) {
|
|
|
|
//
|
|
// RPC Attack.
|
|
//
|
|
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
}
|
|
return (EfsReadFileRaw(
|
|
phContext,
|
|
EfsOutPipe
|
|
)
|
|
);
|
|
}
|
|
|
|
long EfsRpcWriteFileRaw(
|
|
PEXIMPORT_CONTEXT_HANDLE phContext,
|
|
EFS_EXIM_PIPE __RPC_FAR *EfsInPipe
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RPC Stub code for EFS Server EfsWriteFileRaw
|
|
|
|
Arguments:
|
|
|
|
phContext -- Context handle.
|
|
EfsInPipe -- Pipe handle.
|
|
|
|
Return Value:
|
|
|
|
The result of operation.
|
|
|
|
--*/
|
|
{
|
|
long hResult;
|
|
|
|
if ((EfsInPipe == NULL) || (phContext == NULL)) {
|
|
|
|
//
|
|
// RPC Attack.
|
|
//
|
|
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult != RPC_S_OK) {
|
|
DebugLog((DEB_ERROR, "EfsRpcWriteFileRaw: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
return( hResult );
|
|
}
|
|
|
|
hResult = EfsWriteFileRaw(
|
|
phContext,
|
|
EfsInPipe
|
|
);
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return hResult;
|
|
|
|
}
|
|
|
|
DWORD
|
|
EFSSendPipeData(
|
|
char *DataBuf,
|
|
ULONG DataLength,
|
|
PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a wrapper routine for calling RPC pipe. The purposes of this routine
|
|
and EfsRpcReadFileRaw() are to isolate efsapi.c from RPC details,
|
|
and implemtation details from eserver.c.
|
|
|
|
Arguments:
|
|
|
|
DataBuf -- Data buffer.
|
|
DataLength -- The length of data in bytes to be sent out to the client.
|
|
Context -- Pipe handle.
|
|
|
|
Return Value:
|
|
|
|
The result of operation.
|
|
|
|
--*/
|
|
{
|
|
EFS_EXIM_PIPE __RPC_FAR *EfsOutPipe;
|
|
DWORD HResult = NO_ERROR;
|
|
|
|
//
|
|
// Pass in parameter should not be 0. It is called by ourselves.
|
|
//
|
|
|
|
ASSERT( Context );
|
|
|
|
EfsOutPipe = ( EFS_EXIM_PIPE __RPC_FAR * )Context;
|
|
|
|
RpcTryExcept {
|
|
|
|
EfsOutPipe->push(
|
|
EfsOutPipe->state,
|
|
(unsigned char *) DataBuf,
|
|
DataLength
|
|
);
|
|
|
|
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
|
HResult = RpcExceptionCode();
|
|
} RpcEndExcept;
|
|
|
|
return (HResult);
|
|
}
|
|
|
|
DWORD
|
|
EFSReceivePipeData(
|
|
char *DataBuf,
|
|
ULONG* DataLength,
|
|
PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a wrapper routine for calling RPC pipe. The purposes of this routine
|
|
and EfsRpcWriteFileRaw() are to isolate efsapi.c from RPC details,
|
|
and implemtation details from eserver.c.
|
|
|
|
Arguments:
|
|
|
|
DataBuf -- Data buffer.
|
|
DataLength -- The length of data in bytes to be got from the client.
|
|
Context -- Pipe handle.
|
|
|
|
Return Value:
|
|
|
|
The result of operation.
|
|
|
|
--*/
|
|
{
|
|
EFS_EXIM_PIPE __RPC_FAR *EfsInPipe;
|
|
DWORD HResult = NO_ERROR;
|
|
char *WorkBuf;
|
|
ULONG MoreDataBytes;
|
|
ULONG BytesGot = 0;
|
|
BOOLEAN GetMoreData = TRUE;
|
|
|
|
|
|
//
|
|
// Pass in parameter should not be 0. It is called by ourselves.
|
|
//
|
|
|
|
ASSERT( Context );
|
|
|
|
EfsInPipe = ( EFS_EXIM_PIPE __RPC_FAR * )Context;
|
|
WorkBuf = DataBuf;
|
|
MoreDataBytes = *DataLength;
|
|
|
|
while ( GetMoreData ) {
|
|
BytesGot = 0;
|
|
|
|
RpcTryExcept {
|
|
|
|
EfsInPipe->pull(
|
|
EfsInPipe->state,
|
|
(unsigned char *) WorkBuf,
|
|
MoreDataBytes,
|
|
&BytesGot
|
|
);
|
|
|
|
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
|
HResult = RpcExceptionCode();
|
|
GetMoreData = FALSE;
|
|
} RpcEndExcept;
|
|
if ( BytesGot && (BytesGot < MoreDataBytes)){
|
|
WorkBuf += BytesGot;
|
|
MoreDataBytes -= BytesGot;
|
|
} else {
|
|
GetMoreData = FALSE;
|
|
}
|
|
}
|
|
|
|
if (HResult == NO_ERROR){
|
|
*DataLength = (ULONG)(WorkBuf - DataBuf) + BytesGot;
|
|
}
|
|
|
|
return (HResult);
|
|
}
|
|
|
|
long EfsRpcEncryptFileSrv(
|
|
handle_t binding_h,
|
|
wchar_t __RPC_FAR *FileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RPC Stub code for EFS Server Encryption
|
|
|
|
Arguments:
|
|
|
|
binding_h -- RPC binding handle.
|
|
FileName -- Target name.
|
|
|
|
Return Value:
|
|
|
|
The result of operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
UNICODE_STRING DestFileName;
|
|
DWORD hResult;
|
|
UNICODE_STRING RootPath;
|
|
HANDLE LogFile;
|
|
LPWSTR LocalFileName;
|
|
EFS_USER_INFO EfsUserInfo;
|
|
DWORD FileAttributes;
|
|
BOOL b;
|
|
WORD WebDavPath;
|
|
|
|
if (EfsPersonalVer) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
if (EfsDisabled) {
|
|
return ERROR_EFS_DISABLED;
|
|
}
|
|
|
|
hResult = GetLocalFileName(
|
|
FileName,
|
|
&LocalFileName,
|
|
&WebDavPath
|
|
);
|
|
|
|
if (hResult){
|
|
DebugLog((DEB_ERROR, "EfsRpcEncryptFileSrv: GetLocalFileName failed, Error = (%x)\n" ,hResult ));
|
|
return hResult;
|
|
}
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if ((hResult == RPC_S_OK) && EfsCheckForNetSession()) {
|
|
|
|
if (WebDavPath == WEBDAVPATH) {
|
|
|
|
//
|
|
// A RPC attacker. WEBDAV should be local session.
|
|
//
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
|
|
}
|
|
|
|
if (EfsShareDecline(FileName, TRUE, FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES )) {
|
|
|
|
hResult = GetLastError();
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_ERROR, "EfsRpcEncryptFileSrv: EfsShareDecline failed, Error = (%x)\n" ,GetLastError()));
|
|
return hResult;
|
|
|
|
}
|
|
}
|
|
if (hResult == RPC_S_OK) {
|
|
if (WebDavPath == WEBDAVPATH) {
|
|
|
|
//
|
|
// This is a WEB DAV path. We will treat it specially.
|
|
//
|
|
|
|
FileAttributes = GetFileAttributes( LocalFileName );
|
|
if (FileAttributes == -1) {
|
|
|
|
DWORD rc = GetLastError();
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_ERROR, "EfsRpcEncryptFileSrv: GetFileAttributes failed on WEBDAV file, Error = (%x)\n" ,GetLastError()));
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// Mapping the attributes and fake the call of FileEncryptionStatus.
|
|
//
|
|
|
|
if (FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
|
|
hResult = FILE_IS_ENCRYPTED;
|
|
} else if (FileAttributes & FILE_ATTRIBUTE_READONLY) {
|
|
hResult = FILE_READ_ONLY;
|
|
} else {
|
|
hResult = FILE_UNKNOWN;
|
|
}
|
|
|
|
b = TRUE;
|
|
|
|
} else {
|
|
b = FileEncryptionStatus(LocalFileName, &hResult);
|
|
}
|
|
} else {
|
|
DebugLog((DEB_ERROR, "EfsRpcEncryptFileSrv: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return hResult;
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
if ( b ){
|
|
if ( (hResult != FILE_ENCRYPTABLE) && (hResult != FILE_UNKNOWN)){
|
|
|
|
//
|
|
// No encryption is allowed or file is already encrypted
|
|
//
|
|
|
|
if ( hResult == FILE_IS_ENCRYPTED ){
|
|
|
|
HANDLE hSourceFile;
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
if (hResult == RPC_S_OK) {
|
|
|
|
FileAttributes = GetFileAttributes( LocalFileName );
|
|
|
|
if (FileAttributes != -1) {
|
|
|
|
if ( FileAttributes & FILE_ATTRIBUTE_DIRECTORY ){
|
|
hResult = ERROR_SUCCESS;
|
|
} else {
|
|
|
|
hSourceFile = CreateFile(
|
|
LocalFileName,
|
|
FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_OPEN_REPARSE_POINT,
|
|
NULL
|
|
);
|
|
|
|
if (hSourceFile == INVALID_HANDLE_VALUE) {
|
|
hResult = GetLastError();
|
|
} else {
|
|
|
|
CloseHandle( hSourceFile );
|
|
hResult = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
} else{
|
|
hResult = GetLastError();
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
}
|
|
|
|
} else if (hResult == FILE_DIR_DISALLOWED ) {
|
|
hResult = ERROR_DIR_EFS_DISALLOWED;
|
|
} else if ( hResult == FILE_READ_ONLY ){
|
|
hResult = ERROR_FILE_READ_ONLY;
|
|
} else {
|
|
hResult = ERROR_ACCESS_DENIED;
|
|
}
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return hResult;
|
|
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// Error occured checking the status
|
|
//
|
|
DebugLog((DEB_TRACE_EFS, "EfsRpcEncryptFileSrv: FileEncryptionStatus() failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return hResult;
|
|
}
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult != RPC_S_OK) {
|
|
DebugLog((DEB_ERROR, "EfsRpcEncryptFileSrv: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return( hResult );
|
|
}
|
|
|
|
DestFileName.Length = (USHORT) (sizeof(WCHAR) * wcslen(LocalFileName));
|
|
DestFileName.MaximumLength = DestFileName.Length + sizeof (WCHAR);
|
|
DestFileName.Buffer = LocalFileName;
|
|
//
|
|
// Get the rootname
|
|
//
|
|
|
|
if (WebDavPath == WEBDAVPATH){
|
|
|
|
//
|
|
// Do not support LOGFILE for WEB DAV
|
|
//
|
|
|
|
LogFile = NULL;
|
|
RpcRevertToSelf();
|
|
|
|
} else {
|
|
hResult = GetVolumeRoot(&DestFileName, &RootPath);
|
|
RpcRevertToSelf();
|
|
if (hResult != ERROR_SUCCESS) {
|
|
DebugLog((DEB_ERROR, "EfsRpcEncryptFileSrv: GetVolumeRoot failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return( hResult );
|
|
}
|
|
|
|
Status = GetLogFile( &RootPath, &LogFile );
|
|
LsapFreeLsaHeap( RootPath.Buffer );
|
|
}
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult == RPC_S_OK) {
|
|
|
|
if (EfspGetUserInfo( &EfsUserInfo )) {
|
|
if (EfspLoadUserProfile( &EfsUserInfo, FALSE )) {
|
|
hResult = EncryptFileSrv( &EfsUserInfo, &DestFileName, LogFile );
|
|
EfspUnloadUserProfile( &EfsUserInfo );
|
|
} else {
|
|
hResult = GetLastError();
|
|
}
|
|
EfspFreeUserInfo( &EfsUserInfo );
|
|
} else{
|
|
hResult = GetLastError();
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
} else {
|
|
if (LogFile) {
|
|
MarkFileForDelete( LogFile );
|
|
}
|
|
}
|
|
|
|
if (LogFile) {
|
|
CloseHandle(LogFile);
|
|
}
|
|
}
|
|
if (!NT_SUCCESS( Status )){
|
|
hResult = RtlNtStatusToDosError( Status );
|
|
|
|
//
|
|
// Make sure the error was mapped
|
|
//
|
|
|
|
if (hResult == ERROR_MR_MID_NOT_FOUND) {
|
|
|
|
DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
|
|
hResult = ERROR_ENCRYPTION_FAILED;
|
|
}
|
|
}
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return( hResult );
|
|
}
|
|
|
|
long EfsRpcDecryptFileSrv(
|
|
handle_t binding_h,
|
|
wchar_t __RPC_FAR *FileName,
|
|
unsigned long OpenFlag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RPC Stub code for EFS Server Decryption
|
|
|
|
Arguments:
|
|
|
|
binding_h -- RPC binding handle.
|
|
FileName -- Target name.
|
|
OpenFlag -- Open for recovery or decryption
|
|
|
|
Return Value:
|
|
|
|
The result of operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
UNICODE_STRING DestFileName;
|
|
DWORD hResult;
|
|
UNICODE_STRING RootPath;
|
|
HANDLE LogFile;
|
|
LPWSTR LocalFileName;
|
|
DWORD FileAttributes;
|
|
WORD WebDavPath;
|
|
|
|
if (EfsPersonalVer) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
if (EfsDisabled) {
|
|
return ERROR_EFS_DISABLED;
|
|
}
|
|
hResult = GetLocalFileName(
|
|
FileName,
|
|
&LocalFileName,
|
|
&WebDavPath
|
|
);
|
|
|
|
if (hResult){
|
|
DebugLog((DEB_ERROR, "EfsRpcDecryptFileSrv: GetLocalFileName failed, Error = (%x)\n" ,hResult ));
|
|
return hResult;
|
|
}
|
|
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult != RPC_S_OK) {
|
|
DebugLog((DEB_ERROR, "EfsRpcDecryptFileSrv: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return( hResult );
|
|
}
|
|
|
|
if (EfsCheckForNetSession()) {
|
|
|
|
if (WebDavPath == WEBDAVPATH) {
|
|
|
|
//
|
|
// A RPC attacker. WEBDAV should be local session.
|
|
//
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
|
|
}
|
|
|
|
if (EfsShareDecline(FileName, TRUE, FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES )) {
|
|
|
|
hResult = GetLastError();
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_ERROR, "EfsRpcDecryptFileSrv: EfsShareDecline failed, Error = (%x)\n" ,GetLastError() ));
|
|
return hResult;
|
|
|
|
}
|
|
}
|
|
|
|
FileAttributes = GetFileAttributes( LocalFileName );
|
|
if (-1 != FileAttributes){
|
|
if ( !(FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ){
|
|
|
|
//
|
|
// No decryption is needed.
|
|
//
|
|
|
|
RpcRevertToSelf();
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// Error occured checking the status
|
|
//
|
|
|
|
hResult = GetLastError();
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_TRACE_EFS, "EfsRpcDecryptFileSrv: GetFileAttributes() failed, Error = (%x)\n" , hResult));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return hResult;
|
|
}
|
|
|
|
DestFileName.Length = (USHORT) (sizeof(WCHAR) * wcslen(LocalFileName));
|
|
DestFileName.MaximumLength = DestFileName.Length + sizeof (WCHAR);
|
|
DestFileName.Buffer = LocalFileName;
|
|
//
|
|
// Get the rootname
|
|
//
|
|
|
|
if (WebDavPath == WEBDAVPATH){
|
|
|
|
//
|
|
// Do not support LOGFILE for WEB DAV
|
|
//
|
|
|
|
LogFile = NULL;
|
|
RpcRevertToSelf();
|
|
|
|
} else {
|
|
|
|
hResult = GetVolumeRoot(&DestFileName, &RootPath);
|
|
RpcRevertToSelf();
|
|
if (hResult != ERROR_SUCCESS) {
|
|
DebugLog((DEB_ERROR, "EfsRpcDecryptFileSrv: GetVolumeRoot failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return( hResult );
|
|
}
|
|
|
|
Status = GetLogFile( &RootPath, &LogFile );
|
|
LsapFreeLsaHeap( RootPath.Buffer );
|
|
|
|
}
|
|
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult == RPC_S_OK) {
|
|
hResult = DecryptFileSrv( &DestFileName, LogFile, OpenFlag );
|
|
RpcRevertToSelf();
|
|
} else {
|
|
if (LogFile) {
|
|
MarkFileForDelete( LogFile );
|
|
}
|
|
}
|
|
|
|
if (LogFile) {
|
|
CloseHandle(LogFile);
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS( Status )){
|
|
hResult = RtlNtStatusToDosError( Status );
|
|
|
|
//
|
|
// Make sure the error was mapped
|
|
//
|
|
|
|
if (hResult == ERROR_MR_MID_NOT_FOUND) {
|
|
|
|
DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_DECRYPTION_FAILED\n" , Status ));
|
|
hResult = ERROR_DECRYPTION_FAILED;
|
|
}
|
|
}
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return( (long)hResult );
|
|
}
|
|
|
|
long GetLocalFileName(
|
|
LPCWSTR FileName,
|
|
LPWSTR *LocalFileName,
|
|
WORD *Flag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the local file name from the UNC name
|
|
|
|
Arguments:
|
|
|
|
FileName -- Target UNC file name.
|
|
|
|
LocalFileName -- Local file name.
|
|
|
|
Flag -- Indicating special path, such as WEB DAV path.
|
|
|
|
Return Value:
|
|
|
|
The result of operation.
|
|
|
|
--*/
|
|
{
|
|
long RetCode = ERROR_SUCCESS;
|
|
LPWSTR NetName;
|
|
ULONG ii, jj;
|
|
LPBYTE ShareInfo;
|
|
DWORD PathLen;
|
|
DWORD BufLen;
|
|
BOOL SharePath = FALSE;
|
|
BOOL LocalCheckLength = TRUE;
|
|
|
|
*Flag = 0;
|
|
if ( FileName == NULL ) {
|
|
|
|
//
|
|
// Possible RPC attack
|
|
//
|
|
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
PathLen = (DWORD) wcslen(FileName);
|
|
|
|
if (PathLen >= PATHTOOLONG) {
|
|
|
|
//
|
|
// A possible RPC attack. Just return.
|
|
// No need to return good error here.
|
|
//
|
|
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
|
|
BufLen = MAX_PATH >= PathLen + 1? MAX_PATH + 1: PathLen + 10;
|
|
|
|
//
|
|
// Check the WEB DAV path first
|
|
//
|
|
|
|
if (DAVHEADER == FileName[0]) {
|
|
|
|
//
|
|
// This is the WEB DAV path. Treat it as the local case.
|
|
// Take whatever the user passed in.
|
|
//
|
|
|
|
*LocalFileName = (LPWSTR)LsapAllocateLsaHeap( PathLen * sizeof (WCHAR));
|
|
if (NULL == *LocalFileName) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
*Flag = WEBDAVPATH;
|
|
wcscpy(*LocalFileName, &FileName[1]);
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// See if the pass in name is \\server\share
|
|
//
|
|
|
|
if ((PathLen > 4) && (FileName[0] == L'\\') && (FileName[1] == L'\\')) {
|
|
if ((FileName[2] != L'?') && FileName[2] != L'.') {
|
|
SharePath = TRUE;
|
|
} else {
|
|
if (FileName[3] != L'\\') {
|
|
SharePath = TRUE;
|
|
} else {
|
|
|
|
//
|
|
// path \\?\ or \\.\
|
|
//
|
|
|
|
LocalCheckLength = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
*LocalFileName = (LPWSTR)LsapAllocateLsaHeap( BufLen * sizeof (WCHAR));
|
|
if ( NULL == *LocalFileName ){
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if (!SharePath) {
|
|
|
|
//
|
|
// This is a local path. Just copy it.
|
|
//
|
|
|
|
if (LocalCheckLength && PathLen >= MAX_PATH) {
|
|
|
|
//
|
|
// This is for Win2K compatibility
|
|
//
|
|
|
|
wcscpy(*LocalFileName, L"\\\\?\\");
|
|
wcscat(*LocalFileName, FileName);
|
|
} else {
|
|
wcscpy(*LocalFileName, FileName);
|
|
}
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
NetName = (LPWSTR)LsapAllocateLsaHeap( PathLen * sizeof (WCHAR));
|
|
if ( NULL == NetName ){
|
|
LsapFreeLsaHeap( *LocalFileName );
|
|
*LocalFileName = NULL;
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Extract the net name
|
|
//
|
|
|
|
ii = jj = 0;
|
|
|
|
while ( (FileName[jj]) && (FileName[jj] == L'\\') ){
|
|
jj++;
|
|
}
|
|
while ( (FileName[jj]) && (FileName[jj++] != L'\\') );
|
|
while ( (FileName[jj]) && (FileName[jj] != L'\\')){
|
|
NetName[ii++] = FileName[jj++];
|
|
}
|
|
|
|
if ( !(FileName[jj]) ){
|
|
|
|
//
|
|
// Invalid path name
|
|
//
|
|
|
|
LsapFreeLsaHeap( NetName );
|
|
LsapFreeLsaHeap( *LocalFileName );
|
|
*LocalFileName = NULL;
|
|
return ERROR_BAD_NETPATH ;
|
|
|
|
}
|
|
|
|
NetName[ii] = 0;
|
|
RetCode = NetShareGetInfo(
|
|
NULL,
|
|
NetName,
|
|
2,
|
|
&ShareInfo
|
|
);
|
|
|
|
if ( NERR_Success == RetCode ){
|
|
|
|
PathLen = (DWORD) (wcslen(((LPSHARE_INFO_2)ShareInfo)->shi2_path) +
|
|
wcslen(&FileName[jj]) + 1);
|
|
|
|
if ( PathLen >= MAX_PATH ){
|
|
if (PathLen + 5 > BufLen){
|
|
LsapFreeLsaHeap( *LocalFileName );
|
|
BufLen = PathLen + 5;
|
|
*LocalFileName = (LPWSTR)LsapAllocateLsaHeap( BufLen * sizeof (WCHAR));
|
|
if ( NULL == *LocalFileName ){
|
|
NetApiBufferFree(ShareInfo);
|
|
LsapFreeLsaHeap( NetName );
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
if (MAX_PATH <= PathLen){
|
|
|
|
//
|
|
// Put in the \\?\. Buffer should be bigger enough.
|
|
//
|
|
wcscpy(*LocalFileName,L"\\\\?\\");
|
|
wcscat(
|
|
*LocalFileName,
|
|
((LPSHARE_INFO_2)ShareInfo)->shi2_path
|
|
);
|
|
|
|
} else {
|
|
wcscpy(
|
|
*LocalFileName,
|
|
((LPSHARE_INFO_2)ShareInfo)->shi2_path
|
|
);
|
|
}
|
|
|
|
wcscat(*LocalFileName, &FileName[jj]);
|
|
NetApiBufferFree(ShareInfo);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Invalid path name
|
|
//
|
|
|
|
LsapFreeLsaHeap( *LocalFileName );
|
|
*LocalFileName = NULL;
|
|
RetCode = ERROR_BAD_NETPATH ;
|
|
|
|
}
|
|
|
|
LsapFreeLsaHeap( NetName );
|
|
return RetCode;
|
|
|
|
}
|
|
|
|
DWORD
|
|
EfsRpcQueryUsersOnFile(
|
|
IN handle_t binding_h,
|
|
IN LPCWSTR lpFileName,
|
|
OUT PENCRYPTION_CERTIFICATE_HASH_LIST *pUsersList
|
|
)
|
|
{
|
|
DWORD hResult;
|
|
PENCRYPTION_CERTIFICATE_HASH_LIST pHashList;
|
|
LPWSTR LocalFileName;
|
|
WORD WebDavPath;
|
|
|
|
DebugLog((DEB_WARN, "Made it into EfsRpcQueryUsersOnFile\n" ));
|
|
|
|
if (EfsPersonalVer) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
if (EfsDisabled) {
|
|
return ERROR_EFS_DISABLED;
|
|
}
|
|
if (pUsersList == NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
hResult = GetLocalFileName(
|
|
lpFileName,
|
|
&LocalFileName,
|
|
&WebDavPath
|
|
);
|
|
|
|
if (hResult){
|
|
DebugLog((DEB_ERROR, "EfsRpcQueryUsersOnFile: GetLocalFileName failed, Error = (%x)\n" ,hResult ));
|
|
return hResult;
|
|
}
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult != RPC_S_OK) {
|
|
DebugLog((DEB_ERROR, "EfsRpcQueryUsersOnFile: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return( hResult );
|
|
}
|
|
|
|
if (EfsCheckForNetSession()) {
|
|
|
|
if (WebDavPath == WEBDAVPATH) {
|
|
|
|
//
|
|
// A RPC attacker. WEBDAV should be local session.
|
|
//
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
|
|
}
|
|
|
|
if (EfsShareDecline(lpFileName, TRUE, FILE_READ_ATTRIBUTES )) {
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_ERROR, "EfsRpcQueryUsersOnFile: EfsShareDecline failed, Error = (%x)\n" ,GetLastError() ));
|
|
return GetLastError();
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate the structure we're going to return
|
|
//
|
|
|
|
pHashList = (PENCRYPTION_CERTIFICATE_HASH_LIST)MIDL_user_allocate( sizeof( ENCRYPTION_CERTIFICATE_HASH_LIST ));
|
|
|
|
*pUsersList = pHashList;
|
|
|
|
if (pHashList) {
|
|
|
|
hResult = QueryUsersOnFileSrv(
|
|
LocalFileName,
|
|
&pHashList->nCert_Hash,
|
|
&pHashList->pUsers
|
|
);
|
|
|
|
if (hResult != ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Free the structure we allocated
|
|
//
|
|
|
|
MIDL_user_free( pHashList );
|
|
*pUsersList = NULL; // paranoia
|
|
}
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
|
|
return( hResult );
|
|
}
|
|
|
|
DWORD EfsRpcQueryRecoveryAgents(
|
|
IN handle_t binding_h,
|
|
IN LPCWSTR lpFileName,
|
|
OUT PENCRYPTION_CERTIFICATE_HASH_LIST * pRecoveryAgents
|
|
)
|
|
{
|
|
DWORD hResult;
|
|
PENCRYPTION_CERTIFICATE_HASH_LIST pHashList;
|
|
LPWSTR LocalFileName;
|
|
WORD WebDavPath;
|
|
|
|
DebugLog((DEB_WARN, "Made it into EfsRpcQueryRecoveryAgents\n" ));
|
|
if (EfsPersonalVer) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
if (EfsDisabled) {
|
|
return ERROR_EFS_DISABLED;
|
|
}
|
|
if (pRecoveryAgents == NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
hResult = GetLocalFileName(
|
|
lpFileName,
|
|
&LocalFileName,
|
|
&WebDavPath
|
|
);
|
|
|
|
if (hResult){
|
|
DebugLog((DEB_ERROR, "EfsRpcQueryRecoveryAgents: GetLocalFileName failed, Error = (%x)\n" ,hResult ));
|
|
return hResult;
|
|
}
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult != RPC_S_OK) {
|
|
DebugLog((DEB_ERROR, "EfsRpcQueryRecoveryAgents: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return( hResult );
|
|
}
|
|
|
|
if (EfsCheckForNetSession()) {
|
|
|
|
if (WebDavPath == WEBDAVPATH) {
|
|
|
|
//
|
|
// A RPC attacker. WEBDAV should be local session.
|
|
//
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
|
|
}
|
|
|
|
if (EfsShareDecline(lpFileName, TRUE, FILE_READ_ATTRIBUTES )) {
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_ERROR, "EfsRpcQueryRecoveryAgents: EfsShareDecline failed, Error = (%x)\n" ,GetLastError() ));
|
|
return GetLastError();
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate the structure we're going to return
|
|
//
|
|
|
|
pHashList = (PENCRYPTION_CERTIFICATE_HASH_LIST)MIDL_user_allocate( sizeof( ENCRYPTION_CERTIFICATE_HASH_LIST ));
|
|
|
|
*pRecoveryAgents = pHashList;
|
|
|
|
if (pHashList) {
|
|
|
|
hResult = QueryRecoveryAgentsSrv(
|
|
LocalFileName,
|
|
&pHashList->nCert_Hash,
|
|
&pHashList->pUsers
|
|
);
|
|
|
|
if (hResult != ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Free the structure we allocated
|
|
//
|
|
|
|
MIDL_user_free( pHashList );
|
|
*pRecoveryAgents = NULL; // paranoia
|
|
}
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
|
|
return( hResult );
|
|
}
|
|
|
|
DWORD EfsRpcRemoveUsersFromFile(
|
|
IN handle_t binding_h,
|
|
IN LPCWSTR lpFileName,
|
|
IN PENCRYPTION_CERTIFICATE_HASH_LIST pUsers
|
|
)
|
|
{
|
|
DWORD hResult;
|
|
LPWSTR LocalFileName;
|
|
EFS_USER_INFO EfsUserInfo;
|
|
WORD WebDavPath;
|
|
|
|
DebugLog((DEB_WARN, "Made it into EfsRpcRemoveUsersFromFile\n" ));
|
|
|
|
if (EfsPersonalVer) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
if (EfsDisabled) {
|
|
return ERROR_EFS_DISABLED;
|
|
}
|
|
if ((pUsers == NULL) || (lpFileName == NULL) || (pUsers->pUsers == NULL)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
if (pUsers->nCert_Hash > TOOMANYUSER) {
|
|
|
|
//
|
|
// Possible RPC attack
|
|
//
|
|
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
hResult = GetLocalFileName(
|
|
lpFileName,
|
|
&LocalFileName,
|
|
&WebDavPath
|
|
);
|
|
|
|
if (hResult){
|
|
DebugLog((DEB_ERROR, "EfsRpcRemoveUsersFromFile: GetLocalFileName failed, Error = (%x)\n" ,hResult ));
|
|
return hResult;
|
|
}
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult != RPC_S_OK) {
|
|
DebugLog((DEB_ERROR, "EfsRpcRemoveUsersFromFile: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return( hResult );
|
|
}
|
|
|
|
if (EfsCheckForNetSession()) {
|
|
|
|
if (WebDavPath == WEBDAVPATH) {
|
|
|
|
//
|
|
// A RPC attacker. WEBDAV should be local session.
|
|
//
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
|
|
}
|
|
|
|
if (EfsShareDecline(lpFileName, TRUE, FILE_READ_ATTRIBUTES| FILE_WRITE_DATA )) {
|
|
|
|
hResult = GetLastError();
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_ERROR, "EfsRpcRemoveUsersFromFile: EfsShareDecline failed, Error = (%x)\n" ,hResult ));
|
|
return hResult;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (EfspGetUserInfo( &EfsUserInfo )) {
|
|
|
|
if (EfspLoadUserProfile( &EfsUserInfo, FALSE )) {
|
|
|
|
//
|
|
// The cert hash list could be garbage
|
|
//
|
|
|
|
__try{
|
|
|
|
hResult = RemoveUsersFromFileSrv(
|
|
&EfsUserInfo,
|
|
LocalFileName,
|
|
pUsers->nCert_Hash,
|
|
pUsers->pUsers
|
|
);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
hResult = ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
EfspUnloadUserProfile( &EfsUserInfo );
|
|
|
|
} else {
|
|
|
|
hResult = GetLastError();
|
|
}
|
|
|
|
EfspFreeUserInfo( &EfsUserInfo );
|
|
|
|
} else {
|
|
|
|
hResult = GetLastError();
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
|
|
return( hResult );
|
|
}
|
|
|
|
DWORD
|
|
EfsRpcAddUsersToFile(
|
|
IN handle_t binding_h,
|
|
IN LPCWSTR lpFileName,
|
|
IN PENCRYPTION_CERTIFICATE_LIST pEncryptionCertificates
|
|
)
|
|
{
|
|
DWORD hResult;
|
|
LPWSTR LocalFileName;
|
|
|
|
EFS_USER_INFO EfsUserInfo;
|
|
WORD WebDavPath;
|
|
|
|
DebugLog((DEB_WARN, "Made it into EfsRpcAddUsersToFile\n" ));
|
|
|
|
if (EfsPersonalVer) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
if (EfsDisabled) {
|
|
return ERROR_EFS_DISABLED;
|
|
}
|
|
|
|
if (pEncryptionCertificates == NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (pEncryptionCertificates->nUsers > TOOMANYUSER) {
|
|
|
|
//
|
|
// Possible RPC attack
|
|
// We could make this bigger in the future if there is the need.
|
|
//
|
|
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
|
hResult = GetLocalFileName(
|
|
lpFileName,
|
|
&LocalFileName,
|
|
&WebDavPath
|
|
);
|
|
|
|
if (hResult){
|
|
DebugLog((DEB_ERROR, "EfsRpcAddUsersToFile: GetLocalFileName failed, Error = (%x)\n" ,hResult ));
|
|
return hResult;
|
|
}
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult != RPC_S_OK) {
|
|
DebugLog((DEB_ERROR, "EfsRpcAddUsersToFile: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return( hResult );
|
|
}
|
|
|
|
if (EfsCheckForNetSession()) {
|
|
|
|
if (WebDavPath == WEBDAVPATH) {
|
|
|
|
//
|
|
// A RPC attacker. WEBDAV should be local session.
|
|
//
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
|
|
}
|
|
|
|
if (EfsShareDecline(lpFileName, TRUE, FILE_READ_ATTRIBUTES| FILE_WRITE_DATA )) {
|
|
|
|
hResult = GetLastError();
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_ERROR, "EfsRpcAddUsersToFile: EfsShareDecline failed, Error = (%x)\n" , hResult ));
|
|
return hResult;
|
|
|
|
}
|
|
}
|
|
|
|
if (EfspGetUserInfo( &EfsUserInfo )) {
|
|
|
|
if (EfspLoadUserProfile( &EfsUserInfo, FALSE )) {
|
|
|
|
//
|
|
// We may be passed in garbage for the cert list
|
|
// However, RPC will guarantee that the first level reference will not cause AV.
|
|
// TRY is used in AddUsersToFileSrv for better error handling.
|
|
//
|
|
|
|
hResult = AddUsersToFileSrv(
|
|
&EfsUserInfo,
|
|
LocalFileName,
|
|
pEncryptionCertificates->nUsers,
|
|
pEncryptionCertificates->pUsers
|
|
);
|
|
|
|
|
|
EfspUnloadUserProfile( &EfsUserInfo );
|
|
|
|
} else {
|
|
|
|
hResult = GetLastError();
|
|
}
|
|
|
|
EfspFreeUserInfo( &EfsUserInfo );
|
|
|
|
} else {
|
|
|
|
hResult = GetLastError();
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
|
|
return( hResult );
|
|
}
|
|
|
|
|
|
DWORD
|
|
EfsRpcSetFileEncryptionKey(
|
|
IN handle_t binding_h,
|
|
IN PENCRYPTION_CERTIFICATE pEncryptionCertificate
|
|
)
|
|
{
|
|
|
|
DWORD hResult;
|
|
|
|
EFS_USER_INFO EfsUserInfo;
|
|
|
|
DebugLog((DEB_WARN, "Made it into EfsRpcSetFileEncryptionKey\n" ));
|
|
|
|
if (EfsPersonalVer) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
if (EfsDisabled) {
|
|
return ERROR_EFS_DISABLED;
|
|
}
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
if (hResult != RPC_S_OK) {
|
|
DebugLog((DEB_ERROR, "EfsRpcSetFileEncryptionKey: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
return( hResult );
|
|
}
|
|
|
|
if (EfsCheckForNetSession()) {
|
|
|
|
//
|
|
// This call can only be done locally.
|
|
//
|
|
|
|
RpcRevertToSelf();
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (EfspGetUserInfo( &EfsUserInfo )) {
|
|
|
|
if (EfspLoadUserProfile( &EfsUserInfo, TRUE )) {
|
|
|
|
hResult = SetFileEncryptionKeySrv( &EfsUserInfo, pEncryptionCertificate );
|
|
|
|
EfspUnloadUserProfile( &EfsUserInfo );
|
|
|
|
} else {
|
|
|
|
hResult = GetLastError();
|
|
}
|
|
|
|
EfspFreeUserInfo( &EfsUserInfo );
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return( hResult );
|
|
}
|
|
|
|
|
|
DWORD
|
|
EfsRpcDuplicateEncryptionInfoFile(
|
|
IN handle_t binding_h,
|
|
IN LPCWSTR lpSrcFileName,
|
|
IN LPCWSTR lpDestFileName,
|
|
IN DWORD dwCreationDistribution,
|
|
IN DWORD dwAttributes,
|
|
IN PEFS_RPC_BLOB pRelativeSD,
|
|
IN BOOL bInheritHandle
|
|
)
|
|
{
|
|
DWORD hResult;
|
|
|
|
LPWSTR LocalSrcFileName;
|
|
LPWSTR LocalDestFileName;
|
|
BOOLEAN NetSession=FALSE;
|
|
WORD WebDavPathSrc;
|
|
WORD WebDavPathDst;
|
|
|
|
EFS_USER_INFO EfsUserInfo;
|
|
DebugLog((DEB_WARN, "Made it into EfsRpcDuplicateEncryptionInfoFile\n" ));
|
|
|
|
|
|
if (EfsPersonalVer) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
if (EfsDisabled) {
|
|
return ERROR_EFS_DISABLED;
|
|
}
|
|
|
|
if (pRelativeSD && pRelativeSD->cbData > SDTOOBIG) {
|
|
|
|
//
|
|
// RPC attack
|
|
//
|
|
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
hResult = GetLocalFileName(
|
|
lpSrcFileName,
|
|
&LocalSrcFileName,
|
|
&WebDavPathSrc
|
|
);
|
|
|
|
if (hResult){
|
|
DebugLog((DEB_ERROR, "EfsRpcDuplicateEncryptionInfoFile: GetLocalFileName failed, Error = (%x)\n" ,hResult ));
|
|
return hResult;
|
|
}
|
|
|
|
hResult = GetLocalFileName(
|
|
lpDestFileName,
|
|
&LocalDestFileName,
|
|
&WebDavPathDst
|
|
);
|
|
|
|
if (hResult){
|
|
DebugLog((DEB_ERROR, "EfsRpcDuplicateEncryptionInfoFile: GetLocalFileName failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalSrcFileName );
|
|
return hResult;
|
|
}
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult != RPC_S_OK) {
|
|
DebugLog((DEB_ERROR, "EfsRpcDuplicateEncryptionInfoFile: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalDestFileName );
|
|
LsapFreeLsaHeap( LocalSrcFileName );
|
|
return ( hResult );
|
|
}
|
|
|
|
if (EfsCheckForNetSession()) {
|
|
|
|
if ((WebDavPathSrc == WEBDAVPATH) || (WebDavPathDst == WEBDAVPATH)) {
|
|
|
|
//
|
|
// A RPC attacker. WEBDAV should be local session.
|
|
//
|
|
|
|
LsapFreeLsaHeap( LocalDestFileName );
|
|
LsapFreeLsaHeap( LocalSrcFileName );
|
|
RpcRevertToSelf();
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
|
|
}
|
|
|
|
if (EfsShareDecline(lpSrcFileName, TRUE, FILE_READ_ATTRIBUTES )) {
|
|
|
|
LsapFreeLsaHeap( LocalDestFileName );
|
|
LsapFreeLsaHeap( LocalSrcFileName );
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_ERROR, "EfsRpcDuplicateEncryptionInfoFile: EfsShareDecline failed, Error = (%x)\n" ,GetLastError() ));
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
if (EfsShareDecline(lpDestFileName, FALSE, 0 )) {
|
|
|
|
LsapFreeLsaHeap( LocalDestFileName );
|
|
LsapFreeLsaHeap( LocalSrcFileName );
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_ERROR, "EfsRpcDuplicateEncryptionInfoFile: EfsShareDecline failed, Error = (%x)\n" ,GetLastError() ));
|
|
return GetLastError();
|
|
|
|
}
|
|
NetSession = TRUE;
|
|
|
|
}
|
|
|
|
if (EfspGetUserInfo( &EfsUserInfo )) {
|
|
|
|
//
|
|
// Load the profile so we can open the source file
|
|
//
|
|
|
|
if (EfspLoadUserProfile( &EfsUserInfo, FALSE )) {
|
|
|
|
hResult = DuplicateEncryptionInfoFileSrv( &EfsUserInfo,
|
|
LocalSrcFileName,
|
|
LocalDestFileName,
|
|
NetSession? lpDestFileName: NULL,
|
|
dwCreationDistribution,
|
|
dwAttributes,
|
|
pRelativeSD,
|
|
bInheritHandle
|
|
);
|
|
|
|
EfspUnloadUserProfile( &EfsUserInfo );
|
|
|
|
} else {
|
|
|
|
hResult = GetLastError();
|
|
}
|
|
|
|
EfspFreeUserInfo( &EfsUserInfo );
|
|
}
|
|
|
|
LsapFreeLsaHeap( LocalDestFileName );
|
|
LsapFreeLsaHeap( LocalSrcFileName );
|
|
RpcRevertToSelf();
|
|
|
|
return( hResult );
|
|
}
|
|
|
|
DWORD EfsRpcFileKeyInfo(
|
|
IN handle_t binding_h,
|
|
IN LPCWSTR lpFileName,
|
|
IN DWORD InfoClass,
|
|
OUT PEFS_RPC_BLOB *KeyInfo
|
|
)
|
|
{
|
|
DWORD hResult;
|
|
PEFS_RPC_BLOB pKeyInfo;
|
|
LPWSTR LocalFileName;
|
|
WORD WebDavPath;
|
|
|
|
DebugLog((DEB_WARN, "Made it into EfsRpcFileKeyInfo\n" ));
|
|
|
|
if (EfsPersonalVer) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
if (EfsDisabled) {
|
|
return ERROR_EFS_DISABLED;
|
|
}
|
|
if (KeyInfo == NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
hResult = GetLocalFileName(
|
|
lpFileName,
|
|
&LocalFileName,
|
|
&WebDavPath
|
|
);
|
|
|
|
if (hResult){
|
|
DebugLog((DEB_ERROR, "EfsRpcFileKeyInfo: GetLocalFileName failed, Error = (%x)\n" ,hResult ));
|
|
return hResult;
|
|
}
|
|
|
|
hResult = RpcImpersonateClient( NULL );
|
|
|
|
if (hResult != RPC_S_OK) {
|
|
DebugLog((DEB_ERROR, "EfsRpcFileKeyInfo: RpcImpersonateClient failed, Error = (%x)\n" ,hResult ));
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
return( hResult );
|
|
}
|
|
|
|
if (EfsCheckForNetSession()) {
|
|
if (WebDavPath == WEBDAVPATH) {
|
|
|
|
//
|
|
// A RPC attacker. WEBDAV should be local session.
|
|
//
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
|
|
}
|
|
if (EfsShareDecline(lpFileName, TRUE, FILE_READ_ATTRIBUTES )) {
|
|
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
RpcRevertToSelf();
|
|
DebugLog((DEB_ERROR, "EfsRpcFileKeyInfo: EfsShareDecline failed, Error = (%x)\n" ,GetLastError() ));
|
|
return GetLastError();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate the structure we're going to return
|
|
//
|
|
|
|
pKeyInfo = (PEFS_RPC_BLOB)MIDL_user_allocate( sizeof( EFS_RPC_BLOB ));
|
|
|
|
*KeyInfo = pKeyInfo;
|
|
|
|
if (pKeyInfo) {
|
|
|
|
hResult = EfsFileKeyInfoSrv(
|
|
LocalFileName,
|
|
InfoClass,
|
|
&pKeyInfo->cbData,
|
|
&pKeyInfo->pbData
|
|
);
|
|
|
|
if (hResult != ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Free the structure we allocated
|
|
//
|
|
|
|
if (pKeyInfo->pbData) {
|
|
MIDL_user_free( pKeyInfo->pbData );
|
|
}
|
|
MIDL_user_free( pKeyInfo );
|
|
*KeyInfo = NULL; // paranoia
|
|
} else {
|
|
if (NULL == pKeyInfo->pbData) {
|
|
|
|
//
|
|
// No data returned
|
|
//
|
|
|
|
MIDL_user_free( pKeyInfo );
|
|
*KeyInfo = NULL;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
hResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
LsapFreeLsaHeap( LocalFileName );
|
|
|
|
return( hResult );
|
|
}
|
|
|
|
|
|
DWORD
|
|
EfsRpcNotSupported(
|
|
IN handle_t binding_h,
|
|
IN LPCWSTR lpSrcFileName,
|
|
IN LPCWSTR lpDestFileName,
|
|
IN DWORD dwCreationDistribution,
|
|
IN DWORD dwAttributes,
|
|
IN PEFS_RPC_BLOB pRelativeSD,
|
|
IN BOOL bInheritHandle
|
|
)
|
|
{
|
|
DebugLog((DEB_WARN, "Made it into EfsRpcNotSupported\n" ));
|
|
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|