1c2aa98e2SPeter Wemm /* 2*5dd76dd0SGregory Neil Shapiro * Copyright (c) 1998-2004, 2006, 2007 Proofpoint, 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 * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 1412ed1c7cSGregory Neil Shapiro #include <sendmail.h> 15951742c4SGregory Neil Shapiro #include <sm/sendmail.h> 16c2aa98e2SPeter Wemm 17*5dd76dd0SGregory Neil Shapiro SM_RCSID("@(#)$Id: headers.c,v 8.320 2013/11/22 20:51:55 ca Exp $") 183299c2f1SGregory Neil Shapiro 19951742c4SGregory Neil Shapiro static HDR *allocheader __P((char *, char *, int, SM_RPOOL_T *, bool)); 20f9218d3dSGregory Neil Shapiro static size_t fix_mime_header __P((HDR *, ENVELOPE *)); 213299c2f1SGregory Neil Shapiro static int priencode __P((char *)); 22567a2fc9SGregory Neil Shapiro static bool put_vanilla_header __P((HDR *, char *, MCI *)); 23c2aa98e2SPeter Wemm 24c2aa98e2SPeter Wemm /* 25c2aa98e2SPeter Wemm ** SETUPHEADERS -- initialize headers in symbol table 26c2aa98e2SPeter Wemm ** 27c2aa98e2SPeter Wemm ** Parameters: 28c2aa98e2SPeter Wemm ** none 29c2aa98e2SPeter Wemm ** 30c2aa98e2SPeter Wemm ** Returns: 31c2aa98e2SPeter Wemm ** none 32c2aa98e2SPeter Wemm */ 33c2aa98e2SPeter Wemm 34c2aa98e2SPeter Wemm void 35c2aa98e2SPeter Wemm setupheaders() 36c2aa98e2SPeter Wemm { 37c2aa98e2SPeter Wemm struct hdrinfo *hi; 38c2aa98e2SPeter Wemm STAB *s; 39c2aa98e2SPeter Wemm 40c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 41c2aa98e2SPeter Wemm { 42c2aa98e2SPeter Wemm s = stab(hi->hi_field, ST_HEADER, ST_ENTER); 43c2aa98e2SPeter Wemm s->s_header.hi_flags = hi->hi_flags; 44c2aa98e2SPeter Wemm s->s_header.hi_ruleset = NULL; 45c2aa98e2SPeter Wemm } 46c2aa98e2SPeter Wemm } 47951742c4SGregory Neil Shapiro 4812ed1c7cSGregory Neil Shapiro /* 49951742c4SGregory Neil Shapiro ** DOCHOMPHEADER -- process and save a header line. 50c2aa98e2SPeter Wemm ** 51951742c4SGregory Neil Shapiro ** Called by chompheader. 52c2aa98e2SPeter Wemm ** 53c2aa98e2SPeter Wemm ** Parameters: 54c2aa98e2SPeter Wemm ** line -- header as a text line. 55d995d2baSGregory Neil Shapiro ** pflag -- flags for chompheader() (from sendmail.h) 56c2aa98e2SPeter Wemm ** hdrp -- a pointer to the place to save the header. 57c2aa98e2SPeter Wemm ** e -- the envelope including this header. 58c2aa98e2SPeter Wemm ** 59c2aa98e2SPeter Wemm ** Returns: 60c2aa98e2SPeter Wemm ** flags for this header. 61c2aa98e2SPeter Wemm ** 62c2aa98e2SPeter Wemm ** Side Effects: 63c2aa98e2SPeter Wemm ** The header is saved on the header list. 64c2aa98e2SPeter Wemm ** Contents of 'line' are destroyed. 65c2aa98e2SPeter Wemm */ 66c2aa98e2SPeter Wemm 673299c2f1SGregory Neil Shapiro static struct hdrinfo NormalHeader = { NULL, 0, NULL }; 68951742c4SGregory Neil Shapiro static unsigned long dochompheader __P((char *, int, HDR **, ENVELOPE *)); 69c2aa98e2SPeter Wemm 70951742c4SGregory Neil Shapiro static unsigned long 71951742c4SGregory Neil Shapiro dochompheader(line, pflag, hdrp, e) 72c2aa98e2SPeter Wemm char *line; 733299c2f1SGregory Neil Shapiro int pflag; 74c2aa98e2SPeter Wemm HDR **hdrp; 75951742c4SGregory Neil Shapiro ENVELOPE *e; 76c2aa98e2SPeter Wemm { 7712ed1c7cSGregory Neil Shapiro unsigned char mid = '\0'; 78c2aa98e2SPeter Wemm register char *p; 79c2aa98e2SPeter Wemm register HDR *h; 80c2aa98e2SPeter Wemm HDR **hp; 81c2aa98e2SPeter Wemm char *fname; 82c2aa98e2SPeter Wemm char *fvalue; 8312ed1c7cSGregory Neil Shapiro bool cond = false; 843299c2f1SGregory Neil Shapiro bool dropfrom; 85c2aa98e2SPeter Wemm bool headeronly; 86c2aa98e2SPeter Wemm STAB *s; 87c2aa98e2SPeter Wemm struct hdrinfo *hi; 8812ed1c7cSGregory Neil Shapiro bool nullheader = false; 893299c2f1SGregory Neil Shapiro BITMAP256 mopts; 90c2aa98e2SPeter Wemm 91c2aa98e2SPeter Wemm headeronly = hdrp != NULL; 92c2aa98e2SPeter Wemm if (!headeronly) 93c2aa98e2SPeter Wemm hdrp = &e->e_header; 94c2aa98e2SPeter Wemm 95c2aa98e2SPeter Wemm /* strip off options */ 96c2aa98e2SPeter Wemm clrbitmap(mopts); 97c2aa98e2SPeter Wemm p = line; 983299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_USER) && *p == '?') 99c2aa98e2SPeter Wemm { 1003299c2f1SGregory Neil Shapiro int c; 1013299c2f1SGregory Neil Shapiro register char *q; 102c2aa98e2SPeter Wemm 1033299c2f1SGregory Neil Shapiro q = strchr(++p, '?'); 1043299c2f1SGregory Neil Shapiro if (q == NULL) 1053299c2f1SGregory Neil Shapiro goto hse; 1063299c2f1SGregory Neil Shapiro 1073299c2f1SGregory Neil Shapiro *q = '\0'; 1083299c2f1SGregory Neil Shapiro c = *p & 0377; 1093299c2f1SGregory Neil Shapiro 1103299c2f1SGregory Neil Shapiro /* possibly macro conditional */ 1113299c2f1SGregory Neil Shapiro if (c == MACROEXPAND) 112c2aa98e2SPeter Wemm { 1133299c2f1SGregory Neil Shapiro /* catch ?$? */ 1143299c2f1SGregory Neil Shapiro if (*++p == '\0') 1153299c2f1SGregory Neil Shapiro { 1163299c2f1SGregory Neil Shapiro *q = '?'; 1173299c2f1SGregory Neil Shapiro goto hse; 1183299c2f1SGregory Neil Shapiro } 1193299c2f1SGregory Neil Shapiro 12012ed1c7cSGregory Neil Shapiro mid = (unsigned char) *p++; 1213299c2f1SGregory Neil Shapiro 1223299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1233299c2f1SGregory Neil Shapiro if (*p != '\0') 1243299c2f1SGregory Neil Shapiro { 1253299c2f1SGregory Neil Shapiro *q = '?'; 1263299c2f1SGregory Neil Shapiro goto hse; 1273299c2f1SGregory Neil Shapiro } 1283299c2f1SGregory Neil Shapiro } 1293299c2f1SGregory Neil Shapiro else if (*p == '$') 1303299c2f1SGregory Neil Shapiro { 1313299c2f1SGregory Neil Shapiro /* catch ?$? */ 1323299c2f1SGregory Neil Shapiro if (*++p == '\0') 1333299c2f1SGregory Neil Shapiro { 1343299c2f1SGregory Neil Shapiro *q = '?'; 1353299c2f1SGregory Neil Shapiro goto hse; 1363299c2f1SGregory Neil Shapiro } 1373299c2f1SGregory Neil Shapiro 13812ed1c7cSGregory Neil Shapiro mid = (unsigned char) macid(p); 1393299c2f1SGregory Neil Shapiro if (bitset(0200, mid)) 1407660b554SGregory Neil Shapiro { 1413299c2f1SGregory Neil Shapiro p += strlen(macname(mid)) + 2; 1427660b554SGregory Neil Shapiro SM_ASSERT(p <= q); 1437660b554SGregory Neil Shapiro } 1443299c2f1SGregory Neil Shapiro else 1453299c2f1SGregory Neil Shapiro p++; 1463299c2f1SGregory Neil Shapiro 1473299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1483299c2f1SGregory Neil Shapiro if (*p != '\0') 1493299c2f1SGregory Neil Shapiro { 1503299c2f1SGregory Neil Shapiro *q = '?'; 1513299c2f1SGregory Neil Shapiro goto hse; 1523299c2f1SGregory Neil Shapiro } 153c2aa98e2SPeter Wemm } 154c2aa98e2SPeter Wemm else 1553299c2f1SGregory Neil Shapiro { 1563299c2f1SGregory Neil Shapiro while (*p != '\0') 1573299c2f1SGregory Neil Shapiro { 1583299c2f1SGregory Neil Shapiro if (!isascii(*p)) 1593299c2f1SGregory Neil Shapiro { 1603299c2f1SGregory Neil Shapiro *q = '?'; 1613299c2f1SGregory Neil Shapiro goto hse; 1623299c2f1SGregory Neil Shapiro } 1633299c2f1SGregory Neil Shapiro 164c46d91b7SGregory Neil Shapiro setbitn(bitidx(*p), mopts); 16512ed1c7cSGregory Neil Shapiro cond = true; 1663299c2f1SGregory Neil Shapiro p++; 1673299c2f1SGregory Neil Shapiro } 1683299c2f1SGregory Neil Shapiro } 1693299c2f1SGregory Neil Shapiro p = q + 1; 170c2aa98e2SPeter Wemm } 171c2aa98e2SPeter Wemm 172c2aa98e2SPeter Wemm /* find canonical name */ 173c2aa98e2SPeter Wemm fname = p; 174c2aa98e2SPeter Wemm while (isascii(*p) && isgraph(*p) && *p != ':') 175c2aa98e2SPeter Wemm p++; 176c2aa98e2SPeter Wemm fvalue = p; 177c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 178c2aa98e2SPeter Wemm p++; 179c2aa98e2SPeter Wemm if (*p++ != ':' || fname == fvalue) 180c2aa98e2SPeter Wemm { 1813299c2f1SGregory Neil Shapiro hse: 1823299c2f1SGregory Neil Shapiro syserr("553 5.3.0 header syntax error, line \"%s\"", line); 183c2aa98e2SPeter Wemm return 0; 184c2aa98e2SPeter Wemm } 185c2aa98e2SPeter Wemm *fvalue = '\0'; 186e01d6f61SPeter Wemm fvalue = p; 187e01d6f61SPeter Wemm 188e01d6f61SPeter Wemm /* if the field is null, go ahead and use the default */ 189e01d6f61SPeter Wemm while (isascii(*p) && isspace(*p)) 190e01d6f61SPeter Wemm p++; 191e01d6f61SPeter Wemm if (*p == '\0') 19212ed1c7cSGregory Neil Shapiro nullheader = true; 193c2aa98e2SPeter Wemm 194c2aa98e2SPeter Wemm /* security scan: long field names are end-of-header */ 195c2aa98e2SPeter Wemm if (strlen(fname) > 100) 196c2aa98e2SPeter Wemm return H_EOH; 197c2aa98e2SPeter Wemm 198c2aa98e2SPeter Wemm /* check to see if it represents a ruleset call */ 1993299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 200c2aa98e2SPeter Wemm { 201c2aa98e2SPeter Wemm char hbuf[50]; 202c2aa98e2SPeter Wemm 203951742c4SGregory Neil Shapiro (void) expand(fvalue, hbuf, sizeof(hbuf), e); 204c2aa98e2SPeter Wemm for (p = hbuf; isascii(*p) && isspace(*p); ) 205c2aa98e2SPeter Wemm p++; 206c2aa98e2SPeter Wemm if ((*p++ & 0377) == CALLSUBR) 207c2aa98e2SPeter Wemm { 208c2aa98e2SPeter Wemm auto char *endp; 2093299c2f1SGregory Neil Shapiro bool strc; 210c2aa98e2SPeter Wemm 2113299c2f1SGregory Neil Shapiro strc = *p == '+'; /* strip comments? */ 2123299c2f1SGregory Neil Shapiro if (strc) 2133299c2f1SGregory Neil Shapiro ++p; 214c2aa98e2SPeter Wemm if (strtorwset(p, &endp, ST_ENTER) > 0) 215c2aa98e2SPeter Wemm { 216c2aa98e2SPeter Wemm *endp = '\0'; 217c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_ENTER); 21812ed1c7cSGregory Neil Shapiro if (LogLevel > 9 && 21912ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset != NULL) 22012ed1c7cSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 22112ed1c7cSGregory Neil Shapiro "Warning: redefined ruleset for header=%s, old=%s, new=%s", 22212ed1c7cSGregory Neil Shapiro fname, 22312ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset, p); 224c2aa98e2SPeter Wemm s->s_header.hi_ruleset = newstr(p); 2253299c2f1SGregory Neil Shapiro if (!strc) 2263299c2f1SGregory Neil Shapiro s->s_header.hi_flags |= H_STRIPCOMM; 227c2aa98e2SPeter Wemm } 228c2aa98e2SPeter Wemm return 0; 229c2aa98e2SPeter Wemm } 230c2aa98e2SPeter Wemm } 231c2aa98e2SPeter Wemm 232c2aa98e2SPeter Wemm /* see if it is a known type */ 233c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_FIND); 234c2aa98e2SPeter Wemm if (s != NULL) 235c2aa98e2SPeter Wemm hi = &s->s_header; 236c2aa98e2SPeter Wemm else 237c2aa98e2SPeter Wemm hi = &NormalHeader; 238c2aa98e2SPeter Wemm 239c2aa98e2SPeter Wemm if (tTd(31, 9)) 240c2aa98e2SPeter Wemm { 241c2aa98e2SPeter Wemm if (s == NULL) 24212ed1c7cSGregory Neil Shapiro sm_dprintf("no header flags match\n"); 243c2aa98e2SPeter Wemm else 24412ed1c7cSGregory Neil Shapiro sm_dprintf("header match, flags=%lx, ruleset=%s\n", 245c2aa98e2SPeter Wemm hi->hi_flags, 24612ed1c7cSGregory Neil Shapiro hi->hi_ruleset == NULL ? "<NULL>" 24712ed1c7cSGregory Neil Shapiro : hi->hi_ruleset); 248c2aa98e2SPeter Wemm } 249c2aa98e2SPeter Wemm 250c2aa98e2SPeter Wemm /* see if this is a resent message */ 2513299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 2523299c2f1SGregory Neil Shapiro bitset(H_RESENT, hi->hi_flags)) 253c2aa98e2SPeter Wemm e->e_flags |= EF_RESENT; 254c2aa98e2SPeter Wemm 255c2aa98e2SPeter Wemm /* if this is an Errors-To: header keep track of it now */ 2563299c2f1SGregory Neil Shapiro if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly && 257c2aa98e2SPeter Wemm bitset(H_ERRORSTO, hi->hi_flags)) 258c2aa98e2SPeter Wemm (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 259c2aa98e2SPeter Wemm 260c2aa98e2SPeter Wemm /* if this means "end of header" quit now */ 261c2aa98e2SPeter Wemm if (!headeronly && bitset(H_EOH, hi->hi_flags)) 262c2aa98e2SPeter Wemm return hi->hi_flags; 263c2aa98e2SPeter Wemm 264c2aa98e2SPeter Wemm /* 265c2aa98e2SPeter Wemm ** Horrible hack to work around problem with Lotus Notes SMTP 266c2aa98e2SPeter Wemm ** mail gateway, which generates From: headers with newlines in 267c2aa98e2SPeter Wemm ** them and the <address> on the second line. Although this is 268c2aa98e2SPeter Wemm ** legal RFC 822, many MUAs don't handle this properly and thus 269c2aa98e2SPeter Wemm ** never find the actual address. 270c2aa98e2SPeter Wemm */ 271c2aa98e2SPeter Wemm 272c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader) 273c2aa98e2SPeter Wemm { 274c2aa98e2SPeter Wemm while ((p = strchr(fvalue, '\n')) != NULL) 275c2aa98e2SPeter Wemm *p = ' '; 276c2aa98e2SPeter Wemm } 277c2aa98e2SPeter Wemm 278c2aa98e2SPeter Wemm /* 279c2aa98e2SPeter Wemm ** If there is a check ruleset, verify it against the header. 280c2aa98e2SPeter Wemm */ 281c2aa98e2SPeter Wemm 2823299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_CHECK)) 2833299c2f1SGregory Neil Shapiro { 2849d8fddc1SGregory Neil Shapiro int rscheckflags; 2853299c2f1SGregory Neil Shapiro char *rs; 2863299c2f1SGregory Neil Shapiro 2879d8fddc1SGregory Neil Shapiro rscheckflags = RSF_COUNT; 2889d8fddc1SGregory Neil Shapiro if (!bitset(hi->hi_flags, H_FROM|H_RCPT)) 2899d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_UNSTRUCTURED; 290bfb62e91SGregory Neil Shapiro 291bfb62e91SGregory Neil Shapiro /* no ruleset? look for default */ 292bfb62e91SGregory Neil Shapiro rs = hi->hi_ruleset; 2933299c2f1SGregory Neil Shapiro if (rs == NULL) 2943299c2f1SGregory Neil Shapiro { 2953299c2f1SGregory Neil Shapiro s = stab("*", ST_HEADER, ST_FIND); 2963299c2f1SGregory Neil Shapiro if (s != NULL) 2973299c2f1SGregory Neil Shapiro { 2983299c2f1SGregory Neil Shapiro rs = (&s->s_header)->hi_ruleset; 2999d8fddc1SGregory Neil Shapiro if (bitset((&s->s_header)->hi_flags, 3009d8fddc1SGregory Neil Shapiro H_STRIPCOMM)) 3019d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM; 3023299c2f1SGregory Neil Shapiro } 3033299c2f1SGregory Neil Shapiro } 3049d8fddc1SGregory Neil Shapiro else if (bitset(hi->hi_flags, H_STRIPCOMM)) 3059d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM; 3063299c2f1SGregory Neil Shapiro if (rs != NULL) 3073299c2f1SGregory Neil Shapiro { 30812ed1c7cSGregory Neil Shapiro int l, k; 3093299c2f1SGregory Neil Shapiro char qval[MAXNAME]; 3103299c2f1SGregory Neil Shapiro 3113299c2f1SGregory Neil Shapiro l = 0; 31212ed1c7cSGregory Neil Shapiro qval[l++] = '"'; 31312ed1c7cSGregory Neil Shapiro 31412ed1c7cSGregory Neil Shapiro /* - 3 to avoid problems with " at the end */ 3157660b554SGregory Neil Shapiro /* should be sizeof(qval), not MAXNAME */ 31612ed1c7cSGregory Neil Shapiro for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++) 3173299c2f1SGregory Neil Shapiro { 31812ed1c7cSGregory Neil Shapiro switch (fvalue[k]) 3193299c2f1SGregory Neil Shapiro { 32012ed1c7cSGregory Neil Shapiro /* XXX other control chars? */ 3213299c2f1SGregory Neil Shapiro case '\011': /* ht */ 3223299c2f1SGregory Neil Shapiro case '\012': /* nl */ 3233299c2f1SGregory Neil Shapiro case '\013': /* vt */ 3243299c2f1SGregory Neil Shapiro case '\014': /* np */ 3253299c2f1SGregory Neil Shapiro case '\015': /* cr */ 32612ed1c7cSGregory Neil Shapiro qval[l++] = ' '; 3273299c2f1SGregory Neil Shapiro break; 3283299c2f1SGregory Neil Shapiro case '"': 32912ed1c7cSGregory Neil Shapiro qval[l++] = '\\'; 3303299c2f1SGregory Neil Shapiro /* FALLTHROUGH */ 3313299c2f1SGregory Neil Shapiro default: 33212ed1c7cSGregory Neil Shapiro qval[l++] = fvalue[k]; 3333299c2f1SGregory Neil Shapiro break; 3343299c2f1SGregory Neil Shapiro } 3353299c2f1SGregory Neil Shapiro } 33612ed1c7cSGregory Neil Shapiro qval[l++] = '"'; 33712ed1c7cSGregory Neil Shapiro qval[l] = '\0'; 33812ed1c7cSGregory Neil Shapiro k += strlen(fvalue + k); 33912ed1c7cSGregory Neil Shapiro if (k >= MAXNAME) 3403299c2f1SGregory Neil Shapiro { 3413299c2f1SGregory Neil Shapiro if (LogLevel > 9) 3423299c2f1SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 3433299c2f1SGregory Neil Shapiro "Warning: truncated header '%s' before check with '%s' len=%d max=%d", 34412ed1c7cSGregory Neil Shapiro fname, rs, k, MAXNAME - 1); 3453299c2f1SGregory Neil Shapiro } 34612ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 34712ed1c7cSGregory Neil Shapiro macid("{currHeader}"), qval); 34812ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 34912ed1c7cSGregory Neil Shapiro macid("{hdr_name}"), fname); 35012ed1c7cSGregory Neil Shapiro 351951742c4SGregory Neil Shapiro (void) sm_snprintf(qval, sizeof(qval), "%d", k); 35212ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval); 353bfb62e91SGregory Neil Shapiro if (bitset(H_FROM, hi->hi_flags)) 35412ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 35512ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h s"); 356bfb62e91SGregory Neil Shapiro else if (bitset(H_RCPT, hi->hi_flags)) 35712ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 35812ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h r"); 35912ed1c7cSGregory Neil Shapiro else 36012ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 36112ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h"); 3629d8fddc1SGregory Neil Shapiro (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3, 363951742c4SGregory Neil Shapiro NULL, e->e_id, NULL); 3643299c2f1SGregory Neil Shapiro } 3653299c2f1SGregory Neil Shapiro } 366c2aa98e2SPeter Wemm 367c2aa98e2SPeter Wemm /* 368c2aa98e2SPeter Wemm ** Drop explicit From: if same as what we would generate. 369c2aa98e2SPeter Wemm ** This is to make MH (which doesn't always give a full name) 370c2aa98e2SPeter Wemm ** insert the full name information in all circumstances. 371c2aa98e2SPeter Wemm */ 372c2aa98e2SPeter Wemm 37312ed1c7cSGregory Neil Shapiro dropfrom = false; 374c2aa98e2SPeter Wemm p = "resent-from"; 375c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 376c2aa98e2SPeter Wemm p += 7; 3773299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 37812ed1c7cSGregory Neil Shapiro !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0) 379c2aa98e2SPeter Wemm { 380c2aa98e2SPeter Wemm if (e->e_from.q_paddr != NULL && 3813299c2f1SGregory Neil Shapiro e->e_from.q_mailer != NULL && 3823299c2f1SGregory Neil Shapiro bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && 383c2aa98e2SPeter Wemm (strcmp(fvalue, e->e_from.q_paddr) == 0 || 384c2aa98e2SPeter Wemm strcmp(fvalue, e->e_from.q_user) == 0)) 38512ed1c7cSGregory Neil Shapiro dropfrom = true; 386*5dd76dd0SGregory Neil Shapiro if (tTd(31, 2)) 387*5dd76dd0SGregory Neil Shapiro { 388*5dd76dd0SGregory Neil Shapiro sm_dprintf("comparing header from (%s) against default (%s or %s), drop=%d\n", 389*5dd76dd0SGregory Neil Shapiro fvalue, e->e_from.q_paddr, e->e_from.q_user, 390*5dd76dd0SGregory Neil Shapiro dropfrom); 391*5dd76dd0SGregory Neil Shapiro } 392c2aa98e2SPeter Wemm } 393c2aa98e2SPeter Wemm 394c2aa98e2SPeter Wemm /* delete default value for this header */ 395c2aa98e2SPeter Wemm for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 396c2aa98e2SPeter Wemm { 39712ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(fname, h->h_field) == 0 && 3983299c2f1SGregory Neil Shapiro !bitset(H_USER, h->h_flags) && 399c2aa98e2SPeter Wemm !bitset(H_FORCE, h->h_flags)) 400c2aa98e2SPeter Wemm { 401e01d6f61SPeter Wemm if (nullheader) 402e01d6f61SPeter Wemm { 403e01d6f61SPeter Wemm /* user-supplied value was null */ 404e01d6f61SPeter Wemm return 0; 405e01d6f61SPeter Wemm } 4063299c2f1SGregory Neil Shapiro if (dropfrom) 4073299c2f1SGregory Neil Shapiro { 4083299c2f1SGregory Neil Shapiro /* make this look like the user entered it */ 4093299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 410*5dd76dd0SGregory Neil Shapiro 411*5dd76dd0SGregory Neil Shapiro /* 412*5dd76dd0SGregory Neil Shapiro ** If the MH hack is selected, allow to turn 413*5dd76dd0SGregory Neil Shapiro ** it off via a mailer flag to avoid problems 414*5dd76dd0SGregory Neil Shapiro ** with setups that remove the F flag from 415*5dd76dd0SGregory Neil Shapiro ** the RCPT mailer. 416*5dd76dd0SGregory Neil Shapiro */ 417*5dd76dd0SGregory Neil Shapiro 418*5dd76dd0SGregory Neil Shapiro if (bitnset(M_NOMHHACK, 419*5dd76dd0SGregory Neil Shapiro e->e_from.q_mailer->m_flags)) 420*5dd76dd0SGregory Neil Shapiro { 421*5dd76dd0SGregory Neil Shapiro h->h_flags &= ~H_CHECK; 422*5dd76dd0SGregory Neil Shapiro } 4233299c2f1SGregory Neil Shapiro return hi->hi_flags; 4243299c2f1SGregory Neil Shapiro } 425c2aa98e2SPeter Wemm h->h_value = NULL; 426c2aa98e2SPeter Wemm if (!cond) 427c2aa98e2SPeter Wemm { 428c2aa98e2SPeter Wemm /* copy conditions from default case */ 4293299c2f1SGregory Neil Shapiro memmove((char *) mopts, (char *) h->h_mflags, 430951742c4SGregory Neil Shapiro sizeof(mopts)); 431c2aa98e2SPeter Wemm } 4323299c2f1SGregory Neil Shapiro h->h_macro = mid; 433c2aa98e2SPeter Wemm } 434c2aa98e2SPeter Wemm } 435c2aa98e2SPeter Wemm 436c2aa98e2SPeter Wemm /* create a new node */ 437951742c4SGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof(*h)); 43812ed1c7cSGregory Neil Shapiro h->h_field = sm_rpool_strdup_x(e->e_rpool, fname); 43912ed1c7cSGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue); 440c2aa98e2SPeter Wemm h->h_link = NULL; 441951742c4SGregory Neil Shapiro memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts)); 4423299c2f1SGregory Neil Shapiro h->h_macro = mid; 443c2aa98e2SPeter Wemm *hp = h; 444c2aa98e2SPeter Wemm h->h_flags = hi->hi_flags; 445d995d2baSGregory Neil Shapiro if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE)) 4463299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 447c2aa98e2SPeter Wemm 448c2aa98e2SPeter Wemm /* strip EOH flag if parsing MIME headers */ 449c2aa98e2SPeter Wemm if (headeronly) 450c2aa98e2SPeter Wemm h->h_flags &= ~H_EOH; 4513299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 452c2aa98e2SPeter Wemm h->h_flags |= H_DEFAULT; 4533299c2f1SGregory Neil Shapiro if (cond || mid != '\0') 454c2aa98e2SPeter Wemm h->h_flags |= H_CHECK; 455c2aa98e2SPeter Wemm 456c2aa98e2SPeter Wemm /* hack to see if this is a new format message */ 4573299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 4583299c2f1SGregory Neil Shapiro bitset(H_RCPT|H_FROM, h->h_flags) && 459c2aa98e2SPeter Wemm (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 460c2aa98e2SPeter Wemm strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 461c2aa98e2SPeter Wemm { 462c2aa98e2SPeter Wemm e->e_flags &= ~EF_OLDSTYLE; 463c2aa98e2SPeter Wemm } 464c2aa98e2SPeter Wemm 465c2aa98e2SPeter Wemm return h->h_flags; 466c2aa98e2SPeter Wemm } 467951742c4SGregory Neil Shapiro 468951742c4SGregory Neil Shapiro /* 469951742c4SGregory Neil Shapiro ** CHOMPHEADER -- process and save a header line. 470951742c4SGregory Neil Shapiro ** 471951742c4SGregory Neil Shapiro ** Called by collect, readcf, and readqf to deal with header lines. 472951742c4SGregory Neil Shapiro ** This is just a wrapper for dochompheader(). 473951742c4SGregory Neil Shapiro ** 474951742c4SGregory Neil Shapiro ** Parameters: 475951742c4SGregory Neil Shapiro ** line -- header as a text line. 476951742c4SGregory Neil Shapiro ** pflag -- flags for chompheader() (from sendmail.h) 477951742c4SGregory Neil Shapiro ** hdrp -- a pointer to the place to save the header. 478951742c4SGregory Neil Shapiro ** e -- the envelope including this header. 479951742c4SGregory Neil Shapiro ** 480951742c4SGregory Neil Shapiro ** Returns: 481951742c4SGregory Neil Shapiro ** flags for this header. 482951742c4SGregory Neil Shapiro ** 483951742c4SGregory Neil Shapiro ** Side Effects: 484951742c4SGregory Neil Shapiro ** The header is saved on the header list. 485951742c4SGregory Neil Shapiro ** Contents of 'line' are destroyed. 486951742c4SGregory Neil Shapiro */ 487951742c4SGregory Neil Shapiro 488951742c4SGregory Neil Shapiro 489951742c4SGregory Neil Shapiro unsigned long 490951742c4SGregory Neil Shapiro chompheader(line, pflag, hdrp, e) 491951742c4SGregory Neil Shapiro char *line; 492951742c4SGregory Neil Shapiro int pflag; 493951742c4SGregory Neil Shapiro HDR **hdrp; 494951742c4SGregory Neil Shapiro register ENVELOPE *e; 495951742c4SGregory Neil Shapiro { 496951742c4SGregory Neil Shapiro unsigned long rval; 497951742c4SGregory Neil Shapiro 498951742c4SGregory Neil Shapiro if (tTd(31, 6)) 499951742c4SGregory Neil Shapiro { 500951742c4SGregory Neil Shapiro sm_dprintf("chompheader: "); 501951742c4SGregory Neil Shapiro xputs(sm_debug_file(), line); 502951742c4SGregory Neil Shapiro sm_dprintf("\n"); 503951742c4SGregory Neil Shapiro } 504951742c4SGregory Neil Shapiro 505951742c4SGregory Neil Shapiro /* quote this if user (not config file) input */ 506951742c4SGregory Neil Shapiro if (bitset(pflag, CHHDR_USER)) 507951742c4SGregory Neil Shapiro { 508951742c4SGregory Neil Shapiro char xbuf[MAXLINE]; 509951742c4SGregory Neil Shapiro char *xbp = NULL; 510951742c4SGregory Neil Shapiro int xbufs; 511951742c4SGregory Neil Shapiro 512951742c4SGregory Neil Shapiro xbufs = sizeof(xbuf); 513951742c4SGregory Neil Shapiro xbp = quote_internal_chars(line, xbuf, &xbufs); 514951742c4SGregory Neil Shapiro if (tTd(31, 7)) 515951742c4SGregory Neil Shapiro { 516951742c4SGregory Neil Shapiro sm_dprintf("chompheader: quoted: "); 517951742c4SGregory Neil Shapiro xputs(sm_debug_file(), xbp); 518951742c4SGregory Neil Shapiro sm_dprintf("\n"); 519951742c4SGregory Neil Shapiro } 520951742c4SGregory Neil Shapiro rval = dochompheader(xbp, pflag, hdrp, e); 521951742c4SGregory Neil Shapiro if (xbp != xbuf) 522951742c4SGregory Neil Shapiro sm_free(xbp); 523951742c4SGregory Neil Shapiro } 524951742c4SGregory Neil Shapiro else 525951742c4SGregory Neil Shapiro rval = dochompheader(line, pflag, hdrp, e); 526951742c4SGregory Neil Shapiro 527951742c4SGregory Neil Shapiro return rval; 528951742c4SGregory Neil Shapiro } 529951742c4SGregory Neil Shapiro 53012ed1c7cSGregory Neil Shapiro /* 531bfb62e91SGregory Neil Shapiro ** ALLOCHEADER -- allocate a header entry 532bfb62e91SGregory Neil Shapiro ** 533bfb62e91SGregory Neil Shapiro ** Parameters: 534951742c4SGregory Neil Shapiro ** field -- the name of the header field (will not be copied). 535951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied). 536bfb62e91SGregory Neil Shapiro ** flags -- flags to add to h_flags. 537bfb62e91SGregory Neil Shapiro ** rp -- resource pool for allocations 538951742c4SGregory Neil Shapiro ** space -- add leading space? 539bfb62e91SGregory Neil Shapiro ** 540bfb62e91SGregory Neil Shapiro ** Returns: 541bfb62e91SGregory Neil Shapiro ** Pointer to a newly allocated and populated HDR. 542951742c4SGregory Neil Shapiro ** 543951742c4SGregory Neil Shapiro ** Notes: 544951742c4SGregory Neil Shapiro ** o field and value must be in internal format, i.e., 545951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars(). 546951742c4SGregory Neil Shapiro ** o maybe add more flags to decide: 547951742c4SGregory Neil Shapiro ** - what to copy (field/value) 548951742c4SGregory Neil Shapiro ** - whether to convert value to an internal format 549bfb62e91SGregory Neil Shapiro */ 550bfb62e91SGregory Neil Shapiro 551bfb62e91SGregory Neil Shapiro static HDR * 552951742c4SGregory Neil Shapiro allocheader(field, value, flags, rp, space) 553bfb62e91SGregory Neil Shapiro char *field; 554bfb62e91SGregory Neil Shapiro char *value; 555bfb62e91SGregory Neil Shapiro int flags; 556bfb62e91SGregory Neil Shapiro SM_RPOOL_T *rp; 557951742c4SGregory Neil Shapiro bool space; 558bfb62e91SGregory Neil Shapiro { 559bfb62e91SGregory Neil Shapiro HDR *h; 560bfb62e91SGregory Neil Shapiro STAB *s; 561bfb62e91SGregory Neil Shapiro 562bfb62e91SGregory Neil Shapiro /* find info struct */ 563bfb62e91SGregory Neil Shapiro s = stab(field, ST_HEADER, ST_FIND); 564bfb62e91SGregory Neil Shapiro 565bfb62e91SGregory Neil Shapiro /* allocate space for new header */ 566951742c4SGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h)); 567bfb62e91SGregory Neil Shapiro h->h_field = field; 568951742c4SGregory Neil Shapiro if (space) 569951742c4SGregory Neil Shapiro { 570951742c4SGregory Neil Shapiro size_t l; 571951742c4SGregory Neil Shapiro char *n; 572951742c4SGregory Neil Shapiro 573951742c4SGregory Neil Shapiro l = strlen(value); 574951742c4SGregory Neil Shapiro SM_ASSERT(l + 2 > l); 575951742c4SGregory Neil Shapiro n = sm_rpool_malloc_x(rp, l + 2); 576951742c4SGregory Neil Shapiro n[0] = ' '; 577951742c4SGregory Neil Shapiro n[1] = '\0'; 578951742c4SGregory Neil Shapiro sm_strlcpy(n + 1, value, l + 1); 579951742c4SGregory Neil Shapiro h->h_value = n; 580951742c4SGregory Neil Shapiro } 581951742c4SGregory Neil Shapiro else 582bfb62e91SGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(rp, value); 583bfb62e91SGregory Neil Shapiro h->h_flags = flags; 584bfb62e91SGregory Neil Shapiro if (s != NULL) 585bfb62e91SGregory Neil Shapiro h->h_flags |= s->s_header.hi_flags; 586bfb62e91SGregory Neil Shapiro clrbitmap(h->h_mflags); 587bfb62e91SGregory Neil Shapiro h->h_macro = '\0'; 588bfb62e91SGregory Neil Shapiro 589bfb62e91SGregory Neil Shapiro return h; 590bfb62e91SGregory Neil Shapiro } 591951742c4SGregory Neil Shapiro 592bfb62e91SGregory Neil Shapiro /* 593c2aa98e2SPeter Wemm ** ADDHEADER -- add a header entry to the end of the queue. 594c2aa98e2SPeter Wemm ** 595c2aa98e2SPeter Wemm ** This bypasses the special checking of chompheader. 596c2aa98e2SPeter Wemm ** 597c2aa98e2SPeter Wemm ** Parameters: 598951742c4SGregory Neil Shapiro ** field -- the name of the header field (will not be copied). 599951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied). 6003299c2f1SGregory Neil Shapiro ** flags -- flags to add to h_flags. 60112ed1c7cSGregory Neil Shapiro ** e -- envelope. 602951742c4SGregory Neil Shapiro ** space -- add leading space? 603c2aa98e2SPeter Wemm ** 604c2aa98e2SPeter Wemm ** Returns: 605c2aa98e2SPeter Wemm ** none. 606c2aa98e2SPeter Wemm ** 607c2aa98e2SPeter Wemm ** Side Effects: 608c2aa98e2SPeter Wemm ** adds the field on the list of headers for this envelope. 609951742c4SGregory Neil Shapiro ** 610951742c4SGregory Neil Shapiro ** Notes: field and value must be in internal format, i.e., 611951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars(). 612c2aa98e2SPeter Wemm */ 613c2aa98e2SPeter Wemm 614c2aa98e2SPeter Wemm void 615951742c4SGregory Neil Shapiro addheader(field, value, flags, e, space) 616c2aa98e2SPeter Wemm char *field; 617c2aa98e2SPeter Wemm char *value; 6183299c2f1SGregory Neil Shapiro int flags; 61912ed1c7cSGregory Neil Shapiro ENVELOPE *e; 620951742c4SGregory Neil Shapiro bool space; 621c2aa98e2SPeter Wemm { 622c2aa98e2SPeter Wemm register HDR *h; 623c2aa98e2SPeter Wemm HDR **hp; 62412ed1c7cSGregory Neil Shapiro HDR **hdrlist = &e->e_header; 625c2aa98e2SPeter Wemm 626c2aa98e2SPeter Wemm /* find current place in list -- keep back pointer? */ 627c2aa98e2SPeter Wemm for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 628c2aa98e2SPeter Wemm { 62912ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(field, h->h_field) == 0) 630c2aa98e2SPeter Wemm break; 631c2aa98e2SPeter Wemm } 632c2aa98e2SPeter Wemm 633c2aa98e2SPeter Wemm /* allocate space for new header */ 634951742c4SGregory Neil Shapiro h = allocheader(field, value, flags, e->e_rpool, space); 635c2aa98e2SPeter Wemm h->h_link = *hp; 636c2aa98e2SPeter Wemm *hp = h; 637c2aa98e2SPeter Wemm } 638951742c4SGregory Neil Shapiro 63912ed1c7cSGregory Neil Shapiro /* 640bfb62e91SGregory Neil Shapiro ** INSHEADER -- insert a header entry at the specified index 641bfb62e91SGregory Neil Shapiro ** This bypasses the special checking of chompheader. 642bfb62e91SGregory Neil Shapiro ** 643bfb62e91SGregory Neil Shapiro ** Parameters: 644bfb62e91SGregory Neil Shapiro ** idx -- index into the header list at which to insert 645951742c4SGregory Neil Shapiro ** field -- the name of the header field (will be copied). 646951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied). 647bfb62e91SGregory Neil Shapiro ** flags -- flags to add to h_flags. 648bfb62e91SGregory Neil Shapiro ** e -- envelope. 649951742c4SGregory Neil Shapiro ** space -- add leading space? 650bfb62e91SGregory Neil Shapiro ** 651bfb62e91SGregory Neil Shapiro ** Returns: 652bfb62e91SGregory Neil Shapiro ** none. 653bfb62e91SGregory Neil Shapiro ** 654bfb62e91SGregory Neil Shapiro ** Side Effects: 655bfb62e91SGregory Neil Shapiro ** inserts the field on the list of headers for this envelope. 656951742c4SGregory Neil Shapiro ** 657951742c4SGregory Neil Shapiro ** Notes: 658951742c4SGregory Neil Shapiro ** - field and value must be in internal format, i.e., 659951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars(). 660951742c4SGregory Neil Shapiro ** - the header list contains headers that might not be 661951742c4SGregory Neil Shapiro ** sent "out" (see putheader(): "skip"), hence there is no 662951742c4SGregory Neil Shapiro ** reliable way to insert a header at an exact position 663951742c4SGregory Neil Shapiro ** (except at the front or end). 664bfb62e91SGregory Neil Shapiro */ 665bfb62e91SGregory Neil Shapiro 666bfb62e91SGregory Neil Shapiro void 667951742c4SGregory Neil Shapiro insheader(idx, field, value, flags, e, space) 668bfb62e91SGregory Neil Shapiro int idx; 669bfb62e91SGregory Neil Shapiro char *field; 670bfb62e91SGregory Neil Shapiro char *value; 671bfb62e91SGregory Neil Shapiro int flags; 672bfb62e91SGregory Neil Shapiro ENVELOPE *e; 673951742c4SGregory Neil Shapiro bool space; 674bfb62e91SGregory Neil Shapiro { 675bfb62e91SGregory Neil Shapiro HDR *h, *srch, *last = NULL; 676bfb62e91SGregory Neil Shapiro 677bfb62e91SGregory Neil Shapiro /* allocate space for new header */ 678951742c4SGregory Neil Shapiro h = allocheader(field, value, flags, e->e_rpool, space); 679bfb62e91SGregory Neil Shapiro 680bfb62e91SGregory Neil Shapiro /* find insertion position */ 681bfb62e91SGregory Neil Shapiro for (srch = e->e_header; srch != NULL && idx > 0; 682bfb62e91SGregory Neil Shapiro srch = srch->h_link, idx--) 683bfb62e91SGregory Neil Shapiro last = srch; 684bfb62e91SGregory Neil Shapiro 685bfb62e91SGregory Neil Shapiro if (e->e_header == NULL) 686bfb62e91SGregory Neil Shapiro { 687bfb62e91SGregory Neil Shapiro e->e_header = h; 688bfb62e91SGregory Neil Shapiro h->h_link = NULL; 689bfb62e91SGregory Neil Shapiro } 690bfb62e91SGregory Neil Shapiro else if (srch == NULL) 691bfb62e91SGregory Neil Shapiro { 692bfb62e91SGregory Neil Shapiro SM_ASSERT(last != NULL); 693bfb62e91SGregory Neil Shapiro last->h_link = h; 694bfb62e91SGregory Neil Shapiro h->h_link = NULL; 695bfb62e91SGregory Neil Shapiro } 696bfb62e91SGregory Neil Shapiro else 697bfb62e91SGregory Neil Shapiro { 698bfb62e91SGregory Neil Shapiro h->h_link = srch->h_link; 699bfb62e91SGregory Neil Shapiro srch->h_link = h; 700bfb62e91SGregory Neil Shapiro } 701bfb62e91SGregory Neil Shapiro } 702951742c4SGregory Neil Shapiro 703bfb62e91SGregory Neil Shapiro /* 704c2aa98e2SPeter Wemm ** HVALUE -- return value of a header. 705c2aa98e2SPeter Wemm ** 706c2aa98e2SPeter Wemm ** Only "real" fields (i.e., ones that have not been supplied 707c2aa98e2SPeter Wemm ** as a default) are used. 708c2aa98e2SPeter Wemm ** 709c2aa98e2SPeter Wemm ** Parameters: 710c2aa98e2SPeter Wemm ** field -- the field name. 711c2aa98e2SPeter Wemm ** header -- the header list. 712c2aa98e2SPeter Wemm ** 713c2aa98e2SPeter Wemm ** Returns: 714951742c4SGregory Neil Shapiro ** pointer to the value part (internal format). 715c2aa98e2SPeter Wemm ** NULL if not found. 716c2aa98e2SPeter Wemm ** 717c2aa98e2SPeter Wemm ** Side Effects: 718c2aa98e2SPeter Wemm ** none. 719c2aa98e2SPeter Wemm */ 720c2aa98e2SPeter Wemm 721c2aa98e2SPeter Wemm char * 722c2aa98e2SPeter Wemm hvalue(field, header) 723c2aa98e2SPeter Wemm char *field; 724c2aa98e2SPeter Wemm HDR *header; 725c2aa98e2SPeter Wemm { 726c2aa98e2SPeter Wemm register HDR *h; 727c2aa98e2SPeter Wemm 728c2aa98e2SPeter Wemm for (h = header; h != NULL; h = h->h_link) 729c2aa98e2SPeter Wemm { 730c2aa98e2SPeter Wemm if (!bitset(H_DEFAULT, h->h_flags) && 73112ed1c7cSGregory Neil Shapiro sm_strcasecmp(h->h_field, field) == 0) 7329bd497b8SGregory Neil Shapiro { 7339bd497b8SGregory Neil Shapiro char *s; 7349bd497b8SGregory Neil Shapiro 7359bd497b8SGregory Neil Shapiro s = h->h_value; 7369bd497b8SGregory Neil Shapiro if (s == NULL) 7379bd497b8SGregory Neil Shapiro return NULL; 7389bd497b8SGregory Neil Shapiro while (isascii(*s) && isspace(*s)) 7399bd497b8SGregory Neil Shapiro s++; 7409bd497b8SGregory Neil Shapiro return s; 7419bd497b8SGregory Neil Shapiro } 742c2aa98e2SPeter Wemm } 7433299c2f1SGregory Neil Shapiro return NULL; 744c2aa98e2SPeter Wemm } 745951742c4SGregory Neil Shapiro 74612ed1c7cSGregory Neil Shapiro /* 747c2aa98e2SPeter Wemm ** ISHEADER -- predicate telling if argument is a header. 748c2aa98e2SPeter Wemm ** 749c2aa98e2SPeter Wemm ** A line is a header if it has a single word followed by 750c2aa98e2SPeter Wemm ** optional white space followed by a colon. 751c2aa98e2SPeter Wemm ** 752c2aa98e2SPeter Wemm ** Header fields beginning with two dashes, although technically 753c2aa98e2SPeter Wemm ** permitted by RFC822, are automatically rejected in order 754c2aa98e2SPeter Wemm ** to make MIME work out. Without this we could have a technically 755c2aa98e2SPeter Wemm ** legal header such as ``--"foo:bar"'' that would also be a legal 756c2aa98e2SPeter Wemm ** MIME separator. 757c2aa98e2SPeter Wemm ** 758c2aa98e2SPeter Wemm ** Parameters: 759c2aa98e2SPeter Wemm ** h -- string to check for possible headerness. 760c2aa98e2SPeter Wemm ** 761c2aa98e2SPeter Wemm ** Returns: 76212ed1c7cSGregory Neil Shapiro ** true if h is a header. 76312ed1c7cSGregory Neil Shapiro ** false otherwise. 764c2aa98e2SPeter Wemm ** 765c2aa98e2SPeter Wemm ** Side Effects: 766c2aa98e2SPeter Wemm ** none. 767c2aa98e2SPeter Wemm */ 768c2aa98e2SPeter Wemm 769c2aa98e2SPeter Wemm bool 770c2aa98e2SPeter Wemm isheader(h) 771c2aa98e2SPeter Wemm char *h; 772c2aa98e2SPeter Wemm { 773951742c4SGregory Neil Shapiro char *s; 774c2aa98e2SPeter Wemm 775951742c4SGregory Neil Shapiro s = h; 776c2aa98e2SPeter Wemm if (s[0] == '-' && s[1] == '-') 77712ed1c7cSGregory Neil Shapiro return false; 778c2aa98e2SPeter Wemm 779c2aa98e2SPeter Wemm while (*s > ' ' && *s != ':' && *s != '\0') 780c2aa98e2SPeter Wemm s++; 781c2aa98e2SPeter Wemm 782c2aa98e2SPeter Wemm if (h == s) 78312ed1c7cSGregory Neil Shapiro return false; 784c2aa98e2SPeter Wemm 785c2aa98e2SPeter Wemm /* following technically violates RFC822 */ 786c2aa98e2SPeter Wemm while (isascii(*s) && isspace(*s)) 787c2aa98e2SPeter Wemm s++; 788c2aa98e2SPeter Wemm 789c2aa98e2SPeter Wemm return (*s == ':'); 790c2aa98e2SPeter Wemm } 791951742c4SGregory Neil Shapiro 79212ed1c7cSGregory Neil Shapiro /* 793c2aa98e2SPeter Wemm ** EATHEADER -- run through the stored header and extract info. 794c2aa98e2SPeter Wemm ** 795c2aa98e2SPeter Wemm ** Parameters: 796c2aa98e2SPeter Wemm ** e -- the envelope to process. 797c2aa98e2SPeter Wemm ** full -- if set, do full processing (e.g., compute 798c2aa98e2SPeter Wemm ** message priority). This should not be set 799c2aa98e2SPeter Wemm ** when reading a queue file because some info 800c2aa98e2SPeter Wemm ** needed to compute the priority is wrong. 80112ed1c7cSGregory Neil Shapiro ** log -- call logsender()? 802c2aa98e2SPeter Wemm ** 803c2aa98e2SPeter Wemm ** Returns: 804c2aa98e2SPeter Wemm ** none. 805c2aa98e2SPeter Wemm ** 806c2aa98e2SPeter Wemm ** Side Effects: 807c2aa98e2SPeter Wemm ** Sets a bunch of global variables from information 808c2aa98e2SPeter Wemm ** in the collected header. 809c2aa98e2SPeter Wemm */ 810c2aa98e2SPeter Wemm 811c2aa98e2SPeter Wemm void 81212ed1c7cSGregory Neil Shapiro eatheader(e, full, log) 813c2aa98e2SPeter Wemm register ENVELOPE *e; 814c2aa98e2SPeter Wemm bool full; 81512ed1c7cSGregory Neil Shapiro bool log; 816c2aa98e2SPeter Wemm { 817c2aa98e2SPeter Wemm register HDR *h; 818c2aa98e2SPeter Wemm register char *p; 819c2aa98e2SPeter Wemm int hopcnt = 0; 820c2aa98e2SPeter Wemm char buf[MAXLINE]; 821c2aa98e2SPeter Wemm 822c2aa98e2SPeter Wemm /* 823c2aa98e2SPeter Wemm ** Set up macros for possible expansion in headers. 824c2aa98e2SPeter Wemm */ 825c2aa98e2SPeter Wemm 82612ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'f', e->e_sender); 82712ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', e->e_sender); 828c2aa98e2SPeter Wemm if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 82912ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt); 830c2aa98e2SPeter Wemm else 83112ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', NULL); 832c2aa98e2SPeter Wemm 833c2aa98e2SPeter Wemm /* full name of from person */ 834c2aa98e2SPeter Wemm p = hvalue("full-name", e->e_header); 835c2aa98e2SPeter Wemm if (p != NULL) 836c2aa98e2SPeter Wemm { 837c2aa98e2SPeter Wemm if (!rfc822_string(p)) 838c2aa98e2SPeter Wemm { 839c2aa98e2SPeter Wemm /* 840c2aa98e2SPeter Wemm ** Quote a full name with special characters 841c2aa98e2SPeter Wemm ** as a comment so crackaddr() doesn't destroy 842c2aa98e2SPeter Wemm ** the name portion of the address. 843c2aa98e2SPeter Wemm */ 84412ed1c7cSGregory Neil Shapiro 84512ed1c7cSGregory Neil Shapiro p = addquotes(p, e->e_rpool); 846c2aa98e2SPeter Wemm } 84712ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'x', p); 848c2aa98e2SPeter Wemm } 849c2aa98e2SPeter Wemm 850c2aa98e2SPeter Wemm if (tTd(32, 1)) 85112ed1c7cSGregory Neil Shapiro sm_dprintf("----- collected header -----\n"); 85212ed1c7cSGregory Neil Shapiro e->e_msgid = NULL; 853c2aa98e2SPeter Wemm for (h = e->e_header; h != NULL; h = h->h_link) 854c2aa98e2SPeter Wemm { 855c2aa98e2SPeter Wemm if (tTd(32, 1)) 85612ed1c7cSGregory Neil Shapiro sm_dprintf("%s:", h->h_field); 857c2aa98e2SPeter Wemm if (h->h_value == NULL) 858c2aa98e2SPeter Wemm { 859c2aa98e2SPeter Wemm if (tTd(32, 1)) 86012ed1c7cSGregory Neil Shapiro sm_dprintf("<NULL>\n"); 861c2aa98e2SPeter Wemm continue; 862c2aa98e2SPeter Wemm } 863c2aa98e2SPeter Wemm 864c2aa98e2SPeter Wemm /* do early binding */ 8653299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) && 8663299c2f1SGregory Neil Shapiro !bitset(H_BINDLATE, h->h_flags)) 867c2aa98e2SPeter Wemm { 868c2aa98e2SPeter Wemm if (tTd(32, 1)) 869c2aa98e2SPeter Wemm { 87012ed1c7cSGregory Neil Shapiro sm_dprintf("("); 871bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), h->h_value); 87212ed1c7cSGregory Neil Shapiro sm_dprintf(") "); 873c2aa98e2SPeter Wemm } 874951742c4SGregory Neil Shapiro expand(h->h_value, buf, sizeof(buf), e); 875951742c4SGregory Neil Shapiro if (buf[0] != '\0' && 876951742c4SGregory Neil Shapiro (buf[0] != ' ' || buf[1] != '\0')) 877c2aa98e2SPeter Wemm { 878c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 879f9218d3dSGregory Neil Shapiro expand(crackaddr(buf, e), 880951742c4SGregory Neil Shapiro buf, sizeof(buf), e); 88112ed1c7cSGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, buf); 882c2aa98e2SPeter Wemm h->h_flags &= ~H_DEFAULT; 883c2aa98e2SPeter Wemm } 884c2aa98e2SPeter Wemm } 885c2aa98e2SPeter Wemm if (tTd(32, 1)) 886c2aa98e2SPeter Wemm { 887bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), h->h_value); 88812ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 889c2aa98e2SPeter Wemm } 890c2aa98e2SPeter Wemm 891c2aa98e2SPeter Wemm /* count the number of times it has been processed */ 892c2aa98e2SPeter Wemm if (bitset(H_TRACE, h->h_flags)) 893c2aa98e2SPeter Wemm hopcnt++; 894c2aa98e2SPeter Wemm 895c2aa98e2SPeter Wemm /* send to this person if we so desire */ 896c2aa98e2SPeter Wemm if (GrabTo && bitset(H_RCPT, h->h_flags) && 897c2aa98e2SPeter Wemm !bitset(H_DEFAULT, h->h_flags) && 89812ed1c7cSGregory Neil Shapiro (!bitset(EF_RESENT, e->e_flags) || 89912ed1c7cSGregory Neil Shapiro bitset(H_RESENT, h->h_flags))) 900c2aa98e2SPeter Wemm { 901c2aa98e2SPeter Wemm #if 0 902c2aa98e2SPeter Wemm int saveflags = e->e_flags; 9033299c2f1SGregory Neil Shapiro #endif /* 0 */ 904c2aa98e2SPeter Wemm 90512ed1c7cSGregory Neil Shapiro (void) sendtolist(denlstring(h->h_value, true, false), 90612ed1c7cSGregory Neil Shapiro NULLADDR, &e->e_sendqueue, 0, e); 907c2aa98e2SPeter Wemm 908c2aa98e2SPeter Wemm #if 0 909c2aa98e2SPeter Wemm /* 910c2aa98e2SPeter Wemm ** Change functionality so a fatal error on an 911c2aa98e2SPeter Wemm ** address doesn't affect the entire envelope. 912c2aa98e2SPeter Wemm */ 913c2aa98e2SPeter Wemm 914c2aa98e2SPeter Wemm /* delete fatal errors generated by this address */ 915c2aa98e2SPeter Wemm if (!bitset(EF_FATALERRS, saveflags)) 916c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 9173299c2f1SGregory Neil Shapiro #endif /* 0 */ 918c2aa98e2SPeter Wemm } 919c2aa98e2SPeter Wemm 920c2aa98e2SPeter Wemm /* save the message-id for logging */ 921c2aa98e2SPeter Wemm p = "resent-message-id"; 922c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 923c2aa98e2SPeter Wemm p += 7; 92412ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(h->h_field, p) == 0) 925c2aa98e2SPeter Wemm { 92612ed1c7cSGregory Neil Shapiro e->e_msgid = h->h_value; 92712ed1c7cSGregory Neil Shapiro while (isascii(*e->e_msgid) && isspace(*e->e_msgid)) 92812ed1c7cSGregory Neil Shapiro e->e_msgid++; 9291ae5b8d4SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{msg_id}"), 9301ae5b8d4SGregory Neil Shapiro e->e_msgid); 931c2aa98e2SPeter Wemm } 932c2aa98e2SPeter Wemm } 933c2aa98e2SPeter Wemm if (tTd(32, 1)) 93412ed1c7cSGregory Neil Shapiro sm_dprintf("----------------------------\n"); 935c2aa98e2SPeter Wemm 936c2aa98e2SPeter Wemm /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 937c2aa98e2SPeter Wemm if (OpMode == MD_VERIFY) 938c2aa98e2SPeter Wemm return; 939c2aa98e2SPeter Wemm 940c2aa98e2SPeter Wemm /* store hop count */ 941c2aa98e2SPeter Wemm if (hopcnt > e->e_hopcount) 94212ed1c7cSGregory Neil Shapiro { 943c2aa98e2SPeter Wemm e->e_hopcount = hopcnt; 944951742c4SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount); 94512ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 'c', buf); 94612ed1c7cSGregory Neil Shapiro } 947c2aa98e2SPeter Wemm 948c2aa98e2SPeter Wemm /* message priority */ 949c2aa98e2SPeter Wemm p = hvalue("precedence", e->e_header); 950c2aa98e2SPeter Wemm if (p != NULL) 951c2aa98e2SPeter Wemm e->e_class = priencode(p); 952c2aa98e2SPeter Wemm if (e->e_class < 0) 953c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 954c2aa98e2SPeter Wemm else if (e->e_class > 0) 955c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 956c2aa98e2SPeter Wemm if (full) 957c2aa98e2SPeter Wemm { 958c2aa98e2SPeter Wemm e->e_msgpriority = e->e_msgsize 959c2aa98e2SPeter Wemm - e->e_class * WkClassFact 960c2aa98e2SPeter Wemm + e->e_nrcpts * WkRecipFact; 961c2aa98e2SPeter Wemm } 962c2aa98e2SPeter Wemm 963bfb62e91SGregory Neil Shapiro /* check for DSN to properly set e_timeoutclass */ 964bfb62e91SGregory Neil Shapiro p = hvalue("content-type", e->e_header); 965bfb62e91SGregory Neil Shapiro if (p != NULL) 966bfb62e91SGregory Neil Shapiro { 967bfb62e91SGregory Neil Shapiro bool oldsupr; 968bfb62e91SGregory Neil Shapiro char **pvp; 969bfb62e91SGregory Neil Shapiro char pvpbuf[MAXLINE]; 970bfb62e91SGregory Neil Shapiro extern unsigned char MimeTokenTab[256]; 971bfb62e91SGregory Neil Shapiro 972bfb62e91SGregory Neil Shapiro /* tokenize header */ 973bfb62e91SGregory Neil Shapiro oldsupr = SuprErrs; 974bfb62e91SGregory Neil Shapiro SuprErrs = true; 975951742c4SGregory Neil Shapiro pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL, 976bfb62e91SGregory Neil Shapiro MimeTokenTab, false); 977bfb62e91SGregory Neil Shapiro SuprErrs = oldsupr; 978bfb62e91SGregory Neil Shapiro 979bfb62e91SGregory Neil Shapiro /* Check if multipart/report */ 980bfb62e91SGregory Neil Shapiro if (pvp != NULL && pvp[0] != NULL && 981bfb62e91SGregory Neil Shapiro pvp[1] != NULL && pvp[2] != NULL && 982bfb62e91SGregory Neil Shapiro sm_strcasecmp(*pvp++, "multipart") == 0 && 983bfb62e91SGregory Neil Shapiro strcmp(*pvp++, "/") == 0 && 984bfb62e91SGregory Neil Shapiro sm_strcasecmp(*pvp++, "report") == 0) 985bfb62e91SGregory Neil Shapiro { 986bfb62e91SGregory Neil Shapiro /* Look for report-type=delivery-status */ 987bfb62e91SGregory Neil Shapiro while (*pvp != NULL) 988bfb62e91SGregory Neil Shapiro { 989bfb62e91SGregory Neil Shapiro /* skip to semicolon separator */ 990bfb62e91SGregory Neil Shapiro while (*pvp != NULL && strcmp(*pvp, ";") != 0) 991bfb62e91SGregory Neil Shapiro pvp++; 992bfb62e91SGregory Neil Shapiro 993bfb62e91SGregory Neil Shapiro /* skip semicolon */ 994bfb62e91SGregory Neil Shapiro if (*pvp++ == NULL || *pvp == NULL) 995bfb62e91SGregory Neil Shapiro break; 996bfb62e91SGregory Neil Shapiro 997bfb62e91SGregory Neil Shapiro /* look for report-type */ 998bfb62e91SGregory Neil Shapiro if (sm_strcasecmp(*pvp++, "report-type") != 0) 999bfb62e91SGregory Neil Shapiro continue; 1000bfb62e91SGregory Neil Shapiro 1001bfb62e91SGregory Neil Shapiro /* skip equal */ 1002bfb62e91SGregory Neil Shapiro if (*pvp == NULL || strcmp(*pvp, "=") != 0) 1003bfb62e91SGregory Neil Shapiro continue; 1004bfb62e91SGregory Neil Shapiro 1005bfb62e91SGregory Neil Shapiro /* check value */ 1006bfb62e91SGregory Neil Shapiro if (*++pvp != NULL && 1007bfb62e91SGregory Neil Shapiro sm_strcasecmp(*pvp, 1008bfb62e91SGregory Neil Shapiro "delivery-status") == 0) 1009bfb62e91SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 1010bfb62e91SGregory Neil Shapiro 1011bfb62e91SGregory Neil Shapiro /* found report-type, no need to continue */ 1012bfb62e91SGregory Neil Shapiro break; 1013bfb62e91SGregory Neil Shapiro } 1014bfb62e91SGregory Neil Shapiro } 1015bfb62e91SGregory Neil Shapiro } 1016bfb62e91SGregory Neil Shapiro 1017c2aa98e2SPeter Wemm /* message timeout priority */ 1018c2aa98e2SPeter Wemm p = hvalue("priority", e->e_header); 1019c2aa98e2SPeter Wemm if (p != NULL) 1020c2aa98e2SPeter Wemm { 1021c2aa98e2SPeter Wemm /* (this should be in the configuration file) */ 102212ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(p, "urgent") == 0) 1023c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 102412ed1c7cSGregory Neil Shapiro else if (sm_strcasecmp(p, "normal") == 0) 1025c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NORMAL; 102612ed1c7cSGregory Neil Shapiro else if (sm_strcasecmp(p, "non-urgent") == 0) 1027c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 10281ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags)) 10291ae5b8d4SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 10301ae5b8d4SGregory Neil Shapiro } 10311ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags)) 103272936242SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 103372936242SGregory Neil Shapiro 1034c2aa98e2SPeter Wemm /* date message originated */ 1035c2aa98e2SPeter Wemm p = hvalue("posted-date", e->e_header); 1036c2aa98e2SPeter Wemm if (p == NULL) 1037c2aa98e2SPeter Wemm p = hvalue("date", e->e_header); 1038c2aa98e2SPeter Wemm if (p != NULL) 103912ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'a', p); 1040c2aa98e2SPeter Wemm 1041c2aa98e2SPeter Wemm /* check to see if this is a MIME message */ 1042c2aa98e2SPeter Wemm if ((e->e_bodytype != NULL && 104312ed1c7cSGregory Neil Shapiro sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 1044c2aa98e2SPeter Wemm hvalue("MIME-Version", e->e_header) != NULL) 1045c2aa98e2SPeter Wemm { 1046c2aa98e2SPeter Wemm e->e_flags |= EF_IS_MIME; 1047c2aa98e2SPeter Wemm if (HasEightBits) 1048c2aa98e2SPeter Wemm e->e_bodytype = "8BITMIME"; 1049c2aa98e2SPeter Wemm } 1050c2aa98e2SPeter Wemm else if ((p = hvalue("Content-Type", e->e_header)) != NULL) 1051c2aa98e2SPeter Wemm { 1052c2aa98e2SPeter Wemm /* this may be an RFC 1049 message */ 1053c2aa98e2SPeter Wemm p = strpbrk(p, ";/"); 1054c2aa98e2SPeter Wemm if (p == NULL || *p == ';') 1055c2aa98e2SPeter Wemm { 1056c2aa98e2SPeter Wemm /* yep, it is */ 1057c2aa98e2SPeter Wemm e->e_flags |= EF_DONT_MIME; 1058c2aa98e2SPeter Wemm } 1059c2aa98e2SPeter Wemm } 1060c2aa98e2SPeter Wemm 1061c2aa98e2SPeter Wemm /* 1062c2aa98e2SPeter Wemm ** From person in antiquated ARPANET mode 1063c2aa98e2SPeter Wemm ** required by UK Grey Book e-mail gateways (sigh) 1064c2aa98e2SPeter Wemm */ 1065c2aa98e2SPeter Wemm 1066c2aa98e2SPeter Wemm if (OpMode == MD_ARPAFTP) 1067c2aa98e2SPeter Wemm { 1068c2aa98e2SPeter Wemm register struct hdrinfo *hi; 1069c2aa98e2SPeter Wemm 1070c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 1071c2aa98e2SPeter Wemm { 1072c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && 1073c2aa98e2SPeter Wemm (!bitset(H_RESENT, hi->hi_flags) || 1074c2aa98e2SPeter Wemm bitset(EF_RESENT, e->e_flags)) && 1075c2aa98e2SPeter Wemm (p = hvalue(hi->hi_field, e->e_header)) != NULL) 1076c2aa98e2SPeter Wemm break; 1077c2aa98e2SPeter Wemm } 1078c2aa98e2SPeter Wemm if (hi->hi_field != NULL) 1079c2aa98e2SPeter Wemm { 1080c2aa98e2SPeter Wemm if (tTd(32, 2)) 108112ed1c7cSGregory Neil Shapiro sm_dprintf("eatheader: setsender(*%s == %s)\n", 1082c2aa98e2SPeter Wemm hi->hi_field, p); 108312ed1c7cSGregory Neil Shapiro setsender(p, e, NULL, '\0', true); 1084c2aa98e2SPeter Wemm } 1085c2aa98e2SPeter Wemm } 1086c2aa98e2SPeter Wemm 1087c2aa98e2SPeter Wemm /* 1088c2aa98e2SPeter Wemm ** Log collection information. 1089c2aa98e2SPeter Wemm */ 1090c2aa98e2SPeter Wemm 10919bd497b8SGregory Neil Shapiro if (tTd(92, 2)) 10929bd497b8SGregory Neil Shapiro sm_dprintf("eatheader: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d, log=%d\n", 10939bd497b8SGregory Neil Shapiro e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel, 10949bd497b8SGregory Neil Shapiro log); 109512ed1c7cSGregory Neil Shapiro if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 109612ed1c7cSGregory Neil Shapiro { 109712ed1c7cSGregory Neil Shapiro logsender(e, e->e_msgid); 1098c2aa98e2SPeter Wemm e->e_flags &= ~EF_LOGSENDER; 1099c2aa98e2SPeter Wemm } 110012ed1c7cSGregory Neil Shapiro } 1101951742c4SGregory Neil Shapiro 110212ed1c7cSGregory Neil Shapiro /* 1103c2aa98e2SPeter Wemm ** LOGSENDER -- log sender information 1104c2aa98e2SPeter Wemm ** 1105c2aa98e2SPeter Wemm ** Parameters: 1106c2aa98e2SPeter Wemm ** e -- the envelope to log 1107c2aa98e2SPeter Wemm ** msgid -- the message id 1108c2aa98e2SPeter Wemm ** 1109c2aa98e2SPeter Wemm ** Returns: 1110c2aa98e2SPeter Wemm ** none 1111c2aa98e2SPeter Wemm */ 1112c2aa98e2SPeter Wemm 1113c2aa98e2SPeter Wemm void 1114c2aa98e2SPeter Wemm logsender(e, msgid) 1115c2aa98e2SPeter Wemm register ENVELOPE *e; 1116c2aa98e2SPeter Wemm char *msgid; 1117c2aa98e2SPeter Wemm { 1118c2aa98e2SPeter Wemm char *name; 1119c2aa98e2SPeter Wemm register char *sbp; 1120c2aa98e2SPeter Wemm register char *p; 1121c2aa98e2SPeter Wemm char hbuf[MAXNAME + 1]; 1122c2aa98e2SPeter Wemm char sbuf[MAXLINE + 1]; 1123c2aa98e2SPeter Wemm char mbuf[MAXNAME + 1]; 1124c2aa98e2SPeter Wemm 1125c2aa98e2SPeter Wemm /* don't allow newlines in the message-id */ 112612ed1c7cSGregory Neil Shapiro /* XXX do we still need this? sm_syslog() replaces control chars */ 1127c2aa98e2SPeter Wemm if (msgid != NULL) 1128c2aa98e2SPeter Wemm { 1129567a2fc9SGregory Neil Shapiro size_t l; 1130567a2fc9SGregory Neil Shapiro 1131c2aa98e2SPeter Wemm l = strlen(msgid); 1132951742c4SGregory Neil Shapiro if (l > sizeof(mbuf) - 1) 1133951742c4SGregory Neil Shapiro l = sizeof(mbuf) - 1; 11343299c2f1SGregory Neil Shapiro memmove(mbuf, msgid, l); 1135c2aa98e2SPeter Wemm mbuf[l] = '\0'; 1136c2aa98e2SPeter Wemm p = mbuf; 1137c2aa98e2SPeter Wemm while ((p = strchr(p, '\n')) != NULL) 1138c2aa98e2SPeter Wemm *p++ = ' '; 1139c2aa98e2SPeter Wemm } 1140c2aa98e2SPeter Wemm 1141c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags)) 1142c2aa98e2SPeter Wemm name = "[RESPONSE]"; 1143c2aa98e2SPeter Wemm else if ((name = macvalue('_', e)) != NULL) 11443299c2f1SGregory Neil Shapiro /* EMPTY */ 1145c2aa98e2SPeter Wemm ; 1146c2aa98e2SPeter Wemm else if (RealHostName == NULL) 1147c2aa98e2SPeter Wemm name = "localhost"; 1148c2aa98e2SPeter Wemm else if (RealHostName[0] == '[') 1149c2aa98e2SPeter Wemm name = RealHostName; 1150c2aa98e2SPeter Wemm else 1151c2aa98e2SPeter Wemm { 1152c2aa98e2SPeter Wemm name = hbuf; 1153951742c4SGregory Neil Shapiro (void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName); 1154c2aa98e2SPeter Wemm if (RealHostAddr.sa.sa_family != 0) 1155c2aa98e2SPeter Wemm { 1156c2aa98e2SPeter Wemm p = &hbuf[strlen(hbuf)]; 115712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 115812ed1c7cSGregory Neil Shapiro " (%.100s)", 1159c2aa98e2SPeter Wemm anynet_ntoa(&RealHostAddr)); 1160c2aa98e2SPeter Wemm } 1161c2aa98e2SPeter Wemm } 1162c2aa98e2SPeter Wemm 1163c2aa98e2SPeter Wemm /* some versions of syslog only take 5 printf args */ 1164c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256 1165c2aa98e2SPeter Wemm sbp = sbuf; 116612ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 11673299c2f1SGregory Neil Shapiro "from=%.200s, size=%ld, class=%d, nrcpts=%d", 1168c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 1169ba00ec3dSGregory Neil Shapiro PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 1170c2aa98e2SPeter Wemm sbp += strlen(sbp); 1171c2aa98e2SPeter Wemm if (msgid != NULL) 1172c2aa98e2SPeter Wemm { 117312ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 117412ed1c7cSGregory Neil Shapiro ", msgid=%.100s", mbuf); 1175c2aa98e2SPeter Wemm sbp += strlen(sbp); 1176c2aa98e2SPeter Wemm } 1177c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 1178c2aa98e2SPeter Wemm { 117912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 118012ed1c7cSGregory Neil Shapiro ", bodytype=%.20s", e->e_bodytype); 1181c2aa98e2SPeter Wemm sbp += strlen(sbp); 1182c2aa98e2SPeter Wemm } 1183c2aa98e2SPeter Wemm p = macvalue('r', e); 1184c2aa98e2SPeter Wemm if (p != NULL) 11853299c2f1SGregory Neil Shapiro { 118612ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 118712ed1c7cSGregory Neil Shapiro ", proto=%.20s", p); 11883299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 11893299c2f1SGregory Neil Shapiro } 119012ed1c7cSGregory Neil Shapiro p = macvalue(macid("{daemon_name}"), e); 11913299c2f1SGregory Neil Shapiro if (p != NULL) 11923299c2f1SGregory Neil Shapiro { 119312ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 119412ed1c7cSGregory Neil Shapiro ", daemon=%.20s", p); 11953299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 11963299c2f1SGregory Neil Shapiro } 11972ef40764SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name); 1198c2aa98e2SPeter Wemm 11993299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */ 1200c2aa98e2SPeter Wemm 1201c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 1202c2aa98e2SPeter Wemm "from=%s", 1203c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>" 120412ed1c7cSGregory Neil Shapiro : shortenstring(e->e_from.q_paddr, 120512ed1c7cSGregory Neil Shapiro 83)); 1206c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 12073299c2f1SGregory Neil Shapiro "size=%ld, class=%ld, nrcpts=%d", 1208ba00ec3dSGregory Neil Shapiro PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 1209c2aa98e2SPeter Wemm if (msgid != NULL) 1210c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 1211c2aa98e2SPeter Wemm "msgid=%s", 1212c2aa98e2SPeter Wemm shortenstring(mbuf, 83)); 1213c2aa98e2SPeter Wemm sbp = sbuf; 1214c2aa98e2SPeter Wemm *sbp = '\0'; 1215c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 1216c2aa98e2SPeter Wemm { 121712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 121812ed1c7cSGregory Neil Shapiro "bodytype=%.20s, ", e->e_bodytype); 1219c2aa98e2SPeter Wemm sbp += strlen(sbp); 1220c2aa98e2SPeter Wemm } 1221c2aa98e2SPeter Wemm p = macvalue('r', e); 1222c2aa98e2SPeter Wemm if (p != NULL) 1223c2aa98e2SPeter Wemm { 122412ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 122512ed1c7cSGregory Neil Shapiro "proto=%.20s, ", p); 1226c2aa98e2SPeter Wemm sbp += strlen(sbp); 1227c2aa98e2SPeter Wemm } 1228c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 12292ef40764SGregory Neil Shapiro "%.400srelay=%s", sbuf, name); 12303299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 1231c2aa98e2SPeter Wemm } 1232951742c4SGregory Neil Shapiro 123312ed1c7cSGregory Neil Shapiro /* 1234c2aa98e2SPeter Wemm ** PRIENCODE -- encode external priority names into internal values. 1235c2aa98e2SPeter Wemm ** 1236c2aa98e2SPeter Wemm ** Parameters: 1237c2aa98e2SPeter Wemm ** p -- priority in ascii. 1238c2aa98e2SPeter Wemm ** 1239c2aa98e2SPeter Wemm ** Returns: 1240c2aa98e2SPeter Wemm ** priority as a numeric level. 1241c2aa98e2SPeter Wemm ** 1242c2aa98e2SPeter Wemm ** Side Effects: 1243c2aa98e2SPeter Wemm ** none. 1244c2aa98e2SPeter Wemm */ 1245c2aa98e2SPeter Wemm 12463299c2f1SGregory Neil Shapiro static int 1247c2aa98e2SPeter Wemm priencode(p) 1248c2aa98e2SPeter Wemm char *p; 1249c2aa98e2SPeter Wemm { 1250c2aa98e2SPeter Wemm register int i; 1251c2aa98e2SPeter Wemm 1252c2aa98e2SPeter Wemm for (i = 0; i < NumPriorities; i++) 1253c2aa98e2SPeter Wemm { 125412ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(p, Priorities[i].pri_name) == 0) 12553299c2f1SGregory Neil Shapiro return Priorities[i].pri_val; 1256c2aa98e2SPeter Wemm } 1257c2aa98e2SPeter Wemm 1258c2aa98e2SPeter Wemm /* unknown priority */ 12593299c2f1SGregory Neil Shapiro return 0; 1260c2aa98e2SPeter Wemm } 1261951742c4SGregory Neil Shapiro 126212ed1c7cSGregory Neil Shapiro /* 1263c2aa98e2SPeter Wemm ** CRACKADDR -- parse an address and turn it into a macro 1264c2aa98e2SPeter Wemm ** 1265c2aa98e2SPeter Wemm ** This doesn't actually parse the address -- it just extracts 1266c2aa98e2SPeter Wemm ** it and replaces it with "$g". The parse is totally ad hoc 1267c2aa98e2SPeter Wemm ** and isn't even guaranteed to leave something syntactically 1268c2aa98e2SPeter Wemm ** identical to what it started with. However, it does leave 1269f9218d3dSGregory Neil Shapiro ** something semantically identical if possible, else at least 1270f9218d3dSGregory Neil Shapiro ** syntactically correct. 1271f9218d3dSGregory Neil Shapiro ** 1272f9218d3dSGregory Neil Shapiro ** For example, it changes "Real Name <real@example.com> (Comment)" 1273f9218d3dSGregory Neil Shapiro ** to "Real Name <$g> (Comment)". 1274c2aa98e2SPeter Wemm ** 1275c2aa98e2SPeter Wemm ** This algorithm has been cleaned up to handle a wider range 1276c2aa98e2SPeter Wemm ** of cases -- notably quoted and backslash escaped strings. 1277c2aa98e2SPeter Wemm ** This modification makes it substantially better at preserving 1278c2aa98e2SPeter Wemm ** the original syntax. 1279c2aa98e2SPeter Wemm ** 1280c2aa98e2SPeter Wemm ** Parameters: 1281c2aa98e2SPeter Wemm ** addr -- the address to be cracked. 1282f9218d3dSGregory Neil Shapiro ** e -- the current envelope. 1283c2aa98e2SPeter Wemm ** 1284c2aa98e2SPeter Wemm ** Returns: 1285c2aa98e2SPeter Wemm ** a pointer to the new version. 1286c2aa98e2SPeter Wemm ** 1287c2aa98e2SPeter Wemm ** Side Effects: 1288c2aa98e2SPeter Wemm ** none. 1289c2aa98e2SPeter Wemm ** 1290c2aa98e2SPeter Wemm ** Warning: 1291c2aa98e2SPeter Wemm ** The return value is saved in local storage and should 1292c2aa98e2SPeter Wemm ** be copied if it is to be reused. 1293c2aa98e2SPeter Wemm */ 1294c2aa98e2SPeter Wemm 1295f9218d3dSGregory Neil Shapiro #define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend)) 1296f9218d3dSGregory Neil Shapiro 1297f9218d3dSGregory Neil Shapiro /* 1298f9218d3dSGregory Neil Shapiro ** Append a character to bp if we have room. 1299f9218d3dSGregory Neil Shapiro ** If not, punt and return $g. 1300f9218d3dSGregory Neil Shapiro */ 1301f9218d3dSGregory Neil Shapiro 1302f9218d3dSGregory Neil Shapiro #define SM_APPEND_CHAR(c) \ 1303f9218d3dSGregory Neil Shapiro do \ 1304f9218d3dSGregory Neil Shapiro { \ 1305f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) \ 1306f9218d3dSGregory Neil Shapiro *bp++ = (c); \ 1307f9218d3dSGregory Neil Shapiro else \ 1308f9218d3dSGregory Neil Shapiro goto returng; \ 1309f9218d3dSGregory Neil Shapiro } while (0) 1310f9218d3dSGregory Neil Shapiro 1311f9218d3dSGregory Neil Shapiro #if MAXNAME < 10 1312f9218d3dSGregory Neil Shapiro ERROR MAXNAME must be at least 10 1313f9218d3dSGregory Neil Shapiro #endif /* MAXNAME < 10 */ 1314f9218d3dSGregory Neil Shapiro 1315c2aa98e2SPeter Wemm char * 1316f9218d3dSGregory Neil Shapiro crackaddr(addr, e) 1317c2aa98e2SPeter Wemm register char *addr; 1318f9218d3dSGregory Neil Shapiro ENVELOPE *e; 1319c2aa98e2SPeter Wemm { 1320c2aa98e2SPeter Wemm register char *p; 1321c2aa98e2SPeter Wemm register char c; 1322f9218d3dSGregory Neil Shapiro int cmtlev; /* comment level in input string */ 1323f9218d3dSGregory Neil Shapiro int realcmtlev; /* comment level in output string */ 1324f9218d3dSGregory Neil Shapiro int anglelev; /* angle level in input string */ 1325f9218d3dSGregory Neil Shapiro int copylev; /* 0 == in address, >0 copying */ 1326f9218d3dSGregory Neil Shapiro int bracklev; /* bracket level for IPv6 addr check */ 1327f9218d3dSGregory Neil Shapiro bool addangle; /* put closing angle in output */ 1328f9218d3dSGregory Neil Shapiro bool qmode; /* quoting in original string? */ 1329f9218d3dSGregory Neil Shapiro bool realqmode; /* quoting in output string? */ 1330f9218d3dSGregory Neil Shapiro bool putgmac = false; /* already wrote $g */ 1331f9218d3dSGregory Neil Shapiro bool quoteit = false; /* need to quote next character */ 1332f9218d3dSGregory Neil Shapiro bool gotangle = false; /* found first '<' */ 1333f9218d3dSGregory Neil Shapiro bool gotcolon = false; /* found a ':' */ 1334c2aa98e2SPeter Wemm register char *bp; 1335c2aa98e2SPeter Wemm char *buflim; 1336c2aa98e2SPeter Wemm char *bufhead; 1337c2aa98e2SPeter Wemm char *addrhead; 1338f9218d3dSGregory Neil Shapiro char *bufend; 1339c2aa98e2SPeter Wemm static char buf[MAXNAME + 1]; 1340c2aa98e2SPeter Wemm 1341c2aa98e2SPeter Wemm if (tTd(33, 1)) 134212ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr(%s)\n", addr); 1343c2aa98e2SPeter Wemm 1344951742c4SGregory Neil Shapiro buflim = bufend = &buf[sizeof(buf) - 1]; 1345951742c4SGregory Neil Shapiro bp = bufhead = buf; 1346951742c4SGregory Neil Shapiro 1347951742c4SGregory Neil Shapiro /* skip over leading spaces but preserve them */ 1348c2aa98e2SPeter Wemm while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 1349951742c4SGregory Neil Shapiro { 1350951742c4SGregory Neil Shapiro SM_APPEND_CHAR(*addr); 1351c2aa98e2SPeter Wemm addr++; 1352951742c4SGregory Neil Shapiro } 1353951742c4SGregory Neil Shapiro bufhead = bp; 1354c2aa98e2SPeter Wemm 1355c2aa98e2SPeter Wemm /* 1356c2aa98e2SPeter Wemm ** Start by assuming we have no angle brackets. This will be 1357c2aa98e2SPeter Wemm ** adjusted later if we find them. 1358c2aa98e2SPeter Wemm */ 1359c2aa98e2SPeter Wemm 1360c2aa98e2SPeter Wemm p = addrhead = addr; 1361f9218d3dSGregory Neil Shapiro copylev = anglelev = cmtlev = realcmtlev = 0; 1362c2aa98e2SPeter Wemm bracklev = 0; 1363f9218d3dSGregory Neil Shapiro qmode = realqmode = addangle = false; 1364c2aa98e2SPeter Wemm 1365c2aa98e2SPeter Wemm while ((c = *p++) != '\0') 1366c2aa98e2SPeter Wemm { 1367c2aa98e2SPeter Wemm /* 1368f9218d3dSGregory Neil Shapiro ** Try to keep legal syntax using spare buffer space 1369f9218d3dSGregory Neil Shapiro ** (maintained by buflim). 1370c2aa98e2SPeter Wemm */ 1371c2aa98e2SPeter Wemm 1372f9218d3dSGregory Neil Shapiro if (copylev > 0) 1373f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1374c2aa98e2SPeter Wemm 1375c2aa98e2SPeter Wemm /* check for backslash escapes */ 1376c2aa98e2SPeter Wemm if (c == '\\') 1377c2aa98e2SPeter Wemm { 1378c2aa98e2SPeter Wemm /* arrange to quote the address */ 1379c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 138012ed1c7cSGregory Neil Shapiro quoteit = true; 1381c2aa98e2SPeter Wemm 1382c2aa98e2SPeter Wemm if ((c = *p++) == '\0') 1383c2aa98e2SPeter Wemm { 1384c2aa98e2SPeter Wemm /* too far */ 1385c2aa98e2SPeter Wemm p--; 1386c2aa98e2SPeter Wemm goto putg; 1387c2aa98e2SPeter Wemm } 1388f9218d3dSGregory Neil Shapiro if (copylev > 0) 1389f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1390c2aa98e2SPeter Wemm goto putg; 1391c2aa98e2SPeter Wemm } 1392c2aa98e2SPeter Wemm 1393c2aa98e2SPeter Wemm /* check for quoted strings */ 1394c2aa98e2SPeter Wemm if (c == '"' && cmtlev <= 0) 1395c2aa98e2SPeter Wemm { 1396c2aa98e2SPeter Wemm qmode = !qmode; 1397f9218d3dSGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM) 1398f9218d3dSGregory Neil Shapiro { 1399f9218d3dSGregory Neil Shapiro if (realqmode) 1400f9218d3dSGregory Neil Shapiro buflim--; 1401f9218d3dSGregory Neil Shapiro else 1402f9218d3dSGregory Neil Shapiro buflim++; 1403c2aa98e2SPeter Wemm realqmode = !realqmode; 1404f9218d3dSGregory Neil Shapiro } 1405c2aa98e2SPeter Wemm continue; 1406c2aa98e2SPeter Wemm } 1407c2aa98e2SPeter Wemm if (qmode) 1408c2aa98e2SPeter Wemm goto putg; 1409c2aa98e2SPeter Wemm 1410c2aa98e2SPeter Wemm /* check for comments */ 1411c2aa98e2SPeter Wemm if (c == '(') 1412c2aa98e2SPeter Wemm { 1413c2aa98e2SPeter Wemm cmtlev++; 1414c2aa98e2SPeter Wemm 1415c2aa98e2SPeter Wemm /* allow space for closing paren */ 1416f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1417c2aa98e2SPeter Wemm { 1418c2aa98e2SPeter Wemm buflim--; 1419c2aa98e2SPeter Wemm realcmtlev++; 1420c2aa98e2SPeter Wemm if (copylev++ <= 0) 1421c2aa98e2SPeter Wemm { 1422c2aa98e2SPeter Wemm if (bp != bufhead) 1423f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' '); 1424f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1425c2aa98e2SPeter Wemm } 1426c2aa98e2SPeter Wemm } 1427c2aa98e2SPeter Wemm } 1428c2aa98e2SPeter Wemm if (cmtlev > 0) 1429c2aa98e2SPeter Wemm { 1430c2aa98e2SPeter Wemm if (c == ')') 1431c2aa98e2SPeter Wemm { 1432c2aa98e2SPeter Wemm cmtlev--; 1433c2aa98e2SPeter Wemm copylev--; 1434f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1435c2aa98e2SPeter Wemm { 1436c2aa98e2SPeter Wemm realcmtlev--; 1437c2aa98e2SPeter Wemm buflim++; 1438c2aa98e2SPeter Wemm } 1439c2aa98e2SPeter Wemm } 1440c2aa98e2SPeter Wemm continue; 1441c2aa98e2SPeter Wemm } 1442c2aa98e2SPeter Wemm else if (c == ')') 1443c2aa98e2SPeter Wemm { 1444c2aa98e2SPeter Wemm /* syntax error: unmatched ) */ 14457660b554SGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead) 1446c2aa98e2SPeter Wemm bp--; 1447c2aa98e2SPeter Wemm } 1448c2aa98e2SPeter Wemm 1449c2aa98e2SPeter Wemm /* count nesting on [ ... ] (for IPv6 domain literals) */ 1450c2aa98e2SPeter Wemm if (c == '[') 1451c2aa98e2SPeter Wemm bracklev++; 1452c2aa98e2SPeter Wemm else if (c == ']') 1453c2aa98e2SPeter Wemm bracklev--; 1454c2aa98e2SPeter Wemm 1455c2aa98e2SPeter Wemm /* check for group: list; syntax */ 1456c2aa98e2SPeter Wemm if (c == ':' && anglelev <= 0 && bracklev <= 0 && 1457c2aa98e2SPeter Wemm !gotcolon && !ColonOkInAddr) 1458c2aa98e2SPeter Wemm { 1459c2aa98e2SPeter Wemm register char *q; 1460c2aa98e2SPeter Wemm 1461c2aa98e2SPeter Wemm /* 1462c2aa98e2SPeter Wemm ** Check for DECnet phase IV ``::'' (host::user) 1463f9218d3dSGregory Neil Shapiro ** or DECnet phase V ``:.'' syntaxes. The latter 1464c2aa98e2SPeter Wemm ** covers ``user@DEC:.tay.myhost'' and 1465c2aa98e2SPeter Wemm ** ``DEC:.tay.myhost::user'' syntaxes (bletch). 1466c2aa98e2SPeter Wemm */ 1467c2aa98e2SPeter Wemm 1468c2aa98e2SPeter Wemm if (*p == ':' || *p == '.') 1469c2aa98e2SPeter Wemm { 1470c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 147112ed1c7cSGregory Neil Shapiro quoteit = true; 1472f9218d3dSGregory Neil Shapiro if (copylev > 0) 1473c2aa98e2SPeter Wemm { 1474f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1475f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p); 1476c2aa98e2SPeter Wemm } 1477c2aa98e2SPeter Wemm p++; 1478c2aa98e2SPeter Wemm goto putg; 1479c2aa98e2SPeter Wemm } 1480c2aa98e2SPeter Wemm 148112ed1c7cSGregory Neil Shapiro gotcolon = true; 1482c2aa98e2SPeter Wemm 1483c2aa98e2SPeter Wemm bp = bufhead; 1484c2aa98e2SPeter Wemm if (quoteit) 1485c2aa98e2SPeter Wemm { 1486f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1487c2aa98e2SPeter Wemm 1488c2aa98e2SPeter Wemm /* back up over the ':' and any spaces */ 1489c2aa98e2SPeter Wemm --p; 1490f9218d3dSGregory Neil Shapiro while (p > addr && 1491f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p)) 1492c2aa98e2SPeter Wemm continue; 1493c2aa98e2SPeter Wemm p++; 1494c2aa98e2SPeter Wemm } 1495c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1496c2aa98e2SPeter Wemm { 1497c2aa98e2SPeter Wemm c = *q++; 1498c2aa98e2SPeter Wemm if (quoteit && c == '"') 1499f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\'); 1500f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1501c2aa98e2SPeter Wemm } 1502c2aa98e2SPeter Wemm if (quoteit) 1503c2aa98e2SPeter Wemm { 1504c2aa98e2SPeter Wemm if (bp == &bufhead[1]) 1505c2aa98e2SPeter Wemm bp--; 1506c2aa98e2SPeter Wemm else 1507f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1508c2aa98e2SPeter Wemm while ((c = *p++) != ':') 1509f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1510f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1511c2aa98e2SPeter Wemm } 1512c2aa98e2SPeter Wemm 1513c2aa98e2SPeter Wemm /* any trailing white space is part of group: */ 1514f9218d3dSGregory Neil Shapiro while (isascii(*p) && isspace(*p)) 1515f9218d3dSGregory Neil Shapiro { 1516f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p); 1517f9218d3dSGregory Neil Shapiro p++; 1518f9218d3dSGregory Neil Shapiro } 1519c2aa98e2SPeter Wemm copylev = 0; 152012ed1c7cSGregory Neil Shapiro putgmac = quoteit = false; 1521c2aa98e2SPeter Wemm bufhead = bp; 1522c2aa98e2SPeter Wemm addrhead = p; 1523c2aa98e2SPeter Wemm continue; 1524c2aa98e2SPeter Wemm } 1525c2aa98e2SPeter Wemm 1526c2aa98e2SPeter Wemm if (c == ';' && copylev <= 0 && !ColonOkInAddr) 1527f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1528c2aa98e2SPeter Wemm 1529c2aa98e2SPeter Wemm /* check for characters that may have to be quoted */ 1530c2aa98e2SPeter Wemm if (strchr(MustQuoteChars, c) != NULL) 1531c2aa98e2SPeter Wemm { 1532c2aa98e2SPeter Wemm /* 1533c2aa98e2SPeter Wemm ** If these occur as the phrase part of a <> 1534c2aa98e2SPeter Wemm ** construct, but are not inside of () or already 1535c2aa98e2SPeter Wemm ** quoted, they will have to be quoted. Note that 1536c2aa98e2SPeter Wemm ** now (but don't actually do the quoting). 1537c2aa98e2SPeter Wemm */ 1538c2aa98e2SPeter Wemm 1539c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 154012ed1c7cSGregory Neil Shapiro quoteit = true; 1541c2aa98e2SPeter Wemm } 1542c2aa98e2SPeter Wemm 1543c2aa98e2SPeter Wemm /* check for angle brackets */ 1544c2aa98e2SPeter Wemm if (c == '<') 1545c2aa98e2SPeter Wemm { 1546c2aa98e2SPeter Wemm register char *q; 1547c2aa98e2SPeter Wemm 1548c2aa98e2SPeter Wemm /* assume first of two angles is bogus */ 1549c2aa98e2SPeter Wemm if (gotangle) 155012ed1c7cSGregory Neil Shapiro quoteit = true; 155112ed1c7cSGregory Neil Shapiro gotangle = true; 1552c2aa98e2SPeter Wemm 1553c2aa98e2SPeter Wemm /* oops -- have to change our mind */ 1554c2aa98e2SPeter Wemm anglelev = 1; 1555f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1556f9218d3dSGregory Neil Shapiro { 1557f9218d3dSGregory Neil Shapiro if (!addangle) 1558f9218d3dSGregory Neil Shapiro buflim--; 1559f9218d3dSGregory Neil Shapiro addangle = true; 1560f9218d3dSGregory Neil Shapiro } 1561c2aa98e2SPeter Wemm 1562c2aa98e2SPeter Wemm bp = bufhead; 1563c2aa98e2SPeter Wemm if (quoteit) 1564c2aa98e2SPeter Wemm { 1565f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1566c2aa98e2SPeter Wemm 1567c2aa98e2SPeter Wemm /* back up over the '<' and any spaces */ 1568c2aa98e2SPeter Wemm --p; 1569f9218d3dSGregory Neil Shapiro while (p > addr && 1570f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p)) 1571c2aa98e2SPeter Wemm continue; 1572c2aa98e2SPeter Wemm p++; 1573c2aa98e2SPeter Wemm } 1574c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1575c2aa98e2SPeter Wemm { 1576c2aa98e2SPeter Wemm c = *q++; 1577c2aa98e2SPeter Wemm if (quoteit && c == '"') 1578f9218d3dSGregory Neil Shapiro { 1579f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\'); 1580f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1581c2aa98e2SPeter Wemm } 1582f9218d3dSGregory Neil Shapiro else 1583f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1584c2aa98e2SPeter Wemm } 1585c2aa98e2SPeter Wemm if (quoteit) 1586c2aa98e2SPeter Wemm { 1587c2aa98e2SPeter Wemm if (bp == &buf[1]) 1588c2aa98e2SPeter Wemm bp--; 1589c2aa98e2SPeter Wemm else 1590f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1591c2aa98e2SPeter Wemm while ((c = *p++) != '<') 1592f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1593f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1594c2aa98e2SPeter Wemm } 1595c2aa98e2SPeter Wemm copylev = 0; 159612ed1c7cSGregory Neil Shapiro putgmac = quoteit = false; 1597c2aa98e2SPeter Wemm continue; 1598c2aa98e2SPeter Wemm } 1599c2aa98e2SPeter Wemm 1600c2aa98e2SPeter Wemm if (c == '>') 1601c2aa98e2SPeter Wemm { 1602c2aa98e2SPeter Wemm if (anglelev > 0) 1603c2aa98e2SPeter Wemm { 1604c2aa98e2SPeter Wemm anglelev--; 1605f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1606c2aa98e2SPeter Wemm { 1607f9218d3dSGregory Neil Shapiro if (addangle) 1608c2aa98e2SPeter Wemm buflim++; 1609f9218d3dSGregory Neil Shapiro addangle = false; 1610c2aa98e2SPeter Wemm } 1611c2aa98e2SPeter Wemm } 1612f9218d3dSGregory Neil Shapiro else if (SM_HAVE_ROOM) 1613c2aa98e2SPeter Wemm { 1614c2aa98e2SPeter Wemm /* syntax error: unmatched > */ 16157660b554SGregory Neil Shapiro if (copylev > 0 && bp > bufhead) 1616c2aa98e2SPeter Wemm bp--; 161712ed1c7cSGregory Neil Shapiro quoteit = true; 1618c2aa98e2SPeter Wemm continue; 1619c2aa98e2SPeter Wemm } 1620c2aa98e2SPeter Wemm if (copylev++ <= 0) 1621f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1622c2aa98e2SPeter Wemm continue; 1623c2aa98e2SPeter Wemm } 1624c2aa98e2SPeter Wemm 1625c2aa98e2SPeter Wemm /* must be a real address character */ 1626c2aa98e2SPeter Wemm putg: 1627c2aa98e2SPeter Wemm if (copylev <= 0 && !putgmac) 1628c2aa98e2SPeter Wemm { 1629f9218d3dSGregory Neil Shapiro if (bp > buf && bp[-1] == ')') 1630f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' '); 1631f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(MACROEXPAND); 1632f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('g'); 163312ed1c7cSGregory Neil Shapiro putgmac = true; 1634c2aa98e2SPeter Wemm } 1635c2aa98e2SPeter Wemm } 1636c2aa98e2SPeter Wemm 1637c2aa98e2SPeter Wemm /* repair any syntactic damage */ 1638f9218d3dSGregory Neil Shapiro if (realqmode && bp < bufend) 1639c2aa98e2SPeter Wemm *bp++ = '"'; 1640f9218d3dSGregory Neil Shapiro while (realcmtlev-- > 0 && bp < bufend) 1641c2aa98e2SPeter Wemm *bp++ = ')'; 1642f9218d3dSGregory Neil Shapiro if (addangle && bp < bufend) 1643c2aa98e2SPeter Wemm *bp++ = '>'; 1644f9218d3dSGregory Neil Shapiro *bp = '\0'; 1645f9218d3dSGregory Neil Shapiro if (bp < bufend) 1646f9218d3dSGregory Neil Shapiro goto success; 1647c2aa98e2SPeter Wemm 1648f9218d3dSGregory Neil Shapiro returng: 1649f9218d3dSGregory Neil Shapiro /* String too long, punt */ 1650f9218d3dSGregory Neil Shapiro buf[0] = '<'; 1651f9218d3dSGregory Neil Shapiro buf[1] = MACROEXPAND; 1652f9218d3dSGregory Neil Shapiro buf[2]= 'g'; 1653f9218d3dSGregory Neil Shapiro buf[3] = '>'; 1654f9218d3dSGregory Neil Shapiro buf[4]= '\0'; 1655f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 1656f9218d3dSGregory Neil Shapiro "Dropped invalid comments from header address"); 1657f9218d3dSGregory Neil Shapiro 1658f9218d3dSGregory Neil Shapiro success: 1659c2aa98e2SPeter Wemm if (tTd(33, 1)) 1660c2aa98e2SPeter Wemm { 166112ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr=>`"); 1662bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), buf); 166312ed1c7cSGregory Neil Shapiro sm_dprintf("'\n"); 1664c2aa98e2SPeter Wemm } 16653299c2f1SGregory Neil Shapiro return buf; 1666c2aa98e2SPeter Wemm } 1667951742c4SGregory Neil Shapiro 166812ed1c7cSGregory Neil Shapiro /* 1669c2aa98e2SPeter Wemm ** PUTHEADER -- put the header part of a message from the in-core copy 1670c2aa98e2SPeter Wemm ** 1671c2aa98e2SPeter Wemm ** Parameters: 1672c2aa98e2SPeter Wemm ** mci -- the connection information. 16733299c2f1SGregory Neil Shapiro ** hdr -- the header to put. 1674c2aa98e2SPeter Wemm ** e -- envelope to use. 1675e01d6f61SPeter Wemm ** flags -- MIME conversion flags. 1676c2aa98e2SPeter Wemm ** 1677c2aa98e2SPeter Wemm ** Returns: 1678355d91e3SGregory Neil Shapiro ** true iff header part was written successfully 1679c2aa98e2SPeter Wemm ** 1680c2aa98e2SPeter Wemm ** Side Effects: 1681c2aa98e2SPeter Wemm ** none. 1682c2aa98e2SPeter Wemm */ 1683c2aa98e2SPeter Wemm 1684567a2fc9SGregory Neil Shapiro bool 1685e01d6f61SPeter Wemm putheader(mci, hdr, e, flags) 1686c2aa98e2SPeter Wemm register MCI *mci; 1687c2aa98e2SPeter Wemm HDR *hdr; 1688c2aa98e2SPeter Wemm register ENVELOPE *e; 1689e01d6f61SPeter Wemm int flags; 1690c2aa98e2SPeter Wemm { 1691c2aa98e2SPeter Wemm register HDR *h; 169212ed1c7cSGregory Neil Shapiro char buf[SM_MAX(MAXLINE,BUFSIZ)]; 1693c2aa98e2SPeter Wemm char obuf[MAXLINE]; 1694c2aa98e2SPeter Wemm 1695c2aa98e2SPeter Wemm if (tTd(34, 1)) 169612ed1c7cSGregory Neil Shapiro sm_dprintf("--- putheader, mailer = %s ---\n", 1697c2aa98e2SPeter Wemm mci->mci_mailer->m_name); 1698c2aa98e2SPeter Wemm 1699c2aa98e2SPeter Wemm /* 1700c2aa98e2SPeter Wemm ** If we're in MIME mode, we're not really in the header of the 1701c2aa98e2SPeter Wemm ** message, just the header of one of the parts of the body of 1702c2aa98e2SPeter Wemm ** the message. Therefore MCIF_INHEADER should not be turned on. 1703c2aa98e2SPeter Wemm */ 1704c2aa98e2SPeter Wemm 1705c2aa98e2SPeter Wemm if (!bitset(MCIF_INMIME, mci->mci_flags)) 1706c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 1707c2aa98e2SPeter Wemm 1708c2aa98e2SPeter Wemm for (h = hdr; h != NULL; h = h->h_link) 1709c2aa98e2SPeter Wemm { 1710c2aa98e2SPeter Wemm register char *p = h->h_value; 171112ed1c7cSGregory Neil Shapiro char *q; 1712c2aa98e2SPeter Wemm 1713c2aa98e2SPeter Wemm if (tTd(34, 11)) 1714c2aa98e2SPeter Wemm { 171512ed1c7cSGregory Neil Shapiro sm_dprintf(" %s:", h->h_field); 1716bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), p); 1717c2aa98e2SPeter Wemm } 1718c2aa98e2SPeter Wemm 17193299c2f1SGregory Neil Shapiro /* Skip empty headers */ 17203299c2f1SGregory Neil Shapiro if (h->h_value == NULL) 17213299c2f1SGregory Neil Shapiro continue; 17223299c2f1SGregory Neil Shapiro 172376b7bf71SPeter Wemm /* heuristic shortening of MIME fields to avoid MUA overflows */ 172476b7bf71SPeter Wemm if (MaxMimeFieldLength > 0 && 172576b7bf71SPeter Wemm wordinclass(h->h_field, 172612ed1c7cSGregory Neil Shapiro macid("{checkMIMEFieldHeaders}"))) 172776b7bf71SPeter Wemm { 1728c46d91b7SGregory Neil Shapiro size_t len; 1729c46d91b7SGregory Neil Shapiro 1730f9218d3dSGregory Neil Shapiro len = fix_mime_header(h, e); 1731c46d91b7SGregory Neil Shapiro if (len > 0) 173276b7bf71SPeter Wemm { 173376b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1734c46d91b7SGregory Neil Shapiro "Truncated MIME %s header due to field size (length = %ld) (possible attack)", 1735c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 173676b7bf71SPeter Wemm if (tTd(34, 11)) 173712ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", 1738c46d91b7SGregory Neil Shapiro h->h_field, 1739c46d91b7SGregory Neil Shapiro (unsigned long) len); 174076b7bf71SPeter Wemm } 174176b7bf71SPeter Wemm } 174276b7bf71SPeter Wemm 174376b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 174476b7bf71SPeter Wemm wordinclass(h->h_field, 174512ed1c7cSGregory Neil Shapiro macid("{checkMIMETextHeaders}"))) 174676b7bf71SPeter Wemm { 1747c46d91b7SGregory Neil Shapiro size_t len; 1748c46d91b7SGregory Neil Shapiro 1749c46d91b7SGregory Neil Shapiro len = strlen(h->h_value); 1750c46d91b7SGregory Neil Shapiro if (len > (size_t) MaxMimeHeaderLength) 175176b7bf71SPeter Wemm { 175276b7bf71SPeter Wemm h->h_value[MaxMimeHeaderLength - 1] = '\0'; 175376b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1754c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1755c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 175676b7bf71SPeter Wemm if (tTd(34, 11)) 175712ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1758c46d91b7SGregory Neil Shapiro h->h_field, 1759c46d91b7SGregory Neil Shapiro (unsigned long) len); 176076b7bf71SPeter Wemm } 176176b7bf71SPeter Wemm } 176276b7bf71SPeter Wemm 176376b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 176476b7bf71SPeter Wemm wordinclass(h->h_field, 176512ed1c7cSGregory Neil Shapiro macid("{checkMIMEHeaders}"))) 176676b7bf71SPeter Wemm { 1767c46d91b7SGregory Neil Shapiro size_t len; 1768c46d91b7SGregory Neil Shapiro 1769c46d91b7SGregory Neil Shapiro len = strlen(h->h_value); 1770c46d91b7SGregory Neil Shapiro if (shorten_rfc822_string(h->h_value, 1771c46d91b7SGregory Neil Shapiro MaxMimeHeaderLength)) 177276b7bf71SPeter Wemm { 1773f9218d3dSGregory Neil Shapiro if (len < MaxMimeHeaderLength) 1774f9218d3dSGregory Neil Shapiro { 1775f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus header */ 1776f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 1777f9218d3dSGregory Neil Shapiro "Fixed MIME %s header (possible attack)", 1778f9218d3dSGregory Neil Shapiro h->h_field); 1779f9218d3dSGregory Neil Shapiro if (tTd(34, 11)) 1780f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header (possible attack)\n", 1781f9218d3dSGregory Neil Shapiro h->h_field); 1782f9218d3dSGregory Neil Shapiro } 1783f9218d3dSGregory Neil Shapiro else 1784f9218d3dSGregory Neil Shapiro { 1785f9218d3dSGregory Neil Shapiro /* we actually shortened header */ 178676b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1787c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1788f9218d3dSGregory Neil Shapiro h->h_field, 1789f9218d3dSGregory Neil Shapiro (unsigned long) len); 179076b7bf71SPeter Wemm if (tTd(34, 11)) 179112ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1792c46d91b7SGregory Neil Shapiro h->h_field, 1793c46d91b7SGregory Neil Shapiro (unsigned long) len); 179476b7bf71SPeter Wemm } 179576b7bf71SPeter Wemm } 1796f9218d3dSGregory Neil Shapiro } 179776b7bf71SPeter Wemm 1798e01d6f61SPeter Wemm /* 1799e01d6f61SPeter Wemm ** Suppress Content-Transfer-Encoding: if we are MIMEing 1800e01d6f61SPeter Wemm ** and we are potentially converting from 8 bit to 7 bit 1801e01d6f61SPeter Wemm ** MIME. If converting, add a new CTE header in 1802e01d6f61SPeter Wemm ** mime8to7(). 1803e01d6f61SPeter Wemm */ 180412ed1c7cSGregory Neil Shapiro 1805c2aa98e2SPeter Wemm if (bitset(H_CTE, h->h_flags) && 1806e01d6f61SPeter Wemm bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 1807e01d6f61SPeter Wemm mci->mci_flags) && 1808e01d6f61SPeter Wemm !bitset(M87F_NO8TO7, flags)) 1809c2aa98e2SPeter Wemm { 1810c2aa98e2SPeter Wemm if (tTd(34, 11)) 181112ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (content-transfer-encoding))\n"); 1812c2aa98e2SPeter Wemm continue; 1813c2aa98e2SPeter Wemm } 1814c2aa98e2SPeter Wemm 1815c2aa98e2SPeter Wemm if (bitset(MCIF_INMIME, mci->mci_flags)) 1816c2aa98e2SPeter Wemm { 1817c2aa98e2SPeter Wemm if (tTd(34, 11)) 181812ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 1819567a2fc9SGregory Neil Shapiro if (!put_vanilla_header(h, p, mci)) 1820567a2fc9SGregory Neil Shapiro goto writeerr; 1821c2aa98e2SPeter Wemm continue; 1822c2aa98e2SPeter Wemm } 1823c2aa98e2SPeter Wemm 1824c2aa98e2SPeter Wemm if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 18253299c2f1SGregory Neil Shapiro !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && 18263299c2f1SGregory Neil Shapiro (h->h_macro == '\0' || 182712ed1c7cSGregory Neil Shapiro (q = macvalue(bitidx(h->h_macro), e)) == NULL || 182812ed1c7cSGregory Neil Shapiro *q == '\0')) 1829c2aa98e2SPeter Wemm { 1830c2aa98e2SPeter Wemm if (tTd(34, 11)) 183112ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped)\n"); 1832c2aa98e2SPeter Wemm continue; 1833c2aa98e2SPeter Wemm } 1834c2aa98e2SPeter Wemm 1835c2aa98e2SPeter Wemm /* handle Resent-... headers specially */ 1836c2aa98e2SPeter Wemm if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 1837c2aa98e2SPeter Wemm { 1838c2aa98e2SPeter Wemm if (tTd(34, 11)) 183912ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (resent))\n"); 1840c2aa98e2SPeter Wemm continue; 1841c2aa98e2SPeter Wemm } 1842c2aa98e2SPeter Wemm 1843c2aa98e2SPeter Wemm /* suppress return receipts if requested */ 1844c2aa98e2SPeter Wemm if (bitset(H_RECEIPTTO, h->h_flags) && 1845c2aa98e2SPeter Wemm (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) 1846c2aa98e2SPeter Wemm { 1847c2aa98e2SPeter Wemm if (tTd(34, 11)) 184812ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (receipt))\n"); 1849c2aa98e2SPeter Wemm continue; 1850c2aa98e2SPeter Wemm } 1851c2aa98e2SPeter Wemm 1852c2aa98e2SPeter Wemm /* macro expand value if generated internally */ 18533299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) || 18543299c2f1SGregory Neil Shapiro bitset(H_BINDLATE, h->h_flags)) 1855c2aa98e2SPeter Wemm { 1856951742c4SGregory Neil Shapiro expand(p, buf, sizeof(buf), e); 1857c2aa98e2SPeter Wemm p = buf; 1858c2aa98e2SPeter Wemm if (*p == '\0') 1859c2aa98e2SPeter Wemm { 1860c2aa98e2SPeter Wemm if (tTd(34, 11)) 186112ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- null value)\n"); 1862c2aa98e2SPeter Wemm continue; 1863c2aa98e2SPeter Wemm } 1864c2aa98e2SPeter Wemm } 1865c2aa98e2SPeter Wemm 1866c2aa98e2SPeter Wemm if (bitset(H_BCC, h->h_flags)) 1867c2aa98e2SPeter Wemm { 1868c2aa98e2SPeter Wemm /* Bcc: field -- either truncate or delete */ 1869c2aa98e2SPeter Wemm if (bitset(EF_DELETE_BCC, e->e_flags)) 1870c2aa98e2SPeter Wemm { 1871c2aa98e2SPeter Wemm if (tTd(34, 11)) 187212ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- bcc)\n"); 1873c2aa98e2SPeter Wemm } 1874c2aa98e2SPeter Wemm else 1875c2aa98e2SPeter Wemm { 1876c2aa98e2SPeter Wemm /* no other recipient headers: truncate value */ 1877951742c4SGregory Neil Shapiro (void) sm_strlcpyn(obuf, sizeof(obuf), 2, 187812ed1c7cSGregory Neil Shapiro h->h_field, ":"); 1879567a2fc9SGregory Neil Shapiro if (!putline(obuf, mci)) 1880567a2fc9SGregory Neil Shapiro goto writeerr; 1881c2aa98e2SPeter Wemm } 1882c2aa98e2SPeter Wemm continue; 1883c2aa98e2SPeter Wemm } 1884c2aa98e2SPeter Wemm 1885c2aa98e2SPeter Wemm if (tTd(34, 11)) 188612ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 1887c2aa98e2SPeter Wemm 1888c2aa98e2SPeter Wemm if (bitset(H_FROM|H_RCPT, h->h_flags)) 1889c2aa98e2SPeter Wemm { 1890c2aa98e2SPeter Wemm /* address field */ 1891c2aa98e2SPeter Wemm bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 1892c2aa98e2SPeter Wemm 1893c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 189412ed1c7cSGregory Neil Shapiro oldstyle = false; 189541f3d2ceSGregory Neil Shapiro commaize(h, p, oldstyle, mci, e, 189641f3d2ceSGregory Neil Shapiro PXLF_HEADER | PXLF_STRIPMQUOTE); 1897c2aa98e2SPeter Wemm } 1898c2aa98e2SPeter Wemm else 1899c2aa98e2SPeter Wemm { 1900567a2fc9SGregory Neil Shapiro if (!put_vanilla_header(h, p, mci)) 1901567a2fc9SGregory Neil Shapiro goto writeerr; 1902c2aa98e2SPeter Wemm } 1903c2aa98e2SPeter Wemm } 1904c2aa98e2SPeter Wemm 1905c2aa98e2SPeter Wemm /* 1906c2aa98e2SPeter Wemm ** If we are converting this to a MIME message, add the 19073299c2f1SGregory Neil Shapiro ** MIME headers (but not in MIME mode!). 1908c2aa98e2SPeter Wemm */ 1909c2aa98e2SPeter Wemm 1910c2aa98e2SPeter Wemm #if MIME8TO7 1911c2aa98e2SPeter Wemm if (bitset(MM_MIME8BIT, MimeMode) && 1912c2aa98e2SPeter Wemm bitset(EF_HAS8BIT, e->e_flags) && 1913c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 1914c2aa98e2SPeter Wemm !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 19153299c2f1SGregory Neil Shapiro !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) && 19163299c2f1SGregory Neil Shapiro hvalue("MIME-Version", e->e_header) == NULL) 1917c2aa98e2SPeter Wemm { 1918567a2fc9SGregory Neil Shapiro if (!putline("MIME-Version: 1.0", mci)) 1919567a2fc9SGregory Neil Shapiro goto writeerr; 1920c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL) 1921c2aa98e2SPeter Wemm { 1922951742c4SGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof(obuf), 1923c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s", 1924c2aa98e2SPeter Wemm defcharset(e)); 1925567a2fc9SGregory Neil Shapiro if (!putline(obuf, mci)) 1926567a2fc9SGregory Neil Shapiro goto writeerr; 1927c2aa98e2SPeter Wemm } 1928567a2fc9SGregory Neil Shapiro if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL 1929567a2fc9SGregory Neil Shapiro && !putline("Content-Transfer-Encoding: 8bit", mci)) 1930567a2fc9SGregory Neil Shapiro goto writeerr; 1931c2aa98e2SPeter Wemm } 19323299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */ 1933567a2fc9SGregory Neil Shapiro return true; 1934567a2fc9SGregory Neil Shapiro 1935567a2fc9SGregory Neil Shapiro writeerr: 1936567a2fc9SGregory Neil Shapiro return false; 1937c2aa98e2SPeter Wemm } 1938951742c4SGregory Neil Shapiro 193912ed1c7cSGregory Neil Shapiro /* 1940c2aa98e2SPeter Wemm ** PUT_VANILLA_HEADER -- output a fairly ordinary header 1941c2aa98e2SPeter Wemm ** 1942c2aa98e2SPeter Wemm ** Parameters: 1943c2aa98e2SPeter Wemm ** h -- the structure describing this header 1944c2aa98e2SPeter Wemm ** v -- the value of this header 1945c2aa98e2SPeter Wemm ** mci -- the connection info for output 1946c2aa98e2SPeter Wemm ** 1947c2aa98e2SPeter Wemm ** Returns: 1948355d91e3SGregory Neil Shapiro ** true iff header was written successfully 1949c2aa98e2SPeter Wemm */ 1950c2aa98e2SPeter Wemm 1951567a2fc9SGregory Neil Shapiro static bool 1952c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci) 1953c2aa98e2SPeter Wemm HDR *h; 1954c2aa98e2SPeter Wemm char *v; 1955c2aa98e2SPeter Wemm MCI *mci; 1956c2aa98e2SPeter Wemm { 1957c2aa98e2SPeter Wemm register char *nlp; 1958c2aa98e2SPeter Wemm register char *obp; 1959c2aa98e2SPeter Wemm int putflags; 1960684b2a5fSGregory Neil Shapiro char obuf[MAXLINE + 256]; /* additional length for h_field */ 1961c2aa98e2SPeter Wemm 1962951742c4SGregory Neil Shapiro putflags = PXLF_HEADER | PXLF_STRIPMQUOTE; 1963c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1964c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 1965951742c4SGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field); 1966c2aa98e2SPeter Wemm obp = obuf + strlen(obuf); 1967c2aa98e2SPeter Wemm while ((nlp = strchr(v, '\n')) != NULL) 1968c2aa98e2SPeter Wemm { 1969c2aa98e2SPeter Wemm int l; 1970c2aa98e2SPeter Wemm 1971c2aa98e2SPeter Wemm l = nlp - v; 19727660b554SGregory Neil Shapiro 19737660b554SGregory Neil Shapiro /* 19747660b554SGregory Neil Shapiro ** XXX This is broken for SPACELEFT()==0 19757660b554SGregory Neil Shapiro ** However, SPACELEFT() is always > 0 unless MAXLINE==1. 19767660b554SGregory Neil Shapiro */ 19777660b554SGregory Neil Shapiro 19783299c2f1SGregory Neil Shapiro if (SPACELEFT(obuf, obp) - 1 < (size_t) l) 1979c2aa98e2SPeter Wemm l = SPACELEFT(obuf, obp) - 1; 1980c2aa98e2SPeter Wemm 198112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); 1982567a2fc9SGregory Neil Shapiro if (!putxline(obuf, strlen(obuf), mci, putflags)) 1983567a2fc9SGregory Neil Shapiro goto writeerr; 1984c2aa98e2SPeter Wemm v += l + 1; 1985c2aa98e2SPeter Wemm obp = obuf; 1986c2aa98e2SPeter Wemm if (*v != ' ' && *v != '\t') 1987c2aa98e2SPeter Wemm *obp++ = ' '; 1988c2aa98e2SPeter Wemm } 19897660b554SGregory Neil Shapiro 19907660b554SGregory Neil Shapiro /* XXX This is broken for SPACELEFT()==0 */ 199112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", 199212ed1c7cSGregory Neil Shapiro (int) (SPACELEFT(obuf, obp) - 1), v); 1993567a2fc9SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags); 1994567a2fc9SGregory Neil Shapiro 1995567a2fc9SGregory Neil Shapiro writeerr: 1996567a2fc9SGregory Neil Shapiro return false; 1997c2aa98e2SPeter Wemm } 1998951742c4SGregory Neil Shapiro 199912ed1c7cSGregory Neil Shapiro /* 2000c2aa98e2SPeter Wemm ** COMMAIZE -- output a header field, making a comma-translated list. 2001c2aa98e2SPeter Wemm ** 2002c2aa98e2SPeter Wemm ** Parameters: 2003c2aa98e2SPeter Wemm ** h -- the header field to output. 2004c2aa98e2SPeter Wemm ** p -- the value to put in it. 200512ed1c7cSGregory Neil Shapiro ** oldstyle -- true if this is an old style header. 2006c2aa98e2SPeter Wemm ** mci -- the connection information. 2007c2aa98e2SPeter Wemm ** e -- the envelope containing the message. 200841f3d2ceSGregory Neil Shapiro ** putflags -- flags for putxline() 2009c2aa98e2SPeter Wemm ** 2010c2aa98e2SPeter Wemm ** Returns: 2011355d91e3SGregory Neil Shapiro ** true iff header field was written successfully 2012c2aa98e2SPeter Wemm ** 2013c2aa98e2SPeter Wemm ** Side Effects: 2014951742c4SGregory Neil Shapiro ** outputs "p" to "mci". 2015c2aa98e2SPeter Wemm */ 2016c2aa98e2SPeter Wemm 2017567a2fc9SGregory Neil Shapiro bool 201841f3d2ceSGregory Neil Shapiro commaize(h, p, oldstyle, mci, e, putflags) 2019c2aa98e2SPeter Wemm register HDR *h; 2020c2aa98e2SPeter Wemm register char *p; 2021c2aa98e2SPeter Wemm bool oldstyle; 2022c2aa98e2SPeter Wemm register MCI *mci; 2023c2aa98e2SPeter Wemm register ENVELOPE *e; 202441f3d2ceSGregory Neil Shapiro int putflags; 2025c2aa98e2SPeter Wemm { 2026c2aa98e2SPeter Wemm register char *obp; 2027951742c4SGregory Neil Shapiro int opos, omax, spaces; 202812ed1c7cSGregory Neil Shapiro bool firstone = true; 20297660b554SGregory Neil Shapiro char **res; 2030c2aa98e2SPeter Wemm char obuf[MAXLINE + 3]; 2031c2aa98e2SPeter Wemm 2032c2aa98e2SPeter Wemm /* 2033c2aa98e2SPeter Wemm ** Output the address list translated by the 2034c2aa98e2SPeter Wemm ** mailer and with commas. 2035c2aa98e2SPeter Wemm */ 2036c2aa98e2SPeter Wemm 2037c2aa98e2SPeter Wemm if (tTd(14, 2)) 203812ed1c7cSGregory Neil Shapiro sm_dprintf("commaize(%s:%s)\n", h->h_field, p); 2039c2aa98e2SPeter Wemm 2040c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 2041c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 2042c2aa98e2SPeter Wemm 2043c2aa98e2SPeter Wemm obp = obuf; 2044951742c4SGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field); 2045951742c4SGregory Neil Shapiro /* opos = strlen(obp); instead of the next 3 lines? */ 2046951742c4SGregory Neil Shapiro opos = strlen(h->h_field) + 1; 2047951742c4SGregory Neil Shapiro if (opos > 201) 2048951742c4SGregory Neil Shapiro opos = 201; 2049c2aa98e2SPeter Wemm obp += opos; 2050951742c4SGregory Neil Shapiro 2051951742c4SGregory Neil Shapiro spaces = 0; 2052951742c4SGregory Neil Shapiro while (*p != '\0' && isascii(*p) && isspace(*p)) 2053951742c4SGregory Neil Shapiro { 2054951742c4SGregory Neil Shapiro ++spaces; 2055951742c4SGregory Neil Shapiro ++p; 2056951742c4SGregory Neil Shapiro } 2057951742c4SGregory Neil Shapiro if (spaces > 0) 2058951742c4SGregory Neil Shapiro { 2059951742c4SGregory Neil Shapiro SM_ASSERT(sizeof(obuf) > opos * 2); 2060951742c4SGregory Neil Shapiro 2061951742c4SGregory Neil Shapiro /* 2062951742c4SGregory Neil Shapiro ** Restrict number of spaces to half the length of buffer 2063951742c4SGregory Neil Shapiro ** so the header field body can be put in here too. 2064951742c4SGregory Neil Shapiro ** Note: this is a hack... 2065951742c4SGregory Neil Shapiro */ 2066951742c4SGregory Neil Shapiro 2067951742c4SGregory Neil Shapiro if (spaces > sizeof(obuf) / 2) 2068951742c4SGregory Neil Shapiro spaces = sizeof(obuf) / 2; 2069951742c4SGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces, 2070951742c4SGregory Neil Shapiro ""); 2071951742c4SGregory Neil Shapiro opos += spaces; 2072951742c4SGregory Neil Shapiro obp += spaces; 2073951742c4SGregory Neil Shapiro SM_ASSERT(obp < &obuf[MAXLINE]); 2074951742c4SGregory Neil Shapiro } 2075951742c4SGregory Neil Shapiro 2076c2aa98e2SPeter Wemm omax = mci->mci_mailer->m_linelimit - 2; 2077c2aa98e2SPeter Wemm if (omax < 0 || omax > 78) 2078c2aa98e2SPeter Wemm omax = 78; 2079c2aa98e2SPeter Wemm 2080c2aa98e2SPeter Wemm /* 2081c2aa98e2SPeter Wemm ** Run through the list of values. 2082c2aa98e2SPeter Wemm */ 2083c2aa98e2SPeter Wemm 2084c2aa98e2SPeter Wemm while (*p != '\0') 2085c2aa98e2SPeter Wemm { 2086c2aa98e2SPeter Wemm register char *name; 2087c2aa98e2SPeter Wemm register int c; 2088c2aa98e2SPeter Wemm char savechar; 2089c2aa98e2SPeter Wemm int flags; 20903299c2f1SGregory Neil Shapiro auto int status; 2091c2aa98e2SPeter Wemm 2092c2aa98e2SPeter Wemm /* 2093c2aa98e2SPeter Wemm ** Find the end of the name. New style names 2094c2aa98e2SPeter Wemm ** end with a comma, old style names end with 2095c2aa98e2SPeter Wemm ** a space character. However, spaces do not 2096c2aa98e2SPeter Wemm ** necessarily delimit an old-style name -- at 2097c2aa98e2SPeter Wemm ** signs mean keep going. 2098c2aa98e2SPeter Wemm */ 2099c2aa98e2SPeter Wemm 2100c2aa98e2SPeter Wemm /* find end of name */ 2101c2aa98e2SPeter Wemm while ((isascii(*p) && isspace(*p)) || *p == ',') 2102c2aa98e2SPeter Wemm p++; 2103c2aa98e2SPeter Wemm name = p; 21047660b554SGregory Neil Shapiro res = NULL; 2105c2aa98e2SPeter Wemm for (;;) 2106c2aa98e2SPeter Wemm { 2107c2aa98e2SPeter Wemm auto char *oldp; 2108c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 2109c2aa98e2SPeter Wemm 21107660b554SGregory Neil Shapiro res = prescan(p, oldstyle ? ' ' : ',', pvpbuf, 2111951742c4SGregory Neil Shapiro sizeof(pvpbuf), &oldp, ExtTokenTab, false); 2112c2aa98e2SPeter Wemm p = oldp; 21137660b554SGregory Neil Shapiro #if _FFR_IGNORE_BOGUS_ADDR 21147660b554SGregory Neil Shapiro /* ignore addresses that can't be parsed */ 21157660b554SGregory Neil Shapiro if (res == NULL) 21167660b554SGregory Neil Shapiro { 21177660b554SGregory Neil Shapiro name = p; 21187660b554SGregory Neil Shapiro continue; 21197660b554SGregory Neil Shapiro } 21207660b554SGregory Neil Shapiro #endif /* _FFR_IGNORE_BOGUS_ADDR */ 2121c2aa98e2SPeter Wemm 2122c2aa98e2SPeter Wemm /* look to see if we have an at sign */ 2123c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 2124c2aa98e2SPeter Wemm p++; 2125c2aa98e2SPeter Wemm 2126c2aa98e2SPeter Wemm if (*p != '@') 2127c2aa98e2SPeter Wemm { 2128c2aa98e2SPeter Wemm p = oldp; 2129c2aa98e2SPeter Wemm break; 2130c2aa98e2SPeter Wemm } 213112ed1c7cSGregory Neil Shapiro ++p; 2132c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 2133c2aa98e2SPeter Wemm p++; 2134c2aa98e2SPeter Wemm } 2135c2aa98e2SPeter Wemm /* at the end of one complete name */ 2136c2aa98e2SPeter Wemm 2137c2aa98e2SPeter Wemm /* strip off trailing white space */ 2138c2aa98e2SPeter Wemm while (p >= name && 2139c2aa98e2SPeter Wemm ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 2140c2aa98e2SPeter Wemm p--; 2141c2aa98e2SPeter Wemm if (++p == name) 2142c2aa98e2SPeter Wemm continue; 21437660b554SGregory Neil Shapiro 21447660b554SGregory Neil Shapiro /* 21457660b554SGregory Neil Shapiro ** if prescan() failed go a bit backwards; this is a hack, 21467660b554SGregory Neil Shapiro ** there should be some better error recovery. 21477660b554SGregory Neil Shapiro */ 21487660b554SGregory Neil Shapiro 21497660b554SGregory Neil Shapiro if (res == NULL && p > name && 21507660b554SGregory Neil Shapiro !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 21517660b554SGregory Neil Shapiro --p; 2152c2aa98e2SPeter Wemm savechar = *p; 2153c2aa98e2SPeter Wemm *p = '\0'; 2154c2aa98e2SPeter Wemm 2155c2aa98e2SPeter Wemm /* translate the name to be relative */ 2156c2aa98e2SPeter Wemm flags = RF_HEADERADDR|RF_ADDDOMAIN; 2157c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 2158c2aa98e2SPeter Wemm flags |= RF_SENDERADDR; 2159c2aa98e2SPeter Wemm #if USERDB 2160c2aa98e2SPeter Wemm else if (e->e_from.q_mailer != NULL && 2161c2aa98e2SPeter Wemm bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 2162c2aa98e2SPeter Wemm { 2163c2aa98e2SPeter Wemm char *q; 2164c2aa98e2SPeter Wemm 216512ed1c7cSGregory Neil Shapiro q = udbsender(name, e->e_rpool); 2166c2aa98e2SPeter Wemm if (q != NULL) 2167c2aa98e2SPeter Wemm name = q; 2168c2aa98e2SPeter Wemm } 21693299c2f1SGregory Neil Shapiro #endif /* USERDB */ 21703299c2f1SGregory Neil Shapiro status = EX_OK; 21713299c2f1SGregory Neil Shapiro name = remotename(name, mci->mci_mailer, flags, &status, e); 2172c2aa98e2SPeter Wemm if (*name == '\0') 2173c2aa98e2SPeter Wemm { 2174c2aa98e2SPeter Wemm *p = savechar; 2175c2aa98e2SPeter Wemm continue; 2176c2aa98e2SPeter Wemm } 217712ed1c7cSGregory Neil Shapiro name = denlstring(name, false, true); 2178c2aa98e2SPeter Wemm 2179c2aa98e2SPeter Wemm /* output the name with nice formatting */ 2180c2aa98e2SPeter Wemm opos += strlen(name); 2181c2aa98e2SPeter Wemm if (!firstone) 2182c2aa98e2SPeter Wemm opos += 2; 2183c2aa98e2SPeter Wemm if (opos > omax && !firstone) 2184c2aa98e2SPeter Wemm { 218512ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp)); 2186567a2fc9SGregory Neil Shapiro if (!putxline(obuf, strlen(obuf), mci, putflags)) 2187567a2fc9SGregory Neil Shapiro goto writeerr; 2188c2aa98e2SPeter Wemm obp = obuf; 2189951742c4SGregory Neil Shapiro (void) sm_strlcpy(obp, " ", sizeof(obuf)); 2190c2aa98e2SPeter Wemm opos = strlen(obp); 2191c2aa98e2SPeter Wemm obp += opos; 2192c2aa98e2SPeter Wemm opos += strlen(name); 2193c2aa98e2SPeter Wemm } 2194c2aa98e2SPeter Wemm else if (!firstone) 2195c2aa98e2SPeter Wemm { 219612ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp)); 2197c2aa98e2SPeter Wemm obp += 2; 2198c2aa98e2SPeter Wemm } 2199c2aa98e2SPeter Wemm 2200c2aa98e2SPeter Wemm while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 2201c2aa98e2SPeter Wemm *obp++ = c; 220212ed1c7cSGregory Neil Shapiro firstone = false; 2203c2aa98e2SPeter Wemm *p = savechar; 2204c2aa98e2SPeter Wemm } 2205951742c4SGregory Neil Shapiro if (obp < &obuf[sizeof(obuf)]) 2206c2aa98e2SPeter Wemm *obp = '\0'; 22077660b554SGregory Neil Shapiro else 2208951742c4SGregory Neil Shapiro obuf[sizeof(obuf) - 1] = '\0'; 2209567a2fc9SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags); 2210567a2fc9SGregory Neil Shapiro 2211567a2fc9SGregory Neil Shapiro writeerr: 2212567a2fc9SGregory Neil Shapiro return false; 2213c2aa98e2SPeter Wemm } 2214567a2fc9SGregory Neil Shapiro 221512ed1c7cSGregory Neil Shapiro /* 2216c2aa98e2SPeter Wemm ** COPYHEADER -- copy header list 2217c2aa98e2SPeter Wemm ** 2218c2aa98e2SPeter Wemm ** This routine is the equivalent of newstr for header lists 2219c2aa98e2SPeter Wemm ** 2220c2aa98e2SPeter Wemm ** Parameters: 2221c2aa98e2SPeter Wemm ** header -- list of header structures to copy. 222212ed1c7cSGregory Neil Shapiro ** rpool -- resource pool, or NULL 2223c2aa98e2SPeter Wemm ** 2224c2aa98e2SPeter Wemm ** Returns: 2225c2aa98e2SPeter Wemm ** a copy of 'header'. 2226c2aa98e2SPeter Wemm ** 2227c2aa98e2SPeter Wemm ** Side Effects: 2228c2aa98e2SPeter Wemm ** none. 2229c2aa98e2SPeter Wemm */ 2230c2aa98e2SPeter Wemm 2231c2aa98e2SPeter Wemm HDR * 223212ed1c7cSGregory Neil Shapiro copyheader(header, rpool) 2233c2aa98e2SPeter Wemm register HDR *header; 223412ed1c7cSGregory Neil Shapiro SM_RPOOL_T *rpool; 2235c2aa98e2SPeter Wemm { 2236c2aa98e2SPeter Wemm register HDR *newhdr; 2237c2aa98e2SPeter Wemm HDR *ret; 2238c2aa98e2SPeter Wemm register HDR **tail = &ret; 2239c2aa98e2SPeter Wemm 2240c2aa98e2SPeter Wemm while (header != NULL) 2241c2aa98e2SPeter Wemm { 2242951742c4SGregory Neil Shapiro newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr)); 2243c2aa98e2SPeter Wemm STRUCTCOPY(*header, *newhdr); 2244c2aa98e2SPeter Wemm *tail = newhdr; 2245c2aa98e2SPeter Wemm tail = &newhdr->h_link; 2246c2aa98e2SPeter Wemm header = header->h_link; 2247c2aa98e2SPeter Wemm } 2248c2aa98e2SPeter Wemm *tail = NULL; 2249c2aa98e2SPeter Wemm 2250c2aa98e2SPeter Wemm return ret; 2251c2aa98e2SPeter Wemm } 2252951742c4SGregory Neil Shapiro 225312ed1c7cSGregory Neil Shapiro /* 225476b7bf71SPeter Wemm ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header 225576b7bf71SPeter Wemm ** 225676b7bf71SPeter Wemm ** Run through all of the parameters of a MIME header and 225776b7bf71SPeter Wemm ** possibly truncate and rebalance the parameter according 225876b7bf71SPeter Wemm ** to MaxMimeFieldLength. 225976b7bf71SPeter Wemm ** 226076b7bf71SPeter Wemm ** Parameters: 2261f9218d3dSGregory Neil Shapiro ** h -- the header to truncate/rebalance 2262f9218d3dSGregory Neil Shapiro ** e -- the current envelope 226376b7bf71SPeter Wemm ** 226476b7bf71SPeter Wemm ** Returns: 2265c46d91b7SGregory Neil Shapiro ** length of last offending field, 0 if all ok. 226676b7bf71SPeter Wemm ** 226776b7bf71SPeter Wemm ** Side Effects: 226876b7bf71SPeter Wemm ** string modified in place 226976b7bf71SPeter Wemm */ 227076b7bf71SPeter Wemm 2271c46d91b7SGregory Neil Shapiro static size_t 2272f9218d3dSGregory Neil Shapiro fix_mime_header(h, e) 2273f9218d3dSGregory Neil Shapiro HDR *h; 2274f9218d3dSGregory Neil Shapiro ENVELOPE *e; 227576b7bf71SPeter Wemm { 2276f9218d3dSGregory Neil Shapiro char *begin = h->h_value; 227776b7bf71SPeter Wemm char *end; 2278c46d91b7SGregory Neil Shapiro size_t len = 0; 2279c46d91b7SGregory Neil Shapiro size_t retlen = 0; 228076b7bf71SPeter Wemm 2281f9218d3dSGregory Neil Shapiro if (begin == NULL || *begin == '\0') 2282c46d91b7SGregory Neil Shapiro return 0; 228376b7bf71SPeter Wemm 228476b7bf71SPeter Wemm /* Split on each ';' */ 22857660b554SGregory Neil Shapiro /* find_character() never returns NULL */ 228676b7bf71SPeter Wemm while ((end = find_character(begin, ';')) != NULL) 228776b7bf71SPeter Wemm { 228876b7bf71SPeter Wemm char save = *end; 228976b7bf71SPeter Wemm char *bp; 229076b7bf71SPeter Wemm 229176b7bf71SPeter Wemm *end = '\0'; 229276b7bf71SPeter Wemm 2293c46d91b7SGregory Neil Shapiro len = strlen(begin); 2294c46d91b7SGregory Neil Shapiro 229576b7bf71SPeter Wemm /* Shorten individual parameter */ 229676b7bf71SPeter Wemm if (shorten_rfc822_string(begin, MaxMimeFieldLength)) 2297f9218d3dSGregory Neil Shapiro { 2298f9218d3dSGregory Neil Shapiro if (len < MaxMimeFieldLength) 2299f9218d3dSGregory Neil Shapiro { 2300f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus field */ 2301f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 2302f9218d3dSGregory Neil Shapiro "Fixed MIME %s header field (possible attack)", 2303f9218d3dSGregory Neil Shapiro h->h_field); 2304f9218d3dSGregory Neil Shapiro if (tTd(34, 11)) 2305f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header field (possible attack)\n", 2306f9218d3dSGregory Neil Shapiro h->h_field); 2307f9218d3dSGregory Neil Shapiro } 2308f9218d3dSGregory Neil Shapiro else 2309f9218d3dSGregory Neil Shapiro { 2310f9218d3dSGregory Neil Shapiro /* we actually shortened the header */ 2311c46d91b7SGregory Neil Shapiro retlen = len; 2312f9218d3dSGregory Neil Shapiro } 2313f9218d3dSGregory Neil Shapiro } 231476b7bf71SPeter Wemm 231576b7bf71SPeter Wemm /* Collapse the possibly shortened string with rest */ 231676b7bf71SPeter Wemm bp = begin + strlen(begin); 231776b7bf71SPeter Wemm if (bp != end) 231876b7bf71SPeter Wemm { 231976b7bf71SPeter Wemm char *ep = end; 232076b7bf71SPeter Wemm 232176b7bf71SPeter Wemm *end = save; 232276b7bf71SPeter Wemm end = bp; 232376b7bf71SPeter Wemm 232476b7bf71SPeter Wemm /* copy character by character due to overlap */ 232576b7bf71SPeter Wemm while (*ep != '\0') 232676b7bf71SPeter Wemm *bp++ = *ep++; 232776b7bf71SPeter Wemm *bp = '\0'; 232876b7bf71SPeter Wemm } 232976b7bf71SPeter Wemm else 233076b7bf71SPeter Wemm *end = save; 233176b7bf71SPeter Wemm if (*end == '\0') 233276b7bf71SPeter Wemm break; 233376b7bf71SPeter Wemm 233476b7bf71SPeter Wemm /* Move past ';' */ 233576b7bf71SPeter Wemm begin = end + 1; 233676b7bf71SPeter Wemm } 2337c46d91b7SGregory Neil Shapiro return retlen; 233876b7bf71SPeter Wemm } 2339