-/* $OpenBSD: config.c,v 1.17 2014/08/05 14:35:47 deraadt Exp $ */
+/* $OpenBSD: config.c,v 1.18 2014/08/05 15:36:59 reyk Exp $ */
/*
* Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org>
ps->ps_what[PROC_PARENT] = CONFIG_ALL;
ps->ps_what[PROC_SERVER] = CONFIG_SERVERS|CONFIG_MEDIA;
- ps->ps_what[PROC_LOGGER] = 0;
+ ps->ps_what[PROC_LOGGER] = CONFIG_SERVERS;
}
/* Other configuration */
f = SRVFLAG_SSL;
srv_conf->flags |= srv->srv_conf.flags & f;
+ f = SRVFLAG_ACCESS_LOG;
+ if ((srv_conf->flags & f) == 0) {
+ srv_conf->flags |= srv->srv_conf.flags & f;
+ (void)strlcpy(srv_conf->accesslog,
+ srv->srv_conf.accesslog,
+ sizeof(srv_conf->accesslog));
+ }
+
+ f = SRVFLAG_ERROR_LOG;
+ if ((srv_conf->flags & f) == 0) {
+ srv_conf->flags |= srv->srv_conf.flags & f;
+ (void)strlcpy(srv_conf->errorlog,
+ srv->srv_conf.errorlog,
+ sizeof(srv_conf->errorlog));
+ }
+
DPRINTF("%s: %s %d location \"%s\", "
"parent \"%s\", flags: %s",
__func__, ps->ps_title[privsep_process], ps->ps_instance,
-/* $OpenBSD: httpd.c,v 1.16 2014/08/05 09:24:21 jsg Exp $ */
+/* $OpenBSD: httpd.c,v 1.17 2014/08/05 15:36:59 reyk Exp $ */
/*
* Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
ps->ps_instances[PROC_SERVER] = env->sc_prefork_server;
ps->ps_ninstances = env->sc_prefork_server;
+ if (env->sc_chroot == NULL)
+ env->sc_chroot = ps->ps_pw->pw_dir;
for (proc = 0; proc < nitems(procs); proc++)
procs[proc].p_chroot = env->sc_chroot;
case IMSG_CFG_DONE:
parent_configure_done(env);
break;
+ case IMSG_LOG_OPEN:
+ if (logger_open_priv(imsg) == -1)
+ fatalx("failed to open log file");
+ break;
default:
return (-1);
}
-.\" $OpenBSD: httpd.conf.5,v 1.22 2014/08/05 09:24:21 jsg Exp $
+.\" $OpenBSD: httpd.conf.5,v 1.23 2014/08/05 15:36:59 reyk Exp $
.\"
.\" Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
.\"
.Ic listen on
and
.Ic location .
-.It Ic log style Op Ar style
+.It Ic log access Ar name
+Set the
+.Ar name
+of the access log file relative to the log directory.
+If not specified, it defaults to
+.Pa access.log .
+.It Ic log error Ar name
+Set the
+.Ar name
+of the error log file relative to the log directory.
+If not specified, it defaults to
+.Pa error.log .
+.It Ic log style Ar style
Set the logging style.
The
.Ar style
-/* $OpenBSD: httpd.h,v 1.43 2014/08/05 09:24:21 jsg Exp $ */
+/* $OpenBSD: httpd.h,v 1.44 2014/08/05 15:36:59 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
#define HTTPD_DOCROOT "/htdocs"
#define HTTPD_INDEX "index.html"
#define HTTPD_FCGI_SOCKET "/run/slowcgi.sock"
-#define HTTPD_ACCESS_LOG "/logs/access.log"
-#define HTTPD_ERROR_LOG "/logs/error.log"
+#define HTTPD_LOGROOT "/logs"
+#define HTTPD_ACCESS_LOG "access.log"
+#define HTTPD_ERROR_LOG "error.log"
#define HTTPD_SSL_KEY "/conf/server.key"
#define HTTPD_SSL_CERT "/conf/server.crt"
#define FD_RESERVE 5
IMSG_CFG_MEDIA,
IMSG_CFG_DONE,
IMSG_LOG_ACCESS,
- IMSG_LOG_ERROR
+ IMSG_LOG_ERROR,
+ IMSG_LOG_OPEN
};
enum privsep_procid {
#define SRVFLAG_SYSLOG 0x0800
#define SRVFLAG_NO_SYSLOG 0x1000
#define SRVFLAG_SSL 0x2000
+#define SRVFLAG_ACCESS_LOG 0x4000
+#define SRVFLAG_ERROR_LOG 0x8000
#define SRVFLAG_BITS \
"\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX" \
"\05ROOT\06LOCATION\07FCGI\10NO_FCGI\11LOG\12NO_LOG\13SOCKET" \
- "\14SYSLOG\15NO_SYSLOG"
+ "\14SYSLOG\15NO_SYSLOG\16SSL\17ACCESS_LOG\20ERROR_LOG"
#define TCPFLAG_NODELAY 0x01
#define TCPFLAG_NNODELAY 0x02
LOG_FORMAT_CONNECTION
};
+struct log_file {
+ char log_name[NAME_MAX];
+ int log_fd;
+ u_int32_t log_id;
+ TAILQ_ENTRY(log_file) log_entry;
+};
+TAILQ_HEAD(log_files, log_file) log_files;
+
struct server_config {
u_int32_t id;
char name[MAXHOSTNAMELEN];
char index[NAME_MAX];
char root[MAXPATHLEN];
char socket[MAXPATHLEN];
+ char accesslog[NAME_MAX];
+ char errorlog[NAME_MAX];
in_port_t port;
struct sockaddr_storage ss;
- int prefixlen;
struct timeval timeout;
+ int prefixlen;
u_int16_t flags;
u_int8_t tcpflags;
u_int8_t tcpipminttl;
enum log_format logformat;
+ struct log_file *logaccess;
+ struct log_file *logerror;
TAILQ_ENTRY(server_config) entry;
};
void server_read(struct bufferevent *, void *);
void server_error(struct bufferevent *, short, void *);
void server_log(struct client *, const char *);
-void server_log_access(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-void server_log_error(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
+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 *);
void server_inflight_dec(struct client *, const char *);
struct server *
server_byaddr(struct sockaddr *, in_port_t);
+struct server_config *
+ serverconfig_byid(u_int32_t);
+int server_foreach(int (*)(struct server *,
+ struct server_config *, void *), void *);
SPLAY_PROTOTYPE(client_tree, client, clt_nodes, server_client_cmp);
/* logger.c */
pid_t logger(struct privsep *, struct privsep_proc *);
+int logger_open_priv(struct imsg *);
#endif /* _HTTPD_H */
-/* $OpenBSD: logger.c,v 1.2 2014/08/04 15:57:25 reyk Exp $ */
+/* $OpenBSD: logger.c,v 1.3 2014/08/05 15:36:59 reyk Exp $ */
/*
* Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
#include <net/if.h>
struct imsg *);
void logger_shutdown(void);
void logger_close(void);
+struct log_file *logger_open_file(const char *);
+int logger_open_fd(struct imsg *);
+int logger_open(struct server *, struct server_config *, void *);
void logger_init(struct privsep *, struct privsep_proc *p, void *);
int logger_start(void);
int logger_log(struct imsg *);
static struct httpd *env = NULL;
int proc_id;
-int log_fd = -1;
-int error_fd = -1;
+static u_int32_t last_log_id = 0;
static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT, logger_dispatch_parent },
config_purge(env, CONFIG_ALL);
}
-void
-logger_close(void)
-{
- if (log_fd != -1) {
- close(log_fd);
- log_fd = -1;
- }
- if (error_fd != -1) {
- close(error_fd);
- error_fd = -1;
- }
-}
-
void
logger_init(struct privsep *ps, struct privsep_proc *p, void *arg)
{
/* We use a custom shutdown callback */
p->p_shutdown = logger_shutdown;
+
+ TAILQ_INIT(&log_files);
+}
+
+void
+logger_close(void)
+{
+ struct log_file *log, *next;
+
+ TAILQ_FOREACH_SAFE(log, &log_files, log_entry, next) {
+ if (log->log_fd != -1) {
+ close(log->log_fd);
+ log->log_fd = -1;
+ }
+ TAILQ_REMOVE(&log_files, log, log_entry);
+ }
+}
+
+struct log_file *
+logger_open_file(const char *name)
+{
+ struct log_file *log;
+ struct iovec iov[2];
+
+ if ((log = calloc(1, sizeof(*log))) == NULL) {
+ log_warn("failed to allocate log %s", name);
+ return (NULL);
+ }
+
+ log->log_id = ++last_log_id;
+ (void)strlcpy(log->log_name, name, sizeof(log->log_name));
+
+ /* The file will be opened by the parent process */
+ log->log_fd = -1;
+
+ iov[0].iov_base = &log->log_id;
+ iov[0].iov_len = sizeof(log->log_id);
+ iov[1].iov_base = log->log_name;
+ iov[1].iov_len = strlen(log->log_name) + 1;
+
+ proc_composev_imsg(env->sc_ps, PROC_PARENT, -1, IMSG_LOG_OPEN, -1,
+ iov, 2);
+
+ TAILQ_INSERT_TAIL(&log_files, log, log_entry);
+
+ return (log);
}
int
-logger_start(void)
+logger_open_fd(struct imsg *imsg)
{
- logger_close();
- if ((log_fd = open(HTTPD_ACCESS_LOG,
- O_WRONLY|O_APPEND|O_CREAT, 0644)) == -1) {
- log_warn("failed to open %s", HTTPD_ACCESS_LOG);
+ struct log_file *log;
+ u_int32_t id;
+
+ IMSG_SIZE_CHECK(imsg, &id);
+ memcpy(&id, imsg->data, sizeof(id));
+
+ TAILQ_FOREACH(log, &log_files, log_entry) {
+ if (log->log_id == id) {
+ DPRINTF("%s: received log fd %d, file %s",
+ __func__, imsg->fd, log->log_name);
+ log->log_fd = imsg->fd;
+ return (0);
+ }
+ }
+
+ return (-1);
+}
+
+int
+logger_open_priv(struct imsg *imsg)
+{
+ char path[MAXPATHLEN];
+ char name[NAME_MAX], *p;
+ u_int32_t id;
+ size_t len;
+ int fd;
+
+ /* called from the priviled process */
+ IMSG_SIZE_CHECK(imsg, &id);
+ memcpy(&id, imsg->data, sizeof(id));
+ p = (char *)imsg->data + sizeof(id);
+
+ if ((size_t)snprintf(name, sizeof(name), "/%s", p) >= sizeof(name))
+ return (-1);
+ if ((len = (size_t)snprintf(path, sizeof(path), "%s%s",
+ env->sc_chroot, HTTPD_LOGROOT)) >= sizeof(path))
+ return (-1);
+
+ p = path + len;
+ len = sizeof(path) - len;
+
+ if (canonicalize_path(name, p, len) == NULL) {
+ log_warnx("invalid log name");
return (-1);
}
- if ((error_fd = open(HTTPD_ERROR_LOG,
- O_WRONLY|O_APPEND|O_CREAT, 0644)) == -1) {
- log_warn("failed to open %s", HTTPD_ERROR_LOG);
+
+ if ((fd = open(path, O_WRONLY|O_APPEND|O_CREAT, 0644)) == -1) {
+ log_warn("failed to open %s", path);
return (-1);
}
+
+ proc_compose_imsg(env->sc_ps, PROC_LOGGER, -1, IMSG_LOG_OPEN, fd,
+ &id, sizeof(id));
+
+ DPRINTF("%s: opened log file %s, fd %d", __func__, path, fd);
+
+ return (0);
+}
+
+int
+logger_open(struct server *srv, struct server_config *srv_conf, void *arg)
+{
+ struct log_file *log, *logfile = NULL, *errfile = NULL;
+
+ /* disassociate */
+ srv_conf->logaccess = srv_conf->logerror = NULL;
+
+ TAILQ_FOREACH(log, &log_files, log_entry) {
+ if (strcmp(log->log_name, srv_conf->accesslog) == 0)
+ logfile = log;
+ if (strcmp(log->log_name, srv_conf->errorlog) == 0)
+ errfile = log;
+ }
+
+ if (logfile == NULL) {
+ if ((srv_conf->logaccess =
+ logger_open_file(srv_conf->accesslog)) == NULL)
+ return (-1);
+ } else
+ srv_conf->logaccess = logfile;
+
+ if (errfile == NULL) {
+ if ((srv_conf->logerror =
+ logger_open_file(srv_conf->errorlog)) == NULL)
+ return (-1);
+ } else
+ srv_conf->logerror = errfile;
+
+ return (0);
+}
+
+int
+logger_start(void)
+{
+ logger_close();
+ if (server_foreach(logger_open, NULL) == -1)
+ fatalx("failed to open log files");
return (0);
}
int
logger_log(struct imsg *imsg)
{
- char *logline;
- int fd;
+ char *logline;
+ u_int32_t id;
+ struct server_config *srv_conf;
+ struct log_file *log;
+
+ IMSG_SIZE_CHECK(imsg, &id);
+ memcpy(&id, imsg->data, sizeof(id));
+
+ if ((srv_conf = serverconfig_byid(id)) == NULL)
+ fatalx("invalid logging requestr");
if (imsg->hdr.type == IMSG_LOG_ACCESS)
- fd = log_fd;
+ log = srv_conf->logaccess;
else
- fd = error_fd;
+ log = srv_conf->logerror;
+
+ if (log == NULL || log->log_fd == -1) {
+ log_warnx("log file %s not opened", log->log_name);
+ return (0);
+ }
/* XXX get_string() would sanitize the string, but add a malloc */
- logline = imsg->data;
+ logline = (char *)imsg->data + sizeof(id);
/* For debug output */
log_debug("%s", logline);
- if (dprintf(fd, "%s\n", logline) == -1) {
+ if (dprintf(log->log_fd, "%s\n", logline) == -1) {
if (logger_start() == -1)
return (-1);
}
logger_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
{
switch (imsg->hdr.type) {
+ case IMSG_CFG_SERVER:
+ config_getserver(env, imsg);
+ break;
case IMSG_CFG_DONE:
config_getcfg(env, imsg);
break;
case IMSG_CTL_START:
case IMSG_CTL_REOPEN:
- return (logger_start());
+ logger_start();
+ break;
case IMSG_CTL_RESET:
config_getreset(env, imsg);
break;
+ case IMSG_LOG_OPEN:
+ return (logger_open_fd(imsg));
default:
return (-1);
}
{
switch (imsg->hdr.type) {
case IMSG_LOG_ACCESS:
- return (logger_log(imsg));
case IMSG_LOG_ERROR:
- return (logger_log(imsg));
+ logger_log(imsg);
+ break;
default:
return (-1);
}
-/* $OpenBSD: parse.y,v 1.24 2014/08/05 09:24:21 jsg Exp $ */
+/* $OpenBSD: parse.y,v 1.25 2014/08/05 15:36:59 reyk Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
%}
-%token AUTO CHROOT COMMON COMBINED CONNECTION DIRECTORY FCGI FILE INDEX LISTEN
-%token LOCATION LOG NO ON PORT PREFORK ROOT SERVER SOCKET SSL STYLE SYSLOG
-%token TYPES
+%token ACCESS AUTO CHROOT COMMON COMBINED CONNECTION DIRECTORY ERR FCGI
+%token INDEX LISTEN LOCATION LOG NO ON PORT PREFORK ROOT SERVER SOCKET SSL
+%token STYLE SYSLOG TYPES
%token ERROR INCLUDE
%token <v.string> STRING
%token <v.number> NUMBER
sizeof(s->srv_conf.root));
strlcpy(s->srv_conf.index, HTTPD_INDEX,
sizeof(s->srv_conf.index));
+ strlcpy(s->srv_conf.accesslog, HTTPD_ACCESS_LOG,
+ sizeof(s->srv_conf.accesslog));
+ strlcpy(s->srv_conf.errorlog, HTTPD_ERROR_LOG,
+ sizeof(s->srv_conf.errorlog));
s->srv_conf.id = ++last_server_id;
s->srv_conf.timeout.tv_sec = SERVER_TIMEOUT;
s->srv_conf.flags |= SRVFLAG_LOG;
srv->srv_conf.flags &= ~SRVFLAG_SYSLOG;
srv->srv_conf.flags |= SRVFLAG_NO_SYSLOG;
}
+ | ACCESS STRING {
+ if (strlcpy(srv->srv_conf.accesslog, $2,
+ sizeof(srv->srv_conf.accesslog)) >=
+ sizeof(srv->srv_conf.accesslog)) {
+ yyerror("access log name too long");
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ srv->srv_conf.flags |= SRVFLAG_ACCESS_LOG;
+ }
+ | ERR STRING {
+ if (strlcpy(srv->srv_conf.errorlog, $2,
+ sizeof(srv->srv_conf.errorlog)) >=
+ sizeof(srv->srv_conf.errorlog)) {
+ yyerror("error log name too long");
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ srv->srv_conf.flags |= SRVFLAG_ERROR_LOG;
+ }
;
logstyle : COMMON {
{
/* this has to be sorted always */
static const struct keywords keywords[] = {
+ { "access", ACCESS },
{ "auto", AUTO },
{ "chroot", CHROOT },
{ "combined", COMBINED },
{ "common", COMMON },
{ "connection", CONNECTION },
{ "directory", DIRECTORY },
+ { "error", ERR },
{ "fastcgi", FCGI },
- { "file", FILE },
{ "include", INCLUDE },
{ "index", INDEX },
{ "listen", LISTEN },
-/* $OpenBSD: server.c,v 1.28 2014/08/04 18:12:15 reyk Exp $ */
+/* $OpenBSD: server.c,v 1.29 2014/08/05 15:36:59 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <sys/uio.h>
#include <sys/tree.h>
#include <sys/hash.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
#include <unistd.h>
#include <stdio.h>
#include <err.h>
return (NULL);
}
+struct server_config *
+serverconfig_byid(u_int32_t id)
+{
+ struct server *srv;
+ struct server_config *srv_conf;
+
+ TAILQ_FOREACH(srv, env->sc_servers, srv_entry) {
+ if (srv->srv_conf.id == id)
+ return (&srv->srv_conf);
+ TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
+ if (srv_conf->id == id)
+ return (srv_conf);
+ }
+ }
+
+ return (NULL);
+}
+
+int
+server_foreach(int (*srv_cb)(struct server *,
+ struct server_config *, void *), void *arg)
+{
+ struct server *srv;
+ struct server_config *srv_conf;
+
+ TAILQ_FOREACH(srv, env->sc_servers, srv_entry) {
+ if ((srv_cb)(srv, &srv->srv_conf, arg) == -1)
+ return (-1);
+ TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
+ if ((srv_cb)(srv, srv_conf, arg) == -1)
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
int
server_socket_af(struct sockaddr_storage *ss, in_port_t port)
{
}
void
-server_log_access(const char *emsg, ...)
+server_sendlog(struct server_config *srv_conf, int cmd, const char *emsg, ...)
{
- va_list ap;
- char *msg;
- int ret;
+ va_list ap;
+ char *msg;
+ int ret;
+ struct iovec iov[2];
- va_start(ap, emsg);
- ret = vasprintf(&msg, emsg, ap);
- va_end(ap);
- if (ret == -1) {
- log_warn("%s: vasprintf", __func__);
+ if (srv_conf->flags & SRVFLAG_SYSLOG) {
+ if (cmd == IMSG_LOG_ACCESS)
+ vlog(LOG_INFO, emsg, ap);
+ else
+ vlog(LOG_DEBUG, emsg, ap);
return;
}
- proc_compose_imsg(env->sc_ps, PROC_LOGGER, -1,
- IMSG_LOG_ACCESS, -1, msg, strlen(msg) + 1);
-}
-
-void
-server_log_error(const char *emsg, ...)
-{
- va_list ap;
- char *msg;
- int ret;
-
va_start(ap, emsg);
ret = vasprintf(&msg, emsg, ap);
va_end(ap);
return;
}
- proc_compose_imsg(env->sc_ps, PROC_LOGGER, -1,
- IMSG_LOG_ERROR, -1, msg, strlen(msg) + 1);
+ iov[0].iov_base = &srv_conf->id;
+ iov[0].iov_len = sizeof(srv_conf->id);
+ iov[1].iov_base = msg;
+ iov[1].iov_len = strlen(msg) + 1;
+
+ proc_composev_imsg(env->sc_ps, PROC_LOGGER, -1, cmd, -1, iov, 2);
}
void
char ibuf[MAXHOSTNAMELEN], obuf[MAXHOSTNAMELEN];
struct server_config *srv_conf = clt->clt_srv_conf;
char *ptr = NULL;
- void (*log_infocb)(const char *, ...);
- void (*log_debugcb)(const char *, ...);
+ int debug_cmd = -1;
extern int verbose;
- if (srv_conf->flags & SRVFLAG_SYSLOG) {
- log_infocb = log_info;
- log_debugcb = log_debug;
- } else {
- log_infocb = server_log_access;
- log_debugcb = server_log_error;
- }
-
switch (srv_conf->logformat) {
case LOG_FORMAT_CONNECTION:
- log_debugcb = server_log_error;
+ debug_cmd = IMSG_LOG_ACCESS;
break;
default:
- if (verbose <= 1)
- log_debugcb = NULL;
+ if (verbose > 1)
+ debug_cmd = IMSG_LOG_ERROR;
if (EVBUFFER_LENGTH(clt->clt_log)) {
while ((ptr =
evbuffer_readline(clt->clt_log)) != NULL) {
- (log_infocb)("%s", ptr);
+ server_sendlog(srv_conf,
+ IMSG_LOG_ACCESS, "%s", ptr);
free(ptr);
}
}
break;
}
- if (log_debugcb != NULL && msg != NULL) {
+ if (debug_cmd != -1 && msg != NULL) {
memset(&ibuf, 0, sizeof(ibuf));
memset(&obuf, 0, sizeof(obuf));
(void)print_host(&clt->clt_ss, ibuf, sizeof(ibuf));
if (EVBUFFER_LENGTH(clt->clt_log) &&
evbuffer_add_printf(clt->clt_log, "\n") != -1)
ptr = evbuffer_readline(clt->clt_log);
- (log_debugcb)("server %s, "
+ server_sendlog(srv_conf, debug_cmd, "server %s, "
"client %d (%d active), %s:%u -> %s, "
"%s%s%s", srv_conf->name, clt->clt_id, server_clients,
ibuf, ntohs(clt->clt_port), obuf, msg,