Blob


1 /*
2 * Copyright (c) 2020-2022 Martijn van Duren <martijn@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include <ctype.h>
18 #include <errno.h>
19 #include <stddef.h>
20 #include <string.h>
21 #include <strings.h>
23 #include "ltok.h"
25 /* RFC 5234 - Augmented BNF for Syntax Specifications: ABNF */
26 const char *
27 osmtpd_ltok_skip_alpha(const char *ptr, int optional)
28 {
29 if ((ptr[0] >= 0x41 && ptr[0] <= 0x5a) ||
30 (ptr[0] >= 0x61 && ptr[0] <= 0x7a))
31 return ptr + 1;
32 return optional ? ptr : NULL;
33 }
35 const char *
36 osmtpd_ltok_skip_bit(const char *ptr, int optional)
37 {
38 if (ptr[0] == '0' || ptr[0] == '1')
39 return ptr + 1;
40 return optional ? ptr : NULL;
41 }
43 const char *
44 osmtpd_ltok_skip_char(const char *ptr, int optional)
45 {
46 if (ptr[0] >= 0x01 && ptr[0] <= 0x7f)
47 return ptr + 1;
48 return optional ? ptr : NULL;
49 }
51 const char *
52 osmtpd_ltok_skip_cr(const char *ptr, int optional)
53 {
54 if (ptr[0] == 0xd)
55 return ptr + 1;
56 return optional ? ptr : NULL;
57 }
59 const char *
60 osmtpd_ltok_skip_crlf(const char *ptr, int optional)
61 {
62 if (ptr[0] == 13 && ptr[1] == 10)
63 return ptr + 2;
64 return optional ? ptr : NULL;
65 }
67 const char *
68 osmtpd_ltok_skip_ctl(const char *ptr, int optional)
69 {
70 if ((ptr[0] >= 0x00 && ptr[0] <= 0x1f) || ptr[0] == 0x7f)
71 return ptr + 1;
72 return optional ? ptr : NULL;
73 }
75 const char *
76 osmtpd_ltok_skip_digit(const char *ptr, int optional)
77 {
78 if (ptr[0] >= 0x30 && ptr[0] <= 0x39)
79 return ptr + 1;
80 return optional ? ptr : NULL;
81 }
83 const char *
84 osmtpd_ltok_skip_dquote(const char *ptr, int optional)
85 {
86 if (ptr[0] == 0x22)
87 return ptr + 1;
88 return optional ? ptr : NULL;
89 }
91 const char *
92 osmtpd_ltok_skip_hexdig(const char *ptr, int optional)
93 {
94 const char *start = ptr;
95 char l;
97 if ((ptr = osmtpd_ltok_skip_digit(ptr, 0)) != NULL)
98 return ptr;
99 l = tolower(start[0]);
100 if (l == 'a' || l == 'b' || l == 'c' || l == 'd' ||
101 l == 'e' || l == 'f')
102 return start + 1;
103 return optional ? start : NULL;
106 const char *
107 osmtpd_ltok_skip_htab(const char *ptr, int optional)
109 if (ptr[0] == 0x9)
110 return ptr + 1;
111 return optional ? ptr : NULL;
114 const char *
115 osmtpd_ltok_skip_lf(const char *ptr, int optional)
117 if (ptr[0] == 0xa)
118 return ptr + 1;
119 return optional ? ptr : NULL;
122 const char *
123 osmtpd_ltok_skip_octet(const char *ptr, int optional)
125 return ptr + 1;
128 const char *
129 osmtpd_ltok_skip_sp(const char *ptr, int optional)
131 if (ptr[0] == 0x20)
132 return ptr + 1;
133 return optional ? ptr : NULL;
136 const char *
137 osmtpd_ltok_skip_vchar(const char *ptr, int optional)
139 if (ptr[0] >= 0x21 && ptr[0] <= 0x7e)
140 return ptr + 1;
141 return optional ? ptr : NULL;
144 const char *
145 osmtpd_ltok_skip_wsp(const char *ptr, int optional)
147 const char *start = ptr;
149 if ((ptr = osmtpd_ltok_skip_sp(start, 0)) != NULL ||
150 (ptr = osmtpd_ltok_skip_htab(start, 0)) != NULL)
151 return ptr;
152 return optional ? start : NULL;
155 /* RFC 5321 - Simple Mail Transfer Protocol */
156 const char *
157 osmtpd_ltok_skip_keyword(const char *ptr, int optional)
159 return osmtpd_ltok_skip_ldh_string(ptr, optional);
162 const char *
163 osmtpd_ltok_skip_sub_domain(const char *ptr, int optional)
165 const char *start = ptr;
167 if ((ptr = osmtpd_ltok_skip_let_dig(ptr, 0)) == NULL)
168 return optional ? start : NULL;
169 return osmtpd_ltok_skip_ldh_string(ptr, 1);
172 const char *
173 osmtpd_ltok_skip_let_dig(const char *ptr, int optional)
175 const char *start = ptr;
177 if ((ptr = osmtpd_ltok_skip_alpha(start, 0)) == NULL &&
178 (ptr = osmtpd_ltok_skip_digit(start, 0)) == NULL)
179 return optional ? start : NULL;
180 return ptr;
183 const char *
184 osmtpd_ltok_skip_ldh_string(const char *ptr, int optional)
186 const char *start = ptr, *prev;
187 int letdig = 0;
189 while (1) {
190 prev = ptr;
191 if ((ptr = osmtpd_ltok_skip_alpha(prev, 0)) != NULL ||
192 (ptr = osmtpd_ltok_skip_digit(prev, 0)) != NULL) {
193 letdig = 1;
194 continue;
196 if (prev[0] == '-') {
197 letdig = 0;
198 ptr = prev + 1;
199 continue;
201 ptr = prev;
202 break;
204 if (letdig)
205 return ptr;
206 if (ptr == start)
207 return optional ? start : NULL;
208 return ptr;
211 /* RFC 5322 - Internet Message Format */
212 const char *
213 osmtpd_ltok_skip_quoted_pair(const char *ptr, int optional)
215 const char *start = ptr;
217 if (ptr[0] == '\\' && (
218 (ptr = osmtpd_ltok_skip_vchar(start + 1, 0)) != NULL ||
219 (ptr = osmtpd_ltok_skip_wsp(start + 1, 0)) != NULL))
220 return ptr;
221 return osmtpd_ltok_skip_obs_qp(start, optional);
224 const char *
225 osmtpd_ltok_skip_fws(const char *ptr, int optional)
227 const char *start = ptr, *prev = ptr;
229 while ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) != NULL)
230 prev = ptr;
231 if ((ptr = osmtpd_ltok_skip_crlf(prev, 1)) == prev)
232 ptr = start;
233 if ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) == NULL)
234 return osmtpd_ltok_skip_obs_fws(start, optional);
235 prev = ptr;
236 while ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) != NULL)
237 prev = ptr;
238 return prev;
241 const char *
242 osmtpd_ltok_skip_ctext(const char *ptr, int optional)
244 const char *start = ptr;
246 if ((ptr[0] >= 33 && ptr[0] <= 39) || (ptr[0] >= 42 && ptr[0] <= 91) ||
247 (ptr[0] >= 93 && ptr[0] <= 126))
248 return ptr + 1;
249 if ((ptr = osmtpd_ltok_skip_obs_ctext(ptr, 0)) != NULL)
250 return ptr;
251 return optional ? start : NULL;
254 const char *
255 osmtpd_ltok_skip_ccontent(const char *ptr, int optional)
257 const char *start = ptr;
259 if ((ptr = osmtpd_ltok_skip_ctext(ptr, 0)) != NULL)
260 return ptr;
261 if ((ptr = osmtpd_ltok_skip_quoted_pair(start, 0)) != NULL)
262 return ptr;
263 if ((ptr = osmtpd_ltok_skip_comment(start, 0)) != NULL)
264 return ptr;
265 return optional ? start : NULL;
268 const char *
269 osmtpd_ltok_skip_comment(const char *ptr, int optional)
271 const char *start = ptr;
273 if (ptr++[0] != '(')
274 return optional ? start : NULL;
275 while (1) {
276 ptr = osmtpd_ltok_skip_fws(ptr, 1);
277 if (ptr[0] == ')')
278 return ptr + 1;
279 if ((ptr = osmtpd_ltok_skip_ccontent(ptr, 0)) == NULL)
280 return optional ? start : NULL;
284 const char *
285 osmtpd_ltok_skip_cfws(const char *ptr, int optional)
287 const char *start = ptr, *prev;
289 while (1) {
290 ptr = osmtpd_ltok_skip_fws(ptr, 1);
291 prev = ptr;
292 if ((ptr = osmtpd_ltok_skip_comment(ptr, 0)) == NULL) {
293 ptr = prev;
294 break;
297 return ptr == start && !optional ? NULL : ptr;
300 const char *
301 osmtpd_ltok_skip_atext(const char *ptr, int optional)
303 const char *start = ptr;
305 if ((ptr = osmtpd_ltok_skip_alpha(start, 0)) != NULL ||
306 (ptr = osmtpd_ltok_skip_digit(start, 0)) != NULL)
307 return ptr;
308 ptr = start;
309 if (ptr[0] == '!' || ptr[0] == '#' || ptr[0] == '$' || ptr[0] == '%' ||
310 ptr[0] == '&' || ptr[0] == '\'' || ptr[0] == '*' || ptr[0] == '+' ||
311 ptr[0] == '-' || ptr[0] == '/' || ptr[0] == '=' || ptr[0] == '?' ||
312 ptr[0] == '^' || ptr[0] == '_' || ptr[0] == '`' || ptr[0] == '{' ||
313 ptr[0] == '|' || ptr[0] == '}' || ptr[0] == '~')
314 return ptr + 1;
315 return optional ? start : NULL;
318 const char *
319 osmtpd_ltok_skip_atom(const char *ptr, int optional)
321 const char *start = ptr, *prev;
323 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
324 if ((ptr = osmtpd_ltok_skip_atext(ptr, 0)) == NULL)
325 return optional ? start : NULL;
326 do {
327 prev = ptr;
328 ptr = osmtpd_ltok_skip_atext(ptr, 1);
329 } while (prev != ptr);
330 return osmtpd_ltok_skip_cfws(ptr, 1);
333 const char *
334 osmtpd_ltok_skip_dot_atom_text(const char *ptr, int optional)
336 const char *start = ptr, *prev;
338 if ((ptr = osmtpd_ltok_skip_atext(ptr, 0)) == NULL)
339 return optional ? start : NULL;
340 do {
341 prev = ptr;
342 ptr = osmtpd_ltok_skip_atext(ptr, 1);
343 } while (ptr != prev);
345 while (ptr[0] == '.') {
346 ptr++;
347 if ((ptr = osmtpd_ltok_skip_atext(ptr, 0)) == NULL)
348 return prev;
349 do {
350 prev = ptr;
351 ptr = osmtpd_ltok_skip_atext(ptr, 1);
352 } while (ptr != prev);
354 return ptr;
357 const char *
358 osmtpd_ltok_skip_dot_atom(const char *ptr, int optional)
360 const char *start = ptr;
362 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
363 if ((ptr = osmtpd_ltok_skip_dot_atom_text(ptr, 0)) == NULL)
364 return optional ? start : NULL;
365 return osmtpd_ltok_skip_cfws(ptr, 1);
368 const char *
369 osmtpd_ltok_skip_qtext(const char *ptr, int optional)
371 const char *start = ptr;
373 if (ptr[0] == 33 || (ptr[0] >= 35 && ptr[0] <= 91) ||
374 (ptr[0] >= 93 && ptr[0] <= 126))
375 return ptr + 1;
376 if ((ptr = osmtpd_ltok_skip_obs_qtext(ptr, 0)) != NULL)
377 return ptr;
378 return optional ? start : NULL;
381 const char *
382 osmtpd_ltok_skip_qcontent(const char *ptr, int optional)
384 const char *start = ptr;
386 if ((ptr = osmtpd_ltok_skip_qtext(ptr, 0)) != NULL)
387 return ptr;
388 return osmtpd_ltok_skip_quoted_pair(start, optional);
391 const char *
392 osmtpd_ltok_skip_quoted_string(const char *ptr, int optional)
394 const char *start = ptr, *prev;
396 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
397 if ((ptr = osmtpd_ltok_skip_dquote(ptr, 0)) == NULL)
398 return optional ? start : NULL;
399 prev = ptr;
400 while (1) {
401 ptr = osmtpd_ltok_skip_fws(ptr, 1);
402 if ((ptr = osmtpd_ltok_skip_qcontent(ptr, 0)) == NULL)
403 break;
404 prev = ptr;
406 if ((ptr = osmtpd_ltok_skip_dquote(prev, 0)) == NULL)
407 return optional ? start : NULL;
408 return osmtpd_ltok_skip_cfws(ptr, 1);
411 const char *
412 osmtpd_ltok_skip_word(const char *ptr, int optional)
414 const char *start = ptr;
416 if ((ptr = osmtpd_ltok_skip_atom(ptr, 0)) != NULL)
417 return ptr;
418 return osmtpd_ltok_skip_quoted_string(start, optional);
421 const char *
422 osmtpd_ltok_skip_phrase(const char *ptr, int optional)
424 /* obs-phrase is a superset of phrae */
425 return osmtpd_ltok_skip_obs_phrase(ptr, optional);
428 const char *
429 osmtpd_ltok_skip_name_addr(const char *ptr, int optional)
431 const char *start = ptr;
433 ptr = osmtpd_ltok_skip_display_name(ptr, 1);
434 if ((ptr = osmtpd_ltok_skip_angle_addr(ptr, 0)) == NULL)
435 return optional ? start : NULL;
436 return ptr;
439 const char *
440 osmtpd_ltok_skip_angle_addr(const char *ptr, int optional)
442 const char *start = ptr;
444 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
445 if (ptr++[0] != '<')
446 return osmtpd_ltok_skip_obs_angle_addr(start, optional);
447 if ((ptr = osmtpd_ltok_skip_addr_spec(ptr, 0)) == NULL)
448 return osmtpd_ltok_skip_obs_angle_addr(start, optional);
449 if (ptr++[0] != '>')
450 return osmtpd_ltok_skip_obs_angle_addr(start, optional);
451 return osmtpd_ltok_skip_cfws(ptr, 1);
454 const char *
455 osmtpd_ltok_skip_display_name(const char *ptr, int optional)
457 return osmtpd_ltok_skip_phrase(ptr, optional);
460 const char *
461 osmtpd_ltok_skip_addr_spec(const char *ptr, int optional)
463 const char *start = ptr;
465 if ((ptr = osmtpd_ltok_skip_local_part(ptr, 0)) == NULL)
466 return optional ? start : NULL;
467 if (ptr++[0] != '@')
468 return optional ? start : NULL;
469 if ((ptr = osmtpd_ltok_skip_domain(ptr, 0)) == NULL)
470 return optional ? start : NULL;
471 return ptr;
474 const char *
475 osmtpd_ltok_skip_local_part(const char *ptr, int optional)
477 const char *start = ptr;
479 if ((ptr = osmtpd_ltok_skip_dot_atom(ptr, 0)) != NULL)
480 return ptr;
481 ptr = start;
482 if ((ptr = osmtpd_ltok_skip_quoted_string(ptr, 0)) != NULL)
483 return ptr;
484 return osmtpd_ltok_skip_obs_local_part(start, optional);
487 const char *
488 osmtpd_ltok_skip_domain(const char *ptr, int optional)
490 const char *start = ptr;
492 if ((ptr = osmtpd_ltok_skip_dot_atom(start, 0)) != NULL)
493 return ptr;
494 if ((ptr = osmtpd_ltok_skip_domain_literal(start, 0)) != NULL)
495 return ptr;
496 return osmtpd_ltok_skip_obs_domain(start, optional);
499 const char *
500 osmtpd_ltok_skip_domain_literal(const char *ptr, int optional)
502 const char *start = ptr, *prev;
504 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
505 if (ptr++[0] != '[')
506 return optional ? start : NULL;
507 while (1) {
508 ptr = osmtpd_ltok_skip_fws(ptr, 1);
509 prev = ptr;
510 if ((ptr = osmtpd_ltok_skip_dtext(ptr, 0)) == NULL) {
511 ptr = prev;
512 break;
515 if (ptr[0] != ']')
516 return optional ? start : NULL;
517 ptr++;
518 return osmtpd_ltok_skip_cfws(ptr, 1);
521 const char *
522 osmtpd_ltok_skip_dtext(const char *ptr, int optional)
524 if ((ptr[0] >= 33 && ptr[0] <= 90) || (ptr[0] >= 94 && ptr[0] <= 126))
525 return ptr + 1;
526 return osmtpd_ltok_skip_obs_dtext(ptr, optional);
530 const char *
531 osmtpd_ltok_skip_field_name(const char *ptr, int optional)
533 const char *start = ptr;
535 if ((ptr = osmtpd_ltok_skip_ftext(ptr, 0)) == NULL)
536 return optional ? start : NULL;
537 while (1) {
538 start = ptr;
539 if ((ptr = osmtpd_ltok_skip_ftext(ptr, 0)) == NULL)
540 return start;
544 const char *
545 osmtpd_ltok_skip_ftext(const char *ptr, int optional)
547 if ((ptr[0] >= 33 && ptr[0] <= 57) ||
548 (ptr[0] >= 59 && ptr[0] <= 126))
549 return ptr + 1;
550 return optional ? ptr : NULL;
553 const char *
554 osmtpd_ltok_skip_obs_no_ws_ctl(const char *ptr, int optional)
556 if ((ptr[0] >= 1 && ptr[0] <= 8) || ptr[0] == 11 || ptr[0] == 12 ||
557 (ptr[0] >= 14 && ptr[0] <= 31) || ptr[0] == 127)
558 return ptr + 1;
559 return optional ? ptr : NULL;
562 const char *
563 osmtpd_ltok_skip_obs_ctext(const char *ptr, int optional)
565 return osmtpd_ltok_skip_obs_no_ws_ctl(ptr, optional);
568 const char *
569 osmtpd_ltok_skip_obs_qtext(const char *ptr, int optional)
571 return osmtpd_ltok_skip_obs_no_ws_ctl(ptr, optional);
574 const char *
575 osmtpd_ltok_skip_obs_qp(const char *ptr, int optional)
577 const char *start = ptr;
579 if (ptr[0] == '\\' && (
580 (ptr = osmtpd_ltok_skip_obs_no_ws_ctl(start + 1, 0)) != NULL ||
581 (ptr = osmtpd_ltok_skip_lf(start + 1, 0)) != NULL ||
582 (ptr = osmtpd_ltok_skip_cr(start + 1, 0)) != NULL))
583 return ptr;
584 return optional ? start : NULL;
587 const char *
588 osmtpd_ltok_skip_obs_phrase(const char *ptr, int optional)
590 const char *start = ptr, *prev;
592 if ((ptr = osmtpd_ltok_skip_word(ptr, 0)) == NULL)
593 return optional ? start : NULL;
594 while (1) {
595 prev = ptr;
596 if ((ptr = osmtpd_ltok_skip_word(ptr, 0)) != NULL)
597 continue;
598 ptr = prev;
599 if (ptr[0] == '.') {
600 ptr++;
601 continue;
603 if ((ptr = osmtpd_ltok_skip_cfws(ptr, 0)) != NULL)
604 continue;
605 return prev;
609 const char *
610 osmtpd_ltok_skip_obs_fws(const char *ptr, int optional)
612 const char *start = ptr, *prev;
614 if ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) == NULL)
615 return optional ? start : NULL;
616 prev = ptr;
617 while ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) != NULL)
618 prev = ptr;
620 ptr = prev;
621 while (1) {
622 if ((ptr = osmtpd_ltok_skip_crlf(ptr, 0)) == NULL)
623 return prev;
624 if ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) == NULL)
625 return prev;
626 prev = ptr;
627 while ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) != NULL)
628 prev = ptr;
629 ptr = prev;
633 const char *
634 osmtpd_ltok_skip_obs_angle_addr(const char *ptr, int optional)
636 const char *start = ptr;
638 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
639 if (ptr++[0] != '<')
640 return optional ? start : NULL;
641 if ((ptr = osmtpd_ltok_skip_obs_route(ptr, 0)) == NULL)
642 return optional ? start : NULL;
643 if ((ptr = osmtpd_ltok_skip_addr_spec(ptr, 0)) == NULL)
644 return optional ? start : NULL;
645 if (ptr++[0] != '>')
646 return optional ? start : NULL;
647 return osmtpd_ltok_skip_cfws(ptr, 1);
650 const char *
651 osmtpd_ltok_skip_obs_route(const char *ptr, int optional)
653 const char *start = ptr;
655 if ((ptr = osmtpd_ltok_skip_obs_domain_list(ptr, 0)) == NULL)
656 return optional ? start : NULL;
657 if (ptr++[0] != ':')
658 return optional ? start : NULL;
659 return ptr;
662 const char *
663 osmtpd_ltok_skip_obs_domain_list(const char *ptr, int optional)
665 const char *start = ptr, *prev = ptr;
667 while (1) {
668 if (ptr[0] == ',') {
669 ptr++;
670 prev = ptr;
671 continue;
672 } else if ((ptr = osmtpd_ltok_skip_cfws(ptr, 0)) != NULL) {
673 prev = ptr;
674 continue;
676 break;
678 ptr = prev;
680 if (ptr++[0] != '@')
681 return optional ? start : NULL;
682 if ((ptr = osmtpd_ltok_skip_domain(ptr, 0)) == NULL)
683 return optional ? start : NULL;
684 while (1) {
685 if (ptr[0] != ',')
686 break;
687 ptr++;
688 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
689 if (ptr[0] != '@')
690 continue;
691 prev = ptr;
692 if ((ptr = osmtpd_ltok_skip_domain(ptr + 1, 0)) == NULL) {
693 ptr = prev;
694 break;
697 return ptr;
700 const char *
701 osmtpd_ltok_skip_obs_local_part(const char *ptr, int optional)
703 const char *start = ptr, *prev;
705 if ((ptr = osmtpd_ltok_skip_word(ptr, 0)) == NULL)
706 return optional ? start : NULL;
707 prev = ptr;
708 while (ptr[0] == '.') {
709 ptr++;
710 if ((ptr = osmtpd_ltok_skip_word(ptr, 0)) == NULL)
711 return prev;
712 prev = ptr;
714 return ptr;
717 const char *
718 osmtpd_ltok_skip_obs_domain(const char *ptr, int optional)
720 const char *start = ptr, *prev;
722 if ((ptr = osmtpd_ltok_skip_atom(ptr, 0)) == NULL)
723 return optional ? start : NULL;
724 prev = ptr;
725 while (1) {
726 if (ptr++[0] != '.')
727 return prev;
728 if ((ptr = osmtpd_ltok_skip_atom(ptr, 0)) == NULL)
729 return prev;
730 prev = ptr;
734 const char *
735 osmtpd_ltok_skip_obs_dtext(const char *ptr, int optional)
737 const char *start = ptr;
739 if ((ptr = osmtpd_ltok_skip_obs_no_ws_ctl(ptr, 0)) != NULL)
740 return ptr;
741 return osmtpd_ltok_skip_quoted_pair(start, optional);
744 /* RFC 2045 - Multipurpose Internet Mail Extensions */
745 const char *
746 osmtpd_ltok_skip_value(const char *ptr, int optional)
748 const char *start = ptr;
750 if ((ptr = osmtpd_ltok_skip_token(start, 0)) != NULL)
751 return ptr;
752 if ((ptr = osmtpd_ltok_skip_quoted_string(start, 0)) != NULL)
753 return ptr;
754 return optional ? start : NULL;
757 const char *
758 osmtpd_ltok_skip_token(const char *ptr, int optional)
760 const char *start;
761 int first = 1;
763 while (1) {
764 start = ptr;
765 if ((ptr = osmtpd_ltok_skip_char(start, 0)) != NULL &&
766 osmtpd_ltok_skip_sp(start, 0) == NULL &&
767 osmtpd_ltok_skip_ctl(start, 0) == NULL &&
768 osmtpd_ltok_skip_tspecials(start, 0) == NULL) {
769 first = 0;
770 continue;
772 return optional || !first ? start : NULL;
776 const char *
777 osmtpd_ltok_skip_tspecials(const char *ptr, int optional)
779 if (ptr[0] == '(' || ptr[0] == ')' || ptr[0] == '<' || ptr[0] == '>' ||
780 ptr[0] == '@' || ptr[0] == ',' || ptr[0] == ';' || ptr[0] == ':' ||
781 ptr[0] == '\\' || ptr[0] == '"' || ptr[0] == '/' || ptr[0] == '[' ||
782 ptr[0] == ']' || ptr[0] == '?' || ptr[0] == '=')
783 return ptr + 1;
784 return optional ? ptr : NULL;
787 const char *
788 osmtpd_ltok_skip_qp_section(const char *ptr, int optional)
790 const char *prev, *last = ptr;
792 while (1) {
793 prev = ptr;
794 if ((ptr = osmtpd_ltok_skip_ptext(prev, 0)) != NULL)
795 last = ptr;
796 else if ((ptr = osmtpd_ltok_skip_sp(prev, 0)) == NULL &&
797 (ptr = osmtpd_ltok_skip_htab(prev, 0)) == NULL)
798 return last;
802 const char *
803 osmtpd_ltok_skip_ptext(const char *ptr, int optional)
805 const char *start = ptr;
807 if ((ptr = osmtpd_ltok_skip_hex_octet(start, 0)) == NULL &&
808 (ptr = osmtpd_ltok_skip_safe_char(start, 0)) == NULL)
809 return optional ? start : NULL;
810 return ptr;
813 const char *
814 osmtpd_ltok_skip_safe_char(const char *ptr, int optional)
816 if ((ptr[0] >= 33 && ptr[0] <= 60) || (ptr[0] >= 62 && ptr[0] <= 126))
817 return ptr + 1;
818 return optional ? ptr : NULL;
821 const char *
822 osmtpd_ltok_skip_hex_octet(const char *ptr, int optional)
824 const char *start = ptr;
825 char l;
827 if (ptr[0] != '=')
828 return optional ? start : NULL;
829 ptr++;
830 l = tolower(ptr[0]);
831 if (l == 'a' || l == 'b' || l == 'c' || l == 'd' ||
832 l == 'e' || l == 'f')
833 ptr++;
834 else if ((ptr = osmtpd_ltok_skip_digit(ptr, 0)) == NULL)
835 return optional ? start : NULL;
836 l = tolower(ptr[0]);
837 start = ptr;
838 if (l == 'a' || l == 'b' || l == 'c' || l == 'd' ||
839 l == 'e' || l == 'f')
840 ptr++;
841 else if ((ptr = osmtpd_ltok_skip_digit(ptr, 0)) == NULL)
842 return start;
843 return ptr;
846 /* RFC 6376 - DomainKeys Identified Mail (DKIM) Signatures */
847 const char *
848 osmtpd_ltok_skip_hyphenated_word(const char *ptr, int optional)
850 const char *start = ptr, *end;
852 if ((ptr = osmtpd_ltok_skip_alpha(ptr, 0)) == NULL)
853 return optional ? start : NULL;
855 end = ptr;
856 while (1) {
857 start = ptr;
858 if ((ptr = osmtpd_ltok_skip_alpha(start, 0)) != NULL ||
859 (ptr = osmtpd_ltok_skip_digit(start, 0)) != NULL) {
860 end = ptr;
861 } else if (start[0] == '-')
862 ptr = start + 1;
863 else
864 break;
866 return end;
869 const char *
870 osmtpd_ltok_skip_alphadigitps(const char *ptr, int optional)
872 const char *end;
874 if ((end = osmtpd_ltok_skip_alpha(ptr, 0)) == NULL &&
875 (end = osmtpd_ltok_skip_digit(ptr, 0)) == NULL &&
876 ptr[0] != '+' && ptr[0] != '/')
877 return optional ? ptr : NULL;
878 return end == NULL ? ptr + 1 : end;
881 const char *
882 osmtpd_ltok_skip_base64string(const char *ptr, int optional)
884 const char *start = ptr;
886 if ((ptr = osmtpd_ltok_skip_alphadigitps(ptr, 0)) == NULL)
887 return optional ? start : NULL;
888 while (1) {
889 start = ptr;
890 ptr = osmtpd_ltok_skip_fws(ptr, 1);
891 if ((ptr = osmtpd_ltok_skip_alphadigitps(ptr, 0)) == NULL)
892 break;
894 ptr = start;
895 ptr = osmtpd_ltok_skip_fws(ptr, 1);
896 if (ptr[0] == '=') {
897 ptr++;
898 start = ptr;
899 ptr = osmtpd_ltok_skip_fws(ptr, 1);
900 if (ptr[0] == '=')
901 ptr++;
902 else
903 ptr = start;
904 } else
905 ptr = start;
906 return ptr;
909 const char *
910 osmtpd_ltok_skip_hdr_name(const char *ptr, int optional)
912 return osmtpd_ltok_skip_field_name(ptr, optional);
915 const char *
916 osmtpd_ltok_skip_qp_hdr_value(const char *ptr, int optional)
918 return osmtpd_ltok_skip_dkim_quoted_printable(ptr, optional);
921 const char *
922 osmtpd_ltok_skip_dkim_quoted_printable(const char *ptr, int optional)
924 const char *start;
926 while (1) {
927 start = ptr;
928 if ((ptr = osmtpd_ltok_skip_fws(start, 0)) != NULL)
929 continue;
930 if ((ptr = osmtpd_ltok_skip_hex_octet(start, 0)) != NULL)
931 continue;
932 ptr = osmtpd_ltok_skip_dkim_safe_char(start, 0);
933 if (ptr == NULL)
934 break;
936 return start;
939 const char *
940 osmtpd_ltok_skip_dkim_safe_char(const char *ptr, int optional)
942 if ((ptr[0] >= 0x21 && ptr[0] <= 0x3a) || ptr[0] == 0x3c ||
943 (ptr[0] >= 0x3e && ptr[0] <= 0x7e))
944 return ptr + 1;
945 return optional ? ptr : NULL;
948 const char *
949 osmtpd_ltok_skip_selector(const char *ptr, int optional)
951 const char *start = ptr;
953 if ((ptr = osmtpd_ltok_skip_sub_domain(ptr, 0)) == NULL)
954 return optional ? start : NULL;
955 while (1) {
956 start = ptr;
957 if (ptr[0] != '.')
958 return start;
959 ptr++;
960 if ((ptr = osmtpd_ltok_skip_sub_domain(ptr, 0)) == NULL)
961 return start;
965 const char *
966 osmtpd_ltok_skip_tag_list(const char *ptr, int optional)
968 const char *start = ptr;
970 if ((ptr = osmtpd_ltok_skip_tag_spec(ptr, 0)) == NULL)
971 return optional ? start : NULL;
972 while (1) {
973 /* Starting or trailing ';' */
974 if (ptr[0] != ';')
975 return ptr;
976 ptr++;
977 start = ptr;
978 if ((ptr = osmtpd_ltok_skip_tag_spec(ptr, 0)) == NULL)
979 return start;
983 const char *
984 osmtpd_ltok_skip_tag_spec(const char *ptr, int optional)
986 const char *start = ptr;
988 ptr = osmtpd_ltok_skip_fws(ptr, 1);
989 if ((ptr = osmtpd_ltok_skip_tag_name(ptr, 0)) == NULL)
990 return optional ? start : NULL;
991 ptr = osmtpd_ltok_skip_fws(ptr, 1);
992 if (ptr[0] != '=')
993 return optional ? start : NULL;
994 ptr++;
995 ptr = osmtpd_ltok_skip_fws(ptr, 1);
996 if ((ptr = osmtpd_ltok_skip_tag_value(ptr, 0)) == NULL)
997 return optional ? start : NULL;
998 return osmtpd_ltok_skip_fws(ptr, 1);
1001 const char *
1002 osmtpd_ltok_skip_tag_name(const char *ptr, int optional)
1004 const char *start = ptr, *prev;
1006 if ((ptr = osmtpd_ltok_skip_alpha(ptr, 0)) == NULL)
1007 return optional ? start : NULL;
1008 prev = ptr;
1009 while ((ptr = osmtpd_ltok_skip_alnumpunc(ptr, 0)) != NULL)
1010 prev = ptr;
1011 return prev;
1014 const char *
1015 osmtpd_ltok_skip_tag_value(const char *ptr, int optional)
1017 const char *start = ptr, *prev;
1019 if ((ptr = osmtpd_ltok_skip_tval(ptr, 0)) == NULL)
1020 return start;
1022 while (1) {
1023 start = ptr;
1024 /* FWS contains WSP */
1025 if ((ptr = osmtpd_ltok_skip_fws(ptr, 0)) == NULL)
1026 return start;
1027 prev = ptr;
1028 while ((ptr = osmtpd_ltok_skip_fws(ptr, 0)) != NULL)
1029 prev = ptr;
1030 ptr = prev;
1031 if ((ptr = osmtpd_ltok_skip_tval(ptr, 0)) == NULL)
1032 return start;
1036 const char *
1037 osmtpd_ltok_skip_tval(const char *ptr, int optional)
1039 const char *start = ptr, *prev;
1041 if ((ptr = osmtpd_ltok_skip_valchar(ptr, 0)) == NULL)
1042 return optional ? start : NULL;
1043 prev = ptr;
1044 while ((ptr = osmtpd_ltok_skip_valchar(ptr, 0)) != NULL)
1045 prev = ptr;
1046 return prev;
1049 const char *
1050 osmtpd_ltok_skip_valchar(const char *ptr, int optional)
1052 if ((ptr[0] >= 0x21 && ptr[0] <= 0x3A) ||
1053 (ptr[0] >= 0x3C && ptr[0] <= 0x7E))
1054 return ptr + 1;
1055 return optional ? ptr : NULL;
1058 const char *
1059 osmtpd_ltok_skip_alnumpunc(const char *ptr, int optional)
1061 const char *start = ptr;
1063 if ((ptr = osmtpd_ltok_skip_alpha(start, 0)) != NULL)
1064 return ptr;
1065 if ((ptr = osmtpd_ltok_skip_digit(start, 0)) != NULL)
1066 return ptr;
1067 if (start[0] == '_')
1068 return start + 1;
1069 return optional ? start : NULL;
1072 const char *
1073 osmtpd_ltok_skip_sig_v_tag(const char *ptr, int optional)
1075 const char *start = ptr;
1077 if (ptr[0] != 0x76)
1078 return optional ? start : NULL;
1079 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1080 if (ptr[0] != '=')
1081 return optional ? start : NULL;
1082 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1083 if ((ptr = osmtpd_ltok_skip_sig_v_tag_value(ptr, 0)) == NULL)
1084 return optional ? start : NULL;
1085 return ptr;
1088 const char *
1089 osmtpd_ltok_skip_sig_v_tag_value(const char *ptr, int optional)
1091 const char *start = ptr, *prev;
1093 if ((ptr = osmtpd_ltok_skip_digit(ptr, 0)) == NULL)
1094 return optional ? start : NULL;
1095 while (1) {
1096 prev = ptr;
1097 if ((ptr = osmtpd_ltok_skip_digit(ptr, 0)) == NULL)
1098 return prev;
1102 const char *
1103 osmtpd_ltok_skip_sig_a_tag(const char *ptr, int optional)
1105 const char *start = ptr;
1107 if (ptr[0] != 0x61)
1108 return optional ? start : NULL;
1109 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1110 if (ptr[0] != '=')
1111 return optional ? start : NULL;
1112 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1113 if ((ptr = osmtpd_ltok_skip_sig_a_tag_value(ptr, 0)) == NULL)
1114 return optional ? start : NULL;
1115 return ptr;
1118 const char *
1119 osmtpd_ltok_skip_sig_a_tag_value(const char *ptr, int optional)
1121 return osmtpd_ltok_skip_sig_a_tag_alg(ptr, optional);
1124 const char *
1125 osmtpd_ltok_skip_sig_a_tag_alg(const char *ptr, int optional)
1127 const char *start = ptr;
1129 if ((ptr = osmtpd_ltok_skip_sig_a_tag_k(ptr, 0)) == NULL)
1130 return optional ? start : NULL;
1131 if (ptr[0] != '-')
1132 return optional ? start : NULL;
1133 ptr++;
1134 if ((ptr = osmtpd_ltok_skip_sig_a_tag_h(ptr, 0)) == NULL)
1135 return optional ? start : NULL;
1136 return ptr;
1139 const char *
1140 osmtpd_ltok_skip_sig_a_tag_k(const char *ptr, int optional)
1142 /* sha1 / sha256 covered by x-sig-a-tag-k */
1143 return osmtpd_ltok_skip_x_sig_a_tag_k(ptr, optional);
1146 const char *
1147 osmtpd_ltok_skip_sig_a_tag_h(const char *ptr, int optional)
1149 /* rsa / ed25519 covered by x-sig-a-tag-h */
1150 return osmtpd_ltok_skip_x_sig_a_tag_h(ptr, optional);
1153 const char *
1154 osmtpd_ltok_skip_x_sig_a_tag_k(const char *ptr, int optional)
1156 const char *start = ptr, *prev, *end;
1158 if ((ptr = osmtpd_ltok_skip_alpha(ptr, 0)) == NULL)
1159 return optional ? start : NULL;
1160 prev = ptr;
1161 while ((end = osmtpd_ltok_skip_alpha(ptr, 0)) != NULL ||
1162 (end = osmtpd_ltok_skip_digit(ptr, 0)) != NULL) {
1163 ptr = end;
1164 prev = end;
1166 return prev;
1169 const char *
1170 osmtpd_ltok_skip_x_sig_a_tag_h(const char *ptr, int optional)
1172 const char *start = ptr, *prev, *end;
1174 if ((ptr = osmtpd_ltok_skip_alpha(ptr, 0)) == NULL)
1175 return optional ? start : NULL;
1176 prev = ptr;
1177 while ((end = osmtpd_ltok_skip_alpha(ptr, 0)) != NULL ||
1178 (end = osmtpd_ltok_skip_digit(ptr, 0)) != NULL) {
1179 ptr = end;
1180 prev = end;
1182 return prev;
1185 const char *
1186 osmtpd_ltok_skip_sig_b_tag(const char *ptr, int optional)
1188 const char *start = ptr;
1190 if (ptr[0] != 0x62)
1191 return optional ? start : NULL;
1192 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1193 if (ptr[0] != '=')
1194 return optional ? start : NULL;
1195 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1196 if ((ptr = osmtpd_ltok_skip_sig_b_tag_value(ptr, 0)) == NULL)
1197 return optional ? start : NULL;
1198 return ptr;
1201 const char *
1202 osmtpd_ltok_skip_sig_b_tag_value(const char *ptr, int optional)
1204 return osmtpd_ltok_skip_sig_b_tag_data(ptr, optional);
1207 const char *
1208 osmtpd_ltok_skip_sig_b_tag_data(const char *ptr, int optional)
1210 return osmtpd_ltok_skip_base64string(ptr, optional);
1213 const char *
1214 osmtpd_ltok_skip_sig_bh_tag(const char *ptr, int optional)
1216 const char *start = ptr;
1218 if (ptr[0] != 0x62 && ptr[0] != 0x68)
1219 return optional ? start : NULL;
1220 ptr = osmtpd_ltok_skip_fws(ptr + 2, 1);
1221 if (ptr[0] != '=')
1222 return optional ? start : NULL;
1223 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1224 if ((ptr = osmtpd_ltok_skip_sig_bh_tag_value(ptr, 0)) == NULL)
1225 return optional ? start : NULL;
1226 return ptr;
1229 const char *
1230 osmtpd_ltok_skip_sig_bh_tag_value(const char *ptr, int optional)
1232 return osmtpd_ltok_skip_sig_bh_tag_data(ptr, optional);
1235 const char *
1236 osmtpd_ltok_skip_sig_bh_tag_data(const char *ptr, int optional)
1238 return osmtpd_ltok_skip_base64string(ptr, optional);
1241 const char *
1242 osmtpd_ltok_skip_sig_c_tag(const char *ptr, int optional)
1244 const char *start = ptr;
1246 if (ptr[0] != 0x63)
1247 return optional ? start : NULL;
1248 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1249 if (ptr[0] != '=')
1250 return optional ? start : NULL;
1251 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1252 if ((ptr = osmtpd_ltok_skip_sig_c_tag_value(ptr, 0)) == NULL)
1253 return optional ? start : NULL;
1254 return ptr;
1257 const char *
1258 osmtpd_ltok_skip_sig_c_tag_value(const char *ptr, int optional)
1260 const char *start = ptr;
1262 if ((ptr = osmtpd_ltok_skip_sig_c_tag_alg(ptr, 0)) == NULL)
1263 return optional ? start : NULL;
1264 if (ptr[0] == '/') {
1265 start = ptr;
1266 if ((ptr = osmtpd_ltok_skip_sig_c_tag_alg(ptr, 0)) == NULL)
1267 return start;
1269 return ptr;
1272 const char *
1273 osmtpd_ltok_skip_sig_c_tag_alg(const char *ptr, int optional)
1275 /* simple / relaxed covered by x-sig-c-tag-alga */
1276 return osmtpd_ltok_skip_x_sig_c_tag_alg(ptr, optional);
1279 const char *
1280 osmtpd_ltok_skip_x_sig_c_tag_alg(const char *ptr, int optional)
1282 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1285 const char *
1286 osmtpd_ltok_skip_sig_d_tag(const char *ptr, int optional)
1288 const char *start = ptr;
1290 if (ptr[0] != 0x64)
1291 return optional ? start : NULL;
1292 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1293 if (ptr[0] != '=')
1294 return optional ? start : NULL;
1295 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1296 if ((ptr = osmtpd_ltok_skip_sig_d_tag_value(ptr, 0)) == NULL)
1297 return optional ? start : NULL;
1298 return ptr;
1301 const char *
1302 osmtpd_ltok_skip_sig_d_tag_value(const char *ptr, int optional)
1304 return osmtpd_ltok_skip_domain_name(ptr, optional);
1307 const char *
1308 osmtpd_ltok_skip_domain_name(const char *ptr, int optional)
1310 const char *prev = ptr;
1312 if ((ptr = osmtpd_ltok_skip_sub_domain(ptr, 0)) == NULL)
1313 return optional ? prev : NULL;
1314 while (1) {
1315 prev = ptr;
1316 if (ptr[0] != '.' ||
1317 (ptr = osmtpd_ltok_skip_sub_domain(ptr + 1, 0)) == NULL)
1318 return prev;
1322 const char *
1323 osmtpd_ltok_skip_sig_h_tag(const char *ptr, int optional)
1325 const char *start = ptr;
1327 if (ptr[0] != 0x68)
1328 return optional ? start : NULL;
1329 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1330 if (ptr[0] != '=')
1331 return optional ? start : NULL;
1332 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1333 if ((ptr = osmtpd_ltok_skip_sig_h_tag_value(ptr, 0)) == NULL)
1334 return optional ? start : NULL;
1335 return ptr;
1338 const char *
1339 osmtpd_ltok_skip_sig_h_tag_value(const char *ptr, int optional)
1341 const char *prev = ptr;
1343 if ((ptr = osmtpd_ltok_skip_hdr_name(ptr, 0)) == NULL)
1344 return optional ? prev : NULL;
1345 while (1) {
1346 prev = ptr;
1347 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1348 if (ptr[0] != ':')
1349 return prev;
1350 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1351 if ((ptr = osmtpd_ltok_skip_hdr_name(ptr, 0)) == NULL)
1352 return prev;
1356 const char *
1357 osmtpd_ltok_skip_sig_i_tag(const char *ptr, int optional)
1359 const char *start = ptr;
1361 if (ptr[0] != 0x69)
1362 return optional ? start : NULL;
1363 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1364 if (ptr[0] != '=')
1365 return optional ? start : NULL;
1366 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1367 if ((ptr = osmtpd_ltok_skip_sig_i_tag_value(ptr, 0)) == NULL)
1368 return optional ? start : NULL;
1369 return ptr;
1372 const char *
1373 osmtpd_ltok_skip_sig_i_tag_value(const char *ptr, int optional)
1375 const char *start = ptr;
1377 ptr = osmtpd_ltok_skip_local_part(ptr, 1);
1378 if (ptr[0] != '@' ||
1379 (ptr = osmtpd_ltok_skip_domain_name(ptr + 1, 0)) == NULL)
1380 return optional ? start : NULL;
1381 return ptr;
1384 const char *
1385 osmtpd_ltok_skip_sig_l_tag(const char *ptr, int optional)
1387 const char *start = ptr;
1389 if (ptr[0] != 0x6c)
1390 return optional ? start : NULL;
1391 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1392 if (ptr[0] != '=')
1393 return optional ? start : NULL;
1394 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1395 if ((ptr = osmtpd_ltok_skip_sig_l_tag_value(ptr, 0)) == NULL)
1396 return optional ? start : NULL;
1397 return ptr;
1400 const char *
1401 osmtpd_ltok_skip_sig_l_tag_value(const char *ptr, int optional)
1403 size_t i;
1405 for (i = 0; i < 76; i++) {
1406 if (osmtpd_ltok_skip_digit(ptr + i, 0) == NULL)
1407 break;
1409 if (i >= 1 && i <= 76)
1410 return ptr + i;
1411 return optional ? ptr : NULL;
1414 const char *
1415 osmtpd_ltok_skip_sig_q_tag(const char *ptr, int optional)
1417 const char *start = ptr;
1419 if (ptr[0] != 0x71)
1420 return optional ? start : NULL;
1421 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1422 if (ptr[0] != '=')
1423 return optional ? start : NULL;
1424 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1425 if ((ptr = osmtpd_ltok_skip_sig_q_tag_value(ptr, 0)) == NULL)
1426 return optional ? start : NULL;
1427 return ptr;
1430 const char *
1431 osmtpd_ltok_skip_sig_q_tag_value(const char *ptr, int optional)
1433 const char *prev = ptr;
1434 if ((ptr = osmtpd_ltok_skip_sig_q_tag_method(ptr, 0)) == NULL)
1435 return optional ? prev : NULL;
1436 while (1) {
1437 prev = ptr;
1438 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1439 if (ptr[0] != ':')
1440 return prev;
1441 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1442 if ((ptr = osmtpd_ltok_skip_sig_q_tag_method(ptr, 0)) == NULL)
1443 return prev;
1447 const char *
1448 osmtpd_ltok_skip_sig_q_tag_method(const char *ptr, int optional)
1450 const char *start = ptr;
1452 /* dns/txt covered by x-sig-q-tag-type ["/" x-sig-q-tag-args] */
1453 if ((ptr = osmtpd_ltok_skip_x_sig_q_tag_type(ptr, 0)) == NULL)
1454 return optional ? start : NULL;
1455 start = ptr;
1456 if (ptr[0] != '/')
1457 return ptr;
1458 if ((ptr = osmtpd_ltok_skip_x_sig_q_tag_args(ptr, 0)) == NULL)
1459 return start;
1460 return ptr;
1463 const char *
1464 osmtpd_ltok_skip_x_sig_q_tag_type(const char *ptr, int optional)
1466 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1469 const char *
1470 osmtpd_ltok_skip_x_sig_q_tag_args(const char *ptr, int optional)
1472 return osmtpd_ltok_skip_qp_hdr_value(ptr, optional);
1475 const char *
1476 osmtpd_ltok_skip_sig_s_tag(const char *ptr, int optional)
1478 const char *start = ptr;
1480 if (ptr[0] != 0x73)
1481 return optional ? start : NULL;
1482 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1483 if (ptr[0] != '=')
1484 return optional ? start : NULL;
1485 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1486 if ((ptr = osmtpd_ltok_skip_sig_s_tag_value(ptr, 0)) == NULL)
1487 return optional ? start : NULL;
1488 return ptr;
1491 const char *
1492 osmtpd_ltok_skip_sig_s_tag_value(const char *ptr, int optional)
1494 return osmtpd_ltok_skip_selector(ptr, optional);
1497 const char *
1498 osmtpd_ltok_skip_sig_t_tag(const char *ptr, int optional)
1500 const char *start = ptr;
1502 if (ptr[0] != 0x74)
1503 return optional ? start : NULL;
1504 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1505 if (ptr[0] != '=')
1506 return optional ? start : NULL;
1507 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1508 if ((ptr = osmtpd_ltok_skip_sig_t_tag_value(ptr, 0)) == NULL)
1509 return optional ? start : NULL;
1510 return ptr;
1513 const char *
1514 osmtpd_ltok_skip_sig_t_tag_value(const char *ptr, int optional)
1516 size_t i;
1518 for (i = 0; i < 12; i++) {
1519 if (osmtpd_ltok_skip_digit(ptr + i, 0) == NULL)
1520 break;
1522 if (i >= 1 && i <= 12)
1523 return ptr + i;
1524 return optional ? ptr : NULL;
1527 const char *
1528 osmtpd_ltok_skip_sig_x_tag(const char *ptr, int optional)
1530 const char *start = ptr;
1532 if (ptr[0] != 0x78)
1533 return optional ? start : NULL;
1534 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1535 if (ptr[0] != '=')
1536 return optional ? start : NULL;
1537 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1538 if ((ptr = osmtpd_ltok_skip_sig_x_tag_value(ptr, 0)) == NULL)
1539 return optional ? start : NULL;
1540 return ptr;
1543 const char *
1544 osmtpd_ltok_skip_sig_x_tag_value(const char *ptr, int optional)
1546 size_t i;
1548 for (i = 0; i < 12; i++) {
1549 if (osmtpd_ltok_skip_digit(ptr + i, 0) == NULL)
1550 break;
1552 if (i >= 1 && i <= 12)
1553 return ptr + i;
1554 return optional ? ptr : NULL;
1557 const char *
1558 osmtpd_ltok_skip_sig_z_tag(const char *ptr, int optional)
1560 const char *start = ptr;
1562 if (ptr[0] != 0x7a)
1563 return optional ? start : NULL;
1564 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1565 if (ptr[0] != '=')
1566 return optional ? start : NULL;
1567 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1568 if ((ptr = osmtpd_ltok_skip_sig_z_tag_value(ptr, 0)) == NULL)
1569 return optional ? start : NULL;
1570 return ptr;
1573 const char *
1574 osmtpd_ltok_skip_sig_z_tag_value(const char *ptr, int optional)
1576 const char *prev = ptr;
1578 if ((ptr = osmtpd_ltok_skip_sig_z_tag_copy(ptr, 0)) == NULL)
1579 return optional ? ptr : NULL;
1580 while (1) {
1581 prev = ptr;
1582 if (ptr[0] != '|')
1583 return prev;
1584 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1585 if ((ptr = osmtpd_ltok_skip_sig_z_tag_copy(ptr, 0)) == NULL)
1586 return prev;
1590 const char *
1591 osmtpd_ltok_skip_sig_z_tag_copy(const char *ptr, int optional)
1593 const char *start = ptr;
1595 if ((ptr = osmtpd_ltok_skip_hdr_name(ptr, 0)) == NULL)
1596 return optional ? start : NULL;
1597 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1598 if (ptr[0] != ':')
1599 return optional ? start : NULL;
1600 if ((ptr = osmtpd_ltok_skip_qp_hdr_value(ptr, 0)) == NULL)
1601 return optional ? start : NULL;
1602 return ptr;
1605 const char *
1606 osmtpd_ltok_skip_key_v_tag(const char *ptr, int optional)
1608 const char *start = ptr;
1610 if (ptr[0] != 0x76)
1611 return optional ? start : NULL;
1612 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1613 if (ptr[0] != '=')
1614 return optional ? start : NULL;
1615 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1616 if ((ptr = osmtpd_ltok_skip_key_v_tag_value(ptr, 0)) == NULL)
1617 return optional ? start : NULL;
1618 return ptr;
1621 const char *
1622 osmtpd_ltok_skip_key_v_tag_value(const char *ptr, int optional)
1624 if (ptr[0] == 0x44 && ptr[1] == 0x4b && ptr[2] == 0x49 &&
1625 ptr[3] == 0x4d && ptr[4] == 0x31)
1626 return ptr + 5;
1627 return optional ? ptr : NULL;
1630 const char *
1631 osmtpd_ltok_skip_key_h_tag(const char *ptr, int optional)
1633 const char *start = ptr;
1635 if (ptr[0] != 0x68)
1636 return optional ? start : NULL;
1637 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1638 if (ptr[0] != '=')
1639 return optional ? start : NULL;
1640 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1641 if ((ptr = osmtpd_ltok_skip_key_h_tag_value(ptr, 0)) == NULL)
1642 return optional ? start : NULL;
1643 return ptr;
1646 const char *
1647 osmtpd_ltok_skip_key_h_tag_value(const char *ptr, int optional)
1649 const char *prev = ptr;
1651 if ((ptr = osmtpd_ltok_skip_key_h_tag_alg(ptr, 0)) == NULL)
1652 return optional ? prev : NULL;
1653 while (1) {
1654 prev = ptr;
1655 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1656 if (ptr[0] != ':')
1657 return prev;
1658 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1659 if ((ptr = osmtpd_ltok_skip_key_h_tag_alg(ptr, 0)) == NULL)
1660 return prev;
1664 const char *
1665 osmtpd_ltok_skip_key_h_tag_alg(const char *ptr, int optional)
1667 /* sha1 / sha256 covered by x-key-h-tag-alg */
1668 return osmtpd_ltok_skip_x_key_h_tag_alg(ptr, optional);
1671 const char *
1672 osmtpd_ltok_skip_x_key_h_tag_alg(const char *ptr, int optional)
1674 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1677 const char *
1678 osmtpd_ltok_skip_key_k_tag(const char *ptr, int optional)
1680 const char *start = ptr;
1682 if (ptr[0] != 0x6b)
1683 return optional ? start : NULL;
1684 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1685 if (ptr[0] != '=')
1686 return optional ? start : NULL;
1687 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1688 if ((ptr = osmtpd_ltok_skip_key_k_tag_value(ptr, 0)) == NULL)
1689 return optional ? start : NULL;
1690 return ptr;
1693 const char *
1694 osmtpd_ltok_skip_key_k_tag_value(const char *ptr, int optional)
1696 const char *start = ptr;
1698 if ((ptr = osmtpd_ltok_skip_key_k_tag_type(ptr, 0)) == NULL)
1699 return optional ? start : NULL;
1700 return ptr;
1703 const char *
1704 osmtpd_ltok_skip_key_k_tag_type(const char *ptr, int optional)
1706 /* rsa covered by x-key-k-tag-type */
1707 return osmtpd_ltok_skip_x_key_k_tag_type(ptr, optional);
1710 const char *
1711 osmtpd_ltok_skip_x_key_k_tag_type(const char *ptr, int optional)
1713 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1716 const char *
1717 osmtpd_ltok_skip_key_n_tag(const char *ptr, int optional)
1719 const char *start = ptr;
1721 if (ptr[0] != 0x6e)
1722 return optional ? start : NULL;
1723 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1724 if (ptr[0] != '=')
1725 return optional ? start : NULL;
1726 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1727 if ((ptr = osmtpd_ltok_skip_key_n_tag_value(ptr, 0)) == NULL)
1728 return optional ? start : NULL;
1729 return ptr;
1732 const char *
1733 osmtpd_ltok_skip_key_n_tag_value(const char *ptr, int optional)
1735 return osmtpd_ltok_skip_qp_section(ptr, optional);
1738 const char *
1739 osmtpd_ltok_skip_key_p_tag(const char *ptr, int optional)
1741 const char *start = ptr;
1743 if (ptr[0] != 0x70)
1744 return optional ? start : NULL;
1745 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1746 if (ptr[0] != '=')
1747 return optional ? start : NULL;
1748 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1749 if ((ptr = osmtpd_ltok_skip_key_p_tag_value(ptr, 0)) == NULL)
1750 return optional ? start : NULL;
1751 return ptr;
1754 const char *
1755 osmtpd_ltok_skip_key_p_tag_value(const char *ptr, int optional)
1757 const char *start = ptr;
1759 if ((ptr = osmtpd_ltok_skip_base64string(ptr, 0)) == NULL)
1760 return optional ? start : NULL;
1761 return ptr;
1764 const char *
1765 osmtpd_ltok_skip_key_s_tag(const char *ptr, int optional)
1767 const char *start = ptr;
1769 if (ptr[0] != 0x73)
1770 return optional ? start : NULL;
1771 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1772 if (ptr[0] != '=')
1773 return optional ? start : NULL;
1774 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1775 if ((ptr = osmtpd_ltok_skip_key_s_tag_value(ptr, 0)) == NULL)
1776 return optional ? start : NULL;
1777 return ptr;
1780 const char *
1781 osmtpd_ltok_skip_key_s_tag_value(const char *ptr, int optional)
1783 const char *start = ptr;
1785 if ((ptr = osmtpd_ltok_skip_key_s_tag_type(ptr, 0)) == NULL)
1786 return optional ? start : NULL;
1787 while (1) {
1788 start = ptr;
1789 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1790 if (ptr[0] != ':')
1791 return start;
1792 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1793 ptr = osmtpd_ltok_skip_key_s_tag_type(ptr, 0);
1794 if (ptr == NULL)
1795 return start;
1799 const char *
1800 osmtpd_ltok_skip_key_s_tag_type(const char *ptr, int optional)
1802 if (ptr[0] == '*')
1803 return ptr + 1;
1804 /* email covered by x-key-s-tag-type */
1805 return osmtpd_ltok_skip_x_key_s_tag_type(ptr, optional);
1808 const char *
1809 osmtpd_ltok_skip_x_key_s_tag_type(const char *ptr, int optional)
1811 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1814 const char *
1815 osmtpd_ltok_skip_key_t_tag(const char *ptr, int optional)
1817 const char *start = ptr;
1819 if (ptr[0] != 0x74)
1820 return optional ? start : NULL;
1821 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1822 if (ptr[0] != '=')
1823 return optional ? start : NULL;
1824 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1825 if ((ptr = osmtpd_ltok_skip_key_t_tag_value(ptr, 0)) == NULL)
1826 return optional ? start : NULL;
1827 return ptr;
1830 const char *
1831 osmtpd_ltok_skip_key_t_tag_value(const char *ptr, int optional)
1833 const char *start = ptr;
1835 if ((ptr = osmtpd_ltok_skip_key_t_tag_flag(ptr, 0)) == NULL)
1836 return optional ? start : NULL;
1837 while (1) {
1838 start = ptr;
1839 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1840 if (ptr[0] != ':')
1841 return start;
1842 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1843 ptr = osmtpd_ltok_skip_key_t_tag_flag(ptr, 0);
1844 if (ptr == NULL)
1845 return start;
1849 const char *
1850 osmtpd_ltok_skip_key_t_tag_flag(const char *ptr, int optional)
1852 /* y / s covered by x-key-t-tag-flag */
1853 return osmtpd_ltok_skip_x_key_t_tag_flag(ptr, optional);
1856 const char *
1857 osmtpd_ltok_skip_x_key_t_tag_flag(const char *ptr, int optional)
1859 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1862 const char *
1863 osmtpd_ltok_skip_ar_pvalue(const char *ptr, int optional)
1865 const char *start = ptr, *tmp;
1867 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
1868 if ((tmp = osmtpd_ltok_skip_value(ptr, 0)) != NULL)
1869 return tmp;
1870 ptr = osmtpd_ltok_skip_local_part(ptr, 1);
1871 if (ptr[0] == '@')
1872 ptr++;
1873 if ((ptr = osmtpd_ltok_skip_domain(ptr, 0)) == NULL)
1874 return optional ? start : NULL;
1875 return ptr;