windows-nt/Source/XPSP1/NT/ds/security/services/ca/ocmsetup/setuput.cpp
2020-09-26 16:20:57 +08:00

7545 lines
203 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: setuput.cpp
//
// Contents: Utility functions for OCM based setup.
//
// History: 04/20/97 JerryK Created
//
//-------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
// ** C Runtime Includes
#include <sys/types.h>
#include <sys/stat.h>
// ** System Includes **
#include <lmaccess.h>
#include <lmapibuf.h>
#include "csdisp.h"
#include <shlobj.h>
#include <userenv.h>
#include <dsgetdc.h>
#include <sddl.h>
#include <winldap.h>
#include <autoenr.h>
#include <userenvp.h> // CreateLinkFile API
// ** security includes **
#include <aclapi.h>
// ** Application Includes **
#include "initcert.h"
#include "cscsp.h"
#include "cspenum.h"
#include "csldap.h"
#include "wizpage.h"
#include "websetup.h"
#include "certsrvd.h"
#include "regd.h"
#include "usecert.h"
#include "certmsg.h"
#include "dssetup.h"
#include "progress.h"
#include <certca.h>
#include "csprop.h"
#include "setupids.h"
#define __dwFILE__ __dwFILE_OCMSETUP_SETUPUT_CPP__
EXTERN_C const IID IID_IGPEInformation;
EXTERN_C const CLSID CLSID_GPESnapIn;
#define CERT_HALF_SECOND 500 // # of milliseconds in half second
#define CERT_MAX_ATTEMPT 2 * 60 * 2 // # of half seconds in 2 minutes
#define wszREQUESTVERINDPROGID L"CertSrv.Request"
#define wszREQUESTPROGID L"CertSrv.Request.1"
#define wszADMINVERINDPROGID L"CertSrv.Admin"
#define wszADMINPROGID L"CertSrv.Admin.1"
#define wszREQUESTFRIENDLYNAME L"CertSrv Request"
#define wszADMINFRIENDLYNAME L"CertSrv Admin"
#define wszCERTSRV L"CertSrv"
#define wszREGW3SCRIPTMAP L"System\\CurrentControlSet\\Services\\W3SVC\\Parameters\\Script Map"
#define wszHTTPS L"https://"
#define wszASPEXT L".asp"
#define wszHTTP L"http://"
#define wszDOTCERTEXT L".cer"
#define wszNEWLINE L"\n"
#define wszFILESC L"file://\\\\"
#define SZ_REGSVR32 L"regsvr32.exe"
#define SZ_REGSVR32_CERTCLI L"/i:i /n /s certcli.dll"
#define SZ_VERB_OPEN L"open"
// hardcoded shares
#define wszCERTENROLLURLPATH L"/CertEnroll/"
#define wszzREGSUBJECTTEMPLATEVALUE \
wszPROPEMAIL L"\0" \
wszPROPCOMMONNAME L"\0" \
wszATTRORGUNIT4 L"\0" \
wszPROPORGANIZATION L"\0" \
wszPROPLOCALITY L"\0" \
wszPROPSTATE L"\0" \
wszPROPDOMAINCOMPONENT L"\0" \
wszPROPCOUNTRY L"\0"
// Whistler SMIME extension (or any other CSP):
// SMIME Capabilities
// [1]SMIME Capability
// Object ID=1.2.840.113549.3.2 szOID_RSA_RC2CBC, 128 bit
// Parameters=02 02 00 80
// [2]SMIME Capability
// Object ID=1.2.840.113549.3.4 szOID_RSA_RC4, 128 bit
// Parameters=02 02 00 80
// [3]SMIME Capability
// Object ID=1.3.14.3.2.7 szOID_OIWSEC_desCBC
// [4]SMIME Capability
// Object ID=1.2.840.113549.3.7 szOID_RSA_DES_EDE3_CBC
//
#define wszzREGVALUEDEFAULTSMIME \
TEXT(szOID_RSA_RC2CBC) L",128" L"\0" \
TEXT(szOID_RSA_RC4) L",128" L"\0" \
TEXT(szOID_OIWSEC_desCBC) L"\0" \
TEXT(szOID_RSA_DES_EDE3_CBC) L"\0"
#ifdef CERTSRV_ENABLE_ALL_REGISTRY_DEFAULTS
# define wszREGSUBJECTALTNAMEVALUE L"EMail"
# define wszREGSUBJECTALTNAME2VALUE L"EMail"
#else
# define wszREGSUBJECTALTNAMEVALUE \
L"DISABLED: Set to EMail to set SubjectAltName extension to the email address"
# define wszREGSUBJECTALTNAME2VALUE \
L"DISABLED: Set to EMail to set SubjectAltName2 extension to the email address"
#endif
#define szNULL_SESSION_REG_LOCATION "System\\CurrentControlSet\\Services\\LanmanServer\\Parameters"
#define szNULL_SESSION_VALUE "NullSessionPipes"
#define wszDEFAULTSHAREDFOLDER L"\\CAConfig"
// globals
WCHAR *g_pwszArgvPath = NULL; // for installing from local directory
WCHAR *g_pwszNoService = NULL; // skip CreateService
WCHAR *g_pwszSanitizedChar = NULL; // take first char for sanitizing test
#if DBG_CERTSRV
WCHAR *g_pwszDumpStrings = NULL; // dump resource strings
#endif
BOOL g_fW3SvcRunning = FALSE;
WCHAR g_wszServicePath[MAX_PATH];
// Version-independent ProgID
// ProgID
WCHAR const g_wszCertAdmDotDll[] = L"certadm.dll";
WCHAR const g_wszCertCliDotDll[] = L"certcli.dll";
WCHAR const g_wszcertEncDotDll[] = L"certenc.dll";
WCHAR const g_wszCertXDSDotDll[] = L"certxds.dll";
WCHAR const g_wszCertIfDotDll[] = L"certif.dll";
WCHAR const g_wszCertPDefDotDll[] = L"certpdef.dll";
WCHAR const g_wszCertMMCDotDll[] = L"certmmc.dll";
WCHAR const g_wszCertSrvDotMsc[] = L"certsrv.msc";
WCHAR const g_wszSCrdEnrlDotDll[] = L"scrdenrl.dll";
WCHAR const g_wszCertReqDotExe[] = L"certreq.exe";
WCHAR const g_wszCertUtilDotExe[] = L"certutil.exe";
WCHAR const g_wszCertDBDotDll[] = L"certdb.dll";
WCHAR const g_wszCertViewDotDll[] = L"certview.dll";
WCHAR const g_wszCSBullDotGif[] = L"csbull.gif";
WCHAR const g_wszCSBackDotGif[] = L"csback.gif";
WCHAR const g_wszCSLogoDotGif[] = L"cslogo.gif";
CHAR const * const aszRegisterServer[] = {
"DllRegisterServer",
"DllUnregisterServer",
};
typedef struct _REGISTERDLL
{
WCHAR const *pwszDllName;
DWORD Flags;
} REGISTERDLL;
#define RD_SERVER 0x00000001 // Register on server
#define RD_CLIENT 0x00000002 // Register on client
#define RD_UNREGISTER 0x00000004 // Unegister on client & server
#define RD_WHISTLER 0x00000008 // Register must succeed on Whistler only
#define RD_SKIPUNREGPOLICY 0x00000010 // not unreg custom policy during upgrade
#define RD_SKIPUNREGEXIT 0x00000020 // not unreg custom exit during upgrade
#define RD_SKIPUNREGMMC 0x00000040 // bug# 38876
REGISTERDLL const g_aRegisterDll[] = {
{ g_wszCertAdmDotDll, RD_SERVER | RD_CLIENT },
{ g_wszCertCliDotDll, RD_SERVER | RD_CLIENT },
{ g_wszcertEncDotDll, RD_SERVER | RD_CLIENT | RD_UNREGISTER },
{ g_wszCertXDSDotDll, RD_SERVER | RD_UNREGISTER | RD_SKIPUNREGEXIT},
{ g_wszCertIfDotDll, RD_UNREGISTER },
{ g_wszCertPDefDotDll, RD_SERVER | RD_UNREGISTER | RD_SKIPUNREGPOLICY },
{ g_wszCertMMCDotDll, RD_SERVER | RD_UNREGISTER | RD_SKIPUNREGMMC },
{ g_wszSCrdEnrlDotDll, RD_SERVER | RD_CLIENT | RD_UNREGISTER | RD_WHISTLER },
{ g_wszCertDBDotDll, RD_SERVER | RD_UNREGISTER },
{ g_wszCertViewDotDll, RD_UNREGISTER },
{ NULL, 0 }
};
typedef struct _PROGRAMENTRY
{
UINT uiLinkName;
UINT uiGroupName;
UINT uiDescription;
DWORD csidl; // special folder index
WCHAR const *pwszExeName;
WCHAR const *pwszClientArgs;
WCHAR const *pwszServerArgs;
DWORD Flags;
} PROGRAMENTRY;
#define PE_SERVER 0x00000001 // Install on server
#define PE_CLIENT 0x00000002 // Install on client
#define PE_DELETEONLY 0x00000004 // Always delete
PROGRAMENTRY const g_aProgramEntry[] = {
{
IDS_STARTMENU_NEWCRL_LINKNAME, // uiLinkName
IDS_STARTMENU_CERTSERVER, // uiGroupName
0, // uiDescription
CSIDL_COMMON_PROGRAMS, // "All Users\Start Menu\Programs"
g_wszCertUtilDotExe, // pwszExeName
NULL, // pwszClientArgs
L"-crl -", // pwszServerArgs
PE_DELETEONLY | PE_SERVER, // Flags
},
{
IDS_STARTMENU_CERTHIER_LINKNAME, // uiLinkName
IDS_STARTMENU_CERTSERVER, // uiGroupName
0, // uiDescription
CSIDL_COMMON_PROGRAMS, // "All Users\Start Menu\Programs"
L"certhier.exe", // pwszExeName
NULL, // pwszClientArgs
NULL, // pwszServerArgs
PE_DELETEONLY | PE_SERVER, // Flags
},
{
IDS_STARTMENU_CERTREQ_LINKNAME, // uiLinkName
IDS_STARTMENU_CERTSERVER, // uiGroupName
0, // uiDescription
CSIDL_COMMON_PROGRAMS, // "All Users\Start Menu\Programs"
g_wszCertReqDotExe, // pwszExeName
NULL, // pwszClientArgs
NULL, // pwszServerArgs
PE_DELETEONLY | PE_CLIENT | PE_SERVER, // Flags
},
};
#define CPROGRAMENTRY ARRAYSIZE(g_aProgramEntry)
static char rgcCERT_NULL_SESSION[] = {0x43, 0x45, 0x52, 0x54, 0x00, 0x00};
// ** Prototypes **
HRESULT
UpgradeServerRegEntries(
IN HWND hwnd,
IN PER_COMPONENT_DATA *pComp);
HRESULT
CreateServerRegEntries(
IN HWND hwnd,
IN BOOL fUpgrade,
IN PER_COMPONENT_DATA *pComp);
HRESULT
CreateWebClientRegEntries(
BOOL fUpgrade,
PER_COMPONENT_DATA *pComp);
HRESULT
UpgradeWebClientRegEntries(
PER_COMPONENT_DATA *pComp);
HRESULT
GetServerNames(
IN HWND hwnd,
IN HINSTANCE hInstance,
IN BOOL fUnattended,
OUT WCHAR **ppwszServerName,
OUT WCHAR **ppwszServerNameOld);
HRESULT
UpdateDomainAndUserName(
IN HWND hwnd,
IN OUT PER_COMPONENT_DATA *pComp);
HRESULT
RegisterAndUnRegisterDLLs(
IN DWORD Flags,
IN PER_COMPONENT_DATA *pComp,
IN HWND hwnd);
HRESULT RenameMiscTargets(HWND hwnd, PER_COMPONENT_DATA *pComp, BOOL fServer);
HRESULT DeleteProgramGroups(IN BOOL fAll, IN PER_COMPONENT_DATA *pComp);
HRESULT CreateCertificateService(PER_COMPONENT_DATA *pComp, HWND hwnd);
HRESULT DeleteCertificates(const WCHAR *, BOOL fRoot);
HRESULT TriggerAutoenrollment();
//endproto
#ifdef DBG_OCM_TRACE
VOID
CaptureStackBackTrace(
EXCEPTION_POINTERS *pep,
ULONG cSkip,
ULONG cFrames,
ULONG *aeip)
{
ZeroMemory(aeip, cFrames * sizeof(aeip[0]));
#if i386 == 1
ULONG ieip, *pebp;
ULONG *pebpMax = (ULONG *) MAXLONG; // 2 * 1024 * 1024 * 1024; // 2 gig - 1
ULONG *pebpMin = (ULONG *) (64 * 1024); // 64k
if (pep == NULL)
{
ieip = 0;
cSkip++; // always skip current frame
pebp = ((ULONG *) &pep) - 2;
}
else
{
ieip = 1;
CSASSERT(cSkip == 0);
aeip[0] = pep->ContextRecord->Eip;
pebp = (ULONG *) pep->ContextRecord->Ebp;
}
if (pebp >= pebpMin && pebp < pebpMax)
{
__try
{
for ( ; ieip < cSkip + cFrames; ieip++)
{
if (ieip >= cSkip)
{
aeip[ieip - cSkip] = *(pebp + 1); // save an eip
}
ULONG *pebpNext = (ULONG *) *pebp;
if (pebpNext < pebp + 2 || pebpNext >= pebpMax - 1)
{
break;
}
pebp = pebpNext;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
;
}
}
#endif // i386 == 1
}
#endif // DBG_OCM_TRACE
VOID
DumpBackTrace(char const *pszName)
{
#ifdef DBG_OCM_TRACE
ULONG aeip[10];
DBGPRINT((MAXDWORD, "%hs: BackTrace:\n", pszName));
CaptureStackBackTrace(NULL, 1, ARRAYSIZE(aeip), aeip);
for (int i = 0; i < ARRAYSIZE(aeip); i++)
{
if (NULL == aeip[i])
{
break;
}
DBGPRINT((MAXDWORD, "ln %x;", aeip[i]));
}
DBGPRINT((MAXDWORD, "\n"));
#endif // DBG_OCM_TRACE
}
__inline VOID
AppendBackSlash(
IN OUT WCHAR *pwszOut)
{
DWORD cwc = wcslen(pwszOut);
if (0 == cwc || L'\\' != pwszOut[cwc - 1])
{
pwszOut[cwc++] = L'\\';
pwszOut[cwc] = L'\0';
}
}
__inline VOID
StripBackSlash(
IN OUT WCHAR *pwszOut)
{
DWORD cwc = wcslen(pwszOut);
if (0 < cwc && L'\\' == pwszOut[cwc - 1])
{
pwszOut[cwc] = L'\0';
}
}
VOID
BuildPath(
OUT WCHAR *pwszOut,
IN DWORD cwcOut,
IN WCHAR const *pwszDir,
IN WCHAR const *pwszFile)
{
wcscpy(pwszOut, pwszDir);
AppendBackSlash(pwszOut);
wcscat(pwszOut, pwszFile);
StripBackSlash(pwszOut);
CSASSERT(wcslen(pwszOut) < cwcOut);
DBGPRINT((DBG_SS_CERTOCMI, "BuildPath(%ws, %ws) -> %ws\n", pwszDir, pwszFile, pwszOut));
}
VOID
FreeCARequestInfo(CASERVERSETUPINFO *pServer)
{
if (NULL != pServer->pwszRequestFile)
{
LocalFree(pServer->pwszRequestFile);
}
if (NULL != pServer->pwszParentCAMachine)
{
LocalFree(pServer->pwszParentCAMachine);
}
if (NULL != pServer->pwszParentCAName)
{
LocalFree(pServer->pwszParentCAName);
}
}
VOID
FreeCAStoreInfo(CASERVERSETUPINFO *pServer)
{
if (NULL != pServer->pwszSharedFolder)
{
LocalFree(pServer->pwszSharedFolder);
}
if (NULL != pServer->pwszDBDirectory)
{
LocalFree(pServer->pwszDBDirectory);
}
if (NULL != pServer->pwszLogDirectory)
{
LocalFree(pServer->pwszLogDirectory);
}
}
VOID
FreeCAServerAdvanceInfo(CASERVERSETUPINFO *pServer)
{
if (NULL != pServer->pCSPInfoList)
{
FreeCSPInfoList(pServer->pCSPInfoList);
}
if (NULL != pServer->pKeyList)
{
csiFreeKeyList(pServer->pKeyList);
}
if (NULL != pServer->pDefaultCSPInfo)
{
freeCSPInfo(pServer->pDefaultCSPInfo);
}
if (NULL != pServer->pwszDesanitizedKeyContainerName)
{
LocalFree(pServer->pwszDesanitizedKeyContainerName);
}
if (NULL != pServer->pccExistingCert)
{
ClearExistingCertToUse(pServer);
}
if (NULL != pServer->pccUpgradeCert)
{
CertFreeCertificateContext(pServer->pccUpgradeCert);
}
if (NULL != pServer->pwszValidityPeriodCount)
{
LocalFree(pServer->pwszValidityPeriodCount);
}
if (NULL != pServer->pszAlgId)
{
LocalFree(pServer->pszAlgId);
}
if (NULL != pServer->hMyStore)
{
CertCloseStore(pServer->hMyStore, 0);
}
// don't free following because they are just pointers
// pServer->pCSPInfo
// pServer->pHashInfo
}
VOID
FreeCAServerIdInfo(
CASERVERSETUPINFO *pServer)
{
if (NULL != pServer->pwszCACommonName)
{
LocalFree(pServer->pwszCACommonName);
pServer->pwszCACommonName = NULL;
}
}
VOID
FreeCAServerInfo(CASERVERSETUPINFO *pServer)
{
FreeCAServerIdInfo(pServer);
FreeCAServerAdvanceInfo(pServer);
FreeCAStoreInfo(pServer);
FreeCARequestInfo(pServer);
if (NULL != pServer->pwszSanitizedName)
{
LocalFree(pServer->pwszSanitizedName);
}
if (NULL != pServer->pwszDNSuffix)
{
LocalFree(pServer->pwszDNSuffix);
}
if (NULL != pServer->pwszFullCADN)
{
LocalFree(pServer->pwszFullCADN);
}
if (NULL != pServer->pwszKeyContainerName)
{
LocalFree(pServer->pwszKeyContainerName);
}
if (NULL != pServer->pwszCACertFile)
{
LocalFree(pServer->pwszCACertFile);
}
if (NULL != pServer->pwszUseExistingCert)
{
LocalFree(pServer->pwszUseExistingCert);
}
if (NULL != pServer->pwszPreserveDB)
{
LocalFree(pServer->pwszPreserveDB);
}
if (NULL != pServer->pwszCustomPolicy)
{
LocalFree(pServer->pwszCustomPolicy);
}
if (NULL != pServer->pwszzCustomExit)
{
LocalFree(pServer->pwszzCustomExit);
}
}
VOID
FreeCAClientInfo(CAWEBCLIENTSETUPINFO *pClient)
{
if (NULL != pClient)
{
if (NULL != pClient->pwszWebCAMachine)
{
LocalFree(pClient->pwszWebCAMachine);
}
if (NULL != pClient->pwszWebCAName)
{
LocalFree(pClient->pwszWebCAName);
}
if (NULL != pClient->pwszSanitizedWebCAName)
{
LocalFree(pClient->pwszSanitizedWebCAName);
}
if (NULL != pClient->pwszSharedFolder)
{
LocalFree(pClient->pwszSharedFolder);
}
}
}
VOID
FreeCAInfo(CASETUPINFO *pCA)
{
if (NULL != pCA->pServer)
{
FreeCAServerInfo(pCA->pServer);
LocalFree(pCA->pServer);
pCA->pServer = NULL;
}
if (NULL != pCA->pClient)
{
FreeCAClientInfo(pCA->pClient);
LocalFree(pCA->pClient);
pCA->pClient = NULL;
}
}
VOID
FreeCAComponentInfo(PER_COMPONENT_DATA *pComp)
{
if (NULL != pComp->pwszCustomMessage)
{
LocalFree(pComp->pwszCustomMessage);
}
if (NULL != pComp->pwszComponent)
{
LocalFree(pComp->pwszComponent);
}
if (NULL != pComp->pwszUnattendedFile)
{
LocalFree(pComp->pwszUnattendedFile);
}
if (NULL != pComp->pwszServerName)
{
LocalFree(pComp->pwszServerName);
}
if (NULL != pComp->pwszServerNameOld)
{
LocalFree(pComp->pwszServerNameOld);
}
if (NULL != pComp->pwszSystem32)
{
LocalFree(pComp->pwszSystem32);
}
FreeCAInfo(&(pComp->CA));
}
VOID
FreeCAGlobals(VOID)
{
if (NULL != g_pwszArgvPath)
{
LocalFree(g_pwszArgvPath);
}
if (NULL != g_pwszNoService)
{
LocalFree(g_pwszNoService);
}
if (NULL != g_pwszSanitizedChar)
{
LocalFree(g_pwszSanitizedChar);
}
#if DBG_CERTSRV
if (NULL != g_pwszDumpStrings)
{
LocalFree(g_pwszDumpStrings);
}
#endif
}
VOID
SaveCustomMessage(
IN OUT PER_COMPONENT_DATA *pComp,
OPTIONAL IN WCHAR const *pwszCustomMessage)
{
HRESULT hr;
if (NULL != pwszCustomMessage)
{
if (NULL != pComp->pwszCustomMessage)
{
LocalFree(pComp->pwszCustomMessage);
pComp->pwszCustomMessage = NULL;
}
hr = myDupString(pwszCustomMessage, &pComp->pwszCustomMessage);
_JumpIfError(hr, error, "myDupString");
}
error:
;
}
HRESULT
LoadDefaultCAIDAttributes(
IN OUT PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
DWORD i;
// free existing Id info before load default
FreeCAServerIdInfo(pServer);
// load default from resource
if (NULL != g_pwszSanitizedChar)
{
if (NULL != pServer->pwszCACommonName)
{
LocalFree(pServer->pwszCACommonName);
}
// replace with the env var
pServer->pwszCACommonName = (WCHAR*)LocalAlloc(LMEM_FIXED,
(wcslen(g_pwszSanitizedChar) + 1) * sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, pServer->pwszCACommonName);
wcscpy(pServer->pwszCACommonName, g_pwszSanitizedChar);
}
// default validity
pServer->enumValidityPeriod = dwVALIDITYPERIODENUMDEFAULT;
pServer->dwValidityPeriodCount = dwVALIDITYPERIODCOUNTDEFAULT_ROOT;
GetSystemTimeAsFileTime(&pServer->NotBefore);
pServer->NotAfter = pServer->NotBefore;
myMakeExprDateTime(
&pServer->NotAfter,
pServer->dwValidityPeriodCount,
pServer->enumValidityPeriod);
hr = S_OK;
error:
return(hr);
}
HRESULT
GetDefaultDBDirectory(
IN PER_COMPONENT_DATA *pComp,
OUT WCHAR **ppwszDir)
{
HRESULT hr;
DWORD cwc;
*ppwszDir = NULL;
cwc = wcslen(pComp->pwszSystem32) +
wcslen(wszLOGPATH) +
1;
*ppwszDir = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, *ppwszDir);
// default
wcscpy(*ppwszDir, pComp->pwszSystem32);
wcscat(*ppwszDir, wszLOGPATH);
CSASSERT(cwc == (DWORD) (wcslen(*ppwszDir) + 1));
hr = S_OK;
error:
return(hr);
}
HRESULT
LoadDefaultDBDirAttributes(
IN OUT PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
if (NULL != pServer->pwszDBDirectory)
{
LocalFree(pServer->pwszDBDirectory);
pServer->pwszDBDirectory = NULL;
}
hr = GetDefaultDBDirectory(pComp, &pServer->pwszDBDirectory);
_JumpIfError(hr, error, "GetDefaultDBDirectory");
// default log dir is the same as db
if (NULL != pServer->pwszLogDirectory)
{
LocalFree(pServer->pwszLogDirectory);
}
pServer->pwszLogDirectory = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pServer->pwszDBDirectory) + 1) * sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, pServer->pwszLogDirectory);
wcscpy(pServer->pwszLogDirectory, pServer->pwszDBDirectory);
pServer->fPreserveDB = FALSE;
hr = S_OK;
error:
return(hr);
}
HRESULT
LoadDefaultAdvanceAttributes(
IN OUT CASERVERSETUPINFO* pServer)
{
HRESULT hr;
// load default csp, ms base csp
pServer->fAdvance = FALSE;
if (NULL == pServer->pDefaultCSPInfo)
{
pServer->pDefaultCSPInfo = newCSPInfo(PROV_RSA_FULL, wszBASECSP);
if (NULL == pServer->pDefaultCSPInfo && !IsWhistler())
{
pServer->pDefaultCSPInfo = newCSPInfo(PROV_RSA_FULL, MS_DEF_PROV_W);
}
_JumpIfOutOfMemory(hr, error, pServer->pDefaultCSPInfo);
}
// determine default hash, sha1
pServer->pDefaultHashInfo = pServer->pDefaultCSPInfo->pHashList;
while (NULL != pServer->pDefaultHashInfo)
{
if (pServer->pDefaultHashInfo->idAlg == CALG_SHA1)
{
//got default
break;
}
pServer->pDefaultHashInfo = pServer->pDefaultHashInfo->next;
}
// If we have not just created a default key, reset the key container name.
if (pServer->pCSPInfo != pServer->pDefaultCSPInfo ||
(pServer->dwKeyLength != CA_DEFAULT_KEY_LENGTH_ROOT &&
pServer->dwKeyLength != CA_DEFAULT_KEY_LENGTH_SUB) ||
!pServer->fDeletableNewKey) {
ClearKeyContainerName(pServer);
}
// ok, point to defaults
pServer->pCSPInfo = pServer->pDefaultCSPInfo;
pServer->pHashInfo = pServer->pDefaultHashInfo;
// some other related defaults
pServer->dwKeyLength = IsRootCA(pServer->CAType)?
CA_DEFAULT_KEY_LENGTH_ROOT:
CA_DEFAULT_KEY_LENGTH_SUB;
pServer->dwKeyLenMin = 0;
pServer->dwKeyLenMax = 0;
// update hash oid
if (NULL != pServer->pszAlgId)
{
// free old
LocalFree(pServer->pszAlgId);
}
hr = myGetSigningOID(
NULL, // hProv
pServer->pCSPInfo->pwszProvName,
pServer->pCSPInfo->dwProvType,
pServer->pHashInfo->idAlg,
&(pServer->pszAlgId));
_JumpIfError(hr, error, "myGetSigningOID");
error:
return(hr);
}
HRESULT
LoadDefaultCAClientAttributes(
IN HWND hwnd,
IN OUT PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CAWEBCLIENTSETUPINFO *pClient = pComp->CA.pClient;
if (NULL != pClient)
{
// free existing client setup info
FreeCAClientInfo(pClient);
LocalFree(pClient);
pComp->CA.pClient = NULL;
}
pComp->CA.pClient = (CAWEBCLIENTSETUPINFO *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
sizeof(CAWEBCLIENTSETUPINFO));
_JumpIfOutOfMemory(hr, error, pComp->CA.pClient);
pComp->CA.pClient->WebCAType = ENUM_UNKNOWN_CA;
hr = S_OK;
error:
return(hr);
}
HRESULT
GetDefaultSharedFolder(
OUT WCHAR **ppwszSharedFolder)
{
HRESULT hr = S_OK;
WCHAR *pwszSysDrive = NULL;
*ppwszSharedFolder = NULL;
hr = myGetEnvString(&pwszSysDrive, L"SystemDrive");
if (S_OK == hr)
{
*ppwszSharedFolder = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pwszSysDrive) + wcslen(wszDEFAULTSHAREDFOLDER) + 1) *
sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, *ppwszSharedFolder);
wcscpy(*ppwszSharedFolder, pwszSysDrive);
wcscat(*ppwszSharedFolder, wszDEFAULTSHAREDFOLDER);
}
error:
if (NULL != pwszSysDrive)
{
LocalFree(pwszSysDrive);
}
return hr;
}
HRESULT
LoadDefaultCAServerAttributes(
IN HWND hwnd,
IN OUT PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
BOOL fDSCA = FALSE;
WCHAR *pwszSysDrive = NULL;
bool fIsDomainMember;
bool fUserCanInstallCA;
if (NULL != pComp->CA.pServer)
{
// free existing server setup info
FreeCAServerInfo(pComp->CA.pServer);
LocalFree(pComp->CA.pServer);
}
// allocate server info buffer
pComp->CA.pServer = (CASERVERSETUPINFO *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
sizeof(CASERVERSETUPINFO));
_JumpIfOutOfMemory(hr, error, pComp->CA.pServer);
hr = LoadDefaultCAIDAttributes(pComp);
_JumpIfError(hr, error, "LoadDefaultCAIDAttributes");
hr = LoadDefaultAdvanceAttributes(pComp->CA.pServer);
_JumpIfError(hr, error, "LoadDefaultAdvanceAttributes");
hr = LoadDefaultDBDirAttributes(pComp);
_JumpIfError(hr, error, "LoadDefaultDBDirAttributes");
// decide default using DS
// xtan, the following call should be replaced with HasDSWritePermission()
// remove DisableEnterpriseCAs()
pComp->CA.pServer->fUseDS = FALSE;
hr = LocalMachineIsDomainMember(&fIsDomainMember);
_JumpIfError(hr, error, "LocalMachineIsDomainMember");
if (fIsDomainMember)
{
if(IsDSAvailable())
{
hr = CurrentUserCanInstallCA(fUserCanInstallCA);
_JumpIfError(hr, error, "CurrentUserCanInstallCA");
if(fUserCanInstallCA)
{
pComp->CA.pServer->fUseDS = TRUE;
fDSCA = csiIsAnyDSCAAvailable();
}
}
}
// alway free and null old shared folder
if (NULL != pComp->CA.pServer->pwszSharedFolder)
{
LocalFree(pComp->CA.pServer->pwszSharedFolder);
pComp->CA.pServer->pwszSharedFolder = NULL;
}
// decide default CA type and default shared folder
pComp->CA.pServer->CAType = ENUM_STANDALONE_ROOTCA;
if (pComp->CA.pServer->fUseDS)
{
if (fDSCA)
{
pComp->CA.pServer->CAType = ENUM_ENTERPRISE_SUBCA;
}
else
{
pComp->CA.pServer->CAType = ENUM_ENTERPRISE_ROOTCA;
}
}
if (pComp->fUnattended || !pComp->CA.pServer->fUseDS)
{
BOOL fChangeToDefault = FALSE;
// try reg load first
hr = myGetCertRegStrValue(
NULL,
NULL,
NULL,
wszREGDIRECTORY,
&pComp->CA.pServer->pwszSharedFolder);
if (S_OK != hr && HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpErrorStr(hr, error, "myGetCertRegStrValue", wszREGDIRECTORY);
}
if (S_OK == hr)
{
if (L'\0' == *pComp->CA.pServer->pwszSharedFolder)
{
// this mast be empty string
fChangeToDefault = TRUE;
}
else
{
//got something, make sure unc path exist
DWORD dwPathFlag;
if (!myIsFullPath(pComp->CA.pServer->pwszSharedFolder,
&dwPathFlag))
{
// somehow register an invalid path, don't use it
fChangeToDefault = TRUE;
}
else
{
if (UNC_PATH == dwPathFlag &&
DE_DIREXISTS != DirExists(pComp->CA.pServer->pwszSharedFolder))
{
// this unc path doesn't exist any more
// not making any sense to use it
fChangeToDefault = TRUE;
pComp->CA.pServer->fUNCPathNotFound = TRUE;
}
}
}
}
else
{
//must be not found
fChangeToDefault = TRUE;
}
if (fChangeToDefault)
{
//free 1st
if (NULL != pComp->CA.pServer->pwszSharedFolder)
{
LocalFree(pComp->CA.pServer->pwszSharedFolder);
}
// load default
hr = GetDefaultSharedFolder(&pComp->CA.pServer->pwszSharedFolder);
_JumpIfError(hr, error, "GetDefaultSharedFolder");
}
}
pComp->CA.pServer->fSaveRequestAsFile = FALSE;
pComp->CA.pServer->pwszRequestFile = NULL;
pComp->CA.pServer->pwszParentCAMachine = NULL;
pComp->CA.pServer->pwszParentCAName = NULL;
hr = S_OK;
error:
return hr;
}
HRESULT
InitCASetup(
IN HWND hwnd,
IN OUT PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
UINT ui;
bool fIsAdmin = false;
hr = GetServerNames(
hwnd,
pComp->hInstance,
pComp->fUnattended,
&pComp->pwszServerName,
&pComp->pwszServerNameOld);
_JumpIfError(hr, error, "GetServerNames");
DBGPRINT((
DBG_SS_CERTOCMI,
"InitCASetup:GetServerNames:%ws,%ws\n",
pComp->pwszServerName,
pComp->pwszServerNameOld));
DumpBackTrace("InitCASetup");
hr = IsCurrentUserBuiltinAdmin(&fIsAdmin);
_JumpIfError(hr, error, "IsCurrentUserBuiltinAdmin");
if (!fIsAdmin)
{
hr = E_ACCESSDENIED;
CertErrorMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_ERR_NOT_ADM,
0,
NULL);
_JumpError(hr, error, "IsCurrentUserBuiltinAdmin");
}
// load some of environment variables
hr = myGetEnvString(&g_pwszArgvPath, L"CertSrv_BinDir");
hr = myGetEnvString(&g_pwszNoService, L"CertSrv_NoService");
hr = myGetEnvString(&g_pwszSanitizedChar, L"CertSrv_Sanitize");
#if DBG_CERTSRV
myGetEnvString(&g_pwszDumpStrings, L"CertSrv_DumpStrings");
#endif
// figure out where the system root directory is (build path to x:\\winnt\system32\)
ui = GetSystemDirectory(NULL, 0); // returns chars neccessary to hold path (incl null)
if (ui == 0)
{
hr = myHLastError();
_JumpError(hr, error, "GetSystemDirectory");
}
pComp->pwszSystem32 = (LPWSTR)LocalAlloc(LMEM_FIXED, (ui+1)*sizeof(WCHAR));
if (NULL == pComp->pwszSystem32)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if (0 == GetSystemDirectory(pComp->pwszSystem32, ui))
{
hr = myHLastError();
_JumpError(hr, error, "GetSystemDirectory");
}
wcscat(pComp->pwszSystem32, L"\\");
// load default atrributes anyway
hr = LoadDefaultCAServerAttributes(hwnd, pComp);
_JumpIfError(hr, error, "LoadDefaultCAServerAttributes");
hr = LoadDefaultCAClientAttributes(hwnd, pComp);
_JumpIfError(hr, error, "LoadDefaultCAClientAttributes");
if (pComp->fUnattended)
{
// hook unattended data
hr = HookUnattendedServerAttributes(pComp,
LookupSubComponent(cscServer));
_JumpIfError(hr, error, "HookUnattendedServerAttributes");
hr = HookUnattendedClientAttributes(pComp,
LookupSubComponent(cscClient));
_JumpIfError(hr, error, "HookUnattendedClientAttributes");
}
hr = S_OK;
error:
return(hr);
}
HRESULT
CreateInitialCertificateRequest(
IN HCRYPTPROV hProv,
IN CASERVERSETUPINFO *pServer,
IN PER_COMPONENT_DATA *pComp,
IN HWND hwnd,
OUT BYTE **ppbEncode,
OUT DWORD *pcbEncode)
{
HRESULT hr;
BYTE *pbSubjectEncoded = NULL;
DWORD cbSubjectEncoded;
HINF hInf = INVALID_HANDLE_VALUE;
DWORD ErrorLine;
LPCWSTR pszErrorPtr;
hr = AddCNAndEncode(
pServer->pwszCACommonName,
pServer->pwszDNSuffix,
&pbSubjectEncoded,
&cbSubjectEncoded);
_JumpIfError(hr, error, "AddCNAndEncodeCertStrToName");
hr = myInfOpenFile(NULL, &hInf, &ErrorLine);
_PrintIfError2(
hr,
"myInfOpenFile",
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
hr = csiBuildRequest(
hInf,
NULL,
pbSubjectEncoded,
cbSubjectEncoded,
pServer->pszAlgId,
TRUE, // fNewKey
CANAMEIDTOICERT(pServer->dwCertNameId),
CANAMEIDTOIKEY(pServer->dwCertNameId),
hProv,
hwnd,
pComp->hInstance,
pComp->fUnattended,
ppbEncode,
pcbEncode);
_JumpIfError(hr, error, "csiBuildRequest");
error:
if (INVALID_HANDLE_VALUE != hInf)
{
myInfCloseFile(hInf);
}
if (NULL != pbSubjectEncoded)
{
myFree(pbSubjectEncoded, CERTLIB_USE_LOCALALLOC);
}
CSILOG(hr, IDS_LOG_CREATE_REQUEST, NULL, NULL, NULL);
return(hr);
}
HRESULT
BuildCAHierarchy(
HCRYPTPROV hProv,
PER_COMPONENT_DATA *pComp,
CRYPT_KEY_PROV_INFO const *pKeyProvInfo,
HWND hwnd)
{
HRESULT hr;
BYTE *pbRequest = NULL;
DWORD cbRequest;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
BSTR bStrChain = NULL;
if (!pServer->fSaveRequestAsFile)
{
// online case
if (NULL == pServer->pwszParentCAMachine ||
NULL == pServer->pwszParentCAName)
{
hr = E_POINTER;
_JumpError(hr, error, "Empty machine name or parent ca name");
}
}
// create request 1st
hr = CreateInitialCertificateRequest(
hProv,
pServer,
pComp,
hwnd,
&pbRequest,
&cbRequest);
if (S_OK != hr)
{
pComp->iErrMsg = IDS_ERR_BUILDCERTREQUEST;
_JumpError(hr, error, "CreateInitialCertificateRequest");
}
// save it to a file always
hr = EncodeToFileW(
pServer->pwszRequestFile,
pbRequest,
cbRequest,
DECF_FORCEOVERWRITE | CRYPT_STRING_BASE64REQUESTHEADER);
_JumpIfError(hr, error, "EncodeToFileW");
// register request file name always
hr = mySetCARegFileNameTemplate(
wszREGREQUESTFILENAME,
pComp->pwszServerName,
pServer->pwszSanitizedName,
pServer->pwszRequestFile);
_JumpIfErrorStr(hr, error, "mySetCARegFileNameTemplate", wszREGREQUESTFILENAME);
if (pServer->fSaveRequestAsFile)
{
// mark it as request file
hr = SetSetupStatus(
pServer->pwszSanitizedName,
SETUP_SUSPEND_FLAG | SETUP_REQUEST_FLAG,
TRUE);
_JumpIfError(hr, error, "SetSetupStatus");
// done if save as request file
goto done;
}
hr = csiSubmitCARequest(
pComp->hInstance,
pComp->fUnattended,
hwnd,
FALSE, // fRenew
FALSE, // fRetrievePending
pServer->pwszSanitizedName,
pServer->pwszParentCAMachine,
pServer->pwszParentCAName,
pbRequest,
cbRequest,
&bStrChain);
// in any case, you can finish setup from mmc
_JumpIfError(hr, done, "csiSubmitCARequest");
hr = csiFinishInstallationFromPKCS7(
pComp->hInstance,
pComp->fUnattended,
hwnd,
pServer->pwszSanitizedName,
pServer->pwszCACommonName,
pKeyProvInfo,
pServer->CAType,
CANAMEIDTOICERT(pServer->dwCertNameId),
CANAMEIDTOIKEY(pServer->dwCertNameId),
pServer->fUseDS,
FALSE, // fRenew
pComp->pwszServerName,
(BYTE *) bStrChain,
SysStringByteLen(bStrChain),
pServer->pwszCACertFile);
_JumpIfError(hr, error, "csiFinishInstallationFromPKCS7");
done:
hr = S_OK;
error:
if (NULL != pbRequest)
{
myFree(pbRequest, CERTLIB_USE_LOCALALLOC);
}
if (NULL != bStrChain)
{
SysFreeString(bStrChain);
}
return(hr);
}
// Find the newest CA cert that:
// - matches the passed Subject DN,
// - matches the passed cert index,
// - expires prior the next newer cert (compare to pNotAfter)
// - expires latest of all that match the above
// - has KeyProvInfo
// - key and cert can be used together to sign
HRESULT
SetCARegOldCertHashByIndex(
IN WCHAR const *pwszSanitizedName,
IN HCERTSTORE hStore,
IN WCHAR const *pwszDN,
IN DWORD iCert,
IN OUT FILETIME *pNotAfter)
{
HRESULT hr;
CERT_CONTEXT const *pCert = NULL;
CERT_CONTEXT const *pCertNewest = NULL;
WCHAR *pwszDNT = NULL;
DWORD dwProvType;
WCHAR *pwszProvName = NULL;
ALG_ID idAlg;
BOOL fMachineKeyset;
DWORD dwNameId;
DWORD cbKey;
CRYPT_KEY_PROV_INFO *pKey = NULL;
hr = myGetCertSrvCSP(
FALSE, // fEncryptionCSP
pwszSanitizedName,
&dwProvType,
&pwszProvName,
&idAlg,
&fMachineKeyset,
NULL); // pdwKeySize
_JumpIfError(hr, error, "myGetCertSrvCSP");
while (TRUE)
{
if (NULL != pKey)
{
LocalFree(pKey);
pKey = NULL;
}
if (NULL != pwszDNT)
{
LocalFree(pwszDNT);
pwszDNT = NULL;
}
pCert = CertEnumCertificatesInStore(hStore, pCert);
if (NULL == pCert)
{
break;
}
hr = myCertNameToStr(
X509_ASN_ENCODING,
&pCert->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
&pwszDNT);
if (S_OK != hr)
{
_PrintError(hr, "myCertNameToStr");
continue;
}
if (0 != lstrcmp(pwszDN, pwszDNT))
{
DBGPRINT((DBG_SS_CERTOCM, "Skipping cert: %ws\n", pwszDNT));
continue;
}
hr = myGetNameId(pCert, &dwNameId);
if (S_OK != hr ||
MAXDWORD == dwNameId ||
CANAMEIDTOICERT(dwNameId) != iCert)
{
DBGPRINT((DBG_SS_CERTOCM, "Skipping cert: NameId=%x\n", dwNameId));
continue;
}
DBGPRINT((DBG_SS_CERTOCM, "NameId=%x\n", dwNameId));
if (0 < CompareFileTime(&pCert->pCertInfo->NotAfter, pNotAfter))
{
DBGPRINT((DBG_SS_CERTOCM, "Skipping cert: too new\n"));
continue;
}
if (!myCertGetCertificateContextProperty(
pCert,
CERT_KEY_PROV_INFO_PROP_ID,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pKey,
&cbKey))
{
hr = myHLastError();
_PrintError(hr, "CertGetCertificateContextProperty");
continue;
}
hr = myValidateHashForSigning(
pKey->pwszContainerName,
pwszProvName,
dwProvType,
fMachineKeyset,
&pCert->pCertInfo->SubjectPublicKeyInfo,
idAlg);
if (S_OK != hr)
{
_PrintError(hr, "myValidateHashForSigning");
continue;
}
if (NULL != pCertNewest)
{
if (0 > CompareFileTime(
&pCert->pCertInfo->NotAfter,
&pCertNewest->pCertInfo->NotAfter))
{
DBGPRINT((DBG_SS_CERTOCM, "Skipping cert: not newest\n"));
continue;
}
CertFreeCertificateContext(pCertNewest);
pCertNewest = NULL;
}
pCertNewest = CertDuplicateCertificateContext(pCert);
if (NULL == pCertNewest)
{
hr = myHLastError();
_JumpError(hr, error, "CertDuplicateCertificate");
}
}
if (NULL == pCertNewest)
{
hr = CRYPT_E_NOT_FOUND;
_JumpError(hr, error, "CertEnumCertificatesInStore");
}
// mark as unarchived:
CertSetCertificateContextProperty(
pCertNewest,
CERT_ARCHIVED_PROP_ID,
0,
NULL);
hr = mySetCARegHash(pwszSanitizedName, CSRH_CASIGCERT, iCert, pCertNewest);
_JumpIfError(hr, error, "mySetCARegHash");
*pNotAfter = pCertNewest->pCertInfo->NotAfter;
error:
if (NULL != pKey)
{
LocalFree(pKey);
}
if (NULL != pwszDNT)
{
LocalFree(pwszDNT);
}
if (NULL != pwszProvName)
{
LocalFree(pwszProvName);
}
if (NULL != pCertNewest)
{
CertFreeCertificateContext(pCertNewest);
}
if (NULL != pCert)
{
CertFreeCertificateContext(pCert);
}
return(hr);
}
HRESULT
SetCARegOldCertHashes(
IN WCHAR const *pwszSanitizedName,
IN DWORD cCertOld,
IN CERT_CONTEXT const *pccCA)
{
HRESULT hr;
HCERTSTORE hMyStore = NULL;
DWORD i;
WCHAR *pwszDN = NULL;
FILETIME NotAfter;
if (0 != cCertOld)
{
hr = myCertNameToStr(
X509_ASN_ENCODING,
&pccCA->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
&pwszDN);
_JumpIfError(hr, error, "myCertNameToStr");
// open my store
hMyStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM_W,
X509_ASN_ENCODING,
NULL, // hProv
CERT_SYSTEM_STORE_LOCAL_MACHINE |
CERT_STORE_ENUM_ARCHIVED_FLAG,
wszMY_CERTSTORE);
if (NULL == hMyStore)
{
hr = myHLastError();
_JumpError(hr, error, "CertOpenStore");
}
NotAfter = pccCA->pCertInfo->NotAfter;
for (i = cCertOld; i > 0; i--)
{
hr = SetCARegOldCertHashByIndex(
pwszSanitizedName,
hMyStore,
pwszDN,
i - 1,
&NotAfter);
_PrintIfError(hr, "SetCARegOldCertHashByIndex");
}
}
hr = S_OK;
error:
if (NULL != pwszDN)
{
LocalFree(pwszDN);
}
if (NULL != hMyStore)
{
CertCloseStore(hMyStore, 0);
}
return(hr);
}
HRESULT
CreateCertificates(
IN OUT PER_COMPONENT_DATA *pComp,
IN HWND hwnd)
{
HRESULT hr;
HCRYPTPROV hCryptProv = NULL;
HCERTSTORE hStore = NULL;
CRYPT_KEY_PROV_INFO keyProvInfo;
WCHAR wszEnrollPath[MAX_PATH];
CERT_CONTEXT const *pccCA = NULL;
BYTE *pbEncoded = NULL;
WCHAR *pwszEnrollPath = NULL;
WCHAR *pwszDir = NULL;
WCHAR *pwszFolderPath = NULL;
DWORD dwSize;
wszEnrollPath[0] = L'\0';
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
ZeroMemory(&keyProvInfo, sizeof(keyProvInfo));
if (NULL == pServer->pwszKeyContainerName && pComp->fUnattended)
{
// create a new key if unattended
hr = csiGenerateCAKeys(
pServer->pwszSanitizedName,
pServer->pCSPInfo->pwszProvName,
pServer->pCSPInfo->dwProvType,
pServer->pCSPInfo->fMachineKeyset,
pServer->dwKeyLength,
pComp->hInstance,
pComp->fUnattended,
hwnd,
&pComp->CA.pServer->fKeyGenFailed);
if (S_OK != hr)
{
CertErrorMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_ERR_FATAL_GENKEY,
hr,
pServer->pwszSanitizedName);
_JumpIfError(hr, error, "csiGenerateCAKeys");
}
// now set this as the existing key
hr = SetKeyContainerName(pServer, pServer->pwszSanitizedName);
_JumpIfError(hr, error, "SetKeyContainerName");
}
hr = csiFillKeyProvInfo(
pServer->pwszKeyContainerName,
pServer->pCSPInfo->pwszProvName,
pServer->pCSPInfo->dwProvType,
pServer->pCSPInfo->fMachineKeyset,
&keyProvInfo);
_JumpIfError(hr, error, "csiFillKeyProvInfo");
// get csp handle
if (!myCertSrvCryptAcquireContext(
&hCryptProv,
pServer->pwszKeyContainerName,
pServer->pCSPInfo->pwszProvName,
pServer->pCSPInfo->dwProvType,
pComp->fUnattended? CRYPT_SILENT : 0, // query
pServer->pCSPInfo->fMachineKeyset))
{
hr = myHLastError();
_JumpError(hr, error, "myCertSrvCryptAcquireContext");
}
if (hCryptProv == NULL)
{
hr = E_HANDLE;
_JumpError(hr, error, "myCertSrvCryptAcquireContext");
}
// open certificate store
if (NULL == pServer->hMyStore)
{
pServer->hMyStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM_W,
X509_ASN_ENCODING,
NULL, // hProv
CERT_SYSTEM_STORE_LOCAL_MACHINE |
CERT_STORE_ENUM_ARCHIVED_FLAG,
wszMY_CERTSTORE);
if (NULL == pServer->hMyStore)
{
// no store exists, done
hr = myHLastError();
_JumpIfError(hr, error, "CertOpenStore");
}
}
if (NULL != pServer->pccExistingCert)
{
// reuse cert, mark unarchived
CertSetCertificateContextProperty(
pServer->pccExistingCert,
CERT_ARCHIVED_PROP_ID,
0,
NULL);
}
if (IsSubordinateCA(pServer->CAType) && NULL == pServer->pccExistingCert)
{
hr = BuildCAHierarchy(hCryptProv, pComp, &keyProvInfo, hwnd);
_JumpIfError(hr, error, "BuildCAHierarchy");
}
else
{
WCHAR const *pwszCertName;
DWORD cwc;
BuildPath(
wszEnrollPath,
ARRAYSIZE(wszEnrollPath),
pComp->pwszSystem32,
wszCERTENROLLSHAREPATH);
hr = csiBuildFileName(
wszEnrollPath,
pServer->pwszSanitizedName,
L".crt",
CANAMEIDTOICERT(pServer->dwCertNameId),
&pwszEnrollPath,
pComp->hInstance,
pComp->fUnattended,
NULL);
_JumpIfError(hr, error, "csiBuildFileName");
CSASSERT(NULL != pServer->pwszCACertFile);
pwszCertName = wcsrchr(pServer->pwszCACertFile, L'\\');
CSASSERT(NULL != pwszCertName);
cwc = SAFE_SUBTRACT_POINTERS(pwszCertName, pServer->pwszCACertFile);
pwszDir = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
if (NULL == pwszDir)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CopyMemory(pwszDir, pServer->pwszCACertFile, cwc * sizeof(WCHAR));
pwszDir[cwc] = L'\0';
hr = csiBuildFileName(
pwszDir,
pServer->pwszSanitizedName,
L".crt",
CANAMEIDTOICERT(pServer->dwCertNameId),
&pwszFolderPath,
pComp->hInstance,
pComp->fUnattended,
NULL);
_JumpIfError(hr, error, "csiBuildFileName");
// create and save a selfsigned root cert
hr = csiBuildAndWriteCert(
hCryptProv,
pServer,
pwszFolderPath,
pwszEnrollPath,
pServer->pccExistingCert, // if NULL, we will build a new cert
&pccCA,
wszCERTTYPE_CA,
pComp->hInstance,
pComp->fUnattended,
hwnd);
if (S_OK != hr)
{
CertErrorMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_ERR_BUILDCERT,
hr,
NULL);
_JumpError(hr, error, "csiBuildAndWriteCert");
}
hr = SetCARegOldCertHashes(
pServer->pwszSanitizedName,
CANAMEIDTOICERT(pServer->dwCertNameId),
pccCA);
_JumpIfError(hr, error, "SetCARegOldCertHashes");
hr = mySetCARegHash(
pServer->pwszSanitizedName,
CSRH_CASIGCERT,
CANAMEIDTOICERT(pServer->dwCertNameId),
pccCA);
_JumpIfError(hr, error, "mySetCARegHash");
hr = csiSaveCertAndKeys(pccCA, NULL, &keyProvInfo, pServer->CAType);
_JumpIfError(hr, error, "csiSaveCertAndKeys");
if (pServer->fUseDS)
{
hr = csiSetupCAInDS(
hwnd,
pComp->pwszServerName,
pServer->pwszSanitizedName,
pServer->pwszCACommonName,
NULL,
pServer->CAType,
CANAMEIDTOICERT(pServer->dwCertNameId),
CANAMEIDTOIKEY(pServer->dwCertNameId),
FALSE, // fRenew
pccCA);
_PrintIfError(hr, "csiSetupCAInDS");
if (hr == S_OK)
pServer->fSavedCAInDS = TRUE;
}
}
hr = S_OK;
error:
csiFreeKeyProvInfo(&keyProvInfo);
if (NULL != pbEncoded)
{
LocalFree(pbEncoded);
}
if (NULL != pwszDir)
{
LocalFree(pwszDir);
}
if (NULL != pwszFolderPath)
{
LocalFree(pwszFolderPath);
}
if (NULL != pwszEnrollPath)
{
LocalFree(pwszEnrollPath);
}
if (NULL != pccCA)
{
CertFreeCertificateContext(pccCA);
}
if (NULL != hCryptProv)
{
CryptReleaseContext(hCryptProv, 0);
}
CSILOG(hr, IDS_LOG_CREATE_CERTIFICATE, NULL, NULL, NULL);
return(hr);
}
HRESULT
StartCertsrvService(BOOL fSilent)
{
HRESULT hr;
SC_HANDLE hSCManager = NULL;
SC_HANDLE hSCCertsvc = NULL;
SERVICE_STATUS status;
DWORD dwAttempt;
BOOL fSawPending;
WCHAR const *apwszSilentArg[1] = {L"-s"};
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == hSCManager)
{
hr = myHLastError();
_JumpError(hr, error, "OpenSCManager");
}
hSCCertsvc = OpenService(
hSCManager,
wszSERVICE_NAME,
SERVICE_ALL_ACCESS);
if (NULL == hSCCertsvc)
{
hr = myHLastError();
_JumpErrorStr(hr, error, "OpenService", wszSERVICE_NAME);
}
// START the service
if (!StartService(hSCCertsvc,
fSilent ? 1 : 0,
fSilent ? apwszSilentArg : NULL))
{
hr = myHLastError();
_JumpErrorStr(hr, error, "StartService", wszSERVICE_NAME);
}
// get out after it is really started
fSawPending = FALSE;
for (dwAttempt = 0; dwAttempt < CERT_MAX_ATTEMPT; dwAttempt++)
{
DBGCODE(status.dwCurrentState = -1);
if (!QueryServiceStatus(hSCCertsvc, &status))
{
// query failed, ignore error
hr = S_OK;
_JumpErrorStr(
myHLastError(), // Display ignored error
error,
"QueryServiceStatus",
wszSERVICE_NAME);
}
if (SERVICE_START_PENDING != status.dwCurrentState &&
SERVICE_STOPPED != status.dwCurrentState)
{
// it was started already
break;
}
DBGPRINT((
DBG_SS_CERTOCM,
"Starting %ws service: current state=%d\n",
wszSERVICE_NAME,
status.dwCurrentState));
if (fSawPending && SERVICE_STOPPED == status.dwCurrentState)
{
hr = HRESULT_FROM_WIN32(ERROR_SERVICE_NEVER_STARTED);
_JumpErrorStr(
hr,
error,
"Service won't start",
wszSERVICE_NAME);
}
if (SERVICE_START_PENDING == status.dwCurrentState)
{
fSawPending = TRUE;
}
Sleep(CERT_HALF_SECOND);
}
if (dwAttempt >= CERT_MAX_ATTEMPT)
{
DBGPRINT((
DBG_SS_CERTOCM,
"Timeout starting %ws service: current state=%d\n",
wszSERVICE_NAME,
status.dwCurrentState));
}
else
{
DBGPRINT((
DBG_SS_CERTOCM,
"Started %ws service\n",
wszSERVICE_NAME));
}
hr = S_OK;
error:
if (NULL != hSCCertsvc)
{
CloseServiceHandle(hSCCertsvc);
}
if (NULL != hSCManager)
{
CloseServiceHandle(hSCManager);
}
CSILOG(hr, IDS_LOG_START_SERVICE, NULL, NULL, NULL);
return(hr);
}
HRESULT
EnforceCertFileExtensions(
PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
WCHAR *pwszTmp = NULL;
WCHAR *pwszSuffix;
BOOL fAppendExtension = TRUE;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
if (NULL == pServer->pwszCACertFile)
{
// no ca cert file
goto done;
}
// make enough to hold extra extension crt
pwszTmp = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pServer->pwszCACertFile) + 5) * sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, pwszTmp);
wcscpy(pwszTmp, pServer->pwszCACertFile);
// check to make sure our self-signed file has the right extension
// Is there an extension?
pwszSuffix = wcsrchr(pwszTmp, L'.');
if (NULL != pwszSuffix)
{
// Is the stuff after the '.' already a 'crt' extension?
if (0 == lstrcmpi(pwszSuffix, L".crt"))
{
fAppendExtension = FALSE;
}
else if (pwszSuffix[1] == L'\0') // Is '.' last character?
{
while (pwszSuffix >= pwszTmp && *pwszSuffix == L'.')
{
*pwszSuffix-- = L'\0';
}
}
}
if (fAppendExtension)
{
// Apply the extension
wcscat(pwszTmp, L".crt");
// free old one
LocalFree(pServer->pwszCACertFile);
pServer->pwszCACertFile = pwszTmp;
pwszTmp = NULL;
}
done:
hr = S_OK;
error:
if (NULL != pwszTmp)
{
LocalFree(pwszTmp);
}
return(hr);
}
HRESULT
PrepareEDBDirectory(
HWND hwnd,
PER_COMPONENT_DATA *pComp,
WCHAR const *pwszDir)
{
HRESULT hr;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
DWORD dwAttr = GetFileAttributes(pwszDir);
if(MAXDWORD==dwAttr)
{
// file not found or other error
hr = myHLastError();
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpError(hr, error, "CreateDirectory");
}
hr = S_OK;
if (!CreateDirectory(pwszDir, NULL))
{
hr = myHLastError();
_JumpError(hr, error, "CreateDirectory");
}
}
if(!(dwAttr&FILE_ATTRIBUTE_DIRECTORY))
{
// file already exists but it's not a directory
hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
_JumpError(hr, error, "CreateDirectory");
}
if (!pServer->fPreserveDB)
{
hr = myDeleteDBFilesInDir(pwszDir);
_JumpIfError(hr, error, "myDeleteDBFilesInDir");
}
hr = S_OK;
error:
if(S_OK != hr)
{
CertErrorMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
0,
hr,
L""); // only message is the system error message
}
return(hr);
}
//--------------------------------------------------------------------
// Create the web configuration files
HRESULT
CreateCertWebIncPages(
IN HWND hwnd,
IN PER_COMPONENT_DATA *pComp,
IN BOOL bIsServer,
IN BOOL fUpgrade)
{
HRESULT hr;
CSASSERT(NULL != pComp);
// create the web configuration file
hr = CreateCertWebDatIncPage(pComp, bIsServer);
_JumpIfError(hr, error, "CreateCertWebDatIncPage");
error:
CSILOG(hr, IDS_LOG_WEB_INCLUDE, NULL, NULL, NULL);
return hr;
}
//--------------------------------------------------------------------
HRESULT
EnableVRootsAndShares(
IN BOOL fFileSharesOnly,
IN BOOL fUpgrade,
IN BOOL fServer,
IN PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
DWORD Flags = VFF_CREATEFILESHARES |
VFF_SETREGFLAGFIRST |
VFF_SETRUNONCEIFERROR |
VFF_CLEARREGFLAGIFOK;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
CSASSERT(!fServer || NULL != pServer);
CSASSERT(fServer || NULL != pComp->CA.pClient);
if (!fFileSharesOnly)
{
Flags |= VFF_CREATEVROOTS;
}
// if NT GUI mode (base setup) VRoot creation will fail during setup
// because IIS is not yet operational. Make a mark in the registry
// to try this on NEXT service startup or via runonce.
hr = myModifyVirtualRootsAndFileShares(
Flags,
fServer? pServer->CAType : pComp->CA.pClient->WebCAType,
FALSE, // synchronous -- blocking call
VFCSEC_TIMEOUT,
NULL,
NULL);
_JumpIfError(hr, error, "myModifyVirtualRootsAndFileShares");
if (!fUpgrade)
{
pServer->fCreatedShare = TRUE;
if (!fFileSharesOnly)
{
pComp->fCreatedVRoot = TRUE;
}
}
error:
return(hr);
}
HRESULT
DisableVRootsAndShares(
IN BOOL fVRoot,
IN BOOL fFileShares)
{
HRESULT hr;
DWORD Flags = 0;
if (fVRoot)
{
Flags |= VFF_DELETEVROOTS;
}
if (fFileShares)
{
Flags |= VFF_DELETEFILESHARES;
}
if (0 == Flags)
{
goto done;
}
hr = myModifyVirtualRootsAndFileShares(
Flags,
ENUM_UNKNOWN_CA,
FALSE, // synchronous -- blocking call
VFCSEC_TIMEOUT,
NULL,
NULL);
_JumpIfError(hr, error, "myModifyVirtualRootsAndFileShares");
done:
hr = S_OK;
error:
return(hr);
}
HRESULT
InstallClient(
HWND hwnd,
PER_COMPONENT_DATA *pComp)
{
BOOL fCoInit = FALSE;
HRESULT hr;
hr = CoInitialize(NULL);
if (S_OK != hr && S_FALSE != hr)
{
_JumpError(hr, error, "CoInitialize");
}
fCoInit = TRUE;
certocmBumpGasGauge(pComp, 10 DBGPARM(L"InstallClient"));
hr = CreateWebClientRegEntries(FALSE, pComp);
_JumpIfError(hr, error, "CreateWebClientRegEntries");
certocmBumpGasGauge(pComp, 30 DBGPARM(L"InstallClient"));
hr = RegisterAndUnRegisterDLLs(RD_CLIENT, pComp, hwnd);
_JumpIfError(hr, error, "RegisterAndUnRegisterDLLs");
certocmBumpGasGauge(pComp, 50 DBGPARM(L"InstallClient"));
DeleteProgramGroups(FALSE, pComp);
hr = CreateProgramGroups(TRUE, pComp, hwnd);
_JumpIfError(hr, error, "CreateProgramGroups");
certocmBumpGasGauge(pComp, 70 DBGPARM(L"InstallClient"));
hr = CreateCertWebIncPages(hwnd, pComp, FALSE /*IsServer*/, FALSE);
_JumpIfError(hr, error, "CreateCertWebIncPages");
hr = RenameMiscTargets(hwnd, pComp, FALSE);
_JumpIfError(hr, error, "RenameMiscTargets");
certocmBumpGasGauge(pComp, 80 DBGPARM(L"InstallClient"));
hr = EnableVRootsAndShares(FALSE, FALSE, FALSE, pComp);
_JumpIfError(hr, error, "EnableVRootsAndShares");
certocmBumpGasGauge(pComp, 100 DBGPARM(L"InstallClient"));
error:
if (fCoInit)
{
CoUninitialize();
}
CSILOG(hr, IDS_LOG_INSTALL_CLIENT, NULL, NULL, NULL);
return(hr);
}
HRESULT
RemoveWebClientRegEntries(VOID)
{
HRESULT hr;
hr = myDeleteCertRegValue(NULL, NULL, NULL, wszREGWEBCLIENTCAMACHINE);
_PrintIfError(hr, "myDeleteCertRegValue");
hr = myDeleteCertRegValue(NULL, NULL, NULL, wszREGWEBCLIENTCANAME);
_PrintIfError(hr, "myDeleteCertRegValue");
hr = myDeleteCertRegValue(NULL, NULL, NULL, wszREGWEBCLIENTCATYPE);
_PrintIfError(hr, "myDeleteCertRegValue");
hr = S_OK;
//error:
return hr;
}
HRESULT
InstallServer(
HWND hwnd,
PER_COMPONENT_DATA *pComp)
{
BOOL fCoInit = FALSE;
WCHAR *pwszDBFile = NULL;
DWORD dwSetupStatus;
HRESULT hr = pComp->hrContinue;
int ret;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
WCHAR *pwszConfig = NULL;
BOOL fSetDSSecurity;
_JumpIfError(hr, error, "can't continue");
hr = UpdateDomainAndUserName(hwnd, pComp);
_JumpIfError(hr, error, "UpdateDomainAndUserName");
hr = CoInitialize(NULL);
if (S_OK != hr && S_FALSE != hr)
{
_JumpError(hr, error, "CoInitialize");
}
fCoInit = TRUE;
hr = EnforceCertFileExtensions(pComp);
_JumpIfError(hr, error, "EnforceCertFileExtensions");
hr = PrepareEDBDirectory(hwnd, pComp, pServer->pwszDBDirectory);
_JumpIfError(hr, error, "PrepareEDBDirectory");
hr = PrepareEDBDirectory(hwnd, pComp, pServer->pwszLogDirectory);
_JumpIfError(hr, error, "PrepareEDBDirectory");
certocmBumpGasGauge(pComp, 10 DBGPARM(L"InstallServer"));
// alway uninstall before install
PreUninstallCore(hwnd, pComp, FALSE);
UninstallCore(hwnd, pComp, 10, 30, FALSE, FALSE, FALSE);
hr = CreateServerRegEntries(hwnd, FALSE, pComp);
_JumpIfError(hr, error, "CreateServerRegEntries");
if ((IS_SERVER_INSTALL & pComp->dwInstallStatus) &&
(IS_CLIENT_UPGRADE & pComp->dwInstallStatus))
{
// case of install server only and keep web client
// remove parent ca config info of the old web client
hr = RemoveWebClientRegEntries();
_PrintIfError(hr, "RemoveWebClientRegEntries");
}
certocmBumpGasGauge(pComp, 35 DBGPARM(L"InstallServer"));
hr = RegisterAndUnRegisterDLLs(RD_SERVER, pComp, hwnd);
_JumpIfError(hr, error, "RegisterAndUnRegisterDLLs");
certocmBumpGasGauge(pComp, 40 DBGPARM(L"InstallServer"));
hr = CreateCertificateService(pComp, hwnd);
_JumpIfError(hr, error, "CreateCertificateService");
certocmBumpGasGauge(pComp, 45 DBGPARM(L"InstallServer"));
hr = CreateCertificates(pComp, hwnd);
_JumpIfError(hr, error, "CreateCertificates");
certocmBumpGasGauge(pComp, 50 DBGPARM(L"InstallServer"));
hr = CreateProgramGroups(FALSE, pComp, hwnd);
_JumpIfError(hr, error, "CreateProgramGroups");
certocmBumpGasGauge(pComp, 60 DBGPARM(L"InstallServer"));
hr = CreateCertWebIncPages(hwnd, pComp, TRUE /*IsServer*/, FALSE);
_JumpIfError(hr, error, "CreateCertWebIncPages");
hr = RenameMiscTargets(hwnd, pComp, TRUE);
_JumpIfError(hr, error, "RenameMiscTargets");
certocmBumpGasGauge(pComp, 70 DBGPARM(L"InstallServer"));
hr = RegisterDcomServer(
CLSID_CCertRequestD,
wszREQUESTFRIENDLYNAME,
wszREQUESTVERINDPROGID,
wszREQUESTPROGID);
_JumpIfError(hr, error, "RegisterDcomServer");
hr = RegisterDcomServer(
CLSID_CCertAdminD,
wszADMINFRIENDLYNAME,
wszADMINVERINDPROGID,
wszADMINPROGID);
_JumpIfError(hr, error, "RegisterDcomServer");
certocmBumpGasGauge(pComp, 80 DBGPARM(L"InstallServer"));
hr = RegisterDcomApp(CLSID_CCertRequestD);
_JumpIfError(hr, error, "RegisterDcomApp");
certocmBumpGasGauge(pComp, 90 DBGPARM(L"InstallServer"));
if (pServer->fUseDS)
{
hr = AddCAMachineToCertPublishers();
_JumpIfError(hr, error, "AddCAMachineToCertPublishers");
hr = InitializeCertificateTemplates();
_JumpIfError(hr, error, "InitializeCertificateTemplates");
}
certocmBumpGasGauge(pComp, 95 DBGPARM(L"InstallServer"));
// Set the security locally.
// A SubCA sets security when it receives its certificate from
// its parent. ALL OTHER CA installs (Root & reuse of existing certs)
// need to have security set now.
// On a SubCA the DS object security will have been set
// by a previous call in initlib if we already got our cert, or it will
// be set later when we install our cert.
// However, root certs install doesn't run completefrompkcs7(), so
// ds security on ent roots is never set. We must set it here.
// TODO: set security properly at DS object creation time!
fSetDSSecurity = (IsRootCA(pServer->CAType) || pServer->pccExistingCert);
hr = csiInitializeCertSrvSecurity(
pServer->pwszSanitizedName,
pServer->fUseDS,
fSetDSSecurity? pServer->fUseDS : FALSE); // clean SUBCA: happens during cert install, ROOT & reuse cert: apply now
_JumpIfError(hr, error, "csiInitializeCertSrvSecurity");
hr = GetSetupStatus(pServer->pwszSanitizedName, &dwSetupStatus);
if (S_OK == hr)
{
if (IsSubordinateCA(pServer->CAType) &&
(SETUP_SUSPEND_FLAG & dwSetupStatus) &&
(SETUP_REQUEST_FLAG & dwSetupStatus))
{
// put out an info dlg
CertInfoMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_INCOMPLETE_REQUEST,
pServer->pwszRequestFile);
}
}
else
{
_PrintError(hr, "GetSetupStatus");
}
certocmBumpGasGauge(pComp, 100 DBGPARM(L"InstallServer"));
hr = S_OK;
error:
if (NULL != pwszConfig)
{
LocalFree(pwszConfig);
}
if (NULL != pwszDBFile)
{
LocalFree(pwszDBFile);
}
if (fCoInit)
{
CoUninitialize();
}
CSILOG(hr, IDS_LOG_INSTALL_SERVER, NULL, NULL, NULL);
return(hr);
}
HRESULT
CreateCertsrvDirectories(
IN PER_COMPONENT_DATA *pComp,
IN BOOL fUpgrade,
IN BOOL fServer)
{
HRESULT hr;
WCHAR wszCertEnroll[MAX_PATH];
wszCertEnroll[0] = L'\0';
BuildPath(
wszCertEnroll,
ARRAYSIZE(wszCertEnroll),
pComp->pwszSystem32,
wszCERTENROLLSHAREPATH);
if (0 == CreateDirectory(wszCertEnroll, NULL))
{
hr = myHLastError();
if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) != hr)
{
_JumpErrorStr(hr, error, "CreateDirectory", wszCertEnroll);
}
}
if (fServer && NULL != pComp->CA.pServer->pwszSharedFolder)
{
if (pComp->fUnattended && !fUpgrade)
{
// make sure shared folder is created
if (!CreateDirectory(pComp->CA.pServer->pwszSharedFolder, NULL))
{
hr = myHLastError();
if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) != hr)
{
_JumpErrorStr(hr, error, "CreateDirectory",
pComp->CA.pServer->pwszSharedFolder);
}
}
}
if (!fUpgrade)
{
// set security on shared folder to
// FULL: Admins, LocalSystem, DomainAdmins
// READ: Everyone
// NOTE: in upgrade path, the system doesn't enable file share yet
// so skip the call
hr = csiSetAdminOnlyFolderSecurity(
pComp->CA.pServer->pwszSharedFolder,
TRUE, // apply Everyone:READ
pComp->CA.pServer->fUseDS);
_JumpIfError(hr, error, "csiSetAdminOnlyFolderSecurity");
}
}
hr = S_OK;
error:
return hr;
}
// following remove unused file/directory/registry
#define wszOLDHELP L"..\\help\\"
#define wszOLDCERTADM L"\\certadm"
#define wszOLDCERTQUE L"\\certque"
VOID
DeleteOldFilesAndDirectories(
IN PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
WCHAR wszPath[MAX_PATH];
WCHAR *pwszCertsrv;
wszPath[0] = L'\0';
// old help dir path
wcscpy(wszPath, pComp->pwszSystem32);
wcscat(wszPath, wszOLDHELP);
wcscat(wszPath, wszCERTSRV);
// remove old help files
hr = myRemoveFilesAndDirectory(wszPath, TRUE);
_PrintIfErrorStr(hr, "myRemoveFilesAndDirectory", wszPath);
// point to system32\certsrv
wcscpy(wszPath, pComp->pwszSystem32);
wcscat(wszPath, wszCERTSRV);
pwszCertsrv = &wszPath[wcslen(wszPath)];
// old vroot dir path
wcscpy(pwszCertsrv, wszOLDCERTADM);
hr = myRemoveFilesAndDirectory(wszPath, TRUE);
_PrintIfErrorStr(hr, "myRemoveFilesAndDirectory", wszPath);
wcscpy(pwszCertsrv, wszOLDCERTQUE);
hr = myRemoveFilesAndDirectory(wszPath, TRUE);
_PrintIfErrorStr(hr, "myRemoveFilesAndDirectory", wszPath);
// delete some obsolete registry keys and values
// old doc sub-component
hr = myDeleteCertRegValueEx(wszREGKEYOCMSUBCOMPONENTS,
NULL,
NULL,
wszOLDDOCCOMPONENT,
TRUE); //absolute path,
_PrintIfErrorStr2(hr, "myDeleteCertRegValueEx", wszOLDDOCCOMPONENT, hr);
// old CA cert serial number
if (NULL != pComp->CA.pServer &&
NULL != pComp->CA.pServer->pwszSanitizedName)
{
hr = myDeleteCertRegValue(
pComp->CA.pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCASERIALNUMBER);
_PrintIfErrorStr2(hr, "myDeleteCertRegValue", wszREGCASERIALNUMBER, hr);
}
}
VOID
DeleteObsoleteResidue()
{
HRESULT hr;
hr = myDeleteCertRegValueEx(wszREGKEYKEYSNOTTORESTORE,
NULL,
NULL,
wszREGRESTORECERTIFICATEAUTHORITY,
TRUE); //absolute path,
_PrintIfErrorStr(hr, "myDeleteCertRegValueEx",
wszREGRESTORECERTIFICATEAUTHORITY);
hr = myDeleteCertRegValueEx(wszREGKEYFILESNOTTOBACKUP,
NULL,
NULL,
wszREGRESTORECERTIFICATEAUTHORITY,
TRUE); //absolute path,
_PrintIfErrorStr(hr, "myDeleteCertRegValueEx",
wszREGRESTORECERTIFICATEAUTHORITY);
}
HRESULT
InstallCore(
IN HWND hwnd,
IN PER_COMPONENT_DATA *pComp,
IN BOOL fServer)
{
HRESULT hr = pComp->hrContinue;
_JumpIfError(hr, error, "can't continue");
hr = CreateCertsrvDirectories(pComp, FALSE, fServer);
_JumpIfError(hr, error, "CreateCertsrvDirectories");
// Trigger an autoenroll to download root certs (see bug# 341568)
if(IsEnterpriseCA(pComp->CA.pServer->CAType))
{
hr = TriggerAutoenrollment();
_JumpIfError(hr, error, "TriggerAutoenrollment");
}
if (fServer)
{
hr = InstallServer(hwnd, pComp);
_JumpIfError(hr, error, "InstallServer");
}
else
{
hr = InstallClient(hwnd, pComp);
_JumpIfError(hr, error, "InstallClient");
}
if (g_fW3SvcRunning)
{
hr = StartAndStopService(pComp->hInstance,
pComp->fUnattended,
hwnd,
wszW3SVCNAME,
FALSE,
FALSE,
0, //doesn't matter since no confirm
&g_fW3SvcRunning);
_PrintIfError(hr, "StartAndStopService");
}
DeleteOldFilesAndDirectories(pComp);
hr = S_OK;
error:
return(hr);
}
HRESULT
BuildMultiStringList(
IN WCHAR const * const *apwsz,
IN DWORD cpwsz,
OUT WCHAR **ppwszz)
{
HRESULT hr;
DWORD i;
DWORD cwc;
WCHAR *pwc;
WCHAR *apwszEmpty[] = { L"", };
if (0 == cpwsz)
{
cpwsz = ARRAYSIZE(apwszEmpty);
apwsz = apwszEmpty;
}
cwc = 1;
for (i = 0; i < cpwsz; i++)
{
cwc += wcslen(apwsz[i]) + 1;
}
*ppwszz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, *ppwszz);
pwc = *ppwszz;
for (i = 0; i < cpwsz; i++)
{
wcscpy(pwc, apwsz[i]);
pwc += wcslen(pwc) + 1;
}
*pwc = L'\0';
CSASSERT(SAFE_SUBTRACT_POINTERS(pwc, *ppwszz) + 1 == cwc);
hr = S_OK;
error:
return(hr);
}
HRESULT
helperGetDisableExtensionList(
PER_COMPONENT_DATA *pComp,
OUT WCHAR **ppwszz)
{
HRESULT hr;
WCHAR *apwszExt[] = {
L"", // C compiler won't allow empty list
//TEXT(szOID_ENROLL_CERTTYPE_EXTENSION), // 1.3.6.1.4.1.311.20.2
};
hr = BuildMultiStringList(apwszExt, ARRAYSIZE(apwszExt), ppwszz);
_JumpIfError(hr, error, "BuildMultiStringList");
error:
return(hr);
}
HRESULT
helperGetRequestExtensionList(
PER_COMPONENT_DATA *pComp,
OUT WCHAR **ppwszz)
{
HRESULT hr;
WCHAR *apwszExt[] = {
TEXT(szOID_RSA_SMIMECapabilities), // 1.2.840.113549.1.9.15
TEXT(szOID_CROSS_CERT_DIST_POINTS), // 1.3.6.1.4.1.311.10.9.1
TEXT(szOID_ENROLL_CERTTYPE_EXTENSION), // 1.3.6.1.4.1.311.20.2
TEXT(szOID_CERTSRV_CA_VERSION), // 1.3.6.1.4.1.311.21.1
TEXT(szOID_CERTSRV_PREVIOUS_CERT_HASH), // 1.3.6.1.4.1.311.21.2
TEXT(szOID_CERTIFICATE_TEMPLATE), // 1.3.6.1.4.1.311.21.7
TEXT(szOID_APPLICATION_CERT_POLICIES), // 1.3.6.1.4.1.311.21.10
TEXT(szOID_APPLICATION_POLICY_MAPPINGS), // 1.3.6.1.4.1.311.21.11
TEXT(szOID_APPLICATION_POLICY_CONSTRAINTS), // 1.3.6.1.4.1.311.21.12
TEXT(szOID_KEY_USAGE), // 2.5.29.15
TEXT(szOID_SUBJECT_ALT_NAME2), // 2.5.29.17
TEXT(szOID_NAME_CONSTRAINTS), // 2.5.29.30
TEXT(szOID_CERT_POLICIES), // 2.5.29.32
TEXT(szOID_POLICY_MAPPINGS), // 2.5.29.33
TEXT(szOID_POLICY_CONSTRAINTS), // 2.5.29.36
TEXT(szOID_ENHANCED_KEY_USAGE), // 2.5.29.37
};
hr = BuildMultiStringList(apwszExt, ARRAYSIZE(apwszExt), ppwszz);
_JumpIfError(hr, error, "BuildMultiStringList");
error:
return(hr);
}
HRESULT
FindCACertByCommonNameAndSerialNumber(
IN HCERTSTORE hCAStore,
IN WCHAR const *pwszCommonName,
IN BYTE const *pbSerialNumber,
IN DWORD cbSerialNumber,
CERT_CONTEXT const **ppCACert)
{
HRESULT hr;
CERT_RDN_ATTR rdnAttr = { szOID_COMMON_NAME, CERT_RDN_ANY_TYPE,};
CERT_RDN rdn = { 1, &rdnAttr };
CRYPT_INTEGER_BLOB SerialNumber;
CERT_CONTEXT const *pCACert = NULL;
CSASSERT(NULL != hCAStore &&
NULL != pwszCommonName &&
NULL != pbSerialNumber &&
NULL != ppCACert);
*ppCACert = NULL;
rdnAttr.Value.pbData = (BYTE *) pwszCommonName;
rdnAttr.Value.cbData = 0;
pCACert = NULL;
SerialNumber.pbData = const_cast<BYTE *>(pbSerialNumber);
SerialNumber.cbData = cbSerialNumber;
while (TRUE)
{
pCACert = CertFindCertificateInStore(
hCAStore,
X509_ASN_ENCODING,
CERT_UNICODE_IS_RDN_ATTRS_FLAG |
CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG,
CERT_FIND_SUBJECT_ATTR,
&rdn,
pCACert);
if (NULL == pCACert)
{
hr = myHLastError();
_JumpError(hr, error, "CertFindCertificateInStore");
}
if (myAreSerialNumberBlobsSame(
&SerialNumber,
&pCACert->pCertInfo->SerialNumber))
{
break; // found correct one
}
}
*ppCACert = pCACert;
pCACert = NULL;
hr = S_OK;
error:
if (NULL != pCACert)
{
CertFreeCertificateContext(pCACert);
}
return hr;
}
HRESULT
GetCARegSerialNumber(
IN WCHAR const *pwszSanitizedCAName,
OUT BYTE **ppbSerialNumber,
OUT DWORD *pcbSerialNumber)
{
HRESULT hr;
WCHAR *pwszSerialNumber = NULL;
BYTE *pbSN = NULL;
DWORD cbSN;
hr = myGetCertRegStrValue(
pwszSanitizedCAName,
NULL,
NULL,
wszREGCASERIALNUMBER,
&pwszSerialNumber);
_JumpIfErrorStr2(
hr,
error,
"myGetCertRegStrValue",
wszREGCASERIALNUMBER,
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
hr = WszToMultiByteInteger(FALSE, pwszSerialNumber, &cbSN, &pbSN);
_JumpIfError(hr, error, "WszToMultiByteInteger");
*ppbSerialNumber = pbSN;
pbSN = NULL;
*pcbSerialNumber = cbSN;
error:
if (NULL != pwszSerialNumber)
{
LocalFree(pwszSerialNumber);
}
if (NULL != pbSN)
{
LocalFree(pbSN);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
LoadCurrentCACert(
IN WCHAR const *pwszCommonName,
IN WCHAR const *pwszSanitizedName,
IN BOOL fSignTest,
OUT CERT_CONTEXT const **ppcc,
OUT DWORD *pdwNameId)
{
HRESULT hr;
DWORD Count;
HCERTSTORE hMyStore = NULL;
BYTE *pbSerialNumber = NULL;
DWORD cbSerialNumber;
CRYPT_KEY_PROV_INFO *pKey = NULL;
DWORD cbKey;
DWORD dwType;
CERT_CONTEXT const *pcc = NULL;
WCHAR *pwszProvName = NULL;
DWORD dwProvType;
ALG_ID idAlg;
BOOL fMachineKeyset;
*ppcc = NULL;
// get prov name
hr = myGetCertSrvCSP(
FALSE, // fEncryptionCSP
pwszSanitizedName,
&dwProvType,
&pwszProvName,
&idAlg,
&fMachineKeyset,
NULL); // pdwKeySize
_JumpIfError(hr, error, "myGetCertSrvCSP");
// open my store
hMyStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM_W,
X509_ASN_ENCODING,
NULL, // hProv
CERT_SYSTEM_STORE_LOCAL_MACHINE |
CERT_STORE_ENUM_ARCHIVED_FLAG,
wszMY_CERTSTORE);
if (NULL == hMyStore)
{
hr = myHLastError();
_JumpError(hr, error, "CertOpenStore");
}
hr = myGetCARegHashCount(pwszSanitizedName, CSRH_CASIGCERT, &Count);
_JumpIfError(hr, error, "myGetCARegHashCount");
if (0 == Count)
{
*pdwNameId = 0; // renewal wasn't implemented yet
// find current CA cert by serial number -- the old fashioned way
hr = GetCARegSerialNumber(
pwszSanitizedName,
&pbSerialNumber,
&cbSerialNumber);
_JumpIfError(hr, error, "GetCARegSerialNumber");
hr = FindCACertByCommonNameAndSerialNumber(
hMyStore,
pwszCommonName,
pbSerialNumber,
cbSerialNumber,
&pcc);
_JumpIfError(hr, error, "FindCACertByCommonNameAndSerialNumber");
}
else
{
hr = myFindCACertByHashIndex(
hMyStore,
pwszSanitizedName,
CSRH_CASIGCERT,
Count - 1,
pdwNameId,
&pcc);
_JumpIfError(hr, error, "myFindCACertByHashIndex");
}
// get the private key provider info
if (!myCertGetCertificateContextProperty(
pcc,
CERT_KEY_PROV_INFO_PROP_ID,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pKey,
&cbKey))
{
hr = myHLastError();
_JumpError(hr, error, "CertGetCertificateContextProperty");
}
if (fSignTest)
{
// signing testing
hr = myValidateHashForSigning(
pKey->pwszContainerName,
pwszProvName,
dwProvType,
fMachineKeyset,
&pcc->pCertInfo->SubjectPublicKeyInfo,
idAlg);
_JumpIfError(hr, error, "myValidateHashForSigning");
}
*ppcc = pcc;
pcc = NULL;
hr = S_OK;
error:
if (NULL != hMyStore)
{
CertCloseStore(hMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
if (NULL != pbSerialNumber)
{
LocalFree(pbSerialNumber);
}
if (NULL != pKey)
{
LocalFree(pKey);
}
if (NULL != pwszProvName)
{
LocalFree(pwszProvName);
}
if (NULL != pcc)
{
CertFreeCertificateContext(pcc);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
ArchiveCACertificate(
IN WCHAR const *pwszSanitizedName)
{
HRESULT hr;
HCERTSTORE hMyStore = NULL;
DWORD Count;
DWORD i;
CERT_CONTEXT const *pCert = NULL;
DWORD dwNameId;
CRYPT_DATA_BLOB Archived;
// open my store
hMyStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM_W,
X509_ASN_ENCODING,
NULL, // hProv
CERT_SYSTEM_STORE_LOCAL_MACHINE,
wszMY_CERTSTORE);
if (NULL == hMyStore)
{
hr = myHLastError();
_JumpError(hr, error, "CertOpenStore");
}
hr = myGetCARegHashCount(pwszSanitizedName, CSRH_CASIGCERT, &Count);
_JumpIfError(hr, error, "myGetCARegHashCount");
for (i = 0; i < Count; i++)
{
hr = myFindCACertByHashIndex(
hMyStore,
pwszSanitizedName,
CSRH_CASIGCERT,
i,
&dwNameId,
&pCert);
_PrintIfError(hr, "myFindCACertByHashIndex");
if (S_OK == hr)
{
Archived.cbData = 0;
Archived.pbData = NULL;
// We force an archive on the old cert and close it.
CertSetCertificateContextProperty(
pCert,
CERT_ARCHIVED_PROP_ID,
0,
&Archived);
CertFreeCertificateContext(pCert);
pCert = NULL;
}
}
hr = S_OK;
error:
if (NULL != pCert)
{
CertFreeCertificateContext(pCert);
}
if (NULL != hMyStore)
{
CertCloseStore(hMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
// determine CA info, from build to build upgrade
HRESULT
DetermineCAInfoAndType(
PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
ENUM_CATYPES CATypeDummy;
WCHAR *pwszCommonName = NULL;
CERT_CONTEXT const *pCACert = NULL;
DWORD dwNameId;
// ca type
hr = myGetCertRegDWValue(
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCATYPE,
(DWORD *) &CATypeDummy);
if (S_OK == hr)
{
pServer->CAType = CATypeDummy;
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpErrorStr(hr, error, "myGetCertRegDWValue", wszREGCATYPE);
}
// else keep default CAType flag
// get current ca common name
hr = myGetCertRegStrValue(
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCOMMONNAME,
&pwszCommonName);
_JumpIfErrorStr(hr, error, "myGetCertRegStrValue", wszREGCOMMONNAME);
hr = LoadCurrentCACert(
pwszCommonName,
pServer->pwszSanitizedName,
FALSE, // don't do signing test during upgrade
&pCACert,
&pServer->dwCertNameId);
_JumpIfError(hr, error, "LoadCurrentCACert");
// now ready to load DN info
hr = DetermineExistingCAIdInfo(pServer, pCACert);
_JumpIfError(hr, error, "DetermineExistingCAIdInfo");
if (NULL != pServer->pccUpgradeCert)
{
CertFreeCertificateContext(pServer->pccUpgradeCert);
}
pServer->pccUpgradeCert = pCACert;
pCACert = NULL;
error:
if (NULL != pwszCommonName)
{
LocalFree(pwszCommonName);
}
if (NULL != pCACert)
{
CertFreeCertificateContext(pCACert);
}
return(hr);
}
// the following will determine ca sanitized name and upgrade path
HRESULT
DetermineServerUpgradePath(
IN OUT PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
WCHAR *pwszDummy = NULL;
WCHAR *pwszSanitizedCAName = NULL;
LPWSTR pwszB2PolicyGuid = NULL;
DWORD dwVersion;
if (CS_UPGRADE_UNKNOWN != pComp->UpgradeFlag)
{
// already know upgrade type
CSASSERT(pServer->pwszSanitizedName); // this is a side-effect of this fxn, better have been set already
return S_OK;
}
// get active ca name
hr = myGetCertRegStrValue(
NULL,
NULL,
NULL,
wszREGACTIVE,
&pwszSanitizedCAName);
if (hr != S_OK)
{
BOOL fFinishCYS;
//for W2K after, it is possible to be in post mode
hr = CheckPostBaseInstallStatus(&fFinishCYS);
if (S_OK == hr && !fFinishCYS)
{
//this could be either w2k or whistler
//treat as whistler since upgrade path won't execute
pComp->UpgradeFlag = CS_UPGRADE_WHISTLER;
goto done;
}
// wszREGACTIVE used in Win2k product and after. If not found, this is way before our time
// make sure by grabbing wszREGSP4DEFAULTCONFIGURATION
LPWSTR pwszTmp = NULL;
hr = myGetCertRegStrValue(
NULL,
NULL,
NULL,
wszREGSP4DEFAULTCONFIGURATION,
&pwszTmp);
if (pwszTmp)
LocalFree(pwszTmp);
// error! bail, we have no idea what we're seeing
_JumpIfError(hr, error, "myGetCertRegStrValue wszREGSP4DEFAULTCONFIGURATION");
// hr == S_OK: yep, looks like valid NT4 installation
pComp->UpgradeFlag = CS_UPGRADE_UNSUPPORTED;
CSILOG(S_OK, IDS_LOG_UPGRADE_UNSUPPORTED, NULL, NULL, NULL);
_JumpError(hr, error, "myGetCertRegStrValue");
}
// check wszREGVERSION to get current version
hr = myGetCertRegDWValue(
NULL,
NULL,
NULL,
wszREGVERSION,
&dwVersion);
if (S_OK != hr && HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)!= hr)
{
_JumpErrorStr(hr, error, "myGetCertRegDWValue", wszREGVERSION);
}
// now either OK or FILE_NOT_FOUND
if (S_OK == hr)
{
// pComp->UpgradeFlag = SOME_FUNCTION(dwVersion); // CS_UPGRADE_WHISTLER already set as default; in future, key off of this
pComp->UpgradeFlag = CS_UPGRADE_WHISTLER;
CSILOG(S_OK, IDS_LOG_UPGRADE_B2B, NULL, NULL, NULL);
}
else
{
// FILE_NOT_FOUND: now we know it's (NT5 Beta 2 <= X < Whistler)
// is this Win2k, or NT5 Beta? Test for active policy module to have "ICertManageModule" entry
// check nt5 beta 2 and get active policy name
hr = myGetCertRegStrValue(
pwszSanitizedCAName,
wszREGKEYPOLICYMODULES,
NULL,
wszREGACTIVE,
&pwszB2PolicyGuid);
if (S_OK == hr)
{
hr = myGetCertRegStrValue(
wszREGKEYPOLICYMODULES,
pwszB2PolicyGuid,
NULL,
wszREGB2ICERTMANAGEMODULE,
&pwszDummy);
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
// this doesn't exist on Win2k
pComp->UpgradeFlag = CS_UPGRADE_WIN2000;
CSILOG(S_OK, IDS_LOG_UPGRADE_WIN2000, NULL, NULL, NULL);
}
else
{
// this is definitely beta 2
pComp->UpgradeFlag = CS_UPGRADE_UNSUPPORTED;
CSILOG(S_OK, IDS_LOG_UPGRADE_UNSUPPORTED, NULL, NULL, NULL);
}
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
// strange, maybe no active module. Assume OK, latest bits.
pComp->UpgradeFlag = CS_UPGRADE_WIN2000;
CSILOG(S_OK, IDS_LOG_UPGRADE_WIN2000, NULL, NULL, NULL);
}
else
{
// other failure, just bail
_JumpErrorStr(hr, error, "myGetCertRegStrValue",
wszREGKEYPOLICYMODULES);
}
} // wszREGVERSION: FILE_NOT_FOUND
// take sanitized name
if (NULL != pServer->pwszSanitizedName)
{
// this will free the default name
LocalFree(pServer->pwszSanitizedName);
}
pServer->pwszSanitizedName = pwszSanitizedCAName;
pwszSanitizedCAName = NULL;
done:
hr = S_OK;
error:
if (NULL != pwszDummy)
{
LocalFree(pwszDummy);
}
if (NULL != pwszSanitizedCAName)
{
LocalFree(pwszSanitizedCAName);
}
CSILOG(hr, IDS_LOG_UPGRADE_TYPE, NULL, NULL, (DWORD const *) &pComp->UpgradeFlag);
return hr;
}
// Description: load and determine necessary information for upgrade
// upgrade won't continue if any error
HRESULT
LoadAndDetermineServerUpgradeInfo(
IN OUT PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
WCHAR *pwszRevocationType = NULL;
DWORD dwNetscapeType;
BOOL fDummy;
ALG_ID idAlgDummy;
CSP_INFO CSPInfoDummy;
ENUM_CATYPES CATypeDummy;
WCHAR *pwszCommonName = NULL;
// initialize
ZeroMemory(&CSPInfoDummy, sizeof(CSPInfoDummy));
// load information for all upgrade scenarios
// csp
hr = myGetCertRegStrValue(
pServer->pwszSanitizedName,
wszREGKEYCSP,
NULL,
wszREGPROVIDER,
&CSPInfoDummy.pwszProvName);
if (S_OK == hr && NULL != CSPInfoDummy.pwszProvName)
{
if (NULL != pServer->pCSPInfo->pwszProvName)
{
// free default csp
LocalFree(pServer->pCSPInfo->pwszProvName);
}
// use reg one as default for upgrade
pServer->pCSPInfo->pwszProvName = CSPInfoDummy.pwszProvName;
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpErrorStr(hr, error, "myGetCertRegStrValue", wszREGPROVIDER);
}
hr = myGetCertRegDWValue(
pServer->pwszSanitizedName,
wszREGKEYCSP,
NULL,
wszREGPROVIDERTYPE,
&CSPInfoDummy.dwProvType);
if (S_OK == hr)
{
pServer->pCSPInfo->dwProvType = CSPInfoDummy.dwProvType;
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpErrorStr(hr, error, "myGetCertRegDWValue", wszREGPROVIDERTYPE);
}
hr = myGetCertRegDWValue(
pServer->pwszSanitizedName,
wszREGKEYCSP,
NULL,
wszMACHINEKEYSET,
(DWORD*)&CSPInfoDummy.fMachineKeyset);
if (S_OK == hr)
{
pServer->pCSPInfo->fMachineKeyset = CSPInfoDummy.fMachineKeyset;
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpErrorStr(hr, error, "myGetCertRegDWValue", wszMACHINEKEYSET);
}
hr = myGetCertRegDWValue(
pServer->pwszSanitizedName,
wszREGKEYCSP,
NULL,
wszHASHALGORITHM,
(DWORD*)&idAlgDummy);
if (S_OK == hr)
{
pServer->pHashInfo->idAlg = idAlgDummy;
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpIfErrorStr(hr, error, "myGetCertRegDWValue", wszHASHALGORITHM);
}
if (NULL != pServer->pCSPInfoList)
{
// BUG, this will never happen because csp info list is not loaded yet
// one more checking, make sure csp is installed
if (NULL == findCSPInfoFromList(
pServer->pCSPInfoList,
pServer->pCSPInfo->pwszProvName,
pServer->pCSPInfo->dwProvType))
{
// if not, this is a broken ca
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "findCSPInfoFromList",
pServer->pCSPInfo->pwszProvName);
}
}
// UseDS flag
hr = myGetCertRegDWValue(
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCAUSEDS,
(DWORD*)&fDummy);
if (S_OK == hr)
{
// use from reg
pServer->fUseDS = fDummy;
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpErrorStr(hr, error, "myGetCertRegDWValue", wszREGCAUSEDS);
}
// CACommonName
// this will be used for looking cert in store to determine ca DN info
hr = myGetCertRegStrValue(
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCOMMONNAME,
&pwszCommonName);
if (S_OK != hr && HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpError(hr, error, "myGetCertRegStrValue");
}
else if ((HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) ||
(S_OK == hr && L'\0' == pwszCommonName[0]))
{
if (S_OK == hr && L'\0' == pwszCommonName[0])
{
// empty string, use snaitized name instead
LocalFree(pwszCommonName);
}
// in case empty or not found, use sanitized
pwszCommonName = (WCHAR*)LocalAlloc(LMEM_FIXED,
(wcslen(pServer->pwszSanitizedName) + 1) * sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, pwszCommonName);
wcscpy(pwszCommonName, pServer->pwszSanitizedName);
}
if (NULL != pServer->pwszCACommonName)
{
LocalFree(pServer->pwszCACommonName);
}
pServer->pwszCACommonName = pwszCommonName;
pwszCommonName = NULL;
// Collect CAType, DN info, dwCertNameId and upgrade ca cert
hr = DetermineCAInfoAndType(pComp);
_JumpIfError(hr, error, "DetermineCAInfoAndType");
// load following values for later
// check revocation type
hr = myGetCertRegDWValue(
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGREVOCATIONTYPE,
&pServer->dwRevocationFlags);
if(hr != S_OK)
{
pServer->dwRevocationFlags = pServer->fUseDS?
REVEXT_DEFAULT_DS : REVEXT_DEFAULT_NODS;
}
// following for web page creation
// load shared folder for ca cert file name creation
if (NULL != pServer->pwszSharedFolder)
{
// shouldn't happen but in case
LocalFree(pServer->pwszSharedFolder);
pServer->pwszSharedFolder = NULL;
}
hr = myGetCertRegStrValue(
NULL,
NULL,
NULL,
wszREGDIRECTORY,
&pServer->pwszSharedFolder);
if (S_OK == hr && L'\0' == pServer->pwszSharedFolder[0])
{
// in case of empty, set to null
LocalFree(pServer->pwszSharedFolder);
pServer->pwszSharedFolder = NULL;
}
else if (S_OK != hr && HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpError(hr, error, "myGetCertRegStrValue");
}
// build ca cert file name for web install and ca cert saving
if (NULL != pServer->pwszCACertFile)
{
// free old one
LocalFree(pServer->pwszCACertFile);
}
hr = csiBuildCACertFileName(
pComp->hInstance,
NULL, //hwnd, ok for upgrade
pComp->fUnattended,
pServer->pwszSharedFolder,
pServer->pwszSanitizedName,
L".crt",
0, // iCert
&pServer->pwszCACertFile);
_JumpIfError(hr, error, "BuildCACertFileName");
hr = S_OK;
error:
if (NULL != pwszRevocationType)
{
LocalFree(pwszRevocationType);
}
if (NULL != pwszCommonName)
{
LocalFree(pwszCommonName);
}
return hr;
}
HRESULT
GetConfigInSharedFolderWithCert(
WCHAR const *pwszSharedFolder,
OUT WCHAR **ppwszConfig)
{
HRESULT hr;
ICertConfig * pICertConfig = NULL;
BSTR bstrConfig = NULL;
BOOL fCoInit = FALSE;
WCHAR *pwszCAMachine;
WCHAR *pwszCAName;
WCHAR wszCertFileInSharedFolder[MAX_PATH];
LONG i;
LONG lCount;
LONG Index;
BOOL fLocal;
CSASSERT(NULL != ppwszConfig);
*ppwszConfig = NULL;
hr = CoInitialize(NULL);
if (S_OK != hr && S_FALSE != hr)
{
_JumpError(hr, error, "CoInitialize");
}
fCoInit = TRUE;
hr = CoCreateInstance(
CLSID_CCertConfig,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICertConfig,
(VOID**) &pICertConfig);
_JumpIfError(hr, error, "CoCreateInstance");
// get local
hr = pICertConfig->Reset(0, &lCount);
_JumpIfError(hr, error, "ICertConfig->Reset");
for (i = 0; i < lCount; ++i)
{
hr = pICertConfig->Next(&Index);
if (S_OK != hr && S_FALSE != hr)
{
_JumpError(hr, error, "ICertConfig->Next");
}
if (-1 == Index)
{
hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
_JumpError(hr, error, "No CA cert file");
}
hr = pICertConfig->GetField(wszCONFIG_CONFIG, &bstrConfig);
_JumpIfError(hr, error, "ICertConfig->GetField(Config)");
pwszCAMachine = (WCHAR*)bstrConfig;
pwszCAName = wcschr(pwszCAMachine, L'\\');
if (NULL == pwszCAName)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "Invalid config string");
}
pwszCAName[0] = '\0'; // make pwszCAMachine
++pwszCAName;
// form NT4 ca cert file path in shared folder
wcscpy(wszCertFileInSharedFolder, pwszSharedFolder);
wcscat(wszCertFileInSharedFolder, L"\\");
wcscat(wszCertFileInSharedFolder, pwszCAMachine);
wcscat(wszCertFileInSharedFolder, L"_");
wcscat(wszCertFileInSharedFolder, pwszCAName);
wcscat(wszCertFileInSharedFolder, L".crt");
DBGPRINT((
DBG_SS_CERTOCM,
"wszCertFileInSharedFolder: %ws\n",
wszCertFileInSharedFolder));
if (myDoesFileExist(wszCertFileInSharedFolder))
{
//done
break;
}
SysFreeString(bstrConfig);
bstrConfig = NULL;
}
if (i >= lCount)
{
hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
_JumpError(hr, error, "No CA cert file");
}
*ppwszConfig = (WCHAR*)LocalAlloc(LMEM_FIXED,
SysStringByteLen(bstrConfig) + sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, *ppwszConfig);
wcscpy(*ppwszConfig, bstrConfig);
hr = S_OK;
error:
if (NULL != pICertConfig)
{
pICertConfig->Release();
}
if (NULL != bstrConfig)
{
SysFreeString(bstrConfig);
}
if (fCoInit)
{
CoUninitialize();
}
return hr;
}
HRESULT
DetermineClientUpgradePath(
IN OUT PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CAWEBCLIENTSETUPINFO *pClient = pComp->CA.pClient;
WCHAR *pwszCAName;
DWORD dwVersion;
if (CS_UPGRADE_UNKNOWN != pComp->UpgradeFlag)
{
// already know upgrade type
CSASSERT(pClient->pwszWebCAMachine); // this is a side-effect of this fxn, better have been set already
CSASSERT(pClient->pwszWebCAName); // this is a side-effect of this fxn, better have been set already
return S_OK;
}
//get ca info from registry here
if (NULL != pClient->pwszWebCAMachine)
{
// shouldn't happen, just in case
LocalFree(pClient->pwszWebCAMachine);
pClient->pwszWebCAMachine = NULL;
}
if (NULL != pClient->pwszWebCAName)
{
// shouldn't happen, just in case
LocalFree(pClient->pwszWebCAName);
pClient->pwszWebCAName = NULL;
}
// get ca machine
hr = myGetCertRegStrValue(
NULL,
NULL,
NULL,
wszREGWEBCLIENTCAMACHINE,
&pClient->pwszWebCAMachine);
if (S_OK != hr || L'\0' == pClient->pwszWebCAMachine[0])
{
BOOL fFinishCYS;
//for W2K after, it is possible to be in post mode
hr = CheckPostBaseInstallStatus(&fFinishCYS);
if (S_OK == hr && !fFinishCYS)
{
//this could be either w2k or whistler
//treat as whistler since upgrade path won't execute
pComp->UpgradeFlag = CS_UPGRADE_WHISTLER;
goto done;
}
// incorrect reg state,
// either not found entry or empty string: NT4
pComp->UpgradeFlag = CS_UPGRADE_UNSUPPORTED;
hr = S_OK;
CSILOG(S_OK, IDS_LOG_UPGRADE_UNSUPPORTED, NULL, NULL, NULL);
_JumpErrorStr(hr, error, "myGetCertRegStrValue", wszREGWEBCLIENTCAMACHINE);
}
// get ca
hr = myGetCertRegStrValue(
NULL,
NULL,
NULL,
wszREGWEBCLIENTCANAME,
&pClient->pwszWebCAName);
if (S_OK != hr || L'\0' == pClient->pwszWebCAName[0])
{
// incorrect reg state,
// either not found entry or empty string: NT4
if (pClient->pwszWebCAMachine)
LocalFree(pClient->pwszWebCAMachine);
pComp->UpgradeFlag = CS_UPGRADE_UNSUPPORTED;
hr = S_OK;
CSILOG(S_OK, IDS_LOG_UPGRADE_UNSUPPORTED, NULL, NULL, NULL);
_JumpErrorStr(hr, error, "myGetCertRegStrValue", wszREGWEBCLIENTCANAME);
}
// Now either W2k or Whistler
// check wszREGVERSION to get current version on Whistler++
hr = myGetCertRegDWValue(
NULL,
NULL,
NULL,
wszREGVERSION,
&dwVersion);
if (S_OK != hr && HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)!= hr)
{
_JumpErrorStr(hr, error, "myGetCertRegDWValue", wszREGVERSION);
}
// now either OK or FILE_NOT_FOUND
if (S_OK == hr)
{
// pComp->UpgradeFlag = SOME_FUNCTION(dwVersion); // CS_UPGRADE_WHISTLER already set as default; in future, key off of this
pComp->UpgradeFlag = CS_UPGRADE_WHISTLER;
CSILOG(S_OK, IDS_LOG_UPGRADE_B2B, NULL, NULL, NULL);
}
else
{
pComp->UpgradeFlag = CS_UPGRADE_WIN2000;
CSILOG(S_OK, IDS_LOG_UPGRADE_WIN2000, NULL, NULL, NULL);
}
done:
hr = S_OK;
error:
CSILOG(hr, IDS_LOG_UPGRADE_TYPE, NULL, NULL, (DWORD const *) &pComp->UpgradeFlag);
return hr;
}
HRESULT
LoadAndDetermineClientUpgradeInfo(
IN OUT PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CAWEBCLIENTSETUPINFO *pClient = pComp->CA.pClient;
WCHAR *pwszCAName;
DWORD dwVersion;
//get ca info from registry here
if (NULL != pClient->pwszSanitizedWebCAName)
{
// shouldn't happen, just in case
LocalFree(pClient->pwszSanitizedWebCAName);
pClient->pwszSanitizedWebCAName = NULL;
}
hr = DetermineClientUpgradePath(pComp);
_JumpIfError(hr, error, "DetermineClientUpgradePath");
// get ca
hr = myGetCertRegDWValue(
NULL,
NULL,
NULL,
wszREGWEBCLIENTCATYPE,
(DWORD *) &pClient->WebCAType);
_PrintIfErrorStr(hr, "myGetCertRegDWValue", wszREGWEBCLIENTCATYPE);
hr = mySanitizeName(pClient->pwszWebCAName,
&pClient->pwszSanitizedWebCAName);
_JumpIfError(hr, error, "mySanitizeName");
hr = S_OK;
error:
CSILOG(hr, IDS_LOG_UPGRADE_TYPE, NULL, NULL, (DWORD const *) &pComp->UpgradeFlag);
return hr;
}
// apply ACL to key container for all upgrade scenarios
HRESULT
UpgradeKeyContainerSecurity(
HWND hwnd,
PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
HCRYPTPROV hProv = NULL;
WCHAR *pwszProvName = NULL;
DWORD dwProvType;
ALG_ID idAlg;
BOOL fMachineKeyset;
// get prov name
hr = myGetCertSrvCSP(
FALSE, // fEncryptionCSP
pComp->CA.pServer->pwszSanitizedName,
&dwProvType,
&pwszProvName,
&idAlg,
&fMachineKeyset,
NULL); // pdwKeySize
_JumpIfError(hr, error, "myGetCertSrvCSP");
if (!myCertSrvCryptAcquireContext(&hProv,
pComp->CA.pServer->pwszSanitizedName,
pwszProvName,
dwProvType,
CRYPT_SILENT, // get key, upgrade, no UI
fMachineKeyset))
{
hr = myHLastError();
_JumpError(hr, error, "myCertSrvCryptAcquireContext");
}
// set acl on it
hr = csiSetKeyContainerSecurity(hProv);
_JumpIfError(hr, error, "csiSetKeyContainerSecurity");
error:
if (NULL != hProv)
{
CryptReleaseContext(hProv, 0);
}
if (NULL != pwszProvName)
{
LocalFree(pwszProvName);
}
CSILOG(hr, IDS_LOG_UPGRADE_KEY_SECURITY, NULL, NULL, NULL);
return hr;
}
HRESULT InstallNewTemplates(HWND hwnd)
{
HRESULT hr = S_OK;
SHELLEXECUTEINFO shi;
ZeroMemory(&shi, sizeof(shi));
shi.cbSize = sizeof(shi);
shi.hwnd = hwnd;
shi.lpVerb = SZ_VERB_OPEN;
shi.lpFile = SZ_REGSVR32;
shi.lpParameters = SZ_REGSVR32_CERTCLI;
shi.fMask = SEE_MASK_FLAG_NO_UI |
SEE_MASK_NOCLOSEPROCESS;
if(!ShellExecuteEx(&shi))
{
hr = myHLastError();
_JumpError(hr, error, "ShellExecuteEx");
}
if(WAIT_FAILED == WaitForSingleObject(shi.hProcess, INFINITE))
{
hr = myHLastError();
_JumpError(hr, error, "WaitForSingleObject");
}
error:
if(shi.hProcess)
{
CloseHandle(shi.hProcess);
}
return hr;
}
HRESULT
UpgradeServer(
IN HWND hwnd,
IN PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
hr = RegisterAndUnRegisterDLLs(RD_SERVER|RD_SKIPUNREGMMC, pComp, hwnd);
_JumpIfError(hr, error, "RegisterAndUnRegisterDLLs");
hr = LoadAndDetermineServerUpgradeInfo(pComp);
_JumpIfError(hr, error, "LoadAndDetermineServerUpgradeInfo");
// create enroll dir
hr = CreateCertsrvDirectories(pComp, TRUE, TRUE);
_JumpIfError(hr, error, "CreateCertsrvDirectories");
hr = EnableVRootsAndShares(FALSE, TRUE, TRUE, pComp);
_PrintIfError(hr, "EnableVRootsAndShares(share only)");
hr = UpgradeServerRegEntries(hwnd, pComp);
_JumpIfError(hr, error, "UpgradeServerRegEntries");
hr = CreateCertWebIncPages(hwnd, pComp, TRUE /*IsServer*/, TRUE);
_JumpIfError(hr, error, "CreateCertWebIncPages");
hr = RenameMiscTargets(hwnd, pComp, TRUE);
_JumpIfError(hr, error, "RenameMiscTargets");
hr = UpgradeKeyContainerSecurity(hwnd, pComp);
// ignore new acl failure
_PrintIfError(hr, "UpgradeKeyContainerSecurity");
// always register dcom
hr = RegisterDcomServer(
CLSID_CCertRequestD,
wszREQUESTFRIENDLYNAME,
wszREQUESTVERINDPROGID,
wszREQUESTPROGID);
_JumpIfError(hr, error, "RegisterDcomServer");
hr = RegisterDcomServer(
CLSID_CCertAdminD,
wszADMINFRIENDLYNAME,
wszADMINVERINDPROGID,
wszADMINPROGID);
_JumpIfError(hr, error, "RegisterDcomServer");
hr = RegisterDcomApp(CLSID_CCertRequestD);
_JumpIfError(hr, error, "RegisterDcomApp");
// fix for 155772 Certsrv: After upgrading a 2195 Enterprise Root CA
// to 2254.01VBL03 the CA will no longer issue Certs
hr = InstallNewTemplates(hwnd);
_JumpIfError(hr, error, "InstallNewTemplates");
// always fix certsvc in upgrade
hr = FixCertsvcService(pComp);
_PrintIfError(hr, "FixCertsvcService");
// delete any old program groups
DeleteProgramGroups(TRUE, pComp);
hr = CreateProgramGroups(FALSE, pComp, hwnd);
_PrintIfError(hr, "CreateProgramGroups");
// delete old stuff
DeleteOldFilesAndDirectories(pComp);
DBGPRINT((DBG_SS_CERTOCM, "UpgradeServer: setting SETUP_SERVER_UPGRADED_FLAG\n"));
hr = SetSetupStatus(NULL, SETUP_SERVER_UPGRADED_FLAG, TRUE);
_JumpIfError(hr, error, "SetSetupStatus");
hr = csiUpgradeCertSrvSecurity(
pServer->pwszSanitizedName,
IsEnterpriseCA(pServer->CAType)?true:false,
pServer->fUseDS?true:false,
pComp->UpgradeFlag);
if (hr == HRESULT_FROM_WIN32(ERROR_CAN_NOT_COMPLETE))
{
_PrintError(hr, "csiUpgradeCertSrvSecurity marked for later fixup; error ignored");
hr = S_OK;
}
_JumpIfError(hr, error, "csiUpgradeCertSrvSecurity");
hr = S_OK;
error:
CSILOG(hr, IDS_LOG_UPGRADE_SERVER, NULL, NULL, NULL);
return hr;
}
HRESULT
UpgradeClient(
IN HWND hwnd,
IN PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CAWEBCLIENTSETUPINFO *pClient = pComp->CA.pClient;
if ((IS_CLIENT_UPGRADE & pComp->dwInstallStatus) &&
(IS_SERVER_UPGRADE & pComp->dwInstallStatus))
{
// upgrade server will also hit here so skip it
goto done;
}
// unset client
hr = SetSetupStatus(NULL, SETUP_CLIENT_FLAG, FALSE);
_JumpIfError(hr, error, "SetSetupStatus");
hr = RegisterAndUnRegisterDLLs(RD_CLIENT|RD_SKIPUNREGMMC, pComp, hwnd);
_JumpIfError(hr, error, "RegisterAndUnRegisterDLLs");
hr = LoadAndDetermineClientUpgradeInfo(pComp);
_JumpIfError(hr, error, "LoadAndDetermineClientUpgradeInfo");
hr = UpgradeWebClientRegEntries(pComp);
_JumpIfError(hr, error, "UpgradeWebClientRegEntries");
hr = CreateCertWebIncPages(hwnd, pComp, FALSE /*IsServer*/, TRUE);
_JumpIfError(hr, error, "CreateCertWebIncPages");
hr = RenameMiscTargets(hwnd, pComp, FALSE);
_JumpIfError(hr, error, "RenameMiscTargets");
// delete any old program groups
DeleteProgramGroups(FALSE, pComp);
hr = CreateProgramGroups(TRUE, pComp, hwnd);
_PrintIfError(hr, "CreateProgramGroups");
hr = SetSetupStatus(NULL, SETUP_CLIENT_FLAG, TRUE);
_JumpIfError(hr, error, "SetSetupStatus");
DeleteOldFilesAndDirectories(pComp);
done:
hr = S_OK;
error:
CSILOG(hr, IDS_LOG_UPGRADE_CLIENT, NULL, NULL, NULL);
return hr;
}
HRESULT
GetServerNames(
IN HWND hwnd,
IN HINSTANCE hInstance,
IN BOOL fUnattended,
OUT WCHAR **ppwszServerName,
OUT WCHAR **ppwszServerNameOld)
{
HRESULT hr;
// Retrieve computer name strings.
hr = myGetComputerNames(ppwszServerName, ppwszServerNameOld);
if (S_OK != hr)
{
CertErrorMessageBox(
hInstance,
fUnattended,
hwnd,
IDS_ERR_GETCOMPUTERNAME,
hr,
NULL);
_JumpError(hr, error, "myGetComputerNames");
}
error:
return(hr);
}
HRESULT
UpdateDomainAndUserName(
IN HWND hwnd,
IN OUT PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
// free old server and installer info because we might get them in nt base
if (NULL != pComp->pwszServerName)
{
LocalFree(pComp->pwszServerName);
pComp->pwszServerName = NULL;
}
if (NULL != pComp->pwszServerNameOld)
{
LocalFree(pComp->pwszServerNameOld);
pComp->pwszServerNameOld = NULL;
}
hr = GetServerNames(
hwnd,
pComp->hInstance,
pComp->fUnattended,
&pComp->pwszServerName,
&pComp->pwszServerNameOld);
_JumpIfError(hr, error, "GetServerNames");
DBGPRINT((DBG_SS_CERTOCM, "UpdateDomainAndUserName:%ws,%ws\n", pComp->pwszServerName, pComp->pwszServerNameOld));
DumpBackTrace("UpdateDomainAndUserName");
error:
return(hr);
}
HRESULT
StopCertService(
IN HWND hwnd,
IN SC_HANDLE hSC,
IN WCHAR const *pwszServiceName)
{
HRESULT hr;
SERVICE_STATUS status;
DWORD dwAttempt;
if (!ControlService(hSC, SERVICE_CONTROL_STOP, &status))
{
hr = myHLastError();
if (HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE) != hr)
{
_JumpErrorStr(hr, error, "ControlService(Stop)", pwszServiceName);
}
}
// get out after it is really stopped
for (dwAttempt = 0; dwAttempt < CERT_MAX_ATTEMPT; dwAttempt++)
{
DBGCODE(status.dwCurrentState = -1);
if (!QueryServiceStatus(hSC, &status))
{
// query failed, ignore error
hr = S_OK;
_JumpErrorStr(
myHLastError(), // Display ignored error
error,
"QueryServiceStatus",
pwszServiceName);
}
if (status.dwCurrentState != SERVICE_STOP_PENDING &&
status.dwCurrentState != SERVICE_RUNNING)
{
// it was stopped already
break;
}
DBGPRINT((
DBG_SS_CERTOCM,
"Stopping %ws service: current state=%d\n",
pwszServiceName,
status.dwCurrentState));
Sleep(CERT_HALF_SECOND);
}
if (dwAttempt >= CERT_MAX_ATTEMPT)
{
DBGPRINT((
DBG_SS_CERTOCM,
"Timeout stopping %ws service: current state=%d\n",
pwszServiceName,
status.dwCurrentState));
}
else
{
DBGPRINT((
DBG_SS_CERTOCM,
"Stopped %ws service\n",
pwszServiceName));
}
hr = S_OK;
error:
CSILOG(hr, IDS_LOG_SERVICE_STOPPED, pwszServiceName, NULL, NULL);
return(hr);
}
HRESULT
GetServiceControl(
WCHAR const *pwszServiceName,
OUT SC_HANDLE *phService)
{
HRESULT hr;
SC_HANDLE hSCManager = NULL;
*phService = NULL;
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == hSCManager)
{
hr = myHLastError();
_JumpError(hr, error, "OpenSCManager");
}
*phService = OpenService(hSCManager, pwszServiceName, SERVICE_ALL_ACCESS);
if (NULL == *phService)
{
hr = myHLastError();
_JumpErrorStr2(
hr,
error,
"OpenService",
pwszServiceName,
HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST));
}
hr = S_OK;
error:
if (NULL != hSCManager)
{
CloseServiceHandle(hSCManager);
}
return hr;
}
HRESULT
IsServiceRunning(
IN SC_HANDLE const hSCService,
OUT BOOL *pfRun)
{
HRESULT hr;
SERVICE_STATUS status;
*pfRun = FALSE;
if (!QueryServiceStatus(hSCService, &status))
{
hr = myHLastError();
_JumpError(hr, error, "QueryServiceStatus");
}
if (SERVICE_STOPPED != status.dwCurrentState &&
SERVICE_STOP_PENDING != status.dwCurrentState)
{
*pfRun = TRUE;
}
hr = S_OK;
error:
return hr;
}
HRESULT
StartAndStopService(
IN HINSTANCE hInstance,
IN BOOL fUnattended,
IN HWND const hwnd,
IN WCHAR const *pwszServiceName,
IN BOOL const fStopService,
IN BOOL const fConfirm,
IN int iMsg,
OUT BOOL *pfServiceWasRunning)
{
HRESULT hr;
SC_HANDLE hService = NULL;
SERVICE_STATUS status;
*pfServiceWasRunning = FALSE;
hr = GetServiceControl(pwszServiceName, &hService);
if (S_OK != hr)
{
_PrintError2(
hr,
"GetServiceControl",
HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST));
if (HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) == hr)
{
hr = S_OK;
}
goto error;
}
// to get status if the service is running
hr = IsServiceRunning(hService, pfServiceWasRunning);
_JumpIfError(hr, error, "IsServiceRunning");
if (fStopService)
{
if (*pfServiceWasRunning)
{
// stop the service
if (fConfirm)
{
// confirmation dialog
int ret = CertMessageBox(
hInstance,
fUnattended,
hwnd,
iMsg,
0,
MB_YESNO |
MB_ICONWARNING |
CMB_NOERRFROMSYS,
NULL);
if (IDYES != ret)
{
hr = E_ABORT;
_JumpError(hr, error, "Cancel it");
}
}
hr = StopCertService(hwnd, hService, pwszServiceName);
_JumpIfErrorStr(hr, error, "StopCertService", pwszServiceName);
}
}
else
{
// START the service
if (!*pfServiceWasRunning)
{
if (!StartService(hService, 0, NULL))
{
hr = myHLastError();
_JumpErrorStr(hr, error, "StartService", pwszServiceName);
}
}
}
hr = S_OK;
error:
if (NULL != hService)
{
CloseServiceHandle(hService);
}
CSILOG(
hr,
fStopService? IDS_LOG_SERVICE_STOPPED : IDS_LOG_SERVICE_STARTED,
pwszServiceName,
NULL,
NULL);
return hr;
}
// fix existing certsvc service to add/use new service description
HRESULT
FixCertsvcService(PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
SC_HANDLE hService = NULL;
QUERY_SERVICE_CONFIG *pServiceConfig = NULL;
WCHAR *pwszServiceDesc = NULL;
WCHAR const *pwszDisplayName;
SERVICE_DESCRIPTION sd;
DWORD dwSize;
hr = GetServiceControl(wszSERVICE_NAME, &hService);
_JumpIfError(hr, error, "GetServiceControl");
// get size
if (!QueryServiceConfig(hService,
NULL,
0,
&dwSize))
{
hr = myHLastError();
if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
{
_JumpError(hr, fix_desc, "QueryServiceConfig");
}
}
else
{
// impossible???
hr = E_INVALIDARG;
_JumpError(hr, fix_desc, "QueryServiceConfig");
}
CSASSERT(0 < dwSize);
// allocate config buffer
pServiceConfig = (QUERY_SERVICE_CONFIG*)LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
dwSize);
_JumpIfOutOfMemory(hr, error, pServiceConfig);
// get config
if (!QueryServiceConfig(hService,
pServiceConfig,
dwSize,
&dwSize))
{
hr = myHLastError();
_JumpError(hr, fix_desc, "QueryServiceConfig");
}
// use new display name
pwszDisplayName = myLoadResourceString(IDS_CA_SERVICEDISPLAYNAME);
if (NULL == pwszDisplayName)
{
hr = myHLastError();
_JumpError(hr, error, "myLoadResourceString");
}
if (!ChangeServiceConfig(hService,
pServiceConfig->dwServiceType, //dwServiceType
SERVICE_NO_CHANGE, //dwStartType
SERVICE_NO_CHANGE, //dwErrorControl
NULL, //lpBinaryPathName
NULL, //lpLoadOrderGroup
NULL, //lpdwTagId
NULL, //lpDependences
NULL, //lpServiceStartName
NULL, //lpPassword
pwszDisplayName))
{
hr = myHLastError();
_JumpIfError(hr, fix_desc, "ChangeServiceConfig");
}
fix_desc:
// add description
hr = myLoadRCString(pComp->hInstance, IDS_CA_SERVICEDESCRIPTION, &pwszServiceDesc);
_JumpIfError(hr, error, "myLoadRCString");
sd.lpDescription = pwszServiceDesc;
if (!ChangeServiceConfig2(hService,
SERVICE_CONFIG_DESCRIPTION,
(VOID*)&sd))
{
hr = myHLastError();
_JumpError(hr, error, "ChangeServiceConfig2");
}
hr = S_OK;
error:
if (NULL != hService)
{
CloseServiceHandle(hService);
}
if (NULL != pwszServiceDesc)
{
LocalFree(pwszServiceDesc);
}
if (NULL != pServiceConfig)
{
LocalFree(pServiceConfig);
}
return hr;
}
HRESULT
PreUninstallCore(
IN HWND hwnd,
IN PER_COMPONENT_DATA *pComp,
IN BOOL fPreserveClient)
{
BOOL fDummy;
HRESULT hr;
DWORD dwFlags = RD_UNREGISTER;
hr = StartAndStopService(pComp->hInstance,
pComp->fUnattended,
hwnd,
wszSERVICE_NAME,
TRUE, // stop the service
FALSE, // no confirm
0, //doesn't matter since no confirm
&fDummy);
_PrintIfError(hr, "StartAndStopService");
hr = RegisterAndUnRegisterDLLs(dwFlags, pComp, hwnd);
_PrintIfError(hr, "RegisterAndUnRegisterDLLs");
hr = S_OK;
return(hr);
}
VOID
DeleteServiceAndGroups(
IN HINSTANCE hInstance,
IN BOOL fUnattended,
IN HWND hwnd)
{
SC_HANDLE hSCManager = NULL;
SC_HANDLE hSC = NULL;
HRESULT hr;
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == hSCManager)
{
hr = myHLastError();
_JumpError(hr, error, "OpenSCManager");
}
hSC = OpenService(hSCManager, wszSERVICE_NAME, SERVICE_ALL_ACCESS);
if (NULL != hSC)
{
if (!DeleteService(hSC))
{
hr = myHLastError();
CertErrorMessageBox(
hInstance,
fUnattended,
hwnd,
IDS_ERR_DELETESERVICE,
hr,
wszSERVICE_NAME);
_PrintError(hr, "DeleteService");
}
CloseServiceHandle(hSC);
}
error:
if (NULL != hSCManager)
{
CloseServiceHandle(hSCManager);
}
}
HRESULT SetCertSrvInstallVersion()
{
HRESULT hr;
hr = mySetCertRegDWValueEx(
FALSE,
NULL,
NULL,
NULL,
wszREGVERSION,
(CSVER_MAJOR << 16) | CSVER_MINOR);
_PrintIfErrorStr(hr, "mySetCertRegDWValueEx", wszREGVERSION);
return hr;
}
HRESULT
CreateWebClientRegEntries(
BOOL fUpgrade,
PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CAWEBCLIENTSETUPINFO *pClient = pComp->CA.pClient;
hr = mySetCertRegStrValueEx(fUpgrade, NULL, NULL, NULL,
wszREGWEBCLIENTCAMACHINE, pClient->pwszWebCAMachine);
_JumpIfError(hr, error, "mySetCertRegStrValueEx");
hr = mySetCertRegStrValueEx(fUpgrade, NULL, NULL, NULL,
wszREGWEBCLIENTCANAME, pClient->pwszWebCAName);
_JumpIfError(hr, error, "mySetCertRegStrValueEx");
hr = mySetCertRegDWValueEx(fUpgrade, NULL, NULL, NULL,
wszREGWEBCLIENTCATYPE, pClient->WebCAType);
_JumpIfError(hr, error, "mySetCertRegDWValueEx");
hr = SetCertSrvInstallVersion();
_JumpIfError(hr, error, "SetCertSrvInstallVersion");
if (NULL != pClient->pwszSharedFolder)
{
hr = mySetCertRegStrValueEx(fUpgrade, NULL, NULL, NULL,
wszREGDIRECTORY, pClient->pwszSharedFolder);
_JumpIfError(hr, error, "mySetCertRegStrValue");
}
hr = S_OK;
error:
CSILOG(hr, IDS_LOG_CREATE_CLIENT_REG, NULL, NULL, NULL);
return hr;
}
HRESULT
UpgradeWebClientRegEntries(
PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
hr = CreateWebClientRegEntries(TRUE, pComp);
_JumpIfError(hr, error, "CreateWebClientRegEntries");
// hr = S_OK;
error:
return hr;
}
HRESULT
UninstallCore(
IN HWND hwnd,
IN PER_COMPONENT_DATA *pComp,
IN DWORD PerCentCompleteBase,
IN DWORD PerCentCompleteMax,
IN BOOL fPreserveClient,
IN BOOL fRemoveVD,
IN BOOL fPreserveToDoList)
{
BOOL fCoInit = FALSE;
HRESULT hr;
WCHAR *pwszSharedFolder = NULL;
WCHAR *pwszSanitizedCAName = NULL;
ENUM_CATYPES caType = ENUM_UNKNOWN_CA;
BOOL fUseDS = FALSE;
WCHAR *pwszDBDirectory = NULL;
WCHAR *pwszLogDirectory = NULL;
WCHAR *pwszSysDirectory = NULL;
WCHAR *pwszTmpDirectory = NULL;
DWORD DBSessionCount = 0;
DWORD PerCentCompleteDelta;
PerCentCompleteDelta = (PerCentCompleteMax - PerCentCompleteBase) / 10;
#define _UNINSTALLPERCENT(tenths) \
(PerCentCompleteBase + (tenths) * PerCentCompleteDelta)
// get current active CA info
hr = myGetCertRegStrValue(NULL, NULL, NULL, wszREGACTIVE, &pwszSanitizedCAName);
_PrintIfError(hr, "UninstallCore(no active CA)");
if (S_OK == hr)
{
hr = ArchiveCACertificate(pwszSanitizedCAName);
_PrintIfError2(hr, "ArchiveCACertificate", HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
hr = myGetCertRegDWValue(pwszSanitizedCAName, NULL, NULL, wszREGCATYPE, (DWORD*)&caType);
_PrintIfError(hr, "no reg ca type");
hr = myGetCertRegDWValue(pwszSanitizedCAName, NULL, NULL, wszREGCAUSEDS, (DWORD*)&fUseDS);
_PrintIfError(hr, "no reg use ds");
hr = DeleteCertificates(pwszSanitizedCAName, IsRootCA(caType));
if(S_OK != hr)
{
CertWarningMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_IDINFO_DELETECERTIFICATES,
0,
NULL);
}
}
hr = myGetCertRegStrValue(NULL, NULL, NULL, wszREGDIRECTORY, &pwszSharedFolder);
_PrintIfError(hr, "no shared folder");
hr = myGetCertRegStrValue(NULL, NULL, NULL, wszREGDBDIRECTORY, &pwszDBDirectory);
_PrintIfError(hr, "no db directory");
hr = myGetCertRegStrValue(NULL, NULL, NULL, wszREGDBLOGDIRECTORY, &pwszLogDirectory);
_PrintIfError(hr, "no log directory");
hr = myGetCertRegStrValue(NULL, NULL, NULL, wszREGDBSYSDIRECTORY, &pwszSysDirectory);
_PrintIfError(hr, "no sys directory");
hr = myGetCertRegStrValue(NULL, NULL, NULL, wszREGDBTEMPDIRECTORY, &pwszTmpDirectory);
_PrintIfError(hr, "no tmp directory");
hr = myGetCertRegDWValue(NULL, NULL, NULL, wszREGDBSESSIONCOUNT, &DBSessionCount);
_PrintIfError(hr, "no session count");
hr = CoInitialize(NULL);
if (S_OK != hr && S_FALSE != hr)
{
_JumpError(hr, error, "CoInitialize");
}
fCoInit = TRUE;
DeleteServiceAndGroups(pComp->hInstance, pComp->fUnattended, hwnd);
certocmBumpGasGauge(pComp, _UNINSTALLPERCENT(1) DBGPARM(L"UninstallCore"));
if (!fPreserveToDoList)
{
// if we're uninstalling, always clear post-base ToDo list
RegDeleteKey(HKEY_LOCAL_MACHINE, wszREGKEYCERTSRVTODOLIST);
}
if (fPreserveClient)
{
hr = RegisterAndUnRegisterDLLs(RD_CLIENT, pComp, hwnd);
_JumpIfError(hr, error, "RegisterAndUnRegisterDLLs");
hr = CreateCertWebIncPages(hwnd, pComp, FALSE /*IsServer*/, FALSE);
_JumpIfError(hr, error, "CreateCertWebIncPages");
}
certocmBumpGasGauge(pComp, _UNINSTALLPERCENT(2) DBGPARM(L"UninstallCore"));
DeleteProgramGroups(TRUE, pComp);
if (fPreserveClient)
{
hr = CreateProgramGroups(TRUE, pComp, hwnd);
_JumpIfError(hr, error, "CreateProgramGroups");
}
certocmBumpGasGauge(pComp, _UNINSTALLPERCENT(3) DBGPARM(L"UninstallCore"));
UnregisterDcomServer(
CLSID_CCertRequestD,
wszREQUESTVERINDPROGID,
wszREQUESTPROGID);
certocmBumpGasGauge(pComp, _UNINSTALLPERCENT(4) DBGPARM(L"UninstallCore"));
UnregisterDcomServer(
CLSID_CCertAdminD,
wszADMINVERINDPROGID,
wszADMINPROGID);
certocmBumpGasGauge(pComp, _UNINSTALLPERCENT(5) DBGPARM(L"UninstallCore"));
UnregisterDcomApp();
certocmBumpGasGauge(pComp, _UNINSTALLPERCENT(6) DBGPARM(L"UninstallCore"));
if (fRemoveVD && !fPreserveClient)
{
DisableVRootsAndShares(TRUE, TRUE);
myDeleteFilePattern(pComp->pwszSystem32, wszCERTSRV, TRUE);
}
certocmBumpGasGauge(pComp, _UNINSTALLPERCENT(7) DBGPARM(L"UninstallCore"));
if (NULL != pwszSharedFolder)
{
// this must be restore before CreateConfigFiles()
hr = mySetCertRegStrValue(NULL, NULL, NULL,
wszREGDIRECTORY, pwszSharedFolder);
_PrintIfError(hr, "mySetCertRegStrValue");
//remove entry
hr = CreateConfigFiles(pwszSharedFolder, pComp, TRUE, hwnd);
_PrintIfError2(hr, "CreateConfigFiles(Remove old entry)", hr);
}
certocmBumpGasGauge(pComp, _UNINSTALLPERCENT(8) DBGPARM(L"UninstallCore"));
// restore db path
if (NULL != pwszDBDirectory)
{
hr = mySetCertRegStrValue(NULL, NULL, NULL,
wszREGDBDIRECTORY, pwszDBDirectory);
_PrintIfError(hr, "mySetCertRegStrValue");
}
if (NULL != pwszLogDirectory)
{
hr = mySetCertRegStrValue(NULL, NULL, NULL,
wszREGDBLOGDIRECTORY, pwszLogDirectory);
_PrintIfError(hr, "mySetCertRegStrValue");
}
if (NULL != pwszSysDirectory)
{
hr = mySetCertRegStrValue(NULL, NULL, NULL,
wszREGDBSYSDIRECTORY, pwszSysDirectory);
_PrintIfError(hr, "mySetCertRegStrValue");
}
if (NULL != pwszTmpDirectory)
{
hr = mySetCertRegStrValue(NULL, NULL, NULL,
wszREGDBTEMPDIRECTORY, pwszTmpDirectory);
_PrintIfError(hr, "mySetCertRegStrValue");
}
if (0 != DBSessionCount)
{
hr = mySetCertRegDWValue(NULL, NULL, NULL,
wszREGDBSESSIONCOUNT, DBSessionCount);
_PrintIfError(hr, "mySetCertRegDWValueEx");
}
if (fPreserveClient)
{
// this means uninstall server component and keep web client
hr = CreateWebClientRegEntries(FALSE, pComp);
_JumpIfError(hr, error, "CreateWebClientRegEntries");
}
DeleteObsoleteResidue();
DeleteOldFilesAndDirectories(pComp);
certocmBumpGasGauge(pComp, _UNINSTALLPERCENT(9) DBGPARM(L"UninstallCore"));
if (fUseDS)
{
hr = RemoveCAInDS(pwszSanitizedCAName);
_PrintIfError2(hr, "RemoveCAInDS", hr);
}
certocmBumpGasGauge(pComp, PerCentCompleteMax DBGPARM(L"UninstallCore"));
hr = S_OK;
error:
if (NULL != pwszSanitizedCAName)
{
LocalFree(pwszSanitizedCAName);
}
if (NULL != pwszSharedFolder)
{
LocalFree(pwszSharedFolder);
}
if (NULL != pwszDBDirectory)
{
LocalFree(pwszDBDirectory);
}
if (NULL != pwszLogDirectory)
{
LocalFree(pwszLogDirectory);
}
if (NULL != pwszSysDirectory)
{
LocalFree(pwszSysDirectory);
}
if (NULL != pwszTmpDirectory)
{
LocalFree(pwszTmpDirectory);
}
if (fCoInit)
{
CoUninitialize();
}
return(hr);
}
HRESULT
AddCAToRPCNullSessions()
{
HRESULT hr;
HKEY hRegKey = NULL;
char *pszOriginal = NULL;
char *psz;
DWORD cb;
DWORD cbTmp;
DWORD cbSum;
DWORD dwType;
hr = RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
szNULL_SESSION_REG_LOCATION,
0, // dwOptions
KEY_READ | KEY_WRITE,
&hRegKey);
_JumpIfError(hr, error, "RegOpenKeyExA");
// Need to get the size of the value first
hr = RegQueryValueExA(hRegKey, szNULL_SESSION_VALUE, 0, &dwType, NULL, &cb);
_JumpIfError(hr, error, "RegQueryValueExA");
if (REG_MULTI_SZ != dwType)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "RegQueryValueExA: Type");
}
cb += sizeof(rgcCERT_NULL_SESSION) - 1;
pszOriginal = (char *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cb);
if (NULL == pszOriginal)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
// get the multi string of RPC null session pipes
hr = RegQueryValueExA(
hRegKey,
szNULL_SESSION_VALUE,
0,
&dwType,
(BYTE *) pszOriginal,
&cb);
_JumpIfError(hr, error, "RegQueryValueExA");
psz = pszOriginal;
// look for CERT in the list
cbSum = 0;
while (TRUE)
{
if (0 == strcmp(rgcCERT_NULL_SESSION, psz))
{
break;
}
cbTmp = strlen(psz) + 1;
psz += cbTmp;
cbSum += cbTmp;
if (cb < cbSum + 1)
{
break;
}
if ('\0' == psz[0])
{
// add the CA pipe to the multi string
CopyMemory(psz, rgcCERT_NULL_SESSION, sizeof(rgcCERT_NULL_SESSION));
// set the new multi string in the reg value
hr = RegSetValueExA(
hRegKey,
szNULL_SESSION_VALUE,
0,
REG_MULTI_SZ,
(BYTE *) pszOriginal,
cbSum + sizeof(rgcCERT_NULL_SESSION));
_JumpIfError(hr, error, "RegSetValueExA");
break;
}
}
hr = S_OK;
error:
if (NULL != pszOriginal)
{
LocalFree(pszOriginal);
}
if (NULL != hRegKey)
{
RegCloseKey(hRegKey);
}
return(hr);
}
HRESULT
AddCARegKeyToRegConnectExemptions()
{
// add ourselves to list of people that take ACLs seriously
// and should be allowed to reveal our key to outsiders.
HRESULT hr;
LPWSTR pszExempt = NULL;
HKEY hkeyWinReg = NULL, hkeyAllowedPaths = NULL;
LPWSTR pszTmp;
DWORD dwDisposition, dwType;
DWORD cb=0, cbRegKeyCertSrvPath = (wcslen(wszREGKEYCERTSVCPATH)+1) *sizeof(WCHAR);
// carefully query this -- if it doesn't exist, we don't have to apply workaround
hr = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\SecurePipeServers\\Winreg",
0,
KEY_ALL_ACCESS,
&hkeyWinReg);
_JumpIfError(hr, Ret, "RegOpenKeyEx");
// creation of this optional key is always ok if above key exists
hr = RegCreateKeyEx(
hkeyWinReg,
L"AllowedPaths",
NULL,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
&hkeyAllowedPaths,
&dwDisposition);
_JumpIfError(hr, Ret, "RegCreateKeyEx exempt regkey");
hr = RegQueryValueEx(
hkeyAllowedPaths,
L"Machine",
NULL, // reserved
&dwType, // type
NULL, // pb
&cb);
_PrintIfError(hr, "RegQueryValueEx exempt regkey 1");
if ((hr == S_OK) && (dwType != REG_MULTI_SZ))
{
hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
_JumpError(hr, Ret, "RegQueryValueEx invalid type");
}
// always include at least a terminator
if (cb < sizeof(WCHAR))
cb = sizeof(WCHAR);
pszExempt = (LPWSTR)LocalAlloc(LMEM_FIXED, cb + cbRegKeyCertSrvPath );
_JumpIfOutOfMemory(hr, Ret, pszExempt);
// start with double null for safety
pszExempt[0] = L'\0';
pszExempt[1] = L'\0';
hr = RegQueryValueEx(
hkeyAllowedPaths,
L"Machine",
NULL, // reserved
NULL, // type
(PBYTE)pszExempt, // pb
&cb);
_PrintIfError(hr, "RegQueryValueEx exempt regkey 2");
pszTmp = pszExempt;
while(pszTmp[0] != L'\0') // skip all existing strings
{
// if entry already exists, bail
if (0 == lstrcmpi(wszREGKEYCERTSVCPATH, pszTmp))
{
hr = S_OK;
goto Ret;
}
pszTmp += wcslen(pszTmp)+1;
}
wcscpy(&pszTmp[0], wszREGKEYCERTSVCPATH);
pszTmp[wcslen(wszREGKEYCERTSVCPATH)+1] = L'\0'; // double NULL
hr = RegSetValueEx(
hkeyAllowedPaths,
L"Machine",
NULL,
REG_MULTI_SZ,
(PBYTE)pszExempt,
cb + cbRegKeyCertSrvPath);
_JumpIfError(hr, Ret, "RegSetValueEx exempt regkey");
Ret:
if (hkeyAllowedPaths)
RegCloseKey(hkeyAllowedPaths);
if (hkeyWinReg)
RegCloseKey(hkeyWinReg);
if (pszExempt)
LocalFree(pszExempt);
return hr;
}
HRESULT
helperGetFilesNotToRestore(
PER_COMPONENT_DATA *pComp,
OUT WCHAR **ppwszz)
{
HRESULT hr;
WCHAR *pwsz;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
DWORD cwc;
WCHAR const wszDBDIRPATTERN[] = L"\\*.edb";
WCHAR const wszDBLOGDIRPATTERN[] = L"\\*";
*ppwszz = NULL;
cwc = wcslen(pServer->pwszDBDirectory) +
WSZARRAYSIZE(wszDBDIRPATTERN) +
1 +
wcslen(pServer->pwszLogDirectory) +
WSZARRAYSIZE(wszDBLOGDIRPATTERN) +
1 +
1;
pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, pwsz);
*ppwszz = pwsz;
wcscpy(pwsz, pServer->pwszDBDirectory);
wcscat(pwsz, wszDBDIRPATTERN);
pwsz += wcslen(pwsz) + 1;
wcscpy(pwsz, pServer->pwszLogDirectory);
wcscat(pwsz, wszDBLOGDIRPATTERN);
pwsz += wcslen(pwsz) + 1;
*pwsz = L'\0';
CSASSERT(cwc == (DWORD) (pwsz - *ppwszz + 1));
hr = S_OK;
error:
return(hr);
}
HRESULT
CreateServerRegEntries(
HWND hwnd,
BOOL fUpgrade,
PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
HKEY hKeyBase = NULL;
WCHAR *pwszCLSIDCertGetConfig = NULL;
WCHAR *pwszCLSIDCertRequest = NULL;
WCHAR *pwszCRLPeriod = NULL;
WCHAR *pwszCRLDeltaPeriod = NULL;
WCHAR *pwszzCRLPublicationValue = NULL;
WCHAR *pwszzCACertPublicationValue = NULL;
WCHAR *pwszzRequestExtensionList = NULL;
WCHAR *pwszzDisableExtensionList = NULL;
WCHAR *pwszzFilesNotToRestore = NULL;
WCHAR *pwszProvNameReg = NULL;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
DWORD dwUpgradeFlags = fUpgrade ? CSREG_UPGRADE : 0x0;
DWORD dwAppendFlags = 0x0; // default
DWORD dwCRLPeriodCount, dwCRLDeltaPeriodCount;
LDAP *pld = NULL;
BSTR strDomainDN = NULL;
BSTR strConfigDN = NULL;
// no error checking?
hr = AddCAToRPCNullSessions();
_PrintIfError(hr, "AddCAToRPCNullSessions");
hr = AddCARegKeyToRegConnectExemptions();
_PrintIfError(hr, "AddCARegKeyToRegConnectExemptions");
// create the CA key, so we can set security on it.
hr = myCreateCertRegKey(pServer->pwszSanitizedName, NULL, NULL);
_JumpIfError(hr, error, "myCreateCertRegKey");
// configuration level
// active ca
hr = mySetCertRegStrValueEx(
fUpgrade,
NULL,
NULL,
NULL,
wszREGACTIVE,
pServer->pwszSanitizedName);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGACTIVE);
if (NULL != pServer->pwszSharedFolder)
{
// shared folder
hr = mySetCertRegStrValueEx(
fUpgrade,
NULL,
NULL,
NULL,
wszREGDIRECTORY,
pServer->pwszSharedFolder);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGDIRECTORY);
}
// db dir
hr = mySetCertRegStrValueEx(
fUpgrade,
NULL,
NULL,
NULL,
wszREGDBDIRECTORY,
pServer->pwszDBDirectory);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGDBDIRECTORY);
// log dir
hr = mySetCertRegStrValueEx(
fUpgrade,
NULL,
NULL,
NULL,
wszREGDBLOGDIRECTORY,
pServer->pwszLogDirectory);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGDBLOGDIRECTORY);
// db tmp dir
hr = mySetCertRegStrValueEx(
fUpgrade,
NULL,
NULL,
NULL,
wszREGDBTEMPDIRECTORY,
pServer->pwszLogDirectory);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGDBTEMPDIRECTORY);
// db sys dir
hr = mySetCertRegStrValueEx(
fUpgrade,
NULL,
NULL,
NULL,
wszREGDBSYSDIRECTORY,
pServer->pwszLogDirectory);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGDBSYSDIRECTORY);
hr = mySetCertRegDWValueEx(
fUpgrade,
NULL,
NULL,
NULL,
wszREGDBSESSIONCOUNT,
DBSESSIONCOUNTDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGDBSESSIONCOUNT);
hr = SetCertSrvInstallVersion();
_JumpIfError(hr, error, "SetCertSrvInstallVersion");
if (!fUpgrade)
{
// preserve db
hr = SetSetupStatus(NULL, SETUP_CREATEDB_FLAG, !pServer->fPreserveDB);
_JumpIfError(hr, error, "SetSetupStatus");
}
// ca level
if (!fUpgrade && pServer->fUseDS)
{
hr = myLdapOpen(&pld, &strDomainDN, &strConfigDN);
_JumpIfError(hr, error, "myLdapOpen");
// Config DN
hr = mySetCertRegStrValueEx(
FALSE,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGDSCONFIGDN,
strConfigDN);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGDSCONFIGDN);
// Domain DN
hr = mySetCertRegStrValueEx(
FALSE,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGDSDOMAINDN,
strDomainDN);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGDSDOMAINDN);
}
// ca type
CSASSERT(IsEnterpriseCA(pServer->CAType) || IsStandaloneCA(pServer->CAType));
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCATYPE,
pServer->CAType);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGCATYPE);
// use DS flag
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCAUSEDS,
pServer->fUseDS);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGCAUSEDS);
// teletex flag
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGFORCETELETEX,
ENUM_TELETEX_AUTO | ENUM_TELETEX_UTF8);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGFORCETELETEX);
hr = mySetCertRegMultiStrValueEx(
dwUpgradeFlags,
pServer->pwszSanitizedName,
NULL,
NULL,
wszSECUREDATTRIBUTES,
wszzDEFAULTSIGNEDATTRIBUTES);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValueEx", wszSECUREDATTRIBUTES,);
// common name
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCOMMONNAME,
pServer->pwszCACommonName);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGCOMMONNAME);
// enable reg
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGENABLED,
TRUE);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGENABLED);
// policy flag
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGPOLICYFLAGS,
0);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGPOLICYFLAGS);
// enroll compatible flag, always turn it off
// BUG, consider use mySetCertRegDWValueEx with fUpgrade
// after W2K to support CertEnrollCompatible upgrade
hr = mySetCertRegDWValue(
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCERTENROLLCOMPATIBLE,
FALSE);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValue", wszREGCERTENROLLCOMPATIBLE);
// Cert Server CRL Edit Flags
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCRLEDITFLAGS,
EDITF_ENABLEAKIKEYID);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGCRLEDITFLAGS);
// Cert Server CRL Flags
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCRLFLAGS,
CRLF_DELETE_EXPIRED_CRLS);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGCRLFLAGS);
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGENFORCEX500NAMELENGTHS,
TRUE);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGENFORCEX500NAMELENGTHS);
// subject template
hr = mySetCertRegMultiStrValueEx(
0, // dwUpgradeFlags: always overwrite!
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGSUBJECTTEMPLATE,
wszzREGSUBJECTTEMPLATEVALUE);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValueEx", wszREGSUBJECTTEMPLATE);
// (hard code) clock skew minutes
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCLOCKSKEWMINUTES,
CCLOCKSKEWMINUTESDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGCLOCKSKEWMINUTES);
// (hard code) log level
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGLOGLEVEL,
CERTLOG_WARNING);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGLOGLEVEL);
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGHIGHSERIAL,
0);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGLOGLEVEL);
// register server name
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCASERVERNAME,
pComp->pwszServerName);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGCASERVERNAME);
// default validity period string and count for issued certs
// use years for string
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGVALIDITYPERIODSTRING,
wszVALIDITYPERIODSTRINGDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGVALIDITYPERIODSTRING);
// validity period count
// use 1 year for standalone and 2 years for enterprise
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGVALIDITYPERIODCOUNT,
IsEnterpriseCA(pServer->CAType)?
dwVALIDITYPERIODCOUNTDEFAULT_ENTERPRISE :
dwVALIDITYPERIODCOUNTDEFAULT_STANDALONE);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGVALIDITYPERIODCOUNT);
hr = mySetCertRegMultiStrValueEx(
dwUpgradeFlags,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCAXCHGCERTHASH,
NULL);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValueEx", wszREGCAXCHGCERTHASH);
hr = mySetCertRegMultiStrValueEx(
dwUpgradeFlags,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGKRACERTHASH,
NULL);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValueEx", wszREGKRACERTHASH);
hr = mySetCertRegDWValueEx(
dwUpgradeFlags,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGKRACERTCOUNT,
0);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGKRACERTCOUNT);
hr = mySetCertRegDWValueEx(
dwUpgradeFlags,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGKRAFLAGS,
0);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGKRAFLAGS);
// CRL Publication URLs:
hr = csiGetCRLPublicationURLTemplates(
pServer->fUseDS,
pComp->pwszSystem32,
&pwszzCRLPublicationValue);
_JumpIfError(hr, error, "csiGetCRLPublicationURLTemplates");
hr = mySetCertRegMultiStrValueEx(
dwUpgradeFlags | CSREG_MERGE,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCRLPUBLICATIONURLS,
pwszzCRLPublicationValue);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValueEx", wszREGCRLPUBLICATIONURLS);
// if this API returns non-null strings, it's got good data
hr = csiGetCRLPublicationParams(
TRUE,
&pwszCRLPeriod,
&dwCRLPeriodCount);
_PrintIfError(hr, "csiGetCRLPublicationParams");
// crl period string
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCRLPERIODSTRING,
(pwszCRLPeriod == NULL) ? wszCRLPERIODSTRINGDEFAULT : pwszCRLPeriod);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGCRLPERIODSTRING);
// crl period count
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCRLPERIODCOUNT,
(pwszCRLPeriod == NULL) ? dwCRLPERIODCOUNTDEFAULT : dwCRLPeriodCount);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGCRLPERIODCOUNT);
// crl overlap period string
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCRLOVERLAPPERIODSTRING,
wszCRLOVERLAPPERIODSTRINGDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGCRLOVERLAPPERIODSTRING);
// crl overlap period count
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCRLOVERLAPPERIODCOUNT,
dwCRLOVERLAPPERIODCOUNTDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGCRLOVERLAPPERIODCOUNT);
// if this API returns non-null strings, it's got good data
hr = csiGetCRLPublicationParams(
FALSE, // delta
&pwszCRLDeltaPeriod,
&dwCRLDeltaPeriodCount);
_PrintIfError(hr, "csiGetCRLPublicationParams");
// delta crl period string
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCRLDELTAPERIODSTRING,
(pwszCRLDeltaPeriod == NULL) ? wszCRLDELTAPERIODSTRINGDEFAULT : pwszCRLDeltaPeriod);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGCRLDELTAPERIODSTRING);
// delta crl period count
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCRLDELTAPERIODCOUNT,
(pwszCRLDeltaPeriod == NULL) ? dwCRLPERIODCOUNTDEFAULT : dwCRLDeltaPeriodCount);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGCRLDELTAPERIODCOUNT);
// delta crl overlap period string
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCRLDELTAOVERLAPPERIODSTRING,
wszCRLDELTAOVERLAPPERIODSTRINGDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGCRLDELTAOVERLAPPERIODSTRING);
// delta crl overlap period count
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCRLDELTAOVERLAPPERIODCOUNT,
dwCRLDELTAOVERLAPPERIODCOUNTDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGCRLDELTAOVERLAPPERIODCOUNT);
// CA xchg cert validity period string
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCAXCHGVALIDITYPERIODSTRING,
wszCAXCHGVALIDITYPERIODSTRINGDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGCRLDELTAOVERLAPPERIODSTRING);
// CA xchg cert validity period count
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCAXCHGVALIDITYPERIODCOUNT,
dwCAXCHGVALIDITYPERIODCOUNTDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGCRLDELTAOVERLAPPERIODCOUNT);
// CA xchg cert overlap period string
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCAXCHGOVERLAPPERIODSTRING,
wszCAXCHGOVERLAPPERIODSTRINGDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGCRLDELTAOVERLAPPERIODSTRING);
// CA xchg cert overlap period count
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCAXCHGOVERLAPPERIODCOUNT,
dwCAXCHGOVERLAPPERIODCOUNTDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGCRLDELTAOVERLAPPERIODCOUNT);
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGMAXINCOMINGMESSAGESIZE,
MAXINCOMINGMESSAGESIZEDEFAULT);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx", wszREGMAXINCOMINGMESSAGESIZE);
if (NULL != pServer->pwszSharedFolder)
{
// register CA file name for certhier and renewal
hr = mySetCARegFileNameTemplate(
wszREGCACERTFILENAME,
pComp->pwszServerName,
pServer->pwszSanitizedName,
pServer->pwszCACertFile);
_JumpIfError(hr, error, "SetRegCertFileName");
}
// policy
// create default policy entry explicitly to get correct acl if upgrade
hr = myCreateCertRegKeyEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY);
_JumpIfErrorStr(hr, error, "myCreateCertRegKeyEx", wszCLASS_CERTPOLICY);
// if customized policy, create a new entry with correct acl
if (fUpgrade &&
NULL != pServer->pwszCustomPolicy &&
0 != wcscmp(wszCLASS_CERTPOLICY, pServer->pwszCustomPolicy) )
{
hr = myCreateCertRegKeyEx(
TRUE, // upgrade
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
pServer->pwszCustomPolicy);
_JumpIfError(hr, error, "myCreateCertRegKey");
}
// set default policy
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
NULL,
wszREGACTIVE,
(fUpgrade && (NULL != pServer->pwszCustomPolicy)) ?
pServer->pwszCustomPolicy :
wszCLASS_CERTPOLICY);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGACTIVE);
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGREVOCATIONTYPE,
pServer->dwRevocationFlags | pServer->dwUpgradeRevFlags);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGREVOCATIONTYPE);
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGCAPATHLENGTH,
CAPATHLENGTH_INFINITE);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGCAPATHLENGTH);
// revocation url
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGREVOCATIONURL,
g_wszASPRevocationURLTemplate);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGREVOCATIONURL);
// Exit module publish flags
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYEXITMODULES,
wszCLASS_CERTEXIT,
wszREGCERTPUBLISHFLAGS,
pServer->fUseDS ?
EXITPUB_DEFAULT_ENTERPRISE :
EXITPUB_DEFAULT_STANDALONE);
_JumpIfErrorStr(
hr,
error,
"mySetCertRegStrValueEx",
wszREGCERTPUBLISHFLAGS);
// Enable Request Extensions:
hr = helperGetRequestExtensionList(pComp, &pwszzRequestExtensionList);
_JumpIfError(hr, error, "helperGetRequestExtensionList");
hr = mySetCertRegMultiStrValueEx(
dwUpgradeFlags | CSREG_MERGE,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGENABLEREQUESTEXTENSIONLIST,
pwszzRequestExtensionList);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValueEx", wszREGENABLEREQUESTEXTENSIONLIST);
hr = helperGetDisableExtensionList(pComp, &pwszzDisableExtensionList);
_JumpIfError(hr, error, "helperGetDisableExtensionList");
// Disables Template Extensions:
hr = mySetCertRegMultiStrValueEx(
dwUpgradeFlags | CSREG_MERGE,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGDISABLEEXTENSIONLIST,
pwszzDisableExtensionList);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValueEx", wszREGDISABLEEXTENSIONLIST);
// Subject Alt Name Extension
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGSUBJECTALTNAME,
wszREGSUBJECTALTNAMEVALUE);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGSUBJECTALTNAME);
// Subject Alt Name 2 Extension
hr = mySetCertRegStrValueEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGSUBJECTALTNAME2,
wszREGSUBJECTALTNAME2VALUE);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGSUBJECTALTNAME2);
// Request Disposition
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGREQUESTDISPOSITION,
IsEnterpriseCA(pServer->CAType)?
REQDISP_DEFAULT_ENTERPRISE :
REQDISP_DEFAULT_STANDALONE);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValueEx",
wszREGREQUESTDISPOSITION);
// Edit Flags
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGEDITFLAGS,
IsEnterpriseCA(pServer->CAType)?
(EDITF_DEFAULT_ENTERPRISE | pServer->dwUpgradeEditFlags) :
(EDITF_DEFAULT_STANDALONE | pServer->dwUpgradeEditFlags));
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx", wszREGEDITFLAGS);
// Issuer Cert URL Flags
hr = mySetCertRegDWValueEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGISSUERCERTURLFLAGS,
pServer->fUseDS?
ISSCERT_DEFAULT_DS : ISSCERT_DEFAULT_NODS);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValueEx",
wszREGISSUERCERTURLFLAGS);
hr = mySetCertRegMultiStrValueEx(
dwUpgradeFlags,
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
wszREGDEFAULTSMIME,
wszzREGVALUEDEFAULTSMIME);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValueEx", wszREGDEFAULTSMIME);
hr = csiGetCACertPublicationURLTemplates(
pServer->fUseDS,
pComp->pwszSystem32,
&pwszzCACertPublicationValue);
_JumpIfError(hr, error, "csiGetCACertPublicationURLTemplates");
hr = mySetCertRegMultiStrValueEx(
dwUpgradeFlags | CSREG_MERGE,
pServer->pwszSanitizedName,
NULL,
NULL,
wszREGCACERTPUBLICATIONURLS,
pwszzCACertPublicationValue);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValueEx", wszREGCRLPUBLICATIONURLS);
// exit
// create default exit entry to get correct acl if upgrade
hr = myCreateCertRegKeyEx(
fUpgrade,
pServer->pwszSanitizedName,
wszREGKEYEXITMODULES,
wszCLASS_CERTEXIT);
_JumpIfErrorStr(hr, error, "myCreateCertRegKeyEx", wszCLASS_CERTPOLICY);
// if customized exit, create a new entry with correct acl
if (fUpgrade &&
NULL != pServer->pwszzCustomExit &&
0 != wcscmp(wszCLASS_CERTEXIT, pServer->pwszzCustomExit) )
{
// create a new entry for custom exit
hr = myCreateCertRegKeyEx(
TRUE, // upgrade
pServer->pwszSanitizedName,
wszREGKEYEXITMODULES,
pServer->pwszzCustomExit);
_JumpIfError(hr, error, "myCreateCertRegKey");
}
// set default exit
hr = mySetCertRegMultiStrValueEx(
dwUpgradeFlags,
pServer->pwszSanitizedName,
wszREGKEYEXITMODULES,
NULL,
wszREGACTIVE,
(fUpgrade && (NULL != pServer->pwszzCustomExit)) ?
pServer->pwszzCustomExit :
wszCLASS_CERTEXIT L"\0");
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValueEx", wszREGACTIVE);
// set some absolute keys and values
hr = mySetAbsRegMultiStrValue(
wszREGKEYKEYSNOTTORESTORE,
wszREGRESTORECERTIFICATEAUTHORITY,
wszzREGVALUERESTORECERTIFICATEAUTHORITY);
_JumpIfError(hr, error, "mySetAbsRegMultiStrValue");
hr = helperGetFilesNotToRestore(pComp, &pwszzFilesNotToRestore);
_JumpIfError(hr, error, "helperGetFilesNotToRestore");
hr = mySetAbsRegMultiStrValue(
wszREGKEYFILESNOTTOBACKUP,
wszREGRESTORECERTIFICATEAUTHORITY,
pwszzFilesNotToRestore);
_JumpIfError(hr, error, "mySetAbsRegMultiStrValue");
// ICertGetConfig
hr = StringFromCLSID(CLSID_CCertGetConfig, &pwszCLSIDCertGetConfig);
_JumpIfError(hr, error, "StringFromCLSID(CCertGetConfig)");
hr = mySetAbsRegStrValue(
wszREGKEYKEYRING,
wszREGCERTGETCONFIG,
pwszCLSIDCertGetConfig);
_JumpIfError(hr, error, "mySetAbsRegStrValue");
// ICertCertRequest
hr = StringFromCLSID(CLSID_CCertRequest, &pwszCLSIDCertRequest);
_JumpIfError(hr, error, "StringFromCLSID(CCertRequest)");
hr = mySetAbsRegStrValue(
wszREGKEYKEYRING,
wszREGCERTREQUEST,
pwszCLSIDCertRequest);
_JumpIfError(hr, error, "mySetAbsRegStrValue");
if (NULL != pServer->pCSPInfo &&
NULL != pServer->pHashInfo)
{
WCHAR const *pwszProvName = pServer->pCSPInfo->pwszProvName;
DWORD dwProvType;
ALG_ID idAlg;
BOOL fMachineKeyset;
DWORD dwKeySize;
if (0 == lstrcmpi(pwszProvName, MS_DEF_PROV_W))
{
pwszProvName = MS_STRONG_PROV_W;
}
hr = SetCertSrvCSP(
FALSE, // fEncryptionCSP
pServer->pwszSanitizedName,
pServer->pCSPInfo->dwProvType,
pwszProvName,
pServer->pHashInfo->idAlg,
pServer->pCSPInfo->fMachineKeyset,
0); // dwKeySize
_JumpIfError(hr, error, "SetCertSrvCSP");
hr = myGetCertSrvCSP(
TRUE, // fEncryptionCSP
pServer->pwszSanitizedName,
&dwProvType,
&pwszProvNameReg,
&idAlg,
&fMachineKeyset,
&dwKeySize); // pdwKeySize
if (S_OK != hr)
{
_PrintError(hr, "myGetCertSrvCSP");
dwProvType = pServer->pCSPInfo->dwProvType;
idAlg = CALG_3DES;
fMachineKeyset = pServer->pCSPInfo->fMachineKeyset;
dwKeySize = 1024;
}
else if (NULL != pwszProvNameReg && L'\0' != *pwszProvNameReg)
{
pwszProvName = pwszProvNameReg;
if (0 == lstrcmpi(pwszProvName, MS_DEF_PROV_W))
{
pwszProvName = MS_STRONG_PROV_W;
}
}
hr = SetCertSrvCSP(
TRUE, // fEncryptionCSP
pServer->pwszSanitizedName,
dwProvType,
pwszProvName,
idAlg,
fMachineKeyset,
dwKeySize); // dwKeySize
_JumpIfError(hr, error, "SetCertSrvCSP");
}
hr = S_OK;
error:
if (NULL != pwszProvNameReg)
{
LocalFree(pwszProvNameReg);
}
myLdapClose(pld, strDomainDN, strConfigDN);
if (NULL != pwszCLSIDCertGetConfig)
{
CoTaskMemFree(pwszCLSIDCertGetConfig);
}
if (NULL != pwszCRLPeriod)
{
LocalFree(pwszCRLPeriod);
}
if (NULL != pwszCRLDeltaPeriod)
{
LocalFree(pwszCRLDeltaPeriod);
}
if (NULL != pwszCLSIDCertRequest)
{
CoTaskMemFree(pwszCLSIDCertRequest);
}
if (NULL != pwszzCRLPublicationValue)
{
LocalFree(pwszzCRLPublicationValue);
}
if (NULL != pwszzCACertPublicationValue)
{
LocalFree(pwszzCACertPublicationValue);
}
if (NULL != pwszzRequestExtensionList)
{
LocalFree(pwszzRequestExtensionList);
}
if (NULL != pwszzDisableExtensionList)
{
LocalFree(pwszzDisableExtensionList);
}
if (NULL != pwszzFilesNotToRestore)
{
LocalFree(pwszzFilesNotToRestore);
}
if (NULL != hKeyBase)
{
RegCloseKey(hKeyBase);
}
CSILOG(hr, IDS_LOG_CREATE_SERVER_REG, NULL, NULL, NULL);
return(hr);
}
HRESULT
UpgradeRevocationURLReplaceParam(
IN BOOL fPolicy,
IN BOOL fMultiString,
IN WCHAR const *pwszSanitizedName,
IN WCHAR const *pwszValueName)
{
HRESULT hr;
WCHAR *pwszzValue = NULL;
WCHAR *pwsz;
BOOL fModified = FALSE;
CSASSERT(
WSZARRAYSIZE(wszFCSAPARM_CERTFILENAMESUFFIX) ==
WSZARRAYSIZE(wszFCSAPARM_CRLFILENAMESUFFIX));
// getMultiStr will read REG_SZs as well and double-terminate
hr = myGetCertRegMultiStrValue(
pwszSanitizedName,
fPolicy ? wszREGKEYPOLICYMODULES : wszREGKEYEXITMODULES,
fPolicy ? wszCLASS_CERTPOLICY : wszCLASS_CERTEXIT,
pwszValueName,
&pwszzValue);
_JumpIfErrorStr2(hr, error, "myGetCertRegMultiStrValue", pwszValueName, hr);
for (pwsz = pwszzValue; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
{
WCHAR *pwszT = pwsz;
// Replace wszFCSAPARM_CERTFILENAMESUFFIX with
// wszFCSAPARM_CRLFILENAMESUFFIX. Beta 3's registry values incorrectly
// used a Cert Suffix instead of CRL Suffix.
while (TRUE)
{
DWORD i;
pwszT = wcschr(pwszT, wszFCSAPARM_CERTFILENAMESUFFIX[0]);
if (NULL == pwszT)
{
break;
}
for (i = 1; ; i++)
{
if (i == WSZARRAYSIZE(wszFCSAPARM_CERTFILENAMESUFFIX))
{
CopyMemory(
pwszT,
wszFCSAPARM_CRLFILENAMESUFFIX,
i * sizeof(WCHAR));
pwszT += i;
fModified = TRUE;
break;
}
if (pwszT[i] != wszFCSAPARM_CERTFILENAMESUFFIX[i])
{
pwszT++;
break;
}
}
}
}
if (fModified)
{
if (fMultiString)
{
// set as REG_MULTI_SZ
hr = mySetCertRegMultiStrValue(
pwszSanitizedName,
fPolicy ? wszREGKEYPOLICYMODULES : wszREGKEYEXITMODULES,
fPolicy ? wszCLASS_CERTPOLICY : wszCLASS_CERTEXIT,
pwszValueName,
pwszzValue);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValue", pwszValueName);
}
else
{
// set as REG_SZ
hr = mySetCertRegStrValue(
pwszSanitizedName,
fPolicy ? wszREGKEYPOLICYMODULES : wszREGKEYEXITMODULES,
fPolicy ? wszCLASS_CERTPOLICY : wszCLASS_CERTEXIT,
pwszValueName,
pwszzValue);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValue", pwszValueName);
}
}
error:
if (NULL != pwszzValue)
{
LocalFree(pwszzValue);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
UpgradeRevocationURLRemoveParam(
IN WCHAR const *pwszSanitizedName,
IN WCHAR const *pwszValueName)
{
HRESULT hr;
WCHAR *pwszValue = NULL;
WCHAR *pwsz;
BOOL fModified = FALSE;
WCHAR *pwszT;
hr = myGetCertRegStrValue(
pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
pwszValueName,
&pwszValue);
_JumpIfErrorStr2(hr, error, "myGetCertRegStrValue", pwszValueName, hr);
pwszT = pwszValue;
// Remove wszFCSAPARM_CERTFILENAMESUFFIX from the Netscape Revocaton URL
// It should never have been written out in Beta 3's registry value.
while (TRUE)
{
DWORD i;
pwszT = wcschr(pwszT, wszFCSAPARM_CERTFILENAMESUFFIX[0]);
if (NULL == pwszT)
{
break;
}
for (i = 1; ; i++)
{
if (i == WSZARRAYSIZE(wszFCSAPARM_CERTFILENAMESUFFIX))
{
MoveMemory(
pwszT,
&pwszT[i],
(wcslen(&pwszT[i]) + 1) * sizeof(WCHAR));
pwszT += i;
fModified = TRUE;
break;
}
if (pwszT[i] != wszFCSAPARM_CERTFILENAMESUFFIX[i])
{
pwszT++;
break;
}
}
}
if (fModified)
{
hr = mySetCertRegStrValue(
pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
pwszValueName,
pwszValue);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValue", pwszValueName);
}
error:
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
WCHAR const *apwszB3ExitEntriesToFix[] =
{
wszREGLDAPREVOCATIONDNTEMPLATE_OLD,
NULL
};
HRESULT
UpgradeCRLPath(
WCHAR const *pwszSanitizedName)
{
HRESULT hr;
WCHAR *pwszzCRLPath = NULL;
WCHAR *pwszzFixedCRLPath = NULL;
WCHAR *pwsz;
BOOL fRenewReady = TRUE;
DWORD dwSize = 0;
// get current crl path
hr = myGetCertRegMultiStrValue(
pwszSanitizedName,
NULL,
NULL,
wszREGCRLPATH_OLD,
&pwszzCRLPath);
_JumpIfErrorStr(hr, error, "myGetCertRegStrValue", wszREGCRLPATH_OLD);
// to see if it is in renew ready format
for (pwsz = pwszzCRLPath; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
{
dwSize += wcslen(pwsz) + 1;
if (NULL == wcsstr(pwsz, wszFCSAPARM_CRLFILENAMESUFFIX))
{
// found one without suffix
fRenewReady = FALSE;
// add suffix len
dwSize += WSZARRAYSIZE(wszFCSAPARM_CRLFILENAMESUFFIX);
}
}
if (!fRenewReady)
{
++dwSize; // multi string
// at least one of crl path missed suffix
pwszzFixedCRLPath = (WCHAR*)LocalAlloc(LMEM_FIXED,
dwSize * sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, pwszzFixedCRLPath);
WCHAR *pwszPt = pwszzFixedCRLPath;
for (pwsz = pwszzCRLPath; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
{
// copy over whole path 1st
wcscpy(pwszPt, pwsz);
if (NULL == wcsstr(pwszPt, wszFCSAPARM_CRLFILENAMESUFFIX))
{
// miss suffix, find file portion
WCHAR *pwszFile = wcsrchr(pwszPt, L'\\');
if (NULL == pwszFile)
{
// may be relative path, point to begin
pwszFile = pwszPt;
}
// find crl extension portion
WCHAR *pwszCRLExt = wcsrchr(pwszFile, L'.');
if (NULL != pwszCRLExt)
{
// insert suffix
wcscpy(pwszCRLExt, wszFCSAPARM_CRLFILENAMESUFFIX);
// add extension portion from original buffer
wcscat(pwszCRLExt,
pwsz + SAFE_SUBTRACT_POINTERS(pwszCRLExt, pwszPt));
}
else
{
// no crl file extension, append suffix at end
wcscat(pwszPt, wszFCSAPARM_CRLFILENAMESUFFIX);
}
}
// update pointer
pwszPt += wcslen(pwszPt) + 1;
}
// mutil string
*pwszPt = L'\0';
CSASSERT(dwSize == SAFE_SUBTRACT_POINTERS(pwszPt, pwszzFixedCRLPath) + 1);
// reset crl path with the fixed crl path
hr = mySetCertRegMultiStrValue(
pwszSanitizedName,
NULL,
NULL,
wszREGCRLPATH_OLD,
pwszzFixedCRLPath);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValue", wszREGCRLPATH_OLD);
}
hr = S_OK;
error:
if (NULL != pwszzCRLPath)
{
LocalFree(pwszzCRLPath);
}
if (NULL != pwszzFixedCRLPath)
{
LocalFree(pwszzFixedCRLPath);
}
return hr;
}
typedef struct _URLPREFIXSTRUCT
{
WCHAR const *pwszURLPrefix;
DWORD dwURLFlags;
} URLPREFIXSTRUCT;
//array of cdp url type and its default usage which is prefix of url
URLPREFIXSTRUCT aCDPURLPrefixList[] =
{
{L"file:", CSURL_ADDTOCERTCDP | CSURL_ADDTOFRESHESTCRL | CSURL_ADDTOCRLCDP},
{L"http:", CSURL_ADDTOCERTCDP | CSURL_ADDTOFRESHESTCRL | CSURL_ADDTOCRLCDP},
{L"ldap:", CSURL_SERVERPUBLISH | CSURL_ADDTOCERTCDP | CSURL_ADDTOFRESHESTCRL | CSURL_ADDTOCRLCDP},
{NULL, 0}
};
//array of aia url type and its default usage which is prefix of url
URLPREFIXSTRUCT aAIAURLPrefixList[] =
{
{L"file:", CSURL_ADDTOCERTCDP},
{L"http:", CSURL_ADDTOCERTCDP},
{L"ldap:", CSURL_ADDTOCERTCDP | CSURL_SERVERPUBLISH},
{NULL, 0}
};
#define wszURLPREFIXFORMAT L"%d:"
//pass an old url, determine what is prefix in a format of "XX:"
HRESULT
DetermineURLPrefixFlags(
IN BOOL fDisabled,
IN BOOL fCDP,
IN WCHAR const *pwszURL,
IN WCHAR *pwszPrefixFlags)
{
HRESULT hr;
URLPREFIXSTRUCT *pURLPrefix;
DWORD dwPathFlags;
WCHAR *pwszT;
WCHAR *pwszLower = NULL;
//default to disable
wsprintf(pwszPrefixFlags, wszURLPREFIXFORMAT, 0);
if (fDisabled)
{
//easy
goto done;
}
if (myIsFullPath(pwszURL, &dwPathFlags))
{
//local path, easy
wsprintf(pwszPrefixFlags, wszURLPREFIXFORMAT, CSURL_SERVERPUBLISH);
goto done;
}
//make lower case url string
pwszLower = (WCHAR*)LocalAlloc(LMEM_FIXED,
(wcslen(pwszURL) + 1) * sizeof(WCHAR));
if (NULL == pwszLower)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(pwszLower, pwszURL);
CharLower(pwszLower);
//loop through to find out url type
for (pURLPrefix = fCDP ? aCDPURLPrefixList : aAIAURLPrefixList;
NULL != pURLPrefix->pwszURLPrefix; ++pURLPrefix)
{
pwszT = wcsstr(pwszLower, pURLPrefix->pwszURLPrefix);
if (0 == wcsncmp(pwszLower, pURLPrefix->pwszURLPrefix,
wcslen(pURLPrefix->pwszURLPrefix)))
{
//prefix appears at the begining
wsprintf(pwszPrefixFlags, wszURLPREFIXFORMAT, pURLPrefix->dwURLFlags);
goto done;
}
}
//nothing matches, keep 0 flag
done:
hr = S_OK;
error:
if (NULL != pwszLower)
{
LocalFree(pwszLower);
}
return hr;
}
//move old cdp or aia url from policy to a new location under ca
HRESULT
UpgradeMoveURLsLocation(
IN BOOL fCDP,
IN WCHAR const *pwszSanitizedName,
IN WCHAR const *pwszValueName)
{
HRESULT hr;
WCHAR *pwszzValue = NULL;
WCHAR *pwszzURLs = NULL;
BOOL fDisabled;
DWORD cURLs = 0; //count of url from multi_sz
DWORD dwLen = 0;
DWORD dwSize = 0; //total size of chars in multi_sz url exluding '-'
WCHAR *pwsz;
WCHAR *pwszT;
WCHAR *pwszNoMinus;
WCHAR wszPrefixFlags[9]; //should be enough
// get urls in the old location
hr = myGetCertRegMultiStrValue(
pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
pwszValueName,
&pwszzValue);
_JumpIfErrorStr2(hr, error, "myGetCertRegMultiStrValue", pwszValueName, hr);
// fix "-" prefix for disable and count size
for (pwsz = pwszzValue; L'\0' != *pwsz; pwsz += dwLen + 1)
{
//current url length
dwLen = wcslen(pwsz);
//update size
dwSize += dwLen;
++cURLs;
pwszNoMinus = pwsz;
while (L'-' == *pwszNoMinus)
{
//exclude prefix '-'s
--dwSize;
++pwszNoMinus;
}
}
//allocate buffer in "XX:URL" format
pwszzURLs = (WCHAR*)LocalAlloc(LMEM_FIXED,
(dwSize + cURLs * sizeof(wszPrefixFlags) + 1) * sizeof(WCHAR));
if (NULL == pwszzURLs)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pwszT = pwszzURLs;
//form string in new url format
for (pwsz = pwszzValue; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
{
fDisabled = FALSE;
pwszNoMinus = pwsz;
while (L'-' == *pwszNoMinus)
{
//exclude prefix '-'s
++pwszNoMinus;
fDisabled = TRUE;
}
hr = DetermineURLPrefixFlags(fDisabled, fCDP, pwszNoMinus, wszPrefixFlags);
_JumpIfErrorStr(hr, error, "DetermineURLPrefixFlags", pwszNoMinus);
//format "xx:url"
wcscpy(pwszT, wszPrefixFlags);
wcscat(pwszT, pwszNoMinus);
//ready for next url
pwszT += wcslen(pwszT) + 1;
}
//zz
*pwszT = L'\0';
pwszT = fCDP ? wszREGCRLPUBLICATIONURLS : wszREGCACERTPUBLICATIONURLS,
//move or merge to ca
hr = mySetCertRegMultiStrValueEx(
CSREG_UPGRADE | CSREG_MERGE,
pwszSanitizedName,
NULL,
NULL,
pwszT,
pwszzURLs);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValue", pwszT);
//remove url under policy
hr = myDeleteCertRegValue(
pwszSanitizedName,
wszREGKEYPOLICYMODULES,
wszCLASS_CERTPOLICY,
pwszValueName);
_PrintIfErrorStr(hr, "myGetCertRegMultiStrValue", pwszValueName);
hr = S_OK;
error:
if (NULL != pwszzValue)
{
LocalFree(pwszzValue);
}
if (NULL != pwszzURLs)
{
LocalFree(pwszzURLs);
}
return(hr);
}
WCHAR const *apwszPolicyCDPEntriesToFix[] =
{
wszREGLDAPREVOCATIONCRLURL_OLD, //"LDAPRevocationCRLURL"
wszREGREVOCATIONCRLURL_OLD, //"RevocationCRLURL"
wszREGFTPREVOCATIONCRLURL_OLD, //"FTPRevocationCRLURL"
wszREGFILEREVOCATIONCRLURL_OLD, //"FileRevocationCRLURL"
NULL
};
HRESULT
myPrintIfError(
IN HRESULT hrNew,
IN HRESULT hrOld,
IN CHAR const *psz,
IN OPTIONAL WCHAR const *pwsz)
{
if (S_OK != hrNew)
{
if (NULL != pwsz)
{
_PrintErrorStr(hrNew, psz, pwsz);
}
else
{
_PrintError(hrNew, psz);
}
if (S_OK == hrOld)
{
//save only oldest err
hrOld = hrNew;
}
}
return hrOld;
}
HRESULT
UpgradePolicyCDPURLs(
IN WCHAR const *pwszSanitizedName)
{
HRESULT hr = S_OK;
HRESULT hr2;
WCHAR const **ppwsz;
for (ppwsz = apwszPolicyCDPEntriesToFix; NULL != *ppwsz; ppwsz++)
{
// all entries are multi-valued
hr2 = UpgradeRevocationURLReplaceParam(
TRUE, TRUE, pwszSanitizedName, *ppwsz);
hr = myPrintIfError(hr2, hr, "UpgradeRevocationURLReplaceParam", *ppwsz);
hr2 = UpgradeMoveURLsLocation(TRUE, pwszSanitizedName, *ppwsz);
hr = myPrintIfError(hr2, hr, "UpgradeMoveURLsLocation", *ppwsz);
}
hr2 = UpgradeRevocationURLRemoveParam(pwszSanitizedName, wszREGREVOCATIONURL);
hr = myPrintIfError(hr2, hr, "UpgradeRevocationURLRemoveParam", wszREGREVOCATIONURL);
hr2 = UpgradeCRLPath(pwszSanitizedName);
hr = myPrintIfError(hr2, hr, "UpgradeCRLPath", NULL);
return(hr);
}
WCHAR const *apwszPolicyAIAEntriesToFix[] =
{
wszREGLDAPISSUERCERTURL_OLD, //"LDAPIssuerCertURL"
wszREGISSUERCERTURL_OLD, //"IssuerCertURL"
wszREGFTPISSUERCERTURL_OLD, //"FTPIssuerCertURL"
wszREGFILEISSUERCERTURL_OLD, //"FileIssuerCertURL"
NULL
};
HRESULT
UpgradePolicyAIAURLs(
IN WCHAR const *pwszSanitizedName)
{
HRESULT hr = S_OK;
HRESULT hr2;
WCHAR const **ppwsz;
for (ppwsz = apwszPolicyAIAEntriesToFix; NULL != *ppwsz; ppwsz++)
{
// all entries are multi-valued
hr2 = UpgradeMoveURLsLocation(FALSE, pwszSanitizedName, *ppwsz);
hr = myPrintIfError(hr2, hr, "UpgradeMoveURLsLocation", *ppwsz);
}
return(hr);
}
HRESULT
UpgradeExitRevocationURLs(
IN WCHAR const *pwszSanitizedName)
{
WCHAR const **ppwsz;
for (ppwsz = apwszB3ExitEntriesToFix; NULL != *ppwsz; ppwsz++)
{
// all entries are single-valued
UpgradeRevocationURLReplaceParam(FALSE, FALSE, pwszSanitizedName, *ppwsz);
}
return(S_OK);
}
// following code to determine if current policy/exit modules are custom
// if find any custom module and assign it to
// pServer->pwszCustomPolicy/Exit
// otherwise pServer->pwszCustomPolicy/Exit = NULL means default as active
#define wszCERTSRV10POLICYPROGID L"CertificateAuthority.Policy"
#define wszCERTSRV10EXITPROGID L"CertificateAuthority.Exit"
#define wszCLSID L"ClsID\\"
#define wszINPROCSERVER32 L"\\InprocServer32"
HRESULT
DetermineServerCustomModule(
PER_COMPONENT_DATA *pComp,
IN BOOL fPolicy)
{
HRESULT hr;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
// init
if (fPolicy)
{
if (NULL != pServer->pwszCustomPolicy)
{
LocalFree(pServer->pwszCustomPolicy);
pServer->pwszCustomPolicy = NULL;
}
}
else
{
if (NULL != pServer->pwszzCustomExit)
{
LocalFree(pServer->pwszzCustomExit);
pServer->pwszzCustomExit = NULL;
}
}
// build to build
// to pass what is the current active policy
if (fPolicy)
{
// policy module
hr = myGetCertRegStrValue(
pServer->pwszSanitizedName,
wszREGKEYPOLICYMODULES,
NULL,
wszREGACTIVE,
&pServer->pwszCustomPolicy);
_JumpIfError(hr, done, "myGetCertRegStrValue");
}
else
{
// exit module
hr = myGetCertRegMultiStrValue(
pServer->pwszSanitizedName,
wszREGKEYEXITMODULES,
NULL,
wszREGACTIVE,
&pServer->pwszzCustomExit);
_JumpIfError(hr, done, "myGetCertRegStrValue");
}
done:
hr = S_OK;
//error:
return hr;
}
HRESULT
UpgradeServerRegEntries(
HWND hwnd,
PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
WCHAR *pwszCRLPeriodString = NULL;
BOOL fUseNewCRLPublish = FALSE;
DWORD dwCRLPeriodCount;
DWORD Count;
BOOL fUpgradeW2K = CS_UPGRADE_WIN2000 == pComp->UpgradeFlag;
CSASSERT(
NULL != pServer->pwszSanitizedName &&
NULL != pServer->pccUpgradeCert);
// Description:
// - if upgrade and get this point, all necessary data structure
// should be loaded and created in LoadAndDetermineServerUpgradeInfo()
// - in this module, check all different upgrade cases,
// upgrade (move) reg entries
// - remove old unused reg entries if upgrade
// Note: each of above steps applys from config level down to ca then
// to policy, etc.
// - lastly call CreateServerRegEntries with upgrade flag
// CONFIGURATION LEVEL
// CA LEVEL
hr = myGetCARegHashCount(
pServer->pwszSanitizedName,
CSRH_CASIGCERT,
&Count);
_JumpIfError(hr, error, "myGetCARegHashCount");
if (0 == Count)
{
hr = mySetCARegHash(
pServer->pwszSanitizedName,
CSRH_CASIGCERT,
0, // iCert
pServer->pccUpgradeCert);
_JumpIfError(hr, error, "mySetCARegHash");
}
// POLICY LEVEL
{
//could fix two things, 1) W2K from B3 needs fixing token plus 2) or
// 2) W2K needs fix CDP location
hr = UpgradePolicyCDPURLs(pServer->pwszSanitizedName);
_PrintIfError(hr, "UpgradePolicyCDPURLs");
hr = UpgradePolicyAIAURLs(pServer->pwszSanitizedName);
_PrintIfError(hr, "UpgradePolicyAIAURLs");
hr = UpgradeExitRevocationURLs(pServer->pwszSanitizedName);
_PrintIfError(hr, "UpgradeExitRevocationURLs");
//UNDONE, we need move url for cdp and aia under policy to ca level
}
// EXIT LEVEL
// DELETE OLD AND UNUSED ENTRIES
hr = CreateServerRegEntries(hwnd, TRUE, pComp);
_JumpIfError(hr, error, "CreateServerRegEntries");
// hr = S_OK;
error:
if (NULL != pwszCRLPeriodString)
{
LocalFree(pwszCRLPeriodString);
}
CSILOG(hr, IDS_LOG_UPGRADE_SERVER_REG, NULL, NULL, NULL);
return(hr);
}
HRESULT
RegisterAndUnRegisterDLLs(
IN DWORD Flags,
IN PER_COMPONENT_DATA *pComp,
IN HWND hwnd)
{
HRESULT hr;
HMODULE hMod = NULL;
typedef HRESULT (STDAPICALLTYPE FNDLLREGISTERSERVER)(VOID);
FNDLLREGISTERSERVER *pfnRegister;
CHAR const *pszFuncName;
REGISTERDLL const *prd;
WCHAR wszString[MAX_PATH];
UINT errmode = 0;
BOOL fCoInit = FALSE;
hr = CoInitialize(NULL);
if (S_OK != hr && S_FALSE != hr)
{
_JumpError(hr, error, "CoInitialize");
}
fCoInit = TRUE;
errmode = SetErrorMode(SEM_FAILCRITICALERRORS);
pszFuncName = 0 == (RD_UNREGISTER & Flags)?
aszRegisterServer[0] : aszRegisterServer[1];
for (prd = g_aRegisterDll; NULL != prd->pwszDllName; prd++)
{
if ((Flags & RD_UNREGISTER) &&
((Flags & RD_SKIPUNREGPOLICY) && (prd->Flags & RD_SKIPUNREGPOLICY) ||
(Flags & RD_SKIPUNREGEXIT) && (prd->Flags & RD_SKIPUNREGEXIT) ||
(Flags & RD_SKIPUNREGMMC) && (prd->Flags & RD_SKIPUNREGMMC)))
{
// case of upgrade path & this dll doesn't want to unreg
continue;
}
if (Flags & prd->Flags)
{
if (NULL != g_pwszArgvPath)
{
wcscpy(wszString, g_pwszArgvPath);
if (L'\0' != wszString[0] &&
L'\\' != wszString[wcslen(wszString) - 1])
{
wcscat(wszString, L"\\");
}
}
else
{
wcscpy(wszString, pComp->pwszSystem32);
}
wcscat(wszString, prd->pwszDllName);
hMod = LoadLibrary(wszString);
if (NULL == hMod)
{
hr = myHLastError();
if (0 == (RD_UNREGISTER & Flags) &&
(!(RD_WHISTLER & prd->Flags) || IsWhistler()))
{
SaveCustomMessage(pComp, wszString);
CertErrorMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_ERR_DLLFUNCTION_CALL,
hr,
wszString);
_JumpErrorStr(hr, error, "DllRegisterServer", wszString);
CSILOG(hr, IDS_LOG_DLLS_REGISTERED, wszString, NULL, NULL);
_JumpErrorStr(hr, error, "LoadLibrary", wszString);
}
hr = S_OK;
continue;
}
pfnRegister = (FNDLLREGISTERSERVER *) GetProcAddress(
hMod,
pszFuncName);
if (NULL == pfnRegister)
{
hr = myHLastError();
_JumpErrorStr(hr, error, "GetProcAddress", wszString);
}
__try
{
hr = (*pfnRegister)();
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
FreeLibrary(hMod);
hMod = NULL;
if (S_OK != hr)
{
CSILOG(
hr,
(RD_UNREGISTER & Flags)?
IDS_LOG_DLLS_UNREGISTERED : IDS_LOG_DLLS_REGISTERED,
wszString,
NULL,
NULL);
if (0 == (RD_UNREGISTER & Flags))
{
CertErrorMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_ERR_DLLFUNCTION_CALL,
hr,
wszString);
_JumpErrorStr(hr, error, "DllRegisterServer", wszString);
}
else
{
_PrintErrorStr(hr, "DllUnregisterServer", wszString);
}
}
}
}
hr = S_OK;
error:
if (NULL != hMod)
{
FreeLibrary(hMod);
}
SetErrorMode(errmode);
if (fCoInit)
{
CoUninitialize();
}
if (S_OK == hr)
{
CSILOG(
hr,
(RD_UNREGISTER & Flags)?
IDS_LOG_DLLS_UNREGISTERED : IDS_LOG_DLLS_REGISTERED,
NULL,
NULL,
NULL);
}
return(hr);
}
HRESULT
CreateProgramGroups(
BOOL fClient,
PER_COMPONENT_DATA *pComp,
HWND hwnd)
{
HRESULT hr;
PROGRAMENTRY const *ppe;
WCHAR const *pwszLinkName = NULL;
DWORD Flags = fClient? PE_CLIENT : PE_SERVER;
DBGPRINT((
DBG_SS_CERTOCMI,
"CreateProgramGroups: %ws\n",
fClient? L"Client" : L"Server"));
for (ppe = g_aProgramEntry; ppe < &g_aProgramEntry[CPROGRAMENTRY]; ppe++)
{
if ((Flags & ppe->Flags) && 0 == (PE_DELETEONLY & ppe->Flags))
{
WCHAR const *pwszGroupName;
WCHAR const *pwszDescription;
WCHAR awc[MAX_PATH];
WCHAR const *pwszArgs;
wcscpy(awc, pComp->pwszSystem32);
wcscat(awc, ppe->pwszExeName);
pwszArgs = fClient? ppe->pwszClientArgs : ppe->pwszServerArgs;
if (NULL != pwszArgs)
{
wcscat(awc, L" ");
wcscat(awc, pwszArgs);
}
pwszLinkName = myLoadResourceString(ppe->uiLinkName);
if (NULL == pwszLinkName)
{
hr = myHLastError();
_JumpError(hr, error, "myLoadResourceString");
}
pwszGroupName = NULL;
if (0 != ppe->uiGroupName)
{
pwszGroupName = myLoadResourceString(ppe->uiGroupName);
if (NULL == pwszGroupName)
{
hr = myHLastError();
_JumpError(hr, error, "myLoadResourceString");
}
}
pwszDescription = NULL;
if (0 != ppe->uiDescription)
{
pwszDescription = myLoadResourceString(ppe->uiDescription);
if (NULL == pwszDescription)
{
hr = myHLastError();
_JumpError(hr, error, "myLoadResourceString");
}
}
if (!CreateLinkFile(
ppe->csidl, // CSIDL_*
pwszGroupName, // IN LPCSTR lpSubDirectory
pwszLinkName, // IN LPCSTR lpFileName
awc, // IN LPCSTR lpCommandLine
NULL, // IN LPCSTR lpIconPath
0, // IN INT iIconIndex
NULL, // IN LPCSTR lpWorkingDirectory
0, // IN WORD wHotKey
SW_SHOWNORMAL, // IN INT iShowCmd
pwszDescription)) // IN LPCSTR lpDescription
{
hr = myHLastError();
_PrintErrorStr(hr, "CreateLinkFile", awc);
_JumpErrorStr(hr, error, "CreateLinkFile", pwszLinkName);
}
}
}
hr = S_OK;
error:
if (S_OK != hr)
{
CertErrorMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_ERR_CREATELINK,
hr,
pwszLinkName);
pComp->fShownErr = TRUE;
}
CSILOG(hr, IDS_LOG_PROGRAM_GROUPS, NULL, NULL, NULL);
return(hr);
}
HRESULT
MakeRevocationPage(
HWND hwnd,
PER_COMPONENT_DATA *pComp,
IN WCHAR const *pwszFile)
{
DWORD hr;
WCHAR *pwszASP = NULL;
WCHAR *pwszConfig = NULL;
HANDLE hFile = NULL;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
#define wszASP1 \
L"<%\r\n" \
L"Response.ContentType = \"application/x-netscape-revocation\"\r\n" \
L"serialnumber = Request.QueryString\r\n" \
L"set Admin = Server.CreateObject(\"CertificateAuthority.Admin\")\r\n" \
L"\r\n" \
L"stat = Admin.IsValidCertificate(\""
#define wszASP2 \
L"\", serialnumber)\r\n" \
L"\r\n" \
L"if stat = 3 then Response.Write(\"0\") else Response.Write(\"1\") end if\r\n" \
L"%>\r\n"
hr = myFormConfigString(pComp->pwszServerName,
pServer->pwszSanitizedName,
&pwszConfig);
_JumpIfError(hr, error, "myFormConfigString");
pwszASP = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(WSZARRAYSIZE(wszASP1) +
wcslen(pwszConfig) +
WSZARRAYSIZE(wszASP2) + 1) * sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, pwszASP);
wcscpy(pwszASP, wszASP1);
wcscat(pwszASP, pwszConfig);
wcscat(pwszASP, wszASP2);
hFile = CreateFile(
pwszFile, // lpFileName
GENERIC_WRITE, // dwDesiredAccess
0, // dwShareMode
NULL, // lpSecurityAttributes
CREATE_ALWAYS, // dwCreationDisposition
0, // dwFlagsAndAttributes
0); // hTemplateFile
if (INVALID_HANDLE_VALUE == hFile)
{
hr = HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
_JumpError(hr, error, "CreateFile");
}
hr = myStringToAnsiFile(hFile, pwszASP, -1);
error:
if (hFile)
CloseHandle(hFile);
if (NULL != pwszASP)
{
LocalFree(pwszASP);
}
if (NULL != pwszConfig)
{
LocalFree(pwszConfig);
}
return(hr);
}
VOID
setupDeleteFile(
IN WCHAR const *pwszDir,
IN WCHAR const *pwszFile)
{
HRESULT hr;
WCHAR *pwszFilePath = NULL;
hr = myBuildPathAndExt(pwszDir, pwszFile, NULL, &pwszFilePath);
_JumpIfError(hr, error, "myBuildPathAndExt");
if (!DeleteFile(pwszFilePath))
{
hr = myHLastError();
_PrintErrorStr2(hr, "DeleteFile", pwszFilePath, hr);
}
error:
if (NULL != pwszFilePath)
{
LocalFree(pwszFilePath);
}
}
//+------------------------------------------------------------------------
// Function: RenameMiscTargets(. . . .)
//
// Synopsis: Handles various renaming jobs from the names that things
// are given at installation time to the names that they need
// in their new homes to run properly.
//
// Arguments: None
//
// Returns: DWORD error code.
//
// History: 3/21/97 JerryK Created
//-------------------------------------------------------------------------
HRESULT
RenameMiscTargets(
HWND hwnd,
PER_COMPONENT_DATA *pComp,
BOOL fServer)
{
HRESULT hr = S_OK;
WCHAR wszAspPath[MAX_PATH]; wszAspPath[0] = L'\0';
WCHAR wszCertSrv[MAX_PATH]; wszCertSrv[0] = L'\0';
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
if (fServer)
{
// Create nsrev_<CA Name>.asp
BuildPath(
wszCertSrv,
ARRAYSIZE(wszCertSrv),
pComp->pwszSystem32,
wszCERTENROLLSHAREPATH);
BuildPath(
wszAspPath,
ARRAYSIZE(wszAspPath),
wszCertSrv,
L"nsrev_");
wcscat(wszAspPath, pServer->pwszSanitizedName);
wcscat(wszAspPath, TEXT(".asp"));
CSASSERT(wcslen(wszAspPath) < ARRAYSIZE(wszAspPath));
hr = MakeRevocationPage(hwnd, pComp, wszAspPath);
if (S_OK != hr)
{
CertErrorMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_ERR_CREATEFILE,
hr,
wszAspPath);
_JumpError(hr, error, "MakeRevocationPage");
}
}
error:
return(hr);
}
HRESULT
CreateCertificateService(
PER_COMPONENT_DATA *pComp,
HWND hwnd)
{
HRESULT hr;
WCHAR const *pwszDisplayName;
SERVICE_DESCRIPTION sd;
SC_HANDLE hSCManager = NULL;
SC_HANDLE hSC = NULL;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
if (NULL != pServer->pwszSharedFolder)
{
// add entry
hr = CreateConfigFiles(pServer->pwszSharedFolder, pComp, FALSE, hwnd);
if (S_OK != hr)
{
CertErrorMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_ERR_CREATECERTSRVFILE,
hr,
pServer->pwszSharedFolder);
_JumpError(hr, error, "CreateConfigFiles");
}
}
if (NULL != g_pwszArgvPath)
{
wcscpy(g_wszServicePath, g_pwszArgvPath);
if (L'\0' != g_wszServicePath[0] &&
L'\\' != g_wszServicePath[wcslen(g_wszServicePath) - 1])
{
wcscat(g_wszServicePath, L"\\");
}
}
else
{
wcscpy(g_wszServicePath, pComp->pwszSystem32);
}
wcscat(g_wszServicePath, wszCERTSRVEXENAME);
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == hSCManager)
{
hr = myHLastError();
_JumpError(hr, error, "OpenSCManager");
}
if (NULL == g_pwszNoService)
{
pwszDisplayName = myLoadResourceString(IDS_CA_SERVICEDISPLAYNAME);
if (NULL == pwszDisplayName)
{
hr = myHLastError();
_JumpError(hr, error, "myLoadResourceString");
}
sd.lpDescription = const_cast<WCHAR *>(myLoadResourceString(
IDS_CA_SERVICEDESCRIPTION));
if (NULL == sd.lpDescription)
{
hr = myHLastError();
_JumpError(hr, error, "myLoadResourceString");
}
hSC = CreateService(
hSCManager, // hSCManager
wszSERVICE_NAME, // lpServiceName
pwszDisplayName, // lpDisplayName
SERVICE_ALL_ACCESS, // dwDesiredAccess
SERVICE_WIN32_OWN_PROCESS| // dwServiceType
(pServer->fInteractiveService?
SERVICE_INTERACTIVE_PROCESS:0),
SERVICE_AUTO_START, // dwStartType
SERVICE_ERROR_NORMAL, // dwErrorControl
g_wszServicePath, // lpBinaryPathName
NULL, // lpLoadOrderGroup
NULL, // lplpdwTagId
NULL, // lpDependencies
NULL, // lpServiceStartName
NULL); // lpPassword
if (NULL == hSC)
{
hr = myHLastError();
if (HRESULT_FROM_WIN32(ERROR_DUPLICATE_SERVICE_NAME) != hr &&
HRESULT_FROM_WIN32(ERROR_SERVICE_EXISTS) != hr)
{
CertErrorMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_ERR_CREATESERVICE,
hr,
wszSERVICE_NAME);
_JumpError(hr, error, "CreateService");
}
}
if (!ChangeServiceConfig2(
hSC, // hService
SERVICE_CONFIG_DESCRIPTION, // dwInfoLevel
(VOID *) &sd)) // lpInfo
{
// This error is not critical.
hr = myHLastError();
_PrintError(hr, "ChangeServiceConfig2");
}
}
// add event log message DLL (ok, it's really an EXE) as a message source
hr = myAddLogSourceToRegistry(g_wszServicePath, wszSERVICE_NAME);
if (S_OK != hr)
{
CertErrorMessageBox(
pComp->hInstance,
pComp->fUnattended,
hwnd,
IDS_ERR_ADDSOURCETOREGISTRY,
hr,
NULL);
_JumpError(hr, error, "AddLogSourceToRegistry");
}
error:
if (NULL != hSC)
{
CloseServiceHandle(hSC);
}
if (NULL != hSCManager)
{
CloseServiceHandle(hSCManager);
}
CSILOG(hr, IDS_LOG_CREATE_SERVICE, NULL, NULL, NULL);
return(hr);
}
HRESULT
DeleteProgramGroups(
IN BOOL fAll,
IN PER_COMPONENT_DATA *pComp)
{
HRESULT hr;
PROGRAMENTRY const *ppe;
WCHAR const *pwszLinkName;
WCHAR const *pwszGroupName;
for (ppe = g_aProgramEntry; ppe < &g_aProgramEntry[CPROGRAMENTRY]; ppe++)
{
if (fAll || (PE_DELETEONLY & ppe->Flags))
{
pwszLinkName = myLoadResourceString(ppe->uiLinkName);
if (NULL == pwszLinkName)
{
hr = myHLastError();
_PrintError(hr, "myLoadResourceString");
continue;
}
pwszGroupName = NULL;
if (0 != ppe->uiGroupName)
{
pwszGroupName = myLoadResourceString(ppe->uiGroupName);
if (NULL == pwszGroupName)
{
hr = myHLastError();
_PrintError(hr, "myLoadResourceString");
continue;
}
}
if (!DeleteLinkFile(
ppe->csidl, // CSIDL_*
pwszGroupName, // IN LPCSTR lpSubDirectory
pwszLinkName, // IN LPCSTR lpFileName
FALSE)) // IN BOOL fDeleteSubDirectory
{
hr = myHLastError();
_PrintError3(
hr,
"DeleteLinkFile",
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND));
}
}
}
pwszGroupName = myLoadResourceString(IDS_STARTMENU_CERTSERVER);
if (NULL == pwszGroupName)
{
hr = myHLastError();
_PrintError(hr, "myLoadResourceString");
}
else if (!DeleteGroup(pwszGroupName, TRUE))
{
hr = myHLastError();
_PrintError(hr, "DeleteGroup");
}
hr = S_OK;
//error:
return(hr);
}
HRESULT
CancelCertsrvInstallation(
HWND hwnd,
PER_COMPONENT_DATA *pComp)
{
static BOOL s_fCancelled = FALSE;
HRESULT hr;
CASERVERSETUPINFO *pServer = pComp->CA.pServer;
if (s_fCancelled)
{
goto done;
}
if (IS_SERVER_INSTALL & pComp->dwInstallStatus)
{
// uninstall will remove reg entries and others
PreUninstallCore(hwnd, pComp, FALSE);
// Note, GUI mode, we allow re-try post setup in case of cancel or failure
// but unattended mode, only allow once
UninstallCore(hwnd, pComp, 0, 0, FALSE, FALSE, !pComp->fUnattended);
if (pComp->fUnattended)
{
hr = SetSetupStatus(
NULL,
SETUP_CLIENT_FLAG | SETUP_SERVER_FLAG,
FALSE);
}
}
if (NULL != pServer)
{
if (NULL == pServer->pccExistingCert)
{
if (pServer->fSavedCAInDS)
{
// remove ca entry from ds
hr = RemoveCAInDS(pServer->pwszSanitizedName);
if (S_OK == hr)
{
pServer->fSavedCAInDS = FALSE;
}
else
{
_PrintError(hr, "RemoveCAInDS");
}
}
}
// delete the new key container, if necessary.
ClearKeyContainerName(pServer);
DisableVRootsAndShares(pComp->fCreatedVRoot, pServer->fCreatedShare);
}
DBGPRINT((DBG_SS_CERTOCM, "Certsrv setup is cancelled.\n"));
s_fCancelled = TRUE; // only once
done:
hr = S_OK;
//error:
CSILOG(hr, IDS_LOG_CANCEL_INSTALL, NULL, NULL, NULL);
return hr;
}
// Returns true if the specified period is valid. For year it
// should be in the VP_MIN,VP_MAX range. For days/weeks/months,
// we define a separate upper limit to be consistent with the
// attended setup which restricts the edit box to 4 digits.
bool IsValidPeriod(const CASERVERSETUPINFO *pServer)
{
return VP_MIN <= pServer->dwValidityPeriodCount &&
!(ENUM_PERIOD_YEARS == pServer->enumValidityPeriod &&
VP_MAX < pServer->dwValidityPeriodCount) &&
!(ENUM_PERIOD_YEARS != pServer->enumValidityPeriod &&
VP_MAX_DAYS_WEEKS_MONTHS < pServer->dwValidityPeriodCount);
}
HRESULT DeleteCertificates(const WCHAR* pwszSanitizedCAName, BOOL fRoot)
{
HRESULT hr = S_OK, hr2 = S_OK;
DWORD cCACerts, cCACert, dwNameId;
HCERTSTORE hStore = NULL;
CERT_CONTEXT const *pCACert = NULL, *pDupCert;
hr = myGetCARegHashCount(pwszSanitizedCAName, CSRH_CASIGCERT, &cCACerts);
_JumpIfError(hr, error, "myGetCARegHashCount CSRH_CASIGCERT");
hStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM_W,
X509_ASN_ENCODING,
NULL, // hProv
CERT_SYSTEM_STORE_LOCAL_MACHINE,
fRoot?wszROOT_CERTSTORE:wszCA_CERTSTORE);
for(cCACert=0; cCACert<cCACerts; cCACert++)
{
hr2 = myFindCACertByHashIndex(
hStore,
pwszSanitizedCAName,
CSRH_CASIGCERT,
cCACert,
&dwNameId,
&pCACert);
if(S_OK!=hr2)
{
hr = hr2;
_PrintIfError(hr2, "myFindCACertByHashIndex");
continue;
}
if(!CertDeleteCertificateFromStore(pCACert))
{
_PrintError(hr, "CertDeleteCertificateFromStore");
CertFreeCertificateContext(pCACert);
}
pCACert = NULL;
}
error:
CSASSERT(!pCACert);
if (NULL != hStore)
{
CertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
}
return hr;
}
HRESULT TriggerAutoenrollment()
{
HRESULT hr = S_OK;
// must be cleaned up
CAutoHANDLE hEvent;
hEvent=OpenEvent(
EVENT_MODIFY_STATE,
false,
L"Global\\" MACHINE_AUTOENROLLMENT_TRIGGER_EVENT);
if (!hEvent)
{
hr = myHLastError();
_JumpError(hr, error, "OpenEvent");
}
if (!SetEvent(hEvent))
{
hr = myHLastError();
_JumpError(hr, error, "OpenEvent");
}
error:
return hr;
}