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