Import syslogd SoC project by Martin Schuette:
- new syslog protocol api syslogp(3) that supports structured data and draft-rfc timestamps - reliable tcp connections with queueing - encrypted connections
This commit is contained in:
parent
54977cd016
commit
1c6aec2060
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: syslog.3,v 1.24 2006/11/22 17:23:25 christos Exp $
|
||||
.\" $NetBSD: syslog.3,v 1.25 2008/10/31 16:12:18 christos Exp $
|
||||
.\" $OpenBSD: syslog.3,v 1.25 2005/07/22 03:16:58 jaredy Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1985, 1991, 1993
|
||||
@ -30,7 +30,7 @@
|
||||
.\"
|
||||
.\" @(#)syslog.3 8.1 (Berkeley) 6/4/93
|
||||
.\"
|
||||
.Dd November 22, 2006
|
||||
.Dd August 13, 2008
|
||||
.Dt SYSLOG 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -38,6 +38,10 @@
|
||||
.Nm syslog_r ,
|
||||
.Nm vsyslog ,
|
||||
.Nm vsyslog_r ,
|
||||
.Nm syslogp ,
|
||||
.Nm syslogp_r ,
|
||||
.Nm vsyslogp ,
|
||||
.Nm vsyslogp_r ,
|
||||
.Nm openlog ,
|
||||
.Nm openlog_r ,
|
||||
.Nm closelog ,
|
||||
@ -53,6 +57,10 @@
|
||||
.Fn syslog "int priority" "const char *message" "..."
|
||||
.Ft void
|
||||
.Fn syslog_r "int priority" "struct syslog_data *data" "const char *message" "..."
|
||||
.Ft void
|
||||
.Fn syslogp "int priority" "const char *msgid" "const char *sdfmt" "const char *message" "..."
|
||||
.Ft void
|
||||
.Fn syslogp_r "int priority" "struct syslog_data *data" "const char *msgid" "const char *sdfmt" "const char *message" "..."
|
||||
.\" .Ft void
|
||||
.\" .Fn syslog_ss "int priority" "struct syslog_data *data" "const char *message" "..."
|
||||
.Ft void
|
||||
@ -72,6 +80,10 @@
|
||||
.Fn vsyslog "int priority" "const char *message" "va_list args"
|
||||
.Ft void
|
||||
.Fn vsyslog_r "int priority" "struct syslog_data *data" "const char *message" "va_list args"
|
||||
.Ft void
|
||||
.Fn vsyslogp "int priority" "const char *msgid" "const char *sdfmt" "const char *message" "va_list args"
|
||||
.Ft void
|
||||
.Fn vsyslogp_r "int priority" "struct syslog_data *data" "const char *msgid" "const char *sdfmt" "const char *message" "va_list args"
|
||||
.\" .Ft void
|
||||
.\" .Fn vsyslog_ss "int priority" "struct syslog_data *data" "const char *message" "va_list args"
|
||||
.Bd -literal
|
||||
@ -114,6 +126,9 @@ message.
|
||||
see
|
||||
.Xr strerror 3 . )
|
||||
A trailing newline is added if none is present.
|
||||
.\" shouldn't the newline statement be removed?
|
||||
.\" when logging through a socket a newline is
|
||||
.\" not added nor is it required. -- ms
|
||||
The
|
||||
.Fn syslog_r
|
||||
function is a multithread-safe version of the
|
||||
@ -182,6 +197,16 @@ is an alternative form in which the arguments have already been captured
|
||||
using the variable-length argument facilities of
|
||||
.Xr varargs 3 .
|
||||
.Pp
|
||||
The
|
||||
.Fn syslogp
|
||||
variants take additional arguments which correspond to new fields in the
|
||||
syslog-protocol message format. All three arguments are evaluated as
|
||||
.Xr printf 3
|
||||
format strings and any of them can be
|
||||
.Fa NULL .
|
||||
This enables applications to use message IDs, structured data, and UTF-8 encoded
|
||||
content in messages.
|
||||
.Pp
|
||||
The message is tagged with
|
||||
.Fa priority .
|
||||
Priorities are encoded as a
|
||||
@ -391,8 +416,12 @@ The routines
|
||||
.Fn syslog ,
|
||||
.Fn syslog_r ,
|
||||
.Fn vsyslog ,
|
||||
.Fn vsyslog_r ,
|
||||
.Fn syslogp ,
|
||||
.Fn syslogp_r ,
|
||||
.Fn vsyslogp ,
|
||||
and
|
||||
.Fn vsyslog_r
|
||||
.Fn vsyslogp_r
|
||||
return no value.
|
||||
.Pp
|
||||
The routines
|
||||
@ -411,6 +440,11 @@ setlogmask(LOG_UPTO(LOG_ERR));
|
||||
syslog(LOG_INFO, "Connection from host %d", CallingHost);
|
||||
|
||||
syslog(LOG_INFO|LOG_LOCAL2, "foobar error: %m");
|
||||
|
||||
syslogp(LOG_INFO|LOG_LOCAL2, NULL, NULL, "foobar error: %m");
|
||||
|
||||
syslogp(LOG_INFO, "ID%d", "[meta language=\\"en-US\\"]",
|
||||
"event: %s", 42, EventDescription);
|
||||
.Ed
|
||||
.Pp
|
||||
For the multithread-safe functions:
|
||||
@ -422,6 +456,18 @@ syslog_r(LOG_INFO|LOG_LOCAL2, \*[Am]sdata, "foobar error: %m");
|
||||
.Sh SEE ALSO
|
||||
.Xr logger 1 ,
|
||||
.Xr syslogd 8
|
||||
.Rs
|
||||
.%R RFC
|
||||
.%N 3164
|
||||
.%D August 2001
|
||||
.%T The BSD syslog Protocol
|
||||
.Re
|
||||
.Rs
|
||||
.%R Internet-Draft
|
||||
.%N draft-ietf-syslog-protocol-23
|
||||
.%D September 2007
|
||||
.%T The syslog Protocol
|
||||
.Re
|
||||
.Sh HISTORY
|
||||
These non-multithread-safe functions appeared in
|
||||
.Bx 4.2 .
|
||||
@ -431,6 +477,8 @@ and then in
|
||||
.Nx 4.0 .
|
||||
The async-signal-safe functions appeared in
|
||||
.Nx 4.0 .
|
||||
The syslog-protocol functions appeared in
|
||||
.Nx 5.0 .
|
||||
.Sh CAVEATS
|
||||
It is important never to pass a string with user-supplied data as a
|
||||
format without using
|
||||
@ -449,3 +497,13 @@ Always be sure to use the proper secure idiom:
|
||||
.Bd -literal -offset indent
|
||||
syslog(priority, "%s", string);
|
||||
.Ed
|
||||
.Pp
|
||||
With
|
||||
.Fn syslogp
|
||||
the caller is responsible to use the right formatting for the message fields. A
|
||||
.Fa msgid
|
||||
must only contain up to 32 ASCII characters. A
|
||||
.Fa sdfmt
|
||||
has strict rules for paranthesis and character quoting. If the
|
||||
.Fa msgfmt
|
||||
contains UTF-8 characters, then it has to start with a Byte Order Mark.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: syslog.c,v 1.42 2008/10/22 02:17:29 dogcow Exp $ */
|
||||
/* $NetBSD: syslog.c,v 1.43 2008/10/31 16:12:18 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1983, 1988, 1993
|
||||
@ -34,12 +34,13 @@
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)syslog.c 8.5 (Berkeley) 4/29/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: syslog.c,v 1.42 2008/10/22 02:17:29 dogcow Exp $");
|
||||
__RCSID("$NetBSD: syslog.c,v 1.43 2008/10/31 16:12:18 christos Exp $");
|
||||
#endif
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include "namespace.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/uio.h>
|
||||
@ -64,6 +65,8 @@ __weak_alias(openlog,_openlog)
|
||||
__weak_alias(setlogmask,_setlogmask)
|
||||
__weak_alias(syslog,_syslog)
|
||||
__weak_alias(vsyslog,_vsyslog)
|
||||
__weak_alias(syslogp,_syslogp)
|
||||
__weak_alias(vsyslogp,_vsyslogp)
|
||||
|
||||
__weak_alias(closelog_r,_closelog_r)
|
||||
__weak_alias(openlog_r,_openlog_r)
|
||||
@ -72,6 +75,10 @@ __weak_alias(syslog_r,_syslog_r)
|
||||
__weak_alias(vsyslog_r,_vsyslog_r)
|
||||
__weak_alias(syslog_ss,_syslog_ss)
|
||||
__weak_alias(vsyslog_ss,_vsyslog_ss)
|
||||
__weak_alias(syslogp_r,_syslogp_r)
|
||||
__weak_alias(vsyslogp_r,_vsyslogp_r)
|
||||
__weak_alias(syslogp_ss,_syslogp_ss)
|
||||
__weak_alias(vsyslogp_ss,_vsyslogp_ss)
|
||||
#endif
|
||||
|
||||
static struct syslog_data sdata = SYSLOG_DATA_INIT;
|
||||
@ -82,12 +89,14 @@ static void disconnectlog_r(struct syslog_data *);
|
||||
static void connectlog_r(struct syslog_data *);
|
||||
|
||||
#define LOG_SIGNAL_SAFE (int)0x80000000
|
||||
|
||||
|
||||
|
||||
#ifdef _REENTRANT
|
||||
static mutex_t syslog_mutex = MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
static char hostname[MAXHOSTNAMELEN];
|
||||
|
||||
/*
|
||||
* syslog, vsyslog --
|
||||
* print message on log file; output is intended for syslogd(8).
|
||||
@ -108,6 +117,26 @@ vsyslog(int pri, const char *fmt, va_list ap)
|
||||
vsyslog_r(pri, &sdata, fmt, ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* syslogp, vsyslogp --
|
||||
* like syslog but take additional arguments for MSGID and SD
|
||||
*/
|
||||
void
|
||||
syslogp(int pri, const char *msgid, const char *sdfmt, const char *msgfmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, msgfmt);
|
||||
vsyslogp(pri, msgid, sdfmt, msgfmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
vsyslogp(int pri, const char *msgid, const char *sdfmt, const char *msgfmt, va_list ap)
|
||||
{
|
||||
vsyslogp_r(pri, &sdata, msgid, sdfmt, msgfmt, ap);
|
||||
}
|
||||
|
||||
void
|
||||
openlog(const char *ident, int logstat, int logfac)
|
||||
{
|
||||
@ -139,6 +168,17 @@ syslog_r(int pri, struct syslog_data *data, const char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
syslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
const char *sdfmt, const char *msgfmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, msgfmt);
|
||||
vsyslogp_r(pri, data, msgid, sdfmt, msgfmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
syslog_ss(int pri, struct syslog_data *data, const char *fmt, ...)
|
||||
{
|
||||
@ -149,32 +189,60 @@ syslog_ss(int pri, struct syslog_data *data, const char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
syslogp_ss(int pri, struct syslog_data *data, const char *msgid,
|
||||
const char *sdfmt, const char *msgfmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, msgfmt);
|
||||
vsyslogp_r(pri | LOG_SIGNAL_SAFE, data, msgid, sdfmt, msgfmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
vsyslog_ss(int pri, struct syslog_data *data, const char *fmt, va_list ap)
|
||||
{
|
||||
vsyslog_r(pri | LOG_SIGNAL_SAFE, data, fmt, ap);
|
||||
}
|
||||
|
||||
void
|
||||
vsyslogp_ss(int pri, struct syslog_data *data, const char *msgid,
|
||||
const char *sdfmt, const char *msgfmt, va_list ap)
|
||||
{
|
||||
vsyslogp_r(pri | LOG_SIGNAL_SAFE, data, msgid, sdfmt, msgfmt, ap);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
|
||||
{
|
||||
vsyslogp_r(pri, data, NULL, NULL, fmt, ap);
|
||||
}
|
||||
|
||||
void
|
||||
vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
const char *sdfmt, const char *msgfmt, va_list ap)
|
||||
{
|
||||
size_t cnt, prlen, tries;
|
||||
char ch, *p, *t;
|
||||
time_t now;
|
||||
struct timeval tv;
|
||||
struct tm tmnow;
|
||||
time_t now;
|
||||
int fd, saved_errno;
|
||||
#define TBUF_LEN 2048
|
||||
#define FMT_LEN 1024
|
||||
#define TBUF_LEN 2048
|
||||
#define FMT_LEN 1024
|
||||
#define MAXTRIES 10
|
||||
char *stdp = NULL; /* pacify gcc */
|
||||
char tbuf[TBUF_LEN], fmt_cpy[FMT_LEN];
|
||||
char tbuf[TBUF_LEN], fmt_cpy[FMT_LEN], fmt_cat[FMT_LEN] = "";
|
||||
size_t tbuf_left, fmt_left;
|
||||
char *fmt = fmt_cat;
|
||||
int signal_safe = pri & LOG_SIGNAL_SAFE;
|
||||
int opened;
|
||||
|
||||
pri &= ~LOG_SIGNAL_SAFE;
|
||||
|
||||
#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
|
||||
#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
|
||||
/* Check for invalid bits. */
|
||||
if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
|
||||
syslog_r(INTERNALLOG | signal_safe, data,
|
||||
@ -193,22 +261,10 @@ vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
|
||||
pri |= data->log_fac;
|
||||
|
||||
/* Build the message. */
|
||||
|
||||
/*
|
||||
* Although it's tempting, we can't ignore the possibility of
|
||||
* overflowing the buffer when assembling the "fixed" portion
|
||||
* of the message. Strftime's "%h" directive expands to the
|
||||
* locale's abbreviated month name, but if the user has the
|
||||
* ability to construct to his own locale files, it may be
|
||||
* arbitrarily long.
|
||||
*/
|
||||
if (!signal_safe)
|
||||
(void)time(&now);
|
||||
|
||||
p = tbuf;
|
||||
p = tbuf;
|
||||
tbuf_left = TBUF_LEN;
|
||||
|
||||
#define DEC() \
|
||||
|
||||
#define DEC() \
|
||||
do { \
|
||||
if (prlen >= tbuf_left) \
|
||||
prlen = tbuf_left - 1; \
|
||||
@ -216,42 +272,76 @@ vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
|
||||
tbuf_left -= prlen; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
prlen = snprintf_ss(p, tbuf_left, "<%d>", pri);
|
||||
prlen = snprintf_ss(p, tbuf_left, "<%d>1 ", pri);
|
||||
DEC();
|
||||
|
||||
if (!signal_safe) {
|
||||
if (!signal_safe && (gettimeofday(&tv, NULL) != -1)) {
|
||||
/* strftime() implies tzset(), localtime_r() doesn't. */
|
||||
tzset();
|
||||
prlen = strftime(p, tbuf_left, "%h %e %T ",
|
||||
localtime_r(&now, &tmnow));
|
||||
now = (time_t) tv.tv_sec;
|
||||
localtime_r(&now, &tmnow);
|
||||
|
||||
prlen = strftime(p, tbuf_left, "%FT%T", &tmnow);
|
||||
DEC();
|
||||
prlen = snprintf(p, tbuf_left, ".%06ld", tv.tv_usec);
|
||||
DEC();
|
||||
prlen = strftime(p, tbuf_left-1, "%z", &tmnow);
|
||||
/* strftime gives eg. "+0200", but we need "+02:00" */
|
||||
if (prlen == 5) {
|
||||
p[prlen+1] = p[prlen];
|
||||
p[prlen] = p[prlen-1];
|
||||
p[prlen-1] = p[prlen-2];
|
||||
p[prlen-2] = ':';
|
||||
prlen += 1;
|
||||
}
|
||||
} else {
|
||||
prlen = snprintf_ss(p, tbuf_left, "-");
|
||||
|
||||
/* if gmtime_r() was signal-safe we could output the UTC-time:
|
||||
gmtime_r(&now, &tmnow);
|
||||
prlen = strftime(p, tbuf_left, "%FT%TZ", &tmnow);
|
||||
*/
|
||||
}
|
||||
DEC();
|
||||
prlen = snprintf_ss(p, tbuf_left, " %s ", hostname);
|
||||
DEC();
|
||||
|
||||
if (data->log_stat & LOG_PERROR)
|
||||
stdp = p;
|
||||
if (data->log_tag == NULL)
|
||||
data->log_tag = getprogname();
|
||||
if (data->log_tag != NULL) {
|
||||
prlen = snprintf_ss(p, tbuf_left, "%s", data->log_tag);
|
||||
DEC();
|
||||
}
|
||||
if (data->log_stat & LOG_PID) {
|
||||
prlen = snprintf_ss(p, tbuf_left, "[%d]", getpid());
|
||||
DEC();
|
||||
}
|
||||
if (data->log_tag != NULL) {
|
||||
if (tbuf_left > 1) {
|
||||
*p++ = ':';
|
||||
tbuf_left--;
|
||||
}
|
||||
if (tbuf_left > 1) {
|
||||
*p++ = ' ';
|
||||
tbuf_left--;
|
||||
}
|
||||
|
||||
prlen = snprintf_ss(p, tbuf_left, "%s ",
|
||||
data->log_tag ? data->log_tag : "-");
|
||||
DEC();
|
||||
|
||||
if (data->log_stat & LOG_PID)
|
||||
prlen = snprintf_ss(p, tbuf_left, "%d ", getpid());
|
||||
else
|
||||
prlen = snprintf_ss(p, tbuf_left, "- ");
|
||||
DEC();
|
||||
|
||||
/*
|
||||
* concat the format strings, then use one vsnprintf()
|
||||
*/
|
||||
if (msgid != NULL && *msgid != '\0') {
|
||||
strlcat(fmt_cat, msgid, FMT_LEN);
|
||||
strlcat(fmt_cat, " ", FMT_LEN);
|
||||
} else
|
||||
strlcat(fmt_cat, "- ", FMT_LEN);
|
||||
|
||||
if (sdfmt != NULL && *sdfmt != '\0') {
|
||||
strlcat(fmt_cat, sdfmt, FMT_LEN);
|
||||
} else
|
||||
strlcat(fmt_cat, "-", FMT_LEN);
|
||||
|
||||
if (msgfmt != NULL && *msgfmt != '\0') {
|
||||
strlcat(fmt_cat, " ", FMT_LEN);
|
||||
strlcat(fmt_cat, msgfmt, FMT_LEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* We wouldn't need this mess if printf handled %m, or if
|
||||
/*
|
||||
* We wouldn't need this mess if printf handled %m, or if
|
||||
* strerror() had been invented before syslog().
|
||||
*/
|
||||
for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt) != '\0'; ++fmt) {
|
||||
@ -260,7 +350,7 @@ vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
|
||||
++fmt;
|
||||
if (signal_safe ||
|
||||
strerror_r(saved_errno, ebuf, sizeof(ebuf)))
|
||||
prlen = snprintf_ss(t, fmt_left, "Error %d",
|
||||
prlen = snprintf_ss(t, fmt_left, "Error %d",
|
||||
saved_errno);
|
||||
else
|
||||
prlen = snprintf_ss(t, fmt_left, "%s", ebuf);
|
||||
@ -391,11 +481,41 @@ connectlog_r(struct syslog_data *data)
|
||||
sizeof(sun)) == -1) {
|
||||
(void)close(data->log_file);
|
||||
data->log_file = -1;
|
||||
} else
|
||||
} else
|
||||
data->connected = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
init_hostname(void)
|
||||
{
|
||||
struct addrinfo *res;
|
||||
struct addrinfo hints = {
|
||||
.ai_family = PF_UNSPEC,
|
||||
.ai_socktype = 0,
|
||||
.ai_protocol = 0,
|
||||
.ai_flags = AI_CANONNAME,
|
||||
};
|
||||
|
||||
if (gethostname(hostname, sizeof(hostname)) == -1
|
||||
|| hostname[0] == '\0') {
|
||||
/* can this really happen? */
|
||||
hostname[0] = '-';
|
||||
hostname[1] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (strchr(hostname, '.') != NULL) /* FQDN */
|
||||
return;
|
||||
|
||||
if (getaddrinfo(hostname, NULL, &hints, &res) == 0)
|
||||
return;
|
||||
/* try to resolve back to hostname */
|
||||
(void)getnameinfo(res->ai_addr, (socklen_t)res->ai_addr->sa_len,
|
||||
hostname, sizeof(hostname), NULL, 0, 0) == 0)
|
||||
freeaddrinfo(res);
|
||||
}
|
||||
|
||||
static void
|
||||
openlog_unlocked_r(const char *ident, int logstat, int logfac,
|
||||
struct syslog_data *data)
|
||||
@ -409,6 +529,8 @@ openlog_unlocked_r(const char *ident, int logstat, int logfac,
|
||||
if (data->log_stat & LOG_NDELAY) /* open immediately */
|
||||
connectlog_r(data);
|
||||
|
||||
/* We could cache this, but then it might change */
|
||||
init_hostname();
|
||||
data->opened = 1;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: extern.h,v 1.15 2007/12/04 17:45:07 christos Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.16 2008/10/31 16:12:18 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997 Christos Zoulas. All rights reserved.
|
||||
@ -55,6 +55,12 @@ struct syslog_data;
|
||||
void syslog_ss(int, struct syslog_data *, const char *, ...)
|
||||
__attribute__((__format__(__printf__,3,4)));
|
||||
void vsyslog_ss(int, struct syslog_data *, const char *, _BSD_VA_LIST_);
|
||||
void vsyslog_ss(int, struct syslog_data *, const char *, _BSD_VA_LIST_)
|
||||
__attribute__((__format__(__printf__,3,0)));
|
||||
void syslogp_ss(int, struct syslog_data *, const char *, const char *,
|
||||
const char *, ...) __attribute__((__format__(__printf__,5,0)));
|
||||
void vsyslogp_ss(int, struct syslog_data *, const char *, const char *,
|
||||
const char *, _BSD_VA_LIST_) __attribute__((__format__(__printf__,5,0)));
|
||||
|
||||
int snprintf_ss(char * __restrict, size_t, const char * __restrict, ...)
|
||||
__attribute__((__format__(__printf__, 3, 4)));
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: namespace.h,v 1.133 2008/08/04 21:29:27 matt Exp $ */
|
||||
/* $NetBSD: namespace.h,v 1.134 2008/10/31 16:12:18 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997-2004 The NetBSD Foundation, Inc.
|
||||
@ -592,6 +592,9 @@
|
||||
#define syslog _syslog
|
||||
#define syslog_r _syslog_r
|
||||
#define syslog_ss _syslog_ss
|
||||
#define syslogp _syslogp
|
||||
#define syslogp_r _syslogp_r
|
||||
#define syslogp_ss _syslogp_ss
|
||||
#define taddr2uaddr _taddr2uaddr
|
||||
#define tcdrain _tcdrain
|
||||
#define tcflow _tcflow
|
||||
@ -634,6 +637,9 @@
|
||||
#define vsyslog _vsyslog
|
||||
#define vsyslog_r _vsyslog_r
|
||||
#define vsyslog_ss _vsyslog_ss
|
||||
#define vsyslogp _vsyslogp
|
||||
#define vsyslogp_r _vsyslogp_r
|
||||
#define vsyslogp_ss _vsyslogp_ss
|
||||
#define wait _wait
|
||||
#define wait3 _wait3
|
||||
#define waitpid _waitpid
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: syslog.h,v 1.31 2008/08/27 21:17:28 tls Exp $ */
|
||||
/* $NetBSD: syslog.h,v 1.32 2008/10/31 16:12:18 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1988, 1993
|
||||
@ -212,6 +212,16 @@ void syslog_r(int, struct syslog_data *, const char *, ...)
|
||||
__attribute__((__format__(__printf__,3,4)));
|
||||
void vsyslog_r(int, struct syslog_data *, const char *, _BSD_VA_LIST_)
|
||||
__attribute__((__format__(__printf__,3,0)));
|
||||
void syslogp(int, const char *, const char *, const char *, ...)
|
||||
__attribute__((__format__(__printf__,4,5)));
|
||||
void vsyslogp(int, const char *, const char *, const char *, _BSD_VA_LIST_)
|
||||
__attribute__((__format__(__printf__,4,0)));
|
||||
void syslogp_r(int, struct syslog_data *, const char *, const char *,
|
||||
const char *, ...)
|
||||
__attribute__((__format__(__printf__,5,6)));
|
||||
void vsyslogp_r(int, struct syslog_data *, const char *, const char *,
|
||||
const char *, _BSD_VA_LIST_)
|
||||
__attribute__((__format__(__printf__,5,0)));
|
||||
#endif
|
||||
__END_DECLS
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: logger.1,v 1.9 2003/08/07 11:14:23 agc Exp $
|
||||
.\" $NetBSD: logger.1,v 1.10 2008/10/31 16:12:18 christos Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1983, 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" @(#)logger.1 8.1 (Berkeley) 6/6/93
|
||||
.\"
|
||||
.Dd June 6, 1993
|
||||
.Dd August 17, 2008
|
||||
.Dt LOGGER 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -41,6 +41,8 @@
|
||||
.Op Fl f Ar file
|
||||
.Op Fl p Ar pri
|
||||
.Op Fl t Ar tag
|
||||
.Op Fl m Ar msgid
|
||||
.Op Fl d Ar SD
|
||||
.Op Ar message ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
@ -56,8 +58,17 @@ Log the process id of the logger process
|
||||
with each line.
|
||||
.It Fl s
|
||||
Log the message to standard error, as well as the system log.
|
||||
.It Fl d Ar sd
|
||||
Log this in the structured data (SD) field.
|
||||
.Po
|
||||
.Ar sd
|
||||
has to be passed as one argument and will require careful quoting when used from
|
||||
the shell.
|
||||
.Pc
|
||||
.It Fl f Ar file
|
||||
Log the specified file.
|
||||
.It Fl m Ar msgid
|
||||
The MSGID used for the message.
|
||||
.It Fl p Ar pri
|
||||
Enter the message with the specified priority.
|
||||
The priority may be specified numerically or as a ``facility.level''
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: logger.c,v 1.10 2008/07/21 14:19:23 lukem Exp $ */
|
||||
/* $NetBSD: logger.c,v 1.11 2008/10/31 16:12:18 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1983, 1993
|
||||
@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)logger.c 8.1 (Berkeley) 6/6/93";
|
||||
#endif
|
||||
__RCSID("$NetBSD: logger.c,v 1.10 2008/07/21 14:19:23 lukem Exp $");
|
||||
__RCSID("$NetBSD: logger.c,v 1.11 2008/10/31 16:12:18 christos Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <errno.h>
|
||||
@ -69,13 +69,18 @@ main(int argc, char *argv[])
|
||||
{
|
||||
int ch, logflags, pri;
|
||||
const char *tag;
|
||||
const char *sd = "-";
|
||||
const char *msgid = "-";
|
||||
char buf[1024];
|
||||
|
||||
tag = NULL;
|
||||
pri = LOG_NOTICE;
|
||||
logflags = 0;
|
||||
while ((ch = getopt(argc, argv, "f:ip:st:")) != -1)
|
||||
while ((ch = getopt(argc, argv, "d:f:im:p:st:")) != -1)
|
||||
switch((char)ch) {
|
||||
case 'd': /* structured data field */
|
||||
sd = optarg;
|
||||
break;
|
||||
case 'f': /* file to log */
|
||||
if (freopen(optarg, "r", stdin) == NULL)
|
||||
err(EXIT_FAILURE, "%s", optarg);
|
||||
@ -83,6 +88,9 @@ main(int argc, char *argv[])
|
||||
case 'i': /* log process id also */
|
||||
logflags |= LOG_PID;
|
||||
break;
|
||||
case 'm': /* msgid field */
|
||||
msgid = optarg;
|
||||
break;
|
||||
case 'p': /* priority */
|
||||
pri = pencode(optarg);
|
||||
break;
|
||||
@ -111,11 +119,11 @@ main(int argc, char *argv[])
|
||||
for (p = buf, endp = buf + sizeof(buf) - 2; *argv != NULL;) {
|
||||
len = strlen(*argv);
|
||||
if (p + len > endp && p > buf) {
|
||||
syslog(pri, "%s", buf);
|
||||
syslogp(pri, "%s", "%s", "%s", msgid, sd, buf);
|
||||
p = buf;
|
||||
}
|
||||
if (len > sizeof(buf) - 1)
|
||||
syslog(pri, "%s", *argv++);
|
||||
syslogp(pri, "%s", "%s", "%s", msgid, sd, *argv++);
|
||||
else {
|
||||
if (p != buf)
|
||||
*p++ = ' ';
|
||||
@ -124,10 +132,13 @@ main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
if (p != buf)
|
||||
syslog(pri, "%s", buf);
|
||||
} else
|
||||
syslogp(pri, "%s", "%s", "%s", msgid, sd, buf);
|
||||
} else /* TODO: allow syslog-protocol messages from file/stdin
|
||||
* but that will require parsing the line to split
|
||||
* it into three fields.
|
||||
*/
|
||||
while (fgets(buf, sizeof(buf), stdin) != NULL)
|
||||
syslog(pri, "%s", buf);
|
||||
syslogp(pri, "%s", "%s", "%s", msgid, sd, buf);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
/* NOTREACHED */
|
||||
@ -180,7 +191,8 @@ usage(void)
|
||||
{
|
||||
|
||||
(void)fprintf(stderr,
|
||||
"%s: [-is] [-f file] [-p pri] [-t tag] [ message ... ]\n",
|
||||
"%s: [-is] [-f file] [-p pri] [-t tag] "
|
||||
"[-m msgid] [-d SD] [ message ... ]\n",
|
||||
getprogname());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: newsyslog.c,v 1.53 2007/12/21 06:46:31 dogcow Exp $ */
|
||||
/* $NetBSD: newsyslog.c,v 1.54 2008/10/31 16:12:19 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999, 2000 Andrew Doran <ad@NetBSD.org>
|
||||
@ -55,7 +55,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: newsyslog.c,v 1.53 2007/12/21 06:46:31 dogcow Exp $");
|
||||
__RCSID("$NetBSD: newsyslog.c,v 1.54 2008/10/31 16:12:19 christos Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -79,9 +79,9 @@ __RCSID("$NetBSD: newsyslog.c,v 1.53 2007/12/21 06:46:31 dogcow Exp $");
|
||||
#include <err.h>
|
||||
#include <paths.h>
|
||||
|
||||
#define PRHDRINFO(x) \
|
||||
#define PRHDRINFO(x) \
|
||||
(/*LINTED*/(void)(verbose ? printf x : 0))
|
||||
#define PRINFO(x) \
|
||||
#define PRINFO(x) \
|
||||
(/*LINTED*/(void)(verbose ? printf(" ") + printf x : 0))
|
||||
|
||||
#ifndef __arraycount
|
||||
@ -92,6 +92,8 @@ __RCSID("$NetBSD: newsyslog.c,v 1.53 2007/12/21 06:46:31 dogcow Exp $");
|
||||
#define CE_NOSIGNAL 0x04 /* Don't send a signal when trimmed */
|
||||
#define CE_CREATE 0x08 /* Create log file if none exists */
|
||||
#define CE_PLAIN0 0x10 /* Do not compress zero'th history file */
|
||||
#define CE_SYSLPROTOCOL 0x20 /* log in syslog-protocol format,
|
||||
not configurable but detected at runtime */
|
||||
|
||||
struct conf_entry {
|
||||
uid_t uid; /* Owner of log */
|
||||
@ -127,7 +129,7 @@ static struct compressor compress[] =
|
||||
static int verbose; /* Be verbose */
|
||||
static int noaction; /* Take no action */
|
||||
static int nosignal; /* Do not send signals */
|
||||
static char hostname[MAXHOSTNAMELEN + 1]; /* Hostname, no domain */
|
||||
static char hostname[MAXHOSTNAMELEN + 1]; /* Hostname, with domain */
|
||||
static uid_t myeuid; /* EUID we are running with */
|
||||
static int ziptype; /* compression type, if any */
|
||||
|
||||
@ -145,6 +147,7 @@ static void log_create(struct conf_entry *);
|
||||
static void log_examine(struct conf_entry *, int);
|
||||
static void log_trim(struct conf_entry *);
|
||||
static void log_trimmed(struct conf_entry *);
|
||||
static void log_get_format(struct conf_entry *);
|
||||
|
||||
/*
|
||||
* Program entry point.
|
||||
@ -154,7 +157,6 @@ main(int argc, char **argv)
|
||||
{
|
||||
struct conf_entry log;
|
||||
FILE *fd;
|
||||
char *p;
|
||||
const char *cfile;
|
||||
int c, needroot, i, force;
|
||||
size_t lineno;
|
||||
@ -167,10 +169,6 @@ main(int argc, char **argv)
|
||||
(void)gethostname(hostname, sizeof(hostname));
|
||||
hostname[sizeof(hostname) - 1] = '\0';
|
||||
|
||||
/* Truncate domain. */
|
||||
if ((p = strchr(hostname, '.')) != NULL)
|
||||
*p = '\0';
|
||||
|
||||
/* Parse command line options. */
|
||||
while ((c = getopt(argc, argv, "f:nrsvF")) != -1) {
|
||||
switch (c) {
|
||||
@ -415,7 +413,7 @@ bad:
|
||||
}
|
||||
|
||||
/*
|
||||
* Examine a log file. If the trim conditions are met, call log_trim() to
|
||||
* Examine a log file. If the trim conditions are met, call log_trim() to
|
||||
* trim the log file.
|
||||
*/
|
||||
static void
|
||||
@ -435,7 +433,7 @@ log_examine(struct conf_entry *log, int force)
|
||||
compress[ziptype].flag));
|
||||
|
||||
/*
|
||||
* stat() the logfile. If it doesn't exist and the `c' flag has
|
||||
* stat() the logfile. If it doesn't exist and the `c' flag has
|
||||
* been specified, create it. If it doesn't exist and the `c' flag
|
||||
* hasn't been specified, give up.
|
||||
*/
|
||||
@ -486,7 +484,7 @@ log_examine(struct conf_entry *log, int force)
|
||||
*
|
||||
* Note: if `maxage' or `trimat' is used as a trim condition, we
|
||||
* need at least one historical log file to determine the `age' of
|
||||
* the active log file. WRT `trimat', we will trim up to one hour
|
||||
* the active log file. WRT `trimat', we will trim up to one hour
|
||||
* after the specific trim time has passed - we need to know if
|
||||
* we've trimmed to meet that condition with a previous invocation
|
||||
* of newsyslog(8).
|
||||
@ -568,7 +566,7 @@ log_trim(struct conf_entry *log)
|
||||
/*
|
||||
* If a historical log file isn't compressed, and 'z' has been
|
||||
* specified, compress it. (This is convenient, but is also needed
|
||||
* if 'p' has been specified.) It should be noted that gzip(1)
|
||||
* if 'p' has been specified.) It should be noted that gzip(1)
|
||||
* preserves file ownership and file mode.
|
||||
*/
|
||||
if (ziptype) {
|
||||
@ -583,7 +581,7 @@ log_trim(struct conf_entry *log)
|
||||
log_compress(log, file1);
|
||||
}
|
||||
}
|
||||
|
||||
log_get_format(log);
|
||||
log_trimmed(log);
|
||||
|
||||
/* Create the historical log file if we're maintaining history. */
|
||||
@ -637,6 +635,30 @@ log_trim(struct conf_entry *log)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
log_get_format(struct conf_entry *log)
|
||||
{
|
||||
FILE *fd;
|
||||
char *line;
|
||||
size_t linelen;
|
||||
|
||||
if ((log->flags & CE_BINARY) != 0)
|
||||
return;
|
||||
PRINFO(("(read line format of %s)\n", log->logfile));
|
||||
if (noaction)
|
||||
return;
|
||||
|
||||
if ((fd = fopen(log->logfile, "r")) == NULL)
|
||||
return;
|
||||
|
||||
/* read 2nd line */
|
||||
line = fgetln(fd, &linelen);
|
||||
if ((line = fgetln(fd, &linelen)) != NULL
|
||||
&& line[10] == 'T')
|
||||
log->flags |= CE_SYSLPROTOCOL;
|
||||
(void)fclose(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write an entry to the log file recording the fact that it was trimmed.
|
||||
*/
|
||||
@ -646,6 +668,7 @@ log_trimmed(struct conf_entry *log)
|
||||
FILE *fd;
|
||||
time_t now;
|
||||
char *daytime;
|
||||
char trim_message[] = "log file turned over";
|
||||
|
||||
if ((log->flags & CE_BINARY) != 0)
|
||||
return;
|
||||
@ -656,12 +679,54 @@ log_trimmed(struct conf_entry *log)
|
||||
if ((fd = fopen(log->logfile, "at")) == NULL)
|
||||
err(EXIT_FAILURE, "%s", log->logfile);
|
||||
|
||||
now = time(NULL);
|
||||
daytime = ctime(&now) + 4;
|
||||
daytime[15] = '\0';
|
||||
if ((log->flags & CE_SYSLPROTOCOL) == 0) {
|
||||
char shorthostname[MAXHOSTNAMELEN];
|
||||
char *p;
|
||||
|
||||
(void)fprintf(fd, "%s %s newsyslog[%lu]: log file turned over\n",
|
||||
daytime, hostname, (u_long)getpid());
|
||||
/* Truncate domain. */
|
||||
(void)strlcpy(shorthostname, hostname, sizeof(SHORTHOSTNAME));
|
||||
if ((p = strchr(shorthostname, '.')) != NULL)
|
||||
*p = '\0';
|
||||
|
||||
now = time(NULL);
|
||||
daytime = ctime(&now) + 4;
|
||||
daytime[15] = '\0';
|
||||
|
||||
(void)fprintf(fd, "%s %s newsyslog[%lu]: %s\n",
|
||||
daytime, hostname, (u_long)getpid(), trim_message);
|
||||
} else {
|
||||
struct tm *tmnow;
|
||||
struct timeval tv;
|
||||
char timestamp[35];
|
||||
unsigned i, j;
|
||||
|
||||
if (gettimeofday(&tv, NULL) == -1) {
|
||||
daytime = "-";
|
||||
} else {
|
||||
tzset();
|
||||
now = (time_t) tv.tv_sec;
|
||||
tmnow = localtime(&now);
|
||||
|
||||
i = strftime(timestamp, sizeof(timestamp),
|
||||
"%FT%T", tmnow);
|
||||
i += snprintf(timestamp+i, sizeof(timestamp)-i,
|
||||
".%06ld", tv.tv_usec);
|
||||
i += j = strftime(timestamp+i, sizeof(timestamp)-i-1,
|
||||
"%z", tmnow);
|
||||
/* strftime gives eg. "+0200", but we need "+02:00" */
|
||||
if (j == 5) {
|
||||
timestamp[i+1] = timestamp[i];
|
||||
timestamp[i] = timestamp[i-1];
|
||||
timestamp[i-1] = timestamp[i-2];
|
||||
timestamp[i-2] = ':';
|
||||
i += 1;
|
||||
}
|
||||
daytime = timestamp;
|
||||
}
|
||||
(void)fprintf(fd, "%s %s newsyslog %lu - - %s\n",
|
||||
daytime, hostname, (u_long)getpid(), trim_message);
|
||||
|
||||
}
|
||||
(void)fclose(fd);
|
||||
}
|
||||
|
||||
@ -861,7 +926,7 @@ parse_userspec(const char *name, struct passwd **pw, struct group **gr)
|
||||
* to rotate a log file cyclic at
|
||||
*
|
||||
* - every day (D) within a specific hour (hh) (hh = 0...23)
|
||||
* - once a week (W) at a specific day (d) OR (d = 0..6, 0 = Sunday)
|
||||
* - once a week (W) at a specific day (d) OR (d = 0..6, 0 = Sunday)
|
||||
* - once a month (M) at a specific day (d) (d = 1..31,l|L)
|
||||
*
|
||||
* We don't accept a timezone specification; missing fields are defaulted to
|
||||
@ -964,7 +1029,7 @@ parse_dwm(char *s)
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a limited subset of ISO 8601. The specific format is as follows:
|
||||
* Parse a limited subset of ISO 8601. The specific format is as follows:
|
||||
*
|
||||
* [CC[YY[MM[DD]]]][THH[MM[SS]]] (where `T' is the literal letter)
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: Makefile,v 1.7 2008/10/19 22:05:24 apb Exp $
|
||||
# $NetBSD: Makefile,v 1.8 2008/10/31 16:12:19 christos Exp $
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
@ -6,7 +6,7 @@ USE_WIDECHAR?=yes
|
||||
|
||||
CPPFLAGS+=-I${DIST}/include -I${.CURDIR} -I. -DGTAGS
|
||||
WARNS=0
|
||||
#DBG=-g
|
||||
DBG=-g
|
||||
|
||||
#CWARNFLAGS+=-Wno-parentheses -Wno-unused -Wno-missing-prototypes
|
||||
#.if defined(HAVE_GCC) && ${HAVE_GCC} == 4
|
||||
|
@ -1,19 +1,21 @@
|
||||
# $NetBSD: Makefile,v 1.20 2007/05/28 12:06:42 tls Exp $
|
||||
# $NetBSD: Makefile,v 1.21 2008/10/31 16:12:19 christos Exp $
|
||||
# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
WARNS=5
|
||||
USE_FORT?= yes # network server
|
||||
|
||||
LINTFLAGS+=-X 132,247,135,259,117,298
|
||||
|
||||
PROG= syslogd
|
||||
SRCS= syslogd.c utmpentry.c
|
||||
SRCS= syslogd.c utmpentry.c tls.c sign.c
|
||||
MAN= syslogd.8 syslog.conf.5
|
||||
DPADD+=${LIBUTIL}
|
||||
LDADD+=-lutil
|
||||
DPADD+=${LIBUTIL} ${LIBEVENT}
|
||||
LDADD+=-lutil -levent
|
||||
#make symlink to old socket location for transitional period
|
||||
SYMLINKS= /var/run/log /dev/log
|
||||
.PATH.c: ${NETBSDSRCDIR}/usr.bin/who
|
||||
CPPFLAGS+=-I${NETBSDSRCDIR}/usr.bin/who -DSUPPORT_UTMPX -DSUPPORT_UTMP
|
||||
CPPFLAGS+=-I${NETBSDSRCDIR}/usr.bin/who -DSUPPORT_UTMPX -DSUPPORT_UTMP -Wredundant-decls
|
||||
|
||||
.if (${USE_INET6} != "no")
|
||||
CPPFLAGS+=-DINET6
|
||||
@ -23,4 +25,8 @@ CPPFLAGS+=-DLIBWRAP
|
||||
LDADD+= -lwrap
|
||||
DPADD+= ${LIBWRAP}
|
||||
|
||||
.if ${MKCRYPTO} != "no"
|
||||
LDADD+= -lssl -lcrypto
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
89
usr.sbin/syslogd/extern.h
Normal file
89
usr.sbin/syslogd/extern.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* $NetBSD: extern.h,v 1.1 2008/10/31 16:12:19 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Martin Schütte.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* extern.h
|
||||
*
|
||||
* declarations for variables and functions from syslogd.c
|
||||
* that are used in tls.c and sign.c
|
||||
*/
|
||||
#ifndef EXTERN_H_
|
||||
#define EXTERN_H_
|
||||
|
||||
|
||||
/* variables */
|
||||
extern int Debug;
|
||||
extern struct tls_global_options_t tls_opt;
|
||||
extern struct TLS_Incoming TLS_Incoming_Head;
|
||||
extern struct sign_global_t GlobalSign;
|
||||
extern char *linebuf;
|
||||
extern size_t linebufsize;
|
||||
extern int RemoteAddDate;
|
||||
|
||||
extern bool BSDOutputFormat;
|
||||
extern time_t now;
|
||||
extern char timestamp[];
|
||||
extern char appname[];
|
||||
extern char *LocalFQDN;
|
||||
extern char *include_pid;
|
||||
|
||||
/* functions */
|
||||
extern void logerror(const char *, ...)
|
||||
__attribute__((__format__(__printf__,1,2)));
|
||||
extern void loginfo(const char *, ...)
|
||||
__attribute__((__format__(__printf__,1,2)));
|
||||
extern void printline(const char *, char *, int);
|
||||
extern void die(int fd, short event, void *ev)
|
||||
__attribute__((__noreturn__));
|
||||
extern struct event *allocev(void);
|
||||
extern void send_queue(int __unused, short __unused, void *);
|
||||
extern void schedule_event(struct event **, struct timeval *,
|
||||
void (*)(int, short, void *), void *);
|
||||
extern char *make_timestamp(time_t *, bool);
|
||||
extern struct filed *get_f_by_conninfo(struct tls_conn_settings *conn_info);
|
||||
extern bool message_queue_remove(struct filed *, struct buf_queue *);
|
||||
extern void buf_msg_free(struct buf_msg *msg);
|
||||
extern void message_queue_freeall(struct filed *);
|
||||
extern bool copy_string(char **, const char *, const char *);
|
||||
extern bool copy_config_value_quoted(const char *, char **, const char **);
|
||||
extern size_t message_allqueues_purge(void);
|
||||
extern bool format_buffer(struct buf_msg*, char**, size_t*, size_t*, size_t*,
|
||||
size_t*);
|
||||
extern void fprintlog(struct filed *, struct buf_msg *, struct buf_queue *);
|
||||
extern struct buf_msg *buf_msg_new(const size_t);
|
||||
|
||||
#endif /*EXTERN_H_*/
|
89
usr.sbin/syslogd/howto.html
Normal file
89
usr.sbin/syslogd/howto.html
Normal file
@ -0,0 +1,89 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>NetBSD & Google's Summer of Code: Martin Schuette - Improve syslogd (syslogd)</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Testing syslogd</h1>
|
||||
<h2>Compiling</h2>
|
||||
<p>A (hopefully) stable version for testing is available by <a href="http://netbsd-soc.cvs.sourceforge.net/netbsd-soc/syslogd/src/">CVS</a> and as a <a href="syslogd-tls.tar.gz">.tar.gz archive</a>. It contains syslogd itself and all necessary files to build on NetBSD and FreeBSD.</p>
|
||||
|
||||
<p>To build just type <span style="font-family: monospace;">make</span>. Unless you have a complete NetBSD source tree -- then you can extract the files to <span style="font-family: monospace;">/usr/src/usr.sbin/syslogd</span> and replace the <span style="font-family: monospace;">Makefile</span> with <span style="font-family: monospace;">Makefile.NetBSD</span> and then type <span style="font-family: monospace;">make</span>.
|
||||
|
||||
<h3>Note on other BSDs</h3>
|
||||
<p>I also tested syslogd on FreeBSD. There are just a few issues/differences:</p>
|
||||
<ul>
|
||||
<li>You have to install libevent first</li>
|
||||
<li>No pidfile is written</li>
|
||||
<li>The code for wallmsg() is only copied, not tested</li>
|
||||
</ul>
|
||||
<p>I assume the same holds for other BSDs but I have no live system to test them.</p>
|
||||
|
||||
|
||||
<h2>Command line options</h2>
|
||||
<p>syslogd has to be run as root (because it uses chroot()). You should start it with option "-u username" to drop privileges.</p>
|
||||
|
||||
<p>By default messages are written in syslog Protocol format. To get the BSD Syslog output like from previous versions use the "-o" option.</p>
|
||||
|
||||
<h2>syslog.conf</h2>
|
||||
|
||||
<p>To use TLS some additional configuration is required.</p>
|
||||
|
||||
<h3>X.509 certificates</h3>
|
||||
<p>Every syslogd using TLS needs an X.509 certificate.
|
||||
The files containing the private key, certificate, and CA are configured with:</p>
|
||||
<pre>
|
||||
tls_key="/etc/openssl/default.key"
|
||||
tls_cert="/etc/openssl/default.crt"
|
||||
tls_ca="/some/where/my.cacert"
|
||||
</pre>
|
||||
|
||||
<p>If you do not already have a X.509 certificate then you can tell syslogd to generate one for you with</p>
|
||||
<pre>
|
||||
tls_gen_cert=on
|
||||
</pre>
|
||||
|
||||
<h3>TLS client</h3>
|
||||
<p>To send messages with configure a TLS destination. Here are three examples with different additional options required for authentication</p>
|
||||
<pre>
|
||||
# with CA
|
||||
*.* @[logserver.example.org]:13245
|
||||
*.* @[127.0.0.1]:13245(subject="logserver.example.org")
|
||||
# without CA
|
||||
*.* @[127.0.0.1]:13245(fingerprint="SHA1:E4:E1:A6:1C:D4:31:D7:D4:9B:B8:DC:DF:DD:CE:30:71:46:00:92:C9")
|
||||
</pre>
|
||||
|
||||
<p>If using a CA then it is checked whether the server's certificate matches the hostname or a given subject. Assuming the logserver's certificate has "logserver.example.org" as its commonName or as a subjectAltName/dnsName the first line is sufficient. (Once a standard portnumber has been assigned the port becomes optional.) If we do not want to rely on DNS and configure the destination with "127.0.0.1" then the subject comparison will fail. The alternatives are either to configure the subject as an option (as in the example above) or to generate a new certificate with the server's IP as a commonName or subjectAltName/ipAddress.</p>
|
||||
|
||||
<p>Without a CA the easiest way to authenticate the peer's certificate is its fingerprint as in the last line in the example. syslogd logs the fingerprints of all certificates it loads or tries to connect with, but it can also be read from the shell with "openssl x509 -in /etc/openssl/default.crt -noout -fingerprint".</p>
|
||||
|
||||
<h3>TLS server</h3>
|
||||
<p>To enable TLS server mode use these lines.</p>
|
||||
<pre>
|
||||
tls_server="on"
|
||||
tls_bindhost="127.0.0.1"
|
||||
tls_bindport="13245"
|
||||
</pre>
|
||||
<p>The bindhost is optional. The bindport is currently required (as long as there is no tcp port defined for the syslog service).</p>
|
||||
|
||||
<p>With a CA that is all -- there is no additional hostname check for clients.
|
||||
Without a CA the server needs to be told which certificates to trust:</p>
|
||||
<pre>
|
||||
tls_allow_fingerprints = MD5:00:A2:A7:02:CA:A0:0E:00:DC:F1:91:BE:6A:AA:FF:27 "SHA1:E4:E1:A6:1C:D4:31:D7:D4:9B:B8:DC:DF:DD:CE:30:71:46:00:92:C9"
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
<table border=0>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="http://sourceforge.net"><img align="top" src="http://sourceforge.net/sflogo.php?group_id=141771&type=2" width="125" height="37" border="0" alt="SourceForge.net Logo" /></a>
|
||||
<td>
|
||||
<table>
|
||||
<tr> <td> Martin Schütte <<tt>info@mschuette.name</tt>> </td> </tr>
|
||||
<tr> <td> $Id: howto.html,v 1.1 2008/10/31 16:12:19 christos Exp $ </td> </tr>
|
||||
</table>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
161
usr.sbin/syslogd/index.html
Normal file
161
usr.sbin/syslogd/index.html
Normal file
@ -0,0 +1,161 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>NetBSD & Google's Summer of Code: Martin Schuette - Improve syslogd (syslogd)</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center>
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="http://www.NetBSD.org/"><img border=0 valign="top" src="../../NetBSD.png" alt="[NetBSD logo]" /></a></td>
|
||||
<td><font size="+5"> & </font></td>
|
||||
<td><a href="http://www.google.com/"><img border=0 valign="bottom" src="http://www.google.com/intl/en/images/logo.gif" alt="[Google logo]" /></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
|
||||
<h1>NetBSD-SoC: Improve syslogd</h1>
|
||||
|
||||
<h2>What is it?</h2>
|
||||
|
||||
<p>The syslog daemon handles most log messages of a unixoid system. It receives messages from shell-scripts, applications, daemons, the kernel, or by network and then writes them into logfiles, on user's consoles or forwards them to some other logserver -- all depending on its configuration and the message properties.</p>
|
||||
|
||||
<p>implemented the upcoming <a class="ext-link" href="http://tools.ietf.org/wg/syslog/">IETF
|
||||
standards</a> for <a class="ext-link" href="http://www.netbsd.org/">NetBSD</a>'s syslog(3)
|
||||
and syslogd(8):
|
||||
</p>
|
||||
<ul><li><a class="ext-link"
|
||||
href="http://tools.ietf.org/html/draft-ietf-syslog-transport-tls"><span
|
||||
class="icon">transport-tls</span></a> defines the network protocol to send
|
||||
syslog data over TLS (instead of UDP), thus providing a reliable and
|
||||
authenticated transport.
|
||||
</li><li><a class="ext-link"
|
||||
href="http://tools.ietf.org/html/draft-ietf-syslog-protocol"><span
|
||||
class="icon">syslog-protocol</span></a> defines a new layout for syslog
|
||||
lines; the most important additions are full timestamps (with year and timezone)
|
||||
and structured data with name=value pairs. This enables all programs to declare
|
||||
semantic content (uid, client IP, return codes, etc), making automatic
|
||||
log-monitoring (or at least parsing) much easier.
|
||||
</li><li><a class="ext-link"
|
||||
href="http://tools.ietf.org/html/draft-ietf-syslog-sign"><span
|
||||
class="icon">syslog-sign</span></a> defines signature messages to assert
|
||||
authentication, integrity and correct sequencing of syslog messages.
|
||||
</li></ul><p>
|
||||
To my knowledge this is one of the first implementations of these
|
||||
protocols. It will provide NetBSD (and hopefully the other BSDs as well) with
|
||||
an advanced, reliable, and secure syslogd; thus saving admins the time and
|
||||
effort to install custom logging solutions just to get secure transport to
|
||||
their central logserver.
|
||||
</p>
|
||||
|
||||
<h2>Current Status</h2>
|
||||
<h3>Functions</h3>
|
||||
<h4>TLS</h4>
|
||||
<p>The TLS support is now working (tested with RSA and DSA keys).
|
||||
It will read its configuration from syslog.conf, accept incoming TLS connections
|
||||
to receive messages, establish connections to other TLS servers.</p>
|
||||
<p>If a TLS server is temporarily not available then its messages will be buffered
|
||||
and sent after reconnection.</p>
|
||||
|
||||
<h4>syslog-protocol</h4>
|
||||
<p>A command line option determines whether syslogd output is in BSD Syslog or in syslog-protocol format. All received messages are converted accordingly.</p>
|
||||
<p>I also modified syslog(3) in libc to send syslog-protocol messages.</p>
|
||||
<p>While syslog(3) can only use the message field, a new syslogp(3) call is provided to add a MSGID and structured data to a message.</p>
|
||||
|
||||
<h4>syslog-sign</h4>
|
||||
<p>syslogd(8) is now able to <a href="sign.html">digitally sign messages with syslog-sign.</a></p>
|
||||
|
||||
<h3>syslog.conf</h3>
|
||||
<p>I extended the traditional configuration file format to support additionally fields for TLS.
|
||||
A syslog.conf for TLS currently looks like this:</p>
|
||||
<pre>
|
||||
# TLS options
|
||||
tls_ca="/etc/my.cacert"
|
||||
tls_cert="/etc/localhost.crt"
|
||||
tls_key="/etc/localhost.key"
|
||||
tls_verify="off"
|
||||
tls_bindhost="127.0.0.1"
|
||||
tls_bindport="13245"
|
||||
tls_server=on
|
||||
|
||||
# file destination
|
||||
*.* /home/mschuett/test.log
|
||||
# UDP destination
|
||||
*.* @192.168.178.5
|
||||
# TLS destination
|
||||
*.* @[127.0.0.1]:5555(fingerprint="SHA1:E4:E1:A6:1C:D4:31:D7:D4:9B:B8:DC:DF:DD:CE:30:71:46:00:92:C9")
|
||||
</pre>
|
||||
|
||||
<h3>Source Code</h3>
|
||||
<p>To try syslogd fetch the latest <a href="http://mschuette.name/files/syslogd_080818.tar.gz">.tar.gz archive (2008-08-18)</a> (older versions: <a href="http://mschuette.name/files/syslogd_080805.tar.gz">2008-08-05</a>, <a href="http://mschuette.name/files/syslogd-tls.tar.gz">2008-08-05</a>).</p>
|
||||
|
||||
<p>The sources for <a href="http://netbsd-soc.cvs.sourceforge.net/netbsd-soc/syslogd/src/">syslogd</a>, the <a href="http://netbsd-soc.cvs.sourceforge.net/netbsd-soc/syslogd/src-libc_gen/">libc functions</a>, <a href="http://netbsd-soc.cvs.sourceforge.net/netbsd-soc/syslogd/src-newsyslog/">newsyslog</a>, and <a href="http://netbsd-soc.cvs.sourceforge.net/netbsd-soc/syslogd/src-logger/">logger</a> are also available from the <a href="http://netbsd-soc.cvs.sourceforge.net/netbsd-soc/syslogd/">CVS on sourceforge</a>.</p>
|
||||
|
||||
<p>For development I used an own <a href="https://anonymous:anonymous@barney.cs.uni-potsdam.de/svn/syslogd/trunk/src/">SVN</a>; a detailed timeline of code changes is available in the <a href="https://barney.cs.uni-potsdam.de/trac/syslogd/timeline">on my Trac</a>.</p>
|
||||
|
||||
<p>The syslogd code needs <a href="http://www.openssl.org/ OpenSSL"></a> and <a href="http://www.monkey.org/~provos/libevent/">libevent</a>. The only system-dependent function is wallmsg() to write messages to users's terminals.<br/>
|
||||
It was developed and tested on NetBSD and FreeBSD. I heard it does not compile on OpenBSD (I do not know about DragonflyBSD), probably due to different files under /usr/include. I would be interested if someone tried to compile on Linux; this will be some more work, because one will also need additional functions from BSDs libc that are not in glibc (most notably strlcat()).</p>
|
||||
|
||||
<h2>Deliverables</h2>
|
||||
<p>
|
||||
I got all my <b>mandatory components</b>:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Implement transport-tls in syslogd(8)</li>
|
||||
<li>Implement syslog-protocol in syslogd(8)</li>
|
||||
<li>Implement syslog-protocol in syslog(3)</li>
|
||||
<li>Implement syslog-sign in syslogd(8)</li>
|
||||
</ul>
|
||||
<p>
|
||||
...and parts of my <b>optional components</b>:
|
||||
</p>
|
||||
<ul>
|
||||
<li>interoperability with other implementations: so far I could only test TLS-transport with rsyslog</li>
|
||||
<li>Extended API to use new functions: with syslogp() I wrote a new API; but it is not really the extended API I had in mind here.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Documentation</h2>
|
||||
|
||||
<p>New manpages and description:</p>
|
||||
<ul>
|
||||
<li>my <a href="./doc/syslogd.8.html">syslogd(8)</a></li>
|
||||
<li>my <a href="./doc/syslog.conf.5.html">syslog.conf(5)</a></li>
|
||||
<li>my <a href="./doc/syslog.3.html">syslog(3)/syslogp(3)</a></li>
|
||||
<li><a href="howto.html">How-To configure a TLS transport</a></li>
|
||||
<li><a href="sign.html">Overview of syslog-sign and its usage</a></li>
|
||||
</ul>
|
||||
|
||||
<p>Existing specifications and man-pages:</p>
|
||||
<ul>
|
||||
<li><a href="http://tools.ietf.org/html/rfc3164">RFC3164: The BSD syslog Protocol</a></li>
|
||||
<li><a href="http://netbsd.gw.com/cgi-bin/man-cgi?syslogd++NetBSD-current">syslogd(8)</a></li>
|
||||
<li><a href="http://netbsd.gw.com/cgi-bin/man-cgi?syslog.conf+5+NetBSD-current">syslog.conf(5)</a></li>
|
||||
<li><a href="http://netbsd.gw.com/cgi-bin/man-cgi?syslog+3+NetBSD-current">syslog(3)</a></li>
|
||||
<li><a href="http://www.opengroup.org/onlinepubs/009695399/basedefs/syslog.h.html">SUS on syslog.h</a></li>
|
||||
<li><a href="http://www.opengroup.org/onlinepubs/009695399/functions/syslog.html">SUS on syslog()</a></li>
|
||||
</ul>
|
||||
|
||||
<p>IETF documents:</p>
|
||||
<ul>
|
||||
<li><a href="http://tools.ietf.org/html/draft-ietf-syslog-transport-udp">Transmission of syslog messages over UDP (draft-ietf-syslog-transport-udp)</a></li>
|
||||
<li><a href="http://tools.ietf.org/html/draft-ietf-syslog-transport-tls">TLS Transport Mapping for Syslog (draft-ietf-syslog-transport-tls)</a></li>
|
||||
<li><a href="http://tools.ietf.org/html/draft-ietf-syslog-protocol">The syslog Protocol (draft-ietf-syslog-protocol)</a></li>
|
||||
<li><a href="http://tools.ietf.org/html/draft-ietf-syslog-sign">Signed syslog Messages (draft-ietf-syslog-sign)</a></li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<table border=0>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="http://sourceforge.net"><img align="top" src="http://sourceforge.net/sflogo.php?group_id=141771&type=2" width="125" height="37" border="0" alt="SourceForge.net Logo" /></a>
|
||||
<td>
|
||||
<table>
|
||||
<tr> <td> Martin Schütte <<tt>info@mschuette.name</tt>> </td> </tr>
|
||||
<tr> <td> $Id: index.html,v 1.1 2008/10/31 16:12:19 christos Exp $ </td> </tr>
|
||||
</table>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
936
usr.sbin/syslogd/sign.c
Normal file
936
usr.sbin/syslogd/sign.c
Normal file
@ -0,0 +1,936 @@
|
||||
/* $NetBSD: sign.c,v 1.1 2008/10/31 16:12:19 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Martin Schütte.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* sign.c
|
||||
* syslog-sign related code for syslogd
|
||||
*
|
||||
* Martin Schütte
|
||||
*/
|
||||
/*
|
||||
* Issues with the current internet draft:
|
||||
* 1. The draft is a bit unclear on the input format for the signature,
|
||||
* so this might have to be changed later. Cf. sign_string_sign()
|
||||
* 2. The draft only defines DSA signatures. I hope it will be extended
|
||||
* to DSS, thus allowing DSA, RSA (ANSI X9.31) and ECDSA (ANSI X9.62)
|
||||
* 3. The draft does not define the data format for public keys in CBs.
|
||||
* This implementation sends public keys in DER encoding.
|
||||
* 4. This current implementation uses high-level OpenSSL API.
|
||||
* I am not sure if these completely implement the FIPS/ANSI standards.
|
||||
* Update after WG discussion in August:
|
||||
* 1. check; next draft will be clearer and specify the format as implemented.
|
||||
* 2. check; definitely only DSA in this version.
|
||||
* 3. remains a problem, so far no statement from authors or WG.
|
||||
* 4. check; used EVP_dss1 method implements FIPS.
|
||||
*/
|
||||
/*
|
||||
* Limitations of this implementation:
|
||||
* - cannot use OpenPGP keys, only PKIX or DSA due to OpenSSL capabilities
|
||||
* - only works for correctly formatted messages, because incorrect messages
|
||||
* are reformatted (e.g. if it receives a message with two spaces between
|
||||
* fields it might even be parsed, but the output will have only one space).
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: sign.c,v 1.1 2008/10/31 16:12:19 christos Exp $");
|
||||
|
||||
#ifndef DISABLE_SIGN
|
||||
#include "syslogd.h"
|
||||
#ifndef DISABLE_TLS
|
||||
#include "tls.h"
|
||||
#endif /* !DISABLE_TLS */
|
||||
#include "sign.h"
|
||||
#include "extern.h"
|
||||
|
||||
/*
|
||||
* init all SGs for a given algorithm
|
||||
*/
|
||||
bool
|
||||
sign_global_init(struct filed *Files)
|
||||
{
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_global_init()\n");
|
||||
if (!(GlobalSign.sg == 0 || GlobalSign.sg == 1
|
||||
|| GlobalSign.sg == 2 || GlobalSign.sg == 3)) {
|
||||
logerror("sign_init(): invalid SG %d", GlobalSign.sg);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sign_get_keys())
|
||||
return false;
|
||||
|
||||
/* signature algorithm */
|
||||
/* can probably be merged with the hash algorithm/context but
|
||||
* I leave the optimization for later until the RFC is ready */
|
||||
GlobalSign.sigctx = EVP_MD_CTX_create();
|
||||
EVP_MD_CTX_init(GlobalSign.sigctx);
|
||||
|
||||
/* the signature algorithm depends on the type of key */
|
||||
if (EVP_PKEY_DSA == EVP_PKEY_type(GlobalSign.pubkey->type)) {
|
||||
GlobalSign.sig = EVP_dss1();
|
||||
GlobalSign.sig_len_b64 = SIGN_B64SIGLEN_DSS;
|
||||
/* this is the place to add non-DSA key types and algorithms
|
||||
} else if (EVP_PKEY_RSA == EVP_PKEY_type(GlobalSign.pubkey->type)) {
|
||||
GlobalSign.sig = EVP_sha1();
|
||||
GlobalSign.sig_len_b64 = 28;
|
||||
*/
|
||||
} else {
|
||||
logerror("key type not supported for syslog-sign");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(GlobalSign.keytype == 'C' || GlobalSign.keytype == 'K');
|
||||
assert(GlobalSign.pubkey_b64 && GlobalSign.privkey &&
|
||||
GlobalSign.pubkey);
|
||||
assert(GlobalSign.privkey->pkey.dsa->priv_key);
|
||||
|
||||
GlobalSign.gbc = 0;
|
||||
STAILQ_INIT(&GlobalSign.SigGroups);
|
||||
|
||||
/* hash algorithm */
|
||||
OpenSSL_add_all_digests();
|
||||
GlobalSign.mdctx = EVP_MD_CTX_create();
|
||||
EVP_MD_CTX_init(GlobalSign.mdctx);
|
||||
|
||||
/* values for SHA-1 */
|
||||
GlobalSign.md = EVP_dss1();
|
||||
GlobalSign.md_len_b64 = 28;
|
||||
GlobalSign.ver = "0111";
|
||||
|
||||
if (!sign_sg_init(Files))
|
||||
return false;
|
||||
sign_new_reboot_session();
|
||||
|
||||
DPRINTF(D_SIGN, "length values: SIGN_MAX_SD_LENGTH %d, "
|
||||
"SIGN_MAX_FRAG_LENGTH %d, SIGN_MAX_SB_LENGTH %d, "
|
||||
"SIGN_MAX_HASH_NUM %d\n", SIGN_MAX_SD_LENGTH,
|
||||
SIGN_MAX_FRAG_LENGTH, SIGN_MAX_SB_LENGTH, SIGN_MAX_HASH_NUM);
|
||||
|
||||
/* set just before return, so it indicates initialization */
|
||||
GlobalSign.rsid = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* get keys for syslog-sign
|
||||
* either from the X.509 certificate used for TLS
|
||||
* or by generating a new one
|
||||
*
|
||||
* sets the global variables
|
||||
* GlobalSign.keytype, GlobalSign.pubkey_b64,
|
||||
* GlobalSign.privkey, and GlobalSign.pubkey
|
||||
*/
|
||||
bool
|
||||
sign_get_keys()
|
||||
{
|
||||
EVP_PKEY *pubkey = NULL, *privkey = NULL;
|
||||
unsigned char *der_pubkey = NULL, *ptr_der_pubkey = NULL;
|
||||
char *pubkey_b64 = NULL;
|
||||
int der_len;
|
||||
|
||||
/* try PKIX/TLS key first */
|
||||
#ifndef DISABLE_TLS
|
||||
SSL *ssl;
|
||||
if (tls_opt.global_TLS_CTX
|
||||
&& (ssl = SSL_new(tls_opt.global_TLS_CTX))) {
|
||||
X509 *cert;
|
||||
DPRINTF(D_SIGN, "Try to get keys from TLS X.509 cert...\n");
|
||||
|
||||
if (!(cert = SSL_get_certificate(ssl))) {
|
||||
logerror("SSL_get_certificate() failed");
|
||||
FREE_SSL(ssl);
|
||||
return false;
|
||||
}
|
||||
if (!(privkey = SSL_get_privatekey(ssl))) {
|
||||
logerror("SSL_get_privatekey() failed");
|
||||
FREE_SSL(ssl);
|
||||
return false;
|
||||
}
|
||||
if (!(pubkey = X509_get_pubkey(cert))) {
|
||||
logerror("X509_get_pubkey() failed");
|
||||
FREE_SSL(ssl);
|
||||
return false;
|
||||
}
|
||||
/* note:
|
||||
* - privkey is just a pointer into SSL_CTX and
|
||||
* must not be changed nor be free()d
|
||||
* - but pubkey has to be freed with EVP_PKEY_free()
|
||||
*/
|
||||
FREE_SSL(ssl);
|
||||
|
||||
if (EVP_PKEY_DSA != EVP_PKEY_type(pubkey->type)) {
|
||||
DPRINTF(D_SIGN, "X.509 cert has no DSA key\n");
|
||||
EVP_PKEY_free(pubkey);
|
||||
privkey = NULL;
|
||||
pubkey = NULL;
|
||||
} else {
|
||||
DPRINTF(D_SIGN, "Got public and private key "
|
||||
"from X.509 --> use type PKIX\n");
|
||||
GlobalSign.keytype = 'C';
|
||||
GlobalSign.privkey = privkey;
|
||||
GlobalSign.pubkey = pubkey;
|
||||
|
||||
/* base64 certificate encoding */
|
||||
der_len = i2d_X509(cert, NULL);
|
||||
if (!(ptr_der_pubkey = der_pubkey = malloc(der_len))
|
||||
|| !(pubkey_b64 = malloc(der_len*2))) {
|
||||
free(der_pubkey);
|
||||
logerror("malloc() failed");
|
||||
return false;
|
||||
}
|
||||
if (i2d_X509(cert, &ptr_der_pubkey) <= 0) {
|
||||
logerror("i2d_X509() failed");
|
||||
return false;
|
||||
}
|
||||
b64_ntop(der_pubkey, der_len, pubkey_b64, der_len*2);
|
||||
free(der_pubkey);
|
||||
/* try to resize memory object as needed */
|
||||
GlobalSign.pubkey_b64 = realloc(pubkey_b64,
|
||||
strlen(pubkey_b64)+1);
|
||||
if (!GlobalSign.pubkey_b64)
|
||||
GlobalSign.pubkey_b64 = pubkey_b64;
|
||||
}
|
||||
}
|
||||
#endif /* !DISABLE_TLS */
|
||||
if (!(privkey && pubkey)) { /* PKIX not available --> generate key */
|
||||
DSA *dsa;
|
||||
|
||||
DPRINTF(D_SIGN, "Unable to get keys from X.509 "
|
||||
"--> use DSA with type 'K'\n");
|
||||
if (!(privkey = EVP_PKEY_new())) {
|
||||
logerror("EVP_PKEY_new() failed");
|
||||
return false;
|
||||
}
|
||||
dsa = DSA_generate_parameters(SIGN_GENCERT_BITS, NULL, 0,
|
||||
NULL, NULL, NULL, NULL);
|
||||
if (!DSA_generate_key(dsa)) {
|
||||
logerror("DSA_generate_key() failed");
|
||||
return false;
|
||||
}
|
||||
if (!EVP_PKEY_assign_DSA(privkey, dsa)) {
|
||||
logerror("EVP_PKEY_assign_DSA() failed");
|
||||
return false;
|
||||
}
|
||||
GlobalSign.keytype = 'K'; /* public/private keys used */
|
||||
GlobalSign.privkey = privkey;
|
||||
GlobalSign.pubkey = privkey;
|
||||
|
||||
/* pubkey base64 encoding */
|
||||
der_len = i2d_DSA_PUBKEY(dsa, NULL);
|
||||
if (!(ptr_der_pubkey = der_pubkey = malloc(der_len))
|
||||
|| !(pubkey_b64 = malloc(der_len*2))) {
|
||||
free(der_pubkey);
|
||||
logerror("malloc() failed");
|
||||
return false;
|
||||
}
|
||||
if (i2d_DSA_PUBKEY(dsa, &ptr_der_pubkey) <= 0) {
|
||||
logerror("i2d_DSA_PUBKEY() failed");
|
||||
return false;
|
||||
}
|
||||
b64_ntop(der_pubkey, der_len, pubkey_b64, der_len*2);
|
||||
free(der_pubkey);
|
||||
/* try to resize memory object as needed */
|
||||
GlobalSign.pubkey_b64 = realloc(pubkey_b64,
|
||||
strlen(pubkey_b64) + 1);
|
||||
if (!GlobalSign.pubkey_b64)
|
||||
GlobalSign.pubkey_b64 = pubkey_b64;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* init SGs
|
||||
*/
|
||||
bool
|
||||
sign_sg_init(struct filed *Files)
|
||||
{
|
||||
struct signature_group_t *sg, *newsg, *last_sg;
|
||||
struct filed_queue *fq;
|
||||
struct string_queue *sqentry, *last_sqentry;
|
||||
struct filed *f;
|
||||
int i;
|
||||
|
||||
/* note on SG 1 and 2:
|
||||
* it is assumed that redundant signature groups
|
||||
* and especially signature groups without an associated
|
||||
* destination are harmless.
|
||||
* this currently holds true because sign_append_hash()
|
||||
* is called from fprintlog(), so only actually used
|
||||
* signature group get hashes and need memory for them
|
||||
*/
|
||||
/* possible optimization for SGs 1 and 2:
|
||||
* use a struct signature_group_t *newsg[IETF_NUM_PRIVALUES]
|
||||
* for direct group lookup
|
||||
*/
|
||||
|
||||
#define ALLOC_OR_FALSE(x) do { \
|
||||
if(!((x) = calloc(1, sizeof(*(x))))) { \
|
||||
logerror("Unable to allocate memory"); \
|
||||
return false; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define ALLOC_SG(x) do { \
|
||||
ALLOC_OR_FALSE(x); \
|
||||
(x)->last_msg_num = 1; /* cf. section 4.2.5 */ \
|
||||
STAILQ_INIT(&(x)->hashes); \
|
||||
STAILQ_INIT(&(x)->files); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
/* alloc(fq) and add to SGs file queue */
|
||||
#define ASSIGN_FQ() do { \
|
||||
ALLOC_OR_FALSE(fq); \
|
||||
fq->f = f; \
|
||||
f->f_sg = newsg; \
|
||||
DPRINTF(D_SIGN, "SG@%p <--> f@%p\n", newsg, f); \
|
||||
STAILQ_INSERT_TAIL(&newsg->files, fq, entries); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
switch (GlobalSign.sg) {
|
||||
case 0:
|
||||
/* one SG, linked to all files */
|
||||
ALLOC_SG(newsg);
|
||||
newsg->spri = 0;
|
||||
for (f = Files; f; f = f->f_next)
|
||||
ASSIGN_FQ();
|
||||
STAILQ_INSERT_TAIL(&GlobalSign.SigGroups,
|
||||
newsg, entries);
|
||||
break;
|
||||
case 1:
|
||||
/* every PRI gets one SG */
|
||||
for (i = 0; i < IETF_NUM_PRIVALUES; i++) {
|
||||
int fac, prilev;
|
||||
fac = LOG_FAC(i);
|
||||
prilev = LOG_PRI(i);
|
||||
ALLOC_SG(newsg);
|
||||
newsg->spri = i;
|
||||
|
||||
/* now find all destinations associated with this SG */
|
||||
for (f = Files; f; f = f->f_next)
|
||||
/* check priorities */
|
||||
if (MATCH_PRI(f, fac, prilev))
|
||||
ASSIGN_FQ();
|
||||
STAILQ_INSERT_TAIL(&GlobalSign.SigGroups,
|
||||
newsg, entries);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* PRI ranges get one SG, boundaries given by the
|
||||
* SPRI, indicating the largest PRI in the SG
|
||||
*
|
||||
* either GlobalSign.sig2_delims has a list of
|
||||
* user configured delimiters, or we use a default
|
||||
* and set up one SG per facility
|
||||
*/
|
||||
if (STAILQ_EMPTY(&GlobalSign.sig2_delims)) {
|
||||
DPRINTF(D_SIGN, "sign_sg_init(): set default "
|
||||
"values for SG 2\n");
|
||||
for (i = 0; i < (IETF_NUM_PRIVALUES>>3); i++) {
|
||||
ALLOC_OR_FALSE(sqentry);
|
||||
sqentry->data = NULL;
|
||||
sqentry->key = (i<<3);
|
||||
STAILQ_INSERT_TAIL(&GlobalSign.sig2_delims,
|
||||
sqentry, entries);
|
||||
}
|
||||
}
|
||||
assert(!STAILQ_EMPTY(&GlobalSign.sig2_delims));
|
||||
|
||||
/* add one more group at the end */
|
||||
last_sqentry = STAILQ_LAST(&GlobalSign.sig2_delims,
|
||||
string_queue, entries);
|
||||
if (last_sqentry->key < IETF_NUM_PRIVALUES) {
|
||||
ALLOC_OR_FALSE(sqentry);
|
||||
sqentry->data = NULL;
|
||||
sqentry->key = IETF_NUM_PRIVALUES-1;
|
||||
STAILQ_INSERT_TAIL(&GlobalSign.sig2_delims,
|
||||
sqentry, entries);
|
||||
}
|
||||
|
||||
STAILQ_FOREACH(sqentry, &GlobalSign.sig2_delims, entries) {
|
||||
int min_pri = 0;
|
||||
ALLOC_SG(newsg);
|
||||
newsg->spri = sqentry->key;
|
||||
|
||||
/* check _all_ priorities in SG */
|
||||
last_sg = STAILQ_LAST(&GlobalSign.SigGroups,
|
||||
signature_group_t, entries);
|
||||
if (last_sg)
|
||||
min_pri = last_sg->spri + 1;
|
||||
|
||||
DPRINTF(D_SIGN, "sign_sg_init(): add SG@%p: SG=\"2\","
|
||||
" SPRI=\"%d\" -- for msgs with "
|
||||
"%d <= pri <= %d\n",
|
||||
newsg, newsg->spri, min_pri, newsg->spri);
|
||||
/* now find all destinations associated with this SG */
|
||||
for (f = Files; f; f = f->f_next) {
|
||||
bool match = false;
|
||||
for (i = min_pri; i <= newsg->spri; i++) {
|
||||
int fac, prilev;
|
||||
fac = LOG_FAC(i);
|
||||
prilev = LOG_PRI(i);
|
||||
if (MATCH_PRI(f, fac, prilev)) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match)
|
||||
ASSIGN_FQ();
|
||||
}
|
||||
STAILQ_INSERT_TAIL(&GlobalSign.SigGroups,
|
||||
newsg, entries);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
/* every file (with flag) gets one SG */
|
||||
for (f = Files; f; f = f->f_next) {
|
||||
if (!(f->f_flags & FFLAG_SIGN)) {
|
||||
f->f_sg = NULL;
|
||||
continue;
|
||||
}
|
||||
ALLOC_SG(newsg);
|
||||
newsg->spri = f->f_file; /* not needed but shows SGs */
|
||||
ASSIGN_FQ();
|
||||
STAILQ_INSERT_TAIL(&GlobalSign.SigGroups,
|
||||
newsg, entries);
|
||||
}
|
||||
break;
|
||||
}
|
||||
DPRINTF((D_PARSE|D_SIGN), "sign_sg_init() set up these "
|
||||
"Signature Groups:\n");
|
||||
STAILQ_FOREACH(sg, &GlobalSign.SigGroups, entries) {
|
||||
DPRINTF((D_PARSE|D_SIGN), "SG@%p with SG=\"%d\", SPRI=\"%d\","
|
||||
" associated files:\n", sg, GlobalSign.sg, sg->spri);
|
||||
STAILQ_FOREACH(fq, &sg->files, entries) {
|
||||
DPRINTF((D_PARSE|D_SIGN), " f@%p with type %d\n",
|
||||
fq->f, fq->f->f_type);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* free all SGs for a given algorithm
|
||||
*/
|
||||
void
|
||||
sign_global_free()
|
||||
{
|
||||
struct signature_group_t *sg, *tmp_sg;
|
||||
struct filed_queue *fq, *tmp_fq;
|
||||
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_global_free()\n");
|
||||
STAILQ_FOREACH_SAFE(sg, &GlobalSign.SigGroups, entries, tmp_sg) {
|
||||
if (!STAILQ_EMPTY(&sg->hashes)) {
|
||||
/* send CB and SB twice to get minimal redundancy
|
||||
* for the last few message hashes */
|
||||
sign_send_certificate_block(sg);
|
||||
sign_send_certificate_block(sg);
|
||||
sign_send_signature_block(sg, true);
|
||||
sign_send_signature_block(sg, true);
|
||||
sign_free_hashes(sg);
|
||||
}
|
||||
fq = STAILQ_FIRST(&sg->files);
|
||||
while (fq != NULL) {
|
||||
tmp_fq = STAILQ_NEXT(fq, entries);
|
||||
free(fq);
|
||||
fq = tmp_fq;
|
||||
}
|
||||
STAILQ_REMOVE(&GlobalSign.SigGroups,
|
||||
sg, signature_group_t, entries);
|
||||
free(sg);
|
||||
}
|
||||
sign_free_string_queue(&GlobalSign.sig2_delims);
|
||||
|
||||
if (GlobalSign.privkey) {
|
||||
GlobalSign.privkey = NULL;
|
||||
}
|
||||
if (GlobalSign.pubkey) {
|
||||
EVP_PKEY_free(GlobalSign.pubkey);
|
||||
GlobalSign.pubkey = NULL;
|
||||
}
|
||||
if(GlobalSign.mdctx) {
|
||||
EVP_MD_CTX_destroy(GlobalSign.mdctx);
|
||||
GlobalSign.mdctx = NULL;
|
||||
}
|
||||
if(GlobalSign.sigctx) {
|
||||
EVP_MD_CTX_destroy(GlobalSign.sigctx);
|
||||
GlobalSign.sigctx = NULL;
|
||||
}
|
||||
FREEPTR(GlobalSign.pubkey_b64);
|
||||
}
|
||||
|
||||
/*
|
||||
* create and send certificate block
|
||||
*/
|
||||
bool
|
||||
sign_send_certificate_block(struct signature_group_t *sg)
|
||||
{
|
||||
struct filed_queue *fq;
|
||||
struct buf_msg *buffer;
|
||||
char *tstamp;
|
||||
char payload[SIGN_MAX_PAYLOAD_LENGTH];
|
||||
char sd[SIGN_MAX_SD_LENGTH];
|
||||
size_t payload_len, sd_len, fragment_len;
|
||||
size_t payload_index = 0;
|
||||
|
||||
/* do nothing if CBs already sent or if there was no message in SG */
|
||||
if (!sg->resendcount
|
||||
|| ((sg->resendcount == SIGN_RESENDCOUNT_CERTBLOCK)
|
||||
&& STAILQ_EMPTY(&sg->hashes)))
|
||||
return false;
|
||||
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_send_certificate_block(%p)\n", sg);
|
||||
tstamp = make_timestamp(NULL, true);
|
||||
|
||||
payload_len = snprintf(payload, sizeof(payload), "%s %c %s", tstamp,
|
||||
GlobalSign.keytype, GlobalSign.pubkey_b64);
|
||||
if (payload_len >= sizeof(payload)) {
|
||||
DPRINTF(D_SIGN, "Buffer too small for syslog-sign setup\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
while (payload_index < payload_len) {
|
||||
if (payload_len - payload_index <= SIGN_MAX_FRAG_LENGTH)
|
||||
fragment_len = payload_len - payload_index;
|
||||
else
|
||||
fragment_len = SIGN_MAX_FRAG_LENGTH;
|
||||
|
||||
/* format SD */
|
||||
sd_len = snprintf(sd, sizeof(sd), "[ssign-cert "
|
||||
"VER=\"%s\" RSID=\"%" PRIuFAST64 "\" SG=\"%d\" "
|
||||
"SPRI=\"%d\" TBPL=\"%zu\" INDEX=\"%zu\" "
|
||||
"FLEN=\"%zu\" FRAG=\"%.*s\" "
|
||||
"SIGN=\"\"]",
|
||||
GlobalSign.ver, GlobalSign.rsid, GlobalSign.sg,
|
||||
sg->spri, payload_len, payload_index+1,
|
||||
fragment_len, (int)fragment_len,
|
||||
&payload[payload_index]);
|
||||
assert(sd_len < sizeof(sd));
|
||||
assert(sd[sd_len] == '\0');
|
||||
assert(sd[sd_len-1] == ']');
|
||||
assert(sd[sd_len-2] == '"');
|
||||
|
||||
if (!sign_msg_sign(&buffer, sd, sizeof(sd)))
|
||||
return 0;
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_send_certificate_block(): "
|
||||
"calling fprintlog()\n");
|
||||
|
||||
STAILQ_FOREACH(fq, &sg->files, entries) {
|
||||
/* we have to preserve the f_prevcount */
|
||||
int tmpcnt;
|
||||
tmpcnt = fq->f->f_prevcount;
|
||||
fprintlog(fq->f, buffer, NULL);
|
||||
fq->f->f_prevcount = tmpcnt;
|
||||
}
|
||||
sign_inc_gbc();
|
||||
DELREF(buffer);
|
||||
payload_index += fragment_len;
|
||||
}
|
||||
sg->resendcount--;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* determine the SG for a message
|
||||
* returns NULL if -sign not configured or no SG for this priority
|
||||
*/
|
||||
struct signature_group_t *
|
||||
sign_get_sg(int pri, struct filed *f)
|
||||
{
|
||||
struct signature_group_t *sg, *rc = NULL;
|
||||
|
||||
if (GlobalSign.rsid && f)
|
||||
switch (GlobalSign.sg) {
|
||||
case 0:
|
||||
rc = f->f_sg;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
STAILQ_FOREACH(sg, &GlobalSign.SigGroups, entries) {
|
||||
if (sg->spri >= pri) {
|
||||
rc = sg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (f->f_flags & FFLAG_SIGN)
|
||||
rc = f->f_sg;
|
||||
else
|
||||
rc = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_get_sg(%d, %p) --> %p\n", pri, f, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* create and send signature block
|
||||
*
|
||||
* uses a sliding window for redundancy
|
||||
* if force==true then simply send all available hashes, e.g. on shutdown
|
||||
*
|
||||
* sliding window checks implicitly assume that new hashes are appended
|
||||
* to the SG between two calls. if that is not the case (e.g. with repeated
|
||||
* messages) the queue size will shrink.
|
||||
* this has no negative consequences except generating more and shorter SBs
|
||||
* than expected and confusing the operator because two consecutive SBs will
|
||||
* have same FMNn
|
||||
*/
|
||||
unsigned
|
||||
sign_send_signature_block(struct signature_group_t *sg, bool force)
|
||||
{
|
||||
char sd[SIGN_MAX_SD_LENGTH];
|
||||
size_t sd_len;
|
||||
size_t sg_num_hashes = 0; /* hashes in SG queue */
|
||||
size_t hashes_in_sb = 0; /* number of hashes in current SB */
|
||||
size_t hashes_sent = 0; /* count of hashes sent */
|
||||
struct string_queue *qentry, *old_qentry;
|
||||
struct buf_msg *buffer;
|
||||
struct filed_queue *fq;
|
||||
int i;
|
||||
|
||||
if (!sg) return 0;
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_send_signature_block(%p, %d)\n",
|
||||
sg, force);
|
||||
|
||||
STAILQ_FOREACH(qentry, &sg->hashes, entries)
|
||||
sg_num_hashes++;
|
||||
|
||||
/* only act if a division is full */
|
||||
if (!sg_num_hashes
|
||||
|| (!force && (sg_num_hashes % SIGN_HASH_DIVISION_NUM)))
|
||||
return 0;
|
||||
|
||||
/* if no CB sent so far then do now, just before first SB */
|
||||
if (sg->resendcount == SIGN_RESENDCOUNT_CERTBLOCK)
|
||||
sign_send_certificate_block(sg);
|
||||
|
||||
/* shortly after reboot we have shorter SBs */
|
||||
hashes_in_sb = MIN(sg_num_hashes, SIGN_HASH_NUM);
|
||||
|
||||
DPRINTF(D_SIGN, "sign_send_signature_block(): "
|
||||
"sg_num_hashes = %zu, hashes_in_sb = %zu, SIGN_HASH_NUM = %d\n",
|
||||
sg_num_hashes, hashes_in_sb, SIGN_HASH_NUM);
|
||||
if (sg_num_hashes > SIGN_HASH_NUM) {
|
||||
DPRINTF(D_SIGN, "sign_send_signature_block(): sg_num_hashes"
|
||||
" > SIGN_HASH_NUM -- This should not happen!\n");
|
||||
}
|
||||
|
||||
/* now the SD */
|
||||
qentry = STAILQ_FIRST(&sg->hashes);
|
||||
sd_len = snprintf(sd, sizeof(sd), "[ssign "
|
||||
"VER=\"%s\" RSID=\"%" PRIuFAST64 "\" SG=\"%d\" "
|
||||
"SPRI=\"%d\" GBC=\"%" PRIuFAST64 "\" FMN=\"%" PRIuFAST64 "\" "
|
||||
"CNT=\"%zu\" HB=\"",
|
||||
GlobalSign.ver, GlobalSign.rsid, GlobalSign.sg,
|
||||
sg->spri, GlobalSign.gbc, qentry->key,
|
||||
hashes_in_sb);
|
||||
while (hashes_sent < hashes_in_sb) {
|
||||
assert(qentry);
|
||||
sd_len += snprintf(sd+sd_len, sizeof(sd)-sd_len, "%s ",
|
||||
qentry->data);
|
||||
hashes_sent++;
|
||||
qentry = STAILQ_NEXT(qentry, entries);
|
||||
}
|
||||
/* overwrite last space and close SD */
|
||||
assert(sd_len < sizeof(sd));
|
||||
assert(sd[sd_len] == '\0');
|
||||
assert(sd[sd_len-1] == ' ');
|
||||
sd[sd_len-1] = '\0';
|
||||
sd_len = strlcat(sd, "\" SIGN=\"\"]", sizeof(sd));
|
||||
|
||||
if (sign_msg_sign(&buffer, sd, sizeof(sd))) {
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_send_signature_block(): calling"
|
||||
" fprintlog(), sending %zu out of %zu hashes\n",
|
||||
MIN(SIGN_MAX_HASH_NUM, sg_num_hashes), sg_num_hashes);
|
||||
|
||||
STAILQ_FOREACH(fq, &sg->files, entries) {
|
||||
int tmpcnt;
|
||||
tmpcnt = fq->f->f_prevcount;
|
||||
fprintlog(fq->f, buffer, NULL);
|
||||
fq->f->f_prevcount = tmpcnt;
|
||||
}
|
||||
sign_inc_gbc();
|
||||
DELREF(buffer);
|
||||
}
|
||||
/* always drop the oldest division of hashes */
|
||||
if (sg_num_hashes >= SIGN_HASH_NUM) {
|
||||
qentry = STAILQ_FIRST(&sg->hashes);
|
||||
for (i = 0; i < SIGN_HASH_DIVISION_NUM; i++) {
|
||||
old_qentry = qentry;
|
||||
qentry = STAILQ_NEXT(old_qentry, entries);
|
||||
STAILQ_REMOVE(&sg->hashes, old_qentry,
|
||||
string_queue, entries);
|
||||
FREEPTR(old_qentry->data);
|
||||
FREEPTR(old_qentry);
|
||||
}
|
||||
}
|
||||
return hashes_sent;
|
||||
}
|
||||
|
||||
void
|
||||
sign_free_hashes(struct signature_group_t *sg)
|
||||
{
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_free_hashes(%p)\n", sg);
|
||||
sign_free_string_queue(&sg->hashes);
|
||||
}
|
||||
|
||||
void
|
||||
sign_free_string_queue(struct string_queue_head *sqhead)
|
||||
{
|
||||
struct string_queue *qentry, *tmp_qentry;
|
||||
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_free_string_queue(%p)\n", sqhead);
|
||||
STAILQ_FOREACH_SAFE(qentry, sqhead, entries, tmp_qentry) {
|
||||
STAILQ_REMOVE(sqhead, qentry, string_queue, entries);
|
||||
FREEPTR(qentry->data);
|
||||
free(qentry);
|
||||
}
|
||||
assert(STAILQ_EMPTY(sqhead));
|
||||
}
|
||||
|
||||
/*
|
||||
* hash one syslog message
|
||||
*/
|
||||
bool
|
||||
sign_msg_hash(char *line, char **hash)
|
||||
{
|
||||
unsigned char md_value[EVP_MAX_MD_SIZE];
|
||||
unsigned char md_b64[EVP_MAX_MD_SIZE*2];
|
||||
/* TODO: exact expression for b64 length? */
|
||||
unsigned md_len = 0;
|
||||
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_msg_hash('%s')\n", line);
|
||||
|
||||
SSL_CHECK_ONE(EVP_DigestInit_ex(GlobalSign.mdctx, GlobalSign.md, NULL));
|
||||
SSL_CHECK_ONE(EVP_DigestUpdate(GlobalSign.mdctx, line, strlen(line)));
|
||||
SSL_CHECK_ONE(EVP_DigestFinal_ex(GlobalSign.mdctx, md_value, &md_len));
|
||||
|
||||
b64_ntop(md_value, md_len, (char *)md_b64, EVP_MAX_MD_SIZE*2);
|
||||
*hash = strdup((char *)md_b64);
|
||||
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_msg_hash() --> \"%s\"\n", *hash);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* append hash to SG queue
|
||||
*/
|
||||
bool
|
||||
sign_append_hash(char *hash, struct signature_group_t *sg)
|
||||
{
|
||||
struct string_queue *qentry;
|
||||
|
||||
/* if one SG is shared by several destinations
|
||||
* prevent duplicate entries */
|
||||
if ((qentry = STAILQ_LAST(&sg->hashes, string_queue, entries))
|
||||
&& !strcmp(qentry->data, hash)) {
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_append_hash('%s', %p): "
|
||||
"hash already in queue\n", hash, sg);
|
||||
return false;
|
||||
}
|
||||
|
||||
MALLOC(qentry, sizeof(*qentry));
|
||||
qentry->key = sign_assign_msg_num(sg);
|
||||
qentry->data = hash;
|
||||
STAILQ_INSERT_TAIL(&sg->hashes, qentry, entries);
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_append_hash('%s', %p): "
|
||||
"#%" PRIdFAST64 "\n", hash, sg, qentry->key);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* sign one syslog-sign message
|
||||
*
|
||||
* requires a ssign or ssigt-cert SD element
|
||||
* ending with ' SIGN=""]' in sd
|
||||
* linesize is available memory (= sizeof(sd))
|
||||
*
|
||||
* function will calculate signature and return a new buffer
|
||||
*/
|
||||
bool
|
||||
sign_msg_sign(struct buf_msg **bufferptr, char *sd, size_t linesize)
|
||||
{
|
||||
char *signature, *line;
|
||||
size_t linelen, tlsprefixlen, endptr, newlinelen;
|
||||
struct buf_msg *buffer;
|
||||
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_msg_sign()\n");
|
||||
endptr = strlen(sd);
|
||||
|
||||
assert(endptr < linesize);
|
||||
assert(sd[endptr] == '\0');
|
||||
assert(sd[endptr-1] == ']');
|
||||
assert(sd[endptr-2] == '"');
|
||||
|
||||
/* set up buffer */
|
||||
buffer = buf_msg_new(0);
|
||||
buffer->timestamp = strdup(make_timestamp(NULL, !BSDOutputFormat));
|
||||
buffer->prog = appname;
|
||||
buffer->pid = include_pid;
|
||||
buffer->recvhost = buffer->host = LocalFQDN;
|
||||
buffer->pri = 110;
|
||||
buffer->flags = IGN_CONS|SIGN_MSG;
|
||||
buffer->sd = sd;
|
||||
|
||||
/* SD ready, now format and sign */
|
||||
if (!format_buffer(buffer, &line, &linelen, NULL,
|
||||
&tlsprefixlen, NULL)) {
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_send_signature_block():"
|
||||
" format_buffer() failed\n");
|
||||
buffer->sd = NULL;
|
||||
DELREF(buffer);
|
||||
return false;
|
||||
}
|
||||
if (!sign_string_sign(line+tlsprefixlen, &signature)) {
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_send_signature_block():"
|
||||
" sign_string_sign() failed\n");
|
||||
buffer->sd = NULL;
|
||||
DELREF(buffer);
|
||||
FREEPTR(line);
|
||||
return false;
|
||||
}
|
||||
FREEPTR(line);
|
||||
sd[endptr-2] = '\0';
|
||||
newlinelen = strlcat(sd, signature, linesize);
|
||||
newlinelen = strlcat(sd, "\"]", linesize);
|
||||
|
||||
if (newlinelen >= linesize) {
|
||||
DPRINTF(D_SIGN, "sign_send_signature_block(): "
|
||||
"buffer too small\n");
|
||||
buffer->sd = NULL;
|
||||
DELREF(buffer);
|
||||
return false;
|
||||
}
|
||||
assert(newlinelen < linesize);
|
||||
assert(sd[newlinelen] == '\0');
|
||||
assert(sd[newlinelen-1] == ']');
|
||||
assert(sd[newlinelen-2] == '"');
|
||||
|
||||
buffer->sd = strdup(sd);
|
||||
*bufferptr = buffer;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* sign one string
|
||||
*/
|
||||
bool
|
||||
sign_string_sign(char *line, char **signature)
|
||||
{
|
||||
char buf[SIGN_MAX_LENGTH+1];
|
||||
unsigned char sig_value[SIGN_B64SIGLEN_DSS];
|
||||
unsigned char sig_b64[SIGN_B64SIGLEN_DSS];
|
||||
unsigned sig_len = 0;
|
||||
char *p, *q;
|
||||
/*
|
||||
* The signature is calculated over the completely formatted
|
||||
* syslog-message, including all of the PRI, HEADER, and hashes
|
||||
* in the hash block, excluding spaces between fields, and also
|
||||
* excluding the signature field (SD Parameter Name "SIGN", "=",
|
||||
* and corresponding value).
|
||||
*
|
||||
* -- I am not quite sure which spaces are to be removed.
|
||||
* Only the ones inside the "ssign" element or those between
|
||||
* header fields as well?
|
||||
*/
|
||||
/* removes the string ' SIGN=""' */
|
||||
for (p = line, q = buf;
|
||||
*p && (q - buf <= SIGN_MAX_LENGTH);) {
|
||||
if (strncmp(p, " SIGN=\"\"", 8) == 0)
|
||||
p += 8;
|
||||
*q++ = *p++;
|
||||
}
|
||||
*q = '\0';
|
||||
|
||||
SSL_CHECK_ONE(EVP_SignInit(GlobalSign.sigctx, GlobalSign.sig));
|
||||
SSL_CHECK_ONE(EVP_SignUpdate(GlobalSign.sigctx, buf, q-buf));
|
||||
assert(GlobalSign.privkey);
|
||||
SSL_CHECK_ONE(EVP_SignFinal(GlobalSign.sigctx, sig_value, &sig_len,
|
||||
GlobalSign.privkey));
|
||||
|
||||
b64_ntop(sig_value, sig_len, (char *)sig_b64, sizeof(sig_b64));
|
||||
*signature = strdup((char *)sig_b64);
|
||||
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_string_sign('%s') --> '%s'\n",
|
||||
buf, *signature);
|
||||
return *signature != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
sign_new_reboot_session()
|
||||
{
|
||||
struct signature_group_t *sg;
|
||||
|
||||
DPRINTF((D_CALL|D_SIGN), "sign_new_reboot_session()\n");
|
||||
|
||||
/* global counters */
|
||||
GlobalSign.gbc = 0;
|
||||
/* might be useful for later analysis:
|
||||
* rebooted session IDs are sequential,
|
||||
* normal IDs are almost always not */
|
||||
GlobalSign.rsid++;
|
||||
|
||||
assert(GlobalSign.sg <= 3);
|
||||
/* reset SGs */
|
||||
STAILQ_FOREACH(sg, &GlobalSign.SigGroups, entries) {
|
||||
sg->resendcount = SIGN_RESENDCOUNT_CERTBLOCK;
|
||||
sg->last_msg_num = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* get msg_num, increment counter, check overflow */
|
||||
uint_fast64_t
|
||||
sign_assign_msg_num(struct signature_group_t *sg)
|
||||
{
|
||||
uint_fast64_t old;
|
||||
|
||||
old = sg->last_msg_num++;
|
||||
if (sg->last_msg_num > SIGN_MAX_COUNT)
|
||||
sign_new_reboot_session();
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
/* increment gbc, check overflow */
|
||||
void
|
||||
sign_inc_gbc()
|
||||
{
|
||||
if (++GlobalSign.gbc > SIGN_MAX_COUNT)
|
||||
sign_new_reboot_session();
|
||||
}
|
||||
#endif /* !DISABLE_SIGN */
|
207
usr.sbin/syslogd/sign.h
Normal file
207
usr.sbin/syslogd/sign.h
Normal file
@ -0,0 +1,207 @@
|
||||
/* $NetBSD: sign.h,v 1.1 2008/10/31 16:12:19 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Martin Schütte.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* sign.h
|
||||
*
|
||||
*/
|
||||
#ifndef SIGN_H_
|
||||
#define SIGN_H_
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <resolv.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
/* default Signature Group value,
|
||||
* defines signature strategy:
|
||||
* 0 one global SG
|
||||
* 1 one SG per PRI
|
||||
* 2 SGs for PRI ranges
|
||||
* 3 other (SGs not defined by PRI)
|
||||
*
|
||||
* We use '3' and assign one SG to every destination (=struct filed)
|
||||
*/
|
||||
#define SIGN_SG 3
|
||||
|
||||
/* maximum value for several counters in -sign */
|
||||
#define SIGN_MAX_COUNT 9999999999
|
||||
|
||||
/*
|
||||
* many of these options could be made user configurable if desired,
|
||||
* but I do not see the need for that
|
||||
*/
|
||||
|
||||
/* redundancy options */
|
||||
/*
|
||||
* note on the implementation of redundancy:
|
||||
* - certificate blocks: sending the first CB just before first SB.
|
||||
* after that domark() triggers resends until resend count is reached.
|
||||
* - signature blocks: to send every hash n times I use a sliding window.
|
||||
* the hashes in every SB are grouped into n divisions:
|
||||
* * the 1st hashcount/n hashes are sent for the 1st time
|
||||
* * the 2nd hashcount/n hashes are sent for the 2nd time
|
||||
* * ...
|
||||
* * the n-th hashcount/n hashes are sent for the n-th time
|
||||
* (and deleted thereafter)
|
||||
*/
|
||||
#define SIGN_RESENDCOUNT_CERTBLOCK 2
|
||||
#define SIGN_RESENDCOUNT_HASHES 3
|
||||
|
||||
/* maximum length of syslog-sign messages should be <= 2048 by standard
|
||||
* and should be >= 1024 to be long enough.
|
||||
* be careful with small values because there is no check for a lower bound
|
||||
* thus the following derived values would become negative.
|
||||
*/
|
||||
#define SIGN_MAX_LENGTH 2048
|
||||
/* the length we can use for the SD and keep the
|
||||
* message length with header below 2048 octets */
|
||||
#define SIGN_MAX_SD_LENGTH (SIGN_MAX_LENGTH - 1 - HEADER_LEN_MAX)
|
||||
/* length of signature, currently only for DSA */
|
||||
#define SIGN_B64SIGLEN_DSS 64+1
|
||||
/* the maximum length of one payload fragment:
|
||||
* max.SD len - text - max. field lengths - sig len */
|
||||
#define SIGN_MAX_FRAG_LENGTH (SIGN_MAX_SD_LENGTH - 82 - 38 - SIGN_B64SIGLEN_DSS)
|
||||
/* the maximum length of one signature block:
|
||||
* max.SD len - text - max. field lens - sig len */
|
||||
#define SIGN_MAX_SB_LENGTH (SIGN_MAX_SD_LENGTH - 72 - 40 - SIGN_B64SIGLEN_DSS)
|
||||
/* the maximum number of hashes pec signature block */
|
||||
#define SIGN_MAX_HASH_NUM (SIGN_MAX_SB_LENGTH / (GlobalSign.md_len_b64+1))
|
||||
/* number of hashes in one signature block */
|
||||
#define SIGN_HASH_NUM_WANT 100
|
||||
/* make sure to consider SIGN_MAX_HASH_NUM and
|
||||
* to have a SIGN_HASH_NUM that is a multiple of SIGN_HASH_DIVISION_NUM */
|
||||
#define SIGN_HASH_DIVISION_NUM (MIN(SIGN_HASH_NUM_WANT, SIGN_MAX_HASH_NUM) \
|
||||
/ SIGN_RESENDCOUNT_HASHES)
|
||||
#define SIGN_HASH_NUM (SIGN_HASH_DIVISION_NUM * SIGN_RESENDCOUNT_HASHES)
|
||||
|
||||
/* the length of payload strings
|
||||
* since the payload is fragmented there is no technical limit
|
||||
* it just has to be big enough to hold big b64 encoded PKIX certificates
|
||||
*/
|
||||
#define SIGN_MAX_PAYLOAD_LENGTH 20480
|
||||
|
||||
/* length of generated DSA keys for signing */
|
||||
#define SIGN_GENCERT_BITS 1024
|
||||
|
||||
#define SSL_CHECK_ONE(exp) do { \
|
||||
if ((exp) != 1) { \
|
||||
DPRINTF(D_SIGN, #exp " failed in %d: %s\n", __LINE__, \
|
||||
ERR_error_string(ERR_get_error(), NULL)); \
|
||||
return 1; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
/* structs use uint_fast64_t in different places because the standard
|
||||
* requires values in interval [0:9999999999 = SIGN_MAX_COUNT] */
|
||||
|
||||
/* queue of C-Strings (here used for hashes) */
|
||||
struct string_queue {
|
||||
uint_fast64_t key;
|
||||
char *data;
|
||||
STAILQ_ENTRY(string_queue) entries;
|
||||
};
|
||||
STAILQ_HEAD(string_queue_head, string_queue);
|
||||
|
||||
/* queue of destinations (used associate SGs and fileds) */
|
||||
struct filed_queue {
|
||||
struct filed *f;
|
||||
STAILQ_ENTRY(filed_queue) entries;
|
||||
};
|
||||
STAILQ_HEAD(filed_queue_head, filed_queue);
|
||||
|
||||
/* queue of Signature Groups */
|
||||
struct signature_group_t {
|
||||
unsigned spri;
|
||||
unsigned resendcount;
|
||||
uint_fast64_t last_msg_num;
|
||||
struct string_queue_head hashes;
|
||||
struct filed_queue_head files;
|
||||
STAILQ_ENTRY(signature_group_t) entries;
|
||||
};
|
||||
STAILQ_HEAD(signature_group_head, signature_group_t);
|
||||
|
||||
/* all global variables for sign */
|
||||
/* note that there is one object of this type which might only be
|
||||
* partially filled.
|
||||
* The fields .sg and .sig2_delims are set by init() and are always
|
||||
* valid. A value >0 in field .rsid indicates whether the rest of the
|
||||
* structure was already set by sign_global_init().
|
||||
*/
|
||||
struct sign_global_t {
|
||||
/* params for signature block, named as in RFC nnnn */
|
||||
const char *ver;
|
||||
uint_fast64_t rsid;
|
||||
int sg;
|
||||
uint_fast64_t gbc;
|
||||
struct signature_group_head SigGroups;
|
||||
struct string_queue_head sig2_delims;
|
||||
|
||||
EVP_PKEY *privkey;
|
||||
EVP_PKEY *pubkey;
|
||||
char *pubkey_b64;
|
||||
char keytype;
|
||||
|
||||
EVP_MD_CTX *mdctx; /* hashing context */
|
||||
const EVP_MD *md; /* hashing method/algorithm */
|
||||
unsigned md_len_b64; /* length of b64 hash value */
|
||||
|
||||
EVP_MD_CTX *sigctx; /* signature context */
|
||||
const EVP_MD *sig; /* signature method/algorithm */
|
||||
unsigned sig_len_b64; /* length of b64 signature */
|
||||
};
|
||||
|
||||
bool sign_global_init(struct filed*);
|
||||
bool sign_sg_init(struct filed*);
|
||||
bool sign_get_keys(void);
|
||||
void sign_global_free(void);
|
||||
struct signature_group_t* sign_get_sg(int, struct filed*);
|
||||
bool sign_send_certificate_block(struct signature_group_t*);
|
||||
unsigned sign_send_signature_block(struct signature_group_t*, bool);
|
||||
void sign_free_hashes(struct signature_group_t*);
|
||||
void sign_free_string_queue(struct string_queue_head*);
|
||||
bool sign_msg_hash(char*, char**);
|
||||
bool sign_append_hash(char*, struct signature_group_t*);
|
||||
bool sign_msg_sign(struct buf_msg**, char*, size_t);
|
||||
bool sign_string_sign(char*, char**);
|
||||
void sign_new_reboot_session(void);
|
||||
void sign_inc_gbc(void);
|
||||
uint_fast64_t sign_assign_msg_num(struct signature_group_t*);
|
||||
|
||||
#endif /* SIGN_H_ */
|
146
usr.sbin/syslogd/sign.html
Normal file
146
usr.sbin/syslogd/sign.html
Normal file
@ -0,0 +1,146 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>NetBSD & Google's Summer of Code: Martin Schuette - Improve syslogd (syslogd)</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>syslog-sign</h1>
|
||||
<p><a href="http://tools.ietf.org/html/draft-ietf-syslog-sign">syslog-sign</a> defines digital signatures for logfiles. This provides end-to-end authentication for network transports, enables the detection of lost UDP messages, and also makes it possible to check a log archive for later modifications (assuming the private key was kept safe).</p>
|
||||
|
||||
<h2>Signature Groups</h2>
|
||||
<p>A basic concept of syslog-sign is the signature group which describes a set of messages that are grouped and signed together. Their purpose becomes clear with an example: assume you split your messages to two logservers <em>serverA</em> and <em>serverB</em>. Now if all messages were singed as one stream, then a) where do the signatures go to? and b) how could <em>serverA</em>, having only hashes and signatures, decide which message are missing and which are on <em>serverB</em>?<br>
|
||||
Thus the messages are selected into two signature groups containing all signatures for messages to <em>serverA</em> and <em>serverB</em> respectively. Then every server has its own messages and its own signatures to verify them.</p>
|
||||
<p>There are three predefined and one custom signature groups:</p>
|
||||
<ol start="0">
|
||||
<li>one global signature group, useful if all messages go to one central logserver anyway</li>
|
||||
<li>every syslog priority (=combination of facility and severity) gets its own group, i.e. 192 of them, useful if there are lots of different destinations which all receive messages with different priorities</li>
|
||||
<li>take the priorities and split them into intervals, useful to define bigger subsets, e.g. one signature group for the mail facility and two for everything else</li>
|
||||
<li>not defined and reserved for custom strategy. I use this to have one signature group for every configured destination. In this case the selector in syslog.conf will determine which messages go into one group; it is also the only strategy that allows a message to be in multiple groups.</li>
|
||||
</ol>
|
||||
<p>Every signature group has several attributes and only the combination of several values determines one signature group unambiguously. Currently the key to identify a signature group is the tuple (hostname, reboot session ID, SG value, SPRI value). <!-- In a later draft the program name or process ID might be added to allow multiple syslog-sign senders per host.--></p>
|
||||
|
||||
<h2>Configuration/Activation</h2>
|
||||
<p>syslog-sign is enabled with the option "sign_sg" in syslog.conf. The value selects the signature group strategy, so for example the line "sign_sg=0" enables syslog-sign with one signature group.</p>
|
||||
<p>The SG="2" strategy is the only one that might require additional configuration. When selected (with "sign_sg=2") the default is to use one signature group per facility (kernel, user, mail, ...). To allow custom configuration there is an additional option "sign_sg2_delim" to specify the numerical SPRI values, i.e. the boundaries betwen the signature groups.<br>
|
||||
Example: With "sign_sg2_delim = 15 31" syslogd will set up three signature groups: one for all priorities x ≤ 15 (kernel.*,user.*), one for priorities 15 < x ≤ 31 (mail.*), and one for all priorities x > 31.</p>
|
||||
|
||||
<h2>Key, Signature, and Hash Types</h2>
|
||||
<p>The current internet draft defines two values for the VERsion field for using either SHA-1 or SHA-256 hashes. Both versions mandate DSA keys and signatures.<br>
|
||||
There are several alternatives for sending the public key in the initial Certificate Block. If a X.509 certificate is available (for TLS connections) then syslogd will use key type 'C' (PKIX) and send the certificate in DER encoding. Otherwise it generates a new DSA key and uses key type 'K' (public key) to send the public key in DER encoding.</p>
|
||||
|
||||
<h2>Redundancy</h2>
|
||||
<p>As mentioned above one design target of syslog-sign is the detection of lost messages, e.g. due to UDP datagram loss. So one has to take extra precaution to prevent lost signature messages and send them multiple times.<br>
|
||||
This implementation sends the first Certificate block only on demand, just before the first Signature Block. After that it is resent <em>n</em> times with several seconds delay. The Signature Blocks are not repeated but use a sliding window so that every message hash is included in <em>m</em> sequential Signature Blocks.</p>
|
||||
|
||||
<h2>Verification</h2>
|
||||
<p>Sending signatures is only half of the job, -- they have to be verified as well. I used Perl to write an <a href="verify-sign/verify.pl">offline verification</a> tool that reads a complete logfile and prints all messages in their correct order. See the example below for a sample usage and output.</p>
|
||||
|
||||
<h2>Example</h2>
|
||||
<p>Here is an example of a signed message sequence. I let syslogd generate me a DSA key for a self-signed X.509 certificate and use that for signing. I also changed one message so you can see the resulting verification output below.</p>
|
||||
|
||||
<pre>
|
||||
$ cat test.log
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg0
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg1
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg2
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg3
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg4
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg5
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg6
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg7
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg8
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg9
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg10
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg11
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - modified msg12
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg13
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg14
|
||||
<110>1 2008-08-02T01:09:27.773505+02:00 host.example.org syslogd - - [ssign-cert VER="0111" RSID="1217632162" SG="3" SPRI="0" TBPL="1059" INDEX="1" FLEN="1059" FRAG="2008-08-02T01:09:27.773464+02:00 C MIIC+jCCArmgAwIBAwIBATAJBgcqhkjOOAQDMCIxIDAeBgNVBAMTF2NvcmRlbGlhLm1zY2h1ZXR0ZS5uYW1lMB4XDTA4MDczMDIyMDYyMloXDTA5MDczMDIyMDYyMlowIjEgMB4GA1UEAxMXY29yZGVsaWEubXNjaHVldHRlLm5hbWUwggG3MIIBKwYHKoZIzjgEATCCAR4CgYEA92S335Kxy2TTMfdg9Vi/CJvyDCHMHpPYxWwEkEI26xEdKybzLghTfbG/RZw/nnFuhRTH4Xe6GVvlFi2zIzySSClXr+zyXg/D9uHyiVL5TEsu8uQT2IREmGOB8pu70FukL9nQGOr82YxuRFQzZ1p6KltIggivi5ffR4B33+1xoSkCFQDYe5GJKM9Cw6nkLngHkzFGRmcXIQKBgDbHeOLBKYLkRZyRpXd0aTNU2igcKTWyWlUTySJuv/iTAeB09p9WyTIPyAhtqN77CIwX8Ui2jGu6NYT6TWEYJVvL+C/TvddAvAMyefv+w+HPNF2L77IVrjNVRCneERoNKlWc6IzjKH3otl/Lh2D7NAWRid55vxF6Z0oO459+4vpRA4GFAAKBgQCzcJVR343IRntcQs8aENs/QMxoxHN6JVdpSLB9moY5/RC9ooxz32fkakSL0s8zLITLt/y+yzf0F/9JhmTC1XeD8gvPBesE6dc0ZzPCos0hg8WpKUWR0YqXFDOC//uBwIa94DncC8xZ0mCwavno6gtkz57S7ywSwnmrdjhmpdAZuqOBgDB+MBEGCWCGSAGG+EIBAQQEAwIGQDAzBglghkgBhvhCAQ0EJhYkYXV0by1nZW5lcmF0ZWQgYnkgdGhlIE5ldEJTRCBzeXNsb2dkMCYGCWCGSAGG+EIBDAQZFhdjb3JkZWxpYS5tc2NodWV0dGUubmFtZTAMBgNVHRMBAf8EAjAAMAkGByqGSM44BAMDMAAwLQIUZcsHdrbuyx9lR3tyyeiJvClj0B8CFQC+5+NlulgCd/yoSlLPZgsTHYmCYA==" SIGN="MC0CFFEHx8UX391lbmhbisJNS0zLGD/WAhUAuMfCO0BWtARt2vEWHbM2mAe2k+o="]
|
||||
<110>1 2008-08-02T01:09:27.778347+02:00 host.example.org syslogd - - [ssign VER="0111" RSID="1217632162" SG="3" SPRI="0" GBC="1" FMN="1" CNT="15" HB="siUJM358eYFHOS2K0MTlveWeH/U= zTxfthW8WqmtFhOG4k/+ZxkirTA= j9dubU1GNVp7qWShwph/w32nD08= XQDLZ/NuwirmLdMORtm84r9kIW4= RNDFNCo7hiCsK/EKumsPBbFHNZA= ANiE3KbY948J6cEB640fAtWXuO4= e2M/OqjHDfxLVUSPt1CsNJHm9wU= Y+racQst7F1gR8eEUh8O7o+M53s= JAMULRxjMPbOO5EhhKbsUkAwbl0= pd+N5kmlnyQ0BoItELd/KWQrcMg= dsMQSzPHIS6S3Vaa23/t7U8JAJ4= i4rE3x7N4qyQGTkmaWHsWDFP9SY= qgTqV4EgfUFd3uZXNPvJ25erzBI= XW0YrME5kQEh+fxhg1fetnWxfIc= 7YPcRHsDwXWnQuGRWaJtFWw9hus=" SIGN="MCwCFF5hS5GTLxLDwsDCUmOnHhzkmWzbAhRJ0io+LBKM6Ux/cM7eqZ6eRAI11Q=="]
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg15
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg16
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg17
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg18
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg19
|
||||
<110>1 2008-08-02T01:09:32.399406+02:00 host.example.org syslogd - - [ssign VER="0111" RSID="1217632162" SG="3" SPRI="0" GBC="4" FMN="1" CNT="20" HB="siUJM358eYFHOS2K0MTlveWeH/U= zTxfthW8WqmtFhOG4k/+ZxkirTA= j9dubU1GNVp7qWShwph/w32nD08= XQDLZ/NuwirmLdMORtm84r9kIW4= RNDFNCo7hiCsK/EKumsPBbFHNZA= ANiE3KbY948J6cEB640fAtWXuO4= e2M/OqjHDfxLVUSPt1CsNJHm9wU= Y+racQst7F1gR8eEUh8O7o+M53s= JAMULRxjMPbOO5EhhKbsUkAwbl0= pd+N5kmlnyQ0BoItELd/KWQrcMg= dsMQSzPHIS6S3Vaa23/t7U8JAJ4= i4rE3x7N4qyQGTkmaWHsWDFP9SY= qgTqV4EgfUFd3uZXNPvJ25erzBI= XW0YrME5kQEh+fxhg1fetnWxfIc= 7YPcRHsDwXWnQuGRWaJtFWw9hus= PIvLm0mh+he5+PDihG1p7sQlx8k= lPzUvx0I1VwSGWV7yKF9W//Yb2U= X+PWYcx5AXnsDVSNAHLZUGk5ioY= okXY88MGG4QybrYMf8HJN23WO1Y= HcaPyHfQ2s1SuSciTKw4woYWuMg=" SIGN="MCwCFFr0i6taT1vWowR7yc5bEQxFfY7/AhQBCK+rBNPgzR0vUgxPeARvD24kIQ=="]
|
||||
</pre>
|
||||
<p>Just in case you wonder about the different timestamps: The messages were send with a normal syslog(3), so the syslogd received them in BSD Syslog format without subsecond resolution.</p>
|
||||
<hr>
|
||||
<pre>
|
||||
$ perl verify.pl --help
|
||||
|
||||
syslog-sign verifier
|
||||
reads logfile and verifies message signatures
|
||||
|
||||
Notes:
|
||||
- By default uses only SHA-1 hashes. Use option "--sha256" to use only
|
||||
SHA-256 and "--sha1 --sha256"to use both types.
|
||||
- Some status messages are printed to stderr.
|
||||
Use option "--quiet" to disable them.
|
||||
- All verified messages are printed with their identifying signature group.
|
||||
Every line starts with a comma-separated tuple: hostname, reboot session ID,
|
||||
SG value, SPRI value, and message number.
|
||||
- If only one hash is used then all messages not signed are printed as well.
|
||||
|
||||
Limitations: handles only key types 'C' (PKIX) and 'K' (public key)
|
||||
with DSA keys and signatures
|
||||
|
||||
Command Line Options:
|
||||
-i --in input file (default: stdin)
|
||||
-o --out output file for verified messages (default: stdout)
|
||||
-u --unsigned output file for unsigned messages (default: stdout)
|
||||
--sha1 use SHA-1 hashes (default)
|
||||
--sha256 use SHA-256 hashes
|
||||
-v --verbose shows some internals (every CB,SB,hash,...)
|
||||
-q --quiet no status messages to stderr
|
||||
-h --help this help
|
||||
|
||||
$ perl verify.pl -i test.log
|
||||
reading input...
|
||||
processing CBs...
|
||||
decoding SGs...
|
||||
got PKIX DSA key
|
||||
verifying CBs...
|
||||
verified CB and got key for SG: (host.example.org,1217632162,0111,3,0), start: 2008-08-02T01:09:27.773464+02:00
|
||||
now process SBs
|
||||
signed messages:
|
||||
host.example.org,1217632162,0111,3,0,1 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg0
|
||||
host.example.org,1217632162,0111,3,0,2 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg1
|
||||
host.example.org,1217632162,0111,3,0,3 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg2
|
||||
host.example.org,1217632162,0111,3,0,4 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg3
|
||||
host.example.org,1217632162,0111,3,0,5 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg4
|
||||
host.example.org,1217632162,0111,3,0,6 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg5
|
||||
host.example.org,1217632162,0111,3,0,7 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg6
|
||||
host.example.org,1217632162,0111,3,0,8 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg7
|
||||
host.example.org,1217632162,0111,3,0,9 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg8
|
||||
host.example.org,1217632162,0111,3,0,10 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg9
|
||||
host.example.org,1217632162,0111,3,0,11 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg10
|
||||
host.example.org,1217632162,0111,3,0,12 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg11
|
||||
host.example.org,1217632162,0111,3,0,13 **** msg lost
|
||||
host.example.org,1217632162,0111,3,0,14 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg13
|
||||
host.example.org,1217632162,0111,3,0,15 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg14
|
||||
host.example.org,1217632162,0111,3,0,16 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg15
|
||||
host.example.org,1217632162,0111,3,0,17 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg16
|
||||
host.example.org,1217632162,0111,3,0,18 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg17
|
||||
host.example.org,1217632162,0111,3,0,19 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg18
|
||||
host.example.org,1217632162,0111,3,0,20 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg19
|
||||
messages without signature:
|
||||
<15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - modified msg12
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
<table border=0>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="http://sourceforge.net"><img align="top" src="http://sourceforge.net/sflogo.php?group_id=141771&type=2" width="125" height="37" border="0" alt="SourceForge.net Logo"></a>
|
||||
<td>
|
||||
<table>
|
||||
<tr> <td> Martin Schütte <<tt>info@mschuette.name</tt>> </td> </tr>
|
||||
<tr> <td> $Id: sign.html,v 1.1 2008/10/31 16:12:19 christos Exp $ </td> </tr>
|
||||
</table>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: syslog.conf.5,v 1.13 2004/11/19 18:48:43 wiz Exp $
|
||||
.\" $NetBSD: syslog.conf.5,v 1.14 2008/10/31 16:12:19 christos Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" from: @(#)syslog.conf.5 8.1 (Berkeley) 6/9/93
|
||||
.\"
|
||||
.Dd November 18, 2004
|
||||
.Dd August 8, 2008
|
||||
.Dt SYSLOG.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -43,7 +43,8 @@ The
|
||||
file is the configuration file for the
|
||||
.Xr syslogd 8
|
||||
program.
|
||||
It consists of blocks of lines separated by
|
||||
It consists of extended options (lines with one key="value" assignment)
|
||||
and blocks of lines separated by
|
||||
.Em program
|
||||
and
|
||||
.Em hostname
|
||||
@ -300,13 +301,38 @@ Note that use of this option may cause the loss of log information in
|
||||
the event of a system crash immediately following the write attempt.
|
||||
However, using this option may prove to be useful if your system's
|
||||
kernel is logging many messages.
|
||||
.Pp
|
||||
Normally the priority and version is not written to file.
|
||||
In order to use syslog-sign you may prefix a pathname with the plus sign
|
||||
.Ql + .
|
||||
If both switches are used the order has to be
|
||||
.Ql +- .
|
||||
.It
|
||||
A hostname (preceded by an at
|
||||
.Pq Sq @
|
||||
sign).
|
||||
Selected messages are forwarded to the
|
||||
.Xr syslogd 8
|
||||
program on the named host with UDP.
|
||||
.It
|
||||
A hostname preceded by an at
|
||||
.Pq Sq @
|
||||
sign and enclosed in brackets
|
||||
.Pq Sq []
|
||||
.
|
||||
Selected messages are forwarded with TLS to the
|
||||
.Xr syslogd 8
|
||||
program on the named host.
|
||||
After the closing bracket a colon
|
||||
.Pq Sq \&:
|
||||
and a port or service name may be appended.
|
||||
Additional options are configured in parantheses in the form of key="value".
|
||||
Recognized keywords are
|
||||
.Ar subject ,
|
||||
.Ar fingerprint ,
|
||||
.Ar cert ,
|
||||
and
|
||||
.Ar verify .
|
||||
.It
|
||||
A comma separated list of users.
|
||||
Selected messages are written to those users
|
||||
@ -360,17 +386,174 @@ complete.
|
||||
Note that the command is started with the UID of the
|
||||
.Xr syslogd 8
|
||||
process, normally the superuser.
|
||||
.Pp
|
||||
Just like with files a plus sign
|
||||
.Ql +
|
||||
will leave the priority and version information intact.
|
||||
.El
|
||||
.Pp
|
||||
Blank lines and lines whose first non-blank character is a hash
|
||||
.Pq Sq #
|
||||
character are ignored.
|
||||
.Sh "TLS OPTIONS"
|
||||
Additional options are used for TLS configuration:
|
||||
.Bl -ohang
|
||||
.It Em tls_server
|
||||
Enables TLS server mode.
|
||||
.It Em tls_bindport
|
||||
Service name or port number to bind to.
|
||||
Default is
|
||||
.Sq syslog .
|
||||
.Em As long as no official port is assigned this option is required for TLS servers.
|
||||
.It Em tls_bindhost
|
||||
Hostname or IP to bind to.
|
||||
.It Em tls_gen_cert
|
||||
Automatically generate a private key and certificate.
|
||||
.It Em tls_key
|
||||
File with private key.
|
||||
Default is
|
||||
.Sq /etc/openssl/default.key
|
||||
.It Em tls_cert
|
||||
File with certificate to use.
|
||||
Default is
|
||||
.Sq /etc/openssl/default.crt
|
||||
.It Em tls_ca
|
||||
File with CA certificate to use.
|
||||
.It Em tls_cadir
|
||||
Directory containing CA certificates.
|
||||
.It Em tls_verify
|
||||
If set to
|
||||
.Sq off
|
||||
then certificate authentication is skipped.
|
||||
.It Em tls_allow_fingerprints
|
||||
List of fingerprints of trusted client certificates.
|
||||
.It Em tls_allow_clientcerts
|
||||
List of filenames with trusted client certificates.
|
||||
.El
|
||||
.Sh "TLS AUTHENTICATION"
|
||||
One function of TLS is mutual authentication of client and server.
|
||||
Unless authentication is disabled by setting
|
||||
.Sq tls_verify=off
|
||||
the following rules are used:
|
||||
.Ss "as client:"
|
||||
A client can be configured not to check a server's certificate by setting the
|
||||
parameter
|
||||
.Ar verify
|
||||
to
|
||||
.Sq off .
|
||||
If the server's certificate is signed by a trusted CA then it is checked
|
||||
if its hostname or IP is given in its certificate (as a CommonName, as a
|
||||
DNS SubjectAltName, or as an IP SubjectAltName).
|
||||
If any match is found then the server is authenticated.
|
||||
If a
|
||||
.Ar subject
|
||||
parameter is given then it is can satisfy this test as well.
|
||||
This allows DNS-independent configurations using the server's IP address in the
|
||||
destination and adding its hostname as
|
||||
.Ar subject
|
||||
to authenticate the TLS connection without having to add the IP to the X.509
|
||||
certificate.
|
||||
.br
|
||||
If no CA is used or no trust path between CA and server certificate exists, then
|
||||
hash value of the server's certificate is compared with the hash given in
|
||||
.Ar fingerprint
|
||||
and the hash of the certificate in
|
||||
.Ar cert .
|
||||
If the hashes are equal then the server is authenticated.
|
||||
.Ss "as server:"
|
||||
If using a CA and the client's certificate is signed by it then the client is
|
||||
authenticated.
|
||||
Otherwise the hash of the client's certificate is compared with the hashes given
|
||||
in
|
||||
.Ar tls_allow_fingerprints
|
||||
and the hashes of the certificates given in
|
||||
.Ar tls_allow_clientcerts .
|
||||
On any match the client is authenticated.
|
||||
.Sh BUFFERING
|
||||
.Xr syslogd 8
|
||||
is able to buffer temporary not writeable messages in memory.
|
||||
To limit the memory consumed for this buffering the following optons may be
|
||||
given:
|
||||
.Bl -ohang
|
||||
.It Em file_queue_length
|
||||
.It Em pipe_queue_length
|
||||
.It Em tls_queue_length
|
||||
The maximum number of messages buffered for one destination of type tls, file,
|
||||
or pipe respectively.
|
||||
Defaults are
|
||||
.Sq 1024 ,
|
||||
.Sq 1024 ,
|
||||
and
|
||||
.Sq -1
|
||||
(no limit).
|
||||
.It Em file_queue_size
|
||||
.It Em pipe_queue_size
|
||||
.It Em tls_queue_size
|
||||
The maximum memory usage in bytes of messages buffered for one destination.
|
||||
Defaults are
|
||||
.Sq 1M ,
|
||||
.Sq 1M ,
|
||||
and
|
||||
.Sq 16M .
|
||||
.El
|
||||
.Sh SIGNING
|
||||
.Xr syslogd 8
|
||||
is able to digitally sign all processed messages.
|
||||
The used protocol is defined by RFC nnnn (syslog-sign):
|
||||
at the start of a session the signing sender sends so called certificate
|
||||
blocks containing its public key; after that it periodically sends a signed
|
||||
message containing hashes of previous messages.
|
||||
.Pp
|
||||
To detect later manipulation one has to keep a copy of the key used for
|
||||
signing (otherwise an attacker could alter the logs and sign them with his
|
||||
his own key).
|
||||
If TLS is used with a DSA key then the same key will be used for signing.
|
||||
This is the recommended setup because it makes it easy to have copies of
|
||||
the certificate (with the public key) in backups.
|
||||
Otherwise new keys are generated on every restart and for certain verification
|
||||
it is necessary to have copies of all used keys.
|
||||
So logging only to a local file is not secure; at least the used keys should
|
||||
be logged to another host.
|
||||
.Bl -ohang
|
||||
.It Em sign_sg
|
||||
Enables signing.
|
||||
Set this option to enable syslog-sign and select how to assign
|
||||
messages to signature groups (subsets of messages that are signed together).
|
||||
To enable later signature verification and detection of lost messages the
|
||||
assignment should be chosen such that all messages of one signature group
|
||||
are written to the same file.
|
||||
Four possible values for this option are:
|
||||
.Bl -hang -offset indent
|
||||
.It Em 0
|
||||
Use one global signature group for all messages.
|
||||
.It Em 1
|
||||
Use one signature group per priority.
|
||||
.It Em 2
|
||||
Use signature groups for ranges of priorities.
|
||||
.It Em 3
|
||||
Use one signature group per destination.
|
||||
This is a custom strategy not defined by the standard.
|
||||
With this setting one signature group is set up for
|
||||
every file and network action.
|
||||
.El
|
||||
.It Em sign_delim_sg2
|
||||
This option is only evaluated with
|
||||
.Sq sign_sg=2
|
||||
and allows to configure the priority ranges for signature groups.
|
||||
The parameters are numerical values used as the maximum priority for one group.
|
||||
The default is to use one signature groups per facility, which is equal to
|
||||
setting
|
||||
.Sq sign_delim_sg2=7 15 23 31 39 ... .
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/syslog.conf -compact
|
||||
.It Pa /etc/syslog.conf
|
||||
The
|
||||
.Xr syslogd 8
|
||||
configuration file.
|
||||
.It Pa /usr/share/examples/syslogd/verify.pl
|
||||
Example script to verify message signatures.
|
||||
(Requires Perl and modules not part of NetBSD.)
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
A configuration file might appear as follows:
|
||||
@ -389,7 +572,8 @@ A configuration file might appear as follows:
|
||||
daemon.=debug /var/log/daemon.debug
|
||||
|
||||
# The authpriv file has restricted access.
|
||||
authpriv.* /var/log/secure
|
||||
# Write logs with priority for later verification with syslog-sign.
|
||||
authpriv.* +/var/log/secure
|
||||
|
||||
# Log all the mail messages in one place.
|
||||
mail.* /var/log/maillog
|
||||
@ -399,6 +583,11 @@ mail.* /var/log/maillog
|
||||
*.emerg *
|
||||
*.emerg @arpa.berkeley.edu
|
||||
|
||||
# Log all messages of level info or higher to another
|
||||
# machine using TLS with an alternative portname and a
|
||||
# fingerprint for athentication
|
||||
*.info @[logserver]:1234(fingerprint="SHA1:01:02:...")
|
||||
|
||||
# Root and Eric get alert and higher messages.
|
||||
*.alert root,eric
|
||||
|
||||
@ -429,6 +618,10 @@ kern.err |exec /usr/local/sbin/raidfilter
|
||||
!*
|
||||
-@
|
||||
*.* /var/log/foreign
|
||||
|
||||
# Generate digital signatures for all messages
|
||||
# to each file or network destination.
|
||||
sign_sg=3
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr syslog 3 ,
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: syslogd.8,v 1.42 2006/09/15 20:32:59 christos Exp $
|
||||
.\" $NetBSD: syslogd.8,v 1.43 2008/10/31 16:12:19 christos Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1983, 1986, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" from: @(#)syslogd.8 8.1 (Berkeley) 6/6/93
|
||||
.\"
|
||||
.Dd September 15, 2006
|
||||
.Dd August 8, 2008
|
||||
.Dt SYSLOGD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -91,6 +91,14 @@ Select the number of minutes between ``mark'' messages;
|
||||
the default is 20 minutes.
|
||||
.It Fl n
|
||||
Do not perform hostname lookups; report only numeric addresses.
|
||||
.It Fl o
|
||||
Select output message format.
|
||||
.Bl -hang
|
||||
.It Em rfc3164
|
||||
traditional BSD Syslog format (default)
|
||||
.It Em syslog
|
||||
new syslog-protocol format
|
||||
.El
|
||||
.It Fl P
|
||||
Specify the pathname of a file containing a list of sockets to be
|
||||
created.
|
||||
@ -219,26 +227,19 @@ Refer to
|
||||
.Xr hosts_access 5
|
||||
for details.
|
||||
.Ss SYSLOG PROTOCOL NOTES
|
||||
The message sent to
|
||||
.Nm
|
||||
should consist of a single line.
|
||||
The message can contain a priority code, which should be a preceding
|
||||
decimal number in angle braces, for example,
|
||||
.Sq Aq 5 .
|
||||
This priority code should map into the priorities defined in the
|
||||
include file
|
||||
.Aq Pa sys/syslog.h .
|
||||
See RFC 3164 for detailed description of the message format.
|
||||
.Pp
|
||||
Messages from the local kernel that are not tagged with a priority code
|
||||
receive the default facility
|
||||
accepts messages in traditional BSD Syslog or in newer Syslog Protocol
|
||||
format.
|
||||
See RFC 3164 (BSD Syslog) and RFC
|
||||
.Em nnnn
|
||||
(Syslog Protocol) for detailed description of the message format.
|
||||
.Dv LOG_KERN
|
||||
and priority
|
||||
.Dv LOG_NOTICE .
|
||||
All other untagged messages receive the default facility
|
||||
.Dv LOG_USER
|
||||
and priority
|
||||
.Dv LOT_NOTICE .
|
||||
.Dv LOG_NOTICE .
|
||||
.Sh FILES
|
||||
.Bl -tag -width /var/run/syslogd.pid -compact
|
||||
.It Pa /etc/syslog.conf
|
||||
@ -265,6 +266,12 @@ The kernel log device.
|
||||
.%D August 2001
|
||||
.%T The BSD syslog Protocol
|
||||
.Re
|
||||
.Rs
|
||||
.%R Internet-Draft
|
||||
.%N draft-ietf-syslog-protocol-23
|
||||
.%D September 2007
|
||||
.%T The syslog Protocol
|
||||
.Re
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
|
File diff suppressed because it is too large
Load Diff
470
usr.sbin/syslogd/syslogd.h
Normal file
470
usr.sbin/syslogd/syslogd.h
Normal file
@ -0,0 +1,470 @@
|
||||
/* $NetBSD: syslogd.h,v 1.1 2008/10/31 16:12:19 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Martin Schütte.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SYSLOGD_H_
|
||||
#define SYSLOGD_H_
|
||||
/*
|
||||
* hold common data structures and prototypes
|
||||
* for syslogd.c and tls.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#define MAXLINE 1024 /* maximum line length */
|
||||
#define MAXSVLINE 120 /* maximum saved line length */
|
||||
#define DEFUPRI (LOG_USER|LOG_NOTICE)
|
||||
#define DEFSPRI (LOG_KERN|LOG_NOTICE)
|
||||
#define TIMERINTVL 30 /* interval for checking flush, mark */
|
||||
#define TTYMSGTIME 1 /* timeout passed to ttymsg */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/queue.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/event.h>
|
||||
#include <event.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <locale.h>
|
||||
#include <netdb.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <utmp.h>
|
||||
#ifdef __NetBSD_Version__
|
||||
#include <util.h>
|
||||
#include "utmpentry.h"
|
||||
#endif /* __NetBSD_Version__ */
|
||||
#ifdef __FreeBSD_version
|
||||
#include <libutil.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
#include <limits.h>
|
||||
#endif /* __FreeBSD_version */
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
#include <netinet/tcp.h>
|
||||
#include <openssl/ssl.h>
|
||||
#endif /* !DISABLE_TLS */
|
||||
|
||||
#include <sys/stdint.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
/* additional queue macros copied from FreeBSD */
|
||||
#ifndef SLIST_FOREACH_SAFE
|
||||
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = SLIST_FIRST((head)); \
|
||||
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
#endif /* !SLIST_FOREACH_SAFE */
|
||||
#ifndef STAILQ_FOREACH_SAFE
|
||||
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = STAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
#endif /* !STAILQ_FOREACH_SAFE */
|
||||
#ifndef STAILQ_LAST
|
||||
#define STAILQ_LAST(head, type, field) \
|
||||
(STAILQ_EMPTY((head)) ? \
|
||||
NULL : \
|
||||
((struct type *) \
|
||||
((char *)((head)->stqh_last) - offsetof(struct type, field))))
|
||||
#endif /* !STAILQ_LAST */
|
||||
#ifndef STAILQ_CONCAT
|
||||
#define STAILQ_CONCAT(head1, head2) do { \
|
||||
if (!STAILQ_EMPTY((head2))) { \
|
||||
*(head1)->stqh_last = (head2)->stqh_first; \
|
||||
(head1)->stqh_last = (head2)->stqh_last; \
|
||||
STAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif /* !STAILQ_CONCAT */
|
||||
#ifndef TAILQ_CONCAT
|
||||
#define TAILQ_CONCAT(head1, head2, field) do { \
|
||||
if (!TAILQ_EMPTY(head2)) { \
|
||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
TAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif /* !TAILQ_CONCAT */
|
||||
|
||||
#include "pathnames.h"
|
||||
#include <sys/syslog.h>
|
||||
|
||||
/* some differences between the BSDs */
|
||||
#ifdef __FreeBSD_version
|
||||
#undef _PATH_UNIX
|
||||
#define _PATH_UNIX "kernel"
|
||||
#define HAVE_STRNDUP 0
|
||||
#endif /* __FreeBSD_version */
|
||||
|
||||
#ifdef __NetBSD_Version__
|
||||
#define HAVE_STRNDUP 1
|
||||
#define HAVE_DEHUMANIZE_NUMBER 1
|
||||
#endif /* __NetBSD_Version__ */
|
||||
|
||||
#ifndef HAVE_DEHUMANIZE_NUMBER /* not in my 4.0-STABLE yet */
|
||||
extern int dehumanize_number(const char *str, int64_t *size);
|
||||
#endif /* !HAVE_DEHUMANIZE_NUMBER */
|
||||
|
||||
#if !HAVE_STRNDUP
|
||||
char *strndup(const char *str, size_t n);
|
||||
#endif /* !HAVE_STRNDUP */
|
||||
|
||||
#ifdef LIBWRAP
|
||||
#include <tcpd.h>
|
||||
#endif
|
||||
|
||||
#define FDMASK(fd) (1 << (fd))
|
||||
|
||||
#define A_CNT(x) (sizeof((x)) / sizeof((x)[0]))
|
||||
|
||||
/* debug messages with categories */
|
||||
#define D_NONE 0
|
||||
#define D_CALL 1 /* function calls */
|
||||
#define D_DATA 2 /* syslog message reading/formatting */
|
||||
#define D_NET 4 /* sockets/network */
|
||||
#define D_FILE 8 /* local files */
|
||||
#define D_TLS 16 /* TLS */
|
||||
#define D_PARSE 32 /* configuration/parsing */
|
||||
#define D_EVENT 64 /* libevent */
|
||||
#define D_BUFFER 128 /* message queues */
|
||||
#define D_MEM 256 /* malloc/free */
|
||||
#define D_MEM2 1024 /* every single malloc/free */
|
||||
#define D_SIGN 2048 /* -sign */
|
||||
#define D_MISC 4096 /* everything else */
|
||||
#define D_ALL (D_CALL | D_DATA | D_NET | D_FILE | D_TLS | D_PARSE | \
|
||||
D_EVENT | D_BUFFER | D_MEM | D_MEM2 | D_SIGN | D_MISC)
|
||||
#define D_DEFAULT (D_CALL | D_NET | D_FILE | D_TLS | D_MISC)
|
||||
|
||||
|
||||
/* build with -DNDEBUG to remove all assert()s and DPRINTF()s */
|
||||
#ifdef NDEBUG
|
||||
#define DPRINTF(x, ...) (void)0
|
||||
#else
|
||||
#define DPRINTF(x, ...) /*LINTED null effect */(void)(Debug & (x) \
|
||||
? (printf("%s:%s:%s:%.4d\t", make_timestamp(NULL, true), \
|
||||
__FILE__, __func__, __LINE__), printf(__VA_ARGS__)) : 0)
|
||||
#endif
|
||||
|
||||
/* shortcuts for libevent */
|
||||
#define EVENT_ADD(x) do { \
|
||||
DPRINTF(D_EVENT, "event_add(%s@%p)\n", #x, x); \
|
||||
if (event_add(x, NULL) == -1) { \
|
||||
DPRINTF(D_EVENT, "Failure in event_add()\n"); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#define RETRYEVENT_ADD(x) do { \
|
||||
struct timeval _tv; \
|
||||
_tv.tv_sec = 0; \
|
||||
_tv.tv_usec = TLS_RETRY_EVENT_USEC; \
|
||||
DPRINTF(D_EVENT, "retryevent_add(%s@%p)\n", #x, x); \
|
||||
if (event_add(x, &_tv) == -1) { \
|
||||
DPRINTF(D_EVENT, "Failure in event_add()\n"); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#define DEL_EVENT(x) do { \
|
||||
DPRINTF(D_MEM2, "DEL_EVENT(%s@%p)\n", #x, x); \
|
||||
if ((x) && (event_del(x) == -1)) { \
|
||||
DPRINTF(D_EVENT, "Failure in event_del()\n"); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
/* safe calls to free() */
|
||||
#define FREEPTR(x) if (x) { \
|
||||
DPRINTF(D_MEM2, "free(%s@%p)\n", #x, x); \
|
||||
free(x); x = NULL; }
|
||||
#define FREE_SSL(x) if (x) { \
|
||||
DPRINTF(D_MEM2, "SSL_free(%s@%p)\n", #x, x); \
|
||||
SSL_free(x); x = NULL; }
|
||||
#define FREE_SSL_CTX(x) if (x) { \
|
||||
DPRINTF(D_MEM2, "SSL_CTX_free(%s@%p)\n", #x, x); \
|
||||
SSL_CTX_free(x); x = NULL; }
|
||||
|
||||
/* reference counting macros for buffers */
|
||||
#define NEWREF(x) ((x) ? (DPRINTF(D_BUFFER, "inc refcount of " #x \
|
||||
" @ %p: %zu --> %zu\n", (x), (x)->refcount, \
|
||||
(x)->refcount + 1), (x)->refcount++, (x))\
|
||||
: (DPRINTF(D_BUFFER, "inc refcount of NULL!\n"), NULL))
|
||||
#define DELREF(x) /*LINTED null effect*/(void)((x) ? (DPRINTF(D_BUFFER, "dec refcount of " #x \
|
||||
" @ %p: %zu --> %zu\n", (x), (x)->refcount, \
|
||||
(x)->refcount - 1), buf_msg_free(x), NULL) \
|
||||
: (DPRINTF(D_BUFFER, "dec refcount of NULL!\n"), NULL))
|
||||
|
||||
/* assumption:
|
||||
* - malloc()/calloc() only fails if not enough memory available
|
||||
* - once init() has set up all global variables etc.
|
||||
* the bulk of available memory is used for buffers
|
||||
* and can be freed if necessary
|
||||
*/
|
||||
#define MALLOC(ptr, size) do { \
|
||||
while(!(ptr = malloc(size))) { \
|
||||
DPRINTF(D_MEM, "Unable to allocate memory"); \
|
||||
message_allqueues_purge(); \
|
||||
} \
|
||||
DPRINTF(D_MEM2, "MALLOC(%s@%p, %zu)\n", #ptr, ptr, size); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CALLOC(ptr, size) do { \
|
||||
while(!(ptr = calloc(1, size))) { \
|
||||
DPRINTF(D_MEM, "Unable to allocate memory"); \
|
||||
message_allqueues_purge(); \
|
||||
} \
|
||||
DPRINTF(D_MEM2, "CALLOC(%s@%p, %zu)\n", #ptr, ptr, size); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
/* define strlen(NULL) to be 0 */
|
||||
#define SAFEstrlen(x) ((x) ? strlen(x) : 0)
|
||||
|
||||
/* shorthand to block/restore signals for the duration of one function */
|
||||
#define BLOCK_SIGNALS(omask, newmask) do { \
|
||||
sigemptyset(&newmask); \
|
||||
sigaddset(&newmask, SIGHUP); \
|
||||
sigaddset(&newmask, SIGALRM); \
|
||||
sigprocmask(SIG_BLOCK, &newmask, &omask); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define RESTORE_SIGNALS(omask) sigprocmask(SIG_SETMASK, &omask, NULL)
|
||||
|
||||
/* small optimization to call send_queue() only if queue has elements */
|
||||
#define SEND_QUEUE(f) do { \
|
||||
if ((f)->f_qelements) \
|
||||
send_queue(0, 0, f); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define MAXUNAMES 20 /* maximum number of user names */
|
||||
#define BSD_TIMESTAMPLEN 14+1
|
||||
#define MAX_TIMESTAMPLEN 31+1
|
||||
|
||||
/* maximum field lengths in syslog-protocol */
|
||||
#define PRI_MAX 5
|
||||
#define HOST_MAX 255
|
||||
#define APPNAME_MAX 48
|
||||
#define PROCID_MAX 128
|
||||
#define MSGID_MAX 32
|
||||
/* longest possible header length */
|
||||
#define HEADER_LEN_MAX (PRI_MAX + 1 + 1 + MAX_TIMESTAMPLEN + 1 + HOST_MAX \
|
||||
+ 1 + APPNAME_MAX + 1 + PROCID_MAX + 1 + MSGID_MAX)
|
||||
|
||||
/* allowed number of priorities by IETF standards */
|
||||
#define IETF_NUM_PRIVALUES 192
|
||||
|
||||
/* check if message with fac/sev belogs to a destination f */
|
||||
#define MATCH_PRI(f, fac, sev) \
|
||||
( (((f)->f_pcmp[fac] & PRI_EQ) && ((f)->f_pmask[fac] == (sev))) \
|
||||
||(((f)->f_pcmp[fac] & PRI_LT) && ((f)->f_pmask[fac] < (sev))) \
|
||||
||(((f)->f_pcmp[fac] & PRI_GT) && ((f)->f_pmask[fac] > (sev))) \
|
||||
)
|
||||
|
||||
/* shorthand to test Byte Order Mark which indicates UTF-8 content */
|
||||
#define IS_BOM(p) ( \
|
||||
(p)[0] != '\0' && (unsigned char)(p)[0] == (unsigned char)0xEF && \
|
||||
(p)[1] != '\0' && (unsigned char)(p)[1] == (unsigned char)0xBB && \
|
||||
(p)[2] != '\0' && (unsigned char)(p)[2] == (unsigned char)0xBF)
|
||||
|
||||
/* message buffer container used for processing, formatting, and queueing */
|
||||
struct buf_msg {
|
||||
size_t refcount;
|
||||
int pri;
|
||||
int flags;
|
||||
char *timestamp;
|
||||
char *recvhost;
|
||||
char *host;
|
||||
char *prog;
|
||||
char *pid;
|
||||
char *msgid;
|
||||
char *sd; /* structured data */
|
||||
char *msg; /* message content */
|
||||
char *msgorig; /* in case we advance *msg beyond header fields
|
||||
we still want to free() the original ptr */
|
||||
size_t msglen; /* strlen(msg) */
|
||||
size_t msgsize; /* allocated memory size */
|
||||
size_t tlsprefixlen; /* bytes for the TLS length prefix */
|
||||
size_t prilen; /* bytes for priority and version */
|
||||
};
|
||||
|
||||
/* queue of messages */
|
||||
struct buf_queue {
|
||||
struct buf_msg* msg;
|
||||
STAILQ_ENTRY(buf_queue) entries;
|
||||
};
|
||||
STAILQ_HEAD(buf_queue_head, buf_queue);
|
||||
|
||||
/* a pair of a socket and an associated event object */
|
||||
struct socketEvent {
|
||||
int fd;
|
||||
struct event *ev;
|
||||
};
|
||||
|
||||
/*
|
||||
* Flags to logmsg().
|
||||
*/
|
||||
#define IGN_CONS 0x001 /* don't print on console */
|
||||
#define SYNC_FILE 0x002 /* do fsync on file after printing */
|
||||
#define ADDDATE 0x004 /* add a date to the message */
|
||||
#define MARK 0x008 /* this message is a mark */
|
||||
#define ISKERNEL 0x010 /* kernel generated message */
|
||||
#define BSDSYSLOG 0x020 /* line in traditional BSD Syslog format */
|
||||
#define SIGN_MSG 0x040 /* syslog-sign data, not signed again */
|
||||
|
||||
/* strategies for message_queue_purge() */
|
||||
#define PURGE_OLDEST 1
|
||||
#define PURGE_BY_PRIORITY 2
|
||||
|
||||
/*
|
||||
* This structure represents the files that will have log
|
||||
* copies printed.
|
||||
* We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY,
|
||||
* or if f_type is F_PIPE and f_pid > 0.
|
||||
*/
|
||||
|
||||
struct filed {
|
||||
struct filed *f_next; /* next in linked list */
|
||||
short f_type; /* entry type, see below */
|
||||
short f_file; /* file descriptor */
|
||||
time_t f_time; /* time this was last written */
|
||||
char *f_host; /* host from which to record */
|
||||
u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */
|
||||
u_char f_pcmp[LOG_NFACILITIES+1]; /* compare priority */
|
||||
#define PRI_LT 0x1
|
||||
#define PRI_EQ 0x2
|
||||
#define PRI_GT 0x4
|
||||
char *f_program; /* program this applies to */
|
||||
union {
|
||||
char f_uname[MAXUNAMES][UT_NAMESIZE+1];
|
||||
struct {
|
||||
char f_hname[MAXHOSTNAMELEN];
|
||||
struct addrinfo *f_addr;
|
||||
} f_forw; /* UDP forwarding address */
|
||||
#ifndef DISABLE_TLS
|
||||
struct {
|
||||
SSL *ssl; /* SSL object */
|
||||
struct tls_conn_settings *tls_conn; /* certificate info */
|
||||
} f_tls; /* TLS forwarding address */
|
||||
#endif /* !DISABLE_TLS */
|
||||
char f_fname[MAXPATHLEN];
|
||||
struct {
|
||||
char f_pname[MAXPATHLEN];
|
||||
pid_t f_pid;
|
||||
} f_pipe;
|
||||
} f_un;
|
||||
#ifndef DISABLE_SIGN
|
||||
struct signature_group_t *f_sg; /* one signature group */
|
||||
#endif /* !DISABLE_SIGN */
|
||||
struct buf_queue_head f_qhead; /* undelivered msgs queue */
|
||||
size_t f_qelements; /* elements in queue */
|
||||
size_t f_qsize; /* size of queue in bytes */
|
||||
struct buf_msg *f_prevmsg; /* last message logged */
|
||||
struct event *f_sq_event; /* timer for send_queue() */
|
||||
int f_prevcount; /* repetition cnt of prevmsg */
|
||||
int f_repeatcount; /* number of "repeated" msgs */
|
||||
int f_lasterror; /* last error on writev() */
|
||||
int f_flags; /* file-specific flags */
|
||||
#define FFLAG_SYNC 0x01 /* for F_FILE: fsync after every msg */
|
||||
#define FFLAG_FULL 0x02 /* for F_FILE | F_PIPE: write PRI header */
|
||||
#define FFLAG_SIGN 0x04 /* for syslog-sign with SG="3":
|
||||
* sign the messages to this destination */
|
||||
};
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
|
||||
/* linked list for allowed TLS peer credentials
|
||||
* (one for fingerprint, one for cert-files)
|
||||
*/
|
||||
SLIST_HEAD(peer_cred_head, peer_cred);
|
||||
struct peer_cred {
|
||||
SLIST_ENTRY(peer_cred) entries;
|
||||
char *data;
|
||||
};
|
||||
|
||||
/* config options for TLS server-side */
|
||||
struct tls_global_options_t {
|
||||
SSL_CTX *global_TLS_CTX;
|
||||
struct peer_cred_head fprint_head; /* trusted client fingerprints */
|
||||
struct peer_cred_head cert_head; /* trusted client cert files */
|
||||
char *keyfile; /* file with private key */
|
||||
char *certfile; /* file with own certificate */
|
||||
char *CAfile; /* file with CA certificate */
|
||||
char *CAdir; /* alternative: path to directory with CA certs */
|
||||
char *x509verify; /* level of peer verification */
|
||||
char *bindhost; /* hostname/IP to bind to */
|
||||
char *bindport; /* port/service to bind to */
|
||||
char *server; /* if !NULL: do not listen to incoming TLS */
|
||||
char *gen_cert; /* if !NULL: generate self-signed certificate */
|
||||
};
|
||||
|
||||
/* TLS needs three sets of sockets:
|
||||
* - listening sockets: a fixed size array TLS_Listen_Set, just like finet for UDP.
|
||||
* - outgoing connections: managed as part of struct filed.
|
||||
* - incoming connections: variable sized, thus a linked list TLS_Incoming.
|
||||
*/
|
||||
/* every connection has its own input buffer with status
|
||||
* variables for message reading */
|
||||
SLIST_HEAD(TLS_Incoming, TLS_Incoming_Conn);
|
||||
|
||||
struct TLS_Incoming_Conn {
|
||||
SLIST_ENTRY(TLS_Incoming_Conn) entries;
|
||||
struct tls_conn_settings *tls_conn;
|
||||
int socket;
|
||||
char *inbuf; /* input buffer */
|
||||
size_t inbuflen;
|
||||
size_t cur_msg_len; /* length of current msg */
|
||||
size_t cur_msg_start; /* beginning of current msg */
|
||||
size_t read_pos; /* ring buffer position to write to */
|
||||
size_t errorcount; /* to close faulty connections */
|
||||
bool closenow; /* close connection as soon as buffer processed */
|
||||
bool dontsave; /* for receiving oversized messages w/o saving them */
|
||||
};
|
||||
|
||||
#endif /* !DISABLE_TLS */
|
||||
|
||||
#endif /*SYSLOGD_H_*/
|
2181
usr.sbin/syslogd/tls.c
Normal file
2181
usr.sbin/syslogd/tls.c
Normal file
File diff suppressed because it is too large
Load Diff
196
usr.sbin/syslogd/tls.h
Normal file
196
usr.sbin/syslogd/tls.h
Normal file
@ -0,0 +1,196 @@
|
||||
/* $NetBSD: tls.h,v 1.1 2008/10/31 16:12:19 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Martin Schütte.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* tls.h
|
||||
*
|
||||
*/
|
||||
#ifndef _TLS_H
|
||||
#define _TLS_H
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
/* initial size for TLS inbuf, minimum prefix + linelength
|
||||
* guaranteed to be accepted */
|
||||
#define TLS_MIN_LINELENGTH (2048 + 5)
|
||||
/* usually the inbuf is enlarged as needed and then kept.
|
||||
* if bigger than TLS_PERSIST_LINELENGTH, then shrink
|
||||
* to TLS_LARGE_LINELENGTH immediately */
|
||||
#define TLS_LARGE_LINELENGTH 8192
|
||||
#define TLS_PERSIST_LINELENGTH 32768
|
||||
|
||||
/* timeout to call non-blocking TLS operations again */
|
||||
#define TLS_RETRY_EVENT_USEC 20000
|
||||
|
||||
/* reconnect to lost server after n sec (initial value) */
|
||||
#define TLS_RECONNECT_SEC 10
|
||||
/* backoff connection attempts */
|
||||
#define TLS_RECONNECT_BACKOFF_FACTOR 15/10
|
||||
#define TLS_RECONNECT_BACKOFF(x) (x) = (x) * TLS_RECONNECT_BACKOFF_FACTOR
|
||||
/* abandon connection attempts after n sec
|
||||
* This has to be <= 5h (with 10sec initial interval),
|
||||
* otherwise a daily SIGHUP from newsylog will reset
|
||||
* all timers and the giveup time will never be reached
|
||||
*
|
||||
* set here: 2h, reached after ca. 7h of reconnecting
|
||||
*/
|
||||
#define TLS_RECONNECT_GIVEUP 60*60*2
|
||||
|
||||
/* default algorithm for certificate fingerprints */
|
||||
#define DEFAULT_FINGERPRINT_ALG "sha-1"
|
||||
|
||||
/* default X.509 files */
|
||||
#define DEFAULT_X509_CERTFILE "/etc/openssl/default.crt"
|
||||
#define DEFAULT_X509_KEYFILE "/etc/openssl/default.key"
|
||||
|
||||
/* options for peer certificate verification */
|
||||
#define X509VERIFY_ALWAYS 0
|
||||
#define X509VERIFY_IFPRESENT 1
|
||||
#define X509VERIFY_NONE 2
|
||||
|
||||
/* attributes for self-generated keys/certificates */
|
||||
#define TLS_GENCERT_BITS 1024
|
||||
#define TLS_GENCERT_SERIAL 1
|
||||
#define TLS_GENCERT_DAYS 5*365
|
||||
|
||||
/* TLS connection states */
|
||||
#define ST_NONE 0
|
||||
#define ST_TLS_EST 1
|
||||
#define ST_TCP_EST 2
|
||||
#define ST_CONNECTING 3
|
||||
#define ST_ACCEPTING 4
|
||||
#define ST_READING 5
|
||||
#define ST_WRITING 6
|
||||
#define ST_EOF 7
|
||||
#define ST_CLOSING0 8
|
||||
#define ST_CLOSING1 9
|
||||
#define ST_CLOSING2 10
|
||||
|
||||
/* backlog for listen */
|
||||
#define TLSBACKLOG 4
|
||||
/* close TLS connection after multiple 'soft' errors */
|
||||
#define TLS_MAXERRORCOUNT 4
|
||||
|
||||
/*
|
||||
* holds TLS related settings for one connection to be
|
||||
* included in the SSL object and available in callbacks
|
||||
*
|
||||
* Many fields have a slightly different semantic for
|
||||
* incoming and outgoing connections:
|
||||
* - for outgoing connections it contains the values from syslog.conf and
|
||||
* the server's cert is checked against these values by check_peer_cert()
|
||||
* - for incoming connections it is not used for checking, instead
|
||||
* dispatch_tls_accept() fills in the connected hostname/port and
|
||||
* check_peer_cert() fills in subject and fingerprint from the peer cert
|
||||
*/
|
||||
struct tls_conn_settings {
|
||||
unsigned send_queue:1, /* currently sending buffer */
|
||||
errorcount:4, /* counter [0;TLS_MAXERRORCOUNT] */
|
||||
accepted:1, /* workaround cf. check_peer_cert*/
|
||||
shutdown:1, /* fast connection close on exit */
|
||||
x509verify:2, /* kind of validation needed */
|
||||
incoming:1, /* set if we are server */
|
||||
state:4; /* outgoing connection state */
|
||||
struct event *event; /* event for read/write activity */
|
||||
struct event *retryevent; /* event for retries */
|
||||
SSL *sslptr; /* active SSL object */
|
||||
char *hostname; /* hostname or IP we connect to */
|
||||
char *port; /* service name or port number */
|
||||
char *subject; /* configured hostname in cert */
|
||||
char *fingerprint; /* fingerprint of peer cert */
|
||||
char *certfile; /* filename of peer cert */
|
||||
unsigned reconnect; /* seconds between reconnects */
|
||||
};
|
||||
|
||||
/* argument struct only used for tls_send() */
|
||||
struct tls_send_msg {
|
||||
struct filed *f;
|
||||
struct buf_queue *qentry;
|
||||
char *line; /* formatted message */
|
||||
size_t linelen;
|
||||
size_t offset; /* in case of partial writes */
|
||||
};
|
||||
|
||||
/* return values for TLS_examine_error() */
|
||||
#define TLS_OK 0 /* no real problem, just ignore */
|
||||
#define TLS_RETRY_READ 1 /* just retry, non-blocking operation not finished yet */
|
||||
#define TLS_RETRY_WRITE 2 /* just retry, non-blocking operation not finished yet */
|
||||
#define TLS_TEMP_ERROR 4 /* recoverable error condition, but try again */
|
||||
#define TLS_PERM_ERROR 8 /* non-recoverable error condition, closed TLS and socket */
|
||||
|
||||
/* global TLS setup and utility */
|
||||
char *init_global_TLS_CTX(void);
|
||||
struct socketEvent *socksetup_tls(const int, const char *, const char *);
|
||||
int check_peer_cert(int, X509_STORE_CTX *);
|
||||
int accept_cert(const char* , struct tls_conn_settings *, char *, char *);
|
||||
int deny_cert(struct tls_conn_settings *, char *, char *);
|
||||
bool read_certfile(X509 **, const char *);
|
||||
bool write_x509files(EVP_PKEY *, X509 *, const char *, const char *);
|
||||
bool mk_x509_cert(X509 **, EVP_PKEY **, int, int, int);
|
||||
bool x509_cert_add_subjectAltName(X509 *, X509V3_CTX *);
|
||||
int tls_examine_error(const char *, const SSL *, struct tls_conn_settings *, const int);
|
||||
|
||||
bool get_fingerprint(const X509 *, char **, const char *);
|
||||
bool get_commonname(X509 *, char **);
|
||||
bool match_hostnames(X509 *, const char *, const char *);
|
||||
bool match_fingerprint(const X509 *, const char *);
|
||||
bool match_certfile(const X509 *, const char *);
|
||||
|
||||
/* configuration & parsing */
|
||||
bool parse_tls_destination(const char *, struct filed *, size_t);
|
||||
/* event callbacks */
|
||||
void dispatch_socket_accept(int, short, void *);
|
||||
void dispatch_tls_accept(int, short, void *);
|
||||
void dispatch_tls_read(int, short, void *);
|
||||
void dispatch_tls_send(int, short, void *);
|
||||
void dispatch_tls_eof(int, short, void *);
|
||||
void dispatch_SSL_connect(int, short, void *);
|
||||
void dispatch_SSL_shutdown(int, short, void *);
|
||||
void dispatch_force_tls_reconnect(int, short, void *);
|
||||
|
||||
bool tls_connect(struct tls_conn_settings *);
|
||||
void tls_reconnect(int, short, void *);
|
||||
bool tls_send(struct filed *, char *, size_t, struct buf_queue*);
|
||||
void tls_split_messages(struct TLS_Incoming_Conn *);
|
||||
|
||||
void free_tls_conn(struct tls_conn_settings *);
|
||||
void free_tls_sslptr(struct tls_conn_settings *);
|
||||
void free_tls_send_msg(struct tls_send_msg *);
|
||||
|
||||
#endif /* !_TLS_H */
|
Loading…
Reference in New Issue
Block a user