Pass back the number of files to edit when using sudoedit.

The sudo front-end can use this to determine where the list of files
to edit begins.
This commit is contained in:
Todd C. Miller
2023-01-18 13:38:15 -07:00
parent 334daf92b3
commit 0865e61d9e
9 changed files with 139 additions and 38 deletions

View File

@@ -2,7 +2,7 @@
.\" .\"
.\" SPDX-License-Identifier: ISC .\" SPDX-License-Identifier: ISC
.\" .\"
.\" Copyright (c) 2009-2022 Todd C. Miller <Todd.Miller@sudo.ws> .\" Copyright (c) 2009-2023 Todd C. Miller <Todd.Miller@sudo.ws>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above .\" purpose with or without fee is hereby granted, provided that the above
@@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.TH "SUDO_PLUGIN" "5" "October 7, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .TH "SUDO_PLUGIN" "5" "January 18, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@@ -909,15 +909,20 @@ temporary copies of the files to be edited and then overwriting the
originals with the temporary copies after editing is complete. originals with the temporary copies after editing is complete.
If the plugin supports If the plugin supports
\fIsudoedit\fR, \fIsudoedit\fR,
it should choose the editor to be used, potentially from a variable it must set
in the user's environment, such as \fIsudoedit=true\fR
in the
\fIcommand_info\fR
list.
The plugin is responsible for choosing the editor to be used,
potentially from a variable in the user's environment, such as
\fREDITOR\fR, \fREDITOR\fR,
and include it in and should be stored in
\fIargv_out\fR \fIargv_out\fR
(environment variables may include command line options). (environment variables may include command line options).
The files to be edited should be copied from The files to be edited should be copied from
\fIargv\fR \fIargv\fR
into to
\fIargv_out\fR, \fIargv_out\fR,
separated from the separated from the
editor and its arguments by a editor and its arguments by a
@@ -928,11 +933,13 @@ The
will be removed by will be removed by
\fBsudo\fR \fBsudo\fR
before the editor is executed. before the editor is executed.
The plugin should also set The plugin may also set
\fIsudoedit=true\fR \fIsudoedit_nfiles\fR
in the to the number of files to be edited in the
\fIcommand_info\fR \fIcommand_info\fR
list. list; this will only be used by the
\fBsudo\fR
front-end starting with API version 1.21.
.sp .sp
The The
\fBcheck_policy\fR() \fBcheck_policy\fR()
@@ -1536,6 +1543,25 @@ option can be used to restore the older behavior and allow
to open symbolic links. to open symbolic links.
Only available starting with API version 1.8. Only available starting with API version 1.8.
.TP 6n .TP 6n
sudoedit_nfiles=number
The number of files to be edited by the user.
If present, this is will be used by the
\fBsudo\fR
front-end to determine which elements of the
\fIargv_out\fR
vector are files to be edited.
The
\(oq--\(cq
element must immediately precede the first file to be editied.
If
\fIsudoedit_nfiles\fR
is not specified, the
\fBsudo\fR
front-end will use the position of the
\(oq--\(cq
element to determine where the file list begins.
Only available starting with API version 1.21.
.TP 6n
timeout=int timeout=int
Command timeout. Command timeout.
If non-zero then when the timeout expires the command will be killed. If non-zero then when the timeout expires the command will be killed.
@@ -5441,6 +5467,13 @@ The
entry was added to the entry was added to the
\fIcommand_info\fR \fIcommand_info\fR
list. list.
.TP 6n
Version 1.21 (sudo 1.9.13)
The
\fIsudoedit_nfiles\fR
entry was added to the
\fIcommand_info\fR
list.
.SH "SEE ALSO" .SH "SEE ALSO"
sudo.conf(@mansectform@), sudo.conf(@mansectform@),
sudoers(@mansectform@), sudoers(@mansectform@),

View File

@@ -1,7 +1,7 @@
.\" .\"
.\" SPDX-License-Identifier: ISC .\" SPDX-License-Identifier: ISC
.\" .\"
.\" Copyright (c) 2009-2022 Todd C. Miller <Todd.Miller@sudo.ws> .\" Copyright (c) 2009-2023 Todd C. Miller <Todd.Miller@sudo.ws>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above .\" purpose with or without fee is hereby granted, provided that the above
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd October 7, 2022 .Dd January 18, 2023
.Dt SUDO_PLUGIN @mansectform@ .Dt SUDO_PLUGIN @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@@ -807,15 +807,20 @@ temporary copies of the files to be edited and then overwriting the
originals with the temporary copies after editing is complete. originals with the temporary copies after editing is complete.
If the plugin supports If the plugin supports
.Em sudoedit , .Em sudoedit ,
it should choose the editor to be used, potentially from a variable it must set
in the user's environment, such as .Em sudoedit=true
in the
.Fa command_info
list.
The plugin is responsible for choosing the editor to be used,
potentially from a variable in the user's environment, such as
.Ev EDITOR , .Ev EDITOR ,
and include it in and should be stored in
.Fa argv_out .Fa argv_out
(environment variables may include command line options). (environment variables may include command line options).
The files to be edited should be copied from The files to be edited should be copied from
.Fa argv .Fa argv
into to
.Fa argv_out , .Fa argv_out ,
separated from the separated from the
editor and its arguments by a editor and its arguments by a
@@ -826,11 +831,13 @@ The
will be removed by will be removed by
.Nm sudo .Nm sudo
before the editor is executed. before the editor is executed.
The plugin should also set The plugin may also set
.Em sudoedit=true .Em sudoedit_nfiles
in the to the number of files to be edited in the
.Fa command_info .Fa command_info
list. list; this will only be used by the
.Nm sudo
front-end starting with API version 1.21.
.Pp .Pp
The The
.Fn check_policy .Fn check_policy
@@ -1377,6 +1384,24 @@ option can be used to restore the older behavior and allow
.Nm sudoedit .Nm sudoedit
to open symbolic links. to open symbolic links.
Only available starting with API version 1.8. Only available starting with API version 1.8.
.It sudoedit_nfiles=number
The number of files to be edited by the user.
If present, this is will be used by the
.Nm sudo
front-end to determine which elements of the
.Fa argv_out
vector are files to be edited.
The
.Ql --
element must immediately precede the first file to be editied.
If
.Em sudoedit_nfiles
is not specified, the
.Nm sudo
front-end will use the position of the
.Ql --
element to determine where the file list begins.
Only available starting with API version 1.21.
.It timeout=int .It timeout=int
Command timeout. Command timeout.
If non-zero then when the timeout expires the command will be killed. If non-zero then when the timeout expires the command will be killed.
@@ -4826,6 +4851,12 @@ The
entry was added to the entry was added to the
.Fa command_info .Fa command_info
list. list.
.It Version 1.21 (sudo 1.9.13)
The
.Em sudoedit_nfiles
entry was added to the
.Fa command_info
list.
.El .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr sudo.conf @mansectform@ , .Xr sudo.conf @mansectform@ ,

View File

@@ -1,7 +1,7 @@
/* /*
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* Copyright (c) 2009-2022 Todd C. Miller <Todd.Miller@sudo.ws> * Copyright (c) 2009-2023 Todd C. Miller <Todd.Miller@sudo.ws>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -21,7 +21,7 @@
/* API version major/minor */ /* API version major/minor */
#define SUDO_API_VERSION_MAJOR 1 #define SUDO_API_VERSION_MAJOR 1
#define SUDO_API_VERSION_MINOR 20 #define SUDO_API_VERSION_MINOR 21
#define SUDO_API_MKVERSION(x, y) (((x) << 16) | (y)) #define SUDO_API_MKVERSION(x, y) (((x) << 16) | (y))
#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR) #define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR)

View File

@@ -58,6 +58,7 @@ struct sudo_plugin_event * (*plugin_event_alloc)(void);
const char *path_ldap_conf = _PATH_LDAP_CONF; const char *path_ldap_conf = _PATH_LDAP_CONF;
const char *path_ldap_secret = _PATH_LDAP_SECRET; const char *path_ldap_secret = _PATH_LDAP_SECRET;
static bool session_opened; static bool session_opened;
int sudoedit_nfiles;
extern sudo_dso_public struct policy_plugin sudoers_policy; extern sudo_dso_public struct policy_plugin sudoers_policy;
@@ -189,6 +190,7 @@ sudoers_policy_deserialize_info(void *v, struct defaults_list *defaults)
/* Parse command line settings. */ /* Parse command line settings. */
sudo_user.flags = 0; sudo_user.flags = 0;
user_closefrom = -1; user_closefrom = -1;
sudoedit_nfiles = 0;
sudo_mode = 0; sudo_mode = 0;
for (cur = info->settings; *cur != NULL; cur++) { for (cur = info->settings; *cur != NULL; cur++) {
if (MATCHES(*cur, "closefrom=")) { if (MATCHES(*cur, "closefrom=")) {
@@ -653,7 +655,7 @@ sudoers_policy_store_result(bool accepted, char *argv[], char *envp[],
} }
/* Increase the length of command_info as needed, it is *not* checked. */ /* Increase the length of command_info as needed, it is *not* checked. */
command_info = calloc(72, sizeof(char *)); command_info = calloc(73, sizeof(char *));
if (command_info == NULL) if (command_info == NULL)
goto oom; goto oom;
@@ -715,6 +717,11 @@ sudoers_policy_store_result(bool accepted, char *argv[], char *envp[],
if (ISSET(sudo_mode, MODE_EDIT)) { if (ISSET(sudo_mode, MODE_EDIT)) {
if ((command_info[info_len++] = strdup("sudoedit=true")) == NULL) if ((command_info[info_len++] = strdup("sudoedit=true")) == NULL)
goto oom; goto oom;
if (sudoedit_nfiles > 0) {
if (asprintf(&command_info[info_len++], "sudoedit_nfiles=%d",
sudoedit_nfiles) == -1)
goto oom;
}
if (!def_sudoedit_checkdir) { if (!def_sudoedit_checkdir) {
if ((command_info[info_len++] = strdup("sudoedit_checkdir=false")) == NULL) if ((command_info[info_len++] = strdup("sudoedit_checkdir=false")) == NULL)
goto oom; goto oom;

View File

@@ -806,8 +806,9 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
char **edit_argv; char **edit_argv;
int edit_argc; int edit_argc;
sudoedit_nfiles = NewArgc - 1;
free(safe_cmnd); free(safe_cmnd);
safe_cmnd = find_editor(NewArgc - 1, NewArgv + 1, &edit_argc, safe_cmnd = find_editor(sudoedit_nfiles, NewArgv + 1, &edit_argc,
&edit_argv, NULL, &env_editor); &edit_argv, NULL, &env_editor);
if (safe_cmnd == NULL) { if (safe_cmnd == NULL) {
switch (errno) { switch (errno) {

View File

@@ -433,6 +433,7 @@ extern struct sudo_user sudo_user;
extern struct passwd *list_pw; extern struct passwd *list_pw;
extern bool force_umask; extern bool force_umask;
extern int sudo_mode; extern int sudo_mode;
extern int sudoedit_nfiles;
extern uid_t timestamp_uid; extern uid_t timestamp_uid;
extern gid_t timestamp_gid; extern gid_t timestamp_gid;
extern sudo_conv_t sudo_conv; extern sudo_conv_t sudo_conv;

View File

@@ -287,7 +287,8 @@ main(int argc, char *argv[], char *envp[])
/* Setup command details and run command/edit. */ /* Setup command details and run command/edit. */
command_info_to_details(command_info, &command_details); command_info_to_details(command_info, &command_details);
command_details.tty = user_details.tty; command_details.tty = user_details.tty;
command_details.argv = argv_out; command_details.argv = nargv;
command_details.argc = nargc;
command_details.envp = run_envp; command_details.envp = run_envp;
command_details.evbase = sudo_event_base; command_details.evbase = sudo_event_base;
if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
@@ -833,6 +834,14 @@ command_info_to_details(char * const info[], struct command_details *details)
SET_FLAG("sudoedit=", CD_SUDOEDIT) SET_FLAG("sudoedit=", CD_SUDOEDIT)
SET_FLAG("sudoedit_checkdir=", CD_SUDOEDIT_CHECKDIR) SET_FLAG("sudoedit_checkdir=", CD_SUDOEDIT_CHECKDIR)
SET_FLAG("sudoedit_follow=", CD_SUDOEDIT_FOLLOW) SET_FLAG("sudoedit_follow=", CD_SUDOEDIT_FOLLOW)
if (strncmp("sudoedit_nfiles=", info[i], sizeof("sudoedit_nfiles=") - 1) == 0) {
cp = info[i] + sizeof("sudoedit_nfiles=") - 1;
details->nfiles = sudo_strtonum(cp, 1, INT_MAX,
&errstr);
if (errstr != NULL)
sudo_fatalx(U_("%s: %s"), info[i], U_(errstr));
break;
}
break; break;
case 't': case 't':
if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) { if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {

View File

@@ -189,11 +189,13 @@ TAILQ_HEAD(preserved_fd_list, preserved_fd);
struct command_details { struct command_details {
struct sudo_cred cred; struct sudo_cred cred;
mode_t umask; mode_t umask;
int argc;
int priority; int priority;
int timeout; int timeout;
int closefrom; int closefrom;
int flags; int flags;
int execfd; int execfd;
int nfiles;
struct preserved_fd_list preserved_fds; struct preserved_fd_list preserved_fds;
struct passwd *pw; struct passwd *pw;
const char *command; const char *command;

View File

@@ -628,9 +628,10 @@ int
sudo_edit(struct command_details *command_details) sudo_edit(struct command_details *command_details)
{ {
struct command_details saved_command_details; struct command_details saved_command_details;
char **nargv = NULL, **ap, **files = NULL; char **nargv = NULL, **files = NULL;
int nfiles = command_details->nfiles;
int errors, i, ac, nargc, ret; int errors, i, ac, nargc, ret;
int editor_argc = 0, nfiles = 0; int editor_argc = 0;
struct timespec times[2]; struct timespec times[2];
struct tempfile *tf = NULL; struct tempfile *tf = NULL;
debug_decl(sudo_edit, SUDO_DEBUG_EDIT); debug_decl(sudo_edit, SUDO_DEBUG_EDIT);
@@ -650,17 +651,31 @@ sudo_edit(struct command_details *command_details)
if (!set_tmpdir(&user_details.cred)) if (!set_tmpdir(&user_details.cred))
goto cleanup; goto cleanup;
/* if (nfiles > 0) {
* The user's editor must be separated from the files to be /*
* edited by a "--" option. * The plugin specified the number of files to edit, use it.
*/ */
for (ap = command_details->argv; *ap != NULL; ap++) { editor_argc = command_details->argc - nfiles;
if (files) if (editor_argc < 2 || strcmp(command_details->argv[editor_argc - 1], "--") != 0) {
nfiles++; sudo_warnx("%s", U_("plugin error: invalid file list for sudoedit"));
else if (strcmp(*ap, "--") == 0) goto cleanup;
files = ap + 1; }
else
editor_argc++; /* We don't include the "--" when running the user's editor. */
files = &command_details->argv[editor_argc--];
} else {
/*
* Compute the number of files to edit by looking for the "--"
* option which separate the editor from the files.
*/
for (i = 0; command_details->argv[i] != NULL; i++) {
if (strcmp(command_details->argv[i], "--") == 0) {
editor_argc = i;
files = &command_details->argv[i + 1];
nfiles = command_details->argc - (i + 1);
break;
}
}
} }
if (nfiles == 0) { if (nfiles == 0) {
sudo_warnx("%s", U_("plugin error: missing file list for sudoedit")); sudo_warnx("%s", U_("plugin error: missing file list for sudoedit"));
@@ -717,6 +732,7 @@ sudo_edit(struct command_details *command_details)
command_details->cred = user_details.cred; command_details->cred = user_details.cred;
command_details->cred.euid = user_details.cred.uid; command_details->cred.euid = user_details.cred.uid;
command_details->cred.egid = user_details.cred.gid; command_details->cred.egid = user_details.cred.gid;
command_details->argc = nargc;
command_details->argv = nargv; command_details->argv = nargv;
ret = run_command(command_details); ret = run_command(command_details);
if (sudo_gettime_real(&times[1]) == -1) { if (sudo_gettime_real(&times[1]) == -1) {
@@ -726,6 +742,7 @@ sudo_edit(struct command_details *command_details)
/* Restore saved command_details. */ /* Restore saved command_details. */
command_details->cred = saved_command_details.cred; command_details->cred = saved_command_details.cred;
command_details->argc = saved_command_details.argc;
command_details->argv = saved_command_details.argv; command_details->argv = saved_command_details.argv;
/* Copy contents of temp files to real ones. */ /* Copy contents of temp files to real ones. */