head	1.2;
access;
symbols
	pkgsrc-2018Q1:1.1.0.108
	pkgsrc-2018Q1-base:1.1
	pkgsrc-2017Q4:1.1.0.106
	pkgsrc-2017Q4-base:1.1
	pkgsrc-2017Q3:1.1.0.104
	pkgsrc-2017Q3-base:1.1
	pkgsrc-2017Q2:1.1.0.100
	pkgsrc-2017Q2-base:1.1
	pkgsrc-2017Q1:1.1.0.98
	pkgsrc-2017Q1-base:1.1
	pkgsrc-2016Q4:1.1.0.96
	pkgsrc-2016Q4-base:1.1
	pkgsrc-2016Q3:1.1.0.94
	pkgsrc-2016Q3-base:1.1
	pkgsrc-2016Q2:1.1.0.92
	pkgsrc-2016Q2-base:1.1
	pkgsrc-2016Q1:1.1.0.90
	pkgsrc-2016Q1-base:1.1
	pkgsrc-2015Q4:1.1.0.88
	pkgsrc-2015Q4-base:1.1
	pkgsrc-2015Q3:1.1.0.86
	pkgsrc-2015Q3-base:1.1
	pkgsrc-2015Q2:1.1.0.84
	pkgsrc-2015Q2-base:1.1
	pkgsrc-2015Q1:1.1.0.82
	pkgsrc-2015Q1-base:1.1
	pkgsrc-2014Q4:1.1.0.80
	pkgsrc-2014Q4-base:1.1
	pkgsrc-2014Q3:1.1.0.78
	pkgsrc-2014Q3-base:1.1
	pkgsrc-2014Q2:1.1.0.76
	pkgsrc-2014Q2-base:1.1
	pkgsrc-2014Q1:1.1.0.74
	pkgsrc-2014Q1-base:1.1
	pkgsrc-2013Q4:1.1.0.72
	pkgsrc-2013Q4-base:1.1
	pkgsrc-2013Q3:1.1.0.70
	pkgsrc-2013Q3-base:1.1
	pkgsrc-2013Q2:1.1.0.68
	pkgsrc-2013Q2-base:1.1
	pkgsrc-2013Q1:1.1.0.66
	pkgsrc-2013Q1-base:1.1
	pkgsrc-2012Q4:1.1.0.64
	pkgsrc-2012Q4-base:1.1
	pkgsrc-2012Q3:1.1.0.62
	pkgsrc-2012Q3-base:1.1
	pkgsrc-2012Q2:1.1.0.60
	pkgsrc-2012Q2-base:1.1
	pkgsrc-2012Q1:1.1.0.58
	pkgsrc-2012Q1-base:1.1
	pkgsrc-2011Q4:1.1.0.56
	pkgsrc-2011Q4-base:1.1
	pkgsrc-2011Q3:1.1.0.54
	pkgsrc-2011Q3-base:1.1
	pkgsrc-2011Q2:1.1.0.52
	pkgsrc-2011Q2-base:1.1
	pkgsrc-2011Q1:1.1.0.50
	pkgsrc-2011Q1-base:1.1
	pkgsrc-2010Q4:1.1.0.48
	pkgsrc-2010Q4-base:1.1
	pkgsrc-2010Q3:1.1.0.46
	pkgsrc-2010Q3-base:1.1
	pkgsrc-2010Q2:1.1.0.44
	pkgsrc-2010Q2-base:1.1
	pkgsrc-2010Q1:1.1.0.42
	pkgsrc-2010Q1-base:1.1
	pkgsrc-2009Q4:1.1.0.40
	pkgsrc-2009Q4-base:1.1
	pkgsrc-2009Q3:1.1.0.38
	pkgsrc-2009Q3-base:1.1
	pkgsrc-2009Q2:1.1.0.36
	pkgsrc-2009Q2-base:1.1
	pkgsrc-2009Q1:1.1.0.34
	pkgsrc-2009Q1-base:1.1
	pkgsrc-2008Q4:1.1.0.32
	pkgsrc-2008Q4-base:1.1
	pkgsrc-2008Q3:1.1.0.30
	pkgsrc-2008Q3-base:1.1
	cube-native-xorg:1.1.0.28
	cube-native-xorg-base:1.1
	pkgsrc-2008Q2:1.1.0.26
	pkgsrc-2008Q2-base:1.1
	cwrapper:1.1.0.24
	pkgsrc-2008Q1:1.1.0.22
	pkgsrc-2008Q1-base:1.1
	pkgsrc-2007Q4:1.1.0.20
	pkgsrc-2007Q4-base:1.1
	pkgsrc-2007Q3:1.1.0.18
	pkgsrc-2007Q3-base:1.1
	pkgsrc-2007Q2:1.1.0.16
	pkgsrc-2007Q2-base:1.1
	pkgsrc-2007Q1:1.1.0.14
	pkgsrc-2007Q1-base:1.1
	pkgsrc-2006Q4:1.1.0.12
	pkgsrc-2006Q4-base:1.1
	pkgsrc-2006Q3:1.1.0.10
	pkgsrc-2006Q3-base:1.1
	pkgsrc-2006Q2:1.1.0.8
	pkgsrc-2006Q2-base:1.1
	pkgsrc-2006Q1:1.1.0.6
	pkgsrc-2006Q1-base:1.1
	pkgsrc-2005Q4:1.1.0.4
	pkgsrc-2005Q4-base:1.1
	pkgsrc-2005Q3:1.1.0.2;
locks; strict;
comment	@# @;


1.2
date	2018.06.24.16.54.59;	author adam;	state dead;
branches;
next	1.1;
commitid	gko1QjdfYW8xtyHA;

1.1
date	2005.11.03.15.51.59;	author salo;	state Exp;
branches
	1.1.2.1;
next	;

1.1.2.1
date	2005.11.03.15.51.59;	author snj;	state dead;
branches;
next	1.1.2.2;

