[BACK]Return to httpd.h CVS log [TXT][DIR] Up to [local] / src / usr.sbin / httpd

File: [local] / src / usr.sbin / httpd / httpd.h (download)

Revision 1.164, Wed Nov 8 19:19:10 2023 UTC (6 months, 3 weeks ago) by millert
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, HEAD
Changes since 1.163: +2 -1 lines

Avoid a NULL dereference when handling a malformed fastcgi request.

Rework the hack to avoid a use-after-free in the fastcgi code.
Since server_fcgi() can be called by server_read_httpcontent() we
can't set clt_fcgi_error to NULL.  Instead, we implement a simple
reference count to track when a fastcgi session is in progress to
avoid closing the http session prematurely on fastcgi error.
Based on a diff from and OK by tb@.  Reported by Ben Kallus.

/*	$OpenBSD: httpd.h,v 1.164 2023/11/08 19:19:10 millert Exp $	*/

/*
 * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
 * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _HTTPD_H
#define _HTTPD_H

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/tree.h>
#include <sys/time.h>

#include <net/if.h>
#include <netinet/in.h>

#include <stdarg.h>
#include <limits.h>
#include <event.h>
#include <imsg.h>
#include <tls.h>
#include <vis.h>

#include "patterns.h"

#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif

#define CONF_FILE		"/etc/httpd.conf"
#define HTTPD_USER		"www"
#define HTTPD_SERVERNAME	"OpenBSD httpd"
#define HTTPD_DOCROOT		"/htdocs"
#define HTTPD_ERRDOCTEMPLATE	"err" /* 3-char name */
#define HTTPD_ERRDOCROOT_MAX	(PATH_MAX - sizeof("000.html"))
#define HTTPD_INDEX		"index.html"
#define HTTPD_FCGI_SOCKET	"/run/slowcgi.sock"
#define HTTPD_LOGROOT		"/logs"
#define HTTPD_ACCESS_LOG	"access.log"
#define HTTPD_ERROR_LOG		"error.log"
#define HTTPD_MAX_ALIAS_IP	16
#define HTTPD_REALM_MAX		255
#define HTTPD_LOCATION_MAX	255
#define HTTPD_DEFAULT_TYPE	{ "bin", "application", "octet-stream", NULL }
#define HTTPD_LOGVIS		VIS_NL|VIS_TAB|VIS_CSTYLE
#define HTTPD_TLS_CERT		"/etc/ssl/server.crt"
#define HTTPD_TLS_KEY		"/etc/ssl/private/server.key"
#define HTTPD_TLS_CONFIG_MAX	511
#define HTTPD_TLS_CIPHERS	"compat"
#define HTTPD_TLS_DHE_PARAMS	"none"
#define HTTPD_TLS_ECDHE_CURVES	"default"
#define HTTPD_FCGI_NAME_MAX	511
#define HTTPD_FCGI_VAL_MAX	511
#define FD_RESERVE		5

#define SERVER_MAX_CLIENTS	1024
#define SERVER_TIMEOUT		600
#define SERVER_REQUESTTIMEOUT	60
#define SERVER_CACHESIZE	-1	/* use default size */
#define SERVER_NUMPROC		3
#define SERVER_MAXHEADERLENGTH	8192
#define SERVER_MAXREQUESTS	100	/* max requests per connection */
#define SERVER_MAXREQUESTBODY	1048576	/* 1M */
#define SERVER_BACKLOG		10
#define SERVER_OUTOF_FD_RETRIES	5
#define SERVER_MAX_PREFETCH	256
#define SERVER_MIN_PREFETCHED	32
#define SERVER_HSTS_DEFAULT_AGE	31536000
#define SERVER_MAX_RANGES	4
#define SERVER_DEF_TLS_LIFETIME	(2 * 3600)
#define SERVER_MIN_TLS_LIFETIME	(60)
#define SERVER_MAX_TLS_LIFETIME	(24 * 3600)

#define MEDIATYPE_NAMEMAX	128	/* file name extension */
#define MEDIATYPE_TYPEMAX	64	/* length of type/subtype */

