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