mod_authnz_fcgi.c revision 7a42584e6f09102c6776454f090b98a58fd590eb
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein/* Licensed to the Apache Software Foundation (ASF) under one or more
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * contributor license agreements. See the NOTICE file distributed with
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * this work for additional information regarding copyright ownership.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * The ASF licenses this file to You under the Apache License, Version 2.0
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * (the "License"); you may not use this file except in compliance with
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * the License. You may obtain a copy of the License at
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * http://www.apache.org/licenses/LICENSE-2.0
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Unless required by applicable law or agreed to in writing, software
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * distributed under the License is distributed on an "AS IS" BASIS,
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * See the License for the specific language governing permissions and
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * limitations under the License.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein */
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "apr_hash.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "apr_lib.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "apr_strings.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "ap_provider.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "httpd.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "http_config.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "http_core.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "http_protocol.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "http_request.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "http_log.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "util_script.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "ap_provider.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "mod_auth.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "util_fcgi.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein#include "ap_mmn.h"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein
b0fb330a8581c8bfab5e523084f9f39264a52b12gsteinmodule AP_MODULE_DECLARE_DATA authnz_fcgi_module;
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein
b0fb330a8581c8bfab5e523084f9f39264a52b12gsteintypedef struct {
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein const char *name; /* provider name */
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein const char *backend; /* backend address, as configured */
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein const char *host;
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein apr_port_t port;
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein apr_sockaddr_t *backend_addrs;
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein int is_authn;
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein int is_authz;
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein} fcgi_provider_conf;
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein
b0fb330a8581c8bfab5e523084f9f39264a52b12gsteintypedef struct {
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein const char *name; /* provider name */
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein const char *default_user; /* this is user if authorizer returns
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * success and a user expression yields
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * empty string
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein */
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein ap_expr_info_t *user_expr; /* expr to evaluate to set r->user */
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein char authoritative; /* fail request if user is rejected? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein char require_basic_auth; /* fail if client didn't send credentials? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein} fcgi_dir_conf;
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein
b0fb330a8581c8bfab5e523084f9f39264a52b12gsteintypedef struct {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* If an "authnz" provider successfully authenticates, record
f4c310fd2555c6faca1f980f00b161eadb089023gstein * the provider name here for checking during authz.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *successful_authnz_provider;
f4c310fd2555c6faca1f980f00b161eadb089023gstein} fcgi_request_notes;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_hash_t *fcgi_authn_providers, *fcgi_authz_providers;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#define FCGI_IO_TIMEOUT apr_time_from_sec(30)
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#ifndef NON200_RESPONSE_BUF_LEN
f4c310fd2555c6faca1f980f00b161eadb089023gstein#define NON200_RESPONSE_BUF_LEN 8192
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* fcgi://{hostname|IPv4|IPv6}:port[/] */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#define FCGI_BACKEND_REGEX_STR "m%^fcgi://(.*):(\\d{1,5})/?$%"
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * utility function to connect to a peer; generally useful, but
f4c310fd2555c6faca1f980f00b161eadb089023gstein * wait for AF_UNIX support in this mod before thinking about how
f4c310fd2555c6faca1f980f00b161eadb089023gstein * to make it available to other modules
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t connect_to_peer(apr_socket_t **newsock,
f4c310fd2555c6faca1f980f00b161eadb089023gstein request_rec *r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_sockaddr_t *backend_addrs,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *backend_name,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_interval_time_t timeout)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv = APR_EINVAL; /* returned if no backend addr was provided
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein int connected = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_sockaddr_t *addr = backend_addrs;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (addr && !connected) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein int loglevel = addr->next ? APLOG_DEBUG : APLOG_ERR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_socket_create(newsock, addr->family,
f4c310fd2555c6faca1f980f00b161eadb089023gstein SOCK_STREAM, 0, r->pool);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, loglevel, rv, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02494) "error creating family %d socket "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "for target %s",
f4c310fd2555c6faca1f980f00b161eadb089023gstein addr->family, backend_name);
f4c310fd2555c6faca1f980f00b161eadb089023gstein addr = addr->next;
f4c310fd2555c6faca1f980f00b161eadb089023gstein continue;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_opt_set(*newsock, APR_TCP_NODELAY, 1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_timeout_set(*newsock,
f4c310fd2555c6faca1f980f00b161eadb089023gstein timeout ? timeout : r->server->timeout);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_socket_connect(*newsock, addr);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_close(*newsock);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, loglevel, rv, r,
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein APLOGNO(02495) "attempt to connect to %pI (%s) "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "failed", addr, backend_name);
f4c310fd2555c6faca1f980f00b161eadb089023gstein addr = addr->next;
f4c310fd2555c6faca1f980f00b161eadb089023gstein continue;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein connected = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein#undef FN_LOG_MARK
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void log_provider_info(const fcgi_provider_conf *conf, request_rec *r)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02496) "name %s, backend %s, host %s, port %d, "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "first address %pI, %c%c",
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->name,
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->backend,
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->host,
f4c310fd2555c6faca1f980f00b161eadb089023gstein (int)conf->port,
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->backend_addrs,
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->is_authn ? 'N' : '_',
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->is_authz ? 'Z' : '_');
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void setupenv(request_rec *r, const char *password, const char *apache_role)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_add_common_vars(r);
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein ap_add_cgi_vars(r);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_setn(r->subprocess_env, "FCGI_ROLE", AP_FCGI_AUTHORIZER_STR);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (apache_role) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_setn(r->subprocess_env, "FCGI_APACHE_ROLE", apache_role);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (password) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_setn(r->subprocess_env, "REMOTE_PASSWD", password);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Drop the variables CONTENT_LENGTH, PATH_INFO, PATH_TRANSLATED,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * SCRIPT_NAME and most Hop-By-Hop headers - EXCEPT we will pass
f4c310fd2555c6faca1f980f00b161eadb089023gstein * PROXY_AUTH to allow CGI to perform proxy auth for httpd
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_unset(r->subprocess_env, "CONTENT_LENGTH");
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_unset(r->subprocess_env, "PATH_INFO");
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_unset(r->subprocess_env, "PATH_TRANSLATED");
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_unset(r->subprocess_env, "SCRIPT_NAME");
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_unset(r->subprocess_env, "HTTP_KEEP_ALIVE");
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_unset(r->subprocess_env, "HTTP_TE");
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_unset(r->subprocess_env, "HTTP_TRAILER");
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_unset(r->subprocess_env, "HTTP_TRANSFER_ENCODING");
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_unset(r->subprocess_env, "HTTP_UPGRADE");
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Connection hop-by-hop header to prevent the CGI from hanging */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_setn(r->subprocess_env, "HTTP_CONNECTION", "close");
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t recv_data(const fcgi_provider_conf *conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein request_rec *r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_t *s,
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *buf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t *buflen)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_socket_recv(s, buf, buflen);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02497) "Couldn't read from backend %s",
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->backend);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#if AP_MODULE_MAGIC_AT_LEAST(20130702,2)
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rdata(APLOG_MARK, APLOG_TRACE5, r, "FastCGI data received",
f4c310fd2555c6faca1f980f00b161eadb089023gstein buf, *buflen, AP_LOG_DATA_SHOW_OFFSET);
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein return APR_SUCCESS;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t recv_data_full(const fcgi_provider_conf *conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein request_rec *r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_t *s,
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *buf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t buflen)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t readlen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t cumulative_len = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein do {
f4c310fd2555c6faca1f980f00b161eadb089023gstein readlen = buflen - cumulative_len;
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = recv_data(conf, r, s, buf + cumulative_len, &readlen);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein return rv;
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein cumulative_len += readlen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein } while (cumulative_len < buflen);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein return APR_SUCCESS;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t sendv_data(const fcgi_provider_conf *conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein request_rec *r,
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein apr_socket_t *s,
f4c310fd2555c6faca1f980f00b161eadb089023gstein struct iovec *vec,
f4c310fd2555c6faca1f980f00b161eadb089023gstein int nvec,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t *len)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t to_write = 0, written = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv = APR_SUCCESS;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int i, offset;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < nvec; i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein to_write += vec[i].iov_len;
f4c310fd2555c6faca1f980f00b161eadb089023gstein#if AP_MODULE_MAGIC_AT_LEAST(20130702,2)
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein ap_log_rdata(APLOG_MARK, APLOG_TRACE5, r, "FastCGI data sent",
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[i].iov_base, vec[i].iov_len, AP_LOG_DATA_SHOW_OFFSET);
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein offset = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (to_write) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t n = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_socket_sendv(s, vec + offset, nvec - offset, &n);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02498) "Sending data to %s failed",
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->backend);
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein if (n > 0) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein written += n;
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (written >= to_write)
f4c310fd2555c6faca1f980f00b161eadb089023gstein break; /* short circuit out */
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = offset; i < nvec; ) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (n >= vec[i].iov_len) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein offset++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein n -= vec[i++].iov_len;
f4c310fd2555c6faca1f980f00b161eadb089023gstein } else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[i].iov_len -= n;
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[i].iov_base = (char *) vec[i].iov_base + n;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein *len = written;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagsteinstatic apr_status_t send_begin_request(request_rec *r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const fcgi_provider_conf *conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_t *s, int role,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_uint16_t request_id)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein struct iovec vec[2];
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_header header;
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned char farray[AP_FCGI_HEADER_LEN];
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_begin_request_body brb;
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned char abrb[AP_FCGI_HEADER_LEN];
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t len;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_fill_in_header(&header, AP_FCGI_BEGIN_REQUEST, request_id,
f4c310fd2555c6faca1f980f00b161eadb089023gstein sizeof(abrb), 0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_fill_in_request_body(&brb, role, 0 /* *NOT* AP_FCGI_KEEP_CONN */);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_header_to_array(&header, farray);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_begin_request_body_to_array(&brb, abrb);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[0].iov_base = (void *)farray;
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[0].iov_len = sizeof(farray);
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[1].iov_base = (void *)abrb;
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[1].iov_len = sizeof(abrb);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return sendv_data(conf, r, s, vec, 2, &len);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t send_environment(apr_socket_t *s,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const fcgi_provider_conf *conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein request_rec *r, apr_uint16_t request_id,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_t *temp_pool)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *fn = "send_environment";
f4c310fd2555c6faca1f980f00b161eadb089023gstein const apr_array_header_t *envarr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const apr_table_entry_t *elts;
f4c310fd2555c6faca1f980f00b161eadb089023gstein struct iovec vec[2];
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_header header;
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned char farray[AP_FCGI_HEADER_LEN];
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *body;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t avail_len, len, required_len;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int i, next_elem, starting_elem;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein envarr = apr_table_elts(r->subprocess_env);
f4c310fd2555c6faca1f980f00b161eadb089023gstein elts = (const apr_table_entry_t *) envarr->elts;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (APLOG_R_IS_LEVEL(r, APLOG_TRACE2)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < envarr->nelts; ++i) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!elts[i].key) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein continue;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "%s: '%s': '%s'",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, elts[i].key,
f4c310fd2555c6faca1f980f00b161eadb089023gstein !strcmp(elts[i].key, "REMOTE_PASSWD") ?
f4c310fd2555c6faca1f980f00b161eadb089023gstein "XXXXXXXX" : elts[i].val);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Send envvars over in as many FastCGI records as it takes, */
f4c310fd2555c6faca1f980f00b161eadb089023gstein next_elem = 0; /* starting with the first one */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein avail_len = 16 * 1024; /* our limit per record, which could have been up
f4c310fd2555c6faca1f980f00b161eadb089023gstein * to AP_FCGI_MAX_CONTENT_LEN
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (next_elem < envarr->nelts) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein starting_elem = next_elem;
f4c310fd2555c6faca1f980f00b161eadb089023gstein required_len = ap_fcgi_encoded_env_len(r->subprocess_env,
f4c310fd2555c6faca1f980f00b161eadb089023gstein avail_len,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &next_elem);
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!required_len) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (next_elem < envarr->nelts) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02499) "couldn't encode envvar '%s' in %"
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_SIZE_T_FMT " bytes",
f4c310fd2555c6faca1f980f00b161eadb089023gstein elts[next_elem].key, avail_len);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* skip this envvar and continue */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ++next_elem;
f4c310fd2555c6faca1f980f00b161eadb089023gstein continue;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* only an unused element at the end of the array */
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02500) "required len for encoding envvars: %"
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_SIZE_T_FMT ", %d/%d elems processed so far",
f4c310fd2555c6faca1f980f00b161eadb089023gstein required_len, next_elem, envarr->nelts);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein body = apr_palloc(temp_pool, required_len);
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = ap_fcgi_encode_env(r, r->subprocess_env, body, required_len,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &starting_elem);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we pre-compute, so we can't run out of space */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_assert(rv == APR_SUCCESS);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* compute and encode must be in sync */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_assert(starting_elem == next_elem);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_fill_in_header(&header, AP_FCGI_PARAMS, request_id,
f4c310fd2555c6faca1f980f00b161eadb089023gstein (apr_uint16_t)required_len, 0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_header_to_array(&header, farray);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[0].iov_base = (void *)farray;
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[0].iov_len = sizeof(farray);
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[1].iov_base = body;
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[1].iov_len = required_len;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = sendv_data(conf, r, s, vec, 2, &len);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_clear(temp_pool);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Envvars sent, so say we're done */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_fill_in_header(&header, AP_FCGI_PARAMS, request_id, 0, 0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_header_to_array(&header, farray);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[0].iov_base = (void *)farray;
f4c310fd2555c6faca1f980f00b161eadb089023gstein vec[0].iov_len = sizeof(farray);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return sendv_data(conf, r, s, vec, 1, &len);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This header-state logic is from mod_proxy_fcgi.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinenum {
f4c310fd2555c6faca1f980f00b161eadb089023gstein HDR_STATE_READING_HEADERS,
f4c310fd2555c6faca1f980f00b161eadb089023gstein HDR_STATE_GOT_CR,
f4c310fd2555c6faca1f980f00b161eadb089023gstein HDR_STATE_GOT_CRLF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein HDR_STATE_GOT_CRLFCR,
f4c310fd2555c6faca1f980f00b161eadb089023gstein HDR_STATE_GOT_LF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein HDR_STATE_DONE_WITH_HEADERS
f4c310fd2555c6faca1f980f00b161eadb089023gstein};
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Try to find the end of the script headers in the response from the back
f4c310fd2555c6faca1f980f00b161eadb089023gstein * end fastcgi server. STATE holds the current header parsing state for this
f4c310fd2555c6faca1f980f00b161eadb089023gstein * request.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Returns 0 if it can't find the end of the headers, and 1 if it found the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * end of the headers. */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int handle_headers(request_rec *r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein int *state,
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *readbuf)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *itr = readbuf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (*itr) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (*itr == '\r') {
f4c310fd2555c6faca1f980f00b161eadb089023gstein switch (*state) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein case HDR_STATE_GOT_CRLF:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *state = HDR_STATE_GOT_CRLFCR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein default:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *state = HDR_STATE_GOT_CR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (*itr == '\n') {
f4c310fd2555c6faca1f980f00b161eadb089023gstein switch (*state) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein case HDR_STATE_GOT_LF:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *state = HDR_STATE_DONE_WITH_HEADERS;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein case HDR_STATE_GOT_CR:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *state = HDR_STATE_GOT_CRLF;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein case HDR_STATE_GOT_CRLFCR:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *state = HDR_STATE_DONE_WITH_HEADERS;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein default:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *state = HDR_STATE_GOT_LF;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein *state = HDR_STATE_READING_HEADERS;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (*state == HDR_STATE_DONE_WITH_HEADERS)
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein ++itr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (*state == HDR_STATE_DONE_WITH_HEADERS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * handle_response() is based on mod_proxy_fcgi's dispatch()
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t handle_response(const fcgi_provider_conf *conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein request_rec *r, apr_socket_t *s,
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein apr_pool_t *temp_pool,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_uint16_t request_id,
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *rspbuf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t *rspbuflen)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_bucket *b;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_bucket_brigade *ob;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t orspbuflen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv = APR_SUCCESS;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *fn = "handle_response";
f4c310fd2555c6faca1f980f00b161eadb089023gstein int header_state = HDR_STATE_READING_HEADERS;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int seen_end_of_headers = 0, done = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein if (rspbuflen) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein orspbuflen = *rspbuflen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein *rspbuflen = 0; /* unless we actually read something */
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ob = apr_brigade_create(r->pool, r->connection->bucket_alloc);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (!done && rv == APR_SUCCESS) { /* Keep reading FastCGI records until
f4c310fd2555c6faca1f980f00b161eadb089023gstein * we get AP_FCGI_END_REQUEST (done)
f4c310fd2555c6faca1f980f00b161eadb089023gstein * or an error occurs.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t readbuflen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_uint16_t clen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_uint16_t rid;
f4c310fd2555c6faca1f980f00b161eadb089023gstein char readbuf[AP_IOBUFSIZE + 1];
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned char farray[AP_FCGI_HEADER_LEN];
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned char plen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned char type;
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned char version;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = recv_data_full(conf, r, s, (char *)farray, AP_FCGI_HEADER_LEN);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02501) "%s: Error occurred before reading "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "entire header", fn);
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_fcgi_header_fields_from_array(&version, &type, &rid, &clen, &plen,
f4c310fd2555c6faca1f980f00b161eadb089023gstein farray);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (version != AP_FCGI_VERSION_1) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02502) "%s: Got bogus FastCGI header "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "version %d", fn, (int)version);
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = APR_EINVAL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rid != request_id) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02503) "%s: Got bogus FastCGI header "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "request id %d, expected %d",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, rid, request_id);
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = APR_EINVAL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein recv_again: /* if we need to keep reading more of a record's content */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (clen > sizeof(readbuf) - 1) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein readbuflen = sizeof(readbuf) - 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein } else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein readbuflen = clen;
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Now get the actual content of the record.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein if (readbuflen != 0) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = recv_data(conf, r, s, readbuf, &readbuflen);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein readbuf[readbuflen] = '\0';
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein switch (type) {
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein case AP_FCGI_STDOUT: /* Response headers and optional body */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (clen != 0) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein b = apr_bucket_transient_create(readbuf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein readbuflen,
f4c310fd2555c6faca1f980f00b161eadb089023gstein r->connection->bucket_alloc);
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_BRIGADE_INSERT_TAIL(ob, b);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!seen_end_of_headers) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein int st = handle_headers(r, &header_state, readbuf);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (st == 1) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein int status;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein seen_end_of_headers = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein status =
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scan_script_header_err_brigade_ex(r, ob,
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOG_MODULE_INDEX);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02504) "%s: script header "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "parsing -> %d/%d",
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein fn, status, r->status);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rspbuf) { /* caller wants to see response body,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * if any
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t tmprv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rspbuflen) {
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein *rspbuflen = orspbuflen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein tmprv = apr_brigade_flatten(ob, rspbuf, rspbuflen);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (tmprv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* should not occur for these bucket types;
f4c310fd2555c6faca1f980f00b161eadb089023gstein * does not indicate overflow
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, tmprv, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02505) "%s: error "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "flattening response body",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (status != OK) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein r->status = status;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02506) "%s: Error parsing "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "script headers from %s",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, conf->backend);
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = APR_EINVAL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_clear(temp_pool);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We're still looking for the end of the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * headers, so this part of the data will need
f4c310fd2555c6faca1f980f00b161eadb089023gstein * to persist. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_bucket_setaside(b, temp_pool);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* If we didn't read all the data go back and get the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * rest of it. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (clen > readbuflen) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein clen -= readbuflen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein goto recv_again;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_FCGI_STDERR: /* Text to log */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (clen) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02507) "%s: Logged from %s: '%s'",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, conf->backend, readbuf);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (clen > readbuflen) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein clen -= readbuflen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein goto recv_again; /* continue reading this record */
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_FCGI_END_REQUEST:
f4c310fd2555c6faca1f980f00b161eadb089023gstein done = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein default:
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02508) "%s: Got bogus FastCGI record type "
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein "%d", fn, type);
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Read/discard any trailing padding.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (plen) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = recv_data_full(conf, r, s, readbuf, plen);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02509) "%s: Error occurred reading "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "padding",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn);
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_brigade_cleanup(ob);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv == APR_SUCCESS && !seen_end_of_headers) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = APR_EINVAL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02510) "%s: Never reached end of script headers",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* almost from mod_fcgid */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int mod_fcgid_modify_auth_header(void *vars,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *key, const char *val)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* When the application gives a 200 response, the server ignores response
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers whose names aren't prefixed with Variable- prefix, and ignores
f4c310fd2555c6faca1f980f00b161eadb089023gstein any response content */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (strncasecmp(key, "Variable-", 9) == 0)
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_setn(vars, key, val);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int fix_auth_header(void *vr, const char *key, const char *val)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein request_rec *r = vr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "moving %s->%s", key, val);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_unset(r->err_headers_out, key);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_setn(r->subprocess_env, key + 9, val);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void req_rsp(request_rec *r, const fcgi_provider_conf *conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *password, const char *apache_role,
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *rspbuf, apr_size_t *rspbuflen)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *fn = "req_rsp";
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_t *temp_pool;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t orspbuflen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_t *s;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_t *saved_subprocess_env =
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_copy(r->pool, r->subprocess_env);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rspbuflen) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein orspbuflen = *rspbuflen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein *rspbuflen = 0; /* unless we actually read something */
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_create(&temp_pool, r->pool);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein setupenv(r, password, apache_role);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = connect_to_peer(&s, r, conf->backend_addrs,
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->backend, FCGI_IO_TIMEOUT);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv == APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_uint16_t request_id = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = send_begin_request(r, conf, s, AP_FCGI_AUTHORIZER, request_id);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02511) "%s: Failed writing request to %s",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, conf->backend);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv == APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = send_environment(s, conf, r, request_id, temp_pool);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02512) "%s: Failed writing environment "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "to %s", fn, conf->backend);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* The responder owns the request body, not the authorizer.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Don't even send an empty AP_FCGI_STDIN block. libfcgi doesn't care,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * but it wasn't sent to authorizers by mod_fastcgi or mod_fcgi and
f4c310fd2555c6faca1f980f00b161eadb089023gstein * may be unhandled by the app. Additionally, the FastCGI spec does
f4c310fd2555c6faca1f980f00b161eadb089023gstein * not mention FCGI_STDIN in the Authorizer description, though it
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein * does describe FCGI_STDIN elsewhere in more general terms than
f4c310fd2555c6faca1f980f00b161eadb089023gstein * simply a wrapper for the client's request body.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv == APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rspbuflen) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein *rspbuflen = orspbuflen;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = handle_response(conf, r, s, temp_pool, request_id, rspbuf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein rspbuflen);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02514) "%s: Failed handling response "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "from %s", fn, conf->backend);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_close(s);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_destroy(temp_pool);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* some sort of mechanical problem */
f4c310fd2555c6faca1f980f00b161eadb089023gstein r->status = HTTP_INTERNAL_SERVER_ERROR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02515) "%s: Received HTTP status %d",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, r->status);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein r->subprocess_env = saved_subprocess_env;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (r->status == HTTP_OK) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* An Authorizer application's 200 response may include headers
f4c310fd2555c6faca1f980f00b161eadb089023gstein * whose names are prefixed with Variable-, and they should be
f4c310fd2555c6faca1f980f00b161eadb089023gstein * available to subsequent phases via subprocess_env (and yanked
f4c310fd2555c6faca1f980f00b161eadb089023gstein * from the client response).
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein apr_table_t *vars = apr_table_make(r->pool, 10);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_do(mod_fcgid_modify_auth_header, vars,
f4c310fd2555c6faca1f980f00b161eadb089023gstein r->err_headers_out, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_do(fix_auth_header, r, vars, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int fcgi_check_authn(request_rec *r)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *fn = "fcgi_check_authn";
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &authnz_fcgi_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *password = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const fcgi_provider_conf *conf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *prov;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *auth_type;
f4c310fd2555c6faca1f980f00b161eadb089023gstein char rspbuf[NON200_RESPONSE_BUF_LEN + 1]; /* extra byte for '\0' */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t rspbuflen = sizeof rspbuf - 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int res;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein prov = dconf && dconf->name ? dconf->name : NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!prov || !strcasecmp(prov, "None")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return DECLINED;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein auth_type = ap_auth_type(r);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02516) "%s, prov %s, authoritative %s, "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "require-basic %s, user expr? %s type %s",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, prov,
f4c310fd2555c6faca1f980f00b161eadb089023gstein dconf->authoritative ? "yes" : "no",
f4c310fd2555c6faca1f980f00b161eadb089023gstein dconf->require_basic_auth ? "yes" : "no",
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein dconf->user_expr ? "yes" : "no",
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein auth_type);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (auth_type && !strcasecmp(auth_type, "Basic")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((res = ap_get_basic_auth_pw(r, &password))) {
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein APLOGNO(02517) "%s: couldn't retrieve basic auth "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "password", fn);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (dconf->require_basic_auth) {
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein return res;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein password = NULL;
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf = apr_hash_get(fcgi_authn_providers, prov, APR_HASH_KEY_STRING);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!conf) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02518) "%s: can't find config for provider %s",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, prov);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return HTTP_INTERNAL_SERVER_ERROR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (APLOGrdebug(r)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein log_provider_info(conf, r);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein req_rsp(r, conf, password, AP_FCGI_APACHE_ROLE_AUTHENTICATOR_STR,
f4c310fd2555c6faca1f980f00b161eadb089023gstein rspbuf, &rspbuflen);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (r->status == HTTP_OK) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (dconf->user_expr) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *user = ap_expr_str_exec(r, dconf->user_expr,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &err);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (user && strlen(user)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein r->user = apr_pstrdup(r->pool, user);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02519) "%s: Setting user to '%s'",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, r->user);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (user && dconf->default_user) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein r->user = apr_pstrdup(r->pool, dconf->default_user);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (user) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02520) "%s: Failure extracting user "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "after calling authorizer: user expression "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "yielded empty string (variable not set?)",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn);
f4c310fd2555c6faca1f980f00b161eadb089023gstein r->status = HTTP_INTERNAL_SERVER_ERROR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* unexpected error, not even an empty string was returned */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02521) "%s: Failure extracting user "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "after calling authorizer: %s",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, err);
f4c310fd2555c6faca1f980f00b161eadb089023gstein r->status = HTTP_INTERNAL_SERVER_ERROR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (conf->is_authz) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* combined authn/authz phase, so app won't be invoked for authz
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Remember that the request was successfully authorized by this
f4c310fd2555c6faca1f980f00b161eadb089023gstein * provider.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_request_notes *rnotes = apr_palloc(r->pool, sizeof(*rnotes));
f4c310fd2555c6faca1f980f00b161eadb089023gstein rnotes->successful_authnz_provider = conf->name;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_set_module_config(r->request_config, &authnz_fcgi_module,
f4c310fd2555c6faca1f980f00b161eadb089023gstein rnotes);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* From the spec:
f4c310fd2555c6faca1f980f00b161eadb089023gstein * For Authorizer response status values other than "200" (OK), the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Web server denies access and sends the response status, headers,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * and content back to the HTTP client.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * But:
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This only makes sense if this authorizer is authoritative.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rspbuflen > 0 && !dconf->authoritative) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02522) "%s: Ignoring response body from non-"
f4c310fd2555c6faca1f980f00b161eadb089023gstein "authoritative authorizer", fn);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (rspbuflen > 0) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rspbuflen == sizeof rspbuf - 1) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* apr_brigade_flatten() interface :( */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02523) "%s: possible overflow handling "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "response body", fn);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein rspbuf[rspbuflen] = '\0'; /* we reserved an extra byte for '\0' */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_custom_response(r, r->status, rspbuf); /* API makes a copy */
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return r->status == HTTP_OK ?
f4c310fd2555c6faca1f980f00b161eadb089023gstein OK : dconf->authoritative ? r->status : DECLINED;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic authn_status fcgi_check_password(request_rec *r, const char *user,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *password)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *fn = "fcgi_check_password";
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *prov = apr_table_get(r->notes, AUTHN_PROVIDER_NAME_NOTE);
f4c310fd2555c6faca1f980f00b161eadb089023gstein const fcgi_provider_conf *conf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02524) "%s(%s, XXX): provider %s",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, user, prov);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!prov) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02525) "%s: provider note isn't set", fn);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTH_GENERAL_ERROR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf = apr_hash_get(fcgi_authn_providers, prov, APR_HASH_KEY_STRING);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!conf) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02526) "%s: can't find config for provider %s",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, prov);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTH_GENERAL_ERROR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (APLOGrdebug(r)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein log_provider_info(conf, r);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein req_rsp(r, conf, password,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* combined authn and authz: FCGI_APACHE_ROLE not set */
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->is_authz ? NULL : AP_FCGI_APACHE_ROLE_AUTHENTICATOR_STR,
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (r->status == HTTP_OK) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (conf->is_authz) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* combined authn/authz phase, so app won't be invoked for authz
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Remember that the request was successfully authorized by this
f4c310fd2555c6faca1f980f00b161eadb089023gstein * provider.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_request_notes *rnotes = apr_palloc(r->pool, sizeof(*rnotes));
f4c310fd2555c6faca1f980f00b161eadb089023gstein rnotes->successful_authnz_provider = conf->name;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_set_module_config(r->request_config, &authnz_fcgi_module,
f4c310fd2555c6faca1f980f00b161eadb089023gstein rnotes);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTH_GRANTED;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (r->status == HTTP_INTERNAL_SERVER_ERROR) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTH_GENERAL_ERROR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTH_DENIED;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const authn_provider fcgi_authn_provider = {
f4c310fd2555c6faca1f980f00b161eadb089023gstein &fcgi_check_password,
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL /* get-realm-hash not supported */
f4c310fd2555c6faca1f980f00b161eadb089023gstein};
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic authz_status fcgi_authz_check(request_rec *r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *require_line,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const void *parsed_require_line)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *fn = "fcgi_authz_check";
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *prov = apr_table_get(r->notes, AUTHZ_PROVIDER_NAME_NOTE);
f4c310fd2555c6faca1f980f00b161eadb089023gstein const fcgi_provider_conf *conf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02527) "%s(%s)", fn, require_line);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!prov) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02528) "%s: provider note isn't set", fn);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTHZ_GENERAL_ERROR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf = apr_hash_get(fcgi_authz_providers, prov, APR_HASH_KEY_STRING);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!conf) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02529) "%s: can't find config for provider %s",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fn, prov);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTHZ_GENERAL_ERROR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (APLOGrdebug(r)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein log_provider_info(conf, r);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!r->user) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTHZ_DENIED_NO_USER;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (conf->is_authn) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* combined authn/authz phase, so app won't be invoked for authz
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If the provider already successfully authorized this request,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * success.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_request_notes *rnotes = ap_get_module_config(r->request_config,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &authnz_fcgi_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rnotes
f4c310fd2555c6faca1f980f00b161eadb089023gstein && rnotes->successful_authnz_provider
f4c310fd2555c6faca1f980f00b161eadb089023gstein && !strcmp(rnotes->successful_authnz_provider, conf->name)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTHZ_GRANTED;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTHZ_DENIED;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein req_rsp(r, conf, NULL, AP_FCGI_APACHE_ROLE_AUTHORIZER_STR, NULL, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (r->status == HTTP_OK) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTHZ_GRANTED;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (r->status == HTTP_INTERNAL_SERVER_ERROR) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTHZ_GENERAL_ERROR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return AUTHZ_DENIED;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *fcgi_authz_parse(cmd_parms *cmd, const char *require_line,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const void **parsed_require_line)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Allowed form: Require [not] registered-provider-name<EOS>
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (strcmp(require_line, "")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return "mod_authnz_fcgi doesn't support restrictions on providers "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "(i.e., multiple require args)";
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const authz_provider fcgi_authz_provider = {
f4c310fd2555c6faca1f980f00b161eadb089023gstein &fcgi_authz_check,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &fcgi_authz_parse,
f4c310fd2555c6faca1f980f00b161eadb089023gstein};
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *fcgi_check_authn_provider(cmd_parms *cmd,
f4c310fd2555c6faca1f980f00b161eadb089023gstein void *d,
f4c310fd2555c6faca1f980f00b161eadb089023gstein int argc,
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *const argv[])
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *dname = "AuthnzFcgiCheckAuthnProvider";
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_dir_conf *dc = d;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int ca = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ca >= argc) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool, dname, ": No provider given", NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein dc->name = argv[ca];
f4c310fd2555c6faca1f980f00b161eadb089023gstein ca++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!strcasecmp(dc->name, "None")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ca < argc) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return "Options aren't supported with \"None\"";
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (ca < argc) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *var = argv[ca], *val;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int badarg = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ca++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* at present, everything needs an argument */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ca >= argc) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool, dname, ": ", var,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "needs an argument", NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein val = argv[ca];
f4c310fd2555c6faca1f980f00b161eadb089023gstein ca++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!strcasecmp(var, "Authoritative")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!strcasecmp(val, "On")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein dc->authoritative = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!strcasecmp(val, "Off")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein dc->authoritative = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein badarg = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!strcasecmp(var, "DefaultUser")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein dc->default_user = val;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!strcasecmp(var, "RequireBasicAuth")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!strcasecmp(val, "On")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein dc->require_basic_auth = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!strcasecmp(val, "Off")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein dc->require_basic_auth = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein badarg = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!strcasecmp(var, "UserExpr")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int flags = AP_EXPR_FLAG_DONT_VARY | AP_EXPR_FLAG_RESTRICTED
f4c310fd2555c6faca1f980f00b161eadb089023gstein | AP_EXPR_FLAG_STRING_RESULT;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein dc->user_expr = ap_expr_parse_cmd(cmd, val,
f4c310fd2555c6faca1f980f00b161eadb089023gstein flags, &err, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (err) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_psprintf(cmd->pool, "%s: Error parsing '%s': '%s'",
f4c310fd2555c6faca1f980f00b161eadb089023gstein dname, val, err);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool, dname, ": Unexpected option '",
f4c310fd2555c6faca1f980f00b161eadb089023gstein var, "'", NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (badarg) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool, dname, ": Bad argument '",
f4c310fd2555c6faca1f980f00b161eadb089023gstein val, "' to option '", var, "'", NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* AuthnzFcgiAuthDefineProvider {authn|authz|authnz} provider-name \
f4c310fd2555c6faca1f980f00b161eadb089023gstein * fcgi://backendhost:backendport/
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *fcgi_define_provider(cmd_parms *cmd,
f4c310fd2555c6faca1f980f00b161eadb089023gstein void *d,
f4c310fd2555c6faca1f980f00b161eadb089023gstein int argc,
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *const argv[])
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *dname = "AuthnzFcgiDefineProvider";
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_rxplus_t *fcgi_backend_regex;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *host;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *err, *stype;
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_provider_conf *conf = apr_pcalloc(cmd->pool, sizeof(*conf));
f4c310fd2555c6faca1f980f00b161eadb089023gstein int ca = 0, rc;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_backend_regex = ap_rxplus_compile(cmd->pool, FCGI_BACKEND_REGEX_STR);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!fcgi_backend_regex) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_psprintf(cmd->pool,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "%s: failed to compile regexec '%s'",
f4c310fd2555c6faca1f980f00b161eadb089023gstein dname, FCGI_BACKEND_REGEX_STR);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (err)
f4c310fd2555c6faca1f980f00b161eadb089023gstein return err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ca >= argc) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool, dname, ": No type given", NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein stype = argv[ca];
f4c310fd2555c6faca1f980f00b161eadb089023gstein ca++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!strcasecmp(stype, "authn")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->is_authn = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!strcasecmp(stype, "authz")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->is_authz = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!strcasecmp(stype, "authnz")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->is_authn = conf->is_authz = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool,
f4c310fd2555c6faca1f980f00b161eadb089023gstein dname,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ": Invalid provider type ",
f4c310fd2555c6faca1f980f00b161eadb089023gstein stype,
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ca >= argc) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool, dname, ": No provider name given", NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->name = argv[ca];
f4c310fd2555c6faca1f980f00b161eadb089023gstein ca++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ca >= argc) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool, dname, ": No backend-address given",
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein rc = ap_rxplus_exec(cmd->pool, fcgi_backend_regex, argv[ca], NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!rc || ap_rxplus_nmatch(fcgi_backend_regex) != 3) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool,
f4c310fd2555c6faca1f980f00b161eadb089023gstein dname, ": backend-address '",
f4c310fd2555c6faca1f980f00b161eadb089023gstein argv[ca],
f4c310fd2555c6faca1f980f00b161eadb089023gstein "' has invalid form",
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein host = ap_rxplus_pmatch(cmd->pool, fcgi_backend_regex, 1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (host[0] == '[' && host[strlen(host) - 1] == ']') {
f4c310fd2555c6faca1f980f00b161eadb089023gstein host += 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein host[strlen(host) - 1] = '\0';
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->port = atoi(ap_rxplus_pmatch(cmd->pool, fcgi_backend_regex, 2));
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (conf->port > 65535) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool,
f4c310fd2555c6faca1f980f00b161eadb089023gstein dname, ": backend-address '",
f4c310fd2555c6faca1f980f00b161eadb089023gstein argv[ca],
f4c310fd2555c6faca1f980f00b161eadb089023gstein "' has invalid port",
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->backend = argv[ca];
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->host = host;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ca++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_sockaddr_info_get(&conf->backend_addrs, conf->host,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_UNSPEC, conf->port, 0, cmd->pool);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, rv, NULL,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APLOGNO(02530) "Address %s could not be resolved",
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->backend);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool,
f4c310fd2555c6faca1f980f00b161eadb089023gstein dname,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ": Error resolving backend address",
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ca != argc) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(cmd->pool,
f4c310fd2555c6faca1f980f00b161eadb089023gstein dname,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ": Unexpected parameter ",
f4c310fd2555c6faca1f980f00b161eadb089023gstein argv[ca],
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (conf->is_authn) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_hash_set(fcgi_authn_providers, conf->name, APR_HASH_KEY_STRING,
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_register_auth_provider(cmd->pool, AUTHN_PROVIDER_GROUP,
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->name,
f4c310fd2555c6faca1f980f00b161eadb089023gstein AUTHN_PROVIDER_VERSION,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &fcgi_authn_provider,
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_AUTH_INTERNAL_PER_CONF);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (conf->is_authz) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_hash_set(fcgi_authz_providers, conf->name, APR_HASH_KEY_STRING,
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_register_auth_provider(cmd->pool, AUTHZ_PROVIDER_GROUP,
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->name,
f4c310fd2555c6faca1f980f00b161eadb089023gstein AUTHZ_PROVIDER_VERSION,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &fcgi_authz_provider,
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_AUTH_INTERNAL_PER_CONF);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const command_rec fcgi_cmds[] = {
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE_ARGV("AuthnzFcgiDefineProvider",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_define_provider,
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL,
f4c310fd2555c6faca1f980f00b161eadb089023gstein RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Define a FastCGI authn and/or authz provider"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE_ARGV("AuthnzFcgiCheckAuthnProvider",
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_check_authn_provider,
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL,
f4c310fd2555c6faca1f980f00b161eadb089023gstein OR_FILEINFO,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Enable/disable a FastCGI authorizer to handle "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "check_authn phase"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein {NULL}
f4c310fd2555c6faca1f980f00b161eadb089023gstein};
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int fcgi_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_t *ptemp)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_authn_providers = apr_hash_make(pconf);
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_authz_providers = apr_hash_make(pconf);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return OK;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void fcgi_register_hooks(apr_pool_t *p)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein static const char * const auth_basic_runs_after_me[] =
f4c310fd2555c6faca1f980f00b161eadb089023gstein {"mod_auth_basic.c", NULL}; /* to allow for custom response */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_hook_pre_config(fcgi_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_hook_check_authn(fcgi_check_authn, NULL, auth_basic_runs_after_me,
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_HOOK_MIDDLE, AP_AUTH_INTERNAL_PER_CONF);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void *create_dir_conf(apr_pool_t *p, char *dummy)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_dir_conf *dconf = apr_pcalloc(p, sizeof(fcgi_dir_conf));
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein dconf->authoritative = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein return dconf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void *merge_dir_conf(apr_pool_t *p, void *basev, void *overridesv)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein fcgi_dir_conf *a = (fcgi_dir_conf *)apr_pcalloc(p, sizeof(*a));
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_dir_conf *base = (fcgi_dir_conf *)basev,
f4c310fd2555c6faca1f980f00b161eadb089023gstein *over = (fcgi_dir_conf *)overridesv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* currently we just have a single directive applicable to a
f4c310fd2555c6faca1f980f00b161eadb089023gstein * directory, so if it is set then grab all fields from fcgi_dir_conf
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (over->name) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein memcpy(a, over, sizeof(*a));
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein memcpy(a, base, sizeof(*a));
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return a;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinAP_DECLARE_MODULE(authnz_fcgi) =
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein STANDARD20_MODULE_STUFF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein create_dir_conf, /* dir config creater */
f4c310fd2555c6faca1f980f00b161eadb089023gstein merge_dir_conf, /* dir merger */
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL, /* server config */
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL, /* merge server config */
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_cmds, /* command apr_table_t */
f4c310fd2555c6faca1f980f00b161eadb089023gstein fcgi_register_hooks /* register hooks */
f4c310fd2555c6faca1f980f00b161eadb089023gstein};
f4c310fd2555c6faca1f980f00b161eadb089023gstein