]> granicus.if.org Git - sudo/commitdiff
Remove check_sudoedit function pointer in struct sudo_policy.
authorTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 17 May 2010 14:25:27 +0000 (10:25 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 17 May 2010 14:25:27 +0000 (10:25 -0400)
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.

doc/sudo_plugin.man.in
doc/sudo_plugin.pod
include/sudo_plugin.h
plugins/sample/sample_plugin.c
plugins/sudoers/sudoers.c
src/parse_args.c
src/sudo.c
src/sudo_edit.c

index be3746340ffc59055a0ea6ab7596cadb309d0cda..4ae007749d4d0e5eefc12bd4125ecbe056d349b4 100644 (file)
 .\" ========================================================================
 .\"
 .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'
index fb8a1ac408ec8be6e4df3f984dec4734548e6b9f..0c03beeb00acf28a3fc99e977421f8e4fcaccb19 100644 (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
index 0ad4e619fc15f39d9a02a1674a39de44e9eee3ad..26289f901965379195d77be9601a8de1caf34cef 100644 (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 */
index e8fcaeb1e580c45b146aa02a7bdd60300c33dd49..07990a3d7d81ff171fcf41d7542eae5d50b85ee7 100644 (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 */
 };
 
 /*
index 1746a41ebe4392b4cf635f55f7534abbc0b4391e..6c4b27f48f92c209893370d76d78c5847c524ca8 100644 (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 = {
index 584f71b2d348b37f649732604e87ce85c748fa00..59e1595e2b70b88ae29e68abd6f07c0176891bbe 100644 (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':
index 7da8f798cda42abb1cb860955f16ab647f326e5a..33df03b7fd32f353c2ba82d6f5e92db2066bf898 100644 (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);
-           }
+           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);
index 3cf8fa406fd81d85d7f6f2744a967049b6fae788..031a298386c485c583aa673586b71fc0664308a9 100644 (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