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