Subject: bin/5803: su doesn't support it's "-f" option for sh and/or ksh
To: None <gnats-bugs@gnats.netbsd.org>
From: None <woods@most.weird.com>
List: netbsd-bugs
Date: 07/19/1998 19:28:56
>Number:         5803
>Category:       bin
>Synopsis:       su doesn't support it's "-f" option for sh and/or ksh
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Jul 19 16:35:00 1998
>Last-Modified:
>Originator:     Greg A. Woods
>Organization:
Planix, Inc.; Toronto, Ontario; Canada
>Release:        NetBSD-current 19980719
>Environment:

System: NetBSD most 1.3.1 NetBSD 1.3.1 (MOST) #0: Mon May 25 01:21:22 EDT 1998 woods@most:/usr/src-1.3.1/sys/arch/sparc/compile/MOST sparc

>Description:

	Su(1) does not include support for its '-f' option for any shell
	but csh(1).  However both sh(1) and ksh(1) will source a file
	pointed to by the $ENV environment variable.  Su(1) should unset
	this variable if '-f' is given to provide the same behaviour for
	sh(1) and ksh(1) as it does for csh(1).

>How-To-Repeat:

	by behavioural observation and code walk-through

>Fix:

	Apply the attached patch.

	The core of this patch are the segments for the manual page and
	the following change:

***************
*** 272,278 ****
			*np-- = "-f";
  		if (asme)
			*np-- = "-m";
! 	}
  
  	if (asthem) {
  		avshellbuf[0] = '-';
--- 272,279 ----
			*np-- = "-f";	/* don't read .cshrc */
  		if (asme)
			*np-- = "-m";	/* allow reading of my .cshrc by user */
! 	} else if (fastlogin)
! 		unsetenv("ENV");	/* sh & ksh: don't process $ENV */
  
  	if (asthem) {
  		avshellbuf[0] = '-';

	The full patch also includes some KNF and a minor error message
	clarification and clarification of logic leading to that error:

Index: su.c
===================================================================
RCS file: /cvs/NetBSD/src/usr.bin/su/su.c,v
retrieving revision 1.1.1.2
diff -c -r1.1.1.2 su.c
*** su.c	1998/04/04 22:57:32	1.1.1.2
--- su.c	1998/07/19 23:07:45
***************
*** 156,165 ****
  		errx(1, "who are you?");
  	}
  	username = strdup(pwd->pw_name);
! 	if (asme)
  		if (pwd->pw_shell && *pwd->pw_shell)
  			shell = strncpy(shellbuf, pwd->pw_shell,
! 			    sizeof(shellbuf) + 1);
  		else {
  			shell = _PATH_BSHELL;
  			iscsh = NO;
--- 156,165 ----
  		errx(1, "who are you?");
  	}
  	username = strdup(pwd->pw_name);
! 	if (asme)			/* use my shell */
  		if (pwd->pw_shell && *pwd->pw_shell)
  			shell = strncpy(shellbuf, pwd->pw_shell,
! 					sizeof(shellbuf) + 1);
  		else {
  			shell = _PATH_BSHELL;
  			iscsh = NO;
***************
*** 174,238 ****
  	}
  
  	if (ruid) {
  #ifdef KERBEROS
! 	    if (!use_kerberos || kerberos(username, user, pwd->pw_uid))
  #endif
! 	    {
! 		/* Only allow those in group SUGROUP to su to root,
! 		   but only if that group has any members.
! 		   If SUGROUP has no members, allow anyone to su root */
! 		if (pwd->pw_uid == 0 &&
! 		    (gr = getgrnam(SUGROUP)) && *gr->gr_mem) {
! 			char **g;
! 
! 			for (g = gr->gr_mem; ; g++) {
! 				if (*g == NULL)
! 					errx(1,
  	    "you are not listed in the correct secondary group (%s) to su %s.",
! 					    SUGROUP, user);
! 				if (strcmp(username, *g) == 0)
! 					break;
  			}
! 		}
! 		/* if target requires a password, verify it */
! 		if (*pwd->pw_passwd) {
! 			p = getpass("Password:");
  #ifdef SKEY
! 			if (strcasecmp(p, "s/key") == 0) {
! 				if (skey_haskey(user))
! 					errx(1, "Sorry, you have no s/key.");
! 				else {
! 					if (skey_authenticate(user)) {
! 						goto badlogin;
  					}
- 				}
  
! 			} else
  #endif
! 			if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
  badlogin:
! 				fprintf(stderr, "Sorry\n");
! 				syslog(LOG_AUTH|LOG_WARNING,
! 					"BAD SU %s to %s%s", username,
! 					user, ontty());
! 				exit(1);
  			}
  		}
- 	    }
  	}
