Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 5 Nov 2012 10:54:15 +0000 (UTC)
From:      Dag-Erling Smørgrav <des@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r242608 - stable/7/lib/libfetch
Message-ID:  <201211051054.qA5AsF4A083767@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: des
Date: Mon Nov  5 10:54:14 2012
New Revision: 242608
URL: http://svnweb.freebsd.org/changeset/base/242608

Log:
  MFH r221820, r221821, r221822: increase WARNS
  MFH r221830: mark all descriptors close-on-exec
  MFH r225813: man page fixes
  MFH r225814: adjust copyright statement
  MFH r226537: latin1 -> utf8
  MFH r230307, r230478: fix SIGINFO infinite loop and data loss
  MFH r233648: man page fixes
  MFH r234138: support percent-encoded user and password
  MFH r234837: avoid busy-loop on slow connections
  MFH r234838: don't reuse credentials when redirected to another host
  MFH r236193: avoid SIGPIPE on network connections
  MFH r240496: use libmd if and only if OpenSSL is not available

Modified:
  stable/7/lib/libfetch/Makefile
  stable/7/lib/libfetch/common.c
  stable/7/lib/libfetch/common.h
  stable/7/lib/libfetch/fetch.3
  stable/7/lib/libfetch/fetch.c
  stable/7/lib/libfetch/fetch.h
  stable/7/lib/libfetch/file.c
  stable/7/lib/libfetch/ftp.c
  stable/7/lib/libfetch/http.c
Directory Properties:
  stable/7/lib/libfetch/   (props changed)

Modified: stable/7/lib/libfetch/Makefile
==============================================================================
--- stable/7/lib/libfetch/Makefile	Mon Nov  5 10:45:37 2012	(r242607)
+++ stable/7/lib/libfetch/Makefile	Mon Nov  5 10:54:14 2012	(r242608)
@@ -16,8 +16,8 @@ CFLAGS+=	-DINET6
 
 .if ${MK_OPENSSL} != "no"
 CFLAGS+=	-DWITH_SSL
-DPADD=		${LIBSSL} ${LIBCRYPTO} ${LIBMD}
-LDADD=		-lssl -lcrypto -lmd
+DPADD=		${LIBSSL} ${LIBCRYPTO}
+LDADD=		-lssl -lcrypto
 .else
 DPADD=		${LIBMD}
 LDADD=		-lmd
@@ -26,7 +26,7 @@ LDADD=		-lmd
 CFLAGS+=	-DFTP_COMBINE_CWDS
 
 CSTD?=		c99
-WARNS?=		2
+WARNS?=		4
 
 SHLIB_MAJOR=    5
 

Modified: stable/7/lib/libfetch/common.c
==============================================================================
--- stable/7/lib/libfetch/common.c	Mon Nov  5 10:45:37 2012	(r242607)
+++ stable/7/lib/libfetch/common.c	Mon Nov  5 10:54:14 2012	(r242608)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 1998-2011 Dag-Erling Smørgrav
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -209,10 +209,13 @@ conn_t *
 fetch_reopen(int sd)
 {
 	conn_t *conn;
+	int opt = 1;
 
 	/* allocate and fill connection structure */
 	if ((conn = calloc(1, sizeof(*conn))) == NULL)
 		return (NULL);
+	fcntl(sd, F_SETFD, FD_CLOEXEC);
+	setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof opt);
 	conn->sd = sd;
 	++conn->ref;
 	return (conn);
@@ -403,6 +406,33 @@ fetch_ssl_read(SSL *ssl, char *buf, size
 }
 #endif
 