#define CONFIG_RELOAD		0x00
#define CONFIG_MEDIA		0x01
#define CONFIG_SERVERS		0x02
#define CONFIG_AUTH		0x04
#define CONFIG_ALL		0xff

#define FCGI_CONTENT_SIZE	65535
#define FCGI_DEFAULT_PORT	"9000"

#define PROC_PARENT_SOCK_FILENO	3
#define PROC_MAX_INSTANCES	32

enum httpchunk {
	TOREAD_UNLIMITED		= -1,
	TOREAD_HTTP_HEADER		= -2,
	TOREAD_HTTP_CHUNK_LENGTH	= -3,
	TOREAD_HTTP_CHUNK_TRAILER	= -4,
	TOREAD_HTTP_NONE		= -5,
	TOREAD_HTTP_RANGE		= TOREAD_HTTP_CHUNK_LENGTH
};

#if DEBUG
#define DPRINTF		log_debug
#else
#define DPRINTF(x...)	do {} while(0)
#endif

struct ctl_flags {
	uint8_t		 cf_opts;
	uint32_t	 cf_flags;
	uint8_t		 cf_tls_sid[TLS_MAX_SESSION_ID_LENGTH];
};

TAILQ_HEAD(kvlist, kv);
RB_HEAD(kvtree, kv);

struct kv {
	char			*kv_key;
	char			*kv_value;

	struct kvlist		 kv_children;
	struct kv		*kv_parent;
	TAILQ_ENTRY(kv)		 kv_entry;

	RB_ENTRY(kv)		 kv_node;
};

struct portrange {
	in_port_t		 val[2];
	uint8_t			 op;
};

struct address {
	struct sockaddr_storage	 ss;
	int			 ipproto;
	int			 prefixlen;
	struct portrange	 port;
	char			 ifname[IFNAMSIZ];
	TAILQ_ENTRY(address)	 entry;
};
TAILQ_HEAD(addresslist, address);

/* initially control.h */
struct control_sock {
	const char	*cs_name;
	struct event	 cs_ev;
	struct event	 cs_evt;
	int		 cs_fd;
	int		 cs_restricted;
	void		*cs_env;

	TAILQ_ENTRY(control_sock) cs_entry;
};
TAILQ_HEAD(control_socks, control_sock);

extern struct {
	struct event	 ev;
	int		 fd;
} control_state;

struct imsgev {
	struct imsgbuf		 ibuf;
	void			(*handler)(int, short, void *);
	struct event		 ev;
	struct privsep_proc	*proc;
	void			*data;
	short			 events;
};

#define IMSG_SIZE_CHECK(imsg, p) do {				\
	if (IMSG_DATA_SIZE(imsg) < sizeof(*p))			\
		fatalx("bad length imsg received");		\
} while (0)
#define IMSG_DATA_SIZE(imsg)	((imsg)->hdr.len - IMSG_HEADER_SIZE)
#define MAX_IMSG_DATA_SIZE	(MAX_IMSGSIZE - IMSG_HEADER_SIZE)

struct ctl_conn {
	TAILQ_ENTRY(ctl_conn)	 entry;
	uint8_t			 flags;
	unsigned int		 waiting;
#define CTL_CONN_NOTIFY		 0x01
	struct imsgev		 iev;

};
TAILQ_HEAD(ctl_connlist, ctl_conn);

enum imsg_type {
	IMSG_NONE,
	IMSG_CTL_OK,
	IMSG_CTL_FAIL,
	IMSG_CTL_VERBOSE,
	IMSG_CTL_PROCFD,
	IMSG_CTL_RESET,
	IMSG_CTL_SHUTDOWN,
	IMSG_CTL_RELOAD,
	IMSG_CTL_NOTIFY,
	IMSG_CTL_END,
	IMSG_CTL_START,
	IMSG_CTL_REOPEN,
	IMSG_CFG_SERVER,
	IMSG_CFG_TLS,
	IMSG_CFG_MEDIA,
	IMSG_CFG_AUTH,
	IMSG_CFG_FCGI,
	IMSG_CFG_DONE,
	IMSG_LOG_ACCESS,
	IMSG_LOG_ERROR,
	IMSG_LOG_OPEN,
	IMSG_TLSTICKET_REKEY
};

