//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1996 - 2000
//
//  File:       info.cpp
//
//--------------------------------------------------------------------------

#include <pch.cpp>

#pragma hdrstop


#include <certca.h>
#include <ntdsapi.h>
#include <dsgetdc.h>
#include <lmerr.h>
#include <lmaccess.h>
#include <lmapibuf.h>


#define DC_DELBAD	0x00000001
#define DC_DELALL	0x00000002
#define DC_VERIFY	0x00000004

// If you invoke DSSTORE with DC=mydc,DC=rd,DC=com  DSSTORE calls
// DsGetDcName(NULL, L"mydc", NULL, NULL, DS_RETURN_DNS_NAME, &pDCInfo);
//
// I suspect changing the code to pass L"mydc.rd.com" instead of L"mydc" would
// solve the problem.  I will look into this for the port of the code to
// certutil.exe.
//
// -----Original Message-----
// From: Christophe Lapeyre (Intl Vendor)
// Sent: Tuesday, January 09, 2001 3:30 AM
// To: Certificate Server Discussion Alias
// Subject: DSSTORE error 1355 (DsGetDCName failed)
//
//
// Hi all,
//
// I encountered the following problem with the DSSTORE tool:
//
// DSSTORE DC=mydc,DC=rd,DC=com -display
// DsGetDCName failed! - rc=1355 GLE - 3e5
// DsGetDCName failed! - rc=1355 GLE - 3e5
//
// Nltest /dsgetdc:mydc.rd.com just run ok.
//
// My Netbios domain name is different from my DNS domain name.
//
//
//
// There is a preview Kb article numbered Q280122, but I haven't been able to
// find a fix for this.




HRESULT
ExtractCertSubject(
    IN CERT_CONTEXT const *pcc,
    IN DWORD dwType,
    IN DWORD dwFlags,
    OUT WCHAR **ppwszOut)
{
    HRESULT hr;
    DWORD cwc;
    DWORD cwcBuf;
    WCHAR *pwszOut = NULL;

    *ppwszOut = NULL;
    cwcBuf = 0;
    while (TRUE)
    {
	cwc = CertGetNameString(
			pcc,
			dwType,
			dwFlags,
			NULL,		// pvTypePara
			pwszOut,
			cwcBuf);
	if (1 == cwc)
	{
	    hr = CRYPT_E_NOT_FOUND;
	    _JumpError(hr, error, "CertGetNameString");
	}
	if (NULL != pwszOut)
	{
	    break;
	}
	pwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
	if (NULL == pwszOut)
	{
	    hr = E_OUTOFMEMORY;
	    _JumpError(hr, error, "LocalAlloc");
	}
	cwcBuf = cwc;
    }
    *ppwszOut = pwszOut;
    pwszOut = NULL;
    hr = S_OK;

error:
    if (NULL != pwszOut)
    {
	LocalFree(pwszOut);
    }
    return(hr);
}


HRESULT
myCertGetEnhancedKeyUsage(
    IN CERT_CONTEXT const *pcc,
    IN DWORD dwFlags,
    OUT CERT_ENHKEY_USAGE **ppUsage,
    OUT DWORD *pcbUsage)
{
    HRESULT hr;
    CERT_ENHKEY_USAGE *pUsage = NULL;
    DWORD cb;

    *ppUsage = NULL;

    while (TRUE)
    {
	if (!CertGetEnhancedKeyUsage(pcc, dwFlags, pUsage, &cb))
	{
	    hr = myHLastError();
	    _JumpError(hr, error, "CertGetEnhancedKeyUsage");
	}
	if (NULL != pUsage)
	{
	    *pcbUsage = cb;
	    *ppUsage = pUsage;
	    pUsage = NULL;
	    break;
	}
	pUsage = (CERT_ENHKEY_USAGE *) LocalAlloc(LMEM_FIXED, cb);
	if (NULL == pUsage)
	{
	    hr = E_OUTOFMEMORY;
	    _JumpError(hr, error, "LocalAlloc");
	}
    }
    hr = S_OK;

error:
    if (NULL != pUsage)
    {
	LocalFree(pUsage);
    }
    return(hr);
}


