5f8b9398d8799e274486b1f7e87e363eddbd1e25
[platform/upstream/glibc.git] / nss / nss_files / files-netgrp.c
1 /* Netgroup file parser in nss_files modules.
2    Copyright (C) 1996 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 netxt 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 static 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     /* User bug.  setnetgrent() wasn't called before.  */
174     abort ();
175
176   /* First skip leading spaces.  */
177   while (isspace (*cp))
178     ++cp;
179
180   if (*cp != '(')
181     {
182       /* We have a list of other netgroups.  */
183       char *name = cp;
184
185       while (*cp != '\0' && ! isspace (*cp))
186         ++cp;
187
188       if (name != cp)
189         {
190           /* It is another netgroup name.  */
191           int last = *cp == '\0';
192
193           result->type = group_val;
194           result->val.group = name;
195           *cp = '\0';
196           if (! last)
197             ++cp;
198           *cursor = cp;
199           result->first = 0;
200
201           return NSS_STATUS_SUCCESS;
202         }
203
204       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
205     }
206
207   /* Match host name.  */
208   host = ++cp;
209   while (*cp != ',')
210     if (*cp++ == '\0')
211       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
212
213   /* Match user name.  */
214   user = ++cp;
215   while (*cp != ',')
216     if (*cp++ == '\0')
217       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
218
219   /* Match domain name.  */
220   domain = ++cp;
221   while (*cp != ')')
222     if (*cp++ == '\0')
223       return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
224   ++cp;
225
226
227   /* When we got here we have found an entry.  Before we can copy it
228      to the private buffer we have to make sure it is big enough.  */
229   if (cp - host > buflen)
230     {
231       __set_errno (ERANGE);
232       status = NSS_STATUS_UNAVAIL;
233     }
234   else
235     {
236       memcpy (buffer, host, cp - host);
237       result->type = triple_val;
238
239       buffer[(user - host) - 1] = '\0';
240       result->val.triple.host = *host == ',' ? NULL : buffer;
241
242       buffer[(domain - host) - 1] = '\0';
243       result->val.triple.user = *user == ',' ? NULL : buffer + (user - host);
244
245       buffer[(cp - host) - 1] = '\0';
246       result->val.triple.domain =
247         *domain == ')' ? NULL : buffer + (domain - host);
248
249       status = NSS_STATUS_SUCCESS;
250
251       /* Rememember where we stopped reading.  */
252       *cursor = cp;
253
254       result->first = 0;
255     }
256
257   return status;
258 }
259
260
261 enum nss_status
262 _nss_files_getnetgrent_r (struct __netgrent *result, char *buffer, int buflen)
263 {
264   enum nss_status status;
265
266   status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen);
267
268   return status;
269 }