/* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if !defined(LINT) && !defined(CODECENTER) static const char rcsid[] = "$Id: lcl_ng.c,v 1.1.2.1 2004/03/09 09:17:32 marka Exp $"; #endif /* Imports */ #include "port_before.h" #include #include #include #include #include #include #include #include #include #include #include #include "port_after.h" #include "irs_p.h" #include "lcl_p.h" /* Definitions */ #define NG_HOST 0 /* Host name */ #define NG_USER 1 /* User name */ #define NG_DOM 2 /* and Domain name */ #define LINSIZ 1024 /* Length of netgroup file line */ /* * XXX Warning XXX * This code is a hack-and-slash special. It realy needs to be * rewritten with things like strdup, and realloc in mind. * More reasonable data structures would not be a bad thing. */ /* * Static Variables and functions used by setnetgrent(), getnetgrent() and * endnetgrent(). * There are two linked lists: * - linelist is just used by setnetgrent() to parse the net group file via. * parse_netgrp() * - netgrp is the list of entries for the current netgroup */ struct linelist { struct linelist *l_next; /* Chain ptr. */ int l_parsed; /* Flag for cycles */ char * l_groupname; /* Name of netgroup */ char * l_line; /* Netgroup entrie(s) to be parsed */ }; struct ng_old_struct { struct ng_old_struct *ng_next; /* Chain ptr */ char * ng_str[3]; /* Field pointers, see below */ }; struct pvt { FILE *fp; struct linelist *linehead; struct ng_old_struct *nextgrp; struct { struct ng_old_struct *gr; char *grname; } grouphead; }; /* Forward */ static void ng_rewind(struct irs_ng *, const char*); static void ng_close(struct irs_ng *); static int ng_next(struct irs_ng *, const char **, const char **, const char **); static int ng_test(struct irs_ng *, const char *, const char *, const char *, const char *); static void ng_minimize(struct irs_ng *); static int parse_netgrp(struct irs_ng *, const char*); static struct linelist *read_for_group(struct irs_ng *, const char *); static void freelists(struct irs_ng *); /* Public */ struct irs_ng * irs_lcl_ng(struct irs_acc *this) { struct irs_ng *ng; struct pvt *pvt; UNUSED(this); if (!(ng = memget(sizeof *ng))) { errno = ENOMEM; return (NULL); } memset(ng, 0x5e, sizeof *ng); if (!(pvt = memget(sizeof *pvt))) { memput(ng, sizeof *ng); errno = ENOMEM; return (NULL); } memset(pvt, 0, sizeof *pvt); ng->private = pvt; ng->close = ng_close; ng->next = ng_next; ng->test = ng_test; ng->rewind = ng_rewind; ng->minimize = ng_minimize; return (ng); } /* Methods */ static void ng_close(struct irs_ng *this) { struct pvt *pvt = (struct pvt *)this->private; if (pvt->fp != NULL) fclose(pvt->fp); freelists(this); memput(pvt, sizeof *pvt); memput(this, sizeof *this); } /* * Parse the netgroup file looking for the netgroup and build the list * of netgrp structures. Let parse_netgrp() and read_for_group() do * most of the work. */ static void ng_rewind(struct irs_ng *this, const char *group) { struct pvt *pvt = (struct pvt *)this->private; if (pvt->fp != NULL && fseek(pvt->fp, SEEK_CUR, 0L) == -1) { fclose(pvt->fp); pvt->fp = NULL; } if (pvt->fp == NULL || pvt->grouphead.gr == NULL || strcmp(group, pvt->grouphead.grname)) { freelists(this); if (pvt->fp != NULL) fclose(pvt->fp); pvt->fp = fopen(_PATH_NETGROUP, "r"); if (pvt->fp != NULL) { if (parse_netgrp(this, group)) freelists(this); if (!(pvt->grouphead.grname = strdup(group))) freelists(this); fclose(pvt->fp); pvt->fp = NULL; } } pvt->nextgrp = pvt->grouphead.gr; } /* * Get the next netgroup off the list. */ static int ng_next(struct irs_ng *this, const char **host, const char **user, const char **domain) { struct pvt *pvt = (struct pvt *)this->private; if (pvt->nextgrp) { *host = pvt->nextgrp->ng_str[NG_HOST]; *user = pvt->nextgrp->ng_str[NG_USER]; *domain = pvt->nextgrp->ng_str[NG_DOM]; pvt->nextgrp = pvt->nextgrp->ng_next; return (1); } return (0); } /* * Search for a match in a netgroup. */ static int ng_test(struct irs_ng *this, const char *name, const char *host, const char *user, const char *domain) { const char *ng_host, *ng_user, *ng_domain; ng_rewind(this, name); while (ng_next(this, &ng_host, &ng_user, &ng_domain)) if ((host == NULL || ng_host == NULL || !strcmp(host, ng_host)) && (user == NULL || ng_user == NULL || !strcmp(user, ng_user)) && (domain == NULL || ng_domain == NULL || !strcmp(domain, ng_domain))) { freelists(this); return (1); } freelists(this); return (0); } static void ng_minimize(struct irs_ng *this) { struct pvt *pvt = (struct pvt *)this->private; if (pvt->fp != NULL) { (void)fclose(pvt->fp); pvt->fp = NULL; } } /* Private */ /* * endnetgrent() - cleanup */ static void freelists(struct irs_ng *this) { struct pvt *pvt = (struct pvt *)this->private; struct linelist *lp, *olp; struct ng_old_struct *gp, *ogp; lp = pvt->linehead; while (lp) { olp = lp; lp = lp->l_next; free(olp->l_groupname); free(olp->l_line); free((char *)olp); } pvt->linehead = NULL; if (pvt->grouphead.grname) { free(pvt->grouphead.grname); pvt->grouphead.grname = NULL; } gp = pvt->grouphead.gr; while (gp) { ogp = gp; gp = gp->ng_next; if (ogp->ng_str[NG_HOST]) free(ogp->ng_str[NG_HOST]); if (ogp->ng_str[NG_USER]) free(ogp->ng_str[NG_USER]); if (ogp->ng_str[NG_DOM]) free(ogp->ng_str[NG_DOM]); free((char *)ogp); } pvt->grouphead.gr = NULL; } /* * Parse the netgroup file setting up the linked lists. */ static int parse_netgrp(struct irs_ng *this, const char *group) { struct pvt *pvt = (struct pvt *)this->private; char *spos, *epos; int len, strpos; char *pos, *gpos; struct ng_old_struct *grp; struct linelist *lp = pvt->linehead; /* * First, see if the line has already been read in. */ while (lp) { if (!strcmp(group, lp->l_groupname)) break; lp = lp->l_next; } if (lp == NULL && (lp = read_for_group(this, group)) == NULL) return (1); if (lp->l_parsed) { /*fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);*/ return (1); } else lp->l_parsed = 1; pos = lp->l_line; while (*pos != '\0') { if (*pos == '(') { if (!(grp = malloc(sizeof (struct ng_old_struct)))) { freelists(this); errno = ENOMEM; return (1); } memset(grp, 0, sizeof (struct ng_old_struct)); grp->ng_next = pvt->grouphead.gr; pvt->grouphead.gr = grp; pos++; gpos = strsep(&pos, ")"); for (strpos = 0; strpos < 3; strpos++) { if ((spos = strsep(&gpos, ","))) { while (*spos == ' ' || *spos == '\t') spos++; if ((epos = strpbrk(spos, " \t"))) { *epos = '\0'; len = epos - spos; } else len = strlen(spos); if (len > 0) { if(!(grp->ng_str[strpos] = (char *) malloc(len + 1))) { freelists(this); return (1); } memcpy(grp->ng_str[strpos], spos, len + 1); } } else goto errout; } } else { spos = strsep(&pos, ", \t"); if (spos != NULL && parse_netgrp(this, spos)) { freelists(this); return (1); } } if (pos == NULL) break; while (*pos == ' ' || *pos == ',' || *pos == '\t') pos++; } return (0); errout: /*fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname, spos);*/ return (1); } /* * Read the netgroup file and save lines until the line for the netgroup * is found. Return 1 if eof is encountered. */ static struct linelist * read_for_group(struct irs_ng *this, const char *group) { struct pvt *pvt = (struct pvt *)this->private; char *pos, *spos, *linep = NULL, *olinep; int len, olen, cont; struct linelist *lp; char line[LINSIZ + 1]; while (fgets(line, LINSIZ, pvt->fp) != NULL) { pos = line; if (*pos == '#') continue; while (*pos == ' ' || *pos == '\t') pos++; spos = pos; while (*pos != ' ' && *pos != '\t' && *pos != '\n' && *pos != '\0') pos++; len = pos - spos; while (*pos == ' ' || *pos == '\t') pos++; if (*pos != '\n' && *pos != '\0') { if (!(lp = malloc(sizeof (*lp)))) { freelists(this); return (NULL); } lp->l_parsed = 0; if (!(lp->l_groupname = malloc(len + 1))) { free(lp); freelists(this); return (NULL); } memcpy(lp->l_groupname, spos, len); *(lp->l_groupname + len) = '\0'; len = strlen(pos); olen = 0; olinep = NULL; /* * Loop around handling line continuations. */ do { if (*(pos + len - 1) == '\n') len--; if (*(pos + len - 1) == '\\') { len--; cont = 1; } else cont = 0; if (len > 0) { if (!(linep = malloc(olen + len + 1))){ if (olen > 0) free(olinep); free(lp->l_groupname); free(lp); freelists(this); errno = ENOMEM; return (NULL); } if (olen > 0) { memcpy(linep, olinep, olen); free(olinep); } memcpy(linep + olen, pos, len); olen += len; *(linep + olen) = '\0'; olinep = linep; } if (cont) { if (fgets(line, LINSIZ, pvt->fp)) { pos = line; len = strlen(pos); } else cont = 0; } } while (cont); lp->l_line = linep; lp->l_next = pvt->linehead; pvt->linehead = lp; /* * If this is the one we wanted, we are done. */ if (!strcmp(lp->l_groupname, group)) return (lp); } } return (NULL); }