"Fossies" - the Fresh Open Source Software Archive

Member "nss_ldap-265/ldap-netgrp.c" (6 Nov 2009, 24275 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) 2002-2005 Luke Howard.
    2    This file is part of the nss_ldap library.
    3    Linux support contributed by Larry Lile, <llile@dreamworks.com>, 2002.
    4    Solaris support contributed by Luke Howard, <lukeh@padl.com>, 2004.
    5 
    6    The nss_ldap library is free software; you can redistribute it and/or
    7    modify it under the terms of the GNU Library General Public License as
    8    published by the Free Software Foundation; either version 2 of the
    9    License, or (at your option) any later version.
   10 
   11    The nss_ldap library is distributed in the hope that it will be useful,
   12    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14    Library General Public License for more details.
   15 
   16    You should have received a copy of the GNU Library General Public
   17    License along with the nss_ldap library; see the file COPYING.LIB.  If not,
   18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   19    Boston, MA 02111-1307, USA.
   20 
   21    $Id: ldap-netgrp.c,v 2.48 2009/11/06 10:15:26 lukeh Exp $
   22  */
   23 
   24 static char rcsId[] =
   25   "$Id: ldap-netgrp.c,v 2.48 2009/11/06 10:15:26 lukeh Exp $";
   26 
   27 #include "config.h"
   28 
   29 #include <stdio.h>
   30 #include <stdarg.h>
   31 #include <ctype.h>
   32 
   33 #ifdef HAVE_PORT_BEFORE_H
   34 #include <port_before.h>
   35 #endif
   36 
   37 #if defined(HAVE_THREAD_H) && !defined(_AIX)
   38 #include <thread.h>
   39 #elif defined(HAVE_PTHREAD_H)
   40 #include <pthread.h>
   41 #endif
   42 
   43 #include <stdlib.h>
   44 #include <sys/types.h>
   45 #include <sys/param.h>
   46 #include <string.h>
   47 #include <assert.h>
   48 
   49 #ifdef HAVE_LBER_H
   50 #include <lber.h>
   51 #endif
   52 #ifdef HAVE_LDAP_H
   53 #include <ldap.h>
   54 #endif
   55 
   56 #ifndef HAVE_SNPRINTF
   57 #include "snprintf.h"
   58 #endif
   59 
   60 #include "ldap-nss.h"
   61 #include "ldap-netgrp.h"
   62 #include "util.h"
   63 
   64 #ifdef HAVE_PORT_AFTER_H
   65 #include <port_after.h>
   66 #endif
   67 
   68 #ifdef HAVE_NSS_H
   69 static ent_context_t *_ngbe = NULL;
   70 #endif
   71 
   72 #ifdef HAVE_IRS_H
   73 enum nss_netgr_status {
   74     NSS_NETGR_FOUND,
   75     NSS_NETGR_NO,
   76     NSS_NETGR_NOMEM
   77 };
   78 
   79 struct pvt; /* forward declaration for IRS backend type */
   80 #endif /* HAVE_IRS_H */
   81 
   82 #ifdef HAVE_NSSWITCH_H
   83 static nss_backend_op_t netgroup_ops[];
   84 #endif
   85 
   86 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_IRS_H)
   87 struct ldap_innetgr_args
   88 {
   89   const char *lia_netgroup;
   90   enum nss_netgr_status lia_netgr_status;
   91   int lia_depth;
   92   int lia_erange;
   93 };
   94 
   95 typedef struct ldap_innetgr_args ldap_innetgr_args_t;
   96 
   97 static NSS_STATUS do_innetgr_nested (ldap_innetgr_args_t * li_args,
   98                      const char *nested);
   99 #endif /* HAVE_NSSWITCH_H || HAVE_IRS_H */
  100 
  101 /*
  102  * I pulled the following macro (EXPAND), functions (strip_whitespace and
  103  * _nss_netgroup_parseline) and structures (name_list and __netgrent) from
  104  * glibc-2.2.x.  _nss_netgroup_parseline became _nss_ldap_parse_netgr after
  105  * some modification. 
  106  * 
  107  * The rest of the code is modeled on various other _nss_ldap functions.
  108  */
  109 
  110 #define EXPAND(needed)                                                        \
  111   do                                                                          \
  112     {                                                                         \
  113       size_t old_cursor = result->cursor - result->data;                      \
  114                                                                               \
  115       result->data_size += 512 > 2 * needed ? 512 : 2 * needed;               \
  116       result->data = realloc (result->data, result->data_size);               \
  117                                                                               \
  118       if (result->data == NULL)                                               \
  119         {                                                                     \
  120           stat = NSS_UNAVAIL;                                                 \
  121           goto out;                                                           \
  122         }                                                                     \
  123                                                                               \
  124       result->cursor = result->data + old_cursor;                             \
  125     }                                                                         \
  126   while (0)
  127 
  128 /* A netgroup can consist of names of other netgroups.  We have to
  129    track which netgroups were read and which still have to be read.  */
  130 
  131 
  132 /* Dataset for iterating netgroups.  */
  133 struct __netgrent
  134 {
  135   enum
  136   { triple_val, group_val }
  137   type;
  138 
  139   union
  140   {
  141     struct
  142     {
  143       const char *host;
  144       const char *user;
  145       const char *domain;
  146     }
  147     triple;
  148 
  149     const char *group;
  150   }
  151   val;
  152 
  153   /* Room for the data kept between the calls to the netgroup
  154      functions.  We must avoid global variables.  */
  155   char *data;
  156   size_t data_size;
  157   char *cursor;
  158   int first;
  159 
  160   struct name_list *known_groups;
  161   struct name_list *needed_groups;
  162 };
  163 
  164 static char *
  165 strip_whitespace (char *str)
  166 {
  167   char *cp = str;
  168 
  169   /* Skip leading spaces.  */
  170   while (isspace ((int) *cp))
  171     cp++;
  172 
  173   str = cp;
  174   while (*cp != '\0' && !isspace ((int) *cp))
  175     cp++;
  176 
  177   /* Null-terminate, stripping off any trailing spaces.  */
  178   *cp = '\0';
  179 
  180   return *str == '\0' ? NULL : str;
  181 }
  182 
  183 static NSS_STATUS
  184 _nss_ldap_parse_netgr (void *vresultp, char *buffer, size_t buflen)
  185 {
  186   struct __netgrent *result = (struct __netgrent *) vresultp;
  187   char *cp = result->cursor;
  188   char *user, *host, *domain;
  189 
  190   /* The netgroup either doesn't exist or is empty. */
  191   if (cp == NULL)
  192     return NSS_RETURN;
  193 
  194   /* First skip leading spaces. */
  195   while (isspace ((int) *cp))
  196     ++cp;
  197 
  198   if (*cp != '(')
  199     {
  200       /* We have a list of other netgroups. */
  201       char *name = cp;
  202 
  203       while (*cp != '\0' && !isspace ((int) *cp))
  204     ++cp;
  205 
  206       if (name != cp)
  207     {
  208       /* It is another netgroup name. */
  209       int last = *cp == '\0';
  210 
  211       result->type = group_val;
  212       result->val.group = name;
  213       *cp = '\0';
  214       if (!last)
  215         ++cp;
  216       result->cursor = cp;
  217       result->first = 0;
  218 
  219       return NSS_SUCCESS;
  220     }
  221       return result->first ? NSS_NOTFOUND : NSS_RETURN;
  222     }
  223 
  224   /* Match host name. */
  225   host = ++cp;
  226   while (*cp != ',')
  227     if (*cp++ == '\0')
  228       return result->first ? NSS_NOTFOUND : NSS_RETURN;
  229 
  230   /* Match user name. */
  231   user = ++cp;
  232   while (*cp != ',')
  233     if (*cp++ == '\0')
  234       return result->first ? NSS_NOTFOUND : NSS_RETURN;
  235 
  236   /* Match domain name. */
  237   domain = ++cp;
  238   while (*cp != ')')
  239     if (*cp++ == '\0')
  240       return result->first ? NSS_NOTFOUND : NSS_RETURN;
  241   ++cp;
  242 
  243   /* When we got here we have found an entry.  Before we can copy it
  244      to the private buffer we have to make sure it is big enough.  */
  245   if (cp - host > buflen)
  246     return NSS_TRYAGAIN;
  247 
  248   strncpy (buffer, host, cp - host);
  249   result->type = triple_val;
  250 
  251   buffer[(user - host) - 1] = '\0';
  252   result->val.triple.host = strip_whitespace (buffer);
  253 
  254   buffer[(domain - host) - 1] = '\0';
  255   result->val.triple.user = strip_whitespace (buffer + (user - host));
  256 
  257   buffer[(cp - host) - 1] = '\0';
  258   result->val.triple.domain = strip_whitespace (buffer + (domain - host));
  259 
  260   /* Remember where we stopped reading. */
  261   result->cursor = cp;
  262   result->first = 0;
  263 
  264   return NSS_SUCCESS;
  265 }
  266 
  267 #ifdef HAVE_NSS_H
  268 static NSS_STATUS
  269 _nss_ldap_load_netgr (LDAPMessage * e,
  270               ldap_state_t * pvt,
  271               void *vresultp, char *buffer, size_t buflen)
  272 {
  273   int attr;
  274   int nvals;
  275   int valcount = 0;
  276   char **vals;
  277   char **valiter;
  278   struct __netgrent *result = vresultp;
  279   NSS_STATUS stat = NSS_SUCCESS;
  280 
  281   for (attr = 0; attr < 2; attr++)
  282     {
  283       switch (attr)
  284     {
  285     case 1:
  286       vals = _nss_ldap_get_values (e, AT (nisNetgroupTriple));
  287       break;
  288     default:
  289       vals = _nss_ldap_get_values (e, AT (memberNisNetgroup));
  290       break;
  291     }
  292 
  293       nvals = ldap_count_values (vals);
  294 
  295       if (vals == NULL)
  296     continue;
  297 
  298       if (nvals == 0)
  299     {
  300       ldap_value_free (vals);
  301       continue;
  302     }
  303 
  304       if (result->data_size > 0
  305       && result->cursor - result->data + 1 > result->data_size)
  306     EXPAND (1);
  307 
  308       if (result->data_size > 0)
  309     *result->cursor++ = ' ';
  310 
  311       valcount += nvals;
  312       valiter = vals;
  313 
  314       while (*valiter != NULL)
  315     {
  316       int curlen = strlen (*valiter);
  317       if (result->cursor - result->data + curlen + 1 > result->data_size)
  318         EXPAND (curlen + 1);
  319       memcpy (result->cursor, *valiter, curlen + 1);
  320       result->cursor += curlen;
  321       valiter++;
  322       if (*valiter != NULL)
  323         *result->cursor++ = ' ';
  324     }
  325       ldap_value_free (vals);
  326     }
  327 
  328   result->first = 1;
  329   result->cursor = result->data;
  330 
  331 out:
  332 
  333   return stat;
  334 }
  335 
  336 NSS_STATUS
  337 _nss_ldap_endnetgrent (struct __netgrent * result)
  338 {
  339   if (result->data != NULL)
  340     {
  341       free (result->data);
  342       result->data = NULL;
  343       result->data_size = 0;
  344       result->cursor = NULL;
  345     }
  346 
  347   LOOKUP_ENDENT (_ngbe);
  348 }
  349 
  350 NSS_STATUS
  351 _nss_ldap_setnetgrent (char *group, struct __netgrent *result)
  352 {
  353   int errnop = 0, buflen = 0;
  354   char *buffer = (char *) NULL;
  355   ldap_args_t a;
  356   NSS_STATUS stat = NSS_SUCCESS;
  357 
  358   if (group[0] == '\0')
  359     return NSS_UNAVAIL;
  360 
  361   if (result->data != NULL)
  362     free (result->data);
  363   result->data = result->cursor = NULL;
  364   result->data_size = 0;
  365 
  366   LA_INIT (a);
  367   LA_STRING (a) = group;
  368   LA_TYPE (a) = LA_TYPE_STRING;
  369 
  370   stat =
  371     _nss_ldap_getbyname (&a, result, buffer, buflen, &errnop,
  372              _nss_ldap_filt_getnetgrent, LM_NETGROUP,
  373              _nss_ldap_load_netgr);
  374 
  375   if (stat == NSS_NOTFOUND)
  376     return stat;
  377 
  378   LOOKUP_SETENT (_ngbe);
  379 }
  380 
  381 NSS_STATUS
  382 _nss_ldap_getnetgrent_r (struct __netgrent *result,
  383              char *buffer, size_t buflen, int *errnop)
  384 {
  385   return _nss_ldap_parse_netgr (result, buffer, buflen);
  386 }
  387 #endif /* HAVE_NSS_H */
  388 
  389 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_IRS_H)
  390 /*
  391  * Chase nested netgroups. If we can't find a nested netgroup, we try
  392  * the next one - don't want to fail authoritatively because of bad
  393  * user data.
  394  */
  395 static NSS_STATUS
  396 nn_chase (nss_ldap_netgr_backend_t * ngbe, LDAPMessage ** pEntry)
  397 {
  398   ldap_args_t a;
  399   NSS_STATUS stat = NSS_NOTFOUND;
  400 
  401   debug ("==> nn_chase");
  402 
  403   if (ngbe->state->ec_res != NULL)
  404     {
  405       ldap_msgfree (ngbe->state->ec_res);
  406       ngbe->state->ec_res = NULL;
  407     }
  408 
  409   while (ngbe->needed_groups != NULL)
  410     {
  411       /* If this netgroup has already been seen, avoid it  */
  412       if (_nss_ldap_namelist_find (ngbe->known_groups, ngbe->needed_groups->name))
  413     {
  414       _nss_ldap_namelist_pop (&ngbe->needed_groups);
  415       continue;
  416     }
  417 
  418       LA_INIT (a);
  419       LA_TYPE (a) = LA_TYPE_STRING;
  420       LA_STRING (a) = ngbe->needed_groups->name;
  421 
  422       debug (":== nn_chase: nested netgroup=%s", LA_STRING (a));
  423 
  424       _nss_ldap_enter ();
  425       stat = _nss_ldap_search_s (&a, _nss_ldap_filt_getnetgrent,
  426                  LM_NETGROUP, NULL, 1, &ngbe->state->ec_res);
  427       _nss_ldap_leave ();
  428 
  429       if (stat == NSS_SUCCESS)
  430     {
  431       /* we have "seen" this netgroup; track it for loop detection */
  432       stat = _nss_ldap_namelist_push (&ngbe->known_groups, ngbe->needed_groups->name);
  433       if (stat != NSS_SUCCESS)
  434         {
  435           _nss_ldap_namelist_pop (&ngbe->needed_groups);
  436           break;
  437         }
  438     }
  439 
  440       _nss_ldap_namelist_pop (&ngbe->needed_groups);
  441 
  442       if (stat == NSS_SUCCESS)
  443     {
  444       /* Check we got an entry, not just a result. */
  445       *pEntry = _nss_ldap_first_entry (ngbe->state->ec_res);
  446       if (*pEntry == NULL)
  447         {
  448           ldap_msgfree (ngbe->state->ec_res);
  449           ngbe->state->ec_res = NULL;
  450           stat = NSS_NOTFOUND;
  451         }
  452     }
  453 
  454       if (stat == NSS_SUCCESS)
  455     {
  456       /* found one. */
  457       break;
  458     }
  459     }
  460 
  461   debug ("<== nn_chase result=%d", stat);
  462 
  463   return stat;
  464 }
  465 #endif /* HAVE_NSSWITCH_H || HAVE_IRS_H */
  466 
  467 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_IRS_H)
  468 /*
  469  * getnetgrent() inner implementation, used by both Solaris NSS
  470  * and IRS/AIX
  471  */
  472 static NSS_STATUS
  473 do_getnetgrent (nss_ldap_netgr_backend_t *be,
  474         char *buffer, size_t buflen,
  475         enum nss_netgr_status *status,
  476         char **machine, char **user, char **domain)
  477 {
  478   ent_context_t *ctx;
  479   NSS_STATUS parseStat = NSS_NOTFOUND;
  480 
  481   /*
  482    * This function is called with the pseudo-backend that
  483    * we created in _nss_ldap_setnetgrent() (see below)
  484    */
  485   debug ("==> do_getnetgrent");
  486 
  487   ctx = be->state;
  488   assert (ctx != NULL);
  489 
  490   *status = NSS_NETGR_NO;
  491   *machine = NULL;
  492   *user = NULL;
  493   *domain = NULL;
  494 
  495   do
  496     {
  497       NSS_STATUS resultStat = NSS_SUCCESS;
  498       char **vals, **p;
  499       ldap_state_t *state = &ctx->ec_state;
  500       struct __netgrent __netgrent;
  501       LDAPMessage *e = NULL;
  502 
  503       if (state->ls_retry == 0 && state->ls_info.ls_index == -1)
  504     {
  505       resultStat = NSS_NOTFOUND;
  506 
  507       if (ctx->ec_res != NULL)
  508         {
  509           e = _nss_ldap_first_entry (ctx->ec_res);
  510           if (e != NULL)
  511         resultStat = NSS_SUCCESS;
  512         }
  513 
  514       if (resultStat != NSS_SUCCESS)
  515         {
  516           /* chase nested netgroups */
  517           resultStat = nn_chase (be, &e);
  518         }
  519 
  520       if (resultStat != NSS_SUCCESS)
  521         {
  522           parseStat = resultStat;
  523           break;
  524         }
  525 
  526       assert (e != NULL);
  527 
  528       /* Push nested netgroups onto stack for deferred chasing */
  529       vals = _nss_ldap_get_values (e, AT (memberNisNetgroup));
  530       if (vals != NULL)
  531         {
  532           for (p = vals; *p != NULL; p++)
  533         {
  534           parseStat = _nss_ldap_namelist_push (&be->needed_groups, *p);
  535           if (parseStat != NSS_SUCCESS)
  536             break;
  537         }
  538           ldap_value_free (vals);
  539 
  540           if (parseStat != NSS_SUCCESS)
  541         break;      /* out of memory */
  542         }
  543     }
  544       else
  545     {
  546       assert (ctx->ec_res != NULL);
  547       e = _nss_ldap_first_entry (ctx->ec_res);
  548       if (e == NULL)
  549         {
  550           /* This should never happen, but we fail gracefully. */
  551           parseStat = NSS_UNAVAIL;
  552           break;
  553         }
  554     }
  555 
  556       /* We have an entry; now, try to parse it. */
  557       vals = _nss_ldap_get_values (e, AT (nisNetgroupTriple));
  558       if (vals == NULL)
  559     {
  560       state->ls_info.ls_index = -1;
  561       parseStat = NSS_NOTFOUND;
  562       ldap_msgfree (ctx->ec_res);
  563       ctx->ec_res = NULL;
  564       continue;
  565     }
  566 
  567       switch (state->ls_info.ls_index)
  568     {
  569     case 0:
  570       /* last time. decrementing ls_index to -1 AND returning
  571        * an error code will force this entry to be discared.
  572        */
  573       parseStat = NSS_NOTFOUND;
  574       break;
  575     case -1:
  576       /* first time */
  577       state->ls_info.ls_index = ldap_count_values (vals);
  578       /* fall off to default... */
  579     default:
  580       __netgrent.data = vals[state->ls_info.ls_index - 1];
  581       __netgrent.data_size = strlen (vals[state->ls_info.ls_index - 1]);
  582       __netgrent.cursor = __netgrent.data;
  583       __netgrent.first = 1;
  584 
  585       parseStat = _nss_ldap_parse_netgr (&__netgrent, buffer, buflen);
  586       if (parseStat != NSS_SUCCESS)
  587         {
  588           break;
  589         }
  590       if (__netgrent.type != triple_val)
  591         {
  592           parseStat = NSS_NOTFOUND;
  593           break;
  594         }
  595       *machine = (char *) __netgrent.val.triple.host;
  596       *user = (char *) __netgrent.val.triple.user;
  597       *domain = (char *) __netgrent.val.triple.domain;
  598       break;
  599     }
  600 
  601       ldap_value_free (vals);
  602       state->ls_info.ls_index--;
  603 
  604       /* hold onto the state if we're out of memory XXX */
  605       state->ls_retry = (parseStat == NSS_TRYAGAIN ? 1 : 0);
  606       *status = (parseStat == NSS_SUCCESS) ? NSS_NETGR_FOUND : NSS_NETGR_NOMEM;
  607 
  608       if (state->ls_retry == 0 && state->ls_info.ls_index == -1)
  609     {
  610       ldap_msgfree (ctx->ec_res);
  611       ctx->ec_res = NULL;
  612     }
  613     }
  614   while (parseStat == NSS_NOTFOUND);
  615 
  616   if (parseStat == NSS_TRYAGAIN)
  617     {
  618       errno = ERANGE;
  619     }
  620 
  621   debug ("<== do_getnetgrent");
  622 
  623   return parseStat;
  624 }
  625 
  626 /*
  627  * Test a 4-tuple
  628  */
  629 static NSS_STATUS
  630 do_parse_innetgr (LDAPMessage * e, ldap_state_t * pvt,
  631           void *result, char *buffer, size_t buflen)
  632 {
  633   ldap_innetgr_args_t *li_args = (ldap_innetgr_args_t *) result;
  634   int count;
  635   char **values = NULL;
  636   NSS_STATUS stat = NSS_NOTFOUND;
  637 
  638   debug ("==> do_parse_innetgr");
  639 
  640   values = _nss_ldap_get_values (e, ATM (LM_NETGROUP, cn));
  641   if (values == NULL)
  642       return NSS_NOTFOUND;
  643 
  644   count = ldap_count_values (values);
  645 
  646   while (--count >= 0)
  647     {
  648       assert (values[count] != NULL);
  649 
  650       if (strcasecmp (li_args->lia_netgroup, values[count]) == 0)
  651     {
  652       li_args->lia_netgr_status = NSS_NETGR_FOUND;
  653       stat = NSS_SUCCESS;
  654     }
  655       else
  656     {
  657       stat = do_innetgr_nested (li_args, values[count]);
  658     }
  659 
  660       if (stat == NSS_SUCCESS)
  661     break;
  662     }
  663 
  664   ldap_value_free (values);
  665 
  666   debug ("<== do_parse_innetgr");
  667 
  668   return stat;
  669 }
  670 
  671 /*
  672  * NB: caller has acquired the global lock
  673  */
  674 static NSS_STATUS
  675 do_innetgr_nested (ldap_innetgr_args_t * li_args, const char *nested)
  676 {
  677   NSS_STATUS stat;
  678   ldap_args_t a;
  679   ent_context_t *ctx = NULL;
  680 
  681   debug ("==> do_innetgr_nested netgroup=%s assertion=%s",
  682      li_args->lia_netgroup, nested);
  683 
  684   if (li_args->lia_depth >= LDAP_NSS_MAXNETGR_DEPTH)
  685     {
  686       debug ("<== do_innetgr_nested: maximum depth exceeded");
  687       return NSS_NOTFOUND;
  688     }
  689 
  690   LA_INIT (a);
  691   LA_TYPE (a) = LA_TYPE_STRING;
  692   LA_STRING (a) = nested;   /* memberNisNetgroup */
  693 
  694   if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
  695     {
  696       debug ("<== do_innetgr_nested: failed to initialize context");
  697       return NSS_UNAVAIL;
  698     }
  699 
  700   li_args->lia_depth++;
  701 
  702   stat = _nss_ldap_getent_ex (&a, &ctx, (void *) li_args, NULL, 0,
  703                   &li_args->lia_erange, _nss_ldap_filt_innetgr,
  704                   LM_NETGROUP, NULL, do_parse_innetgr);
  705 
  706   li_args->lia_depth--;
  707 
  708   _nss_ldap_ent_context_release (&ctx);
  709 
  710   debug ("<== do_innetgr_nested status=%d netgr_status=%d",
  711      stat, li_args->lia_netgr_status);
  712 
  713   return stat;
  714 }
  715 
  716 /*
  717  * NB: caller has acquired the global lock
  718  */
  719 static NSS_STATUS
  720 do_innetgr (ldap_innetgr_args_t * li_args,
  721         const char *machine, const char *user, const char *domain)
  722 {
  723   NSS_STATUS stat;
  724   ldap_args_t a;
  725   ent_context_t *ctx = NULL;
  726 
  727   debug ("==> do_innetgr netgroup=%s", li_args->lia_netgroup);
  728 
  729   /*
  730    * First, find which netgroup the 3-tuple belongs to.
  731    */
  732   LA_INIT (a);
  733   LA_TYPE (a) = LA_TYPE_TRIPLE;
  734   LA_TRIPLE (a).user = user;
  735   LA_TRIPLE (a).host = machine;
  736   LA_TRIPLE (a).domain = domain;
  737 
  738   if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
  739     {
  740       debug ("<== do_innetgr: failed to initialize context");
  741       return NSS_UNAVAIL;
  742     }
  743 
  744   stat = _nss_ldap_getent_ex (&a, &ctx, (void *) li_args, NULL, 0,
  745                   &li_args->lia_erange, NULL, LM_NETGROUP,
  746                   NULL, do_parse_innetgr);
  747 
  748   _nss_ldap_ent_context_release (&ctx);
  749 
  750   debug ("<== do_innetgr status=%d netgr_status=%d",
  751      stat, li_args->lia_netgr_status);
  752 
  753   return stat;
  754 }
  755 #endif /* HAVE_NSSWITCH_H || HAVE_IRS_H */
  756 
  757 #ifdef HAVE_NSSWITCH_H
  758 static NSS_STATUS
  759 _nss_ldap_getnetgroup_endent (nss_backend_t * be, void *_args)
  760 {
  761   LOOKUP_ENDENT (be);
  762 }
  763 
  764 static NSS_STATUS
  765 _nss_ldap_getnetgroup_setent (nss_backend_t * be, void *_args)
  766 {
  767   return NSS_SUCCESS;
  768 }
  769 
  770 static NSS_STATUS
  771 _nss_ldap_getnetgroup_getent (nss_backend_t * _be, void *_args)
  772 {
  773   nss_ldap_netgr_backend_t *be = (nss_ldap_netgr_backend_t *) _be;
  774   struct nss_getnetgrent_args *args = (struct nss_getnetgrent_args *) _args;
  775   NSS_STATUS stat;
  776 
  777   _nss_ldap_enter ();
  778 
  779   stat = do_getnetgrent (be,
  780              args->buffer,
  781              args->buflen,
  782              &args->status,
  783              &args->retp[NSS_NETGR_MACHINE],
  784              &args->retp[NSS_NETGR_USER],
  785              &args->retp[NSS_NETGR_DOMAIN]);
  786 
  787   _nss_ldap_leave ();
  788 
  789   return stat;
  790 }
  791 
  792 static NSS_STATUS
  793 _nss_ldap_innetgr (nss_backend_t * be, void *_args)
  794 {
  795   struct nss_innetgr_args *args = (struct nss_innetgr_args *) _args;
  796   int i;
  797 
  798   /*
  799    * Enumerate the groups in args structure and see whether
  800    * any 4-tuple was satisfied. This really needs LDAP
  801    * component matching to be done efficiently.
  802    */
  803 
  804   debug
  805     ("==> _nss_ldap_innetgr MACHINE.argc=%d USER.argc=%d DOMAIN.argc=%d groups.argc=%d",
  806      args->arg[NSS_NETGR_MACHINE].argc, args->arg[NSS_NETGR_USER].argc,
  807      args->arg[NSS_NETGR_DOMAIN].argc, args->groups.argc);
  808 
  809   /* note: mountd on Solaris does set multiple 'groups' with one 'arg' for
  810    * efficiency reasons */
  811 
  812   assert (args->arg[NSS_NETGR_MACHINE].argc <= 1);
  813   assert (args->arg[NSS_NETGR_USER].argc <= 1);
  814   assert (args->arg[NSS_NETGR_DOMAIN].argc <= 1);
  815 
  816   _nss_ldap_enter ();
  817 
  818   const char *machine = (args->arg[NSS_NETGR_MACHINE].argc != 0) ?
  819     args->arg[NSS_NETGR_MACHINE].argv[0] : NULL;
  820   const char *user = (args->arg[NSS_NETGR_USER].argc != 0) ?
  821     args->arg[NSS_NETGR_USER].argv[0] : NULL;
  822   const char *domain = (args->arg[NSS_NETGR_DOMAIN].argc != 0) ?
  823     args->arg[NSS_NETGR_DOMAIN].argv[0] : NULL;
  824 
  825   for (i = 0; i < args->groups.argc; i++)
  826     {
  827       NSS_STATUS parseStat;
  828       ldap_innetgr_args_t li_args;
  829 
  830       li_args.lia_netgroup = args->groups.argv[i];
  831       li_args.lia_netgr_status = NSS_NETGR_NO;
  832       li_args.lia_depth = 0;
  833       li_args.lia_erange = 0;
  834 
  835       parseStat = do_innetgr (&li_args, machine, user, domain);
  836       if (parseStat != NSS_SUCCESS && parseStat != NSS_NOTFOUND)
  837     {
  838       /* fatal error */
  839       if (li_args.lia_erange != 0)
  840         errno = ERANGE;
  841       break;
  842     }
  843 
  844       args->status = li_args.lia_netgr_status;
  845 
  846       if (args->status == NSS_NETGR_FOUND)
  847     {
  848       _nss_ldap_leave ();
  849       debug ("<== _nss_ldap_innetgr (FOUND)");
  850       return NSS_SUCCESS;
  851     }
  852     }
  853 
  854   _nss_ldap_leave ();
  855   debug ("<== _nss_ldap_innetgr (not found)");
  856   return NSS_NOTFOUND;
  857 }
  858 
  859 /*
  860  * According to the "documentation", setnetgrent() is really
  861  * a getXXXbyYYY() operation that returns a pseudo-backend
  862  * through which one may enumerate the netgroup's members.
  863  *
  864  * ie. this is the constructor for the pseudo-backend.
  865  */
  866 static NSS_STATUS
  867 _nss_ldap_setnetgrent (nss_backend_t * be, void *_args)
  868 {
  869   NSS_STATUS stat;
  870   struct nss_setnetgrent_args *args;
  871   nss_ldap_netgr_backend_t *ngbe;
  872   ldap_args_t a;
  873 
  874   debug ("==> _nss_ldap_setnetgrent");
  875 
  876   args = (struct nss_setnetgrent_args *) _args;
  877   args->iterator = NULL;    /* initialize */
  878 
  879   /*
  880    * This retrieves the top-level netgroup; nested netgroups
  881    * are chased inside the pseudo-backend.
  882    */
  883 
  884   LA_INIT (a);
  885   LA_TYPE (a) = LA_TYPE_STRING;
  886   LA_STRING (a) = args->netgroup;   /* cn */
  887 
  888   ngbe = (nss_ldap_netgr_backend_t *) malloc (sizeof (*ngbe));
  889   if (ngbe == NULL)
  890     {
  891       debug ("<== _nss_ldap_setnetgrent");
  892       return NSS_UNAVAIL;
  893     }
  894 
  895   ngbe->ops = netgroup_ops;
  896   ngbe->n_ops = 6;
  897   ngbe->state = NULL;
  898   ngbe->known_groups = NULL;
  899   ngbe->needed_groups = NULL;
  900 
  901   stat = _nss_ldap_default_constr ((nss_ldap_backend_t *) ngbe);
  902   if (stat != NSS_SUCCESS)
  903     {
  904       free (ngbe);
  905       debug ("<== _nss_ldap_setnetgrent");
  906       return stat;
  907     }
  908 
  909   if (_nss_ldap_ent_context_init (&ngbe->state) == NULL)
  910     {
  911       _nss_ldap_default_destr ((nss_backend_t *) ngbe, NULL);
  912       debug ("<== _nss_ldap_setnetgrent");
  913       return NSS_UNAVAIL;
  914     }
  915 
  916   assert (ngbe->state != NULL);
  917   assert (ngbe->state->ec_res == NULL);
  918 
  919   _nss_ldap_enter ();
  920   stat = _nss_ldap_search_s (&a, _nss_ldap_filt_getnetgrent,
  921                  LM_NETGROUP, NULL, 1, &ngbe->state->ec_res);
  922   _nss_ldap_leave ();
  923 
  924   if (stat == NSS_SUCCESS)
  925     {
  926       /* we have "seen" this netgroup; track it for loop detection */
  927       stat = _nss_ldap_namelist_push (&ngbe->known_groups, args->netgroup);
  928     }
  929 
  930   if (stat == NSS_SUCCESS)
  931     {
  932       args->iterator = (nss_backend_t *) ngbe;
  933     }
  934   else
  935     {
  936       _nss_ldap_default_destr ((nss_backend_t *) ngbe, NULL);
  937     }
  938 
  939   debug ("<== _nss_ldap_setnetgrent");
  940 
  941   return stat;
  942 }
  943 
  944 static NSS_STATUS
  945 _nss_ldap_netgroup_destr (nss_backend_t * _ngbe, void *args)
  946 {
  947   nss_ldap_netgr_backend_t *ngbe = (nss_ldap_netgr_backend_t *) _ngbe;
  948 
  949   /* free list of nested netgroups */
  950   _nss_ldap_namelist_destroy (&ngbe->known_groups);
  951   _nss_ldap_namelist_destroy (&ngbe->needed_groups);
  952 
  953   return _nss_ldap_default_destr (_ngbe, args);
  954 }
  955 
  956 static nss_backend_op_t netgroup_ops[] = {
  957   _nss_ldap_netgroup_destr, /* NSS_DBOP_DESTRUCTOR */
  958   _nss_ldap_getnetgroup_endent, /* NSS_DBOP_ENDENT */
  959   _nss_ldap_getnetgroup_setent, /* NSS_DBOP_SETENT */
  960   _nss_ldap_getnetgroup_getent, /* NSS_DBOP_GETENT */
  961   _nss_ldap_innetgr,        /* NSS_DBOP_NETGROUP_IN */
  962   _nss_ldap_setnetgrent     /* NSS_DBOP_NETGROUP_SET */
  963 };
  964 
  965 nss_backend_t *
  966 _nss_ldap_netgroup_constr (const char *db_name,
  967                const char *src_name, const char *cfg_args)
  968 {
  969   nss_ldap_netgr_backend_t *be;
  970 
  971   if (!(be = (nss_ldap_netgr_backend_t *) malloc (sizeof (*be))))
  972     return NULL;
  973 
  974   be->ops = netgroup_ops;
  975   be->n_ops = sizeof (netgroup_ops) / sizeof (nss_backend_op_t);
  976   be->known_groups = NULL;
  977   be->needed_groups = NULL;
  978 
  979   if (_nss_ldap_default_constr ((nss_ldap_backend_t *) be) != NSS_SUCCESS)
  980     {
  981       free (be);
  982       return NULL;
  983     }
  984 
  985   return (nss_backend_t *) be;
  986 }
  987 
  988 #endif /* !HAVE_NSS_H */
  989 
  990 #ifdef HAVE_IRS_H
  991 #include "irs-netgrp.c"
  992 #endif /* HAVE_IRS_H */