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.

1107 lines
26 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1997, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // iasapi.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // This file implements all the non-COM DLL exports for the IAS core.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 09/02/1997 Original version.
  16. // 11/12/1997 Added IASInitialize and IASUnitialize.
  17. // Added debug support for small block heap.
  18. // Added IASUpdateRegistry
  19. // 12/04/1997 Added initialization of pAuditChannel to IASInitialize
  20. // 01/30/1998 Added IASAdler32.
  21. // 04/10/1998 Eliminate aliasing in IASSmallBlockFree.
  22. // 04/11/1998 Only update sb_count for non-NULL blocks.
  23. // 04/13/1998 Removed SystemMonitor coclass.
  24. // 05/11/1998 Lifecycle changes for auditors.
  25. // 06/04/1998 Remove lifecycle control of auditors.
  26. // 06/08/1998 Remove timer queue initialization and shutdown.
  27. // 06/16/1998 Added IASVariantChangeType.
  28. // 08/05/1998 Use task allocator for small block pool.
  29. // 08/10/1998 Remove obsolete API's.
  30. // 10/09/1998 Convert between VT_BSTR and VT_ARRAY | VT_UI1
  31. // 05/21/1999 Remove old style trace.
  32. // 01/25/2000 Added IASGetHostByName.
  33. // 03/10/2000 IASGetHostByName can take a null hostname for localhost.
  34. // 04/14/2000 Added dictionary API.
  35. // 05/12/2000 Pass correct buffer size to LoadStringW.
  36. //
  37. ///////////////////////////////////////////////////////////////////////////////
  38. #include <iascore.h>
  39. #include <iastlb.h>
  40. #include <iasutil.h>
  41. #include <varvec.h>
  42. #include <resource.h>
  43. #include <winsock2.h>
  44. #include <svcguid.h>
  45. #include <md5.h>
  46. ///////////////////////////////////////////////////////////////////////////////
  47. //
  48. // Audit Channel API
  49. //
  50. ///////////////////////////////////////////////////////////////////////////////
  51. // Global pointer to the audit channel.
  52. IAuditSink* pAuditChannel = NULL;
  53. HRESULT
  54. WINAPI
  55. IASReportEvent(
  56. DWORD dwEventID,
  57. DWORD dwNumStrings,
  58. DWORD dwDataSize,
  59. LPCWSTR* aszStrings,
  60. LPVOID pRawData
  61. )
  62. {
  63. if (pAuditChannel == NULL) { return E_POINTER; }
  64. return pAuditChannel->AuditEvent(dwEventID,
  65. dwNumStrings,
  66. dwDataSize,
  67. (wchar_t**)aszStrings,
  68. (byte*)pRawData);
  69. }
  70. ///////////////////////////////////////////////////////////////////////////////
  71. //
  72. // Thread Pool API
  73. //
  74. ///////////////////////////////////////////////////////////////////////////////
  75. #include <dispatcher.h>
  76. // The global dispatcher object.
  77. Dispatcher dispatcher;
  78. BOOL
  79. WINAPI
  80. IASRequestThread(PIAS_CALLBACK pOnStart)
  81. {
  82. return dispatcher.requestThread(pOnStart);
  83. }
  84. DWORD
  85. WINAPI
  86. IASSetMaxNumberOfThreads(DWORD dwNumberOfThreads)
  87. {
  88. return dispatcher.setMaxNumberOfThreads(dwNumberOfThreads);
  89. }
  90. DWORD
  91. WINAPI
  92. IASSetMaxThreadIdle(DWORD dwMilliseconds)
  93. {
  94. return dispatcher.setMaxThreadIdle(dwMilliseconds);
  95. }
  96. ///////////////////////////////////////////////////////////////////////////////
  97. //
  98. // FUNCTION
  99. //
  100. // IASRegisterComponent
  101. //
  102. // DESCRIPTION
  103. //
  104. // Updates the registry entries for the specified component.
  105. //
  106. ///////////////////////////////////////////////////////////////////////////////
  107. HRESULT
  108. WINAPI
  109. IASRegisterComponent(
  110. HINSTANCE hInstance,
  111. REFCLSID clsid,
  112. LPCWSTR szProgramName,
  113. LPCWSTR szComponent,
  114. DWORD dwRegFlags,
  115. REFGUID tlid,
  116. WORD wVerMajor,
  117. WORD wVerMinor,
  118. BOOL bRegister
  119. )
  120. {
  121. //////////
  122. // Create the registrar object.
  123. //////////
  124. CComPtr<IRegistrar> p;
  125. RETURN_ERROR(CoCreateInstance(CLSID_Registrar,
  126. NULL,
  127. CLSCTX_INPROC_SERVER,
  128. IID_IRegistrar,
  129. (void**)&p));
  130. //////////
  131. // Get the module file name for the component.
  132. //////////
  133. WCHAR szModule[MAX_PATH + 1];
  134. if (!GetModuleFileNameW(hInstance, szModule, MAX_PATH + 1))
  135. {
  136. DWORD error = GetLastError();
  137. return HRESULT_FROM_WIN32(error);
  138. }
  139. //////////
  140. // Get our module file name.
  141. //////////
  142. WCHAR szOurModule[MAX_PATH + 1] = L"";
  143. if (!GetModuleFileNameW(_Module.GetModuleInstance(),
  144. szOurModule,
  145. MAX_PATH + 1))
  146. {
  147. DWORD error = GetLastError();
  148. return HRESULT_FROM_WIN32(error);
  149. }
  150. //////////
  151. // Convert the GUID strings.
  152. //////////
  153. WCHAR szClsID[40], szLibID[40];
  154. RETURN_ERROR(StringFromGUID2(
  155. clsid,
  156. szClsID,
  157. sizeof(szClsID) / sizeof(WCHAR)));
  158. RETURN_ERROR(StringFromGUID2(
  159. tlid,
  160. szLibID,
  161. sizeof(szLibID) / sizeof(WCHAR)));
  162. //////////
  163. // Convert the version to a string.
  164. //////////
  165. WCHAR szMajor[7] = L"";
  166. wsprintfW(szMajor, L"%d", wVerMajor);
  167. WCHAR szMinor[7] = L"";
  168. wsprintfW(szMinor, L"%d", wVerMinor);
  169. //////////
  170. // Parse the bit flags.
  171. //////////
  172. PCWSTR szContext, szAttributes, szModel;
  173. if (dwRegFlags & IAS_REGISTRY_LOCAL)
  174. {
  175. szContext = L"LocalServer32";
  176. }
  177. else
  178. {
  179. szContext = L"InprocServer32";
  180. }
  181. if (dwRegFlags & IAS_REGISTRY_AUTO)
  182. {
  183. szAttributes = L"Programmable";
  184. }
  185. else
  186. {
  187. szAttributes = L"";
  188. }
  189. if (dwRegFlags & IAS_REGISTRY_BOTH)
  190. {
  191. szModel = L"Both";
  192. }
  193. else if (dwRegFlags & IAS_REGISTRY_APT)
  194. {
  195. szModel = L"Apartment";
  196. }
  197. else
  198. {
  199. szModel = L"Free";
  200. }
  201. //////////
  202. // Add the replacement strings.
  203. //////////
  204. RETURN_ERROR(p->AddReplacement(L"MODULE", szModule));
  205. RETURN_ERROR(p->AddReplacement(L"CLSID", szClsID));
  206. RETURN_ERROR(p->AddReplacement(L"PROGRAM", szProgramName));
  207. RETURN_ERROR(p->AddReplacement(L"COMPONENT", szComponent));
  208. RETURN_ERROR(p->AddReplacement(L"TYPENAME", L" "));
  209. RETURN_ERROR(p->AddReplacement(L"LIBID", szLibID));
  210. RETURN_ERROR(p->AddReplacement(L"MAJORVER", szMajor));
  211. RETURN_ERROR(p->AddReplacement(L"MINORVER", szMinor));
  212. RETURN_ERROR(p->AddReplacement(L"CONTEXT", szContext));
  213. RETURN_ERROR(p->AddReplacement(L"ATTRIBUTES", szAttributes));
  214. RETURN_ERROR(p->AddReplacement(L"MODEL", szModel));
  215. //////////
  216. // Now we either register or unregister the component based on the
  217. // bRegister flag.
  218. //////////
  219. HRESULT hr;
  220. if (bRegister)
  221. {
  222. hr = p->ResourceRegister(szOurModule, IDR_IASCOM, L"REGISTRY");
  223. }
  224. else
  225. {
  226. hr = p->ResourceUnregister(szOurModule, IDR_IASCOM, L"REGISTRY");
  227. }
  228. return hr;
  229. }
  230. ///////////////////////////////////////////////////////////////////////////////
  231. //
  232. // FUNCTION
  233. //
  234. // IASAdler32
  235. //
  236. // DESCRIPTION
  237. //
  238. // Computes the Adler-32 checksum of a buffer.
  239. //
  240. ///////////////////////////////////////////////////////////////////////////////
  241. DWORD
  242. WINAPI
  243. IASAdler32(
  244. CONST BYTE *pBuffer,
  245. DWORD nBufferLength
  246. )
  247. {
  248. static const DWORD ADLER_BASE = 65521;
  249. DWORD s1 = 1;
  250. DWORD s2 = 0;
  251. while (nBufferLength--)
  252. {
  253. s1 = (s1 + *pBuffer++) % ADLER_BASE;
  254. s2 = (s2 + s1) % ADLER_BASE;
  255. }
  256. return (s2 << 16) + s1;
  257. }
  258. ///////////////////////////////////////////////////////////////////////////////
  259. //
  260. // FUNCTION
  261. //
  262. // IASAllocateUniqueID
  263. //
  264. // DESCRIPTION
  265. //
  266. // Allocates a 32-bit integer that's guaranteed to be unique process-wide.
  267. //
  268. ///////////////////////////////////////////////////////////////////////////////
  269. DWORD
  270. WINAPI
  271. IASAllocateUniqueID( VOID )
  272. {
  273. static LONG nextID = 0;
  274. return (DWORD)InterlockedIncrement(&nextID);
  275. }
  276. //////////
  277. // Convert a hex digit to the number it represents.
  278. //////////
  279. inline BYTE digit2Num(WCHAR digit) throw ()
  280. {
  281. return (digit >= L'0' && digit <= L'9') ? digit - L'0'
  282. : digit - (L'A' - 10);
  283. }
  284. //////////
  285. // Convert a number to a hex representation.
  286. //////////
  287. inline WCHAR num2Digit(BYTE num) throw ()
  288. {
  289. return (num < 10) ? num + L'0'
  290. : num + (L'A' - 10);
  291. }
  292. ///////////////////////////////////////////////////////////////////////////////
  293. //
  294. // FUNCTION
  295. //
  296. // IASVariantChangeType
  297. //
  298. // DESCRIPTION
  299. //
  300. // Replacement for VariantChangeType (q.v.) to bypass creating a message
  301. // loop.
  302. //
  303. ///////////////////////////////////////////////////////////////////////////////
  304. HRESULT
  305. WINAPI
  306. IASVariantChangeType(
  307. VARIANT * pvargDest,
  308. VARIANT * pvarSrc,
  309. USHORT wFlags,
  310. VARTYPE vt
  311. )
  312. {
  313. // Check the input arguments.
  314. if (pvargDest == NULL || pvarSrc == NULL)
  315. {
  316. return E_INVALIDARG;
  317. }
  318. // Is the source already the requested type?
  319. if (V_VT(pvarSrc) == vt)
  320. {
  321. return (pvargDest != pvarSrc) ? VariantCopy(pvargDest, pvarSrc) : S_OK;
  322. }
  323. VARIANT varTmp;
  324. VariantInit(&varTmp);
  325. switch (MAKELONG(vt, V_VT(pvarSrc)))
  326. {
  327. case MAKELONG(VT_BOOL, VT_BSTR):
  328. {
  329. if (V_BSTR(pvarSrc) == NULL) { return DISP_E_TYPEMISMATCH; }
  330. V_BOOL(&varTmp) = (VARIANT_BOOL)
  331. _wtol(V_BSTR(pvarSrc)) ? VARIANT_TRUE
  332. : VARIANT_FALSE;
  333. break;
  334. }
  335. case MAKELONG(VT_I4, VT_BSTR):
  336. {
  337. if (V_BSTR(pvarSrc) == NULL) { return DISP_E_TYPEMISMATCH; }
  338. V_I4(&varTmp) = _wtol(V_BSTR(pvarSrc));
  339. break;
  340. }
  341. case MAKELONG((VT_UI1 | VT_ARRAY) , VT_BSTR):
  342. {
  343. // Extract the source string.
  344. PCWSTR src = V_BSTR(pvarSrc);
  345. if (src == NULL) { return DISP_E_TYPEMISMATCH; }
  346. LONG srclen = wcslen(src);
  347. // Compute the destination length.
  348. if (srclen & 1) { return DISP_E_TYPEMISMATCH; }
  349. LONG dstlen = srclen / 2;
  350. // Allocate a SAFEARRAY of bytes to hold the octets.
  351. CVariantVector<BYTE> vec(&varTmp, dstlen);
  352. PBYTE dst = vec.data();
  353. // Loop through the source and convert.
  354. while (dstlen--)
  355. {
  356. *dst = digit2Num(*src++) << 4;
  357. *dst++ |= digit2Num(*src++);
  358. }
  359. break;
  360. }
  361. case MAKELONG(VT_BSTR, VT_BOOL):
  362. {
  363. V_BSTR(&varTmp) = SysAllocString(V_BOOL(pvarSrc) ? L"-1" : L"0");
  364. if (V_BSTR(&varTmp) == NULL) { return E_OUTOFMEMORY; }
  365. break;
  366. }
  367. case MAKELONG(VT_BSTR, VT_I4):
  368. {
  369. WCHAR buffer[12];
  370. V_BSTR(&varTmp) = SysAllocString(_ltow(V_I4(pvarSrc), buffer, 10));
  371. if (V_BSTR(&varTmp) == NULL) { return E_OUTOFMEMORY; }
  372. break;
  373. }
  374. case MAKELONG(VT_BSTR, (VT_UI1 | VT_ARRAY)):
  375. {
  376. // Extract the source octets.
  377. CVariantVector<BYTE> vec(pvarSrc);
  378. CONST BYTE* src = vec.data();
  379. LONG srclen = vec.size();
  380. // Allocate space for the 'stringized' version.
  381. PWCHAR dst = SysAllocStringLen(NULL, srclen * 2);
  382. if (dst == NULL) { return E_OUTOFMEMORY; }
  383. V_BSTR(&varTmp) = dst;
  384. // Loop through and convert.
  385. while (srclen--)
  386. {
  387. *dst++ = num2Digit(*src >> 4);
  388. *dst++ = num2Digit(*src++ & 0xF);
  389. }
  390. // Add a null-terminator.
  391. *dst = L'\0';
  392. break;
  393. }
  394. default:
  395. return DISP_E_TYPEMISMATCH;
  396. }
  397. // We successfully converted, so set the type.
  398. V_VT(&varTmp) = vt;
  399. // Free the destination.
  400. VariantClear(pvargDest);
  401. // Copy in the coerced variant.
  402. *pvargDest = varTmp;
  403. return S_OK;
  404. }
  405. ///////////////////////////////////////////////////////////////////////////////
  406. //
  407. // Routines to handle startup and shutdown.
  408. //
  409. ///////////////////////////////////////////////////////////////////////////////
  410. // Reference count for the IAS API.
  411. LONG refCount = 0;
  412. // Shared local dictionary.
  413. VARIANT theDictionaryStorage;
  414. BOOL
  415. WINAPI
  416. IASInitialize(VOID)
  417. {
  418. HRESULT hr;
  419. DWORD error;
  420. WSADATA wsaData;
  421. // Global lock to serialize access.
  422. std::_Lockit _Lk;
  423. // If we're already initialized, there's nothing to do.
  424. if (refCount > 0)
  425. {
  426. ++refCount;
  427. return TRUE;
  428. }
  429. // Initialize the audit channel.
  430. hr = CoCreateInstance(__uuidof(AuditChannel),
  431. NULL,
  432. CLSCTX_INPROC_SERVER,
  433. __uuidof(IAuditSink),
  434. (PVOID*)&pAuditChannel);
  435. if (FAILED(hr))
  436. {
  437. SetLastError(hr);
  438. goto auditor_failed;
  439. }
  440. // Initialize winsock.
  441. error = WSAStartup(MAKEWORD(2, 0), &wsaData);
  442. if (error)
  443. {
  444. SetLastError(error);
  445. goto wsa_failed;
  446. }
  447. // Initialize the thread pool.
  448. if (!dispatcher.initialize())
  449. {
  450. goto thrdpool_failed;
  451. }
  452. // Everything succeeded, so bump up the refCount.
  453. ++refCount;
  454. return TRUE;
  455. thrdpool_failed:
  456. WSACleanup();
  457. wsa_failed:
  458. pAuditChannel->Release();
  459. pAuditChannel = NULL;
  460. auditor_failed:
  461. return FALSE;
  462. }
  463. VOID
  464. WINAPI
  465. IASUninitialize( VOID)
  466. {
  467. std::_Lockit _Lk;
  468. _ASSERT(refCount != 0);
  469. if (--refCount == 0)
  470. {
  471. // Shutdown the thread pool. This blocks until all threads have exited.
  472. dispatcher.finalize();
  473. // Shutdown winsock.
  474. WSACleanup();
  475. // Shutdown the audit channel.
  476. pAuditChannel->Release();
  477. pAuditChannel = NULL;
  478. // Shutdown the dictionary.
  479. VariantClear(&theDictionaryStorage);
  480. }
  481. }
  482. VOID
  483. WINAPI
  484. IASRadiusCrypt(
  485. BOOL encrypt,
  486. BOOL salted,
  487. const BYTE* secret,
  488. ULONG secretLen,
  489. const BYTE* reqAuth,
  490. PBYTE buf,
  491. ULONG buflen
  492. )
  493. {
  494. MD5_CTX context;
  495. BYTE cipherText[MD5DIGESTLEN];
  496. BYTE *p;
  497. const BYTE *end, *endBlock, *ct, *src;
  498. WORD salt;
  499. static LONG theNextSalt;
  500. // Use the Request-Authenticator as the first block of ciphertext.
  501. ct = reqAuth;
  502. // Compute the beginning and end of the data to be crypted.
  503. p = buf;
  504. end = buf + buflen;
  505. // Is the buffer salted ?
  506. if (salted)
  507. {
  508. if (encrypt)
  509. {
  510. // Get the next salt value.
  511. salt = (WORD)(++theNextSalt);
  512. // High bit must be set.
  513. salt |= 0x8000;
  514. // Store at the front of the buffer.
  515. IASInsertWORD(buf, salt);
  516. }
  517. // Skip past the salt.
  518. p += 2;
  519. }
  520. // Loop through the buffer.
  521. while (p < end)
  522. {
  523. // Compute the digest.
  524. MD5Init(&context);
  525. MD5Update(&context, secret, secretLen);
  526. MD5Update(&context, ct, MD5DIGESTLEN);
  527. if (salted)
  528. {
  529. MD5Update(&context, buf, 2);
  530. // Only use the salt on the first pass.
  531. salted = FALSE;
  532. }
  533. MD5Final(&context);
  534. // Find the end of the block to be decrypted.
  535. endBlock = p + MD5DIGESTLEN;
  536. if (endBlock >= end)
  537. {
  538. // We've reached the end of the buffer.
  539. endBlock = end;
  540. }
  541. else
  542. {
  543. // Save the ciphertext for the next pass.
  544. ct = encrypt ? p : (PBYTE)memcpy(cipherText, p, MD5DIGESTLEN);
  545. }
  546. // Crypt the block.
  547. for (src = context.digest; p < endBlock; ++p, ++src)
  548. {
  549. *p ^= *src;
  550. }
  551. }
  552. }
  553. /////////
  554. // Unicode version of gethostbyname. The caller must free the returned hostent
  555. // struct by calling LocalFree.
  556. /////////
  557. PHOSTENT
  558. WINAPI
  559. IASGetHostByName(
  560. IN PCWSTR name
  561. )
  562. {
  563. // We put these at function scope, so we can clean them up on the way out.
  564. DWORD error = NO_ERROR;
  565. HANDLE lookup = NULL;
  566. union
  567. {
  568. WSAQUERYSETW querySet;
  569. BYTE buffer[512];
  570. };
  571. PWSAQUERYSETW result = NULL;
  572. PHOSTENT retval = NULL;
  573. do
  574. {
  575. if (!name)
  576. {
  577. // A NULL name means use the local host, so allocate a buffer ...
  578. DWORD size = 0;
  579. GetComputerNameEx(
  580. ComputerNamePhysicalDnsFullyQualified,
  581. NULL,
  582. &size
  583. );
  584. PWSTR buf = (PWSTR)_alloca(size * sizeof(WCHAR));
  585. // ... and get the local DNS name.
  586. if (!GetComputerNameEx(
  587. ComputerNamePhysicalDnsFullyQualified,
  588. buf,
  589. &size
  590. ))
  591. {
  592. error = GetLastError();
  593. break;
  594. }
  595. name = buf;
  596. }
  597. //////////
  598. // Create the query set
  599. //////////
  600. GUID hostAddrByNameGuid = SVCID_INET_HOSTADDRBYNAME;
  601. AFPROTOCOLS protocols[2] =
  602. {
  603. { AF_INET, IPPROTO_UDP },
  604. { AF_INET, IPPROTO_TCP }
  605. };
  606. memset(&querySet, 0, sizeof(querySet));
  607. querySet.dwSize = sizeof(querySet);
  608. querySet.lpszServiceInstanceName = (PWSTR)name;
  609. querySet.lpServiceClassId = &hostAddrByNameGuid;
  610. querySet.dwNameSpace = NS_ALL;
  611. querySet.dwNumberOfProtocols = 2;
  612. querySet.lpafpProtocols = protocols;
  613. //////////
  614. // Execute the query.
  615. //////////
  616. error = WSALookupServiceBeginW(
  617. &querySet,
  618. LUP_RETURN_ADDR,
  619. &lookup
  620. );
  621. if (error)
  622. {
  623. error = WSAGetLastError();
  624. break;
  625. }
  626. //////////
  627. // How much space do we need for the result?
  628. //////////
  629. DWORD length = sizeof(buffer);
  630. error = WSALookupServiceNextW(
  631. lookup,
  632. 0,
  633. &length,
  634. &querySet
  635. );
  636. if (!error)
  637. {
  638. result = &querySet;
  639. }
  640. else
  641. {
  642. error = WSAGetLastError();
  643. if (error != WSAEFAULT)
  644. {
  645. break;
  646. }
  647. /////////
  648. // Allocate memory to hold the result.
  649. /////////
  650. result = (PWSAQUERYSETW)LocalAlloc(0, length);
  651. if (!result)
  652. {
  653. error = WSA_NOT_ENOUGH_MEMORY;
  654. break;
  655. }
  656. /////////
  657. // Get the result.
  658. /////////
  659. error = WSALookupServiceNextW(
  660. lookup,
  661. 0,
  662. &length,
  663. result
  664. );
  665. if (error)
  666. {
  667. error = WSAGetLastError();
  668. break;
  669. }
  670. }
  671. if (result->dwNumberOfCsAddrs == 0)
  672. {
  673. error = WSANO_DATA;
  674. break;
  675. }
  676. ///////
  677. // Allocate memory to hold the hostent struct
  678. ///////
  679. DWORD naddr = result->dwNumberOfCsAddrs;
  680. SIZE_T nbyte = sizeof(hostent) +
  681. (naddr + 1) * sizeof(char*) +
  682. naddr * sizeof(in_addr);
  683. retval = (PHOSTENT)LocalAlloc(0, nbyte);
  684. if (!retval)
  685. {
  686. error = WSA_NOT_ENOUGH_MEMORY;
  687. break;
  688. }
  689. ///////
  690. // Initialize the hostent struct.
  691. ///////
  692. retval->h_name = NULL;
  693. retval->h_aliases = NULL;
  694. retval->h_addrtype = AF_INET;
  695. retval->h_length = sizeof(in_addr);
  696. retval->h_addr_list = (char**)(retval + 1);
  697. ///////
  698. // Store the addresses.
  699. ///////
  700. u_long* nextAddr = (u_long*)(retval->h_addr_list + naddr + 1);
  701. for (DWORD i = 0; i < naddr; ++i)
  702. {
  703. sockaddr_in* sin = (sockaddr_in*)
  704. result->lpcsaBuffer[i].RemoteAddr.lpSockaddr;
  705. retval->h_addr_list[i] = (char*)nextAddr;
  706. *nextAddr++ = sin->sin_addr.S_un.S_addr;
  707. }
  708. ///////
  709. // NULL terminate the address list.
  710. ///////
  711. retval->h_addr_list[i] = NULL;
  712. } while (FALSE);
  713. //////////
  714. // Clean up and return.
  715. //////////
  716. if (result && result != &querySet) { LocalFree(result); }
  717. if (lookup) { WSALookupServiceEnd(lookup); }
  718. if (error)
  719. {
  720. if (error == WSASERVICE_NOT_FOUND) { error = WSAHOST_NOT_FOUND; }
  721. WSASetLastError(error);
  722. }
  723. return retval;
  724. }
  725. /////////
  726. // Fill in an IASTable struct from a VARIANT containing the table data.
  727. /////////
  728. HRESULT ExtractTableFromVariant(
  729. IN VARIANT* var,
  730. OUT IASTable* table
  731. ) throw ()
  732. {
  733. // Check the arguments.
  734. if (!var || !table) { return E_POINTER; }
  735. // Outer VARIANT must be an array of VARIANTs.
  736. if (V_VT(var) != (VT_ARRAY | VT_VARIANT)) { return E_INVALIDARG; }
  737. // Array must be 1D with exactly 3 elements.
  738. LPSAFEARRAY array = V_ARRAY(var);
  739. if (array->cDims != 1 || array->rgsabound[0].cElements != 3)
  740. {
  741. return E_INVALIDARG;
  742. }
  743. // tableData is an array of three variants:
  744. // (1) Column names
  745. // (2) Column types.
  746. // (3) Table data matrix.
  747. VARIANT* tableData = (VARIANT*)(array->pvData);
  748. // Process the column names.
  749. VARIANT* namesVariant = tableData + 0;
  750. // The VARIANT must be an array of BSTRs.
  751. if (V_VT(namesVariant) != (VT_ARRAY | VT_BSTR)) { return E_INVALIDARG; }
  752. // Array must be 1D.
  753. LPSAFEARRAY namesArray = V_ARRAY(namesVariant);
  754. if (namesArray->cDims != 1) { return E_INVALIDARG; }
  755. // Store the info in the IASTable.
  756. table->numColumns = namesArray->rgsabound[0].cElements;
  757. table->columnNames = (BSTR*)(namesArray->pvData);
  758. // Process the column types.
  759. VARIANT* typesVariant = tableData + 1;
  760. // The VARIANT must be an array of shorts.
  761. if (V_VT(typesVariant) != (VT_ARRAY | VT_UI2)) { return E_INVALIDARG; }
  762. // Array must be 1D with 1 element per column.
  763. LPSAFEARRAY typesArray = V_ARRAY(typesVariant);
  764. if (typesArray->cDims != 1 ||
  765. typesArray->rgsabound[0].cElements != table->numColumns)
  766. {
  767. return E_INVALIDARG;
  768. }
  769. // Store the info in the IASTable.
  770. table->columnTypes = (VARTYPE*)(namesArray->pvData);
  771. // Process the table data matrix.
  772. VARIANT* tableVariant = tableData + 2;
  773. // The VARIANT must be an array of VARIANTs.
  774. if (V_VT(tableVariant) != (VT_ARRAY | VT_VARIANT)) { return E_INVALIDARG; }
  775. // Array must be 2D with 1st dim equal to number of columns.
  776. LPSAFEARRAY tableArray = V_ARRAY(tableVariant);
  777. if (tableArray->cDims != 2 ||
  778. tableArray->rgsabound[0].cElements != table->numColumns)
  779. {
  780. return E_INVALIDARG;
  781. }
  782. // Store the info in the IASTable.
  783. table->numRows = tableArray->rgsabound[1].cElements;
  784. table->table = (VARIANT*)(tableArray->pvData);
  785. return S_OK;
  786. }
  787. HRESULT
  788. WINAPI
  789. IASGetDictionary(
  790. IN PCWSTR path,
  791. OUT IASTable* dnary,
  792. OUT VARIANT* storage
  793. )
  794. {
  795. // Initialize the out parameters.
  796. VariantInit(storage);
  797. // Create the AttributeDictionary object.
  798. HRESULT hr;
  799. CComPtr<IAttributeDictionary> dnaryObj;
  800. hr = CoCreateInstance(
  801. __uuidof(AttributeDictionary),
  802. NULL,
  803. CLSCTX_SERVER,
  804. __uuidof(IAttributeDictionary),
  805. (PVOID*)&dnaryObj
  806. );
  807. if (FAILED(hr)) { return hr; }
  808. // We need to give the object permission to impersonate us. There's
  809. // no reason to abort if this fails; we'll just try with the
  810. // existing blanket.
  811. CoSetProxyBlanket(
  812. dnaryObj,
  813. RPC_C_AUTHN_DEFAULT,
  814. RPC_C_AUTHZ_DEFAULT,
  815. COLE_DEFAULT_PRINCIPAL,
  816. RPC_C_AUTHN_LEVEL_DEFAULT,
  817. RPC_C_IMP_LEVEL_IMPERSONATE,
  818. NULL,
  819. EOAC_DEFAULT
  820. );
  821. // Convert the path to a BSTR.
  822. CComBSTR bstrPath(path);
  823. if (!bstrPath) { return E_OUTOFMEMORY; }
  824. // Get the dictionary.
  825. hr = dnaryObj->GetDictionary(bstrPath, storage);
  826. if (FAILED(hr)) { return hr; }
  827. hr = ExtractTableFromVariant(storage, dnary);
  828. if (FAILED(hr)) { VariantClear(storage); }
  829. return hr;
  830. }
  831. /////////
  832. // Get the path to the attribute dictionary on the local computer.
  833. /////////
  834. LONG GetDictionaryPath(PWSTR buffer, PDWORD size) throw ()
  835. {
  836. // Key ...
  837. const WCHAR POLICY_KEY[] =
  838. L"SYSTEM\\CurrentControlSet\\Services\\RemoteAccess\\Policy";
  839. // ... and value where the path to the IAS directory is stored.
  840. const WCHAR PRODUCT_DIR_VALUE[] = L"ProductDir";
  841. // String to append to ProductDir to form the path to the dictionary.
  842. const WCHAR DNARY_FILE[] = L"\\dnary.mdb";
  843. // Number of extra characters needed to append DNARY_FILE to the path.
  844. const DWORD EXTRA_CHARS = sizeof(DNARY_FILE)/sizeof(WCHAR) - 1;
  845. // Check the arguments
  846. if (!buffer || !size) { return ERROR_INVALID_PARAMETER; }
  847. // Initialize the out parameter.
  848. DWORD inSize = *size;
  849. *size = 0;
  850. // Open the registry key.
  851. LONG result;
  852. HKEY hKey;
  853. result = RegOpenKeyExW(
  854. HKEY_LOCAL_MACHINE,
  855. POLICY_KEY,
  856. 0,
  857. KEY_READ,
  858. &hKey
  859. );
  860. if (result != NO_ERROR) { return result; }
  861. // Read the ProductDir value.
  862. DWORD dwType;
  863. DWORD cbData = inSize * sizeof(WCHAR);
  864. result = RegQueryValueExW(
  865. hKey,
  866. PRODUCT_DIR_VALUE,
  867. NULL,
  868. &dwType,
  869. (PBYTE)buffer,
  870. &cbData
  871. );
  872. // We're done with the registry key.
  873. RegCloseKey(hKey);
  874. // Compute the length of the full path in characters.
  875. DWORD outSize = cbData / sizeof(WCHAR) + EXTRA_CHARS;
  876. if (result != NO_ERROR)
  877. {
  878. // If we overflowed, return the needed size.
  879. if (result == ERROR_MORE_DATA) { *size = outSize; }
  880. return result;
  881. }
  882. // The registry value must contain a string.
  883. if (dwType != REG_SZ)
  884. {
  885. return REGDB_E_INVALIDVALUE;
  886. }
  887. // Do we have enough room to append the DNARY_FILE.
  888. if (outSize <= inSize)
  889. {
  890. wcscat(buffer, DNARY_FILE);
  891. }
  892. else
  893. {
  894. result = ERROR_MORE_DATA;
  895. }
  896. // Return the size (whether actual or needed).
  897. *size = outSize;
  898. return result;
  899. }
  900. const IASTable*
  901. WINAPI
  902. IASGetLocalDictionary( VOID )
  903. {
  904. static IASTable theTable;
  905. // Global lock to serialize access.
  906. std::_Lockit _Lk;
  907. // Have we already gotten the local dictionary ?
  908. if (V_VT(&theDictionaryStorage) == VT_EMPTY)
  909. {
  910. HRESULT hr;
  911. // No, so determine the path ...
  912. WCHAR path[256];
  913. DWORD size = sizeof(path)/sizeof(WCHAR);
  914. hr = GetDictionaryPath(path, &size);
  915. if (hr == NO_ERROR)
  916. {
  917. // ... and get the dictionary.
  918. hr = IASGetDictionary(
  919. path,
  920. &theTable,
  921. &theDictionaryStorage
  922. );
  923. }
  924. else
  925. {
  926. hr = HRESULT_FROM_WIN32(hr);
  927. }
  928. if (FAILED(hr))
  929. {
  930. SetLastError(hr);
  931. return NULL;
  932. }
  933. }
  934. return &theTable;
  935. }