HRESULT
CheckForKDCCertificate(
    IN WCHAR const *pwszDC,
    IN DWORD dwFlags)
{
    HRESULT hr;
    HCERTSTORE hStoreRemote = NULL;
    WCHAR wszStorePath[512];
    WCHAR *apwszCertType[2] = { NULL, NULL };
    DWORD cCert = 0;
    DWORD dwOpenFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
    CERT_CONTEXT const *pcc = NULL;
    CERT_CONTEXT const *pccPrev = NULL;
    BOOL fDelete;
    BOOL fNewLine;
    DWORD i;
    DWORD j;
    CERT_ENHKEY_USAGE *pUsage = NULL;
    DWORD cbUsage;
    static WCHAR *s_apwszKDCTemplates[] = {
	wszCERTTYPE_DC_AUTH,
	wszCERTTYPE_DS_EMAIL_REPLICATION,
	wszCERTTYPE_DC,
    };

    // If not doing delete operations, open "ReadOnly"

    if (0 == ((DC_DELALL | DC_DELBAD) & dwFlags))
    {
        dwOpenFlags |= CERT_STORE_READONLY_FLAG;
    }

    swprintf(wszStorePath, L"\\\\%ws\\" wszMY_CERTSTORE, pwszDC);
    hStoreRemote = CertOpenStore(
			    CERT_STORE_PROV_SYSTEM_W,
			    X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
			    NULL,
			    dwOpenFlags,
			    (VOID *) wszStorePath);
    if (NULL == hStoreRemote)
    {
        hr = myHLastError();
        _JumpError2(hr, error, "CertOpenStore", E_ACCESSDENIED);
    }

    wprintf(
	myLoadResourceString(IDS_FORMAT_KDCCERTS), // "** KDC Certificates for DC %ws"
	pwszDC);
    wprintf(wszNewLine);


    // Look for KDC certs

    fNewLine = FALSE;
    while (TRUE)
    {
        BOOL fKDCCert;

	for (i = 0; i < ARRAYSIZE(apwszCertType); i++)
	{
	    if (NULL != apwszCertType[i])
	    {
		LocalFree(apwszCertType[i]);
		apwszCertType[i] = NULL;
	    }
	}

	pcc = CertEnumCertificatesInStore(hStoreRemote, pccPrev);
	if (NULL == pcc)
	{
	    hr = myHLastError();
	    _PrintError2(hr, "CertEnumCertificatesInStore", CRYPT_E_NOT_FOUND);
	    break;
	}
        pccPrev = pcc;

        fKDCCert = FALSE;
	hr = cuGetCertType(
		    pcc->pCertInfo,
		    &apwszCertType[0],	// ppwszCertTypeNameV1
		    NULL,		// ppwszDisplayNameV1
		    NULL,		// ppwszCertTypeObjId
		    &apwszCertType[1],	// ppwszCertTypeName
		    NULL);		// ppwszDisplayName
	if (S_OK != hr)
	{
	    _PrintError(hr, "cuGetCertType");
	}
	else
	{
	    for (i = 0; i < ARRAYSIZE(apwszCertType); i++)
	    {
		if (NULL != apwszCertType[i])
		{
		    for (j = 0; j < ARRAYSIZE(s_apwszKDCTemplates); j++)
		    {
			if (0 == lstrcmpi(
				    apwszCertType[i],
				    s_apwszKDCTemplates[j]))
			{
			    fKDCCert = TRUE;
			}
		    }
		}
	    }
	}
	if (!fKDCCert)
	{
	    WCHAR const *pwsz = apwszCertType[0];
	    
	    if (NULL == apwszCertType[0])
	    {
		pwsz = apwszCertType[1];
	    }
	    if (g_fVerbose)
	    {
		    wprintf(myLoadResourceString(IDS_FORMAT_CERT_TYPE_NOT_DC), pwsz);
		    wprintf(wszNewLine);
	    }
	}

        fKDCCert = FALSE;
	hr = myCertGetEnhancedKeyUsage(
				pcc,
				CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
				&pUsage,
				&cbUsage);
	if (S_OK != hr)
	{
	    _PrintError(hr, "myCertGetEnhancedKeyUsage");
	}
	else
	{
	    for (i = 0; i < pUsage->cUsageIdentifier; i++)
	    {
		if (0 == strcmp(
			    szOID_KP_SMARTCARD_LOGON,
			    pUsage->rgpszUsageIdentifier[i]))
		{
		    fKDCCert = TRUE;
		    break;
		}
	    }
	}
	if (!fKDCCert)
	{
	    if (g_fVerbose)
	    {
		    wprintf(myLoadResourceString(IDS_FORMAT_CERT_USAGE_MISSING), L"szOID_KP_SMARTCARD_LOGON");
		    wprintf(wszNewLine);
	    }
	    if (!g_fForce || fDelete)
	    {
		continue;
	    }
	}

        // Cert passed test, dump issuer and subject

	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);
	_PrintIfError(hr, "cuDumpCertType");

	wprintf(wszNewLine);

        cCert++;

        // perform operations on certificatess

	fDelete = 0 != (DC_DELALL & dwFlags);
        if ((DC_VERIFY | DC_DELBAD) & dwFlags)
	{
	    char *apszUsage[] =
	    {
		szOID_PKIX_KP_SERVER_AUTH,
		szOID_KP_SMARTCARD_LOGON,
	    };
	    DWORD VerifyState;

	    hr = cuVerifyCertContext(
				pcc,
				NULL,
				apszUsage,		// apszPolicies
				ARRAYSIZE(apszUsage),	// cPolicies
				&VerifyState);
	    if (S_OK != hr)
	    {
		_PrintError(hr, "cuVerifyCertContext");
		if (CRYPT_E_REVOCATION_OFFLINE != hr)
		{
		    fDelete = 0 != (DC_DELBAD & dwFlags);
		}
	    }
        }
	if (fDelete)
	{
            CERT_CONTEXT const *pccDel;

            pccDel = CertDuplicateCertificateContext(pcc);
            if (!CertDeleteCertificateFromStore(pccDel))
	    {
                hr = myHLastError();
                wprintf(myLoadResourceString(IDS_FORMAT_DELETE_CERT_FROM_STORE_FAILED), hr);
		        wprintf(wszNewLine);
            }
	    else
	    {
                wprintf(myLoadResourceString(IDS_FORMAT_DELETE_DC_CERT));
		        wprintf(wszNewLine);
            }
        }
    }

    swprintf(wszStorePath, myLoadResourceString(IDS_FORMAT_KDC_PATH), cCert, pwszDC);
    wprintf(wszStorePath);
    wprintf(wszNewLine);
    if (0 == cCert)
    {
        wprintf(myLoadResourceString(IDS_NO_KDC_MY_STORE));
	wprintf(wszNewLine);
	hr = CRYPT_E_NOT_FOUND;
	_JumpError(hr, error, "cCert");
    }
    hr = S_OK;

