Annotation of src/usr.bin/sudo/testsudoers.c, Revision 1.2
1.1 millert 1: /*
2: * Copyright (c) 1996, 1998, 1999 Todd C. Miller <Todd.Miller@courtesan.com>
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:
40: #include <stdio.h>
41: #ifdef STDC_HEADERS
42: # include <stdlib.h>
43: #endif /* STDC_HEADERS */
44: #ifdef HAVE_UNISTD_H
45: # include <unistd.h>
46: #endif /* HAVE_UNISTD_H */
47: #ifdef HAVE_STRING_H
48: # include <string.h>
49: #endif /* HAVE_STRING_H */
50: #ifdef HAVE_STRINGS_H
51: # include <strings.h>
52: #endif /* HAVE_STRINGS_H */
1.2 ! millert 53: #ifdef HAVE_FNMATCH
1.1 millert 54: # include <fnmatch.h>
55: #endif /* HAVE_FNMATCH_H */
56: #ifdef HAVE_NETGROUP_H
57: # include <netgroup.h>
58: #endif /* HAVE_NETGROUP_H */
59: #include <ctype.h>
60: #include <pwd.h>
61: #include <grp.h>
62: #include <sys/param.h>
63: #include <sys/types.h>
64: #include <sys/socket.h>
65: #include <netinet/in.h>
66: #include <arpa/inet.h>
67: #include <netdb.h>
68: #include <sys/stat.h>
69: #include <dirent.h>
70:
71: #include "sudo.h"
72: #include "parse.h"
73: #include "interfaces.h"
74:
75: #ifndef HAVE_FNMATCH
76: # include "emul/fnmatch.h"
77: #endif /* HAVE_FNMATCH */
78:
79: #ifndef lint
1.2 ! millert 80: static const char rcsid[] = "$Sudo: testsudoers.c,v 1.66 1999/12/09 03:54:57 millert Exp $";
1.1 millert 81: #endif /* lint */
82:
83: /*
84: * Globals
85: */
86: char **Argv, **NewArgv;
87: int Argc, NewArgc;
88: int parse_error = FALSE;
89: int num_interfaces;
90: struct interface *interfaces;
91: struct sudo_user sudo_user;
92: extern int clearaliases;
93: extern int pedantic;
94:
95: /*
96: * Prototypes for external functions
97: */
98: void init_parser __P((void));
99: void dumpaliases __P((void));
100:
101: /*
102: * Returns TRUE if "s" has shell meta characters in it,
103: * else returns FALSE.
104: */
105: int
106: has_meta(s)
107: char *s;
108: {
109: register char *t;
110:
111: for (t = s; *t; t++) {
112: if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']')
113: return(TRUE);
114: }
115: return(FALSE);
116: }
117:
118: /*
119: * Returns TRUE if cmnd matches, in the sudo sense,
120: * the pathname in path; otherwise, return FALSE
121: */
122: int
123: command_matches(cmnd, cmnd_args, path, sudoers_args)
124: char *cmnd;
125: char *cmnd_args;
126: char *path;
127: char *sudoers_args;
128: {
129: int clen, plen;
130: char *args;
131:
132: if (cmnd == NULL)
133: return(FALSE);
134:
135: if ((args = strchr(path, ' ')))
136: *args++ = '\0';
137:
138: if (has_meta(path)) {
139: if (fnmatch(path, cmnd, FNM_PATHNAME))
140: return(FALSE);
141: if (!sudoers_args)
142: return(TRUE);
143: else if (!cmnd_args && sudoers_args && !strcmp("\"\"", sudoers_args))
144: return(TRUE);
145: else if (sudoers_args)
146: return((fnmatch(sudoers_args, cmnd_args ? cmnd_args : "", 0) == 0));
147: else
148: return(FALSE);
149: } else {
150: plen = strlen(path);
151: if (path[plen - 1] != '/') {
152: if (strcmp(cmnd, path))
153: return(FALSE);
154: if (!sudoers_args)
155: return(TRUE);
156: else if (!cmnd_args && sudoers_args && !strcmp("\"\"", sudoers_args))
157: return(TRUE);
158: else if (sudoers_args)
159: return((fnmatch(sudoers_args, cmnd_args ? cmnd_args : "", 0) == 0));
160: else
161: return(FALSE);
162: }
163:
164: clen = strlen(cmnd);
165: if (clen < plen + 1)
166: /* path cannot be the parent dir of cmnd */
167: return(FALSE);
168:
169: if (strchr(cmnd + plen + 1, '/') != NULL)
170: /* path could only be an anscestor of cmnd -- */
171: /* ignoring, of course, things like // & /./ */
172: return(FALSE);
173:
174: /* see whether path is the prefix of cmnd */
175: return((strncmp(cmnd, path, plen) == 0));
176: }
177: }
178:
179: int
180: addr_matches(n)
181: char *n;
182: {
183: int i;
184: char *m;
185: struct in_addr addr, mask;
186:
187: /* If there's an explicit netmask, use it. */
188: if ((m = strchr(n, '/'))) {
189: *m++ = '\0';
190: addr.s_addr = inet_addr(n);
191: if (strchr(m, '.'))
192: mask.s_addr = inet_addr(m);
193: else
194: mask.s_addr = (1 << atoi(m)) - 1; /* XXX - better way? */
195: *(m - 1) = '/';
196:
197: for (i = 0; i < num_interfaces; i++)
198: if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr)
199: return(TRUE);
200: } else {
201: addr.s_addr = inet_addr(n);
202:
203: for (i = 0; i < num_interfaces; i++)
204: if (interfaces[i].addr.s_addr == addr.s_addr ||
205: (interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr)
206: == addr.s_addr)
207: return(TRUE);
208: }
209:
210: return(FALSE);
211: }
212:
213: int
214: usergr_matches(group, user)
215: char *group;
216: char *user;
217: {
218: struct group *grp;
219: char **cur;
220:
221: /* Make sure we have a valid usergroup, sudo style. */
222: if (*group++ != '%')
223: return(FALSE);
224:
225: if ((grp = getgrnam(group)) == NULL)
226: return(FALSE);
227:
228: /*
229: * Check against user's real gid as well as group's user list
230: */
231: if (getgid() == grp->gr_gid)
232: return(TRUE);
233:
234: for (cur=grp->gr_mem; *cur; cur++) {
235: if (strcmp(*cur, user) == 0)
236: return(TRUE);
237: }
238:
239: return(FALSE);
240: }
241:
242: int
243: netgr_matches(netgr, host, user)
244: char *netgr;
245: char *host;
246: char *user;
247: {
248: #ifdef HAVE_GETDOMAINNAME
249: static char *domain = (char *) -1;
250: #else
251: static char *domain = NULL;
252: #endif /* HAVE_GETDOMAINNAME */
253:
254: /* Make sure we have a valid netgroup, sudo style. */
255: if (*netgr++ != '+')
256: return(FALSE);
257:
258: #ifdef HAVE_GETDOMAINNAME
259: /* Get the domain name (if any). */
260: if (domain == (char *) -1) {
261: domain = (char *) emalloc(MAXHOSTNAMELEN);
262:
263: if (getdomainname(domain, MAXHOSTNAMELEN) != 0 || *domain == '\0') {
264: free(domain);
265: domain = NULL;
266: }
267: }
268: #endif /* HAVE_GETDOMAINNAME */
269:
270: #ifdef HAVE_INNETGR
271: return(innetgr(netgr, host, user, domain));
272: #else
273: return(FALSE);
274: #endif /* HAVE_INNETGR */
275: }
276:
277: void
278: set_perms(i, j)
279: int i, j;
1.2 ! millert 280: {
! 281: return;
! 282: }
! 283:
! 284: void
! 285: set_fqdn()
1.1 millert 286: {
287: return;
288: }
289:
290: int
291: main(argc, argv)
292: int argc;
293: char **argv;
294: {
295: struct passwd pw;
296: char *p;
297: #ifdef YYDEBUG
298: extern int yydebug;
299: yydebug = 1;
300: #endif
301:
302: Argv = argv;
303: Argc = argc;
304:
305: if (Argc >= 6 && strcmp(Argv[1], "-u") == 0) {
306: user_runas = &Argv[2];
307: pw.pw_name = Argv[3];
308: user_host = Argv[4];
309: user_cmnd = Argv[5];
310:
311: NewArgv = &Argv[5];
312: NewArgc = Argc - 5;
313: } else if (Argc >= 4) {
314: pw.pw_name = Argv[1];
315: user_host = Argv[2];
316: user_cmnd = Argv[3];
317:
318: NewArgv = &Argv[3];
319: NewArgc = Argc - 3;
320: } else {
321: (void) fprintf(stderr,
322: "usage: %s [-u user] <user> <host> <command> [args]\n", Argv[0]);
323: exit(1);
324: }
325:
326: sudo_user.pw = &pw; /* user_name needs to be defined */
327:
328: if ((p = strchr(user_host, '.'))) {
329: *p = '\0';
330: user_shost = estrdup(user_host);
331: *p = '.';
332: } else {
333: user_shost = user_host;
334: }
335:
336: /* Fill in cmnd_args from NewArgv. */
337: if (NewArgc > 1) {
338: size_t size;
339: char *to, **from;
340:
341: size = (size_t) NewArgv[NewArgc-1] + strlen(NewArgv[NewArgc-1]) -
342: (size_t) NewArgv[1] + 1;
343: user_args = (char *) emalloc(size);
344: for (to = user_args, from = &NewArgv[1]; *from; from++) {
345: *to++ = ' ';
346: (void) strcpy(to, *from);
347: to += strlen(*from);
348: }
349: }
350:
351: /* Initialize default values. */
352: init_defaults();
353:
354: /* Warn about aliases that are used before being defined. */
355: pedantic = TRUE;
356:
357: /* Need to keep aliases around for dumpaliases(). */
358: clearaliases = FALSE;
359:
360: /* Load ip addr/mask for each interface. */
361: load_interfaces();
362:
363: /* Allocate space for data structures in the parser. */
364: init_parser();
365:
366: if (yyparse() || parse_error) {
367: (void) printf("doesn't parse.\n");
368: } else {
369: (void) printf("parses OK.\n\n");
370: if (top == 0)
371: (void) printf("User %s not found\n", pw.pw_name);
372: else while (top) {
373: (void) printf("[%d]\n", top-1);
374: (void) printf("user_match : %d\n", user_matches);
375: (void) printf("host_match : %d\n", host_matches);
376: (void) printf("cmnd_match : %d\n", cmnd_matches);
377: (void) printf("no_passwd : %d\n", no_passwd);
378: (void) printf("runas_match: %d\n", runas_matches);
379: (void) printf("runas : %s\n", *user_runas);
380: top--;
381: }
382: }
383:
384: /* Dump aliases. */
385: (void) printf("Matching Aliases --\n");
386: dumpaliases();
387:
388: exit(0);
389: }