enum privsep_procid {
	PROC_ALL	= -1,
	PROC_PARENT	= 0,
	PROC_SERVER,
	PROC_LOGGER,
	PROC_MAX
};
extern enum privsep_procid privsep_process;

/* Attach the control socket to the following process */
#define PROC_CONTROL	PROC_LOGGER

struct privsep_pipes {
	int				*pp_pipes[PROC_MAX];
};

struct privsep {
	struct privsep_pipes		*ps_pipes[PROC_MAX];
	struct privsep_pipes		*ps_pp;

	struct imsgev			*ps_ievs[PROC_MAX];
	const char			*ps_title[PROC_MAX];
	uint8_t				 ps_what[PROC_MAX];

	unsigned int			 ps_instances[PROC_MAX];
	unsigned int			 ps_instance;

	struct control_sock		 ps_csock;
	struct control_socks		 ps_rcsocks;

	/* Event and signal handlers */
	struct event			 ps_evsigint;
	struct event			 ps_evsigterm;
	struct event			 ps_evsigchld;
	struct event			 ps_evsighup;
	struct event			 ps_evsigpipe;
	struct event			 ps_evsigusr1;

	int				 ps_noaction;
	struct passwd			*ps_pw;
	struct httpd			*ps_env;
};

struct privsep_proc {
	const char		*p_title;
	enum privsep_procid	 p_id;
	int			(*p_cb)(int, struct privsep_proc *,
				    struct imsg *);
	void			(*p_init)(struct privsep *,
				    struct privsep_proc *);
	const char		*p_chroot;
	struct privsep		*p_ps;
	void			(*p_shutdown)(void);
	struct passwd		*p_pw;
};

struct privsep_fd {
	enum privsep_procid		 pf_procid;
	unsigned int			 pf_instance;
};

enum fcgistate {
	FCGI_READ_HEADER,
	FCGI_READ_CONTENT,
	FCGI_READ_PADDING
};

struct fcgi_data {
	enum fcgistate		 state;
	int			 toread;
	int			 padding_len;
	int			 type;
	int			 chunked;
	int			 end;
	int			 status;
	int			 headersdone;
	int			 headerssent;
};

struct range {
	off_t	start;
	off_t	end;
};

struct range_data {
	struct range		 range[SERVER_MAX_RANGES];
	int			 range_count;
	int			 range_index;
	off_t			 range_toread;

	/* For the Content headers in each part */
	struct media_type	*range_media;
	size_t			 range_total;
};

struct client {
	uint32_t		 clt_id;
	pid_t			 clt_pid;
	void			*clt_srv;
	void			*clt_srv_conf;
	uint32_t		 clt_srv_id;
	struct sockaddr_storage	 clt_srv_ss;
	struct str_match	 clt_srv_match;

	int			 clt_s;
	in_port_t		 clt_port;
	struct sockaddr_storage	 clt_ss;
	struct bufferevent	*clt_bev;
	struct evbuffer		*clt_output;
	struct event		 clt_ev;
	struct http_descriptor	*clt_descreq;
	struct http_descriptor	*clt_descresp;
	int			 clt_sndbufsiz;
	uint64_t		 clt_boundary;

	int			 clt_fd;
	struct tls		*clt_tls_ctx;
	struct bufferevent	*clt_srvbev;
	int			 clt_srvbev_throttled;

	off_t			 clt_toread;
	size_t			 clt_headerlen;
	int			 clt_headersdone;
	unsigned int		 clt_persist;
	unsigned int		 clt_pipelining;
	int			 clt_line;
	int			 clt_done;
	int			 clt_chunk;
	int			 clt_inflight;
	int			 clt_fcgi_count;
	struct range_data	 clt_ranges;
	struct fcgi_data	 clt_fcgi;
	const char		*clt_fcgi_error;
	char			*clt_remote_user;
	struct evbuffer		*clt_srvevb;

	struct evbuffer		*clt_log;
	struct timeval		 clt_timeout;
	struct timeval		 clt_tv_start;
	struct timeval		 clt_tv_last;
	struct event		 clt_inflightevt;

