chiark / gitweb /
Major overhaul. Now uses DSA signatures rather than the bogus symmetric
[become] / src / class.c
CommitLineData
c4f2d992 1/* -*-c-*-
2 *
f60a3434 3 * $Id: class.c,v 1.9 2003/10/12 00:14:55 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 $
f60a3434 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 *
dd9ab078 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 *
c758e654 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
50a87c1f 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
51cf22e0 48 * Patch memory leak. Don't try to trace when tracing's turned off.
49 *
4f67acfa 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.
607937a4 53 *
03f996bd 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
c4f2d992 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
f60a3434 81/* --- mLib headers --- */
82
83#include <mLib/alloc.h>
84#include <mLib/report.h>
85#include <mLib/sym.h>
86
c4f2d992 87/* --- Local headers --- */
88
03f996bd 89#include "become.h"
c4f2d992 90#include "class.h"
c4f2d992 91
92/*----- Global variables --------------------------------------------------*/
93
50a87c1f 94static class_node class__all = { clType_all | clNode_any, -1, { 0 }};
95class_node *class_all = &class__all;
96
97static class_node class__none = { clType_all | clNode_any, -1, { 0 }};
98class_node *class_none = &class__none;
c4f2d992 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
112static 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++;
dd9ab078 120 if (!*pat)
121 return (58);
c4f2d992 122 do {
123 if (class__wildMatch(pat, p))
124 return (27); /* Nyahaha */
125 p++;
126 } while (*p);
dd9ab078 127 return (0);
c4f2d992 128 } else if (*pat == '?' || *pat == *p)
129 p++, pat++;
130 else
131 return (0);
132 }
133}
134
50a87c1f 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
150class_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}
c4f2d992 160
50a87c1f 161/* --- @class_fromUser@ --- *
c4f2d992 162 *
50a87c1f 163 * Arguments: @unsigned type@ = a type field
164 * @uid_t u@ = a user-id number
c4f2d992 165 *
50a87c1f 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@.
c4f2d992 169 *
50a87c1f 170 * Use: Given a uid, wrap a class node around it.
c4f2d992 171 */
172
50a87c1f 173class_node *class_fromUser(unsigned type, uid_t u)
c4f2d992 174{
50a87c1f 175 class_node *c = xmalloc(sizeof(*c));
176 c->type = type | clNode_immed | clFlag_friendly;
c4f2d992 177 c->ref = 1;
50a87c1f 178 c->v.u = u;
c4f2d992 179 return (c);
180}
181
50a87c1f 182/*----- Reference counter tricks ------------------------------------------*/
183
c4f2d992 184/* --- @class_inc@ --- *
185 *
50a87c1f 186 * Arguments: @class_node *c@ = pointer to a class block
c4f2d992 187 *
188 * Returns: ---
189 *
190 * Use: Adds a reference to the class definition.
191 */
192
50a87c1f 193void class_inc(class_node *c)
c4f2d992 194{
50a87c1f 195 if (c != class_all && c != class_none)
c4f2d992 196 c->ref++;
197}
198
199/* --- @class_dec@ --- *
200 *
50a87c1f 201 * Arguments: @class_node *c@ = pointer to a class block
c4f2d992 202 *
203 * Returns: ---
204 *
205 * Use: Removes a reference to a class block.
206 */
207
50a87c1f 208void class_dec(class_node *c)
c4f2d992 209{
50a87c1f 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:
f60a3434 224 sym_destroy(&c->v.t);
50a87c1f 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 }
c4f2d992 233 free(c);
234 }
235}
236
50a87c1f 237/* --- @class_mod@ --- *
c4f2d992 238 *
50a87c1f 239 * Arguments: @class_node *c@ = pointer to a class node
c4f2d992 240 *
50a87c1f 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.
c4f2d992 243 *
50a87c1f 244 * Use: Gives you a node which you can modify. Don't call this
245 * for @class_all@ or @class_none@.
c4f2d992 246 */
247
50a87c1f 248class_node *class_mod(class_node *c)
c4f2d992 249{
50a87c1f 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:
f60a3434 260 die(1, "internal: class_mod called on non-modifiable class node");
50a87c1f 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
f60a3434 274 sym_create(&cc->v.t);
275 for (sym_mkiter(&i, &c->v.t); (b = sym_next(&i)) != 0; )
50a87c1f 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;
03f996bd 287 }
50a87c1f 288
289 class_dec(c);
290 return (cc);
c4f2d992 291}
292
50a87c1f 293/*----- Some weirder operations on classes --------------------------------*/
294
295/* --- @class__hashify@ --- *
c4f2d992 296 *
50a87c1f 297 * Arguments: @class_node *c@ = pointer to a node
c4f2d992 298 *
50a87c1f 299 * Returns: A pointer to a hash node containing the node's value.
c4f2d992 300 *
50a87c1f 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.
c4f2d992 304 */
305
50a87c1f 306static class_node *class__hashify(class_node *c)
c4f2d992 307{
50a87c1f 308 /* --- Some sanity checking --- */
c4f2d992 309
50a87c1f 310 if (~c->type & clFlag_friendly)
f60a3434 311 die(1, "internal: class__hashify can't hashify unfriendly nodes");
50a87c1f 312 if ((c->type & clNode_mask) != clNode_immed)
f60a3434 313 die(1, "internal: class__hashify can't hashify non-immediate nodes");
50a87c1f 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;
f60a3434 323 sym_create(&c->v.t);
50a87c1f 324 sym_find(&c->v.t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
03f996bd 325 } else {
50a87c1f 326 char *s = c->v.s;
f60a3434 327 sym_create(&c->v.t);
50a87c1f 328 sym_find(&c->v.t, s, -1, sizeof(sym_base), 0);
329 free(s);
c4f2d992 330 }
50a87c1f 331
332 return (c);
c4f2d992 333}
334
50a87c1f 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
c4f2d992 342 *
50a87c1f 343 * Returns: A class node representing the result of a binary operation
344 * upon two classes.
c4f2d992 345 *
50a87c1f 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.
c4f2d992 351 *
50a87c1f 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.
c4f2d992 364 */
365
50a87c1f 366class_node *class__binop(class_node *l, class_node *r, int op)
c4f2d992 367{
50a87c1f 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 --- */
c4f2d992 372
50a87c1f 373 if (!type) {
374 class_dec(l);
375 class_dec(r);
c4f2d992 376 return (0);
50a87c1f 377 }
c4f2d992 378
50a87c1f 379 /* --- Handle `friendly' nodes --- */
c4f2d992 380
50a87c1f 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;
03f996bd 441 }
607937a4 442
50a87c1f 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 */
c4f2d992 448
50a87c1f 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
f60a3434 476 for (sym_mkiter(&i, &r->v.t); (b = sym_next(&i)) != 0; )
50a87c1f 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
f60a3434 497 for (sym_mkiter(&i, &r->v.t); (b = sym_next(&i)) != 0; ) {
50a87c1f 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
f60a3434 526 for (sym_mkiter(&i, &l->v.t); (b = sym_next(&i)) != 0; ) {
50a87c1f 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 --- *
c4f2d992 535 *
50a87c1f 536 * It may have lost a load of elements. Maybe it can be represented
537 * better as an immediate or even as @class_none@.
c4f2d992 538 */
539
50a87c1f 540 {
541 sym_iter i;
542 sym_base *b;
c4f2d992 543
50a87c1f 544 class_dec(r);
c4f2d992 545
f60a3434 546 sym_mkiter(&i, &l->v.t);
50a87c1f 547 if ((b = sym_next(&i)) == 0) {
548 class_dec(l);
549 return (class_none);
03f996bd 550 }
50a87c1f 551 if (!sym_next(&i)) {
552 if (type & clType_user) {
553 uid_t u = *(uid_t *)b->name;
f60a3434 554 sym_destroy(&l->v.t);
50a87c1f 555 l->type = (l->type & ~clNode_mask) | clNode_immed;
556 l->v.u = u;
557 } else {
558 char *s = xstrdup(b->name);
f60a3434 559 sym_destroy(&l->v.t);
50a87c1f 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
608class_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);
c4f2d992 622
50a87c1f 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
643class_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 }
c4f2d992 652
50a87c1f 653 if (r == class_none)
654 return (l);
c4f2d992 655
50a87c1f 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
676class_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
708class_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
728class_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
750int 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))
c4f2d992 768 return (1);
50a87c1f 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
f60a3434 783 die(1, "internal: can't get here in class_matchUser");
50a87c1f 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
798int class_matchCommand(class_node *c, const char *s)
799{
800 class_node *cc;
607937a4 801
50a87c1f 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
f60a3434 831 die(1, "internal: can't get here in class_matchCommand");
50a87c1f 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
851static int class__doMatchHost(class_node *c, const char *ip,
852 const char *name, char **aliases)
853{
854 class_node *cc;
607937a4 855
50a87c1f 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))
607937a4 868 return (1);
607937a4 869 }
50a87c1f 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;
c4f2d992 896 }
50a87c1f 897 }
03f996bd 898
f60a3434 899 die(1, "internal: can't get here in class_matchUser");
50a87c1f 900 return (0);
901}
902
903int 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;
c4f2d992 915 }
50a87c1f 916
917 return (class__doMatchHost(c, ip, name, aliases));
c4f2d992 918}
919
50a87c1f 920/*----- Debugging code ----------------------------------------------------*/
921
c4f2d992 922/* --- @class_dump@ --- *
923 *
50a87c1f 924 * Argumemnts: @class_node *c@ = pointer to root node
925 * @int indent@ = indent depth
c4f2d992 926 *
927 * Returns: ---
928 *
50a87c1f 929 * Use: Dumps a class to the trace output.
c4f2d992 930 */
931
50a87c1f 932void class_dump(class_node *c, int indent)
c4f2d992 933{
51cf22e0 934#ifdef TRACING
50a87c1f 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
f60a3434 987 for (sym_mkiter(&i, &c->v.t); (b = sym_next(&i)) != 0; ) {
50a87c1f 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);
c4f2d992 993 }
50a87c1f 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;
c4f2d992 1001 }
50a87c1f 1002
51cf22e0 1003#endif
c4f2d992 1004}
1005
1006/*----- That's all, folks -------------------------------------------------*/