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.
1934 lines
49 KiB
1934 lines
49 KiB
/*++
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
feclient.cpp
|
|
|
|
Abstract:
|
|
|
|
This module implements stubs to call EFS Api
|
|
|
|
Author:
|
|
|
|
Robert Reichel (RobertRe)
|
|
Robert Gu (RobertG)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
//
|
|
// Turn off lean and mean so we get wincrypt.h and winefs.h included
|
|
//
|
|
|
|
#undef WIN32_LEAN_AND_MEAN
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <feclient.h>
|
|
#include <efsstruc.h>
|
|
#include <userenv.h>
|
|
|
|
#include <overflow.h>
|
|
|
|
//
|
|
// Constants used in export\import file
|
|
//
|
|
|
|
#define INISECTIONNAME L"Encryption"
|
|
#define INIKEYNAME L"Disable"
|
|
#define INIFILENAME L"\\Desktop.ini"
|
|
#define TRUSTEDPEOPLE L"TrustedPeople"
|
|
|
|
#define BASIC_KEY_INFO 1
|
|
#define UPDATE_KEY_USED 0x100
|
|
|
|
#if DBG
|
|
|
|
ULONG DebugLevel = 0;
|
|
|
|
#endif
|
|
|
|
|
|
LPSTR EfsOidlpstr = szOID_KP_EFS;
|
|
|
|
//
|
|
// External prototypes
|
|
//
|
|
extern "C" {
|
|
DWORD
|
|
EfsReadFileRawRPCClient(
|
|
IN PFE_EXPORT_FUNC ExportCallback,
|
|
IN PVOID CallbackContext,
|
|
IN PVOID Context
|
|
);
|
|
|
|
DWORD
|
|
EfsWriteFileRawRPCClient(
|
|
IN PFE_IMPORT_FUNC ImportCallback,
|
|
IN PVOID CallbackContext,
|
|
IN PVOID Context
|
|
);
|
|
|
|
DWORD
|
|
EfsAddUsersRPCClient(
|
|
IN LPCWSTR lpFileName,
|
|
IN PENCRYPTION_CERTIFICATE_LIST pEncryptionCertificates
|
|
);
|
|
|
|
|
|
DWORD
|
|
EfsRemoveUsersRPCClient(
|
|
IN LPCWSTR lpFileName,
|
|
IN PENCRYPTION_CERTIFICATE_HASH_LIST pHashes
|
|
);
|
|
|
|
DWORD
|
|
EfsQueryRecoveryAgentsRPCClient(
|
|
IN LPCWSTR lpFileName,
|
|
OUT PENCRYPTION_CERTIFICATE_HASH_LIST * pRecoveryAgents
|
|
);
|
|
|
|
|
|
DWORD
|
|
EfsQueryUsersRPCClient(
|
|
IN LPCWSTR lpFileName,
|
|
OUT PENCRYPTION_CERTIFICATE_HASH_LIST * pUsers
|
|
);
|
|
|
|
DWORD
|
|
EfsSetEncryptionKeyRPCClient(
|
|
IN PENCRYPTION_CERTIFICATE pEncryptionCertificate
|
|
);
|
|
|
|
DWORD
|
|
EfsDuplicateEncryptionInfoRPCClient(
|
|
IN LPCWSTR lpSrcFileName,
|
|
IN LPCWSTR lpDestFileName,
|
|
IN DWORD dwCreationDistribution,
|
|
IN DWORD dwAttributes,
|
|
IN PEFS_RPC_BLOB pRelativeSD,
|
|
IN BOOL bInheritHandle
|
|
);
|
|
|
|
DWORD
|
|
EfsFileKeyInfoRPCClient(
|
|
IN LPCWSTR lpFileName,
|
|
IN DWORD InfoClass,
|
|
OUT PEFS_RPC_BLOB *KeyInfo
|
|
);
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// Exported function prototypes
|
|
//
|
|
|
|
DWORD
|
|
EfsClientEncryptFile(
|
|
IN LPCWSTR FileName
|
|
);
|
|
|
|
DWORD
|
|
EfsClientDecryptFile(
|
|
IN LPCWSTR FileName,
|
|
IN DWORD Recovery
|
|
);
|
|
|
|
BOOL
|
|
EfsClientFileEncryptionStatus(
|
|
IN LPCWSTR FileName,
|
|
OUT LPDWORD lpStatus
|
|
);
|
|
|
|
DWORD
|
|
EfsClientOpenFileRaw(
|
|
IN LPCWSTR lpFileName,
|
|
IN ULONG Flags,
|
|
OUT PVOID * Context
|
|
);
|
|
|
|
DWORD
|
|
EfsClientReadFileRaw(
|
|
IN PFE_EXPORT_FUNC ExportCallback,
|
|
IN PVOID CallbackContext,
|
|
IN PVOID Context
|
|
);
|
|
|
|
DWORD
|
|
EfsClientWriteFileRaw(
|
|
IN PFE_IMPORT_FUNC ImportCallback,
|
|
IN PVOID CallbackContext,
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
EfsClientCloseFileRaw(
|
|
IN PVOID Context
|
|
);
|
|
|
|
DWORD
|
|
EfsClientAddUsers(
|
|
IN LPCTSTR lpFileName,
|
|
IN PENCRYPTION_CERTIFICATE_LIST pEncryptionCertificates
|
|
);
|
|
|
|
DWORD
|
|
EfsClientRemoveUsers(
|
|
IN LPCTSTR lpFileName,
|
|
IN PENCRYPTION_CERTIFICATE_HASH_LIST pHashes
|
|
);
|
|
|
|
DWORD
|
|
EfsClientQueryRecoveryAgents(
|
|
IN LPCTSTR lpFileName,
|
|
OUT PENCRYPTION_CERTIFICATE_HASH_LIST * pRecoveryAgents
|
|
);
|
|
|
|
DWORD
|
|
EfsClientQueryUsers(
|
|
IN LPCTSTR lpFileName,
|
|
OUT PENCRYPTION_CERTIFICATE_HASH_LIST * pUsers
|
|
);
|
|
|
|
DWORD
|
|
EfsClientSetEncryptionKey(
|
|
IN PENCRYPTION_CERTIFICATE pEncryptionCertificate
|
|
);
|
|
|
|
VOID
|
|
EfsClientFreeHashList(
|
|
IN PENCRYPTION_CERTIFICATE_HASH_LIST pHashList
|
|
);
|
|
|
|
DWORD
|
|
EfsClientDuplicateEncryptionInfo(
|
|
IN LPCWSTR lpSrcFile,
|
|
IN LPCWSTR lpDestFile,
|
|
IN DWORD dwCreationDistribution,
|
|
IN DWORD dwAttributes,
|
|
IN LPSECURITY_ATTRIBUTES lpSecurityAttributes
|
|
);
|
|
|
|
BOOL
|
|
EfsClientEncryptionDisable(
|
|
IN LPCWSTR DirPath,
|
|
IN BOOL Disable
|
|
);
|
|
|
|
DWORD
|
|
EfsClientFileKeyInfo(
|
|
IN LPCWSTR lpFileName,
|
|
IN DWORD InfoClass,
|
|
OUT PEFS_RPC_BLOB *KeyInfo
|
|
);
|
|
|
|
VOID
|
|
EfsClientFreeKeyInfo(
|
|
IN PEFS_RPC_BLOB pKeyInfo
|
|
);
|
|
|
|
FE_CLIENT_DISPATCH_TABLE DispatchTable = { EfsClientEncryptFile,
|
|
EfsClientDecryptFile,
|
|
EfsClientFileEncryptionStatus,
|
|
EfsClientOpenFileRaw,
|
|
EfsClientReadFileRaw,
|
|
EfsClientWriteFileRaw,
|
|
EfsClientCloseFileRaw,
|
|
EfsClientAddUsers,
|
|
EfsClientRemoveUsers,
|
|
EfsClientQueryRecoveryAgents,
|
|
EfsClientQueryUsers,
|
|
EfsClientSetEncryptionKey,
|
|
EfsClientFreeHashList,
|
|
EfsClientDuplicateEncryptionInfo,
|
|
EfsClientEncryptionDisable,
|
|
EfsClientFileKeyInfo,
|
|
EfsClientFreeKeyInfo
|
|
};
|
|
|
|
|
|
FE_CLIENT_INFO ClientInfo = {
|
|
FE_REVISION_1_0,
|
|
&DispatchTable
|
|
};
|
|
|
|
//
|
|
// Internal function prototypes
|
|
//
|
|
|
|
|
|
BOOL
|
|
TranslateFileName(
|
|
IN LPCWSTR FileName,
|
|
OUT PUNICODE_STRING FullFileNameU
|
|
);
|
|
|
|
BOOL
|
|
RemoteFile(
|
|
IN LPCWSTR FileName
|
|
);
|
|
|
|
extern "C"
|
|
BOOL
|
|
EfsClientInit(
|
|
IN PVOID hmod,
|
|
IN ULONG Reason,
|
|
IN PCONTEXT Context
|
|
)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
extern "C"
|
|
BOOL
|
|
FeClientInitialize(
|
|
IN DWORD dwFeRevision,
|
|
OUT LPFE_CLIENT_INFO *lpFeInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
description-of-function.
|
|
|
|
Arguments:
|
|
|
|
dwFeRevision - Is the revision of the current FEAPI interface.
|
|
|
|
lpFeInfo - On successful return, must contain a pointer to a structure
|
|
describing the FE Client Interface. Once returned, the FE Client
|
|
must assume that the caller will continue to reference this table until
|
|
an unload call has been made. Any changes to this information, or
|
|
deallocation of the memory containing the information may result in
|
|
system corruptions.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - Indicates the Client DLL successfully initialized.
|
|
|
|
FALSE - Indicates the client DLL has not loaded. More information may be
|
|
obtained by calling GetLastError().
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
*lpFeInfo = &ClientInfo;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOL
|
|
TranslateFileName(
|
|
IN LPCWSTR FileName,
|
|
OUT PUNICODE_STRING FullFileNameU
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes the filename passed by the user and converts
|
|
it to a fully qualified pathname in the passed Unicode string.
|
|
|
|
Arguments:
|
|
|
|
FileName - Supplies the user-supplied file name.
|
|
|
|
FullFileNameU - Returns the fully qualified pathname of the passed file.
|
|
The buffer in this string is allocated out of heap memory and
|
|
must be freed by the caller.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// Note: need to free the buffer of the returned string
|
|
//
|
|
{
|
|
|
|
UNICODE_STRING FileNameU;
|
|
LPWSTR SrcFileName = (LPWSTR)FileName;
|
|
|
|
if (0 == FileName[0]) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
FullFileNameU->Buffer = (PWSTR)RtlAllocateHeap( RtlProcessHeap(), 0, MAX_PATH * sizeof( WCHAR ));
|
|
if (!FullFileNameU->Buffer) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
FullFileNameU->MaximumLength = MAX_PATH * sizeof( WCHAR );
|
|
|
|
FullFileNameU->Length = (USHORT)RtlGetFullPathName_U(
|
|
SrcFileName,
|
|
FullFileNameU->MaximumLength,
|
|
FullFileNameU->Buffer,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// The return value is supposed to be the length of the filename, without counting
|
|
// the trailing NULL character. MAX_PATH is supposed be long enough to contain
|
|
// the length of the file name and the trailing NULL, so what we get back had
|
|
// better be less than MAX_PATH wchars.
|
|
//
|
|
|
|
if ( FullFileNameU->Length >= FullFileNameU->MaximumLength ){
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, FullFileNameU->Buffer );
|
|
FullFileNameU->Buffer = (PWSTR)RtlAllocateHeap( RtlProcessHeap(), 0, FullFileNameU->Length + sizeof(WCHAR));
|
|
|
|
if (FullFileNameU->Buffer == NULL) {
|
|
return( FALSE );
|
|
}
|
|
FullFileNameU->MaximumLength = FullFileNameU->Length + sizeof(WCHAR);
|
|
|
|
FullFileNameU->Length = (USHORT)RtlGetFullPathName_U(
|
|
SrcFileName,
|
|
FullFileNameU->MaximumLength,
|
|
FullFileNameU->Buffer,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
|
|
if (FullFileNameU->Length == 0) {
|
|
//
|
|
// We failed for some reason
|
|
//
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, FullFileNameU->Buffer );
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
BOOL
|
|
WriteEfsIni(
|
|
IN LPCWSTR SectionName,
|
|
IN LPCWSTR KeyName,
|
|
IN LPCWSTR WriteValue,
|
|
IN LPCWSTR IniFileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes to the ini file. A wrap of WritePrivateProfileString
|
|
|
|
Arguments:
|
|
|
|
SectionName - Section name (Encryption).
|
|
|
|
KeyName - Key name (Disable).
|
|
|
|
WriteValue - The value to be write (1).
|
|
|
|
IniFileName - The path for ini file (dir\desktop.ini).
|
|
|
|
Return Value:
|
|
|
|
TRUE on success
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet;
|
|
|
|
bRet = WritePrivateProfileString(
|
|
SectionName,
|
|
KeyName,
|
|
WriteValue,
|
|
IniFileName
|
|
);
|
|
|
|
//
|
|
// If SetFileAttributes fails, life should go on.
|
|
//
|
|
|
|
SetFileAttributes(IniFileName, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN );
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
EfsClientEncryptionDisable(
|
|
IN LPCWSTR DirPath,
|
|
IN BOOL Disable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine disable and enable EFS in the directory DirPath.
|
|
|
|
Arguments:
|
|
|
|
DirPath - Directory path.
|
|
|
|
Disable - TRUE to disable
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE for SUCCESS
|
|
|
|
--*/
|
|
{
|
|
LPWSTR IniFilePath;
|
|
WCHAR WriteValue[2];
|
|
BOOL bRet = FALSE;
|
|
|
|
if (DirPath) {
|
|
|
|
IniFilePath = (LPWSTR)RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
0,
|
|
(wcslen(DirPath)+1+wcslen(INIFILENAME))*sizeof(WCHAR)
|
|
);
|
|
if (IniFilePath) {
|
|
if (Disable) {
|
|
wcscpy(WriteValue, L"1");
|
|
} else {
|
|
wcscpy(WriteValue, L"0");
|
|
}
|
|
|
|
wcscpy(IniFilePath, DirPath);
|
|
wcscat(IniFilePath, INIFILENAME);
|
|
bRet = WriteEfsIni(INISECTIONNAME, INIKEYNAME, WriteValue, IniFilePath);
|
|
RtlFreeHeap( RtlProcessHeap(), 0, IniFilePath );
|
|
|
|
}
|
|
|
|
} else {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
EfsDisabled(
|
|
IN LPCWSTR SectionName,
|
|
IN LPCWSTR KeyName,
|
|
IN LPCWSTR IniFileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks if the encryption has been turned off for the ini file.
|
|
|
|
Arguments:
|
|
|
|
SectionName - Section name (Encryption).
|
|
|
|
KeyName - Key name (Disable).
|
|
|
|
IniFileName - The path for ini file (dir\desktop.ini).
|
|
|
|
Return Value:
|
|
|
|
TRUE for disabled
|
|
|
|
--*/
|
|
{
|
|
DWORD ValueLength;
|
|
WCHAR ResultString[4];
|
|
|
|
memset( ResultString, 0, sizeof(ResultString) );
|
|
|
|
ValueLength = GetPrivateProfileString(
|
|
SectionName,
|
|
KeyName,
|
|
L"0",
|
|
ResultString,
|
|
sizeof(ResultString)/sizeof(WCHAR),
|
|
IniFileName
|
|
);
|
|
|
|
//
|
|
// If GetPrivateProfileString failed, EFS will be enabled
|
|
//
|
|
|
|
return (!wcscmp(L"1", ResultString));
|
|
}
|
|
|
|
BOOL
|
|
DirEfsDisabled(
|
|
IN LPCWSTR DirName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks if the encryption has been turned off for the dir.
|
|
|
|
Arguments:
|
|
|
|
SectionName - Section name (Encryption).
|
|
|
|
KeyName - Key name (Disable).
|
|
|
|
IniFileName - The path for ini file (dir\desktop.ini).
|
|
|
|
Return Value:
|
|
|
|
TRUE for disabled
|
|
|
|
--*/
|
|
{
|
|
LPWSTR FileName;
|
|
DWORD FileLength = (wcslen(INIFILENAME)+wcslen(DirName)+1)*sizeof (WCHAR);
|
|
BOOL bRet = FALSE;
|
|
|
|
FileName = (PWSTR)RtlAllocateHeap( RtlProcessHeap(), 0, FileLength );
|
|
if (FileName) {
|
|
wcscpy( FileName, DirName );
|
|
wcscat( FileName, INIFILENAME );
|
|
bRet = EfsDisabled( INISECTIONNAME, INIKEYNAME, FileName );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, FileName );
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
RemoteFile(
|
|
IN LPCWSTR FileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks if the file is a local file.
|
|
If a UNC name is passed in, it assumes a remote file. A loopback operation will occur.
|
|
|
|
Arguments:
|
|
|
|
FileName - Supplies the user-supplied file name.
|
|
|
|
Return Value:
|
|
|
|
TRUE for remote file.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if ( FileName[1] == L':' ){
|
|
|
|
WCHAR DriveLetter[3];
|
|
DWORD BufferLength = 3;
|
|
DWORD RetCode = ERROR_SUCCESS;
|
|
|
|
DriveLetter[0] = FileName[0];
|
|
DriveLetter[1] = FileName[1];
|
|
DriveLetter[2] = 0;
|
|
|
|
RetCode = WNetGetConnectionW(
|
|
DriveLetter,
|
|
DriveLetter,
|
|
&BufferLength
|
|
);
|
|
|
|
if (RetCode == ERROR_NOT_CONNECTED) {
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
DWORD
|
|
EfsClientEncryptFile(
|
|
IN LPCWSTR FileName
|
|
)
|
|
{
|
|
DWORD rc;
|
|
BOOL Result;
|
|
|
|
|
|
UNICODE_STRING FullFileNameU;
|
|
|
|
if (NULL == FileName) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
Result = TranslateFileName( FileName, &FullFileNameU );
|
|
|
|
if (Result) {
|
|
|
|
//
|
|
// Call the server
|
|
//
|
|
|
|
rc = EfsEncryptFileRPCClient( &FullFileNameU );
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullFileNameU.Buffer);
|
|
|
|
} else {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
return( rc );
|
|
}
|
|
|
|
DWORD
|
|
EfsClientDecryptFile(
|
|
IN LPCWSTR FileName,
|
|
IN DWORD dwRecovery
|
|
)
|
|
{
|
|
DWORD rc;
|
|
BOOL Result;
|
|
|
|
UNICODE_STRING FullFileNameU;
|
|
|
|
if (NULL == FileName) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
Result = TranslateFileName( FileName, &FullFileNameU );
|
|
|
|
if (Result) {
|
|
|
|
//
|
|
// Call the server
|
|
//
|
|
|
|
rc = EfsDecryptFileRPCClient( &FullFileNameU, dwRecovery );
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullFileNameU.Buffer);
|
|
|
|
} else {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
|
|
return( rc );
|
|
}
|
|
|
|
BOOL
|
|
EfsClientFileEncryptionStatus(
|
|
IN LPCWSTR FileName,
|
|
OUT LPDWORD lpStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks if a file is encryptable or not.
|
|
|
|
We do not test the NTFS Volume 5 for the reason of performance.
|
|
This means we might return a file encryptable (on FAT at etc.), but
|
|
actually it could not be encrypted. This should be OK. This is a best effort
|
|
API. We have the same problem with network file. Any way, a file could fail
|
|
to be encrypted for many reasons, delegation, disk space and etc.
|
|
We disable the encryption from %windir% down.
|
|
We might change these features later.
|
|
|
|
Arguments:
|
|
|
|
FileName - The file to be checked.
|
|
|
|
lpStatus - The encryption status of the file. Error code if the return value is
|
|
FALSE.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL Result;
|
|
DWORD FileAttributes;
|
|
|
|
UNICODE_STRING FullFileNameU;
|
|
|
|
if ((NULL == FileName) || ( NULL == lpStatus)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// GetFileAttributes should use the name before TanslateFileName
|
|
// in case the passed in name is longer than MAX_PATH and using the
|
|
// format \\?\
|
|
//
|
|
|
|
FileAttributes = GetFileAttributes( FileName );
|
|
|
|
if (FileAttributes == -1){
|
|
*lpStatus = GetLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
Result = TranslateFileName( FileName, &FullFileNameU );
|
|
|
|
//
|
|
// FullFileNameU.Length does not include the ending 0. The data returned from TranslateFileName does have the ending 0.
|
|
//
|
|
|
|
ASSERT(FullFileNameU.Buffer[FullFileNameU.Length / 2] == 0);
|
|
|
|
if (Result) {
|
|
|
|
if ( (FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ||
|
|
(FileAttributes & FILE_ATTRIBUTE_SYSTEM) ) {
|
|
|
|
//
|
|
// File not encryptable. Either it is encypted or a system file.
|
|
//
|
|
|
|
if ( FileAttributes & FILE_ATTRIBUTE_ENCRYPTED ){
|
|
|
|
*lpStatus = FILE_IS_ENCRYPTED;
|
|
|
|
} else {
|
|
|
|
*lpStatus = FILE_SYSTEM_ATTR ;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
LPWSTR TmpBuffer;
|
|
LPWSTR FullPathName;
|
|
UINT TmpBuffLen;
|
|
UINT FullPathLen;
|
|
UINT PathLength;
|
|
BOOL GotRoot;
|
|
BOOL EfsDisabled = FALSE;
|
|
|
|
//
|
|
// Check if it is the root.
|
|
//
|
|
|
|
if ( FullFileNameU.Length >= MAX_PATH * sizeof(WCHAR)){
|
|
|
|
//
|
|
// We need to put back the \\?\ or \\?\UNC\ to use the
|
|
// Win 32 API. The extra max bytes needed is 7. ( \\?\UNC + NULL - \)
|
|
//
|
|
|
|
FullPathLen = FullFileNameU.Length + 7 * sizeof(WCHAR);
|
|
TmpBuffLen = FullPathLen;
|
|
FullPathName = (LPWSTR)RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
0,
|
|
FullPathLen
|
|
);
|
|
TmpBuffer = (LPWSTR)RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
0,
|
|
TmpBuffLen
|
|
);
|
|
|
|
if ((FullPathName == NULL) || (TmpBuffer == NULL)){
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullFileNameU.Buffer);
|
|
if (FullPathName){
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullPathName);
|
|
}
|
|
if (TmpBuffer){
|
|
RtlFreeHeap(RtlProcessHeap(), 0, TmpBuffer);
|
|
}
|
|
*lpStatus = ERROR_OUTOFMEMORY;
|
|
return FALSE;
|
|
}
|
|
|
|
if ( FullFileNameU.Buffer[0] == L'\\' ){
|
|
|
|
//
|
|
// Put back the \\?\UNC\
|
|
//
|
|
|
|
wcscpy(FullPathName, L"\\\\?\\UNC");
|
|
wcscat(FullPathName, &(FullFileNameU.Buffer[1]));
|
|
FullPathLen = FullFileNameU.Length + 6 * sizeof(WCHAR);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Put back the \\?\
|
|
//
|
|
|
|
wcscpy(FullPathName, L"\\\\?\\");
|
|
wcscat(FullPathName, FullFileNameU.Buffer);
|
|
FullPathLen = FullFileNameU.Length + 4 * sizeof(WCHAR);
|
|
}
|
|
|
|
} else {
|
|
TmpBuffLen = MAX_PATH * sizeof(WCHAR);
|
|
TmpBuffer = (LPWSTR)RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
0,
|
|
TmpBuffLen
|
|
);
|
|
if (TmpBuffer == NULL){
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullFileNameU.Buffer);
|
|
*lpStatus = ERROR_OUTOFMEMORY;
|
|
return FALSE;
|
|
}
|
|
|
|
FullPathName = FullFileNameU.Buffer;
|
|
FullPathLen = FullFileNameU.Length;
|
|
}
|
|
|
|
//
|
|
// Check desktop.ini here
|
|
//
|
|
|
|
|
|
wcscpy(TmpBuffer, FullFileNameU.Buffer);
|
|
if (!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
|
|
//
|
|
// This is a file. Get the DIR path
|
|
//
|
|
|
|
int ii;
|
|
|
|
ii = wcslen(TmpBuffer) - 1;
|
|
while ((ii >= 0) && (TmpBuffer[ii] != L'\\')) {
|
|
ii--;
|
|
}
|
|
if (ii>=0) {
|
|
TmpBuffer[ii] = 0;
|
|
}
|
|
|
|
}
|
|
|
|
EfsDisabled = DirEfsDisabled( TmpBuffer );
|
|
|
|
if (EfsDisabled) {
|
|
*lpStatus = FILE_DIR_DISALLOWED;
|
|
} else if (!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (FileAttributes & FILE_ATTRIBUTE_READONLY)){
|
|
|
|
//
|
|
// Read only file
|
|
//
|
|
|
|
*lpStatus = FILE_READ_ONLY;
|
|
} else {
|
|
GotRoot = GetVolumePathName(
|
|
FullPathName,
|
|
TmpBuffer,
|
|
TmpBuffLen
|
|
);
|
|
|
|
if ( GotRoot ){
|
|
|
|
DWORD RootLength = wcslen(TmpBuffer) - 1;
|
|
TmpBuffer[RootLength] = NULL;
|
|
if ( (FullPathLen == RootLength * sizeof (WCHAR))
|
|
&& !wcscmp(TmpBuffer, FullPathName)){
|
|
|
|
//
|
|
// It is the root
|
|
//
|
|
|
|
*lpStatus = FILE_ROOT_DIR;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Check if it is the Windows\system32 directories
|
|
//
|
|
|
|
PathLength = GetSystemWindowsDirectory( TmpBuffer, TmpBuffLen );
|
|
//PathLength = GetWindowsDirectory( TmpBuffer, TmpBuffLen );
|
|
//PathLength = GetSystemDirectory( TmpBuffer, TmpBuffLen );
|
|
|
|
ASSERT(PathLength <= TmpBuffLen);
|
|
|
|
if ( PathLength > TmpBuffLen ) {
|
|
|
|
//
|
|
// This is unlikely. Not sure who will ever have the length
|
|
// of %windir%\system32 longer than MAXPATH in the real world.
|
|
// Even this happen, user could still encrypt the file. FILE_UNKNOWN
|
|
// does not mean file could\or couldn't be encrypted.
|
|
//
|
|
|
|
*lpStatus = FILE_UNKNOWN ;
|
|
|
|
} else {
|
|
|
|
if ( ( FullFileNameU.Length < PathLength * sizeof (WCHAR) ) ||
|
|
( ( FullFileNameU.Buffer[PathLength] ) &&
|
|
( FullFileNameU.Buffer[PathLength] != L'\\') )){
|
|
|
|
//
|
|
// Check if a remote file
|
|
//
|
|
|
|
if ( RemoteFile( FullFileNameU.Buffer ) ){
|
|
|
|
*lpStatus = FILE_UNKNOWN;
|
|
|
|
} else {
|
|
|
|
*lpStatus = FILE_ENCRYPTABLE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( _wcsnicmp(TmpBuffer, FullFileNameU.Buffer, PathLength)){
|
|
|
|
//
|
|
// Not under %SystemRoot%
|
|
//
|
|
|
|
if ( RemoteFile( FullFileNameU.Buffer ) ){
|
|
|
|
*lpStatus = FILE_UNKNOWN;
|
|
|
|
} else {
|
|
|
|
*lpStatus = FILE_ENCRYPTABLE;
|
|
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// In windows root directory. WINNT
|
|
//
|
|
|
|
BOOL bRet;
|
|
DWORD allowPathLen;
|
|
|
|
//
|
|
// Check for allow lists
|
|
//
|
|
|
|
allowPathLen = (DWORD) TmpBuffLen;
|
|
bRet = GetProfilesDirectory(TmpBuffer, &allowPathLen);
|
|
if (!bRet){
|
|
RtlFreeHeap(RtlProcessHeap(), 0, TmpBuffer);
|
|
TmpBuffer = (LPWSTR)RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
0,
|
|
allowPathLen
|
|
);
|
|
if (TmpBuffer){
|
|
bRet = GetProfilesDirectory(TmpBuffer, &allowPathLen);
|
|
} else {
|
|
*lpStatus = ERROR_OUTOFMEMORY;
|
|
Result = FALSE;
|
|
}
|
|
}
|
|
if (bRet){
|
|
|
|
//
|
|
// Check for Profiles directory. allowPathLen including NULL.
|
|
//
|
|
|
|
if ((FullFileNameU.Length >= ((allowPathLen-1) * sizeof (WCHAR)) ) &&
|
|
!_wcsnicmp(TmpBuffer, FullFileNameU.Buffer, allowPathLen - 1)){
|
|
*lpStatus = FILE_ENCRYPTABLE;
|
|
} else {
|
|
|
|
//
|
|
// Under %windir% but not profiles
|
|
//
|
|
|
|
*lpStatus = FILE_SYSTEM_DIR;
|
|
}
|
|
} else {
|
|
|
|
if ( *lpStatus != ERROR_OUTOFMEMORY){
|
|
|
|
//
|
|
// This should not happen, unless a bug in GetProfilesDirectoryEx()
|
|
//
|
|
ASSERT(FALSE);
|
|
|
|
*lpStatus = FILE_UNKNOWN;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// Cannot get the root. The reason might very well be out of memory.
|
|
// Return FILE_UNKNOWN and let other codes dealing with the memory
|
|
// problem.
|
|
//
|
|
|
|
*lpStatus = FILE_UNKNOWN ;
|
|
|
|
}
|
|
}
|
|
|
|
if ((FullPathName != FullFileNameU.Buffer) && FullPathName){
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullPathName);
|
|
}
|
|
|
|
if (TmpBuffer){
|
|
RtlFreeHeap(RtlProcessHeap(), 0, TmpBuffer);
|
|
}
|
|
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullFileNameU.Buffer);
|
|
|
|
} else {
|
|
*lpStatus = GetLastError();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
DWORD
|
|
EfsClientOpenFileRaw(
|
|
IN LPCWSTR FileName,
|
|
IN ULONG Flags,
|
|
OUT PVOID * Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to open an encrypted file. It opens the file and
|
|
prepares the necessary context to be used in ReadRaw data and WriteRaw
|
|
data.
|
|
|
|
|
|
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 rc;
|
|
BOOL Result;
|
|
UNICODE_STRING FullFileNameU;
|
|
|
|
if ((NULL == FileName) || ( NULL == Context)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
Result = TranslateFileName( FileName, &FullFileNameU );
|
|
|
|
if (Result) {
|
|
|
|
rc = (EfsOpenFileRawRPCClient(
|
|
FullFileNameU.Buffer,
|
|
Flags,
|
|
Context
|
|
)
|
|
);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullFileNameU.Buffer);
|
|
|
|
} else {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
DWORD
|
|
EfsClientReadFileRaw(
|
|
IN PFE_EXPORT_FUNC ExportCallback,
|
|
IN PVOID CallbackContext,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to read encrypted file's raw data. It uses
|
|
NTFS FSCTL to get the data.
|
|
|
|
Arguments:
|
|
|
|
ExportCallback -- Caller supplied callback function to process the
|
|
raw data.
|
|
|
|
CallbackContext -- Caller's context passed back in ExportCallback.
|
|
|
|
Context - Export context created in the CreateRaw.
|
|
|
|
Return Value:
|
|
|
|
Result of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
return ( EfsReadFileRawRPCClient(
|
|
ExportCallback,
|
|
CallbackContext,
|
|
Context
|
|
));
|
|
}
|
|
|
|
DWORD
|
|
EfsClientWriteFileRaw(
|
|
IN PFE_IMPORT_FUNC ImportCallback,
|
|
IN PVOID CallbackContext,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to write encrypted file's raw data. It uses
|
|
NTFS FSCTL to write the data.
|
|
|
|
Arguments:
|
|
|
|
ImportCallback -- Caller supplied callback function to provide the
|
|
raw data.
|
|
|
|
CallbackContext -- Caller's context passed back in ImportCallback.
|
|
|
|
Context - Import context created in the CreateRaw.
|
|
|
|
Return Value:
|
|
|
|
Result of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
return ( EfsWriteFileRawRPCClient(
|
|
ImportCallback,
|
|
CallbackContext,
|
|
Context
|
|
));
|
|
}
|
|
|
|
VOID
|
|
EfsClientCloseFileRaw(
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees the resources allocated by the CreateRaw
|
|
|
|
Arguments:
|
|
|
|
Context - Created by the CreateRaw.
|
|
|
|
Return Value:
|
|
|
|
NO.
|
|
|
|
--*/
|
|
{
|
|
if ( !Context ){
|
|
return;
|
|
}
|
|
|
|
EfsCloseFileRawRPCClient( Context );
|
|
}
|
|
|
|
|
|
//
|
|
// Beta 2 API
|
|
//
|
|
|
|
DWORD
|
|
EfsClientAddUsers(
|
|
IN LPCWSTR lpFileName,
|
|
IN PENCRYPTION_CERTIFICATE_LIST pEncryptionCertificates
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls client stub for AddUsersToFile EFS API.
|
|
|
|
Arguments:
|
|
|
|
lpFileName - Supplies the name of the file to be modified.
|
|
|
|
nUsers - Supplies the number of entries in teh pEncryptionCertificates array
|
|
|
|
pEncryptionCertificates - Supplies an array of pointers to PENCRYPTION_CERTIFICATE
|
|
structures. Length of array is given in nUsers parameter.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
UNICODE_STRING FullFileNameU;
|
|
DWORD ii = 0;
|
|
CERT_CHAIN_PARA CertChainPara;
|
|
|
|
|
|
if ((NULL == lpFileName) || (NULL == pEncryptionCertificates)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Let's check to see if the certs are good or not.
|
|
//
|
|
|
|
CertChainPara.cbSize = sizeof(CERT_CHAIN_PARA);
|
|
CertChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
|
|
CertChainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
|
|
CertChainPara.RequestedUsage.Usage.rgpszUsageIdentifier=&EfsOidlpstr;
|
|
|
|
while ((ERROR_SUCCESS == rc) && (ii < pEncryptionCertificates->nUsers)) {
|
|
|
|
PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING,
|
|
pEncryptionCertificates->pUsers[ii]->pCertBlob->pbData,
|
|
pEncryptionCertificates->pUsers[ii]->pCertBlob->cbData
|
|
);
|
|
if (pCertContext != NULL) {
|
|
|
|
PCCERT_CHAIN_CONTEXT pChainContext;
|
|
|
|
//
|
|
// Do the chain validation
|
|
//
|
|
|
|
if (CertGetCertificateChain (
|
|
HCCE_CURRENT_USER,
|
|
pCertContext,
|
|
NULL,
|
|
NULL,
|
|
&CertChainPara,
|
|
0,
|
|
NULL,
|
|
&pChainContext
|
|
)) {
|
|
//
|
|
// Let's check the chain
|
|
//
|
|
|
|
PCERT_SIMPLE_CHAIN pChain = pChainContext->rgpChain[ 0 ];
|
|
PCERT_CHAIN_ELEMENT pElement = pChain->rgpElement[ 0 ];
|
|
BOOL bSelfSigned = pElement->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED;
|
|
DWORD dwErrorStatus = pChainContext->TrustStatus.dwErrorStatus;
|
|
|
|
if (dwErrorStatus) {
|
|
if ((dwErrorStatus == CERT_TRUST_IS_UNTRUSTED_ROOT) && bSelfSigned ){
|
|
|
|
//
|
|
// Self signed. Check if it is in the my trusted store
|
|
//
|
|
HCERTSTORE trustedStore;
|
|
PCCERT_CONTEXT pCert=NULL;
|
|
|
|
trustedStore = CertOpenStore(
|
|
CERT_STORE_PROV_SYSTEM_W,
|
|
0, // dwEncodingType
|
|
0, // hCryptProv,
|
|
CERT_SYSTEM_STORE_CURRENT_USER,
|
|
TRUSTEDPEOPLE
|
|
);
|
|
|
|
if (trustedStore) {
|
|
|
|
pCert = CertFindCertificateInStore(
|
|
trustedStore,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_EXISTING,
|
|
pCertContext,
|
|
pCert
|
|
);
|
|
if (pCert) {
|
|
|
|
//
|
|
// We found it.
|
|
//
|
|
CertFreeCertificateContext(pCert);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Not trusted self-signed cert
|
|
//
|
|
|
|
rc = CERT_E_UNTRUSTEDROOT;
|
|
|
|
}
|
|
|
|
CertCloseStore( trustedStore, 0 );
|
|
|
|
} else {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Other chain build error
|
|
// Let's get the error code of the chain building.
|
|
//
|
|
|
|
CERT_CHAIN_POLICY_PARA PolicyPara;
|
|
CERT_CHAIN_POLICY_STATUS PolicyStatus;
|
|
|
|
RtlZeroMemory(&PolicyPara, sizeof(CERT_CHAIN_POLICY_PARA));
|
|
RtlZeroMemory(&PolicyStatus, sizeof(CERT_CHAIN_POLICY_STATUS));
|
|
|
|
PolicyPara.cbSize = sizeof(CERT_CHAIN_POLICY_PARA);
|
|
PolicyStatus.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS);
|
|
|
|
if (!CertVerifyCertificateChainPolicy(
|
|
CERT_CHAIN_POLICY_BASE,
|
|
pChainContext,
|
|
&PolicyPara,
|
|
&PolicyStatus
|
|
)) {
|
|
|
|
rc = PolicyStatus.dwError;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
CertFreeCertificateChain( pChainContext );
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
|
|
}
|
|
|
|
CertFreeCertificateContext(pCertContext);
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
|
|
}
|
|
|
|
ii++;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == rc) {
|
|
|
|
if (TranslateFileName( lpFileName, &FullFileNameU )) {
|
|
|
|
rc = EfsAddUsersRPCClient( FullFileNameU.Buffer, pEncryptionCertificates );
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullFileNameU.Buffer);
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
EfsClientRemoveUsers(
|
|
IN LPCWSTR lpFileName,
|
|
IN PENCRYPTION_CERTIFICATE_HASH_LIST pHashes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls client stub for RemoveUsersFromFile EFS API
|
|
|
|
Arguments:
|
|
|
|
lpFileName - Supplies the name of the file to be modified.
|
|
|
|
pHashes - Supplies a structure containing a list of PENCRYPTION_CERTIFICATE_HASH
|
|
structures, each of which represents a user to remove from the specified file.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
DWORD rc;
|
|
UNICODE_STRING FullFileNameU;
|
|
|
|
|
|
if ((NULL == lpFileName) || (NULL == pHashes) || (pHashes->pUsers == NULL)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
if (TranslateFileName( lpFileName, &FullFileNameU )) {
|
|
|
|
rc = EfsRemoveUsersRPCClient( FullFileNameU.Buffer, pHashes );
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullFileNameU.Buffer);
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
EfsClientQueryRecoveryAgents(
|
|
IN LPCWSTR lpFileName,
|
|
OUT PENCRYPTION_CERTIFICATE_HASH_LIST * pRecoveryAgents
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls client stub for QueryRecoveryAgents EFS API
|
|
|
|
Arguments:
|
|
|
|
lpFileName - Supplies the name of the file to be modified.
|
|
|
|
pRecoveryAgents - Returns a pointer to a structure containing a list
|
|
of PENCRYPTION_CERTIFICATE_HASH structures, each of which represents
|
|
a recovery agent on the file.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
DWORD rc;
|
|
UNICODE_STRING FullFileNameU;
|
|
|
|
|
|
if ((NULL == lpFileName) || (NULL == pRecoveryAgents)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
if (TranslateFileName( lpFileName, &FullFileNameU )) {
|
|
|
|
rc = EfsQueryRecoveryAgentsRPCClient( FullFileNameU.Buffer, pRecoveryAgents );
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullFileNameU.Buffer);
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
EfsClientQueryUsers(
|
|
IN LPCWSTR lpFileName,
|
|
OUT PENCRYPTION_CERTIFICATE_HASH_LIST * pUsers
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls client stub for QueryUsersOnFile EFS API
|
|
|
|
Arguments:
|
|
|
|
lpFileName - Supplies the name of the file to be modified.
|
|
|
|
pUsers - Returns a pointer to a structure containing a list
|
|
of PENCRYPTION_CERTIFICATE_HASH structures, each of which represents
|
|
a user of this file (that is, someone who can decrypt the file).
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
DWORD rc;
|
|
UNICODE_STRING FullFileNameU;
|
|
|
|
if ((NULL == lpFileName) || (NULL == pUsers)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
if (TranslateFileName( lpFileName, &FullFileNameU )) {
|
|
|
|
rc = EfsQueryUsersRPCClient( FullFileNameU.Buffer, pUsers );
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullFileNameU.Buffer);
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
EfsClientSetEncryptionKey(
|
|
IN PENCRYPTION_CERTIFICATE pEncryptionCertificate
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls client stub for SetFileEncryptionKey EFS API
|
|
|
|
Arguments:
|
|
|
|
pEncryptionCertificate - Supplies a pointer to an EFS certificate
|
|
representing the public key to use for future encryption operations.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
/*
|
|
if ((NULL == pEncryptionCertificate) || ( NULL == pEncryptionCertificate->pCertBlob)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
*/
|
|
|
|
if ( pEncryptionCertificate && ( NULL == pEncryptionCertificate->pCertBlob)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
DWORD rc = EfsSetEncryptionKeyRPCClient( pEncryptionCertificate );
|
|
|
|
return( rc );
|
|
}
|
|
|
|
VOID
|
|
EfsClientFreeHashList(
|
|
IN PENCRYPTION_CERTIFICATE_HASH_LIST pHashList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees the memory allocated by a call to
|
|
QueryUsersOnEncryptedFile and QueryRecoveryAgentsOnEncryptedFile
|
|
|
|
Arguments:
|
|
|
|
pHashList - Supplies the hash list to be freed.
|
|
|
|
Return Value:
|
|
|
|
None. Faults in user's context if passed bogus data.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (NULL == pHashList) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return;
|
|
}
|
|
|
|
for (DWORD i=0; i<pHashList->nCert_Hash ; i++) {
|
|
|
|
PENCRYPTION_CERTIFICATE_HASH pHash = pHashList->pUsers[i];
|
|
|
|
if (pHash->lpDisplayInformation) {
|
|
MIDL_user_free( pHash->lpDisplayInformation );
|
|
}
|
|
|
|
if (pHash->pUserSid) {
|
|
MIDL_user_free( pHash->pUserSid );
|
|
}
|
|
|
|
MIDL_user_free( pHash->pHash->pbData );
|
|
MIDL_user_free( pHash->pHash );
|
|
MIDL_user_free( pHash );
|
|
}
|
|
|
|
MIDL_user_free( pHashList->pUsers );
|
|
MIDL_user_free( pHashList );
|
|
|
|
return;
|
|
}
|
|
|
|
DWORD
|
|
EfsGetMySDRpcBlob(
|
|
IN PSECURITY_DESCRIPTOR pInSD,
|
|
OUT PEFS_RPC_BLOB *pOutSDRpcBlob
|
|
)
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
PSECURITY_DESCRIPTOR pRelativeSD;
|
|
ULONG SDLength = 0;
|
|
|
|
if ( (pInSD == NULL) || !RtlValidSecurityDescriptor(pInSD) ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( ((PISECURITY_DESCRIPTOR)pInSD)->Control & SE_SELF_RELATIVE) {
|
|
|
|
//
|
|
// The input SD is already RELATIVE
|
|
// Just fill EFS_RPC_BLOB
|
|
//
|
|
|
|
|
|
*pOutSDRpcBlob = (PEFS_RPC_BLOB) RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
0,
|
|
sizeof(EFS_RPC_BLOB)
|
|
);
|
|
if (*pOutSDRpcBlob) {
|
|
|
|
(*pOutSDRpcBlob)->cbData = RtlLengthSecurityDescriptor (
|
|
pInSD
|
|
);
|
|
(*pOutSDRpcBlob)->pbData = (PBYTE) pInSD;
|
|
|
|
} else {
|
|
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
//
|
|
// get the length
|
|
//
|
|
RtlMakeSelfRelativeSD( pInSD,
|
|
NULL,
|
|
&SDLength
|
|
);
|
|
|
|
if ( SDLength > 0 ) {
|
|
|
|
*pOutSDRpcBlob = (PEFS_RPC_BLOB) RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
0,
|
|
SDLength + sizeof(EFS_RPC_BLOB)
|
|
);
|
|
|
|
|
|
if ( !(*pOutSDRpcBlob) ) {
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
pRelativeSD = (PSECURITY_DESCRIPTOR)(*pOutSDRpcBlob + 1);
|
|
(*pOutSDRpcBlob)->cbData = SDLength;
|
|
(*pOutSDRpcBlob)->pbData = (PBYTE) pRelativeSD;
|
|
|
|
|
|
rc = RtlNtStatusToDosError(
|
|
RtlMakeSelfRelativeSD( pInSD,
|
|
pRelativeSD,
|
|
&SDLength
|
|
));
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, *pOutSDRpcBlob);
|
|
*pOutSDRpcBlob = NULL;
|
|
return(rc);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// something is wrong with the SD
|
|
//
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
DWORD
|
|
EfsClientDuplicateEncryptionInfo(
|
|
IN LPCWSTR lpSrcFile,
|
|
IN LPCWSTR lpDestFile,
|
|
IN DWORD dwCreationDistribution,
|
|
IN DWORD dwAttributes,
|
|
IN LPSECURITY_ATTRIBUTES lpSecurityAttributes
|
|
)
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
|
|
UNICODE_STRING SrcFullFileNameU;
|
|
UNICODE_STRING DestFullFileNameU;
|
|
|
|
if (TranslateFileName( lpSrcFile, &SrcFullFileNameU )) {
|
|
|
|
if (TranslateFileName( lpDestFile, &DestFullFileNameU )) {
|
|
|
|
PEFS_RPC_BLOB pRpcBlob = NULL;
|
|
BOOL bInheritHandle = FALSE;
|
|
|
|
if (lpSecurityAttributes) {
|
|
rc = EfsGetMySDRpcBlob(lpSecurityAttributes->lpSecurityDescriptor, &pRpcBlob);
|
|
bInheritHandle = lpSecurityAttributes->bInheritHandle;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == rc) {
|
|
|
|
rc = EfsDuplicateEncryptionInfoRPCClient(
|
|
SrcFullFileNameU.Buffer,
|
|
DestFullFileNameU.Buffer,
|
|
dwCreationDistribution,
|
|
dwAttributes,
|
|
pRpcBlob,
|
|
bInheritHandle
|
|
);
|
|
|
|
if (pRpcBlob) {
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, pRpcBlob);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, DestFullFileNameU.Buffer);
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, SrcFullFileNameU.Buffer);
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
}
|
|
|
|
return( rc );
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
EfsClientFileKeyInfo(
|
|
IN LPCWSTR lpFileName,
|
|
IN DWORD InfoClass,
|
|
OUT PEFS_RPC_BLOB *KeyInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls client stub for EncryptedFileKeyInfo EFS API
|
|
|
|
Arguments:
|
|
|
|
lpFileName - Supplies the name of the file.
|
|
|
|
KeyInfo - Returns a pointer to a structure containing key info.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
DWORD rc;
|
|
UNICODE_STRING FullFileNameU;
|
|
DWORD FileAttributes;
|
|
|
|
if ((NULL == lpFileName) || (NULL == KeyInfo)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((InfoClass != BASIC_KEY_INFO) && (InfoClass != UPDATE_KEY_USED)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( InfoClass == UPDATE_KEY_USED) {
|
|
|
|
FileAttributes = GetFileAttributes( lpFileName );
|
|
if ( (FileAttributes == -1) || !(FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
|
}
|
|
|
|
if (TranslateFileName( lpFileName, &FullFileNameU )) {
|
|
|
|
rc = EfsFileKeyInfoRPCClient( FullFileNameU.Buffer, InfoClass, KeyInfo );
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FullFileNameU.Buffer);
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
VOID
|
|
EfsClientFreeKeyInfo(
|
|
IN PEFS_RPC_BLOB pKeyInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees the memory allocated by a call to
|
|
EfsClientFileKeyInfo
|
|
|
|
Arguments:
|
|
|
|
pKeyInfo - Supplies the memory pointer to be freed.
|
|
|
|
Return Value:
|
|
|
|
None. Faults in user's context if passed bogus data.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (NULL == pKeyInfo) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return;
|
|
}
|
|
|
|
if (pKeyInfo->pbData) {
|
|
MIDL_user_free( pKeyInfo->pbData );
|
|
}
|
|
|
|
MIDL_user_free( pKeyInfo );
|
|
|
|
return;
|
|
}
|