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