diff --git a/doc/sudo_plugin.cat b/doc/sudo_plugin.cat
index a6dd702e4..2e0a0b595 100644
--- a/doc/sudo_plugin.cat
+++ b/doc/sudo_plugin.cat
@@ -61,7 +61,7 @@ SSuuddoo PPlluuggiinn AAPPII
 
 
 
-1.8.0a1                   March 19, 2010                        1
+1.8.0a1                   March 21, 2010                        1
 
 
 
@@ -127,7 +127,7 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
 
 
 
-1.8.0a1                   March 19, 2010                        2
+1.8.0a1                   March 21, 2010                        2
 
 
 
@@ -172,6 +172,15 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
                    Set to true if the user specified the -i flag, indicating
                    that the user wishes to run a login shell.
 
+               implied_shell=bool
+                   If the user does not specify a program on the command line,
+                   ssuuddoo will pass the plugin the path to the user's shell and
+                   set _i_m_p_l_i_e_d___s_h_e_l_l to true.  This allows ssuuddoo with no
+                   arguments to be used similarly to _s_u(1).  If the plugin
+                   does not to support this usage, it may return a value of -2
+                   from the check_policy function, which will cause ssuuddoo to
+                   print a usage message and exit.
+
                preserve_groups=bool
                    Set to true if the user specified the -P flag, indicating
                    that the user wishes to preserve the group vector instead
@@ -182,18 +191,9 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
                    command, indicating that the user wishes to ignore any
                    cached authentication credentials.
 
-               login_class=string
-                   BSD login class to use when setting resource limits and
-                   nice value, if specified by the -c flag.
-
-               selinux_role=string
-                   SELinux role to use when executing the command, if
-                   specified by the -r flag.
 
 
-
-
-1.8.0a1                   March 19, 2010                        3
+1.8.0a1                   March 21, 2010                        3
 
 
 
@@ -202,6 +202,14 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
 SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
 
 
+               login_class=string
+                   BSD login class to use when setting resource limits and
+                   nice value, if specified by the -c flag.
+
+               selinux_role=string
+                   SELinux role to use when executing the command, if
+                   specified by the -r flag.
+
                selinux_type=string
                    SELinux type to use when executing the command, if
                    specified by the -t flag.
@@ -247,6 +255,19 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
                    terminal device associated with the session, the value will
                    be empty, as in tty=.
 
+
+
+
+
+1.8.0a1                   March 21, 2010                        4
+
+
+
+
+
+SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
+
+
                host=string
                    The local machine's hostname as returned by the
                    gethostname() system call.
@@ -256,18 +277,6 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
                    is no terminal device available, a default value of 24 is
                    used.
 
-
-
-
-1.8.0a1                   March 19, 2010                        4
-
-
-
-
-
-SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
-
-
                cols=int
                    The number of columns the user's terminal supports.  If
                    there is no terminal device available, a default value of
@@ -311,6 +320,20 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
            will be set.
 
        check_policy
+
+
+
+
+
+1.8.0a1                   March 21, 2010                        5
+
+
+
+
+
+SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
+
+
             int (*check_policy)(int argc, char * const argv[]
                                 char *env_add[], char **command_info[],
                                 char **argv_out[], char **user_env_out[]);
@@ -322,18 +345,6 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
            SUDO_CONF_ERROR_MSG to present additional error information to the
            user.
 
-
-
-
-1.8.0a1                   March 19, 2010                        5
-
-
-
-
-
-SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
-
-
            The function arguments are as follows:
 
            argc
@@ -377,6 +388,18 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
                runas_gid=gid
                    Group ID to run the command as.
 
+
+
+
+1.8.0a1                   March 21, 2010                        6
+
+
+
+
+
+SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
+
+
                runas_egid=gid
                    Effective group ID to run the command as.  If not
                    specified, the value of _r_u_n_a_s___g_i_d is used.
@@ -388,18 +411,6 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
 
                login_class=login_class
                    BSD login class to use when setting resource limits and
-
-
-
-1.8.0a1                   March 19, 2010                        6
-
-
-
-
-
-SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
-
-
                    nice value (optional).  This option is only set on systems
                    that support login classes.
 
