1 /* LDAP client interface for SXEmacs.
2 Copyright (C) 1998 Free Software Foundation, Inc.
4 This file is part of SXEmacs.
6 SXEmacs is free software: you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation, either version 3 of the License, or (at your
9 option) any later version.
11 SXEmacs is distributed in the hope that it will be
12 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 /* Synched up with: Not in FSF. */
21 /* Author: Oscar Figueiredo */
23 /* This file provides lisp primitives for access to an LDAP library
24 conforming to the API defined in RFC 1823.
25 It has been tested with:
26 - UMich LDAP 3.3 (http://www.umich.edu/~dirsvcs/ldap/)
27 - Netscape's LDAP SDK 1.0 (http://developer.netscape.com) */
31 #if defined (HAVE_LDAP)
32 /* The entire file is within this conditional */
39 #define HAVE_LDAP_SET_OPTION 1
40 #define HAVE_LDAP_GET_ERRNO 1
42 #undef HAVE_LDAP_SET_OPTION
43 #undef HAVE_LDAP_GET_ERRNO
46 static Lisp_Object Vldap_default_base;
47 static Lisp_Object Vldap_default_host;
49 /* ldap-search-internal plist keywords */
50 static Lisp_Object Qhost, Qfilter, Qattributes, Qattrsonly, Qbase, Qscope,
51 Qauth, Qbinddn, Qpasswd, Qderef, Qtimelimit, Qsizelimit;
52 /* Search scope limits */
53 static Lisp_Object Qbase, Qonelevel, Qsubtree;
54 /* Authentication methods */
55 #ifdef LDAP_AUTH_KRBV41
56 static Lisp_Object Qkrbv41;
58 #ifdef LDAP_AUTH_KRBV42
59 static Lisp_Object Qkrbv42;
62 static Lisp_Object Qnever, Qalways, Qfind;
64 DEFUN("ldap-search-internal", Fldap_search_internal, 1, 1, 0, /*
65 Perform a search on a LDAP server.
67 SEARCH-PLIST is a property list describing the search request.
68 Valid keys in that list are:
70 `host' is a string naming one or more (blank separated) LDAP servers
71 to to try to connect to. Each host name may optionally be of the
74 `filter' is a filter string for the search as described in RFC 1558
76 `attributes' is a list of strings indicating which attributes to
77 retrieve for each matching entry. If nil return all available
80 `attrsonly' if non-nil indicates that only the attributes are
81 retrieved, not the associated values.
83 `base' is the base for the search as described in RFC 1779.
85 `scope' is one of the three symbols `subtree', `base' or `onelevel'.
87 `auth' is the authentication method to use, possible values depend
88 on the LDAP library XEmacs was compiled with: `simple', `krbv41' and
91 `binddn' is the distinguished name of the user to bind as (in RFC
94 `passwd' is the password to use for simple authentication.
96 `deref' is one of the symbols `never', `always', `search' or `find'.
98 `timelimit' is the timeout limit for the connection in seconds.
100 `sizelimit' is the maximum number of matches to return.
102 The function returns a list of matching entries. Each entry is itself
103 an alist of attribute/values.
107 /* This function calls lisp */
111 LDAPMessage *res, *e;
116 char *ldap_host = NULL;
117 char *ldap_filter = NULL;
118 char **ldap_attributes = NULL;
119 int ldap_attrsonly = 0;
120 char *ldap_base = NULL;
121 int ldap_scope = LDAP_SCOPE_SUBTREE;
122 int ldap_auth = LDAP_AUTH_SIMPLE;
123 char *ldap_binddn = NULL;
124 char *ldap_passwd = NULL;
125 int ldap_deref = LDAP_DEREF_NEVER;
126 int ldap_timelimit = 0;
127 int ldap_sizelimit = 0;
132 Lisp_Object list, entry, result, keyword, value;
133 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
135 list = entry = result = keyword = value = Qnil;
136 GCPRO5(list, entry, result, keyword, value);
138 EXTERNAL_PROPERTY_LIST_LOOP(list, keyword, value, search_plist) {
140 if (EQ(keyword, Qhost)) {
142 ldap_host = alloca(XSTRING_LENGTH(value) + 1);
143 strcpy(ldap_host, (char *)XSTRING_DATA(value));
146 else if (EQ(keyword, Qfilter)) {
148 ldap_filter = alloca(XSTRING_LENGTH(value) + 1);
149 strcpy(ldap_filter, (char *)XSTRING_DATA(value));
152 else if (EQ(keyword, Qattributes)) {
154 Lisp_Object attr_left = value;
155 struct gcpro ngcpro1;
161 alloca((XINT(Flength(value)) +
162 1) * sizeof(char *));
164 for (i = 0; !NILP(attr_left); i++) {
165 CHECK_STRING(XCAR(attr_left));
167 alloca(XSTRING_LENGTH
168 (XCAR(attr_left)) + 1);
169 strcpy(ldap_attributes[i],
173 attr_left = XCDR(attr_left);
175 ldap_attributes[i] = NULL;
179 /* Attributes Only */
180 else if (EQ(keyword, Qattrsonly)) {
182 ldap_attrsonly = NILP(value) ? 0 : 1;
185 else if (EQ(keyword, Qbase)) {
188 ldap_base = alloca(XSTRING_LENGTH(value) + 1);
189 strcpy(ldap_base, (char *)XSTRING_DATA(value));
193 else if (EQ(keyword, Qscope)) {
196 if (EQ(value, Qbase))
197 ldap_scope = LDAP_SCOPE_BASE;
198 else if (EQ(value, Qonelevel))
199 ldap_scope = LDAP_SCOPE_ONELEVEL;
200 else if (EQ(value, Qsubtree))
201 ldap_scope = LDAP_SCOPE_SUBTREE;
203 signal_simple_error("Invalid scope", value);
205 /* Authentication method */
206 else if (EQ(keyword, Qauth)) {
209 if (EQ(value, Qsimple))
210 ldap_auth = LDAP_AUTH_SIMPLE;
211 #ifdef LDAP_AUTH_KRBV41
212 else if (EQ(value, Qkrbv41))
213 ldap_auth = LDAP_AUTH_KRBV41;
215 #ifdef LDAP_AUTH_KRBV42
216 else if (EQ(value, Qkrbv42))
217 ldap_auth = LDAP_AUTH_KRBV42;
221 ("Invalid authentication method", value);
224 else if (EQ(keyword, Qbinddn)) {
227 ldap_binddn = alloca(XSTRING_LENGTH(value) + 1);
229 (char *)XSTRING_DATA(value));
233 else if (EQ(keyword, Qpasswd)) {
236 ldap_passwd = alloca(XSTRING_LENGTH(value) + 1);
238 (char *)XSTRING_DATA(value));
242 else if (EQ(keyword, Qderef)) {
244 if (EQ(value, Qnever))
245 ldap_deref = LDAP_DEREF_NEVER;
246 else if (EQ(value, Qsearch))
247 ldap_deref = LDAP_DEREF_SEARCHING;
248 else if (EQ(value, Qfind))
249 ldap_deref = LDAP_DEREF_FINDING;
250 else if (EQ(value, Qalways))
251 ldap_deref = LDAP_DEREF_ALWAYS;
253 signal_simple_error("Invalid deref value",
257 else if (EQ(keyword, Qtimelimit)) {
260 ldap_timelimit = XINT(value);
264 else if (EQ(keyword, Qsizelimit)) {
267 ldap_sizelimit = XINT(value);
272 /* Use ldap-default-base if no default base was given */
273 if (ldap_base == NULL && !NILP(Vldap_default_base)) {
274 CHECK_STRING(Vldap_default_base);
275 ldap_base = alloca(XSTRING_LENGTH(Vldap_default_base) + 1);
276 strcpy(ldap_base, (char *)XSTRING_DATA(Vldap_default_base));
279 /* Use ldap-default-host if no host was given */
280 if (ldap_host == NULL && !NILP(Vldap_default_host)) {
281 CHECK_STRING(Vldap_default_host);
282 ldap_host = alloca(XSTRING_LENGTH(Vldap_default_host) + 1);
283 strcpy(ldap_host, (char *)XSTRING_DATA(Vldap_default_host));
286 if (ldap_filter == NULL)
287 error("Empty search filter");
289 /* Garbage collect before connecting (if using UMich lib).
290 This is ugly, I know, but without this, the UMich LDAP library 3.3
291 frequently reports "Can't contact LDAP server". I really need to
292 check what happens inside that lib. Anyway this should be harmless to
293 XEmacs and makes things work. */
294 #if defined (HAVE_UMICH_LDAP)
298 /* Connect to the server and bind */
299 message("Connecting to %s...", ldap_host);
300 if ((ld = ldap_open(ldap_host, LDAP_PORT)) == NULL)
301 signal_simple_error("Failed connecting to host",
302 build_string(ldap_host));
304 #if HAVE_LDAP_SET_OPTION
305 if (ldap_set_option(ld, LDAP_OPT_DEREF, (void *)&ldap_deref) !=
307 error("Failed to set deref option");
308 if (ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *)&ldap_timelimit) !=
310 error("Failed to set timelimit option");
311 if (ldap_set_option(ld, LDAP_OPT_SIZELIMIT, (void *)&ldap_sizelimit) !=
313 error("Failed to set sizelimit option");
314 if (ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON) !=
316 error("Failed to set referral option");
317 #else /* HAVE_LDAP_SET_OPTION */
318 ld->ld_deref = ldap_deref;
319 ld->ld_timelimit = ldap_timelimit;
320 ld->ld_sizelimit = ldap_sizelimit;
321 #ifdef LDAP_REFERRALS
322 ld->ld_options = LDAP_OPT_REFERRALS;
323 #else /* LDAP_REFERRALS */
325 #endif /* LDAP_REFERRALS */
326 #endif /* HAVE_LDAP_SET_OPTION */
328 message("Binding to %s...", ldap_host);
330 (ldap_bind_s(ld, ldap_binddn, ldap_passwd, ldap_auth))) !=
332 signal_simple_error("Failed binding to the server",
333 build_string(ldap_err2string(err)));
335 /* Perform the search */
336 message("Searching with LDAP on %s...", ldap_host);
337 if (ldap_search(ld, ldap_base, ldap_scope, ldap_filter,
338 ldap_attributes, ldap_attrsonly) == -1) {
340 #if HAVE_LDAP_GET_ERRNO
341 signal_simple_error("Error during LDAP search",
342 build_string(ldap_err2string
346 signal_simple_error("Error during LDAP search",
347 build_string(ldap_err2string
352 /* Build the results list */
355 while ((rc = ldap_result(ld, LDAP_RES_ANY, 0, NULL, &res))
356 == LDAP_RES_SEARCH_ENTRY) {
358 e = ldap_first_entry(ld, res);
359 message("Parsing results... %d", matches);
361 for (a = ldap_first_attribute(ld, e, &ptr);
362 a != NULL; a = ldap_next_attribute(ld, e, ptr)) {
363 list = Fcons(build_string(a), Qnil);
364 vals = ldap_get_values(ld, e, a);
366 for (i = 0; vals[i] != NULL; i++) {
367 list = Fcons(build_string(vals[i]),
371 entry = Fcons(Fnreverse(list), entry);
372 ldap_value_free(vals);
374 result = Fcons(Fnreverse(entry), result);
379 #if HAVE_LDAP_GET_ERRNO
380 signal_simple_error("Error retrieving result",
381 build_string(ldap_err2string
385 signal_simple_error("Error retrieving result",
386 build_string(ldap_err2string
391 if ((rc = ldap_result2error(ld, res, 0)) != LDAP_SUCCESS) {
392 #if HAVE_LDAP_GET_ERRNO
393 signal_simple_error("Error on result",
394 build_string(ldap_err2string
398 signal_simple_error("Error on result",
399 build_string(ldap_err2string
408 result = Fnreverse(result);
415 void syms_of_ldap(void)
417 DEFSUBR(Fldap_search_internal);
419 defsymbol(&Qhost, "host");
420 defsymbol(&Qfilter, "filter");
421 defsymbol(&Qattributes, "attributes");
422 defsymbol(&Qattrsonly, "attrsonly");
423 defsymbol(&Qbase, "base");
424 defsymbol(&Qscope, "scope");
425 defsymbol(&Qauth, "auth");
426 defsymbol(&Qbinddn, "binddn");
427 defsymbol(&Qpasswd, "passwd");
428 defsymbol(&Qderef, "deref");
429 defsymbol(&Qtimelimit, "timelimit");
430 defsymbol(&Qsizelimit, "sizelimit");
431 defsymbol(&Qbase, "base");
432 defsymbol(&Qonelevel, "onelevel");
433 defsymbol(&Qsubtree, "subtree");
434 #ifdef LDAP_AUTH_KRBV41
435 defsymbol(&Qkrbv41, "krbv41");
437 #ifdef LDAP_AUTH_KRBV42
438 defsymbol(&Qkrbv42, "krbv42");
440 defsymbol(&Qnever, "never");
441 defsymbol(&Qalways, "always");
442 defsymbol(&Qfind, "find");
445 void vars_of_ldap(void)
447 Fprovide(intern("ldap-internal"));
449 DEFVAR_LISP("ldap-default-host", &Vldap_default_host /*
453 DEFVAR_LISP("ldap-default-base", &Vldap_default_base /*
454 Default base for LDAP searches.
455 This is a string using the syntax of RFC 1779.
456 For instance, "o=ACME, c=US" limits the search to the
457 Acme organization in the United States.
460 Vldap_default_host = Qnil;
461 Vldap_default_base = Qnil;
464 #endif /* HAVE_LDAP */