Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 27 May 2014 04:39:23 +0000 (UTC)
From:      Peter Wemm <peter@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org
Subject:   svn commit: r266727 - in vendor/serf/serf-1.3.5: . auth
Message-ID:  <201405270439.s4R4dNrS071432@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: peter
Date: Tue May 27 04:39:23 2014
New Revision: 266727
URL: http://svnweb.freebsd.org/changeset/base/266727

Log:
  Tag serf-1.3.5 import

Added:
  vendor/serf/serf-1.3.5/
     - copied from r266725, vendor/serf/dist/
Replaced:
  vendor/serf/serf-1.3.5/CHANGES
     - copied unchanged from r266726, vendor/serf/dist/CHANGES
  vendor/serf/serf-1.3.5/auth/auth.c
     - copied unchanged from r266726, vendor/serf/dist/auth/auth.c
  vendor/serf/serf-1.3.5/auth/auth_spnego.c
     - copied unchanged from r266726, vendor/serf/dist/auth/auth_spnego.c
  vendor/serf/serf-1.3.5/outgoing.c
     - copied unchanged from r266726, vendor/serf/dist/outgoing.c
  vendor/serf/serf-1.3.5/serf.h
     - copied unchanged from r266726, vendor/serf/dist/serf.h
  vendor/serf/serf-1.3.5/ssltunnel.c
     - copied unchanged from r266726, vendor/serf/dist/ssltunnel.c