@@ -442,6 +453,19 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
                system call when executing the command.  The plugin is
                responsible for allocating and populating the vector.
 
+
+
+
+
+1.8.0a1                   March 21, 2010                        7
+
+
+
+
+
+SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
+
+
            user_env_out
                The NULL-terminated environment vector to use when executing
                the command.  The plugin is responsible for allocating and
@@ -454,18 +478,6 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
            List available privileges for the invoking user.  Returns 1 on
            success, 0 on failure and -1 on error.  On error, the plugin may
            optionally call the conversation function with SUDO_CONF_ERROR_MSG
-
-
-
-1.8.0a1                   March 19, 2010                        7
-
-
-
-
-
-SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
-
-
            to present additional error information to the user.
 
            Privileges should be output via the conversation function using
@@ -509,6 +521,17 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
        invalidate
             void (*invalidate)(int remove);
 
+
+
+1.8.0a1                   March 21, 2010                        8
+
+
+
+
+
+SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
+
+
            The invalidate function is called when ssuuddoo is called with the -k
            or -K flag.  For policy plugins such as _s_u_d_o_e_r_s that cache
            authentication credentials, this function will invalidate the
@@ -520,18 +543,6 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
 
        _C_o_n_v_e_r_s_a_t_i_o_n _A_P_I
 
-
-
-
-1.8.0a1                   March 19, 2010                        8
-
-
-
-
-
-SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
-
-
        If the plugin needs to interact with the user or display informational
        or error messages, it may do so via the conversation function.  A
        plugin should not attempt to read directly from the standard input or
@@ -566,6 +577,27 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
        usage.
 
    II//OO PPlluuggiinn AAPPII
+
+
+
+
+
+
+
+
+
+
+
+
+1.8.0a1                   March 21, 2010                        9
+
+
+
+
+
+SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
+
+
         struct io_plugin {
         #define SUDO_IO_PLUGIN         2
             unsigned int type; /* always SUDO_IO_PLUGIN */
@@ -586,18 +618,6 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
        disabled, such as passwords).  The log_output function receives output
        from the pseudo-tty that is suitable for replaying the user's session
        at a later time.  Either log_input or log_output may be NULL.  If the
-
-
-
-1.8.0a1                   March 19, 2010                        9
-
-
-
-
-
-SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
-
-
        open function returns 0, no I/O will be sent to the plugin.
 
        The io_plugin struct has the following fields:
@@ -632,6 +652,18 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
                A pointer to the conversation function that may be used by the
                _s_h_o_w___v_e_r_s_i_o_n function to display version information (see
                show_version below).  The conversation function may also be
+
+
+
+1.8.0a1                   March 21, 2010                       10
+
+
+
+
+
+SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
+
+
                used to display additional error message to the user.
 
            settings
@@ -653,17 +685,6 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
                the form of "name=value" strings.  The vector is terminated by
                a NULL pointer.
 
-
-
-1.8.0a1                   March 19, 2010                       10
-
-
-
-
-
-SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
-
-
                When parsing _u_s_e_r___i_n_f_o, the plugin should split on the ffiirrsstt
                equal sign ('=') since the _n_a_m_e field will never include one
                itself but the _v_a_l_u_e might.
@@ -697,6 +718,18 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
                of errno set by the _e_x_e_c_v_e(2) system call.  If the command was
                successfully executed, the value of error is 0.
 
+
+
+
+1.8.0a1                   March 21, 2010                       11
+
+
+
+
+
+SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
+
+
        show_version
             int (*show_version)(int verbose);
 
@@ -718,18 +751,6 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
 
            The function arguments are as follows:
 
-
-
-
-1.8.0a1                   March 19, 2010                       11
-
-
-
-
-
-SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
-
-
            buf The buffer containing user input.
 
            len The length of _b_u_f in bytes.
@@ -757,6 +778,24 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
    SSuuddoo iimmpplleemmeennttaattiioonn ddeettaaiillss
        Version macros:
 
