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.
483 lines
13 KiB
483 lines
13 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
//
|
|
// File: ceformat.cpp
|
|
//
|
|
// Contents: helper functions
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
#include "celib.h"
|
|
#include <assert.h>
|
|
#include <wininet.h>
|
|
|
|
|
|
|
|
HRESULT
|
|
ceDupString(
|
|
IN WCHAR const *pwszIn,
|
|
IN WCHAR **ppwszOut)
|
|
{
|
|
DWORD cb;
|
|
HRESULT hr;
|
|
|
|
cb = (wcslen(pwszIn) + 1) * sizeof(WCHAR);
|
|
*ppwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == *ppwszOut)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
CopyMemory(*ppwszOut, pwszIn, cb);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
#define cwcCNMAX 64 // 64 chars max for CN
|
|
#define cwcCHOPHASHMAX (1 + 5) // "-%05hu" decimal USHORT hash digits
|
|
#define cwcCHOPBASE (cwcCNMAX - (cwcCHOPHASHMAX + cwcSUFFIXMAX))
|
|
|
|
HRESULT
|
|
ceSanitizedNameToDSName(
|
|
IN WCHAR const *pwszSanitizedName,
|
|
OUT WCHAR **ppwszNameOut)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cwc;
|
|
DWORD cwcCopy;
|
|
WCHAR wszDSName[cwcCHOPBASE + cwcCHOPHASHMAX + 1];
|
|
|
|
*ppwszNameOut = NULL;
|
|
|
|
cwc = wcslen(pwszSanitizedName);
|
|
cwcCopy = cwc;
|
|
if (cwcCHOPBASE < cwcCopy)
|
|
{
|
|
cwcCopy = cwcCHOPBASE;
|
|
}
|
|
CopyMemory(wszDSName, pwszSanitizedName, cwcCopy * sizeof(WCHAR));
|
|
wszDSName[cwcCopy] = L'\0';
|
|
|
|
if (cwcCHOPBASE < cwc)
|
|
{
|
|
// Hash the rest of the name into a USHORT
|
|
USHORT usHash = 0;
|
|
DWORD i;
|
|
WCHAR *pwsz;
|
|
|
|
// Truncate an incomplete sanitized Unicode character
|
|
|
|
pwsz = wcsrchr(wszDSName, L'!');
|
|
if (NULL != pwsz && wcslen(pwsz) < 5)
|
|
{
|
|
cwcCopy -= wcslen(pwsz);
|
|
*pwsz = L'\0';
|
|
}
|
|
|
|
for (i = cwcCopy; i < cwc; i++)
|
|
{
|
|
USHORT usLowBit = (0x8000 & usHash)? 1 : 0;
|
|
|
|
usHash = ((usHash << 1) | usLowBit) + pwszSanitizedName[i];
|
|
}
|
|
wsprintf(&wszDSName[cwcCopy], L"-%05hu", usHash);
|
|
assert(wcslen(wszDSName) < ARRAYSIZE(wszDSName));
|
|
}
|
|
|
|
hr = ceDupString(wszDSName, ppwszNameOut);
|
|
_JumpIfError(hr, error, "ceDupString");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ceInternetCanonicalizeUrl(
|
|
IN WCHAR const *pwszIn,
|
|
OUT WCHAR **ppwszOut)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwsz = NULL;
|
|
|
|
assert(NULL != pwszIn);
|
|
|
|
if (0 == _wcsnicmp(L"file:", pwszIn, 5))
|
|
{
|
|
hr = ceDupString(pwszIn, &pwsz);
|
|
_JumpIfError(hr, error, "ceDupString");
|
|
}
|
|
else
|
|
{
|
|
// Calculate required buffer size by passing a very small buffer
|
|
// The call will fail, and tell us how big the buffer should be.
|
|
|
|
WCHAR wszPlaceHolder[1];
|
|
DWORD cwc = ARRAYSIZE(wszPlaceHolder);
|
|
BOOL bResult;
|
|
|
|
bResult = InternetCanonicalizeUrl(
|
|
pwszIn, // lpszUrl
|
|
wszPlaceHolder, // lpszBuffer
|
|
&cwc, // lpdwBufferLength
|
|
0); // dwFlags
|
|
assert(!bResult); // This will always fail
|
|
|
|
hr = ceHLastError();
|
|
if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
|
|
{
|
|
// unexpected error
|
|
|
|
_JumpError(hr, error, "InternetCanonicalizeUrl");
|
|
}
|
|
|
|
// NOTE: InternetCanonicalizeUrl counts characters, not bytes as doc'd
|
|
// cwc includes trailing L'0'
|
|
|
|
pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
|
|
if (NULL == pwsz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
// canonicalize
|
|
if (!InternetCanonicalizeUrl(
|
|
pwszIn, // lpszUrl
|
|
pwsz, // lpszBuffer
|
|
&cwc, // lpdwBufferLength
|
|
0)) // dwFlags
|
|
{
|
|
hr = ceHLastError();
|
|
_JumpError(hr, error, "InternetCanonicalizeUrl");
|
|
}
|
|
}
|
|
*ppwszOut = pwsz;
|
|
pwsz = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwsz)
|
|
{
|
|
LocalFree(pwsz);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// ceFormatCertsrvStringArray FormatMessage arguments:
|
|
//
|
|
// %1 -- Machine full DNS name: pwszServerName_p1_2;
|
|
//
|
|
// %2 -- Machine short name: first DNS component of pwszServerName_p1_2
|
|
//
|
|
// %3 -- Sanitized CA name: pwszSanitizedName_p3_7
|
|
//
|
|
// %4 -- Cert Filename Suffix:
|
|
// if 0 == iCert_p4 && MAXDWORD == iCertTarget_p4: L""
|
|
// else if MAXDWORD != iCertTarget_p4 L"(%u-%u)"
|
|
// else L"(%u)"
|
|
//
|
|
// %5 -- DS DN path to Domain root: pwszDomainDN_p5
|
|
//
|
|
// %6 -- DS DN path to Configuration container: pwszConfigDN_p6
|
|
//
|
|
// %7 -- Sanitized CA name, truncated and hash suffix added if too long:
|
|
// pwszSanitizedName_p3_7
|
|
//
|
|
// %8 -- CRL Filename/Key Name Suffix: L"" if 0 == iCRL_p8; else L"(%u)"
|
|
//
|
|
// %9 -- CRL Filename Suffix: L"" if !fDeltaCRL_p9; else L"+"
|
|
//
|
|
// %10 -- DS CRL attribute: L"" if !fDSAttrib_p10_11; depends on fDeltaCRL_p9
|
|
//
|
|
// %11 -- DS CA Cert attribute: L"" if !fDSAttrib_p10_11
|
|
//
|
|
// %12 -- DS user cert attribute
|
|
//
|
|
// %13 -- DS KRA cert attribute
|
|
//
|
|
// %14 -- DS cross cert pair attribute
|
|
|
|
#ifndef wszDSSEARCHBASECRLATTRIBUTE
|
|
#define wszDSSEARCHBASECRLATTRIBUTE L"?certificateRevocationList?base?objectclass=cRLDistributionPoint"
|
|
#endif
|
|
|
|
#ifndef wszDSSEARCHDELTACRLATTRIBUTE
|
|
#define wszDSSEARCHDELTACRLATTRIBUTE L"?deltaRevocationList?base?objectclass=cRLDistributionPoint"
|
|
#endif
|
|
|
|
#ifndef wszDSSEARCHCACERTATTRIBUTE
|
|
#define wszDSSEARCHCACERTATTRIBUTE L"?cACertificate?base?objectclass=certificationAuthority"
|
|
#endif
|
|
|
|
#ifndef wszDSSEARCHUSERCERTATTRIBUTE
|
|
#define wszDSSEARCHUSERCERTATTRIBUTE L"?userCertificate?base?objectClass=*"
|
|
#endif
|
|
|
|
#ifndef wszDSSEARCHKRACERTATTRIBUTE
|
|
#define wszDSSEARCHKRACERTATTRIBUTE L"?userCertificate?one?objectClass=msPKI-PrivateKeyRecoveryAgent"
|
|
#endif
|
|
|
|
#ifndef wszDSSEARCHCROSSCERTPAIRATTRIBUTE
|
|
#define wszDSSEARCHCROSSCERTPAIRATTRIBUTE L"?crossCertificatePair?one?objectClass=certificationAuthority"
|
|
#endif
|
|
|
|
|
|
HRESULT
|
|
ceFormatCertsrvStringArray(
|
|
IN BOOL fURL,
|
|
IN LPCWSTR pwszServerName_p1_2,
|
|
IN LPCWSTR pwszSanitizedName_p3_7,
|
|
IN DWORD iCert_p4,
|
|
IN DWORD iCertTarget_p4,
|
|
IN LPCWSTR pwszDomainDN_p5,
|
|
IN LPCWSTR pwszConfigDN_p6,
|
|
IN DWORD iCRL_p8,
|
|
IN BOOL fDeltaCRL_p9,
|
|
IN BOOL fDSAttrib_p10_11,
|
|
IN DWORD cStrings,
|
|
IN LPCWSTR *apwszStringsIn,
|
|
OUT LPWSTR *apwszStringsOut)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPCWSTR apwszInsertionArray[100]; // 100 'cause this is the max number of insertion numbers allowed by FormatMessage
|
|
LPWSTR pwszCurrent = NULL;
|
|
BSTR strShortMachineName = NULL;
|
|
DWORD i;
|
|
WCHAR *pwszSanitizedDSName = NULL;
|
|
WCHAR wszCertSuffix[2 * cwcFILENAMESUFFIXMAX];
|
|
WCHAR wszCRLSuffix[cwcFILENAMESUFFIXMAX];
|
|
WCHAR wszDeltaCRLSuffix[cwcFILENAMESUFFIXMAX];
|
|
WCHAR const *pwszT;
|
|
|
|
|
|
ZeroMemory(apwszStringsOut, cStrings * sizeof(apwszStringsOut[0]));
|
|
ZeroMemory(apwszInsertionArray, sizeof(apwszInsertionArray));
|
|
|
|
// Format the template into a real name
|
|
// Initialize the insertion string array.
|
|
|
|
//+================================================
|
|
// Machine DNS name (%1)
|
|
|
|
assert(L'1' == wszFCSAPARM_SERVERDNSNAME[1]);
|
|
apwszInsertionArray[1 - 1] = pwszServerName_p1_2;
|
|
|
|
//+================================================
|
|
// Short Machine Name (%2)
|
|
|
|
assert(L'2' == wszFCSAPARM_SERVERSHORTNAME[1]);
|
|
strShortMachineName = SysAllocString(pwszServerName_p1_2);
|
|
if (strShortMachineName == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpIfError(hr, error, "SysAllocString");
|
|
}
|
|
|
|
pwszCurrent = wcschr(strShortMachineName, L'.');
|
|
if (NULL != pwszCurrent)
|
|
{
|
|
*pwszCurrent = 0;
|
|
}
|
|
apwszInsertionArray[2 - 1] = strShortMachineName;
|
|
|
|
//+================================================
|
|
// sanitized name (%3)
|
|
|
|
assert(L'3' == wszFCSAPARM_SANITIZEDCANAME[1]);
|
|
apwszInsertionArray[3 - 1] = pwszSanitizedName_p3_7;
|
|
|
|
//+================================================
|
|
// Cert filename suffix (%4) | (%4-%4)
|
|
|
|
assert(L'4' == wszFCSAPARM_CERTFILENAMESUFFIX[1]);
|
|
wszCertSuffix[0] = L'\0';
|
|
if (0 != iCert_p4 || MAXDWORD != iCertTarget_p4)
|
|
{
|
|
wsprintf(
|
|
wszCertSuffix,
|
|
MAXDWORD != iCertTarget_p4? L"(%u-%u)" : L"(%u)",
|
|
iCert_p4,
|
|
iCertTarget_p4);
|
|
}
|
|
apwszInsertionArray[4 - 1] = wszCertSuffix;
|
|
|
|
//+================================================
|
|
// Domain DN (%5)
|
|
|
|
if (NULL == pwszDomainDN_p5 || L'\0' == *pwszDomainDN_p5)
|
|
{
|
|
pwszDomainDN_p5 = L"DC=UnavailableDomainDN";
|
|
}
|
|
assert(L'5' == wszFCSAPARM_DOMAINDN[1]);
|
|
apwszInsertionArray[5 - 1] = pwszDomainDN_p5;
|
|
|
|
//+================================================
|
|
// Config DN (%6)
|
|
|
|
if (NULL == pwszConfigDN_p6 || L'\0' == *pwszConfigDN_p6)
|
|
{
|
|
pwszConfigDN_p6 = L"DC=UnavailableConfigDN";
|
|
}
|
|
assert(L'6' == wszFCSAPARM_CONFIGDN[1]);
|
|
apwszInsertionArray[6 - 1] = pwszConfigDN_p6;
|
|
|
|
// Don't pass pwszSanitizedName_p3_7 to SysAllocStringLen with the extended
|
|
// length to avoid faulting past end of pwszSanitizedName_p3_7.
|
|
|
|
//+================================================
|
|
// Sanitized Short Name (%7)
|
|
|
|
assert(L'7' == wszFCSAPARM_SANITIZEDCANAMEHASH[1]);
|
|
hr = ceSanitizedNameToDSName(pwszSanitizedName_p3_7, &pwszSanitizedDSName);
|
|
_JumpIfError(hr, error, "ceSanitizedNameToDSName");
|
|
|
|
apwszInsertionArray[7 - 1] = pwszSanitizedDSName;
|
|
|
|
//+================================================
|
|
// CRL filename suffix (%8)
|
|
|
|
assert(L'8' == wszFCSAPARM_CRLFILENAMESUFFIX[1]);
|
|
wszCRLSuffix[0] = L'\0';
|
|
if (0 != iCRL_p8)
|
|
{
|
|
wsprintf(wszCRLSuffix, L"(%u)", iCRL_p8);
|
|
}
|
|
apwszInsertionArray[8 - 1] = wszCRLSuffix;
|
|
|
|
//+================================================
|
|
// Delta CRL filename suffix (%9)
|
|
|
|
assert(L'9' == wszFCSAPARM_CRLDELTAFILENAMESUFFIX[1]);
|
|
wszDeltaCRLSuffix[0] = L'\0';
|
|
if (fDeltaCRL_p9)
|
|
{
|
|
wcscpy(wszDeltaCRLSuffix, L"+");
|
|
}
|
|
apwszInsertionArray[9 - 1] = wszDeltaCRLSuffix;
|
|
|
|
//+================================================
|
|
// CRL attribute (%10)
|
|
|
|
assert(L'1' == wszFCSAPARM_DSCRLATTRIBUTE[1]);
|
|
assert(L'0' == wszFCSAPARM_DSCRLATTRIBUTE[2]);
|
|
pwszT = L"";
|
|
if (fDSAttrib_p10_11)
|
|
{
|
|
pwszT = fDeltaCRL_p9?
|
|
wszDSSEARCHDELTACRLATTRIBUTE :
|
|
wszDSSEARCHBASECRLATTRIBUTE;
|
|
}
|
|
apwszInsertionArray[10 - 1] = pwszT;
|
|
|
|
//+================================================
|
|
// CA cert attribute (%11)
|
|
|
|
assert(L'1' == wszFCSAPARM_DSCACERTATTRIBUTE[1]);
|
|
assert(L'1' == wszFCSAPARM_DSCACERTATTRIBUTE[2]);
|
|
pwszT = L"";
|
|
if (fDSAttrib_p10_11)
|
|
{
|
|
pwszT = wszDSSEARCHCACERTATTRIBUTE;
|
|
}
|
|
apwszInsertionArray[11 - 1] = pwszT;
|
|
|
|
//+================================================
|
|
// User cert attribute (%12)
|
|
|
|
assert(L'1' == wszFCSAPARM_DSUSERCERTATTRIBUTE[1]);
|
|
assert(L'2' == wszFCSAPARM_DSUSERCERTATTRIBUTE[2]);
|
|
pwszT = L"";
|
|
if (fDSAttrib_p10_11)
|
|
{
|
|
pwszT = wszDSSEARCHUSERCERTATTRIBUTE;
|
|
}
|
|
apwszInsertionArray[12 - 1] = pwszT;
|
|
|
|
//+================================================
|
|
// KRA cert attribute (%13)
|
|
|
|
assert(L'1' == wszFCSAPARM_DSKRACERTATTRIBUTE[1]);
|
|
assert(L'3' == wszFCSAPARM_DSKRACERTATTRIBUTE[2]);
|
|
pwszT = L"";
|
|
if (fDSAttrib_p10_11)
|
|
{
|
|
pwszT = wszDSSEARCHKRACERTATTRIBUTE;
|
|
}
|
|
apwszInsertionArray[13 - 1] = pwszT;
|
|
|
|
//+================================================
|
|
// Cross cert pair attribute (%14)
|
|
|
|
assert(L'1' == wszFCSAPARM_DSCROSSCERTPAIRATTRIBUTE[1]);
|
|
assert(L'4' == wszFCSAPARM_DSCROSSCERTPAIRATTRIBUTE[2]);
|
|
pwszT = L"";
|
|
if (fDSAttrib_p10_11)
|
|
{
|
|
pwszT = wszDSSEARCHCROSSCERTPAIRATTRIBUTE;
|
|
}
|
|
apwszInsertionArray[14 - 1] = pwszT;
|
|
|
|
//+================================================
|
|
// Now format the strings...
|
|
|
|
for (i = 0; i < cStrings; i++)
|
|
{
|
|
if (0 == FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_STRING |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
(VOID *) apwszStringsIn[i],
|
|
0, // dwMessageID
|
|
0, // dwLanguageID
|
|
(LPWSTR) &apwszStringsOut[i],
|
|
wcslen(apwszStringsIn[i]),
|
|
(va_list *) apwszInsertionArray))
|
|
{
|
|
hr = ceHLastError();
|
|
_JumpError(hr, error, "FormatMessage");
|
|
}
|
|
if (fURL)
|
|
{
|
|
WCHAR *pwsz;
|
|
|
|
hr = ceInternetCanonicalizeUrl(apwszStringsOut[i], &pwsz);
|
|
_JumpIfError(hr, error, "ceInternetCanonicalizeUrl");
|
|
|
|
LocalFree(apwszStringsOut[i]);
|
|
apwszStringsOut[i] = pwsz;
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
for (i = 0; i < cStrings; i++)
|
|
{
|
|
if (NULL != apwszStringsOut[i])
|
|
{
|
|
LocalFree(apwszStringsOut[i]);
|
|
apwszStringsOut[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (NULL != strShortMachineName)
|
|
{
|
|
SysFreeString(strShortMachineName);
|
|
}
|
|
if (NULL != pwszSanitizedDSName)
|
|
{
|
|
LocalFree(pwszSanitizedDSName);
|
|
}
|
|
return (hr);
|
|
}
|