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