Back to index

glibc  2.9
files-netgrp.c
Go to the documentation of this file.
00001 /* Netgroup file parser in nss_files modules.
00002    Copyright (C) 1996, 1997, 2000, 2004, 2005 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <ctype.h>
00022 #include <errno.h>
00023 #include <netdb.h>
00024 #include <stdio.h>
00025 #include <stdio_ext.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include "nsswitch.h"
00029 #include "netgroup.h"
00030 
00031 #define DATAFILE     "/etc/netgroup"
00032 
00033 libnss_files_hidden_proto (_nss_files_endnetgrent)
00034 
00035 #define EXPAND(needed)                                                      \
00036   do                                                                 \
00037     {                                                                \
00038       size_t old_cursor = result->cursor - result->data;                    \
00039       void *old_data = result->data;                                        \
00040                                                                      \
00041       result->data_size += 512 > 2 * needed ? 512 : 2 * needed;                    \
00042       result->data = realloc (result->data, result->data_size);                    \
00043                                                                      \
00044       if (result->data == NULL)                                             \
00045        {                                                             \
00046          free (old_data);                                            \
00047          status = NSS_STATUS_UNAVAIL;                                       \
00048          goto the_end;                                                      \
00049        }                                                             \
00050                                                                      \
00051       result->cursor = result->data + old_cursor;                           \
00052     }                                                                \
00053   while (0)
00054 
00055 
00056 enum nss_status
00057 _nss_files_setnetgrent (const char *group, struct __netgrent *result)
00058 {
00059   FILE *fp;
00060   enum nss_status status;
00061 
00062   if (group[0] == '\0')
00063     return NSS_STATUS_UNAVAIL;
00064 
00065   /* Find the netgroups file and open it.  */
00066   fp = fopen (DATAFILE, "r");
00067   if (fp == NULL)
00068     status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
00069   else
00070     {
00071       /* Read the file line by line and try to find the description
00072         GROUP.  We must take care for long lines.  */
00073       char *line = NULL;
00074       size_t line_len = 0;
00075       const ssize_t group_len = strlen (group);
00076 
00077       status = NSS_STATUS_NOTFOUND;
00078       result->cursor = result->data;
00079 
00080       __fsetlocking (fp, FSETLOCKING_BYCALLER);
00081 
00082       while (!feof_unlocked (fp))
00083        {
00084          ssize_t curlen = getline (&line, &line_len, fp);
00085          int found;
00086 
00087          if (curlen < 0)
00088            {
00089              status = NSS_STATUS_NOTFOUND;
00090              break;
00091            }
00092 
00093          found = (curlen > group_len && strncmp (line, group, group_len) == 0
00094                  && isspace (line[group_len]));
00095 
00096          /* Read the whole line (including continuation) and store it
00097             if FOUND in nonzero.  Otherwise we don't need it.  */
00098          if (found)
00099            {
00100              /* Store the data from the first line.  */
00101              EXPAND (curlen - group_len);
00102              memcpy (result->cursor, &line[group_len + 1],
00103                     curlen - group_len);
00104              result->cursor += (curlen - group_len) - 1;
00105            }
00106 
00107          while (line[curlen - 1] == '\n' && line[curlen - 2] == '\\')
00108            {
00109              /* Yes, we have a continuation line.  */
00110              if (found)
00111               /* Remove these characters from the stored line.  */
00112               result->cursor -= 2;
00113 
00114              /* Get next line.  */
00115              curlen = getline (&line, &line_len, fp);
00116              if (curlen <= 0)
00117               break;
00118 
00119              if (found)
00120               {
00121                 /* Make sure we have enough room.  */
00122                 EXPAND (1 + curlen + 1);
00123 
00124                 /* Add separator in case next line starts immediately.  */
00125                 *result->cursor++ = ' ';
00126 
00127                 /* Copy new line.  */
00128                 memcpy (result->cursor, line, curlen + 1);
00129                 result->cursor += curlen;
00130               }
00131            }
00132 
00133          if (found)
00134            {
00135              /* Now we have read the line.  */
00136              status = NSS_STATUS_SUCCESS;
00137              result->cursor = result->data;
00138              result->first = 1;
00139              break;
00140            }
00141        }
00142 
00143     the_end:
00144       /* We don't need the file and the line buffer anymore.  */
00145       free (line);
00146       fclose (fp);
00147 
00148       if (status != NSS_STATUS_SUCCESS)
00149        _nss_files_endnetgrent (result);
00150     }
00151 
00152   return status;
00153 }
00154 
00155 
00156 enum nss_status
00157 _nss_files_endnetgrent (struct __netgrent *result)
00158 {
00159   /* Free allocated memory for data if some is present.  */
00160   free (result->data);
00161   result->data = NULL;
00162   result->data_size = 0;
00163   result->cursor = NULL;
00164   return NSS_STATUS_SUCCESS;
00165 }
00166 libnss_files_hidden_def (_nss_files_endnetgrent)
00167 
00168 static char *
00169 strip_whitespace (char *str)
00170 {
00171   char *cp = str;
00172 
00173   /* Skip leading spaces.  */
00174   while (isspace (*cp))
00175     cp++;
00176 
00177   str = cp;
00178   while (*cp != '\0' && ! isspace(*cp))
00179     cp++;
00180 
00181   /* Null-terminate, stripping off any trailing spaces.  */
00182   *cp = '\0';
00183 
00184   return *str == '\0' ? NULL : str;
00185 }
00186 
00187 enum nss_status
00188 _nss_netgroup_parseline (char **cursor, struct __netgrent *result,
00189                       char *buffer, size_t buflen, int *errnop)
00190 {
00191   enum nss_status status;
00192   const char *host, *user, *domain;
00193   char *cp = *cursor;
00194 
00195   /* Some sanity checks.  */
00196   if (cp == NULL)
00197     return NSS_STATUS_NOTFOUND;
00198 
00199   /* First skip leading spaces.  */
00200   while (isspace (*cp))
00201     ++cp;
00202 
00203   if (*cp != '(')
00204     {
00205       /* We have a list of other netgroups.  */
00206       char *name = cp;
00207 
00208       while (*cp != '\0' && ! isspace (*cp))
00209        ++cp;
00210 
00211       if (name != cp)
00212        {
00213          /* It is another netgroup name.  */
00214          int last = *cp == '\0';
00215 
00216          result->type = group_val;
00217          result->val.group = name;
00218          *cp = '\0';
00219          if (! last)
00220            ++cp;
00221          *cursor = cp;
00222          result->first = 0;
00223 
00224          return NSS_STATUS_SUCCESS;
00225        }
00226 
00227       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
00228     }
00229 
00230   /* Match host name.  */
00231   host = ++cp;
00232   while (*cp != ',')
00233     if (*cp++ == '\0')
00234       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
00235 
00236   /* Match user name.  */
00237   user = ++cp;
00238   while (*cp != ',')
00239     if (*cp++ == '\0')
00240       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
00241 
00242   /* Match domain name.  */
00243   domain = ++cp;
00244   while (*cp != ')')
00245     if (*cp++ == '\0')
00246       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
00247   ++cp;
00248 
00249 
00250   /* When we got here we have found an entry.  Before we can copy it
00251      to the private buffer we have to make sure it is big enough.  */
00252   if (cp - host > buflen)
00253     {
00254       *errnop = ERANGE;
00255       status = NSS_STATUS_UNAVAIL;
00256     }
00257   else
00258     {
00259       memcpy (buffer, host, cp - host);
00260       result->type = triple_val;
00261 
00262       buffer[(user - host) - 1] = '\0';   /* Replace ',' with '\0'.  */
00263       result->val.triple.host = strip_whitespace (buffer);
00264 
00265       buffer[(domain - host) - 1] = '\0'; /* Replace ',' with '\0'.  */
00266       result->val.triple.user = strip_whitespace (buffer + (user - host));
00267 
00268       buffer[(cp - host) - 1] = '\0'; /* Replace ')' with '\0'.  */
00269       result->val.triple.domain = strip_whitespace (buffer + (domain - host));
00270 
00271       status = NSS_STATUS_SUCCESS;
00272 
00273       /* Remember where we stopped reading.  */
00274       *cursor = cp;
00275 
00276       result->first = 0;
00277     }
00278 
00279   return status;
00280 }
00281 libnss_files_hidden_def (_nss_netgroup_parseline)
00282 
00283 
00284 enum nss_status
00285 _nss_files_getnetgrent_r (struct __netgrent *result, char *buffer,
00286                        size_t buflen, int *errnop)
00287 {
00288   enum nss_status status;
00289 
00290   status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen,
00291                                 errnop);
00292 
00293   return status;
00294 }