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.

1172 lines
27 KiB

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