Mercurial > hg > xemacs-beta
diff src/eldap.c @ 276:6330739388db r21-0b36
Import from CVS: tag r21-0b36
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:30:37 +0200 |
parents | c5d627a313b1 |
children | 90d73dddcdc4 |
line wrap: on
line diff
--- a/src/eldap.c Mon Aug 13 10:29:43 2007 +0200 +++ b/src/eldap.c Mon Aug 13 10:30:37 2007 +0200 @@ -36,6 +36,8 @@ #include <lber.h> #include <ldap.h> +#include "eldap.h" + #ifdef HAVE_NS_LDAP #define HAVE_LDAP_SET_OPTION 1 #define HAVE_LDAP_GET_ERRNO 1 @@ -44,12 +46,14 @@ #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; +static int ldap_default_port; +static Lisp_Object Vldap_default_base; + +/* ldap-open plist keywords */ +static Lisp_Object Qport, Qauth, Qbinddn, Qpasswd, Qderef, Qtimelimit, + Qsizelimit; /* Search scope limits */ static Lisp_Object Qbase, Qonelevel, Qsubtree; /* Authentication methods */ @@ -62,19 +66,153 @@ /* 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. +static Lisp_Object Qldapp; + + +/************************************************************************/ +/* Utility Functions */ +/************************************************************************/ + +static void +signal_ldap_error (LDAP *ld) +{ +#if HAVE_LDAP_GET_ERRNO + signal_simple_error + ("LDAP error", + build_string (ldap_err2string (ldap_get_lderrno (ld, NULL, NULL)))); +#else + signal_simple_error ("LDAP error", + build_string (ldap_err2string (ld->ld_errno))); +#endif +} + + +/************************************************************************/ +/* The ldap Lisp object */ +/************************************************************************/ + +/* + * Structure records pertinent information about an open LDAP connection. + */ + +struct Lisp_LDAP +{ + /* lcrecord header */ + struct lcrecord_header header; + /* The LDAP connection handle used by the LDAP API */ + LDAP *ld; + /* Name of the host we connected to */ + Lisp_Object host; + /* Status of the LDAP connection. + This is a symbol: open or closed */ + Lisp_Object status_symbol; +}; + + + +static Lisp_Object +mark_ldap (Lisp_Object obj, void (*markobj) (Lisp_Object)) +{ + struct Lisp_LDAP *ldap = XLDAP (obj); + ((markobj) (ldap->host)); + return ldap->status_symbol; +} + +static void +print_ldap (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) +{ + char buf[16]; + + struct Lisp_LDAP *ldap = XLDAP (obj); + + if (print_readably) + error ("printing unreadable object #<ldap %s>", + XSTRING_DATA (ldap->host)); + + if (!escapeflag) + { + print_internal (ldap->host, printcharfun, 0); + } + else + { + write_c_string (GETTEXT ("#<ldap "), printcharfun); + print_internal (ldap->host, printcharfun, 1); + write_c_string (" state:",printcharfun); + print_internal (ldap->status_symbol, printcharfun, 1); + sprintf (buf, " 0x%x>", ldap); + write_c_string (buf, printcharfun); + } +} + +static struct Lisp_LDAP * +allocate_ldap (void) +{ + struct Lisp_LDAP *ldap = + alloc_lcrecord_type (struct Lisp_LDAP, lrecord_ldap); + + ldap->ld = (LDAP *) NULL; + ldap->host = Qnil; + ldap->status_symbol = Qnil; + return ldap; +} + +DEFINE_LRECORD_IMPLEMENTATION ("ldap", ldap, + mark_ldap, print_ldap, NULL, + NULL, NULL, struct Lisp_LDAP); + + + + +/************************************************************************/ +/* Basic ldap accessors */ +/************************************************************************/ + +DEFUN ("ldapp", Fldapp, 1, 1, 0, /* +Return t if OBJECT is a LDAP connection. +*/ + (object)) +{ + return LDAPP (object) ? Qt : Qnil; +} + + +DEFUN ("ldap-host", Fldap_host, 1, 1, 0, /* +Return the server host of the connection LDAP, as a string. +*/ + (ldap)) +{ + CHECK_LDAP (ldap); + return (XLDAP (ldap))->host; +} + + + +DEFUN ("ldap-status", Fldap_status, 1, 1, 0, /* +Return the status of the connection LDAP. +This is a symbol, one of these: + +open -- for a LDAP connection that is open. +closed -- for a LDAP connection that is closed. +*/ + (ldap)) +{ + CHECK_LDAP (ldap); + return (XLDAP (ldap))->status_symbol; +} + + + +/************************************************************************/ +/* Opening/Closing a LDAP connection */ +/************************************************************************/ + + +DEFUN ("ldap-open", Fldap_open, 1, 2, 0, /* +Open a LDAP connection to HOST. +PLIST is a plist containing additional parameters for the connection. 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'. + `port' the TCP port to use for the connection if different from +`ldap-default-port'. `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). @@ -82,115 +220,40 @@ `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)) + (host, plist)) { - /* This function calls lisp */ + /* This function can call lisp */ - /* Vars for query */ + struct Lisp_LDAP *lisp_ldap; 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_port = 0; 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); - + int err; - 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; + Lisp_Object ldap, list, keyword, value; + struct gcpro gcpro1; - NGCPRO1 (attr_left); - CHECK_CONS (value); - - ldap_attributes = alloca ((XINT (Flength (value)) + 1)*sizeof (char *)); + ldap = Qnil; + GCPRO1 (ldap); - 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)) + CHECK_STRING (host); + + EXTERNAL_PROPERTY_LIST_LOOP(list, keyword, value, plist) + { + /* TCP Port */ + if (EQ (keyword, Qport)) { - 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); + CHECK_INT (value); + ldap_port = XINT (value); } /* Authentication method */ - else if (EQ (keyword, Qauth)) + if (EQ (keyword, Qauth)) { CHECK_SYMBOL (value); @@ -210,22 +273,16 @@ /* 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)); - } + 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)); - } + CHECK_STRING (value); + ldap_passwd = alloca (XSTRING_LENGTH (value) + 1); + strcpy (ldap_passwd, (char *)XSTRING_DATA (value)); } /* Deref */ else if (EQ (keyword, Qderef)) @@ -245,67 +302,41 @@ /* Timelimit */ else if (EQ (keyword, Qtimelimit)) { - if (!NILP (value)) - { - CHECK_INT (value); - ldap_timelimit = XINT (value); - } + CHECK_INT (value); + ldap_timelimit = XINT (value); } /* Sizelimit */ else if (EQ (keyword, Qsizelimit)) { - if (!NILP (value)) - { - CHECK_INT (value); - ldap_sizelimit = XINT (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)) + if (ldap_port == 0) { - 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)); + ldap_port = ldap_default_port; } - if (ldap_filter == NULL) - error ("Empty search filter"); + /* Connect to the server and bind */ + ld = ldap_open ((char *)XSTRING_DATA (host), ldap_port); + if (ld == NULL ) + signal_simple_error_2 ("Failed connecting to host", + host, + lisp_strerror (errno)); - /* 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_2 ("Failed connecting to host", - build_string (ldap_host), - lisp_strerror (errno)); #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"); + signal_ldap_error (ld); + if (ldap_set_option (ld, LDAP_OPT_TIMELIMIT, + (void *)&ldap_timelimit) != LDAP_SUCCESS) + signal_ldap_error (ld); + if (ldap_set_option (ld, LDAP_OPT_SIZELIMIT, + (void *)&ldap_sizelimit) != LDAP_SUCCESS) + signal_ldap_error (ld); if (ldap_set_option (ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON) != LDAP_SUCCESS) - error ("Failed to set referral option"); + signal_ldap_error (ld); #else /* HAVE_LDAP_SET_OPTION */ ld->ld_deref = ldap_deref; ld->ld_timelimit = ldap_timelimit; @@ -317,31 +348,164 @@ #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 ) + /* ldap_bind_s calls select and may be wedged by spurious signals */ + slow_down_interrupts (); + err = ldap_bind_s (ld, ldap_binddn, ldap_passwd, ldap_auth); + speed_up_interrupts (); + if (err != 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) + lisp_ldap = allocate_ldap (); + lisp_ldap->ld = ld; + lisp_ldap->host = host; + lisp_ldap->status_symbol = Qopen; + XSETLDAP (ldap,lisp_ldap); + + UNGCPRO; + return ldap; +} + + + +DEFUN ("ldap-close", Fldap_close, 1, 1, 0, /* +Close an LDAP connection. +Return t if the connection was actually closed or nil if +it was already closed before the call +*/ + (ldap)) +{ + CHECK_LDAP (ldap); + if ( EQ ((XLDAP (ldap))->status_symbol, Qopen) ) { - 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 + ldap_unbind ((XLDAP (ldap))->ld); + (XLDAP (ldap))->status_symbol = Qclosed; + return Qt; + } + return Qnil; +} + + + +/************************************************************************/ +/* Working on a LDAP connection */ +/************************************************************************/ + +DEFUN ("ldap-search-internal", Fldap_search_internal, 2, 6, 0, /* +Perform a search on an open LDAP connection. +LDAP is an LDAP connection object created with `ldap-open'. +FILTER is a filter string for the search as described in RFC 1558 +BASE is the distinguished name at which to start the search +SCOPE is an integer or a symbol indicating the scope of the search + Possible values are `ldap-scope-base', `ldap-scope-onelevel' or + `ldap-scope-subtree' +ATTRS is a list of strings indicating which attributes to retrieve + for each matching entry. If nil return all available attributes. +If ATTRSONLY is non-nil then only the attributes are retrieved, not +the associated values +The function returns a list of matching entries. Each entry is itself +an alist of attribute/values. +*/ + (ldap, filter, base, scope, attrs, attrsonly)) +{ + /* This function can call lisp */ + + /* Vars for query */ + LDAP *ld; + LDAPMessage *res, *e; + BerElement *ptr; + char *a; + int i, rc, err; + + char **vals = NULL; + int matches; + + int ldap_scope = LDAP_SCOPE_SUBTREE; + char **ldap_attributes = NULL; + + Lisp_Object list, entry, result; + struct gcpro gcpro1, gcpro2, gcpro3; + + list = entry = result = Qnil; + GCPRO3(list, entry, result); + + /* Do all the parameter checking */ + CHECK_LIVE_LDAP (ldap); + ld = (XLDAP (ldap))->ld; + + /* Filter */ + CHECK_STRING (filter); + + /* Search base */ + if (NILP (base)) + { + base = Vldap_default_base; + } + if (!NILP (base)) + { + CHECK_STRING (Vldap_default_base); + } + + /* Search scope */ + if (!NILP (scope)) + { + CHECK_SYMBOL (scope); + if (EQ (scope, Qbase)) + ldap_scope = LDAP_SCOPE_BASE; + else if (EQ (scope, Qonelevel)) + ldap_scope = LDAP_SCOPE_ONELEVEL; + else if (EQ (scope, Qsubtree)) + ldap_scope = LDAP_SCOPE_SUBTREE; + else + signal_simple_error ("Invalid scope", scope); + } + + /* Attributes to search */ + if (!NILP (attrs)) + { + Lisp_Object attr_left = attrs; + struct gcpro ngcpro1; + + NGCPRO1 (attr_left); + CHECK_CONS (attrs); + + ldap_attributes = alloca ((XINT (Flength (attrs)) + 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 ? */ + CHECK_SYMBOL (attrsonly); + + + /* Perform the search */ + if (ldap_search (ld, + NILP (base) ? "" : (char *) XSTRING_DATA (base), + ldap_scope, + NILP (filter) ? "" : (char *) XSTRING_DATA (filter), + ldap_attributes, + NILP (attrsonly) ? 0 : 1) + == -1) + { + signal_ldap_error (ld); } /* Build the results list */ matches = 0; - while ( (rc = ldap_result (ld, LDAP_RES_ANY, 0, NULL, &res)) - == LDAP_RES_SEARCH_ENTRY ) + /* ldap_result calls select() and can get wedged by EINTR signals */ + slow_down_interrupts (); + rc = ldap_result (ld, LDAP_RES_ANY, 0, NULL, &res); + speed_up_interrupts (); + while ( rc == LDAP_RES_SEARCH_ENTRY ) { matches ++; e = ldap_first_entry (ld, res); @@ -368,32 +532,23 @@ result = Fcons (Fnreverse (entry), result); ldap_msgfree (res); + + slow_down_interrupts (); + rc = ldap_result (ld, LDAP_RES_ANY, 0, NULL, &res); + speed_up_interrupts (); } 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 + signal_ldap_error (ld); } 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 + signal_ldap_error (ld); } ldap_msgfree (res); - ldap_unbind (ld); message ("Done."); result = Fnreverse (result); @@ -407,40 +562,27 @@ void syms_of_eldap (void) { - DEFSUBR(Fldap_search_internal); + defsymbol (&Qldapp, "ldapp"); - 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 (&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"); + DEFSUBR (Fldapp); + DEFSUBR (Fldap_host); + DEFSUBR (Fldap_status); + DEFSUBR (Fldap_open); + DEFSUBR (Fldap_close); + DEFSUBR (Fldap_search_internal); } void vars_of_eldap (void) { - Fprovide (intern ("ldap-internal")); + Fprovide (intern ("ldap")); - DEFVAR_LISP ("ldap-default-host", &Vldap_default_host /* -Default LDAP host. + ldap_default_port = LDAP_PORT; + Vldap_default_base = Qnil; + + DEFVAR_INT ("ldap-default-port", &ldap_default_port /* +Default TCP port for LDAP connections. +Initialized from the LDAP library. Default value is 389. */ ); DEFVAR_LISP ("ldap-default-base", &Vldap_default_base /* @@ -450,6 +592,6 @@ Acme organization in the United States. */ ); - Vldap_default_host = Qnil; - Vldap_default_base = Qnil; } + +