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:
@@ -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);
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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__));
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user