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:
110
visudo.c
110
visudo.c
@@ -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.
|
||||||
|
Reference in New Issue
Block a user