	SPLAY_ENTRY(client)	 clt_nodes;
};
SPLAY_HEAD(client_tree, client);

#define SRVFLAG_INDEX		0x00000001
#define SRVFLAG_NO_INDEX	0x00000002
#define SRVFLAG_AUTO_INDEX	0x00000004
#define SRVFLAG_NO_AUTO_INDEX	0x00000008
#define SRVFLAG_ROOT		0x00000010
#define SRVFLAG_LOCATION	0x00000020
#define SRVFLAG_FCGI		0x00000040
#define SRVFLAG_NO_FCGI		0x00000080
#define SRVFLAG_LOG		0x00000100
#define SRVFLAG_NO_LOG		0x00000200
#define SRVFLAG_ERRDOCS		0x00000400
#define SRVFLAG_SYSLOG		0x00000800
#define SRVFLAG_NO_SYSLOG	0x00001000
#define SRVFLAG_TLS		0x00002000
#define SRVFLAG_ACCESS_LOG	0x00004000
#define SRVFLAG_ERROR_LOG	0x00008000
#define SRVFLAG_AUTH		0x00010000
#define SRVFLAG_NO_AUTH		0x00020000
#define SRVFLAG_BLOCK		0x00040000
#define SRVFLAG_NO_BLOCK	0x00080000
#define SRVFLAG_LOCATION_MATCH	0x00100000
#define SRVFLAG_SERVER_MATCH	0x00200000
#define SRVFLAG_SERVER_HSTS	0x00400000
#define SRVFLAG_DEFAULT_TYPE	0x00800000
#define SRVFLAG_PATH_REWRITE	0x01000000
#define SRVFLAG_NO_PATH_REWRITE	0x02000000
#define SRVFLAG_GZIP_STATIC	0x04000000
#define SRVFLAG_LOCATION_FOUND	0x40000000
#define SRVFLAG_LOCATION_NOT_FOUND 0x80000000

#define SRVFLAG_BITS							\
	"\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX"		\
	"\05ROOT\06LOCATION\07FCGI\10NO_FCGI\11LOG\12NO_LOG\13ERRDOCS"	\
	"\14SYSLOG\15NO_SYSLOG\16TLS\17ACCESS_LOG\20ERROR_LOG"		\
	"\21AUTH\22NO_AUTH\23BLOCK\24NO_BLOCK\25LOCATION_MATCH"		\
	"\26SERVER_MATCH\27SERVER_HSTS\30DEFAULT_TYPE\31PATH\32NO_PATH" \
	"\37LOCATION_FOUND\40LOCATION_NOT_FOUND"

#define TCPFLAG_NODELAY		0x01
#define TCPFLAG_NNODELAY	0x02
#define TCPFLAG_SACK		0x04
#define TCPFLAG_NSACK		0x08
#define TCPFLAG_BUFSIZ		0x10
#define TCPFLAG_IPTTL		0x20
#define TCPFLAG_IPMINTTL	0x40
#define TCPFLAG_NSPLICE		0x80
#define TCPFLAG_DEFAULT		0x00

#define TCPFLAG_BITS						\
	"\10\01NODELAY\02NO_NODELAY\03SACK\04NO_SACK"		\
	"\05SOCKET_BUFFER_SIZE\06IP_TTL\07IP_MINTTL\10NO_SPLICE"

#define HSTSFLAG_SUBDOMAINS	0x01
#define HSTSFLAG_PRELOAD	0x02
#define HSTSFLAG_BITS		"\10\01SUBDOMAINS\02PRELOAD"

#define TLSFLAG_CA		0x01
#define TLSFLAG_CRL		0x02
#define TLSFLAG_OPTIONAL	0x04
#define TLSFLAG_BITS		"\10\01CA\02CRL\03OPTIONAL"

enum log_format {
	LOG_FORMAT_COMMON,
	LOG_FORMAT_COMBINED,
	LOG_FORMAT_CONNECTION,
	LOG_FORMAT_FORWARDED
};

struct log_file {
	char			log_name[PATH_MAX];
	int			log_fd;
	uint32_t		log_id;
	TAILQ_ENTRY(log_file)	log_entry;
};
extern TAILQ_HEAD(log_files, log_file) log_files;