+
+
+
+
+
+
+
+
+
+1.8.0a1                   March 21, 2010                       12
+
+
+
+
+
+SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
+
+
         #define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16)
         #define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
         #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \
@@ -787,6 +826,33 @@ SUDO_PLUGIN(1m)        MAINTENANCE COMMANDS       SUDO_PLUGIN(1m)
 
 
 
-1.8.0a1                   March 19, 2010                       12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1.8.0a1                   March 21, 2010                       13
 
 
diff --git a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in
index 8dd462c15..46dab62b0 100644
--- a/doc/sudo_plugin.man.in
+++ b/doc/sudo_plugin.man.in
@@ -139,7 +139,7 @@
 .\" ========================================================================
 .\"
 .IX Title "SUDO_PLUGIN @mansectsu@"
-.TH SUDO_PLUGIN @mansectsu@ "March 19, 2010" "1.8.0a1" "MAINTENANCE COMMANDS"
+.TH SUDO_PLUGIN @mansectsu@ "March 21, 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
@@ -295,6 +295,15 @@ the user wishes to preserve the environment.
 .IX Item "login_shell=bool"
 Set to true if the user specified the \f(CW\*(C`\-i\*(C'\fR flag, indicating that
 the user wishes to run a login shell.
+.IP "implied_shell=bool" 4
+.IX Item "implied_shell=bool"
+If the user does not specify a program on the command line, \fBsudo\fR
+will pass the plugin the path to the user's shell and set
+\&\fIimplied_shell\fR to true.  This allows \fBsudo\fR with no arguments
+to be used similarly to \fIsu\fR\|(1).  If the plugin does not to support
+this usage, it may return a value of \-2 from the \f(CW\*(C`check_policy\*(C'\fR
+function, which will cause \fBsudo\fR to print a usage message and
+exit.
 .IP "preserve_groups=bool" 4
 .IX Item "preserve_groups=bool"
 Set to true if the user specified the \f(CW\*(C`\-P\*(C'\fR flag, indicating that
diff --git a/doc/sudo_plugin.pod b/doc/sudo_plugin.pod
index 8f3dbb378..d11114910 100644
--- a/doc/sudo_plugin.pod
+++ b/doc/sudo_plugin.pod
@@ -180,6 +180,16 @@ the user wishes to preserve the environment.
 Set to true if the user specified the C<-i> flag, indicating that
 the user wishes to run a login shell.
 
+=item implied_shell=bool
+
+If the user does not specify a program on the command line, B<sudo>
+will pass the plugin the path to the user's shell and set
+I<implied_shell> to true.  This allows B<sudo> with no arguments
+to be used similarly to L<su(1)>.  If the plugin does not to support
+this usage, it may return a value of -2 from the C<check_policy>
+function, which will cause B<sudo> to print a usage message and
+exit.
+
 =item preserve_groups=bool
 
 Set to true if the user specified the C<-P> flag, indicating that
diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c
index 469c5f1ff..6a5645fa9 100644
--- a/plugins/sudoers/sudoers.c
+++ b/plugins/sudoers/sudoers.c
@@ -262,12 +262,6 @@ sudoers_policy_open(unsigned int version, sudo_conv_t conversation,
     /* Set login class if applicable. */
     set_loginclass(sudo_user.pw);
 
-#if 0 /* XXX - later */
-    /* Update initial shell now that runas is set. */
-    if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
-	NewArgv[0] = runas_pw->pw_shell;
-#endif
-
     /* XXX */
     user_env = envp; /* stash for later */
 
@@ -305,11 +299,17 @@ sudoers_policy_main(int argc, char * const argv[], char *env_add[],
 	return -1;
     }
 
-    /* Local copy of argv */
+    /*
+     * Make a local copy of argc/argv, with special handling
+     * for the '-e', '-i' or '-s' options.
+     * XXX - handle sudoedit
+     */
     NewArgv = emalloc2(argc + 1, sizeof(char *));
     memcpy(NewArgv, argv, argc * sizeof(char *));
     NewArgv[argc] = NULL;
     NewArgc = argc;
+    if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
+	NewArgv[0] = runas_pw->pw_shell;
 
     /* Set environ to contents of user_env. */
     env_init(user_env);
@@ -387,9 +387,9 @@ sudoers_policy_main(int argc, char * const argv[], char *env_add[],
     if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
 	def_preserve_groups = TRUE;
 
-    /* If no command line args and "set_home" is not set, error out. */
+    /* If no command line args and "shell_noargs" is not set, error out. */
     if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) {
-	/* XXX - error message */
+	rval = -2; /* usage error */
 	goto done;
     }
 
@@ -447,7 +447,7 @@ sudoers_policy_main(int argc, char * const argv[], char *env_add[],
 	goto done;
     } else if (cmnd_status == NOT_FOUND) {
 	//audit_failure(NewArgv, "%s: command not found", user_cmnd);
-	warningx("command not found", user_cmnd);
+	warningx("%s: command not found", user_cmnd);
 	goto done;
     }
 
@@ -622,12 +622,6 @@ init_vars(char * const envp[])
     (void) tzset();		/* set the timezone if applicable */
 #endif /* HAVE_TZSET */
 
-#if 0
-    /* Default value for cmnd and cwd, overridden later. */
-    if (user_cmnd == NULL)
-	user_cmnd = NewArgv[0];
-#endif
-
     for (ep = envp; *ep; ep++) {
 	/* XXX - don't fill in if empty string */
 	switch (**ep) {
@@ -644,9 +638,7 @@ init_vars(char * const envp[])
 		    user_path = *ep + 5;
 		break;
 	    case 'S':
-		if (strncmp("SHELL=", *ep, 6) == 0)
-		    user_shell = *ep + 6;
-		else if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
+		if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
 		    user_prompt = *ep + 12;
 		else if (strncmp("SUDO_USER=", *ep, 10) == 0)
 		    prev_user = *ep + 10;
@@ -683,8 +675,6 @@ init_vars(char * const envp[])
 #ifdef HAVE_MBR_CHECK_MEMBERSHIP
     mbr_uid_to_uuid(user_uid, user_uuid);
 #endif
-    if (user_shell == NULL || *user_shell == '\0')
-	user_shell = estrdup(sudo_user.pw->pw_shell);
 
     /* It is now safe to use log_error() and set_perms() */
 
@@ -692,43 +682,6 @@ init_vars(char * const envp[])
 	/* may call log_error() */
 	set_fqdn();
     }
-
-#if 0 /* XXX need to adapt this in sudo.c */
-    /*
-     * If we were given the '-e', '-i' or '-s' options we need to redo
-     * NewArgv and NewArgc.
-     */
-    if (ISSET(sudo_mode, MODE_EDIT)) {
-	NewArgv--;
-	NewArgc++;
-	NewArgv[0] = "sudoedit";
-    } else if (ISSET(sudo_mode, MODE_SHELL)) {
-	char **av;
-
-	/* Allocate an extra slot for execve() failure (ENOEXEC). */
-	av = (char **) emalloc2(5, sizeof(char *));
-	av++;
-
-	av[0] = user_shell;	/* may be updated later */
-	if (NewArgc > 0) {
-	    size_t size;
-	    char *cmnd, *src, *dst, *end;
-	    size = (size_t) (NewArgv[NewArgc - 1] - NewArgv[0]) +
-		    strlen(NewArgv[NewArgc - 1]) + 1;
-	    cmnd = emalloc(size);
-	    src = NewArgv[0];
-	    dst = cmnd;
-	    for (end = src + size - 1; src < end; src++, dst++)
-		*dst = *src == 0 ? ' ' : *src;
-	    *dst = '\0';
-	    av[1] = "-c";
-	    av[2] = cmnd;
-	    NewArgc = 2;
-	}
-	av[++NewArgc] = NULL;
-	NewArgv = av;
-    }
-#endif
 }
 
 /*
@@ -748,6 +701,10 @@ set_cmnd(sudo_mode)
     rval = FOUND;
     user_stat = emalloc(sizeof(struct stat));
 
+    /* Default value for cmnd, overridden below. */
+    if (user_cmnd == NULL)
+	user_cmnd = NewArgv[0];
+
     if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
 	if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
 	    set_perms(PERM_RUNAS);
@@ -766,16 +723,9 @@ set_cmnd(sudo_mode)
 	    char *to, **from;
 	    size_t size, n;
 
-	    /* If we didn't realloc NewArgv it is contiguous so just count. */
-	    if (!ISSET(sudo_mode, MODE_SHELL)) {
-		size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
-			strlen(NewArgv[NewArgc-1]) + 1;
-	    } else {
-		for (size = 0, from = NewArgv + 1; *from; from++)
-		    size += strlen(*from) + 1;
-	    }
-
 	    /* Alloc and build up user_args. */
+	    for (size = 0, from = NewArgv + 1; *from; from++)
+		size += strlen(*from) + 1;
 	    user_args = emalloc(size);
 	    for (to = user_args, from = NewArgv + 1; *from; from++) {
 		n = strlcpy(to, *from, size - (to - user_args));
@@ -1197,6 +1147,11 @@ deserialize_info(char * const settings[], char * const user_info[])
 	    }
 	    continue;
 	}
+	if (MATCHES(*cur, "implied_shell=")) {
+	    if (atobool(*cur + sizeof("implied_shell=") - 1) == TRUE)
+		SET(flags, MODE_IMPLIED_SHELL);
+	    continue;
+	}
 	if (MATCHES(*cur, "preserve_groups=")) {
 	    SET(flags, MODE_PRESERVE_GROUPS);
 	    continue;
diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h
index 19ac90131..8a829a19b 100644
--- a/plugins/sudoers/sudoers.h
+++ b/plugins/sudoers/sudoers.h
@@ -48,7 +48,6 @@ struct sudo_user {
     struct stat *cmnd_stat;
     char *name;
     char *path;
-    char *shell;
     char *tty;
     char *ttypath;
     char *host;
@@ -156,7 +155,6 @@ struct sudo_user {
 #define user_passwd		(sudo_user.pw->pw_passwd)
 #define user_uuid		(sudo_user.uuid)
 #define user_dir		(sudo_user.pw->pw_dir)
-#define user_shell		(sudo_user.shell)
 #define user_ngroups		(sudo_user.ngroups)
 #define user_groups		(sudo_user.groups)
 #define user_tty		(sudo_user.tty)
diff --git a/src/parse_args.c b/src/parse_args.c
index 222a19057..d8837a86a 100644
--- a/src/parse_args.c
+++ b/src/parse_args.c
@@ -66,7 +66,6 @@ const char *list_user, *runas_user, *runas_group;
 /*
  * Local functions.
  */
-static void usage(int) __attribute__((__noreturn__));
 static void usage_excl(int) __attribute__((__noreturn__));
 
 /*
@@ -102,7 +101,9 @@ static struct sudo_settings {
     { "runas_user" },
 #define ARG_PROGNAME 12
     { "progname" },
-#define NUM_SETTINGS 13
+#define ARG_IMPLIED_SHELL 13
+    { "implied_shell" },
+#define NUM_SETTINGS 14
     { NULL }
 };
 
@@ -295,13 +296,13 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
 	}
     }
 
-    *nargc = argc - optind;
-    *nargv = argv + optind;
+    argc -= optind;
+    argv += optind;
 
     if (!mode) {
 	/* Defer -k mode setting until we know whether it is a flag or not */
 	if (sudo_settings[ARG_IGNORE_TICKET].value != NULL) {
-	    if (*nargc == 0) {
+	    if (argc == 0) {
 		mode = MODE_INVALIDATE;	/* -k by itself */
 		sudo_settings[ARG_IGNORE_TICKET].value = NULL;
 		valid_flags = 0;
@@ -311,7 +312,7 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
 	    mode = MODE_RUN;		/* running a command */
     }
 
-    if (*nargc > 0 && mode == MODE_LIST)
+    if (argc > 0 && mode == MODE_LIST)
 	mode = MODE_CHECK;
 
     if (ISSET(flags, MODE_LOGIN_SHELL)) {
@@ -347,15 +348,55 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
 	warningx("the `-A' and `-S' options may not be used together");
 	usage(1);
     }
-    if ((*nargc == 0 && mode == MODE_EDIT) ||
-	(*nargc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
+    if ((argc == 0 && mode == MODE_EDIT) ||
+	(argc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
 	usage(1);
-    if (*nargc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL))
+    if (argc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL)) {
 	SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
+	sudo_settings[ARG_IMPLIED_SHELL].value = "true";
+    }
 
     if (mode == MODE_HELP)
 	usage(0);
 
+    /*
+     * For shell mode we need to rewrite argv
+     */
+    if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {
+	char **av;
+	int ac;
+
+	if (argc == 0) {
+	    /* just the shell */
+	    ac = argc + 1;
+	    av = emalloc2(ac + 1, sizeof(char *));
+	    memcpy(av + 1, argv, argc * sizeof(char *));
+	} else {
+	    /* shell -c "command" */
+	    size_t size;
+	    char *src, *dst, *end;
+
+	    /* length of the command + NUL terminator */
+	    size = (size_t)(argv[argc - 1] - argv[0]) +
+		strlen(argv[argc - 1]) + 1;
+
+	    ac = 3;
+	    av = emalloc2(ac + 1, sizeof(char *));
+	    av[1] = "-c";
+	    av[2] = dst = emalloc(size);
+
+	    src = argv[0];
+	    for (end = src + size - 1; src < end; src++, dst++)
+		*dst = *src == 0 ? ' ' : *src;
+	    *dst = '\0';
+	}
+	av[0] = (char *)user_details.shell; /* plugin may override shell */
+	av[ac] = NULL;
+
+	argv = av;
+	argc = ac;
+    }
+
     /*
      * Format setting_pairs into settings array.
      */
@@ -375,6 +416,8 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
 
     *settingsp = settings;
     *env_addp = env_add;
+    *nargc = argc;
+    *nargv = argv;
     return(mode | flags);
 }
 
@@ -388,7 +431,7 @@ usage_out(const char *buf)
  * Give usage message and exit.
  * The actual usage strings are in sudo_usage.h for configure substitution.
  */
-static void
+void
 usage(int exit_val)
 {
     struct lbuf lbuf;
diff --git a/src/sudo.c b/src/sudo.c
index a595b0aaa..7b9554955 100644
--- a/src/sudo.c
+++ b/src/sudo.c
@@ -224,8 +224,11 @@ main(int argc, char *argv[], char *envp[])
 	    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)
-		exit(ok); /* plugin printed error message */
+	    if (ok != TRUE) {
+		if (ok == -2)
+		    usage(1);
+		exit(1); /* plugin printed error message */
+	    }
 	    command_info_to_details(command_info, &command_details);
 	    /* Restore coredumpsize resource limit before running. */
 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
@@ -330,6 +333,12 @@ get_user_info(struct user_details *ud)
 	errorx(1, "unable to allocate memory");
     ud->username = user_info[i] + sizeof("user=") - 1;
 
+    /* Stash user's shell for use with the -s flag; don't pass to plugin. */
+    if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '\0') {
+	ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_BSHELL;
+    }
+    ud->shell = estrdup(ud->shell);
+
     easprintf(&user_info[++i], "uid=%lu", (unsigned long)ud->uid);
     easprintf(&user_info[++i], "euid=%lu", (unsigned long)ud->euid);
     easprintf(&user_info[++i], "gid=%lu", (unsigned long)ud->gid);
diff --git a/src/sudo.h b/src/sudo.h
index 5dcc4871d..2408e9112 100644
--- a/src/sudo.h
+++ b/src/sudo.h
@@ -117,6 +117,7 @@ struct user_details {
     const char *cwd;
     const char *tty;
     const char *host;
+    const char *shell;
     GETGROUPS_T *groups;
     int ngroups;
     int ts_cols;
@@ -210,6 +211,9 @@ int exec_setup(struct command_details *details);
 extern int debug_level;
 extern struct plugin_container_list io_plugins;
 
+/* parse_args.c */
+void usage(int) __attribute__((__noreturn__));
+
 #ifndef errno
 extern int errno;
 #endif