! 
! 	if (asme) {
! 		/* if asme and non-standard target shell, must be root */
! 		if (!chshell(pwd->pw_shell) && ruid)
! 			errx(1,"permission denied (shell).");
! 	} else if (pwd->pw_shell && *pwd->pw_shell) {
! 		shell = pwd->pw_shell;
! 		iscsh = UNSET;
! 	} else {
! 		shell = _PATH_BSHELL;
! 		iscsh = NO;
  	}
- 
  	if ((p = strrchr(shell, '/')) != NULL)
  		avshell = p+1;
  	else
--- 174,239 ----
  	}
  
  	if (ruid) {
+ 		/* if asme and non-standard target shell, must be root */
+ 		if (asme && !chshell(pwd->pw_shell))
+ 			errx(1, "permission denied (%s has non-standard shell %s).", user, pwd->pw_shell);
  #ifdef KERBEROS
! 		if (!use_kerberos || kerberos(username, user, pwd->pw_uid))
  #endif
! 		{
! 			/* Only allow those in group SUGROUP to su to root,
! 			 * but only if that group has any members.
! 			 * If SUGROUP has no members, allow anyone to su root */
! 			if (pwd->pw_uid == 0 &&
! 			    (gr = getgrnam(SUGROUP)) && *gr->gr_mem) {
! 				char **g;
! 
! 				for (g = gr->gr_mem; ; g++) {
! 					if (*g == NULL)
! 						errx(1,
  	    "you are not listed in the correct secondary group (%s) to su %s.",
! 						     SUGROUP, user);
! 					if (strcmp(username, *g) == 0)
! 						break;
! 				}
  			}
! 			/* if target requires a password, verify it */
! 			if (*pwd->pw_passwd) {
! 				p = getpass("Password:");
  #ifdef SKEY
! 				if (strcasecmp(p, "s/key") == 0) {
! 					if (skey_haskey(user))
! 						errx(1, "Sorry, you have no s/key.");
! 					else {
! 						if (skey_authenticate(user)) {
! 							goto badlogin;
! 						}
  					}
  
! 				} else
  #endif
! 				{
! 					if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
  badlogin:
! 						fprintf(stderr, "Sorry\n");
! 						syslog(LOG_AUTH|LOG_WARNING,
! 						       "BAD SU %s to %s%s", username,
! 						       user, ontty());
! 						exit(1);
! 					}
! 				}
  			}
  		}
  	}
! 	if (!asme) {
! 		if (pwd->pw_shell && *pwd->pw_shell) {
! 			shell = pwd->pw_shell;
! 			iscsh = UNSET;
! 		} else {
! 			shell = _PATH_BSHELL;
! 			iscsh = NO;
! 		}
  	}
  	if ((p = strrchr(shell, '/')) != NULL)
  		avshell = p+1;
  	else
***************
*** 266,278 ****
  		(void)setenv("HOME", pwd->pw_dir, 1);
  		(void)setenv("SHELL", shell, 1);
  	}
