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