Source code of Windows XP (NT5)
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.

653 lines
16 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. rndutil.cpp
  5. Abstract:
  6. This module contains implementation of rend helper functions.
  7. --*/
  8. #include "stdafx.h"
  9. #include "rndcommc.h"
  10. #include "rndils.h"
  11. #include "rndsec.h"
  12. #include "rndcoll.h"
  13. #include "rnduser.h"
  14. #include "rndldap.h"
  15. #include "rndcnf.h"
  16. //////////////////////////////////////////////////////////////////////////////
  17. // GetDomainControllerName (helper funcion)
  18. //
  19. // This function retrieves the name of the nearest domain controller for the
  20. // machine's domain. It allows the caller to specify flags to indicate if a
  21. // domain controller is desired, etc.
  22. //
  23. // Argument: receives a pointer to a new'ed string containing the name
  24. // of the DC. This is a fully qualified domain name in
  25. // the format "foo.bar.com.", NOT "\\foo.bar.com.".
  26. //
  27. // Returns an HRESULT:
  28. // S_OK : it worked
  29. // E_OUTOFMEMORY : not enough memory to allocate the string
  30. // other : reason for failure of ::DsGetDcName()
  31. //
  32. //////////////////////////////////////////////////////////////////////////////
  33. HRESULT GetDomainControllerName(
  34. IN ULONG ulFlags,
  35. OUT WCHAR ** ppszName
  36. )
  37. {
  38. // We are a helper function, so we only assert...
  39. _ASSERTE( ! IsBadWritePtr( ppszName, sizeof(WCHAR *) ) );
  40. LOG((MSP_TRACE, "GetDomainControllerName: Querying DS..."));
  41. //
  42. // Ask the system for the location of the GC (Global Catalog).
  43. //
  44. DWORD dwCode;
  45. DOMAIN_CONTROLLER_INFO * pDcInfo = NULL;
  46. dwCode = DsGetDcName(
  47. NULL, // LPCWSTR computername, (default: this one)
  48. NULL, // LPCWSTR domainname, (default: this one)
  49. NULL, // guid * domainguid, (default: this one)
  50. NULL, // LPCWSTR sitename, (default: this one)
  51. ulFlags, // ULONG Flags, (what do we want)
  52. &pDcInfo // receives pointer to output structure
  53. );
  54. if ( (dwCode != NO_ERROR) || (pDcInfo == NULL) )
  55. {
  56. LOG((MSP_ERROR, "GetDomainControllerName: "
  57. "DsGetDcName failed; returned %d.\n", dwCode));
  58. return HRESULT_FROM_ERROR_CODE(dwCode);
  59. }
  60. //
  61. // Do a quick sanity check in debug builds. If we get the wrong name we
  62. // will fail right after this, so this is only useful for debugging.
  63. //
  64. // In case we find we need to use the address instead of the name:
  65. // _ASSERTE( pDcInfo->DomainControllerAddressType == DS_INET_ADDRESS );
  66. _ASSERTE( pDcInfo->Flags & DS_GC_FLAG );
  67. //
  68. // If we've got something like "\\foo.bar.com.", skip the "\\".
  69. //
  70. WCHAR * pszName = pDcInfo->DomainControllerName;
  71. while (pszName[0] == '\\')
  72. {
  73. pszName++;
  74. }
  75. LOG((MSP_TRACE, "GetDomainControllerName: DC name is %S", pszName));
  76. //
  77. // Allocate and copy the output string.
  78. //
  79. *ppszName = new WCHAR[lstrlenW(pszName) + 1];
  80. if ( (*ppszName) == NULL)
  81. {
  82. LOG((MSP_ERROR, "GetDomainControllerName: "
  83. "out of memory in string allocation"));
  84. NetApiBufferFree(pDcInfo);
  85. return E_OUTOFMEMORY;
  86. }
  87. lstrcpyW(*ppszName, pszName);
  88. //
  89. // Release the DOMAIN_CONTROLLER_INFO structure.
  90. //
  91. NetApiBufferFree(pDcInfo);
  92. //
  93. // All done.
  94. //
  95. LOG((MSP_TRACE, "GetDomainControllerName: exit S_OK"));
  96. return S_OK;
  97. }
  98. HRESULT CreateDialableAddressEnumerator(
  99. IN BSTR * begin,
  100. IN BSTR * end,
  101. OUT IEnumDialableAddrs ** ppIEnum
  102. )
  103. {
  104. typedef CSafeComEnum<IEnumDialableAddrs, &IID_IEnumDialableAddrs,
  105. BSTR, _CopyBSTR> CEnumerator;
  106. HRESULT hr;
  107. CComObject<CEnumerator> *pEnum = NULL;
  108. hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
  109. if (pEnum == NULL)
  110. {
  111. LOG((MSP_ERROR, "Could not create enumerator object, %x", hr));
  112. return hr;
  113. }
  114. hr = pEnum->Init(begin, end, NULL, AtlFlagTakeOwnership);
  115. if (FAILED(hr))
  116. {
  117. LOG((MSP_ERROR, "init enumerator object failed, %x", hr));
  118. delete pEnum;
  119. return hr;
  120. }
  121. // query for the IID_IEnumDirectory i/f
  122. hr = pEnum->_InternalQueryInterface(
  123. IID_IEnumDialableAddrs,
  124. (void**)ppIEnum
  125. );
  126. if (FAILED(hr))
  127. {
  128. LOG((MSP_ERROR, "query enum interface failed, %x", hr));
  129. delete pEnum;
  130. return hr;
  131. }
  132. return hr;
  133. }
  134. HRESULT CreateBstrCollection(
  135. IN long nSize,
  136. IN BSTR * begin,
  137. IN BSTR * end,
  138. OUT VARIANT * pVariant,
  139. CComEnumFlags flags
  140. )
  141. {
  142. // create the collection object
  143. typedef TBstrCollection CCollection;
  144. CComObject<CCollection> * p;
  145. HRESULT hr = CComObject<CCollection>::CreateInstance( &p );
  146. if (NULL == p)
  147. {
  148. LOG((MSP_ERROR, "Could not create Collection object, %x",hr));
  149. return hr;
  150. }
  151. hr = p->Initialize(nSize, begin, end, flags);
  152. if (S_OK != hr)
  153. {
  154. LOG((MSP_ERROR, "Could not initialize Collection object, %x", hr));
  155. delete p;
  156. return hr;
  157. }
  158. IDispatch *pDisp;
  159. // get the IDispatch interface
  160. hr = p->_InternalQueryInterface(IID_IDispatch, (void **)&pDisp);
  161. if (S_OK != hr)
  162. {
  163. LOG((MSP_ERROR, "QI for IDispatch in CreateCollection, %x", hr));
  164. delete p;
  165. return hr;
  166. }
  167. // put it in the variant
  168. VariantInit(pVariant);
  169. pVariant->vt = VT_DISPATCH;
  170. pVariant->pdispVal = pDisp;
  171. return S_OK;
  172. }
  173. HRESULT CreateDirectoryObjectEnumerator(
  174. IN ITDirectoryObject ** begin,
  175. IN ITDirectoryObject ** end,
  176. OUT IEnumDirectoryObject ** ppIEnum
  177. )
  178. {
  179. typedef _CopyInterface<ITDirectoryObject> CCopy;
  180. typedef CSafeComEnum<IEnumDirectoryObject, &IID_IEnumDirectoryObject,
  181. ITDirectoryObject *, CCopy> CEnumerator;
  182. HRESULT hr;
  183. CComObject<CEnumerator> *pEnum = NULL;
  184. hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
  185. if (pEnum == NULL)
  186. {
  187. LOG((MSP_ERROR, "Could not create enumerator object, %x", hr));
  188. return hr;
  189. }
  190. hr = pEnum->Init(begin, end, NULL, AtlFlagCopy);
  191. if (FAILED(hr))
  192. {
  193. LOG((MSP_ERROR, "init enumerator object failed, %x", hr));
  194. delete pEnum;
  195. return hr;
  196. }
  197. // query for the IID_IEnumDirectory i/f
  198. hr = pEnum->_InternalQueryInterface(
  199. IID_IEnumDirectoryObject,
  200. (void**)ppIEnum
  201. );
  202. if (FAILED(hr))
  203. {
  204. LOG((MSP_ERROR, "query enum interface failed, %x", hr));
  205. delete pEnum;
  206. return hr;
  207. }
  208. return hr;
  209. }
  210. HRESULT CreateEmptyUser(
  211. IN BSTR pName,
  212. OUT ITDirectoryObject ** ppDirectoryObject
  213. )
  214. {
  215. HRESULT hr;
  216. CComObject<CUser> * pDirectoryObject;
  217. hr = CComObject<CUser>::CreateInstance(&pDirectoryObject);
  218. if (NULL == pDirectoryObject)
  219. {
  220. LOG((MSP_ERROR, "can't create DirectoryObject user."));
  221. return hr;
  222. }
  223. WCHAR *pCloseBracket = wcschr(pName, CLOSE_BRACKET_CHARACTER);
  224. if ( pCloseBracket != NULL )
  225. {
  226. *pCloseBracket = L'\0';
  227. }
  228. hr = pDirectoryObject->Init(pName);
  229. if (FAILED(hr))
  230. {
  231. LOG((MSP_ERROR, "CreateUser:init failed: %x", hr));
  232. delete pDirectoryObject;
  233. return hr;
  234. }
  235. hr = pDirectoryObject->_InternalQueryInterface(
  236. IID_ITDirectoryObject,
  237. (void **)ppDirectoryObject
  238. );
  239. if (FAILED(hr))
  240. {
  241. LOG((MSP_ERROR, "CreateEmptyUser:QueryInterface failed: %x", hr));
  242. delete pDirectoryObject;
  243. return hr;
  244. }
  245. return S_OK;
  246. }
  247. HRESULT CreateEmptyConference(
  248. IN BSTR pName,
  249. OUT ITDirectoryObject ** ppDirectoryObject
  250. )
  251. {
  252. HRESULT hr;
  253. CComObject<CConference> * pDirectoryObject;
  254. hr = CComObject<CConference>::CreateInstance(&pDirectoryObject);
  255. if (NULL == pDirectoryObject)
  256. {
  257. LOG((MSP_ERROR, "CreateEmptyConference: can't create DirectoryObject conference."));
  258. return hr;
  259. }
  260. hr = pDirectoryObject->Init(pName);
  261. if (FAILED(hr))
  262. {
  263. LOG((MSP_ERROR, "CreateEmptyConference: init failed: %x", hr));
  264. delete pDirectoryObject;
  265. return hr;
  266. }
  267. hr = pDirectoryObject->_InternalQueryInterface(
  268. IID_ITDirectoryObject,
  269. (void **)ppDirectoryObject
  270. );
  271. if (FAILED(hr))
  272. {
  273. LOG((MSP_ERROR, "CreateEmptyConference: QueryInterface failed: %x", hr));
  274. delete pDirectoryObject;
  275. return hr;
  276. }
  277. return S_OK;
  278. }
  279. HRESULT CreateConferenceWithBlob(
  280. IN BSTR pName,
  281. IN BSTR pProtocol,
  282. IN BSTR pBlob,
  283. IN CHAR * pSecurityDescriptor,
  284. IN DWORD dwSDSize,
  285. OUT ITDirectoryObject ** ppDirectoryObject
  286. )
  287. {
  288. //
  289. // This is a helper function; assumes that passed-in pointers are valid.
  290. //
  291. //
  292. // Create a conference object.
  293. //
  294. HRESULT hr;
  295. CComObject<CConference> * pDirectoryObject;
  296. hr = CComObject<CConference>::CreateInstance(&pDirectoryObject);
  297. if (NULL == pDirectoryObject)
  298. {
  299. LOG((MSP_ERROR, "can't create DirectoryObject conference."));
  300. return hr;
  301. }
  302. //
  303. // Get the ITDirectoryObject interface.
  304. //
  305. hr = pDirectoryObject->_InternalQueryInterface(
  306. IID_ITDirectoryObject,
  307. (void **)ppDirectoryObject
  308. );
  309. if (FAILED(hr))
  310. {
  311. LOG((MSP_ERROR, "CreateConference:QueryInterface failed: %x", hr));
  312. delete pDirectoryObject;
  313. *ppDirectoryObject = NULL;
  314. return hr;
  315. }
  316. //
  317. // Init the object.
  318. //
  319. hr = pDirectoryObject->Init(pName, pProtocol, pBlob);
  320. if (FAILED(hr))
  321. {
  322. LOG((MSP_ERROR, "CreateConferenceWithBlob:init failed: %x", hr));
  323. (*ppDirectoryObject)->Release();
  324. *ppDirectoryObject = NULL;
  325. return hr;
  326. }
  327. //
  328. // Set the security descriptor on the object.
  329. //
  330. if (pSecurityDescriptor != NULL)
  331. {
  332. //
  333. // first query the private interface for attributes.
  334. //
  335. ITDirectoryObjectPrivate * pObjectPrivate;
  336. hr = pDirectoryObject->QueryInterface(
  337. IID_ITDirectoryObjectPrivate,
  338. (void **)&pObjectPrivate
  339. );
  340. if ( FAILED(hr) )
  341. {
  342. LOG((MSP_ERROR, "can't get the private directory object "
  343. "interface: 0x%08x", hr));
  344. (*ppDirectoryObject)->Release();
  345. *ppDirectoryObject = NULL;
  346. return hr;
  347. }
  348. //
  349. // Now set the security descriptor in its "converted" (server) form.
  350. //
  351. hr = pObjectPrivate->PutConvertedSecurityDescriptor(
  352. pSecurityDescriptor,
  353. dwSDSize);
  354. pObjectPrivate->Release();
  355. if ( FAILED(hr) )
  356. {
  357. LOG((MSP_ERROR, "PutConvertedSecurityDescriptor failed: %x", hr));
  358. (*ppDirectoryObject)->Release();
  359. *ppDirectoryObject = NULL;
  360. return hr;
  361. }
  362. }
  363. return S_OK;
  364. }
  365. //
  366. // GetCorrectAddressFromHostent
  367. //
  368. // in parameters:
  369. //
  370. // dwInterface -- When picking the IP address from the array of addrs,
  371. // pick the one that is reachable via this local interface.
  372. // If this parameter equals 0, then just pick the first
  373. // one. Network byte order.
  374. // hostp -- pointer to hostent structure to extract from
  375. //
  376. DWORD GetCorrectAddressFromHostent(
  377. DWORD dwInterface,
  378. struct hostent * hostp
  379. )
  380. {
  381. DWORD ** ppAddrs = (DWORD **) hostp->h_addr_list;
  382. if ( dwInterface == 0 )
  383. {
  384. return * ppAddrs[0];
  385. }
  386. for ( int i = 0; ppAddrs[i] != NULL; i++ )
  387. {
  388. if ( dwInterface == ( * ppAddrs[i] ) )
  389. {
  390. return dwInterface;
  391. }
  392. }
  393. //
  394. // If we get here then none of the addresses in the hostent structure
  395. // matched our interface address. This means that we are looking at
  396. // some machine besides the local host. In this case it shouldn't
  397. // matter which address we use.
  398. //
  399. LOG((MSP_WARN, "using first address for multihomed remote machine IP"));
  400. return * ppAddrs[0];
  401. }
  402. //
  403. // ResolveHostName
  404. //
  405. // in parameters:
  406. //
  407. // dwInterface -- When disconvering IP address based on host name, pick
  408. // the one that is reachable via this local interface. If
  409. // this parameter equals 0, then just pick the first one.
  410. // Network byte order.
  411. // pHost -- Must be a valid string pointer. Points to the hostname
  412. // to resolve.
  413. //
  414. // out parameters:
  415. //
  416. // pFullName -- If non-NULL, returns the hostname as returned from DNS.
  417. // pdwIP -- If non-NULL, returns the IP address as returned from
  418. // DNS. Network byte order.
  419. //
  420. HRESULT ResolveHostName(
  421. IN DWORD dwInterface,
  422. IN TCHAR * pHost,
  423. OUT char ** pFullName,
  424. OUT DWORD * pdwIP
  425. )
  426. {
  427. struct hostent *hostp = NULL;
  428. DWORD inaddr;
  429. if(lstrcmpW(pHost, L"255.255.255.255") == 0)
  430. {
  431. return E_FAIL;
  432. }
  433. //
  434. // Convert hostname to an ANSI string.
  435. //
  436. USES_CONVERSION;
  437. char *name = T2A(pHost);
  438. BAIL_IF_NULL(name, E_UNEXPECTED);
  439. //
  440. // Check if the string is in dot-quad notation.
  441. //
  442. if ((inaddr = inet_addr(name)) == -1L)
  443. {
  444. //
  445. // String is not in "dot quad" notation
  446. // So try to get the IP address from DNS.
  447. //
  448. hostp = gethostbyname(name);
  449. if (hostp)
  450. {
  451. //
  452. // If we find a host entry, set up the internet address
  453. //
  454. inaddr = GetCorrectAddressFromHostent(dwInterface, hostp);
  455. // inaddr = *(DWORD *)hostp->h_addr;
  456. }
  457. else
  458. {
  459. // error: the input was neither a valid dot-quad nor hostname
  460. return HRESULT_FROM_ERROR_CODE(WSAGetLastError());
  461. }
  462. }
  463. else
  464. {
  465. //
  466. // String is in "dot quad" notation
  467. // So try to get the host name from the IP address.
  468. //
  469. //
  470. // If we don't care about the host name, we're done resolving.
  471. // Otherwise make sure this IP maps to a hostname.
  472. //
  473. if ( pFullName != NULL )
  474. {
  475. hostp = gethostbyaddr((char *)&inaddr,sizeof(inaddr),AF_INET);
  476. if (!hostp)
  477. {
  478. // error: the input was neither a valid dot-quad nor hostname
  479. return HRESULT_FROM_ERROR_CODE(WSAGetLastError());
  480. }
  481. //[vlade] Changes for the multihomed
  482. inaddr = GetCorrectAddressFromHostent(dwInterface, hostp);
  483. }
  484. }
  485. //
  486. // All succeeded; return what was asked for.
  487. //
  488. if ( pFullName != NULL )
  489. {
  490. *pFullName = hostp->h_name;
  491. }
  492. if ( pdwIP != NULL )
  493. {
  494. *pdwIP = inaddr;
  495. if( inaddr == 0)
  496. {
  497. return E_FAIL;
  498. }
  499. }
  500. return S_OK;
  501. }
  502. /////////////////////////////////////////////////////////////////////////////
  503. // This is a small helper function to print an IP address to a Unicode string.
  504. // We can't use inet_ntoa because we need Unicode.
  505. void ipAddressToStringW(WCHAR * wszDest, DWORD dwAddress)
  506. {
  507. // The IP address is always stored in NETWORK byte order
  508. // So we need to take something like 0x0100007f and produce a string like
  509. // "127.0.0.1".
  510. wsprintf(wszDest, L"%d.%d.%d.%d",
  511. dwAddress & 0xff,
  512. (dwAddress >> 8) & 0xff,
  513. (dwAddress >> 16) & 0xff,
  514. dwAddress >> 24 );
  515. }
  516. // eof