ldapauth.c 34 KB

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