Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1759 lines
38 KiB

//+-------------------------------------------------------------------------
//
// 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>
#include <csldap.h>
#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);
}