Ejemplo n.º 1
0
/* Function is called when 2xx responses are received. Normally we don't
 * have to do anything, except for the first response after the
 * authentication handshake. This specific response includes authentication
 * data which should be validated by the client (mutual authentication).
 */
apr_status_t
serf__validate_response_kerb_auth(int code,
                                    serf_connection_t *conn,
                                    serf_request_t *request,
                                    serf_bucket_t *response,
                                    apr_pool_t *pool)
{
    gss_authn_info_t *gss_info = (code == 401) ? conn->authn_baton :
        conn->proxy_authn_baton;
    serf_bucket_t *hdrs;
    const char *auth_hdr;

    hdrs = serf_bucket_response_get_headers(response);
    auth_hdr = serf_bucket_headers_get(hdrs, "WWW-Authenticate");

    if (gss_info->state != gss_api_auth_completed) {
        return do_auth(code,
                       gss_info,
                       conn,
                       auth_hdr,
                       pool);
    }

    return APR_SUCCESS;
}
Ejemplo n.º 2
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.code = code;
        ab.status = APR_SUCCESS;
        ab.request = request;
        ab.response = response;
        ab.baton = baton;
        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;
        }

        /* Iterate over all headers. Try to find a matching authentication scheme
           handler.

           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,
                               handle_auth_header,
                               &ab);
        if (ab.status != APR_SUCCESS)
            return ab.status;

        if (!ab.scheme || ab.scheme->name == NULL) {
            /* No matching authentication found. */
            return SERF_ERROR_AUTHN_NOT_SUPPORTED;
        }
    } else {
        /* Validate the response authn headers if needed. */

    }

    return APR_SUCCESS;
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
0
/* If a 200 OK was received for the CONNECT request, consider the connection
   as ready for use. */