struct media_type {
	char			 media_name[MEDIATYPE_NAMEMAX];
	char			 media_type[MEDIATYPE_TYPEMAX];
	char			 media_subtype[MEDIATYPE_TYPEMAX];
	char			*media_encoding;
	RB_ENTRY(media_type)	 media_entry;
};
RB_HEAD(mediatypes, media_type);

struct auth {
	char			 auth_htpasswd[PATH_MAX];
	uint32_t		 auth_id;
	TAILQ_ENTRY(auth)	 auth_entry;
};
TAILQ_HEAD(serverauth, auth);

struct server_tls_ticket {
	uint32_t	tt_id;
	uint32_t	tt_keyrev;
	unsigned char	tt_key[TLS_TICKET_KEY_SIZE];
};

struct fastcgi_param {
	char			name[HTTPD_FCGI_NAME_MAX];
	char			value[HTTPD_FCGI_VAL_MAX];

	TAILQ_ENTRY(fastcgi_param) entry;
};
TAILQ_HEAD(server_fcgiparams, fastcgi_param);

struct server_config {
	uint32_t		 id;
	uint32_t		 parent_id;
	char			 name[HOST_NAME_MAX+1];
	char			 location[HTTPD_LOCATION_MAX];
	char			 root[PATH_MAX];
	char			 path[PATH_MAX];
	char			 index[PATH_MAX];
	char			 accesslog[PATH_MAX];
	char			 errorlog[PATH_MAX];
	struct media_type	 default_type;

	struct sockaddr_storage	 fastcgi_ss;

	in_port_t		 port;
	struct sockaddr_storage	 ss;
	int			 prefixlen;
	struct timeval		 timeout;
	struct timeval		 requesttimeout;
	uint32_t		 maxrequests;
	size_t			 maxrequestbody;

	uint8_t			*tls_ca;
	char			*tls_ca_file;
	size_t			 tls_ca_len;
	uint8_t			*tls_cert;
	size_t			 tls_cert_len;
	char			*tls_cert_file;
	char			 tls_ciphers[HTTPD_TLS_CONFIG_MAX];
	uint8_t			*tls_crl;
	char			*tls_crl_file;
	size_t			 tls_crl_len;
	char			 tls_dhe_params[HTTPD_TLS_CONFIG_MAX];
	char			 tls_ecdhe_curves[HTTPD_TLS_CONFIG_MAX];
	uint8_t			 tls_flags;
	uint8_t			*tls_key;
	size_t			 tls_key_len;
	char			*tls_key_file;
	uint32_t		 tls_protocols;
	uint8_t			*tls_ocsp_staple;
	size_t			 tls_ocsp_staple_len;
	char			*tls_ocsp_staple_file;
	struct server_tls_ticket tls_ticket_key;
	int			 tls_ticket_lifetime;

	uint32_t		 flags;
	int			 strip;
	uint8_t			 tcpflags;
	int			 tcpbufsiz;
	int			 tcpbacklog;
	uint8_t			 tcpipttl;
	uint8_t			 tcpipminttl;

	enum log_format		 logformat;
	struct log_file		*logaccess;
	struct log_file		*logerror;

	char			 auth_realm[HTTPD_REALM_MAX];
	uint32_t		 auth_id;
	const struct auth	*auth;

	int			 return_code;
	char			*return_uri;
	off_t			 return_uri_len;

	int			 hsts_max_age;
	uint8_t			 hsts_flags;

	struct server_fcgiparams fcgiparams;
	int			 fcgistrip;
	char			 errdocroot[HTTPD_ERRDOCROOT_MAX];

	TAILQ_ENTRY(server_config) entry;
};
TAILQ_HEAD(serverhosts, server_config);

enum tls_config_type {
	TLS_CFG_CA,
	TLS_CFG_CERT,
	TLS_CFG_CRL,
	TLS_CFG_KEY,
	TLS_CFG_OCSP_STAPLE,
};

struct tls_config {
	uint32_t		 id;

