X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Fparse.c;h=94a1af6ab274908905550697b3bbba29830b96ed;hb=a09f294202729d7e532a1584536fa14e491a0b71;hp=a648f755aeb66a9ad83f62599957d1c054c15dba;hpb=9d4319dfec653f43b64562c8f31b87f2890365b2;p=exim.git diff --git a/src/src/parse.c b/src/src/parse.c index a648f755a..94a1af6ab 100644 --- a/src/src/parse.c +++ b/src/src/parse.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2009 */ +/* Copyright (c) University of Cambridge 1995 - 2017 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for parsing addresses */ @@ -187,7 +187,7 @@ The start of the last potential comment position is remembered to make it possible to ignore comments at the end of compound items. Argument: current character pointer -Regurns: new character pointer +Returns: new character pointer */ static uschar * @@ -661,7 +661,7 @@ if (*s != '@' && *s != '<') while (*s != '<' && (!parse_allow_group || *s != ':')) { s = read_local_part(s, t, errorptr, FALSE); - if (*errorptr != NULL) + if (*errorptr) { *errorptr = string_sprintf("%s (expected word or \"<\")", *errorptr); goto PARSE_FAILED; @@ -686,8 +686,8 @@ processing it. Note that this is "if" rather than "else if" because it's also used after reading a preceding phrase. There are a lot of broken sendmails out there that put additional pairs of <> -round s. If strip_excess_angle_brackets is set, allow any number of -them, as long as they match. */ +round s. If strip_excess_angle_brackets is set, allow a limited +number of them, as long as they match. */ if (*s == '<') { @@ -696,8 +696,11 @@ if (*s == '<') int bracket_count = 1; s++; - if (strip_excess_angle_brackets) - while (*s == '<') { bracket_count++; s++; } + if (strip_excess_angle_brackets) while (*s == '<') + { + if(bracket_count++ > 5) FAILED(US"angle-brackets nested too deep"); + s++; + } t = yield; startptr = s; @@ -711,7 +714,7 @@ if (*s == '<') if (*s == '@') { 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 */ source_routed = TRUE; } @@ -729,7 +732,7 @@ if (*s == '<') else { s = read_addr_spec(s, t, '>', errorptr, &domainptr); - if (*errorptr != NULL) goto PARSE_FAILED; + if (*errorptr) goto PARSE_FAILED; *domain = domainptr - yield; if (source_routed && *domain == 0) FAILED(US"domain missing in source-routed address"); @@ -739,9 +742,10 @@ if (*s == '<') if (*errorptr != NULL) goto PARSE_FAILED; while (bracket_count-- > 0) if (*s++ != '>') { - *errorptr = (s[-1] == 0)? US"'>' missing at end of address" : - string_sprintf("malformed address A: %.32s may not follow %.*s", - s-1, s - (uschar *)mailbox - 1, mailbox); + *errorptr = s[-1] == 0 + ? US"'>' missing at end of address" + : string_sprintf("malformed address: %.32s may not follow %.*s", + s-1, s - (uschar *)mailbox - 1, mailbox); goto PARSE_FAILED; } @@ -793,7 +797,7 @@ if (*s != 0) } else { - *errorptr = string_sprintf("malformed address B: %.32s may not follow %.*s", + *errorptr = string_sprintf("malformed address: %.32s may not follow %.*s", s, s - (uschar *)mailbox, mailbox); goto PARSE_FAILED; } @@ -906,7 +910,7 @@ for (; len > 0; len--) { *t++ = '_'; first_byte = FALSE; - } + } else { sprintf(CS t, "=%02X", ch); @@ -1425,7 +1429,7 @@ for (;;) /* Check file name if required */ - if (directory != NULL) + if (directory) { int len = Ustrlen(directory); uschar *p = filename + len; @@ -1437,16 +1441,53 @@ for (;;) return FF_ERROR; } +#ifdef EXIM_HAVE_OPENAT + /* It is necessary to check that every component inside the directory + is NOT a symbolic link, in order to keep the file inside the directory. + This is mighty tedious. We open the directory and openat every component, + with a flag that fails symlinks. */ + + { + int fd = open(CS directory, O_RDONLY); + if (fd < 0) + { + *error = string_sprintf("failed to open directory %s", directory); + return FF_ERROR; + } + while (*p) + { + uschar temp; + int fd2; + uschar * q = p; + + while (*++p && *p != '/') ; + temp = *p; + *p = '\0'; + + fd2 = openat(fd, CS q, O_RDONLY|O_NOFOLLOW); + close(fd); + *p = temp; + if (fd2 < 0) + { + *error = string_sprintf("failed to open %s (component of included " + "file); could be symbolic link", filename); + return FF_ERROR; + } + fd = fd2; + } + f = fdopen(fd, "rb"); + } +#else /* It is necessary to check that every component inside the directory is NOT a symbolic link, in order to keep the file inside the directory. This is mighty tedious. It is also not totally foolproof in that it leaves the possibility of a race attack, but I don't know how to do any better. */ - while (*p != 0) + while (*p) { int temp; - while (*(++p) != 0 && *p != '/'); + while (*++p && *p != '/'); temp = *p; *p = 0; if (Ulstat(filename, &statbuf) != 0) @@ -1466,11 +1507,16 @@ for (;;) return FF_ERROR; } } +#endif } - /* Open and stat the file */ +#ifdef EXIM_HAVE_OPENAT + else +#endif + /* Open and stat the file */ + f = Ufopen(filename, "rb"); - if ((f = Ufopen(filename, "rb")) == NULL) + if (!f) { *error = string_open_failed(errno, "included file %s", filename); return FF_INCLUDEFAIL; @@ -1486,7 +1532,7 @@ for (;;) /* If directory was checked, double check that we opened a regular file */ - if (directory != NULL && (statbuf.st_mode & S_IFMT) != S_IFREG) + if (directory && (statbuf.st_mode & S_IFMT) != S_IFREG) { *error = string_sprintf("included file %s is not a regular file in " "the %s directory", filename, directory); @@ -1518,10 +1564,9 @@ for (;;) error, incoming_domain, directory, syntax_errors); if (frc != FF_DELIVERED && frc != FF_NOTDELIVERED) return frc; - if (addr != NULL) + if (addr) { - last = addr; - while (last->next != NULL) { count++; last = last->next; } + for (last = addr; last->next; last = last->next) count++; last->next = *anchor; *anchor = addr; count++;