error:
    if (NULL != pUsage)
    {
	LocalFree(pUsage);
    }
    for (i = 0; i < ARRAYSIZE(apwszCertType); i++)
    {
	if (NULL != apwszCertType[i])
	{
	    LocalFree(apwszCertType[i]);
	}
    }
    if (NULL != hStoreRemote)
    {
        CertCloseStore(hStoreRemote, 0);
    }
    return(hr);
}


// This function queries the access token specified by the hToken parameter,
// and returns an allocated copy of the TokenUser information on success.
//
// The access token specified by hToken must be opened for TOKEN_QUERY access.
//
// On success, the return value is TRUE.  The caller is responsible for freeing
// the resultant UserSid via LocalFree.
//
// On failure, the caller does not need to free any buffer.

HRESULT
GetTokenUserSid(
    IN HANDLE hToken,		// token to query
    IN OUT PSID *ppUserSid)	// resultant user sid
{
    HRESULT hr;
    BYTE FastBuffer[256];
    BYTE *SlowBuffer = NULL;
    TOKEN_USER *ptgUser;
    DWORD cbBuffer;
    DWORD cbSid;

    *ppUserSid = NULL;

    // try querying based on a fast stack based buffer first.

    ptgUser = (TOKEN_USER *) FastBuffer;
    cbBuffer = sizeof(FastBuffer);

    if (!GetTokenInformation(
			hToken,		// identifies access token
			TokenUser,	// TokenUser info type
			ptgUser,	// retrieved info buffer
			cbBuffer,	// size of buffer passed-in
			&cbBuffer))	// required buffer size
    {
	hr = myHLastError();
        if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
	{
	    _JumpError(hr, error, "GetTokenInformation");
	}

	// try again with the specified buffer size

	SlowBuffer = (BYTE *) LocalAlloc(LMEM_FIXED, cbBuffer);
	if (NULL == SlowBuffer)
	{
	    hr = E_OUTOFMEMORY;
	    _JumpError(hr, error, "LocalAlloc");
	}
	ptgUser = (TOKEN_USER *) SlowBuffer;

	if (!GetTokenInformation(
			    hToken,		// identifies access token
			    TokenUser,	// TokenUser info type
			    ptgUser,	// retrieved info buffer
			    cbBuffer,	// size of buffer passed-in
			    &cbBuffer))	// required buffer size
	{
	    hr = myHLastError();
	    _JumpError(hr, error, "GetTokenInformation");
	}
    }

    // if we got the token info, copy the relevant element for the caller.

    cbSid = GetLengthSid(ptgUser->User.Sid);
    *ppUserSid = LocalAlloc(LMEM_FIXED, cbSid);
    if (NULL == *ppUserSid)
    {
	hr = E_OUTOFMEMORY;
	_JumpError(hr, error, "LocalAlloc");
    }

    if (!CopySid(cbSid, *ppUserSid, ptgUser->User.Sid))
    {
	hr = myHLastError();
	_JumpError(hr, error, "CopySid");
    }
    hr = S_OK;

error:
    if (S_OK != hr)
    {
        if (NULL != *ppUserSid)
	{
            LocalFree(*ppUserSid);
            *ppUserSid = NULL;
        }
    }
    if (NULL != SlowBuffer)
    {
        LocalFree(SlowBuffer);
    }
    return(hr);
}