	enum tls_config_type	 tls_type;
	size_t			 tls_len;
	size_t			 tls_chunk_len;
	size_t			 tls_chunk_offset;
};

struct server {
	TAILQ_ENTRY(server)	 srv_entry;
	struct server_config	 srv_conf;
	struct serverhosts	 srv_hosts;

	int			 srv_s;
	struct event		 srv_ev;
	struct event		 srv_evt;

	struct tls		 *srv_tls_ctx;
	struct tls_config	 *srv_tls_config;

	struct client_tree	 srv_clients;
};
TAILQ_HEAD(serverlist, server);

struct httpd {
	uint8_t			 sc_opts;
	uint32_t		 sc_flags;
	const char		*sc_conffile;
	struct event		 sc_ev;
	uint16_t		 sc_prefork_server;
	uint16_t		 sc_id;
	int			 sc_paused;
	char			*sc_chroot;
	char			*sc_logdir;

	uint8_t			 sc_tls_sid[TLS_MAX_SESSION_ID_LENGTH];

	struct serverlist	*sc_servers;
	struct mediatypes	*sc_mediatypes;
	struct media_type	 sc_default_type;
	struct serverauth	*sc_auth;

	struct privsep		*sc_ps;
	int			 sc_reload;

	int			 sc_custom_errdocs;
	char			 sc_errdocroot[HTTPD_ERRDOCROOT_MAX];
};

#define HTTPD_OPT_VERBOSE		0x01
#define HTTPD_OPT_NOACTION		0x04

/* control.c */
int	 control_init(struct privsep *, struct control_sock *);
int	 control_listen(struct control_sock *);
void	 control_cleanup(struct control_sock *);
void	 control_dispatch_imsg(int, short, void *);
void	 control_imsg_forward(struct privsep *, struct imsg *);
struct ctl_conn	*
	 control_connbyfd(int);

/* parse.y */
int	 parse_config(const char *, struct httpd *);
int	 load_config(const char *, struct httpd *);
int	 cmdline_symset(char *);

/* server.c */
void	 server(struct privsep *, struct privsep_proc *);
int	 server_tls_cmp(struct server *, struct server *);
int	 server_tls_load_ca(struct server *);
int	 server_tls_load_crl(struct server *);
int	 server_tls_load_keypair(struct server *);
int	 server_tls_load_ocsp(struct server *);
void	 server_generate_ticket_key(struct server_config *);
int	 server_privinit(struct server *);
void	 server_purge(struct server *);
void	 serverconfig_free(struct server_config *);
void	 serverconfig_reset(struct server_config *);
int	 server_socket_af(struct sockaddr_storage *, in_port_t);
in_port_t
	 server_socket_getport(struct sockaddr_storage *);
int	 server_socket_connect(struct sockaddr_storage *, in_port_t,
	    struct server_config *);
void	 server_write(struct bufferevent *, void *);
void	 server_read(struct bufferevent *, void *);
void	 server_error(struct bufferevent *, short, void *);
void	 server_log(struct client *, const char *);
void	 server_sendlog(struct server_config *, int, const char *, ...)
	    __attribute__((__format__ (printf, 3, 4)));
void	 server_close(struct client *, const char *);
void	 server_dump(struct client *, const void *, size_t);
int	 server_client_cmp(struct client *, struct client *);
int	 server_bufferevent_printf(struct client *, const char *, ...)
	    __attribute__((__format__ (printf, 2, 3)));
int	 server_bufferevent_print(struct client *, const char *);
int	 server_bufferevent_write_buffer(struct client *,
	    struct evbuffer *);
int	 server_bufferevent_write_chunk(struct client *,
	    struct evbuffer *, size_t);
int	 server_bufferevent_add(struct event *, int);
int	 server_bufferevent_write(struct client *, void *, size_t);
struct server *
	 server_byaddr(struct sockaddr *, in_port_t);
struct server_config *
	 serverconfig_byid(uint32_t);
int	 server_foreach(int (*)(struct server *,
	    struct server_config *, void *), void *);
struct server *
	 server_match(struct server *, int);

SPLAY_PROTOTYPE(client_tree, client, clt_nodes, server_client_cmp);

