2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-09-03 07:45:47 +00:00

Change how we handle the sudoedit argv. We now require that there

be a "--" in argv to separate the editor and any command line arguments
from the files to be edited.
This commit is contained in:
Todd C. Miller
2010-05-13 17:11:31 -04:00
parent fdd28d411f
commit 7c9c5855fd
4 changed files with 51 additions and 39 deletions

View File

@@ -122,7 +122,7 @@ static void set_runaspw(char *);
static int sudoers_policy_version(int verbose); static int sudoers_policy_version(int verbose);
static struct passwd *get_authpw(void); static struct passwd *get_authpw(void);
static int deserialize_info(char * const settings[], char * const user_info[]); static int deserialize_info(char * const settings[], char * const user_info[]);
static char *find_editor(char ***argv_out); static char *find_editor(int nfiles, char **files, char ***argv_out);
/* XXX */ /* XXX */
extern int runas_ngroups; extern int runas_ngroups;
@@ -561,7 +561,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
sudo_endgrent(); sudo_endgrent();
if (ISSET(sudo_mode, MODE_EDIT)) { if (ISSET(sudo_mode, MODE_EDIT)) {
char *editor = find_editor(&edit_argv); char *editor = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv);
if (!editor) if (!editor)
goto done; goto done;
command_info[info_len++] = fmt_string("command", editor); command_info[info_len++] = fmt_string("command", editor);
@@ -1324,10 +1324,10 @@ deserialize_info(char * const settings[], char * const user_info[])
} }
static char * static char *
resolve_editor(char *editor, char ***argv_out) resolve_editor(char *editor, int nfiles, char **files, char ***argv_out)
{ {
char *cp, **nargv, *editor_path = NULL; char *cp, **nargv, *editor_path = NULL;
int ac, nargc, wasblank; int ac, i, nargc, wasblank;
/* /*
* Split editor into an argument vector; editor is reused (do not free). * Split editor into an argument vector; editor is reused (do not free).
@@ -1349,11 +1349,14 @@ resolve_editor(char *editor, char ***argv_out)
find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) { find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
return NULL; return NULL;
} }
nargv = (char **) emalloc2(nargc + 1, sizeof(char *)); nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *));
for (ac = 0; cp != NULL && ac < nargc; ac++) { for (ac = 0; cp != NULL && ac < nargc; ac++) {
nargv[ac] = cp; nargv[ac] = cp;
cp = strtok(NULL, " \t"); cp = strtok(NULL, " \t");
} }
nargv[ac++] = "--";
for (i = 0; i < nfiles; )
nargv[ac++] = files[i++];
nargv[ac] = NULL; nargv[ac] = NULL;
*argv_out = nargv; *argv_out = nargv;
@@ -1366,7 +1369,7 @@ resolve_editor(char *editor, char ***argv_out)
* not the runas (privileged) user. * not the runas (privileged) user.
*/ */
static char * static char *
find_editor(char ***argv_out) find_editor(int nfiles, char **files, char ***argv_out)
{ {
char *cp, *editor, *editor_path = NULL, **ev, *ev0[4]; char *cp, *editor, *editor_path = NULL, **ev, *ev0[4];
@@ -1379,7 +1382,7 @@ find_editor(char ***argv_out)
ev0[3] = NULL; ev0[3] = NULL;
for (ev = ev0; *ev != NULL; ev++) { for (ev = ev0; *ev != NULL; ev++) {
if ((editor = getenv(*ev)) != NULL && *editor != '\0') { if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
editor_path = resolve_editor(editor, argv_out); editor_path = resolve_editor(editor, nfiles, files, argv_out);
if (editor_path != NULL) if (editor_path != NULL)
break; break;
} }
@@ -1388,7 +1391,7 @@ find_editor(char ***argv_out)
editor = estrdup(def_editor); editor = estrdup(def_editor);
if ((cp = strchr(editor, ':')) != NULL) if ((cp = strchr(editor, ':')) != NULL)
*cp = '\0'; /* def_editor could be a path */ *cp = '\0'; /* def_editor could be a path */
editor_path = resolve_editor(cp, argv_out); editor_path = resolve_editor(cp, nfiles, files, argv_out);
} }
if (!editor_path) { if (!editor_path) {
audit_failure(NewArgv, "%s: command not found", editor); audit_failure(NewArgv, "%s: command not found", editor);

View File

@@ -246,7 +246,7 @@ main(int argc, char *argv[], char *envp[])
#endif /* RLIMIT_CORE && !SUDO_DEVEL */ #endif /* RLIMIT_CORE && !SUDO_DEVEL */
/* run_command will call the close method for us */ /* run_command will call the close method for us */
if (sudo_mode & MODE_EDIT) { if (sudo_mode & MODE_EDIT) {
exitcode = sudo_edit(&command_details, argv_out, nargv + 1, user_env_out); exitcode = sudo_edit(&command_details, argv_out, user_env_out);
} else { } else {
exitcode = run_command(&command_details, argv_out, user_env_out); exitcode = run_command(&command_details, argv_out, user_env_out);
} }

View File

@@ -192,8 +192,7 @@ extern int debug_level;
extern struct plugin_container_list io_plugins; extern struct plugin_container_list io_plugins;
/* sudo_edit.c */ /* sudo_edit.c */
int sudo_edit(struct command_details *details, char *argv[], char *files[], int sudo_edit(struct command_details *details, char *argv[], char *envp[]);
char *envp[]);
/* parse_args.c */ /* parse_args.c */
void usage(int) __attribute__((__noreturn__)); void usage(int) __attribute__((__noreturn__));

View File

@@ -83,15 +83,15 @@ switch_user(uid_t euid, gid_t egid, int ngroups, GETGROUPS_T *groups)
* Wrapper to allow users to edit privileged files with their own uid. * Wrapper to allow users to edit privileged files with their own uid.
*/ */
int int
sudo_edit(struct command_details *command_details, char *argv[], char *files[], sudo_edit(struct command_details *command_details, char *argv[], char *envp[])
char *envp[])
{ {
struct command_details editor_details; struct command_details editor_details;
ssize_t nread, nwritten; ssize_t nread, nwritten;
const char *tmpdir; const char *tmpdir;
char **nargv, **ap, *cp; char *cp, **nargv, **ap, **files = NULL;
char buf[BUFSIZ]; char buf[BUFSIZ];
int retval, i, j, ac, ofd, tfd, nargc, nfiles, rval, tmplen; int rc, i, j, ac, ofd, tfd, nargc, rval, tmplen;
int editor_argc = 0, nfiles = 0;
struct stat sb; struct stat sb;
struct timeval tv, tv1, tv2; struct timeval tv, tv1, tv2;
struct tempfile { struct tempfile {
@@ -129,34 +129,47 @@ sudo_edit(struct command_details *command_details, char *argv[], char *files[],
endpwent(); endpwent();
endgrent(); endgrent();
/*
* The user's editor must be separated from the files to be
* edited by a "--" option.
*/
for (ap = argv; *ap != NULL; ap++) {
if (files)
nfiles++;
else if (strcmp(*ap, "--") == 0)
files = ap + 1;
else
editor_argc++;
}
if (nfiles == 0)
return 1;
/* /*
* For each file specified by the user, make a temporary version * For each file specified by the user, make a temporary version
* and copy the contents of the original to it. * and copy the contents of the original to it.
*/ */
for (nfiles = 0; files[nfiles] != NULL; nfiles++)
continue;
tf = emalloc2(nfiles, sizeof(*tf)); tf = emalloc2(nfiles, sizeof(*tf));
zero_bytes(tf, nfiles * sizeof(*tf)); zero_bytes(tf, nfiles * sizeof(*tf));
for (i = 0, j = 0; i < nfiles; i++) { for (i = 0, j = 0; i < nfiles; i++) {
retval = -1; rc = -1;
switch_user(command_details->euid, command_details->egid, switch_user(command_details->euid, command_details->egid,
command_details->ngroups, command_details->groups); command_details->ngroups, command_details->groups);
if ((ofd = open(files[i], O_RDONLY, 0644)) != -1 || errno == ENOENT) { if ((ofd = open(files[i], O_RDONLY, 0644)) != -1 || errno == ENOENT) {
if (ofd == -1) { if (ofd == -1) {
zero_bytes(&sb, sizeof(sb)); /* new file */ zero_bytes(&sb, sizeof(sb)); /* new file */
retval = 0; rc = 0;
} else { } else {
#ifdef HAVE_FSTAT #ifdef HAVE_FSTAT
retval = fstat(ofd, &sb); rc = fstat(ofd, &sb);
#else #else
retval = stat(tf[j].ofile, &sb); rc = stat(tf[j].ofile, &sb);
#endif #endif
} }
} }
switch_user(ROOT_UID, user_details.egid, switch_user(ROOT_UID, user_details.egid,
user_details.ngroups, user_details.groups); user_details.ngroups, user_details.groups);
if (retval || (ofd != -1 && !S_ISREG(sb.st_mode))) { if (rc || (ofd != -1 && !S_ISREG(sb.st_mode))) {
if (retval) if (rc)
warning("%s", files[i]); warning("%s", files[i]);
else else
warningx("%s: not a regular file", files[i]); warningx("%s: not a regular file", files[i]);
@@ -202,30 +215,27 @@ sudo_edit(struct command_details *command_details, char *argv[], char *files[],
*/ */
(void) touch(tfd, NULL, &tf[j].omtim); (void) touch(tfd, NULL, &tf[j].omtim);
#ifdef HAVE_FSTAT #ifdef HAVE_FSTAT
retval = fstat(tfd, &sb); rc = fstat(tfd, &sb);
#else #else
retval = stat(tf[j].tfile, &sb); rc = stat(tf[j].tfile, &sb);
#endif #endif
if (!retval) if (!rc)
mtim_get(&sb, &tf[j].omtim); mtim_get(&sb, &tf[j].omtim);
close(tfd); close(tfd);
j++; j++;
} }
if (nfiles == 0) if ((nfiles = j) == 0)
return(1); /* no files readable, you lose */ return(1); /* no files readable, you lose */
/* /*
* Allocate space for the new argument vector and fill it in. * Allocate space for the new argument vector and fill it in.
* We concatenate argv (the editor with its args) and the file list * We concatenate the editor with its args and the file list
* to create a new argv. * to create a new argv.
*/ */
for (ap = argv; *ap != NULL; ap++) nargc = editor_argc + nfiles;
continue;
nargc = (int)(ap - argv) + nfiles;
nargv = (char **) emalloc2(nargc + 1, sizeof(char *)); nargv = (char **) emalloc2(nargc + 1, sizeof(char *));
ac = 0; for (ac = 0; ac < editor_argc; ac++)
for (ap = argv; *ap != NULL; ap++) nargv[ac] = argv[ac];
nargv[ac++] = *ap;
for (i = 0; i < nfiles && ac < nargc; ) for (i = 0; i < nfiles && ac < nargc; )
nargv[ac++] = tf[i++].tfile; nargv[ac++] = tf[i++].tfile;
nargv[ac] = NULL; nargv[ac] = NULL;
@@ -247,20 +257,20 @@ sudo_edit(struct command_details *command_details, char *argv[], char *files[],
/* Copy contents of temp files to real ones */ /* Copy contents of temp files to real ones */
for (i = 0; i < nfiles; i++) { for (i = 0; i < nfiles; i++) {
retval = -1; rc = -1;
if (seteuid(user_details.uid) != 0) if (seteuid(user_details.uid) != 0)
error(1, "seteuid(%d)", (int)user_details.uid); error(1, "seteuid(%d)", (int)user_details.uid);
if ((tfd = open(tf[i].tfile, O_RDONLY, 0644)) != -1) { if ((tfd = open(tf[i].tfile, O_RDONLY, 0644)) != -1) {
#ifdef HAVE_FSTAT #ifdef HAVE_FSTAT
retval = fstat(tfd, &sb); rc = fstat(tfd, &sb);
#else #else
retval = stat(tf[i].tfile, &sb); rc = stat(tf[i].tfile, &sb);
#endif #endif
} }
if (seteuid(ROOT_UID) != 0) if (seteuid(ROOT_UID) != 0)
error(1, "seteuid(ROOT_UID)"); error(1, "seteuid(ROOT_UID)");
if (retval || !S_ISREG(sb.st_mode)) { if (rc || !S_ISREG(sb.st_mode)) {
if (retval) if (rc)
warning("%s", tf[i].tfile); warning("%s", tf[i].tfile);
else else
warningx("%s: not a regular file", tf[i].tfile); warningx("%s: not a regular file", tf[i].tfile);