From ee2d0ce1067a3fe6a2b66375d9a12d36c32167c6 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Tue, 29 Oct 2019 09:01:01 +0100 Subject: [PATCH] Sync with FreeBSD syslogd to get full RFC5424 support This massive patch brings support for parsing incoming syslog messages, remote or local, to determine if format is RFC5424 or the older RFC3164. For logging syslogd currently defaults to RFC3164 for local files and supports RFC5424 for sending to remote servers. Signed-off-by: Joachim Nilsson --- src/syslog.h | 37 +- src/syslogd.c | 1070 +++++++++++++++++++++++++++++++------------------ src/syslogd.h | 118 ++++++ 3 files changed, 826 insertions(+), 399 deletions(-) create mode 100644 src/syslogd.h diff --git a/src/syslog.h b/src/syslog.h index 9f1051d..5496486 100644 --- a/src/syslog.h +++ b/src/syslog.h @@ -34,10 +34,28 @@ #ifndef _SYS_SYSLOG_H_ /* From NetBSD, for co-existance with C-library header */ #define _SYS_SYSLOG_H_ +#include "config.h" + #include #include -#define _PATH_LOG "/var/run/log" +/* + * Default on *BSD is /var/run/log, but on Linux systems with + * systemd/journald this is reserved and may already exist as + * a directory. For compatibility with GLIBC syslog API, for + * those who opt not to use this replacement API, we use the + * default/traditional Linux path /dev/log. In case we're in + * unit TESTING mode we usr /tmp/log.sock + */ +#ifndef TESTING +# ifndef __linux__ +# define _PATH_LOG "/var/run/log" +# else +# define _PATH_LOG "/dev/log" +# endif +#else +# define _PATH_LOG "/tmp/log.sock" +#endif /* * priorities/facilities are encoded into a single 32-bit quantity, where the @@ -161,14 +179,15 @@ CODE facilitynames[] = { * LOG_ODELAY no longer does anything. * LOG_NDELAY is the inverse of what it used to be. */ -#define LOG_PID 0x01 /* log the pid with each message */ -#define LOG_CONS 0x02 /* log on the console if errors in sending */ -#define LOG_ODELAY 0x04 /* delay open until first syslog() (default) */ -#define LOG_NDELAY 0x08 /* don't delay open */ -#define LOG_NOWAIT 0x10 /* don't wait for console forks: DEPRECATED */ -#define LOG_PERROR 0x20 /* log to stderr as well */ -#define LOG_PTRIM 0x40 /* trim tag and pid from messages to stderr */ -#define LOG_NLOG 0x80 /* don't write to the system log */ +#define LOG_PID 0x001 /* log the pid with each message */ +#define LOG_CONS 0x002 /* log on the console if errors in sending */ +#define LOG_ODELAY 0x004 /* delay open until first syslog() (default) */ +#define LOG_NDELAY 0x008 /* don't delay open */ +#define LOG_NOWAIT 0x010 /* don't wait for console forks: DEPRECATED */ +#define LOG_PERROR 0x020 /* log to stderr as well */ +#define LOG_PTRIM 0x040 /* trim tag and pid from messages to stderr */ +#define LOG_NLOG 0x080 /* don't write to the system log */ +#define LOG_STDOUT 0x100 /* like nlog, for debugging syslogp() API */ #ifndef __KERNEL__ diff --git a/src/syslogd.c b/src/syslogd.c index c05506d..be45165 100644 --- a/src/syslogd.c +++ b/src/syslogd.c @@ -57,6 +57,7 @@ static char sccsid[] __attribute__((unused)) = #define TIMERINTVL 30 /* interval for checking flush, mark */ #define RCVBUF_MINSIZE (80 * 1024) /* minimum size of dgram rcv buffer */ +#include #include #include #include @@ -95,7 +96,8 @@ static char sccsid[] __attribute__((unused)) = #endif #include "config.h" #include -#include "syslog.h" + +#include "syslogd.h" #include "compat.h" /* @@ -166,21 +168,6 @@ int funix[MAXFUNIX] = { -1, }; -#ifdef UT_NAMESIZE -#define UNAMESZ UT_NAMESIZE /* length of a login name */ -#else -#define UNAMESZ 8 /* length of a login name */ -#endif -#define MAXUNAMES 20 /* maximum number of user names */ -#define MAXFNAME 200 /* max file pathname length */ - -#define INTERNAL_NOPRI 0x10 /* the "no priority" priority */ -#define TABLE_NOPRI 0 /* Value to indicate no priority in f_pmask */ -#define TABLE_ALLPRI 0xFF /* Value to indicate all priorities in f_pmask */ -#define LOG_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0) /* mark "facility" */ - -#define MAX_PRI 191 /* Maximum Priority per RFC 3164 */ - /* * Flags to logmsg(). */ @@ -191,65 +178,12 @@ int funix[MAXFUNIX] = { #define MARK 0x008 /* this message is a mark */ #define RFC5424 0x010 /* format log message according to RFC 5424 */ -/* Timestamps of log entries. */ -struct logtime { - struct tm tm; - suseconds_t usec; -}; - - -/* - * This table contains plain text for h_errno errors used by the - * net subsystem. - */ -const char *sys_h_errlist[] = { - "No problem", /* NETDB_SUCCESS */ - "Authoritative answer: host not found", /* HOST_NOT_FOUND */ - "Non-authoritative answer: host not found, or serverfail", /* TRY_AGAIN */ - "Non recoverable errors", /* NO_RECOVERY */ - "Valid name, no data record of requested type", /* NO_DATA */ - "no address, look for MX record" /* NO_ADDRESS */ -}; - -/* - * This structure represents the files that will have log - * copies printed. - */ - -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 recd. */ - u_char f_pmask[LOG_NFACILITIES + 1]; /* priority mask */ - union { - char f_uname[MAXUNAMES][UNAMESZ + 1]; - struct { - char f_hname[MAXHOSTNAMELEN + 1]; - struct addrinfo *f_addr; - } f_forw; /* forwarding address */ - char f_fname[MAXFNAME]; - } f_un; - char f_prevline[MAXSVLINE]; /* last message logged */ - char f_lasttime[16]; /* time of last occurrence */ - char f_prevhost[MAXHOSTNAMELEN + 1]; /* host from which recd. */ - int f_prevpri; /* pri of f_prevline */ - int f_prevlen; /* length of f_prevline */ - int f_prevcount; /* repetition cnt of prevline */ - size_t f_repeatcount; /* number of "repeated" msgs */ - int f_flags; /* store some additional flags */ - int f_rotatecount; - int f_rotatesz; -}; - /* * Intervals at which we flush out "message repeated" messages, * in seconds after previous message is logged. After each flush, * we move to the next interval until we reach the largest. */ -int repeatinterval[] = { 30, 60 }; /* # of secs before flush */ +static int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) #define BACKOFF(f) \ @@ -344,11 +278,17 @@ int *finet = NULL; /* Internet datagram sockets */ int Initialized = 0; /* set when we have initialized ourselves */ int MarkInterval = 20 * 60; /* interval between marks in seconds */ int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */ -int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */ +static int mask_C1 = 1; /* mask characters from 0x80 - 0x9F */ +static int send_to_all; /* send message to all IPv4/IPv6 addresses */ int MarkSeq = 0; /* mark sequence number */ + +static int RemoteAddDate; /* Always set the date on remote messages */ +static int RemoteHostname; /* Log remote hostname from the message */ + +static int KeepKernFac; /* Keep remotely logged kernel facility */ + int LastAlarm = 0; /* last value passed to alarm() (seconds) */ int DupesPending = 0; /* Number of unflushed duplicate messages */ -int NoFork = 0; /* don't fork - don't run in daemon mode */ int AcceptRemote = 0; /* receive messages that come via UDP */ char **StripDomains = NULL; /* these domains may be stripped before writing logs */ char **LocalHosts = NULL; /* these hosts are logged with their hostname */ @@ -361,13 +301,12 @@ extern int errno; char **crunch_list(char *list); int usage(int code); void untty(void); -void printchopped(const char *hname, char *msg, size_t len, int fd); -void printline(const char *hname, char *msg); +static void parsemsg(const char *from, char *msg); void printsys(char *msg); -void logmsg(int pri, char *msg, const char *from, int flags); -void fprintlog(struct filed *f, char *from, int flags, char *msg); +static void logmsg(struct buf_msg *buffer); +static void fprintlog(struct filed *f, struct buf_msg *buffer); void endtty(); -void wallmsg(struct filed *f, struct iovec *iov); +void wallmsg(struct filed *f, struct iovec *iov, int iovcnt); void reapchild(); const char *cvtaddr(struct sockaddr_storage *f, int len); const char *cvthname(struct sockaddr_storage *f, int len); @@ -409,7 +348,7 @@ int main(int argc, char *argv[]) funix[i] = -1; } - while ((ch = getopt(argc, argv, "46Aa:dhf:l:m:np:R:rs:v?")) != EOF) { + while ((ch = getopt(argc, argv, "46Aa:dhHf:l:m:np:R:rs:v?")) != EOF) { switch ((char)ch) { case '4': family = PF_INET; @@ -438,6 +377,10 @@ int main(int argc, char *argv[]) ConfFile = optarg; break; + case 'H': + RemoteHostname = 1; + break; + case 'h': NoHops = 0; break; @@ -697,7 +640,7 @@ int main(int argc, char *argv[]) msglen = recv(fd, line, MAXLINE - 2, 0); logit("Message from UNIX socket: #%d\n", fd); if (msglen > 0) - printchopped(LocalHostName, line, msglen + 2, fd); + parsemsg(LocalHostName, line); else if (msglen < 0 && errno != EINTR) { logit("UNIX socket error: %d = %s.\n", errno, strerror(errno)); @@ -725,8 +668,7 @@ int main(int argc, char *argv[]) we shouldn't attempt to log the line -- jch */ from = cvthname(&frominet, len); if (from) - printchopped(from, line, - msglen + 2, finet[i + 1]); + parsemsg(from, line); } else if (msglen < 0 && errno != EINTR && errno != EAGAIN) { logit("INET socket error: %d = %s.\n", errno, strerror(errno)); @@ -745,8 +687,9 @@ int main(int argc, char *argv[]) line[0] = '.'; parts[fileno(stdin)] = NULL; i = read(fileno(stdin), line, MAXLINE); + logit("Message len: %d line: '%s'\n", i, line); if (i > 0) { - printchopped(LocalHostName, line, i + 1, fileno(stdin)); + parsemsg(LocalHostName, line); } else if (i < 0) { if (errno != EINTR) logerror("stdin"); @@ -886,6 +829,7 @@ static int *create_inet_sockets(void) continue; } + logit("Created inet socket %d ...\n", *s); increase_rcvbuf(*s); /* We must not block on the network socket, in case a packet @@ -988,114 +932,411 @@ void untty(void) } /* - * Parse the line to make sure that the msg is not a composite of more - * than one message. + * Removes characters from log messages that are unsafe to display. + * TODO: Permit UTF-8 strings that include a BOM per RFC 5424? */ -void printchopped(const char *hname, char *msg, size_t len, int fd) +static void +parsemsg_remove_unsafe_characters(const char *in, char *out, size_t outlen) { - char tmpline[MAXLINE + 1]; - char *start = msg; - char *p, *end; - int ptlngth; + char *q; + int c; - logit("Message length: %d, File descriptor: %d.\n", len, fd); - tmpline[0] = '\0'; - if (parts[fd] != NULL) { - logit("Including part from messages.\n"); - strcpy(tmpline, parts[fd]); - free(parts[fd]); - parts[fd] = NULL; - if ((strlen(msg) + strlen(tmpline)) > MAXLINE) { - logerror("Cannot glue message parts together"); - printline(hname, tmpline); - start = msg; + q = out; + while ((c = (unsigned char)*in++) != '\0' && q < out + outlen - 4) { + if (mask_C1 && (c & 0x80) && c < 0xA0) { + c &= 0x7F; + *q++ = 'M'; + *q++ = '-'; + } + if (isascii(c) && iscntrl(c)) { + if (c == '\n') { + *q++ = ' '; + } else if (c == '\t') { + *q++ = '\t'; + } else { + *q++ = '^'; + *q++ = c ^ 0100; + } } else { - logit("Previous: %s\n", tmpline); - logit("Next: %s\n", msg); - strcat(tmpline, msg); /* length checked above */ - printline(hname, tmpline); - if ((strlen(msg) + 1) == len) - return; - - start = strchr(msg, '\0') + 1; + *q++ = c; } } - - if (msg[len - 1] != '\0') { - msg[len] = '\0'; - for (p = msg + len - 1; *p != '\0' && p > msg;) - --p; - if (*p == '\0') - p++; - ptlngth = strlen(p); - if ((parts[fd] = malloc(ptlngth + 1)) == NULL) - logerror("Cannot allocate memory for message part."); - else { - strcpy(parts[fd], p); - logit("Saving partial msg: %s\n", parts[fd]); - memset(p, 0, ptlngth); - } - } - - do { - end = strchr(start + 1, '\0'); - printline(hname, start); - start = end + 1; - } while (*start != '\0'); + *q = '\0'; } /* - * Take a raw input line, decode the message, and print the message - * on the appropriate log files. + * Parses a syslog message according to RFC 5424, assuming that PRI and + * VERSION (i.e., "<%d>1 ") have already been parsed by parsemsg(). The + * parsed result is passed to logmsg(). */ -void printline(const char *hname, char *msg) +static void +parsemsg_rfc5424(const char *from, int pri, char *msg) { - unsigned char c; - unsigned int pri; /* Valid Priority values are 0-191 */ - char *p, *q; + const struct logtime *timestamp = NULL; + struct logtime timestamp_remote; + struct buf_msg buffer; + const char *omsg; char line[MAXLINE + 1]; - int prilen = 0; /* Track Priority value string len */ - int msglen; - /* test for special codes */ + memset(&buffer, 0, sizeof(buffer)); + buffer.recvhost = (char *)from; + buffer.pri = pri; + buffer.msg = line; + +#define FAIL_IF(field, expr) do { \ + if (expr) { \ + logit("Failed to parse " field " from %s: %s\n", \ + from, omsg); \ + return; \ + } \ +} while (0) +#define PARSE_CHAR(field, sep) do { \ + FAIL_IF(field, *msg != sep); \ + ++msg; \ +} while (0) +#define IF_NOT_NILVALUE(var) \ + if (msg[0] == '-' && msg[1] == ' ') { \ + msg += 2; \ + var = NULL; \ + } else if (msg[0] == '-' && msg[1] == '\0') { \ + ++msg; \ + var = NULL; \ + } else + + omsg = msg; + IF_NOT_NILVALUE(timestamp) { + /* Parse RFC 3339-like timestamp. */ +#define PARSE_NUMBER(dest, length, min, max) do { \ + int i, v; \ + \ + v = 0; \ + for (i = 0; i < length; ++i) { \ + FAIL_IF("TIMESTAMP", *msg < '0' || *msg > '9'); \ + v = v * 10 + *msg++ - '0'; \ + } \ + FAIL_IF("TIMESTAMP", v < min || v > max); \ + dest = v; \ +} while (0) + /* Date and time. */ + memset(×tamp_remote, 0, sizeof(timestamp_remote)); + PARSE_NUMBER(timestamp_remote.tm.tm_year, 4, 0, 9999); + timestamp_remote.tm.tm_year -= 1900; + PARSE_CHAR("TIMESTAMP", '-'); + PARSE_NUMBER(timestamp_remote.tm.tm_mon, 2, 1, 12); + --timestamp_remote.tm.tm_mon; + PARSE_CHAR("TIMESTAMP", '-'); + PARSE_NUMBER(timestamp_remote.tm.tm_mday, 2, 1, 31); + PARSE_CHAR("TIMESTAMP", 'T'); + PARSE_NUMBER(timestamp_remote.tm.tm_hour, 2, 0, 23); + PARSE_CHAR("TIMESTAMP", ':'); + PARSE_NUMBER(timestamp_remote.tm.tm_min, 2, 0, 59); + PARSE_CHAR("TIMESTAMP", ':'); + PARSE_NUMBER(timestamp_remote.tm.tm_sec, 2, 0, 59); + /* Perform normalization. */ + timegm(×tamp_remote.tm); + /* Optional: fractional seconds. */ + if (msg[0] == '.' && msg[1] >= '0' && msg[1] <= '9') { + int i; + + ++msg; + for (i = 100000; i != 0; i /= 10) { + if (*msg < '0' || *msg > '9') + break; + timestamp_remote.usec += (*msg++ - '0') * i; + } + } + /* Timezone. */ + if (*msg == 'Z') { + /* UTC. */ + ++msg; + } else { + int sign, tz_hour, tz_min; + + /* Local time zone offset. */ + FAIL_IF("TIMESTAMP", *msg != '-' && *msg != '+'); + sign = *msg++ == '-' ? -1 : 1; + PARSE_NUMBER(tz_hour, 2, 0, 23); + PARSE_CHAR("TIMESTAMP", ':'); + PARSE_NUMBER(tz_min, 2, 0, 59); + timestamp_remote.tm.tm_gmtoff = + sign * (tz_hour * 3600 + tz_min * 60); + } +#undef PARSE_NUMBER + PARSE_CHAR("TIMESTAMP", ' '); + if (!RemoteAddDate) + timestamp = ×tamp_remote; + } + + if (timestamp) + buffer.timestamp = *timestamp; + + /* String fields part of the HEADER. */ +#define PARSE_STRING(field, var) \ + IF_NOT_NILVALUE(var) { \ + var = msg; \ + while (*msg >= '!' && *msg <= '~') \ + ++msg; \ + FAIL_IF(field, var == msg); \ + PARSE_CHAR(field, ' '); \ + msg[-1] = '\0'; \ + } + PARSE_STRING("HOSTNAME", buffer.hostname); + if (buffer.hostname == NULL || !RemoteHostname) + buffer.hostname = (char *)from; + PARSE_STRING("APP-NAME", buffer.app_name); + PARSE_STRING("PROCID", buffer.proc_id); + PARSE_STRING("MSGID", buffer.msgid); +#undef PARSE_STRING + + /* Structured data. */ +#define PARSE_SD_NAME() do { \ + const char *start; \ + \ + start = msg; \ + while (*msg >= '!' && *msg <= '~' && *msg != '=' && \ + *msg != ']' && *msg != '"') \ + ++msg; \ + FAIL_IF("STRUCTURED-NAME", start == msg); \ +} while (0) + IF_NOT_NILVALUE(buffer.sd) { + /* SD-ELEMENT. */ + while (*msg == '[') { + ++msg; + /* SD-ID. */ + PARSE_SD_NAME(); + /* SD-PARAM. */ + while (*msg == ' ') { + ++msg; + /* PARAM-NAME. */ + PARSE_SD_NAME(); + PARSE_CHAR("STRUCTURED-NAME", '='); + PARSE_CHAR("STRUCTURED-NAME", '"'); + while (*msg != '"') { + FAIL_IF("STRUCTURED-NAME", + *msg == '\0'); + if (*msg++ == '\\') { + FAIL_IF("STRUCTURED-NAME", + *msg == '\0'); + ++msg; + } + } + ++msg; + } + PARSE_CHAR("STRUCTURED-NAME", ']'); + } + PARSE_CHAR("STRUCTURED-NAME", ' '); + msg[-1] = '\0'; + } +#undef PARSE_SD_NAME + +#undef FAIL_IF +#undef PARSE_CHAR +#undef IF_NOT_NILVALUE + parsemsg_remove_unsafe_characters(msg, line, sizeof(line)); + buffer.msg = line; + + logmsg(&buffer); +} + +/* + * Trims the application name ("TAG" in RFC 3164 terminology) and + * process ID from a message if present. + */ +static void +parsemsg_rfc3164_app_name_procid(char **msg, char **app_name, char **procid) +{ + char *m, *app_name_begin, *procid_begin; + size_t app_name_length, procid_length; + + m = *msg; + + /* Application name. */ + app_name_begin = m; + app_name_length = strspn(m, + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "_-"); + if (app_name_length == 0) + goto bad; + m += app_name_length; + + /* Process identifier (optional). */ + if (*m == '[') { + procid_begin = ++m; + procid_length = strspn(m, "0123456789"); + if (procid_length == 0) + goto bad; + m += procid_length; + if (*m++ != ']') + goto bad; + } else { + procid_begin = NULL; + procid_length = 0; + } + + /* Separator. */ + if (m[0] != ':' || m[1] != ' ') + goto bad; + + /* Split strings from input. */ + app_name_begin[app_name_length] = '\0'; + if (procid_begin != 0) + procid_begin[procid_length] = '\0'; + + *msg = m + 2; + *app_name = app_name_begin; + *procid = procid_begin; + return; +bad: + *app_name = NULL; + *procid = NULL; +} + +/* + * Parses a syslog message according to RFC 3164, assuming that PRI + * (i.e., "<%d>") has already been parsed by parsemsg(). The parsed + * result is passed to logmsg(). + */ +static void +parsemsg_rfc3164(const char *from, int pri, char *msg) +{ + struct logtime timestamp_remote; + struct buf_msg buffer; + struct tm tm_parsed; + size_t i, msglen; + char line[MAXLINE + 1]; + + memset(&buffer, 0, sizeof(buffer)); + buffer.recvhost = (char *)from; + buffer.msg = line; + + /* Parse the timestamp provided by the remote side. */ + if (strptime(msg, RFC3164_DATEFMT, &tm_parsed) != + msg + RFC3164_DATELEN || msg[RFC3164_DATELEN] != ' ') { + logit("Failed to parse TIMESTAMP from %s: %s\n", from, msg); + return; + } + msg += RFC3164_DATELEN + 1; + + if (!RemoteAddDate) { + struct tm tm_now; + time_t t_now; + int year; + + /* + * As the timestamp does not contain the year number, + * daylight saving time information, nor a time zone, + * attempt to infer it. Due to clock skews, the + * timestamp may even be part of the next year. Use the + * last year for which the timestamp is at most one week + * in the future. + * + * This loop can only run for at most three iterations + * before terminating. + */ + t_now = time(NULL); + localtime_r(&t_now, &tm_now); + for (year = tm_now.tm_year + 1;; --year) { + assert(year >= tm_now.tm_year - 1); + timestamp_remote.tm = tm_parsed; + timestamp_remote.tm.tm_year = year; + timestamp_remote.tm.tm_isdst = -1; + timestamp_remote.usec = 0; + if (mktime(×tamp_remote.tm) < + t_now + 7 * 24 * 60 * 60) + break; + } + buffer.timestamp = timestamp_remote; + } + + /* + * A single space character MUST also follow the HOSTNAME field. + */ msglen = strlen(msg); - pri = DEFUPRI; - p = msg; - - if (*p == '<') { - pri = 0; - while (--msglen > 0 && isdigit((unsigned char)*++p) && - pri <= MAX_PRI) { - pri = 10 * pri + (*p - '0'); - prilen++; - } - if (*p == '>' && prilen) - ++p; - else { - pri = DEFUPRI; - p = msg; + for (i = 0; i < MIN(MAXHOSTNAMELEN, msglen); i++) { + if (msg[i] == ' ') { + if (RemoteHostname) { + msg[i] = '\0'; + buffer.hostname = msg; + } + msg += i + 1; + break; } + /* + * Support non RFC compliant messages, without hostname. + */ + if (msg[i] == ':') + break; } - if ((pri & ~(LOG_FACMASK | LOG_PRIMASK)) || (pri > MAX_PRI)) { + if (i == MIN(MAXHOSTNAMELEN, msglen)) { + logit("Invalid HOSTNAME from %s: %s\n", from, msg); + return; + } + + /* Remove the TAG, if present. */ + parsemsg_rfc3164_app_name_procid(&msg, &buffer.app_name, &buffer.proc_id); + parsemsg_remove_unsafe_characters(msg, line, sizeof(line)); + logmsg(&buffer); +} + +/* + * Takes a raw input line, extracts PRI and determines whether the + * message is formatted according to RFC 3164 or RFC 5424. Continues + * parsing of addition fields in the message according to those + * standards and prints the message on the appropriate log files. + */ +static void +parsemsg(const char *from, char *msg) +{ + char *q; + long n; + size_t i; + int pri; + + /* Parse PRI. */ + if (msg[0] != '<' || !isdigit(msg[1])) { + logit("Invalid PRI from %s\n", from); + return; + } + for (i = 2; i <= 4; i++) { + if (msg[i] == '>') + break; + if (!isdigit(msg[i])) { + logit("Invalid PRI header from %s\n", from); + return; + } + } + if (msg[i] != '>') { + logit("Invalid PRI header from %s\n", from); + return; + } + errno = 0; + n = strtol(msg + 1, &q, 10); + if (errno != 0 || *q != msg[i] || n < 0 || n >= INT_MAX) { + logit("Invalid PRI %ld from %s: %s\n", + n, from, strerror(errno)); + return; + } + pri = n; + if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) pri = DEFUPRI; - p = msg; - } - memset(line, 0, sizeof(line)); - q = line; - while ((c = *p++) && q < &line[sizeof(line) - 4]) { - if (c == '\n' || c == 127) - *q++ = ' '; - else if (c < 040) { - *q++ = '^'; - *q++ = c ^ 0100; - } else - *q++ = c; - } - *q = '\0'; + /* + * Don't allow users to log kernel messages. + * NOTE: since LOG_KERN == 0 this will also match + * messages with no facility specified. + */ + if ((pri & LOG_FACMASK) == LOG_KERN && !KeepKernFac) + pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); - logmsg(pri, line, hname, SYNC_FILE); + /* Parse VERSION. */ + msg += i + 1; + if (msg[0] == '1' && msg[1] == ' ') + parsemsg_rfc5424(from, pri, msg + 2); + else + parsemsg_rfc3164(from, pri, msg); } /* @@ -1103,36 +1344,38 @@ void printline(const char *hname, char *msg) */ void printsys(char *msg) { + struct buf_msg buffer; char line[MAXLINE + 1]; char *lp, *p, *q; - int c, pri, flags; + int c; - (void)snprintf(line, sizeof(line), "vmunix: "); - lp = line + strlen(line); + lp = line; for (p = msg; *p != '\0';) { - flags = ADDDATE; - pri = DEFSPRI; + memset(&buffer, 0, sizeof(buffer)); + buffer.app_name = "vmunix"; + buffer.pri = DEFSPRI; + buffer.msg = line; if (*p == '<') { - pri = 0; + buffer.pri = 0; while (isdigit(*++p)) - pri = 10 * pri + (*p - '0'); + buffer.pri = 10 * buffer.pri + (*p - '0'); if (*p == '>') ++p; } else { /* kernel printf's come out on console */ - flags |= IGN_CONS; + buffer.flags |= IGN_CONS; } - if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) - pri = DEFSPRI; + if (buffer.pri & ~(LOG_FACMASK | LOG_PRIMASK)) + buffer.pri = DEFSPRI; q = lp; - while (*p != '\0' && (c = *p++) != '\n' && - q < &line[MAXLINE]) + while (*p != '\0' && (c = *p++) != '\n' && q < &line[MAXLINE]) *q++ = c; *q = '\0'; - logmsg(pri, line, LocalHostName, flags); + + logmsg(&buffer); } } @@ -1157,47 +1400,49 @@ char *textpri(int pri) time_t now; /* - * Log a message to the appropriate log files, users, etc. based on - * the priority. + * Logs a message to the appropriate log files, users, etc. based on the + * priority. Log messages are always formatted according to RFC 3164, + * even if they were in RFC 5424 format originally, The MSGID and + * STRUCTURED-DATA fields are thus discarded for the time being. */ -void logmsg(int pri, char *msg, const char *from, int flags) +static void logmsg(struct buf_msg *buffer) { + struct logtime timestamp_now; + struct logtime zero = { 0 }; + struct timeval tv; struct filed *f; sigset_t mask; - char *timestamp; - int fac, prilev, msglen; + size_t savedlen; + char saved[MAXSVLINE]; + int fac, prilev; - logit("logmsg: %s, flags %x, from %s, msg %s\n", textpri(pri), flags, from, msg); + logit("logmsg: %s, flags %x, from %s, msg %s\n", textpri(buffer->pri), + buffer->flags, buffer->hostname, buffer->msg); sigemptyset(&mask); sigaddset(&mask, SIGHUP); sigaddset(&mask, SIGALRM); sigprocmask(SIG_BLOCK, &mask, NULL); - /* - * Check to see if msg looks non-standard. - * - * A message looks like - * Nov 17 11:42:33 CRON[ - * 01234567890123456 - * ^ ^ ^ ^ ^ - * - * Remote messages are not accompanied by a timestamp. - * Local messages are accompanied by a timestamp (program's timezone) - */ - msglen = strlen(msg); - if (!(msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || - msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')) { - msg += 16; - msglen -= 16; + (void)gettimeofday(&tv, NULL); + now = tv.tv_sec; + if (!memcmp(&buffer->timestamp, &zero, sizeof(zero))) { + localtime_r(&now, ×tamp_now.tm); + timestamp_now.usec = tv.tv_usec; + buffer->timestamp = timestamp_now; } - (void)time(&now); - timestamp = ctime(&now) + 4; - /* extract facility and priority level */ - fac = LOG_FAC(pri); - prilev = LOG_PRI(pri); + if (buffer->flags & MARK) + fac = LOG_NFACILITIES; + else + fac = LOG_FAC(buffer->pri); + + /* Check maximum facility number. */ + if (fac > LOG_NFACILITIES) + return; + + prilev = LOG_PRI(buffer->pri); /* log the message to the particular outputs */ if (!Initialized) { @@ -1206,7 +1451,7 @@ void logmsg(int pri, char *msg, const char *from, int flags) if (f->f_file >= 0) { untty(); - fprintlog(f, (char *)from, flags, msg); + fprintlog(f, buffer); (void)close(f->f_file); f->f_file = -1; } @@ -1215,26 +1460,40 @@ void logmsg(int pri, char *msg, const char *from, int flags) return; } + /* + * Store all of the fields of the message, except the timestamp, + * in a single string. This string is used to detect duplicate + * messages. + */ + assert(buffer->hostname != NULL); + assert(buffer->msg != NULL); + savedlen = snprintf(saved, sizeof(saved), + "%d %s %s %s %s %s %s", buffer->pri, buffer->hostname, + buffer->app_name == NULL ? "-" : buffer->app_name, + buffer->proc_id == NULL ? "-" : buffer->proc_id, + buffer->msgid == NULL ? "-" : buffer->msgid, + buffer->sd == NULL ? "-" : buffer->sd, buffer->msg); + for (f = Files; f; f = f->f_next) { /* skip messages that are incorrect priority */ if ((f->f_pmask[fac] == TABLE_NOPRI) || ((f->f_pmask[fac] & (1 << prilev)) == 0)) continue; - if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) + /* skip message to console if it has already been printed */ + if (f->f_type == F_CONSOLE && (buffer->flags & IGN_CONS)) continue; /* don't output marks to recently written files */ - if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) + if ((buffer->flags & MARK) && (now - f->f_time) < MarkInterval / 2) continue; /* * suppress duplicate lines to this file */ - if ((flags & MARK) == 0 && msglen == f->f_prevlen && - !strcmp(msg, f->f_prevline) && - !strcmp(from, f->f_prevhost)) { - (void)strncpy(f->f_lasttime, timestamp, 15); + if ((buffer->flags & MARK) == 0 && savedlen == f->f_prevlen && + !strcmp(saved, f->f_prevline)) { + f->f_lasttime = buffer->timestamp; f->f_prevcount++; logit("msg repeated %d times, %ld sec of %d.\n", f->f_prevcount, now - f->f_time, @@ -1259,13 +1518,13 @@ void logmsg(int pri, char *msg, const char *from, int flags) * in the future. */ if (now > REPEATTIME(f)) { - fprintlog(f, (char *)from, flags, (char *)NULL); + fprintlog(f, NULL); BACKOFF(f); } } else { /* new line, save it */ if (f->f_prevcount) { - fprintlog(f, (char *)from, 0, (char *)NULL); + fprintlog(f, NULL); if (--DupesPending == 0) { logit("unsetting duplicate message flush alarm\n"); @@ -1275,20 +1534,14 @@ void logmsg(int pri, char *msg, const char *from, int flags) alarm(LastAlarm); } } - f->f_prevpri = pri; + f->f_prevpri = buffer->pri; f->f_repeatcount = 0; - (void)strncpy(f->f_lasttime, timestamp, 15); - (void)strncpy(f->f_prevhost, from, + f->f_lasttime = buffer->timestamp; + (void)strncpy(f->f_prevhost, buffer->hostname, sizeof(f->f_prevhost)); - if (msglen < MAXSVLINE) { - f->f_prevlen = msglen; - (void)strcpy(f->f_prevline, msg); - fprintlog(f, (char *)from, flags, (char *)NULL); - } else { - f->f_prevline[0] = 0; - f->f_prevlen = 0; - fprintlog(f, (char *)from, flags, msg); - } + (void)strcpy(f->f_prevline, saved); + f->f_prevlen = savedlen; + fprintlog(f, buffer); } } @@ -1344,151 +1597,157 @@ void logrotate(struct filed *f) } } -/* - * Trims the application name ("TAG" in RFC 3164 terminology) and - * process ID from a message if present. - */ -static void -parsemsg_rfc3164_app_name_procid(char **msg, char **app_name, char **procid) +#define pushiov(iov, cnt, val) do { \ + iov[cnt].iov_base = val; \ + iov[cnt].iov_len = strlen(val); \ + cnt++; \ + } while (0); + +#define pushsp(iov, cnt) do { \ + iov[cnt].iov_base = " "; \ + iov[cnt].iov_len = 1; \ + cnt++; \ + } while (0); + +#define fmtlogit(bm) logit("%s(%d, 0x%02x, %s, %s, %s, %s, %s, %s)", __func__, \ + bm->pri, bm->flags, bm->hostname, bm->app_name, \ + bm->proc_id, bm->msgid, bm->sd, bm->msg) + +static int fmt3164(struct buf_msg *buffer, struct iovec *iov, size_t iovmax) { - char *m, *app_name_begin, *procid_begin; - size_t app_name_length, procid_length; + int i = 0; - m = *msg; + fmtlogit(buffer); + strftime(buffer->timebuf, sizeof(buffer->timebuf), RFC3164_DATEFMT, + &buffer->timestamp.tm); - /* Application name. */ - app_name_begin = m; - app_name_length = strspn(m, - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789" - "_-/"); - if (app_name_length == 0) - goto bad; - m += app_name_length; + snprintf(buffer->pribuf, sizeof(buffer->pribuf), "<%d>", buffer->pri); + pushiov(iov, i, buffer->pribuf); + pushsp(iov, i); - /* Process identifier (optional). */ - if (*m == '[') { - procid_begin = ++m; - procid_length = strspn(m, "0123456789"); - if (procid_length == 0) - goto bad; - m += procid_length; - if (*m++ != ']') - goto bad; - } else { - procid_begin = NULL; - procid_length = 0; + pushiov(iov, i, buffer->timebuf); + pushsp(iov, i); + + pushiov(iov, i, buffer->hostname ? buffer->hostname : buffer->recvhost); + pushsp(iov, i); + + if (buffer->app_name) { + pushiov(iov, i, buffer->app_name); + if (buffer->proc_id) { + pushiov(iov, i, "["); + pushiov(iov, i, buffer->proc_id); + pushiov(iov, i, "]:"); + } + pushsp(iov, i); } - /* Separator. */ - if (m[0] != ':' || m[1] != ' ') - goto bad; + pushiov(iov, i, buffer->msg); - /* Split strings from input. */ - app_name_begin[app_name_length] = '\0'; - if (procid_begin != 0) - procid_begin[procid_length] = '\0'; - - *msg = m + 2; - *app_name = app_name_begin; - *procid = procid_begin; - return; -bad: - *app_name = NULL; - *procid = NULL; + return i; } -/* - * Currently unsupported RFC 5424 fields: msgid, structured_data - */ -static void fmt5424(char *line, size_t len, int pri, char *msg) +static int fmt5424(struct buf_msg *buffer, struct iovec *iov, size_t iovmax) { - struct logtime *timestamp = NULL; - struct logtime timestamp_now; - struct timeval tv; suseconds_t usec; - char *structured_data = NULL; - char *app_name = NULL; - char *procid = NULL; - char *msgid = NULL; - char hostname[256]; - char timebuf[33]; + int i = 0; - parsemsg_rfc3164_app_name_procid(&msg, &app_name, &procid); - - gethostname(hostname, sizeof(hostname)); - - (void)gettimeofday(&tv, NULL); - now = tv.tv_sec; - - if (timestamp == NULL) { - localtime_r(&now, ×tamp_now.tm); - timestamp_now.usec = tv.tv_usec; - timestamp = ×tamp_now; - } - - strftime(timebuf, sizeof(timebuf), "%FT%T.______%z", ×tamp->tm); + fmtlogit(buffer); + strftime(buffer->timebuf, sizeof(buffer->timebuf), "%FT%T.______%z", + &buffer->timestamp.tm); /* Add colon to the time zone offset, which %z doesn't do */ - timebuf[32] = '\0'; - timebuf[31] = timebuf[30]; - timebuf[30] = timebuf[29]; - timebuf[29] = ':'; + buffer->timebuf[32] = '\0'; + buffer->timebuf[31] = buffer->timebuf[30]; + buffer->timebuf[30] = buffer->timebuf[29]; + buffer->timebuf[29] = ':'; /* Overwrite space for microseconds with actual value */ - usec = timestamp->usec; + usec = buffer->timestamp.usec; for (int i = 25; i >= 20; --i) { - timebuf[i] = usec % 10 + '0'; + buffer->timebuf[i] = usec % 10 + '0'; usec /= 10; } - snprintf(line, len, "<%d>1 %s %s %s %s %s %s %s", - pri, timebuf, hostname, - app_name == NULL ? "-" : app_name, - procid == NULL ? "-" : procid, - msgid == NULL ? "-" : msgid, - structured_data == NULL ? "-" : structured_data, - msg); + /* RFC 5424 defines itself as v1 */ + snprintf(buffer->pribuf, sizeof(buffer->pribuf), "<%d>1", buffer->pri); + pushiov(iov, i, buffer->pribuf); + pushsp(iov, i); + + pushiov(iov, i, buffer->timebuf); + pushsp(iov, i); + + pushiov(iov, i, buffer->hostname ? buffer->hostname : buffer->recvhost); + pushsp(iov, i); + + pushiov(iov, i, buffer->app_name ? buffer->app_name : "-"); + pushsp(iov, i); + + pushiov(iov, i, buffer->proc_id ? buffer->proc_id : "-"); + pushsp(iov, i); + + pushiov(iov, i, buffer->msgid ? buffer->msgid : "-"); + pushsp(iov, i); + + pushiov(iov, i, buffer->sd ? buffer->sd : "-"); + pushsp(iov, i); + + pushiov(iov, i, buffer->msg); + + return i; } -void fprintlog(struct filed *f, char *from, int flags, char *msg) +void fprintlog(struct filed *f, struct buf_msg *buffer) { - struct iovec iov[6]; - struct iovec *v = iov; - char repbuf[80]; struct addrinfo hints, *ai; + struct buf_msg repeat; + struct logtime zero = { 0 }; + struct iovec iov[20]; time_t fwd_suspend; + char repbuf[80]; char line[MAXLINE + 1]; - int l, err; + int iovhead = 1; + int iovcnt = iovhead; /* One to spare at head for remote */ + int err; logit("Called fprintlog, "); + if (!buffer) { + memset(&repeat, 0, sizeof(repeat)); + repeat.hostname = f->f_prevhost; + repeat.pri = f->f_prevpri; + repeat.timestamp = f->f_lasttime; + if (f->f_prevcount > 1) { + snprintf(repbuf, sizeof(repbuf), + "last message repeated %d times", + f->f_prevcount); + repeat.msg = repbuf; + } else { + strlcpy(line, f->f_prevline, sizeof(line)); + repeat.msg = line; + } - v->iov_base = f->f_lasttime; - v->iov_len = 15; - v++; - v->iov_base = " "; - v->iov_len = 1; - v++; - v->iov_base = f->f_prevhost; - v->iov_len = strlen(v->iov_base); - v++; - v->iov_base = " "; - v->iov_len = 1; - v++; - if (msg) { - v->iov_base = msg; - v->iov_len = strlen(msg); - } else if (f->f_prevcount > 1) { - (void)snprintf(repbuf, sizeof(repbuf), "last message repeated %d times", - f->f_prevcount); - v->iov_base = repbuf; - v->iov_len = strlen(repbuf); - } else { - v->iov_base = f->f_prevline; - v->iov_len = f->f_prevlen; + buffer = &repeat; } - v++; + + if (!memcmp(&buffer->timestamp, &zero, sizeof(zero))) { + struct logtime timestamp_now; + struct timeval tv; + + (void)gettimeofday(&tv, NULL); + now = tv.tv_sec; + + localtime_r(&now, ×tamp_now.tm); + timestamp_now.usec = tv.tv_usec; + buffer->timestamp = timestamp_now; + } + + if (f->f_flags & RFC5424) + iovcnt = fmt5424(buffer, iov, NELEMS(iov)); + else + iovcnt = fmt3164(buffer, iov, NELEMS(iov)); + + /* Save actual message for future repeats */ +// if (iovcnt > 0) +// strlcpy(f->f_prevline, iov[iovcnt - 1].iov_base, sizeof(f->f_prevline)); logit("logging to %s", TypeNames[f->f_type]); @@ -1558,27 +1817,41 @@ void fprintlog(struct filed *f, char *from, int flags, char *msg) */ f_forw: logit(" %s\n", f->f_un.f_forw.f_hname); - if (strcmp(from, LocalHostName) && NoHops) + if (strcmp(buffer->hostname, LocalHostName) && NoHops) logit("Not sending message to remote.\n"); else if (finet) { - int i; + struct msghdr msg; + ssize_t len = 0; + f->f_time = now; - if (f->f_flags & RFC5424) - fmt5424(line, sizeof(line), f->f_prevpri, - (char *)iov[4].iov_base); - else - snprintf(line, sizeof(line), "<%d>%s", f->f_prevpri, - (char *)iov[4].iov_base); - l = strlen(line); - if (l > MAXLINE) - l = MAXLINE; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = iov; + msg.msg_iovlen = iovcnt; + + for (int i = 0; i < iovcnt; i++) { + logit("iov[%d] => %s\n", i, iov[i].iov_base); + len += iov[i].iov_len; + } + err = -1; for (ai = f->f_un.f_forw.f_addr; ai; ai = ai->ai_next) { - for (i = 0; i < *finet; i++) { - int lsent; - lsent = sendto(finet[i + 1], line, l, 0, - ai->ai_addr, ai->ai_addrlen); - if (lsent == l) { + for (int i = 0; i < *finet; i++) { + struct sockaddr_in *sin; + char buf[64] = { 0 }; + ssize_t lsent; + + msg.msg_name = ai->ai_addr; + msg.msg_namelen = ai->ai_addrlen; + lsent = sendmsg(finet[i + 1], &msg, 0); + + if (AF_INET == ai->ai_family) { + sin = (struct sockaddr_in *)ai->ai_addr; + inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)); + } + logit("Sent %d bytes to remote %s on socket %d ...\n", + lsent, buf, finet[i + 1]); + if (lsent == len) { err = -1; break; } @@ -1599,7 +1872,7 @@ void fprintlog(struct filed *f, char *from, int flags, char *msg) case F_CONSOLE: f->f_time = now; - if (flags & IGN_CONS) { + if (buffer->flags & IGN_CONS) { logit(" (ignored).\n"); break; } @@ -1611,11 +1884,9 @@ void fprintlog(struct filed *f, char *from, int flags, char *msg) f->f_time = now; logit(" %s\n", f->f_un.f_fname); if (f->f_type == F_TTY || f->f_type == F_CONSOLE) { - v->iov_base = "\r\n"; - v->iov_len = 2; + pushiov(iov, iovcnt, "\r\n"); } else { - v->iov_base = "\n"; - v->iov_len = 1; + pushiov(iov, iovcnt, "\n"); } again: /* f->f_file == -1 is an indicator that we couldn't @@ -1626,7 +1897,7 @@ void fprintlog(struct filed *f, char *from, int flags, char *msg) if (f->f_type == F_FILE) logrotate(f); - if (writev(f->f_file, iov, 6) < 0) { + if (writev(f->f_file, &iov[2], iovcnt - 2) < 0) { int e = errno; /* If a named pipe is full, just ignore it for now */ @@ -1672,9 +1943,8 @@ void fprintlog(struct filed *f, char *from, int flags, char *msg) case F_WALL: f->f_time = now; logit("\n"); - v->iov_base = "\r\n"; - v->iov_len = 2; - wallmsg(f, iov); + pushiov(iov, iovcnt, "\r\n"); + wallmsg(f, &iov[2], iovcnt - 2); break; } /* switch */ @@ -1695,7 +1965,7 @@ void endtty(int signo) * Write the specified message to either the entire * world, or a list of approved users. */ -void wallmsg(struct filed *f, struct iovec *iov) +void wallmsg(struct filed *f, struct iovec *iov, int iovcnt) { static int reenter = 0; struct utmp *uptr; @@ -1770,7 +2040,7 @@ void wallmsg(struct filed *f, struct iovec *iov) if (fstat(ttyf, &statb) == 0 && (statb.st_mode & S_IWRITE)) - (void)writev(ttyf, iov, 6); + (void)writev(ttyf, iov, iovcnt); close(ttyf); ttyf = -1; } @@ -1874,6 +2144,34 @@ const char *cvthname(struct sockaddr_storage *f, int len) return hname; } +/* + * Base function for domark(), logerror(), etc. + */ +static void flog(int pri, char *fmt, ...) +{ + struct buf_msg buffer; + va_list ap; + char proc_id[10]; + char buf[BUFSIZ]; + + va_start(ap, fmt); + (void)vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + (void)snprintf(proc_id, sizeof(proc_id), "%d", getpid()); + + memset(&buffer, 0, sizeof(buffer)); + buffer.hostname = LocalHostName; + buffer.app_name = "syslogd"; + buffer.proc_id = proc_id; + buffer.pri = pri; + buffer.msg = buf; + if (pri & LOG_MARK) + buffer.flags = MARK; + + logmsg(&buffer); +} + void domark(int signo) { struct filed *f; @@ -1882,7 +2180,7 @@ void domark(int signo) now = time(0); MarkSeq += LastAlarm; if (MarkSeq >= MarkInterval) { - logmsg(LOG_MARK | LOG_INFO, "-- MARK --", LocalHostName, ADDDATE | MARK); + flog(LOG_MARK | LOG_INFO, "-- MARK --"); MarkSeq -= MarkInterval; } } @@ -1892,7 +2190,7 @@ void domark(int signo) logit("flush %s: repeated %d times, %d sec.\n", TypeNames[f->f_type], f->f_prevcount, repeatinterval[f->f_repeatcount]); - fprintlog(f, LocalHostName, 0, (char *)NULL); + fprintlog(f, NULL); BACKOFF(f); DupesPending--; } @@ -1917,22 +2215,17 @@ void debug_switch(int signo) */ void logerror(const char *type) { - char buf[100]; - logit("Called logerr, msg: %s\n", type); if (errno == 0) - (void)snprintf(buf, sizeof(buf), "syslogd: %s", type); + flog(LOG_SYSLOG | LOG_ERR, "%s", type); else - (void)snprintf(buf, sizeof(buf), "syslogd: %s: %s", type, strerror(errno)); - errno = 0; - logmsg(LOG_SYSLOG | LOG_ERR, buf, LocalHostName, ADDDATE); + flog(LOG_SYSLOG | LOG_ERR, "%s: %m", type); } void die(int signo) { struct filed *f; - char buf[100]; int lognum; int i; int was_initialized = Initialized; @@ -1944,15 +2237,13 @@ void die(int signo) f = &Files[lognum]; /* flush any pending output */ if (f->f_prevcount) - fprintlog(f, LocalHostName, 0, (char *)NULL); + fprintlog(f, NULL); } Initialized = was_initialized; if (signo) { logit("syslogd: exiting on signal %d\n", signo); - (void)snprintf(buf, sizeof(buf), "exiting on signal %d", signo); - errno = 0; - logmsg(LOG_SYSLOG | LOG_INFO, buf, LocalHostName, ADDDATE); + flog(LOG_SYSLOG | LOG_INFO, "exiting on signal %d", signo); } /* Close the UNIX sockets. */ @@ -2014,7 +2305,7 @@ void init(void) /* flush any pending output */ if (f->f_prevcount) - fprintlog(f, LocalHostName, 0, (char *)NULL); + fprintlog(f, NULL); switch (f->f_type) { case F_FILE: @@ -2225,10 +2516,9 @@ void init(void) } if (AcceptRemote) - logmsg(LOG_SYSLOG | LOG_INFO, "syslogd v" VERSION ": restart (remote reception).", LocalHostName, - ADDDATE); + flog(LOG_SYSLOG | LOG_INFO, "syslogd v" VERSION ": restart (remote reception)."); else - logmsg(LOG_SYSLOG | LOG_INFO, "syslogd v" VERSION ": restart.", LocalHostName, ADDDATE); + flog(LOG_SYSLOG | LOG_INFO, "syslogd v" VERSION ": restart."); (void)signal(SIGHUP, sighup_handler); logit("syslogd: restarted.\n"); diff --git a/src/syslogd.h b/src/syslogd.h new file mode 100644 index 0000000..9165387 --- /dev/null +++ b/src/syslogd.h @@ -0,0 +1,118 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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 SYSKLOGD_SYSLOGD_H_ +#define SYSKLOGD_SYSLOGD_H_ + +#include "syslog.h" + +#ifdef UT_NAMESIZE +#define UNAMESZ UT_NAMESIZE /* length of a login name */ +#else +#define UNAMESZ 8 /* length of a login name */ +#endif +#define MAXUNAMES 20 /* maximum number of user names */ +#define MAXFNAME 200 /* max file pathname length */ + +#define INTERNAL_NOPRI 0x10 /* the "no priority" priority */ +#define TABLE_NOPRI 0 /* Value to indicate no priority in f_pmask */ +#define TABLE_ALLPRI 0xFF /* Value to indicate all priorities in f_pmask */ +#define LOG_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0) /* mark "facility" */ + +#define MAX_PRI 191 /* Maximum Priority per RFC 3164 */ + +/* Traditional syslog timestamp format. */ +#define RFC3164_DATELEN 15 +#define RFC3164_DATEFMT "%b %e %H:%M:%S" + +/* From The Practice of Programming, by Kernighan and Pike */ +#ifndef NELEMS +#define NELEMS(array) (sizeof(array) / sizeof(array[0])) +#endif + +/* Timestamps of log entries. */ +struct logtime { + struct tm tm; + suseconds_t usec; +}; + +/* message buffer container used for processing, formatting, and queueing */ +struct buf_msg { + int pri; + char pribuf[7]; + int flags; + struct logtime timestamp; + char timebuf[33]; + char *recvhost; + char *hostname; + char *app_name; + char *proc_id; + char *msgid; + char *sd; /* structured data */ + char *msg; /* message content */ +}; + +/* + * 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 recd. */ + u_char f_pmask[LOG_NFACILITIES + 1]; /* priority mask */ + union { + char f_uname[MAXUNAMES][UNAMESZ + 1]; + struct { + char f_hname[MAXHOSTNAMELEN + 1]; + struct addrinfo *f_addr; + } f_forw; /* forwarding address */ + char f_fname[MAXFNAME]; + } f_un; + char f_prevline[MAXSVLINE]; /* last message logged */ + struct logtime f_lasttime; /* time of last occurrence */ + char f_prevhost[MAXHOSTNAMELEN + 1]; /* host from which recd. */ + int f_prevpri; /* pri of f_prevline */ + size_t f_prevlen; /* length of f_prevline */ + int f_prevcount; /* repetition cnt of prevline */ + size_t f_repeatcount; /* number of "repeated" msgs */ + int f_flags; /* store some additional flags */ + int f_rotatecount; + int f_rotatesz; +}; + +#endif /* SYSKLOGD_SYSLOGD_H_ */