/* server_http.c */
void	 server_http_init(struct server *);
void	 server_http(void);
int	 server_httpdesc_init(struct client *);
void	 server_read_http(struct bufferevent *, void *);
void	 server_abort_http(struct client *, unsigned int, const char *);
unsigned int
	 server_httpmethod_byname(const char *);
const char
	*server_httpmethod_byid(unsigned int);
const char
	*server_httperror_byid(unsigned int);
void	 server_read_httpcontent(struct bufferevent *, void *);
void	 server_read_httpchunks(struct bufferevent *, void *);
void	 server_read_httprange(struct bufferevent *, void *);
int	 server_writeheader_http(struct client *clt, struct kv *, void *);
int	 server_headers(struct client *, void *,
	    int (*)(struct client *, struct kv *, void *), void *);
int	 server_writeresponse_http(struct client *);
int	 server_response_http(struct client *, unsigned int,
	    struct media_type *, off_t, time_t);
void	 server_reset_http(struct client *);
void	 server_close_http(struct client *);
int	 server_response(struct httpd *, struct client *);
const char *
	 server_root_strip(const char *, int);
struct server_config *
	 server_getlocation(struct client *, const char *);
int	 server_locationaccesstest(struct server_config *, const char *);
const char *
	 server_http_host(struct sockaddr_storage *, char *, size_t);
char	*server_http_parsehost(char *, char *, size_t, int *);
ssize_t	 server_http_time(time_t, char *, size_t);
int	 server_log_http(struct client *, unsigned int, size_t);

/* server_file.c */
int	 server_file(struct httpd *, struct client *);
void	 server_file_error(struct bufferevent *, short, void *);

/* server_fcgi.c */
int	 server_fcgi(struct httpd *, struct client *);
int	 fcgi_add_stdin(struct client *, struct evbuffer *);

/* httpd.c */
void		 event_again(struct event *, int, short,
		    void (*)(int, short, void *),
		    struct timeval *, struct timeval *, void *);
int		 expand_string(char *, size_t, const char *, const char *);
const char	*url_decode(char *);
char		*url_encode(const char *);
const char	*canonicalize_path(const char *, char *, size_t);
size_t		 path_info(char *);
char		*escape_html(const char *);
void		 socket_rlimit(int);
char		*evbuffer_getline(struct evbuffer *);
char		*get_string(uint8_t *, size_t);
void		*get_data(uint8_t *, size_t);
int		 sockaddr_cmp(struct sockaddr *, struct sockaddr *, int);
struct in6_addr *prefixlen2mask6(uint8_t, uint32_t *);
uint32_t	 prefixlen2mask(uint8_t);
int		 accept_reserve(int, struct sockaddr *, socklen_t *, int,
		    volatile int *);
struct kv	*kv_add(struct kvtree *, char *, char *);
int		 kv_set(struct kv *, char *, ...)
		    __attribute__((__format__ (printf, 2, 3)));
int		 kv_setkey(struct kv *, char *, ...)
		    __attribute__((__format__ (printf, 2, 3)));
void		 kv_delete(struct kvtree *, struct kv *);
struct kv	*kv_extend(struct kvtree *, struct kv *, char *);
void		 kv_purge(struct kvtree *);
void		 kv_free(struct kv *);
struct kv	*kv_find(struct kvtree *, struct kv *);
int		 kv_cmp(struct kv *, struct kv *);
struct media_type
		*media_add(struct mediatypes *, struct media_type *);
void		 media_delete(struct mediatypes *, struct media_type *);
void		 media_purge(struct mediatypes *);
struct media_type *
		 media_find(struct mediatypes *, const char *);
struct media_type *
		 media_find_config(struct httpd *, struct server_config *,
		    const char *);
int		 media_cmp(struct media_type *, struct media_type *);
RB_PROTOTYPE(kvtree, kv, kv_node, kv_cmp);
RB_PROTOTYPE(mediatypes, media_type, media_entry, media_cmp);
struct auth	*auth_add(struct serverauth *, struct auth *);
struct auth	*auth_byid(struct serverauth *, uint32_t);
void		 auth_free(struct serverauth *, struct auth *);
const char	*print_host(struct sockaddr_storage *, char *, size_t);
const char	*printb_flags(const uint32_t, const char *);
void		 getmonotime(struct timeval *);

