2 * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
16 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18 * Sponsored in part by the Defense Advanced Research Projects
19 * Agency (DARPA) and Air Force Research Laboratory, Air Force
20 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
27 #include <sys/param.h>
28 #include <sys/types.h>
30 #include <sys/socket.h>
39 #endif /* STDC_HEADERS */
43 # ifdef HAVE_STRINGS_H
46 #endif /* HAVE_STRING_H */
49 #endif /* HAVE_UNISTD_H */
52 #endif /* HAVE_FNMATCH */
53 #ifdef HAVE_NETGROUP_H
54 # include <netgroup.h>
55 #endif /* HAVE_NETGROUP_H */
59 # include "emul/err.h"
60 #endif /* HAVE_ERR_H */
64 #include <netinet/in.h>
65 #include <arpa/inet.h>
71 #include "interfaces.h"
74 # include "emul/fnmatch.h"
75 #endif /* HAVE_FNMATCH */
78 static const char rcsid[] = "$Sudo: testsudoers.c,v 1.88 2004/08/02 18:44:58 millert Exp $";
85 void init_parser __P((void));
86 void dumpaliases __P((void));
87 void set_perms_dummy __P((int));
93 char **Argv, **NewArgv;
94 int parse_error = FALSE;
96 struct interface *interfaces;
97 struct sudo_user sudo_user;
98 extern int clearaliases;
100 void (*set_perms) __P((int)) = set_perms_dummy;
103 * Returns TRUE if "s" has shell meta characters in it,
104 * else returns FALSE.
112 for (t = s; *t; t++) {
113 if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']')
120 * Returns TRUE if user_cmnd matches, in the sudo sense,
121 * the pathname in path; otherwise, return FALSE
124 command_matches(path, sudoers_args)
131 if (user_cmnd == NULL)
134 if ((args = strchr(path, ' ')))
137 if (has_meta(path)) {
138 if (fnmatch(path, user_cmnd, FNM_PATHNAME))
142 else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
144 else if (sudoers_args)
145 return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
150 if (path[plen - 1] != '/') {
151 if (strcmp(user_cmnd, path))
155 else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
157 else if (sudoers_args)
158 return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
163 clen = strlen(user_cmnd);
165 /* path cannot be the parent dir of user_cmnd */
168 if (strchr(user_cmnd + plen + 1, '/') != NULL)
169 /* path could only be an anscestor of user_cmnd -- */
170 /* ignoring, of course, things like // & /./ */
173 /* see whether path is the prefix of user_cmnd */
174 return((strncmp(user_cmnd, path, plen) == 0));
184 struct in_addr addr, mask;
186 /* If there's an explicit netmask, use it. */
187 if ((m = strchr(n, '/'))) {
189 addr.s_addr = inet_addr(n);
191 mask.s_addr = inet_addr(m);
194 mask.s_addr = 0xffffffff;
197 mask.s_addr = htonl(mask.s_addr);
201 for (i = 0; i < num_interfaces; i++)
202 if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr)
205 addr.s_addr = inet_addr(n);
207 for (i = 0; i < num_interfaces; i++)
208 if (interfaces[i].addr.s_addr == addr.s_addr ||
209 (interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr)
218 hostname_matches(shost, lhost, pattern)
223 if (has_meta(pattern)) {
224 if (strchr(pattern, '.'))
225 return(fnmatch(pattern, lhost, FNM_CASEFOLD));
227 return(fnmatch(pattern, shost, FNM_CASEFOLD));
229 if (strchr(pattern, '.'))
230 return(strcasecmp(lhost, pattern));
232 return(strcasecmp(shost, pattern));
237 userpw_matches(sudoers_user, user, pw)
242 if (pw != NULL && *sudoers_user == '#') {
243 uid_t uid = atoi(sudoers_user + 1);
244 if (uid == pw->pw_uid)
247 return(strcmp(sudoers_user, user) == 0);
251 usergr_matches(group, user, pw)
259 /* Make sure we have a valid usergroup, sudo style. */
263 if ((grp = getgrnam(group)) == NULL)
267 * Check against user's real gid as well as group's user list
269 if (getgid() == grp->gr_gid)
272 for (cur=grp->gr_mem; *cur; cur++) {
273 if (strcmp(*cur, user) == 0)
281 netgr_matches(netgr, host, shost, user)
287 #ifdef HAVE_GETDOMAINNAME
288 static char *domain = (char *) -1;
290 static char *domain = NULL;
291 #endif /* HAVE_GETDOMAINNAME */
293 /* Make sure we have a valid netgroup, sudo style. */
297 #ifdef HAVE_GETDOMAINNAME
298 /* Get the domain name (if any). */
299 if (domain == (char *) -1) {
300 domain = (char *) emalloc(MAXHOSTNAMELEN);
302 if (getdomainname(domain, MAXHOSTNAMELEN) != 0 || *domain == '\0') {
307 #endif /* HAVE_GETDOMAINNAME */
310 if (innetgr(netgr, host, user, domain))
312 else if (host != shost && innetgr(netgr, shost, user, domain))
314 #endif /* HAVE_INNETGR */
360 if (Argc >= 6 && strcmp(Argv[1], "-u") == 0) {
361 user_runas = &Argv[2];
362 pw.pw_name = Argv[3];
368 } else if (Argc >= 4) {
369 pw.pw_name = Argv[1];
376 (void) fprintf(stderr,
377 "usage: sudo [-u user] <user> <host> <command> [args]\n");
381 sudo_user.pw = &pw; /* user_name needs to be defined */
383 if ((p = strchr(user_host, '.'))) {
385 user_shost = estrdup(user_host);
388 user_shost = user_host;
391 /* Fill in user_args from NewArgv. */
396 size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
397 strlen(NewArgv[NewArgc-1]) + 1;
398 user_args = (char *) emalloc(size);
399 for (to = user_args, from = NewArgv + 1; *from; from++) {
400 n = strlcpy(to, *from, size - (to - user_args));
401 if (n >= size - (to - user_args))
402 errx(1, "internal error, init_vars() overflow");
409 /* Initialize default values. */
412 /* Warn about aliases that are used before being defined. */
415 /* Need to keep aliases around for dumpaliases(). */
416 clearaliases = FALSE;
418 /* Load ip addr/mask for each interface. */
421 /* Allocate space for data structures in the parser. */
424 if (yyparse() || parse_error) {
425 (void) printf("doesn't parse.\n");
427 (void) printf("parses OK.\n\n");
429 (void) printf("User %s not found\n", pw.pw_name);
431 (void) printf("[%d]\n", top-1);
432 (void) printf("user_match : %d\n", user_matches);
433 (void) printf("host_match : %d\n", host_matches);
434 (void) printf("cmnd_match : %d\n", cmnd_matches);
435 (void) printf("no_passwd : %d\n", no_passwd);
436 (void) printf("runas_match: %d\n", runas_matches);
437 (void) printf("runas : %s\n", *user_runas);
443 (void) printf("Matching Aliases --\n");