SPDX: license tags (mostly by guesswork)
[exim.git] / src / src / parse.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2020 - 2022 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-only */
9
10 /* Functions for parsing addresses */
11
12
13 #include "exim.h"
14
15
16 static const uschar *last_comment_position;
17
18
19
20 /* In stand-alone mode, provide a replacement for deliver_make_addr()
21 and rewrite_address[_qualify]() so as to avoid having to drag in too much
22 redundant apparatus. */
23
24 #ifdef STAND_ALONE
25
26 address_item *
27 deliver_make_addr(uschar *address, BOOL copy)
28 {
29 address_item *addr = store_get(sizeof(address_item), GET_UNTAINTED);
30 addr->next = NULL;
31 addr->parent = NULL;
32 addr->address = address;
33 return addr;
34 }
35
36 uschar *
37 rewrite_address(uschar *recipient, BOOL dummy1, BOOL dummy2, rewrite_rule
38   *dummy3, int dummy4)
39 {
40 return recipient;
41 }
42
43 uschar *
44 rewrite_address_qualify(uschar *recipient, BOOL dummy1)
45 {
46 return recipient;
47 }
48
49 #endif
50
51
52
53
54 /*************************************************
55 *             Find the end of an address         *
56 *************************************************/
57
58 /* Scan over a string looking for the termination of an address at a comma,
59 or end of the string. It's the source-routed addresses which cause much pain
60 here. Although Exim ignores source routes, it must recognize such addresses, so
61 we cannot get rid of this logic.
62
63 Argument:
64   s        pointer to the start of an address
65   nl_ends  if TRUE, '\n' terminates an address
66
67 Returns:   pointer past the end of the address
68            (i.e. points to null or comma)
69 */
70
71 uschar *
72 parse_find_address_end(const uschar *s, BOOL nl_ends)
73 {
74 BOOL source_routing = *s == '@';
75 int no_term = source_routing? 1 : 0;
76
77 while (*s != 0 && (*s != ',' || no_term > 0) && (*s != '\n' || !nl_ends))
78   {
79   /* Skip single quoted characters. Strictly these should not occur outside
80   quoted strings in RFC 822 addresses, but they can in RFC 821 addresses. Pity
81   about the lack of consistency, isn't it? */
82
83   if (*s == '\\' && s[1] != 0) s += 2;
84
85   /* Skip quoted items that are not inside brackets. Note that
86   quoted pairs are allowed inside quoted strings. */
87
88   else if (*s == '\"')
89     {
90     while (*(++s) != 0 && (*s != '\n' || !nl_ends))
91       {
92       if (*s == '\\' && s[1] != 0) s++;
93         else if (*s == '\"') { s++; break; }
94       }
95     }
96
97   /* Skip comments, which may include nested brackets, but quotes
98   are not recognized inside comments, though quoted pairs are. */
99
100   else if (*s == '(')
101     {
102     int level = 1;
103     while (*(++s) != 0 && (*s != '\n' || !nl_ends))
104       {
105       if (*s == '\\' && s[1] != 0) s++;
106         else if (*s == '(') level++;
107           else if (*s == ')' && --level <= 0) { s++; break; }
108       }
109     }
110
111   /* Non-special character; just advance. Passing the colon in a source
112   routed address means that any subsequent comma or colon may terminate unless
113   inside angle brackets. */
114
115   else
116     {
117     if (*s == '<')
118       {
119       source_routing = s[1] == '@';
120       no_term = source_routing? 2 : 1;
121       }
122     else if (*s == '>') no_term--;
123     else if (source_routing && *s == ':') no_term--;
124     s++;
125     }
126   }
127
128 return US s;
129 }
130
131
132
133 /*************************************************
134 *            Find last @ in an address           *
135 *************************************************/
136
137 /* This function is used when we have something that may not qualified. If we
138 know it's qualified, searching for the rightmost '@' is sufficient. Here we
139 have to be a bit more clever than just a plain search, in order to handle
140 unqualified local parts like "thing@thong" correctly. Since quotes may not
141 legally be part of a domain name, we can give up on hitting the first quote
142 when searching from the right. Now that the parsing also permits the RFC 821
143 form of address, where quoted-pairs are allowed in unquoted local parts, we
144 must take care to handle that too.
145
146 Argument:  pointer to an address, possibly unqualified
147 Returns:   pointer to the last @ in an address, or NULL if none
148 */
149
150 const uschar *
151 parse_find_at(const uschar *s)
152 {
153 const uschar * t = s + Ustrlen(s);
154 while (--t >= s)
155   if (*t == '@')
156     {
157     int backslash_count = 0;
158     const uschar *tt = t - 1;
159     while (tt > s && *tt-- == '\\') backslash_count++;
160     if ((backslash_count & 1) == 0) return t;
161     }
162   else if (*t == '\"')
163     return NULL;
164
165 return NULL;
166 }
167
168
169
170
171 /***************************************************************************
172 * In all the functions below that read a particular object type from       *
173 * the input, return the new value of the pointer s (the first argument),   *
174 * and put the object into the store pointed to by t (the second argument), *
175 * adding a terminating zero. If no object is found, t will point to zero   *
176 * on return.                                                               *
177 ***************************************************************************/
178
179
180 /*************************************************
181 *          Skip white space and comment          *
182 *************************************************/
183
184 /* Algorithm:
185   (1) Skip spaces.
186   (2) If uschar not '(', return.
187   (3) Skip till matching ')', not counting any characters
188       escaped with '\'.
189   (4) Move past ')' and goto (1).
190
191 The start of the last potential comment position is remembered to
192 make it possible to ignore comments at the end of compound items.
193
194 Argument: current character pointer
195 Returns:  new character pointer
196 */
197
198 static const uschar *
199 skip_comment(const uschar *s)
200 {
201 last_comment_position = s;
202 while (*s)
203   {
204   int c, level;
205
206   if (Uskip_whitespace(&s) != '(') break;
207   level = 1;
208   while((c = *(++s)))
209     {
210     if (c == '(') level++;
211     else if (c == ')') { if (--level <= 0) { s++; break; } }
212     else if (c == '\\' && s[1] != 0) s++;
213     }
214   }
215 return s;
216 }
217
218
219
220 /*************************************************
221 *             Read a domain                      *
222 *************************************************/
223
224 /* A domain is a sequence of subdomains, separated by dots. See comments below
225 for detailed syntax of the subdomains.
226
227 If allow_domain_literals is TRUE, a "domain" may also be an IP address enclosed
228 in []. Make sure the output is set to the null string if there is a syntax
229 error as well as if there is no domain at all.
230
231 Optionally, msg_id domain literals ( printable-ascii enclosed in [] )
232 are permitted.
233
234 Arguments:
235   s          current character pointer
236   t          where to put the domain
237   msg_id_literals     flag for relaxed domain-literal processing
238   errorptr   put error message here on failure (*t will be 0 on exit)
239
240 Returns:     new character pointer
241 */
242
243 static const uschar *
244 read_domain(const uschar *s, uschar *t, BOOL msg_id_literals, uschar **errorptr)
245 {
246 uschar *tt = t;
247 s = skip_comment(s);
248
249 /* Handle domain literals if permitted. An RFC 822 domain literal may contain
250 any character except [ ] \, including linear white space, and may contain
251 quoted characters. However, RFC 821 restricts literals to being dot-separated
252 3-digit numbers, and we make the obvious extension for IPv6. Go for a sequence
253 of digits, dots, hex digits, and colons here; later this will be checked for
254 being a syntactically valid IP address if it ever gets to a router.
255
256 Allow both the formal IPv6 form, with IPV6: at the start, and the informal form
257 without it, and accept IPV4: as well, 'cause someone will use it sooner or
258 later. */
259
260 if (*s == '[')
261   {
262   *t++ = *s++;
263
264   if (strncmpic(s, US"IPv6:", 5) == 0 || strncmpic(s, US"IPv4:", 5) == 0)
265     {
266     memcpy(t, s, 5);
267     t += 5;
268     s += 5;
269     }
270
271   if (msg_id_literals)
272     while (*s >= 33 && *s <= 90 || *s >= 94 && *s <= 126) *t++ = *s++;
273   else
274     while (*s == '.' || *s == ':' || isxdigit(*s)) *t++ = *s++;
275
276   if (*s == ']') *t++ = *s++; else
277     {
278     *errorptr = US"malformed domain literal";
279     *tt = 0;
280     }
281
282   if (!allow_domain_literals && !msg_id_literals)
283     {
284     *errorptr = US"domain literals not allowed";
285     *tt = 0;
286     }
287   *t = 0;
288   return skip_comment(s);
289   }
290
291 /* Handle a proper domain, which is a sequence of dot-separated atoms. Remove
292 trailing dots if strip_trailing_dot is set. A subdomain is an atom.
293
294 An atom is a sequence of any characters except specials, space, and controls.
295 The specials are ( ) < > @ , ; : \ " . [ and ]. This is the rule for RFC 822
296 and its successor (RFC 2822). However, RFC 821 and its successor (RFC 2821) is
297 tighter, allowing only letters, digits, and hyphens, not starting with a
298 hyphen.
299
300 There used to be a global flag that got set when checking addresses that came
301 in over SMTP and which should therefore should be checked according to the
302 stricter rule. However, it seems silly to make the distinction, because I don't
303 suppose anybody ever uses local domains that are 822-compliant and not
304 821-compliant. Furthermore, Exim now has additional data on the spool file line
305 after an address (after "one_time" processing), and it makes use of a #
306 character to delimit it. When I wrote that code, I forgot about this 822-domain
307 stuff, and assumed # could never appear in a domain.
308
309 So the old code is now cut out for Release 4.11 onwards, on 09-Aug-02. In a few
310 years, when we are sure this isn't actually causing trouble, throw it away.
311
312 March 2003: the story continues: There is a camp that is arguing for the use of
313 UTF-8 in domain names as the way to internationalization, and other MTAs
314 support this. Therefore, we now have a flag that permits the use of characters
315 with values greater than 127, encoded in UTF-8, in subdomains, so that Exim can
316 be used experimentally in this way. */
317
318 for (;;)
319   {
320   uschar *tsave = t;
321
322 /*********************
323   if (rfc821_domains)
324     {
325     if (*s != '-') while (isalnum(*s) || *s == '-') *t++ = *s++;
326     }
327   else
328     while (!mac_iscntrl_or_special(*s)) *t++ = *s++;
329 *********************/
330
331   if (*s != '-')
332     {
333     /* Only letters, digits, and hyphens */
334
335     if (!allow_utf8_domains)
336       {
337       while (isalnum(*s) || *s == '-') *t++ = *s++;
338       }
339
340     /* Permit legal UTF-8 characters to be included */
341
342     else for(;;)
343       {
344       int i, d;
345       if (isalnum(*s) || *s == '-')    /* legal ascii characters */
346         {
347         *t++ = *s++;
348         continue;
349         }
350       if ((*s & 0xc0) != 0xc0) break;  /* not start of UTF-8 character */
351       d = *s << 2;
352       for (i = 1; i < 6; i++)          /* i is the number of additional bytes */
353         {
354         if ((d & 0x80) == 0) break;
355         d <<= 1;
356         }
357       if (i == 6) goto BAD_UTF8;       /* invalid UTF-8 */
358       *t++ = *s++;                     /* leading UTF-8 byte */
359       while (i-- > 0)                  /* copy and check remainder */
360         {
361         if ((*s & 0xc0) != 0x80)
362           {
363           BAD_UTF8:
364           *errorptr = US"invalid UTF-8 byte sequence";
365           *tt = 0;
366           return s;
367           }
368         *t++ = *s++;
369         }
370       }    /* End of loop for UTF-8 character */
371     }      /* End of subdomain */
372
373   s = skip_comment(s);
374   *t = 0;
375
376   if (t == tsave)   /* empty component */
377     {
378     if (strip_trailing_dot && t > tt && *s != '.') t[-1] = 0; else
379       {
380       *errorptr = US"domain missing or malformed";
381       *tt = 0;
382       }
383     return s;
384     }
385
386   if (*s != '.') break;
387   *t++ = *s++;
388   s = skip_comment(s);
389   }
390
391 return s;
392 }
393
394
395
396 /*************************************************
397 *            Read a local-part                   *
398 *************************************************/
399
400 /* A local-part is a sequence of words, separated by periods. A null word
401 between dots is not strictly allowed but apparently many mailers permit it,
402 so, sigh, better be compatible. Even accept a trailing dot...
403
404 A <word> is either a quoted string, or an <atom>, which is a sequence
405 of any characters except specials, space, and controls. The specials are
406 ( ) < > @ , ; : \ " . [ and ]. In RFC 822, a single quoted character, (a
407 quoted-pair) is not allowed in a word. However, in RFC 821, it is permitted in
408 the local part of an address. Rather than have separate parsing functions for
409 the different cases, take the liberal attitude always. At least one MUA is
410 happy to recognize this case; I don't know how many other programs do.
411
412 Arguments:
413   s           current character pointer
414   t           where to put the local part
415   error       where to point error text
416   allow_null  TRUE if an empty local part is not an error
417
418 Returns:   new character pointer
419 */
420
421 static const uschar *
422 read_local_part(const uschar *s, uschar *t, uschar **error, BOOL allow_null)
423 {
424 uschar *tt = t;
425 *error = NULL;
426 for (;;)
427   {
428   int c;
429   uschar *tsave = t;
430   s = skip_comment(s);
431
432   /* Handle a quoted string */
433
434   if (*s == '\"')
435     {
436     *t++ = '\"';
437     while ((c = *++s) && c != '\"')
438       {
439       *t++ = c;
440       if (c == '\\' && s[1]) *t++ = *++s;
441       }
442     if (c == '\"')
443       {
444       s++;
445       *t++ = '\"';
446       }
447     else
448       {
449       *error = US"unmatched doublequote in local part";
450       return s;
451       }
452     }
453
454   /* Handle an atom, but allow quoted pairs within it. */
455
456   else while (!mac_iscntrl_or_special(*s) || *s == '\\')
457     {
458     c = *t++ = *s++;
459     if (c == '\\' && *s) *t++ = *s++;
460     }
461
462   /* Terminate the word and skip subsequent comment */
463
464   *t = 0;
465   s = skip_comment(s);
466
467   /* If we have read a null component at this point, give an error unless it is
468   terminated by a dot - an extension to RFC 822 - or if it is the first
469   component of the local part and an empty local part is permitted, in which
470   case just return normally. */
471
472   if (t == tsave && *s != '.')
473     {
474     if (t == tt && !allow_null)
475       *error = US"missing or malformed local part";
476     return s;
477     }
478
479   /* Anything other than a dot terminates the local part. Treat multiple dots
480   as a single dot, as this seems to be a common extension. */
481
482   if (*s != '.') break;
483   do { *t++ = *s++; } while (*s == '.');
484   }
485
486 return s;
487 }
488
489
490 /*************************************************
491 *            Read route part of route-addr       *
492 *************************************************/
493
494 /* The pointer is at the initial "@" on entry. Return it following the
495 terminating colon. Exim no longer supports the use of source routes, but it is
496 required to accept the syntax.
497
498 Arguments:
499   s          current character pointer
500   t          where to put the route
501   errorptr   where to put an error message
502
503 Returns:     new character pointer
504 */
505
506 static const uschar *
507 read_route(const uschar *s, uschar *t, uschar **errorptr)
508 {
509 BOOL commas = FALSE;
510 *errorptr = NULL;
511
512 while (*s == '@')
513   {
514   *t++ = '@';
515   s = read_domain(s+1, t, FALSE, errorptr);
516   if (*t == 0) return s;
517   t += Ustrlen((const uschar *)t);
518   if (*s != ',') break;
519   *t++ = *s++;
520   commas = TRUE;
521   s = skip_comment(s);
522   }
523
524 if (*s == ':') *t++ = *s++;
525
526 /* If there is no colon, and there were no commas, the most likely error
527 is in fact a missing local part in the address rather than a missing colon
528 after the route. */
529
530 else *errorptr = commas?
531   US"colon expected after route list" :
532   US"no local part";
533
534 /* Terminate the route and return */
535
536 *t = 0;
537 return skip_comment(s);
538 }
539
540
541
542 /*************************************************
543 *                Read addr-spec                  *
544 *************************************************/
545
546 /* Addr-spec is local-part@domain. We make the domain optional -
547 the expected terminator for the whole thing is passed to check this.
548 This function is called only when we know we have a route-addr.
549
550 Arguments:
551   s          current character pointer
552   t          where to put the addr-spec
553   term       expected terminator (0 or >)
554   errorptr   where to put an error message
555   domainptr  set to point to the start of the domain
556
557 Returns:     new character pointer
558 */
559
560 static const uschar *
561 read_addr_spec(const uschar *s, uschar *t, int term, uschar **errorptr,
562   uschar **domainptr)
563 {
564 s = read_local_part(s, t, errorptr, FALSE);
565 if (*errorptr == NULL)
566   if (*s != term)
567     if (*s != '@')
568       *errorptr = string_sprintf("\"@\" or \".\" expected after \"%s\"", t);
569     else
570       {
571       t += Ustrlen((const uschar *)t);
572       *t++ = *s++;
573       *domainptr = t;
574       s = read_domain(s, t, FALSE, errorptr);
575       }
576 return s;
577 }
578
579
580
581 /*************************************************
582 *         Extract operative address              *
583 *************************************************/
584
585 /* This function extracts an operative address from a full RFC822 mailbox and
586 returns it in a piece of dynamic store. We take the easy way and get a piece
587 of store the same size as the input, and then copy into it whatever is
588 necessary. If we cannot find a valid address (syntax error), return NULL, and
589 point the error pointer to the reason. The arguments "start" and "end" are used
590 to return the offsets of the first and one past the last characters in the
591 original mailbox of the address that has been extracted, to aid in re-writing.
592 The argument "domain" is set to point to the first character after "@" in the
593 final part of the returned address, or zero if there is no @.
594
595 Exim no longer supports the use of source routed addresses (those of the form
596 @domain,...:route_addr). It recognizes the syntax, but collapses such addresses
597 down to their final components. Formerly, collapse_source_routes had to be set
598 to achieve this effect. RFC 1123 allows collapsing with MAY, while the revision
599 of RFC 821 had increased this to SHOULD, so I've gone for it, because it makes
600 a lot of code elsewhere in Exim much simpler.
601
602 There are some special fudges here for handling RFC 822 group address notation
603 which may appear in certain headers. If the flag parse_allow_group is set
604 TRUE and parse_found_group is FALSE when this function is called, an address
605 which is the start of a group (i.e. preceded by a phrase and a colon) is
606 recognized; the phrase is ignored and the flag parse_found_group is set. If
607 this flag is TRUE at the end of an address, and if an extraneous semicolon is
608 found, it is ignored and the flag is cleared.
609
610 This logic is used only when scanning through addresses in headers, either to
611 fulfil the -t option, or for rewriting, or for checking header syntax. Because
612 the group "state" has to be remembered between multiple calls of this function,
613 the variables parse_{allow,found}_group are global. It is important to ensure
614 that they are reset to FALSE at the end of scanning a header's list of
615 addresses.
616
617 Arguments:
618   mailbox     points to the RFC822 mailbox
619   errorptr    where to point an error message
620   start       set to start offset in mailbox
621   end         set to end offset in mailbox
622   domain      set to domain offset in result, or 0 if no domain present
623   allow_null  allow <> if TRUE
624
625 Returns:      points to the extracted address, or NULL on error
626 */
627
628 #define FAILED(s) { *errorptr = s; goto PARSE_FAILED; }
629
630 uschar *
631 parse_extract_address(const uschar *mailbox, uschar **errorptr, int *start, int *end,
632   int *domain, BOOL allow_null)
633 {
634 uschar * yield = store_get(Ustrlen(mailbox) + 1, mailbox);
635 const uschar *startptr, *endptr;
636 const uschar *s = US mailbox;
637 uschar *t = US yield;
638
639 *domain = 0;
640
641 /* At the start of the string we expect either an addr-spec or a phrase
642 preceding a <route-addr>. If groups are allowed, we might also find a phrase
643 preceding a colon and an address. If we find an initial word followed by
644 a dot, strict interpretation of the RFC would cause it to be taken
645 as the start of an addr-spec. However, many mailers break the rules
646 and use addresses of the form "a.n.other <ano@somewhere>" and so we
647 allow this case. */
648
649 RESTART:   /* Come back here after passing a group name */
650
651 s = skip_comment(s);
652 startptr = s;                                 /* In case addr-spec */
653 s = read_local_part(s, t, errorptr, TRUE);    /* Dot separated words */
654 if (*errorptr) goto PARSE_FAILED;
655
656 /* If the terminator is neither < nor @ then the format of the address
657 must either be a bare local-part (we are now at the end), or a phrase
658 followed by a route-addr (more words must follow). */
659
660 if (*s != '@' && *s != '<')
661   {
662   if (!*s || *s == ';')
663     {
664     if (!*t) FAILED(US"empty address");
665     endptr = last_comment_position;
666     goto PARSE_SUCCEEDED;              /* Bare local part */
667     }
668
669   /* Expect phrase route-addr, or phrase : if groups permitted, but allow
670   dots in the phrase; complete the loop only when '<' or ':' is encountered -
671   end of string will produce a null local_part and therefore fail. We don't
672   need to keep updating t, as the phrase isn't to be kept. */
673
674   while (*s != '<' && (!f.parse_allow_group || *s != ':'))
675     {
676     s = read_local_part(s, t, errorptr, FALSE);
677     if (*errorptr)
678       {
679       *errorptr = string_sprintf("%s (expected word or \"<\")", *errorptr);
680       goto PARSE_FAILED;
681       }
682     }
683
684   if (*s == ':')
685     {
686     f.parse_found_group = TRUE;
687     f.parse_allow_group = FALSE;
688     s++;
689     goto RESTART;
690     }
691
692   /* Assert *s == '<' */
693   }
694
695 /* At this point the next character is either '@' or '<'. If it is '@', only a
696 single local-part has previously been read. An angle bracket signifies the
697 start of an <addr-spec>. Throw away anything we have saved so far before
698 processing it. Note that this is "if" rather than "else if" because it's also
699 used after reading a preceding phrase.
700
701 There are a lot of broken sendmails out there that put additional pairs of <>
702 round <route-addr>s.  If strip_excess_angle_brackets is set, allow a limited
703 number of them, as long as they match. */
704
705 if (*s == '<')
706   {
707   uschar *domainptr = yield;
708   BOOL source_routed = FALSE;
709   int bracket_count = 1;
710
711   s++;
712   if (strip_excess_angle_brackets) while (*s == '<')
713    {
714    if(bracket_count++ > 5) FAILED(US"angle-brackets nested too deep");
715    s++;
716    }
717
718   t = yield;
719   startptr = s;
720   s = skip_comment(s);
721
722   /* Read an optional series of routes, each of which is a domain. They
723   are separated by commas and terminated by a colon. However, we totally ignore
724   such routes (RFC 1123 says we MAY, and the revision of RFC 821 says we
725   SHOULD). */
726
727   if (*s == '@')
728     {
729     s = read_route(s, t, errorptr);
730     if (*errorptr) goto PARSE_FAILED;
731     *t = 0;                  /* Ensure route is ignored - probably overkill */
732     source_routed = TRUE;
733     }
734
735   /* Now an addr-spec, terminated by '>'. If there is no preceding route,
736   we must allow an empty addr-spec if allow_null is TRUE, to permit the
737   address "<>" in some circumstances. A source-routed address MUST have
738   a domain in the final part. */
739
740   if (allow_null && !source_routed && *s == '>')
741     {
742     *t = 0;
743     *errorptr = NULL;
744     }
745   else
746     {
747     s = read_addr_spec(s, t, '>', errorptr, &domainptr);
748     if (*errorptr) goto PARSE_FAILED;
749     *domain = domainptr - yield;
750     if (source_routed && *domain == 0)
751       FAILED(US"domain missing in source-routed address");
752     }
753
754   endptr = s;
755   if (*errorptr) goto PARSE_FAILED;
756   while (bracket_count-- > 0) if (*s++ != '>')
757     {
758     *errorptr = s[-1] == 0
759       ? US"'>' missing at end of address"
760       : string_sprintf("malformed address: %.32s may not follow %.*s",
761           s-1, (int)(s - US mailbox - 1), mailbox);
762     goto PARSE_FAILED;
763     }
764
765   s = skip_comment(s);
766   }
767
768 /* Hitting '@' after the first local-part means we have definitely got an
769 addr-spec, on a strict reading of the RFC, and the rest of the string
770 should be the domain. However, for flexibility we allow for a route-address
771 not enclosed in <> as well, which is indicated by an empty first local
772 part preceding '@'. The source routing is, however, ignored. */
773
774 else if (!*t)
775   {
776   uschar *domainptr = yield;
777   s = read_route(s, t, errorptr);
778   if (*errorptr) goto PARSE_FAILED;
779   *t = 0;         /* Ensure route is ignored - probably overkill */
780   s = read_addr_spec(s, t, 0, errorptr, &domainptr);
781   if (*errorptr) goto PARSE_FAILED;
782   *domain = domainptr - yield;
783   endptr = last_comment_position;
784   if (*domain == 0) FAILED(US"domain missing in source-routed address");
785   }
786
787 /* This is the strict case of local-part@domain. */
788
789 else
790   {
791   t += Ustrlen((const uschar *)t);
792   *t++ = *s++;
793   *domain = t - yield;
794   s = read_domain(s, t, TRUE, errorptr);
795   if (!*t) goto PARSE_FAILED;
796   endptr = last_comment_position;
797   }
798
799 /* Use goto to get here from the bare local part case. Arrive by falling
800 through for other cases. Endptr may have been moved over whitespace, so
801 move it back past white space if necessary. */
802
803 PARSE_SUCCEEDED:
804 if (*s)
805   {
806   if (f.parse_found_group && *s == ';')
807     {
808     f.parse_found_group = FALSE;
809     f.parse_allow_group = TRUE;
810     }
811   else
812     {
813     *errorptr = string_sprintf("malformed address: %.32s may not follow %.*s",
814       s, (int)(s - US mailbox), mailbox);
815     goto PARSE_FAILED;
816     }
817   }
818 *start = startptr - US mailbox;      /* Return offsets */
819 while (isspace(endptr[-1])) endptr--;
820 *end = endptr - US mailbox;
821
822 /* Although this code has no limitation on the length of address extracted,
823 other parts of Exim may have limits, and in any case, RFC 5321 limits email
824 addresses to 256, so we do a check here, giving an error if the address is
825 ridiculously long. */
826
827 if (*end - *start > EXIM_EMAILADDR_MAX)
828   {
829   *errorptr = string_sprintf("address is ridiculously long: %.64s...", yield);
830   return NULL;
831   }
832
833 return yield;
834
835 /* Use goto (via the macro FAILED) to get to here from a variety of places.
836 We might have an empty address in a group - the caller can choose to ignore
837 this. We must, however, keep the flags correct. */
838
839 PARSE_FAILED:
840 if (f.parse_found_group && *s == ';')
841   {
842   f.parse_found_group = FALSE;
843   f.parse_allow_group = TRUE;
844   }
845 return NULL;
846 }
847
848 #undef FAILED
849
850
851
852 /*************************************************
853 *        Quote according to RFC 2047             *
854 *************************************************/
855
856 /* This function is used for quoting text in headers according to RFC 2047.
857 If the only characters that strictly need quoting are spaces, we return the
858 original string, unmodified.
859
860 Hmmph. As always, things get perverted for other uses. This function was
861 originally for the "phrase" part of addresses. Now it is being used for much
862 longer texts in ACLs and via the ${rfc2047: expansion item. This means we have
863 to check for overlong "encoded-word"s and split them. November 2004.
864
865 Arguments:
866   string       the string to quote - already checked to contain non-printing
867                  chars
868   len          the length of the string
869   charset      the name of the character set; NULL => iso-8859-1
870   fold         if TRUE, a newline is inserted before the separating space when
871                  more than one encoded-word is generated
872
873 Returns:       pointer to the original string, if no quoting needed, or
874                pointer to allocated memory containing the quoted string
875 */
876
877 const uschar *
878 parse_quote_2047(const uschar *string, int len, const uschar *charset,
879   BOOL fold)
880 {
881 const uschar * s = string;
882 int hlen, l;
883 BOOL coded = FALSE;
884 BOOL first_byte = FALSE;
885 gstring * g =
886   string_fmt_append(NULL, "=?%s?Q?", charset ? charset : US"iso-8859-1");
887
888 hlen = l = g->ptr;
889
890 for (s = string; len > 0; s++, len--)
891   {
892   int ch = *s;
893
894   if (g->ptr - l > 67 && !first_byte)
895     {
896     g = fold ? string_catn(g, US"?=\n ", 4) : string_catn(g, US"?= ", 3);
897     l = g->ptr;
898     g = string_catn(g, g->s, hlen);
899     }
900
901   if (  ch < 33 || ch > 126
902      || Ustrchr("?=()<>@,;:\\\".[]_", ch) != NULL)
903     {
904     if (ch == ' ')
905       {
906       g = string_catn(g, US"_", 1);
907       first_byte = FALSE;
908       }
909     else
910       {
911       g = string_fmt_append(g, "=%02X", ch);
912       coded = TRUE;
913       first_byte = !first_byte;
914       }
915     }
916   else
917     { g = string_catn(g, s, 1); first_byte = FALSE; }
918   }
919
920 if (coded)
921   string = string_from_gstring(g = string_catn(g, US"?=", 2));
922 else
923   g->ptr = -1;
924
925 gstring_release_unused(g);
926 return string;
927 }
928
929
930
931
932 /*************************************************
933 *            Fix up an RFC 822 "phrase"          *
934 *************************************************/
935
936 /* This function is called to repair any syntactic defects in the "phrase" part
937 of an RFC822 address. In particular, it is applied to the user's name as read
938 from the passwd file when accepting a local message, and to the data from the
939 -F option.
940
941 If the string contains existing quoted strings or comments containing
942 freestanding quotes, then we just quote those bits that need quoting -
943 otherwise it would get awfully messy and probably not look good. If not, we
944 quote the whole thing if necessary. Thus
945
946    John Q. Smith            =>  "John Q. Smith"
947    John "Jack" Smith        =>  John "Jack" Smith
948    John "Jack" Q. Smith     =>  John "Jack" "Q." Smith
949    John (Jack) Q. Smith     =>  "John (Jack) Q. Smith"
950    John ("Jack") Q. Smith   =>  John ("Jack") "Q." Smith
951 but
952    John (\"Jack\") Q. Smith =>  "John (\"Jack\") Q. Smith"
953
954 Sheesh! This is tedious code. It is a great pity that the syntax of RFC822 is
955 the way it is...
956
957 August 2000: Additional code added:
958
959   Previously, non-printing characters were turned into question marks, which do
960   not need to be quoted.
961
962   Now, a different tactic is used if there are any non-printing ASCII
963   characters. The encoding method from RFC 2047 is used, assuming iso-8859-1 as
964   the character set.
965
966   We *could* use this for all cases, getting rid of the messy original code,
967   but leave it for now. It would complicate simple cases like "John Q. Smith".
968
969 The result is passed back in allocated memory.
970
971 Arguments:
972   phrase       an RFC822 phrase
973   len          the length of the phrase
974
975 Returns:       the fixed RFC822 phrase
976 */
977
978 const uschar *
979 parse_fix_phrase(const uschar *phrase, int len)
980 {
981 int ch, i;
982 BOOL quoted = FALSE;
983 const uschar *s, *end;
984 uschar * buffer;
985 uschar *t, *yield;
986
987 while (len > 0 && isspace(*phrase)) { phrase++; len--; }
988
989 /* See if there are any non-printing characters, and if so, use the RFC 2047
990 encoding for the whole thing. */
991
992 for (i = 0, s = phrase; i < len; i++, s++)
993   if ((*s < 32 && *s != '\t') || *s > 126) break;
994
995 if (i < len)
996   return parse_quote_2047(phrase, len, headers_charset, FALSE);
997
998 /* No non-printers; use the RFC 822 quoting rules */
999
1000 if (len <= 0 || len >= INT_MAX/4)
1001   return string_copy_taint(CUS"", phrase);
1002
1003 buffer = store_get((len+1)*4, phrase);
1004
1005 s = phrase;
1006 end = s + len;
1007 yield = t = buffer + 1;
1008
1009 while (s < end)
1010   {
1011   ch = *s++;
1012
1013   /* Copy over quoted strings, remembering we encountered one */
1014
1015   if (ch == '\"')
1016     {
1017     *t++ = '\"';
1018     while (s < end && (ch = *s++) != '\"')
1019       {
1020       *t++ = ch;
1021       if (ch == '\\' && s < end) *t++ = *s++;
1022       }
1023     *t++ = '\"';
1024     if (s >= end) break;
1025     quoted = TRUE;
1026     }
1027
1028   /* Copy over comments, noting if they contain freestanding quote
1029   characters */
1030
1031   else if (ch == '(')
1032     {
1033     int level = 1;
1034     *t++ = '(';
1035     while (s < end)
1036       {
1037       ch = *s++;
1038       *t++ = ch;
1039       if (ch == '(') level++;
1040       else if (ch == ')') { if (--level <= 0) break; }
1041       else if (ch == '\\' && s < end) *t++ = *s++ & 127;
1042       else if (ch == '\"') quoted = TRUE;
1043       }
1044     if (ch == 0)
1045       {
1046       while (level--) *t++ = ')';
1047       break;
1048       }
1049     }
1050
1051   /* Handle special characters that need to be quoted */
1052
1053   else if (Ustrchr(")<>@,;:\\.[]", ch) != NULL)
1054     {
1055     /* If hit previous quotes just make one quoted "word" */
1056
1057     if (quoted)
1058       {
1059       uschar *tt = t++;
1060       while (*(--tt) != ' ' && *tt != '\"' && *tt != ')') tt[1] = *tt;
1061       tt[1] = '\"';
1062       *t++ = ch;
1063       while (s < end)
1064         {
1065         ch = *s++;
1066         if (ch == ' ' || ch == '\"') { s--; break; } else *t++ = ch;
1067         }
1068       *t++ = '\"';
1069       }
1070
1071     /* Else quote the whole string so far, and the rest up to any following
1072     quotes. We must treat anything following a backslash as a literal. */
1073
1074     else
1075       {
1076       BOOL escaped = (ch == '\\');
1077       *(--yield) = '\"';
1078       *t++ = ch;
1079
1080       /* Now look for the end or a quote */
1081
1082       while (s < end)
1083         {
1084         ch = *s++;
1085
1086         /* Handle escaped pairs */
1087
1088         if (escaped)
1089           {
1090           *t++ = ch;
1091           escaped = FALSE;
1092           }
1093
1094         else if (ch == '\\')
1095           {
1096           *t++ = ch;
1097           escaped = TRUE;
1098           }
1099
1100         /* If hit subsequent quotes, insert our quote before any trailing
1101         spaces and back up to re-handle the quote in the outer loop. */
1102
1103         else if (ch == '\"')
1104           {
1105           int count = 0;
1106           while (t[-1] == ' ') { t--; count++; }
1107           *t++ = '\"';
1108           while (count-- > 0) *t++ = ' ';
1109           s--;
1110           break;
1111           }
1112
1113         /* If hit a subsequent comment, check it for unescaped quotes,
1114         and if so, end our quote before it. */
1115
1116         else if (ch == '(')
1117           {
1118           const uschar *ss = s;     /* uschar after '(' */
1119           int level = 1;
1120           while(ss < end)
1121             {
1122             ch = *ss++;
1123             if (ch == '(') level++;
1124             else if (ch == ')') { if (--level <= 0) break; }
1125             else if (ch == '\\' && ss+1 < end) ss++;
1126             else if (ch == '\"') { quoted = TRUE; break; }
1127             }
1128
1129           /* Comment contains unescaped quotes; end our quote before
1130           the start of the comment. */
1131
1132           if (quoted)
1133             {
1134             int count = 0;
1135             while (t[-1] == ' ') { t--; count++; }
1136             *t++ = '\"';
1137             while (count-- > 0) *t++ = ' ';
1138             break;
1139             }
1140
1141           /* Comment does not contain unescaped quotes; include it in
1142           our quote. */
1143
1144           else
1145             {
1146             if (ss >= end) ss--;
1147             *t++ = '(';
1148             if (ss > s)
1149               {
1150               Ustrncpy(t, s, ss-s);
1151               t += ss-s;
1152               s = ss;
1153               }
1154             }
1155           }
1156
1157         /* Not a comment or quote; include this character in our quotes. */
1158
1159         else *t++ = ch;
1160         }
1161       }
1162
1163     /* Add a final quote if we hit the end of the string. */
1164
1165     if (s >= end) *t++ = '\"';
1166     }
1167
1168   /* Non-special character; just copy it over */
1169
1170   else *t++ = ch;
1171   }
1172
1173 *t = 0;
1174 store_release_above(t+1);
1175 return yield;
1176 }
1177
1178
1179 /*************************************************
1180 *          Extract addresses from a list         *
1181 *************************************************/
1182
1183 /* This function is called by the redirect router to scan a string containing a
1184 list of addresses separated by commas (with optional white space) or by
1185 newlines, and to generate a chain of address items from them. In other words,
1186 to unpick data from an alias or .forward file.
1187
1188 The SunOS5 documentation for alias files is not very clear on the syntax; it
1189 does not say that either a comma or a newline can be used for separation.
1190 However, that is the way Smail does it, so we follow suit.
1191
1192 If a # character is encountered in a white space position, then characters from
1193 there to the next newline are skipped.
1194
1195 If an unqualified address begins with '\', just skip that character. This gives
1196 compatibility with Sendmail's use of \ to prevent looping. Exim has its own
1197 loop prevention scheme which handles other cases too - see the code in
1198 route_address().
1199
1200 An "address" can be a specification of a file or a pipe; the latter may often
1201 need to be quoted because it may contain spaces, but we don't want to retain
1202 the quotes. Quotes may appear in normal addresses too, and should be retained.
1203 We can distinguish between these cases, because in addresses, quotes are used
1204 only for parts of the address, not the whole thing. Therefore, we remove quotes
1205 from items when they entirely enclose them, but not otherwise.
1206
1207 An "address" can also be of the form :include:pathname to include a list of
1208 addresses contained in the specified file.
1209
1210 Any unqualified addresses are qualified with and rewritten if necessary, via
1211 the rewrite_address() function.
1212
1213 Arguments:
1214   s                the list of addresses (typically a complete
1215                      .forward file or a list of entries in an alias file)
1216   options          option bits for permitting or denying various special cases;
1217                      not all bits are relevant here - some are for filter
1218                      files; those we use here are:
1219                        RDO_DEFER
1220                        RDO_FREEZE
1221                        RDO_FAIL
1222                        RDO_BLACKHOLE
1223                        RDO_REWRITE
1224                        RDO_INCLUDE
1225   anchor           where to hang the chain of newly-created addresses. This
1226                      should be initialized to NULL.
1227   error            where to return an error text
1228   incoming domain  domain of the incoming address; used to qualify unqualified
1229                      local parts preceded by \
1230   directory        if NULL, no checks are done on :include: files
1231                    otherwise, included file names must start with the given
1232                      directory
1233   syntax_errors    if not NULL, it carries on after syntax errors in addresses,
1234                      building up a list of errors as error blocks chained on
1235                      here.
1236
1237 Returns:      FF_DELIVERED      addresses extracted
1238               FF_NOTDELIVERED   no addresses extracted, but no errors
1239               FF_BLACKHOLE      :blackhole:
1240               FF_DEFER          :defer:
1241               FF_FAIL           :fail:
1242               FF_INCLUDEFAIL    some problem with :include:; *error set
1243               FF_ERROR          other problems; *error is set
1244 */
1245
1246 int
1247 parse_forward_list(const uschar *s, int options, address_item **anchor,
1248   uschar **error, const uschar *incoming_domain, const uschar *directory,
1249   error_block **syntax_errors)
1250 {
1251 int count = 0;
1252
1253 DEBUG(D_route) debug_printf("parse_forward_list: %s\n", s);
1254
1255 for (;;)
1256   {
1257   int len, special = 0, specopt = 0, specbit = 0;
1258   const uschar * ss, * nexts;
1259   address_item * addr;
1260   BOOL inquote = FALSE;
1261
1262   for (;;)
1263     {
1264     while (isspace(*s) || *s == ',') s++;
1265     if (*s == '#') { while (*s && *s != '\n') s++; } else break;
1266     }
1267
1268   /* When we reach the end of the list, we return FF_DELIVERED if any child
1269   addresses have been generated. If nothing has been generated, there are two
1270   possibilities: either the list is really empty, or there were syntax errors
1271   that are being skipped. (If syntax errors are not being skipped, an FF_ERROR
1272   return is generated on hitting a syntax error and we don't get here.) For a
1273   truly empty list we return FF_NOTDELIVERED so that the router can decline.
1274   However, if the list is empty only because syntax errors were skipped, we
1275   return FF_DELIVERED. */
1276
1277   if (!*s)
1278     {
1279     return (count > 0 || (syntax_errors && *syntax_errors))
1280       ?  FF_DELIVERED : FF_NOTDELIVERED;
1281
1282     /* This previous code returns FF_ERROR if nothing is generated but a
1283     syntax error has been skipped. I now think it is the wrong approach, but
1284     have left this here just in case, and for the record. */
1285
1286 #ifdef NEVER
1287     if (count > 0) return FF_DELIVERED;   /* Something was generated */
1288
1289     if (!syntax_errors ||          /* Not skipping syntax errors, or */
1290        !*syntax_errors)            /*   we didn't actually skip any */
1291       return FF_NOTDELIVERED;
1292
1293     *error = string_sprintf("no addresses generated: syntax error in %s: %s",
1294        (*syntax_errors)->text2, (*syntax_errors)->text1);
1295     return FF_ERROR;
1296 #endif
1297     }
1298
1299   /* Find the end of the next address. Quoted strings in addresses may contain
1300   escaped characters; I haven't found a proper specification of .forward or
1301   alias files that mentions the quoting properties, but it seems right to do
1302   the escaping thing in all cases, so use the function that finds the end of an
1303   address. However, don't let a quoted string extend over the end of a line. */
1304
1305   ss = parse_find_address_end(s, TRUE);
1306
1307   /* Remember where we finished, for starting the next one. */
1308
1309   nexts = ss;
1310
1311   /* Remove any trailing spaces; we know there's at least one non-space. */
1312
1313   while (isspace(ss[-1])) ss--;
1314
1315   /* We now have s->start and ss->end of the next address. Remove quotes
1316   if they completely enclose, remembering the address started with a quote
1317   for handling pipes and files. Another round of removal of leading and
1318   trailing spaces is then required. */
1319
1320   if (*s == '\"' && ss[-1] == '\"')
1321     {
1322     s++;
1323     ss--;
1324     inquote = TRUE;
1325     while (s < ss && isspace(*s)) s++;
1326     while (ss > s && isspace(ss[-1])) ss--;
1327     }
1328
1329   /* Set up the length of the address. */
1330
1331   len = ss - s;
1332
1333   DEBUG(D_route) debug_printf("extract item: %.*s\n", len, s);
1334
1335   /* Handle special addresses if permitted. If the address is :unknown:
1336   ignore it - this is for backward compatibility with old alias files. You
1337   don't need to use it nowadays - just generate an empty string. For :defer:,
1338   :blackhole:, or :fail: we have to set up the error message and give up right
1339   away. */
1340
1341   if (Ustrncmp(s, ":unknown:", len) == 0)
1342     {
1343     s = nexts;
1344     continue;
1345     }
1346
1347   if      (Ustrncmp(s, ":defer:", 7) == 0)
1348     { special = FF_DEFER; specopt = RDO_DEFER; }  /* specbit is 0 */
1349   else if (Ustrncmp(s, ":blackhole:", 11) == 0)
1350     { special = FF_BLACKHOLE; specopt = specbit = RDO_BLACKHOLE; }
1351   else if (Ustrncmp(s, ":fail:", 6) == 0)
1352     { special = FF_FAIL; specopt = RDO_FAIL; }  /* specbit is 0 */
1353
1354   if (special)
1355     {
1356     uschar * ss = Ustrchr(s+1, ':') + 1; /* line after the special... */
1357     if ((options & specopt) == specbit)
1358       {
1359       *error = string_sprintf("\"%.*s\" is not permitted", len, s);
1360       return FF_ERROR;
1361       }
1362     while (*ss && isspace(*ss)) ss++;   /* skip leading whitespace */
1363     if ((len = Ustrlen(ss)) > 0)        /* ignore trailing newlines */
1364       for (const uschar * t = ss + len - 1; t >= ss && *t == '\n'; t--) len--;
1365     *error = string_copyn(ss, len);     /* becomes the error */
1366     return special;
1367     }
1368
1369   /* If the address is of the form :include:pathname, read the file, and call
1370   this function recursively to extract the addresses from it. If directory is
1371   NULL, do no checks. Otherwise, insist that the file name starts with the
1372   given directory and is a regular file. */
1373
1374   if (Ustrncmp(s, ":include:", 9) == 0)
1375     {
1376     uschar * filebuf;
1377     uschar filename[256];
1378     const uschar * t = s+9;
1379     int flen = len - 9;
1380     int frc;
1381     struct stat statbuf;
1382     address_item * last;
1383     FILE * f;
1384
1385     while (flen > 0 && isspace(*t)) { t++; flen--; }
1386
1387     if (flen <= 0)
1388       {
1389       *error = US"file name missing after :include:";
1390       return FF_ERROR;
1391       }
1392
1393     if (flen > sizeof(filename)-1)
1394       {
1395       *error = string_sprintf("included file name \"%s\" is too long", t);
1396       return FF_ERROR;
1397       }
1398
1399     Ustrncpy(filename, t, flen);
1400     filename[flen] = 0;
1401
1402     /* Insist on absolute path */
1403
1404     if (filename[0] != '/')
1405       {
1406       *error = string_sprintf("included file \"%s\" is not an absolute path",
1407         filename);
1408       return FF_ERROR;
1409       }
1410
1411     /* Check if include is permitted */
1412
1413     if (options & RDO_INCLUDE)
1414       {
1415       *error = US"included files not permitted";
1416       return FF_ERROR;
1417       }
1418
1419     if (is_tainted(filename))
1420       {
1421       *error = string_sprintf("Tainted name '%s' for included file  not permitted\n",
1422        filename);
1423       return FF_ERROR;
1424       }
1425
1426     /* Check file name if required */
1427
1428     if (directory)
1429       {
1430       int len = Ustrlen(directory);
1431       uschar * p;
1432
1433       while (len > 0 && directory[len-1] == '/') len--;         /* ignore trailing '/' */
1434       p = filename + len;
1435       if (Ustrncmp(filename, directory, len) != 0 || *p != '/')
1436         {
1437         *error = string_sprintf("included file %s is not in directory %s",
1438           filename, directory);
1439         return FF_ERROR;
1440         }
1441
1442 #ifdef EXIM_HAVE_OPENAT
1443       /* It is necessary to check that every component inside the directory
1444       is NOT a symbolic link, in order to keep the file inside the directory.
1445       This is mighty tedious. We open the directory and openat every component,
1446       with a flag that fails symlinks. */
1447
1448       {
1449       int fd = exim_open2(CCS directory, O_RDONLY);
1450       if (fd < 0)
1451         {
1452         *error = string_sprintf("failed to open directory %s", directory);
1453         return FF_ERROR;
1454         }
1455       while (*p)
1456         {
1457         uschar temp;
1458         int fd2;
1459         uschar * q = p + 1;             /* skip dividing '/' */
1460
1461         while (*q == '/') q++;          /* skip extra '/' */
1462         while (*++p && *p != '/') ;     /* end of component */
1463         temp = *p;
1464         *p = '\0';
1465
1466         fd2 = exim_openat(fd, CS q, O_RDONLY|O_NOFOLLOW);
1467         close(fd);
1468         *p = temp;
1469         if (fd2 < 0)
1470           {
1471           *error = string_sprintf("failed to open %s (component of included "
1472             "file); could be symbolic link", filename);
1473           return FF_ERROR;
1474           }
1475         fd = fd2;
1476         }
1477       f = fdopen(fd, "rb");
1478       }
1479 #else
1480       /* It is necessary to check that every component inside the directory
1481       is NOT a symbolic link, in order to keep the file inside the directory.
1482       This is mighty tedious. It is also not totally foolproof in that it
1483       leaves the possibility of a race attack, but I don't know how to do
1484       any better. */
1485
1486       while (*p)
1487         {
1488         int temp;
1489         while (*++p && *p != '/');
1490         temp = *p;
1491         *p = 0;
1492         if (Ulstat(filename, &statbuf) != 0)
1493           {
1494           *error = string_sprintf("failed to stat %s (component of included "
1495             "file)", filename);
1496           *p = temp;
1497           return FF_ERROR;
1498           }
1499
1500         *p = temp;
1501
1502         if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
1503           {
1504           *error = string_sprintf("included file %s in the %s directory "
1505             "involves a symbolic link", filename, directory);
1506           return FF_ERROR;
1507           }
1508         }
1509 #endif
1510       }
1511
1512 #ifdef EXIM_HAVE_OPENAT
1513     else
1514 #endif
1515       /* Open and stat the file */
1516       f = Ufopen(filename, "rb");
1517
1518     if (!f)
1519       {
1520       *error = string_open_failed("included file %s", filename);
1521       return FF_INCLUDEFAIL;
1522       }
1523
1524     if (fstat(fileno(f), &statbuf) != 0)
1525       {
1526       *error = string_sprintf("failed to stat included file %s: %s",
1527         filename, strerror(errno));
1528       (void)fclose(f);
1529       return FF_INCLUDEFAIL;
1530       }
1531
1532     /* If directory was checked, double check that we opened a regular file */
1533
1534     if (directory && (statbuf.st_mode & S_IFMT) != S_IFREG)
1535       {
1536       *error = string_sprintf("included file %s is not a regular file in "
1537         "the %s directory", filename, directory);
1538       return FF_ERROR;
1539       }
1540
1541     /* Get a buffer and read the contents */
1542
1543     if (statbuf.st_size > MAX_INCLUDE_SIZE)
1544       {
1545       *error = string_sprintf("included file %s is too big (max %d)",
1546         filename, MAX_INCLUDE_SIZE);
1547       return FF_ERROR;
1548       }
1549
1550     filebuf = store_get(statbuf.st_size + 1, filename);
1551     if (fread(filebuf, 1, statbuf.st_size, f) != statbuf.st_size)
1552       {
1553       *error = string_sprintf("error while reading included file %s: %s",
1554         filename, strerror(errno));
1555       (void)fclose(f);
1556       return FF_ERROR;
1557       }
1558     filebuf[statbuf.st_size] = 0;
1559     (void)fclose(f);
1560
1561     addr = NULL;
1562     frc = parse_forward_list(filebuf, options, &addr,
1563       error, incoming_domain, directory, syntax_errors);
1564     if (frc != FF_DELIVERED && frc != FF_NOTDELIVERED) return frc;
1565
1566     if (addr)
1567       {
1568       for (last = addr; last->next; last = last->next) count++;
1569       last->next = *anchor;
1570       *anchor = addr;
1571       count++;
1572       }
1573     }
1574
1575   /* Else (not :include:) ensure address is syntactically correct and fully
1576   qualified if not a pipe or a file, removing a leading \ if present on an
1577   unqualified address. For pipes and files we must handle quoting. It's
1578   not quite clear exactly what to do for partially quoted things, but the
1579   common case of having the whole thing in quotes is straightforward. If this
1580   was the case, inquote will have been set TRUE above and the quotes removed.
1581
1582   There is a possible ambiguity over addresses whose local parts start with
1583   a vertical bar or a slash, and the latter do in fact occur, thanks to X.400.
1584   Consider a .forward file that contains the line
1585
1586      /X=xxx/Y=xxx/OU=xxx/@some.gate.way
1587
1588   Is this a file or an X.400 address? Does it make any difference if it is in
1589   quotes? On the grounds that file names of this type are rare, Exim treats
1590   something that parses as an RFC 822 address and has a domain as an address
1591   rather than a file or a pipe. This is also how an address such as the above
1592   would be treated if it came in from outside. */
1593
1594   else
1595     {
1596     int start, end, domain;
1597     const uschar *recipient = NULL;
1598     uschar * s_ltd = string_copyn(s, len);
1599
1600     /* If it starts with \ and the rest of it parses as a valid mail address
1601     without a domain, carry on with that address, but qualify it with the
1602     incoming domain. Otherwise arrange for the address to fall through,
1603     causing an error message on the re-parse. */
1604
1605     if (*s_ltd == '\\')
1606       {
1607       recipient =
1608         parse_extract_address(s_ltd+1, error, &start, &end, &domain, FALSE);
1609       if (recipient)
1610         recipient = domain != 0 ? NULL :
1611           string_sprintf("%s@%s", recipient, incoming_domain);
1612       }
1613
1614     /* Try parsing the item as an address. */
1615
1616     if (!recipient) recipient =
1617       parse_extract_address(s_ltd, error, &start, &end, &domain, FALSE);
1618
1619     /* If item starts with / or | and is not a valid address, or there
1620     is no domain, treat it as a file or pipe. If it was a quoted item,
1621     remove the quoting occurrences of \ within it. */
1622
1623     if ((*s_ltd == '|' || *s_ltd == '/') && (!recipient || domain == 0))
1624       {
1625       uschar * t = store_get(Ustrlen(s_ltd) + 1, s_ltd);
1626       uschar * p = t, * q = s_ltd;
1627
1628       while (*q)
1629         {
1630         if (inquote)
1631           {
1632           *p++ = *q == '\\' ? *++q : *q;
1633           q++;
1634           }
1635         else *p++ = *q++;
1636         }
1637       *p = 0;
1638       addr = deliver_make_addr(t, TRUE);
1639       setflag(addr, af_pfr);                   /* indicates pipe/file/reply */
1640       if (*s_ltd != '|') setflag(addr, af_file);   /* indicates file */
1641       }
1642
1643     /* Item must be an address. Complain if not, else qualify, rewrite and set
1644     up the control block. It appears that people are in the habit of using
1645     empty addresses but with comments as a way of putting comments into
1646     alias and forward files. Therefore, ignore the error "empty address".
1647     Mailing lists might want to tolerate syntax errors; there is therefore
1648     an option to do so. */
1649
1650     else
1651       {
1652       if (!recipient)
1653         {
1654         if (Ustrcmp(*error, "empty address") == 0)
1655           {
1656           *error = NULL;
1657           s = nexts;
1658           continue;
1659           }
1660
1661         if (syntax_errors)
1662           {
1663           error_block * e = store_get(sizeof(error_block), GET_UNTAINTED);
1664           error_block * last = *syntax_errors;
1665           if (last)
1666             {
1667             while (last->next) last = last->next;
1668             last->next = e;
1669             }
1670           else
1671             *syntax_errors = e;
1672           e->next = NULL;
1673           e->text1 = *error;
1674           e->text2 = s_ltd;
1675           s = nexts;
1676           continue;
1677           }
1678         else
1679           {
1680           *error = string_sprintf("%s in \"%s\"", *error, s_ltd);
1681           return FF_ERROR;
1682           }
1683         }
1684
1685       /* Address was successfully parsed. Rewrite, and then make an address
1686       block. */
1687
1688       recipient = options & RDO_REWRITE
1689         ? rewrite_address(recipient, TRUE, FALSE, global_rewrite_rules,
1690                           rewrite_existflags)
1691         : rewrite_address_qualify(recipient, TRUE);     /*XXX loses track of const */
1692       addr = deliver_make_addr(US recipient, TRUE);  /* TRUE => copy recipient, so deconst ok */
1693       }
1694
1695     /* Add the original data to the output chain. */
1696
1697     addr->next = *anchor;
1698     *anchor = addr;
1699     count++;
1700     }
1701
1702   /* Advance pointer for the next address */
1703
1704   s = nexts;
1705   }
1706 }
1707
1708
1709 /*************************************************
1710 *            Extract a Message-ID                *
1711 *************************************************/
1712
1713 /* This function is used to extract message ids from In-Reply-To: and
1714 References: header lines.
1715
1716 Arguments:
1717   str          pointer to the start of the message-id
1718   yield        put pointer to the message id (in dynamic memory) here
1719   error        put error message here on failure
1720
1721 Returns:       points after the processed message-id or NULL on error
1722 */
1723
1724 const uschar *
1725 parse_message_id(const uschar *str, uschar **yield, uschar **error)
1726 {
1727 uschar *domain = NULL;
1728 uschar *id;
1729 rmark reset_point;
1730
1731 str = skip_comment(str);
1732 if (*str != '<')
1733   {
1734   *error = US"Missing '<' before message-id";
1735   return NULL;
1736   }
1737
1738 /* Getting a block the size of the input string will definitely be sufficient
1739 for the answer, but it may also be very long if we are processing a header
1740 line. Therefore, take care to release unwanted store afterwards. */
1741
1742 reset_point = store_mark();
1743 id = *yield = store_get(Ustrlen(str) + 1, str);
1744 *id++ = *str++;
1745
1746 str = read_addr_spec(str, id, '>', error, &domain);
1747
1748 if (!*error)
1749   {
1750   if (*str != '>') *error = US"Missing '>' after message-id";
1751     else if (domain == NULL) *error = US"domain missing in message-id";
1752   }
1753
1754 if (*error)
1755   {
1756   store_reset(reset_point);
1757   return NULL;
1758   }
1759
1760 while (*id) id++;
1761 *id++ = *str++;
1762 *id++ = 0;
1763 store_release_above(id);
1764
1765 return skip_comment(str);
1766 }
1767
1768
1769 /*************************************************
1770 *        Parse a fixed digit number              *
1771 *************************************************/
1772
1773 /* Parse a string containing an ASCII encoded fixed digits number
1774
1775 Arguments:
1776   str          pointer to the start of the ASCII encoded number
1777   n            pointer to the resulting value
1778   digits       number of required digits
1779
1780 Returns:       points after the processed date or NULL on error
1781 */
1782
1783 static const uschar *
1784 parse_number(const uschar *str, int *n, int digits)
1785 {
1786 *n=0;
1787 while (digits--)
1788   {
1789   if (*str<'0' || *str>'9') return NULL;
1790   *n=10*(*n)+(*str++-'0');
1791   }
1792 return str;
1793 }
1794
1795
1796 /*************************************************
1797 *        Parse a RFC 2822 day of week            *
1798 *************************************************/
1799
1800 /* Parse the day of the week from a RFC 2822 date, but do not
1801    decode it, because it is only for humans.
1802
1803 Arguments:
1804   str          pointer to the start of the day of the week
1805
1806 Returns:       points after the parsed day or NULL on error
1807 */
1808
1809 static const uschar *
1810 parse_day_of_week(const uschar * str)
1811 {
1812 /*
1813 day-of-week     =       ([FWS] day-name) / obs-day-of-week
1814
1815 day-name        =       "Mon" / "Tue" / "Wed" / "Thu" /
1816                         "Fri" / "Sat" / "Sun"
1817
1818 obs-day-of-week =       [CFWS] day-name [CFWS]
1819 */
1820
1821 static const uschar *day_name[7]={ US"mon", US"tue", US"wed", US"thu", US"fri", US"sat", US"sun" };
1822 int i;
1823 uschar day[4];
1824
1825 str = skip_comment(str);
1826 for (i = 0; i < 3; ++i)
1827   {
1828   if ((day[i] = tolower(*str)) == '\0') return NULL;
1829   ++str;
1830   }
1831 day[3] = '\0';
1832 for (i = 0; i<7; ++i) if (Ustrcmp(day,day_name[i]) == 0) break;
1833 if (i == 7) return NULL;
1834 return skip_comment(str);
1835 }
1836
1837
1838 /*************************************************
1839 *            Parse a RFC 2822 date               *
1840 *************************************************/
1841
1842 /* Parse the date part of a RFC 2822 date-time, extracting the
1843    day, month and year.
1844
1845 Arguments:
1846   str          pointer to the start of the date
1847   d            pointer to the resulting day
1848   m            pointer to the resulting month
1849   y            pointer to the resulting year
1850
1851 Returns:       points after the processed date or NULL on error
1852 */
1853
1854 static const uschar *
1855 parse_date(const uschar *str, int *d, int *m, int *y)
1856 {
1857 /*
1858 date            =       day month year
1859
1860 year            =       4*DIGIT / obs-year
1861
1862 obs-year        =       [CFWS] 2*DIGIT [CFWS]
1863
1864 month           =       (FWS month-name FWS) / obs-month
1865
1866 month-name      =       "Jan" / "Feb" / "Mar" / "Apr" /
1867                         "May" / "Jun" / "Jul" / "Aug" /
1868                         "Sep" / "Oct" / "Nov" / "Dec"
1869
1870 obs-month       =       CFWS month-name CFWS
1871
1872 day             =       ([FWS] 1*2DIGIT) / obs-day
1873
1874 obs-day         =       [CFWS] 1*2DIGIT [CFWS]
1875 */
1876
1877 const uschar * s, * n;
1878 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" };
1879 int i;
1880 uschar month[4];
1881
1882 str = skip_comment(str);
1883 if ((str = parse_number(str,d,1)) == NULL) return NULL;
1884
1885 if (*str>='0' && *str<='9') *d = 10*(*d)+(*str++-'0');
1886 s = skip_comment(str);
1887 if (s == str) return NULL;
1888 str = s;
1889
1890 for (i = 0; i<3; ++i) if ((month[i]=tolower(*(str+i))) == '\0') return NULL;
1891 month[3] = '\0';
1892 for (i = 0; i<12; ++i) if (Ustrcmp(month,month_name[i]) == 0) break;
1893 if (i == 12) return NULL;
1894 str+=3;
1895 *m = i;
1896 s = skip_comment(str);
1897 if (s == str) return NULL;
1898 str=s;
1899
1900 if ((n = parse_number(str,y,4)))
1901   {
1902   str = n;
1903   if (*y<1900) return NULL;
1904   *y = *y-1900;
1905   }
1906 else if ((n = parse_number(str,y,2)))
1907   {
1908   str = skip_comment(n);
1909   while (*(str-1) == ' ' || *(str-1) == '\t') --str; /* match last FWS later */
1910   if (*y<50) *y+=100;
1911   }
1912 else return NULL;
1913 return str;
1914 }
1915
1916
1917 /*************************************************
1918 *            Parse a RFC 2822 Time               *
1919 *************************************************/
1920
1921 /* Parse the time part of a RFC 2822 date-time, extracting the
1922    hour, minute, second and timezone.
1923
1924 Arguments:
1925   str          pointer to the start of the time
1926   h            pointer to the resulting hour
1927   m            pointer to the resulting minute
1928   s            pointer to the resulting second
1929   z            pointer to the resulting timezone (offset in seconds)
1930
1931 Returns:       points after the processed time or NULL on error
1932 */
1933
1934 static const uschar *
1935 parse_time(const uschar *str, int *h, int *m, int *s, int *z)
1936 {
1937 /*
1938 time            =       time-of-day FWS zone
1939
1940 time-of-day     =       hour ":" minute [ ":" second ]
1941
1942 hour            =       2DIGIT / obs-hour
1943
1944 obs-hour        =       [CFWS] 2DIGIT [CFWS]
1945
1946 minute          =       2DIGIT / obs-minute
1947
1948 obs-minute      =       [CFWS] 2DIGIT [CFWS]
1949
1950 second          =       2DIGIT / obs-second
1951
1952 obs-second      =       [CFWS] 2DIGIT [CFWS]
1953
1954 zone            =       (( "+" / "-" ) 4DIGIT) / obs-zone
1955
1956 obs-zone        =       "UT" / "GMT" /          ; Universal Time
1957                                                 ; North American UT
1958                                                 ; offsets
1959                         "EST" / "EDT" /         ; Eastern:  - 5/ - 4
1960                         "CST" / "CDT" /         ; Central:  - 6/ - 5
1961                         "MST" / "MDT" /         ; Mountain: - 7/ - 6
1962                         "PST" / "PDT" /         ; Pacific:  - 8/ - 7
1963
1964                         %d65-73 /               ; Military zones - "A"
1965                         %d75-90 /               ; through "I" and "K"
1966                         %d97-105 /              ; through "Z", both
1967                         %d107-122               ; upper and lower case
1968 */
1969
1970 const uschar * c;
1971
1972 str = skip_comment(str);
1973 if ((str = parse_number(str,h,2)) == NULL) return NULL;
1974 str = skip_comment(str);
1975 if (*str!=':') return NULL;
1976 ++str;
1977 str = skip_comment(str);
1978 if ((str = parse_number(str,m,2)) == NULL) return NULL;
1979 c = skip_comment(str);
1980 if (*str == ':')
1981   {
1982   ++str;
1983   str = skip_comment(str);
1984   if ((str = parse_number(str,s,2)) == NULL) return NULL;
1985   c = skip_comment(str);
1986   }
1987 if (c == str) return NULL;
1988 else str=c;
1989 if (*str == '+' || *str == '-')
1990   {
1991   int neg;
1992
1993   neg = (*str == '-');
1994   ++str;
1995   if ((str = parse_number(str,z,4)) == NULL) return NULL;
1996   *z = (*z/100)*3600+(*z%100)*60;
1997   if (neg) *z = -*z;
1998   }
1999 else
2000   {
2001   char zone[5];
2002   struct { const char *name; int off; } zone_name[10] =
2003   { {"gmt",0}, {"ut",0}, {"est",-5}, {"edt",-4}, {"cst",-6}, {"cdt",-5}, {"mst",-7}, {"mdt",-6}, {"pst",-8}, {"pdt",-7}};
2004   int i,j;
2005
2006   for (i = 0; i<4; ++i)
2007     {
2008     zone[i] = tolower(*(str+i));
2009     if (zone[i]<'a' || zone[i]>'z') break;
2010     }
2011   zone[i] = '\0';
2012   for (j = 0; j<10 && strcmp(zone,zone_name[j].name); ++j);
2013   /* Besides zones named in the grammar, RFC 2822 says other alphabetic */
2014   /* time zones should be treated as unknown offsets. */
2015   if (j<10)
2016     {
2017     *z = zone_name[j].off*3600;
2018     str+=i;
2019     }
2020   else if (zone[0]<'a' || zone[1]>'z') return 0;
2021   else
2022     {
2023     while ((*str>='a' && *str<='z') || (*str>='A' && *str<='Z')) ++str;
2024     *z = 0;
2025     }
2026   }
2027 return str;
2028 }
2029
2030
2031 /*************************************************
2032 *          Parse a RFC 2822 date-time            *
2033 *************************************************/
2034
2035 /* Parse a RFC 2822 date-time and return it in seconds since the epoch.
2036
2037 Arguments:
2038   str          pointer to the start of the date-time
2039   t            pointer to the parsed time
2040
2041 Returns:       points after the processed date-time or NULL on error
2042 */
2043
2044 const uschar *
2045 parse_date_time(const uschar *str, time_t *t)
2046 {
2047 /*
2048 date-time       =       [ day-of-week "," ] date FWS time [CFWS]
2049 */
2050
2051 struct tm tm;
2052 int zone;
2053 extern char **environ;
2054 char **old_environ;
2055 static char gmt0[]="TZ=GMT0";
2056 static char *gmt_env[]={ gmt0, (char*)0 };
2057 const uschar * try;
2058
2059 if ((try = parse_day_of_week(str)))
2060   {
2061   str = try;
2062   if (*str!=',') return 0;
2063   ++str;
2064   }
2065 if ((str = parse_date(str,&tm.tm_mday,&tm.tm_mon,&tm.tm_year)) == NULL) return NULL;
2066 if (*str!=' ' && *str!='\t') return NULL;
2067 while (*str == ' ' || *str == '\t') ++str;
2068 if ((str = parse_time(str,&tm.tm_hour,&tm.tm_min,&tm.tm_sec,&zone)) == NULL) return NULL;
2069 tm.tm_isdst = 0;
2070 old_environ = environ;
2071 environ = gmt_env;
2072 *t = mktime(&tm);
2073 environ = old_environ;
2074 if (*t == -1) return NULL;
2075 *t-=zone;
2076 return skip_comment(str);
2077 }
2078
2079
2080
2081
2082 /*************************************************
2083 **************************************************
2084 *             Stand-alone test program           *
2085 **************************************************
2086 *************************************************/
2087
2088 #if defined STAND_ALONE
2089 int main(void)
2090 {
2091 int start, end, domain;
2092 uschar buffer[1024];
2093
2094 store_init();
2095 big_buffer = store_malloc(big_buffer_size);
2096
2097 /* strip_trailing_dot = TRUE; */
2098 allow_domain_literals = TRUE;
2099
2100 printf("Testing parse_fix_phrase\n");
2101
2102 while (Ufgets(buffer, sizeof(buffer), stdin) != NULL)
2103   {
2104   buffer[Ustrlen(buffer)-1] = 0;
2105   if (buffer[0] == 0) break;
2106   printf("%s\n", CS parse_fix_phrase(buffer, Ustrlen(buffer)));
2107   }
2108
2109 printf("Testing parse_extract_address without group syntax and without UTF-8\n");
2110
2111 while (Ufgets(buffer, sizeof(buffer), stdin) != NULL)
2112   {
2113   uschar *out;
2114   uschar *errmess;
2115   buffer[Ustrlen(buffer) - 1] = 0;
2116   if (buffer[0] == 0) break;
2117   out = parse_extract_address(buffer, &errmess, &start, &end, &domain, FALSE);
2118   if (!out)
2119     printf("*** bad address: %s\n", errmess);
2120   else
2121     {
2122     uschar extract[1024];
2123     Ustrncpy(extract, buffer+start, end-start);
2124     extract[end-start] = 0;
2125     printf("%s %d %d %d \"%s\"\n", out, start, end, domain, extract);
2126     }
2127   }
2128
2129 printf("Testing parse_extract_address without group syntax but with UTF-8\n");
2130
2131 allow_utf8_domains = TRUE;
2132 while (Ufgets(buffer, sizeof(buffer), stdin) != NULL)
2133   {
2134   uschar *out;
2135   uschar *errmess;
2136   buffer[Ustrlen(buffer) - 1] = 0;
2137   if (buffer[0] == 0) break;
2138   out = parse_extract_address(buffer, &errmess, &start, &end, &domain, FALSE);
2139   if (!out)
2140     printf("*** bad address: %s\n", errmess);
2141   else
2142     {
2143     uschar extract[1024];
2144     Ustrncpy(extract, buffer+start, end-start);
2145     extract[end-start] = 0;
2146     printf("%s %d %d %d \"%s\"\n", out, start, end, domain, extract);
2147     }
2148   }
2149 allow_utf8_domains = FALSE;
2150
2151 printf("Testing parse_extract_address with group syntax\n");
2152
2153 f.parse_allow_group = TRUE;
2154 while (Ufgets(buffer, sizeof(buffer), stdin) != NULL)
2155   {
2156   uschar *out;
2157   uschar *errmess;
2158   uschar *s;
2159   buffer[Ustrlen(buffer) - 1] = 0;
2160   if (buffer[0] == 0) break;
2161   s = buffer;
2162   while (*s)
2163     {
2164     uschar *ss = parse_find_address_end(s, FALSE);
2165     int terminator = *ss;
2166     *ss = 0;
2167     out = parse_extract_address(buffer, &errmess, &start, &end, &domain, FALSE);
2168     *ss = terminator;
2169
2170     if (!out)
2171       printf("*** bad address: %s\n", errmess);
2172     else
2173       {
2174       uschar extract[1024];
2175       Ustrncpy(extract, buffer+start, end-start);
2176       extract[end-start] = 0;
2177       printf("%s %d %d %d \"%s\"\n", out, start, end, domain, extract);
2178       }
2179
2180     s = ss + (terminator? 1:0);
2181     Uskip_whitespace(&s);
2182     }
2183   }
2184
2185 printf("Testing parse_find_at\n");
2186
2187 while (Ufgets(buffer, sizeof(buffer), stdin) != NULL)
2188   {
2189   uschar *s;
2190   buffer[Ustrlen(buffer)-1] = 0;
2191   if (buffer[0] == 0) break;
2192   s = parse_find_at(buffer);
2193   if (s == NULL) printf("no @ found\n");
2194     else printf("offset = %d\n", s - buffer);
2195   }
2196
2197 printf("Testing parse_extract_addresses\n");
2198
2199 while (Ufgets(buffer, sizeof(buffer), stdin) != NULL)
2200   {
2201   uschar *errmess;
2202   int extracted;
2203   address_item *anchor = NULL;
2204   buffer[Ustrlen(buffer) - 1] = 0;
2205   if (buffer[0] == 0) break;
2206   if ((extracted = parse_forward_list(buffer, -1, &anchor,
2207       &errmess, US"incoming.domain", NULL, NULL)) == FF_DELIVERED)
2208     {
2209     while (anchor != NULL)
2210       {
2211       address_item *addr = anchor;
2212       anchor = anchor->next;
2213       printf("%d %s\n", testflag(addr, af_pfr), addr->address);
2214       }
2215     }
2216   else printf("Failed: %d %s\n", extracted, errmess);
2217   }
2218
2219 printf("Testing parse_message_id\n");
2220
2221 while (Ufgets(buffer, sizeof(buffer), stdin) != NULL)
2222   {
2223   uschar *s, *t, *errmess;
2224   buffer[Ustrlen(buffer) - 1] = 0;
2225   if (buffer[0] == 0) break;
2226   s = buffer;
2227   while (*s != 0)
2228     {
2229     s = parse_message_id(s, &t, &errmess);
2230     if (errmess != NULL)
2231       {
2232       printf("Failed: %s\n", errmess);
2233       break;
2234       }
2235     printf("%s\n", t);
2236     }
2237   }
2238
2239 return 0;
2240 }
2241
2242 #endif
2243
2244 /* End of parse.c */