than just running the non-standard shell
SCCS-vsn: usr.bin/su/su.c 5.11
SCCS-vsn: usr.bin/su/su.1 6.7
.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.\" @(#)su.1 6.6 (Berkeley) %G%
+.\" @(#)su.1 6.7 (Berkeley) %G%
.PP
The \fI-m\fP option causes the environment to remain unmodified, and
the invoked shell to be your login shell. No directory changes are
.PP
The \fI-m\fP option causes the environment to remain unmodified, and
the invoked shell to be your login shell. No directory changes are
-made. As a security precaution, if the target shell is not a standard
-shell (as defined by \fIgetusershell\fP(3)) it is invoked instead of
-your login shell.
+made. As a security precaution, if the
+.I -m
+option is specified, the target user's shell is a non-standard shell
+(as defined by \fIgetusershell\fP(3)) and the caller's real uid is
+non-zero,
+.I su
+will fail.
.PP
If the invoked shell is \fIcsh\fP, the \fI-f\fP option prevents it from
reading the \fI.cshrc\fP file. Otherwise, this option is ignored.
.PP
If the invoked shell is \fIcsh\fP, the \fI-f\fP option prevents it from
reading the \fI.cshrc\fP file. Otherwise, this option is ignored.
#endif /* not lint */
#ifndef lint
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)su.c 5.10 (Berkeley) %G%";
+static char sccsid[] = "@(#)su.c 5.11 (Berkeley) %G%";
#endif /* not lint */
#include <sys/param.h>
#endif /* not lint */
#include <sys/param.h>
- /* if not asme or target's shell isn't standard, use it */
- if (!asme || !chshell(pwd->pw_shell))
- if (pwd->pw_shell && *pwd->pw_shell) {
- shell = pwd->pw_shell;
- iscsh = UNSET;
- } else {
- shell = "/bin/sh";
- iscsh = NO;
+ if (asme) {
+ /* if asme and non-standard target shell, must be root */
+ if (!chshell(pwd->pw_shell) && ruid) {
+ fprintf(stderr, "su: Permission denied.\n");
+ exit(1);
+ }
+ else if (pwd->pw_shell && *pwd->pw_shell) {
+ shell = pwd->pw_shell;
+ iscsh = UNSET;
+ } else {
+ shell = "/bin/sh";
+ iscsh = NO;
+ }
/* if we're forking a csh, we want to slightly muck the args */
if (iscsh == UNSET) {
/* if we're forking a csh, we want to slightly muck the args */
if (iscsh == UNSET) {