On Wed, 2022-01-26 at 09:18 -0700, Theo de Raadt wrote: > > However, as things stand interpretation can be broken with the base > > tools. I can't fix garbage input. > > Your proposal builds a mechanism which encourages making decisions based > upon parsing garbage input.
So let's just focus on my original diff and let that one stand on its own. Say I have a sender with the following line: sender$ tail -2 /etc/syslog.conf !doas *.* @100.64.2.2 and a receiver with: receiver$ tail -6 /etc/syslog.conf +100.64.2.3 !doas *.* /tmp/prog_doas !sender *.* /tmp/prog_sender receiver runs syslogd with -U100.64.2.2 When running syslogd on sender without any flags and doing a simple `doas ls`: receiver$ tail /tmp/prog_* ==> /tmp/prog_doas <== Jan 30 15:03:51 100.64.2.3 doas: martijn ran command ls as root from /home/martijn ==> /tmp/prog_sender <== receiver$ When running syslogd on sender with -h and doing a simple `doas ls`: receiver$ tail /tmp/prog_* ==> /tmp/prog_doas <== ==> /tmp/prog_sender <== Jan 30 15:08:08 100.64.2.3 sender doas: martijn ran command ls as root from /home/martijn receiver$ With my diff applied and without -h: receiver$ tail /tmp/prog_* ==> /tmp/prog_doas <== Jan 30 15:11:55 100.64.2.3 doas: martijn ran command ls as root from /home/martijn ==> /tmp/prog_sender <== receiver$ With my diff applied and with -h: receiver$ tail /tmp/prog_* ==> /tmp/prog_doas <== Jan 30 15:12:47 100.64.2.3 doas: martijn ran command ls as root from /home/martijn ==> /tmp/prog_sender <== receiver$ So no new mechanism is introduced, but I am trying to make sure that existing mechanisms work more consistent with what we already offer out of the box in base. martijn@ Index: parsemsg.c =================================================================== RCS file: /cvs/src/usr.sbin/syslogd/parsemsg.c,v retrieving revision 1.1 diff -u -p -r1.1 parsemsg.c --- parsemsg.c 13 Jan 2022 10:34:07 -0000 1.1 +++ parsemsg.c 30 Jan 2022 14:20:36 -0000 @@ -17,8 +17,14 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <sys/socket.h> + +#include <arpa/inet.h> +#include <netinet/in.h> + #include <ctype.h> #include <limits.h> +#include <resolv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -29,27 +35,42 @@ size_t parsemsg_timestamp_bsd(const char *, char *); size_t parsemsg_timestamp_v1(const char *, char *); +size_t parsemsg_hostname(const char *, char *); size_t parsemsg_prog(const char *, char *); struct msg * parsemsg(const char *msgstr, struct msg *msg) { - size_t n; + size_t timelen, proglen; + const char *hostname; msg->m_pri = -1; msgstr += parsemsg_priority(msgstr, &msg->m_pri); if (msg->m_pri &~ (LOG_FACMASK|LOG_PRIMASK)) msg->m_pri = -1; - if ((n = parsemsg_timestamp_bsd(msgstr, msg->m_timestamp)) == 0) - n = parsemsg_timestamp_v1(msgstr, msg->m_timestamp); - msgstr += n; + if ((timelen = parsemsg_timestamp_bsd(msgstr, msg->m_timestamp)) == 0) + timelen = parsemsg_timestamp_v1(msgstr, msg->m_timestamp); + msgstr += timelen; - while (isspace(msgstr[0])) + while (isspace((unsigned char)msgstr[0])) msgstr++; - parsemsg_prog(msgstr, msg->m_prog); + hostname = msgstr; + msgstr += parsemsg_hostname(msgstr, msg->m_hostname); + + while (isspace((unsigned char)msgstr[0])) + msgstr++; + proglen = parsemsg_prog(msgstr, msg->m_prog); + + /* + * Without timestamp and tag, assume hostname as part of message. + */ + if (!timelen && !proglen) { + msg->m_hostname[0] = '\0'; + msgstr = hostname; + } strlcpy(msg->m_msg, msgstr, sizeof(msg->m_msg)); return msg; @@ -169,6 +190,47 @@ parsemsg_timestamp_v1(const char *msgstr return msg - msgstr; } +/* + * Parse the ip address or hostname according to inet_pton and res_hnok and + * return the length of the hostname including the trailing space if available. + */ +size_t +parsemsg_hostname(const char *msgstr, char *hostname) +{ + size_t len; + struct in_addr buf4; + struct in6_addr buf6; + + if (msgstr[0] == '-' && (msgstr[1] == ' ' || msgstr[1] == '\0')) { + hostname[0] = '\0'; + if (msgstr[1] == '\0') + return 1; + return 2; + } + + if ((len = strcspn(msgstr, " ")) > HOST_NAME_MAX) + return 0; + strlcpy(hostname, msgstr, len + 1); + if (msgstr[len] == ' ') + len++; + + if (inet_pton(AF_INET, hostname, &buf4) == 1 || + inet_pton(AF_INET6, hostname, &buf6) == 1) { + return len; + } + + if (res_hnok(hostname) == 0) { + hostname[0] = '\0'; + return 0; + } + return len; +} + +/* + * Parse a program name of the form [[:alnum:]-._]{1,255} + * and which ends in [:[]. + * It return the length of the tag up to the closing symbol. + */ size_t parsemsg_prog(const char *msg, char *prog) { @@ -179,6 +241,10 @@ parsemsg_prog(const char *msg, char *pro msg[i] != '-' && msg[i] != '.' && msg[i] != '_') break; prog[i] = msg[i]; + } + if (msg[i] != ':' && msg[i] != '[') { + prog[0] = '\0'; + return 0; } prog[i] = '\0'; Index: parsemsg.h =================================================================== RCS file: /cvs/src/usr.sbin/syslogd/parsemsg.h,v retrieving revision 1.1 diff -u -p -r1.1 parsemsg.h --- parsemsg.h 13 Jan 2022 10:34:07 -0000 1.1 +++ parsemsg.h 30 Jan 2022 14:20:36 -0000 @@ -25,6 +25,7 @@ struct msg { int m_pri; char m_timestamp[33]; + char m_hostname[HOST_NAME_MAX + 1]; char m_prog[NAME_MAX + 1]; char m_msg[LOG_MAXLINE + 1]; };