2 * Copyright (c) 1996, 1998-2005 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 __unused static const char rcsid[] = "$Sudo: testsudoers.c,v 1.88.2.7 2008/02/09 14:44:49 millert Exp $";
85 void init_parser __P((void));
86 void dumpaliases __P((void));
92 char **Argv, **NewArgv;
93 int parse_error = FALSE;
95 struct interface *interfaces;
96 struct sudo_user sudo_user;
97 extern int clearaliases;
101 * Returns TRUE if "s" has shell meta characters in it,
102 * else returns FALSE.
110 for (t = s; *t; t++) {
111 if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']')
118 * Returns TRUE if user_cmnd matches, in the sudo sense,
119 * the pathname in path; otherwise, return FALSE
122 command_matches(path, sudoers_args)
129 if (user_cmnd == NULL)
132 if ((args = strchr(path, ' ')))
135 if (has_meta(path)) {
136 if (fnmatch(path, user_cmnd, FNM_PATHNAME))
140 else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
142 else if (sudoers_args)
143 return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
148 if (path[plen - 1] != '/') {
149 if (strcmp(user_cmnd, path))
153 else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
155 else if (sudoers_args)
156 return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
161 clen = strlen(user_cmnd);
163 /* path cannot be the parent dir of user_cmnd */
166 if (strchr(user_cmnd + plen + 1, '/') != NULL)
167 /* path could only be an anscestor of user_cmnd -- */
168 /* ignoring, of course, things like // & /./ */
171 /* see whether path is the prefix of user_cmnd */
172 return((strncmp(user_cmnd, path, plen) == 0));
182 struct interface *ifp;
184 struct in6_addr addr6;
190 if (inet_pton(AF_INET6, n, &addr6) > 0) {
196 addr.s_addr = inet_addr(n);
199 for (i = 0; i < num_interfaces; i++) {
200 ifp = &interfaces[i];
201 if (ifp->family != family)
205 if (ifp->addr.ip4.s_addr == addr.s_addr ||
206 (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
212 if (memcmp(ifp->addr.ip6.s6_addr, addr6.s6_addr,
213 sizeof(addr6.s6_addr)) == 0)
215 for (j = 0; j < sizeof(addr6.s6_addr); j++) {
216 if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr6.s6_addr[j])
219 if (j == sizeof(addr6.s6_addr))
221 #endif /* HAVE_IN6_ADDR */
229 addr_matches_if_netmask(n, m)
234 struct in_addr addr, mask;
235 struct interface *ifp;
237 struct in6_addr addr6, mask6;
243 if (inet_pton(AF_INET6, n, &addr6) > 0)
249 addr.s_addr = inet_addr(n);
252 if (family == AF_INET) {
254 mask.s_addr = inet_addr(m);
257 mask.s_addr = 0xffffffff;
260 mask.s_addr = htonl(mask.s_addr);
265 if (inet_pton(AF_INET6, m, &mask6) <= 0) {
267 for (i = 0; i < 16; i++) {
269 mask6.s6_addr[i] = 0;
270 else if (i * 8 + 8 <= j)
271 mask6.s6_addr[i] = 0xff;
273 mask6.s6_addr[i] = 0xff00 >> (j - i * 8);
277 #endif /* HAVE_IN6_ADDR */
279 for (i = 0; i < num_interfaces; i++) {
280 ifp = &interfaces[i];
281 if (ifp->family != family)
285 if ((ifp->addr.ip4.s_addr & mask.s_addr) == addr.s_addr)
289 for (j = 0; j < sizeof(addr6.s6_addr); j++) {
290 if ((ifp->addr.ip6.s6_addr[j] & mask6.s6_addr[j]) != addr6.s6_addr[j])
293 if (j == sizeof(addr6.s6_addr))
295 #endif /* HAVE_IN6_ADDR */
303 * Returns TRUE if "n" is one of our ip addresses or if
304 * "n" is a network that we are on, else returns FALSE.
313 /* If there's an explicit netmask, use it. */
314 if ((m = strchr(n, '/'))) {
316 retval = addr_matches_if_netmask(n, m);
319 retval = addr_matches_if(n);
325 hostname_matches(shost, lhost, pattern)
330 if (has_meta(pattern)) {
331 if (strchr(pattern, '.'))
332 return(fnmatch(pattern, lhost, FNM_CASEFOLD));
334 return(fnmatch(pattern, shost, FNM_CASEFOLD));
336 if (strchr(pattern, '.'))
337 return(strcasecmp(lhost, pattern));
339 return(strcasecmp(shost, pattern));
344 userpw_matches(sudoers_user, user, pw)
349 if (pw != NULL && *sudoers_user == '#') {
350 uid_t uid = atoi(sudoers_user + 1);
351 if (uid == pw->pw_uid)
354 return(strcmp(sudoers_user, user) == 0);
358 usergr_matches(group, user, pw)
366 /* Make sure we have a valid usergroup, sudo style. */
370 if ((grp = getgrnam(group)) == NULL)
374 * Check against user's real gid as well as group's user list
376 if (getgid() == grp->gr_gid)
379 for (cur=grp->gr_mem; *cur; cur++) {
380 if (strcmp(*cur, user) == 0)
388 netgr_matches(netgr, host, shost, user)
394 #ifdef HAVE_GETDOMAINNAME
395 static char *domain = (char *) -1;
397 static char *domain = NULL;
398 #endif /* HAVE_GETDOMAINNAME */
400 /* Make sure we have a valid netgroup, sudo style. */
404 #ifdef HAVE_GETDOMAINNAME
405 /* Get the domain name (if any). */
406 if (domain == (char *) -1) {
407 domain = (char *) emalloc(MAXHOSTNAMELEN);
409 if (getdomainname(domain, MAXHOSTNAMELEN) != 0 || *domain == '\0') {
414 #endif /* HAVE_GETDOMAINNAME */
417 if (innetgr(netgr, host, user, domain))
419 else if (host != shost && innetgr(netgr, shost, user, domain))
421 #endif /* HAVE_INNETGR */
467 if (Argc >= 6 && strcmp(Argv[1], "-u") == 0) {
468 user_runas = &Argv[2];
469 pw.pw_name = Argv[3];
475 } else if (Argc >= 4) {
476 pw.pw_name = Argv[1];
483 (void) fprintf(stderr,
484 "usage: sudo [-u user] <user> <host> <command> [args]\n");
488 sudo_user.pw = &pw; /* user_name needs to be defined */
490 if ((p = strchr(user_host, '.'))) {
492 user_shost = estrdup(user_host);
495 user_shost = user_host;
498 /* Fill in user_args from NewArgv. */
503 size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
504 strlen(NewArgv[NewArgc-1]) + 1;
505 user_args = (char *) emalloc(size);
506 for (to = user_args, from = NewArgv + 1; *from; from++) {
507 n = strlcpy(to, *from, size - (to - user_args));
508 if (n >= size - (to - user_args))
509 errx(1, "internal error, init_vars() overflow");
516 /* Initialize default values. */
519 /* Warn about aliases that are used before being defined. */
522 /* Need to keep aliases around for dumpaliases(). */
523 clearaliases = FALSE;
525 /* Load ip addr/mask for each interface. */
528 /* Allocate space for data structures in the parser. */
531 if (yyparse() || parse_error) {
532 (void) printf("doesn't parse.\n");
534 (void) printf("parses OK.\n\n");
536 (void) printf("User %s not found\n", pw.pw_name);
538 (void) printf("[%d]\n", top-1);
539 (void) printf("user_match : %d\n", user_matches);
540 (void) printf("host_match : %d\n", host_matches);
541 (void) printf("cmnd_match : %d\n", cmnd_matches);
542 (void) printf("no_passwd : %d\n", no_passwd);
543 (void) printf("runas_match: %d\n", runas_matches);
544 (void) printf("runas : %s\n", *user_runas);
545 if (match[top-1].role)
546 (void) printf("role : %s\n", match[top-1].role);
547 if (match[top-1].type)
548 (void) printf("type : %s\n", match[top-1].type);
554 (void) printf("Matching Aliases --\n");