+/*
+ * Cache some data that was read from a socket but cannot be immediately
+ * returned because of an interrupted system call.
+ */
+static int
+fetch_cache_data(conn_t *conn, char *src, size_t nbytes)
+{
+	char *tmp;
+
+	if (conn->cache.size < nbytes) {
+		tmp = realloc(conn->cache.buf, nbytes);
+		if (tmp == NULL) {
+			fetch_syserr();
+			return (-1);
+		}
+		conn->cache.buf = tmp;
+		conn->cache.size = nbytes;
+	}
+
+	memcpy(conn->cache.buf, src, nbytes);
+	conn->cache.len = nbytes;
+	conn->cache.pos = 0;
+
+	return (0);
+}
+
+
 static ssize_t
 fetch_socket_read(int sd, char *buf, size_t len)
 {
@@ -427,15 +457,32 @@ fetch_read(conn_t *conn, char *buf, size
 	struct timeval now, timeout, delta;
 	fd_set readfds;
 	ssize_t rlen, total;
-	int r;
+	char *start;
 
-	if (fetchTimeout) {
-		FD_ZERO(&readfds);
+	if (fetchTimeout > 0) {
 		gettimeofday(&timeout, NULL);
 		timeout.tv_sec += fetchTimeout;
 	}
 
 	total = 0;
+	start = buf;
+
+	if (conn->cache.len > 0) {
+		/*
+		 * The last invocation of fetch_read was interrupted by a
+		 * signal after some data had been read from the socket. Copy
+		 * the cached data into the supplied buffer before trying to
+		 * read from the socket again.
+		 */
+		total = (conn->cache.len < len) ? conn->cache.len : len;
+		memcpy(buf, conn->cache.buf, total);
+
+		conn->cache.len -= total;
+		conn->cache.pos += total;
+		len -= total;
+		buf += total;
+	}
+
 	while (len > 0) {
 		/*
 		 * The socket is non-blocking.  Instead of the canonical
@@ -471,28 +518,32 @@ fetch_read(conn_t *conn, char *buf, size
 			total += rlen;
 			continue;
 		} else if (rlen == FETCH_READ_ERROR) {
+			if (errno == EINTR)
+				fetch_cache_data(conn, start, total);
 			return (-1);
 		}
 		// assert(rlen == FETCH_READ_WAIT);
-		while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) {
+		FD_ZERO(&readfds);
+		while (!FD_ISSET(conn->sd, &readfds)) {
 			FD_SET(conn->sd, &readfds);
-			gettimeofday(&now, NULL);
-			delta.tv_sec = timeout.tv_sec - now.tv_sec;
-			delta.tv_usec = timeout.tv_usec - now.tv_usec;
-			if (delta.tv_usec < 0) {
-				delta.tv_usec += 1000000;
-				delta.tv_sec--;
-			}
-			if (delta.tv_sec < 0) {
-				errno = ETIMEDOUT;
-				fetch_syserr();
-				return (-1);
+			if (fetchTimeout > 0) {
+				gettimeofday(&now, NULL);
+				if (!timercmp(&timeout, &now, >)) {
+					errno = ETIMEDOUT;
+					fetch_syserr();
+					return (-1);
+				}
+				timersub(&timeout, &now, &delta);
 			}
 			errno = 0;
-			r = select(conn->sd + 1, &readfds, NULL, NULL, &delta);
-			if (r == -1) {
-				if (errno == EINTR && fetchRestartCalls)
-					continue;
+			if (select(conn->sd + 1, &readfds, NULL, NULL,
+				fetchTimeout > 0 ? &delta : NULL) < 0) {
+				if (errno == EINTR) {
+					if (fetchRestartCalls)
+						continue;
+					/* Save anything that was read. */
+					fetch_cache_data(conn, start, total);
+				}
 				fetch_syserr();
 				return (-1);
 			}
@@ -676,6 +727,7 @@ fetch_close(conn_t *conn)
 	if (--conn->ref > 0)
 		return (0);
 	ret = close(conn->sd);
+	free(conn->cache.buf);
 	free(conn->buf);
 	free(conn);
 	return (ret);

Modified: stable/7/lib/libfetch/common.h
==============================================================================
--- stable/7/lib/libfetch/common.h	Mon Nov  5 10:45:37 2012	(r242607)
+++ stable/7/lib/libfetch/common.h	Mon Nov  5 10:54:14 2012	(r242608)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 1998-2011 Dag-Erling Smørgrav
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -52,6 +52,13 @@ struct fetchconn {
 	size_t		 bufsize;	/* buffer size */
 	size_t		 buflen;	/* length of buffer contents */
 	int		 err;		/* last protocol reply code */
+	struct {			/* data cached after an interrupted
+					   read */
+		char	*buf;
+		size_t	 size;
+		size_t	 pos;
+		size_t	 len;
+	} cache;
 #ifdef WITH_SSL
 	SSL		*ssl;		/* SSL handle */
 	SSL_CTX		*ssl_ctx;	/* SSL context */

Modified: stable/7/lib/libfetch/fetch.3
==============================================================================
--- stable/7/lib/libfetch/fetch.3	Mon Nov  5 10:45:37 2012	(r242607)
+++ stable/7/lib/libfetch/fetch.3	Mon Nov  5 10:54:14 2012	(r242608)
@@ -1,5 +1,5 @@
 .\"-
-.\" Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+.\" Copyright (c) 1998-2011 Dag-Erling Smørgrav
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 26, 2010
+.Dd September 27, 2011
 .Dt FETCH 3
 .Os
 .Sh NAME
@@ -365,7 +365,7 @@ If the
 (if-modified-since) flag is specified, and
 the
 .Va ims_time
-field is set in 
+field is set in
 .Vt "struct url" ,
 then
 .Fn fetchXGetHTTP

Modified: stable/7/lib/libfetch/fetch.c
==============================================================================
--- stable/7/lib/libfetch/fetch.c	Mon Nov  5 10:45:37 2012	(r242607)
+++ stable/7/lib/libfetch/fetch.c	Mon Nov  5 10:54:14 2012	(r242608)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 1998-2004 Dag-Erling Smørgrav
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -289,6 +289,49 @@ fetchMakeURL(const char *scheme, const c
 }
 
 /*
+ * Return value of the given hex digit.
+ */
+static int
+fetch_hexval(char ch)
+{
+
+	if (ch >= '0' && ch <= '9')
+		return (ch - '0');
+	else if (ch >= 'a' && ch <= 'f')
+		return (ch - 'a' + 10);
+	else if (ch >= 'A' && ch <= 'F')
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/*
+ * Decode percent-encoded URL component from src into dst, stopping at end
+ * of string, or at @ or : separators.  Returns a pointer to the unhandled
+ * part of the input string (null terminator, @, or :).  No terminator is
+ * written to dst (it is the caller's responsibility).
+ */
+static const char *
+fetch_pctdecode(char *dst, const char *src, size_t dlen)
+{
+	int d1, d2;
+	char c;
+	const char *s;
+
+	for (s = src; *s != '\0' && *s != '@' && *s != ':'; s++) {
+		if (s[0] == '%' && (d1 = fetch_hexval(s[1])) >= 0 &&
+		    (d2 = fetch_hexval(s[2])) >= 0 && (d1 > 0 || d2 > 0)) {
+			c = d1 << 4 | d2;
+			s += 2;
+		} else {
+			c = *s;
+		}
+		if (dlen-- > 0)
+			*dst++ = c;
+	}
+	return (s);
+}
+
+/*
  * Split an URL into components. URL syntax is:
  * [method:/][/[user[:pwd]@]host[:port]/][document]
  * This almost, but not quite, RFC1738 URL syntax.
@@ -329,15 +372,11 @@ fetchParseURL(const char *URL)
 	p = strpbrk(URL, "/@");
 	if (p && *p == '@') {
 		/* username */
-		for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
-			if (i < URL_USERLEN)
-				u->user[i++] = *q;
+		q = fetch_pctdecode(u->user, URL, URL_USERLEN);
 
 		/* password */
 		if (*q == ':')
-			for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
-				if (i < URL_PWDLEN)
-					u->pwd[i++] = *q;
+			q = fetch_pctdecode(u->pwd, ++q, URL_PWDLEN);
 
 		p++;
 	} else {

Modified: stable/7/lib/libfetch/fetch.h
==============================================================================
--- stable/7/lib/libfetch/fetch.h	Mon Nov  5 10:45:37 2012	(r242607)
+++ stable/7/lib/libfetch/fetch.h	Mon Nov  5 10:54:14 2012	(r242608)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 1998-2004 Dag-Erling Smørgrav
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without

Modified: stable/7/lib/libfetch/file.c
==============================================================================
--- stable/7/lib/libfetch/file.c	Mon Nov  5 10:45:37 2012	(r242607)
+++ stable/7/lib/libfetch/file.c	Mon Nov  5 10:54:14 2012	(r242608)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 1998-2011 Dag-Erling Smørgrav
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/stat.h>
 
 #include <dirent.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -60,6 +61,7 @@ fetchXGetFile(struct url *u, struct url_
 		return (NULL);
 	}
 
+	fcntl(fileno(f), F_SETFD, FD_CLOEXEC);
 	return (f);
 }
 
@@ -90,6 +92,7 @@ fetchPutFile(struct url *u, const char *
 		return (NULL);
 	}
 
+	fcntl(fileno(f), F_SETFD, FD_CLOEXEC);
 	return (f);
 }
 

Modified: stable/7/lib/libfetch/ftp.c
==============================================================================
--- stable/7/lib/libfetch/ftp.c	Mon Nov  5 10:45:37 2012	(r242607)
+++ stable/7/lib/libfetch/ftp.c	Mon Nov  5 10:54:14 2012	(r242608)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 1998-2011 Dag-Erling Smørgrav
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,7 +41,7 @@ __FBSDID("$FreeBSD$");
  *
  * Major Changelog:
  *
- * Dag-Erling Coïdan Smørgrav
+ * Dag-Erling Smørgrav
  * 9 Jun 1998
  *
  * Incorporated into libfetch
@@ -127,7 +127,7 @@ unmappedaddr(struct sockaddr_in6 *sin6)
 	    !IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
 		return;
 	sin4 = (struct sockaddr_in *)sin6;
-	addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
+	addr = *(u_int32_t *)(uintptr_t)&sin6->sin6_addr.s6_addr[12];
 	port = sin6->sin6_port;
 	memset(sin4, 0, sizeof(struct sockaddr_in));
 	sin4->sin_addr.s_addr = addr;

Modified: stable/7/lib/libfetch/http.c
==============================================================================
--- stable/7/lib/libfetch/http.c	Mon Nov  5 10:45:37 2012	(r242607)
+++ stable/7/lib/libfetch/http.c	Mon Nov  5 10:54:14 2012	(r242608)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2000-2004 Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 2000-2011 Dag-Erling Smørgrav
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -76,7 +76,15 @@ __FBSDID("$FreeBSD$");
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+
+#ifdef WITH_SSL
+#include <openssl/md5.h>
+#define MD5Init(c) MD5_Init(c)
+#define MD5Update(c, data, len) MD5_Update(c, data, len)
+#define MD5Final(md, c) MD5_Final(md, c)
+#else
 #include <md5.h>
+#endif
 
 #include <netinet/in.h>
 #include <netinet/tcp.h>
@@ -199,6 +207,8 @@ http_growbuf(struct httpio *io, size_t l
 static int
 http_fillbuf(struct httpio *io, size_t len)
 {
+	ssize_t nbytes;
+
 	if (io->error)
 		return (-1);
 	if (io->eof)
@@ -207,10 +217,11 @@ http_fillbuf(struct httpio *io, size_t l
 	if (io->chunked == 0) {
 		if (http_growbuf(io, len) == -1)
 			return (-1);
-		if ((io->buflen = fetch_read(io->conn, io->buf, len)) == -1) {
-			io->error = 1;
+		if ((nbytes = fetch_read(io->conn, io->buf, len)) == -1) {
+			io->error = errno;
 			return (-1);
 		}
+		io->buflen = nbytes;
 		io->bufpos = 0;
 		return (io->buflen);
 	}
@@ -230,10 +241,11 @@ http_fillbuf(struct httpio *io, size_t l
 		len = io->chunksize;
 	if (http_growbuf(io, len) == -1)
 		return (-1);
-	if ((io->buflen = fetch_read(io->conn, io->buf, len)) == -1) {
-		io->error = 1;
+	if ((nbytes = fetch_read(io->conn, io->buf, len)) == -1) {
+		io->error = errno;
 		return (-1);
 	}
+	io->buflen = nbytes;
 	io->chunksize -= io->buflen;
 
 	if (io->chunksize == 0) {
@@ -275,8 +287,11 @@ http_readfn(void *v, char *buf, int len)
 		io->bufpos += l;
 	}
 
-	if (!pos && io->error)
+	if (!pos && io->error) {
+		if (io->error == EINTR)
+			io->error = 0;
 		return (-1);
+	}
 	return (pos);
 }
 
@@ -457,7 +472,7 @@ http_match(const char *str, const char *
  * Get the next header and return the appropriate symbolic code.  We
  * need to read one line ahead for checking for a continuation line
  * belonging to the current header (continuation lines start with
- * white space). 
+ * white space).
  *
  * We get called with a fresh line already in the conn buffer, either
  * from the previous http_next_header() invocation, or, the first
@@ -465,7 +480,7 @@ http_match(const char *str, const char *
  *
  * This stops when we encounter an empty line (we dont read beyond the header
  * area).
- * 
+ *
  * Note that the "headerbuf" is just a place to return the result. Its
  * contents are not used for the next call. This means that no cleanup
  * is needed when ie doing another connection, just call the cleanup when
@@ -490,7 +505,7 @@ init_http_headerbuf(http_headerbuf_t *bu
 	buf->buflen = 0;
 }
 
-static void 
+static void
 clean_http_headerbuf(http_headerbuf_t *buf)
 {
 	if (buf->buf)
@@ -499,10 +514,10 @@ clean_http_headerbuf(http_headerbuf_t *b
 }
 
 /* Remove whitespace at the end of the buffer */
-static void 
+static void
 http_conn_trimright(conn_t *conn)
 {
-	while (conn->buflen && 
+	while (conn->buflen &&
 	       isspace((unsigned char)conn->buf[conn->buflen - 1]))
 		conn->buflen--;
 	conn->buf[conn->buflen] = '\0';
@@ -511,11 +526,11 @@ http_conn_trimright(conn_t *conn)
 static hdr_t
 http_next_header(conn_t *conn, http_headerbuf_t *hbuf, const char **p)
 {
-	int i, len;
+	unsigned int i, len;
 
-	/* 
+	/*
 	 * Have to do the stripping here because of the first line. So
-	 * it's done twice for the subsequent lines. No big deal 
+	 * it's done twice for the subsequent lines. No big deal
 	 */
 	http_conn_trimright(conn);
 	if (conn->buflen == 0)
@@ -530,19 +545,19 @@ http_next_header(conn_t *conn, http_head
 	strcpy(hbuf->buf, conn->buf);
 	hbuf->buflen = conn->buflen;
 
-	/* 
+	/*
 	 * Fetch possible continuation lines. Stop at 1st non-continuation
-	 * and leave it in the conn buffer 
-         */
+	 * and leave it in the conn buffer
+	 */
 	for (i = 0; i < HTTP_MAX_CONT_LINES; i++) {
 		if (fetch_getln(conn) == -1)
 			return (hdr_syserror);
 
-		/* 
+		/*
 		 * Note: we carry on the idea from the previous version
 		 * that a pure whitespace line is equivalent to an empty
 		 * one (so it's not continuation and will be handled when
-		 * we are called next) 
+		 * we are called next)
 		 */
 		http_conn_trimright(conn);
 		if (conn->buf[0] != ' ' && conn->buf[0] != "\t"[0])
@@ -558,7 +573,7 @@ http_next_header(conn_t *conn, http_head
 		}
 		strcpy(hbuf->buf + hbuf->buflen, conn->buf);
 		hbuf->buflen += conn->buflen;
-	} 
+	}
 
 	/*
 	 * We could check for malformed headers but we don't really care.
@@ -577,12 +592,12 @@ http_next_header(conn_t *conn, http_head
  * [Proxy-]Authenticate header parsing
  */
 
-/* 
- * Read doublequote-delimited string into output buffer obuf (allocated 
+/*
+ * Read doublequote-delimited string into output buffer obuf (allocated
  * by caller, whose responsibility it is to ensure that it's big enough)
  * cp points to the first char after the initial '"'
- * Handles \ quoting 
- * Returns pointer to the first char after the terminating double quote, or 
+ * Handles \ quoting
+ * Returns pointer to the first char after the terminating double quote, or
  * NULL for error.
  */
 static const char *
@@ -623,7 +638,7 @@ typedef struct {
 	int	 nc; /* Nonce count */
 } http_auth_challenge_t;
 
-static void 
+static void
 init_http_auth_challenge(http_auth_challenge_t *b)
 {
 	b->scheme = HTTPAS_UNKNOWN;
@@ -631,18 +646,18 @@ init_http_auth_challenge(http_auth_chall
 	b->stale = b->nc = 0;
 }
 
-static void 
+static void
 clean_http_auth_challenge(http_auth_challenge_t *b)
 {
-	if (b->realm) 
+	if (b->realm)
 		free(b->realm);
-	if (b->qop) 
+	if (b->qop)
 		free(b->qop);
-	if (b->nonce) 
+	if (b->nonce)
 		free(b->nonce);
-	if (b->opaque) 
+	if (b->opaque)
 		free(b->opaque);
-	if (b->algo) 
+	if (b->algo)
 		free(b->algo);
 	init_http_auth_challenge(b);
 }
@@ -655,7 +670,7 @@ typedef struct {
 	int	valid; /* We did parse an authenticate header */
 } http_auth_challenges_t;
 
-static void 
+static void
 init_http_auth_challenges(http_auth_challenges_t *cs)
 {
 	int i;
@@ -664,7 +679,7 @@ init_http_auth_challenges(http_auth_chal
 	cs->count = cs->valid = 0;
 }
 
-static void 
+static void
 clean_http_auth_challenges(http_auth_challenges_t *cs)
 {
 	int i;
@@ -678,19 +693,19 @@ clean_http_auth_challenges(http_auth_cha
 	init_http_auth_challenges(cs);
 }
 
-/* 
+/*
  * Enumeration for lexical elements. Separators will be returned as their own
  * ascii value
  */
 typedef enum {HTTPHL_WORD=256, HTTPHL_STRING=257, HTTPHL_END=258,
 	      HTTPHL_ERROR = 259} http_header_lex_t;
 
-/* 
+/*
  * Determine what kind of token comes next and return possible value
  * in buf, which is supposed to have been allocated big enough by
- * caller. Advance input pointer and return element type. 
+ * caller. Advance input pointer and return element type.
  */
-static int 
+static int
 http_header_lex(const char **cpp, char *buf)
 {
 	size_t l;
@@ -719,7 +734,7 @@ http_header_lex(const char **cpp, char *
 	return (HTTPHL_WORD);
 }
 
-/* 
+/*
  * Read challenges from http xxx-authenticate header and accumulate them
  * in the challenges list structure.
  *
@@ -731,7 +746,7 @@ http_header_lex(const char **cpp, char *
  *
  * We support both approaches anyway
  */
-static int 
+static int
 http_parse_authenticate(const char *cp, http_auth_challenges_t *cs)
 {
 	int ret = -1;
@@ -755,7 +770,7 @@ http_parse_authenticate(const char *cp, 
 
 	/* Loop on challenges */
 	for (; cs->count < MAX_CHALLENGES; cs->count++) {
-		cs->challenges[cs->count] = 
+		cs->challenges[cs->count] =
 			malloc(sizeof(http_auth_challenge_t));
 		if (cs->challenges[cs->count] == NULL) {
 			fetch_syserr();
@@ -768,14 +783,14 @@ http_parse_authenticate(const char *cp, 
 			cs->challenges[cs->count]->scheme = HTTPAS_DIGEST;
 		} else {
 			cs->challenges[cs->count]->scheme = HTTPAS_UNKNOWN;
-			/* 
-                         * Continue parsing as basic or digest may
+			/*
+			 * Continue parsing as basic or digest may
 			 * follow, and the syntax is the same for
 			 * all. We'll just ignore this one when
 			 * looking at the list
 			 */
 		}
-	
+
 		/* Loop on attributes */
 		for (;;) {
 			/* Key */
@@ -794,31 +809,31 @@ http_parse_authenticate(const char *cp, 
 				goto out;
 
 			if (!strcasecmp(key, "realm"))
-				cs->challenges[cs->count]->realm = 
+				cs->challenges[cs->count]->realm =
 					strdup(value);
 			else if (!strcasecmp(key, "qop"))
-				cs->challenges[cs->count]->qop = 
+				cs->challenges[cs->count]->qop =
 					strdup(value);
 			else if (!strcasecmp(key, "nonce"))
-				cs->challenges[cs->count]->nonce = 
+				cs->challenges[cs->count]->nonce =
 					strdup(value);
 			else if (!strcasecmp(key, "opaque"))
-				cs->challenges[cs->count]->opaque = 
+				cs->challenges[cs->count]->opaque =
 					strdup(value);
 			else if (!strcasecmp(key, "algorithm"))
-				cs->challenges[cs->count]->algo = 
+				cs->challenges[cs->count]->algo =
 					strdup(value);
 			else if (!strcasecmp(key, "stale"))
-				cs->challenges[cs->count]->stale = 
+				cs->challenges[cs->count]->stale =
 					strcasecmp(value, "no");
 			/* Else ignore unknown attributes */
 
 			/* Comma or Next challenge or End */
 			lex = http_header_lex(&cp, key);
-			/* 
-                         * If we get a word here, this is the beginning of the
-			 * next challenge. Break the attributes loop 
-                         */
+			/*
+			 * If we get a word here, this is the beginning of the
+			 * next challenge. Break the attributes loop
+			 */
 			if (lex == HTTPHL_WORD)
 				break;
 
@@ -835,10 +850,10 @@ http_parse_authenticate(const char *cp, 
 		} /* End attributes loop */
 	} /* End challenge loop */
 
-	/* 
-         * Challenges max count exceeded. This really can't happen
-	 * with normal data, something's fishy -> error 
-	 */ 
+	/*
+	 * Challenges max count exceeded. This really can't happen
+	 * with normal data, something's fishy -> error
+	 */
 
 out:
 	if (key)
@@ -1014,16 +1029,16 @@ init_http_auth_params(http_auth_params_t
 	s->scheme = s->realm = s->user = s->password = 0;
 }
 
-static void 
+static void
 clean_http_auth_params(http_auth_params_t *s)
 {
-	if (s->scheme) 
+	if (s->scheme)
 		free(s->scheme);
-	if (s->realm) 
+	if (s->realm)
 		free(s->realm);
-	if (s->user) 
+	if (s->user)
 		free(s->user);
-	if (s->password) 
+	if (s->password)
 		free(s->password);
 	init_http_auth_params(s);
 }
@@ -1078,7 +1093,7 @@ http_authfromenv(const char *p, http_aut
 	}
 	ret = 0;
 out:
-	if (ret == -1) 
+	if (ret == -1)
 		clean_http_auth_params(parms);
 	if (str)
 		free(str);
@@ -1086,11 +1101,11 @@ out:
 }
 
 
-/* 
+/*
  * Digest response: the code to compute the digest is taken from the
- * sample implementation in RFC2616 
+ * sample implementation in RFC2616
  */
-#define IN
+#define IN const
 #define OUT
 
 #define HASHLEN 16
@@ -1099,7 +1114,7 @@ typedef char HASH[HASHLEN];
 typedef char HASHHEX[HASHHEXLEN+1];
 
 static const char *hexchars = "0123456789abcdef";
-static void 
+static void
 CvtHex(IN HASH Bin, OUT HASHHEX Hex)
 {
 	unsigned short i;
@@ -1115,7 +1130,7 @@ CvtHex(IN HASH Bin, OUT HASHHEX Hex)
 };
 
 /* calculate H(A1) as per spec */
-static void 
+static void
 DigestCalcHA1(
 	IN char * pszAlg,
 	IN char * pszUserName,
@@ -1150,7 +1165,7 @@ DigestCalcHA1(
 }
 
 /* calculate request-digest/response-digest as per HTTP Digest spec */
-static void 
+static void
 DigestCalcResponse(
 	IN HASHHEX HA1,           /* H(A1) */
 	IN char * pszNonce,       /* nonce from server */
@@ -1163,7 +1178,7 @@ DigestCalcResponse(
 	OUT HASHHEX Response      /* request-digest or response-digest */
 	)
 {
-/*	DEBUG(fprintf(stderr, 
+/*	DEBUG(fprintf(stderr,
 		      "Calc: HA1[%s] Nonce[%s] qop[%s] method[%s] URI[%s]\n",
 		      HA1, pszNonce, pszQop, pszMethod, pszDigestUri));*/
 	MD5_CTX Md5Ctx;
@@ -1202,8 +1217,8 @@ DigestCalcResponse(
 	CvtHex(RespHash, Response);
 }
 
-/* 
- * Generate/Send a Digest authorization header 
+/*
+ * Generate/Send a Digest authorization header
  * This looks like: [Proxy-]Authorization: credentials
  *
  *  credentials      = "Digest" digest-response
@@ -1236,10 +1251,10 @@ http_digest_auth(conn_t *conn, const cha
 		DEBUG(fprintf(stderr, "realm/nonce not set in challenge\n"));
 		return(-1);
 	}
-	if (!c->algo) 
+	if (!c->algo)
 		c->algo = strdup("");
 
-	if (asprintf(&options, "%s%s%s%s", 
+	if (asprintf(&options, "%s%s%s%s",
 		     *c->algo? ",algorithm=" : "", c->algo,
 		     c->opaque? ",opaque=" : "", c->opaque?c->opaque:"")== -1)
 		return (-1);
@@ -1267,13 +1282,13 @@ http_digest_auth(conn_t *conn, const cha
 		r = http_cmd(conn, "%s: Digest username=\"%s\",realm=\"%s\","
 			     "nonce=\"%s\",uri=\"%s\",response=\"%s\","
 			     "qop=\"auth\", cnonce=\"%s\", nc=%s%s",
-			     hdr, parms->user, c->realm, 
+			     hdr, parms->user, c->realm,
 			     c->nonce, url->doc, digest,
 			     cnonce, noncecount, options);
 	} else {
 		r = http_cmd(conn, "%s: Digest username=\"%s\",realm=\"%s\","
 			     "nonce=\"%s\",uri=\"%s\",response=\"%s\"%s",
-			     hdr, parms->user, c->realm, 
+			     hdr, parms->user, c->realm,
 			     c->nonce, url->doc, digest, options);
 	}
 	if (options)
@@ -1304,7 +1319,7 @@ http_basic_auth(conn_t *conn, const char
 }
 
 /*
- * Chose the challenge to answer and call the appropriate routine to 
+ * Chose the challenge to answer and call the appropriate routine to
  * produce the header.
  */
 static int
@@ -1330,16 +1345,16 @@ http_authorize(conn_t *conn, const char 
 	}
 
 	/* Error if "Digest" was specified and there is no Digest challenge */
-	if (!digest && (parms->scheme && 
+	if (!digest && (parms->scheme &&
 			!strcasecmp(parms->scheme, "digest"))) {
-		DEBUG(fprintf(stderr, 
+		DEBUG(fprintf(stderr,
 			      "Digest auth in env, not supported by peer\n"));
 		return (-1);
 	}
-	/* 
-         * If "basic" was specified in the environment, or there is no Digest
+	/*
+	 * If "basic" was specified in the environment, or there is no Digest
 	 * challenge, do the basic thing. Don't need a challenge for this,
-	 * so no need to check basic!=NULL 
+	 * so no need to check basic!=NULL
 	 */
 	if (!digest || (parms->scheme && !strcasecmp(parms->scheme,"basic")))
 		return (http_basic_auth(conn,hdr,parms->user,parms->password));
@@ -1495,7 +1510,7 @@ http_request(struct url *URL, const char
 	http_auth_challenges_t proxy_challenges;
 
 	/* The following calls don't allocate anything */
-	init_http_headerbuf(&headerbuf); 
+	init_http_headerbuf(&headerbuf);
 	init_http_auth_challenges(&server_challenges);
 	init_http_auth_challenges(&proxy_challenges);
 
@@ -1580,65 +1595,65 @@ http_request(struct url *URL, const char
 		/* virtual host */
 		http_cmd(conn, "Host: %s", host);
 
-		/* 
-                 * Proxy authorization: we only send auth after we received
-		 * a 407 error. We do not first try basic anyway (changed 
-                 * when support was added for digest-auth)
-                 */
+		/*
+		 * Proxy authorization: we only send auth after we received
+		 * a 407 error. We do not first try basic anyway (changed
+		 * when support was added for digest-auth)
+		 */
 		if (purl && proxy_challenges.valid) {
 			http_auth_params_t aparams;
 			init_http_auth_params(&aparams);
 			if (*purl->user || *purl->pwd) {
-				aparams.user = purl->user ? 
+				aparams.user = purl->user ?
 					strdup(purl->user) : strdup("");
 				aparams.password = purl->pwd?
 					strdup(purl->pwd) : strdup("");
-			} else if ((p = getenv("HTTP_PROXY_AUTH")) != NULL && 
+			} else if ((p = getenv("HTTP_PROXY_AUTH")) != NULL &&
 				   *p != '\0') {
 				if (http_authfromenv(p, &aparams) < 0) {
 					http_seterr(HTTP_NEED_PROXY_AUTH);
 					goto ouch;
 				}
 			}
-			http_authorize(conn, "Proxy-Authorization", 
+			http_authorize(conn, "Proxy-Authorization",
 				       &proxy_challenges, &aparams, url);
 			clean_http_auth_params(&aparams);
 		}
 
-		/* 
-                 * Server authorization: we never send "a priori"
+		/*
+		 * Server authorization: we never send "a priori"
 		 * Basic auth, which used to be done if user/pass were
 		 * set in the url. This would be weird because we'd send the
-		 * password in the clear even if Digest is finally to be 
+		 * password in the clear even if Digest is finally to be
 		 * used (it would have made more sense for the
-		 * pre-digest version to do this when Basic was specified 
-                 * in the environment) 
-                 */
+		 * pre-digest version to do this when Basic was specified
+		 * in the environment)
+		 */
 		if (server_challenges.valid) {
 			http_auth_params_t aparams;
 			init_http_auth_params(&aparams);
 			if (*url->user || *url->pwd) {
-				aparams.user = url->user ? 
+				aparams.user = url->user ?
 					strdup(url->user) : strdup("");
-				aparams.password = url->pwd ? 
+				aparams.password = url->pwd ?
 					strdup(url->pwd) : strdup("");
-			} else if ((p = getenv("HTTP_AUTH")) != NULL && 
+			} else if ((p = getenv("HTTP_AUTH")) != NULL &&
 				   *p != '\0') {
 				if (http_authfromenv(p, &aparams) < 0) {
 					http_seterr(HTTP_NEED_AUTH);
 					goto ouch;
 				}
-			} else if (fetchAuthMethod && 
+			} else if (fetchAuthMethod &&
 				   fetchAuthMethod(url) == 0) {
-				aparams.user = url->user ? 
+				aparams.user = url->user ?
 					strdup(url->user) : strdup("");
-				aparams.password = url->pwd ? 
+				aparams.password = url->pwd ?
 					strdup(url->pwd) : strdup("");
 			} else {
 				http_seterr(HTTP_NEED_AUTH);
 				goto ouch;
 			}
-			http_authorize(conn, "Authorization", 
+			http_authorize(conn, "Authorization",
 				       &server_challenges, &aparams, url);
 			clean_http_auth_params(&aparams);
 		}
@@ -1786,7 +1801,9 @@ http_request(struct url *URL, const char
 					DEBUG(fprintf(stderr, "failed to parse new URL\n"));
 					goto ouch;
 				}
-				if (!*new->user && !*new->pwd) {
+
+				/* Only copy credentials if the host matches */
+				if (!strcmp(new->host, url->host) && !*new->user && !*new->pwd) {
 					strcpy(new->user, url->user);
 					strcpy(new->pwd, url->pwd);
 				}
@@ -1818,12 +1835,12 @@ http_request(struct url *URL, const char
 		} while (h > hdr_end);
 
 		/* we need to provide authentication */
-		if (conn->err == HTTP_NEED_AUTH || 
+		if (conn->err == HTTP_NEED_AUTH ||
 		    conn->err == HTTP_NEED_PROXY_AUTH) {
 			e = conn->err;
-			if ((conn->err == HTTP_NEED_AUTH && 
-			     !server_challenges.valid) || 
-			    (conn->err == HTTP_NEED_PROXY_AUTH && 
+			if ((conn->err == HTTP_NEED_AUTH &&
+			     !server_challenges.valid) ||

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201211051054.qA5AsF4A083767>