Mercurial > hg > xemacs-beta
view modules/ldap/eldap.c @ 981:0205cafe98ff
[xemacs-hg @ 2002-08-30 08:25:48 by youngs]
Don't look now, but 21.5.9 is on its way out the door!
Don't forget what good 'ol Ma used to say...
"Eat your brussels sprouts, little Johnny, so you
can grow up big and strong."
author | youngs |
---|---|
date | Fri, 30 Aug 2002 08:26:22 +0000 |
parents | 3ecd8885ac67 |
children | 25e260cb7994 |
line wrap: on
line source
/* 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 <emodules.h> #if defined (HAVE_LDAP) /* The entire file is within this conditional */ #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_ldap (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_ldap (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 */