From: mdw Date: Thu, 7 Aug 1997 09:45:00 +0000 (+0000) Subject: New source file added to maintain a netgroups database. X-Git-Tag: 1.3.3~134 X-Git-Url: https://git.distorted.org.uk/~mdw/become/commitdiff_plain/afce951bf49ff63b726810860a29ebeec534146c New source file added to maintain a netgroups database. --- diff --git a/src/netg.c b/src/netg.c new file mode 100644 index 0000000..87afce0 --- /dev/null +++ b/src/netg.c @@ -0,0 +1,684 @@ +/* -*-c-*- + * + * $Id: netg.c,v 1.1 1997/08/07 09:45:00 mdw Exp $ + * + * A local database of netgroups + * + * (c) 1997 EBI + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of `become' + * + * `Become' is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * `Become' is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with `become'; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: netg.c,v $ + * Revision 1.1 1997/08/07 09:45:00 mdw + * New source file added to maintain a netgroups database. + * + */ + +/*----- Header files ------------------------------------------------------*/ + +/* --- ANSI headers --- */ + +#include +#include +#include +#include + +/* --- Unix headers --- */ + +#include "config.h" + +#include + +#ifdef HAVE_YP +# include +# include +# include +#endif + +#include + +#include + +#include +#include +#include + +/* --- Local headers --- */ + +#include "become.h" +#include "config.h" +#include "netg.h" +#include "sym.h" +#include "userdb.h" +#include "utils.h" + +/*----- Type definitions --------------------------------------------------*/ + +/* --- Quick discussion --- * + * + * I've just noticed: netgroups are horrible. They form a directed graph + * which is really horrible; I'll have to try and turn it into something + * more sensible (which will essentially involve cutting cycles). + * + * The structure looks a little bit like a good ol' List (see Knuth 1 or + * any decent Lisp manual), but with more information in the cons cells. + */ + +/* --- @netg__cons@ --- */ + +typedef struct netg__cons { + unsigned f; + union { + struct netg__cons *cons; + struct netg__atom *atom; + } car; + struct netg__cons *cdr; +} netg__cons; + +enum { + f_cons = 1, /* The @car@ is a cons cell */ + f_visit = 2, /* Currently threaded on this cell */ + f_uncycled = 4 /* Cycles removed from here on in */ +}; + +/* --- @netg__atom@ --- */ + +typedef struct netg__atom { + char *n; /* Unresolved netgroup reference */ + char *h; /* Matched hostname */ + char *u; /* Matched user name */ + char *d; /* Matched domain name */ +} netg__atom; + +/* --- @netg__sym@ --- */ + +typedef struct netg__sym { + sym_base _base; + netg__cons *cons; +} netg__sym; + +/* --- Token types for the netgroup parser --- */ + +enum { + tok_string = 256, + tok_eof +}; + +/*----- Static variables --------------------------------------------------*/ + +static sym_table netg__table; /* Netgroup table */ +static sym_iter netg__iter; /* Iterator object for users */ + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @netg__lex@ --- * + * + * Arguments: @const char **p@ = pointer to next unscanned character + * @char *q@ = pointer to output buffer + * + * Returns: Token type (either character code or a magic number). + * + * Use: Lexes a netgroups line into tokens. + */ + +static int netg__lex(char **p, char *q) +{ + /* --- Skip any leading whitespace --- */ + + while (isspace((unsigned char)**p)) + (*p)++; + + /* --- Now work out what we've got --- */ + + if (**p == 0) + return (tok_eof); + if (**p == '(' || **p == ')' || **p == ',') + return (*(*p)++); + do + *q++ = *(*p)++; + while (**p != 0 && **p != '(' && **p != ')' && + **p != ',' && !isspace((unsigned char)**p)); + *q++ = 0; + return (tok_string); +} + +/* --- @netg__foreach@ --- * + * + * Arguments: @int st@ = YP protocol-level status code + * @char *k@ = pointer to string containing the key + * @int ksz@ = length of the key string + * @char *v@ = pointer to string containing the value + * @int vsz@ = length of the value string + * @char *data@ = pointer to my data information + * + * Returns: Zero to continue, nonzero for no more entries. + * + * Use: Handles each incoming netgroup, attaching it to the table. + */ + +static int netg__foreach(int st, char *k, int ksz, + char *v, int vsz, char *data) +{ + char *kc, *vc; + unsigned f; + netg__sym *sng; + netg__cons *c, **link; + char *p; + int t; + + /* --- If something is amiss, then quit now --- */ + + if (st != YP_TRUE) + return (-1); + + /* --- Ignore empty lines from the original file --- */ + + if (!ksz || !vsz) + return (0); + + /* --- Build my own trashable copies of the key and value --- * + * + * Note the oddness when I copy the value string. The extra byte at the + * beginning allows me to use the same area of memory as an output buffer + * for the lexer. It must be big enough; the lexer doesn't back up; and + * that extra byte gives me somewhere to put a terminating null byte. + */ + + kc = xmalloc(ksz + 1); + memcpy(kc, k, ksz); + kc[ksz] = 0; + + vc = xmalloc(vsz + 2); + memcpy(vc + 1, v, vsz); + vc[vsz + 1] = 0; + + T( trace(TRACE_DEBUG, "debug: netgroup `%s': `%s'", kc, vc + 1); ) + + /* --- Allocate a symbol in my table --- */ + + sng = sym_find(&netg__table, kc, -1, sizeof(*sng), &f); + if (!f) + sng->cons = 0; + + /* --- Run to the end of the list --- */ + + for (link = &sng->cons; *link; link = &((*link)->cdr)) + ; + + /* --- Now start the tricky bit --- * + * + * I have to start parsing the netgroup value string. Oh, well, it + * could be worse. + * + * The parser is written so as to avoid saying things more often than + * necessary. This tends to involve @goto@s. You've been warned. + */ + + p = vc + 1; + t = netg__lex(&p, vc); + + for (;;) { + + /* --- Start with a fresh cons cell, with an empty atom attached --- */ + + c = xmalloc(sizeof(*c)); + c->car.atom = xmalloc(sizeof(*c->car.atom)); + + /* --- Restart here after an error --- * + * + * If I restart here, I can avoid freeing the cons cell reallocating + * it, which is a little silly. + */ + + duff_restart: + c->car.atom->n = c->car.atom->h = c->car.atom->u = c->car.atom->d = 0; + c->f = 0; + c->cdr = 0; + + /* --- Handle end-of-line --- */ + + if (t == tok_eof) + break; + + /* --- Handle a netgroup reference --- */ + + if (t == tok_string) { + T( trace(TRACE_DEBUG, "debug: add reference to `%s'", vc); ) + c->car.atom->n = xstrdup(vc); + *link = c; + link = &c->cdr; + t = netg__lex(&p, vc); + continue; + } + + /* --- Parse our merry way through the host--user--domain triple --- */ + + if (t != '(') + goto duff; + t = netg__lex(&p, vc); + + if (t == tok_string) { + T( trace(TRACE_DEBUG, "debug: add host `%s'", vc); ) + c->car.atom->h = xstrdup(vc); + t = netg__lex(&p, vc); + } + + if (t != ',') + goto duff_paren; + t = netg__lex(&p, vc); + + if (t == tok_string) { + T( trace(TRACE_DEBUG, "debug: add user `%s'", vc); ) + c->car.atom->u = xstrdup(vc); + t = netg__lex(&p, vc); + } + + if (t != ',') + goto duff_paren; + t = netg__lex(&p, vc); + + if (t == tok_string) { + T( trace(TRACE_DEBUG, "debug: add domain `%s'", vc); ) + c->car.atom->d = xstrdup(vc); + t = netg__lex(&p, vc); + } + + if (t != ')') + goto duff_paren; + t = netg__lex(&p, vc); + + /* --- Finished that, so insert this cons cell into the list --- */ + + *link = c; + link = &c->cdr; + continue; + + /* --- Tidy up during scanning of a triple --- * + * + * I'll search for the closing paren, and hope that I won't miss out too + * much. + */ + + duff_paren: + while (t != tok_eof && t != ')') + t = netg__lex(&p, vc); + + /* --- Other syntax oddnesses come out here --- * + * + * Snarf the token which caused the error. + */ + + duff: + moan("syntax error in netgroups line for `%s'", kc); + if (c->car.atom->n) free(c->car.atom->n); + if (c->car.atom->h) free(c->car.atom->h); + if (c->car.atom->u) free(c->car.atom->u); + if (c->car.atom->d) free(c->car.atom->d); + t = netg__lex(&p, vc); + goto duff_restart; + } + + free(kc); + free(vc); + return (0); +} + +/* --- @netg__dumpGroup@ --- * + * + * Arguments: @netg__cons *c@ = pointer to a list head + * @int lev@ = indentation level + * + * Returns: --- + * + * Use: Dumps the netgroup given. + */ + +#ifdef TRACING + +static void netg__dumpGroup(netg__cons *c, int lev) +{ + netg__cons *cc; + + if (!c) + return; + + /* --- Check for a cycle --- */ + + if (c->f & f_visit) { + trace(TRACE_DEBUG, "debug: %*scycle!", lev * 2, ""); + return; + } + + /* --- Dump the netgroup --- */ + + c->f |= f_visit; + + for (cc = c; cc; cc = cc->cdr) { + if (cc->f & f_cons) { + trace(TRACE_DEBUG, "debug: %*ssubnetgroup...", lev * 2, ""); + netg__dumpGroup(cc->car.cons, lev + 1); + } else if (cc->car.atom->n) { + trace(TRACE_DEBUG, "debug: %*sunresolved subgroup `%s'", + lev * 2, "", cc->car.atom->n); + } else { + trace(TRACE_DEBUG, "debug: %*s(%s, %s, %s)", lev * 2, "", + cc->car.atom->h ? cc->car.atom->h : "", + cc->car.atom->u ? cc->car.atom->u : "", + cc->car.atom->d ? cc->car.atom->d : ""); + } + } + + c->f &= ~f_visit; +} + +#endif + +/* --- @netg__dump@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Dumps the netgroups table. + */ + +static void netg__dump(void) +{ + sym_iter i; + netg__sym *sng; + +#ifdef TRACING + trace(TRACE_DEBUG, "debug: dumping netgroups file"); + for (sym_createIter(&i, &netg__table); (sng = sym_next(&i)) != 0; ) { + trace(TRACE_DEBUG, "debug: netgroup `%s'...", sng->_base.name); + sng->cons->f &= ~f_visit; + netg__dumpGroup(sng->cons, 1); + } +#endif +} + +/* --- @netg_iterate@, @netg_iterate_r@ --- * + * + * Arguments: @netg_iter *i@ = pointer to a netgroup iterator object + * + * Returns: --- + * + * Use: Starts iterating over the netgroups. + */ + +void netg_iterate(void) { netg_iterate_r(&netg__iter); } +void netg_iterate_r(netg_iter *i) { sym_createIter(i, &netg__table); } + +/* --- @netg_next@, @netg_next_r@ --- * + * + * Arguments: @netg_iter *i@ = pointer to a netgroup iterator object + * + * Returns: An opaque pointer to the next item, or null. + * + * Use: Returns the next netgroup. + */ + +netg *netg_next(void) { return (netg_next_r(&netg__iter)); } +netg *netg_next_r(netg_iter *i) { return (sym_next(i)); } + +/* --- @netg_name@ --- * + * + * Arguments: @netg *n@ = netgroup handle returned by @netg_next@. + * + * Returns: A pointer to the name; you may not modify this string. + * + * Use: Returns the name of a netgroup. + */ + +const char *netg_name(netg *n) { return (n->_base.name); } + +/* --- @netg_scan@ --- * + * + * Arguments: @netg *n@ = a netgroup handle returned by @netg_next@ + * @int (*proc)(netg *n, const char *host, const char *user,@ + * @const char *domain, void *ctx)@ = function to call + * for each member. + * @void *ctx@ = context pointer to pass to @proc@. + * + * Returns: Zero if all went well, or the nonzero return value from + * @proc@. + * + * Use: Passes all the members of the netgroup to a given function. + * The function is given the names, directly from the NIS + * netgroup map, except that any empty entries are passed as + * null pointers rather than empty strings. You may not modify + * any of the strings. The enumeration function, @proc@, may + * return nonzero to stop itself from being called any more; + * if this happens, the value it returns becomes the result of + * this function. If all the items are enumerated OK, this + * function returns zero. + */ + +static int netg__doScan(netg__cons *c, + netg *n, + int (*proc)(netg */*n*/, const char */*host*/, + const char */*user*/, + const char */*domain*/, void */*ctx*/), + void *ctx) +{ + int e; + + while (c) { + if (c->f & f_cons) + e = netg__doScan(c->car.cons, n, proc, ctx); + else + e = proc(n, c->car.atom->h, c->car.atom->u, c->car.atom->d, ctx); + if (e) + return (e); + c = c->cdr; + } + return (0); +} + +int netg_scan(netg *n, + int (*proc)(netg */*n*/, const char */*host*/, + const char */*user*/, const char */*domain*/, + void */*ctx*/), + void *ctx) +{ + return (netg__doScan(n->cons, n, proc, ctx)); +} + +/* --- @netg__breakCycle@ --- * + * + * Arguments: @netg__cons *c@ = pointer to a list + * + * Returns: --- + * + * Use: Scans the given list (recursively) and breaks any cycles it + * finds. + */ + +static void netg__breakCycle(netg__cons *c) +{ + netg__cons *cc; + + if (!c || c->f & f_uncycled) + return; + + c->f |= f_visit; + for (cc = c; cc; cc = cc->cdr) { + if (~cc->f & f_cons) + continue; + if (cc->car.cons->f & f_visit) { + T( trace(TRACE_DEBUG, "debug: cycle in netgroups"); ) + cc->car.cons = 0; + } else + netg__breakCycle(cc->car.cons); + } + c->f &= ~f_visit; + c->f |= f_uncycled; +} + +/* --- @netg_init@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Reads the netgroup database and turns it into something nice. + */ + +void netg_init(void) +{ + char *ypdom; + + /* --- Initialise my symbol table --- */ + + sym_createTable(&netg__table); + + /* --- Bind myself unto a YP server --- */ + + if (yp_get_default_domain(&ypdom) || + yp_bind(ypdom)) + return; + + /* --- Now try to read all the netgroup entries --- */ + + { + static struct ypall_callback ncb = { netg__foreach, 0 }; + yp_all(ypdom, "netgroup", &ncb); + } + + /* --- Unbind from the server --- */ + + yp_unbind(ypdom); + + /* --- Dump the table --- */ + + IF_TRACING(TRACE_DEBUG, netg__dump(); ) + + /* --- Now resolve all the remaining references --- */ + + { + sym_iter i; + netg__sym *sng, *ng; + netg__cons *c; + netg__atom *a; + + for (sym_createIter(&i, &netg__table); (sng = sym_next(&i)) != 0; ) { + for (c = sng->cons; c; c = c->cdr) { + if ((c->f & f_cons) == 0 && c->car.atom->n) { + a = c->car.atom; + ng = sym_find(&netg__table, a->n, -1, 0, 0); + if (!ng) { + moan("undefined netgroup `%s' (ignored)", a->n); + c->car.atom = 0; + } else { + c->car.cons = ng->cons; + c->f |= f_cons; + } + free(a->n); + free(a); + } + } + } + } + + /* --- Remove cycles in the netgroups table --- */ + + { + sym_iter i; + netg__sym *sng; + + for (sym_createIter(&i, &netg__table); (sng = sym_next(&i)) != 0; ) + sng->cons->f &= ~f_uncycled; + for (sym_createIter(&i, &netg__table); (sng = sym_next(&i)) != 0; ) + netg__breakCycle(sng->cons); + } + + /* --- Dump the table again --- */ + + IF_TRACING(TRACE_DEBUG, netg__dump(); ) +} + +/* --- @netg_reinit@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Forces a re-read of the netgroups file. + */ + +void netg_reinit(void) +{ + sym_iter i; + netg__sym *sng; + netg__cons *c, *cc; + + /* --- Remove all the old netgroups rubbish --- */ + + for (sym_createIter(&i, &netg__table); (sng = sym_next(&i)) != 0; ) { + c = sng->cons; + while (c) { + cc = c->cdr; + if (~c->f & f_cons) { + if (c->car.atom->n) free(c->car.atom->n); + if (c->car.atom->h) free(c->car.atom->h); + if (c->car.atom->u) free(c->car.atom->u); + if (c->car.atom->d) free(c->car.atom->d); + } + free(c); + c = cc; + } + sym_remove(&netg__table, sng); + } + + /* --- Now rebuild the world --- */ + + netg_init(); +} + +/*----- Test driver -------------------------------------------------------*/ + +#ifdef TEST_RIG + +int scanner(netg *n, const char *h, const char *u, const char *d, void *c) +{ + fprintf(stderr, " %s, %s, %s\n", + h ? h : "", u ? u : "", d ? d : ""); + return (0); +} + +int main(void) +{ + netg *n; + ego("netg-test"); + traceon(stderr, TRACE_ALL); + netg_init(); + for (netg_iterate(); (n = netg_next()) != 0; ) { + fprintf(stderr, "netgroup %s\n", netg_name(n)); + netg_scan(n, scanner, 0); + } + return (0); +} + +#endif + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/src/netg.h b/src/netg.h new file mode 100644 index 0000000..964acb6 --- /dev/null +++ b/src/netg.h @@ -0,0 +1,148 @@ +/* -*-c-*- + * + * $Id: netg.h,v 1.1 1997/08/07 09:45:00 mdw Exp $ + * + * A local database of netgroups + * + * (c) 1997 EBI + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of `become' + * + * `Become' is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * `Become' is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with `become'; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + /*----- Revision history --------------------------------------------------* + * + * $Log: netg.h,v $ + * Revision 1.1 1997/08/07 09:45:00 mdw + * New source file added to maintain a netgroups database. + * + */ + +#ifndef NETG_H +#define NETG_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Required headers --------------------------------------------------*/ + +#ifndef SYM_H +# include "sym.h" +#endif + +/*----- Type definitions --------------------------------------------------*/ + +typedef sym_iter netg_iter; +typedef struct netg__sym netg; + +/*----- Functions provided ------------------------------------------------*/ + +/* --- @netg_iterate@, @netg_iterate_r@ --- * + * + * Arguments: @netg_iter *i@ = pointer to a netgroup iterator object + * + * Returns: --- + * + * Use: Starts iterating over the netgroups. + */ + +extern void netg_iterate(void); +extern void netg_iterate_r(netg_iter */*i*/); + +/* --- @netg_next@, @netg_next_r@ --- * + * + * Arguments: @netg_iter *i@ = pointer to a netgroup iterator object + * + * Returns: An opaque pointer to the next item, or null. + * + * Use: Returns the next netgroup. + */ + +extern netg *netg_next(void); +extern netg *netg_next_r(netg_iter */*i*/); + +/* --- @netg_name@ --- * + * + * Arguments: @netg *n@ = netgroup handle returned by @netg_next@. + * + * Returns: A pointer to the name; you may not modify this string. + * + * Use: Returns the name of a netgroup. + */ + +extern const char *netg_name(netg */*n*/); + +/* --- @netg_scan@ --- * + * + * Arguments: @netg *n@ = a netgroup handle returned by @netg_next@ + * @int (*proc)(netg *n, const char *host, const char *user,@ + * @const char *domain, void *ctx)@ = function to call + * for each member. + * @void *ctx@ = context pointer to pass to @proc@. + * + * Returns: Zero if all went well, or the nonzero return value from + * @proc@. + * + * Use: Passes all the members of the netgroup to a given function. + * The function is given the names, directly from the NIS + * netgroup map, except that any empty entries are passed as + * null pointers rather than empty strings. You may not modify + * any of the strings. The enumeration function, @proc@, may + * return nonzero to stop itself from being called any more; + * if this happens, the value it returns becomes the result of + * this function. If all the items are enumerated OK, this + * function returns zero. + */ + +extern int netg_scan(netg */*n*/, + int (*/*proc*/)(netg */*n*/, const char */*host*/, + const char */*user*/, + const char */*domain*/, void */*ctx*/), + void */*ctx*/); + +/* --- @netg_init@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Reads the netgroup database and turns it into something nice. + */ + +extern void netg_init(void); + +/* --- @netg_reinit@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Forces a re-read of the netgroups file. + */ + +extern void netg_reinit(void); + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif