"Fossies" - the Fresh Open Source Software Archive

Member "nss_ldap-265/ldap-nss.c" (6 Nov 2009, 105007 Bytes) of package /linux/privat/old/nss_ldap-265.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* Copyright (C) 1997-2006 Luke Howard.
    2    This file is part of the nss_ldap library.
    3    Contributed by Luke Howard, <lukeh@padl.com>, 1997.
    4 
    5    The nss_ldap library is free software; you can redistribute it and/or
    6    modify it under the terms of the GNU Library General Public License as
    7    published by the Free Software Foundation; either version 2 of the
    8    License, or (at your option) any later version.
    9 
   10    The nss_ldap library is distributed in the hope that it will be useful,
   11    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13    Library General Public License for more details.
   14 
   15    You should have received a copy of the GNU Library General Public
   16    License along with the nss_ldap library; see the file COPYING.LIB.  If not,
   17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   18    Boston, MA 02111-1307, USA.
   19  */
   20 
   21 static char rcsId[] =
   22   "$Id: ldap-nss.c,v 2.302 2009/11/06 10:15:26 lukeh Exp $";
   23 
   24 #include "config.h"
   25 
   26 #ifdef HAVE_PORT_BEFORE_H
   27 #include <port_before.h>
   28 #endif
   29 
   30 #if defined(HAVE_THREAD_H) && !defined(_AIX)
   31 #include <thread.h>
   32 #elif defined(HAVE_PTHREAD_H)
   33 #include <pthread.h>
   34 #endif
   35 
   36 #include <assert.h>
   37 #include <stdlib.h>
   38 #include <unistd.h>
   39 #include <string.h>
   40 #ifdef HAVE_STRINGS_H
   41 #include <strings.h>
   42 #endif
   43 #include <stdio.h>
   44 #include <syslog.h>
   45 #include <signal.h>
   46 #include <fcntl.h>
   47 #include <sys/time.h>
   48 #include <sys/socket.h>
   49 #include <sys/param.h>
   50 #include <errno.h>
   51 #ifdef HAVE_SYS_UN_H
   52 #include <sys/un.h>
   53 #endif
   54 #include <netinet/in.h>
   55 #ifdef HAVE_LBER_H
   56 #include <lber.h>
   57 #endif
   58 #ifdef HAVE_LDAP_H
   59 #include <ldap.h>
   60 #endif
   61 #ifdef HAVE_LDAP_SSL_H
   62 #include <ldap_ssl.h>
   63 #endif
   64 #ifdef HAVE_GSSLDAP_H
   65 #include <gssldap.h>
   66 #endif
   67 #ifdef HAVE_GSSSASL_H
   68 #include <gsssasl.h>
   69 #endif
   70 
   71 /* Try to handle systems with both SASL libraries installed */
   72 #if defined(HAVE_SASL_SASL_H) && defined(HAVE_SASL_AUXPROP_REQUEST)
   73 #include <sasl/sasl.h>
   74 #elif defined(HAVE_SASL_H)
   75 #include <sasl.h>
   76 #endif
   77 
   78 #ifndef HAVE_SNPRINTF
   79 #include "snprintf.h"
   80 #endif
   81 #ifdef HAVE_GSSAPI_H
   82 #include <gssapi.h>
   83 #elif defined(HAVE_GSSAPI_GSSAPI_KRB5_H)
   84 #include <gssapi/gssapi.h>
   85 #include <gssapi/gssapi_krb5.h>
   86 #endif
   87 #ifdef CONFIGURE_KRB5_CCNAME
   88 #include <krb5.h>
   89 #endif
   90 
   91 #include "ldap-nss.h"
   92 #include "ltf.h"
   93 #include "util.h"
   94 #include "dnsconfig.h"
   95 #include "pagectrl.h"
   96 
   97 #if defined(HAVE_THREAD_H) && !defined(_AIX)
   98 #ifdef HAVE_PTHREAD_ATFORK
   99 #undef HAVE_PTHREAD_ATFORK
  100 #endif
  101 #endif
  102 
  103 /* how many messages to retrieve results for */
  104 #ifndef LDAP_MSG_ONE
  105 #define LDAP_MSG_ONE            0x00
  106 #endif
  107 #ifndef LDAP_MSG_ALL
  108 #define LDAP_MSG_ALL            0x01
  109 #endif
  110 #ifndef LDAP_MSG_RECEIVED
  111 #define LDAP_MSG_RECEIVED       0x02
  112 #endif
  113 
  114 #ifdef HAVE_LDAP_LD_FREE
  115 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
  116 extern int ldap_ld_free (LDAP * ld, int close, LDAPControl **,
  117              LDAPControl **);
  118 #else
  119 extern int ldap_ld_free (LDAP * ld, int close);
  120 #endif /* OPENLDAP 2.x */
  121 #endif /* HAVE_LDAP_LD_FREE */
  122 
  123 NSS_LDAP_DEFINE_LOCK (__lock);
  124 
  125 /*
  126  * the configuration is read by the first call to do_open().
  127  * Pointers to elements of the list are passed around but should not
  128  * be freed.
  129  */
  130 static char __configbuf[NSS_LDAP_CONFIG_BUFSIZ];
  131 static ldap_config_t *__config = NULL;
  132 
  133 #ifdef HAVE_SIGACTION
  134 static struct sigaction __stored_handler;
  135 static int __sigaction_retval = -1;
  136 #else
  137 static void (*__sigpipe_handler) (int) = SIG_DFL;
  138 #endif /* HAVE_SIGACTION */
  139 
  140 /*
  141  * Global LDAP session.
  142  */
  143 static ldap_session_t __session = { NULL, NULL, 0, LS_UNINITIALIZED };
  144 
  145 #if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
  146 static pthread_once_t __once = PTHREAD_ONCE_INIT;
  147 #endif
  148 
  149 #ifdef LBER_OPT_LOG_PRINT_FILE
  150 static FILE *__debugfile;
  151 #endif /* LBER_OPT_LOG_PRINT_FILE */
  152 
  153 #ifndef HAVE_PTHREAD_ATFORK
  154 /* 
  155  * Process ID that opened the session.
  156  */
  157 static pid_t __pid = -1;
  158 #endif
  159 static uid_t __euid = -1;
  160 
  161 #ifdef HAVE_LDAPSSL_CLIENT_INIT
  162 static int __ssl_initialized = 0;
  163 #endif /* HAVE_LDAPSSL_CLIENT_INIT */
  164 
  165 #if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
  166 /*
  167  * Prepare for fork(); lock mutex.
  168  */
  169 static void do_atfork_prepare (void);
  170 
  171 /*
  172  * Forked in parent, unlock mutex.
  173  */
  174 static void do_atfork_parent (void);
  175 
  176 /*
  177  * Forked in child; close LDAP socket, unlock mutex.
  178  */
  179 static void do_atfork_child (void);
  180 
  181 /*
  182  * Install handlers for atfork, called once.
  183  */
  184 static void do_atfork_setup (void);
  185 #endif
  186 
  187 /*
  188  * Close the global session, sending an unbind.
  189  */
  190 static void do_close (void);
  191 
  192 /*
  193  * Close the global session without sending an unbind.
  194  */
  195 static void do_close_no_unbind (void);
  196 
  197 /*
  198  * Disable keepalive on a LDAP connection's socket.
  199  */
  200 static void do_set_sockopts (void);
  201 
  202 /*
  203  * TLS routines: set global SSL session options.
  204  */
  205 #if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS) || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
  206 static int do_ssl_options (ldap_config_t * cfg);
  207 static int do_start_tls (ldap_session_t * session);
  208 #endif
  209 
  210 /*
  211  * Read configuration file and initialize schema
  212  */
  213 static NSS_STATUS do_init (void);
  214 
  215 /*
  216  * Open the global session
  217  */
  218 static NSS_STATUS do_open (void);
  219 
  220 /*
  221  * Perform an asynchronous search.
  222  */
  223 static int do_search (const char *base, int scope,
  224               const char *filter, const char **attrs,
  225               int sizelimit, int *);
  226 
  227 /*
  228  * Perform a synchronous search.
  229  */
  230 static int do_search_s (const char *base, int scope,
  231             const char *filter, const char **attrs,
  232             int sizelimit, LDAPMessage **);
  233 
  234 /*
  235  * Fetch an LDAP result.
  236  */
  237 static NSS_STATUS do_result (ent_context_t * ctx, int all);
  238 
  239 /*
  240  * Format a filter given a prototype.
  241  */
  242 static NSS_STATUS do_filter (const ldap_args_t * args, const char *filterprot,
  243                  ldap_service_search_descriptor_t * sd,
  244                  char *filter, size_t filterlen,
  245                  char **dynamicFilter, const char **retFilter);
  246 
  247 /*
  248  * Parse a result, fetching new results until a successful parse
  249  * or exceptional condition.
  250  */
  251 static NSS_STATUS do_parse (ent_context_t * ctx, void *result, char *buffer,
  252                 size_t buflen, int *errnop, parser_t parser);
  253 
  254 /*
  255  * Parse a result, fetching results from the result chain 
  256  * rather than the server.
  257  */
  258 static NSS_STATUS do_parse_s (ent_context_t * ctx, void *result, char *buffer,
  259                   size_t buflen, int *errnop, parser_t parser);
  260 
  261 /*
  262  * Function to be braced by reconnect harness. Used so we
  263  * can apply the reconnect code to both asynchronous and
  264  * synchronous searches.
  265  */
  266 typedef int (*search_func_t) (const char *, int, const char *,
  267                   const char **, int, void *);
  268 
  269 /*
  270  * Do a search with a reconnect harness.
  271  */
  272 static NSS_STATUS
  273 do_with_reconnect (const char *base, int scope,
  274            const char *filter, const char **attrs, int sizelimit,
  275            void *private, search_func_t func);
  276 
  277 /*
  278  * Map error from LDAP status code to NSS status code
  279  */
  280 static NSS_STATUS do_map_error (int rc);
  281 
  282 /*
  283  * Do a bind with a defined timeout
  284  */
  285 static int do_bind (LDAP * ld, int timelimit, const char *dn, const char *pw,
  286             int with_sasl);
  287 
  288 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
  289 static int do_sasl_interact (LDAP * ld, unsigned flags, void *defaults,
  290                  void *p);
  291 #endif
  292 
  293 static int
  294 do_get_our_socket(int *sd);
  295 
  296 static int
  297 do_dupfd(int oldfd, int newfd);
  298 
  299 static void
  300 do_drop_connection(int sd, int closeSd);
  301 
  302 static NSS_STATUS
  303 do_map_error (int rc)
  304 {
  305   NSS_STATUS stat;
  306 
  307   switch (rc)
  308     {
  309     case LDAP_SUCCESS:
  310     case LDAP_SIZELIMIT_EXCEEDED:
  311     case LDAP_TIMELIMIT_EXCEEDED:
  312       stat = NSS_SUCCESS;
  313       break;
  314     case LDAP_NO_SUCH_ATTRIBUTE:
  315     case LDAP_UNDEFINED_TYPE:
  316     case LDAP_INAPPROPRIATE_MATCHING:
  317     case LDAP_CONSTRAINT_VIOLATION:
  318     case LDAP_TYPE_OR_VALUE_EXISTS:
  319     case LDAP_INVALID_SYNTAX:
  320     case LDAP_NO_SUCH_OBJECT:
  321     case LDAP_ALIAS_PROBLEM:
  322     case LDAP_INVALID_DN_SYNTAX:
  323     case LDAP_IS_LEAF:
  324     case LDAP_ALIAS_DEREF_PROBLEM:
  325     case LDAP_FILTER_ERROR:
  326       stat = NSS_NOTFOUND;
  327       break;
  328     case LDAP_SERVER_DOWN:
  329     case LDAP_TIMEOUT:
  330     case LDAP_UNAVAILABLE:
  331     case LDAP_BUSY:
  332 #ifdef LDAP_CONNECT_ERROR
  333     case LDAP_CONNECT_ERROR:
  334 #endif /* LDAP_CONNECT_ERROR */
  335     case LDAP_LOCAL_ERROR:
  336     case LDAP_INVALID_CREDENTIALS:
  337     default:
  338       stat = NSS_UNAVAIL;
  339       break;
  340     }
  341   return stat;
  342 }
  343 
  344 /*
  345  * Rebind functions.
  346  */
  347 
  348 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
  349 #if LDAP_SET_REBIND_PROC_ARGS == 3
  350 static int
  351 do_rebind (LDAP * ld, LDAP_CONST char *url, ber_tag_t request,
  352        ber_int_t msgid, void *arg)
  353 #else
  354 static int
  355 do_rebind (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid)
  356 #endif
  357 {
  358   char *who, *cred;
  359   int timelimit;
  360   int with_sasl = 0;
  361 
  362   if (geteuid () == 0 && __session.ls_config->ldc_rootbinddn)
  363     {
  364       who = __session.ls_config->ldc_rootbinddn;
  365 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
  366       with_sasl = __session.ls_config->ldc_rootusesasl;
  367       if (with_sasl)
  368     {
  369       cred = __session.ls_config->ldc_rootsaslid;
  370     }
  371       else
  372     {
  373 #endif
  374       cred = __session.ls_config->ldc_rootbindpw;
  375 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
  376     }
  377 #endif
  378     }
  379   else
  380     {
  381       who = __session.ls_config->ldc_binddn;
  382 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
  383       with_sasl = __session.ls_config->ldc_usesasl;
  384       if (with_sasl)
  385     {
  386       cred = __session.ls_config->ldc_saslid;
  387     }
  388       else
  389     {
  390 #endif
  391       cred = __session.ls_config->ldc_bindpw;
  392 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
  393     }
  394 #endif
  395     }
  396 
  397   timelimit = __session.ls_config->ldc_bind_timelimit;
  398 
  399 #ifdef HAVE_LDAP_START_TLS_S
  400   if (__session.ls_config->ldc_ssl_on == SSL_START_TLS)
  401     {
  402       int version;
  403 
  404       if (ldap_get_option
  405       (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
  406        &version) == LDAP_OPT_SUCCESS)
  407     {
  408       if (version < LDAP_VERSION3)
  409         {
  410           version = LDAP_VERSION3;
  411           ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
  412                    &version);
  413         }
  414     }
  415 
  416       if (do_start_tls (&__session) == LDAP_SUCCESS)
  417     {
  418       debug ("TLS startup succeeded");
  419     }
  420       else
  421     {
  422       debug ("TLS startup failed");
  423       return NSS_UNAVAIL;
  424     }
  425     }
  426 #endif /* HAVE_LDAP_START_TLS_S */
  427 
  428   return do_bind (ld, timelimit, who, cred, with_sasl);
  429 }
  430 #else
  431 #if LDAP_SET_REBIND_PROC_ARGS == 3
  432 static int
  433 do_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
  434        int freeit, void *arg)
  435 #elif LDAP_SET_REBIND_PROC_ARGS == 2
  436 static int
  437 do_rebind (LDAP * ld, char **whop, char **credp, int *methodp, int freeit)
  438 #endif
  439 {
  440   if (freeit)
  441     {
  442       if (*whop != NULL)
  443     free (*whop);
  444       if (*credp != NULL)
  445     free (*credp);
  446     }
  447 
  448   *whop = *credp = NULL;
  449   if (geteuid () == 0 && __session.ls_config->ldc_rootbinddn)
  450     {
  451       *whop = strdup (__session.ls_config->ldc_rootbinddn);
  452       if (__session.ls_config->ldc_rootbindpw != NULL)
  453     *credp = strdup (__session.ls_config->ldc_rootbindpw);
  454     }
  455   else
  456     {
  457       if (__session.ls_config->ldc_binddn != NULL)
  458     *whop = strdup (__session.ls_config->ldc_binddn);
  459       if (__session.ls_config->ldc_bindpw != NULL)
  460     *credp = strdup (__session.ls_config->ldc_bindpw);
  461     }
  462 
  463   *methodp = LDAP_AUTH_SIMPLE;
  464 
  465   return LDAP_SUCCESS;
  466 }
  467 #endif
  468 
  469 #ifdef HAVE_NSSWITCH_H
  470 /*
  471  * Default destructor.
  472  * The entry point for this function is the destructor in the dispatch
  473  * table for the switch. Thus, it's safe to grab the mutex from this
  474  * function.
  475  */
  476 NSS_STATUS
  477 _nss_ldap_default_destr (nss_backend_t * be, void *args)
  478 {
  479   debug ("==> _nss_ldap_default_destr");
  480 
  481   if ((((nss_ldap_backend_t *) be)->state) != NULL)
  482     {
  483       _nss_ldap_enter ();
  484       _nss_ldap_ent_context_release (&(((nss_ldap_backend_t *) be)->state));
  485       _nss_ldap_leave ();
  486     }
  487 
  488   /* Ditch the backend. */
  489   free (be);
  490 
  491   debug ("<== _nss_ldap_default_destr");
  492 
  493   return NSS_SUCCESS;
  494 }
  495 
  496 /*
  497  * This is the default "constructor" which gets called from each 
  498  * constructor, in the NSS dispatch table.
  499  */
  500 NSS_STATUS
  501 _nss_ldap_default_constr (nss_ldap_backend_t * be)
  502 {
  503   debug ("==> _nss_ldap_default_constr");
  504 
  505   be->state = NULL;
  506 #ifdef HPUX
  507   __thread_mutex_init (&__lock, NULL);
  508 #endif
  509 
  510   debug ("<== _nss_ldap_default_constr");
  511 
  512   return NSS_SUCCESS;
  513 }
  514 #endif /* HAVE_NSSWITCH_H */
  515 
  516 #if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
  517 static void
  518 do_atfork_prepare (void)
  519 {
  520   debug ("==> do_atfork_prepare");
  521   _nss_ldap_enter ();
  522   debug ("<== do_atfork_prepare");
  523 }
  524 
  525 static void
  526 do_atfork_parent (void)
  527 {
  528   debug ("==> do_atfork_parent");
  529   _nss_ldap_leave ();
  530   debug ("<== do_atfork_parent");
  531 }
  532 
  533 static void
  534 do_atfork_child (void)
  535 {
  536   debug ("==> do_atfork_child");
  537   do_close_no_unbind ();
  538   _nss_ldap_leave ();
  539   debug ("<== do_atfork_child");
  540 }
  541 
  542 static void
  543 do_atfork_setup (void)
  544 {
  545   debug ("==> do_atfork_setup");
  546 
  547 #ifdef HAVE_PTHREAD_ATFORK
  548   (void) pthread_atfork (do_atfork_prepare, do_atfork_parent,
  549              do_atfork_child);
  550 #elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
  551   (void) __libc_atfork (do_atfork_prepare, do_atfork_parent, do_atfork_child);
  552 #endif
  553 
  554   debug ("<== do_atfork_setup");
  555 }
  556 #endif
  557 
  558 /*
  559  * Acquires global lock, blocks SIGPIPE.
  560  */
  561 void
  562 _nss_ldap_enter (void)
  563 {
  564 
  565 #ifdef HAVE_SIGACTION
  566   struct sigaction new_handler;
  567 
  568   memset (&new_handler, 0, sizeof (new_handler));
  569 #if 0
  570   /* XXX need to test for sa_sigaction, not on all platforms */
  571   new_handler.sa_sigaction = NULL;
  572 #endif
  573   new_handler.sa_handler = SIG_IGN;
  574   sigemptyset (&new_handler.sa_mask);
  575   new_handler.sa_flags = 0;
  576 #endif /* HAVE_SIGACTION */
  577 
  578   debug ("==> _nss_ldap_enter");
  579 
  580   NSS_LDAP_LOCK (__lock);
  581 
  582   /*
  583    * Patch for Debian Bug 130006:
  584    * ignore SIGPIPE for all LDAP operations.
  585    * 
  586    * The following bug was reintroduced in nss_ldap-213 and is fixed here:
  587    * http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=84344
  588    *
  589    * See:
  590    * http://www.gnu.org/software/libc/manual/html_node/Signal-and-Sigaction.html
  591    * for more details.
  592    */
  593 #ifdef HAVE_SIGACTION
  594   __sigaction_retval = sigaction (SIGPIPE, &new_handler, &__stored_handler);
  595 #elif defined(HAVE_SIGSET)
  596   __sigpipe_handler = sigset (SIGPIPE, SIG_IGN);
  597 #else
  598   __sigpipe_handler = signal (SIGPIPE, SIG_IGN);
  599 #endif /* HAVE_SIGSET */
  600 
  601   debug ("<== _nss_ldap_enter");
  602 }
  603 
  604 /*
  605  * Releases global mutex, releases SIGPIPE.
  606  */
  607 void
  608 _nss_ldap_leave (void)
  609 {
  610   debug ("==> _nss_ldap_leave");
  611 
  612 #ifdef HAVE_SIGACTION
  613   if (__sigaction_retval == 0)
  614     (void) sigaction (SIGPIPE, &__stored_handler, NULL);
  615 #else
  616   if (__sigpipe_handler != SIG_ERR && __sigpipe_handler != SIG_IGN)
  617     {
  618 # ifdef HAVE_SIGSET
  619       (void) sigset (SIGPIPE, __sigpipe_handler);
  620 # else
  621       (void) signal (SIGPIPE, __sigpipe_handler);
  622 # endif /* HAVE_SIGSET */
  623     }
  624 #endif /* HAVE_SIGACTION */
  625 
  626   NSS_LDAP_UNLOCK (__lock);
  627 
  628   debug ("<== _nss_ldap_leave");
  629 }
  630 
  631 static void
  632 do_set_sockopts (void)
  633 {
  634 /*
  635  * Netscape SSL-enabled LDAP library does not
  636  * return the real socket.
  637  */
  638 #ifndef HAVE_LDAPSSL_CLIENT_INIT
  639   int sd = -1;
  640 
  641   debug ("==> do_set_sockopts");
  642 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
  643   if (ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, &sd) == 0)
  644 #else
  645   if ((sd = __session.ls_conn->ld_sb.sb_sd) > 0)
  646 #endif /* LDAP_OPT_DESC */
  647     {
  648       int off = 0;
  649       NSS_LDAP_SOCKLEN_T socknamelen = sizeof (NSS_LDAP_SOCKADDR_STORAGE);
  650       NSS_LDAP_SOCKLEN_T peernamelen = sizeof (NSS_LDAP_SOCKADDR_STORAGE);
  651 
  652       (void) setsockopt (sd, SOL_SOCKET, SO_KEEPALIVE, (void *) &off,
  653              sizeof (off));
  654       (void) fcntl (sd, F_SETFD, FD_CLOEXEC);
  655       /*
  656        * NSS modules shouldn't open file descriptors that the program/utility
  657        * linked against NSS doesn't know about.  The LDAP library opens a
  658        * connection to the LDAP server transparently.  There's an edge case
  659        * where a daemon might fork a child and, being written well, closes
  660        * all its file descriptors.  This will close the socket descriptor
  661        * being used by the LDAP library!  Worse, the daemon might open many
  662        * files and sockets, eventually opening a descriptor with the same number
  663        * as that originally used by the LDAP library.  The only way to know that
  664        * this isn't "our" socket descriptor is to save the local and remote
  665        * sockaddr_in structures for later comparison.
  666        */
  667       (void) getsockname (sd, (struct sockaddr *) &__session.ls_sockname,
  668               &socknamelen);
  669       (void) getpeername (sd, (struct sockaddr *) &__session.ls_peername,
  670               &peernamelen);
  671     }
  672   debug ("<== do_set_sockopts");
  673 #endif /* HAVE_LDAPSSL_CLIENT_INIT */
  674 
  675   return;
  676 }
  677 
  678 /*
  679  * Closes connection to the LDAP server.
  680  * This assumes that we have exclusive access to __session.ls_conn,
  681  * either by some other function having acquired a lock, or by
  682  * using a thread safe libldap.
  683  */
  684 static void
  685 do_close (void)
  686 {
  687 #if defined(DEBUG) || defined(DEBUG_SOCKETS)
  688   int sd = -1;
  689 #endif
  690 
  691   debug ("==> do_close");
  692 
  693   if (__session.ls_conn != NULL)
  694     {
  695 #if defined(DEBUG) || defined(DEBUG_SOCKETS)
  696 # if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
  697       ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, &sd);
  698 # else
  699       sd = __session.ls_conn->ld_sb.sb_sd;
  700 # endif /* LDAP_OPT_DESC */
  701       syslog (LOG_INFO, "nss_ldap: closing connection %p fd %d",
  702           __session.ls_conn, sd);
  703 #endif /* DEBUG */
  704 
  705       ldap_unbind (__session.ls_conn);
  706       __session.ls_conn = NULL;
  707       __session.ls_state = LS_UNINITIALIZED;
  708     }
  709 
  710   debug ("<== do_close");
  711 }
  712 
  713 static int
  714 do_sockaddr_isequal (NSS_LDAP_SOCKADDR_STORAGE *_s1,
  715              NSS_LDAP_SOCKLEN_T _slen1,
  716              NSS_LDAP_SOCKADDR_STORAGE *_s2,
  717              NSS_LDAP_SOCKLEN_T _slen2)
  718 {
  719   int ret;
  720 
  721   if (_s1->ss_family != _s2->ss_family)
  722     return 0;
  723 
  724   if (_slen1 != _slen2)
  725     return 0;
  726 
  727   ret = 0;
  728 
  729   switch (_s1->ss_family)
  730     {
  731       case AF_INET:
  732     {
  733       struct sockaddr_in *s1 = (struct sockaddr_in *) _s1;
  734       struct sockaddr_in *s2 = (struct sockaddr_in *) _s2;
  735 
  736       ret = (s1->sin_port == s2->sin_port &&
  737          memcmp (&s1->sin_addr, &s2->sin_addr, sizeof(struct in_addr)) == 0);
  738       break;
  739     }
  740       case AF_UNIX:
  741     {
  742       struct sockaddr_un *s1 = (struct sockaddr_un *) _s1;
  743       struct sockaddr_un *s2 = (struct sockaddr_un *) _s2;
  744 
  745       ret = (memcmp (s1->sun_path, s2->sun_path,
  746              _slen1 - sizeof (_s1->ss_family)) == 0);
  747       break;
  748     }
  749 #ifdef INET6
  750       case AF_INET6:
  751     {
  752       struct sockaddr_in6 *s1 = (struct sockaddr_in6 *) _s1;
  753       struct sockaddr_in6 *s2 = (struct sockaddr_in6 *) _s2;
  754 
  755       ret = (s1->sin6_port == s2->sin6_port &&
  756          memcmp (&s1->sin6_addr, &s2->sin6_addr, sizeof(struct in6_addr)) == 0 &&
  757          s1->sin6_scope_id == s2->sin6_scope_id);
  758       break;
  759     }
  760 #endif
  761       default:
  762     ret = (memcmp (_s1, _s2, _slen1) == 0);
  763     break;
  764     }
  765 
  766   return ret;
  767 }
  768 
  769 static int
  770 do_get_our_socket(int *sd)
  771 {
  772   /*
  773    * Before freeing the LDAP context or closing the socket descriptor,
  774    * we must ensure that it is *our* socket descriptor.  See the much
  775    * lengthier description of this at the end of do_open () where the
  776    * values __session.ls_sockname and __session.ls_peername are saved.
  777    * With HAVE_LDAPSSL_CLIENT_INIT this returns 0 if the socket has
  778    * been closed or reopened, and sets *sd to the ldap socket
  779    * descriptor.. Returns 1 in all other cases.
  780    */
  781 
  782   int isOurSocket = 1;
  783 
  784 #ifndef HAVE_LDAPSSL_CLIENT_INIT
  785 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
  786   if (ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, sd) == 0)
  787 #else
  788   if ((*sd = __session.ls_conn->ld_sb.sb_sd) > 0)
  789 #endif /* LDAP_OPT_DESC */
  790     {
  791       NSS_LDAP_SOCKADDR_STORAGE sockname;
  792       NSS_LDAP_SOCKADDR_STORAGE peername;
  793       NSS_LDAP_SOCKLEN_T socknamelen = sizeof (sockname);
  794       NSS_LDAP_SOCKLEN_T peernamelen = sizeof (peername);
  795 
  796       if (getsockname (*sd, (struct sockaddr *) &sockname, &socknamelen) != 0 ||
  797       !do_sockaddr_isequal (&__session.ls_sockname,
  798                 socknamelen,
  799                 &sockname,
  800                 socknamelen))
  801         {
  802           isOurSocket = 0;
  803         }
  804       /*
  805        * XXX: We don't pay any attention to return codes in places such as
  806        * do_search_s so we never observe when the other end has disconnected
  807        * our socket.  In that case we'll get an ENOTCONN error here... and
  808        * it's best we ignore the error -- otherwise we'll leak a filedescriptor.
  809        * The correct fix would be to test error codes in many places.
  810        */
  811       else if (getpeername (*sd, (struct sockaddr *) &peername, &peernamelen) != 0)
  812     {
  813           if (errno != ENOTCONN)
  814             isOurSocket = 0;
  815     }
  816       else
  817     {
  818           isOurSocket = do_sockaddr_isequal (&__session.ls_peername,
  819                                               peernamelen,
  820                                               &peername,
  821                                               peernamelen);
  822     }
  823     }
  824 #endif /* HAVE_LDAPSSL_CLIENT_INIT */
  825   return isOurSocket;
  826 }
  827 
  828 static int
  829 do_dupfd(int oldfd, int newfd)
  830 {
  831   int d = -1;
  832   int flags;
  833 
  834   flags = fcntl(oldfd, F_GETFD);
  835 
  836   while (1)
  837     {
  838       d = (newfd > -1) ? dup2 (oldfd, newfd) : dup (oldfd);
  839       if (d > -1)
  840     break;
  841 
  842       if (errno == EBADF)
  843     return -1; /* not open */
  844 
  845       if (errno != EINTR
  846 #ifdef EBUSY
  847         && errno != EBUSY
  848 #endif
  849         )
  850     return -1;
  851   }
  852 
  853   /* duplicate close-on-exec flag */
  854   (void) fcntl (d, F_SETFD, flags);
  855 
  856   return d;
  857 }
  858 
  859 static int
  860 do_closefd(int fd)
  861 {
  862   int rc;
  863 
  864   while ((rc = close(fd)) < 0 && errno == EINTR)
  865     ;
  866 
  867   return rc;
  868 }
  869 
  870 static void
  871 do_drop_connection(int sd, int closeSd)
  872 {
  873      /* Close the LDAP connection without writing anything to the
  874     underlying socket.  The socket will be left open afterwards if
  875     closeSd is 0 */
  876 #ifndef HAVE_LDAPSSL_CLIENT_INIT
  877   {
  878     int dummyfd = -1, savedfd = -1;
  879     /*  Under OpenLDAP 2.x, ldap_set_option (..., LDAP_OPT_DESC, ...) is
  880     a no-op, so to shut down the LDAP connection without writing
  881     anything to the socket, we swap a dummy socket onto that file
  882     descriptor, and then swap the real fd back once the shutdown is
  883     done. */
  884     savedfd = do_dupfd (sd, -1);
  885     dummyfd = socket (AF_INET, SOCK_STREAM, 0);
  886     if (dummyfd > -1 && dummyfd != sd)
  887       {
  888         /* we must let dup2 close sd for us to avoid race conditions
  889          * in multithreaded code.
  890          */
  891     do_dupfd (dummyfd, sd);
  892     do_closefd (dummyfd);
  893       }
  894 
  895 #ifdef HAVE_LDAP_LD_FREE
  896 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
  897     /* XXX: when using openssl this will *ALWAYS* close the fd */
  898     (void) ldap_ld_free (__session.ls_conn, 0, NULL, NULL);
  899 #else
  900     (void) ldap_ld_free (__session.ls_conn, 0);
  901 #endif /* OPENLDAP 2.x */
  902 #else
  903     ldap_unbind (__session.ls_conn);
  904 #endif /* HAVE_LDAP_LD_FREE */
  905 
  906     /* Do we want our original sd back? */
  907     if (savedfd > -1)
  908       {
  909     if (closeSd == 0)
  910       do_dupfd (savedfd, sd);
  911         else
  912           do_closefd (sd);
  913     do_closefd (savedfd);
  914       }
  915     else
  916       {
  917         do_closefd (sd);
  918       }
  919   }
  920 #else /* No sd available */
  921   {
  922     int bogusSd = -1;
  923     if (closeSd == 0)
  924       {
  925     sd = -1; /* don't want to really close the socket */
  926 #ifdef HAVE_LDAP_LD_FREE
  927 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
  928     (void) ldap_set_option (__session.ls_conn, LDAP_OPT_DESC, &sd);
  929 #else
  930     __session.ls_conn->ld_sb.sb_sd = -1;
  931 #endif /* LDAP_OPT_DESC */
  932 #endif /* HAVE_LDAP_LD_FREE */
  933       }
  934 
  935 #ifdef HAVE_LDAP_LD_FREE
  936 
  937 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
  938     (void) ldap_ld_free (__session.ls_conn, 0, NULL, NULL);
  939 #else
  940     (void) ldap_ld_free (__session.ls_conn, 0);
  941 #endif /* OPENLDAP 2.x */
  942     
  943 #else
  944 
  945 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DESC)
  946     (void) ldap_set_option (__session.ls_conn, LDAP_OPT_DESC, &bogusSd);
  947 #else
  948     __session.ls_conn->ld_sb.sb_sd = bogusSd;
  949 #endif /* LDAP_OPT_DESC */
  950 
  951     /* hope we closed it OK! */
  952     ldap_unbind (__session.ls_conn);
  953 
  954 #endif /* HAVE_LDAP_LD_FREE */
  955     
  956   }
  957 #endif /* HAVE_LDAPSSL_CLIENT_INIT */
  958   __session.ls_conn = NULL;
  959   __session.ls_state = LS_UNINITIALIZED;
  960 
  961   return;
  962 }
  963 
  964 /*
  965  * If we've forked, then we need to open a new session.
  966  * Careful: we have the socket shared with our parent,
  967  * so we don't want to send an unbind to the server.
  968  * However, we want to close the descriptor to avoid
  969  * leaking it, and we also want to release the memory
  970  * used by __session.ls_conn. The only entry point
  971  * we have is ldap_unbind() which does both of these
  972  * things, so we use an internal API, at the expense
  973  * of compatibility.
  974  */
  975 static void
  976 do_close_no_unbind (void)
  977 {
  978   int sd = -1;
  979   int closeSd = 1;
  980 
  981   debug ("==> do_close_no_unbind");
  982 
  983   if (__session.ls_state == LS_UNINITIALIZED)
  984     {
  985       assert (__session.ls_conn == NULL);
  986       debug ("<== do_close_no_unbind (connection was not open)");
  987       return;
  988     }
  989 
  990   closeSd = do_get_our_socket (&sd);
  991 
  992 #if defined(DEBUG) || defined(DEBUG_SOCKETS)
  993   syslog (LOG_INFO, "nss_ldap: %sclosing connection (no unbind) %p fd %d",
  994       closeSd ? "" : "not ", __session.ls_conn, sd);
  995 #endif /* DEBUG */
  996 
  997   do_drop_connection(sd, closeSd);
  998 
  999   debug ("<== do_close_no_unbind");
 1000 
 1001   return;
 1002 }
 1003 
 1004 /*
 1005  * A simple alias around do_init().
 1006  */
 1007 NSS_STATUS
 1008 _nss_ldap_init (void)
 1009 {
 1010   return do_init ();
 1011 }
 1012 
 1013 /*
 1014  * A simple alias around do_close().
 1015  */
 1016 void
 1017 _nss_ldap_close (void)
 1018 {
 1019   do_close ();
 1020 }
 1021 
 1022 static NSS_STATUS
 1023 do_init_session (LDAP ** ld, const char *uri, int defport)
 1024 {
 1025   int rc;
 1026   int ldaps;
 1027   char uribuf[NSS_BUFSIZ];
 1028   char *p;
 1029   NSS_STATUS stat;
 1030 
 1031   ldaps = (strncasecmp (uri, "ldaps://", sizeof ("ldaps://") - 1) == 0);
 1032   p = strchr (uri, ':');
 1033   /* we should be looking for the second instance to find the port number */
 1034   if (p != NULL)
 1035     {
 1036       p = strchr (++p, ':');
 1037     }
 1038 
 1039 # ifdef CONFIGURE_KRB5_KEYTAB
 1040   (void)do_init_krb5_cache(__config);
 1041 # endif /* CONFIGURE_KRB5_KEYTAB */
 1042 #ifdef HAVE_LDAP_INITIALIZE
 1043   if (p == NULL && defport != 0 &&
 1044       ((ldaps && defport != LDAPS_PORT) || (!ldaps && defport != LDAP_PORT)))
 1045     {
 1046       /* No port specified in URI and non-default port specified */
 1047       snprintf (uribuf, sizeof (uribuf), "%s:%d", uri, defport);
 1048       uri = uribuf;
 1049     }
 1050 
 1051   rc = ldap_initialize (ld, uri);
 1052 #else
 1053   if (strncasecmp (uri, "ldap://", sizeof ("ldap://") - 1) != 0)
 1054     {
 1055       return NSS_UNAVAIL;
 1056     }
 1057 
 1058   uri += sizeof ("ldap://") - 1;
 1059   p = strchr (uri, ':');
 1060 
 1061   if (p != NULL)
 1062     {
 1063       size_t urilen = (p - uri);
 1064 
 1065       if (urilen >= sizeof (uribuf))
 1066     {
 1067       return NSS_UNAVAIL;
 1068     }
 1069 
 1070       memcpy (uribuf, uri, urilen);
 1071       uribuf[urilen] = '\0';
 1072 
 1073       defport = atoi (p + 1);
 1074       uri = uribuf;
 1075     }
 1076 # ifdef HAVE_LDAP_INIT
 1077   *ld = ldap_init (uri, defport);
 1078 # else
 1079   *ld = ldap_open (uri, defport);
 1080 # endif
 1081 
 1082   rc = (*ld == NULL) ? LDAP_SERVER_DOWN : LDAP_SUCCESS;
 1083 
 1084 #endif /* HAVE_LDAP_INITIALIZE */
 1085 
 1086   stat = do_map_error (rc);
 1087   if (stat == NSS_SUCCESS && *ld == NULL)
 1088     {
 1089       stat = NSS_UNAVAIL;
 1090     }
 1091   return stat;
 1092 }
 1093 
 1094 
 1095 static NSS_STATUS
 1096 do_init (void)
 1097 {
 1098   ldap_config_t *cfg;
 1099 #ifndef HAVE_PTHREAD_ATFORK
 1100   pid_t pid;
 1101 #endif
 1102   uid_t euid;
 1103   NSS_STATUS stat;
 1104   int sd=-1;
 1105 
 1106   debug ("==> do_init");
 1107 
 1108   if (_nss_ldap_validateconfig (__config) != NSS_SUCCESS)
 1109     {
 1110       do_close ();
 1111       __config = NULL;
 1112       __session.ls_current_uri = 0;
 1113     }
 1114 
 1115 #ifndef HAVE_PTHREAD_ATFORK
 1116 #if defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
 1117   /*
 1118    * This bogosity is necessary because Linux uses different
 1119    * PIDs for different threads (like IRIX, which we don't
 1120    * support). We can tell whether we are linked against
 1121    * libpthreads by whether __pthread_once is NULL or
 1122    * not. If it is NULL, then we're not linked with the
 1123    * threading library, and we need to compare the current
 1124    * process ID against the saved one to figure out
 1125    * whether we've forked. 
 1126    *
 1127    * --
 1128    *  __pthread_once does not imply __pthread_atfork being non-NULL!
 1129    *  <tjanouse@redhat.com>
 1130    * --
 1131    * 
 1132    * Once we know whether we have forked or not, 
 1133    * courtesy of pthread_atfork() or us checking
 1134    * ourselves, we can close the socket to the LDAP
 1135    * server to avoid leaking a socket, and reopen
 1136    * another connection. Under no circumstances do we
 1137    * wish to use the same connection, or to send an
 1138    * unbind PDU over the parents connection, as that
 1139    * will wreak all sorts of havoc or inefficiencies,
 1140    * respectively.
 1141    */
 1142   if (__pthread_once == NULL || __pthread_atfork == NULL)
 1143     pid = getpid ();
 1144   else
 1145     pid = -1;           /* linked against libpthreads, don't care */
 1146 #else
 1147   pid = getpid ();
 1148 #endif /* HAVE_LIBC_LOCK_H || HAVE_BITS_LIBC_LOCK_H */
 1149 #endif /* HAVE_PTHREAD_ATFORK */
 1150 
 1151   euid = geteuid ();
 1152 
 1153 #ifdef DEBUG
 1154 #ifdef HAVE_PTHREAD_ATFORK
 1155   syslog (LOG_DEBUG,
 1156       "nss_ldap: __session.ls_state=%d, __session.ls_conn=%p, __euid=%i, euid=%i",
 1157       __session.ls_state, __session.ls_conn, __euid, euid);
 1158 #elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
 1159   syslog (LOG_DEBUG,
 1160       "nss_ldap: libpthreads=%s, __session.ls_state=%d, __session.ls_conn=%p, __pid=%i, pid=%i, __euid=%i, euid=%i",
 1161       ((__pthread_once == NULL || __pthread_atfork == NULL) ? "FALSE" : "TRUE"),
 1162       __session.ls_state,
 1163       __session.ls_conn,
 1164       ((__pthread_once == NULL || __pthread_atfork == NULL) ? __pid : -1),
 1165       ((__pthread_once == NULL || __pthread_atfork == NULL) ? pid : -1), __euid, euid);
 1166 #else
 1167   syslog (LOG_DEBUG,
 1168       "nss_ldap: __session.ls_state=%d, __session.ls_conn=%p, __pid=%i, pid=%i, __euid=%i, euid=%i",
 1169       __session.ls_state, __session.ls_conn, __pid, pid, __euid, euid);
 1170 #endif
 1171 #endif /* DEBUG */
 1172 
 1173   if (__session.ls_state == LS_CONNECTED_TO_DSA &&
 1174       do_get_our_socket (&sd) == 0)
 1175     {
 1176       /* The calling app has stolen our socket. */
 1177       debug (":== do_init (stolen socket detected)");
 1178       do_drop_connection (sd, 0);
 1179     }
 1180   else
 1181 #ifndef HAVE_PTHREAD_ATFORK
 1182 #if defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
 1183   if ((__pthread_once == NULL || __pthread_atfork == NULL) && __pid != pid)
 1184 #else
 1185   if (__pid != pid)
 1186 #endif /* HAVE_LIBC_LOCK_H || HAVE_BITS_LIBC_LOCK_H */
 1187     {
 1188       do_close_no_unbind ();
 1189     }
 1190   else
 1191 #endif /* HAVE_PTHREAD_ATFORK */
 1192   if (__euid != euid && (__euid == 0 || euid == 0))
 1193     {
 1194       /*
 1195        * If we've changed user ids, close the session so we can
 1196        * rebind as the correct user.
 1197        */
 1198       do_close ();
 1199     }
 1200   else if (__session.ls_state == LS_CONNECTED_TO_DSA)
 1201     {
 1202       time_t current_time;
 1203 
 1204       /*
 1205        * Otherwise we can hand back this process' global
 1206        * LDAP session.
 1207        *
 1208        * Patch from Steven Barrus <sbarrus@eng.utah.edu> to
 1209        * close the session after an idle timeout. 
 1210        */
 1211 
 1212       assert (__session.ls_conn != NULL);
 1213       assert (__session.ls_config != NULL);
 1214 
 1215       if (__session.ls_config->ldc_idle_timelimit)
 1216     {
 1217       time (&current_time);
 1218       if ((__session.ls_timestamp +
 1219            __session.ls_config->ldc_idle_timelimit) < current_time)
 1220         {
 1221           debug ("idle_timelimit reached");
 1222           do_close ();
 1223         }
 1224     }
 1225 
 1226       /*
 1227        * If the connection is still there (ie. do_close() wasn't
 1228        * called) then we can return the cached connection.
 1229        */
 1230       if (__session.ls_state == LS_CONNECTED_TO_DSA)
 1231     {
 1232       debug ("<== do_init (cached session)");
 1233       return NSS_SUCCESS;
 1234     }
 1235     }
 1236 
 1237   __session.ls_conn = NULL;
 1238   __session.ls_timestamp = 0;
 1239   __session.ls_state = LS_UNINITIALIZED;
 1240 
 1241 #if defined(HAVE_PTHREAD_ONCE) && defined(HAVE_PTHREAD_ATFORK)
 1242   if (pthread_once (&__once, do_atfork_setup) != 0)
 1243     {
 1244       debug ("<== do_init (pthread_once failed)");
 1245       return NSS_UNAVAIL;
 1246     }
 1247 #elif defined(HAVE_PTHREAD_ATFORK) && ( defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H) )
 1248   __libc_once (__once, do_atfork_setup);
 1249 #elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
 1250   /*
 1251    * Only install the pthread_atfork() handlers i
 1252    * we are linked against libpthreads. Otherwise,
 1253    * do close the session when the PID changes.
 1254    */
 1255   if (__pthread_once == NULL || __pthread_atfork == NULL)
 1256     __pid = pid;
 1257   else
 1258     __libc_once (__once, do_atfork_setup);
 1259 #else
 1260   __pid = pid;
 1261 #endif
 1262 
 1263   __euid = euid;
 1264 
 1265   /* Initialize schema and LDAP handle (but do not connect) */
 1266   if (__config == NULL)
 1267     {
 1268       char *configbufp = __configbuf;
 1269       size_t configbuflen = sizeof (__configbuf);
 1270 
 1271       stat = _nss_ldap_readconfig (&__config, &configbufp, &configbuflen);
 1272       if (stat == NSS_NOTFOUND)
 1273     {
 1274       /* Config was read but no host information specified; try DNS */
 1275       stat = _nss_ldap_mergeconfigfromdns (__config, &configbufp, &configbuflen);
 1276       if (stat != NSS_SUCCESS)
 1277         {
 1278               syslog (LOG_ERR, "nss_ldap: could not determine LDAP server from ldap.conf or DNS");
 1279         }
 1280     }
 1281 
 1282       if (stat != NSS_SUCCESS)
 1283     {
 1284       debug ("<== do_init (failed to read config)");
 1285       __config = NULL;
 1286       return NSS_UNAVAIL;
 1287     }
 1288     }
 1289 
 1290   cfg = __config;
 1291 
 1292   _nss_ldap_init_attributes (cfg->ldc_attrtab, (cfg->ldc_flags & NSS_LDAP_FLAGS_GETGRENT_SKIPMEMBERS) != 0);
 1293   _nss_ldap_init_filters ();
 1294 
 1295 #ifdef HAVE_LDAP_SET_OPTION
 1296   if (cfg->ldc_debug)
 1297     {
 1298 # ifdef LBER_OPT_LOG_PRINT_FILE
 1299       if (cfg->ldc_logdir && !__debugfile)
 1300     {
 1301       char namebuf[PATH_MAX];
 1302 
 1303       snprintf (namebuf, sizeof (namebuf), "%s/ldap.%d", cfg->ldc_logdir,
 1304             (int) getpid ());
 1305       __debugfile = fopen (namebuf, "a");
 1306 
 1307       if (__debugfile != NULL)
 1308         {
 1309           ber_set_option (NULL, LBER_OPT_LOG_PRINT_FILE, __debugfile);
 1310         }
 1311     }
 1312 # endif /* LBER_OPT_LOG_PRINT_FILE */
 1313 # ifdef LBER_OPT_DEBUG_LEVEL
 1314       if (cfg->ldc_debug)
 1315     {
 1316       ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &cfg->ldc_debug);
 1317       ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &cfg->ldc_debug);
 1318     }
 1319 # endif /* LBER_OPT_DEBUG_LEVEL */
 1320     }
 1321 #endif /* HAVE_LDAP_SET_OPTION */
 1322 
 1323 #ifdef HAVE_LDAPSSL_CLIENT_INIT
 1324   /*
 1325    * Initialize the SSL library. 
 1326    */
 1327   if (cfg->ldc_ssl_on == SSL_LDAPS)
 1328     {
 1329       int rc = 0;
 1330       if (__ssl_initialized == 0
 1331       && (rc = ldapssl_client_init (cfg->ldc_sslpath, NULL)) != LDAP_SUCCESS)
 1332     {
 1333           debug ("<== do_init (ldapssl_client_init failed with rc = %d)", rc);
 1334       return NSS_UNAVAIL;
 1335     }
 1336       __ssl_initialized = 1;
 1337     }
 1338 #endif /* SSL */
 1339 
 1340   __session.ls_conn = NULL;
 1341 
 1342   assert (__session.ls_current_uri <= NSS_LDAP_CONFIG_URI_MAX);
 1343   assert (cfg->ldc_uris[__session.ls_current_uri] != NULL);
 1344 
 1345   stat = do_init_session (&__session.ls_conn,
 1346               cfg->ldc_uris[__session.ls_current_uri],
 1347               cfg->ldc_port);
 1348   if (stat != NSS_SUCCESS)
 1349     {
 1350       debug ("<== do_init (failed to initialize LDAP session)");
 1351       return stat;
 1352     }
 1353 
 1354   __session.ls_config = cfg;
 1355   __session.ls_state = LS_INITIALIZED;
 1356 
 1357   debug ("<== do_init (initialized session)");
 1358 
 1359   return NSS_SUCCESS;
 1360 }
 1361 
 1362 #if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS)
 1363 static int
 1364 do_start_tls (ldap_session_t * session)
 1365 {
 1366   int rc;
 1367 #ifdef HAVE_LDAP_START_TLS
 1368   int msgid;
 1369   struct timeval tv, *timeout;
 1370   LDAPMessage *res = NULL;
 1371 
 1372   debug ("==> do_start_tls");
 1373 
 1374   rc = ldap_start_tls (session->ls_conn, NULL, NULL, &msgid);
 1375   if (rc != LDAP_SUCCESS)
 1376     {
 1377       debug ("<== do_start_tls (ldap_start_tls failed: %s)", ldap_err2string (rc));
 1378       return rc;
 1379     }
 1380 
 1381   if (session->ls_config->ldc_bind_timelimit == LDAP_NO_LIMIT)
 1382     {
 1383       timeout = NULL;
 1384     }
 1385   else
 1386     {
 1387       tv.tv_sec = session->ls_config->ldc_bind_timelimit;
 1388       tv.tv_usec = 0;
 1389       timeout = &tv;
 1390     }
 1391 
 1392   rc = ldap_result (session->ls_conn, msgid, 1, timeout, &res);
 1393   if (rc > 0)
 1394     {
 1395       rc = ldap_result2error (session->ls_conn, res, 1);
 1396       if (rc != LDAP_SUCCESS)
 1397         {
 1398           debug ("<== do_start_tls (ldap_result2error failed: %s)", ldap_err2string (rc));
 1399           return rc;
 1400         }
 1401     }
 1402   else 
 1403     {
 1404       if (rc == -1)
 1405         {
 1406 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
 1407           if (ldap_get_option (session->ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
 1408             {
 1409               rc = LDAP_UNAVAILABLE;
 1410             }
 1411 #else
 1412           rc = session->ls_conn->ld_errno;
 1413 #endif /* LDAP_OPT_ERROR_NUMBER */
 1414         }
 1415       else if (rc == 0) /* took too long */
 1416         {
 1417           ldap_abandon (session->ls_conn, msgid);
 1418           rc = LDAP_TIMEOUT;
 1419         } 
 1420 
 1421       syslog (LOG_INFO, "nss_ldap: ldap_start_tls failed: %s", ldap_err2string (rc));
 1422       debug ("<== do_start_tls (ldap_start_tls failed: %s)", ldap_err2string (rc));
 1423       return rc;
 1424     }
 1425 
 1426   rc = ldap_install_tls (session->ls_conn);
 1427 #else
 1428   rc = ldap_start_tls_s (session->ls_conn, NULL, NULL);
 1429 #endif /* HAVE_LDAP_START_TLS */
 1430 
 1431   if (rc != LDAP_SUCCESS)
 1432     {
 1433       debug ("<== do_start_tls (start TLS failed: %s)", ldap_err2string(rc));
 1434       return rc;
 1435     }
 1436 
 1437   return LDAP_SUCCESS;
 1438 }
 1439 #endif
 1440 
 1441 /*
 1442  * Opens connection to an LDAP server - should only be called from search
 1443  * API. Other API that just needs access to configuration and schema should
 1444  * call do_init().
 1445  *
 1446  * As with do_close(), this assumes ownership of sess.
 1447  * It also wants to own __config: is there a potential deadlock here? XXX
 1448  */
 1449 static NSS_STATUS
 1450 do_open (void)
 1451 {
 1452   ldap_config_t *cfg;
 1453   int usesasl;
 1454   char *bindarg;
 1455   NSS_STATUS stat;
 1456 #ifdef LDAP_OPT_NETWORK_TIMEOUT
 1457   struct timeval tv;
 1458 #endif
 1459 #ifdef LDAP_X_OPT_CONNECT_TIMEOUT
 1460   int timeout;
 1461 #endif
 1462   int rc;
 1463 
 1464   debug ("==> do_open");
 1465 
 1466   /* Moved the head part of do_open() into do_init() */
 1467   stat = do_init ();
 1468   if (stat != NSS_SUCCESS)
 1469     {
 1470       debug ("<== do_open (session initialization failed)");
 1471       return stat;
 1472     }
 1473 
 1474   assert (__session.ls_conn != NULL);
 1475   assert (__session.ls_config != NULL);
 1476   assert (__session.ls_state != LS_UNINITIALIZED);
 1477 
 1478   cfg = __session.ls_config;
 1479 
 1480   if (__session.ls_state == LS_CONNECTED_TO_DSA)
 1481     {
 1482       debug ("<== do_open (cached session)");
 1483       return NSS_SUCCESS;
 1484     }
 1485 #ifdef LDAP_OPT_THREAD_FN_PTRS
 1486   if (_nss_ldap_ltf_thread_init (__session.ls_conn) != NSS_SUCCESS)
 1487     {
 1488       do_close ();
 1489       debug ("<== do_open (thread initialization failed)");
 1490       return NSS_UNAVAIL;
 1491     }
 1492 #endif /* LDAP_OPT_THREAD_FN_PTRS */
 1493 
 1494 #if LDAP_SET_REBIND_PROC_ARGS == 3
 1495   ldap_set_rebind_proc (__session.ls_conn, do_rebind, NULL);
 1496 #elif LDAP_SET_REBIND_PROC_ARGS == 2
 1497   ldap_set_rebind_proc (__session.ls_conn, do_rebind);
 1498 #endif
 1499 
 1500 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION)
 1501   ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
 1502            &cfg->ldc_version);
 1503 #else
 1504   __session.ls_conn->ld_version = cfg->ldc_version;
 1505 #endif /* LDAP_OPT_PROTOCOL_VERSION */
 1506 
 1507 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DEREF)
 1508   ldap_set_option (__session.ls_conn, LDAP_OPT_DEREF, &cfg->ldc_deref);
 1509 #else
 1510   __session.ls_conn->ld_deref = cfg->ldc_deref;
 1511 #endif /* LDAP_OPT_DEREF */
 1512 
 1513 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_TIMELIMIT)
 1514   ldap_set_option (__session.ls_conn, LDAP_OPT_TIMELIMIT,
 1515            &cfg->ldc_timelimit);
 1516 #else
 1517   __session.ls_conn->ld_timelimit = cfg->ldc_timelimit;
 1518 #endif /* LDAP_OPT_TIMELIMIT */
 1519 
 1520 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_X_OPT_CONNECT_TIMEOUT)
 1521   /*
 1522    * This is a new option in the Netscape SDK which sets
 1523    * the TCP connect timeout. For want of a better value,
 1524    * we use the bind_timelimit to control this.
 1525    */
 1526   timeout = cfg->ldc_bind_timelimit * 1000;
 1527   ldap_set_option (__session.ls_conn, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout);
 1528 #endif /* LDAP_X_OPT_CONNECT_TIMEOUT */
 1529 
 1530 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT)
 1531   tv.tv_sec = cfg->ldc_bind_timelimit;
 1532   tv.tv_usec = 0;
 1533   ldap_set_option (__session.ls_conn, LDAP_OPT_NETWORK_TIMEOUT, &tv);
 1534 #endif /* LDAP_OPT_NETWORK_TIMEOUT */
 1535 
 1536 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_REFERRALS)
 1537   ldap_set_option (__session.ls_conn, LDAP_OPT_REFERRALS,
 1538            cfg->ldc_referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
 1539 #endif
 1540 
 1541 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_RESTART)
 1542   ldap_set_option (__session.ls_conn, LDAP_OPT_RESTART,
 1543            cfg->ldc_restart ? LDAP_OPT_ON : LDAP_OPT_OFF);
 1544 #endif
 1545 
 1546 #if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS)
 1547   if (cfg->ldc_ssl_on == SSL_START_TLS)
 1548     {
 1549       int version;
 1550 
 1551       if (ldap_get_option
 1552       (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
 1553        &version) == LDAP_OPT_SUCCESS)
 1554     {
 1555       if (version < LDAP_VERSION3)
 1556         {
 1557           version = LDAP_VERSION3;
 1558           ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
 1559                    &version);
 1560         }
 1561     }
 1562 
 1563       /* set up SSL context */
 1564       if (do_ssl_options (cfg) != LDAP_SUCCESS)
 1565     {
 1566       do_close ();
 1567       debug ("<== do_open (SSL setup failed)");
 1568       return NSS_UNAVAIL;
 1569     }
 1570 
 1571       stat = do_map_error (do_start_tls (&__session));
 1572       if (stat == NSS_SUCCESS)
 1573     {
 1574       debug (":== do_open (TLS startup succeeded)");
 1575     }
 1576       else
 1577     {
 1578       do_close ();
 1579       debug ("<== do_open (TLS startup failed)");
 1580       return stat;
 1581     }
 1582     }
 1583   else
 1584 #endif /* HAVE_LDAP_START_TLS_S || HAVE_LDAP_START_TLS */
 1585 
 1586     /*
 1587      * If SSL is desired, either by the "ssl" option or if this
 1588      * is a "ldaps" URI, then enable it.
 1589      */
 1590   if (cfg->ldc_ssl_on == SSL_LDAPS ||
 1591       strncasecmp(cfg->ldc_uris[__session.ls_current_uri],
 1592                   "ldaps://", sizeof ("ldaps://") - 1) == 0
 1593      )
 1594     {
 1595 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
 1596       int tls = LDAP_OPT_X_TLS_HARD;
 1597       if (ldap_set_option (__session.ls_conn, LDAP_OPT_X_TLS, &tls) !=
 1598       LDAP_SUCCESS)
 1599     {
 1600       do_close ();
 1601       debug ("<== do_open (TLS setup failed)");
 1602       return NSS_UNAVAIL;
 1603     }
 1604 
 1605       /* set up SSL context */
 1606       if (do_ssl_options (cfg) != LDAP_SUCCESS)
 1607     {
 1608       do_close ();
 1609       debug ("<== do_open (SSL setup failed)");
 1610       return NSS_UNAVAIL;
 1611     }
 1612 
 1613 #elif defined(HAVE_LDAPSSL_CLIENT_INIT)
 1614       if (ldapssl_install_routines (__session.ls_conn) != LDAP_SUCCESS)
 1615     {
 1616       do_close ();
 1617       debug ("<== do_open (SSL setup failed)");
 1618       return NSS_UNAVAIL;
 1619     }
 1620 /* not in Solaris 9? */
 1621 #ifndef LDAP_OPT_SSL
 1622 #define LDAP_OPT_SSL 0x0A
 1623 #endif
 1624       if (ldap_set_option (__session.ls_conn, LDAP_OPT_SSL, LDAP_OPT_ON) !=
 1625       LDAP_SUCCESS)
 1626     {
 1627       do_close ();
 1628       debug ("<== do_open (SSL setup failed)");
 1629       return NSS_UNAVAIL;
 1630     }
 1631 #endif
 1632     }
 1633 
 1634   /*
 1635    * If we're running as root, let us bind as a special
 1636    * user, so we can fake shadow passwords.
 1637    * Thanks to Doug Nazar <nazard@dragoninc.on.ca> for this
 1638    * patch.
 1639    */
 1640   if (__euid == 0 && cfg->ldc_rootbinddn != NULL)
 1641     {
 1642 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
 1643       usesasl = cfg->ldc_rootusesasl;
 1644       bindarg =
 1645     cfg->ldc_rootusesasl ? cfg->ldc_rootsaslid : cfg->ldc_rootbindpw;
 1646 #else
 1647       usesasl = 0;
 1648       bindarg = cfg->ldc_rootbindpw;
 1649 #endif
 1650 
 1651       rc = do_bind (__session.ls_conn,
 1652             cfg->ldc_bind_timelimit,
 1653             cfg->ldc_rootbinddn, bindarg, usesasl);
 1654     }
 1655   else
 1656     {
 1657 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
 1658       usesasl = cfg->ldc_usesasl;
 1659       bindarg = cfg->ldc_usesasl ? cfg->ldc_saslid : cfg->ldc_bindpw;
 1660 #else
 1661       usesasl = 0;
 1662       bindarg = cfg->ldc_bindpw;
 1663 #endif
 1664 
 1665       rc = do_bind (__session.ls_conn,
 1666             cfg->ldc_bind_timelimit,
 1667             cfg->ldc_binddn,
 1668             cfg->ldc_bindpw, usesasl);
 1669     }
 1670 
 1671   if (rc != LDAP_SUCCESS)
 1672     {
 1673       /* log actual LDAP error code */
 1674       syslog (LOG_INFO,
 1675           "nss_ldap: failed to bind to LDAP server %s: %s",
 1676           cfg->ldc_uris[__session.ls_current_uri],
 1677           ldap_err2string (rc));
 1678       stat = do_map_error (rc);
 1679       do_close ();
 1680       debug ("<== do_open (failed to bind to DSA");
 1681     }
 1682   else
 1683     {
 1684       do_set_sockopts ();
 1685       time (&__session.ls_timestamp);
 1686       __session.ls_state = LS_CONNECTED_TO_DSA;
 1687       stat = NSS_SUCCESS;
 1688       debug ("<== do_open (session connected to DSA)");
 1689     }
 1690 
 1691   return stat;
 1692 }
 1693 
 1694 #if defined HAVE_LDAP_START_TLS_S || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
 1695 static int
 1696 do_ssl_options (ldap_config_t * cfg)
 1697 {
 1698   int rc;
 1699 
 1700   debug ("==> do_ssl_options");
 1701 
 1702 #ifdef LDAP_OPT_X_TLS_RANDOM_FILE
 1703   if (cfg->ldc_tls_randfile != NULL)
 1704     {
 1705       /* rand file */
 1706       rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
 1707                 cfg->ldc_tls_randfile);
 1708       if (rc != LDAP_SUCCESS)
 1709     {
 1710       debug
 1711         ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_RANDOM_FILE failed");
 1712       return LDAP_OPERATIONS_ERROR;
 1713     }
 1714     }
 1715 #endif /* LDAP_OPT_X_TLS_RANDOM_FILE */
 1716 
 1717   if (cfg->ldc_tls_cacertfile != NULL)
 1718     {
 1719       /* ca cert file */
 1720       rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE,
 1721                 cfg->ldc_tls_cacertfile);
 1722       if (rc != LDAP_SUCCESS)
 1723     {
 1724       debug
 1725         ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CACERTFILE failed");
 1726       return LDAP_OPERATIONS_ERROR;
 1727     }
 1728     }
 1729 
 1730   if (cfg->ldc_tls_cacertdir != NULL)
 1731     {
 1732       /* ca cert directory */
 1733       rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR,
 1734                 cfg->ldc_tls_cacertdir);
 1735       if (rc != LDAP_SUCCESS)
 1736     {
 1737       debug
 1738         ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CACERTDIR failed");
 1739       return LDAP_OPERATIONS_ERROR;
 1740     }
 1741     }
 1742 
 1743   /* require cert? */
 1744   if (cfg->ldc_tls_checkpeer > -1)
 1745     {
 1746       rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
 1747                 &cfg->ldc_tls_checkpeer);
 1748       if (rc != LDAP_SUCCESS)
 1749     {
 1750       debug
 1751         ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_REQUIRE_CERT failed");
 1752       return LDAP_OPERATIONS_ERROR;
 1753     }
 1754     }
 1755 
 1756   if (cfg->ldc_tls_ciphers != NULL)
 1757     {
 1758       /* set cipher suite, certificate and private key: */
 1759       rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
 1760                 cfg->ldc_tls_ciphers);
 1761       if (rc != LDAP_SUCCESS)
 1762     {
 1763       debug
 1764         ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CIPHER_SUITE failed");
 1765       return LDAP_OPERATIONS_ERROR;
 1766     }
 1767     }
 1768 
 1769   if (cfg->ldc_tls_cert != NULL)
 1770     {
 1771       rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE, cfg->ldc_tls_cert);
 1772       if (rc != LDAP_SUCCESS)
 1773     {
 1774       debug
 1775         ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CERTFILE failed");
 1776       return LDAP_OPERATIONS_ERROR;
 1777     }
 1778     }
 1779 
 1780   if (cfg->ldc_tls_key != NULL)
 1781     {
 1782       rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE, cfg->ldc_tls_key);
 1783       if (rc != LDAP_SUCCESS)
 1784     {
 1785       debug
 1786         ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_KEYFILE failed");
 1787       return LDAP_OPERATIONS_ERROR;
 1788     }
 1789     }
 1790 
 1791   debug ("<== do_ssl_options");
 1792 
 1793   return LDAP_SUCCESS;
 1794 }
 1795 #endif
 1796 
 1797 static int
 1798 do_bind (LDAP * ld, int timelimit, const char *dn, const char *pw,
 1799      int with_sasl)
 1800 {
 1801   int rc;
 1802   int msgid;
 1803   struct timeval tv;
 1804   LDAPMessage *result;
 1805 
 1806   debug("==> do_bind");
 1807 
 1808   /*
 1809    * set timelimit in ld for select() call in ldap_pvt_connect() 
 1810    * function implemented in libldap2's os-ip.c
 1811    */
 1812   tv.tv_sec = timelimit;
 1813   tv.tv_usec = 0;
 1814 
 1815 #if (defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))) || defined(HAVE_LDAP_GSS_BIND)
 1816   if (!with_sasl)
 1817     {
 1818 #endif
 1819       msgid = ldap_simple_bind (ld, dn, pw);
 1820 
 1821       if (msgid < 0)
 1822     {
 1823 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
 1824       if (ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &rc) !=
 1825           LDAP_SUCCESS)
 1826         {
 1827           rc = LDAP_UNAVAILABLE;
 1828         }
 1829 #else
 1830       rc = ld->ld_errno;
 1831 #endif /* LDAP_OPT_ERROR_NUMBER */
 1832       debug ("<== do_bind");
 1833 
 1834       return rc;
 1835     }
 1836 
 1837       rc = ldap_result (ld, msgid, 0, &tv, &result);
 1838       if (rc > 0)
 1839     {
 1840       debug ("<== do_bind");
 1841       return ldap_result2error (ld, result, 1);
 1842     }
 1843 
 1844       /* took too long */
 1845       if (rc == 0)
 1846     {
 1847       ldap_abandon (ld, msgid);
 1848     }
 1849 #if (defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))) || defined(HAVE_LDAP_GSS_BIND)
 1850     }
 1851   else
 1852     {
 1853 #ifdef HAVE_LDAP_GSS_BIND
 1854       return ldap_gss_bind (ld, dn, pw, GSSSASL_NO_SECURITY_LAYER,
 1855                 LDAP_SASL_GSSAPI);
 1856 #else
 1857 # ifdef CONFIGURE_KRB5_CCNAME
 1858 # ifndef CONFIGURE_KRB5_CCNAME_GSSAPI
 1859       char tmpbuf[256];
 1860       static char envbuf[256];
 1861 # endif
 1862       char *ccname;
 1863       const char *oldccname = NULL;
 1864       int retval;
 1865 # endif /* CONFIGURE_KRB5_CCNAME */
 1866 
 1867       if (__config->ldc_sasl_secprops != NULL)
 1868     {
 1869       rc =
 1870         ldap_set_option (ld, LDAP_OPT_X_SASL_SECPROPS,
 1871                  (void *) __config->ldc_sasl_secprops);
 1872       if (rc != LDAP_SUCCESS)
 1873         {
 1874           debug ("do_bind: unable to set SASL security properties");
 1875           return rc;
 1876         }
 1877     }
 1878 
 1879 #ifdef CONFIGURE_KRB5_KEYTAB
 1880       if (do_select_krb5_cache(__config)) { return -1; }
 1881 #else
 1882 # ifdef CONFIGURE_KRB5_CCNAME
 1883       /* Set default Kerberos ticket cache for SASL-GSSAPI */
 1884       /* There are probably race conditions here XXX */
 1885       ccname = __config->ldc_krb5_ccname;
 1886       if (ccname != NULL)
 1887     {
 1888       char *ccfile = ccname;
 1889       /* Check that cache exists and is readable */
 1890       if ((strncasecmp(ccfile, "FILE:", sizeof("FILE:") - 1) == 0)
 1891           || (strncasecmp(ccfile, "WRFILE:", sizeof("WRFILE:") - 1) == 0))
 1892         {
 1893           ccfile = strchr(ccfile, ':') + 1;
 1894         }
 1895       if (access(ccfile, R_OK) != 0)
 1896         {
 1897           ccname = NULL;
 1898         }
 1899     }
 1900       if (ccname != NULL)
 1901     {       
 1902 # ifdef CONFIGURE_KRB5_CCNAME_ENV
 1903       oldccname = getenv ("KRB5CCNAME");
 1904       if (oldccname != NULL)
 1905         {
 1906           strncpy (tmpbuf, oldccname, sizeof (tmpbuf));
 1907           tmpbuf[sizeof (tmpbuf) - 1] = '\0';
 1908         }
 1909       else
 1910         {
 1911           tmpbuf[0] = '\0';
 1912         }
 1913       oldccname = tmpbuf;
 1914       snprintf (envbuf, sizeof (envbuf), "KRB5CCNAME=%s", ccname);
 1915       putenv (envbuf);
 1916 # elif defined(CONFIGURE_KRB5_CCNAME_GSSAPI)
 1917       if (gss_krb5_ccache_name (&retval, ccname, &oldccname) !=
 1918           GSS_S_COMPLETE)
 1919         {
 1920           debug ("do_bind: unable to set default credential cache");
 1921           return -1;
 1922         }
 1923 # endif
 1924     }
 1925 # endif /* CONFIGURE_KRB5_CCNAME */
 1926 #endif /* CONFIGURE_KRB5_KEYTAB */
 1927       rc = ldap_sasl_interactive_bind_s (ld, dn, "GSSAPI", NULL, NULL,
 1928                      LDAP_SASL_QUIET,
 1929                      do_sasl_interact, (void *) pw);
 1930 #ifdef CONFIGURE_KRB5_KEYTAB
 1931       if (do_restore_krb5_cache(__config)) { return -1; }
 1932 #else
 1933 # ifdef CONFIGURE_KRB5_CCNAME
 1934       /* Restore default Kerberos ticket cache. */
 1935       if (oldccname != NULL)
 1936     {
 1937 # ifdef CONFIGURE_KRB5_CCNAME_ENV
 1938       snprintf (envbuf, sizeof (envbuf), "KRB5CCNAME=%s", oldccname);
 1939       putenv (envbuf);
 1940 # elif defined(CONFIGURE_KRB5_CCNAME_GSSAPI)
 1941       if (gss_krb5_ccache_name (&retval, oldccname, NULL) !=
 1942           GSS_S_COMPLETE)
 1943         {
 1944           debug ("do_bind: unable to restore default credential cache");
 1945           return -1;
 1946         }
 1947 # endif
 1948     }
 1949 # endif /* CONFIGURE_KRB5_CCNAME */
 1950 #endif /* CONFIGURE_KRB5_KEYTAB */
 1951       return rc;
 1952 #endif /* HAVE_LDAP_GSS_BIND */
 1953     }
 1954 #endif
 1955 
 1956   debug ("<== do_bind");
 1957 
 1958   return -1;
 1959 }
 1960 
 1961 /*
 1962  * This function initializes an enumeration context, acquiring
 1963  * the global mutex.
 1964  *
 1965  * It could be done from the default constructor, under Solaris, but we
 1966  * delay it until the setXXent() function is called.
 1967  */
 1968 ent_context_t *
 1969 _nss_ldap_ent_context_init (ent_context_t ** pctx)
 1970 {
 1971   ent_context_t *ctx;
 1972 
 1973   _nss_ldap_enter ();
 1974 
 1975   ctx = _nss_ldap_ent_context_init_locked (pctx);
 1976 
 1977   _nss_ldap_leave ();
 1978 
 1979   return ctx;
 1980 }
 1981 
 1982 /*
 1983  * This function initializes an enumeration context.
 1984  *
 1985  * It could be done from the default constructor, under Solaris, but we
 1986  * delay it until the setXXent() function is called.
 1987  */
 1988 ent_context_t *
 1989 _nss_ldap_ent_context_init_locked (ent_context_t ** pctx)
 1990 {
 1991   ent_context_t *ctx;
 1992 
 1993   debug ("==> _nss_ldap_ent_context_init_locked");
 1994 
 1995   ctx = *pctx;
 1996 
 1997   if (ctx == NULL)
 1998     {
 1999       ctx = (ent_context_t *) malloc (sizeof (*ctx));
 2000       if (ctx == NULL)
 2001     {
 2002       debug ("<== _nss_ldap_ent_context_init_locked");
 2003       return NULL;
 2004     }
 2005       *pctx = ctx;
 2006     }
 2007   else
 2008     {
 2009       if (ctx->ec_res != NULL)
 2010     {
 2011       ldap_msgfree (ctx->ec_res);
 2012           ctx->ec_res = NULL;
 2013     }
 2014       if (ctx->ec_cookie != NULL)
 2015     {
 2016       ber_bvfree (ctx->ec_cookie);
 2017     }
 2018       if (ctx->ec_msgid > -1 && do_result (ctx, LDAP_MSG_ONE) == NSS_SUCCESS)
 2019     {
 2020       ldap_abandon (__session.ls_conn, ctx->ec_msgid);
 2021     }
 2022     }
 2023 
 2024   ctx->ec_cookie = NULL;
 2025   ctx->ec_res = NULL;
 2026   ctx->ec_msgid = -1;
 2027   ctx->ec_sd = NULL;
 2028   ctx->ec_eof = 0;
 2029 
 2030   LS_INIT (ctx->ec_state);
 2031 
 2032   debug ("<== _nss_ldap_ent_context_init_locked");
 2033 
 2034   return ctx;
 2035 }
 2036 
 2037 static void
 2038 do_context_release (ent_context_t * ctx, int free_context)
 2039 {
 2040   /*
 2041    * Abandon the search if there were more results to fetch.
 2042    */
 2043   if (ctx->ec_msgid > -1 && do_result (ctx, LDAP_MSG_ONE) == NSS_SUCCESS)
 2044     {
 2045       ldap_abandon (__session.ls_conn, ctx->ec_msgid);
 2046       ctx->ec_msgid = -1;
 2047     }
 2048 
 2049   if (ctx->ec_res != NULL)
 2050     {
 2051       ldap_msgfree (ctx->ec_res);
 2052       ctx->ec_res = NULL;
 2053     }
 2054 
 2055   if (ctx->ec_cookie != NULL)
 2056     {
 2057       ber_bvfree (ctx->ec_cookie);
 2058       ctx->ec_cookie = NULL;
 2059     }
 2060 
 2061   ctx->ec_sd = NULL;
 2062   ctx->ec_eof = 0;
 2063 
 2064   LS_INIT (ctx->ec_state);
 2065 
 2066   if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_CONNECT_POLICY_ONESHOT))
 2067     {
 2068       do_close ();
 2069     }
 2070 
 2071   if (free_context)
 2072     free (ctx);
 2073 }
 2074 
 2075 /*
 2076  * Clears a given context; we require the caller
 2077  * to acquire the lock.
 2078  */
 2079 void
 2080 _nss_ldap_ent_context_release (ent_context_t ** ctx)
 2081 {
 2082   debug ("==> _nss_ldap_ent_context_release");
 2083 
 2084   if (ctx == NULL || *ctx == NULL)
 2085     {
 2086       debug ("<== _nss_ldap_ent_context_release");
 2087       return;
 2088     }
 2089 
 2090   do_context_release (*ctx, 1);
 2091   *ctx = NULL;
 2092 
 2093   debug ("<== _nss_ldap_ent_context_release");
 2094 
 2095   return;
 2096 }
 2097 
 2098 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_IRS_H)
 2099 /*
 2100  * Make all triple permutations
 2101  */
 2102 static NSS_STATUS
 2103 do_triple_permutations (const char *machine, const char *user,
 2104             const char *domain, char *bufptr, size_t buflen)
 2105 {
 2106   /*
 2107    * Map a triple
 2108    *
 2109    *      (M,U,D)
 2110    *
 2111    * to the filter
 2112    *
 2113    *      (|(nisNetgroupTriple=P1)...(nisNetgroupTriple=PN))
 2114    *
 2115    * where P1..PN are all permutations of triples that may match
 2116    * ie. including wildcards. Certainly this would be preferable
 2117    * to do server-side with an appropriate matching rule.
 2118    */
 2119   char escaped_machine[3 * (MAXHOSTNAMELEN + 1)];
 2120   char escaped_user[3 * (LOGNAME_MAX + 1)];
 2121   char escaped_domain[3 * (MAXHOSTNAMELEN + 1)];
 2122   const char *AT_NISNETGROUPTRIPLE = AT (nisNetgroupTriple);
 2123   NSS_STATUS stat;
 2124 
 2125 #define ESCAPE_TRIPLE_COMPONENT(component) do { \
 2126         if ((component) == NULL) \
 2127         { \
 2128             (escaped_##component)[0] = '*'; \
 2129             (escaped_##component)[1] = '\0'; \
 2130         } \
 2131         else \
 2132         { \
 2133             stat = _nss_ldap_escape_string((component), (escaped_##component), \
 2134                 (sizeof((escaped_##component)))); \
 2135             if (stat != NSS_SUCCESS) \
 2136                 return stat; \
 2137         } \
 2138     } while (0)
 2139 
 2140   ESCAPE_TRIPLE_COMPONENT (machine);
 2141   ESCAPE_TRIPLE_COMPONENT (user);
 2142   ESCAPE_TRIPLE_COMPONENT (domain);
 2143 
 2144 #define _APPEND_STRING(_buffer, _buflen, _s, _len) do { \
 2145         if ((_buflen) < (size_t)((_len) + 1)) \
 2146         { \
 2147             return NSS_TRYAGAIN; \
 2148         } \
 2149         memcpy((_buffer), (_s), (_len)); \
 2150         (_buffer)[(_len)] = '\0'; \
 2151         (_buffer) += (_len); \
 2152         (_buflen) -= (_len); \
 2153     } while (0)
 2154 
 2155 #define APPEND_STRING(_buffer, _buflen, _s) _APPEND_STRING(_buffer, _buflen, _s, strlen((_s)))
 2156 #define APPEND_CONSTANT_STRING(_buffer, _buflen, _s) _APPEND_STRING(_buffer, _buflen, _s, (sizeof((_s)) - 1))
 2157 
 2158 #define APPEND_TRIPLE(_buffer, _buflen, _machine, _user, _domain) do { \
 2159         APPEND_CONSTANT_STRING((_buffer), (_buflen), "("); \
 2160         APPEND_STRING((_buffer), (_buflen), AT_NISNETGROUPTRIPLE); \
 2161         APPEND_CONSTANT_STRING((_buffer), (_buflen), "=\\("); \
 2162         if ((_machine) != NULL) \
 2163         { \
 2164             APPEND_STRING((_buffer), (_buflen), (_machine)); \
 2165         } \
 2166         APPEND_CONSTANT_STRING((_buffer), (_buflen), ","); \
 2167         if ((_user) != NULL) \
 2168         { \
 2169             APPEND_STRING((_buffer), (_buflen), (_user)); \
 2170         } \
 2171         APPEND_CONSTANT_STRING((_buffer), (_buflen), ","); \
 2172         if ((_domain) != NULL) \
 2173         { \
 2174             APPEND_STRING((_buffer), (_buflen), (_domain)); \
 2175         } \
 2176         APPEND_CONSTANT_STRING((_buffer), (_buflen), "\\))"); \
 2177     } while (0)
 2178 
 2179   APPEND_CONSTANT_STRING (bufptr, buflen, "(&(");
 2180   APPEND_STRING (bufptr, buflen, AT (objectClass));
 2181   APPEND_CONSTANT_STRING (bufptr, buflen, "=");
 2182   APPEND_STRING (bufptr, buflen, OC (nisNetgroup));
 2183   APPEND_CONSTANT_STRING (bufptr, buflen, ")(|");
 2184 
 2185   APPEND_TRIPLE (bufptr, buflen, escaped_machine, escaped_user,
 2186          escaped_domain);
 2187   APPEND_TRIPLE (bufptr, buflen, escaped_machine, escaped_user, NULL);
 2188   APPEND_TRIPLE (bufptr, buflen, escaped_machine, NULL, NULL);
 2189   APPEND_TRIPLE (bufptr, buflen, NULL, escaped_user, escaped_domain);
 2190   APPEND_TRIPLE (bufptr, buflen, NULL, escaped_user, NULL);
 2191   APPEND_TRIPLE (bufptr, buflen, escaped_machine, NULL, escaped_domain);
 2192   APPEND_TRIPLE (bufptr, buflen, NULL, NULL, escaped_domain);
 2193   APPEND_TRIPLE (bufptr, buflen, NULL, NULL, NULL);
 2194 
 2195   APPEND_CONSTANT_STRING (bufptr, buflen, "))");
 2196 
 2197   return NSS_SUCCESS;
 2198 }
 2199 #endif /* HAVE_NSSWITCH_H || HAVE_IRS_H */
 2200 
 2201 /*
 2202  * AND or OR a set of filters.
 2203  */
 2204 static NSS_STATUS
 2205 do_aggregate_filter (const char **values,
 2206              ldap_args_types_t type,
 2207              const char *filterprot, char *bufptr, size_t buflen)
 2208 {
 2209   NSS_STATUS stat;
 2210   const char **valueP;
 2211 
 2212   assert (buflen > sizeof ("(|)"));
 2213 
 2214   bufptr[0] = '(';
 2215   bufptr[1] = (type == LA_TYPE_STRING_LIST_AND) ? '&' : '|';
 2216 
 2217   bufptr += 2;
 2218   buflen -= 2;
 2219 
 2220   for (valueP = values; *valueP != NULL; valueP++)
 2221     {
 2222       size_t len;
 2223       char filter[LDAP_FILT_MAXSIZ], escapedBuf[LDAP_FILT_MAXSIZ];
 2224 
 2225       stat =
 2226     _nss_ldap_escape_string (*valueP, escapedBuf, sizeof (escapedBuf));
 2227       if (stat != NSS_SUCCESS)
 2228     return stat;
 2229 
 2230       snprintf (filter, sizeof (filter), filterprot, escapedBuf);
 2231       len = strlen (filter);
 2232 
 2233       if (buflen < len + 1 /* ')' */ )
 2234     return NSS_TRYAGAIN;
 2235 
 2236       memcpy (bufptr, filter, len);
 2237       bufptr[len] = '\0';
 2238       bufptr += len;
 2239       buflen -= len;
 2240     }
 2241 
 2242   if (buflen < 2)
 2243     return NSS_TRYAGAIN;
 2244 
 2245   *bufptr++ = ')';
 2246   *bufptr++ = '\0';
 2247 
 2248   buflen -= 2;
 2249 
 2250   return NSS_SUCCESS;
 2251 }
 2252 
 2253 /*
 2254  * Do the necessary formatting to create a string filter.
 2255  */
 2256 static NSS_STATUS
 2257 do_filter (const ldap_args_t * args, const char *filterprot,
 2258        ldap_service_search_descriptor_t * sd, char *userBuf,
 2259        size_t userBufSiz, char **dynamicUserBuf, const char **retFilter)
 2260 {
 2261   char buf1[LDAP_FILT_MAXSIZ], buf2[LDAP_FILT_MAXSIZ];
 2262   char *filterBufP, filterBuf[LDAP_FILT_MAXSIZ];
 2263   size_t filterSiz;
 2264   NSS_STATUS stat = NSS_SUCCESS;
 2265 
 2266   debug ("==> do_filter");
 2267 
 2268   *dynamicUserBuf = NULL;
 2269 
 2270   if (args != NULL && args->la_type != LA_TYPE_NONE)
 2271     {
 2272       /* choose what to use for temporary storage */
 2273 
 2274       if (sd != NULL && sd->lsd_filter != NULL)
 2275     {
 2276       filterBufP = filterBuf;
 2277       filterSiz = sizeof (filterBuf);
 2278     }
 2279       else
 2280     {
 2281       filterBufP = userBuf;
 2282       filterSiz = userBufSiz;
 2283     }
 2284 
 2285       switch (args->la_type)
 2286     {
 2287     case LA_TYPE_STRING:
 2288       stat = _nss_ldap_escape_string (args->la_arg1.la_string, buf1,
 2289                       sizeof (buf1));
 2290       if (stat != NSS_SUCCESS)
 2291         break;
 2292 
 2293       snprintf (filterBufP, filterSiz, filterprot, buf1);
 2294       break;
 2295     case LA_TYPE_NUMBER:
 2296       snprintf (filterBufP, filterSiz, filterprot,
 2297             args->la_arg1.la_number);
 2298       break;
 2299     case LA_TYPE_STRING_AND_STRING:
 2300       stat = _nss_ldap_escape_string (args->la_arg1.la_string, buf1,
 2301                       sizeof (buf1));
 2302       if (stat != NSS_SUCCESS)
 2303         break;
 2304 
 2305       stat = _nss_ldap_escape_string (args->la_arg2.la_string, buf2,
 2306                       sizeof (buf2));
 2307       if (stat != NSS_SUCCESS)
 2308         break;
 2309 
 2310       snprintf (filterBufP, filterSiz, filterprot, buf1, buf2);
 2311       break;
 2312     case LA_TYPE_NUMBER_AND_STRING:
 2313       stat = _nss_ldap_escape_string (args->la_arg2.la_string, buf1,
 2314                       sizeof (buf1));
 2315       if (stat != NSS_SUCCESS)
 2316         break;
 2317 
 2318       snprintf (filterBufP, filterSiz, filterprot,
 2319             args->la_arg1.la_number, buf1);
 2320       break;
 2321 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_IRS_H)
 2322     case LA_TYPE_TRIPLE:
 2323       do
 2324         {
 2325           stat = do_triple_permutations (args->la_arg1.la_triple.host,
 2326                          args->la_arg1.la_triple.user,
 2327                          args->la_arg1.la_triple.domain,
 2328                          filterBufP, filterSiz);
 2329           if (stat == NSS_TRYAGAIN)
 2330         {
 2331           filterBufP = *dynamicUserBuf = realloc (*dynamicUserBuf,
 2332                               2 * filterSiz);
 2333           if (filterBufP == NULL)
 2334             return NSS_UNAVAIL;
 2335           filterSiz *= 2;
 2336         }
 2337         }
 2338       while (stat == NSS_TRYAGAIN);
 2339       break;
 2340 #endif /* HAVE_NSSWITCH_H || HAVE_IRS_H */
 2341     case LA_TYPE_STRING_LIST_OR:
 2342     case LA_TYPE_STRING_LIST_AND:
 2343       do
 2344         {
 2345           stat = do_aggregate_filter (args->la_arg1.la_string_list,
 2346                       args->la_type,
 2347                       filterprot, filterBufP, filterSiz);
 2348           if (stat == NSS_TRYAGAIN)
 2349         {
 2350           filterBufP = *dynamicUserBuf = realloc (*dynamicUserBuf,
 2351                               2 * filterSiz);
 2352           if (filterBufP == NULL)
 2353             return NSS_UNAVAIL;
 2354           filterSiz *= 2;
 2355         }
 2356         }
 2357       while (stat == NSS_TRYAGAIN);
 2358       break;
 2359     default:
 2360       return NSS_UNAVAIL;
 2361       break;
 2362     }
 2363 
 2364       if (stat != NSS_SUCCESS)
 2365     return stat;
 2366 
 2367       /*
 2368        * This code really needs to be cleaned up.
 2369        */
 2370       if (sd != NULL && sd->lsd_filter != NULL)
 2371     {
 2372       size_t filterBufPLen = strlen (filterBufP);
 2373 
 2374       /* remove trailing bracket */
 2375       if (filterBufP[filterBufPLen - 1] == ')')
 2376         filterBufP[filterBufPLen - 1] = '\0';
 2377 
 2378       if (*dynamicUserBuf != NULL)
 2379         {
 2380           char *oldDynamicUserBuf = *dynamicUserBuf;
 2381           size_t dynamicUserBufSiz;
 2382 
 2383           dynamicUserBufSiz = filterBufPLen + strlen (sd->lsd_filter) +
 2384         sizeof ("())");
 2385           *dynamicUserBuf = malloc (dynamicUserBufSiz);
 2386           if (*dynamicUserBuf == NULL)
 2387         {
 2388           free (oldDynamicUserBuf);
 2389           return NSS_UNAVAIL;
 2390         }
 2391 
 2392           snprintf (*dynamicUserBuf, dynamicUserBufSiz, "%s(%s))",
 2393             filterBufP, sd->lsd_filter);
 2394           free (oldDynamicUserBuf);
 2395         }
 2396       else
 2397         {
 2398           snprintf (userBuf, userBufSiz, "%s(%s))",
 2399             filterBufP, sd->lsd_filter);
 2400         }
 2401     }
 2402 
 2403       if (*dynamicUserBuf != NULL)
 2404     *retFilter = *dynamicUserBuf;
 2405       else
 2406     *retFilter = userBuf;
 2407     }
 2408   else
 2409     {
 2410       /* no arguments, probably an enumeration filter */
 2411       if (sd != NULL && sd->lsd_filter != NULL)
 2412     {
 2413       snprintf (userBuf, userBufSiz, "(&%s(%s))",
 2414             filterprot, sd->lsd_filter);
 2415       *retFilter = userBuf;
 2416     }
 2417       else
 2418     {
 2419       *retFilter = filterprot;
 2420     }
 2421     }
 2422 
 2423   debug (":== do_filter: %s", *retFilter);
 2424 
 2425   debug ("<== do_filter");
 2426 
 2427   return NSS_SUCCESS;
 2428 }
 2429 
 2430 /*
 2431  * Wrapper around ldap_result() to skip over search references
 2432  * and deal transparently with the last entry.
 2433  */
 2434 static NSS_STATUS
 2435 do_result (ent_context_t * ctx, int all)
 2436 {
 2437   int rc = LDAP_UNAVAILABLE;
 2438   NSS_STATUS stat = NSS_TRYAGAIN;
 2439   struct timeval tv, *tvp;
 2440 
 2441   debug ("==> do_result");
 2442 
 2443   if (__session.ls_state != LS_CONNECTED_TO_DSA)
 2444     {
 2445       debug ("<== do_result");
 2446       return NSS_UNAVAIL;
 2447     }
 2448 
 2449   if (__session.ls_config->ldc_timelimit == LDAP_NO_LIMIT)
 2450     {
 2451       tvp = NULL;
 2452     }
 2453   else
 2454     {
 2455       tv.tv_sec = __session.ls_config->ldc_timelimit;
 2456       tv.tv_usec = 0;
 2457       tvp = &tv;
 2458     }
 2459 
 2460   do
 2461     {
 2462       if (ctx->ec_res != NULL)
 2463     {
 2464       ldap_msgfree (ctx->ec_res);
 2465       ctx->ec_res = NULL;
 2466     }
 2467 
 2468       rc =
 2469     ldap_result (__session.ls_conn, ctx->ec_msgid, all, tvp,
 2470              &ctx->ec_res);
 2471       switch (rc)
 2472     {
 2473     case -1:
 2474     case 0:
 2475 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
 2476       if (ldap_get_option
 2477           (__session.ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
 2478         {
 2479           rc = LDAP_UNAVAILABLE;
 2480         }
 2481 #else
 2482       rc = __session.ls_conn->ld_errno;
 2483 #endif /* LDAP_OPT_ERROR_NUMBER */
 2484       syslog (LOG_ERR, "nss_ldap: could not get LDAP result - %s",
 2485           ldap_err2string (rc));
 2486       do_close();
 2487       stat = NSS_UNAVAIL;
 2488       break;
 2489     case LDAP_RES_SEARCH_ENTRY:
 2490       stat = NSS_SUCCESS;
 2491       break;
 2492     case LDAP_RES_SEARCH_RESULT:
 2493       if (all == LDAP_MSG_ALL)
 2494         {
 2495           /* we asked for the result chain, we got it. */
 2496           stat = NSS_SUCCESS;
 2497         }
 2498       else
 2499         {
 2500 #ifdef LDAP_MORE_RESULTS_TO_RETURN
 2501           int parserc;
 2502           /* NB: this frees ctx->ec_res */
 2503           LDAPControl **resultControls = NULL;
 2504 
 2505           if (ctx->ec_cookie != NULL)
 2506         {
 2507           ber_bvfree(ctx->ec_cookie);
 2508           ctx->ec_cookie = NULL;
 2509         }
 2510 
 2511           parserc =
 2512         ldap_parse_result (__session.ls_conn, ctx->ec_res, &rc, NULL,
 2513                    NULL, NULL, &resultControls, 1);
 2514           if (parserc != LDAP_SUCCESS
 2515           && parserc != LDAP_MORE_RESULTS_TO_RETURN)
 2516         {
 2517           ldap_abandon (__session.ls_conn, ctx->ec_msgid);
 2518           syslog (LOG_ERR,
 2519               "nss_ldap: could not get LDAP result - %s",
 2520               ldap_err2string (rc));
 2521           do_close();
 2522           stat = NSS_UNAVAIL;
 2523         }
 2524           else if (resultControls != NULL)
 2525         {
 2526           /* See if there are any more pages to come */
 2527           parserc = ldap_parse_page_control (__session.ls_conn,
 2528                              resultControls, NULL,
 2529                              &(ctx->ec_cookie));
 2530           ldap_controls_free (resultControls);
 2531           stat = NSS_NOTFOUND;
 2532         }
 2533           else
 2534         {
 2535           stat = NSS_NOTFOUND;
 2536         }
 2537 #else
 2538           stat = NSS_NOTFOUND;
 2539 #endif /* LDAP_MORE_RESULTS_TO_RETURN */
 2540           ctx->ec_res = NULL;
 2541           ctx->ec_msgid = -1;
 2542         }
 2543       break;
 2544     default:
 2545       stat = NSS_UNAVAIL;
 2546       break;
 2547     }
 2548     }
 2549 #ifdef LDAP_RES_SEARCH_REFERENCE
 2550   while (rc == LDAP_RES_SEARCH_REFERENCE);
 2551 #else
 2552   while (0);
 2553 #endif /* LDAP_RES_SEARCH_REFERENCE */
 2554 
 2555   if (stat == NSS_SUCCESS)
 2556     time (&__session.ls_timestamp);
 2557 
 2558   debug ("<== do_result");
 2559 
 2560   return stat;
 2561 }
 2562 
 2563 /*
 2564  * Function to call either do_search() or do_search_s() with
 2565  * reconnection logic.
 2566  */
 2567 static NSS_STATUS
 2568 do_with_reconnect (const char *base, int scope,
 2569            const char *filter, const char **attrs, int sizelimit,
 2570            void *private, search_func_t search_func)
 2571 {
 2572   int rc = LDAP_UNAVAILABLE, tries = 0, backoff = 0;
 2573   int hard = 1, start_uri = 0, log = 0;
 2574   NSS_STATUS stat = NSS_UNAVAIL;
 2575   int maxtries;
 2576 
 2577   debug ("==> do_with_reconnect");
 2578 
 2579   /* caller must successfully call do_init() first */
 2580   assert (__session.ls_config != NULL);
 2581 
 2582   maxtries = __session.ls_config->ldc_reconnect_maxconntries +
 2583          __session.ls_config->ldc_reconnect_tries;
 2584 
 2585   while (stat == NSS_UNAVAIL && hard && tries < maxtries)
 2586     {
 2587       if (tries >= __session.ls_config->ldc_reconnect_maxconntries)
 2588     {
 2589       if (backoff == 0)
 2590         backoff = __session.ls_config->ldc_reconnect_sleeptime;
 2591       else if (backoff < __session.ls_config->ldc_reconnect_maxsleeptime)
 2592         backoff *= 2;
 2593 
 2594       syslog (LOG_INFO,
 2595           "nss_ldap: reconnecting to LDAP server (sleeping %d seconds)...",
 2596           backoff);
 2597       (void) sleep (backoff);
 2598     }
 2599       else if (tries > 1)
 2600     {
 2601       /* Don't sleep, reconnect immediately. */
 2602       syslog (LOG_INFO, "nss_ldap: reconnecting to LDAP server...");
 2603     }
 2604 
 2605       /* For each "try", attempt to connect to all specified URIs */
 2606       start_uri = __session.ls_current_uri;
 2607       do
 2608     {
 2609       stat = do_open ();
 2610       if (stat == NSS_SUCCESS)
 2611         {
 2612           stat = do_map_error (search_func (base, scope, filter,
 2613                         attrs, sizelimit, private));
 2614         }
 2615       if (stat != NSS_UNAVAIL)
 2616         break;
 2617 
 2618       log++;
 2619 
 2620       /* test in case config file could not be read */
 2621       if (__session.ls_config != NULL)
 2622         {
 2623           assert (__session.ls_config->
 2624               ldc_uris[__session.ls_current_uri] != NULL);
 2625 
 2626           __session.ls_current_uri++;
 2627 
 2628           if (__session.ls_config->ldc_uris[__session.ls_current_uri] ==
 2629           NULL)
 2630         __session.ls_current_uri = 0;
 2631         }
 2632     }
 2633       while (__session.ls_current_uri != start_uri);
 2634 
 2635       if (stat == NSS_UNAVAIL)
 2636     {
 2637       do_close ();
 2638 
 2639       /*
 2640        * If a soft reconnect policy is specified, then do not
 2641        * try to reconnect to the LDAP server if it is down.
 2642        */
 2643       if (__session.ls_config->ldc_reconnect_pol == LP_RECONNECT_SOFT)
 2644         hard = 0;
 2645 
 2646       ++tries;
 2647     }
 2648     }
 2649 
 2650   switch (stat)
 2651     {
 2652     case NSS_UNAVAIL:
 2653       syslog (LOG_ERR, "nss_ldap: could not search LDAP server - %s",
 2654           ldap_err2string (rc));
 2655       break;
 2656     case NSS_TRYAGAIN:
 2657       syslog (LOG_ERR,
 2658           "nss_ldap: could not %s %sconnect to LDAP server - %s",
 2659           hard ? "hard" : "soft", tries ? "re" : "",
 2660           ldap_err2string (rc));
 2661       stat = NSS_UNAVAIL;
 2662       break;
 2663     case NSS_SUCCESS:
 2664       if (log)
 2665     {
 2666       char *uri = __session.ls_config->ldc_uris[__session.ls_current_uri];
 2667 
 2668       if (uri == NULL)
 2669         uri = "(null)";
 2670 
 2671       if (tries)
 2672         syslog (LOG_INFO,
 2673           "nss_ldap: reconnected to LDAP server %s after %d attempt%s",
 2674           uri, tries, (tries == 1) ? "" : "s");
 2675       else
 2676         syslog (LOG_INFO, "nss_ldap: reconnected to LDAP server %s", uri);
 2677     }
 2678       time (&__session.ls_timestamp);
 2679       break;
 2680     default:
 2681       break;
 2682     }
 2683 
 2684   debug ("<== do_with_reconnect");
 2685   return stat;
 2686 }
 2687 
 2688 /*
 2689  * Synchronous search function. Don't call this directly;
 2690  * always wrap calls to this with do_with_reconnect(), or,
 2691  * better still, use _nss_ldap_search_s().
 2692  */
 2693 static int
 2694 do_search_s (const char *base, int scope,
 2695          const char *filter, const char **attrs, int sizelimit,
 2696          LDAPMessage ** res)
 2697 {
 2698   int rc;
 2699   struct timeval tv, *tvp;
 2700 
 2701   debug ("==> do_search_s");
 2702 
 2703 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_SIZELIMIT)
 2704   ldap_set_option (__session.ls_conn, LDAP_OPT_SIZELIMIT,
 2705            (void *) &sizelimit);
 2706 #else
 2707   __session.ls_conn->ld_sizelimit = sizelimit;
 2708 #endif /* LDAP_OPT_SIZELIMIT */
 2709 
 2710   if (__session.ls_config->ldc_timelimit == LDAP_NO_LIMIT)
 2711     {
 2712       tvp = NULL;
 2713     }
 2714   else
 2715     {
 2716       tv.tv_sec = __session.ls_config->ldc_timelimit;
 2717       tv.tv_usec = 0;
 2718       tvp = &tv;
 2719     }
 2720 
 2721   rc = ldap_search_st (__session.ls_conn, base, scope, filter,
 2722                (char **) attrs, 0, tvp, res);
 2723 
 2724   debug ("<== do_search_s");
 2725 
 2726   return rc;
 2727 }
 2728 
 2729 /*
 2730  * Asynchronous search function. Don't call this directly;
 2731  * always wrap calls to this with do_with_reconnect(), or,
 2732  * better still, use _nss_ldap_search().
 2733  */
 2734 static int
 2735 do_search (const char *base, int scope,
 2736        const char *filter, const char **attrs, int sizelimit, int *msgid)
 2737 {
 2738   int rc;
 2739   LDAPControl *serverCtrls[2];
 2740   LDAPControl **pServerCtrls;
 2741 
 2742   debug ("==> do_search");
 2743 
 2744 #ifdef HAVE_LDAP_SEARCH_EXT
 2745   if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_PAGED_RESULTS))
 2746     {
 2747       rc = ldap_create_page_control (__session.ls_conn,
 2748                      __session.ls_config->ldc_pagesize,
 2749                      NULL, 0, &serverCtrls[0]);
 2750       if (rc != LDAP_SUCCESS)
 2751     return rc;
 2752 
 2753       serverCtrls[1] = NULL;
 2754       pServerCtrls = serverCtrls;
 2755     }
 2756   else
 2757     {
 2758       pServerCtrls = NULL;
 2759     }
 2760 
 2761   rc = ldap_search_ext (__session.ls_conn, base, scope, filter,
 2762             (char **) attrs, 0, pServerCtrls, NULL,
 2763             LDAP_NO_LIMIT, sizelimit, msgid);
 2764 
 2765   if (pServerCtrls != NULL)
 2766     {
 2767       ldap_control_free (serverCtrls[0]);
 2768       serverCtrls[0] = NULL;
 2769     }
 2770 
 2771 #else
 2772 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_SIZELIMIT)
 2773   ldap_set_option (__session.ls_conn, LDAP_OPT_SIZELIMIT,
 2774            (void *) &sizelimit);
 2775 #else
 2776   __session.ls_conn->ld_sizelimit = sizelimit;
 2777 #endif /* LDAP_OPT_SIZELIMIT */
 2778 
 2779   *msgid = ldap_search (__session.ls_conn, base, scope, filter,
 2780             (char **) attrs, 0);
 2781   if (*msgid < 0)
 2782     {
 2783 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
 2784       if (ldap_get_option
 2785       (__session.ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
 2786     {
 2787       rc = LDAP_UNAVAILABLE;
 2788     }
 2789 #else
 2790       rc = __session.ls_conn->ld_errno;
 2791 #endif /* LDAP_OPT_ERROR_NUMBER */
 2792     }
 2793   else
 2794     {
 2795       rc = LDAP_SUCCESS;
 2796     }
 2797 #endif /* HAVE_LDAP_SEARCH_EXT */
 2798 
 2799   debug ("<== do_search");
 2800 
 2801   return rc;
 2802 }
 2803 
 2804 static void
 2805 do_map_errno (NSS_STATUS status, int *errnop)
 2806 {
 2807   if (status == NSS_TRYAGAIN)
 2808     {
 2809 #ifdef HAVE_NSSWITCH_H
 2810       errno = ERANGE;
 2811       *errnop = 1; /* this is really erange */
 2812 #else
 2813       *errnop = errno = ERANGE;
 2814 #endif
 2815     }
 2816   else
 2817     {
 2818       *errnop = 0;
 2819     }
 2820 }
 2821 
 2822 /*
 2823  * Tries parser function "parser" on entries, calling do_result()
 2824  * to retrieve them from the LDAP server until one parses
 2825  * correctly or there is an exceptional condition.
 2826  */
 2827 static NSS_STATUS
 2828 do_parse (ent_context_t * ctx, void *result, char
 2829       *buffer, size_t buflen, int *errnop, parser_t parser)
 2830 {
 2831   NSS_STATUS parseStat = NSS_NOTFOUND;
 2832 
 2833   debug ("==> do_parse");
 2834 
 2835   /*
 2836    * if ec_state.ls_info.ls_index is non-zero, then we don't collect another
 2837    * entry off the LDAP chain, and instead refeed the existing result to
 2838    * the parser. Once the parser has finished with it, it will return
 2839    * NSS_NOTFOUND and reset the index to -1, at which point we'll retrieve
 2840    * another entry.
 2841    */
 2842   do
 2843     {
 2844       NSS_STATUS resultStat = NSS_SUCCESS;
 2845 
 2846       if (ctx->ec_state.ls_retry == 0 &&
 2847       (ctx->ec_state.ls_type == LS_TYPE_KEY
 2848        || ctx->ec_state.ls_info.ls_index == -1))
 2849     {
 2850       resultStat = do_result (ctx, LDAP_MSG_ONE);
 2851     }
 2852 
 2853       if (resultStat != NSS_SUCCESS)
 2854     {
 2855       /* Could not get a result; bail */
 2856       parseStat = resultStat;
 2857       break;
 2858     }
 2859 
 2860       /*
 2861        * We have an entry; now, try to parse it.
 2862        *
 2863        * If we do not parse the entry because of a schema
 2864        * violation, the parser should return NSS_NOTFOUND.
 2865        * We'll keep on trying subsequent entries until we
 2866        * find one which is parseable, or exhaust avialable
 2867        * entries, whichever is first.
 2868        */
 2869       parseStat = parser (ctx->ec_res, &ctx->ec_state, result,
 2870               buffer, buflen);
 2871 
 2872       /* hold onto the state if we're out of memory XXX */
 2873       ctx->ec_state.ls_retry = (parseStat == NSS_TRYAGAIN && buffer != NULL ? 1 : 0);
 2874 
 2875       /* free entry is we're moving on */
 2876       if (ctx->ec_state.ls_retry == 0 &&
 2877       (ctx->ec_state.ls_type == LS_TYPE_KEY
 2878        || ctx->ec_state.ls_info.ls_index == -1))
 2879     {
 2880       /* we don't need the result anymore, ditch it. */
 2881       ldap_msgfree (ctx->ec_res);
 2882       ctx->ec_res = NULL;
 2883     }
 2884     }
 2885   while (parseStat == NSS_NOTFOUND);
 2886 
 2887   do_map_errno (parseStat, errnop);
 2888 
 2889   debug ("<== do_parse");
 2890 
 2891   return parseStat;
 2892 }
 2893 
 2894 /*
 2895  * Parse, fetching reuslts from chain instead of server.
 2896  */
 2897 static NSS_STATUS
 2898 do_parse_s (ent_context_t * ctx, void *result, char
 2899         *buffer, size_t buflen, int *errnop, parser_t parser)
 2900 {
 2901   NSS_STATUS parseStat = NSS_NOTFOUND;
 2902   LDAPMessage *e = NULL;
 2903 
 2904   debug ("==> do_parse_s");
 2905 
 2906   /*
 2907    * if ec_state.ls_info.ls_index is non-zero, then we don't collect another
 2908    * entry off the LDAP chain, and instead refeed the existing result to
 2909    * the parser. Once the parser has finished with it, it will return
 2910    * NSS_NOTFOUND and reset the index to -1, at which point we'll retrieve
 2911    * another entry.
 2912    */
 2913   do
 2914     {
 2915       if (ctx->ec_state.ls_retry == 0 &&
 2916       (ctx->ec_state.ls_type == LS_TYPE_KEY
 2917        || ctx->ec_state.ls_info.ls_index == -1))
 2918     {
 2919       if (e == NULL)
 2920         e = ldap_first_entry (__session.ls_conn, ctx->ec_res);
 2921       else
 2922         e = ldap_next_entry (__session.ls_conn, e);
 2923     }
 2924 
 2925       if (e == NULL)
 2926     {
 2927       /* Could not get a result; bail */
 2928       parseStat = NSS_NOTFOUND;
 2929       break;
 2930     }
 2931 
 2932       /*
 2933        * We have an entry; now, try to parse it. 
 2934        *
 2935        * If we do not parse the entry because of a schema
 2936        * violation, the parser should return NSS_NOTFOUND.
 2937        * We'll keep on trying subsequent entries until we
 2938        * find one which is parseable, or exhaust avialable
 2939        * entries, whichever is first.
 2940        */
 2941       parseStat = parser (e, &ctx->ec_state, result, buffer, buflen);
 2942 
 2943       /* hold onto the state if we're out of memory XXX */
 2944       ctx->ec_state.ls_retry = (parseStat == NSS_TRYAGAIN && buffer != NULL ? 1 : 0);
 2945     }
 2946   while (parseStat == NSS_NOTFOUND);
 2947 
 2948   do_map_errno (parseStat, errnop);
 2949 
 2950   debug ("<== do_parse_s");
 2951 
 2952   return parseStat;
 2953 }
 2954 
 2955 /*
 2956  * Read an entry from the directory, a la X.500. This is used
 2957  * for functions that need to retrieve attributes from a DN,
 2958  * such as the RFC2307bis group expansion function.
 2959  */
 2960 NSS_STATUS
 2961 _nss_ldap_read (const char *dn, const char **attributes, LDAPMessage ** res)
 2962 {
 2963   return do_with_reconnect (dn, LDAP_SCOPE_BASE, "(objectclass=*)",
 2964                 attributes, 1, /* sizelimit */ res,
 2965                 (search_func_t) do_search_s);
 2966 }
 2967 
 2968 /*
 2969  * Simple wrapper around ldap_get_values(). Requires that
 2970  * session is already established.
 2971  */
 2972 char **
 2973 _nss_ldap_get_values (LDAPMessage * e, const char *attr)
 2974 {
 2975   if (__session.ls_state != LS_CONNECTED_TO_DSA)
 2976     {
 2977       return NULL;
 2978     }
 2979   assert (__session.ls_conn != NULL);
 2980 
 2981   return ldap_get_values (__session.ls_conn, e, (char *) attr);
 2982 }
 2983 
 2984 /*
 2985  * Simple wrapper around ldap_get_dn(). Requires that
 2986  * session is already established.
 2987  */
 2988 char *
 2989 _nss_ldap_get_dn (LDAPMessage * e)
 2990 {
 2991   if (__session.ls_state != LS_CONNECTED_TO_DSA)
 2992     {
 2993       return NULL;
 2994     }
 2995   assert (__session.ls_conn != NULL);
 2996 
 2997   return ldap_get_dn (__session.ls_conn, e);
 2998 }
 2999 
 3000 /*
 3001  * Simple wrapper around ldap_first_entry(). Requires that
 3002  * session is already established.
 3003  */
 3004 LDAPMessage *
 3005 _nss_ldap_first_entry (LDAPMessage * res)
 3006 {
 3007   if (__session.ls_state != LS_CONNECTED_TO_DSA)
 3008     {
 3009       return NULL;
 3010     }
 3011   assert (__session.ls_conn != NULL);
 3012 
 3013   return ldap_first_entry (__session.ls_conn, res);
 3014 }
 3015 
 3016 /*
 3017  * Simple wrapper around ldap_next_entry(). Requires that
 3018  * session is already established.
 3019  */
 3020 LDAPMessage *
 3021 _nss_ldap_next_entry (LDAPMessage * res)
 3022 {
 3023   if (__session.ls_state != LS_CONNECTED_TO_DSA)
 3024     {
 3025       return NULL;
 3026     }
 3027   assert (__session.ls_conn != NULL);
 3028 
 3029   return ldap_next_entry (__session.ls_conn, res);
 3030 }
 3031 
 3032 char *
 3033 _nss_ldap_first_attribute (LDAPMessage * entry, BerElement ** berptr)
 3034 {
 3035   if (__session.ls_state != LS_CONNECTED_TO_DSA)
 3036     {
 3037       return NULL;
 3038     }
 3039   assert (__session.ls_conn != NULL);
 3040 
 3041   return ldap_first_attribute (__session.ls_conn, entry, berptr);
 3042 }
 3043 
 3044 char *
 3045 _nss_ldap_next_attribute (LDAPMessage * entry, BerElement * ber)
 3046 {
 3047   if (__session.ls_state != LS_CONNECTED_TO_DSA)
 3048     {
 3049       return NULL;
 3050     }
 3051   assert (__session.ls_conn != NULL);
 3052 
 3053   return ldap_next_attribute (__session.ls_conn, entry, ber);
 3054 }
 3055 
 3056 /*
 3057  * The generic synchronous lookup cover function.
 3058  * Assumes caller holds lock.
 3059  */
 3060 NSS_STATUS
 3061 _nss_ldap_search_s (const ldap_args_t * args,
 3062             const char *filterprot, ldap_map_selector_t sel, const
 3063             char **user_attrs, int sizelimit, LDAPMessage ** res)
 3064 {
 3065   char sdBase[LDAP_FILT_MAXSIZ];
 3066   const char *base = NULL;
 3067   char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
 3068   const char **attrs, *filter;
 3069   int scope;
 3070   NSS_STATUS stat;
 3071   ldap_service_search_descriptor_t *sd = NULL;
 3072 
 3073   debug ("==> _nss_ldap_search_s");
 3074 
 3075   stat = do_init ();
 3076   if (stat != NSS_SUCCESS)
 3077     {
 3078       debug ("<== _nss_ldap_search_s");
 3079       return stat;
 3080     }
 3081 
 3082   /* Set some reasonable defaults. */
 3083   base = __session.ls_config->ldc_base;
 3084   scope = __session.ls_config->ldc_scope;
 3085   attrs = NULL;
 3086 
 3087   if (args != NULL && args->la_base != NULL)
 3088     {
 3089       sel = LM_NONE;
 3090       base = args->la_base;
 3091     }
 3092 
 3093   if (sel < LM_NONE)
 3094     {
 3095       sd = __session.ls_config->ldc_sds[sel];
 3096     next:
 3097       if (sd != NULL)
 3098     {
 3099       size_t len = strlen (sd->lsd_base);
 3100       if (sd->lsd_base[len - 1] == ',')
 3101         {
 3102           /* is relative */
 3103           snprintf (sdBase, sizeof (sdBase),
 3104                       "%s%s", sd->lsd_base,
 3105                       __session.ls_config->ldc_base);
 3106           base = sdBase;
 3107         }
 3108       else
 3109         {
 3110           base = sd->lsd_base;
 3111         }
 3112 
 3113       if (sd->lsd_scope != -1)
 3114         {
 3115           scope = sd->lsd_scope;
 3116         }
 3117     }
 3118       attrs = __session.ls_config->ldc_attrtab[sel];
 3119     }
 3120 
 3121   stat =
 3122     do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
 3123            &dynamicFilterBuf, &filter);
 3124   if (stat != NSS_SUCCESS)
 3125     return stat;
 3126 
 3127   stat = do_with_reconnect (base, scope, filter,
 3128                 (user_attrs != NULL) ? user_attrs : attrs,
 3129                 sizelimit, res, (search_func_t) do_search_s);
 3130 
 3131   if (dynamicFilterBuf != NULL)
 3132     {
 3133       free (dynamicFilterBuf);
 3134       dynamicFilterBuf = NULL;
 3135     }
 3136 
 3137   if (stat == NSS_SUCCESS &&
 3138       ldap_count_entries (__session.ls_conn, *res) == 0) /* No results */
 3139     {
 3140       stat = NSS_NOTFOUND;
 3141       ldap_msgfree (*res);
 3142       *res = NULL;
 3143     }
 3144 
 3145   /* If no entry was returned, try the next search descriptor. */
 3146   if (sd != NULL && sd->lsd_next != NULL)
 3147     {
 3148       if (stat == NSS_NOTFOUND)
 3149     {
 3150       sd = sd->lsd_next;
 3151       goto next;
 3152     }
 3153     }
 3154 
 3155   debug ("<== _nss_ldap_search_s");
 3156 
 3157   return stat;
 3158 }
 3159 
 3160 /*
 3161  * The generic lookup cover function (asynchronous).
 3162  * Assumes caller holds lock.
 3163  */
 3164 NSS_STATUS
 3165 _nss_ldap_search (const ldap_args_t * args,
 3166           const char *filterprot, ldap_map_selector_t sel,
 3167           const char **user_attrs, int sizelimit, int *msgid,
 3168           ldap_service_search_descriptor_t ** csd)
 3169 {
 3170   char sdBase[LDAP_FILT_MAXSIZ];
 3171   const char *base = NULL;
 3172   char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
 3173   const char **attrs, *filter;
 3174   int scope;
 3175   NSS_STATUS stat;
 3176   ldap_service_search_descriptor_t *sd = NULL;
 3177 
 3178   debug ("==> _nss_ldap_search");
 3179 
 3180   *msgid = -1;
 3181 
 3182   stat = do_init ();
 3183   if (stat != NSS_SUCCESS)
 3184     {
 3185       debug ("<== _nss_ldap_search");
 3186       return stat;
 3187     }
 3188 
 3189   /* Set some reasonable defaults. */
 3190   base = __session.ls_config->ldc_base;
 3191   scope = __session.ls_config->ldc_scope;
 3192   attrs = NULL;
 3193 
 3194   if (args != NULL && args->la_base != NULL)
 3195     {
 3196       sel = LM_NONE;
 3197       base = args->la_base;
 3198     }
 3199 
 3200   if (sel < LM_NONE || *csd != NULL)
 3201     {
 3202       /*
 3203        * If we were chasing multiple descriptors and there are none left,
 3204        * just quit with NSS_NOTFOUND.
 3205        */
 3206       if (*csd != NULL)
 3207     {
 3208       sd = (*csd)->lsd_next;
 3209       if (sd == NULL)
 3210         return NSS_NOTFOUND;
 3211     }
 3212       else
 3213     {
 3214       sd = __session.ls_config->ldc_sds[sel];
 3215     }
 3216 
 3217       *csd = sd;
 3218 
 3219       if (sd != NULL)
 3220     {
 3221       size_t len = strlen (sd->lsd_base);
 3222       if (sd->lsd_base[len - 1] == ',')
 3223         {
 3224           /* is relative */
 3225           snprintf (sdBase, sizeof (sdBase), "%s%s", sd->lsd_base,
 3226             __session.ls_config->ldc_base);
 3227           base = sdBase;
 3228         }
 3229       else
 3230         {
 3231           base = sd->lsd_base;
 3232         }
 3233 
 3234       if (sd->lsd_scope != -1)
 3235         {
 3236           scope = sd->lsd_scope;
 3237         }
 3238     }
 3239       attrs = __session.ls_config->ldc_attrtab[sel];
 3240     }
 3241 
 3242   stat =
 3243     do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
 3244            &dynamicFilterBuf, &filter);
 3245   if (stat != NSS_SUCCESS)
 3246     return stat;
 3247 
 3248   stat = do_with_reconnect (base, scope, filter,
 3249                 (user_attrs != NULL) ? user_attrs : attrs,
 3250                 sizelimit, msgid, (search_func_t) do_search);
 3251 
 3252   if (dynamicFilterBuf != NULL)
 3253     free (dynamicFilterBuf);
 3254 
 3255   debug ("<== _nss_ldap_search");
 3256 
 3257   return stat;
 3258 }
 3259 
 3260 #ifdef HAVE_LDAP_SEARCH_EXT
 3261 static NSS_STATUS
 3262 do_next_page (const ldap_args_t * args,
 3263           const char *filterprot, ldap_map_selector_t sel, int
 3264           sizelimit, int *msgid, struct berval *pCookie)
 3265 {
 3266   char sdBase[LDAP_FILT_MAXSIZ];
 3267   const char *base = NULL;
 3268   char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
 3269   const char **attrs, *filter;
 3270   int scope;
 3271   NSS_STATUS stat;
 3272   ldap_service_search_descriptor_t *sd = NULL;
 3273   LDAPControl *serverctrls[2] = {
 3274     NULL, NULL
 3275   };
 3276 
 3277   /* Set some reasonable defaults. */
 3278   base = __session.ls_config->ldc_base;
 3279   scope = __session.ls_config->ldc_scope;
 3280   attrs = NULL;
 3281 
 3282   if (args != NULL && args->la_base != NULL)
 3283     {
 3284       sel = LM_NONE;
 3285       base = args->la_base;
 3286     }
 3287 
 3288   if (sel < LM_NONE)
 3289     {
 3290       sd = __session.ls_config->ldc_sds[sel];
 3291       if (sd != NULL)
 3292     {
 3293       size_t len = strlen (sd->lsd_base);
 3294       if (sd->lsd_base[len - 1] == ',')
 3295         {
 3296           snprintf (sdBase, sizeof (sdBase), "%s%s", sd->lsd_base,
 3297             __session.ls_config->ldc_base);
 3298           base = sdBase;
 3299         }
 3300       else
 3301         {
 3302           base = sd->lsd_base;
 3303         }
 3304 
 3305       if (sd->lsd_scope != -1)
 3306         {
 3307           scope = sd->lsd_scope;
 3308         }
 3309     }
 3310       attrs = __session.ls_config->ldc_attrtab[sel];
 3311     }
 3312 
 3313   stat =
 3314     do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
 3315            &dynamicFilterBuf, &filter);
 3316   if (stat != NSS_SUCCESS)
 3317     {
 3318       return stat;
 3319     }
 3320 
 3321   stat =
 3322     ldap_create_page_control (__session.ls_conn,
 3323                   __session.ls_config->ldc_pagesize,
 3324                   pCookie, 0, &serverctrls[0]);
 3325   if (stat != LDAP_SUCCESS)
 3326     {
 3327       if (dynamicFilterBuf != NULL)
 3328     free (dynamicFilterBuf);
 3329       return NSS_UNAVAIL;
 3330     }
 3331 
 3332   stat =
 3333     ldap_search_ext (__session.ls_conn, base,
 3334              __session.ls_config->ldc_scope,
 3335              filter,
 3336              (char **) attrs, 0, serverctrls, NULL, LDAP_NO_LIMIT,
 3337              sizelimit, msgid);
 3338 
 3339   ldap_control_free (serverctrls[0]);
 3340   if (dynamicFilterBuf != NULL)
 3341     free (dynamicFilterBuf);
 3342 
 3343   return (*msgid < 0) ? NSS_UNAVAIL : NSS_SUCCESS;
 3344 }
 3345 #endif /* HAVE_LDAP_SEARCH_EXT */
 3346 
 3347 /*
 3348  * General entry point for enumeration routines.
 3349  * This should really use the asynchronous LDAP search API to avoid 
 3350  * pulling down all the entries at once, particularly if the
 3351  * enumeration is not completed.
 3352  * Locks mutex.
 3353  */
 3354 NSS_STATUS
 3355 _nss_ldap_getent (ent_context_t ** ctx,
 3356           void *result, char *buffer, size_t buflen,
 3357           int *errnop, const char *filterprot,
 3358           ldap_map_selector_t sel, parser_t parser)
 3359 {
 3360   NSS_STATUS status;
 3361 
 3362   /*
 3363    * we need to lock here as the context may not be thread-specific
 3364    * data (under glibc, for example). Maybe we should make the lock part
 3365    * of the context.
 3366    */
 3367 
 3368   _nss_ldap_enter ();
 3369   status = _nss_ldap_getent_ex (NULL, ctx, result,
 3370                 buffer, buflen,
 3371                 errnop, filterprot, sel, NULL, parser);
 3372   _nss_ldap_leave ();
 3373 
 3374   return status;
 3375 }
 3376 
 3377 /*
 3378  * Internal entry point for enumeration routines.
 3379  * Caller holds global mutex
 3380  */
 3381 NSS_STATUS
 3382 _nss_ldap_getent_ex (ldap_args_t * args,
 3383              ent_context_t ** ctx, void *result,
 3384              char *buffer, size_t buflen, int *errnop,
 3385              const char *filterprot,
 3386              ldap_map_selector_t sel,
 3387              const char **user_attrs, parser_t parser)
 3388 {
 3389   NSS_STATUS stat = NSS_SUCCESS;
 3390 
 3391   debug ("==> _nss_ldap_getent_ex");
 3392 
 3393   if (*ctx != NULL && (*ctx)->ec_eof != 0)
 3394     {
 3395       debug ("<== _nss_ldap_getent_ex (EOF)");
 3396       return NSS_NOTFOUND;
 3397     }
 3398   else if (*ctx == NULL || (*ctx)->ec_msgid < 0)
 3399     {
 3400       /*
 3401        * implicitly call setent() if this is the first time
 3402        * or there is no active search
 3403        */
 3404       if (_nss_ldap_ent_context_init_locked (ctx) == NULL)
 3405     {
 3406       debug ("<== _nss_ldap_getent_ex");
 3407       return NSS_UNAVAIL;
 3408     }
 3409     }
 3410 
 3411 next:
 3412   /*
 3413    * If ctx->ec_msgid < 0, then we haven't searched yet. Let's do it!
 3414    */
 3415   if ((*ctx)->ec_msgid < 0)
 3416     {
 3417       int msgid;
 3418 
 3419       stat = _nss_ldap_search (args, filterprot, sel, user_attrs,
 3420                    LDAP_NO_LIMIT, &msgid, &(*ctx)->ec_sd);
 3421       if (stat != NSS_SUCCESS)
 3422     {
 3423       debug ("<== _nss_ldap_getent_ex");
 3424       return stat;
 3425     }
 3426 
 3427       (*ctx)->ec_msgid = msgid;
 3428     }
 3429 
 3430   stat = do_parse (*ctx, result, buffer, buflen, errnop, parser);
 3431 
 3432 #ifdef HAVE_LDAP_SEARCH_EXT
 3433   if (stat == NSS_NOTFOUND)
 3434     {
 3435       /* Is there another page of results? */
 3436       if ((*ctx)->ec_cookie != NULL && (*ctx)->ec_cookie->bv_len != 0)
 3437     {
 3438       int msgid;
 3439 
 3440       stat =
 3441         do_next_page (NULL, filterprot, sel, LDAP_NO_LIMIT, &msgid,
 3442               (*ctx)->ec_cookie);
 3443       if (stat != NSS_SUCCESS)
 3444         {
 3445           debug ("<== _nss_ldap_getent_ex");
 3446           return stat;
 3447         }
 3448       (*ctx)->ec_msgid = msgid;
 3449       stat = do_parse (*ctx, result, buffer, buflen, errnop, parser);
 3450     }
 3451     }
 3452 #endif /* HAVE_LDAP_SEARCH_EXT */
 3453 
 3454   if (stat == NSS_NOTFOUND)
 3455     {
 3456       if ((*ctx)->ec_sd != NULL)
 3457     {
 3458       (*ctx)->ec_msgid = -1;
 3459       goto next;
 3460     }
 3461       else
 3462     {
 3463       /* Mark notional end of file */
 3464       (*ctx)->ec_eof = 1;
 3465     }
 3466     }
 3467 
 3468   debug ("<== _nss_ldap_getent_ex");
 3469 
 3470   return stat;
 3471 }
 3472 
 3473 /*
 3474  * General match function.
 3475  * Locks mutex. 
 3476  */
 3477 NSS_STATUS
 3478 _nss_ldap_getbyname (ldap_args_t * args,
 3479              void *result, char *buffer, size_t buflen, int
 3480              *errnop, const char *filterprot,
 3481              ldap_map_selector_t sel, parser_t parser)
 3482 {
 3483   NSS_STATUS stat = NSS_NOTFOUND;
 3484   ent_context_t ctx;
 3485 
 3486   _nss_ldap_enter ();
 3487 
 3488   debug ("==> _nss_ldap_getbyname");
 3489 
 3490   ctx.ec_msgid = -1;
 3491   ctx.ec_cookie = NULL;
 3492   ctx.ec_eof = 0;
 3493 
 3494   stat = _nss_ldap_search_s (args, filterprot, sel, NULL, 1, &ctx.ec_res);
 3495   if (stat != NSS_SUCCESS)
 3496     {
 3497       _nss_ldap_leave ();
 3498       debug ("<== _nss_ldap_getbyname");
 3499       return stat;
 3500     }
 3501 
 3502   /*
 3503    * we pass this along for the benefit of the services parser,
 3504    * which uses it to figure out which protocol we really wanted.
 3505    * we only pass the second argument along, as that's what we need
 3506    * in services.
 3507    */
 3508   LS_INIT (ctx.ec_state);
 3509   ctx.ec_state.ls_type = LS_TYPE_KEY;
 3510   ctx.ec_state.ls_info.ls_key = args->la_arg2.la_string;
 3511 
 3512   stat = do_parse_s (&ctx, result, buffer, buflen, errnop, parser);
 3513 
 3514   do_context_release (&ctx, 0);
 3515 
 3516   /* moved unlock here to avoid race condition bug #49 */
 3517   _nss_ldap_leave ();
 3518 
 3519   debug ("<== _nss_ldap_getbyname");
 3520 
 3521   return stat;
 3522 }
 3523 
 3524 /*
 3525  * These functions are called from within the parser, where it is assumed
 3526  * to be safe to use the connection and the respective message.
 3527  */
 3528 
 3529 /*
 3530  * Assign all values, bar omitvalue (if not NULL), to *valptr.
 3531  */
 3532 NSS_STATUS
 3533 _nss_ldap_assign_attrvals (LDAPMessage * e,
 3534                const char *attr, const char *omitvalue,
 3535                char ***valptr, char **pbuffer, size_t *
 3536                pbuflen, size_t * pvalcount)
 3537 {
 3538   char **vals;
 3539   char **valiter;
 3540   int valcount;
 3541   char **p = NULL;
 3542 
 3543   register int buflen = *pbuflen;
 3544   register char *buffer = *pbuffer;
 3545 
 3546   if (pvalcount != NULL)
 3547     {
 3548       *pvalcount = 0;
 3549     }
 3550 
 3551   if (__session.ls_conn == NULL)
 3552     {
 3553       return NSS_UNAVAIL;
 3554     }
 3555 
 3556   vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
 3557 
 3558   valcount = (vals == NULL) ? 0 : ldap_count_values (vals);
 3559   if (bytesleft (buffer, buflen, char *) < (valcount + 1) * sizeof (char *))
 3560     {
 3561       ldap_value_free (vals);
 3562       return NSS_TRYAGAIN;
 3563     }
 3564 
 3565   align (buffer, buflen, char *);
 3566   p = *valptr = (char **) buffer;
 3567 
 3568   buffer += (valcount + 1) * sizeof (char *);
 3569   buflen -= (valcount + 1) * sizeof (char *);
 3570 
 3571   if (valcount == 0)
 3572     {
 3573       *p = NULL;
 3574       *pbuffer = buffer;
 3575       *pbuflen = buflen;
 3576       return NSS_SUCCESS;
 3577     }
 3578 
 3579   valiter = vals;
 3580 
 3581   while (*valiter != NULL)
 3582     {
 3583       int vallen;
 3584       char *elt = NULL;
 3585 
 3586       if (omitvalue != NULL && strcmp (*valiter, omitvalue) == 0)
 3587     {
 3588       valcount--;
 3589     }
 3590       else
 3591     {
 3592       vallen = strlen (*valiter);
 3593       if (buflen < (size_t) (vallen + 1))
 3594         {
 3595           ldap_value_free (vals);
 3596           return NSS_TRYAGAIN;
 3597         }
 3598 
 3599       /* copy this value into the next block of buffer space */
 3600       elt = buffer;
 3601       buffer += vallen + 1;
 3602       buflen -= vallen + 1;
 3603 
 3604       strncpy (elt, *valiter, vallen);
 3605       elt[vallen] = '\0';
 3606       *p = elt;
 3607       p++;
 3608     }
 3609       valiter++;
 3610     }
 3611 
 3612   *p = NULL;
 3613   *pbuffer = buffer;
 3614   *pbuflen = buflen;
 3615 
 3616   if (pvalcount != NULL)
 3617     {
 3618       *pvalcount = valcount;
 3619     }
 3620 
 3621   ldap_value_free (vals);
 3622   return NSS_SUCCESS;
 3623 }
 3624 
 3625 /* Assign a single value to *valptr. */
 3626 NSS_STATUS
 3627 _nss_ldap_assign_attrval (LDAPMessage * e,
 3628               const char *attr, char **valptr, char **buffer,
 3629               size_t * buflen)
 3630 {
 3631   char **vals;
 3632   int vallen;
 3633   const char *ovr, *def;
 3634 
 3635   ovr = OV (attr);
 3636   if (ovr != NULL)
 3637     {
 3638       vallen = strlen (ovr);
 3639       if (*buflen < (size_t) (vallen + 1))
 3640     {
 3641       return NSS_TRYAGAIN;
 3642     }
 3643 
 3644       *valptr = *buffer;
 3645 
 3646       strncpy (*valptr, ovr, vallen);
 3647       (*valptr)[vallen] = '\0';
 3648 
 3649       *buffer += vallen + 1;
 3650       *buflen -= vallen + 1;
 3651 
 3652       return NSS_SUCCESS;
 3653     }
 3654 
 3655   if (__session.ls_conn == NULL)
 3656     {
 3657       return NSS_UNAVAIL;
 3658     }
 3659 
 3660   vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
 3661   if (vals == NULL)
 3662     {
 3663       def = DF (attr);
 3664       if (def != NULL)
 3665     {
 3666       vallen = strlen (def);
 3667       if (*buflen < (size_t) (vallen + 1))
 3668         {
 3669           return NSS_TRYAGAIN;
 3670         }
 3671 
 3672       *valptr = *buffer;
 3673 
 3674       strncpy (*valptr, def, vallen);
 3675       (*valptr)[vallen] = '\0';
 3676 
 3677       *buffer += vallen + 1;
 3678       *buflen -= vallen + 1;
 3679 
 3680       return NSS_SUCCESS;
 3681     }
 3682       else
 3683     {
 3684       return NSS_NOTFOUND;
 3685     }
 3686     }
 3687 
 3688   vallen = strlen (*vals);
 3689   if (*buflen < (size_t) (vallen + 1))
 3690     {
 3691       ldap_value_free (vals);
 3692       return NSS_TRYAGAIN;
 3693     }
 3694 
 3695   *valptr = *buffer;
 3696 
 3697   strncpy (*valptr, *vals, vallen);
 3698   (*valptr)[vallen] = '\0';
 3699 
 3700   *buffer += vallen + 1;
 3701   *buflen -= vallen + 1;
 3702 
 3703   ldap_value_free (vals);
 3704 
 3705   return NSS_SUCCESS;
 3706 }
 3707 
 3708 const char *
 3709 _nss_ldap_locate_userpassword (char **vals)
 3710 {
 3711   const char *token = NULL;
 3712   size_t token_length = 0;
 3713   char **valiter;
 3714   const char *pwd = NULL;
 3715 
 3716   if (__config != NULL)
 3717     {
 3718       switch (__config->ldc_password_type)
 3719     {
 3720     case LU_RFC2307_USERPASSWORD:
 3721       token = "{CRYPT}";
 3722       token_length = sizeof ("{CRYPT}") - 1;
 3723       break;
 3724     case LU_RFC3112_AUTHPASSWORD:
 3725       token = "CRYPT$";
 3726       token_length = sizeof ("CRYPT$") - 1;
 3727       break;
 3728     case LU_OTHER_PASSWORD:
 3729       break;
 3730     }
 3731     }
 3732 
 3733   if (vals != NULL)
 3734     {
 3735       for (valiter = vals; *valiter != NULL; valiter++)
 3736     {
 3737       if (token_length == 0 ||
 3738           strncasecmp (*valiter, token, token_length) == 0)
 3739         {
 3740           pwd = *valiter;
 3741           break;
 3742         }
 3743     }
 3744     }
 3745 
 3746   if (pwd == NULL)
 3747     pwd = "*";
 3748   else
 3749     pwd += token_length;
 3750 
 3751   return pwd;
 3752 }
 3753 
 3754 /*
 3755  * Assign a single value to *valptr, after examining userPassword for
 3756  * a syntactically suitable value.
 3757  */
 3758 NSS_STATUS
 3759 _nss_ldap_assign_userpassword (LDAPMessage * e,
 3760                    const char *attr, char **valptr,
 3761                    char **buffer, size_t * buflen)
 3762 {
 3763   char **vals;
 3764   const char *pwd;
 3765   int vallen;
 3766 
 3767   debug ("==> _nss_ldap_assign_userpassword");
 3768 
 3769   if (__session.ls_conn == NULL)
 3770     {
 3771       return NSS_UNAVAIL;
 3772     }
 3773 
 3774   vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
 3775   pwd = _nss_ldap_locate_userpassword (vals);
 3776 
 3777   vallen = strlen (pwd);
 3778 
 3779   if (*buflen < (size_t) (vallen + 1))
 3780     {
 3781       if (vals != NULL)
 3782     {
 3783       ldap_value_free (vals);
 3784     }
 3785       debug ("<== _nss_ldap_assign_userpassword");
 3786       return NSS_TRYAGAIN;
 3787     }
 3788 
 3789   *valptr = *buffer;
 3790 
 3791   strncpy (*valptr, pwd, vallen);
 3792   (*valptr)[vallen] = '\0';
 3793 
 3794   *buffer += vallen + 1;
 3795   *buflen -= vallen + 1;
 3796 
 3797   if (vals != NULL)
 3798     {
 3799       ldap_value_free (vals);
 3800     }
 3801 
 3802   debug ("<== _nss_ldap_assign_userpassword");
 3803 
 3804   return NSS_SUCCESS;
 3805 }
 3806 
 3807 NSS_STATUS
 3808 _nss_ldap_oc_check (LDAPMessage * e, const char *oc)
 3809 {
 3810   char **vals, **valiter;
 3811   NSS_STATUS ret = NSS_NOTFOUND;
 3812 
 3813   if (__session.ls_conn == NULL)
 3814     {
 3815       return NSS_UNAVAIL;
 3816     }
 3817 
 3818   vals = ldap_get_values (__session.ls_conn, e, AT (objectClass));
 3819   if (vals != NULL)
 3820     {
 3821       for (valiter = vals; *valiter != NULL; valiter++)
 3822     {
 3823       if (strcasecmp (*valiter, oc) == 0)
 3824         {
 3825           ret = NSS_SUCCESS;
 3826           break;
 3827         }
 3828     }
 3829     }
 3830 
 3831   if (vals != NULL)
 3832     {
 3833       ldap_value_free (vals);
 3834     }
 3835 
 3836   return ret;
 3837 }
 3838 
 3839 #ifdef HAVE_SHADOW_H
 3840 NSS_STATUS
 3841 _nss_ldap_shadow_date (const char *val, long default_date, long *value)
 3842 {
 3843   int date;
 3844   char *p;
 3845   long long ll;
 3846 
 3847   if (val == NULL || strlen(val) == 0)
 3848     {
 3849       *value = default_date;
 3850       return NSS_NOTFOUND;
 3851     }
 3852   ll = strtoll(val, &p, 10);
 3853   if (p == NULL || p == val || *p != '\0')
 3854     {
 3855       *value = default_date;
 3856       return NSS_NOTFOUND;
 3857     }
 3858   if (__config->ldc_shadow_type == LS_AD_SHADOW)
 3859     {
 3860       date = ll / 864000000000LL - 134774LL;
 3861       date = (date > 99999) ? 99999 : date;
 3862     }
 3863   else
 3864     {
 3865       date = ll;
 3866     }
 3867 
 3868   *value = date;
 3869   return NSS_SUCCESS;
 3870 }
 3871 
 3872 void
 3873 _nss_ldap_shadow_handle_flag (struct spwd *sp)
 3874 {
 3875   if (__config->ldc_shadow_type == LS_AD_SHADOW)
 3876     {
 3877       if (sp->sp_flag & UF_DONT_EXPIRE_PASSWD)
 3878     sp->sp_max = 99999;
 3879       sp->sp_flag = 0;
 3880     }
 3881 }
 3882 #endif /* HAVE_SHADOW_H */
 3883 
 3884 const char *
 3885 _nss_ldap_map_at (ldap_map_selector_t sel, const char *attribute)
 3886 {
 3887   const char *mapped = NULL;
 3888   NSS_STATUS stat;
 3889 
 3890   stat = _nss_ldap_map_get (__config, sel, MAP_ATTRIBUTE, attribute, &mapped);
 3891 
 3892   return (stat == NSS_SUCCESS) ? mapped : attribute;
 3893 }
 3894 
 3895 const char *
 3896 _nss_ldap_unmap_at (ldap_map_selector_t sel, const char *attribute)
 3897 {
 3898   const char *mapped = NULL;
 3899   NSS_STATUS stat;
 3900 
 3901   stat = _nss_ldap_map_get (__config, sel, MAP_ATTRIBUTE_REVERSE, attribute, &mapped);
 3902 
 3903   return (stat == NSS_SUCCESS) ? mapped : attribute;
 3904 }
 3905 
 3906 const char *
 3907 _nss_ldap_map_oc (ldap_map_selector_t sel, const char *objectclass)
 3908 {
 3909   const char *mapped = NULL;
 3910   NSS_STATUS stat;
 3911 
 3912   stat = _nss_ldap_map_get (__config, sel, MAP_OBJECTCLASS, objectclass, &mapped);
 3913 
 3914   return (stat == NSS_SUCCESS) ? mapped : objectclass;
 3915 }
 3916 
 3917 const char *
 3918 _nss_ldap_unmap_oc (ldap_map_selector_t sel, const char *objectclass)
 3919 {
 3920   const char *mapped = NULL;
 3921   NSS_STATUS stat;
 3922 
 3923   stat = _nss_ldap_map_get (__config, sel, MAP_OBJECTCLASS_REVERSE, objectclass, &mapped);
 3924 
 3925   return (stat == NSS_SUCCESS) ? mapped : objectclass;
 3926 }
 3927 
 3928 const char *
 3929 _nss_ldap_map_ov (const char *attribute)
 3930 {
 3931   const char *value = NULL;
 3932 
 3933   _nss_ldap_map_get (__config, LM_NONE, MAP_OVERRIDE, attribute, &value);
 3934 
 3935   return value;
 3936 }
 3937 
 3938 const char *
 3939 _nss_ldap_map_df (const char *attribute)
 3940 {
 3941   const char *value = NULL;
 3942 
 3943   _nss_ldap_map_get (__config, LM_NONE, MAP_DEFAULT, attribute, &value);
 3944 
 3945   return value;
 3946 }
 3947 
 3948 NSS_STATUS
 3949 _nss_ldap_map_put (ldap_config_t * config,
 3950            ldap_map_selector_t sel,
 3951            ldap_map_type_t type,
 3952            const char *from,
 3953            const char *to)
 3954 {
 3955   ldap_datum_t key, val;
 3956   void **map;
 3957   NSS_STATUS stat;
 3958 
 3959   switch (type)
 3960     {
 3961     case MAP_ATTRIBUTE:
 3962       /* special handling for attribute mapping */ if (strcmp
 3963                                (from,
 3964                             "userPassword") == 0)
 3965     {
 3966       if (strcasecmp (to, "userPassword") == 0)
 3967         config->ldc_password_type = LU_RFC2307_USERPASSWORD;
 3968       else if (strcasecmp (to, "authPassword") == 0)
 3969         config->ldc_password_type = LU_RFC3112_AUTHPASSWORD;
 3970       else
 3971         config->ldc_password_type = LU_OTHER_PASSWORD;
 3972     }
 3973       else if (strcmp (from, "shadowLastChange") == 0)
 3974     {
 3975       if (strcasecmp (to, "shadowLastChange") == 0)
 3976         config->ldc_shadow_type = LS_RFC2307_SHADOW;
 3977       else if (strcasecmp (to, "pwdLastSet") == 0)
 3978         config->ldc_shadow_type = LS_AD_SHADOW;
 3979       else
 3980         config->ldc_shadow_type = LS_OTHER_SHADOW;
 3981     }
 3982       break;
 3983     case MAP_OBJECTCLASS:
 3984     case MAP_OVERRIDE:
 3985     case MAP_DEFAULT:
 3986       break;
 3987     default:
 3988       return NSS_NOTFOUND;
 3989       break;
 3990     }
 3991 
 3992   assert (sel <= LM_NONE);
 3993   map = &config->ldc_maps[sel][type];
 3994   assert (*map != NULL);
 3995 
 3996   NSS_LDAP_DATUM_ZERO (&key);
 3997   key.data = (void *) from;
 3998   key.size = strlen (from) + 1;
 3999 
 4000   NSS_LDAP_DATUM_ZERO (&val);
 4001   val.data = (void *) to;
 4002   val.size = strlen (to) + 1;
 4003 
 4004   stat = _nss_ldap_db_put (*map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
 4005   if (stat == NSS_SUCCESS &&
 4006       (type == MAP_ATTRIBUTE || type == MAP_OBJECTCLASS))
 4007     {
 4008       type = (type == MAP_ATTRIBUTE) ? MAP_ATTRIBUTE_REVERSE : MAP_OBJECTCLASS_REVERSE;
 4009       map = &config->ldc_maps[sel][type];
 4010 
 4011       stat = _nss_ldap_db_put (*map, NSS_LDAP_DB_NORMALIZE_CASE, &val, &key);
 4012     }
 4013 
 4014   return stat;
 4015 }
 4016 
 4017 NSS_STATUS
 4018 _nss_ldap_map_get (ldap_config_t * config,
 4019            ldap_map_selector_t sel,
 4020            ldap_map_type_t type,
 4021            const char *from, const char **to)
 4022 {
 4023   ldap_datum_t key, val;
 4024   void *map;
 4025   NSS_STATUS stat;
 4026 
 4027   if (config == NULL || sel > LM_NONE || type > MAP_MAX)
 4028     {
 4029       return NSS_NOTFOUND;
 4030     }
 4031 
 4032   map = config->ldc_maps[sel][type];
 4033   assert (map != NULL);
 4034 
 4035   NSS_LDAP_DATUM_ZERO (&key);
 4036   key.data = (void *) from;
 4037   key.size = strlen (from) + 1;
 4038 
 4039   NSS_LDAP_DATUM_ZERO (&val);
 4040 
 4041   stat = _nss_ldap_db_get (map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
 4042   if (stat == NSS_NOTFOUND && sel != LM_NONE)
 4043     {
 4044       map = config->ldc_maps[LM_NONE][type];
 4045       assert (map != NULL);
 4046       stat = _nss_ldap_db_get (map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
 4047     }
 4048 
 4049   if (stat == NSS_SUCCESS)
 4050     *to = (char *) val.data;
 4051   else
 4052     *to = NULL;
 4053 
 4054   return stat;
 4055 }
 4056 
 4057 /*
 4058  * Proxy bind support for AIX. Very simple, but should do
 4059  * the job. 
 4060  */
 4061 
 4062 #if LDAP_SET_REBIND_PROC_ARGS < 3
 4063 static ldap_proxy_bind_args_t __proxy_args = { NULL, NULL };
 4064 #endif
 4065 
 4066 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
 4067 #if LDAP_SET_REBIND_PROC_ARGS == 3
 4068 static int
 4069 do_proxy_rebind (LDAP * ld, LDAP_CONST char *url, ber_tag_t request,
 4070          ber_int_t msgid, void *arg)
 4071 #else
 4072 static int
 4073 do_proxy_rebind (LDAP * ld, LDAP_CONST char *url, int request,
 4074          ber_int_t msgid)
 4075 #endif
 4076 {
 4077   int timelimit;
 4078 #if LDAP_SET_REBIND_PROC_ARGS == 3
 4079   ldap_proxy_bind_args_t *who = (ldap_proxy_bind_args_t *) arg;
 4080 #else
 4081   ldap_proxy_bind_args_t *who = &__proxy_args;
 4082 #endif
 4083 
 4084   timelimit = __session.ls_config->ldc_bind_timelimit;
 4085 
 4086   return do_bind (ld, timelimit, who->binddn, who->bindpw, 0);
 4087 }
 4088 #else
 4089 #if LDAP_SET_REBIND_PROC_ARGS == 3
 4090 static int
 4091 do_proxy_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
 4092          int freeit, void *arg)
 4093 #elif LDAP_SET_REBIND_PROC_ARGS == 2
 4094 static int
 4095 do_proxy_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
 4096          int freeit)
 4097 #endif
 4098 {
 4099 #if LDAP_SET_REBIND_PROC_ARGS == 3
 4100   ldap_proxy_bind_args_t *who = (ldap_proxy_bind_args_t *) arg;
 4101 #else
 4102   ldap_proxy_bind_args_t *who = &__proxy_args;
 4103 #endif
 4104   if (freeit)
 4105     {
 4106       if (*whop != NULL)
 4107     free (*whop);
 4108       if (*credp != NULL)
 4109     free (*credp);
 4110     }
 4111 
 4112   *whop = who->binddn ? strdup (who->binddn) : NULL;
 4113   *credp = who->bindpw ? strdup (who->bindpw) : NULL;
 4114 
 4115   *methodp = LDAP_AUTH_SIMPLE;
 4116 
 4117   return LDAP_SUCCESS;
 4118 }
 4119 #endif
 4120 
 4121 NSS_STATUS
 4122 _nss_ldap_proxy_bind (const char *user, const char *password)
 4123 {
 4124   ldap_args_t args;
 4125   LDAPMessage *res, *e;
 4126   NSS_STATUS stat;
 4127   int rc;
 4128 #if LDAP_SET_REBIND_PROC_ARGS == 3
 4129   ldap_proxy_bind_args_t proxy_args_buf;
 4130   ldap_proxy_bind_args_t *proxy_args = &proxy_args_buf;
 4131 #else
 4132   ldap_proxy_bind_args_t *proxy_args = &__proxy_args;
 4133 #endif
 4134 
 4135   debug ("==> _nss_ldap_proxy_bind");
 4136 
 4137   LA_INIT (args);
 4138   LA_TYPE (args) = LA_TYPE_STRING;
 4139   LA_STRING (args) = user;
 4140 
 4141   /*
 4142    * Binding with an empty password will always work, so don't let
 4143    * the user in if they try that.
 4144    */
 4145   if (password == NULL || password[0] == '\0')
 4146     {
 4147       debug ("<== _nss_ldap_proxy_bind (empty password not permitted)");
 4148       /* XXX overload */
 4149       return NSS_TRYAGAIN;
 4150     }
 4151 
 4152   _nss_ldap_enter ();
 4153 
 4154   stat = _nss_ldap_search_s (&args, _nss_ldap_filt_getpwnam,
 4155                  LM_PASSWD, NULL, 1, &res);
 4156   if (stat == NSS_SUCCESS)
 4157     {
 4158       e = _nss_ldap_first_entry (res);
 4159       if (e != NULL)
 4160     {
 4161       proxy_args->binddn = _nss_ldap_get_dn (e);
 4162       proxy_args->bindpw = password;
 4163 
 4164       if (proxy_args->binddn != NULL)
 4165         {
 4166           /* Use our special rebind procedure. */
 4167 #if LDAP_SET_REBIND_PROC_ARGS == 3
 4168           ldap_set_rebind_proc (__session.ls_conn, do_proxy_rebind, NULL);
 4169 #elif LDAP_SET_REBIND_PROC_ARGS == 2
 4170           ldap_set_rebind_proc (__session.ls_conn, do_proxy_rebind);
 4171 #endif
 4172 
 4173           debug (":== _nss_ldap_proxy_bind: %s", proxy_args->binddn);
 4174 
 4175           rc = do_bind (__session.ls_conn,
 4176                 __session.ls_config->ldc_bind_timelimit,
 4177                 proxy_args->binddn, proxy_args->bindpw, 0);
 4178           switch (rc)
 4179         {
 4180         case LDAP_INVALID_CREDENTIALS:
 4181           /* XXX overload */
 4182           stat = NSS_TRYAGAIN;
 4183           break;
 4184         case LDAP_NO_SUCH_OBJECT:
 4185           stat = NSS_NOTFOUND;
 4186           break;
 4187         case LDAP_SUCCESS:
 4188           stat = NSS_SUCCESS;
 4189           break;
 4190         default:
 4191           stat = NSS_UNAVAIL;
 4192           break;
 4193         }
 4194           /*
 4195            * Close the connection, don't want to continue
 4196            * being bound as this user or using this rebind proc.
 4197            */
 4198           do_close ();
 4199           ldap_memfree (proxy_args->binddn);
 4200         }
 4201       else
 4202         {
 4203           stat = NSS_NOTFOUND;
 4204         }
 4205       proxy_args->binddn = NULL;
 4206       proxy_args->bindpw = NULL;
 4207     }
 4208       else
 4209     {
 4210       stat = NSS_NOTFOUND;
 4211     }
 4212       ldap_msgfree (res);
 4213     }
 4214 
 4215   _nss_ldap_leave ();
 4216 
 4217   debug ("<== _nss_ldap_proxy_bind");
 4218 
 4219   return stat;
 4220 }
 4221 
 4222 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) ||defined (HAVE_SASL_SASL_H))
 4223 static int
 4224 do_sasl_interact (LDAP * ld, unsigned flags, void *defaults, void *_interact)
 4225 {
 4226   char *authzid = (char *) defaults;
 4227   sasl_interact_t *interact = (sasl_interact_t *) _interact;
 4228 
 4229   while (interact->id != SASL_CB_LIST_END)
 4230     {
 4231       if (interact->id == SASL_CB_USER)
 4232     {
 4233       if (authzid != NULL)
 4234         {
 4235           interact->result = authzid;
 4236           interact->len = strlen (authzid);
 4237         }
 4238       else if (interact->defresult != NULL)
 4239         {
 4240           interact->result = interact->defresult;
 4241           interact->len = strlen (interact->defresult);
 4242         }
 4243       else
 4244         {
 4245           interact->result = "";
 4246           interact->len = 0;
 4247         }
 4248 #if SASL_VERSION_MAJOR < 2
 4249       interact->result = strdup (interact->result);
 4250       if (interact->result == NULL)
 4251         {
 4252           return LDAP_NO_MEMORY;
 4253         }
 4254 #endif /* SASL_VERSION_MAJOR < 2 */
 4255     }
 4256       else
 4257     {
 4258       return LDAP_PARAM_ERROR;
 4259     }
 4260       interact++;
 4261     }
 4262   return LDAP_SUCCESS;
 4263 }
 4264 #endif
 4265 
 4266 const char **
 4267 _nss_ldap_get_attributes (ldap_map_selector_t sel)
 4268 {
 4269   const char **attrs = NULL;
 4270 
 4271   debug ("==> _nss_ldap_get_attributes");
 4272 
 4273   if (sel < LM_NONE)
 4274     {
 4275       if (do_init () != NSS_SUCCESS)
 4276     {
 4277       debug ("<== _nss_ldap_get_attributes (init failed)");
 4278       return NULL;
 4279     }
 4280 
 4281       attrs = __session.ls_config->ldc_attrtab[sel];
 4282     }
 4283 
 4284   debug ("<== _nss_ldap_get_attributes");
 4285 
 4286   return attrs;
 4287 }
 4288 
 4289 int
 4290 _nss_ldap_test_config_flag (unsigned int flag)
 4291 {
 4292   if (__config != NULL && (__config->ldc_flags & flag) != 0)
 4293     return 1;
 4294 
 4295   return 0;
 4296 }
 4297 
 4298 int
 4299 _nss_ldap_test_initgroups_ignoreuser (const char *user)
 4300 {
 4301   char **p;
 4302 
 4303   if (__config == NULL)
 4304     return 0;
 4305 
 4306   if (__config->ldc_initgroups_ignoreusers == NULL)
 4307     return 0;
 4308 
 4309   for (p = __config->ldc_initgroups_ignoreusers; *p != NULL; p++)
 4310     {
 4311       if (strcmp (*p, user) == 0)
 4312     return 1;
 4313     }
 4314 
 4315   return 0;
 4316 }
 4317 
 4318 int
 4319 _nss_ldap_get_ld_errno (char **m, char **s)
 4320 {
 4321 #ifdef HAVE_LDAP_GET_OPTION
 4322   int rc;
 4323 #endif
 4324   int lderrno;
 4325 
 4326   if (__session.ls_conn == NULL)
 4327     {
 4328       return LDAP_UNAVAILABLE;
 4329     }
 4330 
 4331 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
 4332   /* is this needed? */
 4333   rc = ldap_get_option (__session.ls_conn, LDAP_OPT_ERROR_NUMBER, &lderrno);
 4334   if (rc != LDAP_SUCCESS)
 4335     return rc;
 4336 #else
 4337   lderrno = ld->ld_errno;
 4338 #endif
 4339 
 4340   if (s != NULL)
 4341     {
 4342 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_STRING)
 4343       rc = ldap_get_option (__session.ls_conn, LDAP_OPT_ERROR_STRING, s);
 4344       if (rc != LDAP_SUCCESS)
 4345     return rc;
 4346 #else
 4347       *s = ld->ld_error;
 4348 #endif
 4349     }
 4350 
 4351   if (m != NULL)
 4352     {
 4353 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_MATCHED_DN)
 4354       rc = ldap_get_option (__session.ls_conn, LDAP_OPT_MATCHED_DN, m);
 4355       if (rc != LDAP_SUCCESS)
 4356     return rc;
 4357 #else
 4358       *m = ld->ld_matched;
 4359 #endif
 4360     }
 4361 
 4362   return lderrno;
 4363 }
 4364 
 4365