Blame auth/auth.c

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