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.

874 lines
20 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // iastlimp.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // Provides function definitions for the Internet Authentication Service
  12. // Template Library (IASTL).
  13. //
  14. // MODIFICATION HISTORY
  15. //
  16. // 08/09/1998 Original version.
  17. // 10/13/1998 Drop null terminator when converting strings to octets.
  18. // 10/27/1998 Added IASDictionaryView.
  19. // 06/01/1999 Fix bug computing length in setOctetString.
  20. // 01/25/2000 Removed IASDictionaryView.
  21. // 04/14/2000 Added IASDictionary.
  22. // 06/26/2000 Relax the type checking in IASPeekAttribute.
  23. //
  24. ///////////////////////////////////////////////////////////////////////////////
  25. //////////
  26. // Must be NT5.0 or higher.
  27. //////////
  28. #if (_WIN32_WINNT < 0x0500)
  29. #error iastlimp.cpp requires NT5.0 or later.
  30. #endif
  31. //////////
  32. // IASTL must be used in conjuction with ATL.
  33. //////////
  34. #ifndef __ATLCOM_H__
  35. #error iastlimp.cpp requires atlcom.h to be included first
  36. #endif
  37. #include <windows.h>
  38. //////////
  39. // IASTL declarations.
  40. //////////
  41. #include <iastl.h>
  42. //////////
  43. // The entire library is contained within the IASTL namespace.
  44. //////////
  45. namespace IASTL {
  46. //////////
  47. // FSM governing IAS components.
  48. //////////
  49. const IASComponent::State IASComponent::fsm[NUM_EVENTS][NUM_STATES] =
  50. {
  51. { STATE_UNINITIALIZED, STATE_UNEXPECTED, STATE_UNEXPECTED, STATE_UNEXPECTED },
  52. { STATE_UNEXPECTED, STATE_INITIALIZED, STATE_INITIALIZED, STATE_UNEXPECTED },
  53. { STATE_UNEXPECTED, STATE_UNEXPECTED, STATE_SUSPENDED, STATE_SUSPENDED },
  54. { STATE_UNEXPECTED, STATE_UNEXPECTED, STATE_INITIALIZED, STATE_INITIALIZED },
  55. { STATE_SHUTDOWN, STATE_SHUTDOWN, STATE_UNEXPECTED, STATE_SHUTDOWN }
  56. };
  57. ///////////////////////////////////////////////////////////////////////////////
  58. //
  59. // IASComponent
  60. //
  61. ///////////////////////////////////////////////////////////////////////////////
  62. HRESULT IASComponent::fireEvent(Event event) throw ()
  63. {
  64. // Check the input parameters.
  65. if (event >= NUM_EVENTS) { return E_UNEXPECTED; }
  66. // Compute the next state.
  67. State next = fsm[event][state];
  68. Lock();
  69. HRESULT hr;
  70. if (next == state)
  71. {
  72. // If we're already in that state, there's nothing to do.
  73. hr = S_OK;
  74. }
  75. else if (next == STATE_UNEXPECTED)
  76. {
  77. // We received an unexpected event.
  78. hr = E_UNEXPECTED;
  79. }
  80. else
  81. {
  82. // Attempt the transition.
  83. hr = attemptTransition(event);
  84. // Only change state if the transition was successful.
  85. if (SUCCEEDED(hr))
  86. {
  87. state = next;
  88. }
  89. }
  90. Unlock();
  91. return hr;
  92. }
  93. ///////////////////////////////////////////////////////////////////////////////
  94. //
  95. // IASRequestHandler
  96. //
  97. ///////////////////////////////////////////////////////////////////////////////
  98. STDMETHODIMP IASRequestHandler::OnRequest(IRequest* pRequest)
  99. {
  100. if (getState() != IASComponent::STATE_INITIALIZED)
  101. {
  102. pRequest->SetResponse(IAS_RESPONSE_DISCARD_PACKET, IAS_INTERNAL_ERROR);
  103. pRequest->ReturnToSource(IAS_REQUEST_STATUS_ABORT);
  104. }
  105. else
  106. {
  107. onAsyncRequest(pRequest);
  108. }
  109. return S_OK;
  110. }
  111. ///////////////////////////////////////////////////////////////////////////////
  112. //
  113. // IASRequestHandlerSync
  114. //
  115. ///////////////////////////////////////////////////////////////////////////////
  116. void IASRequestHandlerSync::onAsyncRequest(IRequest* pRequest) throw ()
  117. {
  118. pRequest->ReturnToSource(onSyncRequest(pRequest));
  119. }
  120. //////////
  121. // End of the IASTL namespace.
  122. //////////
  123. }
  124. //////////
  125. // Only pull in the utility classes if necessary.
  126. //////////
  127. #ifdef _IASTLUTL_H_
  128. //////////
  129. // The utility classes are also contained within the IASTL namespace.
  130. //////////
  131. namespace IASTL {
  132. ///////////////////////////////////////////////////////////////////////////////
  133. //
  134. // IASAttribute
  135. //
  136. ///////////////////////////////////////////////////////////////////////////////
  137. IASAttribute& IASAttribute::operator=(PIASATTRIBUTE attr) throw ()
  138. {
  139. // Check for self-assignment.
  140. if (p != attr)
  141. {
  142. _release();
  143. p = attr;
  144. _addref();
  145. }
  146. return *this;
  147. }
  148. void IASAttribute::attach(PIASATTRIBUTE attr, bool addRef) throw ()
  149. {
  150. _release();
  151. p = attr;
  152. if (addRef) { _addref(); }
  153. }
  154. bool IASAttribute::load(IAttributesRaw* request, DWORD dwId)
  155. {
  156. // Release any existing attribute.
  157. release();
  158. DWORD posCount = 1;
  159. ATTRIBUTEPOSITION pos;
  160. HRESULT hr = request->GetAttributes(&posCount, &pos, 1, &dwId);
  161. if (FAILED(hr))
  162. {
  163. if (hr == HRESULT_FROM_WIN32(ERROR_MORE_DATA))
  164. {
  165. // There was more than one, so release the partial result.
  166. IASAttributeRelease(pos.pAttribute);
  167. }
  168. issue_error(hr);
  169. }
  170. p = (posCount ? pos.pAttribute : NULL);
  171. return p != NULL;
  172. }
  173. bool IASAttribute::load(IAttributesRaw* request, DWORD dwId, IASTYPE itType)
  174. {
  175. // Get an attribute with the given ID.
  176. load(request, dwId);
  177. // Attributes have a fixed type, so if the type doesn't match it must
  178. // be an error.
  179. if (p && p->Value.itType != itType)
  180. {
  181. release();
  182. issue_error(DISP_E_TYPEMISMATCH);
  183. }
  184. return p != NULL;
  185. }
  186. void IASAttribute::store(IAttributesRaw* request) const
  187. {
  188. if (p)
  189. {
  190. ATTRIBUTEPOSITION pos;
  191. pos.pAttribute = p;
  192. HRESULT hr = request->AddAttributes(1, &pos);
  193. if (FAILED(hr))
  194. {
  195. issue_error(hr);
  196. }
  197. }
  198. }
  199. void IASAttribute::setOctetString(DWORD dwLength, const BYTE* lpValue)
  200. {
  201. PBYTE newVal = NULL;
  202. if (dwLength)
  203. {
  204. // Allocate a buffer for the octet string ...
  205. newVal = (PBYTE)CoTaskMemAlloc(dwLength);
  206. if (!newVal) { issue_error(E_OUTOFMEMORY); }
  207. // ... and copy it in.
  208. memcpy(newVal, lpValue, dwLength);
  209. }
  210. // Clear the old value.
  211. clearValue();
  212. // Store the new.
  213. p->Value.OctetString.lpValue = newVal;
  214. p->Value.OctetString.dwLength = dwLength;
  215. p->Value.itType = IASTYPE_OCTET_STRING;
  216. }
  217. void IASAttribute::setOctetString(PCSTR szAnsi)
  218. {
  219. setOctetString((szAnsi ? strlen(szAnsi) : 0), (const BYTE*)szAnsi);
  220. }
  221. void IASAttribute::setOctetString(PCWSTR szWide)
  222. {
  223. // Allocate a buffer for the conversion.
  224. int len = WideCharToMultiByte(CP_ACP, 0, szWide, -1, NULL, 0, NULL, NULL);
  225. PSTR ansi = (PSTR)_alloca(len);
  226. // Convert from wide to ansi.
  227. len = WideCharToMultiByte(CP_ACP, 0, szWide, -1, ansi, len, NULL, NULL);
  228. // Don't include the null-terminator.
  229. if (len) { --len; }
  230. // Set the octet string.
  231. setOctetString(len, (const BYTE*)ansi);
  232. }
  233. void IASAttribute::setString(DWORD dwLength, const BYTE* lpValue)
  234. {
  235. // Reserve space for a null terminator.
  236. LPSTR newVal = (LPSTR)CoTaskMemAlloc(dwLength + 1);
  237. if (!newVal) { issue_error(E_OUTOFMEMORY); }
  238. // Copy in the string ...
  239. memcpy(newVal, lpValue, dwLength);
  240. // ... and add a null terminator.
  241. newVal[dwLength] = 0;
  242. // Clear the old value.
  243. clearValue();
  244. // Store the new value.
  245. p->Value.String.pszAnsi = newVal;
  246. p->Value.String.pszWide = NULL;
  247. p->Value.itType = IASTYPE_STRING;
  248. }
  249. void IASAttribute::setString(PCSTR szAnsi)
  250. {
  251. LPSTR newVal = NULL;
  252. if (szAnsi)
  253. {
  254. // Allocate a buffer for the string ...
  255. size_t nbyte = strlen(szAnsi) + 1;
  256. newVal = (LPSTR)CoTaskMemAlloc(nbyte);
  257. if (!newVal) { issue_error(E_OUTOFMEMORY); }
  258. // ... and copy it in.
  259. memcpy(newVal, szAnsi, nbyte);
  260. }
  261. // Clear the old value.
  262. clearValue();
  263. // Store the new value.
  264. p->Value.String.pszAnsi = newVal;
  265. p->Value.String.pszWide = NULL;
  266. p->Value.itType = IASTYPE_STRING;
  267. }
  268. void IASAttribute::setString(PCWSTR szWide)
  269. {
  270. LPWSTR newVal = NULL;
  271. if (szWide)
  272. {
  273. // Allocate a buffer for the string ...
  274. size_t nbyte = sizeof(WCHAR) * (wcslen(szWide) + 1);
  275. newVal = (LPWSTR)CoTaskMemAlloc(nbyte);
  276. if (!newVal) { issue_error(E_OUTOFMEMORY); }
  277. // ... and copy it in.
  278. memcpy(newVal, szWide, nbyte);
  279. }
  280. // Clear the old value.
  281. clearValue();
  282. // Store the new value.
  283. p->Value.String.pszWide = newVal;
  284. p->Value.String.pszAnsi = NULL;
  285. p->Value.itType = IASTYPE_STRING;
  286. }
  287. void IASAttribute::clearValue() throw ()
  288. {
  289. switch (p->Value.itType)
  290. {
  291. case IASTYPE_STRING:
  292. CoTaskMemFree(p->Value.String.pszAnsi);
  293. CoTaskMemFree(p->Value.String.pszWide);
  294. break;
  295. case IASTYPE_OCTET_STRING:
  296. CoTaskMemFree(p->Value.OctetString.lpValue);
  297. break;
  298. }
  299. p->Value.itType = IASTYPE_INVALID;
  300. }
  301. ///////////////////////////////////////////////////////////////////////////////
  302. //
  303. // IASAttributeVector
  304. //
  305. ///////////////////////////////////////////////////////////////////////////////
  306. IASAttributeVector::IASAttributeVector() throw ()
  307. : begin_(NULL), end_(NULL), capacity_(0), owner(false)
  308. { }
  309. IASAttributeVector::IASAttributeVector(size_type N)
  310. : begin_(NULL), end_(NULL), capacity_(0), owner(false)
  311. {
  312. reserve(N);
  313. }
  314. IASAttributeVector::IASAttributeVector(
  315. PATTRIBUTEPOSITION init,
  316. size_type initCap
  317. ) throw ()
  318. : begin_(init), end_(begin_), capacity_(initCap), owner(false)
  319. { }
  320. IASAttributeVector::IASAttributeVector(const IASAttributeVector& v)
  321. : begin_(NULL), end_(NULL), capacity_(0), owner(false)
  322. {
  323. reserve(v.size());
  324. for (const_iterator i = v.begin(); i != v.end(); ++i, ++end_)
  325. {
  326. *end_ = *i;
  327. IASAttributeAddRef(end_->pAttribute);
  328. }
  329. }
  330. IASAttributeVector& IASAttributeVector::operator=(const IASAttributeVector& v)
  331. {
  332. if (this != &v)
  333. {
  334. clear();
  335. reserve(v.size());
  336. for (const_iterator i = v.begin(); i != v.end(); ++i, ++end_)
  337. {
  338. *end_ = *i;
  339. IASAttributeAddRef(end_->pAttribute);
  340. }
  341. }
  342. return *this;
  343. }
  344. IASAttributeVector::~IASAttributeVector() throw ()
  345. {
  346. clear();
  347. if (owner && begin_)
  348. {
  349. CoTaskMemFree(begin_);
  350. }
  351. }
  352. IASAttributeVector::iterator IASAttributeVector::discard(iterator p) throw ()
  353. {
  354. // We now have one less attribute.
  355. --end_;
  356. // Shift over one.
  357. memmove(p, p + 1, (size_t)((PBYTE)end_ - (PBYTE)p));
  358. // The iterator now points to the next element, so no need to update.
  359. return p;
  360. }
  361. IASAttributeVector::iterator IASAttributeVector::fast_discard(iterator p) throw ()
  362. {
  363. // We now have one less attribute.
  364. --end_;
  365. // Use the attribute from the end to fill the empty slot.
  366. *p = *end_;
  367. return p;
  368. }
  369. DWORD IASAttributeVector::load(
  370. IAttributesRaw* request,
  371. DWORD attrIDCount,
  372. LPDWORD attrIDs
  373. )
  374. {
  375. clear();
  376. // Get the desired attributes.
  377. DWORD posCount = capacity_;
  378. HRESULT hr = request->GetAttributes(&posCount,
  379. begin_,
  380. attrIDCount,
  381. attrIDs);
  382. end_ = begin_ + posCount;
  383. if (FAILED(hr))
  384. {
  385. // Maybe the array just wasn't big enough.
  386. if (hr == HRESULT_FROM_WIN32(ERROR_MORE_DATA))
  387. {
  388. // Clear the partial result.
  389. clear();
  390. // Find out how much space we really need.
  391. DWORD needed = 0;
  392. hr = request->GetAttributes(&needed, NULL, attrIDCount, attrIDs);
  393. if (FAILED(hr)) { issue_error(hr); }
  394. // Reserve the necessary space ...
  395. reserve(needed);
  396. // ... and try again.
  397. return load(request, attrIDCount, attrIDs);
  398. }
  399. end_ = begin_;
  400. issue_error(hr);
  401. }
  402. return posCount;
  403. }
  404. DWORD IASAttributeVector::load(IAttributesRaw* request)
  405. {
  406. // Find out how much space we need.
  407. DWORD needed;
  408. HRESULT hr = request->GetAttributeCount(&needed);
  409. if (FAILED(hr)) { issue_error(hr); }
  410. // Make sure we have enough space.
  411. reserve(needed);
  412. return load(request, 0, NULL);
  413. }
  414. void IASAttributeVector::push_back(ATTRIBUTEPOSITION& p, bool addRef) throw ()
  415. {
  416. // Make sure we have enough room for one more attribute.
  417. if (size() == capacity())
  418. {
  419. reserve(empty() ? 1 : 2 * size());
  420. }
  421. if (addRef) { IASAttributeAddRef(p.pAttribute); }
  422. // Store the attribute at the end.
  423. *end_ = p;
  424. // Move the end.
  425. ++end_;
  426. }
  427. void IASAttributeVector::remove(IAttributesRaw* request)
  428. {
  429. if (begin_ != end_)
  430. {
  431. HRESULT hr = request->RemoveAttributes(size(), begin_);
  432. if (FAILED(hr)) { issue_error(hr); }
  433. }
  434. }
  435. void IASAttributeVector::store(IAttributesRaw* request) const
  436. {
  437. if (begin_ != end_)
  438. {
  439. HRESULT hr = request->AddAttributes(size(), begin_);
  440. if (FAILED(hr)) { issue_error(hr); }
  441. }
  442. }
  443. void IASAttributeVector::clear() throw ()
  444. {
  445. while (end_ != begin_)
  446. {
  447. --end_;
  448. IASAttributeRelease(end_->pAttribute);
  449. }
  450. }
  451. void IASAttributeVector::reserve(size_type N)
  452. {
  453. // We only worry about growing; shrinking is a nop.
  454. if (N > capacity_)
  455. {
  456. // Allocate memory for the new vector.
  457. PATTRIBUTEPOSITION tmp =
  458. (PATTRIBUTEPOSITION)CoTaskMemAlloc(N * sizeof(ATTRIBUTEPOSITION));
  459. if (tmp == NULL) { issue_error(E_OUTOFMEMORY); }
  460. // Copy the existing attributes into the new array.
  461. size_type size_ = size();
  462. memcpy(tmp, begin_, size_ * sizeof(ATTRIBUTEPOSITION));
  463. // Free the old array if necessary.
  464. if (owner) { CoTaskMemFree(begin_); }
  465. // Update our state to point at the new array.
  466. begin_ = tmp;
  467. end_ = begin_ + size_;
  468. capacity_ = N;
  469. owner = true;
  470. }
  471. }
  472. ///////////////////////////////////////////////////////////////////////////////
  473. //
  474. // IASRequest
  475. //
  476. ///////////////////////////////////////////////////////////////////////////////
  477. IASRequest::IASRequest(IRequest* request)
  478. : req(request)
  479. {
  480. if (!req)
  481. {
  482. // We don't allow NULL request objects.
  483. issue_error(E_POINTER);
  484. }
  485. // Get the 'raw' counterpart.
  486. checkError(req->QueryInterface(__uuidof(IAttributesRaw), (PVOID*)&raw));
  487. }
  488. IASRequest& IASRequest::operator=(const IASRequest& request) throw ()
  489. {
  490. // Check for self-assignment.
  491. if (this != &request)
  492. {
  493. _release();
  494. req = request.req;
  495. raw = request.raw;
  496. _addref();
  497. }
  498. return *this;
  499. }
  500. DWORD IASRequest::GetAttributes(DWORD dwPosCount,
  501. PATTRIBUTEPOSITION pPositions,
  502. DWORD dwAttrIDCount,
  503. LPDWORD lpdwAttrIDs)
  504. {
  505. DWORD count = dwPosCount;
  506. HRESULT hr = raw->GetAttributes(&count,
  507. pPositions,
  508. dwAttrIDCount,
  509. lpdwAttrIDs);
  510. if (FAILED(hr))
  511. {
  512. if (hr == HRESULT_FROM_WIN32(ERROR_MORE_DATA))
  513. {
  514. // Free the partial results.
  515. while (count--)
  516. {
  517. IASAttributeRelease(pPositions->pAttribute);
  518. pPositions->pAttribute = NULL;
  519. ++pPositions;
  520. }
  521. }
  522. issue_error(hr);
  523. }
  524. return count;
  525. }
  526. IASDictionary::IASDictionary(
  527. const WCHAR* const* selectNames,
  528. PCWSTR path
  529. )
  530. : mapSize(0),
  531. nextRowNumber(0),
  532. currentRow(NULL)
  533. {
  534. if (!path)
  535. {
  536. // No path, so get the cached local dictionary.
  537. table = IASGetLocalDictionary();
  538. if (!table) { issue_error(GetLastError()); }
  539. }
  540. else
  541. {
  542. // Otherwise, get an arbitrary dictionary.
  543. HRESULT hr = IASGetDictionary(path, &data, &storage);
  544. if (FAILED(hr)) { issue_error(hr); }
  545. table = &data;
  546. }
  547. // How many columns are selected ?
  548. for (const WCHAR* const* p = selectNames; *p; ++p)
  549. {
  550. ++mapSize;
  551. }
  552. // Allocate memory for the map.
  553. selectMap = (PULONG)CoTaskMemAlloc(mapSize * sizeof(ULONG));
  554. if (!selectMap) { issue_error(E_OUTOFMEMORY); }
  555. // Lookup the column names.
  556. for (ULONG i = 0; i < mapSize; ++i)
  557. {
  558. for (ULONG j = 0; j < table->numColumns; ++j)
  559. {
  560. if (!_wcsicmp(selectNames[i], table->columnNames[j]))
  561. {
  562. selectMap[i] = j;
  563. break;
  564. }
  565. }
  566. if (j == table->numColumns)
  567. {
  568. // We didn't find the column.
  569. CoTaskMemFree(selectMap);
  570. issue_error(E_INVALIDARG);
  571. }
  572. }
  573. }
  574. IASDictionary::~IASDictionary() throw ()
  575. {
  576. CoTaskMemFree(selectMap);
  577. }
  578. bool IASDictionary::next() throw ()
  579. {
  580. // Are there any rows left ?
  581. if (nextRowNumber >= table->numRows) { return false; }
  582. // Set currentRow to the next row.
  583. currentRow = table->table + nextRowNumber * table->numColumns;
  584. // Advance nextRowNumber.
  585. ++nextRowNumber;
  586. return true;
  587. }
  588. void IASDictionary::reset() throw ()
  589. {
  590. nextRowNumber = 0;
  591. currentRow = NULL;
  592. }
  593. bool IASDictionary::isEmpty(ULONG ordinal) const
  594. {
  595. return V_VT(getVariant(ordinal)) == VT_EMPTY;
  596. }
  597. VARIANT_BOOL IASDictionary::getBool(ULONG ordinal) const
  598. {
  599. const VARIANT* v = getVariant(ordinal);
  600. if (V_VT(v) == VT_BOOL)
  601. {
  602. return V_BOOL(v);
  603. }
  604. else if (V_VT(v) != VT_EMPTY)
  605. {
  606. issue_error(DISP_E_TYPEMISMATCH);
  607. }
  608. return VARIANT_FALSE;
  609. }
  610. BSTR IASDictionary::getBSTR(ULONG ordinal) const
  611. {
  612. const VARIANT* v = getVariant(ordinal);
  613. if (V_VT(v) == VT_BSTR)
  614. {
  615. return V_BSTR(v);
  616. }
  617. else if (V_VT(v) != VT_EMPTY)
  618. {
  619. issue_error(DISP_E_TYPEMISMATCH);
  620. }
  621. return NULL;
  622. }
  623. LONG IASDictionary::getLong(ULONG ordinal) const
  624. {
  625. const VARIANT* v = getVariant(ordinal);
  626. if (V_VT(v) == VT_I4)
  627. {
  628. return V_I4(v);
  629. }
  630. else if (V_VT(v) != VT_EMPTY)
  631. {
  632. issue_error(DISP_E_TYPEMISMATCH);
  633. }
  634. return 0L;
  635. }
  636. const VARIANT* IASDictionary::getVariant(ULONG ordinal) const
  637. {
  638. // Are we positioned on a row ?
  639. if (!currentRow) { issue_error(E_UNEXPECTED); }
  640. // Is the ordinal valid ?
  641. if (ordinal >= mapSize) { issue_error(E_INVALIDARG); }
  642. return currentRow + selectMap[ordinal];
  643. }
  644. //////////
  645. // End of the IASTL namespace.
  646. //////////
  647. }
  648. ///////////////////////////////////////////////////////////////////////////////
  649. //
  650. // OctetString conversion macros and functions.
  651. //
  652. ///////////////////////////////////////////////////////////////////////////////
  653. PSTR IASOctetStringToAnsi(const IAS_OCTET_STRING& src, PSTR dst) throw ()
  654. {
  655. dst[src.dwLength] = '\0';
  656. return (PSTR)memcpy(dst, src.lpValue, src.dwLength);
  657. }
  658. PWSTR IASOctetStringToWide(const IAS_OCTET_STRING& src, PWSTR dst) throw ()
  659. {
  660. DWORD nChar = MultiByteToWideChar(CP_ACP,
  661. 0,
  662. (PSTR)src.lpValue,
  663. src.dwLength,
  664. dst,
  665. src.dwLength);
  666. dst[nChar] = L'\0';
  667. return dst;
  668. }
  669. ///////////////////////////////////////////////////////////////////////////////
  670. //
  671. // Miscellaneous functions.
  672. //
  673. ///////////////////////////////////////////////////////////////////////////////
  674. // Returns 'true' if the IASTYPE maps to a RADIUS integer attribute.
  675. bool isRadiusInteger(IASTYPE type) throw ()
  676. {
  677. bool retval;
  678. switch (type)
  679. {
  680. case IASTYPE_BOOLEAN:
  681. case IASTYPE_INTEGER:
  682. case IASTYPE_ENUM:
  683. retval = true;
  684. break;
  685. default:
  686. retval = false;
  687. }
  688. return retval;
  689. }
  690. PIASATTRIBUTE IASPeekAttribute(
  691. IAttributesRaw* request,
  692. DWORD dwId,
  693. IASTYPE itType
  694. ) throw ()
  695. {
  696. if (request)
  697. {
  698. DWORD posCount = 1;
  699. ATTRIBUTEPOSITION pos;
  700. HRESULT hr = request->GetAttributes(&posCount, &pos, 1, &dwId);
  701. if (posCount == 1)
  702. {
  703. IASAttributeRelease(pos.pAttribute);
  704. if (SUCCEEDED(hr))
  705. {
  706. // There is some confusion between RAS and IAS regarding which
  707. // IASTYPEs to use for various RADIUS attributes, so we'll assume
  708. // any of the RADIUS integer types are interchangeable.
  709. if (itType == pos.pAttribute->Value.itType ||
  710. (isRadiusInteger(itType) &&
  711. isRadiusInteger(pos.pAttribute->Value.itType)))
  712. {
  713. return pos.pAttribute;
  714. }
  715. }
  716. }
  717. }
  718. return NULL;
  719. }
  720. //////////
  721. // End of utility classe.
  722. //////////
  723. #endif // _IASTLUTL_H_