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];
};