1.1.2.2
date	2005.11.05.17.25.26;	author snj;	state Exp;
branches;
next	;


desc
@@


1.2
log
@libwww: updated to 5.4.2

5.4.2:
Unknown changes.

Changes with libwww 5.4.1
* Removed the expat source code in favor of linking against
the global system expat library to avoid having to track
security advisories in that library
* Updated expat to 2.2.0
* Updated autotools to the current versions
* Library/src/HTSQL.c: add missing mysql_init to HTSQL_connect reported by Xavier Torne
* configure.ac, Library/src/Makefile.am, Library/cvs2sql/Makefile.am,
  Robot/src/Makefile.am:
  modify configure scripts for mysql_config based autoconf processing
* Library/src/HTSQL.c, Library/src/HTSQL.html, Library/src/HTSQLLog.c: remove
  mysql directory from include directiv
* Robot/src/RobotMain.c: added flag MR_KEEP_META for -lm last modified option
  detected by Jan Hutaø
* Robot/src/RobotMain.c: added flag MR_KEEP_META for -title option
  detected by Jan Hutaø
* close leak in HTBound process_boundary() detected by Sam Varshavchik
  using valgrind; excised old #if 0 snippets from HTMIME.c
* Library/src/HTCookie.c: add private function HTCookie_splitPair to
  split a KEY=VALUE pair, from Jesse Morgan
* configure.ac: remove unecessary check for appkit.h as
  suggested by Roger Persson
* Library/src/wwwsys.html: change genuine angle bracket characters
  into the angle bracket entities, thanks to Bobby Jack
* Library/src/HT*.html, Library/src/SSL/HT*.html: wrap
  all header files with extern "C"
* Library/src/HTFile, configure.ac: add a basis for
  addressing Ben's security concerns
* Library/src/HTBound.c: libwww security advisory fix from
  Sam Varshavchik, fix double-counting of processed bytes,
  rewrote HTBoundary_put_block, to fix problematic HTTP 1.1
  byte range requests
* Library/src/: HTAlert.c, HTHeader.c, HTInit.c, HTNet.c,
  HTProfil.c, HTProt.c, HTTrans.c: Patch to greatly speed up
  repeated requests, from Arthur Smith
* Library/src/HTSQL.c: modifications to compile without using
  deprecated mysql functions
* config/: config.sub, ltmain.sh: updates for recent version of
  libtool
* INSTALL.html, Library/src/HTEvtLst.c: cleaning
* libwww-config.in: include -lwwwssl, thanks to mgoddard at
  itgs-presearch.com
* Library/src/SSL/HTSSLWriter.c: avoids an eternal loop in libwww
* Library/src/SSL/HTSSL.html, Robot/src/RobotMain.c: fix for webbot
  -v option check and documentation addition
* configure.ac, Library/src/SSL/HTSSL.c,
  Library/src/SSL/windows/wwwssl.def, Robot/src/HTRobMan.html,
  Robot/src/Makefile.am, Robot/src/RobotMain.c: basic support for
  client side certificates using PEM format
* Library/src/SSL/: HTSSL.c, HTSSLReader.c, HTSSLWriter.c: add
  openssl to include for ssl.h and rand.h
* config/: config.guess, config.sub, ltmain.sh: update after
  running libtoolize
* Robot/src/Makefile.am: use SSL directory for libwwwssl.la
* Robot/src/RobotMain.c: include HTSSL.h
* configure.ac: fix aclocal underquoting warnings
* Robot/src/: RobotMain.c, Makefile.am: update to enable https
  protocol
* Library/src/HTTPReq.c: fixed , to _ in HTTRACE call
* Library/src/HTTPReq.c: removed LIBWWW_USEIDN, because unnecessary
* modules/idn/unicode_template.c: forgot one file
* Library/src/HTDNS.html: moved IDN to main branch
* Library/src/HTDNS.c: moved IDN to main branch
* Library/src/HTTPReq.c: added "LIBWWW_USEIDN" conditional
* Library/src/HTTPReq.c: moved IDN to main branch
* Library/Overview.html: JK: Added the libwww survey results
@
text
@$NetBSD: patch-ap,v 1.1 2005/11/03 15:51:59 salo Exp $

--- Library/src/HTBound.c.orig	1999-02-22 23:10:10.000000000 +0100
+++ Library/src/HTBound.c	2005-11-03 16:43:25.000000000 +0100
@@@@ -11,9 +11,12 @@@@
 **
 ** Authors
 **	HF	Henrik Frystyk <frystyk@@w3.org>
+**      SV      Sam Varshavchik <mrsam@@courier-mta.com>
 **
 ** History:
 **	Nov 95	Written from scratch
+**   SV Jun 05  Rewrote HTBoundary_put_block.  Fixed many bugs+segfaults.
+**   SV Jul 05  Fix double-counting of processed bytes.
 **
 */
 
@@@@ -23,104 +26,395 @@@@
 #include "WWWCore.h"
 #include "HTMerge.h"
 #include "HTReqMan.h"
+#include "HTNetMan.h"
+#include "HTChannl.h"
 #include "HTBound.h"					 /* Implemented here */
 
-#define PUTBLOCK(b, l)	(*me->target->isa->put_block)(me->target, b, l)
+#define PUTBLOCK(b, l)	(me->target ? (*me->target->isa->put_block)(me->target, b, l):HT_OK)
+
 #define PUTDEBUG(b, l)	(*me->debug->isa->put_block)(me->debug, b, l)
 #define FREE_TARGET	(*me->target->isa->_free)(me->target)
 
 struct _HTStream {
     const HTStreamClass *	isa;
+    HTNet *                      net;
     HTStream *			target;
     HTStream *			orig_target;
     HTFormat			format;
     HTStream *			debug;		  /* For preamble and epilog */
     HTRequest *			request;
-    BOOL			body;		  /* Body or preamble|epilog */
-    HTEOLState			state;
-    int				dash;			 /* Number of dashes */
     char *			boundary;
-    char *			bpos;
+
+    BOOL                        keptcrlf;
+    int                         (*state)(HTStream *, const char *, int);
+
+    char                        *boundary_ptr;
+
 };
 
