[comp.bugs.4bsd] parsing bug in Berkeley mail

jnford@jay.weeg.uiowa.edu (Jay Ford) (11/14/89)

Subject: address parsing bug in Berkeley mail (/usr/ucb/Mail)
Index: UCB Mail Version 5.2 (6/21/85)

Description:
	There is a parsing bug in the routine skin in aux.c which causes it
	to mangle mail addresses containing quoted or commented strings
	following an address in angle brackets.

Problem found on:
	IBM RT running IBM/4.3 rel 2 (Dec 1988);
	NeXT running MACH 1.0;
	VAX running 4.3BSD;
	Sun running SunOS Release 4.0

Rebeat-by:
	Get mail from someone with an address like
		<jnford@jay.weeg.uiowa.edu> "commas, in, quotes"
	or
		<jnford@jay.weeg.uiowa.edu> (commas, in, a, comment)
	This can be done by saving a piece of mail, hacking the from line,
	and using mail -f on the file.

Fix:
	Apply the following patches in /usr/src/ucb/Mail.


Jay Ford,  Weeg Computing Center,  University of Iowa,  Iowa City,  IA  52242
jnford@jay.weeg.uiowa.edu  or  jnfordpb@uiamvs.bitnet,  319-335-5555


*** version.c.orig	Fri Dec  9 13:56:05 1988
--- version.c	Mon Nov 13 17:55:52 1989
***************
*** 13,19 ****
   */
  
  #ifndef lint
! static char *sccsid = "@(#)version.c	5.2 (Berkeley) 6/21/85";
  #endif not lint
  
  /*
--- 13,19 ----
   */
  
  #ifndef lint
! static char *sccsid = "@(#)version.c	5.2.1 (Berkeley) 11/13/89";
  #endif not lint
  
  /*
***************
*** 20,24 ****
   * Just keep track of the date/sid of this version of Mail.
   * Load this file first to get a "total" Mail version.
   */
! static	char	*SccsID = "@(#)UCB Mail Version 5.2 (6/21/85)";
! char	*version = "5.2 6/21/85";
--- 20,24 ----
   * Just keep track of the date/sid of this version of Mail.
   * Load this file first to get a "total" Mail version.
   */
! static	char	*SccsID = "@(#)UCB Mail Version 5.2.1 (11/13/89)";
! char	*version = "5.2.1 11/13/89";


*** def.h.orig	Fri Dec  9 13:55:23 1988
--- def.h	Mon Nov 13 17:32:54 1989
***************
*** 288,293 ****
--- 288,294 ----
  char	*arpafix();
  char	*calloc();
  char	*copy();
+ char	*do_quoted_string();
  char	*copyin();
  char	*detract();
  char	*expand();
***************
*** 311,316 ****
--- 312,318 ----
  char	*salloc();
  char	*savestr();
  char	*skin();
+ char	*skip_comment();
  char	*snarf();
  char	*strcat();
  char	*strcpy();


