1c2aa98e2SPeter Wemm /* 2951742c4SGregory Neil Shapiro * Copyright (c) 1998-2004, 2006, 2007 Sendmail, Inc. and its suppliers. 33299c2f1SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 1412ed1c7cSGregory Neil Shapiro #include <sendmail.h> 15951742c4SGregory Neil Shapiro #include <sm/sendmail.h> 16c2aa98e2SPeter Wemm 17*ba00ec3dSGregory Neil Shapiro SM_RCSID("@(#)$Id: headers.c,v 8.318 2012/06/14 23:54:02 ca Exp $") 183299c2f1SGregory Neil Shapiro 19951742c4SGregory Neil Shapiro static HDR *allocheader __P((char *, char *, int, SM_RPOOL_T *, bool)); 20f9218d3dSGregory Neil Shapiro static size_t fix_mime_header __P((HDR *, ENVELOPE *)); 213299c2f1SGregory Neil Shapiro static int priencode __P((char *)); 22567a2fc9SGregory Neil Shapiro static bool put_vanilla_header __P((HDR *, char *, MCI *)); 23c2aa98e2SPeter Wemm 24c2aa98e2SPeter Wemm /* 25c2aa98e2SPeter Wemm ** SETUPHEADERS -- initialize headers in symbol table 26c2aa98e2SPeter Wemm ** 27c2aa98e2SPeter Wemm ** Parameters: 28c2aa98e2SPeter Wemm ** none 29c2aa98e2SPeter Wemm ** 30c2aa98e2SPeter Wemm ** Returns: 31c2aa98e2SPeter Wemm ** none 32c2aa98e2SPeter Wemm */ 33c2aa98e2SPeter Wemm 34c2aa98e2SPeter Wemm void 35c2aa98e2SPeter Wemm setupheaders() 36c2aa98e2SPeter Wemm { 37c2aa98e2SPeter Wemm struct hdrinfo *hi; 38c2aa98e2SPeter Wemm STAB *s; 39c2aa98e2SPeter Wemm 40c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 41c2aa98e2SPeter Wemm { 42c2aa98e2SPeter Wemm s = stab(hi->hi_field, ST_HEADER, ST_ENTER); 43c2aa98e2SPeter Wemm s->s_header.hi_flags = hi->hi_flags; 44c2aa98e2SPeter Wemm s->s_header.hi_ruleset = NULL; 45c2aa98e2SPeter Wemm } 46c2aa98e2SPeter Wemm } 47951742c4SGregory Neil Shapiro 4812ed1c7cSGregory Neil Shapiro /* 49951742c4SGregory Neil Shapiro ** DOCHOMPHEADER -- process and save a header line. 50c2aa98e2SPeter Wemm ** 51951742c4SGregory Neil Shapiro ** Called by chompheader. 52c2aa98e2SPeter Wemm ** 53c2aa98e2SPeter Wemm ** Parameters: 54c2aa98e2SPeter Wemm ** line -- header as a text line. 55d995d2baSGregory Neil Shapiro ** pflag -- flags for chompheader() (from sendmail.h) 56c2aa98e2SPeter Wemm ** hdrp -- a pointer to the place to save the header. 57c2aa98e2SPeter Wemm ** e -- the envelope including this header. 58c2aa98e2SPeter Wemm ** 59c2aa98e2SPeter Wemm ** Returns: 60c2aa98e2SPeter Wemm ** flags for this header. 61c2aa98e2SPeter Wemm ** 62c2aa98e2SPeter Wemm ** Side Effects: 63c2aa98e2SPeter Wemm ** The header is saved on the header list. 64c2aa98e2SPeter Wemm ** Contents of 'line' are destroyed. 65c2aa98e2SPeter Wemm */ 66c2aa98e2SPeter Wemm 673299c2f1SGregory Neil Shapiro static struct hdrinfo NormalHeader = { NULL, 0, NULL }; 68951742c4SGregory Neil Shapiro static unsigned long dochompheader __P((char *, int, HDR **, ENVELOPE *)); 69c2aa98e2SPeter Wemm 70951742c4SGregory Neil Shapiro static unsigned long 71951742c4SGregory Neil Shapiro dochompheader(line, pflag, hdrp, e) 72c2aa98e2SPeter Wemm char *line; 733299c2f1SGregory Neil Shapiro int pflag; 74c2aa98e2SPeter Wemm HDR **hdrp; 75951742c4SGregory Neil Shapiro ENVELOPE *e; 76c2aa98e2SPeter Wemm { 7712ed1c7cSGregory Neil Shapiro unsigned char mid = '\0'; 78c2aa98e2SPeter Wemm register char *p; 79c2aa98e2SPeter Wemm register HDR *h; 80c2aa98e2SPeter Wemm HDR **hp; 81c2aa98e2SPeter Wemm char *fname; 82c2aa98e2SPeter Wemm char *fvalue; 8312ed1c7cSGregory Neil Shapiro bool cond = false; 843299c2f1SGregory Neil Shapiro bool dropfrom; 85c2aa98e2SPeter Wemm bool headeronly; 86c2aa98e2SPeter Wemm STAB *s; 87c2aa98e2SPeter Wemm struct hdrinfo *hi; 8812ed1c7cSGregory Neil Shapiro bool nullheader = false; 893299c2f1SGregory Neil Shapiro BITMAP256 mopts; 90c2aa98e2SPeter Wemm 91c2aa98e2SPeter Wemm headeronly = hdrp != NULL; 92c2aa98e2SPeter Wemm if (!headeronly) 93c2aa98e2SPeter Wemm hdrp = &e->e_header; 94c2aa98e2SPeter Wemm 95c2aa98e2SPeter Wemm /* strip off options */ 96c2aa98e2SPeter Wemm clrbitmap(mopts); 97c2aa98e2SPeter Wemm p = line; 983299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_USER) && *p == '?') 99c2aa98e2SPeter Wemm { 1003299c2f1SGregory Neil Shapiro int c; 1013299c2f1SGregory Neil Shapiro register char *q; 102c2aa98e2SPeter Wemm 1033299c2f1SGregory Neil Shapiro q = strchr(++p, '?'); 1043299c2f1SGregory Neil Shapiro if (q == NULL) 1053299c2f1SGregory Neil Shapiro goto hse; 1063299c2f1SGregory Neil Shapiro 1073299c2f1SGregory Neil Shapiro *q = '\0'; 1083299c2f1SGregory Neil Shapiro c = *p & 0377; 1093299c2f1SGregory Neil Shapiro 1103299c2f1SGregory Neil Shapiro /* possibly macro conditional */ 1113299c2f1SGregory Neil Shapiro if (c == MACROEXPAND) 112c2aa98e2SPeter Wemm { 1133299c2f1SGregory Neil Shapiro /* catch ?$? */ 1143299c2f1SGregory Neil Shapiro if (*++p == '\0') 1153299c2f1SGregory Neil Shapiro { 1163299c2f1SGregory Neil Shapiro *q = '?'; 1173299c2f1SGregory Neil Shapiro goto hse; 1183299c2f1SGregory Neil Shapiro } 1193299c2f1SGregory Neil Shapiro 12012ed1c7cSGregory Neil Shapiro mid = (unsigned char) *p++; 1213299c2f1SGregory Neil Shapiro 1223299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1233299c2f1SGregory Neil Shapiro if (*p != '\0') 1243299c2f1SGregory Neil Shapiro { 1253299c2f1SGregory Neil Shapiro *q = '?'; 1263299c2f1SGregory Neil Shapiro goto hse; 1273299c2f1SGregory Neil Shapiro } 1283299c2f1SGregory Neil Shapiro } 1293299c2f1SGregory Neil Shapiro else if (*p == '$') 1303299c2f1SGregory Neil Shapiro { 1313299c2f1SGregory Neil Shapiro /* catch ?$? */ 1323299c2f1SGregory Neil Shapiro if (*++p == '\0') 1333299c2f1SGregory Neil Shapiro { 1343299c2f1SGregory Neil Shapiro *q = '?'; 1353299c2f1SGregory Neil Shapiro goto hse; 1363299c2f1SGregory Neil Shapiro } 1373299c2f1SGregory Neil Shapiro 13812ed1c7cSGregory Neil Shapiro mid = (unsigned char) macid(p); 1393299c2f1SGregory Neil Shapiro if (bitset(0200, mid)) 1407660b554SGregory Neil Shapiro { 1413299c2f1SGregory Neil Shapiro p += strlen(macname(mid)) + 2; 1427660b554SGregory Neil Shapiro SM_ASSERT(p <= q); 1437660b554SGregory Neil Shapiro } 1443299c2f1SGregory Neil Shapiro else 1453299c2f1SGregory Neil Shapiro p++; 1463299c2f1SGregory Neil Shapiro 1473299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1483299c2f1SGregory Neil Shapiro if (*p != '\0') 1493299c2f1SGregory Neil Shapiro { 1503299c2f1SGregory Neil Shapiro *q = '?'; 1513299c2f1SGregory Neil Shapiro goto hse; 1523299c2f1SGregory Neil Shapiro } 153c2aa98e2SPeter Wemm } 154c2aa98e2SPeter Wemm else 1553299c2f1SGregory Neil Shapiro { 1563299c2f1SGregory Neil Shapiro while (*p != '\0') 1573299c2f1SGregory Neil Shapiro { 1583299c2f1SGregory Neil Shapiro if (!isascii(*p)) 1593299c2f1SGregory Neil Shapiro { 1603299c2f1SGregory Neil Shapiro *q = '?'; 1613299c2f1SGregory Neil Shapiro goto hse; 1623299c2f1SGregory Neil Shapiro } 1633299c2f1SGregory Neil Shapiro 164c46d91b7SGregory Neil Shapiro setbitn(bitidx(*p), mopts); 16512ed1c7cSGregory Neil Shapiro cond = true; 1663299c2f1SGregory Neil Shapiro p++; 1673299c2f1SGregory Neil Shapiro } 1683299c2f1SGregory Neil Shapiro } 1693299c2f1SGregory Neil Shapiro p = q + 1; 170c2aa98e2SPeter Wemm } 171c2aa98e2SPeter Wemm 172c2aa98e2SPeter Wemm /* find canonical name */ 173c2aa98e2SPeter Wemm fname = p; 174c2aa98e2SPeter Wemm while (isascii(*p) && isgraph(*p) && *p != ':') 175c2aa98e2SPeter Wemm p++; 176c2aa98e2SPeter Wemm fvalue = p; 177c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 178c2aa98e2SPeter Wemm p++; 179c2aa98e2SPeter Wemm if (*p++ != ':' || fname == fvalue) 180c2aa98e2SPeter Wemm { 1813299c2f1SGregory Neil Shapiro hse: 1823299c2f1SGregory Neil Shapiro syserr("553 5.3.0 header syntax error, line \"%s\"", line); 183c2aa98e2SPeter Wemm return 0; 184c2aa98e2SPeter Wemm } 185c2aa98e2SPeter Wemm *fvalue = '\0'; 186e01d6f61SPeter Wemm fvalue = p; 187e01d6f61SPeter Wemm 188e01d6f61SPeter Wemm /* if the field is null, go ahead and use the default */ 189e01d6f61SPeter Wemm while (isascii(*p) && isspace(*p)) 190e01d6f61SPeter Wemm p++; 191e01d6f61SPeter Wemm if (*p == '\0') 19212ed1c7cSGregory Neil Shapiro nullheader = true; 193c2aa98e2SPeter Wemm 194c2aa98e2SPeter Wemm /* security scan: long field names are end-of-header */ 195c2aa98e2SPeter Wemm if (strlen(fname) > 100) 196c2aa98e2SPeter Wemm return H_EOH; 197c2aa98e2SPeter Wemm 198c2aa98e2SPeter Wemm /* check to see if it represents a ruleset call */ 1993299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 200c2aa98e2SPeter Wemm { 201c2aa98e2SPeter Wemm char hbuf[50]; 202c2aa98e2SPeter Wemm 203951742c4SGregory Neil Shapiro (void) expand(fvalue, hbuf, sizeof(hbuf), e); 204c2aa98e2SPeter Wemm for (p = hbuf; isascii(*p) && isspace(*p); ) 205c2aa98e2SPeter Wemm p++; 206c2aa98e2SPeter Wemm if ((*p++ & 0377) == CALLSUBR) 207c2aa98e2SPeter Wemm { 208c2aa98e2SPeter Wemm auto char *endp; 2093299c2f1SGregory Neil Shapiro bool strc; 210c2aa98e2SPeter Wemm 2113299c2f1SGregory Neil Shapiro strc = *p == '+'; /* strip comments? */ 2123299c2f1SGregory Neil Shapiro if (strc) 2133299c2f1SGregory Neil Shapiro ++p; 214c2aa98e2SPeter Wemm if (strtorwset(p, &endp, ST_ENTER) > 0) 215c2aa98e2SPeter Wemm { 216c2aa98e2SPeter Wemm *endp = '\0'; 217c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_ENTER); 21812ed1c7cSGregory Neil Shapiro if (LogLevel > 9 && 21912ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset != NULL) 22012ed1c7cSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 22112ed1c7cSGregory Neil Shapiro "Warning: redefined ruleset for header=%s, old=%s, new=%s", 22212ed1c7cSGregory Neil Shapiro fname, 22312ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset, p); 224c2aa98e2SPeter Wemm s->s_header.hi_ruleset = newstr(p); 2253299c2f1SGregory Neil Shapiro if (!strc) 2263299c2f1SGregory Neil Shapiro s->s_header.hi_flags |= H_STRIPCOMM; 227c2aa98e2SPeter Wemm } 228c2aa98e2SPeter Wemm return 0; 229c2aa98e2SPeter Wemm } 230c2aa98e2SPeter Wemm } 231c2aa98e2SPeter Wemm 232c2aa98e2SPeter Wemm /* see if it is a known type */ 233c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_FIND); 234c2aa98e2SPeter Wemm if (s != NULL) 235c2aa98e2SPeter Wemm hi = &s->s_header; 236c2aa98e2SPeter Wemm else 237c2aa98e2SPeter Wemm hi = &NormalHeader; 238c2aa98e2SPeter Wemm 239c2aa98e2SPeter Wemm if (tTd(31, 9)) 240c2aa98e2SPeter Wemm { 241c2aa98e2SPeter Wemm if (s == NULL) 24212ed1c7cSGregory Neil Shapiro sm_dprintf("no header flags match\n"); 243c2aa98e2SPeter Wemm else 24412ed1c7cSGregory Neil Shapiro sm_dprintf("header match, flags=%lx, ruleset=%s\n", 245c2aa98e2SPeter Wemm hi->hi_flags, 24612ed1c7cSGregory Neil Shapiro hi->hi_ruleset == NULL ? "<NULL>" 24712ed1c7cSGregory Neil Shapiro : hi->hi_ruleset); 248c2aa98e2SPeter Wemm } 249c2aa98e2SPeter Wemm 250c2aa98e2SPeter Wemm /* see if this is a resent message */ 2513299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 2523299c2f1SGregory Neil Shapiro bitset(H_RESENT, hi->hi_flags)) 253c2aa98e2SPeter Wemm e->e_flags |= EF_RESENT; 254c2aa98e2SPeter Wemm 255c2aa98e2SPeter Wemm /* if this is an Errors-To: header keep track of it now */ 2563299c2f1SGregory Neil Shapiro if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly && 257c2aa98e2SPeter Wemm bitset(H_ERRORSTO, hi->hi_flags)) 258c2aa98e2SPeter Wemm (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 259c2aa98e2SPeter Wemm 260c2aa98e2SPeter Wemm /* if this means "end of header" quit now */ 261c2aa98e2SPeter Wemm if (!headeronly && bitset(H_EOH, hi->hi_flags)) 262c2aa98e2SPeter Wemm return hi->hi_flags; 263c2aa98e2SPeter Wemm 264c2aa98e2SPeter Wemm /* 265c2aa98e2SPeter Wemm ** Horrible hack to work around problem with Lotus Notes SMTP 266c2aa98e2SPeter Wemm ** mail gateway, which generates From: headers with newlines in 267c2aa98e2SPeter Wemm ** them and the <address> on the second line. Although this is 268c2aa98e2SPeter Wemm ** legal RFC 822, many MUAs don't handle this properly and thus 269c2aa98e2SPeter Wemm ** never find the actual address. 270c2aa98e2SPeter Wemm */ 271c2aa98e2SPeter Wemm 272c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader) 273c2aa98e2SPeter Wemm { 274c2aa98e2SPeter Wemm while ((p = strchr(fvalue, '\n')) != NULL) 275c2aa98e2SPeter Wemm *p = ' '; 276c2aa98e2SPeter Wemm } 277c2aa98e2SPeter Wemm 278c2aa98e2SPeter Wemm /* 279c2aa98e2SPeter Wemm ** If there is a check ruleset, verify it against the header. 280c2aa98e2SPeter Wemm */ 281c2aa98e2SPeter Wemm 2823299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_CHECK)) 2833299c2f1SGregory Neil Shapiro { 2849d8fddc1SGregory Neil Shapiro int rscheckflags; 2853299c2f1SGregory Neil Shapiro char *rs; 2863299c2f1SGregory Neil Shapiro 2879d8fddc1SGregory Neil Shapiro rscheckflags = RSF_COUNT; 2889d8fddc1SGregory Neil Shapiro if (!bitset(hi->hi_flags, H_FROM|H_RCPT)) 2899d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_UNSTRUCTURED; 290bfb62e91SGregory Neil Shapiro 291bfb62e91SGregory Neil Shapiro /* no ruleset? look for default */ 292bfb62e91SGregory Neil Shapiro rs = hi->hi_ruleset; 2933299c2f1SGregory Neil Shapiro if (rs == NULL) 2943299c2f1SGregory Neil Shapiro { 2953299c2f1SGregory Neil Shapiro s = stab("*", ST_HEADER, ST_FIND); 2963299c2f1SGregory Neil Shapiro if (s != NULL) 2973299c2f1SGregory Neil Shapiro { 2983299c2f1SGregory Neil Shapiro rs = (&s->s_header)->hi_ruleset; 2999d8fddc1SGregory Neil Shapiro if (bitset((&s->s_header)->hi_flags, 3009d8fddc1SGregory Neil Shapiro H_STRIPCOMM)) 3019d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM; 3023299c2f1SGregory Neil Shapiro } 3033299c2f1SGregory Neil Shapiro } 3049d8fddc1SGregory Neil Shapiro else if (bitset(hi->hi_flags, H_STRIPCOMM)) 3059d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM; 3063299c2f1SGregory Neil Shapiro if (rs != NULL) 3073299c2f1SGregory Neil Shapiro { 30812ed1c7cSGregory Neil Shapiro int l, k; 3093299c2f1SGregory Neil Shapiro char qval[MAXNAME]; 3103299c2f1SGregory Neil Shapiro 3113299c2f1SGregory Neil Shapiro l = 0; 31212ed1c7cSGregory Neil Shapiro qval[l++] = '"'; 31312ed1c7cSGregory Neil Shapiro 31412ed1c7cSGregory Neil Shapiro /* - 3 to avoid problems with " at the end */ 3157660b554SGregory Neil Shapiro /* should be sizeof(qval), not MAXNAME */ 31612ed1c7cSGregory Neil Shapiro for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++) 3173299c2f1SGregory Neil Shapiro { 31812ed1c7cSGregory Neil Shapiro switch (fvalue[k]) 3193299c2f1SGregory Neil Shapiro { 32012ed1c7cSGregory Neil Shapiro /* XXX other control chars? */ 3213299c2f1SGregory Neil Shapiro case '\011': /* ht */ 3223299c2f1SGregory Neil Shapiro case '\012': /* nl */ 3233299c2f1SGregory Neil Shapiro case '\013': /* vt */ 3243299c2f1SGregory Neil Shapiro case '\014': /* np */ 3253299c2f1SGregory Neil Shapiro case '\015': /* cr */ 32612ed1c7cSGregory Neil Shapiro qval[l++] = ' '; 3273299c2f1SGregory Neil Shapiro break; 3283299c2f1SGregory Neil Shapiro case '"': 32912ed1c7cSGregory Neil Shapiro qval[l++] = '\\'; 3303299c2f1SGregory Neil Shapiro /* FALLTHROUGH */ 3313299c2f1SGregory Neil Shapiro default: 33212ed1c7cSGregory Neil Shapiro qval[l++] = fvalue[k]; 3333299c2f1SGregory Neil Shapiro break; 3343299c2f1SGregory Neil Shapiro } 3353299c2f1SGregory Neil Shapiro } 33612ed1c7cSGregory Neil Shapiro qval[l++] = '"'; 33712ed1c7cSGregory Neil Shapiro qval[l] = '\0'; 33812ed1c7cSGregory Neil Shapiro k += strlen(fvalue + k); 33912ed1c7cSGregory Neil Shapiro if (k >= MAXNAME) 3403299c2f1SGregory Neil Shapiro { 3413299c2f1SGregory Neil Shapiro if (LogLevel > 9) 3423299c2f1SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 3433299c2f1SGregory Neil Shapiro "Warning: truncated header '%s' before check with '%s' len=%d max=%d", 34412ed1c7cSGregory Neil Shapiro fname, rs, k, MAXNAME - 1); 3453299c2f1SGregory Neil Shapiro } 34612ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 34712ed1c7cSGregory Neil Shapiro macid("{currHeader}"), qval); 34812ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 34912ed1c7cSGregory Neil Shapiro macid("{hdr_name}"), fname); 35012ed1c7cSGregory Neil Shapiro 351951742c4SGregory Neil Shapiro (void) sm_snprintf(qval, sizeof(qval), "%d", k); 35212ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval); 353bfb62e91SGregory Neil Shapiro if (bitset(H_FROM, hi->hi_flags)) 35412ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 35512ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h s"); 356bfb62e91SGregory Neil Shapiro else if (bitset(H_RCPT, hi->hi_flags)) 35712ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 35812ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h r"); 35912ed1c7cSGregory Neil Shapiro else 36012ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 36112ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h"); 3629d8fddc1SGregory Neil Shapiro (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3, 363951742c4SGregory Neil Shapiro NULL, e->e_id, NULL); 3643299c2f1SGregory Neil Shapiro } 3653299c2f1SGregory Neil Shapiro } 366c2aa98e2SPeter Wemm 367c2aa98e2SPeter Wemm /* 368c2aa98e2SPeter Wemm ** Drop explicit From: if same as what we would generate. 369c2aa98e2SPeter Wemm ** This is to make MH (which doesn't always give a full name) 370c2aa98e2SPeter Wemm ** insert the full name information in all circumstances. 371c2aa98e2SPeter Wemm */ 372c2aa98e2SPeter Wemm 37312ed1c7cSGregory Neil Shapiro dropfrom = false; 374c2aa98e2SPeter Wemm p = "resent-from"; 375c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 376c2aa98e2SPeter Wemm p += 7; 3773299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 37812ed1c7cSGregory Neil Shapiro !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0) 379c2aa98e2SPeter Wemm { 380c2aa98e2SPeter Wemm if (tTd(31, 2)) 381c2aa98e2SPeter Wemm { 38212ed1c7cSGregory Neil Shapiro sm_dprintf("comparing header from (%s) against default (%s or %s)\n", 383c2aa98e2SPeter Wemm fvalue, e->e_from.q_paddr, e->e_from.q_user); 384c2aa98e2SPeter Wemm } 385c2aa98e2SPeter Wemm if (e->e_from.q_paddr != NULL && 3863299c2f1SGregory Neil Shapiro e->e_from.q_mailer != NULL && 3873299c2f1SGregory Neil Shapiro bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && 388c2aa98e2SPeter Wemm (strcmp(fvalue, e->e_from.q_paddr) == 0 || 389c2aa98e2SPeter Wemm strcmp(fvalue, e->e_from.q_user) == 0)) 39012ed1c7cSGregory Neil Shapiro dropfrom = true; 391c2aa98e2SPeter Wemm } 392c2aa98e2SPeter Wemm 393c2aa98e2SPeter Wemm /* delete default value for this header */ 394c2aa98e2SPeter Wemm for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 395c2aa98e2SPeter Wemm { 39612ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(fname, h->h_field) == 0 && 3973299c2f1SGregory Neil Shapiro !bitset(H_USER, h->h_flags) && 398c2aa98e2SPeter Wemm !bitset(H_FORCE, h->h_flags)) 399c2aa98e2SPeter Wemm { 400e01d6f61SPeter Wemm if (nullheader) 401e01d6f61SPeter Wemm { 402e01d6f61SPeter Wemm /* user-supplied value was null */ 403e01d6f61SPeter Wemm return 0; 404e01d6f61SPeter Wemm } 4053299c2f1SGregory Neil Shapiro if (dropfrom) 4063299c2f1SGregory Neil Shapiro { 4073299c2f1SGregory Neil Shapiro /* make this look like the user entered it */ 4083299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 4093299c2f1SGregory Neil Shapiro return hi->hi_flags; 4103299c2f1SGregory Neil Shapiro } 411c2aa98e2SPeter Wemm h->h_value = NULL; 412c2aa98e2SPeter Wemm if (!cond) 413c2aa98e2SPeter Wemm { 414c2aa98e2SPeter Wemm /* copy conditions from default case */ 4153299c2f1SGregory Neil Shapiro memmove((char *) mopts, (char *) h->h_mflags, 416951742c4SGregory Neil Shapiro sizeof(mopts)); 417c2aa98e2SPeter Wemm } 4183299c2f1SGregory Neil Shapiro h->h_macro = mid; 419c2aa98e2SPeter Wemm } 420c2aa98e2SPeter Wemm } 421c2aa98e2SPeter Wemm 422c2aa98e2SPeter Wemm /* create a new node */ 423951742c4SGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof(*h)); 42412ed1c7cSGregory Neil Shapiro h->h_field = sm_rpool_strdup_x(e->e_rpool, fname); 42512ed1c7cSGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue); 426c2aa98e2SPeter Wemm h->h_link = NULL; 427951742c4SGregory Neil Shapiro memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts)); 4283299c2f1SGregory Neil Shapiro h->h_macro = mid; 429c2aa98e2SPeter Wemm *hp = h; 430c2aa98e2SPeter Wemm h->h_flags = hi->hi_flags; 431d995d2baSGregory Neil Shapiro if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE)) 4323299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 433c2aa98e2SPeter Wemm 434c2aa98e2SPeter Wemm /* strip EOH flag if parsing MIME headers */ 435c2aa98e2SPeter Wemm if (headeronly) 436c2aa98e2SPeter Wemm h->h_flags &= ~H_EOH; 4373299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 438c2aa98e2SPeter Wemm h->h_flags |= H_DEFAULT; 4393299c2f1SGregory Neil Shapiro if (cond || mid != '\0') 440c2aa98e2SPeter Wemm h->h_flags |= H_CHECK; 441c2aa98e2SPeter Wemm 442c2aa98e2SPeter Wemm /* hack to see if this is a new format message */ 4433299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 4443299c2f1SGregory Neil Shapiro bitset(H_RCPT|H_FROM, h->h_flags) && 445c2aa98e2SPeter Wemm (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 446c2aa98e2SPeter Wemm strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 447c2aa98e2SPeter Wemm { 448c2aa98e2SPeter Wemm e->e_flags &= ~EF_OLDSTYLE; 449c2aa98e2SPeter Wemm } 450c2aa98e2SPeter Wemm 451c2aa98e2SPeter Wemm return h->h_flags; 452c2aa98e2SPeter Wemm } 453951742c4SGregory Neil Shapiro 454951742c4SGregory Neil Shapiro /* 455951742c4SGregory Neil Shapiro ** CHOMPHEADER -- process and save a header line. 456951742c4SGregory Neil Shapiro ** 457951742c4SGregory Neil Shapiro ** Called by collect, readcf, and readqf to deal with header lines. 458951742c4SGregory Neil Shapiro ** This is just a wrapper for dochompheader(). 459951742c4SGregory Neil Shapiro ** 460951742c4SGregory Neil Shapiro ** Parameters: 461951742c4SGregory Neil Shapiro ** line -- header as a text line. 462951742c4SGregory Neil Shapiro ** pflag -- flags for chompheader() (from sendmail.h) 463951742c4SGregory Neil Shapiro ** hdrp -- a pointer to the place to save the header. 464951742c4SGregory Neil Shapiro ** e -- the envelope including this header. 465951742c4SGregory Neil Shapiro ** 466951742c4SGregory Neil Shapiro ** Returns: 467951742c4SGregory Neil Shapiro ** flags for this header. 468951742c4SGregory Neil Shapiro ** 469951742c4SGregory Neil Shapiro ** Side Effects: 470951742c4SGregory Neil Shapiro ** The header is saved on the header list. 471951742c4SGregory Neil Shapiro ** Contents of 'line' are destroyed. 472951742c4SGregory Neil Shapiro */ 473951742c4SGregory Neil Shapiro 474951742c4SGregory Neil Shapiro 475951742c4SGregory Neil Shapiro unsigned long 476951742c4SGregory Neil Shapiro chompheader(line, pflag, hdrp, e) 477951742c4SGregory Neil Shapiro char *line; 478951742c4SGregory Neil Shapiro int pflag; 479951742c4SGregory Neil Shapiro HDR **hdrp; 480951742c4SGregory Neil Shapiro register ENVELOPE *e; 481951742c4SGregory Neil Shapiro { 482951742c4SGregory Neil Shapiro unsigned long rval; 483951742c4SGregory Neil Shapiro 484951742c4SGregory Neil Shapiro if (tTd(31, 6)) 485951742c4SGregory Neil Shapiro { 486951742c4SGregory Neil Shapiro sm_dprintf("chompheader: "); 487951742c4SGregory Neil Shapiro xputs(sm_debug_file(), line); 488951742c4SGregory Neil Shapiro sm_dprintf("\n"); 489951742c4SGregory Neil Shapiro } 490951742c4SGregory Neil Shapiro 491951742c4SGregory Neil Shapiro /* quote this if user (not config file) input */ 492951742c4SGregory Neil Shapiro if (bitset(pflag, CHHDR_USER)) 493951742c4SGregory Neil Shapiro { 494951742c4SGregory Neil Shapiro char xbuf[MAXLINE]; 495951742c4SGregory Neil Shapiro char *xbp = NULL; 496951742c4SGregory Neil Shapiro int xbufs; 497951742c4SGregory Neil Shapiro 498951742c4SGregory Neil Shapiro xbufs = sizeof(xbuf); 499951742c4SGregory Neil Shapiro xbp = quote_internal_chars(line, xbuf, &xbufs); 500951742c4SGregory Neil Shapiro if (tTd(31, 7)) 501951742c4SGregory Neil Shapiro { 502951742c4SGregory Neil Shapiro sm_dprintf("chompheader: quoted: "); 503951742c4SGregory Neil Shapiro xputs(sm_debug_file(), xbp); 504951742c4SGregory Neil Shapiro sm_dprintf("\n"); 505951742c4SGregory Neil Shapiro } 506951742c4SGregory Neil Shapiro rval = dochompheader(xbp, pflag, hdrp, e); 507951742c4SGregory Neil Shapiro if (xbp != xbuf) 508951742c4SGregory Neil Shapiro sm_free(xbp); 509951742c4SGregory Neil Shapiro } 510951742c4SGregory Neil Shapiro else 511951742c4SGregory Neil Shapiro rval = dochompheader(line, pflag, hdrp, e); 512951742c4SGregory Neil Shapiro 513951742c4SGregory Neil Shapiro return rval; 514951742c4SGregory Neil Shapiro } 515951742c4SGregory Neil Shapiro 51612ed1c7cSGregory Neil Shapiro /* 517bfb62e91SGregory Neil Shapiro ** ALLOCHEADER -- allocate a header entry 518bfb62e91SGregory Neil Shapiro ** 519bfb62e91SGregory Neil Shapiro ** Parameters: 520951742c4SGregory Neil Shapiro ** field -- the name of the header field (will not be copied). 521951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied). 522bfb62e91SGregory Neil Shapiro ** flags -- flags to add to h_flags. 523bfb62e91SGregory Neil Shapiro ** rp -- resource pool for allocations 524951742c4SGregory Neil Shapiro ** space -- add leading space? 525bfb62e91SGregory Neil Shapiro ** 526bfb62e91SGregory Neil Shapiro ** Returns: 527bfb62e91SGregory Neil Shapiro ** Pointer to a newly allocated and populated HDR. 528951742c4SGregory Neil Shapiro ** 529951742c4SGregory Neil Shapiro ** Notes: 530951742c4SGregory Neil Shapiro ** o field and value must be in internal format, i.e., 531951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars(). 532951742c4SGregory Neil Shapiro ** o maybe add more flags to decide: 533951742c4SGregory Neil Shapiro ** - what to copy (field/value) 534951742c4SGregory Neil Shapiro ** - whether to convert value to an internal format 535bfb62e91SGregory Neil Shapiro */ 536bfb62e91SGregory Neil Shapiro 537bfb62e91SGregory Neil Shapiro static HDR * 538951742c4SGregory Neil Shapiro allocheader(field, value, flags, rp, space) 539bfb62e91SGregory Neil Shapiro char *field; 540bfb62e91SGregory Neil Shapiro char *value; 541bfb62e91SGregory Neil Shapiro int flags; 542bfb62e91SGregory Neil Shapiro SM_RPOOL_T *rp; 543951742c4SGregory Neil Shapiro bool space; 544bfb62e91SGregory Neil Shapiro { 545bfb62e91SGregory Neil Shapiro HDR *h; 546bfb62e91SGregory Neil Shapiro STAB *s; 547bfb62e91SGregory Neil Shapiro 548bfb62e91SGregory Neil Shapiro /* find info struct */ 549bfb62e91SGregory Neil Shapiro s = stab(field, ST_HEADER, ST_FIND); 550bfb62e91SGregory Neil Shapiro 551bfb62e91SGregory Neil Shapiro /* allocate space for new header */ 552951742c4SGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h)); 553bfb62e91SGregory Neil Shapiro h->h_field = field; 554951742c4SGregory Neil Shapiro if (space) 555951742c4SGregory Neil Shapiro { 556951742c4SGregory Neil Shapiro size_t l; 557951742c4SGregory Neil Shapiro char *n; 558951742c4SGregory Neil Shapiro 559951742c4SGregory Neil Shapiro l = strlen(value); 560951742c4SGregory Neil Shapiro SM_ASSERT(l + 2 > l); 561951742c4SGregory Neil Shapiro n = sm_rpool_malloc_x(rp, l + 2); 562951742c4SGregory Neil Shapiro n[0] = ' '; 563951742c4SGregory Neil Shapiro n[1] = '\0'; 564951742c4SGregory Neil Shapiro sm_strlcpy(n + 1, value, l + 1); 565951742c4SGregory Neil Shapiro h->h_value = n; 566951742c4SGregory Neil Shapiro } 567951742c4SGregory Neil Shapiro else 568bfb62e91SGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(rp, value); 569bfb62e91SGregory Neil Shapiro h->h_flags = flags; 570bfb62e91SGregory Neil Shapiro if (s != NULL) 571bfb62e91SGregory Neil Shapiro h->h_flags |= s->s_header.hi_flags; 572bfb62e91SGregory Neil Shapiro clrbitmap(h->h_mflags); 573bfb62e91SGregory Neil Shapiro h->h_macro = '\0'; 574bfb62e91SGregory Neil Shapiro 575bfb62e91SGregory Neil Shapiro return h; 576bfb62e91SGregory Neil Shapiro } 577951742c4SGregory Neil Shapiro 578bfb62e91SGregory Neil Shapiro /* 579c2aa98e2SPeter Wemm ** ADDHEADER -- add a header entry to the end of the queue. 580c2aa98e2SPeter Wemm ** 581c2aa98e2SPeter Wemm ** This bypasses the special checking of chompheader. 582c2aa98e2SPeter Wemm ** 583c2aa98e2SPeter Wemm ** Parameters: 584951742c4SGregory Neil Shapiro ** field -- the name of the header field (will not be copied). 585951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied). 5863299c2f1SGregory Neil Shapiro ** flags -- flags to add to h_flags. 58712ed1c7cSGregory Neil Shapiro ** e -- envelope. 588951742c4SGregory Neil Shapiro ** space -- add leading space? 589c2aa98e2SPeter Wemm ** 590c2aa98e2SPeter Wemm ** Returns: 591c2aa98e2SPeter Wemm ** none. 592c2aa98e2SPeter Wemm ** 593c2aa98e2SPeter Wemm ** Side Effects: 594c2aa98e2SPeter Wemm ** adds the field on the list of headers for this envelope. 595951742c4SGregory Neil Shapiro ** 596951742c4SGregory Neil Shapiro ** Notes: field and value must be in internal format, i.e., 597951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars(). 598c2aa98e2SPeter Wemm */ 599c2aa98e2SPeter Wemm 600c2aa98e2SPeter Wemm void 601951742c4SGregory Neil Shapiro addheader(field, value, flags, e, space) 602c2aa98e2SPeter Wemm char *field; 603c2aa98e2SPeter Wemm char *value; 6043299c2f1SGregory Neil Shapiro int flags; 60512ed1c7cSGregory Neil Shapiro ENVELOPE *e; 606951742c4SGregory Neil Shapiro bool space; 607c2aa98e2SPeter Wemm { 608c2aa98e2SPeter Wemm register HDR *h; 609c2aa98e2SPeter Wemm HDR **hp; 61012ed1c7cSGregory Neil Shapiro HDR **hdrlist = &e->e_header; 611c2aa98e2SPeter Wemm 612c2aa98e2SPeter Wemm /* find current place in list -- keep back pointer? */ 613c2aa98e2SPeter Wemm for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 614c2aa98e2SPeter Wemm { 61512ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(field, h->h_field) == 0) 616c2aa98e2SPeter Wemm break; 617c2aa98e2SPeter Wemm } 618c2aa98e2SPeter Wemm 619c2aa98e2SPeter Wemm /* allocate space for new header */ 620951742c4SGregory Neil Shapiro h = allocheader(field, value, flags, e->e_rpool, space); 621c2aa98e2SPeter Wemm h->h_link = *hp; 622c2aa98e2SPeter Wemm *hp = h; 623c2aa98e2SPeter Wemm } 624951742c4SGregory Neil Shapiro 62512ed1c7cSGregory Neil Shapiro /* 626bfb62e91SGregory Neil Shapiro ** INSHEADER -- insert a header entry at the specified index 627bfb62e91SGregory Neil Shapiro ** This bypasses the special checking of chompheader. 628bfb62e91SGregory Neil Shapiro ** 629bfb62e91SGregory Neil Shapiro ** Parameters: 630bfb62e91SGregory Neil Shapiro ** idx -- index into the header list at which to insert 631951742c4SGregory Neil Shapiro ** field -- the name of the header field (will be copied). 632951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied). 633bfb62e91SGregory Neil Shapiro ** flags -- flags to add to h_flags. 634bfb62e91SGregory Neil Shapiro ** e -- envelope. 635951742c4SGregory Neil Shapiro ** space -- add leading space? 636bfb62e91SGregory Neil Shapiro ** 637bfb62e91SGregory Neil Shapiro ** Returns: 638bfb62e91SGregory Neil Shapiro ** none. 639bfb62e91SGregory Neil Shapiro ** 640bfb62e91SGregory Neil Shapiro ** Side Effects: 641bfb62e91SGregory Neil Shapiro ** inserts the field on the list of headers for this envelope. 642951742c4SGregory Neil Shapiro ** 643951742c4SGregory Neil Shapiro ** Notes: 644951742c4SGregory Neil Shapiro ** - field and value must be in internal format, i.e., 645951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars(). 646951742c4SGregory Neil Shapiro ** - the header list contains headers that might not be 647951742c4SGregory Neil Shapiro ** sent "out" (see putheader(): "skip"), hence there is no 648951742c4SGregory Neil Shapiro ** reliable way to insert a header at an exact position 649951742c4SGregory Neil Shapiro ** (except at the front or end). 650bfb62e91SGregory Neil Shapiro */ 651bfb62e91SGregory Neil Shapiro 652bfb62e91SGregory Neil Shapiro void 653951742c4SGregory Neil Shapiro insheader(idx, field, value, flags, e, space) 654bfb62e91SGregory Neil Shapiro int idx; 655bfb62e91SGregory Neil Shapiro char *field; 656bfb62e91SGregory Neil Shapiro char *value; 657bfb62e91SGregory Neil Shapiro int flags; 658bfb62e91SGregory Neil Shapiro ENVELOPE *e; 659951742c4SGregory Neil Shapiro bool space; 660bfb62e91SGregory Neil Shapiro { 661bfb62e91SGregory Neil Shapiro HDR *h, *srch, *last = NULL; 662bfb62e91SGregory Neil Shapiro 663bfb62e91SGregory Neil Shapiro /* allocate space for new header */ 664951742c4SGregory Neil Shapiro h = allocheader(field, value, flags, e->e_rpool, space); 665bfb62e91SGregory Neil Shapiro 666bfb62e91SGregory Neil Shapiro /* find insertion position */ 667bfb62e91SGregory Neil Shapiro for (srch = e->e_header; srch != NULL && idx > 0; 668bfb62e91SGregory Neil Shapiro srch = srch->h_link, idx--) 669bfb62e91SGregory Neil Shapiro last = srch; 670bfb62e91SGregory Neil Shapiro 671bfb62e91SGregory Neil Shapiro if (e->e_header == NULL) 672bfb62e91SGregory Neil Shapiro { 673bfb62e91SGregory Neil Shapiro e->e_header = h; 674bfb62e91SGregory Neil Shapiro h->h_link = NULL; 675bfb62e91SGregory Neil Shapiro } 676bfb62e91SGregory Neil Shapiro else if (srch == NULL) 677bfb62e91SGregory Neil Shapiro { 678bfb62e91SGregory Neil Shapiro SM_ASSERT(last != NULL); 679bfb62e91SGregory Neil Shapiro last->h_link = h; 680bfb62e91SGregory Neil Shapiro h->h_link = NULL; 681bfb62e91SGregory Neil Shapiro } 682bfb62e91SGregory Neil Shapiro else 683bfb62e91SGregory Neil Shapiro { 684bfb62e91SGregory Neil Shapiro h->h_link = srch->h_link; 685bfb62e91SGregory Neil Shapiro srch->h_link = h; 686bfb62e91SGregory Neil Shapiro } 687bfb62e91SGregory Neil Shapiro } 688951742c4SGregory Neil Shapiro 689bfb62e91SGregory Neil Shapiro /* 690c2aa98e2SPeter Wemm ** HVALUE -- return value of a header. 691c2aa98e2SPeter Wemm ** 692c2aa98e2SPeter Wemm ** Only "real" fields (i.e., ones that have not been supplied 693c2aa98e2SPeter Wemm ** as a default) are used. 694c2aa98e2SPeter Wemm ** 695c2aa98e2SPeter Wemm ** Parameters: 696c2aa98e2SPeter Wemm ** field -- the field name. 697c2aa98e2SPeter Wemm ** header -- the header list. 698c2aa98e2SPeter Wemm ** 699c2aa98e2SPeter Wemm ** Returns: 700951742c4SGregory Neil Shapiro ** pointer to the value part (internal format). 701c2aa98e2SPeter Wemm ** NULL if not found. 702c2aa98e2SPeter Wemm ** 703c2aa98e2SPeter Wemm ** Side Effects: 704c2aa98e2SPeter Wemm ** none. 705c2aa98e2SPeter Wemm */ 706c2aa98e2SPeter Wemm 707c2aa98e2SPeter Wemm char * 708c2aa98e2SPeter Wemm hvalue(field, header) 709c2aa98e2SPeter Wemm char *field; 710c2aa98e2SPeter Wemm HDR *header; 711c2aa98e2SPeter Wemm { 712c2aa98e2SPeter Wemm register HDR *h; 713c2aa98e2SPeter Wemm 714c2aa98e2SPeter Wemm for (h = header; h != NULL; h = h->h_link) 715c2aa98e2SPeter Wemm { 716c2aa98e2SPeter Wemm if (!bitset(H_DEFAULT, h->h_flags) && 71712ed1c7cSGregory Neil Shapiro sm_strcasecmp(h->h_field, field) == 0) 7189bd497b8SGregory Neil Shapiro { 7199bd497b8SGregory Neil Shapiro char *s; 7209bd497b8SGregory Neil Shapiro 7219bd497b8SGregory Neil Shapiro s = h->h_value; 7229bd497b8SGregory Neil Shapiro if (s == NULL) 7239bd497b8SGregory Neil Shapiro return NULL; 7249bd497b8SGregory Neil Shapiro while (isascii(*s) && isspace(*s)) 7259bd497b8SGregory Neil Shapiro s++; 7269bd497b8SGregory Neil Shapiro return s; 7279bd497b8SGregory Neil Shapiro } 728c2aa98e2SPeter Wemm } 7293299c2f1SGregory Neil Shapiro return NULL; 730c2aa98e2SPeter Wemm } 731951742c4SGregory Neil Shapiro 73212ed1c7cSGregory Neil Shapiro /* 733c2aa98e2SPeter Wemm ** ISHEADER -- predicate telling if argument is a header. 734c2aa98e2SPeter Wemm ** 735c2aa98e2SPeter Wemm ** A line is a header if it has a single word followed by 736c2aa98e2SPeter Wemm ** optional white space followed by a colon. 737c2aa98e2SPeter Wemm ** 738c2aa98e2SPeter Wemm ** Header fields beginning with two dashes, although technically 739c2aa98e2SPeter Wemm ** permitted by RFC822, are automatically rejected in order 740c2aa98e2SPeter Wemm ** to make MIME work out. Without this we could have a technically 741c2aa98e2SPeter Wemm ** legal header such as ``--"foo:bar"'' that would also be a legal 742c2aa98e2SPeter Wemm ** MIME separator. 743c2aa98e2SPeter Wemm ** 744c2aa98e2SPeter Wemm ** Parameters: 745c2aa98e2SPeter Wemm ** h -- string to check for possible headerness. 746c2aa98e2SPeter Wemm ** 747c2aa98e2SPeter Wemm ** Returns: 74812ed1c7cSGregory Neil Shapiro ** true if h is a header. 74912ed1c7cSGregory Neil Shapiro ** false otherwise. 750c2aa98e2SPeter Wemm ** 751c2aa98e2SPeter Wemm ** Side Effects: 752c2aa98e2SPeter Wemm ** none. 753c2aa98e2SPeter Wemm */ 754c2aa98e2SPeter Wemm 755c2aa98e2SPeter Wemm bool 756c2aa98e2SPeter Wemm isheader(h) 757c2aa98e2SPeter Wemm char *h; 758c2aa98e2SPeter Wemm { 759951742c4SGregory Neil Shapiro char *s; 760c2aa98e2SPeter Wemm 761951742c4SGregory Neil Shapiro s = h; 762c2aa98e2SPeter Wemm if (s[0] == '-' && s[1] == '-') 76312ed1c7cSGregory Neil Shapiro return false; 764c2aa98e2SPeter Wemm 765c2aa98e2SPeter Wemm while (*s > ' ' && *s != ':' && *s != '\0') 766c2aa98e2SPeter Wemm s++; 767c2aa98e2SPeter Wemm 768c2aa98e2SPeter Wemm if (h == s) 76912ed1c7cSGregory Neil Shapiro return false; 770c2aa98e2SPeter Wemm 771c2aa98e2SPeter Wemm /* following technically violates RFC822 */ 772c2aa98e2SPeter Wemm while (isascii(*s) && isspace(*s)) 773c2aa98e2SPeter Wemm s++; 774c2aa98e2SPeter Wemm 775c2aa98e2SPeter Wemm return (*s == ':'); 776c2aa98e2SPeter Wemm } 777951742c4SGregory Neil Shapiro 77812ed1c7cSGregory Neil Shapiro /* 779c2aa98e2SPeter Wemm ** EATHEADER -- run through the stored header and extract info. 780c2aa98e2SPeter Wemm ** 781c2aa98e2SPeter Wemm ** Parameters: 782c2aa98e2SPeter Wemm ** e -- the envelope to process. 783c2aa98e2SPeter Wemm ** full -- if set, do full processing (e.g., compute 784c2aa98e2SPeter Wemm ** message priority). This should not be set 785c2aa98e2SPeter Wemm ** when reading a queue file because some info 786c2aa98e2SPeter Wemm ** needed to compute the priority is wrong. 78712ed1c7cSGregory Neil Shapiro ** log -- call logsender()? 788c2aa98e2SPeter Wemm ** 789c2aa98e2SPeter Wemm ** Returns: 790c2aa98e2SPeter Wemm ** none. 791c2aa98e2SPeter Wemm ** 792c2aa98e2SPeter Wemm ** Side Effects: 793c2aa98e2SPeter Wemm ** Sets a bunch of global variables from information 794c2aa98e2SPeter Wemm ** in the collected header. 795c2aa98e2SPeter Wemm */ 796c2aa98e2SPeter Wemm 797c2aa98e2SPeter Wemm void 79812ed1c7cSGregory Neil Shapiro eatheader(e, full, log) 799c2aa98e2SPeter Wemm register ENVELOPE *e; 800c2aa98e2SPeter Wemm bool full; 80112ed1c7cSGregory Neil Shapiro bool log; 802c2aa98e2SPeter Wemm { 803c2aa98e2SPeter Wemm register HDR *h; 804c2aa98e2SPeter Wemm register char *p; 805c2aa98e2SPeter Wemm int hopcnt = 0; 806c2aa98e2SPeter Wemm char buf[MAXLINE]; 807c2aa98e2SPeter Wemm 808c2aa98e2SPeter Wemm /* 809c2aa98e2SPeter Wemm ** Set up macros for possible expansion in headers. 810c2aa98e2SPeter Wemm */ 811c2aa98e2SPeter Wemm 81212ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'f', e->e_sender); 81312ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', e->e_sender); 814c2aa98e2SPeter Wemm if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 81512ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt); 816c2aa98e2SPeter Wemm else 81712ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', NULL); 818c2aa98e2SPeter Wemm 819c2aa98e2SPeter Wemm /* full name of from person */ 820c2aa98e2SPeter Wemm p = hvalue("full-name", e->e_header); 821c2aa98e2SPeter Wemm if (p != NULL) 822c2aa98e2SPeter Wemm { 823c2aa98e2SPeter Wemm if (!rfc822_string(p)) 824c2aa98e2SPeter Wemm { 825c2aa98e2SPeter Wemm /* 826c2aa98e2SPeter Wemm ** Quote a full name with special characters 827c2aa98e2SPeter Wemm ** as a comment so crackaddr() doesn't destroy 828c2aa98e2SPeter Wemm ** the name portion of the address. 829c2aa98e2SPeter Wemm */ 83012ed1c7cSGregory Neil Shapiro 83112ed1c7cSGregory Neil Shapiro p = addquotes(p, e->e_rpool); 832c2aa98e2SPeter Wemm } 83312ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'x', p); 834c2aa98e2SPeter Wemm } 835c2aa98e2SPeter Wemm 836c2aa98e2SPeter Wemm if (tTd(32, 1)) 83712ed1c7cSGregory Neil Shapiro sm_dprintf("----- collected header -----\n"); 83812ed1c7cSGregory Neil Shapiro e->e_msgid = NULL; 839c2aa98e2SPeter Wemm for (h = e->e_header; h != NULL; h = h->h_link) 840c2aa98e2SPeter Wemm { 841c2aa98e2SPeter Wemm if (tTd(32, 1)) 84212ed1c7cSGregory Neil Shapiro sm_dprintf("%s:", h->h_field); 843c2aa98e2SPeter Wemm if (h->h_value == NULL) 844c2aa98e2SPeter Wemm { 845c2aa98e2SPeter Wemm if (tTd(32, 1)) 84612ed1c7cSGregory Neil Shapiro sm_dprintf("<NULL>\n"); 847c2aa98e2SPeter Wemm continue; 848c2aa98e2SPeter Wemm } 849c2aa98e2SPeter Wemm 850c2aa98e2SPeter Wemm /* do early binding */ 8513299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) && 8523299c2f1SGregory Neil Shapiro !bitset(H_BINDLATE, h->h_flags)) 853c2aa98e2SPeter Wemm { 854c2aa98e2SPeter Wemm if (tTd(32, 1)) 855c2aa98e2SPeter Wemm { 85612ed1c7cSGregory Neil Shapiro sm_dprintf("("); 857bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), h->h_value); 85812ed1c7cSGregory Neil Shapiro sm_dprintf(") "); 859c2aa98e2SPeter Wemm } 860951742c4SGregory Neil Shapiro expand(h->h_value, buf, sizeof(buf), e); 861951742c4SGregory Neil Shapiro if (buf[0] != '\0' && 862951742c4SGregory Neil Shapiro (buf[0] != ' ' || buf[1] != '\0')) 863c2aa98e2SPeter Wemm { 864c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 865f9218d3dSGregory Neil Shapiro expand(crackaddr(buf, e), 866951742c4SGregory Neil Shapiro buf, sizeof(buf), e); 86712ed1c7cSGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, buf); 868c2aa98e2SPeter Wemm h->h_flags &= ~H_DEFAULT; 869c2aa98e2SPeter Wemm } 870c2aa98e2SPeter Wemm } 871c2aa98e2SPeter Wemm if (tTd(32, 1)) 872c2aa98e2SPeter Wemm { 873bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), h->h_value); 87412ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 875c2aa98e2SPeter Wemm } 876c2aa98e2SPeter Wemm 877c2aa98e2SPeter Wemm /* count the number of times it has been processed */ 878c2aa98e2SPeter Wemm if (bitset(H_TRACE, h->h_flags)) 879c2aa98e2SPeter Wemm hopcnt++; 880c2aa98e2SPeter Wemm 881c2aa98e2SPeter Wemm /* send to this person if we so desire */ 882c2aa98e2SPeter Wemm if (GrabTo && bitset(H_RCPT, h->h_flags) && 883c2aa98e2SPeter Wemm !bitset(H_DEFAULT, h->h_flags) && 88412ed1c7cSGregory Neil Shapiro (!bitset(EF_RESENT, e->e_flags) || 88512ed1c7cSGregory Neil Shapiro bitset(H_RESENT, h->h_flags))) 886c2aa98e2SPeter Wemm { 887c2aa98e2SPeter Wemm #if 0 888c2aa98e2SPeter Wemm int saveflags = e->e_flags; 8893299c2f1SGregory Neil Shapiro #endif /* 0 */ 890c2aa98e2SPeter Wemm 89112ed1c7cSGregory Neil Shapiro (void) sendtolist(denlstring(h->h_value, true, false), 89212ed1c7cSGregory Neil Shapiro NULLADDR, &e->e_sendqueue, 0, e); 893c2aa98e2SPeter Wemm 894c2aa98e2SPeter Wemm #if 0 895c2aa98e2SPeter Wemm /* 896c2aa98e2SPeter Wemm ** Change functionality so a fatal error on an 897c2aa98e2SPeter Wemm ** address doesn't affect the entire envelope. 898c2aa98e2SPeter Wemm */ 899c2aa98e2SPeter Wemm 900c2aa98e2SPeter Wemm /* delete fatal errors generated by this address */ 901c2aa98e2SPeter Wemm if (!bitset(EF_FATALERRS, saveflags)) 902c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 9033299c2f1SGregory Neil Shapiro #endif /* 0 */ 904c2aa98e2SPeter Wemm } 905c2aa98e2SPeter Wemm 906c2aa98e2SPeter Wemm /* save the message-id for logging */ 907c2aa98e2SPeter Wemm p = "resent-message-id"; 908c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 909c2aa98e2SPeter Wemm p += 7; 91012ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(h->h_field, p) == 0) 911c2aa98e2SPeter Wemm { 91212ed1c7cSGregory Neil Shapiro e->e_msgid = h->h_value; 91312ed1c7cSGregory Neil Shapiro while (isascii(*e->e_msgid) && isspace(*e->e_msgid)) 91412ed1c7cSGregory Neil Shapiro e->e_msgid++; 9151ae5b8d4SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{msg_id}"), 9161ae5b8d4SGregory Neil Shapiro e->e_msgid); 917c2aa98e2SPeter Wemm } 918c2aa98e2SPeter Wemm } 919c2aa98e2SPeter Wemm if (tTd(32, 1)) 92012ed1c7cSGregory Neil Shapiro sm_dprintf("----------------------------\n"); 921c2aa98e2SPeter Wemm 922c2aa98e2SPeter Wemm /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 923c2aa98e2SPeter Wemm if (OpMode == MD_VERIFY) 924c2aa98e2SPeter Wemm return; 925c2aa98e2SPeter Wemm 926c2aa98e2SPeter Wemm /* store hop count */ 927c2aa98e2SPeter Wemm if (hopcnt > e->e_hopcount) 92812ed1c7cSGregory Neil Shapiro { 929c2aa98e2SPeter Wemm e->e_hopcount = hopcnt; 930951742c4SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount); 93112ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 'c', buf); 93212ed1c7cSGregory Neil Shapiro } 933c2aa98e2SPeter Wemm 934c2aa98e2SPeter Wemm /* message priority */ 935c2aa98e2SPeter Wemm p = hvalue("precedence", e->e_header); 936c2aa98e2SPeter Wemm if (p != NULL) 937c2aa98e2SPeter Wemm e->e_class = priencode(p); 938c2aa98e2SPeter Wemm if (e->e_class < 0) 939c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 940c2aa98e2SPeter Wemm else if (e->e_class > 0) 941c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 942c2aa98e2SPeter Wemm if (full) 943c2aa98e2SPeter Wemm { 944c2aa98e2SPeter Wemm e->e_msgpriority = e->e_msgsize 945c2aa98e2SPeter Wemm - e->e_class * WkClassFact 946c2aa98e2SPeter Wemm + e->e_nrcpts * WkRecipFact; 947c2aa98e2SPeter Wemm } 948c2aa98e2SPeter Wemm 949bfb62e91SGregory Neil Shapiro /* check for DSN to properly set e_timeoutclass */ 950bfb62e91SGregory Neil Shapiro p = hvalue("content-type", e->e_header); 951bfb62e91SGregory Neil Shapiro if (p != NULL) 952bfb62e91SGregory Neil Shapiro { 953bfb62e91SGregory Neil Shapiro bool oldsupr; 954bfb62e91SGregory Neil Shapiro char **pvp; 955bfb62e91SGregory Neil Shapiro char pvpbuf[MAXLINE]; 956bfb62e91SGregory Neil Shapiro extern unsigned char MimeTokenTab[256]; 957bfb62e91SGregory Neil Shapiro 958bfb62e91SGregory Neil Shapiro /* tokenize header */ 959bfb62e91SGregory Neil Shapiro oldsupr = SuprErrs; 960bfb62e91SGregory Neil Shapiro SuprErrs = true; 961951742c4SGregory Neil Shapiro pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL, 962bfb62e91SGregory Neil Shapiro MimeTokenTab, false); 963bfb62e91SGregory Neil Shapiro SuprErrs = oldsupr; 964bfb62e91SGregory Neil Shapiro 965bfb62e91SGregory Neil Shapiro /* Check if multipart/report */ 966bfb62e91SGregory Neil Shapiro if (pvp != NULL && pvp[0] != NULL && 967bfb62e91SGregory Neil Shapiro pvp[1] != NULL && pvp[2] != NULL && 968bfb62e91SGregory Neil Shapiro sm_strcasecmp(*pvp++, "multipart") == 0 && 969bfb62e91SGregory Neil Shapiro strcmp(*pvp++, "/") == 0 && 970bfb62e91SGregory Neil Shapiro sm_strcasecmp(*pvp++, "report") == 0) 971bfb62e91SGregory Neil Shapiro { 972bfb62e91SGregory Neil Shapiro /* Look for report-type=delivery-status */ 973bfb62e91SGregory Neil Shapiro while (*pvp != NULL) 974bfb62e91SGregory Neil Shapiro { 975bfb62e91SGregory Neil Shapiro /* skip to semicolon separator */ 976bfb62e91SGregory Neil Shapiro while (*pvp != NULL && strcmp(*pvp, ";") != 0) 977bfb62e91SGregory Neil Shapiro pvp++; 978bfb62e91SGregory Neil Shapiro 979bfb62e91SGregory Neil Shapiro /* skip semicolon */ 980bfb62e91SGregory Neil Shapiro if (*pvp++ == NULL || *pvp == NULL) 981bfb62e91SGregory Neil Shapiro break; 982bfb62e91SGregory Neil Shapiro 983bfb62e91SGregory Neil Shapiro /* look for report-type */ 984bfb62e91SGregory Neil Shapiro if (sm_strcasecmp(*pvp++, "report-type") != 0) 985bfb62e91SGregory Neil Shapiro continue; 986bfb62e91SGregory Neil Shapiro 987bfb62e91SGregory Neil Shapiro /* skip equal */ 988bfb62e91SGregory Neil Shapiro if (*pvp == NULL || strcmp(*pvp, "=") != 0) 989bfb62e91SGregory Neil Shapiro continue; 990bfb62e91SGregory Neil Shapiro 991bfb62e91SGregory Neil Shapiro /* check value */ 992bfb62e91SGregory Neil Shapiro if (*++pvp != NULL && 993bfb62e91SGregory Neil Shapiro sm_strcasecmp(*pvp, 994bfb62e91SGregory Neil Shapiro "delivery-status") == 0) 995bfb62e91SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 996bfb62e91SGregory Neil Shapiro 997bfb62e91SGregory Neil Shapiro /* found report-type, no need to continue */ 998bfb62e91SGregory Neil Shapiro break; 999bfb62e91SGregory Neil Shapiro } 1000bfb62e91SGregory Neil Shapiro } 1001bfb62e91SGregory Neil Shapiro } 1002bfb62e91SGregory Neil Shapiro 1003c2aa98e2SPeter Wemm /* message timeout priority */ 1004c2aa98e2SPeter Wemm p = hvalue("priority", e->e_header); 1005c2aa98e2SPeter Wemm if (p != NULL) 1006c2aa98e2SPeter Wemm { 1007c2aa98e2SPeter Wemm /* (this should be in the configuration file) */ 100812ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(p, "urgent") == 0) 1009c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 101012ed1c7cSGregory Neil Shapiro else if (sm_strcasecmp(p, "normal") == 0) 1011c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NORMAL; 101212ed1c7cSGregory Neil Shapiro else if (sm_strcasecmp(p, "non-urgent") == 0) 1013c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 10141ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags)) 10151ae5b8d4SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 10161ae5b8d4SGregory Neil Shapiro } 10171ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags)) 101872936242SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 101972936242SGregory Neil Shapiro 1020c2aa98e2SPeter Wemm /* date message originated */ 1021c2aa98e2SPeter Wemm p = hvalue("posted-date", e->e_header); 1022c2aa98e2SPeter Wemm if (p == NULL) 1023c2aa98e2SPeter Wemm p = hvalue("date", e->e_header); 1024c2aa98e2SPeter Wemm if (p != NULL) 102512ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'a', p); 1026c2aa98e2SPeter Wemm 1027c2aa98e2SPeter Wemm /* check to see if this is a MIME message */ 1028c2aa98e2SPeter Wemm if ((e->e_bodytype != NULL && 102912ed1c7cSGregory Neil Shapiro sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 1030c2aa98e2SPeter Wemm hvalue("MIME-Version", e->e_header) != NULL) 1031c2aa98e2SPeter Wemm { 1032c2aa98e2SPeter Wemm e->e_flags |= EF_IS_MIME; 1033c2aa98e2SPeter Wemm if (HasEightBits) 1034c2aa98e2SPeter Wemm e->e_bodytype = "8BITMIME"; 1035c2aa98e2SPeter Wemm } 1036c2aa98e2SPeter Wemm else if ((p = hvalue("Content-Type", e->e_header)) != NULL) 1037c2aa98e2SPeter Wemm { 1038c2aa98e2SPeter Wemm /* this may be an RFC 1049 message */ 1039c2aa98e2SPeter Wemm p = strpbrk(p, ";/"); 1040c2aa98e2SPeter Wemm if (p == NULL || *p == ';') 1041c2aa98e2SPeter Wemm { 1042c2aa98e2SPeter Wemm /* yep, it is */ 1043c2aa98e2SPeter Wemm e->e_flags |= EF_DONT_MIME; 1044c2aa98e2SPeter Wemm } 1045c2aa98e2SPeter Wemm } 1046c2aa98e2SPeter Wemm 1047c2aa98e2SPeter Wemm /* 1048c2aa98e2SPeter Wemm ** From person in antiquated ARPANET mode 1049c2aa98e2SPeter Wemm ** required by UK Grey Book e-mail gateways (sigh) 1050c2aa98e2SPeter Wemm */ 1051c2aa98e2SPeter Wemm 1052c2aa98e2SPeter Wemm if (OpMode == MD_ARPAFTP) 1053c2aa98e2SPeter Wemm { 1054c2aa98e2SPeter Wemm register struct hdrinfo *hi; 1055c2aa98e2SPeter Wemm 1056c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 1057c2aa98e2SPeter Wemm { 1058c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && 1059c2aa98e2SPeter Wemm (!bitset(H_RESENT, hi->hi_flags) || 1060c2aa98e2SPeter Wemm bitset(EF_RESENT, e->e_flags)) && 1061c2aa98e2SPeter Wemm (p = hvalue(hi->hi_field, e->e_header)) != NULL) 1062c2aa98e2SPeter Wemm break; 1063c2aa98e2SPeter Wemm } 1064c2aa98e2SPeter Wemm if (hi->hi_field != NULL) 1065c2aa98e2SPeter Wemm { 1066c2aa98e2SPeter Wemm if (tTd(32, 2)) 106712ed1c7cSGregory Neil Shapiro sm_dprintf("eatheader: setsender(*%s == %s)\n", 1068c2aa98e2SPeter Wemm hi->hi_field, p); 106912ed1c7cSGregory Neil Shapiro setsender(p, e, NULL, '\0', true); 1070c2aa98e2SPeter Wemm } 1071c2aa98e2SPeter Wemm } 1072c2aa98e2SPeter Wemm 1073c2aa98e2SPeter Wemm /* 1074c2aa98e2SPeter Wemm ** Log collection information. 1075c2aa98e2SPeter Wemm */ 1076c2aa98e2SPeter Wemm 10779bd497b8SGregory Neil Shapiro if (tTd(92, 2)) 10789bd497b8SGregory Neil Shapiro sm_dprintf("eatheader: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d, log=%d\n", 10799bd497b8SGregory Neil Shapiro e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel, 10809bd497b8SGregory Neil Shapiro log); 108112ed1c7cSGregory Neil Shapiro if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 108212ed1c7cSGregory Neil Shapiro { 108312ed1c7cSGregory Neil Shapiro logsender(e, e->e_msgid); 1084c2aa98e2SPeter Wemm e->e_flags &= ~EF_LOGSENDER; 1085c2aa98e2SPeter Wemm } 108612ed1c7cSGregory Neil Shapiro } 1087951742c4SGregory Neil Shapiro 108812ed1c7cSGregory Neil Shapiro /* 1089c2aa98e2SPeter Wemm ** LOGSENDER -- log sender information 1090c2aa98e2SPeter Wemm ** 1091c2aa98e2SPeter Wemm ** Parameters: 1092c2aa98e2SPeter Wemm ** e -- the envelope to log 1093c2aa98e2SPeter Wemm ** msgid -- the message id 1094c2aa98e2SPeter Wemm ** 1095c2aa98e2SPeter Wemm ** Returns: 1096c2aa98e2SPeter Wemm ** none 1097c2aa98e2SPeter Wemm */ 1098c2aa98e2SPeter Wemm 1099c2aa98e2SPeter Wemm void 1100c2aa98e2SPeter Wemm logsender(e, msgid) 1101c2aa98e2SPeter Wemm register ENVELOPE *e; 1102c2aa98e2SPeter Wemm char *msgid; 1103c2aa98e2SPeter Wemm { 1104c2aa98e2SPeter Wemm char *name; 1105c2aa98e2SPeter Wemm register char *sbp; 1106c2aa98e2SPeter Wemm register char *p; 1107c2aa98e2SPeter Wemm char hbuf[MAXNAME + 1]; 1108c2aa98e2SPeter Wemm char sbuf[MAXLINE + 1]; 1109c2aa98e2SPeter Wemm char mbuf[MAXNAME + 1]; 1110c2aa98e2SPeter Wemm 1111c2aa98e2SPeter Wemm /* don't allow newlines in the message-id */ 111212ed1c7cSGregory Neil Shapiro /* XXX do we still need this? sm_syslog() replaces control chars */ 1113c2aa98e2SPeter Wemm if (msgid != NULL) 1114c2aa98e2SPeter Wemm { 1115567a2fc9SGregory Neil Shapiro size_t l; 1116567a2fc9SGregory Neil Shapiro 1117c2aa98e2SPeter Wemm l = strlen(msgid); 1118951742c4SGregory Neil Shapiro if (l > sizeof(mbuf) - 1) 1119951742c4SGregory Neil Shapiro l = sizeof(mbuf) - 1; 11203299c2f1SGregory Neil Shapiro memmove(mbuf, msgid, l); 1121c2aa98e2SPeter Wemm mbuf[l] = '\0'; 1122c2aa98e2SPeter Wemm p = mbuf; 1123c2aa98e2SPeter Wemm while ((p = strchr(p, '\n')) != NULL) 1124c2aa98e2SPeter Wemm *p++ = ' '; 1125c2aa98e2SPeter Wemm } 1126c2aa98e2SPeter Wemm 1127c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags)) 1128c2aa98e2SPeter Wemm name = "[RESPONSE]"; 1129c2aa98e2SPeter Wemm else if ((name = macvalue('_', e)) != NULL) 11303299c2f1SGregory Neil Shapiro /* EMPTY */ 1131c2aa98e2SPeter Wemm ; 1132c2aa98e2SPeter Wemm else if (RealHostName == NULL) 1133c2aa98e2SPeter Wemm name = "localhost"; 1134c2aa98e2SPeter Wemm else if (RealHostName[0] == '[') 1135c2aa98e2SPeter Wemm name = RealHostName; 1136c2aa98e2SPeter Wemm else 1137c2aa98e2SPeter Wemm { 1138c2aa98e2SPeter Wemm name = hbuf; 1139951742c4SGregory Neil Shapiro (void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName); 1140c2aa98e2SPeter Wemm if (RealHostAddr.sa.sa_family != 0) 1141c2aa98e2SPeter Wemm { 1142c2aa98e2SPeter Wemm p = &hbuf[strlen(hbuf)]; 114312ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 114412ed1c7cSGregory Neil Shapiro " (%.100s)", 1145c2aa98e2SPeter Wemm anynet_ntoa(&RealHostAddr)); 1146c2aa98e2SPeter Wemm } 1147c2aa98e2SPeter Wemm } 1148c2aa98e2SPeter Wemm 1149c2aa98e2SPeter Wemm /* some versions of syslog only take 5 printf args */ 1150c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256 1151c2aa98e2SPeter Wemm sbp = sbuf; 115212ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 11533299c2f1SGregory Neil Shapiro "from=%.200s, size=%ld, class=%d, nrcpts=%d", 1154c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 1155*ba00ec3dSGregory Neil Shapiro PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 1156c2aa98e2SPeter Wemm sbp += strlen(sbp); 1157c2aa98e2SPeter Wemm if (msgid != NULL) 1158c2aa98e2SPeter Wemm { 115912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 116012ed1c7cSGregory Neil Shapiro ", msgid=%.100s", mbuf); 1161c2aa98e2SPeter Wemm sbp += strlen(sbp); 1162c2aa98e2SPeter Wemm } 1163c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 1164c2aa98e2SPeter Wemm { 116512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 116612ed1c7cSGregory Neil Shapiro ", bodytype=%.20s", e->e_bodytype); 1167c2aa98e2SPeter Wemm sbp += strlen(sbp); 1168c2aa98e2SPeter Wemm } 1169c2aa98e2SPeter Wemm p = macvalue('r', e); 1170c2aa98e2SPeter Wemm if (p != NULL) 11713299c2f1SGregory Neil Shapiro { 117212ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 117312ed1c7cSGregory Neil Shapiro ", proto=%.20s", p); 11743299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 11753299c2f1SGregory Neil Shapiro } 117612ed1c7cSGregory Neil Shapiro p = macvalue(macid("{daemon_name}"), e); 11773299c2f1SGregory Neil Shapiro if (p != NULL) 11783299c2f1SGregory Neil Shapiro { 117912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 118012ed1c7cSGregory Neil Shapiro ", daemon=%.20s", p); 11813299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 11823299c2f1SGregory Neil Shapiro } 11832ef40764SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name); 1184c2aa98e2SPeter Wemm 11853299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */ 1186c2aa98e2SPeter Wemm 1187c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 1188c2aa98e2SPeter Wemm "from=%s", 1189c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>" 119012ed1c7cSGregory Neil Shapiro : shortenstring(e->e_from.q_paddr, 119112ed1c7cSGregory Neil Shapiro 83)); 1192c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 11933299c2f1SGregory Neil Shapiro "size=%ld, class=%ld, nrcpts=%d", 1194*ba00ec3dSGregory Neil Shapiro PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 1195c2aa98e2SPeter Wemm if (msgid != NULL) 1196c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 1197c2aa98e2SPeter Wemm "msgid=%s", 1198c2aa98e2SPeter Wemm shortenstring(mbuf, 83)); 1199c2aa98e2SPeter Wemm sbp = sbuf; 1200c2aa98e2SPeter Wemm *sbp = '\0'; 1201c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 1202c2aa98e2SPeter Wemm { 120312ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 120412ed1c7cSGregory Neil Shapiro "bodytype=%.20s, ", e->e_bodytype); 1205c2aa98e2SPeter Wemm sbp += strlen(sbp); 1206c2aa98e2SPeter Wemm } 1207c2aa98e2SPeter Wemm p = macvalue('r', e); 1208c2aa98e2SPeter Wemm if (p != NULL) 1209c2aa98e2SPeter Wemm { 121012ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 121112ed1c7cSGregory Neil Shapiro "proto=%.20s, ", p); 1212c2aa98e2SPeter Wemm sbp += strlen(sbp); 1213c2aa98e2SPeter Wemm } 1214c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 12152ef40764SGregory Neil Shapiro "%.400srelay=%s", sbuf, name); 12163299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 1217c2aa98e2SPeter Wemm } 1218951742c4SGregory Neil Shapiro 121912ed1c7cSGregory Neil Shapiro /* 1220c2aa98e2SPeter Wemm ** PRIENCODE -- encode external priority names into internal values. 1221c2aa98e2SPeter Wemm ** 1222c2aa98e2SPeter Wemm ** Parameters: 1223c2aa98e2SPeter Wemm ** p -- priority in ascii. 1224c2aa98e2SPeter Wemm ** 1225c2aa98e2SPeter Wemm ** Returns: 1226c2aa98e2SPeter Wemm ** priority as a numeric level. 1227c2aa98e2SPeter Wemm ** 1228c2aa98e2SPeter Wemm ** Side Effects: 1229c2aa98e2SPeter Wemm ** none. 1230c2aa98e2SPeter Wemm */ 1231c2aa98e2SPeter Wemm 12323299c2f1SGregory Neil Shapiro static int 1233c2aa98e2SPeter Wemm priencode(p) 1234c2aa98e2SPeter Wemm char *p; 1235c2aa98e2SPeter Wemm { 1236c2aa98e2SPeter Wemm register int i; 1237c2aa98e2SPeter Wemm 1238c2aa98e2SPeter Wemm for (i = 0; i < NumPriorities; i++) 1239c2aa98e2SPeter Wemm { 124012ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(p, Priorities[i].pri_name) == 0) 12413299c2f1SGregory Neil Shapiro return Priorities[i].pri_val; 1242c2aa98e2SPeter Wemm } 1243c2aa98e2SPeter Wemm 1244c2aa98e2SPeter Wemm /* unknown priority */ 12453299c2f1SGregory Neil Shapiro return 0; 1246c2aa98e2SPeter Wemm } 1247951742c4SGregory Neil Shapiro 124812ed1c7cSGregory Neil Shapiro /* 1249c2aa98e2SPeter Wemm ** CRACKADDR -- parse an address and turn it into a macro 1250c2aa98e2SPeter Wemm ** 1251c2aa98e2SPeter Wemm ** This doesn't actually parse the address -- it just extracts 1252c2aa98e2SPeter Wemm ** it and replaces it with "$g". The parse is totally ad hoc 1253c2aa98e2SPeter Wemm ** and isn't even guaranteed to leave something syntactically 1254c2aa98e2SPeter Wemm ** identical to what it started with. However, it does leave 1255f9218d3dSGregory Neil Shapiro ** something semantically identical if possible, else at least 1256f9218d3dSGregory Neil Shapiro ** syntactically correct. 1257f9218d3dSGregory Neil Shapiro ** 1258f9218d3dSGregory Neil Shapiro ** For example, it changes "Real Name <real@example.com> (Comment)" 1259f9218d3dSGregory Neil Shapiro ** to "Real Name <$g> (Comment)". 1260c2aa98e2SPeter Wemm ** 1261c2aa98e2SPeter Wemm ** This algorithm has been cleaned up to handle a wider range 1262c2aa98e2SPeter Wemm ** of cases -- notably quoted and backslash escaped strings. 1263c2aa98e2SPeter Wemm ** This modification makes it substantially better at preserving 1264c2aa98e2SPeter Wemm ** the original syntax. 1265c2aa98e2SPeter Wemm ** 1266c2aa98e2SPeter Wemm ** Parameters: 1267c2aa98e2SPeter Wemm ** addr -- the address to be cracked. 1268f9218d3dSGregory Neil Shapiro ** e -- the current envelope. 1269c2aa98e2SPeter Wemm ** 1270c2aa98e2SPeter Wemm ** Returns: 1271c2aa98e2SPeter Wemm ** a pointer to the new version. 1272c2aa98e2SPeter Wemm ** 1273c2aa98e2SPeter Wemm ** Side Effects: 1274c2aa98e2SPeter Wemm ** none. 1275c2aa98e2SPeter Wemm ** 1276c2aa98e2SPeter Wemm ** Warning: 1277c2aa98e2SPeter Wemm ** The return value is saved in local storage and should 1278c2aa98e2SPeter Wemm ** be copied if it is to be reused. 1279c2aa98e2SPeter Wemm */ 1280c2aa98e2SPeter Wemm 1281f9218d3dSGregory Neil Shapiro #define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend)) 1282f9218d3dSGregory Neil Shapiro 1283f9218d3dSGregory Neil Shapiro /* 1284f9218d3dSGregory Neil Shapiro ** Append a character to bp if we have room. 1285f9218d3dSGregory Neil Shapiro ** If not, punt and return $g. 1286f9218d3dSGregory Neil Shapiro */ 1287f9218d3dSGregory Neil Shapiro 1288f9218d3dSGregory Neil Shapiro #define SM_APPEND_CHAR(c) \ 1289f9218d3dSGregory Neil Shapiro do \ 1290f9218d3dSGregory Neil Shapiro { \ 1291f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) \ 1292f9218d3dSGregory Neil Shapiro *bp++ = (c); \ 1293f9218d3dSGregory Neil Shapiro else \ 1294f9218d3dSGregory Neil Shapiro goto returng; \ 1295f9218d3dSGregory Neil Shapiro } while (0) 1296f9218d3dSGregory Neil Shapiro 1297f9218d3dSGregory Neil Shapiro #if MAXNAME < 10 1298f9218d3dSGregory Neil Shapiro ERROR MAXNAME must be at least 10 1299f9218d3dSGregory Neil Shapiro #endif /* MAXNAME < 10 */ 1300f9218d3dSGregory Neil Shapiro 1301c2aa98e2SPeter Wemm char * 1302f9218d3dSGregory Neil Shapiro crackaddr(addr, e) 1303c2aa98e2SPeter Wemm register char *addr; 1304f9218d3dSGregory Neil Shapiro ENVELOPE *e; 1305c2aa98e2SPeter Wemm { 1306c2aa98e2SPeter Wemm register char *p; 1307c2aa98e2SPeter Wemm register char c; 1308f9218d3dSGregory Neil Shapiro int cmtlev; /* comment level in input string */ 1309f9218d3dSGregory Neil Shapiro int realcmtlev; /* comment level in output string */ 1310f9218d3dSGregory Neil Shapiro int anglelev; /* angle level in input string */ 1311f9218d3dSGregory Neil Shapiro int copylev; /* 0 == in address, >0 copying */ 1312f9218d3dSGregory Neil Shapiro int bracklev; /* bracket level for IPv6 addr check */ 1313f9218d3dSGregory Neil Shapiro bool addangle; /* put closing angle in output */ 1314f9218d3dSGregory Neil Shapiro bool qmode; /* quoting in original string? */ 1315f9218d3dSGregory Neil Shapiro bool realqmode; /* quoting in output string? */ 1316f9218d3dSGregory Neil Shapiro bool putgmac = false; /* already wrote $g */ 1317f9218d3dSGregory Neil Shapiro bool quoteit = false; /* need to quote next character */ 1318f9218d3dSGregory Neil Shapiro bool gotangle = false; /* found first '<' */ 1319f9218d3dSGregory Neil Shapiro bool gotcolon = false; /* found a ':' */ 1320c2aa98e2SPeter Wemm register char *bp; 1321c2aa98e2SPeter Wemm char *buflim; 1322c2aa98e2SPeter Wemm char *bufhead; 1323c2aa98e2SPeter Wemm char *addrhead; 1324f9218d3dSGregory Neil Shapiro char *bufend; 1325c2aa98e2SPeter Wemm static char buf[MAXNAME + 1]; 1326c2aa98e2SPeter Wemm 1327c2aa98e2SPeter Wemm if (tTd(33, 1)) 132812ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr(%s)\n", addr); 1329c2aa98e2SPeter Wemm 1330951742c4SGregory Neil Shapiro buflim = bufend = &buf[sizeof(buf) - 1]; 1331951742c4SGregory Neil Shapiro bp = bufhead = buf; 1332951742c4SGregory Neil Shapiro 1333951742c4SGregory Neil Shapiro /* skip over leading spaces but preserve them */ 1334c2aa98e2SPeter Wemm while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 1335951742c4SGregory Neil Shapiro { 1336951742c4SGregory Neil Shapiro SM_APPEND_CHAR(*addr); 1337c2aa98e2SPeter Wemm addr++; 1338951742c4SGregory Neil Shapiro } 1339951742c4SGregory Neil Shapiro bufhead = bp; 1340c2aa98e2SPeter Wemm 1341c2aa98e2SPeter Wemm /* 1342c2aa98e2SPeter Wemm ** Start by assuming we have no angle brackets. This will be 1343c2aa98e2SPeter Wemm ** adjusted later if we find them. 1344c2aa98e2SPeter Wemm */ 1345c2aa98e2SPeter Wemm 1346c2aa98e2SPeter Wemm p = addrhead = addr; 1347f9218d3dSGregory Neil Shapiro copylev = anglelev = cmtlev = realcmtlev = 0; 1348c2aa98e2SPeter Wemm bracklev = 0; 1349f9218d3dSGregory Neil Shapiro qmode = realqmode = addangle = false; 1350c2aa98e2SPeter Wemm 1351c2aa98e2SPeter Wemm while ((c = *p++) != '\0') 1352c2aa98e2SPeter Wemm { 1353c2aa98e2SPeter Wemm /* 1354f9218d3dSGregory Neil Shapiro ** Try to keep legal syntax using spare buffer space 1355f9218d3dSGregory Neil Shapiro ** (maintained by buflim). 1356c2aa98e2SPeter Wemm */ 1357c2aa98e2SPeter Wemm 1358f9218d3dSGregory Neil Shapiro if (copylev > 0) 1359f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1360c2aa98e2SPeter Wemm 1361c2aa98e2SPeter Wemm /* check for backslash escapes */ 1362c2aa98e2SPeter Wemm if (c == '\\') 1363c2aa98e2SPeter Wemm { 1364c2aa98e2SPeter Wemm /* arrange to quote the address */ 1365c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 136612ed1c7cSGregory Neil Shapiro quoteit = true; 1367c2aa98e2SPeter Wemm 1368c2aa98e2SPeter Wemm if ((c = *p++) == '\0') 1369c2aa98e2SPeter Wemm { 1370c2aa98e2SPeter Wemm /* too far */ 1371c2aa98e2SPeter Wemm p--; 1372c2aa98e2SPeter Wemm goto putg; 1373c2aa98e2SPeter Wemm } 1374f9218d3dSGregory Neil Shapiro if (copylev > 0) 1375f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1376c2aa98e2SPeter Wemm goto putg; 1377c2aa98e2SPeter Wemm } 1378c2aa98e2SPeter Wemm 1379c2aa98e2SPeter Wemm /* check for quoted strings */ 1380c2aa98e2SPeter Wemm if (c == '"' && cmtlev <= 0) 1381c2aa98e2SPeter Wemm { 1382c2aa98e2SPeter Wemm qmode = !qmode; 1383f9218d3dSGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM) 1384f9218d3dSGregory Neil Shapiro { 1385f9218d3dSGregory Neil Shapiro if (realqmode) 1386f9218d3dSGregory Neil Shapiro buflim--; 1387f9218d3dSGregory Neil Shapiro else 1388f9218d3dSGregory Neil Shapiro buflim++; 1389c2aa98e2SPeter Wemm realqmode = !realqmode; 1390f9218d3dSGregory Neil Shapiro } 1391c2aa98e2SPeter Wemm continue; 1392c2aa98e2SPeter Wemm } 1393c2aa98e2SPeter Wemm if (qmode) 1394c2aa98e2SPeter Wemm goto putg; 1395c2aa98e2SPeter Wemm 1396c2aa98e2SPeter Wemm /* check for comments */ 1397c2aa98e2SPeter Wemm if (c == '(') 1398c2aa98e2SPeter Wemm { 1399c2aa98e2SPeter Wemm cmtlev++; 1400c2aa98e2SPeter Wemm 1401c2aa98e2SPeter Wemm /* allow space for closing paren */ 1402f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1403c2aa98e2SPeter Wemm { 1404c2aa98e2SPeter Wemm buflim--; 1405c2aa98e2SPeter Wemm realcmtlev++; 1406c2aa98e2SPeter Wemm if (copylev++ <= 0) 1407c2aa98e2SPeter Wemm { 1408c2aa98e2SPeter Wemm if (bp != bufhead) 1409f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' '); 1410f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1411c2aa98e2SPeter Wemm } 1412c2aa98e2SPeter Wemm } 1413c2aa98e2SPeter Wemm } 1414c2aa98e2SPeter Wemm if (cmtlev > 0) 1415c2aa98e2SPeter Wemm { 1416c2aa98e2SPeter Wemm if (c == ')') 1417c2aa98e2SPeter Wemm { 1418c2aa98e2SPeter Wemm cmtlev--; 1419c2aa98e2SPeter Wemm copylev--; 1420f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1421c2aa98e2SPeter Wemm { 1422c2aa98e2SPeter Wemm realcmtlev--; 1423c2aa98e2SPeter Wemm buflim++; 1424c2aa98e2SPeter Wemm } 1425c2aa98e2SPeter Wemm } 1426c2aa98e2SPeter Wemm continue; 1427c2aa98e2SPeter Wemm } 1428c2aa98e2SPeter Wemm else if (c == ')') 1429c2aa98e2SPeter Wemm { 1430c2aa98e2SPeter Wemm /* syntax error: unmatched ) */ 14317660b554SGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead) 1432c2aa98e2SPeter Wemm bp--; 1433c2aa98e2SPeter Wemm } 1434c2aa98e2SPeter Wemm 1435c2aa98e2SPeter Wemm /* count nesting on [ ... ] (for IPv6 domain literals) */ 1436c2aa98e2SPeter Wemm if (c == '[') 1437c2aa98e2SPeter Wemm bracklev++; 1438c2aa98e2SPeter Wemm else if (c == ']') 1439c2aa98e2SPeter Wemm bracklev--; 1440c2aa98e2SPeter Wemm 1441c2aa98e2SPeter Wemm /* check for group: list; syntax */ 1442c2aa98e2SPeter Wemm if (c == ':' && anglelev <= 0 && bracklev <= 0 && 1443c2aa98e2SPeter Wemm !gotcolon && !ColonOkInAddr) 1444c2aa98e2SPeter Wemm { 1445c2aa98e2SPeter Wemm register char *q; 1446c2aa98e2SPeter Wemm 1447c2aa98e2SPeter Wemm /* 1448c2aa98e2SPeter Wemm ** Check for DECnet phase IV ``::'' (host::user) 1449f9218d3dSGregory Neil Shapiro ** or DECnet phase V ``:.'' syntaxes. The latter 1450c2aa98e2SPeter Wemm ** covers ``user@DEC:.tay.myhost'' and 1451c2aa98e2SPeter Wemm ** ``DEC:.tay.myhost::user'' syntaxes (bletch). 1452c2aa98e2SPeter Wemm */ 1453c2aa98e2SPeter Wemm 1454c2aa98e2SPeter Wemm if (*p == ':' || *p == '.') 1455c2aa98e2SPeter Wemm { 1456c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 145712ed1c7cSGregory Neil Shapiro quoteit = true; 1458f9218d3dSGregory Neil Shapiro if (copylev > 0) 1459c2aa98e2SPeter Wemm { 1460f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1461f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p); 1462c2aa98e2SPeter Wemm } 1463c2aa98e2SPeter Wemm p++; 1464c2aa98e2SPeter Wemm goto putg; 1465c2aa98e2SPeter Wemm } 1466c2aa98e2SPeter Wemm 146712ed1c7cSGregory Neil Shapiro gotcolon = true; 1468c2aa98e2SPeter Wemm 1469c2aa98e2SPeter Wemm bp = bufhead; 1470c2aa98e2SPeter Wemm if (quoteit) 1471c2aa98e2SPeter Wemm { 1472f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1473c2aa98e2SPeter Wemm 1474c2aa98e2SPeter Wemm /* back up over the ':' and any spaces */ 1475c2aa98e2SPeter Wemm --p; 1476f9218d3dSGregory Neil Shapiro while (p > addr && 1477f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p)) 1478c2aa98e2SPeter Wemm continue; 1479c2aa98e2SPeter Wemm p++; 1480c2aa98e2SPeter Wemm } 1481c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1482c2aa98e2SPeter Wemm { 1483c2aa98e2SPeter Wemm c = *q++; 1484c2aa98e2SPeter Wemm if (quoteit && c == '"') 1485f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\'); 1486f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1487c2aa98e2SPeter Wemm } 1488c2aa98e2SPeter Wemm if (quoteit) 1489c2aa98e2SPeter Wemm { 1490c2aa98e2SPeter Wemm if (bp == &bufhead[1]) 1491c2aa98e2SPeter Wemm bp--; 1492c2aa98e2SPeter Wemm else 1493f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1494c2aa98e2SPeter Wemm while ((c = *p++) != ':') 1495f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1496f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1497c2aa98e2SPeter Wemm } 1498c2aa98e2SPeter Wemm 1499c2aa98e2SPeter Wemm /* any trailing white space is part of group: */ 1500f9218d3dSGregory Neil Shapiro while (isascii(*p) && isspace(*p)) 1501f9218d3dSGregory Neil Shapiro { 1502f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p); 1503f9218d3dSGregory Neil Shapiro p++; 1504f9218d3dSGregory Neil Shapiro } 1505c2aa98e2SPeter Wemm copylev = 0; 150612ed1c7cSGregory Neil Shapiro putgmac = quoteit = false; 1507c2aa98e2SPeter Wemm bufhead = bp; 1508c2aa98e2SPeter Wemm addrhead = p; 1509c2aa98e2SPeter Wemm continue; 1510c2aa98e2SPeter Wemm } 1511c2aa98e2SPeter Wemm 1512c2aa98e2SPeter Wemm if (c == ';' && copylev <= 0 && !ColonOkInAddr) 1513f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1514c2aa98e2SPeter Wemm 1515c2aa98e2SPeter Wemm /* check for characters that may have to be quoted */ 1516c2aa98e2SPeter Wemm if (strchr(MustQuoteChars, c) != NULL) 1517c2aa98e2SPeter Wemm { 1518c2aa98e2SPeter Wemm /* 1519c2aa98e2SPeter Wemm ** If these occur as the phrase part of a <> 1520c2aa98e2SPeter Wemm ** construct, but are not inside of () or already 1521c2aa98e2SPeter Wemm ** quoted, they will have to be quoted. Note that 1522c2aa98e2SPeter Wemm ** now (but don't actually do the quoting). 1523c2aa98e2SPeter Wemm */ 1524c2aa98e2SPeter Wemm 1525c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 152612ed1c7cSGregory Neil Shapiro quoteit = true; 1527c2aa98e2SPeter Wemm } 1528c2aa98e2SPeter Wemm 1529c2aa98e2SPeter Wemm /* check for angle brackets */ 1530c2aa98e2SPeter Wemm if (c == '<') 1531c2aa98e2SPeter Wemm { 1532c2aa98e2SPeter Wemm register char *q; 1533c2aa98e2SPeter Wemm 1534c2aa98e2SPeter Wemm /* assume first of two angles is bogus */ 1535c2aa98e2SPeter Wemm if (gotangle) 153612ed1c7cSGregory Neil Shapiro quoteit = true; 153712ed1c7cSGregory Neil Shapiro gotangle = true; 1538c2aa98e2SPeter Wemm 1539c2aa98e2SPeter Wemm /* oops -- have to change our mind */ 1540c2aa98e2SPeter Wemm anglelev = 1; 1541f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1542f9218d3dSGregory Neil Shapiro { 1543f9218d3dSGregory Neil Shapiro if (!addangle) 1544f9218d3dSGregory Neil Shapiro buflim--; 1545f9218d3dSGregory Neil Shapiro addangle = true; 1546f9218d3dSGregory Neil Shapiro } 1547c2aa98e2SPeter Wemm 1548c2aa98e2SPeter Wemm bp = bufhead; 1549c2aa98e2SPeter Wemm if (quoteit) 1550c2aa98e2SPeter Wemm { 1551f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1552c2aa98e2SPeter Wemm 1553c2aa98e2SPeter Wemm /* back up over the '<' and any spaces */ 1554c2aa98e2SPeter Wemm --p; 1555f9218d3dSGregory Neil Shapiro while (p > addr && 1556f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p)) 1557c2aa98e2SPeter Wemm continue; 1558c2aa98e2SPeter Wemm p++; 1559c2aa98e2SPeter Wemm } 1560c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1561c2aa98e2SPeter Wemm { 1562c2aa98e2SPeter Wemm c = *q++; 1563c2aa98e2SPeter Wemm if (quoteit && c == '"') 1564f9218d3dSGregory Neil Shapiro { 1565f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\'); 1566f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1567c2aa98e2SPeter Wemm } 1568f9218d3dSGregory Neil Shapiro else 1569f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1570c2aa98e2SPeter Wemm } 1571c2aa98e2SPeter Wemm if (quoteit) 1572c2aa98e2SPeter Wemm { 1573c2aa98e2SPeter Wemm if (bp == &buf[1]) 1574c2aa98e2SPeter Wemm bp--; 1575c2aa98e2SPeter Wemm else 1576f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1577c2aa98e2SPeter Wemm while ((c = *p++) != '<') 1578f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1579f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1580c2aa98e2SPeter Wemm } 1581c2aa98e2SPeter Wemm copylev = 0; 158212ed1c7cSGregory Neil Shapiro putgmac = quoteit = false; 1583c2aa98e2SPeter Wemm continue; 1584c2aa98e2SPeter Wemm } 1585c2aa98e2SPeter Wemm 1586c2aa98e2SPeter Wemm if (c == '>') 1587c2aa98e2SPeter Wemm { 1588c2aa98e2SPeter Wemm if (anglelev > 0) 1589c2aa98e2SPeter Wemm { 1590c2aa98e2SPeter Wemm anglelev--; 1591f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1592c2aa98e2SPeter Wemm { 1593f9218d3dSGregory Neil Shapiro if (addangle) 1594c2aa98e2SPeter Wemm buflim++; 1595f9218d3dSGregory Neil Shapiro addangle = false; 1596c2aa98e2SPeter Wemm } 1597c2aa98e2SPeter Wemm } 1598f9218d3dSGregory Neil Shapiro else if (SM_HAVE_ROOM) 1599c2aa98e2SPeter Wemm { 1600c2aa98e2SPeter Wemm /* syntax error: unmatched > */ 16017660b554SGregory Neil Shapiro if (copylev > 0 && bp > bufhead) 1602c2aa98e2SPeter Wemm bp--; 160312ed1c7cSGregory Neil Shapiro quoteit = true; 1604c2aa98e2SPeter Wemm continue; 1605c2aa98e2SPeter Wemm } 1606c2aa98e2SPeter Wemm if (copylev++ <= 0) 1607f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1608c2aa98e2SPeter Wemm continue; 1609c2aa98e2SPeter Wemm } 1610c2aa98e2SPeter Wemm 1611c2aa98e2SPeter Wemm /* must be a real address character */ 1612c2aa98e2SPeter Wemm putg: 1613c2aa98e2SPeter Wemm if (copylev <= 0 && !putgmac) 1614c2aa98e2SPeter Wemm { 1615f9218d3dSGregory Neil Shapiro if (bp > buf && bp[-1] == ')') 1616f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' '); 1617f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(MACROEXPAND); 1618f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('g'); 161912ed1c7cSGregory Neil Shapiro putgmac = true; 1620c2aa98e2SPeter Wemm } 1621c2aa98e2SPeter Wemm } 1622c2aa98e2SPeter Wemm 1623c2aa98e2SPeter Wemm /* repair any syntactic damage */ 1624f9218d3dSGregory Neil Shapiro if (realqmode && bp < bufend) 1625c2aa98e2SPeter Wemm *bp++ = '"'; 1626f9218d3dSGregory Neil Shapiro while (realcmtlev-- > 0 && bp < bufend) 1627c2aa98e2SPeter Wemm *bp++ = ')'; 1628f9218d3dSGregory Neil Shapiro if (addangle && bp < bufend) 1629c2aa98e2SPeter Wemm *bp++ = '>'; 1630f9218d3dSGregory Neil Shapiro *bp = '\0'; 1631f9218d3dSGregory Neil Shapiro if (bp < bufend) 1632f9218d3dSGregory Neil Shapiro goto success; 1633c2aa98e2SPeter Wemm 1634f9218d3dSGregory Neil Shapiro returng: 1635f9218d3dSGregory Neil Shapiro /* String too long, punt */ 1636f9218d3dSGregory Neil Shapiro buf[0] = '<'; 1637f9218d3dSGregory Neil Shapiro buf[1] = MACROEXPAND; 1638f9218d3dSGregory Neil Shapiro buf[2]= 'g'; 1639f9218d3dSGregory Neil Shapiro buf[3] = '>'; 1640f9218d3dSGregory Neil Shapiro buf[4]= '\0'; 1641f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 1642f9218d3dSGregory Neil Shapiro "Dropped invalid comments from header address"); 1643f9218d3dSGregory Neil Shapiro 1644f9218d3dSGregory Neil Shapiro success: 1645c2aa98e2SPeter Wemm if (tTd(33, 1)) 1646c2aa98e2SPeter Wemm { 164712ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr=>`"); 1648bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), buf); 164912ed1c7cSGregory Neil Shapiro sm_dprintf("'\n"); 1650c2aa98e2SPeter Wemm } 16513299c2f1SGregory Neil Shapiro return buf; 1652c2aa98e2SPeter Wemm } 1653951742c4SGregory Neil Shapiro 165412ed1c7cSGregory Neil Shapiro /* 1655c2aa98e2SPeter Wemm ** PUTHEADER -- put the header part of a message from the in-core copy 1656c2aa98e2SPeter Wemm ** 1657c2aa98e2SPeter Wemm ** Parameters: 1658c2aa98e2SPeter Wemm ** mci -- the connection information. 16593299c2f1SGregory Neil Shapiro ** hdr -- the header to put. 1660c2aa98e2SPeter Wemm ** e -- envelope to use. 1661e01d6f61SPeter Wemm ** flags -- MIME conversion flags. 1662c2aa98e2SPeter Wemm ** 1663c2aa98e2SPeter Wemm ** Returns: 1664355d91e3SGregory Neil Shapiro ** true iff header part was written successfully 1665c2aa98e2SPeter Wemm ** 1666c2aa98e2SPeter Wemm ** Side Effects: 1667c2aa98e2SPeter Wemm ** none. 1668c2aa98e2SPeter Wemm */ 1669c2aa98e2SPeter Wemm 1670567a2fc9SGregory Neil Shapiro bool 1671e01d6f61SPeter Wemm putheader(mci, hdr, e, flags) 1672c2aa98e2SPeter Wemm register MCI *mci; 1673c2aa98e2SPeter Wemm HDR *hdr; 1674c2aa98e2SPeter Wemm register ENVELOPE *e; 1675e01d6f61SPeter Wemm int flags; 1676c2aa98e2SPeter Wemm { 1677c2aa98e2SPeter Wemm register HDR *h; 167812ed1c7cSGregory Neil Shapiro char buf[SM_MAX(MAXLINE,BUFSIZ)]; 1679c2aa98e2SPeter Wemm char obuf[MAXLINE]; 1680c2aa98e2SPeter Wemm 1681c2aa98e2SPeter Wemm if (tTd(34, 1)) 168212ed1c7cSGregory Neil Shapiro sm_dprintf("--- putheader, mailer = %s ---\n", 1683c2aa98e2SPeter Wemm mci->mci_mailer->m_name); 1684c2aa98e2SPeter Wemm 1685c2aa98e2SPeter Wemm /* 1686c2aa98e2SPeter Wemm ** If we're in MIME mode, we're not really in the header of the 1687c2aa98e2SPeter Wemm ** message, just the header of one of the parts of the body of 1688c2aa98e2SPeter Wemm ** the message. Therefore MCIF_INHEADER should not be turned on. 1689c2aa98e2SPeter Wemm */ 1690c2aa98e2SPeter Wemm 1691c2aa98e2SPeter Wemm if (!bitset(MCIF_INMIME, mci->mci_flags)) 1692c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 1693c2aa98e2SPeter Wemm 1694c2aa98e2SPeter Wemm for (h = hdr; h != NULL; h = h->h_link) 1695c2aa98e2SPeter Wemm { 1696c2aa98e2SPeter Wemm register char *p = h->h_value; 169712ed1c7cSGregory Neil Shapiro char *q; 1698c2aa98e2SPeter Wemm 1699c2aa98e2SPeter Wemm if (tTd(34, 11)) 1700c2aa98e2SPeter Wemm { 170112ed1c7cSGregory Neil Shapiro sm_dprintf(" %s:", h->h_field); 1702bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), p); 1703c2aa98e2SPeter Wemm } 1704c2aa98e2SPeter Wemm 17053299c2f1SGregory Neil Shapiro /* Skip empty headers */ 17063299c2f1SGregory Neil Shapiro if (h->h_value == NULL) 17073299c2f1SGregory Neil Shapiro continue; 17083299c2f1SGregory Neil Shapiro 170976b7bf71SPeter Wemm /* heuristic shortening of MIME fields to avoid MUA overflows */ 171076b7bf71SPeter Wemm if (MaxMimeFieldLength > 0 && 171176b7bf71SPeter Wemm wordinclass(h->h_field, 171212ed1c7cSGregory Neil Shapiro macid("{checkMIMEFieldHeaders}"))) 171376b7bf71SPeter Wemm { 1714c46d91b7SGregory Neil Shapiro size_t len; 1715c46d91b7SGregory Neil Shapiro 1716f9218d3dSGregory Neil Shapiro len = fix_mime_header(h, e); 1717c46d91b7SGregory Neil Shapiro if (len > 0) 171876b7bf71SPeter Wemm { 171976b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1720c46d91b7SGregory Neil Shapiro "Truncated MIME %s header due to field size (length = %ld) (possible attack)", 1721c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 172276b7bf71SPeter Wemm if (tTd(34, 11)) 172312ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", 1724c46d91b7SGregory Neil Shapiro h->h_field, 1725c46d91b7SGregory Neil Shapiro (unsigned long) len); 172676b7bf71SPeter Wemm } 172776b7bf71SPeter Wemm } 172876b7bf71SPeter Wemm 172976b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 173076b7bf71SPeter Wemm wordinclass(h->h_field, 173112ed1c7cSGregory Neil Shapiro macid("{checkMIMETextHeaders}"))) 173276b7bf71SPeter Wemm { 1733c46d91b7SGregory Neil Shapiro size_t len; 1734c46d91b7SGregory Neil Shapiro 1735c46d91b7SGregory Neil Shapiro len = strlen(h->h_value); 1736c46d91b7SGregory Neil Shapiro if (len > (size_t) MaxMimeHeaderLength) 173776b7bf71SPeter Wemm { 173876b7bf71SPeter Wemm h->h_value[MaxMimeHeaderLength - 1] = '\0'; 173976b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1740c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1741c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 174276b7bf71SPeter Wemm if (tTd(34, 11)) 174312ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1744c46d91b7SGregory Neil Shapiro h->h_field, 1745c46d91b7SGregory Neil Shapiro (unsigned long) len); 174676b7bf71SPeter Wemm } 174776b7bf71SPeter Wemm } 174876b7bf71SPeter Wemm 174976b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 175076b7bf71SPeter Wemm wordinclass(h->h_field, 175112ed1c7cSGregory Neil Shapiro macid("{checkMIMEHeaders}"))) 175276b7bf71SPeter Wemm { 1753c46d91b7SGregory Neil Shapiro size_t len; 1754c46d91b7SGregory Neil Shapiro 1755c46d91b7SGregory Neil Shapiro len = strlen(h->h_value); 1756c46d91b7SGregory Neil Shapiro if (shorten_rfc822_string(h->h_value, 1757c46d91b7SGregory Neil Shapiro MaxMimeHeaderLength)) 175876b7bf71SPeter Wemm { 1759f9218d3dSGregory Neil Shapiro if (len < MaxMimeHeaderLength) 1760f9218d3dSGregory Neil Shapiro { 1761f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus header */ 1762f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 1763f9218d3dSGregory Neil Shapiro "Fixed MIME %s header (possible attack)", 1764f9218d3dSGregory Neil Shapiro h->h_field); 1765f9218d3dSGregory Neil Shapiro if (tTd(34, 11)) 1766f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header (possible attack)\n", 1767f9218d3dSGregory Neil Shapiro h->h_field); 1768f9218d3dSGregory Neil Shapiro } 1769f9218d3dSGregory Neil Shapiro else 1770f9218d3dSGregory Neil Shapiro { 1771f9218d3dSGregory Neil Shapiro /* we actually shortened header */ 177276b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1773c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1774f9218d3dSGregory Neil Shapiro h->h_field, 1775f9218d3dSGregory Neil Shapiro (unsigned long) len); 177676b7bf71SPeter Wemm if (tTd(34, 11)) 177712ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1778c46d91b7SGregory Neil Shapiro h->h_field, 1779c46d91b7SGregory Neil Shapiro (unsigned long) len); 178076b7bf71SPeter Wemm } 178176b7bf71SPeter Wemm } 1782f9218d3dSGregory Neil Shapiro } 178376b7bf71SPeter Wemm 1784e01d6f61SPeter Wemm /* 1785e01d6f61SPeter Wemm ** Suppress Content-Transfer-Encoding: if we are MIMEing 1786e01d6f61SPeter Wemm ** and we are potentially converting from 8 bit to 7 bit 1787e01d6f61SPeter Wemm ** MIME. If converting, add a new CTE header in 1788e01d6f61SPeter Wemm ** mime8to7(). 1789e01d6f61SPeter Wemm */ 179012ed1c7cSGregory Neil Shapiro 1791c2aa98e2SPeter Wemm if (bitset(H_CTE, h->h_flags) && 1792e01d6f61SPeter Wemm bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 1793e01d6f61SPeter Wemm mci->mci_flags) && 1794e01d6f61SPeter Wemm !bitset(M87F_NO8TO7, flags)) 1795c2aa98e2SPeter Wemm { 1796c2aa98e2SPeter Wemm if (tTd(34, 11)) 179712ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (content-transfer-encoding))\n"); 1798c2aa98e2SPeter Wemm continue; 1799c2aa98e2SPeter Wemm } 1800c2aa98e2SPeter Wemm 1801c2aa98e2SPeter Wemm if (bitset(MCIF_INMIME, mci->mci_flags)) 1802c2aa98e2SPeter Wemm { 1803c2aa98e2SPeter Wemm if (tTd(34, 11)) 180412ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 1805567a2fc9SGregory Neil Shapiro if (!put_vanilla_header(h, p, mci)) 1806567a2fc9SGregory Neil Shapiro goto writeerr; 1807c2aa98e2SPeter Wemm continue; 1808c2aa98e2SPeter Wemm } 1809c2aa98e2SPeter Wemm 1810c2aa98e2SPeter Wemm if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 18113299c2f1SGregory Neil Shapiro !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && 18123299c2f1SGregory Neil Shapiro (h->h_macro == '\0' || 181312ed1c7cSGregory Neil Shapiro (q = macvalue(bitidx(h->h_macro), e)) == NULL || 181412ed1c7cSGregory Neil Shapiro *q == '\0')) 1815c2aa98e2SPeter Wemm { 1816c2aa98e2SPeter Wemm if (tTd(34, 11)) 181712ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped)\n"); 1818c2aa98e2SPeter Wemm continue; 1819c2aa98e2SPeter Wemm } 1820c2aa98e2SPeter Wemm 1821c2aa98e2SPeter Wemm /* handle Resent-... headers specially */ 1822c2aa98e2SPeter Wemm if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 1823c2aa98e2SPeter Wemm { 1824c2aa98e2SPeter Wemm if (tTd(34, 11)) 182512ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (resent))\n"); 1826c2aa98e2SPeter Wemm continue; 1827c2aa98e2SPeter Wemm } 1828c2aa98e2SPeter Wemm 1829c2aa98e2SPeter Wemm /* suppress return receipts if requested */ 1830c2aa98e2SPeter Wemm if (bitset(H_RECEIPTTO, h->h_flags) && 1831c2aa98e2SPeter Wemm (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) 1832c2aa98e2SPeter Wemm { 1833c2aa98e2SPeter Wemm if (tTd(34, 11)) 183412ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (receipt))\n"); 1835c2aa98e2SPeter Wemm continue; 1836c2aa98e2SPeter Wemm } 1837c2aa98e2SPeter Wemm 1838c2aa98e2SPeter Wemm /* macro expand value if generated internally */ 18393299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) || 18403299c2f1SGregory Neil Shapiro bitset(H_BINDLATE, h->h_flags)) 1841c2aa98e2SPeter Wemm { 1842951742c4SGregory Neil Shapiro expand(p, buf, sizeof(buf), e); 1843c2aa98e2SPeter Wemm p = buf; 1844c2aa98e2SPeter Wemm if (*p == '\0') 1845c2aa98e2SPeter Wemm { 1846c2aa98e2SPeter Wemm if (tTd(34, 11)) 184712ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- null value)\n"); 1848c2aa98e2SPeter Wemm continue; 1849c2aa98e2SPeter Wemm } 1850c2aa98e2SPeter Wemm } 1851c2aa98e2SPeter Wemm 1852c2aa98e2SPeter Wemm if (bitset(H_BCC, h->h_flags)) 1853c2aa98e2SPeter Wemm { 1854c2aa98e2SPeter Wemm /* Bcc: field -- either truncate or delete */ 1855c2aa98e2SPeter Wemm if (bitset(EF_DELETE_BCC, e->e_flags)) 1856c2aa98e2SPeter Wemm { 1857c2aa98e2SPeter Wemm if (tTd(34, 11)) 185812ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- bcc)\n"); 1859c2aa98e2SPeter Wemm } 1860c2aa98e2SPeter Wemm else 1861c2aa98e2SPeter Wemm { 1862c2aa98e2SPeter Wemm /* no other recipient headers: truncate value */ 1863951742c4SGregory Neil Shapiro (void) sm_strlcpyn(obuf, sizeof(obuf), 2, 186412ed1c7cSGregory Neil Shapiro h->h_field, ":"); 1865567a2fc9SGregory Neil Shapiro if (!putline(obuf, mci)) 1866567a2fc9SGregory Neil Shapiro goto writeerr; 1867c2aa98e2SPeter Wemm } 1868c2aa98e2SPeter Wemm continue; 1869c2aa98e2SPeter Wemm } 1870c2aa98e2SPeter Wemm 1871c2aa98e2SPeter Wemm if (tTd(34, 11)) 187212ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 1873c2aa98e2SPeter Wemm 1874c2aa98e2SPeter Wemm if (bitset(H_FROM|H_RCPT, h->h_flags)) 1875c2aa98e2SPeter Wemm { 1876c2aa98e2SPeter Wemm /* address field */ 1877c2aa98e2SPeter Wemm bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 1878c2aa98e2SPeter Wemm 1879c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 188012ed1c7cSGregory Neil Shapiro oldstyle = false; 188141f3d2ceSGregory Neil Shapiro commaize(h, p, oldstyle, mci, e, 188241f3d2ceSGregory Neil Shapiro PXLF_HEADER | PXLF_STRIPMQUOTE); 1883c2aa98e2SPeter Wemm } 1884c2aa98e2SPeter Wemm else 1885c2aa98e2SPeter Wemm { 1886567a2fc9SGregory Neil Shapiro if (!put_vanilla_header(h, p, mci)) 1887567a2fc9SGregory Neil Shapiro goto writeerr; 1888c2aa98e2SPeter Wemm } 1889c2aa98e2SPeter Wemm } 1890c2aa98e2SPeter Wemm 1891c2aa98e2SPeter Wemm /* 1892c2aa98e2SPeter Wemm ** If we are converting this to a MIME message, add the 18933299c2f1SGregory Neil Shapiro ** MIME headers (but not in MIME mode!). 1894c2aa98e2SPeter Wemm */ 1895c2aa98e2SPeter Wemm 1896c2aa98e2SPeter Wemm #if MIME8TO7 1897c2aa98e2SPeter Wemm if (bitset(MM_MIME8BIT, MimeMode) && 1898c2aa98e2SPeter Wemm bitset(EF_HAS8BIT, e->e_flags) && 1899c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 1900c2aa98e2SPeter Wemm !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 19013299c2f1SGregory Neil Shapiro !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) && 19023299c2f1SGregory Neil Shapiro hvalue("MIME-Version", e->e_header) == NULL) 1903c2aa98e2SPeter Wemm { 1904567a2fc9SGregory Neil Shapiro if (!putline("MIME-Version: 1.0", mci)) 1905567a2fc9SGregory Neil Shapiro goto writeerr; 1906c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL) 1907c2aa98e2SPeter Wemm { 1908951742c4SGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof(obuf), 1909c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s", 1910c2aa98e2SPeter Wemm defcharset(e)); 1911567a2fc9SGregory Neil Shapiro if (!putline(obuf, mci)) 1912567a2fc9SGregory Neil Shapiro goto writeerr; 1913c2aa98e2SPeter Wemm } 1914567a2fc9SGregory Neil Shapiro if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL 1915567a2fc9SGregory Neil Shapiro && !putline("Content-Transfer-Encoding: 8bit", mci)) 1916567a2fc9SGregory Neil Shapiro goto writeerr; 1917c2aa98e2SPeter Wemm } 19183299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */ 1919567a2fc9SGregory Neil Shapiro return true; 1920567a2fc9SGregory Neil Shapiro 1921567a2fc9SGregory Neil Shapiro writeerr: 1922567a2fc9SGregory Neil Shapiro return false; 1923c2aa98e2SPeter Wemm } 1924951742c4SGregory Neil Shapiro 192512ed1c7cSGregory Neil Shapiro /* 1926c2aa98e2SPeter Wemm ** PUT_VANILLA_HEADER -- output a fairly ordinary header 1927c2aa98e2SPeter Wemm ** 1928c2aa98e2SPeter Wemm ** Parameters: 1929c2aa98e2SPeter Wemm ** h -- the structure describing this header 1930c2aa98e2SPeter Wemm ** v -- the value of this header 1931c2aa98e2SPeter Wemm ** mci -- the connection info for output 1932c2aa98e2SPeter Wemm ** 1933c2aa98e2SPeter Wemm ** Returns: 1934355d91e3SGregory Neil Shapiro ** true iff header was written successfully 1935c2aa98e2SPeter Wemm */ 1936c2aa98e2SPeter Wemm 1937567a2fc9SGregory Neil Shapiro static bool 1938c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci) 1939c2aa98e2SPeter Wemm HDR *h; 1940c2aa98e2SPeter Wemm char *v; 1941c2aa98e2SPeter Wemm MCI *mci; 1942c2aa98e2SPeter Wemm { 1943c2aa98e2SPeter Wemm register char *nlp; 1944c2aa98e2SPeter Wemm register char *obp; 1945c2aa98e2SPeter Wemm int putflags; 1946684b2a5fSGregory Neil Shapiro char obuf[MAXLINE + 256]; /* additional length for h_field */ 1947c2aa98e2SPeter Wemm 1948951742c4SGregory Neil Shapiro putflags = PXLF_HEADER | PXLF_STRIPMQUOTE; 1949c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1950c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 1951951742c4SGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field); 1952c2aa98e2SPeter Wemm obp = obuf + strlen(obuf); 1953c2aa98e2SPeter Wemm while ((nlp = strchr(v, '\n')) != NULL) 1954c2aa98e2SPeter Wemm { 1955c2aa98e2SPeter Wemm int l; 1956c2aa98e2SPeter Wemm 1957c2aa98e2SPeter Wemm l = nlp - v; 19587660b554SGregory Neil Shapiro 19597660b554SGregory Neil Shapiro /* 19607660b554SGregory Neil Shapiro ** XXX This is broken for SPACELEFT()==0 19617660b554SGregory Neil Shapiro ** However, SPACELEFT() is always > 0 unless MAXLINE==1. 19627660b554SGregory Neil Shapiro */ 19637660b554SGregory Neil Shapiro 19643299c2f1SGregory Neil Shapiro if (SPACELEFT(obuf, obp) - 1 < (size_t) l) 1965c2aa98e2SPeter Wemm l = SPACELEFT(obuf, obp) - 1; 1966c2aa98e2SPeter Wemm 196712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); 1968567a2fc9SGregory Neil Shapiro if (!putxline(obuf, strlen(obuf), mci, putflags)) 1969567a2fc9SGregory Neil Shapiro goto writeerr; 1970c2aa98e2SPeter Wemm v += l + 1; 1971c2aa98e2SPeter Wemm obp = obuf; 1972c2aa98e2SPeter Wemm if (*v != ' ' && *v != '\t') 1973c2aa98e2SPeter Wemm *obp++ = ' '; 1974c2aa98e2SPeter Wemm } 19757660b554SGregory Neil Shapiro 19767660b554SGregory Neil Shapiro /* XXX This is broken for SPACELEFT()==0 */ 197712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", 197812ed1c7cSGregory Neil Shapiro (int) (SPACELEFT(obuf, obp) - 1), v); 1979567a2fc9SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags); 1980567a2fc9SGregory Neil Shapiro 1981567a2fc9SGregory Neil Shapiro writeerr: 1982567a2fc9SGregory Neil Shapiro return false; 1983c2aa98e2SPeter Wemm } 1984951742c4SGregory Neil Shapiro 198512ed1c7cSGregory Neil Shapiro /* 1986c2aa98e2SPeter Wemm ** COMMAIZE -- output a header field, making a comma-translated list. 1987c2aa98e2SPeter Wemm ** 1988c2aa98e2SPeter Wemm ** Parameters: 1989c2aa98e2SPeter Wemm ** h -- the header field to output. 1990c2aa98e2SPeter Wemm ** p -- the value to put in it. 199112ed1c7cSGregory Neil Shapiro ** oldstyle -- true if this is an old style header. 1992c2aa98e2SPeter Wemm ** mci -- the connection information. 1993c2aa98e2SPeter Wemm ** e -- the envelope containing the message. 199441f3d2ceSGregory Neil Shapiro ** putflags -- flags for putxline() 1995c2aa98e2SPeter Wemm ** 1996c2aa98e2SPeter Wemm ** Returns: 1997355d91e3SGregory Neil Shapiro ** true iff header field was written successfully 1998c2aa98e2SPeter Wemm ** 1999c2aa98e2SPeter Wemm ** Side Effects: 2000951742c4SGregory Neil Shapiro ** outputs "p" to "mci". 2001c2aa98e2SPeter Wemm */ 2002c2aa98e2SPeter Wemm 2003567a2fc9SGregory Neil Shapiro bool 200441f3d2ceSGregory Neil Shapiro commaize(h, p, oldstyle, mci, e, putflags) 2005c2aa98e2SPeter Wemm register HDR *h; 2006c2aa98e2SPeter Wemm register char *p; 2007c2aa98e2SPeter Wemm bool oldstyle; 2008c2aa98e2SPeter Wemm register MCI *mci; 2009c2aa98e2SPeter Wemm register ENVELOPE *e; 201041f3d2ceSGregory Neil Shapiro int putflags; 2011c2aa98e2SPeter Wemm { 2012c2aa98e2SPeter Wemm register char *obp; 2013951742c4SGregory Neil Shapiro int opos, omax, spaces; 201412ed1c7cSGregory Neil Shapiro bool firstone = true; 20157660b554SGregory Neil Shapiro char **res; 2016c2aa98e2SPeter Wemm char obuf[MAXLINE + 3]; 2017c2aa98e2SPeter Wemm 2018c2aa98e2SPeter Wemm /* 2019c2aa98e2SPeter Wemm ** Output the address list translated by the 2020c2aa98e2SPeter Wemm ** mailer and with commas. 2021c2aa98e2SPeter Wemm */ 2022c2aa98e2SPeter Wemm 2023c2aa98e2SPeter Wemm if (tTd(14, 2)) 202412ed1c7cSGregory Neil Shapiro sm_dprintf("commaize(%s:%s)\n", h->h_field, p); 2025c2aa98e2SPeter Wemm 2026c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 2027c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 2028c2aa98e2SPeter Wemm 2029c2aa98e2SPeter Wemm obp = obuf; 2030951742c4SGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field); 2031951742c4SGregory Neil Shapiro /* opos = strlen(obp); instead of the next 3 lines? */ 2032951742c4SGregory Neil Shapiro opos = strlen(h->h_field) + 1; 2033951742c4SGregory Neil Shapiro if (opos > 201) 2034951742c4SGregory Neil Shapiro opos = 201; 2035c2aa98e2SPeter Wemm obp += opos; 2036951742c4SGregory Neil Shapiro 2037951742c4SGregory Neil Shapiro spaces = 0; 2038951742c4SGregory Neil Shapiro while (*p != '\0' && isascii(*p) && isspace(*p)) 2039951742c4SGregory Neil Shapiro { 2040951742c4SGregory Neil Shapiro ++spaces; 2041951742c4SGregory Neil Shapiro ++p; 2042951742c4SGregory Neil Shapiro } 2043951742c4SGregory Neil Shapiro if (spaces > 0) 2044951742c4SGregory Neil Shapiro { 2045951742c4SGregory Neil Shapiro SM_ASSERT(sizeof(obuf) > opos * 2); 2046951742c4SGregory Neil Shapiro 2047951742c4SGregory Neil Shapiro /* 2048951742c4SGregory Neil Shapiro ** Restrict number of spaces to half the length of buffer 2049951742c4SGregory Neil Shapiro ** so the header field body can be put in here too. 2050951742c4SGregory Neil Shapiro ** Note: this is a hack... 2051951742c4SGregory Neil Shapiro */ 2052951742c4SGregory Neil Shapiro 2053951742c4SGregory Neil Shapiro if (spaces > sizeof(obuf) / 2) 2054951742c4SGregory Neil Shapiro spaces = sizeof(obuf) / 2; 2055951742c4SGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces, 2056951742c4SGregory Neil Shapiro ""); 2057951742c4SGregory Neil Shapiro opos += spaces; 2058951742c4SGregory Neil Shapiro obp += spaces; 2059951742c4SGregory Neil Shapiro SM_ASSERT(obp < &obuf[MAXLINE]); 2060951742c4SGregory Neil Shapiro } 2061951742c4SGregory Neil Shapiro 2062c2aa98e2SPeter Wemm omax = mci->mci_mailer->m_linelimit - 2; 2063c2aa98e2SPeter Wemm if (omax < 0 || omax > 78) 2064c2aa98e2SPeter Wemm omax = 78; 2065c2aa98e2SPeter Wemm 2066c2aa98e2SPeter Wemm /* 2067c2aa98e2SPeter Wemm ** Run through the list of values. 2068c2aa98e2SPeter Wemm */ 2069c2aa98e2SPeter Wemm 2070c2aa98e2SPeter Wemm while (*p != '\0') 2071c2aa98e2SPeter Wemm { 2072c2aa98e2SPeter Wemm register char *name; 2073c2aa98e2SPeter Wemm register int c; 2074c2aa98e2SPeter Wemm char savechar; 2075c2aa98e2SPeter Wemm int flags; 20763299c2f1SGregory Neil Shapiro auto int status; 2077c2aa98e2SPeter Wemm 2078c2aa98e2SPeter Wemm /* 2079c2aa98e2SPeter Wemm ** Find the end of the name. New style names 2080c2aa98e2SPeter Wemm ** end with a comma, old style names end with 2081c2aa98e2SPeter Wemm ** a space character. However, spaces do not 2082c2aa98e2SPeter Wemm ** necessarily delimit an old-style name -- at 2083c2aa98e2SPeter Wemm ** signs mean keep going. 2084c2aa98e2SPeter Wemm */ 2085c2aa98e2SPeter Wemm 2086c2aa98e2SPeter Wemm /* find end of name */ 2087c2aa98e2SPeter Wemm while ((isascii(*p) && isspace(*p)) || *p == ',') 2088c2aa98e2SPeter Wemm p++; 2089c2aa98e2SPeter Wemm name = p; 20907660b554SGregory Neil Shapiro res = NULL; 2091c2aa98e2SPeter Wemm for (;;) 2092c2aa98e2SPeter Wemm { 2093c2aa98e2SPeter Wemm auto char *oldp; 2094c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 2095c2aa98e2SPeter Wemm 20967660b554SGregory Neil Shapiro res = prescan(p, oldstyle ? ' ' : ',', pvpbuf, 2097951742c4SGregory Neil Shapiro sizeof(pvpbuf), &oldp, ExtTokenTab, false); 2098c2aa98e2SPeter Wemm p = oldp; 20997660b554SGregory Neil Shapiro #if _FFR_IGNORE_BOGUS_ADDR 21007660b554SGregory Neil Shapiro /* ignore addresses that can't be parsed */ 21017660b554SGregory Neil Shapiro if (res == NULL) 21027660b554SGregory Neil Shapiro { 21037660b554SGregory Neil Shapiro name = p; 21047660b554SGregory Neil Shapiro continue; 21057660b554SGregory Neil Shapiro } 21067660b554SGregory Neil Shapiro #endif /* _FFR_IGNORE_BOGUS_ADDR */ 2107c2aa98e2SPeter Wemm 2108c2aa98e2SPeter Wemm /* look to see if we have an at sign */ 2109c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 2110c2aa98e2SPeter Wemm p++; 2111c2aa98e2SPeter Wemm 2112c2aa98e2SPeter Wemm if (*p != '@') 2113c2aa98e2SPeter Wemm { 2114c2aa98e2SPeter Wemm p = oldp; 2115c2aa98e2SPeter Wemm break; 2116c2aa98e2SPeter Wemm } 211712ed1c7cSGregory Neil Shapiro ++p; 2118c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 2119c2aa98e2SPeter Wemm p++; 2120c2aa98e2SPeter Wemm } 2121c2aa98e2SPeter Wemm /* at the end of one complete name */ 2122c2aa98e2SPeter Wemm 2123c2aa98e2SPeter Wemm /* strip off trailing white space */ 2124c2aa98e2SPeter Wemm while (p >= name && 2125c2aa98e2SPeter Wemm ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 2126c2aa98e2SPeter Wemm p--; 2127c2aa98e2SPeter Wemm if (++p == name) 2128c2aa98e2SPeter Wemm continue; 21297660b554SGregory Neil Shapiro 21307660b554SGregory Neil Shapiro /* 21317660b554SGregory Neil Shapiro ** if prescan() failed go a bit backwards; this is a hack, 21327660b554SGregory Neil Shapiro ** there should be some better error recovery. 21337660b554SGregory Neil Shapiro */ 21347660b554SGregory Neil Shapiro 21357660b554SGregory Neil Shapiro if (res == NULL && p > name && 21367660b554SGregory Neil Shapiro !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 21377660b554SGregory Neil Shapiro --p; 2138c2aa98e2SPeter Wemm savechar = *p; 2139c2aa98e2SPeter Wemm *p = '\0'; 2140c2aa98e2SPeter Wemm 2141c2aa98e2SPeter Wemm /* translate the name to be relative */ 2142c2aa98e2SPeter Wemm flags = RF_HEADERADDR|RF_ADDDOMAIN; 2143c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 2144c2aa98e2SPeter Wemm flags |= RF_SENDERADDR; 2145c2aa98e2SPeter Wemm #if USERDB 2146c2aa98e2SPeter Wemm else if (e->e_from.q_mailer != NULL && 2147c2aa98e2SPeter Wemm bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 2148c2aa98e2SPeter Wemm { 2149c2aa98e2SPeter Wemm char *q; 2150c2aa98e2SPeter Wemm 215112ed1c7cSGregory Neil Shapiro q = udbsender(name, e->e_rpool); 2152c2aa98e2SPeter Wemm if (q != NULL) 2153c2aa98e2SPeter Wemm name = q; 2154c2aa98e2SPeter Wemm } 21553299c2f1SGregory Neil Shapiro #endif /* USERDB */ 21563299c2f1SGregory Neil Shapiro status = EX_OK; 21573299c2f1SGregory Neil Shapiro name = remotename(name, mci->mci_mailer, flags, &status, e); 2158c2aa98e2SPeter Wemm if (*name == '\0') 2159c2aa98e2SPeter Wemm { 2160c2aa98e2SPeter Wemm *p = savechar; 2161c2aa98e2SPeter Wemm continue; 2162c2aa98e2SPeter Wemm } 216312ed1c7cSGregory Neil Shapiro name = denlstring(name, false, true); 2164c2aa98e2SPeter Wemm 2165c2aa98e2SPeter Wemm /* output the name with nice formatting */ 2166c2aa98e2SPeter Wemm opos += strlen(name); 2167c2aa98e2SPeter Wemm if (!firstone) 2168c2aa98e2SPeter Wemm opos += 2; 2169c2aa98e2SPeter Wemm if (opos > omax && !firstone) 2170c2aa98e2SPeter Wemm { 217112ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp)); 2172567a2fc9SGregory Neil Shapiro if (!putxline(obuf, strlen(obuf), mci, putflags)) 2173567a2fc9SGregory Neil Shapiro goto writeerr; 2174c2aa98e2SPeter Wemm obp = obuf; 2175951742c4SGregory Neil Shapiro (void) sm_strlcpy(obp, " ", sizeof(obuf)); 2176c2aa98e2SPeter Wemm opos = strlen(obp); 2177c2aa98e2SPeter Wemm obp += opos; 2178c2aa98e2SPeter Wemm opos += strlen(name); 2179c2aa98e2SPeter Wemm } 2180c2aa98e2SPeter Wemm else if (!firstone) 2181c2aa98e2SPeter Wemm { 218212ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp)); 2183c2aa98e2SPeter Wemm obp += 2; 2184c2aa98e2SPeter Wemm } 2185c2aa98e2SPeter Wemm 2186c2aa98e2SPeter Wemm while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 2187c2aa98e2SPeter Wemm *obp++ = c; 218812ed1c7cSGregory Neil Shapiro firstone = false; 2189c2aa98e2SPeter Wemm *p = savechar; 2190c2aa98e2SPeter Wemm } 2191951742c4SGregory Neil Shapiro if (obp < &obuf[sizeof(obuf)]) 2192c2aa98e2SPeter Wemm *obp = '\0'; 21937660b554SGregory Neil Shapiro else 2194951742c4SGregory Neil Shapiro obuf[sizeof(obuf) - 1] = '\0'; 2195567a2fc9SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags); 2196567a2fc9SGregory Neil Shapiro 2197567a2fc9SGregory Neil Shapiro writeerr: 2198567a2fc9SGregory Neil Shapiro return false; 2199c2aa98e2SPeter Wemm } 2200567a2fc9SGregory Neil Shapiro 220112ed1c7cSGregory Neil Shapiro /* 2202c2aa98e2SPeter Wemm ** COPYHEADER -- copy header list 2203c2aa98e2SPeter Wemm ** 2204c2aa98e2SPeter Wemm ** This routine is the equivalent of newstr for header lists 2205c2aa98e2SPeter Wemm ** 2206c2aa98e2SPeter Wemm ** Parameters: 2207c2aa98e2SPeter Wemm ** header -- list of header structures to copy. 220812ed1c7cSGregory Neil Shapiro ** rpool -- resource pool, or NULL 2209c2aa98e2SPeter Wemm ** 2210c2aa98e2SPeter Wemm ** Returns: 2211c2aa98e2SPeter Wemm ** a copy of 'header'. 2212c2aa98e2SPeter Wemm ** 2213c2aa98e2SPeter Wemm ** Side Effects: 2214c2aa98e2SPeter Wemm ** none. 2215c2aa98e2SPeter Wemm */ 2216c2aa98e2SPeter Wemm 2217c2aa98e2SPeter Wemm HDR * 221812ed1c7cSGregory Neil Shapiro copyheader(header, rpool) 2219c2aa98e2SPeter Wemm register HDR *header; 222012ed1c7cSGregory Neil Shapiro SM_RPOOL_T *rpool; 2221c2aa98e2SPeter Wemm { 2222c2aa98e2SPeter Wemm register HDR *newhdr; 2223c2aa98e2SPeter Wemm HDR *ret; 2224c2aa98e2SPeter Wemm register HDR **tail = &ret; 2225c2aa98e2SPeter Wemm 2226c2aa98e2SPeter Wemm while (header != NULL) 2227c2aa98e2SPeter Wemm { 2228951742c4SGregory Neil Shapiro newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr)); 2229c2aa98e2SPeter Wemm STRUCTCOPY(*header, *newhdr); 2230c2aa98e2SPeter Wemm *tail = newhdr; 2231c2aa98e2SPeter Wemm tail = &newhdr->h_link; 2232c2aa98e2SPeter Wemm header = header->h_link; 2233c2aa98e2SPeter Wemm } 2234c2aa98e2SPeter Wemm *tail = NULL; 2235c2aa98e2SPeter Wemm 2236c2aa98e2SPeter Wemm return ret; 2237c2aa98e2SPeter Wemm } 2238951742c4SGregory Neil Shapiro 223912ed1c7cSGregory Neil Shapiro /* 224076b7bf71SPeter Wemm ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header 224176b7bf71SPeter Wemm ** 224276b7bf71SPeter Wemm ** Run through all of the parameters of a MIME header and 224376b7bf71SPeter Wemm ** possibly truncate and rebalance the parameter according 224476b7bf71SPeter Wemm ** to MaxMimeFieldLength. 224576b7bf71SPeter Wemm ** 224676b7bf71SPeter Wemm ** Parameters: 2247f9218d3dSGregory Neil Shapiro ** h -- the header to truncate/rebalance 2248f9218d3dSGregory Neil Shapiro ** e -- the current envelope 224976b7bf71SPeter Wemm ** 225076b7bf71SPeter Wemm ** Returns: 2251c46d91b7SGregory Neil Shapiro ** length of last offending field, 0 if all ok. 225276b7bf71SPeter Wemm ** 225376b7bf71SPeter Wemm ** Side Effects: 225476b7bf71SPeter Wemm ** string modified in place 225576b7bf71SPeter Wemm */ 225676b7bf71SPeter Wemm 2257c46d91b7SGregory Neil Shapiro static size_t 2258f9218d3dSGregory Neil Shapiro fix_mime_header(h, e) 2259f9218d3dSGregory Neil Shapiro HDR *h; 2260f9218d3dSGregory Neil Shapiro ENVELOPE *e; 226176b7bf71SPeter Wemm { 2262f9218d3dSGregory Neil Shapiro char *begin = h->h_value; 226376b7bf71SPeter Wemm char *end; 2264c46d91b7SGregory Neil Shapiro size_t len = 0; 2265c46d91b7SGregory Neil Shapiro size_t retlen = 0; 226676b7bf71SPeter Wemm 2267f9218d3dSGregory Neil Shapiro if (begin == NULL || *begin == '\0') 2268c46d91b7SGregory Neil Shapiro return 0; 226976b7bf71SPeter Wemm 227076b7bf71SPeter Wemm /* Split on each ';' */ 22717660b554SGregory Neil Shapiro /* find_character() never returns NULL */ 227276b7bf71SPeter Wemm while ((end = find_character(begin, ';')) != NULL) 227376b7bf71SPeter Wemm { 227476b7bf71SPeter Wemm char save = *end; 227576b7bf71SPeter Wemm char *bp; 227676b7bf71SPeter Wemm 227776b7bf71SPeter Wemm *end = '\0'; 227876b7bf71SPeter Wemm 2279c46d91b7SGregory Neil Shapiro len = strlen(begin); 2280c46d91b7SGregory Neil Shapiro 228176b7bf71SPeter Wemm /* Shorten individual parameter */ 228276b7bf71SPeter Wemm if (shorten_rfc822_string(begin, MaxMimeFieldLength)) 2283f9218d3dSGregory Neil Shapiro { 2284f9218d3dSGregory Neil Shapiro if (len < MaxMimeFieldLength) 2285f9218d3dSGregory Neil Shapiro { 2286f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus field */ 2287f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 2288f9218d3dSGregory Neil Shapiro "Fixed MIME %s header field (possible attack)", 2289f9218d3dSGregory Neil Shapiro h->h_field); 2290f9218d3dSGregory Neil Shapiro if (tTd(34, 11)) 2291f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header field (possible attack)\n", 2292f9218d3dSGregory Neil Shapiro h->h_field); 2293f9218d3dSGregory Neil Shapiro } 2294f9218d3dSGregory Neil Shapiro else 2295f9218d3dSGregory Neil Shapiro { 2296f9218d3dSGregory Neil Shapiro /* we actually shortened the header */ 2297c46d91b7SGregory Neil Shapiro retlen = len; 2298f9218d3dSGregory Neil Shapiro } 2299f9218d3dSGregory Neil Shapiro } 230076b7bf71SPeter Wemm 230176b7bf71SPeter Wemm /* Collapse the possibly shortened string with rest */ 230276b7bf71SPeter Wemm bp = begin + strlen(begin); 230376b7bf71SPeter Wemm if (bp != end) 230476b7bf71SPeter Wemm { 230576b7bf71SPeter Wemm char *ep = end; 230676b7bf71SPeter Wemm 230776b7bf71SPeter Wemm *end = save; 230876b7bf71SPeter Wemm end = bp; 230976b7bf71SPeter Wemm 231076b7bf71SPeter Wemm /* copy character by character due to overlap */ 231176b7bf71SPeter Wemm while (*ep != '\0') 231276b7bf71SPeter Wemm *bp++ = *ep++; 231376b7bf71SPeter Wemm *bp = '\0'; 231476b7bf71SPeter Wemm } 231576b7bf71SPeter Wemm else 231676b7bf71SPeter Wemm *end = save; 231776b7bf71SPeter Wemm if (*end == '\0') 231876b7bf71SPeter Wemm break; 231976b7bf71SPeter Wemm 232076b7bf71SPeter Wemm /* Move past ';' */ 232176b7bf71SPeter Wemm begin = end + 1; 232276b7bf71SPeter Wemm } 2323c46d91b7SGregory Neil Shapiro return retlen; 232476b7bf71SPeter Wemm } 2325