xref: /openbsd/usr.sbin/smtpd/rfc5322.c (revision a5bc80fb)
1*a5bc80fbSop /*	$OpenBSD: rfc5322.c,v 1.4 2023/12/05 13:38:25 op Exp $	*/
2ca4531c3Seric 
3ca4531c3Seric /*
4ca4531c3Seric  * Copyright (c) 2018 Eric Faurot <eric@openbsd.org>
5ca4531c3Seric  *
6ca4531c3Seric  * Permission to use, copy, modify, and distribute this software for any
7ca4531c3Seric  * purpose with or without fee is hereby granted, provided that the above
8ca4531c3Seric  * copyright notice and this permission notice appear in all copies.
9ca4531c3Seric  *
10ca4531c3Seric  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11ca4531c3Seric  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12ca4531c3Seric  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13ca4531c3Seric  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14ca4531c3Seric  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15ca4531c3Seric  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16ca4531c3Seric  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17ca4531c3Seric  */
18ca4531c3Seric 
19ca4531c3Seric #include <errno.h>
20ca4531c3Seric #include <limits.h>
21ca4531c3Seric #include <stdlib.h>
22ca4531c3Seric #include <string.h>
23ca4531c3Seric 
24ca4531c3Seric #include "rfc5322.h"
25ca4531c3Seric 
26ca4531c3Seric struct buf {
27ca4531c3Seric 	char	*buf;
28ca4531c3Seric 	size_t	 bufsz;
29ca4531c3Seric 	size_t	 buflen;
30ca4531c3Seric 	size_t	 bufmax;
31ca4531c3Seric };
32ca4531c3Seric 
33ca4531c3Seric static int buf_alloc(struct buf *, size_t);
34ca4531c3Seric static int buf_grow(struct buf *, size_t);
35ca4531c3Seric static int buf_cat(struct buf *, const char *);
36ca4531c3Seric 
37ca4531c3Seric struct rfc5322_parser {
38ca4531c3Seric 	const char	*line;
39ca4531c3Seric 	int		 state;		/* last parser state */
40ca4531c3Seric 	int		 next;		/* parser needs data */
41ca4531c3Seric 	int		 unfold;
42ca4531c3Seric 	const char	*currhdr;
43ca4531c3Seric 	struct buf	 hdr;
44ca4531c3Seric 	struct buf	 val;
45ca4531c3Seric };
46ca4531c3Seric 
47ca4531c3Seric struct rfc5322_parser *
rfc5322_parser_new(void)48ca4531c3Seric rfc5322_parser_new(void)
49ca4531c3Seric {
50ca4531c3Seric 	struct rfc5322_parser *parser;
51ca4531c3Seric 
52ca4531c3Seric 	parser = calloc(1, sizeof(*parser));
53ca4531c3Seric 	if (parser == NULL)
54ca4531c3Seric 		return NULL;
55ca4531c3Seric 
56ca4531c3Seric 	rfc5322_clear(parser);
57ca4531c3Seric 	parser->hdr.bufmax = 1024;
58ca4531c3Seric 	parser->val.bufmax = 65536;
59ca4531c3Seric 
60ca4531c3Seric 	return parser;
61ca4531c3Seric }
62ca4531c3Seric 
63ca4531c3Seric void
rfc5322_free(struct rfc5322_parser * parser)64ca4531c3Seric rfc5322_free(struct rfc5322_parser *parser)
65ca4531c3Seric {
66ca4531c3Seric 	free(parser->hdr.buf);
67ca4531c3Seric 	free(parser->val.buf);
68ca4531c3Seric 	free(parser);
69ca4531c3Seric }
70ca4531c3Seric 
71ca4531c3Seric void
rfc5322_clear(struct rfc5322_parser * parser)72ca4531c3Seric rfc5322_clear(struct rfc5322_parser *parser)
73ca4531c3Seric {
74ca4531c3Seric 	parser->line = NULL;
75ca4531c3Seric 	parser->state = RFC5322_NONE;
76ca4531c3Seric 	parser->next = 0;
77ca4531c3Seric 	parser->hdr.buflen = 0;
78ca4531c3Seric 	parser->val.buflen = 0;
79ca4531c3Seric }
80ca4531c3Seric 
81ca4531c3Seric int
rfc5322_push(struct rfc5322_parser * parser,const char * line)82ca4531c3Seric rfc5322_push(struct rfc5322_parser *parser, const char *line)
83ca4531c3Seric {
84ca4531c3Seric 	if (parser->line) {
85ca4531c3Seric 		errno = EALREADY;
86ca4531c3Seric 		return -1;
87ca4531c3Seric 	}
88ca4531c3Seric 
89ca4531c3Seric 	parser->line = line;
90ca4531c3Seric 	parser->next = 0;
91ca4531c3Seric 
92ca4531c3Seric 	return 0;
93ca4531c3Seric }
94ca4531c3Seric 
95ca4531c3Seric int
rfc5322_unfold_header(struct rfc5322_parser * parser)96ca4531c3Seric rfc5322_unfold_header(struct rfc5322_parser *parser)
97ca4531c3Seric {
98ca4531c3Seric 	if (parser->unfold) {
99ca4531c3Seric 		errno = EALREADY;
100ca4531c3Seric 		return -1;
101ca4531c3Seric 	}
102ca4531c3Seric 
103ca4531c3Seric 	if (parser->currhdr == NULL) {
104ca4531c3Seric 		errno = EOPNOTSUPP;
105ca4531c3Seric 		return -1;
106ca4531c3Seric 	}
107ca4531c3Seric 
108ca4531c3Seric 	if (buf_cat(&parser->val, parser->currhdr) == -1)
109ca4531c3Seric 		return -1;
110ca4531c3Seric 
111ca4531c3Seric 	parser->currhdr = NULL;
112ca4531c3Seric 	parser->unfold = 1;
113ca4531c3Seric 
114ca4531c3Seric 	return 0;
115ca4531c3Seric }
116ca4531c3Seric 
117ca4531c3Seric static int
_rfc5322_next(struct rfc5322_parser * parser,struct rfc5322_result * res)118ca4531c3Seric _rfc5322_next(struct rfc5322_parser *parser, struct rfc5322_result *res)
119ca4531c3Seric {
120ca4531c3Seric 	size_t len;
121ca4531c3Seric 	const char *pos, *line;
122ca4531c3Seric 
123ca4531c3Seric 	line = parser->line;
124ca4531c3Seric 
125ca4531c3Seric 	switch(parser->state) {
126ca4531c3Seric 
127ca4531c3Seric 	case RFC5322_HEADER_START:
128ca4531c3Seric 	case RFC5322_HEADER_CONT:
129ca4531c3Seric 		res->hdr = parser->hdr.buf;
130ca4531c3Seric 
131ca4531c3Seric 		if (line && (line[0] == ' ' || line[0] == '\t')) {
132ca4531c3Seric 			parser->line = NULL;
133ca4531c3Seric 			parser->next = 1;
134ca4531c3Seric 			if (parser->unfold) {
135ca4531c3Seric 				if (buf_cat(&parser->val, "\n") == -1 ||
136ca4531c3Seric 				    buf_cat(&parser->val, line) == -1)
137ca4531c3Seric 					return -1;
138ca4531c3Seric 			}
139ca4531c3Seric 			res->value = line;
140ca4531c3Seric 			return RFC5322_HEADER_CONT;
141ca4531c3Seric 		}
142ca4531c3Seric 
143ca4531c3Seric 		if (parser->unfold) {
144ca4531c3Seric 			parser->val.buflen = 0;
145ca4531c3Seric 			parser->unfold = 0;
146ca4531c3Seric 			res->value = parser->val.buf;
147ca4531c3Seric 		}
148ca4531c3Seric 		return RFC5322_HEADER_END;
149ca4531c3Seric 
150ca4531c3Seric 	case RFC5322_NONE:
151ca4531c3Seric 	case RFC5322_HEADER_END:
152*a5bc80fbSop 		if (line && line[0] != ' ' && line[0] != '\t' &&
153*a5bc80fbSop 		    (pos = strchr(line, ':'))) {
154ca4531c3Seric 			len = pos - line;
155ca4531c3Seric 			if (buf_grow(&parser->hdr, len + 1) == -1)
156ca4531c3Seric 				return -1;
157ca4531c3Seric 			(void)memcpy(parser->hdr.buf, line, len);
158ca4531c3Seric 			parser->hdr.buf[len] = '\0';
159ca4531c3Seric 			parser->hdr.buflen = len + 1;
160ca4531c3Seric 			parser->line = NULL;
161ca4531c3Seric 			parser->next = 1;
162ca4531c3Seric 			parser->currhdr = pos + 1;
163ca4531c3Seric 			res->hdr = parser->hdr.buf;
164ca4531c3Seric 			res->value = pos + 1;
165ca4531c3Seric 			return RFC5322_HEADER_START;
166ca4531c3Seric 		}
167ca4531c3Seric 
168ca4531c3Seric 		return RFC5322_END_OF_HEADERS;
169ca4531c3Seric 
170ca4531c3Seric 	case RFC5322_END_OF_HEADERS:
171ca4531c3Seric 		if (line == NULL)
172ca4531c3Seric 			return RFC5322_END_OF_MESSAGE;
173ca4531c3Seric 
174ca4531c3Seric 		if (line[0] == '\0') {
175ca4531c3Seric 			parser->line = NULL;
176ca4531c3Seric 			parser->next = 1;
177ca4531c3Seric 			res->value = line;
178ca4531c3Seric 			return RFC5322_BODY_START;
179ca4531c3Seric 		}
180ca4531c3Seric 
1812f200fbbSgilles 		errno = EINVAL;
182ca4531c3Seric 		return -1;
183ca4531c3Seric 
184ca4531c3Seric 	case RFC5322_BODY_START:
185ca4531c3Seric 	case RFC5322_BODY:
186ca4531c3Seric 		if (line == NULL)
187ca4531c3Seric 			return RFC5322_END_OF_MESSAGE;
188ca4531c3Seric 
189ca4531c3Seric 		parser->line = NULL;
190ca4531c3Seric 		parser->next = 1;
191ca4531c3Seric 		res->value = line;
192ca4531c3Seric 		return RFC5322_BODY;
193ca4531c3Seric 
194ca4531c3Seric 	case RFC5322_END_OF_MESSAGE:
195ca4531c3Seric 		errno = ENOMSG;
196ca4531c3Seric 		return -1;
197ca4531c3Seric 
198ca4531c3Seric 	default:
199ca4531c3Seric 		errno = EINVAL;
200ca4531c3Seric 		return -1;
201ca4531c3Seric 	}
202ca4531c3Seric }
203ca4531c3Seric 
204ca4531c3Seric int
rfc5322_next(struct rfc5322_parser * parser,struct rfc5322_result * res)205ca4531c3Seric rfc5322_next(struct rfc5322_parser *parser, struct rfc5322_result *res)
206ca4531c3Seric {
207ca4531c3Seric 	memset(res, 0, sizeof(*res));
208ca4531c3Seric 
209ca4531c3Seric 	if (parser->next)
210ca4531c3Seric 		return RFC5322_NONE;
211ca4531c3Seric 
212ca4531c3Seric 	return (parser->state = _rfc5322_next(parser, res));
213ca4531c3Seric }
214ca4531c3Seric 
215ca4531c3Seric static int
buf_alloc(struct buf * b,size_t need)216ca4531c3Seric buf_alloc(struct buf *b, size_t need)
217ca4531c3Seric {
218ca4531c3Seric 	char *buf;
219ca4531c3Seric 	size_t alloc;
220ca4531c3Seric 
221ca4531c3Seric 	if (b->buf && b->bufsz >= need)
222ca4531c3Seric 		return 0;
223ca4531c3Seric 
224ca4531c3Seric 	if (need >= b->bufmax) {
225ca4531c3Seric 		errno = ERANGE;
226ca4531c3Seric 		return -1;
227ca4531c3Seric 	}
228ca4531c3Seric 
229ca4531c3Seric #define N 256
230ca4531c3Seric 	alloc = N * (need / N) + ((need % N) ? N : 0);
231ca4531c3Seric #undef N
232ca4531c3Seric 	buf = reallocarray(b->buf, alloc, 1);
233ca4531c3Seric 	if (buf == NULL)
234ca4531c3Seric 		return -1;
235ca4531c3Seric 
236ca4531c3Seric 	b->buf = buf;
237ca4531c3Seric 	b->bufsz = alloc;
238ca4531c3Seric 
239ca4531c3Seric 	return 0;
240ca4531c3Seric }
241ca4531c3Seric 
242ca4531c3Seric static int
buf_grow(struct buf * b,size_t sz)243ca4531c3Seric buf_grow(struct buf *b, size_t sz)
244ca4531c3Seric {
245ca4531c3Seric 	if (SIZE_T_MAX - b->buflen <= sz) {
246ca4531c3Seric 		errno = ERANGE;
247ca4531c3Seric 		return -1;
248ca4531c3Seric 	}
249ca4531c3Seric 
250ca4531c3Seric 	return buf_alloc(b, b->buflen + sz);
251ca4531c3Seric }
252ca4531c3Seric 
253ca4531c3Seric static int
buf_cat(struct buf * b,const char * s)254ca4531c3Seric buf_cat(struct buf *b, const char *s)
255ca4531c3Seric {
256ca4531c3Seric 	size_t len = strlen(s);
257ca4531c3Seric 
258ca4531c3Seric 	if (buf_grow(b, len + 1) == -1)
259ca4531c3Seric 		return -1;
260ca4531c3Seric 
261ca4531c3Seric 	(void)memmove(b->buf + b->buflen, s, len + 1);
262ca4531c3Seric 	b->buflen += len;
263ca4531c3Seric 	return 0;
264ca4531c3Seric }
265