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