[comp.bugs.4bsd] Process group bug in su command

philip@cs.vu.nl (Philip Homburg) (02/24/90)

Description:
	su should create a new process group for the new shell,
	and wait for the new shell to finish in order to reset
	the tty process group to its old value.

Repeat-By:
	% sh
	$ su somebody-ELSE-with-a-Bourne-shell
	Password:
	$ csh	# any shell with job control
	% exit
	% $
	Stopped (tty input)	# or Stopped (tty output), depending on
	%			# the status of the tostop bit

Fix:
----------cut here----------
*** su.c.old	Sat Feb 24 00:06:13 1990
--- su.c	Sat Feb 24 05:43:11 1990
***************
*** 18,26 ****
--- 18,29 ----
  #include <pwd.h>
  #include <grp.h>
  #include <syslog.h>
+ #include <signal.h>
  #include <sys/types.h>
  #include <sys/time.h>
  #include <sys/resource.h>
+ #include <sys/ioctl.h>
+ #include <sys/wait.h>
  
  char	userbuf[16]	= "USER=";
  char	homebuf[128]	= "HOME=";
***************
*** 111,128 ****
  		syslog(LOG_NOTICE, "%s on %s", Getlogin(), ttyname(2));
  		closelog();
  	}
- 	if (setgid(pwd->pw_gid) < 0) {
- 		perror("su: setgid");
- 		exit(3);
- 	}
- 	if (initgroups(user, pwd->pw_gid)) {
- 		fprintf(stderr, "su: initgroups failed\n");
- 		exit(4);
- 	}
- 	if (setuid(pwd->pw_uid) < 0) {
- 		perror("su: setuid");
- 		exit(5);
- 	}
  	if (pwd->pw_shell && *pwd->pw_shell)
  		shell = pwd->pw_shell;
  	if (fulllogin) {
--- 114,119 ----
***************
*** 145,153 ****
  		*argv = "-su";
  	} else
  		*argv = "su";
! 	execv(shell, argv);
! 	fprintf(stderr, "No shell\n");
! 	exit(7);
  }
  
  setenv(ename, eval, buf)
--- 136,193 ----
  		*argv = "-su";
  	} else
  		*argv = "su";
! 	{
! 		int opgrp, npgrp, fd;
! 		union wait w;
! 
! 		fd = open("/dev/tty", 0);
! 
! 		if (fd >= 0)
! 			(void) ioctl(fd, TIOCGPGRP, &opgrp);
! 
! 		switch (fork()) {
! 		case -1:
! 			perror("fork");
! 			exit(1);
! 		case 0:
! 			if (setgid(pwd->pw_gid) < 0) {
! 				perror("su: setgid");
! 				exit(3);
! 			}
! 			if (initgroups(user, pwd->pw_gid)) {
! 				perror("su: initgroups failed");
! 				exit(4);
! 			}
! 			if (setuid(pwd->pw_uid) < 0) {
! 				perror("su: setuid");
! 				exit(5);
! 			}
! 			npgrp = getpid();
! 			if (fd >= 0) {
! 				if (ioctl(fd, TIOCSPGRP, &npgrp) < 0) {
! 					perror("ioctl TIOCSPGRP");
! 					exit(99);
! 				}
! 				close(fd);
! 			}
! 			setpgrp(0, npgrp);
! 			execv(shell, argv);
! 			perror(shell);
! 			exit(7);
! 		default:
! 			(void) wait3(&w, 0, (struct rusage *) 0);
! 			setuid(getuid());
! 			setgid(getgid());
! 			if (fd >= 0) {
! 				sigblock(sigmask(SIGTTOU));
! 				(void) ioctl(fd, TIOCSPGRP, &opgrp);
! 			}
! 			if (WIFEXITED(w))
! 				exit(w.w_retcode);
! 			else
! 				exit(0200 + w.w_termsig);
! 		}
! 	}
  }
  
  setenv(ename, eval, buf)
----------cut here----------

casey@gauss.llnl.gov (Casey Leedom) (02/25/90)

| From: philip@cs.vu.nl (Philip Homburg)
| Description:
| 	su should create a new process group for the new shell,
| 	and wait for the new shell to finish in order to reset
| 	the tty process group to its old value.
| 
| Repeat-By:
| 	% sh
| 	$ su somebody-ELSE-with-a-Bourne-shell
| 	Password:
| 	$ csh	# any shell with job control
| 	% exit
| 	% $
| 	Stopped (tty input)	# or Stopped (tty output), depending on
| 	%			# the status of the tostop bit

  This isn't a bug in su.  It's a bug in the shell.