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.

1504 lines
40 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows NT Security
  4. // Copyright (C) Microsoft Corporation, 1997 - 1999
  5. //
  6. // File: ldapsp.cpp
  7. //
  8. // Contents: LDAP Scheme Provider for Remote Object Retrieval
  9. //
  10. // History: 23-Jul-97 kirtd Created
  11. // 01-Jan-02 philh Changed to internally use UNICODE Urls
  12. //
  13. //----------------------------------------------------------------------------
  14. #include <global.hxx>
  15. #ifndef INTERNET_MAX_PATH_LENGTH
  16. #define INTERNET_MAX_PATH_LENGTH 2048
  17. #endif
  18. //+---------------------------------------------------------------------------
  19. //
  20. // Function: LdapRetrieveEncodedObject
  21. //
  22. // Synopsis: retrieve encoded object via LDAP protocol
  23. //
  24. //----------------------------------------------------------------------------
  25. BOOL WINAPI LdapRetrieveEncodedObject (
  26. IN LPCWSTR pwszUrl,
  27. IN LPCSTR pszObjectOid,
  28. IN DWORD dwRetrievalFlags,
  29. IN DWORD dwTimeout,
  30. OUT PCRYPT_BLOB_ARRAY pObject,
  31. OUT PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject,
  32. OUT LPVOID* ppvFreeContext,
  33. IN HCRYPTASYNC hAsyncRetrieve,
  34. IN PCRYPT_CREDENTIALS pCredentials,
  35. IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  36. )
  37. {
  38. BOOL fResult;
  39. IObjectRetriever* por = NULL;
  40. if ( !( dwRetrievalFlags & CRYPT_ASYNC_RETRIEVAL ) )
  41. {
  42. por = new CLdapSynchronousRetriever;
  43. }
  44. if ( por == NULL )
  45. {
  46. SetLastError( (DWORD) E_OUTOFMEMORY );
  47. return( FALSE );
  48. }
  49. fResult = por->RetrieveObjectByUrl(
  50. pwszUrl,
  51. pszObjectOid,
  52. dwRetrievalFlags,
  53. dwTimeout,
  54. (LPVOID *)pObject,
  55. ppfnFreeObject,
  56. ppvFreeContext,
  57. hAsyncRetrieve,
  58. pCredentials,
  59. NULL,
  60. pAuxInfo
  61. );
  62. por->Release();
  63. return( fResult );
  64. }
  65. //+---------------------------------------------------------------------------
  66. //
  67. // Function: LdapFreeEncodedObject
  68. //
  69. // Synopsis: free encoded object retrieved via LdapRetrieveEncodedObject
  70. //
  71. //----------------------------------------------------------------------------
  72. VOID WINAPI LdapFreeEncodedObject (
  73. IN LPCSTR pszObjectOid,
  74. IN PCRYPT_BLOB_ARRAY pObject,
  75. IN LPVOID pvFreeContext
  76. )
  77. {
  78. assert( pvFreeContext == NULL );
  79. LdapFreeCryptBlobArray( pObject );
  80. }
  81. //+---------------------------------------------------------------------------
  82. //
  83. // Function: LdapCancelAsyncRetrieval
  84. //
  85. // Synopsis: cancel asynchronous object retrieval
  86. //
  87. //----------------------------------------------------------------------------
  88. BOOL WINAPI LdapCancelAsyncRetrieval (
  89. IN HCRYPTASYNC hAsyncRetrieve
  90. )
  91. {
  92. SetLastError( (DWORD) E_NOTIMPL );
  93. return( FALSE );
  94. }
  95. //+---------------------------------------------------------------------------
  96. //
  97. // Member: CLdapSynchronousRetriever::CLdapSynchronousRetriever, public
  98. //
  99. // Synopsis: Constructor
  100. //
  101. //----------------------------------------------------------------------------
  102. CLdapSynchronousRetriever::CLdapSynchronousRetriever ()
  103. {
  104. m_cRefs = 1;
  105. }
  106. //+---------------------------------------------------------------------------
  107. //
  108. // Member: CLdapSynchronousRetriever::~CLdapSynchronousRetriever, public
  109. //
  110. // Synopsis: Destructor
  111. //
  112. //----------------------------------------------------------------------------
  113. CLdapSynchronousRetriever::~CLdapSynchronousRetriever ()
  114. {
  115. }
  116. //+---------------------------------------------------------------------------
  117. //
  118. // Member: CLdapSynchronousRetriever::AddRef, public
  119. //
  120. // Synopsis: IRefCountedObject::AddRef
  121. //
  122. //----------------------------------------------------------------------------
  123. VOID
  124. CLdapSynchronousRetriever::AddRef ()
  125. {
  126. InterlockedIncrement( (LONG *)&m_cRefs );
  127. }
  128. //+---------------------------------------------------------------------------
  129. //
  130. // Member: CLdapSynchronousRetriever::Release, public
  131. //
  132. // Synopsis: IRefCountedObject::Release
  133. //
  134. //----------------------------------------------------------------------------
  135. VOID
  136. CLdapSynchronousRetriever::Release ()
  137. {
  138. if ( InterlockedDecrement( (LONG *)&m_cRefs ) == 0 )
  139. {
  140. delete this;
  141. }
  142. }
  143. //+---------------------------------------------------------------------------
  144. //
  145. // Member: CLdapSynchronousRetriever::RetrieveObjectByUrl, public
  146. //
  147. // Synopsis: IObjectRetriever::RetrieveObjectByUrl
  148. //
  149. //----------------------------------------------------------------------------
  150. BOOL
  151. CLdapSynchronousRetriever::RetrieveObjectByUrl (
  152. LPCWSTR pwszUrl,
  153. LPCSTR pszObjectOid,
  154. DWORD dwRetrievalFlags,
  155. DWORD dwTimeout,
  156. LPVOID* ppvObject,
  157. PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject,
  158. LPVOID* ppvFreeContext,
  159. HCRYPTASYNC hAsyncRetrieve,
  160. PCRYPT_CREDENTIALS pCredentials,
  161. LPVOID pvVerify,
  162. PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  163. )
  164. {
  165. BOOL fResult;
  166. DWORD LastError = 0;
  167. LDAP_URL_COMPONENTS LdapUrlComponents;
  168. LDAP* pld = NULL;
  169. BOOL fLdapUrlCracked = FALSE;
  170. assert( hAsyncRetrieve == NULL );
  171. if ( dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL )
  172. {
  173. return( SchemeRetrieveCachedCryptBlobArray(
  174. pwszUrl,
  175. dwRetrievalFlags,
  176. (PCRYPT_BLOB_ARRAY)ppvObject,
  177. ppfnFreeObject,
  178. ppvFreeContext,
  179. pAuxInfo
  180. ) );
  181. }
  182. fResult = LdapCrackUrl( pwszUrl, &LdapUrlComponents );
  183. #if DBG
  184. if ( fResult == TRUE )
  185. {
  186. LdapDisplayUrlComponents( &LdapUrlComponents );
  187. }
  188. #endif
  189. if ( fResult == TRUE )
  190. {
  191. fLdapUrlCracked = TRUE;
  192. if ( dwRetrievalFlags & CRYPT_LDAP_SCOPE_BASE_ONLY_RETRIEVAL )
  193. {
  194. if ( LdapUrlComponents.Scope != LDAP_SCOPE_BASE )
  195. {
  196. fResult = FALSE;
  197. SetLastError( (DWORD) E_INVALIDARG );
  198. }
  199. }
  200. }
  201. if ( fResult == TRUE )
  202. {
  203. DWORD iAuth;
  204. if ( dwRetrievalFlags &
  205. (CRYPT_LDAP_AREC_EXCLUSIVE_RETRIEVAL |
  206. CRYPT_LDAP_SIGN_RETRIEVAL) )
  207. {
  208. // Only attempt AUTH_SSPI binds
  209. iAuth = 1;
  210. }
  211. else
  212. {
  213. // First attempt AUTH_SIMPLE bind. If that fails or returns
  214. // nothing, then, attempt AUTH_SSPI bind.
  215. iAuth = 0;
  216. }
  217. for ( ; iAuth < 2; iAuth++)
  218. {
  219. fResult = LdapGetBindings(
  220. LdapUrlComponents.pwszHost,
  221. LdapUrlComponents.Port,
  222. dwRetrievalFlags,
  223. 0 == iAuth ? LDAP_BIND_AUTH_SIMPLE_ENABLE_FLAG :
  224. LDAP_BIND_AUTH_SSPI_ENABLE_FLAG,
  225. dwTimeout,
  226. pCredentials,
  227. &pld
  228. );
  229. if ( fResult == TRUE )
  230. {
  231. fResult = LdapSendReceiveUrlRequest(
  232. pld,
  233. &LdapUrlComponents,
  234. dwRetrievalFlags,
  235. dwTimeout,
  236. (PCRYPT_BLOB_ARRAY)ppvObject,
  237. pAuxInfo
  238. );
  239. if ( fResult == TRUE )
  240. {
  241. break;
  242. }
  243. else
  244. {
  245. LastError = GetLastError();
  246. LdapFreeBindings( pld );
  247. pld = NULL;
  248. SetLastError( LastError );
  249. }
  250. }
  251. }
  252. }
  253. if ( fResult == TRUE )
  254. {
  255. if ( !( dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT ) )
  256. {
  257. fResult = SchemeCacheCryptBlobArray(
  258. pwszUrl,
  259. dwRetrievalFlags,
  260. (PCRYPT_BLOB_ARRAY)ppvObject,
  261. pAuxInfo
  262. );
  263. if ( fResult == FALSE )
  264. {
  265. LdapFreeEncodedObject(
  266. pszObjectOid,
  267. (PCRYPT_BLOB_ARRAY)ppvObject,
  268. NULL
  269. );
  270. }
  271. }
  272. else
  273. {
  274. SchemeRetrieveUncachedAuxInfo( pAuxInfo );
  275. }
  276. }
  277. if ( fResult == TRUE )
  278. {
  279. *ppfnFreeObject = LdapFreeEncodedObject;
  280. *ppvFreeContext = NULL;
  281. }
  282. else
  283. {
  284. LastError = GetLastError();
  285. }
  286. if ( fLdapUrlCracked == TRUE )
  287. {
  288. LdapFreeUrlComponents( &LdapUrlComponents );
  289. }
  290. LdapFreeBindings( pld );
  291. SetLastError( LastError );
  292. return( fResult );
  293. }
  294. //+---------------------------------------------------------------------------
  295. //
  296. // Member: CLdapSynchronousRetriever::CancelAsyncRetrieval, public
  297. //
  298. // Synopsis: IObjectRetriever::CancelAsyncRetrieval
  299. //
  300. //----------------------------------------------------------------------------
  301. BOOL
  302. CLdapSynchronousRetriever::CancelAsyncRetrieval ()
  303. {
  304. SetLastError( (DWORD) E_NOTIMPL );
  305. return( FALSE );
  306. }
  307. //+---------------------------------------------------------------------------
  308. //
  309. // Function: LdapCrackUrl
  310. //
  311. // Synopsis: Crack an LDAP URL into its relevant parts. The result must
  312. // be freed using LdapFreeUrlComponents
  313. //
  314. //----------------------------------------------------------------------------
  315. BOOL
  316. LdapCrackUrl (
  317. LPCWSTR pwszUrl,
  318. PLDAP_URL_COMPONENTS pLdapUrlComponents
  319. )
  320. {
  321. BOOL fResult = TRUE;
  322. LPWSTR pwszHostInfo = NULL;
  323. LPWSTR pwszDN = NULL;
  324. LPWSTR pwszAttrList = NULL;
  325. LPWSTR pwszScope = NULL;
  326. LPWSTR pwszFilter = NULL;
  327. LPWSTR pwszToken = NULL;
  328. WCHAR pwsz[INTERNET_MAX_PATH_LENGTH+1];
  329. ULONG cchUrl = INTERNET_MAX_PATH_LENGTH;
  330. //
  331. // Capture the URL and initialize the out parameter
  332. //
  333. __try
  334. {
  335. HRESULT hr;
  336. #if 0
  337. // UrlCanonicalizeW() moves stuff after the # character to
  338. // the end of Url.
  339. hr = UrlCanonicalizeW(
  340. pwszUrl,
  341. pwsz,
  342. &cchUrl,
  343. URL_UNESCAPE | URL_WININET_COMPATIBILITY
  344. );
  345. #else
  346. // UrlUnescapeW() handles the # character properly
  347. hr = UrlUnescapeW(
  348. (LPWSTR) pwszUrl,
  349. pwsz,
  350. &cchUrl,
  351. 0
  352. );
  353. #endif
  354. if (S_OK != hr)
  355. {
  356. SetLastError( (DWORD) hr );
  357. return( FALSE );
  358. }
  359. if ( pwsz[0] == L'\0' )
  360. {
  361. SetLastError( (DWORD) E_INVALIDARG );
  362. return( FALSE );
  363. }
  364. pwsz[sizeof(pwsz)/sizeof(pwsz[0]) - 1] = L'\0';
  365. }
  366. __except(EXCEPTION_EXECUTE_HANDLER)
  367. {
  368. SetLastError( GetExceptionCode() );
  369. return( FALSE );
  370. }
  371. memset( pLdapUrlComponents, 0, sizeof( LDAP_URL_COMPONENTS ) );
  372. //
  373. // Find the host
  374. //
  375. pwszHostInfo = pwsz + wcslen( L"ldap://" );
  376. if ( *pwszHostInfo == L'/' )
  377. {
  378. pwszToken = pwszHostInfo + 1;
  379. pwszHostInfo = NULL;
  380. }
  381. else
  382. {
  383. #if 0
  384. pwszHostInfo = wcstok( pszHostInfo, "/" );
  385. #else
  386. pwszToken = pwszHostInfo;
  387. while ( ( *pwszToken != L'\0' ) && ( *pwszToken != L'/' ) )
  388. pwszToken++;
  389. if ( *pwszToken == L'/' )
  390. {
  391. *pwszToken = L'\0';
  392. pwszToken += 1;
  393. }
  394. while ( *pwszToken == L'/' )
  395. pwszToken++;
  396. #endif
  397. }
  398. //
  399. // Find the DN
  400. //
  401. if ( pwszToken != NULL )
  402. {
  403. pwszDN = L"";
  404. if ( *pwszToken != L'\0' )
  405. {
  406. if ( *pwszToken == L'?' )
  407. {
  408. pwszToken += 1;
  409. }
  410. else
  411. {
  412. pwszDN = pwszToken;
  413. do
  414. {
  415. pwszToken += 1;
  416. }
  417. while ( ( *pwszToken != L'\0' ) && ( *pwszToken != L'?' ) );
  418. if ( *pwszToken == L'?' )
  419. {
  420. *pwszToken = L'\0';
  421. pwszToken += 1;
  422. }
  423. }
  424. }
  425. }
  426. else
  427. {
  428. pwszDN = wcstok( pwszToken, L"?" );
  429. pwszToken = NULL;
  430. if ( pwszDN == NULL )
  431. {
  432. SetLastError( (DWORD) E_INVALIDARG );
  433. return( FALSE );
  434. }
  435. }
  436. //
  437. // Check for attributes
  438. //
  439. if ( pwszToken != NULL )
  440. {
  441. if ( *pwszToken == L'?' )
  442. {
  443. pwszAttrList = L"";
  444. pwszToken += 1;
  445. }
  446. else if ( *pwszToken == L'\0' )
  447. {
  448. pwszAttrList = NULL;
  449. }
  450. else
  451. {
  452. pwszAttrList = wcstok( pwszToken, L"?" );
  453. pwszToken = NULL;
  454. }
  455. }
  456. else
  457. {
  458. pwszAttrList = wcstok( NULL, L"?" );
  459. }
  460. //
  461. // Check for a scope and filter
  462. //
  463. if ( pwszAttrList != NULL )
  464. {
  465. pwszScope = wcstok( pwszToken, L"?" );
  466. if ( pwszScope != NULL )
  467. {
  468. pwszFilter = wcstok( NULL, L"?" );
  469. }
  470. }
  471. if ( pwszScope == NULL )
  472. {
  473. pwszScope = L"base";
  474. }
  475. if ( pwszFilter == NULL )
  476. {
  477. pwszFilter = L"(objectClass=*)";
  478. }
  479. //
  480. // Now we build up our URL components
  481. //
  482. fResult = LdapParseCrackedHost( pwszHostInfo, pLdapUrlComponents );
  483. if ( fResult == TRUE )
  484. {
  485. fResult = LdapParseCrackedDN( pwszDN, pLdapUrlComponents );
  486. }
  487. if ( fResult == TRUE )
  488. {
  489. fResult = LdapParseCrackedAttributeList(
  490. pwszAttrList,
  491. pLdapUrlComponents
  492. );
  493. }
  494. if ( fResult == TRUE )
  495. {
  496. fResult = LdapParseCrackedScopeAndFilter(
  497. pwszScope,
  498. pwszFilter,
  499. pLdapUrlComponents
  500. );
  501. }
  502. if ( fResult != TRUE )
  503. {
  504. LdapFreeUrlComponents( pLdapUrlComponents );
  505. }
  506. return( fResult );
  507. }
  508. //+---------------------------------------------------------------------------
  509. //
  510. // Function: LdapParseCrackedHost
  511. //
  512. // Synopsis: Parse the cracked host string (pszHost is modified)
  513. //
  514. //----------------------------------------------------------------------------
  515. BOOL
  516. LdapParseCrackedHost (
  517. LPWSTR pwszHost,
  518. PLDAP_URL_COMPONENTS pLdapUrlComponents
  519. )
  520. {
  521. LPWSTR pwszPort;
  522. if ( pwszHost != NULL )
  523. {
  524. pwszHost = wcstok( pwszHost, L" " );
  525. }
  526. if ( pwszHost == NULL )
  527. {
  528. pLdapUrlComponents->pwszHost = NULL;
  529. pLdapUrlComponents->Port = LDAP_PORT;
  530. return( TRUE );
  531. }
  532. // See if multiple host names are present
  533. if ( NULL != wcstok( NULL, L" " ) )
  534. {
  535. SetLastError( (DWORD) E_INVALIDARG );
  536. return( FALSE );
  537. }
  538. pwszPort = wcschr( pwszHost, L':' );
  539. if ( pwszPort != NULL )
  540. {
  541. *pwszPort = L'\0';
  542. pwszPort++;
  543. }
  544. pLdapUrlComponents->pwszHost = new WCHAR [wcslen( pwszHost ) + 1];
  545. if ( pLdapUrlComponents->pwszHost == NULL )
  546. {
  547. SetLastError( (DWORD) E_OUTOFMEMORY );
  548. return( FALSE );
  549. }
  550. wcscpy( pLdapUrlComponents->pwszHost, pwszHost );
  551. pLdapUrlComponents->Port = 0;
  552. if ( pwszPort != NULL )
  553. {
  554. pLdapUrlComponents->Port = _wtol( pwszPort );
  555. }
  556. if ( pLdapUrlComponents->Port == 0 )
  557. {
  558. pLdapUrlComponents->Port = LDAP_PORT;
  559. }
  560. return( TRUE );
  561. }
  562. //+---------------------------------------------------------------------------
  563. //
  564. // Function: LdapParseCrackedDN
  565. //
  566. // Synopsis: Parse the cracked DN
  567. //
  568. //----------------------------------------------------------------------------
  569. BOOL
  570. LdapParseCrackedDN (
  571. LPWSTR pwszDN,
  572. PLDAP_URL_COMPONENTS pLdapUrlComponents
  573. )
  574. {
  575. pLdapUrlComponents->pwszDN = new WCHAR [wcslen( pwszDN ) + 1];
  576. if ( pLdapUrlComponents->pwszDN == NULL )
  577. {
  578. SetLastError( (DWORD) E_OUTOFMEMORY );
  579. return( FALSE );
  580. }
  581. wcscpy( pLdapUrlComponents->pwszDN, pwszDN );
  582. return( TRUE );
  583. }
  584. //+---------------------------------------------------------------------------
  585. //
  586. // Function: LdapParseCrackedAttributeList
  587. //
  588. // Synopsis: Parse the cracked attribute list
  589. //
  590. //----------------------------------------------------------------------------
  591. BOOL
  592. LdapParseCrackedAttributeList (
  593. LPWSTR pwszAttrList,
  594. PLDAP_URL_COMPONENTS pLdapUrlComponents
  595. )
  596. {
  597. LPWSTR pwsz;
  598. LPWSTR pwszAttr;
  599. ULONG cAttr = 0;
  600. ULONG cCount;
  601. if ( ( pwszAttrList == NULL ) || ( wcslen( pwszAttrList ) == 0 ) )
  602. {
  603. pLdapUrlComponents->cAttr = 0;
  604. pLdapUrlComponents->apwszAttr = NULL;
  605. return( TRUE );
  606. }
  607. pwsz = new WCHAR [wcslen( pwszAttrList ) + 1];
  608. if ( pwsz == NULL )
  609. {
  610. SetLastError( (DWORD) E_OUTOFMEMORY );
  611. return( FALSE );
  612. }
  613. wcscpy( pwsz, pwszAttrList );
  614. pwszAttr = wcstok( pwsz, L"," );
  615. while ( pwszAttr != NULL )
  616. {
  617. cAttr += 1;
  618. pwszAttr = wcstok( NULL, L"," );
  619. }
  620. pLdapUrlComponents->apwszAttr = new LPWSTR [cAttr+1];
  621. if ( pLdapUrlComponents->apwszAttr == NULL )
  622. {
  623. delete [] pwsz;
  624. SetLastError( (DWORD) E_OUTOFMEMORY );
  625. return( FALSE );
  626. }
  627. pLdapUrlComponents->cAttr = cAttr;
  628. for ( cCount = 0; cCount < cAttr; cCount++ )
  629. {
  630. pLdapUrlComponents->apwszAttr[cCount] = pwsz;
  631. pwsz += ( wcslen(pwsz) + 1 );
  632. }
  633. pLdapUrlComponents->apwszAttr[cAttr] = NULL;
  634. return( TRUE );
  635. }
  636. //+---------------------------------------------------------------------------
  637. //
  638. // Function: LdapParseCrackedScopeAndFilter
  639. //
  640. // Synopsis: Parse the cracked scope and filter
  641. //
  642. //----------------------------------------------------------------------------
  643. BOOL
  644. LdapParseCrackedScopeAndFilter (
  645. LPWSTR pwszScope,
  646. LPWSTR pwszFilter,
  647. PLDAP_URL_COMPONENTS pLdapUrlComponents
  648. )
  649. {
  650. ULONG Scope;
  651. if ( _wcsicmp( pwszScope, L"base" ) == 0 )
  652. {
  653. Scope = LDAP_SCOPE_BASE;
  654. }
  655. else if ( _wcsicmp( pwszScope, L"one" ) == 0 )
  656. {
  657. Scope = LDAP_SCOPE_ONELEVEL;
  658. }
  659. else if ( _wcsicmp( pwszScope, L"sub" ) == 0 )
  660. {
  661. Scope = LDAP_SCOPE_SUBTREE;
  662. }
  663. else
  664. {
  665. SetLastError( (DWORD) E_INVALIDARG );
  666. return( FALSE );
  667. }
  668. pLdapUrlComponents->pwszFilter = new WCHAR [wcslen( pwszFilter ) + 1];
  669. if ( pLdapUrlComponents->pwszFilter == NULL )
  670. {
  671. SetLastError( (DWORD) E_OUTOFMEMORY );
  672. return( FALSE );
  673. }
  674. wcscpy( pLdapUrlComponents->pwszFilter, pwszFilter );
  675. pLdapUrlComponents->Scope = Scope;
  676. return( TRUE );
  677. }
  678. //+---------------------------------------------------------------------------
  679. //
  680. // Function: LdapFreeUrlComponents
  681. //
  682. // Synopsis: Frees allocate URL components returned from LdapCrackUrl
  683. //
  684. //----------------------------------------------------------------------------
  685. VOID
  686. LdapFreeUrlComponents (
  687. PLDAP_URL_COMPONENTS pLdapUrlComponents
  688. )
  689. {
  690. delete [] pLdapUrlComponents->pwszHost;
  691. delete [] pLdapUrlComponents->pwszDN;
  692. if ( pLdapUrlComponents->apwszAttr != NULL )
  693. {
  694. delete pLdapUrlComponents->apwszAttr[0];
  695. }
  696. delete [] pLdapUrlComponents->apwszAttr;
  697. delete [] pLdapUrlComponents->pwszFilter;
  698. }
  699. //+---------------------------------------------------------------------------
  700. //
  701. // Function: LdapGetBindings
  702. //
  703. // Synopsis: allocates and initializes the LDAP session binding
  704. //
  705. //----------------------------------------------------------------------------
  706. BOOL
  707. LdapGetBindings (
  708. LPWSTR pwszHost,
  709. ULONG Port,
  710. DWORD dwRetrievalFlags,
  711. DWORD dwBindFlags,
  712. DWORD dwTimeout, // milliseconds
  713. PCRYPT_CREDENTIALS pCredentials,
  714. LDAP** ppld
  715. )
  716. {
  717. BOOL fResult = TRUE;
  718. DWORD LastError = 0;
  719. CRYPT_PASSWORD_CREDENTIALSW PasswordCredentials;
  720. LDAP* pld = NULL;
  721. BOOL fFreeCredentials = FALSE;
  722. memset( &PasswordCredentials, 0, sizeof( PasswordCredentials ) );
  723. PasswordCredentials.cbSize = sizeof( PasswordCredentials );
  724. if ( SchemeGetPasswordCredentialsW(
  725. pCredentials,
  726. &PasswordCredentials,
  727. &fFreeCredentials
  728. ) == FALSE )
  729. {
  730. return( FALSE );
  731. }
  732. pld = ldap_initW( pwszHost, Port );
  733. if ( pld != NULL )
  734. {
  735. SEC_WINNT_AUTH_IDENTITY_W AuthIdentity;
  736. ULONG ldaperr;
  737. struct l_timeval tv;
  738. struct l_timeval *ptv = NULL;
  739. if ((dwRetrievalFlags & CRYPT_LDAP_AREC_EXCLUSIVE_RETRIEVAL) &&
  740. (NULL != pwszHost))
  741. {
  742. void *pvOn;
  743. pvOn = LDAP_OPT_ON;
  744. ldap_set_option(
  745. pld,
  746. LDAP_OPT_AREC_EXCLUSIVE,
  747. &pvOn
  748. );
  749. }
  750. // Note, dwTimeout is in units of milliseconds.
  751. // LDAP_OPT_TIMELIMIT is in units of seconds.
  752. if ( 0 != dwTimeout )
  753. {
  754. DWORD dwTimeoutSeconds = dwTimeout / 1000;
  755. if ( LDAP_MIN_TIMEOUT_SECONDS > dwTimeoutSeconds )
  756. {
  757. dwTimeoutSeconds = LDAP_MIN_TIMEOUT_SECONDS;
  758. }
  759. tv.tv_sec = dwTimeoutSeconds;
  760. tv.tv_usec = 0;
  761. ptv = &tv;
  762. ldap_set_option( pld, LDAP_OPT_TIMELIMIT,
  763. (void *)&dwTimeoutSeconds );
  764. }
  765. ldaperr = ldap_connect( pld, ptv );
  766. if ( ( ldaperr != LDAP_SUCCESS ) && ( pwszHost == NULL ) )
  767. {
  768. DWORD dwFlags = DS_FORCE_REDISCOVERY;
  769. ULONG ldapsaveerr = ldaperr;
  770. ldaperr = ldap_set_option(
  771. pld,
  772. LDAP_OPT_GETDSNAME_FLAGS,
  773. (LPVOID)&dwFlags
  774. );
  775. if ( ldaperr == LDAP_SUCCESS )
  776. {
  777. ldaperr = ldap_connect( pld, ptv );
  778. }
  779. else
  780. {
  781. ldaperr = ldapsaveerr;
  782. }
  783. }
  784. if ( ldaperr != LDAP_SUCCESS )
  785. {
  786. fResult = FALSE;
  787. SetLastError( I_CryptNetLdapMapErrorToWin32( pld, ldaperr ) );
  788. }
  789. if ( fResult == TRUE )
  790. {
  791. fResult = SchemeGetAuthIdentityFromPasswordCredentialsW(
  792. &PasswordCredentials,
  793. &AuthIdentity
  794. );
  795. if ( fResult == TRUE )
  796. {
  797. #if 0
  798. printf(
  799. "Credentials = %S\\%S <%S>\n",
  800. AuthIdentity.Domain,
  801. AuthIdentity.User,
  802. AuthIdentity.Password
  803. );
  804. #endif
  805. fResult = LdapSSPIOrSimpleBind(
  806. pld,
  807. &AuthIdentity,
  808. dwRetrievalFlags,
  809. dwBindFlags
  810. );
  811. // following doesn't globber LastError
  812. SchemeFreeAuthIdentityFromPasswordCredentialsW(
  813. &PasswordCredentials,
  814. &AuthIdentity
  815. );
  816. }
  817. }
  818. }
  819. else
  820. {
  821. fResult = FALSE;
  822. }
  823. if ( fResult == TRUE )
  824. {
  825. *ppld = pld;
  826. }
  827. else
  828. {
  829. LastError = GetLastError();
  830. LdapFreeBindings( pld );
  831. }
  832. if ( fFreeCredentials == TRUE )
  833. {
  834. SchemeFreePasswordCredentialsW( &PasswordCredentials );
  835. }
  836. SetLastError( LastError );
  837. return( fResult );
  838. }
  839. //+---------------------------------------------------------------------------
  840. //
  841. // Function: LdapFreeBindings
  842. //
  843. // Synopsis: frees allocated LDAP session binding
  844. //
  845. //----------------------------------------------------------------------------
  846. VOID
  847. LdapFreeBindings (
  848. LDAP* pld
  849. )
  850. {
  851. if ( pld != NULL )
  852. {
  853. ldap_unbind_s( pld );
  854. }
  855. }
  856. //+---------------------------------------------------------------------------
  857. //
  858. // Function: LdapSendReceiveUrlRequest
  859. //
  860. // Synopsis: sends an URL based search request to the LDAP server, receives
  861. // the result message and converts it to a CRYPT_BLOB_ARRAY of
  862. // encoded object bits
  863. //
  864. //----------------------------------------------------------------------------
  865. BOOL
  866. LdapSendReceiveUrlRequest (
  867. LDAP* pld,
  868. PLDAP_URL_COMPONENTS pLdapUrlComponents,
  869. DWORD dwRetrievalFlags,
  870. DWORD dwTimeout, // milliseconds
  871. PCRYPT_BLOB_ARRAY pcba,
  872. PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  873. )
  874. {
  875. BOOL fResult;
  876. DWORD LastError = 0;
  877. ULONG lderr;
  878. LDAPMessage* plm = NULL;
  879. if ( 0 != dwTimeout )
  880. {
  881. DWORD dwTimeoutSeconds = dwTimeout / 1000;
  882. struct l_timeval tv;
  883. if ( LDAP_MIN_TIMEOUT_SECONDS > dwTimeoutSeconds )
  884. {
  885. dwTimeoutSeconds = LDAP_MIN_TIMEOUT_SECONDS;
  886. }
  887. tv.tv_sec = dwTimeoutSeconds;
  888. tv.tv_usec = 0;
  889. lderr = ldap_search_stW(
  890. pld,
  891. pLdapUrlComponents->pwszDN,
  892. pLdapUrlComponents->Scope,
  893. pLdapUrlComponents->pwszFilter,
  894. pLdapUrlComponents->apwszAttr,
  895. FALSE,
  896. &tv,
  897. &plm
  898. );
  899. }
  900. else
  901. {
  902. lderr = ldap_search_sW(
  903. pld,
  904. pLdapUrlComponents->pwszDN,
  905. pLdapUrlComponents->Scope,
  906. pLdapUrlComponents->pwszFilter,
  907. pLdapUrlComponents->apwszAttr,
  908. FALSE,
  909. &plm
  910. );
  911. }
  912. if ( lderr != LDAP_SUCCESS )
  913. {
  914. if ( plm != NULL )
  915. {
  916. ldap_msgfree( plm );
  917. }
  918. SetLastError( I_CryptNetLdapMapErrorToWin32( pld, lderr ) );
  919. return( FALSE );
  920. }
  921. fResult = LdapConvertLdapResultMessage( pld, plm, dwRetrievalFlags, pcba, pAuxInfo);
  922. if ( !fResult )
  923. {
  924. LastError = GetLastError();
  925. }
  926. ldap_msgfree( plm );
  927. SetLastError( LastError );
  928. return( fResult );
  929. }
  930. //+---------------------------------------------------------------------------
  931. //
  932. // Function: LdapConvertResultMessage
  933. //
  934. // Synopsis: convert returned LDAP message to a crypt blob array
  935. //
  936. //----------------------------------------------------------------------------
  937. BOOL
  938. LdapConvertLdapResultMessage (
  939. LDAP* pld,
  940. PLDAPMessage plm,
  941. DWORD dwRetrievalFlags,
  942. PCRYPT_BLOB_ARRAY pcba,
  943. PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  944. )
  945. {
  946. BOOL fResult = TRUE;
  947. PLDAPMessage plmElem;
  948. BerElement* pber;
  949. CHAR* pszAttr;
  950. struct berval** apbv;
  951. ULONG cCount;
  952. CCryptBlobArray cba( 10, 5, fResult );
  953. DWORD dwIndex;
  954. ULONG cbIndex = 0;
  955. char szIndex[33];
  956. ULONG cbTotalVal = 0;
  957. DWORD dwMaxUrlRetrievalByteCount = 0; // 0 => no max
  958. if (pAuxInfo &&
  959. offsetof(CRYPT_RETRIEVE_AUX_INFO, dwMaxUrlRetrievalByteCount) <
  960. pAuxInfo->cbSize)
  961. dwMaxUrlRetrievalByteCount = pAuxInfo->dwMaxUrlRetrievalByteCount;
  962. for ( plmElem = ldap_first_entry( pld, plm ), dwIndex = 0;
  963. ( plmElem != NULL ) && ( fResult == TRUE );
  964. plmElem = ldap_next_entry( pld, plmElem ), dwIndex++ )
  965. {
  966. if ( dwRetrievalFlags & CRYPT_LDAP_INSERT_ENTRY_ATTRIBUTE )
  967. {
  968. _ltoa(dwIndex, szIndex, 10);
  969. cbIndex = strlen(szIndex) + 1;
  970. }
  971. for ( pszAttr = ldap_first_attributeA( pld, plmElem, &pber );
  972. ( pszAttr != NULL ) && ( fResult == TRUE );
  973. pszAttr = ldap_next_attributeA( pld, plmElem, pber ) )
  974. {
  975. apbv = ldap_get_values_lenA( pld, plmElem, pszAttr );
  976. if ( apbv == NULL )
  977. {
  978. fResult = FALSE;
  979. }
  980. for ( cCount = 0;
  981. ( fResult == TRUE ) && ( apbv[cCount] != NULL );
  982. cCount++ )
  983. {
  984. ULONG cbAttr = 0;
  985. ULONG cbVal;
  986. ULONG cbToAdd;
  987. LPBYTE pbToAdd;
  988. cbToAdd = cbVal = apbv[cCount]->bv_len;
  989. cbTotalVal += cbVal;
  990. if ((0 != dwMaxUrlRetrievalByteCount) &&
  991. (cbTotalVal > dwMaxUrlRetrievalByteCount))
  992. {
  993. I_CryptNetDebugErrorPrintfA(
  994. "CRYPTNET.DLL --> Exceeded MaxUrlRetrievalByteCount for: Ldap Url\n");
  995. SetLastError(ERROR_INVALID_DATA);
  996. fResult = FALSE;
  997. continue;
  998. }
  999. if ( dwRetrievalFlags & CRYPT_LDAP_INSERT_ENTRY_ATTRIBUTE )
  1000. {
  1001. cbAttr = strlen(pszAttr) + 1;
  1002. cbToAdd += cbIndex + cbAttr;
  1003. }
  1004. pbToAdd = cba.AllocBlob( cbToAdd );
  1005. if ( pbToAdd != NULL )
  1006. {
  1007. LPBYTE pb;
  1008. pb = pbToAdd;
  1009. if ( dwRetrievalFlags & CRYPT_LDAP_INSERT_ENTRY_ATTRIBUTE )
  1010. {
  1011. memcpy( pb, szIndex, cbIndex );
  1012. pb += cbIndex;
  1013. memcpy( pb, pszAttr, cbAttr );
  1014. pb += cbAttr;
  1015. }
  1016. memcpy( pb, (LPBYTE)apbv[cCount]->bv_val, cbVal );
  1017. }
  1018. else
  1019. {
  1020. SetLastError( (DWORD) E_OUTOFMEMORY );
  1021. fResult = FALSE;
  1022. }
  1023. if ( fResult == TRUE )
  1024. {
  1025. fResult = cba.AddBlob(
  1026. cbToAdd,
  1027. pbToAdd,
  1028. FALSE
  1029. );
  1030. if ( fResult == FALSE )
  1031. {
  1032. cba.FreeBlob( pbToAdd );
  1033. }
  1034. }
  1035. }
  1036. ldap_value_free_len( apbv );
  1037. }
  1038. }
  1039. if ( fResult == TRUE )
  1040. {
  1041. if ( cba.GetBlobCount() > 0 )
  1042. {
  1043. cba.GetArrayInNativeForm( pcba );
  1044. }
  1045. else
  1046. {
  1047. cba.FreeArray( TRUE );
  1048. SetLastError( (DWORD) CRYPT_E_NOT_FOUND );
  1049. fResult = FALSE;
  1050. }
  1051. }
  1052. else
  1053. {
  1054. cba.FreeArray( TRUE );
  1055. }
  1056. return( fResult );
  1057. }
  1058. //+---------------------------------------------------------------------------
  1059. //
  1060. // Function: LdapFreeCryptBlobArray
  1061. //
  1062. // Synopsis: free CRYPT_BLOB_ARRAY allocated in LdapConvertLdapResultMessage
  1063. //
  1064. //----------------------------------------------------------------------------
  1065. VOID
  1066. LdapFreeCryptBlobArray (
  1067. PCRYPT_BLOB_ARRAY pcba
  1068. )
  1069. {
  1070. CCryptBlobArray cba( pcba, 0 );
  1071. cba.FreeArray( TRUE );
  1072. }
  1073. //+---------------------------------------------------------------------------
  1074. //
  1075. // Function: LdapHasWriteAccess
  1076. //
  1077. // Synopsis: check if the caller has write access to the given LDAP URL
  1078. // query components
  1079. //
  1080. //----------------------------------------------------------------------------
  1081. BOOL
  1082. LdapHasWriteAccess (
  1083. LDAP* pld,
  1084. PLDAP_URL_COMPONENTS pLdapUrlComponents,
  1085. DWORD dwTimeout
  1086. )
  1087. {
  1088. BOOL fResult = FALSE;
  1089. LPWSTR pwszAttr = L"allowedAttributesEffective";
  1090. LPWSTR apwszAttr[2] = {pwszAttr, NULL};
  1091. LDAP_URL_COMPONENTS LdapUrlComponents;
  1092. CRYPT_BLOB_ARRAY cba;
  1093. ULONG cCount;
  1094. ULONG cchAttr;
  1095. LPSTR pszUrlAttr = NULL;
  1096. if ( ( pLdapUrlComponents->cAttr != 1 ) ||
  1097. ( pLdapUrlComponents->Scope != LDAP_SCOPE_BASE ) )
  1098. {
  1099. return( FALSE );
  1100. }
  1101. memset( &LdapUrlComponents, 0, sizeof( LdapUrlComponents ) );
  1102. LdapUrlComponents.pwszHost = pLdapUrlComponents->pwszHost;
  1103. LdapUrlComponents.Port = pLdapUrlComponents->Port;
  1104. LdapUrlComponents.pwszDN = pLdapUrlComponents->pwszDN;
  1105. LdapUrlComponents.cAttr = 1;
  1106. LdapUrlComponents.apwszAttr = apwszAttr;
  1107. LdapUrlComponents.Scope = LDAP_SCOPE_BASE;
  1108. LdapUrlComponents.pwszFilter = L"(objectClass=*)";
  1109. if ( LdapSendReceiveUrlRequest( pld, &LdapUrlComponents, 0, dwTimeout, &cba, NULL ) == FALSE )
  1110. {
  1111. return( FALSE );
  1112. }
  1113. cchAttr = wcslen( pLdapUrlComponents->apwszAttr[ 0 ] );
  1114. pszUrlAttr = new CHAR [cchAttr + 1];
  1115. if ( pszUrlAttr == NULL )
  1116. {
  1117. SetLastError( (DWORD) E_OUTOFMEMORY );
  1118. return( FALSE );
  1119. }
  1120. if ( WideCharToMultiByte(
  1121. CP_ACP,
  1122. 0,
  1123. pLdapUrlComponents->apwszAttr[ 0 ],
  1124. -1,
  1125. pszUrlAttr,
  1126. cchAttr + 1,
  1127. NULL,
  1128. NULL
  1129. ) == FALSE )
  1130. {
  1131. delete [] pszUrlAttr;
  1132. return( FALSE );
  1133. }
  1134. for ( cCount = 0; cCount < cba.cBlob; cCount++ )
  1135. {
  1136. if ( cba.rgBlob[ cCount ].cbData != cchAttr )
  1137. {
  1138. continue;
  1139. }
  1140. if ( _strnicmp(
  1141. pszUrlAttr,
  1142. (LPSTR)cba.rgBlob[ cCount ].pbData,
  1143. cchAttr
  1144. ) == 0 )
  1145. {
  1146. fResult = TRUE;
  1147. break;
  1148. }
  1149. }
  1150. LdapFreeCryptBlobArray( &cba );
  1151. delete [] pszUrlAttr;
  1152. return( fResult );
  1153. }
  1154. //+---------------------------------------------------------------------------
  1155. //
  1156. // Function: LdapSSPIOrSimpleBind
  1157. //
  1158. // Synopsis: do a SSPI and/or simple bind
  1159. //
  1160. //----------------------------------------------------------------------------
  1161. BOOL
  1162. LdapSSPIOrSimpleBind (
  1163. LDAP* pld,
  1164. SEC_WINNT_AUTH_IDENTITY_W* pAuthIdentity,
  1165. DWORD dwRetrievalFlags,
  1166. DWORD dwBindFlags
  1167. )
  1168. {
  1169. BOOL fResult = TRUE;
  1170. ULONG ldaperr;
  1171. ULONG uVersion= LDAP_VERSION3;
  1172. // Per bug 25497, do V3 negotiate instead of the default V2.
  1173. ldap_set_option(pld, LDAP_OPT_VERSION, &uVersion);
  1174. if (dwRetrievalFlags & CRYPT_LDAP_SIGN_RETRIEVAL)
  1175. {
  1176. void *pvOn;
  1177. pvOn = LDAP_OPT_ON;
  1178. ldaperr = ldap_set_option(
  1179. pld,
  1180. LDAP_OPT_SIGN,
  1181. &pvOn
  1182. );
  1183. if ( ldaperr != LDAP_SUCCESS )
  1184. {
  1185. SetLastError( I_CryptNetLdapMapErrorToWin32( pld, ldaperr ) );
  1186. return FALSE;
  1187. }
  1188. }
  1189. ldaperr = LDAP_AUTH_METHOD_NOT_SUPPORTED;
  1190. if (dwBindFlags & LDAP_BIND_AUTH_SSPI_ENABLE_FLAG)
  1191. {
  1192. ldaperr = ldap_bind_sW(
  1193. pld,
  1194. NULL,
  1195. (PWCHAR)pAuthIdentity,
  1196. LDAP_AUTH_SSPI
  1197. );
  1198. }
  1199. if (dwBindFlags & LDAP_BIND_AUTH_SIMPLE_ENABLE_FLAG)
  1200. {
  1201. // Per Anoop's 4/25/00 email:
  1202. // You should fall back to anonymous bind only if the server returns
  1203. // LDAP_AUTH_METHOD_NOT_SUPPORTED.
  1204. //
  1205. // Per sergiod/trevorf 4/25/01 also need to check for invalid creds
  1206. // because target server could be in a different forest.
  1207. if ( ldaperr == LDAP_AUTH_METHOD_NOT_SUPPORTED ||
  1208. ldaperr == LDAP_INVALID_CREDENTIALS )
  1209. {
  1210. ldaperr = ldap_bind_sW(
  1211. pld,
  1212. NULL,
  1213. NULL,
  1214. LDAP_AUTH_SIMPLE
  1215. );
  1216. if ( ldaperr != LDAP_SUCCESS )
  1217. {
  1218. uVersion = LDAP_VERSION2;
  1219. if ( LDAP_SUCCESS == ldap_set_option(pld,
  1220. LDAP_OPT_VERSION,
  1221. &uVersion) )
  1222. {
  1223. ldaperr = ldap_bind_sW(
  1224. pld,
  1225. NULL,
  1226. NULL,
  1227. LDAP_AUTH_SIMPLE
  1228. );
  1229. }
  1230. }
  1231. }
  1232. }
  1233. if ( ldaperr != LDAP_SUCCESS )
  1234. {
  1235. fResult = FALSE;
  1236. if ( ldaperr != LDAP_LOCAL_ERROR )
  1237. {
  1238. SetLastError( I_CryptNetLdapMapErrorToWin32( pld, ldaperr ) );
  1239. }
  1240. // else per Anoop's 4/25/00 email:
  1241. // For LDAP_LOCAL_ERROR, its an underlying security error where
  1242. // LastError has already been updated with a more meaningful error
  1243. // value.
  1244. }
  1245. return( fResult );
  1246. }
  1247. #if DBG
  1248. //+---------------------------------------------------------------------------
  1249. //
  1250. // Function: LdapDisplayUrlComponents
  1251. //
  1252. // Synopsis: display the URL components
  1253. //
  1254. //----------------------------------------------------------------------------
  1255. VOID
  1256. LdapDisplayUrlComponents (
  1257. PLDAP_URL_COMPONENTS pLdapUrlComponents
  1258. )
  1259. {
  1260. ULONG cCount;
  1261. printf( "pLdapUrlComponents->pwszHost = %S\n",
  1262. pLdapUrlComponents->pwszHost );
  1263. printf( "pLdapUrlComponents->Port = %d\n", pLdapUrlComponents->Port );
  1264. printf( "pLdapUrlComponents->pwszDN = %S\n", pLdapUrlComponents->pwszDN );
  1265. printf( "pLdapUrlComponents->cAttr = %d\n", pLdapUrlComponents->cAttr );
  1266. for ( cCount = 0; cCount < pLdapUrlComponents->cAttr; cCount++ )
  1267. {
  1268. printf(
  1269. "pLdapUrlComponents->apwszAttr[%d] = %S\n",
  1270. cCount,
  1271. pLdapUrlComponents->apwszAttr[cCount]
  1272. );
  1273. }
  1274. printf( "pLdapUrlComponents->Scope = %d\n", pLdapUrlComponents->Scope );
  1275. printf( "pLdapUrlComponents->pwszFilter = %S\n",
  1276. pLdapUrlComponents->pwszFilter );
  1277. }
  1278. #endif
  1279. DWORD g_dwLdapServerExtError;
  1280. CHAR g_rgszLdapServerError[128];
  1281. ULONG
  1282. I_CryptNetLdapMapErrorToWin32(
  1283. LDAP* pld,
  1284. ULONG LdapError
  1285. )
  1286. {
  1287. if (NULL != pld) {
  1288. CHAR *pszError = NULL;
  1289. DWORD dwError = ERROR_SUCCESS;
  1290. ULONG ldaperr;
  1291. ldaperr = ldap_get_option(pld, LDAP_OPT_SERVER_ERROR, &pszError);
  1292. if (LDAP_SUCCESS == ldaperr && NULL != pszError) {
  1293. DWORD cchBuf = sizeof(g_rgszLdapServerError) /
  1294. sizeof(g_rgszLdapServerError[0]);
  1295. strncpy(g_rgszLdapServerError, pszError, cchBuf - 1);
  1296. g_rgszLdapServerError[cchBuf - 1] = '\0';
  1297. }
  1298. ldaperr = ldap_get_option(pld, LDAP_OPT_SERVER_EXT_ERROR, &dwError);
  1299. if (LDAP_SUCCESS == ldaperr)
  1300. g_dwLdapServerExtError = dwError;
  1301. I_CryptNetDebugErrorPrintfA("CRYPTNET.DLL --> LdapError: 0x%x <%s>\n",
  1302. LdapError, pszError);
  1303. if (NULL != pszError)
  1304. ldap_memfreeA(pszError);
  1305. }
  1306. return LdapMapErrorToWin32(LdapError);
  1307. }