//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 2000 // // File: tcainfo.cpp // // This code contains tests to exercise the functionality of the certcli // "CA" interfaces, detailed in certca.h // //-------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include #define __dwFILE__ __dwFILE_CERTUTIL_TCAINFO_CPP__ #define wszREGADMINALIAS L"Software\\Policies\\Microsoft\\CertificateTemplates\\Aliases\\Administrator" #define wszREGPOLICYHISTORY L"Software\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History" WCHAR const g_wszSep[] = L"================================================================"; #define TE_USER 0 #define TE_MACHINE 1 // // CheckSupportedCertTypes() // // This function checks the certificate types enumerated through the property // API, and compares them to the types enumerated by the cert type API. // // Params: // hCA - IN Handle to CA // papwszProperty - IN String array w/ present values // // Returns: // HRESULT from CAINFO calls. // HRESULT CheckSupportedCertTypes( IN HCAINFO hCA, IN WCHAR const * const *papwszTemplate) { HRESULT hr; DWORD dwCT; DWORD dwCT2; DWORD cTemplate; DWORD i; DWORD *rgIndex = NULL; HCERTTYPE hCT = NULL; WCHAR **papwszCTFriendlyName = NULL; WCHAR **papwszCTCN = NULL; BOOL fFirst; // First, find out how many cert types there are according to // value returned from property array... for (cTemplate = 0; NULL != papwszTemplate[cTemplate]; cTemplate++) ; // alloc bool array for testing rgIndex = (DWORD *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof(DWORD) * cTemplate); if (NULL == rgIndex) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } memset(rgIndex, 0xff, sizeof(DWORD) * cTemplate); CSASSERT(MAXDWORD == rgIndex[0]); // Let's try out the enumeration of cert types on the CA object, // just as a sanity check... we'll then compare them against // the values stored in the property array. hr = CAEnumCertTypesForCA( hCA, CT_ENUM_USER_TYPES | CT_ENUM_MACHINE_TYPES, &hCT); if (S_OK != hr) { cuPrintAPIError(L"CAEnumCertTypesForCA", hr); _JumpError(hr, error, "CAEnumCertTypesForCA"); } if (NULL == hCT) // no cert types for CA { // Should be at least one, according to property enumeration if (NULL != papwszTemplate[0]) { wprintf(myLoadResourceString(IDS_NO_CT_BUT_EXISTS)); wprintf(wszNewLine); hr = CRYPT_E_NOT_FOUND; _JumpError(hr, error, "CAEnumCertTypesForCA"); } wprintf(myLoadResourceString(IDS_NO_CT_FOR_CA)); wprintf(wszNewLine); } dwCT = 0; dwCT2 = CACountCertTypes(hCT); // Enumerate remaining certificate types for CA while (NULL != hCT) { HCERTTYPE hPrevCT; // Mark bool... hr = CAGetCertTypeProperty( hCT, CERTTYPE_PROP_FRIENDLY_NAME, &papwszCTFriendlyName); if (S_OK != hr) { cuPrintAPIError(L"CAGetCertTypeProperty", hr); _JumpError(hr, error, "CAGetCertTypeProperty"); } hr = CAGetCertTypeProperty( hCT, CERTTYPE_PROP_CN, &papwszCTCN); if (S_OK != hr) { cuPrintAPIError(L"CAGetCertTypeProperty", hr); _JumpError(hr, error, "CAGetCertTypeProperty"); } wprintf( L"%ws[%u]: %ws (%ws)", myLoadResourceString(IDS_CERT_TYPE), dwCT, NULL != papwszCTCN? papwszCTCN[0] : NULL, NULL != papwszCTFriendlyName? papwszCTFriendlyName[0] : NULL); hr = CACertTypeAccessCheck(hCT, NULL); if (S_OK != hr) { if (hr != E_ACCESSDENIED) { wprintf(wszNewLine); cuPrintAPIError(L"CACertTypeAccessCheck", hr); _JumpError(hr, error, "CACertTypeAccessCheck"); } wprintf(L" -- %ws", myLoadResourceString(IDS_NO_ACCESS)); hr = S_OK; } wprintf(wszNewLine); if (NULL != papwszCTCN) { for (i = 0; i < cTemplate; i++) { if (0 == mylstrcmpiL(papwszTemplate[i], papwszCTCN[0])) { rgIndex[i] = dwCT; break; } } CAFreeCertTypeProperty(hCT, papwszCTCN); papwszCTCN = NULL; } if (NULL != papwszCTFriendlyName) { CAFreeCertTypeProperty(hCT, papwszCTFriendlyName); papwszCTFriendlyName = NULL; } dwCT++; // CACountCertTypes checking // set up enumeration object hPrevCT = hCT; hCT = NULL; hr = CAEnumNextCertType(hPrevCT, &hCT); CACloseCertType(hPrevCT); hPrevCT = hCT; if (S_OK != hr) { cuPrintAPIError(L"CAEnumNextCertType", hr); _JumpError(hr, error, "CAEnumNextCertType"); } if (NULL == hCT) { break; } } wprintf(L"%ws: %u\n", myLoadResourceString(IDS_CERT_TYPES), dwCT); fFirst = TRUE; for (i = 0; i < cTemplate; i++) { //wprintf(L"ct[%u]: %ws\n", i, papwszTemplate[i]); if (MAXDWORD == rgIndex[i]) { if (fFirst) { wprintf(wszNewLine); fFirst = FALSE; } wprintf( L"%ws: %ws\n", papwszTemplate[i], myLoadResourceString(IDS_CERT_TYPE_MISSING)); } } hr = S_OK; error: if (NULL != rgIndex) { LocalFree(rgIndex); } if (NULL != papwszCTFriendlyName) { CAFreeCertTypeProperty(hCT, papwszCTFriendlyName); } if (NULL != papwszCTCN) { CAFreeCertTypeProperty(hCT, papwszCTCN); } if (NULL != hCT) { CACloseCertType(hCT); } return(hr); } // // ShowExpirationTime() // // This function simply displays the expiration time. // // Parameters: // // hCA - IN Handle to CA // // Returns: // // HRESULT from APIs, or S_OK // HRESULT ShowExpirationTime( IN HCAINFO hCA) { HRESULT hr; DWORD dwExp; DWORD dwUnits; DWORD ardwUnits[] = {CA_UNITS_DAYS, CA_UNITS_WEEKS, CA_UNITS_MONTHS, CA_UNITS_YEARS}; WCHAR *arwszDisplay[] = {L"Days", L"Weeks", L"Months", L"Years"}; // Retrieve and display expiration data hr = CAGetCAExpiration(hCA, &dwExp, &dwUnits); if (S_OK != hr) { cuPrintAPIError(L"CAGetCAExpiration", hr); _JumpError(hr, error, "CAGetCAExpiration"); } for (DWORD i = 0; i < ARRAYSIZE(ardwUnits); i++) { if (dwUnits == ardwUnits[i]) { wprintf(wszNewLine); wprintf(myLoadResourceString(IDS_FORMAT_CA_EXPIRATION), arwszDisplay[i], dwExp); break; } } wprintf(wszNewLine); wprintf(wszNewLine); error: return(hr); } // // DisplaySupportedCertTypes() // // Returns: // // hr from CAINFO API, fills array of cert types, for use in -addct flag // HRESULT DisplaySupportedCertTypes( IN HCAINFO hCA) { HRESULT hr; WCHAR **papwszCertTypes = NULL; DWORD i; hr = CAGetCAProperty(hCA, CA_PROP_CERT_TYPES, &papwszCertTypes); _JumpIfErrorStr(hr, error, "CAGetCAProperty", CA_PROP_CERT_TYPES); wprintf(myLoadResourceString(IDS_SUPPORTED_TEMPLATE)); wprintf(wszNewLine); // Prepare certificate types in tab delimited format if (NULL == papwszCertTypes || NULL == papwszCertTypes[0]) { wprintf(myLoadResourceString(IDS_NO_SUPPORTED_TEMPLATE)); wprintf(wszNewLine); hr = S_FALSE; _JumpErrorStr(hr, error, "CAGetCAProperty", CA_PROP_CERT_TYPES); } if (g_fVerbose) { for (i = 0; NULL != papwszCertTypes[i]; i++) { wprintf(L"%ws\n", papwszCertTypes[i]); } wprintf(L":::::::::::::::::::::::::::::::::::\n"); } // This compares the values returned from the property enumeration // to the values returned by enumerating the cert types hr = CheckSupportedCertTypes(hCA, papwszCertTypes); _JumpIfError(hr, error, "CheckSupportedCertTypes"); error: if (NULL != papwszCertTypes) { HRESULT hr2 = CAFreeCAProperty(hCA, papwszCertTypes); if (S_OK != hr2) { if (S_OK == hr) { hr = hr2; } cuPrintAPIError(L"CAFreeCAProperty", hr2); _PrintError(hr2, "CAFreeCAProperty"); } } return(hr); } HRESULT PingCA( IN WCHAR const *pwszCAName, IN WCHAR const *pwszServer, OUT ENUM_CATYPES *pCAType) { HRESULT hr; WCHAR *pwszConfig = NULL; CAINFO *pCAInfo = NULL; hr = myFormConfigString(pwszServer, pwszCAName, &pwszConfig); _JumpIfError(hr, error, "myFormConfigString"); hr = cuPingCertSrv(pwszConfig, &pCAInfo); _JumpIfError(hr, error, "cuPingCertSrv"); *pCAType = pCAInfo->CAType; error: if (NULL != pCAInfo) { LocalFree(pCAInfo); } if (NULL != pwszConfig) { LocalFree(pwszConfig); } return(hr); } HRESULT DisplayCAProperty( IN HCAINFO hCA, IN WCHAR const *pwszProperty, IN UINT idsFail, IN UINT idsDisplay, IN BOOL fIgnoreEmpty, OPTIONAL OUT WCHAR **ppwszOut) { HRESULT hr; WCHAR **papwszProperty = NULL; WCHAR const *pwsz; if (NULL != ppwszOut) { *ppwszOut = NULL; } hr = CAGetCAProperty(hCA, pwszProperty, &papwszProperty); if (S_OK != hr) { wprintf(myLoadResourceString(idsFail), hr); wprintf(wszNewLine); _JumpError(hr, error, "CAGetCAProperty"); } if (NULL != papwszProperty && NULL != papwszProperty[0]) { pwsz = papwszProperty[0]; } else { if (fIgnoreEmpty) { hr = S_OK; goto error; } pwsz = L""; } wprintf(wszNewLine); wprintf(myLoadResourceString(idsDisplay), pwsz); wprintf(wszNewLine); if (NULL != ppwszOut) { hr = myDupString(pwsz, ppwszOut); _JumpIfError(hr, error, "myDupString"); } hr = S_OK; error: if (NULL != papwszProperty) { HRESULT hr2 = CAFreeCAProperty(hCA, papwszProperty); if (S_OK != hr2) { if (S_OK == hr) { hr = hr2; } cuPrintAPIError(L"CAFreeCAProperty", hr2); _PrintError(hr2, "CAFreeCAProperty"); } } return(hr); } #define CASMF_ONLINE 0x00000001 class CASummary { public: CASummary() { m_pwszMachine = NULL; m_pwszCA = NULL; m_CAType = ENUM_UNKNOWN_CA; m_dwFlags = 0; m_hrCACert = S_OK; m_hrAccess = S_OK; } ~CASummary() { if (NULL != m_pwszMachine) { LocalFree(m_pwszMachine); } if (NULL != m_pwszCA) { LocalFree(m_pwszCA); } } public: WCHAR *m_pwszMachine; WCHAR *m_pwszCA; ENUM_CATYPES m_CAType; DWORD m_dwFlags; HRESULT m_hrCACert; HRESULT m_hrAccess; }; HRESULT DisplayCAInfo( IN HCAINFO hCA, IN BOOL fPing, IN OUT CASummary *pCA) { HRESULT hr; CERT_CONTEXT const *pccCA = NULL; DWORD VerifyState; wprintf(g_wszSep); // CA Name hr = DisplayCAProperty( hCA, CA_PROP_NAME, IDS_FORMAT_CA_NAME_PROP_FAILED, IDS_FORMAT_CA_NAME_LIST, FALSE, &pCA->m_pwszCA); _JumpIfErrorStr(hr, error, "DisplayCAProperty", CA_PROP_NAME); // Machine name for CA hr = DisplayCAProperty( hCA, CA_PROP_DNSNAME, IDS_FORMAT_CA_DNS_PROP_FAILED, IDS_FORMAT_CA_MACHINE_LIST, FALSE, &pCA->m_pwszMachine); _JumpIfErrorStr(hr, error, "DisplayCAProperty", CA_PROP_DNSNAME); // DN of CA Object on DS hr = DisplayCAProperty( hCA, CA_PROP_DSLOCATION, IDS_FORMAT_CA_NAME_PROP_FAILED, IDS_FORMAT_CA_DS_LIST, FALSE, NULL); _JumpIfErrorStr(hr, error, "DisplayCAProperty", CA_PROP_DSLOCATION); // DN of CA certificate hr = DisplayCAProperty( hCA, CA_PROP_CERT_DN, IDS_FORMAT_CERT_DN_PROP_FAILED, IDS_FORMAT_CERT_DN_LIST, FALSE, NULL); _JumpIfErrorStr(hr, error, "DisplayCAProperty", CA_PROP_DSLOCATION); // Signature algs hr = DisplayCAProperty( hCA, CA_PROP_SIGNATURE_ALGS, IDS_FORMAT_CA_ALG_PROP_FAILED, IDS_FORMAT_CA_ALG_LIST, TRUE, NULL); _JumpIfErrorStr(hr, error, "DisplayCAProperty", CA_PROP_SIGNATURE_ALGS); pCA->m_hrAccess = CAAccessCheck(hCA, NULL); if (S_OK != pCA->m_hrAccess) { _PrintError(pCA->m_hrAccess, "CAAccessCheck"); wprintf(wszNewLine); cuPrintError(0, pCA->m_hrAccess); } // Get the expiration date/time/... for an individual CA hr = ShowExpirationTime(hCA); _JumpIfError(hr, error, "ShowExpirationTime"); if (fPing) { hr = PingCA(pCA->m_pwszCA, pCA->m_pwszMachine, &pCA->m_CAType); _PrintIfError(hr, "PingCA"); if (S_OK == hr) { wprintf(wszNewLine); wprintf(g_wszPad2); cuDisplayCAType(pCA->m_CAType); pCA->m_dwFlags |= CASMF_ONLINE; } } hr = CAGetCACertificate(hCA, &pccCA); _JumpIfError(hr, error, "CAGetCACertificate"); wprintf(wszNewLine); pCA->m_hrCACert = cuVerifyCertContext( pccCA, // pCert NULL, // hStoreCA 0, // cApplicationPolicies 0, // apszApplicationPolicies 0, // cIssuancePolicies 0, // apszIssuancePolicies IsEnterpriseCA(pCA->m_CAType), // fNTAuth &VerifyState); _PrintIfError(pCA->m_hrCACert, "cuVerifyCertContext"); // Cert Types for CA == Multi valued property wprintf(wszNewLine); hr = DisplaySupportedCertTypes(hCA); if (S_FALSE == hr) { hr = S_OK; } _JumpIfError(hr, error, "DisplaySupportedCertTypes"); error: wprintf(wszNewLine); return(hr); } VOID DisplayCASummary( IN CASummary const *pCA) { wprintf(L"%ws\\%ws:\n", pCA->m_pwszMachine, pCA->m_pwszCA); if (ENUM_UNKNOWN_CA != pCA->m_CAType) { wprintf(g_wszPad2); cuDisplayCAType(pCA->m_CAType); } if (S_OK != pCA->m_hrCACert) { wprintf(g_wszPad2); cuPrintError(0, pCA->m_hrCACert); } wprintf( L" %ws\n", myLoadResourceString((CASMF_ONLINE & pCA->m_dwFlags)? IDS_ONLINE : IDS_OFFLINE)); if (S_OK != pCA->m_hrAccess) { wprintf(g_wszPad2); cuPrintError(0, pCA->m_hrAccess); } wprintf(wszNewLine); } // EnumCAs() // // We've got to assume that this works. Enumerates CAs on the DS. // // Returns: // Number of CA's on DS. // HRESULT EnumCAs( IN WCHAR const *pwszDomain, IN DWORD dwFlags, IN BOOL fPing) { HRESULT hr; DWORD i; DWORD cCA; HCAINFO hCA = NULL; CASummary *prgCAList = NULL; // Enumerate all of the CA's on the DS hr = CAEnumFirstCA(pwszDomain, dwFlags, &hCA); if (S_OK != hr) { cuPrintAPIError(L"CAEnumFirstCA", hr); _JumpError(hr, error, "CAEnumFirstCA"); } if (NULL == hCA) { wprintf(myLoadResourceString(IDS_NO_CA_ON_DOMAIN)); wprintf(wszNewLine); hr = CRYPT_E_NOT_FOUND; _JumpError(hr, error, "CAEnumFirstCA"); } // Make sure that the counting function works at this stage. cCA = CACountCAs(hCA); prgCAList = new CASummary[cCA]; if (NULL == prgCAList) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "new"); } for (i = 0; i < cCA; i++) { HCAINFO hNextCA; if (0 != i) { hr = CAEnumNextCA(hCA, &hNextCA); if (S_OK != hr) { cuPrintAPIError(L"CAEnumNextCA", hr); _JumpError(hr, error, "CAEnumNextCA"); } if (NULL == hNextCA) { wprintf( myLoadResourceString(IDS_FORMAT_CAS_ON_DOMAIN), i, pwszDomain); wprintf(wszNewLine); break; } // It is difficult to determine the desired behavior for this API. hr = CACloseCA(hCA); if (S_OK != hr) { cuPrintAPIError(L"CACloseCA", hr); _JumpError(hr, error, "CACloseCA"); } hCA = hNextCA; } hr = DisplayCAInfo(hCA, fPing, &prgCAList[i]); _JumpIfError(hr, error, "DisplayCAInfo"); } // check the count in the enumeration, and verify the results if (cCA != i) { cuPrintAPIError(myLoadResourceString(IDS_CAENUMNEXTCA), cCA); hr = E_FAIL; _JumpError(hr, error, "cCA != i"); } wprintf(g_wszSep); wprintf(wszNewLine); for (i = 0; i < cCA; i++) { DisplayCASummary(&prgCAList[i]); } error: delete [] prgCAList; if (NULL != hCA) { CACloseCA(hCA); } return(hr); } // // TestDFSPath() // // Verifies that the DFS on this machine can access the SYSVOL share // HRESULT TestDFSPath( IN WCHAR const *pwszDFSPath) { HRESULT hr; DWORD dwDate = 0; DWORD dwTime = 0; WIN32_FILE_ATTRIBUTE_DATA sFileData; if (!GetFileAttributesEx( pwszDFSPath, GetFileExInfoStandard, (VOID *) &sFileData)) { hr = myHLastError(); cuPrintAPIError(myLoadResourceString(IDS_NO_DFS), hr); _JumpError(hr, error, "GetFileAttributesEx"); // To do... Add diagnostics here } wprintf(myLoadResourceString(IDS_DFS_DATA_ACCESS)); wprintf(wszNewLine); hr = S_OK; error: return(hr); } // // TestLdapPath() // // This function verifies that LDAP connectivity is still there for a given // ldap URL // HRESULT TestLdapPath( IN WCHAR const *pwszLdapURL) { HRESULT hr; ULONG ldaperr; WCHAR *pwszError = NULL; LDAP *pldapbind = NULL; WCHAR *rgwszSearchAttribute[2] = {L"CN", NULL}; WCHAR *pwszSearchParam = L"(&(objectClass=*))"; LDAPMessage *SearchResult = NULL; WCHAR *pwszTmpUrl = NULL; // Parse URL, and do the search thing. pwszTmpUrl = wcsstr(pwszLdapURL, L"//"); if (NULL == pwszTmpUrl) // not a URL { hr = S_OK; goto error; } pwszTmpUrl += 2; pldapbind = ldap_init(NULL, LDAP_PORT); if (NULL == pldapbind) { hr = myHLdapLastError(NULL, &pwszError); cuPrintAPIError(L"ldap_init", hr); _JumpError(hr, error, "ldap_init"); } // This gives the IP address of the Cached LDAP DC from binding handle. // Resolve the name? ldaperr = ldap_bind_s(pldapbind, NULL, NULL, LDAP_AUTH_NEGOTIATE); if (ldaperr != LDAP_SUCCESS) { hr = myHLdapError(pldapbind, ldaperr, &pwszError); cuPrintAPIError(L"ldap_bind_s", hr); _JumpError(hr, error, "ldap_bind_s"); } wprintf( L"%ws: %hs\n", myLoadResourceString(IDS_CACHED_LDAP_DC), pldapbind->ld_host); ldaperr = ldap_search_s( pldapbind, pwszTmpUrl, LDAP_SCOPE_SUBTREE, pwszSearchParam, rgwszSearchAttribute, 0, &SearchResult); if (ldaperr != LDAP_SUCCESS) { // we can't be 100% sure that this attribute is on the objec // for example, user UPN, so don't log to event log hr = myHLdapError(pldapbind, ldaperr, &pwszError); cuPrintAPIError(L"ldap_search_s", hr); _JumpError(hr, error, "ldap_search_s"); } if (0 == ldap_count_entries(pldapbind, SearchResult)) { wprintf(myLoadResourceString(IDS_NO_ENTRY_IN_PING)); wprintf(wszNewLine); hr = CRYPT_E_NOT_FOUND; _JumpError(hr, error, "ldap_search_s"); } hr = S_OK; error: if (NULL != pwszError) { wprintf(L"%ws\n", pwszError); LocalFree(pwszError); } if (NULL != SearchResult) { ldap_msgfree(SearchResult); } if (NULL != pldapbind) { ldap_unbind(pldapbind); } return(hr); } // // DisplayHistoryData() // // This function takes a key name, hkey, and value, and prints the value string. // #define wszREGDISPLAYNAME L"DisplayName" #define wszREGGPONAME L"GPOName" #define wszREGDSPATH L"DSPath" #define wszREGFILESYSPATH L"FileSysPath" HRESULT DisplayHistoryData( IN WCHAR const *pwszKeyName, IN WCHAR const *pwszSubKeyName, IN HKEY hKeyPolicy) { HRESULT hr; HRESULT hr2; HKEY hKeyNew = NULL; WCHAR buff[512]; DWORD cwc; DWORD dwType; // Get #'d history key handle hr = RegOpenKeyEx( hKeyPolicy, pwszSubKeyName, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &hKeyNew); if (S_OK != hr) { cuPrintAPIError(L"RegOpenKeyEx", hr); _JumpErrorStr(hr, error, "RegOpenKeyEx", pwszSubKeyName); } // Get GPO Values cwc = ARRAYSIZE(buff); hr = RegQueryValueEx( hKeyNew, wszREGDISPLAYNAME, 0, &dwType, (BYTE *) buff, &cwc); if (S_OK != hr) { cuPrintAPIError(L"RegQueryValueEx", hr); _JumpErrorStr(hr, error, "RegQueryValueEx", wszREGDISPLAYNAME); } wprintf(myLoadResourceString(IDS_KEY_COLON)); wprintf(L" %ws\\%ws\n", pwszKeyName, pwszSubKeyName); wprintf(myLoadResourceString(IDS_DISPLAYNAME_COLON)); wprintf(L" %ws\n", buff); cwc = ARRAYSIZE(buff); hr = RegQueryValueEx( hKeyNew, wszREGGPONAME, 0, &dwType, (BYTE *) buff, &cwc); if (S_OK != hr) { cuPrintAPIError(L"RegQueryValueEx", hr); _JumpErrorStr(hr, error, "RegQueryValueEx", wszREGGPONAME); } wprintf(myLoadResourceString(IDS_FORMAT_GPO_NAME), buff); wprintf(wszNewLine); // See if LDAP can hit this policy cwc = ARRAYSIZE(buff); hr = RegQueryValueEx( hKeyNew, wszREGDSPATH, 0, &dwType, (BYTE *) buff, &cwc); if (hr == S_OK) { wprintf(L"%ws\n", buff); hr = TestLdapPath(buff); _PrintIfError(hr, "TestLdapPath"); } else if (hr == ERROR_FILE_NOT_FOUND) { wprintf(myLoadResourceString(IDS_NO_DSPATH)); wprintf(wszNewLine); hr = S_OK; } else { wprintf(myLoadResourceString(IDS_FORMAT_REG_QUERY_VALUE_FAILED), hr); wprintf(wszNewLine); _JumpErrorStr(hr, error, "RegQueryValueEx", wszREGDSPATH); } // See if DFS can get the data.. cwc = ARRAYSIZE(buff); hr2 = RegQueryValueEx( hKeyNew, wszREGFILESYSPATH, 0, &dwType, (BYTE *) buff, &cwc); if (hr2 == S_OK) { wprintf(L"%ws\n", buff); hr2 = TestDFSPath(buff); _PrintIfErrorStr(hr2, "TestDFSPath", buff); } else if (hr2 == ERROR_FILE_NOT_FOUND) { wprintf(myLoadResourceString(IDS_NO_FILE_SYS_PATH)); wprintf(wszNewLine); hr2 = S_OK; } else { wprintf(myLoadResourceString(IDS_FORMAT_REG_QUERY_VALUE_FAILED), hr2); wprintf(wszNewLine); if (S_OK == hr) { hr = hr2; } _JumpErrorStr(hr2, error, "RegQueryValueEx", wszREGFILESYSPATH); } if (S_OK == hr) { hr = hr2; } error: wprintf(wszNewLine); if (NULL != hKeyNew) { RegCloseKey(hKeyNew); } return(hr); } // // ResultFree() // // Frees results copied from LDAP search // VOID ResultFree( IN OUT WCHAR **rgwszRes) { DWORD i = 0; if (NULL != rgwszRes) { while (NULL != rgwszRes[i]) { LocalFree(rgwszRes[i]); i++; } LocalFree(rgwszRes); } } HRESULT ResultAlloc( IN WCHAR const * const *rgpwszLdapRes, OUT WCHAR ***prgpwszOut) { HRESULT hr; DWORD cValue; DWORD i; WCHAR **rgpwszOut = NULL; for (cValue = 0; NULL != rgpwszLdapRes[cValue]; cValue++) ; rgpwszOut = (WCHAR **) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, (cValue + 1) * sizeof(WCHAR *)); if (NULL == rgpwszOut) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } for (i = 0; i < cValue; i++) { hr = myDupString(rgpwszLdapRes[i], &rgpwszOut[i]); _JumpIfError(hr, error, "myDupString"); } rgpwszOut[i] = NULL; *prgpwszOut = rgpwszOut; rgpwszOut = NULL; hr = S_OK; error: if (NULL != rgpwszOut) { ResultFree(rgpwszOut); } return(hr); } // // GetPropertyFromDSObject() // // This function calls the DS to get a property of the user or machine object, // mimicing the call made by the CA. // // Params: // // rgwszSearchAttribute - IN NULL Terminated WCHAR *array. Only coded for 1 // value retrieval at a time // // Returns: // // Pointer to string array that must be freed by call to LocalFree(), and // wszDN, if User specified // HRESULT GetPropertyFromDSObject( IN WCHAR **rgwszSearchAttribute, IN BOOL fMachine, OPTIONAL OUT WCHAR **ppwszUserDN, OUT WCHAR ***prgwszDSSearchRes) { HRESULT hr; ULONG ldaperr; WCHAR *pwszError = NULL; LDAP *pldapbind = NULL; WCHAR *pwszEmail = NULL; WCHAR *pwszCNName = NULL; DWORD cwc; WCHAR wszNTLM[MAX_PATH]; WCHAR wszDN[MAX_PATH]; WCHAR *pwszSearchUser = L"(&(objectClass=user)"; WCHAR *pwszSearchComputer = L"(&(objectClass=computer)(cn="; WCHAR wszSearchParam[MAX_PATH]; WCHAR *pwszAttName = NULL; WCHAR **rgwszValues = NULL; LDAPMessage *SearchResult = NULL; LDAPMessage *Attributes = NULL; DWORD dwValCount; *prgwszDSSearchRes = NULL; if (fMachine) { // Get CN cwc = ARRAYSIZE(wszNTLM); if (!GetComputerName(wszNTLM, &cwc)) { hr = myHLastError(); cuPrintAPIError(L"GetComputerName", hr); _JumpError(hr, error, "GetComputerName"); } // Get DN cwc = ARRAYSIZE(wszDN); if (!GetComputerObjectName(NameFullyQualifiedDN, wszDN, &cwc)) { hr = myHLastError(); cuPrintAPIError(L"GetComputerName", hr); _JumpError(hr, error, "GetComputerObjectName"); } pwszCNName = wszNTLM; } else // User { // Get the SAM name.. cwc = ARRAYSIZE(wszNTLM); if (!GetUserNameEx(NameSamCompatible, wszNTLM, &cwc)) { hr = myHLastError(); cuPrintAPIError(L"GetUserNameEx", hr); _JumpError(hr, error, "GetUserNameEx"); } // Parse off user name... pwszCNName = wcschr(wszNTLM, L'\\'); if (NULL == pwszCNName) { pwszCNName = wszNTLM; } else { pwszCNName++; } cwc = ARRAYSIZE(wszDN); if (!TranslateName( wszNTLM, NameSamCompatible, NameFullyQualifiedDN, wszDN, &cwc)) { hr = myHLastError(); cuPrintAPIError(L"TranslateName", hr); _JumpErrorStr(hr, error, "TranslateName", wszNTLM); } } if (!fMachine && NULL != ppwszUserDN) { hr = myDupString(wszDN, ppwszUserDN); _JumpIfError(hr, error, "myDupString"); } // Init LDAP calls pldapbind = ldap_init(NULL, LDAP_PORT); if (NULL == pldapbind) { hr = myHLastError(); cuPrintAPIError(L"ldap_init", hr); _JumpError(hr, error, "ldap_init"); } ldaperr = ldap_bind_s(pldapbind, NULL, NULL, LDAP_AUTH_NEGOTIATE); if (ldaperr != LDAP_SUCCESS) { hr = myHLdapError(pldapbind, ldaperr, &pwszError); cuPrintAPIError(L"ldap_bind_s", hr); _JumpError(hr, error, "ldap_bind_s"); } // Compose search string if (fMachine) { swprintf(wszSearchParam, L"%ws%ws))", pwszSearchComputer, pwszCNName); } else { swprintf(wszSearchParam, L"%ws)", pwszSearchUser); } // Do the search ldaperr = ldap_search_s( pldapbind, wszDN, LDAP_SCOPE_SUBTREE, wszSearchParam, rgwszSearchAttribute, 0, &SearchResult); if (ldaperr != LDAP_SUCCESS) { // we can't be 100% sure that this attribute is on the objec // for example, user UPN, so don't log to event log hr = myHLdapError(pldapbind, ldaperr, &pwszError); cuPrintAPIError(L"ldap_search_s", hr); _JumpError(hr, error, "ldap_search_s"); } if (0 == ldap_count_entries(pldapbind, SearchResult)) { wprintf(myLoadResourceString(IDS_FORMAT_LDAP_NO_ENTRY), rgwszSearchAttribute[0]); wprintf(wszNewLine); hr = CRYPT_E_NOT_FOUND; _JumpError(hr, error, "ldap_search_s"); } // Make assumption that only one value will be returned for a user. Attributes = ldap_first_entry(pldapbind, SearchResult); if (NULL == Attributes) { hr = myHLastError(); cuPrintAPIError(L"ldap_first_entry", hr); _JumpError(hr, error, "ldap_first_entry"); } rgwszValues = ldap_get_values( pldapbind, Attributes, rgwszSearchAttribute[0]); // remember, only one search if (NULL == rgwszValues) { // we can't be 100% sure that this attribute is on the object // for example, user UPN, so don't log to event log // wprintf(L"ldap_get_values failed! %x", hr); hr = S_OK; goto error; } // ok, we've got the required attributes off of the user object.. // Let's return the proper strings, which must be freed by ResultFree() hr = ResultAlloc(rgwszValues, prgwszDSSearchRes); _JumpIfError(hr, error, "ResultAlloc"); error: if (NULL != pwszError) { wprintf(L"%ws\n", pwszError); LocalFree(pwszError); } if (NULL != SearchResult) { ldap_msgfree(SearchResult); } if (NULL != rgwszValues) { ldap_value_free(rgwszValues); } if (NULL != pldapbind) { ldap_unbind(pldapbind); } return(hr); } // // DisplayLMGPRoot() // // This function uses CAPI2 api to enumerate roots in group policy root store // HRESULT DisplayLMGPRoot() { HRESULT hr; HCERTSTORE hStore = NULL; DWORD cCert; CERT_CONTEXT const *pcc = NULL; CERT_CONTEXT const *pccPrev; // Open local machine GP store hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W, 0, NULL, CERT_STORE_OPEN_EXISTING_FLAG | CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY, (VOID const *) wszROOT_CERTSTORE); if (NULL == hStore) { hr = myHLastError(); cuPrintAPIError(L"CertOpenStore", hr); _JumpError(hr, error, "CertOpenStore"); } wprintf(myLoadResourceString(IDS_ROOT_CERT_IN_POLICY)); wprintf(wszNewLine); // Enumerate certificates in store, giving subject, and thumbprint cCert = 0; pccPrev = NULL; while (TRUE) { pcc = CertEnumCertificatesInStore(hStore, pccPrev); if (NULL == pcc) { break; } // Output info wprintf(myLoadResourceString(IDS_FORMAT_CERT_COLON), cCert); wprintf(wszNewLine); hr = cuDumpSerial(g_wszPad2, IDS_SERIAL, &pcc->pCertInfo->SerialNumber); _PrintIfError(hr, "cuDumpSerial"); hr = cuDisplayCertNames(FALSE, g_wszPad2, pcc->pCertInfo); _PrintIfError(hr, "cuDisplayCertNames"); hr = cuDumpCertType(g_wszPad2, pcc->pCertInfo); _PrintIfError2(hr, "cuDumpCertType", CRYPT_E_NOT_FOUND); hr = cuDisplayHash( g_wszPad2, pcc, NULL, CERT_SHA1_HASH_PROP_ID, L"sha1"); _PrintIfError(hr, "cuDisplayHash"); wprintf(wszNewLine); // Prepare for next cert pccPrev = pcc; cCert++; } if (0 == cCert) { wprintf(myLoadResourceString(IDS_NO_ROOT_IN_POLICY)); wprintf(wszNewLine); wprintf(myLoadResourceString(IDS_CHECK_EVENT_LOG)); wprintf(wszNewLine); } hr = S_OK; error: return(hr); } // // DisplayPolicyList() // // This function displays the GPOs applied to a machine / user // HRESULT DisplayPolicyList( IN DWORD dwFlags) { HRESULT hr; HRESULT hr2; HKEY hKeyPolicy = NULL; HKEY hKeyPolicySub = NULL; DWORD iPolicy; DWORD cwc; WCHAR wszKey[512]; WCHAR wszKeySub[512]; WCHAR **rgszValues = NULL; FILETIME ft; // Output switch (dwFlags) { case TE_MACHINE: wprintf(myLoadResourceString(IDS_POLICY_MACHINE)); wprintf(wszNewLine); break; default: wprintf(myLoadResourceString(IDS_POLICY_USER)); wprintf(wszNewLine); break; } // Open history key for enumeration hr = RegOpenKeyEx( (TE_MACHINE & dwFlags)? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, wszREGPOLICYHISTORY, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &hKeyPolicy); if (S_OK != hr) { cuPrintErrorAndString(L"RegOpenKeyEx", 0, hr, wszREGPOLICYHISTORY); wprintf(myLoadResourceString(IDS_POSSIBLE_NO_POLICY)); wprintf(wszNewLine); _PrintErrorStr(hr, "RegOpenKeyEx", wszREGPOLICYHISTORY); if (hr == ERROR_FILE_NOT_FOUND) { hr = S_OK; } goto error; } for (iPolicy = 0; ; iPolicy++) { DWORD iPolicySub; cwc = ARRAYSIZE(wszKey); hr2 = RegEnumKeyEx( hKeyPolicy, iPolicy, wszKey, &cwc, NULL, NULL, NULL, &ft); if (S_OK != hr2) { if (hr2 == ERROR_NO_MORE_ITEMS) { break; } cuPrintAPIError(L"RegEnumKeyEx", hr2); if (S_OK == hr) { hr = hr2; } _JumpError(hr2, error, "RegEnumKeyEx"); } hr2 = RegOpenKeyEx( hKeyPolicy, wszKey, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &hKeyPolicySub); if (S_OK != hr2) { cuPrintAPIError(L"RegOpenKeyEx", hr2); if (S_OK == hr) { hr = hr2; } _JumpErrorStr(hr2, error, "RegOpenKeyEx", wszKey); } for (iPolicySub = 0; ; iPolicySub++) { cwc = ARRAYSIZE(wszKeySub); hr2 = RegEnumKeyEx( hKeyPolicySub, iPolicySub, wszKeySub, &cwc, NULL, NULL, NULL, &ft); if (S_OK != hr2) { if (hr2 == ERROR_NO_MORE_ITEMS) { break; } cuPrintAPIError(L"RegEnumKeyEx", hr2); if (S_OK == hr) { hr = hr2; } _JumpError(hr2, error, "RegEnumKeyEx"); } hr2 = DisplayHistoryData(wszKey, wszKeySub, hKeyPolicySub); _PrintIfError(hr2, "DisplayHistoryData"); if (S_OK == hr) { hr = hr2; } } RegCloseKey(hKeyPolicySub); hKeyPolicySub = NULL; } error: if (NULL != hKeyPolicySub) { RegCloseKey(hKeyPolicySub); } if (NULL != hKeyPolicy) { RegCloseKey(hKeyPolicy); } return(hr); } // // ShowUserAndComputerInfo() // // GetUserName and GetComputerName() // HRESULT ShowUserAndComputerInfo() { HRESULT hr; WCHAR buff[256]; DWORD cwc; cwc = ARRAYSIZE(buff); if (!GetComputerNameEx(ComputerNamePhysicalNetBIOS, buff, &cwc)) { hr = myHLastError(); _PrintError(hr, "GetComputerNameEx"); cuPrintAPIError(L"GetComputerNameEx", hr); } else { wprintf(myLoadResourceString(IDS_FORMAT_COMPUTER_NAME), buff); wprintf(wszNewLine); hr = S_OK; } cwc = ARRAYSIZE(buff); if (!GetUserNameEx(NameSamCompatible, buff, &cwc)) { HRESULT hr2 = myHLastError(); _PrintError(hr, "GetUserNameEx"); cuPrintAPIError(L"GetUserNameEx", hr2); if (S_OK == hr) { hr = hr2; } } else { wprintf(myLoadResourceString(IDS_FORMAT_USER_NAME), buff); wprintf(wszNewLine); wprintf(wszNewLine); } //error: return(hr); } // // Display Client Info // // This function is responsible for printing out the certificate template // alias information, as well as any policies downloaded for an individual // machine. // HRESULT DisplayClientInfo() { HRESULT hr = S_OK; HRESULT hr2; WCHAR **rgwszDSSearchRes = NULL; WCHAR *rgwszSearch[] = { L"mail", NULL }; // Show user and computer name *including domain* hr2 = ShowUserAndComputerInfo(); _PrintIfError(hr2, "ShowUserAndComputerInfo"); if (S_OK == hr) { hr = hr2; } // Then, display all of the policies downloaded hr2 = DisplayPolicyList(TE_USER); _PrintIfError(hr2, "DisplayPolicyList"); if (S_OK == hr) { hr = hr2; } hr2 = DisplayPolicyList(TE_MACHINE); _PrintIfError(hr2, "DisplayPolicyList"); if (S_OK == hr) { hr = hr2; } // Show the root certificates in the LMGP store hr2 = DisplayLMGPRoot(); _PrintIfError(hr2, "DisplayLMGPRoot"); if (S_OK == hr) { hr = hr2; } // Display autoenrollment object(s) #if 0 hr2 = DisplayAutoenrollmentObjects(); _PrintIfError(hr2, "DisplayAutoenrollmentObjects"); if (S_OK == hr) { hr = hr2; } #endif // Verify DC LDAP connectivity // PingDC(); hr2 = GetPropertyFromDSObject(rgwszSearch, FALSE, NULL, &rgwszDSSearchRes); _PrintIfError(hr2, "GetPropertyFromDSObject"); if (S_OK == hr) { hr = hr2; } if (NULL != rgwszDSSearchRes) { ResultFree(rgwszDSSearchRes); } //error: return(hr); } HRESULT verbTCAInfo( IN WCHAR const *pwszOption, OPTIONAL IN WCHAR const *pwszDomain, IN WCHAR const *pwszArg2, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr; BSTR strDomainDN = NULL; BSTR strConfigDN = NULL; LDAP *pld = NULL; if (myIsMinusSignString(pwszDomain)) { hr = DisplayClientInfo(); _JumpIfError(hr, error, "DisplayClientInfo"); } else { DWORD dwFlags = 0; BOOL fForceOld; if (NULL == pwszDomain) { if (NULL != g_pwszDC) { pwszDomain = g_pwszDC; dwFlags |= CA_FLAG_SCOPE_DNS; } else { hr = myLdapOpen(NULL, 0, &pld, &strDomainDN, &strConfigDN); _JumpIfError(hr, error, "myLdapOpen"); pwszDomain = strDomainDN; } } fForceOld = g_fForce; if (g_fForce) { g_fForce--; dwFlags |= CA_FIND_INCLUDE_NON_TEMPLATE_CA | CA_FIND_INCLUDE_UNTRUSTED; } hr = EnumCAs(pwszDomain, dwFlags, TRUE); g_fForce = fForceOld; _JumpIfError(hr, error, "EnumCAs"); } hr = S_OK; error: myLdapClose(pld, strDomainDN, strConfigDN); return(hr); }