[net.bugs.4bsd] bugs in -ltermlib termcap.c

hansen@pegasus.UUCP (Tony L. Hansen) (04/27/85)

I've found a few bugs in the termcap library that still exist in
4.2BSD.

1: tgetent() cannot be called more than once in a program (hopcount doesn't
   get rezeroed).
2: an entry with ":tc=foo" but no trailing colon will cause coredumps.
3. buffer overflows can still occur, causing coredumps.
4. in tc=foo, foo can only be 16 chars long. this is not checked.

Apply patch at will.

					Tony Hansen
					pegasus!hansen


*** /tmp/termcap.c	Fri Apr 26 16:41:17 1985
--- /tmp/ntermcap.c	Fri Apr 26 16:57:40 1985
***************
*** 2,8
  static char sccsid[] = "@(#)termcap.c	4.1 (Berkeley) 6/27/83";
  #endif
  
! #define	BUFSIZ		1024
  #define MAXHOP		32	/* max number of tc= indirections */
  #define	E_TERMCAP	"/etc/termcap"
  

--- 2,8 -----
  static char sccsid[] = "@(#)termcap.c	4.1 (Berkeley) 6/27/83";
  #endif
  
! #define	TBUFSIZE	2048
  #define MAXHOP		32	/* max number of tc= indirections */
  #define	E_TERMCAP	"/etc/termcap"
  
***************
*** 36,41
  tgetent(bp, name)
  	char *bp, *name;
  {
  	register char *cp;
  	register int c;
  	register int i = 0, cnt = 0;

--- 36,59 -----
  tgetent(bp, name)
  	char *bp, *name;
  {
+ 	/* Tony Hansen */
+ 	int ret;
+ 	hopcount = 0;
+ 	ret = _tgetent(bp, name);
+ 	/*
+ 	  There is some sort of bug in the check way down below to prevent
+ 	  buffer overflow. I really don't want to track it down, so I
+ 	  upped the standard buffer size and check here to see if the created
+ 	  buffer is larger than the old buffer size.
+ 	*/
+ 	if (strlen(bp) >= 1024)
+ 		write(2,"Termcap entry too long\n", 23);
+ 	return ret;
+ }
+ 
+ static _tgetent(bp, name)
+ 	char *bp, *name;
+ {
  	register char *cp;
  	register int c;
  	register int i = 0, cnt = 0;
***************
*** 39,45
  	register char *cp;
  	register int c;
  	register int i = 0, cnt = 0;
! 	char ibuf[BUFSIZ];
  	char *cp2;
  	int tf;
  

--- 57,63 -----
  	register char *cp;
  	register int c;
  	register int i = 0, cnt = 0;
! 	char ibuf[TBUFSIZ];
  	char *cp2;
  	int tf;
  
***************
*** 77,83
  		cp = bp;
  		for (;;) {
  			if (i == cnt) {
! 				cnt = read(tf, ibuf, BUFSIZ);
  				if (cnt <= 0) {
  					close(tf);
  					return (0);

--- 95,101 -----
  		cp = bp;
  		for (;;) {
  			if (i == cnt) {
! 				cnt = read(tf, ibuf, TBUFSIZE);
  				if (cnt <= 0) {
  					close(tf);
  					return (0);
***************
*** 92,98
  				}
  				break;
  			}
! 			if (cp >= bp+BUFSIZ) {
  				write(2,"Termcap entry too long\n", 23);
  				break;
  			} else

--- 110,116 -----
  				}
  				break;
  			}
! 			if (cp >= bp+TBUFSIZE) {
  				write(2,"Termcap entry too long\n", 23);
  				break;
  			} else
***************
*** 120,125
  tnchktc()
  {
  	register char *p, *q;
  	char tcname[16];	/* name of similar terminal */
  	char tcbuf[BUFSIZ];
  	char *holdtbuf = tbuf;

--- 138,145 -----
  tnchktc()
  {
  	register char *p, *q;
+ #define TERMNAMESIZE 16
+ 	char tcname[TERMNAMESIZE];	/* name of similar terminal */
  	char tcname[16];	/* name of similar terminal */
  	char tcbuf[TBUFSIZE];
  	char *holdtbuf = tbuf;
***************
*** 121,127
  {
  	register char *p, *q;
  	char tcname[16];	/* name of similar terminal */
! 	char tcbuf[BUFSIZ];
  	char *holdtbuf = tbuf;
  	int l;
  

--- 141,147 -----
  #define TERMNAMESIZE 16
  	char tcname[TERMNAMESIZE];	/* name of similar terminal */
  	char tcname[16];	/* name of similar terminal */
! 	char tcbuf[TBUFSIZE];
  	char *holdtbuf = tbuf;
  	int l;
  
***************
*** 135,140
  	/* p now points to beginning of last field */
  	if (p[0] != 't' || p[1] != 'c')
  		return(1);
  	strcpy(tcname,p+3);
  	q = tcname;
  	while (q && *q != ':')

--- 155,161 -----
  	/* p now points to beginning of last field */
  	if (p[0] != 't' || p[1] != 'c')
  		return(1);
+ 	strncpy(tcname,p+3, TERMNAMESIZE);	/* TLH */
  	strcpy(tcname,p+3);
  	q = tcname;
  	while (*q && *q != ':')
***************
*** 137,143
  		return(1);
  	strcpy(tcname,p+3);
  	q = tcname;
! 	while (q && *q != ':')
  		q++;
  	*q = 0;
  	if (++hopcount > MAXHOP) {

--- 158,164 -----
  	strncpy(tcname,p+3, TERMNAMESIZE);	/* TLH */
  	strcpy(tcname,p+3);
  	q = tcname;
! 	while (*q && *q != ':')
  		q++;
  	*q = 0;
  	if (++hopcount > MAXHOP) {
***************
*** 144,150
  		write(2, "Infinite tc= loop\n", 18);
  		return (0);
  	}
! 	if (tgetent(tcbuf, tcname) != 1)
  		return(0);
  	for (q=tcbuf; *q != ':'; q++)
  		;

--- 165,171 -----
  		write(2, "Infinite tc= loop\n", 18);
  		return (0);
  	}
! 	if (_tgetent(tcbuf, tcname) != 1)
  		return(0);
  	for (q=tcbuf; *q != ':'; q++)
  		;
***************
*** 149,155
  	for (q=tcbuf; *q != ':'; q++)
  		;
  	l = p - holdtbuf + strlen(q);
! 	if (l > BUFSIZ) {
  		write(2, "Termcap entry too long\n", 23);
  		q[BUFSIZ - (p-tbuf)] = 0;
  	}

--- 170,176 -----
  	for (q=tcbuf; *q != ':'; q++)
  		;
  	l = p - holdtbuf + strlen(q);
! 	if (l > TBUFSIZE) {
  		write(2, "Termcap entry too long\n", 23);
  		q[TBUFSIZE - (p-tbuf)] = 0;
  	}
***************
*** 151,157
  	l = p - holdtbuf + strlen(q);
  	if (l > BUFSIZ) {
  		write(2, "Termcap entry too long\n", 23);
! 		q[BUFSIZ - (p-tbuf)] = 0;
  	}
  	strcpy(p, q+1);
  	tbuf = holdtbuf;

--- 172,178 -----
  	l = p - holdtbuf + strlen(q);
  	if (l > TBUFSIZE) {
  		write(2, "Termcap entry too long\n", 23);
! 		q[TBUFSIZE - (p-tbuf)] = 0;
  	}
  	strcpy(p, q+1);
  	tbuf = holdtbuf;