// This routine obtains a domain controller computer name associated with
// the account related to the hToken access token.
//
// hToken should be opened for TOKEN_QUERY access.
// pwszDomain should be of size (UNCLEN+1)

HRESULT
GetDomainControllers(
    OPTIONAL IN WCHAR const *pwszDomain,
    IN HANDLE hToken,
    OUT DS_DOMAIN_CONTROLLER_INFO_1 **ppDCInfoOut,
    OUT DWORD *pcDC)
{
    HRESULT hr;
    PSID pSidUser = NULL;   // sid of client user.
    WCHAR wszUserName[UNLEN + 1];
    DWORD cwcUserName;
    WCHAR wszDomainName[DNLEN + 1]; // domain we want a controller for.
    DWORD cwcDomainName;
    SID_NAME_USE snu;
    DOMAIN_CONTROLLER_INFO *pDomainInfo = NULL;
    DS_DOMAIN_CONTROLLER_INFO_1 *pDcInfo = NULL;
    HANDLE hDS = INVALID_HANDLE_VALUE;
    BOOL fSuccess = FALSE;

    *ppDCInfoOut = NULL;
    if (NULL == pwszDomain)
    {
        // first, get the user sid associated with the specified access token.

        hr = GetTokenUserSid(hToken, &pSidUser);
        _JumpIfError(hr, error, "GetTokenUserSid");

        // next, lookup the domain name associated with the specified account.

	cwcUserName = ARRAYSIZE(wszUserName);
	cwcDomainName = ARRAYSIZE(wszDomainName);
        if (!LookupAccountSid(
			NULL,
			pSidUser,
			wszUserName,
			&cwcUserName,
			wszDomainName,
			&cwcDomainName,
			&snu))
	{
	    hr = myHLastError();
	    _JumpError(hr, error, "LookupAccountSid");
        }
    }
    else
    {
        wcscpy(wszDomainName, pwszDomain);
    }

    hr = DsGetDcName(
		NULL,
		wszDomainName,
		NULL,
		NULL,
		DS_RETURN_DNS_NAME,
		&pDomainInfo);
    _JumpIfError(hr, error, "DsGetDcName");

    // Get a handle to the DS on that machine

    hr = DsBind(pDomainInfo->DomainControllerName, NULL, &hDS);
    _JumpIfError(hr, error, "DsBind");

    // Use the handle to enumerate all of the DCs

    hr = DsGetDomainControllerInfo(
			    hDS,
			    pDomainInfo->DomainName,
			    1,		// info level
			    pcDC,
			    (VOID **) ppDCInfoOut);
    _JumpIfError(hr, error, "DsGetDomainControllerInfo");

error:
    if (INVALID_HANDLE_VALUE != hDS)
    {
        DsUnBind(&hDS);
    }
    if (NULL != pDomainInfo)
    {
        NetApiBufferFree(pDomainInfo);
    }
    if (NULL != pSidUser)
    {
        LocalFree(pSidUser);
    }
    return(hr);
}


