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