- 
  	if (iscsh == YES) {
  		if (fastlogin)
! 			*np-- = "-f";
  		if (asme)
! 			*np-- = "-m";
! 	}
  
  	if (asthem) {
  		avshellbuf[0] = '-';
--- 267,279 ----
  		(void)setenv("HOME", pwd->pw_dir, 1);
  		(void)setenv("SHELL", shell, 1);
  	}
  	if (iscsh == YES) {
  		if (fastlogin)
! 			*np-- = "-f";	/* don't read .cshrc */
  		if (asme)
! 			*np-- = "-m";	/* allow reading of my .cshrc by user */
! 	} else if (fastlogin)
! 		unsetenv("ENV");	/* sh & ksh: don't process $ENV */
  
  	if (asthem) {
  		avshellbuf[0] = '-';
***************
*** 325,330 ****
--- 326,333 ----
  {
  	char *cp;
  
+ 	if (!pwd->pw_shell || !*pwd->pw_shell)
+ 		return (1);		/* an unspecified shell is always "standard" */
  	while ((cp = getusershell()) != NULL)
  		if (!strcmp(cp, sh))
  			return (1);
Index: su.1
===================================================================
RCS file: /cvs/NetBSD/src/usr.bin/su/su.1,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 su.1
*** su.1	1998/02/20 00:43:25	1.1.1.1
--- su.1	1998/07/19 23:10:01
***************
*** 32,38 ****
  .\"	from: @(#)su.1	8.2 (Berkeley) 4/18/94
  .\"	$NetBSD: su.1,v 1.14 1997/10/19 23:31:52 lukem Exp $
  .\"
! .Dd April 18, 1994
  .Dt SU 1
  .Os
  .Sh NAME
--- 32,38 ----
  .\"	from: @(#)su.1	8.2 (Berkeley) 4/18/94
  .\"	$NetBSD: su.1,v 1.14 1997/10/19 23:31:52 lukem Exp $
  .\"
! .Dd July 19, 1998
  .Dt SU 1
  .Os
  .Sh NAME
***************
*** 81,89 ****
  .Ev USER
  is set to the target login, unless the target login has a user ID of 0,
  in which case it is unmodified.
! The invoked shell is the target login's.
! This is the traditional behavior of
! .Nm "" .
  .Pp
  The options are as follows:
  .Bl -tag -width Ds
--- 81,89 ----
  .Ev USER
  is set to the target login, unless the target login has a user ID of 0,
  in which case it is unmodified.
! The invoked shell is the target login's default shell unless the
! .Fl m
! option is set.
  .Pp
  The options are as follows:
  .Bl -tag -width Ds
***************
*** 95,100 ****
--- 95,109 ----
  this option prevents it from reading the
  .Dq Pa .cshrc
  file.
+ If the invoked shell is not
+ .Xr csh 1 ,
+ this option unsets any occurance of
+ .Ev ENV
+ in the environment to prevent possible processing of the file pointed to
+ by this variable by
+ .Xr ksh 1
+ or
+ .Xr sh 1 .
  .It Fl l
  Simulate a full login.
  The environment is discarded except for
***************
*** 121,128 ****
  .It Fl m
  Leave the environment unmodified.
  The invoked shell is your login shell, and no directory changes are made.
! As a security precaution, if the target user's shell is a non-standard
! shell (as defined by
  .Xr getusershell 3 )
  and the caller's real uid is
  non-zero,
--- 130,137 ----
  .It Fl m
  Leave the environment unmodified.
  The invoked shell is your login shell, and no directory changes are made.
! As a security precaution, if the target user's default shell is a
! non-standard shell (as defined by
  .Xr getusershell 3 )
  and the caller's real uid is
  non-zero,
***************
*** 163,168 ****
--- 172,178 ----
  to remind one of its awesome power.
  .Sh SEE ALSO
  .Xr csh 1 ,
+ .Xr ksh 1 ,
  .Xr login 1 ,
  .Xr sh 1 ,
  .Xr skey 1 ,
***************
*** 175,180 ****
--- 185,195 ----
  Environment variables used by
  .Nm "" :
  .Bl -tag -width "HOME"
+ .It Ev ENV
+ Gives file to process on shell startup, used by
+ .Xr ksh
+ and
+ .Xr sh .
  .It Ev HOME
  Default home directory of real user ID unless modified as
  specified above.
>Audit-Trail:
>Unformatted: