//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: certlib.cpp // // Contents: Cert Server wrapper routines // //--------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include extern "C" { #include } #include #include "csdisp.h" #include "csprop.h" #include #include #include #include "csldap.h" #include #include "cainfop.h" #include #include #define __dwFILE__ __dwFILE_CERTLIB_CERTLIB_CPP__ #define wszSANITIZEESCAPECHAR L"!" #define wszURLESCAPECHAR L"%" #define wcSANITIZEESCAPECHAR L'!' char PrintableChar(char ch) { if (ch < ' ' || ch > '~') { ch = '.'; } return(ch); } VOID mydbgDumpHex( IN DWORD dwSubSysId, IN DWORD Flags, IN BYTE const *pb, IN ULONG cb) { if (DbgIsSSActive(dwSubSysId)) { DumpHex(Flags, pb, cb); } } VOID DumpHex( IN DWORD Flags, IN BYTE const *pb, IN ULONG cb) { char const *pszsep; ULONG r; ULONG i; ULONG cbremain; BOOL fZero = FALSE; DWORD cchIndent; DWORD cchAsciiSep; char szAddress[8 + 1]; char szHexDump[1 + 1 + 3 * 16 + 1]; char szAsciiDump[16 + 1]; char *psz; cchIndent = DH_INDENTMASK & Flags; if ((DH_MULTIADDRESS & Flags) && 16 >= cb) { Flags |= DH_NOADDRESS; } cbremain = 0; for (r = 0; r < cb; r += 16) { szAddress[0] = '\0'; if (0 == (DH_NOADDRESS & Flags)) { sprintf(szAddress, 64 * 1024 < cb? "%06x": "%04x", r); CSASSERT(strlen(szAddress) < ARRAYSIZE(szAddress)); } cbremain = cb - r; if (r != 0 && pb[r] == 0 && cbremain >= 16) { ULONG j; for (j = r + 1; j < cb; j++) { if (pb[j] != 0) { break; } } if (j == cb) { fZero = TRUE; break; } } psz = szHexDump; for (i = 0; i < min(cbremain, 16); i++) { pszsep = " "; if ((i % 8) == 0) // 0 or 8 { pszsep = " "; if (i == 0) // 0 { if (0 == (DH_NOTABPREFIX & Flags)) { pszsep = "\t"; } else if (DH_NOADDRESS & Flags) { pszsep = ""; } } } CSASSERT(strlen(pszsep) <= 2); psz += sprintf(psz, "%hs%02x", pszsep, pb[r + i]); } *psz = '\0'; CSASSERT(strlen(szHexDump) < ARRAYSIZE(szHexDump)); cchAsciiSep = 0; szAsciiDump[0] = '\0'; if (0 == (DH_NOASCIIHEX & Flags) && 0 != i) { cchAsciiSep = 3 + (16 - i)*3 + ((i <= 8)? 1 : 0); for (i = 0; i < min(cbremain, 16); i++) { szAsciiDump[i] = PrintableChar(pb[r + i]); } szAsciiDump[i] = '\0'; CSASSERT(strlen(szAsciiDump) < ARRAYSIZE(szAsciiDump)); } char szBuf[ sizeof(szAddress) + sizeof(szHexDump) + 3 + sizeof(szAsciiDump)]; _snprintf( szBuf, ARRAYSIZE(szBuf), "%hs%hs%*hs%hs", szAddress, szHexDump, cchAsciiSep, "", szAsciiDump); szBuf[ARRAYSIZE(szBuf) - 1] = '\0'; CSASSERT(strlen(szBuf) + 1 < ARRAYSIZE(szBuf)); #define szFMTHEXDUMP "%*hs%hs\n" if (DH_PRIVATEDATA & Flags) { wprintf(TEXT(szFMTHEXDUMP), cchIndent, "", szBuf); } else { CONSOLEPRINT7((MAXDWORD, szFMTHEXDUMP, cchIndent, "", szBuf)); } } if (fZero) { CONSOLEPRINT1((MAXDWORD, "\tRemaining %lx bytes are zero\n", cbremain)); } } HRESULT myDateToFileTime( IN DATE const *pDate, OUT FILETIME *pft) { SYSTEMTIME st; HRESULT hr = S_OK; if (*pDate == 0.0) { GetSystemTime(&st); } else { if (!VariantTimeToSystemTime(*pDate, &st)) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "VariantTimeToSystemTime"); } } if (!SystemTimeToFileTime(&st, pft)) { hr = myHLastError(); _JumpError(hr, error, "SystemTimeToFileTime"); } error: return(hr); } HRESULT myMakeExprDate( IN OUT DATE *pDate, IN LONG lDelta, IN enum ENUM_PERIOD enumPeriod) { HRESULT hr; FILETIME ft; hr = myDateToFileTime(pDate, &ft); _JumpIfError(hr, error, "myDateToFileTime"); myMakeExprDateTime(&ft, lDelta, enumPeriod); hr = myFileTimeToDate(&ft, pDate); _JumpIfError(hr, error, "myFileTimeToDate"); error: return(hr); } typedef struct _UNITSTABLE { WCHAR const *pwszString; enum ENUM_PERIOD enumPeriod; } UNITSTABLE; UNITSTABLE g_aut[] = { { wszPERIODSECONDS, ENUM_PERIOD_SECONDS }, { wszPERIODMINUTES, ENUM_PERIOD_MINUTES }, { wszPERIODHOURS, ENUM_PERIOD_HOURS }, { wszPERIODDAYS, ENUM_PERIOD_DAYS }, { wszPERIODWEEKS, ENUM_PERIOD_WEEKS }, { wszPERIODMONTHS, ENUM_PERIOD_MONTHS }, { wszPERIODYEARS, ENUM_PERIOD_YEARS }, }; #define CUNITSTABLEMAX (sizeof(g_aut)/sizeof(g_aut[0])) HRESULT myTranslatePeriodUnits( IN WCHAR const *pwszPeriod, IN LONG lCount, OUT enum ENUM_PERIOD *penumPeriod, OUT LONG *plCount) { HRESULT hr; UNITSTABLE const *put; for (put = g_aut; put < &g_aut[CUNITSTABLEMAX]; put++) { if (0 == mylstrcmpiS(pwszPeriod, put->pwszString)) { *penumPeriod = put->enumPeriod; if (0 > lCount) { lCount = MAXLONG; } *plCount = lCount; hr = S_OK; goto error; } } hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); error: CSASSERT(hr == S_OK); return(hr); } HRESULT myTranslateUnlocalizedPeriodString( IN enum ENUM_PERIOD enumPeriod, OUT WCHAR const **ppwszPeriodString) { HRESULT hr; UNITSTABLE const *put; *ppwszPeriodString = NULL; for (put = g_aut; put < &g_aut[CUNITSTABLEMAX]; put++) { if (enumPeriod == put->enumPeriod) { *ppwszPeriodString = put->pwszString; hr = S_OK; goto error; } } hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); error: CSASSERT(hr == S_OK); return(hr); } HRESULT myFileTimePeriodToWszTimePeriod( IN FILETIME const *pftGMT, IN BOOL fExact, OUT WCHAR **ppwszTimePeriod) { HRESULT hr; DWORD cPeriodUnits; PERIODUNITS *rgPeriodUnits = NULL; WCHAR const *pwszUnitSep; DWORD i; WCHAR awc[MAX_PATH]; WCHAR *pwsz; *ppwszTimePeriod = NULL; hr = caTranslateFileTimePeriodToPeriodUnits( pftGMT, fExact, &cPeriodUnits, &rgPeriodUnits); _JumpIfError(hr, error, "caTranslateFileTimePeriodToPeriodUnits"); CSASSERT(0 < cPeriodUnits); pwszUnitSep = L""; pwsz = awc; for (i = 0; i < cPeriodUnits; i++) { WCHAR const *pwszPeriodString; hr = myTranslateUnlocalizedPeriodString( rgPeriodUnits[i].enumPeriod, &pwszPeriodString); _JumpIfError(hr, error, "myTranslateUnlocalizedPeriodString"); pwsz += wsprintf( pwsz, L"%ws%u %ws", pwszUnitSep, rgPeriodUnits[i].lCount, pwszPeriodString); pwszUnitSep = L", "; } hr = myDupString(awc, ppwszTimePeriod); _JumpIfError(hr, error, "myDupString"); error: if (NULL != rgPeriodUnits) { LocalFree(rgPeriodUnits); } return(hr); } HRESULT myFileTimeToDate( IN FILETIME const *pft, OUT DATE *pDate) { SYSTEMTIME st; HRESULT hr = S_OK; if (!FileTimeToSystemTime(pft, &st)) { hr = myHLastError(); _JumpError(hr, error, "FileTimeToSystemTime"); } if (!SystemTimeToVariantTime(&st, pDate)) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "SystemTimeToVariantTime"); } error: return(hr); } HRESULT mySystemTimeToGMTSystemTime( IN OUT SYSTEMTIME *pSys) { // Conversion path: SystemTimeLocal -> ftLocal -> ftGMT -> SystemTimeGMT FILETIME ftLocal, ftGMT; HRESULT hr = S_OK; if (!SystemTimeToFileTime(pSys, &ftLocal)) { hr = myHLastError(); _JumpError(hr, error, "SystemTimeToFileTime"); } if (!LocalFileTimeToFileTime(&ftLocal, &ftGMT)) { hr = myHLastError(); _JumpError(hr, error, "LocalFileTimeToFileTime"); } if (!FileTimeToSystemTime(&ftGMT, pSys)) { hr = myHLastError(); _JumpError(hr, error, "FileTimeToSystemTime"); } error: return hr; } HRESULT myGMTFileTimeToWszLocalTime( IN FILETIME const *pftGMT, IN BOOL fSeconds, OUT WCHAR **ppwszLocalTime) { HRESULT hr; FILETIME ftLocal; *ppwszLocalTime = NULL; if (!FileTimeToLocalFileTime(pftGMT, &ftLocal)) { hr = myHLastError(); _JumpError(hr, error, "FileTimeToLocalFileTime"); } hr = myFileTimeToWszTime(&ftLocal, fSeconds, ppwszLocalTime); _JumpIfError(hr, error, "myFileTimeToWszTime"); error: return(hr); } HRESULT myFileTimeToWszTime( IN FILETIME const *pft, IN BOOL fSeconds, OUT WCHAR **ppwszTime) { HRESULT hr; SYSTEMTIME st; WCHAR awcDate[128]; WCHAR awcTime[128]; WCHAR *pwsz; *ppwszTime = NULL; if (!FileTimeToSystemTime(pft, &st)) { hr = myHLastError(); _JumpError(hr, error, "FileTimeToSystemTime"); } if (0 == GetDateFormat( LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, awcDate, sizeof(awcDate)/sizeof(awcDate[0]))) { hr = myHLastError(); _JumpError(hr, error, "GetDateFormat"); } if (0 == GetTimeFormat( LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, awcTime, sizeof(awcTime)/sizeof(awcTime[0]))) { hr = myHLastError(); _JumpError(hr, error, "GetTimeFormat"); } if (fSeconds) { wsprintf( &awcTime[wcslen(awcTime)], L" %02u.%03us", st.wSecond, st.wMilliseconds); } pwsz = (WCHAR *) LocalAlloc( LMEM_FIXED, (wcslen(awcDate) + 1 + wcslen(awcTime) + 1) * sizeof(WCHAR)); if (NULL == pwsz) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwsz, awcDate); wcscat(pwsz, L" "); wcscat(pwsz, awcTime); *ppwszTime = pwsz; hr = S_OK; error: return(hr); } HRESULT myGMTDateToWszLocalTime( IN DATE const *pDateGMT, IN BOOL fSeconds, OUT WCHAR **ppwszLocalTime) { HRESULT hr; FILETIME ftGMT; *ppwszLocalTime = NULL; hr = myDateToFileTime(pDateGMT, &ftGMT); _JumpIfError(hr, error, "myDateToFileTime"); hr = myGMTFileTimeToWszLocalTime(&ftGMT, fSeconds, ppwszLocalTime); _JumpIfError(hr, error, "FileTimeToLocalFileTime"); hr = S_OK; error: return(hr); } HRESULT myWszLocalTimeToGMTDate( IN WCHAR const *pwszLocalTime, OUT DATE *pDateGMT) { HRESULT hr; FILETIME ftGMT; hr = myWszLocalTimeToGMTFileTime(pwszLocalTime, &ftGMT); _JumpIfError2(hr, error, "myWszLocalTimeToGMTFileTime", E_INVALIDARG); hr = myFileTimeToDate(&ftGMT, pDateGMT); _JumpIfError(hr, error, "myFileTimeToDate"); error: return(hr); } HRESULT myWszLocalTimeToGMTFileTime( IN WCHAR const *pwszLocalTime, OUT FILETIME *pftGMT) { HRESULT hr; time_t time; USHORT parselen; struct tm *ptm; SYSTEMTIME stLocal; FILETIME ftLocal; char *pszLocalTime = NULL; if (!ConvertWszToSz(&pszLocalTime, pwszLocalTime, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToSz"); } hr = LUI_ParseDateTime(pszLocalTime, (time_t *) &time, &parselen, 0); if (S_OK != hr) { _PrintError2(hr, "LUI_ParseDateTime", hr); hr = E_INVALIDARG; _JumpError2(hr, error, "LUI_ParseDateTime", hr); } DBGPRINT(( DBG_SS_CERTLIBI, "myWszLocalTimeToGMTDate = %ws: %x -- %ws\n", pwszLocalTime, time, _wctime(&time))); ptm = gmtime(&time); if (ptm == NULL) { hr = E_UNEXPECTED; _JumpError(hr, error, "gmTime"); } stLocal.wYear = (WORD) ptm->tm_year + 1900; stLocal.wMonth = (WORD) ptm->tm_mon + 1; stLocal.wDayOfWeek = (WORD) ptm->tm_wday; stLocal.wDay = (WORD) ptm->tm_mday; stLocal.wHour = (WORD) ptm->tm_hour; stLocal.wMinute = (WORD) ptm->tm_min; stLocal.wSecond = (WORD) ptm->tm_sec; stLocal.wMilliseconds = 0; DBGPRINT(( DBG_SS_CERTLIBI, "%u/%u/%u %u:%02u:%02u.%03u DayOfWeek=%u\n", stLocal.wMonth, stLocal.wDay, stLocal.wYear, stLocal.wHour, stLocal.wMinute, stLocal.wSecond, stLocal.wMilliseconds, stLocal.wDayOfWeek)); if (!SystemTimeToFileTime(&stLocal, &ftLocal)) { hr = myHLastError(); _JumpError(hr, error, "SystemTimeToFileTime"); } if (!LocalFileTimeToFileTime(&ftLocal, pftGMT)) { hr = myHLastError(); _JumpError(hr, error, "LocalFileTimeToFileTime"); } error: if (NULL != pszLocalTime) { LocalFree(pszLocalTime); } return(hr); } // counts # of string in a multisz string DWORD CountMultiSz(LPCWSTR pcwszString) { DWORD dwCount = 0; if(!pcwszString) return 0; while(*pcwszString) { dwCount++; pcwszString += wcslen(pcwszString)+1; } return dwCount; } // // myRegValueToVariant and myVariantToRegValue map registry values // to/from variant: // // REG_SZ <-> VT_BSTR // REG_BINARY <-> VT_ARRAY|VT_UI1 // REG_DWORD <-> VT_I4 (VT_I2) // REG_MULTI_SZ <-> VT_ARRAY|VT_BSTR // HRESULT myRegValueToVariant( IN DWORD dwType, IN DWORD cbValue, IN BYTE const *pbValue, OUT VARIANT *pVar) { HRESULT hr = S_OK; SAFEARRAYBOUND sab; LPWSTR pwszCrtString = (LPWSTR)pbValue; BSTR bstr = NULL; SAFEARRAY* psa; VariantInit(pVar); switch(dwType) { case REG_SZ: if(sizeof(WCHAR)<=cbValue) cbValue -= sizeof(WCHAR); V_BSTR(pVar) = NULL; if (!ConvertWszToBstr( &(V_BSTR(pVar)), (WCHAR const *) pbValue, cbValue)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToBstr"); } V_VT(pVar) = VT_BSTR; break; case REG_BINARY: sab.cElements = cbValue; sab.lLbound = 0; psa = SafeArrayCreate( VT_UI1, 1, &sab); if(!psa) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SafeArrayCreate"); } for(DWORD c=0; cvt) { case VT_BYREF|VT_BSTR: case VT_BSTR: bstr = (pvarPropertyValue->vt & VT_BYREF)? *V_BSTRREF(pvarPropertyValue): V_BSTR(pvarPropertyValue); *pdwType = REG_SZ; if (NULL == bstr) { bstr = L""; } pbprop = (BYTE *) bstr; cbprop = (wcslen(bstr) + 1) * sizeof(WCHAR); break; case VT_BYREF|VT_ARRAY|VT_UI1: case VT_ARRAY|VT_UI1: psa = (pvarPropertyValue->vt & VT_BYREF)? *V_ARRAYREF(pvarPropertyValue): V_ARRAY(pvarPropertyValue); *pdwType = REG_BINARY; if(1!=SafeArrayGetDim(psa)) { hr = E_INVALIDARG; _JumpError(hr, error, "only 1 dim array of bytes allowed"); } hr = SafeArrayGetLBound( psa, 1, &lLbound); _JumpIfError(hr, error, "SafeArrayGetLBound"); hr = SafeArrayGetUBound( psa, 1, &lUbound); _JumpIfError(hr, error, "SafeArrayGetLBound"); hr = SafeArrayAccessData(psa, &pData); _JumpIfError(hr, error, "SafeArrayGetLBound"); cbprop = lUbound-lLbound+1; pbprop = (LPBYTE)pData; break; case VT_BYREF|VT_I2: case VT_I2: *pdwType = REG_DWORD; pbprop = (BYTE *)((pvarPropertyValue->vt & VT_BYREF)? V_I2REF(pvarPropertyValue): &V_I2(pvarPropertyValue)); cbprop = sizeof(V_I2(pvarPropertyValue)); break; case VT_BYREF|VT_I4: case VT_I4: *pdwType = REG_DWORD; pbprop = (BYTE *) ((pvarPropertyValue->vt & VT_BYREF)? V_I4REF(pvarPropertyValue): &V_I4(pvarPropertyValue)); cbprop = sizeof(pvarPropertyValue->lVal); break; case VT_BYREF|VT_ARRAY|VT_BSTR: case VT_ARRAY|VT_BSTR: psa = (pvarPropertyValue->vt & VT_BYREF)? *V_ARRAYREF(pvarPropertyValue): V_ARRAY(pvarPropertyValue); *pdwType = REG_MULTI_SZ; if(1!=SafeArrayGetDim(psa)) { hr = E_INVALIDARG; _JumpError(hr, error, "only 1 dim array of bstr allowed"); } hr = SafeArrayGetLBound( psa, 1, &lLbound); _JumpIfError(hr, error, "SafeArrayGetLBound"); hr = SafeArrayGetUBound( psa, 1, &lUbound); _JumpIfError(hr, error, "SafeArrayGetLBound"); hr = SafeArrayAccessData(psa, &pData); _JumpIfError(hr, error, "SafeArrayGetLBound"); for(LONG c=0;c<=lUbound-lLbound;c++) { BSTR str = ((BSTR *) pData)[c]; if (NULL == str) { hr = E_POINTER; _JumpError(hr, error, "BSTR NULL"); } cbprop += wcslen(str)+1; } cbprop += 1; cbprop *= sizeof(WCHAR); { BYTE* pbprop2 = (BYTE *) LocalAlloc(LMEM_FIXED, cbprop); if (NULL == pbprop2) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } *ppbprop = pbprop2; for(LONG c=0;c<=lUbound-lLbound;c++) { wcscpy((LPWSTR)pbprop2, ((BSTR*)pData)[c]); pbprop2 += (wcslen((LPWSTR)pbprop2)+1)*sizeof(WCHAR); } *(LPWSTR)pbprop2 = L'\0'; } break; default: hr = E_INVALIDARG; _JumpError(hr, error, "invalid variant type"); } if (NULL != pbprop) { *ppbprop = (BYTE *) LocalAlloc(LMEM_FIXED, cbprop); if (NULL == *ppbprop) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(*ppbprop, pbprop, cbprop); } *pcbprop = cbprop; error: if(pData) { CSASSERT(psa); SafeArrayUnaccessData(psa); } return(hr); } HRESULT myUnmarshalVariant( IN DWORD PropType, IN DWORD cbValue, IN BYTE const *pbValue, OUT VARIANT *pvarValue) { HRESULT hr = S_OK; CSASSERT(NULL != pvarValue); VariantInit(pvarValue); // pb = NULL, cb = 0 always returns VT_EMPTY if (NULL == pbValue) { CSASSERT(0 == cbValue); CSASSERT(VT_EMPTY == pvarValue->vt); goto error; } switch (PROPTYPE_MASK & PropType) { case PROPTYPE_STRING: if (0 == (PROPMARSHAL_LOCALSTRING & PropType) && sizeof(WCHAR) <= cbValue) { cbValue -= sizeof(WCHAR); } if (*(WCHAR const*)(pbValue+cbValue) != L'\0' && wcslen((WCHAR const *) pbValue) * sizeof(WCHAR) != cbValue) { hr = E_INVALIDARG; _JumpError(hr, error, "bad string len"); } // FALLTHROUGH: case PROPTYPE_BINARY: // CSASSERT(0 != cbValue); pvarValue->bstrVal = NULL; if (!ConvertWszToBstr( &pvarValue->bstrVal, (WCHAR const *) pbValue, cbValue)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToBstr"); } pvarValue->vt = VT_BSTR; break; case PROPTYPE_LONG: if (sizeof(LONG) != cbValue) { hr = E_INVALIDARG; _JumpError(hr, error, "bad PROPTYPE_LONG len"); } pvarValue->vt = VT_I4; pvarValue->lVal = *(LONG const *) pbValue; break; case PROPTYPE_DATE: if (sizeof(FILETIME) != cbValue) { hr = E_INVALIDARG; _JumpError(hr, error, "bad PROPTYPE_DATE len"); } hr = myFileTimeToDate( (FILETIME const *) pbValue, &pvarValue->date); _JumpIfError(hr, error, "myFileTimeToDate"); pvarValue->vt = VT_DATE; break; default: hr = E_INVALIDARG; _JumpError(hr, error, "PropType parameter"); } error: return(hr); } HRESULT myUnmarshalFormattedVariant( IN DWORD Flags, IN DWORD PropId, IN DWORD PropType, IN DWORD cbValue, IN BYTE const *pbValue, OUT VARIANT *pvarValue) { HRESULT hr; BSTR strCert; hr = myUnmarshalVariant( PropType, cbValue, pbValue, pvarValue); _JumpIfError(hr, error, "myUnmarshalVariant"); if (PROPTYPE_BINARY == (PROPTYPE_MASK & PropType)) { CSASSERT(VT_BSTR == pvarValue->vt); CSASSERT(CSExpr(CV_OUT_BASE64HEADER == CRYPT_STRING_BASE64HEADER)); CSASSERT(CSExpr(CV_OUT_BASE64 == CRYPT_STRING_BASE64)); CSASSERT(CSExpr(CV_OUT_BINARY == CRYPT_STRING_BINARY)); CSASSERT(CSExpr(CV_OUT_BASE64REQUESTHEADER == CRYPT_STRING_BASE64REQUESTHEADER)); CSASSERT(CSExpr(CV_OUT_HEX == CRYPT_STRING_HEX)); CSASSERT(CSExpr(CV_OUT_HEXASCII == CRYPT_STRING_HEXASCII)); CSASSERT(CSExpr(CV_OUT_HEXADDR == CRYPT_STRING_HEXADDR)); CSASSERT(CSExpr(CV_OUT_HEXASCIIADDR == CRYPT_STRING_HEXASCIIADDR)); switch (Flags) { case CV_OUT_BASE64HEADER: if (CR_PROP_BASECRL == PropId || CR_PROP_DELTACRL == PropId) { Flags = CV_OUT_BASE64X509CRLHEADER; } else if (MAXDWORD == PropId) { Flags = CV_OUT_BASE64REQUESTHEADER; } break; case CV_OUT_BASE64: case CV_OUT_BINARY: case CV_OUT_BASE64REQUESTHEADER: case CV_OUT_BASE64X509CRLHEADER: case CV_OUT_HEX: case CV_OUT_HEXASCII: case CV_OUT_HEXADDR: case CV_OUT_HEXASCIIADDR: break; default: hr = E_INVALIDARG; _JumpError(hr, error, "Flags"); } if (CV_OUT_BINARY != Flags) { strCert = NULL; hr = EncodeCertString(pbValue, cbValue, Flags, &strCert); _JumpIfError(hr, error, "EncodeCertString"); SysFreeString(pvarValue->bstrVal); pvarValue->bstrVal = strCert; } } hr = S_OK; error: return(hr); } HRESULT myMarshalVariant( IN VARIANT const *pvarPropertyValue, IN DWORD PropType, OUT DWORD *pcbprop, OUT BYTE **ppbprop) { HRESULT hr = S_OK; DWORD cbprop = 0; BYTE *pbprop = NULL; BSTR str = NULL; FILETIME ft; LONG lval; *ppbprop = NULL; // VT_EMPTY always produces same result: *ppbprop = NULL, *pcbprop = 0 if (VT_EMPTY != pvarPropertyValue->vt) { switch (PROPTYPE_MASK & PropType) { case PROPTYPE_BINARY: case PROPTYPE_STRING: switch (pvarPropertyValue->vt) { case VT_BYREF | VT_BSTR: if (NULL != pvarPropertyValue->pbstrVal) { str = *pvarPropertyValue->pbstrVal; } break; case VT_BSTR: str = pvarPropertyValue->bstrVal; break; } if (NULL == str) { if (PROPTYPE_STRING == (PROPTYPE_MASK & PropType) && (PROPMARSHAL_NULLBSTROK & PropType) && VT_NULL == pvarPropertyValue->vt) { cbprop = 0; } else { hr = E_INVALIDARG; _JumpError( pvarPropertyValue->vt, error, "variant BSTR type/value"); } } else { pbprop = (BYTE *) str; if (PROPTYPE_BINARY == (PROPTYPE_MASK & PropType)) { cbprop = SysStringByteLen(str) + sizeof(WCHAR); } else { cbprop = (wcslen(str) + 1) * sizeof(WCHAR); } } break; case PROPTYPE_LONG: // VB likes to send small constant integers as VT_I2 if (VT_I2 == pvarPropertyValue->vt) { lval = pvarPropertyValue->iVal; } else if (VT_I4 == pvarPropertyValue->vt) { lval = pvarPropertyValue->lVal; } else if (VT_EMPTY == pvarPropertyValue->vt) { pbprop = NULL; cbprop = 0; break; } else { hr = E_INVALIDARG; _JumpError(pvarPropertyValue->vt, error, "variant LONG type"); } pbprop = (BYTE *) &lval; cbprop = sizeof(lval); break; case PROPTYPE_DATE: if (VT_DATE == pvarPropertyValue->vt) { hr = myDateToFileTime(&pvarPropertyValue->date, &ft); _JumpIfError(hr, error, "myDateToFileTime"); } else if (VT_EMPTY == pvarPropertyValue->vt) { pbprop = NULL; cbprop = 0; break; } else { hr = E_INVALIDARG; _JumpError(pvarPropertyValue->vt, error, "variant DATE type"); } pbprop = (BYTE *) &ft; cbprop = sizeof(ft); break; default: hr = E_INVALIDARG; _JumpError(pvarPropertyValue->vt, error, "variant type/value"); } if (NULL != pbprop) { *ppbprop = (BYTE *) LocalAlloc(LMEM_FIXED, cbprop); if (NULL == *ppbprop) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(*ppbprop, pbprop, cbprop); if (NULL != str && sizeof(WCHAR) <= cbprop && ((PROPMARSHAL_LOCALSTRING & PropType) || PROPTYPE_BINARY == (PROPTYPE_MASK & PropType))) { cbprop -= sizeof(WCHAR); } } } *pcbprop = cbprop; error: return(hr); } BOOL myIsMinusSignString( IN WCHAR const *pwsz) { return( NULL != pwsz && L'\0' != pwsz[0] && L'\0' == pwsz[1] && myIsMinusSign(pwsz[0])); } // IsCharRegKeyChar -- Determines if a character is valid for use in a file // name AND in a registry key name. #define wszInvalidFileAndKeyChars L"<>\"/\\:|?*" #define wszUnsafeURLChars L"#\"&<>[]^`{}|" #define wszUnsafeDSChars L"()='\"`,;+" BOOL myIsCharSanitized( IN WCHAR wc) { BOOL fCharOk = TRUE; if (L' ' > wc || L'~' < wc || NULL != wcschr( wszInvalidFileAndKeyChars wszUnsafeURLChars wszSANITIZEESCAPECHAR wszURLESCAPECHAR wszUnsafeDSChars, wc)) { fCharOk = FALSE; } return(fCharOk); } HRESULT mySanitizeName( IN WCHAR const *pwszName, OUT WCHAR **ppwszNameOut) { HRESULT hr = S_OK; WCHAR const *pwszPassedName; WCHAR *pwszDst; WCHAR *pwszOut = NULL; WCHAR wcChar; DWORD dwSize; *ppwszNameOut = NULL; pwszPassedName = pwszName; dwSize = 0; if (NULL == pwszName) { hr = E_POINTER; _JumpError(hr, error, "pwszName NULL"); } while (L'\0' != (wcChar = *pwszPassedName++)) { if (myIsCharSanitized(wcChar)) { dwSize++; } else { dwSize += 5; // format !XXXX } } if (0 == dwSize) { goto error; // done } pwszOut = (WCHAR *) LocalAlloc(LMEM_ZEROINIT, (dwSize + 1) * sizeof(WCHAR)); if (NULL == pwszOut) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } pwszDst = pwszOut; while (L'\0' != (wcChar = *pwszName++)) { if (myIsCharSanitized(wcChar)) { *pwszDst++ = wcChar; } else { pwszDst += wsprintf( pwszDst, L"%ws%04x", wszSANITIZEESCAPECHAR, wcChar); } } *pwszDst = wcChar; // L'\0' terminator *ppwszNameOut = pwszOut; pwszOut = NULL; hr = S_OK; error: if (NULL != pwszOut) { LocalFree(pwszOut); } return(hr); } BOOL ScanHexEscapeDigits( IN WCHAR const *pwszHex, OUT WCHAR *pwcRevert) { BOOL ret = FALSE; DWORD i; WCHAR wc; WCHAR wszValue[5]; for (i = 0; i < 4; i++) { wc = pwszHex[i]; wszValue[i] = wc; if (!isascii(wc) || !isxdigit((char) wc)) { goto error; } } wszValue[4] = L'\0'; if (1 != swscanf(wszValue, L"%04x", &i)) { goto error; } *pwcRevert = (WCHAR) i; ret = TRUE; error: return(ret); } // This function will truncate the output if pwszName contains "!0000". // The output string is L'\0' terminated, so the length is not returned. HRESULT myRevertSanitizeName( IN WCHAR const *pwszName, OUT WCHAR **ppwszNameOut) { HRESULT hr; DWORD cwc; WCHAR wc; WCHAR wcRevert; WCHAR *pwszRevert; *ppwszNameOut = NULL; if (NULL == pwszName) { hr = E_POINTER; _JumpError(hr, error, "NULL sanitized name"); } cwc = wcslen(pwszName); *ppwszNameOut = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == *ppwszNameOut) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Out of memory"); } pwszRevert = *ppwszNameOut; while (L'\0' != *pwszName) { wc = *pwszName++; if (wcSANITIZEESCAPECHAR == wc && ScanHexEscapeDigits(pwszName, &wcRevert)) { wc = wcRevert; pwszName += 4; } *pwszRevert++ = wc; } *pwszRevert = L'\0'; CSASSERT(wcslen(*ppwszNameOut) <= cwc); hr = S_OK; error: return hr; } #define cwcCNMAX 64 // 64 chars max for DS CN #define cwcCHOPHASHMAX (1 + 5) // "-%05hu" decimal USHORT hash digits #define cwcCHOPBASE (cwcCNMAX - (cwcCHOPHASHMAX + cwcSUFFIXMAX)) HRESULT mySanitizedNameToDSName( IN WCHAR const *pwszSanitizedName, OUT WCHAR **ppwszNameOut) { HRESULT hr; DWORD cwc; DWORD cwcCopy; WCHAR wszDSName[cwcCHOPBASE + cwcCHOPHASHMAX + 1]; *ppwszNameOut = NULL; if (NULL == pwszSanitizedName) { hr = E_POINTER; _JumpError(hr, error, "NULL sanitized name"); } 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 = (USHORT) ((0x8000 & usHash)? 1 : 0); usHash = ((usHash << 1) | usLowBit) + pwszSanitizedName[i]; } wsprintf(&wszDSName[cwcCopy], L"-%05hu", usHash); CSASSERT(wcslen(wszDSName) < ARRAYSIZE(wszDSName)); } hr = myDupString(wszDSName, ppwszNameOut); _JumpIfError(hr, error, "myDupString"); DBGPRINT((DBG_SS_CERTLIBI, "mySanitizedNameToDSName(%ws)\n", *ppwszNameOut)); error: return(hr); } HRESULT CertNameToHashString( IN CERT_NAME_BLOB const *pCertName, OUT WCHAR **ppwszHash) { HRESULT hr = S_OK; WCHAR wszHash[CBMAX_CRYPT_HASH_LEN * 3]; // 20 bytes @ 3 WCHARs/byte DWORD cbString; HCRYPTPROV hProv = NULL; HCRYPTHASH hHash = NULL; BYTE rgbHashVal[CBMAX_CRYPT_HASH_LEN]; DWORD cbHashVal; if (0 == pCertName->cbData) { hr = E_INVALIDARG; _JumpError(hr, error, "empty cert name"); } CSASSERT(NULL != ppwszHash); // get a cryptographic provider if (!CryptAcquireContext( &hProv, NULL, // container MS_DEF_PROV, // provider name PROV_RSA_FULL, // provider type CRYPT_VERIFYCONTEXT)) // dwflags { hr = myHLastError(); _JumpError(hr, error, "CryptAcquireContext"); } // get a hash if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash)) { hr = myHLastError(); _JumpError(hr, error, "CryptCreateHash"); } // hash the name if (!CryptHashData(hHash, pCertName->pbData, pCertName->cbData, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptHashData"); } cbHashVal = CBMAX_CRYPT_HASH_LEN; if (!CryptGetHashParam(hHash, HP_HASHVAL, rgbHashVal, &cbHashVal, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptGetHashParam"); } cbString = sizeof(wszHash); hr = MultiByteIntegerToWszBuf( TRUE, // byte multiple cbHashVal, rgbHashVal, &cbString, wszHash); _JumpIfError(hr, error, "MultiByteIntegerToWszBuf"); // Generated string looks like this: // // 04 e7 23 92 98 9f d8 45 80 c9 ef 87 81 29 41 5d bc 4f 63 20 // // We need to trim the spaces. We'll do it inplace. { WCHAR *pwcSrc; WCHAR *pwcDest; for (pwcSrc = pwcDest = wszHash; L'\0' != *pwcSrc; pwcSrc++) { if (L' ' != *pwcSrc) { *pwcDest++ = *pwcSrc; } } *pwcDest = L'\0'; } *ppwszHash = (WCHAR *) LocalAlloc(LMEM_FIXED, cbString); _JumpIfAllocFailed(*ppwszHash, error); wcscpy(*ppwszHash, wszHash); error: if (NULL != hHash) { CryptDestroyHash(hHash); } if (NULL != hProv) { CryptReleaseContext(hProv, 0); } return(hr); } HRESULT myCombineStrings( IN WCHAR const *pwszNew, IN BOOL fAppendNew, OPTIONAL IN WCHAR const *pwszSeparator, IN OUT WCHAR **ppwszInOut) { HRESULT hr; DWORD cwc; WCHAR *pwsz; if (NULL == pwszSeparator) { pwszSeparator = L""; } cwc = wcslen(pwszNew); if (NULL != *ppwszInOut) { cwc += wcslen(*ppwszInOut) + wcslen(pwszSeparator); } pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == pwsz) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:LocalAlloc"); } *pwsz = L'\0'; if (fAppendNew) { if (NULL != *ppwszInOut) { wcscat(pwsz, *ppwszInOut); wcscat(pwsz, pwszSeparator); } wcscat(pwsz, pwszNew); } else { wcscat(pwsz, pwszNew); if (NULL != *ppwszInOut) { wcscat(pwsz, pwszSeparator); wcscat(pwsz, *ppwszInOut); } } if (NULL != *ppwszInOut) { LocalFree(*ppwszInOut); } *ppwszInOut = pwsz; hr = S_OK; error: return(hr); } HRESULT myAppendString( IN WCHAR const *pwszNew, OPTIONAL IN WCHAR const *pwszSeparator, IN OUT WCHAR **ppwszInOut) { return(myCombineStrings(pwszNew, TRUE, pwszSeparator, ppwszInOut)); } HRESULT myPrependString( IN WCHAR const *pwszNew, OPTIONAL IN WCHAR const *pwszSeparator, IN OUT WCHAR **ppwszInOut) { return(myCombineStrings(pwszNew, FALSE, pwszSeparator, ppwszInOut)); } HRESULT myGetRDNAttributeFromNameBlob( IN CERT_NAME_BLOB const *pNameBlob, IN LPCSTR pcszAttributeOID, OUT WCHAR **ppwszCN) { HRESULT hr; CERT_NAME_INFO *pNameInfo = NULL; DWORD cbNameInfo; CERT_RDN *prdn; CERT_RDN *prdnEnd; WCHAR const *pwszCN = NULL; *ppwszCN = NULL; if (!myDecodeName( X509_ASN_ENCODING, X509_UNICODE_NAME, pNameBlob->pbData, pNameBlob->cbData, CERTLIB_USE_LOCALALLOC, &pNameInfo, &cbNameInfo)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeName"); } for ( prdn = pNameInfo->rgRDN, prdnEnd = &prdn[pNameInfo->cRDN]; NULL == pwszCN && prdn < prdnEnd; prdn++) { CERT_RDN_ATTR *prdna; CERT_RDN_ATTR *prdnaEnd; for ( prdna = prdn->rgRDNAttr, prdnaEnd = &prdna[prdn->cRDNAttr]; prdna < prdnaEnd; prdna++) { CSASSERT( prdna->dwValueType == CERT_RDN_PRINTABLE_STRING || prdna->dwValueType == CERT_RDN_UNICODE_STRING || prdna->dwValueType == CERT_RDN_TELETEX_STRING || prdna->dwValueType == CERT_RDN_IA5_STRING || prdna->dwValueType == CERT_RDN_UTF8_STRING); if (0 != strcmp(pcszAttributeOID, prdna->pszObjId) || NULL == prdna->Value.pbData || sizeof(WCHAR) > prdna->Value.cbData || L'\0' == *(WCHAR *) prdna->Value.pbData) { continue; } pwszCN = (WCHAR const *) prdna->Value.pbData; //break; don't break, we're interested in the last CN found, not the first } } if (NULL != pwszCN) { hr = myDupString(pwszCN, ppwszCN); _JumpIfError(hr, error, "myDupString"); } else { hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); } error: if (NULL != pNameInfo) { LocalFree(pNameInfo); } return(hr); } HRESULT myGetCommonName( IN CERT_NAME_BLOB const *pNameBlob, IN BOOL fAllowDefault, OUT WCHAR **ppwszCN) { HRESULT hr; hr = myGetRDNAttributeFromNameBlob(pNameBlob, szOID_COMMON_NAME, ppwszCN); if (S_OK != hr) { _PrintError(hr, "myGetRDNAttributeFromNameBlob"); *ppwszCN = NULL; if (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) != hr) { _JumpError(hr, error, "myGetRDNAttributeFromNameBlob"); } } if (NULL == *ppwszCN) { if (!fAllowDefault) { hr = CERTSRV_E_BAD_REQUESTSUBJECT; _JumpError(hr, error, "No CN"); } hr = CertNameToHashString(pNameBlob, ppwszCN); _JumpIfError(hr, error, "CertNameToHashString"); } hr = S_OK; error: return(hr); } // Decode OCTET string, and convert UTF8 string to Unicode. // Can return S_OK and NULL pointer. HRESULT myDecodeCMCRegInfo( IN BYTE const *pbOctet, IN DWORD cbOctet, OUT WCHAR **ppwszRA) { HRESULT hr; CRYPT_DATA_BLOB *pBlob = NULL; DWORD cb; *ppwszRA = NULL; if (!myDecodeObject( X509_ASN_ENCODING, X509_OCTET_STRING, pbOctet, cbOctet, CERTLIB_USE_LOCALALLOC, (VOID **) &pBlob, &cb)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeObject"); } if (0 != pBlob->cbData && NULL != pBlob->pbData) { if (!myConvertUTF8ToWsz( ppwszRA, (CHAR const *) pBlob->pbData, pBlob->cbData)) { hr = myHLastError(); _JumpError(hr, error, "myConvertUTF8ToWsz"); } } hr = S_OK; error: if (NULL != pBlob) { LocalFree(pBlob); } return(hr); } DWORD myGetCertNameProperty( IN BOOL fFirstRDN, // else last matching RDN IN CERT_NAME_INFO const *pNameInfo, IN char const *pszObjId, OUT WCHAR const **ppwszName) { HRESULT hr; CERT_RDN_ATTR const *prdnaT; CERT_RDN const *prdn; CERT_RDN const *prdnEnd; prdnaT = NULL; for ( prdn = pNameInfo->rgRDN, prdnEnd = &prdn[pNameInfo->cRDN]; prdn < prdnEnd; prdn++) { CERT_RDN_ATTR *prdna; CERT_RDN_ATTR *prdnaEnd; for ( prdna = prdn->rgRDNAttr, prdnaEnd = &prdna[prdn->cRDNAttr]; prdna < prdnaEnd; prdna++) { if (0 == strcmp(prdna->pszObjId, pszObjId)) { prdnaT = prdna; if (fFirstRDN) { goto done; } } } } if (NULL == prdnaT) { hr = CERTSRV_E_PROPERTY_EMPTY; goto error; } done: *ppwszName = (WCHAR const *) prdnaT->Value.pbData; hr = S_OK; error: return(hr); } VOID myUuidCreate( OUT UUID *pUuid) { HRESULT hr; BYTE *pb; ZeroMemory(pUuid, sizeof(*pUuid)); hr = UuidCreate(pUuid); if (S_OK != hr) { BYTE *pbEnd; CSASSERT((HRESULT) RPC_S_UUID_LOCAL_ONLY == hr); // No net card? Fake up a GUID: pb = (BYTE *) pUuid; pbEnd = (BYTE *) pb + sizeof(*pUuid); GetSystemTimeAsFileTime((FILETIME *) pb); pb += sizeof(FILETIME); while (pb < pbEnd) { *(DWORD *) pb = GetTickCount(); pb += sizeof(DWORD); } CSASSERT(pb == pbEnd); } } VOID myGenerateGuidSerialNumber( OUT GUID *pguidSerialNumber) { BYTE *pb; myUuidCreate(pguidSerialNumber); pb = &((BYTE *) pguidSerialNumber)[sizeof(*pguidSerialNumber) - 1]; // make sure the last byte is never zero if (0 == *pb) { *pb = 'z'; } // Some clients can't handle negative serial numbers: *pb &= 0x7f; } BOOL myAreBlobsSame( IN BYTE const *pbData1, IN DWORD cbData1, IN BYTE const *pbData2, IN DWORD cbData2) { BOOL ret = FALSE; if (cbData1 != cbData2) { goto error; } if (NULL != pbData1 && NULL != pbData2) { if (0 != memcmp(pbData1, pbData2, cbData1)) { goto error; } } // else at least one is NULL -- they'd better both be NULL, & the count 0. else if (pbData1 != pbData2 || 0 != cbData1) { goto error; } ret = TRUE; error: return(ret); } BOOL myAreSerialNumberBlobsSame( IN CRYPT_INTEGER_BLOB const *pBlob1, IN CRYPT_INTEGER_BLOB const *pBlob2) { DWORD cbData1 = pBlob1->cbData; DWORD cbData2 = pBlob2->cbData; if (NULL != pBlob1->pbData) { while (0 != cbData1 && 0 == pBlob1->pbData[cbData1 - 1]) { cbData1--; } } if (NULL != pBlob2->pbData) { while (0 != cbData2 && 0 == pBlob2->pbData[cbData2 - 1]) { cbData2--; } } return(myAreBlobsSame(pBlob1->pbData, cbData1, pBlob2->pbData, cbData2)); } // myAreCertContextBlobsSame -- return TRUE if the certs are identical. BOOL myAreCertContextBlobsSame( IN CERT_CONTEXT const *pcc1, IN CERT_CONTEXT const *pcc2) { return(myAreBlobsSame( pcc1->pbCertEncoded, pcc1->cbCertEncoded, pcc2->pbCertEncoded, pcc2->cbCertEncoded)); } WCHAR const g_wszCert[] = L"cert"; HRESULT myIsDirWriteable( IN WCHAR const *pwszPath, IN BOOL fFilePath) { HRESULT hr; WCHAR *pwszBase; WCHAR *pwsz; WCHAR wszDir[MAX_PATH]; WCHAR wszTempFile[MAX_PATH]; if (fFilePath && iswalpha(pwszPath[0]) && L':' == pwszPath[1] && L'\0' == pwszPath[2]) { hr = HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME); _JumpErrorStr(hr, error, "not a file path", pwszPath); } if (!GetFullPathName( pwszPath, ARRAYSIZE(wszDir), wszDir, &pwsz)) { hr = myHLastError(); _JumpErrorStr(hr, error, "GetFullPathName", pwszPath); } if (fFilePath) { if (NULL == pwsz) { hr = HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME); _JumpErrorStr(hr, error, "not a file path", pwszPath); } pwszBase = wszDir; if (iswalpha(wszDir[0]) && L':' == wszDir[1] && L'\\' == wszDir[2]) { pwszBase += 3; } else if (L'\\' == wszDir[0] && L'\\' == wszDir[1]) { pwszBase += 2; } if (pwsz > pwszBase && L'\\' == pwsz[-1]) { pwsz--; } *pwsz = L'\0'; } if (!GetTempFileName(wszDir, g_wszCert, 0, wszTempFile)) { hr = myHLastError(); _JumpErrorStr(hr, error, "GetTempFileName", wszDir); } if (!DeleteFile(wszTempFile)) { hr = myHLastError(); _JumpErrorStr(hr, error, "DeleteFile", wszTempFile); } hr = S_OK; error: return(hr); } HRESULT myGetComputerObjectName( IN EXTENDED_NAME_FORMAT NameFormat, OUT WCHAR **ppwszComputerObjectName) { HRESULT hr; WCHAR *pwszComputerObjectName = NULL; DWORD cwc; *ppwszComputerObjectName = NULL; cwc = 0; if (!GetComputerObjectName(NameFormat, NULL, &cwc)) { hr = myHLastError(); if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr) { _JumpError(hr, error, "GetComputerObjectName"); } } pwszComputerObjectName = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR)); if (NULL == pwszComputerObjectName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (!GetComputerObjectName(NameFormat, pwszComputerObjectName, &cwc)) { hr = myHLastError(); _JumpError(hr, error, "GetComputerObjectName"); } *ppwszComputerObjectName = pwszComputerObjectName; pwszComputerObjectName = NULL; hr = S_OK; error: if (NULL != pwszComputerObjectName) { LocalFree(pwszComputerObjectName); } return(hr); } HRESULT myGetComputerNames( OUT WCHAR **ppwszDnsName, OUT WCHAR **ppwszOldName) { HRESULT hr; DWORD cwc; WCHAR *pwszOldName = NULL; *ppwszOldName = NULL; *ppwszDnsName = NULL; cwc = MAX_COMPUTERNAME_LENGTH + 1; pwszOldName = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR)); if (NULL == pwszOldName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (!GetComputerName(pwszOldName, &cwc)) { hr = myHLastError(); _JumpError(hr, error, "GetComputerName"); } hr = myGetMachineDnsName(ppwszDnsName); _JumpIfError(hr, error, "myGetMachineDnsName"); *ppwszOldName = pwszOldName; pwszOldName = NULL; error: if (NULL != pwszOldName) { LocalFree(pwszOldName); } return(hr); } HRESULT myGetComputerNameEx( IN COMPUTER_NAME_FORMAT NameFormat, OUT WCHAR **ppwszName) { HRESULT hr; WCHAR *pwszName = NULL; DWORD cwc; *ppwszName = NULL; cwc = 0; if (!GetComputerNameEx(NameFormat, NULL, &cwc)) { hr = myHLastError(); if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) != hr) { _JumpError(hr, error, "GetComputerNameEx"); } } pwszName = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR)); if (NULL == pwszName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (!GetComputerNameEx(NameFormat, pwszName, &cwc)) { hr = myHLastError(); _JumpError(hr, error, "GetComputerNameEx"); } *ppwszName = pwszName; pwszName = NULL; hr = S_OK; error: if (NULL != pwszName) { LocalFree(pwszName); } return(hr); } typedef LANGID (WINAPI FNSETTHREADUILANGUAGE)( IN WORD wReserved); LANGID mySetThreadUILanguage( IN WORD wReserved) { HMODULE hModule; LANGID lang = 0; HANDLE hStdOut; static FNSETTHREADUILANGUAGE *s_pfn = NULL; // Make the SetThreadUILanguage call only if a console exists: // FILE_TYPE_CHAR (what about FILE_TYPE_PIPE, FILE_TYPE_DISK) hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if (INVALID_HANDLE_VALUE != hStdOut && FILE_TYPE_CHAR == (~FILE_TYPE_REMOTE & GetFileType(hStdOut))) { if (NULL == s_pfn) { hModule = GetModuleHandle(TEXT("kernel32.dll")); if (NULL == hModule) { goto error; } // load system function s_pfn = (FNSETTHREADUILANGUAGE *) GetProcAddress( hModule, "SetThreadUILanguage"); if (NULL == s_pfn) { goto error; } } lang = (*s_pfn)(wReserved); } error: return(lang); } HRESULT myFormConfigString( IN WCHAR const *pwszServer, IN WCHAR const *pwszCAName, OUT WCHAR **ppwszConfig) { HRESULT hr; WCHAR *pwszConfig = NULL; *ppwszConfig = NULL; pwszConfig = (WCHAR *) LocalAlloc(LPTR, (wcslen(pwszServer) + wcslen(pwszCAName) + 2) * sizeof(WCHAR)); if (NULL == pwszConfig) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwszConfig, pwszServer); wcscat(pwszConfig, L"\\"); wcscat(pwszConfig, pwszCAName); *ppwszConfig = pwszConfig; hr = S_OK; error: return hr; } HRESULT myCLSIDToWsz( IN CLSID const *pclsid, OUT WCHAR **ppwsz) { HRESULT hr; WCHAR *pwsz = NULL; WCHAR *pwsz1; WCHAR *pwsz2; *ppwsz = NULL; hr = StringFromCLSID(*pclsid, &pwsz); _JumpIfError(hr, error, "StringFromCLSID"); for (pwsz1 = pwsz; L'\0' != *pwsz1; pwsz1++) { if (L'A' <= *pwsz1 && L'F' >= *pwsz1) { *pwsz1 += L'a' - L'A'; } } pwsz1 = pwsz; pwsz2 = &pwsz[wcslen(pwsz) - 1]; if (wcLBRACE == *pwsz1 && wcRBRACE == *pwsz2) { pwsz1++; *pwsz2 = L'\0'; } hr = myDupString(pwsz1, ppwsz); _JumpIfError(hr, error, "myDupString"); error: if (NULL != pwsz) { CoTaskMemFree(pwsz); } return(hr); } HRESULT myLoadRCString( IN HINSTANCE hInstance, IN int iRCId, OUT WCHAR **ppwsz) { #define CS_RCALLOCATEBLOCK 256 HRESULT hr; WCHAR *pwszTemp = NULL; int sizeTemp; int size; int cBlocks = 1; *ppwsz = NULL; size = 0; while (NULL == pwszTemp) { sizeTemp = cBlocks * CS_RCALLOCATEBLOCK; pwszTemp = (WCHAR*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeTemp * sizeof(WCHAR)); if (NULL == pwszTemp) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } size = LoadString( hInstance, iRCId, pwszTemp, sizeTemp); if (0 == size) { hr = myHLastError(); DBGPRINT(( DBG_SS_CERTLIB, "myLoadRCString(hInstance=%x, iRCId=%u) --> %x\n", hInstance, iRCId, hr)); if (S_OK != hr && HRESULT_FROM_WIN32(ERROR_RESOURCE_NAME_NOT_FOUND) != hr) { _JumpError(hr, error, "LoadString"); } } if (size < sizeTemp - 1) { // ok, size is big enough break; } ++cBlocks; LocalFree(pwszTemp); pwszTemp = NULL; } *ppwsz = (WCHAR*) LocalAlloc(LPTR, (size+1) * sizeof(WCHAR)); if (NULL == *ppwsz) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (0 == size) { // two possible cases, 1) real empty string or // 2) id not found in resource. either case make it empty string **ppwsz = L'\0'; } else { // copy it wcscpy(*ppwsz, pwszTemp); } hr = S_OK; error: if (NULL != pwszTemp) { LocalFree(pwszTemp); } return hr; } HRESULT _IsConfigLocal( IN WCHAR const *pwszConfig, IN WCHAR const *pwszDnsName, IN WCHAR const *pwszOldName, OPTIONAL OUT WCHAR **ppwszMachine, OUT BOOL *pfLocal) { HRESULT hr; WCHAR *pwszMachine = NULL; WCHAR const *pwsz; DWORD cwc; *pfLocal = FALSE; if (NULL != ppwszMachine) { *ppwszMachine = NULL; } while (L'\\' == *pwszConfig) { pwszConfig++; } pwsz = wcschr(pwszConfig, L'\\'); if (NULL != pwsz) { cwc = SAFE_SUBTRACT_POINTERS(pwsz, pwszConfig); } else { cwc = wcslen(pwszConfig); } pwszMachine = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == pwszMachine) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(pwszMachine, pwszConfig, cwc * sizeof(WCHAR)); pwszMachine[cwc] = L'\0'; if (0 == mylstrcmpiL(pwszMachine, pwszDnsName) || 0 == mylstrcmpiL(pwszMachine, pwszOldName)) { *pfLocal = TRUE; } if (NULL != ppwszMachine) { *ppwszMachine = pwszMachine; pwszMachine = NULL; } hr = S_OK; error: if (NULL != pwszMachine) { LocalFree(pwszMachine); } return(hr); } HRESULT myIsConfigLocal( IN WCHAR const *pwszConfig, OPTIONAL OUT WCHAR **ppwszMachine, OUT BOOL *pfLocal) { HRESULT hr; WCHAR *pwszDnsName = NULL; WCHAR *pwszOldName = NULL; *pfLocal = FALSE; if (NULL != ppwszMachine) { *ppwszMachine = NULL; } hr = myGetComputerNames(&pwszDnsName, &pwszOldName); _JumpIfError(hr, error, "myGetComputerNames"); hr = _IsConfigLocal( pwszConfig, pwszDnsName, pwszOldName, ppwszMachine, pfLocal); _JumpIfError(hr, error, "_IsConfigLocal"); error: if (NULL != pwszDnsName) { LocalFree(pwszDnsName); } if (NULL != pwszOldName) { LocalFree(pwszOldName); } return(hr); } HRESULT myIsConfigLocal2( IN WCHAR const *pwszConfig, IN WCHAR const *pwszDnsName, IN WCHAR const *pwszOldName, OUT BOOL *pfLocal) { HRESULT hr; hr = _IsConfigLocal( pwszConfig, pwszDnsName, pwszOldName, NULL, pfLocal); _JumpIfError(hr, error, "_IsConfigLocal"); error: return(hr); } HRESULT myGetConfig( IN DWORD dwUIFlag, OUT WCHAR **ppwszConfig) { HRESULT hr; HRESULT hr2; BSTR strConfig = NULL; WCHAR *pwszConfig = NULL; WCHAR *pwszActiveCA = NULL; WCHAR *pwszCommonName = NULL; WCHAR *pwszDnsName = NULL; CSASSERT(NULL != ppwszConfig); *ppwszConfig = NULL; hr = ConfigGetConfig(DISPSETUP_COM, dwUIFlag, &strConfig); if (S_OK != hr) { if (CC_LOCALCONFIG != dwUIFlag) { _JumpError(hr, error, "ConfigGetConfig"); } hr2 = hr; hr = myGetCertRegStrValue( NULL, NULL, NULL, wszREGACTIVE, &pwszActiveCA); _PrintIfError(hr, "myGetCertRegStrValue"); if (S_OK == hr) { hr = myGetCertRegStrValue( pwszActiveCA, NULL, NULL, wszREGCOMMONNAME, &pwszCommonName); _PrintIfError(hr, "myGetCertRegStrValue"); } if (S_OK != hr) { hr = hr2; _JumpError(hr, error, "ConfigGetConfig"); } hr = myGetMachineDnsName(&pwszDnsName); _JumpIfError(hr, error, "myGetMachineDnsName"); hr = myFormConfigString(pwszDnsName, pwszCommonName, &pwszConfig); _JumpIfError(hr, error, "myFormConfigString"); if (!ConvertWszToBstr(&strConfig, pwszConfig, MAXDWORD)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToBstr"); } } *ppwszConfig = (WCHAR *) LocalAlloc( LMEM_FIXED, SysStringByteLen(strConfig) + sizeof(WCHAR)); if (NULL == *ppwszConfig) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(*ppwszConfig, strConfig); CSASSERT( wcslen(*ppwszConfig) * sizeof(WCHAR) == SysStringByteLen(strConfig)); hr = S_OK; error: if (NULL != pwszActiveCA) { LocalFree(pwszActiveCA); } if (NULL != pwszCommonName) { LocalFree(pwszCommonName); } if (NULL != pwszDnsName) { LocalFree(pwszDnsName); } if (NULL != pwszConfig) { LocalFree(pwszConfig); } if (NULL != strConfig) { SysFreeString(strConfig); } return(hr); } HRESULT myBuildPathAndExt( IN WCHAR const *pwszDir, IN WCHAR const *pwszFile, OPTIONAL IN WCHAR const *pwszExt, OUT WCHAR **ppwszPath) { HRESULT hr; WCHAR *pwsz; DWORD cwc; *ppwszPath = NULL; cwc = wcslen(pwszDir) + 1 + wcslen(pwszFile) + 1; if (NULL != pwszExt) { cwc += wcslen(pwszExt); } pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR)); if (NULL == pwsz) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwsz, pwszDir); if (L'\\' != pwsz[wcslen(pwsz) - 1]) { wcscat(pwsz, L"\\"); } wcscat(pwsz, pwszFile); if (NULL != pwszExt) { wcscat(pwsz, pwszExt); } *ppwszPath = pwsz; hr = S_OK; error: return(hr); } HRESULT myDeleteFilePattern( IN WCHAR const *pwszDir, OPTIONAL IN WCHAR const *pwszPattern, // defaults to L"*.*" IN BOOL fRecurse) { HRESULT hr; HRESULT hr2; HANDLE hf; WIN32_FIND_DATA wfd; WCHAR *pwszFindPath = NULL; WCHAR *pwszDeleteFile; WCHAR *pwszDeletePath = NULL; DBGPRINT(( DBG_SS_CERTLIBI, "myDeleteFilePattern(%ws, %ws, %ws)\n", pwszDir, pwszPattern, fRecurse? L"Recurse" : L"NO Recurse")); if (NULL == pwszPattern) { pwszPattern = L"*.*"; } hr = myBuildPathAndExt(pwszDir, pwszPattern, NULL, &pwszFindPath); _JumpIfError(hr, error, "myBuildPathAndExt"); pwszDeletePath = (WCHAR *) LocalAlloc( LMEM_FIXED, (wcslen(pwszDir) + 1 + MAX_PATH) * sizeof(WCHAR)); if (NULL == pwszDeletePath) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwszDeletePath, pwszFindPath); pwszDeleteFile = wcsrchr(pwszDeletePath, L'\\'); CSASSERT(NULL != pwszDeleteFile); pwszDeleteFile++; hf = FindFirstFile(pwszFindPath, &wfd); if (INVALID_HANDLE_VALUE == hf) { hr = myHLastError(); if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) { hr = S_OK; goto error; } _JumpErrorStr(hr, error, "FindFirstFile", pwszFindPath); } do { wcscpy(pwszDeleteFile, wfd.cFileName); if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (fRecurse && 0 != lstrcmp(L".", wfd.cFileName) && 0 != lstrcmp(L"..", wfd.cFileName)) { DBGPRINT(( DBG_SS_CERTLIBI, "myDeleteFilePattern(DIR): %ws\n", pwszDeletePath)); hr2 = myRemoveFilesAndDirectory(pwszDeletePath, TRUE); if (S_OK != hr2) { if (S_OK == hr) { hr = hr2; // only return first error } _PrintErrorStr(hr2, "myRemoveFilesAndDirectory", pwszDeletePath); } } } else { DBGPRINT(( DBG_SS_CERTLIBI, "myDeleteFilePattern: %ws\n", pwszDeletePath)); if (!DeleteFile(pwszDeletePath)) { hr2 = myHLastError(); if (S_OK == hr) { hr = hr2; // only return first error } _PrintErrorStr(hr2, "DeleteFile", pwszDeletePath); } } } while (FindNextFile(hf, &wfd)); FindClose(hf); error: if (NULL != pwszFindPath) { LocalFree(pwszFindPath); } if (NULL != pwszDeletePath) { LocalFree(pwszDeletePath); } return(hr); } HRESULT myRemoveFilesAndDirectory( IN WCHAR const *pwszPath, IN BOOL fRecurse) { HRESULT hr; HRESULT hr2; hr = myDeleteFilePattern(pwszPath, NULL, fRecurse); if (S_OK != hr) { _PrintErrorStr(hr, "myDeleteFilePattern", pwszPath); } if (!RemoveDirectory(pwszPath)) { hr2 = myHLastError(); if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr2 && HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) != hr2) { if (S_OK == hr) { hr = hr2; // only return first error } _JumpErrorStr(hr2, error, "RemoveDirectory", pwszPath); } } error: return(hr); } BOOL myIsFullPath( IN WCHAR const *pwszPath, OUT DWORD *pdwFlag) { BOOL fFullPath = FALSE; *pdwFlag = 0; if (NULL != pwszPath) { if (L'\\' == pwszPath[0] && L'\\' == pwszPath[1]) { fFullPath = TRUE; *pdwFlag = UNC_PATH; } else if (iswalpha(pwszPath[0]) && L':' == pwszPath[1] && L'\\' == pwszPath[2]) { fFullPath = TRUE; *pdwFlag = LOCAL_PATH; } } return(fFullPath); } // Convert local full path to UNC, as in c:\foo... --> \\server\c$\foo... // If pwszServer is NULL or empty, preserve the local full path HRESULT myConvertLocalPathToUNC( OPTIONAL IN WCHAR const *pwszServer, IN WCHAR const *pwszFile, OUT WCHAR **ppwszFileUNC) { HRESULT hr; DWORD cwc; WCHAR const *pwsz; WCHAR *pwszDst; WCHAR *pwszFileUNC = NULL; if (!iswalpha(pwszFile[0]) || L':' != pwszFile[1] || L'\\' != pwszFile[2]) { hr = E_INVALIDARG; _JumpError(hr, error, "non-local path"); } if (NULL != pwszServer && L'\0' == *pwszServer) { pwszServer = NULL; } cwc = wcslen(pwszFile) + 1; if (NULL != pwszServer) { cwc += 2 + wcslen(pwszServer) + 1; } pwszFileUNC = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR)); if (NULL == pwszFileUNC) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc pwszFiles"); } pwsz = pwszFile; pwszDst = pwszFileUNC; if (NULL != pwszServer) { wcscpy(pwszDst, L"\\\\"); // --> "\\" wcscat(pwszDst, pwszServer); // --> "\\server" pwszDst += wcslen(pwszDst); *pwszDst++ = L'\\'; // --> "\\server\" *pwszDst++ = *pwsz++; // --> "\\server\c" *pwszDst++ = L'$'; // --> "\\server\c$" pwsz++; // skip colon } wcscpy(pwszDst, pwsz); // --> "\\server\c$\foo..." *ppwszFileUNC = pwszFileUNC; hr = S_OK; error: return(hr); } WCHAR const * LocalStart( IN WCHAR const *pwsz, OUT BOOL *pfUNC) { WCHAR const *pwc; *pfUNC = FALSE; pwc = pwsz; if (L'\\' != *pwc) { pwc++; } if (L'\\' == pwc[0] || L'\\' == pwc[1]) { pwc = wcschr(&pwc[2], L'\\'); if (NULL != pwc && iswalpha(pwc[1]) && L'$' == pwc[2] && L'\\' == pwc[3]) { pwsz = &pwc[1]; *pfUNC = TRUE; } } return(pwsz); } ULONG myLocalPathwcslen( IN WCHAR const *pwsz) { BOOL fUNC; return(wcslen(LocalStart(pwsz, &fUNC))); } VOID myLocalPathwcscpy( OUT WCHAR *pwszOut, IN WCHAR const *pwszIn) { BOOL fUNC; wcscpy(pwszOut, LocalStart(pwszIn, &fUNC)); if (fUNC) { CSASSERT(L'$' == pwszOut[1]); pwszOut[1] = L':'; } } HRESULT myConvertUNCPathToLocal( IN WCHAR const *pwszUNCPath, OUT WCHAR **ppwszLocalPath) { HRESULT hr; DWORD cwc; WCHAR *pwszLocalPath; CSASSERT(NULL != pwszUNCPath); CSASSERT(NULL != ppwszLocalPath); *ppwszLocalPath = NULL; if (L'\\' != pwszUNCPath[0] || L'\\' != pwszUNCPath[1]) { hr = E_INVALIDARG; _JumpError(hr, error, "bad parm"); } cwc = myLocalPathwcslen(pwszUNCPath) + 1; pwszLocalPath = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR)); if (NULL == pwszLocalPath) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } myLocalPathwcscpy(pwszLocalPath, pwszUNCPath); *ppwszLocalPath = pwszLocalPath; hr = S_OK; error: return(hr); } //+------------------------------------------------------------------------- // Description: create any number of directories in one call //-------------------------------------------------------------------------- HRESULT myCreateNestedDirectories( WCHAR const *pwszDirectory) { HRESULT hr; WCHAR rgszDir[MAX_PATH]; // static buffer WCHAR *pszNext = const_cast(pwszDirectory); // point to end of current directory // skip "X:\" if ((pszNext[1] == L':') && (pszNext[2] == L'\\')) pszNext += 3; while (pszNext) // incr past { DWORD ch; // find the next occurence of '\' pszNext = wcschr(pszNext, L'\\'); if (pszNext == NULL) { // last directory: copy everything wcscpy(rgszDir, pwszDirectory); } else { // else copy up to Next ptr ch = SAFE_SUBTRACT_POINTERS(pszNext, pwszDirectory); if (0 != ch) { CopyMemory(rgszDir, pwszDirectory, ch*sizeof(WCHAR)); // zero-term rgszDir[ch] = L'\0'; // incr past '\\' pszNext++; } else { //if ch = 0, means the first char is \, skip CreateDirectory pszNext++; //must shift to next char to get out of loop continue; } } // UNDONE: PeteSk - add in directory security if (!CreateDirectory(rgszDir, NULL)) { hr = myHLastError(); if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) != hr) { // something must be wrong with the path _JumpError(hr, error, "CreateDirectory"); } } } hr = S_OK; error: return hr; } HRESULT myUncanonicalizeURLParm( IN WCHAR const *pwszParmIn, OUT WCHAR **ppwszParmOut) { HRESULT hr; DWORD cwc; WCHAR *pwszCanon = NULL; WCHAR *pwszUncanon = NULL; static const WCHAR s_wszLdap[] = L"ldap:///"; *ppwszParmOut = NULL; cwc = WSZARRAYSIZE(s_wszLdap) + wcslen(pwszParmIn); pwszCanon = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == pwszCanon) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwszCanon, s_wszLdap); wcscat(&pwszCanon[WSZARRAYSIZE(s_wszLdap)], pwszParmIn); hr = myInternetUncanonicalizeURL(pwszCanon, &pwszUncanon); _JumpIfError(hr, error, "myInternetUncanonicalizeURL"); hr = myDupString(&pwszUncanon[WSZARRAYSIZE(s_wszLdap)], ppwszParmOut); _JumpIfError(hr, error, "myDupString"); error: if (NULL != pwszCanon) { LocalFree(pwszCanon); } if (NULL != pwszUncanon) { LocalFree(pwszUncanon); } return(hr); } // myFormatCertsrvStringArray 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 HRESULT myFormatCertsrvStringArray( 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) CSASSERT(L'1' == wszFCSAPARM_SERVERDNSNAME[1]); apwszInsertionArray[1 - 1] = pwszServerName_p1_2; //+================================================ // Short Machine Name (%2) CSASSERT(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) CSASSERT(L'3' == wszFCSAPARM_SANITIZEDCANAME[1]); apwszInsertionArray[3 - 1] = pwszSanitizedName_p3_7; //+================================================ // Cert filename suffix (%4) | (%4-%4) CSASSERT(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"; } CSASSERT(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"; } CSASSERT(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) CSASSERT(L'7' == wszFCSAPARM_SANITIZEDCANAMEHASH[1]); hr = mySanitizedNameToDSName(pwszSanitizedName_p3_7, &pwszSanitizedDSName); _JumpIfError(hr, error, "mySanitizedNameToDSName"); apwszInsertionArray[7 - 1] = pwszSanitizedDSName; //+================================================ // CRL filename suffix (%8) CSASSERT(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) CSASSERT(L'9' == wszFCSAPARM_CRLDELTAFILENAMESUFFIX[1]); wszDeltaCRLSuffix[0] = L'\0'; if (fDeltaCRL_p9) { wcscpy(wszDeltaCRLSuffix, L"+"); } apwszInsertionArray[9 - 1] = wszDeltaCRLSuffix; //+================================================ // CRL attribute (%10) CSASSERT(L'1' == wszFCSAPARM_DSCRLATTRIBUTE[1]); CSASSERT(L'0' == wszFCSAPARM_DSCRLATTRIBUTE[2]); pwszT = L""; if (fDSAttrib_p10_11) { pwszT = fDeltaCRL_p9? wszDSSEARCHDELTACRLATTRIBUTE : wszDSSEARCHBASECRLATTRIBUTE; } apwszInsertionArray[10 - 1] = pwszT; //+================================================ // CA cert attribute (%11) CSASSERT(L'1' == wszFCSAPARM_DSCACERTATTRIBUTE[1]); CSASSERT(L'1' == wszFCSAPARM_DSCACERTATTRIBUTE[2]); pwszT = L""; if (fDSAttrib_p10_11) { pwszT = wszDSSEARCHCACERTATTRIBUTE; } apwszInsertionArray[11 - 1] = pwszT; //+================================================ // User cert attribute (%12) CSASSERT(L'1' == wszFCSAPARM_DSUSERCERTATTRIBUTE[1]); CSASSERT(L'2' == wszFCSAPARM_DSUSERCERTATTRIBUTE[2]); pwszT = L""; if (fDSAttrib_p10_11) { pwszT = wszDSSEARCHUSERCERTATTRIBUTE; } apwszInsertionArray[12 - 1] = pwszT; //+================================================ // KRA cert attribute (%13) CSASSERT(L'1' == wszFCSAPARM_DSKRACERTATTRIBUTE[1]); CSASSERT(L'3' == wszFCSAPARM_DSKRACERTATTRIBUTE[2]); pwszT = L""; if (fDSAttrib_p10_11) { pwszT = wszDSSEARCHKRACERTATTRIBUTE; } apwszInsertionArray[13 - 1] = pwszT; //+================================================ // Cross cert pair attribute (%14) CSASSERT(L'1' == wszFCSAPARM_DSCROSSCERTPAIRATTRIBUTE[1]); CSASSERT(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 = myHLastError(); _JumpError(hr, error, "FormatMessage"); } if (fURL) { WCHAR *pwsz; hr = myInternetCanonicalizeUrl(apwszStringsOut[i], &pwsz); _JumpIfError(hr, error, "myInternetCanonicalizeUrl"); 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); } HRESULT myAllocIndexedName( IN WCHAR const *pwszName, IN DWORD Index, IN DWORD IndexTarget, OUT WCHAR **ppwszIndexedName) { HRESULT hr; WCHAR wszIndex[1 + 2 * cwcDWORDSPRINTF + 3]; // L"(%u-%u)" WCHAR *pwszIndexedName; *ppwszIndexedName = NULL; wszIndex[0] = L'\0'; if (0 != Index || MAXDWORD != IndexTarget) { wsprintf( wszIndex, MAXDWORD != IndexTarget? L"(%u-%u)" : L"(%u)", Index, IndexTarget); } pwszIndexedName = (WCHAR *) LocalAlloc( LMEM_FIXED, (wcslen(pwszName) + wcslen(wszIndex) + 1) * sizeof(WCHAR)); if (NULL == pwszIndexedName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwszIndexedName, pwszName); wcscat(pwszIndexedName, wszIndex); *ppwszIndexedName = pwszIndexedName; hr = S_OK; error: return(hr); } int myWtoI( IN WCHAR const *string, OUT BOOL *pfValid) { HRESULT hr; WCHAR wszBuf[16]; WCHAR *pwszT = wszBuf; int cTmp = ARRAYSIZE(wszBuf); int i = 0; WCHAR const *pwsz; BOOL fSawDigit = FALSE; CSASSERT(NULL != pfValid); *pfValid = FALSE; cTmp = FoldString(MAP_FOLDDIGITS, string, -1, pwszT, cTmp); if (cTmp == 0) { hr = myHLastError(); if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) { hr = S_OK; cTmp = FoldString(MAP_FOLDDIGITS, string, -1, NULL, 0); pwszT = (WCHAR *) LocalAlloc(LMEM_FIXED, cTmp * sizeof(WCHAR)); if (NULL == pwszT) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } cTmp = FoldString(MAP_FOLDDIGITS, string, -1, pwszT, cTmp); if (cTmp == 0) { hr = myHLastError(); } } _JumpIfError(hr, error, "FoldString"); } pwsz = pwszT; while (iswspace(*pwsz)) { pwsz++; } if (L'0' == *pwsz && (L'x' == pwsz[1] || L'X' == pwsz[1])) { pwsz += 2; while (iswxdigit(*pwsz)) { i <<= 4; if (iswdigit(*pwsz)) { i |= *pwsz - L'0'; } else if (L'A' <= *pwsz && L'F' >= *pwsz) { i |= *pwsz - L'A' + 10; } else { i |= *pwsz - L'a' + 10; } fSawDigit = TRUE; pwsz++; } } else { while (iswdigit(*pwsz)) { fSawDigit = TRUE; pwsz++; } i = _wtoi(pwszT); } while (iswspace(*pwsz)) { pwsz++; } if (L'\0' == *pwsz) { *pfValid = fSawDigit; } error: if (NULL != pwszT && pwszT != wszBuf) { LocalFree(pwszT); } return(i); } HRESULT myGetEnvString( OUT WCHAR **ppwszOut, IN WCHAR const *pwszVariable) { HRESULT hr; WCHAR awcBuf[MAX_PATH]; DWORD len; len = GetEnvironmentVariable(pwszVariable, awcBuf, ARRAYSIZE(awcBuf)); if (0 == len) { hr = myHLastError(); _JumpErrorStr2( hr, error, "GetEnvironmentVariable", pwszVariable, HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND)); } if (ARRAYSIZE(awcBuf) <= len) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); _JumpError(hr, error, "GetEnvironmentVariable"); } *ppwszOut = (WCHAR *) LocalAlloc( LMEM_FIXED, (wcslen(awcBuf) + 1) * sizeof(WCHAR)); if (NULL == *ppwszOut) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(*ppwszOut, awcBuf); hr = S_OK; error: return(hr); } BOOL IsValidAttributeChar( IN WCHAR wc) { BOOL fOk = TRUE; if (myIsMinusSign(wc) || iswspace(wc)) { fOk = FALSE; } return(fOk); } // myParseNextAttribute -- destructively parse a name, value attribute pair. // Allow CR and/or LF delimiters -- MAC web pages seem to convert LFs into CRs. HRESULT myParseNextAttribute( IN OUT WCHAR **ppwszBuf, IN BOOL fURL, // Use = and & instead of : and \r\n OUT WCHAR const **ppwszName, OUT WCHAR const **ppwszValue) { HRESULT hr; WCHAR *pwszBuf = *ppwszBuf; WCHAR wcSep = fURL? L'=' : L':'; WCHAR *wszTerm = fURL? L"&" : L"\r\n"; for (;;) { WCHAR *pwcToken; WCHAR *pwcDst; WCHAR *pwc; WCHAR const *pwszTerm; WCHAR wszQuote[2]; // Find the beginning of the next token while (iswspace(*pwszBuf)) { pwszBuf++; } pwcToken = pwszBuf; pwszBuf = wcschr(pwszBuf, wcSep); if (NULL == pwszBuf) { hr = S_FALSE; goto error; } // If there's a wszTerm char before the next wcSep char, start over. pwc = &pwcToken[wcscspn(pwcToken, wszTerm)]; if (pwc < pwszBuf) { pwszBuf = pwc + 1; continue; } for (pwc = pwcDst = pwcToken; pwc < pwszBuf; pwc++) { if (IsValidAttributeChar(*pwc)) { *pwcDst++ = *pwc; } } pwszBuf++; // skip past the wcSep before it gets stomped *pwcDst = L'\0'; // may stomp the wcSep separator *ppwszName = pwcToken; // Find beginning of Value string while (NULL == wcschr(wszTerm, *pwszBuf) && iswspace(*pwszBuf)) { pwszBuf++; } wszQuote[0] = L'\0'; pwszTerm = wszTerm; if (fURL && (L'"' == *pwszBuf || L'\'' == *pwszBuf)) { wszQuote[0] = *pwszBuf; wszQuote[1] = L'\0'; pwszTerm = wszQuote; pwszBuf++; } pwcToken = pwszBuf; // find end of Value string pwc = &pwcToken[wcscspn(pwcToken, pwszTerm)]; pwszBuf = pwc; if (L'\0' != *pwszBuf) { // for case when last Value *is* terminated by a wszTerm char: *pwszBuf++ = L'\0'; } // trim trailing whitespace from Value string while (--pwc >= pwcToken && iswspace(*pwc)) { *pwc = L'\0'; } if (L'\0' != wszQuote[0] && pwc >= pwcToken && wszQuote[0] == *pwc) { *pwc = L'\0'; } if (L'\0' == **ppwszName || L'\0' == *pwcToken) { continue; } *ppwszValue = pwcToken; break; } hr = S_OK; error: *ppwszBuf = pwszBuf; return(hr); } // Destructively parse an old-style 4 byte IP Address. HRESULT infParseIPV4Address( IN WCHAR *pwszValue, OUT BYTE *pb, IN OUT DWORD *pcb) { HRESULT hr; DWORD cb; DBGPRINT((DBG_SS_CERTLIBI, "infParseIPV4Address(%ws)\n", pwszValue)); if (CB_IPV4ADDRESS > *pcb) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); _JumpError(hr, error, "buffer too small"); } for (cb = 0; cb < CB_IPV4ADDRESS; cb++) { WCHAR *pwszNext; BOOL fValid; DWORD dw; pwszNext = &pwszValue[wcscspn(pwszValue, L".")]; if (L'.' == *pwszNext) { *pwszNext++ = L'\0'; } dw = myWtoI(pwszValue, &fValid); if (!fValid || 255 < dw) { hr = E_INVALIDARG; _JumpErrorStr(hr, error, "bad IP Address digit string", pwszValue); } pb[cb] = (BYTE) dw; pwszValue = pwszNext; } if (L'\0' != *pwszValue) { hr = E_INVALIDARG; _JumpError(hr, error, "extra data"); } *pcb = cb; DBGPRINT(( DBG_SS_CERTLIBI, "infParseIPV4Address: %u.%u.%u.%u\n", pb[0], pb[1], pb[2], pb[3])); hr = S_OK; error: return(hr); } // Destructively parse a new-style 16 byte IP Address. #define MAKE16(b0, b1) (((b0) << 8) | (b1)) HRESULT infParseIPV6AddressSub( IN WCHAR *pwszValue, OUT BYTE *pb, IN OUT DWORD *pcb) { HRESULT hr; DWORD cbMax = *pcb; DWORD cb; DBGPRINT((DBG_SS_CERTLIBI, "infParseIPV6AddressSub(%ws)\n", pwszValue)); ZeroMemory(pb, cbMax); for (cb = 0; cb < cbMax; cb += 2) { WCHAR *pwszNext; BOOL fValid; DWORD dw; WCHAR awc[7]; pwszNext = &pwszValue[wcscspn(pwszValue, L":")]; if (L':' == *pwszNext) { *pwszNext++ = L'\0'; } if (L'\0' == *pwszValue) { break; } if (4 < wcslen(pwszValue)) { hr = E_INVALIDARG; _JumpErrorStr(hr, error, "too many IP Address digits", pwszValue); } wcscpy(awc, L"0x"); wcscat(awc, pwszValue); CSASSERT(wcslen(awc) < ARRAYSIZE(awc)); dw = myWtoI(awc, &fValid); if (!fValid || 64 * 1024 <= dw) { hr = E_INVALIDARG; _JumpErrorStr(hr, error, "bad IP Address digit string", pwszValue); } pb[cb] = (BYTE) (dw >> 8); pb[cb + 1] = (BYTE) dw; pwszValue = pwszNext; } if (L'\0' != *pwszValue) { hr = E_INVALIDARG; _JumpErrorStr(hr, error, "extra data", pwszValue); } *pcb = cb; hr = S_OK; error: return(hr); } // Destructively parse a new-style 16 byte IP Address. HRESULT infParseIPV6Address( IN WCHAR *pwszValue, OUT BYTE *pb, IN OUT DWORD *pcb) { HRESULT hr; DWORD cbMax; WCHAR *pwsz; WCHAR *pwszLeft; WCHAR *pwszRight; BYTE abRight[CB_IPV6ADDRESS]; DWORD cbLeft; DWORD cbRight; DWORD i; BOOL fV4Compat; DBGPRINT((DBG_SS_CERTLIBI, "infParseIPV6Address(%ws)\n", pwszValue)); if (CB_IPV6ADDRESS > *pcb) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); _JumpError(hr, error, "buffer too small"); } ZeroMemory(pb, CB_IPV6ADDRESS); cbMax = CB_IPV6ADDRESS; // If there's a period after the last colon, an IP V4 Address is attached. // Parse it as an IP V4 Address, and reduce the expected size of the IP V6 // Address to be parsed from eight to six 16-bit address chunks. pwsz = wcsrchr(pwszValue, L':'); if (NULL != pwsz) { if (NULL != wcschr(pwsz, L'.')) { DWORD cb = CB_IPV4ADDRESS; hr = infParseIPV4Address( &pwsz[1], &pb[CB_IPV6ADDRESS - CB_IPV4ADDRESS], &cb); _JumpIfError(hr, error, "infParseIPV4Address"); CSASSERT(CB_IPV4ADDRESS == cb); pwsz[1] = L'\0'; // get rid of the trailing IP V4 Address // drop the trailing colon -- if it's not part of a double colon. if (pwsz > pwszValue && L':' != *--pwsz) { pwsz[1] = L'\0'; } cbMax -= CB_IPV4ADDRESS; } } cbLeft = 0; cbRight = 0; pwszLeft = pwszValue; pwszRight = wcsstr(pwszValue, L"::"); if (NULL != pwszRight) { *pwszRight = L'\0'; pwszRight += 2; if (L'\0' != *pwszRight) { cbRight = cbMax; hr = infParseIPV6AddressSub(pwszRight, abRight, &cbRight); _JumpIfError(hr, error, "infParseIPV6AddressSub"); } } if (L'\0' != *pwszLeft) { cbLeft = cbMax; hr = infParseIPV6AddressSub(pwszLeft, pb, &cbLeft); _JumpIfError(hr, error, "infParseIPV6AddressSub"); } if (NULL == pwszRight && cbLeft != cbMax) { hr = E_INVALIDARG; _JumpError(hr, error, "too few IP Address chunks"); } if (cbLeft + cbRight + (NULL != pwszRight? 1 : 0) > cbMax) { hr = E_INVALIDARG; _JumpError(hr, error, "too many IP Address chunks"); } if (0 != cbRight) { CopyMemory(&pb[cbMax - cbRight], abRight, cbRight); } *pcb = CB_IPV6ADDRESS; fV4Compat = TRUE; for (i = 0; i < CB_IPV6ADDRESS - CB_IPV4ADDRESS - 2; i++) { if (0 != pb[i]) { fV4Compat = FALSE; break; } } if (fV4Compat) { CSASSERT(i == CB_IPV6ADDRESS - CB_IPV4ADDRESS - 2); fV4Compat = (0 == pb[i] && 0 == pb[i + 1]) || (0xff == pb[i] && 0xff == pb[i + 1]); } if (fV4Compat) { CSASSERT(i == CB_IPV6ADDRESS - CB_IPV4ADDRESS - 2); DBGPRINT(( DBG_SS_CERTLIBI, "infParseIPV6Address: ::%hs%u.%u.%u.%u\n", 0 == pb[i]? "" : "ffff:", pb[12], pb[13], pb[14], pb[15])); } else { DBGPRINT(( DBG_SS_CERTLIBI, "infParseIPV6Address: %x:%x:%x:%x:%x:%x:%x:%x\n", MAKE16(pb[0], pb[1]), MAKE16(pb[2], pb[3]), MAKE16(pb[4], pb[5]), MAKE16(pb[6], pb[7]), MAKE16(pb[8], pb[9]), MAKE16(pb[10], pb[11]), MAKE16(pb[12], pb[13]), MAKE16(pb[14], pb[15]))); } hr = S_OK; error: return(hr); } HRESULT myParseIPAddress( IN WCHAR const *pwszValue, OUT BYTE *pbData, OUT DWORD *pcbData) { HRESULT hr; DWORD cb = *pcbData; WCHAR *pwszDup = NULL; // if pwszValue is an empty string, return zero length. *pcbData = 0; if (L'\0' != *pwszValue) { hr = myDupString(pwszValue, &pwszDup); _JumpIfError(hr, error, "myDupString"); if (NULL == wcschr(pwszDup, L':')) { hr = infParseIPV4Address(pwszDup, pbData, &cb); _JumpIfError(hr, error, "infParseIPV4Address"); } else { hr = infParseIPV6Address(pwszDup, pbData, &cb); _JumpIfError(hr, error, "infParseIPV6Address"); } *pcbData = cb; DBGDUMPHEX(( DBG_SS_CERTLIBI, DH_NOADDRESS | DH_NOTABPREFIX | 8, pbData, *pcbData)); } hr = S_OK; error: if (NULL != pwszDup) { LocalFree(pwszDup); } return(hr); } HRESULT myBuildOSVersionAttribute( OUT BYTE **ppbVersion, OUT DWORD *pcbVersion) { HRESULT hr; DWORD i; OSVERSIONINFO osvInfo; CERT_NAME_VALUE cnvOSVer; #define cwcVERSIONMAX 128 WCHAR wszVersion[12 * 4 + cwcVERSIONMAX]; *ppbVersion = NULL; ZeroMemory(&osvInfo, sizeof(osvInfo)); // get the OSVersion osvInfo.dwOSVersionInfoSize = sizeof(osvInfo); if (!GetVersionEx(&osvInfo)) { hr = myHLastError(); _JumpError(hr, error, "GetVersionEx"); } for (i = 0; ; i++) { swprintf( wszVersion, 0 == i? L"%d.%d.%d.%d.%.*ws" : L"%d.%d.%d.%d", osvInfo.dwMajorVersion, osvInfo.dwMinorVersion, osvInfo.dwBuildNumber, osvInfo.dwPlatformId, cwcVERSIONMAX, osvInfo.szCSDVersion); CSASSERT(ARRAYSIZE(wszVersion) > wcslen(wszVersion)); cnvOSVer.dwValueType = CERT_RDN_IA5_STRING; cnvOSVer.Value.pbData = (BYTE *) wszVersion; cnvOSVer.Value.cbData = 0; if (!myEncodeObject( X509_ASN_ENCODING, X509_UNICODE_ANY_STRING, &cnvOSVer, 0, CERTLIB_USE_LOCALALLOC, ppbVersion, pcbVersion)) { hr = myHLastError(); _PrintError(hr, "myEncodeObject"); if (0 == i) { continue; } goto error; } break; } hr = S_OK; error: return(hr); } WCHAR const * myFixTemplateCase( IN WCHAR const *pwszCertType) { DWORD i; static WCHAR const *apwszCertType[] = { wszCERTTYPE_CA, wszCERTTYPE_SUBORDINATE_CA, wszCERTTYPE_CROSS_CA, }; for (i = 0; i < ARRAYSIZE(apwszCertType); i++) { if (0 == mylstrcmpiS(pwszCertType, apwszCertType[i])) { pwszCertType = apwszCertType[i]; break; } } return(pwszCertType); } HRESULT myBuildCertTypeExtension( IN WCHAR const *pwszCertType, OUT CERT_EXTENSION *pExt) { HRESULT hr; CERT_TEMPLATE_EXT Template; CERT_NAME_VALUE NameValue; LPCSTR pszStructType; char *pszObjId = NULL; VOID *pv; char *pszObjIdExt; if (!ConvertWszToSz(&pszObjId, pwszCertType, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToSz"); } hr = myVerifyObjIdA(pszObjId); if (S_OK == hr) { ZeroMemory(&Template, sizeof(Template)); Template.pszObjId = pszObjId; //Template.dwMajorVersion = 0; //Template.fMinorVersion = FALSE; // TRUE for a minor version //Template.dwMinorVersion = 0; pszStructType = X509_CERTIFICATE_TEMPLATE; pv = &Template; pszObjIdExt = szOID_CERTIFICATE_TEMPLATE; } else { NameValue.dwValueType = CERT_RDN_UNICODE_STRING; NameValue.Value.pbData = (BYTE *) myFixTemplateCase(pwszCertType); NameValue.Value.cbData = 0; pszStructType = X509_UNICODE_ANY_STRING; pv = &NameValue; pszObjIdExt = szOID_ENROLL_CERTTYPE_EXTENSION; } if (!myEncodeObject( X509_ASN_ENCODING, pszStructType, pv, 0, CERTLIB_USE_LOCALALLOC, &pExt->Value.pbData, &pExt->Value.cbData)) { hr = myHLastError(); _JumpError(hr, error, "myEncodeObject"); } pExt->pszObjId = pszObjIdExt; pExt->fCritical = FALSE; hr = S_OK; error: if (NULL != pszObjId) { LocalFree(pszObjId); } return(hr); } VOID myPackExtensionArray( IN BOOL fFreeData, IN OUT DWORD *pcExt, IN OUT CERT_EXTENSION **prgExt) { CERT_EXTENSION *rgExt = *prgExt; DWORD cExt = *pcExt; DWORD i; DWORD j; CERT_EXTENSION *pExti; CERT_EXTENSION *pExtj; for (i = 0; i < cExt; i++) { pExti = &rgExt[i]; if (NULL != pExti->pszObjId) { for (j = i + 1; j < cExt; j++) { pExtj = &rgExt[j]; if (NULL != pExtj->pszObjId && 0 == strcmp(pExti->pszObjId, pExtj->pszObjId)) { if (fFreeData) { LocalFree(pExtj->pszObjId); if (NULL != pExtj->Value.pbData) { LocalFree(pExtj->Value.pbData); } } pExtj->pszObjId = NULL; pExtj->Value.pbData = NULL; } } if (NULL == pExti->Value.pbData) { if (fFreeData) { LocalFree(pExti->pszObjId); } pExti->pszObjId = NULL; } } } for (i = j = 0; i < cExt; i++) { pExti = &rgExt[i]; pExtj = &rgExt[j]; CSASSERT((NULL != pExti->pszObjId) ^ (NULL == pExti->Value.pbData)); if (NULL != pExti->pszObjId && NULL != pExti->Value.pbData) { *pExtj = *pExti; j++; } } if (j < cExt) { ZeroMemory(&rgExt[j], (cExt - j) * sizeof(rgExt[0])); *pcExt = j; } } HRESULT myMergeExtensions( IN DWORD cExtOrg, IN CERT_EXTENSION *rgExtOrg, IN DWORD cExtInf, IN CERT_EXTENSION *rgExtInf, OUT DWORD *pcExtMerged, OUT CERT_EXTENSION **prgExtMerged) { HRESULT hr; CERT_EXTENSION *rgExtMerged; *prgExtMerged = NULL; rgExtMerged = (CERT_EXTENSION *) LocalAlloc( LMEM_FIXED, (cExtInf + cExtOrg) * sizeof(rgExtMerged[0])); if (NULL == rgExtMerged) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (0 != cExtInf) { CopyMemory( &rgExtMerged[0], &rgExtInf[0], cExtInf * sizeof(rgExtMerged[0])); } if (0 != cExtOrg) { CopyMemory( &rgExtMerged[cExtInf], &rgExtOrg[0], cExtOrg * sizeof(rgExtMerged[0])); } *pcExtMerged = cExtInf + cExtOrg; *prgExtMerged = rgExtMerged; myPackExtensionArray(FALSE, pcExtMerged, prgExtMerged); hr = S_OK; error: return(hr); } BOOL IsWhistler(VOID) { HRESULT hr; OSVERSIONINFO ovi; static BOOL s_fDone = FALSE; static BOOL s_fWhistler = FALSE; if (!s_fDone) { s_fDone = TRUE; // get and confirm platform info ovi.dwOSVersionInfoSize = sizeof(ovi); if (!GetVersionEx(&ovi)) { hr = myHLastError(); _JumpError(hr, error, "GetVersionEx"); } if (VER_PLATFORM_WIN32_NT != ovi.dwPlatformId) { hr = ERROR_CANCELLED; _JumpError(hr, error, "Not a supported OS"); } if (5 < ovi.dwMajorVersion || (5 <= ovi.dwMajorVersion && 0 < ovi.dwMinorVersion)) { s_fWhistler = TRUE; } } error: return(s_fWhistler); } static BOOL GetFlags( OUT DWORD *pdw) { HRESULT hr = S_FALSE; *pdw = 0; #if defined(_ALLOW_GET_FLAGS_) hr = myGetCertRegDWValue(NULL, NULL, NULL, L"SFlags", pdw); if (S_OK == hr) { DBGPRINT(( DBG_SS_CERTLIB, "CertSrv\\Configuration\\SFlags override: %u\n", *pdw)); } #endif return(S_OK == hr); } BOOL FIsAdvancedServer(VOID) { HRESULT hr; OSVERSIONINFOEX ovi; static BOOL s_fDone = FALSE; static BOOL s_fIsAdvSvr = FALSE; if (!s_fDone) { s_fDone = TRUE; // get and confirm platform info ovi.dwOSVersionInfoSize = sizeof(ovi); if (!GetVersionEx((OSVERSIONINFO *) &ovi)) { hr = myHLastError(); _JumpError(hr, error, "GetVersionEx"); } if (VER_PLATFORM_WIN32_NT != ovi.dwPlatformId) { hr = ERROR_CANCELLED; _JumpError(hr, error, "Not a supported OS"); } // if server or DC, if DTC or ADS bits are set, return TRUE s_fIsAdvSvr = (ovi.wProductType == VER_NT_SERVER || ovi.wProductType == VER_NT_DOMAIN_CONTROLLER) && (ovi.wSuiteMask & VER_SUITE_DATACENTER || ovi.wSuiteMask & VER_SUITE_ENTERPRISE); { DWORD dw; if (GetFlags(&dw)) { s_fIsAdvSvr = dw; } } } error: return(s_fIsAdvSvr); } BOOL FIsServer(VOID) { HRESULT hr; OSVERSIONINFOEX ovi; static BOOL s_fDone = FALSE; static BOOL s_fIsSvr = FALSE; if (!s_fDone) { s_fDone = TRUE; // get and confirm platform info ovi.dwOSVersionInfoSize = sizeof(ovi); if (!GetVersionEx((OSVERSIONINFO *) &ovi)) { hr = myHLastError(); _JumpError(hr, error, "GetVersionEx"); } if (VER_PLATFORM_WIN32_NT != ovi.dwPlatformId) { hr = ERROR_CANCELLED; _JumpError(hr, error, "Not a supported OS"); } // if server or DC, if DTC or ADS bits are set, return TRUE s_fIsSvr = (ovi.wProductType == VER_NT_SERVER || ovi.wProductType == VER_NT_DOMAIN_CONTROLLER) && 0 == ((VER_SUITE_PERSONAL | VER_SUITE_BLADE) & ovi.wSuiteMask); if (!s_fIsSvr && VER_NT_WORKSTATION == ovi.wProductType) { DWORD dw; if (GetFlags(&dw)) { s_fIsSvr = TRUE; } } } error: return(s_fIsSvr); } HRESULT myAddLogSourceToRegistry( IN LPWSTR pwszMsgDLL, IN LPWSTR pwszApp) { HRESULT hr=S_OK; DWORD dwData=0; WCHAR const *pwszRegPath = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\"; WCHAR NameBuf[MAX_PATH]; HKEY hkey = NULL; if (wcslen(pwszRegPath) + wcslen(pwszApp) >= ARRAYSIZE(NameBuf)) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); _JumpErrorStr(hr, error, "NameBuf", pwszApp); } wcscpy(NameBuf, pwszRegPath); wcscat(NameBuf, pwszApp); // Create a new key for our application hr = RegOpenKey(HKEY_LOCAL_MACHINE, NameBuf, &hkey); if (S_OK != hr) { hr = RegCreateKey(HKEY_LOCAL_MACHINE, NameBuf, &hkey); _JumpIfError(hr, error, "RegCreateKey"); } // Add the Event-ID message-file name to the subkey hr = RegSetValueEx( hkey, L"EventMessageFile", 0, REG_EXPAND_SZ, (const BYTE *) pwszMsgDLL, (wcslen(pwszMsgDLL) + 1) * sizeof(WCHAR)); _JumpIfError(hr, error, "RegSetValueEx"); // Set the supported types flags and add it to the subkey dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; hr = RegSetValueEx( hkey, L"TypesSupported", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD)); _JumpIfError(hr, error, "RegSetValueEx"); error: if (NULL != hkey) { RegCloseKey(hkey); } return(myHError(hr)); } HRESULT myDupStringA( IN CHAR const *pszIn, IN CHAR **ppszOut) { DWORD cb; HRESULT hr; cb = (strlen(pszIn) + 1) * sizeof(CHAR); *ppszOut = (CHAR *) LocalAlloc(LMEM_FIXED, cb); if (NULL == *ppszOut) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(*ppszOut, pszIn, cb); hr = S_OK; error: return(hr); } HRESULT myIsCurrentUserBuiltinAdmin( OUT bool *pfIsMember) { HANDLE hAccessToken = NULL, hDupToken = NULL; PSID psidAdministrators = NULL; SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY; HRESULT hr = S_OK; BOOL fIsMember = FALSE; CSASSERT(pfIsMember); if (!AllocateAndInitializeSid( &siaNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdministrators)) { hr = myHLastError(); _JumpError(hr, error, "AllocateAndInitializeSid"); } { HANDLE hThread = GetCurrentThread(); if (NULL == hThread) { hr = myHLastError(); _JumpIfError(hr, error, "GetCurrentThread"); } // Get the access token for current thread if (!OpenThreadToken( hThread, TOKEN_QUERY | TOKEN_DUPLICATE, FALSE, &hAccessToken)) { hr = myHLastError(); if(hr==HRESULT_FROM_WIN32(ERROR_NO_TOKEN)) { HANDLE hProcess = GetCurrentProcess(); if (NULL == hProcess) { hr = myHLastError(); _JumpError(hr, error, "GetCurrentProcess"); } if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, &hAccessToken)) { hr = myHLastError(); _JumpError(hr, error, "OpenProcessToken"); } } else { _JumpError(hr, error, "OpenThreadToken"); } } } // CheckTokenMembership must operate on impersonation token, so make one if (!DuplicateToken(hAccessToken, SecurityIdentification, &hDupToken)) { hr = myHLastError(); _JumpError(hr, error, "DuplicateToken"); } if (!CheckTokenMembership( hDupToken, psidAdministrators, &fIsMember)) { hr = myHLastError(); _JumpError(hr, error, "CheckTokenMembership"); } *pfIsMember = fIsMember?true:false; hr = S_OK; error: if (hAccessToken) CloseHandle(hAccessToken); if (hDupToken) CloseHandle(hDupToken); // Free the SID we allocated if (psidAdministrators) FreeSid(psidAdministrators); return(hr); } HRESULT mySetRegistryLocalPathString( IN HKEY hkey, IN WCHAR const *pwszRegValueName, IN WCHAR const *pwszUNCPath) { HRESULT hr; WCHAR *pwszLocalPath = NULL; hr = myConvertUNCPathToLocal(pwszUNCPath, &pwszLocalPath); _JumpIfError(hr, error, "myConvertUNCPathToLocal"); hr = RegSetValueEx( hkey, pwszRegValueName, 0, REG_SZ, (BYTE *) pwszLocalPath, (wcslen(pwszLocalPath) + 1) * sizeof(WCHAR)); _JumpIfError(hr, error, "RegSetValueEx"); error: if (NULL != pwszLocalPath) { LocalFree(pwszLocalPath); } return(hr); } HRESULT myLocalMachineIsDomainMember( OUT bool *pfIsDomainMember) { HRESULT hr = S_OK; NTSTATUS status; LSA_HANDLE PolicyHandle = NULL; PPOLICY_PRIMARY_DOMAIN_INFO pPDI = NULL; LSA_OBJECT_ATTRIBUTES ObjectAttributes; CSASSERT(pfIsDomainMember); *pfIsDomainMember = FALSE; ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); status = LsaOpenPolicy( NULL, &ObjectAttributes, GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle); if(ERROR_SUCCESS != status) { hr = myHError(LsaNtStatusToWinError(status)); _JumpError(hr, error, "LsaOpenPolicy"); } status = LsaQueryInformationPolicy( PolicyHandle, PolicyPrimaryDomainInformation, (PVOID*)&pPDI); if(status) { hr = myHError(LsaNtStatusToWinError(status)); _JumpError(hr, error, "LsaQueryInformationPolicy"); } if( pPDI->Sid ) { // domain member if has domain SID *pfIsDomainMember = TRUE; } error: if(pPDI) { LsaFreeMemory((LPVOID)pPDI); } if(PolicyHandle) { LsaClose(PolicyHandle); } return hr; } HRESULT myComputeMAC( IN WCHAR const *pcwsFileName, OUT WCHAR **ppwszMAC) { HRESULT hr; HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hFileMapping = NULL; BYTE *pbFile = NULL; DWORD cbImage, cbImageHigh = 0; __int64 icbImage, icbHashed; WCHAR rgwszMAC[CBMAX_CRYPT_HASH_LEN * 3]; // 20 bytes @ 3 WCHARs/byte DWORD cbString; DWORD dwFileMappingSize; HCRYPTPROV hProv = NULL; HCRYPTHASH hHash = NULL; BYTE rgbHashVal[CBMAX_CRYPT_HASH_LEN]; DWORD cbHashVal = sizeof(rgbHashVal); *ppwszMAC = NULL; // find allocation granularity we can use SYSTEM_INFO systemInfo; GetSystemInfo(&systemInfo); dwFileMappingSize = systemInfo.dwAllocationGranularity; // get the file size hFile = CreateFile( pcwsFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (INVALID_HANDLE_VALUE == hFile) { hr = myHLastError(); if (S_OK == hr) { _PrintError(hr, "CreateFile"); hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } _JumpErrorStr(hr, error, "CreateFile", pcwsFileName); } if (0xffffffff == (cbImage = GetFileSize(hFile, &cbImageHigh))) { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); _JumpError(hr, error, "GetFileSize"); } icbImage = ((__int64) cbImageHigh << 32) | cbImage; // create mapping, indicating we will map the entire file sooner or later hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if(hFileMapping == NULL) { hr = myHLastError(); _JumpError(hr, error, "CreateFileMapping"); } // get a cryptographic provider if (!CryptAcquireContext( &hProv, NULL, // container MS_DEF_PROV, // provider name PROV_RSA_FULL, // provider type CRYPT_VERIFYCONTEXT)) // dwflags { hr = myHLastError(); _JumpError(hr, error, "CryptAcquireContext"); } // get a hash if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash)) { hr = myHLastError(); _JumpError(hr, error, "CryptCreateHash"); } // begin looping over data for (icbHashed = 0; icbHashed < icbImage; icbHashed += dwFileMappingSize) { DWORD cbBytesLeft = (DWORD) min( (__int64) dwFileMappingSize, icbImage - icbHashed); // map the next blob into memory pbFile = (BYTE *) MapViewOfFile( hFileMapping, FILE_MAP_READ, (DWORD) (icbHashed>>32), //hi32 (DWORD) (icbHashed), //lo32 cbBytesLeft); // max num bytes to map if (NULL == pbFile) { hr = myHLastError(); _JumpError(hr, error, "MapViewOfFile"); } // hash file if (!CryptHashData(hHash, pbFile, cbBytesLeft, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptHashData"); } // unmap this portion if (!UnmapViewOfFile(pbFile)) { pbFile = NULL; hr = myHLastError(); _JumpError(hr, error, "UnmapViewOfFile"); } pbFile = NULL; } // end looping over data // retry the hash if (!CryptGetHashParam(hHash, HP_HASHVAL, rgbHashVal, &cbHashVal, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptGetHashParam"); } cbString = sizeof(rgwszMAC); hr = MultiByteIntegerToWszBuf( TRUE, // byte multiple cbHashVal, rgbHashVal, &cbString, rgwszMAC); _JumpIfError(hr, error, "MultiByteIntegerToWszBuf"); hr = myDupString(rgwszMAC, ppwszMAC); _JumpIfError(hr, error, "myDupString"); error: if (NULL != pbFile) { UnmapViewOfFile(pbFile); } if (NULL != hFileMapping) { CloseHandle(hFileMapping); } if (INVALID_HANDLE_VALUE != hFile) { CloseHandle(hFile); } if (NULL != hHash) { if (!CryptDestroyHash(hHash)) { if (hr == S_OK) { hr = myHLastError(); } } } if (NULL != hProv) { if (!CryptReleaseContext(hProv, 0)) { if (hr == S_OK) { hr = myHLastError(); } } } return(hr); } HRESULT myHExceptionCodePrintLineFile( IN EXCEPTION_POINTERS const *pep, IN DWORD dwLineFile) { return(myHExceptionCodePrint( pep, NULL, __LINEFILETOFILE__(dwLineFile), __LINEFILETOLINE__(dwLineFile))); } BOOL myShouldPrintError( IN HRESULT hr, IN HRESULT hrquiet) { BOOL fPrint = TRUE; if (myIsDelayLoadHResult(hr)) { #if DBG_CERTSRV if (!DbgIsSSActive(DBG_SS_MODLOAD)) #endif { fPrint = FALSE; } } if (S_OK != hrquiet && hrquiet == hr) { #if DBG_CERTSRV if (!DbgIsSSActive(DBG_SS_NOQUIET)) #endif { fPrint = FALSE; } } return(fPrint); } VOID CSPrintErrorLineFileData2( OPTIONAL IN WCHAR const *pwszData, IN DWORD dwLineFile, IN HRESULT hr, IN HRESULT hrquiet) { WCHAR awchr[cwcHRESULTSTRING]; if (DbgIsSSActive(DBG_SS_ERROR) && myShouldPrintError(hr, hrquiet)) { DbgPrintf( MAXDWORD, "%u.%u.%u: %ws%ws%ws\n", __LINEFILETOFILE__(dwLineFile), __LINEFILETOLINE__(dwLineFile), 0, myHResultToString(awchr, hr), NULL != pwszData? L": " : L"", NULL != pwszData? pwszData : L""); DBGPRINT(( DBG_SS_ERROR, "%u.%u.%u: %ws%ws%ws\n", __LINEFILETOFILE__(dwLineFile), __LINEFILETOLINE__(dwLineFile), 0, myHResultToString(awchr, hr), NULL != pwszData? L": " : L"", NULL != pwszData? pwszData : L"")); } } VOID CSPrintErrorLineFile( IN DWORD dwLineFile, IN HRESULT hr) { CSPrintErrorLineFileData2(NULL, dwLineFile, hr, S_OK); } VOID CSPrintErrorLineFile2( IN DWORD dwLineFile, IN HRESULT hr, IN HRESULT hrquiet) { CSPrintErrorLineFileData2(NULL, dwLineFile, hr, hrquiet); } VOID CSPrintErrorLineFileData( OPTIONAL IN WCHAR const *pwszData, IN DWORD dwLineFile, IN HRESULT hr) { CSPrintErrorLineFileData2(pwszData, dwLineFile, hr, S_OK); } // Finds a template in list based on name or OID. // Caller is responsible for CACloseCertType(hCertType) in case of success HRESULT myFindCertTypeByNameOrOID( IN const HCERTTYPE &hCertTypeList, IN OPTIONAL LPCWSTR pcwszCertName, IN OPTIONAL LPCWSTR pcwszCertOID, OUT HCERTTYPE& hCertType) { HRESULT hr; HCERTTYPE hCrtCertType; HCERTTYPE hPrevCertType; CSASSERT(pcwszCertName || pcwszCertOID); hCertType = NULL; hCrtCertType = hCertTypeList; while (NULL != hCrtCertType) { LPWSTR *apwszCrtCertType; BOOL fFound; hr = CAGetCertTypeProperty( hCrtCertType, CERTTYPE_PROP_CN, &apwszCrtCertType); _JumpIfError(hr, error, "CAGetCertTypeProperty CERTTYPE_PROP_CN"); if (NULL != apwszCrtCertType) { fFound = NULL != apwszCrtCertType[0] && NULL != pcwszCertName && 0 == mylstrcmpiS(apwszCrtCertType[0], pcwszCertName); CAFreeCertTypeProperty(hCrtCertType, apwszCrtCertType); if (fFound) { break; } } hr = CAGetCertTypeProperty( hCrtCertType, CERTTYPE_PROP_OID, &apwszCrtCertType); // ignore errors, V1 templates don't have OIDs if (S_OK == hr && NULL != apwszCrtCertType) { fFound = NULL != apwszCrtCertType[0] && NULL != pcwszCertOID && 0 == mylstrcmpiS(apwszCrtCertType[0], pcwszCertOID); CAFreeCertTypeProperty(hCrtCertType, apwszCrtCertType); if (fFound) { break; } } hPrevCertType = hCrtCertType; hr = CAEnumNextCertType(hPrevCertType, &hCrtCertType); _JumpIfError(hr, error, "CAEnumNextCertType"); // hold on to the initial list if (hCertTypeList != hPrevCertType) { CACloseCertType(hPrevCertType); } } if (NULL == hCrtCertType) { hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); _JumpError2(hr, error, "NULL hCrtCertType", hr); } hCertType = hCrtCertType; hCrtCertType = NULL; hr = S_OK; error: if (NULL != hCrtCertType && hCertTypeList != hCrtCertType) { CACloseCertType(hCrtCertType); } return(hr); } /////////////////////////////////////////////////////////////////////////////// // ConvertToString* /////////////////////////////////////////////////////////////////////////////// HRESULT ConvertToStringI2I4( LONG lVal, LPWSTR *ppwszOut) { WCHAR wszVal[cwcDWORDSPRINTF]; // big enough to hold a LONG as string _itow(lVal, wszVal, 10); *ppwszOut = (LPWSTR) LocalAlloc( LMEM_FIXED, sizeof(WCHAR)*(wcslen(wszVal)+1)); if(!*ppwszOut) { return E_OUTOFMEMORY; } wcscpy(*ppwszOut, wszVal); return S_OK; } /////////////////////////////////////////////////////////////////////////////// HRESULT ConvertToStringUI2UI4( ULONG ulVal, LPWSTR *ppwszOut) { WCHAR wszVal[cwcDWORDSPRINTF]; // big enough to hold a LONG as string _itow(ulVal, wszVal, 10); *ppwszOut = (LPWSTR) LocalAlloc( LMEM_FIXED, sizeof(WCHAR)*(wcslen(wszVal)+1)); if(!*ppwszOut) { return E_OUTOFMEMORY; } wcscpy(*ppwszOut, wszVal); return S_OK; } /////////////////////////////////////////////////////////////////////////////// HRESULT ConvertToStringUI8( ULARGE_INTEGER *puliVal, LPWSTR *ppwszOut) { WCHAR wszVal[cwcULONG_INTEGERSPRINTF]; // big enough to hold a LONG as string _ui64tow(puliVal->QuadPart, wszVal, 10); *ppwszOut = (LPWSTR) LocalAlloc( LMEM_FIXED, sizeof(WCHAR)*(wcslen(wszVal)+1)); if(!*ppwszOut) { return E_OUTOFMEMORY; } wcscpy(*ppwszOut, wszVal); return S_OK; } /////////////////////////////////////////////////////////////////////////////// HRESULT ConvertToStringWSZ( LPCWSTR pcwszVal, LPWSTR *ppwszOut, bool fDoublePercentsInString) { if(fDoublePercentsInString) { // replace each occurence of % with %% return DoublePercentsInString( pcwszVal, ppwszOut); } else { *ppwszOut = (LPWSTR) LocalAlloc( LMEM_FIXED, sizeof(WCHAR)*(wcslen(pcwszVal)+1)); if(!*ppwszOut) { return E_OUTOFMEMORY; } wcscpy(*ppwszOut, pcwszVal); } return S_OK; } /////////////////////////////////////////////////////////////////////////////// HRESULT ConvertToStringArrayUI1( LPSAFEARRAY psa, LPWSTR *ppwszOut) { SafeArrayEnum saenum(psa); if(!saenum.IsValid()) { return E_INVALIDARG; } BYTE b; // byte array is formated as "0x00 0x00..." ie 5 // chars per byte *ppwszOut = (LPWSTR) LocalAlloc( LMEM_FIXED, sizeof(WCHAR)*(saenum.GetCount()*5 + 1)); if(!*ppwszOut) return E_OUTOFMEMORY; LPWSTR pwszCrt = *ppwszOut; while(S_OK==saenum.Next(b)) { wsprintf(pwszCrt, L"0x%02X ", b); // eg "0x0f" or "0xa4" pwszCrt+=5; } return S_OK; } /////////////////////////////////////////////////////////////////////////////// HRESULT ConvertToStringArrayBSTR( LPSAFEARRAY psa, LPWSTR *ppwszOut, bool fDoublePercentsInString) { SafeArrayEnum saenum(psa); if(!saenum.IsValid()) { return E_INVALIDARG; } DWORD dwLen = 1; BSTR bstr; while(S_OK==saenum.Next(bstr)) { dwLen+=2*wcslen(bstr)+10; } *ppwszOut = (LPWSTR) LocalAlloc( LMEM_FIXED, sizeof(WCHAR)*(dwLen)); if(!*ppwszOut) return E_OUTOFMEMORY; **ppwszOut = L'\0'; saenum.Reset(); WCHAR* pwszTemp = NULL; while(S_OK==saenum.Next(bstr)) { if(fDoublePercentsInString) { if (NULL != pwszTemp) { LocalFree(pwszTemp); pwszTemp = NULL; } if (S_OK != DoublePercentsInString(bstr, &pwszTemp)) { LocalFree(*ppwszOut); *ppwszOut = NULL; return E_OUTOFMEMORY; } wcscat(*ppwszOut, pwszTemp); } else { wcscat(*ppwszOut, bstr); } wcscat(*ppwszOut, L"\n"); } LOCAL_FREE(pwszTemp); return S_OK; } /////////////////////////////////////////////////////////////////////////////// HRESULT DoublePercentsInString( LPCWSTR pcwszIn, LPWSTR *ppwszOut) { const WCHAR *pchSrc; WCHAR *pchDest; *ppwszOut = (LPWSTR) LocalAlloc( LMEM_FIXED, sizeof(WCHAR)*(2*wcslen(pcwszIn)+1)); if(!*ppwszOut) return E_OUTOFMEMORY; for(pchSrc = pcwszIn, pchDest = *ppwszOut; L'\0'!=*pchSrc; pchSrc++, pchDest++) { *pchDest = *pchSrc; if(L'%'==*pchSrc) *(++pchDest) = L'%'; } *pchDest = L'\0'; return S_OK; } HRESULT ConvertToStringDATE( IN DATE const *pDate, IN BOOL fGMT, OUT LPWSTR *ppwszOut) { HRESULT hr; FILETIME ft; hr = myDateToFileTime(pDate, &ft); if (S_OK == hr) { if (fGMT) { hr = myFileTimeToWszTime(&ft, FALSE, ppwszOut); } else { hr = myGMTFileTimeToWszLocalTime(&ft, FALSE, ppwszOut); } } return(hr); } typedef DWORD (WINAPI fnDsEnumerateDomainTrusts) ( IN LPWSTR ServerName OPTIONAL, IN ULONG Flags, OUT PDS_DOMAIN_TRUSTSW *Domains, OUT PULONG DomainCount ); typedef NET_API_STATUS (NET_API_FUNCTION fnNetApiBufferFree) ( IN LPVOID Buffer ); /////////////////////////////////////////////////////////////////////////////// HRESULT myGetComputerDomainSid(PSID& rpsidDomain) { HRESULT hr = S_OK; PDS_DOMAIN_TRUSTS pDomainInfo = NULL; ULONG cDomainInfo = 0; HMODULE hModule = NULL; fnDsEnumerateDomainTrusts *pfnDsEnumerateDomainTrusts = NULL; fnNetApiBufferFree *pfnNetApiBufferFree = NULL; hModule = LoadLibrary(L"netapi32.dll"); if (NULL == hModule) { hr = myHLastError(); _JumpError(hr, error, "LoadLibrary(netapi32.dll)"); } pfnDsEnumerateDomainTrusts = (fnDsEnumerateDomainTrusts *) GetProcAddress( hModule, "DsEnumerateDomainTrustsW"); if (NULL == pfnDsEnumerateDomainTrusts) { hr = myHLastError(); _JumpError(hr, error, "DsEnumerateDomainTrustsW"); } pfnNetApiBufferFree = (fnNetApiBufferFree *) GetProcAddress( hModule, "NetApiBufferFree"); if(NULL == pfnNetApiBufferFree) { hr = myHLastError(); _JumpError(hr, error, "NetApiBufferFree"); } hr = (*pfnDsEnumerateDomainTrusts)( NULL, DS_DOMAIN_PRIMARY, &pDomainInfo, &cDomainInfo); _JumpIfError(hr, error, "DsEnumerateDomainTrusts"); CSASSERT(1==cDomainInfo); rpsidDomain = (PSID)LocalAlloc( LMEM_FIXED, GetLengthSid(pDomainInfo->DomainSid)); _JumpIfAllocFailed(rpsidDomain, error); CopySid( GetLengthSid(pDomainInfo->DomainSid), rpsidDomain, pDomainInfo->DomainSid); error: if(pDomainInfo) { (*pfnNetApiBufferFree)(pDomainInfo); } if(hModule) { FreeLibrary(hModule); } return hr; } /////////////////////////////////////////////////////////////////////////////// HRESULT myGetSidFromRid( DWORD dwGroupRid, OPTIONAL PSID *ppSid, OPTIONAL LPWSTR* ppwszSid) { HRESULT hr; LPWSTR pwszDomain = NULL; LPWSTR pwszDomainSid = NULL; PSID psidDomain = NULL; LPWSTR pwszSid = NULL; PSID psid = NULL; static const cchRid = 10; hr = myGetComputerDomainSid(psidDomain); _JumpIfError(hr, error, "myGetComputerDomainSid"); if(!ConvertSidToStringSid( psidDomain, &pwszDomainSid)) { hr = myHLastError(); _JumpError(hr, error, "ConvertSidToStringSid"); } myRegisterMemAlloc(pwszDomainSid, -1, CSM_LOCALALLOC); pwszSid = (LPWSTR) LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*(wcslen(pwszDomainSid)+cchRid+2)); // add 2 for dash and '\0' _JumpIfAllocFailed(pwszSid, error); wsprintf(pwszSid, L"%s-%d", pwszDomainSid, dwGroupRid); if(ppSid) { if(!ConvertStringSidToSid( pwszSid, &psid)) { hr = myHLastError(); _JumpErrorStr(hr, error, "ConvertSidToStringSid", pwszSid); } myRegisterMemAlloc(psid, -1, CSM_LOCALALLOC); *ppSid = psid; psid = NULL; } if(ppwszSid) { *ppwszSid = pwszSid; pwszSid = NULL; } hr = S_OK; error: LOCAL_FREE(pwszDomain); LOCAL_FREE(pwszDomainSid); LOCAL_FREE(psidDomain); LOCAL_FREE(psid); LOCAL_FREE(pwszSid); return hr; } HRESULT myEncodeUTF8( IN WCHAR const *pwszIn, OUT BYTE **ppbOut, OUT DWORD *pcbOut) { HRESULT hr; CERT_NAME_VALUE name; *ppbOut = NULL; name.dwValueType = CERT_RDN_UTF8_STRING; name.Value.pbData = (BYTE *) pwszIn; name.Value.cbData = 0; if (!myEncodeObject( X509_ASN_ENCODING, X509_UNICODE_ANY_STRING, &name, 0, CERTLIB_USE_LOCALALLOC, ppbOut, pcbOut)) { hr = myHLastError(); _JumpError(hr, error, "myEncodeObject"); } hr = S_OK; error: return(hr); } HRESULT myEncodeOtherNameBinary( IN WCHAR const *pwszIn, OUT BYTE **ppbOut, OUT DWORD *pcbOut) { HRESULT hr; CRYPT_DATA_BLOB blob; *ppbOut = NULL; blob.pbData = NULL; if (0 == _wcsnicmp(wszPROPUTF8TAG, pwszIn, WSZARRAYSIZE(wszPROPUTF8TAG))) { hr = myEncodeUTF8( &pwszIn[WSZARRAYSIZE(wszPROPUTF8TAG)], ppbOut, pcbOut); _JumpIfError(hr, error, "Policy:myEncodeUTF8"); } else { WCHAR const *pwsz; BOOL fOctet = FALSE; if (0 == _wcsnicmp( wszPROPOCTETTAG, pwszIn, WSZARRAYSIZE(wszPROPOCTETTAG))) { pwsz = &pwszIn[WSZARRAYSIZE(wszPROPOCTETTAG)]; fOctet = TRUE; } else if (0 == _wcsnicmp(wszPROPASNTAG, pwszIn, WSZARRAYSIZE(wszPROPASNTAG))) { pwsz = &pwszIn[WSZARRAYSIZE(wszPROPASNTAG)]; } else { hr = HRESULT_FROM_WIN32(ERROR_DS_BAD_ATT_SCHEMA_SYNTAX); _JumpError(hr, error, "Policy:polReencodeBinary"); } // CryptStringToBinaryW(CRYPT_STRING_BASE64) fails on empty strings, // because zero length means use wcslen + 1, which passes the L'\0' // terminator to the base 64 conversion code. if (L'\0' == *pwsz) { *ppbOut = (BYTE *) LocalAlloc(LMEM_FIXED, 0); if (NULL == *ppbOut) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } *pcbOut = 0; } else { hr = myCryptStringToBinary( pwsz, wcslen(pwsz), CRYPT_STRING_BASE64, ppbOut, pcbOut, NULL, NULL); _JumpIfError(hr, error, "myCryptStringToBinary"); } if (fOctet) { blob.pbData = *ppbOut; blob.cbData = *pcbOut; *ppbOut = NULL; if (!myEncodeObject( X509_ASN_ENCODING, X509_OCTET_STRING, &blob, 0, CERTLIB_USE_LOCALALLOC, ppbOut, pcbOut)) { hr = myHLastError(); _JumpError(hr, error, "Policy:myEncodeObject"); } } } hr = S_OK; error: if (NULL != blob.pbData) { LocalFree(blob.pbData); } return(hr); } // Wrappers to make sure zeroing memory survives compiler optimizations. // Use to wipe private key and password data. VOID myZeroDataString( IN WCHAR *pwsz) { HRESULT hr; hr = S_OK; __try { SecureZeroMemory(pwsz, wcslen(pwsz) * sizeof(*pwsz)); } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { _PrintError(hr, "Exception"); } } VOID myZeroDataStringA( IN char *psz) { HRESULT hr; hr = S_OK; __try { SecureZeroMemory(psz, strlen(psz) * sizeof(*psz)); } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { _PrintError(hr, "Exception"); } } // Locale-independent case-ignore string compare int mylstrcmpiL( IN WCHAR const *pwsz1, IN WCHAR const *pwsz2) { // CSTR_LESS_THAN(1) - CSTR_EQUAL(2) == -1 string 1 less than string 2 // CSTR_EQUAL(2) - CSTR_EQUAL(2) == 0 string 1 equal to string 2 // CSTR_GREATER_THAN(3) - CSTR_EQUAL(2) == 1 string 1 greater than string 2 return(CompareString( IsWhistler()? LOCALE_INVARIANT : MAKELCID( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, pwsz1, -1, pwsz2, -1) - CSTR_EQUAL); } // Locale-independent case-ignore string compare // asserts the static string contains a strict subset of 7-bit ASCII characters. int mylstrcmpiS( IN WCHAR const *pwszDynamic, IN WCHAR const *pwszStatic) { #if DBG_CERTSRV WCHAR const *pwszS; for (pwszS = pwszStatic; L'\0' != *pwszS; pwszS++) { CSASSERT(L' ' <= *pwszS && L'~' >= *pwszS); } #endif //DBG_CERTSRV return(mylstrcmpiL(pwszDynamic, pwszStatic)); } HRESULT myGetLong( WCHAR const *pwszIn, LONG *pLong) { HRESULT hr = E_INVALIDARG; WCHAR const *pwsz; LONG l; pwsz = pwszIn; if (NULL == pwsz) { _JumpError(hr, error, "NULL parm"); } if (L'\0' == *pwsz) { _JumpError(hr, error, "empty string"); } if (L'0' == *pwsz && (L'x' == pwsz[1] || L'X' == pwsz[1])) { pwsz += 2; l = 0; for ( ; L'\0' != *pwsz; pwsz++) { if (!iswxdigit(*pwsz)) { _JumpErrorStr(hr, error, "Non-hex digit", pwszIn); } l <<= 4; if (iswdigit(*pwsz)) { l |= *pwsz - L'0'; } else if (L'A' <= *pwsz && L'F' >= *pwsz) { l |= *pwsz - L'A' + 10; } else { l |= *pwsz - L'a' + 10; } } *pLong = l; } else { for ( ; L'\0' != *pwsz; pwsz++) { if (!iswdigit(*pwsz)) { _JumpErrorStr2(hr, error, "Non-decimal digit", pwszIn, hr); } } *pLong = _wtol(pwszIn); } hr = S_OK; //wprintf(L"myGetLong(%ws) --> %x (%d)\n", pwszIn, *pLong, *pLong); error: return(hr); } HRESULT myGetSignedLong( WCHAR const *pwszIn, LONG *pLong) { HRESULT hr = E_INVALIDARG; WCHAR const *pwsz; LONG sign = 1; pwsz = pwszIn; if (NULL == pwsz) { _JumpError(hr, error, "NULL parm"); } if (myIsMinusSign(*pwsz)) { pwsz++; sign = -1; } else if (L'+' == *pwsz) { pwsz++; } hr = myGetLong(pwsz, pLong); _JumpIfError2(hr, error, "myGetLong", hr); *pLong *= sign; //wprintf(L"myGetSignedLong(%ws) --> %x (%d)\n", pwszIn, *pLong, *pLong); error: return(hr); }