+PRIVATE int HTBoundary_flush (HTStream * me);
+
 /* ------------------------------------------------------------------------- */
 
+PRIVATE int start_of_line (HTStream * me, const char * b, int l);
+PRIVATE int seen_dash (HTStream * me, const char * b, int l);
+PRIVATE int seen_doubledash (HTStream * me, const char * b, int l);
+PRIVATE int seen_delimiter_nonterminal(HTStream * me, const char * b, int l);
+PRIVATE int seen_delimiter_nonterminal_CR(HTStream * me, const char * b, int l);
+PRIVATE int seen_delimiter_dash(HTStream * me, const char * b, int l);
+PRIVATE int seen_delimiter_terminal(HTStream * me, const char * b, int l);
+PRIVATE int seen_delimiter_terminal_CR(HTStream * me, const char * b, int l);
+PRIVATE int not_delimiter(HTStream * me, const char * b, int l, int extra);
+PRIVATE int seen_nothing(HTStream * me, const char * b, int l);
+PRIVATE int seen_cr(HTStream * me, const char * b, int l);
+PRIVATE void process_boundary(HTStream *me, int isterminal);
+
+#define UNUSED(l) (l=l)    /* Shut up about unused variables */
+
 PRIVATE int HTBoundary_put_block (HTStream * me, const char * b, int l)
 {
-    const char *start = b;
-    const char *end = b;
-    while (l-- > 0) {
-	if (me->state == EOL_FCR) {
-	    me->state = (*b == LF) ? EOL_FLF : EOL_BEGIN;
-	} else if (me->state == EOL_FLF) {
-	    if (me->dash == 2) {
-		while (l>0 && *me->bpos && *me->bpos==*b) l--, me->bpos++, b++;
-		if (!*me->bpos) {
-		    HTTRACE(STREAM_TRACE, "Boundary.... `%s\' found\n" _ me->boundary);
-		    me->bpos = me->boundary;
-		    me->body = YES;
-		    me->state = EOL_DOT;
-		} else if (l>0) {
-		    me->dash = 0;
-		    me->bpos = me->boundary;
-		    me->state = EOL_BEGIN;
-		}
-	    }
-	    if (*b == '-') {
-		me->dash++;
-	    } else if (*b != CR && *b != LF) {
-		me->dash = 0;
-		me->state = EOL_BEGIN;
-	    }
-	} else if (me->state == EOL_SLF) {	    /* Look for closing '--' */
-	    if (me->dash == 4) {
-		if (end > start) {
-		    int status = PUTBLOCK(start, end-start);
-		    if (status != HT_OK) return status;
-		}
-		HTTRACE(STREAM_TRACE, "Boundary.... Ending\n");
-		start = b;
-		me->dash = 0;
-		me->state = EOL_BEGIN;
-	    }
-	    if (*b == '-') {
-		me->dash++;
-	    } else if (*b != CR && *b != LF) {
-		me->dash = 0;
-		me->state = EOL_BEGIN;
-	    }
-	    me->body = NO;
-	} else if (me->state == EOL_DOT) {
-	    int status;
-	    if (me->body) {
-		if (me->target) FREE_TARGET;
-		me->target = HTStreamStack(WWW_MIME,me->format,
-					   HTMerge(me->orig_target, 2),
-					   me->request, YES);
-		if (end > start) {
-		    if ((status = PUTBLOCK(start, end-start)) != HT_OK)
-			return status;
+	/*
+	** The HTBoundary object gets attached downstream of HTMime.
+	** The HTBoundary object creates another HTMime object downstream of
+	** the HTBoundary object.
+	**
+	** When we push data downstream to the second HTBoundary object, it
+	** updates the bytes read count in the HTNet object.
+	**
+	** When we return to the parent HTMime object, itupdates the
+	** bytes read count in the HTNet object again.  Oops.
+	**
+	** Same thing happens with the consumed byte count.  We can prevent
+	** the consumed byte counts from being updated by temporary setting
+	** the input channel stream pointer to NULL, but for the byte counts
+	** we have to save them and restore them before existing.
+	**
+	** This bug was discovered by chance when a multipart/partial response
+	** was partially received, and as a result of double-counting the
+	** real response got cut off (because HTMime thought that more bytes
+	** were processed than actually were, thus it processed only the
+	** partial count of the remaining bytes in the response).  When the
+	** multipart/partial response was received all at once this bug did
+	** not get triggered.
+	*/
+
+	HTHost *host=HTNet_host(me->net);
+	HTChannel *c=HTHost_channel(host);
+	HTInputStream *i=HTChannel_input(c);
+
+	long saveBytesRead=HTNet_bytesRead(me->net);
+	long saveHeaderBytesRead=HTNet_headerBytesRead(me->net);
+
+	if (i)
+		HTChannel_setInput(c, NULL);
+
+	HTTRACE(STREAM_TRACE, "Boundary: processing %d bytes\n" _ l);
+	/* Main loop consumes all input */
+
+	while (l)
+	{
+		int n= (*me->state)(me, b, l);
+
+		if (n == 0)
+			return HT_ERROR;
+		b += n;
+		l -= n;
+	}
+
+	if (i)
+		HTChannel_setInput(c, i);
+	HTNet_setBytesRead(me->net, saveBytesRead);
+	HTNet_setHeaderBytesRead(me->net, saveHeaderBytesRead);
+
+	return HT_OK;
+}
+
+/*
+** Start of line, keptcrlf=YES if we've kept the preceding CRLF from downstream
+** and we'll pass it along if we decide that this is not a boundary delimiter.
+*/
+
+PRIVATE int start_of_line (HTStream * me, const char * b, int l)
+{
+	if (*b != '-')
+		return not_delimiter(me, b, l, 0);
+
+	HTTRACE(STREAM_TRACE, "Boundary: start of line: input '-'\n");
+
+	me->state= seen_dash;
+
+	return 1;
+}
+
+/*
+** Line: -
+*/
+
+PRIVATE int seen_dash (HTStream * me, const char * b, int l)
+{
+	if (*b != '-')
+		return not_delimiter(me, b, l, 1);
+
+	HTTRACE(STREAM_TRACE, "Boundary: start of line: input '--'\n");
+
+	me->state= seen_doubledash;
+	me->boundary_ptr=me->boundary;
+	return 1;
+}
+
+/*
+** Line: --
+*/
+
+PRIVATE int seen_doubledash (HTStream * me, const char * b, int l)
+{
+	me->state=seen_doubledash;
+
+	if (*me->boundary_ptr)
+	{
+		if (*b != *me->boundary_ptr)
+		{
+			return not_delimiter(me, b, l,
+					     me->boundary_ptr - me->boundary
+					     + 2);
 		}
-	    } else {
-		if (me->debug)
-		    if ((status = PUTDEBUG(start, end-start)) != HT_OK)
-			return status;
+		++me->boundary_ptr;
+		return 1;
 	    }
-	    start = b;
-	    if (*b == '-') me->dash++;
-	    me->state = EOL_SLF;
-	} else if (*b == CR) {
-	    me->state = EOL_FCR;
-	    end = b;
-	} else if (*b == LF) {
-	    if (me->state != EOL_FCR) end = b;
-	    me->state = EOL_FLF;
+
+	/*
+	** Line: --delimiter
+	*/
+
+	if (*b == '-')
+	{
+		HTTRACE(STREAM_TRACE,
+			"Boundary: start of line: input '--%s-'\n"
+			_ me->boundary);
+
+		me->state=seen_delimiter_dash;
+		return 1;
 	}
-	b++;
+
+	HTTRACE(STREAM_TRACE,
+		"Boundary: Found: '--%s'\n" _ me->boundary);
+	
+	return seen_delimiter_nonterminal(me, b, l);
+}
+
+/*
+** Line: --delimiter
+**
+** Waiting for CRLF.
+*/
+
+
+PRIVATE int seen_delimiter_nonterminal(HTStream * me, const char * b, int l)
+{
+	UNUSED(l);
+
+	me->state=seen_delimiter_nonterminal;
+	if (*b == CR)
+		me->state=seen_delimiter_nonterminal_CR;
+
+	return 1;
+}
+
+/*
+** Line: --delimiter<CR>
+*/
+
+PRIVATE int seen_delimiter_nonterminal_CR(HTStream * me, const char * b, int l)
+{
+	HTTRACE(STREAM_TRACE,
+		"Boundary: Found: '--%s<CR>'\n" _ me->boundary);
+	
+	if (*b != LF)
+		return seen_delimiter_nonterminal(me, b, l);
+
+	HTTRACE(STREAM_TRACE,
+		"Boundary: Found: '--%s<CR><LF>'\n" _ me->boundary);
+	
+	process_boundary(me, NO);
+	return 1;
+}
+
+/*
+** Line: --delimiter-
+*/
+
+PRIVATE int seen_delimiter_dash(HTStream * me, const char * b, int l)
+{
+	if (*b != '-')
+		return seen_delimiter_nonterminal(me, b, l);
+
+	HTTRACE(STREAM_TRACE,
+		"Boundary: start of line: input '--%s--'\n"
+		_ me->boundary);
+	
+	me->state=seen_delimiter_terminal;
+	return 1;
+}
+
+/*
+** Line: --delimiter--
+*/
+
+PRIVATE int seen_delimiter_terminal(HTStream * me, const char * b, int l)
+{
+	UNUSED(l);
+
+	me->state=seen_delimiter_terminal;
+
+	if (*b == CR)
+		me->state=seen_delimiter_terminal_CR;
+	return 1;
+}
+/*
+** Line: --delimiter--<CR>
+*/
+
+PRIVATE int seen_delimiter_terminal_CR(HTStream * me, const char * b, int l)
+{
+	HTTRACE(STREAM_TRACE,
+		"Boundary: Found '--%s--<CR>'\n"
+		_ me->boundary);
+	
+	if (*b != LF)
+		return seen_delimiter_terminal(me, b, l);
+	HTTRACE(STREAM_TRACE,
+		"Boundary: Found '--%s--<CR><LF>'\n"
+		_ me->boundary);
+	
+	process_boundary(me, YES);
+	return 1;
+}
+
+/*
+** Beginning of the line does not contain a delimiter.
+**
+**
+** extra: Count of characters in a partially matched delimiter.  Since it's
+** not a delimiter this is content that needs to go downstream.
+*/
+
+PRIVATE int not_delimiter(HTStream * me, const char * b, int l, int extra)
+{
+	HTTRACE(STREAM_TRACE, "Boundary: not a delimiter line\n");
+	
+	if (me->keptcrlf)
+	{
+		HTTRACE(STREAM_TRACE, "Boundary: Sending previous line's <CR><LF>\n");
+		/*
+		** Did not process CRLF from previous line, because prev CRLF
+		** is considered a part of the delimiter.  See MIME RFC.
+		*/
+
+		me->keptcrlf=NO;
+		if (PUTBLOCK("\r\n", 2) != HT_OK)
+			return 0;
+	}
+
+	/*
+	** Potentially matched some of: --DELIMITER
+	*/
+
+	if (extra)
+	{
+		HTTRACE(STREAM_TRACE, "Boundary: Sending partially-matched %d characters\n" _ extra);
+
+		if (PUTBLOCK("--", extra > 2 ? 2:extra) != HT_OK)
+			return 0;
+
+		if (extra > 2)
+			if (PUTBLOCK(me->boundary, extra-2) != HT_OK)
+				return 0;
+	}
+	return seen_nothing(me, b, l);
+}
+
+/*
+** We're not looking for a delimiter.  Look for the next line of input
+** in the data that could potentially be a delimiter.
+*/
+
+PRIVATE int seen_nothing(HTStream * me, const char * b, int l)
+{
+	int i;
+
+	me->state=seen_nothing;
+
+	for (i=0; i<l; i++)
+	{
+		if (b[i] != CR)
+			continue;
+
+		/*
+		** If we have at least four more characters in unconsumed
+		** input, and they're not \r\n--, we can safely skip over
+		** them.
+		*/
+
+		if (l-i > 4 &&
+		    strncmp(b+i, "\r\n--", 4))
+			continue;
+		break;
+	}
+
+	if (i == 0)
+	{
+		/* Could only be a CR here. */
+
+		me->state=seen_cr;
+		return 1;
+	}
+
+	HTTRACE(STREAM_TRACE, "Boundary: Processed %d (out of %d) bytes\n"
+		_ i _ l);
+
+	if (PUTBLOCK(b, i) != HT_OK)
+		return 0;
+
+	return i;
+}
+
+/*
+** State: seen a CR
+*/
+
+PRIVATE int seen_cr(HTStream * me, const char * b, int l)
+{
+	HTTRACE(STREAM_TRACE, "Boundary: Processed <CR>\n");
+
+	if (*b != LF)
+	{
+		HTTRACE(STREAM_TRACE, "Boundary: ... <LF> didn't follow\n");
+		if (PUTBLOCK("\r", 1) != HT_OK)
+			return 0;
+		return seen_nothing(me, b, l);
     }
-    return (start<b && me->body) ? PUTBLOCK(start, b-start) : HT_OK;
+
+	HTTRACE(STREAM_TRACE, "Boundary: Processed <CR><LF>\n");
+	me->state=start_of_line;
+	me->keptcrlf=YES;
+	return 1;
+}
+
+PRIVATE void process_boundary(HTStream *me, int isterminal)
+{
+	HTBoundary_flush(me);
+	if (me->target) FREE_TARGET;
+	me->target=NULL;
+	me->state=start_of_line;
+	me->keptcrlf=NO;
+
+	if (!isterminal)
+		me->target = HTStreamStack(WWW_MIME,me->format,
+					   HTMerge(me->orig_target, 2),
+					   me->request, YES);
 }
 
+
 PRIVATE int HTBoundary_put_string (HTStream * me, const char * s)
 {
     return HTBoundary_put_block(me, s, (int) strlen(s));
@@@@ -133,6 +427,8 @@@@
 
 PRIVATE int HTBoundary_flush (HTStream * me)
 {
+	if (me->target == NULL)
+		return HT_OK;
     return (*me->target->isa->flush)(me->target);
 }
 
@@@@ -182,18 +478,26 @@@@
 	HTResponse_formatParam(response) :
 	HTAnchor_formatParam(anchor);
     char * boundary = HTAssocList_findObject(type_param, "boundary");
+
+    UNUSED(param);
+    UNUSED(input_format);
+
     if (boundary) {
 	HTStream * me;
 	if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
 	    HT_OUTOFMEM("HTBoundary");
 	me->isa = &HTBoundaryClass;
+	me->net = HTRequest_net(request);
 	me->request = request;
 	me->format = output_format;
 	me->orig_target = output_stream;
 	me->debug = HTRequest_debugStream(request);
-	me->state = EOL_FLF;
+
+	me->state = start_of_line;
+	me->keptcrlf=NO;
+
 	StrAllocCopy(me->boundary, boundary);		       /* Local copy */
-	me->bpos = me->boundary;
+
 	HTTRACE(STREAM_TRACE, "Boundary.... Stream created with boundary '%s\'\n" _ me->boundary);
 	return me;
     } else {
@


1.1
log
@Security fix for SA17119:

"A vulnerability was found in W3C Libwww, which potentially can be exploited
by malicious people to cause a DoS (Denial of Service).

The vulnerability is caused due to a boundary error in the
"HTBoundary_put_block()" function when processing multipart MIME data. This
may be exploited to cause an illegal memory access past the end of the input
buffer via specially crafted multipart MIME data.

Successful exploitation can potentially cause an application that uses Libwww
to crash."

http://secunia.com/advisories/17119/
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=159597

Bump PKGREVISION.
Patch from RedHat.
@
text
@d1 1
a1 1
$NetBSD$
@


1.1.2.1
log
@file patch-ap was added on branch pkgsrc-2005Q3 on 2005-11-03 15:51:59 +0000
@
text
@d1 524
@


1.1.2.2
log
@Pullup ticket 886 - requested by Lubomir Sedlacik
security fix for libwww

Revisions pulled up:
- pkgsrc/www/libwww/Makefile		1.62
- pkgsrc/www/libwww/distinfo		1.21
- pkgsrc/www/libwww/patches/patch-ap	1.1

   Module Name:    pkgsrc
   Committed By:   salo
   Date:           Thu Nov  3 15:51:59 UTC 2005

   Modified Files:
           pkgsrc/www/libwww: Makefile distinfo
   Added Files:
           pkgsrc/www/libwww/patches: patch-ap

   Log Message:
   Security fix for SA17119:

   "A vulnerability was found in W3C Libwww, which potentially can be
   exploited by malicious people to cause a DoS (Denial of Service).

   The vulnerability is caused due to a boundary error in the
   "HTBoundary_put_block()" function when processing multipart MIME data.
   This may be exploited to cause an illegal memory access past the end of
   the input buffer via specially crafted multipart MIME data.

   Successful exploitation can potentially cause an application that uses
   Libwww to crash."

   http://secunia.com/advisories/17119/
   https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=159597

   Bump PKGREVISION.
   Patch from RedHat.
@
text
@a0 524
$NetBSD: patch-ap,v 1.1.2.1 2005/11/05 17:25:26 snj Exp $

--- Library/src/HTBound.c.orig	1999-02-22 23:10:10.000000000 +0100
+++ Library/src/HTBound.c	2005-11-03 16:43:25.000000000 +0100
@@@@ -11,9 +11,12 @@@@
 **
 ** Authors
 **	HF	Henrik Frystyk <frystyk@@w3.org>
+**      SV      Sam Varshavchik <mrsam@@courier-mta.com>
 **
 ** History:
 **	Nov 95	Written from scratch
+**   SV Jun 05  Rewrote HTBoundary_put_block.  Fixed many bugs+segfaults.
+**   SV Jul 05  Fix double-counting of processed bytes.
 **
 */
 
@@@@ -23,104 +26,395 @@@@
 #include "WWWCore.h"
 #include "HTMerge.h"
 #include "HTReqMan.h"
+#include "HTNetMan.h"
+#include "HTChannl.h"
 #include "HTBound.h"					 /* Implemented here */
 
-#define PUTBLOCK(b, l)	(*me->target->isa->put_block)(me->target, b, l)
+#define PUTBLOCK(b, l)	(me->target ? (*me->target->isa->put_block)(me->target, b, l):HT_OK)
+
 #define PUTDEBUG(b, l)	(*me->debug->isa->put_block)(me->debug, b, l)
 #define FREE_TARGET	(*me->target->isa->_free)(me->target)
 
 struct _HTStream {
     const HTStreamClass *	isa;
+    HTNet *                      net;
     HTStream *			target;
     HTStream *			orig_target;
     HTFormat			format;
     HTStream *			debug;		  /* For preamble and epilog */
     HTRequest *			request;
-    BOOL			body;		  /* Body or preamble|epilog */
-    HTEOLState			state;
-    int				dash;			 /* Number of dashes */
     char *			boundary;
-    char *			bpos;
+
+    BOOL                        keptcrlf;
+    int                         (*state)(HTStream *, const char *, int);
+
+    char                        *boundary_ptr;
+
 };
 
+PRIVATE int HTBoundary_flush (HTStream * me);
+
 /* ------------------------------------------------------------------------- */
 
+PRIVATE int start_of_line (HTStream * me, const char * b, int l);
+PRIVATE int seen_dash (HTStream * me, const char * b, int l);
+PRIVATE int seen_doubledash (HTStream * me, const char * b, int l);
+PRIVATE int seen_delimiter_nonterminal(HTStream * me, const char * b, int l);
+PRIVATE int seen_delimiter_nonterminal_CR(HTStream * me, const char * b, int l);
+PRIVATE int seen_delimiter_dash(HTStream * me, const char * b, int l);
+PRIVATE int seen_delimiter_terminal(HTStream * me, const char * b, int l);
+PRIVATE int seen_delimiter_terminal_CR(HTStream * me, const char * b, int l);
+PRIVATE int not_delimiter(HTStream * me, const char * b, int l, int extra);
+PRIVATE int seen_nothing(HTStream * me, const char * b, int l);
+PRIVATE int seen_cr(HTStream * me, const char * b, int l);
+PRIVATE void process_boundary(HTStream *me, int isterminal);
+
+#define UNUSED(l) (l=l)    /* Shut up about unused variables */
+
 PRIVATE int HTBoundary_put_block (HTStream * me, const char * b, int l)
 {
-    const char *start = b;
-    const char *end = b;
-    while (l-- > 0) {
-	if (me->state == EOL_FCR) {
-	    me->state = (*b == LF) ? EOL_FLF : EOL_BEGIN;
-	} else if (me->state == EOL_FLF) {
-	    if (me->dash == 2) {
-		while (l>0 && *me->bpos && *me->bpos==*b) l--, me->bpos++, b++;
-		if (!*me->bpos) {
-		    HTTRACE(STREAM_TRACE, "Boundary.... `%s\' found\n" _ me->boundary);
-		    me->bpos = me->boundary;
-		    me->body = YES;
-		    me->state = EOL_DOT;
-		} else if (l>0) {
-		    me->dash = 0;
-		    me->bpos = me->boundary;
-		    me->state = EOL_BEGIN;
-		}
-	    }
-	    if (*b == '-') {
-		me->dash++;
-	    } else if (*b != CR && *b != LF) {
-		me->dash = 0;
-		me->state = EOL_BEGIN;
-	    }
-	} else if (me->state == EOL_SLF) {	    /* Look for closing '--' */
-	    if (me->dash == 4) {
-		if (end > start) {
-		    int status = PUTBLOCK(start, end-start);
-		    if (status != HT_OK) return status;
-		}
-		HTTRACE(STREAM_TRACE, "Boundary.... Ending\n");
-		start = b;
-		me->dash = 0;
-		me->state = EOL_BEGIN;
-	    }
-	    if (*b == '-') {
-		me->dash++;
-	    } else if (*b != CR && *b != LF) {
-		me->dash = 0;
-		me->state = EOL_BEGIN;
-	    }
-	    me->body = NO;
-	} else if (me->state == EOL_DOT) {
-	    int status;
-	    if (me->body) {
-		if (me->target) FREE_TARGET;
-		me->target = HTStreamStack(WWW_MIME,me->format,
-					   HTMerge(me->orig_target, 2),
-					   me->request, YES);
-		if (end > start) {
-		    if ((status = PUTBLOCK(start, end-start)) != HT_OK)
-			return status;
+	/*
+	** The HTBoundary object gets attached downstream of HTMime.
+	** The HTBoundary object creates another HTMime object downstream of
+	** the HTBoundary object.
+	**
+	** When we push data downstream to the second HTBoundary object, it
+	** updates the bytes read count in the HTNet object.
+	**
+	** When we return to the parent HTMime object, itupdates the
+	** bytes read count in the HTNet object again.  Oops.
+	**
+	** Same thing happens with the consumed byte count.  We can prevent
+	** the consumed byte counts from being updated by temporary setting
+	** the input channel stream pointer to NULL, but for the byte counts
+	** we have to save them and restore them before existing.
+	**
+	** This bug was discovered by chance when a multipart/partial response
+	** was partially received, and as a result of double-counting the
+	** real response got cut off (because HTMime thought that more bytes
+	** were processed than actually were, thus it processed only the
+	** partial count of the remaining bytes in the response).  When the
+	** multipart/partial response was received all at once this bug did
+	** not get triggered.
+	*/
+
+	HTHost *host=HTNet_host(me->net);
+	HTChannel *c=HTHost_channel(host);
+	HTInputStream *i=HTChannel_input(c);
+
+	long saveBytesRead=HTNet_bytesRead(me->net);
+	long saveHeaderBytesRead=HTNet_headerBytesRead(me->net);
+
+	if (i)
+		HTChannel_setInput(c, NULL);
+
+	HTTRACE(STREAM_TRACE, "Boundary: processing %d bytes\n" _ l);
+	/* Main loop consumes all input */
+
+	while (l)
+	{
+		int n= (*me->state)(me, b, l);
+
+		if (n == 0)
+			return HT_ERROR;
+		b += n;
+		l -= n;
+	}
+
+	if (i)
+		HTChannel_setInput(c, i);
+	HTNet_setBytesRead(me->net, saveBytesRead);
+	HTNet_setHeaderBytesRead(me->net, saveHeaderBytesRead);
+
+	return HT_OK;
+}
+
+/*
+** Start of line, keptcrlf=YES if we've kept the preceding CRLF from downstream
+** and we'll pass it along if we decide that this is not a boundary delimiter.
+*/
+
+PRIVATE int start_of_line (HTStream * me, const char * b, int l)
+{
+	if (*b != '-')
+		return not_delimiter(me, b, l, 0);
+
+	HTTRACE(STREAM_TRACE, "Boundary: start of line: input '-'\n");
+
+	me->state= seen_dash;
+
+	return 1;
+}
+
+/*
+** Line: -
+*/
+
+PRIVATE int seen_dash (HTStream * me, const char * b, int l)
+{
+	if (*b != '-')
+		return not_delimiter(me, b, l, 1);
+
+	HTTRACE(STREAM_TRACE, "Boundary: start of line: input '--'\n");
+
+	me->state= seen_doubledash;
+	me->boundary_ptr=me->boundary;
+	return 1;
+}
+
+/*
+** Line: --
+*/
+
+PRIVATE int seen_doubledash (HTStream * me, const char * b, int l)
+{
+	me->state=seen_doubledash;
+
+	if (*me->boundary_ptr)
+	{
+		if (*b != *me->boundary_ptr)
+		{
+			return not_delimiter(me, b, l,
+					     me->boundary_ptr - me->boundary
+					     + 2);
 		}
-	    } else {
-		if (me->debug)
-		    if ((status = PUTDEBUG(start, end-start)) != HT_OK)
-			return status;
+		++me->boundary_ptr;
+		return 1;
 	    }
-	    start = b;
-	    if (*b == '-') me->dash++;
-	    me->state = EOL_SLF;
-	} else if (*b == CR) {
-	    me->state = EOL_FCR;
-	    end = b;
-	} else if (*b == LF) {
-	    if (me->state != EOL_FCR) end = b;
-	    me->state = EOL_FLF;
+
+	/*
+	** Line: --delimiter
+	*/
+
+	if (*b == '-')
+	{
+		HTTRACE(STREAM_TRACE,
+			"Boundary: start of line: input '--%s-'\n"
+			_ me->boundary);
+
+		me->state=seen_delimiter_dash;
+		return 1;
 	}
-	b++;
+
+	HTTRACE(STREAM_TRACE,
+		"Boundary: Found: '--%s'\n" _ me->boundary);
+	
+	return seen_delimiter_nonterminal(me, b, l);
+}
+
+/*
+** Line: --delimiter
+**
+** Waiting for CRLF.
+*/
+
+
+PRIVATE int seen_delimiter_nonterminal(HTStream * me, const char * b, int l)
+{
+	UNUSED(l);
+
+	me->state=seen_delimiter_nonterminal;
+	if (*b == CR)
+		me->state=seen_delimiter_nonterminal_CR;
+
+	return 1;
+}
+
+/*
+** Line: --delimiter<CR>
+*/
+
+PRIVATE int seen_delimiter_nonterminal_CR(HTStream * me, const char * b, int l)
+{
+	HTTRACE(STREAM_TRACE,
+		"Boundary: Found: '--%s<CR>'\n" _ me->boundary);
+	
+	if (*b != LF)
+		return seen_delimiter_nonterminal(me, b, l);
+
+	HTTRACE(STREAM_TRACE,
+		"Boundary: Found: '--%s<CR><LF>'\n" _ me->boundary);
+	
+	process_boundary(me, NO);
+	return 1;
+}
+
+/*
+** Line: --delimiter-
+*/
+
+PRIVATE int seen_delimiter_dash(HTStream * me, const char * b, int l)
+{
+	if (*b != '-')
+		return seen_delimiter_nonterminal(me, b, l);
+
+	HTTRACE(STREAM_TRACE,
+		"Boundary: start of line: input '--%s--'\n"
+		_ me->boundary);
+	
+	me->state=seen_delimiter_terminal;
+	return 1;
+}
+
+/*
+** Line: --delimiter--
+*/
+
+PRIVATE int seen_delimiter_terminal(HTStream * me, const char * b, int l)
+{
+	UNUSED(l);
+
+	me->state=seen_delimiter_terminal;
+
+	if (*b == CR)
+		me->state=seen_delimiter_terminal_CR;
+	return 1;
+}
+/*
+** Line: --delimiter--<CR>
+*/
+
+PRIVATE int seen_delimiter_terminal_CR(HTStream * me, const char * b, int l)
+{
+	HTTRACE(STREAM_TRACE,
+		"Boundary: Found '--%s--<CR>'\n"
+		_ me->boundary);
+	
+	if (*b != LF)
+		return seen_delimiter_terminal(me, b, l);
+	HTTRACE(STREAM_TRACE,
+		"Boundary: Found '--%s--<CR><LF>'\n"
+		_ me->boundary);
+	
+	process_boundary(me, YES);
+	return 1;
+}
+
+/*
+** Beginning of the line does not contain a delimiter.
+**
+**
+** extra: Count of characters in a partially matched delimiter.  Since it's
+** not a delimiter this is content that needs to go downstream.
+*/
+
+PRIVATE int not_delimiter(HTStream * me, const char * b, int l, int extra)
+{
+	HTTRACE(STREAM_TRACE, "Boundary: not a delimiter line\n");
+	
+	if (me->keptcrlf)
+	{
+		HTTRACE(STREAM_TRACE, "Boundary: Sending previous line's <CR><LF>\n");
+		/*
+		** Did not process CRLF from previous line, because prev CRLF
+		** is considered a part of the delimiter.  See MIME RFC.
+		*/
+
+		me->keptcrlf=NO;
+		if (PUTBLOCK("\r\n", 2) != HT_OK)
+			return 0;
+	}
+
+	/*
+	** Potentially matched some of: --DELIMITER
+	*/
+
+	if (extra)
+	{
+		HTTRACE(STREAM_TRACE, "Boundary: Sending partially-matched %d characters\n" _ extra);
+
+		if (PUTBLOCK("--", extra > 2 ? 2:extra) != HT_OK)
+			return 0;
+
+		if (extra > 2)
+			if (PUTBLOCK(me->boundary, extra-2) != HT_OK)
+				return 0;
+	}
+	return seen_nothing(me, b, l);
+}
+
+/*
+** We're not looking for a delimiter.  Look for the next line of input
+** in the data that could potentially be a delimiter.
+*/
+
+PRIVATE int seen_nothing(HTStream * me, const char * b, int l)
+{
+	int i;
+
+	me->state=seen_nothing;
+
+	for (i=0; i<l; i++)
+	{
+		if (b[i] != CR)
+			continue;
+
+		/*
+		** If we have at least four more characters in unconsumed
+		** input, and they're not \r\n--, we can safely skip over
+		** them.
+		*/
+
+		if (l-i > 4 &&
+		    strncmp(b+i, "\r\n--", 4))
+			continue;
+		break;
+	}
+
+	if (i == 0)
+	{
+		/* Could only be a CR here. */
+
+		me->state=seen_cr;
+		return 1;
+	}
+
+	HTTRACE(STREAM_TRACE, "Boundary: Processed %d (out of %d) bytes\n"
+		_ i _ l);
+
+	if (PUTBLOCK(b, i) != HT_OK)
+		return 0;
+
+	return i;
+}
+
+/*
+** State: seen a CR
+*/
+
+PRIVATE int seen_cr(HTStream * me, const char * b, int l)
+{
+	HTTRACE(STREAM_TRACE, "Boundary: Processed <CR>\n");
+
+	if (*b != LF)
+	{
+		HTTRACE(STREAM_TRACE, "Boundary: ... <LF> didn't follow\n");
+		if (PUTBLOCK("\r", 1) != HT_OK)
+			return 0;
+		return seen_nothing(me, b, l);
     }
-    return (start<b && me->body) ? PUTBLOCK(start, b-start) : HT_OK;
+
+	HTTRACE(STREAM_TRACE, "Boundary: Processed <CR><LF>\n");
+	me->state=start_of_line;
+	me->keptcrlf=YES;
+	return 1;
+}
+
+PRIVATE void process_boundary(HTStream *me, int isterminal)
+{
+	HTBoundary_flush(me);
+	if (me->target) FREE_TARGET;
+	me->target=NULL;
+	me->state=start_of_line;
+	me->keptcrlf=NO;
+
+	if (!isterminal)
+		me->target = HTStreamStack(WWW_MIME,me->format,
+					   HTMerge(me->orig_target, 2),
+					   me->request, YES);
 }
 
+
 PRIVATE int HTBoundary_put_string (HTStream * me, const char * s)
 {
     return HTBoundary_put_block(me, s, (int) strlen(s));
@@@@ -133,6 +427,8 @@@@
 
 PRIVATE int HTBoundary_flush (HTStream * me)
 {
+	if (me->target == NULL)
+		return HT_OK;
     return (*me->target->isa->flush)(me->target);
 }
 
@@@@ -182,18 +478,26 @@@@
 	HTResponse_formatParam(response) :
 	HTAnchor_formatParam(anchor);
     char * boundary = HTAssocList_findObject(type_param, "boundary");
+
+    UNUSED(param);
+    UNUSED(input_format);
+
     if (boundary) {
 	HTStream * me;
 	if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
 	    HT_OUTOFMEM("HTBoundary");
 	me->isa = &HTBoundaryClass;
+	me->net = HTRequest_net(request);
 	me->request = request;
 	me->format = output_format;
 	me->orig_target = output_stream;
 	me->debug = HTRequest_debugStream(request);
-	me->state = EOL_FLF;
+
+	me->state = start_of_line;
+	me->keptcrlf=NO;
+
 	StrAllocCopy(me->boundary, boundary);		       /* Local copy */
-	me->bpos = me->boundary;
+
 	HTTRACE(STREAM_TRACE, "Boundary.... Stream created with boundary '%s\'\n" _ me->boundary);
 	return me;
     } else {
@
