Add support for VISUAL and EDITOR containing command line args.

If env_editor is not set any args in VISUAL and EDITOR are ignored.
Arguments are also now supported in def_editor.
This commit is contained in:
Todd C. Miller
2004-11-18 20:28:53 +00:00
parent cf02ff7f52
commit 75ad6b81a2

110
visudo.c
View File

@@ -97,21 +97,21 @@ struct sudoersfile {
* Function prototypes * Function prototypes
*/ */
static RETSIGTYPE quit __P((int)) __attribute__((__noreturn__)); static RETSIGTYPE quit __P((int)) __attribute__((__noreturn__));
static char *get_editor __P((void)); static char *get_args __P((char *));
static char *get_editor __P((char **));
static char whatnow __P((void)); static char whatnow __P((void));
static int check_aliases __P((int)); static int check_aliases __P((int));
static int check_syntax __P((char *, int)); static int check_syntax __P((char *, int));
static int edit_sudoers __P((struct sudoersfile *, char *, int)); static int edit_sudoers __P((struct sudoersfile *, char *, char *, int));
static int install_sudoers __P((struct sudoersfile *)); static int install_sudoers __P((struct sudoersfile *));
static int print_unused __P((VOID *, VOID *)); static int print_unused __P((VOID *, VOID *));
static int reparse_sudoers __P((char *, int, int)); static int reparse_sudoers __P((char *, char *, int, int));
static int run_command __P((char *, char **)); static int run_command __P((char *, char **));
static void setup_signals __P((void)); static void setup_signals __P((void));
static void usage __P((void)) __attribute__((__noreturn__)); static void usage __P((void)) __attribute__((__noreturn__));
VOID *v2;
void yyerror __P((const char *)); extern void yyerror __P((const char *));
void yyrestart __P((FILE *)); extern void yyrestart __P((FILE *));
/* /*
* External globals exported by the parser * External globals exported by the parser
@@ -144,7 +144,7 @@ main(argc, argv)
char **argv; char **argv;
{ {
struct sudoersfile *sp; struct sudoersfile *sp;
char *editor, *sudoers_path; char *args, *editor, *sudoers_path;
int ch, checkonly, quiet, strict; int ch, checkonly, quiet, strict;
Argv = argv; Argv = argv;
@@ -205,7 +205,7 @@ main(argc, argv)
yyparse(); yyparse();
(void) update_defaults(); (void) update_defaults();
editor = get_editor(); editor = get_editor(&args);
/* Install signal handlers to clean up temp files if we are killed. */ /* Install signal handlers to clean up temp files if we are killed. */
setup_signals(); setup_signals();
@@ -217,11 +217,11 @@ main(argc, argv)
while ((ch = getchar()) != EOF && ch != '\n') while ((ch = getchar()) != EOF && ch != '\n')
continue; continue;
} }
edit_sudoers(sp, editor, -1); edit_sudoers(sp, editor, args, -1);
} }
/* Check edited files for a parse error and re-edit any that fail. */ /* Check edited files for a parse error and re-edit any that fail. */
reparse_sudoers(editor, strict, quiet); reparse_sudoers(editor, args, strict, quiet);
/* Install the sudoers temp files. */ /* Install the sudoers temp files. */
for (sp = sudoerslist.first; sp != NULL; sp = sp->next) { for (sp = sudoerslist.first; sp != NULL; sp = sp->next) {
@@ -239,20 +239,22 @@ main(argc, argv)
* Returns TRUE on success, else FALSE. * Returns TRUE on success, else FALSE.
*/ */
static int static int
edit_sudoers(sp, editor, lineno) edit_sudoers(sp, editor, args, lineno)
struct sudoersfile *sp; struct sudoersfile *sp;
char *editor; char *editor, *args;
int lineno; int lineno;
{ {
int tfd; /* sudoers temp file descriptor */ int tfd; /* sudoers temp file descriptor */
int n; /* length parameter */
int modified; /* was the file modified? */ int modified; /* was the file modified? */
int ac; /* argument count */
char **av; /* argument vector for run_command */
char *cp; /* scratch char pointer */
char buf[PATH_MAX*2]; /* buffer used for copying files */ char buf[PATH_MAX*2]; /* buffer used for copying files */
char linestr[64]; /* string version of lineno */ char linestr[64]; /* string version of lineno */
char *av[4]; /* argument vector for run_command */
struct timespec ts1, ts2; /* time before and after edit */ struct timespec ts1, ts2; /* time before and after edit */
struct timespec orig_mtim; /* starting mtime of sudoers file */ struct timespec orig_mtim; /* starting mtime of sudoers file */
off_t orig_size; /* starting size of sudoers file */ off_t orig_size; /* starting size of sudoers file */
ssize_t nread; /* number of bytes read */
struct stat sb; /* stat buffer */ struct stat sb; /* stat buffer */
#ifdef HAVE_FSTAT #ifdef HAVE_FSTAT
@@ -275,12 +277,12 @@ edit_sudoers(sp, editor, lineno)
/* Copy sp->path -> sp->tpath and reset the mtime. */ /* Copy sp->path -> sp->tpath and reset the mtime. */
if (orig_size != 0) { if (orig_size != 0) {
(void) lseek(sp->fd, (off_t)0, SEEK_SET); (void) lseek(sp->fd, (off_t)0, SEEK_SET);
while ((n = read(sp->fd, buf, sizeof(buf))) > 0) while ((nread = read(sp->fd, buf, sizeof(buf))) > 0)
if (write(tfd, buf, n) != n) if (write(tfd, buf, nread) != nread)
error(1, "write error"); error(1, "write error");
/* Add missing newline at EOF if needed. */ /* Add missing newline at EOF if needed. */
if (n > 0 && buf[n - 1] != '\n') { if (nread > 0 && buf[nread - 1] != '\n') {
buf[0] = '\n'; buf[0] = '\n';
write(tfd, buf, 1); write(tfd, buf, 1);
} }
@@ -289,18 +291,39 @@ edit_sudoers(sp, editor, lineno)
} }
(void) touch(-1, sp->tpath, &orig_mtim); (void) touch(-1, sp->tpath, &orig_mtim);
/* Find the length of the argument vector */
ac = 3 + (lineno > 0);
if (args) {
int wasspace;
ac++;
for (wasspace = FALSE, cp = args; *cp; cp++) {
if (isspace((unsigned char) *cp))
wasspace = TRUE;
else if (wasspace) {
wasspace = FALSE;
ac++;
}
}
}
/* Build up argument vector for the command */ /* Build up argument vector for the command */
av = emalloc2(ac, sizeof(char *));
if ((av[0] = strrchr(editor, '/')) != NULL) if ((av[0] = strrchr(editor, '/')) != NULL)
av[0]++; av[0]++;
else else
av[0] = editor; av[0] = editor;
n = 1; ac = 1;
if (lineno > 0) { if (lineno > 0) {
(void) snprintf(linestr, sizeof(linestr), "+%d", lineno); (void) snprintf(linestr, sizeof(linestr), "+%d", lineno);
av[n++] = linestr; av[ac++] = linestr;
} }
av[n++] = sp->tpath; if (args) {
av[n++] = NULL; for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t")))
av[ac++] = cp;
}
av[ac++] = sp->tpath;
av[ac++] = NULL;
/* /*
* Do the edit: * Do the edit:
@@ -360,8 +383,8 @@ edit_sudoers(sp, editor, lineno)
* Returns TRUE on success, else FALSE. * Returns TRUE on success, else FALSE.
*/ */
static int static int
reparse_sudoers(editor, strict, quiet) reparse_sudoers(editor, args, strict, quiet)
char *editor; char *editor, *args;
int strict, quiet; int strict, quiet;
{ {
struct sudoersfile *sp, *last; struct sudoersfile *sp, *last;
@@ -411,7 +434,7 @@ reparse_sudoers(editor, strict, quiet)
/* Edit file with the parse error */ /* Edit file with the parse error */
for (sp = sudoerslist.first; sp != NULL; sp = sp->next) { for (sp = sudoerslist.first; sp != NULL; sp = sp->next) {
if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) { if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) {
edit_sudoers(sp, editor, errorlineno); edit_sudoers(sp, editor, args, errorlineno);
break; break;
} }
} }
@@ -424,7 +447,7 @@ reparse_sudoers(editor, strict, quiet)
printf("press return to edit %s: ", sp->path); printf("press return to edit %s: ", sp->path);
while ((ch = getchar()) != EOF && ch != '\n') while ((ch = getchar()) != EOF && ch != '\n')
continue; continue;
edit_sudoers(sp, editor, errorlineno); edit_sudoers(sp, editor, args, errorlineno);
} }
} while (parse_error); } while (parse_error);
@@ -726,9 +749,10 @@ open_sudoers(path, keepopen)
} }
static char * static char *
get_editor() get_editor(args)
char **args;
{ {
char *Editor, *UserEditor, *EditorPath; char *Editor, *EditorArgs, *EditorPath, *UserEditor, *UserEditorArgs;
/* /*
* Check VISUAL and EDITOR environment variables to see which editor * Check VISUAL and EDITOR environment variables to see which editor
@@ -736,11 +760,13 @@ get_editor()
* If the path is not fully-qualified, make it so and check that * If the path is not fully-qualified, make it so and check that
* the specified executable actually exists. * the specified executable actually exists.
*/ */
UserEditorArgs = NULL;
if ((UserEditor = getenv("VISUAL")) == NULL || *UserEditor == '\0') if ((UserEditor = getenv("VISUAL")) == NULL || *UserEditor == '\0')
UserEditor = getenv("EDITOR"); UserEditor = getenv("EDITOR");
if (UserEditor && *UserEditor == '\0') if (UserEditor && *UserEditor == '\0')
UserEditor = NULL; UserEditor = NULL;
else if (UserEditor) { else if (UserEditor) {
UserEditorArgs = get_args(UserEditor);
if (find_path(UserEditor, &Editor, NULL, getenv("PATH")) == FOUND) { if (find_path(UserEditor, &Editor, NULL, getenv("PATH")) == FOUND) {
UserEditor = Editor; UserEditor = Editor;
} else { } else {
@@ -758,10 +784,11 @@ get_editor()
* See if we can use the user's choice of editors either because * See if we can use the user's choice of editors either because
* we allow any $EDITOR or because $EDITOR is in the allowable list. * we allow any $EDITOR or because $EDITOR is in the allowable list.
*/ */
Editor = EditorPath = NULL; Editor = EditorArgs = EditorPath = NULL;
if (def_env_editor && UserEditor) if (def_env_editor && UserEditor) {
Editor = UserEditor; Editor = UserEditor;
else if (UserEditor) { EditorArgs = UserEditorArgs;
} else if (UserEditor) {
struct stat editor_sb; struct stat editor_sb;
struct stat user_editor_sb; struct stat user_editor_sb;
char *base, *userbase; char *base, *userbase;
@@ -773,6 +800,7 @@ get_editor()
EditorPath = estrdup(def_editor); EditorPath = estrdup(def_editor);
Editor = strtok(EditorPath, ":"); Editor = strtok(EditorPath, ":");
do { do {
EditorArgs = get_args(Editor);
/* /*
* Both Editor and UserEditor should be fully qualified but * Both Editor and UserEditor should be fully qualified but
* check anyway... * check anyway...
@@ -809,6 +837,7 @@ get_editor()
EditorPath = estrdup(def_editor); EditorPath = estrdup(def_editor);
Editor = strtok(EditorPath, ":"); Editor = strtok(EditorPath, ":");
do { do {
EditorArgs = get_args(Editor);
if (sudo_goodpath(Editor, NULL)) if (sudo_goodpath(Editor, NULL))
break; break;
} while ((Editor = strtok(NULL, ":"))); } while ((Editor = strtok(NULL, ":")));
@@ -817,9 +846,30 @@ get_editor()
if (Editor == NULL || *Editor == '\0') if (Editor == NULL || *Editor == '\0')
errorx(1, "no editor found (editor path = %s)", def_editor); errorx(1, "no editor found (editor path = %s)", def_editor);
} }
*args = EditorArgs;
return(Editor); return(Editor);
} }
/*
* Split out any command line arguments and return them.
*/
static char *
get_args(cmnd)
char *cmnd;
{
char *args;
args = cmnd;
while (*args && !isspace((unsigned char) *args))
args++;
if (*args) {
*args++ = '\0';
while (*args && isspace((unsigned char) *args))
args++;
}
return(*args ? args : NULL);
}
/* /*
* Iterate through the sudoers datastructures looking for undefined * Iterate through the sudoers datastructures looking for undefined
* aliases or unused aliases. * aliases or unused aliases.