Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2688 lines
64 KiB

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: reg.cpp
//
// Contents: Cert Server wrapper routines
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <sddl.h>
#include <assert.h>
#include "certacl.h"
#include "polreg.h"
#define __dwFILE__ __dwFILE_CERTLIB_REG_CPP__
HRESULT
myFormCertRegPath(
IN WCHAR const *pwszName1,
IN WCHAR const *pwszName2,
IN WCHAR const *pwszName3,
IN BOOL fConfigLevel, // from CertSrv if FALSE
OUT WCHAR **ppwszPath)
{
HRESULT hr;
WCHAR *pwszPath = NULL;
DWORD len1;
DWORD len2;
DWORD len3;
len1 = NULL != pwszName1 ? wcslen(pwszName1) + 1 : 0;
len2 = 0 != len1 && NULL != pwszName2 ? wcslen(pwszName2) + 1 : 0;
len3 = 0 != len2 && NULL != pwszName3 ? wcslen(pwszName3) + 1 : 0;
pwszPath = (WCHAR*)LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
((fConfigLevel?
WSZARRAYSIZE(wszREGKEYCONFIGPATH) :
WSZARRAYSIZE(wszREGKEYCERTSVCPATH)) +
len1 +
len2 +
len3 +
1) * sizeof(WCHAR));
if (NULL == pwszPath)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(pwszPath, fConfigLevel? wszREGKEYCONFIGPATH : wszREGKEYCERTSVCPATH);
if (NULL != pwszName1)
{
wcscat(pwszPath, L"\\");
wcscat(pwszPath, pwszName1);
if (NULL != pwszName2)
{
wcscat(pwszPath, L"\\");
wcscat(pwszPath, pwszName2);
if (NULL != pwszName3)
{
wcscat(pwszPath, L"\\");
wcscat(pwszPath, pwszName3);
}
}
}
*ppwszPath = pwszPath;
pwszPath = NULL;
hr = S_OK;
error:
if (NULL != pwszPath)
{
LocalFree(pwszPath);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
myDeleteCertRegValueEx(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
OPTIONAL IN WCHAR const *pwszValueName,
IN BOOL fAbsolutePath)
{
HRESULT hr;
HKEY hKey = NULL;
WCHAR *pwszTemp = NULL;
if (!fAbsolutePath)
{
hr = myFormCertRegPath(pwszName1, pwszName2, pwszName3, TRUE, &pwszTemp);
_JumpIfError(hr, error, "myFormCertRegPath");
}
else
{
CSASSERT(NULL == pwszName2 && NULL == pwszName3);
}
hr = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
fAbsolutePath ? pwszName1 : pwszTemp,
0,
KEY_ALL_ACCESS,
&hKey);
_JumpIfError(hr, error, "RegOpenKeyEx");
hr = RegDeleteValue(hKey, pwszValueName);
if ((HRESULT) ERROR_FILE_NOT_FOUND != hr)
{
_JumpIfError(hr, error, "RegDeleteValue");
}
hr = S_OK;
error:
if (NULL != pwszTemp)
{
LocalFree(pwszTemp);
}
if (NULL != hKey)
{
RegCloseKey(hKey);
}
return(myHError(hr));
}
HRESULT
myDeleteCertRegValue(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
OPTIONAL IN WCHAR const *pwszValueName)
{
return myDeleteCertRegValueEx(pwszName1,
pwszName2,
pwszName3,
pwszValueName,
FALSE);
}
HRESULT
myDeleteCertRegKeyEx(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
IN BOOL fConfigLevel)
{
HRESULT hr;
WCHAR *pwszTemp = NULL;
hr = myFormCertRegPath(pwszName1, pwszName2, pwszName3, fConfigLevel, &pwszTemp);
_JumpIfError(hr, error, "myFormCertRegPath");
hr = RegDeleteKey(
HKEY_LOCAL_MACHINE,
pwszTemp);
_JumpIfError(hr, error, "RegDeleteKey");
hr = S_OK;
error:
if (NULL != pwszTemp)
{
LocalFree(pwszTemp);
}
return(myHError(hr));
}
HRESULT
myDeleteCertRegKey(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3)
{
return myDeleteCertRegKeyEx(pwszName1, pwszName2, pwszName3, TRUE);
}
HRESULT
myCreateCertRegKeyEx(
IN BOOL fSetAcl,
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3)
{
HRESULT hr;
HKEY hKey = NULL;
DWORD dwDisposition;
WCHAR *pwszTemp = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
hr = myFormCertRegPath(pwszName1, pwszName2, pwszName3, TRUE, &pwszTemp);
_JumpIfError(hr, error, "myFormCertRegPath");
hr = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
pwszTemp,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwDisposition);
_JumpIfError(hr, error, "RegCreateKeyEx");
if (fSetAcl)
{
// construct correct reg acl for the key if upgrade
hr = myGetSDFromTemplate(WSZ_DEFAULT_UPGRADE_SECURITY,
NULL,
&pSD);
if (S_OK == hr)
{
// set to correct acl
hr = RegSetKeySecurity(hKey,
DACL_SECURITY_INFORMATION,
pSD);
_PrintIfErrorStr(hr, "RegSetKeySecurity", pwszTemp);
}
else
{
_PrintErrorStr(hr, "myGetSDFromTemplate", pwszTemp);
}
}
hr = S_OK;
error:
if (NULL != pwszTemp)
{
LocalFree(pwszTemp);
}
if (NULL != hKey)
{
RegCloseKey(hKey);
}
if (NULL != pSD)
{
LocalFree(pSD);
}
return(myHError(hr));
}
HRESULT
myCreateCertRegKey(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3)
{
return myCreateCertRegKeyEx(FALSE, // not upgrade
pwszName1,
pwszName2,
pwszName3);
}
HRESULT
mySetCertRegValueEx(
OPTIONAL IN WCHAR const *pwszMachine,
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
IN BOOL fConfigLevel,
OPTIONAL IN WCHAR const *pwszValueName,
IN DWORD const dwValueType,
IN BYTE const *pbData,
IN DWORD const cbData,
IN BOOL fAbsolutePath)
{
HRESULT hr;
HKEY hKey = NULL;
WCHAR *pwszTemp = NULL;
DWORD dwDisposition;
HKEY hBaseKey = NULL;
DWORD cbD = cbData;
if (!fAbsolutePath)
{
hr = myFormCertRegPath(pwszName1, pwszName2, pwszName3, fConfigLevel, &pwszTemp);
_JumpIfError(hr, error, "myFormCertRegPath");
}
if (pwszMachine)
{
hr = RegConnectRegistry(pwszMachine, HKEY_LOCAL_MACHINE, &hBaseKey);
_JumpIfErrorStr(hr, error, "RegConnectRegistry", pwszMachine);
}
else
hBaseKey = HKEY_LOCAL_MACHINE;
hr = RegCreateKeyEx(
hBaseKey,
fAbsolutePath ? pwszName1 : pwszTemp,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwDisposition);
_JumpIfError(hr, error, "RegCreateKeyEx");
if (NULL != pwszValueName)
{
if(NULL == pbData || 0 == cbData)
{
switch(dwValueType)
{
case REG_EXPAND_SZ:
case REG_SZ:
pbData = (BYTE*) L"";
cbD = sizeof (L"");
break;
case REG_MULTI_SZ:
pbData = (BYTE*) L"\0";
cbD = sizeof (L"\0");
break;
}
}
hr = RegSetValueEx(
hKey,
pwszValueName,
0,
dwValueType,
pbData,
cbD);
_JumpIfError(hr, error, "RegSetValueEx");
}
hr = S_OK;
error:
if ((NULL != hBaseKey) && (HKEY_LOCAL_MACHINE != hBaseKey))
{
RegCloseKey(hBaseKey);
}
if (NULL != pwszTemp)
{
LocalFree(pwszTemp);
}
if (NULL != hKey)
{
RegCloseKey(hKey);
}
return(myHError(hr));
}
HRESULT
mySetCertRegValue(
OPTIONAL IN WCHAR const *pwszMachine,
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
OPTIONAL IN WCHAR const *pwszValueName,
IN DWORD const dwValueType,
IN BYTE const *pbData,
IN DWORD const cbData,
IN BOOL fAbsolutePath)
{
return mySetCertRegValueEx(pwszMachine,
pwszName1,
pwszName2,
pwszName3,
TRUE, //from Configuration
pwszValueName,
dwValueType,
pbData,
cbData,
fAbsolutePath);
}
HRESULT
myRegQueryValueEx(
IN HKEY hKey,
IN LPCTSTR pwszValueName,
OUT LPDWORD pValueType,
OUT LPBYTE *ppbData,
OUT LPDWORD pcbData)
{
HRESULT hr;
DWORD dwType;
DWORD dwLen;
BYTE *pbData = NULL;
DWORD cbZero = 0;
*ppbData = NULL;
if (NULL != pcbData)
{
*pcbData = 0;
}
if (NULL != pValueType)
{
*pValueType = REG_NONE;
}
for (;;)
{
hr = RegQueryValueEx(
hKey,
pwszValueName,
0,
&dwType,
pbData,
&dwLen);
_JumpIfErrorStr2(
hr,
error,
"RegQueryValueEx",
pwszValueName,
ERROR_FILE_NOT_FOUND);
if (NULL != pbData)
{
ZeroMemory(&pbData[dwLen], cbZero);
break;
}
// Enforce WCHAR-aligned double null termination for malformed values.
// Some callers need to treat REG_SZ values as REG_MULTI_SZ.
if (REG_MULTI_SZ == dwType || REG_SZ == dwType)
{
cbZero = 2 * sizeof(WCHAR);
if (dwLen & (sizeof(WCHAR) - 1))
{
cbZero++;
}
}
pbData = (BYTE *) LocalAlloc(LMEM_FIXED, dwLen + cbZero);
if (NULL == pbData)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
}
if (NULL != pValueType)
{
*pValueType = dwType;
}
if (NULL != pcbData)
{
*pcbData = dwLen;
}
*ppbData = pbData;
hr = S_OK;
error:
return(myHError(hr));
}
HRESULT
myGetCertRegValueEx(
OPTIONAL IN WCHAR const *pwszMachine,
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
IN BOOL fConfigLevel,
IN WCHAR const *pwszValueName,
OUT BYTE **ppbData,
OPTIONAL OUT DWORD *pcbData,
OPTIONAL OUT DWORD *pValueType)
{
HRESULT hr;
HKEY hKey = NULL;
WCHAR *pwszTemp = NULL;
HKEY hBaseKey = NULL;
hr = myFormCertRegPath(pwszName1, pwszName2, pwszName3, fConfigLevel, &pwszTemp);
_JumpIfError(hr, error, "myFormCertRegPath");
if (pwszMachine)
{
hr = RegConnectRegistry(pwszMachine, HKEY_LOCAL_MACHINE, &hBaseKey);
_JumpIfErrorStr(hr, error, "RegConnectRegistry", pwszMachine);
}
else
hBaseKey = HKEY_LOCAL_MACHINE;
hr = RegOpenKeyEx(
hBaseKey,
pwszTemp,
0,
KEY_READ,
&hKey);
_JumpIfError2(hr, error, "RegOpenKeyEx", ERROR_FILE_NOT_FOUND);
hr = myRegQueryValueEx(
hKey,
pwszValueName,
pValueType,
ppbData,
pcbData);
_JumpIfErrorStr2(
hr,
error,
"myRegQueryValueEx",
pwszValueName,
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
error:
if ((NULL != hBaseKey) && (hBaseKey != HKEY_LOCAL_MACHINE))
{
RegCloseKey(hBaseKey);
}
if (NULL != pwszTemp)
{
LocalFree(pwszTemp);
}
if (NULL != hKey)
{
RegCloseKey(hKey);
}
return(myHError(hr));
}
HRESULT
myGetCertRegValue(
OPTIONAL IN WCHAR const *pwszMachine,
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
IN WCHAR const *pwszValueName,
OUT BYTE **ppbData,
OPTIONAL OUT DWORD *pcbData,
OPTIONAL OUT DWORD *pValueType)
{
return myGetCertRegValueEx(pwszMachine,
pwszName1,
pwszName2,
pwszName3,
TRUE, //from Configuration
pwszValueName,
ppbData,
pcbData,
pValueType);
}
HRESULT
mySetCertRegMultiStrValue(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
OPTIONAL IN WCHAR const *pwszValueName,
IN WCHAR const *pwszzValue)
{
DWORD cwc = 0;
DWORD cwcT;
WCHAR const *pwc;
if (NULL != pwszzValue)
{
for (pwc = pwszzValue; L'\0' != *pwc; cwc += cwcT, pwc += cwcT)
{
cwcT = wcslen(pwc) + 1;
}
cwc++;
}
return(mySetCertRegValue(
NULL,
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
REG_MULTI_SZ,
(BYTE const *) pwszzValue,
cwc * sizeof(WCHAR),
FALSE));
}
HRESULT
mySetCertRegStrValue(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
OPTIONAL IN WCHAR const *pwszValueName,
IN WCHAR const *pwszValue)
{
DWORD cwc = 0;
if (NULL != pwszValue)
{
cwc = wcslen(pwszValue) + 1;
}
return mySetCertRegValue(
NULL,
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
REG_SZ,
(BYTE const *) pwszValue,
cwc * sizeof(WCHAR),
FALSE);
}
HRESULT
mySetAbsRegMultiStrValue(
IN WCHAR const *pwszName,
IN WCHAR const *pwszValueName,
IN WCHAR const *pwszzValue)
{
DWORD cwc = 0;
DWORD cwcT;
WCHAR const *pwc;
if (NULL != pwszzValue)
{
for (pwc = pwszzValue; L'\0' != *pwc; cwc += cwcT, pwc += cwcT)
{
cwcT = wcslen(pwc) + 1;
}
cwc++;
}
return(mySetCertRegValue(
NULL,
pwszName,
NULL,
NULL,
pwszValueName,
REG_MULTI_SZ,
(BYTE const *) pwszzValue,
cwc * sizeof(WCHAR),
TRUE));
}
HRESULT
mySetAbsRegStrValue(
IN WCHAR const *pwszName,
IN WCHAR const *pwszValueName,
IN WCHAR const *pwszValue)
{
DWORD cwc = 0;
if (NULL != pwszValue)
{
cwc = wcslen(pwszValue) + 1;
}
return mySetCertRegValue(
NULL,
pwszName,
NULL,
NULL,
pwszValueName,
REG_SZ,
(BYTE const *)pwszValue,
cwc*sizeof(WCHAR),
TRUE);
}
HRESULT
mySetCertRegDWValue(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
OPTIONAL IN WCHAR const *pwszValueName,
IN DWORD const dwValue)
{
return mySetCertRegValue(
NULL,
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
REG_DWORD,
(BYTE const *)&dwValue,
sizeof(DWORD),
FALSE);
}
HRESULT
myGetCertRegMultiStrValue(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
OPTIONAL IN WCHAR const *pwszValueName,
OUT WCHAR **ppwszzValue)
{
HRESULT hr;
DWORD dwType;
hr = myGetCertRegValue(
NULL,
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
(BYTE **) ppwszzValue,
NULL,
&dwType);
_JumpIfErrorStr2(
hr,
error,
"myGetCertRegValue",
pwszValueName,
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
if (REG_MULTI_SZ != dwType && REG_SZ != dwType)
{
LocalFree(*ppwszzValue);
*ppwszzValue = NULL;
hr = E_INVALIDARG;
_JumpError(hr, error, "not REG_SZ or REG_MULTI_SZ");
}
hr = S_OK;
error:
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
myGetCertRegBinaryValue(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
IN WCHAR const *pwszValueName,
OUT BYTE **ppbValue)
{
HRESULT hr;
DWORD dwType;
hr = myGetCertRegValue(
NULL,
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
ppbValue,
NULL,
&dwType);
_JumpIfErrorStr2(
hr,
error,
"myGetCertRegValue",
pwszName1,
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
if (REG_BINARY != dwType)
{
LocalFree(*ppbValue);
*ppbValue = NULL;
hr = E_INVALIDARG;
_JumpError(hr, error, "not REG_BINARY");
}
hr = S_OK;
error:
return hr;
}
HRESULT
myGetCertRegStrValue(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
IN WCHAR const *pwszValueName,
OUT WCHAR **ppwszValue)
{
HRESULT hr;
DWORD dwType;
hr = myGetCertRegValue(
NULL,
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
(BYTE **) ppwszValue,
NULL,
&dwType);
_JumpIfErrorStr2(
hr,
error,
"myGetCertRegValue",
pwszName1,
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
if (REG_SZ != dwType)
{
LocalFree(*ppwszValue);
*ppwszValue = NULL;
hr = E_INVALIDARG;
_JumpError(hr, error, "not REG_SZ");
}
hr = S_OK;
error:
return hr;
}
HRESULT
myGetCertRegDWValue(
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
IN WCHAR const *pwszValueName,
OUT DWORD *pdwValue)
{
HRESULT hr;
DWORD *pdw = NULL;
DWORD dwType;
*pdwValue = 0;
hr = myGetCertRegValue(
NULL,
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
(BYTE **) &pdw,
NULL,
&dwType);
_JumpIfErrorStr2(
hr,
error,
"myGetCertRegValue",
pwszValueName,
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
if (REG_DWORD != dwType)
{
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "not REG_DWORD", pwszValueName);
}
*pdwValue = *pdw;
hr = S_OK;
error:
if (NULL != pdw)
{
LocalFree(pdw);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
myCopyCertRegStrValue(
OPTIONAL IN WCHAR const *pwszSrcName1,
OPTIONAL IN WCHAR const *pwszSrcName2,
OPTIONAL IN WCHAR const *pwszSrcName3,
IN WCHAR const *pwszSrcValueName,
OPTIONAL IN WCHAR const *pwszDesName1,
OPTIONAL IN WCHAR const *pwszDesName2,
OPTIONAL IN WCHAR const *pwszDesName3,
OPTIONAL IN WCHAR const *pwszDesValueName,
IN BOOL fMultiStr)
{
HRESULT hr;
WCHAR *pwszOrzzValue = NULL;
WCHAR const *pwszName = NULL != pwszDesValueName?
pwszDesValueName : pwszSrcValueName;
// get value from source
if (fMultiStr)
{
hr = myGetCertRegMultiStrValue(
pwszSrcName1,
pwszSrcName2,
pwszSrcName3,
pwszSrcValueName,
&pwszOrzzValue);
_JumpIfErrorStr(hr, error, "myGetCertRegMultiStrValue", pwszSrcValueName);
// set it to destination
hr = mySetCertRegMultiStrValue(
pwszDesName1,
pwszDesName2,
pwszDesName3,
pwszName,
pwszOrzzValue);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValue", pwszName);
}
else
{
hr = myGetCertRegStrValue(
pwszSrcName1,
pwszSrcName2,
pwszSrcName3,
pwszSrcValueName,
&pwszOrzzValue);
_JumpIfErrorStr(hr, error, "myGetCertRegStrValue", pwszSrcValueName);
// set it to destination
hr = mySetCertRegStrValue(
pwszDesName1,
pwszDesName2,
pwszDesName3,
pwszName,
pwszOrzzValue);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValue", pwszName);
}
hr = S_OK;
error:
if (NULL != pwszOrzzValue)
{
LocalFree(pwszOrzzValue);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
myMoveCertRegStrValue(
OPTIONAL IN WCHAR const *pwszSrcName1,
OPTIONAL IN WCHAR const *pwszSrcName2,
OPTIONAL IN WCHAR const *pwszSrcName3,
IN WCHAR const *pwszSrcValueName,
OPTIONAL IN WCHAR const *pwszDesName1,
OPTIONAL IN WCHAR const *pwszDesName2,
OPTIONAL IN WCHAR const *pwszDesName3,
OPTIONAL IN WCHAR const *pwszDesValueName,
IN BOOL fMultiStr)
{
HRESULT hr;
hr = myCopyCertRegStrValue(
pwszSrcName1,
pwszSrcName2,
pwszSrcName3,
pwszSrcValueName,
pwszDesName1,
pwszDesName2,
pwszDesName3,
pwszDesValueName,
fMultiStr);
_JumpIfErrorStr(hr, error, "myCopyCertRegStrValue", pwszSrcValueName);
hr = myDeleteCertRegValue(
pwszSrcName1,
pwszSrcName2,
pwszSrcName3,
pwszSrcValueName);
_PrintIfErrorStr(hr, "myDeleteCertRegValue", pwszSrcValueName);
hr = S_OK;
error:
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
myMoveOrCopyCertRegStrValue(
OPTIONAL IN WCHAR const *pwszSrcName1,
OPTIONAL IN WCHAR const *pwszSrcName2,
OPTIONAL IN WCHAR const *pwszSrcName3,
IN WCHAR const *pwszSrcValueName,
OPTIONAL IN WCHAR const *pwszDesName1,
OPTIONAL IN WCHAR const *pwszDesName2,
OPTIONAL IN WCHAR const *pwszDesName3,
OPTIONAL IN WCHAR const *pwszDesValueName,
IN BOOL fMultiStr,
IN BOOL fMove)
{
HRESULT hr;
if (fMove)
{
hr = myMoveCertRegStrValue(
pwszSrcName1,
pwszSrcName2,
pwszSrcName3,
pwszSrcValueName,
pwszDesName1,
pwszDesName2,
pwszDesName3,
pwszDesValueName,
fMultiStr);
}
else
{
hr = myCopyCertRegStrValue(
pwszSrcName1,
pwszSrcName2,
pwszSrcName3,
pwszSrcValueName,
pwszDesName1,
pwszDesName2,
pwszDesName3,
pwszDesValueName,
fMultiStr);
}
return hr;
}
// Description: it does the same thing as mySetCertRegStrValue but it takes
// upgrade flag, if upgrade and entry exists, do nothing
HRESULT
mySetCertRegStrValueEx(
IN BOOL fUpgrade,
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
OPTIONAL IN WCHAR const *pwszValueName,
IN WCHAR const *pwszValue)
{
HRESULT hr;
WCHAR *pwszDummy = NULL;
if (fUpgrade)
{
// see if it exists
hr = myGetCertRegStrValue(
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
&pwszDummy);
if (S_OK == hr)
{
if (NULL != pwszDummy && L'\0' != pwszDummy[0])
{
goto error; // keep existing entry
}
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpErrorStr(hr, error, "myGetCertRegStrValue", pwszValueName);
}
}
// cases: 1) not upgrade
// 2) upgrade but no existing entry
// 3) upgrade, existing but empty reg string
hr = mySetCertRegStrValue(
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
pwszValue);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValue", pwszValueName);
error:
if (NULL != pwszDummy)
{
LocalFree(pwszDummy);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
// calculate multi string character length including double zero terminators
DWORD
myWCSZZLength(
IN WCHAR const *pwszz)
{
DWORD cwc = 0;
if (NULL != pwszz)
{
WCHAR const *pwsz;
for (pwsz = pwszz; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
{
}
cwc = SAFE_SUBTRACT_POINTERS(pwsz, pwszz) + 1;
if (1 == cwc)
{
CSASSERT(L'\0' == pwsz[1]);
cwc++; // empty values are double terminated, too
}
}
return(cwc);
}
// merge two multi strings into one
// ignore redundant strings
HRESULT
myMergeMultiStrings(
IN WCHAR const *pwszzStr1,
IN WCHAR const *pwszzStr2,
OUT WCHAR **ppwszzStr)
{
HRESULT hr;
DWORD cwcStr1 = myWCSZZLength(pwszzStr1);
DWORD cwcStr2; // doesn't include second terminator
DWORD iStr2;
DWORD cStr2;
WCHAR const *pwsz1;
WCHAR const *pwsz2;
WCHAR *pwsz;
BOOL *pfRedundant = NULL;
WCHAR *pwszzMerge = NULL;
*ppwszzStr = NULL;
// calculate string count
cStr2 = 0;
for (pwsz2 = pwszzStr2; L'\0' != *pwsz2; pwsz2 += wcslen(pwsz2) + 1)
{
cStr2++;
}
cwcStr2 = 0;
if (0 == cStr2)
{
goto only_str1; // no merge needed
}
pfRedundant = (BOOL *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
cStr2 * sizeof(*pfRedundant));
if (NULL == pfRedundant)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
// calculate size
iStr2 = 0;
for (pwsz2 = pwszzStr2; L'\0' != *pwsz2; pwsz2 += wcslen(pwsz2) + 1)
{
for (pwsz1 = pwszzStr1; L'\0' != *pwsz1; pwsz1 += wcslen(pwsz1) + 1)
{
if (0 == mylstrcmpiL(pwsz2, pwsz1))
{
// pwsz2 exists in pwszzStr1, skip it -- save redundant flag
pfRedundant[iStr2] = TRUE;
break; // for pwsz1
}
}
if (L'\0' == *pwsz1) // if not redundant ...
{
cwcStr2 += wcslen(pwsz2) + 1;
}
iStr2++;
}
only_str1:
pwszzMerge = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(cwcStr1 + cwcStr2) * sizeof(WCHAR));
if (NULL == pwszzMerge)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
// copy existing
CopyMemory(pwszzMerge, pwszzStr1, cwcStr1 * sizeof(WCHAR));
if (0 < cStr2)
{
// merge begins
// point to end at 2nd terminator
iStr2 = 0;
pwsz = &pwszzMerge[cwcStr1 - 1];
if (L'\0' == *pwszzMerge)
{
CSASSERT(2 == cwcStr1);
pwsz = pwszzMerge;
}
for (pwsz2 = pwszzStr2; L'\0' != *pwsz2; pwsz2 += wcslen(pwsz2) + 1)
{
if (!pfRedundant[iStr2])
{
wcscpy(pwsz, pwsz2);
pwsz += wcslen(pwsz) + 1;
}
iStr2++;
}
*pwsz = L'\0'; // double terminate
CSASSERT(
SAFE_SUBTRACT_POINTERS(pwsz, pwszzMerge) + 1 <= cwcStr1 + cwcStr2);
}
CSASSERT(myWCSZZLength(pwszzMerge) <= cwcStr1 + cwcStr2);
*ppwszzStr = pwszzMerge;
pwszzMerge = NULL;
hr = S_OK;
error:
if (NULL != pfRedundant)
{
LocalFree(pfRedundant);
}
if (NULL != pwszzMerge)
{
LocalFree(pwszzMerge);
}
return(hr);
}
// append one multi_sz to another
HRESULT
myAppendMultiStrings(
IN WCHAR const *pwszzStr1,
IN WCHAR const *pwszzStr2,
OUT WCHAR **ppwszzStr)
{
HRESULT hr;
DWORD cwcStr1 = myWCSZZLength(pwszzStr1);
DWORD cwcStr2 = myWCSZZLength(pwszzStr2);
WCHAR *pwszzMerge;
WCHAR *pwsz;
*ppwszzStr = NULL;
pwszzMerge = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(cwcStr1 + cwcStr2 - 1) * sizeof(WCHAR));
if (NULL == pwszzMerge)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
// copy existing
CopyMemory(pwszzMerge, pwszzStr1, (cwcStr1 - 1) * sizeof(WCHAR));
// append second
pwsz = &pwszzMerge[cwcStr1 - 1];
if (L'\0' == *pwszzMerge)
{
CSASSERT(2 == cwcStr1);
pwsz = pwszzMerge;
}
CopyMemory(pwsz, pwszzStr2, cwcStr2 * sizeof(WCHAR));
CSASSERT(myWCSZZLength(pwszzMerge) <= cwcStr1 + cwcStr2);
*ppwszzStr = pwszzMerge;
hr = S_OK;
error:
return(hr);
}
// Description: mySetCertRegMultiStrValueEx is the same as
// mySetCertRegMultiStrValue but it takes an upgrade | append flag.
// if upgrade and entry exists, do nothing.
// if upgrade & append, merge existing entry with input pwszz.
HRESULT
mySetCertRegMultiStrValueEx(
IN DWORD dwFlags, // CSREG_UPGRADE | CSREG_APPEND | CSREG_REPLACE | CSREG_MERGE
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
OPTIONAL IN WCHAR const *pwszValueName,
IN WCHAR const *pwszzValue)
{
HRESULT hr;
WCHAR *pwszzExisting = NULL;
WCHAR const *pwszzFinal = pwszzValue; // default
WCHAR *pwszzMerge = NULL;
if (0 == (CSREG_REPLACE & dwFlags) && (CSREG_UPGRADE & dwFlags))
{
// to see if it exist
hr = myGetCertRegMultiStrValue(
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
&pwszzExisting);
if (S_OK == hr)
{
if (NULL != pwszzExisting)
{
if (0 == ((CSREG_MERGE | CSREG_APPEND) & dwFlags))
{
goto error; // keep existing entry
}
if (CSREG_MERGE & dwFlags)
{
hr = myMergeMultiStrings(
pwszzExisting,
pwszzValue,
&pwszzMerge);
_JumpIfError(hr, error, "myMergeMultiStrings");
}
else if (CSREG_APPEND & dwFlags)
{
hr = myAppendMultiStrings(
pwszzExisting,
pwszzValue,
&pwszzMerge);
_JumpIfError(hr, error, "myAppendMultiStrings");
}
pwszzFinal = pwszzMerge;
}
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpErrorStr(hr, error, "myGetCertRegMultiStrValue", pwszValueName);
}
}
hr = mySetCertRegMultiStrValue(
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
pwszzFinal);
_JumpIfErrorStr(hr, error, "mySetCertRegMultiStrValue", pwszValueName);
error:
if (NULL != pwszzExisting)
{
LocalFree(pwszzExisting);
}
if (NULL != pwszzMerge)
{
LocalFree(pwszzMerge);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
// Description: it does the same thing as mySetCertRegDWValue but it takes
// upgrade flag, if upgrade and entry exists, do nothing
HRESULT
mySetCertRegDWValueEx(
IN BOOL fUpgrade,
OPTIONAL IN WCHAR const *pwszName1,
OPTIONAL IN WCHAR const *pwszName2,
OPTIONAL IN WCHAR const *pwszName3,
OPTIONAL IN WCHAR const *pwszValueName,
IN DWORD const dwValue)
{
HRESULT hr;
DWORD dwDummy;
if (fUpgrade)
{
// to see if it exist
hr = myGetCertRegDWValue(
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
&dwDummy);
if (S_OK == hr)
{
goto error; // keep existing entry
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpErrorStr(hr, error, "myGetCertRegDWValue", pwszValueName);
}
}
hr = mySetCertRegDWValue(
pwszName1,
pwszName2,
pwszName3,
pwszValueName,
dwValue);
_JumpIfErrorStr(hr, error, "mySetCertRegDWValue", pwszValueName);
error:
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
WCHAR const *
wszRegCertChoice(
IN DWORD dwRegHashChoice)
{
WCHAR const *pwsz;
switch (dwRegHashChoice)
{
case CSRH_CASIGCERT:
pwsz = wszREGCACERTHASH;
break;
case CSRH_CAXCHGCERT:
pwsz = wszREGCAXCHGCERTHASH;
break;
case CSRH_CAKRACERT:
pwsz = wszREGKRACERTHASH;
break;
default:
CSASSERT(CSExpr(!"dwRegHashChoice"));
pwsz = L"";
break;
}
return(pwsz);
}
WCHAR const g_wszNoHash[] = L"-";
HRESULT myShrinkCARegHash(
IN WCHAR const *pwszSanitizedCAName,
IN DWORD dwRegHashChoice,
IN DWORD Index)
{
HRESULT hr = S_OK;
DWORD i;
DWORD dwType;
DWORD count;
WCHAR *pwszzOld = NULL;
WCHAR *pwchr = NULL; // no free
hr = myGetCertRegValue(
NULL,
pwszSanitizedCAName,
NULL,
NULL,
wszRegCertChoice(dwRegHashChoice),
(BYTE **) &pwszzOld,
&i, // ignore &cb
&dwType);
_JumpIfErrorStr(hr, error, "myGetCertRegValue", wszRegCertChoice(dwRegHashChoice));
for (count = 0, pwchr = pwszzOld;
count < Index && L'\0' != *pwchr;
count++, pwchr += wcslen(pwchr) + 1)
NULL;
// valid only if shrinking the list
if(L'\0' == *pwchr)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "new hash count should be smaller than current count");
}
*pwchr = L'\0';
hr = mySetCertRegValue(
NULL,
pwszSanitizedCAName,
NULL,
NULL,
wszRegCertChoice(dwRegHashChoice),
REG_MULTI_SZ,
(BYTE const *) pwszzOld,
(SAFE_SUBTRACT_POINTERS(pwchr, pwszzOld) + 1) * sizeof(WCHAR),
FALSE);
_JumpIfError(hr, error, "mySetCertRegValue");
error:
if(pwszzOld)
LocalFree(pwszzOld);
return hr;
}
HRESULT
mySetCARegHash(
IN WCHAR const *pwszSanitizedCAName,
IN DWORD dwRegHashChoice,
IN DWORD Index,
IN CERT_CONTEXT const *pCert)
{
HRESULT hr;
BSTR strHash = NULL;
BYTE abHash[CBMAX_CRYPT_HASH_LEN];
DWORD cbHash;
WCHAR *pwszzOld = NULL;
WCHAR *pwszzNew = NULL;
DWORD cOld;
DWORD i;
DWORD cNew;
DWORD cwcNew;
WCHAR const **apwsz = NULL;
DWORD dwType;
WCHAR *pwc;
if (NULL == pwszSanitizedCAName)
{
hr = E_POINTER;
_JumpError(hr, error, "empty ca name");
}
cbHash = sizeof(abHash);
if (!CertGetCertificateContextProperty(
pCert,
CERT_HASH_PROP_ID,
abHash,
&cbHash))
{
hr = myHLastError();
_JumpError(hr, error, "CertGetCertificateContextProperty");
}
hr = MultiByteIntegerToBstr(TRUE, cbHash, abHash, &strHash);
_JumpIfError(hr, error, "MultiByteIntegerToBstr");
cOld = 0;
hr = myGetCertRegValue(
NULL,
pwszSanitizedCAName,
NULL,
NULL,
wszRegCertChoice(dwRegHashChoice),
(BYTE **) &pwszzOld,
&i, // ignore &cb
&dwType);
_PrintIfError2(hr, "myGetCertRegValue", HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
if (S_OK == hr && REG_MULTI_SZ == dwType)
{
for (pwc = pwszzOld; L'\0' != *pwc; pwc += wcslen(pwc) + 1)
{
cOld++;
}
}
cNew = max(Index + 1, cOld);
apwsz = (WCHAR const **) LocalAlloc(LMEM_FIXED, cNew * sizeof(*apwsz));
if (NULL == apwsz)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
i = 0;
if (0 != cOld)
{
for (pwc = pwszzOld; L'\0' != *pwc; pwc += wcslen(pwc) + 1)
{
DBGPRINT((DBG_SS_CERTLIBI, "Old CARegHash[%u] = \"%ws\"\n", i, pwc));
apwsz[i++] = pwc;
}
CSASSERT(i == cOld);
}
while (i < Index)
{
DBGPRINT((DBG_SS_CERTLIBI, "CARegHash[%u] Unused\n", i));
apwsz[i++] = g_wszNoHash;
}
if (Index < cOld)
{
DBGPRINT((
DBG_SS_CERTLIBI,
"Replacing CARegHash[%u] = \"%ws\"\n",
Index,
apwsz[Index]));
}
DBGPRINT((
DBG_SS_CERTLIBI,
"Adding CARegHash[%u] = \"%ws\"\n",
Index,
strHash));
apwsz[Index] = strHash;
cwcNew = 1; // wszz double termination
for (i = 0; i < cNew; i++)
{
cwcNew += wcslen(apwsz[i]) + 1;
}
pwszzNew = (WCHAR *) LocalAlloc(LMEM_FIXED, cwcNew * sizeof(WCHAR));
if (NULL == pwszzNew)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pwc = pwszzNew;
for (i = 0; i < cNew; i++)
{
wcscpy(pwc, apwsz[i]);
DBGPRINT((DBG_SS_CERTLIBI, "New CARegHash[%u] = \"%ws\"\n", i, pwc));
pwc += wcslen(pwc) + 1;
}
*pwc = L'\0';
CSASSERT(&pwszzNew[cwcNew - 1] == pwc);
hr = mySetCertRegValue(
NULL,
pwszSanitizedCAName,
NULL,
NULL,
wszRegCertChoice(dwRegHashChoice),
REG_MULTI_SZ,
(BYTE const *) pwszzNew,
cwcNew * sizeof(WCHAR),
FALSE);
_JumpIfError(hr, error, "mySetCertRegValue");
error:
if (NULL != apwsz)
{
LocalFree(apwsz);
}
if (NULL != pwszzOld)
{
LocalFree(pwszzOld);
}
if (NULL != pwszzNew)
{
LocalFree(pwszzNew);
}
if (NULL != strHash)
{
SysFreeString(strHash);
}
return(hr);
}
HRESULT
myGetCARegHash(
IN WCHAR const *pwszSanitizedCAName,
IN DWORD dwRegHashChoice,
IN DWORD Index,
OUT BYTE **ppbHash,
OUT DWORD *pcbHash)
{
HRESULT hr;
WCHAR *pwszz = NULL;
DWORD cb;
DWORD dwType;
WCHAR *pwc;
DWORD i;
*ppbHash = NULL;
hr = myGetCertRegValue(
NULL,
pwszSanitizedCAName,
NULL,
NULL,
wszRegCertChoice(dwRegHashChoice),
(BYTE **) &pwszz,
&cb,
&dwType);
_JumpIfError(hr, error, "myGetCertRegValue");
if (REG_MULTI_SZ != dwType)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "dwType");
}
pwc = pwszz;
for (i = 0; i < Index; i++)
{
if (L'\0' == *pwc)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpError(hr, error, "Index too large");
}
pwc += wcslen(pwc) + 1;
}
if (0 == lstrcmp(g_wszNoHash, pwc))
{
hr = S_FALSE;
_JumpError2(hr, error, "Unused hash", S_FALSE);
}
hr = WszToMultiByteInteger(TRUE, pwc, pcbHash, ppbHash);
_JumpIfError(hr, error, "WszToMultiByteInteger");
error:
if (NULL != pwszz)
{
LocalFree(pwszz);
}
return(hr);
}
HRESULT
myGetCARegHashCount(
IN WCHAR const *pwszSanitizedCAName,
IN DWORD dwRegHashChoice,
OUT DWORD *pCount)
{
HRESULT hr;
WCHAR *pwszz = NULL;
DWORD cb;
DWORD dwType;
WCHAR *pwc;
DWORD Count = 0;
hr = myGetCertRegValue(
NULL,
pwszSanitizedCAName,
NULL,
NULL,
wszRegCertChoice(dwRegHashChoice),
(BYTE **) &pwszz,
&cb,
&dwType);
if (S_OK == hr)
{
if (REG_MULTI_SZ == dwType)
{
for (pwc = pwszz; L'\0' != *pwc; pwc += wcslen(pwc) + 1)
{
Count++;
}
}
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
{
_JumpError(hr, error, "myGetCertRegValue");
}
hr = S_OK;
error:
*pCount = Count;
if (NULL != pwszz)
{
LocalFree(pwszz);
}
return(hr);
}
HRESULT
myFindCACertByHash(
IN HCERTSTORE hStore,
IN BYTE const *pbHash,
IN DWORD cbHash,
OUT OPTIONAL DWORD *pdwNameId,
CERT_CONTEXT const **ppCACert)
{
HRESULT hr;
CRYPT_DATA_BLOB Hash;
CSASSERT(
NULL != hStore &&
NULL != pbHash &&
NULL != ppCACert);
*ppCACert = NULL;
Hash.pbData = const_cast<BYTE *>(pbHash);
Hash.cbData = cbHash;
*ppCACert = CertFindCertificateInStore(
hStore,
X509_ASN_ENCODING,
0,
CERT_FIND_HASH,
&Hash,
NULL);
if (NULL == *ppCACert)
{
hr = myHLastError();
_JumpError(hr, error, "CertFindCertificateInStore");
}
if (NULL != pdwNameId)
{
*pdwNameId = MAXDWORD;
hr = myGetNameId(*ppCACert, pdwNameId);
_PrintIfError(hr, "myGetNameId");
}
hr = S_OK;
error:
return(hr);
}
HRESULT
myFindCACertByHashIndex(
IN HCERTSTORE hStore,
IN WCHAR const *pwszSanitizedCAName,
IN DWORD dwRegHashChoice,
IN DWORD Index,
OPTIONAL OUT DWORD *pdwNameId,
CERT_CONTEXT const **ppCACert)
{
HRESULT hr;
DWORD cbHash;
BYTE *pbHash = NULL;
CSASSERT(NULL != hStore && NULL != ppCACert);
if (NULL != pdwNameId)
{
*pdwNameId = MAXDWORD;
}
*ppCACert = NULL;
hr = myGetCARegHash(
pwszSanitizedCAName,
dwRegHashChoice,
Index,
&pbHash,
&cbHash);
_JumpIfError2(hr, error, "myGetCARegHash", S_FALSE);
hr = myFindCACertByHash(hStore, pbHash, cbHash, pdwNameId, ppCACert);
_JumpIfError(hr, error, "myFindCACertByHash");
error:
if (NULL != pbHash)
{
LocalFree(pbHash);
}
return(hr);
}
HRESULT
GetSetupStatus(
OPTIONAL IN WCHAR const *pwszSanitizedCAName,
OUT DWORD *pdwStatus)
{
HRESULT hr;
hr = myGetCertRegDWValue(
pwszSanitizedCAName,
NULL,
NULL,
wszREGSETUPSTATUS,
pdwStatus);
_JumpIfErrorStr2(
hr,
error,
"myGetCertRegDWValue",
wszREGSETUPSTATUS,
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
DBGPRINT((DBG_SS_CERTLIBI, "GetSetupStatus(%ws) --> %x\n", pwszSanitizedCAName, *pdwStatus));
error:
return(hr);
}
HRESULT
SetSetupStatus(
OPTIONAL IN WCHAR const *pwszSanitizedCAName,
IN const DWORD dwFlag,
IN const BOOL fSetBit)
{
HRESULT hr;
DWORD dwCurrentStatus;
DWORD dwStatus = dwFlag;
hr = myGetCertRegDWValue(
pwszSanitizedCAName,
NULL,
NULL,
wszREGSETUPSTATUS,
&dwCurrentStatus);
_PrintIfError2(
hr,
"myGetCertRegDWValue",
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
// check to if there is existing status
if (S_OK == hr || 0xFFFFFFFF == dwStatus)
{
// existing status, set according to dwFlag
if (fSetBit)
{
// set corresponding bit
dwStatus = dwCurrentStatus | dwStatus;
}
else
{
// unset corresponding
dwStatus = dwCurrentStatus & ~dwStatus;
}
}
else if(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)==hr)
{
hr = S_OK;
// entry doesn't exist, if fSetBit, keep dwStatus=dwFlag
if (!fSetBit)
{
// otherwise set all 0
dwStatus = 0;
}
}
else
{
_JumpIfError(hr, error, "myGetCertRegDWValue(wszREGSETUPSTATUS)");
}
hr = mySetCertRegDWValue(
pwszSanitizedCAName,
NULL,
NULL,
wszREGSETUPSTATUS,
dwStatus);
_JumpIfError(hr, error, "mySetCertRegDWValue");
DBGPRINT((DBG_SS_CERTLIBI, "SetSetupStatus(%ws, %x)\n", pwszSanitizedCAName, dwStatus));
error:
return(hr);
}
HRESULT
myGetActiveManageModule(
OPTIONAL IN WCHAR const *pwszMachine,
IN WCHAR const *pwszSanitizedCAName,
IN BOOL fPolicyModule,
IN DWORD Index,
OUT LPOLESTR *ppwszProgIdManageModule, // CoTaskMem*
OUT CLSID *pclsidManageModule)
{
DWORD dw;
PBYTE pb = NULL;
DWORD cbClassName;
LPOLESTR lpszProgID = NULL;
LPWSTR szClassName = NULL;
if (NULL != *ppwszProgIdManageModule)
{
CoTaskMemFree(*ppwszProgIdManageModule);
*ppwszProgIdManageModule = NULL;
}
dw = myGetActiveModule(
pwszMachine,
pwszSanitizedCAName,
fPolicyModule,
Index,
&lpszProgID,
NULL);
if (S_OK != dw)
goto error;
{
// terminate class name at first '.'
LPWSTR pAddTermination = wcschr(lpszProgID, L'.');
if (NULL != pAddTermination)
{
pAddTermination[0] = L'\0';
}
}
cbClassName = (wcslen(lpszProgID) + 1) * sizeof(WCHAR);
cbClassName += (fPolicyModule) ? sizeof(wszCERTMANAGEPOLICY_POSTFIX) : sizeof(wszCERTMANAGEEXIT_POSTFIX);
szClassName = (LPWSTR) CoTaskMemAlloc(cbClassName);
if (NULL == szClassName)
goto error;
wcscpy(szClassName, lpszProgID);
wcscat(szClassName, fPolicyModule? wszCERTMANAGEPOLICY_POSTFIX : wszCERTMANAGEEXIT_POSTFIX);
// Now we have class module name, cvt to clsid
dw = CLSIDFromProgID(szClassName, pclsidManageModule);
if (S_OK != dw)
goto error; // clsid not found?
error:
if (pb)
LocalFree(pb);
// intermediate ProgId
if (lpszProgID)
CoTaskMemFree(lpszProgID);
*ppwszProgIdManageModule = szClassName;
return dw;
}
HRESULT
myGetActiveModule(
OPTIONAL IN WCHAR const *pwszMachine,
IN WCHAR const *pwszSanitizedCAName,
IN BOOL fPolicyModule,
IN DWORD Index,
OPTIONAL OUT LPOLESTR *ppwszProgIdModule, // CoTaskMem*
OPTIONAL OUT CLSID *pclsidModule)
{
HRESULT hr;
WCHAR *pwszzValue = NULL;
WCHAR *pwsz;
DWORD dwType;
DWORD cb = 0;
LPWSTR pwszModuleSubkey = NULL;
DWORD chModule;
chModule = wcslen(pwszSanitizedCAName) + 1 + 1; // (L'\\' + trailing L'\0');
chModule += fPolicyModule?
WSZARRAYSIZE(wszREGKEYPOLICYMODULES) :
WSZARRAYSIZE(wszREGKEYEXITMODULES);
pwszModuleSubkey = (LPWSTR) LocalAlloc(
LMEM_FIXED,
chModule * sizeof(WCHAR));
if (NULL == pwszModuleSubkey)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(pwszModuleSubkey, pwszSanitizedCAName);
wcscat(pwszModuleSubkey, L"\\");
wcscat(
pwszModuleSubkey,
fPolicyModule? wszREGKEYPOLICYMODULES : wszREGKEYEXITMODULES);
// grab entry under CA with the active module ProgID
hr = myGetCertRegValue(
pwszMachine,
pwszModuleSubkey,
NULL,
NULL,
wszREGACTIVE,
(BYTE **) &pwszzValue,
&cb,
&dwType);
_JumpIfError(hr, error, "myGetCertRegValue");
hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
// might or might not have an active entry
if (REG_SZ != dwType && REG_MULTI_SZ != dwType)
{
_JumpError(hr, error, "Bad active entry type");
}
if (0 == cb || NULL == pwszzValue)
{
_JumpError(hr, error, "No active entry");
}
if (0 != Index && (REG_SZ == dwType || fPolicyModule))
{
_JumpError(hr, error, "only one policy module or REG_SZ entry");
}
pwsz = pwszzValue;
if (REG_MULTI_SZ == dwType)
{
// look for Index'th entry
for ( ; 0 != Index; pwsz += wcslen(pwsz) + 1, Index--)
{
if (L'\0' == *pwsz)
{
_JumpError(hr, error, "No more active entries");
}
}
}
// Verify nth entry exists
if (L'\0' == *pwsz)
{
_JumpError(hr, error, "No active entries");
}
if (NULL != pclsidModule)
{
hr = CLSIDFromProgID(pwsz, pclsidModule);
_JumpIfError(hr, error, "CLSIDFromProgID");
}
if (NULL != ppwszProgIdModule)
{
*ppwszProgIdModule = (LPOLESTR) CoTaskMemAlloc(
(wcslen(pwsz) + 1) * sizeof(WCHAR));
if (NULL == *ppwszProgIdModule)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "CoTaskMemAlloc");
}
wcscpy(*ppwszProgIdModule, pwsz);
}
hr = S_OK; // not reset after ERROR_MOD_NOT_FOUND in all cases
error:
if (NULL != pwszModuleSubkey)
{
LocalFree(pwszModuleSubkey);
}
if (NULL != pwszzValue)
{
LocalFree(pwszzValue);
}
return(hr);
}
BOOL
IsPrefix(
WCHAR const *pwszPrefix,
WCHAR const *pwszString,
DWORD cwcPrefix)
{
return(
0 == _wcsnicmp(pwszPrefix, pwszString, cwcPrefix) &&
(L'\\' == pwszString[cwcPrefix] ||
L'\0' == pwszString[cwcPrefix]));
}
//+------------------------------------------------------------------------
// Function: myRegOpenRelativeKey
//
// Synopsis: Compute CA-relative, Policy-relative or Exit-relative registry
// path, and retrieve the value, type, and parent registry key.
//
// IN params:
//
// pwszConfig is the config string of the CA:
// if NULL, the local machine's first active CA is used.
// if a server name (no \CAName is present), the specified machine's
// first active CA is used.
//
// pwszRegName can specify any of the following the targets:
// Passed String: ValueName Relative Key Opened:
// ------------- ------------------------------
// "ValueName" Configuration key
// "CA[\ValueName]" CAName key
// "policy[\ValueName]" CAName\PolicyModules\<ActivePolicy>
// "policy\ModuleProgId[\ValueName]" CAName\PolicyModules\ModuleProgId
// "exit[\ValueName]" CAName\ExitModules\<ActiveExit>
// "exit\ModuleProgId[\ValueName]" CAName\ExitModules\ModuleProgId
// "Template[\ValueName]" Template
//
//
// RORKF_FULLPATH specifies whether the path returned is relative from HKLM or
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration.
//
// RORKF_CREATESUBKEYS will allow subkeys to be created if necessary and the
// returned hkey opened for WRITE access
//
// RORKF_CREATEKEY will allow the top level key to be created if necessary
//
// On successful execution:
//
// *ppwszPath will contain a LocalAlloc'd registry path relative to
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration.
//
// *ppwszName will contain a LocalAlloc'd registry value name string relative to
// the returned parent key. If NULL, pwszRegName specifies a key, not a value.
//
// *phkey contains the opened reg key, if phkey non-NULL. Caller is responsible
// for freeing this key.
//-------------------------------------------------------------------------
HRESULT
myRegOpenRelativeKey(
OPTIONAL IN WCHAR const *pwszConfig,
IN WCHAR const *pwszRegName,
IN DWORD Flags, // RORKF_*
OUT WCHAR **ppwszPath,
OUT OPTIONAL WCHAR **ppwszName,
OUT OPTIONAL HKEY *phkey)
{
HRESULT hr;
WCHAR awc[MAX_PATH];
WCHAR awc2[MAX_PATH];
HKEY hkeyRoot = HKEY_LOCAL_MACHINE;
HKEY hkeyConfig = NULL;
HKEY hkeyMod = NULL;
HKEY hkeyRequested = NULL;
WCHAR *pwszMachine = NULL;
WCHAR const *pwszModules = NULL;
WCHAR const *pwszName;
WCHAR const *pwsz;
DWORD dwType;
DWORD cb;
DWORD cwc;
DWORD i;
BOOL fTemplateCache;
DWORD dwDisposition;
// Parameter checking
if (NULL != phkey)
{
*phkey = NULL;
}
if (NULL != ppwszName)
{
*ppwszName = NULL;
}
if (NULL == ppwszPath)
{
hr = E_POINTER;
_JumpError(hr, error, "ppwszPath not optional");
}
*ppwszPath = NULL;
fTemplateCache = IsPrefix(L"Template", pwszRegName, 8);
if (fTemplateCache && (RORKF_USERKEY & Flags))
{
hkeyRoot = HKEY_CURRENT_USER;
}
// take care of remote machine access
if (NULL != pwszConfig)
{
BOOL fLocal;
hr = myIsConfigLocal(pwszConfig, &pwszMachine, &fLocal);
_JumpIfError(hr, error, "myIsConfigLocal");
if (!fLocal)
{
hr = RegConnectRegistry(pwszMachine, hkeyRoot, &hkeyRoot);
_JumpIfErrorStr(hr, error, "RegConnectRegistry", pwszMachine);
}
}
if (!fTemplateCache)
{
hr = RegOpenKeyEx(
hkeyRoot,
wszREGKEYCONFIGPATH,
0,
(RORKF_CREATESUBKEYS & Flags)? KEY_ALL_ACCESS : KEY_READ,
&hkeyConfig);
if ((HRESULT) ERROR_FILE_NOT_FOUND == hr && (RORKF_CREATEKEY & Flags))
{
_PrintError(hr, "RegOpenKey(config)");
hr = RegCreateKey(hkeyRoot, wszREGKEYCONFIGPATH, &hkeyConfig);
_JumpIfError(hr, error, "RegCreateKey(config)");
}
_JumpIfError(hr, error, "RegOpenKey(config)");
}
// value or key\value passed in under pwszRegName?
pwsz = wcschr(pwszRegName, L'\\');
if (NULL == pwsz &&
!IsPrefix(L"CA", pwszRegName, 2) &&
!IsPrefix(L"Policy", pwszRegName, 6) &&
!IsPrefix(L"Exit", pwszRegName, 4) &&
!IsPrefix(L"Restore", pwszRegName, 7) &&
!IsPrefix(L"Config", pwszRegName, 6) &&
!fTemplateCache)
{
// Operate on registry value under the Configuration registry key
pwszName = pwszRegName;
// this is the final key we'll open
hkeyRequested = hkeyConfig;
hkeyConfig = NULL;
awc[0] = L'\0';
}
else if (fTemplateCache)
{
pwszName = &pwszRegName[8];
wcscpy(awc, wszCERTTYPECACHE);
}
else
{
//printf("RegName = '%ws'\n", pwszRegName);
// load config of the active CA
awc[0] = L'\0';
if (!IsPrefix(L"Config", pwszRegName, 6))
{
cb = sizeof(awc);
hr = RegQueryValueEx(
hkeyConfig,
wszREGACTIVE,
NULL,
&dwType,
(BYTE *) awc,
&cb);
_JumpIfErrorStr(hr, error, "RegQueryValueEx", wszREGACTIVE);
if (REG_SZ != dwType && REG_MULTI_SZ != dwType)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpIfErrorStr(hr, error, "RegQueryValueEx TYPE", wszREGACTIVE);
}
//printf("Active CA = '%ws'\n", awc);
}
// operate on key\value
// first, subdivide into policymodules\exitmodules subkey
if (IsPrefix(L"CA", pwszRegName, 2))
{
// Operate on registry value under the Active CA registry key
pwszName = &pwszRegName[2];
}
else if (IsPrefix(L"Policy", pwszRegName, 6))
{
// Operate on registry value under a Policy Module registry key
pwszModules = wszREGKEYPOLICYMODULES;
pwszName = &pwszRegName[6];
}
else if (IsPrefix(L"Exit", pwszRegName, 4))
{
// Operate on registry value under an Exit Module registry key
pwszModules = wszREGKEYEXITMODULES;
pwszName = &pwszRegName[4];
}
else if (IsPrefix(L"Restore", pwszRegName, 7))
{
// Operate on registry value under Restore registry key
pwszName = &pwszRegName[7];
wcscpy(awc, wszREGKEYRESTOREINPROGRESS);
}
else if (IsPrefix(L"Config", pwszRegName, 6))
{
// Operate on registry value under Configuration registry key
pwszName = &pwszRegName[6];
}
else
{
hr = E_INVALIDARG;
_JumpError(hr, error, "pwszRegName: no subkey description");
}
// expand module ProgId if necessary: get active ProgId
if (NULL != pwszModules) // if a policy or exit module
{
wcscat(awc, L"\\");
wcscat(awc, pwszModules);
}
//printf("CA|restore|policy|exit key = '%ws'\n", awc);
if (NULL != ppwszName) // if a registry value expected
{
// Find active policy/exit module's ProgId
hr = RegOpenKeyEx(
hkeyConfig,
awc,
0,
KEY_READ,
&hkeyMod);
_JumpIfErrorStr(hr, error, "RegOpenKey", awc);
if (NULL != pwszModules) // if a policy or exit module
{
cb = sizeof(awc2);
hr = RegQueryValueEx(
hkeyMod,
wszREGACTIVE,
NULL,
&dwType,
(BYTE *) awc2,
&cb);
_JumpIfErrorStr(hr, error, "RegQueryValueEx", wszREGACTIVE);
if (REG_SZ != dwType && REG_MULTI_SZ != dwType)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpIfErrorStr(hr, error, "RegQueryValueEx Active Module", awc);
}
//printf("Active Module = '%ws'\n", awc2);
wcscat(awc, L"\\");
wcscat(awc, awc2);
}
}
else // else a registry key name is expected
{
// key\value: ProgId was passed in
// concatenate key name (including the \\ prefix) onto end of awc
if (NULL != pwsz)
{
CSASSERT(L'\\' == *pwsz);
wcscat(awc, pwsz);
}
}
} // end if (operate on key/value or value)
if (NULL == hkeyRequested)
{
//printf("Creating key = '%ws'\n", awc);
// open this key
hr = RegCreateKeyEx(
NULL != hkeyConfig? hkeyConfig : hkeyRoot,
awc,
0,
NULL,
0,
(RORKF_CREATESUBKEYS & Flags)? KEY_ALL_ACCESS : KEY_READ,
NULL,
&hkeyRequested,
&dwDisposition);
_JumpIfErrorStr(hr, error, "RegCreateKeyEx(parent)", awc);
} // end if (operate on key/value or value)
if (L'\\' == *pwszName)
{
pwszName++;
}
if (NULL != ppwszName && L'\0' != *pwszName)
{
// Look for case-ignore matching registry value name, & use the value's
// correct upper/lower case spelling if an existing registry value:
for (i = 0; ; i++)
{
cwc = ARRAYSIZE(awc2);
hr = RegEnumValue(hkeyRequested, i, awc2, &cwc, NULL, NULL, NULL, NULL);
if (S_OK != hr)
{
hr = S_OK;
break;
}
if (0 == mylstrcmpiL(awc2, pwszName))
{
pwszName = awc2;
break;
}
}
}
cb = (wcslen(awc) + 1) * sizeof(WCHAR);
if (!fTemplateCache && (RORKF_FULLPATH & Flags))
{
cb += WSZARRAYSIZE(wszREGKEYCONFIGPATH_BS) * sizeof(WCHAR);
}
*ppwszPath = (WCHAR *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == *ppwszPath)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
(*ppwszPath)[0] = L'\0';
if (!fTemplateCache && (RORKF_FULLPATH & Flags))
{
wcscpy(*ppwszPath, wszREGKEYCONFIGPATH_BS);
}
wcscat(*ppwszPath, awc);
CSASSERT((wcslen(*ppwszPath) + 1) * sizeof(WCHAR) == cb);
if (L'\0' == awc[0] && L'\\' == (*ppwszPath)[cb / sizeof(WCHAR) - 2])
{
(*ppwszPath)[cb / sizeof(WCHAR) - 2] = L'\0';
}
if (NULL != ppwszName)
{
*ppwszName = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pwszName) + 1) * sizeof(WCHAR));
if (NULL == *ppwszName)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(*ppwszName, pwszName);
}
if (NULL != phkey)
{
*phkey = hkeyRequested;
hkeyRequested = NULL;
}
hr = S_OK;
//printf("key path = '%ws'\n", *ppwszPath);
//if (NULL != ppwszName) printf("value name = '%ws'\n", *ppwszName);
error:
if (HKEY_LOCAL_MACHINE != hkeyRoot && HKEY_CURRENT_USER != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
if (NULL != hkeyConfig)
{
RegCloseKey(hkeyConfig);
}
if (NULL != hkeyMod)
{
RegCloseKey(hkeyMod);
}
if (NULL != hkeyRequested)
{
RegCloseKey(hkeyRequested);
}
if (NULL != pwszMachine)
{
LocalFree(pwszMachine);
}
if (S_OK != hr)
{
if (NULL != ppwszPath && NULL != *ppwszPath)
{
LocalFree(*ppwszPath);
*ppwszPath = NULL;
}
if (NULL != ppwszName && NULL != *ppwszName)
{
LocalFree(*ppwszName);
*ppwszName = NULL;
}
}
return(myHError(hr));
}
#define wszTEMPLATE wszFCSAPARM_SERVERDNSNAME L"_" wszFCSAPARM_SANITIZEDCANAME
#define cwcTEMPLATE WSZARRAYSIZE(wszTEMPLATE)
HRESULT
mySetCARegFileNameTemplate(
IN WCHAR const *pwszRegValueName,
IN WCHAR const *pwszServerName,
IN WCHAR const *pwszSanitizedName,
IN WCHAR const *pwszFileName)
{
HRESULT hr;
WCHAR *pwszMatch = NULL;
WCHAR *pwszMatchIn;
WCHAR const *pwszBase;
WCHAR const *pwszExt;
DWORD cwcPath;
DWORD cwcBase;
DWORD cwcMatch;
DWORD cwcT;
WCHAR *pwszT = NULL;
WCHAR *pwszT2;
pwszBase = wcsrchr(pwszFileName, L'\\');
if (NULL == pwszBase)
{
hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
_JumpErrorStr(hr, error, "bad path", pwszFileName);
}
pwszBase++;
cwcPath = SAFE_SUBTRACT_POINTERS(pwszBase, pwszFileName);
pwszExt = wcsrchr(pwszBase, L'.');
if (NULL == pwszExt)
{
pwszExt = &pwszBase[wcslen(pwszBase)];
}
cwcBase = SAFE_SUBTRACT_POINTERS(pwszExt, pwszBase);
cwcMatch = wcslen(pwszServerName) + 1 + wcslen(pwszSanitizedName);
if (cwcBase == cwcMatch)
{
// Allocate space for both strings at once:
pwszMatch = (WCHAR *) LocalAlloc(
LMEM_FIXED,
2 * (cwcMatch + 1) * sizeof(WCHAR));
if (NULL == pwszMatch)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(pwszMatch, pwszServerName);
wcscat(pwszMatch, L"_");
wcscat(pwszMatch, pwszSanitizedName);
pwszMatchIn = &pwszMatch[cwcMatch + 1];
CopyMemory(pwszMatchIn, pwszBase, cwcMatch * sizeof(WCHAR));
pwszMatchIn[cwcMatch] = L'\0';
if (0 == mylstrcmpiL(pwszMatch, pwszMatchIn))
{
pwszBase = wszTEMPLATE;
cwcBase = cwcTEMPLATE;
}
}
cwcT = cwcPath +
cwcBase +
WSZARRAYSIZE(wszFCSAPARM_CERTFILENAMESUFFIX) +
wcslen(pwszExt);
pwszT = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(cwcT + 1) * sizeof(WCHAR));
if (NULL == pwszT)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pwszT2 = pwszT;
CopyMemory(pwszT2, pwszFileName, cwcPath * sizeof(WCHAR));
pwszT2 += cwcPath;
CopyMemory(pwszT2, pwszBase, cwcBase * sizeof(WCHAR));
pwszT2 += cwcBase;
wcscpy(pwszT2, wszFCSAPARM_CERTFILENAMESUFFIX);
wcscat(pwszT2, pwszExt);
hr = mySetCertRegStrValue(
pwszSanitizedName,
NULL,
NULL,
pwszRegValueName,
pwszT);
_JumpIfErrorStr(hr, error, "mySetCertRegStrValue", pwszRegValueName);
error:
if (NULL != pwszMatch)
{
LocalFree(pwszMatch);
}
if (NULL != pwszT)
{
LocalFree(pwszT);
}
return(hr);
}
HRESULT
myGetCARegFileNameTemplate(
IN WCHAR const *pwszRegValueName,
IN WCHAR const *pwszServerName,
IN WCHAR const *pwszSanitizedName,
IN DWORD iCert,
IN DWORD iCRL,
OUT WCHAR **ppwszFileName)
{
HRESULT hr;
WCHAR *pwszT = NULL;
*ppwszFileName = NULL;
hr = myGetCertRegStrValue(
pwszSanitizedName,
NULL,
NULL,
pwszRegValueName,
&pwszT);
_JumpIfErrorStr2(
hr,
error,
"myGetCertRegStrValue",
pwszRegValueName,
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
hr = myFormatCertsrvStringArray(
FALSE, // fURL
pwszServerName, // pwszServerName_p1_2
pwszSanitizedName, // pwszSanitizedName_p3_7
iCert, // iCert_p4
MAXDWORD, // iCertTarget_p4
L"", // pwszDomainDN_p5
L"", // pwszConfigDN_p6
iCRL, // iCRL_p8
FALSE, // fDeltaCRL_p9
FALSE, // fDSAttrib_p10_11
1, // cStrings
(LPCWSTR *) &pwszT, // apwszStringsIn
ppwszFileName); // apwszStringsOut
_JumpIfError(hr, error, "myFormatCertsrvStringArray");
error:
if (NULL != pwszT)
{
LocalFree(pwszT);
}
return(hr);
}