2025-04-27 07:49:33 -04:00

1661 lines
35 KiB
C++

//+-------------------------------------------------------------------------
//
// 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 <pch.cpp>
#pragma hdrstop
#include <certca.h>
#include <winldap.h>
#define wszREGADMINALIAS L"Software\\Policies\\Microsoft\\CertificateTemplates\\Aliases\\Administrator"
#define wszREGPOLICYHISTORY L"Software\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History"
#define TE_USER 0
#define TE_MACHINE 1
VOID
cuPrintAPIError(
IN WCHAR const *pwszAPIName,
IN HRESULT hr);
VOID
cuPrintError(
IN WCHAR const *pwszMsg);
VOID
cuPrintAPIError(
IN WCHAR const *pwszAPIName,
IN HRESULT hr)
{
wprintf(myLoadResourceString(IDS_API_RPINT_FAILED), pwszAPIName, hr);
wprintf(wszNewLine);
}
VOID
cuPrintError(
IN WCHAR const *pwszMsg)
{
wprintf(L"%ws\n", pwszMsg);
}
//
// 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 = 1;
DWORD dwCT2 = 0;
DWORD cTemplate;
DWORD i;
BOOL *pfPresent = NULL;
HCERTTYPE hCT = NULL;
HCERTTYPE hPrevCT = NULL;
WCHAR **papwszCTFriendlyName = NULL;
// First, find out how many cert types there are according to
// value returned from property array...
for (cTemplate = 0; NULL != papwszTemplate[cTemplate]; cTemplate++)
;
cTemplate--; // adjust
// alloc bool array for testing
pfPresent = (BOOL *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
sizeof(BOOL) * cTemplate);
if (NULL == pfPresent)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
// 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);
goto error;
}
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);
goto error;
}
wprintf(myLoadResourceString(IDS_NO_CT_FOR_CA));
wprintf(wszNewLine);
}
dwCT2 = CACountCertTypes(hCT);
// Mark bool...
hr = CAGetCertTypeProperty(
hCT,
CERTTYPE_PROP_FRIENDLY_NAME,
&papwszCTFriendlyName);
if (S_OK != hr)
{
cuPrintAPIError(L"CAGetCertTypeProperty", hr);
goto error;
}
wprintf(L"CT #%u: %ws\n", dwCT, papwszCTFriendlyName[0]);
hr = CACertTypeAccessCheck(hCT, NULL);
if (S_OK != hr)
{
if (hr != E_ACCESSDENIED)
{
cuPrintAPIError(L"CACertTypeAccessCheck", hr);
goto error;
}
wprintf(myLoadResourceString(IDS_NO_ACCESS));
wprintf(wszNewLine);
hr = S_OK;
}
for (i = 0; i < cTemplate; i++)
{
if (0 == lstrcmpi(papwszCTFriendlyName[0], papwszTemplate[i]))
{
pfPresent[i] = TRUE;
break;
}
}
if (NULL != papwszCTFriendlyName)
{
CAFreeCertTypeProperty(hCT, papwszCTFriendlyName);
papwszCTFriendlyName = NULL;
}
// Enumerate remaining certificate types for CA
hPrevCT = hCT;
while (NULL != hCT)
{
// set up enumeration object
hCT = NULL;
hr = CAEnumNextCertType(hPrevCT, &hCT);
if (NULL != hPrevCT)
{
CACloseCertType(hPrevCT);
hPrevCT = hCT;
}
if (S_OK != hr)
{
cuPrintAPIError(L"CAEnumNextCertType", hr);
goto error;
}
if (NULL == hCT)
{
wprintf(L"#CTs: %u\n", dwCT);
break;
}
// CACountCertTypes checking
dwCT++;
// Mark bool...
hr = CAGetCertTypeProperty(
hCT,
CERTTYPE_PROP_FRIENDLY_NAME,
&papwszCTFriendlyName);
wprintf(L"CT #%u: %ws\n", dwCT, papwszCTFriendlyName[0]);
hr = CACertTypeAccessCheck(hCT, NULL);
if (S_OK != hr)
{
if (hr != E_ACCESSDENIED)
{
cuPrintAPIError(L"CACertTypeAccessCheck", hr);
goto error;
}
wprintf(myLoadResourceString(IDS_NO_ACCESS));
wprintf(wszNewLine);
hr = S_OK;
}
for (i = 0; i < cTemplate; i++)
{
if (0 == lstrcmpi(papwszCTFriendlyName[0], papwszTemplate[i]))
{
pfPresent[i] = TRUE;
break;
}
}
if (NULL != papwszCTFriendlyName)
{
CAFreeCertTypeProperty(hCT, papwszCTFriendlyName);
papwszCTFriendlyName = NULL;
}
}
error:
if (NULL != papwszCTFriendlyName)
{
CAFreeCertTypeProperty(hCT, papwszCTFriendlyName);
}
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 = S_OK;
HRESULT hrRet = S_OK;
DWORD dwExp;
WCHAR buff[256];
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
wprintf(wszNewLine);
wprintf(myLoadResourceString(IDS_CA_EXPIRATION_DATA));
wprintf(wszNewLine);
for (DWORD i = 0; i < 4; i++)
{
hr = CAGetCAExpiration(hCA, &dwExp, &ardwUnits[i]);
if (S_OK != hr)
{
wprintf(myLoadResourceString(IDS_FORMAT_CA_EXPIRATION_FAILED), arwszDisplay[i], hr);
wprintf(wszNewLine);
hrRet = hr;
}
else
{
wprintf(myLoadResourceString(IDS_FORMAT_CA_EXPIRATION), arwszDisplay[i], dwExp);
wprintf(wszNewLine);
}
}
wprintf(L"#### ####\n");
return(hrRet);
}
//
// DisplaySupportedCertTypes()
//
// Returns:
//
// hr from CAINFO API, fills array of cert types, for use in -addct flag
//
HRESULT
DisplaySupportedCertTypes(
IN HCAINFO hCA,
OUT WCHAR ***ppapwszTemplate)
{
HRESULT hr;
DWORD i;
hr = CAGetCAProperty(hCA, CA_PROP_CERT_TYPES, ppapwszTemplate);
_JumpIfErrorStr(hr, error, "CAGetCAProperty", CA_PROP_CERT_TYPES);
wprintf(myLoadResourceString(IDS_SUPPORTED_TEMPLATE));
wprintf(wszNewLine);
// Prepare certificate types in tab delimited format
if (NULL == *ppapwszTemplate || NULL == **ppapwszTemplate)
{
wprintf(myLoadResourceString(IDS_NO_SUPPORTED_TEMPLATE));
wprintf(wszNewLine);
hr = CRYPT_E_NOT_FOUND;
_JumpErrorStr(hr, error, "CAGetCAProperty", CA_PROP_CERT_TYPES);
}
for (i = 0; NULL != (*ppapwszTemplate)[i]; i++)
{
wprintf(L"%ws\n", (*ppapwszTemplate)[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, *ppapwszTemplate);
_JumpIfError(hr, error, "CheckSupportedCertTypes");
error:
return(hr);
}
HRESULT
PingCA(
IN WCHAR const *pwszCAName,
IN WCHAR const *pwszServer)
{
HRESULT hr;
WCHAR *pwszConfig = NULL;
hr = myFormConfigString(pwszServer, pwszCAName, &pwszConfig);
_JumpIfError(hr, error, "myFormConfigString");
hr = cuPingCertSrv(pwszConfig);
_JumpIfError(hr, error, "cuPingCertSrv");
error:
if (NULL != pwszConfig)
{
LocalFree(pwszConfig);
}
return(hr);
}
HRESULT
DisplayCAInfo(
IN HCAINFO hCA,
IN BOOL fPing)
{
HRESULT hr;
HRESULT hr2 = S_OK;
WCHAR wszMachine[512];
WCHAR wszCA[256];
DWORD dwCount = 0;
WCHAR **pawszProperty = NULL;
WCHAR **pawszCertTypes = NULL;
// CA Name
hr = CAGetCAProperty(hCA, CA_PROP_NAME, &pawszProperty);
if (S_OK != hr)
{
wprintf(myLoadResourceString(IDS_FORMAT_CA_NAME_PROP_FAILED), hr);
wprintf(wszNewLine);
goto error;
}
wcscpy(wszCA, pawszProperty[0]);
wprintf(wszNewLine);
wprintf(
myLoadResourceString(IDS_FORMAT_CA_NAME_LIST),
pawszProperty[0]);
wprintf(wszNewLine);
if (NULL != pawszProperty)
{
hr = CAFreeCAProperty(hCA, pawszProperty);
if (S_OK != hr)
{
cuPrintAPIError(L"CAFreeCAProperty", hr);
goto error;
}
pawszProperty = NULL;
}
// Machine name for CA
hr = CAGetCAProperty(hCA, CA_PROP_DNSNAME, &pawszProperty);
if (S_OK != hr)
{
wprintf(myLoadResourceString(IDS_FORMAT_CA_DNS_PROP_FAILED), hr);
wprintf(wszNewLine);
goto error;
}
wcscpy(wszMachine, pawszProperty[0]);
// Display CA Machine DNS Name
wprintf(myLoadResourceString(IDS_FORMAT_CA_MACHINE_LIST), pawszProperty[0]);
wprintf(wszNewLine);
if (NULL != pawszProperty)
{
hr = CAFreeCAProperty(hCA, pawszProperty);
if (S_OK != hr)
{
cuPrintAPIError(L"CAFreeCAProperty", hr);
goto error;
}
pawszProperty = NULL;
}
// DN of CA Object on DS
hr = CAGetCAProperty(hCA, CA_PROP_DSLOCATION, &pawszProperty);
if (S_OK != hr)
{
wprintf(myLoadResourceString(IDS_FORMAT_CA_NAME_PROP_FAILED), hr);
wprintf(wszNewLine);
goto error;
}
// Display DN Name
wprintf(myLoadResourceString(IDS_FORMAT_CA_DS_LIST), pawszProperty[0]); // assume single DN
wprintf(wszNewLine);
if (NULL != pawszProperty)
{
hr = CAFreeCAProperty(hCA, pawszProperty);
if (S_OK != hr)
{
cuPrintAPIError(L"CAFreeCAProperty", hr);
goto error;
}
pawszProperty = NULL;
}
// Cert Types for CA == Multi valued property
hr = DisplaySupportedCertTypes(hCA, &pawszCertTypes);
if (S_OK != hr)
{
goto error;
}
if (NULL != pawszProperty)
{
hr = CAFreeCAProperty(hCA, pawszCertTypes);
if (S_OK != hr)
{
cuPrintAPIError(L"CAFreeCAProperty", hr);
goto error;
}
pawszProperty = NULL;
}
// DN of CA certificate
hr = CAGetCAProperty(hCA, CA_PROP_CERT_DN, &pawszProperty);
if (S_OK != hr)
{
wprintf(myLoadResourceString(IDS_FORMAT_CERT_DN_PROP_FAILED), hr);
wprintf(wszNewLine);
goto error;
}
// assume single DN for CA
wprintf(myLoadResourceString(IDS_FORMAT_CERT_DN_LIST), pawszProperty[0]);
wprintf(wszNewLine);
if (NULL != pawszProperty)
{
hr = CAFreeCAProperty(hCA, pawszProperty);
if (S_OK != hr)
{
cuPrintAPIError(L"CAFreeCAProperty", hr);
goto error;
}
pawszProperty = NULL;
}
// Signature algs
hr = CAGetCAProperty(hCA, CA_PROP_SIGNATURE_ALGS, &pawszProperty);
if (S_OK != hr)
{
wprintf(myLoadResourceString(IDS_FORMAT_CA_ALG_PROP_FAILED), hr);
wprintf(wszNewLine);
goto error;
}
if (NULL != pawszProperty)
{
wprintf(
myLoadResourceString(IDS_FORMAT_CA_ALG_LIST),
pawszProperty[0]);
hr = CAFreeCAProperty(hCA, pawszProperty);
if (S_OK != hr)
{
cuPrintAPIError(L"CAFreeCAProperty", hr);
goto error;
}
pawszProperty = NULL;
}
else
{
wprintf(myLoadResourceString(IDS_NO_ALG_UNEXPECTED));
wprintf(wszNewLine);
}
// Get the expiration date/time/... for an indvidual CA
hr = ShowExpirationTime(hCA);
if (S_OK != hr)
goto error;
if (fPing)
{
PingCA(wszCA, wszMachine);
}
hr = S_OK;
error:
return(hr);
}
// 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 BOOL fPing)
{
HRESULT hr;
DWORD i;
DWORD cCA;
HCAINFO hCA = NULL;
// Enumerate all of the CA's on the DS
hr = CAEnumFirstCA(pwszDomain, 0, &hCA);
if (S_OK != hr)
{
cuPrintAPIError(L"CAEnumFirstCA", hr);
goto error;
}
if (NULL == hCA)
{
wprintf(myLoadResourceString(IDS_NO_CA_ON_DOMAIN));
wprintf(wszNewLine);
hr = CRYPT_E_NOT_FOUND;
goto error;
}
// Make sure that the counting function works at this stage.
cCA = CACountCAs(hCA);
// We've got first CA, so lets look at some info about it
hr = DisplayCAInfo(hCA, fPing);
_JumpIfError(hr, error, "DisplayCAInfo");
for (i = 1; i < cCA; i++)
{
HCAINFO hNextCA;
hr = CAEnumNextCA(hCA, &hNextCA);
if (S_OK != hr)
{
cuPrintAPIError(L"EnumNextCA", hr);
_JumpError(hr, error, "CAEnumNextCA");
}
if (NULL == hNextCA)
{
wprintf(
L"================ %u CAs on %ws Domain ====",
i,
pwszDomain);
wprintf(wszNewLine);
break;
}
// It is difficult to determine what the desired behavior will be for
// this api call.
hr = CACloseCA(hCA);
if (S_OK != hr)
{
cuPrintAPIError(L"CACloseCA", hr);
goto error;
}
hCA = hNextCA;
hr = DisplayCAInfo(hCA, fPing);
_JumpIfError(hr, error, "DisplayCAInfo");
}
// check the count in the enumeration, and verify the results
if (cCA != i)
{
cuPrintAPIError(
L"CACountCAs returned wrong value after CAEnumNextCA!",
cCA);
hr = E_FAIL;
goto error;
}
wprintf(L"================ %u CAs on %ws Domain ====", i, pwszDomain);
wprintf(wszNewLine);
error:
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();
wprintf(myLoadResourceString(IDS_FORMAT_NO_DFS), hr);
wprintf(wszNewLine);
goto error;
// To do... Add diagnostics here
}
wprintf(myLoadResourceString(IDS_DFS_DATA_ACCESS));
wprintf(wszNewLine);
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;
LDAP *pldapbind = NULL;
ULONG ldaperr = LDAP_SUCCESS;
WCHAR *rgwszSearchAttribute[2] = {L"CN", NULL};
WCHAR *pwszSearchParam = L"(&(objectClass=*))";
LDAPMessage *SearchResult = NULL;
WCHAR buff[256];
WCHAR *pwszTmpUrl = NULL;
pldapbind = ldap_init(NULL, LDAP_PORT);
if (NULL == pldapbind)
{
hr = myHLastError();
cuPrintAPIError(L"TestLdapPath:ldap_init", hr);
goto error;
}
// 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);
wprintf(L"Cached LDAP DC: %ws\n", pldapbind->ld_host);
if (ldaperr != LDAP_SUCCESS)
{
cuPrintAPIError(L"TestLdapPath:ldap_bind", ldaperr);
goto error;
}
// Parse URL, and do the search thing.
pwszTmpUrl = wcsstr(pwszLdapURL, L"//");
pwszTmpUrl += 2;
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
cuPrintAPIError(L"ldap_search", ldaperr);
goto error;
}
if (0 == ldap_count_entries(pldapbind, SearchResult))
{
wprintf(myLoadResourceString(IDS_NO_ENTRY_IN_PING));
wprintf(wszNewLine);
goto error;
}
hr = S_OK;
error:
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.
//
HRESULT
DisplayHistoryData(
IN WCHAR const *pwszSubKeyName,
IN HKEY hPolicyKey)
{
HRESULT hr;
HKEY hKeyNew = NULL;
WCHAR buff[512];
DWORD cwc;
DWORD dwType;
// Get #'d history key handle
hr = RegOpenKeyEx(
hPolicyKey,
pwszSubKeyName,
0,
KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
&hKeyNew);
if (S_OK != hr)
{
cuPrintAPIError(L"RegOpenKeyEx", hr);
return(hr);
}
// Get GPO Values
cwc = ARRAYSIZE(buff);
hr = RegQueryValueEx(
hKeyNew,
L"DisplayName",
0,
&dwType,
(BYTE *) buff,
&cwc);
if (S_OK != hr)
{
cuPrintAPIError(L"RegQueryValue", hr);
goto error;
}
wprintf(wszNewLine);
wprintf(myLoadResourceString(IDS_FORMAT_KEY_LIST), pwszSubKeyName, buff);
wprintf(wszNewLine);
cwc = ARRAYSIZE(buff);
hr = RegQueryValueEx(
hKeyNew,
L"GPOName",
0,
&dwType,
(BYTE *) buff,
&cwc);
if (S_OK != hr)
{
cuPrintAPIError(L"RegQueryValue", hr);
goto error;
}
wprintf(myLoadResourceString(IDS_FORMAT_GPO_NAME), buff);
wprintf(wszNewLine);
// See if LDAP can hit this policy
cwc = ARRAYSIZE(buff);
hr = RegQueryValueEx(
hKeyNew,
L"DSPath",
0,
&dwType,
(BYTE *) buff,
&cwc);
if (hr == S_OK)
{
hr = TestLdapPath(buff);
}
else if (hr == ERROR_FILE_NOT_FOUND)
{
wprintf(myLoadResourceString(IDS_NO_DSPATH));
wprintf(wszNewLine);
}
else
{
wprintf(myLoadResourceString(IDS_FORMAT_REG_QUERY_VALUE_FAILED), hr);
wprintf(wszNewLine);
goto error;
}
// See if DFS can get the data..
cwc = ARRAYSIZE(buff);
hr = RegQueryValueEx(
hKeyNew,
L"FileSysPath",
0,
&dwType,
(BYTE *) buff,
&cwc);
if (hr == S_OK)
{
hr = TestDFSPath(buff);
}
else if (hr == ERROR_FILE_NOT_FOUND)
{
wprintf(myLoadResourceString(IDS_NO_FILE_SYS_PATH));
wprintf(wszNewLine);
}
else
{
wprintf(myLoadResourceString(IDS_FORMAT_REG_QUERY_VALUE_FAILED), hr);
wprintf(wszNewLine);
goto error;
}
hr = S_OK;
error:
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
//
WCHAR **
GetPropertyFromDSObject(
IN WCHAR **rgwszSearchAttribute,
IN BOOL fMachine,
OPTIONAL OUT WCHAR **ppwszUserDN)
{
HRESULT hr;
LDAP *pldapbind = NULL;
ULONG ldaperr = LDAP_SUCCESS;
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;
WCHAR **rgwszRet = NULL;
LDAPMessage *SearchResult = NULL;
LDAPMessage *Attributes = NULL;
DWORD dwValCount;
if (fMachine)
{
// Get CN
cwc = ARRAYSIZE(wszNTLM);
if (!GetComputerName(wszNTLM, &cwc))
{
hr = myHLastError();
cuPrintAPIError(L"GetComputerName", hr);
goto error;
}
// Get DN
cwc = ARRAYSIZE(wszDN);
if (!GetComputerObjectName(NameFullyQualifiedDN, wszDN, &cwc))
{
hr = myHLastError();
cuPrintAPIError(L"GetComputerName", hr);
goto error;
}
pwszCNName = wszNTLM;
}
else // User
{
// Get the SAM name..
cwc = ARRAYSIZE(wszNTLM);
if (!GetUserNameEx(NameSamCompatible, wszNTLM, &cwc))
{
hr = myHLastError();
_PrintError(hr, "GetUserNameEx");
cuPrintAPIError(L"GetUserNameEx", hr);
goto error;
}
// Fix NULL termination bug
if (0 != cwc)
{
wszNTLM[cwc - 1] = L'\0';
}
// 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);
goto error;
}
}
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);
goto error;
}
ldaperr = ldap_bind_s(pldapbind, NULL, NULL, LDAP_AUTH_NEGOTIATE);
if (ldaperr != LDAP_SUCCESS)
{
cuPrintAPIError(L"ldap_bind", ldaperr);
goto error;
}
// 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
cuPrintAPIError(L"ldap_search", ldaperr);
goto error;
}
if (0 == ldap_count_entries(pldapbind, SearchResult))
{
wprintf(myLoadResourceString(IDS_FORMAT_LDAP_NO_ENTRY), rgwszSearchAttribute[0]);
wprintf(wszNewLine);
goto error;
}
// 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);
goto error;
}
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, &rgwszRet);
_JumpIfError(hr, error, "ResultAlloc");
error:
if (NULL != SearchResult)
{
ldap_msgfree(SearchResult);
}
if (NULL != rgwszValues)
{
ldap_value_free(rgwszValues);
}
if (NULL != pldapbind)
{
ldap_unbind(pldapbind);
}
return(rgwszRet);
}
//
//
// 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;
CRYPT_HASH_BLOB HashBlob;
ZeroMemory(&HashBlob, sizeof(CRYPT_HASH_BLOB));
HashBlob.cbData = CBMAX_CRYPT_HASH_LEN;
HashBlob.pbData = (BYTE *) LocalAlloc(LMEM_FIXED, CBMAX_CRYPT_HASH_LEN);
if (NULL == HashBlob.pbData)
{
hr = E_OUTOFMEMORY;
cuPrintAPIError(L"LocalAlloc", hr);
goto error;
}
// 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);
goto error;
}
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)
{
HKEY hKey = (dwFlags & TE_MACHINE)? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
HKEY hPolicyKey = NULL;
HRESULT hr;
DWORD dwIndex = 0;
DWORD cwc;
WCHAR buff[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);
}
// Open history key for enumeration
hr = RegOpenKeyEx(
hKey,
wszREGPOLICYHISTORY,
0,
KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
&hPolicyKey);
if (S_OK != hr)
{
cuPrintAPIError(L"RegOpenKeyEx", hr);
wprintf(myLoadResourceString(IDS_POSSIBLE_NO_POLICY));
wprintf(wszNewLine);
goto error;
}
while (TRUE)
{
cwc = ARRAYSIZE(buff);
hr = RegEnumKeyEx(
hPolicyKey,
dwIndex,
buff,
&cwc,
NULL,
NULL,
NULL,
&ft);
if (S_OK != hr)
{
if (hr == ERROR_NO_MORE_ITEMS)
{
break;
}
cuPrintAPIError(L"RegEnumKeyEx", hr);
goto error;
}
DisplayHistoryData(buff, hPolicyKey);
dwIndex++;
}
hr = S_OK;
error:
if (NULL != hPolicyKey)
{
RegCloseKey(hPolicyKey);
}
return(hr);
}
//
// DisplayAlias()
//
// This function displays the certificate template alias GUID, so that
// we can see which GUID | Certtype will be enrolled for.
//
HRESULT
DisplayAlias(
IN DWORD dwFlags)
{
HRESULT hr;
HKEY hKey = (TE_MACHINE & dwFlags)? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
HKEY hAliasKey = NULL;
WCHAR wszguid[MAX_PATH];
DWORD cwc;
DWORD dwType = 0;
WCHAR *wszTrim = NULL;
// Output
switch (dwFlags)
{
case TE_MACHINE:
wprintf(myLoadResourceString(IDS_DEFAULT_CERT_FOR_MACHINE));
wprintf(wszNewLine);
break;
default:
wprintf(myLoadResourceString(IDS_DEFAULT_CERT_FOR_USER));
wprintf(wszNewLine);
}
// Open alias key for admin cert type
hr = RegOpenKeyEx(
hKey,
wszREGADMINALIAS,
0,
KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_READ,
&hAliasKey);
if (S_OK != hr)
{
cuPrintAPIError(L"RegOpenKey", hr);
wprintf(myLoadResourceString(IDS_POLICY_DOWNLOAD_ERROR));
wprintf(wszNewLine);
return(hr);
}
cwc = ARRAYSIZE(wszguid);
hr = RegQueryValueEx(
hAliasKey,
L"Alias",
0,
&dwType,
(BYTE *) wszguid,
&cwc);
if (S_OK != hr)
{
cuPrintAPIError(L"RegQueryValue", hr);
goto error;
}
// Trim off |Administrator
wszTrim = wcschr(wszguid, L'|');
if(wszTrim)
*wszTrim = L'\0';
wprintf(wszguid);
wprintf(L"\n\n");
error:
if (NULL != hAliasKey)
RegCloseKey(hAliasKey);
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;
}
// First, we want to display current alias info
hr2 = DisplayAlias(TE_USER);
_PrintIfError(hr2, "DisplayAlias");
if (S_OK == hr)
{
hr = hr2;
}
hr2 = DisplayAlias(TE_MACHINE);
_PrintIfError(hr2, "DisplayAlias");
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();
rgwszDSSearchRes = GetPropertyFromDSObject(rgwszSearch, FALSE, NULL);
if (NULL != rgwszDSSearchRes)
{
ResultFree(rgwszDSSearchRes);
}
//error:
return(hr);
}
HRESULT
verbTCAInfo(
IN WCHAR const *pwszOption,
OPTIONAL IN WCHAR const *pwszDomain,
OPTIONAL IN WCHAR const *pwszPing,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
if (NULL == pwszDomain && NULL == pwszPing)
{
hr = DisplayClientInfo();
_JumpIfError(hr, error, "DisplayClientInfo");
}
else
{
BOOL fPing = FALSE;
if (NULL != pwszDomain && 0 == lstrcmp(L"-", pwszDomain))
{
pwszDomain = NULL;
}
if (NULL != pwszPing)
{
if (0 == lstrcmpi(L"ping", pwszPing))
{
fPing = TRUE;
}
else
{
hr = E_INVALIDARG;
_JumpError(hr, error, "pwszPing");
}
}
hr = EnumCAs(pwszDomain, fPing);
_JumpIfError(hr, error, "EnumCAs");
}
hr = S_OK;
error:
return(hr);
}