From owner-svn-src-stable-7@FreeBSD.ORG Mon Nov 5 10:54:15 2012 Return-Path: Delivered-To: svn-src-stable-7@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 7B77B7DF; Mon, 5 Nov 2012 10:54:15 +0000 (UTC) (envelope-from des@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 5EFDA8FC0A; Mon, 5 Nov 2012 10:54:15 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id qA5AsFQF083777; Mon, 5 Nov 2012 10:54:15 GMT (envelope-from des@svn.freebsd.org) Received: (from des@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id qA5AsF4A083767; Mon, 5 Nov 2012 10:54:15 GMT (envelope-from des@svn.freebsd.org) Message-Id: <201211051054.qA5AsF4A083767@svn.freebsd.org> From: Dag-Erling Smørgrav Date: Mon, 5 Nov 2012 10:54:15 +0000 (UTC) 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 X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-7@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for only the 7-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 05 Nov 2012 10:54:15 -0000 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 #include +#include #include #include @@ -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 #include #include + +#ifdef WITH_SSL +#include +#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 +#endif #include #include @@ -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 ***