"Fossies" - the Fresh Open Source Software Archive

Member "nss_ldap-265/util.c" (6 Nov 2009, 38593 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-2005 Luke Howard.
    2    This file is part of the nss_ldap library.
    3    Contributed by Luke Howard, <lukeh@padl.com>, 1997.
    4    (The author maintains a non-exclusive licence to distribute this file
    5    under their own conditions.)
    6 
    7    The nss_ldap library is free software; you can redistribute it and/or
    8    modify it under the terms of the GNU Library General Public License as
    9    published by the Free Software Foundation; either version 2 of the
   10    License, or (at your option) any later version.
   11 
   12    The nss_ldap library is distributed in the hope that it will be useful,
   13    but WITHOUT ANY WARRANTY; without even the implied warranty of
   14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15    Library General Public License for more details.
   16 
   17    You should have received a copy of the GNU Library General Public
   18    License along with the nss_ldap library; see the file COPYING.LIB.  If not,
   19    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   20    Boston, MA 02111-1307, USA.
   21  */
   22 
   23 #include "config.h"
   24 
   25 #if defined(HAVE_THREAD_H) && !defined(_AIX)
   26 #include <thread.h>
   27 #elif defined(HAVE_PTHREAD_H)
   28 #include <pthread.h>
   29 #endif
   30 
   31 #include <stdio.h>
   32 #include <string.h>
   33 #ifdef HAVE_STRINGS_H
   34 #include <strings.h>
   35 #endif
   36 #include <stdlib.h>
   37 
   38 #include <sys/param.h>
   39 #include <sys/stat.h>
   40 
   41 #include <netdb.h>
   42 #include <syslog.h>
   43 #include <string.h>
   44 #include <fcntl.h>
   45 #include <assert.h>
   46 
   47 #ifdef HAVE_LBER_H
   48 #include <lber.h>
   49 #endif
   50 #ifdef HAVE_LDAP_H
   51 #include <ldap.h>
   52 #endif
   53 
   54 #ifndef HAVE_SNPRINTF
   55 #include "snprintf.h"
   56 #endif
   57 
   58 #include "ldap-nss.h"
   59 #include "util.h"
   60 
   61 static char rcsId[] = "$Id: util.c,v 2.138 2009/11/06 10:16:04 lukeh Exp $";
   62 
   63 static NSS_STATUS do_getrdnvalue (const char *dn,
   64                   const char *rdntype,
   65                   char **rval, char **buffer,
   66                   size_t * buflen);
   67 
   68 
   69 static NSS_STATUS do_parse_map_statement (ldap_config_t * cfg,
   70                       const char *statement,
   71                       ldap_map_type_t type);
   72 
   73 static NSS_STATUS do_searchdescriptorconfig (const char *key,
   74                          const char *value,
   75                          size_t valueLength,
   76                          ldap_service_search_descriptor_t
   77                          ** result, char **buffer,
   78                          size_t * buflen);
   79 
   80 #include <fcntl.h>
   81 static void *__cache = NULL;
   82 
   83 NSS_LDAP_DEFINE_LOCK (__cache_lock);
   84 
   85 #define cache_lock()     NSS_LDAP_LOCK(__cache_lock)
   86 #define cache_unlock()   NSS_LDAP_UNLOCK(__cache_lock)
   87 
   88 static NSS_STATUS
   89 dn2uid_cache_put (const char *dn, const char *uid)
   90 {
   91   NSS_STATUS stat;
   92   ldap_datum_t key, val;
   93 
   94   cache_lock ();
   95 
   96   if (__cache == NULL)
   97     {
   98       __cache = _nss_ldap_db_open ();
   99       if (__cache == NULL)
  100     {
  101       cache_unlock ();
  102       return NSS_TRYAGAIN;
  103     }
  104     }
  105 
  106   key.data = (void *) dn;
  107   key.size = strlen (dn);
  108   val.data = (void *) uid;
  109   val.size = strlen (uid);
  110 
  111   stat = _nss_ldap_db_put (__cache, 0, &key, &val);
  112 
  113   cache_unlock ();
  114 
  115   return stat;
  116 }
  117 
  118 static NSS_STATUS
  119 dn2uid_cache_get (const char *dn, char **uid, char **buffer, size_t * buflen)
  120 {
  121   ldap_datum_t key, val;
  122   NSS_STATUS stat;
  123 
  124   cache_lock ();
  125 
  126   if (__cache == NULL)
  127     {
  128       cache_unlock ();
  129       return NSS_NOTFOUND;
  130     }
  131 
  132   key.data = (void *) dn;
  133   key.size = strlen (dn);
  134 
  135   stat = _nss_ldap_db_get (__cache, 0, &key, &val);
  136   if (stat != NSS_SUCCESS)
  137     {
  138       cache_unlock ();
  139       return stat;
  140     }
  141 
  142   if (*buflen <= val.size)
  143     {
  144       cache_unlock ();
  145       return NSS_TRYAGAIN;
  146     }
  147 
  148   *uid = *buffer;
  149   memcpy (*uid, (char *) val.data, val.size);
  150   (*uid)[val.size] = '\0';
  151   *buffer += val.size + 1;
  152   *buflen -= val.size + 1;
  153 
  154   cache_unlock ();
  155   return NSS_SUCCESS;
  156 }
  157 
  158 #ifdef HPUX
  159 static int lock_inited = 0;
  160 #endif
  161 
  162 NSS_STATUS
  163 _nss_ldap_dn2uid (const char *dn, char **uid, char **buffer, size_t * buflen,
  164           int *pIsNestedGroup, LDAPMessage ** pRes)
  165 {
  166   NSS_STATUS stat;
  167 
  168   debug ("==> _nss_ldap_dn2uid");
  169 
  170   *pIsNestedGroup = 0;
  171 
  172 #ifdef HPUX
  173   /* XXX this is not thread-safe */
  174   if (!lock_inited)
  175     {
  176       __thread_mutex_init (&__cache_lock, NULL);
  177       lock_inited = 1;
  178     }
  179 #endif
  180 
  181   stat = dn2uid_cache_get (dn, uid, buffer, buflen);
  182   if (stat == NSS_NOTFOUND)
  183     {
  184       const char *attrs[4];
  185       LDAPMessage *res;
  186 
  187       attrs[0] = ATM (LM_PASSWD, uid);
  188       attrs[1] = ATM (LM_GROUP, uniqueMember);
  189       attrs[2] = AT (objectClass);
  190       attrs[3] = NULL;
  191 
  192       if (_nss_ldap_read (dn, attrs, &res) == NSS_SUCCESS)
  193     {
  194       LDAPMessage *e = _nss_ldap_first_entry (res);
  195       if (e != NULL)
  196         {
  197           if (_nss_ldap_oc_check (e, OC (posixGroup)) == NSS_SUCCESS)
  198         {
  199           *pIsNestedGroup = 1;
  200           *pRes = res;
  201           debug ("<== _nss_ldap_dn2uid (nested group)");
  202           return NSS_SUCCESS;
  203         }
  204 
  205           stat =
  206         _nss_ldap_assign_attrval (e, ATM (LM_PASSWD, uid), uid,
  207                       buffer, buflen);
  208           if (stat == NSS_SUCCESS)
  209         dn2uid_cache_put (dn, *uid);
  210         }
  211     }
  212       ldap_msgfree (res);
  213     }
  214 
  215   debug ("<== _nss_ldap_dn2uid");
  216 
  217   return stat;
  218 }
  219 
  220 NSS_STATUS
  221 _nss_ldap_getrdnvalue (LDAPMessage * entry,
  222                const char *rdntype,
  223                char **rval, char **buffer, size_t * buflen)
  224 {
  225   char *dn;
  226   NSS_STATUS status;
  227 
  228   dn = _nss_ldap_get_dn (entry);
  229   if (dn == NULL)
  230     {
  231       return NSS_NOTFOUND;
  232     }
  233 
  234   status = do_getrdnvalue (dn, rdntype, rval, buffer, buflen);
  235 #ifdef HAVE_LDAP_MEMFREE
  236   ldap_memfree (dn);
  237 #else
  238   free (dn);
  239 #endif /* HAVE_LDAP_MEMFREE */
  240 
  241   /*
  242    * If examining the DN failed, then pick the nominal first
  243    * value of cn as the canonical name (recall that attributes
  244    * are sets, not sequences)
  245    */
  246   if (status == NSS_NOTFOUND)
  247     {
  248       char **vals;
  249 
  250       vals = _nss_ldap_get_values (entry, rdntype);
  251 
  252       if (vals != NULL)
  253     {
  254       int rdnlen = strlen (*vals);
  255       if (*buflen > rdnlen)
  256         {
  257           char *rdnvalue = *buffer;
  258           strncpy (rdnvalue, *vals, rdnlen);
  259           rdnvalue[rdnlen] = '\0';
  260           *buffer += rdnlen + 1;
  261           *buflen -= rdnlen + 1;
  262           *rval = rdnvalue;
  263           status = NSS_SUCCESS;
  264         }
  265       else
  266         {
  267           status = NSS_TRYAGAIN;
  268         }
  269       ldap_value_free (vals);
  270     }
  271     }
  272 
  273   return status;
  274 }
  275 
  276 static NSS_STATUS
  277 do_getrdnvalue (const char *dn,
  278         const char *rdntype,
  279         char **rval, char **buffer, size_t * buflen)
  280 {
  281   char **exploded_dn;
  282   char *rdnvalue = NULL;
  283   char rdnava[64];
  284   int rdnlen = 0, rdnavalen;
  285 
  286   snprintf (rdnava, sizeof rdnava, "%s=", rdntype);
  287   rdnavalen = strlen (rdnava);
  288 
  289   exploded_dn = ldap_explode_dn (dn, 0);
  290 
  291   if (exploded_dn != NULL)
  292     {
  293       /*
  294        * attempt to get the naming attribute's principal
  295        * value by parsing the RDN. We need to support
  296        * multivalued RDNs (as they're essentially mandated
  297        * for services)
  298        */
  299 #ifdef HAVE_LDAP_EXPLODE_RDN
  300       /*
  301        * use ldap_explode_rdn() API, as it's cleaner than
  302        * strtok(). This code has not been tested!
  303        */
  304       char **p, **exploded_rdn;
  305 
  306       exploded_rdn = ldap_explode_rdn (*exploded_dn, 0);
  307       if (exploded_rdn != NULL)
  308     {
  309       for (p = exploded_rdn; *p != NULL; p++)
  310         {
  311           if (strncasecmp (*p, rdnava, rdnavalen) == 0)
  312         {
  313           char *r = *p + rdnavalen;
  314 
  315           rdnlen = strlen (r);
  316           if (*buflen <= rdnlen)
  317             {
  318               ldap_value_free (exploded_rdn);
  319               ldap_value_free (exploded_dn);
  320               return NSS_TRYAGAIN;
  321             }
  322           rdnvalue = *buffer;
  323           strncpy (rdnvalue, r, rdnlen);
  324           break;
  325         }
  326         }
  327       ldap_value_free (exploded_rdn);
  328     }
  329 #else
  330       /*
  331        * we don't have Netscape's ldap_explode_rdn() API,
  332        * so we fudge it with strtok(). Note that this will
  333        * not handle escaping properly.
  334        */
  335       char *p, *r = *exploded_dn;
  336 #ifdef HAVE_STRTOK_R
  337       char *st = NULL;
  338 #endif
  339 
  340 #ifndef HAVE_STRTOK_R
  341       for (p = strtok (r, "+");
  342 #else
  343       for (p = strtok_r (r, "+", &st);
  344 #endif
  345        p != NULL;
  346 #ifndef HAVE_STRTOK_R
  347        p = strtok (NULL, "+"))
  348 #else
  349        p = strtok_r (NULL, "+", &st))
  350 #endif
  351       {
  352     if (strncasecmp (p, rdnava, rdnavalen) == 0)
  353       {
  354         p += rdnavalen;
  355         rdnlen = strlen (p);
  356         if (*buflen <= rdnlen)
  357           {
  358         ldap_value_free (exploded_dn);
  359         return NSS_TRYAGAIN;
  360           }
  361         rdnvalue = *buffer;
  362         strncpy (rdnvalue, p, rdnlen);
  363         break;
  364       }
  365     if (r != NULL)
  366       r = NULL;
  367       }
  368 #endif /* HAVE_LDAP_EXPLODE_RDN */
  369     }
  370 
  371   if (exploded_dn != NULL)
  372     {
  373       ldap_value_free (exploded_dn);
  374     }
  375 
  376   if (rdnvalue != NULL)
  377     {
  378       rdnvalue[rdnlen] = '\0';
  379       *buffer += rdnlen + 1;
  380       *buflen -= rdnlen + 1;
  381       *rval = rdnvalue;
  382       return NSS_SUCCESS;
  383     }
  384 
  385   return NSS_NOTFOUND;
  386 }
  387 
  388 static NSS_STATUS
  389 do_parse_map_statement (ldap_config_t * cfg,
  390             const char *statement, ldap_map_type_t type)
  391 {
  392   char *key, *val;
  393   ldap_map_selector_t sel = LM_NONE;
  394 
  395   key = (char *) statement;
  396   val = key;
  397   while (*val != ' ' && *val != '\t')
  398     val++;
  399   *(val++) = '\0';
  400 
  401   while (*val == ' ' || *val == '\t')
  402     val++;
  403 
  404   {
  405     char *p = strchr (key, ':');
  406 
  407     if (p != NULL)
  408       {
  409     *p = '\0';
  410     sel = _nss_ldap_str2selector (key);
  411     key = ++p;
  412       }
  413   }
  414 
  415   return _nss_ldap_map_put (cfg, sel, type, key, val);
  416 }
  417 
  418 /* parse a comma-separated list */
  419 static NSS_STATUS
  420 do_parse_list (char *values, char ***valptr,
  421            char **pbuffer, size_t *pbuflen)
  422 {
  423   char *s, **p;
  424 #ifdef HAVE_STRTOK_R
  425   char *tok_r;
  426 #endif
  427   int valcount;
  428 
  429   int buflen = *pbuflen;
  430   char *buffer = *pbuffer;
  431 
  432   /* comma separated list of values to ignore on initgroups() */
  433   for (valcount = 1, s = values; *s != '\0'; s++)
  434     {
  435       if (*s == ',')
  436     valcount++;
  437     }
  438 
  439   if (bytesleft (buffer, buflen, char *) < (valcount + 1) * sizeof (char *))
  440     {
  441       return NSS_UNAVAIL;
  442     }
  443 
  444   align (buffer, buflen, char *);
  445   p = *valptr = (char **) buffer;
  446 
  447   buffer += (valcount + 1) * sizeof (char *);
  448   buflen -= (valcount + 1) * sizeof (char *);
  449 
  450 #ifdef HAVE_STRTOK_R
  451   for (s = strtok_r(values, ",", &tok_r); s != NULL;
  452        s = strtok_r(NULL, ",", &tok_r))
  453 #else
  454   for (s = strtok(values, ","); s != NULL; s = strtok(NULL, ","))
  455 #endif
  456     {
  457       int vallen;
  458       char *elt = NULL;
  459 
  460       vallen = strlen (s);
  461       if (buflen < (size_t) (vallen + 1))
  462         {
  463       return NSS_UNAVAIL;
  464     }
  465 
  466       /* copy this value into the next block of buffer space */
  467       elt = buffer;
  468       buffer += vallen + 1;
  469       buflen -= vallen + 1;
  470 
  471       strncpy (elt, s, vallen);
  472       elt[vallen] = '\0';
  473       *p++ = elt;
  474     }
  475 
  476   *p = NULL;
  477   *pbuffer = buffer;
  478   *pbuflen = buflen;
  479 
  480   return NSS_SUCCESS;
  481 }
  482 
  483 ldap_map_selector_t
  484 _nss_ldap_str2selector (const char *key)
  485 {
  486   ldap_map_selector_t sel;
  487 
  488   if (!strcasecmp (key, MP_passwd))
  489     sel = LM_PASSWD;
  490   else if (!strcasecmp (key, MP_shadow))
  491     sel = LM_SHADOW;
  492   else if (!strcasecmp (key, MP_group))
  493     sel = LM_GROUP;
  494   else if (!strcasecmp (key, MP_hosts))
  495     sel = LM_HOSTS;
  496   else if (!strcasecmp (key, MP_services))
  497     sel = LM_SERVICES;
  498   else if (!strcasecmp (key, MP_networks))
  499     sel = LM_NETWORKS;
  500   else if (!strcasecmp (key, MP_protocols))
  501     sel = LM_PROTOCOLS;
  502   else if (!strcasecmp (key, MP_rpc))
  503     sel = LM_RPC;
  504   else if (!strcasecmp (key, MP_ethers))
  505     sel = LM_ETHERS;
  506   else if (!strcasecmp (key, MP_netmasks))
  507     sel = LM_NETMASKS;
  508   else if (!strcasecmp (key, MP_bootparams))
  509     sel = LM_BOOTPARAMS;
  510   else if (!strcasecmp (key, MP_aliases))
  511     sel = LM_ALIASES;
  512   else if (!strcasecmp (key, MP_netgroup))
  513     sel = LM_NETGROUP;
  514   else if (!strcasecmp (key, MP_automount))
  515     sel = LM_AUTOMOUNT;
  516   else
  517     sel = LM_NONE;
  518 
  519   return sel;
  520 }
  521 
  522 static NSS_STATUS
  523 do_searchdescriptorconfig (const char *key, const char *value, size_t len,
  524                ldap_service_search_descriptor_t ** result,
  525                char **buffer, size_t * buflen)
  526 {
  527   ldap_service_search_descriptor_t **t, *cur;
  528   char *base;
  529   char *filter, *s;
  530   int scope;
  531   ldap_map_selector_t sel;
  532 
  533   t = NULL;
  534   filter = NULL;
  535   scope = -1;
  536 
  537   if (strncasecmp (key, NSS_LDAP_KEY_NSS_BASE_PREFIX,
  538            NSS_LDAP_KEY_NSS_BASE_PREFIX_LEN) != 0)
  539     return NSS_SUCCESS;
  540 
  541   sel = _nss_ldap_str2selector (&key[NSS_LDAP_KEY_NSS_BASE_PREFIX_LEN]);
  542   t = (sel < LM_NONE) ? &result[sel] : NULL;
  543 
  544   if (t == NULL)
  545     return NSS_SUCCESS;
  546 
  547   /* we have already checked for room for the value */
  548   /* len is set to the length of value */
  549   base = *buffer;
  550   strncpy (base, value, len);
  551   base[len] = '\0';
  552 
  553   *buffer += len + 1;
  554   *buflen -= len + 1;
  555 
  556   /* probably is some funky escaping needed here. later... */
  557   s = strchr (base, '?');
  558   if (s != NULL)
  559     {
  560       *s = '\0';
  561       s++;
  562       if (!strcasecmp (s, "sub"))
  563     scope = LDAP_SCOPE_SUBTREE;
  564       else if (!strcasecmp (s, "one"))
  565     scope = LDAP_SCOPE_ONELEVEL;
  566       else if (!strcasecmp (s, "base"))
  567     scope = LDAP_SCOPE_BASE;
  568       filter = strchr (s, '?');
  569       if (filter != NULL)
  570     {
  571       *filter = '\0';
  572       filter++;
  573     }
  574     }
  575 
  576   if (bytesleft (*buffer, *buflen, ldap_service_search_descriptor_t) <
  577       sizeof (ldap_service_search_descriptor_t))
  578     return NSS_UNAVAIL;
  579 
  580   align (*buffer, *buflen, ldap_service_search_descriptor_t);
  581 
  582   for (cur = *t; cur && cur->lsd_next; cur = cur->lsd_next)
  583     ;
  584   if (!cur)
  585     {
  586       *t = (ldap_service_search_descriptor_t *) * buffer;
  587       cur = *t;
  588     }
  589   else
  590     {
  591       cur->lsd_next = (ldap_service_search_descriptor_t *) * buffer;
  592       cur = cur->lsd_next;
  593     }
  594 
  595   cur->lsd_base = base;
  596   cur->lsd_scope = scope;
  597   cur->lsd_filter = filter;
  598   cur->lsd_next = NULL;
  599 
  600   *buffer += sizeof (ldap_service_search_descriptor_t);
  601   *buflen -= sizeof (ldap_service_search_descriptor_t);
  602 
  603   return NSS_SUCCESS;
  604 }
  605 
  606 NSS_STATUS _nss_ldap_init_config (ldap_config_t * result)
  607 {
  608   int i, j;
  609 
  610   memset (result, 0, sizeof (*result));
  611 
  612   result->ldc_scope = LDAP_SCOPE_SUBTREE;
  613   result->ldc_deref = LDAP_DEREF_NEVER;
  614   result->ldc_base = NULL;
  615   result->ldc_binddn = NULL;
  616   result->ldc_bindpw = NULL;
  617   result->ldc_saslid = NULL;
  618   result->ldc_usesasl = 0;
  619   result->ldc_rootbinddn = NULL;
  620   result->ldc_rootbindpw = NULL;
  621   result->ldc_rootsaslid = NULL;
  622   result->ldc_rootusesasl = 0;
  623 #ifdef LDAP_VERSION3
  624   result->ldc_version = LDAP_VERSION3;
  625 #else
  626   result->ldc_version = LDAP_VERSION2;
  627 #endif /* LDAP_VERSION3 */
  628   result->ldc_timelimit = LDAP_NO_LIMIT;
  629   result->ldc_bind_timelimit = 30;
  630   result->ldc_ssl_on = SSL_OFF;
  631   result->ldc_sslpath = NULL;
  632   result->ldc_referrals = 1;
  633   result->ldc_restart = 1;
  634   result->ldc_tls_checkpeer = -1;
  635   result->ldc_tls_cacertfile = NULL;
  636   result->ldc_tls_cacertdir = NULL;
  637   result->ldc_tls_ciphers = NULL;
  638   result->ldc_tls_cert = NULL;
  639   result->ldc_tls_key = NULL;
  640   result->ldc_tls_randfile = NULL;
  641   result->ldc_idle_timelimit = 0;
  642   result->ldc_reconnect_pol = LP_RECONNECT_HARD_OPEN;
  643   result->ldc_sasl_secprops = NULL;
  644   result->ldc_srv_domain = NULL;
  645   result->ldc_logdir = NULL;
  646   result->ldc_debug = 0;
  647   result->ldc_pagesize = LDAP_PAGESIZE;
  648 #ifdef CONFIGURE_KRB5_CCNAME
  649   result->ldc_krb5_ccname = NULL;
  650   result->ldc_krb5_rootccname = NULL;
  651   result->ldc_krb5_autorenew = 0;
  652   result->ldc_krb5_rootautorenew = 0;
  653 #endif /* CONFIGURE_KRB5_CCNAME */
  654 #ifdef CONFIGURE_KRB5_KEYTAB
  655   result->ldc_krb5_keytabname = NULL;
  656   result->ldc_krb5_rootkeytabname = NULL;
  657   result->ldc_krb5_usekeytab = 0;
  658   result->ldc_krb5_rootusekeytab = 0;
  659 #endif /* CONFIGURE_KRB5_KEYTAB */
  660   result->ldc_flags = 0;
  661 #ifdef RFC2307BIS
  662   result->ldc_flags |= NSS_LDAP_FLAGS_RFC2307BIS;
  663 #endif
  664 #ifdef PAGE_RESULTS
  665   result->ldc_flags |= NSS_LDAP_FLAGS_PAGED_RESULTS;
  666 #endif
  667   result->ldc_reconnect_tries = LDAP_NSS_TRIES;
  668   result->ldc_reconnect_sleeptime = LDAP_NSS_SLEEPTIME;
  669   result->ldc_reconnect_maxsleeptime = LDAP_NSS_MAXSLEEPTIME;
  670   result->ldc_reconnect_maxconntries = LDAP_NSS_MAXCONNTRIES;
  671   result->ldc_initgroups_ignoreusers = NULL;
  672 
  673   for (i = 0; i <= LM_NONE; i++)
  674     {
  675       for (j = 0; j <= MAP_MAX; j++)
  676     {
  677       result->ldc_maps[i][j] = _nss_ldap_db_open ();
  678       if (result->ldc_maps[i][j] == NULL)
  679         return NSS_UNAVAIL;
  680     }
  681     }
  682 
  683   return NSS_SUCCESS;
  684 }
  685 
  686 NSS_STATUS
  687 _nss_ldap_add_uri (ldap_config_t *result, const char *uri,
  688            char **buffer, size_t *buflen)
  689 {
  690   /* add a single URI to the list of URIs in the configuration */
  691   int i;
  692   size_t uri_len;
  693 
  694   debug ("==> _nss_ldap_add_uri");
  695 
  696   for (i = 0; result->ldc_uris[i] != NULL; i++)
  697     ;
  698 
  699   if (i == NSS_LDAP_CONFIG_URI_MAX)
  700     {
  701       debug ("<== _nss_ldap_add_uri: maximum number of URIs exceeded");
  702       return NSS_UNAVAIL;
  703     }
  704 
  705   assert (i < NSS_LDAP_CONFIG_URI_MAX);
  706 
  707   uri_len = strlen (uri);
  708 
  709   if (*buflen < uri_len + 1)
  710     return NSS_TRYAGAIN;
  711 
  712   memcpy (*buffer, uri, uri_len + 1);
  713 
  714   result->ldc_uris[i] = *buffer;
  715   result->ldc_uris[i + 1] = NULL;
  716 
  717   *buffer += uri_len + 1;
  718   *buflen -= uri_len + 1;
  719 
  720   debug ("<== _nss_ldap_add_uri: added URI %s", uri);
  721 
  722   return NSS_SUCCESS;
  723 }
  724 
  725 static NSS_STATUS
  726 do_add_uris (ldap_config_t *result, char *uris,
  727          char **buffer, size_t *buflen)
  728 {
  729   /* Add a space separated list of URIs */
  730   char *p;
  731   NSS_STATUS stat = NSS_SUCCESS;
  732 
  733   for (p = uris; p != NULL; )
  734     {
  735       char *q = strchr (p, ' ');
  736       if (q != NULL)
  737     *q = '\0';
  738 
  739       stat = _nss_ldap_add_uri (result, p, buffer, buflen);
  740 
  741       p = (q != NULL) ? ++q : NULL;
  742 
  743       if (stat != NSS_SUCCESS)
  744     break;
  745     }
  746 
  747   return stat;
  748 }
  749 
  750 static NSS_STATUS
  751 do_add_hosts (ldap_config_t *result, char *hosts,
  752           char **buffer, size_t *buflen)
  753 {
  754   /* Add a space separated list of hosts */
  755   char *p;
  756   NSS_STATUS stat = NSS_SUCCESS;
  757 
  758   for (p = hosts; p != NULL; )
  759     {
  760       char b[NSS_LDAP_CONFIG_BUFSIZ];
  761       char *q = strchr (p, ' ');
  762 
  763       if (q != NULL)
  764     *q = '\0';
  765 
  766       snprintf (b, sizeof(b), "ldap://%s", p);
  767 
  768       stat = _nss_ldap_add_uri (result, b, buffer, buflen);
  769 
  770       p = (q != NULL) ? ++q : NULL;
  771 
  772       if (stat != NSS_SUCCESS)
  773     break;
  774     }
  775 
  776   return stat;
  777 }
  778 
  779 NSS_STATUS
  780 _nss_ldap_readconfig (ldap_config_t ** presult, char **buffer, size_t *buflen)
  781 {
  782   FILE *fp;
  783   char b[NSS_LDAP_CONFIG_BUFSIZ];
  784   NSS_STATUS stat = NSS_SUCCESS;
  785   ldap_config_t *result;
  786   struct stat statbuf;
  787 
  788   fp = fopen (NSS_LDAP_PATH_CONF, "r");
  789   if (fp == NULL)
  790     {
  791       return NSS_UNAVAIL;
  792     }
  793 
  794   if (bytesleft (*buffer, *buflen, ldap_config_t *) < sizeof (ldap_config_t))
  795     {
  796       fclose (fp);
  797       return NSS_TRYAGAIN;
  798     }
  799   align (*buffer, *buflen, ldap_config_t *);
  800   result = *presult = (ldap_config_t *) *buffer;
  801   *buffer += sizeof (ldap_config_t);
  802   *buflen -= sizeof (ldap_config_t);
  803 
  804   stat = _nss_ldap_init_config (result);
  805   if (stat != NSS_SUCCESS)
  806     {
  807       fclose (fp);
  808       return NSS_SUCCESS;
  809     }
  810 
  811   if (fstat (fileno (fp), &statbuf) == 0)
  812       result->ldc_mtime = statbuf.st_mtime;
  813   else
  814       result->ldc_mtime = 0;
  815 
  816   while (fgets (b, sizeof (b), fp) != NULL)
  817     {
  818       char *k, *v;
  819       int len;
  820       char **t = NULL;
  821 
  822       if (*b == '\n' || *b == '\r' || *b == '#')
  823     continue;
  824 
  825       k = b;
  826       v = k;
  827 
  828       /* skip past all characters in keyword */
  829       while (*v != '\0' && *v != ' ' && *v != '\t')
  830     v++;
  831 
  832       if (*v == '\0')
  833     continue;
  834 
  835       /* terminate keyword */
  836       *(v++) = '\0';
  837 
  838       /* skip empty lines with more than 3 spaces at the start of the line */
  839       /* rds.oliver@samera.com.py 01-set-2004                              */
  840       if (*v == '\n')
  841     continue;
  842 
  843       /* skip all whitespaces between keyword and value */
  844       /* Lars Oergel <lars.oergel@innominate.de>, 05.10.2000 */
  845       while (*v == ' ' || *v == '\t')
  846     v++;
  847 
  848       /* kick off all whitespaces and newline at the end of value */
  849       /* Bob Guo <bob@mail.ied.ac.cn>, 08.10.2001 */
  850 
  851       /* Also remove \r (CR) to be able to handle files in DOS format (lines
  852        * terminated in CR LF).  Alejandro Forero Cuervo
  853        * <azul@freaks-unidos.net>, 10-may-2005 */
  854 
  855       len = strlen (v) - 1;
  856       while (v[len] == ' ' || v[len] == '\t' || v[len] == '\n' || v[len] == '\r')
  857     --len;
  858       v[++len] = '\0';
  859 
  860       if (*buflen < (size_t) (len + 1))
  861     {
  862       stat = NSS_TRYAGAIN;
  863       break;
  864     }
  865 
  866       if (!strcasecmp (k, NSS_LDAP_KEY_HOST))
  867     {
  868       stat = do_add_hosts (result, v, buffer, buflen);
  869       if (stat != NSS_SUCCESS)
  870         break;
  871     }
  872       else if (!strcasecmp (k, NSS_LDAP_KEY_URI))
  873     {
  874       stat = do_add_uris (result, v, buffer, buflen);
  875       if (stat != NSS_SUCCESS)
  876         break;
  877     }
  878       else if (!strcasecmp (k, NSS_LDAP_KEY_BASE))
  879     {
  880       t = &result->ldc_base;
  881     }
  882       else if (!strcasecmp (k, NSS_LDAP_KEY_BINDDN))
  883     {
  884       t = &result->ldc_binddn;
  885     }
  886       else if (!strcasecmp (k, NSS_LDAP_KEY_BINDPW))
  887     {
  888       t = &result->ldc_bindpw;
  889     }
  890       else if (!strcasecmp (k, NSS_LDAP_KEY_USESASL))
  891     {
  892       result->ldc_usesasl = (!strcasecmp (v, "on")
  893                  || !strcasecmp (v, "yes")
  894                  || !strcasecmp (v, "true"));
  895     }
  896       else if (!strcasecmp (k, NSS_LDAP_KEY_SASLID))
  897     {
  898       t = &result->ldc_saslid;
  899     }
  900       else if (!strcasecmp (k, NSS_LDAP_KEY_ROOTBINDDN))
  901     {
  902       t = &result->ldc_rootbinddn;
  903     }
  904       else if (!strcasecmp (k, NSS_LDAP_KEY_ROOTUSESASL))
  905     {
  906       result->ldc_rootusesasl = (!strcasecmp (v, "on")
  907                      || !strcasecmp (v, "yes")
  908                      || !strcasecmp (v, "true"));
  909     }
  910       else if (!strcasecmp (k, NSS_LDAP_KEY_ROOTSASLID))
  911     {
  912       t = &result->ldc_rootsaslid;
  913     }
  914       else if (!strcasecmp (k, NSS_LDAP_KEY_SSLPATH))
  915     {
  916       t = &result->ldc_sslpath;
  917     }
  918       else if (!strcasecmp (k, NSS_LDAP_KEY_SCOPE))
  919     {
  920       if (!strcasecmp (v, "sub"))
  921         {
  922           result->ldc_scope = LDAP_SCOPE_SUBTREE;
  923         }
  924       else if (!strcasecmp (v, "one"))
  925         {
  926           result->ldc_scope = LDAP_SCOPE_ONELEVEL;
  927         }
  928       else if (!strcasecmp (v, "base"))
  929         {
  930           result->ldc_scope = LDAP_SCOPE_BASE;
  931         }
  932     }
  933       else if (!strcasecmp (k, NSS_LDAP_KEY_DEREF))
  934     {
  935       if (!strcasecmp (v, "never"))
  936         {
  937           result->ldc_deref = LDAP_DEREF_NEVER;
  938         }
  939       else if (!strcasecmp (v, "searching"))
  940         {
  941           result->ldc_deref = LDAP_DEREF_SEARCHING;
  942         }
  943       else if (!strcasecmp (v, "finding"))
  944         {
  945           result->ldc_deref = LDAP_DEREF_FINDING;
  946         }
  947       else if (!strcasecmp (v, "always"))
  948         {
  949           result->ldc_deref = LDAP_DEREF_ALWAYS;
  950         }
  951     }
  952       else if (!strcasecmp (k, NSS_LDAP_KEY_PORT))
  953     {
  954       result->ldc_port = atoi (v);
  955     }
  956       else if (!strcasecmp (k, NSS_LDAP_KEY_SSL))
  957     {
  958       if (!strcasecmp (v, "on") || !strcasecmp (v, "yes")
  959           || !strcasecmp (v, "true"))
  960         {
  961           result->ldc_ssl_on = SSL_LDAPS;
  962         }
  963       else if (!strcasecmp (v, "start_tls"))
  964         {
  965           result->ldc_ssl_on = SSL_START_TLS;
  966         }
  967     }
  968       else if (!strcasecmp (k, NSS_LDAP_KEY_REFERRALS))
  969     {
  970       result->ldc_referrals = (!strcasecmp (v, "on")
  971                    || !strcasecmp (v, "yes")
  972                    || !strcasecmp (v, "true"));
  973     }
  974       else if (!strcasecmp (k, NSS_LDAP_KEY_RESTART))
  975     {
  976       result->ldc_restart = (!strcasecmp (v, "on")
  977                  || !strcasecmp (v, "yes")
  978                  || !strcasecmp (v, "true"));
  979     }
  980       else if (!strcasecmp (k, NSS_LDAP_KEY_LDAP_VERSION))
  981     {
  982       result->ldc_version = atoi (v);
  983     }
  984       else if (!strcasecmp (k, NSS_LDAP_KEY_TIMELIMIT))
  985     {
  986       result->ldc_timelimit = atoi (v);
  987     }
  988       else if (!strcasecmp (k, NSS_LDAP_KEY_BIND_TIMELIMIT))
  989     {
  990       result->ldc_bind_timelimit = atoi (v);
  991     }
  992       else if (!strcasecmp (k, NSS_LDAP_KEY_IDLE_TIMELIMIT))
  993     {
  994       result->ldc_idle_timelimit = atoi (v);
  995     }
  996       else if (!strcasecmp (k, NSS_LDAP_KEY_RECONNECT_POLICY))
  997     {
  998       if (!strcasecmp (v, "hard") ||
  999           !strcasecmp (v, "hard_open"))
 1000         {
 1001           result->ldc_reconnect_pol = LP_RECONNECT_HARD_OPEN;
 1002         }
 1003       else if (!strcasecmp (v, "hard_init"))
 1004         {
 1005           result->ldc_reconnect_pol = LP_RECONNECT_HARD_INIT;
 1006         }
 1007       else if (!strcasecmp (v, "soft"))
 1008         {
 1009           result->ldc_reconnect_pol = LP_RECONNECT_SOFT;
 1010         }
 1011     }
 1012       else if (!strcasecmp (k, NSS_LDAP_KEY_RECONNECT_TRIES))
 1013     {
 1014       result->ldc_reconnect_tries = atoi (v);
 1015     }
 1016       else if (!strcasecmp (k, NSS_LDAP_KEY_RECONNECT_SLEEPTIME))
 1017     {
 1018       result->ldc_reconnect_sleeptime = atoi (v);
 1019     }
 1020       else if (!strcasecmp (k, NSS_LDAP_KEY_RECONNECT_MAXSLEEPTIME))
 1021     {
 1022       result->ldc_reconnect_maxsleeptime = atoi (v);
 1023     }
 1024       else if (!strcasecmp (k, NSS_LDAP_KEY_RECONNECT_MAXCONNTRIES))
 1025     {
 1026       result->ldc_reconnect_maxconntries = atoi (v);
 1027     }
 1028       else if (!strcasecmp (k, NSS_LDAP_KEY_SASL_SECPROPS))
 1029     {
 1030       t = &result->ldc_sasl_secprops;
 1031     }
 1032       else if (!strcasecmp (k, NSS_LDAP_KEY_LOGDIR))
 1033     {
 1034       t = &result->ldc_logdir;
 1035     }
 1036       else if (!strcasecmp (k, NSS_LDAP_KEY_DEBUG))
 1037     {
 1038       result->ldc_debug = atoi (v);
 1039     }
 1040       else if (!strcasecmp (k, NSS_LDAP_KEY_PAGESIZE))
 1041     {
 1042       result->ldc_pagesize = atoi (v);
 1043     }
 1044 #ifdef CONFIGURE_KRB5_CCNAME
 1045       else if (!strcasecmp (k, NSS_LDAP_KEY_KRB5_CCNAME))
 1046     {
 1047       t = &result->ldc_krb5_ccname;
 1048     }
 1049       else if (!strcasecmp (k, NSS_LDAP_KEY_KRB5_ROOTCCNAME))
 1050     {
 1051       t = &result->ldc_krb5_rootccname;
 1052     }
 1053       else if (!strcasecmp (k, NSS_LDAP_KEY_KRB5_AUTORENEW))
 1054     {
 1055       result->ldc_krb5_autorenew = atoi (v);
 1056     }
 1057       else if (!strcasecmp (k, NSS_LDAP_KEY_KRB5_ROOTAUTORENEW))
 1058     {
 1059       result->ldc_krb5_rootautorenew = atoi (v);
 1060     }
 1061 #endif /* CONFIGURE_KRB5_CCNAME */
 1062 #ifdef CONFIGURE_KRB5_KEYTAB
 1063       else if (!strcasecmp (k, NSS_LDAP_KEY_KRB5_KEYTAB))
 1064     {
 1065       t = &result->ldc_krb5_keytabname;
 1066     }
 1067       else if (!strcasecmp (k, NSS_LDAP_KEY_KRB5_ROOTKEYTAB))
 1068     {
 1069       t = &result->ldc_krb5_rootkeytabname;
 1070     }
 1071       else if (!strcasecmp (k, NSS_LDAP_KEY_KRB5_USEKEYTAB))
 1072     {
 1073       result->ldc_krb5_usekeytab = atoi (v);
 1074     }
 1075       else if (!strcasecmp (k, NSS_LDAP_KEY_KRB5_ROOTUSEKEYTAB))
 1076     {
 1077       result->ldc_krb5_rootusekeytab = atoi (v);
 1078     }
 1079 #endif /* CONFIGURE_KRB5_KEYTAB */
 1080       else if (!strcasecmp (k, "tls_checkpeer"))
 1081     {
 1082       if (!strcasecmp (v, "on") || !strcasecmp (v, "yes")
 1083           || !strcasecmp (v, "true"))
 1084         {
 1085           result->ldc_tls_checkpeer = 1;
 1086         }
 1087       else if (!strcasecmp (v, "off") || !strcasecmp (v, "no")
 1088            || !strcasecmp (v, "false"))
 1089         {
 1090           result->ldc_tls_checkpeer = 0;
 1091         }
 1092     }
 1093       else if (!strcasecmp (k, "tls_cacertfile"))
 1094     {
 1095       t = &result->ldc_tls_cacertfile;
 1096     }
 1097       else if (!strcasecmp (k, "tls_cacertdir"))
 1098     {
 1099       t = &result->ldc_tls_cacertdir;
 1100     }
 1101       else if (!strcasecmp (k, "tls_ciphers"))
 1102     {
 1103       t = &result->ldc_tls_ciphers;
 1104     }
 1105       else if (!strcasecmp (k, "tls_cert"))
 1106     {
 1107       t = &result->ldc_tls_cert;
 1108     }
 1109       else if (!strcasecmp (k, "tls_key"))
 1110     {
 1111       t = &result->ldc_tls_key;
 1112     }
 1113       else if (!strcasecmp (k, "tls_randfile"))
 1114     {
 1115       t = &result->ldc_tls_randfile;
 1116     }
 1117       else if (!strncasecmp (k, NSS_LDAP_KEY_MAP_ATTRIBUTE,
 1118                  strlen (NSS_LDAP_KEY_MAP_ATTRIBUTE)))
 1119     {
 1120       do_parse_map_statement (result, v, MAP_ATTRIBUTE);
 1121     }
 1122       else if (!strncasecmp (k, NSS_LDAP_KEY_MAP_OBJECTCLASS,
 1123                  strlen (NSS_LDAP_KEY_MAP_OBJECTCLASS)))
 1124     {
 1125       do_parse_map_statement (result, v, MAP_OBJECTCLASS);
 1126     }
 1127       else if (!strncasecmp (k, NSS_LDAP_KEY_SET_OVERRIDE,
 1128                  strlen (NSS_LDAP_KEY_SET_OVERRIDE)))
 1129     {
 1130       do_parse_map_statement (result, v, MAP_OVERRIDE);
 1131     }
 1132       else if (!strncasecmp (k, NSS_LDAP_KEY_SET_DEFAULT,
 1133                  strlen (NSS_LDAP_KEY_SET_DEFAULT)))
 1134     {
 1135       do_parse_map_statement (result, v, MAP_DEFAULT);
 1136     }
 1137       else if (!strcasecmp (k, NSS_LDAP_KEY_INITGROUPS))
 1138     {
 1139       if (!strcasecmp (v, "backlink"))
 1140         {
 1141           result->ldc_flags |= NSS_LDAP_FLAGS_INITGROUPS_BACKLINK;
 1142         }
 1143       else
 1144         {
 1145           result->ldc_flags &= ~(NSS_LDAP_FLAGS_INITGROUPS_BACKLINK);
 1146         }
 1147     }
 1148       else if (!strcasecmp (k, NSS_LDAP_KEY_SCHEMA))
 1149     {
 1150       if (!strcasecmp (v, "rfc2307bis"))
 1151         {
 1152           result->ldc_flags |= NSS_LDAP_FLAGS_RFC2307BIS;
 1153         }
 1154       else if (!strcasecmp (v, "rfc2307"))
 1155         {
 1156           result->ldc_flags &= ~(NSS_LDAP_FLAGS_RFC2307BIS);
 1157         }
 1158     }
 1159       else if (!strcasecmp (k, NSS_LDAP_KEY_PAGED_RESULTS))
 1160     {
 1161       if (!strcasecmp (v, "on")
 1162           || !strcasecmp (v, "yes")
 1163           || !strcasecmp (v, "true"))
 1164         {
 1165           result->ldc_flags |= NSS_LDAP_FLAGS_PAGED_RESULTS;
 1166         }
 1167       else
 1168         {
 1169           result->ldc_flags &= ~(NSS_LDAP_FLAGS_PAGED_RESULTS);
 1170         }
 1171     }
 1172       else if (!strcasecmp (k, NSS_LDAP_KEY_INITGROUPS_IGNOREUSERS))
 1173     {
 1174       stat = do_parse_list (v, &result->ldc_initgroups_ignoreusers,
 1175                 buffer, buflen);
 1176       if (stat == NSS_UNAVAIL)
 1177         {
 1178           break;
 1179         }
 1180     }
 1181       else if (!strcasecmp (k, NSS_LDAP_KEY_GETGRENT_SKIPMEMBERS))
 1182     {
 1183       if (!strcasecmp (v, "on") || !strcasecmp (v, "yes")
 1184           || !strcasecmp (v, "true"))
 1185         {
 1186           result->ldc_flags |= NSS_LDAP_FLAGS_GETGRENT_SKIPMEMBERS;
 1187         }
 1188       else if (!strcasecmp (v, "off") || !strcasecmp (v, "no")
 1189            || !strcasecmp (v, "false"))
 1190         {
 1191           result->ldc_flags &= ~(NSS_LDAP_FLAGS_GETGRENT_SKIPMEMBERS);
 1192         }
 1193     }
 1194       else if (!strcasecmp (k, NSS_LDAP_KEY_CONNECT_POLICY))
 1195         {
 1196       if (!strcasecmp (v, "oneshot"))
 1197         {
 1198           result->ldc_flags |= NSS_LDAP_FLAGS_CONNECT_POLICY_ONESHOT;
 1199         }
 1200       else if (!strcasecmp (v, "persist"))
 1201         {
 1202           result->ldc_flags &= ~(NSS_LDAP_FLAGS_CONNECT_POLICY_ONESHOT);
 1203         }
 1204     }
 1205       else if (!strcasecmp (k, NSS_LDAP_KEY_SRV_DOMAIN))
 1206     {
 1207       t = &result->ldc_srv_domain;
 1208     }
 1209       else
 1210     {
 1211       /*
 1212        * check whether the key is a naming context key
 1213        * if yes, parse; otherwise just return NSS_SUCCESS
 1214        * so we can ignore keys we don't understand.
 1215        */
 1216       stat =
 1217         do_searchdescriptorconfig (k, v, len, result->ldc_sds,
 1218                        buffer, buflen);
 1219       if (stat == NSS_UNAVAIL)
 1220         {
 1221           break;
 1222         }
 1223     }
 1224 
 1225       if (t != NULL)
 1226     {
 1227       strncpy (*buffer, v, len);
 1228       (*buffer)[len] = '\0';
 1229       *t = *buffer;
 1230       *buffer += len + 1;
 1231       *buflen -= len + 1;
 1232     }
 1233     }
 1234 
 1235   fclose (fp);
 1236 
 1237   if (stat != NSS_SUCCESS)
 1238     {
 1239       return stat;
 1240     }
 1241 
 1242   if (result->ldc_rootbinddn != NULL)
 1243     {
 1244       fp = fopen (NSS_LDAP_PATH_ROOTPASSWD, "r");
 1245       if (fp)
 1246     {
 1247       if (fgets (b, sizeof (b), fp) != NULL)
 1248         {
 1249           int len;
 1250 
 1251           len = strlen (b);
 1252           /* BUG#138: check for newline before removing */
 1253           if (len > 0 && b[len - 1] == '\n')
 1254         len--;
 1255 
 1256           if (*buflen < (size_t) (len + 1))
 1257         {
 1258           fclose (fp);
 1259           return NSS_UNAVAIL;
 1260         }
 1261 
 1262           strncpy (*buffer, b, len);
 1263           (*buffer)[len] = '\0';
 1264           result->ldc_rootbindpw = *buffer;
 1265           *buffer += len + 1;
 1266           *buflen -= len + 1;
 1267         }
 1268       fclose (fp);
 1269     }
 1270       else if (!result->ldc_rootusesasl)
 1271     {
 1272       result->ldc_rootbinddn = NULL;
 1273     }
 1274     }
 1275 
 1276   if (result->ldc_port == 0 &&
 1277       result->ldc_ssl_on == SSL_LDAPS)
 1278     {
 1279       result->ldc_port = LDAPS_PORT;
 1280     }
 1281 
 1282   if (result->ldc_uris[0] == NULL)
 1283     {
 1284       stat = NSS_NOTFOUND;
 1285     }
 1286 
 1287   return stat;
 1288 }
 1289 
 1290 NSS_STATUS
 1291 _nss_ldap_escape_string (const char *str, char *buf, size_t buflen)
 1292 {
 1293   int ret = NSS_TRYAGAIN;
 1294   char *p = buf;
 1295   char *limit = p + buflen - 3;
 1296   const char *s = str;
 1297 
 1298   while (p < limit && *s)
 1299     {
 1300       switch (*s)
 1301     {
 1302     case '*':
 1303       strcpy (p, "\\2a");
 1304       p += 3;
 1305       break;
 1306     case '(':
 1307       strcpy (p, "\\28");
 1308       p += 3;
 1309       break;
 1310     case ')':
 1311       strcpy (p, "\\29");
 1312       p += 3;
 1313       break;
 1314     case '\\':
 1315       strcpy (p, "\\5c");
 1316       p += 3;
 1317       break;
 1318     default:
 1319       *p++ = *s;
 1320       break;
 1321     }
 1322       s++;
 1323     }
 1324 
 1325   if (*s == '\0')
 1326     {
 1327       /* got to end */
 1328       *p = '\0';
 1329       ret = NSS_SUCCESS;
 1330     }
 1331 
 1332   return ret;
 1333 }
 1334 
 1335 /* XXX just a linked list for now */
 1336 
 1337 struct ldap_dictionary
 1338 {
 1339   ldap_datum_t key;
 1340   ldap_datum_t value;
 1341   struct ldap_dictionary *next;
 1342 };
 1343 
 1344 static struct ldap_dictionary *
 1345 do_alloc_dictionary (void)
 1346 {
 1347   struct ldap_dictionary *dict;
 1348 
 1349   dict = malloc (sizeof (*dict));
 1350   if (dict == NULL)
 1351     {
 1352       return NULL;
 1353     }
 1354   NSS_LDAP_DATUM_ZERO (&dict->key);
 1355   NSS_LDAP_DATUM_ZERO (&dict->value);
 1356   dict->next = NULL;
 1357 
 1358   return dict;
 1359 }
 1360 
 1361 static void
 1362 do_free_datum (ldap_datum_t * datum)
 1363 {
 1364   if (datum->data != NULL)
 1365     {
 1366       free (datum->data);
 1367       datum->data = NULL;
 1368     }
 1369   datum->size = 0;
 1370 }
 1371 
 1372 static struct ldap_dictionary *
 1373 do_find_last (struct ldap_dictionary *dict)
 1374 {
 1375   struct ldap_dictionary *p;
 1376 
 1377   for (p = dict; p->next != NULL; p = p->next)
 1378     ;
 1379 
 1380   return p;
 1381 }
 1382 
 1383 static void
 1384 do_free_dictionary (struct ldap_dictionary *dict)
 1385 {
 1386   do_free_datum (&dict->key);
 1387   do_free_datum (&dict->value);
 1388   free (dict);
 1389 }
 1390 
 1391 static NSS_STATUS
 1392 do_dup_datum (unsigned flags, ldap_datum_t * dst, const ldap_datum_t * src)
 1393 {
 1394   dst->data = malloc (src->size);
 1395   if (dst->data == NULL)
 1396     return NSS_TRYAGAIN;
 1397 
 1398   memcpy (dst->data, src->data, src->size);
 1399   dst->size = src->size;
 1400 
 1401   return NSS_SUCCESS;
 1402 }
 1403 
 1404 void *
 1405 _nss_ldap_db_open (void)
 1406 {
 1407   return (void *) do_alloc_dictionary ();
 1408 }
 1409 
 1410 void
 1411 _nss_ldap_db_close (void *db)
 1412 {
 1413   struct ldap_dictionary *dict;
 1414 
 1415   dict = (struct ldap_dictionary *) db;
 1416 
 1417   while (dict != NULL)
 1418     {
 1419       struct ldap_dictionary *next = dict->next;
 1420 
 1421       do_free_dictionary (dict);
 1422 
 1423       dict = next;
 1424     }
 1425 }
 1426 
 1427 NSS_STATUS
 1428 _nss_ldap_db_get (void *db,
 1429           unsigned flags,
 1430           const ldap_datum_t * key,
 1431           ldap_datum_t * value)
 1432 {
 1433   struct ldap_dictionary *dict = (struct ldap_dictionary *) db;
 1434   struct ldap_dictionary *p;
 1435 
 1436   for (p = dict; p != NULL; p = p->next)
 1437     {
 1438       int cmp;
 1439 
 1440       if (p->key.size != key->size)
 1441     continue;
 1442 
 1443       if (flags & NSS_LDAP_DB_NORMALIZE_CASE)
 1444     cmp = strncasecmp ((char *)p->key.data, (char *)key->data, key->size);
 1445       else
 1446     cmp = memcmp (p->key.data, key->data, key->size);
 1447 
 1448       if (cmp == 0)
 1449     {
 1450       value->data = p->value.data;
 1451       value->size = p->value.size;
 1452 
 1453       return NSS_SUCCESS;
 1454     }
 1455     }
 1456 
 1457   return NSS_NOTFOUND;
 1458 }
 1459 
 1460 NSS_STATUS
 1461 _nss_ldap_db_put (void *db,
 1462           unsigned flags,
 1463           const ldap_datum_t * key,
 1464           const ldap_datum_t * value)
 1465 {
 1466   struct ldap_dictionary *dict = (struct ldap_dictionary *) db;
 1467   struct ldap_dictionary *p, *q;
 1468 
 1469   assert (key != NULL);
 1470   assert (key->data != NULL);
 1471 
 1472   if (dict->key.data == NULL)
 1473     {
 1474       /* uninitialized */
 1475       q = dict;
 1476       p = NULL;
 1477     }
 1478   else
 1479     {
 1480       p = do_find_last (dict);
 1481       assert (p != NULL);
 1482       assert (p->next == NULL);
 1483       q = do_alloc_dictionary ();
 1484       if (q == NULL)
 1485     return NSS_TRYAGAIN;
 1486     }
 1487 
 1488   if (do_dup_datum (flags, &q->key, key) != NSS_SUCCESS)
 1489     {
 1490       do_free_dictionary (q);
 1491       return NSS_TRYAGAIN;
 1492     }
 1493 
 1494   if (do_dup_datum (flags, &q->value, value) != NSS_SUCCESS)
 1495     {
 1496       do_free_dictionary (q);
 1497       return NSS_TRYAGAIN;
 1498     }
 1499 
 1500   if (p != NULL)
 1501     p->next = q;
 1502 
 1503   return NSS_SUCCESS;
 1504 }
 1505 
 1506 /*
 1507  * Add a nested netgroup or group to the namelist
 1508  */
 1509 NSS_STATUS
 1510 _nss_ldap_namelist_push (struct name_list **head, const char *name)
 1511 {
 1512   struct name_list *nl;
 1513 
 1514   debug ("==> _nss_ldap_namelist_push (%s)", name);
 1515 
 1516   nl = (struct name_list *) malloc (sizeof (*nl));
 1517   if (nl == NULL)
 1518     {
 1519       debug ("<== _nss_ldap_namelist_push");
 1520       return NSS_TRYAGAIN;
 1521     }
 1522 
 1523   nl->name = strdup (name);
 1524   if (nl->name == NULL)
 1525     {
 1526       debug ("<== _nss_ldap_namelist_push");
 1527       free (nl);
 1528       return NSS_TRYAGAIN;
 1529     }
 1530 
 1531   nl->next = *head;
 1532 
 1533   *head = nl;
 1534 
 1535   debug ("<== _nss_ldap_namelist_push");
 1536 
 1537   return NSS_SUCCESS;
 1538 }
 1539 
 1540 /*
 1541  * Remove last nested netgroup or group from the namelist
 1542  */
 1543 void
 1544 _nss_ldap_namelist_pop (struct name_list **head)
 1545 {
 1546   struct name_list *nl;
 1547 
 1548   debug ("==> _nss_ldap_namelist_pop");
 1549 
 1550   assert (*head != NULL);
 1551   nl = *head;
 1552 
 1553   *head = nl->next;
 1554 
 1555   assert (nl->name != NULL);
 1556   free (nl->name);
 1557   free (nl);
 1558 
 1559   debug ("<== _nss_ldap_namelist_pop");
 1560 }
 1561 
 1562 /*
 1563  * Cleanup nested netgroup or group namelist.
 1564  */
 1565 void
 1566 _nss_ldap_namelist_destroy (struct name_list **head)
 1567 {
 1568   struct name_list *p, *next;
 1569 
 1570   debug ("==> _nss_ldap_namelist_destroy");
 1571 
 1572   for (p = *head; p != NULL; p = next)
 1573     {
 1574       next = p->next;
 1575 
 1576       if (p->name != NULL)
 1577     free (p->name);
 1578       free (p);
 1579     }
 1580 
 1581   *head = NULL;
 1582 
 1583   debug ("<== _nss_ldap_namelist_destroy");
 1584 }
 1585 
 1586 /*
 1587  * Check whether we have already seen a netgroup or group,
 1588  * to avoid loops in nested netgroup traversal
 1589  */
 1590 int
 1591 _nss_ldap_namelist_find (struct name_list *head, const char *netgroup)
 1592 {
 1593   struct name_list *p;
 1594   int found = 0;
 1595 
 1596   debug ("==> _nss_ldap_namelist_find");
 1597 
 1598   for (p = head; p != NULL; p = p->next)
 1599     {
 1600       if (strcasecmp (p->name, netgroup) == 0)
 1601     {
 1602       found++;
 1603       break;
 1604     }
 1605     }
 1606 
 1607   debug ("<== _nss_ldap_namelist_find");
 1608 
 1609   return found;
 1610 }
 1611 
 1612 NSS_STATUS _nss_ldap_validateconfig (ldap_config_t *config)
 1613 {
 1614   struct stat statbuf;
 1615 
 1616   if (config == NULL)
 1617     {
 1618       return NSS_UNAVAIL;
 1619     }
 1620 
 1621   if (config->ldc_mtime == 0)
 1622     {
 1623       return NSS_SUCCESS;
 1624     }
 1625 
 1626   if (stat (NSS_LDAP_PATH_CONF, &statbuf) == 0)
 1627     {
 1628       return (statbuf.st_mtime > config->ldc_mtime) ? NSS_TRYAGAIN : NSS_SUCCESS;
 1629     }
 1630 
 1631   return NSS_SUCCESS;
 1632 }
 1633 
 1634 /*
 1635  * Parse a text string into a long integer. If we fail for
 1636  * any reason, store the passed-in default value and return
 1637  * an error.
 1638  */
 1639 NSS_STATUS
 1640 _nss_ldap_parse_long (const char *text, long default_value, long *value)
 1641 {
 1642   char *p;
 1643   long l;
 1644 
 1645   if (text == NULL || strlen(text) == 0)
 1646     {
 1647       *value = default_value;
 1648       return NSS_NOTFOUND;
 1649     }
 1650 
 1651   l = strtol(text, &p, 10);
 1652   if (p == NULL || p == text || *p != '\0')
 1653     {
 1654       *value = default_value;
 1655       return NSS_NOTFOUND;
 1656     }
 1657 
 1658   *value = l;
 1659 
 1660   return NSS_SUCCESS;
 1661 }
 1662 
 1663 NSS_STATUS
 1664 _nss_ldap_parse_ulong (const char *text, unsigned long default_value,
 1665                        unsigned long *value)
 1666 {
 1667   char *p;
 1668   unsigned long l;
 1669 
 1670   if (text == NULL || strlen(text) == 0)
 1671     {
 1672       *value = default_value;
 1673       return NSS_NOTFOUND;
 1674     }
 1675 
 1676   l = strtoul(text, &p, 10);
 1677   if (p == NULL || p == text || *p != '\0')
 1678     {
 1679       *value = default_value;
 1680       return NSS_NOTFOUND;
 1681     }
 1682 
 1683   *value = l;
 1684 
 1685   return NSS_SUCCESS;
 1686 }
 1687 
 1688 NSS_STATUS
 1689 _nss_ldap_parse_int (const char *text, int default_value, int *value)
 1690 {
 1691   char *p;
 1692   long l;
 1693 
 1694   if (text == NULL || strlen(text) == 0)
 1695     {
 1696       *value = default_value;
 1697       return NSS_NOTFOUND;
 1698     }
 1699 
 1700   l = strtol(text, &p, 10);
 1701   if (p == NULL || p == text || *p != '\0')
 1702     {
 1703       *value = default_value;
 1704       return NSS_NOTFOUND;
 1705     }
 1706 
 1707   if (l < INT_MIN || l > INT_MAX)
 1708     {
 1709       *value = default_value;
 1710       return NSS_NOTFOUND;
 1711     }
 1712 
 1713   *value = l;
 1714 
 1715   return NSS_SUCCESS;
 1716 }
 1717 
 1718 NSS_STATUS
 1719 _nss_ldap_parse_uid_t (const char *text, uid_t default_value, uid_t *value)
 1720 {
 1721   char *p;
 1722   unsigned long l;
 1723 
 1724   if (text == NULL || strlen(text) == 0)
 1725     {
 1726       *value = default_value;
 1727       return NSS_NOTFOUND;
 1728     }
 1729 
 1730   l = strtoul(text, &p, 10);
 1731   if (p == NULL || p == text || *p != '\0')
 1732     {
 1733       *value = default_value;
 1734       return NSS_NOTFOUND;
 1735     }
 1736 #if SIZEOF_UID_T == SIZEOF_UNSIGNED_INT
 1737   if (l > UINT_MAX)
 1738     {
 1739       *value = default_value;
 1740       return NSS_NOTFOUND;
 1741     }
 1742 #endif
 1743 
 1744   *value = l;
 1745 
 1746   return NSS_SUCCESS;
 1747 }
 1748 
 1749 NSS_STATUS
 1750 _nss_ldap_parse_gid_t (const char *text, gid_t default_value, gid_t *value)
 1751 {
 1752   char *p;
 1753   unsigned long l;
 1754 
 1755   if (text == NULL || strlen(text) == 0)
 1756     {
 1757       *value = default_value;
 1758       return NSS_NOTFOUND;
 1759     }
 1760 
 1761   l = strtoul(text, &p, 10);
 1762   if (p == NULL || p == text || *p != '\0')
 1763     {
 1764       *value = default_value;
 1765       return NSS_NOTFOUND;
 1766     }
 1767 #if SIZEOF_GID_T == SIZEOF_UNSIGNED_INT
 1768   if (l > UINT_MAX)
 1769     {
 1770       *value = default_value;
 1771       return NSS_NOTFOUND;
 1772     }
 1773 #endif
 1774 
 1775   *value = l;
 1776 
 1777   return NSS_SUCCESS;
 1778 }