Subject: bin/5788: su enhancement: allow root to su explicitly with /bin/sh
To: None <gnats-bugs@gnats.netbsd.org>
From: None <woods@most.weird.com>
List: netbsd-bugs
Date: 07/18/1998 01:56:05
>Number:         5788
>Category:       bin
>Synopsis:       su enhancement: allow root to su explicitly with /bin/sh
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Fri Jul 17 23:05:00 1998
>Last-Modified:
>Originator:     Greg A. Woods
>Organization:
Planix, Inc.; Toronto, Ontario; Canada
>Release:        NetBSD-1.3.1
>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:

	When a user has a non-generic shell (i.e. not one of the normal
	command-line shells such as /bin/sh, but instead something like
	/sbin/nologin), it is impossible, even for root, to start a normal
	shell as that user.

>How-To-Repeat:

	Try to run a command as the user 'daemon' when that user's shell
	is set to /sbin/nologin.  For example:

		01:35 [2083] # su daemon -c id
		This account is currently not available.

>Fix:

	Apply the following patch.  It adds a new option '-s' to su(1)
	which when used with the above example results in success:

		01:35 [2085] # su -s daemon -c id
	      	uid=1(daemon) gid=31(guest) groups=31(guest), 1(daemon)

	Note that this new option is only available to root.

	BTW, defaulting to /bin/sh only is more than enough -- anyone
	who wants some other shell can get it from there....

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/17 17:48:48
***************
*** 70,76 ****
  #include <kerberosIV/krb.h>
  #include <netdb.h>
  
! #define	ARGSTR	"-Kflm"
  
  int use_kerberos = 1;
  
--- 70,76 ----
  #include <kerberosIV/krb.h>
  #include <netdb.h>
  
! #define	ARGSTR	"-Kflms"
  
  int use_kerberos = 1;
  
***************
*** 78,84 ****
  static int koktologin __P((char *, char *, char *));
  
  #else
! #define	ARGSTR	"-flm"
  #endif
  
  #ifndef	SUGROUP
--- 78,84 ----
  static int koktologin __P((char *, char *, char *));
  
  #else
! #define	ARGSTR	"-flms"
  #endif
  
  #ifndef	SUGROUP
***************
*** 104,115 ****
  	struct group *gr;
  	struct timeval tp;
  	uid_t ruid;
! 	int asme, ch, asthem, fastlogin, prio;
  	enum { UNSET, YES, NO } iscsh = UNSET;
  	char *user, *shell, *avshell, *username, *cleanenv[10], **np;
  	char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN];
  
! 	asme = asthem = fastlogin = 0;
  	shell = NULL;
  	while ((ch = getopt(argc, argv, ARGSTR)) != -1)
  		switch((char)ch) {
--- 104,115 ----
  	struct group *gr;
  	struct timeval tp;
  	uid_t ruid;
! 	int asme, ch, asthem, fastlogin, prio, usebshell;
  	enum { UNSET, YES, NO } iscsh = UNSET;
  	char *user, *shell, *avshell, *username, *cleanenv[10], **np;
  	char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN];
  
! 	asme = asthem = fastlogin = usebshell = 0;
  	shell = NULL;
  	while ((ch = getopt(argc, argv, ARGSTR)) != -1)
  		switch((char)ch) {
***************
*** 130,135 ****
--- 130,138 ----
  			asme = 1;
  			asthem = 0;
  			break;
+ 		case 's':
+ 			usebshell = 1;
+ 			break;
  		case '?':
  		default:
  			(void)fprintf(stderr,
***************
*** 155,165 ****
  	if (pwd == NULL) {
  		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;
--- 158,170 ----
  	if (pwd == NULL) {
  		errx(1, "who are you?");
  	}
+ 	if (usebshell && ruid)
+ 		errx(1,"permission denied (-s).");
  	username = strdup(pwd->pw_name);
  	if (asme)
! 		if (!usebshell && pwd->pw_shell && *pwd->pw_shell)
  			shell = strncpy(shellbuf, pwd->pw_shell,
! 					sizeof(shellbuf) + 1);
  		else {
  			shell = _PATH_BSHELL;
  			iscsh = NO;
***************
*** 225,231 ****
  		/* 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 {
--- 230,236 ----
  		/* if asme and non-standard target shell, must be root */
  		if (!chshell(pwd->pw_shell) && ruid)
  			errx(1,"permission denied (shell).");
! 	} else if (!usebshell && pwd->pw_shell && *pwd->pw_shell) {
  		shell = pwd->pw_shell;
  		iscsh = UNSET;
  	} else {

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/17 17:02:16
***************
*** 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 17, 1998
  .Dt SU 1
  .Os
  .Sh NAME
***************
*** 40,46 ****
  .Nd substitute user identity
  .Sh SYNOPSIS
  .Nm
! .Op Fl Kflm
  .Op Ar login Op Ar "shell arguments"
  .Sh DESCRIPTION
  .Nm
--- 40,46 ----
  .Nd substitute user identity
  .Sh SYNOPSIS
  .Nm
! .Op Fl Kflms
  .Op Ar login Op Ar "shell arguments"
  .Sh DESCRIPTION
  .Nm
***************
*** 128,133 ****
--- 128,138 ----
  non-zero,
  .Nm
  will fail.
+ .It Fl s
+ Ignore the user's shell and invoke
+ .Pa /bin/sh
+ instead.
+ This option is only available for callers with a real uid of zero.
  .El
  .Pp
  The
>Audit-Trail:
>Unformatted: