From: Todd C. Miller Date: Thu, 18 Nov 2004 20:28:53 +0000 (+0000) Subject: Add support for VISUAL and EDITOR containing command line args. X-Git-Tag: SUDO_1_7_0~805 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=75ad6b81a2d05eae05f0dd3b69ed3f53e838bf70;p=sudo 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. --- diff --git a/visudo.c b/visudo.c index 1d849ec07..6535d88c2 100644 --- a/visudo.c +++ b/visudo.c @@ -97,21 +97,21 @@ struct sudoersfile { * Function prototypes */ 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 int check_aliases __P((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 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 void setup_signals __P((void)); static void usage __P((void)) __attribute__((__noreturn__)); - VOID *v2; -void yyerror __P((const char *)); -void yyrestart __P((FILE *)); +extern void yyerror __P((const char *)); +extern void yyrestart __P((FILE *)); /* * External globals exported by the parser @@ -144,7 +144,7 @@ main(argc, argv) char **argv; { struct sudoersfile *sp; - char *editor, *sudoers_path; + char *args, *editor, *sudoers_path; int ch, checkonly, quiet, strict; Argv = argv; @@ -205,7 +205,7 @@ main(argc, argv) yyparse(); (void) update_defaults(); - editor = get_editor(); + editor = get_editor(&args); /* Install signal handlers to clean up temp files if we are killed. */ setup_signals(); @@ -217,11 +217,11 @@ main(argc, argv) while ((ch = getchar()) != EOF && ch != '\n') 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. */ - reparse_sudoers(editor, strict, quiet); + reparse_sudoers(editor, args, strict, quiet); /* Install the sudoers temp files. */ for (sp = sudoerslist.first; sp != NULL; sp = sp->next) { @@ -239,20 +239,22 @@ main(argc, argv) * Returns TRUE on success, else FALSE. */ static int -edit_sudoers(sp, editor, lineno) +edit_sudoers(sp, editor, args, lineno) struct sudoersfile *sp; - char *editor; + char *editor, *args; int lineno; { int tfd; /* sudoers temp file descriptor */ - int n; /* length parameter */ 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 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 orig_mtim; /* starting mtime of sudoers file */ off_t orig_size; /* starting size of sudoers file */ + ssize_t nread; /* number of bytes read */ struct stat sb; /* stat buffer */ #ifdef HAVE_FSTAT @@ -275,12 +277,12 @@ edit_sudoers(sp, editor, lineno) /* Copy sp->path -> sp->tpath and reset the mtime. */ if (orig_size != 0) { (void) lseek(sp->fd, (off_t)0, SEEK_SET); - while ((n = read(sp->fd, buf, sizeof(buf))) > 0) - if (write(tfd, buf, n) != n) + while ((nread = read(sp->fd, buf, sizeof(buf))) > 0) + if (write(tfd, buf, nread) != nread) error(1, "write error"); /* Add missing newline at EOF if needed. */ - if (n > 0 && buf[n - 1] != '\n') { + if (nread > 0 && buf[nread - 1] != '\n') { buf[0] = '\n'; write(tfd, buf, 1); } @@ -289,18 +291,39 @@ edit_sudoers(sp, editor, lineno) } (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 */ + av = emalloc2(ac, sizeof(char *)); if ((av[0] = strrchr(editor, '/')) != NULL) av[0]++; else av[0] = editor; - n = 1; + ac = 1; if (lineno > 0) { (void) snprintf(linestr, sizeof(linestr), "+%d", lineno); - av[n++] = linestr; + av[ac++] = linestr; } - av[n++] = sp->tpath; - av[n++] = NULL; + if (args) { + for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t"))) + av[ac++] = cp; + } + av[ac++] = sp->tpath; + av[ac++] = NULL; /* * Do the edit: @@ -360,8 +383,8 @@ edit_sudoers(sp, editor, lineno) * Returns TRUE on success, else FALSE. */ static int -reparse_sudoers(editor, strict, quiet) - char *editor; +reparse_sudoers(editor, args, strict, quiet) + char *editor, *args; int strict, quiet; { struct sudoersfile *sp, *last; @@ -411,7 +434,7 @@ reparse_sudoers(editor, strict, quiet) /* Edit file with the parse error */ for (sp = sudoerslist.first; sp != NULL; sp = sp->next) { if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) { - edit_sudoers(sp, editor, errorlineno); + edit_sudoers(sp, editor, args, errorlineno); break; } } @@ -424,7 +447,7 @@ reparse_sudoers(editor, strict, quiet) printf("press return to edit %s: ", sp->path); while ((ch = getchar()) != EOF && ch != '\n') continue; - edit_sudoers(sp, editor, errorlineno); + edit_sudoers(sp, editor, args, errorlineno); } } while (parse_error); @@ -726,9 +749,10 @@ open_sudoers(path, keepopen) } 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 @@ -736,11 +760,13 @@ get_editor() * If the path is not fully-qualified, make it so and check that * the specified executable actually exists. */ + UserEditorArgs = NULL; if ((UserEditor = getenv("VISUAL")) == NULL || *UserEditor == '\0') UserEditor = getenv("EDITOR"); if (UserEditor && *UserEditor == '\0') UserEditor = NULL; else if (UserEditor) { + UserEditorArgs = get_args(UserEditor); if (find_path(UserEditor, &Editor, NULL, getenv("PATH")) == FOUND) { UserEditor = Editor; } else { @@ -758,10 +784,11 @@ get_editor() * 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. */ - Editor = EditorPath = NULL; - if (def_env_editor && UserEditor) + Editor = EditorArgs = EditorPath = NULL; + if (def_env_editor && UserEditor) { Editor = UserEditor; - else if (UserEditor) { + EditorArgs = UserEditorArgs; + } else if (UserEditor) { struct stat editor_sb; struct stat user_editor_sb; char *base, *userbase; @@ -773,6 +800,7 @@ get_editor() EditorPath = estrdup(def_editor); Editor = strtok(EditorPath, ":"); do { + EditorArgs = get_args(Editor); /* * Both Editor and UserEditor should be fully qualified but * check anyway... @@ -809,6 +837,7 @@ get_editor() EditorPath = estrdup(def_editor); Editor = strtok(EditorPath, ":"); do { + EditorArgs = get_args(Editor); if (sudo_goodpath(Editor, NULL)) break; } while ((Editor = strtok(NULL, ":"))); @@ -817,9 +846,30 @@ get_editor() if (Editor == NULL || *Editor == '\0') errorx(1, "no editor found (editor path = %s)", def_editor); } + *args = EditorArgs; 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 * aliases or unused aliases.