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.

814 lines
16 KiB

  1. //--------------------------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation, 1996
  4. //
  5. // Description:
  6. //
  7. // Microsoft Internet LDAP Client RFC 1823 API
  8. //
  9. //
  10. // History
  11. // davidsan 06/17/96 Created
  12. //
  13. //--------------------------------------------------------------------------------------------
  14. // note: this is ugly code. all i'm doing is mapping things to my API in as painless a way
  15. // as i can.
  16. //--------------------------------------------------------------------------------------------
  17. //
  18. // INCLUDES
  19. //
  20. //--------------------------------------------------------------------------------------------
  21. #include "ldappch.h"
  22. //--------------------------------------------------------------------------------------------
  23. //
  24. // PROTOTYPES
  25. //
  26. //--------------------------------------------------------------------------------------------
  27. //--------------------------------------------------------------------------------------------
  28. //
  29. // GLOBALS
  30. //
  31. //--------------------------------------------------------------------------------------------
  32. //--------------------------------------------------------------------------------------------
  33. //
  34. // FUNCTIONS
  35. //
  36. //--------------------------------------------------------------------------------------------
  37. int
  38. LdapResFromHr(HRESULT hr)
  39. {
  40. switch (hr)
  41. {
  42. default:
  43. return LDAP_LOCAL_ERROR;
  44. case NOERROR:
  45. return LDAP_SUCCESS;
  46. case LDAP_E_OPERATIONS:
  47. return LDAP_OPERATIONS_ERROR;
  48. case LDAP_E_PROTOCOL:
  49. return LDAP_PROTOCOL_ERROR;
  50. case LDAP_S_TIMEEXCEEDED:
  51. return LDAP_TIMELIMIT_EXCEEDED;
  52. case LDAP_S_SIZEEXCEEDED:
  53. return LDAP_SIZELIMIT_EXCEEDED;
  54. case S_FALSE:
  55. return LDAP_COMPARE_FALSE;
  56. case LDAP_E_AUTHMETHOD:
  57. return LDAP_AUTH_METHOD_NOT_SUPPORTED;
  58. case LDAP_E_STRONGAUTHREQUIRED:
  59. return LDAP_STRONG_AUTH_REQUIRED;
  60. case LDAP_E_NOSUCHATTRIBUTE:
  61. return LDAP_NO_SUCH_ATTRIBUTE;
  62. case LDAP_E_UNDEFINEDTYPE:
  63. return LDAP_UNDEFINED_TYPE;
  64. case LDAP_E_MATCHING:
  65. return LDAP_INAPPROPRIATE_MATCHING;
  66. case LDAP_E_CONSTRAINT:
  67. return LDAP_CONSTRAINT_VIOLATION;
  68. case LDAP_E_ATTRIBORVALEXISTS:
  69. return LDAP_ATTRIBUTE_OR_VALUE_EXISTS;
  70. case LDAP_E_SYNTAX:
  71. return LDAP_INVALID_SYNTAX;
  72. case LDAP_E_NOSUCHOBJECT:
  73. return LDAP_NO_SUCH_OBJECT;
  74. case LDAP_E_ALIAS:
  75. return LDAP_ALIAS_PROBLEM;
  76. case LDAP_E_DNSYNTAX:
  77. return LDAP_INVALID_DN_SYNTAX;
  78. case LDAP_E_ISLEAF:
  79. return LDAP_IS_LEAF;
  80. case LDAP_E_ALIASDEREF:
  81. return LDAP_ALIAS_DEREF_PROBLEM;
  82. case LDAP_E_AUTH:
  83. return LDAP_INAPPROPRIATE_AUTH;
  84. case LDAP_E_CREDENTIALS:
  85. return LDAP_INVALID_CREDENTIALS;
  86. case LDAP_E_RIGHTS:
  87. return LDAP_INSUFFICIENT_RIGHTS;
  88. case LDAP_E_BUSY:
  89. return LDAP_BUSY;
  90. case LDAP_E_UNAVAILABLE:
  91. return LDAP_UNAVAILABLE;
  92. case LDAP_E_UNWILLING:
  93. return LDAP_UNWILLING_TO_PERFORM;
  94. case LDAP_E_LOOP:
  95. return LDAP_LOOP_DETECT;
  96. case LDAP_E_NAMING:
  97. return LDAP_NAMING_VIOLATION;
  98. case LDAP_E_OBJECTCLASS:
  99. return LDAP_OBJECT_CLASS_VIOLATION;
  100. case LDAP_E_NOTALLOWEDONNONLEAF:
  101. return LDAP_NOT_ALLOWED_ON_NONLEAF;
  102. case LDAP_E_NOTALLOWEDONRDN:
  103. return LDAP_NOT_ALLOWED_ON_RDN;
  104. case LDAP_E_ALREADYEXISTS:
  105. return LDAP_ALREADY_EXISTS;
  106. case LDAP_E_NOOBJECTCLASSMODS:
  107. return LDAP_NO_OBJECT_CLASS_MODS;
  108. case LDAP_E_RESULTSTOOLARGE:
  109. return LDAP_RESULTS_TOO_LARGE;
  110. case LDAP_E_OTHER:
  111. return LDAP_OTHER;
  112. case LDAP_E_SERVERDOWN:
  113. return LDAP_SERVER_DOWN;
  114. case LDAP_E_LOCAL:
  115. return LDAP_LOCAL_ERROR;
  116. case LDAP_E_ENCODING:
  117. return LDAP_ENCODING_ERROR;
  118. case LDAP_E_DECODING:
  119. return LDAP_DECODING_ERROR;
  120. case LDAP_E_TIMEOUT:
  121. return LDAP_TIMEOUT;
  122. case LDAP_E_AUTHUNKNOWN:
  123. return LDAP_AUTH_UNKNOWN;
  124. case LDAP_E_FILTER:
  125. return LDAP_FILTER_ERROR;
  126. case LDAP_E_USERCANCELLED:
  127. return LDAP_USER_CANCELLED;
  128. case E_INVALIDARG:
  129. return LDAP_PARAM_ERROR;
  130. case E_OUTOFMEMORY:
  131. return LDAP_NO_MEMORY;
  132. }
  133. }
  134. DWORD
  135. TimeoutFromTimeval(struct timeval *ptv)
  136. {
  137. if (!ptv->tv_usec && !ptv->tv_sec)
  138. return INFINITE;
  139. return (ptv->tv_usec / 1000) + (ptv->tv_sec * 1000);
  140. }
  141. char *
  142. SzMatchingParen(char *sz)
  143. {
  144. int cLev = 0;
  145. if (sz[0] != '(')
  146. return NULL;
  147. while (*sz)
  148. {
  149. if (*sz == '(')
  150. cLev++;
  151. else if (*sz == ')')
  152. {
  153. cLev--;
  154. if (!cLev)
  155. return sz;
  156. }
  157. sz++;
  158. }
  159. return NULL;
  160. }
  161. char *
  162. SzFT(char *sz, DWORD *ptype)
  163. {
  164. while (*sz)
  165. {
  166. if (*sz == '=')
  167. {
  168. if (*(sz-1) == '~')
  169. {
  170. *ptype = LDAP_FILTER_APPROX;
  171. *(sz-1) = 0;
  172. return sz;
  173. }
  174. else if (*(sz - 1) == '<')
  175. {
  176. *ptype = LDAP_FILTER_LE;
  177. *(sz-1) = 0;
  178. return sz;
  179. }
  180. else if (*(sz - 1) == '<')
  181. {
  182. *ptype = LDAP_FILTER_GE;
  183. *(sz-1) = 0;
  184. return sz;
  185. }
  186. if (*(sz + 1) == '*')
  187. {
  188. *ptype = LDAP_FILTER_PRESENT;
  189. *sz = 0;
  190. return sz+1;
  191. }
  192. *ptype = 0;
  193. return sz;
  194. }
  195. sz++;
  196. }
  197. return NULL;
  198. }
  199. char *
  200. SzStar(char *sz)
  201. {
  202. while (*sz)
  203. {
  204. if (*sz == '*')
  205. return sz;
  206. sz++;
  207. }
  208. return NULL;
  209. }
  210. void
  211. Unquote(char *sz)
  212. {
  213. char *pchSrc = sz, *pchDest = sz;
  214. BOOL fQuoted = FALSE;
  215. while (*pchSrc)
  216. {
  217. if (fQuoted)
  218. {
  219. goto LCopy;
  220. }
  221. else
  222. {
  223. if (*pchSrc == '\\')
  224. fQuoted = TRUE;
  225. else
  226. {
  227. LCopy:
  228. *pchDest++ = *pchSrc;
  229. fQuoted = FALSE;
  230. }
  231. }
  232. pchSrc++;
  233. }
  234. }
  235. void
  236. FreePfilter(PFILTER pfilter)
  237. {
  238. PFILTER pfilterNext;
  239. while (pfilter)
  240. {
  241. if (pfilter->type == LDAP_FILTER_AND ||
  242. pfilter->type == LDAP_FILTER_OR ||
  243. pfilter->type == LDAP_FILTER_NOT)
  244. FreePfilter(pfilter->pfilterSub);
  245. pfilterNext = pfilter->pfilterNext;
  246. delete pfilter;
  247. pfilter = pfilterNext;
  248. }
  249. }
  250. PFILTER
  251. PfilterFromString(char *sz)
  252. {
  253. PFILTER pfilter = NULL;
  254. char *szMatchingParen;
  255. char *szSubMatchingParen;
  256. PFILTER pfilterSub = NULL;
  257. PFILTER pfilterPrev = NULL;
  258. char *szFT;
  259. char *szStar;
  260. char *szOldStar;
  261. if (sz[0] != '(')
  262. return NULL;
  263. szMatchingParen = SzMatchingParen(sz);
  264. if (!szMatchingParen)
  265. return NULL;
  266. pfilter = new FILTER;
  267. if (!pfilter)
  268. return NULL;
  269. FillMemory(pfilter, sizeof(FILTER), 0);
  270. switch (sz[1])
  271. {
  272. case '&':
  273. case '|':
  274. if (sz[1] == '&')
  275. pfilter->type = LDAP_FILTER_AND;
  276. else
  277. pfilter->type = LDAP_FILTER_OR;
  278. sz++;
  279. sz++;
  280. // sz now points to what should be first paren of first subfilter
  281. while (sz < szMatchingParen)
  282. {
  283. szSubMatchingParen = SzMatchingParen(sz);
  284. if (!szSubMatchingParen || szSubMatchingParen >= szMatchingParen)
  285. goto LFail;
  286. pfilterSub = PfilterFromString(sz);
  287. if (!pfilter->pfilterSub)
  288. pfilter->pfilterSub = pfilterSub;
  289. if (pfilterPrev)
  290. pfilterPrev->pfilterNext = pfilterSub;
  291. pfilterPrev = pfilterSub;
  292. sz = szSubMatchingParen + 1;
  293. }
  294. break;
  295. case '!':
  296. pfilter->type = LDAP_FILTER_NOT;
  297. sz++;
  298. sz++;
  299. szSubMatchingParen = SzMatchingParen(sz);
  300. if (!szSubMatchingParen || szSubMatchingParen >= szMatchingParen)
  301. goto LFail;
  302. pfilterSub = PfilterFromString(sz);
  303. pfilter->pfilterSub = pfilterSub;
  304. break;
  305. default:
  306. // it's not an and/or/not, so it must be an attribute-related filter.
  307. sz++;
  308. szFT = SzFT(sz, &pfilter->type);
  309. if (!szFT)
  310. goto LFail;
  311. *szFT++ = 0;
  312. *szMatchingParen = 0;
  313. Unquote(sz);
  314. // so now sz points to the attribute and szFT points to the value.
  315. if (pfilter->type == LDAP_FILTER_PRESENT)
  316. {
  317. pfilter->szAttrib = sz;
  318. }
  319. else
  320. {
  321. pfilter->ava.szAttrib = sz;
  322. pfilter->ava.szValue = szFT;
  323. }
  324. if (!pfilter->type)
  325. {
  326. // if a type wasn't filled in, it means it's either eq or substring;
  327. // we need to grind through the string and look for *s. note that we
  328. // use a less general format of substring commands than the LDAP
  329. // api and spec.
  330. szStar = SzStar(szFT);
  331. if (!szStar)
  332. {
  333. pfilter->type = LDAP_FILTER_EQUALITY;
  334. }
  335. else
  336. {
  337. pfilter->type = LDAP_FILTER_SUBSTRINGS;
  338. pfilter->sub.szAttrib = sz;
  339. pfilter->sub.szInitial = szFT;
  340. Unquote(szFT);
  341. *szStar++ = 0;
  342. szOldStar = szStar;
  343. szStar = SzStar(szOldStar);
  344. if (szStar)
  345. {
  346. *szStar++ = 0;
  347. pfilter->sub.szAny = szOldStar;
  348. Unquote(szOldStar);
  349. szOldStar = szStar;
  350. szStar = SzStar(szOldStar);
  351. if (szStar)
  352. {
  353. *szStar++ = 0;
  354. pfilter->sub.szFinal = szOldStar;
  355. Unquote(szOldStar);
  356. }
  357. }
  358. }
  359. }
  360. break;
  361. }
  362. return pfilter;
  363. LFail:
  364. if (pfilter)
  365. {
  366. FreePfilter(pfilter);
  367. }
  368. return NULL;
  369. }
  370. int
  371. CAttrib(char **rgsz)
  372. {
  373. int c = 0;
  374. while (*rgsz)
  375. {
  376. c++;
  377. rgsz++;
  378. }
  379. return c;
  380. }
  381. int
  382. Cval(PATTR pattr)
  383. {
  384. PVAL pval = pattr->pvalFirst;
  385. int c = 0;
  386. while (pval)
  387. {
  388. c++;
  389. pval = pval->pvalNext;
  390. }
  391. return c;
  392. }
  393. extern "C" DLLEXPORT LDAP * __cdecl
  394. ldap_open(char *hostname, int portno)
  395. {
  396. PLCLI plcli = NULL;
  397. LDAP *pldap = NULL;
  398. pldap = new LDAP;
  399. if (!pldap)
  400. return NULL;
  401. FillMemory(pldap, sizeof(LDAP), 0);
  402. if (FAILED(HrCreateLdapClient(LDAP_VER_CURRENT, INTERFACE_VER_CURRENT, &plcli)))
  403. {
  404. delete pldap;
  405. return NULL;
  406. }
  407. if (FAILED(plcli->HrConnect(hostname, portno)))
  408. {
  409. delete pldap;
  410. plcli->Release();
  411. return NULL;
  412. }
  413. pldap->plcli = plcli;
  414. return pldap;
  415. }
  416. extern "C" DLLEXPORT int __cdecl
  417. ldap_bind_s(LDAP *ld, char *dn, char *cred, int method)
  418. {
  419. HRESULT hr;
  420. XID xid;
  421. if (!ld->plcli)
  422. return LDAP_PARAM_ERROR;
  423. if (method != LDAP_AUTH_SIMPLE)
  424. return LDAP_AUTH_METHOD_NOT_SUPPORTED;
  425. if (!cred)
  426. cred = "";
  427. if (!dn)
  428. dn = "";
  429. hr = ld->plcli->HrBindSimple(dn, cred, &xid);
  430. if (FAILED(hr))
  431. return LdapResFromHr(hr);
  432. hr = ld->plcli->HrGetBindResponse(xid, INFINITE);
  433. return LdapResFromHr(hr);
  434. }
  435. extern "C" DLLEXPORT int __cdecl
  436. ldap_unbind(LDAP *ld)
  437. {
  438. if (!ld->plcli)
  439. return LDAP_PARAM_ERROR;
  440. ld->plcli->HrUnbind();
  441. ld->plcli->HrDisconnect();
  442. ld->plcli->Release();
  443. // just in case someone tries to use the ld after this...
  444. ld->plcli = NULL;
  445. delete ld;
  446. return LDAP_SUCCESS;
  447. }
  448. extern "C" DLLEXPORT int __cdecl
  449. ldap_search_s(LDAP *ld, char *base, int scope, char *filter, char *attrs[], int attrsonly, LDAPMessage **res)
  450. {
  451. struct timeval time;
  452. timerclear(&time);
  453. return ldap_search_st(ld, base, scope, filter, attrs, attrsonly, &time, res);
  454. }
  455. char *attrsNull[] = {NULL};
  456. extern "C" DLLEXPORT int __cdecl
  457. ldap_search_st(LDAP *ld, char *base, int scope, char *filter, char *attrs[], int attrsonly, struct timeval *timeout, LDAPMessage **res)
  458. {
  459. HRESULT hr;
  460. POBJ pobj;
  461. XID xid;
  462. SP sp;
  463. char szFilter[1024];
  464. *res = NULL;
  465. if (!attrs)
  466. attrs = attrsNull;
  467. // make local copy so we can munge this in place
  468. if (lstrlen(filter) > 1023)
  469. return LDAP_PARAM_ERROR;
  470. StrCpyN(szFilter, filter, ARRAYSIZE(szFilter));
  471. if (!ld->plcli)
  472. return LDAP_PARAM_ERROR;
  473. sp.szDNBase = base;
  474. sp.scope = scope;
  475. sp.deref = ld->ld_deref;
  476. sp.cRecordsMax = ld->ld_sizelimit;
  477. sp.cSecondsMax = ld->ld_timelimit;
  478. sp.fAttrsOnly = attrsonly;
  479. sp.pfilter = PfilterFromString(szFilter);
  480. if (!sp.pfilter)
  481. return LDAP_PARAM_ERROR;
  482. sp.cAttrib = CAttrib(attrs);
  483. sp.rgszAttrib = attrs;
  484. hr = ld->plcli->HrSearch(&sp, &xid);
  485. FreePfilter(sp.pfilter);
  486. if (FAILED(hr))
  487. return LdapResFromHr(hr);
  488. hr = ld->plcli->HrGetSearchResponse(xid, TimeoutFromTimeval(timeout), &pobj);
  489. if (FAILED(hr))
  490. return LdapResFromHr(hr);
  491. *res = pobj;
  492. return LdapResFromHr(hr);
  493. }
  494. extern "C" DLLEXPORT int __cdecl
  495. ldap_msgfree(LDAPMessage *res)
  496. {
  497. POBJ pobj = res;
  498. return LdapResFromHr(HrFreePobjList(pobj));
  499. }
  500. extern "C" DLLEXPORT LDAPMessage * __cdecl
  501. ldap_first_entry(LDAP *ld, LDAPMessage *res)
  502. {
  503. ld->ld_errno = 0;
  504. return res;
  505. }
  506. extern "C" DLLEXPORT LDAPMessage * __cdecl
  507. ldap_next_entry(LDAP *ld, LDAPMessage *entry)
  508. {
  509. ld->ld_errno = 0;
  510. return (LDAPMessage *)((POBJ)entry->pobjNext);
  511. }
  512. extern "C" DLLEXPORT int __cdecl
  513. ldap_count_entries(LDAP *ld, LDAPMessage *res)
  514. {
  515. POBJ pobj = (POBJ)res;
  516. int i = 0;
  517. ld->ld_errno = 0;
  518. while (pobj)
  519. {
  520. i++;
  521. pobj = pobj->pobjNext;
  522. }
  523. return i;
  524. }
  525. extern "C" DLLEXPORT char * __cdecl
  526. ldap_first_attribute(LDAP *ld, LDAPMessage *entry, void **ptr)
  527. {
  528. POBJ pobj = (POBJ)entry;
  529. *ptr = (void *)(pobj->pattrFirst);
  530. ld->ld_errno = 0;
  531. return pobj->pattrFirst->szAttrib;
  532. }
  533. // NOTE! minor change from rfc1823 API: the **ptr field below is just *ptr
  534. // in rfc1823,but thats not a good idea, so i'm using **ptr here
  535. // instead.
  536. extern "C" DLLEXPORT char * __cdecl
  537. ldap_next_attribute(LDAP *ld, LDAPMessage *entry, void **ptr)
  538. {
  539. ld->ld_errno = 0;
  540. if (!(*ptr))
  541. return NULL;
  542. PATTR pattr = ((PATTR)*ptr)->pattrNext;
  543. *ptr = (void *)pattr;
  544. if (pattr)
  545. return pattr->szAttrib;
  546. else
  547. return NULL;
  548. }
  549. PATTR
  550. PattrForAttr(POBJ pobj, char *szAttr)
  551. {
  552. PATTR pattr = pobj->pattrFirst;
  553. while (pattr)
  554. {
  555. if (!lstrcmpi(pattr->szAttrib, szAttr))
  556. return pattr;
  557. pattr = pattr->pattrNext;
  558. }
  559. return NULL;
  560. }
  561. extern "C" DLLEXPORT char ** __cdecl
  562. ldap_get_values(LDAP *ld, LDAPMessage *entry, char *attr)
  563. {
  564. POBJ pobj = (POBJ)entry;
  565. PATTR pattr;
  566. int cval;
  567. char **rgsz;
  568. int isz = 0;
  569. PVAL pval;
  570. ld->ld_errno = 0;
  571. pattr = PattrForAttr(pobj, attr);
  572. if (!pattr)
  573. return NULL;
  574. cval = Cval(pattr);
  575. rgsz = new char *[cval + 1];
  576. if (!rgsz)
  577. return NULL;
  578. pval = pattr->pvalFirst;
  579. while (pval)
  580. {
  581. rgsz[isz++] = pval->szVal;
  582. pval = pval->pvalNext;
  583. }
  584. rgsz[isz] = NULL;
  585. return rgsz;
  586. }
  587. extern "C" DLLEXPORT struct berval ** __cdecl
  588. ldap_get_values_len(LDAP *ld, LDAPMessage *entry, char *attr)
  589. {
  590. POBJ pobj = (POBJ)entry;
  591. PATTR pattr;
  592. int cval;
  593. BERVAL **rgpberval;
  594. int iberval = 0;
  595. PVAL pval;
  596. ld->ld_errno = 0;
  597. pattr = PattrForAttr(pobj, attr);
  598. if (!pattr)
  599. return NULL;
  600. cval = Cval(pattr);
  601. rgpberval = new BERVAL *[cval + 1];
  602. if (!rgpberval)
  603. return NULL;
  604. pval = pattr->pvalFirst;
  605. while (pval)
  606. {
  607. rgpberval[iberval] = new BERVAL;
  608. if (!rgpberval[iberval])
  609. {
  610. while (--iberval >= 0)
  611. delete rgpberval[iberval];
  612. delete [] rgpberval;
  613. return NULL;
  614. }
  615. rgpberval[iberval]->bv_len = lstrlen(pval->szVal) + 1;
  616. rgpberval[iberval]->bv_val = pval->szVal;
  617. iberval++;
  618. pval = pval->pvalNext;
  619. }
  620. rgpberval[iberval] = NULL;
  621. return rgpberval;
  622. }
  623. extern "C" DLLEXPORT int __cdecl
  624. ldap_count_values(char **vals)
  625. {
  626. // mmm, reuse of poorly-named code
  627. return CAttrib(vals);
  628. }
  629. extern "C" DLLEXPORT int __cdecl
  630. ldap_count_values_len(struct berval **vals)
  631. {
  632. // mmm, reuse of poorly-named code
  633. return CAttrib((char **)vals);
  634. }
  635. extern "C" DLLEXPORT int __cdecl
  636. ldap_value_free(char **vals)
  637. {
  638. delete [] vals;
  639. return LDAP_SUCCESS;
  640. }
  641. extern "C" DLLEXPORT int __cdecl
  642. ldap_value_free_len(struct berval **rgpberval)
  643. {
  644. BERVAL **ppberval = rgpberval;
  645. while (*ppberval)
  646. {
  647. delete *ppberval;
  648. ppberval++;
  649. }
  650. delete [] rgpberval;
  651. return LDAP_SUCCESS;
  652. }
  653. extern "C" DLLEXPORT char * __cdecl
  654. ldap_get_dn(LDAP *ld, LDAPMessage *entry)
  655. {
  656. POBJ pobj = (POBJ)entry;
  657. char *szDN;
  658. ld->ld_errno = 0;
  659. szDN = new char[lstrlen(pobj->szDN) + 1];
  660. if (!szDN)
  661. {
  662. ld->ld_errno = LDAP_NO_MEMORY;
  663. return NULL;
  664. }
  665. StrCpyN(szDN, pobj->szDN, lstrlen(pobj->szDN) + 1);
  666. return szDN;
  667. }
  668. extern "C" DLLEXPORT void __cdecl
  669. ldap_free_dn(char *dn)
  670. {
  671. delete [] dn;
  672. }