//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: misc.cpp // //-------------------------------------------------------------------------- #include // sddl.h requires this value to be at least // 0x0500. Bump it up if necessary. NOTE: This // 'bump' comes after all other H files that may // be sensitive to this value. #if(_WIN32_WINNT < 0x500) #undef _WIN32_WINNT #define _WIN32_WINNT 0x0500 #endif #include #include #include #include #include #include #include CLIPFORMAT g_cfDsObjectPicker = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST); // returns (if cstr.IsEmpty()) ? NULL : cstr) LPCWSTR GetNullMachineName(CString* pcstr) { LPCWSTR szMachine = (pcstr->IsEmpty()) ? NULL : (LPCWSTR)*pcstr; return szMachine; } BOOL StringFromDurationUnit(DWORD dwExpirationUnits, CString* pcstr, BOOL fLocalized) { if (NULL == pcstr) return FALSE; UINT uiRsc = 0; switch (dwExpirationUnits) { case(ENUM_PERIOD_YEARS): if (fLocalized) uiRsc = IDS_PERIOD_YEARS; else *pcstr = wszPERIODYEARS; break; case(ENUM_PERIOD_MONTHS): if (fLocalized) uiRsc = IDS_PERIOD_MONTHS; else *pcstr = wszPERIODMONTHS; break; case(ENUM_PERIOD_WEEKS): if (fLocalized) uiRsc = IDS_PERIOD_WEEKS; else *pcstr = wszPERIODWEEKS; break; case(ENUM_PERIOD_DAYS): if (fLocalized) uiRsc = IDS_PERIOD_DAYS; else *pcstr = wszPERIODDAYS; break; default: break; } if (uiRsc) pcstr->LoadString(uiRsc); return !pcstr->IsEmpty(); } ///////////////////////////////////////// // fxns to load/save cstrings to a streams STDMETHODIMP CStringLoad(CString& cstr, IStream *pStm) { ASSERT(pStm); HRESULT hr; DWORD cbSize=0; ULONG nBytesRead; // get cbSize (bytes) hr = pStm->Read(&cbSize, sizeof(cbSize), &nBytesRead); ASSERT(SUCCEEDED(hr) && (nBytesRead == sizeof(cbSize)) ); if (FAILED(hr)) return E_FAIL; // get string hr = pStm->Read(cstr.GetBuffer(cbSize), cbSize, &nBytesRead); ASSERT(SUCCEEDED(hr) && (nBytesRead == cbSize)); cstr.ReleaseBuffer(); return SUCCEEDED(hr) ? S_OK : E_FAIL; } STDMETHODIMP CStringSave(CString& cstr, IStream *pStm, BOOL fClearDirty) { // Write the string DWORD cbSize = (cstr.GetLength()+1)*sizeof(WCHAR); ULONG nBytesWritten; HRESULT hr; // write size in bytes hr = pStm->Write(&cbSize, sizeof(cbSize), &nBytesWritten); ASSERT(SUCCEEDED(hr) && (nBytesWritten == sizeof(cbSize)) ); if (FAILED(hr)) return STG_E_CANTSAVE; // write string hr = pStm->Write((LPCWSTR)cstr, cbSize, &nBytesWritten); ASSERT(SUCCEEDED(hr) && (nBytesWritten == cbSize)); // Verify that the write operation succeeded return SUCCEEDED(hr) ? S_OK : STG_E_CANTSAVE; } LPSTR AllocAndCopyStr(LPCSTR psz) { LPSTR pszReturn; pszReturn = (LPSTR) new(BYTE[strlen(psz)+1]); if(pszReturn) { strcpy(pszReturn, psz); } return pszReturn; } LPWSTR AllocAndCopyStr(LPCWSTR pwsz) { LPWSTR pwszReturn; pwszReturn = (LPWSTR) new(WCHAR[wcslen(pwsz)+1]); if(pwszReturn) { wcscpy(pwszReturn, pwsz); } return pwszReturn; } LPWSTR BuildErrorMessage(DWORD dwErr) { LPWSTR lpMsgBuf = NULL; FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR) &lpMsgBuf, 0, NULL ); return lpMsgBuf; } ////////////////////////////////////////////////////////////////// // given an error code and a console pointer, will pop error dlg void DisplayGenericCertSrvError(LPCONSOLE2 pConsole, DWORD dwErr) { ASSERT(pConsole); LPWSTR lpMsgBuf = BuildErrorMessage(dwErr); if(lpMsgBuf) { // ... // Display the string. pConsole->MessageBoxW(lpMsgBuf, L"Certificate Services Error", MB_OK | MB_ICONINFORMATION, NULL); // Free the buffer. LocalFree( lpMsgBuf ); } } // returns localized, stringized time BOOL FileTimeToLocalTimeString(FILETIME* pftGMT, LPWSTR* ppszTmp) { FILETIME ftLocal; if (FileTimeToLocalFileTime(pftGMT, &ftLocal)) { SYSTEMTIME sysLocal; if (FileTimeToSystemTime( &ftLocal, &sysLocal)) { WCHAR rgTmpDate[128], rgTmpTime[128]; DWORD dwLen; dwLen = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &sysLocal, NULL, rgTmpDate, ARRAYLEN(rgTmpDate)); dwLen += GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &sysLocal, NULL, rgTmpTime, ARRAYLEN(rgTmpTime)); dwLen += sizeof(L" "); *ppszTmp = new WCHAR[dwLen]; if(*ppszTmp == NULL) { return FALSE; } wcscpy(*ppszTmp, rgTmpDate); wcscat(*ppszTmp, L" "); wcscat(*ppszTmp, rgTmpTime); } } return TRUE; } void MyErrorBox(HWND hwndParent, UINT nIDText, UINT nIDCaption, DWORD dwErrorCode) { CString cstrTitle, cstrFormatText, cstrFullText; cstrTitle.LoadString(nIDCaption); cstrFormatText.LoadString(nIDText); WCHAR const *pwszError = NULL; if (dwErrorCode != ERROR_SUCCESS) { pwszError = myGetErrorMessageText(dwErrorCode, TRUE); cstrFullText.Format(cstrFormatText, pwszError); // Free the buffer if (NULL != pwszError) { LocalFree(const_cast(pwszError)); } } ::MessageBoxW(hwndParent, cstrFullText, cstrTitle, MB_OK | MB_ICONERROR); } BOOL MyGetOIDInfo(LPWSTR string, DWORD stringSize, LPSTR pszObjId) { PCCRYPT_OID_INFO pOIDInfo; pOIDInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY, pszObjId, 0); if (pOIDInfo != NULL) { if (wcslen(pOIDInfo->pwszName)+1 <= stringSize) { wcscpy(string, pOIDInfo->pwszName); } else { return FALSE; } } else { return (MultiByteToWideChar(CP_ACP, 0, pszObjId, -1, string, stringSize) != 0); } return TRUE; } BOOL MyGetEnhancedKeyUsages(HCERTTYPE hCertType, CString **aszUsages, DWORD *cUsages, BOOL *pfCritical, BOOL fGetOIDSNotNames) { PCERT_EXTENSIONS pCertExtensions; CERT_ENHKEY_USAGE *pehku; DWORD cb = 0; WCHAR OIDName[256]; unsigned int i; LPWSTR pwszOID; HRESULT hr; CSASSERT(cUsages); if(aszUsages) *aszUsages = NULL; hr = CAGetCertTypeExtensions(hCertType, &pCertExtensions); if(hr != S_OK) { return FALSE; } i = 0; while ((icExtension) && (strcmp(pCertExtensions->rgExtension[i].pszObjId, szOID_ENHANCED_KEY_USAGE) != 0)) { i++; } if (i >= pCertExtensions->cExtension) { CAFreeCertTypeExtensions(hCertType, pCertExtensions); return FALSE; } if (pfCritical != NULL) { *pfCritical = pCertExtensions->rgExtension[i].fCritical; } CryptDecodeObject( X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, pCertExtensions->rgExtension[i].Value.pbData, pCertExtensions->rgExtension[i].Value.cbData, 0, NULL, &cb); if (NULL == (pehku = (CERT_ENHKEY_USAGE *) new(BYTE[cb]))) { CAFreeCertTypeExtensions(hCertType, pCertExtensions); return FALSE; } CryptDecodeObject( X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, pCertExtensions->rgExtension[i].Value.pbData, pCertExtensions->rgExtension[i].Value.cbData, 0, pehku, &cb); if(!aszUsages) { // only retrieving the usage count *cUsages = pehku->cUsageIdentifier; } else { // retrieving usage strings, count better match CSASSERT(*cUsages == pehku->cUsageIdentifier); for (i=0; icUsageIdentifier; i++) { if (fGetOIDSNotNames) { pwszOID = MyMkWStr(pehku->rgpszUsageIdentifier[i]); aszUsages[i]= new CString(pwszOID); delete(pwszOID); if(aszUsages[i] == NULL) { return FALSE; } } else { MyGetOIDInfo(OIDName, sizeof(OIDName)/sizeof(WCHAR), pehku->rgpszUsageIdentifier[i]); aszUsages[i]= new CString(OIDName); if(aszUsages[i] == NULL) { return FALSE; } } } } delete[](pehku); CAFreeCertTypeExtensions(hCertType, pCertExtensions); return TRUE; } BOOL GetIntendedUsagesString(HCERTTYPE hCertType, CString *pUsageString) { CString **aszUsages = NULL; DWORD cNumUsages = 0; unsigned int i; if(!MyGetEnhancedKeyUsages(hCertType, NULL, &cNumUsages, NULL, FALSE)) return FALSE; if(0==cNumUsages) { *pUsageString = ""; return TRUE; } aszUsages = new CString*[cNumUsages]; if(!aszUsages) return FALSE; if(!MyGetEnhancedKeyUsages(hCertType, aszUsages, &cNumUsages, NULL, FALSE)) { delete[] aszUsages; return FALSE; } *pUsageString = ""; for (i=0; icExtension) && (strcmp(pCertExtensions->rgExtension[i].pszObjId, szOID_KEY_USAGE) != 0)) { i++; } if (i >= pCertExtensions->cExtension) { CAFreeCertTypeExtensions(hCertType, pCertExtensions); return FALSE; } if (pfPublicKeyUsageCritical != NULL) { *pfPublicKeyUsageCritical = pCertExtensions->rgExtension[i].fCritical; } CryptDecodeObject( X509_ASN_ENCODING, X509_KEY_USAGE, pCertExtensions->rgExtension[i].Value.pbData, pCertExtensions->rgExtension[i].Value.cbData, 0, NULL, &cb); if (NULL == (*ppBitBlob = (CRYPT_BIT_BLOB *) new(BYTE[cb]))) { CAFreeCertTypeExtensions(hCertType, pCertExtensions); return FALSE; } CryptDecodeObject( X509_ASN_ENCODING, X509_KEY_USAGE, pCertExtensions->rgExtension[i].Value.pbData, pCertExtensions->rgExtension[i].Value.cbData, 0, *ppBitBlob, &cb); CAFreeCertTypeExtensions(hCertType, pCertExtensions); return TRUE; } BOOL MyGetBasicConstraintInfo(HCERTTYPE hCertType, BOOL *pfCA, BOOL *pfPathLenConstraint, DWORD *pdwPathLenConstraint) { PCERT_EXTENSIONS pCertExtensions; DWORD cb = sizeof(CERT_BASIC_CONSTRAINTS2_INFO); unsigned int i; CERT_BASIC_CONSTRAINTS2_INFO basicConstraintsInfo; HRESULT hr; hr = CAGetCertTypeExtensions(hCertType, &pCertExtensions); if(hr != S_OK) { return FALSE; } i = 0; while ((icExtension) && (strcmp(pCertExtensions->rgExtension[i].pszObjId, szOID_BASIC_CONSTRAINTS2) != 0)) { i++; } if (i >= pCertExtensions->cExtension) { CAFreeCertTypeExtensions(hCertType, pCertExtensions); return FALSE; } CryptDecodeObject( X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, pCertExtensions->rgExtension[i].Value.pbData, pCertExtensions->rgExtension[i].Value.cbData, 0, &basicConstraintsInfo, &cb); *pfCA = basicConstraintsInfo.fCA; *pfPathLenConstraint = basicConstraintsInfo.fPathLenConstraint; *pdwPathLenConstraint = basicConstraintsInfo.dwPathLenConstraint; CAFreeCertTypeExtensions(hCertType, pCertExtensions); return TRUE; } LPSTR MyMkMBStr(LPCWSTR pwsz) { int cb; LPSTR psz; if (pwsz == NULL) { return NULL; } cb = WideCharToMultiByte( 0, 0, pwsz, -1, NULL, 0, NULL, NULL); if (NULL == (psz = (LPSTR) new BYTE[cb])) { return NULL; } cb = WideCharToMultiByte( 0, 0, pwsz, -1, psz, cb, NULL, NULL); if (cb==0) { delete [] psz; return NULL; } return(psz); } LPWSTR MyMkWStr(LPCSTR psz) { int cWChars; LPWSTR pwsz; if (psz == NULL) { return NULL; } cWChars = MultiByteToWideChar( 0, 0, psz, -1, NULL, 0); if (NULL == (pwsz = (LPWSTR) new BYTE[cWChars * sizeof(WCHAR)] )) { return NULL; } cWChars = MultiByteToWideChar( 0, 0, psz, -1, pwsz, cWChars); if (cWChars == 0) { delete [] pwsz; return NULL; } return(pwsz); } BOOL IsCerttypeEditingAllowed() { DWORD lResult; HKEY hKey = NULL; DWORD dwType; DWORD dwEnabled = 0; DWORD cbEnabled = sizeof(dwEnabled); lResult = RegOpenKeyEx (HKEY_CURRENT_USER, L"Software\\Microsoft\\Cryptography\\CertificateTemplateCache", 0, KEY_READ, &hKey); if (lResult == ERROR_SUCCESS) { lResult = RegQueryValueEx(hKey, REGSZ_ENABLE_CERTTYPE_EDITING, NULL, &dwType, (PBYTE)&dwEnabled, &cbEnabled); if(lResult == ERROR_SUCCESS) { if(dwType != REG_DWORD) { dwEnabled = 0; } } RegCloseKey (hKey); } return (dwEnabled != 0); } HRESULT RetrieveCATemplateListFromCA( HCAINFO hCAInfo, CTemplateList& list) { HRESULT hr = S_OK; LPWSTR *ppwszDNSName = NULL; LPWSTR *ppwszAuthority = NULL; ICertAdminD2 *pAdminD2 = NULL; DWORD dwServerVersion = 2; CERTTRANSBLOB ctbSD; ZeroMemory(&ctbSD, sizeof(CERTTRANSBLOB)); hr = CAGetCAProperty(hCAInfo, CA_PROP_DNSNAME, &ppwszDNSName); _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_DNSNAME"); hr = CAGetCAProperty(hCAInfo, CA_PROP_NAME, &ppwszAuthority); _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_DNSNAME"); ASSERT(ppwszDNSName[0]); hr = myOpenAdminDComConnection( ppwszDNSName[0], NULL, NULL, &dwServerVersion, &pAdminD2); _JumpIfError(hr, error, "myOpenAdminDComConnection"); if (2 > dwServerVersion) { hr = RPC_E_VERSION_MISMATCH; _JumpError(hr, error, "old server"); } CSASSERT(ppwszAuthority[0]); hr = pAdminD2->GetCAProperty( ppwszAuthority[0], CR_PROP_TEMPLATES, 0, PROPTYPE_STRING, &ctbSD); _JumpIfErrorStr(hr, error, "ICertAdminD2::GetCAProperty CR_PROP_TEMPLATES", ppwszDNSName[0]); hr = list.Unmarshal(ctbSD.pb, ctbSD.cb); _JumpIfError(hr, error, "CTemplateList::Unmarshal"); error: if(ppwszDNSName) CAFreeCAProperty(hCAInfo, ppwszDNSName); if(ppwszAuthority) CAFreeCAProperty(hCAInfo, ppwszAuthority); if(pAdminD2) pAdminD2->Release(); return hr; } HRESULT RetrieveCATemplateListFromDS( HCAINFO hCAInfo, CTemplateList& list) { HRESULT hr = S_OK; HCERTTYPE hCertTypeNext, hCertTypePrev; hr = CAEnumCertTypesForCA( hCAInfo, CT_ENUM_MACHINE_TYPES | CT_ENUM_USER_TYPES | CT_FLAG_NO_CACHE_LOOKUP, &hCertTypeNext); _JumpIfError(hr, error, "CAEnumCertTypesForCA"); while (hCertTypeNext != NULL) { hr = list.AddTemplateInfo(hCertTypeNext); _JumpIfError(hr, error, "CTemplateList::AddTemplate"); hCertTypePrev = hCertTypeNext; hr = CAEnumNextCertType(hCertTypePrev, &hCertTypeNext); _JumpIfError(hr, error, "CAEnumNextCertType"); } error: return hr; } HRESULT RetrieveCATemplateList( HCAINFO hCAInfo, CTemplateList& list) { HRESULT hr = S_OK; hr = RetrieveCATemplateListFromCA(hCAInfo, list); if(S_OK != hr) { // if failed to retrieve from the CA for any reason, try // fetching from DS hr = RetrieveCATemplateListFromDS(hCAInfo, list); } return hr; } HRESULT UpdateCATemplateListToDS( HCAINFO hCAInfo, const CTemplateList& list) { HRESULT hr = S_OK; hr = CAUpdateCA(hCAInfo); _JumpIfError(hr, error, "CAUpdateCA"); error: return hr; } HRESULT UpdateCATemplateListToCA( HCAINFO hCAInfo, const CTemplateList& list) { HRESULT hr = S_OK; LPWSTR *ppwszDNSName = NULL; LPWSTR *ppwszAuthority = NULL; ICertAdminD2 *pAdminD2 = NULL; DWORD dwServerVersion = 2; CERTTRANSBLOB ctbSD; ZeroMemory(&ctbSD, sizeof(CERTTRANSBLOB)); hr = CAGetCAProperty(hCAInfo, CA_PROP_DNSNAME, &ppwszDNSName); _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_DNSNAME"); hr = CAGetCAProperty(hCAInfo, CA_PROP_NAME, &ppwszAuthority); _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_DNSNAME"); ASSERT(ppwszDNSName[0]); hr = myOpenAdminDComConnection( ppwszDNSName[0], NULL, NULL, &dwServerVersion, &pAdminD2); _JumpIfError(hr, error, "myOpenAdminDComConnection"); if (2 > dwServerVersion) { hr = RPC_E_VERSION_MISMATCH; _JumpError(hr, error, "old server"); } CSASSERT(ppwszAuthority[0]); hr = list.Marshal(ctbSD.pb, ctbSD.cb); _JumpIfError(hr, error, "CTemplateList::Marshal"); CSASSERT(S_OK==list.ValidateMarshalBuffer(ctbSD.pb, ctbSD.cb)); hr = pAdminD2->SetCAProperty( ppwszAuthority[0], CR_PROP_TEMPLATES, 0, PROPTYPE_STRING, &ctbSD); _JumpIfErrorStr(hr, error, "ICertAdminD2::SetCAProperty CR_PROP_TEMPLATES", ppwszDNSName[0]); error: if(ppwszDNSName) CAFreeCAProperty(hCAInfo, ppwszDNSName); if(ppwszAuthority) CAFreeCAProperty(hCAInfo, ppwszAuthority); if(pAdminD2) pAdminD2->Release(); if(ctbSD.pb) MIDL_user_free(ctbSD.pb); return hr; } HRESULT UpdateCATemplateList( HCAINFO hCAInfo, const CTemplateList& list) { HRESULT hr = UpdateCATemplateListToCA(hCAInfo, list); if(S_OK != hr) { // if failed to update through the CA for any reason, try // writing directly to DS hr = UpdateCATemplateListToDS(hCAInfo, list); } return hr; } HRESULT AddToCATemplateList( HCAINFO hCAInfo, CTemplateList& list, HCERTTYPE hCertType) { HRESULT hr = S_OK; hr = CAAddCACertificateType(hCAInfo, hCertType); _JumpIfError(hr, error, "CAAddCACertificateType"); hr = list.AddTemplateInfo(hCertType); _JumpIfError(hr, error, "CTemplateList::AddTemplateInfo HCERTTYPE"); error: return hr; } HRESULT RemoveFromCATemplateList( HCAINFO hCAInfo, CTemplateList& list, HCERTTYPE hCertType) { HRESULT hr = S_OK; hr = CARemoveCACertificateType(hCAInfo, hCertType); _JumpIfError(hr, error, "CARemoveCACertificateType"); hr = list.RemoveTemplateInfo(hCertType); _JumpIfError(hr, error, "CTemplateList::RemoveTemplateInfo HCERTTYPE"); error: return hr; }