Add cmnd_base to struct sudo_user and set it in init_vars().
Add cmnd_stat to struct sudo_user and set it in sudo_goodpath(). No longer use gross statics in command_matches(). Also rename some variables for improved clarity.
This commit is contained in:
10
TODO
10
TODO
@@ -127,17 +127,15 @@ TODO list (most will be addressed in sudo 2.0)
|
||||
line and that have a constant record length (sparse files) for
|
||||
easy seeking.
|
||||
|
||||
46) Move cmnd_base setting and stashing of stat info from parse.c to sudo.c
|
||||
|
||||
47) Investigate using glob(3) instead of fnmatch(3) for path matching. That
|
||||
46) Investigate using glob(3) instead of fnmatch(3) for path matching. That
|
||||
way we can stat each potential match like we normally would. Patterns
|
||||
ending in '/*' can be replaced with '/basename' as an optimization.
|
||||
|
||||
48) Some way of using a new pty for the program run via sudo would prevent
|
||||
47) Some way of using a new pty for the program run via sudo would prevent
|
||||
access to the caller's /dev/tty (but probably makes job control tricky).
|
||||
|
||||
49) Maybe have a database of checksums that commands are verified against.
|
||||
48) Maybe have a database of checksums that commands are verified against.
|
||||
Basically replace the st_ino/st_dev check with a checksum lookup.
|
||||
|
||||
50) Look into testing writability of a file via sudoedit *before* doing
|
||||
49) Look into testing writability of a file via sudoedit *before* doing
|
||||
the edit; e.g., try opening with O_APPEND.
|
||||
|
@@ -62,9 +62,10 @@ static const char rcsid[] = "$Sudo$";
|
||||
* but it is in '.' and IGNORE_DOT is set.
|
||||
*/
|
||||
int
|
||||
find_path(infile, outfile, path)
|
||||
find_path(infile, outfile, sbp, path)
|
||||
char *infile; /* file to find */
|
||||
char **outfile; /* result parameter */
|
||||
struct stat *sbp; /* stat result parameter */
|
||||
char *path; /* path to search */
|
||||
{
|
||||
static char command[PATH_MAX]; /* qualified filename */
|
||||
@@ -83,7 +84,7 @@ find_path(infile, outfile, path)
|
||||
*/
|
||||
if (strchr(infile, '/')) {
|
||||
strlcpy(command, infile, sizeof(command)); /* paranoia */
|
||||
if (sudo_goodpath(command)) {
|
||||
if (sudo_goodpath(command, sbp)) {
|
||||
*outfile = command;
|
||||
return(FOUND);
|
||||
} else
|
||||
@@ -120,7 +121,7 @@ find_path(infile, outfile, path)
|
||||
len = snprintf(command, sizeof(command), "%s/%s", path, infile);
|
||||
if (len <= 0 || len >= sizeof(command))
|
||||
errx(1, "%s: File name too long", infile);
|
||||
if ((result = sudo_goodpath(command)))
|
||||
if ((result = sudo_goodpath(command, sbp)))
|
||||
break;
|
||||
|
||||
path = n + 1;
|
||||
@@ -132,7 +133,7 @@ find_path(infile, outfile, path)
|
||||
* Check current dir if dot was in the PATH
|
||||
*/
|
||||
if (!result && checkdot) {
|
||||
result = sudo_goodpath(infile);
|
||||
result = sudo_goodpath(infile, sbp);
|
||||
if (result && def_ignore_dot)
|
||||
return(NOT_FOUND_DOT);
|
||||
}
|
||||
|
@@ -47,8 +47,9 @@ static const char rcsid[] = "$Sudo$";
|
||||
* Verify that path is a normal file and executable by root.
|
||||
*/
|
||||
char *
|
||||
sudo_goodpath(path)
|
||||
sudo_goodpath(path, sbp)
|
||||
const char *path;
|
||||
struct stat *sbp;
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
@@ -65,5 +66,7 @@ sudo_goodpath(path)
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if (sbp != NULL)
|
||||
(void) memcpy(sbp, &sb, sizeof(struct stat));
|
||||
return((char *)path);
|
||||
}
|
||||
|
74
parse.c
74
parse.c
@@ -230,27 +230,25 @@ sudoers_lookup(pwflag)
|
||||
* otherwise, return TRUE if user_cmnd names one of the inodes in path.
|
||||
*/
|
||||
int
|
||||
command_matches(path, sudoers_args)
|
||||
char *path;
|
||||
command_matches(sudoers_cmnd, sudoers_args)
|
||||
char *sudoers_cmnd;
|
||||
char *sudoers_args;
|
||||
{
|
||||
int plen;
|
||||
static struct stat cst;
|
||||
struct stat pst;
|
||||
DIR *dirp;
|
||||
struct stat sudoers_stat;
|
||||
struct dirent *dent;
|
||||
char buf[PATH_MAX];
|
||||
static char *cmnd_base;
|
||||
DIR *dirp;
|
||||
|
||||
/* Check for pseudo-commands */
|
||||
if (strchr(user_cmnd, '/') == NULL) {
|
||||
/*
|
||||
* Return true if both path and user_cmnd are "sudoedit" AND
|
||||
* 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(path, "sudoedit") != 0 || strcmp(user_cmnd, "sudoedit") != 0)
|
||||
if (strcmp(sudoers_cmnd, "sudoedit") != 0 ||
|
||||
strcmp(user_cmnd, "sudoedit") != 0)
|
||||
return(FALSE);
|
||||
if (!sudoers_args ||
|
||||
(!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
|
||||
@@ -258,29 +256,17 @@ command_matches(path, sudoers_args)
|
||||
fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
|
||||
if (safe_cmnd)
|
||||
free(safe_cmnd);
|
||||
safe_cmnd = estrdup(path);
|
||||
safe_cmnd = estrdup(sudoers_cmnd);
|
||||
return(TRUE);
|
||||
} else
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
plen = strlen(path);
|
||||
|
||||
/* Only need to stat user_cmnd and set base once since it never changes */
|
||||
if (cmnd_base == NULL) {
|
||||
if (stat(user_cmnd, &cst) == -1)
|
||||
return(FALSE);
|
||||
if ((cmnd_base = strrchr(user_cmnd, '/')) == NULL)
|
||||
cmnd_base = user_cmnd;
|
||||
else
|
||||
cmnd_base++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the pathname has meta characters in it use fnmatch(3)
|
||||
* to do the matching
|
||||
* If sudoers_cmnd has meta characters in it, use fnmatch(3)
|
||||
* to do the matching.
|
||||
*/
|
||||
if (has_meta(path)) {
|
||||
if (has_meta(sudoers_cmnd)) {
|
||||
/*
|
||||
* Return true if fnmatch(3) succeeds AND
|
||||
* a) there are no args in sudoers OR
|
||||
@@ -288,7 +274,7 @@ command_matches(path, sudoers_args)
|
||||
* c) there are args in sudoers and on command line and they match
|
||||
* else return false.
|
||||
*/
|
||||
if (fnmatch(path, user_cmnd, FNM_PATHNAME) != 0)
|
||||
if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0)
|
||||
return(FALSE);
|
||||
if (!sudoers_args ||
|
||||
(!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
|
||||
@@ -301,19 +287,22 @@ command_matches(path, sudoers_args)
|
||||
} 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 (path[plen - 1] != '/') {
|
||||
char *p;
|
||||
if (sudoers_cmnd[dlen - 1] != '/') {
|
||||
char *base;
|
||||
|
||||
/* Only proceed if cmnd_base and basename(path) are the same */
|
||||
if ((p = strrchr(path, '/')) == NULL)
|
||||
p = path;
|
||||
/* Only proceed if user_base and basename(sudoers_cmnd) match */
|
||||
if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
|
||||
base = sudoers_cmnd;
|
||||
else
|
||||
p++;
|
||||
if (strcmp(cmnd_base, p) != 0 || stat(path, &pst) == -1)
|
||||
base++;
|
||||
if (strcmp(user_base, base) != 0 ||
|
||||
stat(sudoers_cmnd, &sudoers_stat) == -1)
|
||||
return(FALSE);
|
||||
|
||||
/*
|
||||
@@ -322,7 +311,8 @@ command_matches(path, sudoers_args)
|
||||
* 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)
|
||||
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)) ||
|
||||
@@ -330,31 +320,33 @@ command_matches(path, sudoers_args)
|
||||
fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
|
||||
if (safe_cmnd)
|
||||
free(safe_cmnd);
|
||||
safe_cmnd = estrdup(path);
|
||||
safe_cmnd = estrdup(sudoers_cmnd);
|
||||
return(TRUE);
|
||||
} else
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Grot through path's directory entries, looking for cmnd_base.
|
||||
* Grot through sudoers_cmnd's directory entries, looking for user_base.
|
||||
*/
|
||||
dirp = opendir(path);
|
||||
dirp = opendir(sudoers_cmnd);
|
||||
if (dirp == NULL)
|
||||
return(FALSE);
|
||||
|
||||
if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf))
|
||||
if (strlcpy(buf, sudoers_cmnd, sizeof(buf)) >= sizeof(buf))
|
||||
return(FALSE);
|
||||
while ((dent = readdir(dirp)) != NULL) {
|
||||
/* ignore paths > PATH_MAX (XXX - log) */
|
||||
buf[plen] = '\0';
|
||||
buf[dlen] = '\0';
|
||||
if (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)
|
||||
if (strcmp(user_base, dent->d_name) != 0 ||
|
||||
stat(buf, &sudoers_stat) == -1)
|
||||
continue;
|
||||
if (cst.st_dev == pst.st_dev && cst.st_ino == pst.st_ino) {
|
||||
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);
|
||||
|
9
sudo.c
9
sudo.c
@@ -622,16 +622,17 @@ init_vars(sudo_mode)
|
||||
|
||||
/* Resolve the path and return. */
|
||||
rval = FOUND;
|
||||
user_stat = emalloc(sizeof(struct stat));
|
||||
if (sudo_mode & (MODE_RUN | MODE_EDIT)) {
|
||||
if (ISSET(sudo_mode, MODE_RUN)) {
|
||||
/* XXX - default_runas may be modified during parsing of sudoers */
|
||||
set_perms(PERM_RUNAS);
|
||||
rval = find_path(NewArgv[0], &user_cmnd, user_path);
|
||||
rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
|
||||
set_perms(PERM_ROOT);
|
||||
if (rval != FOUND) {
|
||||
/* Failed as root, try as invoking user. */
|
||||
set_perms(PERM_USER);
|
||||
rval = find_path(NewArgv[0], &user_cmnd, user_path);
|
||||
rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
|
||||
set_perms(PERM_ROOT);
|
||||
}
|
||||
}
|
||||
@@ -662,6 +663,10 @@ init_vars(sudo_mode)
|
||||
*--to = '\0';
|
||||
}
|
||||
}
|
||||
if ((user_base = strrchr(user_cmnd, '/')) != NULL)
|
||||
user_base++;
|
||||
else
|
||||
user_base = user_cmnd;
|
||||
|
||||
return(rval);
|
||||
}
|
||||
|
10
sudo.h
10
sudo.h
@@ -35,6 +35,7 @@
|
||||
struct sudo_user {
|
||||
struct passwd *pw;
|
||||
struct passwd *_runas_pw;
|
||||
struct stat *cmnd_stat;
|
||||
char *path;
|
||||
char *shell;
|
||||
char *tty;
|
||||
@@ -43,9 +44,10 @@ struct sudo_user {
|
||||
char *shost;
|
||||
char **runas;
|
||||
char *prompt;
|
||||
char *cmnd_safe;
|
||||
char *cmnd;
|
||||
char *cmnd_args;
|
||||
char *cmnd_base;
|
||||
char *cmnd_safe;
|
||||
char *class_name;
|
||||
};
|
||||
|
||||
@@ -128,6 +130,8 @@ struct sudo_user {
|
||||
#define user_runas (sudo_user.runas)
|
||||
#define user_cmnd (sudo_user.cmnd)
|
||||
#define user_args (sudo_user.cmnd_args)
|
||||
#define user_base (sudo_user.cmnd_base)
|
||||
#define user_stat (sudo_user.cmnd_stat)
|
||||
#define user_path (sudo_user.path)
|
||||
#define user_prompt (sudo_user.prompt)
|
||||
#define user_host (sudo_user.host)
|
||||
@@ -189,9 +193,9 @@ size_t strlcat __P((char *, const char *, size_t));
|
||||
#ifndef HAVE_STRLCPY
|
||||
size_t strlcpy __P((char *, const char *, size_t));
|
||||
#endif
|
||||
char *sudo_goodpath __P((const char *));
|
||||
char *sudo_goodpath __P((const char *, struct stat *));
|
||||
char *tgetpass __P((const char *, int, int));
|
||||
int find_path __P((char *, char **, char *));
|
||||
int find_path __P((char *, char **, struct stat *, char *));
|
||||
void check_user __P((int));
|
||||
void verify_user __P((struct passwd *, char *));
|
||||
int sudoers_lookup __P((int));
|
||||
|
4
visudo.c
4
visudo.c
@@ -248,7 +248,7 @@ main(argc, argv)
|
||||
if (UserEditor && *UserEditor == '\0')
|
||||
UserEditor = NULL;
|
||||
else if (UserEditor) {
|
||||
if (find_path(UserEditor, &Editor, getenv("PATH")) == FOUND) {
|
||||
if (find_path(UserEditor, &Editor, NULL, getenv("PATH")) == FOUND) {
|
||||
UserEditor = Editor;
|
||||
} else {
|
||||
if (def_env_editor) {
|
||||
@@ -318,7 +318,7 @@ main(argc, argv)
|
||||
EditorPath = estrdup(def_editor);
|
||||
Editor = strtok(EditorPath, ":");
|
||||
do {
|
||||
if (sudo_goodpath(Editor))
|
||||
if (sudo_goodpath(Editor, NULL))
|
||||
break;
|
||||
} while ((Editor = strtok(NULL, ":")));
|
||||
|
||||
|
Reference in New Issue
Block a user