2 * Copyright (c) 1996, 1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
5 * This code is derived from software contributed by Chris Jepeway.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
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.
39 #include <sys/param.h>
40 #include <sys/types.h>
42 #include <sys/socket.h>
51 #endif /* STDC_HEADERS */
55 # ifdef HAVE_STRINGS_H
58 #endif /* HAVE_STRING_H */
61 #endif /* HAVE_UNISTD_H */
64 #endif /* HAVE_FNMATCH_H */
65 #ifdef HAVE_NETGROUP_H
66 # include <netgroup.h>
67 #endif /* HAVE_NETGROUP_H */
71 #include <netinet/in.h>
72 #include <arpa/inet.h>
78 #include "interfaces.h"
81 # include "emul/fnmatch.h"
82 #endif /* HAVE_FNMATCH */
85 static const char rcsid[] = "$Sudo: testsudoers.c,v 1.76 2002/03/16 00:44:48 millert Exp $";
92 void init_parser __P((void));
93 void dumpaliases __P((void));
94 void set_perms_dummy __P((int, int));
99 char **Argv, **NewArgv;
101 int parse_error = FALSE;
103 struct interface *interfaces;
104 struct sudo_user sudo_user;
105 void (*set_perms) __P((int, int)) = set_perms_dummy;
106 extern int clearaliases;
110 * Returns TRUE if "s" has shell meta characters in it,
111 * else returns FALSE.
119 for (t = s; *t; t++) {
120 if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']')
127 * Returns TRUE if cmnd matches, in the sudo sense,
128 * the pathname in path; otherwise, return FALSE
131 command_matches(cmnd, cmnd_args, path, sudoers_args)
143 if ((args = strchr(path, ' ')))
146 if (has_meta(path)) {
147 if (fnmatch(path, cmnd, FNM_PATHNAME))
151 else if (!cmnd_args && sudoers_args && !strcmp("\"\"", sudoers_args))
153 else if (sudoers_args)
154 return((fnmatch(sudoers_args, cmnd_args ? cmnd_args : "", 0) == 0));
159 if (path[plen - 1] != '/') {
160 if (strcmp(cmnd, path))
164 else if (!cmnd_args && sudoers_args && !strcmp("\"\"", sudoers_args))
166 else if (sudoers_args)
167 return((fnmatch(sudoers_args, cmnd_args ? cmnd_args : "", 0) == 0));
174 /* path cannot be the parent dir of cmnd */
177 if (strchr(cmnd + plen + 1, '/') != NULL)
178 /* path could only be an anscestor of cmnd -- */
179 /* ignoring, of course, things like // & /./ */
182 /* see whether path is the prefix of cmnd */
183 return((strncmp(cmnd, path, plen) == 0));
193 struct in_addr addr, mask;
195 /* If there's an explicit netmask, use it. */
196 if ((m = strchr(n, '/'))) {
198 addr.s_addr = inet_addr(n);
200 mask.s_addr = inet_addr(m);
203 mask.s_addr = 0xffffffff;
206 mask.s_addr = htonl(mask.s_addr);
210 for (i = 0; i < num_interfaces; i++)
211 if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr)
214 addr.s_addr = inet_addr(n);
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)
227 hostname_matches(shost, lhost, pattern)
232 if (has_meta(pattern)) {
233 if (strchr(pattern, '.'))
234 return(fnmatch(pattern, lhost, FNM_CASEFOLD));
236 return(fnmatch(pattern, shost, FNM_CASEFOLD));
238 if (strchr(pattern, '.'))
239 return(strcasecmp(lhost, pattern));
241 return(strcasecmp(shost, pattern));
246 usergr_matches(group, user)
253 /* Make sure we have a valid usergroup, sudo style. */
257 if ((grp = getgrnam(group)) == NULL)
261 * Check against user's real gid as well as group's user list
263 if (getgid() == grp->gr_gid)
266 for (cur=grp->gr_mem; *cur; cur++) {
267 if (strcmp(*cur, user) == 0)
275 netgr_matches(netgr, host, shost, user)
281 #ifdef HAVE_GETDOMAINNAME
282 static char *domain = (char *) -1;
284 static char *domain = NULL;
285 #endif /* HAVE_GETDOMAINNAME */
287 /* Make sure we have a valid netgroup, sudo style. */
291 #ifdef HAVE_GETDOMAINNAME
292 /* Get the domain name (if any). */
293 if (domain == (char *) -1) {
294 domain = (char *) emalloc(MAXHOSTNAMELEN);
296 if (getdomainname(domain, MAXHOSTNAMELEN) != 0 || *domain == '\0') {
301 #endif /* HAVE_GETDOMAINNAME */
304 if (innetgr(netgr, host, user, domain))
306 else if (host != shost && innetgr(netgr, shost, user, domain))
308 #endif /* HAVE_INNETGR */
314 set_perms_dummy(i, j)
347 if (Argc >= 6 && strcmp(Argv[1], "-u") == 0) {
348 user_runas = &Argv[2];
349 pw.pw_name = Argv[3];
355 } else if (Argc >= 4) {
356 pw.pw_name = Argv[1];
363 (void) fprintf(stderr,
364 "usage: %s [-u user] <user> <host> <command> [args]\n", Argv[0]);
368 sudo_user.pw = &pw; /* user_name needs to be defined */
370 if ((p = strchr(user_host, '.'))) {
372 user_shost = estrdup(user_host);
375 user_shost = user_host;
378 /* Fill in cmnd_args from NewArgv. */
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++) {
388 (void) strcpy(to, *from);
393 /* Initialize default values. */
396 /* Warn about aliases that are used before being defined. */
399 /* Need to keep aliases around for dumpaliases(). */
400 clearaliases = FALSE;
402 /* Load ip addr/mask for each interface. */
405 /* Allocate space for data structures in the parser. */
408 if (yyparse() || parse_error) {
409 (void) printf("doesn't parse.\n");
411 (void) printf("parses OK.\n\n");
413 (void) printf("User %s not found\n", pw.pw_name);
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);
427 (void) printf("Matching Aliases --\n");