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.

587 lines
13 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows NT Security
  4. // Copyright (C) Microsoft Corporation, 1997 - 1998
  5. //
  6. // File: ldapsp.cpp
  7. //
  8. // Contents: LDAP Scheme Provider for Remote Object Retrieval
  9. //
  10. // History: 23-Jul-97 kirtd Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <aclpch.hxx>
  14. #pragma hdrstop
  15. #include <ldapsp.h>
  16. #include <shlwapi.h>
  17. //+---------------------------------------------------------------------------
  18. //
  19. // Function: LdapCrackUrl
  20. //
  21. // Synopsis: Crack an LDAP URL into its relevant parts. The result must
  22. // be freed using LdapFreeUrlComponents
  23. //
  24. //----------------------------------------------------------------------------
  25. BOOL
  26. LdapCrackUrl (
  27. LPCWSTR pwszUrl,
  28. PLDAP_URL_COMPONENTS pLdapUrlComponents
  29. )
  30. {
  31. BOOL fResult = TRUE;
  32. ULONG cbUrl = INTERNET_MAX_PATH_LENGTH;
  33. LPWSTR pwszHostInfo = NULL;
  34. LPWSTR pwszDN = NULL;
  35. LPWSTR pwszAttrList = NULL;
  36. LPWSTR pwszScope = NULL;
  37. LPWSTR pwszFilter = NULL;
  38. LPWSTR pwszToken = NULL;
  39. WCHAR pwszBuffer[INTERNET_MAX_PATH_LENGTH+1];
  40. PWCHAR pwsz = pwszBuffer;
  41. DWORD len = 0;
  42. HRESULT hr;
  43. //
  44. // Capture the URL and initialize the out parameter
  45. //
  46. if ( wcsncmp( pwszUrl, LDAP_SCHEME_U, wcslen( LDAP_SCHEME_U ) ) == 0 )
  47. {
  48. __try
  49. {
  50. hr = UrlCanonicalizeW(
  51. pwszUrl,
  52. pwsz,
  53. &cbUrl,
  54. ICU_DECODE | URL_WININET_COMPATIBILITY);
  55. if(FAILED(hr))
  56. {
  57. return( FALSE );
  58. }
  59. }
  60. __except(EXCEPTION_EXECUTE_HANDLER)
  61. {
  62. SetLastError( GetExceptionCode() );
  63. return( FALSE );
  64. }
  65. }
  66. else
  67. {
  68. len = wcslen(pwszUrl);
  69. if (len > INTERNET_MAX_PATH_LENGTH)
  70. {
  71. pwsz = new WCHAR [len + 1];
  72. if (pwsz == NULL)
  73. {
  74. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  75. return( FALSE );
  76. }
  77. }
  78. wcscpy(pwsz, pwszUrl);
  79. }
  80. memset( pLdapUrlComponents, 0, sizeof( LDAP_URL_COMPONENTS ) );
  81. //
  82. // Find the host
  83. //
  84. pwszHostInfo = pwsz + sizeof( "ldap://" ) - sizeof( CHAR );
  85. if ( *pwszHostInfo == L'/' )
  86. {
  87. pwszToken = pwszHostInfo + 1;
  88. pwszHostInfo = NULL;
  89. }
  90. else
  91. {
  92. pwszHostInfo = wcstok( pwszHostInfo, L"/" );
  93. }
  94. //
  95. // Find the DN
  96. //
  97. if ( wcsncmp( pwszUrl, LDAP_SCHEME_U, wcslen( LDAP_SCHEME_U ) ) == 0 )
  98. {
  99. if ( pwszToken != NULL )
  100. {
  101. pwszDN = L"";
  102. if ( *pwszToken != L'\0' )
  103. {
  104. if ( *pwszToken == L'?' )
  105. {
  106. pwszToken += 1;
  107. }
  108. else
  109. {
  110. pwszDN = pwszToken;
  111. do
  112. {
  113. pwszToken += 1;
  114. }
  115. while ( ( *pwszToken != L'\0' ) && ( *pwszToken != L'?' ) );
  116. if ( *pwszToken == L'?' )
  117. {
  118. *pwszToken = L'\0';
  119. pwszToken += 1;
  120. }
  121. }
  122. }
  123. }
  124. else
  125. {
  126. pwszDN = wcstok( pwszToken, L"?" );
  127. pwszToken = NULL;
  128. if ( pwszDN == NULL )
  129. {
  130. SetLastError( E_INVALIDARG );
  131. return( FALSE );
  132. }
  133. }
  134. //
  135. // Check for attributes
  136. //
  137. if ( pwszToken != NULL )
  138. {
  139. if ( *pwszToken == L'?' )
  140. {
  141. pwszAttrList = L"";
  142. pwszToken += 1;
  143. }
  144. else if ( *pwszToken == L'\0' )
  145. {
  146. pwszAttrList = NULL;
  147. }
  148. else
  149. {
  150. pwszAttrList = wcstok( pwszToken, L"?" );
  151. pwszToken = NULL;
  152. }
  153. }
  154. else
  155. {
  156. pwszAttrList = wcstok( NULL, L"?" );
  157. }
  158. //
  159. // Check for a scope and filter
  160. //
  161. if ( pwszAttrList != NULL )
  162. {
  163. pwszScope = wcstok( pwszToken, L"?" );
  164. if ( pwszScope != NULL )
  165. {
  166. pwszFilter = wcstok( NULL, L"?" );
  167. }
  168. }
  169. if ( pwszScope == NULL )
  170. {
  171. pwszScope = L"base";
  172. }
  173. if ( pwszFilter == NULL )
  174. {
  175. pwszFilter = L"(objectClass=*)";
  176. }
  177. }
  178. else
  179. {
  180. if ( pwszToken != NULL )
  181. {
  182. pwszDN = pwszToken;
  183. }
  184. else
  185. {
  186. //
  187. // pwszDN = wcstok( pwszToken, L"\0" );
  188. //
  189. pwszDN = pwszHostInfo + wcslen( pwszHostInfo ) + 1;
  190. }
  191. pwszAttrList = NULL;
  192. pwszFilter = L"(objectClass=*)";
  193. pwszScope = L"base";
  194. }
  195. //
  196. // Now we build up our URL components
  197. //
  198. fResult = LdapParseCrackedHost( pwszHostInfo, pLdapUrlComponents );
  199. if ( fResult == TRUE )
  200. {
  201. fResult = LdapParseCrackedDN( pwszDN, pLdapUrlComponents );
  202. }
  203. if ( fResult == TRUE )
  204. {
  205. fResult = LdapParseCrackedAttributeList(
  206. pwszAttrList,
  207. pLdapUrlComponents
  208. );
  209. }
  210. if ( fResult == TRUE )
  211. {
  212. fResult = LdapParseCrackedScopeAndFilter(
  213. pwszScope,
  214. pwszFilter,
  215. pLdapUrlComponents
  216. );
  217. }
  218. if ( fResult != TRUE )
  219. {
  220. LdapFreeUrlComponents( pLdapUrlComponents );
  221. }
  222. if (pwsz != pwszBuffer)
  223. {
  224. delete pwsz;
  225. }
  226. return( fResult );
  227. }
  228. //+---------------------------------------------------------------------------
  229. //
  230. // Function: LdapParseCrackedHost
  231. //
  232. // Synopsis: Parse the cracked host string (pwszHost is modified)
  233. //
  234. //----------------------------------------------------------------------------
  235. BOOL
  236. LdapParseCrackedHost (
  237. LPWSTR pwszHost,
  238. PLDAP_URL_COMPONENTS pLdapUrlComponents
  239. )
  240. {
  241. LPWSTR pwszPort;
  242. if ( pwszHost == NULL )
  243. {
  244. pLdapUrlComponents->pwszHost = NULL;
  245. pLdapUrlComponents->Port = LDAP_PORT;
  246. return( TRUE );
  247. }
  248. pwszPort = wcschr( pwszHost, L':' );
  249. if ( pwszPort != NULL )
  250. {
  251. *pwszPort = L'\0';
  252. pwszPort++;
  253. }
  254. pLdapUrlComponents->pwszHost = new WCHAR [wcslen( pwszHost ) + 1];
  255. if ( pLdapUrlComponents->pwszHost == NULL )
  256. {
  257. SetLastError( E_OUTOFMEMORY );
  258. return( FALSE );
  259. }
  260. wcscpy( pLdapUrlComponents->pwszHost, pwszHost );
  261. pLdapUrlComponents->Port = 0;
  262. if ( pwszPort != NULL )
  263. {
  264. pLdapUrlComponents->Port = _wtol( pwszPort );
  265. }
  266. if ( pLdapUrlComponents->Port == 0 )
  267. {
  268. pLdapUrlComponents->Port = LDAP_PORT;
  269. }
  270. return( TRUE );
  271. }
  272. //+---------------------------------------------------------------------------
  273. //
  274. // Function: LdapParseCrackedDN
  275. //
  276. // Synopsis: Parse the cracked DN
  277. //
  278. //----------------------------------------------------------------------------
  279. BOOL
  280. LdapParseCrackedDN (
  281. LPWSTR pwszDN,
  282. PLDAP_URL_COMPONENTS pLdapUrlComponents
  283. )
  284. {
  285. pLdapUrlComponents->pwszDN = new WCHAR [wcslen( pwszDN ) + 1];
  286. if ( pLdapUrlComponents->pwszDN == NULL )
  287. {
  288. SetLastError( E_OUTOFMEMORY );
  289. return( FALSE );
  290. }
  291. wcscpy( pLdapUrlComponents->pwszDN, pwszDN );
  292. return( TRUE );
  293. }
  294. //+---------------------------------------------------------------------------
  295. //
  296. // Function: LdapParseCrackedAttributeList
  297. //
  298. // Synopsis: Parse the cracked attribute list
  299. //
  300. //----------------------------------------------------------------------------
  301. BOOL
  302. LdapParseCrackedAttributeList (
  303. LPWSTR pwszAttrList,
  304. PLDAP_URL_COMPONENTS pLdapUrlComponents
  305. )
  306. {
  307. LPWSTR pwsz;
  308. LPWSTR pwszAttr;
  309. ULONG cAttr = 0;
  310. ULONG cCount;
  311. if ( ( pwszAttrList == NULL ) || ( wcslen( pwszAttrList ) == 0 ) )
  312. {
  313. pLdapUrlComponents->cAttr = 0;
  314. pLdapUrlComponents->apwszAttr = NULL;
  315. return( TRUE );
  316. }
  317. pwsz = new WCHAR [wcslen( pwszAttrList ) + 1];
  318. if ( pwsz == NULL )
  319. {
  320. SetLastError( E_OUTOFMEMORY );
  321. return( FALSE );
  322. }
  323. wcscpy( pwsz, pwszAttrList );
  324. pwszAttr = wcstok( pwsz, L"," );
  325. while ( pwszAttr != NULL )
  326. {
  327. cAttr += 1;
  328. pwszAttr = wcstok( NULL, L"," );
  329. }
  330. pLdapUrlComponents->apwszAttr = new LPWSTR [cAttr+1];
  331. if ( pLdapUrlComponents->apwszAttr == NULL )
  332. {
  333. delete pwsz;
  334. SetLastError( E_OUTOFMEMORY );
  335. return( FALSE );
  336. }
  337. pLdapUrlComponents->cAttr = cAttr;
  338. for ( cCount = 0; cCount < cAttr; cCount++ )
  339. {
  340. pLdapUrlComponents->apwszAttr[cCount] = pwsz;
  341. pwsz += ( wcslen(pwsz) + 1 );
  342. }
  343. pLdapUrlComponents->apwszAttr[cAttr] = NULL;
  344. return( TRUE );
  345. }
  346. //+---------------------------------------------------------------------------
  347. //
  348. // Function: LdapParseCrackedScopeAndFilter
  349. //
  350. // Synopsis: Parse the cracked scope and filter
  351. //
  352. //----------------------------------------------------------------------------
  353. BOOL
  354. LdapParseCrackedScopeAndFilter (
  355. LPWSTR pwszScope,
  356. LPWSTR pwszFilter,
  357. PLDAP_URL_COMPONENTS pLdapUrlComponents
  358. )
  359. {
  360. ULONG Scope;
  361. if ( _wcsicmp( pwszScope, L"base" ) == 0 )
  362. {
  363. Scope = LDAP_SCOPE_BASE;
  364. }
  365. else if ( _wcsicmp( pwszScope, L"one" ) == 0 )
  366. {
  367. Scope = LDAP_SCOPE_ONELEVEL;
  368. }
  369. else if ( _wcsicmp( pwszScope, L"sub" ) == 0 )
  370. {
  371. Scope = LDAP_SCOPE_SUBTREE;
  372. }
  373. else
  374. {
  375. SetLastError( E_INVALIDARG );
  376. return( FALSE );
  377. }
  378. pLdapUrlComponents->pwszFilter = new WCHAR [wcslen( pwszFilter ) + 1];
  379. if ( pLdapUrlComponents->pwszFilter == NULL )
  380. {
  381. SetLastError( E_OUTOFMEMORY );
  382. return( FALSE );
  383. }
  384. wcscpy( pLdapUrlComponents->pwszFilter, pwszFilter );
  385. pLdapUrlComponents->Scope = Scope;
  386. return( TRUE );
  387. }
  388. //+---------------------------------------------------------------------------
  389. //
  390. // Function: LdapFreeUrlComponents
  391. //
  392. // Synopsis: Frees allocate URL components returned from LdapCrackUrl
  393. //
  394. //----------------------------------------------------------------------------
  395. VOID
  396. LdapFreeUrlComponents (
  397. PLDAP_URL_COMPONENTS pLdapUrlComponents
  398. )
  399. {
  400. delete pLdapUrlComponents->pwszHost;
  401. delete pLdapUrlComponents->pwszDN;
  402. if ( pLdapUrlComponents->apwszAttr != NULL )
  403. {
  404. delete pLdapUrlComponents->apwszAttr[0];
  405. }
  406. delete pLdapUrlComponents->apwszAttr;
  407. delete pLdapUrlComponents->pwszFilter;
  408. }
  409. //+---------------------------------------------------------------------------
  410. //
  411. // Function: LdapGetBindings
  412. //
  413. // Synopsis: allocates and initializes the LDAP session binding
  414. //
  415. //----------------------------------------------------------------------------
  416. BOOL
  417. LdapGetBindings (
  418. LPWSTR pwszHost,
  419. ULONG Port,
  420. DWORD dwRetrievalFlags,
  421. DWORD dwTimeout,
  422. LDAP** ppld
  423. )
  424. {
  425. BOOL fResult = TRUE;
  426. LDAP* pld;
  427. pld = ldap_initW( pwszHost, Port );
  428. if ( pld != NULL )
  429. {
  430. ULONG ldaperr;
  431. if ( dwTimeout != 0 )
  432. {
  433. ldap_set_option( pld, LDAP_OPT_TIMELIMIT, (void *)&dwTimeout );
  434. }
  435. fResult = LdapBindWithOptionalRediscover( pld, pwszHost );
  436. }
  437. else
  438. {
  439. fResult = FALSE;
  440. }
  441. if ( fResult == TRUE )
  442. {
  443. *ppld = pld;
  444. }
  445. return( fResult );
  446. }
  447. //+---------------------------------------------------------------------------
  448. //
  449. // Function: LdapFreeBindings
  450. //
  451. // Synopsis: frees allocated LDAP session binding
  452. //
  453. //----------------------------------------------------------------------------
  454. VOID
  455. LdapFreeBindings (
  456. LDAP* pld
  457. )
  458. {
  459. if ( pld != NULL )
  460. {
  461. ldap_unbind_s( pld );
  462. }
  463. }
  464. //+---------------------------------------------------------------------------
  465. //
  466. // Function: LdapBindWithOptionalRediscover
  467. //
  468. // Synopsis: bind to the host with optional DC rediscovery if the host is
  469. // NULL (which means use default via DsGetDcName)
  470. //
  471. //----------------------------------------------------------------------------
  472. BOOL
  473. LdapBindWithOptionalRediscover (LDAP* pld, LPWSTR pwszHost)
  474. {
  475. BOOL fResult = TRUE;
  476. ULONG ldaperr;
  477. ULONG ldapsaveerr;
  478. DWORD dwFlags = DS_FORCE_REDISCOVERY;
  479. ldaperr = ldap_bind_sW(
  480. pld,
  481. NULL,
  482. NULL,
  483. LDAP_AUTH_SSPI
  484. );
  485. if ( ( ldaperr != LDAP_SUCCESS ) && ( pwszHost == NULL ) )
  486. {
  487. ldapsaveerr = ldaperr;
  488. ldaperr = ldap_set_option(
  489. pld,
  490. LDAP_OPT_GETDSNAME_FLAGS,
  491. (LPVOID)&dwFlags
  492. );
  493. if ( ldaperr == LDAP_SUCCESS )
  494. {
  495. ldaperr = ldap_bind_sW(
  496. pld,
  497. NULL,
  498. NULL,
  499. LDAP_AUTH_SSPI
  500. );
  501. }
  502. else
  503. {
  504. ldaperr = ldapsaveerr;
  505. }
  506. }
  507. if ( ldaperr != LDAP_SUCCESS )
  508. {
  509. fResult = FALSE;
  510. SetLastError( LdapMapErrorToWin32(ldaperr) );
  511. }
  512. return( fResult );
  513. }