HRESULT
OpenRemoteEnterpriseRoot(
    IN WCHAR const *pwszDC)
{
    HRESULT hr;
    HCERTSTORE hStoreRemote = NULL;
    WCHAR wszStorePath[512];
    DWORD cCert = 0;
    CERT_CONTEXT const *pcc = NULL;
    CERT_CONTEXT const *pccPrev;

    swprintf(wszStorePath, L"\\\\%ws\\" wszROOT_CERTSTORE, pwszDC);
    hStoreRemote = CertOpenStore(
			CERT_STORE_PROV_SYSTEM_W,
			X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
			NULL,
			CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE |
			    CERT_STORE_READONLY_FLAG,
			(VOID *) wszStorePath);
    if (NULL == hStoreRemote)
    {
        hr = myHLastError();
        _JumpError2(hr, error, "CertOpenStore", E_ACCESSDENIED);
    }

    wprintf(
	myLoadResourceString(IDS_FORMAT_DCROOTCERTS), // "** Enterprise Root Certificates for DC %ws"
	pwszDC);
    wprintf(wszNewLine);

    // Dump issuer of enterprise roots.

    pccPrev = NULL;
    while (TRUE)
    {
	pcc = CertEnumCertificatesInStore(hStoreRemote, pccPrev);
	if (NULL == pcc)
	{
	    hr = myHLastError();
	    _PrintError2(hr, "CertEnumCertificatesInStore", CRYPT_E_NOT_FOUND);
	    break;
	}

	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);
        cCert++;
        pccPrev = pcc;
    }
    if (0 == cCert)
    {
        wprintf(myLoadResourceString(IDS_NO_KDC_ENT_STORE));
	    wprintf(wszNewLine);
	    hr = CRYPT_E_NOT_FOUND;
    }
    hr = S_OK;

error:
    if (NULL != hStoreRemote)
    {
        CertCloseStore(hStoreRemote, 0);
    }
    return(hr);
}


HRESULT
verbDCInfo(
    IN WCHAR const *pwszOption,
    OPTIONAL IN WCHAR const *pwszFlags,
    IN WCHAR const *pwszArg2,
    IN WCHAR const *pwszArg3,
    IN WCHAR const *pwszArg4)
{
    HRESULT hr;
    HRESULT hrSave;
    HANDLE hToken = NULL;
    DS_DOMAIN_CONTROLLER_INFO_1 *pDcInfo = NULL;
    DWORD cDC = 0;
    DWORD dwFlags;
    DWORD i;
    WCHAR *pwszDomain = NULL;

    dwFlags = 0;
    if (NULL != pwszFlags)
    {
	if (0 == lstrcmpi(L"DeleteAll", pwszFlags))
	{
	    dwFlags = DC_DELALL;
	}
	else
	if (0 == lstrcmpi(L"DeleteBad", pwszFlags))
	{
	    dwFlags = DC_DELBAD | DC_VERIFY;
	}
	else
	if (0 == lstrcmpi(L"Verify", pwszFlags))
	{
	    dwFlags = DC_VERIFY;
	}
	else
	{
	    hr = E_INVALIDARG;
	    _JumpError(hr, error, "bad Flags");
	}
    }

    // Grovel the process token for user identity.  Used in determining
    // target domain

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
    {
        hr = myHLastError();
        _JumpError(hr, error, "OpenProcessToken");
    }

    // Use DS APIs to get all of the DCs in our domain

    hr = GetDomainControllers(pwszDomain, hToken, &pDcInfo, &cDC);
    _JumpIfError(hr, error, "GetDomainControllers");

    for (i = 0; i < cDC; i++)
    {
        wprintf(L"%u: %ws\n", i, pDcInfo[i].NetbiosName);
    }
    hrSave = S_OK;
    for (i = 0; i < cDC; i++)
    {
        WCHAR wszBuffer[512];

	wprintf(wszNewLine);
        wprintf(
	    myLoadResourceString(IDS_FORMAT_TESTINGDC), // "*** Testing DC[%u]: %ws"
	    i,
	    pDcInfo[i].NetbiosName);
	wprintf(wszNewLine);

        // Is DC available ?

        wsprintf(wszBuffer, L"\\\\%ws\\netlogon", pDcInfo[i].NetbiosName);

        if (MAXDWORD == GetFileAttributes(wszBuffer))
	{
	    hr = myHLastError();
	    _PrintError2(hr, "GetFileAttributes", hr);
	    cuPrintError(IDS_DCUNAVAILABLE, hr);
	    if (S_OK == hrSave)
	    {
		hrSave = hr;
	    }
            continue;
        }

        // Open the enterprise root store, and make sure it's got the
        // NTDEV ROOT CERTIFICATE (subject #defined above)

        hr = OpenRemoteEnterpriseRoot(pDcInfo[i].NetbiosName);
	if (S_OK != hr)
	{
	    _PrintError2(hr, "OpenRemoteEnterpriseRoot", hr);
	    cuPrintError(IDS_REMOTEENTROOT, hr);
	    if (S_OK == hrSave)
	    {
		hrSave = hr;
	    }
	}

        // Make sure the machine has a *valid* KDC certificate

        hr = CheckForKDCCertificate(
				pDcInfo[i].NetbiosName,
				dwFlags);
	if (S_OK != hr)
	{
	    _PrintError2(hr, "CheckForKDCCertificate", hr);
	    cuPrintError(IDS_REMOTEKDCCERT, hr);
	    if (S_OK == hrSave)
	    {
		hrSave = hr;
	    }
	}
    }
    wprintf(wszNewLine);
    hr = hrSave;
    _JumpIfError2(hr, error, "verbDCInfo", hr);

error:
    if (NULL != pDcInfo)
    {
       DsFreeDomainControllerInfo(1, cDC, pDcInfo);
    }
    return(hr);
}


