1c2aa98e2SPeter Wemm /* 2f9218d3dSGregory Neil Shapiro * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. 33299c2f1SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 127660b554SGregory Neil Shapiro * $FreeBSD$ 13c2aa98e2SPeter Wemm */ 14c2aa98e2SPeter Wemm 1512ed1c7cSGregory Neil Shapiro #include <sendmail.h> 16c2aa98e2SPeter Wemm 171ae5b8d4SGregory Neil Shapiro SM_RCSID("@(#)$Id: headers.c,v 8.266.4.9 2003/10/30 00:17:22 gshapiro Exp $") 183299c2f1SGregory Neil Shapiro 19f9218d3dSGregory Neil Shapiro static size_t fix_mime_header __P((HDR *, ENVELOPE *)); 203299c2f1SGregory Neil Shapiro static int priencode __P((char *)); 213299c2f1SGregory Neil Shapiro static void put_vanilla_header __P((HDR *, char *, MCI *)); 22c2aa98e2SPeter Wemm 23c2aa98e2SPeter Wemm /* 24c2aa98e2SPeter Wemm ** SETUPHEADERS -- initialize headers in symbol table 25c2aa98e2SPeter Wemm ** 26c2aa98e2SPeter Wemm ** Parameters: 27c2aa98e2SPeter Wemm ** none 28c2aa98e2SPeter Wemm ** 29c2aa98e2SPeter Wemm ** Returns: 30c2aa98e2SPeter Wemm ** none 31c2aa98e2SPeter Wemm */ 32c2aa98e2SPeter Wemm 33c2aa98e2SPeter Wemm void 34c2aa98e2SPeter Wemm setupheaders() 35c2aa98e2SPeter Wemm { 36c2aa98e2SPeter Wemm struct hdrinfo *hi; 37c2aa98e2SPeter Wemm STAB *s; 38c2aa98e2SPeter Wemm 39c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 40c2aa98e2SPeter Wemm { 41c2aa98e2SPeter Wemm s = stab(hi->hi_field, ST_HEADER, ST_ENTER); 42c2aa98e2SPeter Wemm s->s_header.hi_flags = hi->hi_flags; 43c2aa98e2SPeter Wemm s->s_header.hi_ruleset = NULL; 44c2aa98e2SPeter Wemm } 45c2aa98e2SPeter Wemm } 4612ed1c7cSGregory Neil Shapiro /* 47c2aa98e2SPeter Wemm ** CHOMPHEADER -- process and save a header line. 48c2aa98e2SPeter Wemm ** 493299c2f1SGregory Neil Shapiro ** Called by collect, readcf, and readqf to deal with header lines. 50c2aa98e2SPeter Wemm ** 51c2aa98e2SPeter Wemm ** Parameters: 52c2aa98e2SPeter Wemm ** line -- header as a text line. 53d995d2baSGregory Neil Shapiro ** pflag -- flags for chompheader() (from sendmail.h) 54c2aa98e2SPeter Wemm ** hdrp -- a pointer to the place to save the header. 55c2aa98e2SPeter Wemm ** e -- the envelope including this header. 56c2aa98e2SPeter Wemm ** 57c2aa98e2SPeter Wemm ** Returns: 58c2aa98e2SPeter Wemm ** flags for this header. 59c2aa98e2SPeter Wemm ** 60c2aa98e2SPeter Wemm ** Side Effects: 61c2aa98e2SPeter Wemm ** The header is saved on the header list. 62c2aa98e2SPeter Wemm ** Contents of 'line' are destroyed. 63c2aa98e2SPeter Wemm */ 64c2aa98e2SPeter Wemm 653299c2f1SGregory Neil Shapiro static struct hdrinfo NormalHeader = { NULL, 0, NULL }; 66c2aa98e2SPeter Wemm 6712ed1c7cSGregory Neil Shapiro unsigned long 683299c2f1SGregory Neil Shapiro chompheader(line, pflag, hdrp, e) 69c2aa98e2SPeter Wemm char *line; 703299c2f1SGregory Neil Shapiro int pflag; 71c2aa98e2SPeter Wemm HDR **hdrp; 72c2aa98e2SPeter Wemm register ENVELOPE *e; 73c2aa98e2SPeter Wemm { 7412ed1c7cSGregory Neil Shapiro unsigned char mid = '\0'; 75c2aa98e2SPeter Wemm register char *p; 76c2aa98e2SPeter Wemm register HDR *h; 77c2aa98e2SPeter Wemm HDR **hp; 78c2aa98e2SPeter Wemm char *fname; 79c2aa98e2SPeter Wemm char *fvalue; 8012ed1c7cSGregory Neil Shapiro bool cond = false; 813299c2f1SGregory Neil Shapiro bool dropfrom; 82c2aa98e2SPeter Wemm bool headeronly; 83c2aa98e2SPeter Wemm STAB *s; 84c2aa98e2SPeter Wemm struct hdrinfo *hi; 8512ed1c7cSGregory Neil Shapiro bool nullheader = false; 863299c2f1SGregory Neil Shapiro BITMAP256 mopts; 87c2aa98e2SPeter Wemm 88c2aa98e2SPeter Wemm if (tTd(31, 6)) 89c2aa98e2SPeter Wemm { 9012ed1c7cSGregory Neil Shapiro sm_dprintf("chompheader: "); 91c2aa98e2SPeter Wemm xputs(line); 9212ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 93c2aa98e2SPeter Wemm } 94c2aa98e2SPeter Wemm 95c2aa98e2SPeter Wemm headeronly = hdrp != NULL; 96c2aa98e2SPeter Wemm if (!headeronly) 97c2aa98e2SPeter Wemm hdrp = &e->e_header; 98c2aa98e2SPeter Wemm 99c2aa98e2SPeter Wemm /* strip off options */ 100c2aa98e2SPeter Wemm clrbitmap(mopts); 101c2aa98e2SPeter Wemm p = line; 1023299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_USER) && *p == '?') 103c2aa98e2SPeter Wemm { 1043299c2f1SGregory Neil Shapiro int c; 1053299c2f1SGregory Neil Shapiro register char *q; 106c2aa98e2SPeter Wemm 1073299c2f1SGregory Neil Shapiro q = strchr(++p, '?'); 1083299c2f1SGregory Neil Shapiro if (q == NULL) 1093299c2f1SGregory Neil Shapiro goto hse; 1103299c2f1SGregory Neil Shapiro 1113299c2f1SGregory Neil Shapiro *q = '\0'; 1123299c2f1SGregory Neil Shapiro c = *p & 0377; 1133299c2f1SGregory Neil Shapiro 1143299c2f1SGregory Neil Shapiro /* possibly macro conditional */ 1153299c2f1SGregory Neil Shapiro if (c == MACROEXPAND) 116c2aa98e2SPeter Wemm { 1173299c2f1SGregory Neil Shapiro /* catch ?$? */ 1183299c2f1SGregory Neil Shapiro if (*++p == '\0') 1193299c2f1SGregory Neil Shapiro { 1203299c2f1SGregory Neil Shapiro *q = '?'; 1213299c2f1SGregory Neil Shapiro goto hse; 1223299c2f1SGregory Neil Shapiro } 1233299c2f1SGregory Neil Shapiro 12412ed1c7cSGregory Neil Shapiro mid = (unsigned char) *p++; 1253299c2f1SGregory Neil Shapiro 1263299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1273299c2f1SGregory Neil Shapiro if (*p != '\0') 1283299c2f1SGregory Neil Shapiro { 1293299c2f1SGregory Neil Shapiro *q = '?'; 1303299c2f1SGregory Neil Shapiro goto hse; 1313299c2f1SGregory Neil Shapiro } 1323299c2f1SGregory Neil Shapiro } 1333299c2f1SGregory Neil Shapiro else if (*p == '$') 1343299c2f1SGregory Neil Shapiro { 1353299c2f1SGregory Neil Shapiro /* catch ?$? */ 1363299c2f1SGregory Neil Shapiro if (*++p == '\0') 1373299c2f1SGregory Neil Shapiro { 1383299c2f1SGregory Neil Shapiro *q = '?'; 1393299c2f1SGregory Neil Shapiro goto hse; 1403299c2f1SGregory Neil Shapiro } 1413299c2f1SGregory Neil Shapiro 14212ed1c7cSGregory Neil Shapiro mid = (unsigned char) macid(p); 1433299c2f1SGregory Neil Shapiro if (bitset(0200, mid)) 1447660b554SGregory Neil Shapiro { 1453299c2f1SGregory Neil Shapiro p += strlen(macname(mid)) + 2; 1467660b554SGregory Neil Shapiro SM_ASSERT(p <= q); 1477660b554SGregory Neil Shapiro } 1483299c2f1SGregory Neil Shapiro else 1493299c2f1SGregory Neil Shapiro p++; 1503299c2f1SGregory Neil Shapiro 1513299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1523299c2f1SGregory Neil Shapiro if (*p != '\0') 1533299c2f1SGregory Neil Shapiro { 1543299c2f1SGregory Neil Shapiro *q = '?'; 1553299c2f1SGregory Neil Shapiro goto hse; 1563299c2f1SGregory Neil Shapiro } 157c2aa98e2SPeter Wemm } 158c2aa98e2SPeter Wemm else 1593299c2f1SGregory Neil Shapiro { 1603299c2f1SGregory Neil Shapiro while (*p != '\0') 1613299c2f1SGregory Neil Shapiro { 1623299c2f1SGregory Neil Shapiro if (!isascii(*p)) 1633299c2f1SGregory Neil Shapiro { 1643299c2f1SGregory Neil Shapiro *q = '?'; 1653299c2f1SGregory Neil Shapiro goto hse; 1663299c2f1SGregory Neil Shapiro } 1673299c2f1SGregory Neil Shapiro 168c46d91b7SGregory Neil Shapiro setbitn(bitidx(*p), mopts); 16912ed1c7cSGregory Neil Shapiro cond = true; 1703299c2f1SGregory Neil Shapiro p++; 1713299c2f1SGregory Neil Shapiro } 1723299c2f1SGregory Neil Shapiro } 1733299c2f1SGregory Neil Shapiro p = q + 1; 174c2aa98e2SPeter Wemm } 175c2aa98e2SPeter Wemm 176c2aa98e2SPeter Wemm /* find canonical name */ 177c2aa98e2SPeter Wemm fname = p; 178c2aa98e2SPeter Wemm while (isascii(*p) && isgraph(*p) && *p != ':') 179c2aa98e2SPeter Wemm p++; 180c2aa98e2SPeter Wemm fvalue = p; 181c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 182c2aa98e2SPeter Wemm p++; 183c2aa98e2SPeter Wemm if (*p++ != ':' || fname == fvalue) 184c2aa98e2SPeter Wemm { 1853299c2f1SGregory Neil Shapiro hse: 1863299c2f1SGregory Neil Shapiro syserr("553 5.3.0 header syntax error, line \"%s\"", line); 187c2aa98e2SPeter Wemm return 0; 188c2aa98e2SPeter Wemm } 189c2aa98e2SPeter Wemm *fvalue = '\0'; 190c2aa98e2SPeter Wemm 191c2aa98e2SPeter Wemm /* strip field value on front */ 192e01d6f61SPeter Wemm if (*p == ' ') 193e01d6f61SPeter Wemm p++; 194e01d6f61SPeter Wemm fvalue = p; 195e01d6f61SPeter Wemm 196e01d6f61SPeter Wemm /* if the field is null, go ahead and use the default */ 197e01d6f61SPeter Wemm while (isascii(*p) && isspace(*p)) 198e01d6f61SPeter Wemm p++; 199e01d6f61SPeter Wemm if (*p == '\0') 20012ed1c7cSGregory Neil Shapiro nullheader = true; 201c2aa98e2SPeter Wemm 202c2aa98e2SPeter Wemm /* security scan: long field names are end-of-header */ 203c2aa98e2SPeter Wemm if (strlen(fname) > 100) 204c2aa98e2SPeter Wemm return H_EOH; 205c2aa98e2SPeter Wemm 206c2aa98e2SPeter Wemm /* check to see if it represents a ruleset call */ 2073299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 208c2aa98e2SPeter Wemm { 209c2aa98e2SPeter Wemm char hbuf[50]; 210c2aa98e2SPeter Wemm 211c2aa98e2SPeter Wemm (void) expand(fvalue, hbuf, sizeof hbuf, e); 212c2aa98e2SPeter Wemm for (p = hbuf; isascii(*p) && isspace(*p); ) 213c2aa98e2SPeter Wemm p++; 214c2aa98e2SPeter Wemm if ((*p++ & 0377) == CALLSUBR) 215c2aa98e2SPeter Wemm { 216c2aa98e2SPeter Wemm auto char *endp; 2173299c2f1SGregory Neil Shapiro bool strc; 218c2aa98e2SPeter Wemm 2193299c2f1SGregory Neil Shapiro strc = *p == '+'; /* strip comments? */ 2203299c2f1SGregory Neil Shapiro if (strc) 2213299c2f1SGregory Neil Shapiro ++p; 222c2aa98e2SPeter Wemm if (strtorwset(p, &endp, ST_ENTER) > 0) 223c2aa98e2SPeter Wemm { 224c2aa98e2SPeter Wemm *endp = '\0'; 225c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_ENTER); 22612ed1c7cSGregory Neil Shapiro if (LogLevel > 9 && 22712ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset != NULL) 22812ed1c7cSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 22912ed1c7cSGregory Neil Shapiro "Warning: redefined ruleset for header=%s, old=%s, new=%s", 23012ed1c7cSGregory Neil Shapiro fname, 23112ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset, p); 232c2aa98e2SPeter Wemm s->s_header.hi_ruleset = newstr(p); 2333299c2f1SGregory Neil Shapiro if (!strc) 2343299c2f1SGregory Neil Shapiro s->s_header.hi_flags |= H_STRIPCOMM; 235c2aa98e2SPeter Wemm } 236c2aa98e2SPeter Wemm return 0; 237c2aa98e2SPeter Wemm } 238c2aa98e2SPeter Wemm } 239c2aa98e2SPeter Wemm 240c2aa98e2SPeter Wemm /* see if it is a known type */ 241c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_FIND); 242c2aa98e2SPeter Wemm if (s != NULL) 243c2aa98e2SPeter Wemm hi = &s->s_header; 244c2aa98e2SPeter Wemm else 245c2aa98e2SPeter Wemm hi = &NormalHeader; 246c2aa98e2SPeter Wemm 247c2aa98e2SPeter Wemm if (tTd(31, 9)) 248c2aa98e2SPeter Wemm { 249c2aa98e2SPeter Wemm if (s == NULL) 25012ed1c7cSGregory Neil Shapiro sm_dprintf("no header flags match\n"); 251c2aa98e2SPeter Wemm else 25212ed1c7cSGregory Neil Shapiro sm_dprintf("header match, flags=%lx, ruleset=%s\n", 253c2aa98e2SPeter Wemm hi->hi_flags, 25412ed1c7cSGregory Neil Shapiro hi->hi_ruleset == NULL ? "<NULL>" 25512ed1c7cSGregory Neil Shapiro : hi->hi_ruleset); 256c2aa98e2SPeter Wemm } 257c2aa98e2SPeter Wemm 258c2aa98e2SPeter Wemm /* see if this is a resent message */ 2593299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 2603299c2f1SGregory Neil Shapiro bitset(H_RESENT, hi->hi_flags)) 261c2aa98e2SPeter Wemm e->e_flags |= EF_RESENT; 262c2aa98e2SPeter Wemm 263c2aa98e2SPeter Wemm /* if this is an Errors-To: header keep track of it now */ 2643299c2f1SGregory Neil Shapiro if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly && 265c2aa98e2SPeter Wemm bitset(H_ERRORSTO, hi->hi_flags)) 266c2aa98e2SPeter Wemm (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 267c2aa98e2SPeter Wemm 268c2aa98e2SPeter Wemm /* if this means "end of header" quit now */ 269c2aa98e2SPeter Wemm if (!headeronly && bitset(H_EOH, hi->hi_flags)) 270c2aa98e2SPeter Wemm return hi->hi_flags; 271c2aa98e2SPeter Wemm 272c2aa98e2SPeter Wemm /* 273c2aa98e2SPeter Wemm ** Horrible hack to work around problem with Lotus Notes SMTP 274c2aa98e2SPeter Wemm ** mail gateway, which generates From: headers with newlines in 275c2aa98e2SPeter Wemm ** them and the <address> on the second line. Although this is 276c2aa98e2SPeter Wemm ** legal RFC 822, many MUAs don't handle this properly and thus 277c2aa98e2SPeter Wemm ** never find the actual address. 278c2aa98e2SPeter Wemm */ 279c2aa98e2SPeter Wemm 280c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader) 281c2aa98e2SPeter Wemm { 282c2aa98e2SPeter Wemm while ((p = strchr(fvalue, '\n')) != NULL) 283c2aa98e2SPeter Wemm *p = ' '; 284c2aa98e2SPeter Wemm } 285c2aa98e2SPeter Wemm 286c2aa98e2SPeter Wemm /* 287c2aa98e2SPeter Wemm ** If there is a check ruleset, verify it against the header. 288c2aa98e2SPeter Wemm */ 289c2aa98e2SPeter Wemm 2903299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_CHECK)) 2913299c2f1SGregory Neil Shapiro { 2929d8fddc1SGregory Neil Shapiro int rscheckflags; 2933299c2f1SGregory Neil Shapiro char *rs; 2943299c2f1SGregory Neil Shapiro 2953299c2f1SGregory Neil Shapiro /* no ruleset? look for default */ 2963299c2f1SGregory Neil Shapiro rs = hi->hi_ruleset; 2979d8fddc1SGregory Neil Shapiro rscheckflags = RSF_COUNT; 2989d8fddc1SGregory Neil Shapiro if (!bitset(hi->hi_flags, H_FROM|H_RCPT)) 2999d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_UNSTRUCTURED; 3003299c2f1SGregory Neil Shapiro if (rs == NULL) 3013299c2f1SGregory Neil Shapiro { 3023299c2f1SGregory Neil Shapiro s = stab("*", ST_HEADER, ST_FIND); 3033299c2f1SGregory Neil Shapiro if (s != NULL) 3043299c2f1SGregory Neil Shapiro { 3053299c2f1SGregory Neil Shapiro rs = (&s->s_header)->hi_ruleset; 3069d8fddc1SGregory Neil Shapiro if (bitset((&s->s_header)->hi_flags, 3079d8fddc1SGregory Neil Shapiro H_STRIPCOMM)) 3089d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM; 3093299c2f1SGregory Neil Shapiro } 3103299c2f1SGregory Neil Shapiro } 3119d8fddc1SGregory Neil Shapiro else if (bitset(hi->hi_flags, H_STRIPCOMM)) 3129d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM; 3133299c2f1SGregory Neil Shapiro if (rs != NULL) 3143299c2f1SGregory Neil Shapiro { 31512ed1c7cSGregory Neil Shapiro int l, k; 3163299c2f1SGregory Neil Shapiro char qval[MAXNAME]; 3173299c2f1SGregory Neil Shapiro 3183299c2f1SGregory Neil Shapiro l = 0; 31912ed1c7cSGregory Neil Shapiro qval[l++] = '"'; 32012ed1c7cSGregory Neil Shapiro 32112ed1c7cSGregory Neil Shapiro /* - 3 to avoid problems with " at the end */ 3227660b554SGregory Neil Shapiro /* should be sizeof(qval), not MAXNAME */ 32312ed1c7cSGregory Neil Shapiro for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++) 3243299c2f1SGregory Neil Shapiro { 32512ed1c7cSGregory Neil Shapiro switch (fvalue[k]) 3263299c2f1SGregory Neil Shapiro { 32712ed1c7cSGregory Neil Shapiro /* XXX other control chars? */ 3283299c2f1SGregory Neil Shapiro case '\011': /* ht */ 3293299c2f1SGregory Neil Shapiro case '\012': /* nl */ 3303299c2f1SGregory Neil Shapiro case '\013': /* vt */ 3313299c2f1SGregory Neil Shapiro case '\014': /* np */ 3323299c2f1SGregory Neil Shapiro case '\015': /* cr */ 33312ed1c7cSGregory Neil Shapiro qval[l++] = ' '; 3343299c2f1SGregory Neil Shapiro break; 3353299c2f1SGregory Neil Shapiro case '"': 33612ed1c7cSGregory Neil Shapiro qval[l++] = '\\'; 3373299c2f1SGregory Neil Shapiro /* FALLTHROUGH */ 3383299c2f1SGregory Neil Shapiro default: 33912ed1c7cSGregory Neil Shapiro qval[l++] = fvalue[k]; 3403299c2f1SGregory Neil Shapiro break; 3413299c2f1SGregory Neil Shapiro } 3423299c2f1SGregory Neil Shapiro } 34312ed1c7cSGregory Neil Shapiro qval[l++] = '"'; 34412ed1c7cSGregory Neil Shapiro qval[l] = '\0'; 34512ed1c7cSGregory Neil Shapiro k += strlen(fvalue + k); 34612ed1c7cSGregory Neil Shapiro if (k >= MAXNAME) 3473299c2f1SGregory Neil Shapiro { 3483299c2f1SGregory Neil Shapiro if (LogLevel > 9) 3493299c2f1SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 3503299c2f1SGregory Neil Shapiro "Warning: truncated header '%s' before check with '%s' len=%d max=%d", 35112ed1c7cSGregory Neil Shapiro fname, rs, k, MAXNAME - 1); 3523299c2f1SGregory Neil Shapiro } 35312ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 35412ed1c7cSGregory Neil Shapiro macid("{currHeader}"), qval); 35512ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 35612ed1c7cSGregory Neil Shapiro macid("{hdr_name}"), fname); 35712ed1c7cSGregory Neil Shapiro 35812ed1c7cSGregory Neil Shapiro (void) sm_snprintf(qval, sizeof qval, "%d", k); 35912ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval); 36012ed1c7cSGregory Neil Shapiro #if _FFR_HDR_TYPE 36112ed1c7cSGregory Neil Shapiro /* 36212ed1c7cSGregory Neil Shapiro ** XXX: h isn't set yet 36312ed1c7cSGregory Neil Shapiro ** If we really want to be precise then we have 36412ed1c7cSGregory Neil Shapiro ** to lookup the header (see below). 36512ed1c7cSGregory Neil Shapiro ** It's probably not worth the effort. 36612ed1c7cSGregory Neil Shapiro */ 36712ed1c7cSGregory Neil Shapiro 36812ed1c7cSGregory Neil Shapiro if (bitset(H_FROM, h->h_flags)) 36912ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 37012ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h s"); 37112ed1c7cSGregory Neil Shapiro else if (bitset(H_RCPT, h->h_flags)) 37212ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 37312ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h r"); 37412ed1c7cSGregory Neil Shapiro else 37512ed1c7cSGregory Neil Shapiro #endif /* _FFR_HDR_TYPE */ 37612ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 37712ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h"); 3789d8fddc1SGregory Neil Shapiro (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3, 37912ed1c7cSGregory Neil Shapiro NULL, e->e_id); 3803299c2f1SGregory Neil Shapiro } 3813299c2f1SGregory Neil Shapiro } 382c2aa98e2SPeter Wemm 383c2aa98e2SPeter Wemm /* 384c2aa98e2SPeter Wemm ** Drop explicit From: if same as what we would generate. 385c2aa98e2SPeter Wemm ** This is to make MH (which doesn't always give a full name) 386c2aa98e2SPeter Wemm ** insert the full name information in all circumstances. 387c2aa98e2SPeter Wemm */ 388c2aa98e2SPeter Wemm 38912ed1c7cSGregory Neil Shapiro dropfrom = false; 390c2aa98e2SPeter Wemm p = "resent-from"; 391c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 392c2aa98e2SPeter Wemm p += 7; 3933299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 39412ed1c7cSGregory Neil Shapiro !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0) 395c2aa98e2SPeter Wemm { 396c2aa98e2SPeter Wemm if (tTd(31, 2)) 397c2aa98e2SPeter Wemm { 39812ed1c7cSGregory Neil Shapiro sm_dprintf("comparing header from (%s) against default (%s or %s)\n", 399c2aa98e2SPeter Wemm fvalue, e->e_from.q_paddr, e->e_from.q_user); 400c2aa98e2SPeter Wemm } 401c2aa98e2SPeter Wemm if (e->e_from.q_paddr != NULL && 4023299c2f1SGregory Neil Shapiro e->e_from.q_mailer != NULL && 4033299c2f1SGregory Neil Shapiro bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && 404c2aa98e2SPeter Wemm (strcmp(fvalue, e->e_from.q_paddr) == 0 || 405c2aa98e2SPeter Wemm strcmp(fvalue, e->e_from.q_user) == 0)) 40612ed1c7cSGregory Neil Shapiro dropfrom = true; 407c2aa98e2SPeter Wemm } 408c2aa98e2SPeter Wemm 409c2aa98e2SPeter Wemm /* delete default value for this header */ 410c2aa98e2SPeter Wemm for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 411c2aa98e2SPeter Wemm { 41212ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(fname, h->h_field) == 0 && 4133299c2f1SGregory Neil Shapiro !bitset(H_USER, h->h_flags) && 414c2aa98e2SPeter Wemm !bitset(H_FORCE, h->h_flags)) 415c2aa98e2SPeter Wemm { 416e01d6f61SPeter Wemm if (nullheader) 417e01d6f61SPeter Wemm { 418e01d6f61SPeter Wemm /* user-supplied value was null */ 419e01d6f61SPeter Wemm return 0; 420e01d6f61SPeter Wemm } 4213299c2f1SGregory Neil Shapiro if (dropfrom) 4223299c2f1SGregory Neil Shapiro { 4233299c2f1SGregory Neil Shapiro /* make this look like the user entered it */ 4243299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 4253299c2f1SGregory Neil Shapiro return hi->hi_flags; 4263299c2f1SGregory Neil Shapiro } 427c2aa98e2SPeter Wemm h->h_value = NULL; 428c2aa98e2SPeter Wemm if (!cond) 429c2aa98e2SPeter Wemm { 430c2aa98e2SPeter Wemm /* copy conditions from default case */ 4313299c2f1SGregory Neil Shapiro memmove((char *) mopts, (char *) h->h_mflags, 432c2aa98e2SPeter Wemm sizeof mopts); 433c2aa98e2SPeter Wemm } 4343299c2f1SGregory Neil Shapiro h->h_macro = mid; 435c2aa98e2SPeter Wemm } 436c2aa98e2SPeter Wemm } 437c2aa98e2SPeter Wemm 438c2aa98e2SPeter Wemm /* create a new node */ 43912ed1c7cSGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h); 44012ed1c7cSGregory Neil Shapiro h->h_field = sm_rpool_strdup_x(e->e_rpool, fname); 44112ed1c7cSGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue); 442c2aa98e2SPeter Wemm h->h_link = NULL; 4433299c2f1SGregory Neil Shapiro memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts); 4443299c2f1SGregory Neil Shapiro h->h_macro = mid; 445c2aa98e2SPeter Wemm *hp = h; 446c2aa98e2SPeter Wemm h->h_flags = hi->hi_flags; 447d995d2baSGregory Neil Shapiro if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE)) 4483299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 449c2aa98e2SPeter Wemm 450c2aa98e2SPeter Wemm /* strip EOH flag if parsing MIME headers */ 451c2aa98e2SPeter Wemm if (headeronly) 452c2aa98e2SPeter Wemm h->h_flags &= ~H_EOH; 4533299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 454c2aa98e2SPeter Wemm h->h_flags |= H_DEFAULT; 4553299c2f1SGregory Neil Shapiro if (cond || mid != '\0') 456c2aa98e2SPeter Wemm h->h_flags |= H_CHECK; 457c2aa98e2SPeter Wemm 458c2aa98e2SPeter Wemm /* hack to see if this is a new format message */ 4593299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 4603299c2f1SGregory Neil Shapiro bitset(H_RCPT|H_FROM, h->h_flags) && 461c2aa98e2SPeter Wemm (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 462c2aa98e2SPeter Wemm strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 463c2aa98e2SPeter Wemm { 464c2aa98e2SPeter Wemm e->e_flags &= ~EF_OLDSTYLE; 465c2aa98e2SPeter Wemm } 466c2aa98e2SPeter Wemm 467c2aa98e2SPeter Wemm return h->h_flags; 468c2aa98e2SPeter Wemm } 46912ed1c7cSGregory Neil Shapiro /* 470c2aa98e2SPeter Wemm ** ADDHEADER -- add a header entry to the end of the queue. 471c2aa98e2SPeter Wemm ** 472c2aa98e2SPeter Wemm ** This bypasses the special checking of chompheader. 473c2aa98e2SPeter Wemm ** 474c2aa98e2SPeter Wemm ** Parameters: 475c2aa98e2SPeter Wemm ** field -- the name of the header field. 476c2aa98e2SPeter Wemm ** value -- the value of the field. 4773299c2f1SGregory Neil Shapiro ** flags -- flags to add to h_flags. 47812ed1c7cSGregory Neil Shapiro ** e -- envelope. 479c2aa98e2SPeter Wemm ** 480c2aa98e2SPeter Wemm ** Returns: 481c2aa98e2SPeter Wemm ** none. 482c2aa98e2SPeter Wemm ** 483c2aa98e2SPeter Wemm ** Side Effects: 484c2aa98e2SPeter Wemm ** adds the field on the list of headers for this envelope. 485c2aa98e2SPeter Wemm */ 486c2aa98e2SPeter Wemm 487c2aa98e2SPeter Wemm void 48812ed1c7cSGregory Neil Shapiro addheader(field, value, flags, e) 489c2aa98e2SPeter Wemm char *field; 490c2aa98e2SPeter Wemm char *value; 4913299c2f1SGregory Neil Shapiro int flags; 49212ed1c7cSGregory Neil Shapiro ENVELOPE *e; 493c2aa98e2SPeter Wemm { 494c2aa98e2SPeter Wemm register HDR *h; 495c2aa98e2SPeter Wemm STAB *s; 496c2aa98e2SPeter Wemm HDR **hp; 49712ed1c7cSGregory Neil Shapiro HDR **hdrlist = &e->e_header; 498c2aa98e2SPeter Wemm 499c2aa98e2SPeter Wemm /* find info struct */ 500c2aa98e2SPeter Wemm s = stab(field, ST_HEADER, ST_FIND); 501c2aa98e2SPeter Wemm 502c2aa98e2SPeter Wemm /* find current place in list -- keep back pointer? */ 503c2aa98e2SPeter Wemm for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 504c2aa98e2SPeter Wemm { 50512ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(field, h->h_field) == 0) 506c2aa98e2SPeter Wemm break; 507c2aa98e2SPeter Wemm } 508c2aa98e2SPeter Wemm 509c2aa98e2SPeter Wemm /* allocate space for new header */ 51012ed1c7cSGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h); 511c2aa98e2SPeter Wemm h->h_field = field; 51212ed1c7cSGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, value); 513c2aa98e2SPeter Wemm h->h_link = *hp; 5143299c2f1SGregory Neil Shapiro h->h_flags = flags; 515c2aa98e2SPeter Wemm if (s != NULL) 516c2aa98e2SPeter Wemm h->h_flags |= s->s_header.hi_flags; 517c2aa98e2SPeter Wemm clrbitmap(h->h_mflags); 5183299c2f1SGregory Neil Shapiro h->h_macro = '\0'; 519c2aa98e2SPeter Wemm *hp = h; 520c2aa98e2SPeter Wemm } 52112ed1c7cSGregory Neil Shapiro /* 522c2aa98e2SPeter Wemm ** HVALUE -- return value of a header. 523c2aa98e2SPeter Wemm ** 524c2aa98e2SPeter Wemm ** Only "real" fields (i.e., ones that have not been supplied 525c2aa98e2SPeter Wemm ** as a default) are used. 526c2aa98e2SPeter Wemm ** 527c2aa98e2SPeter Wemm ** Parameters: 528c2aa98e2SPeter Wemm ** field -- the field name. 529c2aa98e2SPeter Wemm ** header -- the header list. 530c2aa98e2SPeter Wemm ** 531c2aa98e2SPeter Wemm ** Returns: 532c2aa98e2SPeter Wemm ** pointer to the value part. 533c2aa98e2SPeter Wemm ** NULL if not found. 534c2aa98e2SPeter Wemm ** 535c2aa98e2SPeter Wemm ** Side Effects: 536c2aa98e2SPeter Wemm ** none. 537c2aa98e2SPeter Wemm */ 538c2aa98e2SPeter Wemm 539c2aa98e2SPeter Wemm char * 540c2aa98e2SPeter Wemm hvalue(field, header) 541c2aa98e2SPeter Wemm char *field; 542c2aa98e2SPeter Wemm HDR *header; 543c2aa98e2SPeter Wemm { 544c2aa98e2SPeter Wemm register HDR *h; 545c2aa98e2SPeter Wemm 546c2aa98e2SPeter Wemm for (h = header; h != NULL; h = h->h_link) 547c2aa98e2SPeter Wemm { 548c2aa98e2SPeter Wemm if (!bitset(H_DEFAULT, h->h_flags) && 54912ed1c7cSGregory Neil Shapiro sm_strcasecmp(h->h_field, field) == 0) 5503299c2f1SGregory Neil Shapiro return h->h_value; 551c2aa98e2SPeter Wemm } 5523299c2f1SGregory Neil Shapiro return NULL; 553c2aa98e2SPeter Wemm } 55412ed1c7cSGregory Neil Shapiro /* 555c2aa98e2SPeter Wemm ** ISHEADER -- predicate telling if argument is a header. 556c2aa98e2SPeter Wemm ** 557c2aa98e2SPeter Wemm ** A line is a header if it has a single word followed by 558c2aa98e2SPeter Wemm ** optional white space followed by a colon. 559c2aa98e2SPeter Wemm ** 560c2aa98e2SPeter Wemm ** Header fields beginning with two dashes, although technically 561c2aa98e2SPeter Wemm ** permitted by RFC822, are automatically rejected in order 562c2aa98e2SPeter Wemm ** to make MIME work out. Without this we could have a technically 563c2aa98e2SPeter Wemm ** legal header such as ``--"foo:bar"'' that would also be a legal 564c2aa98e2SPeter Wemm ** MIME separator. 565c2aa98e2SPeter Wemm ** 566c2aa98e2SPeter Wemm ** Parameters: 567c2aa98e2SPeter Wemm ** h -- string to check for possible headerness. 568c2aa98e2SPeter Wemm ** 569c2aa98e2SPeter Wemm ** Returns: 57012ed1c7cSGregory Neil Shapiro ** true if h is a header. 57112ed1c7cSGregory Neil Shapiro ** false otherwise. 572c2aa98e2SPeter Wemm ** 573c2aa98e2SPeter Wemm ** Side Effects: 574c2aa98e2SPeter Wemm ** none. 575c2aa98e2SPeter Wemm */ 576c2aa98e2SPeter Wemm 577c2aa98e2SPeter Wemm bool 578c2aa98e2SPeter Wemm isheader(h) 579c2aa98e2SPeter Wemm char *h; 580c2aa98e2SPeter Wemm { 581c2aa98e2SPeter Wemm register char *s = h; 582c2aa98e2SPeter Wemm 583c2aa98e2SPeter Wemm if (s[0] == '-' && s[1] == '-') 58412ed1c7cSGregory Neil Shapiro return false; 585c2aa98e2SPeter Wemm 586c2aa98e2SPeter Wemm while (*s > ' ' && *s != ':' && *s != '\0') 587c2aa98e2SPeter Wemm s++; 588c2aa98e2SPeter Wemm 589c2aa98e2SPeter Wemm if (h == s) 59012ed1c7cSGregory Neil Shapiro return false; 591c2aa98e2SPeter Wemm 592c2aa98e2SPeter Wemm /* following technically violates RFC822 */ 593c2aa98e2SPeter Wemm while (isascii(*s) && isspace(*s)) 594c2aa98e2SPeter Wemm s++; 595c2aa98e2SPeter Wemm 596c2aa98e2SPeter Wemm return (*s == ':'); 597c2aa98e2SPeter Wemm } 59812ed1c7cSGregory Neil Shapiro /* 599c2aa98e2SPeter Wemm ** EATHEADER -- run through the stored header and extract info. 600c2aa98e2SPeter Wemm ** 601c2aa98e2SPeter Wemm ** Parameters: 602c2aa98e2SPeter Wemm ** e -- the envelope to process. 603c2aa98e2SPeter Wemm ** full -- if set, do full processing (e.g., compute 604c2aa98e2SPeter Wemm ** message priority). This should not be set 605c2aa98e2SPeter Wemm ** when reading a queue file because some info 606c2aa98e2SPeter Wemm ** needed to compute the priority is wrong. 60712ed1c7cSGregory Neil Shapiro ** log -- call logsender()? 608c2aa98e2SPeter Wemm ** 609c2aa98e2SPeter Wemm ** Returns: 610c2aa98e2SPeter Wemm ** none. 611c2aa98e2SPeter Wemm ** 612c2aa98e2SPeter Wemm ** Side Effects: 613c2aa98e2SPeter Wemm ** Sets a bunch of global variables from information 614c2aa98e2SPeter Wemm ** in the collected header. 615c2aa98e2SPeter Wemm */ 616c2aa98e2SPeter Wemm 617c2aa98e2SPeter Wemm void 61812ed1c7cSGregory Neil Shapiro eatheader(e, full, log) 619c2aa98e2SPeter Wemm register ENVELOPE *e; 620c2aa98e2SPeter Wemm bool full; 62112ed1c7cSGregory Neil Shapiro bool log; 622c2aa98e2SPeter Wemm { 623c2aa98e2SPeter Wemm register HDR *h; 624c2aa98e2SPeter Wemm register char *p; 625c2aa98e2SPeter Wemm int hopcnt = 0; 626c2aa98e2SPeter Wemm char buf[MAXLINE]; 627c2aa98e2SPeter Wemm 628c2aa98e2SPeter Wemm /* 629c2aa98e2SPeter Wemm ** Set up macros for possible expansion in headers. 630c2aa98e2SPeter Wemm */ 631c2aa98e2SPeter Wemm 63212ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'f', e->e_sender); 63312ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', e->e_sender); 634c2aa98e2SPeter Wemm if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 63512ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt); 636c2aa98e2SPeter Wemm else 63712ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', NULL); 638c2aa98e2SPeter Wemm 639c2aa98e2SPeter Wemm /* full name of from person */ 640c2aa98e2SPeter Wemm p = hvalue("full-name", e->e_header); 641c2aa98e2SPeter Wemm if (p != NULL) 642c2aa98e2SPeter Wemm { 643c2aa98e2SPeter Wemm if (!rfc822_string(p)) 644c2aa98e2SPeter Wemm { 645c2aa98e2SPeter Wemm /* 646c2aa98e2SPeter Wemm ** Quote a full name with special characters 647c2aa98e2SPeter Wemm ** as a comment so crackaddr() doesn't destroy 648c2aa98e2SPeter Wemm ** the name portion of the address. 649c2aa98e2SPeter Wemm */ 65012ed1c7cSGregory Neil Shapiro 65112ed1c7cSGregory Neil Shapiro p = addquotes(p, e->e_rpool); 652c2aa98e2SPeter Wemm } 65312ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'x', p); 654c2aa98e2SPeter Wemm } 655c2aa98e2SPeter Wemm 656c2aa98e2SPeter Wemm if (tTd(32, 1)) 65712ed1c7cSGregory Neil Shapiro sm_dprintf("----- collected header -----\n"); 65812ed1c7cSGregory Neil Shapiro e->e_msgid = NULL; 659c2aa98e2SPeter Wemm for (h = e->e_header; h != NULL; h = h->h_link) 660c2aa98e2SPeter Wemm { 661c2aa98e2SPeter Wemm if (tTd(32, 1)) 66212ed1c7cSGregory Neil Shapiro sm_dprintf("%s: ", h->h_field); 663c2aa98e2SPeter Wemm if (h->h_value == NULL) 664c2aa98e2SPeter Wemm { 665c2aa98e2SPeter Wemm if (tTd(32, 1)) 66612ed1c7cSGregory Neil Shapiro sm_dprintf("<NULL>\n"); 667c2aa98e2SPeter Wemm continue; 668c2aa98e2SPeter Wemm } 669c2aa98e2SPeter Wemm 670c2aa98e2SPeter Wemm /* do early binding */ 6713299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) && 6723299c2f1SGregory Neil Shapiro !bitset(H_BINDLATE, h->h_flags)) 673c2aa98e2SPeter Wemm { 674c2aa98e2SPeter Wemm if (tTd(32, 1)) 675c2aa98e2SPeter Wemm { 67612ed1c7cSGregory Neil Shapiro sm_dprintf("("); 677c2aa98e2SPeter Wemm xputs(h->h_value); 67812ed1c7cSGregory Neil Shapiro sm_dprintf(") "); 679c2aa98e2SPeter Wemm } 680c2aa98e2SPeter Wemm expand(h->h_value, buf, sizeof buf, e); 681c2aa98e2SPeter Wemm if (buf[0] != '\0') 682c2aa98e2SPeter Wemm { 683c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 684f9218d3dSGregory Neil Shapiro expand(crackaddr(buf, e), 685f9218d3dSGregory Neil Shapiro buf, sizeof buf, e); 68612ed1c7cSGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, buf); 687c2aa98e2SPeter Wemm h->h_flags &= ~H_DEFAULT; 688c2aa98e2SPeter Wemm } 689c2aa98e2SPeter Wemm } 690c2aa98e2SPeter Wemm if (tTd(32, 1)) 691c2aa98e2SPeter Wemm { 692c2aa98e2SPeter Wemm xputs(h->h_value); 69312ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 694c2aa98e2SPeter Wemm } 695c2aa98e2SPeter Wemm 696c2aa98e2SPeter Wemm /* count the number of times it has been processed */ 697c2aa98e2SPeter Wemm if (bitset(H_TRACE, h->h_flags)) 698c2aa98e2SPeter Wemm hopcnt++; 699c2aa98e2SPeter Wemm 700c2aa98e2SPeter Wemm /* send to this person if we so desire */ 701c2aa98e2SPeter Wemm if (GrabTo && bitset(H_RCPT, h->h_flags) && 702c2aa98e2SPeter Wemm !bitset(H_DEFAULT, h->h_flags) && 70312ed1c7cSGregory Neil Shapiro (!bitset(EF_RESENT, e->e_flags) || 70412ed1c7cSGregory Neil Shapiro bitset(H_RESENT, h->h_flags))) 705c2aa98e2SPeter Wemm { 706c2aa98e2SPeter Wemm #if 0 707c2aa98e2SPeter Wemm int saveflags = e->e_flags; 7083299c2f1SGregory Neil Shapiro #endif /* 0 */ 709c2aa98e2SPeter Wemm 71012ed1c7cSGregory Neil Shapiro (void) sendtolist(denlstring(h->h_value, true, false), 71112ed1c7cSGregory Neil Shapiro NULLADDR, &e->e_sendqueue, 0, e); 712c2aa98e2SPeter Wemm 713c2aa98e2SPeter Wemm #if 0 714c2aa98e2SPeter Wemm /* 715c2aa98e2SPeter Wemm ** Change functionality so a fatal error on an 716c2aa98e2SPeter Wemm ** address doesn't affect the entire envelope. 717c2aa98e2SPeter Wemm */ 718c2aa98e2SPeter Wemm 719c2aa98e2SPeter Wemm /* delete fatal errors generated by this address */ 720c2aa98e2SPeter Wemm if (!bitset(EF_FATALERRS, saveflags)) 721c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 7223299c2f1SGregory Neil Shapiro #endif /* 0 */ 723c2aa98e2SPeter Wemm } 724c2aa98e2SPeter Wemm 725c2aa98e2SPeter Wemm /* save the message-id for logging */ 726c2aa98e2SPeter Wemm p = "resent-message-id"; 727c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 728c2aa98e2SPeter Wemm p += 7; 72912ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(h->h_field, p) == 0) 730c2aa98e2SPeter Wemm { 73112ed1c7cSGregory Neil Shapiro e->e_msgid = h->h_value; 73212ed1c7cSGregory Neil Shapiro while (isascii(*e->e_msgid) && isspace(*e->e_msgid)) 73312ed1c7cSGregory Neil Shapiro e->e_msgid++; 7341ae5b8d4SGregory Neil Shapiro #if _FFR_MESSAGEID_MACRO 7351ae5b8d4SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{msg_id}"), 7361ae5b8d4SGregory Neil Shapiro e->e_msgid); 7371ae5b8d4SGregory Neil Shapiro #endif /* _FFR_MESSAGEID_MACRO */ 738c2aa98e2SPeter Wemm } 739c2aa98e2SPeter Wemm } 740c2aa98e2SPeter Wemm if (tTd(32, 1)) 74112ed1c7cSGregory Neil Shapiro sm_dprintf("----------------------------\n"); 742c2aa98e2SPeter Wemm 743c2aa98e2SPeter Wemm /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 744c2aa98e2SPeter Wemm if (OpMode == MD_VERIFY) 745c2aa98e2SPeter Wemm return; 746c2aa98e2SPeter Wemm 747c2aa98e2SPeter Wemm /* store hop count */ 748c2aa98e2SPeter Wemm if (hopcnt > e->e_hopcount) 74912ed1c7cSGregory Neil Shapiro { 750c2aa98e2SPeter Wemm e->e_hopcount = hopcnt; 75112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount); 75212ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 'c', buf); 75312ed1c7cSGregory Neil Shapiro } 754c2aa98e2SPeter Wemm 755c2aa98e2SPeter Wemm /* message priority */ 756c2aa98e2SPeter Wemm p = hvalue("precedence", e->e_header); 757c2aa98e2SPeter Wemm if (p != NULL) 758c2aa98e2SPeter Wemm e->e_class = priencode(p); 759c2aa98e2SPeter Wemm if (e->e_class < 0) 760c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 761c2aa98e2SPeter Wemm else if (e->e_class > 0) 762c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 763c2aa98e2SPeter Wemm if (full) 764c2aa98e2SPeter Wemm { 765c2aa98e2SPeter Wemm e->e_msgpriority = e->e_msgsize 766c2aa98e2SPeter Wemm - e->e_class * WkClassFact 767c2aa98e2SPeter Wemm + e->e_nrcpts * WkRecipFact; 768c2aa98e2SPeter Wemm } 769c2aa98e2SPeter Wemm 770c2aa98e2SPeter Wemm /* message timeout priority */ 771c2aa98e2SPeter Wemm p = hvalue("priority", e->e_header); 772c2aa98e2SPeter Wemm if (p != NULL) 773c2aa98e2SPeter Wemm { 774c2aa98e2SPeter Wemm /* (this should be in the configuration file) */ 77512ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(p, "urgent") == 0) 776c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 77712ed1c7cSGregory Neil Shapiro else if (sm_strcasecmp(p, "normal") == 0) 778c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NORMAL; 77912ed1c7cSGregory Neil Shapiro else if (sm_strcasecmp(p, "non-urgent") == 0) 780c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 78172936242SGregory Neil Shapiro #if _FFR_QUEUERETURN_DSN 7821ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags)) 7831ae5b8d4SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 7841ae5b8d4SGregory Neil Shapiro #endif /* _FFR_QUEUERETURN_DSN */ 7851ae5b8d4SGregory Neil Shapiro } 7861ae5b8d4SGregory Neil Shapiro #if _FFR_QUEUERETURN_DSN 7871ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags)) 78872936242SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 78972936242SGregory Neil Shapiro #endif /* _FFR_QUEUERETURN_DSN */ 79072936242SGregory Neil Shapiro 791c2aa98e2SPeter Wemm /* date message originated */ 792c2aa98e2SPeter Wemm p = hvalue("posted-date", e->e_header); 793c2aa98e2SPeter Wemm if (p == NULL) 794c2aa98e2SPeter Wemm p = hvalue("date", e->e_header); 795c2aa98e2SPeter Wemm if (p != NULL) 79612ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'a', p); 797c2aa98e2SPeter Wemm 798c2aa98e2SPeter Wemm /* check to see if this is a MIME message */ 799c2aa98e2SPeter Wemm if ((e->e_bodytype != NULL && 80012ed1c7cSGregory Neil Shapiro sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 801c2aa98e2SPeter Wemm hvalue("MIME-Version", e->e_header) != NULL) 802c2aa98e2SPeter Wemm { 803c2aa98e2SPeter Wemm e->e_flags |= EF_IS_MIME; 804c2aa98e2SPeter Wemm if (HasEightBits) 805c2aa98e2SPeter Wemm e->e_bodytype = "8BITMIME"; 806c2aa98e2SPeter Wemm } 807c2aa98e2SPeter Wemm else if ((p = hvalue("Content-Type", e->e_header)) != NULL) 808c2aa98e2SPeter Wemm { 809c2aa98e2SPeter Wemm /* this may be an RFC 1049 message */ 810c2aa98e2SPeter Wemm p = strpbrk(p, ";/"); 811c2aa98e2SPeter Wemm if (p == NULL || *p == ';') 812c2aa98e2SPeter Wemm { 813c2aa98e2SPeter Wemm /* yep, it is */ 814c2aa98e2SPeter Wemm e->e_flags |= EF_DONT_MIME; 815c2aa98e2SPeter Wemm } 816c2aa98e2SPeter Wemm } 817c2aa98e2SPeter Wemm 818c2aa98e2SPeter Wemm /* 819c2aa98e2SPeter Wemm ** From person in antiquated ARPANET mode 820c2aa98e2SPeter Wemm ** required by UK Grey Book e-mail gateways (sigh) 821c2aa98e2SPeter Wemm */ 822c2aa98e2SPeter Wemm 823c2aa98e2SPeter Wemm if (OpMode == MD_ARPAFTP) 824c2aa98e2SPeter Wemm { 825c2aa98e2SPeter Wemm register struct hdrinfo *hi; 826c2aa98e2SPeter Wemm 827c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 828c2aa98e2SPeter Wemm { 829c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && 830c2aa98e2SPeter Wemm (!bitset(H_RESENT, hi->hi_flags) || 831c2aa98e2SPeter Wemm bitset(EF_RESENT, e->e_flags)) && 832c2aa98e2SPeter Wemm (p = hvalue(hi->hi_field, e->e_header)) != NULL) 833c2aa98e2SPeter Wemm break; 834c2aa98e2SPeter Wemm } 835c2aa98e2SPeter Wemm if (hi->hi_field != NULL) 836c2aa98e2SPeter Wemm { 837c2aa98e2SPeter Wemm if (tTd(32, 2)) 83812ed1c7cSGregory Neil Shapiro sm_dprintf("eatheader: setsender(*%s == %s)\n", 839c2aa98e2SPeter Wemm hi->hi_field, p); 84012ed1c7cSGregory Neil Shapiro setsender(p, e, NULL, '\0', true); 841c2aa98e2SPeter Wemm } 842c2aa98e2SPeter Wemm } 843c2aa98e2SPeter Wemm 844c2aa98e2SPeter Wemm /* 845c2aa98e2SPeter Wemm ** Log collection information. 846c2aa98e2SPeter Wemm */ 847c2aa98e2SPeter Wemm 84812ed1c7cSGregory Neil Shapiro if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 84912ed1c7cSGregory Neil Shapiro { 85012ed1c7cSGregory Neil Shapiro logsender(e, e->e_msgid); 851c2aa98e2SPeter Wemm e->e_flags &= ~EF_LOGSENDER; 852c2aa98e2SPeter Wemm } 85312ed1c7cSGregory Neil Shapiro } 85412ed1c7cSGregory Neil Shapiro /* 855c2aa98e2SPeter Wemm ** LOGSENDER -- log sender information 856c2aa98e2SPeter Wemm ** 857c2aa98e2SPeter Wemm ** Parameters: 858c2aa98e2SPeter Wemm ** e -- the envelope to log 859c2aa98e2SPeter Wemm ** msgid -- the message id 860c2aa98e2SPeter Wemm ** 861c2aa98e2SPeter Wemm ** Returns: 862c2aa98e2SPeter Wemm ** none 863c2aa98e2SPeter Wemm */ 864c2aa98e2SPeter Wemm 865c2aa98e2SPeter Wemm void 866c2aa98e2SPeter Wemm logsender(e, msgid) 867c2aa98e2SPeter Wemm register ENVELOPE *e; 868c2aa98e2SPeter Wemm char *msgid; 869c2aa98e2SPeter Wemm { 870c2aa98e2SPeter Wemm char *name; 871c2aa98e2SPeter Wemm register char *sbp; 872c2aa98e2SPeter Wemm register char *p; 873c2aa98e2SPeter Wemm int l; 874c2aa98e2SPeter Wemm char hbuf[MAXNAME + 1]; 875c2aa98e2SPeter Wemm char sbuf[MAXLINE + 1]; 876c2aa98e2SPeter Wemm char mbuf[MAXNAME + 1]; 877c2aa98e2SPeter Wemm 878c2aa98e2SPeter Wemm /* don't allow newlines in the message-id */ 87912ed1c7cSGregory Neil Shapiro /* XXX do we still need this? sm_syslog() replaces control chars */ 880c2aa98e2SPeter Wemm if (msgid != NULL) 881c2aa98e2SPeter Wemm { 882c2aa98e2SPeter Wemm l = strlen(msgid); 883c2aa98e2SPeter Wemm if (l > sizeof mbuf - 1) 884c2aa98e2SPeter Wemm l = sizeof mbuf - 1; 8853299c2f1SGregory Neil Shapiro memmove(mbuf, msgid, l); 886c2aa98e2SPeter Wemm mbuf[l] = '\0'; 887c2aa98e2SPeter Wemm p = mbuf; 888c2aa98e2SPeter Wemm while ((p = strchr(p, '\n')) != NULL) 889c2aa98e2SPeter Wemm *p++ = ' '; 890c2aa98e2SPeter Wemm } 891c2aa98e2SPeter Wemm 892c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags)) 893c2aa98e2SPeter Wemm name = "[RESPONSE]"; 894c2aa98e2SPeter Wemm else if ((name = macvalue('_', e)) != NULL) 8953299c2f1SGregory Neil Shapiro /* EMPTY */ 896c2aa98e2SPeter Wemm ; 897c2aa98e2SPeter Wemm else if (RealHostName == NULL) 898c2aa98e2SPeter Wemm name = "localhost"; 899c2aa98e2SPeter Wemm else if (RealHostName[0] == '[') 900c2aa98e2SPeter Wemm name = RealHostName; 901c2aa98e2SPeter Wemm else 902c2aa98e2SPeter Wemm { 903c2aa98e2SPeter Wemm name = hbuf; 90412ed1c7cSGregory Neil Shapiro (void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName); 905c2aa98e2SPeter Wemm if (RealHostAddr.sa.sa_family != 0) 906c2aa98e2SPeter Wemm { 907c2aa98e2SPeter Wemm p = &hbuf[strlen(hbuf)]; 90812ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 90912ed1c7cSGregory Neil Shapiro " (%.100s)", 910c2aa98e2SPeter Wemm anynet_ntoa(&RealHostAddr)); 911c2aa98e2SPeter Wemm } 912c2aa98e2SPeter Wemm } 913c2aa98e2SPeter Wemm 914c2aa98e2SPeter Wemm /* some versions of syslog only take 5 printf args */ 915c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256 916c2aa98e2SPeter Wemm sbp = sbuf; 91712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 9183299c2f1SGregory Neil Shapiro "from=%.200s, size=%ld, class=%d, nrcpts=%d", 919c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 9203299c2f1SGregory Neil Shapiro e->e_msgsize, e->e_class, e->e_nrcpts); 921c2aa98e2SPeter Wemm sbp += strlen(sbp); 922c2aa98e2SPeter Wemm if (msgid != NULL) 923c2aa98e2SPeter Wemm { 92412ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 92512ed1c7cSGregory Neil Shapiro ", msgid=%.100s", mbuf); 926c2aa98e2SPeter Wemm sbp += strlen(sbp); 927c2aa98e2SPeter Wemm } 928c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 929c2aa98e2SPeter Wemm { 93012ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 93112ed1c7cSGregory Neil Shapiro ", bodytype=%.20s", e->e_bodytype); 932c2aa98e2SPeter Wemm sbp += strlen(sbp); 933c2aa98e2SPeter Wemm } 934c2aa98e2SPeter Wemm p = macvalue('r', e); 935c2aa98e2SPeter Wemm if (p != NULL) 9363299c2f1SGregory Neil Shapiro { 93712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 93812ed1c7cSGregory Neil Shapiro ", proto=%.20s", p); 9393299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 9403299c2f1SGregory Neil Shapiro } 94112ed1c7cSGregory Neil Shapiro p = macvalue(macid("{daemon_name}"), e); 9423299c2f1SGregory Neil Shapiro if (p != NULL) 9433299c2f1SGregory Neil Shapiro { 94412ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 94512ed1c7cSGregory Neil Shapiro ", daemon=%.20s", p); 9463299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 9473299c2f1SGregory Neil Shapiro } 9482ef40764SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name); 949c2aa98e2SPeter Wemm 9503299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */ 951c2aa98e2SPeter Wemm 952c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 953c2aa98e2SPeter Wemm "from=%s", 954c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>" 95512ed1c7cSGregory Neil Shapiro : shortenstring(e->e_from.q_paddr, 95612ed1c7cSGregory Neil Shapiro 83)); 957c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 9583299c2f1SGregory Neil Shapiro "size=%ld, class=%ld, nrcpts=%d", 9593299c2f1SGregory Neil Shapiro e->e_msgsize, e->e_class, e->e_nrcpts); 960c2aa98e2SPeter Wemm if (msgid != NULL) 961c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 962c2aa98e2SPeter Wemm "msgid=%s", 963c2aa98e2SPeter Wemm shortenstring(mbuf, 83)); 964c2aa98e2SPeter Wemm sbp = sbuf; 965c2aa98e2SPeter Wemm *sbp = '\0'; 966c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 967c2aa98e2SPeter Wemm { 96812ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 96912ed1c7cSGregory Neil Shapiro "bodytype=%.20s, ", e->e_bodytype); 970c2aa98e2SPeter Wemm sbp += strlen(sbp); 971c2aa98e2SPeter Wemm } 972c2aa98e2SPeter Wemm p = macvalue('r', e); 973c2aa98e2SPeter Wemm if (p != NULL) 974c2aa98e2SPeter Wemm { 97512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 97612ed1c7cSGregory Neil Shapiro "proto=%.20s, ", p); 977c2aa98e2SPeter Wemm sbp += strlen(sbp); 978c2aa98e2SPeter Wemm } 979c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 9802ef40764SGregory Neil Shapiro "%.400srelay=%s", sbuf, name); 9813299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 982c2aa98e2SPeter Wemm } 98312ed1c7cSGregory Neil Shapiro /* 984c2aa98e2SPeter Wemm ** PRIENCODE -- encode external priority names into internal values. 985c2aa98e2SPeter Wemm ** 986c2aa98e2SPeter Wemm ** Parameters: 987c2aa98e2SPeter Wemm ** p -- priority in ascii. 988c2aa98e2SPeter Wemm ** 989c2aa98e2SPeter Wemm ** Returns: 990c2aa98e2SPeter Wemm ** priority as a numeric level. 991c2aa98e2SPeter Wemm ** 992c2aa98e2SPeter Wemm ** Side Effects: 993c2aa98e2SPeter Wemm ** none. 994c2aa98e2SPeter Wemm */ 995c2aa98e2SPeter Wemm 9963299c2f1SGregory Neil Shapiro static int 997c2aa98e2SPeter Wemm priencode(p) 998c2aa98e2SPeter Wemm char *p; 999c2aa98e2SPeter Wemm { 1000c2aa98e2SPeter Wemm register int i; 1001c2aa98e2SPeter Wemm 1002c2aa98e2SPeter Wemm for (i = 0; i < NumPriorities; i++) 1003c2aa98e2SPeter Wemm { 100412ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(p, Priorities[i].pri_name) == 0) 10053299c2f1SGregory Neil Shapiro return Priorities[i].pri_val; 1006c2aa98e2SPeter Wemm } 1007c2aa98e2SPeter Wemm 1008c2aa98e2SPeter Wemm /* unknown priority */ 10093299c2f1SGregory Neil Shapiro return 0; 1010c2aa98e2SPeter Wemm } 101112ed1c7cSGregory Neil Shapiro /* 1012c2aa98e2SPeter Wemm ** CRACKADDR -- parse an address and turn it into a macro 1013c2aa98e2SPeter Wemm ** 1014c2aa98e2SPeter Wemm ** This doesn't actually parse the address -- it just extracts 1015c2aa98e2SPeter Wemm ** it and replaces it with "$g". The parse is totally ad hoc 1016c2aa98e2SPeter Wemm ** and isn't even guaranteed to leave something syntactically 1017c2aa98e2SPeter Wemm ** identical to what it started with. However, it does leave 1018f9218d3dSGregory Neil Shapiro ** something semantically identical if possible, else at least 1019f9218d3dSGregory Neil Shapiro ** syntactically correct. 1020f9218d3dSGregory Neil Shapiro ** 1021f9218d3dSGregory Neil Shapiro ** For example, it changes "Real Name <real@example.com> (Comment)" 1022f9218d3dSGregory Neil Shapiro ** to "Real Name <$g> (Comment)". 1023c2aa98e2SPeter Wemm ** 1024c2aa98e2SPeter Wemm ** This algorithm has been cleaned up to handle a wider range 1025c2aa98e2SPeter Wemm ** of cases -- notably quoted and backslash escaped strings. 1026c2aa98e2SPeter Wemm ** This modification makes it substantially better at preserving 1027c2aa98e2SPeter Wemm ** the original syntax. 1028c2aa98e2SPeter Wemm ** 1029c2aa98e2SPeter Wemm ** Parameters: 1030c2aa98e2SPeter Wemm ** addr -- the address to be cracked. 1031f9218d3dSGregory Neil Shapiro ** e -- the current envelope. 1032c2aa98e2SPeter Wemm ** 1033c2aa98e2SPeter Wemm ** Returns: 1034c2aa98e2SPeter Wemm ** a pointer to the new version. 1035c2aa98e2SPeter Wemm ** 1036c2aa98e2SPeter Wemm ** Side Effects: 1037c2aa98e2SPeter Wemm ** none. 1038c2aa98e2SPeter Wemm ** 1039c2aa98e2SPeter Wemm ** Warning: 1040c2aa98e2SPeter Wemm ** The return value is saved in local storage and should 1041c2aa98e2SPeter Wemm ** be copied if it is to be reused. 1042c2aa98e2SPeter Wemm */ 1043c2aa98e2SPeter Wemm 1044f9218d3dSGregory Neil Shapiro #define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend)) 1045f9218d3dSGregory Neil Shapiro 1046f9218d3dSGregory Neil Shapiro /* 1047f9218d3dSGregory Neil Shapiro ** Append a character to bp if we have room. 1048f9218d3dSGregory Neil Shapiro ** If not, punt and return $g. 1049f9218d3dSGregory Neil Shapiro */ 1050f9218d3dSGregory Neil Shapiro 1051f9218d3dSGregory Neil Shapiro #define SM_APPEND_CHAR(c) \ 1052f9218d3dSGregory Neil Shapiro do \ 1053f9218d3dSGregory Neil Shapiro { \ 1054f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) \ 1055f9218d3dSGregory Neil Shapiro *bp++ = (c); \ 1056f9218d3dSGregory Neil Shapiro else \ 1057f9218d3dSGregory Neil Shapiro goto returng; \ 1058f9218d3dSGregory Neil Shapiro } while (0) 1059f9218d3dSGregory Neil Shapiro 1060f9218d3dSGregory Neil Shapiro #if MAXNAME < 10 1061f9218d3dSGregory Neil Shapiro ERROR MAXNAME must be at least 10 1062f9218d3dSGregory Neil Shapiro #endif /* MAXNAME < 10 */ 1063f9218d3dSGregory Neil Shapiro 1064c2aa98e2SPeter Wemm char * 1065f9218d3dSGregory Neil Shapiro crackaddr(addr, e) 1066c2aa98e2SPeter Wemm register char *addr; 1067f9218d3dSGregory Neil Shapiro ENVELOPE *e; 1068c2aa98e2SPeter Wemm { 1069c2aa98e2SPeter Wemm register char *p; 1070c2aa98e2SPeter Wemm register char c; 1071f9218d3dSGregory Neil Shapiro int cmtlev; /* comment level in input string */ 1072f9218d3dSGregory Neil Shapiro int realcmtlev; /* comment level in output string */ 1073f9218d3dSGregory Neil Shapiro int anglelev; /* angle level in input string */ 1074f9218d3dSGregory Neil Shapiro int copylev; /* 0 == in address, >0 copying */ 1075f9218d3dSGregory Neil Shapiro int bracklev; /* bracket level for IPv6 addr check */ 1076f9218d3dSGregory Neil Shapiro bool addangle; /* put closing angle in output */ 1077f9218d3dSGregory Neil Shapiro bool qmode; /* quoting in original string? */ 1078f9218d3dSGregory Neil Shapiro bool realqmode; /* quoting in output string? */ 1079f9218d3dSGregory Neil Shapiro bool putgmac = false; /* already wrote $g */ 1080f9218d3dSGregory Neil Shapiro bool quoteit = false; /* need to quote next character */ 1081f9218d3dSGregory Neil Shapiro bool gotangle = false; /* found first '<' */ 1082f9218d3dSGregory Neil Shapiro bool gotcolon = false; /* found a ':' */ 1083c2aa98e2SPeter Wemm register char *bp; 1084c2aa98e2SPeter Wemm char *buflim; 1085c2aa98e2SPeter Wemm char *bufhead; 1086c2aa98e2SPeter Wemm char *addrhead; 1087f9218d3dSGregory Neil Shapiro char *bufend; 1088c2aa98e2SPeter Wemm static char buf[MAXNAME + 1]; 1089c2aa98e2SPeter Wemm 1090c2aa98e2SPeter Wemm if (tTd(33, 1)) 109112ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr(%s)\n", addr); 1092c2aa98e2SPeter Wemm 1093c2aa98e2SPeter Wemm /* strip leading spaces */ 1094c2aa98e2SPeter Wemm while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 1095c2aa98e2SPeter Wemm addr++; 1096c2aa98e2SPeter Wemm 1097c2aa98e2SPeter Wemm /* 1098c2aa98e2SPeter Wemm ** Start by assuming we have no angle brackets. This will be 1099c2aa98e2SPeter Wemm ** adjusted later if we find them. 1100c2aa98e2SPeter Wemm */ 1101c2aa98e2SPeter Wemm 1102f9218d3dSGregory Neil Shapiro buflim = bufend = &buf[sizeof(buf) - 1]; 1103c2aa98e2SPeter Wemm bp = bufhead = buf; 1104c2aa98e2SPeter Wemm p = addrhead = addr; 1105f9218d3dSGregory Neil Shapiro copylev = anglelev = cmtlev = realcmtlev = 0; 1106c2aa98e2SPeter Wemm bracklev = 0; 1107f9218d3dSGregory Neil Shapiro qmode = realqmode = addangle = false; 1108c2aa98e2SPeter Wemm 1109c2aa98e2SPeter Wemm while ((c = *p++) != '\0') 1110c2aa98e2SPeter Wemm { 1111c2aa98e2SPeter Wemm /* 1112f9218d3dSGregory Neil Shapiro ** Try to keep legal syntax using spare buffer space 1113f9218d3dSGregory Neil Shapiro ** (maintained by buflim). 1114c2aa98e2SPeter Wemm */ 1115c2aa98e2SPeter Wemm 1116f9218d3dSGregory Neil Shapiro if (copylev > 0) 1117f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1118c2aa98e2SPeter Wemm 1119c2aa98e2SPeter Wemm /* check for backslash escapes */ 1120c2aa98e2SPeter Wemm if (c == '\\') 1121c2aa98e2SPeter Wemm { 1122c2aa98e2SPeter Wemm /* arrange to quote the address */ 1123c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 112412ed1c7cSGregory Neil Shapiro quoteit = true; 1125c2aa98e2SPeter Wemm 1126c2aa98e2SPeter Wemm if ((c = *p++) == '\0') 1127c2aa98e2SPeter Wemm { 1128c2aa98e2SPeter Wemm /* too far */ 1129c2aa98e2SPeter Wemm p--; 1130c2aa98e2SPeter Wemm goto putg; 1131c2aa98e2SPeter Wemm } 1132f9218d3dSGregory Neil Shapiro if (copylev > 0) 1133f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1134c2aa98e2SPeter Wemm goto putg; 1135c2aa98e2SPeter Wemm } 1136c2aa98e2SPeter Wemm 1137c2aa98e2SPeter Wemm /* check for quoted strings */ 1138c2aa98e2SPeter Wemm if (c == '"' && cmtlev <= 0) 1139c2aa98e2SPeter Wemm { 1140c2aa98e2SPeter Wemm qmode = !qmode; 1141f9218d3dSGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM) 1142f9218d3dSGregory Neil Shapiro { 1143f9218d3dSGregory Neil Shapiro if (realqmode) 1144f9218d3dSGregory Neil Shapiro buflim--; 1145f9218d3dSGregory Neil Shapiro else 1146f9218d3dSGregory Neil Shapiro buflim++; 1147c2aa98e2SPeter Wemm realqmode = !realqmode; 1148f9218d3dSGregory Neil Shapiro } 1149c2aa98e2SPeter Wemm continue; 1150c2aa98e2SPeter Wemm } 1151c2aa98e2SPeter Wemm if (qmode) 1152c2aa98e2SPeter Wemm goto putg; 1153c2aa98e2SPeter Wemm 1154c2aa98e2SPeter Wemm /* check for comments */ 1155c2aa98e2SPeter Wemm if (c == '(') 1156c2aa98e2SPeter Wemm { 1157c2aa98e2SPeter Wemm cmtlev++; 1158c2aa98e2SPeter Wemm 1159c2aa98e2SPeter Wemm /* allow space for closing paren */ 1160f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1161c2aa98e2SPeter Wemm { 1162c2aa98e2SPeter Wemm buflim--; 1163c2aa98e2SPeter Wemm realcmtlev++; 1164c2aa98e2SPeter Wemm if (copylev++ <= 0) 1165c2aa98e2SPeter Wemm { 1166c2aa98e2SPeter Wemm if (bp != bufhead) 1167f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' '); 1168f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1169c2aa98e2SPeter Wemm } 1170c2aa98e2SPeter Wemm } 1171c2aa98e2SPeter Wemm } 1172c2aa98e2SPeter Wemm if (cmtlev > 0) 1173c2aa98e2SPeter Wemm { 1174c2aa98e2SPeter Wemm if (c == ')') 1175c2aa98e2SPeter Wemm { 1176c2aa98e2SPeter Wemm cmtlev--; 1177c2aa98e2SPeter Wemm copylev--; 1178f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1179c2aa98e2SPeter Wemm { 1180c2aa98e2SPeter Wemm realcmtlev--; 1181c2aa98e2SPeter Wemm buflim++; 1182c2aa98e2SPeter Wemm } 1183c2aa98e2SPeter Wemm } 1184c2aa98e2SPeter Wemm continue; 1185c2aa98e2SPeter Wemm } 1186c2aa98e2SPeter Wemm else if (c == ')') 1187c2aa98e2SPeter Wemm { 1188c2aa98e2SPeter Wemm /* syntax error: unmatched ) */ 11897660b554SGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead) 1190c2aa98e2SPeter Wemm bp--; 1191c2aa98e2SPeter Wemm } 1192c2aa98e2SPeter Wemm 1193c2aa98e2SPeter Wemm /* count nesting on [ ... ] (for IPv6 domain literals) */ 1194c2aa98e2SPeter Wemm if (c == '[') 1195c2aa98e2SPeter Wemm bracklev++; 1196c2aa98e2SPeter Wemm else if (c == ']') 1197c2aa98e2SPeter Wemm bracklev--; 1198c2aa98e2SPeter Wemm 1199c2aa98e2SPeter Wemm /* check for group: list; syntax */ 1200c2aa98e2SPeter Wemm if (c == ':' && anglelev <= 0 && bracklev <= 0 && 1201c2aa98e2SPeter Wemm !gotcolon && !ColonOkInAddr) 1202c2aa98e2SPeter Wemm { 1203c2aa98e2SPeter Wemm register char *q; 1204c2aa98e2SPeter Wemm 1205c2aa98e2SPeter Wemm /* 1206c2aa98e2SPeter Wemm ** Check for DECnet phase IV ``::'' (host::user) 1207f9218d3dSGregory Neil Shapiro ** or DECnet phase V ``:.'' syntaxes. The latter 1208c2aa98e2SPeter Wemm ** covers ``user@DEC:.tay.myhost'' and 1209c2aa98e2SPeter Wemm ** ``DEC:.tay.myhost::user'' syntaxes (bletch). 1210c2aa98e2SPeter Wemm */ 1211c2aa98e2SPeter Wemm 1212c2aa98e2SPeter Wemm if (*p == ':' || *p == '.') 1213c2aa98e2SPeter Wemm { 1214c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 121512ed1c7cSGregory Neil Shapiro quoteit = true; 1216f9218d3dSGregory Neil Shapiro if (copylev > 0) 1217c2aa98e2SPeter Wemm { 1218f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1219f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p); 1220c2aa98e2SPeter Wemm } 1221c2aa98e2SPeter Wemm p++; 1222c2aa98e2SPeter Wemm goto putg; 1223c2aa98e2SPeter Wemm } 1224c2aa98e2SPeter Wemm 122512ed1c7cSGregory Neil Shapiro gotcolon = true; 1226c2aa98e2SPeter Wemm 1227c2aa98e2SPeter Wemm bp = bufhead; 1228c2aa98e2SPeter Wemm if (quoteit) 1229c2aa98e2SPeter Wemm { 1230f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1231c2aa98e2SPeter Wemm 1232c2aa98e2SPeter Wemm /* back up over the ':' and any spaces */ 1233c2aa98e2SPeter Wemm --p; 1234f9218d3dSGregory Neil Shapiro while (p > addr && 1235f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p)) 1236c2aa98e2SPeter Wemm continue; 1237c2aa98e2SPeter Wemm p++; 1238c2aa98e2SPeter Wemm } 1239c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1240c2aa98e2SPeter Wemm { 1241c2aa98e2SPeter Wemm c = *q++; 1242c2aa98e2SPeter Wemm if (quoteit && c == '"') 1243f9218d3dSGregory Neil Shapiro { 1244f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\'); 1245f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1246c2aa98e2SPeter Wemm } 1247f9218d3dSGregory Neil Shapiro else 1248f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1249c2aa98e2SPeter Wemm } 1250c2aa98e2SPeter Wemm if (quoteit) 1251c2aa98e2SPeter Wemm { 1252c2aa98e2SPeter Wemm if (bp == &bufhead[1]) 1253c2aa98e2SPeter Wemm bp--; 1254c2aa98e2SPeter Wemm else 1255f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1256c2aa98e2SPeter Wemm while ((c = *p++) != ':') 1257f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1258f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1259c2aa98e2SPeter Wemm } 1260c2aa98e2SPeter Wemm 1261c2aa98e2SPeter Wemm /* any trailing white space is part of group: */ 1262f9218d3dSGregory Neil Shapiro while (isascii(*p) && isspace(*p)) 1263f9218d3dSGregory Neil Shapiro { 1264f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p); 1265f9218d3dSGregory Neil Shapiro p++; 1266f9218d3dSGregory Neil Shapiro } 1267c2aa98e2SPeter Wemm copylev = 0; 126812ed1c7cSGregory Neil Shapiro putgmac = quoteit = false; 1269c2aa98e2SPeter Wemm bufhead = bp; 1270c2aa98e2SPeter Wemm addrhead = p; 1271c2aa98e2SPeter Wemm continue; 1272c2aa98e2SPeter Wemm } 1273c2aa98e2SPeter Wemm 1274c2aa98e2SPeter Wemm if (c == ';' && copylev <= 0 && !ColonOkInAddr) 1275f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1276c2aa98e2SPeter Wemm 1277c2aa98e2SPeter Wemm /* check for characters that may have to be quoted */ 1278c2aa98e2SPeter Wemm if (strchr(MustQuoteChars, c) != NULL) 1279c2aa98e2SPeter Wemm { 1280c2aa98e2SPeter Wemm /* 1281c2aa98e2SPeter Wemm ** If these occur as the phrase part of a <> 1282c2aa98e2SPeter Wemm ** construct, but are not inside of () or already 1283c2aa98e2SPeter Wemm ** quoted, they will have to be quoted. Note that 1284c2aa98e2SPeter Wemm ** now (but don't actually do the quoting). 1285c2aa98e2SPeter Wemm */ 1286c2aa98e2SPeter Wemm 1287c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 128812ed1c7cSGregory Neil Shapiro quoteit = true; 1289c2aa98e2SPeter Wemm } 1290c2aa98e2SPeter Wemm 1291c2aa98e2SPeter Wemm /* check for angle brackets */ 1292c2aa98e2SPeter Wemm if (c == '<') 1293c2aa98e2SPeter Wemm { 1294c2aa98e2SPeter Wemm register char *q; 1295c2aa98e2SPeter Wemm 1296c2aa98e2SPeter Wemm /* assume first of two angles is bogus */ 1297c2aa98e2SPeter Wemm if (gotangle) 129812ed1c7cSGregory Neil Shapiro quoteit = true; 129912ed1c7cSGregory Neil Shapiro gotangle = true; 1300c2aa98e2SPeter Wemm 1301c2aa98e2SPeter Wemm /* oops -- have to change our mind */ 1302c2aa98e2SPeter Wemm anglelev = 1; 1303f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1304f9218d3dSGregory Neil Shapiro { 1305f9218d3dSGregory Neil Shapiro if (!addangle) 1306f9218d3dSGregory Neil Shapiro buflim--; 1307f9218d3dSGregory Neil Shapiro addangle = true; 1308f9218d3dSGregory Neil Shapiro } 1309c2aa98e2SPeter Wemm 1310c2aa98e2SPeter Wemm bp = bufhead; 1311c2aa98e2SPeter Wemm if (quoteit) 1312c2aa98e2SPeter Wemm { 1313f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1314c2aa98e2SPeter Wemm 1315c2aa98e2SPeter Wemm /* back up over the '<' and any spaces */ 1316c2aa98e2SPeter Wemm --p; 1317f9218d3dSGregory Neil Shapiro while (p > addr && 1318f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p)) 1319c2aa98e2SPeter Wemm continue; 1320c2aa98e2SPeter Wemm p++; 1321c2aa98e2SPeter Wemm } 1322c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1323c2aa98e2SPeter Wemm { 1324c2aa98e2SPeter Wemm c = *q++; 1325c2aa98e2SPeter Wemm if (quoteit && c == '"') 1326f9218d3dSGregory Neil Shapiro { 1327f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\'); 1328f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1329c2aa98e2SPeter Wemm } 1330f9218d3dSGregory Neil Shapiro else 1331f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1332c2aa98e2SPeter Wemm } 1333c2aa98e2SPeter Wemm if (quoteit) 1334c2aa98e2SPeter Wemm { 1335c2aa98e2SPeter Wemm if (bp == &buf[1]) 1336c2aa98e2SPeter Wemm bp--; 1337c2aa98e2SPeter Wemm else 1338f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1339c2aa98e2SPeter Wemm while ((c = *p++) != '<') 1340f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1341f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1342c2aa98e2SPeter Wemm } 1343c2aa98e2SPeter Wemm copylev = 0; 134412ed1c7cSGregory Neil Shapiro putgmac = quoteit = false; 1345c2aa98e2SPeter Wemm continue; 1346c2aa98e2SPeter Wemm } 1347c2aa98e2SPeter Wemm 1348c2aa98e2SPeter Wemm if (c == '>') 1349c2aa98e2SPeter Wemm { 1350c2aa98e2SPeter Wemm if (anglelev > 0) 1351c2aa98e2SPeter Wemm { 1352c2aa98e2SPeter Wemm anglelev--; 1353f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1354c2aa98e2SPeter Wemm { 1355f9218d3dSGregory Neil Shapiro if (addangle) 1356c2aa98e2SPeter Wemm buflim++; 1357f9218d3dSGregory Neil Shapiro addangle = false; 1358c2aa98e2SPeter Wemm } 1359c2aa98e2SPeter Wemm } 1360f9218d3dSGregory Neil Shapiro else if (SM_HAVE_ROOM) 1361c2aa98e2SPeter Wemm { 1362c2aa98e2SPeter Wemm /* syntax error: unmatched > */ 13637660b554SGregory Neil Shapiro if (copylev > 0 && bp > bufhead) 1364c2aa98e2SPeter Wemm bp--; 136512ed1c7cSGregory Neil Shapiro quoteit = true; 1366c2aa98e2SPeter Wemm continue; 1367c2aa98e2SPeter Wemm } 1368c2aa98e2SPeter Wemm if (copylev++ <= 0) 1369f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1370c2aa98e2SPeter Wemm continue; 1371c2aa98e2SPeter Wemm } 1372c2aa98e2SPeter Wemm 1373c2aa98e2SPeter Wemm /* must be a real address character */ 1374c2aa98e2SPeter Wemm putg: 1375c2aa98e2SPeter Wemm if (copylev <= 0 && !putgmac) 1376c2aa98e2SPeter Wemm { 1377f9218d3dSGregory Neil Shapiro if (bp > buf && bp[-1] == ')') 1378f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' '); 1379f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(MACROEXPAND); 1380f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('g'); 138112ed1c7cSGregory Neil Shapiro putgmac = true; 1382c2aa98e2SPeter Wemm } 1383c2aa98e2SPeter Wemm } 1384c2aa98e2SPeter Wemm 1385c2aa98e2SPeter Wemm /* repair any syntactic damage */ 1386f9218d3dSGregory Neil Shapiro if (realqmode && bp < bufend) 1387c2aa98e2SPeter Wemm *bp++ = '"'; 1388f9218d3dSGregory Neil Shapiro while (realcmtlev-- > 0 && bp < bufend) 1389c2aa98e2SPeter Wemm *bp++ = ')'; 1390f9218d3dSGregory Neil Shapiro if (addangle && bp < bufend) 1391c2aa98e2SPeter Wemm *bp++ = '>'; 1392f9218d3dSGregory Neil Shapiro *bp = '\0'; 1393f9218d3dSGregory Neil Shapiro if (bp < bufend) 1394f9218d3dSGregory Neil Shapiro goto success; 1395c2aa98e2SPeter Wemm 1396f9218d3dSGregory Neil Shapiro returng: 1397f9218d3dSGregory Neil Shapiro /* String too long, punt */ 1398f9218d3dSGregory Neil Shapiro buf[0] = '<'; 1399f9218d3dSGregory Neil Shapiro buf[1] = MACROEXPAND; 1400f9218d3dSGregory Neil Shapiro buf[2]= 'g'; 1401f9218d3dSGregory Neil Shapiro buf[3] = '>'; 1402f9218d3dSGregory Neil Shapiro buf[4]= '\0'; 1403f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 1404f9218d3dSGregory Neil Shapiro "Dropped invalid comments from header address"); 1405f9218d3dSGregory Neil Shapiro 1406f9218d3dSGregory Neil Shapiro success: 1407c2aa98e2SPeter Wemm if (tTd(33, 1)) 1408c2aa98e2SPeter Wemm { 140912ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr=>`"); 1410c2aa98e2SPeter Wemm xputs(buf); 141112ed1c7cSGregory Neil Shapiro sm_dprintf("'\n"); 1412c2aa98e2SPeter Wemm } 14133299c2f1SGregory Neil Shapiro return buf; 1414c2aa98e2SPeter Wemm } 141512ed1c7cSGregory Neil Shapiro /* 1416c2aa98e2SPeter Wemm ** PUTHEADER -- put the header part of a message from the in-core copy 1417c2aa98e2SPeter Wemm ** 1418c2aa98e2SPeter Wemm ** Parameters: 1419c2aa98e2SPeter Wemm ** mci -- the connection information. 14203299c2f1SGregory Neil Shapiro ** hdr -- the header to put. 1421c2aa98e2SPeter Wemm ** e -- envelope to use. 1422e01d6f61SPeter Wemm ** flags -- MIME conversion flags. 1423c2aa98e2SPeter Wemm ** 1424c2aa98e2SPeter Wemm ** Returns: 1425c2aa98e2SPeter Wemm ** none. 1426c2aa98e2SPeter Wemm ** 1427c2aa98e2SPeter Wemm ** Side Effects: 1428c2aa98e2SPeter Wemm ** none. 1429c2aa98e2SPeter Wemm */ 1430c2aa98e2SPeter Wemm 1431c2aa98e2SPeter Wemm void 1432e01d6f61SPeter Wemm putheader(mci, hdr, e, flags) 1433c2aa98e2SPeter Wemm register MCI *mci; 1434c2aa98e2SPeter Wemm HDR *hdr; 1435c2aa98e2SPeter Wemm register ENVELOPE *e; 1436e01d6f61SPeter Wemm int flags; 1437c2aa98e2SPeter Wemm { 1438c2aa98e2SPeter Wemm register HDR *h; 143912ed1c7cSGregory Neil Shapiro char buf[SM_MAX(MAXLINE,BUFSIZ)]; 1440c2aa98e2SPeter Wemm char obuf[MAXLINE]; 1441c2aa98e2SPeter Wemm 1442c2aa98e2SPeter Wemm if (tTd(34, 1)) 144312ed1c7cSGregory Neil Shapiro sm_dprintf("--- putheader, mailer = %s ---\n", 1444c2aa98e2SPeter Wemm mci->mci_mailer->m_name); 1445c2aa98e2SPeter Wemm 1446c2aa98e2SPeter Wemm /* 1447c2aa98e2SPeter Wemm ** If we're in MIME mode, we're not really in the header of the 1448c2aa98e2SPeter Wemm ** message, just the header of one of the parts of the body of 1449c2aa98e2SPeter Wemm ** the message. Therefore MCIF_INHEADER should not be turned on. 1450c2aa98e2SPeter Wemm */ 1451c2aa98e2SPeter Wemm 1452c2aa98e2SPeter Wemm if (!bitset(MCIF_INMIME, mci->mci_flags)) 1453c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 1454c2aa98e2SPeter Wemm 1455c2aa98e2SPeter Wemm for (h = hdr; h != NULL; h = h->h_link) 1456c2aa98e2SPeter Wemm { 1457c2aa98e2SPeter Wemm register char *p = h->h_value; 145812ed1c7cSGregory Neil Shapiro char *q; 1459c2aa98e2SPeter Wemm 1460c2aa98e2SPeter Wemm if (tTd(34, 11)) 1461c2aa98e2SPeter Wemm { 146212ed1c7cSGregory Neil Shapiro sm_dprintf(" %s: ", h->h_field); 1463c2aa98e2SPeter Wemm xputs(p); 1464c2aa98e2SPeter Wemm } 1465c2aa98e2SPeter Wemm 14663299c2f1SGregory Neil Shapiro /* Skip empty headers */ 14673299c2f1SGregory Neil Shapiro if (h->h_value == NULL) 14683299c2f1SGregory Neil Shapiro continue; 14693299c2f1SGregory Neil Shapiro 147076b7bf71SPeter Wemm /* heuristic shortening of MIME fields to avoid MUA overflows */ 147176b7bf71SPeter Wemm if (MaxMimeFieldLength > 0 && 147276b7bf71SPeter Wemm wordinclass(h->h_field, 147312ed1c7cSGregory Neil Shapiro macid("{checkMIMEFieldHeaders}"))) 147476b7bf71SPeter Wemm { 1475c46d91b7SGregory Neil Shapiro size_t len; 1476c46d91b7SGregory Neil Shapiro 1477f9218d3dSGregory Neil Shapiro len = fix_mime_header(h, e); 1478c46d91b7SGregory Neil Shapiro if (len > 0) 147976b7bf71SPeter Wemm { 148076b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1481c46d91b7SGregory Neil Shapiro "Truncated MIME %s header due to field size (length = %ld) (possible attack)", 1482c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 148376b7bf71SPeter Wemm if (tTd(34, 11)) 148412ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", 1485c46d91b7SGregory Neil Shapiro h->h_field, 1486c46d91b7SGregory Neil Shapiro (unsigned long) len); 148776b7bf71SPeter Wemm } 148876b7bf71SPeter Wemm } 148976b7bf71SPeter Wemm 149076b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 149176b7bf71SPeter Wemm wordinclass(h->h_field, 149212ed1c7cSGregory Neil Shapiro macid("{checkMIMETextHeaders}"))) 149376b7bf71SPeter Wemm { 1494c46d91b7SGregory Neil Shapiro size_t len; 1495c46d91b7SGregory Neil Shapiro 1496c46d91b7SGregory Neil Shapiro len = strlen(h->h_value); 1497c46d91b7SGregory Neil Shapiro if (len > (size_t) MaxMimeHeaderLength) 149876b7bf71SPeter Wemm { 149976b7bf71SPeter Wemm h->h_value[MaxMimeHeaderLength - 1] = '\0'; 150076b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1501c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1502c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 150376b7bf71SPeter Wemm if (tTd(34, 11)) 150412ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1505c46d91b7SGregory Neil Shapiro h->h_field, 1506c46d91b7SGregory Neil Shapiro (unsigned long) len); 150776b7bf71SPeter Wemm } 150876b7bf71SPeter Wemm } 150976b7bf71SPeter Wemm 151076b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 151176b7bf71SPeter Wemm wordinclass(h->h_field, 151212ed1c7cSGregory Neil Shapiro macid("{checkMIMEHeaders}"))) 151376b7bf71SPeter Wemm { 1514c46d91b7SGregory Neil Shapiro size_t len; 1515c46d91b7SGregory Neil Shapiro 1516c46d91b7SGregory Neil Shapiro len = strlen(h->h_value); 1517c46d91b7SGregory Neil Shapiro if (shorten_rfc822_string(h->h_value, 1518c46d91b7SGregory Neil Shapiro MaxMimeHeaderLength)) 151976b7bf71SPeter Wemm { 1520f9218d3dSGregory Neil Shapiro if (len < MaxMimeHeaderLength) 1521f9218d3dSGregory Neil Shapiro { 1522f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus header */ 1523f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 1524f9218d3dSGregory Neil Shapiro "Fixed MIME %s header (possible attack)", 1525f9218d3dSGregory Neil Shapiro h->h_field); 1526f9218d3dSGregory Neil Shapiro if (tTd(34, 11)) 1527f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header (possible attack)\n", 1528f9218d3dSGregory Neil Shapiro h->h_field); 1529f9218d3dSGregory Neil Shapiro } 1530f9218d3dSGregory Neil Shapiro else 1531f9218d3dSGregory Neil Shapiro { 1532f9218d3dSGregory Neil Shapiro /* we actually shortened header */ 153376b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1534c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1535f9218d3dSGregory Neil Shapiro h->h_field, 1536f9218d3dSGregory Neil Shapiro (unsigned long) len); 153776b7bf71SPeter Wemm if (tTd(34, 11)) 153812ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1539c46d91b7SGregory Neil Shapiro h->h_field, 1540c46d91b7SGregory Neil Shapiro (unsigned long) len); 154176b7bf71SPeter Wemm } 154276b7bf71SPeter Wemm } 1543f9218d3dSGregory Neil Shapiro } 154476b7bf71SPeter Wemm 1545e01d6f61SPeter Wemm /* 1546e01d6f61SPeter Wemm ** Suppress Content-Transfer-Encoding: if we are MIMEing 1547e01d6f61SPeter Wemm ** and we are potentially converting from 8 bit to 7 bit 1548e01d6f61SPeter Wemm ** MIME. If converting, add a new CTE header in 1549e01d6f61SPeter Wemm ** mime8to7(). 1550e01d6f61SPeter Wemm */ 155112ed1c7cSGregory Neil Shapiro 1552c2aa98e2SPeter Wemm if (bitset(H_CTE, h->h_flags) && 1553e01d6f61SPeter Wemm bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 1554e01d6f61SPeter Wemm mci->mci_flags) && 1555e01d6f61SPeter Wemm !bitset(M87F_NO8TO7, flags)) 1556c2aa98e2SPeter Wemm { 1557c2aa98e2SPeter Wemm if (tTd(34, 11)) 155812ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (content-transfer-encoding))\n"); 1559c2aa98e2SPeter Wemm continue; 1560c2aa98e2SPeter Wemm } 1561c2aa98e2SPeter Wemm 1562c2aa98e2SPeter Wemm if (bitset(MCIF_INMIME, mci->mci_flags)) 1563c2aa98e2SPeter Wemm { 1564c2aa98e2SPeter Wemm if (tTd(34, 11)) 156512ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 1566c2aa98e2SPeter Wemm put_vanilla_header(h, p, mci); 1567c2aa98e2SPeter Wemm continue; 1568c2aa98e2SPeter Wemm } 1569c2aa98e2SPeter Wemm 1570c2aa98e2SPeter Wemm if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 15713299c2f1SGregory Neil Shapiro !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && 15723299c2f1SGregory Neil Shapiro (h->h_macro == '\0' || 157312ed1c7cSGregory Neil Shapiro (q = macvalue(bitidx(h->h_macro), e)) == NULL || 157412ed1c7cSGregory Neil Shapiro *q == '\0')) 1575c2aa98e2SPeter Wemm { 1576c2aa98e2SPeter Wemm if (tTd(34, 11)) 157712ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped)\n"); 1578c2aa98e2SPeter Wemm continue; 1579c2aa98e2SPeter Wemm } 1580c2aa98e2SPeter Wemm 1581c2aa98e2SPeter Wemm /* handle Resent-... headers specially */ 1582c2aa98e2SPeter Wemm if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 1583c2aa98e2SPeter Wemm { 1584c2aa98e2SPeter Wemm if (tTd(34, 11)) 158512ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (resent))\n"); 1586c2aa98e2SPeter Wemm continue; 1587c2aa98e2SPeter Wemm } 1588c2aa98e2SPeter Wemm 1589c2aa98e2SPeter Wemm /* suppress return receipts if requested */ 1590c2aa98e2SPeter Wemm if (bitset(H_RECEIPTTO, h->h_flags) && 1591c2aa98e2SPeter Wemm (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) 1592c2aa98e2SPeter Wemm { 1593c2aa98e2SPeter Wemm if (tTd(34, 11)) 159412ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (receipt))\n"); 1595c2aa98e2SPeter Wemm continue; 1596c2aa98e2SPeter Wemm } 1597c2aa98e2SPeter Wemm 1598c2aa98e2SPeter Wemm /* macro expand value if generated internally */ 15993299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) || 16003299c2f1SGregory Neil Shapiro bitset(H_BINDLATE, h->h_flags)) 1601c2aa98e2SPeter Wemm { 1602c2aa98e2SPeter Wemm expand(p, buf, sizeof buf, e); 1603c2aa98e2SPeter Wemm p = buf; 1604c2aa98e2SPeter Wemm if (*p == '\0') 1605c2aa98e2SPeter Wemm { 1606c2aa98e2SPeter Wemm if (tTd(34, 11)) 160712ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- null value)\n"); 1608c2aa98e2SPeter Wemm continue; 1609c2aa98e2SPeter Wemm } 1610c2aa98e2SPeter Wemm } 1611c2aa98e2SPeter Wemm 1612c2aa98e2SPeter Wemm if (bitset(H_BCC, h->h_flags)) 1613c2aa98e2SPeter Wemm { 1614c2aa98e2SPeter Wemm /* Bcc: field -- either truncate or delete */ 1615c2aa98e2SPeter Wemm if (bitset(EF_DELETE_BCC, e->e_flags)) 1616c2aa98e2SPeter Wemm { 1617c2aa98e2SPeter Wemm if (tTd(34, 11)) 161812ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- bcc)\n"); 1619c2aa98e2SPeter Wemm } 1620c2aa98e2SPeter Wemm else 1621c2aa98e2SPeter Wemm { 1622c2aa98e2SPeter Wemm /* no other recipient headers: truncate value */ 162312ed1c7cSGregory Neil Shapiro (void) sm_strlcpyn(obuf, sizeof obuf, 2, 162412ed1c7cSGregory Neil Shapiro h->h_field, ":"); 1625c2aa98e2SPeter Wemm putline(obuf, mci); 1626c2aa98e2SPeter Wemm } 1627c2aa98e2SPeter Wemm continue; 1628c2aa98e2SPeter Wemm } 1629c2aa98e2SPeter Wemm 1630c2aa98e2SPeter Wemm if (tTd(34, 11)) 163112ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 1632c2aa98e2SPeter Wemm 1633c2aa98e2SPeter Wemm if (bitset(H_FROM|H_RCPT, h->h_flags)) 1634c2aa98e2SPeter Wemm { 1635c2aa98e2SPeter Wemm /* address field */ 1636c2aa98e2SPeter Wemm bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 1637c2aa98e2SPeter Wemm 1638c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 163912ed1c7cSGregory Neil Shapiro oldstyle = false; 1640c2aa98e2SPeter Wemm commaize(h, p, oldstyle, mci, e); 1641c2aa98e2SPeter Wemm } 1642c2aa98e2SPeter Wemm else 1643c2aa98e2SPeter Wemm { 1644c2aa98e2SPeter Wemm put_vanilla_header(h, p, mci); 1645c2aa98e2SPeter Wemm } 1646c2aa98e2SPeter Wemm } 1647c2aa98e2SPeter Wemm 1648c2aa98e2SPeter Wemm /* 1649c2aa98e2SPeter Wemm ** If we are converting this to a MIME message, add the 16503299c2f1SGregory Neil Shapiro ** MIME headers (but not in MIME mode!). 1651c2aa98e2SPeter Wemm */ 1652c2aa98e2SPeter Wemm 1653c2aa98e2SPeter Wemm #if MIME8TO7 1654c2aa98e2SPeter Wemm if (bitset(MM_MIME8BIT, MimeMode) && 1655c2aa98e2SPeter Wemm bitset(EF_HAS8BIT, e->e_flags) && 1656c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 1657c2aa98e2SPeter Wemm !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 16583299c2f1SGregory Neil Shapiro !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) && 16593299c2f1SGregory Neil Shapiro hvalue("MIME-Version", e->e_header) == NULL) 1660c2aa98e2SPeter Wemm { 1661c2aa98e2SPeter Wemm putline("MIME-Version: 1.0", mci); 1662c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL) 1663c2aa98e2SPeter Wemm { 166412ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof obuf, 1665c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s", 1666c2aa98e2SPeter Wemm defcharset(e)); 1667c2aa98e2SPeter Wemm putline(obuf, mci); 1668c2aa98e2SPeter Wemm } 1669c2aa98e2SPeter Wemm if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL) 1670c2aa98e2SPeter Wemm putline("Content-Transfer-Encoding: 8bit", mci); 1671c2aa98e2SPeter Wemm } 16723299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */ 1673c2aa98e2SPeter Wemm } 167412ed1c7cSGregory Neil Shapiro /* 1675c2aa98e2SPeter Wemm ** PUT_VANILLA_HEADER -- output a fairly ordinary header 1676c2aa98e2SPeter Wemm ** 1677c2aa98e2SPeter Wemm ** Parameters: 1678c2aa98e2SPeter Wemm ** h -- the structure describing this header 1679c2aa98e2SPeter Wemm ** v -- the value of this header 1680c2aa98e2SPeter Wemm ** mci -- the connection info for output 1681c2aa98e2SPeter Wemm ** 1682c2aa98e2SPeter Wemm ** Returns: 1683c2aa98e2SPeter Wemm ** none. 1684c2aa98e2SPeter Wemm */ 1685c2aa98e2SPeter Wemm 16863299c2f1SGregory Neil Shapiro static void 1687c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci) 1688c2aa98e2SPeter Wemm HDR *h; 1689c2aa98e2SPeter Wemm char *v; 1690c2aa98e2SPeter Wemm MCI *mci; 1691c2aa98e2SPeter Wemm { 1692c2aa98e2SPeter Wemm register char *nlp; 1693c2aa98e2SPeter Wemm register char *obp; 1694c2aa98e2SPeter Wemm int putflags; 1695c2aa98e2SPeter Wemm char obuf[MAXLINE]; 1696c2aa98e2SPeter Wemm 1697c2aa98e2SPeter Wemm putflags = PXLF_HEADER; 1698c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1699c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 170012ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field); 1701c2aa98e2SPeter Wemm obp = obuf + strlen(obuf); 1702c2aa98e2SPeter Wemm while ((nlp = strchr(v, '\n')) != NULL) 1703c2aa98e2SPeter Wemm { 1704c2aa98e2SPeter Wemm int l; 1705c2aa98e2SPeter Wemm 1706c2aa98e2SPeter Wemm l = nlp - v; 17077660b554SGregory Neil Shapiro 17087660b554SGregory Neil Shapiro /* 17097660b554SGregory Neil Shapiro ** XXX This is broken for SPACELEFT()==0 17107660b554SGregory Neil Shapiro ** However, SPACELEFT() is always > 0 unless MAXLINE==1. 17117660b554SGregory Neil Shapiro */ 17127660b554SGregory Neil Shapiro 17133299c2f1SGregory Neil Shapiro if (SPACELEFT(obuf, obp) - 1 < (size_t) l) 1714c2aa98e2SPeter Wemm l = SPACELEFT(obuf, obp) - 1; 1715c2aa98e2SPeter Wemm 171612ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); 1717c2aa98e2SPeter Wemm putxline(obuf, strlen(obuf), mci, putflags); 1718c2aa98e2SPeter Wemm v += l + 1; 1719c2aa98e2SPeter Wemm obp = obuf; 1720c2aa98e2SPeter Wemm if (*v != ' ' && *v != '\t') 1721c2aa98e2SPeter Wemm *obp++ = ' '; 1722c2aa98e2SPeter Wemm } 17237660b554SGregory Neil Shapiro 17247660b554SGregory Neil Shapiro /* XXX This is broken for SPACELEFT()==0 */ 172512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", 172612ed1c7cSGregory Neil Shapiro (int) (SPACELEFT(obuf, obp) - 1), v); 1727c2aa98e2SPeter Wemm putxline(obuf, strlen(obuf), mci, putflags); 1728c2aa98e2SPeter Wemm } 172912ed1c7cSGregory Neil Shapiro /* 1730c2aa98e2SPeter Wemm ** COMMAIZE -- output a header field, making a comma-translated list. 1731c2aa98e2SPeter Wemm ** 1732c2aa98e2SPeter Wemm ** Parameters: 1733c2aa98e2SPeter Wemm ** h -- the header field to output. 1734c2aa98e2SPeter Wemm ** p -- the value to put in it. 173512ed1c7cSGregory Neil Shapiro ** oldstyle -- true if this is an old style header. 1736c2aa98e2SPeter Wemm ** mci -- the connection information. 1737c2aa98e2SPeter Wemm ** e -- the envelope containing the message. 1738c2aa98e2SPeter Wemm ** 1739c2aa98e2SPeter Wemm ** Returns: 1740c2aa98e2SPeter Wemm ** none. 1741c2aa98e2SPeter Wemm ** 1742c2aa98e2SPeter Wemm ** Side Effects: 1743c2aa98e2SPeter Wemm ** outputs "p" to file "fp". 1744c2aa98e2SPeter Wemm */ 1745c2aa98e2SPeter Wemm 1746c2aa98e2SPeter Wemm void 1747c2aa98e2SPeter Wemm commaize(h, p, oldstyle, mci, e) 1748c2aa98e2SPeter Wemm register HDR *h; 1749c2aa98e2SPeter Wemm register char *p; 1750c2aa98e2SPeter Wemm bool oldstyle; 1751c2aa98e2SPeter Wemm register MCI *mci; 1752c2aa98e2SPeter Wemm register ENVELOPE *e; 1753c2aa98e2SPeter Wemm { 1754c2aa98e2SPeter Wemm register char *obp; 1755c2aa98e2SPeter Wemm int opos; 1756c2aa98e2SPeter Wemm int omax; 175712ed1c7cSGregory Neil Shapiro bool firstone = true; 1758c2aa98e2SPeter Wemm int putflags = PXLF_HEADER; 17597660b554SGregory Neil Shapiro char **res; 1760c2aa98e2SPeter Wemm char obuf[MAXLINE + 3]; 1761c2aa98e2SPeter Wemm 1762c2aa98e2SPeter Wemm /* 1763c2aa98e2SPeter Wemm ** Output the address list translated by the 1764c2aa98e2SPeter Wemm ** mailer and with commas. 1765c2aa98e2SPeter Wemm */ 1766c2aa98e2SPeter Wemm 1767c2aa98e2SPeter Wemm if (tTd(14, 2)) 176812ed1c7cSGregory Neil Shapiro sm_dprintf("commaize(%s: %s)\n", h->h_field, p); 1769c2aa98e2SPeter Wemm 1770c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1771c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 1772c2aa98e2SPeter Wemm 1773c2aa98e2SPeter Wemm obp = obuf; 177412ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", 177512ed1c7cSGregory Neil Shapiro h->h_field); 17767660b554SGregory Neil Shapiro 17777660b554SGregory Neil Shapiro /* opos = strlen(obp); */ 1778c2aa98e2SPeter Wemm opos = strlen(h->h_field) + 2; 1779c2aa98e2SPeter Wemm if (opos > 202) 1780c2aa98e2SPeter Wemm opos = 202; 1781c2aa98e2SPeter Wemm obp += opos; 1782c2aa98e2SPeter Wemm omax = mci->mci_mailer->m_linelimit - 2; 1783c2aa98e2SPeter Wemm if (omax < 0 || omax > 78) 1784c2aa98e2SPeter Wemm omax = 78; 1785c2aa98e2SPeter Wemm 1786c2aa98e2SPeter Wemm /* 1787c2aa98e2SPeter Wemm ** Run through the list of values. 1788c2aa98e2SPeter Wemm */ 1789c2aa98e2SPeter Wemm 1790c2aa98e2SPeter Wemm while (*p != '\0') 1791c2aa98e2SPeter Wemm { 1792c2aa98e2SPeter Wemm register char *name; 1793c2aa98e2SPeter Wemm register int c; 1794c2aa98e2SPeter Wemm char savechar; 1795c2aa98e2SPeter Wemm int flags; 17963299c2f1SGregory Neil Shapiro auto int status; 1797c2aa98e2SPeter Wemm 1798c2aa98e2SPeter Wemm /* 1799c2aa98e2SPeter Wemm ** Find the end of the name. New style names 1800c2aa98e2SPeter Wemm ** end with a comma, old style names end with 1801c2aa98e2SPeter Wemm ** a space character. However, spaces do not 1802c2aa98e2SPeter Wemm ** necessarily delimit an old-style name -- at 1803c2aa98e2SPeter Wemm ** signs mean keep going. 1804c2aa98e2SPeter Wemm */ 1805c2aa98e2SPeter Wemm 1806c2aa98e2SPeter Wemm /* find end of name */ 1807c2aa98e2SPeter Wemm while ((isascii(*p) && isspace(*p)) || *p == ',') 1808c2aa98e2SPeter Wemm p++; 1809c2aa98e2SPeter Wemm name = p; 18107660b554SGregory Neil Shapiro res = NULL; 1811c2aa98e2SPeter Wemm for (;;) 1812c2aa98e2SPeter Wemm { 1813c2aa98e2SPeter Wemm auto char *oldp; 1814c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 1815c2aa98e2SPeter Wemm 18167660b554SGregory Neil Shapiro res = prescan(p, oldstyle ? ' ' : ',', pvpbuf, 1817c2aa98e2SPeter Wemm sizeof pvpbuf, &oldp, NULL); 1818c2aa98e2SPeter Wemm p = oldp; 18197660b554SGregory Neil Shapiro #if _FFR_IGNORE_BOGUS_ADDR 18207660b554SGregory Neil Shapiro /* ignore addresses that can't be parsed */ 18217660b554SGregory Neil Shapiro if (res == NULL) 18227660b554SGregory Neil Shapiro { 18237660b554SGregory Neil Shapiro name = p; 18247660b554SGregory Neil Shapiro continue; 18257660b554SGregory Neil Shapiro } 18267660b554SGregory Neil Shapiro #endif /* _FFR_IGNORE_BOGUS_ADDR */ 1827c2aa98e2SPeter Wemm 1828c2aa98e2SPeter Wemm /* look to see if we have an at sign */ 1829c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 1830c2aa98e2SPeter Wemm p++; 1831c2aa98e2SPeter Wemm 1832c2aa98e2SPeter Wemm if (*p != '@') 1833c2aa98e2SPeter Wemm { 1834c2aa98e2SPeter Wemm p = oldp; 1835c2aa98e2SPeter Wemm break; 1836c2aa98e2SPeter Wemm } 183712ed1c7cSGregory Neil Shapiro ++p; 1838c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 1839c2aa98e2SPeter Wemm p++; 1840c2aa98e2SPeter Wemm } 1841c2aa98e2SPeter Wemm /* at the end of one complete name */ 1842c2aa98e2SPeter Wemm 1843c2aa98e2SPeter Wemm /* strip off trailing white space */ 1844c2aa98e2SPeter Wemm while (p >= name && 1845c2aa98e2SPeter Wemm ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 1846c2aa98e2SPeter Wemm p--; 1847c2aa98e2SPeter Wemm if (++p == name) 1848c2aa98e2SPeter Wemm continue; 18497660b554SGregory Neil Shapiro 18507660b554SGregory Neil Shapiro /* 18517660b554SGregory Neil Shapiro ** if prescan() failed go a bit backwards; this is a hack, 18527660b554SGregory Neil Shapiro ** there should be some better error recovery. 18537660b554SGregory Neil Shapiro */ 18547660b554SGregory Neil Shapiro 18557660b554SGregory Neil Shapiro if (res == NULL && p > name && 18567660b554SGregory Neil Shapiro !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 18577660b554SGregory Neil Shapiro --p; 1858c2aa98e2SPeter Wemm savechar = *p; 1859c2aa98e2SPeter Wemm *p = '\0'; 1860c2aa98e2SPeter Wemm 1861c2aa98e2SPeter Wemm /* translate the name to be relative */ 1862c2aa98e2SPeter Wemm flags = RF_HEADERADDR|RF_ADDDOMAIN; 1863c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 1864c2aa98e2SPeter Wemm flags |= RF_SENDERADDR; 1865c2aa98e2SPeter Wemm #if USERDB 1866c2aa98e2SPeter Wemm else if (e->e_from.q_mailer != NULL && 1867c2aa98e2SPeter Wemm bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 1868c2aa98e2SPeter Wemm { 1869c2aa98e2SPeter Wemm char *q; 1870c2aa98e2SPeter Wemm 187112ed1c7cSGregory Neil Shapiro q = udbsender(name, e->e_rpool); 1872c2aa98e2SPeter Wemm if (q != NULL) 1873c2aa98e2SPeter Wemm name = q; 1874c2aa98e2SPeter Wemm } 18753299c2f1SGregory Neil Shapiro #endif /* USERDB */ 18763299c2f1SGregory Neil Shapiro status = EX_OK; 18773299c2f1SGregory Neil Shapiro name = remotename(name, mci->mci_mailer, flags, &status, e); 1878c2aa98e2SPeter Wemm if (*name == '\0') 1879c2aa98e2SPeter Wemm { 1880c2aa98e2SPeter Wemm *p = savechar; 1881c2aa98e2SPeter Wemm continue; 1882c2aa98e2SPeter Wemm } 188312ed1c7cSGregory Neil Shapiro name = denlstring(name, false, true); 1884c2aa98e2SPeter Wemm 18853299c2f1SGregory Neil Shapiro /* 18863299c2f1SGregory Neil Shapiro ** record data progress so DNS timeouts 18873299c2f1SGregory Neil Shapiro ** don't cause DATA timeouts 18883299c2f1SGregory Neil Shapiro */ 18893299c2f1SGregory Neil Shapiro 189012ed1c7cSGregory Neil Shapiro DataProgress = true; 18913299c2f1SGregory Neil Shapiro 1892c2aa98e2SPeter Wemm /* output the name with nice formatting */ 1893c2aa98e2SPeter Wemm opos += strlen(name); 1894c2aa98e2SPeter Wemm if (!firstone) 1895c2aa98e2SPeter Wemm opos += 2; 1896c2aa98e2SPeter Wemm if (opos > omax && !firstone) 1897c2aa98e2SPeter Wemm { 189812ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp)); 1899c2aa98e2SPeter Wemm putxline(obuf, strlen(obuf), mci, putflags); 1900c2aa98e2SPeter Wemm obp = obuf; 19017660b554SGregory Neil Shapiro (void) sm_strlcpy(obp, " ", sizeof obuf); 1902c2aa98e2SPeter Wemm opos = strlen(obp); 1903c2aa98e2SPeter Wemm obp += opos; 1904c2aa98e2SPeter Wemm opos += strlen(name); 1905c2aa98e2SPeter Wemm } 1906c2aa98e2SPeter Wemm else if (!firstone) 1907c2aa98e2SPeter Wemm { 190812ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp)); 1909c2aa98e2SPeter Wemm obp += 2; 1910c2aa98e2SPeter Wemm } 1911c2aa98e2SPeter Wemm 1912c2aa98e2SPeter Wemm while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 1913c2aa98e2SPeter Wemm *obp++ = c; 191412ed1c7cSGregory Neil Shapiro firstone = false; 1915c2aa98e2SPeter Wemm *p = savechar; 1916c2aa98e2SPeter Wemm } 19177660b554SGregory Neil Shapiro if (obp < &obuf[sizeof obuf]) 1918c2aa98e2SPeter Wemm *obp = '\0'; 19197660b554SGregory Neil Shapiro else 19207660b554SGregory Neil Shapiro obuf[sizeof obuf - 1] = '\0'; 1921c2aa98e2SPeter Wemm putxline(obuf, strlen(obuf), mci, putflags); 1922c2aa98e2SPeter Wemm } 192312ed1c7cSGregory Neil Shapiro /* 1924c2aa98e2SPeter Wemm ** COPYHEADER -- copy header list 1925c2aa98e2SPeter Wemm ** 1926c2aa98e2SPeter Wemm ** This routine is the equivalent of newstr for header lists 1927c2aa98e2SPeter Wemm ** 1928c2aa98e2SPeter Wemm ** Parameters: 1929c2aa98e2SPeter Wemm ** header -- list of header structures to copy. 193012ed1c7cSGregory Neil Shapiro ** rpool -- resource pool, or NULL 1931c2aa98e2SPeter Wemm ** 1932c2aa98e2SPeter Wemm ** Returns: 1933c2aa98e2SPeter Wemm ** a copy of 'header'. 1934c2aa98e2SPeter Wemm ** 1935c2aa98e2SPeter Wemm ** Side Effects: 1936c2aa98e2SPeter Wemm ** none. 1937c2aa98e2SPeter Wemm */ 1938c2aa98e2SPeter Wemm 1939c2aa98e2SPeter Wemm HDR * 194012ed1c7cSGregory Neil Shapiro copyheader(header, rpool) 1941c2aa98e2SPeter Wemm register HDR *header; 194212ed1c7cSGregory Neil Shapiro SM_RPOOL_T *rpool; 1943c2aa98e2SPeter Wemm { 1944c2aa98e2SPeter Wemm register HDR *newhdr; 1945c2aa98e2SPeter Wemm HDR *ret; 1946c2aa98e2SPeter Wemm register HDR **tail = &ret; 1947c2aa98e2SPeter Wemm 1948c2aa98e2SPeter Wemm while (header != NULL) 1949c2aa98e2SPeter Wemm { 195012ed1c7cSGregory Neil Shapiro newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr); 1951c2aa98e2SPeter Wemm STRUCTCOPY(*header, *newhdr); 1952c2aa98e2SPeter Wemm *tail = newhdr; 1953c2aa98e2SPeter Wemm tail = &newhdr->h_link; 1954c2aa98e2SPeter Wemm header = header->h_link; 1955c2aa98e2SPeter Wemm } 1956c2aa98e2SPeter Wemm *tail = NULL; 1957c2aa98e2SPeter Wemm 1958c2aa98e2SPeter Wemm return ret; 1959c2aa98e2SPeter Wemm } 196012ed1c7cSGregory Neil Shapiro /* 196176b7bf71SPeter Wemm ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header 196276b7bf71SPeter Wemm ** 196376b7bf71SPeter Wemm ** Run through all of the parameters of a MIME header and 196476b7bf71SPeter Wemm ** possibly truncate and rebalance the parameter according 196576b7bf71SPeter Wemm ** to MaxMimeFieldLength. 196676b7bf71SPeter Wemm ** 196776b7bf71SPeter Wemm ** Parameters: 1968f9218d3dSGregory Neil Shapiro ** h -- the header to truncate/rebalance 1969f9218d3dSGregory Neil Shapiro ** e -- the current envelope 197076b7bf71SPeter Wemm ** 197176b7bf71SPeter Wemm ** Returns: 1972c46d91b7SGregory Neil Shapiro ** length of last offending field, 0 if all ok. 197376b7bf71SPeter Wemm ** 197476b7bf71SPeter Wemm ** Side Effects: 197576b7bf71SPeter Wemm ** string modified in place 197676b7bf71SPeter Wemm */ 197776b7bf71SPeter Wemm 1978c46d91b7SGregory Neil Shapiro static size_t 1979f9218d3dSGregory Neil Shapiro fix_mime_header(h, e) 1980f9218d3dSGregory Neil Shapiro HDR *h; 1981f9218d3dSGregory Neil Shapiro ENVELOPE *e; 198276b7bf71SPeter Wemm { 1983f9218d3dSGregory Neil Shapiro char *begin = h->h_value; 198476b7bf71SPeter Wemm char *end; 1985c46d91b7SGregory Neil Shapiro size_t len = 0; 1986c46d91b7SGregory Neil Shapiro size_t retlen = 0; 198776b7bf71SPeter Wemm 1988f9218d3dSGregory Neil Shapiro if (begin == NULL || *begin == '\0') 1989c46d91b7SGregory Neil Shapiro return 0; 199076b7bf71SPeter Wemm 199176b7bf71SPeter Wemm /* Split on each ';' */ 19927660b554SGregory Neil Shapiro /* find_character() never returns NULL */ 199376b7bf71SPeter Wemm while ((end = find_character(begin, ';')) != NULL) 199476b7bf71SPeter Wemm { 199576b7bf71SPeter Wemm char save = *end; 199676b7bf71SPeter Wemm char *bp; 199776b7bf71SPeter Wemm 199876b7bf71SPeter Wemm *end = '\0'; 199976b7bf71SPeter Wemm 2000c46d91b7SGregory Neil Shapiro len = strlen(begin); 2001c46d91b7SGregory Neil Shapiro 200276b7bf71SPeter Wemm /* Shorten individual parameter */ 200376b7bf71SPeter Wemm if (shorten_rfc822_string(begin, MaxMimeFieldLength)) 2004f9218d3dSGregory Neil Shapiro { 2005f9218d3dSGregory Neil Shapiro if (len < MaxMimeFieldLength) 2006f9218d3dSGregory Neil Shapiro { 2007f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus field */ 2008f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 2009f9218d3dSGregory Neil Shapiro "Fixed MIME %s header field (possible attack)", 2010f9218d3dSGregory Neil Shapiro h->h_field); 2011f9218d3dSGregory Neil Shapiro if (tTd(34, 11)) 2012f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header field (possible attack)\n", 2013f9218d3dSGregory Neil Shapiro h->h_field); 2014f9218d3dSGregory Neil Shapiro } 2015f9218d3dSGregory Neil Shapiro else 2016f9218d3dSGregory Neil Shapiro { 2017f9218d3dSGregory Neil Shapiro /* we actually shortened the header */ 2018c46d91b7SGregory Neil Shapiro retlen = len; 2019f9218d3dSGregory Neil Shapiro } 2020f9218d3dSGregory Neil Shapiro } 202176b7bf71SPeter Wemm 202276b7bf71SPeter Wemm /* Collapse the possibly shortened string with rest */ 202376b7bf71SPeter Wemm bp = begin + strlen(begin); 202476b7bf71SPeter Wemm if (bp != end) 202576b7bf71SPeter Wemm { 202676b7bf71SPeter Wemm char *ep = end; 202776b7bf71SPeter Wemm 202876b7bf71SPeter Wemm *end = save; 202976b7bf71SPeter Wemm end = bp; 203076b7bf71SPeter Wemm 203176b7bf71SPeter Wemm /* copy character by character due to overlap */ 203276b7bf71SPeter Wemm while (*ep != '\0') 203376b7bf71SPeter Wemm *bp++ = *ep++; 203476b7bf71SPeter Wemm *bp = '\0'; 203576b7bf71SPeter Wemm } 203676b7bf71SPeter Wemm else 203776b7bf71SPeter Wemm *end = save; 203876b7bf71SPeter Wemm if (*end == '\0') 203976b7bf71SPeter Wemm break; 204076b7bf71SPeter Wemm 204176b7bf71SPeter Wemm /* Move past ';' */ 204276b7bf71SPeter Wemm begin = end + 1; 204376b7bf71SPeter Wemm } 2044c46d91b7SGregory Neil Shapiro return retlen; 204576b7bf71SPeter Wemm } 2046