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.

626 lines
15 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. // Make sure that we do not have a trailing '/'.
  61. //
  62. len = wcslen(pwsz);
  63. if (pwsz[len-1] == L'/')
  64. {
  65. pwsz[--len] = L'\0';
  66. }
  67. }
  68. __except(EXCEPTION_EXECUTE_HANDLER)
  69. {
  70. SetLastError( GetExceptionCode() );
  71. return( FALSE );
  72. }
  73. }
  74. else
  75. {
  76. len = wcslen(pwszUrl);
  77. if (len > INTERNET_MAX_PATH_LENGTH)
  78. {
  79. pwsz = new WCHAR [len + 1];
  80. if (pwsz == NULL)
  81. {
  82. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  83. return( FALSE );
  84. }
  85. }
  86. wcscpy(pwsz, pwszUrl);
  87. }
  88. memset( pLdapUrlComponents, 0, sizeof( LDAP_URL_COMPONENTS ) );
  89. //
  90. // Find the host
  91. //
  92. pwszHostInfo = pwsz + sizeof( "ldap://" ) - sizeof( CHAR );
  93. if ( *pwszHostInfo == L'/' )
  94. {
  95. //
  96. // This is ldap:///ObjectName format.
  97. //
  98. pwszToken = pwszHostInfo + 1;
  99. pwszHostInfo = NULL;
  100. }
  101. else
  102. {
  103. if (wcschr(pwszHostInfo, L'/'))
  104. {
  105. //
  106. // This is ldap://ServerName/ObjectName format.
  107. //
  108. pwszHostInfo = wcstok( pwszHostInfo, L"/" );
  109. }
  110. else
  111. {
  112. //
  113. // This is ldap://ObjectName format.
  114. //
  115. pwszToken = pwszHostInfo;
  116. pwszHostInfo = NULL;
  117. }
  118. }
  119. //
  120. // Find the DN
  121. //
  122. if ( wcsncmp( pwszUrl, LDAP_SCHEME_U, wcslen( LDAP_SCHEME_U ) ) == 0 )
  123. {
  124. if ( pwszToken != NULL )
  125. {
  126. pwszDN = L"";
  127. if ( *pwszToken != L'\0' )
  128. {
  129. if ( *pwszToken == L'?' )
  130. {
  131. pwszToken += 1;
  132. }
  133. else
  134. {
  135. pwszDN = pwszToken;
  136. do
  137. {
  138. pwszToken += 1;
  139. }
  140. while ( ( *pwszToken != L'\0' ) && ( *pwszToken != L'?' ) );
  141. if ( *pwszToken == L'?' )
  142. {
  143. *pwszToken = L'\0';
  144. pwszToken += 1;
  145. }
  146. }
  147. }
  148. }
  149. else
  150. {
  151. pwszDN = wcstok( pwszToken, L"?" );
  152. pwszToken = NULL;
  153. if ( pwszDN == NULL )
  154. {
  155. SetLastError( E_INVALIDARG );
  156. return( FALSE );
  157. }
  158. }
  159. //
  160. // Check for attributes
  161. //
  162. if ( pwszToken != NULL )
  163. {
  164. if ( *pwszToken == L'?' )
  165. {
  166. pwszAttrList = L"";
  167. pwszToken += 1;
  168. }
  169. else if ( *pwszToken == L'\0' )
  170. {
  171. pwszAttrList = NULL;
  172. }
  173. else
  174. {
  175. pwszAttrList = wcstok( pwszToken, L"?" );
  176. pwszToken = NULL;
  177. }
  178. }
  179. else
  180. {
  181. pwszAttrList = wcstok( NULL, L"?" );
  182. }
  183. //
  184. // Check for a scope and filter
  185. //
  186. if ( pwszAttrList != NULL )
  187. {
  188. pwszScope = wcstok( pwszToken, L"?" );
  189. if ( pwszScope != NULL )
  190. {
  191. pwszFilter = wcstok( NULL, L"?" );
  192. }
  193. }
  194. if ( pwszScope == NULL )
  195. {
  196. pwszScope = L"base";
  197. }
  198. if ( pwszFilter == NULL )
  199. {
  200. pwszFilter = L"(objectClass=*)";
  201. }
  202. }
  203. else
  204. {
  205. if ( pwszToken != NULL )
  206. {
  207. pwszDN = pwszToken;
  208. }
  209. else
  210. {
  211. //
  212. // pwszDN = wcstok( pwszToken, L"\0" );
  213. //
  214. pwszDN = pwszHostInfo + wcslen( pwszHostInfo ) + 1;
  215. }
  216. pwszAttrList = NULL;
  217. pwszFilter = L"(objectClass=*)";
  218. pwszScope = L"base";
  219. }
  220. //
  221. // Now we build up our URL components
  222. //
  223. fResult = LdapParseCrackedHost( pwszHostInfo, pLdapUrlComponents );
  224. if ( fResult == TRUE )
  225. {
  226. fResult = LdapParseCrackedDN( pwszDN, pLdapUrlComponents );
  227. }
  228. if ( fResult == TRUE )
  229. {
  230. fResult = LdapParseCrackedAttributeList(
  231. pwszAttrList,
  232. pLdapUrlComponents
  233. );
  234. }
  235. if ( fResult == TRUE )
  236. {
  237. fResult = LdapParseCrackedScopeAndFilter(
  238. pwszScope,
  239. pwszFilter,
  240. pLdapUrlComponents
  241. );
  242. }
  243. if ( fResult != TRUE )
  244. {
  245. LdapFreeUrlComponents( pLdapUrlComponents );
  246. }
  247. if (pwsz != pwszBuffer)
  248. {
  249. delete pwsz;
  250. }
  251. return( fResult );
  252. }
  253. //+---------------------------------------------------------------------------
  254. //
  255. // Function: LdapParseCrackedHost
  256. //
  257. // Synopsis: Parse the cracked host string (pwszHost is modified)
  258. //
  259. //----------------------------------------------------------------------------
  260. BOOL
  261. LdapParseCrackedHost (
  262. LPWSTR pwszHost,
  263. PLDAP_URL_COMPONENTS pLdapUrlComponents
  264. )
  265. {
  266. LPWSTR pwszPort;
  267. if ( pwszHost == NULL )
  268. {
  269. pLdapUrlComponents->pwszHost = NULL;
  270. pLdapUrlComponents->Port = LDAP_PORT;
  271. return( TRUE );
  272. }
  273. pwszPort = wcschr( pwszHost, L':' );
  274. if ( pwszPort != NULL )
  275. {
  276. *pwszPort = L'\0';
  277. pwszPort++;
  278. }
  279. pLdapUrlComponents->pwszHost = new WCHAR [wcslen( pwszHost ) + 1];
  280. if ( pLdapUrlComponents->pwszHost == NULL )
  281. {
  282. SetLastError( E_OUTOFMEMORY );
  283. return( FALSE );
  284. }
  285. wcscpy( pLdapUrlComponents->pwszHost, pwszHost );
  286. pLdapUrlComponents->Port = 0;
  287. if ( pwszPort != NULL )
  288. {
  289. pLdapUrlComponents->Port = _wtol( pwszPort );
  290. }
  291. if ( pLdapUrlComponents->Port == 0 )
  292. {
  293. pLdapUrlComponents->Port = LDAP_PORT;
  294. }
  295. return( TRUE );
  296. }
  297. //+---------------------------------------------------------------------------
  298. //
  299. // Function: LdapParseCrackedDN
  300. //
  301. // Synopsis: Parse the cracked DN
  302. //
  303. //----------------------------------------------------------------------------
  304. BOOL
  305. LdapParseCrackedDN (
  306. LPWSTR pwszDN,
  307. PLDAP_URL_COMPONENTS pLdapUrlComponents
  308. )
  309. {
  310. pLdapUrlComponents->pwszDN = new WCHAR [wcslen( pwszDN ) + 1];
  311. if ( pLdapUrlComponents->pwszDN == NULL )
  312. {
  313. SetLastError( E_OUTOFMEMORY );
  314. return( FALSE );
  315. }
  316. wcscpy( pLdapUrlComponents->pwszDN, pwszDN );
  317. return( TRUE );
  318. }
  319. //+---------------------------------------------------------------------------
  320. //
  321. // Function: LdapParseCrackedAttributeList
  322. //
  323. // Synopsis: Parse the cracked attribute list
  324. //
  325. //----------------------------------------------------------------------------
  326. BOOL
  327. LdapParseCrackedAttributeList (
  328. LPWSTR pwszAttrList,
  329. PLDAP_URL_COMPONENTS pLdapUrlComponents
  330. )
  331. {
  332. LPWSTR pwsz;
  333. LPWSTR pwszAttr;
  334. ULONG cAttr = 0;
  335. ULONG cCount;
  336. if ( ( pwszAttrList == NULL ) || ( wcslen( pwszAttrList ) == 0 ) )
  337. {
  338. pLdapUrlComponents->cAttr = 0;
  339. pLdapUrlComponents->apwszAttr = NULL;
  340. return( TRUE );
  341. }
  342. pwsz = new WCHAR [wcslen( pwszAttrList ) + 1];
  343. if ( pwsz == NULL )
  344. {
  345. SetLastError( E_OUTOFMEMORY );
  346. return( FALSE );
  347. }
  348. wcscpy( pwsz, pwszAttrList );
  349. pwszAttr = wcstok( pwsz, L"," );
  350. while ( pwszAttr != NULL )
  351. {
  352. cAttr += 1;
  353. pwszAttr = wcstok( NULL, L"," );
  354. }
  355. pLdapUrlComponents->apwszAttr = new LPWSTR [cAttr+1];
  356. if ( pLdapUrlComponents->apwszAttr == NULL )
  357. {
  358. delete pwsz;
  359. SetLastError( E_OUTOFMEMORY );
  360. return( FALSE );
  361. }
  362. pLdapUrlComponents->cAttr = cAttr;
  363. for ( cCount = 0; cCount < cAttr; cCount++ )
  364. {
  365. pLdapUrlComponents->apwszAttr[cCount] = pwsz;
  366. pwsz += ( wcslen(pwsz) + 1 );
  367. }
  368. pLdapUrlComponents->apwszAttr[cAttr] = NULL;
  369. return( TRUE );
  370. }
  371. //+---------------------------------------------------------------------------
  372. //
  373. // Function: LdapParseCrackedScopeAndFilter
  374. //
  375. // Synopsis: Parse the cracked scope and filter
  376. //
  377. //----------------------------------------------------------------------------
  378. BOOL
  379. LdapParseCrackedScopeAndFilter (
  380. LPWSTR pwszScope,
  381. LPWSTR pwszFilter,
  382. PLDAP_URL_COMPONENTS pLdapUrlComponents
  383. )
  384. {
  385. ULONG Scope;
  386. if ( _wcsicmp( pwszScope, L"base" ) == 0 )
  387. {
  388. Scope = LDAP_SCOPE_BASE;
  389. }
  390. else if ( _wcsicmp( pwszScope, L"one" ) == 0 )
  391. {
  392. Scope = LDAP_SCOPE_ONELEVEL;
  393. }
  394. else if ( _wcsicmp( pwszScope, L"sub" ) == 0 )
  395. {
  396. Scope = LDAP_SCOPE_SUBTREE;
  397. }
  398. else
  399. {
  400. SetLastError( E_INVALIDARG );
  401. return( FALSE );
  402. }
  403. pLdapUrlComponents->pwszFilter = new WCHAR [wcslen( pwszFilter ) + 1];
  404. if ( pLdapUrlComponents->pwszFilter == NULL )
  405. {
  406. SetLastError( E_OUTOFMEMORY );
  407. return( FALSE );
  408. }
  409. wcscpy( pLdapUrlComponents->pwszFilter, pwszFilter );
  410. pLdapUrlComponents->Scope = Scope;
  411. return( TRUE );
  412. }
  413. //+---------------------------------------------------------------------------
  414. //
  415. // Function: LdapFreeUrlComponents
  416. //
  417. // Synopsis: Frees allocate URL components returned from LdapCrackUrl
  418. //
  419. //----------------------------------------------------------------------------
  420. VOID
  421. LdapFreeUrlComponents (
  422. PLDAP_URL_COMPONENTS pLdapUrlComponents
  423. )
  424. {
  425. delete pLdapUrlComponents->pwszHost;
  426. pLdapUrlComponents->pwszHost = NULL;
  427. delete pLdapUrlComponents->pwszDN;
  428. pLdapUrlComponents->pwszDN = NULL;
  429. if ( pLdapUrlComponents->apwszAttr != NULL )
  430. {
  431. delete pLdapUrlComponents->apwszAttr[0];
  432. pLdapUrlComponents->apwszAttr = NULL;
  433. }
  434. delete pLdapUrlComponents->apwszAttr;
  435. pLdapUrlComponents->apwszAttr = NULL;
  436. delete pLdapUrlComponents->pwszFilter;
  437. pLdapUrlComponents->pwszFilter = NULL;
  438. }
  439. //+---------------------------------------------------------------------------
  440. //
  441. // Function: LdapGetBindings
  442. //
  443. // Synopsis: allocates and initializes the LDAP session binding
  444. //
  445. //----------------------------------------------------------------------------
  446. BOOL
  447. LdapGetBindings (
  448. LPWSTR pwszHost,
  449. ULONG Port,
  450. DWORD dwRetrievalFlags,
  451. DWORD dwTimeout,
  452. LDAP** ppld
  453. )
  454. {
  455. BOOL fResult = TRUE;
  456. LDAP* pld;
  457. pld = ldap_initW( pwszHost, Port );
  458. if ( pld != NULL )
  459. {
  460. ULONG ldaperr;
  461. if ( dwTimeout != 0 )
  462. {
  463. ldap_set_option( pld, LDAP_OPT_TIMELIMIT, (void *)&dwTimeout );
  464. }
  465. fResult = LdapBindWithOptionalRediscover( pld, pwszHost );
  466. }
  467. else
  468. {
  469. fResult = FALSE;
  470. }
  471. if ( fResult == TRUE )
  472. {
  473. *ppld = pld;
  474. }
  475. return( fResult );
  476. }
  477. //+---------------------------------------------------------------------------
  478. //
  479. // Function: LdapFreeBindings
  480. //
  481. // Synopsis: frees allocated LDAP session binding
  482. //
  483. //----------------------------------------------------------------------------
  484. VOID
  485. LdapFreeBindings (
  486. LDAP* pld
  487. )
  488. {
  489. if ( pld != NULL )
  490. {
  491. ldap_unbind_s( pld );
  492. }
  493. }
  494. //+---------------------------------------------------------------------------
  495. //
  496. // Function: LdapBindWithOptionalRediscover
  497. //
  498. // Synopsis: bind to the host with optional DC rediscovery if the host is
  499. // NULL (which means use default via DsGetDcName)
  500. //
  501. //----------------------------------------------------------------------------
  502. BOOL
  503. LdapBindWithOptionalRediscover (LDAP* pld, LPWSTR pwszHost)
  504. {
  505. BOOL fResult = TRUE;
  506. ULONG ldaperr;
  507. ULONG ldapsaveerr;
  508. DWORD dwFlags = DS_FORCE_REDISCOVERY;
  509. ldaperr = ldap_connect( pld, NULL );
  510. if ( ( ldaperr != LDAP_SUCCESS ) && ( pwszHost == NULL ) )
  511. {
  512. ldapsaveerr = ldaperr;
  513. ldaperr = ldap_set_option(
  514. pld,
  515. LDAP_OPT_GETDSNAME_FLAGS,
  516. (LPVOID)&dwFlags
  517. );
  518. if ( ldaperr == LDAP_SUCCESS )
  519. {
  520. ldaperr = ldap_connect( pld, NULL );
  521. }
  522. else
  523. {
  524. ldaperr = ldapsaveerr;
  525. }
  526. }
  527. if ( ldaperr == LDAP_SUCCESS )
  528. {
  529. ldaperr = ldap_bind_sW(
  530. pld,
  531. NULL,
  532. NULL,
  533. LDAP_AUTH_SSPI
  534. );
  535. }
  536. if ( ldaperr != LDAP_SUCCESS )
  537. {
  538. fResult = FALSE;
  539. SetLastError( LdapMapErrorToWin32(ldaperr) );
  540. }
  541. return( fResult );
  542. }