From owner-svn-src-all@FreeBSD.ORG Tue May 27 04:39:24 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 245ED51A; Tue, 27 May 2014 04:39:24 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 105852BF9; Tue, 27 May 2014 04:39:24 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s4R4dOgQ071437; Tue, 27 May 2014 04:39:24 GMT (envelope-from peter@svn.freebsd.org) Received: (from peter@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s4R4dNrS071432; Tue, 27 May 2014 04:39:23 GMT (envelope-from peter@svn.freebsd.org) Message-Id: <201405270439.s4R4dNrS071432@svn.freebsd.org> From: Peter Wemm Date: Tue, 27 May 2014 04:39:23 +0000 (UTC) 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 X-SVN-Group: vendor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 May 2014 04:39:24 -0000 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 +#include +#include +#include + +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, " %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 +#include +#include + +#include +#include +#include + +/** 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 + * gss_api_ctx->state = gss_api_auth_in_progress; + * + * C <-- S: 200 OK + * WWW-Authenticate: Negotiate + * + * -> 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 ***