=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/sudo/Attic/parse.c,v retrieving revision 1.11 retrieving revision 1.12 diff -c -r1.11 -r1.12 *** src/usr.bin/sudo/Attic/parse.c 2003/04/19 21:57:17 1.11 --- src/usr.bin/sudo/Attic/parse.c 2004/09/28 15:10:51 1.12 *************** *** 1,35 **** /* ! * Copyright (c) 1996, 1998-2003 Todd C. Miller ! * All rights reserved. * ! * This code is derived from software contributed by Chris Jepeway. * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * 3. The name of the author may not be used to endorse or promote products ! * derived from this software without specific prior written permission. ! * ! * 4. Products derived from this software may not be called "Sudo" nor ! * may "Sudo" appear in their names without specific prior written ! * permission from the author. ! * ! * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, ! * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY ! * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ! * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ! * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ! * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ! * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ! * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * --- 1,17 ---- /* ! * Copyright (c) 1996, 1998-2004 Todd C. Miller * ! * Permission to use, copy, modify, and distribute this software for any ! * purpose with or without fee is hereby granted, provided that the above ! * copyright notice and this permission notice appear in all copies. * ! * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ! * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ! * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ! * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ! * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ! * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ! * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *************** *** 100,106 **** #endif /* HAVE_FNMATCH */ #ifndef lint ! static const char rcsid[] = "$Sudo: parse.c,v 1.142 2003/04/16 00:42:10 millert Exp $"; #endif /* lint */ /* --- 82,88 ---- #endif /* HAVE_FNMATCH */ #ifndef lint ! static const char rcsid[] = "$Sudo: parse.c,v 1.161 2004/08/24 18:01:13 millert Exp $"; #endif /* lint */ /* *************** *** 124,136 **** sudoers_lookup(pwflag) int pwflag; { ! int error; ! int pwcheck; ! int nopass; - /* Become sudoers file owner */ - set_perms(PERM_SUDOERS); - /* We opened _PATH_SUDOERS in check_sudoers() so just rewind it. */ rewind(sudoers_fp); yyin = sudoers_fp; --- 106,114 ---- sudoers_lookup(pwflag) int pwflag; { ! int error, nopass; ! enum def_tupple pwcheck; /* We opened _PATH_SUDOERS in check_sudoers() so just rewind it. */ rewind(sudoers_fp); yyin = sudoers_fp; *************** *** 139,165 **** /* Allocate space for data structures in the parser. */ init_parser(); ! /* If pwcheck *could* be PWCHECK_ALL or PWCHECK_ANY, keep more state. */ if (pwflag > 0) keepall = TRUE; ! /* Need to be root while stat'ing things in the parser. */ ! set_perms(PERM_ROOT); error = yyparse(); /* Close the sudoers file now that we are done with it. */ (void) fclose(sudoers_fp); sudoers_fp = NULL; ! if (error || parse_error) return(VALIDATE_ERROR); /* * The pw options may have changed during sudoers parse so we * wait until now to set this. */ if (pwflag) ! pwcheck = (pwflag == -1) ? PWCHECK_NEVER : def_ival(pwflag); else pwcheck = 0; --- 117,145 ---- /* Allocate space for data structures in the parser. */ init_parser(); ! /* If pwcheck *could* be "all" or "any", keep more state. */ if (pwflag > 0) keepall = TRUE; ! /* Need to be runas user while stat'ing things in the parser. */ ! set_perms(PERM_RUNAS); error = yyparse(); /* Close the sudoers file now that we are done with it. */ (void) fclose(sudoers_fp); sudoers_fp = NULL; ! if (error || parse_error) { ! set_perms(PERM_ROOT); return(VALIDATE_ERROR); + } /* * The pw options may have changed during sudoers parse so we * wait until now to set this. */ if (pwflag) ! pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple; else pwcheck = 0; *************** *** 167,207 **** * Assume the worst. If the stack is empty the user was * not mentioned at all. */ ! if (def_flag(I_AUTHENTICATE)) error = VALIDATE_NOT_OK; else error = VALIDATE_NOT_OK | FLAG_NOPASS; if (pwcheck) { ! error |= FLAG_NO_CHECK; } else { ! error |= FLAG_NO_HOST; if (!top) ! error |= FLAG_NO_USER; } /* ! * Only check the actual command if pwcheck flag is not set. * It is set for the "validate", "list" and "kill" pseudo-commands. * Always check the host and user. */ nopass = -1; ! if (pwcheck) { int found; ! if (pwcheck == PWCHECK_NEVER || !def_flag(I_AUTHENTICATE)) nopass = FLAG_NOPASS; found = 0; while (top) { if (host_matches == TRUE) { found = 1; ! if (pwcheck == PWCHECK_ANY && no_passwd == TRUE) nopass = FLAG_NOPASS; ! else if (pwcheck == PWCHECK_ALL && nopass != 0) nopass = (no_passwd == TRUE) ? FLAG_NOPASS : 0; } top--; } if (found) { if (nopass == -1) nopass = 0; return(VALIDATE_OK | nopass); --- 147,190 ---- * Assume the worst. If the stack is empty the user was * not mentioned at all. */ ! if (def_authenticate) error = VALIDATE_NOT_OK; else error = VALIDATE_NOT_OK | FLAG_NOPASS; if (pwcheck) { ! SET(error, FLAG_NO_CHECK); } else { ! SET(error, FLAG_NO_HOST); if (!top) ! SET(error, FLAG_NO_USER); } /* ! * Only check the actual command if pwflag is not set. * It is set for the "validate", "list" and "kill" pseudo-commands. * Always check the host and user. */ nopass = -1; ! if (pwflag) { int found; ! if (pwcheck == always && def_authenticate) ! nopass = FLAG_CHECK_USER; ! else if (pwcheck == never || !def_authenticate) nopass = FLAG_NOPASS; found = 0; while (top) { if (host_matches == TRUE) { found = 1; ! if (pwcheck == any && no_passwd == TRUE) nopass = FLAG_NOPASS; ! else if (pwcheck == all && nopass != 0) nopass = (no_passwd == TRUE) ? FLAG_NOPASS : 0; } top--; } if (found) { + set_perms(PERM_ROOT); if (nopass == -1) nopass = 0; return(VALIDATE_OK | nopass); *************** *** 209,242 **** } else { while (top) { if (host_matches == TRUE) { ! error &= ~FLAG_NO_HOST; ! if (runas_matches == TRUE) { ! if (cmnd_matches == TRUE) { ! /* ! * User was granted access to cmnd on host. ! * If no passwd required return as such. ! */ ! if (no_passwd == TRUE) ! return(VALIDATE_OK | FLAG_NOPASS); ! else ! return(VALIDATE_OK); ! } else if (cmnd_matches == FALSE) { ! /* ! * User was explicitly denied access to cmnd on host. ! */ ! if (no_passwd == TRUE) ! return(VALIDATE_NOT_OK | FLAG_NOPASS); ! else ! return(VALIDATE_NOT_OK); ! } } } top--; } } /* ! * The user was not explicitly granted nor denied access. */ if (nopass == -1) nopass = 0; --- 192,224 ---- } else { while (top) { if (host_matches == TRUE) { ! CLR(error, FLAG_NO_HOST); ! if (runas_matches == TRUE && cmnd_matches == TRUE) { ! /* ! * User was granted access to cmnd on host as user. ! */ ! set_perms(PERM_ROOT); ! return(VALIDATE_OK | ! (no_passwd == TRUE ? FLAG_NOPASS : 0) | ! (no_execve == TRUE ? FLAG_NOEXEC : 0)); ! } else if ((runas_matches == TRUE && cmnd_matches == FALSE) || ! (runas_matches == FALSE && cmnd_matches == TRUE)) { ! /* ! * User was explicitly denied access to cmnd on host. ! */ ! set_perms(PERM_ROOT); ! return(VALIDATE_NOT_OK | ! (no_passwd == TRUE ? FLAG_NOPASS : 0) | ! (no_execve == TRUE ? FLAG_NOEXEC : 0)); } } top--; } } + set_perms(PERM_ROOT); /* ! * The user was neither explicitly granted nor denied access. */ if (nopass == -1) nopass = 0; *************** *** 245,288 **** /* * If path doesn't end in /, return TRUE iff cmnd & path name the same inode; ! * otherwise, return TRUE if cmnd names one of the inodes in path. */ int ! command_matches(cmnd, cmnd_args, path, sudoers_args) ! char *cmnd; ! char *cmnd_args; ! char *path; char *sudoers_args; { ! int plen; ! static struct stat cst; ! struct stat pst; ! DIR *dirp; struct dirent *dent; ! char buf[MAXPATHLEN]; ! static char *cmnd_base; ! /* Don't bother with pseudo commands like "validate" */ ! if (strchr(cmnd, '/') == NULL) ! return(FALSE); ! ! plen = strlen(path); ! ! /* Only need to stat cmnd once since it never changes */ ! if (cst.st_dev == 0) { ! if (stat(cmnd, &cst) == -1) return(FALSE); ! if ((cmnd_base = strrchr(cmnd, '/')) == NULL) ! cmnd_base = cmnd; ! else ! cmnd_base++; } /* ! * If the pathname has meta characters in it use fnmatch(3) ! * to do the matching */ ! if (has_meta(path)) { /* * Return true if fnmatch(3) succeeds AND * a) there are no args in sudoers OR --- 227,272 ---- /* * If path doesn't end in /, return TRUE iff cmnd & path name the same inode; ! * otherwise, return TRUE if user_cmnd names one of the inodes in path. */ int ! command_matches(sudoers_cmnd, sudoers_args) ! char *sudoers_cmnd; char *sudoers_args; { ! struct stat sudoers_stat; struct dirent *dent; ! char buf[PATH_MAX]; ! DIR *dirp; ! /* Check for pseudo-commands */ ! if (strchr(user_cmnd, '/') == NULL) { ! /* ! * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND ! * a) there are no args in sudoers OR ! * b) there are no args on command line and none req by sudoers OR ! * c) there are args in sudoers and on command line and they match ! */ ! if (strcmp(sudoers_cmnd, "sudoedit") != 0 || ! strcmp(user_cmnd, "sudoedit") != 0) return(FALSE); ! if (!sudoers_args || ! (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) || ! (sudoers_args && ! fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) { ! if (safe_cmnd) ! free(safe_cmnd); ! safe_cmnd = estrdup(sudoers_cmnd); ! return(TRUE); ! } else ! return(FALSE); } /* ! * If sudoers_cmnd has meta characters in it, use fnmatch(3) ! * to do the matching. */ ! if (has_meta(sudoers_cmnd)) { /* * Return true if fnmatch(3) succeeds AND * a) there are no args in sudoers OR *************** *** 290,301 **** * c) there are args in sudoers and on command line and they match * else return false. */ ! if (fnmatch(path, cmnd, FNM_PATHNAME) != 0) return(FALSE); if (!sudoers_args || ! (!cmnd_args && sudoers_args && !strcmp("\"\"", sudoers_args)) || ! (sudoers_args && fnmatch(sudoers_args, cmnd_args ? cmnd_args : "", ! 0) == 0)) { if (safe_cmnd) free(safe_cmnd); safe_cmnd = estrdup(user_cmnd); --- 274,285 ---- * c) there are args in sudoers and on command line and they match * else return false. */ ! if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0) return(FALSE); if (!sudoers_args || ! (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) || ! (sudoers_args && ! fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) { if (safe_cmnd) free(safe_cmnd); safe_cmnd = estrdup(user_cmnd); *************** *** 303,321 **** } else return(FALSE); } else { /* * No meta characters * Check to make sure this is not a directory spec (doesn't end in '/') */ ! if (path[plen - 1] != '/') { ! char *p; ! /* Only proceed if the basenames of cmnd and path are the same */ ! if ((p = strrchr(path, '/')) == NULL) ! p = path; else ! p++; ! if (strcmp(cmnd_base, p) != 0 || stat(path, &pst) == -1) return(FALSE); /* --- 287,308 ---- } else return(FALSE); } else { + size_t dlen = strlen(sudoers_cmnd); + /* * No meta characters * Check to make sure this is not a directory spec (doesn't end in '/') */ ! if (sudoers_cmnd[dlen - 1] != '/') { ! char *base; ! /* Only proceed if user_base and basename(sudoers_cmnd) match */ ! if ((base = strrchr(sudoers_cmnd, '/')) == NULL) ! base = sudoers_cmnd; else ! base++; ! if (strcmp(user_base, base) != 0 || ! stat(sudoers_cmnd, &sudoers_stat) == -1) return(FALSE); /* *************** *** 324,360 **** * b) there are no args on command line and none req by sudoers OR * c) there are args in sudoers and on command line and they match */ ! if (cst.st_dev != pst.st_dev || cst.st_ino != pst.st_ino) return(FALSE); if (!sudoers_args || ! (!cmnd_args && sudoers_args && !strcmp("\"\"", sudoers_args)) || (sudoers_args && ! fnmatch(sudoers_args, cmnd_args ? cmnd_args : "", 0) == 0)) { if (safe_cmnd) free(safe_cmnd); ! safe_cmnd = estrdup(path); return(TRUE); } else return(FALSE); } /* ! * Grot through path's directory entries, looking for cmnd. */ ! dirp = opendir(path); if (dirp == NULL) return(FALSE); while ((dent = readdir(dirp)) != NULL) { ! /* ignore paths > MAXPATHLEN (XXX - log) */ ! if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf) || ! strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf)) continue; /* only stat if basenames are the same */ ! if (strcmp(cmnd_base, dent->d_name) != 0 || stat(buf, &pst) == -1) continue; ! if (cst.st_dev == pst.st_dev && cst.st_ino == pst.st_ino) { if (safe_cmnd) free(safe_cmnd); safe_cmnd = estrdup(buf); --- 311,352 ---- * b) there are no args on command line and none req by sudoers OR * c) there are args in sudoers and on command line and they match */ ! if (user_stat->st_dev != sudoers_stat.st_dev || ! user_stat->st_ino != sudoers_stat.st_ino) return(FALSE); if (!sudoers_args || ! (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) || (sudoers_args && ! fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) { if (safe_cmnd) free(safe_cmnd); ! safe_cmnd = estrdup(sudoers_cmnd); return(TRUE); } else return(FALSE); } /* ! * Grot through sudoers_cmnd's directory entries, looking for user_base. */ ! dirp = opendir(sudoers_cmnd); if (dirp == NULL) return(FALSE); + if (strlcpy(buf, sudoers_cmnd, sizeof(buf)) >= sizeof(buf)) + return(FALSE); while ((dent = readdir(dirp)) != NULL) { ! /* ignore paths > PATH_MAX (XXX - log) */ ! buf[dlen] = '\0'; ! if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf)) continue; /* only stat if basenames are the same */ ! if (strcmp(user_base, dent->d_name) != 0 || ! stat(buf, &sudoers_stat) == -1) continue; ! if (user_stat->st_dev == sudoers_stat.st_dev && ! user_stat->st_ino == sudoers_stat.st_ino) { if (safe_cmnd) free(safe_cmnd); safe_cmnd = estrdup(buf); *************** *** 433,467 **** } /* * Returns TRUE if the given user belongs to the named group, * else returns FALSE. */ int ! usergr_matches(group, user) char *group; char *user; { struct group *grp; ! struct passwd *pw; char **cur; /* make sure we have a valid usergroup, sudo style */ if (*group++ != '%') return(FALSE); ! if ((grp = getgrnam(group)) == NULL) return(FALSE); ! /* ! * Check against user's real gid as well as group's user list ! */ ! if ((pw = getpwnam(user)) == NULL) return(FALSE); ! if (grp->gr_gid == pw->pw_gid) return(TRUE); ! for (cur=grp->gr_mem; *cur; cur++) { if (strcmp(*cur, user) == 0) return(TRUE); } --- 425,480 ---- } /* + * Returns TRUE if the user/uid from sudoers matches the specified user/uid, + * else returns FALSE. + */ + int + userpw_matches(sudoers_user, user, pw) + char *sudoers_user; + char *user; + struct passwd *pw; + { + if (pw != NULL && *sudoers_user == '#') { + uid_t uid = atoi(sudoers_user + 1); + if (uid == pw->pw_uid) + return(1); + } + return(strcmp(sudoers_user, user) == 0); + } + + /* * Returns TRUE if the given user belongs to the named group, * else returns FALSE. + * XXX - reduce the number of passwd/group lookups */ int ! usergr_matches(group, user, pw) char *group; char *user; + struct passwd *pw; { struct group *grp; ! gid_t pw_gid; char **cur; /* make sure we have a valid usergroup, sudo style */ if (*group++ != '%') return(FALSE); ! /* look up user's primary gid in the passwd file */ ! if (pw == NULL && (pw = getpwnam(user)) == NULL) return(FALSE); + pw_gid = pw->pw_gid; ! if ((grp = getgrnam(group)) == NULL) return(FALSE); ! /* check against user's primary (passwd file) gid */ ! if (grp->gr_gid == pw_gid) return(TRUE); ! /* check to see if user is explicitly listed in the group */ ! for (cur = grp->gr_mem; *cur; cur++) { if (strcmp(*cur, user) == 0) return(TRUE); } *************** *** 521,527 **** char *s; { char *t; ! for (t = s; *t; t++) { if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']') return(TRUE); --- 534,540 ---- char *s; { char *t; ! for (t = s; *t; t++) { if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']') return(TRUE);