"Fossies" - the Fresh Open Source Software Archive

Member "nss_ldap-265/ldap-grp.c" (6 Nov 2009, 30682 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-grp.c,v 2.110 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 <string.h>
   39 #include <stdio.h>
   40 #include <sys/types.h>
   41 #include <sys/param.h>
   42 #include <grp.h>
   43 
   44 #ifdef HAVE_LBER_H
   45 #include <lber.h>
   46 #endif
   47 #ifdef HAVE_LDAP_H
   48 #include <ldap.h>
   49 #endif
   50 
   51 #ifndef HAVE_SNPRINTF
   52 #include "snprintf.h"
   53 #endif
   54 
   55 #include "ldap-nss.h"
   56 #include "ldap-grp.h"
   57 #include "util.h"
   58 
   59 #ifdef HAVE_PORT_AFTER_H
   60 #include <port_after.h>
   61 #endif
   62 
   63 #ifdef HAVE_NSS_H
   64 static ent_context_t *gr_context = NULL;
   65 #endif
   66 
   67 #ifdef HAVE_USERSEC_H
   68 typedef struct ldap_initgroups_args
   69 {
   70   char *grplist;
   71   size_t listlen;
   72   int depth;
   73   struct name_list *known_groups;
   74   int backlink;
   75 }
   76 ldap_initgroups_args_t;
   77 #else
   78 # ifdef HAVE_NSSWITCH_H
   79 typedef struct ldap_initgroups_args
   80 {
   81   struct nss_groupsbymem *gbm;
   82   int depth;
   83   struct name_list *known_groups;
   84   int backlink;
   85 }
   86 ldap_initgroups_args_t;
   87 # else
   88 typedef struct ldap_initgroups_args
   89 {
   90   gid_t group;
   91   long int *start;
   92   long int *size;
   93   gid_t **groups;
   94   long int limit;
   95   int depth;
   96   struct name_list *known_groups;
   97   int backlink;
   98 }
   99 ldap_initgroups_args_t;
  100 # endif
  101 #endif /* HAVE_USERSEC_H */
  102 
  103 static NSS_STATUS
  104 ng_chase (const char *dn, ldap_initgroups_args_t * lia);
  105 
  106 static NSS_STATUS
  107 ng_chase_backlink (const char ** membersOf, ldap_initgroups_args_t * lia);
  108 
  109 /*
  110  * Range retrieval logic was reimplemented from example in
  111  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/searching_using_range_retrieval.asp
  112  */
  113 
  114 static NSS_STATUS
  115 do_parse_range (const char *attributeType,
  116         const char *attributeDescription, int *start, int *end)
  117 {
  118   NSS_STATUS stat = NSS_NOTFOUND;
  119   char *attribute;
  120   size_t attributeTypeLength;
  121   size_t attributeDescriptionLength;
  122   char *p;
  123 #ifdef HAVE_STRTOK_R
  124   char *st = NULL;
  125 #endif
  126 
  127   *start = 0;
  128   *end = -1;
  129 
  130   if (strcasecmp (attributeType, attributeDescription) == 0)
  131     {
  132       return NSS_SUCCESS;
  133     }
  134 
  135   attributeDescriptionLength = strlen (attributeDescription);
  136   attributeTypeLength = strlen (attributeType);
  137 
  138   if (attributeDescriptionLength < attributeTypeLength)
  139     {
  140       /* could not be a subtype */
  141       return NSS_NOTFOUND;
  142     }
  143 
  144   /* XXX need to copy as strtok() is destructive */
  145   attribute = strdup (attributeDescription);
  146   if (attribute == NULL)
  147     {
  148       return NSS_TRYAGAIN;
  149     }
  150 
  151 #ifndef HAVE_STRTOK_R
  152   for (p = strtok (attribute, ";"); p != NULL; p = strtok (NULL, ";"))
  153 #else
  154   for (p = strtok_r (attribute, ";", &st);
  155        p != NULL; p = strtok_r (NULL, ";", &st))
  156 #endif /* !HAVE_STRTOK_R */
  157     {
  158       char *q;
  159 
  160       if (p == attribute)
  161     {
  162       if (strcasecmp (p, attributeType) != 0)
  163         {
  164           free (attribute);
  165           return NSS_NOTFOUND;
  166         }
  167     }
  168       else if (strncasecmp (p, "range=", sizeof ("range=") - 1) == 0)
  169     {
  170       p += sizeof ("range=") - 1;
  171 
  172       q = strchr (p, '-');
  173       if (q == NULL)
  174         {
  175           free (attribute);
  176           return NSS_NOTFOUND;
  177         }
  178 
  179       *q++ = '\0';
  180 
  181       *start = strtoul (p, (char **) NULL, 10);
  182       if (strcmp (q, "*") == 0)
  183         *end = -1;
  184       else
  185         *end = strtoul (q, (char **) NULL, 10);
  186 
  187       stat = NSS_SUCCESS;
  188       break;
  189     }
  190     }
  191 
  192   free (attribute);
  193   return stat;
  194 }
  195 
  196 static NSS_STATUS
  197 do_get_range_values (LDAPMessage * e,
  198              const char *attributeType,
  199              int *start, int *end, char ***pGroupMembers)
  200 {
  201   NSS_STATUS stat = NSS_NOTFOUND;
  202   BerElement *ber = NULL;
  203   char *attribute;
  204 
  205   *pGroupMembers = NULL;
  206 
  207   for (attribute = _nss_ldap_first_attribute (e, &ber);
  208        attribute != NULL; attribute = _nss_ldap_next_attribute (e, ber))
  209     {
  210       stat = do_parse_range (attributeType, attribute, start, end);
  211       if (stat == NSS_SUCCESS)
  212     {
  213       *pGroupMembers = _nss_ldap_get_values (e, attribute);
  214       if (*pGroupMembers == NULL)
  215         {
  216           stat = NSS_NOTFOUND;
  217         }
  218       else if ((*pGroupMembers)[0] == NULL)
  219         {
  220           ldap_value_free (*pGroupMembers);
  221           *pGroupMembers = NULL;
  222           stat = NSS_NOTFOUND;
  223         }
  224     }
  225 
  226 #ifdef HAVE_LDAP_MEMFREE
  227       ldap_memfree (attribute);
  228 #endif
  229 
  230       if (stat == NSS_SUCCESS)
  231     break;
  232     }
  233 
  234   if (ber != NULL)
  235     ber_free (ber, 0);
  236 
  237   return stat;
  238 }
  239 
  240 /*
  241  * Format an attribute with description as:
  242  *  attribute;range=START-END
  243  */
  244 static NSS_STATUS
  245 do_construct_range_attribute (const char *attribute,
  246                   int start,
  247                   int end,
  248                   char **buffer,
  249                   size_t * buflen,
  250                   const char **pAttributeWithRange)
  251 {
  252   size_t len;
  253   char startbuf[32], endbuf[32];
  254 
  255   snprintf (startbuf, sizeof (startbuf), "%u", start);
  256 
  257   if (end != -1)
  258     snprintf (endbuf, sizeof (endbuf), "%u", end);
  259   else
  260     snprintf (endbuf, sizeof (endbuf), "*");
  261 
  262   len = strlen (attribute) + sizeof (";range=") - 1;
  263   len += strlen (startbuf) + 1 /* - */  + strlen (endbuf);
  264   len++;            /* \0 */
  265 
  266   if (*buflen < len)
  267     return NSS_TRYAGAIN;
  268 
  269   *pAttributeWithRange = *buffer;
  270 
  271   snprintf (*buffer, len, "%s;range=%s-%s", attribute, startbuf, endbuf);
  272 
  273   *buffer += len;
  274   *buflen -= len;
  275 
  276   return NSS_SUCCESS;
  277 }
  278 
  279 /* 
  280  * Expand group members, including nested groups
  281  */
  282 static NSS_STATUS
  283 do_parse_group_members (LDAPMessage * e,
  284             char ***pGroupMembers,
  285             size_t * pGroupMembersCount,
  286                         size_t * pGroupMembersNext,
  287             size_t * pGroupMembersBufferSize,
  288             int *pGroupMembersBufferIsMalloced,
  289             char **buffer, size_t * buflen,
  290             int *depth,
  291             struct name_list **pKnownGroups,
  292             int itemsLeft) /* traversed groups */
  293 {
  294   NSS_STATUS stat = NSS_SUCCESS;
  295   char **dnValues = NULL;
  296   char **uidValues = NULL;
  297   char **groupMembers;
  298   size_t groupMembersCount, i;
  299   char **valiter;
  300   /* support for range retrieval */
  301   const char *uniquemember_attr;
  302   const char *uniquemember_attrs[2];
  303   LDAPMessage *res = NULL;
  304   int start, end = 0;
  305   char *groupdn = NULL;
  306 
  307   uniquemember_attr = ATM (LM_GROUP, uniqueMember);
  308 
  309   uniquemember_attrs[0] = uniquemember_attr;
  310   uniquemember_attrs[1] = NULL;
  311 
  312   if (*depth > LDAP_NSS_MAXGR_DEPTH)
  313     {
  314       return NSS_NOTFOUND;
  315     }
  316 
  317   i = *pGroupMembersNext;   /* index of next member */
  318   groupMembers = *pGroupMembers;
  319 
  320   groupdn = _nss_ldap_get_dn (e);
  321   if (groupdn == NULL)
  322     {
  323       stat = NSS_NOTFOUND;
  324       goto out;
  325     }
  326 
  327   if (_nss_ldap_namelist_find (*pKnownGroups, groupdn))
  328     {
  329       stat = NSS_NOTFOUND;
  330       goto out;
  331     }
  332 
  333   /* store group DN for nested group loop detection */
  334   stat = _nss_ldap_namelist_push (pKnownGroups, groupdn);
  335   if (stat != NSS_SUCCESS)
  336     {
  337       goto out;
  338     }
  339 
  340   do
  341     {
  342       if (e == NULL)
  343     {
  344       stat = NSS_NOTFOUND;
  345       goto out;
  346     }
  347 
  348       groupMembersCount = 0;    /* number of members in this group */
  349 
  350       (void) do_get_range_values (e, uniquemember_attrs[0], &start, &end, &dnValues);
  351       if (dnValues != NULL)
  352     {
  353       groupMembersCount += ldap_count_values (dnValues);
  354     }
  355 
  356       uidValues = _nss_ldap_get_values (e, ATM (LM_GROUP, memberUid));
  357       if (uidValues != NULL)
  358     {
  359       groupMembersCount += ldap_count_values (uidValues);
  360     }
  361 
  362       /*
  363        * Check whether we need to increase the group membership buffer.
  364        * As an optimization the buffer is preferentially allocated off
  365        * the stack
  366        */
  367       if ((*pGroupMembersCount + groupMembersCount) * sizeof (char *) >=
  368       *pGroupMembersBufferSize)
  369     {
  370       *pGroupMembersBufferSize =
  371         (*pGroupMembersCount + groupMembersCount + 1) * sizeof (char *);
  372       *pGroupMembersBufferSize +=
  373         (LDAP_NSS_NGROUPS * sizeof (char *)) - 1;
  374       *pGroupMembersBufferSize -=
  375         (*pGroupMembersBufferSize %
  376          (LDAP_NSS_NGROUPS * sizeof (char *)));
  377 
  378       if (*pGroupMembersBufferIsMalloced == 0)
  379         {
  380           groupMembers = *pGroupMembers;
  381           *pGroupMembers = NULL;    /* force malloc() */
  382         }
  383 
  384       *pGroupMembers =
  385         (char **) realloc (*pGroupMembers, *pGroupMembersBufferSize);
  386       if (*pGroupMembers == NULL)
  387         {
  388           *pGroupMembersBufferIsMalloced = 0; /* don't try to free */
  389           stat = NSS_TRYAGAIN;
  390           goto out;
  391         }
  392 
  393       if (*pGroupMembersBufferIsMalloced == 0)
  394         {
  395           memcpy (*pGroupMembers, groupMembers, i * sizeof (char *));
  396           groupMembers = NULL;  /* defensive programming */
  397           *pGroupMembersBufferIsMalloced = 1;
  398         }
  399     }
  400 
  401       groupMembers = *pGroupMembers;
  402       *pGroupMembersCount += groupMembersCount;
  403 
  404       /* Parse distinguished name members */
  405       if (dnValues != NULL)
  406     {
  407       for (valiter = dnValues; *valiter != NULL; valiter++)
  408         {
  409           LDAPMessage *res;
  410           NSS_STATUS parseStat;
  411           int isNestedGroup = 0;
  412           char *uid;
  413 
  414           uid = strrchr (*valiter, '#');
  415           if (uid != NULL)
  416         {
  417           *uid = '\0';
  418         }
  419 
  420           parseStat = _nss_ldap_dn2uid (*valiter, &groupMembers[i],
  421                         buffer, buflen, &isNestedGroup,
  422                         &res);
  423           if (parseStat == NSS_SUCCESS)
  424         {
  425           if (isNestedGroup == 0)
  426             {
  427               /* just a normal user which we have flattened */
  428               i++;
  429               itemsLeft--;
  430               continue;
  431             }
  432 
  433           (*depth)++;
  434           parseStat =
  435             do_parse_group_members (_nss_ldap_first_entry (res),
  436                         &groupMembers, pGroupMembersCount, &i,
  437                         pGroupMembersBufferSize,
  438                         pGroupMembersBufferIsMalloced,
  439                         buffer, buflen, depth,
  440                         pKnownGroups, itemsLeft);
  441           (*depth)--;
  442 
  443           if (parseStat == NSS_TRYAGAIN)
  444             {
  445               stat = NSS_TRYAGAIN;
  446               goto out;
  447             }
  448 
  449           ldap_msgfree (res);
  450         }
  451           else if (parseStat == NSS_TRYAGAIN)
  452         {
  453           stat = NSS_TRYAGAIN;
  454           goto out;
  455         }
  456         }
  457     }
  458 
  459       /* Parse RFC 2307 (flat) members */
  460       if (uidValues != NULL)
  461     {
  462       for (valiter = uidValues; *valiter != NULL; valiter++)
  463         {
  464           size_t len = strlen (*valiter) + 1;
  465           if (*buflen < len)
  466         {
  467           stat = NSS_TRYAGAIN;
  468           goto out;
  469         }
  470           groupMembers[i] = *buffer;
  471           *buffer += len;
  472           *buflen -= len;
  473 
  474           memcpy (groupMembers[i++], *valiter, len);
  475         }
  476     }
  477 
  478       /* Get next range for Active Directory compat */
  479       if (end != -1)
  480     {
  481       stat = do_construct_range_attribute (uniquemember_attr,
  482                            end + 1,
  483                            -1,
  484                            buffer,
  485                            buflen,
  486                            &uniquemember_attrs[0]);
  487       if (stat == NSS_SUCCESS)
  488         {
  489           if (dnValues != NULL)
  490         {
  491           ldap_value_free (dnValues);
  492           dnValues = NULL;
  493         }
  494           if (uidValues != NULL)
  495         {
  496           ldap_value_free (uidValues);
  497           uidValues = NULL;
  498         }
  499           if (res != NULL)
  500         {
  501           ldap_msgfree (res);
  502           res = NULL;
  503         }
  504 
  505           stat = _nss_ldap_read (groupdn, uniquemember_attrs, &res);
  506           if (stat != NSS_SUCCESS)
  507         goto out;
  508 
  509           e = _nss_ldap_first_entry (res);
  510         }
  511     }
  512     }
  513   while (end != -1);
  514 
  515 out:
  516   if (dnValues != NULL)
  517     ldap_value_free (dnValues);
  518   if (uidValues != NULL)
  519     ldap_value_free (uidValues);
  520   if (res != NULL)
  521     ldap_msgfree (res);
  522   if (groupdn != NULL)
  523 #ifdef HAVE_LDAP_MEMFREE
  524     ldap_memfree (groupdn);
  525 #else
  526     free (groupdn);
  527 #endif
  528 
  529   *pGroupMembers = groupMembers;
  530   *pGroupMembersNext = i;
  531 
  532   return stat;
  533 }
  534 
  535 /*
  536  * "Fix" group membership list into caller provided buffer,
  537  * and NULL terminate.
  538 */
  539 static NSS_STATUS
  540 do_fix_group_members_buffer (char **mallocedGroupMembers,
  541                  size_t groupMembersCount,
  542                  char ***pGroupMembers,
  543                  char **buffer, size_t * buflen)
  544 {
  545   size_t len;
  546 
  547   len = (groupMembersCount + 1) * sizeof (char *);
  548 
  549   if (bytesleft (*buffer, *buflen, char *) < len)
  550     {
  551       return NSS_TRYAGAIN;
  552     }
  553 
  554   align (*buffer, *buflen, char *);
  555   *pGroupMembers = (char **) *buffer;
  556   *buffer += len;
  557   *buflen -= len;
  558 
  559   memcpy (*pGroupMembers, mallocedGroupMembers,
  560       groupMembersCount * sizeof (char *));
  561   (*pGroupMembers)[groupMembersCount] = NULL;
  562 
  563   return NSS_SUCCESS;
  564 }
  565 
  566 static NSS_STATUS
  567 _nss_ldap_parse_gr (LDAPMessage * e,
  568             ldap_state_t * pvt,
  569             void *result, char *buffer, size_t buflen)
  570 {
  571   struct group *gr = (struct group *) result;
  572   char *gid;
  573   NSS_STATUS stat;
  574   char **groupMembers;
  575   size_t groupMembersCount, groupMembersAttrCount;
  576   size_t groupMembersBufferSize;
  577   char *groupMembersBuffer[LDAP_NSS_NGROUPS];
  578   int groupMembersBufferIsMalloced;
  579   int depth;
  580   struct name_list *knownGroups = NULL;
  581 
  582   stat =
  583     _nss_ldap_assign_attrval (e, ATM (LM_GROUP, gidNumber), &gid, &buffer,
  584                   &buflen);
  585   if (stat != NSS_SUCCESS)
  586     return stat;
  587 
  588   gr->gr_gid =
  589     (*gid == '\0') ? (unsigned) GID_NOBODY : (gid_t) strtoul (gid,
  590                                   (char **) NULL,
  591                                   10);
  592 
  593   stat =
  594     _nss_ldap_getrdnvalue (e, ATM (LM_GROUP, cn), &gr->gr_name, &buffer,
  595                &buflen);
  596   if (stat != NSS_SUCCESS)
  597     return stat;
  598 
  599   stat =
  600     _nss_ldap_assign_userpassword (e, ATM (LM_GROUP, userPassword),
  601                    &gr->gr_passwd, &buffer, &buflen);
  602   if (stat != NSS_SUCCESS)
  603     return stat;
  604 
  605   if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS))
  606     {
  607       groupMembers = groupMembersBuffer;
  608       groupMembersAttrCount = 0;
  609       groupMembersCount = 0;
  610       groupMembersBufferSize = sizeof (groupMembersBuffer);
  611       groupMembersBufferIsMalloced = 0;
  612       depth = 0;
  613 
  614       stat = do_parse_group_members (e, &groupMembers,
  615                      &groupMembersAttrCount,
  616                      &groupMembersCount,
  617                      &groupMembersBufferSize,
  618                      &groupMembersBufferIsMalloced, &buffer,
  619                      &buflen, &depth, &knownGroups, 0);
  620       if (stat != NSS_SUCCESS)
  621     {
  622       if (groupMembersBufferIsMalloced)
  623         free (groupMembers);
  624       _nss_ldap_namelist_destroy (&knownGroups);
  625       return stat;
  626     }
  627 
  628       stat = do_fix_group_members_buffer (groupMembers, groupMembersCount,
  629                       &gr->gr_mem, &buffer, &buflen);
  630 
  631       if (groupMembersBufferIsMalloced)
  632     free (groupMembers);
  633       _nss_ldap_namelist_destroy (&knownGroups);
  634     }
  635   else
  636     {
  637       stat =
  638     _nss_ldap_assign_attrvals (e, ATM (LM_GROUP, memberUid), NULL,
  639                    &gr->gr_mem, &buffer, &buflen, NULL);
  640     }
  641 
  642   return stat;
  643 }
  644 
  645 /*
  646  * Add a group ID to a group list, and optionally the group IDs
  647  * of any groups to which this group belongs (RFC2307bis nested
  648  * group expansion is done by do_parse_initgroups_nested()).
  649  */
  650 static NSS_STATUS
  651 do_parse_initgroups (LDAPMessage * e,
  652              ldap_state_t * pvt, void *result,
  653              char *buffer, size_t buflen)
  654 {
  655   char **values;
  656   ssize_t i;
  657   gid_t gid;
  658   ldap_initgroups_args_t *lia = (ldap_initgroups_args_t *) result;
  659 
  660   values = _nss_ldap_get_values (e, ATM (LM_GROUP, gidNumber));
  661   if (values == NULL)
  662     {
  663       /* invalid group; skip it */
  664       return NSS_NOTFOUND;
  665     }
  666 
  667   if (values[0] == NULL)
  668     {
  669       /* invalid group; skip it */
  670       ldap_value_free (values);
  671       return NSS_NOTFOUND;
  672     }
  673 
  674 #ifdef HAVE_USERSEC_H
  675   i = strlen (values[0]);
  676   lia->grplist = realloc (lia->grplist, lia->listlen + i + 2);
  677   if (lia->grplist == NULL)
  678     {
  679       ldap_value_free (values);
  680       return NSS_TRYAGAIN;
  681     }
  682   memcpy (lia->grplist + lia->listlen, values[0], i);
  683   lia->grplist[lia->listlen + i] = ',';
  684   lia->listlen += i + 1;
  685   ldap_value_free (values);
  686 #else
  687   gid = strtoul (values[0], (char **) NULL, 10);
  688   ldap_value_free (values);
  689 
  690   if (gid == LONG_MAX && errno == ERANGE)
  691     {
  692       /* invalid group, skip it */
  693       return NSS_NOTFOUND;
  694     }
  695 
  696 # ifdef HAVE_NSSWITCH_H
  697   /* weed out duplicates; is this really our resposibility? */
  698   for (i = 0; i < lia->gbm->numgids; i++)
  699     {
  700       if (lia->gbm->gid_array[i] == (gid_t) gid)
  701     return NSS_NOTFOUND;
  702     }
  703 
  704   if (lia->gbm->numgids == lia->gbm->maxgids)
  705     {
  706       /* can't fit any more */
  707       /*
  708        * should probably return NSS_TRYAGAIN but IIRC
  709        * will send Solaris into an infinite loop XXX
  710        */
  711       return NSS_SUCCESS;
  712     }
  713 
  714   lia->gbm->gid_array[lia->gbm->numgids++] = (gid_t) gid;
  715 # else
  716   if (gid == lia->group)
  717     {
  718       /* primary group, so skip it */
  719       return NSS_NOTFOUND;
  720     }
  721 
  722   if (lia->limit > 0)
  723     {
  724       if (*(lia->start) >= lia->limit)
  725     {
  726       /* can't fit any more */
  727       return NSS_TRYAGAIN;
  728     }
  729     }
  730 
  731   if (*(lia->size) == 0)
  732     {
  733       *(lia->groups) = (gid_t *) realloc(*(lia->groups),
  734                      LDAP_NSS_NGROUPS * sizeof (gid_t));
  735       if (*(lia->groups) == NULL)
  736     {
  737       return NSS_TRYAGAIN;
  738     }
  739       *(lia->size) = LDAP_NSS_NGROUPS;
  740     }
  741   if (*(lia->start) == *(lia->size))
  742     {
  743       /* Need a bigger buffer */
  744       *(lia->groups) = (gid_t *) realloc (*(lia->groups),
  745                       2 * *(lia->size) * sizeof (gid_t));
  746       if (*(lia->groups) == NULL)
  747     {
  748       return NSS_TRYAGAIN;
  749     }
  750       *(lia->size) *= 2;
  751     }
  752   else
  753     {
  754       assert(*(lia->start) < *(lia->size));
  755     }
  756 
  757   /* weed out duplicates; is this really our responsibility? */
  758   for (i = 0; i < *(lia->start); i++)
  759     {
  760       if ((*(lia->groups))[i] == gid)
  761     {
  762       return NSS_NOTFOUND;
  763     }
  764     }
  765 
  766   /* add to group list */
  767   (*(lia->groups))[*(lia->start)] = gid;
  768   (*(lia->start)) += 1;
  769 # endif             /* HAVE_NSSWITCH_H */
  770 #endif /* HAVE_USERSEC_H */
  771 
  772   return NSS_NOTFOUND;
  773 }
  774 
  775 static NSS_STATUS
  776 do_parse_initgroups_nested (LDAPMessage * e,
  777                 ldap_state_t * pvt, void *result,
  778                 char *buffer, size_t buflen)
  779 {
  780   NSS_STATUS stat;
  781   ldap_initgroups_args_t *lia = (ldap_initgroups_args_t *) result;
  782   char **values;
  783   char *groupdn;
  784 
  785   stat = do_parse_initgroups (e, pvt, result, buffer, buflen);
  786   if (stat != NSS_NOTFOUND)
  787     {
  788       return stat;
  789     }
  790 
  791   if (!_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS))
  792     {
  793       return NSS_NOTFOUND;
  794     }
  795 
  796   if (lia->backlink != 0)
  797     {
  798       /*
  799        * Now add the GIDs of any groups of which this group is
  800        * a member.
  801        */
  802       values = _nss_ldap_get_values (e, ATM (LM_GROUP, memberOf));
  803       if (values != NULL)
  804     {
  805       NSS_STATUS stat;
  806 
  807       lia->depth++;
  808       stat = ng_chase_backlink ((const char **)values, lia);
  809       lia->depth--;
  810 
  811       ldap_value_free (values);
  812  
  813       return stat;
  814     }
  815     }
  816   else
  817     {
  818       /*
  819        * Now add the GIDs of any groups which refer to this group
  820        */
  821       groupdn = _nss_ldap_get_dn (e);
  822       if (groupdn != NULL)
  823     {
  824       NSS_STATUS stat;
  825 
  826       lia->depth++;
  827       stat = ng_chase (groupdn, lia);
  828       lia->depth--;
  829 #ifdef HAVE_LDAP_MEMFREE
  830       ldap_memfree (groupdn);
  831 #else
  832       free (groupdn);
  833 #endif
  834     }
  835     }
  836 
  837   return stat;
  838 }
  839 
  840 static NSS_STATUS
  841 ng_chase (const char *dn, ldap_initgroups_args_t * lia)
  842 {
  843   ldap_args_t a;
  844   NSS_STATUS stat;
  845   ent_context_t *ctx = NULL;
  846   const char *gidnumber_attrs[2];
  847   int erange;
  848 
  849   if (lia->depth > LDAP_NSS_MAXGR_DEPTH)
  850     return NSS_NOTFOUND;
  851 
  852   if (_nss_ldap_namelist_find (lia->known_groups, dn))
  853     return NSS_NOTFOUND;
  854 
  855   gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
  856   gidnumber_attrs[1] = NULL;
  857 
  858   LA_INIT (a);
  859   LA_STRING (a) = dn;
  860   LA_TYPE (a) = LA_TYPE_STRING;
  861 
  862   if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
  863     {
  864       return NSS_UNAVAIL;
  865     }
  866 
  867   stat = _nss_ldap_getent_ex (&a, &ctx, lia, NULL, 0,
  868                   &erange, _nss_ldap_filt_getgroupsbydn,
  869                   LM_GROUP, gidnumber_attrs,
  870                   do_parse_initgroups_nested);
  871 
  872   if (stat == NSS_SUCCESS)
  873     {
  874       stat = _nss_ldap_namelist_push (&lia->known_groups, dn);
  875     }
  876 
  877   _nss_ldap_ent_context_release (&ctx);
  878 
  879   return stat;
  880 }
  881 
  882 static NSS_STATUS
  883 ng_chase_backlink (const char ** membersOf, ldap_initgroups_args_t * lia)
  884 {
  885   ldap_args_t a;
  886   NSS_STATUS stat;
  887   ent_context_t *ctx = NULL;
  888   const char *gidnumber_attrs[3];
  889   const char **memberP;
  890   const char **filteredMembersOf; /* remove already traversed groups */
  891   size_t memberCount, i;
  892   int erange;
  893 
  894   if (lia->depth > LDAP_NSS_MAXGR_DEPTH)
  895     return NSS_NOTFOUND;
  896 
  897   for (memberCount = 0; membersOf[memberCount] != NULL; memberCount++)
  898     ;
  899 
  900   /* Build a list of membersOf values without any already traversed groups */
  901   filteredMembersOf = (const char **) malloc(sizeof(char *) * (memberCount + 1));
  902   if (filteredMembersOf == NULL)
  903     {
  904       return NSS_TRYAGAIN;
  905     }
  906 
  907   memberP = filteredMembersOf;
  908 
  909   for (i = 0; i < memberCount; i++)
  910     {
  911       if (_nss_ldap_namelist_find (lia->known_groups, membersOf[i]))
  912     continue;
  913 
  914       *memberP = membersOf[i];
  915       memberP++;
  916     }
  917 
  918   *memberP = NULL;
  919 
  920   if (filteredMembersOf[0] == NULL)
  921     {
  922       free (filteredMembersOf);
  923       return NSS_NOTFOUND;
  924     }
  925 
  926   gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
  927   gidnumber_attrs[1] = ATM (LM_GROUP, memberOf);
  928   gidnumber_attrs[2] = NULL;
  929 
  930   LA_INIT (a);
  931   LA_STRING_LIST (a) = filteredMembersOf;
  932   LA_TYPE (a) = LA_TYPE_STRING_LIST_OR;
  933 
  934   if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
  935     {
  936       free (filteredMembersOf);
  937       return NSS_UNAVAIL;
  938     }
  939 
  940   stat = _nss_ldap_getent_ex (&a, &ctx, lia, NULL, 0,
  941                   &erange, "(distinguishedName=%s)",
  942                   LM_GROUP, gidnumber_attrs,
  943                   do_parse_initgroups_nested);
  944 
  945   if (stat == NSS_SUCCESS)
  946     {
  947       NSS_STATUS stat2;
  948 
  949       for (memberP = filteredMembersOf; *memberP != NULL; memberP++)
  950     {
  951       stat2 = _nss_ldap_namelist_push (&lia->known_groups, *memberP);
  952       if (stat2 != NSS_SUCCESS)
  953         {
  954           stat = stat2;
  955           break;
  956         }
  957     }
  958     }
  959 
  960   free (filteredMembersOf);
  961 
  962   _nss_ldap_ent_context_release (&ctx);
  963 
  964   return stat;
  965 }
  966 
  967 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_NSS_H) || defined(HAVE_USERSEC_H)
  968 #ifdef HAVE_NSS_H
  969 NSS_STATUS _nss_ldap_initgroups_dyn (const char *user, gid_t group,
  970                      long int *start, long int *size,
  971                      gid_t ** groupsp, long int limit,
  972                      int *errnop);
  973 
  974 NSS_STATUS
  975 _nss_ldap_initgroups (const char *user, gid_t group, long int *start,
  976               long int *size, gid_t * groups, long int limit,
  977               int *errnop)
  978 {
  979   return (_nss_ldap_initgroups_dyn (user, group, start, size, &groups, limit,
  980                     errnop));
  981 }
  982 #endif
  983 
  984 #ifdef HAVE_NSSWITCH_H
  985 #define NSS_LDAP_INITGROUPS_FUNCTION    "_nss_ldap_getgroupsbymember_r"
  986 #elif defined(HAVE_NSS_H)
  987 #define NSS_LDAP_INITGROUPS_FUNCTION    "_nss_ldap_initgroups_dyn"
  988 #elif defined(HAVE_USERSEC_H)
  989 #define NSS_LDAP_INITGROUPS_FUNCTION    "_nss_ldap_getgrset"
  990 #endif
  991 
  992 #ifdef HAVE_NSSWITCH_H
  993 static NSS_STATUS
  994 _nss_ldap_getgroupsbymember_r (nss_backend_t * be, void *args)
  995 #elif defined(HAVE_NSS_H)
  996   NSS_STATUS
  997 _nss_ldap_initgroups_dyn (const char *user, gid_t group, long int *start,
  998               long int *size, gid_t ** groupsp, long int limit,
  999               int *errnop)
 1000 #elif defined(HAVE_USERSEC_H)
 1001 char *_nss_ldap_getgrset (char *user)
 1002 #endif
 1003 {
 1004   ldap_initgroups_args_t lia;
 1005 #ifndef HAVE_NSS_H
 1006   int erange = 0;
 1007 #endif /* HAVE_NSS_H */
 1008   char *userdn = NULL;
 1009   LDAPMessage *res, *e;
 1010   static const char *no_attrs[] = { NULL };
 1011   const char *filter;
 1012   ldap_args_t a;
 1013   NSS_STATUS stat;
 1014   ent_context_t *ctx = NULL;
 1015   const char *gidnumber_attrs[3];
 1016   ldap_map_selector_t map = LM_GROUP;
 1017 
 1018   LA_INIT (a);
 1019 #if defined(HAVE_NSS_H) || defined(HAVE_USERSEC_H)
 1020   LA_STRING (a) = user;
 1021 #else
 1022   LA_STRING (a) = ((struct nss_groupsbymem *) args)->username;
 1023 #endif /* HAVE_NSS_H || HAVE_USERSEC_H */
 1024   LA_TYPE (a) = LA_TYPE_STRING;
 1025 
 1026   debug ("==> " NSS_LDAP_INITGROUPS_FUNCTION " (user=%s)", LA_STRING (a) );
 1027 
 1028 #ifdef INITGROUPS_ROOT_ONLY
 1029   /* XXX performance hack for old versions of KDE only */
 1030   if ((getuid() != 0) && (geteuid() != 0))
 1031     return NSS_NOTFOUND;
 1032 #endif
 1033 
 1034 #ifdef HAVE_USERSEC_H
 1035   lia.grplist = NULL;
 1036   lia.listlen = 0;
 1037 #elif defined(HAVE_NSSWITCH_H)
 1038   lia.gbm = (struct nss_groupsbymem *) args;
 1039 #else
 1040   lia.group = group;
 1041   lia.start = start;
 1042   lia.size = size;
 1043   lia.groups = groupsp;
 1044   lia.limit = limit;
 1045 #endif /* HAVE_USERSEC_H */
 1046   lia.depth = 0;
 1047   lia.known_groups = NULL;
 1048 
 1049   _nss_ldap_enter ();
 1050 
 1051   /* initialize schema */
 1052   stat = _nss_ldap_init ();
 1053   if (stat != NSS_SUCCESS)
 1054     {
 1055       debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (init failed)");
 1056       _nss_ldap_leave ();
 1057 # ifdef HAVE_USERSEC_H
 1058       return NULL;
 1059 # else
 1060       return stat;
 1061 # endif             /* !HAVE_USERSEC_H */
 1062     }
 1063 
 1064   if (_nss_ldap_test_initgroups_ignoreuser (LA_STRING (a)))
 1065     {
 1066       debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (user ignored)");
 1067       _nss_ldap_leave ();
 1068       return NSS_NOTFOUND;
 1069     }
 1070 
 1071   lia.backlink = _nss_ldap_test_config_flag (NSS_LDAP_FLAGS_INITGROUPS_BACKLINK);
 1072 
 1073   if (lia.backlink != 0)
 1074     {
 1075       filter = _nss_ldap_filt_getpwnam_groupsbymember;
 1076       LA_STRING2 (a) = LA_STRING (a);
 1077       LA_TYPE (a) = LA_TYPE_STRING_AND_STRING;
 1078 
 1079       gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
 1080       gidnumber_attrs[1] = ATM (LM_GROUP, memberOf);
 1081       gidnumber_attrs[2] = NULL;
 1082 
 1083       map = LM_PASSWD;
 1084     }
 1085   else
 1086     {
 1087       if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS))
 1088     {
 1089       /* lookup the user's DN. */
 1090       stat = _nss_ldap_search_s (&a, _nss_ldap_filt_getpwnam, LM_PASSWD,
 1091                      no_attrs, 1, &res);
 1092       if (stat == NSS_SUCCESS)
 1093         {
 1094           e = _nss_ldap_first_entry (res);
 1095           if (e != NULL)
 1096         {
 1097           userdn = _nss_ldap_get_dn (e);
 1098         }
 1099           ldap_msgfree (res);
 1100         }
 1101     }
 1102       else
 1103     {
 1104       userdn = NULL;
 1105     }
 1106 
 1107       if (userdn != NULL)
 1108     {
 1109       LA_STRING2 (a) = userdn;
 1110       LA_TYPE (a) = LA_TYPE_STRING_AND_STRING;
 1111       filter = _nss_ldap_filt_getgroupsbymemberanddn;
 1112     }
 1113       else
 1114     {
 1115       filter = _nss_ldap_filt_getgroupsbymember;
 1116     }
 1117 
 1118       gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
 1119       gidnumber_attrs[1] = NULL;
 1120     }
 1121 
 1122   if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
 1123     {
 1124       debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (ent_context_init failed)");
 1125       _nss_ldap_leave ();
 1126 # ifdef HAVE_USERSEC_H
 1127       return NULL;
 1128 # else
 1129       return NSS_UNAVAIL;
 1130 # endif             /* HAVE_USERSEC_H */
 1131     }
 1132 
 1133   stat = _nss_ldap_getent_ex (&a, &ctx, (void *) &lia, NULL, 0,
 1134 #ifdef HAVE_NSS_H
 1135                   errnop,
 1136 #else
 1137                   &erange,
 1138 #endif /* HAVE_NSS_H */
 1139                   filter,
 1140                   map,
 1141                   gidnumber_attrs,
 1142                   do_parse_initgroups_nested);
 1143 
 1144   if (userdn != NULL)
 1145     {
 1146 #ifdef HAVE_LDAP_MEMFREE
 1147       ldap_memfree (userdn);
 1148 #else
 1149       free (userdn);
 1150 #endif /* HAVE_LDAP_MEMFREE */
 1151     }
 1152 
 1153   _nss_ldap_namelist_destroy (&lia.known_groups);
 1154   _nss_ldap_ent_context_release (&ctx);
 1155   _nss_ldap_leave ();
 1156 
 1157   /*
 1158    * We return NSS_NOTFOUND to force the parser to be called
 1159    * for as many entries (i.e. groups) as exist, for all
 1160    * search descriptors. So confusingly this means "success".
 1161    */
 1162   if (stat != NSS_SUCCESS && stat != NSS_NOTFOUND)
 1163     {
 1164       debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (not found)");
 1165 #ifndef HAVE_NSS_H
 1166       if (erange)
 1167     errno = ERANGE;
 1168 #endif /* HAVE_NSS_H */
 1169 #ifndef HAVE_USERSEC_H
 1170       return stat;
 1171 #else
 1172       return NULL;
 1173 #endif /* HAVE_USERSEC_H */
 1174     }
 1175 
 1176   debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (success)");
 1177 
 1178 #ifdef HAVE_NSS_H
 1179   return NSS_SUCCESS;
 1180 #elif defined(HAVE_USERSEC_H)
 1181   /* Strip last comma and terminate the string */
 1182   if (lia.grplist == NULL)
 1183     lia.grplist = strdup("");
 1184   else if (lia.listlen != 0)
 1185     lia.grplist[lia.listlen - 1] = '\0';
 1186 
 1187   return lia.grplist;
 1188 #else
 1189   /* yes, NSS_NOTFOUND is the successful errno code. see nss_dbdefs.h */
 1190   return NSS_NOTFOUND;
 1191 #endif /* HAVE_NSS_H */
 1192 }
 1193 
 1194 #endif /* HAVE_NSSWITCH_H || HAVE_NSS_H || HAVE_USERSEC_H */
 1195 
 1196 #ifdef HAVE_NSS_H
 1197 NSS_STATUS
 1198 _nss_ldap_getgrnam_r (const char *name,
 1199               struct group * result,
 1200               char *buffer, size_t buflen, int *errnop)
 1201 {
 1202   LOOKUP_NAME (name, result, buffer, buflen, errnop, _nss_ldap_filt_getgrnam,
 1203            LM_GROUP, _nss_ldap_parse_gr, LDAP_NSS_BUFLEN_GROUP);
 1204 }
 1205 #elif defined(HAVE_NSSWITCH_H)
 1206 static NSS_STATUS
 1207 _nss_ldap_getgrnam_r (nss_backend_t * be, void *args)
 1208 {
 1209   LOOKUP_NAME (args, _nss_ldap_filt_getgrnam, LM_GROUP, _nss_ldap_parse_gr,
 1210            LDAP_NSS_BUFLEN_GROUP);
 1211 }
 1212 #endif
 1213 
 1214 #ifdef HAVE_NSS_H
 1215 NSS_STATUS
 1216 _nss_ldap_getgrgid_r (gid_t gid,
 1217               struct group *result,
 1218               char *buffer, size_t buflen, int *errnop)
 1219 {
 1220   LOOKUP_NUMBER (gid, result, buffer, buflen, errnop, _nss_ldap_filt_getgrgid,
 1221          LM_GROUP, _nss_ldap_parse_gr, LDAP_NSS_BUFLEN_GROUP);
 1222 }
 1223 #elif defined(HAVE_NSSWITCH_H)
 1224 static NSS_STATUS
 1225 _nss_ldap_getgrgid_r (nss_backend_t * be, void *args)
 1226 {
 1227   LOOKUP_NUMBER (args, key.gid, _nss_ldap_filt_getgrgid, LM_GROUP,
 1228          _nss_ldap_parse_gr, LDAP_NSS_BUFLEN_GROUP);
 1229 }
 1230 #endif
 1231 
 1232 #if defined(HAVE_NSS_H)
 1233 NSS_STATUS _nss_ldap_setgrent (void)
 1234 {
 1235   LOOKUP_SETENT (gr_context);
 1236 }
 1237 #elif defined(HAVE_NSSWITCH_H)
 1238 static NSS_STATUS
 1239 _nss_ldap_setgrent_r (nss_backend_t * gr_context, void *args)
 1240 {
 1241   LOOKUP_SETENT (gr_context);
 1242 }
 1243 #endif
 1244 
 1245 #if defined(HAVE_NSS_H)
 1246 NSS_STATUS _nss_ldap_endgrent (void)
 1247 {
 1248   LOOKUP_ENDENT (gr_context);
 1249 }
 1250 #elif defined(HAVE_NSSWITCH_H)
 1251 static NSS_STATUS
 1252 _nss_ldap_endgrent_r (nss_backend_t * gr_context, void *args)
 1253 {
 1254   LOOKUP_ENDENT (gr_context);
 1255 }
 1256 #endif
 1257 
 1258 #ifdef HAVE_NSS_H
 1259 NSS_STATUS
 1260 _nss_ldap_getgrent_r (struct group *result,
 1261               char *buffer, size_t buflen, int *errnop)
 1262 {
 1263   LOOKUP_GETENT (gr_context, result, buffer, buflen, errnop,
 1264          _nss_ldap_filt_getgrent, LM_GROUP, _nss_ldap_parse_gr,
 1265          LDAP_NSS_BUFLEN_GROUP);
 1266 }
 1267 #elif defined(HAVE_NSSWITCH_H)
 1268 static NSS_STATUS
 1269 _nss_ldap_getgrent_r (nss_backend_t * gr_context, void *args)
 1270 {
 1271   LOOKUP_GETENT (args, gr_context, _nss_ldap_filt_getgrent, LM_GROUP,
 1272          _nss_ldap_parse_gr, LDAP_NSS_BUFLEN_GROUP);
 1273 }
 1274 #endif
 1275 
 1276 #ifdef HAVE_NSSWITCH_H
 1277 static NSS_STATUS
 1278 _nss_ldap_group_destr (nss_backend_t * gr_context, void *args)
 1279 {
 1280   return _nss_ldap_default_destr (gr_context, args);
 1281 }
 1282 
 1283 static nss_backend_op_t group_ops[] = {
 1284   _nss_ldap_group_destr,
 1285   _nss_ldap_endgrent_r,
 1286   _nss_ldap_setgrent_r,
 1287   _nss_ldap_getgrent_r,
 1288   _nss_ldap_getgrnam_r,
 1289   _nss_ldap_getgrgid_r,
 1290   _nss_ldap_getgroupsbymember_r
 1291 };
 1292 
 1293 nss_backend_t *
 1294 _nss_ldap_group_constr (const char *db_name,
 1295             const char *src_name, const char *cfg_args)
 1296 {
 1297   nss_ldap_backend_t *be;
 1298 
 1299   if (!(be = (nss_ldap_backend_t *) malloc (sizeof (*be))))
 1300     return NULL;
 1301 
 1302   be->ops = group_ops;
 1303   be->n_ops = sizeof (group_ops) / sizeof (nss_backend_op_t);
 1304 
 1305   /* a NOOP at the moment */
 1306   if (_nss_ldap_default_constr (be) != NSS_SUCCESS)
 1307     return NULL;
 1308 
 1309   return (nss_backend_t *) be;
 1310 }
 1311 
 1312 
 1313 #endif /* !HAVE_NSS_H */
 1314 
 1315 #ifdef HAVE_IRS_H
 1316 #include "irs-grp.c"
 1317 #endif