commit 2bff1e0dd3746ad335de1c4fcc8f43e7790b4839 from: Kirill A. Korinsky date: Fri Jan 31 23:33:46 2025 UTC Simplified parser of AR header which should improve it's stability on edge cases as well. commit - 5f5f9df0fb9731664a2b3fe1c002f569aaa9239e commit + 2bff1e0dd3746ad335de1c4fcc8f43e7790b4839 blob - a80fe73155a15ab043e1a707f959f87e196668da blob + c655cc4e4bb605f09ee68cf2aae27c8c0359340e --- ltok.c +++ ltok.c @@ -1862,15 +1862,88 @@ osmtpd_ltok_skip_x_key_t_tag_flag(const char *ptr, int const char * osmtpd_ltok_skip_ar_pvalue(const char *ptr, int optional) { - const char *start = ptr, *tmp; + const char *start = ptr, *value, *addr, *local; - ptr = osmtpd_ltok_skip_cfws(ptr, 1); - if ((tmp = osmtpd_ltok_skip_value(ptr, 0)) != NULL) - return tmp; - ptr = osmtpd_ltok_skip_local_part(ptr, 1); - if (ptr[0] == '@') - ptr++; - if ((ptr = osmtpd_ltok_skip_domain(ptr, 0)) == NULL) + ptr = osmtpd_ltok_skip_cfws(start, 1); + + value = osmtpd_ltok_skip_value(ptr, 1); + addr = osmtpd_ltok_skip_addr_spec(ptr, 1); + local = osmtpd_ltok_skip_local_part(ptr, 1); + + if (value > ptr) + ptr = value; + + if (addr > ptr) + ptr = addr; + + if (local > ptr) + ptr = local; + + if (ptr == NULL) return optional ? start : NULL; + return ptr; } + +const char * +osmtpd_ltok_skip_ar_propspec(const char *ptr, int optional) +{ + const char *start = ptr; + + if (strncmp(ptr, "smtp", sizeof("smtp") - 1) == 0) + ptr += sizeof("smtp") - 1; + else if (strncmp(ptr, "header", sizeof("header") - 1) == 0) + ptr += sizeof("header") - 1; + else if (strncmp(ptr, "body", sizeof("body") - 1) == 0) + ptr += sizeof("body") - 1; + else if (strncmp(ptr, "policy", sizeof("policy") - 1) == 0) + ptr += sizeof("policy") - 1; + else + return optional ? start : NULL; + + ptr = osmtpd_ltok_skip_cfws(ptr, 1); + + if (*ptr != '.') + return optional ? start : NULL; + ptr++; + + ptr = osmtpd_ltok_skip_cfws(ptr, 1); + + if ((ptr = osmtpd_ltok_skip_keyword(ptr, 0)) == NULL) + return optional ? start : NULL; + + ptr = osmtpd_ltok_skip_cfws(ptr, 1); + + if (*ptr != '=') + return optional ? start : NULL; + ptr++; + + if ((ptr = osmtpd_ltok_skip_ar_pvalue(ptr, 0)) == NULL) + return optional ? start : NULL; + + return ptr; +} + +const char * +osmtpd_ltok_skip_ar_reasonspec(const char *ptr, int optional) +{ + const char *start = ptr; + + if (strncmp(ptr, "reason", sizeof("reason") - 1) != 0) + return optional ? start : NULL; + + ptr += sizeof("reason") - 1; + + ptr = osmtpd_ltok_skip_cfws(ptr, 1); + + if (*ptr != '=') + return optional ? start : NULL; + ptr++; + + ptr = osmtpd_ltok_skip_cfws(ptr, 1); + + if ((ptr = osmtpd_ltok_skip_value(ptr, 0)) == NULL) + return optional ? start : NULL; + + return ptr; +} blob - cee68002870cea1b7b26b1c6f40800b7b93f04c1 blob + cfc1e74a9bf973c4ca7a00ced5849076188a2453 --- ltok.h +++ ltok.h @@ -167,6 +167,8 @@ const char *osmtpd_ltok_skip_key_t_tag_flag(const char const char *osmtpd_ltok_skip_x_key_t_tag_flag(const char *, int); /* Authentication-Results */ +const char *osmtpd_ltok_skip_ar_propspec(const char *, int); +const char *osmtpd_ltok_skip_ar_reasonspec(const char *, int); const char *osmtpd_ltok_skip_ar_pvalue(const char *, int); const char *osmtpd_ltok_domain_uncomment(const char *); blob - 886cf1e7e01098aa49c5e1a3511f8c6f41466e68 blob + 397b26033ea5ced5eeb1a66bfdf14a35bbc6b97a --- main.c +++ main.c @@ -1684,6 +1684,7 @@ dkim_ar_print(struct osmtpd_ctx *ctx, const char *star start = osmtpd_ltok_skip_cfws(checkpoint, 1); if (*start == '\0') return; + ncheckpoint = start; scan = start; arlen = 8; first = 0; @@ -1704,16 +1705,19 @@ dkim_ar_print(struct osmtpd_ctx *ctx, const char *star /* reasonspec */ } else if (strncmp(ncheckpoint, "reason", sizeof("reason") - 1) == 0) { - ncheckpoint = osmtpd_ltok_skip_value( - ncheckpoint + sizeof("reason"), 0); + ncheckpoint = osmtpd_ltok_skip_ar_reasonspec( + ncheckpoint, 0); /* propspec */ } else { - ncheckpoint += sizeof("header.x=") - 1; - ncheckpoint = osmtpd_ltok_skip_ar_pvalue( + ncheckpoint = osmtpd_ltok_skip_ar_propspec( ncheckpoint, 0); - if (ncheckpoint[0] == ';') - ncheckpoint++; - } + } + + if (ncheckpoint == NULL) + osmtpd_errx(1, "Invalid AR line: |%s", scan); + + if (*ncheckpoint == ';') + ncheckpoint++; } } osmtpd_filter_dataline(ctx, "%s%s", first ? "" : "\t", start);