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