*** aux.c.orig	Fri Dec  9 13:55:07 1988
--- aux.c	Mon Nov 13 17:31:09 1989
***************
*** 547,557 ****
  	char *name;
  {
  	register int c;
! 	register char *cp, *cp2;
  	char *bufend;
  	int gotlt, lastsp;
  	char nbuf[BUFSIZ];
- 	int nesting;
  
  	if (name == NOSTR)
  		return(NOSTR);
--- 547,558 ----
  	char *name;
  {
  	register int c;
! 	register char *cp;
! 	char *cp2;
! 	int c2;
  	char *bufend;
  	int gotlt, lastsp;
  	char nbuf[BUFSIZ];
  
  	if (name == NOSTR)
  		return(NOSTR);
***************
*** 564,617 ****
  	for (cp = name, cp2 = bufend; c = *cp++; ) {
  		switch (c) {
  		case '(':
! 			/*
! 			 * Start of a "comment".
! 			 * Ignore it.
! 			 */
! 			nesting = 1;
! 			while ((c = *cp) != 0) {
! 				cp++;
! 				switch (c) {
! 				case '\\':
! 					if (*cp == 0)
! 						goto outcm;
! 					cp++;
! 					break;
! 				case '(':
! 					nesting++;
! 					break;
! 
! 				case ')':
! 					--nesting;
! 					break;
! 				}
! 
! 				if (nesting <= 0)
! 					break;
! 			}
! 		outcm:
  			lastsp = 0;
  			break;
  
  		case '"':
! 			/*
! 			 * Start of a "quoted-string".
! 			 * Copy it in its entirety.
! 			 */
! 			while ((c = *cp) != 0) {
! 				cp++;
! 				switch (c) {
! 				case '\\':
! 					if ((c = *cp) == 0)
! 						goto outqs;
! 					cp++;
! 					break;
! 				case '"':
! 					goto outqs;
! 				}
! 				*cp2++ = c;
! 			}
! 		outqs:
  			lastsp = 0;
  			break;
  
--- 565,576 ----
  	for (cp = name, cp2 = bufend; c = *cp++; ) {
  		switch (c) {
  		case '(':
! 			cp = skip_comment ( cp );
  			lastsp = 0;
  			break;
  
  		case '"':
! 			cp = do_quoted_string ( cp, &cp2 );
  			lastsp = 0;
  			break;
  
***************
*** 634,641 ****
  		case '>':
  			if (gotlt) {
  				gotlt = 0;
! 				while (*cp != ',' && *cp != 0)
! 					cp++;
  				if (*cp == 0 )
  					goto done;
  				*cp2++ = ',';
--- 593,613 ----
  		case '>':
  			if (gotlt) {
  				gotlt = 0;
! 				while (*cp != ',' && *cp != 0) {
! 					c2 = *cp++;
! 					switch ( c2 ) {
! 					case '\\':
! 						if (*cp != '\0') cp++;
! 						break;
! 					case '(':
! 						cp = skip_comment ( cp );
! 						break;
! 			
! 					case '"':
! 						cp = do_quoted_string ( cp, NULL );
! 						break;
! 					}
! 				}
  				if (*cp == 0 )
  					goto done;
  				*cp2++ = ',';
***************
*** 659,664 ****
--- 631,703 ----
  	*cp2 = 0;
  
  	return(savestr(nbuf));
+ }
+ 
+ /*
+  * Start of a "comment".
+  * Ignore it.
+  */
+ char *
+ skip_comment(cp)
+ 	register char *cp;
+ {
+ 	register int c;
+ 	int nesting;
+ 
+ 	nesting = 1;
+ 	while ((c = *cp) != 0) {
+ 		cp++;
+ 		switch (c) {
+ 		case '\\':
+ 			if (*cp == 0)
+ 				return ( cp );
+ 			cp++;
+ 			break;
+ 		case '(':
+ 			nesting++;
+ 			break;
+ 		case ')':
+ 			--nesting;
+ 			break;
+ 		}
+ 		if (nesting <= 0)
+ 			break;
+ 	}
+ 	return ( cp );
+ }
+ 
+ /*
+  * Start of a "quoted-string".
+  * If a target string is given, copy it & advance the pointer;
+  * otherwise, just advance the source pointer.
+  */
+ char *
+ do_quoted_string(cp, cp2p)
+ 	register char *cp;
+ 	char **cp2p;
+ {
+ 	register int c;
+ 
+ 	if ( cp2p != NULL ) printf ( "do_quoted_string: cp2p is not null\n" );
+ 	else printf ( "do_quoted_string: cp2p is null\n" );
+ 
+ 	while ((c = *cp) != 0) {
+ 		cp++;
+ 		switch (c) {
+ 		case '\\':
+ 			if ((c = *cp) == 0)
+ 				return ( cp );
+ 			cp++;
+ 			break;
+ 		case '"':
+ 			return ( cp );
+ 		}
+ 		if ( cp2p != NULL ) {
+ 			**cp2p = c;
+ 			(*cp2p)++;
+ 		}
+ 	}
+ 	return ( cp );
  }
  
  /*