From fbc5ecfb8cf86d753b7c9a3b5b549a8f279666ab Mon Sep 17 00:00:00 2001 From: Arthur de Jong Date: Thu, 21 Dec 2006 19:55:55 +0000 Subject: rename server directory to nslcd git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-ldapd@196 ef36b2f9-881f-0410-afb5-c4e39611909c --- server/ldap-nss.c | 4032 ----------------------------------------------------- 1 file changed, 4032 deletions(-) delete mode 100644 server/ldap-nss.c (limited to 'server/ldap-nss.c') 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 -#include -#include -#include -#ifdef HAVE_STRINGS_H -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_UN_H -#include -#endif -#include -#ifdef HAVE_LBER_H -#include -#endif -#ifdef HAVE_LDAP_H -#include -#endif -#ifdef HAVE_LDAP_SSL_H -#include -#endif -#ifdef HAVE_GSSLDAP_H -#include -#endif -#ifdef HAVE_GSSSASL_H -#include -#endif -#ifdef HAVE_MALLOC_H -#include -#endif -#if defined(HAVE_THREAD_H) -#include -#elif defined(HAVE_PTHREAD_H) -#include -#endif -/* Try to handle systems with both SASL libraries installed */ -#if defined(HAVE_SASL_SASL_H) && defined(HAVE_SASL_AUXPROP_REQUEST) -#include -#elif defined(HAVE_SASL_H) -#include -#endif -#ifdef HAVE_GSSAPI_H -#include -#elif defined(HAVE_GSSAPI_GSSAPI_KRB5_H) -#include -#include -#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 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 (¤t_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 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;ildc_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; -} -- cgit v1.2.3