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.

432 lines
10 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: dstest.cpp
  7. //
  8. // Contents: DS ping test
  9. //
  10. // History: 13-Mar-98 mattt created
  11. //
  12. //---------------------------------------------------------------------------
  13. #include "pch.cpp"
  14. #pragma hdrstop
  15. #include <winldap.h>
  16. #include <ntldap.h>
  17. #include <dsrole.h>
  18. #include <dsgetdc.h>
  19. #include <lmaccess.h>
  20. #include <lmapibuf.h>
  21. #include <cainfop.h>
  22. #include "csldap.h"
  23. #define __dwFILE__ __dwFILE_CERTCLIB_DSTEST_CPP__
  24. #define DS_RETEST_SECONDS 15
  25. HRESULT
  26. myDoesDSExist(
  27. IN BOOL fRetry)
  28. {
  29. HRESULT hr = S_OK;
  30. static BOOL s_fKnowDSExists = FALSE;
  31. static HRESULT s_hrDSExists = HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN);
  32. static FILETIME s_ftNextTest = {0,0};
  33. if (s_fKnowDSExists && (s_hrDSExists != S_OK) && fRetry)
  34. // s_fKnowDSExists = FALSE; // force a retry
  35. {
  36. FILETIME ftCurrent;
  37. GetSystemTimeAsFileTime(&ftCurrent);
  38. // if Compare is < 0 (next < current), force retest
  39. if (0 > CompareFileTime(&s_ftNextTest, &ftCurrent))
  40. s_fKnowDSExists = FALSE;
  41. }
  42. if (!s_fKnowDSExists)
  43. {
  44. FILETIME ftCurrentNew;
  45. GetSystemTimeAsFileTime(&ftCurrentNew);
  46. // set NEXT in 100ns increments
  47. ((LARGE_INTEGER *) &s_ftNextTest)->QuadPart =
  48. ((LARGE_INTEGER *) &ftCurrentNew)->QuadPart +
  49. (__int64) (CVT_BASE * CVT_SECONDS) * DS_RETEST_SECONDS;
  50. // NetApi32 is delay loaded, so wrap to catch problems when it's not available
  51. __try
  52. {
  53. DOMAIN_CONTROLLER_INFO *pDCI;
  54. DSROLE_PRIMARY_DOMAIN_INFO_BASIC *pDsRole;
  55. // ensure we're not standalone
  56. pDsRole = NULL;
  57. hr = DsRoleGetPrimaryDomainInformation( // Delayload wrapped
  58. NULL,
  59. DsRolePrimaryDomainInfoBasic,
  60. (BYTE **) &pDsRole);
  61. _PrintIfError(hr, "DsRoleGetPrimaryDomainInformation");
  62. if (S_OK == hr &&
  63. (pDsRole->MachineRole == DsRole_RoleStandaloneServer ||
  64. pDsRole->MachineRole == DsRole_RoleStandaloneWorkstation))
  65. {
  66. hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN);
  67. _PrintError(hr, "DsRoleGetPrimaryDomainInformation(no domain)");
  68. }
  69. if (NULL != pDsRole)
  70. {
  71. DsRoleFreeMemory(pDsRole); // Delayload wrapped
  72. }
  73. if (S_OK == hr)
  74. {
  75. // not standalone; return info on our DS
  76. pDCI = NULL;
  77. hr = DsGetDcName( // Delayload wrapped
  78. NULL,
  79. NULL,
  80. NULL,
  81. NULL,
  82. DS_DIRECTORY_SERVICE_PREFERRED,
  83. &pDCI);
  84. _PrintIfError(hr, "DsGetDcName");
  85. if (S_OK == hr && 0 == (pDCI->Flags & DS_DS_FLAG))
  86. {
  87. hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
  88. _PrintError(hr, "DsGetDcName(no domain info)");
  89. }
  90. if (NULL != pDCI)
  91. {
  92. NetApiBufferFree(pDCI); // Delayload wrapped
  93. }
  94. }
  95. s_fKnowDSExists = TRUE;
  96. }
  97. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  98. {
  99. }
  100. // else just allow users without netapi flounder with timeouts
  101. // if ds not available...
  102. s_hrDSExists = myHError(hr);
  103. _PrintIfError2(
  104. s_hrDSExists,
  105. "DsRoleGetPrimaryDomainInformation/DsGetDcName",
  106. HRESULT_FROM_WIN32(ERROR_NETWORK_UNREACHABLE));
  107. }
  108. return(s_hrDSExists);
  109. }
  110. HRESULT
  111. myRobustLdapBind(
  112. OUT LDAP **ppldap,
  113. IN BOOL dwFlags) // RLBF_* -- must be BOOL to preserve signature
  114. {
  115. DWORD dwFlags1 = 0;
  116. // for backward compatibility, TRUE implies RLBF_REQUIRE_GC
  117. CSASSERT(TRUE == RLBF_TRUE);
  118. if (RLBF_TRUE & dwFlags)
  119. {
  120. dwFlags |= RLBF_REQUIRE_GC;
  121. dwFlags &= ~RLBF_TRUE;
  122. dwFlags1 |= RLBF_TRUE;
  123. }
  124. return(myRobustLdapBindEx(
  125. dwFlags1, // dwFlags1
  126. dwFlags, // dwFlags2
  127. LDAP_VERSION2,
  128. NULL,
  129. ppldap,
  130. NULL));
  131. }
  132. HRESULT
  133. DCSupportsSigning(
  134. IN LDAP *pld,
  135. OUT BOOL *pfSigningSupported)
  136. {
  137. HRESULT hr;
  138. LDAPMessage *pSearchResult = NULL;
  139. LDAPMessage *pEntry;
  140. LDAP_TIMEVAL timeval;
  141. WCHAR **rgpwszValues;
  142. WCHAR *apwszAttrArray[2];
  143. WCHAR *pwszSupportedCapabilities = LDAP_OPATT_SUPPORTED_CAPABILITIES_W;
  144. *pfSigningSupported = FALSE;
  145. // Query for the ldap server oerational attributes to obtain the default
  146. // naming context.
  147. apwszAttrArray[0] = pwszSupportedCapabilities;
  148. apwszAttrArray[1] = NULL; // this is the sentinel
  149. timeval.tv_sec = csecLDAPTIMEOUT;
  150. timeval.tv_usec = 0;
  151. hr = ldap_search_st(
  152. pld,
  153. NULL, // base
  154. LDAP_SCOPE_BASE,
  155. L"objectClass=*",
  156. apwszAttrArray,
  157. FALSE, // attrsonly
  158. &timeval,
  159. &pSearchResult);
  160. hr = myHLdapError(pld, hr, NULL);
  161. _JumpIfError(hr, error, "ldap_search_st");
  162. pEntry = ldap_first_entry(pld, pSearchResult);
  163. if (NULL == pEntry)
  164. {
  165. hr = myHLdapLastError(pld, NULL);
  166. _JumpError(hr, error, "ldap_first_entry");
  167. }
  168. rgpwszValues = ldap_get_values(pld, pEntry, pwszSupportedCapabilities);
  169. if (NULL != rgpwszValues)
  170. {
  171. DWORD i;
  172. for (i = 0; NULL != rgpwszValues[i]; i++)
  173. {
  174. if (0 == wcscmp(
  175. rgpwszValues[i],
  176. LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG_OID_W))
  177. {
  178. *pfSigningSupported = TRUE;
  179. break;
  180. }
  181. }
  182. ldap_value_free(rgpwszValues);
  183. }
  184. hr = S_OK;
  185. error:
  186. if (NULL != pSearchResult)
  187. {
  188. ldap_msgfree(pSearchResult);
  189. }
  190. return(hr);
  191. }
  192. HRESULT
  193. myRobustLdapBindEx(
  194. IN BOOL dwFlags1, // TRUE --> RLBF_REQUIRE_GC -- both Flags must be BOOL
  195. IN BOOL dwFlags2, // RLBF_* -- TRUE --> RLBF_ATTEMPT_REDISCOVER
  196. IN ULONG uVersion,
  197. OPTIONAL IN WCHAR const *pwszDomainName,
  198. OUT LDAP **ppldap,
  199. OPTIONAL OUT WCHAR **ppwszForestDNSName)
  200. {
  201. HRESULT hr;
  202. BOOL fGC;
  203. BOOL fRediscover;
  204. ULONG ldaperr;
  205. DWORD GetDSNameFlags;
  206. LDAP *pld = NULL;
  207. DWORD LDAPFlags = myGetLDAPFlags();
  208. if (RLBF_TRUE & dwFlags1)
  209. {
  210. dwFlags2 |= RLBF_REQUIRE_GC;
  211. }
  212. if (RLBF_TRUE & dwFlags2)
  213. {
  214. dwFlags2 |= RLBF_ATTEMPT_REDISCOVER;
  215. }
  216. fGC = (RLBF_REQUIRE_GC & dwFlags2)? TRUE : FALSE;
  217. fRediscover = (RLBF_ATTEMPT_REDISCOVER & dwFlags2)? TRUE : FALSE;
  218. GetDSNameFlags = DS_RETURN_DNS_NAME;
  219. if (fGC)
  220. {
  221. GetDSNameFlags |= DS_GC_SERVER_REQUIRED;
  222. }
  223. // bind to ds
  224. while (TRUE)
  225. {
  226. if (NULL != pld)
  227. {
  228. ldap_unbind(pld);
  229. }
  230. pld = ldap_init(
  231. const_cast<WCHAR *>(pwszDomainName),
  232. (LDAPF_SSLENABLE & LDAPFlags)?
  233. (fGC? LDAP_SSL_GC_PORT : LDAP_SSL_PORT) :
  234. (fGC? LDAP_GC_PORT : LDAP_PORT));
  235. if (NULL == pld)
  236. {
  237. hr = myHLdapLastError(NULL, NULL);
  238. if (!fRediscover)
  239. {
  240. _PrintError2(hr, "ldap_init", hr);
  241. fRediscover = TRUE;
  242. continue;
  243. }
  244. _JumpError(hr, error, "ldap_init");
  245. }
  246. if (fRediscover)
  247. {
  248. GetDSNameFlags |= DS_FORCE_REDISCOVERY;
  249. }
  250. ldaperr = ldap_set_option(
  251. pld,
  252. LDAP_OPT_GETDSNAME_FLAGS,
  253. (VOID *) &GetDSNameFlags);
  254. if (LDAP_SUCCESS != ldaperr)
  255. {
  256. hr = myHLdapError(pld, ldaperr, NULL);
  257. if (!fRediscover)
  258. {
  259. _PrintError2(hr, "ldap_set_option", hr);
  260. fRediscover = TRUE;
  261. continue;
  262. }
  263. _JumpError(hr, error, "ldap_set_option");
  264. }
  265. // if uVersion is 0, turn on TCP_KEEPALIVE
  266. if (0 == uVersion)
  267. {
  268. ldaperr = ldap_set_option(pld, LDAP_OPT_TCP_KEEPALIVE, LDAP_OPT_ON);
  269. if (LDAP_SUCCESS != ldaperr)
  270. {
  271. hr = myHLdapError(pld, ldaperr, NULL);
  272. if (!fRediscover)
  273. {
  274. _PrintError2(hr, "ldap_set_option", hr);
  275. fRediscover = TRUE;
  276. continue;
  277. }
  278. _JumpError2(hr, error, "ldap_set_option", hr);
  279. }
  280. // set the uVersion to LDAP_VERSION3
  281. uVersion = LDAP_VERSION3;
  282. }
  283. // set the client version. No need to set LDAP_VERSION2 since
  284. // this is the default
  285. if (LDAP_VERSION2 != uVersion)
  286. {
  287. ldaperr = ldap_set_option(pld, LDAP_OPT_VERSION, &uVersion);
  288. if (LDAP_SUCCESS != ldaperr)
  289. {
  290. hr = myHLdapError(pld, ldaperr, NULL);
  291. if (!fRediscover)
  292. {
  293. _PrintError2(hr, "ldap_set_option", hr);
  294. fRediscover = TRUE;
  295. continue;
  296. }
  297. _JumpError(hr, error, "ldap_set_option");
  298. }
  299. }
  300. if (0 == (LDAPF_SIGNDISABLE & LDAPFlags) && IsWhistler())
  301. {
  302. BOOL fSigningSupported = TRUE;
  303. // if caller requires the related DS bug fix...
  304. if (RLBF_REQUIRE_LDAP_INTEG & dwFlags2)
  305. {
  306. hr = DCSupportsSigning(pld, &fSigningSupported);
  307. _JumpIfError(hr, error, "DCSupportsSigning");
  308. }
  309. if (fSigningSupported)
  310. {
  311. ldaperr = ldap_set_option(pld, LDAP_OPT_SIGN, LDAP_OPT_ON);
  312. if (LDAP_SUCCESS != ldaperr)
  313. {
  314. hr = myHLdapError2(pld, ldaperr, LDAP_PARAM_ERROR, NULL);
  315. if (!fRediscover)
  316. {
  317. _PrintError2(hr, "ldap_set_option", hr);
  318. fRediscover = TRUE;
  319. continue;
  320. }
  321. _JumpError(hr, error, "ldap_set_option");
  322. }
  323. }
  324. else
  325. if (0 == (LDAPF_SSLENABLE & LDAPFlags) &&
  326. (RLBF_REQUIRE_SECURE_LDAP & dwFlags2))
  327. {
  328. hr = CERTSRV_E_DOWNLEVEL_DC_SSL_OR_UPGRADE;
  329. _JumpError(hr, error, "server missing required service pack");
  330. }
  331. }
  332. ldaperr = ldap_bind_s(pld, NULL, NULL, LDAP_AUTH_NEGOTIATE);
  333. if (LDAP_SUCCESS != ldaperr)
  334. {
  335. hr = myHLdapError(pld, ldaperr, NULL);
  336. if (!fRediscover)
  337. {
  338. _PrintError2(hr, "ldap_bind_s", hr);
  339. fRediscover = TRUE;
  340. continue;
  341. }
  342. _JumpError(hr, error, "ldap_bind_s");
  343. }
  344. if (NULL != ppwszForestDNSName)
  345. {
  346. WCHAR *pwszDomainControllerName;
  347. hr = myLdapGetDSHostName(pld, &pwszDomainControllerName);
  348. if (S_OK != hr)
  349. {
  350. if (!fRediscover)
  351. {
  352. _PrintError2(hr, "myLdapGetDSHostName", hr);
  353. fRediscover = TRUE;
  354. continue;
  355. }
  356. _JumpError(hr, error, "myLdapGetDSHostName");
  357. }
  358. hr = myDupString(pwszDomainControllerName, ppwszForestDNSName);
  359. _JumpIfError(hr, error, "myDupString");
  360. }
  361. break;
  362. }
  363. *ppldap = pld;
  364. pld = NULL;
  365. hr = S_OK;
  366. error:
  367. if (NULL != pld)
  368. {
  369. ldap_unbind(pld);
  370. }
  371. return(hr);
  372. }