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.

1127 lines
26 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 2000
  6. //
  7. // File: info.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include <pch.cpp>
  11. #pragma hdrstop
  12. #include <certca.h>
  13. #include <ntdsapi.h>
  14. #include <dsgetdc.h>
  15. #include <lmerr.h>
  16. #include <lmaccess.h>
  17. #include <lmapibuf.h>
  18. #define __dwFILE__ __dwFILE_CERTUTIL_INFO_CPP__
  19. #define DC_DELBAD 0x00000001
  20. #define DC_DELALL 0x00000002
  21. #define DC_VERIFY 0x00000004
  22. // If you invoke DSSTORE with DC=mydc,DC=rd,DC=com DSSTORE calls
  23. // DsGetDcName(NULL, L"mydc", NULL, NULL, DS_RETURN_DNS_NAME, &pDCInfo);
  24. //
  25. // I suspect changing the code to pass L"mydc.rd.com" instead of L"mydc" would
  26. // solve the problem. I will look into this for the port of the code to
  27. // certutil.exe.
  28. //
  29. // -----Original Message-----
  30. // From: Christophe Lapeyre (Intl Vendor)
  31. // Sent: Tuesday, January 09, 2001 3:30 AM
  32. // To: Certificate Server Discussion Alias
  33. // Subject: DSSTORE error 1355 (DsGetDCName failed)
  34. //
  35. //
  36. // Hi all,
  37. //
  38. // I encountered the following problem with the DSSTORE tool:
  39. //
  40. // DSSTORE DC=mydc,DC=rd,DC=com -display
  41. // DsGetDCName failed! - rc=1355 GLE - 3e5
  42. // DsGetDCName failed! - rc=1355 GLE - 3e5
  43. //
  44. // Nltest /dsgetdc:mydc.rd.com just run ok.
  45. //
  46. // My Netbios domain name is different from my DNS domain name.
  47. //
  48. //
  49. //
  50. // There is a preview Kb article numbered Q280122, but I haven't been able to
  51. // find a fix for this.
  52. HRESULT
  53. ExtractCertSubject(
  54. IN CERT_CONTEXT const *pcc,
  55. IN DWORD dwType,
  56. IN DWORD dwFlags,
  57. OUT WCHAR **ppwszOut)
  58. {
  59. HRESULT hr;
  60. DWORD cwc;
  61. DWORD cwcBuf;
  62. WCHAR *pwszOut = NULL;
  63. *ppwszOut = NULL;
  64. cwcBuf = 0;
  65. while (TRUE)
  66. {
  67. cwc = CertGetNameString(
  68. pcc,
  69. dwType,
  70. dwFlags,
  71. NULL, // pvTypePara
  72. pwszOut,
  73. cwcBuf);
  74. if (1 == cwc)
  75. {
  76. hr = CRYPT_E_NOT_FOUND;
  77. _JumpError(hr, error, "CertGetNameString");
  78. }
  79. if (NULL != pwszOut)
  80. {
  81. break;
  82. }
  83. pwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  84. if (NULL == pwszOut)
  85. {
  86. hr = E_OUTOFMEMORY;
  87. _JumpError(hr, error, "LocalAlloc");
  88. }
  89. cwcBuf = cwc;
  90. }
  91. *ppwszOut = pwszOut;
  92. pwszOut = NULL;
  93. hr = S_OK;
  94. error:
  95. if (NULL != pwszOut)
  96. {
  97. LocalFree(pwszOut);
  98. }
  99. return(hr);
  100. }
  101. static WCHAR *s_apwszKDCTemplates[] = {
  102. wszCERTTYPE_DC_AUTH,
  103. wszCERTTYPE_DS_EMAIL_REPLICATION,
  104. wszCERTTYPE_DC,
  105. };
  106. HRESULT
  107. CheckForKDCCertificate(
  108. IN WCHAR const *pwszDC,
  109. IN DWORD dwFlags)
  110. {
  111. HRESULT hr;
  112. HCERTSTORE hStoreRemote = NULL;
  113. WCHAR wszStorePath[512];
  114. WCHAR *apwszCertType[2] = { NULL, NULL };
  115. DWORD cCert = 0;
  116. DWORD dwOpenFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  117. CERT_CONTEXT const *pcc = NULL;
  118. CERT_CONTEXT const *pccPrev = NULL;
  119. BOOL fDelete;
  120. BOOL fNewLine;
  121. DWORD i;
  122. DWORD j;
  123. CERT_ENHKEY_USAGE *pUsage = NULL;
  124. // If not doing delete operations, open "ReadOnly"
  125. if (0 == ((DC_DELALL | DC_DELBAD) & dwFlags))
  126. {
  127. dwOpenFlags |= CERT_STORE_READONLY_FLAG;
  128. }
  129. swprintf(wszStorePath, L"\\\\%ws\\" wszMY_CERTSTORE, pwszDC);
  130. hStoreRemote = CertOpenStore(
  131. CERT_STORE_PROV_SYSTEM_W,
  132. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  133. NULL,
  134. dwOpenFlags,
  135. (VOID *) wszStorePath);
  136. if (NULL == hStoreRemote)
  137. {
  138. hr = myHLastError();
  139. _JumpError2(hr, error, "CertOpenStore", E_ACCESSDENIED);
  140. }
  141. wprintf(
  142. myLoadResourceString(IDS_FORMAT_KDCCERTS), // "** KDC Certificates for DC %ws"
  143. pwszDC);
  144. wprintf(wszNewLine);
  145. // Look for KDC certs
  146. fNewLine = FALSE;
  147. while (TRUE)
  148. {
  149. BOOL fKDCCert;
  150. for (i = 0; i < ARRAYSIZE(apwszCertType); i++)
  151. {
  152. if (NULL != apwszCertType[i])
  153. {
  154. LocalFree(apwszCertType[i]);
  155. apwszCertType[i] = NULL;
  156. }
  157. }
  158. pcc = CertEnumCertificatesInStore(hStoreRemote, pccPrev);
  159. if (NULL == pcc)
  160. {
  161. hr = myHLastError();
  162. _PrintError2(hr, "CertEnumCertificatesInStore", CRYPT_E_NOT_FOUND);
  163. break;
  164. }
  165. pccPrev = pcc;
  166. fKDCCert = FALSE;
  167. hr = cuGetCertType(
  168. pcc->pCertInfo,
  169. &apwszCertType[0], // ppwszCertTypeNameV1
  170. NULL, // ppwszDisplayNameV1
  171. NULL, // ppwszCertTypeObjId
  172. &apwszCertType[1], // ppwszCertTypeName
  173. NULL); // ppwszDisplayName
  174. if (S_OK != hr)
  175. {
  176. _PrintError(hr, "cuGetCertType");
  177. }
  178. else
  179. {
  180. for (i = 0; i < ARRAYSIZE(apwszCertType); i++)
  181. {
  182. if (NULL != apwszCertType[i])
  183. {
  184. for (j = 0; j < ARRAYSIZE(s_apwszKDCTemplates); j++)
  185. {
  186. if (0 == mylstrcmpiS(
  187. apwszCertType[i],
  188. s_apwszKDCTemplates[j]))
  189. {
  190. fKDCCert = TRUE;
  191. }
  192. }
  193. }
  194. }
  195. }
  196. if (!fKDCCert)
  197. {
  198. WCHAR const *pwsz = apwszCertType[0];
  199. if (NULL == apwszCertType[0])
  200. {
  201. pwsz = apwszCertType[1];
  202. }
  203. if (g_fVerbose)
  204. {
  205. wprintf(
  206. myLoadResourceString(IDS_FORMAT_CERT_TYPE_NOT_DC),
  207. pwsz);
  208. wprintf(wszNewLine);
  209. }
  210. }
  211. if (NULL != pUsage)
  212. {
  213. LocalFree(pUsage);
  214. pUsage = NULL;
  215. }
  216. hr = myCertGetEnhancedKeyUsage(
  217. pcc,
  218. CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
  219. &pUsage);
  220. if (S_OK != hr)
  221. {
  222. _PrintError2(hr, "myCertGetEnhancedKeyUsage", CRYPT_E_NOT_FOUND);
  223. }
  224. else
  225. {
  226. for (i = 0; i < pUsage->cUsageIdentifier; i++)
  227. {
  228. if (0 == strcmp(
  229. szOID_KP_SMARTCARD_LOGON,
  230. pUsage->rgpszUsageIdentifier[i]))
  231. {
  232. fKDCCert = TRUE;
  233. break;
  234. }
  235. }
  236. }
  237. if (!fKDCCert)
  238. {
  239. if (g_fVerbose)
  240. {
  241. wprintf(
  242. myLoadResourceString(IDS_FORMAT_CERT_USAGE_MISSING),
  243. L"szOID_KP_SMARTCARD_LOGON");
  244. wprintf(wszNewLine);
  245. }
  246. if (!g_fForce || fDelete)
  247. {
  248. continue;
  249. }
  250. }
  251. // Cert passed test, dump issuer and subject
  252. wprintf(myLoadResourceString(IDS_FORMAT_CERT_COLON), cCert);
  253. wprintf(wszNewLine);
  254. hr = cuDumpAsnBinaryQuiet(
  255. pcc->pbCertEncoded,
  256. pcc->cbCertEncoded,
  257. MAXDWORD);
  258. _PrintIfError(hr, "cuDumpAsnBinaryQuiet");
  259. wprintf(wszNewLine);
  260. cCert++;
  261. // perform operations on certificatess
  262. fDelete = 0 != (DC_DELALL & dwFlags);
  263. if ((DC_VERIFY | DC_DELBAD) & dwFlags)
  264. {
  265. char *apszUsage[] =
  266. {
  267. szOID_PKIX_KP_SERVER_AUTH,
  268. szOID_KP_SMARTCARD_LOGON,
  269. };
  270. DWORD VerifyState;
  271. hr = cuVerifyCertContext(
  272. pcc,
  273. NULL,
  274. ARRAYSIZE(apszUsage),
  275. apszUsage,
  276. 0, // cIssuancePolicies
  277. NULL, // apszIssuancePolicies
  278. TRUE, // fNTAuth
  279. &VerifyState);
  280. if (S_OK != hr)
  281. {
  282. _PrintError(hr, "cuVerifyCertContext");
  283. if (CRYPT_E_REVOCATION_OFFLINE != hr)
  284. {
  285. fDelete = 0 != (DC_DELBAD & dwFlags);
  286. }
  287. }
  288. }
  289. if (fDelete)
  290. {
  291. CERT_CONTEXT const *pccDel;
  292. pccDel = CertDuplicateCertificateContext(pcc);
  293. if (!CertDeleteCertificateFromStore(pccDel))
  294. {
  295. hr = myHLastError();
  296. wprintf(myLoadResourceString(IDS_FORMAT_DELETE_CERT_FROM_STORE_FAILED), hr);
  297. wprintf(wszNewLine);
  298. }
  299. else
  300. {
  301. wprintf(myLoadResourceString(IDS_FORMAT_DELETE_DC_CERT));
  302. wprintf(wszNewLine);
  303. }
  304. }
  305. }
  306. swprintf(wszStorePath, myLoadResourceString(IDS_FORMAT_KDC_PATH), cCert, pwszDC);
  307. wprintf(wszStorePath);
  308. wprintf(wszNewLine);
  309. if (0 == cCert)
  310. {
  311. wprintf(myLoadResourceString(IDS_NO_KDC_MY_STORE));
  312. wprintf(wszNewLine);
  313. hr = CRYPT_E_NOT_FOUND;
  314. _JumpError(hr, error, "cCert");
  315. }
  316. hr = S_OK;
  317. error:
  318. if (NULL != pUsage)
  319. {
  320. LocalFree(pUsage);
  321. }
  322. for (i = 0; i < ARRAYSIZE(apwszCertType); i++)
  323. {
  324. if (NULL != apwszCertType[i])
  325. {
  326. LocalFree(apwszCertType[i]);
  327. }
  328. }
  329. if (NULL != hStoreRemote)
  330. {
  331. CertCloseStore(hStoreRemote, 0);
  332. }
  333. return(hr);
  334. }
  335. // This function queries the access token specified by the hToken parameter,
  336. // and returns an allocated copy of the TokenUser information on success.
  337. //
  338. // The access token specified by hToken must be opened for TOKEN_QUERY access.
  339. //
  340. // On success, the return value is TRUE. The caller is responsible for freeing
  341. // the resultant UserSid via LocalFree.
  342. //
  343. // On failure, the caller does not need to free any buffer.
  344. HRESULT
  345. GetTokenUserSid(
  346. IN HANDLE hToken, // token to query
  347. IN OUT PSID *ppUserSid) // resultant user sid
  348. {
  349. HRESULT hr;
  350. BYTE FastBuffer[256];
  351. BYTE *SlowBuffer = NULL;
  352. TOKEN_USER *ptgUser;
  353. DWORD cbBuffer;
  354. DWORD cbSid;
  355. *ppUserSid = NULL;
  356. // try querying based on a fast stack based buffer first.
  357. ptgUser = (TOKEN_USER *) FastBuffer;
  358. cbBuffer = sizeof(FastBuffer);
  359. if (!GetTokenInformation(
  360. hToken, // identifies access token
  361. TokenUser, // TokenUser info type
  362. ptgUser, // retrieved info buffer
  363. cbBuffer, // size of buffer passed-in
  364. &cbBuffer)) // required buffer size
  365. {
  366. hr = myHLastError();
  367. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  368. {
  369. _JumpError(hr, error, "GetTokenInformation");
  370. }
  371. // try again with the specified buffer size
  372. SlowBuffer = (BYTE *) LocalAlloc(LMEM_FIXED, cbBuffer);
  373. if (NULL == SlowBuffer)
  374. {
  375. hr = E_OUTOFMEMORY;
  376. _JumpError(hr, error, "LocalAlloc");
  377. }
  378. ptgUser = (TOKEN_USER *) SlowBuffer;
  379. if (!GetTokenInformation(
  380. hToken, // identifies access token
  381. TokenUser, // TokenUser info type
  382. ptgUser, // retrieved info buffer
  383. cbBuffer, // size of buffer passed-in
  384. &cbBuffer)) // required buffer size
  385. {
  386. hr = myHLastError();
  387. _JumpError(hr, error, "GetTokenInformation");
  388. }
  389. }
  390. // if we got the token info, copy the relevant element for the caller.
  391. cbSid = GetLengthSid(ptgUser->User.Sid);
  392. *ppUserSid = LocalAlloc(LMEM_FIXED, cbSid);
  393. if (NULL == *ppUserSid)
  394. {
  395. hr = E_OUTOFMEMORY;
  396. _JumpError(hr, error, "LocalAlloc");
  397. }
  398. if (!CopySid(cbSid, *ppUserSid, ptgUser->User.Sid))
  399. {
  400. hr = myHLastError();
  401. _JumpError(hr, error, "CopySid");
  402. }
  403. hr = S_OK;
  404. error:
  405. if (S_OK != hr)
  406. {
  407. if (NULL != *ppUserSid)
  408. {
  409. LocalFree(*ppUserSid);
  410. *ppUserSid = NULL;
  411. }
  412. }
  413. if (NULL != SlowBuffer)
  414. {
  415. LocalFree(SlowBuffer);
  416. }
  417. return(hr);
  418. }
  419. // This routine obtains a domain controller computer name associated with
  420. // the account related to the hToken access token.
  421. //
  422. // hToken should be opened for TOKEN_QUERY access.
  423. // pwszDomain should be of size (UNCLEN+1)
  424. HRESULT
  425. GetDomainControllers(
  426. OPTIONAL IN WCHAR const *pwszDomain,
  427. IN HANDLE hToken,
  428. OUT DS_DOMAIN_CONTROLLER_INFO_1 **ppDCInfoOut,
  429. OUT DWORD *pcDC)
  430. {
  431. HRESULT hr;
  432. PSID pSidUser = NULL; // sid of client user.
  433. WCHAR wszUserName[UNLEN + 1];
  434. DWORD cwcUserName;
  435. WCHAR wszDomainName[DNLEN + 1]; // domain we want a controller for.
  436. DWORD cwcDomainName;
  437. SID_NAME_USE snu;
  438. DOMAIN_CONTROLLER_INFO *pDomainInfo = NULL;
  439. DS_DOMAIN_CONTROLLER_INFO_1 *pDcInfo = NULL;
  440. HANDLE hDS = INVALID_HANDLE_VALUE;
  441. BOOL fSuccess = FALSE;
  442. *ppDCInfoOut = NULL;
  443. if (NULL == pwszDomain)
  444. {
  445. // first, get the user sid associated with the specified access token.
  446. hr = GetTokenUserSid(hToken, &pSidUser);
  447. _JumpIfError(hr, error, "GetTokenUserSid");
  448. // next, lookup the domain name associated with the specified account.
  449. cwcUserName = ARRAYSIZE(wszUserName);
  450. cwcDomainName = ARRAYSIZE(wszDomainName);
  451. if (!LookupAccountSid(
  452. NULL,
  453. pSidUser,
  454. wszUserName,
  455. &cwcUserName,
  456. wszDomainName,
  457. &cwcDomainName,
  458. &snu))
  459. {
  460. hr = myHLastError();
  461. _JumpError(hr, error, "LookupAccountSid");
  462. }
  463. }
  464. else
  465. {
  466. wcscpy(wszDomainName, pwszDomain);
  467. }
  468. hr = DsGetDcName(
  469. NULL,
  470. wszDomainName,
  471. NULL,
  472. NULL,
  473. DS_RETURN_DNS_NAME,
  474. &pDomainInfo);
  475. _JumpIfError(hr, error, "DsGetDcName");
  476. // Get a handle to the DS on that machine
  477. hr = DsBind(pDomainInfo->DomainControllerName, NULL, &hDS);
  478. _JumpIfError(hr, error, "DsBind");
  479. // Use the handle to enumerate all of the DCs
  480. hr = DsGetDomainControllerInfo(
  481. hDS,
  482. pDomainInfo->DomainName,
  483. 1, // info level
  484. pcDC,
  485. (VOID **) ppDCInfoOut);
  486. _JumpIfError(hr, error, "DsGetDomainControllerInfo");
  487. error:
  488. if (INVALID_HANDLE_VALUE != hDS)
  489. {
  490. DsUnBind(&hDS);
  491. }
  492. if (NULL != pDomainInfo)
  493. {
  494. NetApiBufferFree(pDomainInfo);
  495. }
  496. if (NULL != pSidUser)
  497. {
  498. LocalFree(pSidUser);
  499. }
  500. return(hr);
  501. }
  502. HRESULT
  503. OpenRemoteEnterpriseRoot(
  504. IN WCHAR const *pwszDC)
  505. {
  506. HRESULT hr;
  507. HCERTSTORE hStoreRemote = NULL;
  508. WCHAR wszStorePath[512];
  509. DWORD cCert = 0;
  510. CERT_CONTEXT const *pcc = NULL;
  511. CERT_CONTEXT const *pccPrev;
  512. swprintf(wszStorePath, L"\\\\%ws\\" wszROOT_CERTSTORE, pwszDC);
  513. hStoreRemote = CertOpenStore(
  514. CERT_STORE_PROV_SYSTEM_W,
  515. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  516. NULL,
  517. CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE |
  518. CERT_STORE_READONLY_FLAG,
  519. (VOID *) wszStorePath);
  520. if (NULL == hStoreRemote)
  521. {
  522. hr = myHLastError();
  523. _JumpError2(hr, error, "CertOpenStore", E_ACCESSDENIED);
  524. }
  525. wprintf(
  526. myLoadResourceString(IDS_FORMAT_DCROOTCERTS), // "** Enterprise Root Certificates for DC %ws"
  527. pwszDC);
  528. wprintf(wszNewLine);
  529. // Dump issuer of enterprise roots.
  530. pccPrev = NULL;
  531. while (TRUE)
  532. {
  533. pcc = CertEnumCertificatesInStore(hStoreRemote, pccPrev);
  534. if (NULL == pcc)
  535. {
  536. hr = myHLastError();
  537. _PrintError2(hr, "CertEnumCertificatesInStore", CRYPT_E_NOT_FOUND);
  538. break;
  539. }
  540. wprintf(myLoadResourceString(IDS_FORMAT_CERT_COLON), cCert);
  541. wprintf(wszNewLine);
  542. hr = cuDumpAsnBinaryQuiet(
  543. pcc->pbCertEncoded,
  544. pcc->cbCertEncoded,
  545. MAXDWORD);
  546. _PrintIfError(hr, "cuDumpAsnBinaryQuiet");
  547. wprintf(wszNewLine);
  548. cCert++;
  549. pccPrev = pcc;
  550. }
  551. if (0 == cCert)
  552. {
  553. wprintf(myLoadResourceString(IDS_NO_KDC_ENT_STORE));
  554. wprintf(wszNewLine);
  555. hr = CRYPT_E_NOT_FOUND;
  556. }
  557. hr = S_OK;
  558. error:
  559. if (NULL != hStoreRemote)
  560. {
  561. CertCloseStore(hStoreRemote, 0);
  562. }
  563. return(hr);
  564. }
  565. HRESULT
  566. verbDCInfo(
  567. IN WCHAR const *pwszOption,
  568. OPTIONAL IN WCHAR const *pwszFlags,
  569. IN WCHAR const *pwszArg2,
  570. IN WCHAR const *pwszArg3,
  571. IN WCHAR const *pwszArg4)
  572. {
  573. HRESULT hr;
  574. HRESULT hrSave;
  575. HANDLE hToken = NULL;
  576. DS_DOMAIN_CONTROLLER_INFO_1 *pDcInfo = NULL;
  577. DWORD cDC = 0;
  578. DWORD dwFlags;
  579. DWORD i;
  580. WCHAR *pwszDomain = NULL;
  581. dwFlags = 0;
  582. if (NULL != pwszFlags)
  583. {
  584. if (0 == LSTRCMPIS(pwszFlags, L"DeleteAll"))
  585. {
  586. dwFlags = DC_DELALL;
  587. }
  588. else
  589. if (0 == LSTRCMPIS(pwszFlags, L"DeleteBad"))
  590. {
  591. dwFlags = DC_DELBAD | DC_VERIFY;
  592. }
  593. else
  594. if (0 == LSTRCMPIS(pwszFlags, L"Verify"))
  595. {
  596. dwFlags = DC_VERIFY;
  597. }
  598. else
  599. {
  600. hr = E_INVALIDARG;
  601. _JumpError(hr, error, "bad Flags");
  602. }
  603. }
  604. // Grovel the process token for user identity. Used in determining
  605. // target domain
  606. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
  607. {
  608. hr = myHLastError();
  609. _JumpError(hr, error, "OpenProcessToken");
  610. }
  611. // Use DS APIs to get all of the DCs in our domain
  612. hr = GetDomainControllers(pwszDomain, hToken, &pDcInfo, &cDC);
  613. _JumpIfError(hr, error, "GetDomainControllers");
  614. for (i = 0; i < cDC; i++)
  615. {
  616. wprintf(L"%u: %ws\n", i, pDcInfo[i].NetbiosName);
  617. }
  618. hrSave = S_OK;
  619. for (i = 0; i < cDC; i++)
  620. {
  621. WCHAR wszBuffer[512];
  622. wprintf(wszNewLine);
  623. wprintf(
  624. myLoadResourceString(IDS_FORMAT_TESTINGDC), // "*** Testing DC[%u]: %ws"
  625. i,
  626. pDcInfo[i].NetbiosName);
  627. wprintf(wszNewLine);
  628. // Is DC available ?
  629. wsprintf(wszBuffer, L"\\\\%ws\\netlogon", pDcInfo[i].NetbiosName);
  630. if (MAXDWORD == GetFileAttributes(wszBuffer))
  631. {
  632. hr = myHLastError();
  633. _PrintError2(hr, "GetFileAttributes", hr);
  634. cuPrintError(IDS_DCUNAVAILABLE, hr);
  635. if (S_OK == hrSave)
  636. {
  637. hrSave = hr;
  638. }
  639. continue;
  640. }
  641. // Open the enterprise root store, and make sure it's got the
  642. // NTDEV ROOT CERTIFICATE (subject #defined above)
  643. hr = OpenRemoteEnterpriseRoot(pDcInfo[i].NetbiosName);
  644. if (S_OK != hr)
  645. {
  646. _PrintError2(hr, "OpenRemoteEnterpriseRoot", hr);
  647. cuPrintError(IDS_REMOTEENTROOT, hr);
  648. if (S_OK == hrSave)
  649. {
  650. hrSave = hr;
  651. }
  652. }
  653. // Make sure the machine has a *valid* KDC certificate
  654. hr = CheckForKDCCertificate(
  655. pDcInfo[i].NetbiosName,
  656. dwFlags);
  657. if (S_OK != hr)
  658. {
  659. _PrintError2(hr, "CheckForKDCCertificate", hr);
  660. cuPrintError(IDS_REMOTEKDCCERT, hr);
  661. if (S_OK == hrSave)
  662. {
  663. hrSave = hr;
  664. }
  665. }
  666. }
  667. wprintf(wszNewLine);
  668. hr = hrSave;
  669. _JumpIfError2(hr, error, "verbDCInfo", hr);
  670. error:
  671. if (NULL != pDcInfo)
  672. {
  673. DsFreeDomainControllerInfo(1, cDC, pDcInfo);
  674. }
  675. return(hr);
  676. }
  677. BOOL
  678. IsAutoenrolledCert(
  679. IN CERT_CONTEXT const *pcc,
  680. OPTIONAL IN WCHAR const *pwszzTemplates)
  681. {
  682. HRESULT hr;
  683. BOOL fMatch = FALSE;
  684. WCHAR *pwszTemplate = NULL;
  685. WCHAR const *pwsz;
  686. hr = cuGetCertType(pcc->pCertInfo, &pwszTemplate, NULL, NULL, NULL, NULL);
  687. if (S_OK != hr)
  688. {
  689. _PrintError(hr, "cuGetCertType");
  690. if (CRYPT_E_NOT_FOUND == hr)
  691. {
  692. hr = S_OK;
  693. }
  694. goto error;
  695. }
  696. pwsz = pwszzTemplates;
  697. if (NULL != pwsz)
  698. {
  699. for ( ; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
  700. {
  701. if (0 == mylstrcmpiL(pwsz, pwszTemplate))
  702. {
  703. fMatch = TRUE;
  704. break;
  705. }
  706. }
  707. }
  708. if (!fMatch)
  709. {
  710. DWORD i;
  711. for (i = 0; i < ARRAYSIZE(s_apwszKDCTemplates); i++)
  712. {
  713. if (0 == mylstrcmpiS(pwszTemplate, s_apwszKDCTemplates[i]))
  714. {
  715. fMatch = TRUE;
  716. }
  717. }
  718. }
  719. error:
  720. if (NULL != pwszTemplate)
  721. {
  722. LocalFree(pwszTemplate);
  723. }
  724. return(fMatch);
  725. }
  726. //
  727. // Check for autoenrolled certificate
  728. //
  729. HRESULT
  730. CheckForV1AutoenrolledCertificate(
  731. IN WCHAR const *pwszDC,
  732. OPTIONAL IN WCHAR const *pwszzTemplates)
  733. {
  734. HRESULT hr;
  735. HCERTSTORE hStoreRemote = NULL;
  736. WCHAR wszStorePath[512];
  737. DWORD cCert;
  738. DWORD cCertArchived;
  739. DWORD dwArchiveBit;
  740. CERT_CONTEXT const *pcc;
  741. swprintf(wszStorePath, L"\\\\%ws\\" wszMY_CERTSTORE, pwszDC);
  742. hStoreRemote = CertOpenStore(
  743. CERT_STORE_PROV_SYSTEM_W,
  744. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  745. NULL,
  746. CERT_STORE_READONLY_FLAG |
  747. CERT_SYSTEM_STORE_LOCAL_MACHINE |
  748. CERT_STORE_ENUM_ARCHIVED_FLAG,
  749. (VOID *) wszStorePath);
  750. if (NULL == hStoreRemote)
  751. {
  752. hr = myHLastError();
  753. wprintf(myLoadResourceString(IDS_FORMAT_OPEN_REMOTE_MY_FAILED), hr);
  754. wprintf(wszNewLine);
  755. goto error;
  756. }
  757. cCert = 0;
  758. cCertArchived = 0;
  759. pcc = NULL;
  760. while (TRUE)
  761. {
  762. pcc = CertEnumCertificatesInStore(hStoreRemote, pcc);
  763. if (NULL == pcc)
  764. {
  765. break;
  766. }
  767. if (!IsAutoenrolledCert(pcc, pwszzTemplates) && 1 >= g_fForce)
  768. {
  769. continue;
  770. }
  771. // Cert passed test, dump issuer and subject
  772. wprintf(myLoadResourceString(IDS_FORMAT_CERT_COLON), cCert);
  773. wprintf(wszNewLine);
  774. if (!CertGetCertificateContextProperty(
  775. pcc,
  776. CERT_ARCHIVED_PROP_ID,
  777. NULL,
  778. &dwArchiveBit))
  779. {
  780. hr = myHLastError();
  781. if (hr != CRYPT_E_NOT_FOUND)
  782. {
  783. wprintf(myLoadResourceString(IDS_FORMAT_ERROR_GET_ARCHIVE_PROP), hr);
  784. wprintf(wszNewLine);
  785. }
  786. }
  787. else
  788. {
  789. wprintf(myLoadResourceString(IDS_LIST_ARCHIVED_CERT));
  790. wprintf(wszNewLine);
  791. cCertArchived++;
  792. }
  793. hr = cuDumpSerial(g_wszPad2, IDS_SERIAL, &pcc->pCertInfo->SerialNumber);
  794. _PrintIfError(hr, "cuDumpSerial");
  795. hr = cuDisplayCertNames(FALSE, g_wszPad2, pcc->pCertInfo);
  796. _PrintIfError(hr, "cuDisplayCertNames");
  797. hr = cuDumpCertType(g_wszPad2, pcc->pCertInfo);
  798. _PrintIfError2(hr, "cuDumpCertType", CRYPT_E_NOT_FOUND);
  799. hr = cuDisplayHash(
  800. g_wszPad2,
  801. pcc,
  802. NULL,
  803. CERT_SHA1_HASH_PROP_ID,
  804. L"sha1");
  805. _PrintIfError(hr, "cuDisplayHash");
  806. wprintf(wszNewLine);
  807. cCert++;
  808. }
  809. if (0 == cCert)
  810. {
  811. wprintf(myLoadResourceString(IDS_NO_AUTOENROLLED_CERT));
  812. wprintf(wszNewLine);
  813. hr = CRYPT_E_NOT_FOUND;
  814. _JumpError(hr, error, "no AE certs");
  815. }
  816. wprintf(
  817. myLoadResourceString(IDS_FORMAT_MACHINE_AND_ARCHIVED_CERTS),
  818. cCert,
  819. cCertArchived);
  820. wprintf(L" ");
  821. wprintf(myLoadResourceString(IDS_FORMAT_FOR_DC), pwszDC);
  822. wprintf(wszNewLine);
  823. hr = S_OK;
  824. error:
  825. if (NULL != hStoreRemote)
  826. {
  827. CertCloseStore(hStoreRemote, 0);
  828. }
  829. return(hr);
  830. }
  831. HRESULT
  832. CheckForV1AutoenrollmentObject(
  833. IN WCHAR const *pwszDC,
  834. OUT WCHAR **ppwszzTemplates)
  835. {
  836. HRESULT hr;
  837. HCERTSTORE hStoreRemote = NULL;
  838. WCHAR wszStorePath[512];
  839. DWORD cAE;
  840. CTL_CONTEXT const *pCTL;
  841. DWORD cwc;
  842. WCHAR *pwsz;
  843. *ppwszzTemplates = NULL;
  844. swprintf(wszStorePath, L"\\\\%ws\\" wszACRS_CERTSTORE, pwszDC);
  845. hStoreRemote = CertOpenStore(
  846. CERT_STORE_PROV_SYSTEM,
  847. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  848. NULL,
  849. CERT_SYSTEM_STORE_LOCAL_MACHINE |
  850. CERT_STORE_READONLY_FLAG,
  851. (VOID *) wszStorePath);
  852. if (NULL == hStoreRemote)
  853. {
  854. hr = myHLastError();
  855. wprintf(myLoadResourceString(IDS_FORMAT_OPEN_STORE_REMOTE_ENT_FAILED), hr);
  856. wprintf(wszNewLine);
  857. goto error;
  858. }
  859. cwc = 1;
  860. cAE = 0;
  861. pCTL = NULL;
  862. while (TRUE)
  863. {
  864. pCTL = CertEnumCTLsInStore(hStoreRemote, pCTL);
  865. if (NULL == pCTL)
  866. {
  867. break;
  868. }
  869. cwc += wcslen((WCHAR const *) pCTL->pCtlInfo->ListIdentifier.pbData) + 1;
  870. cAE++;
  871. }
  872. if (0 == cAE)
  873. {
  874. wprintf(myLoadResourceString(IDS_NO_AUTOENROLL_OBJECT));
  875. wprintf(wszNewLine);
  876. }
  877. else
  878. {
  879. pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  880. if (NULL == pwsz)
  881. {
  882. hr = E_OUTOFMEMORY;
  883. _JumpError(hr, error, "LocalAlloc");
  884. }
  885. *ppwszzTemplates = pwsz;
  886. wprintf(myLoadResourceString(IDS_V1_AUTOENROLLMENT_OBJECTS_COLON));
  887. while (TRUE)
  888. {
  889. pCTL = CertEnumCTLsInStore(hStoreRemote, pCTL);
  890. if (NULL == pCTL)
  891. {
  892. break;
  893. }
  894. wprintf(L" %ws\n", pCTL->pCtlInfo->ListIdentifier.pbData);
  895. wcscpy(pwsz, (WCHAR const *) pCTL->pCtlInfo->ListIdentifier.pbData);
  896. pwsz += wcslen(pwsz) + 1;
  897. cAE++;
  898. }
  899. *pwsz++ = L'\0';
  900. CSASSERT(cwc == SAFE_SUBTRACT_POINTERS(pwsz, *ppwszzTemplates));
  901. }
  902. wprintf(wszNewLine);
  903. hr = S_OK;
  904. error:
  905. if (NULL != hStoreRemote)
  906. {
  907. CertCloseStore(hStoreRemote, 0);
  908. }
  909. return(hr);
  910. }
  911. //
  912. // This function takes a Marc Jacobs supplied text file (results from SSOLogon
  913. // scripts) and runs through entmon for each machine in the list
  914. //
  915. HRESULT
  916. verbEntInfo(
  917. IN WCHAR const *pwszOption,
  918. IN WCHAR const *pwszSamMachine,
  919. IN WCHAR const *pwszArg2,
  920. IN WCHAR const *pwszArg3,
  921. IN WCHAR const *pwszArg4)
  922. {
  923. HRESULT hr;
  924. HRESULT hrSave;
  925. WCHAR *pwszDomain = NULL;
  926. WCHAR *pwszMachine = NULL;
  927. WCHAR *pwszMachineName = NULL;
  928. WCHAR *pwszzTemplates = NULL;
  929. hr = mySplitConfigString(pwszSamMachine, &pwszDomain, &pwszMachine);
  930. _JumpIfError(hr, error, "mySplitConfigString");
  931. if (NULL == pwszMachine || NULL == wcschr(pwszMachine, L'$'))
  932. {
  933. wprintf(myLoadResourceString(IDS_ERROR_CHECK_MACHINE_NAME));
  934. wprintf(wszNewLine);
  935. hr = E_INVALIDARG;
  936. _JumpError(hr, error, "bad machine name");
  937. }
  938. // knock off trailing $
  939. hr = myDupString(pwszMachine, &pwszMachineName);
  940. _JumpIfError(hr, error, "myDupString");
  941. pwszMachineName[wcslen(pwszMachineName)-1] = L'\0';
  942. // assume for now that we're only interested in opening remote root store
  943. wprintf(myLoadResourceString(IDS_FORMAT_MACHINE_LIST), pwszMachine);
  944. wprintf(wszNewLine);
  945. // Cert store functions, if first fails, bail.
  946. hrSave = S_OK;
  947. hr = OpenRemoteEnterpriseRoot(pwszMachineName);
  948. if (S_OK != hr)
  949. {
  950. cuPrintError(IDS_REMOTEENTROOT, hr);
  951. _PrintError2(hr, "OpenRemoteEnterpriseRoot", hr);
  952. hrSave = hr;
  953. }
  954. else
  955. {
  956. hr = CheckForV1AutoenrollmentObject(pwszMachineName, &pwszzTemplates);
  957. _PrintIfError(hr, "CheckForV1AutoenrollmentObject");
  958. hrSave = hr;
  959. hr = CheckForV1AutoenrolledCertificate(pwszMachineName, pwszzTemplates);
  960. _PrintIfError(hr, "CheckForV1AutoenrolledCertificate");
  961. if (S_OK == hrSave && CRYPT_E_NOT_FOUND != hr)
  962. {
  963. hrSave = hr;
  964. }
  965. }
  966. hr = cuGetGroupMembership(pwszSamMachine);
  967. _PrintIfError(hr, "cuGetGroupMembership");
  968. hr = hrSave;
  969. _JumpIfError2(hr, error, "RunEntmon", hr);
  970. wprintf(wszNewLine);
  971. error:
  972. if (NULL != pwszzTemplates)
  973. {
  974. LocalFree(pwszzTemplates);
  975. }
  976. if (NULL != pwszDomain)
  977. {
  978. LocalFree(pwszDomain);
  979. }
  980. if (NULL != pwszMachine)
  981. {
  982. LocalFree(pwszMachine);
  983. }
  984. if (NULL != pwszMachineName)
  985. {
  986. LocalFree(pwszMachineName);
  987. }
  988. return(hr);
  989. }