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.
1127 lines
26 KiB
1127 lines
26 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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 __dwFILE__ __dwFILE_CERTUTIL_INFO_CPP__
|
|
|
|
|
|
#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);
|
|
}
|
|
|
|
static WCHAR *s_apwszKDCTemplates[] = {
|
|
wszCERTTYPE_DC_AUTH,
|
|
wszCERTTYPE_DS_EMAIL_REPLICATION,
|
|
wszCERTTYPE_DC,
|
|
};
|
|
|
|
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;
|
|
|
|
// 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 == mylstrcmpiS(
|
|
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);
|
|
}
|
|
}
|
|
|
|
if (NULL != pUsage)
|
|
{
|
|
LocalFree(pUsage);
|
|
pUsage = NULL;
|
|
}
|
|
hr = myCertGetEnhancedKeyUsage(
|
|
pcc,
|
|
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
|
|
&pUsage);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError2(hr, "myCertGetEnhancedKeyUsage", CRYPT_E_NOT_FOUND);
|
|
}
|
|
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
|
|
|
|
wprintf(myLoadResourceString(IDS_FORMAT_CERT_COLON), cCert);
|
|
wprintf(wszNewLine);
|
|
|
|
hr = cuDumpAsnBinaryQuiet(
|
|
pcc->pbCertEncoded,
|
|
pcc->cbCertEncoded,
|
|
MAXDWORD);
|
|
_PrintIfError(hr, "cuDumpAsnBinaryQuiet");
|
|
|
|
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,
|
|
ARRAYSIZE(apszUsage),
|
|
apszUsage,
|
|
0, // cIssuancePolicies
|
|
NULL, // apszIssuancePolicies
|
|
TRUE, // fNTAuth
|
|
&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;
|
|
}
|
|
|
|
wprintf(myLoadResourceString(IDS_FORMAT_CERT_COLON), cCert);
|
|
wprintf(wszNewLine);
|
|
|
|
hr = cuDumpAsnBinaryQuiet(
|
|
pcc->pbCertEncoded,
|
|
pcc->cbCertEncoded,
|
|
MAXDWORD);
|
|
_PrintIfError(hr, "cuDumpAsnBinaryQuiet");
|
|
|
|
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 == LSTRCMPIS(pwszFlags, L"DeleteAll"))
|
|
{
|
|
dwFlags = DC_DELALL;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pwszFlags, L"DeleteBad"))
|
|
{
|
|
dwFlags = DC_DELBAD | DC_VERIFY;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pwszFlags, L"Verify"))
|
|
{
|
|
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);
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsAutoenrolledCert(
|
|
IN CERT_CONTEXT const *pcc,
|
|
OPTIONAL IN WCHAR const *pwszzTemplates)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fMatch = FALSE;
|
|
WCHAR *pwszTemplate = NULL;
|
|
WCHAR const *pwsz;
|
|
|
|
hr = cuGetCertType(pcc->pCertInfo, &pwszTemplate, NULL, NULL, NULL, NULL);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "cuGetCertType");
|
|
if (CRYPT_E_NOT_FOUND == hr)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
goto error;
|
|
}
|
|
|
|
pwsz = pwszzTemplates;
|
|
if (NULL != pwsz)
|
|
{
|
|
for ( ; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
|
|
{
|
|
if (0 == mylstrcmpiL(pwsz, pwszTemplate))
|
|
{
|
|
fMatch = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!fMatch)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < ARRAYSIZE(s_apwszKDCTemplates); i++)
|
|
{
|
|
if (0 == mylstrcmpiS(pwszTemplate, s_apwszKDCTemplates[i]))
|
|
{
|
|
fMatch = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszTemplate)
|
|
{
|
|
LocalFree(pwszTemplate);
|
|
}
|
|
return(fMatch);
|
|
}
|
|
|
|
|
|
//
|
|
// Check for autoenrolled certificate
|
|
//
|
|
|
|
HRESULT
|
|
CheckForV1AutoenrolledCertificate(
|
|
IN WCHAR const *pwszDC,
|
|
OPTIONAL IN WCHAR const *pwszzTemplates)
|
|
{
|
|
HRESULT hr;
|
|
HCERTSTORE hStoreRemote = NULL;
|
|
WCHAR wszStorePath[512];
|
|
DWORD cCert;
|
|
DWORD cCertArchived;
|
|
DWORD dwArchiveBit;
|
|
CERT_CONTEXT const *pcc;
|
|
|
|
swprintf(wszStorePath, L"\\\\%ws\\" wszMY_CERTSTORE, pwszDC);
|
|
|
|
hStoreRemote = 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 == hStoreRemote)
|
|
{
|
|
hr = myHLastError();
|
|
wprintf(myLoadResourceString(IDS_FORMAT_OPEN_REMOTE_MY_FAILED), hr);
|
|
wprintf(wszNewLine);
|
|
goto error;
|
|
}
|
|
|
|
cCert = 0;
|
|
cCertArchived = 0;
|
|
pcc = NULL;
|
|
while (TRUE)
|
|
{
|
|
pcc = CertEnumCertificatesInStore(hStoreRemote, pcc);
|
|
if (NULL == pcc)
|
|
{
|
|
break;
|
|
}
|
|
if (!IsAutoenrolledCert(pcc, pwszzTemplates) && 1 >= g_fForce)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Cert passed test, dump issuer and subject
|
|
|
|
wprintf(myLoadResourceString(IDS_FORMAT_CERT_COLON), cCert);
|
|
wprintf(wszNewLine);
|
|
|
|
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);
|
|
|
|
hr = cuDisplayHash(
|
|
g_wszPad2,
|
|
pcc,
|
|
NULL,
|
|
CERT_SHA1_HASH_PROP_ID,
|
|
L"sha1");
|
|
_PrintIfError(hr, "cuDisplayHash");
|
|
|
|
wprintf(wszNewLine);
|
|
|
|
cCert++;
|
|
}
|
|
if (0 == cCert)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_NO_AUTOENROLLED_CERT));
|
|
wprintf(wszNewLine);
|
|
hr = CRYPT_E_NOT_FOUND;
|
|
_JumpError(hr, error, "no AE certs");
|
|
}
|
|
wprintf(
|
|
myLoadResourceString(IDS_FORMAT_MACHINE_AND_ARCHIVED_CERTS),
|
|
cCert,
|
|
cCertArchived);
|
|
wprintf(L" ");
|
|
wprintf(myLoadResourceString(IDS_FORMAT_FOR_DC), pwszDC);
|
|
wprintf(wszNewLine);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hStoreRemote)
|
|
{
|
|
CertCloseStore(hStoreRemote, 0);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CheckForV1AutoenrollmentObject(
|
|
IN WCHAR const *pwszDC,
|
|
OUT WCHAR **ppwszzTemplates)
|
|
{
|
|
HRESULT hr;
|
|
HCERTSTORE hStoreRemote = NULL;
|
|
WCHAR wszStorePath[512];
|
|
DWORD cAE;
|
|
CTL_CONTEXT const *pCTL;
|
|
DWORD cwc;
|
|
WCHAR *pwsz;
|
|
|
|
*ppwszzTemplates = NULL;
|
|
swprintf(wszStorePath, L"\\\\%ws\\" wszACRS_CERTSTORE, pwszDC);
|
|
|
|
hStoreRemote = 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 == hStoreRemote)
|
|
{
|
|
hr = myHLastError();
|
|
wprintf(myLoadResourceString(IDS_FORMAT_OPEN_STORE_REMOTE_ENT_FAILED), hr);
|
|
wprintf(wszNewLine);
|
|
goto error;
|
|
}
|
|
|
|
cwc = 1;
|
|
cAE = 0;
|
|
pCTL = NULL;
|
|
while (TRUE)
|
|
{
|
|
pCTL = CertEnumCTLsInStore(hStoreRemote, pCTL);
|
|
if (NULL == pCTL)
|
|
{
|
|
break;
|
|
}
|
|
cwc += wcslen((WCHAR const *) pCTL->pCtlInfo->ListIdentifier.pbData) + 1;
|
|
cAE++;
|
|
}
|
|
if (0 == cAE)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_NO_AUTOENROLL_OBJECT));
|
|
wprintf(wszNewLine);
|
|
}
|
|
else
|
|
{
|
|
pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
|
|
if (NULL == pwsz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
*ppwszzTemplates = pwsz;
|
|
|
|
wprintf(myLoadResourceString(IDS_V1_AUTOENROLLMENT_OBJECTS_COLON));
|
|
while (TRUE)
|
|
{
|
|
pCTL = CertEnumCTLsInStore(hStoreRemote, pCTL);
|
|
if (NULL == pCTL)
|
|
{
|
|
break;
|
|
}
|
|
wprintf(L" %ws\n", pCTL->pCtlInfo->ListIdentifier.pbData);
|
|
wcscpy(pwsz, (WCHAR const *) pCTL->pCtlInfo->ListIdentifier.pbData);
|
|
pwsz += wcslen(pwsz) + 1;
|
|
cAE++;
|
|
}
|
|
*pwsz++ = L'\0';
|
|
CSASSERT(cwc == SAFE_SUBTRACT_POINTERS(pwsz, *ppwszzTemplates));
|
|
}
|
|
wprintf(wszNewLine);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hStoreRemote)
|
|
{
|
|
CertCloseStore(hStoreRemote, 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;
|
|
WCHAR *pwszzTemplates = 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 = CheckForV1AutoenrollmentObject(pwszMachineName, &pwszzTemplates);
|
|
_PrintIfError(hr, "CheckForV1AutoenrollmentObject");
|
|
hrSave = hr;
|
|
|
|
hr = CheckForV1AutoenrolledCertificate(pwszMachineName, pwszzTemplates);
|
|
_PrintIfError(hr, "CheckForV1AutoenrolledCertificate");
|
|
if (S_OK == hrSave && CRYPT_E_NOT_FOUND != hr)
|
|
{
|
|
hrSave = hr;
|
|
}
|
|
}
|
|
hr = cuGetGroupMembership(pwszSamMachine);
|
|
_PrintIfError(hr, "cuGetGroupMembership");
|
|
|
|
hr = hrSave;
|
|
_JumpIfError2(hr, error, "RunEntmon", hr);
|
|
|
|
wprintf(wszNewLine);
|
|
|
|
error:
|
|
if (NULL != pwszzTemplates)
|
|
{
|
|
LocalFree(pwszzTemplates);
|
|
}
|
|
if (NULL != pwszDomain)
|
|
{
|
|
LocalFree(pwszDomain);
|
|
}
|
|
if (NULL != pwszMachine)
|
|
{
|
|
LocalFree(pwszMachine);
|
|
}
|
|
if (NULL != pwszMachineName)
|
|
{
|
|
LocalFree(pwszMachineName);
|
|
}
|
|
return(hr);
|
|
}
|