0202ebc654d0da5a03d149844d3b393511d52f68
3 * $Id: netg.c,v 1.6 2003/10/12 00:39:16 mdw Exp $
5 * A local database of netgroups
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of `become'
14 * `Become' is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * `Become' is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with `become'; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /*----- Revision history --------------------------------------------------*
32 * Revision 1.6 2003/10/12 00:39:16 mdw
33 * Light fixes for strange building.
35 * Revision 1.5 2003/10/12 00:14:55 mdw
36 * Major overhaul. Now uses DSA signatures rather than the bogus symmetric
37 * encrypt-and-hope thing. Integrated with mLib and Catacomb.
39 * Revision 1.4 1998/04/23 13:24:49 mdw
40 * Switch to using the ypstuff interface to YP server.
42 * Revision 1.3 1998/01/12 16:46:17 mdw
45 * Revision 1.2 1997/08/20 16:19:11 mdw
46 * Patch memory leak. Replace `name_reinit' by `name_end' for more sensible
47 * restart. Don't try to trace when tracing's turned off.
49 * Revision 1.1 1997/08/07 09:45:00 mdw
50 * New source file added to maintain a netgroups database.
54 /*----- Header files ------------------------------------------------------*/
56 /* --- ANSI headers --- */
63 /* --- Unix headers --- */
67 #include <sys/types.h>
69 #include <netinet/in.h>
71 #include <arpa/inet.h>
77 /* --- mLib headers --- */
79 #include <mLib/alloc.h>
80 #include <mLib/report.h>
82 #include <mLib/trace.h>
84 /* --- Local headers --- */
92 /*----- Type definitions --------------------------------------------------*/
94 /* --- Quick discussion --- *
96 * I've just noticed: netgroups are horrible. They form a directed graph
97 * which is really horrible; I'll have to try and turn it into something
98 * more sensible (which will essentially involve cutting cycles).
100 * The structure looks a little bit like a good ol' List (see Knuth 1 or
101 * any decent Lisp manual), but with more information in the cons cells.
104 /* --- @netg__cons@ --- */
106 typedef struct netg__cons
{
109 struct netg__cons
*cons
;
110 struct netg__atom
*atom
;
112 struct netg__cons
*cdr
;
116 f_cons
= 1, /* The @car@ is a cons cell */
117 f_visit
= 2, /* Currently threaded on this cell */
118 f_uncycled
= 4 /* Cycles removed from here on in */
121 /* --- @netg__atom@ --- */
123 typedef struct netg__atom
{
124 char *n
; /* Unresolved netgroup reference */
125 char *h
; /* Matched hostname */
126 char *u
; /* Matched user name */
127 char *d
; /* Matched domain name */
130 /* --- @netg__sym@ --- */
132 typedef struct netg__sym
{
137 /* --- Token types for the netgroup parser --- */
144 /*----- Static variables --------------------------------------------------*/
146 static sym_table netg__table
; /* Netgroup table */
147 static sym_iter netg__iter
; /* Iterator object for users */
149 /*----- Main code ---------------------------------------------------------*/
151 /* --- @netg__lex@ --- *
153 * Arguments: @const char **p@ = pointer to next unscanned character
154 * @char *q@ = pointer to output buffer
156 * Returns: Token type (either character code or a magic number).
158 * Use: Lexes a netgroups line into tokens.
161 static int netg__lex(char **p
, char *q
)
163 /* --- Skip any leading whitespace --- */
165 while (isspace((unsigned char)**p
))
168 /* --- Now work out what we've got --- */
172 if (**p
== '(' || **p
== ')' || **p
== ',')
176 while (**p
!= 0 && **p
!= '(' && **p
!= ')' &&
177 **p
!= ',' && !isspace((unsigned char)**p
));
182 /* --- @netg__foreach@ --- *
184 * Arguments: @int st@ = YP protocol-level status code
185 * @char *k@ = pointer to string containing the key
186 * @int ksz@ = length of the key string
187 * @char *v@ = pointer to string containing the value
188 * @int vsz@ = length of the value string
189 * @char *data@ = pointer to my data information
191 * Returns: Zero to continue, nonzero for no more entries.
193 * Use: Handles each incoming netgroup, attaching it to the table.
196 static int netg__foreach(int st
, char *k
, int ksz
,
197 char *v
, int vsz
, char *data
)
202 netg__cons
*c
, **link
;
206 /* --- If something is amiss, then quit now --- */
211 /* --- Ignore empty lines from the original file --- */
216 /* --- Build my own trashable copies of the key and value --- *
218 * Note the oddness when I copy the value string. The extra byte at the
219 * beginning allows me to use the same area of memory as an output buffer
220 * for the lexer. It must be big enough; the lexer doesn't back up; and
221 * that extra byte gives me somewhere to put a terminating null byte.
224 kc
= xmalloc(ksz
+ 1);
228 vc
= xmalloc(vsz
+ 2);
229 memcpy(vc
+ 1, v
, vsz
);
232 T( trace(TRACE_DEBUG
, "debug: netgroup `%s': `%s'", kc
, vc
+ 1); )
234 /* --- Allocate a symbol in my table --- */
236 sng
= sym_find(&netg__table
, kc
, -1, sizeof(*sng
), &f
);
240 /* --- Run to the end of the list --- */
242 for (link
= &sng
->cons
; *link
; link
= &((*link
)->cdr
))
245 /* --- Now start the tricky bit --- *
247 * I have to start parsing the netgroup value string. Oh, well, it
250 * The parser is written so as to avoid saying things more often than
251 * necessary. This tends to involve @goto@s. You've been warned.
255 t
= netg__lex(&p
, vc
);
259 /* --- Start with a fresh cons cell, with an empty atom attached --- */
261 c
= xmalloc(sizeof(*c
));
262 c
->car
.atom
= xmalloc(sizeof(*c
->car
.atom
));
264 /* --- Restart here after an error --- *
266 * If I restart here, I can avoid freeing the cons cell reallocating
267 * it, which is a little silly.
271 c
->car
.atom
->n
= c
->car
.atom
->h
= c
->car
.atom
->u
= c
->car
.atom
->d
= 0;
275 /* --- Handle end-of-line --- */
280 /* --- Handle a netgroup reference --- */
282 if (t
== tok_string
) {
283 T( trace(TRACE_DEBUG
, "debug: add reference to `%s'", vc
); )
284 c
->car
.atom
->n
= xstrdup(vc
);
287 t
= netg__lex(&p
, vc
);
291 /* --- Parse our merry way through the host--user--domain triple --- */
295 t
= netg__lex(&p
, vc
);
297 if (t
== tok_string
) {
298 T( trace(TRACE_DEBUG
, "debug: add host `%s'", vc
); )
299 c
->car
.atom
->h
= xstrdup(vc
);
300 t
= netg__lex(&p
, vc
);
305 t
= netg__lex(&p
, vc
);
307 if (t
== tok_string
) {
308 T( trace(TRACE_DEBUG
, "debug: add user `%s'", vc
); )
309 c
->car
.atom
->u
= xstrdup(vc
);
310 t
= netg__lex(&p
, vc
);
315 t
= netg__lex(&p
, vc
);
317 if (t
== tok_string
) {
318 T( trace(TRACE_DEBUG
, "debug: add domain `%s'", vc
); )
319 c
->car
.atom
->d
= xstrdup(vc
);
320 t
= netg__lex(&p
, vc
);
325 t
= netg__lex(&p
, vc
);
327 /* --- Finished that, so insert this cons cell into the list --- */
333 /* --- Tidy up during scanning of a triple --- *
335 * I'll search for the closing paren, and hope that I won't miss out too
340 while (t
!= tok_eof
&& t
!= ')')
341 t
= netg__lex(&p
, vc
);
343 /* --- Other syntax oddnesses come out here --- *
345 * Snarf the token which caused the error.
349 moan("syntax error in netgroups line for `%s'", kc
);
350 if (c
->car
.atom
->n
) free(c
->car
.atom
->n
);
351 if (c
->car
.atom
->h
) free(c
->car
.atom
->h
);
352 if (c
->car
.atom
->u
) free(c
->car
.atom
->u
);
353 if (c
->car
.atom
->d
) free(c
->car
.atom
->d
);
354 t
= netg__lex(&p
, vc
);
365 /* --- @netg__dumpGroup@ --- *
367 * Arguments: @netg__cons *c@ = pointer to a list head
368 * @int lev@ = indentation level
372 * Use: Dumps the netgroup given.
377 static void netg__dumpGroup(netg__cons
*c
, int lev
)
384 /* --- Check for a cycle --- */
386 if (c
->f
& f_visit
) {
387 trace(TRACE_DEBUG
, "debug: %*scycle!", lev
* 2, "");
391 /* --- Dump the netgroup --- */
395 for (cc
= c
; cc
; cc
= cc
->cdr
) {
396 if (cc
->f
& f_cons
) {
397 trace(TRACE_DEBUG
, "debug: %*ssubnetgroup...", lev
* 2, "");
398 netg__dumpGroup(cc
->car
.cons
, lev
+ 1);
399 } else if (cc
->car
.atom
->n
) {
400 trace(TRACE_DEBUG
, "debug: %*sunresolved subgroup `%s'",
401 lev
* 2, "", cc
->car
.atom
->n
);
403 trace(TRACE_DEBUG
, "debug: %*s(%s, %s, %s)", lev
* 2, "",
404 cc
->car
.atom
->h ? cc
->car
.atom
->h
: "<all-hosts>",
405 cc
->car
.atom
->u ? cc
->car
.atom
->u
: "<all-users>",
406 cc
->car
.atom
->d ? cc
->car
.atom
->d
: "<all-domains>");
415 /* --- @netg__dump@ --- *
421 * Use: Dumps the netgroups table.
426 static void netg__dump(void)
431 trace(TRACE_DEBUG
, "debug: dumping netgroups file");
432 for (sym_mkiter(&i
, &netg__table
); (sng
= sym_next(&i
)) != 0; ) {
433 trace(TRACE_DEBUG
, "debug: netgroup `%s'...", sng
->_base
.name
);
434 sng
->cons
->f
&= ~f_visit
;
435 netg__dumpGroup(sng
->cons
, 1);
441 /* --- @netg_iterate@, @netg_iterate_r@ --- *
443 * Arguments: @netg_iter *i@ = pointer to a netgroup iterator object
447 * Use: Starts iterating over the netgroups.
450 void netg_iterate(void) { netg_iterate_r(&netg__iter
); }
451 void netg_iterate_r(netg_iter
*i
) { sym_mkiter(i
, &netg__table
); }
453 /* --- @netg_next@, @netg_next_r@ --- *
455 * Arguments: @netg_iter *i@ = pointer to a netgroup iterator object
457 * Returns: An opaque pointer to the next item, or null.
459 * Use: Returns the next netgroup.
462 netg
*netg_next(void) { return (netg_next_r(&netg__iter
)); }
463 netg
*netg_next_r(netg_iter
*i
) { return (sym_next(i
)); }
465 /* --- @netg_name@ --- *
467 * Arguments: @netg *n@ = netgroup handle returned by @netg_next@.
469 * Returns: A pointer to the name; you may not modify this string.
471 * Use: Returns the name of a netgroup.
474 const char *netg_name(netg
*n
) { return (n
->_base
.name
); }
476 /* --- @netg_scan@ --- *
478 * Arguments: @netg *n@ = a netgroup handle returned by @netg_next@
479 * @int (*proc)(netg *n, const char *host, const char *user,@
480 * @const char *domain, void *ctx)@ = function to call
482 * @void *ctx@ = context pointer to pass to @proc@.
484 * Returns: Zero if all went well, or the nonzero return value from
487 * Use: Passes all the members of the netgroup to a given function.
488 * The function is given the names, directly from the NIS
489 * netgroup map, except that any empty entries are passed as
490 * null pointers rather than empty strings. You may not modify
491 * any of the strings. The enumeration function, @proc@, may
492 * return nonzero to stop itself from being called any more;
493 * if this happens, the value it returns becomes the result of
494 * this function. If all the items are enumerated OK, this
495 * function returns zero.
498 static int netg__doScan(netg__cons
*c
,
500 int (*proc
)(netg */
*n*/
, const char */
*host*/
,
501 const char */
*user*/
,
502 const char */
*domain*/
, void */
*ctx*/
),
509 e
= netg__doScan(c
->car
.cons
, n
, proc
, ctx
);
511 e
= proc(n
, c
->car
.atom
->h
, c
->car
.atom
->u
, c
->car
.atom
->d
, ctx
);
519 int netg_scan(netg
*n
,
520 int (*proc
)(netg */
*n*/
, const char */
*host*/
,
521 const char */
*user*/
, const char */
*domain*/
,
525 return (netg__doScan(n
->cons
, n
, proc
, ctx
));
528 /* --- @netg__breakCycle@ --- *
530 * Arguments: @netg__cons *c@ = pointer to a list
534 * Use: Scans the given list (recursively) and breaks any cycles it
538 static void netg__breakCycle(netg__cons
*c
)
542 if (!c
|| c
->f
& f_uncycled
)
546 for (cc
= c
; cc
; cc
= cc
->cdr
) {
549 if (cc
->car
.cons
->f
& f_visit
) {
550 T( trace(TRACE_DEBUG
, "debug: cycle in netgroups"); )
553 netg__breakCycle(cc
->car
.cons
);
559 /* --- @netg_init@ --- *
565 * Use: Reads the netgroup database and turns it into something nice.
570 /* --- Initialise my symbol table --- */
572 sym_create(&netg__table
);
574 /* --- Bind myself unto a YP server --- */
580 /* --- Now try to read all the netgroup entries --- */
583 static struct ypall_callback ncb
= { netg__foreach
, 0 };
584 yp_all(yp_domain
, "netgroup", &ncb
);
587 /* --- Dump the table --- */
589 IF_TRACING(TRACE_DEBUG
, netg__dump(); )
591 /* --- Now resolve all the remaining references --- */
599 for (sym_mkiter(&i
, &netg__table
); (sng
= sym_next(&i
)) != 0; ) {
600 for (c
= sng
->cons
; c
; c
= c
->cdr
) {
601 if ((c
->f
& f_cons
) == 0 && c
->car
.atom
->n
) {
603 ng
= sym_find(&netg__table
, a
->n
, -1, 0, 0);
605 moan("undefined netgroup `%s' (ignored)", a
->n
);
608 c
->car
.cons
= ng
->cons
;
618 /* --- Remove cycles in the netgroups table --- */
624 for (sym_mkiter(&i
, &netg__table
); (sng
= sym_next(&i
)) != 0; )
625 sng
->cons
->f
&= ~f_uncycled
;
626 for (sym_mkiter(&i
, &netg__table
); (sng
= sym_next(&i
)) != 0; )
627 netg__breakCycle(sng
->cons
);
630 /* --- Dump the table again --- */
632 IF_TRACING(TRACE_DEBUG
, netg__dump(); )
635 /* --- @netg_end@ --- *
641 * Use: Empties the netgroups database.
650 /* --- Remove all the old netgroups rubbish --- */
652 for (sym_mkiter(&i
, &netg__table
); (sng
= sym_next(&i
)) != 0; ) {
656 if (~c
->f
& f_cons
) {
657 if (c
->car
.atom
->n
) free(c
->car
.atom
->n
);
658 if (c
->car
.atom
->h
) free(c
->car
.atom
->h
);
659 if (c
->car
.atom
->u
) free(c
->car
.atom
->u
);
660 if (c
->car
.atom
->d
) free(c
->car
.atom
->d
);
666 sym_remove(&netg__table
, sng
);
669 sym_destroy(&netg__table
);
672 /*----- Test driver -------------------------------------------------------*/
676 int scanner(netg
*n
, const char *h
, const char *u
, const char *d
, void *c
)
678 fprintf(stderr
, " %s, %s, %s\n",
679 h ? h
: "<any>", u ? u
: "<any>", d ? d
: "<any>");
687 trace_on(stderr
, TRACE_ALL
);
689 for (netg_iterate(); (n
= netg_next()) != 0; ) {
690 fprintf(stderr
, "netgroup %s\n", netg_name(n
));
691 netg_scan(n
, scanner
, 0);
698 /*----- That's all, folks -------------------------------------------------*/