138032Speter/* 2261363Sgshapiro * Copyright (c) 1998-2004, 2006, 2007 Proofpoint, Inc. and its suppliers. 364565Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1490795Sgshapiro#include <sendmail.h> 15168520Sgshapiro#include <sm/sendmail.h> 1638032Speter 17266692SgshapiroSM_RCSID("@(#)$Id: headers.c,v 8.320 2013-11-22 20:51:55 ca Exp $") 1864565Sgshapiro 19168520Sgshapirostatic HDR *allocheader __P((char *, char *, int, SM_RPOOL_T *, bool)); 20111826Sgshapirostatic size_t fix_mime_header __P((HDR *, ENVELOPE *)); 2164565Sgshapirostatic int priencode __P((char *)); 22157006Sgshapirostatic bool put_vanilla_header __P((HDR *, char *, MCI *)); 2364565Sgshapiro 2438032Speter/* 2538032Speter** SETUPHEADERS -- initialize headers in symbol table 2638032Speter** 2738032Speter** Parameters: 2838032Speter** none 2938032Speter** 3038032Speter** Returns: 3138032Speter** none 3238032Speter*/ 3338032Speter 3438032Spetervoid 3538032Spetersetupheaders() 3638032Speter{ 3738032Speter struct hdrinfo *hi; 3838032Speter STAB *s; 3938032Speter 4038032Speter for (hi = HdrInfo; hi->hi_field != NULL; hi++) 4138032Speter { 4238032Speter s = stab(hi->hi_field, ST_HEADER, ST_ENTER); 4338032Speter s->s_header.hi_flags = hi->hi_flags; 4438032Speter s->s_header.hi_ruleset = NULL; 4538032Speter } 4638032Speter} 47168520Sgshapiro 4890795Sgshapiro/* 49168520Sgshapiro** DOCHOMPHEADER -- process and save a header line. 5038032Speter** 51168520Sgshapiro** Called by chompheader. 5238032Speter** 5338032Speter** Parameters: 5438032Speter** line -- header as a text line. 5566497Sgshapiro** pflag -- flags for chompheader() (from sendmail.h) 5638032Speter** hdrp -- a pointer to the place to save the header. 5738032Speter** e -- the envelope including this header. 5838032Speter** 5938032Speter** Returns: 6038032Speter** flags for this header. 6138032Speter** 6238032Speter** Side Effects: 6338032Speter** The header is saved on the header list. 6438032Speter** Contents of 'line' are destroyed. 6538032Speter*/ 6638032Speter 6764565Sgshapirostatic struct hdrinfo NormalHeader = { NULL, 0, NULL }; 68168520Sgshapirostatic unsigned long dochompheader __P((char *, int, HDR **, ENVELOPE *)); 6938032Speter 70168520Sgshapirostatic unsigned long 71168520Sgshapirodochompheader(line, pflag, hdrp, e) 7238032Speter char *line; 7364565Sgshapiro int pflag; 7438032Speter HDR **hdrp; 75168520Sgshapiro ENVELOPE *e; 7638032Speter{ 7790795Sgshapiro unsigned char mid = '\0'; 7838032Speter register char *p; 7938032Speter register HDR *h; 8038032Speter HDR **hp; 8138032Speter char *fname; 8238032Speter char *fvalue; 8390795Sgshapiro bool cond = false; 8464565Sgshapiro bool dropfrom; 8538032Speter bool headeronly; 8638032Speter STAB *s; 8738032Speter struct hdrinfo *hi; 8890795Sgshapiro bool nullheader = false; 8964565Sgshapiro BITMAP256 mopts; 9038032Speter 9138032Speter headeronly = hdrp != NULL; 9238032Speter if (!headeronly) 9338032Speter hdrp = &e->e_header; 9438032Speter 9538032Speter /* strip off options */ 9638032Speter clrbitmap(mopts); 9738032Speter p = line; 9864565Sgshapiro if (!bitset(pflag, CHHDR_USER) && *p == '?') 9938032Speter { 10064565Sgshapiro int c; 10164565Sgshapiro register char *q; 10264565Sgshapiro 10364565Sgshapiro q = strchr(++p, '?'); 10464565Sgshapiro if (q == NULL) 10564565Sgshapiro goto hse; 10664565Sgshapiro 10764565Sgshapiro *q = '\0'; 10864565Sgshapiro c = *p & 0377; 10964565Sgshapiro 11064565Sgshapiro /* possibly macro conditional */ 11164565Sgshapiro if (c == MACROEXPAND) 11238032Speter { 11364565Sgshapiro /* catch ?$? */ 11464565Sgshapiro if (*++p == '\0') 11564565Sgshapiro { 11664565Sgshapiro *q = '?'; 11764565Sgshapiro goto hse; 11864565Sgshapiro } 11964565Sgshapiro 12090795Sgshapiro mid = (unsigned char) *p++; 12164565Sgshapiro 12264565Sgshapiro /* catch ?$abc? */ 12364565Sgshapiro if (*p != '\0') 12464565Sgshapiro { 12564565Sgshapiro *q = '?'; 12664565Sgshapiro goto hse; 12764565Sgshapiro } 12864565Sgshapiro } 12964565Sgshapiro else if (*p == '$') 13064565Sgshapiro { 13164565Sgshapiro /* catch ?$? */ 13264565Sgshapiro if (*++p == '\0') 13364565Sgshapiro { 13464565Sgshapiro *q = '?'; 13564565Sgshapiro goto hse; 13664565Sgshapiro } 13764565Sgshapiro 13890795Sgshapiro mid = (unsigned char) macid(p); 13964565Sgshapiro if (bitset(0200, mid)) 140120259Sgshapiro { 14164565Sgshapiro p += strlen(macname(mid)) + 2; 142120259Sgshapiro SM_ASSERT(p <= q); 143120259Sgshapiro } 14464565Sgshapiro else 14564565Sgshapiro p++; 14664565Sgshapiro 14764565Sgshapiro /* catch ?$abc? */ 14864565Sgshapiro if (*p != '\0') 14964565Sgshapiro { 15064565Sgshapiro *q = '?'; 15164565Sgshapiro goto hse; 15264565Sgshapiro } 15364565Sgshapiro } 15464565Sgshapiro else 15564565Sgshapiro { 15664565Sgshapiro while (*p != '\0') 15764565Sgshapiro { 15864565Sgshapiro if (!isascii(*p)) 15964565Sgshapiro { 16064565Sgshapiro *q = '?'; 16164565Sgshapiro goto hse; 16264565Sgshapiro } 16364565Sgshapiro 16471348Sgshapiro setbitn(bitidx(*p), mopts); 16590795Sgshapiro cond = true; 16664565Sgshapiro p++; 16764565Sgshapiro } 16838032Speter } 16964565Sgshapiro p = q + 1; 17038032Speter } 17138032Speter 17238032Speter /* find canonical name */ 17338032Speter fname = p; 17438032Speter while (isascii(*p) && isgraph(*p) && *p != ':') 17538032Speter p++; 17638032Speter fvalue = p; 17738032Speter while (isascii(*p) && isspace(*p)) 17838032Speter p++; 17938032Speter if (*p++ != ':' || fname == fvalue) 18038032Speter { 18164565Sgshapirohse: 18264565Sgshapiro syserr("553 5.3.0 header syntax error, line \"%s\"", line); 18338032Speter return 0; 18438032Speter } 18538032Speter *fvalue = '\0'; 18643733Speter fvalue = p; 18738032Speter 18843733Speter /* if the field is null, go ahead and use the default */ 18943733Speter while (isascii(*p) && isspace(*p)) 19043733Speter p++; 19143733Speter if (*p == '\0') 19290795Sgshapiro nullheader = true; 19343733Speter 19438032Speter /* security scan: long field names are end-of-header */ 19538032Speter if (strlen(fname) > 100) 19638032Speter return H_EOH; 19738032Speter 19838032Speter /* check to see if it represents a ruleset call */ 19964565Sgshapiro if (bitset(pflag, CHHDR_DEF)) 20038032Speter { 20138032Speter char hbuf[50]; 20238032Speter 203168520Sgshapiro (void) expand(fvalue, hbuf, sizeof(hbuf), e); 20438032Speter for (p = hbuf; isascii(*p) && isspace(*p); ) 20538032Speter p++; 20638032Speter if ((*p++ & 0377) == CALLSUBR) 20738032Speter { 20838032Speter auto char *endp; 20964565Sgshapiro bool strc; 21038032Speter 21164565Sgshapiro strc = *p == '+'; /* strip comments? */ 21264565Sgshapiro if (strc) 21364565Sgshapiro ++p; 21438032Speter if (strtorwset(p, &endp, ST_ENTER) > 0) 21538032Speter { 21638032Speter *endp = '\0'; 21738032Speter s = stab(fname, ST_HEADER, ST_ENTER); 21890795Sgshapiro if (LogLevel > 9 && 21990795Sgshapiro s->s_header.hi_ruleset != NULL) 22090795Sgshapiro sm_syslog(LOG_WARNING, NOQID, 22190795Sgshapiro "Warning: redefined ruleset for header=%s, old=%s, new=%s", 22290795Sgshapiro fname, 22390795Sgshapiro s->s_header.hi_ruleset, p); 22438032Speter s->s_header.hi_ruleset = newstr(p); 22564565Sgshapiro if (!strc) 22664565Sgshapiro s->s_header.hi_flags |= H_STRIPCOMM; 22738032Speter } 22838032Speter return 0; 22938032Speter } 23038032Speter } 23138032Speter 23238032Speter /* see if it is a known type */ 23338032Speter s = stab(fname, ST_HEADER, ST_FIND); 23438032Speter if (s != NULL) 23538032Speter hi = &s->s_header; 23638032Speter else 23738032Speter hi = &NormalHeader; 23838032Speter 23938032Speter if (tTd(31, 9)) 24038032Speter { 24138032Speter if (s == NULL) 24290795Sgshapiro sm_dprintf("no header flags match\n"); 24338032Speter else 24490795Sgshapiro sm_dprintf("header match, flags=%lx, ruleset=%s\n", 24590795Sgshapiro hi->hi_flags, 24690795Sgshapiro hi->hi_ruleset == NULL ? "<NULL>" 24790795Sgshapiro : hi->hi_ruleset); 24838032Speter } 24938032Speter 25038032Speter /* see if this is a resent message */ 25164565Sgshapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 25264565Sgshapiro bitset(H_RESENT, hi->hi_flags)) 25338032Speter e->e_flags |= EF_RESENT; 25438032Speter 25538032Speter /* if this is an Errors-To: header keep track of it now */ 25664565Sgshapiro if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly && 25738032Speter bitset(H_ERRORSTO, hi->hi_flags)) 25838032Speter (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 25938032Speter 26038032Speter /* if this means "end of header" quit now */ 26138032Speter if (!headeronly && bitset(H_EOH, hi->hi_flags)) 26238032Speter return hi->hi_flags; 26338032Speter 26438032Speter /* 26538032Speter ** Horrible hack to work around problem with Lotus Notes SMTP 26638032Speter ** mail gateway, which generates From: headers with newlines in 26738032Speter ** them and the <address> on the second line. Although this is 26838032Speter ** legal RFC 822, many MUAs don't handle this properly and thus 26938032Speter ** never find the actual address. 27038032Speter */ 27138032Speter 27238032Speter if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader) 27338032Speter { 27438032Speter while ((p = strchr(fvalue, '\n')) != NULL) 27538032Speter *p = ' '; 27638032Speter } 27738032Speter 27838032Speter /* 27938032Speter ** If there is a check ruleset, verify it against the header. 28038032Speter */ 28138032Speter 28264565Sgshapiro if (bitset(pflag, CHHDR_CHECK)) 28364565Sgshapiro { 284102531Sgshapiro int rscheckflags; 28564565Sgshapiro char *rs; 28638032Speter 287102531Sgshapiro rscheckflags = RSF_COUNT; 288102531Sgshapiro if (!bitset(hi->hi_flags, H_FROM|H_RCPT)) 289102531Sgshapiro rscheckflags |= RSF_UNSTRUCTURED; 290132946Sgshapiro 291132946Sgshapiro /* no ruleset? look for default */ 292132946Sgshapiro rs = hi->hi_ruleset; 29364565Sgshapiro if (rs == NULL) 29464565Sgshapiro { 29564565Sgshapiro s = stab("*", ST_HEADER, ST_FIND); 29664565Sgshapiro if (s != NULL) 29764565Sgshapiro { 29864565Sgshapiro rs = (&s->s_header)->hi_ruleset; 299102531Sgshapiro if (bitset((&s->s_header)->hi_flags, 300102531Sgshapiro H_STRIPCOMM)) 301102531Sgshapiro rscheckflags |= RSF_RMCOMM; 30264565Sgshapiro } 30364565Sgshapiro } 304102531Sgshapiro else if (bitset(hi->hi_flags, H_STRIPCOMM)) 305102531Sgshapiro rscheckflags |= RSF_RMCOMM; 30664565Sgshapiro if (rs != NULL) 30764565Sgshapiro { 30890795Sgshapiro int l, k; 30964565Sgshapiro char qval[MAXNAME]; 31064565Sgshapiro 31164565Sgshapiro l = 0; 31290795Sgshapiro qval[l++] = '"'; 31390795Sgshapiro 31490795Sgshapiro /* - 3 to avoid problems with " at the end */ 315120259Sgshapiro /* should be sizeof(qval), not MAXNAME */ 31690795Sgshapiro for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++) 31764565Sgshapiro { 31890795Sgshapiro switch (fvalue[k]) 31964565Sgshapiro { 32090795Sgshapiro /* XXX other control chars? */ 32164565Sgshapiro case '\011': /* ht */ 32264565Sgshapiro case '\012': /* nl */ 32364565Sgshapiro case '\013': /* vt */ 32464565Sgshapiro case '\014': /* np */ 32564565Sgshapiro case '\015': /* cr */ 32690795Sgshapiro qval[l++] = ' '; 32764565Sgshapiro break; 32864565Sgshapiro case '"': 32990795Sgshapiro qval[l++] = '\\'; 33064565Sgshapiro /* FALLTHROUGH */ 33164565Sgshapiro default: 33290795Sgshapiro qval[l++] = fvalue[k]; 33364565Sgshapiro break; 33464565Sgshapiro } 33564565Sgshapiro } 33690795Sgshapiro qval[l++] = '"'; 33790795Sgshapiro qval[l] = '\0'; 33890795Sgshapiro k += strlen(fvalue + k); 33990795Sgshapiro if (k >= MAXNAME) 34064565Sgshapiro { 34164565Sgshapiro if (LogLevel > 9) 34264565Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 34364565Sgshapiro "Warning: truncated header '%s' before check with '%s' len=%d max=%d", 34490795Sgshapiro fname, rs, k, MAXNAME - 1); 34564565Sgshapiro } 34690795Sgshapiro macdefine(&e->e_macro, A_TEMP, 34790795Sgshapiro macid("{currHeader}"), qval); 34890795Sgshapiro macdefine(&e->e_macro, A_TEMP, 34990795Sgshapiro macid("{hdr_name}"), fname); 35090795Sgshapiro 351168520Sgshapiro (void) sm_snprintf(qval, sizeof(qval), "%d", k); 35290795Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval); 353132946Sgshapiro if (bitset(H_FROM, hi->hi_flags)) 35490795Sgshapiro macdefine(&e->e_macro, A_PERM, 35590795Sgshapiro macid("{addr_type}"), "h s"); 356132946Sgshapiro else if (bitset(H_RCPT, hi->hi_flags)) 35790795Sgshapiro macdefine(&e->e_macro, A_PERM, 35890795Sgshapiro macid("{addr_type}"), "h r"); 35990795Sgshapiro else 36090795Sgshapiro macdefine(&e->e_macro, A_PERM, 36190795Sgshapiro macid("{addr_type}"), "h"); 362102531Sgshapiro (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3, 363285303Sgshapiro NULL, e->e_id, NULL, NULL); 36464565Sgshapiro } 36564565Sgshapiro } 36664565Sgshapiro 36738032Speter /* 36838032Speter ** Drop explicit From: if same as what we would generate. 36938032Speter ** This is to make MH (which doesn't always give a full name) 37038032Speter ** insert the full name information in all circumstances. 37138032Speter */ 37238032Speter 37390795Sgshapiro dropfrom = false; 37438032Speter p = "resent-from"; 37538032Speter if (!bitset(EF_RESENT, e->e_flags)) 37638032Speter p += 7; 37764565Sgshapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 37890795Sgshapiro !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0) 37938032Speter { 38038032Speter if (e->e_from.q_paddr != NULL && 38164565Sgshapiro e->e_from.q_mailer != NULL && 38264565Sgshapiro bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && 38338032Speter (strcmp(fvalue, e->e_from.q_paddr) == 0 || 38438032Speter strcmp(fvalue, e->e_from.q_user) == 0)) 38590795Sgshapiro dropfrom = true; 386261363Sgshapiro if (tTd(31, 2)) 387261363Sgshapiro { 388261363Sgshapiro sm_dprintf("comparing header from (%s) against default (%s or %s), drop=%d\n", 389261363Sgshapiro fvalue, e->e_from.q_paddr, e->e_from.q_user, 390261363Sgshapiro dropfrom); 391261363Sgshapiro } 39238032Speter } 39338032Speter 39438032Speter /* delete default value for this header */ 39538032Speter for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 39638032Speter { 39790795Sgshapiro if (sm_strcasecmp(fname, h->h_field) == 0 && 39864565Sgshapiro !bitset(H_USER, h->h_flags) && 39938032Speter !bitset(H_FORCE, h->h_flags)) 40038032Speter { 40143733Speter if (nullheader) 40243733Speter { 40343733Speter /* user-supplied value was null */ 40443733Speter return 0; 40543733Speter } 40664565Sgshapiro if (dropfrom) 40764565Sgshapiro { 40864565Sgshapiro /* make this look like the user entered it */ 40964565Sgshapiro h->h_flags |= H_USER; 410261363Sgshapiro 411261363Sgshapiro /* 412261363Sgshapiro ** If the MH hack is selected, allow to turn 413261363Sgshapiro ** it off via a mailer flag to avoid problems 414261363Sgshapiro ** with setups that remove the F flag from 415261363Sgshapiro ** the RCPT mailer. 416261363Sgshapiro */ 417261363Sgshapiro 418285303Sgshapiro if (bitnset(M_NOMHHACK, 419261363Sgshapiro e->e_from.q_mailer->m_flags)) 420261363Sgshapiro { 421261363Sgshapiro h->h_flags &= ~H_CHECK; 422261363Sgshapiro } 42364565Sgshapiro return hi->hi_flags; 42464565Sgshapiro } 42538032Speter h->h_value = NULL; 42638032Speter if (!cond) 42738032Speter { 42838032Speter /* copy conditions from default case */ 42990795Sgshapiro memmove((char *) mopts, (char *) h->h_mflags, 430168520Sgshapiro sizeof(mopts)); 43138032Speter } 43264565Sgshapiro h->h_macro = mid; 43338032Speter } 43438032Speter } 43538032Speter 43638032Speter /* create a new node */ 437168520Sgshapiro h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof(*h)); 43890795Sgshapiro h->h_field = sm_rpool_strdup_x(e->e_rpool, fname); 43990795Sgshapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue); 44038032Speter h->h_link = NULL; 441168520Sgshapiro memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts)); 44264565Sgshapiro h->h_macro = mid; 44338032Speter *hp = h; 44438032Speter h->h_flags = hi->hi_flags; 44566497Sgshapiro if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE)) 44664565Sgshapiro h->h_flags |= H_USER; 44738032Speter 44838032Speter /* strip EOH flag if parsing MIME headers */ 44938032Speter if (headeronly) 45038032Speter h->h_flags &= ~H_EOH; 45164565Sgshapiro if (bitset(pflag, CHHDR_DEF)) 45238032Speter h->h_flags |= H_DEFAULT; 45364565Sgshapiro if (cond || mid != '\0') 45438032Speter h->h_flags |= H_CHECK; 45538032Speter 45638032Speter /* hack to see if this is a new format message */ 45764565Sgshapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 45864565Sgshapiro bitset(H_RCPT|H_FROM, h->h_flags) && 45938032Speter (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 46038032Speter strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 46138032Speter { 46238032Speter e->e_flags &= ~EF_OLDSTYLE; 46338032Speter } 46438032Speter 46538032Speter return h->h_flags; 46638032Speter} 467168520Sgshapiro 46890795Sgshapiro/* 469168520Sgshapiro** CHOMPHEADER -- process and save a header line. 470168520Sgshapiro** 471168520Sgshapiro** Called by collect, readcf, and readqf to deal with header lines. 472168520Sgshapiro** This is just a wrapper for dochompheader(). 473168520Sgshapiro** 474168520Sgshapiro** Parameters: 475168520Sgshapiro** line -- header as a text line. 476168520Sgshapiro** pflag -- flags for chompheader() (from sendmail.h) 477168520Sgshapiro** hdrp -- a pointer to the place to save the header. 478168520Sgshapiro** e -- the envelope including this header. 479168520Sgshapiro** 480168520Sgshapiro** Returns: 481168520Sgshapiro** flags for this header. 482168520Sgshapiro** 483168520Sgshapiro** Side Effects: 484168520Sgshapiro** The header is saved on the header list. 485168520Sgshapiro** Contents of 'line' are destroyed. 486168520Sgshapiro*/ 487168520Sgshapiro 488168520Sgshapiro 489168520Sgshapirounsigned long 490168520Sgshapirochompheader(line, pflag, hdrp, e) 491168520Sgshapiro char *line; 492168520Sgshapiro int pflag; 493168520Sgshapiro HDR **hdrp; 494168520Sgshapiro register ENVELOPE *e; 495168520Sgshapiro{ 496168520Sgshapiro unsigned long rval; 497168520Sgshapiro 498168520Sgshapiro if (tTd(31, 6)) 499168520Sgshapiro { 500168520Sgshapiro sm_dprintf("chompheader: "); 501168520Sgshapiro xputs(sm_debug_file(), line); 502168520Sgshapiro sm_dprintf("\n"); 503168520Sgshapiro } 504168520Sgshapiro 505168520Sgshapiro /* quote this if user (not config file) input */ 506168520Sgshapiro if (bitset(pflag, CHHDR_USER)) 507168520Sgshapiro { 508168520Sgshapiro char xbuf[MAXLINE]; 509168520Sgshapiro char *xbp = NULL; 510168520Sgshapiro int xbufs; 511168520Sgshapiro 512168520Sgshapiro xbufs = sizeof(xbuf); 513168520Sgshapiro xbp = quote_internal_chars(line, xbuf, &xbufs); 514168520Sgshapiro if (tTd(31, 7)) 515168520Sgshapiro { 516168520Sgshapiro sm_dprintf("chompheader: quoted: "); 517168520Sgshapiro xputs(sm_debug_file(), xbp); 518168520Sgshapiro sm_dprintf("\n"); 519168520Sgshapiro } 520168520Sgshapiro rval = dochompheader(xbp, pflag, hdrp, e); 521168520Sgshapiro if (xbp != xbuf) 522168520Sgshapiro sm_free(xbp); 523168520Sgshapiro } 524168520Sgshapiro else 525168520Sgshapiro rval = dochompheader(line, pflag, hdrp, e); 526168520Sgshapiro 527168520Sgshapiro return rval; 528168520Sgshapiro} 529168520Sgshapiro 530168520Sgshapiro/* 531132946Sgshapiro** ALLOCHEADER -- allocate a header entry 532132946Sgshapiro** 533132946Sgshapiro** Parameters: 534168520Sgshapiro** field -- the name of the header field (will not be copied). 535168520Sgshapiro** value -- the value of the field (will be copied). 536132946Sgshapiro** flags -- flags to add to h_flags. 537132946Sgshapiro** rp -- resource pool for allocations 538168520Sgshapiro** space -- add leading space? 539132946Sgshapiro** 540132946Sgshapiro** Returns: 541132946Sgshapiro** Pointer to a newly allocated and populated HDR. 542168520Sgshapiro** 543168520Sgshapiro** Notes: 544168520Sgshapiro** o field and value must be in internal format, i.e., 545168520Sgshapiro** metacharacters must be "quoted", see quote_internal_chars(). 546168520Sgshapiro** o maybe add more flags to decide: 547168520Sgshapiro** - what to copy (field/value) 548168520Sgshapiro** - whether to convert value to an internal format 549132946Sgshapiro*/ 550132946Sgshapiro 551132946Sgshapirostatic HDR * 552168520Sgshapiroallocheader(field, value, flags, rp, space) 553132946Sgshapiro char *field; 554132946Sgshapiro char *value; 555132946Sgshapiro int flags; 556132946Sgshapiro SM_RPOOL_T *rp; 557168520Sgshapiro bool space; 558132946Sgshapiro{ 559132946Sgshapiro HDR *h; 560132946Sgshapiro STAB *s; 561132946Sgshapiro 562132946Sgshapiro /* find info struct */ 563132946Sgshapiro s = stab(field, ST_HEADER, ST_FIND); 564132946Sgshapiro 565132946Sgshapiro /* allocate space for new header */ 566168520Sgshapiro h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h)); 567132946Sgshapiro h->h_field = field; 568168520Sgshapiro if (space) 569168520Sgshapiro { 570168520Sgshapiro size_t l; 571168520Sgshapiro char *n; 572168520Sgshapiro 573168520Sgshapiro l = strlen(value); 574168520Sgshapiro SM_ASSERT(l + 2 > l); 575168520Sgshapiro n = sm_rpool_malloc_x(rp, l + 2); 576168520Sgshapiro n[0] = ' '; 577168520Sgshapiro n[1] = '\0'; 578168520Sgshapiro sm_strlcpy(n + 1, value, l + 1); 579168520Sgshapiro h->h_value = n; 580168520Sgshapiro } 581168520Sgshapiro else 582168520Sgshapiro h->h_value = sm_rpool_strdup_x(rp, value); 583132946Sgshapiro h->h_flags = flags; 584132946Sgshapiro if (s != NULL) 585132946Sgshapiro h->h_flags |= s->s_header.hi_flags; 586132946Sgshapiro clrbitmap(h->h_mflags); 587132946Sgshapiro h->h_macro = '\0'; 588132946Sgshapiro 589132946Sgshapiro return h; 590132946Sgshapiro} 591168520Sgshapiro 592132946Sgshapiro/* 59338032Speter** ADDHEADER -- add a header entry to the end of the queue. 59438032Speter** 59538032Speter** This bypasses the special checking of chompheader. 59638032Speter** 59738032Speter** Parameters: 598168520Sgshapiro** field -- the name of the header field (will not be copied). 599168520Sgshapiro** value -- the value of the field (will be copied). 60064565Sgshapiro** flags -- flags to add to h_flags. 60190795Sgshapiro** e -- envelope. 602168520Sgshapiro** space -- add leading space? 60338032Speter** 60438032Speter** Returns: 60538032Speter** none. 60638032Speter** 60738032Speter** Side Effects: 60838032Speter** adds the field on the list of headers for this envelope. 609168520Sgshapiro** 610168520Sgshapiro** Notes: field and value must be in internal format, i.e., 611168520Sgshapiro** metacharacters must be "quoted", see quote_internal_chars(). 61238032Speter*/ 61338032Speter 61438032Spetervoid 615168520Sgshapiroaddheader(field, value, flags, e, space) 61638032Speter char *field; 61738032Speter char *value; 61864565Sgshapiro int flags; 61990795Sgshapiro ENVELOPE *e; 620168520Sgshapiro bool space; 62138032Speter{ 62238032Speter register HDR *h; 62338032Speter HDR **hp; 62490795Sgshapiro HDR **hdrlist = &e->e_header; 62538032Speter 62638032Speter /* find current place in list -- keep back pointer? */ 62738032Speter for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 62838032Speter { 62990795Sgshapiro if (sm_strcasecmp(field, h->h_field) == 0) 63038032Speter break; 63138032Speter } 63238032Speter 63338032Speter /* allocate space for new header */ 634168520Sgshapiro h = allocheader(field, value, flags, e->e_rpool, space); 63538032Speter h->h_link = *hp; 63638032Speter *hp = h; 63738032Speter} 638168520Sgshapiro 63990795Sgshapiro/* 640132946Sgshapiro** INSHEADER -- insert a header entry at the specified index 641132946Sgshapiro** This bypasses the special checking of chompheader. 642132946Sgshapiro** 643132946Sgshapiro** Parameters: 644132946Sgshapiro** idx -- index into the header list at which to insert 645168520Sgshapiro** field -- the name of the header field (will be copied). 646168520Sgshapiro** value -- the value of the field (will be copied). 647132946Sgshapiro** flags -- flags to add to h_flags. 648132946Sgshapiro** e -- envelope. 649168520Sgshapiro** space -- add leading space? 650132946Sgshapiro** 651132946Sgshapiro** Returns: 652132946Sgshapiro** none. 653132946Sgshapiro** 654132946Sgshapiro** Side Effects: 655132946Sgshapiro** inserts the field on the list of headers for this envelope. 656168520Sgshapiro** 657168520Sgshapiro** Notes: 658168520Sgshapiro** - field and value must be in internal format, i.e., 659168520Sgshapiro** metacharacters must be "quoted", see quote_internal_chars(). 660168520Sgshapiro** - the header list contains headers that might not be 661168520Sgshapiro** sent "out" (see putheader(): "skip"), hence there is no 662168520Sgshapiro** reliable way to insert a header at an exact position 663168520Sgshapiro** (except at the front or end). 664132946Sgshapiro*/ 665132946Sgshapiro 666132946Sgshapirovoid 667168520Sgshapiroinsheader(idx, field, value, flags, e, space) 668132946Sgshapiro int idx; 669132946Sgshapiro char *field; 670132946Sgshapiro char *value; 671132946Sgshapiro int flags; 672132946Sgshapiro ENVELOPE *e; 673168520Sgshapiro bool space; 674132946Sgshapiro{ 675132946Sgshapiro HDR *h, *srch, *last = NULL; 676132946Sgshapiro 677132946Sgshapiro /* allocate space for new header */ 678168520Sgshapiro h = allocheader(field, value, flags, e->e_rpool, space); 679132946Sgshapiro 680132946Sgshapiro /* find insertion position */ 681132946Sgshapiro for (srch = e->e_header; srch != NULL && idx > 0; 682132946Sgshapiro srch = srch->h_link, idx--) 683132946Sgshapiro last = srch; 684132946Sgshapiro 685132946Sgshapiro if (e->e_header == NULL) 686132946Sgshapiro { 687132946Sgshapiro e->e_header = h; 688132946Sgshapiro h->h_link = NULL; 689132946Sgshapiro } 690132946Sgshapiro else if (srch == NULL) 691132946Sgshapiro { 692132946Sgshapiro SM_ASSERT(last != NULL); 693132946Sgshapiro last->h_link = h; 694132946Sgshapiro h->h_link = NULL; 695132946Sgshapiro } 696132946Sgshapiro else 697132946Sgshapiro { 698132946Sgshapiro h->h_link = srch->h_link; 699132946Sgshapiro srch->h_link = h; 700132946Sgshapiro } 701132946Sgshapiro} 702168520Sgshapiro 703132946Sgshapiro/* 70438032Speter** HVALUE -- return value of a header. 70538032Speter** 70638032Speter** Only "real" fields (i.e., ones that have not been supplied 70738032Speter** as a default) are used. 70838032Speter** 70938032Speter** Parameters: 71038032Speter** field -- the field name. 71138032Speter** header -- the header list. 71238032Speter** 71338032Speter** Returns: 714168520Sgshapiro** pointer to the value part (internal format). 71538032Speter** NULL if not found. 71638032Speter** 71738032Speter** Side Effects: 71838032Speter** none. 71938032Speter*/ 72038032Speter 72138032Speterchar * 72238032Speterhvalue(field, header) 72338032Speter char *field; 72438032Speter HDR *header; 72538032Speter{ 72638032Speter register HDR *h; 72738032Speter 72838032Speter for (h = header; h != NULL; h = h->h_link) 72938032Speter { 73038032Speter if (!bitset(H_DEFAULT, h->h_flags) && 73190795Sgshapiro sm_strcasecmp(h->h_field, field) == 0) 732203004Sgshapiro { 733203004Sgshapiro char *s; 734203004Sgshapiro 735203004Sgshapiro s = h->h_value; 736203004Sgshapiro if (s == NULL) 737203004Sgshapiro return NULL; 738203004Sgshapiro while (isascii(*s) && isspace(*s)) 739203004Sgshapiro s++; 740203004Sgshapiro return s; 741203004Sgshapiro } 74238032Speter } 74364565Sgshapiro return NULL; 74438032Speter} 745168520Sgshapiro 74690795Sgshapiro/* 74738032Speter** ISHEADER -- predicate telling if argument is a header. 74838032Speter** 74938032Speter** A line is a header if it has a single word followed by 75038032Speter** optional white space followed by a colon. 75138032Speter** 75238032Speter** Header fields beginning with two dashes, although technically 75338032Speter** permitted by RFC822, are automatically rejected in order 75438032Speter** to make MIME work out. Without this we could have a technically 75538032Speter** legal header such as ``--"foo:bar"'' that would also be a legal 75638032Speter** MIME separator. 75738032Speter** 75838032Speter** Parameters: 75938032Speter** h -- string to check for possible headerness. 76038032Speter** 76138032Speter** Returns: 76290795Sgshapiro** true if h is a header. 76390795Sgshapiro** false otherwise. 76438032Speter** 76538032Speter** Side Effects: 76638032Speter** none. 76738032Speter*/ 76838032Speter 76938032Speterbool 77038032Speterisheader(h) 77138032Speter char *h; 77238032Speter{ 773168520Sgshapiro char *s; 77438032Speter 775168520Sgshapiro s = h; 77638032Speter if (s[0] == '-' && s[1] == '-') 77790795Sgshapiro return false; 77838032Speter 77938032Speter while (*s > ' ' && *s != ':' && *s != '\0') 78038032Speter s++; 78138032Speter 78238032Speter if (h == s) 78390795Sgshapiro return false; 78438032Speter 78538032Speter /* following technically violates RFC822 */ 78638032Speter while (isascii(*s) && isspace(*s)) 78738032Speter s++; 78838032Speter 78938032Speter return (*s == ':'); 79038032Speter} 791168520Sgshapiro 79290795Sgshapiro/* 79338032Speter** EATHEADER -- run through the stored header and extract info. 79438032Speter** 79538032Speter** Parameters: 79638032Speter** e -- the envelope to process. 79738032Speter** full -- if set, do full processing (e.g., compute 79838032Speter** message priority). This should not be set 79938032Speter** when reading a queue file because some info 80038032Speter** needed to compute the priority is wrong. 80190795Sgshapiro** log -- call logsender()? 80238032Speter** 80338032Speter** Returns: 80438032Speter** none. 80538032Speter** 80638032Speter** Side Effects: 80738032Speter** Sets a bunch of global variables from information 80838032Speter** in the collected header. 80938032Speter*/ 81038032Speter 81138032Spetervoid 81290795Sgshapiroeatheader(e, full, log) 81338032Speter register ENVELOPE *e; 81438032Speter bool full; 81590795Sgshapiro bool log; 81638032Speter{ 81738032Speter register HDR *h; 81838032Speter register char *p; 81938032Speter int hopcnt = 0; 82038032Speter char buf[MAXLINE]; 82138032Speter 82238032Speter /* 82338032Speter ** Set up macros for possible expansion in headers. 82438032Speter */ 82538032Speter 82690795Sgshapiro macdefine(&e->e_macro, A_PERM, 'f', e->e_sender); 82790795Sgshapiro macdefine(&e->e_macro, A_PERM, 'g', e->e_sender); 82838032Speter if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 82990795Sgshapiro macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt); 83038032Speter else 83190795Sgshapiro macdefine(&e->e_macro, A_PERM, 'u', NULL); 83238032Speter 83338032Speter /* full name of from person */ 83438032Speter p = hvalue("full-name", e->e_header); 83538032Speter if (p != NULL) 83638032Speter { 83738032Speter if (!rfc822_string(p)) 83838032Speter { 83938032Speter /* 84038032Speter ** Quote a full name with special characters 84138032Speter ** as a comment so crackaddr() doesn't destroy 84238032Speter ** the name portion of the address. 84338032Speter */ 84490795Sgshapiro 84590795Sgshapiro p = addquotes(p, e->e_rpool); 84638032Speter } 84790795Sgshapiro macdefine(&e->e_macro, A_PERM, 'x', p); 84838032Speter } 84938032Speter 85038032Speter if (tTd(32, 1)) 85190795Sgshapiro sm_dprintf("----- collected header -----\n"); 85290795Sgshapiro e->e_msgid = NULL; 85338032Speter for (h = e->e_header; h != NULL; h = h->h_link) 85438032Speter { 85538032Speter if (tTd(32, 1)) 856168520Sgshapiro sm_dprintf("%s:", h->h_field); 85738032Speter if (h->h_value == NULL) 85838032Speter { 85938032Speter if (tTd(32, 1)) 86090795Sgshapiro sm_dprintf("<NULL>\n"); 86138032Speter continue; 86238032Speter } 86338032Speter 86438032Speter /* do early binding */ 86564565Sgshapiro if (bitset(H_DEFAULT, h->h_flags) && 86664565Sgshapiro !bitset(H_BINDLATE, h->h_flags)) 86738032Speter { 86838032Speter if (tTd(32, 1)) 86938032Speter { 87090795Sgshapiro sm_dprintf("("); 871132946Sgshapiro xputs(sm_debug_file(), h->h_value); 87290795Sgshapiro sm_dprintf(") "); 87338032Speter } 874168520Sgshapiro expand(h->h_value, buf, sizeof(buf), e); 875168520Sgshapiro if (buf[0] != '\0' && 876168520Sgshapiro (buf[0] != ' ' || buf[1] != '\0')) 87738032Speter { 87838032Speter if (bitset(H_FROM, h->h_flags)) 879111826Sgshapiro expand(crackaddr(buf, e), 880168520Sgshapiro buf, sizeof(buf), e); 88190795Sgshapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, buf); 88238032Speter h->h_flags &= ~H_DEFAULT; 88338032Speter } 88438032Speter } 88538032Speter if (tTd(32, 1)) 88638032Speter { 887132946Sgshapiro xputs(sm_debug_file(), h->h_value); 88890795Sgshapiro sm_dprintf("\n"); 88938032Speter } 89038032Speter 89138032Speter /* count the number of times it has been processed */ 89238032Speter if (bitset(H_TRACE, h->h_flags)) 89338032Speter hopcnt++; 89438032Speter 89538032Speter /* send to this person if we so desire */ 89638032Speter if (GrabTo && bitset(H_RCPT, h->h_flags) && 89738032Speter !bitset(H_DEFAULT, h->h_flags) && 89890795Sgshapiro (!bitset(EF_RESENT, e->e_flags) || 89990795Sgshapiro bitset(H_RESENT, h->h_flags))) 90038032Speter { 90138032Speter#if 0 90238032Speter int saveflags = e->e_flags; 90364565Sgshapiro#endif /* 0 */ 90438032Speter 90590795Sgshapiro (void) sendtolist(denlstring(h->h_value, true, false), 90690795Sgshapiro NULLADDR, &e->e_sendqueue, 0, e); 90738032Speter 90838032Speter#if 0 90938032Speter /* 91042580Speter ** Change functionality so a fatal error on an 91142580Speter ** address doesn't affect the entire envelope. 91238032Speter */ 91364565Sgshapiro 91438032Speter /* delete fatal errors generated by this address */ 91538032Speter if (!bitset(EF_FATALERRS, saveflags)) 91638032Speter e->e_flags &= ~EF_FATALERRS; 91764565Sgshapiro#endif /* 0 */ 91838032Speter } 91938032Speter 92038032Speter /* save the message-id for logging */ 92138032Speter p = "resent-message-id"; 92238032Speter if (!bitset(EF_RESENT, e->e_flags)) 92338032Speter p += 7; 92490795Sgshapiro if (sm_strcasecmp(h->h_field, p) == 0) 92538032Speter { 92690795Sgshapiro e->e_msgid = h->h_value; 92790795Sgshapiro while (isascii(*e->e_msgid) && isspace(*e->e_msgid)) 92890795Sgshapiro e->e_msgid++; 929125823Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{msg_id}"), 930132946Sgshapiro e->e_msgid); 93138032Speter } 93238032Speter } 93338032Speter if (tTd(32, 1)) 93490795Sgshapiro sm_dprintf("----------------------------\n"); 93538032Speter 93638032Speter /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 93738032Speter if (OpMode == MD_VERIFY) 93838032Speter return; 93938032Speter 94038032Speter /* store hop count */ 94138032Speter if (hopcnt > e->e_hopcount) 94290795Sgshapiro { 94338032Speter e->e_hopcount = hopcnt; 944168520Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount); 94590795Sgshapiro macdefine(&e->e_macro, A_TEMP, 'c', buf); 94690795Sgshapiro } 94738032Speter 94838032Speter /* message priority */ 94938032Speter p = hvalue("precedence", e->e_header); 95038032Speter if (p != NULL) 95138032Speter e->e_class = priencode(p); 95238032Speter if (e->e_class < 0) 95338032Speter e->e_timeoutclass = TOC_NONURGENT; 95438032Speter else if (e->e_class > 0) 95538032Speter e->e_timeoutclass = TOC_URGENT; 95638032Speter if (full) 95738032Speter { 95838032Speter e->e_msgpriority = e->e_msgsize 95938032Speter - e->e_class * WkClassFact 96038032Speter + e->e_nrcpts * WkRecipFact; 96138032Speter } 96238032Speter 963132946Sgshapiro /* check for DSN to properly set e_timeoutclass */ 964132946Sgshapiro p = hvalue("content-type", e->e_header); 965132946Sgshapiro if (p != NULL) 966132946Sgshapiro { 967132946Sgshapiro bool oldsupr; 968132946Sgshapiro char **pvp; 969132946Sgshapiro char pvpbuf[MAXLINE]; 970132946Sgshapiro extern unsigned char MimeTokenTab[256]; 971132946Sgshapiro 972132946Sgshapiro /* tokenize header */ 973132946Sgshapiro oldsupr = SuprErrs; 974132946Sgshapiro SuprErrs = true; 975168520Sgshapiro pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL, 976132946Sgshapiro MimeTokenTab, false); 977132946Sgshapiro SuprErrs = oldsupr; 978132946Sgshapiro 979132946Sgshapiro /* Check if multipart/report */ 980132946Sgshapiro if (pvp != NULL && pvp[0] != NULL && 981132946Sgshapiro pvp[1] != NULL && pvp[2] != NULL && 982132946Sgshapiro sm_strcasecmp(*pvp++, "multipart") == 0 && 983132946Sgshapiro strcmp(*pvp++, "/") == 0 && 984132946Sgshapiro sm_strcasecmp(*pvp++, "report") == 0) 985132946Sgshapiro { 986132946Sgshapiro /* Look for report-type=delivery-status */ 987132946Sgshapiro while (*pvp != NULL) 988132946Sgshapiro { 989132946Sgshapiro /* skip to semicolon separator */ 990132946Sgshapiro while (*pvp != NULL && strcmp(*pvp, ";") != 0) 991132946Sgshapiro pvp++; 992132946Sgshapiro 993132946Sgshapiro /* skip semicolon */ 994132946Sgshapiro if (*pvp++ == NULL || *pvp == NULL) 995132946Sgshapiro break; 996132946Sgshapiro 997132946Sgshapiro /* look for report-type */ 998132946Sgshapiro if (sm_strcasecmp(*pvp++, "report-type") != 0) 999132946Sgshapiro continue; 1000132946Sgshapiro 1001132946Sgshapiro /* skip equal */ 1002132946Sgshapiro if (*pvp == NULL || strcmp(*pvp, "=") != 0) 1003132946Sgshapiro continue; 1004132946Sgshapiro 1005132946Sgshapiro /* check value */ 1006132946Sgshapiro if (*++pvp != NULL && 1007132946Sgshapiro sm_strcasecmp(*pvp, 1008132946Sgshapiro "delivery-status") == 0) 1009132946Sgshapiro e->e_timeoutclass = TOC_DSN; 1010132946Sgshapiro 1011132946Sgshapiro /* found report-type, no need to continue */ 1012132946Sgshapiro break; 1013132946Sgshapiro } 1014132946Sgshapiro } 1015132946Sgshapiro } 1016132946Sgshapiro 101738032Speter /* message timeout priority */ 101838032Speter p = hvalue("priority", e->e_header); 101938032Speter if (p != NULL) 102038032Speter { 102138032Speter /* (this should be in the configuration file) */ 102290795Sgshapiro if (sm_strcasecmp(p, "urgent") == 0) 102338032Speter e->e_timeoutclass = TOC_URGENT; 102490795Sgshapiro else if (sm_strcasecmp(p, "normal") == 0) 102538032Speter e->e_timeoutclass = TOC_NORMAL; 102690795Sgshapiro else if (sm_strcasecmp(p, "non-urgent") == 0) 102738032Speter e->e_timeoutclass = TOC_NONURGENT; 1028125823Sgshapiro else if (bitset(EF_RESPONSE, e->e_flags)) 1029125823Sgshapiro e->e_timeoutclass = TOC_DSN; 103038032Speter } 1031125823Sgshapiro else if (bitset(EF_RESPONSE, e->e_flags)) 1032112813Sgshapiro e->e_timeoutclass = TOC_DSN; 1033112813Sgshapiro 103438032Speter /* date message originated */ 103538032Speter p = hvalue("posted-date", e->e_header); 103638032Speter if (p == NULL) 103738032Speter p = hvalue("date", e->e_header); 103838032Speter if (p != NULL) 103990795Sgshapiro macdefine(&e->e_macro, A_PERM, 'a', p); 104038032Speter 104138032Speter /* check to see if this is a MIME message */ 104238032Speter if ((e->e_bodytype != NULL && 104390795Sgshapiro sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 104438032Speter hvalue("MIME-Version", e->e_header) != NULL) 104538032Speter { 104638032Speter e->e_flags |= EF_IS_MIME; 104738032Speter if (HasEightBits) 104838032Speter e->e_bodytype = "8BITMIME"; 104938032Speter } 105038032Speter else if ((p = hvalue("Content-Type", e->e_header)) != NULL) 105138032Speter { 105238032Speter /* this may be an RFC 1049 message */ 105338032Speter p = strpbrk(p, ";/"); 105438032Speter if (p == NULL || *p == ';') 105538032Speter { 105638032Speter /* yep, it is */ 105738032Speter e->e_flags |= EF_DONT_MIME; 105838032Speter } 105938032Speter } 106038032Speter 106138032Speter /* 106238032Speter ** From person in antiquated ARPANET mode 106338032Speter ** required by UK Grey Book e-mail gateways (sigh) 106438032Speter */ 106538032Speter 106638032Speter if (OpMode == MD_ARPAFTP) 106738032Speter { 106838032Speter register struct hdrinfo *hi; 106938032Speter 107038032Speter for (hi = HdrInfo; hi->hi_field != NULL; hi++) 107138032Speter { 107238032Speter if (bitset(H_FROM, hi->hi_flags) && 107338032Speter (!bitset(H_RESENT, hi->hi_flags) || 107438032Speter bitset(EF_RESENT, e->e_flags)) && 107538032Speter (p = hvalue(hi->hi_field, e->e_header)) != NULL) 107638032Speter break; 107738032Speter } 107838032Speter if (hi->hi_field != NULL) 107938032Speter { 108038032Speter if (tTd(32, 2)) 108190795Sgshapiro sm_dprintf("eatheader: setsender(*%s == %s)\n", 108238032Speter hi->hi_field, p); 108390795Sgshapiro setsender(p, e, NULL, '\0', true); 108438032Speter } 108538032Speter } 108638032Speter 108738032Speter /* 108838032Speter ** Log collection information. 108938032Speter */ 109038032Speter 1091203004Sgshapiro if (tTd(92, 2)) 1092203004Sgshapiro sm_dprintf("eatheader: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d, log=%d\n", 1093203004Sgshapiro e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel, 1094203004Sgshapiro log); 109590795Sgshapiro if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 109690795Sgshapiro { 109790795Sgshapiro logsender(e, e->e_msgid); 109890795Sgshapiro e->e_flags &= ~EF_LOGSENDER; 109990795Sgshapiro } 110038032Speter} 1101168520Sgshapiro 110290795Sgshapiro/* 110338032Speter** LOGSENDER -- log sender information 110438032Speter** 110538032Speter** Parameters: 110638032Speter** e -- the envelope to log 110738032Speter** msgid -- the message id 110838032Speter** 110938032Speter** Returns: 111038032Speter** none 111138032Speter*/ 111238032Speter 111338032Spetervoid 111438032Speterlogsender(e, msgid) 111538032Speter register ENVELOPE *e; 111638032Speter char *msgid; 111738032Speter{ 111838032Speter char *name; 111938032Speter register char *sbp; 112038032Speter register char *p; 112138032Speter char hbuf[MAXNAME + 1]; 112238032Speter char sbuf[MAXLINE + 1]; 112338032Speter char mbuf[MAXNAME + 1]; 112438032Speter 112538032Speter /* don't allow newlines in the message-id */ 112690795Sgshapiro /* XXX do we still need this? sm_syslog() replaces control chars */ 112738032Speter if (msgid != NULL) 112838032Speter { 1129157006Sgshapiro size_t l; 1130157006Sgshapiro 113138032Speter l = strlen(msgid); 1132168520Sgshapiro if (l > sizeof(mbuf) - 1) 1133168520Sgshapiro l = sizeof(mbuf) - 1; 113464565Sgshapiro memmove(mbuf, msgid, l); 113538032Speter mbuf[l] = '\0'; 113638032Speter p = mbuf; 113738032Speter while ((p = strchr(p, '\n')) != NULL) 113838032Speter *p++ = ' '; 113938032Speter } 114038032Speter 114138032Speter if (bitset(EF_RESPONSE, e->e_flags)) 114238032Speter name = "[RESPONSE]"; 114338032Speter else if ((name = macvalue('_', e)) != NULL) 114464565Sgshapiro /* EMPTY */ 114538032Speter ; 114638032Speter else if (RealHostName == NULL) 114738032Speter name = "localhost"; 114838032Speter else if (RealHostName[0] == '[') 114938032Speter name = RealHostName; 115038032Speter else 115138032Speter { 115238032Speter name = hbuf; 1153168520Sgshapiro (void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName); 115438032Speter if (RealHostAddr.sa.sa_family != 0) 115538032Speter { 115638032Speter p = &hbuf[strlen(hbuf)]; 115790795Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 115890795Sgshapiro " (%.100s)", 115990795Sgshapiro anynet_ntoa(&RealHostAddr)); 116038032Speter } 116138032Speter } 116238032Speter 116338032Speter /* some versions of syslog only take 5 printf args */ 116464565Sgshapiro#if (SYSLOG_BUFSIZE) >= 256 116538032Speter sbp = sbuf; 116690795Sgshapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 116790795Sgshapiro "from=%.200s, size=%ld, class=%d, nrcpts=%d", 116890795Sgshapiro e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 1169244833Sgshapiro PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 117038032Speter sbp += strlen(sbp); 117138032Speter if (msgid != NULL) 117238032Speter { 117390795Sgshapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 117490795Sgshapiro ", msgid=%.100s", mbuf); 117538032Speter sbp += strlen(sbp); 117638032Speter } 117738032Speter if (e->e_bodytype != NULL) 117838032Speter { 117990795Sgshapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 118090795Sgshapiro ", bodytype=%.20s", e->e_bodytype); 118138032Speter sbp += strlen(sbp); 118238032Speter } 118338032Speter p = macvalue('r', e); 118438032Speter if (p != NULL) 118564565Sgshapiro { 118690795Sgshapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 118790795Sgshapiro ", proto=%.20s", p); 118864565Sgshapiro sbp += strlen(sbp); 118964565Sgshapiro } 119090795Sgshapiro p = macvalue(macid("{daemon_name}"), e); 119164565Sgshapiro if (p != NULL) 119264565Sgshapiro { 119390795Sgshapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 119490795Sgshapiro ", daemon=%.20s", p); 119564565Sgshapiro sbp += strlen(sbp); 119664565Sgshapiro } 1197285303Sgshapiro# if _FFR_LOG_MORE1 1198285303Sgshapiro# if STARTTLS 1199285303Sgshapiro p = macvalue(macid("{verify}"), e); 1200285303Sgshapiro if (p == NULL || *p == '\0') 1201285303Sgshapiro p = "NONE"; 1202285303Sgshapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), ", tls_verify=%.20s", p); 1203285303Sgshapiro sbp += strlen(sbp); 1204285303Sgshapiro# endif /* STARTTLS */ 1205285303Sgshapiro# if SASL 1206285303Sgshapiro p = macvalue(macid("{auth_type}"), e); 1207285303Sgshapiro if (p == NULL || *p == '\0') 1208285303Sgshapiro p = "NONE"; 1209285303Sgshapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.20s", p); 1210285303Sgshapiro sbp += strlen(sbp); 1211285303Sgshapiro# endif /* SASL */ 1212285303Sgshapiro# endif /* _FFR_LOG_MORE1 */ 1213110563Sgshapiro sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name); 121438032Speter 121564565Sgshapiro#else /* (SYSLOG_BUFSIZE) >= 256 */ 121638032Speter 121738032Speter sm_syslog(LOG_INFO, e->e_id, 121864565Sgshapiro "from=%s", 121964565Sgshapiro e->e_from.q_paddr == NULL ? "<NONE>" 122090795Sgshapiro : shortenstring(e->e_from.q_paddr, 122190795Sgshapiro 83)); 122238032Speter sm_syslog(LOG_INFO, e->e_id, 122364565Sgshapiro "size=%ld, class=%ld, nrcpts=%d", 1224244833Sgshapiro PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 122538032Speter if (msgid != NULL) 122638032Speter sm_syslog(LOG_INFO, e->e_id, 122764565Sgshapiro "msgid=%s", 122864565Sgshapiro shortenstring(mbuf, 83)); 122938032Speter sbp = sbuf; 123038032Speter *sbp = '\0'; 123138032Speter if (e->e_bodytype != NULL) 123238032Speter { 123390795Sgshapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 123490795Sgshapiro "bodytype=%.20s, ", e->e_bodytype); 123538032Speter sbp += strlen(sbp); 123638032Speter } 123738032Speter p = macvalue('r', e); 123838032Speter if (p != NULL) 123938032Speter { 124090795Sgshapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 124190795Sgshapiro "proto=%.20s, ", p); 124238032Speter sbp += strlen(sbp); 124338032Speter } 124438032Speter sm_syslog(LOG_INFO, e->e_id, 1245110563Sgshapiro "%.400srelay=%s", sbuf, name); 124664565Sgshapiro#endif /* (SYSLOG_BUFSIZE) >= 256 */ 124738032Speter} 1248168520Sgshapiro 124990795Sgshapiro/* 125038032Speter** PRIENCODE -- encode external priority names into internal values. 125138032Speter** 125238032Speter** Parameters: 125338032Speter** p -- priority in ascii. 125438032Speter** 125538032Speter** Returns: 125638032Speter** priority as a numeric level. 125738032Speter** 125838032Speter** Side Effects: 125938032Speter** none. 126038032Speter*/ 126138032Speter 126264565Sgshapirostatic int 126338032Speterpriencode(p) 126438032Speter char *p; 126538032Speter{ 126638032Speter register int i; 126738032Speter 126838032Speter for (i = 0; i < NumPriorities; i++) 126938032Speter { 127090795Sgshapiro if (sm_strcasecmp(p, Priorities[i].pri_name) == 0) 127164565Sgshapiro return Priorities[i].pri_val; 127238032Speter } 127338032Speter 127438032Speter /* unknown priority */ 127564565Sgshapiro return 0; 127638032Speter} 1277168520Sgshapiro 127890795Sgshapiro/* 127938032Speter** CRACKADDR -- parse an address and turn it into a macro 128038032Speter** 128138032Speter** This doesn't actually parse the address -- it just extracts 128238032Speter** it and replaces it with "$g". The parse is totally ad hoc 128338032Speter** and isn't even guaranteed to leave something syntactically 128438032Speter** identical to what it started with. However, it does leave 1285111826Sgshapiro** something semantically identical if possible, else at least 1286111826Sgshapiro** syntactically correct. 128738032Speter** 1288111826Sgshapiro** For example, it changes "Real Name <real@example.com> (Comment)" 1289111826Sgshapiro** to "Real Name <$g> (Comment)". 1290111826Sgshapiro** 129138032Speter** This algorithm has been cleaned up to handle a wider range 129238032Speter** of cases -- notably quoted and backslash escaped strings. 129338032Speter** This modification makes it substantially better at preserving 129438032Speter** the original syntax. 129538032Speter** 129638032Speter** Parameters: 129738032Speter** addr -- the address to be cracked. 1298111826Sgshapiro** e -- the current envelope. 129938032Speter** 130038032Speter** Returns: 130138032Speter** a pointer to the new version. 130238032Speter** 130338032Speter** Side Effects: 130438032Speter** none. 130538032Speter** 130638032Speter** Warning: 130738032Speter** The return value is saved in local storage and should 130838032Speter** be copied if it is to be reused. 130938032Speter*/ 131038032Speter 1311111826Sgshapiro#define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend)) 1312111826Sgshapiro 1313111826Sgshapiro/* 1314111826Sgshapiro** Append a character to bp if we have room. 1315111826Sgshapiro** If not, punt and return $g. 1316111826Sgshapiro*/ 1317111826Sgshapiro 1318111826Sgshapiro#define SM_APPEND_CHAR(c) \ 1319111826Sgshapiro do \ 1320111826Sgshapiro { \ 1321111826Sgshapiro if (SM_HAVE_ROOM) \ 1322111826Sgshapiro *bp++ = (c); \ 1323111826Sgshapiro else \ 1324111826Sgshapiro goto returng; \ 1325111826Sgshapiro } while (0) 1326111826Sgshapiro 1327111826Sgshapiro#if MAXNAME < 10 1328111826SgshapiroERROR MAXNAME must be at least 10 1329111826Sgshapiro#endif /* MAXNAME < 10 */ 1330111826Sgshapiro 133138032Speterchar * 1332111826Sgshapirocrackaddr(addr, e) 133338032Speter register char *addr; 1334111826Sgshapiro ENVELOPE *e; 133538032Speter{ 133638032Speter register char *p; 133738032Speter register char c; 1338111826Sgshapiro int cmtlev; /* comment level in input string */ 1339111826Sgshapiro int realcmtlev; /* comment level in output string */ 1340111826Sgshapiro int anglelev; /* angle level in input string */ 1341111826Sgshapiro int copylev; /* 0 == in address, >0 copying */ 1342111826Sgshapiro int bracklev; /* bracket level for IPv6 addr check */ 1343111826Sgshapiro bool addangle; /* put closing angle in output */ 1344111826Sgshapiro bool qmode; /* quoting in original string? */ 1345111826Sgshapiro bool realqmode; /* quoting in output string? */ 1346111826Sgshapiro bool putgmac = false; /* already wrote $g */ 1347111826Sgshapiro bool quoteit = false; /* need to quote next character */ 1348111826Sgshapiro bool gotangle = false; /* found first '<' */ 1349111826Sgshapiro bool gotcolon = false; /* found a ':' */ 135038032Speter register char *bp; 135138032Speter char *buflim; 135238032Speter char *bufhead; 135338032Speter char *addrhead; 1354111826Sgshapiro char *bufend; 135538032Speter static char buf[MAXNAME + 1]; 135638032Speter 135738032Speter if (tTd(33, 1)) 135890795Sgshapiro sm_dprintf("crackaddr(%s)\n", addr); 135938032Speter 1360168520Sgshapiro buflim = bufend = &buf[sizeof(buf) - 1]; 1361168520Sgshapiro bp = bufhead = buf; 1362168520Sgshapiro 1363168520Sgshapiro /* skip over leading spaces but preserve them */ 136438032Speter while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 1365168520Sgshapiro { 1366168520Sgshapiro SM_APPEND_CHAR(*addr); 136738032Speter addr++; 1368168520Sgshapiro } 1369168520Sgshapiro bufhead = bp; 137038032Speter 137138032Speter /* 137238032Speter ** Start by assuming we have no angle brackets. This will be 137338032Speter ** adjusted later if we find them. 137438032Speter */ 137538032Speter 137638032Speter p = addrhead = addr; 1377111826Sgshapiro copylev = anglelev = cmtlev = realcmtlev = 0; 137838032Speter bracklev = 0; 1379111826Sgshapiro qmode = realqmode = addangle = false; 138038032Speter 138138032Speter while ((c = *p++) != '\0') 138238032Speter { 138338032Speter /* 1384111826Sgshapiro ** Try to keep legal syntax using spare buffer space 1385111826Sgshapiro ** (maintained by buflim). 138638032Speter */ 138738032Speter 1388111826Sgshapiro if (copylev > 0) 1389111826Sgshapiro SM_APPEND_CHAR(c); 139038032Speter 139138032Speter /* check for backslash escapes */ 139238032Speter if (c == '\\') 139338032Speter { 139438032Speter /* arrange to quote the address */ 139538032Speter if (cmtlev <= 0 && !qmode) 139690795Sgshapiro quoteit = true; 139738032Speter 139838032Speter if ((c = *p++) == '\0') 139938032Speter { 140038032Speter /* too far */ 140138032Speter p--; 140238032Speter goto putg; 140338032Speter } 1404111826Sgshapiro if (copylev > 0) 1405111826Sgshapiro SM_APPEND_CHAR(c); 140638032Speter goto putg; 140738032Speter } 140838032Speter 140938032Speter /* check for quoted strings */ 141038032Speter if (c == '"' && cmtlev <= 0) 141138032Speter { 141238032Speter qmode = !qmode; 1413111826Sgshapiro if (copylev > 0 && SM_HAVE_ROOM) 1414111826Sgshapiro { 1415111826Sgshapiro if (realqmode) 1416111826Sgshapiro buflim--; 1417111826Sgshapiro else 1418111826Sgshapiro buflim++; 141938032Speter realqmode = !realqmode; 1420111826Sgshapiro } 142138032Speter continue; 142238032Speter } 142338032Speter if (qmode) 142438032Speter goto putg; 142538032Speter 142638032Speter /* check for comments */ 142738032Speter if (c == '(') 142838032Speter { 142938032Speter cmtlev++; 143038032Speter 143138032Speter /* allow space for closing paren */ 1432111826Sgshapiro if (SM_HAVE_ROOM) 143338032Speter { 143438032Speter buflim--; 143538032Speter realcmtlev++; 143638032Speter if (copylev++ <= 0) 143738032Speter { 143838032Speter if (bp != bufhead) 1439111826Sgshapiro SM_APPEND_CHAR(' '); 1440111826Sgshapiro SM_APPEND_CHAR(c); 144138032Speter } 144238032Speter } 144338032Speter } 144438032Speter if (cmtlev > 0) 144538032Speter { 144638032Speter if (c == ')') 144738032Speter { 144838032Speter cmtlev--; 144938032Speter copylev--; 1450111826Sgshapiro if (SM_HAVE_ROOM) 145138032Speter { 145238032Speter realcmtlev--; 145338032Speter buflim++; 145438032Speter } 145538032Speter } 145638032Speter continue; 145738032Speter } 145838032Speter else if (c == ')') 145938032Speter { 146038032Speter /* syntax error: unmatched ) */ 1461120259Sgshapiro if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead) 146238032Speter bp--; 146338032Speter } 146438032Speter 146538032Speter /* count nesting on [ ... ] (for IPv6 domain literals) */ 146638032Speter if (c == '[') 146738032Speter bracklev++; 146838032Speter else if (c == ']') 146938032Speter bracklev--; 147038032Speter 147138032Speter /* check for group: list; syntax */ 147238032Speter if (c == ':' && anglelev <= 0 && bracklev <= 0 && 147338032Speter !gotcolon && !ColonOkInAddr) 147438032Speter { 147538032Speter register char *q; 147638032Speter 147738032Speter /* 147838032Speter ** Check for DECnet phase IV ``::'' (host::user) 1479111826Sgshapiro ** or DECnet phase V ``:.'' syntaxes. The latter 148038032Speter ** covers ``user@DEC:.tay.myhost'' and 148138032Speter ** ``DEC:.tay.myhost::user'' syntaxes (bletch). 148238032Speter */ 148338032Speter 148438032Speter if (*p == ':' || *p == '.') 148538032Speter { 148638032Speter if (cmtlev <= 0 && !qmode) 148790795Sgshapiro quoteit = true; 1488111826Sgshapiro if (copylev > 0) 148938032Speter { 1490111826Sgshapiro SM_APPEND_CHAR(c); 1491111826Sgshapiro SM_APPEND_CHAR(*p); 149238032Speter } 149338032Speter p++; 149438032Speter goto putg; 149538032Speter } 149638032Speter 149790795Sgshapiro gotcolon = true; 149838032Speter 149938032Speter bp = bufhead; 150038032Speter if (quoteit) 150138032Speter { 1502111826Sgshapiro SM_APPEND_CHAR('"'); 150338032Speter 150438032Speter /* back up over the ':' and any spaces */ 150538032Speter --p; 1506111826Sgshapiro while (p > addr && 1507111826Sgshapiro isascii(*--p) && isspace(*p)) 150838032Speter continue; 150938032Speter p++; 151038032Speter } 151138032Speter for (q = addrhead; q < p; ) 151238032Speter { 151338032Speter c = *q++; 1514111826Sgshapiro if (quoteit && c == '"') 1515111826Sgshapiro SM_APPEND_CHAR('\\'); 1516132946Sgshapiro SM_APPEND_CHAR(c); 151738032Speter } 151838032Speter if (quoteit) 151938032Speter { 152038032Speter if (bp == &bufhead[1]) 152138032Speter bp--; 152238032Speter else 1523111826Sgshapiro SM_APPEND_CHAR('"'); 152438032Speter while ((c = *p++) != ':') 1525111826Sgshapiro SM_APPEND_CHAR(c); 1526111826Sgshapiro SM_APPEND_CHAR(c); 152738032Speter } 152838032Speter 152938032Speter /* any trailing white space is part of group: */ 1530111826Sgshapiro while (isascii(*p) && isspace(*p)) 1531111826Sgshapiro { 1532111826Sgshapiro SM_APPEND_CHAR(*p); 1533111826Sgshapiro p++; 1534111826Sgshapiro } 153538032Speter copylev = 0; 153690795Sgshapiro putgmac = quoteit = false; 153738032Speter bufhead = bp; 153838032Speter addrhead = p; 153938032Speter continue; 154038032Speter } 154138032Speter 154238032Speter if (c == ';' && copylev <= 0 && !ColonOkInAddr) 1543111826Sgshapiro SM_APPEND_CHAR(c); 154438032Speter 154538032Speter /* check for characters that may have to be quoted */ 154638032Speter if (strchr(MustQuoteChars, c) != NULL) 154738032Speter { 154838032Speter /* 154938032Speter ** If these occur as the phrase part of a <> 155038032Speter ** construct, but are not inside of () or already 155138032Speter ** quoted, they will have to be quoted. Note that 155238032Speter ** now (but don't actually do the quoting). 155338032Speter */ 155438032Speter 155538032Speter if (cmtlev <= 0 && !qmode) 155690795Sgshapiro quoteit = true; 155738032Speter } 155838032Speter 155938032Speter /* check for angle brackets */ 156038032Speter if (c == '<') 156138032Speter { 156238032Speter register char *q; 156338032Speter 156438032Speter /* assume first of two angles is bogus */ 156538032Speter if (gotangle) 156690795Sgshapiro quoteit = true; 156790795Sgshapiro gotangle = true; 156838032Speter 156938032Speter /* oops -- have to change our mind */ 157038032Speter anglelev = 1; 1571111826Sgshapiro if (SM_HAVE_ROOM) 1572111826Sgshapiro { 1573111826Sgshapiro if (!addangle) 1574111826Sgshapiro buflim--; 1575111826Sgshapiro addangle = true; 1576111826Sgshapiro } 157738032Speter 157838032Speter bp = bufhead; 157938032Speter if (quoteit) 158038032Speter { 1581111826Sgshapiro SM_APPEND_CHAR('"'); 158238032Speter 158338032Speter /* back up over the '<' and any spaces */ 158438032Speter --p; 1585111826Sgshapiro while (p > addr && 1586111826Sgshapiro isascii(*--p) && isspace(*p)) 158738032Speter continue; 158838032Speter p++; 158938032Speter } 159038032Speter for (q = addrhead; q < p; ) 159138032Speter { 159238032Speter c = *q++; 1593111826Sgshapiro if (quoteit && c == '"') 159438032Speter { 1595111826Sgshapiro SM_APPEND_CHAR('\\'); 1596111826Sgshapiro SM_APPEND_CHAR(c); 159738032Speter } 1598111826Sgshapiro else 1599111826Sgshapiro SM_APPEND_CHAR(c); 160038032Speter } 160138032Speter if (quoteit) 160238032Speter { 160338032Speter if (bp == &buf[1]) 160438032Speter bp--; 160538032Speter else 1606111826Sgshapiro SM_APPEND_CHAR('"'); 160738032Speter while ((c = *p++) != '<') 1608111826Sgshapiro SM_APPEND_CHAR(c); 1609111826Sgshapiro SM_APPEND_CHAR(c); 161038032Speter } 161138032Speter copylev = 0; 161290795Sgshapiro putgmac = quoteit = false; 161338032Speter continue; 161438032Speter } 161538032Speter 161638032Speter if (c == '>') 161738032Speter { 161838032Speter if (anglelev > 0) 161938032Speter { 162038032Speter anglelev--; 1621111826Sgshapiro if (SM_HAVE_ROOM) 162238032Speter { 1623111826Sgshapiro if (addangle) 1624111826Sgshapiro buflim++; 1625111826Sgshapiro addangle = false; 162638032Speter } 162738032Speter } 1628111826Sgshapiro else if (SM_HAVE_ROOM) 162938032Speter { 163038032Speter /* syntax error: unmatched > */ 1631120259Sgshapiro if (copylev > 0 && bp > bufhead) 163238032Speter bp--; 163390795Sgshapiro quoteit = true; 163438032Speter continue; 163538032Speter } 163638032Speter if (copylev++ <= 0) 1637111826Sgshapiro SM_APPEND_CHAR(c); 163838032Speter continue; 163938032Speter } 164038032Speter 164138032Speter /* must be a real address character */ 164238032Speter putg: 164338032Speter if (copylev <= 0 && !putgmac) 164438032Speter { 1645111826Sgshapiro if (bp > buf && bp[-1] == ')') 1646111826Sgshapiro SM_APPEND_CHAR(' '); 1647111826Sgshapiro SM_APPEND_CHAR(MACROEXPAND); 1648111826Sgshapiro SM_APPEND_CHAR('g'); 164990795Sgshapiro putgmac = true; 165038032Speter } 165138032Speter } 165238032Speter 165338032Speter /* repair any syntactic damage */ 1654111826Sgshapiro if (realqmode && bp < bufend) 165538032Speter *bp++ = '"'; 1656111826Sgshapiro while (realcmtlev-- > 0 && bp < bufend) 165738032Speter *bp++ = ')'; 1658111826Sgshapiro if (addangle && bp < bufend) 165938032Speter *bp++ = '>'; 1660111826Sgshapiro *bp = '\0'; 1661111826Sgshapiro if (bp < bufend) 1662111826Sgshapiro goto success; 166338032Speter 1664111826Sgshapiro returng: 1665111826Sgshapiro /* String too long, punt */ 1666111826Sgshapiro buf[0] = '<'; 1667111826Sgshapiro buf[1] = MACROEXPAND; 1668111826Sgshapiro buf[2]= 'g'; 1669111826Sgshapiro buf[3] = '>'; 1670111826Sgshapiro buf[4]= '\0'; 1671111826Sgshapiro sm_syslog(LOG_ALERT, e->e_id, 1672111826Sgshapiro "Dropped invalid comments from header address"); 1673111826Sgshapiro 1674111826Sgshapiro success: 167538032Speter if (tTd(33, 1)) 167638032Speter { 167790795Sgshapiro sm_dprintf("crackaddr=>`"); 1678132946Sgshapiro xputs(sm_debug_file(), buf); 167990795Sgshapiro sm_dprintf("'\n"); 168038032Speter } 168164565Sgshapiro return buf; 168238032Speter} 1683168520Sgshapiro 168490795Sgshapiro/* 168538032Speter** PUTHEADER -- put the header part of a message from the in-core copy 168638032Speter** 168738032Speter** Parameters: 168838032Speter** mci -- the connection information. 168964565Sgshapiro** hdr -- the header to put. 169038032Speter** e -- envelope to use. 169143733Speter** flags -- MIME conversion flags. 169238032Speter** 169338032Speter** Returns: 1694159613Sgshapiro** true iff header part was written successfully 169538032Speter** 169638032Speter** Side Effects: 169738032Speter** none. 169838032Speter*/ 169938032Speter 1700157006Sgshapirobool 170143733Speterputheader(mci, hdr, e, flags) 170238032Speter register MCI *mci; 170338032Speter HDR *hdr; 170438032Speter register ENVELOPE *e; 170543733Speter int flags; 170638032Speter{ 170738032Speter register HDR *h; 170890795Sgshapiro char buf[SM_MAX(MAXLINE,BUFSIZ)]; 170938032Speter char obuf[MAXLINE]; 171038032Speter 171138032Speter if (tTd(34, 1)) 171290795Sgshapiro sm_dprintf("--- putheader, mailer = %s ---\n", 171338032Speter mci->mci_mailer->m_name); 171438032Speter 171538032Speter /* 171638032Speter ** If we're in MIME mode, we're not really in the header of the 171738032Speter ** message, just the header of one of the parts of the body of 171838032Speter ** the message. Therefore MCIF_INHEADER should not be turned on. 171938032Speter */ 172038032Speter 172138032Speter if (!bitset(MCIF_INMIME, mci->mci_flags)) 172238032Speter mci->mci_flags |= MCIF_INHEADER; 172338032Speter 172438032Speter for (h = hdr; h != NULL; h = h->h_link) 172538032Speter { 172638032Speter register char *p = h->h_value; 172790795Sgshapiro char *q; 172838032Speter 172938032Speter if (tTd(34, 11)) 173038032Speter { 1731168520Sgshapiro sm_dprintf(" %s:", h->h_field); 1732132946Sgshapiro xputs(sm_debug_file(), p); 173338032Speter } 173438032Speter 173564565Sgshapiro /* Skip empty headers */ 173664565Sgshapiro if (h->h_value == NULL) 173764565Sgshapiro continue; 173864565Sgshapiro 173942580Speter /* heuristic shortening of MIME fields to avoid MUA overflows */ 174042580Speter if (MaxMimeFieldLength > 0 && 174142580Speter wordinclass(h->h_field, 174290795Sgshapiro macid("{checkMIMEFieldHeaders}"))) 174342580Speter { 174471348Sgshapiro size_t len; 174571348Sgshapiro 1746111826Sgshapiro len = fix_mime_header(h, e); 174771348Sgshapiro if (len > 0) 174842580Speter { 174942580Speter sm_syslog(LOG_ALERT, e->e_id, 175071348Sgshapiro "Truncated MIME %s header due to field size (length = %ld) (possible attack)", 175171348Sgshapiro h->h_field, (unsigned long) len); 175242580Speter if (tTd(34, 11)) 175390795Sgshapiro sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", 175490795Sgshapiro h->h_field, 175590795Sgshapiro (unsigned long) len); 175642580Speter } 175742580Speter } 175842580Speter 175942580Speter if (MaxMimeHeaderLength > 0 && 176042580Speter wordinclass(h->h_field, 176190795Sgshapiro macid("{checkMIMETextHeaders}"))) 176242580Speter { 176371348Sgshapiro size_t len; 176471348Sgshapiro 176571348Sgshapiro len = strlen(h->h_value); 176671348Sgshapiro if (len > (size_t) MaxMimeHeaderLength) 176742580Speter { 176842580Speter h->h_value[MaxMimeHeaderLength - 1] = '\0'; 176942580Speter sm_syslog(LOG_ALERT, e->e_id, 177071348Sgshapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 177171348Sgshapiro h->h_field, (unsigned long) len); 177242580Speter if (tTd(34, 11)) 177390795Sgshapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 177490795Sgshapiro h->h_field, 177590795Sgshapiro (unsigned long) len); 177642580Speter } 177742580Speter } 177842580Speter 177942580Speter if (MaxMimeHeaderLength > 0 && 178042580Speter wordinclass(h->h_field, 178190795Sgshapiro macid("{checkMIMEHeaders}"))) 178242580Speter { 178371348Sgshapiro size_t len; 178471348Sgshapiro 178571348Sgshapiro len = strlen(h->h_value); 178671348Sgshapiro if (shorten_rfc822_string(h->h_value, 178771348Sgshapiro MaxMimeHeaderLength)) 178842580Speter { 1789111826Sgshapiro if (len < MaxMimeHeaderLength) 1790111826Sgshapiro { 1791111826Sgshapiro /* we only rebalanced a bogus header */ 1792111826Sgshapiro sm_syslog(LOG_ALERT, e->e_id, 1793111826Sgshapiro "Fixed MIME %s header (possible attack)", 1794111826Sgshapiro h->h_field); 1795111826Sgshapiro if (tTd(34, 11)) 1796111826Sgshapiro sm_dprintf(" fixed MIME %s header (possible attack)\n", 1797111826Sgshapiro h->h_field); 1798111826Sgshapiro } 1799111826Sgshapiro else 1800111826Sgshapiro { 1801111826Sgshapiro /* we actually shortened header */ 1802111826Sgshapiro sm_syslog(LOG_ALERT, e->e_id, 1803111826Sgshapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1804111826Sgshapiro h->h_field, 1805111826Sgshapiro (unsigned long) len); 1806111826Sgshapiro if (tTd(34, 11)) 1807111826Sgshapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1808111826Sgshapiro h->h_field, 1809111826Sgshapiro (unsigned long) len); 1810111826Sgshapiro } 181142580Speter } 181242580Speter } 181342580Speter 181443733Speter /* 181543733Speter ** Suppress Content-Transfer-Encoding: if we are MIMEing 181643733Speter ** and we are potentially converting from 8 bit to 7 bit 181743733Speter ** MIME. If converting, add a new CTE header in 181843733Speter ** mime8to7(). 181943733Speter */ 182090795Sgshapiro 182138032Speter if (bitset(H_CTE, h->h_flags) && 182243733Speter bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 182343733Speter mci->mci_flags) && 182443733Speter !bitset(M87F_NO8TO7, flags)) 182538032Speter { 182638032Speter if (tTd(34, 11)) 182790795Sgshapiro sm_dprintf(" (skipped (content-transfer-encoding))\n"); 182838032Speter continue; 182938032Speter } 183038032Speter 183138032Speter if (bitset(MCIF_INMIME, mci->mci_flags)) 183238032Speter { 183338032Speter if (tTd(34, 11)) 183490795Sgshapiro sm_dprintf("\n"); 1835157006Sgshapiro if (!put_vanilla_header(h, p, mci)) 1836157006Sgshapiro goto writeerr; 183738032Speter continue; 183838032Speter } 183938032Speter 184038032Speter if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 184164565Sgshapiro !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && 184264565Sgshapiro (h->h_macro == '\0' || 184390795Sgshapiro (q = macvalue(bitidx(h->h_macro), e)) == NULL || 184490795Sgshapiro *q == '\0')) 184538032Speter { 184638032Speter if (tTd(34, 11)) 184790795Sgshapiro sm_dprintf(" (skipped)\n"); 184838032Speter continue; 184938032Speter } 185038032Speter 185138032Speter /* handle Resent-... headers specially */ 185238032Speter if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 185338032Speter { 185438032Speter if (tTd(34, 11)) 185590795Sgshapiro sm_dprintf(" (skipped (resent))\n"); 185638032Speter continue; 185738032Speter } 185838032Speter 185938032Speter /* suppress return receipts if requested */ 186038032Speter if (bitset(H_RECEIPTTO, h->h_flags) && 186138032Speter (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) 186238032Speter { 186338032Speter if (tTd(34, 11)) 186490795Sgshapiro sm_dprintf(" (skipped (receipt))\n"); 186538032Speter continue; 186638032Speter } 186738032Speter 186838032Speter /* macro expand value if generated internally */ 186964565Sgshapiro if (bitset(H_DEFAULT, h->h_flags) || 187064565Sgshapiro bitset(H_BINDLATE, h->h_flags)) 187138032Speter { 1872168520Sgshapiro expand(p, buf, sizeof(buf), e); 187338032Speter p = buf; 187438032Speter if (*p == '\0') 187538032Speter { 187638032Speter if (tTd(34, 11)) 187790795Sgshapiro sm_dprintf(" (skipped -- null value)\n"); 187838032Speter continue; 187938032Speter } 188038032Speter } 188138032Speter 188238032Speter if (bitset(H_BCC, h->h_flags)) 188338032Speter { 188438032Speter /* Bcc: field -- either truncate or delete */ 188538032Speter if (bitset(EF_DELETE_BCC, e->e_flags)) 188638032Speter { 188738032Speter if (tTd(34, 11)) 188890795Sgshapiro sm_dprintf(" (skipped -- bcc)\n"); 188938032Speter } 189038032Speter else 189138032Speter { 189238032Speter /* no other recipient headers: truncate value */ 1893168520Sgshapiro (void) sm_strlcpyn(obuf, sizeof(obuf), 2, 189490795Sgshapiro h->h_field, ":"); 1895157006Sgshapiro if (!putline(obuf, mci)) 1896157006Sgshapiro goto writeerr; 189738032Speter } 189838032Speter continue; 189938032Speter } 190038032Speter 190138032Speter if (tTd(34, 11)) 190290795Sgshapiro sm_dprintf("\n"); 190338032Speter 190438032Speter if (bitset(H_FROM|H_RCPT, h->h_flags)) 190538032Speter { 190638032Speter /* address field */ 190738032Speter bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 190838032Speter 190938032Speter if (bitset(H_FROM, h->h_flags)) 191090795Sgshapiro oldstyle = false; 1911285303Sgshapiro if (!commaize(h, p, oldstyle, mci, e, 1912285303Sgshapiro PXLF_HEADER | PXLF_STRIPMQUOTE) 1913285303Sgshapiro && bitnset(M_xSMTP, mci->mci_mailer->m_flags)) 1914285303Sgshapiro goto writeerr; 191538032Speter } 191638032Speter else 191738032Speter { 1918157006Sgshapiro if (!put_vanilla_header(h, p, mci)) 1919157006Sgshapiro goto writeerr; 192038032Speter } 192138032Speter } 192238032Speter 192338032Speter /* 192438032Speter ** If we are converting this to a MIME message, add the 192564565Sgshapiro ** MIME headers (but not in MIME mode!). 192638032Speter */ 192738032Speter 192838032Speter#if MIME8TO7 192938032Speter if (bitset(MM_MIME8BIT, MimeMode) && 193038032Speter bitset(EF_HAS8BIT, e->e_flags) && 193138032Speter !bitset(EF_DONT_MIME, e->e_flags) && 193238032Speter !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 193364565Sgshapiro !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) && 193464565Sgshapiro hvalue("MIME-Version", e->e_header) == NULL) 193538032Speter { 1936157006Sgshapiro if (!putline("MIME-Version: 1.0", mci)) 1937157006Sgshapiro goto writeerr; 193838032Speter if (hvalue("Content-Type", e->e_header) == NULL) 193938032Speter { 1940168520Sgshapiro (void) sm_snprintf(obuf, sizeof(obuf), 194190795Sgshapiro "Content-Type: text/plain; charset=%s", 194290795Sgshapiro defcharset(e)); 1943157006Sgshapiro if (!putline(obuf, mci)) 1944157006Sgshapiro goto writeerr; 194538032Speter } 1946157006Sgshapiro if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL 1947157006Sgshapiro && !putline("Content-Transfer-Encoding: 8bit", mci)) 1948157006Sgshapiro goto writeerr; 194938032Speter } 195064565Sgshapiro#endif /* MIME8TO7 */ 1951157006Sgshapiro return true; 1952157006Sgshapiro 1953157006Sgshapiro writeerr: 1954157006Sgshapiro return false; 195538032Speter} 1956168520Sgshapiro 195790795Sgshapiro/* 195838032Speter** PUT_VANILLA_HEADER -- output a fairly ordinary header 195938032Speter** 196038032Speter** Parameters: 196138032Speter** h -- the structure describing this header 196238032Speter** v -- the value of this header 196338032Speter** mci -- the connection info for output 196438032Speter** 196538032Speter** Returns: 1966159613Sgshapiro** true iff header was written successfully 196738032Speter*/ 196838032Speter 1969157006Sgshapirostatic bool 197038032Speterput_vanilla_header(h, v, mci) 197138032Speter HDR *h; 197238032Speter char *v; 197338032Speter MCI *mci; 197438032Speter{ 197538032Speter register char *nlp; 197638032Speter register char *obp; 197738032Speter int putflags; 1978141862Sgshapiro char obuf[MAXLINE + 256]; /* additional length for h_field */ 197938032Speter 1980168520Sgshapiro putflags = PXLF_HEADER | PXLF_STRIPMQUOTE; 198138032Speter if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 198238032Speter putflags |= PXLF_STRIP8BIT; 1983168520Sgshapiro (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field); 198438032Speter obp = obuf + strlen(obuf); 198538032Speter while ((nlp = strchr(v, '\n')) != NULL) 198638032Speter { 198738032Speter int l; 198838032Speter 198938032Speter l = nlp - v; 1990120259Sgshapiro 1991120259Sgshapiro /* 1992120259Sgshapiro ** XXX This is broken for SPACELEFT()==0 1993120259Sgshapiro ** However, SPACELEFT() is always > 0 unless MAXLINE==1. 1994120259Sgshapiro */ 1995120259Sgshapiro 199690795Sgshapiro if (SPACELEFT(obuf, obp) - 1 < (size_t) l) 199738032Speter l = SPACELEFT(obuf, obp) - 1; 199838032Speter 199990795Sgshapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); 2000157006Sgshapiro if (!putxline(obuf, strlen(obuf), mci, putflags)) 2001157006Sgshapiro goto writeerr; 200238032Speter v += l + 1; 200338032Speter obp = obuf; 200438032Speter if (*v != ' ' && *v != '\t') 200538032Speter *obp++ = ' '; 200638032Speter } 2007120259Sgshapiro 2008120259Sgshapiro /* XXX This is broken for SPACELEFT()==0 */ 200990795Sgshapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", 201090795Sgshapiro (int) (SPACELEFT(obuf, obp) - 1), v); 2011157006Sgshapiro return putxline(obuf, strlen(obuf), mci, putflags); 2012157006Sgshapiro 2013157006Sgshapiro writeerr: 2014157006Sgshapiro return false; 201538032Speter} 2016168520Sgshapiro 201790795Sgshapiro/* 201838032Speter** COMMAIZE -- output a header field, making a comma-translated list. 201938032Speter** 202038032Speter** Parameters: 202138032Speter** h -- the header field to output. 202238032Speter** p -- the value to put in it. 202390795Sgshapiro** oldstyle -- true if this is an old style header. 202438032Speter** mci -- the connection information. 202538032Speter** e -- the envelope containing the message. 2026173343Sgshapiro** putflags -- flags for putxline() 202738032Speter** 202838032Speter** Returns: 2029159613Sgshapiro** true iff header field was written successfully 203038032Speter** 203138032Speter** Side Effects: 2032168520Sgshapiro** outputs "p" to "mci". 203338032Speter*/ 203438032Speter 2035157006Sgshapirobool 2036173343Sgshapirocommaize(h, p, oldstyle, mci, e, putflags) 203738032Speter register HDR *h; 203838032Speter register char *p; 203938032Speter bool oldstyle; 204038032Speter register MCI *mci; 204138032Speter register ENVELOPE *e; 2042173343Sgshapiro int putflags; 204338032Speter{ 204438032Speter register char *obp; 2045168520Sgshapiro int opos, omax, spaces; 204690795Sgshapiro bool firstone = true; 2047120259Sgshapiro char **res; 204838032Speter char obuf[MAXLINE + 3]; 204938032Speter 205038032Speter /* 205138032Speter ** Output the address list translated by the 205238032Speter ** mailer and with commas. 205338032Speter */ 205438032Speter 205538032Speter if (tTd(14, 2)) 2056168520Sgshapiro sm_dprintf("commaize(%s:%s)\n", h->h_field, p); 205738032Speter 205838032Speter if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 205938032Speter putflags |= PXLF_STRIP8BIT; 206038032Speter 206138032Speter obp = obuf; 2062168520Sgshapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field); 2063168520Sgshapiro /* opos = strlen(obp); instead of the next 3 lines? */ 2064168520Sgshapiro opos = strlen(h->h_field) + 1; 2065168520Sgshapiro if (opos > 201) 2066168520Sgshapiro opos = 201; 2067168520Sgshapiro obp += opos; 2068120259Sgshapiro 2069168520Sgshapiro spaces = 0; 2070168520Sgshapiro while (*p != '\0' && isascii(*p) && isspace(*p)) 2071168520Sgshapiro { 2072168520Sgshapiro ++spaces; 2073168520Sgshapiro ++p; 2074168520Sgshapiro } 2075168520Sgshapiro if (spaces > 0) 2076168520Sgshapiro { 2077168520Sgshapiro SM_ASSERT(sizeof(obuf) > opos * 2); 2078168520Sgshapiro 2079168520Sgshapiro /* 2080168520Sgshapiro ** Restrict number of spaces to half the length of buffer 2081168520Sgshapiro ** so the header field body can be put in here too. 2082168520Sgshapiro ** Note: this is a hack... 2083168520Sgshapiro */ 2084168520Sgshapiro 2085168520Sgshapiro if (spaces > sizeof(obuf) / 2) 2086168520Sgshapiro spaces = sizeof(obuf) / 2; 2087168520Sgshapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces, 2088168520Sgshapiro ""); 2089168520Sgshapiro opos += spaces; 2090168520Sgshapiro obp += spaces; 2091168520Sgshapiro SM_ASSERT(obp < &obuf[MAXLINE]); 2092168520Sgshapiro } 2093168520Sgshapiro 209438032Speter omax = mci->mci_mailer->m_linelimit - 2; 209538032Speter if (omax < 0 || omax > 78) 209638032Speter omax = 78; 209738032Speter 209838032Speter /* 209938032Speter ** Run through the list of values. 210038032Speter */ 210138032Speter 210238032Speter while (*p != '\0') 210338032Speter { 210438032Speter register char *name; 210538032Speter register int c; 210638032Speter char savechar; 210738032Speter int flags; 210864565Sgshapiro auto int status; 210938032Speter 211038032Speter /* 211138032Speter ** Find the end of the name. New style names 211238032Speter ** end with a comma, old style names end with 211338032Speter ** a space character. However, spaces do not 211438032Speter ** necessarily delimit an old-style name -- at 211538032Speter ** signs mean keep going. 211638032Speter */ 211738032Speter 211838032Speter /* find end of name */ 211938032Speter while ((isascii(*p) && isspace(*p)) || *p == ',') 212038032Speter p++; 212138032Speter name = p; 2122120259Sgshapiro res = NULL; 212338032Speter for (;;) 212438032Speter { 212538032Speter auto char *oldp; 212638032Speter char pvpbuf[PSBUFSIZE]; 212738032Speter 2128120259Sgshapiro res = prescan(p, oldstyle ? ' ' : ',', pvpbuf, 2129168520Sgshapiro sizeof(pvpbuf), &oldp, ExtTokenTab, false); 213038032Speter p = oldp; 2131120259Sgshapiro#if _FFR_IGNORE_BOGUS_ADDR 2132120259Sgshapiro /* ignore addresses that can't be parsed */ 2133120259Sgshapiro if (res == NULL) 2134120259Sgshapiro { 2135120259Sgshapiro name = p; 2136120259Sgshapiro continue; 2137120259Sgshapiro } 2138120259Sgshapiro#endif /* _FFR_IGNORE_BOGUS_ADDR */ 213938032Speter 214038032Speter /* look to see if we have an at sign */ 214138032Speter while (*p != '\0' && isascii(*p) && isspace(*p)) 214238032Speter p++; 214338032Speter 214438032Speter if (*p != '@') 214538032Speter { 214638032Speter p = oldp; 214738032Speter break; 214838032Speter } 214990795Sgshapiro ++p; 215038032Speter while (*p != '\0' && isascii(*p) && isspace(*p)) 215138032Speter p++; 215238032Speter } 215338032Speter /* at the end of one complete name */ 215438032Speter 215538032Speter /* strip off trailing white space */ 215638032Speter while (p >= name && 215738032Speter ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 215838032Speter p--; 215938032Speter if (++p == name) 216038032Speter continue; 2161120259Sgshapiro 2162120259Sgshapiro /* 2163120259Sgshapiro ** if prescan() failed go a bit backwards; this is a hack, 2164120259Sgshapiro ** there should be some better error recovery. 2165120259Sgshapiro */ 2166120259Sgshapiro 2167120259Sgshapiro if (res == NULL && p > name && 2168120259Sgshapiro !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 2169120259Sgshapiro --p; 217038032Speter savechar = *p; 217138032Speter *p = '\0'; 217238032Speter 217338032Speter /* translate the name to be relative */ 217438032Speter flags = RF_HEADERADDR|RF_ADDDOMAIN; 217538032Speter if (bitset(H_FROM, h->h_flags)) 217638032Speter flags |= RF_SENDERADDR; 217738032Speter#if USERDB 217838032Speter else if (e->e_from.q_mailer != NULL && 217938032Speter bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 218038032Speter { 218138032Speter char *q; 218238032Speter 218390795Sgshapiro q = udbsender(name, e->e_rpool); 218438032Speter if (q != NULL) 218538032Speter name = q; 218638032Speter } 218764565Sgshapiro#endif /* USERDB */ 218864565Sgshapiro status = EX_OK; 218964565Sgshapiro name = remotename(name, mci->mci_mailer, flags, &status, e); 2190285303Sgshapiro if (status != EX_OK && bitnset(M_xSMTP, mci->mci_mailer->m_flags)) 2191285303Sgshapiro { 2192285303Sgshapiro if (status == EX_TEMPFAIL) 2193285303Sgshapiro mci->mci_flags |= MCIF_NOTSTICKY; 2194285303Sgshapiro goto writeerr; 2195285303Sgshapiro } 219638032Speter if (*name == '\0') 219738032Speter { 219838032Speter *p = savechar; 219938032Speter continue; 220038032Speter } 220190795Sgshapiro name = denlstring(name, false, true); 220238032Speter 220338032Speter /* output the name with nice formatting */ 220438032Speter opos += strlen(name); 220538032Speter if (!firstone) 220638032Speter opos += 2; 220738032Speter if (opos > omax && !firstone) 220838032Speter { 220990795Sgshapiro (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp)); 2210157006Sgshapiro if (!putxline(obuf, strlen(obuf), mci, putflags)) 2211157006Sgshapiro goto writeerr; 221238032Speter obp = obuf; 2213168520Sgshapiro (void) sm_strlcpy(obp, " ", sizeof(obuf)); 221438032Speter opos = strlen(obp); 221538032Speter obp += opos; 221638032Speter opos += strlen(name); 221738032Speter } 221838032Speter else if (!firstone) 221938032Speter { 222090795Sgshapiro (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp)); 222138032Speter obp += 2; 222238032Speter } 222338032Speter 222438032Speter while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 222538032Speter *obp++ = c; 222690795Sgshapiro firstone = false; 222738032Speter *p = savechar; 222838032Speter } 2229168520Sgshapiro if (obp < &obuf[sizeof(obuf)]) 2230120259Sgshapiro *obp = '\0'; 2231120259Sgshapiro else 2232168520Sgshapiro obuf[sizeof(obuf) - 1] = '\0'; 2233157006Sgshapiro return putxline(obuf, strlen(obuf), mci, putflags); 2234157006Sgshapiro 2235157006Sgshapiro writeerr: 2236157006Sgshapiro return false; 223738032Speter} 2238157006Sgshapiro 223990795Sgshapiro/* 224038032Speter** COPYHEADER -- copy header list 224138032Speter** 224238032Speter** This routine is the equivalent of newstr for header lists 224338032Speter** 224438032Speter** Parameters: 224538032Speter** header -- list of header structures to copy. 224690795Sgshapiro** rpool -- resource pool, or NULL 224738032Speter** 224838032Speter** Returns: 224938032Speter** a copy of 'header'. 225038032Speter** 225138032Speter** Side Effects: 225238032Speter** none. 225338032Speter*/ 225438032Speter 225538032SpeterHDR * 225690795Sgshapirocopyheader(header, rpool) 225738032Speter register HDR *header; 225890795Sgshapiro SM_RPOOL_T *rpool; 225938032Speter{ 226038032Speter register HDR *newhdr; 226138032Speter HDR *ret; 226238032Speter register HDR **tail = &ret; 226338032Speter 226438032Speter while (header != NULL) 226538032Speter { 2266168520Sgshapiro newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr)); 226738032Speter STRUCTCOPY(*header, *newhdr); 226838032Speter *tail = newhdr; 226938032Speter tail = &newhdr->h_link; 227038032Speter header = header->h_link; 227138032Speter } 227238032Speter *tail = NULL; 227364565Sgshapiro 227438032Speter return ret; 227538032Speter} 2276168520Sgshapiro 227790795Sgshapiro/* 227842580Speter** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header 227942580Speter** 228042580Speter** Run through all of the parameters of a MIME header and 228142580Speter** possibly truncate and rebalance the parameter according 228242580Speter** to MaxMimeFieldLength. 228342580Speter** 228442580Speter** Parameters: 2285111826Sgshapiro** h -- the header to truncate/rebalance 2286111826Sgshapiro** e -- the current envelope 228742580Speter** 228842580Speter** Returns: 228971348Sgshapiro** length of last offending field, 0 if all ok. 229042580Speter** 229142580Speter** Side Effects: 229242580Speter** string modified in place 229342580Speter*/ 229442580Speter 229571348Sgshapirostatic size_t 2296111826Sgshapirofix_mime_header(h, e) 2297111826Sgshapiro HDR *h; 2298111826Sgshapiro ENVELOPE *e; 229942580Speter{ 2300111826Sgshapiro char *begin = h->h_value; 230142580Speter char *end; 230271348Sgshapiro size_t len = 0; 230371348Sgshapiro size_t retlen = 0; 230464565Sgshapiro 2305111826Sgshapiro if (begin == NULL || *begin == '\0') 230671348Sgshapiro return 0; 230764565Sgshapiro 230842580Speter /* Split on each ';' */ 2309120259Sgshapiro /* find_character() never returns NULL */ 231042580Speter while ((end = find_character(begin, ';')) != NULL) 231142580Speter { 231242580Speter char save = *end; 231342580Speter char *bp; 231464565Sgshapiro 231542580Speter *end = '\0'; 231664565Sgshapiro 231771348Sgshapiro len = strlen(begin); 231871348Sgshapiro 231942580Speter /* Shorten individual parameter */ 232042580Speter if (shorten_rfc822_string(begin, MaxMimeFieldLength)) 2321111826Sgshapiro { 2322111826Sgshapiro if (len < MaxMimeFieldLength) 2323111826Sgshapiro { 2324111826Sgshapiro /* we only rebalanced a bogus field */ 2325111826Sgshapiro sm_syslog(LOG_ALERT, e->e_id, 2326111826Sgshapiro "Fixed MIME %s header field (possible attack)", 2327111826Sgshapiro h->h_field); 2328111826Sgshapiro if (tTd(34, 11)) 2329111826Sgshapiro sm_dprintf(" fixed MIME %s header field (possible attack)\n", 2330111826Sgshapiro h->h_field); 2331111826Sgshapiro } 2332111826Sgshapiro else 2333111826Sgshapiro { 2334111826Sgshapiro /* we actually shortened the header */ 2335111826Sgshapiro retlen = len; 2336111826Sgshapiro } 2337111826Sgshapiro } 233864565Sgshapiro 233942580Speter /* Collapse the possibly shortened string with rest */ 234042580Speter bp = begin + strlen(begin); 234142580Speter if (bp != end) 234242580Speter { 234342580Speter char *ep = end; 234464565Sgshapiro 234542580Speter *end = save; 234642580Speter end = bp; 234764565Sgshapiro 234842580Speter /* copy character by character due to overlap */ 234942580Speter while (*ep != '\0') 235042580Speter *bp++ = *ep++; 235142580Speter *bp = '\0'; 235242580Speter } 235342580Speter else 235442580Speter *end = save; 235542580Speter if (*end == '\0') 235642580Speter break; 235764565Sgshapiro 235842580Speter /* Move past ';' */ 235942580Speter begin = end + 1; 236042580Speter } 236171348Sgshapiro return retlen; 236242580Speter} 2363