Copied: vendor/serf/serf-1.3.5/CHANGES (from r266726, vendor/serf/dist/CHANGES)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/serf/serf-1.3.5/CHANGES	Tue May 27 04:39:23 2014	(r266727, copy of r266726, vendor/serf/dist/CHANGES)
@@ -0,0 +1,276 @@
+Serf 1.3.5 [2014-04-27, from /tags/1.3.5, rxxxx]
+  Fix issue #125: no reverse lookup during Negotiate authentication for proxies.
+  Fix a crash caused by incorrect reuse of the ssltunnel CONNECT request (r2316)
+  Cancel request if response parsing failed + authn callback set (r2319)
+  Update the expired certificates in the test suite.
+
+
+Serf 1.3.4 [2014-02-08, from /tags/1.3.4, r2310]
+  Fix issue #119: Endless loop during ssl tunnel setup with Negotiate authn
+  Fix issue #123: Can't setup ssl tunnel which sends Connection close header
+  Fix a race condition when initializing OpenSSL from multiple threads (r2263)
+  Fix issue #138: Incorrect pkg-config file when GSSAPI isn't configured
+
+
+Serf 1.3.3 [2013-12-09, from /tags/1.3.3, r2242]
+  Fix issue 129: Try more addresses of multihomed servers
+  Handle X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE correctly (r2225)
+  Return APR_TIMEUP from poll() to enable detecting connection timeouts (r2183)
+
+
+Serf 1.3.2 [2013-10-04, from /tags/1.3.2, r2195]
+  Fix issue 130: HTTP headers should be treated case-insensitively
+  Fix issue 126: Compilation breaks with Codewarrior compiler
+  Fix crash during cleanup of SSL buckets in apr_terminate() (r2145)
+  Fix Windows build: Also export functions with capital letters in .def file
+  Fix host header when url contains a username or password (r2170)
+  Ensure less TCP package fragmentation on Windows (r2145)
+  Handle authentication for responses to HEAD requests (r2178,-9)
+  Improve serf_get: add option to add request headers, allow url with query,
+     allow HEAD requests (r2143,r2175,-6)
+  Improve RFC conformance: don't expect body for certain responses (r2011,-2)
+  Do not invoke progress callback when no data was received (r2144)
+  And more test suite fixes and build warning cleanups
+  SCons-related fixes:
+   Fix build when GSSAPI not in default include path (2155)
+   Fix OpenBSD build: always map all LIBPATH entries into RPATH (r2156)
+   Checksum generation in Windows shared libraries for release builds (2162)
+   Mac OS X: Use MAJOR version only in dylib install name (r2161)
+   Use both MAJOR and MINOR version for the shared library name (2163)
+   Fix the .pc file when installing serf in a non-default LIBDIR (r2191)
+
+
+Serf 1.3.1 [2013-08-15, from /tags/1.3.1, r2138]
+  Fix issue 77: Endless loop if server doesn't accept Negotiate authentication.
+  Fix issue 114: ssl/tls renegotiation fails
+  Fix issue 120: error with ssl tunnel over proxy with KeepAlive off and
+                 Basic authentication.
+  Fixed bugs with authentication (r2057,2115,2118)
+  SCons-related fixes:
+   Fix issue 111: add flag to set custom library path
+   Fix issue 112: add soname
+   Fix issue 113: add gssapi libs in the serf pc file
+   Fix issue 115: Setting RPATH on Solaris broken in SConstruct
+   Fix issue 116: scons check should return non-zero exit staths
+   Fix issue 121: make CFLAGS, LIBS, LINKFLAGS and CPPFLAGS take a space-
+                   separated list of flags.
+   Fix issue 122: make scons PREFIX create the folder if it doesn't exist
+   Mac OS X: Fix scons --install-sandbox
+   Solaris: Fix build with cc, don't use unsupported compiler flags
+  Require SCons version 2.3.0 or higher now (for the soname support).
+
+
+Serf 1.3.0 [2013-07-23, from /tags/1.3.0, r2074]
+  Fix issue 83: use PATH rather than URI within an ssltunnel (r1952)
+  Fix issue 108: improved error reporting from the underlying socket (r1951)
+  NEW: Switch to the SCons build system; retire serfmake, serf.mak, autotools
+  Improved Basic and Digest authentication:
+    - remember credentials on a per-server basis
+    - properly manage authentication realms
+    - continue functioning when a server sets KeepAlive: off
+  Windows: add support for NTLM authentication
+  Improved 2617 compliance: always use strongest authentication (r1968,1971)
+  Fixed bugs with proxy authentication and SSL tunneling through a proxy
+  Fixed bugs the response parser (r2032,r2036)
+  SSL connection performance improvements
+  Huge expansion of the test suite
+
+
+Serf 1.2.1 [2013-06-03, from /tags/1.2.1, r1906]
+  Fix issue 95: add gssapi switches to configure (r1864, r1900)
+  Fix issue 97: skip mmap bucket if APR_HAS_MMAP is undefined (r1877)
+  Fix issue 100: building against an old Windows Platform SDK (r1881)
+  Fix issue 102: digest authentication failures (r1885)
+  Improve error return values in SSPI authentication (r1804)
+  Ensure serf-1.pc is constructed by serfmake (r1865)
+  Optimize SPNego authentication processing (r1868)
+  Reject certs that application does not like (r1794)
+  Fix possible endless loop in serf_linebuf_fetch() (r1816)
+  Windows build: dereference INTDIR in serf.mak (r1882)
+
+
+Serf 1.2.0 [2013-02-22, from /tags/1.2.0, r1726]
+  Fixed issue 94: Serf can enter an infinite loop when server aborts conn.
+  Fixed issue 91: Serf doesn't handle an incoming 408 Timeout Request
+  Fixed issue 80: Serf is not handling Negotiate authentication correctly
+  Fixed issue 77: Endless loop if server doesn't accept Negotiate authn
+  Fixed issue 93: cleanup-after-fork interferes with parent (r1714)
+  Fixed most of issue 89: Support REAL SPNEGO authentication
+  Enable Negotiate/Kerberos support for proxy servers.
+  Return error when C-L, chunked, gzip encoded response bodies were
+    truncated (due to aborted connection) (r1688)
+  Add a logging mechanism that can be enabled at compile-time.
+  Don't lookup server address if a proxy was configured. (r1706)
+  Fix an off-by-one in buffer sizing (r1695)
+  Disable SSL compression by default + API to enable it (r1692)
+  New serf_connection_get_latency() for estimated network latency (r1689)
+  New error code and RFC compliance for the HTTPS tunnel (r1701, r1644)
+  Handle EINTR when a user suspends and then backgrounds the app (r1708)
+  Minor fixes and test suite improvements.
+
+
+Serf 1.1.1 [2012-10-04, from /tags/1.1.1, r1657]
+  Fixed issue 86: ensure requeued requests are correctly handled.
+    This fixes:
+      - infinite loop with multiple connection resets or SIGPIPE errors
+      - "connection" hang where we would not re-queue requests that are
+        held after we re-connect
+  Fixed issue 74: test_all goes in an endless loop
+  Fix memleak when conn. is closed explicitly/due to pool cleanups (r1623)
+  Windows: Fix https connection aborts (r1628..-30,-33,-34,-37)
+  Add new error codes for the SSL bucket
+
+
+Serf 1.1.0 [2012-06-07, from /tags/1.1.0, r1617]
+  New: serf_bucket_request_set_CL() for C-L based, non-chunked requests
+  New: serf_ssl_server_cert_chain_callback_set() for full-chain validation
+
+
+Serf 1.0.3 [2012-03-20, from /tags/1.0.3, r1586]
+  Map more OpenSSL errors into SERF_SSL_CERT_UNKNOWNCA (r1573)
+
+
+Serf 1.0.2
+  Not released.
+
+
+Serf 1.0.1 [2012-02-15, from /tags/1.0.1, r1569]
+  FreeBSD fixes in the test suite (r1560, r1565)
+  Minor build fixes
+
+
+Serf 1.0.0 [2011-07-15, from /tags/1.0.0, r1540]
+  Fixed issue 38: enable builds using non-GNU make
+  Fixed issue 49: support SSL tunnels for HTTPS via a proxy
+  Fixed issue 56: allow Subject Alternative Name, and enable SNI
+  Fixed issue 61: include order dependencies
+  Fixed issue 66: improved error reporting when creating install dirs
+  Fixed issue 71: handle ECONNREFUSED on Windows
+  Fixed issue 79: destroy the APR allocator, if we create one
+  Fixed issue 81: build failed on APR 0.9.x
+  Major performance improvements and bug fixes for SSL buckets/handling (r1462)
+  Add a new "iovec" bucket type (r1434)
+  Minimize network packet writes based on ra_serf analysis (r1467, r1471)
+  Fix out of order issue with multiple priority requests (r1469)
+  Work around broken WSAPoll() impl on Windows introduced in APR 1.4.0 (r1506)
+  Fix 100% CPU usage with many pipelined requests (r1456)
+  Corrected contents of build/serf.def; it now includes bucket types (r1512)
+  Removed "snapshot" feature from buckets (r1503)
+  Various improvements to the test system
+  Various memory leak fixes
+
+
+Serf 0.7.2 [2011-03-12, from /tags/0.7.2, r1452]
+  Actually disable Nagle when creating a connection (r1441)
+  Return error when app asks for HTTPS over proxy connection (r1433)
+
+
+Serf 0.7.1 [2011-01-25, from /tags/0.7.1, r1432]
+  Fix memory leak when using SSL (r1408, r1416)
+  Fix build for blank apr-util directory (r1421)
+
+
+Serf 0.7.0 [2010-08-25, from /tags/0.7.0, r1407]
+  Fix double free abort when destroying request buckets
+  Fix test server in unit test framework to avoid random test failures
+  Allow older Serf programs which don't use the new authn framework to still
+    handle authn without forcing them to switch to the new framework. (r1401)
+  Remove the SERF_DECLARE macros, preferring a .DEF file for Windows
+  Barrier buckets now pass read_iovec to their wrapped bucket
+  Fix HTTP header parsing to allow for empty header values
+
+
+Serf 0.6.1 [2010-05-14, from /tags/0.6.1, r1370]
+  Generally: this release fixes problems with the 0.4.0 packaging
+  Small compilation fix in outgoing.c for Windows builds
+
+
+Serf 0.6.0
+  Not released.
+
+
+Serf 0.5.0
+  Not released.
+
+
+Serf 0.4.0
+  WITHDRAWN: this release misstated itself as 0.5.0; use a later release
+
+  Provide authn framework, supporting Basic, Digest, Kerberos (SSPI, GSS),
+    along with proxy authn using Basic or Digest
+  Added experimental listener framework, along with test_server.c
+  Improvements and fixes to SSL support, including connection setup changes
+  Experimental support for unrequested, arriving ("async") responses
+  Experimental BWTP support using the async arrival feature
+  Headers are combined on read (not write), to ease certian classes of parsing
+  Experimental feature on aggregate buckets for a callback-on-empty
+  Fix the bucket allocator for when APR is using its pool debugging features
+  Proxy support in the serf_get testing utility
+  Fix to include the port number in the Host header
+  serf_get propagates errors from the response, instead of aborting (Issue 52)
+  Added serf_lib_version() for runtime version tests
+
+
+Serf 0.3.1 [2010-02-14, from /tags/0.3.1, r1322]
+  Fix loss of error on request->setup() callback. (Issue 47)
+  Support APR 2.x. (Issue 48)
+  Fixed slowdown in aggregate bucket with millions of child buckets
+  Avoid hang in apr_pollset_poll() by unclosed connections after fork()
+
+
+Serf 0.3.0 [2009-01-26, from /tags/0.3.0, r1217]
+  Support LTFLAGS override as a config-time env. variable (Issue 44)
+  Fix CUTest test harness compilation on Solaris (Issue 43)
+  Fix small race condition in OpenSSL initialization (Issue 39)
+  Handle content streams larger than 4GB on 32-bit OSes (Issue 41)
+  Fix test_ssl.c compilation with mingw+msys
+  Fix conn close segfault by explicitly closing conn when pool is destroyed
+  Expose the depth of the SSL certificate so the validator can use that info
+  Fix socket address family issue when opening a connection to a proxy
+  Provide new API to take snapshots of buckets
+  Implement snapshot API for simple and aggregate buckets
+  Build with bundled apr and apr-util VPATH builds
+  Build with bundled OpenSSL builds
+
+
+Serf 0.2.0 [2008-06-06, from /tags/0.2.0, r1189]
+  Enable use of external event loop: serf_create_context_ex
+  Enable adding new requests at the beginning of the request queue
+  Handle 'Connection:close' headers
+  Enable limiting the number of outstanding requests
+  Add readline function to simple buckets
+  Concatenate repeated headers using comma as separator, as per RFC 2616,
+    section 4.2. (Issue 29)
+  Add proxy server support
+  Add progress feedback support. (Issue 11)
+  Provide new API to simplify use of proxy and progress feedback support
+  Add callback to validate SSL server certificates. (Issue 31)
+  Add new test framework
+  Send current version string in the test programs (Issue 21)
+  Bugfixes:
+     Fix segfault with epoll when removing a NULL socket
+     Reset OpenSSL thread-safety callbacks when apr_terminate() called
+     Do not remove the socket from the pollset on pool cleanup
+     Do not issue double close on skt w/second one being close(-1) (Issue 33)
+
+
+Serf 0.1.2 [2007-06-18, from /tags/0.1.2, r1115]
+  Enable thread-safety with OpenSSL (Issue 19)
+  Teach serfmake to install headers into include/serf-0
+  Be more tolerant when servers close the connection without telling us
+  Do not open the connection until we have requests to deliver
+  Fix serfmake to produce the library that corresponds to the minor version
+  Fix a memory leak with the socket bucket (Issue 14)
+  Fix uninitialized branch in serf_spider (Issue 15)
+
+
+Serf 0.1.1 [2007-05-12, from /tags/0.1.1, r1105]
+  Add SSL client certificate support
+  Implement optimized iovec reads for header buckets
+  Fix up 'make clean' and 'make distclean' (Issues 9, 10)
+  Add SERF_VERSION_AT_LEAST macro
+  Remove abort() calls (Issue 13)
+
+
+Serf 0.1.0 [2006-12-14, from /tags/0.1.0, r1087]
+  Initial packaged release

