1 /*
2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1996-1999 by Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /* Imports */
19
20 #include "port_before.h"
21
22 #include <sys/types.h>
23 #include <netinet/in.h>
24 #include <arpa/nameser.h>
25 #include <resolv.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include <irs.h>
33 #include <isc/memcluster.h>
34
35 #include "port_after.h"
36
37 #include "irs_p.h"
38 #include "lcl_p.h"
39
40 /* Definitions */
41
42 #define NG_HOST 0 /*%< Host name */
43 #define NG_USER 1 /*%< User name */
44 #define NG_DOM 2 /*%< and Domain name */
45 #define LINSIZ 1024 /*%< Length of netgroup file line */
46 /*
47 * XXX Warning XXX
48 * This code is a hack-and-slash special. It realy needs to be
49 * rewritten with things like strdup, and realloc in mind.
50 * More reasonable data structures would not be a bad thing.
51 */
52
53 /*%
54 * Static Variables and functions used by setnetgrent(), getnetgrent() and
55 * endnetgrent().
56 *
57 * There are two linked lists:
58 * \li linelist is just used by setnetgrent() to parse the net group file via.
59 * parse_netgrp()
60 * \li netgrp is the list of entries for the current netgroup
61 */
62 struct linelist {
63 struct linelist *l_next; /*%< Chain ptr. */
64 int l_parsed; /*%< Flag for cycles */
65 char * l_groupname; /*%< Name of netgroup */
66 char * l_line; /*%< Netgroup entrie(s) to be parsed */
67 };
68
69 struct ng_old_struct {
70 struct ng_old_struct *ng_next; /*%< Chain ptr */
71 char * ng_str[3]; /*%< Field pointers, see below */
72 };
73
74 struct pvt {
75 FILE *fp;
76 struct linelist *linehead;
77 struct ng_old_struct *nextgrp;
78 struct {
79 struct ng_old_struct *gr;
80 char *grname;
81 } grouphead;
82 };
83
84 /* Forward */
85
86 static void ng_rewind(struct irs_ng *, const char*);
87 static void ng_close(struct irs_ng *);
88 static int ng_next(struct irs_ng *, const char **,
89 const char **, const char **);
90 static int ng_test(struct irs_ng *, const char *,
91 const char *, const char *,
92 const char *);
93 static void ng_minimize(struct irs_ng *);
94
95 static int parse_netgrp(struct irs_ng *, const char*);
96 static struct linelist *read_for_group(struct irs_ng *, const char *);
97 static void freelists(struct irs_ng *);
98
99 /* Public */
100
101 struct irs_ng *
irs_lcl_ng(struct irs_acc * this)102 irs_lcl_ng(struct irs_acc *this) {
103 struct irs_ng *ng;
104 struct pvt *pvt;
105
106 UNUSED(this);
107
108 if (!(ng = memget(sizeof *ng))) {
109 errno = ENOMEM;
110 return (NULL);
111 }
112 memset(ng, 0x5e, sizeof *ng);
113 if (!(pvt = memget(sizeof *pvt))) {
114 memput(ng, sizeof *ng);
115 errno = ENOMEM;
116 return (NULL);
117 }
118 memset(pvt, 0, sizeof *pvt);
119 ng->private = pvt;
120 ng->close = ng_close;
121 ng->next = ng_next;
122 ng->test = ng_test;
123 ng->rewind = ng_rewind;
124 ng->minimize = ng_minimize;
125 return (ng);
126 }
127
128 /* Methods */
129
130 static void
ng_close(struct irs_ng * this)131 ng_close(struct irs_ng *this) {
132 struct pvt *pvt = (struct pvt *)this->private;
133
134 if (pvt->fp != NULL)
135 fclose(pvt->fp);
136 freelists(this);
137 memput(pvt, sizeof *pvt);
138 memput(this, sizeof *this);
139 }
140
141 /*%
142 * Parse the netgroup file looking for the netgroup and build the list
143 * of netgrp structures. Let parse_netgrp() and read_for_group() do
144 * most of the work.
145 */
146 static void
ng_rewind(struct irs_ng * this,const char * group)147 ng_rewind(struct irs_ng *this, const char *group) {
148 struct pvt *pvt = (struct pvt *)this->private;
149
150 if (pvt->fp != NULL && fseek(pvt->fp, SEEK_CUR, 0L) == -1) {
151 fclose(pvt->fp);
152 pvt->fp = NULL;
153 }
154
155 if (pvt->fp == NULL || pvt->grouphead.gr == NULL ||
156 strcmp(group, pvt->grouphead.grname)) {
157 freelists(this);
158 if (pvt->fp != NULL)
159 fclose(pvt->fp);
160 pvt->fp = fopen(_PATH_NETGROUP, "r");
161 if (pvt->fp != NULL) {
162 if (parse_netgrp(this, group))
163 freelists(this);
164 if (!(pvt->grouphead.grname = strdup(group)))
165 freelists(this);
166 fclose(pvt->fp);
167 pvt->fp = NULL;
168 }
169 }
170 pvt->nextgrp = pvt->grouphead.gr;
171 }
172
173 /*%
174 * Get the next netgroup off the list.
175 */
176 static int
ng_next(struct irs_ng * this,const char ** host,const char ** user,const char ** domain)177 ng_next(struct irs_ng *this, const char **host, const char **user,
178 const char **domain)
179 {
180 struct pvt *pvt = (struct pvt *)this->private;
181
182 if (pvt->nextgrp) {
183 *host = pvt->nextgrp->ng_str[NG_HOST];
184 *user = pvt->nextgrp->ng_str[NG_USER];
185 *domain = pvt->nextgrp->ng_str[NG_DOM];
186 pvt->nextgrp = pvt->nextgrp->ng_next;
187 return (1);
188 }
189 return (0);
190 }
191
192 /*%
193 * Search for a match in a netgroup.
194 */
195 static int
ng_test(struct irs_ng * this,const char * name,const char * host,const char * user,const char * domain)196 ng_test(struct irs_ng *this, const char *name,
197 const char *host, const char *user, const char *domain)
198 {
199 const char *ng_host, *ng_user, *ng_domain;
200
201 ng_rewind(this, name);
202 while (ng_next(this, &ng_host, &ng_user, &ng_domain))
203 if ((host == NULL || ng_host == NULL ||
204 !strcmp(host, ng_host)) &&
205 (user == NULL || ng_user == NULL ||
206 !strcmp(user, ng_user)) &&
207 (domain == NULL || ng_domain == NULL ||
208 !strcmp(domain, ng_domain))) {
209 freelists(this);
210 return (1);
211 }
212 freelists(this);
213 return (0);
214 }
215
216 static void
ng_minimize(struct irs_ng * this)217 ng_minimize(struct irs_ng *this) {
218 struct pvt *pvt = (struct pvt *)this->private;
219
220 if (pvt->fp != NULL) {
221 (void)fclose(pvt->fp);
222 pvt->fp = NULL;
223 }
224 }
225
226 /* Private */
227
228 /*%
229 * endnetgrent() - cleanup
230 */
231 static void
freelists(struct irs_ng * this)232 freelists(struct irs_ng *this) {
233 struct pvt *pvt = (struct pvt *)this->private;
234 struct linelist *lp, *olp;
235 struct ng_old_struct *gp, *ogp;
236
237 lp = pvt->linehead;
238 while (lp) {
239 olp = lp;
240 lp = lp->l_next;
241 free(olp->l_groupname);
242 free(olp->l_line);
243 free((char *)olp);
244 }
245 pvt->linehead = NULL;
246 if (pvt->grouphead.grname) {
247 free(pvt->grouphead.grname);
248 pvt->grouphead.grname = NULL;
249 }
250 gp = pvt->grouphead.gr;
251 while (gp) {
252 ogp = gp;
253 gp = gp->ng_next;
254 if (ogp->ng_str[NG_HOST])
255 free(ogp->ng_str[NG_HOST]);
256 if (ogp->ng_str[NG_USER])
257 free(ogp->ng_str[NG_USER]);
258 if (ogp->ng_str[NG_DOM])
259 free(ogp->ng_str[NG_DOM]);
260 free((char *)ogp);
261 }
262 pvt->grouphead.gr = NULL;
263 }
264
265 /*%
266 * Parse the netgroup file setting up the linked lists.
267 */
268 static int
parse_netgrp(struct irs_ng * this,const char * group)269 parse_netgrp(struct irs_ng *this, const char *group) {
270 struct pvt *pvt = (struct pvt *)this->private;
271 char *spos, *epos;
272 int len, strpos;
273 char *pos, *gpos;
274 struct ng_old_struct *grp;
275 struct linelist *lp = pvt->linehead;
276
277 /*
278 * First, see if the line has already been read in.
279 */
280 while (lp) {
281 if (!strcmp(group, lp->l_groupname))
282 break;
283 lp = lp->l_next;
284 }
285 if (lp == NULL &&
286 (lp = read_for_group(this, group)) == NULL)
287 return (1);
288 if (lp->l_parsed) {
289 /*fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);*/
290 return (1);
291 } else
292 lp->l_parsed = 1;
293 pos = lp->l_line;
294 while (*pos != '\0') {
295 if (*pos == '(') {
296 if (!(grp = malloc(sizeof (struct ng_old_struct)))) {
297 freelists(this);
298 errno = ENOMEM;
299 return (1);
300 }
301 memset(grp, 0, sizeof (struct ng_old_struct));
302 grp->ng_next = pvt->grouphead.gr;
303 pvt->grouphead.gr = grp;
304 pos++;
305 gpos = strsep(&pos, ")");
306 for (strpos = 0; strpos < 3; strpos++) {
307 if ((spos = strsep(&gpos, ","))) {
308 while (*spos == ' ' || *spos == '\t')
309 spos++;
310 if ((epos = strpbrk(spos, " \t"))) {
311 *epos = '\0';
312 len = epos - spos;
313 } else
314 len = strlen(spos);
315 if (len > 0) {
316 if(!(grp->ng_str[strpos]
317 = (char *)
318 malloc(len + 1))) {
319 freelists(this);
320 return (1);
321 }
322 memcpy(grp->ng_str[strpos],
323 spos,
324 len + 1);
325 }
326 } else
327 goto errout;
328 }
329 } else {
330 spos = strsep(&pos, ", \t");
331 if (spos != NULL && parse_netgrp(this, spos)) {
332 freelists(this);
333 return (1);
334 }
335 }
336 if (pos == NULL)
337 break;
338 while (*pos == ' ' || *pos == ',' || *pos == '\t')
339 pos++;
340 }
341 return (0);
342 errout:
343 /*fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname,
344 spos);*/
345 return (1);
346 }
347
348 /*%
349 * Read the netgroup file and save lines until the line for the netgroup
350 * is found. Return 1 if eof is encountered.
351 */
352 static struct linelist *
read_for_group(struct irs_ng * this,const char * group)353 read_for_group(struct irs_ng *this, const char *group) {
354 struct pvt *pvt = (struct pvt *)this->private;
355 char *pos, *spos, *linep = NULL, *olinep;
356 int len, olen, cont;
357 struct linelist *lp;
358 char line[LINSIZ + 1];
359
360 while (fgets(line, LINSIZ, pvt->fp) != NULL) {
361 pos = line;
362 if (*pos == '#')
363 continue;
364 while (*pos == ' ' || *pos == '\t')
365 pos++;
366 spos = pos;
367 while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
368 *pos != '\0')
369 pos++;
370 len = pos - spos;
371 while (*pos == ' ' || *pos == '\t')
372 pos++;
373 if (*pos != '\n' && *pos != '\0') {
374 if (!(lp = malloc(sizeof (*lp)))) {
375 freelists(this);
376 return (NULL);
377 }
378 lp->l_parsed = 0;
379 if (!(lp->l_groupname = malloc(len + 1))) {
380 free(lp);
381 freelists(this);
382 return (NULL);
383 }
384 memcpy(lp->l_groupname, spos, len);
385 *(lp->l_groupname + len) = '\0';
386 len = strlen(pos);
387 olen = 0;
388 olinep = NULL;
389
390 /*
391 * Loop around handling line continuations.
392 */
393 do {
394 if (*(pos + len - 1) == '\n')
395 len--;
396 if (*(pos + len - 1) == '\\') {
397 len--;
398 cont = 1;
399 } else
400 cont = 0;
401 if (len > 0) {
402 if (!(linep = malloc(olen + len + 1))){
403 if (olen > 0)
404 free(olinep);
405 free(lp->l_groupname);
406 free(lp);
407 freelists(this);
408 errno = ENOMEM;
409 return (NULL);
410 }
411 if (olen > 0) {
412 memcpy(linep, olinep, olen);
413 free(olinep);
414 }
415 memcpy(linep + olen, pos, len);
416 olen += len;
417 *(linep + olen) = '\0';
418 olinep = linep;
419 }
420 if (cont) {
421 if (fgets(line, LINSIZ, pvt->fp)) {
422 pos = line;
423 len = strlen(pos);
424 } else
425 cont = 0;
426 }
427 } while (cont);
428 lp->l_line = linep;
429 lp->l_next = pvt->linehead;
430 pvt->linehead = lp;
431
432 /*
433 * If this is the one we wanted, we are done.
434 */
435 if (!strcmp(lp->l_groupname, group))
436 return (lp);
437 }
438 }
439 return (NULL);
440 }
441
442 /*! \file */
443