xref: /openbsd/usr.sbin/syslogd/parsemsg.c (revision 2a99deb5)
1*2a99deb5Smartijn /*	$OpenBSD: parsemsg.c,v 1.1 2022/01/13 10:34:07 martijn Exp $	*/
2*2a99deb5Smartijn 
3*2a99deb5Smartijn /*
4*2a99deb5Smartijn  * Copyright (c) 2022 Martijn van Duren <martijn@openbsd>
5*2a99deb5Smartijn  * Copyright (c) 2014-2021 Alexander Bluhm <bluhm@genua.de>
6*2a99deb5Smartijn  *
7*2a99deb5Smartijn  * Permission to use, copy, modify, and distribute this software for any
8*2a99deb5Smartijn  * purpose with or without fee is hereby granted, provided that the above
9*2a99deb5Smartijn  * copyright notice and this permission notice appear in all copies.
10*2a99deb5Smartijn  *
11*2a99deb5Smartijn  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12*2a99deb5Smartijn  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13*2a99deb5Smartijn  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14*2a99deb5Smartijn  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15*2a99deb5Smartijn  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16*2a99deb5Smartijn  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17*2a99deb5Smartijn  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18*2a99deb5Smartijn  */
19*2a99deb5Smartijn 
20*2a99deb5Smartijn #include <ctype.h>
21*2a99deb5Smartijn #include <limits.h>
22*2a99deb5Smartijn #include <stdio.h>
23*2a99deb5Smartijn #include <stdlib.h>
24*2a99deb5Smartijn #include <string.h>
25*2a99deb5Smartijn #include <syslog.h>
26*2a99deb5Smartijn 
27*2a99deb5Smartijn #include "parsemsg.h"
28*2a99deb5Smartijn #include "syslogd.h"
29*2a99deb5Smartijn 
30*2a99deb5Smartijn size_t parsemsg_timestamp_bsd(const char *, char *);
31*2a99deb5Smartijn size_t parsemsg_timestamp_v1(const char *, char *);
32*2a99deb5Smartijn size_t parsemsg_prog(const char *, char *);
33*2a99deb5Smartijn 
34*2a99deb5Smartijn struct msg *
parsemsg(const char * msgstr,struct msg * msg)35*2a99deb5Smartijn parsemsg(const char *msgstr, struct msg *msg)
36*2a99deb5Smartijn {
37*2a99deb5Smartijn 	size_t n;
38*2a99deb5Smartijn 
39*2a99deb5Smartijn 	msg->m_pri = -1;
40*2a99deb5Smartijn 	msgstr += parsemsg_priority(msgstr, &msg->m_pri);
41*2a99deb5Smartijn 	if (msg->m_pri &~ (LOG_FACMASK|LOG_PRIMASK))
42*2a99deb5Smartijn 		msg->m_pri = -1;
43*2a99deb5Smartijn 
44*2a99deb5Smartijn 	if ((n = parsemsg_timestamp_bsd(msgstr, msg->m_timestamp)) == 0)
45*2a99deb5Smartijn 		n = parsemsg_timestamp_v1(msgstr, msg->m_timestamp);
46*2a99deb5Smartijn 	msgstr += n;
47*2a99deb5Smartijn 
48*2a99deb5Smartijn 	while (isspace(msgstr[0]))
49*2a99deb5Smartijn 		msgstr++;
50*2a99deb5Smartijn 
51*2a99deb5Smartijn 	parsemsg_prog(msgstr, msg->m_prog);
52*2a99deb5Smartijn 
53*2a99deb5Smartijn 	strlcpy(msg->m_msg, msgstr, sizeof(msg->m_msg));
54*2a99deb5Smartijn 
55*2a99deb5Smartijn 	return msg;
56*2a99deb5Smartijn }
57*2a99deb5Smartijn 
58*2a99deb5Smartijn /*
59*2a99deb5Smartijn  * Parse a priority code of the form "<123>" into pri, and return the
60*2a99deb5Smartijn  * length of the priority code including the surrounding angle brackets.
61*2a99deb5Smartijn  */
62*2a99deb5Smartijn size_t
parsemsg_priority(const char * msg,int * pri)63*2a99deb5Smartijn parsemsg_priority(const char *msg, int *pri)
64*2a99deb5Smartijn {
65*2a99deb5Smartijn 	size_t nlen;
66*2a99deb5Smartijn 	char buf[11];
67*2a99deb5Smartijn 	const char *errstr;
68*2a99deb5Smartijn 	int maybepri;
69*2a99deb5Smartijn 
70*2a99deb5Smartijn 	if (*msg++ == '<') {
71*2a99deb5Smartijn 		nlen = strspn(msg, "1234567890");
72*2a99deb5Smartijn 		if (nlen > 0 && nlen < sizeof(buf) && msg[nlen] == '>') {
73*2a99deb5Smartijn 			strlcpy(buf, msg, nlen + 1);
74*2a99deb5Smartijn 			maybepri = strtonum(buf, 0, INT_MAX, &errstr);
75*2a99deb5Smartijn 			if (errstr == NULL) {
76*2a99deb5Smartijn 				*pri = maybepri;
77*2a99deb5Smartijn 				return nlen + 2;
78*2a99deb5Smartijn 			}
79*2a99deb5Smartijn 		}
80*2a99deb5Smartijn 	}
81*2a99deb5Smartijn 
82*2a99deb5Smartijn 	return 0;
83*2a99deb5Smartijn }
84*2a99deb5Smartijn 
85*2a99deb5Smartijn size_t
parsemsg_timestamp_bsd(const char * msg,char * timestamp)86*2a99deb5Smartijn parsemsg_timestamp_bsd(const char *msg, char *timestamp)
87*2a99deb5Smartijn {
88*2a99deb5Smartijn 	size_t i;
89*2a99deb5Smartijn 
90*2a99deb5Smartijn 	timestamp[0] = '\0';
91*2a99deb5Smartijn 	for (i = 0; i < 16; i++) {
92*2a99deb5Smartijn 		if (msg[i] == '\0')
93*2a99deb5Smartijn 			return 0;
94*2a99deb5Smartijn 	}
95*2a99deb5Smartijn 
96*2a99deb5Smartijn 	if (msg[3] == ' ' && msg[6] == ' ' && msg[9] == ':' && msg[12] == ':' &&
97*2a99deb5Smartijn 	    msg[15] == ' ') {
98*2a99deb5Smartijn 		/* BSD syslog TIMESTAMP, RFC 3164 */
99*2a99deb5Smartijn 		if (!ZuluTime)
100*2a99deb5Smartijn 			strlcpy(timestamp, msg, 16);
101*2a99deb5Smartijn 		return 16;
102*2a99deb5Smartijn 	}
103*2a99deb5Smartijn 
104*2a99deb5Smartijn 	return 0;
105*2a99deb5Smartijn }
106*2a99deb5Smartijn 
107*2a99deb5Smartijn size_t
parsemsg_timestamp_v1(const char * msgstr,char * timestamp)108*2a99deb5Smartijn parsemsg_timestamp_v1(const char *msgstr, char *timestamp)
109*2a99deb5Smartijn {
110*2a99deb5Smartijn 	const char *msg;
111*2a99deb5Smartijn 	size_t msglen, i;
112*2a99deb5Smartijn 
113*2a99deb5Smartijn 	for (msglen = 0; msglen < 33; msglen++) {
114*2a99deb5Smartijn 		if(msgstr[msglen] == '\0')
115*2a99deb5Smartijn 			break;
116*2a99deb5Smartijn 	}
117*2a99deb5Smartijn 
118*2a99deb5Smartijn 	msg = msgstr;
119*2a99deb5Smartijn 	timestamp[0] = '\0';
120*2a99deb5Smartijn 
121*2a99deb5Smartijn 	if (msglen >= 20 &&
122*2a99deb5Smartijn 	    isdigit(msg[0]) && isdigit(msg[1]) && isdigit(msg[2]) &&
123*2a99deb5Smartijn 	    isdigit(msg[3]) && msg[4] == '-' &&
124*2a99deb5Smartijn 	    isdigit(msg[5]) && isdigit(msg[6]) && msg[7] == '-' &&
125*2a99deb5Smartijn 	    isdigit(msg[8]) && isdigit(msg[9]) && msg[10] == 'T' &&
126*2a99deb5Smartijn 	    isdigit(msg[11]) && isdigit(msg[12]) && msg[13] == ':' &&
127*2a99deb5Smartijn 	    isdigit(msg[14]) && isdigit(msg[15]) && msg[16] == ':' &&
128*2a99deb5Smartijn 	    isdigit(msg[17]) && isdigit(msg[18]) && (msg[19] == '.' ||
129*2a99deb5Smartijn 	    msg[19] == 'Z' || msg[19] == '+' || msg[19] == '-')) {
130*2a99deb5Smartijn 		/* FULL-DATE "T" FULL-TIME, RFC 5424 */
131*2a99deb5Smartijn 		strlcpy(timestamp, msg, 33);
132*2a99deb5Smartijn 		msg += 19;
133*2a99deb5Smartijn 		msglen -= 19;
134*2a99deb5Smartijn 		i = 0;
135*2a99deb5Smartijn 		if (msglen >= 3 && msg[0] == '.' && isdigit(msg[1])) {
136*2a99deb5Smartijn 			/* TIME-SECFRAC */
137*2a99deb5Smartijn 			msg += 2;
138*2a99deb5Smartijn 			msglen -= 2;
139*2a99deb5Smartijn 			i += 2;
140*2a99deb5Smartijn 			while(i < 7 && msglen >= 1 && isdigit(msg[0])) {
141*2a99deb5Smartijn 				msg++;
142*2a99deb5Smartijn 				msglen--;
143*2a99deb5Smartijn 				i++;
144*2a99deb5Smartijn 			}
145*2a99deb5Smartijn 		}
146*2a99deb5Smartijn 		if (msglen >= 2 && msg[0] == 'Z' && msg[1] == ' ') {
147*2a99deb5Smartijn 			/* "Z" */
148*2a99deb5Smartijn 			timestamp[20+i] = '\0';
149*2a99deb5Smartijn 			msg += 2;
150*2a99deb5Smartijn 		} else if (msglen >= 7 &&
151*2a99deb5Smartijn 		    (msg[0] == '+' || msg[0] == '-') &&
152*2a99deb5Smartijn 		    isdigit(msg[1]) && isdigit(msg[2]) &&
153*2a99deb5Smartijn 		    msg[3] == ':' &&
154*2a99deb5Smartijn 		    isdigit(msg[4]) && isdigit(msg[5]) &&
155*2a99deb5Smartijn 		    msg[6] == ' ') {
156*2a99deb5Smartijn 			/* TIME-NUMOFFSET */
157*2a99deb5Smartijn 			timestamp[25+i] = '\0';
158*2a99deb5Smartijn 			msg += 7;
159*2a99deb5Smartijn 		} else {
160*2a99deb5Smartijn 			/* invalid time format, roll back */
161*2a99deb5Smartijn 			timestamp[0] = '\0';
162*2a99deb5Smartijn 			return 0;
163*2a99deb5Smartijn 		}
164*2a99deb5Smartijn 	} else if (msglen >= 2 && msg[0] == '-' && msg[1] == ' ') {
165*2a99deb5Smartijn 		/* NILVALUE, RFC 5424 */
166*2a99deb5Smartijn 		msg += 2;
167*2a99deb5Smartijn 	}
168*2a99deb5Smartijn 
169*2a99deb5Smartijn 	return msg - msgstr;
170*2a99deb5Smartijn }
171*2a99deb5Smartijn 
172*2a99deb5Smartijn size_t
parsemsg_prog(const char * msg,char * prog)173*2a99deb5Smartijn parsemsg_prog(const char *msg, char *prog)
174*2a99deb5Smartijn {
175*2a99deb5Smartijn 	size_t i;
176*2a99deb5Smartijn 
177*2a99deb5Smartijn 	for (i = 0; i < NAME_MAX; i++) {
178*2a99deb5Smartijn 		if (!isalnum((unsigned char)msg[i]) &&
179*2a99deb5Smartijn 		    msg[i] != '-' && msg[i] != '.' && msg[i] != '_')
180*2a99deb5Smartijn 			break;
181*2a99deb5Smartijn 		prog[i] = msg[i];
182*2a99deb5Smartijn 	}
183*2a99deb5Smartijn 	prog[i] = '\0';
184*2a99deb5Smartijn 
185*2a99deb5Smartijn 	return i;
186*2a99deb5Smartijn }
187