Copied: vendor/serf/serf-1.3.5/auth/auth.c (from r266726, vendor/serf/dist/auth/auth.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/serf/serf-1.3.5/auth/auth.c	Tue May 27 04:39:23 2014	(r266727, copy of r266726, vendor/serf/dist/auth/auth.c)
@@ -0,0 +1,486 @@
+/* Copyright 2009 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "serf.h"
+#include "serf_private.h"
+#include "auth.h"
+
+#include <apr.h>
+#include <apr_base64.h>
+#include <apr_strings.h>
+#include <apr_lib.h>
+
+static apr_status_t
+default_auth_response_handler(const serf__authn_scheme_t *scheme,
+                              peer_t peer,
+                              int code,
+                              serf_connection_t *conn,
+                              serf_request_t *request,
+                              serf_bucket_t *response,
+                              apr_pool_t *pool)
+{
+    return APR_SUCCESS;
+}
+
+/* These authentication schemes are in order of decreasing security, the topmost
+   scheme will be used first when the server supports it.
+ 
+   Each set of handlers should support both server (401) and proxy (407)
+   authentication.
+ 
+   Use lower case for the scheme names to enable case insensitive matching.
+ */
+static const serf__authn_scheme_t serf_authn_schemes[] = {
+#ifdef SERF_HAVE_SPNEGO
+    {
+        "Negotiate",
+        "negotiate",
+        SERF_AUTHN_NEGOTIATE,
+        serf__init_spnego,
+        serf__init_spnego_connection,
+        serf__handle_spnego_auth,
+        serf__setup_request_spnego_auth,
+        serf__validate_response_spnego_auth,
+    },
+#ifdef WIN32
+    {
+        "NTLM",
+        "ntlm",
+        SERF_AUTHN_NTLM,
+        serf__init_spnego,
+        serf__init_spnego_connection,
+        serf__handle_spnego_auth,
+        serf__setup_request_spnego_auth,
+        serf__validate_response_spnego_auth,
+    },
+#endif /* #ifdef WIN32 */
+#endif /* SERF_HAVE_SPNEGO */
+    {
+        "Digest",
+        "digest",
+        SERF_AUTHN_DIGEST,
+        serf__init_digest,
+        serf__init_digest_connection,
+        serf__handle_digest_auth,
+        serf__setup_request_digest_auth,
+        serf__validate_response_digest_auth,
+    },
+    {
+        "Basic",
+        "basic",
+        SERF_AUTHN_BASIC,
+        serf__init_basic,
+        serf__init_basic_connection,
+        serf__handle_basic_auth,
+        serf__setup_request_basic_auth,
+        default_auth_response_handler,
+    },
+    /* ADD NEW AUTHENTICATION IMPLEMENTATIONS HERE (as they're written) */
+
+    /* sentinel */
+    { 0 }
+};
+
+
+/* Reads and discards all bytes in the response body. */
+static apr_status_t discard_body(serf_bucket_t *response)
+{
+    apr_status_t status;
+    const char *data;
+    apr_size_t len;
+
+    while (1) {
+        status = serf_bucket_read(response, SERF_READ_ALL_AVAIL, &data, &len);
+
+        if (status) {
+            return status;
+        }
+
+        /* feed me */
+    }
+}
+
+/**
+ * handle_auth_header is called for each header in the response. It filters
+ * out the Authenticate headers (WWW or Proxy depending on what's needed) and
+ * tries to find a matching scheme handler.
+ *
+ * Returns a non-0 value of a matching handler was found.
+ */
+static int handle_auth_headers(int code,
+                               void *baton,
+                               apr_hash_t *hdrs,
+                               serf_request_t *request,
+                               serf_bucket_t *response,
+                               apr_pool_t *pool)
+{
+    const serf__authn_scheme_t *scheme;
+    serf_connection_t *conn = request->conn;
+    serf_context_t *ctx = conn->ctx;
+    apr_status_t status;
+
+    status = SERF_ERROR_AUTHN_NOT_SUPPORTED;
+
+    /* Find the matching authentication handler.
+       Note that we don't reuse the auth scheme stored in the context,
+       as that may have changed. (ex. fallback from ntlm to basic.) */
+    for (scheme = serf_authn_schemes; scheme->name != 0; ++scheme) {
+        const char *auth_hdr;
+        serf__auth_handler_func_t handler;
+        serf__authn_info_t *authn_info;
+
+        if (! (ctx->authn_types & scheme->type))
+            continue;
+
+        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                      "Client supports: %s\n", scheme->name);
+
+        auth_hdr = apr_hash_get(hdrs, scheme->key, APR_HASH_KEY_STRING);
+
+        if (!auth_hdr)
+            continue;
+
+        if (code == 401) {
+            authn_info = serf__get_authn_info_for_server(conn);
+        } else {
+            authn_info = &ctx->proxy_authn_info;
+        }
+
+        if (authn_info->failed_authn_types & scheme->type) {
+            /* Skip this authn type since we already tried it before. */
+            continue;
+        }
+
+        /* Found a matching scheme */
+        status = APR_SUCCESS;
+
+        handler = scheme->handle_func;
+
+        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                      "... matched: %s\n", scheme->name);
+
+        /* If this is the first time we use this scheme on this context and/or
+           this connection, make sure to initialize the authentication handler 
+           first. */
+        if (authn_info->scheme != scheme) {
+            status = scheme->init_ctx_func(code, ctx, ctx->pool);
+            if (!status) {
+                status = scheme->init_conn_func(scheme, code, conn,
+                                                conn->pool);
+                if (!status)
+                    authn_info->scheme = scheme;
+                else
+                    authn_info->scheme = NULL;
+            }
+        }
+
+        if (!status) {
+            const char *auth_attr = strchr(auth_hdr, ' ');
+            if (auth_attr) {
+                auth_attr++;
+            }
+
+            status = handler(code, request, response,
+                             auth_hdr, auth_attr, baton, ctx->pool);
+        }
+
+        if (status == APR_SUCCESS)
+            break;
+
+        /* No success authenticating with this scheme, try the next.
+           If no more authn schemes are found the status of this scheme will be
+           returned.
+        */
+        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                      "%s authentication failed.\n", scheme->name);
+
+        /* Clear per-request auth_baton when switching to next auth scheme. */
+        request->auth_baton = NULL;
+
+        /* Remember failed auth types to skip in future. */
+        authn_info->failed_authn_types |= scheme->type;
+    }
+
+    return status;
+}
+
+/**
+ * Baton passed to the store_header_in_dict callback function
+ */
+typedef struct {
+    const char *header;
+    apr_pool_t *pool;
+    apr_hash_t *hdrs;
+} auth_baton_t;
+
+static int store_header_in_dict(void *baton,
+                                const char *key,
+                                const char *header)
+{
+    auth_baton_t *ab = baton;
+    const char *auth_attr;
+    char *auth_name, *c;
+
+    /* We're only interested in xxxx-Authenticate headers. */
+    if (strcasecmp(key, ab->header) != 0)
+        return 0;
+
+    /* Extract the authentication scheme name.  */
+    auth_attr = strchr(header, ' ');
+    if (auth_attr) {
+        auth_name = apr_pstrmemdup(ab->pool, header, auth_attr - header);
+    }
+    else
+        auth_name = apr_pstrmemdup(ab->pool, header, strlen(header));
+
+    /* Convert scheme name to lower case to enable case insensitive matching. */
+    for (c = auth_name; *c != '\0'; c++)
+        *c = (char)apr_tolower(*c);
+
+    apr_hash_set(ab->hdrs, auth_name, APR_HASH_KEY_STRING,
+                 apr_pstrdup(ab->pool, header));
+
+    return 0;
+}
+
+/* Dispatch authentication handling. This function matches the possible
+   authentication mechanisms with those available. Server and proxy
+   authentication are evaluated separately. */
+static apr_status_t dispatch_auth(int code,
+                                  serf_request_t *request,
+                                  serf_bucket_t *response,
+                                  void *baton,
+                                  apr_pool_t *pool)
+{
+    serf_bucket_t *hdrs;
+
+    if (code == 401 || code == 407) {
+        auth_baton_t ab = { 0 };
+        const char *auth_hdr;
+
+        ab.hdrs = apr_hash_make(pool);
+        ab.pool = pool;
+
+        /* Before iterating over all authn headers, check if there are any. */
+        if (code == 401)
+            ab.header = "WWW-Authenticate";
+        else
+            ab.header = "Proxy-Authenticate";
+
+        hdrs = serf_bucket_response_get_headers(response);
+        auth_hdr = serf_bucket_headers_get(hdrs, ab.header);
+
+        if (!auth_hdr) {
+            return SERF_ERROR_AUTHN_FAILED;
+        }
+        serf__log_skt(AUTH_VERBOSE, __FILE__, request->conn->skt,
+                      "%s authz required. Response header(s): %s\n",
+                      code == 401 ? "Server" : "Proxy", auth_hdr);
+
+
+        /* Store all WWW- or Proxy-Authenticate headers in a dictionary.
+
+           Note: it is possible to have multiple Authentication: headers. We do
+           not want to combine them (per normal header combination rules) as that
+           would make it hard to parse. Instead, we want to individually parse
+           and handle each header in the response, looking for one that we can
+           work with.
+        */
+        serf_bucket_headers_do(hdrs,
+                               store_header_in_dict,
+                               &ab);
+
+        /* Iterate over all authentication schemes, in order of decreasing
+           security. Try to find a authentication schema the server support. */
+        return handle_auth_headers(code, baton, ab.hdrs,
+                                   request, response, pool);
+    }
+
+    return APR_SUCCESS;
+}
+
+/* Read the headers of the response and try the available
+   handlers if authentication or validation is needed. */
+apr_status_t serf__handle_auth_response(int *consumed_response,
+                                        serf_request_t *request,
+                                        serf_bucket_t *response,
+                                        void *baton,
+                                        apr_pool_t *pool)
+{
+    apr_status_t status;
+    serf_status_line sl;
+
+    *consumed_response = 0;
+
+    /* TODO: the response bucket was created by the application, not at all
+       guaranteed that this is of type response_bucket!! */
+    status = serf_bucket_response_status(response, &sl);
+    if (SERF_BUCKET_READ_ERROR(status)) {
+        return status;
+    }
+    if (!sl.version && (APR_STATUS_IS_EOF(status) ||
+                        APR_STATUS_IS_EAGAIN(status))) {
+        return status;
+    }
+
+    status = serf_bucket_response_wait_for_headers(response);
+    if (status) {
+        if (!APR_STATUS_IS_EOF(status)) {
+            return status;
+        }
+
+        /* If status is APR_EOF, there were no headers to read.
+           This can be ok in some situations, and it definitely
+           means there's no authentication requested now. */
+        return APR_SUCCESS;
+    }
+
+    if (sl.code == 401 || sl.code == 407) {
+        /* Authentication requested. */
+
+        /* Don't bother handling the authentication request if the response
+           wasn't received completely yet. Serf will call serf__handle_auth_response
+           again when more data is received. */
+        status = discard_body(response);
+        *consumed_response = 1;
+        
+        /* Discard all response body before processing authentication. */
+        if (!APR_STATUS_IS_EOF(status)) {
+            return status;
+        }
+
+        status = dispatch_auth(sl.code, request, response, baton, pool);
+        if (status != APR_SUCCESS) {
+            return status;
+        }
+
+        /* Requeue the request with the necessary auth headers. */
+        /* ### Application doesn't know about this request! */
+        if (request->ssltunnel) {
+            serf__ssltunnel_request_create(request->conn,
+                                           request->setup,
+                                           request->setup_baton);
+        } else {
+            serf_connection_priority_request_create(request->conn,
+                                                    request->setup,
+                                                    request->setup_baton);
+        }
+
+        return APR_EOF;
+    } else {
+        serf__validate_response_func_t validate_resp;
+        serf_connection_t *conn = request->conn;
+        serf_context_t *ctx = conn->ctx;
+        serf__authn_info_t *authn_info;
+        apr_status_t resp_status = APR_SUCCESS;
+
+
+        /* Validate the response server authn headers. */
+        authn_info = serf__get_authn_info_for_server(conn);
+        if (authn_info->scheme) {
+            validate_resp = authn_info->scheme->validate_response_func;
+            resp_status = validate_resp(authn_info->scheme, HOST, sl.code,
+                                        conn, request, response, pool);
+        }
+
+        /* Validate the response proxy authn headers. */
+        authn_info = &ctx->proxy_authn_info;
+        if (!resp_status && authn_info->scheme) {
+            validate_resp = authn_info->scheme->validate_response_func;
+            resp_status = validate_resp(authn_info->scheme, PROXY, sl.code,
+                                        conn, request, response, pool);
+        }
+
+        if (resp_status) {
+            /* If there was an error in the final step of the authentication,
+               consider the reponse body as invalid and discard it. */
+            status = discard_body(response);
+            *consumed_response = 1;
+
+            if (!APR_STATUS_IS_EOF(status)) {
+                return status;
+            }
+            /* The whole body was discarded, now return our error. */
+            return resp_status;
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+/**
+ * base64 encode the authentication data and build an authentication
+ * header in this format:
+ * [SCHEME] [BASE64 of auth DATA]
+ */
+void serf__encode_auth_header(const char **header,
+                              const char *scheme,
+                              const char *data, apr_size_t data_len,
+                              apr_pool_t *pool)
+{
+    apr_size_t encoded_len, scheme_len;
+    char *ptr;
+
+    encoded_len = apr_base64_encode_len(data_len);
+    scheme_len = strlen(scheme);
+
+    ptr = apr_palloc(pool, encoded_len + scheme_len + 1);
+    *header = ptr;
+
+    apr_cpystrn(ptr, scheme, scheme_len + 1);
+    ptr += scheme_len;
+    *ptr++ = ' ';
+
+    apr_base64_encode(ptr, data, data_len);
+}
+
+const char *serf__construct_realm(peer_t peer,
+                                  serf_connection_t *conn,
+                                  const char *realm_name,
+                                  apr_pool_t *pool)
+{
+    if (peer == HOST) {
+        return apr_psprintf(pool, "<%s://%s:%d> %s",
+                            conn->host_info.scheme,
+                            conn->host_info.hostname,
+                            conn->host_info.port,
+                            realm_name);
+    } else {
+        serf_context_t *ctx = conn->ctx;
+
+        return apr_psprintf(pool, "<http://%s:%d>; %s",
+                            ctx->proxy_address->hostname,
+                            ctx->proxy_address->port,
+                            realm_name);
+    }
+}
+
+serf__authn_info_t *serf__get_authn_info_for_server(serf_connection_t *conn)
+{
+    serf_context_t *ctx = conn->ctx;
+    serf__authn_info_t *authn_info;
+
+    authn_info = apr_hash_get(ctx->server_authn_info, conn->host_url,
+                              APR_HASH_KEY_STRING);
+
+    if (!authn_info) {
+        authn_info = apr_pcalloc(ctx->pool, sizeof(serf__authn_info_t));
+        apr_hash_set(ctx->server_authn_info,
+                     apr_pstrdup(ctx->pool, conn->host_url),
+                     APR_HASH_KEY_STRING, authn_info);
+    }
+
+    return authn_info;
+}

Copied: vendor/serf/serf-1.3.5/auth/auth_spnego.c (from r266726, vendor/serf/dist/auth/auth_spnego.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/serf/serf-1.3.5/auth/auth_spnego.c	Tue May 27 04:39:23 2014	(r266727, copy of r266726, vendor/serf/dist/auth/auth_spnego.c)
@@ -0,0 +1,656 @@
+/* Copyright 2009 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "auth_spnego.h"
+
+#ifdef SERF_HAVE_SPNEGO
+
+/** These functions implement SPNEGO-based Kerberos and NTLM authentication,
+ *  using either GSS-API (RFC 2743) or SSPI on Windows.
+ *  The HTTP message exchange is documented in RFC 4559.
+ **/
+
+#include <serf.h>
+#include <serf_private.h>
+#include <auth/auth.h>
+
+#include <apr.h>
+#include <apr_base64.h>
+#include <apr_strings.h>
+
+/** TODO:
+ ** - send session key directly on new connections where we already know
+ **   the server requires Kerberos authn.
+ ** - Add a way for serf to give detailed error information back to the
+ **   application.
+ **/
+
+/* Authentication over HTTP using Kerberos
+ *
+ * Kerberos involves three servers:
+ * - Authentication Server (AS): verifies users during login
+ * - Ticket-Granting Server (TGS): issues proof of identity tickets
+ * - HTTP server (S)
+ *
+ * Steps:
+ * 0. User logs in to the AS and receives a TGS ticket. On workstations
+ * where the login program doesn't support Kerberos, the user can use
+ * 'kinit'.
+ *
+ * 1. C  --> S:    GET
+ *
+ *    C <--  S:    401 Authentication Required
+ *                 WWW-Authenticate: Negotiate
+ *
+ * -> app contacts the TGS to request a session key for the HTTP service
+ *    @ target host. The returned session key is encrypted with the HTTP
+ *    service's secret key, so we can safely send it to the server.
+ *
+ * 2. C  --> S:    GET
+ *                 Authorization: Negotiate <Base64 encoded session key>
+ *                 gss_api_ctx->state = gss_api_auth_in_progress;
+ *
+ *    C <--  S:    200 OK
+ *                 WWW-Authenticate: Negotiate <Base64 encoded server
+ *                                              authentication data>
+ *
+ * -> The server returned an (optional) key to proof itself to us. We check this
+ *    key with the TGS again. If it checks out, we can return the response
+ *    body to the application.
+ *
+ * Note: It's possible that the server returns 401 again in step 2, if the
+ *       Kerberos context isn't complete yet. This means there is 3rd step
+ *       where we'll send a request with an Authorization header to the 
+ *       server. Some (simple) tests with mod_auth_kerb and MIT Kerberos 5 show
+ *       this never happens.
+ *
+ * Depending on the type of HTTP server, this handshake is required for either
+ * every new connection, or for every new request! For more info see the next
+ * comment on authn_persistence_state_t.
+ *
+ * Note: Step 1 of the handshake will only happen on the first connection, once
+ * we know the server requires Kerberos authentication, the initial requests
+ * on the other connections will include a session key, so we start at
+ * step 2 in the handshake.
+ * ### TODO: Not implemented yet!
+ */
+
+/* Current state of the authentication of the current request. */
+typedef enum {
+    gss_api_auth_not_started,
+    gss_api_auth_in_progress,
+    gss_api_auth_completed,
+} gss_api_auth_state;
+
+/**
+   authn_persistence_state_t: state that indicates if we are talking with a
+   server that requires authentication only of the first request (stateful),
+   or of each request (stateless).
+ 
+   INIT: Begin state. Authenticating the first request on this connection.
+   UNDECIDED: we haven't identified the server yet, assume STATEFUL for now.
+     Pipeline mode disabled, requests are sent only after the response off the
+     previous request arrived.
+   STATELESS: we know the server requires authentication for each request.
+     On all new requests add the Authorization header with an initial SPNEGO
+     token (created per request).
+     To keep things simple, keep the connection in one by one mode.
+     (otherwise we'd have to keep a queue of gssapi context objects to match
+      the Negotiate header of the response with the session initiated by the
+      mathing request).
+     This state is an final state.
+   STATEFUL: alright, we have authenticated the connection and for the server
+     that is enough. Don't add an Authorization header to new requests.
+     Serf will switch to pipelined mode.
+     This state is not a final state, although in practical scenario's it will
+     be. When we receive a 40x response from the server switch to STATELESS
+     mode.
+
+   We start in state init for the first request until it is authenticated.
+
+   The rest of the state machine starts with the arrival of the response to the
+   second request, and then goes on with each response:
+
+      --------
+      | INIT |     C --> S:    GET request in response to 40x of the server
+      --------                 add [Proxy]-Authorization header
+          |
+          |
+    ------------
+    | UNDECIDED|   C --> S:    GET request, assume stateful,
+    ------------               no [Proxy]-Authorization header
+          |
+          |
+          |------------------------------------------------
+          |                                               |
+          | C <-- S: 40x Authentication                   | C <-- S: 200 OK
+          |          Required                             |
+          |                                               |
+          v                                               v
+      -------------                               ------------
+    ->| STATELESS |<------------------------------| STATEFUL |<--
+    | -------------       C <-- S: 40x            ------------  |
+  * |    |                Authentication                  |     | 200 OK
+    |    /                Required                        |     |
+    -----                                                 -----/
+
+ **/
+typedef enum {
+    pstate_init,
+    pstate_undecided,
+    pstate_stateless,
+    pstate_stateful,
+} authn_persistence_state_t;
+
+
+/* HTTP Service name, used to get the session key.  */
+#define KRB_HTTP_SERVICE "HTTP"
+
+/* Stores the context information related to Kerberos authentication. */
+typedef struct
+{
+    apr_pool_t *pool;
+
+    /* GSSAPI context */
+    serf__spnego_context_t *gss_ctx;
+
+    /* Current state of the authentication cycle. */
+    gss_api_auth_state state;
+
+    /* Current persistence state. */
+    authn_persistence_state_t pstate;
+
+    const char *header;
+    const char *value;
+} gss_authn_info_t;
+
+/* On the initial 401 response of the server, request a session key from
+   the Kerberos KDC to pass to the server, proving that we are who we
+   claim to be. The session key can only be used with the HTTP service
+   on the target host. */
+static apr_status_t
+gss_api_get_credentials(serf_connection_t *conn,
+                        char *token, apr_size_t token_len,
+                        const char *hostname,
+                        const char **buf, apr_size_t *buf_len,
+                        gss_authn_info_t *gss_info)
+{
+    serf__spnego_buffer_t input_buf;
+    serf__spnego_buffer_t output_buf;
+    apr_status_t status = APR_SUCCESS;
+
+    /* If the server sent us a token, pass it to gss_init_sec_token for
+       validation. */
+    if (token) {
+        input_buf.value = token;
+        input_buf.length = token_len;
+    } else {
+        input_buf.value = 0;
+        input_buf.length = 0;
+    }
+
+    /* Establish a security context to the server. */
+    status = serf__spnego_init_sec_context(
+         conn,
+         gss_info->gss_ctx,
+         KRB_HTTP_SERVICE, hostname,
+         &input_buf,
+         &output_buf,
+         gss_info->pool,
+         gss_info->pool
+        );
+
+    switch(status) {
+    case APR_SUCCESS:
+        if (output_buf.length == 0) {
+            gss_info->state = gss_api_auth_completed;
+        } else {
+            gss_info->state = gss_api_auth_in_progress;
+        }
+        break;
+    case APR_EAGAIN:
+        gss_info->state = gss_api_auth_in_progress;
+        status = APR_SUCCESS;
+        break;
+    default:
+        return status;
+    }

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



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