Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/server/ldap-nss.c
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2006-12-21 20:55:55 +0100
committerArthur de Jong <arthur@arthurdejong.org>2006-12-21 20:55:55 +0100
commitfbc5ecfb8cf86d753b7c9a3b5b549a8f279666ab (patch)
tree5d008fb2963ef8a27da784ba851984f64678e6f0 /server/ldap-nss.c
parent8366a3eb4a9032ca43cae9fccaa536182dcece04 (diff)
rename server directory to nslcd
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-ldapd@196 ef36b2f9-881f-0410-afb5-c4e39611909c
Diffstat (limited to 'server/ldap-nss.c')
-rw-r--r--server/ldap-nss.c4032
1 files changed, 0 insertions, 4032 deletions
diff --git a/server/ldap-nss.c b/server/ldap-nss.c
deleted file mode 100644
index f442037..0000000
--- a/server/ldap-nss.c
+++ /dev/null
@@ -1,4032 +0,0 @@
-/*
- ldap-nss.c - main file for NSS interface
- This file was part of the nss_ldap library which has been
- forked into the nss-ldapd library.
-
- Copyright (C) 1997-2006 Luke Howard
- Copyright (C) 2006 West Consulting
- Copyright (C) 2006 Arthur de Jong
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- MA 02110-1301 USA
-*/
-
-#include "config.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#include <stdio.h>
-#include <syslog.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/param.h>
-#include <errno.h>
-#ifdef HAVE_SYS_UN_H
-#include <sys/un.h>
-#endif
-#include <netinet/in.h>
-#ifdef HAVE_LBER_H
-#include <lber.h>
-#endif
-#ifdef HAVE_LDAP_H
-#include <ldap.h>
-#endif
-#ifdef HAVE_LDAP_SSL_H
-#include <ldap_ssl.h>
-#endif
-#ifdef HAVE_GSSLDAP_H
-#include <gssldap.h>
-#endif
-#ifdef HAVE_GSSSASL_H
-#include <gsssasl.h>
-#endif
-#ifdef HAVE_MALLOC_H
-#include <malloc.h>
-#endif
-#if defined(HAVE_THREAD_H)
-#include <thread.h>
-#elif defined(HAVE_PTHREAD_H)
-#include <pthread.h>
-#endif
-/* Try to handle systems with both SASL libraries installed */
-#if defined(HAVE_SASL_SASL_H) && defined(HAVE_SASL_AUXPROP_REQUEST)
-#include <sasl/sasl.h>
-#elif defined(HAVE_SASL_H)
-#include <sasl.h>
-#endif
-#ifdef HAVE_GSSAPI_H
-#include <gssapi.h>
-#elif defined(HAVE_GSSAPI_GSSAPI_KRB5_H)
-#include <gssapi/gssapi.h>
-#include <gssapi/gssapi_krb5.h>
-#endif
-
-#include "ldap-nss.h"
-#include "util.h"
-#include "dnsconfig.h"
-#include "pagectrl.h"
-#include "common.h"
-#include "log.h"
-
-#if defined(HAVE_THREAD_H)
-#ifdef HAVE_PTHREAD_ATFORK
-#undef HAVE_PTHREAD_ATFORK
-#endif
-#endif
-
-/* how many messages to retrieve results for */
-#ifndef LDAP_MSG_ONE
-#define LDAP_MSG_ONE 0x00
-#endif
-#ifndef LDAP_MSG_ALL
-#define LDAP_MSG_ALL 0x01
-#endif
-#ifndef LDAP_MSG_RECEIVED
-#define LDAP_MSG_RECEIVED 0x02
-#endif
-
-#ifdef HAVE_LDAP_LD_FREE
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-extern int ldap_ld_free (LDAP * ld, int close, LDAPControl **,
- LDAPControl **);
-#else
-extern int ldap_ld_free (LDAP * ld, int close);
-#endif /* OPENLDAP 2.x */
-#endif /* HAVE_LDAP_LD_FREE */
-
-NSS_LDAP_DEFINE_LOCK (__lock);
-
-/*
- * LS_INIT only used for enumeration contexts
- */
-#define LS_INIT(state) do { state.ls_type = LS_TYPE_INDEX; state.ls_retry = 0; state.ls_info.ls_index = -1; } while (0)
-
-/*
- * the configuration is read by the first call to do_open().
- * Pointers to elements of the list are passed around but should not
- * be freed.
- */
-static char __configbuf[NSS_LDAP_CONFIG_BUFSIZ];
-static struct ldap_config *__config = NULL;
-
-#ifdef HAVE_SIGACTION
-static struct sigaction __stored_handler;
-static int __sigaction_retval = -1;
-#else
-static void (*__sigpipe_handler) (int) = SIG_DFL;
-#endif /* HAVE_SIGACTION */
-
-/*
- * Global LDAP session.
- */
-static struct ldap_session __session = { NULL, NULL, 0, LS_UNINITIALIZED };
-
-#if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
-static pthread_once_t __once = PTHREAD_ONCE_INIT;
-#endif
-
-#ifdef LBER_OPT_LOG_PRINT_FILE
-static FILE *__debugfile;
-#endif /* LBER_OPT_LOG_PRINT_FILE */
-
-#ifndef HAVE_PTHREAD_ATFORK
-/*
- * Process ID that opened the session.
- */
-static pid_t __pid = -1;
-#endif
-static uid_t __euid = -1;
-
-#ifdef HAVE_LDAPSSL_CLIENT_INIT
-static int __ssl_initialized = 0;
-#endif /* HAVE_LDAPSSL_CLIENT_INIT */
-
-#if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
-/*
- * Prepare for fork(); lock mutex.
- */
-static void do_atfork_prepare (void);
-
-/*
- * Forked in parent, unlock mutex.
- */
-static void do_atfork_parent (void);
-
-/*
- * Forked in child; close LDAP socket, unlock mutex.
- */
-static void do_atfork_child (void);
-
-/*
- * Install handlers for atfork, called once.
- */
-static void do_atfork_setup (void);
-#endif
-
-/*
- * Close the global session, sending an unbind.
- */
-static void do_close (void);
-
-/*
- * Close the global session without sending an unbind.
- */
-static void do_close_no_unbind (void);
-
-/*
- * Disable keepalive on a LDAP connection's socket.
- */
-static void do_set_sockopts (void);
-
-/*
- * TLS routines: set global SSL session options.
- */
-#if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS) || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
-static int do_ssl_options (struct ldap_config * cfg);
-static int do_start_tls (struct ldap_session * session);
-#endif
-
-/*
- * Function to be braced by reconnect harness. Used so we
- * can apply the reconnect code to both asynchronous and
- * synchronous searches.
- */
-typedef int (*search_func_t) (const char *, int, const char *,
- const char **, int, void *);
-
-static enum nss_status
-do_map_error (int rc)
-{
- enum nss_status stat;
-
- switch (rc)
- {
- case LDAP_SUCCESS:
- case LDAP_SIZELIMIT_EXCEEDED:
- case LDAP_TIMELIMIT_EXCEEDED:
- stat = NSS_STATUS_SUCCESS;
- break;
- case LDAP_NO_SUCH_ATTRIBUTE:
- case LDAP_UNDEFINED_TYPE:
- case LDAP_INAPPROPRIATE_MATCHING:
- case LDAP_CONSTRAINT_VIOLATION:
- case LDAP_TYPE_OR_VALUE_EXISTS:
- case LDAP_INVALID_SYNTAX:
- case LDAP_NO_SUCH_OBJECT:
- case LDAP_ALIAS_PROBLEM:
- case LDAP_INVALID_DN_SYNTAX:
- case LDAP_IS_LEAF:
- case LDAP_ALIAS_DEREF_PROBLEM:
- case LDAP_FILTER_ERROR:
- stat = NSS_STATUS_NOTFOUND;
- break;
- case LDAP_SERVER_DOWN:
- case LDAP_TIMEOUT:
- case LDAP_UNAVAILABLE:
- case LDAP_BUSY:
-#ifdef LDAP_CONNECT_ERROR
- case LDAP_CONNECT_ERROR:
-#endif /* LDAP_CONNECT_ERROR */
- case LDAP_LOCAL_ERROR:
- case LDAP_INVALID_CREDENTIALS:
- default:
- stat = NSS_STATUS_UNAVAIL;
- break;
- }
- return stat;
-}
-
-#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) ||defined (HAVE_SASL_SASL_H))
-static int
-do_sasl_interact (LDAP * ld, unsigned flags, void *defaults, void *_interact)
-{
- char *authzid = (char *) defaults;
- sasl_interact_t *interact = (sasl_interact_t *) _interact;
-
- while (interact->id != SASL_CB_LIST_END)
- {
- if (interact->id == SASL_CB_USER)
- {
- if (authzid != NULL)
- {
- interact->result = authzid;
- interact->len = strlen (authzid);
- }
- else if (interact->defresult != NULL)
- {
- interact->result = interact->defresult;
- interact->len = strlen (interact->defresult);
- }
- else
- {
- interact->result = "";
- interact->len = 0;
- }
-#if SASL_VERSION_MAJOR < 2
- interact->result = strdup (interact->result);
- if (interact->result == NULL)
- {
- return LDAP_NO_MEMORY;
- }
-#endif /* SASL_VERSION_MAJOR < 2 */
- }
- else
- {
- return LDAP_PARAM_ERROR;
- }
- interact++;
- }
- return LDAP_SUCCESS;
-}
-#endif
-
-static int
-do_bind (LDAP * ld, int timelimit, const char *dn, const char *pw,
- int with_sasl)
-{
- int rc;
- int msgid;
- struct timeval tv;
- LDAPMessage *result;
-
- debug("==> do_bind");
-
- /*
- * set timelimit in ld for select() call in ldap_pvt_connect()
- * function implemented in libldap2's os-ip.c
- */
- tv.tv_sec = timelimit;
- tv.tv_usec = 0;
-
-#if (defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))) || defined(HAVE_LDAP_GSS_BIND)
- if (!with_sasl)
- {
-#endif
- msgid = ldap_simple_bind (ld, dn, pw);
-
- if (msgid < 0)
- {
- if (ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &rc) !=
- LDAP_SUCCESS)
- {
- rc = LDAP_UNAVAILABLE;
- }
- /* Notify if we failed. */
- syslog (LOG_AUTHPRIV | LOG_ERR, "nss_ldap: could not connect to any LDAP server as %s - %s",
- dn, ldap_err2string (rc));
- debug ("<== do_bind");
-
- return rc;
- }
-
- rc = ldap_result (ld, msgid, 0, &tv, &result);
- if (rc > 0)
- {
- debug ("<== do_bind");
- return ldap_result2error (ld, result, 1);
- }
-
- /* took too long */
- if (rc == 0)
- {
- ldap_abandon (ld, msgid);
- }
-#if (defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))) || defined(HAVE_LDAP_GSS_BIND)
- }
- else
- {
-#ifdef HAVE_LDAP_GSS_BIND
- return ldap_gss_bind (ld, dn, pw, GSSSASL_NO_SECURITY_LAYER,
- LDAP_SASL_GSSAPI);
-#else
-#ifdef CONFIGURE_KRB5_CCNAME
-#ifndef CONFIGURE_KRB5_CCNAME_GSSAPI
- char tmpbuf[256];
- static char envbuf[256];
-#endif
- char *ccname;
- const char *oldccname = NULL;
- int retval;
-#endif /* CONFIGURE_KRB5_CCNAME */
-
- if (__config->ldc_sasl_secprops != NULL)
- {
- rc =
- ldap_set_option (ld, LDAP_OPT_X_SASL_SECPROPS,
- (void *) __config->ldc_sasl_secprops);
- if (rc != LDAP_SUCCESS)
- {
- debug ("do_bind: unable to set SASL security properties");
- return rc;
- }
- }
-
-#ifdef CONFIGURE_KRB5_CCNAME
- /* Set default Kerberos ticket cache for SASL-GSSAPI */
- /* There are probably race conditions here XXX */
- if (__config->ldc_krb5_ccname != NULL)
- {
- ccname = __config->ldc_krb5_ccname;
-#ifdef CONFIGURE_KRB5_CCNAME_ENV
- oldccname = getenv ("KRB5CCNAME");
- if (oldccname != NULL)
- {
- strncpy (tmpbuf, oldccname, sizeof (tmpbuf));
- tmpbuf[sizeof (tmpbuf) - 1] = '\0';
- }
- else
- {
- tmpbuf[0] = '\0';
- }
- oldccname = tmpbuf;
- snprintf (envbuf, sizeof (envbuf), "KRB5CCNAME=%s", ccname);
- putenv (envbuf);
-#elif defined(CONFIGURE_KRB5_CCNAME_GSSAPI)
- if (gss_krb5_ccache_name (&retval, ccname, &oldccname) !=
- GSS_S_COMPLETE)
- {
- debug ("do_bind: unable to set default credential cache");
- return -1;
- }
-#endif
- }
-#endif /* CONFIGURE_KRB5_CCNAME */
-
- rc = ldap_sasl_interactive_bind_s (ld, dn, "GSSAPI", NULL, NULL,
- LDAP_SASL_QUIET,
- do_sasl_interact, (void *) pw);
-
-#ifdef CONFIGURE_KRB5_CCNAME
- /* Restore default Kerberos ticket cache. */
- if (oldccname != NULL)
- {
-#ifdef CONFIGURE_KRB5_CCNAME_ENV
- snprintf (envbuf, sizeof (envbuf), "KRB5CCNAME=%s", oldccname);
- putenv (envbuf);
-#elif defined(CONFIGURE_KRB5_CCNAME_GSSAPI)
- if (gss_krb5_ccache_name (&retval, oldccname, NULL) !=
- GSS_S_COMPLETE)
- {
- debug ("do_bind: unable to restore default credential cache");
- return -1;
- }
-#endif
- }
-#endif /* CONFIGURE_KRB5_CCNAME */
-
- return rc;
-#endif /* HAVE_LDAP_GSS_BIND */
- }
-#endif
-
- debug ("<== do_bind");
-
- return -1;
-}
-
-/*
- * Rebind functions.
- */
-
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-#if LDAP_SET_REBIND_PROC_ARGS == 3
-static int
-do_rebind (LDAP * ld, LDAP_CONST char *url, ber_tag_t request,
- ber_int_t msgid, void *arg)
-#else
-static int
-do_rebind (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid)
-#endif
-{
- char *who, *cred;
- int timelimit;
- int with_sasl = 0;
-
- if (geteuid () == 0 && __session.ls_config->ldc_rootbinddn)
- {
- who = __session.ls_config->ldc_rootbinddn;
-#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
- with_sasl = __session.ls_config->ldc_rootusesasl;
- if (with_sasl)
- {
- cred = __session.ls_config->ldc_rootsaslid;
- }
- else
- {
-#endif
- cred = __session.ls_config->ldc_rootbindpw;
-#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
- }
-#endif
- }
- else
- {
- who = __session.ls_config->ldc_binddn;
-#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
- with_sasl = __session.ls_config->ldc_usesasl;
- if (with_sasl)
- {
- cred = __session.ls_config->ldc_saslid;
- }
- else
- {
-#endif
- cred = __session.ls_config->ldc_bindpw;
-#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
- }
-#endif
- }
-
- timelimit = __session.ls_config->ldc_bind_timelimit;
-
-#ifdef HAVE_LDAP_START_TLS_S
- if (__session.ls_config->ldc_ssl_on == SSL_START_TLS)
- {
- int version;
-
- if (ldap_get_option
- (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
- &version) == LDAP_OPT_SUCCESS)
- {
- if (version < LDAP_VERSION3)
- {
- version = LDAP_VERSION3;
- ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
- &version);
- }
- }
-
- if (do_start_tls (&__session) == LDAP_SUCCESS)
- {
- debug ("TLS startup succeeded");
- }
- else
- {
- debug ("TLS startup failed");
- return NSS_STATUS_UNAVAIL;
- }
- }
-#endif /* HAVE_LDAP_START_TLS_S */
-
- return do_bind (ld, timelimit, who, cred, with_sasl);
-}
-#else
-#if LDAP_SET_REBIND_PROC_ARGS == 3
-static int
-do_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
- int freeit, void *arg)
-#elif LDAP_SET_REBIND_PROC_ARGS == 2
-static int
-do_rebind (LDAP * ld, char **whop, char **credp, int *methodp, int freeit)
-#endif
-{
- if (freeit)
- {
- if (*whop != NULL)
- free (*whop);
- if (*credp != NULL)
- free (*credp);
- }
-
- *whop = *credp = NULL;
- if (geteuid () == 0 && __session.ls_config->ldc_rootbinddn)
- {
- *whop = strdup (__session.ls_config->ldc_rootbinddn);
- if (__session.ls_config->ldc_rootbindpw != NULL)
- *credp = strdup (__session.ls_config->ldc_rootbindpw);
- }
- else
- {
- if (__session.ls_config->ldc_binddn != NULL)
- *whop = strdup (__session.ls_config->ldc_binddn);
- if (__session.ls_config->ldc_bindpw != NULL)
- *credp = strdup (__session.ls_config->ldc_bindpw);
- }
-
- *methodp = LDAP_AUTH_SIMPLE;
-
- return LDAP_SUCCESS;
-}
-#endif
-
-static void
-_nss_ldap_block_sigpipe (void)
-{
-#ifdef HAVE_SIGACTION
- struct sigaction new_handler;
-
- memset (&new_handler, 0, sizeof (new_handler));
-#if 0
- /* XXX need to test for sa_sigaction, not on all platforms */
- new_handler.sa_sigaction = NULL;
-#endif
- new_handler.sa_handler = SIG_IGN;
- sigemptyset (&new_handler.sa_mask);
- new_handler.sa_flags = 0;
-#endif /* HAVE_SIGACTION */
-
- /*
- * Patch for Debian Bug 130006:
- * ignore SIGPIPE for all LDAP operations.
- *
- * The following bug was reintroduced in nss_ldap-213 and is fixed here:
- * http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=84344
- *
- * See:
- * http://www.gnu.org/software/libc/manual/html_node/Signal-and-Sigaction.html
- * for more details.
- */
-#ifdef HAVE_SIGACTION
- __sigaction_retval = sigaction (SIGPIPE, &new_handler, &__stored_handler);
-#elif defined(HAVE_SIGSET)
- __sigpipe_handler = sigset (SIGPIPE, SIG_IGN);
-#else
- __sigpipe_handler = signal (SIGPIPE, SIG_IGN);
-#endif /* HAVE_SIGSET */
-}
-
-static void
-_nss_ldap_unblock_sigpipe (void)
-{
-#ifdef HAVE_SIGACTION
- if (__sigaction_retval == 0)
- (void) sigaction (SIGPIPE, &__stored_handler, NULL);
-#else
- if (__sigpipe_handler != SIG_ERR && __sigpipe_handler != SIG_IGN)
- {
-#ifdef HAVE_SIGSET
- (void) sigset (SIGPIPE, __sigpipe_handler);
-#else
- (void) signal (SIGPIPE, __sigpipe_handler);
-#endif /* HAVE_SIGSET */
- }
-#endif /* HAVE_SIGACTION */
-}
-
-#if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
-static void
-do_atfork_prepare (void)
-{
- debug ("==> do_atfork_prepare");
- NSS_LDAP_LOCK (__lock);
- debug ("<== do_atfork_prepare");
-}
-
-static void
-do_atfork_parent (void)
-{
- debug ("==> do_atfork_parent");
- NSS_LDAP_UNLOCK (__lock);
- debug ("<== do_atfork_parent");
-}
-
-static void
-do_atfork_child (void)
-{
- debug ("==> do_atfork_child");
- _nss_ldap_block_sigpipe();
- do_close_no_unbind ();
- _nss_ldap_unblock_sigpipe();
- NSS_LDAP_UNLOCK (__lock);
- debug ("<== do_atfork_child");
-}
-
-static void
-do_atfork_setup (void)
-{
- debug ("==> do_atfork_setup");
-
-#ifdef HAVE_PTHREAD_ATFORK
- (void) pthread_atfork (do_atfork_prepare, do_atfork_parent,
- do_atfork_child);
-#elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
- (void) __libc_atfork (do_atfork_prepare, do_atfork_parent, do_atfork_child);
-#endif
-
- debug ("<== do_atfork_setup");
-}
-#endif
-
-/*
- * Acquires global lock, blocks SIGPIPE.
- */
-void
-_nss_ldap_enter (void)
-{
- debug ("==> _nss_ldap_enter");
-
- NSS_LDAP_LOCK (__lock);
- _nss_ldap_block_sigpipe();
-
- debug ("<== _nss_ldap_enter");
-}
-
-/*
- * Releases global mutex, releases SIGPIPE.
- */
-void
-_nss_ldap_leave (void)
-{
- debug ("==> _nss_ldap_leave");
-
- _nss_ldap_unblock_sigpipe();
- NSS_LDAP_UNLOCK (__lock);
-
- debug ("<== _nss_ldap_leave");
-}
-
-static void
-do_set_sockopts (void)
-{
-/*
- * Netscape SSL-enabled LDAP library does not
- * return the real socket.
- */
-#ifndef HAVE_LDAPSSL_CLIENT_INIT
- int sd = -1;
-
- debug ("==> do_set_sockopts");
- if (ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, &sd) == 0)
- {
- int off = 0;
- socklen_t socknamelen = sizeof (struct sockaddr_storage);
- socklen_t peernamelen = sizeof (struct sockaddr_storage);
-
- (void) setsockopt (sd, SOL_SOCKET, SO_KEEPALIVE, (void *) &off,
- sizeof (off));
- (void) fcntl (sd, F_SETFD, FD_CLOEXEC);
- /*
- * NSS modules shouldn't open file descriptors that the program/utility
- * linked against NSS doesn't know about. The LDAP library opens a
- * connection to the LDAP server transparently. There's an edge case
- * where a daemon might fork a child and, being written well, closes
- * all its file descriptors. This will close the socket descriptor
- * being used by the LDAP library! Worse, the daemon might open many
- * files and sockets, eventually opening a descriptor with the same number
- * as that originally used by the LDAP library. The only way to know that
- * this isn't "our" socket descriptor is to save the local and remote
- * sockaddr_in structures for later comparison.
- */
- (void) getsockname (sd, (struct sockaddr *) &__session.ls_sockname,
- &socknamelen);
- (void) getpeername (sd, (struct sockaddr *) &__session.ls_peername,
- &peernamelen);
- }
- debug ("<== do_set_sockopts");
-#endif /* HAVE_LDAPSSL_CLIENT_INIT */
-
- return;
-}
-
-/*
- * Closes connection to the LDAP server.
- * This assumes that we have exclusive access to __session.ls_conn,
- * either by some other function having acquired a lock, or by
- * using a thread safe libldap.
- */
-static void
-do_close (void)
-{
-#if defined(DEBUG) || defined(DEBUG_SOCKETS)
- int sd = -1;
-#endif
-
- debug ("==> do_close");
-
- if (__session.ls_conn != NULL)
- {
-#if defined(DEBUG) || defined(DEBUG_SOCKETS)
-#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
- ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, &sd);
-#else
- sd = __session.ls_conn->ld_sb.sb_sd;
-#endif /* LDAP_OPT_DESC */
- syslog (LOG_AUTHPRIV | LOG_INFO, "nss_ldap: closing connection %p fd %d",
- (void *)__session.ls_conn, sd);
-#endif /* DEBUG */
-
- ldap_unbind (__session.ls_conn);
- __session.ls_conn = NULL;
- __session.ls_state = LS_UNINITIALIZED;
- }
-
- debug ("<== do_close");
-}
-
-static int
-do_sockaddr_isequal (struct sockaddr_storage *_s1,
- socklen_t _slen1,
- struct sockaddr_storage *_s2,
- socklen_t _slen2)
-{
- int ret;
-
- if (_s1->ss_family != _s2->ss_family)
- return 0;
-
- if (_slen1 != _slen2)
- return 0;
-
- ret = 0;
-
- switch (_s1->ss_family)
- {
- case AF_INET:
- {
- struct sockaddr_in *s1 = (struct sockaddr_in *) _s1;
- struct sockaddr_in *s2 = (struct sockaddr_in *) _s2;
-
- ret = (s1->sin_port == s2->sin_port &&
- memcmp (&s1->sin_addr, &s2->sin_addr, sizeof(struct in_addr)) == 0);
- break;
- }
- case AF_UNIX:
- {
- struct sockaddr_un *s1 = (struct sockaddr_un *) _s1;
- struct sockaddr_un *s2 = (struct sockaddr_un *) _s2;
-
- ret = (memcmp (s1->sun_path, s2->sun_path,
- _slen1 - sizeof (_s1->ss_family)) == 0);
- break;
- }
-#ifdef INET6
- case AF_INET6:
- {
- struct sockaddr_in6 *s1 = (struct sockaddr_in6 *) _s1;
- struct sockaddr_in6 *s2 = (struct sockaddr_in6 *) _s2;
-
- ret = (s1->sin6_port == s2->sin6_port &&
- memcmp (&s1->sin6_addr, &s2->sin6_addr, sizeof(struct in6_addr)) == 0 &&
- s1->sin6_scope_id == s2->sin6_scope_id);
- break;
- }
-#endif
- default:
- ret = (memcmp (_s1, _s2, _slen1) == 0);
- break;
- }
-
- return ret;
-}
-
-static int
-do_get_our_socket(int *sd)
-{
- /*
- * Before freeing the LDAP context or closing the socket descriptor,
- * we must ensure that it is *our* socket descriptor. See the much
- * lengthier description of this at the end of do_open () where the
- * values __session.ls_sockname and __session.ls_peername are saved.
- * With HAVE_LDAPSSL_CLIENT_INIT this returns 0 if the socket has
- * been closed or reopened, and sets *sd to the ldap socket
- * descriptor.. Returns 1 in all other cases.
- */
-
- int isOurSocket = 1;
-
-#ifndef HAVE_LDAPSSL_CLIENT_INIT
- if (ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, sd) == 0)
- {
- struct sockaddr_storage sockname;
- struct sockaddr_storage peername;
- socklen_t socknamelen = sizeof (sockname);
- socklen_t peernamelen = sizeof (peername);
-
- if (getsockname (*sd, (struct sockaddr *) &sockname, &socknamelen) != 0 ||
- getpeername (*sd, (struct sockaddr *) &peername, &peernamelen) != 0)
- {
- isOurSocket = 0;
- }
- else
- {
- isOurSocket = do_sockaddr_isequal (&__session.ls_sockname,
- socknamelen,
- &sockname,
- socknamelen);
- if (isOurSocket)
- {
- isOurSocket = do_sockaddr_isequal (&__session.ls_peername,
- peernamelen,
- &peername,
- peernamelen);
- }
- }
- }
-#endif /* HAVE_LDAPSSL_CLIENT_INIT */
- return isOurSocket;
-}
-
-static int
-do_dupfd(int oldfd, int newfd)
-{
- int d = -1;
- int flags;
-
- flags = fcntl(oldfd, F_GETFD);
-
- while (1)
- {
- d = (newfd > -1) ? dup2 (oldfd, newfd) : dup (oldfd);
- if (d > -1)
- break;
-
- if (errno == EBADF)
- return -1; /* not open */
-
- if (errno != EINTR
-#ifdef EBUSY
- && errno != EBUSY
-#endif
- )
- return -1;
- }
-
- /* duplicate close-on-exec flag */
- (void) fcntl (d, F_SETFD, flags);
-
- return d;
-}
-
-static int
-do_closefd(int fd)
-{
- int rc;
-
- while ((rc = close(fd)) < 0 && errno == EINTR)
- ;
-
- return rc;
-}
-
-static void
-do_drop_connection(int sd, int closeSd)
-{
- /* Close the LDAP connection without writing anything to the
- underlying socket. The socket will be left open afterwards if
- closeSd is 0 */
-#ifndef HAVE_LDAPSSL_CLIENT_INIT
- {
- int dummyfd = -1, savedfd = -1;
- /* Under OpenLDAP 2.x, ldap_set_option (..., LDAP_OPT_DESC, ...) is
- a no-op, so to shut down the LDAP connection without writing
- anything to the socket, we swap a dummy socket onto that file
- descriptor, and then swap the real fd back once the shutdown is
- done. */
- savedfd = do_dupfd (sd, -1);
- dummyfd = socket (AF_INET, SOCK_STREAM, 0);
- if (dummyfd > -1 && dummyfd != sd)
- {
- do_closefd (sd);
- do_dupfd (dummyfd, sd);
- do_closefd (dummyfd);
- }
-
-#ifdef HAVE_LDAP_LD_FREE
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
- (void) ldap_ld_free (__session.ls_conn, 0, NULL, NULL);
-#else
- (void) ldap_ld_free (__session.ls_conn, 0);
-#endif /* OPENLDAP 2.x */
-#else
- ldap_unbind (__session.ls_conn);
-#endif /* HAVE_LDAP_LD_FREE */
-
- /* Do we want our original sd back? */
- do_closefd (sd);
- if (savedfd > -1)
- {
- if (closeSd == 0)
- do_dupfd (savedfd, sd);
- do_closefd (savedfd);
- }
- }
-#else /* No sd available */
- {
- int bogusSd = -1;
- if (closeSd == 0)
- {
- sd = -1; /* don't want to really close the socket */
-#ifdef HAVE_LDAP_LD_FREE
-#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
- (void) ldap_set_option (__session.ls_conn, LDAP_OPT_DESC, &sd);
-#else
- __session.ls_conn->ld_sb.sb_sd = -1;
-#endif /* LDAP_OPT_DESC */
-#endif /* HAVE_LDAP_LD_FREE */
- }
-
-#ifdef HAVE_LDAP_LD_FREE
-
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
- (void) ldap_ld_free (__session.ls_conn, 0, NULL, NULL);
-#else
- (void) ldap_ld_free (__session.ls_conn, 0);
-#endif /* OPENLDAP 2.x */
-
-#else
-
-#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DESC)
- (void) ldap_set_option (__session.ls_conn, LDAP_OPT_DESC, &bogusSd);
-#else
- __session.ls_conn->ld_sb.sb_sd = bogusSd;
-#endif /* LDAP_OPT_DESC */
-
- /* hope we closed it OK! */
- ldap_unbind (__session.ls_conn);
-
-#endif /* HAVE_LDAP_LD_FREE */
-
- }
-#endif /* HAVE_LDAPSSL_CLIENT_INIT */
- __session.ls_conn = NULL;
- __session.ls_state = LS_UNINITIALIZED;
-
- return;
-}
-
-/*
- * If we've forked, then we need to open a new session.
- * Careful: we have the socket shared with our parent,
- * so we don't want to send an unbind to the server.
- * However, we want to close the descriptor to avoid
- * leaking it, and we also want to release the memory
- * used by __session.ls_conn. The only entry point
- * we have is ldap_unbind() which does both of these
- * things, so we use an internal API, at the expense
- * of compatibility.
- */
-static void
-do_close_no_unbind (void)
-{
- int sd = -1;
- int closeSd = 1;
-
- debug ("==> do_close_no_unbind");
-
- if (__session.ls_state == LS_UNINITIALIZED)
- {
- assert (__session.ls_conn == NULL);
- debug ("<== do_close_no_unbind (connection was not open)");
- return;
- }
-
- closeSd = do_get_our_socket (&sd);
-
-#if defined(DEBUG) || defined(DEBUG_SOCKETS)
- syslog (LOG_AUTHPRIV | LOG_INFO, "nss_ldap: %sclosing connection (no unbind) %p fd %d",
- closeSd ? "" : "not ", (void *)__session.ls_conn, sd);
-#endif /* DEBUG */
-
- do_drop_connection(sd, closeSd);
-
- debug ("<== do_close_no_unbind");
-
- return;
-}
-
-static enum nss_status
-do_init_session (LDAP ** ld, const char *uri, int defport)
-{
- int rc;
- int ldaps;
- char uribuf[NSS_BUFSIZ];
- char *p;
- enum nss_status stat;
-
- ldaps = (strncasecmp (uri, "ldaps://", sizeof ("ldaps://") - 1) == 0);
- p = strchr (uri, ':');
- /* we should be looking for the second instance to find the port number */
- if (p != NULL)
- {
- p = strchr (p, ':');
- }
-
-#ifdef HAVE_LDAP_INITIALIZE
- if (p == NULL &&
- ((ldaps && defport != LDAPS_PORT) || (!ldaps && defport != LDAP_PORT)))
- {
- /* No port specified in URI and non-default port specified */
- snprintf (uribuf, sizeof (uribuf), "%s:%d", uri, defport);
- uri = uribuf;
- }
-
- rc = ldap_initialize (ld, uri);
-#else
- if (strncasecmp (uri, "ldap://", sizeof ("ldap://") - 1) != 0)
- {
- return NSS_STATUS_UNAVAIL;
- }
-
- uri += sizeof ("ldap://") - 1;
- p = strchr (uri, ':');
-
- if (p != NULL)
- {
- size_t urilen = (p - uri);
-
- if (urilen >= sizeof (uribuf))
- {
- return NSS_STATUS_UNAVAIL;
- }
-
- memcpy (uribuf, uri, urilen);
- uribuf[urilen] = '\0';
-
- defport = atoi (p + 1);
- uri = uribuf;
- }
-
-#ifdef HAVE_LDAP_INIT
- *ld = ldap_init (uri, defport);
-#else
- *ld = ldap_open (uri, defport);
-#endif
-
- rc = (*ld == NULL) ? LDAP_SERVER_DOWN : LDAP_SUCCESS;
-
-#endif /* HAVE_LDAP_INITIALIZE */
-
- stat = do_map_error (rc);
- if (stat == NSS_STATUS_SUCCESS && *ld == NULL)
- {
- stat = NSS_STATUS_UNAVAIL;
- }
- return stat;
-}
-
-static enum nss_status
-do_init (void)
-{
- struct ldap_config *cfg;
-#ifndef HAVE_PTHREAD_ATFORK
- pid_t pid;
-#endif
- uid_t euid;
- enum nss_status stat;
- int sd=-1;
-
- debug ("==> do_init");
-
- if (_nss_ldap_validateconfig (__config) != NSS_STATUS_SUCCESS)
- {
- do_close ();
- __config = NULL;
- __session.ls_current_uri = 0;
- }
-
-#ifndef HAVE_PTHREAD_ATFORK
-#if defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
- /*
- * This bogosity is necessary because Linux uses different
- * PIDs for different threads (like IRIX, which we don't
- * support). We can tell whether we are linked against
- * libpthreads by whether __pthread_once is NULL or
- * not. If it is NULL, then we're not linked with the
- * threading library, and we need to compare the current
- * process ID against the saved one to figure out
- * whether we've forked.
- *
- * Once we know whether we have forked or not,
- * courtesy of pthread_atfork() or us checking
- * ourselves, we can close the socket to the LDAP
- * server to avoid leaking a socket, and reopen
- * another connection. Under no circumstances do we
- * wish to use the same connection, or to send an
- * unbind PDU over the parents connection, as that
- * will wreak all sorts of havoc or inefficiencies,
- * respectively.
- */
- if (__pthread_once == NULL)
- pid = getpid ();
- else
- pid = -1; /* linked against libpthreads, don't care */
-#else
- pid = getpid ();
-#endif /* HAVE_LIBC_LOCK_H || HAVE_BITS_LIBC_LOCK_H */
-#endif /* HAVE_PTHREAD_ATFORK */
-
- euid = geteuid ();
-
-#ifdef DEBUG
-#ifdef HAVE_PTHREAD_ATFORK
- syslog (LOG_AUTHPRIV | LOG_DEBUG,
- "nss_ldap: __session.ls_state=%d, __session.ls_conn=%p, __euid=%i, euid=%i",
- __session.ls_state, __session.ls_conn, __euid, euid);
-#elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
- syslog (LOG_AUTHPRIV | LOG_DEBUG,
- "nss_ldap: libpthreads=%s, __session.ls_state=%d, __session.ls_conn=%p, __pid=%i, pid=%i, __euid=%i, euid=%i",
- (__pthread_once == NULL ? "FALSE" : "TRUE"),
- __session.ls_state,
- (void *)__session.ls_conn,
- (__pthread_once == NULL ? __pid : -1),
- (__pthread_once == NULL ? pid : -1), __euid, euid);
-#else
- syslog (LOG_AUTHPRIV | LOG_DEBUG,
- "nss_ldap: __session.ls_state=%d, __session.ls_conn=%p, __pid=%i, pid=%i, __euid=%i, euid=%i",
- __session.ls_state, __session.ls_conn, __pid, pid, __euid, euid);
-#endif
-#endif /* DEBUG */
-
- if (__session.ls_state == LS_CONNECTED_TO_DSA &&
- do_get_our_socket (&sd) == 0)
- {
- /* The calling app has stolen our socket. */
- debug (":== do_init (stolen socket detected)");
- do_drop_connection (sd, 0);
- }
- else
-#ifndef HAVE_PTHREAD_ATFORK
-#if defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
- if (__pthread_once == NULL && __pid != pid)
-#else
- if (__pid != pid)
-#endif /* HAVE_LIBC_LOCK_H || HAVE_BITS_LIBC_LOCK_H */
- {
- do_close_no_unbind ();
- }
- else
-#endif /* HAVE_PTHREAD_ATFORK */
- if (__euid != euid && (__euid == 0 || euid == 0))
- {
- /*
- * If we've changed user ids, close the session so we can
- * rebind as the correct user.
- */
- do_close ();
- }
- else if (__session.ls_state == LS_CONNECTED_TO_DSA)
- {
- time_t current_time;
-
- /*
- * Otherwise we can hand back this process' global
- * LDAP session.
- *
- * Patch from Steven Barrus <sbarrus@eng.utah.edu> to
- * close the session after an idle timeout.
- */
-
- assert (__session.ls_conn != NULL);
- assert (__session.ls_config != NULL);
-
- if (__session.ls_config->ldc_idle_timelimit)
- {
- time (&current_time);
- if ((__session.ls_timestamp +
- __session.ls_config->ldc_idle_timelimit) < current_time)
- {
- debug ("idle_timelimit reached");
- do_close ();
- }
- }
-
- /*
- * If the connection is still there (ie. do_close() wasn't
- * called) then we can return the cached connection.
- */
- if (__session.ls_state == LS_CONNECTED_TO_DSA)
- {
- debug ("<== do_init (cached session)");
- return NSS_STATUS_SUCCESS;
- }
- }
-
- __session.ls_conn = NULL;
- __session.ls_timestamp = 0;
- __session.ls_state = LS_UNINITIALIZED;
-
-#ifdef HAVE_PTHREAD_ATFORK
- if (pthread_once (&__once, do_atfork_setup) != 0)
- {
- debug ("<== do_init (pthread_once failed)");
- return NSS_STATUS_UNAVAIL;
- }
-#elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
- /*
- * Only install the pthread_atfork() handlers i
- * we are linked against libpthreads. Otherwise,
- * do close the session when the PID changes.
- */
- if (__pthread_once == NULL)
- __pid = pid;
- else
- __libc_once (__once, do_atfork_setup);
-#else
- __pid = pid;
-#endif
-
- __euid = euid;
-
- /* Initialize schema and LDAP handle (but do not connect) */
- if (__config == NULL)
- {
- char *configbufp = __configbuf;
- size_t configbuflen = sizeof (__configbuf);
-
- stat = _nss_ldap_readconfig (&__config, &configbufp, &configbuflen);
- if (stat == NSS_STATUS_NOTFOUND)
- {
- /* Config was read but no host information specified; try DNS */
- stat = _nss_ldap_mergeconfigfromdns (__config, &configbufp, &configbuflen);
- }
-
- if (stat != NSS_STATUS_SUCCESS)
- {
- debug ("<== do_init (failed to read config)");
- return NSS_STATUS_UNAVAIL;
- }
- }
-
- cfg = __config;
-
- _nss_ldap_init_attributes (cfg->ldc_attrtab);
- _nss_ldap_init_filters ();
-
-#ifdef HAVE_LDAP_SET_OPTION
- if (cfg->ldc_debug)
- {
-#ifdef LBER_OPT_LOG_PRINT_FILE
- if (cfg->ldc_logdir && !__debugfile)
- {
- char namebuf[PATH_MAX];
-
- snprintf (namebuf, sizeof (namebuf), "%s/ldap.%d", cfg->ldc_logdir,
- (int) getpid ());
- __debugfile = fopen (namebuf, "a");
-
- if (__debugfile != NULL)
- {
- ber_set_option (NULL, LBER_OPT_LOG_PRINT_FILE, __debugfile);
- }
- }
-#endif /* LBER_OPT_LOG_PRINT_FILE */
-#ifdef LBER_OPT_DEBUG_LEVEL
- if (cfg->ldc_debug)
- {
- ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &cfg->ldc_debug);
- ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &cfg->ldc_debug);
- }
-#endif /* LBER_OPT_DEBUG_LEVEL */
- }
-#endif /* HAVE_LDAP_SET_OPTION */
-
-#ifdef HAVE_LDAPSSL_CLIENT_INIT
- /*
- * Initialize the SSL library.
- */
- if (cfg->ldc_ssl_on == SSL_LDAPS)
- {
- int rc = 0;
- if (__ssl_initialized == 0
- && (rc = ldapssl_client_init (cfg->ldc_sslpath, NULL)) != LDAP_SUCCESS)
- {
- debug ("<== do_init (ldapssl_client_init failed with rc = %d)", rc);
- return NSS_STATUS_UNAVAIL;
- }
- __ssl_initialized = 1;
- }
-#endif /* SSL */
-
- __session.ls_conn = NULL;
-
- assert (__session.ls_current_uri <= NSS_LDAP_CONFIG_URI_MAX);
- assert (cfg->ldc_uris[__session.ls_current_uri] != NULL);
-
- stat = do_init_session (&__session.ls_conn,
- cfg->ldc_uris[__session.ls_current_uri],
- cfg->ldc_port);
- if (stat != NSS_STATUS_SUCCESS)
- {
- debug ("<== do_init (failed to initialize LDAP session)");
- return stat;
- }
-
- __session.ls_config = cfg;
- __session.ls_state = LS_INITIALIZED;
-
- debug ("<== do_init (initialized session)");
-
- return NSS_STATUS_SUCCESS;
-}
-
-/*
- * A simple alias around do_init().
- */
-enum nss_status
-_nss_ldap_init (void)
-{
- return do_init ();
-}
-
-/*
- * A simple alias around do_close().
- */
-void
-_nss_ldap_close (void)
-{
- do_close ();
-}
-
-#if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS)
-static int
-do_start_tls (struct ldap_session * session)
-{
- int rc;
-#ifdef HAVE_LDAP_START_TLS
- int msgid;
- struct timeval tv, *timeout;
- LDAPMessage *res = NULL;
-
- debug ("==> do_start_tls");
-
- rc = ldap_start_tls (session->ls_conn, NULL, NULL, &msgid);
- if (rc != LDAP_SUCCESS)
- {
- debug ("<== do_start_tls (ldap_start_tls failed: %s)", ldap_err2string (rc));
- return rc;
- }
-
- if (session->ls_config->ldc_bind_timelimit == LDAP_NO_LIMIT)
- {
- timeout = NULL;
- }
- else
- {
- tv.tv_sec = session->ls_config->ldc_bind_timelimit;
- tv.tv_usec = 0;
- timeout = &tv;
- }
-
- rc = ldap_result (session->ls_conn, msgid, 1, timeout, &res);
- if (rc == -1)
- {
-#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
- if (ldap_get_option (session->ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
- {
- rc = LDAP_UNAVAILABLE;
- }
-#else
- rc = ld->ld_errno;
-#endif /* LDAP_OPT_ERROR_NUMBER */
-
- debug ("<== do_start_tls (ldap_start_tls failed: %s)", ldap_err2string (rc));
- return rc;
- }
-
- rc = ldap_result2error (session->ls_conn, res, 1);
- if (rc != LDAP_SUCCESS)
- {
- debug ("<== do_start_tls (ldap_result2error failed: %s)", ldap_err2string (rc));
- return rc;
- }
-
- rc = ldap_install_tls (session->ls_conn);
-#else
- rc = ldap_start_tls_s (session->ls_conn, NULL, NULL);
-#endif /* HAVE_LDAP_START_TLS */
-
- if (rc != LDAP_SUCCESS)
- {
- debug ("<== do_start_tls (start TLS failed: %s)", ldap_err2string(rc));
- return rc;
- }
-
- return LDAP_SUCCESS;
-}
-#endif
-
-/*
- * Opens connection to an LDAP server - should only be called from search
- * API. Other API that just needs access to configuration and schema should
- * call do_init().
- *
- * As with do_close(), this assumes ownership of sess.
- * It also wants to own __config: is there a potential deadlock here? XXX
- */
-static enum nss_status
-do_open (void)
-{
- struct ldap_config *cfg;
- int usesasl;
- char *bindarg;
- enum nss_status stat;
-#ifdef LDAP_OPT_NETWORK_TIMEOUT
- struct timeval tv;
-#endif
-#ifdef LDAP_X_OPT_CONNECT_TIMEOUT
- int timeout;
-#endif
- int rc;
-
- debug ("==> do_open");
-
- /* Moved the head part of do_open() into do_init() */
- stat = do_init ();
- if (stat != NSS_STATUS_SUCCESS)
- {
- debug ("<== do_open (session initialization failed)");
- return stat;
- }
-
- assert (__session.ls_conn != NULL);
- assert (__session.ls_config != NULL);
- assert (__session.ls_state != LS_UNINITIALIZED);
-
- if (__session.ls_state == LS_CONNECTED_TO_DSA)
- {
- debug ("<== do_open (cached session)");
- return NSS_STATUS_SUCCESS;
- }
-
- cfg = __session.ls_config;
-
-#if LDAP_SET_REBIND_PROC_ARGS == 3
- ldap_set_rebind_proc (__session.ls_conn, do_rebind, NULL);
-#elif LDAP_SET_REBIND_PROC_ARGS == 2
- ldap_set_rebind_proc (__session.ls_conn, do_rebind);
-#endif
-
- ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
- &cfg->ldc_version);
-
- ldap_set_option (__session.ls_conn, LDAP_OPT_DEREF, &cfg->ldc_deref);
-
- ldap_set_option (__session.ls_conn, LDAP_OPT_TIMELIMIT,
- &cfg->ldc_timelimit);
-
-#ifdef LDAP_X_OPT_CONNECT_TIMEOUT
- /*
- * This is a new option in the Netscape SDK which sets
- * the TCP connect timeout. For want of a better value,
- * we use the bind_timelimit to control this.
- */
- timeout = cfg->ldc_bind_timelimit * 1000;
- ldap_set_option (__session.ls_conn, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout);
-#endif /* LDAP_X_OPT_CONNECT_TIMEOUT */
-
-#ifdef LDAP_OPT_NETWORK_TIMEOUT
- tv.tv_sec = cfg->ldc_bind_timelimit;
- tv.tv_usec = 0;
- ldap_set_option (__session.ls_conn, LDAP_OPT_NETWORK_TIMEOUT, &tv);
-#endif /* LDAP_OPT_NETWORK_TIMEOUT */
-
-#ifdef LDAP_OPT_REFERRALS
- ldap_set_option (__session.ls_conn, LDAP_OPT_REFERRALS,
- cfg->ldc_referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
-#endif /* LDAP_OPT_REFERRALS */
-
-#ifdef LDAP_OPT_RESTART
- ldap_set_option (__session.ls_conn, LDAP_OPT_RESTART,
- cfg->ldc_restart ? LDAP_OPT_ON : LDAP_OPT_OFF);
-#endif /* LDAP_OPT_RESTART */
-
-#if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS)
- if (cfg->ldc_ssl_on == SSL_START_TLS)
- {
- int version;
-
- if (ldap_get_option
- (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
- &version) == LDAP_OPT_SUCCESS)
- {
- if (version < LDAP_VERSION3)
- {
- version = LDAP_VERSION3;
- ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
- &version);
- }
- }
-
- /* set up SSL context */
- if (do_ssl_options (cfg) != LDAP_SUCCESS)
- {
- do_close ();
- debug ("<== do_open (SSL setup failed)");
- return NSS_STATUS_UNAVAIL;
- }
-
- stat = do_map_error (do_start_tls (&__session));
- if (stat == NSS_STATUS_SUCCESS)
- {
- debug (":== do_open (TLS startup succeeded)");
- }
- else
- {
- do_close ();
- debug ("<== do_open (TLS startup failed)");
- return stat;
- }
- }
- else
-#endif /* HAVE_LDAP_START_TLS_S || HAVE_LDAP_START_TLS */
-
- /*
- * If SSL is desired, then enable it.
- */
- if (cfg->ldc_ssl_on == SSL_LDAPS)
- {
-#if defined(LDAP_OPT_X_TLS)
- int tls = LDAP_OPT_X_TLS_HARD;
- if (ldap_set_option (__session.ls_conn, LDAP_OPT_X_TLS, &tls) !=
- LDAP_SUCCESS)
- {
- do_close ();
- debug ("<== do_open (TLS setup failed)");
- return NSS_STATUS_UNAVAIL;
- }
-
- /* set up SSL context */
- if (do_ssl_options (cfg) != LDAP_SUCCESS)
- {
- do_close ();
- debug ("<== do_open (SSL setup failed)");
- return NSS_STATUS_UNAVAIL;
- }
-
-#elif defined(HAVE_LDAPSSL_CLIENT_INIT)
- if (ldapssl_install_routines (__session.ls_conn) != LDAP_SUCCESS)
- {
- do_close ();
- debug ("<== do_open (SSL setup failed)");
- return NSS_STATUS_UNAVAIL;
- }
-/* not in Solaris 9? */
-#ifndef LDAP_OPT_SSL
-#define LDAP_OPT_SSL 0x0A
-#endif
- if (ldap_set_option (__session.ls_conn, LDAP_OPT_SSL, LDAP_OPT_ON) !=
- LDAP_SUCCESS)
- {
- do_close ();
- debug ("<== do_open (SSL setup failed)");
- return NSS_STATUS_UNAVAIL;
- }
-#endif
- }
-
- /*
- * If we're running as root, let us bind as a special
- * user, so we can fake shadow passwords.
- * Thanks to Doug Nazar <nazard@dragoninc.on.ca> for this
- * patch.
- */
- if (__euid == 0 && cfg->ldc_rootbinddn != NULL)
- {
-#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
- usesasl = cfg->ldc_rootusesasl;
- bindarg =
- cfg->ldc_rootusesasl ? cfg->ldc_rootsaslid : cfg->ldc_rootbindpw;
-#else
- usesasl = 0;
- bindarg = cfg->ldc_rootbindpw;
-#endif
-
- rc = do_bind (__session.ls_conn,
- cfg->ldc_bind_timelimit,
- cfg->ldc_rootbinddn, bindarg, usesasl);
- }
- else
- {
-#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
- usesasl = cfg->ldc_usesasl;
- bindarg = cfg->ldc_usesasl ? cfg->ldc_saslid : cfg->ldc_bindpw;
-#else
- usesasl = 0;
- bindarg = cfg->ldc_bindpw;
-#endif
-
- rc = do_bind (__session.ls_conn,
- cfg->ldc_bind_timelimit,
- cfg->ldc_binddn,
- cfg->ldc_bindpw, usesasl);
- }
-
- if (rc != LDAP_SUCCESS)
- {
- /* log actual LDAP error code */
- syslog (LOG_AUTHPRIV | LOG_INFO,
- "nss_ldap: failed to bind to LDAP server %s: %s",
- cfg->ldc_uris[__session.ls_current_uri],
- ldap_err2string (rc));
- stat = do_map_error (rc);
- do_close ();
- debug ("<== do_open (failed to bind to DSA");
- }
- else
- {
- do_set_sockopts ();
- time (&__session.ls_timestamp);
- __session.ls_state = LS_CONNECTED_TO_DSA;
- stat = NSS_STATUS_SUCCESS;
- debug ("<== do_open (session connected to DSA)");
- }
-
- return stat;
-}
-
-#if defined HAVE_LDAP_START_TLS_S || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
-static int
-do_ssl_options (struct ldap_config * cfg)
-{
- int rc;
-
- debug ("==> do_ssl_options");
-
-#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
- if (cfg->ldc_tls_randfile != NULL)
- {
- /* rand file */
- rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
- cfg->ldc_tls_randfile);
- if (rc != LDAP_SUCCESS)
- {
- debug
- ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_RANDOM_FILE failed");
- return LDAP_OPERATIONS_ERROR;
- }
- }
-#endif /* LDAP_OPT_X_TLS_RANDOM_FILE */
-
- if (cfg->ldc_tls_cacertfile != NULL)
- {
- /* ca cert file */
- rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE,
- cfg->ldc_tls_cacertfile);
- if (rc != LDAP_SUCCESS)
- {
- debug
- ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CACERTFILE failed");
- return LDAP_OPERATIONS_ERROR;
- }
- }
-
- if (cfg->ldc_tls_cacertdir != NULL)
- {
- /* ca cert directory */
- rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR,
- cfg->ldc_tls_cacertdir);
- if (rc != LDAP_SUCCESS)
- {
- debug
- ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CACERTDIR failed");
- return LDAP_OPERATIONS_ERROR;
- }
- }
-
- /* require cert? */
- if (cfg->ldc_tls_checkpeer > -1)
- {
- rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
- &cfg->ldc_tls_checkpeer);
- if (rc != LDAP_SUCCESS)
- {
- debug
- ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_REQUIRE_CERT failed");
- return LDAP_OPERATIONS_ERROR;
- }
- }
-
- if (cfg->ldc_tls_ciphers != NULL)
- {
- /* set cipher suite, certificate and private key: */
- rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
- cfg->ldc_tls_ciphers);
- if (rc != LDAP_SUCCESS)
- {
- debug
- ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CIPHER_SUITE failed");
- return LDAP_OPERATIONS_ERROR;
- }
- }
-
- if (cfg->ldc_tls_cert != NULL)
- {
- rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE, cfg->ldc_tls_cert);
- if (rc != LDAP_SUCCESS)
- {
- debug
- ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CERTFILE failed");
- return LDAP_OPERATIONS_ERROR;
- }
- }
-
- if (cfg->ldc_tls_key != NULL)
- {
- rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE, cfg->ldc_tls_key);
- if (rc != LDAP_SUCCESS)
- {
- debug
- ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_KEYFILE failed");
- return LDAP_OPERATIONS_ERROR;
- }
- }
-
- debug ("<== do_ssl_options");
-
- return LDAP_SUCCESS;
-}
-#endif
-
-/*
- * This function initializes an enumeration context, acquiring
- * the global mutex.
- *
- * It could be done from the default constructor, under Solaris, but we
- * delay it until the setXXent() function is called.
- */
-struct ent_context *
-_nss_ldap_ent_context_init (struct ent_context ** pctx)
-{
- struct ent_context *ctx;
-
- _nss_ldap_enter ();
-
- ctx = _nss_ldap_ent_context_init_locked (pctx);
-
- _nss_ldap_leave ();
-
- return ctx;
-}
-
-/*
- * Wrapper around ldap_result() to skip over search references
- * and deal transparently with the last entry.
- */
-static enum nss_status
-do_result (struct ent_context * ctx, int all)
-{
- int rc = LDAP_UNAVAILABLE;
- enum nss_status stat = NSS_STATUS_TRYAGAIN;
- struct timeval tv, *tvp;
-
- debug ("==> do_result");
-
- if (__session.ls_config->ldc_timelimit == LDAP_NO_LIMIT)
- {
- tvp = NULL;
- }
- else
- {
- tv.tv_sec = __session.ls_config->ldc_timelimit;
- tv.tv_usec = 0;
- tvp = &tv;
- }
-
- do
- {
- if (ctx->ec_res != NULL)
- {
- ldap_msgfree (ctx->ec_res);
- ctx->ec_res = NULL;
- }
-
- rc =
- ldap_result (__session.ls_conn, ctx->ec_msgid, all, tvp,
- &ctx->ec_res);
- switch (rc)
- {
- case -1:
- case 0:
- if (ldap_get_option
- (__session.ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
- {
- rc = LDAP_UNAVAILABLE;
- }
- syslog (LOG_AUTHPRIV | LOG_ERR, "nss_ldap: could not get LDAP result - %s",
- ldap_err2string (rc));
- stat = NSS_STATUS_UNAVAIL;
- break;
- case LDAP_RES_SEARCH_ENTRY:
- stat = NSS_STATUS_SUCCESS;
- break;
- case LDAP_RES_SEARCH_RESULT:
- if (all == LDAP_MSG_ALL)
- {
- /* we asked for the result chain, we got it. */
- stat = NSS_STATUS_SUCCESS;
- }
- else
- {
-#ifdef LDAP_MORE_RESULTS_TO_RETURN
- int parserc;
- /* NB: this frees ctx->ec_res */
- LDAPControl **resultControls = NULL;
-
- ctx->ec_cookie = NULL;
-
- parserc =
- ldap_parse_result (__session.ls_conn, ctx->ec_res, &rc, NULL,
- NULL, NULL, &resultControls, 1);
- if (parserc != LDAP_SUCCESS
- && parserc != LDAP_MORE_RESULTS_TO_RETURN)
- {
- stat = NSS_STATUS_UNAVAIL;
- ldap_abandon (__session.ls_conn, ctx->ec_msgid);
- syslog (LOG_AUTHPRIV | LOG_ERR,
- "nss_ldap: could not get LDAP result - %s",
- ldap_err2string (rc));
- }
- else if (resultControls != NULL)
- {
- /* See if there are any more pages to come */
- parserc = ldap_parse_page_control (__session.ls_conn,
- resultControls, NULL,
- &(ctx->ec_cookie));
- ldap_controls_free (resultControls);
- stat = NSS_STATUS_NOTFOUND;
- }
- else
- {
- stat = NSS_STATUS_NOTFOUND;
- }
-#else
- stat = NSS_STATUS_NOTFOUND;
-#endif /* LDAP_MORE_RESULTS_TO_RETURN */
- ctx->ec_res = NULL;
- ctx->ec_msgid = -1;
- }
- break;
- default:
- stat = NSS_STATUS_UNAVAIL;
- break;
- }
- }
-#ifdef LDAP_RES_SEARCH_REFERENCE
- while (rc == LDAP_RES_SEARCH_REFERENCE);
-#else
- while (0);
-#endif /* LDAP_RES_SEARCH_REFERENCE */
-
- if (stat == NSS_STATUS_SUCCESS)
- time (&__session.ls_timestamp);
-
- debug ("<== do_result");
-
- return stat;
-}
-
-/*
- * This function initializes an enumeration context.
- *
- * It could be done from the default constructor, under Solaris, but we
- * delay it until the setXXent() function is called.
- */
-struct ent_context *
-_nss_ldap_ent_context_init_locked (struct ent_context ** pctx)
-{
- struct ent_context *ctx;
-
- debug ("==> _nss_ldap_ent_context_init_locked");
-
- ctx = *pctx;
-
- if (ctx == NULL)
- {
- ctx = (struct ent_context *) malloc (sizeof (*ctx));
- if (ctx == NULL)
- {
- debug ("<== _nss_ldap_ent_context_init_locked");
- return NULL;
- }
- *pctx = ctx;
- }
- else
- {
- if (ctx->ec_res != NULL)
- {
- ldap_msgfree (ctx->ec_res);
- }
- if (ctx->ec_cookie != NULL)
- {
- ber_bvfree (ctx->ec_cookie);
- }
- if (ctx->ec_msgid > -1 && do_result (ctx, LDAP_MSG_ONE) == NSS_STATUS_SUCCESS)
- {
- ldap_abandon (__session.ls_conn, ctx->ec_msgid);
- }
- }
-
- ctx->ec_cookie = NULL;
- ctx->ec_res = NULL;
- ctx->ec_msgid = -1;
- ctx->ec_sd = NULL;
-
- LS_INIT (ctx->ec_state);
-
- debug ("<== _nss_ldap_ent_context_init_locked");
-
- return ctx;
-}
-
-/*
- * Clears a given context; we require the caller
- * to acquire the lock.
- */
-void
-_nss_ldap_ent_context_release (struct ent_context * ctx)
-{
- debug ("==> _nss_ldap_ent_context_release");
-
- if (ctx == NULL)
- {
- debug ("<== _nss_ldap_ent_context_release");
- return;
- }
-
- if (ctx->ec_res != NULL)
- {
- ldap_msgfree (ctx->ec_res);
- ctx->ec_res = NULL;
- }
-
- /*
- * Abandon the search if there were more results to fetch.
- */
- if (ctx->ec_msgid > -1 && do_result (ctx, LDAP_MSG_ONE) == NSS_STATUS_SUCCESS)
- {
- ldap_abandon (__session.ls_conn, ctx->ec_msgid);
- ctx->ec_msgid = -1;
- }
-
- if (ctx->ec_cookie != NULL)
- {
- ber_bvfree (ctx->ec_cookie);
- ctx->ec_cookie = NULL;
- }
-
- ctx->ec_sd = NULL;
-
- LS_INIT (ctx->ec_state);
-
- if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_CONNECT_POLICY_ONESHOT))
- {
- do_close ();
- }
-
- debug ("<== _nss_ldap_ent_context_release");
-
- return;
-}
-
-/*
- * AND or OR a set of filters.
- */
-static enum nss_status
-do_aggregate_filter (const char **values,
- enum ldap_args_types type,
- const char *filterprot, char *bufptr, size_t buflen)
-{
- enum nss_status stat;
- const char **valueP;
-
- assert (buflen > sizeof ("(|)"));
-
- bufptr[0] = '(';
- bufptr[1] = (type == LA_TYPE_STRING_LIST_AND) ? '&' : '|';
-
- bufptr += 2;
- buflen -= 2;
-
- for (valueP = values; *valueP != NULL; valueP++)
- {
- size_t len;
- char filter[LDAP_FILT_MAXSIZ], escapedBuf[LDAP_FILT_MAXSIZ];
-
- stat =
- _nss_ldap_escape_string (*valueP, escapedBuf, sizeof (escapedBuf));
- if (stat != NSS_STATUS_SUCCESS)
- return stat;
-
- snprintf (filter, sizeof (filter), filterprot, escapedBuf);
- len = strlen (filter);
-
- if (buflen < len + 1 /* ')' */ )
- return NSS_STATUS_TRYAGAIN;
-
- memcpy (bufptr, filter, len);
- bufptr[len] = '\0';
- bufptr += len;
- buflen -= len;
- }
-
- if (buflen < 2)
- return NSS_STATUS_TRYAGAIN;
-
- *bufptr++ = ')';
- *bufptr++ = '\0';
-
- buflen -= 2;
-
- return NSS_STATUS_SUCCESS;
-}
-
-/*
- * Do the necessary formatting to create a string filter.
- */
-static enum nss_status
-do_filter (const struct ldap_args * args, const char *filterprot,
- struct ldap_service_search_descriptor * sd, char *userBuf,
- size_t userBufSiz, char **dynamicUserBuf, const char **retFilter)
-{
- char buf1[LDAP_FILT_MAXSIZ], buf2[LDAP_FILT_MAXSIZ];
- char *filterBufP, filterBuf[LDAP_FILT_MAXSIZ];
- size_t filterSiz;
- enum nss_status stat = NSS_STATUS_SUCCESS;
-
- debug ("==> do_filter");
-
- *dynamicUserBuf = NULL;
-
- if (args != NULL && args->la_type != LA_TYPE_NONE)
- {
- /* choose what to use for temporary storage */
-
- if (sd != NULL && sd->lsd_filter != NULL)
- {
- filterBufP = filterBuf;
- filterSiz = sizeof (filterBuf);
- }
- else
- {
- filterBufP = userBuf;
- filterSiz = userBufSiz;
- }
-
- switch (args->la_type)
- {
- case LA_TYPE_STRING:
- stat = _nss_ldap_escape_string (args->la_arg1.la_string, buf1,
- sizeof (buf1));
- if (stat != NSS_STATUS_SUCCESS)
- break;
-
- snprintf (filterBufP, filterSiz, filterprot, buf1);
- break;
- case LA_TYPE_NUMBER:
- snprintf (filterBufP, filterSiz, filterprot,
- args->la_arg1.la_number);
- break;
- case LA_TYPE_STRING_AND_STRING:
- stat = _nss_ldap_escape_string (args->la_arg1.la_string, buf1,
- sizeof (buf1));
- if (stat != NSS_STATUS_SUCCESS)
- break;
-
- stat = _nss_ldap_escape_string (args->la_arg2.la_string, buf2,
- sizeof (buf2));
- if (stat != NSS_STATUS_SUCCESS)
- break;
-
- snprintf (filterBufP, filterSiz, filterprot, buf1, buf2);
- break;
- case LA_TYPE_NUMBER_AND_STRING:
- stat = _nss_ldap_escape_string (args->la_arg2.la_string, buf1,
- sizeof (buf1));
- if (stat != NSS_STATUS_SUCCESS)
- break;
-
- snprintf (filterBufP, filterSiz, filterprot,
- args->la_arg1.la_number, buf1);
- break;
- case LA_TYPE_STRING_LIST_OR:
- case LA_TYPE_STRING_LIST_AND:
- do
- {
- stat = do_aggregate_filter (args->la_arg1.la_string_list,
- args->la_type,
- filterprot, filterBufP, filterSiz);
- if (stat == NSS_STATUS_TRYAGAIN)
- {
- filterBufP = *dynamicUserBuf = realloc (*dynamicUserBuf,
- 2 * filterSiz);
- if (filterBufP == NULL)
- return NSS_STATUS_UNAVAIL;
- filterSiz *= 2;
- }
- }
- while (stat == NSS_STATUS_TRYAGAIN);
- break;
- default:
- return NSS_STATUS_UNAVAIL;
- break;
- }
-
- if (stat != NSS_STATUS_SUCCESS)
- return stat;
-
- /*
- * This code really needs to be cleaned up.
- */
- if (sd != NULL && sd->lsd_filter != NULL)
- {
- size_t filterBufPLen = strlen (filterBufP);
-
- /* remove trailing bracket */
- if (filterBufP[filterBufPLen - 1] == ')')
- filterBufP[filterBufPLen - 1] = '\0';
-
- if (*dynamicUserBuf != NULL)
- {
- char *oldDynamicUserBuf = *dynamicUserBuf;
- size_t dynamicUserBufSiz;
-
- dynamicUserBufSiz = filterBufPLen + strlen (sd->lsd_filter) +
- sizeof ("())");
- *dynamicUserBuf = malloc (dynamicUserBufSiz);
- if (*dynamicUserBuf == NULL)
- {
- free (oldDynamicUserBuf);
- return NSS_STATUS_UNAVAIL;
- }
-
- snprintf (*dynamicUserBuf, dynamicUserBufSiz, "%s(%s))",
- filterBufP, sd->lsd_filter);
- free (oldDynamicUserBuf);
- }
- else
- {
- snprintf (userBuf, userBufSiz, "%s(%s))",
- filterBufP, sd->lsd_filter);
- }
- }
-
- if (*dynamicUserBuf != NULL)
- *retFilter = *dynamicUserBuf;
- else
- *retFilter = userBuf;
- }
- else
- {
- /* no arguments, probably an enumeration filter */
- if (sd != NULL && sd->lsd_filter != NULL)
- {
- snprintf (userBuf, userBufSiz, "(&%s(%s))",
- filterprot, sd->lsd_filter);
- *retFilter = userBuf;
- }
- else
- {
- *retFilter = filterprot;
- }
- }
-
- debug (":== do_filter: %s", *retFilter);
-
- debug ("<== do_filter");
-
- return NSS_STATUS_SUCCESS;
-}
-
-/*
- * Function to call either do_search() or do_search_s() with
- * reconnection logic.
- */
-static enum nss_status
-do_with_reconnect (const char *base, int scope,
- const char *filter, const char **attrs, int sizelimit,
- void *private, search_func_t search_func)
-{
- int rc = LDAP_UNAVAILABLE, tries = 0, backoff = 0;
- int hard = 1, start_uri = 0, log = 0;
- enum nss_status stat = NSS_STATUS_UNAVAIL;
- int maxtries;
-
- debug ("==> do_with_reconnect");
-
- /* caller must successfully call do_init() first */
- assert (__session.ls_config != NULL);
-
- maxtries = __session.ls_config->ldc_reconnect_maxconntries +
- __session.ls_config->ldc_reconnect_tries;
-
- while (stat == NSS_STATUS_UNAVAIL && hard && tries < maxtries)
- {
- if (tries >= __session.ls_config->ldc_reconnect_maxconntries)
- {
- if (backoff == 0)
- backoff = __session.ls_config->ldc_reconnect_sleeptime;
- else if (backoff < __session.ls_config->ldc_reconnect_maxsleeptime)
- backoff *= 2;
-
- syslog (LOG_AUTHPRIV | LOG_INFO,
- "nss_ldap: reconnecting to LDAP server (sleeping %d seconds)...",
- backoff);
- (void) sleep (backoff);
- }
- else if (tries > 1)
- {
- /* Don't sleep, reconnect immediately. */
- syslog (LOG_AUTHPRIV | LOG_INFO, "nss_ldap: reconnecting to LDAP server...");
- }
-
- /* For each "try", attempt to connect to all specified URIs */
- start_uri = __session.ls_current_uri;
- do
- {
- stat = do_open ();
- if (stat == NSS_STATUS_SUCCESS)
- {
- stat = do_map_error (search_func (base, scope, filter,
- attrs, sizelimit, private));
- }
- if (stat != NSS_STATUS_UNAVAIL)
- break;
-
- log++;
-
- /* test in case config file could not be read */
- if (__session.ls_config != NULL)
- {
- assert (__session.ls_config->
- ldc_uris[__session.ls_current_uri] != NULL);
-
- __session.ls_current_uri++;
-
- if (__session.ls_config->ldc_uris[__session.ls_current_uri] ==
- NULL)
- __session.ls_current_uri = 0;
- }
- }
- while (__session.ls_current_uri != start_uri);
-
- if (stat == NSS_STATUS_UNAVAIL)
- {
- do_close ();
-
- /*
- * If a soft reconnect policy is specified, then do not
- * try to reconnect to the LDAP server if it is down.
- */
- if (__session.ls_config->ldc_reconnect_pol == LP_RECONNECT_SOFT)
- hard = 0;
-
- /*
- * If the file /lib/init/rw/libnss-ldap.bind_policy_soft exists,
- * then ignore the actual bind_policy definition and use the
- * soft semantics. This file should only exist during early
- * boot and late shutdown, points at which the networking or
- * the LDAP server itself are likely to be unavailable anyway.
- */
- if (access("/lib/init/rw/libnss-ldap.bind_policy_soft",R_OK) == 0)
- hard = 0;
-
- ++tries;
- }
- }
-
- switch (stat)
- {
- case NSS_STATUS_UNAVAIL:
- syslog (LOG_AUTHPRIV | LOG_ERR, "nss_ldap: could not search LDAP server - %s",
- ldap_err2string (rc));
- break;
- case NSS_STATUS_TRYAGAIN:
- syslog (LOG_AUTHPRIV | LOG_ERR,
- "nss_ldap: could not %s %sconnect to LDAP server - %s",
- hard ? "hard" : "soft", tries ? "re" : "",
- ldap_err2string (rc));
- stat = NSS_STATUS_UNAVAIL;
- break;
- case NSS_STATUS_SUCCESS:
- if (log)
- {
- char *uri = __session.ls_config->ldc_uris[__session.ls_current_uri];
-
- if (uri == NULL)
- uri = "(null)";
-
- if (tries)
- syslog (LOG_AUTHPRIV | LOG_INFO,
- "nss_ldap: reconnected to LDAP server %s after %d attempt%s",
- uri, tries, (tries == 1) ? "" : "s");
- else
- syslog (LOG_AUTHPRIV | LOG_INFO, "nss_ldap: reconnected to LDAP server %s", uri);
- }
- time (&__session.ls_timestamp);
- break;
- default:
- break;
- }
-
- debug ("<== do_with_reconnect");
- return stat;
-}
-
-/*
- * Synchronous search function. Don't call this directly;
- * always wrap calls to this with do_with_reconnect(), or,
- * better still, use _nss_ldap_search_s().
- */
-static int
-do_search_s (const char *base, int scope,
- const char *filter, const char **attrs, int sizelimit,
- LDAPMessage ** res)
-{
- int rc;
- struct timeval tv, *tvp;
-
- debug ("==> do_search_s");
-
- ldap_set_option (__session.ls_conn, LDAP_OPT_SIZELIMIT,
- (void *) &sizelimit);
-
- if (__session.ls_config->ldc_timelimit == LDAP_NO_LIMIT)
- {
- tvp = NULL;
- }
- else
- {
- tv.tv_sec = __session.ls_config->ldc_timelimit;
- tv.tv_usec = 0;
- tvp = &tv;
- }
-
- rc = ldap_search_st (__session.ls_conn, base, scope, filter,
- (char **) attrs, 0, tvp, res);
-
- debug ("<== do_search_s");
-
- return rc;
-}
-
-/*
- * Asynchronous search function. Don't call this directly;
- * always wrap calls to this with do_with_reconnect(), or,
- * better still, use _nss_ldap_search().
- */
-static int
-do_search (const char *base, int scope,
- const char *filter, const char **attrs, int sizelimit, int *msgid)
-{
- int rc;
- LDAPControl *serverCtrls[2];
- LDAPControl **pServerCtrls;
-
- debug ("==> do_search");
-
-#ifdef HAVE_LDAP_SEARCH_EXT
- if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_PAGED_RESULTS))
- {
- rc = ldap_create_page_control (__session.ls_conn,
- __session.ls_config->ldc_pagesize,
- NULL, 0, &serverCtrls[0]);
- if (rc != LDAP_SUCCESS)
- return rc;
-
- serverCtrls[1] = NULL;
- pServerCtrls = serverCtrls;
- }
- else
- {
- pServerCtrls = NULL;
- }
-
- rc = ldap_search_ext (__session.ls_conn, base, scope, filter,
- (char **) attrs, 0, pServerCtrls, NULL,
- LDAP_NO_LIMIT, sizelimit, msgid);
-
- if (pServerCtrls != NULL)
- {
- ldap_control_free (serverCtrls[0]);
- serverCtrls[0] = NULL;
- }
-
-#else
- ldap_set_option (__session.ls_conn, LDAP_OPT_SIZELIMIT,
- (void *) &sizelimit);
-
- *msgid = ldap_search (__session.ls_conn, base, scope, filter,
- (char **) attrs, 0);
- if (*msgid < 0)
- {
- if (ldap_get_option
- (__session.ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
- {
- rc = LDAP_UNAVAILABLE;
- }
- }
- else
- {
- rc = LDAP_SUCCESS;
- }
-#endif /* HAVE_LDAP_SEARCH_EXT */
-
- debug ("<== do_search");
-
- return rc;
-}
-
-static void
-do_map_errno (enum nss_status status, int *errnop)
-{
- switch (status)
- {
- case NSS_STATUS_TRYAGAIN:
- *errnop = ERANGE;
- break;
- case NSS_STATUS_NOTFOUND:
- *errnop = ENOENT;
- break;
- case NSS_STATUS_SUCCESS:
- default:
- *errnop = 0;
- }
-}
-
-/*
- * Tries parser function "parser" on entries, calling do_result()
- * to retrieve them from the LDAP server until one parses
- * correctly or there is an exceptional condition.
- */
-static enum nss_status
-do_parse (struct ent_context * ctx, void *result, char
- *buffer, size_t buflen, int *errnop, parser_t parser)
-{
- enum nss_status parseStat = NSS_STATUS_NOTFOUND;
-
- debug ("==> do_parse");
-
- /*
- * if ec_state.ls_info.ls_index is non-zero, then we don't collect another
- * entry off the LDAP chain, and instead refeed the existing result to
- * the parser. Once the parser has finished with it, it will return
- * NSS_STATUS_NOTFOUND and reset the index to -1, at which point we'll retrieve
- * another entry.
- */
- do
- {
- enum nss_status resultStat = NSS_STATUS_SUCCESS;
-
- if (ctx->ec_state.ls_retry == 0 &&
- (ctx->ec_state.ls_type == LS_TYPE_KEY
- || ctx->ec_state.ls_info.ls_index == -1))
- {
- resultStat = do_result (ctx, LDAP_MSG_ONE);
- }
-
- if (resultStat != NSS_STATUS_SUCCESS)
- {
- /* Could not get a result; bail */
- parseStat = resultStat;
- break;
- }
-
- /*
- * We have an entry; now, try to parse it.
- *
- * If we do not parse the entry because of a schema
- * violation, the parser should return NSS_STATUS_NOTFOUND.
- * We'll keep on trying subsequent entries until we
- * find one which is parseable, or exhaust avialable
- * entries, whichever is first.
- */
- parseStat = parser (ctx->ec_res, &ctx->ec_state, result,
- buffer, buflen);
-
- /* hold onto the state if we're out of memory XXX */
- ctx->ec_state.ls_retry = (parseStat == NSS_STATUS_TRYAGAIN && buffer != NULL ? 1 : 0);
-
- /* free entry is we're moving on */
- if (ctx->ec_state.ls_retry == 0 &&
- (ctx->ec_state.ls_type == LS_TYPE_KEY
- || ctx->ec_state.ls_info.ls_index == -1))
- {
- /* we don't need the result anymore, ditch it. */
- ldap_msgfree (ctx->ec_res);
- ctx->ec_res = NULL;
- }
- }
- while (parseStat == NSS_STATUS_NOTFOUND);
-
- do_map_errno (parseStat, errnop);
-
- debug ("<== do_parse");
-
- return parseStat;
-}
-
-/*
- * Parse, fetching reuslts from chain instead of server.
- */
-static enum nss_status
-do_parse_s (struct ent_context * ctx, void *result, char
- *buffer, size_t buflen, int *errnop, parser_t parser)
-{
- enum nss_status parseStat = NSS_STATUS_NOTFOUND;
- LDAPMessage *e = NULL;
-
- debug ("==> do_parse_s");
-
- /*
- * if ec_state.ls_info.ls_index is non-zero, then we don't collect another
- * entry off the LDAP chain, and instead refeed the existing result to
- * the parser. Once the parser has finished with it, it will return
- * NSS_STATUS_NOTFOUND and reset the index to -1, at which point we'll retrieve
- * another entry.
- */
- do
- {
- if (ctx->ec_state.ls_retry == 0 &&
- (ctx->ec_state.ls_type == LS_TYPE_KEY
- || ctx->ec_state.ls_info.ls_index == -1))
- {
- if (e == NULL)
- e = ldap_first_entry (__session.ls_conn, ctx->ec_res);
- else
- e = ldap_next_entry (__session.ls_conn, e);
- }
-
- if (e == NULL)
- {
- /* Could not get a result; bail */
- parseStat = NSS_STATUS_NOTFOUND;
- break;
- }
-
- /*
- * We have an entry; now, try to parse it.
- *
- * If we do not parse the entry because of a schema
- * violation, the parser should return NSS_STATUS_NOTFOUND.
- * We'll keep on trying subsequent entries until we
- * find one which is parseable, or exhaust avialable
- * entries, whichever is first.
- */
- parseStat = parser (e, &ctx->ec_state, result, buffer, buflen);
-
- /* hold onto the state if we're out of memory XXX */
- ctx->ec_state.ls_retry = (parseStat == NSS_STATUS_TRYAGAIN && buffer != NULL ? 1 : 0);
- }
- while (parseStat == NSS_STATUS_NOTFOUND);
-
- do_map_errno (parseStat, errnop);
-
- debug ("<== do_parse_s");
-
- return parseStat;
-}
-
-/*
- * Read an entry from the directory, a la X.500. This is used
- * for functions that need to retrieve attributes from a DN,
- * such as the RFC2307bis group expansion function.
- */
-enum nss_status
-_nss_ldap_read (const char *dn, const char **attributes, LDAPMessage ** res)
-{
- return do_with_reconnect (dn, LDAP_SCOPE_BASE, "(objectclass=*)",
- attributes, 1, /* sizelimit */ res,
- (search_func_t) do_search_s);
-}
-
-/*
- * Simple wrapper around ldap_get_values(). Requires that
- * session is already established.
- */
-char **
-_nss_ldap_get_values (LDAPMessage * e, const char *attr)
-{
- if (__session.ls_state != LS_CONNECTED_TO_DSA)
- {
- return NULL;
- }
- assert (__session.ls_conn != NULL);
-
- return ldap_get_values (__session.ls_conn, e, (char *) attr);
-}
-
-/*
- * Simple wrapper around ldap_get_dn(). Requires that
- * session is already established.
- */
-char *
-_nss_ldap_get_dn (LDAPMessage * e)
-{
- if (__session.ls_state != LS_CONNECTED_TO_DSA)
- {
- return NULL;
- }
- assert (__session.ls_conn != NULL);
-
- return ldap_get_dn (__session.ls_conn, e);
-}
-
-/*
- * Simple wrapper around ldap_first_entry(). Requires that
- * session is already established.
- */
-LDAPMessage *
-_nss_ldap_first_entry (LDAPMessage * res)
-{
- if (__session.ls_state != LS_CONNECTED_TO_DSA)
- {
- return NULL;
- }
- assert (__session.ls_conn != NULL);
-
- return ldap_first_entry (__session.ls_conn, res);
-}
-
-/*
- * Simple wrapper around ldap_next_entry(). Requires that
- * session is already established.
- */
-LDAPMessage *
-_nss_ldap_next_entry (LDAPMessage * res)
-{
- if (__session.ls_state != LS_CONNECTED_TO_DSA)
- {
- return NULL;
- }
- assert (__session.ls_conn != NULL);
-
- return ldap_next_entry (__session.ls_conn, res);
-}
-
-char *
-_nss_ldap_first_attribute (LDAPMessage * entry, BerElement ** berptr)
-{
- if (__session.ls_state != LS_CONNECTED_TO_DSA)
- {
- return NULL;
- }
- assert (__session.ls_conn != NULL);
-
- return ldap_first_attribute (__session.ls_conn, entry, berptr);
-}
-
-char *
-_nss_ldap_next_attribute (LDAPMessage * entry, BerElement * ber)
-{
- if (__session.ls_state != LS_CONNECTED_TO_DSA)
- {
- return NULL;
- }
- assert (__session.ls_conn != NULL);
-
- return ldap_next_attribute (__session.ls_conn, entry, ber);
-}
-
-/*
- * The generic synchronous lookup cover function.
- * Assumes caller holds lock.
- */
-enum nss_status
-_nss_ldap_search_s (const struct ldap_args * args,
- const char *filterprot, enum ldap_map_selector sel, const
- char **user_attrs, int sizelimit, LDAPMessage ** res)
-{
- char sdBase[LDAP_FILT_MAXSIZ];
- const char *base = NULL;
- char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
- const char **attrs, *filter;
- int scope;
- enum nss_status stat;
- struct ldap_service_search_descriptor *sd = NULL;
-
- debug ("==> _nss_ldap_search_s");
-
- stat = do_init ();
- if (stat != NSS_STATUS_SUCCESS)
- {
- debug ("<== _nss_ldap_search_s");
- return stat;
- }
-
- /* Set some reasonable defaults. */
- base = __session.ls_config->ldc_base;
- scope = __session.ls_config->ldc_scope;
- attrs = NULL;
-
- if (args != NULL && args->la_base != NULL)
- {
- sel = LM_NONE;
- base = args->la_base;
- }
-
- if (sel < LM_NONE)
- {
- sd = __session.ls_config->ldc_sds[sel];
- next:
- if (sd != NULL)
- {
- size_t len = strlen (sd->lsd_base);
- if (sd->lsd_base[len - 1] == ',')
- {
- /* is relative */
- snprintf (sdBase, sizeof (sdBase),
- "%s%s", sd->lsd_base,
- __session.ls_config->ldc_base);
- base = sdBase;
- }
- else
- {
- base = sd->lsd_base;
- }
-
- if (sd->lsd_scope != -1)
- {
- scope = sd->lsd_scope;
- }
- }
- attrs = __session.ls_config->ldc_attrtab[sel];
- }
-
- stat =
- do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
- &dynamicFilterBuf, &filter);
- if (stat != NSS_STATUS_SUCCESS)
- return stat;
-
- stat = do_with_reconnect (base, scope, filter,
- (user_attrs != NULL) ? user_attrs : attrs,
- sizelimit, res, (search_func_t) do_search_s);
-
- if (dynamicFilterBuf != NULL)
- {
- free (dynamicFilterBuf);
- dynamicFilterBuf = NULL;
- }
-
- /* If no entry was returned, try the next search descriptor. */
- if (sd != NULL && sd->lsd_next != NULL)
- {
- if (stat == NSS_STATUS_NOTFOUND ||
- (stat == NSS_STATUS_SUCCESS &&
- ldap_first_entry (__session.ls_conn, *res) == NULL))
- {
- sd = sd->lsd_next;
- goto next;
- }
- }
-
- debug ("<== _nss_ldap_search_s");
-
- return stat;
-}
-
-/*
- * The generic lookup cover function (asynchronous).
- * Assumes caller holds lock.
- */
-static enum nss_status
-_nss_ldap_search (const struct ldap_args * args,
- const char *filterprot, enum ldap_map_selector sel,
- const char **user_attrs, int sizelimit, int *msgid,
- struct ldap_service_search_descriptor ** csd)
-{
- char sdBase[LDAP_FILT_MAXSIZ];
- const char *base = NULL;
- char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
- const char **attrs, *filter;
- int scope;
- enum nss_status stat;
- struct ldap_service_search_descriptor *sd = NULL;
-
- debug ("==> _nss_ldap_search");
-
- *msgid = -1;
-
- stat = do_init ();
- if (stat != NSS_STATUS_SUCCESS)
- {
- debug ("<== _nss_ldap_search");
- return stat;
- }
-
- /* Set some reasonable defaults. */
- base = __session.ls_config->ldc_base;
- scope = __session.ls_config->ldc_scope;
- attrs = NULL;
-
- if (args != NULL && args->la_base != NULL)
- {
- sel = LM_NONE;
- base = args->la_base;
- }
-
- if (sel < LM_NONE || *csd != NULL)
- {
- /*
- * If we were chasing multiple descriptors and there are none left,
- * just quit with NSS_STATUS_NOTFOUND.
- */
- if (*csd != NULL)
- {
- sd = (*csd)->lsd_next;
- if (sd == NULL)
- return NSS_STATUS_NOTFOUND;
- }
- else
- {
- sd = __session.ls_config->ldc_sds[sel];
- }
-
- *csd = sd;
-
- if (sd != NULL)
- {
- size_t len = strlen (sd->lsd_base);
- if (sd->lsd_base[len - 1] == ',')
- {
- /* is relative */
- snprintf (sdBase, sizeof (sdBase), "%s%s", sd->lsd_base,
- __session.ls_config->ldc_base);
- base = sdBase;
- }
- else
- {
- base = sd->lsd_base;
- }
-
- if (sd->lsd_scope != -1)
- {
- scope = sd->lsd_scope;
- }
- }
- attrs = __session.ls_config->ldc_attrtab[sel];
- }
-
- stat =
- do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
- &dynamicFilterBuf, &filter);
- if (stat != NSS_STATUS_SUCCESS)
- return stat;
-
- stat = do_with_reconnect (base, scope, filter,
- (user_attrs != NULL) ? user_attrs : attrs,
- sizelimit, msgid, (search_func_t) do_search);
-
- if (dynamicFilterBuf != NULL)
- free (dynamicFilterBuf);
-
- debug ("<== _nss_ldap_search");
-
- return stat;
-}
-
-#ifdef HAVE_LDAP_SEARCH_EXT
-static enum nss_status
-do_next_page (const struct ldap_args * args,
- const char *filterprot, enum ldap_map_selector sel, int
- sizelimit, int *msgid, struct berval *pCookie)
-{
- char sdBase[LDAP_FILT_MAXSIZ];
- const char *base = NULL;
- char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
- const char **attrs, *filter;
- int scope;
- enum nss_status stat;
- struct ldap_service_search_descriptor *sd = NULL;
- LDAPControl *serverctrls[2] = {
- NULL, NULL
- };
-
- /* Set some reasonable defaults. */
- base = __session.ls_config->ldc_base;
- scope = __session.ls_config->ldc_scope;
- attrs = NULL;
-
- if (args != NULL && args->la_base != NULL)
- {
- sel = LM_NONE;
- base = args->la_base;
- }
-
- if (sel < LM_NONE)
- {
- sd = __session.ls_config->ldc_sds[sel];
- if (sd != NULL)
- {
- size_t len = strlen (sd->lsd_base);
- if (sd->lsd_base[len - 1] == ',')
- {
- snprintf (sdBase, sizeof (sdBase), "%s%s", sd->lsd_base,
- __session.ls_config->ldc_base);
- base = sdBase;
- }
- else
- {
- base = sd->lsd_base;
- }
-
- if (sd->lsd_scope != -1)
- {
- scope = sd->lsd_scope;
- }
- }
- attrs = __session.ls_config->ldc_attrtab[sel];
- }
-
- stat =
- do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
- &dynamicFilterBuf, &filter);
- if (stat != NSS_STATUS_SUCCESS)
- {
- return stat;
- }
-
- stat =
- ldap_create_page_control (__session.ls_conn,
- __session.ls_config->ldc_pagesize,
- pCookie, 0, &serverctrls[0]);
- if (stat != LDAP_SUCCESS)
- {
- if (dynamicFilterBuf != NULL)
- free (dynamicFilterBuf);
- return NSS_STATUS_UNAVAIL;
- }
-
- stat =
- ldap_search_ext (__session.ls_conn, base,
- __session.ls_config->ldc_scope,
- filter,
- (char **) attrs, 0, serverctrls, NULL, LDAP_NO_LIMIT,
- sizelimit, msgid);
-
- ldap_control_free (serverctrls[0]);
- if (dynamicFilterBuf != NULL)
- free (dynamicFilterBuf);
-
- return (*msgid < 0) ? NSS_STATUS_UNAVAIL : NSS_STATUS_SUCCESS;
-}
-#endif /* HAVE_LDAP_SEARCH_EXT */
-
-/*
- * General entry point for enumeration routines.
- * This should really use the asynchronous LDAP search API to avoid
- * pulling down all the entries at once, particularly if the
- * enumeration is not completed.
- * Locks mutex.
- */
-enum nss_status
-_nss_ldap_getent (struct ent_context ** ctx,
- void *result, char *buffer, size_t buflen,
- int *errnop, const char *filterprot,
- enum ldap_map_selector sel, parser_t parser)
-{
- enum nss_status status;
-
- /*
- * we need to lock here as the context may not be thread-specific
- * data (under glibc, for example). Maybe we should make the lock part
- * of the context.
- */
-
- _nss_ldap_enter ();
- status = _nss_ldap_getent_ex (NULL, ctx, result,
- buffer, buflen,
- errnop, filterprot, sel, NULL, parser);
- _nss_ldap_leave ();
-
- return status;
-}
-
-/*
- * Internal entry point for enumeration routines.
- * Caller holds global mutex
- */
-enum nss_status
-_nss_ldap_getent_ex (struct ldap_args * args,
- struct ent_context ** ctx, void *result,
- char *buffer, size_t buflen, int *errnop,
- const char *filterprot,
- enum ldap_map_selector sel,
- const char **user_attrs, parser_t parser)
-{
- enum nss_status stat = NSS_STATUS_SUCCESS;
-
- debug ("==> _nss_ldap_getent_ex");
-
- if (*ctx == NULL || (*ctx)->ec_msgid < 0)
- {
- /*
- * implicitly call setent() if this is the first time
- * or there is no active search
- */
- if (_nss_ldap_ent_context_init_locked (ctx) == NULL)
- {
- debug ("<== _nss_ldap_getent_ex");
- return NSS_STATUS_UNAVAIL;
- }
- }
-
-next:
- /*
- * If ctx->ec_msgid < 0, then we haven't searched yet. Let's do it!
- */
- if ((*ctx)->ec_msgid < 0)
- {
- int msgid;
-
- stat = _nss_ldap_search (args, filterprot, sel, user_attrs,
- LDAP_NO_LIMIT, &msgid, &(*ctx)->ec_sd);
- if (stat != NSS_STATUS_SUCCESS)
- {
- debug ("<== _nss_ldap_getent_ex");
- return stat;
- }
-
- (*ctx)->ec_msgid = msgid;
- }
-
- stat = do_parse (*ctx, result, buffer, buflen, errnop, parser);
-
-#ifdef HAVE_LDAP_SEARCH_EXT
- if (stat == NSS_STATUS_NOTFOUND)
- {
- /* Is there another page of results? */
- if ((*ctx)->ec_cookie != NULL && (*ctx)->ec_cookie->bv_len != 0)
- {
- int msgid;
-
- stat =
- do_next_page (NULL, filterprot, sel, LDAP_NO_LIMIT, &msgid,
- (*ctx)->ec_cookie);
- if (stat != NSS_STATUS_SUCCESS)
- {
- debug ("<== _nss_ldap_getent_ex");
- return stat;
- }
- (*ctx)->ec_msgid = msgid;
- stat = do_parse (*ctx, result, buffer, buflen, errnop, parser);
- }
- }
-#endif /* HAVE_LDAP_SEARCH_EXT */
-
- if (stat == NSS_STATUS_NOTFOUND && (*ctx)->ec_sd != NULL)
- {
- (*ctx)->ec_msgid = -1;
- goto next;
- }
-
- debug ("<== _nss_ldap_getent_ex");
-
- return stat;
-}
-
-/*
- * General match function.
- * Locks mutex.
- */
-enum nss_status
-_nss_ldap_getbyname (struct ldap_args * args,
- void *result, char *buffer, size_t buflen, int
- *errnop, const char *filterprot,
- enum ldap_map_selector sel, parser_t parser)
-{
- enum nss_status stat = NSS_STATUS_NOTFOUND;
- struct ent_context ctx;
-
- _nss_ldap_enter ();
-
- debug ("==> _nss_ldap_getbyname");
-
- ctx.ec_msgid = -1;
- ctx.ec_cookie = NULL;
-
- stat = _nss_ldap_search_s (args, filterprot, sel, NULL, 1, &ctx.ec_res);
- if (stat != NSS_STATUS_SUCCESS)
- {
- _nss_ldap_leave ();
- debug ("<== _nss_ldap_getbyname");
- return stat;
- }
-
- /*
- * we pass this along for the benefit of the services parser,
- * which uses it to figure out which protocol we really wanted.
- * we only pass the second argument along, as that's what we need
- * in services.
- */
- LS_INIT (ctx.ec_state);
- ctx.ec_state.ls_type = LS_TYPE_KEY;
- ctx.ec_state.ls_info.ls_key = args->la_arg2.la_string;
-
- stat = do_parse_s (&ctx, result, buffer, buflen, errnop, parser);
-
- _nss_ldap_ent_context_release (&ctx);
-
- debug ("<== _nss_ldap_getbyname");
-
- /* moved unlock here to avoid race condition bug #49 */
- _nss_ldap_leave ();
-
- return stat;
-}
-
-static int NEW_do_parse_s(struct ent_context *ctx,FILE *fp,NEWparser_t parser)
-{
- int parseStat=NSLCD_RESULT_NOTFOUND;
- LDAPMessage *e=NULL;
- /*
- * if ec_state.ls_info.ls_index is non-zero, then we don't collect another
- * entry off the LDAP chain, and instead refeed the existing result to
- * the parser. Once the parser has finished with it, it will return
- * NSS_STATUS_NOTFOUND and reset the index to -1, at which point we'll retrieve
- * another entry.
- */
- do
- {
- if (ctx->ec_state.ls_retry == 0 &&
- (ctx->ec_state.ls_type == LS_TYPE_KEY
- || ctx->ec_state.ls_info.ls_index == -1))
- {
- if (e == NULL)
- e = ldap_first_entry (__session.ls_conn, ctx->ec_res);
- else
- e = ldap_next_entry (__session.ls_conn, e);
- }
- if (e == NULL)
- {
- /* Could not get a result; bail */
- parseStat=NSLCD_RESULT_NOTFOUND;
- break;
- }
- /*
- * We have an entry; now, try to parse it.
- *
- * If we do not parse the entry because of a schema
- * violation, the parser should return NSS_STATUS_NOTFOUND.
- * We'll keep on trying subsequent entries until we
- * find one which is parseable, or exhaust avialable
- * entries, whichever is first.
- */
- parseStat=parser(e,&ctx->ec_state,fp);
- /* hold onto the state if we're out of memory XXX */
- ctx->ec_state.ls_retry=0;
- }
- while (parseStat==NSLCD_RESULT_NOTFOUND);
- return parseStat;
-}
-
-
-int _nss_ldap_searchbyname(
- struct ldap_args *args,const char *filterprot,
- enum ldap_map_selector sel,FILE *fp,NEWparser_t parser)
-{
- int stat;
- struct ent_context ctx;
- int32_t tmpint32;
-
- _nss_ldap_enter();
-
- ctx.ec_msgid=-1;
- ctx.ec_cookie=NULL;
-
- stat=nss2nslcd(_nss_ldap_search_s(args,filterprot,sel,NULL,1,&ctx.ec_res));
- /* write the result code */
- WRITE_INT32(fp,stat);
- /* bail on nothing found */
- if (stat!=NSLCD_RESULT_SUCCESS)
- {
- _nss_ldap_leave();
- return 1;
- }
- /*
- * we pass this along for the benefit of the services parser,
- * which uses it to figure out which protocol we really wanted.
- * we only pass the second argument along, as that's what we need
- * in services.
- */
- LS_INIT(ctx.ec_state);
- ctx.ec_state.ls_type=LS_TYPE_KEY;
- ctx.ec_state.ls_info.ls_key=args->la_arg2.la_string;
- /* call the parser for the result */
- stat=NEW_do_parse_s(&ctx,fp,parser);
-
- _nss_ldap_ent_context_release(&ctx);
-
- /* moved unlock here to avoid race condition bug #49 */
- _nss_ldap_leave();
-
- return stat;
-}
-
-/*
- * These functions are called from within the parser, where it is assumed
- * to be safe to use the connection and the respective message.
- */
-
-/*
- * Assign all values, bar omitvalue (if not NULL), to *valptr.
- */
-enum nss_status
-_nss_ldap_assign_attrvals (LDAPMessage * e,
- const char *attr, const char *omitvalue,
- char ***valptr, char **pbuffer, size_t *
- pbuflen, size_t * pvalcount)
-{
- char **vals;
- char **valiter;
- int valcount;
- char **p = NULL;
-
- register int buflen = *pbuflen;
- register char *buffer = *pbuffer;
-
- if (pvalcount != NULL)
- {
- *pvalcount = 0;
- }
-
- if (__session.ls_conn == NULL)
- {
- return NSS_STATUS_UNAVAIL;
- }
-
- vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
-
- valcount = (vals == NULL) ? 0 : ldap_count_values (vals);
- if (bytesleft (buffer, buflen, char *) < (valcount + 1) * sizeof (char *))
- {
- ldap_value_free (vals);
- return NSS_STATUS_TRYAGAIN;
- }
-
- align (buffer, buflen, char *);
- p = *valptr = (char **) buffer;
-
- buffer += (valcount + 1) * sizeof (char *);
- buflen -= (valcount + 1) * sizeof (char *);
-
- if (valcount == 0)
- {
- *p = NULL;
- *pbuffer = buffer;
- *pbuflen = buflen;
- return NSS_STATUS_SUCCESS;
- }
-
- valiter = vals;
-
- while (*valiter != NULL)
- {
- int vallen;
- char *elt = NULL;
-
- if (omitvalue != NULL && strcmp (*valiter, omitvalue) == 0)
- {
- valcount--;
- }
- else
- {
- vallen = strlen (*valiter);
- if (buflen < (size_t) (vallen + 1))
- {
- ldap_value_free (vals);
- return NSS_STATUS_TRYAGAIN;
- }
-
- /* copy this value into the next block of buffer space */
- elt = buffer;
- buffer += vallen + 1;
- buflen -= vallen + 1;
-
- strncpy (elt, *valiter, vallen);
- elt[vallen] = '\0';
- *p = elt;
- p++;
- }
- valiter++;
- }
-
- *p = NULL;
- *pbuffer = buffer;
- *pbuflen = buflen;
-
- if (pvalcount != NULL)
- {
- *pvalcount = valcount;
- }
-
- ldap_value_free (vals);
- return NSS_STATUS_SUCCESS;
-}
-
-int _nss_ldap_write_attrvals(FILE *fp,LDAPMessage *e,const char *attr)
-{
- char **vals;
- int valcount;
- int i;
- int32_t tmpint32;
- /* log */
- log_log(LOG_DEBUG,"_nss_ldap_write_attrvals(%s)",attr);
- /* check if we have a connection */
- if (__session.ls_conn==NULL)
- return NSLCD_RESULT_UNAVAIL;
- /* get the values and the number of values */
- vals=ldap_get_values(__session.ls_conn,e,(char *)attr);
- valcount=(vals==NULL)?0:ldap_count_values(vals);
- /* write number of entries */
- WRITE_INT32(fp,valcount);
- /* write the entries themselves */
- for (i=0;i<valcount;i++)
- {
- WRITE_STRING(fp,vals[i]);
- }
- if (vals!=NULL)
- ldap_value_free(vals);
- return NSLCD_RESULT_SUCCESS;
-}
-
-/* Assign a single value to *valptr. */
-enum nss_status
-_nss_ldap_assign_attrval (LDAPMessage * e,
- const char *attr, char **valptr, char **buffer,
- size_t * buflen)
-{
- char **vals;
- int vallen;
- const char *ovr, *def;
-
- ovr = OV (attr);
- if (ovr != NULL)
- {
- vallen = strlen (ovr);
- if (*buflen < (size_t) (vallen + 1))
- {
- return NSS_STATUS_TRYAGAIN;
- }
-
- *valptr = *buffer;
-
- strncpy (*valptr, ovr, vallen);
- (*valptr)[vallen] = '\0';
-
- *buffer += vallen + 1;
- *buflen -= vallen + 1;
-
- return NSS_STATUS_SUCCESS;
- }
-
- if (__session.ls_conn == NULL)
- {
- return NSS_STATUS_UNAVAIL;
- }
-
- vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
- if (vals == NULL)
- {
- def = DF (attr);
- if (def != NULL)
- {
- vallen = strlen (def);
- if (*buflen < (size_t) (vallen + 1))
- {
- return NSS_STATUS_TRYAGAIN;
- }
-
- *valptr = *buffer;
-
- strncpy (*valptr, def, vallen);
- (*valptr)[vallen] = '\0';
-
- *buffer += vallen + 1;
- *buflen -= vallen + 1;
-
- return NSS_STATUS_SUCCESS;
- }
- else
- {
- return NSS_STATUS_NOTFOUND;
- }
- }
-
- vallen = strlen (*vals);
- if (*buflen < (size_t) (vallen + 1))
- {
- ldap_value_free (vals);
- return NSS_STATUS_TRYAGAIN;
- }
-
- *valptr = *buffer;
-
- strncpy (*valptr, *vals, vallen);
- (*valptr)[vallen] = '\0';
-
- *buffer += vallen + 1;
- *buflen -= vallen + 1;
-
- ldap_value_free (vals);
-
- return NSS_STATUS_SUCCESS;
-}
-
-const char *
-_nss_ldap_locate_userpassword (char **vals)
-{
- const char *token = NULL;
- size_t token_length = 0;
- char **valiter;
- const char *pwd = NULL;
-
- if (__config != NULL)
- {
- switch (__config->ldc_password_type)
- {
- case LU_RFC2307_USERPASSWORD:
- token = "{CRYPT}";
- token_length = sizeof ("{CRYPT}") - 1;
- break;
- case LU_RFC3112_AUTHPASSWORD:
- token = "CRYPT$";
- token_length = sizeof ("CRYPT$") - 1;
- break;
- case LU_OTHER_PASSWORD:
- break;
- }
- }
-
- if (vals != NULL)
- {
- for (valiter = vals; *valiter != NULL; valiter++)
- {
- if (token_length == 0 ||
- strncasecmp (*valiter, token, token_length) == 0)
- {
- pwd = *valiter;
- break;
- }
- }
- }
-
- if (pwd == NULL)
- pwd = "*";
- else
- pwd += token_length;
-
- return pwd;
-}
-
-/*
- * Assign a single value to *valptr, after examining userPassword for
- * a syntactically suitable value.
- */
-enum nss_status
-_nss_ldap_assign_userpassword (LDAPMessage * e,
- const char *attr, char **valptr,
- char **buffer, size_t * buflen)
-{
- char **vals;
- const char *pwd;
- int vallen;
-
- debug ("==> _nss_ldap_assign_userpassword");
-
- if (__session.ls_conn == NULL)
- {
- return NSS_STATUS_UNAVAIL;
- }
-
- vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
- pwd = _nss_ldap_locate_userpassword (vals);
-
- vallen = strlen (pwd);
-
- if (*buflen < (size_t) (vallen + 1))
- {
- if (vals != NULL)
- {
- ldap_value_free (vals);
- }
- debug ("<== _nss_ldap_assign_userpassword");
- return NSS_STATUS_TRYAGAIN;
- }
-
- *valptr = *buffer;
-
- strncpy (*valptr, pwd, vallen);
- (*valptr)[vallen] = '\0';
-
- *buffer += vallen + 1;
- *buflen -= vallen + 1;
-
- if (vals != NULL)
- {
- ldap_value_free (vals);
- }
-
- debug ("<== _nss_ldap_assign_userpassword");
-
- return NSS_STATUS_SUCCESS;
-}
-
-enum nss_status
-_nss_ldap_oc_check (LDAPMessage * e, const char *oc)
-{
- char **vals, **valiter;
- enum nss_status ret = NSS_STATUS_NOTFOUND;
-
- if (__session.ls_conn == NULL)
- {
- return NSS_STATUS_UNAVAIL;
- }
-
- vals = ldap_get_values (__session.ls_conn, e, AT (objectClass));
- if (vals != NULL)
- {
- for (valiter = vals; *valiter != NULL; valiter++)
- {
- if (strcasecmp (*valiter, oc) == 0)
- {
- ret = NSS_STATUS_SUCCESS;
- break;
- }
- }
- }
-
- if (vals != NULL)
- {
- ldap_value_free (vals);
- }
-
- return ret;
-}
-
-#ifdef HAVE_SHADOW_H
-int
-_nss_ldap_shadow_date (const char *val)
-{
- int date;
-
- if (__config->ldc_shadow_type == LS_AD_SHADOW)
- {
- date = atoll (val) / 864000000000LL - 134774LL;
- date = (date > 99999) ? 99999 : date;
- }
- else
- {
- date = atol (val);
- }
-
- return date;
-}
-
-void
-_nss_ldap_shadow_handle_flag (struct spwd *sp)
-{
- if (__config->ldc_shadow_type == LS_AD_SHADOW)
- {
- if (sp->sp_flag & UF_DONT_EXPIRE_PASSWD)
- sp->sp_max = 99999;
- sp->sp_flag = 0;
- }
-}
-#endif /* HAVE_SHADOW_H */
-
-const char *
-_nss_ldap_map_at (enum ldap_map_selector sel, const char *attribute)
-{
- const char *mapped = NULL;
- enum nss_status stat;
-
- stat = _nss_ldap_map_get (__config, sel, MAP_ATTRIBUTE, attribute, &mapped);
-
- return (stat == NSS_STATUS_SUCCESS) ? mapped : attribute;
-}
-
-const char *
-_nss_ldap_unmap_at (enum ldap_map_selector sel, const char *attribute)
-{
- const char *mapped = NULL;
- enum nss_status stat;
-
- stat = _nss_ldap_map_get (__config, sel, MAP_ATTRIBUTE_REVERSE, attribute, &mapped);
-
- return (stat == NSS_STATUS_SUCCESS) ? mapped : attribute;
-}
-
-const char *
-_nss_ldap_map_oc (enum ldap_map_selector sel, const char *objectclass)
-{
- const char *mapped = NULL;
- enum nss_status stat;
-
- stat = _nss_ldap_map_get (__config, sel, MAP_OBJECTCLASS, objectclass, &mapped);
-
- return (stat == NSS_STATUS_SUCCESS) ? mapped : objectclass;
-}
-
-const char *
-_nss_ldap_unmap_oc (enum ldap_map_selector sel, const char *objectclass)
-{
- const char *mapped = NULL;
- enum nss_status stat;
-
- stat = _nss_ldap_map_get (__config, sel, MAP_OBJECTCLASS_REVERSE, objectclass, &mapped);
-
- return (stat == NSS_STATUS_SUCCESS) ? mapped : objectclass;
-}
-
-const char *
-_nss_ldap_map_ov (const char *attribute)
-{
- const char *value = NULL;
-
- _nss_ldap_map_get (__config, LM_NONE, MAP_OVERRIDE, attribute, &value);
-
- return value;
-}
-
-const char *
-_nss_ldap_map_df (const char *attribute)
-{
- const char *value = NULL;
-
- _nss_ldap_map_get (__config, LM_NONE, MAP_DEFAULT, attribute, &value);
-
- return value;
-}
-
-enum nss_status
-_nss_ldap_map_put (struct ldap_config * config,
- enum ldap_map_selector sel,
- enum ldap_map_type type,
- const char *from,
- const char *to)
-{
- struct ldap_datum key, val;
- void **map;
- enum nss_status stat;
-
- switch (type)
- {
- case MAP_ATTRIBUTE:
- /* special handling for attribute mapping */ if (strcmp
- (from,
- "userPassword") == 0)
- {
- if (strcasecmp (to, "userPassword") == 0)
- config->ldc_password_type = LU_RFC2307_USERPASSWORD;
- else if (strcasecmp (to, "authPassword") == 0)
- config->ldc_password_type = LU_RFC3112_AUTHPASSWORD;
- else
- config->ldc_password_type = LU_OTHER_PASSWORD;
- }
- else if (strcmp (from, "shadowLastChange") == 0)
- {
- if (strcasecmp (to, "shadowLastChange") == 0)
- config->ldc_shadow_type = LS_RFC2307_SHADOW;
- else if (strcasecmp (to, "pwdLastSet") == 0)
- config->ldc_shadow_type = LS_AD_SHADOW;
- else
- config->ldc_shadow_type = LS_OTHER_SHADOW;
- }
- break;
- case MAP_OBJECTCLASS:
- case MAP_OVERRIDE:
- case MAP_DEFAULT:
- break;
- default:
- return NSS_STATUS_NOTFOUND;
- break;
- }
-
- assert (sel <= LM_NONE);
- map = &config->ldc_maps[sel][type];
- assert (*map != NULL);
-
- NSS_LDAP_DATUM_ZERO (&key);
- key.data = (void *) from;
- key.size = strlen (from) + 1;
-
- NSS_LDAP_DATUM_ZERO (&val);
- val.data = (void *) to;
- val.size = strlen (to) + 1;
-
- stat = _nss_ldap_db_put (*map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
- if (stat == NSS_STATUS_SUCCESS &&
- (type == MAP_ATTRIBUTE || type == MAP_OBJECTCLASS))
- {
- type = (type == MAP_ATTRIBUTE) ? MAP_ATTRIBUTE_REVERSE : MAP_OBJECTCLASS_REVERSE;
- map = &config->ldc_maps[sel][type];
-
- stat = _nss_ldap_db_put (*map, NSS_LDAP_DB_NORMALIZE_CASE, &val, &key);
- }
-
- return stat;
-}
-
-enum nss_status
-_nss_ldap_map_get (struct ldap_config * config,
- enum ldap_map_selector sel,
- enum ldap_map_type type,
- const char *from, const char **to)
-{
- struct ldap_datum key, val;
- void *map;
- enum nss_status stat;
-
- if (config == NULL || sel > LM_NONE || type > MAP_MAX)
- {
- return NSS_STATUS_NOTFOUND;
- }
-
- map = config->ldc_maps[sel][type];
- assert (map != NULL);
-
- NSS_LDAP_DATUM_ZERO (&key);
- key.data = from;
- key.size = strlen (from) + 1;
-
- NSS_LDAP_DATUM_ZERO (&val);
-
- stat = _nss_ldap_db_get (map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
- if (stat == NSS_STATUS_NOTFOUND && sel != LM_NONE)
- {
- map = config->ldc_maps[LM_NONE][type];
- assert (map != NULL);
- stat = _nss_ldap_db_get (map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
- }
-
- if (stat == NSS_STATUS_SUCCESS)
- *to = (char *) val.data;
- else
- *to = NULL;
-
- return stat;
-}
-
-/*
- * Proxy bind support for AIX. Very simple, but should do
- * the job.
- */
-
-struct ldap_proxy_bind_args
-{
- char *binddn;
- const char *bindpw;
-};
-
-
-#if LDAP_SET_REBIND_PROC_ARGS < 3
-static struct ldap_proxy_bind_args __proxy_args = { NULL, NULL };
-#endif
-
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-#if LDAP_SET_REBIND_PROC_ARGS == 3
-static int
-do_proxy_rebind (LDAP * ld, LDAP_CONST char *url, ber_tag_t request,
- ber_int_t msgid, void *arg)
-#else
-static int
-do_proxy_rebind (LDAP * ld, LDAP_CONST char *url, int request,
- ber_int_t msgid)
-#endif
-{
- int timelimit;
-#if LDAP_SET_REBIND_PROC_ARGS == 3
- struct ldap_proxy_bind_args *who = (struct ldap_proxy_bind_args *) arg;
-#else
- struct ldap_proxy_bind_args *who = &__proxy_args;
-#endif
-
- timelimit = __session.ls_config->ldc_bind_timelimit;
-
- return do_bind (ld, timelimit, who->binddn, who->bindpw, 0);
-}
-#else
-#if LDAP_SET_REBIND_PROC_ARGS == 3
-static int
-do_proxy_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
- int freeit, void *arg)
-#elif LDAP_SET_REBIND_PROC_ARGS == 2
-static int
-do_proxy_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
- int freeit)
-#endif
-{
-#if LDAP_SET_REBIND_PROC_ARGS == 3
- struct ldap_proxy_bind_args *who = (struct ldap_proxy_bind_args *) arg;
-#else
- struct ldap_proxy_bind_args *who = &__proxy_args;
-#endif
- if (freeit)
- {
- if (*whop != NULL)
- free (*whop);
- if (*credp != NULL)
- free (*credp);
- }
-
- *whop = who->binddn ? strdup (who->binddn) : NULL;
- *credp = who->bindpw ? strdup (who->bindpw) : NULL;
-
- *methodp = LDAP_AUTH_SIMPLE;
-
- return LDAP_SUCCESS;
-}
-#endif
-
-enum nss_status
-_nss_ldap_proxy_bind (const char *user, const char *password)
-{
- struct ldap_args args;
- LDAPMessage *res, *e;
- enum nss_status stat;
- int rc;
-#if LDAP_SET_REBIND_PROC_ARGS == 3
- struct ldap_proxy_bind_args proxy_args_buf;
- struct ldap_proxy_bind_args *proxy_args = &proxy_args_buf;
-#else
- struct ldap_proxy_bind_args *proxy_args = &__proxy_args;
-#endif
-
- debug ("==> _nss_ldap_proxy_bind");
-
- LA_INIT (args);
- LA_TYPE (args) = LA_TYPE_STRING;
- LA_STRING (args) = user;
-
- /*
- * Binding with an empty password will always work, so don't let
- * the user in if they try that.
- */
- if (password == NULL || password[0] == '\0')
- {
- debug ("<== _nss_ldap_proxy_bind (empty password not permitted)");
- /* XXX overload */
- return NSS_STATUS_TRYAGAIN;
- }
-
- _nss_ldap_enter ();
-
- stat = _nss_ldap_search_s (&args, _nss_ldap_filt_getpwnam,
- LM_PASSWD, NULL, 1, &res);
- if (stat == NSS_STATUS_SUCCESS)
- {
- e = _nss_ldap_first_entry (res);
- if (e != NULL)
- {
- proxy_args->binddn = _nss_ldap_get_dn (e);
- proxy_args->bindpw = password;
-
- if (proxy_args->binddn != NULL)
- {
- /* Use our special rebind procedure. */
-#if LDAP_SET_REBIND_PROC_ARGS == 3
- ldap_set_rebind_proc (__session.ls_conn, do_proxy_rebind, NULL);
-#elif LDAP_SET_REBIND_PROC_ARGS == 2
- ldap_set_rebind_proc (__session.ls_conn, do_proxy_rebind);
-#endif
-
- debug (":== _nss_ldap_proxy_bind: %s", proxy_args->binddn);
-
- rc = do_bind (__session.ls_conn,
- __session.ls_config->ldc_bind_timelimit,
- proxy_args->binddn, proxy_args->bindpw, 0);
- switch (rc)
- {
- case LDAP_INVALID_CREDENTIALS:
- /* XXX overload */
- stat = NSS_STATUS_TRYAGAIN;
- break;
- case LDAP_NO_SUCH_OBJECT:
- stat = NSS_STATUS_NOTFOUND;
- break;
- case LDAP_SUCCESS:
- stat = NSS_STATUS_SUCCESS;
- break;
- default:
- stat = NSS_STATUS_UNAVAIL;
- break;
- }
- /*
- * Close the connection, don't want to continue
- * being bound as this user or using this rebind proc.
- */
- do_close ();
- ldap_memfree (proxy_args->binddn);
- }
- else
- {
- stat = NSS_STATUS_NOTFOUND;
- }
- proxy_args->binddn = NULL;
- proxy_args->bindpw = NULL;
- }
- else
- {
- stat = NSS_STATUS_NOTFOUND;
- }
- ldap_msgfree (res);
- }
-
- _nss_ldap_leave ();
-
- debug ("<== _nss_ldap_proxy_bind");
-
- return stat;
-}
-
-const char **
-_nss_ldap_get_attributes (enum ldap_map_selector sel)
-{
- const char **attrs = NULL;
-
- debug ("==> _nss_ldap_get_attributes");
-
- if (sel < LM_NONE)
- {
- if (do_init () != NSS_STATUS_SUCCESS)
- {
- debug ("<== _nss_ldap_get_attributes (init failed)");
- return NULL;
- }
-
- attrs = __session.ls_config->ldc_attrtab[sel];
- }
-
- debug ("<== _nss_ldap_get_attributes");
-
- return attrs;
-}
-
-int
-_nss_ldap_test_config_flag (unsigned int flag)
-{
- if (__config != NULL && (__config->ldc_flags & flag) != 0)
- return 1;
-
- return 0;
-}
-
-int
-_nss_ldap_test_initgroups_ignoreuser (const char *user)
-{
- char **p;
-
- if (__config == NULL)
- return 0;
-
- if (__config->ldc_initgroups_ignoreusers == NULL)
- return 0;
-
- for (p = __config->ldc_initgroups_ignoreusers; *p != NULL; p++)
- {
- if (strcmp (*p, user) == 0)
- return 1;
- }
-
- return 0;
-}