//
// Check for autoenrolled certificate
//

HRESULT
CheckForAutoenrolledCertificate(
    IN WCHAR const *pwszDC)
{
    HRESULT hr;
    HCERTSTORE hRemoteStore = NULL;
    WCHAR wszStorePath[512];
    DWORD dwEnrollPropId = CERT_AUTO_ENROLL_PROP_ID;
    DWORD cCert;
    DWORD cCertArchived;
    DWORD dwArchiveBit;
    CERT_CONTEXT const *pcc;

    swprintf(wszStorePath, L"\\\\%ws\\" wszMY_CERTSTORE, pwszDC);

    hRemoteStore = CertOpenStore(
			CERT_STORE_PROV_SYSTEM_W,
			X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
			NULL,
			CERT_STORE_READONLY_FLAG |
			    CERT_SYSTEM_STORE_LOCAL_MACHINE |
			    CERT_STORE_ENUM_ARCHIVED_FLAG,
			(VOID *) wszStorePath);
    if (NULL == hRemoteStore)
    {
        hr = myHLastError();
        wprintf(myLoadResourceString(IDS_FORMAT_OPEN_REMOTE_MY_FAILED), hr);
		wprintf(wszNewLine);
        goto error;
    }

    cCert = 0;
    cCertArchived = 0;
    pcc = NULL;
    while (TRUE)
    {
	pcc = CertFindCertificateInStore(
				    hRemoteStore,
				    X509_ASN_ENCODING,
				    0,
				    CERT_FIND_PROPERTY,
				    &dwEnrollPropId,
				    pcc);
	if (NULL == pcc)
	{
	    break;
	}

        // Cert passed test, dump issuer and subject

        cCert++;

        if (!CertGetCertificateContextProperty(
					pcc,
					CERT_ARCHIVED_PROP_ID,
					NULL,
					&dwArchiveBit))
	{
            hr = myHLastError();
            if (hr != CRYPT_E_NOT_FOUND)
	    {
                wprintf(myLoadResourceString(IDS_FORMAT_ERROR_GET_ARCHIVE_PROP), hr);
		        wprintf(wszNewLine);
            }
        }
	else
	{
            wprintf(myLoadResourceString(IDS_LIST_ARCHIVED_CERT));
		    wprintf(wszNewLine);
            cCertArchived++;
        }

	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);
    }
    if (0 == cCert)
    {
        wprintf(myLoadResourceString(IDS_NO_AUTOENROLLED_CERT));
		wprintf(wszNewLine);
	hr = CRYPT_E_NOT_FOUND;
	_JumpError(hr, error, "no AE certs");
    }
    wprintf(
	L"%i Machine certs (%i archived) for %ws\n",
	cCert,
	cCertArchived,
	pwszDC);
    hr = S_OK;

error:
    if (NULL != hRemoteStore)
    {
        CertCloseStore(hRemoteStore, 0);
    }
    return(hr);
}


