1c2aa98e2SPeter Wemm /* 25dd76dd0SGregory 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> 16*2fb4f839SGregory Neil Shapiro #include <sm/ixlen.h> 17c2aa98e2SPeter Wemm 184313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: headers.c,v 8.320 2013-11-22 20:51:55 ca Exp $") 193299c2f1SGregory Neil Shapiro 20951742c4SGregory Neil Shapiro static HDR *allocheader __P((char *, char *, int, SM_RPOOL_T *, bool)); 21f9218d3dSGregory Neil Shapiro static size_t fix_mime_header __P((HDR *, ENVELOPE *)); 223299c2f1SGregory Neil Shapiro static int priencode __P((char *)); 23567a2fc9SGregory Neil Shapiro static bool put_vanilla_header __P((HDR *, char *, MCI *)); 24c2aa98e2SPeter Wemm 25c2aa98e2SPeter Wemm /* 26c2aa98e2SPeter Wemm ** SETUPHEADERS -- initialize headers in symbol table 27c2aa98e2SPeter Wemm ** 28c2aa98e2SPeter Wemm ** Parameters: 29c2aa98e2SPeter Wemm ** none 30c2aa98e2SPeter Wemm ** 31c2aa98e2SPeter Wemm ** Returns: 32c2aa98e2SPeter Wemm ** none 33c2aa98e2SPeter Wemm */ 34c2aa98e2SPeter Wemm 35c2aa98e2SPeter Wemm void 36c2aa98e2SPeter Wemm setupheaders() 37c2aa98e2SPeter Wemm { 38c2aa98e2SPeter Wemm struct hdrinfo *hi; 39c2aa98e2SPeter Wemm STAB *s; 40c2aa98e2SPeter Wemm 41c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 42c2aa98e2SPeter Wemm { 43c2aa98e2SPeter Wemm s = stab(hi->hi_field, ST_HEADER, ST_ENTER); 44c2aa98e2SPeter Wemm s->s_header.hi_flags = hi->hi_flags; 45c2aa98e2SPeter Wemm s->s_header.hi_ruleset = NULL; 46c2aa98e2SPeter Wemm } 47c2aa98e2SPeter Wemm } 48951742c4SGregory Neil Shapiro 4912ed1c7cSGregory Neil Shapiro /* 50951742c4SGregory Neil Shapiro ** DOCHOMPHEADER -- process and save a header line. 51c2aa98e2SPeter Wemm ** 52951742c4SGregory Neil Shapiro ** Called by chompheader. 53c2aa98e2SPeter Wemm ** 54c2aa98e2SPeter Wemm ** Parameters: 55c2aa98e2SPeter Wemm ** line -- header as a text line. 56d995d2baSGregory Neil Shapiro ** pflag -- flags for chompheader() (from sendmail.h) 57c2aa98e2SPeter Wemm ** hdrp -- a pointer to the place to save the header. 58c2aa98e2SPeter Wemm ** e -- the envelope including this header. 59c2aa98e2SPeter Wemm ** 60c2aa98e2SPeter Wemm ** Returns: 61c2aa98e2SPeter Wemm ** flags for this header. 62c2aa98e2SPeter Wemm ** 63c2aa98e2SPeter Wemm ** Side Effects: 64c2aa98e2SPeter Wemm ** The header is saved on the header list. 65c2aa98e2SPeter Wemm ** Contents of 'line' are destroyed. 66c2aa98e2SPeter Wemm */ 67c2aa98e2SPeter Wemm 683299c2f1SGregory Neil Shapiro static struct hdrinfo NormalHeader = { NULL, 0, NULL }; 69951742c4SGregory Neil Shapiro static unsigned long dochompheader __P((char *, int, HDR **, ENVELOPE *)); 70c2aa98e2SPeter Wemm 71951742c4SGregory Neil Shapiro static unsigned long 72951742c4SGregory Neil Shapiro dochompheader(line, pflag, hdrp, e) 73c2aa98e2SPeter Wemm char *line; 743299c2f1SGregory Neil Shapiro int pflag; 75c2aa98e2SPeter Wemm HDR **hdrp; 76951742c4SGregory Neil Shapiro ENVELOPE *e; 77c2aa98e2SPeter Wemm { 7812ed1c7cSGregory Neil Shapiro unsigned char mid = '\0'; 79c2aa98e2SPeter Wemm register char *p; 80c2aa98e2SPeter Wemm register HDR *h; 81c2aa98e2SPeter Wemm HDR **hp; 82c2aa98e2SPeter Wemm char *fname; 83c2aa98e2SPeter Wemm char *fvalue; 8412ed1c7cSGregory Neil Shapiro bool cond = false; 853299c2f1SGregory Neil Shapiro bool dropfrom; 86c2aa98e2SPeter Wemm bool headeronly; 87c2aa98e2SPeter Wemm STAB *s; 88c2aa98e2SPeter Wemm struct hdrinfo *hi; 8912ed1c7cSGregory Neil Shapiro bool nullheader = false; 903299c2f1SGregory Neil Shapiro BITMAP256 mopts; 91c2aa98e2SPeter Wemm 92c2aa98e2SPeter Wemm headeronly = hdrp != NULL; 93c2aa98e2SPeter Wemm if (!headeronly) 94c2aa98e2SPeter Wemm hdrp = &e->e_header; 95c2aa98e2SPeter Wemm 96c2aa98e2SPeter Wemm /* strip off options */ 97c2aa98e2SPeter Wemm clrbitmap(mopts); 98c2aa98e2SPeter Wemm p = line; 993299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_USER) && *p == '?') 100c2aa98e2SPeter Wemm { 1013299c2f1SGregory Neil Shapiro int c; 1023299c2f1SGregory Neil Shapiro register char *q; 103c2aa98e2SPeter Wemm 1043299c2f1SGregory Neil Shapiro q = strchr(++p, '?'); 1053299c2f1SGregory Neil Shapiro if (q == NULL) 1063299c2f1SGregory Neil Shapiro goto hse; 1073299c2f1SGregory Neil Shapiro 1083299c2f1SGregory Neil Shapiro *q = '\0'; 1093299c2f1SGregory Neil Shapiro c = *p & 0377; 1103299c2f1SGregory Neil Shapiro 1113299c2f1SGregory Neil Shapiro /* possibly macro conditional */ 1123299c2f1SGregory Neil Shapiro if (c == MACROEXPAND) 113c2aa98e2SPeter Wemm { 1143299c2f1SGregory Neil Shapiro /* catch ?$? */ 1153299c2f1SGregory Neil Shapiro if (*++p == '\0') 1163299c2f1SGregory Neil Shapiro { 1173299c2f1SGregory Neil Shapiro *q = '?'; 1183299c2f1SGregory Neil Shapiro goto hse; 1193299c2f1SGregory Neil Shapiro } 1203299c2f1SGregory Neil Shapiro 12112ed1c7cSGregory Neil Shapiro mid = (unsigned char) *p++; 1223299c2f1SGregory Neil Shapiro 1233299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1243299c2f1SGregory Neil Shapiro if (*p != '\0') 1253299c2f1SGregory Neil Shapiro { 1263299c2f1SGregory Neil Shapiro *q = '?'; 1273299c2f1SGregory Neil Shapiro goto hse; 1283299c2f1SGregory Neil Shapiro } 1293299c2f1SGregory Neil Shapiro } 1303299c2f1SGregory Neil Shapiro else if (*p == '$') 1313299c2f1SGregory Neil Shapiro { 1323299c2f1SGregory Neil Shapiro /* catch ?$? */ 1333299c2f1SGregory Neil Shapiro if (*++p == '\0') 1343299c2f1SGregory Neil Shapiro { 1353299c2f1SGregory Neil Shapiro *q = '?'; 1363299c2f1SGregory Neil Shapiro goto hse; 1373299c2f1SGregory Neil Shapiro } 1383299c2f1SGregory Neil Shapiro 13912ed1c7cSGregory Neil Shapiro mid = (unsigned char) macid(p); 1403299c2f1SGregory Neil Shapiro if (bitset(0200, mid)) 1417660b554SGregory Neil Shapiro { 1423299c2f1SGregory Neil Shapiro p += strlen(macname(mid)) + 2; 1437660b554SGregory Neil Shapiro SM_ASSERT(p <= q); 1447660b554SGregory Neil Shapiro } 1453299c2f1SGregory Neil Shapiro else 1463299c2f1SGregory Neil Shapiro p++; 1473299c2f1SGregory Neil Shapiro 1483299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1493299c2f1SGregory Neil Shapiro if (*p != '\0') 1503299c2f1SGregory Neil Shapiro { 1513299c2f1SGregory Neil Shapiro *q = '?'; 1523299c2f1SGregory Neil Shapiro goto hse; 1533299c2f1SGregory Neil Shapiro } 154c2aa98e2SPeter Wemm } 155c2aa98e2SPeter Wemm else 1563299c2f1SGregory Neil Shapiro { 1573299c2f1SGregory Neil Shapiro while (*p != '\0') 1583299c2f1SGregory Neil Shapiro { 1593299c2f1SGregory Neil Shapiro if (!isascii(*p)) 1603299c2f1SGregory Neil Shapiro { 1613299c2f1SGregory Neil Shapiro *q = '?'; 1623299c2f1SGregory Neil Shapiro goto hse; 1633299c2f1SGregory Neil Shapiro } 1643299c2f1SGregory Neil Shapiro 165c46d91b7SGregory Neil Shapiro setbitn(bitidx(*p), mopts); 16612ed1c7cSGregory Neil Shapiro cond = true; 1673299c2f1SGregory Neil Shapiro p++; 1683299c2f1SGregory Neil Shapiro } 1693299c2f1SGregory Neil Shapiro } 1703299c2f1SGregory Neil Shapiro p = q + 1; 171c2aa98e2SPeter Wemm } 172c2aa98e2SPeter Wemm 173c2aa98e2SPeter Wemm /* find canonical name */ 174c2aa98e2SPeter Wemm fname = p; 175c2aa98e2SPeter Wemm while (isascii(*p) && isgraph(*p) && *p != ':') 176c2aa98e2SPeter Wemm p++; 177c2aa98e2SPeter Wemm fvalue = p; 1785b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p)) 179c2aa98e2SPeter Wemm p++; 180c2aa98e2SPeter Wemm if (*p++ != ':' || fname == fvalue) 181c2aa98e2SPeter Wemm { 1823299c2f1SGregory Neil Shapiro hse: 1833299c2f1SGregory Neil Shapiro syserr("553 5.3.0 header syntax error, line \"%s\"", line); 184c2aa98e2SPeter Wemm return 0; 185c2aa98e2SPeter Wemm } 186c2aa98e2SPeter Wemm *fvalue = '\0'; 187e01d6f61SPeter Wemm fvalue = p; 188e01d6f61SPeter Wemm 189e01d6f61SPeter Wemm /* if the field is null, go ahead and use the default */ 1905b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p)) 191e01d6f61SPeter Wemm p++; 192e01d6f61SPeter Wemm if (*p == '\0') 19312ed1c7cSGregory Neil Shapiro nullheader = true; 194c2aa98e2SPeter Wemm 195c2aa98e2SPeter Wemm /* security scan: long field names are end-of-header */ 196c2aa98e2SPeter Wemm if (strlen(fname) > 100) 197c2aa98e2SPeter Wemm return H_EOH; 198c2aa98e2SPeter Wemm 199c2aa98e2SPeter Wemm /* check to see if it represents a ruleset call */ 2003299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 201c2aa98e2SPeter Wemm { 202c2aa98e2SPeter Wemm char hbuf[50]; 203c2aa98e2SPeter Wemm 204951742c4SGregory Neil Shapiro (void) expand(fvalue, hbuf, sizeof(hbuf), e); 2055b0945b5SGregory Neil Shapiro for (p = hbuf; SM_ISSPACE(*p); ) 206c2aa98e2SPeter Wemm p++; 207c2aa98e2SPeter Wemm if ((*p++ & 0377) == CALLSUBR) 208c2aa98e2SPeter Wemm { 209c2aa98e2SPeter Wemm auto char *endp; 2103299c2f1SGregory Neil Shapiro bool strc; 211c2aa98e2SPeter Wemm 2123299c2f1SGregory Neil Shapiro strc = *p == '+'; /* strip comments? */ 2133299c2f1SGregory Neil Shapiro if (strc) 2143299c2f1SGregory Neil Shapiro ++p; 215c2aa98e2SPeter Wemm if (strtorwset(p, &endp, ST_ENTER) > 0) 216c2aa98e2SPeter Wemm { 217c2aa98e2SPeter Wemm *endp = '\0'; 218c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_ENTER); 21912ed1c7cSGregory Neil Shapiro if (LogLevel > 9 && 22012ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset != NULL) 22112ed1c7cSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 22212ed1c7cSGregory Neil Shapiro "Warning: redefined ruleset for header=%s, old=%s, new=%s", 22312ed1c7cSGregory Neil Shapiro fname, 22412ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset, p); 225c2aa98e2SPeter Wemm s->s_header.hi_ruleset = newstr(p); 2263299c2f1SGregory Neil Shapiro if (!strc) 2273299c2f1SGregory Neil Shapiro s->s_header.hi_flags |= H_STRIPCOMM; 228c2aa98e2SPeter Wemm } 229c2aa98e2SPeter Wemm return 0; 230c2aa98e2SPeter Wemm } 231c2aa98e2SPeter Wemm } 232c2aa98e2SPeter Wemm 233c2aa98e2SPeter Wemm /* see if it is a known type */ 234c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_FIND); 235c2aa98e2SPeter Wemm if (s != NULL) 236c2aa98e2SPeter Wemm hi = &s->s_header; 237c2aa98e2SPeter Wemm else 238c2aa98e2SPeter Wemm hi = &NormalHeader; 239c2aa98e2SPeter Wemm 240c2aa98e2SPeter Wemm if (tTd(31, 9)) 241c2aa98e2SPeter Wemm { 242c2aa98e2SPeter Wemm if (s == NULL) 24312ed1c7cSGregory Neil Shapiro sm_dprintf("no header flags match\n"); 244c2aa98e2SPeter Wemm else 24512ed1c7cSGregory Neil Shapiro sm_dprintf("header match, flags=%lx, ruleset=%s\n", 246c2aa98e2SPeter Wemm hi->hi_flags, 24712ed1c7cSGregory Neil Shapiro hi->hi_ruleset == NULL ? "<NULL>" 24812ed1c7cSGregory Neil Shapiro : hi->hi_ruleset); 249c2aa98e2SPeter Wemm } 250c2aa98e2SPeter Wemm 251c2aa98e2SPeter Wemm /* see if this is a resent message */ 2523299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 2533299c2f1SGregory Neil Shapiro bitset(H_RESENT, hi->hi_flags)) 254c2aa98e2SPeter Wemm e->e_flags |= EF_RESENT; 255c2aa98e2SPeter Wemm 256c2aa98e2SPeter Wemm /* if this is an Errors-To: header keep track of it now */ 2573299c2f1SGregory Neil Shapiro if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly && 258c2aa98e2SPeter Wemm bitset(H_ERRORSTO, hi->hi_flags)) 259c2aa98e2SPeter Wemm (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 260c2aa98e2SPeter Wemm 261c2aa98e2SPeter Wemm /* if this means "end of header" quit now */ 262c2aa98e2SPeter Wemm if (!headeronly && bitset(H_EOH, hi->hi_flags)) 263c2aa98e2SPeter Wemm return hi->hi_flags; 264c2aa98e2SPeter Wemm 265c2aa98e2SPeter Wemm /* 266c2aa98e2SPeter Wemm ** Horrible hack to work around problem with Lotus Notes SMTP 267c2aa98e2SPeter Wemm ** mail gateway, which generates From: headers with newlines in 268c2aa98e2SPeter Wemm ** them and the <address> on the second line. Although this is 269c2aa98e2SPeter Wemm ** legal RFC 822, many MUAs don't handle this properly and thus 270c2aa98e2SPeter Wemm ** never find the actual address. 271c2aa98e2SPeter Wemm */ 272c2aa98e2SPeter Wemm 273c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader) 274c2aa98e2SPeter Wemm { 275c2aa98e2SPeter Wemm while ((p = strchr(fvalue, '\n')) != NULL) 276c2aa98e2SPeter Wemm *p = ' '; 277c2aa98e2SPeter Wemm } 278c2aa98e2SPeter Wemm 279c2aa98e2SPeter Wemm /* 280c2aa98e2SPeter Wemm ** If there is a check ruleset, verify it against the header. 281c2aa98e2SPeter Wemm */ 282c2aa98e2SPeter Wemm 2833299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_CHECK)) 2843299c2f1SGregory Neil Shapiro { 2859d8fddc1SGregory Neil Shapiro int rscheckflags; 2863299c2f1SGregory Neil Shapiro char *rs; 2873299c2f1SGregory Neil Shapiro 2889d8fddc1SGregory Neil Shapiro rscheckflags = RSF_COUNT; 2899d8fddc1SGregory Neil Shapiro if (!bitset(hi->hi_flags, H_FROM|H_RCPT)) 2909d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_UNSTRUCTURED; 291bfb62e91SGregory Neil Shapiro 292bfb62e91SGregory Neil Shapiro /* no ruleset? look for default */ 293bfb62e91SGregory Neil Shapiro rs = hi->hi_ruleset; 2943299c2f1SGregory Neil Shapiro if (rs == NULL) 2953299c2f1SGregory Neil Shapiro { 2963299c2f1SGregory Neil Shapiro s = stab("*", ST_HEADER, ST_FIND); 2973299c2f1SGregory Neil Shapiro if (s != NULL) 2983299c2f1SGregory Neil Shapiro { 2993299c2f1SGregory Neil Shapiro rs = (&s->s_header)->hi_ruleset; 3009d8fddc1SGregory Neil Shapiro if (bitset((&s->s_header)->hi_flags, 3019d8fddc1SGregory Neil Shapiro H_STRIPCOMM)) 3029d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM; 3033299c2f1SGregory Neil Shapiro } 3043299c2f1SGregory Neil Shapiro } 3059d8fddc1SGregory Neil Shapiro else if (bitset(hi->hi_flags, H_STRIPCOMM)) 3069d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM; 3073299c2f1SGregory Neil Shapiro if (rs != NULL) 3083299c2f1SGregory Neil Shapiro { 30912ed1c7cSGregory Neil Shapiro int l, k; 310*2fb4f839SGregory Neil Shapiro char qval[MAXNAME_I]; 311*2fb4f839SGregory Neil Shapiro XLENDECL 3123299c2f1SGregory Neil Shapiro 3133299c2f1SGregory Neil Shapiro l = 0; 314*2fb4f839SGregory Neil Shapiro XLEN('"'); 31512ed1c7cSGregory Neil Shapiro qval[l++] = '"'; 31612ed1c7cSGregory Neil Shapiro 31712ed1c7cSGregory Neil Shapiro /* - 3 to avoid problems with " at the end */ 318*2fb4f839SGregory Neil Shapiro for (k = 0; 319*2fb4f839SGregory Neil Shapiro fvalue[k] != '\0' && l < sizeof(qval) - 3 320*2fb4f839SGregory Neil Shapiro && xlen < MAXNAME - 3; 321*2fb4f839SGregory Neil Shapiro k++) 3223299c2f1SGregory Neil Shapiro { 323*2fb4f839SGregory Neil Shapiro XLEN(fvalue[k]); 32412ed1c7cSGregory Neil Shapiro switch (fvalue[k]) 3253299c2f1SGregory Neil Shapiro { 32612ed1c7cSGregory Neil Shapiro /* XXX other control chars? */ 3273299c2f1SGregory Neil Shapiro case '\011': /* ht */ 3283299c2f1SGregory Neil Shapiro case '\012': /* nl */ 3293299c2f1SGregory Neil Shapiro case '\013': /* vt */ 3303299c2f1SGregory Neil Shapiro case '\014': /* np */ 3313299c2f1SGregory Neil Shapiro case '\015': /* cr */ 33212ed1c7cSGregory Neil Shapiro qval[l++] = ' '; 3333299c2f1SGregory Neil Shapiro break; 3343299c2f1SGregory Neil Shapiro case '"': 335*2fb4f839SGregory Neil Shapiro XLEN('\\'); 33612ed1c7cSGregory Neil Shapiro qval[l++] = '\\'; 3373299c2f1SGregory Neil Shapiro /* FALLTHROUGH */ 3383299c2f1SGregory Neil Shapiro default: 33912ed1c7cSGregory Neil Shapiro qval[l++] = fvalue[k]; 3403299c2f1SGregory Neil Shapiro break; 3413299c2f1SGregory Neil Shapiro } 3423299c2f1SGregory Neil Shapiro } 343*2fb4f839SGregory Neil Shapiro /* just for "completeness": xlen not used afterwards */ 344*2fb4f839SGregory Neil Shapiro XLEN('"'); 34512ed1c7cSGregory Neil Shapiro qval[l++] = '"'; 34612ed1c7cSGregory Neil Shapiro qval[l] = '\0'; 34712ed1c7cSGregory Neil Shapiro k += strlen(fvalue + k); 348*2fb4f839SGregory Neil Shapiro if (k >= sizeof(qval)) 3493299c2f1SGregory Neil Shapiro { 3503299c2f1SGregory Neil Shapiro if (LogLevel > 9) 3513299c2f1SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 3523299c2f1SGregory Neil Shapiro "Warning: truncated header '%s' before check with '%s' len=%d max=%d", 353*2fb4f839SGregory Neil Shapiro fname, rs, k, 354*2fb4f839SGregory Neil Shapiro (int) (sizeof(qval) - 1)); 3553299c2f1SGregory Neil Shapiro } 35612ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 35712ed1c7cSGregory Neil Shapiro macid("{currHeader}"), qval); 35812ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 35912ed1c7cSGregory Neil Shapiro macid("{hdr_name}"), fname); 36012ed1c7cSGregory Neil Shapiro 361951742c4SGregory Neil Shapiro (void) sm_snprintf(qval, sizeof(qval), "%d", k); 36212ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval); 363bfb62e91SGregory Neil Shapiro if (bitset(H_FROM, hi->hi_flags)) 36412ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 36512ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h s"); 366bfb62e91SGregory Neil Shapiro else if (bitset(H_RCPT, hi->hi_flags)) 36712ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 36812ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h r"); 36912ed1c7cSGregory Neil Shapiro else 37012ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 37112ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h"); 3729d8fddc1SGregory Neil Shapiro (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3, 373da7d7b9cSGregory Neil Shapiro NULL, e->e_id, NULL, NULL); 3743299c2f1SGregory Neil Shapiro } 3753299c2f1SGregory Neil Shapiro } 376c2aa98e2SPeter Wemm 377c2aa98e2SPeter Wemm /* 378c2aa98e2SPeter Wemm ** Drop explicit From: if same as what we would generate. 379c2aa98e2SPeter Wemm ** This is to make MH (which doesn't always give a full name) 380c2aa98e2SPeter Wemm ** insert the full name information in all circumstances. 381c2aa98e2SPeter Wemm */ 382c2aa98e2SPeter Wemm 38312ed1c7cSGregory Neil Shapiro dropfrom = false; 384c2aa98e2SPeter Wemm p = "resent-from"; 385c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 386c2aa98e2SPeter Wemm p += 7; 3873299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 388*2fb4f839SGregory Neil Shapiro !bitset(EF_QUEUERUN, e->e_flags) && SM_STRCASEEQ(fname, p)) 389c2aa98e2SPeter Wemm { 390c2aa98e2SPeter Wemm if (e->e_from.q_paddr != NULL && 3913299c2f1SGregory Neil Shapiro e->e_from.q_mailer != NULL && 3923299c2f1SGregory Neil Shapiro bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && 393c2aa98e2SPeter Wemm (strcmp(fvalue, e->e_from.q_paddr) == 0 || 394c2aa98e2SPeter Wemm strcmp(fvalue, e->e_from.q_user) == 0)) 39512ed1c7cSGregory Neil Shapiro dropfrom = true; 3965dd76dd0SGregory Neil Shapiro if (tTd(31, 2)) 3975dd76dd0SGregory Neil Shapiro { 3985dd76dd0SGregory Neil Shapiro sm_dprintf("comparing header from (%s) against default (%s or %s), drop=%d\n", 3995dd76dd0SGregory Neil Shapiro fvalue, e->e_from.q_paddr, e->e_from.q_user, 4005dd76dd0SGregory Neil Shapiro dropfrom); 4015dd76dd0SGregory Neil Shapiro } 402c2aa98e2SPeter Wemm } 403c2aa98e2SPeter Wemm 404c2aa98e2SPeter Wemm /* delete default value for this header */ 405c2aa98e2SPeter Wemm for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 406c2aa98e2SPeter Wemm { 407*2fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(fname, h->h_field) && 4083299c2f1SGregory Neil Shapiro !bitset(H_USER, h->h_flags) && 409c2aa98e2SPeter Wemm !bitset(H_FORCE, h->h_flags)) 410c2aa98e2SPeter Wemm { 411e01d6f61SPeter Wemm if (nullheader) 412e01d6f61SPeter Wemm { 413e01d6f61SPeter Wemm /* user-supplied value was null */ 414e01d6f61SPeter Wemm return 0; 415e01d6f61SPeter Wemm } 4163299c2f1SGregory Neil Shapiro if (dropfrom) 4173299c2f1SGregory Neil Shapiro { 4183299c2f1SGregory Neil Shapiro /* make this look like the user entered it */ 4193299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 4205dd76dd0SGregory Neil Shapiro 4215dd76dd0SGregory Neil Shapiro /* 4225dd76dd0SGregory Neil Shapiro ** If the MH hack is selected, allow to turn 4235dd76dd0SGregory Neil Shapiro ** it off via a mailer flag to avoid problems 4245dd76dd0SGregory Neil Shapiro ** with setups that remove the F flag from 4255dd76dd0SGregory Neil Shapiro ** the RCPT mailer. 4265dd76dd0SGregory Neil Shapiro */ 4275dd76dd0SGregory Neil Shapiro 4285dd76dd0SGregory Neil Shapiro if (bitnset(M_NOMHHACK, 4295dd76dd0SGregory Neil Shapiro e->e_from.q_mailer->m_flags)) 4305dd76dd0SGregory Neil Shapiro { 4315dd76dd0SGregory Neil Shapiro h->h_flags &= ~H_CHECK; 4325dd76dd0SGregory Neil Shapiro } 4333299c2f1SGregory Neil Shapiro return hi->hi_flags; 4343299c2f1SGregory Neil Shapiro } 435c2aa98e2SPeter Wemm h->h_value = NULL; 436c2aa98e2SPeter Wemm if (!cond) 437c2aa98e2SPeter Wemm { 438c2aa98e2SPeter Wemm /* copy conditions from default case */ 4393299c2f1SGregory Neil Shapiro memmove((char *) mopts, (char *) h->h_mflags, 440951742c4SGregory Neil Shapiro sizeof(mopts)); 441c2aa98e2SPeter Wemm } 4423299c2f1SGregory Neil Shapiro h->h_macro = mid; 443c2aa98e2SPeter Wemm } 444c2aa98e2SPeter Wemm } 445c2aa98e2SPeter Wemm 446c2aa98e2SPeter Wemm /* create a new node */ 447*2fb4f839SGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_tagged_x(e->e_rpool, sizeof(*h), "header", 448*2fb4f839SGregory Neil Shapiro pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1); 449*2fb4f839SGregory Neil Shapiro h->h_field = sm_rpool_strdup_tagged_x(e->e_rpool, fname, "h_field", 450*2fb4f839SGregory Neil Shapiro pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1); 451*2fb4f839SGregory Neil Shapiro h->h_value = sm_rpool_strdup_tagged_x(e->e_rpool, fvalue, "h_value", 452*2fb4f839SGregory Neil Shapiro pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1); 453c2aa98e2SPeter Wemm h->h_link = NULL; 454951742c4SGregory Neil Shapiro memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts)); 4553299c2f1SGregory Neil Shapiro h->h_macro = mid; 456c2aa98e2SPeter Wemm *hp = h; 457c2aa98e2SPeter Wemm h->h_flags = hi->hi_flags; 458d995d2baSGregory Neil Shapiro if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE)) 4593299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 460c2aa98e2SPeter Wemm 461c2aa98e2SPeter Wemm /* strip EOH flag if parsing MIME headers */ 462c2aa98e2SPeter Wemm if (headeronly) 463c2aa98e2SPeter Wemm h->h_flags &= ~H_EOH; 4643299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 465c2aa98e2SPeter Wemm h->h_flags |= H_DEFAULT; 4663299c2f1SGregory Neil Shapiro if (cond || mid != '\0') 467c2aa98e2SPeter Wemm h->h_flags |= H_CHECK; 468c2aa98e2SPeter Wemm 469c2aa98e2SPeter Wemm /* hack to see if this is a new format message */ 4703299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 4713299c2f1SGregory Neil Shapiro bitset(H_RCPT|H_FROM, h->h_flags) && 472c2aa98e2SPeter Wemm (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 473c2aa98e2SPeter Wemm strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 474c2aa98e2SPeter Wemm { 475c2aa98e2SPeter Wemm e->e_flags &= ~EF_OLDSTYLE; 476c2aa98e2SPeter Wemm } 477c2aa98e2SPeter Wemm 478c2aa98e2SPeter Wemm return h->h_flags; 479c2aa98e2SPeter Wemm } 480951742c4SGregory Neil Shapiro 481951742c4SGregory Neil Shapiro /* 482951742c4SGregory Neil Shapiro ** CHOMPHEADER -- process and save a header line. 483951742c4SGregory Neil Shapiro ** 484951742c4SGregory Neil Shapiro ** Called by collect, readcf, and readqf to deal with header lines. 485951742c4SGregory Neil Shapiro ** This is just a wrapper for dochompheader(). 486951742c4SGregory Neil Shapiro ** 487951742c4SGregory Neil Shapiro ** Parameters: 488951742c4SGregory Neil Shapiro ** line -- header as a text line. 489951742c4SGregory Neil Shapiro ** pflag -- flags for chompheader() (from sendmail.h) 490951742c4SGregory Neil Shapiro ** hdrp -- a pointer to the place to save the header. 491951742c4SGregory Neil Shapiro ** e -- the envelope including this header. 492951742c4SGregory Neil Shapiro ** 493951742c4SGregory Neil Shapiro ** Returns: 494951742c4SGregory Neil Shapiro ** flags for this header. 495951742c4SGregory Neil Shapiro ** 496951742c4SGregory Neil Shapiro ** Side Effects: 497951742c4SGregory Neil Shapiro ** The header is saved on the header list. 498951742c4SGregory Neil Shapiro ** Contents of 'line' are destroyed. 499951742c4SGregory Neil Shapiro */ 500951742c4SGregory Neil Shapiro 501951742c4SGregory Neil Shapiro 502951742c4SGregory Neil Shapiro unsigned long 503951742c4SGregory Neil Shapiro chompheader(line, pflag, hdrp, e) 504951742c4SGregory Neil Shapiro char *line; 505951742c4SGregory Neil Shapiro int pflag; 506951742c4SGregory Neil Shapiro HDR **hdrp; 507951742c4SGregory Neil Shapiro register ENVELOPE *e; 508951742c4SGregory Neil Shapiro { 509951742c4SGregory Neil Shapiro unsigned long rval; 510951742c4SGregory Neil Shapiro 511951742c4SGregory Neil Shapiro if (tTd(31, 6)) 512951742c4SGregory Neil Shapiro { 513951742c4SGregory Neil Shapiro sm_dprintf("chompheader: "); 514951742c4SGregory Neil Shapiro xputs(sm_debug_file(), line); 515951742c4SGregory Neil Shapiro sm_dprintf("\n"); 516951742c4SGregory Neil Shapiro } 517951742c4SGregory Neil Shapiro 518951742c4SGregory Neil Shapiro /* quote this if user (not config file) input */ 519951742c4SGregory Neil Shapiro if (bitset(pflag, CHHDR_USER)) 520951742c4SGregory Neil Shapiro { 521*2fb4f839SGregory Neil Shapiro char xbuf[MAXLINE]; /* EAI:ok; actual buffer might be greater */ 522951742c4SGregory Neil Shapiro char *xbp = NULL; 523951742c4SGregory Neil Shapiro int xbufs; 524951742c4SGregory Neil Shapiro 525951742c4SGregory Neil Shapiro xbufs = sizeof(xbuf); 526*2fb4f839SGregory Neil Shapiro xbp = quote_internal_chars(line, xbuf, &xbufs, NULL); 527951742c4SGregory Neil Shapiro if (tTd(31, 7)) 528951742c4SGregory Neil Shapiro { 529951742c4SGregory Neil Shapiro sm_dprintf("chompheader: quoted: "); 530951742c4SGregory Neil Shapiro xputs(sm_debug_file(), xbp); 531951742c4SGregory Neil Shapiro sm_dprintf("\n"); 532951742c4SGregory Neil Shapiro } 533951742c4SGregory Neil Shapiro rval = dochompheader(xbp, pflag, hdrp, e); 534951742c4SGregory Neil Shapiro if (xbp != xbuf) 535951742c4SGregory Neil Shapiro sm_free(xbp); 536951742c4SGregory Neil Shapiro } 537951742c4SGregory Neil Shapiro else 538951742c4SGregory Neil Shapiro rval = dochompheader(line, pflag, hdrp, e); 539951742c4SGregory Neil Shapiro 540951742c4SGregory Neil Shapiro return rval; 541951742c4SGregory Neil Shapiro } 542951742c4SGregory Neil Shapiro 54312ed1c7cSGregory Neil Shapiro /* 544bfb62e91SGregory Neil Shapiro ** ALLOCHEADER -- allocate a header entry 545bfb62e91SGregory Neil Shapiro ** 546bfb62e91SGregory Neil Shapiro ** Parameters: 547951742c4SGregory Neil Shapiro ** field -- the name of the header field (will not be copied). 548951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied). 549bfb62e91SGregory Neil Shapiro ** flags -- flags to add to h_flags. 550bfb62e91SGregory Neil Shapiro ** rp -- resource pool for allocations 551951742c4SGregory Neil Shapiro ** space -- add leading space? 552bfb62e91SGregory Neil Shapiro ** 553bfb62e91SGregory Neil Shapiro ** Returns: 554bfb62e91SGregory Neil Shapiro ** Pointer to a newly allocated and populated HDR. 555951742c4SGregory Neil Shapiro ** 556951742c4SGregory Neil Shapiro ** Notes: 557951742c4SGregory Neil Shapiro ** o field and value must be in internal format, i.e., 558951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars(). 559951742c4SGregory Neil Shapiro ** o maybe add more flags to decide: 560951742c4SGregory Neil Shapiro ** - what to copy (field/value) 561951742c4SGregory Neil Shapiro ** - whether to convert value to an internal format 562bfb62e91SGregory Neil Shapiro */ 563bfb62e91SGregory Neil Shapiro 564bfb62e91SGregory Neil Shapiro static HDR * 565951742c4SGregory Neil Shapiro allocheader(field, value, flags, rp, space) 566bfb62e91SGregory Neil Shapiro char *field; 567bfb62e91SGregory Neil Shapiro char *value; 568bfb62e91SGregory Neil Shapiro int flags; 569bfb62e91SGregory Neil Shapiro SM_RPOOL_T *rp; 570951742c4SGregory Neil Shapiro bool space; 571bfb62e91SGregory Neil Shapiro { 572bfb62e91SGregory Neil Shapiro HDR *h; 573bfb62e91SGregory Neil Shapiro STAB *s; 574bfb62e91SGregory Neil Shapiro 575bfb62e91SGregory Neil Shapiro /* find info struct */ 576bfb62e91SGregory Neil Shapiro s = stab(field, ST_HEADER, ST_FIND); 577bfb62e91SGregory Neil Shapiro 578bfb62e91SGregory Neil Shapiro /* allocate space for new header */ 579951742c4SGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h)); 580bfb62e91SGregory Neil Shapiro h->h_field = field; 581951742c4SGregory Neil Shapiro if (space) 582951742c4SGregory Neil Shapiro { 583951742c4SGregory Neil Shapiro size_t l; 584951742c4SGregory Neil Shapiro char *n; 585951742c4SGregory Neil Shapiro 586951742c4SGregory Neil Shapiro l = strlen(value); 587951742c4SGregory Neil Shapiro SM_ASSERT(l + 2 > l); 588951742c4SGregory Neil Shapiro n = sm_rpool_malloc_x(rp, l + 2); 589951742c4SGregory Neil Shapiro n[0] = ' '; 590951742c4SGregory Neil Shapiro n[1] = '\0'; 591951742c4SGregory Neil Shapiro sm_strlcpy(n + 1, value, l + 1); 592951742c4SGregory Neil Shapiro h->h_value = n; 593951742c4SGregory Neil Shapiro } 594951742c4SGregory Neil Shapiro else 595bfb62e91SGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(rp, value); 596bfb62e91SGregory Neil Shapiro h->h_flags = flags; 597bfb62e91SGregory Neil Shapiro if (s != NULL) 598bfb62e91SGregory Neil Shapiro h->h_flags |= s->s_header.hi_flags; 599bfb62e91SGregory Neil Shapiro clrbitmap(h->h_mflags); 600bfb62e91SGregory Neil Shapiro h->h_macro = '\0'; 601bfb62e91SGregory Neil Shapiro 602bfb62e91SGregory Neil Shapiro return h; 603bfb62e91SGregory Neil Shapiro } 604951742c4SGregory Neil Shapiro 605bfb62e91SGregory Neil Shapiro /* 606c2aa98e2SPeter Wemm ** ADDHEADER -- add a header entry to the end of the queue. 607c2aa98e2SPeter Wemm ** 608c2aa98e2SPeter Wemm ** This bypasses the special checking of chompheader. 609c2aa98e2SPeter Wemm ** 610c2aa98e2SPeter Wemm ** Parameters: 611951742c4SGregory Neil Shapiro ** field -- the name of the header field (will not be copied). 612951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied). 6133299c2f1SGregory Neil Shapiro ** flags -- flags to add to h_flags. 61412ed1c7cSGregory Neil Shapiro ** e -- envelope. 615951742c4SGregory Neil Shapiro ** space -- add leading space? 616c2aa98e2SPeter Wemm ** 617c2aa98e2SPeter Wemm ** Returns: 618c2aa98e2SPeter Wemm ** none. 619c2aa98e2SPeter Wemm ** 620c2aa98e2SPeter Wemm ** Side Effects: 621c2aa98e2SPeter Wemm ** adds the field on the list of headers for this envelope. 622951742c4SGregory Neil Shapiro ** 623951742c4SGregory Neil Shapiro ** Notes: field and value must be in internal format, i.e., 624951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars(). 625c2aa98e2SPeter Wemm */ 626c2aa98e2SPeter Wemm 627c2aa98e2SPeter Wemm void 628951742c4SGregory Neil Shapiro addheader(field, value, flags, e, space) 629c2aa98e2SPeter Wemm char *field; 630c2aa98e2SPeter Wemm char *value; 6313299c2f1SGregory Neil Shapiro int flags; 63212ed1c7cSGregory Neil Shapiro ENVELOPE *e; 633951742c4SGregory Neil Shapiro bool space; 634c2aa98e2SPeter Wemm { 635c2aa98e2SPeter Wemm register HDR *h; 636c2aa98e2SPeter Wemm HDR **hp; 63712ed1c7cSGregory Neil Shapiro HDR **hdrlist = &e->e_header; 638c2aa98e2SPeter Wemm 639c2aa98e2SPeter Wemm /* find current place in list -- keep back pointer? */ 640c2aa98e2SPeter Wemm for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 641c2aa98e2SPeter Wemm { 642*2fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(field, h->h_field)) 643c2aa98e2SPeter Wemm break; 644c2aa98e2SPeter Wemm } 645c2aa98e2SPeter Wemm 646c2aa98e2SPeter Wemm /* allocate space for new header */ 647951742c4SGregory Neil Shapiro h = allocheader(field, value, flags, e->e_rpool, space); 648c2aa98e2SPeter Wemm h->h_link = *hp; 649c2aa98e2SPeter Wemm *hp = h; 650c2aa98e2SPeter Wemm } 651951742c4SGregory Neil Shapiro 65212ed1c7cSGregory Neil Shapiro /* 653bfb62e91SGregory Neil Shapiro ** INSHEADER -- insert a header entry at the specified index 654bfb62e91SGregory Neil Shapiro ** This bypasses the special checking of chompheader. 655bfb62e91SGregory Neil Shapiro ** 656bfb62e91SGregory Neil Shapiro ** Parameters: 657bfb62e91SGregory Neil Shapiro ** idx -- index into the header list at which to insert 658951742c4SGregory Neil Shapiro ** field -- the name of the header field (will be copied). 659951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied). 660bfb62e91SGregory Neil Shapiro ** flags -- flags to add to h_flags. 661bfb62e91SGregory Neil Shapiro ** e -- envelope. 662951742c4SGregory Neil Shapiro ** space -- add leading space? 663bfb62e91SGregory Neil Shapiro ** 664bfb62e91SGregory Neil Shapiro ** Returns: 665bfb62e91SGregory Neil Shapiro ** none. 666bfb62e91SGregory Neil Shapiro ** 667bfb62e91SGregory Neil Shapiro ** Side Effects: 668bfb62e91SGregory Neil Shapiro ** inserts the field on the list of headers for this envelope. 669951742c4SGregory Neil Shapiro ** 670951742c4SGregory Neil Shapiro ** Notes: 671951742c4SGregory Neil Shapiro ** - field and value must be in internal format, i.e., 672951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars(). 673951742c4SGregory Neil Shapiro ** - the header list contains headers that might not be 674951742c4SGregory Neil Shapiro ** sent "out" (see putheader(): "skip"), hence there is no 675951742c4SGregory Neil Shapiro ** reliable way to insert a header at an exact position 676951742c4SGregory Neil Shapiro ** (except at the front or end). 677bfb62e91SGregory Neil Shapiro */ 678bfb62e91SGregory Neil Shapiro 679bfb62e91SGregory Neil Shapiro void 680951742c4SGregory Neil Shapiro insheader(idx, field, value, flags, e, space) 681bfb62e91SGregory Neil Shapiro int idx; 682bfb62e91SGregory Neil Shapiro char *field; 683bfb62e91SGregory Neil Shapiro char *value; 684bfb62e91SGregory Neil Shapiro int flags; 685bfb62e91SGregory Neil Shapiro ENVELOPE *e; 686951742c4SGregory Neil Shapiro bool space; 687bfb62e91SGregory Neil Shapiro { 688bfb62e91SGregory Neil Shapiro HDR *h, *srch, *last = NULL; 689bfb62e91SGregory Neil Shapiro 690bfb62e91SGregory Neil Shapiro /* allocate space for new header */ 691951742c4SGregory Neil Shapiro h = allocheader(field, value, flags, e->e_rpool, space); 692bfb62e91SGregory Neil Shapiro 693bfb62e91SGregory Neil Shapiro /* find insertion position */ 694bfb62e91SGregory Neil Shapiro for (srch = e->e_header; srch != NULL && idx > 0; 695bfb62e91SGregory Neil Shapiro srch = srch->h_link, idx--) 696bfb62e91SGregory Neil Shapiro last = srch; 697bfb62e91SGregory Neil Shapiro 698bfb62e91SGregory Neil Shapiro if (e->e_header == NULL) 699bfb62e91SGregory Neil Shapiro { 700bfb62e91SGregory Neil Shapiro e->e_header = h; 701bfb62e91SGregory Neil Shapiro h->h_link = NULL; 702bfb62e91SGregory Neil Shapiro } 703bfb62e91SGregory Neil Shapiro else if (srch == NULL) 704bfb62e91SGregory Neil Shapiro { 705bfb62e91SGregory Neil Shapiro SM_ASSERT(last != NULL); 706bfb62e91SGregory Neil Shapiro last->h_link = h; 707bfb62e91SGregory Neil Shapiro h->h_link = NULL; 708bfb62e91SGregory Neil Shapiro } 709bfb62e91SGregory Neil Shapiro else 710bfb62e91SGregory Neil Shapiro { 711bfb62e91SGregory Neil Shapiro h->h_link = srch->h_link; 712bfb62e91SGregory Neil Shapiro srch->h_link = h; 713bfb62e91SGregory Neil Shapiro } 714bfb62e91SGregory Neil Shapiro } 715951742c4SGregory Neil Shapiro 716bfb62e91SGregory Neil Shapiro /* 717c2aa98e2SPeter Wemm ** HVALUE -- return value of a header. 718c2aa98e2SPeter Wemm ** 719c2aa98e2SPeter Wemm ** Only "real" fields (i.e., ones that have not been supplied 720c2aa98e2SPeter Wemm ** as a default) are used. 721c2aa98e2SPeter Wemm ** 722c2aa98e2SPeter Wemm ** Parameters: 723c2aa98e2SPeter Wemm ** field -- the field name. 724c2aa98e2SPeter Wemm ** header -- the header list. 725c2aa98e2SPeter Wemm ** 726c2aa98e2SPeter Wemm ** Returns: 727951742c4SGregory Neil Shapiro ** pointer to the value part (internal format). 728c2aa98e2SPeter Wemm ** NULL if not found. 729c2aa98e2SPeter Wemm ** 730c2aa98e2SPeter Wemm ** Side Effects: 731c2aa98e2SPeter Wemm ** none. 732c2aa98e2SPeter Wemm */ 733c2aa98e2SPeter Wemm 734c2aa98e2SPeter Wemm char * 735c2aa98e2SPeter Wemm hvalue(field, header) 736c2aa98e2SPeter Wemm char *field; 737c2aa98e2SPeter Wemm HDR *header; 738c2aa98e2SPeter Wemm { 739c2aa98e2SPeter Wemm register HDR *h; 740c2aa98e2SPeter Wemm 741c2aa98e2SPeter Wemm for (h = header; h != NULL; h = h->h_link) 742c2aa98e2SPeter Wemm { 743c2aa98e2SPeter Wemm if (!bitset(H_DEFAULT, h->h_flags) && 744*2fb4f839SGregory Neil Shapiro SM_STRCASEEQ(h->h_field, field)) 7459bd497b8SGregory Neil Shapiro { 7469bd497b8SGregory Neil Shapiro char *s; 7479bd497b8SGregory Neil Shapiro 7489bd497b8SGregory Neil Shapiro s = h->h_value; 7499bd497b8SGregory Neil Shapiro if (s == NULL) 7509bd497b8SGregory Neil Shapiro return NULL; 7515b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*s)) 7529bd497b8SGregory Neil Shapiro s++; 7539bd497b8SGregory Neil Shapiro return s; 7549bd497b8SGregory Neil Shapiro } 755c2aa98e2SPeter Wemm } 7563299c2f1SGregory Neil Shapiro return NULL; 757c2aa98e2SPeter Wemm } 758951742c4SGregory Neil Shapiro 75912ed1c7cSGregory Neil Shapiro /* 760c2aa98e2SPeter Wemm ** ISHEADER -- predicate telling if argument is a header. 761c2aa98e2SPeter Wemm ** 762c2aa98e2SPeter Wemm ** A line is a header if it has a single word followed by 763c2aa98e2SPeter Wemm ** optional white space followed by a colon. 764c2aa98e2SPeter Wemm ** 765c2aa98e2SPeter Wemm ** Header fields beginning with two dashes, although technically 766c2aa98e2SPeter Wemm ** permitted by RFC822, are automatically rejected in order 767c2aa98e2SPeter Wemm ** to make MIME work out. Without this we could have a technically 768c2aa98e2SPeter Wemm ** legal header such as ``--"foo:bar"'' that would also be a legal 769c2aa98e2SPeter Wemm ** MIME separator. 770c2aa98e2SPeter Wemm ** 771c2aa98e2SPeter Wemm ** Parameters: 772c2aa98e2SPeter Wemm ** h -- string to check for possible headerness. 773c2aa98e2SPeter Wemm ** 774c2aa98e2SPeter Wemm ** Returns: 77512ed1c7cSGregory Neil Shapiro ** true if h is a header. 77612ed1c7cSGregory Neil Shapiro ** false otherwise. 777c2aa98e2SPeter Wemm ** 778c2aa98e2SPeter Wemm ** Side Effects: 779c2aa98e2SPeter Wemm ** none. 780c2aa98e2SPeter Wemm */ 781c2aa98e2SPeter Wemm 782c2aa98e2SPeter Wemm bool 783c2aa98e2SPeter Wemm isheader(h) 784c2aa98e2SPeter Wemm char *h; 785c2aa98e2SPeter Wemm { 786951742c4SGregory Neil Shapiro char *s; 787c2aa98e2SPeter Wemm 788951742c4SGregory Neil Shapiro s = h; 789c2aa98e2SPeter Wemm if (s[0] == '-' && s[1] == '-') 79012ed1c7cSGregory Neil Shapiro return false; 791c2aa98e2SPeter Wemm 792c2aa98e2SPeter Wemm while (*s > ' ' && *s != ':' && *s != '\0') 793c2aa98e2SPeter Wemm s++; 794c2aa98e2SPeter Wemm 795c2aa98e2SPeter Wemm if (h == s) 79612ed1c7cSGregory Neil Shapiro return false; 797c2aa98e2SPeter Wemm 798c2aa98e2SPeter Wemm /* following technically violates RFC822 */ 7995b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*s)) 800c2aa98e2SPeter Wemm s++; 801c2aa98e2SPeter Wemm 802c2aa98e2SPeter Wemm return (*s == ':'); 803c2aa98e2SPeter Wemm } 804951742c4SGregory Neil Shapiro 80512ed1c7cSGregory Neil Shapiro /* 806c2aa98e2SPeter Wemm ** EATHEADER -- run through the stored header and extract info. 807c2aa98e2SPeter Wemm ** 808c2aa98e2SPeter Wemm ** Parameters: 809c2aa98e2SPeter Wemm ** e -- the envelope to process. 810c2aa98e2SPeter Wemm ** full -- if set, do full processing (e.g., compute 811c2aa98e2SPeter Wemm ** message priority). This should not be set 812c2aa98e2SPeter Wemm ** when reading a queue file because some info 813c2aa98e2SPeter Wemm ** needed to compute the priority is wrong. 81412ed1c7cSGregory Neil Shapiro ** log -- call logsender()? 815c2aa98e2SPeter Wemm ** 816c2aa98e2SPeter Wemm ** Returns: 817c2aa98e2SPeter Wemm ** none. 818c2aa98e2SPeter Wemm ** 819c2aa98e2SPeter Wemm ** Side Effects: 820c2aa98e2SPeter Wemm ** Sets a bunch of global variables from information 821c2aa98e2SPeter Wemm ** in the collected header. 822c2aa98e2SPeter Wemm */ 823c2aa98e2SPeter Wemm 824c2aa98e2SPeter Wemm void 82512ed1c7cSGregory Neil Shapiro eatheader(e, full, log) 826c2aa98e2SPeter Wemm register ENVELOPE *e; 827c2aa98e2SPeter Wemm bool full; 82812ed1c7cSGregory Neil Shapiro bool log; 829c2aa98e2SPeter Wemm { 830c2aa98e2SPeter Wemm register HDR *h; 831c2aa98e2SPeter Wemm register char *p; 832c2aa98e2SPeter Wemm int hopcnt = 0; 833c2aa98e2SPeter Wemm char buf[MAXLINE]; 834c2aa98e2SPeter Wemm 835c2aa98e2SPeter Wemm /* 836c2aa98e2SPeter Wemm ** Set up macros for possible expansion in headers. 837c2aa98e2SPeter Wemm */ 838c2aa98e2SPeter Wemm 83912ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'f', e->e_sender); 84012ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', e->e_sender); 841c2aa98e2SPeter Wemm if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 84212ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt); 843c2aa98e2SPeter Wemm else 84412ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', NULL); 845c2aa98e2SPeter Wemm 846c2aa98e2SPeter Wemm /* full name of from person */ 847c2aa98e2SPeter Wemm p = hvalue("full-name", e->e_header); 848c2aa98e2SPeter Wemm if (p != NULL) 849c2aa98e2SPeter Wemm { 850c2aa98e2SPeter Wemm if (!rfc822_string(p)) 851c2aa98e2SPeter Wemm { 852c2aa98e2SPeter Wemm /* 853c2aa98e2SPeter Wemm ** Quote a full name with special characters 854c2aa98e2SPeter Wemm ** as a comment so crackaddr() doesn't destroy 855c2aa98e2SPeter Wemm ** the name portion of the address. 856c2aa98e2SPeter Wemm */ 85712ed1c7cSGregory Neil Shapiro 85812ed1c7cSGregory Neil Shapiro p = addquotes(p, e->e_rpool); 859c2aa98e2SPeter Wemm } 86012ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'x', p); 861c2aa98e2SPeter Wemm } 862c2aa98e2SPeter Wemm 863c2aa98e2SPeter Wemm if (tTd(32, 1)) 86412ed1c7cSGregory Neil Shapiro sm_dprintf("----- collected header -----\n"); 86512ed1c7cSGregory Neil Shapiro e->e_msgid = NULL; 866c2aa98e2SPeter Wemm for (h = e->e_header; h != NULL; h = h->h_link) 867c2aa98e2SPeter Wemm { 868c2aa98e2SPeter Wemm if (tTd(32, 1)) 86912ed1c7cSGregory Neil Shapiro sm_dprintf("%s:", h->h_field); 870c2aa98e2SPeter Wemm if (h->h_value == NULL) 871c2aa98e2SPeter Wemm { 872c2aa98e2SPeter Wemm if (tTd(32, 1)) 87312ed1c7cSGregory Neil Shapiro sm_dprintf("<NULL>\n"); 874c2aa98e2SPeter Wemm continue; 875c2aa98e2SPeter Wemm } 876c2aa98e2SPeter Wemm 877c2aa98e2SPeter Wemm /* do early binding */ 8783299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) && 8793299c2f1SGregory Neil Shapiro !bitset(H_BINDLATE, h->h_flags)) 880c2aa98e2SPeter Wemm { 881c2aa98e2SPeter Wemm if (tTd(32, 1)) 882c2aa98e2SPeter Wemm { 88312ed1c7cSGregory Neil Shapiro sm_dprintf("("); 884bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), h->h_value); 88512ed1c7cSGregory Neil Shapiro sm_dprintf(") "); 886c2aa98e2SPeter Wemm } 887951742c4SGregory Neil Shapiro expand(h->h_value, buf, sizeof(buf), e); 888951742c4SGregory Neil Shapiro if (buf[0] != '\0' && 889951742c4SGregory Neil Shapiro (buf[0] != ' ' || buf[1] != '\0')) 890c2aa98e2SPeter Wemm { 891c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 892f9218d3dSGregory Neil Shapiro expand(crackaddr(buf, e), 893951742c4SGregory Neil Shapiro buf, sizeof(buf), e); 89412ed1c7cSGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, buf); 895c2aa98e2SPeter Wemm h->h_flags &= ~H_DEFAULT; 896c2aa98e2SPeter Wemm } 897c2aa98e2SPeter Wemm } 898c2aa98e2SPeter Wemm if (tTd(32, 1)) 899c2aa98e2SPeter Wemm { 900bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), h->h_value); 90112ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 902c2aa98e2SPeter Wemm } 903c2aa98e2SPeter Wemm 904c2aa98e2SPeter Wemm /* count the number of times it has been processed */ 905c2aa98e2SPeter Wemm if (bitset(H_TRACE, h->h_flags)) 906c2aa98e2SPeter Wemm hopcnt++; 907c2aa98e2SPeter Wemm 908c2aa98e2SPeter Wemm /* send to this person if we so desire */ 909c2aa98e2SPeter Wemm if (GrabTo && bitset(H_RCPT, h->h_flags) && 910c2aa98e2SPeter Wemm !bitset(H_DEFAULT, h->h_flags) && 91112ed1c7cSGregory Neil Shapiro (!bitset(EF_RESENT, e->e_flags) || 91212ed1c7cSGregory Neil Shapiro bitset(H_RESENT, h->h_flags))) 913c2aa98e2SPeter Wemm { 914c2aa98e2SPeter Wemm #if 0 915c2aa98e2SPeter Wemm int saveflags = e->e_flags; 9165b0945b5SGregory Neil Shapiro #endif 917c2aa98e2SPeter Wemm 91812ed1c7cSGregory Neil Shapiro (void) sendtolist(denlstring(h->h_value, true, false), 91912ed1c7cSGregory Neil Shapiro NULLADDR, &e->e_sendqueue, 0, e); 920c2aa98e2SPeter Wemm 921c2aa98e2SPeter Wemm #if 0 922c2aa98e2SPeter Wemm /* 923c2aa98e2SPeter Wemm ** Change functionality so a fatal error on an 924c2aa98e2SPeter Wemm ** address doesn't affect the entire envelope. 925c2aa98e2SPeter Wemm */ 926c2aa98e2SPeter Wemm 927c2aa98e2SPeter Wemm /* delete fatal errors generated by this address */ 928c2aa98e2SPeter Wemm if (!bitset(EF_FATALERRS, saveflags)) 929c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 9303299c2f1SGregory Neil Shapiro #endif /* 0 */ 931c2aa98e2SPeter Wemm } 932c2aa98e2SPeter Wemm 933c2aa98e2SPeter Wemm /* save the message-id for logging */ 934c2aa98e2SPeter Wemm p = "resent-message-id"; 935c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 936c2aa98e2SPeter Wemm p += 7; 937*2fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(h->h_field, p)) 938c2aa98e2SPeter Wemm { 93912ed1c7cSGregory Neil Shapiro e->e_msgid = h->h_value; 940*2fb4f839SGregory Neil Shapiro while (SM_ISSPACE(*e->e_msgid)) 94112ed1c7cSGregory Neil Shapiro e->e_msgid++; 9421ae5b8d4SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{msg_id}"), 9431ae5b8d4SGregory Neil Shapiro e->e_msgid); 944c2aa98e2SPeter Wemm } 945c2aa98e2SPeter Wemm } 946c2aa98e2SPeter Wemm if (tTd(32, 1)) 94712ed1c7cSGregory Neil Shapiro sm_dprintf("----------------------------\n"); 948c2aa98e2SPeter Wemm 949c2aa98e2SPeter Wemm /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 950c2aa98e2SPeter Wemm if (OpMode == MD_VERIFY) 951c2aa98e2SPeter Wemm return; 952c2aa98e2SPeter Wemm 953c2aa98e2SPeter Wemm /* store hop count */ 954c2aa98e2SPeter Wemm if (hopcnt > e->e_hopcount) 95512ed1c7cSGregory Neil Shapiro { 956c2aa98e2SPeter Wemm e->e_hopcount = hopcnt; 957951742c4SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount); 95812ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 'c', buf); 95912ed1c7cSGregory Neil Shapiro } 960c2aa98e2SPeter Wemm 961c2aa98e2SPeter Wemm /* message priority */ 962c2aa98e2SPeter Wemm p = hvalue("precedence", e->e_header); 963c2aa98e2SPeter Wemm if (p != NULL) 964c2aa98e2SPeter Wemm e->e_class = priencode(p); 965c2aa98e2SPeter Wemm if (e->e_class < 0) 966c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 967c2aa98e2SPeter Wemm else if (e->e_class > 0) 968c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 969c2aa98e2SPeter Wemm if (full) 970c2aa98e2SPeter Wemm { 971c2aa98e2SPeter Wemm e->e_msgpriority = e->e_msgsize 972c2aa98e2SPeter Wemm - e->e_class * WkClassFact 973c2aa98e2SPeter Wemm + e->e_nrcpts * WkRecipFact; 974c2aa98e2SPeter Wemm } 975c2aa98e2SPeter Wemm 976bfb62e91SGregory Neil Shapiro /* check for DSN to properly set e_timeoutclass */ 977bfb62e91SGregory Neil Shapiro p = hvalue("content-type", e->e_header); 978bfb62e91SGregory Neil Shapiro if (p != NULL) 979bfb62e91SGregory Neil Shapiro { 980bfb62e91SGregory Neil Shapiro bool oldsupr; 981bfb62e91SGregory Neil Shapiro char **pvp; 982bfb62e91SGregory Neil Shapiro char pvpbuf[MAXLINE]; 983bfb62e91SGregory Neil Shapiro extern unsigned char MimeTokenTab[256]; 984bfb62e91SGregory Neil Shapiro 985bfb62e91SGregory Neil Shapiro /* tokenize header */ 986bfb62e91SGregory Neil Shapiro oldsupr = SuprErrs; 987bfb62e91SGregory Neil Shapiro SuprErrs = true; 988951742c4SGregory Neil Shapiro pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL, 989bfb62e91SGregory Neil Shapiro MimeTokenTab, false); 990bfb62e91SGregory Neil Shapiro SuprErrs = oldsupr; 991bfb62e91SGregory Neil Shapiro 992bfb62e91SGregory Neil Shapiro /* Check if multipart/report */ 993bfb62e91SGregory Neil Shapiro if (pvp != NULL && pvp[0] != NULL && 994bfb62e91SGregory Neil Shapiro pvp[1] != NULL && pvp[2] != NULL && 995*2fb4f839SGregory Neil Shapiro SM_STRCASEEQ(*pvp++, "multipart") && 996bfb62e91SGregory Neil Shapiro strcmp(*pvp++, "/") == 0 && 997*2fb4f839SGregory Neil Shapiro SM_STRCASEEQ(*pvp++, "report")) 998bfb62e91SGregory Neil Shapiro { 999bfb62e91SGregory Neil Shapiro /* Look for report-type=delivery-status */ 1000bfb62e91SGregory Neil Shapiro while (*pvp != NULL) 1001bfb62e91SGregory Neil Shapiro { 1002bfb62e91SGregory Neil Shapiro /* skip to semicolon separator */ 1003bfb62e91SGregory Neil Shapiro while (*pvp != NULL && strcmp(*pvp, ";") != 0) 1004bfb62e91SGregory Neil Shapiro pvp++; 1005bfb62e91SGregory Neil Shapiro 1006bfb62e91SGregory Neil Shapiro /* skip semicolon */ 1007bfb62e91SGregory Neil Shapiro if (*pvp++ == NULL || *pvp == NULL) 1008bfb62e91SGregory Neil Shapiro break; 1009bfb62e91SGregory Neil Shapiro 1010bfb62e91SGregory Neil Shapiro /* look for report-type */ 1011*2fb4f839SGregory Neil Shapiro if (!SM_STRCASEEQ(*pvp++, "report-type")) 1012bfb62e91SGregory Neil Shapiro continue; 1013bfb62e91SGregory Neil Shapiro 1014bfb62e91SGregory Neil Shapiro /* skip equal */ 1015bfb62e91SGregory Neil Shapiro if (*pvp == NULL || strcmp(*pvp, "=") != 0) 1016bfb62e91SGregory Neil Shapiro continue; 1017bfb62e91SGregory Neil Shapiro 1018bfb62e91SGregory Neil Shapiro /* check value */ 1019bfb62e91SGregory Neil Shapiro if (*++pvp != NULL && 1020*2fb4f839SGregory Neil Shapiro SM_STRCASEEQ(*pvp, "delivery-status")) 1021bfb62e91SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 1022bfb62e91SGregory Neil Shapiro 1023bfb62e91SGregory Neil Shapiro /* found report-type, no need to continue */ 1024bfb62e91SGregory Neil Shapiro break; 1025bfb62e91SGregory Neil Shapiro } 1026bfb62e91SGregory Neil Shapiro } 1027bfb62e91SGregory Neil Shapiro } 1028bfb62e91SGregory Neil Shapiro 1029c2aa98e2SPeter Wemm /* message timeout priority */ 1030c2aa98e2SPeter Wemm p = hvalue("priority", e->e_header); 1031c2aa98e2SPeter Wemm if (p != NULL) 1032c2aa98e2SPeter Wemm { 1033c2aa98e2SPeter Wemm /* (this should be in the configuration file) */ 1034*2fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(p, "urgent")) 1035c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 1036*2fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(p, "normal")) 1037c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NORMAL; 1038*2fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(p, "non-urgent")) 1039c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 10401ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags)) 10411ae5b8d4SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 10421ae5b8d4SGregory Neil Shapiro } 10431ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags)) 104472936242SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 104572936242SGregory Neil Shapiro 1046c2aa98e2SPeter Wemm /* date message originated */ 1047c2aa98e2SPeter Wemm p = hvalue("posted-date", e->e_header); 1048c2aa98e2SPeter Wemm if (p == NULL) 1049c2aa98e2SPeter Wemm p = hvalue("date", e->e_header); 1050c2aa98e2SPeter Wemm if (p != NULL) 105112ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'a', p); 1052c2aa98e2SPeter Wemm 1053c2aa98e2SPeter Wemm /* check to see if this is a MIME message */ 1054c2aa98e2SPeter Wemm if ((e->e_bodytype != NULL && 1055*2fb4f839SGregory Neil Shapiro SM_STRCASEEQ(e->e_bodytype, "8bitmime")) || 1056c2aa98e2SPeter Wemm hvalue("MIME-Version", e->e_header) != NULL) 1057c2aa98e2SPeter Wemm { 1058c2aa98e2SPeter Wemm e->e_flags |= EF_IS_MIME; 1059c2aa98e2SPeter Wemm if (HasEightBits) 1060c2aa98e2SPeter Wemm e->e_bodytype = "8BITMIME"; 1061c2aa98e2SPeter Wemm } 1062c2aa98e2SPeter Wemm else if ((p = hvalue("Content-Type", e->e_header)) != NULL) 1063c2aa98e2SPeter Wemm { 1064c2aa98e2SPeter Wemm /* this may be an RFC 1049 message */ 1065c2aa98e2SPeter Wemm p = strpbrk(p, ";/"); 1066c2aa98e2SPeter Wemm if (p == NULL || *p == ';') 1067c2aa98e2SPeter Wemm { 1068c2aa98e2SPeter Wemm /* yep, it is */ 1069c2aa98e2SPeter Wemm e->e_flags |= EF_DONT_MIME; 1070c2aa98e2SPeter Wemm } 1071c2aa98e2SPeter Wemm } 1072c2aa98e2SPeter Wemm 1073c2aa98e2SPeter Wemm /* 1074c2aa98e2SPeter Wemm ** From person in antiquated ARPANET mode 1075c2aa98e2SPeter Wemm ** required by UK Grey Book e-mail gateways (sigh) 1076c2aa98e2SPeter Wemm */ 1077c2aa98e2SPeter Wemm 1078c2aa98e2SPeter Wemm if (OpMode == MD_ARPAFTP) 1079c2aa98e2SPeter Wemm { 1080c2aa98e2SPeter Wemm register struct hdrinfo *hi; 1081c2aa98e2SPeter Wemm 1082c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 1083c2aa98e2SPeter Wemm { 1084c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && 1085c2aa98e2SPeter Wemm (!bitset(H_RESENT, hi->hi_flags) || 1086c2aa98e2SPeter Wemm bitset(EF_RESENT, e->e_flags)) && 1087c2aa98e2SPeter Wemm (p = hvalue(hi->hi_field, e->e_header)) != NULL) 1088c2aa98e2SPeter Wemm break; 1089c2aa98e2SPeter Wemm } 1090c2aa98e2SPeter Wemm if (hi->hi_field != NULL) 1091c2aa98e2SPeter Wemm { 1092c2aa98e2SPeter Wemm if (tTd(32, 2)) 109312ed1c7cSGregory Neil Shapiro sm_dprintf("eatheader: setsender(*%s == %s)\n", 1094c2aa98e2SPeter Wemm hi->hi_field, p); 109512ed1c7cSGregory Neil Shapiro setsender(p, e, NULL, '\0', true); 1096c2aa98e2SPeter Wemm } 1097c2aa98e2SPeter Wemm } 1098c2aa98e2SPeter Wemm 1099c2aa98e2SPeter Wemm /* 1100c2aa98e2SPeter Wemm ** Log collection information. 1101c2aa98e2SPeter Wemm */ 1102c2aa98e2SPeter Wemm 11039bd497b8SGregory Neil Shapiro if (tTd(92, 2)) 11049bd497b8SGregory Neil Shapiro sm_dprintf("eatheader: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d, log=%d\n", 11059bd497b8SGregory Neil Shapiro e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel, 11069bd497b8SGregory Neil Shapiro log); 110712ed1c7cSGregory Neil Shapiro if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 110812ed1c7cSGregory Neil Shapiro { 110912ed1c7cSGregory Neil Shapiro logsender(e, e->e_msgid); 1110c2aa98e2SPeter Wemm e->e_flags &= ~EF_LOGSENDER; 1111c2aa98e2SPeter Wemm } 111212ed1c7cSGregory Neil Shapiro } 1113951742c4SGregory Neil Shapiro 111412ed1c7cSGregory Neil Shapiro /* 1115c2aa98e2SPeter Wemm ** LOGSENDER -- log sender information 1116c2aa98e2SPeter Wemm ** 1117c2aa98e2SPeter Wemm ** Parameters: 1118c2aa98e2SPeter Wemm ** e -- the envelope to log 1119c2aa98e2SPeter Wemm ** msgid -- the message id 1120c2aa98e2SPeter Wemm ** 1121c2aa98e2SPeter Wemm ** Returns: 1122c2aa98e2SPeter Wemm ** none 1123c2aa98e2SPeter Wemm */ 1124c2aa98e2SPeter Wemm 1125*2fb4f839SGregory Neil Shapiro 1126*2fb4f839SGregory Neil Shapiro #define XBUFLEN MAXNAME 1127*2fb4f839SGregory Neil Shapiro #if (SYSLOG_BUFSIZE) >= 256 1128*2fb4f839SGregory Neil Shapiro # ifndef MSGIDLOGLEN 1129*2fb4f839SGregory Neil Shapiro # define MSGIDLOGLEN 100 1130*2fb4f839SGregory Neil Shapiro # define FIRSTLOGLEN 850 1131*2fb4f839SGregory Neil Shapiro # else 1132*2fb4f839SGregory Neil Shapiro # if MSGIDLOGLEN < 100 1133*2fb4f839SGregory Neil Shapiro # ERROR "MSGIDLOGLEN too short" 1134*2fb4f839SGregory Neil Shapiro # endif 1135*2fb4f839SGregory Neil Shapiro /* XREF: this is "sizeof(sbuf)", see above */ 1136*2fb4f839SGregory Neil Shapiro # if MSGIDLOGLEN >= MAXLINE / 2 1137*2fb4f839SGregory Neil Shapiro # ERROR "MSGIDLOGLEN too long" 1138*2fb4f839SGregory Neil Shapiro # endif 1139*2fb4f839SGregory Neil Shapiro 1140*2fb4f839SGregory Neil Shapiro /* 850 - 100 for original MSGIDLOGLEN */ 1141*2fb4f839SGregory Neil Shapiro # define FIRSTLOGLEN (750 + MSGIDLOGLEN) 1142*2fb4f839SGregory Neil Shapiro 1143*2fb4f839SGregory Neil Shapiro /* check that total length is ok */ 1144*2fb4f839SGregory Neil Shapiro # if FIRSTLOGLEN + 200 >= MAXLINE 1145*2fb4f839SGregory Neil Shapiro # ERROR "MSGIDLOGLEN too long" 1146*2fb4f839SGregory Neil Shapiro # endif 1147*2fb4f839SGregory Neil Shapiro # if MSGIDLOGLEN > MAXNAME 1148*2fb4f839SGregory Neil Shapiro # undef XBUFLEN 1149*2fb4f839SGregory Neil Shapiro # define XBUFLEN MSGIDLOGLEN 1150*2fb4f839SGregory Neil Shapiro # endif 1151*2fb4f839SGregory Neil Shapiro # endif 1152*2fb4f839SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 1153*2fb4f839SGregory Neil Shapiro 1154c2aa98e2SPeter Wemm void 1155c2aa98e2SPeter Wemm logsender(e, msgid) 1156c2aa98e2SPeter Wemm register ENVELOPE *e; 1157c2aa98e2SPeter Wemm char *msgid; 1158c2aa98e2SPeter Wemm { 1159c2aa98e2SPeter Wemm char *name; 1160c2aa98e2SPeter Wemm register char *sbp; 1161c2aa98e2SPeter Wemm register char *p; 1162*2fb4f839SGregory Neil Shapiro char hbuf[MAXNAME + 1]; /* EAI:ok; restricted to short size */ 1163*2fb4f839SGregory Neil Shapiro char sbuf[MAXLINE + 1]; /* EAI:ok; XREF: see also MSGIDLOGLEN */ 1164*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR 1165*2fb4f839SGregory Neil Shapiro char xbuf[XBUFLEN + 1]; /* EAI:ok */ 1166*2fb4f839SGregory Neil Shapiro #endif 1167*2fb4f839SGregory Neil Shapiro char *xstr; 1168c2aa98e2SPeter Wemm 1169c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags)) 1170c2aa98e2SPeter Wemm name = "[RESPONSE]"; 1171c2aa98e2SPeter Wemm else if ((name = macvalue('_', e)) != NULL) 11723299c2f1SGregory Neil Shapiro /* EMPTY */ 1173c2aa98e2SPeter Wemm ; 1174c2aa98e2SPeter Wemm else if (RealHostName == NULL) 1175c2aa98e2SPeter Wemm name = "localhost"; 1176c2aa98e2SPeter Wemm else if (RealHostName[0] == '[') 1177c2aa98e2SPeter Wemm name = RealHostName; 1178c2aa98e2SPeter Wemm else 1179c2aa98e2SPeter Wemm { 1180c2aa98e2SPeter Wemm name = hbuf; 1181951742c4SGregory Neil Shapiro (void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName); 1182c2aa98e2SPeter Wemm if (RealHostAddr.sa.sa_family != 0) 1183c2aa98e2SPeter Wemm { 1184c2aa98e2SPeter Wemm p = &hbuf[strlen(hbuf)]; 118512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 118612ed1c7cSGregory Neil Shapiro " (%.100s)", 1187c2aa98e2SPeter Wemm anynet_ntoa(&RealHostAddr)); 1188c2aa98e2SPeter Wemm } 1189c2aa98e2SPeter Wemm } 1190c2aa98e2SPeter Wemm 1191c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256 1192c2aa98e2SPeter Wemm sbp = sbuf; 1193*2fb4f839SGregory Neil Shapiro if (NULL != e->e_from.q_paddr) 1194*2fb4f839SGregory Neil Shapiro { 1195*2fb4f839SGregory Neil Shapiro xstr = e->e_from.q_paddr; 1196*2fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR 1197*2fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(e->e_from.q_paddr, xbuf, sizeof(xbuf)); 1198*2fb4f839SGregory Neil Shapiro xstr = xbuf; 1199*2fb4f839SGregory Neil Shapiro # endif 1200*2fb4f839SGregory Neil Shapiro } 1201*2fb4f839SGregory Neil Shapiro else 1202*2fb4f839SGregory Neil Shapiro xstr = "<NONE>"; 120312ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1204*2fb4f839SGregory Neil Shapiro "from=%.200s, size=%ld, class=%d, nrcpts=%d", xstr, 1205ba00ec3dSGregory Neil Shapiro PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 1206c2aa98e2SPeter Wemm sbp += strlen(sbp); 1207c2aa98e2SPeter Wemm if (msgid != NULL) 1208c2aa98e2SPeter Wemm { 1209*2fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR 1210*2fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(msgid, xbuf, sizeof(xbuf)); 1211*2fb4f839SGregory Neil Shapiro msgid = xbuf; 12125b0945b5SGregory Neil Shapiro # endif 121312ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 12145b0945b5SGregory Neil Shapiro ", msgid=%.*s", MSGIDLOGLEN, msgid); 1215c2aa98e2SPeter Wemm sbp += strlen(sbp); 1216c2aa98e2SPeter Wemm } 1217c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 1218c2aa98e2SPeter Wemm { 121912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 122012ed1c7cSGregory Neil Shapiro ", bodytype=%.20s", e->e_bodytype); 1221c2aa98e2SPeter Wemm sbp += strlen(sbp); 1222c2aa98e2SPeter Wemm } 1223c2aa98e2SPeter Wemm p = macvalue('r', e); 1224c2aa98e2SPeter Wemm if (p != NULL) 12253299c2f1SGregory Neil Shapiro { 122612ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 122712ed1c7cSGregory Neil Shapiro ", proto=%.20s", p); 12283299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 12293299c2f1SGregory Neil Shapiro } 123012ed1c7cSGregory Neil Shapiro p = macvalue(macid("{daemon_name}"), e); 12313299c2f1SGregory Neil Shapiro if (p != NULL) 12323299c2f1SGregory Neil Shapiro { 123312ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 123412ed1c7cSGregory Neil Shapiro ", daemon=%.20s", p); 12353299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 12363299c2f1SGregory Neil Shapiro } 1237da7d7b9cSGregory Neil Shapiro # if _FFR_LOG_MORE1 12385b0945b5SGregory Neil Shapiro LOG_MORE(sbuf, sbp); 1239da7d7b9cSGregory Neil Shapiro # if SASL 1240da7d7b9cSGregory Neil Shapiro p = macvalue(macid("{auth_type}"), e); 1241*2fb4f839SGregory Neil Shapiro if (SM_IS_EMPTY(p)) 1242da7d7b9cSGregory Neil Shapiro p = "NONE"; 1243da7d7b9cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.20s", p); 1244da7d7b9cSGregory Neil Shapiro sbp += strlen(sbp); 1245da7d7b9cSGregory Neil Shapiro # endif /* SASL */ 1246da7d7b9cSGregory Neil Shapiro # endif /* _FFR_LOG_MORE1 */ 12475b0945b5SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "%.*s, relay=%s", FIRSTLOGLEN, sbuf, name); 1248c2aa98e2SPeter Wemm 12493299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */ 1250c2aa98e2SPeter Wemm 1251c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 1252c2aa98e2SPeter Wemm "from=%s", 1253c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>" 125412ed1c7cSGregory Neil Shapiro : shortenstring(e->e_from.q_paddr, 125512ed1c7cSGregory Neil Shapiro 83)); 1256c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 12573299c2f1SGregory Neil Shapiro "size=%ld, class=%ld, nrcpts=%d", 1258ba00ec3dSGregory Neil Shapiro PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 1259c2aa98e2SPeter Wemm if (msgid != NULL) 1260*2fb4f839SGregory Neil Shapiro { 1261*2fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR 1262*2fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(msgid, xbuf, sizeof(xbuf)); 1263*2fb4f839SGregory Neil Shapiro msgid = xbuf; 1264*2fb4f839SGregory Neil Shapiro # endif 1265c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 1266c2aa98e2SPeter Wemm "msgid=%s", 12675b0945b5SGregory Neil Shapiro shortenstring(msgid, 83)); 1268*2fb4f839SGregory Neil Shapiro } 1269c2aa98e2SPeter Wemm sbp = sbuf; 1270c2aa98e2SPeter Wemm *sbp = '\0'; 1271c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 1272c2aa98e2SPeter Wemm { 127312ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 127412ed1c7cSGregory Neil Shapiro "bodytype=%.20s, ", e->e_bodytype); 1275c2aa98e2SPeter Wemm sbp += strlen(sbp); 1276c2aa98e2SPeter Wemm } 1277c2aa98e2SPeter Wemm p = macvalue('r', e); 1278c2aa98e2SPeter Wemm if (p != NULL) 1279c2aa98e2SPeter Wemm { 128012ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 128112ed1c7cSGregory Neil Shapiro "proto=%.20s, ", p); 1282c2aa98e2SPeter Wemm sbp += strlen(sbp); 1283c2aa98e2SPeter Wemm } 1284c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 12852ef40764SGregory Neil Shapiro "%.400srelay=%s", sbuf, name); 12863299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 1287c2aa98e2SPeter Wemm } 1288951742c4SGregory Neil Shapiro 128912ed1c7cSGregory Neil Shapiro /* 1290c2aa98e2SPeter Wemm ** PRIENCODE -- encode external priority names into internal values. 1291c2aa98e2SPeter Wemm ** 1292c2aa98e2SPeter Wemm ** Parameters: 1293c2aa98e2SPeter Wemm ** p -- priority in ascii. 1294c2aa98e2SPeter Wemm ** 1295c2aa98e2SPeter Wemm ** Returns: 1296c2aa98e2SPeter Wemm ** priority as a numeric level. 1297c2aa98e2SPeter Wemm ** 1298c2aa98e2SPeter Wemm ** Side Effects: 1299c2aa98e2SPeter Wemm ** none. 1300c2aa98e2SPeter Wemm */ 1301c2aa98e2SPeter Wemm 13023299c2f1SGregory Neil Shapiro static int 1303c2aa98e2SPeter Wemm priencode(p) 1304c2aa98e2SPeter Wemm char *p; 1305c2aa98e2SPeter Wemm { 1306c2aa98e2SPeter Wemm register int i; 1307c2aa98e2SPeter Wemm 1308c2aa98e2SPeter Wemm for (i = 0; i < NumPriorities; i++) 1309c2aa98e2SPeter Wemm { 1310*2fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(p, Priorities[i].pri_name)) 13113299c2f1SGregory Neil Shapiro return Priorities[i].pri_val; 1312c2aa98e2SPeter Wemm } 1313c2aa98e2SPeter Wemm 1314c2aa98e2SPeter Wemm /* unknown priority */ 13153299c2f1SGregory Neil Shapiro return 0; 1316c2aa98e2SPeter Wemm } 1317951742c4SGregory Neil Shapiro 131812ed1c7cSGregory Neil Shapiro /* 1319c2aa98e2SPeter Wemm ** CRACKADDR -- parse an address and turn it into a macro 1320c2aa98e2SPeter Wemm ** 1321c2aa98e2SPeter Wemm ** This doesn't actually parse the address -- it just extracts 1322c2aa98e2SPeter Wemm ** it and replaces it with "$g". The parse is totally ad hoc 1323c2aa98e2SPeter Wemm ** and isn't even guaranteed to leave something syntactically 1324c2aa98e2SPeter Wemm ** identical to what it started with. However, it does leave 1325f9218d3dSGregory Neil Shapiro ** something semantically identical if possible, else at least 1326f9218d3dSGregory Neil Shapiro ** syntactically correct. 1327f9218d3dSGregory Neil Shapiro ** 1328f9218d3dSGregory Neil Shapiro ** For example, it changes "Real Name <real@example.com> (Comment)" 1329f9218d3dSGregory Neil Shapiro ** to "Real Name <$g> (Comment)". 1330c2aa98e2SPeter Wemm ** 1331c2aa98e2SPeter Wemm ** This algorithm has been cleaned up to handle a wider range 1332c2aa98e2SPeter Wemm ** of cases -- notably quoted and backslash escaped strings. 1333c2aa98e2SPeter Wemm ** This modification makes it substantially better at preserving 1334c2aa98e2SPeter Wemm ** the original syntax. 1335c2aa98e2SPeter Wemm ** 1336c2aa98e2SPeter Wemm ** Parameters: 1337*2fb4f839SGregory Neil Shapiro ** addr -- the address to be cracked. [A] 1338f9218d3dSGregory Neil Shapiro ** e -- the current envelope. 1339c2aa98e2SPeter Wemm ** 1340c2aa98e2SPeter Wemm ** Returns: 1341c2aa98e2SPeter Wemm ** a pointer to the new version. 1342c2aa98e2SPeter Wemm ** 1343c2aa98e2SPeter Wemm ** Side Effects: 1344c2aa98e2SPeter Wemm ** none. 1345c2aa98e2SPeter Wemm ** 1346c2aa98e2SPeter Wemm ** Warning: 1347*2fb4f839SGregory Neil Shapiro ** The return value is saved in static storage and should 1348c2aa98e2SPeter Wemm ** be copied if it is to be reused. 1349c2aa98e2SPeter Wemm */ 1350c2aa98e2SPeter Wemm 1351*2fb4f839SGregory Neil Shapiro #define SM_HAVE_ROOMB ((bp < buflim) && (buflim <= bufend)) 1352*2fb4f839SGregory Neil Shapiro #if USE_EAI 1353*2fb4f839SGregory Neil Shapiro # define SM_HAVE_ROOM ((xlen < MAXNAME) && SM_HAVE_ROOMB) 1354*2fb4f839SGregory Neil Shapiro #else 1355*2fb4f839SGregory Neil Shapiro # define SM_HAVE_ROOM SM_HAVE_ROOMB 1356*2fb4f839SGregory Neil Shapiro #endif 1357f9218d3dSGregory Neil Shapiro 1358f9218d3dSGregory Neil Shapiro /* 1359f9218d3dSGregory Neil Shapiro ** Append a character to bp if we have room. 1360f9218d3dSGregory Neil Shapiro ** If not, punt and return $g. 1361f9218d3dSGregory Neil Shapiro */ 1362f9218d3dSGregory Neil Shapiro 1363f9218d3dSGregory Neil Shapiro #define SM_APPEND_CHAR(c) \ 1364f9218d3dSGregory Neil Shapiro do \ 1365f9218d3dSGregory Neil Shapiro { \ 1366*2fb4f839SGregory Neil Shapiro XLEN(c); \ 1367f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) \ 1368f9218d3dSGregory Neil Shapiro *bp++ = (c); \ 1369f9218d3dSGregory Neil Shapiro else \ 1370f9218d3dSGregory Neil Shapiro goto returng; \ 1371f9218d3dSGregory Neil Shapiro } while (0) 1372f9218d3dSGregory Neil Shapiro 1373f9218d3dSGregory Neil Shapiro #if MAXNAME < 10 1374*2fb4f839SGregory Neil Shapiro # ERROR "MAXNAME must be at least 10" 13755b0945b5SGregory Neil Shapiro #endif 1376f9218d3dSGregory Neil Shapiro 1377c2aa98e2SPeter Wemm char * 1378f9218d3dSGregory Neil Shapiro crackaddr(addr, e) 1379c2aa98e2SPeter Wemm register char *addr; 1380f9218d3dSGregory Neil Shapiro ENVELOPE *e; 1381c2aa98e2SPeter Wemm { 1382c2aa98e2SPeter Wemm register char *p; 1383c2aa98e2SPeter Wemm register char c; 1384f9218d3dSGregory Neil Shapiro int cmtlev; /* comment level in input string */ 1385f9218d3dSGregory Neil Shapiro int realcmtlev; /* comment level in output string */ 1386f9218d3dSGregory Neil Shapiro int anglelev; /* angle level in input string */ 1387f9218d3dSGregory Neil Shapiro int copylev; /* 0 == in address, >0 copying */ 1388f9218d3dSGregory Neil Shapiro int bracklev; /* bracket level for IPv6 addr check */ 1389f9218d3dSGregory Neil Shapiro bool addangle; /* put closing angle in output */ 1390f9218d3dSGregory Neil Shapiro bool qmode; /* quoting in original string? */ 1391f9218d3dSGregory Neil Shapiro bool realqmode; /* quoting in output string? */ 1392f9218d3dSGregory Neil Shapiro bool putgmac = false; /* already wrote $g */ 1393f9218d3dSGregory Neil Shapiro bool quoteit = false; /* need to quote next character */ 1394f9218d3dSGregory Neil Shapiro bool gotangle = false; /* found first '<' */ 1395f9218d3dSGregory Neil Shapiro bool gotcolon = false; /* found a ':' */ 1396c2aa98e2SPeter Wemm register char *bp; 1397c2aa98e2SPeter Wemm char *buflim; 1398c2aa98e2SPeter Wemm char *bufhead; 1399c2aa98e2SPeter Wemm char *addrhead; 1400f9218d3dSGregory Neil Shapiro char *bufend; 1401*2fb4f839SGregory Neil Shapiro static char buf[MAXNAME_I + 1]; /* XXX: EAI? */ 1402*2fb4f839SGregory Neil Shapiro XLENDECL 1403c2aa98e2SPeter Wemm 1404c2aa98e2SPeter Wemm if (tTd(33, 1)) 140512ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr(%s)\n", addr); 1406c2aa98e2SPeter Wemm 1407951742c4SGregory Neil Shapiro buflim = bufend = &buf[sizeof(buf) - 1]; 1408951742c4SGregory Neil Shapiro bp = bufhead = buf; 1409951742c4SGregory Neil Shapiro 1410951742c4SGregory Neil Shapiro /* skip over leading spaces but preserve them */ 14115b0945b5SGregory Neil Shapiro while (*addr != '\0' && SM_ISSPACE(*addr)) 1412951742c4SGregory Neil Shapiro { 1413951742c4SGregory Neil Shapiro SM_APPEND_CHAR(*addr); 1414c2aa98e2SPeter Wemm addr++; 1415951742c4SGregory Neil Shapiro } 1416951742c4SGregory Neil Shapiro bufhead = bp; 1417c2aa98e2SPeter Wemm 1418c2aa98e2SPeter Wemm /* 1419c2aa98e2SPeter Wemm ** Start by assuming we have no angle brackets. This will be 1420c2aa98e2SPeter Wemm ** adjusted later if we find them. 1421c2aa98e2SPeter Wemm */ 1422c2aa98e2SPeter Wemm 1423c2aa98e2SPeter Wemm p = addrhead = addr; 1424f9218d3dSGregory Neil Shapiro copylev = anglelev = cmtlev = realcmtlev = 0; 1425c2aa98e2SPeter Wemm bracklev = 0; 1426f9218d3dSGregory Neil Shapiro qmode = realqmode = addangle = false; 1427c2aa98e2SPeter Wemm 1428c2aa98e2SPeter Wemm while ((c = *p++) != '\0') 1429c2aa98e2SPeter Wemm { 1430c2aa98e2SPeter Wemm /* 1431f9218d3dSGregory Neil Shapiro ** Try to keep legal syntax using spare buffer space 1432f9218d3dSGregory Neil Shapiro ** (maintained by buflim). 1433c2aa98e2SPeter Wemm */ 1434c2aa98e2SPeter Wemm 1435f9218d3dSGregory Neil Shapiro if (copylev > 0) 1436f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1437c2aa98e2SPeter Wemm 1438c2aa98e2SPeter Wemm /* check for backslash escapes */ 1439c2aa98e2SPeter Wemm if (c == '\\') 1440c2aa98e2SPeter Wemm { 1441c2aa98e2SPeter Wemm /* arrange to quote the address */ 1442c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 144312ed1c7cSGregory Neil Shapiro quoteit = true; 1444c2aa98e2SPeter Wemm 1445c2aa98e2SPeter Wemm if ((c = *p++) == '\0') 1446c2aa98e2SPeter Wemm { 1447c2aa98e2SPeter Wemm /* too far */ 1448c2aa98e2SPeter Wemm p--; 1449c2aa98e2SPeter Wemm goto putg; 1450c2aa98e2SPeter Wemm } 1451f9218d3dSGregory Neil Shapiro if (copylev > 0) 1452f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1453c2aa98e2SPeter Wemm goto putg; 1454c2aa98e2SPeter Wemm } 1455c2aa98e2SPeter Wemm 1456c2aa98e2SPeter Wemm /* check for quoted strings */ 1457c2aa98e2SPeter Wemm if (c == '"' && cmtlev <= 0) 1458c2aa98e2SPeter Wemm { 1459c2aa98e2SPeter Wemm qmode = !qmode; 1460f9218d3dSGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM) 1461f9218d3dSGregory Neil Shapiro { 1462f9218d3dSGregory Neil Shapiro if (realqmode) 1463f9218d3dSGregory Neil Shapiro buflim--; 1464f9218d3dSGregory Neil Shapiro else 1465f9218d3dSGregory Neil Shapiro buflim++; 1466c2aa98e2SPeter Wemm realqmode = !realqmode; 1467f9218d3dSGregory Neil Shapiro } 1468c2aa98e2SPeter Wemm continue; 1469c2aa98e2SPeter Wemm } 1470c2aa98e2SPeter Wemm if (qmode) 1471c2aa98e2SPeter Wemm goto putg; 1472c2aa98e2SPeter Wemm 1473c2aa98e2SPeter Wemm /* check for comments */ 1474c2aa98e2SPeter Wemm if (c == '(') 1475c2aa98e2SPeter Wemm { 1476c2aa98e2SPeter Wemm cmtlev++; 1477c2aa98e2SPeter Wemm 1478c2aa98e2SPeter Wemm /* allow space for closing paren */ 1479f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1480c2aa98e2SPeter Wemm { 1481c2aa98e2SPeter Wemm buflim--; 1482c2aa98e2SPeter Wemm realcmtlev++; 1483c2aa98e2SPeter Wemm if (copylev++ <= 0) 1484c2aa98e2SPeter Wemm { 1485c2aa98e2SPeter Wemm if (bp != bufhead) 1486f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' '); 1487f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1488c2aa98e2SPeter Wemm } 1489c2aa98e2SPeter Wemm } 1490c2aa98e2SPeter Wemm } 1491c2aa98e2SPeter Wemm if (cmtlev > 0) 1492c2aa98e2SPeter Wemm { 1493c2aa98e2SPeter Wemm if (c == ')') 1494c2aa98e2SPeter Wemm { 1495c2aa98e2SPeter Wemm cmtlev--; 1496c2aa98e2SPeter Wemm copylev--; 1497f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1498c2aa98e2SPeter Wemm { 1499c2aa98e2SPeter Wemm realcmtlev--; 1500c2aa98e2SPeter Wemm buflim++; 1501c2aa98e2SPeter Wemm } 1502c2aa98e2SPeter Wemm } 1503c2aa98e2SPeter Wemm continue; 1504c2aa98e2SPeter Wemm } 1505c2aa98e2SPeter Wemm else if (c == ')') 1506c2aa98e2SPeter Wemm { 1507c2aa98e2SPeter Wemm /* syntax error: unmatched ) */ 15087660b554SGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead) 1509c2aa98e2SPeter Wemm bp--; 1510c2aa98e2SPeter Wemm } 1511c2aa98e2SPeter Wemm 1512c2aa98e2SPeter Wemm /* count nesting on [ ... ] (for IPv6 domain literals) */ 1513c2aa98e2SPeter Wemm if (c == '[') 1514c2aa98e2SPeter Wemm bracklev++; 1515c2aa98e2SPeter Wemm else if (c == ']') 1516c2aa98e2SPeter Wemm bracklev--; 1517c2aa98e2SPeter Wemm 1518c2aa98e2SPeter Wemm /* check for group: list; syntax */ 1519c2aa98e2SPeter Wemm if (c == ':' && anglelev <= 0 && bracklev <= 0 && 1520c2aa98e2SPeter Wemm !gotcolon && !ColonOkInAddr) 1521c2aa98e2SPeter Wemm { 1522c2aa98e2SPeter Wemm register char *q; 1523c2aa98e2SPeter Wemm 1524c2aa98e2SPeter Wemm /* 1525c2aa98e2SPeter Wemm ** Check for DECnet phase IV ``::'' (host::user) 1526f9218d3dSGregory Neil Shapiro ** or DECnet phase V ``:.'' syntaxes. The latter 1527c2aa98e2SPeter Wemm ** covers ``user@DEC:.tay.myhost'' and 1528c2aa98e2SPeter Wemm ** ``DEC:.tay.myhost::user'' syntaxes (bletch). 1529c2aa98e2SPeter Wemm */ 1530c2aa98e2SPeter Wemm 1531c2aa98e2SPeter Wemm if (*p == ':' || *p == '.') 1532c2aa98e2SPeter Wemm { 1533c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 153412ed1c7cSGregory Neil Shapiro quoteit = true; 1535f9218d3dSGregory Neil Shapiro if (copylev > 0) 1536c2aa98e2SPeter Wemm { 1537f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1538f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p); 1539c2aa98e2SPeter Wemm } 1540c2aa98e2SPeter Wemm p++; 1541c2aa98e2SPeter Wemm goto putg; 1542c2aa98e2SPeter Wemm } 1543c2aa98e2SPeter Wemm 154412ed1c7cSGregory Neil Shapiro gotcolon = true; 1545c2aa98e2SPeter Wemm 1546c2aa98e2SPeter Wemm bp = bufhead; 1547c2aa98e2SPeter Wemm if (quoteit) 1548c2aa98e2SPeter Wemm { 1549f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1550c2aa98e2SPeter Wemm 1551c2aa98e2SPeter Wemm /* back up over the ':' and any spaces */ 1552c2aa98e2SPeter Wemm --p; 1553f9218d3dSGregory Neil Shapiro while (p > addr && 1554f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p)) 1555c2aa98e2SPeter Wemm continue; 1556c2aa98e2SPeter Wemm p++; 1557c2aa98e2SPeter Wemm } 1558c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1559c2aa98e2SPeter Wemm { 1560c2aa98e2SPeter Wemm c = *q++; 1561c2aa98e2SPeter Wemm if (quoteit && c == '"') 1562f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\'); 1563f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1564c2aa98e2SPeter Wemm } 1565c2aa98e2SPeter Wemm if (quoteit) 1566c2aa98e2SPeter Wemm { 1567c2aa98e2SPeter Wemm if (bp == &bufhead[1]) 1568c2aa98e2SPeter Wemm bp--; 1569c2aa98e2SPeter Wemm else 1570f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1571c2aa98e2SPeter Wemm while ((c = *p++) != ':') 1572f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1573f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1574c2aa98e2SPeter Wemm } 1575c2aa98e2SPeter Wemm 1576c2aa98e2SPeter Wemm /* any trailing white space is part of group: */ 15775b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p)) 1578f9218d3dSGregory Neil Shapiro { 1579f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p); 1580f9218d3dSGregory Neil Shapiro p++; 1581f9218d3dSGregory Neil Shapiro } 1582c2aa98e2SPeter Wemm copylev = 0; 158312ed1c7cSGregory Neil Shapiro putgmac = quoteit = false; 1584c2aa98e2SPeter Wemm bufhead = bp; 1585c2aa98e2SPeter Wemm addrhead = p; 1586c2aa98e2SPeter Wemm continue; 1587c2aa98e2SPeter Wemm } 1588c2aa98e2SPeter Wemm 1589c2aa98e2SPeter Wemm if (c == ';' && copylev <= 0 && !ColonOkInAddr) 1590f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1591c2aa98e2SPeter Wemm 1592c2aa98e2SPeter Wemm /* check for characters that may have to be quoted */ 1593c2aa98e2SPeter Wemm if (strchr(MustQuoteChars, c) != NULL) 1594c2aa98e2SPeter Wemm { 1595c2aa98e2SPeter Wemm /* 1596c2aa98e2SPeter Wemm ** If these occur as the phrase part of a <> 1597c2aa98e2SPeter Wemm ** construct, but are not inside of () or already 1598c2aa98e2SPeter Wemm ** quoted, they will have to be quoted. Note that 1599c2aa98e2SPeter Wemm ** now (but don't actually do the quoting). 1600c2aa98e2SPeter Wemm */ 1601c2aa98e2SPeter Wemm 1602c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 160312ed1c7cSGregory Neil Shapiro quoteit = true; 1604c2aa98e2SPeter Wemm } 1605c2aa98e2SPeter Wemm 1606c2aa98e2SPeter Wemm /* check for angle brackets */ 1607c2aa98e2SPeter Wemm if (c == '<') 1608c2aa98e2SPeter Wemm { 1609c2aa98e2SPeter Wemm register char *q; 1610c2aa98e2SPeter Wemm 1611c2aa98e2SPeter Wemm /* assume first of two angles is bogus */ 1612c2aa98e2SPeter Wemm if (gotangle) 161312ed1c7cSGregory Neil Shapiro quoteit = true; 161412ed1c7cSGregory Neil Shapiro gotangle = true; 1615c2aa98e2SPeter Wemm 1616c2aa98e2SPeter Wemm /* oops -- have to change our mind */ 1617c2aa98e2SPeter Wemm anglelev = 1; 1618f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1619f9218d3dSGregory Neil Shapiro { 1620f9218d3dSGregory Neil Shapiro if (!addangle) 1621f9218d3dSGregory Neil Shapiro buflim--; 1622f9218d3dSGregory Neil Shapiro addangle = true; 1623f9218d3dSGregory Neil Shapiro } 1624c2aa98e2SPeter Wemm 1625c2aa98e2SPeter Wemm bp = bufhead; 1626c2aa98e2SPeter Wemm if (quoteit) 1627c2aa98e2SPeter Wemm { 1628f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1629c2aa98e2SPeter Wemm 1630c2aa98e2SPeter Wemm /* back up over the '<' and any spaces */ 1631c2aa98e2SPeter Wemm --p; 1632f9218d3dSGregory Neil Shapiro while (p > addr && 1633f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p)) 1634c2aa98e2SPeter Wemm continue; 1635c2aa98e2SPeter Wemm p++; 1636c2aa98e2SPeter Wemm } 1637c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1638c2aa98e2SPeter Wemm { 1639c2aa98e2SPeter Wemm c = *q++; 1640c2aa98e2SPeter Wemm if (quoteit && c == '"') 1641f9218d3dSGregory Neil Shapiro { 1642f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\'); 1643f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1644c2aa98e2SPeter Wemm } 1645f9218d3dSGregory Neil Shapiro else 1646f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1647c2aa98e2SPeter Wemm } 1648c2aa98e2SPeter Wemm if (quoteit) 1649c2aa98e2SPeter Wemm { 1650c2aa98e2SPeter Wemm if (bp == &buf[1]) 1651c2aa98e2SPeter Wemm bp--; 1652c2aa98e2SPeter Wemm else 1653f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1654c2aa98e2SPeter Wemm while ((c = *p++) != '<') 1655f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1656f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1657c2aa98e2SPeter Wemm } 1658c2aa98e2SPeter Wemm copylev = 0; 165912ed1c7cSGregory Neil Shapiro putgmac = quoteit = false; 1660c2aa98e2SPeter Wemm continue; 1661c2aa98e2SPeter Wemm } 1662c2aa98e2SPeter Wemm 1663c2aa98e2SPeter Wemm if (c == '>') 1664c2aa98e2SPeter Wemm { 1665c2aa98e2SPeter Wemm if (anglelev > 0) 1666c2aa98e2SPeter Wemm { 1667c2aa98e2SPeter Wemm anglelev--; 1668f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1669c2aa98e2SPeter Wemm { 1670f9218d3dSGregory Neil Shapiro if (addangle) 1671c2aa98e2SPeter Wemm buflim++; 1672f9218d3dSGregory Neil Shapiro addangle = false; 1673c2aa98e2SPeter Wemm } 1674c2aa98e2SPeter Wemm } 1675f9218d3dSGregory Neil Shapiro else if (SM_HAVE_ROOM) 1676c2aa98e2SPeter Wemm { 1677c2aa98e2SPeter Wemm /* syntax error: unmatched > */ 16787660b554SGregory Neil Shapiro if (copylev > 0 && bp > bufhead) 1679c2aa98e2SPeter Wemm bp--; 168012ed1c7cSGregory Neil Shapiro quoteit = true; 1681c2aa98e2SPeter Wemm continue; 1682c2aa98e2SPeter Wemm } 1683c2aa98e2SPeter Wemm if (copylev++ <= 0) 1684f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1685c2aa98e2SPeter Wemm continue; 1686c2aa98e2SPeter Wemm } 1687c2aa98e2SPeter Wemm 1688c2aa98e2SPeter Wemm /* must be a real address character */ 1689c2aa98e2SPeter Wemm putg: 1690c2aa98e2SPeter Wemm if (copylev <= 0 && !putgmac) 1691c2aa98e2SPeter Wemm { 1692f9218d3dSGregory Neil Shapiro if (bp > buf && bp[-1] == ')') 1693f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' '); 1694f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(MACROEXPAND); 1695f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('g'); 169612ed1c7cSGregory Neil Shapiro putgmac = true; 1697c2aa98e2SPeter Wemm } 1698c2aa98e2SPeter Wemm } 1699c2aa98e2SPeter Wemm 1700c2aa98e2SPeter Wemm /* repair any syntactic damage */ 1701f9218d3dSGregory Neil Shapiro if (realqmode && bp < bufend) 1702c2aa98e2SPeter Wemm *bp++ = '"'; 1703f9218d3dSGregory Neil Shapiro while (realcmtlev-- > 0 && bp < bufend) 1704c2aa98e2SPeter Wemm *bp++ = ')'; 1705f9218d3dSGregory Neil Shapiro if (addangle && bp < bufend) 1706c2aa98e2SPeter Wemm *bp++ = '>'; 1707f9218d3dSGregory Neil Shapiro *bp = '\0'; 1708f9218d3dSGregory Neil Shapiro if (bp < bufend) 1709f9218d3dSGregory Neil Shapiro goto success; 1710c2aa98e2SPeter Wemm 1711f9218d3dSGregory Neil Shapiro returng: 1712f9218d3dSGregory Neil Shapiro /* String too long, punt */ 1713f9218d3dSGregory Neil Shapiro buf[0] = '<'; 1714f9218d3dSGregory Neil Shapiro buf[1] = MACROEXPAND; 1715f9218d3dSGregory Neil Shapiro buf[2]= 'g'; 1716f9218d3dSGregory Neil Shapiro buf[3] = '>'; 1717f9218d3dSGregory Neil Shapiro buf[4]= '\0'; 1718f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 1719f9218d3dSGregory Neil Shapiro "Dropped invalid comments from header address"); 1720f9218d3dSGregory Neil Shapiro 1721f9218d3dSGregory Neil Shapiro success: 1722c2aa98e2SPeter Wemm if (tTd(33, 1)) 1723c2aa98e2SPeter Wemm { 172412ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr=>`"); 1725bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), buf); 172612ed1c7cSGregory Neil Shapiro sm_dprintf("'\n"); 1727c2aa98e2SPeter Wemm } 17283299c2f1SGregory Neil Shapiro return buf; 1729c2aa98e2SPeter Wemm } 1730951742c4SGregory Neil Shapiro 173112ed1c7cSGregory Neil Shapiro /* 1732c2aa98e2SPeter Wemm ** PUTHEADER -- put the header part of a message from the in-core copy 1733c2aa98e2SPeter Wemm ** 1734c2aa98e2SPeter Wemm ** Parameters: 1735c2aa98e2SPeter Wemm ** mci -- the connection information. 17363299c2f1SGregory Neil Shapiro ** hdr -- the header to put. 1737c2aa98e2SPeter Wemm ** e -- envelope to use. 1738e01d6f61SPeter Wemm ** flags -- MIME conversion flags. 1739c2aa98e2SPeter Wemm ** 1740c2aa98e2SPeter Wemm ** Returns: 1741355d91e3SGregory Neil Shapiro ** true iff header part was written successfully 1742c2aa98e2SPeter Wemm ** 1743c2aa98e2SPeter Wemm ** Side Effects: 1744c2aa98e2SPeter Wemm ** none. 1745c2aa98e2SPeter Wemm */ 1746c2aa98e2SPeter Wemm 1747567a2fc9SGregory Neil Shapiro bool 1748e01d6f61SPeter Wemm putheader(mci, hdr, e, flags) 1749c2aa98e2SPeter Wemm register MCI *mci; 1750c2aa98e2SPeter Wemm HDR *hdr; 1751c2aa98e2SPeter Wemm register ENVELOPE *e; 1752e01d6f61SPeter Wemm int flags; 1753c2aa98e2SPeter Wemm { 1754c2aa98e2SPeter Wemm register HDR *h; 175512ed1c7cSGregory Neil Shapiro char buf[SM_MAX(MAXLINE,BUFSIZ)]; 1756c2aa98e2SPeter Wemm char obuf[MAXLINE]; 1757c2aa98e2SPeter Wemm 1758c2aa98e2SPeter Wemm if (tTd(34, 1)) 175912ed1c7cSGregory Neil Shapiro sm_dprintf("--- putheader, mailer = %s ---\n", 1760c2aa98e2SPeter Wemm mci->mci_mailer->m_name); 1761c2aa98e2SPeter Wemm 1762c2aa98e2SPeter Wemm /* 1763c2aa98e2SPeter Wemm ** If we're in MIME mode, we're not really in the header of the 1764c2aa98e2SPeter Wemm ** message, just the header of one of the parts of the body of 1765c2aa98e2SPeter Wemm ** the message. Therefore MCIF_INHEADER should not be turned on. 1766c2aa98e2SPeter Wemm */ 1767c2aa98e2SPeter Wemm 1768c2aa98e2SPeter Wemm if (!bitset(MCIF_INMIME, mci->mci_flags)) 1769c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 1770c2aa98e2SPeter Wemm 1771c2aa98e2SPeter Wemm for (h = hdr; h != NULL; h = h->h_link) 1772c2aa98e2SPeter Wemm { 1773c2aa98e2SPeter Wemm register char *p = h->h_value; 177412ed1c7cSGregory Neil Shapiro char *q; 1775c2aa98e2SPeter Wemm 1776c2aa98e2SPeter Wemm if (tTd(34, 11)) 1777c2aa98e2SPeter Wemm { 177812ed1c7cSGregory Neil Shapiro sm_dprintf(" %s:", h->h_field); 1779bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), p); 1780c2aa98e2SPeter Wemm } 1781c2aa98e2SPeter Wemm 17823299c2f1SGregory Neil Shapiro /* Skip empty headers */ 1783*2fb4f839SGregory Neil Shapiro if (p == NULL) 17843299c2f1SGregory Neil Shapiro continue; 1785*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR 1786*2fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(p, buf, sizeof(buf)); 1787*2fb4f839SGregory Neil Shapiro #endif 17883299c2f1SGregory Neil Shapiro 178976b7bf71SPeter Wemm /* heuristic shortening of MIME fields to avoid MUA overflows */ 179076b7bf71SPeter Wemm if (MaxMimeFieldLength > 0 && 179176b7bf71SPeter Wemm wordinclass(h->h_field, 179212ed1c7cSGregory Neil Shapiro macid("{checkMIMEFieldHeaders}"))) 179376b7bf71SPeter Wemm { 1794c46d91b7SGregory Neil Shapiro size_t len; 1795c46d91b7SGregory Neil Shapiro 1796f9218d3dSGregory Neil Shapiro len = fix_mime_header(h, e); 1797c46d91b7SGregory Neil Shapiro if (len > 0) 179876b7bf71SPeter Wemm { 179976b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1800c46d91b7SGregory Neil Shapiro "Truncated MIME %s header due to field size (length = %ld) (possible attack)", 1801c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 180276b7bf71SPeter Wemm if (tTd(34, 11)) 180312ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", 1804c46d91b7SGregory Neil Shapiro h->h_field, 1805c46d91b7SGregory Neil Shapiro (unsigned long) len); 180676b7bf71SPeter Wemm } 180776b7bf71SPeter Wemm } 180876b7bf71SPeter Wemm 180976b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 181076b7bf71SPeter Wemm wordinclass(h->h_field, 181112ed1c7cSGregory Neil Shapiro macid("{checkMIMETextHeaders}"))) 181276b7bf71SPeter Wemm { 1813c46d91b7SGregory Neil Shapiro size_t len; 1814c46d91b7SGregory Neil Shapiro 1815*2fb4f839SGregory Neil Shapiro len = strlen(p); 1816c46d91b7SGregory Neil Shapiro if (len > (size_t) MaxMimeHeaderLength) 181776b7bf71SPeter Wemm { 181876b7bf71SPeter Wemm h->h_value[MaxMimeHeaderLength - 1] = '\0'; 181976b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1820c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1821c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 182276b7bf71SPeter Wemm if (tTd(34, 11)) 182312ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1824c46d91b7SGregory Neil Shapiro h->h_field, 1825c46d91b7SGregory Neil Shapiro (unsigned long) len); 182676b7bf71SPeter Wemm } 182776b7bf71SPeter Wemm } 182876b7bf71SPeter Wemm 182976b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 183076b7bf71SPeter Wemm wordinclass(h->h_field, 183112ed1c7cSGregory Neil Shapiro macid("{checkMIMEHeaders}"))) 183276b7bf71SPeter Wemm { 1833c46d91b7SGregory Neil Shapiro size_t len; 1834c46d91b7SGregory Neil Shapiro 1835c46d91b7SGregory Neil Shapiro len = strlen(h->h_value); 1836c46d91b7SGregory Neil Shapiro if (shorten_rfc822_string(h->h_value, 1837c46d91b7SGregory Neil Shapiro MaxMimeHeaderLength)) 183876b7bf71SPeter Wemm { 1839f9218d3dSGregory Neil Shapiro if (len < MaxMimeHeaderLength) 1840f9218d3dSGregory Neil Shapiro { 1841f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus header */ 1842f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 1843f9218d3dSGregory Neil Shapiro "Fixed MIME %s header (possible attack)", 1844f9218d3dSGregory Neil Shapiro h->h_field); 1845f9218d3dSGregory Neil Shapiro if (tTd(34, 11)) 1846f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header (possible attack)\n", 1847f9218d3dSGregory Neil Shapiro h->h_field); 1848f9218d3dSGregory Neil Shapiro } 1849f9218d3dSGregory Neil Shapiro else 1850f9218d3dSGregory Neil Shapiro { 1851f9218d3dSGregory Neil Shapiro /* we actually shortened header */ 185276b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1853c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1854f9218d3dSGregory Neil Shapiro h->h_field, 1855f9218d3dSGregory Neil Shapiro (unsigned long) len); 185676b7bf71SPeter Wemm if (tTd(34, 11)) 185712ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1858c46d91b7SGregory Neil Shapiro h->h_field, 1859c46d91b7SGregory Neil Shapiro (unsigned long) len); 186076b7bf71SPeter Wemm } 186176b7bf71SPeter Wemm } 1862f9218d3dSGregory Neil Shapiro } 186376b7bf71SPeter Wemm 1864e01d6f61SPeter Wemm /* 1865e01d6f61SPeter Wemm ** Suppress Content-Transfer-Encoding: if we are MIMEing 1866e01d6f61SPeter Wemm ** and we are potentially converting from 8 bit to 7 bit 1867e01d6f61SPeter Wemm ** MIME. If converting, add a new CTE header in 1868e01d6f61SPeter Wemm ** mime8to7(). 1869e01d6f61SPeter Wemm */ 187012ed1c7cSGregory Neil Shapiro 1871c2aa98e2SPeter Wemm if (bitset(H_CTE, h->h_flags) && 1872e01d6f61SPeter Wemm bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 1873e01d6f61SPeter Wemm mci->mci_flags) && 1874e01d6f61SPeter Wemm !bitset(M87F_NO8TO7, flags)) 1875c2aa98e2SPeter Wemm { 1876c2aa98e2SPeter Wemm if (tTd(34, 11)) 187712ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (content-transfer-encoding))\n"); 1878c2aa98e2SPeter Wemm continue; 1879c2aa98e2SPeter Wemm } 1880c2aa98e2SPeter Wemm 1881c2aa98e2SPeter Wemm if (bitset(MCIF_INMIME, mci->mci_flags)) 1882c2aa98e2SPeter Wemm { 1883c2aa98e2SPeter Wemm if (tTd(34, 11)) 188412ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 1885567a2fc9SGregory Neil Shapiro if (!put_vanilla_header(h, p, mci)) 1886567a2fc9SGregory Neil Shapiro goto writeerr; 1887c2aa98e2SPeter Wemm continue; 1888c2aa98e2SPeter Wemm } 1889c2aa98e2SPeter Wemm 1890c2aa98e2SPeter Wemm if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 18913299c2f1SGregory Neil Shapiro !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && 18923299c2f1SGregory Neil Shapiro (h->h_macro == '\0' || 189312ed1c7cSGregory Neil Shapiro (q = macvalue(bitidx(h->h_macro), e)) == NULL || 189412ed1c7cSGregory Neil Shapiro *q == '\0')) 1895c2aa98e2SPeter Wemm { 1896c2aa98e2SPeter Wemm if (tTd(34, 11)) 189712ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped)\n"); 1898c2aa98e2SPeter Wemm continue; 1899c2aa98e2SPeter Wemm } 1900c2aa98e2SPeter Wemm 1901c2aa98e2SPeter Wemm /* handle Resent-... headers specially */ 1902c2aa98e2SPeter Wemm if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 1903c2aa98e2SPeter Wemm { 1904c2aa98e2SPeter Wemm if (tTd(34, 11)) 190512ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (resent))\n"); 1906c2aa98e2SPeter Wemm continue; 1907c2aa98e2SPeter Wemm } 1908c2aa98e2SPeter Wemm 1909c2aa98e2SPeter Wemm /* suppress return receipts if requested */ 1910c2aa98e2SPeter Wemm if (bitset(H_RECEIPTTO, h->h_flags) && 1911c2aa98e2SPeter Wemm (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) 1912c2aa98e2SPeter Wemm { 1913c2aa98e2SPeter Wemm if (tTd(34, 11)) 191412ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (receipt))\n"); 1915c2aa98e2SPeter Wemm continue; 1916c2aa98e2SPeter Wemm } 1917c2aa98e2SPeter Wemm 1918c2aa98e2SPeter Wemm /* macro expand value if generated internally */ 19193299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) || 19203299c2f1SGregory Neil Shapiro bitset(H_BINDLATE, h->h_flags)) 1921c2aa98e2SPeter Wemm { 1922951742c4SGregory Neil Shapiro expand(p, buf, sizeof(buf), e); 1923c2aa98e2SPeter Wemm p = buf; 1924c2aa98e2SPeter Wemm if (*p == '\0') 1925c2aa98e2SPeter Wemm { 1926c2aa98e2SPeter Wemm if (tTd(34, 11)) 192712ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- null value)\n"); 1928c2aa98e2SPeter Wemm continue; 1929c2aa98e2SPeter Wemm } 1930c2aa98e2SPeter Wemm } 1931c2aa98e2SPeter Wemm 19325b0945b5SGregory Neil Shapiro if (bitset(H_BCC, h->h_flags) && !KeepBcc) 1933c2aa98e2SPeter Wemm { 1934c2aa98e2SPeter Wemm /* Bcc: field -- either truncate or delete */ 1935c2aa98e2SPeter Wemm if (bitset(EF_DELETE_BCC, e->e_flags)) 1936c2aa98e2SPeter Wemm { 1937c2aa98e2SPeter Wemm if (tTd(34, 11)) 193812ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- bcc)\n"); 1939c2aa98e2SPeter Wemm } 1940c2aa98e2SPeter Wemm else 1941c2aa98e2SPeter Wemm { 1942c2aa98e2SPeter Wemm /* no other recipient headers: truncate value */ 1943951742c4SGregory Neil Shapiro (void) sm_strlcpyn(obuf, sizeof(obuf), 2, 194412ed1c7cSGregory Neil Shapiro h->h_field, ":"); 1945567a2fc9SGregory Neil Shapiro if (!putline(obuf, mci)) 1946567a2fc9SGregory Neil Shapiro goto writeerr; 1947c2aa98e2SPeter Wemm } 1948c2aa98e2SPeter Wemm continue; 1949c2aa98e2SPeter Wemm } 1950c2aa98e2SPeter Wemm 1951c2aa98e2SPeter Wemm if (tTd(34, 11)) 195212ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 1953c2aa98e2SPeter Wemm 1954c2aa98e2SPeter Wemm if (bitset(H_FROM|H_RCPT, h->h_flags)) 1955c2aa98e2SPeter Wemm { 1956c2aa98e2SPeter Wemm /* address field */ 1957c2aa98e2SPeter Wemm bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 1958c2aa98e2SPeter Wemm 1959c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 196012ed1c7cSGregory Neil Shapiro oldstyle = false; 1961da7d7b9cSGregory Neil Shapiro if (!commaize(h, p, oldstyle, mci, e, 1962da7d7b9cSGregory Neil Shapiro PXLF_HEADER | PXLF_STRIPMQUOTE) 1963da7d7b9cSGregory Neil Shapiro && bitnset(M_xSMTP, mci->mci_mailer->m_flags)) 1964da7d7b9cSGregory Neil Shapiro goto writeerr; 1965c2aa98e2SPeter Wemm } 1966c2aa98e2SPeter Wemm else 1967c2aa98e2SPeter Wemm { 1968567a2fc9SGregory Neil Shapiro if (!put_vanilla_header(h, p, mci)) 1969567a2fc9SGregory Neil Shapiro goto writeerr; 1970c2aa98e2SPeter Wemm } 1971c2aa98e2SPeter Wemm } 1972c2aa98e2SPeter Wemm 1973c2aa98e2SPeter Wemm /* 1974c2aa98e2SPeter Wemm ** If we are converting this to a MIME message, add the 19753299c2f1SGregory Neil Shapiro ** MIME headers (but not in MIME mode!). 1976c2aa98e2SPeter Wemm */ 1977c2aa98e2SPeter Wemm 1978c2aa98e2SPeter Wemm #if MIME8TO7 1979c2aa98e2SPeter Wemm if (bitset(MM_MIME8BIT, MimeMode) && 1980c2aa98e2SPeter Wemm bitset(EF_HAS8BIT, e->e_flags) && 1981c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 1982c2aa98e2SPeter Wemm !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 19833299c2f1SGregory Neil Shapiro !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) && 19843299c2f1SGregory Neil Shapiro hvalue("MIME-Version", e->e_header) == NULL) 1985c2aa98e2SPeter Wemm { 1986567a2fc9SGregory Neil Shapiro if (!putline("MIME-Version: 1.0", mci)) 1987567a2fc9SGregory Neil Shapiro goto writeerr; 1988c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL) 1989c2aa98e2SPeter Wemm { 1990951742c4SGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof(obuf), 1991c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s", 1992c2aa98e2SPeter Wemm defcharset(e)); 1993567a2fc9SGregory Neil Shapiro if (!putline(obuf, mci)) 1994567a2fc9SGregory Neil Shapiro goto writeerr; 1995c2aa98e2SPeter Wemm } 1996567a2fc9SGregory Neil Shapiro if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL 1997567a2fc9SGregory Neil Shapiro && !putline("Content-Transfer-Encoding: 8bit", mci)) 1998567a2fc9SGregory Neil Shapiro goto writeerr; 1999c2aa98e2SPeter Wemm } 20003299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */ 2001567a2fc9SGregory Neil Shapiro return true; 2002567a2fc9SGregory Neil Shapiro 2003567a2fc9SGregory Neil Shapiro writeerr: 2004567a2fc9SGregory Neil Shapiro return false; 2005c2aa98e2SPeter Wemm } 2006951742c4SGregory Neil Shapiro 200712ed1c7cSGregory Neil Shapiro /* 2008c2aa98e2SPeter Wemm ** PUT_VANILLA_HEADER -- output a fairly ordinary header 2009c2aa98e2SPeter Wemm ** 2010c2aa98e2SPeter Wemm ** Parameters: 2011c2aa98e2SPeter Wemm ** h -- the structure describing this header 2012c2aa98e2SPeter Wemm ** v -- the value of this header 2013c2aa98e2SPeter Wemm ** mci -- the connection info for output 2014c2aa98e2SPeter Wemm ** 2015c2aa98e2SPeter Wemm ** Returns: 2016355d91e3SGregory Neil Shapiro ** true iff header was written successfully 2017c2aa98e2SPeter Wemm */ 2018c2aa98e2SPeter Wemm 2019567a2fc9SGregory Neil Shapiro static bool 2020c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci) 2021c2aa98e2SPeter Wemm HDR *h; 2022c2aa98e2SPeter Wemm char *v; 2023c2aa98e2SPeter Wemm MCI *mci; 2024c2aa98e2SPeter Wemm { 2025c2aa98e2SPeter Wemm register char *nlp; 2026c2aa98e2SPeter Wemm register char *obp; 2027c2aa98e2SPeter Wemm int putflags; 2028684b2a5fSGregory Neil Shapiro char obuf[MAXLINE + 256]; /* additional length for h_field */ 2029c2aa98e2SPeter Wemm 2030951742c4SGregory Neil Shapiro putflags = PXLF_HEADER | PXLF_STRIPMQUOTE; 2031c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 2032c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 2033951742c4SGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field); 2034c2aa98e2SPeter Wemm obp = obuf + strlen(obuf); 2035c2aa98e2SPeter Wemm while ((nlp = strchr(v, '\n')) != NULL) 2036c2aa98e2SPeter Wemm { 2037c2aa98e2SPeter Wemm int l; 2038c2aa98e2SPeter Wemm 2039c2aa98e2SPeter Wemm l = nlp - v; 20407660b554SGregory Neil Shapiro 20417660b554SGregory Neil Shapiro /* 20427660b554SGregory Neil Shapiro ** XXX This is broken for SPACELEFT()==0 20437660b554SGregory Neil Shapiro ** However, SPACELEFT() is always > 0 unless MAXLINE==1. 20447660b554SGregory Neil Shapiro */ 20457660b554SGregory Neil Shapiro 20463299c2f1SGregory Neil Shapiro if (SPACELEFT(obuf, obp) - 1 < (size_t) l) 2047c2aa98e2SPeter Wemm l = SPACELEFT(obuf, obp) - 1; 2048c2aa98e2SPeter Wemm 204912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); 2050567a2fc9SGregory Neil Shapiro if (!putxline(obuf, strlen(obuf), mci, putflags)) 2051567a2fc9SGregory Neil Shapiro goto writeerr; 2052c2aa98e2SPeter Wemm v += l + 1; 2053c2aa98e2SPeter Wemm obp = obuf; 2054c2aa98e2SPeter Wemm if (*v != ' ' && *v != '\t') 2055c2aa98e2SPeter Wemm *obp++ = ' '; 2056c2aa98e2SPeter Wemm } 20577660b554SGregory Neil Shapiro 20587660b554SGregory Neil Shapiro /* XXX This is broken for SPACELEFT()==0 */ 205912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", 206012ed1c7cSGregory Neil Shapiro (int) (SPACELEFT(obuf, obp) - 1), v); 2061567a2fc9SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags); 2062567a2fc9SGregory Neil Shapiro 2063567a2fc9SGregory Neil Shapiro writeerr: 2064567a2fc9SGregory Neil Shapiro return false; 2065c2aa98e2SPeter Wemm } 2066951742c4SGregory Neil Shapiro 206712ed1c7cSGregory Neil Shapiro /* 2068c2aa98e2SPeter Wemm ** COMMAIZE -- output a header field, making a comma-translated list. 2069c2aa98e2SPeter Wemm ** 2070c2aa98e2SPeter Wemm ** Parameters: 2071c2aa98e2SPeter Wemm ** h -- the header field to output. 2072c2aa98e2SPeter Wemm ** p -- the value to put in it. 207312ed1c7cSGregory Neil Shapiro ** oldstyle -- true if this is an old style header. 2074c2aa98e2SPeter Wemm ** mci -- the connection information. 2075c2aa98e2SPeter Wemm ** e -- the envelope containing the message. 207641f3d2ceSGregory Neil Shapiro ** putflags -- flags for putxline() 2077c2aa98e2SPeter Wemm ** 2078c2aa98e2SPeter Wemm ** Returns: 2079355d91e3SGregory Neil Shapiro ** true iff header field was written successfully 2080c2aa98e2SPeter Wemm ** 2081c2aa98e2SPeter Wemm ** Side Effects: 2082951742c4SGregory Neil Shapiro ** outputs "p" to "mci". 2083c2aa98e2SPeter Wemm */ 2084c2aa98e2SPeter Wemm 2085567a2fc9SGregory Neil Shapiro bool 208641f3d2ceSGregory Neil Shapiro commaize(h, p, oldstyle, mci, e, putflags) 2087c2aa98e2SPeter Wemm register HDR *h; 2088c2aa98e2SPeter Wemm register char *p; 2089c2aa98e2SPeter Wemm bool oldstyle; 2090c2aa98e2SPeter Wemm register MCI *mci; 2091c2aa98e2SPeter Wemm register ENVELOPE *e; 209241f3d2ceSGregory Neil Shapiro int putflags; 2093c2aa98e2SPeter Wemm { 2094c2aa98e2SPeter Wemm register char *obp; 2095951742c4SGregory Neil Shapiro int opos, omax, spaces; 209612ed1c7cSGregory Neil Shapiro bool firstone = true; 20977660b554SGregory Neil Shapiro char **res; 2098c2aa98e2SPeter Wemm char obuf[MAXLINE + 3]; 2099c2aa98e2SPeter Wemm 2100c2aa98e2SPeter Wemm /* 2101c2aa98e2SPeter Wemm ** Output the address list translated by the 2102c2aa98e2SPeter Wemm ** mailer and with commas. 2103c2aa98e2SPeter Wemm */ 2104c2aa98e2SPeter Wemm 2105c2aa98e2SPeter Wemm if (tTd(14, 2)) 210612ed1c7cSGregory Neil Shapiro sm_dprintf("commaize(%s:%s)\n", h->h_field, p); 2107c2aa98e2SPeter Wemm 2108c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 2109c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 2110c2aa98e2SPeter Wemm 2111*2fb4f839SGregory Neil Shapiro #if _FFR_MTA_MODE 2112*2fb4f839SGregory Neil Shapiro /* activate this per mailer? */ 2113*2fb4f839SGregory Neil Shapiro if (bitset(H_FROM, h->h_flags) && bitset(H_ASIS, h->h_flags)) 2114*2fb4f839SGregory Neil Shapiro { 2115*2fb4f839SGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:%s", h->h_field, 2116*2fb4f839SGregory Neil Shapiro h->h_value); 2117*2fb4f839SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags); 2118*2fb4f839SGregory Neil Shapiro } 2119*2fb4f839SGregory Neil Shapiro #endif 2120*2fb4f839SGregory Neil Shapiro 2121c2aa98e2SPeter Wemm obp = obuf; 2122951742c4SGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field); 2123951742c4SGregory Neil Shapiro /* opos = strlen(obp); instead of the next 3 lines? */ 2124951742c4SGregory Neil Shapiro opos = strlen(h->h_field) + 1; 2125951742c4SGregory Neil Shapiro if (opos > 201) 2126951742c4SGregory Neil Shapiro opos = 201; 2127c2aa98e2SPeter Wemm obp += opos; 2128951742c4SGregory Neil Shapiro 2129951742c4SGregory Neil Shapiro spaces = 0; 21305b0945b5SGregory Neil Shapiro while (*p != '\0' && SM_ISSPACE(*p)) 2131951742c4SGregory Neil Shapiro { 2132951742c4SGregory Neil Shapiro ++spaces; 2133951742c4SGregory Neil Shapiro ++p; 2134951742c4SGregory Neil Shapiro } 2135951742c4SGregory Neil Shapiro if (spaces > 0) 2136951742c4SGregory Neil Shapiro { 2137951742c4SGregory Neil Shapiro SM_ASSERT(sizeof(obuf) > opos * 2); 2138951742c4SGregory Neil Shapiro 2139951742c4SGregory Neil Shapiro /* 2140951742c4SGregory Neil Shapiro ** Restrict number of spaces to half the length of buffer 2141951742c4SGregory Neil Shapiro ** so the header field body can be put in here too. 2142951742c4SGregory Neil Shapiro ** Note: this is a hack... 2143951742c4SGregory Neil Shapiro */ 2144951742c4SGregory Neil Shapiro 2145951742c4SGregory Neil Shapiro if (spaces > sizeof(obuf) / 2) 2146951742c4SGregory Neil Shapiro spaces = sizeof(obuf) / 2; 2147951742c4SGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces, 2148951742c4SGregory Neil Shapiro ""); 2149951742c4SGregory Neil Shapiro opos += spaces; 2150951742c4SGregory Neil Shapiro obp += spaces; 2151951742c4SGregory Neil Shapiro SM_ASSERT(obp < &obuf[MAXLINE]); 2152951742c4SGregory Neil Shapiro } 2153951742c4SGregory Neil Shapiro 2154c2aa98e2SPeter Wemm omax = mci->mci_mailer->m_linelimit - 2; 2155c2aa98e2SPeter Wemm if (omax < 0 || omax > 78) 2156c2aa98e2SPeter Wemm omax = 78; 2157c2aa98e2SPeter Wemm 2158c2aa98e2SPeter Wemm /* 2159c2aa98e2SPeter Wemm ** Run through the list of values. 2160c2aa98e2SPeter Wemm */ 2161c2aa98e2SPeter Wemm 2162c2aa98e2SPeter Wemm while (*p != '\0') 2163c2aa98e2SPeter Wemm { 2164c2aa98e2SPeter Wemm register char *name; 2165c2aa98e2SPeter Wemm register int c; 2166c2aa98e2SPeter Wemm char savechar; 2167c2aa98e2SPeter Wemm int flags; 21683299c2f1SGregory Neil Shapiro auto int status; 2169c2aa98e2SPeter Wemm 2170c2aa98e2SPeter Wemm /* 2171c2aa98e2SPeter Wemm ** Find the end of the name. New style names 2172c2aa98e2SPeter Wemm ** end with a comma, old style names end with 2173c2aa98e2SPeter Wemm ** a space character. However, spaces do not 2174c2aa98e2SPeter Wemm ** necessarily delimit an old-style name -- at 2175c2aa98e2SPeter Wemm ** signs mean keep going. 2176c2aa98e2SPeter Wemm */ 2177c2aa98e2SPeter Wemm 2178c2aa98e2SPeter Wemm /* find end of name */ 21795b0945b5SGregory Neil Shapiro while ((SM_ISSPACE(*p)) || *p == ',') 2180c2aa98e2SPeter Wemm p++; 2181c2aa98e2SPeter Wemm name = p; 21827660b554SGregory Neil Shapiro res = NULL; 2183c2aa98e2SPeter Wemm for (;;) 2184c2aa98e2SPeter Wemm { 2185c2aa98e2SPeter Wemm auto char *oldp; 2186c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 2187c2aa98e2SPeter Wemm 21887660b554SGregory Neil Shapiro res = prescan(p, oldstyle ? ' ' : ',', pvpbuf, 2189951742c4SGregory Neil Shapiro sizeof(pvpbuf), &oldp, ExtTokenTab, false); 2190c2aa98e2SPeter Wemm p = oldp; 21917660b554SGregory Neil Shapiro #if _FFR_IGNORE_BOGUS_ADDR 21927660b554SGregory Neil Shapiro /* ignore addresses that can't be parsed */ 21937660b554SGregory Neil Shapiro if (res == NULL) 21947660b554SGregory Neil Shapiro { 21957660b554SGregory Neil Shapiro name = p; 21967660b554SGregory Neil Shapiro continue; 21977660b554SGregory Neil Shapiro } 21987660b554SGregory Neil Shapiro #endif /* _FFR_IGNORE_BOGUS_ADDR */ 2199c2aa98e2SPeter Wemm 2200c2aa98e2SPeter Wemm /* look to see if we have an at sign */ 22015b0945b5SGregory Neil Shapiro while (*p != '\0' && SM_ISSPACE(*p)) 2202c2aa98e2SPeter Wemm p++; 2203c2aa98e2SPeter Wemm 2204c2aa98e2SPeter Wemm if (*p != '@') 2205c2aa98e2SPeter Wemm { 2206c2aa98e2SPeter Wemm p = oldp; 2207c2aa98e2SPeter Wemm break; 2208c2aa98e2SPeter Wemm } 220912ed1c7cSGregory Neil Shapiro ++p; 22105b0945b5SGregory Neil Shapiro while (*p != '\0' && SM_ISSPACE(*p)) 2211c2aa98e2SPeter Wemm p++; 2212c2aa98e2SPeter Wemm } 2213c2aa98e2SPeter Wemm /* at the end of one complete name */ 2214c2aa98e2SPeter Wemm 2215c2aa98e2SPeter Wemm /* strip off trailing white space */ 2216c2aa98e2SPeter Wemm while (p >= name && 22175b0945b5SGregory Neil Shapiro ((SM_ISSPACE(*p)) || *p == ',' || *p == '\0')) 2218c2aa98e2SPeter Wemm p--; 2219c2aa98e2SPeter Wemm if (++p == name) 2220c2aa98e2SPeter Wemm continue; 22217660b554SGregory Neil Shapiro 22227660b554SGregory Neil Shapiro /* 22237660b554SGregory Neil Shapiro ** if prescan() failed go a bit backwards; this is a hack, 22247660b554SGregory Neil Shapiro ** there should be some better error recovery. 22257660b554SGregory Neil Shapiro */ 22267660b554SGregory Neil Shapiro 22277660b554SGregory Neil Shapiro if (res == NULL && p > name && 22285b0945b5SGregory Neil Shapiro !((SM_ISSPACE(*p)) || *p == ',' || *p == '\0')) 22297660b554SGregory Neil Shapiro --p; 2230c2aa98e2SPeter Wemm savechar = *p; 2231c2aa98e2SPeter Wemm *p = '\0'; 2232c2aa98e2SPeter Wemm 2233c2aa98e2SPeter Wemm /* translate the name to be relative */ 2234c2aa98e2SPeter Wemm flags = RF_HEADERADDR|RF_ADDDOMAIN; 2235c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 2236c2aa98e2SPeter Wemm flags |= RF_SENDERADDR; 2237c2aa98e2SPeter Wemm #if USERDB 2238c2aa98e2SPeter Wemm else if (e->e_from.q_mailer != NULL && 2239c2aa98e2SPeter Wemm bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 2240c2aa98e2SPeter Wemm { 2241c2aa98e2SPeter Wemm char *q; 2242c2aa98e2SPeter Wemm 224312ed1c7cSGregory Neil Shapiro q = udbsender(name, e->e_rpool); 2244c2aa98e2SPeter Wemm if (q != NULL) 2245c2aa98e2SPeter Wemm name = q; 2246c2aa98e2SPeter Wemm } 22473299c2f1SGregory Neil Shapiro #endif /* USERDB */ 22483299c2f1SGregory Neil Shapiro status = EX_OK; 22493299c2f1SGregory Neil Shapiro name = remotename(name, mci->mci_mailer, flags, &status, e); 2250da7d7b9cSGregory Neil Shapiro if (status != EX_OK && bitnset(M_xSMTP, mci->mci_mailer->m_flags)) 2251da7d7b9cSGregory Neil Shapiro { 2252da7d7b9cSGregory Neil Shapiro if (status == EX_TEMPFAIL) 2253da7d7b9cSGregory Neil Shapiro mci->mci_flags |= MCIF_NOTSTICKY; 2254da7d7b9cSGregory Neil Shapiro goto writeerr; 2255da7d7b9cSGregory Neil Shapiro } 2256c2aa98e2SPeter Wemm if (*name == '\0') 2257c2aa98e2SPeter Wemm { 2258c2aa98e2SPeter Wemm *p = savechar; 2259c2aa98e2SPeter Wemm continue; 2260c2aa98e2SPeter Wemm } 226112ed1c7cSGregory Neil Shapiro name = denlstring(name, false, true); 2262c2aa98e2SPeter Wemm 2263c2aa98e2SPeter Wemm /* output the name with nice formatting */ 2264c2aa98e2SPeter Wemm opos += strlen(name); 2265c2aa98e2SPeter Wemm if (!firstone) 2266c2aa98e2SPeter Wemm opos += 2; 2267c2aa98e2SPeter Wemm if (opos > omax && !firstone) 2268c2aa98e2SPeter Wemm { 226912ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp)); 2270567a2fc9SGregory Neil Shapiro if (!putxline(obuf, strlen(obuf), mci, putflags)) 2271567a2fc9SGregory Neil Shapiro goto writeerr; 2272c2aa98e2SPeter Wemm obp = obuf; 2273951742c4SGregory Neil Shapiro (void) sm_strlcpy(obp, " ", sizeof(obuf)); 2274c2aa98e2SPeter Wemm opos = strlen(obp); 2275c2aa98e2SPeter Wemm obp += opos; 2276c2aa98e2SPeter Wemm opos += strlen(name); 2277c2aa98e2SPeter Wemm } 2278c2aa98e2SPeter Wemm else if (!firstone) 2279c2aa98e2SPeter Wemm { 228012ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp)); 2281c2aa98e2SPeter Wemm obp += 2; 2282c2aa98e2SPeter Wemm } 2283c2aa98e2SPeter Wemm 2284c2aa98e2SPeter Wemm while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 2285c2aa98e2SPeter Wemm *obp++ = c; 228612ed1c7cSGregory Neil Shapiro firstone = false; 2287c2aa98e2SPeter Wemm *p = savechar; 2288c2aa98e2SPeter Wemm } 2289951742c4SGregory Neil Shapiro if (obp < &obuf[sizeof(obuf)]) 2290c2aa98e2SPeter Wemm *obp = '\0'; 22917660b554SGregory Neil Shapiro else 2292951742c4SGregory Neil Shapiro obuf[sizeof(obuf) - 1] = '\0'; 2293567a2fc9SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags); 2294567a2fc9SGregory Neil Shapiro 2295567a2fc9SGregory Neil Shapiro writeerr: 2296567a2fc9SGregory Neil Shapiro return false; 2297c2aa98e2SPeter Wemm } 2298567a2fc9SGregory Neil Shapiro 229912ed1c7cSGregory Neil Shapiro /* 2300c2aa98e2SPeter Wemm ** COPYHEADER -- copy header list 2301c2aa98e2SPeter Wemm ** 2302c2aa98e2SPeter Wemm ** This routine is the equivalent of newstr for header lists 2303c2aa98e2SPeter Wemm ** 2304c2aa98e2SPeter Wemm ** Parameters: 2305c2aa98e2SPeter Wemm ** header -- list of header structures to copy. 230612ed1c7cSGregory Neil Shapiro ** rpool -- resource pool, or NULL 2307c2aa98e2SPeter Wemm ** 2308c2aa98e2SPeter Wemm ** Returns: 2309c2aa98e2SPeter Wemm ** a copy of 'header'. 2310c2aa98e2SPeter Wemm ** 2311c2aa98e2SPeter Wemm ** Side Effects: 2312c2aa98e2SPeter Wemm ** none. 2313c2aa98e2SPeter Wemm */ 2314c2aa98e2SPeter Wemm 2315c2aa98e2SPeter Wemm HDR * 231612ed1c7cSGregory Neil Shapiro copyheader(header, rpool) 2317c2aa98e2SPeter Wemm register HDR *header; 231812ed1c7cSGregory Neil Shapiro SM_RPOOL_T *rpool; 2319c2aa98e2SPeter Wemm { 2320c2aa98e2SPeter Wemm register HDR *newhdr; 2321c2aa98e2SPeter Wemm HDR *ret; 2322c2aa98e2SPeter Wemm register HDR **tail = &ret; 2323c2aa98e2SPeter Wemm 2324c2aa98e2SPeter Wemm while (header != NULL) 2325c2aa98e2SPeter Wemm { 2326951742c4SGregory Neil Shapiro newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr)); 2327c2aa98e2SPeter Wemm STRUCTCOPY(*header, *newhdr); 2328c2aa98e2SPeter Wemm *tail = newhdr; 2329c2aa98e2SPeter Wemm tail = &newhdr->h_link; 2330c2aa98e2SPeter Wemm header = header->h_link; 2331c2aa98e2SPeter Wemm } 2332c2aa98e2SPeter Wemm *tail = NULL; 2333c2aa98e2SPeter Wemm 2334c2aa98e2SPeter Wemm return ret; 2335c2aa98e2SPeter Wemm } 2336951742c4SGregory Neil Shapiro 233712ed1c7cSGregory Neil Shapiro /* 233876b7bf71SPeter Wemm ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header 233976b7bf71SPeter Wemm ** 234076b7bf71SPeter Wemm ** Run through all of the parameters of a MIME header and 234176b7bf71SPeter Wemm ** possibly truncate and rebalance the parameter according 234276b7bf71SPeter Wemm ** to MaxMimeFieldLength. 234376b7bf71SPeter Wemm ** 234476b7bf71SPeter Wemm ** Parameters: 2345f9218d3dSGregory Neil Shapiro ** h -- the header to truncate/rebalance 2346f9218d3dSGregory Neil Shapiro ** e -- the current envelope 234776b7bf71SPeter Wemm ** 234876b7bf71SPeter Wemm ** Returns: 2349c46d91b7SGregory Neil Shapiro ** length of last offending field, 0 if all ok. 235076b7bf71SPeter Wemm ** 235176b7bf71SPeter Wemm ** Side Effects: 235276b7bf71SPeter Wemm ** string modified in place 235376b7bf71SPeter Wemm */ 235476b7bf71SPeter Wemm 2355c46d91b7SGregory Neil Shapiro static size_t 2356f9218d3dSGregory Neil Shapiro fix_mime_header(h, e) 2357f9218d3dSGregory Neil Shapiro HDR *h; 2358f9218d3dSGregory Neil Shapiro ENVELOPE *e; 235976b7bf71SPeter Wemm { 2360f9218d3dSGregory Neil Shapiro char *begin = h->h_value; 236176b7bf71SPeter Wemm char *end; 2362c46d91b7SGregory Neil Shapiro size_t len = 0; 2363c46d91b7SGregory Neil Shapiro size_t retlen = 0; 236476b7bf71SPeter Wemm 2365*2fb4f839SGregory Neil Shapiro if (SM_IS_EMPTY(begin)) 2366c46d91b7SGregory Neil Shapiro return 0; 236776b7bf71SPeter Wemm 236876b7bf71SPeter Wemm /* Split on each ';' */ 23697660b554SGregory Neil Shapiro /* find_character() never returns NULL */ 237076b7bf71SPeter Wemm while ((end = find_character(begin, ';')) != NULL) 237176b7bf71SPeter Wemm { 237276b7bf71SPeter Wemm char save = *end; 237376b7bf71SPeter Wemm char *bp; 237476b7bf71SPeter Wemm 237576b7bf71SPeter Wemm *end = '\0'; 237676b7bf71SPeter Wemm 2377c46d91b7SGregory Neil Shapiro len = strlen(begin); 2378c46d91b7SGregory Neil Shapiro 237976b7bf71SPeter Wemm /* Shorten individual parameter */ 238076b7bf71SPeter Wemm if (shorten_rfc822_string(begin, MaxMimeFieldLength)) 2381f9218d3dSGregory Neil Shapiro { 2382f9218d3dSGregory Neil Shapiro if (len < MaxMimeFieldLength) 2383f9218d3dSGregory Neil Shapiro { 2384f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus field */ 2385f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 2386f9218d3dSGregory Neil Shapiro "Fixed MIME %s header field (possible attack)", 2387f9218d3dSGregory Neil Shapiro h->h_field); 2388f9218d3dSGregory Neil Shapiro if (tTd(34, 11)) 2389f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header field (possible attack)\n", 2390f9218d3dSGregory Neil Shapiro h->h_field); 2391f9218d3dSGregory Neil Shapiro } 2392f9218d3dSGregory Neil Shapiro else 2393f9218d3dSGregory Neil Shapiro { 2394f9218d3dSGregory Neil Shapiro /* we actually shortened the header */ 2395c46d91b7SGregory Neil Shapiro retlen = len; 2396f9218d3dSGregory Neil Shapiro } 2397f9218d3dSGregory Neil Shapiro } 239876b7bf71SPeter Wemm 239976b7bf71SPeter Wemm /* Collapse the possibly shortened string with rest */ 240076b7bf71SPeter Wemm bp = begin + strlen(begin); 240176b7bf71SPeter Wemm if (bp != end) 240276b7bf71SPeter Wemm { 240376b7bf71SPeter Wemm char *ep = end; 240476b7bf71SPeter Wemm 240576b7bf71SPeter Wemm *end = save; 240676b7bf71SPeter Wemm end = bp; 240776b7bf71SPeter Wemm 240876b7bf71SPeter Wemm /* copy character by character due to overlap */ 240976b7bf71SPeter Wemm while (*ep != '\0') 241076b7bf71SPeter Wemm *bp++ = *ep++; 241176b7bf71SPeter Wemm *bp = '\0'; 241276b7bf71SPeter Wemm } 241376b7bf71SPeter Wemm else 241476b7bf71SPeter Wemm *end = save; 241576b7bf71SPeter Wemm if (*end == '\0') 241676b7bf71SPeter Wemm break; 241776b7bf71SPeter Wemm 241876b7bf71SPeter Wemm /* Move past ';' */ 241976b7bf71SPeter Wemm begin = end + 1; 242076b7bf71SPeter Wemm } 2421c46d91b7SGregory Neil Shapiro return retlen; 242276b7bf71SPeter Wemm } 2423