Remove check_sudoedit function pointer in struct sudo_policy.

Instead, sudo will set sudoedit=true in the settings array.
The plugin should check for this and modify argv_out as appropriate
in check_policy.
This commit is contained in:
Todd C. Miller
2010-05-17 10:25:27 -04:00
parent 3ac9aee52e
commit fa717176b2
8 changed files with 121 additions and 164 deletions

View File

@@ -139,7 +139,7 @@
.\" ========================================================================
.\"
.IX Title "SUDO_PLUGIN @mansectsu@"
.TH SUDO_PLUGIN @mansectsu@ "May 14, 2010" "1.8.0a1" "MAINTENANCE COMMANDS"
.TH SUDO_PLUGIN @mansectsu@ "May 17, 2010" "1.8.0a1" "MAINTENANCE COMMANDS"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@@ -219,9 +219,6 @@ so that \fBsudo\fR can load it.
\& const char *list_user);
\& int (*validate)(void);
\& void (*invalidate)(int remove);
\& int (*check_sudoedit)(int argc, char * const argv[],
\& char *env_add[], char **command_info[],
\& char **argv_out[], char **user_env_out[]);
\& };
.Ve
.PP
@@ -348,6 +345,13 @@ systems where \s-1BSD\s0 authentication is supported.
.IP "progname=string" 4
.IX Item "progname=string"
The command name that sudo was run as, typically \*(L"sudo\*(R" or \*(L"sudoedit\*(R".
.IP "sudoedit=bool" 4
.IX Item "sudoedit=bool"
Set to true when the \f(CW\*(C`\-e\*(C'\fR flag is is specified or if invoked as
\&\fBsudoedit\fR. The plugin shall substitute an editor into \fIargv\fR
in the \fIcheck_policy\fR function or return \f(CW\*(C`\-2\*(C'\fR with a usage error
if the plugin does not support \fIsudoedit\fR. For more information,
see the \fIcheck_policy\fR section.
.RE
.RS 4
.Sp
@@ -455,13 +459,31 @@ information, the verbose flag will be set.
.Ve
.Sp
The \fIcheck_policy\fR function is called by \fBsudo\fR to determine
whether the user is allowed to run the specified commands. Returns
1 if the command is allowed, 0 if not allowed, \-1 for a general
error, or \-2 for a usage error. In the latter case, \fBsudo\fR will
print a usage message before it exits. If an error occurs, the
plugin may optionally call the conversation or plugin_printf function
with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional error information
to the user.
whether the user is allowed to run the specified commands.
.Sp
If the \fIsudoedit\fR option was enabled in the \fIsettings\fR array
passed to the \fIopen\fR function, the user has requested \fIsudoedit\fR
mode. \fIsudoedit\fR is a mechanism for editing one or more files
where an editor is run with the user's credentials instead of with
elevated privileges. \fBsudo\fR achieves this by creating user-writable
temporary copies of the files to be edited and then overwriting the
originals with the temporary copies after editing is complete. If
the plugin supports \fBsudoedit\fR, it should choose the editor to be
used, potentially from a variable in the user's environment, such
as \f(CW\*(C`EDITOR\*(C'\fR, and include it in \fIargv_out\fR (note that environment
variables may include command line flags). The files to be edited
should be copied from \fIargv\fR into \fIargv_out\fR, separated from the
editor and its arguments by a \f(CW"\-\-"\fR element. The \f(CW"\-\-"\fR will
be removed by \fBsudo\fR before the editor is executed. The plugin
should also set \fIsudoedit=true\fR in the \fIcommand_info\fR list.
.Sp
The \fIcheck_policy\fR function returns 1 if the command is allowed,
0 if not allowed, \-1 for a general error, or \-2 for a usage error
or if \fBsudoedit\fR was specified but is unsupported by the plugin.
In the latter case, \fBsudo\fR will print a usage message before it
exits. If an error occurs, the plugin may optionally call the
conversation or plugin_printf function with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR
to present additional error information to the user.
.Sp
The function arguments are as follows:
.RS 4
@@ -550,6 +572,12 @@ SELinux type to use when executing the command.
.IX Item "timeout=int"
Command timeout. If non-zero then when the timeout expires the
command will be killed.
.IP "sudoedit=bool" 4
.IX Item "sudoedit=bool"
Set to true when in \fIsudoedit\fR mode. The plugin may enable
\&\fIsudoedit\fR mode even if \fBsudo\fR was not invoked as \fBsudoedit\fR.
This allows the plugin to perform command substitution and transparently
enable \fIsudoedit\fR when the user attempts to run an editor.
.RE
.RS 4
.Sp
@@ -638,38 +666,6 @@ the credentials instead of simply invalidating them.
.Sp
The \f(CW\*(C`invalidate\*(C'\fR function should be \f(CW\*(C`NULL\*(C'\fR if the plugin does not
support credential caching.
.IP "check_sudoedit" 4
.IX Item "check_sudoedit"
.Vb 3
\& int (*check_sudoedit)(int argc, char * const argv[]
\& char *env_add[], char **command_info[],
\& char **argv_out[], char **user_env_out[]);
.Ve
.Sp
The \fIcheck_sudoedit\fR function is called instead of \fIcheck_policy\fR
when \fBsudo\fR is invoked as \fBsudoedit\fR or when the \f(CW\*(C`\-e\*(C'\fR flag is
specified. \fBsudoedit\fR is a mechanism for editing one or more files
where an editor is run with the user's credentials instead of with
elevated privileges. \fBsudo\fR achieves this by creating user-writable
temporary copies of the files to be edited and then overwriting the
originals with the temporary copies after editing is complete.
.Sp
The plugin should choose the editor to be used, potentially from a
variable in the user's environment, such as \f(CW\*(C`EDITOR\*(C'\fR, and include
it in \fIargv_out\fR. The files to be edited should be copied from
\&\fIargv\fR into \fIargv_out\fR, separated from the editor and its arguments
by a \f(CW"\-\-"\fR element. The \f(CW"\-\-"\fR will be removed by \fBsudo\fR before
the editor is executed.
.Sp
Returns 1 if the command is allowed, 0 if not allowed, \-1 for a
general error, or \-2 for a usage error. In the latter case, \fBsudo\fR
will print a usage message before it exits. If an error occurs,
the plugin may optionally call the conversation or plugin_printf
function with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional error
information to the user.
.Sp
The function arguments are the same as for \fIcheck_policy\fR, except
that \fIargv[0]\fR will always be the string \*(L"sudoedit\*(R".
.PP
\fIConversation \s-1API\s0\fR
.IX Subsection "Conversation API"
@@ -1035,3 +1031,9 @@ the plugin type.
\& struct io_plugin io;
\& };
.Ve
.SH "POD ERRORS"
.IX Header "POD ERRORS"
Hey! \fBThe above document had some coding errors, which are explained below:\fR
.IP "Around line 597:" 4
.IX Item "Around line 597:"
You forgot a '=back' before '=head3'

View File

@@ -89,9 +89,6 @@ so that B<sudo> can load it.
const char *list_user);
int (*validate)(void);
void (*invalidate)(int remove);
int (*check_sudoedit)(int argc, char * const argv[],
char *env_add[], char **command_info[],
char **argv_out[], char **user_env_out[]);
};
The policy_plugin struct has the following fields:
@@ -243,6 +240,14 @@ systems where BSD authentication is supported.
The command name that sudo was run as, typically "sudo" or "sudoedit".
=item sudoedit=bool
Set to true when the C<-e> flag is is specified or if invoked as
B<sudoedit>. The plugin shall substitute an editor into I<argv>
in the I<check_policy> function or return C<-2> with a usage error
if the plugin does not support I<sudoedit>. For more information,
see the I<check_policy> section.
=back
Additional settings may be added in the future so the plugin should
@@ -357,13 +362,31 @@ information, the verbose flag will be set.
char **argv_out[], char **user_env_out[]);
The I<check_policy> function is called by B<sudo> to determine
whether the user is allowed to run the specified commands. Returns
1 if the command is allowed, 0 if not allowed, -1 for a general
error, or -2 for a usage error. In the latter case, B<sudo> will
print a usage message before it exits. If an error occurs, the
plugin may optionally call the conversation or plugin_printf function
with C<SUDO_CONF_ERROR_MSG> to present additional error information
to the user.
whether the user is allowed to run the specified commands.
If the I<sudoedit> option was enabled in the I<settings> array
passed to the I<open> function, the user has requested I<sudoedit>
mode. I<sudoedit> is a mechanism for editing one or more files
where an editor is run with the user's credentials instead of with
elevated privileges. B<sudo> achieves this by creating user-writable
temporary copies of the files to be edited and then overwriting the
originals with the temporary copies after editing is complete. If
the plugin supports B<sudoedit>, it should choose the editor to be
used, potentially from a variable in the user's environment, such
as C<EDITOR>, and include it in I<argv_out> (note that environment
variables may include command line flags). The files to be edited
should be copied from I<argv> into I<argv_out>, separated from the
editor and its arguments by a C<"--"> element. The C<"--"> will
be removed by B<sudo> before the editor is executed. The plugin
should also set I<sudoedit=true> in the I<command_info> list.
The I<check_policy> function returns 1 if the command is allowed,
0 if not allowed, -1 for a general error, or -2 for a usage error
or if B<sudoedit> was specified but is unsupported by the plugin.
In the latter case, B<sudo> will print a usage message before it
exits. If an error occurs, the plugin may optionally call the
conversation or plugin_printf function with C<SUDO_CONF_ERROR_MSG>
to present additional error information to the user.
The function arguments are as follows:
@@ -475,6 +498,13 @@ SELinux type to use when executing the command.
Command timeout. If non-zero then when the timeout expires the
command will be killed.
=item sudoedit=bool
Set to true when in I<sudoedit> mode. The plugin may enable
I<sudoedit> mode even if B<sudo> was not invoked as B<sudoedit>.
This allows the plugin to perform command substitution and transparently
enable I<sudoedit> when the user attempts to run an editor.
=back
Unsupported values will be ignored.
@@ -564,39 +594,6 @@ the credentials instead of simply invalidating them.
The C<invalidate> function should be C<NULL> if the plugin does not
support credential caching.
=item check_sudoedit
int (*check_sudoedit)(int argc, char * const argv[]
char *env_add[], char **command_info[],
char **argv_out[], char **user_env_out[]);
The I<check_sudoedit> function is called instead of I<check_policy>
when B<sudo> is invoked as B<sudoedit> or when the C<-e> flag is
specified. B<sudoedit> is a mechanism for editing one or more files
where an editor is run with the user's credentials instead of with
elevated privileges. B<sudo> achieves this by creating user-writable
temporary copies of the files to be edited and then overwriting the
originals with the temporary copies after editing is complete.
The plugin should choose the editor to be used, potentially from a
variable in the user's environment, such as C<EDITOR>, and include
it in I<argv_out>. The files to be edited should be copied from
I<argv> into I<argv_out>, separated from the editor and its arguments
by a C<"--"> element. The C<"--"> will be removed by B<sudo> before
the editor is executed.
Returns 1 if the command is allowed, 0 if not allowed, -1 for a
general error, or -2 for a usage error. In the latter case, B<sudo>
will print a usage message before it exits. If an error occurs,
the plugin may optionally call the conversation or plugin_printf
function with C<SUDO_CONF_ERROR_MSG> to present additional error
information to the user.
The function arguments are the same as for I<check_policy>, except
that I<argv[0]> will always be the string "sudoedit".
=back
=head3 Conversation API
If the plugin needs to interact with the user, it may do so via the

View File

@@ -68,9 +68,6 @@ struct policy_plugin {
const char *list_user);
int (*validate)(void);
void (*invalidate)(int remove);
int (*check_sudoedit)(int argc, char * const argv[],
char *env_add[], char **command_info[],
char **argv_out[], char **user_env_out[]);
};
/* I/O plugin type and defines */

View File

@@ -84,6 +84,7 @@ static sudo_printf_t sudo_log;
static FILE *input, *output;
static uid_t runas_uid = ROOT_UID;
static gid_t runas_gid = -1;
static int use_sudoedit = FALSE;
/*
* Allocate storage for a name=value string and return it.
@@ -147,6 +148,11 @@ policy_open(unsigned int version, sudo_conv_t conversation,
setprogname(*ui + sizeof("progname=") - 1);
}
#endif
/* Check to see if sudo was called as sudoedit or with -e flag. */
if (strncmp(*ui, "sudoedit=", sizeof("sudoedit=") - 1) == 0) {
if (strcasecmp(*ui + sizeof("sudoedit=") - 1, "true") == 0)
use_sudoedit = TRUE;
}
}
if (runas_user != NULL) {
if ((pw = getpwnam(runas_user)) == NULL) {
@@ -230,7 +236,7 @@ check_passwd(void)
}
static char **
build_command_info(char *command, int sudoedit)
build_command_info(char *command)
{
static char **command_info;
int i = 0;
@@ -250,7 +256,7 @@ build_command_info(char *command, int sudoedit)
return NULL;
}
}
if (sudoedit) {
if (use_sudoedit) {
command_info[i] = strdup("sudoedit=true");
if (command_info[i++] == NULL)
return NULL;
@@ -344,18 +350,20 @@ policy_check(int argc, char * const argv[],
return FALSE;
}
/*
* If "sudo vi" is run, auto-convert to sudoedit.
*/
if (strcmp(command, _PATH_VI) == 0) {
/* If "sudo vi" is run, auto-convert to sudoedit. */
if (strcmp(command, _PATH_VI) == 0)
use_sudoedit = TRUE;
if (use_sudoedit) {
/* Rebuild argv using editor */
command = find_editor(argc - 1, argv + 1, argv_out);
if (command == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "unable to find valid editor\n");
return ERROR;
}
use_sudoedit = TRUE;
} else {
/* No changes to argv */
/* No changes needd to argv */
*argv_out = (char **)argv;
}
@@ -363,41 +371,7 @@ policy_check(int argc, char * const argv[],
*user_env_out = plugin_state.envp;
/* Setup command info. */
*command_info_out = build_command_info(command, *argv_out != argv);
if (*command_info_out == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "out of memory\n");
return ERROR;
}
return TRUE;
}
/*
* Plugin policy edit function.
* Simple example that prompts for a password, hard-coded to "test".
*/
static int
policy_edit(int argc, char * const argv[],
char *env_add[], char **command_info_out[],
char **argv_out[], char **user_env_out[])
{
char *editor;
if (!check_passwd())
return FALSE;
/* Rebuild argv using editor */
editor = find_editor(argc - 1, argv + 1, argv_out);
if (editor == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "unable to find valid editor\n");
return ERROR;
}
/* No changes to envp */
*user_env_out = plugin_state.envp;
/* Setup command info. */
*command_info_out = build_command_info(editor, TRUE);
*command_info_out = build_command_info(command);
if (*command_info_out == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "out of memory\n");
return ERROR;
@@ -512,8 +486,7 @@ struct policy_plugin sample_policy = {
policy_check,
policy_list,
NULL, /* validate */
NULL, /* invalidate */
policy_edit
NULL /* invalidate */
};
/*

View File

@@ -565,6 +565,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
if (!editor)
goto done;
command_info[info_len++] = fmt_string("command", editor);
command_info[info_len++] = estrdup("sudoedit=true");
} else {
command_info[info_len++] = fmt_string("command", safe_cmnd);
}
@@ -623,16 +624,6 @@ sudoers_policy_check(int argc, char * const argv[], char *env_add[],
argv_out, user_env_out);
}
static int
sudoers_policy_sudoedit(int argc, char * const argv[], char *env_add[],
char **command_infop[], char **argv_out[], char **user_env_out[])
{
SET(sudo_mode, MODE_EDIT);
return sudoers_policy_main(argc, argv, 0, env_add, command_infop,
argv_out, user_env_out);
}
static int
sudoers_policy_validate(void)
{
@@ -1226,6 +1217,11 @@ deserialize_info(char * const settings[], char * const user_info[])
SET(flags, MODE_IGNORE_TICKET);
continue;
}
if (MATCHES(*cur, "sudoedit=")) {
if (atobool(*cur + sizeof("sudoedit=") - 1) == TRUE)
SET(flags, MODE_EDIT);
continue;
}
if (MATCHES(*cur, "login_class=")) {
login_class = *cur + sizeof("login_class=") - 1;
def_use_loginclass = TRUE;
@@ -1409,8 +1405,7 @@ struct policy_plugin sudoers_policy = {
sudoers_policy_check,
sudoers_policy_list,
sudoers_policy_validate,
sudoers_policy_invalidate,
sudoers_policy_sudoedit
sudoers_policy_invalidate
};
struct io_plugin sudoers_io = {

View File

@@ -107,7 +107,9 @@ static struct sudo_settings {
{ "preserve_groups" },
#define ARG_NONINTERACTIVE 15
{ "noninteractive" },
#define NUM_SETTINGS 16
#define ARG_SUDOEDIT 16
{ "sudoedit" },
#define NUM_SETTINGS 17
{ NULL }
};
@@ -135,8 +137,10 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
sudo_settings[ARG_PROGNAME].value = getprogname();
/* First, check to see if we were invoked as "sudoedit". */
if (strcmp(getprogname(), "sudoedit") == 0)
if (strcmp(getprogname(), "sudoedit") == 0) {
mode = MODE_EDIT;
sudo_settings[ARG_SUDOEDIT].value = "true";
}
/* Returns true if the last option string was "--" */
#define got_end_of_args (optind > 1 && argv[optind - 1][0] == '-' && \
@@ -194,6 +198,7 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
if (mode && mode != MODE_EDIT)
usage_excl(1);
mode = MODE_EDIT;
sudo_settings[ARG_SUDOEDIT].value = "true";
valid_flags = MODE_NONINTERACTIVE;
break;
case 'g':

View File

@@ -199,21 +199,9 @@ main(int argc, char *argv[], char *envp[])
}
exit(ok != TRUE);
case MODE_EDIT:
if (!policy_plugin.u.policy->check_sudoedit)
errorx(1, "policy plugin %s does not support sudoedit",
policy_plugin.name);
/* FALLTHROUGH */
case MODE_RUN:
if (sudo_mode & MODE_EDIT) {
/* XXX - must be able to tell which are the files in argv */
/* as opposed to editor flags; could use original argv */
/* and only use argv_out for the command path + args */
ok = policy_plugin.u.policy->check_sudoedit(nargc, nargv,
env_add, &command_info, &argv_out, &user_env_out);
} else {
ok = policy_plugin.u.policy->check_policy(nargc, nargv, env_add,
&command_info, &argv_out, &user_env_out);
}
sudo_debug(8, "policy plugin returns %d", ok);
if (ok != TRUE) {
if (ok == -2)
@@ -240,8 +228,6 @@ main(int argc, char *argv[], char *envp[])
}
}
command_info_to_details(command_info, &command_details);
if (ISSET(sudo_mode, MODE_EDIT))
SET(command_details.flags, CD_SUDOEDIT);
/* Restore coredumpsize resource limit before running. */
#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
(void) setrlimit(RLIMIT_CORE, &corelimit);

View File

@@ -143,8 +143,10 @@ sudo_edit(struct command_details *command_details, char *argv[], char *envp[])
else
editor_argc++;
}
if (nfiles == 0)
if (nfiles == 0) {
warningx("plugin error: missing file list for sudoedit");
return 1;
}
/*
* For each file specified by the user, make a temporary version