--- /dev/null
+/* LDAP client interface for XEmacs.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Synched up with: Not in FSF. */
+
+/* Author: Oscar Figueiredo */
+
+/* This file provides lisp primitives for access to an LDAP library
+ conforming to the API defined in RFC 1823.
+ It has been tested with:
+ - UMich LDAP 3.3 (http://www.umich.edu/~dirsvcs/ldap/)
+ - Netscape's LDAP SDK 1.0 (http://developer.netscape.com) */
+
+
+
+#include <config.h>
+
+#if defined (HAVE_LDAP)
+
+/* The entire file is within this conditional */
+
+#include "lisp.h"
+
+#include "eldap.h"
+#include <lber.h>
+#include <ldap.h>
+
+#ifdef HAVE_NS_LDAP
+#define HAVE_LDAP_SET_OPTION 1
+#define HAVE_LDAP_GET_ERRNO 1
+#else
+#undef HAVE_LDAP_SET_OPTION
+#undef HAVE_LDAP_GET_ERRNO
+#endif
+
+static Lisp_Object Vldap_default_base;
+static Lisp_Object Vldap_default_host;
+
+/* ldap-search-internal plist keywords */
+static Lisp_Object Qhost, Qfilter, Qattributes, Qattrsonly, Qbase, Qscope,
+ Qauth, Qbinddn, Qpasswd, Qderef, Qtimelimit, Qsizelimit;
+/* Search scope limits */
+static Lisp_Object Qbase, Qonelevel, Qsubtree;
+/* Authentication methods */
+#ifdef LDAP_AUTH_KRBV41
+static Lisp_Object Qkrbv41;
+#endif
+#ifdef LDAP_AUTH_KRBV42
+static Lisp_Object Qkrbv42;
+#endif
+/* Deref policy */
+static Lisp_Object Qnever, Qalways, Qfind;
+
+DEFUN ("ldap-search-internal", Fldap_search_internal, 1, 1, 0, /*
+Perform a search on a LDAP server.
+SEARCH-PLIST is a property list describing the search request.
+Valid keys in that list are:
+ `host' is a string naming one or more (blank separated) LDAP servers to
+to try to connect to. Each host name may optionally be of the form host:port.
+ `filter' is a filter string for the search as described in RFC 1558
+ `attributes' is a list of strings indicating which attributes to retrieve
+for each matching entry. If nil return all available attributes.
+ `attrsonly' if non-nil indicates that only the attributes are retrieved, not
+the associated values.
+ `base' is the base for the search as described in RFC 1779.
+ `scope' is one of the three symbols `subtree', `base' or `onelevel'.
+ `auth' is the authentication method to use, possible values depend on
+the LDAP library XEmacs was compiled with: `simple', `krbv41' and `krbv42'.
+ `binddn' is the distinguished name of the user to bind as (in RFC 1779 syntax).
+ `passwd' is the password to use for simple authentication.
+ `deref' is one of the symbols `never', `always', `search' or `find'.
+ `timelimit' is the timeout limit for the connection in seconds.
+ `sizelimit' is the maximum number of matches to return.
+The function returns a list of matching entries. Each entry is itself
+an alist of attribute/values.
+*/
+ (search_plist))
+{
+ /* This function calls lisp */
+
+ /* Vars for query */
+ LDAP *ld;
+ LDAPMessage *res, *e;
+ BerElement *ptr;
+ char *a;
+ int i, rc, err;
+
+ char *ldap_host = NULL;
+ char *ldap_filter = NULL;
+ char **ldap_attributes = NULL;
+ int ldap_attrsonly = 0;
+ char *ldap_base = NULL;
+ int ldap_scope = LDAP_SCOPE_SUBTREE;
+ int ldap_auth = LDAP_AUTH_SIMPLE;
+ char *ldap_binddn = NULL;
+ char *ldap_passwd = NULL;
+ int ldap_deref = LDAP_DEREF_NEVER;
+ int ldap_timelimit = 0;
+ int ldap_sizelimit = 0;
+
+ char **vals = NULL;
+ int matches;
+
+ Lisp_Object list, entry, result, keyword, value;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+
+ list = entry = result = keyword = value = Qnil;
+ GCPRO5 (list, entry, result, keyword, value);
+
+
+ EXTERNAL_PROPERTY_LIST_LOOP(list, keyword, value, search_plist)
+ {
+ /* Host */
+ if (EQ (keyword, Qhost))
+ {
+ CHECK_STRING (value);
+ ldap_host = alloca (XSTRING_LENGTH (value) + 1);
+ strcpy (ldap_host, (char *)XSTRING_DATA (value));
+ }
+ /* Filter */
+ else if (EQ (keyword, Qfilter))
+ {
+ CHECK_STRING (value);
+ ldap_filter = alloca (XSTRING_LENGTH (value) + 1);
+ strcpy (ldap_filter, (char *)XSTRING_DATA (value));
+ }
+ /* Attributes */
+ else if (EQ (keyword, Qattributes))
+ {
+ if (! NILP (value))
+ {
+ Lisp_Object attr_left = value;
+ struct gcpro ngcpro1;
+
+ NGCPRO1 (attr_left);
+ CHECK_CONS (value);
+
+ ldap_attributes = alloca ((XINT (Flength (value)) + 1)*sizeof (char *));
+
+ for (i=0; !NILP (attr_left); i++) {
+ CHECK_STRING (XCAR (attr_left));
+ ldap_attributes[i] = alloca (XSTRING_LENGTH (XCAR (attr_left)) + 1);
+ strcpy(ldap_attributes[i],
+ (char *)(XSTRING_DATA( XCAR (attr_left))));
+ attr_left = XCDR (attr_left);
+ }
+ ldap_attributes[i] = NULL;
+ NUNGCPRO;
+ }
+ }
+ /* Attributes Only */
+ else if (EQ (keyword, Qattrsonly))
+ {
+ CHECK_SYMBOL (value);
+ ldap_attrsonly = NILP (value) ? 0 : 1;
+ }
+ /* Base */
+ else if (EQ (keyword, Qbase))
+ {
+ if (!NILP (value))
+ {
+ CHECK_STRING (value);
+ ldap_base = alloca (XSTRING_LENGTH (value) + 1);
+ strcpy (ldap_base, (char *)XSTRING_DATA (value));
+ }
+ }
+ /* Scope */
+ else if (EQ (keyword, Qscope))
+ {
+ CHECK_SYMBOL (value);
+
+ if (EQ (value, Qbase))
+ ldap_scope = LDAP_SCOPE_BASE;
+ else if (EQ (value, Qonelevel))
+ ldap_scope = LDAP_SCOPE_ONELEVEL;
+ else if (EQ (value, Qsubtree))
+ ldap_scope = LDAP_SCOPE_SUBTREE;
+ else
+ signal_simple_error ("Invalid scope", value);
+ }
+ /* Authentication method */
+ else if (EQ (keyword, Qauth))
+ {
+ CHECK_SYMBOL (value);
+
+ if (EQ (value, Qsimple))
+ ldap_auth = LDAP_AUTH_SIMPLE;
+#ifdef LDAP_AUTH_KRBV41
+ else if (EQ (value, Qkrbv41))
+ ldap_auth = LDAP_AUTH_KRBV41;
+#endif
+#ifdef LDAP_AUTH_KRBV42
+ else if (EQ (value, Qkrbv42))
+ ldap_auth = LDAP_AUTH_KRBV42;
+#endif
+ else
+ signal_simple_error ("Invalid authentication method", value);
+ }
+ /* Bind DN */
+ else if (EQ (keyword, Qbinddn))
+ {
+ if (!NILP (value))
+ {
+ CHECK_STRING (value);
+ ldap_binddn = alloca (XSTRING_LENGTH (value) + 1);
+ strcpy (ldap_binddn, (char *)XSTRING_DATA (value));
+ }
+ }
+ /* Password */
+ else if (EQ (keyword, Qpasswd))
+ {
+ if (!NILP (value))
+ {
+ CHECK_STRING (value);
+ ldap_passwd = alloca (XSTRING_LENGTH (value) + 1);
+ strcpy (ldap_passwd, (char *)XSTRING_DATA (value));
+ }
+ }
+ /* Deref */
+ else if (EQ (keyword, Qderef))
+ {
+ CHECK_SYMBOL (value);
+ if (EQ (value, Qnever))
+ ldap_deref = LDAP_DEREF_NEVER;
+ else if (EQ (value, Qsearch))
+ ldap_deref = LDAP_DEREF_SEARCHING;
+ else if (EQ (value, Qfind))
+ ldap_deref = LDAP_DEREF_FINDING;
+ else if (EQ (value, Qalways))
+ ldap_deref = LDAP_DEREF_ALWAYS;
+ else
+ signal_simple_error ("Invalid deref value", value);
+ }
+ /* Timelimit */
+ else if (EQ (keyword, Qtimelimit))
+ {
+ if (!NILP (value))
+ {
+ CHECK_INT (value);
+ ldap_timelimit = XINT (value);
+ }
+ }
+ /* Sizelimit */
+ else if (EQ (keyword, Qsizelimit))
+ {
+ if (!NILP (value))
+ {
+ CHECK_INT (value);
+ ldap_sizelimit = XINT (value);
+ }
+ }
+ }
+
+ /* Use ldap-default-base if no default base was given */
+ if (ldap_base == NULL && !NILP (Vldap_default_base))
+ {
+ CHECK_STRING (Vldap_default_base);
+ ldap_base = alloca (XSTRING_LENGTH (Vldap_default_base) + 1);
+ strcpy (ldap_base, (char *)XSTRING_DATA (Vldap_default_base));
+ }
+
+ /* Use ldap-default-host if no host was given */
+ if (ldap_host == NULL && !NILP (Vldap_default_host))
+ {
+ CHECK_STRING (Vldap_default_host);
+ ldap_host = alloca (XSTRING_LENGTH (Vldap_default_host) + 1);
+ strcpy (ldap_host, (char *)XSTRING_DATA (Vldap_default_host));
+ }
+
+ if (ldap_filter == NULL)
+ error ("Empty search filter");
+
+ /* Garbage collect before connecting (if using UMich lib).
+ This is ugly, I know, but without this, the UMich LDAP library 3.3
+ frequently reports "Can't contact LDAP server". I really need to
+ check what happens inside that lib. Anyway this should be harmless to
+ XEmacs and makes things work. */
+#if defined (HAVE_UMICH_LDAP)
+ garbage_collect_1 ();
+#endif
+
+ /* Connect to the server and bind */
+ message ("Connecting to %s...", ldap_host);
+ if ( (ld = ldap_open (ldap_host, LDAP_PORT)) == NULL )
+ signal_simple_error ("Failed connecting to host",
+ build_string (ldap_host));
+
+#if HAVE_LDAP_SET_OPTION
+ if (ldap_set_option (ld, LDAP_OPT_DEREF, (void *)&ldap_deref) != LDAP_SUCCESS)
+ error ("Failed to set deref option");
+ if (ldap_set_option (ld, LDAP_OPT_TIMELIMIT, (void *)&ldap_timelimit) != LDAP_SUCCESS)
+ error ("Failed to set timelimit option");
+ if (ldap_set_option (ld, LDAP_OPT_SIZELIMIT, (void *)&ldap_sizelimit) != LDAP_SUCCESS)
+ error ("Failed to set sizelimit option");
+ if (ldap_set_option (ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON) != LDAP_SUCCESS)
+ error ("Failed to set referral option");
+#else /* HAVE_LDAP_SET_OPTION */
+ ld->ld_deref = ldap_deref;
+ ld->ld_timelimit = ldap_timelimit;
+ ld->ld_sizelimit = ldap_sizelimit;
+#ifdef LDAP_REFERRALS
+ ld->ld_options = LDAP_OPT_REFERRALS;
+#else /* LDAP_REFERRALS */
+ ld->ld_options = 0;
+#endif /* LDAP_REFERRALS */
+#endif /* HAVE_LDAP_SET_OPTION */
+
+ message ("Binding to %s...", ldap_host);
+ if ( (err = (ldap_bind_s (ld, ldap_binddn, ldap_passwd, ldap_auth ))) != LDAP_SUCCESS )
+ signal_simple_error ("Failed binding to the server",
+ build_string (ldap_err2string (err)));
+
+ /* Perform the search */
+ message ("Searching with LDAP on %s...", ldap_host);
+ if ( ldap_search (ld, ldap_base, ldap_scope, ldap_filter,
+ ldap_attributes, ldap_attrsonly) == -1)
+ {
+ ldap_unbind (ld);
+#if HAVE_LDAP_GET_ERRNO
+ signal_simple_error ("Error during LDAP search",
+ build_string (ldap_err2string (ldap_get_lderrno (ld, NULL, NULL))));
+#else
+ signal_simple_error ("Error during LDAP search",
+ build_string (ldap_err2string (ld->ld_errno)));
+#endif
+ }
+
+ /* Build the results list */
+ matches = 0;
+
+ while ( (rc = ldap_result (ld, LDAP_RES_ANY, 0, NULL, &res))
+ == LDAP_RES_SEARCH_ENTRY )
+ {
+ matches ++;
+ e = ldap_first_entry (ld, res);
+ message ("Parsing results... %d", matches);
+ entry = Qnil;
+ for (a= ldap_first_attribute (ld, e, &ptr);
+ a != NULL;
+ a= ldap_next_attribute (ld, e, ptr) )
+ {
+ list = Fcons (build_string (a), Qnil);
+ vals = ldap_get_values (ld, e, a);
+ if (vals != NULL)
+ {
+ for (i=0; vals[i]!=NULL; i++)
+ {
+ list = Fcons (build_string (vals[i]),
+ list);
+ }
+ }
+ entry = Fcons (Fnreverse (list),
+ entry);
+ ldap_value_free (vals);
+ }
+ result = Fcons (Fnreverse (entry),
+ result);
+ ldap_msgfree (res);
+ }
+
+ if (rc == -1)
+ {
+#if HAVE_LDAP_GET_ERRNO
+ signal_simple_error ("Error retrieving result",
+ build_string (ldap_err2string (ldap_get_lderrno (ld, NULL, NULL))));
+#else
+ signal_simple_error ("Error retrieving result",
+ build_string (ldap_err2string (ld->ld_errno)));
+#endif
+ }
+
+ if ((rc = ldap_result2error (ld, res, 0)) != LDAP_SUCCESS)
+ {
+#if HAVE_LDAP_GET_ERRNO
+ signal_simple_error ("Error on result",
+ build_string (ldap_err2string (ldap_get_lderrno (ld, NULL, NULL))));
+#else
+ signal_simple_error ("Error on result",
+ build_string (ldap_err2string (ld->ld_errno)));
+#endif
+ }
+
+ ldap_msgfree (res);
+ ldap_unbind (ld);
+ message ("Done.");
+
+ result = Fnreverse (result);
+ clear_message ();
+
+ UNGCPRO;
+ return result;
+}
+
+void
+syms_of (void)
+{
+ DEFSUBR(Fldap_search_internal);
+
+ defsymbol (&Qhost, "host");
+ defsymbol (&Qfilter, "filter");
+ defsymbol (&Qattributes, "attributes");
+ defsymbol (&Qattrsonly, "attrsonly");
+ defsymbol (&Qbase, "base");
+ defsymbol (&Qscope, "scope");
+ defsymbol (&Qauth, "auth");
+ defsymbol (&Qbinddn, "binddn");
+ defsymbol (&Qpasswd, "passwd");
+ defsymbol (&Qderef, "deref");
+ defsymbol (&Qtimelimit, "timelimit");
+ defsymbol (&Qsizelimit, "sizelimit");
+ defsymbol (&Qbase, "base");
+ defsymbol (&Qonelevel, "onelevel");
+ defsymbol (&Qsubtree, "subtree");
+#ifdef LDAP_AUTH_KRBV41
+ defsymbol (&Qkrbv41, "krbv41");
+#endif
+#ifdef LDAP_AUTH_KRBV42
+ defsymbol (&Qkrbv42, "krbv42");
+#endif
+ defsymbol (&Qnever, "never");
+ defsymbol (&Qalways, "always");
+ defsymbol (&Qfind, "find");
+}
+
+void
+vars_of (void)
+{
+ Fprovide (intern ("ldap-internal"));
+
+ DEFVAR_LISP ("ldap-default-host", &Vldap_default_host /*
+Default LDAP host.
+*/ );
+
+ DEFVAR_LISP ("ldap-default-base", &Vldap_default_base /*
+Default base for LDAP searches.
+This is a string using the syntax of RFC 1779.
+For instance, "o=ACME, c=US" limits the search to the
+Acme organization in the United States.
+*/ );
+
+ Vldap_default_host = Qnil;
+ Vldap_default_base = Qnil;
+}
+
+#endif /* HAVE_LDAP */