HRESULT
CheckForAutoenrollmentObject(
    IN WCHAR const *pwszDC)
{
    HRESULT hr;
    HCERTSTORE hRemoteStore = NULL;
    WCHAR wszStorePath[512];
    DWORD cAE;
    CTL_CONTEXT const *pCTL;

    swprintf(wszStorePath, L"\\\\%ws\\" wszACRS_CERTSTORE, pwszDC);

    hRemoteStore = CertOpenStore(
			    CERT_STORE_PROV_SYSTEM,
			    X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
			    NULL,
			    CERT_SYSTEM_STORE_LOCAL_MACHINE |
				CERT_STORE_READONLY_FLAG,
			    (VOID *) wszStorePath);
    if (NULL == hRemoteStore)
    {
        hr = myHLastError();
        wprintf(myLoadResourceString(IDS_FORMAT_OPEN_STORE_REMOTE_ENT_FAILED), hr);
		wprintf(wszNewLine);
        goto error;
    }

    // Dump issuer of enterprise roots.

    cAE = 0;
    pCTL = NULL;
    while (TRUE)
    {
	pCTL = CertEnumCTLsInStore(hRemoteStore, pCTL);
	if (NULL == pCTL)
	{
	    break;
	}
        wprintf(
	    L"Autoenrollment Object:\n%ws\n",
            pCTL->pCtlInfo->ListIdentifier.pbData);

        cAE++;
    }
    if (0 == cAE)
    {
        wprintf(myLoadResourceString(IDS_NO_AUTOENROLL_OBJECT));
        wprintf(wszNewLine);
    }
    hr = S_OK;

error:
    if (NULL != hRemoteStore)
    {
        CertCloseStore(hRemoteStore, 0);
    }
    return(hr);
}


//
// This function takes a Marc Jacobs supplied text file (results from SSOLogon
// scripts) and runs through entmon for each machine in the list
//

HRESULT
verbEntInfo(
    IN WCHAR const *pwszOption,
    IN WCHAR const *pwszSamMachine,
    IN WCHAR const *pwszArg2,
    IN WCHAR const *pwszArg3,
    IN WCHAR const *pwszArg4)
{
    HRESULT hr;
    HRESULT hrSave;
    WCHAR *pwszDomain = NULL;
    WCHAR *pwszMachine = NULL;
    WCHAR *pwszMachineName = NULL;


    hr = mySplitConfigString(pwszSamMachine, &pwszDomain, &pwszMachine);
    _JumpIfError(hr, error, "mySplitConfigString");

    if (NULL == pwszMachine || NULL == wcschr(pwszMachine, L'$'))
    {
        wprintf(myLoadResourceString(IDS_ERROR_CHECK_MACHINE_NAME));
        wprintf(wszNewLine);
	hr = E_INVALIDARG;
	_JumpError(hr, error, "bad machine name");
    }

    // knock off trailing $
    hr = myDupString(pwszMachine, &pwszMachineName);
    _JumpIfError(hr, error, "myDupString");

    pwszMachineName[wcslen(pwszMachineName)-1] = L'\0';

    // assume for now that we're only interested in opening remote root store

    wprintf(myLoadResourceString(IDS_FORMAT_MACHINE_LIST), pwszMachine);
    wprintf(wszNewLine);


    // Cert store functions, if first fails, bail.

    hrSave = S_OK;
    hr = OpenRemoteEnterpriseRoot(pwszMachineName);
    if (S_OK != hr)
    {
	cuPrintError(IDS_REMOTEENTROOT, hr);
	_PrintError2(hr, "OpenRemoteEnterpriseRoot", hr);
	hrSave = hr;
    }
    else
    {
	hr = CheckForAutoenrollmentObject(pwszMachineName);
	_PrintIfError(hr, "CheckForAutoenrollmentObject");
	hrSave = hr;

	hr = CheckForAutoenrolledCertificate(pwszMachineName);
	_PrintIfError(hr, "CheckForAutoenrolledCertificate");
	if (S_OK == hrSave)
	{
	    hrSave = hr;
	}
    }
    hr = cuGetGroupMembership(pwszSamMachine);
    _PrintIfError(hr, "cuGetGroupMembership");
    if (S_OK == hrSave)
    {
	hrSave = hr;
    }
    hr = hrSave;
    _JumpIfError2(hr, error, "RunEntmon", hr);

    wprintf(wszNewLine);

error:
    if (NULL != pwszDomain)
    {
	LocalFree(pwszDomain);
    }
    if (NULL != pwszMachine)
    {
	LocalFree(pwszMachine);
    }
    if (NULL != pwszMachineName)
    {
	LocalFree(pwszMachineName);
    }
    return(hr);
}