Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / sendmail / src / headers.c
1 /*
2  * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5  * Copyright (c) 1988, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENSE file which can be found at the top level of
10  * the sendmail distribution.
11  *
12  * $FreeBSD: src/contrib/sendmail/src/headers.c,v 1.4.2.10 2003/03/29 19:33:17 gshapiro Exp $
13  * $DragonFly: src/contrib/sendmail/src/Attic/headers.c,v 1.2 2003/06/17 04:24:06 dillon Exp $
14  *
15  */
16
17 #include <sendmail.h>
18
19 SM_RCSID("@(#)$Id: headers.c,v 8.266.4.5 2003/03/12 22:42:52 gshapiro Exp $")
20
21 static size_t   fix_mime_header __P((HDR *, ENVELOPE *));
22 static int      priencode __P((char *));
23 static void     put_vanilla_header __P((HDR *, char *, MCI *));
24
25 /*
26 **  SETUPHEADERS -- initialize headers in symbol table
27 **
28 **      Parameters:
29 **              none
30 **
31 **      Returns:
32 **              none
33 */
34
35 void
36 setupheaders()
37 {
38         struct hdrinfo *hi;
39         STAB *s;
40
41         for (hi = HdrInfo; hi->hi_field != NULL; hi++)
42         {
43                 s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
44                 s->s_header.hi_flags = hi->hi_flags;
45                 s->s_header.hi_ruleset = NULL;
46         }
47 }
48 /*
49 **  CHOMPHEADER -- process and save a header line.
50 **
51 **      Called by collect, readcf, and readqf to deal with header lines.
52 **
53 **      Parameters:
54 **              line -- header as a text line.
55 **              pflag -- flags for chompheader() (from sendmail.h)
56 **              hdrp -- a pointer to the place to save the header.
57 **              e -- the envelope including this header.
58 **
59 **      Returns:
60 **              flags for this header.
61 **
62 **      Side Effects:
63 **              The header is saved on the header list.
64 **              Contents of 'line' are destroyed.
65 */
66
67 static struct hdrinfo   NormalHeader =  { NULL, 0, NULL };
68
69 unsigned long
70 chompheader(line, pflag, hdrp, e)
71         char *line;
72         int pflag;
73         HDR **hdrp;
74         register ENVELOPE *e;
75 {
76         unsigned char mid = '\0';
77         register char *p;
78         register HDR *h;
79         HDR **hp;
80         char *fname;
81         char *fvalue;
82         bool cond = false;
83         bool dropfrom;
84         bool headeronly;
85         STAB *s;
86         struct hdrinfo *hi;
87         bool nullheader = false;
88         BITMAP256 mopts;
89
90         if (tTd(31, 6))
91         {
92                 sm_dprintf("chompheader: ");
93                 xputs(line);
94                 sm_dprintf("\n");
95         }
96
97         headeronly = hdrp != NULL;
98         if (!headeronly)
99                 hdrp = &e->e_header;
100
101         /* strip off options */
102         clrbitmap(mopts);
103         p = line;
104         if (!bitset(pflag, CHHDR_USER) && *p == '?')
105         {
106                 int c;
107                 register char *q;
108
109                 q = strchr(++p, '?');
110                 if (q == NULL)
111                         goto hse;
112
113                 *q = '\0';
114                 c = *p & 0377;
115
116                 /* possibly macro conditional */
117                 if (c == MACROEXPAND)
118                 {
119                         /* catch ?$? */
120                         if (*++p == '\0')
121                         {
122                                 *q = '?';
123                                 goto hse;
124                         }
125
126                         mid = (unsigned char) *p++;
127
128                         /* catch ?$abc? */
129                         if (*p != '\0')
130                         {
131                                 *q = '?';
132                                 goto hse;
133                         }
134                 }
135                 else if (*p == '$')
136                 {
137                         /* catch ?$? */
138                         if (*++p == '\0')
139                         {
140                                 *q = '?';
141                                 goto hse;
142                         }
143
144                         mid = (unsigned char) macid(p);
145                         if (bitset(0200, mid))
146                                 p += strlen(macname(mid)) + 2;
147                         else
148                                 p++;
149
150                         /* catch ?$abc? */
151                         if (*p != '\0')
152                         {
153                                 *q = '?';
154                                 goto hse;
155                         }
156                 }
157                 else
158                 {
159                         while (*p != '\0')
160                         {
161                                 if (!isascii(*p))
162                                 {
163                                         *q = '?';
164                                         goto hse;
165                                 }
166
167                                 setbitn(bitidx(*p), mopts);
168                                 cond = true;
169                                 p++;
170                         }
171                 }
172                 p = q + 1;
173         }
174
175         /* find canonical name */
176         fname = p;
177         while (isascii(*p) && isgraph(*p) && *p != ':')
178                 p++;
179         fvalue = p;
180         while (isascii(*p) && isspace(*p))
181                 p++;
182         if (*p++ != ':' || fname == fvalue)
183         {
184 hse:
185                 syserr("553 5.3.0 header syntax error, line \"%s\"", line);
186                 return 0;
187         }
188         *fvalue = '\0';
189
190         /* strip field value on front */
191         if (*p == ' ')
192                 p++;
193         fvalue = p;
194
195         /* if the field is null, go ahead and use the default */
196         while (isascii(*p) && isspace(*p))
197                 p++;
198         if (*p == '\0')
199                 nullheader = true;
200
201         /* security scan: long field names are end-of-header */
202         if (strlen(fname) > 100)
203                 return H_EOH;
204
205         /* check to see if it represents a ruleset call */
206         if (bitset(pflag, CHHDR_DEF))
207         {
208                 char hbuf[50];
209
210                 (void) expand(fvalue, hbuf, sizeof hbuf, e);
211                 for (p = hbuf; isascii(*p) && isspace(*p); )
212                         p++;
213                 if ((*p++ & 0377) == CALLSUBR)
214                 {
215                         auto char *endp;
216                         bool strc;
217
218                         strc = *p == '+';       /* strip comments? */
219                         if (strc)
220                                 ++p;
221                         if (strtorwset(p, &endp, ST_ENTER) > 0)
222                         {
223                                 *endp = '\0';
224                                 s = stab(fname, ST_HEADER, ST_ENTER);
225                                 if (LogLevel > 9 &&
226                                     s->s_header.hi_ruleset != NULL)
227                                         sm_syslog(LOG_WARNING, NOQID,
228                                                   "Warning: redefined ruleset for header=%s, old=%s, new=%s",
229                                                   fname,
230                                                   s->s_header.hi_ruleset, p);
231                                 s->s_header.hi_ruleset = newstr(p);
232                                 if (!strc)
233                                         s->s_header.hi_flags |= H_STRIPCOMM;
234                         }
235                         return 0;
236                 }
237         }
238
239         /* see if it is a known type */
240         s = stab(fname, ST_HEADER, ST_FIND);
241         if (s != NULL)
242                 hi = &s->s_header;
243         else
244                 hi = &NormalHeader;
245
246         if (tTd(31, 9))
247         {
248                 if (s == NULL)
249                         sm_dprintf("no header flags match\n");
250                 else
251                         sm_dprintf("header match, flags=%lx, ruleset=%s\n",
252                                    hi->hi_flags,
253                                    hi->hi_ruleset == NULL ? "<NULL>"
254                                                           : hi->hi_ruleset);
255         }
256
257         /* see if this is a resent message */
258         if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
259             bitset(H_RESENT, hi->hi_flags))
260                 e->e_flags |= EF_RESENT;
261
262         /* if this is an Errors-To: header keep track of it now */
263         if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
264             bitset(H_ERRORSTO, hi->hi_flags))
265                 (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
266
267         /* if this means "end of header" quit now */
268         if (!headeronly && bitset(H_EOH, hi->hi_flags))
269                 return hi->hi_flags;
270
271         /*
272         **  Horrible hack to work around problem with Lotus Notes SMTP
273         **  mail gateway, which generates From: headers with newlines in
274         **  them and the <address> on the second line.  Although this is
275         **  legal RFC 822, many MUAs don't handle this properly and thus
276         **  never find the actual address.
277         */
278
279         if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
280         {
281                 while ((p = strchr(fvalue, '\n')) != NULL)
282                         *p = ' ';
283         }
284
285         /*
286         **  If there is a check ruleset, verify it against the header.
287         */
288
289         if (bitset(pflag, CHHDR_CHECK))
290         {
291                 int rscheckflags;
292                 char *rs;
293
294                 /* no ruleset? look for default */
295                 rs = hi->hi_ruleset;
296                 rscheckflags = RSF_COUNT;
297                 if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
298                         rscheckflags |= RSF_UNSTRUCTURED;
299                 if (rs == NULL)
300                 {
301                         s = stab("*", ST_HEADER, ST_FIND);
302                         if (s != NULL)
303                         {
304                                 rs = (&s->s_header)->hi_ruleset;
305                                 if (bitset((&s->s_header)->hi_flags,
306                                            H_STRIPCOMM))
307                                         rscheckflags |= RSF_RMCOMM;
308                         }
309                 }
310                 else if (bitset(hi->hi_flags, H_STRIPCOMM))
311                         rscheckflags |= RSF_RMCOMM;
312                 if (rs != NULL)
313                 {
314                         int l, k;
315                         char qval[MAXNAME];
316
317                         l = 0;
318                         qval[l++] = '"';
319
320                         /* - 3 to avoid problems with " at the end */
321                         for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++)
322                         {
323                                 switch (fvalue[k])
324                                 {
325                                   /* XXX other control chars? */
326                                   case '\011': /* ht */
327                                   case '\012': /* nl */
328                                   case '\013': /* vt */
329                                   case '\014': /* np */
330                                   case '\015': /* cr */
331                                         qval[l++] = ' ';
332                                         break;
333                                   case '"':
334                                         qval[l++] = '\\';
335                                         /* FALLTHROUGH */
336                                   default:
337                                         qval[l++] = fvalue[k];
338                                         break;
339                                 }
340                         }
341                         qval[l++] = '"';
342                         qval[l] = '\0';
343                         k += strlen(fvalue + k);
344                         if (k >= MAXNAME)
345                         {
346                                 if (LogLevel > 9)
347                                         sm_syslog(LOG_WARNING, e->e_id,
348                                                   "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
349                                                   fname, rs, k, MAXNAME - 1);
350                         }
351                         macdefine(&e->e_macro, A_TEMP,
352                                 macid("{currHeader}"), qval);
353                         macdefine(&e->e_macro, A_TEMP,
354                                 macid("{hdr_name}"), fname);
355
356                         (void) sm_snprintf(qval, sizeof qval, "%d", k);
357                         macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
358 #if _FFR_HDR_TYPE
359                         /*
360                         **  XXX: h isn't set yet
361                         **  If we really want to be precise then we have
362                         **  to lookup the header (see below).
363                         **  It's probably not worth the effort.
364                         */
365
366                         if (bitset(H_FROM, h->h_flags))
367                                 macdefine(&e->e_macro, A_PERM,
368                                         macid("{addr_type}"), "h s");
369                         else if (bitset(H_RCPT, h->h_flags))
370                                 macdefine(&e->e_macro, A_PERM,
371                                         macid("{addr_type}"), "h r");
372                         else
373 #endif /* _FFR_HDR_TYPE */
374                                 macdefine(&e->e_macro, A_PERM,
375                                         macid("{addr_type}"), "h");
376                         (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
377                                        NULL, e->e_id);
378                 }
379         }
380
381         /*
382         **  Drop explicit From: if same as what we would generate.
383         **  This is to make MH (which doesn't always give a full name)
384         **  insert the full name information in all circumstances.
385         */
386
387         dropfrom = false;
388         p = "resent-from";
389         if (!bitset(EF_RESENT, e->e_flags))
390                 p += 7;
391         if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
392             !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0)
393         {
394                 if (tTd(31, 2))
395                 {
396                         sm_dprintf("comparing header from (%s) against default (%s or %s)\n",
397                                 fvalue, e->e_from.q_paddr, e->e_from.q_user);
398                 }
399                 if (e->e_from.q_paddr != NULL &&
400                     e->e_from.q_mailer != NULL &&
401                     bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
402                     (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
403                      strcmp(fvalue, e->e_from.q_user) == 0))
404                         dropfrom = true;
405         }
406
407         /* delete default value for this header */
408         for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
409         {
410                 if (sm_strcasecmp(fname, h->h_field) == 0 &&
411                     !bitset(H_USER, h->h_flags) &&
412                     !bitset(H_FORCE, h->h_flags))
413                 {
414                         if (nullheader)
415                         {
416                                 /* user-supplied value was null */
417                                 return 0;
418                         }
419                         if (dropfrom)
420                         {
421                                 /* make this look like the user entered it */
422                                 h->h_flags |= H_USER;
423                                 return hi->hi_flags;
424                         }
425                         h->h_value = NULL;
426                         if (!cond)
427                         {
428                                 /* copy conditions from default case */
429                                 memmove((char *) mopts, (char *) h->h_mflags,
430                                         sizeof mopts);
431                         }
432                         h->h_macro = mid;
433                 }
434         }
435
436         /* create a new node */
437         h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h);
438         h->h_field = sm_rpool_strdup_x(e->e_rpool, fname);
439         h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue);
440         h->h_link = NULL;
441         memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts);
442         h->h_macro = mid;
443         *hp = h;
444         h->h_flags = hi->hi_flags;
445         if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
446                 h->h_flags |= H_USER;
447
448         /* strip EOH flag if parsing MIME headers */
449         if (headeronly)
450                 h->h_flags &= ~H_EOH;
451         if (bitset(pflag, CHHDR_DEF))
452                 h->h_flags |= H_DEFAULT;
453         if (cond || mid != '\0')
454                 h->h_flags |= H_CHECK;
455
456         /* hack to see if this is a new format message */
457         if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
458             bitset(H_RCPT|H_FROM, h->h_flags) &&
459             (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
460              strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
461         {
462                 e->e_flags &= ~EF_OLDSTYLE;
463         }
464
465         return h->h_flags;
466 }
467 /*
468 **  ADDHEADER -- add a header entry to the end of the queue.
469 **
470 **      This bypasses the special checking of chompheader.
471 **
472 **      Parameters:
473 **              field -- the name of the header field.
474 **              value -- the value of the field.
475 **              flags -- flags to add to h_flags.
476 **              e -- envelope.
477 **
478 **      Returns:
479 **              none.
480 **
481 **      Side Effects:
482 **              adds the field on the list of headers for this envelope.
483 */
484
485 void
486 addheader(field, value, flags, e)
487         char *field;
488         char *value;
489         int flags;
490         ENVELOPE *e;
491 {
492         register HDR *h;
493         STAB *s;
494         HDR **hp;
495         HDR **hdrlist = &e->e_header;
496
497         /* find info struct */
498         s = stab(field, ST_HEADER, ST_FIND);
499
500         /* find current place in list -- keep back pointer? */
501         for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
502         {
503                 if (sm_strcasecmp(field, h->h_field) == 0)
504                         break;
505         }
506
507         /* allocate space for new header */
508         h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h);
509         h->h_field = field;
510         h->h_value = sm_rpool_strdup_x(e->e_rpool, value);
511         h->h_link = *hp;
512         h->h_flags = flags;
513         if (s != NULL)
514                 h->h_flags |= s->s_header.hi_flags;
515         clrbitmap(h->h_mflags);
516         h->h_macro = '\0';
517         *hp = h;
518 }
519 /*
520 **  HVALUE -- return value of a header.
521 **
522 **      Only "real" fields (i.e., ones that have not been supplied
523 **      as a default) are used.
524 **
525 **      Parameters:
526 **              field -- the field name.
527 **              header -- the header list.
528 **
529 **      Returns:
530 **              pointer to the value part.
531 **              NULL if not found.
532 **
533 **      Side Effects:
534 **              none.
535 */
536
537 char *
538 hvalue(field, header)
539         char *field;
540         HDR *header;
541 {
542         register HDR *h;
543
544         for (h = header; h != NULL; h = h->h_link)
545         {
546                 if (!bitset(H_DEFAULT, h->h_flags) &&
547                     sm_strcasecmp(h->h_field, field) == 0)
548                         return h->h_value;
549         }
550         return NULL;
551 }
552 /*
553 **  ISHEADER -- predicate telling if argument is a header.
554 **
555 **      A line is a header if it has a single word followed by
556 **      optional white space followed by a colon.
557 **
558 **      Header fields beginning with two dashes, although technically
559 **      permitted by RFC822, are automatically rejected in order
560 **      to make MIME work out.  Without this we could have a technically
561 **      legal header such as ``--"foo:bar"'' that would also be a legal
562 **      MIME separator.
563 **
564 **      Parameters:
565 **              h -- string to check for possible headerness.
566 **
567 **      Returns:
568 **              true if h is a header.
569 **              false otherwise.
570 **
571 **      Side Effects:
572 **              none.
573 */
574
575 bool
576 isheader(h)
577         char *h;
578 {
579         register char *s = h;
580
581         if (s[0] == '-' && s[1] == '-')
582                 return false;
583
584         while (*s > ' ' && *s != ':' && *s != '\0')
585                 s++;
586
587         if (h == s)
588                 return false;
589
590         /* following technically violates RFC822 */
591         while (isascii(*s) && isspace(*s))
592                 s++;
593
594         return (*s == ':');
595 }
596 /*
597 **  EATHEADER -- run through the stored header and extract info.
598 **
599 **      Parameters:
600 **              e -- the envelope to process.
601 **              full -- if set, do full processing (e.g., compute
602 **                      message priority).  This should not be set
603 **                      when reading a queue file because some info
604 **                      needed to compute the priority is wrong.
605 **              log -- call logsender()?
606 **
607 **      Returns:
608 **              none.
609 **
610 **      Side Effects:
611 **              Sets a bunch of global variables from information
612 **                      in the collected header.
613 */
614
615 void
616 eatheader(e, full, log)
617         register ENVELOPE *e;
618         bool full;
619         bool log;
620 {
621         register HDR *h;
622         register char *p;
623         int hopcnt = 0;
624         char buf[MAXLINE];
625
626         /*
627         **  Set up macros for possible expansion in headers.
628         */
629
630         macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
631         macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
632         if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
633                 macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
634         else
635                 macdefine(&e->e_macro, A_PERM, 'u', NULL);
636
637         /* full name of from person */
638         p = hvalue("full-name", e->e_header);
639         if (p != NULL)
640         {
641                 if (!rfc822_string(p))
642                 {
643                         /*
644                         **  Quote a full name with special characters
645                         **  as a comment so crackaddr() doesn't destroy
646                         **  the name portion of the address.
647                         */
648
649                         p = addquotes(p, e->e_rpool);
650                 }
651                 macdefine(&e->e_macro, A_PERM, 'x', p);
652         }
653
654         if (tTd(32, 1))
655                 sm_dprintf("----- collected header -----\n");
656         e->e_msgid = NULL;
657         for (h = e->e_header; h != NULL; h = h->h_link)
658         {
659                 if (tTd(32, 1))
660                         sm_dprintf("%s: ", h->h_field);
661                 if (h->h_value == NULL)
662                 {
663                         if (tTd(32, 1))
664                                 sm_dprintf("<NULL>\n");
665                         continue;
666                 }
667
668                 /* do early binding */
669                 if (bitset(H_DEFAULT, h->h_flags) &&
670                     !bitset(H_BINDLATE, h->h_flags))
671                 {
672                         if (tTd(32, 1))
673                         {
674                                 sm_dprintf("(");
675                                 xputs(h->h_value);
676                                 sm_dprintf(") ");
677                         }
678                         expand(h->h_value, buf, sizeof buf, e);
679                         if (buf[0] != '\0')
680                         {
681                                 if (bitset(H_FROM, h->h_flags))
682                                         expand(crackaddr(buf, e),
683                                                buf, sizeof buf, e);
684                                 h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
685                                 h->h_flags &= ~H_DEFAULT;
686                         }
687                 }
688                 if (tTd(32, 1))
689                 {
690                         xputs(h->h_value);
691                         sm_dprintf("\n");
692                 }
693
694                 /* count the number of times it has been processed */
695                 if (bitset(H_TRACE, h->h_flags))
696                         hopcnt++;
697
698                 /* send to this person if we so desire */
699                 if (GrabTo && bitset(H_RCPT, h->h_flags) &&
700                     !bitset(H_DEFAULT, h->h_flags) &&
701                     (!bitset(EF_RESENT, e->e_flags) ||
702                      bitset(H_RESENT, h->h_flags)))
703                 {
704 #if 0
705                         int saveflags = e->e_flags;
706 #endif /* 0 */
707
708                         (void) sendtolist(denlstring(h->h_value, true, false),
709                                           NULLADDR, &e->e_sendqueue, 0, e);
710
711 #if 0
712                         /*
713                         **  Change functionality so a fatal error on an
714                         **  address doesn't affect the entire envelope.
715                         */
716
717                         /* delete fatal errors generated by this address */
718                         if (!bitset(EF_FATALERRS, saveflags))
719                                 e->e_flags &= ~EF_FATALERRS;
720 #endif /* 0 */
721                 }
722
723                 /* save the message-id for logging */
724                 p = "resent-message-id";
725                 if (!bitset(EF_RESENT, e->e_flags))
726                         p += 7;
727                 if (sm_strcasecmp(h->h_field, p) == 0)
728                 {
729                         e->e_msgid = h->h_value;
730                         while (isascii(*e->e_msgid) && isspace(*e->e_msgid))
731                                 e->e_msgid++;
732                 }
733         }
734         if (tTd(32, 1))
735                 sm_dprintf("----------------------------\n");
736
737         /* if we are just verifying (that is, sendmail -t -bv), drop out now */
738         if (OpMode == MD_VERIFY)
739                 return;
740
741         /* store hop count */
742         if (hopcnt > e->e_hopcount)
743         {
744                 e->e_hopcount = hopcnt;
745                 (void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount);
746                 macdefine(&e->e_macro, A_TEMP, 'c', buf);
747         }
748
749         /* message priority */
750         p = hvalue("precedence", e->e_header);
751         if (p != NULL)
752                 e->e_class = priencode(p);
753         if (e->e_class < 0)
754                 e->e_timeoutclass = TOC_NONURGENT;
755         else if (e->e_class > 0)
756                 e->e_timeoutclass = TOC_URGENT;
757         if (full)
758         {
759                 e->e_msgpriority = e->e_msgsize
760                                  - e->e_class * WkClassFact
761                                  + e->e_nrcpts * WkRecipFact;
762         }
763
764         /* message timeout priority */
765         p = hvalue("priority", e->e_header);
766         if (p != NULL)
767         {
768                 /* (this should be in the configuration file) */
769                 if (sm_strcasecmp(p, "urgent") == 0)
770                         e->e_timeoutclass = TOC_URGENT;
771                 else if (sm_strcasecmp(p, "normal") == 0)
772                         e->e_timeoutclass = TOC_NORMAL;
773                 else if (sm_strcasecmp(p, "non-urgent") == 0)
774                         e->e_timeoutclass = TOC_NONURGENT;
775         }
776
777 #if _FFR_QUEUERETURN_DSN
778         /* If no timeoutclass picked and it's a DSN, use that timeoutclass */
779         if (e->e_timeoutclass == TOC_NORMAL && bitset(EF_RESPONSE, e->e_flags))
780                 e->e_timeoutclass = TOC_DSN;
781 #endif /* _FFR_QUEUERETURN_DSN */
782
783         /* date message originated */
784         p = hvalue("posted-date", e->e_header);
785         if (p == NULL)
786                 p = hvalue("date", e->e_header);
787         if (p != NULL)
788                 macdefine(&e->e_macro, A_PERM, 'a', p);
789
790         /* check to see if this is a MIME message */
791         if ((e->e_bodytype != NULL &&
792              sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
793             hvalue("MIME-Version", e->e_header) != NULL)
794         {
795                 e->e_flags |= EF_IS_MIME;
796                 if (HasEightBits)
797                         e->e_bodytype = "8BITMIME";
798         }
799         else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
800         {
801                 /* this may be an RFC 1049 message */
802                 p = strpbrk(p, ";/");
803                 if (p == NULL || *p == ';')
804                 {
805                         /* yep, it is */
806                         e->e_flags |= EF_DONT_MIME;
807                 }
808         }
809
810         /*
811         **  From person in antiquated ARPANET mode
812         **      required by UK Grey Book e-mail gateways (sigh)
813         */
814
815         if (OpMode == MD_ARPAFTP)
816         {
817                 register struct hdrinfo *hi;
818
819                 for (hi = HdrInfo; hi->hi_field != NULL; hi++)
820                 {
821                         if (bitset(H_FROM, hi->hi_flags) &&
822                             (!bitset(H_RESENT, hi->hi_flags) ||
823                              bitset(EF_RESENT, e->e_flags)) &&
824                             (p = hvalue(hi->hi_field, e->e_header)) != NULL)
825                                 break;
826                 }
827                 if (hi->hi_field != NULL)
828                 {
829                         if (tTd(32, 2))
830                                 sm_dprintf("eatheader: setsender(*%s == %s)\n",
831                                         hi->hi_field, p);
832                         setsender(p, e, NULL, '\0', true);
833                 }
834         }
835
836         /*
837         **  Log collection information.
838         */
839
840         if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
841         {
842                 logsender(e, e->e_msgid);
843                 e->e_flags &= ~EF_LOGSENDER;
844         }
845 }
846 /*
847 **  LOGSENDER -- log sender information
848 **
849 **      Parameters:
850 **              e -- the envelope to log
851 **              msgid -- the message id
852 **
853 **      Returns:
854 **              none
855 */
856
857 void
858 logsender(e, msgid)
859         register ENVELOPE *e;
860         char *msgid;
861 {
862         char *name;
863         register char *sbp;
864         register char *p;
865         int l;
866         char hbuf[MAXNAME + 1];
867         char sbuf[MAXLINE + 1];
868         char mbuf[MAXNAME + 1];
869
870         /* don't allow newlines in the message-id */
871         /* XXX do we still need this? sm_syslog() replaces control chars */
872         if (msgid != NULL)
873         {
874                 l = strlen(msgid);
875                 if (l > sizeof mbuf - 1)
876                         l = sizeof mbuf - 1;
877                 memmove(mbuf, msgid, l);
878                 mbuf[l] = '\0';
879                 p = mbuf;
880                 while ((p = strchr(p, '\n')) != NULL)
881                         *p++ = ' ';
882         }
883
884         if (bitset(EF_RESPONSE, e->e_flags))
885                 name = "[RESPONSE]";
886         else if ((name = macvalue('_', e)) != NULL)
887                 /* EMPTY */
888                 ;
889         else if (RealHostName == NULL)
890                 name = "localhost";
891         else if (RealHostName[0] == '[')
892                 name = RealHostName;
893         else
894         {
895                 name = hbuf;
896                 (void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
897                 if (RealHostAddr.sa.sa_family != 0)
898                 {
899                         p = &hbuf[strlen(hbuf)];
900                         (void) sm_snprintf(p, SPACELEFT(hbuf, p),
901                                            " (%.100s)",
902                                            anynet_ntoa(&RealHostAddr));
903                 }
904         }
905
906         /* some versions of syslog only take 5 printf args */
907 #if (SYSLOG_BUFSIZE) >= 256
908         sbp = sbuf;
909         (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
910                 "from=%.200s, size=%ld, class=%d, nrcpts=%d",
911                 e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
912                 e->e_msgsize, e->e_class, e->e_nrcpts);
913         sbp += strlen(sbp);
914         if (msgid != NULL)
915         {
916                 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
917                                 ", msgid=%.100s", mbuf);
918                 sbp += strlen(sbp);
919         }
920         if (e->e_bodytype != NULL)
921         {
922                 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
923                                 ", bodytype=%.20s", e->e_bodytype);
924                 sbp += strlen(sbp);
925         }
926         p = macvalue('r', e);
927         if (p != NULL)
928         {
929                 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
930                                 ", proto=%.20s", p);
931                 sbp += strlen(sbp);
932         }
933         p = macvalue(macid("{daemon_name}"), e);
934         if (p != NULL)
935         {
936                 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
937                                 ", daemon=%.20s", p);
938                 sbp += strlen(sbp);
939         }
940         sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
941
942 #else /* (SYSLOG_BUFSIZE) >= 256 */
943
944         sm_syslog(LOG_INFO, e->e_id,
945                   "from=%s",
946                   e->e_from.q_paddr == NULL ? "<NONE>"
947                                             : shortenstring(e->e_from.q_paddr,
948                                                             83));
949         sm_syslog(LOG_INFO, e->e_id,
950                   "size=%ld, class=%ld, nrcpts=%d",
951                   e->e_msgsize, e->e_class, e->e_nrcpts);
952         if (msgid != NULL)
953                 sm_syslog(LOG_INFO, e->e_id,
954                           "msgid=%s",
955                           shortenstring(mbuf, 83));
956         sbp = sbuf;
957         *sbp = '\0';
958         if (e->e_bodytype != NULL)
959         {
960                 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
961                                 "bodytype=%.20s, ", e->e_bodytype);
962                 sbp += strlen(sbp);
963         }
964         p = macvalue('r', e);
965         if (p != NULL)
966         {
967                 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
968                                 "proto=%.20s, ", p);
969                 sbp += strlen(sbp);
970         }
971         sm_syslog(LOG_INFO, e->e_id,
972                   "%.400srelay=%s", sbuf, name);
973 #endif /* (SYSLOG_BUFSIZE) >= 256 */
974 }
975 /*
976 **  PRIENCODE -- encode external priority names into internal values.
977 **
978 **      Parameters:
979 **              p -- priority in ascii.
980 **
981 **      Returns:
982 **              priority as a numeric level.
983 **
984 **      Side Effects:
985 **              none.
986 */
987
988 static int
989 priencode(p)
990         char *p;
991 {
992         register int i;
993
994         for (i = 0; i < NumPriorities; i++)
995         {
996                 if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
997                         return Priorities[i].pri_val;
998         }
999
1000         /* unknown priority */
1001         return 0;
1002 }
1003 /*
1004 **  CRACKADDR -- parse an address and turn it into a macro
1005 **
1006 **      This doesn't actually parse the address -- it just extracts
1007 **      it and replaces it with "$g".  The parse is totally ad hoc
1008 **      and isn't even guaranteed to leave something syntactically
1009 **      identical to what it started with.  However, it does leave
1010 **      something semantically identical if possible, else at least
1011 **      syntactically correct.
1012 **
1013 **      For example, it changes "Real Name <real@example.com> (Comment)"
1014 **      to "Real Name <$g> (Comment)".
1015 **
1016 **      This algorithm has been cleaned up to handle a wider range
1017 **      of cases -- notably quoted and backslash escaped strings.
1018 **      This modification makes it substantially better at preserving
1019 **      the original syntax.
1020 **
1021 **      Parameters:
1022 **              addr -- the address to be cracked.
1023 **              e -- the current envelope.
1024 **
1025 **      Returns:
1026 **              a pointer to the new version.
1027 **
1028 **      Side Effects:
1029 **              none.
1030 **
1031 **      Warning:
1032 **              The return value is saved in local storage and should
1033 **              be copied if it is to be reused.
1034 */
1035
1036 #define SM_HAVE_ROOM            ((bp < buflim) && (buflim <= bufend))
1037
1038 /*
1039 **  Append a character to bp if we have room.
1040 **  If not, punt and return $g.
1041 */
1042
1043 #define SM_APPEND_CHAR(c)                                       \
1044         do                                                      \
1045         {                                                       \
1046                 if (SM_HAVE_ROOM)                               \
1047                         *bp++ = (c);                            \
1048                 else                                            \
1049                         goto returng;                           \
1050         } while (0)
1051
1052 #if MAXNAME < 10
1053 ERROR MAXNAME must be at least 10
1054 #endif /* MAXNAME < 10 */
1055
1056 char *
1057 crackaddr(addr, e)
1058         register char *addr;
1059         ENVELOPE *e;
1060 {
1061         register char *p;
1062         register char c;
1063         int cmtlev;                     /* comment level in input string */
1064         int realcmtlev;                 /* comment level in output string */
1065         int anglelev;                   /* angle level in input string */
1066         int copylev;                    /* 0 == in address, >0 copying */
1067         int bracklev;                   /* bracket level for IPv6 addr check */
1068         bool addangle;                  /* put closing angle in output */
1069         bool qmode;                     /* quoting in original string? */
1070         bool realqmode;                 /* quoting in output string? */
1071         bool putgmac = false;           /* already wrote $g */
1072         bool quoteit = false;           /* need to quote next character */
1073         bool gotangle = false;          /* found first '<' */
1074         bool gotcolon = false;          /* found a ':' */
1075         register char *bp;
1076         char *buflim;
1077         char *bufhead;
1078         char *addrhead;
1079         char *bufend;
1080         static char buf[MAXNAME + 1];
1081
1082         if (tTd(33, 1))
1083                 sm_dprintf("crackaddr(%s)\n", addr);
1084
1085         /* strip leading spaces */
1086         while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1087                 addr++;
1088
1089         /*
1090         **  Start by assuming we have no angle brackets.  This will be
1091         **  adjusted later if we find them.
1092         */
1093
1094         buflim = bufend = &buf[sizeof(buf) - 1];
1095         bp = bufhead = buf;
1096         p = addrhead = addr;
1097         copylev = anglelev = cmtlev = realcmtlev = 0;
1098         bracklev = 0;
1099         qmode = realqmode = addangle = false;
1100
1101         while ((c = *p++) != '\0')
1102         {
1103                 /*
1104                 **  Try to keep legal syntax using spare buffer space
1105                 **  (maintained by buflim).
1106                 */
1107
1108                 if (copylev > 0)
1109                         SM_APPEND_CHAR(c);
1110
1111                 /* check for backslash escapes */
1112                 if (c == '\\')
1113                 {
1114                         /* arrange to quote the address */
1115                         if (cmtlev <= 0 && !qmode)
1116                                 quoteit = true;
1117
1118                         if ((c = *p++) == '\0')
1119                         {
1120                                 /* too far */
1121                                 p--;
1122                                 goto putg;
1123                         }
1124                         if (copylev > 0)
1125                                 SM_APPEND_CHAR(c);
1126                         goto putg;
1127                 }
1128
1129                 /* check for quoted strings */
1130                 if (c == '"' && cmtlev <= 0)
1131                 {
1132                         qmode = !qmode;
1133                         if (copylev > 0 && SM_HAVE_ROOM)
1134                         {
1135                                 if (realqmode)
1136                                         buflim--;
1137                                 else
1138                                         buflim++;
1139                                 realqmode = !realqmode;
1140                         }
1141                         continue;
1142                 }
1143                 if (qmode)
1144                         goto putg;
1145
1146                 /* check for comments */
1147                 if (c == '(')
1148                 {
1149                         cmtlev++;
1150
1151                         /* allow space for closing paren */
1152                         if (SM_HAVE_ROOM)
1153                         {
1154                                 buflim--;
1155                                 realcmtlev++;
1156                                 if (copylev++ <= 0)
1157                                 {
1158                                         if (bp != bufhead)
1159                                                 SM_APPEND_CHAR(' ');
1160                                         SM_APPEND_CHAR(c);
1161                                 }
1162                         }
1163                 }
1164                 if (cmtlev > 0)
1165                 {
1166                         if (c == ')')
1167                         {
1168                                 cmtlev--;
1169                                 copylev--;
1170                                 if (SM_HAVE_ROOM)
1171                                 {
1172                                         realcmtlev--;
1173                                         buflim++;
1174                                 }
1175                         }
1176                         continue;
1177                 }
1178                 else if (c == ')')
1179                 {
1180                         /* syntax error: unmatched ) */
1181                         if (copylev > 0 && SM_HAVE_ROOM)
1182                                 bp--;
1183                 }
1184
1185                 /* count nesting on [ ... ] (for IPv6 domain literals) */
1186                 if (c == '[')
1187                         bracklev++;
1188                 else if (c == ']')
1189                         bracklev--;
1190
1191                 /* check for group: list; syntax */
1192                 if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1193                     !gotcolon && !ColonOkInAddr)
1194                 {
1195                         register char *q;
1196
1197                         /*
1198                         **  Check for DECnet phase IV ``::'' (host::user)
1199                         **  or DECnet phase V ``:.'' syntaxes.  The latter
1200                         **  covers ``user@DEC:.tay.myhost'' and
1201                         **  ``DEC:.tay.myhost::user'' syntaxes (bletch).
1202                         */
1203
1204                         if (*p == ':' || *p == '.')
1205                         {
1206                                 if (cmtlev <= 0 && !qmode)
1207                                         quoteit = true;
1208                                 if (copylev > 0)
1209                                 {
1210                                         SM_APPEND_CHAR(c);
1211                                         SM_APPEND_CHAR(*p);
1212                                 }
1213                                 p++;
1214                                 goto putg;
1215                         }
1216
1217                         gotcolon = true;
1218
1219                         bp = bufhead;
1220                         if (quoteit)
1221                         {
1222                                 SM_APPEND_CHAR('"');
1223
1224                                 /* back up over the ':' and any spaces */
1225                                 --p;
1226                                 while (p > addr &&
1227                                        isascii(*--p) && isspace(*p))
1228                                         continue;
1229                                 p++;
1230                         }
1231                         for (q = addrhead; q < p; )
1232                         {
1233                                 c = *q++;
1234                                 if (quoteit && c == '"')
1235                                 {
1236                                         SM_APPEND_CHAR('\\');
1237                                         SM_APPEND_CHAR(c);
1238                                 }
1239                                 else
1240                                         SM_APPEND_CHAR(c);
1241                         }
1242                         if (quoteit)
1243                         {
1244                                 if (bp == &bufhead[1])
1245                                         bp--;
1246                                 else
1247                                         SM_APPEND_CHAR('"');
1248                                 while ((c = *p++) != ':')
1249                                         SM_APPEND_CHAR(c);
1250                                 SM_APPEND_CHAR(c);
1251                         }
1252
1253                         /* any trailing white space is part of group: */
1254                         while (isascii(*p) && isspace(*p))
1255                         {
1256                                 SM_APPEND_CHAR(*p);
1257                                 p++;
1258                         }
1259                         copylev = 0;
1260                         putgmac = quoteit = false;
1261                         bufhead = bp;
1262                         addrhead = p;
1263                         continue;
1264                 }
1265
1266                 if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1267                         SM_APPEND_CHAR(c);
1268
1269                 /* check for characters that may have to be quoted */
1270                 if (strchr(MustQuoteChars, c) != NULL)
1271                 {
1272                         /*
1273                         **  If these occur as the phrase part of a <>
1274                         **  construct, but are not inside of () or already
1275                         **  quoted, they will have to be quoted.  Note that
1276                         **  now (but don't actually do the quoting).
1277                         */
1278
1279                         if (cmtlev <= 0 && !qmode)
1280                                 quoteit = true;
1281                 }
1282
1283                 /* check for angle brackets */
1284                 if (c == '<')
1285                 {
1286                         register char *q;
1287
1288                         /* assume first of two angles is bogus */
1289                         if (gotangle)
1290                                 quoteit = true;
1291                         gotangle = true;
1292
1293                         /* oops -- have to change our mind */
1294                         anglelev = 1;
1295                         if (SM_HAVE_ROOM)
1296                         {
1297                                 if (!addangle)
1298                                         buflim--;
1299                                 addangle = true;
1300                         }
1301
1302                         bp = bufhead;
1303                         if (quoteit)
1304                         {
1305                                 SM_APPEND_CHAR('"');
1306
1307                                 /* back up over the '<' and any spaces */
1308                                 --p;
1309                                 while (p > addr &&
1310                                        isascii(*--p) && isspace(*p))
1311                                         continue;
1312                                 p++;
1313                         }
1314                         for (q = addrhead; q < p; )
1315                         {
1316                                 c = *q++;
1317                                 if (quoteit && c == '"')
1318                                 {
1319                                         SM_APPEND_CHAR('\\');
1320                                         SM_APPEND_CHAR(c);
1321                                 }
1322                                 else
1323                                         SM_APPEND_CHAR(c);
1324                         }
1325                         if (quoteit)
1326                         {
1327                                 if (bp == &buf[1])
1328                                         bp--;
1329                                 else
1330                                         SM_APPEND_CHAR('"');
1331                                 while ((c = *p++) != '<')
1332                                         SM_APPEND_CHAR(c);
1333                                 SM_APPEND_CHAR(c);
1334                         }
1335                         copylev = 0;
1336                         putgmac = quoteit = false;
1337                         continue;
1338                 }
1339
1340                 if (c == '>')
1341                 {
1342                         if (anglelev > 0)
1343                         {
1344                                 anglelev--;
1345                                 if (SM_HAVE_ROOM)
1346                                 {
1347                                         if (addangle)
1348                                                 buflim++;
1349                                         addangle = false;
1350                                 }
1351                         }
1352                         else if (SM_HAVE_ROOM)
1353                         {
1354                                 /* syntax error: unmatched > */
1355                                 if (copylev > 0)
1356                                         bp--;
1357                                 quoteit = true;
1358                                 continue;
1359                         }
1360                         if (copylev++ <= 0)
1361                                 SM_APPEND_CHAR(c);
1362                         continue;
1363                 }
1364
1365                 /* must be a real address character */
1366         putg:
1367                 if (copylev <= 0 && !putgmac)
1368                 {
1369                         if (bp > buf && bp[-1] == ')')
1370                                 SM_APPEND_CHAR(' ');
1371                         SM_APPEND_CHAR(MACROEXPAND);
1372                         SM_APPEND_CHAR('g');
1373                         putgmac = true;
1374                 }
1375         }
1376
1377         /* repair any syntactic damage */
1378         if (realqmode && bp < bufend)
1379                 *bp++ = '"';
1380         while (realcmtlev-- > 0 && bp < bufend)
1381                 *bp++ = ')';
1382         if (addangle && bp < bufend)
1383                 *bp++ = '>';
1384         *bp = '\0';
1385         if (bp < bufend)
1386                 goto success;
1387
1388  returng:
1389         /* String too long, punt */
1390         buf[0] = '<';
1391         buf[1] = MACROEXPAND;
1392         buf[2]= 'g';
1393         buf[3] = '>';
1394         buf[4]= '\0';
1395         sm_syslog(LOG_ALERT, e->e_id,
1396                   "Dropped invalid comments from header address");
1397
1398  success:
1399         if (tTd(33, 1))
1400         {
1401                 sm_dprintf("crackaddr=>`");
1402                 xputs(buf);
1403                 sm_dprintf("'\n");
1404         }
1405         return buf;
1406 }
1407 /*
1408 **  PUTHEADER -- put the header part of a message from the in-core copy
1409 **
1410 **      Parameters:
1411 **              mci -- the connection information.
1412 **              hdr -- the header to put.
1413 **              e -- envelope to use.
1414 **              flags -- MIME conversion flags.
1415 **
1416 **      Returns:
1417 **              none.
1418 **
1419 **      Side Effects:
1420 **              none.
1421 */
1422
1423 void
1424 putheader(mci, hdr, e, flags)
1425         register MCI *mci;
1426         HDR *hdr;
1427         register ENVELOPE *e;
1428         int flags;
1429 {
1430         register HDR *h;
1431         char buf[SM_MAX(MAXLINE,BUFSIZ)];
1432         char obuf[MAXLINE];
1433
1434         if (tTd(34, 1))
1435                 sm_dprintf("--- putheader, mailer = %s ---\n",
1436                         mci->mci_mailer->m_name);
1437
1438         /*
1439         **  If we're in MIME mode, we're not really in the header of the
1440         **  message, just the header of one of the parts of the body of
1441         **  the message.  Therefore MCIF_INHEADER should not be turned on.
1442         */
1443
1444         if (!bitset(MCIF_INMIME, mci->mci_flags))
1445                 mci->mci_flags |= MCIF_INHEADER;
1446
1447         for (h = hdr; h != NULL; h = h->h_link)
1448         {
1449                 register char *p = h->h_value;
1450                 char *q;
1451
1452                 if (tTd(34, 11))
1453                 {
1454                         sm_dprintf("  %s: ", h->h_field);
1455                         xputs(p);
1456                 }
1457
1458                 /* Skip empty headers */
1459                 if (h->h_value == NULL)
1460                         continue;
1461
1462                 /* heuristic shortening of MIME fields to avoid MUA overflows */
1463                 if (MaxMimeFieldLength > 0 &&
1464                     wordinclass(h->h_field,
1465                                 macid("{checkMIMEFieldHeaders}")))
1466                 {
1467                         size_t len;
1468
1469                         len = fix_mime_header(h, e);
1470                         if (len > 0)
1471                         {
1472                                 sm_syslog(LOG_ALERT, e->e_id,
1473                                           "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1474                                           h->h_field, (unsigned long) len);
1475                                 if (tTd(34, 11))
1476                                         sm_dprintf("  truncated MIME %s header due to field size  (length = %ld) (possible attack)\n",
1477                                                    h->h_field,
1478                                                    (unsigned long) len);
1479                         }
1480                 }
1481
1482                 if (MaxMimeHeaderLength > 0 &&
1483                     wordinclass(h->h_field,
1484                                 macid("{checkMIMETextHeaders}")))
1485                 {
1486                         size_t len;
1487
1488                         len = strlen(h->h_value);
1489                         if (len > (size_t) MaxMimeHeaderLength)
1490                         {
1491                                 h->h_value[MaxMimeHeaderLength - 1] = '\0';
1492                                 sm_syslog(LOG_ALERT, e->e_id,
1493                                           "Truncated long MIME %s header (length = %ld) (possible attack)",
1494                                           h->h_field, (unsigned long) len);
1495                                 if (tTd(34, 11))
1496                                         sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1497                                                    h->h_field,
1498                                                    (unsigned long) len);
1499                         }
1500                 }
1501
1502                 if (MaxMimeHeaderLength > 0 &&
1503                     wordinclass(h->h_field,
1504                                 macid("{checkMIMEHeaders}")))
1505                 {
1506                         size_t len;
1507
1508                         len = strlen(h->h_value);
1509                         if (shorten_rfc822_string(h->h_value,
1510                                                   MaxMimeHeaderLength))
1511                         {
1512                                 if (len < MaxMimeHeaderLength)
1513                                 {
1514                                         /* we only rebalanced a bogus header */
1515                                         sm_syslog(LOG_ALERT, e->e_id,
1516                                                   "Fixed MIME %s header (possible attack)",
1517                                                   h->h_field);
1518                                         if (tTd(34, 11))
1519                                                 sm_dprintf("  fixed MIME %s header (possible attack)\n",
1520                                                            h->h_field);
1521                                 }
1522                                 else
1523                                 {
1524                                         /* we actually shortened header */
1525                                         sm_syslog(LOG_ALERT, e->e_id,
1526                                                   "Truncated long MIME %s header (length = %ld) (possible attack)",
1527                                                   h->h_field,
1528                                                   (unsigned long) len);
1529                                         if (tTd(34, 11))
1530                                                 sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1531                                                            h->h_field,
1532                                                            (unsigned long) len);
1533                                 }
1534                         }
1535                 }
1536
1537                 /*
1538                 **  Suppress Content-Transfer-Encoding: if we are MIMEing
1539                 **  and we are potentially converting from 8 bit to 7 bit
1540                 **  MIME.  If converting, add a new CTE header in
1541                 **  mime8to7().
1542                 */
1543
1544                 if (bitset(H_CTE, h->h_flags) &&
1545                     bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1546                            mci->mci_flags) &&
1547                     !bitset(M87F_NO8TO7, flags))
1548                 {
1549                         if (tTd(34, 11))
1550                                 sm_dprintf(" (skipped (content-transfer-encoding))\n");
1551                         continue;
1552                 }
1553
1554                 if (bitset(MCIF_INMIME, mci->mci_flags))
1555                 {
1556                         if (tTd(34, 11))
1557                                 sm_dprintf("\n");
1558                         put_vanilla_header(h, p, mci);
1559                         continue;
1560                 }
1561
1562                 if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
1563                     !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
1564                     (h->h_macro == '\0' ||
1565                      (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
1566                      *q == '\0'))
1567                 {
1568                         if (tTd(34, 11))
1569                                 sm_dprintf(" (skipped)\n");
1570                         continue;
1571                 }
1572
1573                 /* handle Resent-... headers specially */
1574                 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1575                 {
1576                         if (tTd(34, 11))
1577                                 sm_dprintf(" (skipped (resent))\n");
1578                         continue;
1579                 }
1580
1581                 /* suppress return receipts if requested */
1582                 if (bitset(H_RECEIPTTO, h->h_flags) &&
1583                     (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1584                 {
1585                         if (tTd(34, 11))
1586                                 sm_dprintf(" (skipped (receipt))\n");
1587                         continue;
1588                 }
1589
1590                 /* macro expand value if generated internally */
1591                 if (bitset(H_DEFAULT, h->h_flags) ||
1592                     bitset(H_BINDLATE, h->h_flags))
1593                 {
1594                         expand(p, buf, sizeof buf, e);
1595                         p = buf;
1596                         if (*p == '\0')
1597                         {
1598                                 if (tTd(34, 11))
1599                                         sm_dprintf(" (skipped -- null value)\n");
1600                                 continue;
1601                         }
1602                 }
1603
1604                 if (bitset(H_BCC, h->h_flags))
1605                 {
1606                         /* Bcc: field -- either truncate or delete */
1607                         if (bitset(EF_DELETE_BCC, e->e_flags))
1608                         {
1609                                 if (tTd(34, 11))
1610                                         sm_dprintf(" (skipped -- bcc)\n");
1611                         }
1612                         else
1613                         {
1614                                 /* no other recipient headers: truncate value */
1615                                 (void) sm_strlcpyn(obuf, sizeof obuf, 2,
1616                                                    h->h_field, ":");
1617                                 putline(obuf, mci);
1618                         }
1619                         continue;
1620                 }
1621
1622                 if (tTd(34, 11))
1623                         sm_dprintf("\n");
1624
1625                 if (bitset(H_FROM|H_RCPT, h->h_flags))
1626                 {
1627                         /* address field */
1628                         bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1629
1630                         if (bitset(H_FROM, h->h_flags))
1631                                 oldstyle = false;
1632                         commaize(h, p, oldstyle, mci, e);
1633                 }
1634                 else
1635                 {
1636                         put_vanilla_header(h, p, mci);
1637                 }
1638         }
1639
1640         /*
1641         **  If we are converting this to a MIME message, add the
1642         **  MIME headers (but not in MIME mode!).
1643         */
1644
1645 #if MIME8TO7
1646         if (bitset(MM_MIME8BIT, MimeMode) &&
1647             bitset(EF_HAS8BIT, e->e_flags) &&
1648             !bitset(EF_DONT_MIME, e->e_flags) &&
1649             !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
1650             !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
1651             hvalue("MIME-Version", e->e_header) == NULL)
1652         {
1653                 putline("MIME-Version: 1.0", mci);
1654                 if (hvalue("Content-Type", e->e_header) == NULL)
1655                 {
1656                         (void) sm_snprintf(obuf, sizeof obuf,
1657                                         "Content-Type: text/plain; charset=%s",
1658                                         defcharset(e));
1659                         putline(obuf, mci);
1660                 }
1661                 if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
1662                         putline("Content-Transfer-Encoding: 8bit", mci);
1663         }
1664 #endif /* MIME8TO7 */
1665 }
1666 /*
1667 **  PUT_VANILLA_HEADER -- output a fairly ordinary header
1668 **
1669 **      Parameters:
1670 **              h -- the structure describing this header
1671 **              v -- the value of this header
1672 **              mci -- the connection info for output
1673 **
1674 **      Returns:
1675 **              none.
1676 */
1677
1678 static void
1679 put_vanilla_header(h, v, mci)
1680         HDR *h;
1681         char *v;
1682         MCI *mci;
1683 {
1684         register char *nlp;
1685         register char *obp;
1686         int putflags;
1687         char obuf[MAXLINE];
1688
1689         putflags = PXLF_HEADER;
1690         if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1691                 putflags |= PXLF_STRIP8BIT;
1692         (void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
1693         obp = obuf + strlen(obuf);
1694         while ((nlp = strchr(v, '\n')) != NULL)
1695         {
1696                 int l;
1697
1698                 l = nlp - v;
1699                 if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
1700                         l = SPACELEFT(obuf, obp) - 1;
1701
1702                 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1703                 putxline(obuf, strlen(obuf), mci, putflags);
1704                 v += l + 1;
1705                 obp = obuf;
1706                 if (*v != ' ' && *v != '\t')
1707                         *obp++ = ' ';
1708         }
1709         (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
1710                            (int) (SPACELEFT(obuf, obp) - 1), v);
1711         putxline(obuf, strlen(obuf), mci, putflags);
1712 }
1713 /*
1714 **  COMMAIZE -- output a header field, making a comma-translated list.
1715 **
1716 **      Parameters:
1717 **              h -- the header field to output.
1718 **              p -- the value to put in it.
1719 **              oldstyle -- true if this is an old style header.
1720 **              mci -- the connection information.
1721 **              e -- the envelope containing the message.
1722 **
1723 **      Returns:
1724 **              none.
1725 **
1726 **      Side Effects:
1727 **              outputs "p" to file "fp".
1728 */
1729
1730 void
1731 commaize(h, p, oldstyle, mci, e)
1732         register HDR *h;
1733         register char *p;
1734         bool oldstyle;
1735         register MCI *mci;
1736         register ENVELOPE *e;
1737 {
1738         register char *obp;
1739         int opos;
1740         int omax;
1741         bool firstone = true;
1742         int putflags = PXLF_HEADER;
1743         char obuf[MAXLINE + 3];
1744
1745         /*
1746         **  Output the address list translated by the
1747         **  mailer and with commas.
1748         */
1749
1750         if (tTd(14, 2))
1751                 sm_dprintf("commaize(%s: %s)\n", h->h_field, p);
1752
1753         if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1754                 putflags |= PXLF_STRIP8BIT;
1755
1756         obp = obuf;
1757         (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ",
1758                         h->h_field);
1759         opos = strlen(h->h_field) + 2;
1760         if (opos > 202)
1761                 opos = 202;
1762         obp += opos;
1763         omax = mci->mci_mailer->m_linelimit - 2;
1764         if (omax < 0 || omax > 78)
1765                 omax = 78;
1766
1767         /*
1768         **  Run through the list of values.
1769         */
1770
1771         while (*p != '\0')
1772         {
1773                 register char *name;
1774                 register int c;
1775                 char savechar;
1776                 int flags;
1777                 auto int status;
1778
1779                 /*
1780                 **  Find the end of the name.  New style names
1781                 **  end with a comma, old style names end with
1782                 **  a space character.  However, spaces do not
1783                 **  necessarily delimit an old-style name -- at
1784                 **  signs mean keep going.
1785                 */
1786
1787                 /* find end of name */
1788                 while ((isascii(*p) && isspace(*p)) || *p == ',')
1789                         p++;
1790                 name = p;
1791                 for (;;)
1792                 {
1793                         auto char *oldp;
1794                         char pvpbuf[PSBUFSIZE];
1795
1796                         (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1797                                        sizeof pvpbuf, &oldp, NULL);
1798                         p = oldp;
1799
1800                         /* look to see if we have an at sign */
1801                         while (*p != '\0' && isascii(*p) && isspace(*p))
1802                                 p++;
1803
1804                         if (*p != '@')
1805                         {
1806                                 p = oldp;
1807                                 break;
1808                         }
1809                         ++p;
1810                         while (*p != '\0' && isascii(*p) && isspace(*p))
1811                                 p++;
1812                 }
1813                 /* at the end of one complete name */
1814
1815                 /* strip off trailing white space */
1816                 while (p >= name &&
1817                        ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1818                         p--;
1819                 if (++p == name)
1820                         continue;
1821                 savechar = *p;
1822                 *p = '\0';
1823
1824                 /* translate the name to be relative */
1825                 flags = RF_HEADERADDR|RF_ADDDOMAIN;
1826                 if (bitset(H_FROM, h->h_flags))
1827                         flags |= RF_SENDERADDR;
1828 #if USERDB
1829                 else if (e->e_from.q_mailer != NULL &&
1830                          bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
1831                 {
1832                         char *q;
1833
1834                         q = udbsender(name, e->e_rpool);
1835                         if (q != NULL)
1836                                 name = q;
1837                 }
1838 #endif /* USERDB */
1839                 status = EX_OK;
1840                 name = remotename(name, mci->mci_mailer, flags, &status, e);
1841                 if (*name == '\0')
1842                 {
1843                         *p = savechar;
1844                         continue;
1845                 }
1846                 name = denlstring(name, false, true);
1847
1848                 /*
1849                 **  record data progress so DNS timeouts
1850                 **  don't cause DATA timeouts
1851                 */
1852
1853                 DataProgress = true;
1854
1855                 /* output the name with nice formatting */
1856                 opos += strlen(name);
1857                 if (!firstone)
1858                         opos += 2;
1859                 if (opos > omax && !firstone)
1860                 {
1861                         (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
1862                         putxline(obuf, strlen(obuf), mci, putflags);
1863                         obp = obuf;
1864                         (void) sm_strlcpy(obp, "        ", sizeof obp);
1865                         opos = strlen(obp);
1866                         obp += opos;
1867                         opos += strlen(name);
1868                 }
1869                 else if (!firstone)
1870                 {
1871                         (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
1872                         obp += 2;
1873                 }
1874
1875                 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
1876                         *obp++ = c;
1877                 firstone = false;
1878                 *p = savechar;
1879         }
1880         *obp = '\0';
1881         putxline(obuf, strlen(obuf), mci, putflags);
1882 }
1883 /*
1884 **  COPYHEADER -- copy header list
1885 **
1886 **      This routine is the equivalent of newstr for header lists
1887 **
1888 **      Parameters:
1889 **              header -- list of header structures to copy.
1890 **              rpool -- resource pool, or NULL
1891 **
1892 **      Returns:
1893 **              a copy of 'header'.
1894 **
1895 **      Side Effects:
1896 **              none.
1897 */
1898
1899 HDR *
1900 copyheader(header, rpool)
1901         register HDR *header;
1902         SM_RPOOL_T *rpool;
1903 {
1904         register HDR *newhdr;
1905         HDR *ret;
1906         register HDR **tail = &ret;
1907
1908         while (header != NULL)
1909         {
1910                 newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr);
1911                 STRUCTCOPY(*header, *newhdr);
1912                 *tail = newhdr;
1913                 tail = &newhdr->h_link;
1914                 header = header->h_link;
1915         }
1916         *tail = NULL;
1917
1918         return ret;
1919 }
1920 /*
1921 **  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
1922 **
1923 **      Run through all of the parameters of a MIME header and
1924 **      possibly truncate and rebalance the parameter according
1925 **      to MaxMimeFieldLength.
1926 **
1927 **      Parameters:
1928 **              h -- the header to truncate/rebalance
1929 **              e -- the current envelope
1930 **
1931 **      Returns:
1932 **              length of last offending field, 0 if all ok.
1933 **
1934 **      Side Effects:
1935 **              string modified in place
1936 */
1937
1938 static size_t
1939 fix_mime_header(h, e)
1940         HDR *h;
1941         ENVELOPE *e;
1942 {
1943         char *begin = h->h_value;
1944         char *end;
1945         size_t len = 0;
1946         size_t retlen = 0;
1947
1948         if (begin == NULL || *begin == '\0')
1949                 return 0;
1950
1951         /* Split on each ';' */
1952         while ((end = find_character(begin, ';')) != NULL)
1953         {
1954                 char save = *end;
1955                 char *bp;
1956
1957                 *end = '\0';
1958
1959                 len = strlen(begin);
1960
1961                 /* Shorten individual parameter */
1962                 if (shorten_rfc822_string(begin, MaxMimeFieldLength))
1963                 {
1964                         if (len < MaxMimeFieldLength)
1965                         {
1966                                 /* we only rebalanced a bogus field */
1967                                 sm_syslog(LOG_ALERT, e->e_id,
1968                                           "Fixed MIME %s header field (possible attack)",
1969                                           h->h_field);
1970                                 if (tTd(34, 11))
1971                                         sm_dprintf("  fixed MIME %s header field (possible attack)\n",
1972                                                    h->h_field);
1973                         }
1974                         else
1975                         {
1976                                 /* we actually shortened the header */
1977                                 retlen = len;
1978                         }
1979                 }
1980
1981                 /* Collapse the possibly shortened string with rest */
1982                 bp = begin + strlen(begin);
1983                 if (bp != end)
1984                 {
1985                         char *ep = end;
1986
1987                         *end = save;
1988                         end = bp;
1989
1990                         /* copy character by character due to overlap */
1991                         while (*ep != '\0')
1992                                 *bp++ = *ep++;
1993                         *bp = '\0';
1994                 }
1995                 else
1996                         *end = save;
1997                 if (*end == '\0')
1998                         break;
1999
2000                 /* Move past ';' */
2001                 begin = end + 1;
2002         }
2003         return retlen;
2004 }