Back to index

glibc  2.9
hesiod-grp.c
Go to the documentation of this file.
00001 /* Copyright (C) 1997, 1999, 2000, 2002 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <ctype.h>
00021 #include <errno.h>
00022 #include <grp.h>
00023 #include <hesiod.h>
00024 #include <nss.h>
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <sys/param.h>
00029 
00030 #include "nss_hesiod.h"
00031 
00032 /* Get the declaration of the parser function.  */
00033 #define ENTNAME grent
00034 #define STRUCTURE group
00035 #define EXTERN_PARSER
00036 #include <nss/nss_files/files-parse.c>
00037 
00038 enum nss_status
00039 _nss_hesiod_setgrent (int stayopen)
00040 {
00041   return NSS_STATUS_SUCCESS;
00042 }
00043 
00044 enum nss_status
00045 _nss_hesiod_endgrent (void)
00046 {
00047   return NSS_STATUS_SUCCESS;
00048 }
00049 
00050 static enum nss_status
00051 lookup (const char *name, const char *type, struct group *grp,
00052        char *buffer, size_t buflen, int *errnop)
00053 {
00054   struct parser_data *data = (void *) buffer;
00055   size_t linebuflen;
00056   void *context;
00057   char **list;
00058   int parse_res;
00059   size_t len;
00060   int olderr = errno;
00061 
00062   context = _nss_hesiod_init ();
00063   if (context == NULL)
00064     return NSS_STATUS_UNAVAIL;
00065 
00066   list = hesiod_resolve (context, name, type);
00067   if (list == NULL)
00068     {
00069       int err = errno;
00070       hesiod_end (context);
00071       __set_errno (olderr);
00072       return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
00073     }
00074 
00075   linebuflen = buffer + buflen - data->linebuffer;
00076   len = strlen (*list) + 1;
00077   if (linebuflen < len)
00078     {
00079       hesiod_free_list (context, list);
00080       hesiod_end (context);
00081       *errnop = ERANGE;
00082       return NSS_STATUS_TRYAGAIN;
00083     }
00084 
00085   memcpy (data->linebuffer, *list, len);
00086   hesiod_free_list (context, list);
00087   hesiod_end (context);
00088 
00089   parse_res = _nss_files_parse_grent (buffer, grp, data, buflen, errnop);
00090   if (parse_res < 1)
00091     {
00092       __set_errno (olderr);
00093       return parse_res == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
00094     }
00095 
00096   return NSS_STATUS_SUCCESS;
00097 }
00098 
00099 enum nss_status
00100 _nss_hesiod_getgrnam_r (const char *name, struct group *grp,
00101                      char *buffer, size_t buflen, int *errnop)
00102 {
00103   return lookup (name, "group", grp, buffer, buflen, errnop);
00104 }
00105 
00106 enum nss_status
00107 _nss_hesiod_getgrgid_r (gid_t gid, struct group *grp,
00108                      char *buffer, size_t buflen, int *errnop)
00109 {
00110   char gidstr[21];   /* We will probably never have a gid_t with more
00111                         than 64 bits.  */
00112 
00113   snprintf (gidstr, sizeof gidstr, "%d", gid);
00114 
00115   return lookup (gidstr, "gid", grp, buffer, buflen, errnop);
00116 }
00117 
00118 static int
00119 internal_gid_in_list (const gid_t *list, const gid_t g, long int len)
00120 {
00121   while (len > 0)
00122     {
00123       if (*list == g)
00124        return 1;
00125       --len;
00126       ++list;
00127     }
00128   return 0;
00129 }
00130 
00131 static enum nss_status
00132 internal_gid_from_group (void *context, const char *groupname, gid_t *group)
00133 {
00134   char **grp_res;
00135   enum nss_status status = NSS_STATUS_NOTFOUND;
00136 
00137   grp_res = hesiod_resolve (context, groupname, "group");
00138   if (grp_res != NULL && *grp_res != NULL)
00139     {
00140       char *p = *grp_res;
00141 
00142       while (*p != '\0' && *p != ':')
00143        ++p;
00144       while (*p != '\0' && *p == ':')
00145        ++p;
00146       while (*p != '\0' && *p != ':')
00147        ++p;
00148       while (*p != '\0' && *p == ':')
00149        ++p;
00150       if (*p == ':')
00151        {
00152          char *endp;
00153          char *q = ++p;
00154          long int val;
00155 
00156          q = p;
00157          while (*q != '\0' && *q != ':')
00158            ++q;
00159 
00160          val = strtol (p, &endp, 10);
00161          if (sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
00162            {
00163              *group = val;
00164              if (endp == q && endp != p)
00165               status = NSS_STATUS_SUCCESS;
00166            }
00167         }
00168       hesiod_free_list (context, grp_res);
00169     }
00170   return status;
00171 }
00172 
00173 enum nss_status
00174 _nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start,
00175                          long int *size, gid_t **groupsp, long int limit,
00176                          int *errnop)
00177 {
00178   enum nss_status status = NSS_STATUS_SUCCESS;
00179   char **list = NULL;
00180   char *p;
00181   void *context;
00182   gid_t *groups = *groupsp;
00183   int save_errno;
00184 
00185   context = _nss_hesiod_init ();
00186   if (context == NULL)
00187     return NSS_STATUS_UNAVAIL;
00188 
00189   list = hesiod_resolve (context, user, "grplist");
00190 
00191   if (list == NULL)
00192     {
00193       hesiod_end (context);
00194       return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
00195     }
00196 
00197   if (!internal_gid_in_list (groups, group, *start))
00198     {
00199       if (__builtin_expect (*start == *size, 0))
00200        {
00201          /* Need a bigger buffer.  */
00202          gid_t *newgroups;
00203          long int newsize;
00204 
00205          if (limit > 0 && *size == limit)
00206            /* We reached the maximum.  */
00207            goto done;
00208 
00209          if (limit <= 0)
00210            newsize = 2 * *size;
00211          else
00212            newsize = MIN (limit, 2 * *size);
00213 
00214          newgroups = realloc (groups, newsize * sizeof (*groups));
00215          if (newgroups == NULL)
00216            goto done;
00217          *groupsp = groups = newgroups;
00218          *size = newsize;
00219        }
00220 
00221       groups[(*start)++] = group;
00222     }
00223 
00224   save_errno = errno;
00225 
00226   p = *list;
00227   while (*p != '\0')
00228     {
00229       char *endp;
00230       char *q;
00231       long int val;
00232 
00233       status = NSS_STATUS_NOTFOUND;
00234 
00235       q = p;
00236       while (*q != '\0' && *q != ':' && *q != ',')
00237        ++q;
00238 
00239       if (*q != '\0')
00240        *q++ = '\0';
00241 
00242       __set_errno (0);
00243       val = strtol (p, &endp, 10);
00244       /* Test whether the number is representable in a variable of
00245          type `gid_t'.  If not ignore the number.  */
00246       if ((sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
00247          && errno == 0)
00248        {
00249          if (*endp == '\0' && endp != p)
00250            {
00251              group = val;
00252              status = NSS_STATUS_SUCCESS;
00253            }
00254          else
00255            status = internal_gid_from_group (context, p, &group);
00256 
00257          if (status == NSS_STATUS_SUCCESS
00258              && !internal_gid_in_list (groups, group, *start))
00259            {
00260              if (__builtin_expect (*start == *size, 0))
00261               {
00262                 /* Need a bigger buffer.  */
00263                 gid_t *newgroups;
00264                 long int newsize;
00265 
00266                 if (limit > 0 && *size == limit)
00267                   /* We reached the maximum.  */
00268                   goto done;
00269 
00270                 if (limit <= 0)
00271                   newsize = 2 * *size;
00272                 else
00273                   newsize = MIN (limit, 2 * *size);
00274 
00275                 newgroups = realloc (groups, newsize * sizeof (*groups));
00276                 if (newgroups == NULL)
00277                   goto done;
00278                 *groupsp = groups = newgroups;
00279                 *size = newsize;
00280               }
00281 
00282              groups[(*start)++] = group;
00283            }
00284        }
00285 
00286       p = q;
00287     }
00288 
00289   __set_errno (save_errno);
00290 
00291  done:
00292   hesiod_free_list (context, list);
00293   hesiod_end (context);
00294 
00295   return NSS_STATUS_SUCCESS;
00296 }