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.

1246 lines
28 KiB

  1. //--------------------------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation, 1996
  4. //
  5. // Description:
  6. //
  7. // Microsoft LDAP Sockets implementation.
  8. //
  9. // Authors:
  10. //
  11. // Umesh Madan
  12. // RobertC 4/17/96 Modified from CHATSOCK for LDAPCLI
  13. // davidsan 04-25-96 hacked to pieces and started over
  14. //
  15. //--------------------------------------------------------------------------------------------
  16. //--------------------------------------------------------------------------------------------
  17. //
  18. // INCLUDES
  19. //
  20. //--------------------------------------------------------------------------------------------
  21. #include "ldappch.h"
  22. #include "lclilist.h"
  23. #include "lclixd.h"
  24. //--------------------------------------------------------------------------------------------
  25. //
  26. // GLOBALS
  27. //
  28. //--------------------------------------------------------------------------------------------
  29. XL g_xl; // transaction list. limit one per process.
  30. //--------------------------------------------------------------------------------------------
  31. //
  32. // PROTOTYPES
  33. //
  34. //--------------------------------------------------------------------------------------------
  35. void ReceiveData(PVOID pvCookie, PVOID pv, int cb, int *pcbReceived);
  36. //--------------------------------------------------------------------------------------------
  37. //
  38. // FUNCTIONS
  39. //
  40. //--------------------------------------------------------------------------------------------
  41. __declspec(dllexport) HRESULT
  42. HrCreateLdapClient(int iVerLdap, int iVerInterface, PLCLI *pplcli)
  43. {
  44. if (iVerLdap != LDAP_VER_CURRENT || iVerInterface != INTERFACE_VER_CURRENT)
  45. return LDAP_E_VERSION;
  46. *pplcli = new CLdapClient(iVerLdap);
  47. if (!*pplcli)
  48. return E_OUTOFMEMORY;
  49. return NOERROR;
  50. }
  51. __declspec(dllexport) HRESULT
  52. HrFreePobjList(POBJ pobjList)
  53. {
  54. PATTR pattr;
  55. PVAL pval;
  56. while (pobjList)
  57. {
  58. delete [] pobjList->szDN;
  59. pattr = pobjList->pattrFirst;
  60. while (pattr)
  61. {
  62. delete [] pattr->szAttrib;
  63. pval = pattr->pvalFirst;
  64. while (pval)
  65. {
  66. delete [] pval->szVal;
  67. pval = pval->pvalNext;
  68. }
  69. pattr = pattr->pattrNext;
  70. }
  71. pobjList = pobjList->pobjNext;
  72. }
  73. return NOERROR;
  74. }
  75. typedef struct _genericstruct
  76. {
  77. struct _genericstruct *pgenNext;
  78. } GEN, *PGEN;
  79. void AddElemToList(void *pelem, void **ppelemList)
  80. {
  81. PGEN pgen = (PGEN)pelem;
  82. PGEN *ppgenList = (PGEN *)ppelemList;
  83. PGEN pgenT;
  84. if (!*ppgenList)
  85. {
  86. *ppgenList = pgen;
  87. }
  88. else
  89. {
  90. pgenT = *ppgenList;
  91. while (pgenT->pgenNext)
  92. {
  93. pgenT = pgenT->pgenNext;
  94. }
  95. pgenT->pgenNext = pgen;
  96. }
  97. }
  98. //--------------------------------------------------------------------------------------------
  99. //
  100. // CLASSES
  101. //
  102. //--------------------------------------------------------------------------------------------
  103. CLdapClient::CLdapClient(int iVerLdap)
  104. {
  105. InitializeCriticalSection(&m_cs);
  106. InitializeCriticalSection(&m_csRef);
  107. m_cRef = 1;
  108. m_iVerLdap = iVerLdap;
  109. m_psock = NULL;
  110. m_fConnected = FALSE;
  111. m_fHasCred = FALSE;
  112. m_fHasCtxt = FALSE;
  113. // some idle asserts that i'll put here cuz i don't have any better
  114. // place:
  115. Assert(&(((PVAL)0)->pvalNext) == (PVAL)0);
  116. Assert(&(((PATTR)0)->pattrNext) == (PATTR)0);
  117. Assert(&(((POBJ)0)->pobjNext) == (POBJ)0);
  118. }
  119. CLdapClient::~CLdapClient(void)
  120. {
  121. Assert(m_cRef == 0);
  122. delete m_psock;
  123. DeleteCriticalSection(&m_cs);
  124. DeleteCriticalSection(&m_csRef);
  125. }
  126. STDMETHODIMP
  127. CLdapClient::QueryInterface(REFIID riid,LPVOID FAR *ppvObj)
  128. {
  129. return E_NOTIMPL;
  130. }
  131. ULONG
  132. CLdapClient::AddRef()
  133. {
  134. ULONG cRefNew;
  135. ::EnterCriticalSection(&m_csRef);
  136. cRefNew = ++m_cRef;
  137. ::LeaveCriticalSection(&m_csRef);
  138. return cRefNew;
  139. }
  140. ULONG
  141. CLdapClient::Release()
  142. {
  143. ULONG cRefNew;
  144. ::EnterCriticalSection(&m_csRef);
  145. cRefNew = --m_cRef;
  146. ::LeaveCriticalSection(&m_csRef);
  147. if (!cRefNew)
  148. delete this;
  149. return cRefNew;
  150. }
  151. STDMETHODIMP
  152. CLdapClient::HrConnect(char *szServer, USHORT usPort)
  153. {
  154. HRESULT hr;
  155. StrCpyN(m_szServer, szServer, ARRAYSIZE(m_szServer));
  156. if (m_fConnected)
  157. return LDAP_E_ALREADYCONNECTED;
  158. ::EnterCriticalSection(&m_cs);
  159. if (!m_psock)
  160. {
  161. m_psock = new SOCK;
  162. if (!m_psock)
  163. {
  164. hr = E_OUTOFMEMORY;
  165. goto LBail;
  166. }
  167. }
  168. hr = m_psock->HrConnect(::ReceiveData, (PVOID)this, szServer, usPort);
  169. if (FAILED(hr))
  170. goto LBail;
  171. m_fConnected = TRUE;
  172. LBail:
  173. ::LeaveCriticalSection(&m_cs);
  174. return hr;
  175. }
  176. // constructs and returns an int from the next cb bytes of pb.
  177. DWORD
  178. DwBer(BYTE *pb, int cb)
  179. {
  180. int i;
  181. DWORD cbRet;
  182. cbRet = 0;
  183. for (i = 0; i < cb; i++)
  184. {
  185. cbRet <<= 8;
  186. cbRet |= pb[i];
  187. }
  188. return cbRet;
  189. }
  190. // decodes the length field at *pb, returning the length and setting *pcbLengthField.
  191. HRESULT
  192. HrCbBer(BYTE *pbData, int cbData, int *pcb, int *pcbLengthField)
  193. {
  194. if (cbData < 1)
  195. return LDAP_E_NOTENOUGHDATA;
  196. if (*pbData & 0x80)
  197. {
  198. // bottom 7 bits of *pb are # of bytes to turn into a size. let's us
  199. // just assume that we'll never have more than a 32-bit size indicator, mkey?
  200. *pcbLengthField = *pbData & 0x7f;
  201. if (cbData < *pcbLengthField + 1)
  202. return LDAP_E_NOTENOUGHDATA;
  203. *pcb = DwBer(&pbData[1], *pcbLengthField);
  204. (*pcbLengthField)++; // for the first byte
  205. }
  206. else
  207. {
  208. *pcbLengthField = 1;
  209. *pcb = (int)(DWORD)*pbData;
  210. }
  211. if (!*pcb)
  212. return LDAP_E_UNEXPECTEDDATA;
  213. return NOERROR;
  214. }
  215. // We can take advantage of certain features of LDAP to make assumptions
  216. // about the data that we receive. The main feature that's important for
  217. // this is the fact that any data block we receive is nested at the outermost
  218. // level with a SEQUENCE structure. This means that any block we get in
  219. // this routine should start with 0x30 followed by an encoded length field.
  220. // We use this encoded length field to decide if we've received the entire
  221. // data block or not.
  222. void
  223. CLdapClient::ReceiveData(PVOID pv, int cb, int *pcbReceived)
  224. {
  225. BYTE *pb = (BYTE *)pv;
  226. int cbSeq;
  227. int cbMsgId;
  228. int cbLengthField;
  229. int i;
  230. int ibCur;
  231. XID xid;
  232. PXD pxd;
  233. Assert(cb > 0);
  234. Assert(BER_SEQUENCE == 0x30);
  235. Assert(BER_INTEGER == 0x02);
  236. if (pb[0] != BER_SEQUENCE)
  237. {
  238. // what should we be doing with this? we've apparently
  239. // either received bogus data or gotten lost! //$ TODO: remove the assert someday
  240. Assert(FALSE);
  241. *pcbReceived = 0;
  242. return;
  243. }
  244. if (FAILED(HrCbBer(&pb[1], cb, &cbSeq, &cbLengthField)))
  245. {
  246. *pcbReceived = 0;
  247. return;
  248. }
  249. if (cbSeq + cbLengthField + 1 > cb)
  250. {
  251. *pcbReceived = 0;
  252. return;
  253. }
  254. *pcbReceived = cbSeq + cbLengthField + 1;
  255. // process pb[2+cbLengthField..*pcbReceived]. first element of the overall
  256. // structure is a message id. let's hope it's there...
  257. ibCur = 1 + cbLengthField;
  258. if (pb[ibCur++] != BER_INTEGER)
  259. {
  260. Assert(FALSE); //$ TODO: should remove this assert someday
  261. return;
  262. }
  263. // now a length
  264. if (FAILED(HrCbBer(&pb[ibCur], cb - ibCur, &cbMsgId, &cbLengthField)))
  265. return;
  266. ibCur += cbLengthField;
  267. // msg id is next bytes
  268. if (cbMsgId + ibCur >= cb)
  269. return;
  270. xid = DwBer(&pb[ibCur], cbMsgId);
  271. ibCur += cbMsgId;
  272. pxd = g_xl.PxdForXid(xid);
  273. // if we don't have an entry for this, assume it was cancelled or
  274. // something and just ignore this packet.
  275. if (!pxd)
  276. return;
  277. if (!pxd->FAddBuffer(&pb[ibCur], *pcbReceived - ibCur))
  278. {
  279. pxd->SetFOOM(TRUE);
  280. return;
  281. }
  282. ReleaseSemaphore(pxd->HsemSignal(), 1, NULL);
  283. }
  284. void
  285. ReceiveData(PVOID pvCookie, PVOID pv, int cb, int *pcbReceived)
  286. {
  287. CLdapClient *plcli = (CLdapClient *)pvCookie;
  288. plcli->ReceiveData(pv, cb, pcbReceived);
  289. }
  290. STDMETHODIMP
  291. CLdapClient::HrDisconnect()
  292. {
  293. if (!m_fConnected)
  294. {
  295. return LDAP_E_NOTCONNECTED;
  296. }
  297. m_fConnected = FALSE;
  298. return m_psock->HrDisconnect();
  299. }
  300. STDMETHODIMP
  301. CLdapClient::HrIsConnected()
  302. {
  303. return m_fConnected ? NOERROR : S_FALSE;
  304. }
  305. HRESULT
  306. CLdapClient::HrSendBindMsg(XID xid, char *szDN, int iAuth, void *pv, int cb)
  307. {
  308. LBER lber;
  309. HRESULT hr;
  310. // a BIND request looks like:
  311. // [APPLICATION 0] (IMPLICIT) SEQUENCE {
  312. // version (INTEGER)
  313. // szDN (LDAPDN)
  314. // authentication CHOICE {
  315. // simple [0] OCTET STRING
  316. // [... other choices ...]
  317. // }
  318. // }
  319. VERIFY(lber.HrStartWriteSequence());
  320. VERIFY(lber.HrAddValue((LONG)xid));
  321. VERIFY(lber.HrStartWriteSequence(LDAP_BIND_CMD));
  322. VERIFY(lber.HrAddValue((LONG)m_iVerLdap));
  323. VERIFY(lber.HrAddValue((const TCHAR *)szDN));
  324. VERIFY(lber.HrAddBinaryValue((BYTE *)pv, cb, iAuth));
  325. VERIFY(lber.HrEndWriteSequence());
  326. VERIFY(lber.HrEndWriteSequence());
  327. hr = m_psock->HrSend(lber.PbData(), lber.CbData());
  328. LBail:
  329. return hr;
  330. }
  331. STDMETHODIMP
  332. CLdapClient::HrBindSimple(char *szDN, char *szPass, PXID pxid)
  333. {
  334. LBER lber;
  335. HRESULT hr;
  336. PXD pxd;
  337. pxd = g_xl.PxdNewXaction(xtypeBind);
  338. if (!pxd)
  339. return E_OUTOFMEMORY;
  340. hr = this->HrSendBindMsg(pxd->Xid(), szDN, BIND_SIMPLE, szPass, lstrlen(szPass));
  341. if (FAILED(hr))
  342. return hr;
  343. *pxid = pxd->Xid();
  344. return NOERROR;
  345. }
  346. HRESULT
  347. CLdapClient::HrWaitForPxd(PXD pxd, DWORD timeout, BOOL *pfDel)
  348. {
  349. DWORD dwWait;
  350. HRESULT hr;
  351. *pfDel = FALSE;
  352. dwWait = WaitForSingleObject(pxd->HsemSignal(), timeout);
  353. switch (dwWait)
  354. {
  355. default:
  356. Assert(FALSE);
  357. // fall through
  358. case WAIT_FAILED:
  359. hr = LDAP_E_INVALIDXID;
  360. break;
  361. case WAIT_TIMEOUT:
  362. hr = LDAP_E_TIMEOUT;
  363. break;
  364. case WAIT_OBJECT_0:
  365. *pfDel = TRUE;
  366. if (pxd->FCancelled())
  367. {
  368. hr = LDAP_E_CANCELLED;
  369. }
  370. else if (pxd->FOOM())
  371. {
  372. hr = E_OUTOFMEMORY;
  373. }
  374. else
  375. {
  376. hr = NOERROR;
  377. }
  378. break;
  379. }
  380. return hr;
  381. }
  382. HRESULT
  383. CLdapClient::HrGetSimpleResponse(XID xid, DWORD xtype, ULONG ulTagResult, DWORD timeout)
  384. {
  385. PXD pxd;
  386. BYTE *pbData;
  387. int cbData;
  388. HRESULT hr = LDAP_E_UNEXPECTEDDATA;
  389. BOOL fDel;
  390. int cb;
  391. int cbSub;
  392. int cbLengthField;
  393. int ibCur;
  394. long lResult;
  395. ULONG ulTag;
  396. LBER lber;
  397. pxd = g_xl.PxdForXid(xid);
  398. if (!pxd)
  399. return LDAP_E_INVALIDXID;
  400. if (pxd->Xtype() != xtype)
  401. return LDAP_E_INVALIDXTYPE;
  402. if (pxd->FCancelled())
  403. return LDAP_E_CANCELLED;
  404. if (pxd->FOOM())
  405. return E_OUTOFMEMORY;
  406. if (pxd->FHasData())
  407. {
  408. fDel = TRUE;
  409. }
  410. else
  411. {
  412. hr = this->HrWaitForPxd(pxd, timeout, &fDel);
  413. if (FAILED(hr))
  414. goto LBail;
  415. }
  416. if (!pxd->FGetBuffer(&pbData, &cbData))
  417. {
  418. //$ what's the right error here?
  419. hr = LDAP_E_UNEXPECTEDDATA;
  420. goto LBail;
  421. }
  422. VERIFY(lber.HrLoadBer(pbData, cbData));
  423. VERIFY(lber.HrStartReadSequence(ulTagResult));
  424. VERIFY(lber.HrPeekTag(&ulTag));
  425. if (ulTag == BER_SEQUENCE)
  426. {
  427. Assert(FALSE); // i want to see if any server returns explicit sequences
  428. VERIFY(lber.HrStartReadSequence());
  429. }
  430. VERIFY(lber.HrGetEnumValue(&lResult));
  431. if (ulTag == BER_SEQUENCE)
  432. {
  433. VERIFY(lber.HrEndReadSequence());
  434. }
  435. VERIFY(lber.HrEndReadSequence());
  436. hr = this->HrFromLdapResult(lResult);
  437. LBail:
  438. if (fDel)
  439. g_xl.RemovePxd(pxd);
  440. return hr;
  441. }
  442. STDMETHODIMP
  443. CLdapClient::HrGetBindResponse(XID xid, DWORD timeout)
  444. {
  445. return this->HrGetSimpleResponse(xid, xtypeBind, LDAP_BIND_RES, timeout);
  446. }
  447. STDMETHODIMP
  448. CLdapClient::HrUnbind()
  449. {
  450. PXD pxd;
  451. XID xid;
  452. HRESULT hr;
  453. LBER lber;
  454. pxd = g_xl.PxdNewXaction(xtypeUnbind);
  455. if (!pxd)
  456. return E_OUTOFMEMORY;
  457. xid = pxd->Xid();
  458. g_xl.RemovePxd(pxd); // don't need this, since there's no response
  459. // unbind:
  460. // [APPLICATION 2] NULL
  461. VERIFY(lber.HrStartWriteSequence());
  462. VERIFY(lber.HrAddValue((LONG)xid));
  463. VERIFY(lber.HrStartWriteSequence(LDAP_UNBIND_CMD));
  464. VERIFY(lber.HrAddValue((const TCHAR *)"", BER_NULL));
  465. VERIFY(lber.HrEndWriteSequence());
  466. VERIFY(lber.HrEndWriteSequence());
  467. hr = m_psock->HrSend(lber.PbData(), lber.CbData());
  468. LBail:
  469. return hr;
  470. }
  471. HRESULT
  472. CLdapClient::HrEncodeFilter(LBER *plber, PFILTER pfilter)
  473. {
  474. HRESULT hr = E_OUTOFMEMORY;
  475. HRESULT hrSub;
  476. PFILTER pfilterT;
  477. switch (pfilter->type)
  478. {
  479. case LDAP_FILTER_AND:
  480. case LDAP_FILTER_OR:
  481. VERIFY(plber->HrStartWriteSequence(pfilter->type));
  482. pfilterT = pfilter->pfilterSub;
  483. while (pfilterT)
  484. {
  485. VERIFY(this->HrEncodeFilter(plber, pfilterT));
  486. pfilterT = pfilterT->pfilterNext;
  487. }
  488. VERIFY(plber->HrEndWriteSequence());
  489. break;
  490. case LDAP_FILTER_NOT:
  491. VERIFY(plber->HrStartWriteSequence(LDAP_FILTER_NOT));
  492. VERIFY(this->HrEncodeFilter(plber, pfilter->pfilterSub));
  493. VERIFY(plber->HrEndWriteSequence());
  494. break;
  495. case LDAP_FILTER_GE:
  496. case LDAP_FILTER_LE:
  497. case LDAP_FILTER_APPROX:
  498. case LDAP_FILTER_EQUALITY:
  499. VERIFY(plber->HrStartWriteSequence(pfilter->type));
  500. VERIFY(plber->HrAddValue(pfilter->ava.szAttrib));
  501. VERIFY(plber->HrAddValue(pfilter->ava.szValue));
  502. VERIFY(plber->HrEndWriteSequence());
  503. break;
  504. case LDAP_FILTER_SUBSTRINGS:
  505. VERIFY(plber->HrStartWriteSequence(LDAP_FILTER_SUBSTRINGS));
  506. VERIFY(plber->HrAddValue(pfilter->sub.szAttrib));
  507. VERIFY(plber->HrStartWriteSequence());
  508. if (pfilter->sub.szInitial)
  509. {
  510. VERIFY(plber->HrAddValue(pfilter->sub.szInitial, 0 | BER_CLASS_CONTEXT_SPECIFIC));
  511. }
  512. if (pfilter->sub.szAny)
  513. {
  514. VERIFY(plber->HrAddValue(pfilter->sub.szAny, 1 | BER_CLASS_CONTEXT_SPECIFIC));
  515. }
  516. if (pfilter->sub.szFinal)
  517. {
  518. VERIFY(plber->HrAddValue(pfilter->sub.szFinal, 2 | BER_CLASS_CONTEXT_SPECIFIC));
  519. }
  520. VERIFY(plber->HrEndWriteSequence());
  521. VERIFY(plber->HrEndWriteSequence());
  522. break;
  523. case LDAP_FILTER_PRESENT:
  524. VERIFY(plber->HrAddValue(pfilter->szAttrib, LDAP_FILTER_PRESENT));
  525. break;
  526. }
  527. hr = NOERROR;
  528. LBail:
  529. return hr;
  530. }
  531. STDMETHODIMP
  532. CLdapClient::HrSearch(PSP psp, PXID pxid)
  533. {
  534. LBER lber;
  535. HRESULT hr;
  536. PXD pxd;
  537. int i;
  538. pxd = g_xl.PxdNewXaction(xtypeSearch);
  539. if (!pxd)
  540. return E_OUTOFMEMORY;
  541. // a SEARCH request looks like:
  542. // [APPLICATION 3] SEQUENCE {
  543. // szDNBase (LDAPDN)
  544. // scope {enum base==0, singlelevel==1, subtree=2}
  545. // deref {enum never=0, derefsearch==1, derefbase==2, derefall==3}
  546. // sizelimit (integer)
  547. // timelimit (integer)
  548. // attrsOnly (BOOLEAN)
  549. // filter (complex type)
  550. // sequence of attrtype
  551. VERIFY(lber.HrStartWriteSequence());
  552. VERIFY(lber.HrAddValue((LONG)pxd->Xid()));
  553. VERIFY(lber.HrStartWriteSequence(LDAP_SEARCH_CMD));
  554. VERIFY(lber.HrAddValue((const TCHAR *)psp->szDNBase));
  555. VERIFY(lber.HrAddValue(psp->scope, BER_ENUMERATED));
  556. VERIFY(lber.HrAddValue(psp->deref, BER_ENUMERATED));
  557. VERIFY(lber.HrAddValue((LONG)psp->cRecordsMax));
  558. VERIFY(lber.HrAddValue((LONG)psp->cSecondsMax));
  559. VERIFY(lber.HrAddValue(psp->fAttrsOnly, BER_BOOLEAN));
  560. VERIFY(this->HrEncodeFilter(&lber, psp->pfilter));
  561. // attributes to return
  562. VERIFY(lber.HrStartWriteSequence());
  563. for (i = 0; i < psp->cAttrib; i++)
  564. {
  565. VERIFY(lber.HrAddValue((const TCHAR *)psp->rgszAttrib[i]));
  566. }
  567. VERIFY(lber.HrEndWriteSequence());
  568. VERIFY(lber.HrEndWriteSequence());
  569. VERIFY(lber.HrEndWriteSequence());
  570. hr = m_psock->HrSend(lber.PbData(), lber.CbData());
  571. LBail:
  572. if (FAILED(hr))
  573. return hr;
  574. *pxid = pxd->Xid();
  575. return NOERROR;
  576. }
  577. STDMETHODIMP
  578. CLdapClient::HrGetSearchResponse(XID xid, DWORD timeout, POBJ *ppobj)
  579. {
  580. PXD pxd;
  581. BYTE *pbData;
  582. int cbData;
  583. HRESULT hr = LDAP_E_UNEXPECTEDDATA;
  584. BOOL fDel;
  585. int cb;
  586. int cbString;
  587. int cbSub;
  588. int cbLengthField;
  589. int ibCur;
  590. ULONG ulTag;
  591. long lResult;
  592. LBER lber;
  593. BOOL fGotAllData = FALSE;
  594. POBJ pobj;
  595. PATTR pattr;
  596. PVAL pval;
  597. *ppobj = NULL;
  598. pxd = g_xl.PxdForXid(xid);
  599. if (!pxd)
  600. return LDAP_E_INVALIDXID;
  601. if (pxd->Xtype() != xtypeSearch)
  602. return LDAP_E_INVALIDXTYPE;
  603. while (!fGotAllData)
  604. {
  605. if (pxd->FCancelled())
  606. return LDAP_E_CANCELLED;
  607. if (pxd->FOOM())
  608. return E_OUTOFMEMORY;
  609. hr = this->HrWaitForPxd(pxd, timeout, &fDel);
  610. if (FAILED(hr))
  611. goto LBail;
  612. if (!pxd->FGetBuffer(&pbData, &cbData))
  613. {
  614. //$ what's the right error here?
  615. hr = LDAP_E_UNEXPECTEDDATA;
  616. Assert(FALSE);
  617. goto LBail;
  618. }
  619. VERIFY(lber.HrLoadBer(pbData, cbData));
  620. hr = LDAP_E_UNEXPECTEDDATA;
  621. VERIFY(lber.HrPeekTag(&ulTag));
  622. if (ulTag == (LDAP_SEARCH_ENTRY | BER_FORM_CONSTRUCTED | BER_CLASS_APPLICATION))
  623. {
  624. VERIFY(lber.HrStartReadSequence(LDAP_SEARCH_ENTRY | BER_FORM_CONSTRUCTED | BER_CLASS_APPLICATION));
  625. pobj = new OBJ;
  626. pobj->pobjNext = NULL;
  627. pobj->pattrFirst = NULL;
  628. if (!pobj)
  629. {
  630. hr = E_OUTOFMEMORY;
  631. goto LBail;
  632. }
  633. AddElemToList(pobj, (void **)ppobj);
  634. VERIFY(lber.HrGetStringLength(&cbString));
  635. pobj->szDN = new char[cbString + 1];
  636. if (!pobj->szDN)
  637. {
  638. hr = E_OUTOFMEMORY;
  639. goto LBail;
  640. }
  641. VERIFY(lber.HrGetValue(pobj->szDN, cbString + 1));
  642. VERIFY(lber.HrStartReadSequence());
  643. while (!lber.FEndOfSequence())
  644. {
  645. VERIFY(lber.HrStartReadSequence());
  646. while (!lber.FEndOfSequence())
  647. {
  648. pattr = new ATTR;
  649. pattr->pattrNext = NULL;
  650. pattr->pvalFirst = NULL;
  651. AddElemToList(pattr, (void **)&(pobj->pattrFirst));
  652. VERIFY(lber.HrGetStringLength(&cbString));
  653. pattr->szAttrib = new char[cbString + 1];
  654. if (!pattr->szAttrib)
  655. {
  656. hr = E_OUTOFMEMORY;
  657. goto LBail;
  658. }
  659. VERIFY(lber.HrGetValue(pattr->szAttrib, cbString + 1));
  660. VERIFY(lber.HrStartReadSequence(BER_SET));
  661. while (!lber.FEndOfSequence())
  662. {
  663. pval = new VAL;
  664. pval->pvalNext = NULL;
  665. AddElemToList(pval, (void **)&(pattr->pvalFirst));
  666. VERIFY(lber.HrGetStringLength(&cbString));
  667. pval->szVal = new char[cbString + 1];
  668. if (!pval->szVal)
  669. {
  670. hr = E_OUTOFMEMORY;
  671. goto LBail;
  672. }
  673. VERIFY(lber.HrGetValue(pval->szVal, cbString + 1));
  674. }
  675. VERIFY(lber.HrEndReadSequence());
  676. }
  677. VERIFY(lber.HrEndReadSequence());
  678. }
  679. VERIFY(lber.HrEndReadSequence());
  680. VERIFY(lber.HrEndReadSequence());
  681. }
  682. else if (ulTag == (LDAP_SEARCH_RESULTCODE | BER_FORM_CONSTRUCTED | BER_CLASS_APPLICATION))
  683. {
  684. fGotAllData = TRUE;
  685. VERIFY(lber.HrStartReadSequence(LDAP_SEARCH_RESULTCODE | BER_FORM_CONSTRUCTED | BER_CLASS_APPLICATION));
  686. VERIFY(lber.HrGetEnumValue(&lResult));
  687. VERIFY(lber.HrEndReadSequence());
  688. hr = this->HrFromLdapResult(lResult);
  689. }
  690. else
  691. {
  692. goto LBail;
  693. }
  694. } // while !fGotAllData
  695. LBail:
  696. if (fDel)
  697. g_xl.RemovePxd(pxd);
  698. return hr;
  699. }
  700. // seq { type set {values}}
  701. HRESULT
  702. CLdapClient::HrEncodePattr(LBER *plber, PATTR pattr)
  703. {
  704. HRESULT hr;
  705. PVAL pval;
  706. VERIFY(plber->HrStartWriteSequence());
  707. VERIFY(plber->HrAddValue((TCHAR *)pattr->szAttrib));
  708. VERIFY(plber->HrStartWriteSequence(BER_SET));
  709. pval = pattr->pvalFirst;
  710. while (pval)
  711. {
  712. VERIFY(plber->HrAddValue((TCHAR *)pval->szVal));
  713. pval = pval->pvalNext;
  714. }
  715. VERIFY(plber->HrEndWriteSequence());
  716. VERIFY(plber->HrEndWriteSequence());
  717. LBail:
  718. return hr;
  719. }
  720. // pmod is SEQ { op seq { type set {values}}}
  721. HRESULT
  722. CLdapClient::HrEncodePmod(LBER *plber, PMOD pmod)
  723. {
  724. HRESULT hr;
  725. PATTR pattr;
  726. VERIFY(plber->HrStartWriteSequence());
  727. VERIFY(plber->HrAddValue((long)pmod->modop, BER_ENUMERATED));
  728. pattr = pmod->pattrFirst;
  729. while (pattr)
  730. {
  731. VERIFY(this->HrEncodePattr(plber, pattr));
  732. pattr = pattr->pattrNext;
  733. }
  734. VERIFY(plber->HrEndWriteSequence());
  735. LBail:
  736. return hr;
  737. }
  738. STDMETHODIMP
  739. CLdapClient::HrModify(char *szDN, PMOD pmod, PXID pxid)
  740. {
  741. LBER lber;
  742. HRESULT hr;
  743. PXD pxd;
  744. pxd = g_xl.PxdNewXaction(xtypeModify);
  745. if (!pxd)
  746. return E_OUTOFMEMORY;
  747. // a MODIFY request looks like:
  748. // [APPLICATION 6] SEQUENCE {
  749. // object (LDAPDN)
  750. // SEQUENCE OF SEQUENCE {
  751. // operation
  752. // SEQUENCE {
  753. // type
  754. // SET OF values
  755. // }
  756. // }
  757. // }
  758. VERIFY(lber.HrStartWriteSequence());
  759. VERIFY(lber.HrAddValue((LONG)pxd->Xid()));
  760. VERIFY(lber.HrStartWriteSequence(LDAP_MODIFY_CMD));
  761. VERIFY(lber.HrAddValue((const TCHAR *)szDN));
  762. VERIFY(lber.HrStartWriteSequence());
  763. while (pmod)
  764. {
  765. VERIFY(this->HrEncodePmod(&lber, pmod));
  766. pmod = pmod->pmodNext;
  767. }
  768. VERIFY(lber.HrEndWriteSequence());
  769. VERIFY(lber.HrEndWriteSequence());
  770. VERIFY(lber.HrEndWriteSequence());
  771. hr = m_psock->HrSend(lber.PbData(), lber.CbData());
  772. LBail:
  773. if (FAILED(hr))
  774. return hr;
  775. *pxid = pxd->Xid();
  776. return NOERROR;
  777. }
  778. STDMETHODIMP
  779. CLdapClient::HrGetModifyResponse(XID xid, DWORD timeout)
  780. {
  781. return this->HrGetSimpleResponse(xid, xtypeModify, LDAP_MODIFY_RES, timeout);
  782. }
  783. STDMETHODIMP
  784. CLdapClient::HrAdd(char *szDN, PATTR pattr, PXID pxid)
  785. {
  786. LBER lber;
  787. HRESULT hr;
  788. PXD pxd;
  789. pxd = g_xl.PxdNewXaction(xtypeAdd);
  790. if (!pxd)
  791. return E_OUTOFMEMORY;
  792. // an ADD request looks like:
  793. // [APPLICATION 8] SEQUENCE {
  794. // object (LDAPDN)
  795. // SEQUENCE OF SEQUENCE {
  796. // type
  797. // SET OF values
  798. // }
  799. // }
  800. VERIFY(lber.HrStartWriteSequence());
  801. VERIFY(lber.HrAddValue((LONG)pxd->Xid()));
  802. VERIFY(lber.HrStartWriteSequence(LDAP_ADD_CMD));
  803. VERIFY(lber.HrAddValue((const TCHAR *)szDN));
  804. VERIFY(lber.HrStartWriteSequence());
  805. while (pattr)
  806. {
  807. VERIFY(this->HrEncodePattr(&lber, pattr));
  808. pattr = pattr->pattrNext;
  809. }
  810. VERIFY(lber.HrEndWriteSequence());
  811. VERIFY(lber.HrEndWriteSequence());
  812. VERIFY(lber.HrEndWriteSequence());
  813. hr = m_psock->HrSend(lber.PbData(), lber.CbData());
  814. LBail:
  815. if (FAILED(hr))
  816. return hr;
  817. *pxid = pxd->Xid();
  818. return NOERROR;
  819. }
  820. STDMETHODIMP
  821. CLdapClient::HrGetAddResponse(XID xid, DWORD timeout)
  822. {
  823. return this->HrGetSimpleResponse(xid, xtypeAdd, LDAP_ADD_RES, timeout);
  824. }
  825. STDMETHODIMP
  826. CLdapClient::HrDelete(char *szDN, PXID pxid)
  827. {
  828. LBER lber;
  829. HRESULT hr;
  830. PXD pxd;
  831. pxd = g_xl.PxdNewXaction(xtypeDelete);
  832. if (!pxd)
  833. return E_OUTOFMEMORY;
  834. // a DELETE request looks like:
  835. // [APPLICATION 10] LDAPDN
  836. VERIFY(lber.HrStartWriteSequence());
  837. VERIFY(lber.HrAddValue((LONG)pxd->Xid()));
  838. VERIFY(lber.HrAddValue((const TCHAR *)szDN, LDAP_DELETE_CMD));
  839. VERIFY(lber.HrEndWriteSequence());
  840. hr = m_psock->HrSend(lber.PbData(), lber.CbData());
  841. LBail:
  842. if (FAILED(hr))
  843. return hr;
  844. *pxid = pxd->Xid();
  845. return NOERROR;
  846. }
  847. STDMETHODIMP
  848. CLdapClient::HrGetDeleteResponse(XID xid, DWORD timeout)
  849. {
  850. return this->HrGetSimpleResponse(xid, xtypeDelete, LDAP_DELETE_RES, timeout);
  851. }
  852. STDMETHODIMP
  853. CLdapClient::HrModifyRDN(char *szDN, char *szNewRDN, BOOL fDeleteOldRDN, PXID pxid)
  854. {
  855. LBER lber;
  856. HRESULT hr;
  857. PXD pxd;
  858. pxd = g_xl.PxdNewXaction(xtypeModifyRDN);
  859. if (!pxd)
  860. return E_OUTOFMEMORY;
  861. // a MODIFYRDN request looks like:
  862. // [APPLICATION 12] SEQUENCE {
  863. // object (LDAPDN)
  864. // newrdn (RELATIVE LDAPDN)
  865. // deleteoldrdn (BOOL)
  866. // }
  867. VERIFY(lber.HrStartWriteSequence());
  868. VERIFY(lber.HrAddValue((LONG)pxd->Xid()));
  869. VERIFY(lber.HrStartWriteSequence(LDAP_MODRDN_CMD));
  870. VERIFY(lber.HrAddValue((const TCHAR *)szDN));
  871. VERIFY(lber.HrAddValue((const TCHAR *)szNewRDN));
  872. VERIFY(lber.HrAddValue(fDeleteOldRDN, BER_BOOLEAN));
  873. VERIFY(lber.HrEndWriteSequence());
  874. VERIFY(lber.HrEndWriteSequence());
  875. hr = m_psock->HrSend(lber.PbData(), lber.CbData());
  876. LBail:
  877. if (FAILED(hr))
  878. return hr;
  879. *pxid = pxd->Xid();
  880. return NOERROR;
  881. }
  882. STDMETHODIMP
  883. CLdapClient::HrGetModifyRDNResponse(XID xid, DWORD timeout)
  884. {
  885. return this->HrGetSimpleResponse(xid, xtypeModifyRDN, LDAP_MODRDN_RES, timeout);
  886. }
  887. STDMETHODIMP
  888. CLdapClient::HrCompare(char *szDN, char *szAttrib, char *szValue, PXID pxid)
  889. {
  890. LBER lber;
  891. HRESULT hr;
  892. PXD pxd;
  893. pxd = g_xl.PxdNewXaction(xtypeCompare);
  894. if (!pxd)
  895. return E_OUTOFMEMORY;
  896. // a COMPARE request looks like:
  897. // [APPLICATION 14] SEQUENCE {
  898. // object (LDAPDN)
  899. // AVA ava
  900. // }
  901. VERIFY(lber.HrStartWriteSequence());
  902. VERIFY(lber.HrAddValue((LONG)pxd->Xid()));
  903. VERIFY(lber.HrStartWriteSequence(LDAP_COMPARE_CMD));
  904. VERIFY(lber.HrAddValue((const TCHAR *)szDN));
  905. VERIFY(lber.HrStartWriteSequence());
  906. VERIFY(lber.HrAddValue((const TCHAR *)szAttrib));
  907. VERIFY(lber.HrAddValue((const TCHAR *)szValue));
  908. VERIFY(lber.HrEndWriteSequence());
  909. VERIFY(lber.HrEndWriteSequence());
  910. VERIFY(lber.HrEndWriteSequence());
  911. hr = m_psock->HrSend(lber.PbData(), lber.CbData());
  912. LBail:
  913. if (FAILED(hr))
  914. return hr;
  915. *pxid = pxd->Xid();
  916. return NOERROR;
  917. }
  918. STDMETHODIMP
  919. CLdapClient::HrGetCompareResponse(XID xid, DWORD timeout)
  920. {
  921. return this->HrGetSimpleResponse(xid, xtypeCompare, LDAP_COMPARE_RES, timeout);
  922. }
  923. STDMETHODIMP
  924. CLdapClient::HrCancelXid(XID xid)
  925. {
  926. PXD pxd = g_xl.PxdForXid(xid);
  927. PXD pxdNew;
  928. XID xidNew;
  929. HRESULT hr;
  930. LBER lber;
  931. if (!pxd)
  932. return LDAP_E_INVALIDXID;
  933. pxdNew = g_xl.PxdNewXaction(xtypeAbandon);
  934. if (!pxdNew)
  935. return E_OUTOFMEMORY;
  936. xidNew = pxdNew->Xid();
  937. g_xl.RemovePxd(pxdNew); // don't need to keep this around
  938. // abandon:
  939. // [APPLICATION 16] message id
  940. VERIFY(lber.HrStartWriteSequence());
  941. VERIFY(lber.HrAddValue((LONG)xidNew));
  942. VERIFY(lber.HrStartWriteSequence(LDAP_ABANDON_CMD));
  943. VERIFY(lber.HrAddValue((LONG)xid));
  944. VERIFY(lber.HrEndWriteSequence());
  945. VERIFY(lber.HrEndWriteSequence());
  946. hr = m_psock->HrSend(lber.PbData(), lber.CbData());
  947. LBail:
  948. pxd->SetFCancelled(TRUE);
  949. return hr;
  950. }
  951. //$ TODO: Map all LDAP results to HRESULTs
  952. HRESULT
  953. CLdapClient::HrFromLdapResult(int iResult)
  954. {
  955. HRESULT hr;
  956. switch (iResult)
  957. {
  958. default:
  959. return E_FAIL;
  960. case LDAP_OPERATIONS_ERROR:
  961. return LDAP_E_OPERATIONS;
  962. case LDAP_PROTOCOL_ERROR:
  963. return LDAP_E_PROTOCOL;
  964. case LDAP_TIMELIMIT_EXCEEDED:
  965. return LDAP_S_TIMEEXCEEDED;
  966. case LDAP_SIZELIMIT_EXCEEDED:
  967. return LDAP_S_SIZEEXCEEDED;
  968. case LDAP_COMPARE_FALSE:
  969. return S_FALSE;
  970. case LDAP_COMPARE_TRUE:
  971. return NOERROR;
  972. case LDAP_AUTH_METHOD_NOT_SUPPORTED:
  973. return LDAP_E_AUTHMETHOD;
  974. case LDAP_STRONG_AUTH_REQUIRED:
  975. return LDAP_E_STRONGAUTHREQUIRED;
  976. case LDAP_NO_SUCH_ATTRIBUTE:
  977. return LDAP_E_NOSUCHATTRIBUTE;
  978. case LDAP_UNDEFINED_TYPE:
  979. return LDAP_E_UNDEFINEDTYPE;
  980. case LDAP_INAPPROPRIATE_MATCHING:
  981. return LDAP_E_MATCHING;
  982. case LDAP_CONSTRAINT_VIOLATION:
  983. return LDAP_E_CONSTRAINT;
  984. case LDAP_ATTRIBUTE_OR_VALUE_EXISTS:
  985. return LDAP_E_ATTRIBORVALEXISTS;
  986. case LDAP_INVALID_SYNTAX:
  987. return LDAP_E_SYNTAX;
  988. case LDAP_NO_SUCH_OBJECT:
  989. return LDAP_E_NOSUCHOBJECT;
  990. case LDAP_ALIAS_PROBLEM:
  991. return LDAP_E_ALIAS;
  992. case LDAP_INVALID_DN_SYNTAX:
  993. return LDAP_E_DNSYNTAX;
  994. case LDAP_IS_LEAF:
  995. return LDAP_E_ISLEAF;
  996. case LDAP_ALIAS_DEREF_PROBLEM:
  997. return LDAP_E_ALIASDEREF;
  998. case LDAP_INAPPROPRIATE_AUTH:
  999. return LDAP_E_AUTH;
  1000. case LDAP_INVALID_CREDENTIALS:
  1001. return LDAP_E_CREDENTIALS;
  1002. case LDAP_INSUFFICIENT_RIGHTS:
  1003. return LDAP_E_RIGHTS;
  1004. case LDAP_BUSY:
  1005. return LDAP_E_BUSY;
  1006. case LDAP_UNAVAILABLE:
  1007. return LDAP_E_UNAVAILABLE;
  1008. case LDAP_UNWILLING_TO_PERFORM:
  1009. return LDAP_E_UNWILLING;
  1010. case LDAP_LOOP_DETECT:
  1011. return LDAP_E_LOOP;
  1012. case LDAP_NAMING_VIOLATION:
  1013. return LDAP_E_NAMING;
  1014. case LDAP_OBJECT_CLASS_VIOLATION:
  1015. return LDAP_E_OBJECTCLASS;
  1016. case LDAP_NOT_ALLOWED_ON_NONLEAF:
  1017. return LDAP_E_NOTALLOWEDONNONLEAF;
  1018. case LDAP_NOT_ALLOWED_ON_RDN:
  1019. return LDAP_E_NOTALLOWEDONRDN;
  1020. case LDAP_ALREADY_EXISTS:
  1021. return LDAP_E_ALREADYEXISTS;
  1022. case LDAP_NO_OBJECT_CLASS_MODS:
  1023. return LDAP_E_NOOBJECTCLASSMODS;
  1024. case LDAP_RESULTS_TOO_LARGE:
  1025. return LDAP_E_RESULTSTOOLARGE;
  1026. case LDAP_OTHER:
  1027. return LDAP_E_OTHER;
  1028. case LDAP_SERVER_DOWN:
  1029. return LDAP_E_SERVERDOWN;
  1030. case LDAP_LOCAL_ERROR:
  1031. return LDAP_E_LOCAL;
  1032. case LDAP_ENCODING_ERROR:
  1033. return LDAP_E_ENCODING;
  1034. case LDAP_DECODING_ERROR:
  1035. return LDAP_E_DECODING;
  1036. case LDAP_TIMEOUT:
  1037. return LDAP_E_TIMEOUT;
  1038. case LDAP_AUTH_UNKNOWN:
  1039. return LDAP_E_AUTHUNKNOWN;
  1040. case LDAP_FILTER_ERROR:
  1041. return LDAP_E_FILTER;
  1042. case LDAP_USER_CANCELLED:
  1043. return LDAP_E_USERCANCELLED;
  1044. case LDAP_PARAM_ERROR:
  1045. return E_INVALIDARG;
  1046. case LDAP_NO_MEMORY:
  1047. return E_OUTOFMEMORY;
  1048. case LDAP_SUCCESS:
  1049. return NOERROR;
  1050. }
  1051. }