Initial import from FreeBSD RELENG_4:
[dragonfly.git] / libexec / revnetgroup / parse_netgroup.c
1 /*
2  * Copyright (c) 1992, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #ifndef lint
38 static const char rcsid[] =
39   "$FreeBSD: src/libexec/revnetgroup/parse_netgroup.c,v 1.7 1999/08/28 00:09:48 peter Exp $";
40 #endif /* not lint */
41
42 /*
43  * This is a specially hacked-up version of getnetgrent.c used to parse
44  * data from the stored hash table of netgroup info rather than from a
45  * file. It's used mainly for the parse_netgroup() function. All the YP
46  * stuff and file support has been stripped out since it isn't needed.
47  */
48
49 #include <stdio.h>
50 #include <strings.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include "hash.h"
54
55 /*
56  * Static Variables and functions used by setnetgrent(), getnetgrent() and
57  * __endnetgrent().
58  * There are two linked lists:
59  * - linelist is just used by setnetgrent() to parse the net group file via.
60  *   parse_netgrp()
61  * - netgrp is the list of entries for the current netgroup
62  */
63 struct linelist {
64         struct linelist *l_next;        /* Chain ptr. */
65         int             l_parsed;       /* Flag for cycles */
66         char            *l_groupname;   /* Name of netgroup */
67         char            *l_line;        /* Netgroup entrie(s) to be parsed */
68 };
69
70 struct netgrp {
71         struct netgrp   *ng_next;       /* Chain ptr */
72         char            *ng_str[3];     /* Field pointers, see below */
73 };
74 #define NG_HOST         0       /* Host name */
75 #define NG_USER         1       /* User name */
76 #define NG_DOM          2       /* and Domain name */
77
78 static struct linelist  *linehead = (struct linelist *)0;
79 static struct netgrp    *nextgrp = (struct netgrp *)0;
80 static struct {
81         struct netgrp   *gr;
82         char            *grname;
83 } grouphead = {
84         (struct netgrp *)0,
85         (char *)0,
86 };
87 static int parse_netgrp();
88 static struct linelist *read_for_group();
89 void __setnetgrent(), __endnetgrent();
90 int __getnetgrent();
91 extern struct group_entry *gtable[];
92
93 /*
94  * setnetgrent()
95  * Parse the netgroup file looking for the netgroup and build the list
96  * of netgrp structures. Let parse_netgrp() and read_for_group() do
97  * most of the work.
98  */
99 void
100 __setnetgrent(group)
101         char *group;
102 {
103         /* Sanity check */
104
105         if (group == NULL || !strlen(group))
106                 return;
107
108         if (grouphead.gr == (struct netgrp *)0 ||
109                 strcmp(group, grouphead.grname)) {
110                 __endnetgrent();
111                 if (parse_netgrp(group))
112                         __endnetgrent();
113                 else {
114                         grouphead.grname = (char *)
115                                 malloc(strlen(group) + 1);
116                         strcpy(grouphead.grname, group);
117                 }
118         }
119         nextgrp = grouphead.gr;
120 }
121
122 /*
123  * Get the next netgroup off the list.
124  */
125 int
126 __getnetgrent(hostp, userp, domp)
127         char **hostp, **userp, **domp;
128 {
129         if (nextgrp) {
130                 *hostp = nextgrp->ng_str[NG_HOST];
131                 *userp = nextgrp->ng_str[NG_USER];
132                 *domp = nextgrp->ng_str[NG_DOM];
133                 nextgrp = nextgrp->ng_next;
134                 return (1);
135         }
136         return (0);
137 }
138
139 /*
140  * __endnetgrent() - cleanup
141  */
142 void
143 __endnetgrent()
144 {
145         register struct linelist *lp, *olp;
146         register struct netgrp *gp, *ogp;
147
148         lp = linehead;
149         while (lp) {
150                 olp = lp;
151                 lp = lp->l_next;
152                 free(olp->l_groupname);
153                 free(olp->l_line);
154                 free((char *)olp);
155         }
156         linehead = (struct linelist *)0;
157         if (grouphead.grname) {
158                 free(grouphead.grname);
159                 grouphead.grname = (char *)0;
160         }
161         gp = grouphead.gr;
162         while (gp) {
163                 ogp = gp;
164                 gp = gp->ng_next;
165                 if (ogp->ng_str[NG_HOST])
166                         free(ogp->ng_str[NG_HOST]);
167                 if (ogp->ng_str[NG_USER])
168                         free(ogp->ng_str[NG_USER]);
169                 if (ogp->ng_str[NG_DOM])
170                         free(ogp->ng_str[NG_DOM]);
171                 free((char *)ogp);
172         }
173         grouphead.gr = (struct netgrp *)0;
174 }
175
176 /*
177  * Parse the netgroup file setting up the linked lists.
178  */
179 static int
180 parse_netgrp(group)
181         char *group;
182 {
183         register char *spos, *epos;
184         register int len, strpos;
185 #ifdef DEBUG
186         register int fields;
187 #endif
188         char *pos, *gpos;
189         struct netgrp *grp;
190         struct linelist *lp = linehead;
191
192         /*
193          * First, see if the line has already been read in.
194          */
195         while (lp) {
196                 if (!strcmp(group, lp->l_groupname))
197                         break;
198                 lp = lp->l_next;
199         }
200         if (lp == (struct linelist *)0 &&
201             (lp = read_for_group(group)) == (struct linelist *)0)
202                 return (1);
203         if (lp->l_parsed) {
204 #ifdef DEBUG
205                 /*
206                  * This error message is largely superflous since the
207                  * code handles the error condition sucessfully, and
208                  * spewing it out from inside libc can actually hose
209                  * certain programs.
210                  */
211                 warnx("cycle in netgroup %s", lp->l_groupname);
212 #endif
213                 return (1);
214         } else
215                 lp->l_parsed = 1;
216         pos = lp->l_line;
217         /* Watch for null pointer dereferences, dammit! */
218         while (pos != NULL && *pos != '\0') {
219                 if (*pos == '(') {
220                         grp = (struct netgrp *)malloc(sizeof (struct netgrp));
221                         bzero((char *)grp, sizeof (struct netgrp));
222                         grp->ng_next = grouphead.gr;
223                         grouphead.gr = grp;
224                         pos++;
225                         gpos = strsep(&pos, ")");
226 #ifdef DEBUG
227                         fields = 0;
228 #endif
229                         for (strpos = 0; strpos < 3; strpos++) {
230                                 if ((spos = strsep(&gpos, ","))) {
231 #ifdef DEBUG
232                                         fields++;
233 #endif
234                                         while (*spos == ' ' || *spos == '\t')
235                                                 spos++;
236                                         if ((epos = strpbrk(spos, " \t"))) {
237                                                 *epos = '\0';
238                                                 len = epos - spos;
239                                         } else
240                                                 len = strlen(spos);
241                                         if (len > 0) {
242                                                 grp->ng_str[strpos] =  (char *)
243                                                         malloc(len + 1);
244                                                 bcopy(spos, grp->ng_str[strpos],
245                                                         len + 1);
246                                         }
247                                 } else {
248                                         /*
249                                          * All other systems I've tested
250                                          * return NULL for empty netgroup
251                                          * fields. It's up to user programs
252                                          * to handle the NULLs appropriately.
253                                          */
254                                         grp->ng_str[strpos] = NULL;
255                                 }
256                         }
257 #ifdef DEBUG
258                         /*
259                          * Note: on other platforms, malformed netgroup
260                          * entries are not normally flagged. While we
261                          * can catch bad entries and report them, we should
262                          * stay silent by default for compatibility's sake.
263                          */
264                         if (fields < 3)
265                                         warnx("bad entry (%s%s%s%s%s) in netgroup \"%s\"",
266                                                 grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
267                                                 grp->ng_str[NG_USER] == NULL ? "" : ",",
268                                                 grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
269                                                 grp->ng_str[NG_DOM] == NULL ? "" : ",",
270                                                 grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
271                                                 lp->l_groupname);
272 #endif
273                 } else {
274                         spos = strsep(&pos, ", \t");
275                         if (parse_netgrp(spos))
276                                 continue;
277                 }
278                 /* Watch for null pointer dereferences, dammit! */
279                 if (pos != NULL)
280                         while (*pos == ' ' || *pos == ',' || *pos == '\t')
281                                 pos++;
282         }
283         return (0);
284 }
285
286 /*
287  * Read the netgroup file and save lines until the line for the netgroup
288  * is found. Return 1 if eof is encountered.
289  */
290 static struct linelist *
291 read_for_group(group)
292         char *group;
293 {
294         register char *pos, *spos, *linep = NULL, *olinep = NULL;
295         register int len, olen;
296         int cont;
297         struct linelist *lp;
298         char line[LINSIZ + 1];
299         char *data = NULL;
300
301         data = lookup (gtable, group);
302         sprintf(line, "%s %s", group, data);
303         pos = (char *)&line;
304 #ifdef CANT_HAPPEN
305         if (*pos == '#')
306                 continue;
307 #endif
308         while (*pos == ' ' || *pos == '\t')
309                 pos++;
310         spos = pos;
311         while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
312                 *pos != '\0')
313                 pos++;
314         len = pos - spos;
315         while (*pos == ' ' || *pos == '\t')
316                 pos++;
317         if (*pos != '\n' && *pos != '\0') {
318                 lp = (struct linelist *)malloc(sizeof (*lp));
319                 lp->l_parsed = 0;
320                 lp->l_groupname = (char *)malloc(len + 1);
321                 bcopy(spos, lp->l_groupname, len);
322                 *(lp->l_groupname + len) = '\0';
323                 len = strlen(pos);
324                 olen = 0;
325                         /*
326                          * Loop around handling line continuations.
327                          */
328                         do {
329                                 if (*(pos + len - 1) == '\n')
330                                         len--;
331                                 if (*(pos + len - 1) == '\\') {
332                                         len--;
333                                         cont = 1;
334                                 } else
335                                         cont = 0;
336                                 if (len > 0) {
337                                         linep = (char *)malloc(olen + len + 1);
338                                         if (olen > 0) {
339                                                 bcopy(olinep, linep, olen);
340                                                 free(olinep);
341                                         }
342                                         bcopy(pos, linep + olen, len);
343                                         olen += len;
344                                         *(linep + olen) = '\0';
345                                         olinep = linep;
346                                 }
347 #ifdef CANT_HAPPEN
348                                 if (cont) {
349                                         if (fgets(line, LINSIZ, netf)) {
350                                                 pos = line;
351                                                 len = strlen(pos);
352                                         } else
353                                                 cont = 0;
354                                 }
355 #endif
356                         } while (cont);
357                 lp->l_line = linep;
358                 lp->l_next = linehead;
359                 linehead = lp;
360 #ifdef CANT_HAPPEN
361                 /*
362                  * If this is the one we wanted, we are done.
363                  */
364                 if (!strcmp(lp->l_groupname, group))
365 #endif
366                         return (lp);
367         }
368         return ((struct linelist *)0);
369 }