From: Todd C. Miller Date: Thu, 13 May 2010 21:11:31 +0000 (-0400) Subject: Change how we handle the sudoedit argv. We now require that there X-Git-Tag: SUDO_1_8_0~635 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7c9c5855fd4203bbe5b76e8227c58dfdb57df062;p=sudo 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. --- diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 36106c235..1746a41eb 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -122,7 +122,7 @@ static void set_runaspw(char *); static int sudoers_policy_version(int verbose); static struct passwd *get_authpw(void); 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 */ extern int runas_ngroups; @@ -561,7 +561,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], sudo_endgrent(); if (ISSET(sudo_mode, MODE_EDIT)) { - char *editor = find_editor(&edit_argv); + char *editor = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv); if (!editor) goto done; command_info[info_len++] = fmt_string("command", editor); @@ -1324,10 +1324,10 @@ deserialize_info(char * const settings[], char * const user_info[]) } 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; - int ac, nargc, wasblank; + int ac, i, nargc, wasblank; /* * 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) { 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++) { nargv[ac] = cp; cp = strtok(NULL, " \t"); } + nargv[ac++] = "--"; + for (i = 0; i < nfiles; ) + nargv[ac++] = files[i++]; nargv[ac] = NULL; *argv_out = nargv; @@ -1366,7 +1369,7 @@ resolve_editor(char *editor, char ***argv_out) * not the runas (privileged) user. */ 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]; @@ -1379,7 +1382,7 @@ find_editor(char ***argv_out) ev0[3] = NULL; for (ev = ev0; *ev != NULL; ev++) { 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) break; } @@ -1388,7 +1391,7 @@ find_editor(char ***argv_out) editor = estrdup(def_editor); if ((cp = strchr(editor, ':')) != NULL) *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) { audit_failure(NewArgv, "%s: command not found", editor); diff --git a/src/sudo.c b/src/sudo.c index d7621f1ef..95222fbca 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -246,7 +246,7 @@ main(int argc, char *argv[], char *envp[]) #endif /* RLIMIT_CORE && !SUDO_DEVEL */ /* run_command will call the close method for us */ 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 { exitcode = run_command(&command_details, argv_out, user_env_out); } diff --git a/src/sudo.h b/src/sudo.h index fd913299b..d7e345ae1 100644 --- a/src/sudo.h +++ b/src/sudo.h @@ -192,8 +192,7 @@ extern int debug_level; extern struct plugin_container_list io_plugins; /* sudo_edit.c */ -int sudo_edit(struct command_details *details, char *argv[], char *files[], - char *envp[]); +int sudo_edit(struct command_details *details, char *argv[], char *envp[]); /* parse_args.c */ void usage(int) __attribute__((__noreturn__)); diff --git a/src/sudo_edit.c b/src/sudo_edit.c index 0b7d3ee80..20b7fbd8f 100644 --- a/src/sudo_edit.c +++ b/src/sudo_edit.c @@ -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. */ int -sudo_edit(struct command_details *command_details, char *argv[], char *files[], - char *envp[]) +sudo_edit(struct command_details *command_details, char *argv[], char *envp[]) { struct command_details editor_details; ssize_t nread, nwritten; const char *tmpdir; - char **nargv, **ap, *cp; + char *cp, **nargv, **ap, **files = NULL; 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 timeval tv, tv1, tv2; struct tempfile { @@ -129,34 +129,47 @@ sudo_edit(struct command_details *command_details, char *argv[], char *files[], endpwent(); 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 * and copy the contents of the original to it. */ - for (nfiles = 0; files[nfiles] != NULL; nfiles++) - continue; tf = emalloc2(nfiles, sizeof(*tf)); zero_bytes(tf, nfiles * sizeof(*tf)); for (i = 0, j = 0; i < nfiles; i++) { - retval = -1; + rc = -1; switch_user(command_details->euid, command_details->egid, command_details->ngroups, command_details->groups); if ((ofd = open(files[i], O_RDONLY, 0644)) != -1 || errno == ENOENT) { if (ofd == -1) { zero_bytes(&sb, sizeof(sb)); /* new file */ - retval = 0; + rc = 0; } else { #ifdef HAVE_FSTAT - retval = fstat(ofd, &sb); + rc = fstat(ofd, &sb); #else - retval = stat(tf[j].ofile, &sb); + rc = stat(tf[j].ofile, &sb); #endif } } switch_user(ROOT_UID, user_details.egid, user_details.ngroups, user_details.groups); - if (retval || (ofd != -1 && !S_ISREG(sb.st_mode))) { - if (retval) + if (rc || (ofd != -1 && !S_ISREG(sb.st_mode))) { + if (rc) warning("%s", files[i]); else 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); #ifdef HAVE_FSTAT - retval = fstat(tfd, &sb); + rc = fstat(tfd, &sb); #else - retval = stat(tf[j].tfile, &sb); + rc = stat(tf[j].tfile, &sb); #endif - if (!retval) + if (!rc) mtim_get(&sb, &tf[j].omtim); close(tfd); j++; } - if (nfiles == 0) + if ((nfiles = j) == 0) return(1); /* no files readable, you lose */ /* * 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. */ - for (ap = argv; *ap != NULL; ap++) - continue; - nargc = (int)(ap - argv) + nfiles; + nargc = editor_argc + nfiles; nargv = (char **) emalloc2(nargc + 1, sizeof(char *)); - ac = 0; - for (ap = argv; *ap != NULL; ap++) - nargv[ac++] = *ap; + for (ac = 0; ac < editor_argc; ac++) + nargv[ac] = argv[ac]; for (i = 0; i < nfiles && ac < nargc; ) nargv[ac++] = tf[i++].tfile; 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 */ for (i = 0; i < nfiles; i++) { - retval = -1; + rc = -1; if (seteuid(user_details.uid) != 0) error(1, "seteuid(%d)", (int)user_details.uid); if ((tfd = open(tf[i].tfile, O_RDONLY, 0644)) != -1) { #ifdef HAVE_FSTAT - retval = fstat(tfd, &sb); + rc = fstat(tfd, &sb); #else - retval = stat(tf[i].tfile, &sb); + rc = stat(tf[i].tfile, &sb); #endif } if (seteuid(ROOT_UID) != 0) error(1, "seteuid(ROOT_UID)"); - if (retval || !S_ISREG(sb.st_mode)) { - if (retval) + if (rc || !S_ISREG(sb.st_mode)) { + if (rc) warning("%s", tf[i].tfile); else warningx("%s: not a regular file", tf[i].tfile);