Complete rewrite to support class trees. Makes the behaviour of the set
[become] / src / class.c
1 /* -*-c-*-
2 *
3 * $Id: class.c,v 1.6 1997/09/17 10:14:56 mdw Exp $
4 *
5 * Handling classes of things nicely
6 *
7 * (c) 1997 EBI
8 */
9
10 /*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of `become'
13 *
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.
18 *
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.
23 *
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.
27 */
28
29 /*----- Revision history --------------------------------------------------*
30 *
31 * $Log: class.c,v $
32 * Revision 1.6 1997/09/17 10:14:56 mdw
33 * Complete rewrite to support class trees. Makes the behaviour of the set
34 * operators much more logical.
35 *
36 * Revision 1.5 1997/08/20 16:16:13 mdw
37 * Patch memory leak. Don't try to trace when tracing's turned off.
38 *
39 * Revision 1.4 1997/08/07 09:56:37 mdw
40 * (Log entry for previous version is bogus.) Minor changes to host
41 * checking code.
42 *
43 * Revision 1.2 1997/08/04 10:24:21 mdw
44 * Sources placed under CVS control.
45 *
46 * Revision 1.1 1997/07/21 13:47:52 mdw
47 * Initial revision
48 *
49 */
50
51 /*----- Header files ------------------------------------------------------*/
52
53 /* --- ANSI headers --- */
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58
59 /* --- Unix headers --- */
60
61 #include <sys/types.h>
62 #include <sys/socket.h>
63
64 #include <netinet/in.h>
65
66 #include <arpa/inet.h>
67
68 #include <netdb.h>
69
70 /* --- Local headers --- */
71
72 #include "become.h"
73 #include "class.h"
74 #include "sym.h"
75 #include "utils.h"
76
77 /*----- Global variables --------------------------------------------------*/
78
79 static class_node class__all = { clType_all | clNode_any, -1, { 0 }};
80 class_node *class_all = &class__all;
81
82 static class_node class__none = { clType_all | clNode_any, -1, { 0 }};
83 class_node *class_none = &class__none;
84
85 /*----- Wildcard matching -------------------------------------------------*/
86
87 /* --- @class__wildMatch@ --- *
88 *
89 * Arguments: @const char *pat@ = pointer to pattern string
90 * @const char *p@ = pointer to target string
91 *
92 * Returns: Zero if no match, nonzero if match.
93 *
94 * Use: Wildcard-matches the pattern against the target string.
95 */
96
97 static int class__wildMatch(const char *pat, const char *p)
98 {
99 for (;;) {
100 if (*pat == 0 && *p == 0)
101 return (42); /* For sadism's sake */
102 else if (*pat == '*') {
103 while (*pat == '*')
104 pat++;
105 do {
106 if (class__wildMatch(pat, p))
107 return (27); /* Nyahaha */
108 p++;
109 } while (*p);
110 return (pat[1] == 0);
111 } else if (*pat == '?' || *pat == *p)
112 p++, pat++;
113 else
114 return (0);
115 }
116 }
117
118 /*----- Creating new class nodes ------------------------------------------*/
119
120 /* --- @class_fromString@ --- *
121 *
122 * Arguments: @unsigned type@ = a type field
123 * @const char *s@ = pointer to string to copy
124 *
125 * Returns: A pointer to a class node containing that string, typed to
126 * be the right thing.
127 *
128 * Use: Given a string, wrap a class node around it. The node has
129 * one reference (the one you get returned). The string is
130 * copied, so you can get rid of your original one if you like.
131 */
132
133 class_node *class_fromString(unsigned type, const char *s)
134 {
135 class_node *c = xmalloc(sizeof(*c));
136 c->type = type | clNode_immed;
137 if (s[strcspn(s, "*?")] == 0)
138 c->type |= clFlag_friendly;
139 c->ref = 1;
140 c->v.s = xstrdup(s);
141 return (c);
142 }
143
144 /* --- @class_fromUser@ --- *
145 *
146 * Arguments: @unsigned type@ = a type field
147 * @uid_t u@ = a user-id number
148 *
149 * Returns: A pointer to a class node containing the uid, typed to be
150 * the thing you asked for. Hopefully this will be
151 * @clType_user@.
152 *
153 * Use: Given a uid, wrap a class node around it.
154 */
155
156 class_node *class_fromUser(unsigned type, uid_t u)
157 {
158 class_node *c = xmalloc(sizeof(*c));
159 c->type = type | clNode_immed | clFlag_friendly;
160 c->ref = 1;
161 c->v.u = u;
162 return (c);
163 }
164
165 /*----- Reference counter tricks ------------------------------------------*/
166
167 /* --- @class_inc@ --- *
168 *
169 * Arguments: @class_node *c@ = pointer to a class block
170 *
171 * Returns: ---
172 *
173 * Use: Adds a reference to the class definition.
174 */
175
176 void class_inc(class_node *c)
177 {
178 if (c != class_all && c != class_none)
179 c->ref++;
180 }
181
182 /* --- @class_dec@ --- *
183 *
184 * Arguments: @class_node *c@ = pointer to a class block
185 *
186 * Returns: ---
187 *
188 * Use: Removes a reference to a class block.
189 */
190
191 void class_dec(class_node *c)
192 {
193 class_node *cc;
194
195 for (cc = 0; c; c = cc, cc = 0) {
196 if (c == class_all || c == class_none || --c->ref)
197 continue;
198 switch (c->type & clNode_mask) {
199 case clNode_any:
200 /* Nothing to do */
201 break;
202 case clNode_immed:
203 if (c->type & (clType_host | clType_command))
204 free(c->v.s);
205 break;
206 case clNode_hash:
207 sym_destroyTable(&c->v.t);
208 break;
209 case clNode_union:
210 case clNode_diff:
211 case clNode_isect:
212 class_dec(c->v.c.l);
213 cc = c->v.c.r;
214 break;
215 }
216 free(c);
217 }
218 }
219
220 /* --- @class_mod@ --- *
221 *
222 * Arguments: @class_node *c@ = pointer to a class node
223 *
224 * Returns: A pointer to a class node, maybe the same one, maybe not,
225 * with a reference count of 1, containing the same data.
226 *
227 * Use: Gives you a node which you can modify. Don't call this
228 * for @class_all@ or @class_none@.
229 */
230
231 class_node *class_mod(class_node *c)
232 {
233 class_node *cc;
234
235 if (c->ref == 1)
236 return (c);
237
238 cc = xmalloc(sizeof(*cc));
239 cc->type = c->type;
240 cc->ref = 1;
241 switch (c->type & clNode_mask) {
242 case clNode_any:
243 die("internal error: class_mod called on non-modifiable class node");
244 break;
245
246 case clNode_immed:
247 if (c->type & clType_user)
248 cc->v.u = c->v.u;
249 else
250 cc->v.s = xstrdup(c->v.s);
251 break;
252
253 case clNode_hash: {
254 sym_iter i;
255 sym_base *b;
256
257 sym_createTable(&cc->v.t);
258 for (sym_createIter(&i, &c->v.t); (b = sym_next(&i)) != 0; )
259 sym_find(&cc->v.t, b->name, b->len, sizeof(sym_base), 0);
260 } break;
261
262 case clNode_union:
263 case clNode_diff:
264 case clNode_isect:
265 cc->v.c.l = c->v.c.l;
266 cc->v.c.r = c->v.c.r;
267 class_inc(cc->v.c.l);
268 class_inc(cc->v.c.r);
269 break;
270 }
271
272 class_dec(c);
273 return (cc);
274 }
275
276 /*----- Some weirder operations on classes --------------------------------*/
277
278 /* --- @class__hashify@ --- *
279 *
280 * Arguments: @class_node *c@ = pointer to a node
281 *
282 * Returns: A pointer to a hash node containing the node's value.
283 *
284 * Use: The original node must have type `immediate', and it must
285 * be friendly. The old reference is discarded -- you get this
286 * one instead.
287 */
288
289 static class_node *class__hashify(class_node *c)
290 {
291 /* --- Some sanity checking --- */
292
293 if (~c->type & clFlag_friendly)
294 die("internal error: class__hashify can't hashify unfriendly nodes");
295 if ((c->type & clNode_mask) != clNode_immed)
296 die("internal error: class__hashify can't hashify non-immediate nodes");
297
298 /* --- Split off a private copy of the node --- */
299
300 c = class_mod(c);
301
302 c->type = (c->type & clType_mask) | clNode_hash | clFlag_friendly;
303
304 if (c->type & clType_user) {
305 uid_t u = c->v.u;
306 sym_createTable(&c->v.t);
307 sym_find(&c->v.t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
308 } else {
309 char *s = c->v.s;
310 sym_createTable(&c->v.t);
311 sym_find(&c->v.t, s, -1, sizeof(sym_base), 0);
312 free(s);
313 }
314
315 return (c);
316 }
317
318 /*----- Arithmetic on classes ---------------------------------------------*/
319
320 /* --- @class__binop@ --- *
321 *
322 * Arguments: @class_node *l@ = left argument
323 * @class_node *r@ = right argument
324 * @unsigned op@ = the binop code
325 *
326 * Returns: A class node representing the result of a binary operation
327 * upon two classes.
328 *
329 * Use: Performs a binary operation on classes. If the types don't
330 * match, then a null pointer is returned. Both @l@ and @r@
331 * may be modified, and will be decremented before they get
332 * returned to you. If you don't want that to happen, ensure
333 * that you've claimed a reference to the original versions.
334 *
335 * If both nodes are `friendly' (see below), then an attempt is
336 * made to combine them sensibly using a hashtable.
337 *
338 * If one or both nodes is/are unfriendly, a binop node is
339 * created with type @op@ to allow the matcher to decide on
340 * membership appropriately at match time.
341 *
342 * A friendly node is one which can be placed in a hash table to
343 * speed up searching. It's friendly, because it doesn't mind
344 * living with other nodes. Uid numbers are friendly.
345 * Wildcarded strings aren't. Hashtables are trivially
346 * friendly.
347 */
348
349 class_node *class__binop(class_node *l, class_node *r, int op)
350 {
351 unsigned type = l->type & r->type & clType_mask;
352 unsigned lnode = l->type & clNode_mask, rnode = r->type & clNode_mask;
353
354 /* --- Check for compatible types --- */
355
356 if (!type) {
357 class_dec(l);
358 class_dec(r);
359 return (0);
360 }
361
362 /* --- Handle `friendly' nodes --- */
363
364 if ((l->type & r->type & clFlag_friendly)) {
365
366 /* --- Consider promoting an item to a hash --- *
367 *
368 * If both are immediate nodes, and they're both `friendly', we can
369 * profitably hash them together.
370 *
371 * Life gets complicated when we do subtraction, because it's not
372 * commutative. In this case, I have to promote the left operand anyway.
373 */
374
375 if (lnode == clNode_immed &&
376 (rnode == clNode_immed || op == clNode_diff)) {
377
378 /* --- Quick check for triviality --- *
379 *
380 * There are some more short-cuts I can employ if the values are
381 * the same.
382 */
383
384 if (rnode == clNode_immed) {
385
386 /* --- See whether the two items are equal --- */
387
388 int eq = (type & clType_user ?
389 l->v.u == r->v.u : strcmp(l->v.s, r->v.s) == 0);
390
391 /* --- Now do something appropriate --- */
392
393 switch (op) {
394 case clNode_union:
395 if (eq) {
396 class_dec(r);
397 return (l);
398 }
399 break;
400 case clNode_diff:
401 if (eq) {
402 class_dec(l);
403 class_dec(r);
404 return (class_none);
405 }
406 break;
407 case clNode_isect:
408 if (eq) {
409 class_dec(r);
410 return (l);
411 } else {
412 class_dec(l);
413 class_dec(r);
414 return (class_none);
415 }
416 break;
417 }
418 }
419
420 /* --- Turn @l@ into a hash containing itself --- */
421
422 l = class__hashify(l);
423 lnode = clNode_hash;
424 }
425
426 /* --- Otherwise, make @l@ the hash --- *
427 *
428 * Both @l@ and @r@ are friendly. Since they're not both immediates,
429 * one must be a hash.
430 */
431
432 else if ((l->type & clNode_mask) == clNode_immed) {
433 class_node *tn;
434 unsigned tt;
435
436 tn = l, l = r, r = tn;
437 tt = lnode, lnode = rnode, rnode = tt;
438 }
439
440 /* --- Now merge @r@ with @l@ --- */
441
442 l = class_mod(l);
443
444 switch (op) {
445
446 /* --- The union operation isn't hard --- */
447
448 case clNode_union:
449 if (rnode == clNode_immed) {
450 if (type & clType_user) {
451 sym_find(&l->v.t, (char *)&r->v.u,
452 sizeof(r->v.u), sizeof(sym_base), 0);
453 } else
454 sym_find(&l->v.t, r->v.s, -1, sizeof(sym_base), 0);
455 } else {
456 sym_iter i;
457 sym_base *b;
458
459 for (sym_createIter(&i, &r->v.t); (b = sym_next(&i)) != 0; )
460 sym_find(&l->v.t, b->name, b->len, sizeof(sym_base), 0);
461 }
462 break;
463
464 /* --- Set difference is similar in spirit --- */
465
466 case clNode_diff:
467 if (rnode == clNode_immed) {
468 sym_base *f;
469
470 if (type & clType_user)
471 f = sym_find(&l->v.t, (char *)&r->v.u, sizeof(r->v.u), 0, 0);
472 else
473 f = sym_find(&l->v.t, r->v.s, -1, 0, 0);
474 if (f)
475 sym_remove(&l->v.t, f);
476 } else {
477 sym_iter i;
478 sym_base *b, *f;
479
480 for (sym_createIter(&i, &r->v.t); (b = sym_next(&i)) != 0; ) {
481 if ((f = sym_find(&l->v.t, b->name, b->len, 0, 0)) != 0)
482 sym_remove(&l->v.t, f);
483 }
484 }
485 break;
486
487 /* --- Intersection is wild and wacky --- */
488
489 case clNode_isect:
490 if (rnode == clNode_immed) {
491 sym_base *f;
492
493 if (type & clType_user)
494 f = sym_find(&l->v.t, (char *)&r->v.u, sizeof(r->v.u), 0, 0);
495 else
496 f = sym_find(&l->v.t, r->v.s, -1, 0, 0);
497 if (f) {
498 class_dec(l);
499 return (r);
500 } else {
501 class_dec(l);
502 class_dec(r);
503 return (class_none);
504 }
505 } else {
506 sym_iter i;
507 sym_base *b;
508
509 for (sym_createIter(&i, &l->v.t); (b = sym_next(&i)) != 0; ) {
510 if (!sym_find(&r->v.t, b->name, b->len, 0, 0))
511 sym_remove(&l->v.t, b);
512 }
513 }
514 break;
515 }
516
517 /* --- Now trim the @l@ table to size --- *
518 *
519 * It may have lost a load of elements. Maybe it can be represented
520 * better as an immediate or even as @class_none@.
521 */
522
523 {
524 sym_iter i;
525 sym_base *b;
526
527 class_dec(r);
528
529 sym_createIter(&i, &l->v.t);
530 if ((b = sym_next(&i)) == 0) {
531 class_dec(l);
532 return (class_none);
533 }
534 if (!sym_next(&i)) {
535 if (type & clType_user) {
536 uid_t u = *(uid_t *)b->name;
537 sym_destroyTable(&l->v.t);
538 l->type = (l->type & ~clNode_mask) | clNode_immed;
539 l->v.u = u;
540 } else {
541 char *s = xstrdup(b->name);
542 sym_destroyTable(&l->v.t);
543 l->type = (l->type & ~clNode_mask) | clNode_immed;
544 l->v.s = s;
545 }
546 }
547 }
548
549 /* --- Done --- */
550
551 return (l);
552 }
553
554 /* --- Unfriendly nodes --- *
555 *
556 * Create a binop node and return that. If @l@ is a binop node, and @r@
557 * isn't, and the operation isn't set difference (i.e., it's commutative)
558 * then swap the two over to lessen the depth of recursion later.
559 */
560
561 else {
562 class_node *c = xmalloc(sizeof(*c));
563
564 c->type = type | op;
565 c->ref = 1;
566 if (lnode >= clNode_binop && rnode < clNode_binop && op != clNode_diff) {
567 c->v.c.l = r;
568 c->v.c.r = l;
569 } else {
570 c->v.c.l = l;
571 c->v.c.r = r;
572 }
573 return (c);
574 }
575 }
576
577 /* --- @class_union@ --- *
578 *
579 * Arguments: @class_node *l@ = left argument
580 * @class_node *r@ = right argument
581 *
582 * Returns: A class node representing the union of the two classes.
583 *
584 * Use: Performs the union operation on classes. If the types don't
585 * match, then a null pointer is returned. Both @l@ and @r@
586 * may be modified, and will be decremented before they get
587 * returned to you. If you don't want that to happen, ensure
588 * that you've claimed a reference to the original versions.
589 */
590
591 class_node *class_union(class_node *l, class_node *r)
592 {
593 /* --- Check for the really simple cases --- */
594
595 if (l == class_all || r == class_all) {
596 class_dec(l);
597 class_dec(r);
598 return (class_all);
599 }
600
601 if (l == class_none)
602 return (r);
603 if (r == class_none)
604 return (l);
605
606 /* --- Do the job --- */
607
608 return (class__binop(l, r, clNode_union));
609 }
610
611 /* --- @class_diff@ --- *
612 *
613 * Arguments: @class_node *l@ = left argument
614 * @class_node *r@ = right argument
615 *
616 * Returns: A class node representing the difference of the two classes.
617 *
618 * Use: Performs the set difference operation on classes. If the
619 * types don't match, then a null pointer is returned. Both
620 * @l@ and @r@ may be modified, and will be decremented before
621 * they get returned to you. If you don't want that to happen,
622 * ensure that you've claimed a reference to the original
623 * versions.
624 */
625
626 class_node *class_diff(class_node *l, class_node *r)
627 {
628 /* --- Check for the really simple cases --- */
629
630 if (l == class_none || r == class_all) {
631 class_dec(l);
632 class_dec(r);
633 return (class_none);
634 }
635
636 if (r == class_none)
637 return (l);
638
639 /* --- Do the job --- */
640
641 return (class__binop(l, r, clNode_diff));
642 }
643
644 /* --- @class_isect@ --- *
645 *
646 * Arguments: @class_node *l@ = left argument
647 * @class_node *r@ = right argument
648 *
649 * Returns: A class node representing the intersection of the two
650 * classes.
651 *
652 * Use: Performs the intersecion operation on classes. If the types
653 * don't match, then a null pointer is returned. Both @l@ and
654 * @r@ may be modified, and will be decremented before they get
655 * returned to you. If you don't want that to happen, ensure
656 * that you've claimed a reference to the original versions.
657 */
658
659 class_node *class_isect(class_node *l, class_node *r)
660 {
661 /* --- Check for the really simple cases --- */
662
663 if (l == class_none || r == class_none) {
664 class_dec(l);
665 class_dec(r);
666 return (class_none);
667 }
668
669 if (l == class_all)
670 return (r);
671 if (r == class_all)
672 return (l);
673
674 /* --- Do the job --- */
675
676 return (class__binop(l, r, clNode_isect));
677 }
678
679 /*----- Building the predefined classes -----------------------------------*/
680
681 /* --- @class_addUser@ --- *
682 *
683 * Arguments: @class_node *c@ = pointer to a class node (may be null)
684 * @uid_t u@ = user id number
685 *
686 * Returns: Pointer to the combined node.
687 *
688 * Use: Adds a user to a node, maybe hashifying it.
689 */
690
691 class_node *class_addUser(class_node *c, uid_t u)
692 {
693 if (!c)
694 return (class_fromUser(clType_user, u));
695 if ((c->type & clNode_mask) == clNode_immed)
696 c = class__hashify(c);
697 sym_find(&c->v.t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
698 return (c);
699 }
700
701 /* --- @class_addString@ --- *
702 *
703 * Arguments: @class_node *c@ = pointer to a class node (may be null)
704 * @const char *s@ = pointer to a string
705 *
706 * Returns: Pointer to the combined node.
707 *
708 * Use: Adds a user to a node, maybe hashifying it.
709 */
710
711 class_node *class_addString(class_node *c, const char *s)
712 {
713 class_node *n = class_fromString(clType_host, s); /* hack */
714 if (c)
715 return (class_union(c, n));
716 else
717 return (n);
718 }
719
720 /*----- Matching functions ------------------------------------------------*/
721
722 /* --- @class_matchUser@ --- *
723 *
724 * Arguments: @class_node *c@ = pointer to root class node
725 * @uid_t u@ = user id number
726 *
727 * Returns: Nonzero if it matches, zero if it doesn't.
728 *
729 * Use: Determines whether a user is matched by a class. Assumes
730 * that the types are correct.
731 */
732
733 int class_matchUser(class_node *c, uid_t u)
734 {
735 class_node *cc;
736
737 for (cc = 0; c; c = cc, cc = 0) {
738 if (c == class_none)
739 return (0);
740 if (c == class_all)
741 return (1);
742 switch (c->type & clNode_mask) {
743 case clNode_immed:
744 return (u == c->v.u);
745 break;
746 case clNode_hash:
747 return (sym_find(&c->v.t, (char *)&u, sizeof(u), 0, 0) != 0);
748 break;
749 case clNode_union:
750 if (class_matchUser(c->v.c.l, u))
751 return (1);
752 cc = c->v.c.r;
753 break;
754 case clNode_isect:
755 if (!class_matchUser(c->v.c.l, u))
756 return (0);
757 cc = c->v.c.r;
758 break;
759 case clNode_diff:
760 return (class_matchUser(c->v.c.l, u) &&
761 !class_matchUser(c->v.c.r, u));
762 break;
763 }
764 }
765
766 die("internal error: can't get here in class_matchUser");
767 return (0);
768 }
769
770 /* --- @class_matchCommand@ --- *
771 *
772 * Arguments: @class_node *c@ = pointer to root class node
773 * @const char *s@ = pointer to a string
774 *
775 * Returns: Nonzero if it matches, zero if it doesn't.
776 *
777 * Use: Determines whether a string is matched by a class. Assumes
778 * that the types are correct.
779 */
780
781 int class_matchCommand(class_node *c, const char *s)
782 {
783 class_node *cc;
784
785 for (cc = 0; c; c = cc, cc = 0) {
786 if (c == class_none)
787 return (0);
788 if (c == class_all)
789 return (1);
790 switch (c->type & clNode_mask) {
791 case clNode_immed:
792 return (class__wildMatch(c->v.s, s));
793 break;
794 case clNode_hash:
795 return (sym_find(&c->v.t, s, -1, 0, 0) != 0);
796 break;
797 case clNode_union:
798 if (class_matchCommand(c->v.c.l, s))
799 return (1);
800 cc = c->v.c.r;
801 break;
802 case clNode_isect:
803 if (!class_matchCommand(c->v.c.l, s))
804 return (0);
805 cc = c->v.c.r;
806 break;
807 case clNode_diff:
808 return (class_matchCommand(c->v.c.l, s) &&
809 !class_matchCommand(c->v.c.r, s));
810 break;
811 }
812 }
813
814 die("internal error: can't get here in class_matchCommand");
815 return (0);
816 }
817
818 /* --- @class_matchHost@ --- *
819 *
820 * Arguments: @class_node *c@ = pointer to root class node
821 * @struct in_addr a@ = IP address to match
822 *
823 * Returns: Nonzero if it matches, zero if it doesn't.
824 *
825 * Use: Determines whether a host matches a host class. Assumes
826 * that the types are correct. The actual mechanism is a bit
827 * odd here, but I think this is the Right Thing. At each stage
828 * I try to match %%@/all/%% of the possible names for the host.
829 * Thus host `splat' with address 1.2.3.4 would fail to match
830 * the class "1.2.*" - "splat". This seems to be what the
831 * author intuitively expects. It's just a bit weird.
832 */
833
834 static int class__doMatchHost(class_node *c, const char *ip,
835 const char *name, char **aliases)
836 {
837 class_node *cc;
838
839 for (cc = 0; c; c = cc, cc = 0) {
840 if (c == class_none)
841 return (0);
842 if (c == class_all)
843 return (1);
844 switch (c->type & clNode_mask) {
845 case clNode_immed:
846 if ((ip && class__wildMatch(c->v.s, ip)) ||
847 (name && class__wildMatch(c->v.s, name)))
848 return (1);
849 if (aliases) for (; *aliases; aliases++) {
850 if (class__wildMatch(c->v.s, *aliases))
851 return (1);
852 }
853 return (0);
854 break;
855 case clNode_hash:
856 if ((ip && sym_find(&c->v.t, ip, -1, 0, 0)) ||
857 (name && sym_find(&c->v.t, name, -1, 0, 0)))
858 return (1);
859 if (aliases) for (; *aliases; aliases++) {
860 if (sym_find(&c->v.t, *aliases, -1, 0, 0))
861 return (1);
862 }
863 return (0);
864 break;
865 case clNode_union:
866 if (class__doMatchHost(c->v.c.l, ip, name, aliases))
867 return (1);
868 cc = c->v.c.r;
869 break;
870 case clNode_isect:
871 if (!class__doMatchHost(c->v.c.l, ip, name, aliases))
872 return (0);
873 cc = c->v.c.r;
874 break;
875 case clNode_diff:
876 return (class__doMatchHost(c->v.c.l, ip, name, aliases) &&
877 !class__doMatchHost(c->v.c.r, ip, name, aliases));
878 break;
879 }
880 }
881
882 die("internal error: can't get here in class_matchUser");
883 return (0);
884 }
885
886 int class_matchHost(class_node *c, struct in_addr a)
887 {
888 char *ip, *name, **aliases;
889 struct hostent *h;
890
891 ip = inet_ntoa(a);
892 if ((h = gethostbyaddr((char *)&a, sizeof(a), AF_INET)) != 0) {
893 name = h->h_name;
894 aliases = h->h_aliases;
895 } else {
896 name = 0;
897 aliases = 0;
898 }
899
900 return (class__doMatchHost(c, ip, name, aliases));
901 }
902
903 /*----- Debugging code ----------------------------------------------------*/
904
905 /* --- @class_dump@ --- *
906 *
907 * Argumemnts: @class_node *c@ = pointer to root node
908 * @int indent@ = indent depth
909 *
910 * Returns: ---
911 *
912 * Use: Dumps a class to the trace output.
913 */
914
915 void class_dump(class_node *c, int indent)
916 {
917 #ifdef TRACING
918
919 static char *types[] = {
920 "<duff>",
921 "user",
922 "command",
923 "<duff>",
924 "host"
925 };
926
927 static char *nodes[] = {
928 "<duff>",
929 "<magical>",
930 "immediate",
931 "hash",
932 "binop: union",
933 "binop: difference",
934 "binop: intersection"
935 };
936
937 /* --- Handle some magical cases --- */
938
939 if (c == class_all) {
940 trace(TRACE_RULE, "rule:%*s class ALL", indent * 2, "");
941 return;
942 }
943 if (c == class_none) {
944 trace(TRACE_RULE, "rule:%*s class NONE", indent * 2, "");
945 return;
946 }
947
948 /* --- Dump basic type information --- */
949
950 trace(TRACE_RULE, "rule:%*s type == [%s], node type == [%s]%s",
951 indent * 2, "",
952 types[c->type & clType_mask],
953 nodes[(c->type & clNode_mask) >> 4],
954 (c->type & clFlag_friendly) ? " Friendly" : "");
955
956 /* --- Now trace the contents --- */
957
958 switch (c->type & clNode_mask) {
959 case clNode_immed:
960 if (c->type & clType_user) {
961 trace(TRACE_RULE, "rule:%*s user %lu",
962 indent * 2, "", (unsigned long)c->v.u);
963 } else
964 trace(TRACE_RULE, "rule:%*s `%s'", indent * 2, "", c->v.s);
965 break;
966 case clNode_hash: {
967 sym_iter i;
968 sym_base *b;
969
970 for (sym_createIter(&i, &c->v.t); (b = sym_next(&i)) != 0; ) {
971 if (c->type & clType_user) {
972 trace(TRACE_RULE, "rule:%*s user %lu",
973 indent * 2, "", (unsigned long)*(uid_t *)b->name);
974 } else
975 trace(TRACE_RULE, "rule:%*s `%s'", indent * 2, "", b->name);
976 }
977 } break;
978 case clNode_union:
979 case clNode_diff:
980 case clNode_isect:
981 class_dump(c->v.c.l, indent + 1);
982 class_dump(c->v.c.r, indent + 1);
983 break;
984 }
985
986 #endif
987 }
988
989 /*----- That's all, folks -------------------------------------------------*/