(_nss_netgroup_parseline): Don't panic if setnetgrent wasn't called
[kopensolaris-gnu/glibc.git] / nss / nss_files / files-netgrp.c
1 /* Netgroup file parser in nss_files modules.
2    Copyright (C) 1996, 1997 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
6    The GNU C 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 GNU C 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 GNU C 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 #include <ctype.h>
22 #include <errno.h>
23 #include <netdb.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "nsswitch.h"
28 #include "netgroup.h"
29
30 #define DATAFILE        "/etc/netgroup"
31
32
33 #define EXPAND(needed)                                                        \
34   do                                                                          \
35     {                                                                         \
36       size_t old_cursor = result->cursor - result->data;                      \
37                                                                               \
38       result->data_size += 512 > 2 * needed ? 512 : 2 * needed;               \
39       result->data = realloc (result->data, result->data_size);               \
40                                                                               \
41       if (result->data == NULL)                                               \
42         {                                                                     \
43           status = NSS_STATUS_UNAVAIL;                                        \
44           goto the_end;                                                       \
45         }                                                                     \
46                                                                               \
47       result->cursor = result->data + old_cursor;                             \
48     }                                                                         \
49   while (0)
50
51
52 enum nss_status
53 _nss_files_setnetgrent (const char *group, struct __netgrent *result)
54 {
55   FILE *fp;
56   enum nss_status status;
57
58   if (group[0] == '\0')
59     return NSS_STATUS_UNAVAIL;
60
61   /* Find the netgroups file and open it.  */
62   fp = fopen (DATAFILE, "r");
63   if (fp == NULL)
64     status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
65   else
66     {
67       /* Read the file line by line and try to find the description
68          GROUP.  We must take care for long lines.  */
69       char *line = NULL;
70       size_t line_len = 0;
71       const ssize_t group_len = strlen (group);
72
73       status = NSS_STATUS_NOTFOUND;
74       result->cursor = result->data;
75
76       while (!feof (fp))
77         {
78           ssize_t curlen = getline (&line, &line_len, fp);
79           int found;
80
81           if (curlen < 0)
82             {
83               status = NSS_STATUS_NOTFOUND;
84               break;
85             }
86
87           found = (curlen > group_len && strncmp (line, group, group_len) == 0
88                    && isspace (line[group_len]));
89
90           /* Read the whole line (including continuation) and store it
91              if FOUND in nonzero.  Otherwise we don't need it.  */
92           if (found)
93             {
94               /* Store the data from the first line.  */
95               EXPAND (curlen - group_len);
96               memcpy (result->cursor, &line[group_len + 1],
97                       curlen - group_len);
98               result->cursor += (curlen - group_len) - 1;
99             }
100
101           while (line[curlen - 1] == '\n' && line[curlen - 2] == '\\')
102             {
103               /* Yes, we have a continuation line.  */
104               if (found)
105                 /* Remove these characters from the stored line.  */
106                 result->cursor -= 2;
107
108               /* Get next line.  */
109               curlen = getline (&line, &line_len, fp);
110               if (curlen <= 0)
111                 break;
112
113               if (found)
114                 {
115                   /* Make sure we have enough room.  */
116                   EXPAND (1 + curlen + 1);
117
118                   /* Add separator in case next line starts immediately.  */
119                   *result->cursor++ = ' ';
120
121                   /* Copy new line.  */
122                   memcpy (result->cursor, line, curlen + 1);
123                   result->cursor += curlen;
124                 }
125             }
126
127           if (found)
128             {
129               /* Now we have read the line.  */
130               status = NSS_STATUS_SUCCESS;
131               result->cursor = result->data;
132               result->first = 1;
133               break;
134             }
135         }
136
137     the_end:
138       /* We don't need the file and the line buffer anymore.  */
139       free (line);
140       fclose (fp);
141     }
142
143   return status;
144 }
145
146
147 int
148 _nss_files_endnetgrent (struct __netgrent *result)
149 {
150   /* Free allocated memory for data if some is present.  */
151   if (result->data != NULL)
152     {
153       free (result->data);
154       result->data = NULL;
155       result->data_size = 0;
156       result->cursor = NULL;
157     }
158
159   return NSS_STATUS_SUCCESS;
160 }
161
162
163 enum nss_status
164 _nss_netgroup_parseline (char **cursor, struct __netgrent *result,
165                          char *buffer, int buflen)
166 {
167   enum nss_status status;
168   const char *host, *user, *domain;
169   char *cp = *cursor;
170
171   /* Some sanity checks.  */
172   if (cp == NULL)
173     return NSS_STATUS_NOTFOUND;
174
175   /* First skip leading spaces.  */
176   while (isspace (*cp))
177     ++cp;
178
179   if (*cp != '(')
180     {
181       /* We have a list of other netgroups.  */
182       char *name = cp;
183
184       while (*cp != '\0' && ! isspace (*cp))
185         ++cp;
186
187       if (name != cp)
188         {
189           /* It is another netgroup name.  */
190           int last = *cp == '\0';
191
192           result->type = group_val;
193           result->val.group = name;
194           *cp = '\0';
195           if (! last)
196             ++cp;
197           *cursor = cp;
198           result->first = 0;
199
200           return NSS_STATUS_SUCCESS;
201         }
202
203       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
204     }
205
206   /* Match host name.  */
207   host = ++cp;
208   while (*cp != ',')
209     if (*cp++ == '\0')
210       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
211
212   /* Match user name.  */
213   user = ++cp;
214   while (*cp != ',')
215     if (*cp++ == '\0')
216       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
217
218   /* Match domain name.  */
219   domain = ++cp;
220   while (*cp != ')')
221     if (*cp++ == '\0')
222       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
223   ++cp;
224
225
226   /* When we got here we have found an entry.  Before we can copy it
227      to the private buffer we have to make sure it is big enough.  */
228   if (cp - host > buflen)
229     {
230       __set_errno (ERANGE);
231       status = NSS_STATUS_UNAVAIL;
232     }
233   else
234     {
235       memcpy (buffer, host, cp - host);
236       result->type = triple_val;
237
238       buffer[(user - host) - 1] = '\0';
239       result->val.triple.host = *host == ',' ? NULL : buffer;
240
241       buffer[(domain - host) - 1] = '\0';
242       result->val.triple.user = *user == ',' ? NULL : buffer + (user - host);
243
244       buffer[(cp - host) - 1] = '\0';
245       result->val.triple.domain =
246         *domain == ')' ? NULL : buffer + (domain - host);
247
248       status = NSS_STATUS_SUCCESS;
249
250       /* Remember where we stopped reading.  */
251       *cursor = cp;
252
253       result->first = 0;
254     }
255
256   return status;
257 }
258
259
260 enum nss_status
261 _nss_files_getnetgrent_r (struct __netgrent *result, char *buffer, int buflen)
262 {
263   enum nss_status status;
264
265   status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen);
266
267   return status;
268 }