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.

1076 lines
23 KiB

  1. /* ----------------------------------------------------------------------
  2. Module: ULS.DLL (Service Provider)
  3. File: spils.cpp
  4. Content: This file contains the ILS specifics.
  5. History:
  6. 12/10/96 Chu, Lon-Chan [lonchanc]
  7. Created.
  8. Copyright (c) Microsoft Corporation 1996-1997
  9. ---------------------------------------------------------------------- */
  10. #include "ulsp.h"
  11. #include "spinc.h"
  12. #include "winsock.h"
  13. #include "ping.h"
  14. // Constant string for ISBU's special modify-operation attribute
  15. //
  16. const TCHAR c_szModOp[] = { TEXT ('s'), TEXT ('m'), TEXT ('o'), TEXT ('d'),
  17. TEXT ('o'), TEXT ('p'), TEXT ('\0'),
  18. TEXT ('0'), TEXT ('\0')}; //TEXT ("smodop\0000");
  19. ULONG g_cbUserPrefix = sizeof (c_szModOp);
  20. TCHAR *g_pszUserPrefix = NULL;
  21. ULONG g_cbMtgPrefix = sizeof (c_szModOp);
  22. TCHAR *g_pszMtgPrefix = NULL;
  23. CPing *g_pPing = NULL;
  24. HRESULT
  25. IlsInitialize ( VOID )
  26. {
  27. // Allocate the ping object
  28. //
  29. g_pPing = new CPing;
  30. if (g_pPing == NULL)
  31. return ILS_E_MEMORY;
  32. // Allocate user prefix
  33. //
  34. g_pszUserPrefix = (TCHAR *) MemAlloc (g_cbUserPrefix);
  35. if (g_pszUserPrefix == NULL)
  36. return ILS_E_MEMORY;
  37. // Fill in user prefix string
  38. //
  39. TCHAR *psz = g_pszUserPrefix;
  40. lstrcpy (psz, &c_szModOp[0]);
  41. psz += lstrlen (psz) + 1;
  42. lstrcpy (psz, TEXT ("0"));
  43. // Allocate mtg prefix
  44. //
  45. g_pszMtgPrefix = (TCHAR *) MemAlloc (g_cbMtgPrefix);
  46. if (g_pszMtgPrefix == NULL)
  47. {
  48. MemFree (g_pszUserPrefix);
  49. g_pszUserPrefix = NULL;
  50. return ILS_E_MEMORY;
  51. }
  52. // Fill in mtg prefix string
  53. //
  54. psz = g_pszMtgPrefix;
  55. lstrcpy (psz, &c_szModOp[0]);
  56. psz += lstrlen (psz) + 1;
  57. lstrcpy (psz, TEXT ("0"));
  58. return S_OK;
  59. }
  60. HRESULT
  61. IlsCleanup ( VOID )
  62. {
  63. // Free the ping object
  64. //
  65. if (g_pPing != NULL)
  66. {
  67. delete g_pPing;
  68. g_pPing = NULL;
  69. }
  70. // Free user prefix string
  71. //
  72. MemFree (g_pszUserPrefix);
  73. g_pszUserPrefix = NULL;
  74. // Free mtg prefix string
  75. //
  76. MemFree (g_pszMtgPrefix);
  77. g_pszMtgPrefix = NULL;
  78. return S_OK;
  79. }
  80. ULONG
  81. IlsCalcModifyListSize ( ULONG cAttrs )
  82. {
  83. ULONG cbSize;
  84. // array itself
  85. cbSize = (cAttrs + 1) * sizeof (LDAPMod *);
  86. // array elements
  87. cbSize += cAttrs * sizeof (LDAPMod);
  88. // single valued attribute requires two pointers
  89. cbSize += cAttrs * 2 * sizeof (TCHAR *);
  90. return cbSize;
  91. }
  92. LDAPMod *
  93. IlsGetModifyListMod ( LDAPMod ***pppMod, ULONG cAttrs, LONG AttrIdx )
  94. {
  95. return (LDAPMod *) (((BYTE *) *pppMod) +
  96. (cAttrs + 1) * sizeof (LDAPMod *) +
  97. AttrIdx * (sizeof (LDAPMod) + 2 * sizeof (TCHAR *)));
  98. }
  99. VOID
  100. IlsFillModifyListItem (
  101. LDAPMod *pMod,
  102. TCHAR *pszAttrName,
  103. TCHAR *pszAttrValue )
  104. {
  105. MyAssert (pMod != NULL);
  106. MyAssert (pszAttrName != NULL);
  107. // Set attribute name
  108. //
  109. pMod->mod_type = pszAttrName;
  110. // Set single valued attribute value
  111. //
  112. TCHAR **ppsz = (TCHAR **) (pMod + 1);
  113. pMod->mod_values = ppsz;
  114. *ppsz++ = (pszAttrValue != NULL) ? pszAttrValue : STR_EMPTY;
  115. // Set null string to terminate this array of values
  116. //
  117. *ppsz = NULL;
  118. }
  119. VOID
  120. IlsFillModifyListForAnyAttrs (
  121. LDAPMod *apMod[],
  122. ULONG *puIndex,
  123. ANY_ATTRS *pAnyAttrs )
  124. {
  125. LDAPMod *pMod;
  126. TCHAR *pszName, *pszValue;
  127. ULONG i = *puIndex, j;
  128. // Put in extended attributes to add
  129. //
  130. pszName = pAnyAttrs->pszAttrsToAdd;
  131. for (j = 0; j < pAnyAttrs->cAttrsToAdd; j++)
  132. {
  133. pMod = apMod[i++];
  134. pMod->mod_op = LDAP_MOD_ADD;
  135. pszValue = pszName + lstrlen (pszName) + 1;
  136. IlsFillModifyListItem (pMod, pszName, pszValue);
  137. pszName = pszValue + lstrlen (pszValue) + 1;
  138. }
  139. // Put in extended attributes to modify
  140. //
  141. pszName = pAnyAttrs->pszAttrsToModify;
  142. for (j = 0; j < pAnyAttrs->cAttrsToModify; j++)
  143. {
  144. pMod = apMod[i++];
  145. pMod->mod_op = LDAP_MOD_REPLACE;
  146. pszValue = pszName + lstrlen (pszName) + 1;
  147. IlsFillModifyListItem (pMod, pszName, pszValue);
  148. pszName = pszValue + lstrlen (pszValue) + 1;
  149. }
  150. // Put in extended attributes to remove
  151. //
  152. pszName = pAnyAttrs->pszAttrsToRemove;
  153. for (j = 0; j < pAnyAttrs->cAttrsToRemove; j++)
  154. {
  155. pMod = apMod[i++];
  156. pMod->mod_op = LDAP_MOD_DELETE;
  157. IlsFillModifyListItem (pMod, pszName, NULL);
  158. pszName = pszName + lstrlen (pszName) + 1;
  159. }
  160. // Return the running index
  161. //
  162. *puIndex = i;
  163. }
  164. TCHAR c_szModOp_AddApp[] = TEXT ("0");
  165. TCHAR c_szModOp_DeleteApp[] = TEXT ("1");
  166. TCHAR c_szModOp_ModifyUser[] = TEXT ("2");
  167. TCHAR c_szModOp_ModifyApp[] = TEXT ("3");
  168. VOID
  169. IlsFixUpModOp ( LDAPMod *pMod, LONG LdapModOp, LONG IsbuModOp )
  170. {
  171. MyAssert (pMod != NULL);
  172. pMod->mod_op = LdapModOp;
  173. // pMod->mod_op = LDAP_MOD_ADD; // lonchanc: MUST MUST MUST
  174. pMod->mod_type = (TCHAR *) &c_szModOp[0];
  175. pMod->mod_values = (TCHAR **) (pMod + 1);
  176. switch (IsbuModOp)
  177. {
  178. case ISBU_MODOP_ADD_APP:
  179. *(pMod->mod_values) = &c_szModOp_AddApp[0];
  180. break;
  181. case ISBU_MODOP_DELETE_APP:
  182. *(pMod->mod_values) = &c_szModOp_DeleteApp[0];
  183. break;
  184. case ISBU_MODOP_MODIFY_USER:
  185. *(pMod->mod_values) = &c_szModOp_ModifyUser[0];
  186. break;
  187. case ISBU_MODOP_MODIFY_APP:
  188. *(pMod->mod_values) = &c_szModOp_ModifyApp[0];
  189. break;
  190. default:
  191. MyAssert (FALSE);
  192. break;
  193. }
  194. }
  195. HRESULT
  196. IlsParseRefreshPeriod (
  197. LDAP *ld,
  198. LDAPMessage *pLdapMsg,
  199. const TCHAR *pszTtlAttrName,
  200. ULONG *puTTL )
  201. {
  202. MyAssert (ld != NULL);
  203. MyAssert (pLdapMsg != NULL);
  204. MyAssert (pszTtlAttrName != NULL);
  205. MyAssert (puTTL != NULL);
  206. HRESULT hr;
  207. ULONG uRefreshPeriod;
  208. ULONG tcRefreshPeriod;
  209. // Get the first entry
  210. //
  211. LDAPMessage *pEntry = ldap_first_entry (ld, pLdapMsg);
  212. if (pEntry == NULL)
  213. {
  214. MyAssert (FALSE);
  215. hr = ILS_E_MEMORY;
  216. goto MyExit;
  217. }
  218. // Get the sTTL attribute
  219. //
  220. TCHAR **ppszAttrVal;
  221. ppszAttrVal = my_ldap_get_values (ld, pEntry, (TCHAR *) pszTtlAttrName);
  222. if (ppszAttrVal == NULL || *ppszAttrVal == NULL)
  223. {
  224. MyAssert (FALSE);
  225. hr = ILS_E_MEMORY;
  226. goto MyExit;
  227. }
  228. // Convert string to long
  229. //
  230. uRefreshPeriod = ::GetStringLong (*ppszAttrVal);
  231. // Reserve two-minute overhead
  232. //
  233. if (uRefreshPeriod > ILS_DEF_REFRESH_MARGIN_MINUTE)
  234. uRefreshPeriod -= ILS_DEF_REFRESH_MARGIN_MINUTE;
  235. // Make sure we have a safe, reasonable refresh period at least
  236. //
  237. if (uRefreshPeriod < ILS_DEF_REFRESH_MARGIN_MINUTE)
  238. uRefreshPeriod = ILS_DEF_REFRESH_MARGIN_MINUTE;
  239. // Convert min to ms
  240. //
  241. tcRefreshPeriod = Minute2TickCount (uRefreshPeriod);
  242. // Free the attribute value
  243. //
  244. ldap_value_free (ppszAttrVal);
  245. // Update ttl
  246. //
  247. *puTTL = uRefreshPeriod; // in unit of minute
  248. hr = S_OK;
  249. MyExit:
  250. if (hr != S_OK)
  251. {
  252. MyAssert (FALSE);
  253. }
  254. return hr;
  255. }
  256. HRESULT
  257. IlsUpdateOneAttr (
  258. SERVER_INFO *pServerInfo,
  259. TCHAR *pszDN,
  260. TCHAR *pszAttrName,
  261. TCHAR *pszAttrValue,
  262. LONG nModifyMagic,
  263. ULONG cPrefix,
  264. TCHAR *pszPrefix,
  265. SP_CSession **ppSession, // output
  266. ULONG *puMsgID ) // output
  267. {
  268. MyAssert (pServerInfo != NULL);
  269. MyAssert (pszDN != NULL);
  270. MyAssert (pszAttrName != NULL);
  271. MyAssert (pszAttrValue != NULL);
  272. MyAssert ( nModifyMagic == ISBU_MODOP_MODIFY_USER ||
  273. nModifyMagic == ISBU_MODOP_MODIFY_APP);
  274. MyAssert (ppSession != NULL);
  275. MyAssert (puMsgID != NULL);
  276. // Build modify array for ldap_modify()
  277. //
  278. LDAP *ld;
  279. LDAPMod **ppMod = NULL;
  280. ULONG cTotal = 0;
  281. HRESULT hr = IlsFillDefStdAttrsModArr (&ppMod,
  282. 1, // one attribute (i.e. IP addr)
  283. 1, // max? there is only one attr, come on
  284. &cTotal,
  285. nModifyMagic,
  286. cPrefix,
  287. pszPrefix);
  288. if (hr != S_OK)
  289. goto MyExit;
  290. // Fill in modify list
  291. //
  292. MyAssert (ppMod != NULL);
  293. LDAPMod *pMod;
  294. pMod = ppMod[cPrefix];
  295. MyAssert (pMod != NULL);
  296. pMod->mod_type = pszAttrName;
  297. // Put in ip address
  298. //
  299. pMod->mod_values = (TCHAR **) (pMod + 1);
  300. *(pMod->mod_values) = pszAttrValue;
  301. // Get the session object
  302. //
  303. hr = g_pSessionContainer->GetSession (ppSession, pServerInfo, FALSE);
  304. if (hr != S_OK)
  305. goto MyExit;
  306. MyAssert (*ppSession != NULL);
  307. // Get the ldap session
  308. //
  309. ld = (*ppSession)->GetLd ();
  310. MyAssert (ld != NULL);
  311. // Send the data over the wire
  312. //
  313. *puMsgID = ldap_modify (ld, pszDN, ppMod);
  314. if (*puMsgID == -1)
  315. {
  316. hr = ::LdapError2Hresult (ld->ld_errno);
  317. (*ppSession)->Disconnect ();
  318. goto MyExit;
  319. }
  320. // Success
  321. //
  322. hr = S_OK;
  323. MyExit:
  324. MemFree (ppMod);
  325. return hr;
  326. }
  327. HRESULT
  328. IlsUpdateIPAddress (
  329. SERVER_INFO *pServerInfo,
  330. TCHAR *pszDN,
  331. TCHAR *pszIPAddrName,
  332. TCHAR *pszIPAddrValue,
  333. LONG nModifyMagic,
  334. ULONG cPrefix,
  335. TCHAR *pszPrefix )
  336. {
  337. SP_CSession *pSession = NULL;
  338. LDAP *ld;
  339. ULONG uMsgID;
  340. // Update the ip address attribute on the server
  341. //
  342. HRESULT hr = IlsUpdateOneAttr ( pServerInfo,
  343. pszDN,
  344. pszIPAddrName,
  345. pszIPAddrValue,
  346. nModifyMagic,
  347. cPrefix,
  348. pszPrefix,
  349. &pSession,
  350. &uMsgID);
  351. if (hr != S_OK)
  352. return hr;
  353. // Get the ldap session
  354. //
  355. MyAssert (pSession != NULL);
  356. ld = pSession->GetLd ();
  357. MyAssert (ld != NULL);
  358. // Let's wait for the result
  359. //
  360. LDAP_TIMEVAL TimeVal;
  361. TimeVal.tv_usec = 0;
  362. TimeVal.tv_sec = pSession->GetServerTimeoutInSecond ();
  363. // We don't care the result.
  364. // Should it fails, nothing we can do.
  365. // We can try it again in next keep alive time.
  366. //
  367. LDAPMessage *pLdapMsg;
  368. pLdapMsg = NULL;
  369. ldap_result (ld, uMsgID, LDAP_MSG_ALL, &TimeVal, &pLdapMsg);
  370. // Free message
  371. //
  372. if (pLdapMsg != NULL)
  373. ldap_msgfree (pLdapMsg);
  374. // Free up the session
  375. //
  376. if (pSession != NULL)
  377. pSession->Disconnect ();
  378. return S_OK;
  379. }
  380. HRESULT
  381. IlsSendRefreshMsg (
  382. SERVER_INFO *pServerInfo,
  383. TCHAR *pszBaseDN,
  384. TCHAR *pszTTL,
  385. TCHAR *pszRefreshFilter,
  386. ULONG *puTTL )
  387. {
  388. MyAssert (pServerInfo != NULL);
  389. MyAssert (MyIsGoodString (pszBaseDN));
  390. MyAssert (MyIsGoodString (pszTTL));
  391. MyAssert (MyIsGoodString (pszRefreshFilter));
  392. MyAssert (puTTL != NULL);
  393. // Let's check to see if we need to use Ping...
  394. //
  395. if (g_pPing != NULL && g_pPing->IsAutodialEnabled ())
  396. {
  397. LPTSTR pszServerName = My_strdup(pServerInfo->pszServerName);
  398. if (NULL == pszServerName)
  399. {
  400. return E_OUTOFMEMORY;
  401. }
  402. LPTSTR pszSeparator = My_strchr(pszServerName, _T(':'));
  403. if (NULL != pszSeparator)
  404. {
  405. *pszSeparator = _T('\0');
  406. }
  407. DWORD dwIPAddr = inet_addr (pszServerName);
  408. MemFree(pszServerName);
  409. if (dwIPAddr != INADDR_NONE)
  410. {
  411. if (g_pPing->Ping (dwIPAddr, 10 * 1000, 9) == S_FALSE)
  412. {
  413. MyDebugMsg ((ZONE_KA, "KA: ping failed, network down\r\n"));
  414. // The "ping" operation failed, but other operations failed
  415. //
  416. return ILS_E_NETWORK_DOWN;
  417. }
  418. }
  419. }
  420. // Get the connection object
  421. //
  422. SP_CSession *pSession = NULL;
  423. HRESULT hr = g_pSessionContainer->GetSession (&pSession, pServerInfo, FALSE);
  424. if (hr != S_OK)
  425. {
  426. MyDebugMsg ((ZONE_KA, "KA: network down, hr=0x%lX\r\n", hr));
  427. // Report error
  428. //
  429. return ILS_E_NETWORK_DOWN;
  430. }
  431. MyAssert (pSession != NULL);
  432. // Get the ldap session
  433. //
  434. LDAP *ld = pSession->GetLd ();
  435. MyAssert (ld != NULL);
  436. // Set attributes to return
  437. //
  438. TCHAR *apszAttrNames[2];
  439. apszAttrNames[0] = pszTTL;
  440. apszAttrNames[1] = NULL;
  441. // Update options in ld
  442. //
  443. ld->ld_sizelimit = 0; // no limit in the num of entries to return
  444. ld->ld_timelimit = 0; // no limit on the time to spend on the search
  445. ld->ld_deref = LDAP_DEREF_ALWAYS;
  446. // Send search query
  447. //
  448. MyDebugMsg ((ZONE_KA, "KA: calling ldap_search()...\r\n"));
  449. ULONG uMsgID = ::ldap_search ( ld,
  450. pszBaseDN, // base DN
  451. LDAP_SCOPE_BASE, // scope
  452. pszRefreshFilter, // filter
  453. &apszAttrNames[0], // attrs[]
  454. 0); // both type and value
  455. if (uMsgID == -1)
  456. {
  457. MyDebugMsg ((ZONE_KA, "KA: ldap_search() failed\r\n"));
  458. hr = ::LdapError2Hresult (ld->ld_errno);
  459. pSession->Disconnect ();
  460. return hr;
  461. }
  462. // Let's wait for the result
  463. //
  464. LDAP_TIMEVAL TimeVal;
  465. TimeVal.tv_usec = 0;
  466. TimeVal.tv_sec = pSession->GetServerTimeoutInSecond ();
  467. // Wait and get the result back
  468. //
  469. LDAPMessage *pLdapMsg = NULL;
  470. INT ResultType = ::ldap_result (ld, uMsgID, LDAP_MSG_ALL, &TimeVal, &pLdapMsg);
  471. if (ResultType == LDAP_RES_SEARCH_ENTRY ||
  472. ResultType == LDAP_RES_SEARCH_RESULT)
  473. {
  474. if (pLdapMsg != NULL)
  475. {
  476. switch (pLdapMsg->lm_returncode)
  477. {
  478. case LDAP_NO_SUCH_OBJECT:
  479. MyDebugMsg ((ZONE_KA, "KA: no such object!\r\n"));
  480. // Report error
  481. //
  482. hr = ILS_E_NEED_RELOGON;
  483. break;
  484. case LDAP_SUCCESS:
  485. // Get the new refresh period
  486. //
  487. hr = ::IlsParseRefreshPeriod (ld, pLdapMsg, pszTTL, puTTL);
  488. break;
  489. default:
  490. MyDebugMsg ((ZONE_KA, "KA: unknown lm_returncode=%ld\r\n", pLdapMsg->lm_returncode));
  491. MyAssert (FALSE);
  492. hr = ::LdapError2Hresult (ld->ld_errno);
  493. break;
  494. }
  495. // Free this message
  496. //
  497. ldap_msgfree (pLdapMsg);
  498. } // if (pLdapMsg != NULL)
  499. else
  500. {
  501. hr = ILS_E_FAIL;
  502. }
  503. } // not timeout
  504. else
  505. {
  506. // Timeout
  507. //
  508. hr = ILS_E_TIMEOUT;
  509. }
  510. // Free up the session
  511. //
  512. pSession->Disconnect ();
  513. return hr;
  514. }
  515. HRESULT
  516. IlsFillDefStdAttrsModArr (
  517. LDAPMod ***pppMod,
  518. DWORD dwFlags,
  519. ULONG cMaxAttrs,
  520. ULONG *pcTotal, // in/out parameter!!!
  521. LONG IsbuModOp,
  522. ULONG cPrefix,
  523. TCHAR *pszPrefix )
  524. {
  525. MyAssert (pppMod != NULL);
  526. MyAssert (pcTotal != NULL);
  527. MyAssert ( (cPrefix == 0 && pszPrefix == NULL) ||
  528. (cPrefix != 0 && pszPrefix != NULL));
  529. // Figure out the num of attributes
  530. //
  531. ULONG cAttrs = 0;
  532. for (ULONG i = 0; i < cMaxAttrs; i++)
  533. {
  534. if (dwFlags & 0x01)
  535. cAttrs++;
  536. dwFlags >>= 1;
  537. }
  538. // Allocate modify list
  539. //
  540. ULONG cTotal = *pcTotal + cPrefix + cAttrs;
  541. ULONG cbMod = IlsCalcModifyListSize (cTotal);
  542. *pppMod = (LDAPMod **) MemAlloc (cbMod);
  543. if (*pppMod == NULL)
  544. return ILS_E_MEMORY;
  545. // Fill in the modify list
  546. //
  547. LDAPMod *pMod;
  548. for (i = 0; i < cTotal; i++)
  549. {
  550. pMod = IlsGetModifyListMod (pppMod, cTotal, i);
  551. (*pppMod)[i] = pMod;
  552. pMod->mod_values = (TCHAR **) (pMod + 1);
  553. if (i < cPrefix)
  554. {
  555. pMod->mod_op = LDAP_MOD_REPLACE;
  556. pMod->mod_type = pszPrefix;
  557. pszPrefix += lstrlen (pszPrefix) + 1;
  558. *(pMod->mod_values) = pszPrefix;
  559. pszPrefix += lstrlen (pszPrefix) + 1;
  560. }
  561. }
  562. // Fix up the first and the last ones
  563. //
  564. IlsFixUpModOp ((*pppMod)[0], LDAP_MOD_REPLACE, IsbuModOp);
  565. (*pppMod)[cTotal] = NULL;
  566. // Return the total number of entries
  567. //
  568. *pcTotal = cTotal;
  569. return S_OK;
  570. }
  571. const TCHAR c_szAnyAttrPrefix[] = TEXT ("ILSA");
  572. #define SIZE_ANY_ATTR_PREFIX (sizeof (c_szAnyAttrPrefix) / sizeof (TCHAR))
  573. const TCHAR *
  574. UlsLdap_GetExtAttrNamePrefix ( VOID )
  575. {
  576. return &c_szAnyAttrPrefix[0];
  577. }
  578. const TCHAR *
  579. IlsSkipAnyAttrNamePrefix ( const TCHAR *pszAttrName )
  580. {
  581. MyAssert (pszAttrName != NULL);
  582. const TCHAR *psz = IlsIsAnyAttrName (pszAttrName);
  583. if (psz == NULL)
  584. {
  585. MyAssert (FALSE);
  586. psz = pszAttrName;
  587. }
  588. return psz;
  589. }
  590. const TCHAR *
  591. IlsIsAnyAttrName ( const TCHAR *pszAttrName )
  592. {
  593. BOOL fRet = FALSE;
  594. TCHAR *psz = (TCHAR *) pszAttrName;
  595. if (pszAttrName != NULL)
  596. {
  597. if (lstrlen (pszAttrName) > SIZE_ANY_ATTR_PREFIX)
  598. {
  599. TCHAR c = pszAttrName[SIZE_ANY_ATTR_PREFIX-1];
  600. psz[SIZE_ANY_ATTR_PREFIX-1] = TEXT ('\0');
  601. fRet = (My_lstrcmpi (pszAttrName, &c_szAnyAttrPrefix[0]) == 0);
  602. psz[SIZE_ANY_ATTR_PREFIX-1] = c;
  603. }
  604. }
  605. return (fRet ? &pszAttrName[SIZE_ANY_ATTR_PREFIX-1] : NULL);
  606. }
  607. TCHAR *
  608. IlsPrefixNameValueArray (
  609. BOOL fPair,
  610. ULONG cAttrs,
  611. const TCHAR *pszAttrs )
  612. {
  613. if (cAttrs == 0 || pszAttrs == NULL)
  614. {
  615. MyAssert (FALSE);
  616. return NULL;
  617. }
  618. // compute the total size required
  619. ULONG cbTotalSize = 0;
  620. ULONG cbThisSize;
  621. TCHAR *pszSrc = (TCHAR *) pszAttrs;
  622. for (ULONG i = 0; i < cAttrs; i++)
  623. {
  624. // get name size
  625. cbThisSize = lstrlen (pszSrc) + 1;
  626. pszSrc += lstrlen (pszSrc) + 1;
  627. // get value size as needed
  628. if (fPair)
  629. {
  630. cbThisSize += lstrlen (pszSrc) + 1;
  631. pszSrc += lstrlen (pszSrc) + 1;
  632. }
  633. // adjust the size
  634. cbThisSize += SIZE_ANY_ATTR_PREFIX;
  635. cbThisSize *= sizeof (TCHAR);
  636. // accumulate it
  637. cbTotalSize += cbThisSize;
  638. }
  639. // allocate the new buffer
  640. TCHAR *pszPrefixAttrs = (TCHAR *) MemAlloc (cbTotalSize);
  641. if (pszPrefixAttrs == NULL)
  642. return NULL;
  643. // copy the strings over to the new buffer
  644. pszSrc = (TCHAR *) pszAttrs;
  645. TCHAR *pszDst = pszPrefixAttrs;
  646. for (i = 0; i < cAttrs; i++)
  647. {
  648. // copy prefix
  649. lstrcpy (pszDst, &c_szAnyAttrPrefix[0]);
  650. pszDst += lstrlen (pszDst); // no plus 1
  651. // copy name
  652. lstrcpy (pszDst, pszSrc);
  653. pszDst += lstrlen (pszDst) + 1;
  654. pszSrc += lstrlen (pszSrc) + 1;
  655. // copy value as needed
  656. if (fPair)
  657. {
  658. lstrcpy (pszDst, pszSrc);
  659. pszDst += lstrlen (pszDst) + 1;
  660. pszSrc += lstrlen (pszSrc) + 1;
  661. }
  662. }
  663. return pszPrefixAttrs;
  664. }
  665. TCHAR *
  666. IlsBuildDN (
  667. TCHAR *pszBaseDN,
  668. TCHAR *pszC,
  669. TCHAR *pszO,
  670. TCHAR *pszCN,
  671. TCHAR *pszObjectClass )
  672. {
  673. MyAssert (MyIsGoodString (pszCN));
  674. MyAssert (MyIsGoodString (pszObjectClass));
  675. static TCHAR s_szC[] = TEXT ("c=");
  676. static TCHAR s_szO[] = TEXT ("o=");
  677. static TCHAR s_szCN[] = TEXT ("cn=");
  678. static TCHAR s_szObjectClass[] = TEXT ("objectClass=");
  679. static TCHAR s_szDelimiter[] = TEXT (", ");
  680. enum { C_LENGTH = 2 };
  681. enum { O_LENGTH = 2 };
  682. enum { CN_LENGTH = 3 };
  683. enum { OBJECTCLASS_LENGTH = 12 };
  684. enum { DELIMITER_LENGTH = 2 };
  685. ULONG cchDN = 1;
  686. BOOL fInBaseDN;
  687. ASSERT(MyIsGoodString(pszC));
  688. cchDN += lstrlen (pszC) + DELIMITER_LENGTH + C_LENGTH;
  689. if (MyIsGoodString (pszBaseDN))
  690. {
  691. fInBaseDN = TRUE;
  692. cchDN += lstrlen (pszBaseDN) + DELIMITER_LENGTH;
  693. }
  694. else
  695. {
  696. fInBaseDN = FALSE;
  697. if (MyIsGoodString (pszO))
  698. cchDN += lstrlen (pszO) + DELIMITER_LENGTH + O_LENGTH;
  699. }
  700. if (MyIsGoodString (pszCN))
  701. cchDN += lstrlen (pszCN) + CN_LENGTH;
  702. if (MyIsGoodString (pszObjectClass))
  703. cchDN += lstrlen (pszObjectClass) + DELIMITER_LENGTH + OBJECTCLASS_LENGTH;
  704. TCHAR *pszDN = (TCHAR *) MemAlloc (cchDN * sizeof (TCHAR));
  705. if (pszDN != NULL)
  706. {
  707. TCHAR *psz = pszDN;
  708. psz[0] = TEXT ('\0');
  709. if (MyIsGoodString (pszC))
  710. {
  711. lstrcpy (psz, &s_szC[0]);
  712. psz += lstrlen (psz);
  713. lstrcpy (psz, pszC);
  714. psz += lstrlen (psz);
  715. }
  716. if (fInBaseDN)
  717. {
  718. if (psz != pszDN)
  719. {
  720. lstrcpy (psz, &s_szDelimiter[0]);
  721. psz += lstrlen (psz);
  722. }
  723. lstrcpy (psz, pszBaseDN);
  724. psz += lstrlen (psz);
  725. }
  726. else
  727. {
  728. if (MyIsGoodString (pszO))
  729. {
  730. if (psz != pszDN)
  731. {
  732. lstrcpy (psz, &s_szDelimiter[0]);
  733. psz += lstrlen (psz);
  734. }
  735. lstrcpy (psz, &s_szO[0]);
  736. psz += lstrlen (psz);
  737. lstrcpy (psz, pszO);
  738. psz += lstrlen (psz);
  739. }
  740. }
  741. if (MyIsGoodString (pszCN))
  742. {
  743. if (psz != pszDN)
  744. {
  745. lstrcpy (psz, &s_szDelimiter[0]);
  746. psz += lstrlen (psz);
  747. }
  748. lstrcpy (psz, &s_szCN[0]);
  749. psz += lstrlen (psz);
  750. lstrcpy (psz, pszCN);
  751. psz += lstrlen (psz);
  752. }
  753. if (MyIsGoodString (pszObjectClass))
  754. {
  755. if (psz != pszDN)
  756. {
  757. lstrcpy (psz, &s_szDelimiter[0]);
  758. psz += lstrlen (psz);
  759. }
  760. lstrcpy (psz, &s_szObjectClass[0]);
  761. psz += lstrlen (psz);
  762. lstrcpy (psz, pszObjectClass);
  763. psz += lstrlen (psz);
  764. }
  765. MyAssert (psz == pszDN + cchDN - 1);
  766. }
  767. return pszDN;
  768. }
  769. HRESULT
  770. IlsCreateAnyAttrsPrefix ( ANY_ATTRS *pAnyAttrs )
  771. {
  772. if (pAnyAttrs->cAttrsToAdd != 0)
  773. {
  774. MyAssert (pAnyAttrs->pszAttrsToAdd != NULL);
  775. pAnyAttrs->pszAttrsToAdd = IlsPrefixNameValueArray (
  776. TRUE,
  777. pAnyAttrs->cAttrsToAdd,
  778. (const TCHAR *) pAnyAttrs->pszAttrsToAdd);
  779. if (pAnyAttrs->pszAttrsToAdd == NULL)
  780. return ILS_E_MEMORY;
  781. }
  782. if (pAnyAttrs->cAttrsToModify != 0)
  783. {
  784. MyAssert (pAnyAttrs->pszAttrsToModify != NULL);
  785. pAnyAttrs->pszAttrsToModify = IlsPrefixNameValueArray (
  786. TRUE,
  787. pAnyAttrs->cAttrsToModify,
  788. (const TCHAR *) pAnyAttrs->pszAttrsToModify);
  789. if (pAnyAttrs->pszAttrsToModify == NULL)
  790. {
  791. MemFree (pAnyAttrs->pszAttrsToAdd);
  792. pAnyAttrs->pszAttrsToAdd = NULL;
  793. return ILS_E_MEMORY;
  794. }
  795. }
  796. if (pAnyAttrs->cAttrsToRemove != 0)
  797. {
  798. MyAssert (pAnyAttrs->pszAttrsToRemove != NULL);
  799. pAnyAttrs->pszAttrsToRemove = IlsPrefixNameValueArray (
  800. FALSE,
  801. pAnyAttrs->cAttrsToRemove,
  802. (const TCHAR *) pAnyAttrs->pszAttrsToRemove);
  803. if (pAnyAttrs->pszAttrsToRemove == NULL)
  804. {
  805. MemFree (pAnyAttrs->pszAttrsToAdd);
  806. MemFree (pAnyAttrs->pszAttrsToModify);
  807. pAnyAttrs->pszAttrsToAdd = NULL;
  808. pAnyAttrs->pszAttrsToModify = NULL;
  809. return ILS_E_MEMORY;
  810. }
  811. }
  812. return S_OK;
  813. }
  814. VOID
  815. IlsReleaseAnyAttrsPrefix ( ANY_ATTRS *pAnyAttrs )
  816. {
  817. MemFree (pAnyAttrs->pszAttrsToAdd);
  818. MemFree (pAnyAttrs->pszAttrsToModify);
  819. MemFree (pAnyAttrs->pszAttrsToRemove);
  820. ZeroMemory (pAnyAttrs, sizeof (*pAnyAttrs));
  821. }
  822. TCHAR **my_ldap_get_values ( LDAP *ld, LDAPMessage *pEntry, TCHAR *pszRetAttrName )
  823. {
  824. MyAssert (ld != NULL);
  825. MyAssert (pEntry != NULL);
  826. MyAssert (pszRetAttrName != NULL);
  827. // Examine the first attribute
  828. //
  829. struct berelement *pContext = NULL;
  830. TCHAR *pszAttrName = ldap_first_attribute (ld, pEntry, &pContext);
  831. if (My_lstrcmpi (pszAttrName, pszRetAttrName) != 0)
  832. {
  833. // Examine the other attributes
  834. //
  835. while ((pszAttrName = ldap_next_attribute (ld, pEntry, pContext))
  836. != NULL)
  837. {
  838. if (My_lstrcmpi (pszAttrName, pszRetAttrName) == 0)
  839. break;
  840. }
  841. }
  842. // Get the attribute value if needed
  843. //
  844. TCHAR **ppszAttrValue = NULL;
  845. if (pszAttrName != NULL)
  846. ppszAttrValue = ldap_get_values (ld, pEntry, pszAttrName);
  847. return ppszAttrValue;
  848. }
  849. ULONG my_ldap_count_1st_entry_attributes ( LDAP *ld, LDAPMessage *pLdapMsg )
  850. {
  851. MyAssert (ld != NULL);
  852. MyAssert (pLdapMsg != NULL);
  853. ULONG cAttrs = 0;
  854. // there should be only an entry
  855. ULONG cEntries = ldap_count_entries (ld, pLdapMsg);
  856. if (cEntries > 0)
  857. {
  858. // there should be only one entry
  859. MyAssert (cEntries == 1);
  860. TCHAR *pszAttrName;
  861. // get this entry
  862. LDAPMessage *pEntry = ldap_first_entry (ld, pLdapMsg);
  863. if (pEntry == NULL)
  864. {
  865. MyAssert (FALSE);
  866. return cAttrs;
  867. }
  868. // examine the first attribute
  869. struct berelement *pContext = NULL;
  870. pszAttrName = ldap_first_attribute (ld, pEntry, &pContext);
  871. if (pszAttrName == NULL)
  872. {
  873. MyAssert (FALSE);
  874. return 0;
  875. }
  876. cAttrs = 1;
  877. TCHAR **ppszAttrVal;
  878. ppszAttrVal = ldap_get_values (ld, pEntry, pszAttrName);
  879. if (ppszAttrVal != NULL)
  880. ldap_value_free (ppszAttrVal);
  881. // step through the others
  882. while ((pszAttrName = ldap_next_attribute (ld, pEntry, pContext)) != NULL)
  883. {
  884. cAttrs++;
  885. ppszAttrVal = ldap_get_values (ld, pEntry, pszAttrName);
  886. if (ppszAttrVal != NULL)
  887. ldap_value_free (ppszAttrVal);
  888. }
  889. } // if cEntries > 0
  890. return cAttrs;
  891. }