ldapauth.c 34 KB

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