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