Blob


1 /*
2 * Copyright (c) 2020 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 #include <stdio.h>
27 /* RFC 5234 - Augmented BNF for Syntax Specifications: ABNF */
28 const char *
29 osmtpd_ltok_skip_alpha(const char *ptr, int optional)
30 {
31 if ((ptr[0] >= 0x41 && ptr[0] <= 0x5a) ||
32 (ptr[0] >= 0x61 && ptr[0] <= 0x7a))
33 return ptr + 1;
34 return optional ? ptr : NULL;
35 }
37 const char *
38 osmtpd_ltok_skip_bit(const char *ptr, int optional)
39 {
40 if (ptr[0] == '0' || ptr[0] == '1')
41 return ptr + 1;
42 return optional ? ptr : NULL;
43 }
45 const char *
46 osmtpd_ltok_skip_char(const char *ptr, int optional)
47 {
48 if (ptr[0] >= 0x01 && ptr[0] <= 0x7f)
49 return ptr + 1;
50 return optional ? ptr : NULL;
51 }
53 const char *
54 osmtpd_ltok_skip_cr(const char *ptr, int optional)
55 {
56 if (ptr[0] == 0xd)
57 return ptr + 1;
58 return optional ? ptr : NULL;
59 }
61 const char *
62 osmtpd_ltok_skip_crlf(const char *ptr, int optional)
63 {
64 if (ptr[0] == 13 && ptr[1] == 10)
65 return ptr + 2;
66 return optional ? ptr : NULL;
67 }
69 const char *
70 osmtpd_ltok_skip_ctl(const char *ptr, int optional)
71 {
72 if ((ptr[0] >= 0x00 && ptr[0] <= 0x1f) || ptr[0] == 0x7f)
73 return ptr + 1;
74 return optional ? ptr : NULL;
75 }
77 const char *
78 osmtpd_ltok_skip_digit(const char *ptr, int optional)
79 {
80 if (ptr[0] >= 0x30 && ptr[0] <= 0x39)
81 return ptr + 1;
82 return optional ? ptr : NULL;
83 }
85 const char *
86 osmtpd_ltok_skip_dquote(const char *ptr, int optional)
87 {
88 if (ptr[0] == 0x22)
89 return ptr + 1;
90 return optional ? ptr : NULL;
91 }
93 const char *
94 osmtpd_ltok_skip_hexdig(const char *ptr, int optional)
95 {
96 const char *start = ptr;
97 char l;
99 if ((ptr = osmtpd_ltok_skip_digit(ptr, 0)) != NULL)
100 return ptr;
101 l = tolower(ptr[0]);
102 if (l == 'a' || l == 'b' || l == 'c' || l == 'd' ||
103 l == 'e' || l == 'f')
104 return ptr + 1;
105 return optional ? start : NULL;
108 const char *
109 osmtpd_ltok_skip_htab(const char *ptr, int optional)
111 if (ptr[0] == 0x9)
112 return ptr + 1;
113 return optional ? ptr : NULL;
116 const char *
117 osmtpd_ltok_skip_lf(const char *ptr, int optional)
119 if (ptr[0] == 0xa)
120 return ptr + 1;
121 return optional ? ptr : NULL;
124 const char *
125 osmtpd_ltok_skip_octet(const char *ptr, int optional)
127 return ptr + 1;
130 const char *
131 osmtpd_ltok_skip_sp(const char *ptr, int optional)
133 if (ptr[0] == 0x20)
134 return ptr + 1;
135 return optional ? ptr : NULL;
138 const char *
139 osmtpd_ltok_skip_vchar(const char *ptr, int optional)
141 if (ptr[0] >= 0x21 && ptr[0] <= 0x7e)
142 return ptr + 1;
143 return optional ? ptr : NULL;
146 const char *
147 osmtpd_ltok_skip_wsp(const char *ptr, int optional)
149 const char *start = ptr;
151 if ((ptr = osmtpd_ltok_skip_sp(start, 0)) != NULL ||
152 (ptr = osmtpd_ltok_skip_htab(start, 0)) != NULL)
153 return ptr;
154 return optional ? start : NULL;
157 /* RFC 5321 - Simple Mail Transfer Protocol */
158 const char *
159 osmtpd_ltok_skip_keyword(const char *ptr, int optional)
161 return osmtpd_ltok_skip_ldh_string(ptr, optional);
164 const char *
165 osmtpd_ltok_skip_sub_domain(const char *ptr, int optional)
167 const char *start = ptr;
169 if ((ptr = osmtpd_ltok_skip_let_dig(ptr, 0)) == NULL)
170 return optional ? start : NULL;
171 return osmtpd_ltok_skip_ldh_string(ptr, 1);
174 const char *
175 osmtpd_ltok_skip_let_dig(const char *ptr, int optional)
177 const char *start = ptr;
179 if ((ptr = osmtpd_ltok_skip_alpha(start, 0)) == NULL &&
180 (ptr = osmtpd_ltok_skip_digit(start, 0)) == NULL)
181 return optional ? start : NULL;
182 return ptr;
185 const char *
186 osmtpd_ltok_skip_ldh_string(const char *ptr, int optional)
188 const char *start = ptr, *prev;
189 int letdig = 0;
191 while (1) {
192 prev = ptr;
193 if ((ptr = osmtpd_ltok_skip_alpha(prev, 0)) != NULL ||
194 (ptr = osmtpd_ltok_skip_digit(prev, 0)) != NULL) {
195 letdig = 1;
196 continue;
198 if (prev[0] == '-') {
199 letdig = 0;
200 ptr = prev + 1;
201 continue;
203 ptr = prev;
204 break;
206 if (letdig)
207 return ptr;
208 if (ptr == start)
209 return optional ? start : NULL;
210 return ptr;
213 /* RFC 5322 - Internet Message Format */
214 const char *
215 osmtpd_ltok_skip_quoted_pair(const char *ptr, int optional)
217 const char *start = ptr;
219 if (ptr[0] == '\\' && (
220 (ptr = osmtpd_ltok_skip_vchar(start + 1, 0)) != NULL ||
221 (ptr = osmtpd_ltok_skip_wsp(start + 1, 0)) != NULL))
222 return ptr;
223 return osmtpd_ltok_skip_obs_qp(start, optional);
226 const char *
227 osmtpd_ltok_skip_fws(const char *ptr, int optional)
229 const char *start = ptr, *prev = ptr;
231 while ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) != NULL)
232 prev = ptr;
233 if ((ptr = osmtpd_ltok_skip_crlf(prev, 1)) == prev)
234 ptr = start;
235 if ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) == NULL)
236 return osmtpd_ltok_skip_obs_fws(start, optional);
237 prev = ptr;
238 while ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) != NULL)
239 prev = ptr;
240 return prev;
243 const char *
244 osmtpd_ltok_skip_ctext(const char *ptr, int optional)
246 const char *start = ptr;
248 if ((ptr[0] >= 33 && ptr[0] <= 39) || (ptr[0] >= 42 && ptr[0] <= 91) ||
249 (ptr[0] >= 93 && ptr[0] <= 126))
250 return ptr + 1;
251 if ((ptr = osmtpd_ltok_skip_obs_ctext(ptr, 0)) != NULL)
252 return ptr;
253 return optional ? start : NULL;
256 const char *
257 osmtpd_ltok_skip_ccontent(const char *ptr, int optional)
259 const char *start = ptr;
261 if ((ptr = osmtpd_ltok_skip_ctext(ptr, 0)) != NULL)
262 return ptr;
263 if ((ptr = osmtpd_ltok_skip_quoted_pair(start, 0)) != NULL)
264 return ptr;
265 if ((ptr = osmtpd_ltok_skip_comment(start, 0)) != NULL)
266 return ptr;
267 return optional ? start : NULL;
270 const char *
271 osmtpd_ltok_skip_comment(const char *ptr, int optional)
273 const char *start = ptr;
275 if (ptr++[0] != '(')
276 return optional ? start : NULL;
277 while (1) {
278 ptr = osmtpd_ltok_skip_fws(ptr, 1);
279 if (ptr[0] == ')')
280 return ptr + 1;
281 if ((ptr = osmtpd_ltok_skip_ccontent(ptr, 0)) == NULL)
282 return optional ? start : NULL;
286 const char *
287 osmtpd_ltok_skip_cfws(const char *ptr, int optional)
289 const char *start = ptr, *prev;
291 while (1) {
292 ptr = osmtpd_ltok_skip_fws(ptr, 1);
293 prev = ptr;
294 if ((ptr = osmtpd_ltok_skip_comment(ptr, 0)) == NULL) {
295 ptr = prev;
296 break;
299 return ptr == start && !optional ? NULL : ptr;
302 const char *
303 osmtpd_ltok_skip_atext(const char *ptr, int optional)
305 const char *start = ptr;
307 if ((ptr = osmtpd_ltok_skip_alpha(start, 0)) != NULL ||
308 (ptr = osmtpd_ltok_skip_digit(start, 0)) != NULL)
309 return ptr;
310 ptr = start;
311 if (ptr[0] == '!' || ptr[0] == '#' || ptr[0] == '$' || ptr[0] == '%' ||
312 ptr[0] == '&' || ptr[0] == '\'' || ptr[0] == '*' || ptr[0] == '+' ||
313 ptr[0] == '-' || ptr[0] == '/' || ptr[0] == '=' || ptr[0] == '?' ||
314 ptr[0] == '^' || ptr[0] == '_' || ptr[0] == '`' || ptr[0] == '{' ||
315 ptr[0] == '|' || ptr[0] == '}' || ptr[0] == '~')
316 return ptr + 1;
317 return optional ? start : NULL;
320 const char *
321 osmtpd_ltok_skip_atom(const char *ptr, int optional)
323 const char *start = ptr, *prev;
325 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
326 if ((ptr = osmtpd_ltok_skip_atext(ptr, 0)) == NULL)
327 return optional ? start : NULL;
328 do {
329 prev = ptr;
330 ptr = osmtpd_ltok_skip_atext(ptr, 1);
331 } while (prev != ptr);
332 return osmtpd_ltok_skip_cfws(ptr, 1);
335 const char *
336 osmtpd_ltok_skip_dot_atom_text(const char *ptr, int optional)
338 const char *start = ptr, *prev;
340 if ((ptr = osmtpd_ltok_skip_atext(ptr, 0)) == NULL)
341 return optional ? start : NULL;
342 do {
343 prev = ptr;
344 ptr = osmtpd_ltok_skip_atext(ptr, 1);
345 } while (ptr != prev);
347 while (ptr[0] == '.') {
348 ptr++;
349 if ((ptr = osmtpd_ltok_skip_atext(ptr, 0)) == NULL)
350 return prev;
351 do {
352 prev = ptr;
353 ptr = osmtpd_ltok_skip_atext(ptr, 1);
354 } while (ptr != prev);
356 return ptr;
359 const char *
360 osmtpd_ltok_skip_dot_atom(const char *ptr, int optional)
362 const char *start = ptr;
364 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
365 if ((ptr = osmtpd_ltok_skip_dot_atom_text(ptr, 0)) == NULL)
366 return optional ? start : NULL;
367 return osmtpd_ltok_skip_cfws(ptr, 1);
370 const char *
371 osmtpd_ltok_skip_qtext(const char *ptr, int optional)
373 const char *start = ptr;
375 if (ptr[0] == 33 || (ptr[0] >= 35 && ptr[0] <= 91) ||
376 (ptr[0] >= 93 && ptr[0] <= 126))
377 return ptr + 1;
378 if ((ptr = osmtpd_ltok_skip_obs_qtext(ptr, 0)) != NULL)
379 return ptr;
380 return optional ? start : NULL;
383 const char *
384 osmtpd_ltok_skip_qcontent(const char *ptr, int optional)
386 const char *start = ptr;
388 if ((ptr = osmtpd_ltok_skip_qtext(ptr, 0)) != NULL)
389 return ptr;
390 return osmtpd_ltok_skip_quoted_pair(start, optional);
393 const char *
394 osmtpd_ltok_skip_quoted_string(const char *ptr, int optional)
396 const char *start = ptr, *prev;
398 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
399 if ((ptr = osmtpd_ltok_skip_dquote(ptr, 0)) == NULL)
400 return optional ? start : NULL;
401 prev = ptr;
402 while (1) {
403 ptr = osmtpd_ltok_skip_fws(ptr, 1);
404 if ((ptr = osmtpd_ltok_skip_qcontent(ptr, 0)) == NULL)
405 break;
406 prev = ptr;
408 if ((ptr = osmtpd_ltok_skip_dquote(prev, 0)) == NULL)
409 return optional ? start : NULL;
410 return osmtpd_ltok_skip_cfws(ptr, 1);
413 const char *
414 osmtpd_ltok_skip_word(const char *ptr, int optional)
416 const char *start = ptr;
418 if ((ptr = osmtpd_ltok_skip_atom(ptr, 0)) != NULL)
419 return ptr;
420 return osmtpd_ltok_skip_quoted_string(start, optional);
423 const char *
424 osmtpd_ltok_skip_phrase(const char *ptr, int optional)
426 /* obs-phrase is a superset of phrae */
427 return osmtpd_ltok_skip_obs_phrase(ptr, optional);
430 const char *
431 osmtpd_ltok_skip_name_addr(const char *ptr, int optional)
433 const char *start = ptr;
435 ptr = osmtpd_ltok_skip_display_name(ptr, 1);
436 if ((ptr = osmtpd_ltok_skip_angle_addr(ptr, 0)) == NULL)
437 return optional ? start : NULL;
438 return ptr;
441 const char *
442 osmtpd_ltok_skip_angle_addr(const char *ptr, int optional)
444 const char *start = ptr;
446 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
447 if (ptr++[0] != '<')
448 return osmtpd_ltok_skip_obs_angle_addr(start, optional);
449 if ((ptr = osmtpd_ltok_skip_addr_spec(ptr, 0)) == NULL)
450 return osmtpd_ltok_skip_obs_angle_addr(start, optional);
451 if (ptr++[0] != '>')
452 return osmtpd_ltok_skip_obs_angle_addr(start, optional);
453 return osmtpd_ltok_skip_cfws(ptr, 1);
456 const char *
457 osmtpd_ltok_skip_display_name(const char *ptr, int optional)
459 return osmtpd_ltok_skip_phrase(ptr, optional);
462 const char *
463 osmtpd_ltok_skip_addr_spec(const char *ptr, int optional)
465 const char *start = ptr;
467 if ((ptr = osmtpd_ltok_skip_local_part(ptr, 0)) == NULL)
468 return optional ? start : NULL;
469 if (ptr++[0] != '@')
470 return optional ? start : NULL;
471 if ((ptr = osmtpd_ltok_skip_domain(ptr, 0)) == NULL)
472 return optional ? start : NULL;
473 return ptr;
476 const char *
477 osmtpd_ltok_skip_local_part(const char *ptr, int optional)
479 const char *start = ptr;
481 if ((ptr = osmtpd_ltok_skip_dot_atom(ptr, 0)) != NULL)
482 return ptr;
483 ptr = start;
484 if ((ptr = osmtpd_ltok_skip_quoted_string(ptr, 0)) != NULL)
485 return ptr;
486 return osmtpd_ltok_skip_obs_local_part(start, optional);
489 const char *
490 osmtpd_ltok_skip_domain(const char *ptr, int optional)
492 const char *start = ptr;
494 if ((ptr = osmtpd_ltok_skip_dot_atom(start, 0)) != NULL)
495 return ptr;
496 if ((ptr = osmtpd_ltok_skip_domain_literal(start, 0)) != NULL)
497 return ptr;
498 return osmtpd_ltok_skip_obs_domain(start, optional);
501 const char *
502 osmtpd_ltok_skip_domain_literal(const char *ptr, int optional)
504 const char *start = ptr, *prev;
506 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
507 if (ptr++[0] != '[')
508 return optional ? start : NULL;
509 while (1) {
510 ptr = osmtpd_ltok_skip_fws(ptr, 1);
511 prev = ptr;
512 if ((ptr = osmtpd_ltok_skip_dtext(ptr, 0)) == NULL) {
513 ptr = prev;
514 break;
517 if (ptr[0] != ']')
518 return optional ? start : NULL;
519 ptr++;
520 return osmtpd_ltok_skip_cfws(ptr, 1);
523 const char *
524 osmtpd_ltok_skip_dtext(const char *ptr, int optional)
526 if ((ptr[0] >= 33 && ptr[0] <= 90) || (ptr[0] >= 94 && ptr[0] <= 126))
527 return ptr + 1;
528 return osmtpd_ltok_skip_obs_dtext(ptr, optional);
532 const char *
533 osmtpd_ltok_skip_field_name(const char *ptr, int optional)
535 const char *start = ptr;
537 if ((ptr = osmtpd_ltok_skip_ftext(ptr, 0)) == NULL)
538 return optional ? start : NULL;
539 while (1) {
540 start = ptr;
541 if ((ptr = osmtpd_ltok_skip_ftext(ptr, 0)) == NULL)
542 return start;
546 const char *
547 osmtpd_ltok_skip_ftext(const char *ptr, int optional)
549 if ((ptr[0] >= 33 && ptr[0] <= 57) ||
550 (ptr[0] >= 59 && ptr[0] <= 126))
551 return ptr + 1;
552 return optional ? ptr : NULL;
555 const char *
556 osmtpd_ltok_skip_obs_no_ws_ctl(const char *ptr, int optional)
558 if ((ptr[0] >= 1 && ptr[0] <= 8) || ptr[0] == 11 || ptr[0] == 12 ||
559 (ptr[0] >= 14 && ptr[0] <= 31) || ptr[0] == 127)
560 return ptr + 1;
561 return optional ? ptr : NULL;
564 const char *
565 osmtpd_ltok_skip_obs_ctext(const char *ptr, int optional)
567 return osmtpd_ltok_skip_obs_no_ws_ctl(ptr, optional);
570 const char *
571 osmtpd_ltok_skip_obs_qtext(const char *ptr, int optional)
573 return osmtpd_ltok_skip_obs_no_ws_ctl(ptr, optional);
576 const char *
577 osmtpd_ltok_skip_obs_qp(const char *ptr, int optional)
579 const char *start = ptr;
581 if (ptr[0] == '\\' && (
582 (ptr = osmtpd_ltok_skip_obs_no_ws_ctl(start + 1, 0)) != NULL ||
583 (ptr = osmtpd_ltok_skip_lf(start + 1, 0)) != NULL ||
584 (ptr = osmtpd_ltok_skip_cr(start + 1, 0)) != NULL))
585 return ptr;
586 return optional ? start : NULL;
589 const char *
590 osmtpd_ltok_skip_obs_phrase(const char *ptr, int optional)
592 const char *start = ptr, *prev;
594 if ((ptr = osmtpd_ltok_skip_word(ptr, 0)) == NULL)
595 return optional ? start : NULL;
596 while (1) {
597 prev = ptr;
598 if ((ptr = osmtpd_ltok_skip_word(ptr, 0)) != NULL)
599 continue;
600 ptr = prev;
601 if (ptr[0] == '.') {
602 ptr++;
603 continue;
605 if ((ptr = osmtpd_ltok_skip_cfws(ptr, 0)) != NULL)
606 continue;
607 return prev;
611 const char *
612 osmtpd_ltok_skip_obs_fws(const char *ptr, int optional)
614 const char *start = ptr, *prev;
616 if ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) == NULL)
617 return optional ? start : NULL;
618 prev = ptr;
619 while ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) != NULL)
620 prev = ptr;
622 ptr = prev;
623 while (1) {
624 if ((ptr = osmtpd_ltok_skip_crlf(ptr, 0)) == NULL)
625 return prev;
626 if ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) == NULL)
627 return prev;
628 prev = ptr;
629 while ((ptr = osmtpd_ltok_skip_wsp(ptr, 0)) != NULL)
630 prev = ptr;
631 ptr = prev;
635 const char *
636 osmtpd_ltok_skip_obs_angle_addr(const char *ptr, int optional)
638 const char *start = ptr;
640 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
641 if (ptr++[0] != '<')
642 return optional ? start : NULL;
643 if ((ptr = osmtpd_ltok_skip_obs_route(ptr, 0)) == NULL)
644 return optional ? start : NULL;
645 if ((ptr = osmtpd_ltok_skip_addr_spec(ptr, 0)) == NULL)
646 return optional ? start : NULL;
647 if (ptr++[0] != '>')
648 return optional ? start : NULL;
649 return osmtpd_ltok_skip_cfws(ptr, 1);
652 const char *
653 osmtpd_ltok_skip_obs_route(const char *ptr, int optional)
655 const char *start = ptr;
657 if ((ptr = osmtpd_ltok_skip_obs_domain_list(ptr, 0)) == NULL)
658 return optional ? start : NULL;
659 if (ptr++[0] != ':')
660 return optional ? start : NULL;
661 return ptr;
664 const char *
665 osmtpd_ltok_skip_obs_domain_list(const char *ptr, int optional)
667 const char *start = ptr, *prev = ptr;
669 while (1) {
670 if (ptr[0] == ',') {
671 ptr++;
672 prev = ptr;
673 continue;
674 } else if ((ptr = osmtpd_ltok_skip_cfws(ptr, 0)) != NULL) {
675 prev = ptr;
676 continue;
678 break;
680 ptr = prev;
682 if (ptr++[0] != '@')
683 return optional ? start : NULL;
684 if ((ptr = osmtpd_ltok_skip_domain(ptr, 0)) == NULL)
685 return optional ? start : NULL;
686 while (1) {
687 if (ptr[0] != ',')
688 break;
689 ptr++;
690 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
691 if (ptr[0] != '@')
692 continue;
693 prev = ptr;
694 if ((ptr = osmtpd_ltok_skip_domain(ptr + 1, 0)) == NULL) {
695 ptr = prev;
696 break;
699 return ptr;
702 const char *
703 osmtpd_ltok_skip_obs_local_part(const char *ptr, int optional)
705 const char *start = ptr, *prev;
707 if ((ptr = osmtpd_ltok_skip_word(ptr, 0)) == NULL)
708 return optional ? start : NULL;
709 prev = ptr;
710 while (ptr[0] == '.') {
711 ptr++;
712 if ((ptr = osmtpd_ltok_skip_word(ptr, 0)) == NULL)
713 return prev;
714 prev = ptr;
716 return ptr;
719 const char *
720 osmtpd_ltok_skip_obs_domain(const char *ptr, int optional)
722 const char *start = ptr, *prev;
724 if ((ptr = osmtpd_ltok_skip_atom(ptr, 0)) == NULL)
725 return optional ? start : NULL;
726 prev = ptr;
727 while (1) {
728 if (ptr++[0] != '.')
729 return prev;
730 if ((ptr = osmtpd_ltok_skip_atom(ptr, 0)) == NULL)
731 return prev;
732 prev = ptr;
736 const char *
737 osmtpd_ltok_skip_obs_dtext(const char *ptr, int optional)
739 const char *start = ptr;
741 if ((ptr = osmtpd_ltok_skip_obs_no_ws_ctl(ptr, 0)) != NULL)
742 return ptr;
743 return osmtpd_ltok_skip_quoted_pair(start, optional);
746 /* RFC 2045 - Multipurpose Internet Mail Extensions */
747 const char *
748 osmtpd_ltok_skip_value(const char *ptr, int optional)
750 const char *start = ptr;
752 if ((ptr = osmtpd_ltok_skip_token(start, 0)) != NULL)
753 return ptr;
754 if ((ptr = osmtpd_ltok_skip_quoted_string(start, 0)) != NULL)
755 return ptr;
756 return optional ? start : NULL;
759 const char *
760 osmtpd_ltok_skip_token(const char *ptr, int optional)
762 const char *start;
763 int first = 1;
765 while (1) {
766 start = ptr;
767 if ((ptr = osmtpd_ltok_skip_char(start, 0)) != NULL &&
768 osmtpd_ltok_skip_sp(start, 0) == NULL &&
769 osmtpd_ltok_skip_ctl(start, 0) == NULL &&
770 osmtpd_ltok_skip_tspecials(start, 0) == NULL) {
771 first = 0;
772 continue;
774 return optional || !first ? start : NULL;
778 const char *
779 osmtpd_ltok_skip_tspecials(const char *ptr, int optional)
781 if (ptr[0] == '(' || ptr[0] == ')' || ptr[0] == '<' || ptr[0] == '>' ||
782 ptr[0] == '@' || ptr[0] == ',' || ptr[0] == ';' || ptr[0] == ':' ||
783 ptr[0] == '\\' || ptr[0] == '"' || ptr[0] == '/' || ptr[0] == '[' ||
784 ptr[0] == ']' || ptr[0] == '?' || ptr[0] == '=')
785 return ptr + 1;
786 return optional ? ptr : NULL;
789 const char *
790 osmtpd_ltok_skip_qp_section(const char *ptr, int optional)
792 const char *prev, *last = ptr;
794 while (1) {
795 prev = ptr;
796 if ((ptr = osmtpd_ltok_skip_ptext(prev, 0)) != NULL)
797 last = ptr;
798 else if ((ptr = osmtpd_ltok_skip_sp(prev, 0)) == NULL &&
799 (ptr = osmtpd_ltok_skip_htab(prev, 0)) == NULL)
800 return last;
804 const char *
805 osmtpd_ltok_skip_ptext(const char *ptr, int optional)
807 const char *start = ptr;
809 if ((ptr = osmtpd_ltok_skip_hex_octet(start, 0)) == NULL &&
810 (ptr = osmtpd_ltok_skip_safe_char(start, 0)) == NULL)
811 return optional ? start : NULL;
812 return ptr;
815 const char *
816 osmtpd_ltok_skip_safe_char(const char *ptr, int optional)
818 if ((ptr[0] >= 33 && ptr[0] <= 60) || (ptr[0] >= 62 && ptr[0] <= 126))
819 return ptr + 1;
820 return optional ? ptr : NULL;
823 const char *
824 osmtpd_ltok_skip_hex_octet(const char *ptr, int optional)
826 const char *start = ptr;
827 char l;
829 if (ptr[0] != '=')
830 return optional ? start : NULL;
831 ptr++;
832 l = tolower(ptr[0]);
833 if (l == 'a' || l == 'b' || l == 'c' || l == 'd' ||
834 l == 'e' || l == 'f')
835 ptr++;
836 else if ((ptr = osmtpd_ltok_skip_digit(ptr, 0)) == NULL)
837 return optional ? start : NULL;
838 l = tolower(ptr[0]);
839 start = ptr;
840 if (l == 'a' || l == 'b' || l == 'c' || l == 'd' ||
841 l == 'e' || l == 'f')
842 ptr++;
843 else if ((ptr = osmtpd_ltok_skip_digit(ptr, 0)) == NULL)
844 return start;
845 return ptr;
848 /* RFC 6376 - DomainKeys Identified Mail (DKIM) Signatures */
849 const char *
850 osmtpd_ltok_skip_hyphenated_word(const char *ptr, int optional)
852 const char *start = ptr, *end, *hyphen;
854 if ((ptr = osmtpd_ltok_skip_alpha(ptr, 0)) == NULL)
855 return optional ? start : NULL;
857 end = ptr;
858 while (1) {
859 if (ptr[0] == '-') {
860 hyphen = hyphen == NULL ? ptr - 1 : hyphen;
861 ptr++;
862 continue;
864 start = ptr;
865 if ((ptr = osmtpd_ltok_skip_alpha(start, 0)) == NULL &&
866 (ptr = osmtpd_ltok_skip_digit(start, 0)) == NULL)
867 break;
868 hyphen = NULL;
869 end = ptr;
872 return hyphen == NULL ? end : hyphen;
875 const char *
876 osmtpd_ltok_skip_alphadigitps(const char *ptr, int optional)
878 const char *end;
880 if ((end = osmtpd_ltok_skip_alpha(ptr, 0)) == NULL &&
881 (end = osmtpd_ltok_skip_digit(ptr, 0)) == NULL &&
882 ptr[0] != '+' && ptr[0] != '/')
883 return optional ? ptr : NULL;
884 return end == NULL ? ptr + 1 : end;
887 const char *
888 osmtpd_ltok_skip_base64string(const char *ptr, int optional)
890 const char *start = ptr;
892 if ((ptr = osmtpd_ltok_skip_alphadigitps(ptr, 0)) == NULL)
893 return optional ? start : NULL;
894 while (1) {
895 start = ptr;
896 ptr = osmtpd_ltok_skip_fws(ptr, 1);
897 if ((ptr = osmtpd_ltok_skip_alphadigitps(ptr, 0)) == NULL)
898 break;
900 ptr = start;
901 ptr = osmtpd_ltok_skip_fws(ptr, 1);
902 if (ptr[0] == '=') {
903 ptr++;
904 start = ptr;
905 ptr = osmtpd_ltok_skip_fws(ptr, 1);
906 if (ptr[0] == '=')
907 ptr++;
908 else
909 ptr = start;
910 } else
911 ptr = start;
912 return ptr;
915 const char *
916 osmtpd_ltok_skip_hdr_name(const char *ptr, int optional)
918 return osmtpd_ltok_skip_field_name(ptr, optional);
921 const char *
922 osmtpd_ltok_skip_qp_hdr_value(const char *ptr, int optional)
924 return osmtpd_ltok_skip_dkim_quoted_printable(ptr, optional);
927 const char *
928 osmtpd_ltok_skip_dkim_quoted_printable(const char *ptr, int optional)
930 const char *start;
932 while (1) {
933 start = ptr;
934 if ((ptr = osmtpd_ltok_skip_fws(start, 0)) != NULL)
935 continue;
936 if ((ptr = osmtpd_ltok_skip_hex_octet(start, 0)) != NULL)
937 continue;
938 ptr = osmtpd_ltok_skip_dkim_safe_char(start, 0);
939 if (ptr == NULL)
940 break;
942 return start;
945 const char *
946 osmtpd_ltok_skip_dkim_safe_char(const char *ptr, int optional)
948 if ((ptr[0] >= 0x21 && ptr[0] <= 0x3a) || ptr[0] == 0x3c ||
949 (ptr[0] >= 0x3e && ptr[0] <= 0x7e))
950 return ptr + 1;
951 return optional ? ptr : NULL;
954 const char *
955 osmtpd_ltok_skip_selector(const char *ptr, int optional)
957 const char *start = ptr;
959 if ((ptr = osmtpd_ltok_skip_sub_domain(ptr, 0)) == NULL)
960 return optional ? start : NULL;
961 while (1) {
962 start = ptr;
963 if (ptr[0] != '.')
964 return start;
965 ptr++;
966 if ((ptr = osmtpd_ltok_skip_sub_domain(ptr, 0)) == NULL)
967 return start;
971 const char *
972 osmtpd_ltok_skip_tag_list(const char *ptr, int optional)
974 const char *start = ptr;
976 if ((ptr = osmtpd_ltok_skip_tag_spec(ptr, 0)) == NULL)
977 return optional ? start : NULL;
978 while (1) {
979 /* Starting or trailing ';' */
980 if (ptr[0] != ';')
981 return ptr;
982 ptr++;
983 start = ptr;
984 if ((ptr = osmtpd_ltok_skip_tag_spec(ptr, 0)) == NULL)
985 return start;
989 const char *
990 osmtpd_ltok_skip_tag_spec(const char *ptr, int optional)
992 const char *start = ptr;
994 ptr = osmtpd_ltok_skip_fws(ptr, 1);
995 if ((ptr = osmtpd_ltok_skip_tag_name(ptr, 0)) == NULL)
996 return optional ? start : NULL;
997 ptr = osmtpd_ltok_skip_fws(ptr, 1);
998 if (ptr[0] != '=')
999 return optional ? start : NULL;
1000 ptr++;
1001 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1002 if ((ptr = osmtpd_ltok_skip_tag_value(ptr, 0)) == NULL)
1003 return optional ? start : NULL;
1004 return osmtpd_ltok_skip_fws(ptr, 1);
1007 const char *
1008 osmtpd_ltok_skip_tag_name(const char *ptr, int optional)
1010 const char *start = ptr, *prev;
1012 if ((ptr = osmtpd_ltok_skip_alpha(ptr, 0)) == NULL)
1013 return optional ? start : NULL;
1014 prev = ptr;
1015 while ((ptr = osmtpd_ltok_skip_alnumpunc(ptr, 0)) != NULL)
1016 prev = ptr;
1017 return prev;
1020 const char *
1021 osmtpd_ltok_skip_tag_value(const char *ptr, int optional)
1023 const char *start = ptr, *prev;
1025 if ((ptr = osmtpd_ltok_skip_tval(ptr, 0)) == NULL)
1026 return start;
1028 while (1) {
1029 start = ptr;
1030 /* FWS contains WSP */
1031 if ((ptr = osmtpd_ltok_skip_fws(ptr, 0)) == NULL)
1032 return start;
1033 prev = ptr;
1034 while ((ptr = osmtpd_ltok_skip_fws(ptr, 0)) != NULL)
1035 prev = ptr;
1036 ptr = prev;
1037 if ((ptr = osmtpd_ltok_skip_tval(ptr, 0)) == NULL)
1038 return start;
1042 const char *
1043 osmtpd_ltok_skip_tval(const char *ptr, int optional)
1045 const char *start = ptr, *prev;
1047 if ((ptr = osmtpd_ltok_skip_valchar(ptr, 0)) == NULL)
1048 return optional ? start : NULL;
1049 prev = ptr;
1050 while ((ptr = osmtpd_ltok_skip_valchar(ptr, 0)) != NULL)
1051 prev = ptr;
1052 return prev;
1055 const char *
1056 osmtpd_ltok_skip_valchar(const char *ptr, int optional)
1058 if ((ptr[0] >= 0x21 && ptr[0] <= 0x3A) ||
1059 (ptr[0] >= 0x3C && ptr[0] <= 0x7E))
1060 return ptr + 1;
1061 return optional ? ptr : NULL;
1064 const char *
1065 osmtpd_ltok_skip_alnumpunc(const char *ptr, int optional)
1067 const char *start = ptr;
1069 if ((ptr = osmtpd_ltok_skip_alpha(start, 0)) != NULL)
1070 return ptr;
1071 if ((ptr = osmtpd_ltok_skip_digit(start, 0)) != NULL)
1072 return ptr;
1073 if (start[0] == '_')
1074 return start + 1;
1075 return optional ? start : NULL;
1078 const char *
1079 osmtpd_ltok_skip_sig_v_tag(const char *ptr, int optional)
1081 const char *start = ptr;
1083 if (ptr[0] != 0x76)
1084 return optional ? start : NULL;
1085 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1086 if (ptr[0] != '=')
1087 return optional ? start : NULL;
1088 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1089 if ((ptr = osmtpd_ltok_skip_sig_v_tag_value(ptr, 0)) == NULL)
1090 return optional ? start : NULL;
1091 return ptr;
1094 const char *
1095 osmtpd_ltok_skip_sig_v_tag_value(const char *ptr, int optional)
1097 const char *start = ptr, *prev;
1099 if ((ptr = osmtpd_ltok_skip_digit(ptr, 0)) == NULL)
1100 return optional ? start : NULL;
1101 while (1) {
1102 prev = ptr;
1103 if ((ptr = osmtpd_ltok_skip_digit(ptr, 0)) == NULL)
1104 return prev;
1108 const char *
1109 osmtpd_ltok_skip_sig_a_tag(const char *ptr, int optional)
1111 const char *start = ptr;
1113 if (ptr[0] != 0x61)
1114 return optional ? start : NULL;
1115 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1116 if (ptr[0] != '=')
1117 return optional ? start : NULL;
1118 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1119 if ((ptr = osmtpd_ltok_skip_sig_a_tag_value(ptr, 0)) == NULL)
1120 return optional ? start : NULL;
1121 return ptr;
1124 const char *
1125 osmtpd_ltok_skip_sig_a_tag_value(const char *ptr, int optional)
1127 return osmtpd_ltok_skip_sig_a_tag_alg(ptr, optional);
1130 const char *
1131 osmtpd_ltok_skip_sig_a_tag_alg(const char *ptr, int optional)
1133 const char *start = ptr;
1135 if ((ptr = osmtpd_ltok_skip_sig_a_tag_k(ptr, 0)) == NULL)
1136 return optional ? start : NULL;
1137 if (ptr[0] != '-')
1138 return optional ? start : NULL;
1139 ptr++;
1140 if ((ptr = osmtpd_ltok_skip_sig_a_tag_h(ptr, 0)) == NULL)
1141 return optional ? start : NULL;
1142 return ptr;
1145 const char *
1146 osmtpd_ltok_skip_sig_a_tag_k(const char *ptr, int optional)
1148 /* sha1 / sha256 covered by x-sig-a-tag-k */
1149 return osmtpd_ltok_skip_x_sig_a_tag_k(ptr, optional);
1152 const char *
1153 osmtpd_ltok_skip_sig_a_tag_h(const char *ptr, int optional)
1155 /* rsa / ed25519 covered by x-sig-a-tag-h */
1156 return osmtpd_ltok_skip_x_sig_a_tag_h(ptr, optional);
1159 const char *
1160 osmtpd_ltok_skip_x_sig_a_tag_k(const char *ptr, int optional)
1162 const char *start = ptr, *prev, *end;
1164 if ((ptr = osmtpd_ltok_skip_alpha(ptr, 0)) == NULL)
1165 return optional ? start : NULL;
1166 prev = ptr;
1167 while ((end = osmtpd_ltok_skip_alpha(ptr, 0)) != NULL ||
1168 (end = osmtpd_ltok_skip_digit(ptr, 0)) != NULL) {
1169 ptr = end;
1170 prev = end;
1172 return prev;
1175 const char *
1176 osmtpd_ltok_skip_x_sig_a_tag_h(const char *ptr, int optional)
1178 const char *start = ptr, *prev, *end;
1180 if ((ptr = osmtpd_ltok_skip_alpha(ptr, 0)) == NULL)
1181 return optional ? start : NULL;
1182 prev = ptr;
1183 while ((end = osmtpd_ltok_skip_alpha(ptr, 0)) != NULL ||
1184 (end = osmtpd_ltok_skip_digit(ptr, 0)) != NULL) {
1185 ptr = end;
1186 prev = end;
1188 return prev;
1191 const char *
1192 osmtpd_ltok_skip_sig_b_tag(const char *ptr, int optional)
1194 const char *start = ptr;
1196 if (ptr[0] != 0x62)
1197 return optional ? start : NULL;
1198 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1199 if (ptr[0] != '=')
1200 return optional ? start : NULL;
1201 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1202 if ((ptr = osmtpd_ltok_skip_sig_b_tag_value(ptr, 0)) == NULL)
1203 return optional ? start : NULL;
1204 return ptr;
1207 const char *
1208 osmtpd_ltok_skip_sig_b_tag_value(const char *ptr, int optional)
1210 return osmtpd_ltok_skip_sig_b_tag_data(ptr, optional);
1213 const char *
1214 osmtpd_ltok_skip_sig_b_tag_data(const char *ptr, int optional)
1216 return osmtpd_ltok_skip_base64string(ptr, optional);
1219 const char *
1220 osmtpd_ltok_skip_sig_bh_tag(const char *ptr, int optional)
1222 const char *start = ptr;
1224 if (ptr[0] != 0x62 && ptr[0] != 0x68)
1225 return optional ? start : NULL;
1226 ptr = osmtpd_ltok_skip_fws(ptr + 2, 1);
1227 if (ptr[0] != '=')
1228 return optional ? start : NULL;
1229 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1230 if ((ptr = osmtpd_ltok_skip_sig_bh_tag_value(ptr, 0)) == NULL)
1231 return optional ? start : NULL;
1232 return ptr;
1235 const char *
1236 osmtpd_ltok_skip_sig_bh_tag_value(const char *ptr, int optional)
1238 return osmtpd_ltok_skip_sig_bh_tag_data(ptr, optional);
1241 const char *
1242 osmtpd_ltok_skip_sig_bh_tag_data(const char *ptr, int optional)
1244 return osmtpd_ltok_skip_base64string(ptr, optional);
1247 const char *
1248 osmtpd_ltok_skip_sig_c_tag(const char *ptr, int optional)
1250 const char *start = ptr;
1252 if (ptr[0] != 0x63)
1253 return optional ? start : NULL;
1254 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1255 if (ptr[0] != '=')
1256 return optional ? start : NULL;
1257 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1258 if ((ptr = osmtpd_ltok_skip_sig_c_tag_value(ptr, 0)) == NULL)
1259 return optional ? start : NULL;
1260 return ptr;
1263 const char *
1264 osmtpd_ltok_skip_sig_c_tag_value(const char *ptr, int optional)
1266 const char *start = ptr;
1268 if ((ptr = osmtpd_ltok_skip_sig_c_tag_alg(ptr, 0)) == NULL)
1269 return optional ? start : NULL;
1270 if (ptr[0] == '/') {
1271 start = ptr;
1272 if ((ptr = osmtpd_ltok_skip_sig_c_tag_alg(ptr, 0)) == NULL)
1273 return start;
1275 return ptr;
1278 const char *
1279 osmtpd_ltok_skip_sig_c_tag_alg(const char *ptr, int optional)
1281 /* simple / relaxed covered by x-sig-c-tag-alga */
1282 return osmtpd_ltok_skip_x_sig_c_tag_alg(ptr, optional);
1285 const char *
1286 osmtpd_ltok_skip_x_sig_c_tag_alg(const char *ptr, int optional)
1288 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1291 const char *
1292 osmtpd_ltok_skip_sig_d_tag(const char *ptr, int optional)
1294 const char *start = ptr;
1296 if (ptr[0] != 0x64)
1297 return optional ? start : NULL;
1298 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1299 if (ptr[0] != '=')
1300 return optional ? start : NULL;
1301 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1302 if ((ptr = osmtpd_ltok_skip_sig_d_tag_value(ptr, 0)) == NULL)
1303 return optional ? start : NULL;
1304 return ptr;
1307 const char *
1308 osmtpd_ltok_skip_sig_d_tag_value(const char *ptr, int optional)
1310 return osmtpd_ltok_skip_domain_name(ptr, optional);
1313 const char *
1314 osmtpd_ltok_skip_domain_name(const char *ptr, int optional)
1316 const char *prev = ptr;
1318 if ((ptr = osmtpd_ltok_skip_sub_domain(ptr, 0)) == NULL)
1319 return optional ? prev : NULL;
1320 while (1) {
1321 prev = ptr;
1322 if (ptr[0] != '.' ||
1323 (ptr = osmtpd_ltok_skip_sub_domain(ptr + 1, 0)) == NULL)
1324 return prev;
1328 const char *
1329 osmtpd_ltok_skip_sig_h_tag(const char *ptr, int optional)
1331 const char *start = ptr;
1333 if (ptr[0] != 0x68)
1334 return optional ? start : NULL;
1335 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1336 if (ptr[0] != '=')
1337 return optional ? start : NULL;
1338 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1339 if ((ptr = osmtpd_ltok_skip_sig_h_tag_value(ptr, 0)) == NULL)
1340 return optional ? start : NULL;
1341 return ptr;
1344 const char *
1345 osmtpd_ltok_skip_sig_h_tag_value(const char *ptr, int optional)
1347 const char *prev = ptr;
1349 if ((ptr = osmtpd_ltok_skip_hdr_name(ptr, 0)) == NULL)
1350 return optional ? prev : NULL;
1351 while (1) {
1352 prev = ptr;
1353 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1354 if (ptr[0] != ':')
1355 return prev;
1356 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1357 if ((ptr = osmtpd_ltok_skip_hdr_name(ptr, 0)) == NULL)
1358 return prev;
1362 const char *
1363 osmtpd_ltok_skip_sig_i_tag(const char *ptr, int optional)
1365 const char *start = ptr;
1367 if (ptr[0] != 0x69)
1368 return optional ? start : NULL;
1369 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1370 if (ptr[0] != '=')
1371 return optional ? start : NULL;
1372 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1373 if ((ptr = osmtpd_ltok_skip_sig_i_tag_value(ptr, 0)) == NULL)
1374 return optional ? start : NULL;
1375 return ptr;
1378 const char *
1379 osmtpd_ltok_skip_sig_i_tag_value(const char *ptr, int optional)
1381 const char *start = ptr;
1383 ptr = osmtpd_ltok_skip_local_part(ptr, 1);
1384 if (ptr[0] != '@' ||
1385 (ptr = osmtpd_ltok_skip_domain_name(ptr, 0)) == NULL)
1386 return optional ? start : NULL;
1387 return ptr;
1390 const char *
1391 osmtpd_ltok_skip_sig_l_tag(const char *ptr, int optional)
1393 const char *start = ptr;
1395 if (ptr[0] != 0x6c)
1396 return optional ? start : NULL;
1397 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1398 if (ptr[0] != '=')
1399 return optional ? start : NULL;
1400 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1401 if ((ptr = osmtpd_ltok_skip_sig_l_tag_value(ptr, 0)) == NULL)
1402 return optional ? start : NULL;
1403 return ptr;
1406 const char *
1407 osmtpd_ltok_skip_sig_l_tag_value(const char *ptr, int optional)
1409 size_t i;
1411 for (i = 0; i < 76; i++) {
1412 if (osmtpd_ltok_skip_digit(ptr + i, 0) == NULL)
1413 break;
1415 if (i >= 1 && i <= 76)
1416 return ptr + i;
1417 return optional ? ptr : NULL;
1420 const char *
1421 osmtpd_ltok_skip_sig_q_tag(const char *ptr, int optional)
1423 const char *start = ptr;
1425 if (ptr[0] != 0x71)
1426 return optional ? start : NULL;
1427 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1428 if (ptr[0] != '=')
1429 return optional ? start : NULL;
1430 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1431 if ((ptr = osmtpd_ltok_skip_sig_q_tag_value(ptr, 0)) == NULL)
1432 return optional ? start : NULL;
1433 return ptr;
1436 const char *
1437 osmtpd_ltok_skip_sig_q_tag_value(const char *ptr, int optional)
1439 const char *prev = ptr;
1440 if ((ptr = osmtpd_ltok_skip_sig_q_tag_method(ptr, 0)) == NULL)
1441 return optional ? prev : NULL;
1442 while (1) {
1443 prev = ptr;
1444 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1445 if (ptr[0] != ':')
1446 return prev;
1447 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1448 if ((ptr = osmtpd_ltok_skip_sig_q_tag_method(ptr, 0)) == NULL)
1449 return prev;
1453 const char *
1454 osmtpd_ltok_skip_sig_q_tag_method(const char *ptr, int optional)
1456 const char *start = ptr;
1458 /* dns/txt covered by x-sig-q-tag-type ["/" x-sig-q-tag-args] */
1459 if ((ptr = osmtpd_ltok_skip_x_sig_q_tag_type(ptr, 0)) == NULL)
1460 return optional ? start : NULL;
1461 start = ptr;
1462 if (ptr[0] != '/')
1463 return ptr;
1464 if ((ptr = osmtpd_ltok_skip_x_sig_q_tag_args(ptr, 0)) == NULL)
1465 return start;
1466 return ptr;
1469 const char *
1470 osmtpd_ltok_skip_x_sig_q_tag_type(const char *ptr, int optional)
1472 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1475 const char *
1476 osmtpd_ltok_skip_x_sig_q_tag_args(const char *ptr, int optional)
1478 return osmtpd_ltok_skip_qp_hdr_value(ptr, optional);
1481 const char *
1482 osmtpd_ltok_skip_sig_s_tag(const char *ptr, int optional)
1484 const char *start = ptr;
1486 if (ptr[0] != 0x73)
1487 return optional ? start : NULL;
1488 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1489 if (ptr[0] != '=')
1490 return optional ? start : NULL;
1491 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1492 if ((ptr = osmtpd_ltok_skip_sig_s_tag_value(ptr, 0)) == NULL)
1493 return optional ? start : NULL;
1494 return ptr;
1497 const char *
1498 osmtpd_ltok_skip_sig_s_tag_value(const char *ptr, int optional)
1500 return osmtpd_ltok_skip_selector(ptr, optional);
1503 const char *
1504 osmtpd_ltok_skip_sig_t_tag(const char *ptr, int optional)
1506 const char *start = ptr;
1508 if (ptr[0] != 0x74)
1509 return optional ? start : NULL;
1510 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1511 if (ptr[0] != '=')
1512 return optional ? start : NULL;
1513 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1514 if ((ptr = osmtpd_ltok_skip_sig_t_tag_value(ptr, 0)) == NULL)
1515 return optional ? start : NULL;
1516 return ptr;
1519 const char *
1520 osmtpd_ltok_skip_sig_t_tag_value(const char *ptr, int optional)
1522 size_t i;
1524 for (i = 0; i < 12; i++) {
1525 if (osmtpd_ltok_skip_digit(ptr + i, 0) == NULL)
1526 break;
1528 if (i >= 1 && i <= 12)
1529 return ptr + i;
1530 return optional ? ptr : NULL;
1533 const char *
1534 osmtpd_ltok_skip_sig_x_tag(const char *ptr, int optional)
1536 const char *start = ptr;
1538 if (ptr[0] != 0x78)
1539 return optional ? start : NULL;
1540 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1541 if (ptr[0] != '=')
1542 return optional ? start : NULL;
1543 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1544 if ((ptr = osmtpd_ltok_skip_sig_x_tag_value(ptr, 0)) == NULL)
1545 return optional ? start : NULL;
1546 return ptr;
1549 const char *
1550 osmtpd_ltok_skip_sig_x_tag_value(const char *ptr, int optional)
1552 size_t i;
1554 for (i = 0; i < 12; i++) {
1555 if (osmtpd_ltok_skip_digit(ptr + i, 0) == NULL)
1556 break;
1558 if (i >= 1 && i <= 12)
1559 return ptr + i;
1560 return optional ? ptr : NULL;
1563 const char *
1564 osmtpd_ltok_skip_sig_z_tag(const char *ptr, int optional)
1566 const char *start = ptr;
1568 if (ptr[0] != 0x7a)
1569 return optional ? start : NULL;
1570 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1571 if (ptr[0] != '=')
1572 return optional ? start : NULL;
1573 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1574 if ((ptr = osmtpd_ltok_skip_sig_z_tag_value(ptr, 0)) == NULL)
1575 return optional ? start : NULL;
1576 return ptr;
1579 const char *
1580 osmtpd_ltok_skip_sig_z_tag_value(const char *ptr, int optional)
1582 const char *prev = ptr;
1584 if ((ptr = osmtpd_ltok_skip_sig_z_tag_copy(ptr, 0)) == NULL)
1585 return optional ? ptr : NULL;
1586 while (1) {
1587 prev = ptr;
1588 if (ptr[0] != '|')
1589 return prev;
1590 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1591 if ((ptr = osmtpd_ltok_skip_sig_z_tag_copy(ptr, 0)) == NULL)
1592 return prev;
1596 const char *
1597 osmtpd_ltok_skip_sig_z_tag_copy(const char *ptr, int optional)
1599 const char *start = ptr;
1601 if ((ptr = osmtpd_ltok_skip_hdr_name(ptr, 0)) == NULL)
1602 return optional ? start : NULL;
1603 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1604 if (ptr[0] != ':')
1605 return optional ? start : NULL;
1606 if ((ptr = osmtpd_ltok_skip_qp_hdr_value(ptr, 0)) == NULL)
1607 return optional ? start : NULL;
1608 return ptr;
1611 const char *
1612 osmtpd_ltok_skip_key_v_tag(const char *ptr, int optional)
1614 const char *start = ptr;
1616 if (ptr[0] != 0x76)
1617 return optional ? start : NULL;
1618 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1619 if (ptr[0] != '=')
1620 return optional ? start : NULL;
1621 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1622 if ((ptr = osmtpd_ltok_skip_key_v_tag_value(ptr, 0)) == NULL)
1623 return optional ? start : NULL;
1624 return ptr;
1627 const char *
1628 osmtpd_ltok_skip_key_v_tag_value(const char *ptr, int optional)
1630 if (ptr[0] == 0x44 && ptr[1] == 0x4b && ptr[2] == 0x49 &&
1631 ptr[3] == 0x4d && ptr[4] == 0x31)
1632 return ptr + 5;
1633 return optional ? ptr : NULL;
1636 const char *
1637 osmtpd_ltok_skip_key_h_tag(const char *ptr, int optional)
1639 const char *start = ptr;
1641 if (ptr[0] != 0x68)
1642 return optional ? start : NULL;
1643 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1644 if (ptr[0] != '=')
1645 return optional ? start : NULL;
1646 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1647 if ((ptr = osmtpd_ltok_skip_key_h_tag_value(ptr, 0)) == NULL)
1648 return optional ? start : NULL;
1649 return ptr;
1652 const char *
1653 osmtpd_ltok_skip_key_h_tag_value(const char *ptr, int optional)
1655 const char *prev = ptr;
1657 if ((prev = osmtpd_ltok_skip_key_h_tag_alg(ptr, 0)) == NULL)
1658 return optional ? prev : NULL;
1659 while (1) {
1660 prev = ptr;
1661 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1662 if (ptr[0] != ':')
1663 return prev;
1664 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1665 if ((ptr = osmtpd_ltok_skip_key_h_tag_alg(ptr, 0)) == NULL)
1666 return prev;
1670 const char *
1671 osmtpd_ltok_skip_key_h_tag_alg(const char *ptr, int optional)
1673 /* sha1 / sha256 covered by x-key-h-tag-alg */
1674 return osmtpd_ltok_skip_x_key_h_tag_alg(ptr, optional);
1677 const char *
1678 osmtpd_ltok_skip_x_key_h_tag_alg(const char *ptr, int optional)
1680 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1683 const char *
1684 osmtpd_ltok_skip_key_k_tag(const char *ptr, int optional)
1686 const char *start = ptr;
1688 if (ptr[0] != 0x6b)
1689 return optional ? start : NULL;
1690 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1691 if (ptr[0] != '=')
1692 return optional ? start : NULL;
1693 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1694 if ((ptr = osmtpd_ltok_skip_key_k_tag_value(ptr, 0)) == NULL)
1695 return optional ? start : NULL;
1696 return ptr;
1699 const char *
1700 osmtpd_ltok_skip_key_k_tag_value(const char *ptr, int optional)
1702 const char *start = ptr;
1704 if ((ptr = osmtpd_ltok_skip_key_k_tag_type(ptr, 0)) == NULL)
1705 return optional ? start : NULL;
1706 return ptr;
1709 const char *
1710 osmtpd_ltok_skip_key_k_tag_type(const char *ptr, int optional)
1712 /* rsa covered by x-key-k-tag-type */
1713 return osmtpd_ltok_skip_x_key_k_tag_type(ptr, optional);
1716 const char *
1717 osmtpd_ltok_skip_x_key_k_tag_type(const char *ptr, int optional)
1719 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1722 const char *
1723 osmtpd_ltok_skip_key_n_tag(const char *ptr, int optional)
1725 const char *start = ptr;
1727 if (ptr[0] != 0x6e)
1728 return optional ? start : NULL;
1729 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1730 if (ptr[0] != '=')
1731 return optional ? start : NULL;
1732 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1733 if ((ptr = osmtpd_ltok_skip_key_n_tag_value(ptr, 0)) == NULL)
1734 return optional ? start : NULL;
1735 return ptr;
1738 const char *
1739 osmtpd_ltok_skip_key_n_tag_value(const char *ptr, int optional)
1741 return osmtpd_ltok_skip_qp_section(ptr, optional);
1744 const char *
1745 osmtpd_ltok_skip_key_p_tag(const char *ptr, int optional)
1747 const char *start = ptr;
1749 if (ptr[0] != 0x70)
1750 return optional ? start : NULL;
1751 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1752 if (ptr[0] != '=')
1753 return optional ? start : NULL;
1754 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1755 if ((ptr = osmtpd_ltok_skip_key_p_tag_value(ptr, 0)) == NULL)
1756 return optional ? start : NULL;
1757 return ptr;
1760 const char *
1761 osmtpd_ltok_skip_key_p_tag_value(const char *ptr, int optional)
1763 const char *start = ptr;
1765 if ((ptr = osmtpd_ltok_skip_base64string(ptr, 0)) == NULL)
1766 return optional ? start : NULL;
1767 return ptr;
1770 const char *
1771 osmtpd_ltok_skip_key_s_tag(const char *ptr, int optional)
1773 const char *start = ptr;
1775 if (ptr[0] != 0x73)
1776 return optional ? start : NULL;
1777 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1778 if (ptr[0] != '=')
1779 return optional ? start : NULL;
1780 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1781 if ((ptr = osmtpd_ltok_skip_key_s_tag_value(ptr, 0)) == NULL)
1782 return optional ? start : NULL;
1783 return ptr;
1786 const char *
1787 osmtpd_ltok_skip_key_s_tag_value(const char *ptr, int optional)
1789 const char *start = ptr;
1791 if ((ptr = osmtpd_ltok_skip_key_s_tag_type(ptr, 0)) == NULL)
1792 return optional ? start : NULL;
1793 while (1) {
1794 start = ptr;
1795 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1796 if (ptr[0] != ':')
1797 return start;
1798 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1799 ptr = osmtpd_ltok_skip_key_s_tag_type(ptr, 0);
1800 if (ptr == NULL)
1801 return start;
1805 const char *
1806 osmtpd_ltok_skip_key_s_tag_type(const char *ptr, int optional)
1808 if (ptr[0] == '*')
1809 return ptr + 1;
1810 /* email covered by x-key-s-tag-type */
1811 return osmtpd_ltok_skip_x_key_s_tag_type(ptr, optional);
1814 const char *
1815 osmtpd_ltok_skip_x_key_s_tag_type(const char *ptr, int optional)
1817 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1820 const char *
1821 osmtpd_ltok_skip_key_t_tag(const char *ptr, int optional)
1823 const char *start = ptr;
1825 if (ptr[0] != 0x74)
1826 return optional ? start : NULL;
1827 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1828 if (ptr[0] != '=')
1829 return optional ? start : NULL;
1830 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1831 if ((ptr = osmtpd_ltok_skip_key_t_tag_value(ptr, 0)) == NULL)
1832 return optional ? start : NULL;
1833 return ptr;
1836 const char *
1837 osmtpd_ltok_skip_key_t_tag_value(const char *ptr, int optional)
1839 const char *start = ptr;
1841 if ((ptr = osmtpd_ltok_skip_key_t_tag_flag(ptr, 0)) == NULL)
1842 return optional ? start : NULL;
1843 while (1) {
1844 start = ptr;
1845 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1846 if (ptr[0] != ':')
1847 return start;
1848 ptr = osmtpd_ltok_skip_fws(ptr + 1, 1);
1849 ptr = osmtpd_ltok_skip_key_t_tag_flag(ptr, 0);
1850 if (ptr == NULL)
1851 return start;
1855 const char *
1856 osmtpd_ltok_skip_key_t_tag_flag(const char *ptr, int optional)
1858 /* y / s covered by x-key-t-tag-flag */
1859 return osmtpd_ltok_skip_x_key_t_tag_flag(ptr, optional);
1862 const char *
1863 osmtpd_ltok_skip_x_key_t_tag_flag(const char *ptr, int optional)
1865 return osmtpd_ltok_skip_hyphenated_word(ptr, optional);
1868 const char *
1869 osmtpd_ltok_skip_ar_pvalue(const char *ptr, int optional)
1871 const char *start = ptr, *tmp;
1873 ptr = osmtpd_ltok_skip_cfws(ptr, 1);
1874 if ((tmp = osmtpd_ltok_skip_value(ptr, 0)) != NULL)
1875 return tmp;
1876 ptr = osmtpd_ltok_skip_local_part(ptr, 1);
1877 if (ptr[0] == '@')
1878 ptr++;
1879 if ((ptr = osmtpd_ltok_skip_domain(ptr, 0)) == NULL)
1880 return optional ? start : NULL;
1881 return ptr;