[comp.protocols.kerberos] bug in login.krb + fix

pst@ACK.STANFORD.EDU (Paul Traina) (09/18/90)

The following was observed in Kerberos R4 PL9.

System: Sun (SPARC) + SunOS 4.0.3  (but affects others too)
Program: login.krb

I decided to replace /bin/login with login.krb so that I would generate
kerberos tickets any time I log into a machine.  Everything works fine
when login is execed by getty, everything is also fine when login
was invoked from rlogind/klogind in the normal manner.  However, when
attempting to rlogin to a target workstation from a device that doesn't
send down a username (like a TIP) we get a core dump.

It's a long problem description, but the fix is simple.
Setenv as supplied in the Athena distribution expects the environ array
to be in malloc'ed memory so it can realloc it if it needs to add more
slots.  The envinit code was just an automatic variable.  The solution
is to grab the environment table and insure that it is in malloc'ed
memory by copying it there.

This fix is relevant to more than just SunOS and the problem can occur
even when the -p (preserve environment) flag is passed to login,  so
I've placed the fixup in the main program flow.  Don't try to #ifdef
it or make it conditional on pflag, as it's a reasonable security blanket.

*** /mit/kerberos/src/appl/bsd/login.c	Thu Jun 21 12:56:55 1990
--- login.c	Mon Sep 17 14:20:20 1990
***************
*** 116,122 ****
--- 116,125 ----
  
  struct passwd *pwd;
  char term[64], *hostname, *username;
+ char *envinit[] = { 0 };
  
+ extern char *malloc();
+ 
  struct sgttyb sgttyb;
  struct tchars tc = {
  	CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
***************
*** 169,175 ****
  	int kflag, Kflag, eflag;
  	int quietlog, passwd_req, ioctlval;
  	sigtype timedout();
! 	char *domain, *salt, *envinit[1], *ttyn, *tty;
  	char tbuf[MAXPATHLEN + 2];
  	char *ttyname(), *stypeof(), *crypt(), *getpass();
  	time_t time();
--- 172,178 ----
  	int kflag, Kflag, eflag;
  	int quietlog, passwd_req, ioctlval;
  	sigtype timedout();
! 	char *domain, *salt, *ttyn, *tty, **envnew;
  	char tbuf[MAXPATHLEN + 2];
  	char *ttyname(), *stypeof(), *crypt(), *getpass();
  	time_t time();
***************
*** 598,603 ****
--- 601,618 ----
  	/* destroy environment unless user has requested preservation */
  	if (!pflag)
  		environ = envinit;
+ 
+ 	/* the environ array has to be in malloc'ed memory otherwise
+ 	   when setenv tries to realloc it,  ugly things happen on
+ 	   picky processors */
+ 
+ 	for (cnt = 0; environ[cnt]; ++cnt)	/* count current slots */
+ 		;
+ 	envnew = (char **) malloc(sizeof(char *) * (cnt + 1));
+ 	for ( ; cnt >= 0; --cnt)
+ 		envnew[cnt] = environ[cnt];
+ 	environ = envnew;
+ 
  	(void)setenv("HOME", pwd->pw_dir, 1);
  	(void)setenv("SHELL", pwd->pw_shell, 1);
  	if (term[0] == '\0')