extern struct httpd *httpd_env;

/* log.c */
void	log_init(int, int);
void	log_procinit(const char *);
void	log_setverbose(int);
int	log_getverbose(void);
void	log_warn(const char *, ...)
	    __attribute__((__format__ (printf, 1, 2)));
void	log_warnx(const char *, ...)
	    __attribute__((__format__ (printf, 1, 2)));
void	log_info(const char *, ...)
	    __attribute__((__format__ (printf, 1, 2)));
void	log_debug(const char *, ...)
	    __attribute__((__format__ (printf, 1, 2)));
void	logit(int, const char *, ...)
	    __attribute__((__format__ (printf, 2, 3)));
void	vlog(int, const char *, va_list)
	    __attribute__((__format__ (printf, 2, 0)));
__dead void fatal(const char *, ...)
	    __attribute__((__format__ (printf, 1, 2)));
__dead void fatalx(const char *, ...)
	    __attribute__((__format__ (printf, 1, 2)));

/* proc.c */
enum privsep_procid
	    proc_getid(struct privsep_proc *, unsigned int, const char *);
void	 proc_init(struct privsep *, struct privsep_proc *, unsigned int, int,
	    int, char **, enum privsep_procid);
void	 proc_kill(struct privsep *);
void	 proc_connect(struct privsep *);
void	 proc_dispatch(int, short event, void *);
void	 proc_run(struct privsep *, struct privsep_proc *,
	    struct privsep_proc *, unsigned int,
	    void (*)(struct privsep *, struct privsep_proc *, void *), void *);
void	 proc_range(struct privsep *, enum privsep_procid, int *, int *);
int	 proc_compose_imsg(struct privsep *, enum privsep_procid, int,
	    u_int16_t, u_int32_t, int, void *, u_int16_t);
int	 proc_compose(struct privsep *, enum privsep_procid,
	    uint16_t, void *, uint16_t);
int	 proc_composev_imsg(struct privsep *, enum privsep_procid, int,
	    u_int16_t, u_int32_t, int, const struct iovec *, int);
int	 proc_composev(struct privsep *, enum privsep_procid,
	    uint16_t, const struct iovec *, int);
int	 proc_forward_imsg(struct privsep *, struct imsg *,
	    enum privsep_procid, int);
struct imsgbuf *
	 proc_ibuf(struct privsep *, enum privsep_procid, int);
struct imsgev *
	 proc_iev(struct privsep *, enum privsep_procid, int);
int	 proc_flush_imsg(struct privsep *, enum privsep_procid, int);
void	 imsg_event_add(struct imsgev *);
int	 imsg_compose_event(struct imsgev *, uint16_t, uint32_t,
	    pid_t, int, void *, uint16_t);
int	 imsg_composev_event(struct imsgev *, uint16_t, uint32_t,
	    pid_t, int, const struct iovec *, int);

/* config.c */
int	 config_init(struct httpd *);
void	 config_purge(struct httpd *, unsigned int);
int	 config_setreset(struct httpd *, unsigned int);
int	 config_getreset(struct httpd *, struct imsg *);
int	 config_getcfg(struct httpd *, struct imsg *);
int	 config_setserver(struct httpd *, struct server *);
int	 config_setserver_tls(struct httpd *, struct server *);
int	 config_setserver_fcgiparams(struct httpd *, struct server *);
int	 config_getserver(struct httpd *, struct imsg *);
int	 config_getserver_tls(struct httpd *, struct imsg *);
int	 config_getserver_fcgiparams(struct httpd *, struct imsg *);
int	 config_setmedia(struct httpd *, struct media_type *);
int	 config_getmedia(struct httpd *, struct imsg *);
int	 config_setauth(struct httpd *, struct auth *);
int	 config_getauth(struct httpd *, struct imsg *);

/* logger.c */
void	 logger(struct privsep *, struct privsep_proc *);
int	 logger_open_priv(struct imsg *);

#endif /* _HTTPD_H */