static apr_status_t handle_response(serf_request_t *request,
                                    serf_bucket_t *response,
                                    void *handler_baton,
                                    apr_pool_t *pool)
{
    apr_status_t status;
    serf_status_line sl;
    req_ctx_t *ctx = handler_baton;
    serf_connection_t *conn = request->conn;

    /* CONNECT request was cancelled. Assuming that this is during connection
       reset, we can safely discard the request as a new one will be created
       when setting up the next connection. */
    if (!response)
        return APR_SUCCESS;

    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 && !APR_STATUS_IS_EOF(status)) {
        return status;
    }

    /* RFC 2817:  Any successful (2xx) response to a CONNECT request indicates
       that the proxy has established a connection to the requested host and
       port, and has switched to tunneling the current connection to that server
       connection.
    */
    if (sl.code >= 200 && sl.code < 300) {
        serf_bucket_t *hdrs;
        const char *val;

        conn->state = SERF_CONN_CONNECTED;

        /* Body is supposed to be empty. */
        apr_pool_destroy(ctx->pool);
        serf_bucket_destroy(conn->ssltunnel_ostream);
        serf_bucket_destroy(conn->stream);
        conn->stream = NULL;
        ctx = NULL;

        serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
                      "successfully set up ssl tunnel.\n");

        /* Fix for issue #123: ignore the "Connection: close" header here,
           leaving the header in place would make the serf's main context
           loop close this connection immediately after reading the 200 OK
           response. */

        hdrs = serf_bucket_response_get_headers(response);
        val = serf_bucket_headers_get(hdrs, "Connection");
        if (val && strcasecmp("close", val) == 0) {
            serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
                      "Ignore Connection: close header on this reponse, don't "
                      "close the connection now that the tunnel is set up.\n");
            serf__bucket_headers_remove(hdrs, "Connection");
        }

        return APR_EOF;
    }

    /* Authentication failure and 2xx Ok are handled at this point,
       the rest are errors. */
    return SERF_ERROR_SSLTUNNEL_SETUP_FAILED;
}
Ejemplo n.º 5
0
apr_status_t
serf__validate_response_digest_auth(peer_t peer,
                                    int code,
                                    serf_connection_t *conn,
                                    serf_request_t *request,
                                    serf_bucket_t *response,
                                    apr_pool_t *pool)
{
    const char *key;
    char *auth_attr;
    char *nextkv;
    const char *rspauth = NULL;
    const char *qop = NULL;
    const char *nc_str = NULL;
    serf_bucket_t *hdrs;
    digest_authn_info_t *digest_info = (peer == HOST) ? conn->authn_baton :
        conn->proxy_authn_baton;

    hdrs = serf_bucket_response_get_headers(response);

    /* Need a copy cuz we're going to write NUL characters into the string.  */
    if (peer == HOST)
        auth_attr = apr_pstrdup(pool,
            serf_bucket_headers_get(hdrs, "Authentication-Info"));
    else
        auth_attr = apr_pstrdup(pool,
            serf_bucket_headers_get(hdrs, "Proxy-Authentication-Info"));

    /* If there's no Authentication-Info header there's nothing to validate. */
    if (! auth_attr)
        return APR_SUCCESS;

    /* We're expecting a list of key=value pairs, separated by a comma.
       Ex. rspauth="8a4b8451084b082be6b105e2b7975087",
       cnonce="346531653132652d303033392d3435", nc=00000007,
       qop=auth */
    for ( ; (key = apr_strtok(auth_attr, ",", &nextkv)) != NULL; auth_attr = NULL) {
        char *val;

        val = strchr(key, '=');
        if (val == NULL)
            continue;
        *val++ = '\0';

        /* skip leading spaces */
        while (*key && *key == ' ')
            key++;

        /* If the value is quoted, then remove the quotes.  */
        if (*val == '"') {
            apr_size_t last = strlen(val) - 1;

            if (val[last] == '"') {
                val[last] = '\0';
                val++;
            }
        }

        if (strcmp(key, "rspauth") == 0)
            rspauth = val;
        else if (strcmp(key, "qop") == 0)
            qop = val;
        else if (strcmp(key, "nc") == 0)
            nc_str = val;
    }

    if (rspauth) {
        const char *ha2, *tmp, *resp_hdr_hex;
        unsigned char resp_hdr[APR_MD5_DIGESTSIZE];
        const char *req_uri = request->auth_baton;

        ha2 = build_digest_ha2(req_uri, "", qop, pool);
        tmp = apr_psprintf(pool, "%s:%s:%s:%s:%s:%s",
                           digest_info->ha1, digest_info->nonce, nc_str,
                           digest_info->cnonce, digest_info->qop, ha2);
        apr_md5(resp_hdr, tmp, strlen(tmp));
        resp_hdr_hex =  hex_encode(resp_hdr, pool);

        /* Incorrect response-digest in Authentication-Info header. */
        if (strcmp(rspauth, resp_hdr_hex) != 0) {
            return SERF_ERROR_AUTHN_FAILED;
        }
    }

    return APR_SUCCESS;
}
Ejemplo n.º 6
0
static apr_status_t handle_response(serf_request_t *request,
                                    serf_bucket_t *response,
                                    void *handler_baton,
                                    apr_pool_t *pool)
{
    const char *data;
    apr_size_t len;
    serf_status_line sl;
    apr_status_t status;
    handler_baton_t *ctx = handler_baton;

    if (!response) {
        /* Oh no!  We've been cancelled! */
        abort();
    }

    status = serf_bucket_response_status(response, &sl);
    if (status) {
        if (APR_STATUS_IS_EAGAIN(status)) {
            return APR_SUCCESS;
        }
        abort();
    }

    while (1) {
        status = serf_bucket_read(response, 2048, &data, &len);

        if (SERF_BUCKET_READ_ERROR(status))
            return status;

        /*fwrite(data, 1, len, stdout);*/

        if (!ctx->hdr_read) {
            serf_bucket_t *hdrs;
            const char *val;

            printf("Processing %s\n", ctx->path);

            hdrs = serf_bucket_response_get_headers(response);
            val = serf_bucket_headers_get(hdrs, "Content-Type");
            /* FIXME: This check isn't quite right because Content-Type could
             * be decorated; ideally strcasestr would be correct.
             */
            if (val && strcasecmp(val, "text/html") == 0) {
                ctx->is_html = 1;
                apr_pool_create(&ctx->parser_pool, NULL);
                ctx->parser = apr_xml_parser_create(ctx->parser_pool);
            }
            else {
                ctx->is_html = 0;
            }
            ctx->hdr_read = 1;
        }
        if (ctx->is_html) {
            apr_status_t xs;

            xs = apr_xml_parser_feed(ctx->parser, data, len);
            /* Uh-oh. */
            if (xs) {
#ifdef SERF_VERBOSE
                printf("XML parser error (feed): %d\n", xs);
#endif
                ctx->is_html = 0;
            }
        }

        /* are we done yet? */
        if (APR_STATUS_IS_EOF(status)) {

            if (ctx->is_html) {
                apr_xml_doc *xmld;
                apr_status_t xs;
                doc_path_t *dup;

                xs = apr_xml_parser_done(ctx->parser, &xmld);
                if (xs) {
#ifdef SERF_VERBOSE
                    printf("XML parser error (done): %d\n", xs);
#endif
                    return xs;
                }
                dup = (doc_path_t*)
                    serf_bucket_mem_alloc(ctx->doc_queue_alloc,
                                          sizeof(doc_path_t));
                dup->doc = xmld;
                dup->path = (char*)serf_bucket_mem_alloc(ctx->doc_queue_alloc,
                                                         ctx->path_len);
                memcpy(dup->path, ctx->path, ctx->path_len);
                dup->pool = ctx->parser_pool;

                *(doc_path_t **)apr_array_push(ctx->doc_queue) = dup;

                apr_thread_cond_signal(ctx->doc_queue_condvar);
            }

            apr_atomic_dec32(ctx->requests_outstanding);
            serf_bucket_mem_free(ctx->allocator, ctx->path);
            if (ctx->query) {
                serf_bucket_mem_free(ctx->allocator, ctx->query);
                serf_bucket_mem_free(ctx->allocator, ctx->full_path);
            }
            if (ctx->fragment) {
                serf_bucket_mem_free(ctx->allocator, ctx->fragment);
            }
            serf_bucket_mem_free(ctx->allocator, ctx);
            return APR_EOF;
        }

        /* have we drained the response so far? */
        if (APR_STATUS_IS_EAGAIN(status))
            return APR_SUCCESS;

        /* loop to read some more. */
    }
    /* NOTREACHED */
}
Ejemplo n.º 7
0
static apr_status_t handle_response(serf_request_t *request,
                                    serf_bucket_t *response,
                                    void *handler_baton,
                                    apr_pool_t *pool)
{
    serf_status_line sl;
    apr_status_t status;
    handler_baton_t *ctx = handler_baton;

    if (!response) {
        /* A NULL response probably means that the connection was closed while
           this request was already written. Just requeue it. */
        serf_connection_t *conn = serf_request_get_conn(request);

        serf_connection_request_create(conn, setup_request, handler_baton);
        return APR_SUCCESS;
    }

    status = serf_bucket_response_status(response, &sl);
    if (status) {
        return status;
    }

    while (1) {
        struct iovec vecs[64];
        int vecs_read;
        apr_size_t bytes_written;

        status = serf_bucket_read_iovec(response, 8000, 64, vecs, &vecs_read);
        if (SERF_BUCKET_READ_ERROR(status))
            return status;

        /* got some data. print it out. */
        if (vecs_read) {
            apr_file_writev(ctx->output_file, vecs, vecs_read, &bytes_written);
        }

        /* are we done yet? */
        if (APR_STATUS_IS_EOF(status)) {
            if (ctx->print_headers) {
                serf_bucket_t *hdrs;
                hdrs = serf_bucket_response_get_headers(response);
                while (1) {
                    status = serf_bucket_read_iovec(hdrs, 8000, 64, vecs,
                                                    &vecs_read);

                    if (SERF_BUCKET_READ_ERROR(status))
                        return status;

                    if (vecs_read) {
                        apr_file_writev(ctx->output_file, vecs, vecs_read,
                                        &bytes_written);
                    }
                    if (APR_STATUS_IS_EOF(status)) {
                        break;
                    }
                }
            }

            apr_atomic_inc32(&ctx->completed_requests);
            return APR_EOF;
        }

        /* have we drained the response so far? */
        if (APR_STATUS_IS_EAGAIN(status))
            return status;

        /* loop to read some more. */
    }
    /* NOTREACHED */
}
Ejemplo n.º 8
0
/* Function is called when 2xx responses are received. Normally we don't
 * have to do anything, except for the first response after the
 * authentication handshake. This specific response includes authentication
 * data which should be validated by the client (mutual authentication).
 */
