3199 lines
83 KiB
C++
3199 lines
83 KiB
C++
/*++
|
||
|
||
Copyright (c) 1998 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
recovery.cpp
|
||
|
||
Abstract:
|
||
|
||
This module implements the callout from winlogon to set
|
||
recovery policy.
|
||
|
||
Author:
|
||
|
||
Robert Reichel (RobertRe)
|
||
|
||
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 <ntlsa.h>
|
||
#include <windows.h>
|
||
#include <stdio.h>
|
||
#include <lmcons.h>
|
||
#include <cryptui.h>
|
||
#include <winwlx.h>
|
||
#include <malloc.h>
|
||
#include <feclient.h>
|
||
#include <efsstruc.h>
|
||
#include <netlib.h>
|
||
#include <secobj.h>
|
||
|
||
#include <initguid.h>
|
||
#include <gpedit.h>
|
||
#include <wincrypt.h>
|
||
#include <winreg.h>
|
||
#include <dsrole.h>
|
||
|
||
|
||
#include <winldap.h>
|
||
#include <dsgetdc.h>
|
||
#include <ntdsapi.h>
|
||
|
||
#include "sclgntfy.hxx"
|
||
|
||
#define YEARCOUNT (LONGLONG) 10000000*3600*24*365 // One Year's tick count
|
||
|
||
typedef BOOL (WINAPI *PFREFRESHPOLICY)(BOOL);
|
||
|
||
extern HINSTANCE g_hDllInstance;
|
||
|
||
HANDLE hEventLog = NULL;
|
||
TCHAR EventSourceName[] = TEXT("SclgNtfy");
|
||
|
||
GUID guidExtension = { 0xb1be8d72, 0x6eac, 0x11d2, {0xa4, 0xea, 0x00, 0xc0, 0x4f, 0x79, 0xf8, 0x3a }};
|
||
GUID guidRegExt = REGISTRY_EXTENSION_GUID;
|
||
GUID guidSnapin = {0x53D6AB1B,0x2488,0x11d1,{0xA2,0x8C,0x00,0xC0,0x4F,0xB9,0x4F,0x17}}; // CLSID_CertificateManager
|
||
|
||
//
|
||
// Event handle
|
||
//
|
||
|
||
PTOKEN_USER
|
||
GetTokenUser(
|
||
HANDLE TokenHandle
|
||
);
|
||
|
||
BOOLEAN
|
||
CreateSelfSignedRecoveryCertificate(
|
||
IN BOOL bIsDC,
|
||
OUT PCCERT_CONTEXT * pCertContext
|
||
);
|
||
|
||
BOOL
|
||
EncodeAndAlloc(
|
||
DWORD dwEncodingType,
|
||
LPCSTR lpszStructType,
|
||
const void * pvStructInfo,
|
||
PBYTE * pbEncoded,
|
||
PDWORD pcbEncoded
|
||
);
|
||
|
||
LPWSTR
|
||
MakeDNName(
|
||
VOID
|
||
);
|
||
|
||
DWORD
|
||
CreatePublicKeyInformationCertificate(
|
||
IN PSID pUserSid OPTIONAL,
|
||
PBYTE pbCert,
|
||
DWORD cbCert,
|
||
OUT PEFS_PUBLIC_KEY_INFO * PublicKeyInformation
|
||
);
|
||
|
||
DWORD
|
||
GetDefaultRecoveryPolicy(
|
||
IN HANDLE hToken,
|
||
IN BOOL bIsDC,
|
||
OUT PUCHAR *pRecoveryPolicyBlob,
|
||
OUT ULONG *PolicySize,
|
||
OUT PCCERT_CONTEXT *ppCertContext
|
||
);
|
||
|
||
HRESULT
|
||
CreateLocalMachinePolicy(
|
||
IN PWLX_NOTIFICATION_INFO pInfo,
|
||
IN BOOL bIsDC,
|
||
OUT PUCHAR *pEfsBlob,
|
||
OUT ULONG *pEfsSize,
|
||
OUT PCCERT_CONTEXT *ppCertContext
|
||
);
|
||
|
||
typedef DWORD (WINAPI *PFNDSGETDCNAME)(LPCTSTR, LPCTSTR, GUID *, LPCTSTR, ULONG, PDOMAIN_CONTROLLER_INFO *);
|
||
|
||
HRESULT
|
||
CreateEFSDefaultPolicy(
|
||
IN HANDLE hToken,
|
||
IN PUCHAR *pEfsBlob,
|
||
IN DWORD *pEfsSize,
|
||
IN PCCERT_CONTEXT *ppCertContext,
|
||
IN LPTSTR DomainName
|
||
);
|
||
|
||
DWORD
|
||
MyLdapOpen(
|
||
OUT PLDAP *pLdap
|
||
);
|
||
|
||
DWORD
|
||
MyGetDsObjectRoot(
|
||
IN PLDAP pLdap,
|
||
OUT PWSTR *pDsRootName
|
||
);
|
||
|
||
HRESULT
|
||
CreateGroupPolicyObjectInDomain(
|
||
IN HANDLE hToken,
|
||
IN PWSTR DomainNCName,
|
||
IN PWSTR GPObjectName,
|
||
IN PUCHAR EfsBlob,
|
||
IN ULONG EfsSize,
|
||
IN PCCERT_CONTEXT pCertContext,
|
||
OUT LPGROUPPOLICYOBJECT *ppObject
|
||
);
|
||
|
||
DWORD
|
||
CheckExistingEFSPolicy(
|
||
IN PLDAP phLdap,
|
||
IN LPTSTR DomainNCName,
|
||
OUT BOOL *bExist
|
||
);
|
||
|
||
DWORD
|
||
MyLdapClose(
|
||
IN PLDAP *pLdap
|
||
);
|
||
|
||
LPWSTR
|
||
GetCertDisplayInformation(
|
||
IN PCCERT_CONTEXT pCertContext
|
||
);
|
||
|
||
BOOLEAN
|
||
IsSelfSignedPolicyExpired(
|
||
IN PRECOVERY_POLICY_1_1 RecoveryPolicy OPTIONAL
|
||
);
|
||
|
||
#define EFS_NOTIFY_PATH TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify\\EFS")
|
||
|
||
|
||
extern "C"
|
||
BOOL
|
||
EfsRecInit(
|
||
IN PVOID hmod,
|
||
IN ULONG Reason,
|
||
IN PCONTEXT Context
|
||
)
|
||
{
|
||
return( TRUE );
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// DllRegisterServer - Adds entries to the system registry
|
||
|
||
STDAPI DllRegisterServerEFS(void)
|
||
{
|
||
HKEY hKey;
|
||
LONG lResult;
|
||
DWORD dwDisp;
|
||
|
||
lResult = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
|
||
EFS_NOTIFY_PATH,
|
||
0,
|
||
NULL,
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_WRITE,
|
||
NULL,
|
||
&hKey,
|
||
&dwDisp
|
||
);
|
||
|
||
if (lResult != ERROR_SUCCESS)
|
||
{
|
||
return lResult;
|
||
}
|
||
|
||
RegSetValueEx( hKey,
|
||
TEXT("Logon"),
|
||
0,
|
||
REG_SZ,
|
||
(LPBYTE)TEXT("WLEventLogon"),
|
||
(lstrlen(TEXT("WLEventLogon")) + 1) * sizeof(TCHAR)
|
||
);
|
||
|
||
RegSetValueEx( hKey,
|
||
TEXT("DllName"),
|
||
0,
|
||
REG_EXPAND_SZ,
|
||
(LPBYTE)TEXT("sclgntfy.dll"),
|
||
(lstrlen(TEXT("sclgntfy.dll")) + 1) * sizeof(TCHAR)
|
||
);
|
||
//
|
||
// increase the wait limit to 10 minutes
|
||
//
|
||
DWORD dwValue = 120;
|
||
|
||
RegSetValueEx( hKey,
|
||
TEXT("MaxWait"),
|
||
0,
|
||
REG_DWORD,
|
||
(LPBYTE)&dwValue,
|
||
sizeof(DWORD)
|
||
);
|
||
|
||
RegCloseKey (hKey);
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// DllUnregisterServer - Removes entries from the system registry
|
||
|
||
STDAPI DllUnregisterServerEFS(void)
|
||
{
|
||
|
||
RegDeleteKey (HKEY_LOCAL_MACHINE, EFS_NOTIFY_PATH);
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
DWORD WINAPI
|
||
EFSRecPolicyPostProcess(
|
||
IN LPVOID Param
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
|
||
Enumerate the volumes and do the possible recovery jobs caused by
|
||
power outage or crash during encryption or decryption.
|
||
|
||
Arguments:
|
||
|
||
Param -- Standard parameter for thread. Not used.
|
||
|
||
Return Value:
|
||
|
||
Operation result.
|
||
|
||
--*/
|
||
{
|
||
PEFS_POLICY_POST_PROCESS pPcType = (PEFS_POLICY_POST_PROCESS) Param;
|
||
LPWSTR objName = NULL;
|
||
LPWSTR popUpMsg = NULL;
|
||
LPWSTR popUpTitle = NULL;
|
||
DWORD dRet;
|
||
|
||
DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1;
|
||
|
||
if ( pPcType == NULL ) {
|
||
return(ERROR_INVALID_PARAMETER);
|
||
}
|
||
|
||
if (!SetThreadDesktop( pPcType->ShellWnd )){
|
||
return GetLastError();
|
||
}
|
||
|
||
if (!(pPcType->PCIsDC)) {
|
||
|
||
//
|
||
// Get the PC name
|
||
//
|
||
|
||
BOOL b = GetComputerName ( pPcType->ObjName, &nSize );
|
||
|
||
if (b) {
|
||
objName = pPcType->ObjName;
|
||
}
|
||
|
||
} else {
|
||
objName = pPcType->ObjName;
|
||
}
|
||
|
||
dRet = FormatMessage(
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||
g_hDllInstance,
|
||
EFS_POLICY_WARNING,
|
||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||
(LPTSTR) &popUpMsg,
|
||
0,
|
||
(va_list *)&objName
|
||
);
|
||
|
||
if (dRet) {
|
||
dRet = FormatMessage(
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY | 80,
|
||
g_hDllInstance,
|
||
EFS_POLICY_WARNING_TITLE,
|
||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||
(LPTSTR) &popUpTitle,
|
||
0,
|
||
NULL
|
||
);
|
||
if (dRet) {
|
||
MessageBox(NULL, popUpMsg, popUpTitle, MB_OK | MB_ICONINFORMATION);
|
||
LocalFree( popUpTitle );
|
||
}
|
||
LocalFree( popUpMsg );
|
||
}
|
||
|
||
//
|
||
// free the buffer allocated
|
||
//
|
||
LocalFree(pPcType);
|
||
|
||
return 0;
|
||
|
||
}
|
||
|
||
#if 0
|
||
DWORD
|
||
EFSRecPolicyPopup(
|
||
IN DSROLE_MACHINE_ROLE MachineRole,
|
||
IN LPTSTR DomainNameFlat OPTIONAL
|
||
)
|
||
{
|
||
|
||
DWORD EFSRecPolicyThreadID;
|
||
HANDLE EfsWarningThread;
|
||
PEFS_POLICY_POST_PROCESS PcType = NULL;
|
||
|
||
//
|
||
// Pop the dialog warning the user that the recovery policy has been created.
|
||
//
|
||
|
||
PcType = (PEFS_POLICY_POST_PROCESS)LocalAlloc(LPTR, sizeof(EFS_POLICY_POST_PROCESS));
|
||
|
||
if ( PcType == NULL ) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
|
||
if (MachineRole == DsRole_RolePrimaryDomainController ||
|
||
MachineRole == DsRole_RoleBackupDomainController ) {
|
||
|
||
//
|
||
// The PC is a DC.
|
||
//
|
||
|
||
PcType->PCIsDC = TRUE;
|
||
if ( DomainNameFlat) {
|
||
wcscpy(PcType->ObjName,DomainNameFlat);
|
||
} else {
|
||
PcType->ObjName[0] = L'\0';
|
||
}
|
||
|
||
} else {
|
||
|
||
PcType->PCIsDC = FALSE;
|
||
PcType->ObjName[0] = L'\0';
|
||
|
||
}
|
||
|
||
DWORD rc=ERROR_SUCCESS;
|
||
|
||
PcType->ShellWnd = GetThreadDesktop( GetCurrentThreadId() );
|
||
|
||
if (PcType->ShellWnd) {
|
||
|
||
EfsWarningThread = CreateThread( NULL,
|
||
0,
|
||
EFSRecPolicyPostProcess,
|
||
PcType,
|
||
0,
|
||
&EFSRecPolicyThreadID
|
||
);
|
||
if (EfsWarningThread) {
|
||
CloseHandle(EfsWarningThread);
|
||
} else {
|
||
//
|
||
// free the buffer allocated
|
||
//
|
||
LocalFree(PcType);
|
||
rc = GetLastError();
|
||
}
|
||
|
||
} else {
|
||
//
|
||
// free the buffer allocated
|
||
//
|
||
LocalFree(PcType);
|
||
rc = GetLastError();
|
||
}
|
||
|
||
return rc;
|
||
|
||
}
|
||
#endif
|
||
|
||
VOID WLEventLogon(
|
||
PWLX_NOTIFICATION_INFO pInfo
|
||
)
|
||
{
|
||
|
||
//
|
||
// First, local EFS policy is always created on all products (wks, srv, DC)
|
||
//
|
||
|
||
DWORD rc;
|
||
LONG lResult;
|
||
HKEY hKey;
|
||
DWORD IsCreated=0;
|
||
|
||
//
|
||
// even if we were unregistered, without a reboot, we still get this event.
|
||
// use the EFS... key to see if we were deregistered, and if so, leave.
|
||
//
|
||
|
||
lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
EFS_NOTIFY_PATH,
|
||
0,
|
||
MAXIMUM_ALLOWED,
|
||
&hKey
|
||
);
|
||
|
||
if (lResult != ERROR_SUCCESS) {
|
||
return;
|
||
} else {
|
||
|
||
//
|
||
// query if a domain EFS policy was created before
|
||
//
|
||
DWORD RegType;
|
||
DWORD nSize=sizeof(DWORD);
|
||
|
||
RegQueryValueEx(
|
||
hKey,
|
||
L"EFSDomainGPOCreated",
|
||
0,
|
||
&RegType,
|
||
(LPBYTE)&IsCreated,
|
||
&nSize
|
||
);
|
||
|
||
RegCloseKey( hKey );
|
||
}
|
||
|
||
if (IsCreated != 0) {
|
||
|
||
//
|
||
// The DC recovery policy is already set
|
||
//
|
||
|
||
DllUnregisterServerEFS();
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
//
|
||
// check the current logon user. If not a member of administrators, quit
|
||
//
|
||
|
||
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
||
PSID AdminAccountSid;
|
||
BOOL bIsMemberOfAdmins = FALSE;
|
||
|
||
if ( NT_SUCCESS( RtlAllocateAndInitializeSid(
|
||
&NtAuthority,
|
||
2,
|
||
SECURITY_BUILTIN_DOMAIN_RID,
|
||
DOMAIN_ALIAS_RID_ADMINS,
|
||
0, 0, 0, 0, 0, 0,
|
||
&AdminAccountSid
|
||
) ) ) {
|
||
|
||
HANDLE NewToken;
|
||
|
||
if ( DuplicateToken( pInfo->hToken, SecurityImpersonation, &NewToken )) {
|
||
|
||
if ( FALSE == CheckTokenMembership(
|
||
NewToken,
|
||
AdminAccountSid,
|
||
&bIsMemberOfAdmins
|
||
) ) {
|
||
|
||
//
|
||
// error occured when checking membership, assume it is not a member
|
||
//
|
||
|
||
bIsMemberOfAdmins = FALSE;
|
||
|
||
}
|
||
|
||
CloseHandle(NewToken);
|
||
|
||
}
|
||
|
||
RtlFreeSid( AdminAccountSid);
|
||
|
||
}
|
||
|
||
if ( bIsMemberOfAdmins == FALSE ) {
|
||
//
|
||
// if it's not admin logon, or for some reason token membership can't
|
||
// be checked, quit ???
|
||
//
|
||
return;
|
||
}
|
||
|
||
//
|
||
// impersonate the token
|
||
//
|
||
|
||
if ( FALSE == ImpersonateLoggedOnUser(pInfo->hToken) ) {
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// initialize event log. If failed, will try later for each LogEvent call.
|
||
//
|
||
|
||
(void) InitializeEvents();
|
||
|
||
//
|
||
// check the machine role
|
||
//
|
||
|
||
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole;
|
||
|
||
rc = DsRoleGetPrimaryDomainInformation(
|
||
NULL,
|
||
DsRolePrimaryDomainInfoBasic,
|
||
(PBYTE *)&pDsRole
|
||
);
|
||
|
||
if (rc != ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Try again some other time? Deregister?
|
||
// This isn't supposed to happen.
|
||
//
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_DSROLE,
|
||
IDS_FAILED_GET_DSROLE,
|
||
GetLastError()
|
||
);
|
||
|
||
(void) ShutdownEvents();
|
||
|
||
RevertToSelf();
|
||
|
||
return;
|
||
}
|
||
|
||
DSROLE_MACHINE_ROLE MachineRole = pDsRole->MachineRole;
|
||
|
||
if (MachineRole != DsRole_RolePrimaryDomainController) {
|
||
|
||
//
|
||
// We don't create EFS recovery policy on non-PDC
|
||
//
|
||
|
||
(void) ShutdownEvents();
|
||
DsRoleFreeMemory( pDsRole );
|
||
RevertToSelf();
|
||
DllUnregisterServerEFS();
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// create the EFS local policy if not exist
|
||
//
|
||
|
||
CoInitialize(NULL);
|
||
|
||
HRESULT hr = ERROR_SUCCESS;
|
||
PUCHAR EfsBlob=NULL;
|
||
ULONG EfsSize=0;
|
||
PCCERT_CONTEXT pCertContext=NULL;
|
||
|
||
/*
|
||
//
|
||
// check/create EFS policy in the local machine object
|
||
//
|
||
|
||
hr = CreateLocalMachinePolicy(
|
||
pInfo,
|
||
( MachineRole == DsRole_RolePrimaryDomainController ) ? TRUE : FALSE,
|
||
&EfsBlob,
|
||
&EfsSize,
|
||
&pCertContext
|
||
);
|
||
|
||
if ( SUCCEEDED(hr) ) {
|
||
|
||
//
|
||
// local machine policy has been successfully created
|
||
// delete the SystemClone flag if it exists (or set it to 0 if it can't be deleted)
|
||
//
|
||
lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
EFS_NOTIFY_PATH,
|
||
0,
|
||
MAXIMUM_ALLOWED,
|
||
&hKey
|
||
);
|
||
|
||
if (lResult == ERROR_SUCCESS) {
|
||
|
||
lResult = RegDeleteValue (hKey, TEXT("SystemCloned") );
|
||
|
||
if ( lResult == ERROR_ACCESS_DENIED ) {
|
||
|
||
//
|
||
// can't delete it, now set it to 0
|
||
//
|
||
DWORD dwClone = 0;
|
||
|
||
RegSetValueEx( hKey,
|
||
TEXT("SystemCloned"),
|
||
0,
|
||
REG_DWORD,
|
||
(LPBYTE)&dwClone,
|
||
sizeof(DWORD)
|
||
);
|
||
|
||
}
|
||
|
||
RegCloseKey( hKey );
|
||
}
|
||
|
||
//
|
||
// detect the role of this computer and create the default EFS group
|
||
// policies for domain controllers
|
||
//
|
||
// this code is also executed for replicas because if the user logs on
|
||
// to replica first (before logging onto the PDC), we still want to
|
||
// have EFS recovery policy created.
|
||
//
|
||
// if the replica is a READ ONLY replica (BDC), this call will fail
|
||
//
|
||
|
||
if ( (MachineRole == DsRole_RolePrimaryDomainController) &&
|
||
( IsCreated == 0) ) {
|
||
|
||
//
|
||
// Create the default group policy object and add it to the gPLink list.
|
||
//
|
||
|
||
if ( EfsBlob == NULL ) {
|
||
EfsSize = 0;
|
||
|
||
if ( pCertContext ) {
|
||
//
|
||
// free it first
|
||
//
|
||
CertFreeCertificateContext( pCertContext );
|
||
pCertContext = NULL;
|
||
}
|
||
}
|
||
|
||
*/
|
||
//
|
||
// create both EFS default policy and domain account policy objects.
|
||
//
|
||
|
||
hr = CreateEFSDefaultPolicy(pInfo->hToken,
|
||
&EfsBlob,
|
||
&EfsSize,
|
||
&pCertContext,
|
||
pDsRole->DomainNameFlat);
|
||
|
||
if ( SUCCEEDED(hr) ) {
|
||
|
||
//
|
||
// update the registry value EFSDomainGPOCreated
|
||
//
|
||
lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
EFS_NOTIFY_PATH,
|
||
0,
|
||
MAXIMUM_ALLOWED,
|
||
&hKey
|
||
);
|
||
|
||
if (lResult == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// set the flag
|
||
//
|
||
|
||
IsCreated = 1;
|
||
RegSetValueEx( hKey,
|
||
L"EFSDomainGPOCreated",
|
||
0,
|
||
REG_DWORD,
|
||
(LPBYTE)&IsCreated,
|
||
sizeof(DWORD)
|
||
);
|
||
|
||
RegCloseKey( hKey );
|
||
}
|
||
|
||
}
|
||
/*
|
||
} else {
|
||
|
||
//
|
||
// the domain GPO is already created, or
|
||
//
|
||
// If it's workstation or server (either standalone or member), local policy
|
||
// (existing or just created) is enough.
|
||
//
|
||
|
||
//
|
||
// If it's a backup domain controller (replica), no need to create any
|
||
// default ( because either the one replicated from the primary domain
|
||
// or the one created by server setup will take effect );
|
||
//
|
||
|
||
// !!! do nothing !!!
|
||
|
||
}
|
||
*/
|
||
|
||
if ( SUCCEEDED(hr) ) {
|
||
|
||
DllUnregisterServerEFS();
|
||
|
||
HINSTANCE hUserEnvDll = LoadLibrary(TEXT("userenv.dll"));
|
||
PFREFRESHPOLICY pfRefreshPolicy=NULL;
|
||
|
||
if ( hUserEnvDll) {
|
||
pfRefreshPolicy = (PFREFRESHPOLICY)GetProcAddress(
|
||
hUserEnvDll,
|
||
"RefreshPolicy");
|
||
|
||
if ( pfRefreshPolicy ) {
|
||
//
|
||
// do not care errors
|
||
//
|
||
(void) (*pfRefreshPolicy)(TRUE);
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_WARNING,
|
||
GPOEVENT_WARNING_NOT_REFRESH,
|
||
IDS_ERROR_GET_PROC_ADDR,
|
||
GetLastError()
|
||
);
|
||
}
|
||
|
||
FreeLibrary(hUserEnvDll);
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_WARNING,
|
||
GPOEVENT_WARNING_NOT_REFRESH,
|
||
IDS_ERROR_LOAD_USERENV,
|
||
GetLastError()
|
||
);
|
||
}
|
||
}
|
||
// }
|
||
|
||
if (pDsRole) {
|
||
DsRoleFreeMemory( pDsRole );
|
||
}
|
||
(void) ShutdownEvents();
|
||
|
||
//
|
||
// uninitialize OLE
|
||
//
|
||
|
||
CoUninitialize();
|
||
|
||
RevertToSelf();
|
||
|
||
//
|
||
// clean up buffers
|
||
//
|
||
|
||
if ( EfsBlob ) {
|
||
free(EfsBlob);
|
||
}
|
||
|
||
if ( pCertContext ) {
|
||
CertFreeCertificateContext( pCertContext );
|
||
}
|
||
|
||
}
|
||
|
||
#if 0
|
||
|
||
HRESULT
|
||
CreateLocalMachinePolicy(
|
||
IN PWLX_NOTIFICATION_INFO pInfo,
|
||
IN BOOL bIsDC,
|
||
OUT PUCHAR *pEfsBlob,
|
||
OUT ULONG *pEfsSize,
|
||
OUT PCCERT_CONTEXT *ppCertContext
|
||
)
|
||
{
|
||
|
||
LPGROUPPOLICYOBJECT pGPO = NULL;
|
||
HRESULT hr;
|
||
HKEY hKeyPolicyRoot;
|
||
HKEY hKey;
|
||
DWORD rc=ERROR_SUCCESS;
|
||
|
||
//
|
||
// create Policy Object instance
|
||
//
|
||
|
||
hr = CoCreateInstance( CLSID_GroupPolicyObject,
|
||
NULL,
|
||
CLSCTX_SERVER,
|
||
IID_IGroupPolicyObject,
|
||
(PVOID *)&pGPO
|
||
);
|
||
|
||
if (SUCCEEDED(hr) && pGPO) {
|
||
|
||
//
|
||
// open LPO and load policy into registry
|
||
// if LPO does not exist, create it (under system context now)
|
||
//
|
||
|
||
hr = pGPO->OpenLocalMachineGPO( TRUE );
|
||
|
||
if (SUCCEEDED(hr)) {
|
||
|
||
//
|
||
// get the registry key for the root of machine policy object
|
||
//
|
||
|
||
hr = pGPO->GetRegistryKey( GPO_SECTION_MACHINE,
|
||
&hKeyPolicyRoot
|
||
);
|
||
|
||
if (SUCCEEDED(hr)) {
|
||
|
||
//
|
||
// open EFS recovery policy base key in the registry
|
||
//
|
||
|
||
BOOL fContinue = TRUE;
|
||
DWORD dwDisposition;
|
||
|
||
if ( (rc = RegCreateKeyEx(
|
||
hKeyPolicyRoot,
|
||
CERT_EFSBLOB_REGPATH,
|
||
0,
|
||
TEXT("REG_SZ"),
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_ALL_ACCESS,
|
||
NULL,
|
||
&hKey,
|
||
&dwDisposition
|
||
)) == ERROR_SUCCESS ) {
|
||
|
||
//
|
||
// check to see if there is EFS blob
|
||
// if not, create it.
|
||
//
|
||
|
||
DWORD RegType;
|
||
DWORD EfsSize;
|
||
PUCHAR pEfsOldBlob=NULL;
|
||
BOOL bIsExpired=FALSE;
|
||
|
||
rc = RegQueryValueEx(
|
||
hKey,
|
||
CERT_EFSBLOB_VALUE_NAME,
|
||
0,
|
||
&RegType,
|
||
NULL,
|
||
&EfsSize
|
||
);
|
||
|
||
if ( rc == ERROR_SUCCESS && EfsSize > 0 ) {
|
||
|
||
//
|
||
// query if this machine is cloned
|
||
//
|
||
HKEY hKeyClone;
|
||
|
||
rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
EFS_NOTIFY_PATH,
|
||
0,
|
||
MAXIMUM_ALLOWED,
|
||
&hKeyClone
|
||
);
|
||
|
||
if (rc == ERROR_SUCCESS) {
|
||
|
||
DWORD nSize=sizeof(DWORD);
|
||
DWORD dwClone=0;
|
||
|
||
RegQueryValueEx(
|
||
hKeyClone,
|
||
L"SystemCloned",
|
||
0,
|
||
&RegType,
|
||
(LPBYTE)&dwClone,
|
||
&nSize
|
||
);
|
||
|
||
RegCloseKey( hKeyClone );
|
||
|
||
if ( dwClone > 0 ) {
|
||
bIsExpired = TRUE;
|
||
}
|
||
}
|
||
|
||
if ( !bIsExpired ) {
|
||
|
||
//
|
||
// EFS recovery policy already exists
|
||
// query the blob and check if this policy needs to be
|
||
// upgraded (change expiration date)
|
||
//
|
||
pEfsOldBlob = (PUCHAR)LocalAlloc(LPTR, EfsSize+1);
|
||
|
||
if ( pEfsOldBlob ) {
|
||
|
||
rc = RegQueryValueEx(
|
||
hKey,
|
||
CERT_EFSBLOB_VALUE_NAME,
|
||
0,
|
||
&RegType,
|
||
pEfsOldBlob,
|
||
&EfsSize
|
||
);
|
||
|
||
if ( rc == ERROR_SUCCESS ) {
|
||
|
||
//
|
||
// check if the policy should be recreated.
|
||
//
|
||
bIsExpired = IsSelfSignedPolicyExpired((PRECOVERY_POLICY_1_1)pEfsOldBlob);
|
||
|
||
|
||
}
|
||
|
||
LocalFree(pEfsOldBlob);
|
||
pEfsOldBlob = NULL;
|
||
|
||
} else {
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( rc != ERROR_SUCCESS || EfsSize == 0 || bIsExpired ) {
|
||
|
||
//
|
||
// the EFSBlob registry value does not exis
|
||
// this means that local EFS policy should be created
|
||
//
|
||
|
||
*pEfsSize = 0;
|
||
|
||
rc = GetDefaultRecoveryPolicy(pInfo->hToken,
|
||
bIsDC,
|
||
pEfsBlob,
|
||
pEfsSize,
|
||
ppCertContext
|
||
);
|
||
|
||
if ( ERROR_SUCCESS == rc && *ppCertContext ) {
|
||
|
||
//
|
||
// add to the cert store of this GPO first
|
||
//
|
||
|
||
CERT_SYSTEM_STORE_RELOCATE_PARA paraRelocate;
|
||
paraRelocate.hKeyBase = hKeyPolicyRoot;
|
||
paraRelocate.pwszSystemStore = L"EFS";
|
||
|
||
HCERTSTORE hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
|
||
0,
|
||
NULL,
|
||
CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY |
|
||
CERT_SYSTEM_STORE_RELOCATE_FLAG,
|
||
(void *)¶Relocate
|
||
);
|
||
|
||
if ( hCertStore ) {
|
||
|
||
if ( bIsExpired ) {
|
||
//
|
||
// delete all old certs from the store first
|
||
//
|
||
|
||
PCCERT_CONTEXT pEnumCertContext = CertEnumCertificatesInStore(
|
||
hCertStore,
|
||
NULL
|
||
);
|
||
PCCERT_CONTEXT pCertContextDelete=NULL;
|
||
|
||
while ( pEnumCertContext ) {
|
||
|
||
//
|
||
// duplicate the cert context
|
||
//
|
||
pCertContextDelete = CertDuplicateCertificateContext( pEnumCertContext );
|
||
|
||
//
|
||
// enumerate the next certificate context
|
||
//
|
||
pEnumCertContext = CertEnumCertificatesInStore(
|
||
hCertStore,
|
||
pEnumCertContext
|
||
);
|
||
|
||
if ( pCertContextDelete ) {
|
||
|
||
//
|
||
// delete the cert from store
|
||
//
|
||
CertDeleteCertificateFromStore( pCertContextDelete );
|
||
|
||
//
|
||
// no need to free the cert context
|
||
// because it's freed by the previous call (even under error case)
|
||
//
|
||
pCertContextDelete = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if ( !CertAddCertificateContextToStore(
|
||
hCertStore,
|
||
*ppCertContext,
|
||
CERT_STORE_ADD_ALWAYS,
|
||
NULL
|
||
) ) {
|
||
|
||
rc = GetLastError();
|
||
}
|
||
|
||
//
|
||
// close the store
|
||
//
|
||
CertCloseStore(hCertStore, 0);
|
||
hCertStore = NULL;
|
||
|
||
} else {
|
||
rc = GetLastError();
|
||
}
|
||
|
||
if ( ERROR_SUCCESS == rc ) {
|
||
|
||
rc = RegSetValueEx(
|
||
hKey,
|
||
CERT_EFSBLOB_VALUE_NAME,
|
||
0,
|
||
REG_BINARY,
|
||
(PBYTE)(*pEfsBlob),
|
||
*pEfsSize
|
||
);
|
||
|
||
if (rc == ERROR_SUCCESS) {
|
||
|
||
hr = pGPO->Save(TRUE, TRUE, &guidExtension, &guidSnapin );
|
||
hr = pGPO->Save(TRUE, TRUE, &guidRegExt, &guidSnapin );
|
||
|
||
if ( FAILED(hr) ) {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_LPO,
|
||
IDS_ERROR_SAVE_LPO,
|
||
hr
|
||
);
|
||
} else {
|
||
/* comment out due to PM request
|
||
//
|
||
// popup a message to warn user
|
||
//
|
||
|
||
EFSRecPolicyPopup(
|
||
DsRole_RoleStandaloneWorkstation, // this value doesn't matter
|
||
NULL
|
||
);
|
||
*/
|
||
}
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_LPO,
|
||
IDS_ERROR_SAVE_EFSBLOB,
|
||
rc
|
||
);
|
||
}
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_LPO,
|
||
IDS_ERROR_ADD_CERTIFICATE,
|
||
rc
|
||
);
|
||
}
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_LPO,
|
||
IDS_ERROR_CREATE_EFSBLOB,
|
||
rc
|
||
);
|
||
}
|
||
}
|
||
|
||
//
|
||
// close the registry key
|
||
//
|
||
|
||
RegCloseKey(hKey);
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_LPO,
|
||
IDS_ERROR_OPEN_EFSKEY,
|
||
rc
|
||
);
|
||
}
|
||
|
||
if ( rc != ERROR_SUCCESS ) {
|
||
hr = HRESULT_FROM_WIN32(rc);
|
||
}
|
||
|
||
RegCloseKey(hKeyPolicyRoot);
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_LPO,
|
||
IDS_ERROR_GET_REGISTRY_KEY,
|
||
hr
|
||
);
|
||
}
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_LPO,
|
||
IDS_ERROR_OPEN_LPO,
|
||
hr
|
||
);
|
||
}
|
||
|
||
//
|
||
// release the policy object instance
|
||
//
|
||
|
||
pGPO->Release();
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_LPO,
|
||
IDS_ERROR_CREATE_GPO_INSTANCE,
|
||
hr
|
||
);
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
#endif
|
||
|
||
DWORD
|
||
GetDefaultRecoveryPolicy(
|
||
IN HANDLE hToken,
|
||
IN BOOL bIsDC,
|
||
OUT PUCHAR *pRecoveryPolicyBlob,
|
||
OUT ULONG *BlobSize,
|
||
OUT PCCERT_CONTEXT *ppCertContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates the default recovery policy for the current system.
|
||
It does this by auto-generating a recovery key based on the name of the
|
||
machine.
|
||
|
||
Arguments:
|
||
|
||
hToken - the token of current user
|
||
|
||
pRecoveryPolicyBlob - the output buffer to hold EFSBlob
|
||
|
||
BlobSize - the size of EFSBlob
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
DWORD rc = ERROR_SUCCESS;
|
||
PCCERT_CONTEXT pCertContext;
|
||
|
||
*pRecoveryPolicyBlob = NULL;
|
||
*BlobSize = 0;
|
||
*ppCertContext = NULL;
|
||
|
||
if (CreateSelfSignedRecoveryCertificate(
|
||
bIsDC,
|
||
&pCertContext
|
||
)) {
|
||
|
||
PEFS_PUBLIC_KEY_INFO PublicKeyInformation;
|
||
|
||
PBYTE pbCert = pCertContext->pbCertEncoded;
|
||
DWORD cbCert = pCertContext->cbCertEncoded;
|
||
|
||
PTOKEN_USER pTokenUser = GetTokenUser( hToken );
|
||
|
||
if (pTokenUser) {
|
||
|
||
rc = CreatePublicKeyInformationCertificate(
|
||
pTokenUser->User.Sid,
|
||
pbCert,
|
||
cbCert,
|
||
&PublicKeyInformation
|
||
);
|
||
|
||
if (rc == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Compute the total size of the RECOVERY_POLICY_1_1 structure, which
|
||
// is the size of the structure minus the size of the EFS_PUBLIC_KEY_INFO
|
||
// plus the size of the thing we just created above.
|
||
//
|
||
|
||
ULONG RecoveryKeySize = sizeof( RECOVERY_KEY_1_1 ) - sizeof( EFS_PUBLIC_KEY_INFO ) + PublicKeyInformation->Length;
|
||
|
||
ULONG PolicySize = sizeof( RECOVERY_POLICY_1_1 ) + RecoveryKeySize - sizeof( RECOVERY_KEY_1_1 );
|
||
|
||
//
|
||
// Allocate the policy block
|
||
//
|
||
|
||
PRECOVERY_POLICY_1_1 RecoveryPolicy = (PRECOVERY_POLICY_1_1)malloc( PolicySize );
|
||
|
||
if (RecoveryPolicy != NULL) {
|
||
|
||
RecoveryPolicy->RecoveryPolicyHeader.MajorRevision = EFS_RECOVERY_POLICY_MAJOR_REVISION_1;
|
||
RecoveryPolicy->RecoveryPolicyHeader.MinorRevision = EFS_RECOVERY_POLICY_MINOR_REVISION_1;
|
||
RecoveryPolicy->RecoveryPolicyHeader.RecoveryKeyCount = 1;
|
||
|
||
PRECOVERY_KEY_1_1 RecoveryKey = (PRECOVERY_KEY_1_1) &(RecoveryPolicy->RecoveryKeyList[0]);
|
||
|
||
memcpy( &RecoveryKey->PublicKeyInfo, PublicKeyInformation, PublicKeyInformation->Length );
|
||
RecoveryKey->TotalLength = sizeof( RECOVERY_KEY_1_1 ) + PublicKeyInformation->Length - sizeof( EFS_PUBLIC_KEY_INFO );
|
||
|
||
*pRecoveryPolicyBlob = (PUCHAR)RecoveryPolicy;
|
||
*BlobSize = PolicySize;
|
||
*ppCertContext = pCertContext;
|
||
|
||
//
|
||
// will free this outside this function
|
||
//
|
||
pCertContext = NULL;
|
||
|
||
} else {
|
||
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
free( PublicKeyInformation );
|
||
}
|
||
|
||
free( pTokenUser );
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
}
|
||
|
||
//
|
||
// free the certificate context if not outputted
|
||
//
|
||
if ( pCertContext ) {
|
||
CertFreeCertificateContext( pCertContext );
|
||
}
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
}
|
||
|
||
return( rc );
|
||
|
||
}
|
||
|
||
|
||
|
||
BOOLEAN
|
||
CreateSelfSignedRecoveryCertificate(
|
||
IN BOOL bIsDC,
|
||
OUT PCCERT_CONTEXT * pCertContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets up and creates a self-signed certificate.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
TRUE on success, FALSE on failure. Call GetLastError() for more details.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN fReturn = FALSE;
|
||
DWORD rc = ERROR_SUCCESS;
|
||
|
||
LPWSTR lpContainerName = NULL;
|
||
LPWSTR lpProviderName = NULL;
|
||
PBYTE pbHash = NULL;
|
||
LPWSTR lpDisplayInfo = NULL;
|
||
|
||
HCRYPTKEY hKey = NULL;
|
||
HCRYPTPROV hProv = NULL;
|
||
|
||
*pCertContext = NULL;
|
||
|
||
//
|
||
// Croft up a key pair
|
||
//
|
||
|
||
//
|
||
// Container name
|
||
//
|
||
|
||
GUID guidContainerName;
|
||
|
||
if ( ERROR_SUCCESS != UuidCreate(&guidContainerName) ) {
|
||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||
return(fReturn);
|
||
}
|
||
|
||
LPWSTR TmpContainerName;
|
||
|
||
if (ERROR_SUCCESS == UuidToStringW(&guidContainerName, (unsigned short **)&lpContainerName )) {
|
||
|
||
//
|
||
// Copy the container name into LSA heap memory
|
||
//
|
||
|
||
lpProviderName = MS_DEF_PROV;
|
||
|
||
//
|
||
// Create the key container
|
||
//
|
||
|
||
if (CryptAcquireContext(&hProv, lpContainerName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET )) {
|
||
|
||
if (CryptGenKey(hProv, AT_KEYEXCHANGE, RSA1024BIT_KEY | CRYPT_EXPORTABLE, &hKey)) {
|
||
|
||
DWORD NameLength = 64;
|
||
LPWSTR AgentName = NULL;
|
||
|
||
//
|
||
// Construct the subject name information
|
||
//
|
||
|
||
//lpDisplayInfo = MakeDNName();
|
||
|
||
AgentName = (LPWSTR)malloc(NameLength * sizeof(WCHAR));
|
||
if (AgentName){
|
||
if (!GetUserName(AgentName, &NameLength)){
|
||
free(AgentName);
|
||
AgentName = (LPWSTR)malloc(NameLength * sizeof(WCHAR));
|
||
|
||
//
|
||
// Try again with big buffer
|
||
//
|
||
|
||
if ( AgentName ){
|
||
|
||
if (!GetUserName(AgentName, &NameLength)){
|
||
rc = GetLastError();
|
||
free(AgentName);
|
||
AgentName = NULL;
|
||
}
|
||
|
||
} else {
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
}
|
||
} else {
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
if (AgentName) {
|
||
|
||
LPCWSTR DNNameTemplate = L"CN=%ws,L=EFS,OU=EFS File Encryption Certificate";
|
||
DWORD cbDNName = 0;
|
||
|
||
cbDNName = (wcslen( DNNameTemplate ) + 1) * sizeof( WCHAR ) + (wcslen( AgentName ) + 1) * sizeof( WCHAR );
|
||
lpDisplayInfo = (LPWSTR)malloc( cbDNName );
|
||
if (lpDisplayInfo) {
|
||
swprintf( lpDisplayInfo, DNNameTemplate, AgentName );
|
||
} else {
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
free(AgentName);
|
||
AgentName = NULL;
|
||
|
||
}
|
||
|
||
if (lpDisplayInfo) {
|
||
|
||
//
|
||
// Use this piece of code to create the PCERT_NAME_BLOB going into CertCreateSelfSignCertificate()
|
||
//
|
||
|
||
CERT_NAME_BLOB SubjectName;
|
||
|
||
SubjectName.cbData = 0;
|
||
|
||
if(CertStrToNameW(
|
||
CRYPT_ASN_ENCODING,
|
||
lpDisplayInfo,
|
||
0,
|
||
NULL,
|
||
NULL,
|
||
&SubjectName.cbData,
|
||
NULL)) {
|
||
|
||
SubjectName.pbData = (BYTE *) malloc(SubjectName.cbData);
|
||
|
||
if (SubjectName.pbData) {
|
||
|
||
if (CertStrToNameW(
|
||
CRYPT_ASN_ENCODING,
|
||
lpDisplayInfo,
|
||
0,
|
||
NULL,
|
||
SubjectName.pbData,
|
||
&SubjectName.cbData,
|
||
NULL) ) {
|
||
|
||
//
|
||
// Make the enhanced key usage
|
||
//
|
||
|
||
CERT_ENHKEY_USAGE certEnhKeyUsage;
|
||
LPSTR lpstr;
|
||
CERT_EXTENSION certExt;
|
||
|
||
lpstr = szOID_EFS_RECOVERY;
|
||
certEnhKeyUsage.cUsageIdentifier = 1;
|
||
certEnhKeyUsage.rgpszUsageIdentifier = &lpstr;
|
||
|
||
// now call CryptEncodeObject to encode the enhanced key usage into the extension struct
|
||
|
||
certExt.Value.cbData = 0;
|
||
certExt.Value.pbData = NULL;
|
||
certExt.fCritical = FALSE;
|
||
certExt.pszObjId = szOID_ENHANCED_KEY_USAGE;
|
||
|
||
//
|
||
// Encode it
|
||
//
|
||
|
||
if (EncodeAndAlloc(
|
||
CRYPT_ASN_ENCODING,
|
||
X509_ENHANCED_KEY_USAGE,
|
||
&certEnhKeyUsage,
|
||
&certExt.Value.pbData,
|
||
&certExt.Value.cbData
|
||
)) {
|
||
|
||
//
|
||
// finally, set up the array of extensions in the certInfo struct
|
||
// any further extensions need to be added to this array.
|
||
//
|
||
|
||
CERT_EXTENSIONS certExts;
|
||
|
||
certExts.cExtension = 1;
|
||
certExts.rgExtension = &certExt;
|
||
|
||
CRYPT_KEY_PROV_INFO KeyProvInfo;
|
||
|
||
memset( &KeyProvInfo, 0, sizeof( CRYPT_KEY_PROV_INFO ));
|
||
|
||
KeyProvInfo.pwszContainerName = lpContainerName;
|
||
KeyProvInfo.pwszProvName = lpProviderName;
|
||
KeyProvInfo.dwProvType = PROV_RSA_FULL;
|
||
KeyProvInfo.dwKeySpec = AT_KEYEXCHANGE;
|
||
|
||
SYSTEMTIME StartTime;
|
||
FILETIME FileTime;
|
||
LARGE_INTEGER TimeData;
|
||
SYSTEMTIME EndTime;
|
||
|
||
GetSystemTime(&StartTime);
|
||
SystemTimeToFileTime(&StartTime, &FileTime);
|
||
TimeData.LowPart = FileTime.dwLowDateTime;
|
||
TimeData.HighPart = (LONG) FileTime.dwHighDateTime;
|
||
|
||
if ( bIsDC ) {
|
||
TimeData.QuadPart += YEARCOUNT * 3;
|
||
} else {
|
||
TimeData.QuadPart += YEARCOUNT * 100;
|
||
|
||
}
|
||
FileTime.dwLowDateTime = TimeData.LowPart;
|
||
FileTime.dwHighDateTime = (DWORD) TimeData.HighPart;
|
||
|
||
FileTimeToSystemTime(&FileTime, &EndTime);
|
||
|
||
*pCertContext = CertCreateSelfSignCertificate(
|
||
hProv,
|
||
&SubjectName,
|
||
0,
|
||
&KeyProvInfo,
|
||
NULL,
|
||
&StartTime,
|
||
&EndTime,
|
||
&certExts
|
||
);
|
||
|
||
if (*pCertContext) {
|
||
|
||
HCERTSTORE hStore;
|
||
|
||
hStore = CertOpenSystemStoreW( NULL, L"MY" );
|
||
|
||
if (hStore) {
|
||
|
||
//
|
||
// save the temp cert
|
||
//
|
||
|
||
if(CertAddCertificateContextToStore(
|
||
hStore,
|
||
*pCertContext,
|
||
CERT_STORE_ADD_NEW,
|
||
NULL) ) {
|
||
|
||
fReturn = TRUE;
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
}
|
||
|
||
CertCloseStore( hStore, 0 );
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
}
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
}
|
||
|
||
free( certExt.Value.pbData );
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
}
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
}
|
||
|
||
free( SubjectName.pbData );
|
||
|
||
} else {
|
||
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
}
|
||
|
||
free( lpDisplayInfo );
|
||
|
||
} else {
|
||
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
CryptDestroyKey( hKey );
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
}
|
||
|
||
CryptReleaseContext( hProv, 0 );
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
}
|
||
|
||
RpcStringFree( (unsigned short **)&lpContainerName );
|
||
|
||
} else {
|
||
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
SetLastError( rc );
|
||
|
||
if (!fReturn) {
|
||
|
||
if (*pCertContext) {
|
||
CertFreeCertificateContext( *pCertContext );
|
||
*pCertContext = NULL;
|
||
}
|
||
}
|
||
|
||
return( fReturn );
|
||
}
|
||
|
||
BOOL
|
||
EncodeAndAlloc(
|
||
DWORD dwEncodingType,
|
||
LPCSTR lpszStructType,
|
||
const void * pvStructInfo,
|
||
PBYTE * pbEncoded,
|
||
PDWORD pcbEncoded
|
||
)
|
||
{
|
||
BOOL b = FALSE;
|
||
|
||
if (CryptEncodeObject(
|
||
dwEncodingType,
|
||
lpszStructType,
|
||
pvStructInfo,
|
||
NULL,
|
||
pcbEncoded )) {
|
||
|
||
*pbEncoded = (PBYTE)malloc( *pcbEncoded );
|
||
|
||
if (*pbEncoded) {
|
||
|
||
if (CryptEncodeObject(
|
||
dwEncodingType,
|
||
lpszStructType,
|
||
pvStructInfo,
|
||
*pbEncoded,
|
||
pcbEncoded )) {
|
||
|
||
b = TRUE;
|
||
|
||
} else {
|
||
|
||
free( *pbEncoded );
|
||
*pbEncoded = NULL;
|
||
}
|
||
|
||
} else {
|
||
|
||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
}
|
||
|
||
return( b );
|
||
}
|
||
|
||
|
||
LPWSTR
|
||
MakeDNName(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Fabricates a display name for a locally built self-signed cert
|
||
|
||
Arguments:
|
||
|
||
RecoveryKey - Specifies if this is a recovery key or not.
|
||
|
||
Return Value:
|
||
|
||
Returns a string containing a display name, or NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
LPWSTR DNName = NULL;
|
||
LPCWSTR DNNameTemplate = L"CN=%ws,L=EFS,OU=EFS File Encryption Certificate";
|
||
DWORD cbDNName = 0;
|
||
|
||
DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1;
|
||
|
||
WCHAR lpComputerName[(MAX_COMPUTERNAME_LENGTH + 1) * sizeof( WCHAR )];
|
||
|
||
BOOL b = GetComputerName ( lpComputerName, &nSize );
|
||
|
||
if (b) {
|
||
|
||
cbDNName = (wcslen( DNNameTemplate ) + 1) * sizeof( WCHAR ) + (wcslen( lpComputerName ) + 1) * sizeof( WCHAR );
|
||
|
||
DNName = (LPWSTR)malloc( cbDNName );
|
||
|
||
if (DNName) {
|
||
|
||
swprintf( DNName, DNNameTemplate, lpComputerName );
|
||
|
||
} else {
|
||
|
||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
}
|
||
|
||
return( DNName );
|
||
}
|
||
|
||
DWORD
|
||
CreatePublicKeyInformationCertificate(
|
||
IN PSID pUserSid OPTIONAL,
|
||
PBYTE pbCert,
|
||
DWORD cbCert,
|
||
OUT PEFS_PUBLIC_KEY_INFO * PublicKeyInformation
|
||
)
|
||
{
|
||
DWORD PublicKeyInformationLength = 0;
|
||
DWORD UserSidLength = 0;
|
||
PWCHAR Base;
|
||
|
||
if (pUserSid != NULL) {
|
||
UserSidLength = GetLengthSid( pUserSid );
|
||
}
|
||
|
||
//
|
||
// Total size is the size of the public key info structure, the size of the
|
||
// cert hash data structure, the length of the thumbprint, and the lengths of the
|
||
// container name and provider name if they were passed.
|
||
//
|
||
|
||
PublicKeyInformationLength = sizeof( EFS_PUBLIC_KEY_INFO ) + UserSidLength + cbCert;
|
||
|
||
//
|
||
// Allocate and fill in the PublicKeyInformation structure
|
||
//
|
||
|
||
*PublicKeyInformation = (PEFS_PUBLIC_KEY_INFO)malloc( PublicKeyInformationLength );
|
||
|
||
if (*PublicKeyInformation == NULL) {
|
||
return( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
|
||
(*PublicKeyInformation)->Length = PublicKeyInformationLength;
|
||
(*PublicKeyInformation)->KeySourceTag = (ULONG)EfsCertificate;
|
||
|
||
//
|
||
// Copy the string and SID data to the end of the structure.
|
||
//
|
||
|
||
Base = (PWCHAR)(*PublicKeyInformation);
|
||
Base = (PWCHAR)((PBYTE)Base + sizeof( EFS_PUBLIC_KEY_INFO ));
|
||
|
||
if (pUserSid != NULL) {
|
||
|
||
(*PublicKeyInformation)->PossibleKeyOwner = (ULONG)POINTER_TO_OFFSET( Base, *PublicKeyInformation );
|
||
CopySid( UserSidLength, (PSID)Base, pUserSid );
|
||
|
||
} else {
|
||
|
||
(*PublicKeyInformation)->PossibleKeyOwner = (ULONG)0;
|
||
}
|
||
|
||
Base = (PWCHAR)((PBYTE)Base + UserSidLength);
|
||
|
||
(*PublicKeyInformation)->CertificateInfo.CertificateLength = cbCert;
|
||
(*PublicKeyInformation)->CertificateInfo.Certificate = (ULONG)POINTER_TO_OFFSET( Base, *PublicKeyInformation );
|
||
|
||
memcpy( (PBYTE)Base, pbCert, cbCert );
|
||
|
||
return( ERROR_SUCCESS );
|
||
|
||
}
|
||
|
||
#if 0
|
||
|
||
BOOLEAN
|
||
Admin(
|
||
IN LSA_HANDLE LsaPolicyHandle,
|
||
IN HANDLE hToken,
|
||
OUT PSID * Sid
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine determines if the passed token belongs to an administrator.
|
||
|
||
If we are in a domain, the user must be a domain admin for this to succeed.
|
||
|
||
If we are standalne, the user must be in the local administrator's group.
|
||
|
||
Arguments:
|
||
|
||
hToken - Supplies the token of the user to be examined.
|
||
|
||
bDomain - Returns TRUE if the caller is a domain administrator.
|
||
|
||
Sid - Returns the Sid of the user.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the user is an administrator of the type we need, FALSE otherwise.
|
||
|
||
Note that this routine does not attempt to set last error, it either works
|
||
or it doesn't.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS NetStatus;
|
||
PSID DomainId;
|
||
NTSTATUS Status;
|
||
BOOLEAN fReturn = FALSE;
|
||
|
||
DWORD ReturnLength;
|
||
|
||
PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo;
|
||
|
||
//
|
||
// Initialize OUT parameters
|
||
//
|
||
|
||
*Sid = NULL;
|
||
|
||
Status = NtQueryInformationToken (
|
||
hToken,
|
||
TokenGroups,
|
||
NULL,
|
||
0,
|
||
&ReturnLength
|
||
);
|
||
|
||
if (STATUS_BUFFER_TOO_SMALL == Status) {
|
||
|
||
PTOKEN_GROUPS Groups = (PTOKEN_GROUPS)malloc( ReturnLength );
|
||
|
||
if (Groups) {
|
||
|
||
Status = NtQueryInformationToken (
|
||
hToken,
|
||
TokenGroups,
|
||
Groups,
|
||
ReturnLength,
|
||
&ReturnLength
|
||
);
|
||
|
||
if (NT_SUCCESS( Status )) {
|
||
|
||
//
|
||
// We've got the groups, build the SIDs and see if
|
||
// they're in the token.
|
||
//
|
||
|
||
//
|
||
// We're standalone
|
||
//
|
||
|
||
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
||
|
||
PSID AdminAccountSid;
|
||
|
||
Status = RtlAllocateAndInitializeSid(
|
||
&NtAuthority,
|
||
2,
|
||
SECURITY_BUILTIN_DOMAIN_RID,
|
||
DOMAIN_ALIAS_RID_ADMINS,
|
||
0, 0, 0, 0, 0, 0,
|
||
&AdminAccountSid
|
||
);
|
||
|
||
if (NT_SUCCESS( Status )) {
|
||
|
||
DWORD i;
|
||
|
||
for (i=0; i<Groups->GroupCount; i++) {
|
||
|
||
if (RtlEqualSid(Groups->Groups[i].Sid, AdminAccountSid)) {
|
||
*Sid = AdminAccountSid;
|
||
fReturn = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
free( Groups );
|
||
}
|
||
|
||
if (!fReturn) {
|
||
|
||
//
|
||
// Something failed, clean up any allocated OUT parameters
|
||
//
|
||
|
||
if (*Sid) {
|
||
|
||
if (*bDomain == FALSE) {
|
||
FreeSid( *Sid );
|
||
} else {
|
||
free( *Sid );
|
||
}
|
||
|
||
*Sid = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
return( fReturn );
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
PTOKEN_USER
|
||
GetTokenUser(
|
||
HANDLE TokenHandle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the TOKEN_USER structure for the
|
||
current user, and optionally, the AuthenticationId from his
|
||
token.
|
||
|
||
Arguments:
|
||
|
||
AuthenticationId - Supplies an optional pointer to return the
|
||
AuthenticationId.
|
||
|
||
Return Value:
|
||
|
||
On success, returns a pointer to a TOKEN_USER structure.
|
||
|
||
On failure, returns NULL. Call GetLastError() for more
|
||
detailed error information.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG ReturnLength;
|
||
TOKEN_STATISTICS TokenStats;
|
||
PTOKEN_USER pTokenUser = NULL;
|
||
BOOLEAN b = FALSE;
|
||
|
||
Status = NtQueryInformationToken (
|
||
TokenHandle,
|
||
TokenUser,
|
||
NULL,
|
||
0,
|
||
&ReturnLength
|
||
);
|
||
|
||
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
||
|
||
pTokenUser = (PTOKEN_USER)malloc( ReturnLength );
|
||
|
||
if (pTokenUser) {
|
||
|
||
Status = NtQueryInformationToken (
|
||
TokenHandle,
|
||
TokenUser,
|
||
pTokenUser,
|
||
ReturnLength,
|
||
&ReturnLength
|
||
);
|
||
|
||
if ( NT_SUCCESS( Status )) {
|
||
|
||
//
|
||
// We're done, mark that everything worked
|
||
//
|
||
|
||
b = TRUE;
|
||
|
||
} else {
|
||
|
||
SetLastError( RtlNtStatusToDosError( Status ));
|
||
}
|
||
|
||
if (!b) {
|
||
|
||
//
|
||
// Something failed, clean up what we were going to return
|
||
//
|
||
|
||
free( pTokenUser );
|
||
pTokenUser = NULL;
|
||
}
|
||
|
||
} else {
|
||
|
||
SetLastError( RtlNtStatusToDosError( STATUS_INSUFFICIENT_RESOURCES ));
|
||
}
|
||
|
||
} else {
|
||
|
||
SetLastError( RtlNtStatusToDosError( Status ));
|
||
}
|
||
|
||
return( pTokenUser );
|
||
}
|
||
|
||
VOID
|
||
InitializeOtherPolicies(LPGROUPPOLICYOBJECT pGPO, HKEY hKeyRoot)
|
||
{
|
||
TCHAR szPath[2*MAX_PATH];
|
||
GUID guidRIClient = {0x3060e8d0, 0x7020, 0x11d2, 0x84, 0x2d, 0x0, 0xc0, 0x4f, 0xa3, 0x72, 0xd4};
|
||
GUID guidRISnap = {0x3060e8ce, 0x7020, 0x11d2, 0x84, 0x2d, 0x0, 0xc0, 0x4f, 0xa3, 0x72, 0xd4};
|
||
|
||
|
||
//
|
||
// Initialize Remote Install settings
|
||
//
|
||
|
||
if (SUCCEEDED(pGPO->GetFileSysPath (GPO_SECTION_USER, szPath, 2*MAX_PATH)))
|
||
{
|
||
lstrcat (szPath, TEXT("\\Microsoft"));
|
||
if (!CreateDirectory(szPath, NULL)) {
|
||
return;
|
||
}
|
||
|
||
lstrcat (szPath, TEXT("\\RemoteInstall"));
|
||
if (!CreateDirectory(szPath, NULL)) {
|
||
return;
|
||
}
|
||
|
||
lstrcat (szPath, TEXT("\\oscfilter.ini"));
|
||
|
||
WritePrivateProfileString(TEXT("choice"), TEXT("custom"), TEXT("0"), szPath);
|
||
WritePrivateProfileString(TEXT("choice"), TEXT("tools"), TEXT("0"), szPath);
|
||
WritePrivateProfileString(TEXT("choice"), TEXT("restart"), TEXT("0"), szPath);
|
||
|
||
pGPO->Save(FALSE, TRUE, &guidRIClient, &guidRISnap);
|
||
}
|
||
}
|
||
|
||
|
||
HRESULT
|
||
CreateEFSDefaultPolicy(
|
||
IN HANDLE hToken,
|
||
IN PUCHAR *pEfsBlob,
|
||
IN DWORD *pEfsSize,
|
||
IN PCCERT_CONTEXT *ppCertContext,
|
||
IN LPTSTR DomainName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates the default domain-wide EFS recovery policy object.
|
||
|
||
Arguments:
|
||
|
||
hToken - the current logged on user's token
|
||
|
||
EfsBlob - EFS recovery policy blob
|
||
|
||
EfsSize - the size of the blob ( in bytes)
|
||
|
||
Return:
|
||
|
||
HRESULT
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// bind to DS to find the domain DNS name
|
||
//
|
||
|
||
DWORD rc;
|
||
PLDAP phLdap=NULL;
|
||
PWSTR DsRootName=NULL;
|
||
|
||
|
||
rc = MyLdapOpen(&phLdap);
|
||
|
||
if ( ERROR_SUCCESS == rc ) {
|
||
|
||
rc = MyGetDsObjectRoot(
|
||
phLdap,
|
||
&DsRootName
|
||
);
|
||
|
||
if ( ERROR_SUCCESS != rc ) {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_GET_DSROOT,
|
||
rc
|
||
);
|
||
}
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_BIND_DS,
|
||
rc
|
||
);
|
||
}
|
||
|
||
HRESULT hr = HRESULT_FROM_WIN32(rc);
|
||
|
||
// if ( SUCCEEDED(hr) && DsRootName ) {
|
||
|
||
/* Get the default recovery policy only when there is no existing one
|
||
|
||
if ( *pEfsBlob == NULL ) {
|
||
|
||
rc = GetDefaultRecoveryPolicy(hToken,
|
||
TRUE,
|
||
pEfsBlob,
|
||
pEfsSize,
|
||
ppCertContext);
|
||
|
||
if ( ERROR_SUCCESS != rc ) {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_CREATE_EFSBLOB,
|
||
rc
|
||
);
|
||
}
|
||
|
||
hr = HRESULT_FROM_WIN32(rc);
|
||
}
|
||
*/
|
||
// }
|
||
|
||
if ( SUCCEEDED(hr) && DsRootName) {
|
||
|
||
LPGROUPPOLICYOBJECT pEfsGPO = NULL;
|
||
|
||
//
|
||
// OLE is already initialized before this call
|
||
// create Policy Object instances
|
||
//
|
||
|
||
TCHAR szPolicyName[MAX_PATH];
|
||
|
||
pLoadResourceString(IDS_DEFAULT_EFS_POLICY,
|
||
szPolicyName,
|
||
MAX_PATH,
|
||
L"Domain EFS Recovery Policy"
|
||
);
|
||
|
||
hr = CreateGroupPolicyObjectInDomain(hToken,
|
||
DsRootName,
|
||
szPolicyName,
|
||
*pEfsBlob,
|
||
*pEfsSize,
|
||
*ppCertContext,
|
||
&pEfsGPO);
|
||
|
||
if ( FAILED(hr) ) {
|
||
|
||
//
|
||
// if any of the creation failed, delet both objects
|
||
//
|
||
|
||
if ( pEfsGPO ) {
|
||
pEfsGPO->Delete();
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// release the instances
|
||
//
|
||
|
||
if ( pEfsGPO ) {
|
||
pEfsGPO->Release();
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// close LDAP port
|
||
//
|
||
if ( phLdap ) {
|
||
MyLdapClose(&phLdap);
|
||
}
|
||
if ( DsRootName ) {
|
||
LocalFree(DsRootName);
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
|
||
HRESULT
|
||
CreateGroupPolicyObjectInDomain(
|
||
IN HANDLE hToken,
|
||
IN PWSTR DomainNCName,
|
||
IN PWSTR GPObjectName,
|
||
IN PUCHAR EfsBlob,
|
||
IN ULONG EfsSize,
|
||
IN PCCERT_CONTEXT pCertContext,
|
||
OUT LPGROUPPOLICYOBJECT *ppObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates a group policy object in DS (and sysvol).
|
||
|
||
Arguments:
|
||
|
||
DomainNCName - The DS domain's ADSI name
|
||
|
||
GPObjectName - the display name for the group policy object to create
|
||
|
||
EfsBlob - The EFS recovery policy blob (ignored if to create default
|
||
domain policy)
|
||
|
||
EfsSize - the size of EfsBlob (in bytes)
|
||
|
||
ppObject - the created group policy object instance. This will be
|
||
released by the caller.
|
||
|
||
Return:
|
||
|
||
HRESULT
|
||
|
||
--*/
|
||
{
|
||
|
||
LPGROUPPOLICYOBJECT pGPO;
|
||
|
||
HRESULT hr = CoCreateInstance( CLSID_GroupPolicyObject,
|
||
NULL,
|
||
CLSCTX_SERVER,
|
||
IID_IGroupPolicyObject,
|
||
(PVOID *)&pGPO
|
||
);
|
||
|
||
if (SUCCEEDED(hr) && pGPO) {
|
||
|
||
LPWSTR lpPath;
|
||
|
||
//
|
||
// Build the path to the default GPO
|
||
//
|
||
|
||
lpPath = (LPWSTR) LocalAlloc (LPTR, (lstrlen(DomainNCName) + 100) * sizeof(WCHAR));
|
||
|
||
if (lpPath) {
|
||
|
||
lstrcpy (lpPath, TEXT("LDAP://CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,"));
|
||
lstrcat (lpPath, (DomainNCName+7));
|
||
|
||
|
||
//
|
||
// Open the default GPO
|
||
//
|
||
|
||
hr = pGPO->OpenDSGPO(lpPath, GPO_OPEN_LOAD_REGISTRY);
|
||
|
||
LocalFree (lpPath);
|
||
|
||
if ( SUCCEEDED(hr) ) {
|
||
|
||
//
|
||
// save EFS blob into the object
|
||
//
|
||
|
||
HKEY hKeyPolicyRoot;
|
||
|
||
hr = pGPO->GetRegistryKey( GPO_SECTION_MACHINE,
|
||
&hKeyPolicyRoot
|
||
);
|
||
|
||
if (SUCCEEDED(hr)) {
|
||
|
||
//
|
||
// create EFS recovery policy in the registry
|
||
// open reg key CERT_EFSBLOB_REGPATH defined in wincrypt.h
|
||
//
|
||
|
||
DWORD dwDisposition;
|
||
HKEY hKey;
|
||
DWORD Win32rc;
|
||
|
||
if ( (Win32rc = RegCreateKeyEx(
|
||
hKeyPolicyRoot,
|
||
CERT_EFSBLOB_REGPATH,
|
||
0,
|
||
TEXT("REG_SZ"),
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_ALL_ACCESS,
|
||
NULL,
|
||
&hKey,
|
||
&dwDisposition
|
||
) ) == ERROR_SUCCESS ) {
|
||
|
||
|
||
//
|
||
// check to see if there is EFS blob
|
||
// if not, create it.
|
||
//
|
||
|
||
DWORD RegType;
|
||
DWORD BlobSize;
|
||
PUCHAR pNewBlob=NULL;
|
||
PCCERT_CONTEXT pNewCert=NULL;
|
||
|
||
Win32rc = RegQueryValueEx(
|
||
hKey,
|
||
CERT_EFSBLOB_VALUE_NAME,
|
||
0,
|
||
&RegType,
|
||
NULL,
|
||
&BlobSize
|
||
);
|
||
|
||
|
||
if ( Win32rc != ERROR_SUCCESS || BlobSize == 0 ) {
|
||
|
||
if ( EfsBlob == NULL ) {
|
||
|
||
Win32rc = GetDefaultRecoveryPolicy(hToken,
|
||
TRUE,
|
||
&pNewBlob,
|
||
&BlobSize,
|
||
&pNewCert);
|
||
|
||
if ( ERROR_SUCCESS != Win32rc ) {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_CREATE_EFSBLOB,
|
||
Win32rc
|
||
);
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// EFS blob is already created, just use it
|
||
//
|
||
pNewBlob = EfsBlob;
|
||
BlobSize = EfsSize;
|
||
pNewCert = pCertContext;
|
||
|
||
Win32rc = ERROR_SUCCESS;
|
||
}
|
||
|
||
if ( ERROR_SUCCESS == Win32rc ) {
|
||
|
||
//
|
||
// add to the cert store of this GPO first
|
||
//
|
||
|
||
CERT_SYSTEM_STORE_RELOCATE_PARA paraRelocate;
|
||
|
||
paraRelocate.hKeyBase = hKeyPolicyRoot;
|
||
paraRelocate.pwszSystemStore = L"EFS";
|
||
|
||
HCERTSTORE hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
|
||
0,
|
||
NULL,
|
||
CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY |
|
||
CERT_SYSTEM_STORE_RELOCATE_FLAG,
|
||
(void *)¶Relocate
|
||
);
|
||
|
||
if ( hCertStore ) {
|
||
|
||
if ( !CertAddCertificateContextToStore(
|
||
hCertStore,
|
||
pNewCert, // pCertContext,
|
||
CERT_STORE_ADD_ALWAYS,
|
||
NULL
|
||
) ) {
|
||
|
||
Win32rc = GetLastError();
|
||
}
|
||
|
||
//
|
||
// close the store
|
||
//
|
||
CertCloseStore(hCertStore, 0);
|
||
hCertStore = NULL;
|
||
|
||
} else {
|
||
|
||
Win32rc = GetLastError();
|
||
}
|
||
|
||
if ( ERROR_SUCCESS == Win32rc ) {
|
||
//
|
||
// set EFS recovery policy binary data to registry
|
||
// open reg key CERT_EFSBLOB_REGPATH defined in wincrypt.h
|
||
//
|
||
|
||
Win32rc = RegSetValueEx(
|
||
hKey,
|
||
CERT_EFSBLOB_VALUE_NAME,
|
||
0,
|
||
REG_BINARY,
|
||
(PBYTE)pNewBlob, // EfsBlob
|
||
BlobSize // EfsSize
|
||
);
|
||
|
||
if (Win32rc == ERROR_SUCCESS) {
|
||
|
||
hr = pGPO->Save(TRUE, TRUE, &guidExtension, &guidSnapin);
|
||
hr = pGPO->Save(TRUE, TRUE, &guidRegExt, &guidSnapin );
|
||
|
||
if ( FAILED(hr) ) {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_SAVE_GPO,
|
||
hr,
|
||
GPObjectName
|
||
);
|
||
}
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_SAVE_EFSBLOB,
|
||
Win32rc
|
||
);
|
||
}
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_ADD_CERTIFICATE,
|
||
Win32rc
|
||
);
|
||
}
|
||
|
||
//
|
||
// free allocated blob and certificate
|
||
//
|
||
if ( pNewBlob != EfsBlob ) {
|
||
|
||
if ( pNewBlob ) {
|
||
free(pNewBlob);
|
||
}
|
||
|
||
if ( pNewCert ) {
|
||
CertFreeCertificateContext( pNewCert );
|
||
}
|
||
}
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_CREATE_EFSBLOB,
|
||
Win32rc
|
||
);
|
||
}
|
||
}
|
||
|
||
//
|
||
// close the registry key
|
||
//
|
||
|
||
RegCloseKey(hKey);
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_OPEN_EFSKEY,
|
||
Win32rc
|
||
);
|
||
}
|
||
|
||
if ( Win32rc != ERROR_SUCCESS ) {
|
||
|
||
hr = HRESULT_FROM_WIN32(Win32rc);
|
||
|
||
}
|
||
|
||
InitializeOtherPolicies(pGPO, hKeyPolicyRoot);
|
||
|
||
RegCloseKey(hKeyPolicyRoot);
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_GETGPO_REGKEY,
|
||
hr,
|
||
GPObjectName
|
||
);
|
||
}
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_NEW_GPO,
|
||
hr,
|
||
GPObjectName,
|
||
DomainNCName
|
||
);
|
||
}
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
LogEvent(STATUS_SEVERITY_ERROR,
|
||
GPOEVENT_ERROR_CREATE_GPO,
|
||
IDS_ERROR_CREATE_GPO_INSTANCE,
|
||
hr
|
||
);
|
||
}
|
||
|
||
if ( SUCCEEDED(hr) ) {
|
||
|
||
*ppObject = pGPO;
|
||
|
||
} else if ( pGPO ) {
|
||
|
||
//
|
||
// failed, release the instance
|
||
//
|
||
|
||
pGPO->Release();
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
DWORD
|
||
MyGetDsObjectRoot(
|
||
IN PLDAP pLdap,
|
||
OUT PWSTR *pDsRootName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get the root domain name of the current domain. The returned domain's
|
||
name is in ADSI format, for example,
|
||
LDAP://DC=test_dom,DC=ntdev,DC=microsoft,DC=com
|
||
|
||
Arguments:
|
||
|
||
pLdap - the ldap handle
|
||
|
||
pDsRootName - the domain's ADSI name to output
|
||
|
||
Return:
|
||
|
||
Win32 error
|
||
|
||
--*/
|
||
{
|
||
DWORD retErr;
|
||
LDAPMessage *Message = NULL; // for LDAP calls.
|
||
PWSTR Attribs[2]; // for LDAP calls.
|
||
|
||
if ( pLdap == NULL || pDsRootName == NULL ) {
|
||
return(ERROR_INVALID_PARAMETER);
|
||
}
|
||
|
||
Attribs[0] = L"defaultNamingContext";
|
||
Attribs[1] = NULL;
|
||
|
||
|
||
retErr = ldap_search_s(pLdap,
|
||
L"",
|
||
LDAP_SCOPE_BASE,
|
||
L"(objectClass=*)",
|
||
Attribs,
|
||
0,
|
||
&Message);
|
||
|
||
if( Message ) { // should not check for error code
|
||
|
||
retErr = ERROR_SUCCESS;
|
||
|
||
LDAPMessage *Entry = NULL;
|
||
//
|
||
// read the first entry.
|
||
// we did base level search, we have only one entry.
|
||
// Entry does not need to be freed (it is freed with the message)
|
||
//
|
||
Entry = ldap_first_entry(pLdap, Message);
|
||
if(Entry != NULL) {
|
||
|
||
PWSTR *Values = ldap_get_values(pLdap, Entry, Attribs[0]);
|
||
|
||
if(Values != NULL) {
|
||
//
|
||
// should only get one value for the default naming context
|
||
// Values[0] here is the DN.
|
||
//
|
||
*pDsRootName = (PWSTR)LocalAlloc(0, (wcslen(Values[0])+1+7)*sizeof(WCHAR));
|
||
|
||
if ( *pDsRootName ) {
|
||
swprintf(*pDsRootName, L"LDAP://%s\0", Values[0]);
|
||
} else {
|
||
retErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
ldap_value_free(Values);
|
||
|
||
} else
|
||
retErr = LdapMapErrorToWin32(pLdap->ld_errno);
|
||
|
||
} else
|
||
retErr = LdapMapErrorToWin32(pLdap->ld_errno);
|
||
|
||
ldap_msgfree(Message);
|
||
Message = NULL;
|
||
}
|
||
|
||
return(retErr);
|
||
|
||
}
|
||
|
||
DWORD
|
||
MyLdapOpen(
|
||
OUT PLDAP *pLdap
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Open a LDAP port and bind to it.
|
||
|
||
Arguments:
|
||
|
||
pLdap - the ldap handle to output
|
||
|
||
Return:
|
||
|
||
Win32 error
|
||
|
||
--*/
|
||
{
|
||
|
||
DWORD Win32rc;
|
||
WCHAR sysName[256];
|
||
DWORD dSize = (sizeof(sysName) / sizeof(sysName[0]));
|
||
|
||
if ( pLdap == NULL ) {
|
||
return(ERROR_INVALID_PARAMETER);
|
||
}
|
||
//
|
||
// get current computer and IP address
|
||
//
|
||
if ( !GetComputerName(sysName, &dSize) ) {
|
||
Win32rc = GetLastError();
|
||
|
||
} else {
|
||
|
||
PDOMAIN_CONTROLLER_INFOW DCInfo; // for DsGetDcName
|
||
|
||
HINSTANCE hDsGetDcDll = LoadLibrary(TEXT("netapi32.dll"));
|
||
PFNDSGETDCNAME pfnDsGetDcName=NULL;
|
||
|
||
|
||
if ( hDsGetDcDll) {
|
||
#if defined(UNICODE)
|
||
pfnDsGetDcName = (PFNDSGETDCNAME)GetProcAddress(hDsGetDcDll,
|
||
"DsGetDcNameW");
|
||
#else
|
||
pfnDsGetDcName = (PFNDSGETDCNAME)GetProcAddress(hDsGetDcDll,
|
||
"DsGetDcNameA");
|
||
#endif
|
||
}
|
||
|
||
if ( pfnDsGetDcName ) {
|
||
Win32rc = (*pfnDsGetDcName)(sysName,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
DS_IP_REQUIRED,
|
||
&DCInfo
|
||
);
|
||
} else {
|
||
Win32rc = ERROR_PROC_NOT_FOUND;
|
||
}
|
||
|
||
if ( hDsGetDcDll ) {
|
||
FreeLibrary(hDsGetDcDll);
|
||
}
|
||
|
||
if(Win32rc == ERROR_SUCCESS) {
|
||
|
||
PWSTR pwszAddress = DCInfo[0].DomainControllerAddress;
|
||
if(*pwszAddress == L'\\') {
|
||
pwszAddress += 2;
|
||
}
|
||
//
|
||
// bind to ldap
|
||
//
|
||
*pLdap = ldap_open(pwszAddress, LDAP_PORT);
|
||
|
||
if ( *pLdap == NULL ) {
|
||
|
||
Win32rc = ERROR_FILE_NOT_FOUND;
|
||
|
||
} else {
|
||
Win32rc = ldap_bind_s(*pLdap,
|
||
NULL,
|
||
NULL,
|
||
LDAP_AUTH_SSPI);
|
||
|
||
}
|
||
|
||
//
|
||
// free DCInfo
|
||
//
|
||
LocalFree(DCInfo);
|
||
}
|
||
}
|
||
|
||
return(Win32rc);
|
||
|
||
}
|
||
|
||
DWORD
|
||
MyLdapClose(
|
||
IN PLDAP *pLdap
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Close the LDAP bind.
|
||
|
||
Arguments:
|
||
|
||
pLdap - the ldap handle
|
||
|
||
Return:
|
||
|
||
Win32 error
|
||
|
||
--*/
|
||
{
|
||
if ( pLdap != NULL ) {
|
||
|
||
//
|
||
// unbind pLDAP
|
||
//
|
||
if ( *pLdap != NULL )
|
||
ldap_unbind(*pLdap);
|
||
|
||
*pLdap = NULL;
|
||
}
|
||
|
||
return(ERROR_SUCCESS);
|
||
}
|
||
|
||
|
||
//*************************************************************
|
||
// Routines to handle events
|
||
//*************************************************************
|
||
|
||
BOOL InitializeEvents (void)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Opens the event log
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return:
|
||
|
||
TRUE if successful
|
||
FALSE if an error occurs
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Open the event source
|
||
//
|
||
|
||
hEventLog = RegisterEventSource(NULL, EventSourceName);
|
||
|
||
if (hEventLog) {
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
int
|
||
LogEvent(
|
||
IN DWORD LogLevel,
|
||
IN DWORD dwEventID,
|
||
IN UINT idMsg,
|
||
...)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Logs a verbose event to the event log
|
||
|
||
Arguments:
|
||
|
||
bLogLevel - the severity level of the log
|
||
STATUS_SEVERITY_SUCCESS
|
||
STATUS_SEVERITY_INFORMATIONAL
|
||
STATUS_SEVERITY_WARNING
|
||
STATUS_SEVERITY_ERROR
|
||
|
||
dwEventID - the event ID (defined in uevents.mc)
|
||
|
||
idMsg - Message id
|
||
|
||
Return:
|
||
|
||
TRUE if successful
|
||
FALSE if an error occurs
|
||
|
||
--*/
|
||
{
|
||
|
||
TCHAR szMsg[MAX_PATH];
|
||
TCHAR szErrorMsg[2*MAX_PATH+40];
|
||
LPTSTR aStrings[2];
|
||
WORD wType;
|
||
va_list marker;
|
||
|
||
//
|
||
// Load the message
|
||
//
|
||
if (idMsg != 0) {
|
||
|
||
pLoadResourceString(idMsg, szMsg, MAX_PATH,
|
||
TEXT("Error loading resource string. Params : %x"));
|
||
|
||
} else {
|
||
lstrcpy (szMsg, TEXT("%s"));
|
||
}
|
||
|
||
|
||
//
|
||
// Plug in the arguments
|
||
//
|
||
szErrorMsg[0] = L'\0';
|
||
va_start(marker, idMsg);
|
||
__try {
|
||
wvsprintf(szErrorMsg, szMsg, marker);
|
||
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
}
|
||
va_end(marker);
|
||
|
||
//
|
||
// Check for the event log being open.
|
||
//
|
||
|
||
if (!hEventLog) {
|
||
if (!InitializeEvents()) {
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Report the event to the eventlog
|
||
//
|
||
|
||
aStrings[0] = szErrorMsg;
|
||
|
||
switch (LogLevel) {
|
||
case STATUS_SEVERITY_WARNING:
|
||
wType = EVENTLOG_WARNING_TYPE;
|
||
break;
|
||
case STATUS_SEVERITY_SUCCESS:
|
||
wType = EVENTLOG_SUCCESS;
|
||
break;
|
||
case STATUS_SEVERITY_ERROR:
|
||
wType = EVENTLOG_ERROR_TYPE;
|
||
break;
|
||
default:
|
||
wType = EVENTLOG_INFORMATION_TYPE;
|
||
break;
|
||
}
|
||
|
||
if (!ReportEvent(hEventLog,
|
||
wType,
|
||
0,
|
||
dwEventID,
|
||
NULL,
|
||
1,
|
||
0,
|
||
(LPCTSTR *)aStrings,
|
||
NULL) ) {
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
BOOL
|
||
ShutdownEvents (void)
|
||
/*++
|
||
Routine Description:
|
||
|
||
Stops the event log
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return:
|
||
|
||
TRUE if successful
|
||
FALSE if an error occurs
|
||
--*/
|
||
{
|
||
BOOL bRetVal = TRUE;
|
||
|
||
if (hEventLog) {
|
||
bRetVal = DeregisterEventSource(hEventLog);
|
||
hEventLog = NULL;
|
||
}
|
||
|
||
return bRetVal;
|
||
}
|
||
|
||
LPWSTR
|
||
GetCertDisplayInformation(
|
||
IN PCCERT_CONTEXT pCertContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the display string from the passed certificate context.
|
||
|
||
Arguments:
|
||
|
||
pCertContext - Supplies a pointer to an open certificate context.
|
||
|
||
Return Value:
|
||
|
||
On success, pointer to display string. Caller must call
|
||
free() to free.
|
||
|
||
NULL on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Format = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
|
||
|
||
//
|
||
// First, try to get the email name
|
||
//
|
||
|
||
DWORD cchNameString;
|
||
LPWSTR wszNameString = NULL;
|
||
|
||
cchNameString = CertGetNameString(
|
||
pCertContext,
|
||
CERT_NAME_RDN_TYPE,
|
||
0,
|
||
&Format,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
if (cchNameString != 1) {
|
||
|
||
//
|
||
// String was found
|
||
//
|
||
|
||
wszNameString = (LPWSTR)malloc( cchNameString * sizeof( WCHAR ));
|
||
|
||
if (wszNameString) {
|
||
|
||
cchNameString = CertGetNameString(
|
||
pCertContext,
|
||
CERT_NAME_RDN_TYPE,
|
||
0,
|
||
&Format,
|
||
wszNameString,
|
||
cchNameString
|
||
);
|
||
} else {
|
||
|
||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// This shouldn't happen. If it does, we'll return NULL.
|
||
// Try to complain about it.
|
||
//
|
||
|
||
ASSERT( FALSE );
|
||
}
|
||
|
||
return( wszNameString );
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
IsSelfSignedPolicyExpired(
|
||
IN PRECOVERY_POLICY_1_1 RecoveryPolicy OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks if the existing recovery cert expiring within one year
|
||
|
||
Arguments:
|
||
|
||
PolicyEfsInfo - Supplies a pointer to the current EFS recovery policy.
|
||
|
||
Return Value:
|
||
|
||
return-value - TRUE if it is within one year
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN GetNewCert = TRUE;
|
||
|
||
if (RecoveryPolicy == NULL) {
|
||
//
|
||
// We need to create a new one if none exists.
|
||
//
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
if (RecoveryPolicy->RecoveryPolicyHeader.RecoveryKeyCount > 1){
|
||
|
||
//
|
||
// Default recovery policy changed.
|
||
//
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
__try {
|
||
|
||
//
|
||
// Scan the recovery data looking for recovery keys in a format we understand
|
||
//
|
||
|
||
|
||
PEFS_PUBLIC_KEY_INFO PublicKeyInfo = &((PRECOVERY_KEY_1_1) &(RecoveryPolicy->RecoveryKeyList[0]))->PublicKeyInfo;
|
||
|
||
|
||
if (PublicKeyInfo->KeySourceTag != EfsCertificate) {
|
||
|
||
//
|
||
// Out dated recovery cert. Get a new one
|
||
//
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
PBYTE pbCert = (PBYTE)OFFSET_TO_POINTER(CertificateInfo.Certificate, PublicKeyInfo);
|
||
DWORD cbCert = PublicKeyInfo->CertificateInfo.CertificateLength;
|
||
|
||
PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(
|
||
CRYPT_ASN_ENCODING,
|
||
(const PBYTE)pbCert,
|
||
cbCert);
|
||
|
||
if (pCertContext) {
|
||
|
||
SYSTEMTIME CertTime;
|
||
SYSTEMTIME CrntTime;
|
||
|
||
if (FileTimeToSystemTime(&(pCertContext->pCertInfo->NotAfter), &CertTime)){
|
||
|
||
GetSystemTime( &CrntTime);
|
||
|
||
if ( CertTime.wYear <= CrntTime.wYear + 1) {
|
||
//
|
||
// Get the display information
|
||
//
|
||
|
||
LPWSTR lpDisplayInfo = GetCertDisplayInformation( pCertContext );
|
||
|
||
if (lpDisplayInfo ) {
|
||
|
||
if (!wcstok( lpDisplayInfo, L"OU=EFS File Encryption Certificate" )){
|
||
GetNewCert = FALSE;
|
||
}
|
||
|
||
free(lpDisplayInfo);
|
||
}
|
||
} else {
|
||
|
||
GetNewCert = FALSE;
|
||
|
||
}
|
||
}
|
||
|
||
CertFreeCertificateContext( pCertContext );
|
||
|
||
}
|
||
|
||
|
||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
//
|
||
// There was something wrong with the recovery policy.
|
||
// Get a new recovery cert.
|
||
//
|
||
|
||
}
|
||
|
||
return GetNewCert;
|
||
|
||
}
|
||
|
||
|