ldapauth.c 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /*
  42. * ldapauth.cpp: Implements LDAP integration in the web server.
  43. *
  44. * Nitin More, John Kristian
  45. */
  46. /* #define DBG_PRINT */
  47. #include <stdio.h> /* for BUFSIZ */
  48. #include <string.h> /* for strncpy, strcat */
  49. #include <ldap.h>
  50. #include <prprf.h>
  51. #include <ldaputil/certmap.h>
  52. #include <ldaputil/errors.h>
  53. #include <ldaputil/ldapauth.h>
  54. #include <ldaputili.h>
  55. /* If we are not interested in the returned attributes, just ask for one
  56. * attribute in the call to ldap_search. Also don't ask for the attribute
  57. * value -- just the attr.
  58. */
  59. static const char *default_search_attrs[] = { "c" , 0 };
  60. static int default_search_attrsonly = 1;
  61. /*
  62. * ldapu_find
  63. * Description:
  64. * Caller should free res if it is not NULL.
  65. * Arguments:
  66. * ld Pointer to LDAP (assumes connection has been
  67. * established and the client has called the
  68. * appropriate bind routine)
  69. * base basedn (where to start the search)
  70. * scope scope for the search. One of
  71. * LDAP_SCOPE_SUBTREE, LDAP_SCOPE_ONELEVEL, and
  72. * LDAP_SCOPE_BASE
  73. * filter LDAP filter
  74. * attrs A NULL-terminated array of strings indicating which
  75. * attributes to return for each matching entry. Passing
  76. * NULL for this parameter causes all available
  77. * attributes to be retrieved.
  78. * attrsonly A boolean value that should be zero if both attribute
  79. * types and values are to be returned, non-zero if only
  80. * types are wanted.
  81. * res A result parameter which will contain the results of
  82. * the search upon completion of the call.
  83. * Return Values:
  84. * LDAPU_SUCCESS if entry is found
  85. * LDAPU_FAILED if entry is not found
  86. * <rv> if error, where <rv> can be passed to
  87. * ldap_err2string to get an error string.
  88. */
  89. int ldapu_find (LDAP *ld, const char *base, int scope,
  90. const char *filter, const char **attrs,
  91. int attrsonly, LDAPMessage **res)
  92. {
  93. int retval;
  94. #ifdef USE_THIS_CODE /* ASYNCHRONOUS */
  95. int msgid;
  96. #endif
  97. int numEntries;
  98. *res = 0;
  99. /* If base is NULL set it to null string */
  100. if (!base) {
  101. DBG_PRINT1("ldapu_find: basedn is missing -- assuming null string\n");
  102. base = "";
  103. }
  104. if (!filter || !*filter) {
  105. DBG_PRINT1("ldapu_find: filter is missing -- assuming objectclass=*\n");
  106. filter = ldapu_strings[LDAPU_STR_FILTER_DEFAULT];
  107. }
  108. DBG_PRINT2("\tbase:\t\"%s\"\n", base);
  109. DBG_PRINT2("\tfilter:\t\"%s\"\n", filter ? filter : "<NULL>");
  110. DBG_PRINT2("\tscope:\t\"%s\"\n",
  111. (scope == LDAP_SCOPE_SUBTREE ? "LDAP_SCOPE_SUBTREE"
  112. : (scope == LDAP_SCOPE_ONELEVEL ? "LDAP_SCOPE_ONELEVEL"
  113. : "LDAP_SCOPE_BASE")));
  114. retval = ldapu_search_s(ld, base, scope, filter, (char **)attrs,
  115. attrsonly, res);
  116. if (retval != LDAP_SUCCESS)
  117. {
  118. /* retval = ldap_result2error(ld, *res, 0); */
  119. DBG_PRINT2("ldapu_search_s: %s\n", ldapu_err2string(retval));
  120. return(retval);
  121. }
  122. numEntries = ldapu_count_entries(ld, *res);
  123. if (numEntries == 1) {
  124. /* success */
  125. return LDAPU_SUCCESS;
  126. }
  127. else if (numEntries == 0) {
  128. /* not found -- but not an error */
  129. DBG_PRINT1("ldapu_search_s: Entry not found\n");
  130. return LDAPU_FAILED;
  131. }
  132. else if (numEntries > 0) {
  133. /* Found more than one entry! */
  134. DBG_PRINT1("ldapu_search_s: Found more than one entry\n");
  135. return LDAPU_ERR_MULTIPLE_MATCHES;
  136. }
  137. else {
  138. /* should never get here */
  139. DBG_PRINT1("ldapu_search_s: should never reach here\n");
  140. ldapu_msgfree(ld, *res);
  141. return LDAP_OPERATIONS_ERROR;
  142. }
  143. }
  144. /* Search function for the cases where base = "" = NULL suffix, that is, search to
  145. * be performed on the entire DIT tree.
  146. * We actually do various searches taking a naming context at a time as the base for
  147. * the search. */
  148. int ldapu_find_entire_tree (LDAP *ld, int scope,
  149. const char *filter, const char **attrs,
  150. int attrsonly, LDAPMessage ***res)
  151. {
  152. int retval = LDAPU_FAILED;
  153. int rv,i, num_namingcontexts;
  154. LDAPMessage *result_entry, *result = NULL;
  155. const char *suffix_attr[2] = {"namingcontexts", NULL};
  156. /* these are private suffixes that may contain pseudo users
  157. e.g. replication manager that may have certs */
  158. int num_private_suffix = 1;
  159. const char *private_suffix_list[2] = {"cn=config", NULL};
  160. char **suffix_list, **suffix = NULL;
  161. rv = ldapu_find(ld, "",LDAP_SCOPE_BASE, "objectclass=*", suffix_attr, 0, &result);
  162. if (rv != LDAP_SUCCESS) {
  163. if (result) ldapu_msgfree(ld, result);
  164. return rv;
  165. }
  166. result_entry = ldapu_first_entry(ld, result);
  167. suffix = ldapu_get_values(ld, result_entry, suffix_attr[0]);
  168. suffix_list = suffix;
  169. num_namingcontexts = ldap_count_values(suffix);
  170. /* add private suffixes to our list of suffixes to search */
  171. if (num_private_suffix) {
  172. suffix_list = ldapu_realloc(suffix_list,
  173. sizeof(char *)*(num_namingcontexts+num_private_suffix+1));
  174. if (!suffix_list) {
  175. if (result) {
  176. ldapu_msgfree(ld, result);
  177. }
  178. retval = LDAPU_FAILED;
  179. return retval;
  180. }
  181. for (i = num_namingcontexts; i < (num_namingcontexts+num_private_suffix); ++i) {
  182. suffix_list[i] = strdup(private_suffix_list[i-num_namingcontexts]);
  183. }
  184. suffix_list[i] = NULL;
  185. num_namingcontexts += num_private_suffix;
  186. suffix = suffix_list;
  187. }
  188. if (result) ldapu_msgfree(ld, result);
  189. result = 0;
  190. i = 0;
  191. /* ugaston - the caller function must remember to free the memory allocated here */
  192. *res = (LDAPMessage **) ldapu_malloc((num_namingcontexts + 1) * sizeof(LDAPMessage *));
  193. while (suffix && *suffix) {
  194. rv = ldapu_find(ld, *suffix, scope, filter, attrs, attrsonly, &result);
  195. if (scope == LDAP_SCOPE_BASE && rv == LDAP_SUCCESS) {
  196. retval = rv;
  197. (*res)[i++] = result;
  198. break;
  199. }
  200. switch (rv) {
  201. case LDAP_SUCCESS:
  202. if (retval == LDAP_SUCCESS) {
  203. retval = LDAPU_ERR_MULTIPLE_MATCHES;
  204. (*res)[i++] = result;
  205. break;
  206. }
  207. case LDAPU_ERR_MULTIPLE_MATCHES:
  208. retval = rv;
  209. (*res)[i++] = result;
  210. break;
  211. default:
  212. if (retval != LDAP_SUCCESS && retval != LDAPU_ERR_MULTIPLE_MATCHES) {
  213. retval = rv;
  214. }
  215. if (result) ldapu_msgfree(ld, result);
  216. result = 0;
  217. break;
  218. }
  219. suffix++;
  220. }
  221. (*res)[i] = NULL;
  222. ldapu_value_free(ld, suffix_list);
  223. return retval;
  224. }
  225. /*
  226. * ldapu_find_uid_attrs
  227. * Description:
  228. * Maps the given uid to a user dn. Caller should free res if it is not
  229. * NULL. Accepts the attrs & attrsonly args.
  230. * Arguments:
  231. * ld Pointer to LDAP (assumes connection has been
  232. * established and the client has called the
  233. * appropriate bind routine)
  234. * uid User's name
  235. * base basedn (where to start the search)
  236. * attrs list of attributes to retrieve
  237. * attrsonly flag indicating if attr values are to be retrieved
  238. * res A result parameter which will contain the results of
  239. * the search upon completion of the call.
  240. * Return Values:
  241. * LDAPU_SUCCESS if entry is found
  242. * LDAPU_FAILED if entry is not found
  243. * <rv> if error, where <rv> can be passed to
  244. * ldap_err2string to get an error string.
  245. */
  246. int ldapu_find_uid_attrs (LDAP *ld, const char *uid, const char *base,
  247. const char **attrs, int attrsonly,
  248. LDAPMessage **res)
  249. {
  250. int scope = LDAP_SCOPE_SUBTREE;
  251. char filter[ BUFSIZ ];
  252. int retval;
  253. /* setup filter as (uid=<uid>) */
  254. PR_snprintf(filter, sizeof(filter), ldapu_strings[LDAPU_STR_FILTER_USER], uid);
  255. retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, res);
  256. return retval;
  257. }
  258. /*
  259. * ldapu_find_uid
  260. * Description:
  261. * Maps the given uid to a user dn. Caller should free res if it is not
  262. * NULL.
  263. * Arguments:
  264. * ld Pointer to LDAP (assumes connection has been
  265. * established and the client has called the
  266. * appropriate bind routine)
  267. * uid User's name
  268. * base basedn (where to start the search)
  269. * res A result parameter which will contain the results of
  270. * the search upon completion of the call.
  271. * Return Values:
  272. * LDAPU_SUCCESS if entry is found
  273. * LDAPU_FAILED if entry is not found
  274. * <rv> if error, where <rv> can be passed to
  275. * ldap_err2string to get an error string.
  276. */
  277. int ldapu_find_uid (LDAP *ld, const char *uid, const char *base,
  278. LDAPMessage **res)
  279. {
  280. const char **attrs = 0; /* get all attributes ... */
  281. int attrsonly = 0; /* ... and their values */
  282. int retval;
  283. retval = ldapu_find_uid_attrs(ld, uid, base, attrs, attrsonly, res);
  284. return retval;
  285. }
  286. /*
  287. * ldapu_find_userdn
  288. * Description:
  289. * Maps the given uid to a user dn. Caller should free dn if it is not
  290. * NULL.
  291. * Arguments:
  292. * ld Pointer to LDAP (assumes connection has been
  293. * established and the client has called the
  294. * appropriate bind routine)
  295. * uid User's name
  296. * base basedn (where to start the search)
  297. * dn user dn
  298. * Return Values:
  299. * LDAPU_SUCCESS if entry is found
  300. * LDAPU_FAILED if entry is not found
  301. * <rv> if error, where <rv> can be passed to
  302. * ldap_err2string to get an error string.
  303. */
  304. int ldapu_find_userdn (LDAP *ld, const char *uid, const char *base,
  305. char **dn)
  306. {
  307. LDAPMessage *res = 0;
  308. int retval;
  309. retval = ldapu_find_uid_attrs(ld, uid, base, default_search_attrs,
  310. default_search_attrsonly, &res);
  311. if (retval == LDAPU_SUCCESS) {
  312. LDAPMessage *entry;
  313. entry = ldapu_first_entry(ld, res);
  314. *dn = ldapu_get_dn(ld, entry);
  315. }
  316. else {
  317. *dn = 0;
  318. }
  319. if (res) ldapu_msgfree(ld, res);
  320. return retval;
  321. }
  322. /*
  323. * ldapu_find_group_attrs
  324. * Description:
  325. * Maps the given groupid to a group dn. Caller should free res if it is
  326. * not NULL. Accepts the attrs & attrsonly args.
  327. * Arguments:
  328. * ld Pointer to LDAP (assumes connection has been
  329. * established and the client has called the
  330. * appropriate bind routine)
  331. * groupid Groups's name
  332. * base basedn (where to start the search)
  333. * attrs list of attributes to retrieve
  334. * attrsonly flag indicating if attr values are to be retrieved
  335. * res A result parameter which will contain the results of
  336. * the search upon completion of the call.
  337. * Return Values:
  338. * LDAPU_SUCCESS if entry is found
  339. * LDAPU_FAILED if entry is not found
  340. * <rv> if error, where <rv> can be passed to
  341. * ldap_err2string to get an error string.
  342. */
  343. int ldapu_find_group_attrs (LDAP *ld, const char *groupid,
  344. const char *base, const char **attrs,
  345. int attrsonly, LDAPMessage **res)
  346. {
  347. int scope = LDAP_SCOPE_SUBTREE;
  348. char filter[ BUFSIZ ];
  349. int retval;
  350. /* setup the filter */
  351. PR_snprintf(filter, sizeof(filter),
  352. ldapu_strings[LDAPU_STR_FILTER_GROUP],
  353. groupid);
  354. retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, res);
  355. return retval;
  356. }
  357. /*
  358. * ldapu_find_group
  359. * Description:
  360. * Maps the given groupid to a group dn. Caller should free res if it is
  361. * not NULL.
  362. * Arguments:
  363. * ld Pointer to LDAP (assumes connection has been
  364. * established and the client has called the
  365. * appropriate bind routine)
  366. * groupid Groups's name
  367. * base basedn (where to start the search)
  368. * res A result parameter which will contain the results of
  369. * the search upon completion of the call.
  370. * Return Values:
  371. * LDAPU_SUCCESS if entry is found
  372. * LDAPU_FAILED if entry is not found
  373. * <rv> if error, where <rv> can be passed to
  374. * ldap_err2string to get an error string.
  375. */
  376. int ldapu_find_group (LDAP *ld, const char *groupid, const char *base,
  377. LDAPMessage **res)
  378. {
  379. const char **attrs = 0; /* get all attributes ... */
  380. int attrsonly = 0; /* ... and their values */
  381. int retval;
  382. retval = ldapu_find_group_attrs (ld, groupid, base, attrs, attrsonly, res);
  383. return retval;
  384. }
  385. /*
  386. * ldapu_find_groupdn
  387. * Description:
  388. * Maps the given groupid to a group dn. Caller should free dn if it is
  389. * not NULL.
  390. * Arguments:
  391. * ld Pointer to LDAP (assumes connection has been
  392. * established and the client has called the
  393. * appropriate bind routine)
  394. * groupid Groups's name
  395. * base basedn (where to start the search)
  396. * dn group dn
  397. * Return Values:
  398. * LDAPU_SUCCESS if entry is found
  399. * LDAPU_FAILED if entry is not found
  400. * <rv> if error, where <rv> can be passed to
  401. * ldap_err2string to get an error string.
  402. */
  403. int ldapu_find_groupdn (LDAP *ld, const char *groupid, const char *base,
  404. char **dn)
  405. {
  406. LDAPMessage *res = 0;
  407. int retval;
  408. retval = ldapu_find_group_attrs(ld, groupid, base, default_search_attrs,
  409. default_search_attrsonly, &res);
  410. if (retval == LDAPU_SUCCESS) {
  411. LDAPMessage *entry;
  412. /* get ldap entry */
  413. entry = ldapu_first_entry(ld, res);
  414. *dn = ldapu_get_dn(ld, entry);
  415. }
  416. else {
  417. *dn = 0;
  418. }
  419. if (res) ldapu_msgfree(ld, res);
  420. return retval;
  421. }
  422. /*
  423. * continuable_err
  424. * Description:
  425. * Returns true for benign errors (i.e. errors for which recursive
  426. * search can continue.
  427. * Return Values:
  428. * 0 (zero) - if not a benign error
  429. * 1 - if a benign error -- search can continue.
  430. */
  431. static int continuable_err (int err)
  432. {
  433. return (err == LDAPU_FAILED);
  434. }
  435. int ldapu_auth_udn_gdn_recurse (LDAP *ld, const char *userdn,
  436. const char *groupdn, const char *base,
  437. int recurse_cnt)
  438. {
  439. char filter[ BUFSIZ ];
  440. const char **attrs = default_search_attrs;
  441. int attrsonly = default_search_attrsonly;
  442. LDAPMessage *res = 0;
  443. int retval;
  444. char member_filter[ BUFSIZ ];
  445. if (recurse_cnt >= 30)
  446. return LDAPU_ERR_CIRCULAR_GROUPS;
  447. /* setup the filter */
  448. PR_snprintf(member_filter, sizeof(member_filter), ldapu_strings[LDAPU_STR_FILTER_MEMBER], userdn, userdn);
  449. retval = ldapu_find(ld, groupdn, LDAP_SCOPE_BASE, member_filter, attrs,
  450. attrsonly, &res);
  451. if (res) ldap_msgfree(res);
  452. if (retval != LDAPU_SUCCESS && continuable_err(retval)) {
  453. LDAPMessage *entry;
  454. DBG_PRINT2("Find parent groups of \"%s\"\n", userdn);
  455. /* Modify the filter to include the objectclass check */
  456. PR_snprintf(filter, sizeof(filter), ldapu_strings[LDAPU_STR_FILTER_MEMBER_RECURSE],
  457. member_filter);
  458. retval = ldapu_find(ld, base, LDAP_SCOPE_SUBTREE, filter,
  459. attrs, attrsonly, &res);
  460. if (retval == LDAPU_SUCCESS || retval == LDAPU_ERR_MULTIPLE_MATCHES) {
  461. /* Found at least one group the userdn is member of */
  462. if (!res) {
  463. /* this should never happen */
  464. retval = LDAPU_ERR_EMPTY_LDAP_RESULT;
  465. }
  466. else {
  467. retval = LDAPU_ERR_MISSING_RES_ENTRY;
  468. for (entry = ldap_first_entry(ld, res); entry != NULL;
  469. entry = ldap_next_entry(ld, entry))
  470. {
  471. char *dn = ldap_get_dn(ld, entry);
  472. retval = ldapu_auth_udn_gdn_recurse(ld, dn, groupdn,
  473. base, recurse_cnt+1);
  474. ldap_memfree(dn);
  475. if (retval == LDAPU_SUCCESS || !continuable_err(retval)) {
  476. break;
  477. }
  478. }
  479. }
  480. }
  481. if (res) ldap_msgfree(res);
  482. }
  483. return retval;
  484. }
  485. /*
  486. * ldapu_auth_userdn_groupdn:
  487. * Description:
  488. * Checks if the user (userdn) belongs to the given group (groupdn).
  489. * Arguments:
  490. * ld Pointer to LDAP (assumes connection has been
  491. * established and the client has called the
  492. * appropriate bind routine)
  493. * userdn User's full DN -- actually it could be a group
  494. * dn to check subgroup membership.
  495. * groupdn Group's full DN
  496. * Return Values: (same as ldapu_find)
  497. * LDAPU_SUCCESS if user is member of the group
  498. * LDAPU_FAILED if user is not a member of the group
  499. * <rv> if error, where <rv> can be passed to
  500. * ldap_err2string to get an error string.
  501. */
  502. int ldapu_auth_userdn_groupdn (LDAP *ld, const char *userdn,
  503. const char *groupdn, const char *base)
  504. {
  505. return ldapu_auth_udn_gdn_recurse(ld, userdn, groupdn, base, 0);
  506. }
  507. /*
  508. * ldapu_auth_uid_groupdn:
  509. * Description:
  510. * Similar to ldapu_auth_userdn_groupdn but first maps the uid to a
  511. * full user DN before calling ldapu_auth_userdn_groupdn.
  512. * Arguments:
  513. * ld Pointer to LDAP (assumes connection has been
  514. * established and the client has called the
  515. * appropriate bind routine)
  516. * uid User's login name
  517. * groupdn Group's full DN
  518. * base basedn (where to start the search)
  519. * Return Values: (same as ldapu_find)
  520. * LDAPU_SUCCESS if user is member of the group
  521. * LDAPU_FAILED if user is not a member of the group
  522. * <rv> if error, where <rv> can be passed to
  523. * ldap_err2string to get an error string.
  524. */
  525. int ldapu_auth_uid_groupdn (LDAP *ld, const char *uid, const char *groupdn,
  526. const char *base)
  527. {
  528. int retval;
  529. char *dn;
  530. /* First find userdn for the given uid and
  531. then call ldapu_auth_userdn_groupdn */
  532. retval = ldapu_find_userdn(ld, uid, base, &dn);
  533. if (retval == LDAPU_SUCCESS) {
  534. retval = ldapu_auth_userdn_groupdn(ld, dn, groupdn, base);
  535. ldap_memfree(dn);
  536. }
  537. return retval;
  538. }
  539. /*
  540. * ldapu_auth_uid_groupid:
  541. * Description:
  542. * Similar to ldapu_auth_uid_groupdn but first maps the groupid to a
  543. * full group DN before calling ldapu_auth_uid_groupdn.
  544. * Arguments:
  545. * ld Pointer to LDAP (assumes connection has been
  546. * established and the client has called the
  547. * appropriate bind routine)
  548. * uid User's login name
  549. * groupid Group's name
  550. * base basedn (where to start the search)
  551. * Return Values: (same as ldapu_find)
  552. * LDAPU_SUCCESS if user is member of the group
  553. * LDAPU_FAILED if user is not a member of the group
  554. * <rv> if error, where <rv> can be passed to
  555. * ldap_err2string to get an error string.
  556. */
  557. int ldapu_auth_uid_groupid (LDAP *ld, const char *uid,
  558. const char *groupid, const char *base)
  559. {
  560. int retval;
  561. char *dn;
  562. /* First find groupdn for the given groupid and
  563. then call ldapu_auth_uid_groupdn */
  564. retval = ldapu_find_groupdn(ld, groupid, base, &dn);
  565. if (retval == LDAPU_SUCCESS) {
  566. retval = ldapu_auth_uid_groupdn(ld, uid, dn, base);
  567. ldapu_memfree(ld, dn);
  568. }
  569. return retval;
  570. }
  571. /*
  572. * ldapu_auth_userdn_groupid:
  573. * Description:
  574. * Similar to ldapu_auth_userdn_groupdn but first maps the groupid to a
  575. * full group DN before calling ldapu_auth_userdn_groupdn.
  576. * Arguments:
  577. * ld Pointer to LDAP (assumes connection has been
  578. * established and the client has called the
  579. * appropriate bind routine)
  580. * userdn User's full DN
  581. * groupid Group's name
  582. * base basedn (where to start the search)
  583. * Return Values: (same as ldapu_find)
  584. * LDAPU_SUCCESS if user is member of the group
  585. * LDAPU_FAILED if user is not a member of the group
  586. * <rv> if error, where <rv> can be passed to
  587. * ldap_err2string to get an error string.
  588. */
  589. int ldapu_auth_userdn_groupid (LDAP *ld, const char *userdn,
  590. const char *groupid, const char *base)
  591. {
  592. int retval;
  593. char *groupdn;
  594. /* First find groupdn for the given groupid and
  595. then call ldapu_auth_userdn_groupdn */
  596. retval = ldapu_find_groupdn(ld, groupid, base, &groupdn);
  597. if (retval == LDAPU_SUCCESS) {
  598. retval = ldapu_auth_userdn_groupdn(ld, userdn, groupdn, base);
  599. ldap_memfree(groupdn);
  600. }
  601. return retval;
  602. }
  603. LDAPUStr_t *ldapu_str_alloc (const int size)
  604. {
  605. LDAPUStr_t *lstr = (LDAPUStr_t *)ldapu_malloc(sizeof(LDAPUStr_t));
  606. if (!lstr) return 0;
  607. lstr->size = size < 0 ? 1024 : size;
  608. lstr->str = (char *)ldapu_malloc(lstr->size*sizeof(char));
  609. lstr->len = 0;
  610. lstr->str[lstr->len] = 0;
  611. return lstr;
  612. }
  613. void ldapu_str_free (LDAPUStr_t *lstr)
  614. {
  615. if (lstr) {
  616. if (lstr->str) ldapu_free(lstr->str);
  617. ldapu_free((void *)lstr);
  618. }
  619. }
  620. int ldapu_str_append(LDAPUStr_t *lstr, const char *arg)
  621. {
  622. int arglen = strlen(arg);
  623. int len = lstr->len + arglen;
  624. if (len >= lstr->size) {
  625. /* realloc some more */
  626. lstr->size += arglen > 4095 ? arglen+1 : 4096;
  627. lstr->str = (char *)ldapu_realloc(lstr->str, lstr->size);
  628. if (!lstr->str) return LDAPU_ERR_OUT_OF_MEMORY;
  629. }
  630. memcpy((void *)&(lstr->str[lstr->len]), (void *)arg, arglen);
  631. lstr->len += arglen;
  632. lstr->str[lstr->len] = 0;
  633. return LDAPU_SUCCESS;
  634. }
  635. /*
  636. * ldapu_auth_userdn_groupids_recurse:
  637. * Description:
  638. * Checks if the user is member of the given comma separated list of
  639. * group names.
  640. * Arguments:
  641. * ld Pointer to LDAP (assumes connection has been
  642. * established and the client has called the
  643. * appropriate bind routine)
  644. * filter filter to use in the search
  645. * groupids some representation of group names. Example,
  646. * a comma separated names in a string, hash
  647. * table, etc. This function doesn't need to
  648. * know the name of the groups. It calls the
  649. * following function to check if one of the
  650. * groups returned by the search is in the list.
  651. * grpcmpfn group name comparison function.
  652. * base basedn (where to start the search)
  653. * recurse_cnt recursion count to detect circular groups
  654. * group_out if successful, pointer to the user's group
  655. * Return Values: (same as ldapu_find)
  656. * LDAPU_SUCCESS if user is member of one of the groups
  657. * LDAPU_FAILED if user is not a member of the group
  658. * <rv> if error, where <rv> can be passed to
  659. * ldap_err2string to get an error string.
  660. */
  661. static int ldapu_auth_userdn_groupids_recurse (LDAP *ld, const char *filter,
  662. void *groupids,
  663. LDAPU_GroupCmpFn_t grpcmpfn,
  664. const char *base,
  665. int recurse_cnt,
  666. char **group_out)
  667. {
  668. LDAPMessage *res = 0;
  669. const char *attrs[] = { "CN", 0 };
  670. int attrsonly = 0;
  671. LDAPMessage *entry;
  672. int rv;
  673. int retval;
  674. int i;
  675. int done;
  676. if (recurse_cnt >= 30)
  677. return LDAPU_ERR_CIRCULAR_GROUPS;
  678. /* Perform the ldap lookup */
  679. retval = ldapu_find(ld, base, LDAP_SCOPE_SUBTREE, filter, attrs,
  680. attrsonly, &res);
  681. if (retval != LDAPU_SUCCESS && retval != LDAPU_ERR_MULTIPLE_MATCHES ) {
  682. /* user is not a member of any group */
  683. if (res) ldap_msgfree(res);
  684. return retval;
  685. }
  686. retval = LDAPU_FAILED;
  687. done = 0;
  688. /* check if one of the matched groups is one of the given groups */
  689. for (entry = ldap_first_entry(ld, res); entry != NULL && !done;
  690. entry = ldap_next_entry(ld, entry))
  691. {
  692. struct berval **bvals;
  693. if ((bvals = ldap_get_values_len(ld, entry, "CN")) == NULL) {
  694. /* This shouldn't happen */
  695. retval = LDAPU_ERR_MISSING_ATTR_VAL;
  696. continue;
  697. }
  698. /* "CN" may have multiple values */
  699. /* Check each value of "CN" against the 'groupids' */
  700. for ( i = 0; bvals[i] != NULL; i++ ) {
  701. rv = (*grpcmpfn)(groupids, bvals[i]->bv_val, bvals[i]->bv_len);
  702. if (rv == LDAPU_SUCCESS) {
  703. char *group = (char *)ldapu_malloc(bvals[i]->bv_len+1);
  704. if (!group) {
  705. retval = LDAPU_ERR_OUT_OF_MEMORY;
  706. }
  707. else {
  708. strncpy(group, bvals[i]->bv_val, bvals[i]->bv_len);
  709. group[bvals[i]->bv_len] = 0;
  710. *group_out = group;
  711. retval = LDAPU_SUCCESS;
  712. }
  713. done = 1; /* exit from the outer loop too */
  714. break;
  715. }
  716. }
  717. ldap_value_free_len(bvals);
  718. }
  719. if (retval == LDAPU_FAILED) {
  720. /* None of the matched groups is in 'groupids' */
  721. /* Perform the nested group membership check */
  722. LDAPUStr_t *filter1;
  723. LDAPUStr_t *filter2;
  724. char *rfilter = 0;
  725. int rlen;
  726. /* Finally we need a filter which looks like:
  727. (| (& (objectclass=groupofuniquenames)
  728. (| (uniquemember=<grp1dn>)(uniquemember=<grp2dn>) ...))
  729. (& (objectclass=groupofnames)
  730. (| (member=<grp1dn>)(member=<grp2dn>) ...)))
  731. Construct 2 sub-filters first as follows:
  732. (uniquemember=<grp1dn>)(uniquemember=<grp2dn>)... AND
  733. (member=<grp1dn>)(member=<grp2dn>)...
  734. Then insert them in the main filter.
  735. */
  736. filter1 = ldapu_str_alloc(1024);
  737. filter2 = ldapu_str_alloc(1024);
  738. if (!filter1 || !filter2) return LDAPU_ERR_OUT_OF_MEMORY;
  739. rv = LDAPU_SUCCESS;
  740. for (entry = ldap_first_entry(ld, res); entry != NULL;
  741. entry = ldap_next_entry(ld, entry))
  742. {
  743. char *dn = ldap_get_dn(ld, entry);
  744. if (((rv = ldapu_str_append(filter1, "(uniquemember="))
  745. != LDAPU_SUCCESS) ||
  746. ((rv = ldapu_str_append(filter1, dn)) != LDAPU_SUCCESS) ||
  747. ((rv = ldapu_str_append(filter1, ")")) != LDAPU_SUCCESS) ||
  748. ((rv = ldapu_str_append(filter2, "(member="))
  749. != LDAPU_SUCCESS) ||
  750. ((rv = ldapu_str_append(filter2, dn)) != LDAPU_SUCCESS) ||
  751. ((rv = ldapu_str_append(filter2, ")")) != LDAPU_SUCCESS))
  752. {
  753. ldap_memfree(dn);
  754. break;
  755. }
  756. ldap_memfree(dn);
  757. }
  758. if (rv != LDAPU_SUCCESS) {
  759. /* something went wrong in appending to filter1 or filter2 */
  760. ldapu_str_free(filter1);
  761. ldapu_str_free(filter2);
  762. retval = rv;
  763. }
  764. else {
  765. /* Insert the 2 filters in the main filter */
  766. rlen = filter1->len + filter2->len +
  767. strlen("(| (& (objectclass=groupofuniquenames)"
  768. "(| ))"
  769. "(& (objectclass=groupofnames)"
  770. "(| )))") + 1;
  771. rfilter = (char *)ldapu_malloc(rlen);
  772. if (!rfilter) return LDAPU_ERR_OUT_OF_MEMORY;
  773. sprintf(rfilter,
  774. "(| (& (objectclass=groupofuniquenames)"
  775. "(| %s))"
  776. "(& (objectclass=groupofnames)"
  777. "(| %s)))",
  778. filter1->str, filter2->str);
  779. ldapu_str_free(filter1);
  780. ldapu_str_free(filter2);
  781. retval = ldapu_auth_userdn_groupids_recurse(ld, rfilter, groupids,
  782. grpcmpfn, base,
  783. ++recurse_cnt,
  784. group_out);
  785. ldapu_free(rfilter);
  786. }
  787. }
  788. if (res) ldap_msgfree(res);
  789. return retval;
  790. }
  791. /*
  792. * ldapu_auth_userdn_groupids:
  793. * Description:
  794. * Checks if the user is member of the given comma separated list of
  795. * group names.
  796. * Arguments:
  797. * ld Pointer to LDAP (assumes connection has been
  798. * established and the client has called the
  799. * appropriate bind routine)
  800. * userdn User's full DN
  801. * groupids some representation of group names. Example,
  802. * a comma separated names in a string, hash
  803. * table, etc. This function doesn't need to
  804. * know the name of the groups. It calls the
  805. * following function to check if one of the
  806. * groups returned by the search is in the list.
  807. * grpcmpfn group name comparison function.
  808. * base basedn (where to start the search)
  809. * group_out if successful, pointer to the user's group
  810. * Return Values: (same as ldapu_find)
  811. * LDAPU_SUCCESS if user is member of one of the groups
  812. * LDAPU_FAILED if user is not a member of the group
  813. * <rv> if error, where <rv> can be passed to
  814. * ldap_err2string to get an error string.
  815. */
  816. int ldapu_auth_userdn_groupids (LDAP *ld, const char *userdn,
  817. void *groupids,
  818. LDAPU_GroupCmpFn_t grpcmpfn,
  819. const char *base,
  820. char **group_out)
  821. {
  822. char *filter;
  823. int len;
  824. int rv;
  825. *group_out = 0;
  826. /* allocate a big enough filter */
  827. /* The filter looks like:
  828. (| (& (objectclass=groupofuniquenames)(uniquemember=<userdn>))
  829. (& (objectclass=groupofnames)(member=<userdn>)))
  830. */
  831. len = 2 * strlen(userdn) + 1 +
  832. strlen("(| (& (objectclass=groupofuniquenames)(uniquemember=))"
  833. "(& (objectclass=groupofnames)(member=)))");
  834. filter = (char *)ldapu_malloc(len);
  835. if (!filter) return LDAPU_ERR_OUT_OF_MEMORY;
  836. sprintf(filter, "(| (& (objectclass=groupofuniquenames)(uniquemember=%s))"
  837. "(& (objectclass=groupofnames)(member=%s)))",
  838. userdn, userdn);
  839. rv = ldapu_auth_userdn_groupids_recurse(ld, filter, groupids,
  840. grpcmpfn, base,
  841. 0, group_out);
  842. ldapu_free(filter);
  843. return rv;
  844. }
  845. /*
  846. * ldapu_auth_userdn_attrfilter:
  847. * Description:
  848. * Checks if the user's entry has the given attributes
  849. * Arguments:
  850. * ld Pointer to LDAP (assumes connection has been
  851. * established and the client has called the
  852. * appropriate bind routine)
  853. * userdn User's full DN
  854. * attrfilter attribute filter
  855. * Return Values: (same as ldapu_find)
  856. * LDAPU_SUCCESS if user is member of the group
  857. * LDAPU_FAILED if user is not a member of the group
  858. * <rv> if error, where <rv> can be passed to
  859. * ldap_err2string to get an error string.
  860. */
  861. int ldapu_auth_userdn_attrfilter (LDAP *ld, const char *userdn,
  862. const char *attrfilter)
  863. {
  864. const char *base = userdn;
  865. int scope = LDAP_SCOPE_BASE;
  866. const char *filter = attrfilter;
  867. const char **attrs = default_search_attrs;
  868. int attrsonly = default_search_attrsonly;
  869. LDAPMessage *res = 0;
  870. int retval;
  871. retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, &res);
  872. if (res) ldapu_msgfree(ld, res);
  873. return retval;
  874. }
  875. /*
  876. * ldapu_auth_uid_attrfilter:
  877. * Description:
  878. * Checks if the user's entry has the given attributes. First maps
  879. the uid to userdn.
  880. * Arguments:
  881. * ld Pointer to LDAP (assumes connection has been
  882. * established and the client has called the
  883. * appropriate bind routine)
  884. * uid User's name
  885. * attrfilter attribute filter
  886. * base basedn (where to start the search)
  887. * Return Values: (same as ldapu_find)
  888. * LDAPU_SUCCESS if user is member of the group
  889. * LDAPU_FAILED if user is not a member of the group
  890. * <rv> if error, where <rv> can be passed to
  891. * ldap_err2string to get an error string.
  892. */
  893. int ldapu_auth_uid_attrfilter (LDAP *ld, const char *uid, const char *attrfilter,
  894. const char *base)
  895. {
  896. int scope = LDAP_SCOPE_SUBTREE;
  897. char filter[ BUFSIZ ];
  898. const char **attrs = default_search_attrs;
  899. int attrsonly = default_search_attrsonly;
  900. LDAPMessage *res = 0;
  901. int retval;
  902. /* setup filter as (& (uid=<uid>) (attrfilter)) */
  903. if (*attrfilter == '(')
  904. PR_snprintf(filter, sizeof(filter), "(& (uid=%s) %s)", uid, attrfilter);
  905. else
  906. PR_snprintf(filter, sizeof(filter), "(& (uid=%s) (%s))", uid, attrfilter);
  907. retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, &res);
  908. if (res) ldapu_msgfree(ld, res);
  909. return retval;
  910. }
  911. /*
  912. * ldapu_auth_userdn_password:
  913. * Description:
  914. * Checks the user's password against LDAP by binding using the
  915. * userdn and the password.
  916. * Arguments:
  917. * ld Pointer to LDAP (assumes connection has been
  918. * established and the client has called the
  919. * appropriate bind routine)
  920. * userdn User's full DN
  921. * password User's password (clear text)
  922. * Return Values: (same as ldapu_find)
  923. * LDAPU_SUCCESS if user credentials are valid
  924. * <rv> if error, where <rv> can be passed to
  925. * ldap_err2string to get an error string.
  926. */
  927. int ldapu_auth_userdn_password (LDAP *ld, const char *userdn, const char *password)
  928. {
  929. int retval;
  930. DBG_PRINT2("\tuserdn:\t\"%s\"\n", userdn);
  931. DBG_PRINT2("\tpassword:\t\"%s\"\n", password);
  932. retval = ldap_simple_bind_s(ld, userdn, password);
  933. if (retval != LDAP_SUCCESS)
  934. {
  935. DBG_PRINT2("ldap_simple_bind_s: %s\n", ldap_err2string(retval));
  936. return(retval);
  937. }
  938. return LDAPU_SUCCESS;
  939. }
  940. /*
  941. * ldapu_auth_uid_password:
  942. * Description:
  943. * First converts the uid to userdn and calls
  944. * ldapu_auth_userdn_password.
  945. * Arguments:
  946. * ld Pointer to LDAP (assumes connection has been
  947. * established and the client has called the
  948. * appropriate bind routine)
  949. * uid User's name
  950. * password User's password (clear text)
  951. * Return Values: (same as ldapu_find)
  952. * LDAPU_SUCCESS if user credentials are valid
  953. * <rv> if error, where <rv> can be passed to
  954. * ldap_err2string to get an error string.
  955. */
  956. int ldapu_auth_uid_password (LDAP *ld, const char *uid,
  957. const char *password, const char *base)
  958. {
  959. int retval;
  960. char *dn;
  961. /* First find userdn for the given uid and
  962. then call ldapu_auth_userdn_password */
  963. retval = ldapu_find_userdn(ld, uid, base, &dn);
  964. if (retval == LDAPU_SUCCESS) {
  965. retval = ldapu_auth_userdn_password(ld, dn, password);
  966. ldapu_memfree(ld, dn);
  967. }
  968. return retval;
  969. }
  970. /* ldapu_string_set --
  971. * This function is not tested yet for its usefulness. This is to be used to
  972. * customize the strings used in the LDAP searches performed through
  973. * 'ldaputil'. This could also be extended to setting customized error
  974. * messages (and even i18n equivalent of error messages).
  975. */
  976. NSAPI_PUBLIC int ldapu_string_set (const int type, const char *filter)
  977. {
  978. if (!filter || !*filter) return LDAPU_ERR_INVALID_STRING;
  979. if (type < 0 || type >= LDAPU_STR_MAX_INDEX)
  980. return LDAPU_ERR_INVALID_STRING_INDEX;
  981. ldapu_strings[type] = strdup(filter);
  982. if (!ldapu_strings[type]) return LDAPU_ERR_OUT_OF_MEMORY;
  983. return LDAPU_SUCCESS;
  984. }
  985. NSAPI_PUBLIC const char *ldapu_string_get (const int type)
  986. {
  987. if (type < 0 || type >= LDAPU_STR_MAX_INDEX)
  988. return 0;
  989. return ldapu_strings[type];
  990. }