apr_status_t
serf__validate_response_spnego_auth(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)
{
    serf_context_t *ctx = conn->ctx;
    gss_authn_info_t *gss_info;
    const char *auth_hdr_name;

    /* TODO: currently this function is only called when a response includes
       an Authenticate header. This header is optional. If the server does
       not provide this header on the first 2xx response, we will not promote
       the connection from undecided to stateful. This won't break anything,
       but means we stay in non-pipelining mode. */
    serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
                  "Validate Negotiate response header.\n");

    if (peer == HOST) {
        gss_info = conn->authn_info.baton;
        auth_hdr_name = "WWW-Authenticate";
    } else {
        gss_info = ctx->proxy_authn_info.baton;
        auth_hdr_name = "Proxy-Authenticate";
    }

    if (gss_info->state != gss_api_auth_completed) {
        serf_bucket_t *hdrs;
        const char *auth_hdr_val;
        apr_status_t status;

        hdrs = serf_bucket_response_get_headers(response);
        auth_hdr_val = get_auth_header(hdrs, auth_hdr_name, scheme->name,
                                       pool);

        if (auth_hdr_val) {
            status = do_auth(peer, code, gss_info, conn, request, auth_hdr_val,
                             pool);
            if (status) {
                return status;
            }
        } else {
            /* No Authenticate headers, nothing to validate: authentication
               completed.*/
            gss_info->state = gss_api_auth_completed;

            serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
                          "SPNEGO handshake completed.\n");
        }
    }

    if (gss_info->state == gss_api_auth_completed) {
        switch(gss_info->pstate) {
            case pstate_init:
                /* Authentication of the first request is done. */
                gss_info->pstate = pstate_undecided;
                break;
            case pstate_undecided:
                /* The server didn't request for authentication even though
                   we didn't add an Authorization header to previous
                   request. That means it supports persistent authentication. */
                gss_info->pstate = pstate_stateful;
                serf_connection_set_max_outstanding_requests(conn, 0);
                break;
            default:
                /* Nothing to do here. */
                break;
        }
    }

    return APR_SUCCESS;
}
Ejemplo n.º 9
0
static apr_status_t 
s_handle_response(serf_request_t *UNUSED(request), serf_bucket_t *response, void *handler_ctx, apr_pool_t *UNUSED(pool))
{
  const char      *data;
  apr_size_t      len;
  serf_status_line sl;
  apr_status_t     rv;
  handler_ctx_t  *ctx = handler_ctx;

  rv = serf_bucket_response_status(response, &sl);
  if (rv != APR_SUCCESS) {
    if (APR_STATUS_IS_EAGAIN(rv)) {
      return rv;
    }
    ctx->rv = rv;
    apr_atomic_dec32(&ctx->requests_outstanding); 
    return rv;
  }
  ctx->reason = sl.reason;
  ctx->response_code = sl.code;

  while (1) {
    rv = serf_bucket_read(response, 2048, &data, &len);
    if (SERF_BUCKET_READ_ERROR(rv)) {
      ctx->rv = rv;
      apr_atomic_dec32(&ctx->requests_outstanding);
      DBG(ctx->r, "REQ[%X] (ERROR)", TO_ADDR(ctx->r));
      DBG(ctx->r,"REQ[%X] end %s()",TO_ADDR(ctx->r),__func__);
      return rv;
    }
    if (APR_STATUS_IS_EAGAIN(rv)) {
      /* 0 byte return if EAGAIN returned. */
      DBG(ctx->r,"REQ[%X] (EAGAIN) len:[%d]", TO_ADDR(ctx->r), (int)len);
      DBG(ctx->r,"REQ[%X] end %s()",TO_ADDR(ctx->r),__func__);
      return rv;
    }

    if (len > 0) {
      if (! ctx->response) {
        ctx->response = apr_palloc(ctx->pool, len);
        ctx->response[0] = 0;
        ctx->response_len = 0;
      }
      else {
        char *tmp = apr_palloc(ctx->pool, ctx->response_len);
        memcpy(tmp, ctx->response, ctx->response_len);
        ctx->response = apr_palloc(ctx->pool, ctx->response_len + len);
        memcpy(ctx->response, tmp, ctx->response_len);
      }
      memcpy(&ctx->response[ctx->response_len], data, len);
      ctx->response_len += len;
      ctx->response[ctx->response_len] = 0;
    }
    
    if (APR_STATUS_IS_EOF(rv)) {
      serf_bucket_t *hdrs;
      char *tmp_headers = "";
      hdrs = serf_bucket_response_get_headers(response);
      while (1) {
        rv = serf_bucket_read(hdrs, 2048, &data, &len);
        if (SERF_BUCKET_READ_ERROR(rv))
          return rv;
        tmp_headers = apr_pstrcat(ctx->pool, tmp_headers, apr_psprintf(ctx->pool , "%.*s", (unsigned int)len, data), NULL);
        if (APR_STATUS_IS_EOF(rv)) {
          break;
        }
      }
      ctx->headers_out = apr_table_make(ctx->pool, 0);

      char *pstat;
      char *pair = NULL;
      for (;;) {
        pair = apr_strtok(tmp_headers, "\n", &pstat);
        if (!pair) break;
        tmp_headers = NULL;
        char *key;
        char *val;

        char *tpair = apr_pstrdup(ctx->pool, pair);
        key = tpair;
        val = strchr(tpair, ':');
        if (val) {
          *val = 0;
          val++;
          key = qs_trim_string(ctx->pool, key);
          val = qs_trim_string(ctx->pool, val);
          DBG(ctx->r,"REQ[%X] key:[%s], val:[%s]", TO_ADDR(ctx->r),key, val);
          apr_table_add(ctx->headers_out, key, val);
        }
      }
      ctx->rv = APR_SUCCESS;
      apr_atomic_dec32(&ctx->requests_outstanding);
      DBG(ctx->r,"REQ[%X] (NORMAL)", TO_ADDR(ctx->r));
      DBG(ctx->r,"REQ[%X] end %s()",TO_ADDR(ctx->r),__func__);
      return APR_EOF;
    }

    if (APR_STATUS_IS_EAGAIN(rv)) {
      DBG(ctx->r,"REQ[%X] (EAGAIN)", TO_ADDR(ctx->r));
      DBG(ctx->r,"REQ[%X] end %s()",TO_ADDR(ctx->r),__func__);
      return rv;
    }
  }
}
Ejemplo n.º 10
0
Archivo: auth.c Proyecto: vocho/openqnx
svn_error_t *
svn_ra_serf__handle_auth(int code,
                         svn_ra_serf__session_t *session,
                         svn_ra_serf__connection_t *conn,
                         serf_request_t *request,
                         serf_bucket_t *response,
                         apr_pool_t *pool)
{
  serf_bucket_t *hdrs;
  const svn_ra_serf__auth_protocol_t *prot;
  char *auth_name, *auth_attr, *auth_hdr, *header, *header_attr;
  svn_error_t *cached_err;

  hdrs = serf_bucket_response_get_headers(response);
  if (code == 401)
    auth_hdr = (char*)serf_bucket_headers_get(hdrs, "WWW-Authenticate");
  else if (code == 407)
    auth_hdr = (char*)serf_bucket_headers_get(hdrs, "Proxy-Authenticate");

  if (!auth_hdr)
    {
      if (session->auth_protocol)
        return svn_error_createf(SVN_ERR_AUTHN_FAILED, NULL,
                                 "%s Authentication failed",
                                 session->auth_protocol->auth_name);
      else
        return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL, NULL);
    }

  /* If multiple *-Authenticate headers are found, serf will combine them into
     one header, with the values separated by a comma. */
  header = apr_strtok(auth_hdr, ",", &header_attr);

  while (header)
    {
      svn_boolean_t proto_found = FALSE;
      auth_name = apr_strtok(header, " ", &auth_attr);

      cached_err = SVN_NO_ERROR;

      /* Find the matching authentication handler.
         Note that we don't reuse the auth protocol stored in the session,
         as that may have changed. (ex. fallback from ntlm to basic.) */
      for (prot = serf_auth_protocols; prot->code != 0; ++prot)
        {
          if (code == prot->code && strcmp(auth_name, prot->auth_name) == 0)
            {
              svn_serf__auth_handler_func_t handler = prot->handle_func;
              svn_error_t *err = NULL;

              /* If this is the first time we use this protocol in this session,
                 make sure to initialize the authentication part of the session
                 first. */
              if (code == 401 && session->auth_protocol != prot)
                {
                  err = prot->init_conn_func(session, conn, session->pool);
                  if (err == SVN_NO_ERROR)
                    session->auth_protocol = prot;
                  else
                    session->auth_protocol = NULL;
                }
             else if (code == 407 && session->proxy_auth_protocol != prot)
                {
                  err = prot->init_conn_func(session, conn, session->pool);
                  if (err == SVN_NO_ERROR)
                    session->proxy_auth_protocol = prot;
                  else
                    session->proxy_auth_protocol = NULL;
                }

              if (err == SVN_NO_ERROR)
                {
                  proto_found = TRUE;
                  err = handler(session, conn, request, response,
                                header, auth_attr, session->pool);
                }
              if (err)
                {
                  /* If authentication fails, cache the error for now. Try the
                     next available scheme. If there's none raise the error. */
                  proto_found = FALSE;
                  prot = NULL;
                  if (cached_err)
                    svn_error_clear(cached_err);
                  cached_err = err;
                }

              break;
            }
        }
      if (proto_found)
        break;

      /* Try the next Authentication header. */
      header = apr_strtok(NULL, ",", &header_attr);
    }

  SVN_ERR(cached_err);

  if (!prot || prot->auth_name == NULL)
    {
      /* Support more authentication mechanisms. */
      return svn_error_createf(SVN_ERR_AUTHN_FAILED, NULL,
                               "%s authentication not supported.\n"
                               "Authentication failed", auth_name);
    }

  return SVN_NO_ERROR;
}
Ejemplo n.º 11
0
static apr_status_t handle_response(serf_request_t *request,
                                    serf_bucket_t *response,
                                    void *vbaton,
                                    apr_pool_t *pool)
{
    apr_status_t rv;
    s_baton_t *ctx = vbaton;
    const char *data;
    apr_size_t len;
    serf_status_line sl;

    if (response == NULL) {
        ctx->rstatus = HTTP_INTERNAL_SERVER_ERROR;
        return APR_EGENERAL;
    }

    /* XXXXXXX: Create better error message. */
    rv = serf_bucket_response_status(response, &sl);
    if (rv) {
        if (APR_STATUS_IS_EAGAIN(rv)) {
            return APR_SUCCESS;
        }

        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, ctx->r, APLOGNO(01121) "serf_bucket_response_status...");

        ctx->rstatus = HTTP_INTERNAL_SERVER_ERROR;

        if (mpm_supprts_serf) {
            ap_mpm_register_timed_callback(apr_time_from_msec(1),
                                           timed_cleanup_callback, ctx);
        }

        return rv;
    }

    /**
     * XXXXX: If I understood serf buckets better, it might be possible to not
     * copy all of the data here, and better stream it to the client.
     **/

    do {
        apr_brigade_cleanup(ctx->tmpbb);
        rv = serf_bucket_read(response, AP_IOBUFSIZE, &data, &len);

        if (SERF_BUCKET_READ_ERROR(rv)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, ctx->r, APLOGNO(01122) "serf_bucket_read(response)");
            return rv;
        }

        if (!ctx->done_headers) {
            serf_bucket_t *hdrs;
            serf_status_line line;

            /* TODO: improve */
            serf_bucket_response_status(response, &line);
            ctx->r->status = line.code;

            hdrs = serf_bucket_response_get_headers(response);
            serf_bucket_headers_do(hdrs, copy_headers_out, ctx);
            ctx->done_headers = 1;
        }


        if (len > 0) {
            /* TODO: make APR bucket <-> serf bucket stuff more magical. */
            apr_brigade_write(ctx->tmpbb, NULL, NULL, data, len);
        }

        if (APR_STATUS_IS_EOF(rv)) {
            ctx->keep_reading = 0;

            ctx->rstatus = ap_pass_brigade(ctx->r->output_filters, ctx->tmpbb);

            if (mpm_supprts_serf) {
                ap_mpm_register_timed_callback(apr_time_from_msec(1),
                                               timed_cleanup_callback, ctx);
            }
            return APR_EOF;
        }

        ctx->rstatus = ap_pass_brigade(ctx->r->output_filters, ctx->tmpbb);

        /* XXXX: Should we send a flush now? */
        if (APR_STATUS_IS_EAGAIN(rv)) {
            return APR_SUCCESS;
        }

    } while (1);
}