chiark / gitweb /
Added. No idea why this wasn't done before.
[become] / src / class.c
1 /* -*-c-*-
2  *
3  * $Id: class.c,v 1.2 1997/08/04 10:24:21 mdw Exp $
4  *
5  * Handling classes of things nicely
6  *
7  * (c) 1997 EBI
8  */
9
10 /*----- Licensing notice --------------------------------------------------*
11  *
12  * This file is part of `become'
13  *
14  * `Become' is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * `Become' is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with `become'; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Revision history --------------------------------------------------*
30  *
31  * $Log: class.c,v $
32  * Revision 1.2  1997/08/04 10:24:21  mdw
33  * Sources placed under CVS control.
34  *
35  * Revision 1.1  1997/07/21  13:47:52  mdw
36  * Initial revision
37  *
38  */
39
40 /*----- Header files ------------------------------------------------------*/
41
42 /* --- ANSI headers --- */
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 /* --- Unix headers --- */
49
50 #include <sys/types.h>
51 #include <sys/socket.h>
52
53 #include <netinet/in.h>
54
55 #include <arpa/inet.h>
56
57 #include <netdb.h>
58
59 /* --- Local headers --- */
60
61 #include "become.h"
62 #include "class.h"
63 #include "set.h"
64 #include "sym.h"
65 #include "utils.h"
66
67 /*----- Global variables --------------------------------------------------*/
68
69 static classdef class__all = { clType_all, -1, 0 };
70 classdef *class_all = &class__all;
71
72 /*----- Wildcard matching -------------------------------------------------*/
73
74 /* --- @class__wildMatch@ --- *
75  *
76  * Arguments:   @const char *pat@ = pointer to pattern string
77  *              @const char *p@ = pointer to target string
78  *
79  * Returns:     Zero if no match, nonzero if match.
80  *
81  * Use:         Wildcard-matches the pattern against the target string.
82  */
83
84 static int class__wildMatch(const char *pat, const char *p)
85 {
86   for (;;) {
87     if (*pat == 0 && *p == 0)
88       return (42); /* For sadism's sake */
89     else if (*pat == '*') {
90       while (*pat == '*')
91         pat++;
92       do {
93         if (class__wildMatch(pat, p))
94           return (27); /* Nyahaha */
95         p++;
96       } while (*p);
97       return (0);
98     } else if (*pat == '?' || *pat == *p)
99       p++, pat++;
100     else
101       return (0);
102   }
103 }
104
105 /*----- Main code ---------------------------------------------------------*/
106
107 /* --- @class_create@ --- *
108  *
109  * Arguments:   @unsigned type@ = type of the class to create
110  *              @sym_table *t@ = pointer to symbol table which stores info
111  *
112  * Returns:     Pointer to a @classdef@ which maintains the class's info.
113  *
114  * Use:         Creates a new class definition.  The new definition has one
115  *              reference attached to it (which is the one you get returned).
116  */
117
118 classdef *class_create(unsigned type, sym_table *t)
119 {
120   classdef *c = xmalloc(sizeof(*c));
121   c->type = type;
122   c->ref = 1;
123   c->t = t;
124   return (c);
125 }
126
127 /* --- @class_inc@ --- *
128  *
129  * Arguments:   @classdef *c@ = pointer to a class block
130  *
131  * Returns:     ---
132  *
133  * Use:         Adds a reference to the class definition.
134  */
135
136 void class_inc(classdef *c)
137 {
138   if (c != class_all)
139     c->ref++;
140 }
141
142 /* --- @class_dec@ --- *
143  *
144  * Arguments:   @classdef *c@ = pointer to a class block
145  *
146  * Returns:     ---
147  *
148  * Use:         Removes a reference to a class block.
149  */
150
151 void class_dec(classdef *c)
152 {
153   if (c != class_all && !--c->ref) {
154     sym_destroyTable(c->t);
155     free(c);
156   }
157 }
158
159 /* --- @class_userMatch@ --- *
160  *
161  * Arguments:   @classdef *c@ = pointer to a class block
162  *              @int u@ = uid number to check against
163  *
164  * Returns:     Zero if no match, nonzero if it matched.
165  *
166  * Use:         Looks to see if a user is in a group.
167  */
168
169 int class_userMatch(classdef *c, int u)
170 {
171   if (~c->type & clType_user)
172     return (0);
173   else if (c == class_all) {
174     T( trace(TRACE_CHECK, "check: user %i matched by all", u); )
175     return (1);
176   } else {
177     sym_base *s = sym_find(c->t, (char *)&u, sizeof(u), 0, 0);
178     T( trace(TRACE_CHECK,
179              s ? "check: user %i matched" : "check: user %i not matched",
180              u); )
181     return (s != 0);
182   }
183 }
184
185 /* --- @class_commandMatch@ --- *
186  *
187  * Arguments:   @classdef *c@ = pointer to a class block
188  *              @const char *p@ = pointer to command string to match
189  *
190  * Returns:     Zero for no match, nonzero if it matched.
191  *
192  * Use:         Tries to match a string against the wildcard patterns in the
193  *              given class.  Note that this involves examining all the
194  *              items, so it's not too quick.  Then again, you don't have
195  *              big command classes, do you...?
196  */
197
198 int class_commandMatch(classdef *c, const char *p)
199 {
200   sym_iter i;
201   sym_base *s;
202
203   if (~c->type & clType_command)
204     return (0);
205   else if (c == class_all) {
206     T( trace(TRACE_CHECK, "check: command `%s' matched by all", p); )
207     return (1);
208   } else {
209     for (sym_createIter(&i, c->t); (s = sym_next(&i)) != 0; ) {
210       if (class__wildMatch(s->name, p)) {
211         T( trace(TRACE_CHECK, "check: command `%s' matched by `%s'",
212                  p, s->name); )
213         return (1);
214       }
215     }
216     T( trace(TRACE_CHECK, "check: command `%s' not matched", p); )
217     return (0);
218   }
219 }
220
221 /* --- @class_hostMatch@ --- *
222  *
223  * Arguments:   @classdef *c@ = pointer to class block
224  *              @struct in_addr addr@ = IP address to match
225  *
226  * Returns:     Zero for no match, nonzero if it matched.
227  *
228  * Use:         Tries to match an IP address against the patterns and masks
229  *              in the given class.
230  */
231
232 int class_hostMatch(classdef *c, struct in_addr addr)
233 {
234   sym_iter i;
235   sym_base *s;
236   const char *a;
237   struct hostent *he;
238   char **p;
239
240   if (~c->type & clType_host)
241     return (0);
242   else if (c == class_all) {
243     T( trace(TRACE_CHECK, "check: host %s matched by all",
244              inet_ntoa(addr)); )
245     return (1);
246   } else {
247
248     /* --- Get the dotted-quad and other names for the address --- */
249
250     if ((a = inet_ntoa(addr)) == 0) {
251       T( trace(TRACE_CHECK, "check: couldn't translate address (erk!)"); )
252       return (0);
253     }
254     if ((he = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == 0) {
255       T( trace(TRACE_CHECK, "check: couldn't resolve hostname for %s", a); )
256       return (0);
257     }
258
259     /* --- Now search the list for a match --- *
260      *
261      * This is almost infinitely slow, I'm afraid.
262      */
263
264     for (sym_createIter(&i, c->t); (s = sym_next(&i)) != 0; ) {
265
266       /* --- Check the dotted-quad name first --- */
267
268       if (class__wildMatch(s->name, a)) {
269         T( trace(TRACE_CHECK, "check: host address `%s' matched by `%s'",
270                  a, s->name); )
271         return (1);
272       }
273
274       /* --- Now try the host's main name --- */
275
276       if (class__wildMatch(s->name, he->h_name)) {
277         T( trace(TRACE_CHECK, "check: host name `%s' matched by `%s'",
278                  he->h_name, s->name); )
279         return (1);
280       }
281
282       /* --- Now go through all the names --- */
283
284       for (p = he->h_aliases; *p; p++) {
285         if (class__wildMatch(s->name, *p)) {
286           T( trace(TRACE_CHECK, "check: host alias `%s' matched by `%s'",
287                    *p, s->name); )
288           return (1);
289         }
290       }
291     }
292
293     T( trace(TRACE_CHECK, "check: couldn't match hostname `%s'",
294              he->h_name); )
295     return (0);
296   }
297 }
298
299 /* --- @class_dump@ --- *
300  *
301  * Arguments:   @classdef *c@ = pointer to a class block
302  *
303  * Returns:     ---
304  *
305  * Use:         Dumps the contents of a class to a stream.
306  */
307
308 void class_dump(classdef *c)
309 {
310   sym_iter i;
311   sym_base *s;
312
313   /* --- Dump the table --- */
314
315   if (c->type != clType_all) {
316     for (sym_createIter(&i, c->t); (s = sym_next(&i)) != 0; ) {
317       switch (c->type) {
318         case clType_user:
319           trace(TRACE_RULE, "    %i", *(int *)s->name);
320           break;
321         case clType_command:
322         case clType_host:
323           trace(TRACE_RULE, "    `%s'", s->name);
324           break;
325       }
326     }
327   }
328   else
329     trace(TRACE_RULE, "    ALL");
330 }
331
332 /*----- That's all, folks -------------------------------------------------*/