Merge from vendor branch FILE:
[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  * $FreeBSD: src/libexec/revnetgroup/parse_netgroup.c,v 1.7 1999/08/28 00:09:48 peter Exp $
37  * $DragonFly: src/libexec/revnetgroup/parse_netgroup.c,v 1.3 2004/08/25 01:53:39 dillon Exp $
38  */
39
40 /*
41  * This is a specially hacked-up version of getnetgrent.c used to parse
42  * data from the stored hash table of netgroup info rather than from a
43  * file. It's used mainly for the parse_netgroup() function. All the YP
44  * stuff and file support has been stripped out since it isn't needed.
45  */
46
47 #include <stdio.h>
48 #include <strings.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include "hash.h"
52
53 /*
54  * Static Variables and functions used by setnetgrent(), getnetgrent() and
55  * __endnetgrent().
56  * There are two linked lists:
57  * - linelist is just used by setnetgrent() to parse the net group file via.
58  *   parse_netgrp()
59  * - netgrp is the list of entries for the current netgroup
60  */
61 struct linelist {
62         struct linelist *l_next;        /* Chain ptr. */
63         int             l_parsed;       /* Flag for cycles */
64         char            *l_groupname;   /* Name of netgroup */
65         char            *l_line;        /* Netgroup entrie(s) to be parsed */
66 };
67
68 struct netgrp {
69         struct netgrp   *ng_next;       /* Chain ptr */
70         char            *ng_str[3];     /* Field pointers, see below */
71 };
72 #define NG_HOST         0       /* Host name */
73 #define NG_USER         1       /* User name */
74 #define NG_DOM          2       /* and Domain name */
75
76 static struct linelist  *linehead = (struct linelist *)0;
77 static struct netgrp    *nextgrp = (struct netgrp *)0;
78 static struct {
79         struct netgrp   *gr;
80         char            *grname;
81 } grouphead = {
82         (struct netgrp *)0,
83         (char *)0,
84 };
85 static int parse_netgrp();
86 static struct linelist *read_for_group();
87 void __setnetgrent(), __endnetgrent();
88 int __getnetgrent();
89 extern struct group_entry *gtable[];
90
91 /*
92  * setnetgrent()
93  * Parse the netgroup file looking for the netgroup and build the list
94  * of netgrp structures. Let parse_netgrp() and read_for_group() do
95  * most of the work.
96  */
97 void
98 __setnetgrent(group)
99         char *group;
100 {
101         /* Sanity check */
102
103         if (group == NULL || !strlen(group))
104                 return;
105
106         if (grouphead.gr == (struct netgrp *)0 ||
107                 strcmp(group, grouphead.grname)) {
108                 __endnetgrent();
109                 if (parse_netgrp(group))
110                         __endnetgrent();
111                 else {
112                         grouphead.grname = (char *)
113                                 malloc(strlen(group) + 1);
114                         strcpy(grouphead.grname, group);
115                 }
116         }
117         nextgrp = grouphead.gr;
118 }
119
120 /*
121  * Get the next netgroup off the list.
122  */
123 int
124 __getnetgrent(hostp, userp, domp)
125         char **hostp, **userp, **domp;
126 {
127         if (nextgrp) {
128                 *hostp = nextgrp->ng_str[NG_HOST];
129                 *userp = nextgrp->ng_str[NG_USER];
130                 *domp = nextgrp->ng_str[NG_DOM];
131                 nextgrp = nextgrp->ng_next;
132                 return (1);
133         }
134         return (0);
135 }
136
137 /*
138  * __endnetgrent() - cleanup
139  */
140 void
141 __endnetgrent()
142 {
143         register struct linelist *lp, *olp;
144         register struct netgrp *gp, *ogp;
145
146         lp = linehead;
147         while (lp) {
148                 olp = lp;
149                 lp = lp->l_next;
150                 free(olp->l_groupname);
151                 free(olp->l_line);
152                 free((char *)olp);
153         }
154         linehead = (struct linelist *)0;
155         if (grouphead.grname) {
156                 free(grouphead.grname);
157                 grouphead.grname = (char *)0;
158         }
159         gp = grouphead.gr;
160         while (gp) {
161                 ogp = gp;
162                 gp = gp->ng_next;
163                 if (ogp->ng_str[NG_HOST])
164                         free(ogp->ng_str[NG_HOST]);
165                 if (ogp->ng_str[NG_USER])
166                         free(ogp->ng_str[NG_USER]);
167                 if (ogp->ng_str[NG_DOM])
168                         free(ogp->ng_str[NG_DOM]);
169                 free((char *)ogp);
170         }
171         grouphead.gr = (struct netgrp *)0;
172 }
173
174 /*
175  * Parse the netgroup file setting up the linked lists.
176  */
177 static int
178 parse_netgrp(group)
179         char *group;
180 {
181         register char *spos, *epos;
182         register int len, strpos;
183 #ifdef DEBUG
184         register int fields;
185 #endif
186         char *pos, *gpos;
187         struct netgrp *grp;
188         struct linelist *lp = linehead;
189
190         /*
191          * First, see if the line has already been read in.
192          */
193         while (lp) {
194                 if (!strcmp(group, lp->l_groupname))
195                         break;
196                 lp = lp->l_next;
197         }
198         if (lp == (struct linelist *)0 &&
199             (lp = read_for_group(group)) == (struct linelist *)0)
200                 return (1);
201         if (lp->l_parsed) {
202 #ifdef DEBUG
203                 /*
204                  * This error message is largely superfluous since the
205                  * code handles the error condition successfully, and
206                  * spewing it out from inside libc can actually hose
207                  * certain programs.
208                  */
209                 warnx("cycle in netgroup %s", lp->l_groupname);
210 #endif
211                 return (1);
212         } else
213                 lp->l_parsed = 1;
214         pos = lp->l_line;
215         /* Watch for null pointer dereferences, dammit! */
216         while (pos != NULL && *pos != '\0') {
217                 if (*pos == '(') {
218                         grp = (struct netgrp *)malloc(sizeof (struct netgrp));
219                         bzero((char *)grp, sizeof (struct netgrp));
220                         grp->ng_next = grouphead.gr;
221                         grouphead.gr = grp;
222                         pos++;
223                         gpos = strsep(&pos, ")");
224 #ifdef DEBUG
225                         fields = 0;
226 #endif
227                         for (strpos = 0; strpos < 3; strpos++) {
228                                 if ((spos = strsep(&gpos, ","))) {
229 #ifdef DEBUG
230                                         fields++;
231 #endif
232                                         while (*spos == ' ' || *spos == '\t')
233                                                 spos++;
234                                         if ((epos = strpbrk(spos, " \t"))) {
235                                                 *epos = '\0';
236                                                 len = epos - spos;
237                                         } else
238                                                 len = strlen(spos);
239                                         if (len > 0) {
240                                                 grp->ng_str[strpos] =  (char *)
241                                                         malloc(len + 1);
242                                                 bcopy(spos, grp->ng_str[strpos],
243                                                         len + 1);
244                                         }
245                                 } else {
246                                         /*
247                                          * All other systems I've tested
248                                          * return NULL for empty netgroup
249                                          * fields. It's up to user programs
250                                          * to handle the NULLs appropriately.
251                                          */
252                                         grp->ng_str[strpos] = NULL;
253                                 }
254                         }
255 #ifdef DEBUG
256                         /*
257                          * Note: on other platforms, malformed netgroup
258                          * entries are not normally flagged. While we
259                          * can catch bad entries and report them, we should
260                          * stay silent by default for compatibility's sake.
261                          */
262                         if (fields < 3)
263                                         warnx("bad entry (%s%s%s%s%s) in netgroup \"%s\"",
264                                                 grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
265                                                 grp->ng_str[NG_USER] == NULL ? "" : ",",
266                                                 grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
267                                                 grp->ng_str[NG_DOM] == NULL ? "" : ",",
268                                                 grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
269                                                 lp->l_groupname);
270 #endif
271                 } else {
272                         spos = strsep(&pos, ", \t");
273                         if (parse_netgrp(spos))
274                                 continue;
275                 }
276                 /* Watch for null pointer dereferences, dammit! */
277                 if (pos != NULL)
278                         while (*pos == ' ' || *pos == ',' || *pos == '\t')
279                                 pos++;
280         }
281         return (0);
282 }
283
284 /*
285  * Read the netgroup file and save lines until the line for the netgroup
286  * is found. Return 1 if eof is encountered.
287  */
288 static struct linelist *
289 read_for_group(group)
290         char *group;
291 {
292         register char *pos, *spos, *linep = NULL, *olinep = NULL;
293         register int len, olen;
294         int cont;
295         struct linelist *lp;
296         char line[LINSIZ + 1];
297         char *data = NULL;
298
299         data = lookup (gtable, group);
300         sprintf(line, "%s %s", group, data);
301         pos = (char *)&line;
302 #ifdef CANT_HAPPEN
303         if (*pos == '#')
304                 continue;
305 #endif
306         while (*pos == ' ' || *pos == '\t')
307                 pos++;
308         spos = pos;
309         while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
310                 *pos != '\0')
311                 pos++;
312         len = pos - spos;
313         while (*pos == ' ' || *pos == '\t')
314                 pos++;
315         if (*pos != '\n' && *pos != '\0') {
316                 lp = (struct linelist *)malloc(sizeof (*lp));
317                 lp->l_parsed = 0;
318                 lp->l_groupname = (char *)malloc(len + 1);
319                 bcopy(spos, lp->l_groupname, len);
320                 *(lp->l_groupname + len) = '\0';
321                 len = strlen(pos);
322                 olen = 0;
323                         /*
324                          * Loop around handling line continuations.
325                          */
326                         do {
327                                 if (*(pos + len - 1) == '\n')
328                                         len--;
329                                 if (*(pos + len - 1) == '\\') {
330                                         len--;
331                                         cont = 1;
332                                 } else
333                                         cont = 0;
334                                 if (len > 0) {
335                                         linep = (char *)malloc(olen + len + 1);
336                                         if (olen > 0) {
337                                                 bcopy(olinep, linep, olen);
338                                                 free(olinep);
339                                         }
340                                         bcopy(pos, linep + olen, len);
341                                         olen += len;
342                                         *(linep + olen) = '\0';
343                                         olinep = linep;
344                                 }
345 #ifdef CANT_HAPPEN
346                                 if (cont) {
347                                         if (fgets(line, LINSIZ, netf)) {
348                                                 pos = line;
349                                                 len = strlen(pos);
350                                         } else
351                                                 cont = 0;
352                                 }
353 #endif
354                         } while (cont);
355                 lp->l_line = linep;
356                 lp->l_next = linehead;
357                 linehead = lp;
358 #ifdef CANT_HAPPEN
359                 /*
360                  * If this is the one we wanted, we are done.
361                  */
362                 if (!strcmp(lp->l_groupname, group))
363 #endif
364                         return (lp);
365         }
366         return ((struct linelist *)0);
367 }