Imported Upstream version 1.6.6
[debian/sudo] / testsudoers.c
1 /*
2  * Copyright (c) 1996, 1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
3  * All rights reserved.
4  *
5  * This code is derived from software contributed by Chris Jepeway.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * 4. Products derived from this software may not be called "Sudo" nor
22  *    may "Sudo" appear in their names without specific prior written
23  *    permission from the author.
24  *
25  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
28  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36
37 #include "config.h"
38
39 #include <sys/param.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <sys/socket.h>
43 #include <stdio.h>
44 #ifdef STDC_HEADERS
45 # include <stdlib.h>
46 # include <stddef.h>
47 #else
48 # ifdef HAVE_STDLIB_H
49 #  include <stdlib.h>
50 # endif
51 #endif /* STDC_HEADERS */
52 #ifdef HAVE_STRING_H
53 # include <string.h>
54 #else
55 # ifdef HAVE_STRINGS_H
56 #  include <strings.h>
57 # endif
58 #endif /* HAVE_STRING_H */
59 #ifdef HAVE_UNISTD_H
60 # include <unistd.h>
61 #endif /* HAVE_UNISTD_H */
62 #ifdef HAVE_FNMATCH
63 # include <fnmatch.h>
64 #endif /* HAVE_FNMATCH_H */
65 #ifdef HAVE_NETGROUP_H
66 # include <netgroup.h>
67 #endif /* HAVE_NETGROUP_H */
68 #include <ctype.h>
69 #include <pwd.h>
70 #include <grp.h>
71 #include <netinet/in.h>
72 #include <arpa/inet.h>
73 #include <netdb.h>
74 #include <dirent.h>
75
76 #include "sudo.h"
77 #include "parse.h"
78 #include "interfaces.h"
79
80 #ifndef HAVE_FNMATCH
81 # include "emul/fnmatch.h"
82 #endif /* HAVE_FNMATCH */
83
84 #ifndef lint
85 static const char rcsid[] = "$Sudo: testsudoers.c,v 1.76 2002/03/16 00:44:48 millert Exp $";
86 #endif /* lint */
87
88
89 /*
90  * Prototypes
91  */
92 void init_parser        __P((void));
93 void dumpaliases        __P((void));
94 void set_perms_dummy    __P((int, int));
95
96 /*
97  * Globals
98  */
99 char **Argv, **NewArgv;
100 int  Argc, NewArgc;
101 int parse_error = FALSE;
102 int num_interfaces;
103 struct interface *interfaces;
104 struct sudo_user sudo_user;
105 void (*set_perms) __P((int, int)) = set_perms_dummy;
106 extern int clearaliases;
107 extern int pedantic;
108
109 /*
110  * Returns TRUE if "s" has shell meta characters in it,
111  * else returns FALSE.
112  */
113 int
114 has_meta(s)
115     char *s;
116 {
117     char *t;
118     
119     for (t = s; *t; t++) {
120         if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']')
121             return(TRUE);
122     }
123     return(FALSE);
124 }
125
126 /*
127  * Returns TRUE if cmnd matches, in the sudo sense,
128  * the pathname in path; otherwise, return FALSE
129  */
130 int
131 command_matches(cmnd, cmnd_args, path, sudoers_args)
132     char *cmnd;
133     char *cmnd_args;
134     char *path;
135     char *sudoers_args;
136 {
137     int clen, plen;
138     char *args;
139
140     if (cmnd == NULL)
141         return(FALSE);
142
143     if ((args = strchr(path, ' ')))  
144         *args++ = '\0';
145
146     if (has_meta(path)) {
147         if (fnmatch(path, cmnd, FNM_PATHNAME))
148             return(FALSE);
149         if (!sudoers_args)
150             return(TRUE);
151         else if (!cmnd_args && sudoers_args && !strcmp("\"\"", sudoers_args))
152             return(TRUE);
153         else if (sudoers_args)
154             return((fnmatch(sudoers_args, cmnd_args ? cmnd_args : "", 0) == 0));
155         else
156             return(FALSE);
157     } else {
158         plen = strlen(path);
159         if (path[plen - 1] != '/') {
160             if (strcmp(cmnd, path))
161                 return(FALSE);
162             if (!sudoers_args)
163                 return(TRUE);
164             else if (!cmnd_args && sudoers_args && !strcmp("\"\"", sudoers_args))
165                 return(TRUE);
166             else if (sudoers_args)
167                 return((fnmatch(sudoers_args, cmnd_args ? cmnd_args : "", 0) == 0));
168             else
169                 return(FALSE);
170         }
171
172         clen = strlen(cmnd);
173         if (clen < plen + 1)
174             /* path cannot be the parent dir of cmnd */
175             return(FALSE);
176
177         if (strchr(cmnd + plen + 1, '/') != NULL)
178             /* path could only be an anscestor of cmnd -- */
179             /* ignoring, of course, things like // & /./  */
180             return(FALSE);
181
182         /* see whether path is the prefix of cmnd */
183         return((strncmp(cmnd, path, plen) == 0));
184     }
185 }
186
187 int
188 addr_matches(n)
189     char *n;
190 {
191     int i;
192     char *m;
193     struct in_addr addr, mask;
194
195     /* If there's an explicit netmask, use it. */
196     if ((m = strchr(n, '/'))) {
197         *m++ = '\0';
198         addr.s_addr = inet_addr(n);
199         if (strchr(m, '.'))
200             mask.s_addr = inet_addr(m);
201         else {
202             i = 32 - atoi(m);
203             mask.s_addr = 0xffffffff;
204             mask.s_addr >>= i;
205             mask.s_addr <<= i;
206             mask.s_addr = htonl(mask.s_addr);
207         }
208         *(m - 1) = '/';               
209
210         for (i = 0; i < num_interfaces; i++)
211             if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr)
212                 return(TRUE);
213     } else {
214         addr.s_addr = inet_addr(n);
215
216         for (i = 0; i < num_interfaces; i++)
217             if (interfaces[i].addr.s_addr == addr.s_addr ||
218                 (interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr)
219                 == addr.s_addr)
220                 return(TRUE);
221     }
222
223     return(FALSE);
224 }
225
226 int
227 hostname_matches(shost, lhost, pattern)
228     char *shost;
229     char *lhost;
230     char *pattern;
231 {
232     if (has_meta(pattern)) {  
233         if (strchr(pattern, '.'))   
234             return(fnmatch(pattern, lhost, FNM_CASEFOLD));
235         else
236             return(fnmatch(pattern, shost, FNM_CASEFOLD));
237     } else {
238         if (strchr(pattern, '.'))
239             return(strcasecmp(lhost, pattern));
240         else
241             return(strcasecmp(shost, pattern));
242     }
243 }
244
245 int
246 usergr_matches(group, user)
247     char *group;
248     char *user;
249 {
250     struct group *grp;
251     char **cur;
252
253     /* Make sure we have a valid usergroup, sudo style. */
254     if (*group++ != '%')
255         return(FALSE);
256
257     if ((grp = getgrnam(group)) == NULL) 
258         return(FALSE);
259
260     /*
261      * Check against user's real gid as well as group's user list
262      */
263     if (getgid() == grp->gr_gid)
264         return(TRUE);
265
266     for (cur=grp->gr_mem; *cur; cur++) {
267         if (strcmp(*cur, user) == 0)
268             return(TRUE);
269     }
270
271     return(FALSE);
272 }
273
274 int
275 netgr_matches(netgr, host, shost, user)
276     char *netgr;
277     char *host;
278     char *shost;
279     char *user;
280 {
281 #ifdef HAVE_GETDOMAINNAME
282     static char *domain = (char *) -1;
283 #else
284     static char *domain = NULL;
285 #endif /* HAVE_GETDOMAINNAME */
286
287     /* Make sure we have a valid netgroup, sudo style. */
288     if (*netgr++ != '+')
289         return(FALSE);
290
291 #ifdef HAVE_GETDOMAINNAME
292     /* Get the domain name (if any). */
293     if (domain == (char *) -1) {
294         domain = (char *) emalloc(MAXHOSTNAMELEN);
295
296         if (getdomainname(domain, MAXHOSTNAMELEN) != 0 || *domain == '\0') {
297             free(domain);
298             domain = NULL;
299         }
300     }
301 #endif /* HAVE_GETDOMAINNAME */
302
303 #ifdef HAVE_INNETGR
304     if (innetgr(netgr, host, user, domain))
305         return(TRUE);
306     else if (host != shost && innetgr(netgr, shost, user, domain))
307         return(TRUE);
308 #endif /* HAVE_INNETGR */
309
310     return(FALSE);
311 }
312
313 void
314 set_perms_dummy(i, j)
315     int i, j;
316 {
317     return;
318 }
319
320 void
321 set_fqdn()
322 {
323     return;
324 }
325
326 void
327 init_envtables()
328 {
329     return;
330 }
331
332 int
333 main(argc, argv)
334     int argc;
335     char **argv;
336 {
337     struct passwd pw;
338     char *p;
339 #ifdef  YYDEBUG
340     extern int yydebug;
341     yydebug = 1;
342 #endif
343
344     Argv = argv;
345     Argc = argc;
346
347     if (Argc >= 6 && strcmp(Argv[1], "-u") == 0) {
348         user_runas = &Argv[2];
349         pw.pw_name = Argv[3];
350         user_host = Argv[4];
351         user_cmnd = Argv[5];
352
353         NewArgv = &Argv[5];
354         NewArgc = Argc - 5;
355     } else if (Argc >= 4) {
356         pw.pw_name = Argv[1];
357         user_host = Argv[2];
358         user_cmnd = Argv[3];
359
360         NewArgv = &Argv[3];
361         NewArgc = Argc - 3;
362     } else {
363         (void) fprintf(stderr,
364             "usage: %s [-u user] <user> <host> <command> [args]\n", Argv[0]);
365         exit(1);
366     }
367
368     sudo_user.pw = &pw;         /* user_name needs to be defined */
369
370     if ((p = strchr(user_host, '.'))) {
371         *p = '\0';
372         user_shost = estrdup(user_host);
373         *p = '.';
374     } else {
375         user_shost = user_host;
376     }
377
378     /* Fill in cmnd_args from NewArgv. */
379     if (NewArgc > 1) {
380         size_t size;
381         char *to, **from;
382
383         size = (size_t) NewArgv[NewArgc-1] + strlen(NewArgv[NewArgc-1]) -
384                (size_t) NewArgv[1] + 1;
385         user_args = (char *) emalloc(size);
386         for (to = user_args, from = &NewArgv[1]; *from; from++) {
387             *to++ = ' ';
388             (void) strcpy(to, *from);
389             to += strlen(*from);
390         }
391     }
392
393     /* Initialize default values. */
394     init_defaults();
395
396     /* Warn about aliases that are used before being defined. */
397     pedantic = TRUE;
398
399     /* Need to keep aliases around for dumpaliases(). */
400     clearaliases = FALSE;
401
402     /* Load ip addr/mask for each interface. */
403     load_interfaces();
404
405     /* Allocate space for data structures in the parser. */
406     init_parser();
407
408     if (yyparse() || parse_error) {
409         (void) printf("doesn't parse.\n");
410     } else {
411         (void) printf("parses OK.\n\n");
412         if (top == 0)
413             (void) printf("User %s not found\n", pw.pw_name);
414         else while (top) {
415             (void) printf("[%d]\n", top-1);
416             (void) printf("user_match : %d\n", user_matches);
417             (void) printf("host_match : %d\n", host_matches);
418             (void) printf("cmnd_match : %d\n", cmnd_matches);
419             (void) printf("no_passwd  : %d\n", no_passwd);
420             (void) printf("runas_match: %d\n", runas_matches);
421             (void) printf("runas      : %s\n", *user_runas);
422             top--;
423         }
424     }
425
426     /* Dump aliases. */
427     (void) printf("Matching Aliases --\n");
428     dumpaliases();
429
430     exit(0);
431 }