X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/1e1ddfac79fbcd052f199500a6493c7f79cb8462..a85c067ba6c6940512cf57ec213277a370d87e70:/src/src/parse.c diff --git a/src/src/parse.c b/src/src/parse.c index e3b471f1a..93b12bc77 100644 --- a/src/src/parse.c +++ b/src/src/parse.c @@ -2,9 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ +/* Copyright (c) The Exim Maintainers 2020 - 2022 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ -/* Copyright (c) The Exim Maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* Functions for parsing addresses */ @@ -12,7 +13,7 @@ #include "exim.h" -static uschar *last_comment_position; +static const uschar *last_comment_position; @@ -22,22 +23,25 @@ redundant apparatus. */ #ifdef STAND_ALONE -address_item *deliver_make_addr(uschar *address, BOOL copy) +address_item * +deliver_make_addr(uschar *address, BOOL copy) { -address_item *addr = store_get(sizeof(address_item), FALSE); +address_item *addr = store_get(sizeof(address_item), GET_UNTAINTED); addr->next = NULL; addr->parent = NULL; addr->address = address; return addr; } -uschar *rewrite_address(uschar *recipient, BOOL dummy1, BOOL dummy2, rewrite_rule +uschar * +rewrite_address(uschar *recipient, BOOL dummy1, BOOL dummy2, rewrite_rule *dummy3, int dummy4) { return recipient; } -uschar *rewrite_address_qualify(uschar *recipient, BOOL dummy1) +uschar * +rewrite_address_qualify(uschar *recipient, BOOL dummy1) { return recipient; } @@ -65,7 +69,7 @@ Returns: pointer past the end of the address */ uschar * -parse_find_address_end(uschar *s, BOOL nl_ends) +parse_find_address_end(const uschar *s, BOOL nl_ends) { BOOL source_routing = *s == '@'; int no_term = source_routing? 1 : 0; @@ -121,7 +125,7 @@ while (*s != 0 && (*s != ',' || no_term > 0) && (*s != '\n' || !nl_ends)) } } -return s; +return US s; } @@ -143,21 +147,21 @@ Argument: pointer to an address, possibly unqualified Returns: pointer to the last @ in an address, or NULL if none */ -uschar * -parse_find_at(uschar *s) +const uschar * +parse_find_at(const uschar *s) { -uschar *t = s + Ustrlen(s); +const uschar * t = s + Ustrlen(s); while (--t >= s) - { if (*t == '@') { int backslash_count = 0; - uschar *tt = t - 1; + const uschar *tt = t - 1; while (tt > s && *tt-- == '\\') backslash_count++; if ((backslash_count & 1) == 0) return t; } - else if (*t == '\"') return NULL; - } + else if (*t == '\"') + return NULL; + return NULL; } @@ -191,8 +195,8 @@ Argument: current character pointer Returns: new character pointer */ -static uschar * -skip_comment(uschar *s) +static const uschar * +skip_comment(const uschar *s) { last_comment_position = s; while (*s) @@ -224,16 +228,20 @@ If allow_domain_literals is TRUE, a "domain" may also be an IP address enclosed in []. Make sure the output is set to the null string if there is a syntax error as well as if there is no domain at all. +Optionally, msg_id domain literals ( printable-ascii enclosed in [] ) +are permitted. + Arguments: s current character pointer t where to put the domain + msg_id_literals flag for relaxed domain-literal processing errorptr put error message here on failure (*t will be 0 on exit) Returns: new character pointer */ -static uschar * -read_domain(uschar *s, uschar *t, uschar **errorptr) +static const uschar * +read_domain(const uschar *s, uschar *t, BOOL msg_id_literals, uschar **errorptr) { uschar *tt = t; s = skip_comment(s); @@ -259,7 +267,11 @@ if (*s == '[') t += 5; s += 5; } - while (*s == '.' || *s == ':' || isxdigit(*s)) *t++ = *s++; + + if (msg_id_literals) + while (*s >= 33 && *s <= 90 || *s >= 94 && *s <= 126) *t++ = *s++; + else + while (*s == '.' || *s == ':' || isxdigit(*s)) *t++ = *s++; if (*s == ']') *t++ = *s++; else { @@ -267,7 +279,7 @@ if (*s == '[') *tt = 0; } - if (!allow_domain_literals) + if (!allow_domain_literals && !msg_id_literals) { *errorptr = US"domain literals not allowed"; *tt = 0; @@ -406,8 +418,8 @@ Arguments: Returns: new character pointer */ -static uschar * -read_local_part(uschar *s, uschar *t, uschar **error, BOOL allow_null) +static const uschar * +read_local_part(const uschar *s, uschar *t, uschar **error, BOOL allow_null) { uschar *tt = t; *error = NULL; @@ -491,8 +503,8 @@ Arguments: Returns: new character pointer */ -static uschar * -read_route(uschar *s, uschar *t, uschar **errorptr) +static const uschar * +read_route(const uschar *s, uschar *t, uschar **errorptr) { BOOL commas = FALSE; *errorptr = NULL; @@ -500,7 +512,7 @@ BOOL commas = FALSE; while (*s == '@') { *t++ = '@'; - s = read_domain(s+1, t, errorptr); + s = read_domain(s+1, t, FALSE, errorptr); if (*t == 0) return s; t += Ustrlen((const uschar *)t); if (*s != ',') break; @@ -545,8 +557,8 @@ Arguments: Returns: new character pointer */ -static uschar * -read_addr_spec(uschar *s, uschar *t, int term, uschar **errorptr, +static const uschar * +read_addr_spec(const uschar *s, uschar *t, int term, uschar **errorptr, uschar **domainptr) { s = read_local_part(s, t, errorptr, FALSE); @@ -559,7 +571,7 @@ if (*errorptr == NULL) t += Ustrlen((const uschar *)t); *t++ = *s++; *domainptr = t; - s = read_domain(s, t, errorptr); + s = read_domain(s, t, FALSE, errorptr); } return s; } @@ -616,12 +628,12 @@ Returns: points to the extracted address, or NULL on error #define FAILED(s) { *errorptr = s; goto PARSE_FAILED; } uschar * -parse_extract_address(uschar *mailbox, uschar **errorptr, int *start, int *end, +parse_extract_address(const uschar *mailbox, uschar **errorptr, int *start, int *end, int *domain, BOOL allow_null) { -uschar *yield = store_get(Ustrlen(mailbox) + 1, is_tainted(mailbox)); -uschar *startptr, *endptr; -uschar *s = US mailbox; +uschar * yield = store_get(Ustrlen(mailbox) + 1, mailbox); +const uschar *startptr, *endptr; +const uschar *s = US mailbox; uschar *t = US yield; *domain = 0; @@ -647,9 +659,9 @@ followed by a route-addr (more words must follow). */ if (*s != '@' && *s != '<') { - if (*s == 0 || *s == ';') + if (!*s || *s == ';') { - if (*t == 0) FAILED(US"empty address"); + if (!*t) FAILED(US"empty address"); endptr = last_comment_position; goto PARSE_SUCCEEDED; /* Bare local part */ } @@ -740,7 +752,7 @@ if (*s == '<') } endptr = s; - if (*errorptr != NULL) goto PARSE_FAILED; + if (*errorptr) goto PARSE_FAILED; while (bracket_count-- > 0) if (*s++ != '>') { *errorptr = s[-1] == 0 @@ -759,14 +771,14 @@ should be the domain. However, for flexibility we allow for a route-address not enclosed in <> as well, which is indicated by an empty first local part preceding '@'. The source routing is, however, ignored. */ -else if (*t == 0) +else if (!*t) { uschar *domainptr = yield; s = read_route(s, t, errorptr); - if (*errorptr != NULL) goto PARSE_FAILED; + if (*errorptr) goto PARSE_FAILED; *t = 0; /* Ensure route is ignored - probably overkill */ s = read_addr_spec(s, t, 0, errorptr, &domainptr); - if (*errorptr != NULL) goto PARSE_FAILED; + if (*errorptr) goto PARSE_FAILED; *domain = domainptr - yield; endptr = last_comment_position; if (*domain == 0) FAILED(US"domain missing in source-routed address"); @@ -779,8 +791,8 @@ else t += Ustrlen((const uschar *)t); *t++ = *s++; *domain = t - yield; - s = read_domain(s, t, errorptr); - if (*t == 0) goto PARSE_FAILED; + s = read_domain(s, t, TRUE, errorptr); + if (!*t) goto PARSE_FAILED; endptr = last_comment_position; } @@ -789,7 +801,7 @@ through for other cases. Endptr may have been moved over whitespace, so move it back past white space if necessary. */ PARSE_SUCCEEDED: -if (*s != 0) +if (*s) { if (f.parse_found_group && *s == ';') { @@ -808,11 +820,11 @@ while (isspace(endptr[-1])) endptr--; *end = endptr - US mailbox; /* Although this code has no limitation on the length of address extracted, -other parts of Exim may have limits, and in any case, RFC 2821 limits local -parts to 64 and domains to 255, so we do a check here, giving an error if the -address is ridiculously long. */ +other parts of Exim may have limits, and in any case, RFC 5321 limits email +addresses to 256, so we do a check here, giving an error if the address is +ridiculously long. */ -if (*end - *start > ADDRESS_MAXLENGTH) +if (*end - *start > EXIM_EMAILADDR_MAX) { *errorptr = string_sprintf("address is ridiculously long: %.64s...", yield); return NULL; @@ -843,8 +855,7 @@ return NULL; /* This function is used for quoting text in headers according to RFC 2047. If the only characters that strictly need quoting are spaces, we return the -original string, unmodified. If a quoted string is too long for the buffer, it -is truncated. (This shouldn't happen: this is normally handling short strings.) +original string, unmodified. Hmmph. As always, things get perverted for other uses. This function was originally for the "phrase" part of addresses. Now it is being used for much @@ -856,77 +867,63 @@ Arguments: chars len the length of the string charset the name of the character set; NULL => iso-8859-1 - buffer the buffer to put the answer in - buffer_size the size of the buffer fold if TRUE, a newline is inserted before the separating space when more than one encoded-word is generated Returns: pointer to the original string, if no quoting needed, or - pointer to buffer containing the quoted string, or - a pointer to "String too long" if the buffer can't even hold - the introduction + pointer to allocated memory containing the quoted string */ const uschar * -parse_quote_2047(const uschar *string, int len, uschar *charset, uschar *buffer, - int buffer_size, BOOL fold) +parse_quote_2047(const uschar *string, int len, const uschar *charset, + BOOL fold) { -const uschar *s = string; -uschar *p, *t; -int hlen; +const uschar * s = string; +int hlen, l; BOOL coded = FALSE; BOOL first_byte = FALSE; +gstring * g = + string_fmt_append(NULL, "=?%s?Q?", charset ? charset : US"iso-8859-1"); -if (!charset) charset = US"iso-8859-1"; +hlen = l = g->ptr; -/* We don't expect this to fail! */ - -if (!string_format(buffer, buffer_size, "=?%s?Q?", charset)) - return US"String too long"; - -hlen = Ustrlen(buffer); -t = buffer + hlen; -p = buffer; - -for (; len > 0; len--) +for (s = string; len > 0; s++, len--) { - int ch = *s++; - if (t > buffer + buffer_size - hlen - 8) break; + int ch = *s; - if ((t - p > 67) && !first_byte) + if (g->ptr - l > 67 && !first_byte) { - *t++ = '?'; - *t++ = '='; - if (fold) *t++ = '\n'; - *t++ = ' '; - p = t; - Ustrncpy(p, buffer, hlen); - t += hlen; + g = fold ? string_catn(g, US"?=\n ", 4) : string_catn(g, US"?= ", 3); + l = g->ptr; + g = string_catn(g, g->s, hlen); } - if (ch < 33 || ch > 126 || - Ustrchr("?=()<>@,;:\\\".[]_", ch) != NULL) + if ( ch < 33 || ch > 126 + || Ustrchr("?=()<>@,;:\\\".[]_", ch) != NULL) { if (ch == ' ') { - *t++ = '_'; + g = string_catn(g, US"_", 1); first_byte = FALSE; } else { - t += sprintf(CS t, "=%02X", ch); + g = string_fmt_append(g, "=%02X", ch); coded = TRUE; first_byte = !first_byte; } } - else { *t++ = ch; first_byte = FALSE; } + else + { g = string_catn(g, s, 1); first_byte = FALSE; } } -*t++ = '?'; -*t++ = '='; -*t = 0; +if (coded) + string = string_from_gstring(g = string_catn(g, US"?=", 2)); +else + g->ptr = -1; -return coded ? buffer : string; +gstring_release_unused(g); +return string; } @@ -969,32 +966,25 @@ August 2000: Additional code added: We *could* use this for all cases, getting rid of the messy original code, but leave it for now. It would complicate simple cases like "John Q. Smith". -The result is passed back in the buffer; it is usually going to be added to -some other string. In order to be sure there is going to be no overflow, -restrict the length of the input to 1/4 of the buffer size - this allows for -every single character to be quoted or encoded without overflowing, and that -wouldn't happen because of amalgamation. If the phrase is too long, return a -fixed string. +The result is passed back in allocated memory. Arguments: phrase an RFC822 phrase len the length of the phrase - buffer a buffer to put the result in - buffer_size the size of the buffer Returns: the fixed RFC822 phrase */ const uschar * -parse_fix_phrase(const uschar *phrase, int len, uschar *buffer, int buffer_size) +parse_fix_phrase(const uschar *phrase, int len) { int ch, i; BOOL quoted = FALSE; const uschar *s, *end; +uschar * buffer; uschar *t, *yield; while (len > 0 && isspace(*phrase)) { phrase++; len--; } -if (len > buffer_size/4) return US"Name too long"; /* See if there are any non-printing characters, and if so, use the RFC 2047 encoding for the whole thing. */ @@ -1002,11 +992,16 @@ encoding for the whole thing. */ for (i = 0, s = phrase; i < len; i++, s++) if ((*s < 32 && *s != '\t') || *s > 126) break; -if (i < len) return parse_quote_2047(phrase, len, headers_charset, buffer, - buffer_size, FALSE); +if (i < len) + return parse_quote_2047(phrase, len, headers_charset, FALSE); /* No non-printers; use the RFC 822 quoting rules */ +if (len <= 0 || len >= INT_MAX/4) + return string_copy_taint(CUS"", phrase); + +buffer = store_get((len+1)*4, phrase); + s = phrase; end = s + len; yield = t = buffer + 1; @@ -1150,9 +1145,12 @@ while (s < end) { if (ss >= end) ss--; *t++ = '('; - Ustrncpy(t, s, ss-s); - t += ss-s; - s = ss; + if (ss > s) + { + Ustrncpy(t, s, ss-s); + t += ss-s; + s = ss; + } } } @@ -1173,6 +1171,7 @@ while (s < end) } *t = 0; +store_release_above(t+1); return yield; } @@ -1245,8 +1244,8 @@ Returns: FF_DELIVERED addresses extracted */ int -parse_forward_list(uschar *s, int options, address_item **anchor, - uschar **error, const uschar *incoming_domain, uschar *directory, +parse_forward_list(const uschar *s, int options, address_item **anchor, + uschar **error, const uschar *incoming_domain, const uschar *directory, error_block **syntax_errors) { int count = 0; @@ -1255,18 +1254,15 @@ DEBUG(D_route) debug_printf("parse_forward_list: %s\n", s); for (;;) { - int len; - int special = 0; - int specopt = 0; - int specbit = 0; - uschar *ss, *nexts; - address_item *addr; + int len, special = 0, specopt = 0, specbit = 0; + const uschar * ss, * nexts; + address_item * addr; BOOL inquote = FALSE; for (;;) { while (isspace(*s) || *s == ',') s++; - if (*s == '#') { while (*s != 0 && *s != '\n') s++; } else break; + if (*s == '#') { while (*s && *s != '\n') s++; } else break; } /* When we reach the end of the list, we return FF_DELIVERED if any child @@ -1287,18 +1283,17 @@ for (;;) syntax error has been skipped. I now think it is the wrong approach, but have left this here just in case, and for the record. */ - #ifdef NEVER +#ifdef NEVER if (count > 0) return FF_DELIVERED; /* Something was generated */ - if (syntax_errors == NULL || /* Not skipping syntax errors, or */ - *syntax_errors == NULL) /* we didn't actually skip any */ + if (!syntax_errors || /* Not skipping syntax errors, or */ + !*syntax_errors) /* we didn't actually skip any */ return FF_NOTDELIVERED; *error = string_sprintf("no addresses generated: syntax error in %s: %s", (*syntax_errors)->text2, (*syntax_errors)->text1); return FF_ERROR; - #endif - +#endif } /* Find the end of the next address. Quoted strings in addresses may contain @@ -1315,7 +1310,7 @@ for (;;) /* Remove any trailing spaces; we know there's at least one non-space. */ - while (isspace((ss[-1]))) ss--; + while (isspace(ss[-1])) ss--; /* We now have s->start and ss->end of the next address. Remove quotes if they completely enclose, remembering the address started with a quote @@ -1328,20 +1323,14 @@ for (;;) ss--; inquote = TRUE; while (s < ss && isspace(*s)) s++; - while (ss > s && isspace((ss[-1]))) ss--; + while (ss > s && isspace(ss[-1])) ss--; } /* Set up the length of the address. */ len = ss - s; - DEBUG(D_route) - { - int save = s[len]; - s[len] = 0; - debug_printf("extract item: %s\n", s); - s[len] = save; - } + DEBUG(D_route) debug_printf("extract item: %.*s\n", len, s); /* Handle special addresses if permitted. If the address is :unknown: ignore it - this is for backward compatibility with old alias files. You @@ -1362,18 +1351,18 @@ for (;;) else if (Ustrncmp(s, ":fail:", 6) == 0) { special = FF_FAIL; specopt = RDO_FAIL; } /* specbit is 0 */ - if (special != 0) + if (special) { - uschar *ss = Ustrchr(s+1, ':') + 1; + uschar * ss = Ustrchr(s+1, ':') + 1; /* line after the special... */ if ((options & specopt) == specbit) { *error = string_sprintf("\"%.*s\" is not permitted", len, s); return FF_ERROR; } - while (*ss != 0 && isspace(*ss)) ss++; - while (s[len] != 0 && s[len] != '\n') len++; - s[len] = 0; - *error = string_copy(ss); + while (*ss && isspace(*ss)) ss++; /* skip leading whitespace */ + if ((len = Ustrlen(ss)) > 0) /* ignore trailing newlines */ + for (const uschar * t = ss + len - 1; t >= ss && *t == '\n'; t--) len--; + *error = string_copyn(ss, len); /* becomes the error */ return special; } @@ -1384,14 +1373,14 @@ for (;;) if (Ustrncmp(s, ":include:", 9) == 0) { - uschar *filebuf; + uschar * filebuf; uschar filename[256]; - uschar *t = s+9; + const uschar * t = s+9; int flen = len - 9; int frc; struct stat statbuf; - address_item *last; - FILE *f; + address_item * last; + FILE * f; while (flen > 0 && isspace(*t)) { t++; flen--; } @@ -1401,7 +1390,7 @@ for (;;) return FF_ERROR; } - if (flen > 255) + if (flen > sizeof(filename)-1) { *error = string_sprintf("included file name \"%s\" is too long", t); return FF_ERROR; @@ -1439,8 +1428,10 @@ for (;;) if (directory) { int len = Ustrlen(directory); - uschar *p = filename + len; + uschar * p; + while (len > 0 && directory[len-1] == '/') len--; /* ignore trailing '/' */ + p = filename + len; if (Ustrncmp(filename, directory, len) != 0 || *p != '/') { *error = string_sprintf("included file %s is not in directory %s", @@ -1455,7 +1446,7 @@ for (;;) with a flag that fails symlinks. */ { - int fd = exim_open2(CS directory, O_RDONLY); + int fd = exim_open2(CCS directory, O_RDONLY); if (fd < 0) { *error = string_sprintf("failed to open directory %s", directory); @@ -1465,9 +1456,10 @@ for (;;) { uschar temp; int fd2; - uschar * q = p; + uschar * q = p + 1; /* skip dividing '/' */ - while (*++p && *p != '/') ; + while (*q == '/') q++; /* skip extra '/' */ + while (*++p && *p != '/') ; /* end of component */ temp = *p; *p = '\0'; @@ -1525,7 +1517,7 @@ for (;;) if (!f) { - *error = string_open_failed(errno, "included file %s", filename); + *error = string_open_failed("included file %s", filename); return FF_INCLUDEFAIL; } @@ -1555,7 +1547,7 @@ for (;;) return FF_ERROR; } - filebuf = store_get(statbuf.st_size + 1, is_tainted(filename)); + filebuf = store_get(statbuf.st_size + 1, filename); if (fread(filebuf, 1, statbuf.st_size, f) != statbuf.st_size) { *error = string_sprintf("error while reading included file %s: %s", @@ -1602,19 +1594,18 @@ for (;;) else { int start, end, domain; - uschar *recipient = NULL; - int save = s[len]; - s[len] = 0; + const uschar *recipient = NULL; + uschar * s_ltd = string_copyn(s, len); /* If it starts with \ and the rest of it parses as a valid mail address without a domain, carry on with that address, but qualify it with the incoming domain. Otherwise arrange for the address to fall through, causing an error message on the re-parse. */ - if (*s == '\\') + if (*s_ltd == '\\') { recipient = - parse_extract_address(s+1, error, &start, &end, &domain, FALSE); + parse_extract_address(s_ltd+1, error, &start, &end, &domain, FALSE); if (recipient) recipient = domain != 0 ? NULL : string_sprintf("%s@%s", recipient, incoming_domain); @@ -1623,22 +1614,22 @@ for (;;) /* Try parsing the item as an address. */ if (!recipient) recipient = - parse_extract_address(s, error, &start, &end, &domain, FALSE); + parse_extract_address(s_ltd, error, &start, &end, &domain, FALSE); /* If item starts with / or | and is not a valid address, or there is no domain, treat it as a file or pipe. If it was a quoted item, remove the quoting occurrences of \ within it. */ - if ((*s == '|' || *s == '/') && (recipient == NULL || domain == 0)) + if ((*s_ltd == '|' || *s_ltd == '/') && (!recipient || domain == 0)) { - uschar *t = store_get(Ustrlen(s) + 1, is_tainted(s)); - uschar *p = t; - uschar *q = s; - while (*q != 0) + uschar * t = store_get(Ustrlen(s_ltd) + 1, s_ltd); + uschar * p = t, * q = s_ltd; + + while (*q) { if (inquote) { - *p++ = (*q == '\\')? *(++q) : *q; + *p++ = *q == '\\' ? *++q : *q; q++; } else *p++ = *q++; @@ -1646,7 +1637,7 @@ for (;;) *p = 0; addr = deliver_make_addr(t, TRUE); setflag(addr, af_pfr); /* indicates pipe/file/reply */ - if (*s != '|') setflag(addr, af_file); /* indicates file */ + if (*s_ltd != '|') setflag(addr, af_file); /* indicates file */ } /* Item must be an address. Complain if not, else qualify, rewrite and set @@ -1658,36 +1649,35 @@ for (;;) else { - if (recipient == NULL) + if (!recipient) { if (Ustrcmp(*error, "empty address") == 0) { *error = NULL; - s[len] = save; s = nexts; continue; } - if (syntax_errors != NULL) + if (syntax_errors) { - error_block *e = store_get(sizeof(error_block), FALSE); - error_block *last = *syntax_errors; - if (last == NULL) *syntax_errors = e; else + error_block * e = store_get(sizeof(error_block), GET_UNTAINTED); + error_block * last = *syntax_errors; + if (last) { - while (last->next != NULL) last = last->next; + while (last->next) last = last->next; last->next = e; } + else + *syntax_errors = e; e->next = NULL; e->text1 = *error; - e->text2 = string_copy(s); - s[len] = save; + e->text2 = s_ltd; s = nexts; continue; } else { - *error = string_sprintf("%s in \"%s\"", *error, s); - s[len] = save; /* _after_ using it for *error */ + *error = string_sprintf("%s in \"%s\"", *error, s_ltd); return FF_ERROR; } } @@ -1695,17 +1685,15 @@ for (;;) /* Address was successfully parsed. Rewrite, and then make an address block. */ - recipient = ((options & RDO_REWRITE) != 0)? - rewrite_address(recipient, TRUE, FALSE, global_rewrite_rules, - rewrite_existflags) : - rewrite_address_qualify(recipient, TRUE); - addr = deliver_make_addr(recipient, TRUE); /* TRUE => copy recipient */ + recipient = options & RDO_REWRITE + ? rewrite_address(recipient, TRUE, FALSE, global_rewrite_rules, + rewrite_existflags) + : rewrite_address_qualify(recipient, TRUE); /*XXX loses track of const */ + addr = deliver_make_addr(US recipient, TRUE); /* TRUE => copy recipient, so deconst ok */ } - /* Restore the final character in the original data, and add to the - output chain. */ + /* Add the original data to the output chain. */ - s[len] = save; addr->next = *anchor; *anchor = addr; count++; @@ -1733,8 +1721,8 @@ Arguments: Returns: points after the processed message-id or NULL on error */ -uschar * -parse_message_id(uschar *str, uschar **yield, uschar **error) +const uschar * +parse_message_id(const uschar *str, uschar **yield, uschar **error) { uschar *domain = NULL; uschar *id; @@ -1752,7 +1740,7 @@ for the answer, but it may also be very long if we are processing a header line. Therefore, take care to release unwanted store afterwards. */ reset_point = store_mark(); -id = *yield = store_get(Ustrlen(str) + 1, is_tainted(str)); +id = *yield = store_get(Ustrlen(str) + 1, str); *id++ = *str++; str = read_addr_spec(str, id, '>', error, &domain); @@ -1774,8 +1762,7 @@ while (*id) id++; *id++ = 0; store_release_above(id); -str = skip_comment(str); -return str; +return skip_comment(str); } @@ -1793,16 +1780,16 @@ Arguments: Returns: points after the processed date or NULL on error */ -static uschar * -parse_number(uschar *str, int *n, int digits) +static const uschar * +parse_number(const uschar *str, int *n, int digits) { - *n=0; - while (digits--) +*n=0; +while (digits--) { - if (*str<'0' || *str>'9') return NULL; - *n=10*(*n)+(*str++-'0'); + if (*str<'0' || *str>'9') return NULL; + *n=10*(*n)+(*str++-'0'); } - return str; +return str; } @@ -1819,8 +1806,8 @@ Arguments: Returns: points after the parsed day or NULL on error */ -static uschar * -parse_day_of_week(uschar *str) +static const uschar * +parse_day_of_week(const uschar * str) { /* day-of-week = ([FWS] day-name) / obs-day-of-week @@ -1835,17 +1822,16 @@ static const uschar *day_name[7]={ US"mon", US"tue", US"wed", US"thu", US"fri", int i; uschar day[4]; -str=skip_comment(str); -for (i=0; i<3; ++i) +str = skip_comment(str); +for (i = 0; i < 3; ++i) { - if ((day[i]=tolower(*str))=='\0') return NULL; + if ((day[i] = tolower(*str)) == '\0') return NULL; ++str; } -day[3]='\0'; -for (i=0; i<7; ++i) if (Ustrcmp(day,day_name[i])==0) break; -if (i==7) return NULL; -str=skip_comment(str); -return str; +day[3] = '\0'; +for (i = 0; i<7; ++i) if (Ustrcmp(day,day_name[i]) == 0) break; +if (i == 7) return NULL; +return skip_comment(str); } @@ -1865,8 +1851,8 @@ Arguments: Returns: points after the processed date or NULL on error */ -static uschar * -parse_date(uschar *str, int *d, int *m, int *y) +static const uschar * +parse_date(const uschar *str, int *d, int *m, int *y) { /* date = day month year @@ -1888,36 +1874,39 @@ day = ([FWS] 1*2DIGIT) / obs-day obs-day = [CFWS] 1*2DIGIT [CFWS] */ -uschar *c,*n; +const uschar * s, * n; static const uschar *month_name[]={ US"jan", US"feb", US"mar", US"apr", US"may", US"jun", US"jul", US"aug", US"sep", US"oct", US"nov", US"dec" }; int i; uschar month[4]; -str=skip_comment(str); -if ((str=parse_number(str,d,1))==NULL) return NULL; -if (*str>='0' && *str<='9') *d=10*(*d)+(*str++-'0'); -c=skip_comment(str); -if (c==str) return NULL; -else str=c; -for (i=0; i<3; ++i) if ((month[i]=tolower(*(str+i)))=='\0') return NULL; -month[3]='\0'; -for (i=0; i<12; ++i) if (Ustrcmp(month,month_name[i])==0) break; -if (i==12) return NULL; +str = skip_comment(str); +if ((str = parse_number(str,d,1)) == NULL) return NULL; + +if (*str>='0' && *str<='9') *d = 10*(*d)+(*str++-'0'); +s = skip_comment(str); +if (s == str) return NULL; +str = s; + +for (i = 0; i<3; ++i) if ((month[i]=tolower(*(str+i))) == '\0') return NULL; +month[3] = '\0'; +for (i = 0; i<12; ++i) if (Ustrcmp(month,month_name[i]) == 0) break; +if (i == 12) return NULL; str+=3; -*m=i; -c=skip_comment(str); -if (c==str) return NULL; -else str=c; -if ((n=parse_number(str,y,4))) +*m = i; +s = skip_comment(str); +if (s == str) return NULL; +str=s; + +if ((n = parse_number(str,y,4))) { - str=n; + str = n; if (*y<1900) return NULL; - *y=*y-1900; + *y = *y-1900; } -else if ((n=parse_number(str,y,2))) +else if ((n = parse_number(str,y,2))) { - str=skip_comment(n); - while (*(str-1)==' ' || *(str-1)=='\t') --str; /* match last FWS later */ + str = skip_comment(n); + while (*(str-1) == ' ' || *(str-1) == '\t') --str; /* match last FWS later */ if (*y<50) *y+=100; } else return NULL; @@ -1942,8 +1931,8 @@ Arguments: Returns: points after the processed time or NULL on error */ -static uschar * -parse_time(uschar *str, int *h, int *m, int *s, int *z) +static const uschar * +parse_time(const uschar *str, int *h, int *m, int *s, int *z) { /* time = time-of-day FWS zone @@ -1978,61 +1967,61 @@ obs-zone = "UT" / "GMT" / ; Universal Time %d107-122 ; upper and lower case */ -uschar *c; +const uschar * c; -str=skip_comment(str); -if ((str=parse_number(str,h,2))==NULL) return NULL; -str=skip_comment(str); +str = skip_comment(str); +if ((str = parse_number(str,h,2)) == NULL) return NULL; +str = skip_comment(str); if (*str!=':') return NULL; ++str; -str=skip_comment(str); -if ((str=parse_number(str,m,2))==NULL) return NULL; -c=skip_comment(str); -if (*str==':') +str = skip_comment(str); +if ((str = parse_number(str,m,2)) == NULL) return NULL; +c = skip_comment(str); +if (*str == ':') { ++str; - str=skip_comment(str); - if ((str=parse_number(str,s,2))==NULL) return NULL; - c=skip_comment(str); + str = skip_comment(str); + if ((str = parse_number(str,s,2)) == NULL) return NULL; + c = skip_comment(str); } -if (c==str) return NULL; +if (c == str) return NULL; else str=c; -if (*str=='+' || *str=='-') +if (*str == '+' || *str == '-') { int neg; - neg=(*str=='-'); + neg = (*str == '-'); ++str; - if ((str=parse_number(str,z,4))==NULL) return NULL; - *z=(*z/100)*3600+(*z%100)*60; - if (neg) *z=-*z; + if ((str = parse_number(str,z,4)) == NULL) return NULL; + *z = (*z/100)*3600+(*z%100)*60; + if (neg) *z = -*z; } else { char zone[5]; - struct { const char *name; int off; } zone_name[10]= + struct { const char *name; int off; } zone_name[10] = { {"gmt",0}, {"ut",0}, {"est",-5}, {"edt",-4}, {"cst",-6}, {"cdt",-5}, {"mst",-7}, {"mdt",-6}, {"pst",-8}, {"pdt",-7}}; int i,j; - for (i=0; i<4; ++i) + for (i = 0; i<4; ++i) { - zone[i]=tolower(*(str+i)); + zone[i] = tolower(*(str+i)); if (zone[i]<'a' || zone[i]>'z') break; } - zone[i]='\0'; - for (j=0; j<10 && strcmp(zone,zone_name[j].name); ++j); + zone[i] = '\0'; + for (j = 0; j<10 && strcmp(zone,zone_name[j].name); ++j); /* Besides zones named in the grammar, RFC 2822 says other alphabetic */ /* time zones should be treated as unknown offsets. */ if (j<10) { - *z=zone_name[j].off*3600; + *z = zone_name[j].off*3600; str+=i; } else if (zone[0]<'a' || zone[1]>'z') return 0; else { while ((*str>='a' && *str<='z') || (*str>='A' && *str<='Z')) ++str; - *z=0; + *z = 0; } } return str; @@ -2052,8 +2041,8 @@ Arguments: Returns: points after the processed date-time or NULL on error */ -uschar * -parse_date_time(uschar *str, time_t *t) +const uschar * +parse_date_time(const uschar *str, time_t *t) { /* date-time = [ day-of-week "," ] date FWS time [CFWS] @@ -2065,27 +2054,26 @@ extern char **environ; char **old_environ; static char gmt0[]="TZ=GMT0"; static char *gmt_env[]={ gmt0, (char*)0 }; -uschar *try; +const uschar * try; -if ((try=parse_day_of_week(str))) +if ((try = parse_day_of_week(str))) { - str=try; + str = try; if (*str!=',') return 0; ++str; } -if ((str=parse_date(str,&tm.tm_mday,&tm.tm_mon,&tm.tm_year))==NULL) return NULL; +if ((str = parse_date(str,&tm.tm_mday,&tm.tm_mon,&tm.tm_year)) == NULL) return NULL; if (*str!=' ' && *str!='\t') return NULL; -while (*str==' ' || *str=='\t') ++str; -if ((str=parse_time(str,&tm.tm_hour,&tm.tm_min,&tm.tm_sec,&zone))==NULL) return NULL; -tm.tm_isdst=0; -old_environ=environ; -environ=gmt_env; -*t=mktime(&tm); -environ=old_environ; -if (*t==-1) return NULL; +while (*str == ' ' || *str == '\t') ++str; +if ((str = parse_time(str,&tm.tm_hour,&tm.tm_min,&tm.tm_sec,&zone)) == NULL) return NULL; +tm.tm_isdst = 0; +old_environ = environ; +environ = gmt_env; +*t = mktime(&tm); +environ = old_environ; +if (*t == -1) return NULL; *t-=zone; -str=skip_comment(str); -return str; +return skip_comment(str); } @@ -2102,8 +2090,8 @@ int main(void) { int start, end, domain; uschar buffer[1024]; -uschar outbuff[1024]; +store_init(); big_buffer = store_malloc(big_buffer_size); /* strip_trailing_dot = TRUE; */ @@ -2115,8 +2103,7 @@ while (Ufgets(buffer, sizeof(buffer), stdin) != NULL) { buffer[Ustrlen(buffer)-1] = 0; if (buffer[0] == 0) break; - printf("%s\n", CS parse_fix_phrase(buffer, Ustrlen(buffer), outbuff, - sizeof(outbuff))); + printf("%s\n", CS parse_fix_phrase(buffer, Ustrlen(buffer))); } printf("Testing parse_extract_address without group syntax and without UTF-8\n");