headers.c revision 266527
149909Smjacob/* 235388Smjacob * Copyright (c) 1998-2004, 2006, 2007 Proofpoint, Inc. and its suppliers. 335388Smjacob * All rights reserved. 435388Smjacob * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 535388Smjacob * Copyright (c) 1988, 1993 648484Smjacob * The Regents of the University of California. All rights reserved. 735388Smjacob * 835388Smjacob * By using this file, you agree to the terms and conditions set 935388Smjacob * forth in the LICENSE file which can be found at the top level of 1035388Smjacob * the sendmail distribution. 1135388Smjacob * 1235388Smjacob */ 1335388Smjacob 1435388Smjacob#include <sendmail.h> 1535388Smjacob#include <sm/sendmail.h> 1635388Smjacob 1735388SmjacobSM_RCSID("@(#)$Id: headers.c,v 8.320 2013-11-22 20:51:55 ca Exp $") 1835388Smjacob 1935388Smjacobstatic HDR *allocheader __P((char *, char *, int, SM_RPOOL_T *, bool)); 2035388Smjacobstatic size_t fix_mime_header __P((HDR *, ENVELOPE *)); 2135388Smjacobstatic int priencode __P((char *)); 2235388Smjacobstatic bool put_vanilla_header __P((HDR *, char *, MCI *)); 2335388Smjacob 2435388Smjacob/* 2535388Smjacob** SETUPHEADERS -- initialize headers in symbol table 2635388Smjacob** 2735388Smjacob** Parameters: 2835388Smjacob** none 2935388Smjacob** 3035388Smjacob** Returns: 3135388Smjacob** none 3235388Smjacob*/ 3335388Smjacob 3435388Smjacobvoid 3535388Smjacobsetupheaders() 3635388Smjacob{ 3735388Smjacob struct hdrinfo *hi; 3835388Smjacob STAB *s; 3944819Smjacob 4035388Smjacob for (hi = HdrInfo; hi->hi_field != NULL; hi++) 4135388Smjacob { 4235388Smjacob s = stab(hi->hi_field, ST_HEADER, ST_ENTER); 4335388Smjacob s->s_header.hi_flags = hi->hi_flags; 4435388Smjacob s->s_header.hi_ruleset = NULL; 4535388Smjacob } 4642131Smjacob} 4735388Smjacob 4835388Smjacob/* 4939235Sgibbs** DOCHOMPHEADER -- process and save a header line. 5048484Smjacob** 5139235Sgibbs** Called by chompheader. 5235388Smjacob** 5343420Smjacob** Parameters: 5435388Smjacob** line -- header as a text line. 5535388Smjacob** pflag -- flags for chompheader() (from sendmail.h) 5635388Smjacob** hdrp -- a pointer to the place to save the header. 5735388Smjacob** e -- the envelope including this header. 5835388Smjacob** 5935388Smjacob** Returns: 6035388Smjacob** flags for this header. 6135388Smjacob** 6235388Smjacob** Side Effects: 6335388Smjacob** The header is saved on the header list. 6435388Smjacob** Contents of 'line' are destroyed. 6535388Smjacob*/ 6635388Smjacob 6735388Smjacobstatic struct hdrinfo NormalHeader = { NULL, 0, NULL }; 6835388Smjacobstatic unsigned long dochompheader __P((char *, int, HDR **, ENVELOPE *)); 6935388Smjacob 7049909Smjacobstatic unsigned long 7135388Smjacobdochompheader(line, pflag, hdrp, e) 7235388Smjacob char *line; 7335388Smjacob int pflag; 7435388Smjacob HDR **hdrp; 7535388Smjacob ENVELOPE *e; 7635388Smjacob{ 7735388Smjacob unsigned char mid = '\0'; 7835388Smjacob register char *p; 7944819Smjacob register HDR *h; 8044819Smjacob HDR **hp; 8144819Smjacob char *fname; 8235388Smjacob char *fvalue; 8344819Smjacob bool cond = false; 8435388Smjacob bool dropfrom; 8549909Smjacob bool headeronly; 8649909Smjacob STAB *s; 8749909Smjacob struct hdrinfo *hi; 8849909Smjacob bool nullheader = false; 8949909Smjacob BITMAP256 mopts; 9049909Smjacob 9149909Smjacob headeronly = hdrp != NULL; 9249909Smjacob if (!headeronly) 9349909Smjacob hdrp = &e->e_header; 9449909Smjacob 9549909Smjacob /* strip off options */ 9639235Sgibbs clrbitmap(mopts); 9739235Sgibbs p = line; 9839235Sgibbs if (!bitset(pflag, CHHDR_USER) && *p == '?') 9944819Smjacob { 10039235Sgibbs int c; 10139235Sgibbs register char *q; 10239235Sgibbs 10339235Sgibbs q = strchr(++p, '?'); 10439235Sgibbs if (q == NULL) 10539235Sgibbs goto hse; 10635388Smjacob 10746968Smjacob *q = '\0'; 10835388Smjacob c = *p & 0377; 10935388Smjacob 11035388Smjacob /* possibly macro conditional */ 11146968Smjacob if (c == MACROEXPAND) 11246968Smjacob { 11335388Smjacob /* catch ?$? */ 11435388Smjacob if (*++p == '\0') 11535388Smjacob { 11642461Smjacob *q = '?'; 11743420Smjacob goto hse; 11835388Smjacob } 11945040Smjacob 12046968Smjacob mid = (unsigned char) *p++; 12135388Smjacob 12235388Smjacob /* catch ?$abc? */ 12335388Smjacob if (*p != '\0') 12435388Smjacob { 12535388Smjacob *q = '?'; 12635388Smjacob goto hse; 12735388Smjacob } 12835388Smjacob } 12935388Smjacob else if (*p == '$') 13046968Smjacob { 13146968Smjacob /* catch ?$? */ 13243420Smjacob if (*++p == '\0') 13343420Smjacob { 13445040Smjacob *q = '?'; 13545040Smjacob goto hse; 13645040Smjacob } 13745040Smjacob 13845040Smjacob mid = (unsigned char) macid(p); 13945040Smjacob if (bitset(0200, mid)) 14045040Smjacob { 14135388Smjacob p += strlen(macname(mid)) + 2; 14246968Smjacob SM_ASSERT(p <= q); 14335388Smjacob } 14435388Smjacob else 14535388Smjacob p++; 14635388Smjacob 14739235Sgibbs /* catch ?$abc? */ 14839235Sgibbs if (*p != '\0') 14939235Sgibbs { 15039235Sgibbs *q = '?'; 15139235Sgibbs goto hse; 15239235Sgibbs } 15339235Sgibbs } 15439235Sgibbs else 15539235Sgibbs { 15639235Sgibbs while (*p != '\0') 15743793Smjacob { 15839235Sgibbs if (!isascii(*p)) 15935388Smjacob { 16039235Sgibbs *q = '?'; 16145040Smjacob goto hse; 16245040Smjacob } 16335388Smjacob 16435388Smjacob setbitn(bitidx(*p), mopts); 16535388Smjacob cond = true; 16635388Smjacob p++; 16735388Smjacob } 16835388Smjacob } 16935388Smjacob p = q + 1; 17035388Smjacob } 17135388Smjacob 17235388Smjacob /* find canonical name */ 17348484Smjacob fname = p; 17448484Smjacob while (isascii(*p) && isgraph(*p) && *p != ':') 17548484Smjacob p++; 17648484Smjacob fvalue = p; 17748484Smjacob while (isascii(*p) && isspace(*p)) 17848484Smjacob p++; 17948484Smjacob if (*p++ != ':' || fname == fvalue) 18039235Sgibbs { 18139235Sgibbshse: 18248484Smjacob syserr("553 5.3.0 header syntax error, line \"%s\"", line); 18339235Sgibbs return 0; 18439235Sgibbs } 18535388Smjacob *fvalue = '\0'; 18639235Sgibbs fvalue = p; 18739235Sgibbs 18848484Smjacob /* if the field is null, go ahead and use the default */ 18948484Smjacob while (isascii(*p) && isspace(*p)) 19035388Smjacob p++; 19148484Smjacob if (*p == '\0') 19248484Smjacob nullheader = true; 19348484Smjacob 19448484Smjacob /* security scan: long field names are end-of-header */ 19548484Smjacob if (strlen(fname) > 100) 19648484Smjacob return H_EOH; 19748484Smjacob 19844819Smjacob /* check to see if it represents a ruleset call */ 19948484Smjacob if (bitset(pflag, CHHDR_DEF)) 20048484Smjacob { 20148484Smjacob char hbuf[50]; 20248484Smjacob 20348484Smjacob (void) expand(fvalue, hbuf, sizeof(hbuf), e); 20448484Smjacob for (p = hbuf; isascii(*p) && isspace(*p); ) 20548484Smjacob p++; 20648484Smjacob if ((*p++ & 0377) == CALLSUBR) 20748484Smjacob { 20848484Smjacob auto char *endp; 20948484Smjacob bool strc; 21044819Smjacob 21144819Smjacob strc = *p == '+'; /* strip comments? */ 21235388Smjacob if (strc) 21335388Smjacob ++p; 21448195Smjacob if (strtorwset(p, &endp, ST_ENTER) > 0) 21535388Smjacob { 21635388Smjacob *endp = '\0'; 21735388Smjacob s = stab(fname, ST_HEADER, ST_ENTER); 21848484Smjacob if (LogLevel > 9 && 21948484Smjacob s->s_header.hi_ruleset != NULL) 22048484Smjacob sm_syslog(LOG_WARNING, NOQID, 22148484Smjacob "Warning: redefined ruleset for header=%s, old=%s, new=%s", 22248484Smjacob fname, 22348484Smjacob s->s_header.hi_ruleset, p); 22448484Smjacob s->s_header.hi_ruleset = newstr(p); 22548484Smjacob if (!strc) 22635388Smjacob s->s_header.hi_flags |= H_STRIPCOMM; 22748484Smjacob } 22848484Smjacob return 0; 22948484Smjacob } 23048484Smjacob } 23135388Smjacob 23248484Smjacob /* see if it is a known type */ 23348484Smjacob s = stab(fname, ST_HEADER, ST_FIND); 23448484Smjacob if (s != NULL) 23548484Smjacob hi = &s->s_header; 23642131Smjacob else 23742131Smjacob hi = &NormalHeader; 23842131Smjacob 23942131Smjacob if (tTd(31, 9)) 24042131Smjacob { 24142131Smjacob if (s == NULL) 24242131Smjacob sm_dprintf("no header flags match\n"); 24342131Smjacob else 24442131Smjacob sm_dprintf("header match, flags=%lx, ruleset=%s\n", 24542131Smjacob hi->hi_flags, 24642131Smjacob hi->hi_ruleset == NULL ? "<NULL>" 24742131Smjacob : hi->hi_ruleset); 24842131Smjacob } 24942131Smjacob 25042131Smjacob /* see if this is a resent message */ 25142131Smjacob if (!bitset(pflag, CHHDR_DEF) && !headeronly && 25241519Smjacob bitset(H_RESENT, hi->hi_flags)) 25335388Smjacob e->e_flags |= EF_RESENT; 25442131Smjacob 25542131Smjacob /* if this is an Errors-To: header keep track of it now */ 25642131Smjacob if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly && 25742131Smjacob bitset(H_ERRORSTO, hi->hi_flags)) 25842131Smjacob (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 25942131Smjacob 26042131Smjacob /* if this means "end of header" quit now */ 26142131Smjacob if (!headeronly && bitset(H_EOH, hi->hi_flags)) 26242131Smjacob return hi->hi_flags; 26342131Smjacob 26442131Smjacob /* 26542131Smjacob ** Horrible hack to work around problem with Lotus Notes SMTP 26642131Smjacob ** mail gateway, which generates From: headers with newlines in 26742131Smjacob ** them and the <address> on the second line. Although this is 26842131Smjacob ** legal RFC 822, many MUAs don't handle this properly and thus 26942131Smjacob ** never find the actual address. 27042131Smjacob */ 27142131Smjacob 27242131Smjacob if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader) 27335388Smjacob { 27435388Smjacob while ((p = strchr(fvalue, '\n')) != NULL) 27535388Smjacob *p = ' '; 27635388Smjacob } 27735388Smjacob 27835388Smjacob /* 27935388Smjacob ** If there is a check ruleset, verify it against the header. 28035388Smjacob */ 28135388Smjacob 28235388Smjacob if (bitset(pflag, CHHDR_CHECK)) 28335388Smjacob { 28435388Smjacob int rscheckflags; 28535388Smjacob char *rs; 28635388Smjacob 28746968Smjacob rscheckflags = RSF_COUNT; 28835388Smjacob if (!bitset(hi->hi_flags, H_FROM|H_RCPT)) 28935388Smjacob rscheckflags |= RSF_UNSTRUCTURED; 29046968Smjacob 29139235Sgibbs /* no ruleset? look for default */ 29246968Smjacob rs = hi->hi_ruleset; 29346968Smjacob if (rs == NULL) 29444819Smjacob { 29539235Sgibbs s = stab("*", ST_HEADER, ST_FIND); 29635388Smjacob if (s != NULL) 29739235Sgibbs { 29839235Sgibbs rs = (&s->s_header)->hi_ruleset; 29935388Smjacob if (bitset((&s->s_header)->hi_flags, 30045282Smjacob H_STRIPCOMM)) 30145282Smjacob rscheckflags |= RSF_RMCOMM; 30239235Sgibbs } 30339235Sgibbs } 30435388Smjacob else if (bitset(hi->hi_flags, H_STRIPCOMM)) 30539235Sgibbs rscheckflags |= RSF_RMCOMM; 30635388Smjacob if (rs != NULL) 30735388Smjacob { 30839235Sgibbs int l, k; 30946968Smjacob char qval[MAXNAME]; 31039235Sgibbs 31146968Smjacob l = 0; 31246968Smjacob qval[l++] = '"'; 31346968Smjacob 31446968Smjacob /* - 3 to avoid problems with " at the end */ 31539235Sgibbs /* should be sizeof(qval), not MAXNAME */ 31635388Smjacob for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++) 31739235Sgibbs { 31835388Smjacob switch (fvalue[k]) 31939235Sgibbs { 32035388Smjacob /* XXX other control chars? */ 32135388Smjacob case '\011': /* ht */ 32239235Sgibbs case '\012': /* nl */ 32335388Smjacob case '\013': /* vt */ 32435388Smjacob case '\014': /* np */ 32535388Smjacob case '\015': /* cr */ 32635388Smjacob qval[l++] = ' '; 32735388Smjacob break; 32835388Smjacob case '"': 32935388Smjacob qval[l++] = '\\'; 33035388Smjacob /* FALLTHROUGH */ 33135388Smjacob default: 33235388Smjacob qval[l++] = fvalue[k]; 33343420Smjacob break; 33435388Smjacob } 33535388Smjacob } 33639235Sgibbs qval[l++] = '"'; 33735388Smjacob qval[l] = '\0'; 33848195Smjacob k += strlen(fvalue + k); 33948195Smjacob if (k >= MAXNAME) 34035388Smjacob { 34135388Smjacob if (LogLevel > 9) 34241519Smjacob sm_syslog(LOG_WARNING, e->e_id, 34342131Smjacob "Warning: truncated header '%s' before check with '%s' len=%d max=%d", 34442131Smjacob fname, rs, k, MAXNAME - 1); 34542131Smjacob } 34642131Smjacob macdefine(&e->e_macro, A_TEMP, 34742131Smjacob macid("{currHeader}"), qval); 34842131Smjacob macdefine(&e->e_macro, A_TEMP, 34942131Smjacob macid("{hdr_name}"), fname); 35042131Smjacob 35142131Smjacob (void) sm_snprintf(qval, sizeof(qval), "%d", k); 35242131Smjacob macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval); 35342131Smjacob if (bitset(H_FROM, hi->hi_flags)) 35442131Smjacob macdefine(&e->e_macro, A_PERM, 35542131Smjacob macid("{addr_type}"), "h s"); 35642131Smjacob else if (bitset(H_RCPT, hi->hi_flags)) 35742131Smjacob macdefine(&e->e_macro, A_PERM, 35842131Smjacob macid("{addr_type}"), "h r"); 35942131Smjacob else 36042131Smjacob macdefine(&e->e_macro, A_PERM, 36142131Smjacob macid("{addr_type}"), "h"); 36242131Smjacob (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3, 36342131Smjacob NULL, e->e_id, NULL); 36435388Smjacob } 36535388Smjacob } 36649909Smjacob 36749909Smjacob /* 36849909Smjacob ** Drop explicit From: if same as what we would generate. 36935388Smjacob ** This is to make MH (which doesn't always give a full name) 37035388Smjacob ** insert the full name information in all circumstances. 37135388Smjacob */ 37235388Smjacob 37335388Smjacob dropfrom = false; 37435388Smjacob p = "resent-from"; 37535388Smjacob if (!bitset(EF_RESENT, e->e_flags)) 37635388Smjacob p += 7; 37735388Smjacob if (!bitset(pflag, CHHDR_DEF) && !headeronly && 37835388Smjacob !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0) 37935388Smjacob { 38035388Smjacob if (e->e_from.q_paddr != NULL && 38143793Smjacob e->e_from.q_mailer != NULL && 38248484Smjacob bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && 38335388Smjacob (strcmp(fvalue, e->e_from.q_paddr) == 0 || 38445282Smjacob strcmp(fvalue, e->e_from.q_user) == 0)) 38546968Smjacob dropfrom = true; 38639235Sgibbs if (tTd(31, 2)) 38745282Smjacob { 38835388Smjacob sm_dprintf("comparing header from (%s) against default (%s or %s), drop=%d\n", 38939235Sgibbs fvalue, e->e_from.q_paddr, e->e_from.q_user, 39035388Smjacob dropfrom); 39139235Sgibbs } 39239235Sgibbs } 39339235Sgibbs 39439235Sgibbs /* delete default value for this header */ 39539235Sgibbs for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 39639235Sgibbs { 39735388Smjacob if (sm_strcasecmp(fname, h->h_field) == 0 && 39839235Sgibbs !bitset(H_USER, h->h_flags) && 39939235Sgibbs !bitset(H_FORCE, h->h_flags)) 40039235Sgibbs { 40139235Sgibbs if (nullheader) 40239235Sgibbs { 40339235Sgibbs /* user-supplied value was null */ 40445282Smjacob return 0; 40545040Smjacob } 40645040Smjacob if (dropfrom) 40735388Smjacob { 40835388Smjacob /* make this look like the user entered it */ 40948484Smjacob h->h_flags |= H_USER; 41035388Smjacob 41144819Smjacob /* 41244819Smjacob ** If the MH hack is selected, allow to turn 41345040Smjacob ** it off via a mailer flag to avoid problems 41444819Smjacob ** with setups that remove the F flag from 41544819Smjacob ** the RCPT mailer. 41635388Smjacob */ 41743420Smjacob 41835388Smjacob if (bitnset(M_NOMHHACK, 41935388Smjacob e->e_from.q_mailer->m_flags)) 42035388Smjacob { 42135388Smjacob h->h_flags &= ~H_CHECK; 42235388Smjacob } 42335388Smjacob return hi->hi_flags; 42435388Smjacob } 42535388Smjacob h->h_value = NULL; 42635388Smjacob if (!cond) 42735388Smjacob { 42835388Smjacob /* copy conditions from default case */ 42935388Smjacob memmove((char *) mopts, (char *) h->h_mflags, 43035388Smjacob sizeof(mopts)); 43135388Smjacob } 43235388Smjacob h->h_macro = mid; 43335388Smjacob } 43435388Smjacob } 43535388Smjacob 43635388Smjacob /* create a new node */ 43735388Smjacob h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof(*h)); 43835388Smjacob h->h_field = sm_rpool_strdup_x(e->e_rpool, fname); 43935388Smjacob h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue); 44035388Smjacob h->h_link = NULL; 44135388Smjacob memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts)); 44235388Smjacob h->h_macro = mid; 44335388Smjacob *hp = h; 44435388Smjacob h->h_flags = hi->hi_flags; 44535388Smjacob if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE)) 44635388Smjacob h->h_flags |= H_USER; 44735388Smjacob 44835388Smjacob /* strip EOH flag if parsing MIME headers */ 44935388Smjacob if (headeronly) 45035388Smjacob h->h_flags &= ~H_EOH; 45135388Smjacob if (bitset(pflag, CHHDR_DEF)) 45235388Smjacob h->h_flags |= H_DEFAULT; 45335388Smjacob if (cond || mid != '\0') 45439235Sgibbs h->h_flags |= H_CHECK; 45539235Sgibbs 45635388Smjacob /* hack to see if this is a new format message */ 45735388Smjacob if (!bitset(pflag, CHHDR_DEF) && !headeronly && 45835388Smjacob bitset(H_RCPT|H_FROM, h->h_flags) && 45935388Smjacob (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 46035388Smjacob strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 46135388Smjacob { 46235388Smjacob e->e_flags &= ~EF_OLDSTYLE; 46335388Smjacob } 46435388Smjacob 46539235Sgibbs return h->h_flags; 46639235Sgibbs} 46739235Sgibbs 46839235Sgibbs/* 46939235Sgibbs** CHOMPHEADER -- process and save a header line. 47035388Smjacob** 47135388Smjacob** Called by collect, readcf, and readqf to deal with header lines. 47235388Smjacob** This is just a wrapper for dochompheader(). 47335388Smjacob** 47435388Smjacob** Parameters: 47535388Smjacob** line -- header as a text line. 47635388Smjacob** pflag -- flags for chompheader() (from sendmail.h) 47739235Sgibbs** hdrp -- a pointer to the place to save the header. 47835388Smjacob** e -- the envelope including this header. 47939235Sgibbs** 48043420Smjacob** Returns: 48139235Sgibbs** flags for this header. 48248484Smjacob** 48339235Sgibbs** Side Effects: 48439235Sgibbs** The header is saved on the header list. 48539235Sgibbs** Contents of 'line' are destroyed. 48648484Smjacob*/ 48748484Smjacob 48848484Smjacob 48948484Smjacobunsigned long 49048484Smjacobchompheader(line, pflag, hdrp, e) 49139235Sgibbs char *line; 49239235Sgibbs int pflag; 49339235Sgibbs HDR **hdrp; 49443420Smjacob register ENVELOPE *e; 49539235Sgibbs{ 49643420Smjacob unsigned long rval; 49743420Smjacob 49843420Smjacob if (tTd(31, 6)) 49948484Smjacob { 50043420Smjacob sm_dprintf("chompheader: "); 50143420Smjacob xputs(sm_debug_file(), line); 50243420Smjacob sm_dprintf("\n"); 50343420Smjacob } 50443793Smjacob 50548484Smjacob /* quote this if user (not config file) input */ 50648484Smjacob if (bitset(pflag, CHHDR_USER)) 50748484Smjacob { 50848484Smjacob char xbuf[MAXLINE]; 50948484Smjacob char *xbp = NULL; 51048484Smjacob int xbufs; 51143420Smjacob 51243420Smjacob xbufs = sizeof(xbuf); 51343420Smjacob xbp = quote_internal_chars(line, xbuf, &xbufs); 51443420Smjacob if (tTd(31, 7)) 51539235Sgibbs { 51639235Sgibbs sm_dprintf("chompheader: quoted: "); 51739235Sgibbs xputs(sm_debug_file(), xbp); 51839235Sgibbs sm_dprintf("\n"); 51939235Sgibbs } 52035388Smjacob rval = dochompheader(xbp, pflag, hdrp, e); 521 if (xbp != xbuf) 522 sm_free(xbp); 523 } 524 else 525 rval = dochompheader(line, pflag, hdrp, e); 526 527 return rval; 528} 529 530/* 531** ALLOCHEADER -- allocate a header entry 532** 533** Parameters: 534** field -- the name of the header field (will not be copied). 535** value -- the value of the field (will be copied). 536** flags -- flags to add to h_flags. 537** rp -- resource pool for allocations 538** space -- add leading space? 539** 540** Returns: 541** Pointer to a newly allocated and populated HDR. 542** 543** Notes: 544** o field and value must be in internal format, i.e., 545** metacharacters must be "quoted", see quote_internal_chars(). 546** o maybe add more flags to decide: 547** - what to copy (field/value) 548** - whether to convert value to an internal format 549*/ 550 551static HDR * 552allocheader(field, value, flags, rp, space) 553 char *field; 554 char *value; 555 int flags; 556 SM_RPOOL_T *rp; 557 bool space; 558{ 559 HDR *h; 560 STAB *s; 561 562 /* find info struct */ 563 s = stab(field, ST_HEADER, ST_FIND); 564 565 /* allocate space for new header */ 566 h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h)); 567 h->h_field = field; 568 if (space) 569 { 570 size_t l; 571 char *n; 572 573 l = strlen(value); 574 SM_ASSERT(l + 2 > l); 575 n = sm_rpool_malloc_x(rp, l + 2); 576 n[0] = ' '; 577 n[1] = '\0'; 578 sm_strlcpy(n + 1, value, l + 1); 579 h->h_value = n; 580 } 581 else 582 h->h_value = sm_rpool_strdup_x(rp, value); 583 h->h_flags = flags; 584 if (s != NULL) 585 h->h_flags |= s->s_header.hi_flags; 586 clrbitmap(h->h_mflags); 587 h->h_macro = '\0'; 588 589 return h; 590} 591 592/* 593** ADDHEADER -- add a header entry to the end of the queue. 594** 595** This bypasses the special checking of chompheader. 596** 597** Parameters: 598** field -- the name of the header field (will not be copied). 599** value -- the value of the field (will be copied). 600** flags -- flags to add to h_flags. 601** e -- envelope. 602** space -- add leading space? 603** 604** Returns: 605** none. 606** 607** Side Effects: 608** adds the field on the list of headers for this envelope. 609** 610** Notes: field and value must be in internal format, i.e., 611** metacharacters must be "quoted", see quote_internal_chars(). 612*/ 613 614void 615addheader(field, value, flags, e, space) 616 char *field; 617 char *value; 618 int flags; 619 ENVELOPE *e; 620 bool space; 621{ 622 register HDR *h; 623 HDR **hp; 624 HDR **hdrlist = &e->e_header; 625 626 /* find current place in list -- keep back pointer? */ 627 for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 628 { 629 if (sm_strcasecmp(field, h->h_field) == 0) 630 break; 631 } 632 633 /* allocate space for new header */ 634 h = allocheader(field, value, flags, e->e_rpool, space); 635 h->h_link = *hp; 636 *hp = h; 637} 638 639/* 640** INSHEADER -- insert a header entry at the specified index 641** This bypasses the special checking of chompheader. 642** 643** Parameters: 644** idx -- index into the header list at which to insert 645** field -- the name of the header field (will be copied). 646** value -- the value of the field (will be copied). 647** flags -- flags to add to h_flags. 648** e -- envelope. 649** space -- add leading space? 650** 651** Returns: 652** none. 653** 654** Side Effects: 655** inserts the field on the list of headers for this envelope. 656** 657** Notes: 658** - field and value must be in internal format, i.e., 659** metacharacters must be "quoted", see quote_internal_chars(). 660** - the header list contains headers that might not be 661** sent "out" (see putheader(): "skip"), hence there is no 662** reliable way to insert a header at an exact position 663** (except at the front or end). 664*/ 665 666void 667insheader(idx, field, value, flags, e, space) 668 int idx; 669 char *field; 670 char *value; 671 int flags; 672 ENVELOPE *e; 673 bool space; 674{ 675 HDR *h, *srch, *last = NULL; 676 677 /* allocate space for new header */ 678 h = allocheader(field, value, flags, e->e_rpool, space); 679 680 /* find insertion position */ 681 for (srch = e->e_header; srch != NULL && idx > 0; 682 srch = srch->h_link, idx--) 683 last = srch; 684 685 if (e->e_header == NULL) 686 { 687 e->e_header = h; 688 h->h_link = NULL; 689 } 690 else if (srch == NULL) 691 { 692 SM_ASSERT(last != NULL); 693 last->h_link = h; 694 h->h_link = NULL; 695 } 696 else 697 { 698 h->h_link = srch->h_link; 699 srch->h_link = h; 700 } 701} 702 703/* 704** HVALUE -- return value of a header. 705** 706** Only "real" fields (i.e., ones that have not been supplied 707** as a default) are used. 708** 709** Parameters: 710** field -- the field name. 711** header -- the header list. 712** 713** Returns: 714** pointer to the value part (internal format). 715** NULL if not found. 716** 717** Side Effects: 718** none. 719*/ 720 721char * 722hvalue(field, header) 723 char *field; 724 HDR *header; 725{ 726 register HDR *h; 727 728 for (h = header; h != NULL; h = h->h_link) 729 { 730 if (!bitset(H_DEFAULT, h->h_flags) && 731 sm_strcasecmp(h->h_field, field) == 0) 732 { 733 char *s; 734 735 s = h->h_value; 736 if (s == NULL) 737 return NULL; 738 while (isascii(*s) && isspace(*s)) 739 s++; 740 return s; 741 } 742 } 743 return NULL; 744} 745 746/* 747** ISHEADER -- predicate telling if argument is a header. 748** 749** A line is a header if it has a single word followed by 750** optional white space followed by a colon. 751** 752** Header fields beginning with two dashes, although technically 753** permitted by RFC822, are automatically rejected in order 754** to make MIME work out. Without this we could have a technically 755** legal header such as ``--"foo:bar"'' that would also be a legal 756** MIME separator. 757** 758** Parameters: 759** h -- string to check for possible headerness. 760** 761** Returns: 762** true if h is a header. 763** false otherwise. 764** 765** Side Effects: 766** none. 767*/ 768 769bool 770isheader(h) 771 char *h; 772{ 773 char *s; 774 775 s = h; 776 if (s[0] == '-' && s[1] == '-') 777 return false; 778 779 while (*s > ' ' && *s != ':' && *s != '\0') 780 s++; 781 782 if (h == s) 783 return false; 784 785 /* following technically violates RFC822 */ 786 while (isascii(*s) && isspace(*s)) 787 s++; 788 789 return (*s == ':'); 790} 791 792/* 793** EATHEADER -- run through the stored header and extract info. 794** 795** Parameters: 796** e -- the envelope to process. 797** full -- if set, do full processing (e.g., compute 798** message priority). This should not be set 799** when reading a queue file because some info 800** needed to compute the priority is wrong. 801** log -- call logsender()? 802** 803** Returns: 804** none. 805** 806** Side Effects: 807** Sets a bunch of global variables from information 808** in the collected header. 809*/ 810 811void 812eatheader(e, full, log) 813 register ENVELOPE *e; 814 bool full; 815 bool log; 816{ 817 register HDR *h; 818 register char *p; 819 int hopcnt = 0; 820 char buf[MAXLINE]; 821 822 /* 823 ** Set up macros for possible expansion in headers. 824 */ 825 826 macdefine(&e->e_macro, A_PERM, 'f', e->e_sender); 827 macdefine(&e->e_macro, A_PERM, 'g', e->e_sender); 828 if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 829 macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt); 830 else 831 macdefine(&e->e_macro, A_PERM, 'u', NULL); 832 833 /* full name of from person */ 834 p = hvalue("full-name", e->e_header); 835 if (p != NULL) 836 { 837 if (!rfc822_string(p)) 838 { 839 /* 840 ** Quote a full name with special characters 841 ** as a comment so crackaddr() doesn't destroy 842 ** the name portion of the address. 843 */ 844 845 p = addquotes(p, e->e_rpool); 846 } 847 macdefine(&e->e_macro, A_PERM, 'x', p); 848 } 849 850 if (tTd(32, 1)) 851 sm_dprintf("----- collected header -----\n"); 852 e->e_msgid = NULL; 853 for (h = e->e_header; h != NULL; h = h->h_link) 854 { 855 if (tTd(32, 1)) 856 sm_dprintf("%s:", h->h_field); 857 if (h->h_value == NULL) 858 { 859 if (tTd(32, 1)) 860 sm_dprintf("<NULL>\n"); 861 continue; 862 } 863 864 /* do early binding */ 865 if (bitset(H_DEFAULT, h->h_flags) && 866 !bitset(H_BINDLATE, h->h_flags)) 867 { 868 if (tTd(32, 1)) 869 { 870 sm_dprintf("("); 871 xputs(sm_debug_file(), h->h_value); 872 sm_dprintf(") "); 873 } 874 expand(h->h_value, buf, sizeof(buf), e); 875 if (buf[0] != '\0' && 876 (buf[0] != ' ' || buf[1] != '\0')) 877 { 878 if (bitset(H_FROM, h->h_flags)) 879 expand(crackaddr(buf, e), 880 buf, sizeof(buf), e); 881 h->h_value = sm_rpool_strdup_x(e->e_rpool, buf); 882 h->h_flags &= ~H_DEFAULT; 883 } 884 } 885 if (tTd(32, 1)) 886 { 887 xputs(sm_debug_file(), h->h_value); 888 sm_dprintf("\n"); 889 } 890 891 /* count the number of times it has been processed */ 892 if (bitset(H_TRACE, h->h_flags)) 893 hopcnt++; 894 895 /* send to this person if we so desire */ 896 if (GrabTo && bitset(H_RCPT, h->h_flags) && 897 !bitset(H_DEFAULT, h->h_flags) && 898 (!bitset(EF_RESENT, e->e_flags) || 899 bitset(H_RESENT, h->h_flags))) 900 { 901#if 0 902 int saveflags = e->e_flags; 903#endif /* 0 */ 904 905 (void) sendtolist(denlstring(h->h_value, true, false), 906 NULLADDR, &e->e_sendqueue, 0, e); 907 908#if 0 909 /* 910 ** Change functionality so a fatal error on an 911 ** address doesn't affect the entire envelope. 912 */ 913 914 /* delete fatal errors generated by this address */ 915 if (!bitset(EF_FATALERRS, saveflags)) 916 e->e_flags &= ~EF_FATALERRS; 917#endif /* 0 */ 918 } 919 920 /* save the message-id for logging */ 921 p = "resent-message-id"; 922 if (!bitset(EF_RESENT, e->e_flags)) 923 p += 7; 924 if (sm_strcasecmp(h->h_field, p) == 0) 925 { 926 e->e_msgid = h->h_value; 927 while (isascii(*e->e_msgid) && isspace(*e->e_msgid)) 928 e->e_msgid++; 929 macdefine(&e->e_macro, A_PERM, macid("{msg_id}"), 930 e->e_msgid); 931 } 932 } 933 if (tTd(32, 1)) 934 sm_dprintf("----------------------------\n"); 935 936 /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 937 if (OpMode == MD_VERIFY) 938 return; 939 940 /* store hop count */ 941 if (hopcnt > e->e_hopcount) 942 { 943 e->e_hopcount = hopcnt; 944 (void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount); 945 macdefine(&e->e_macro, A_TEMP, 'c', buf); 946 } 947 948 /* message priority */ 949 p = hvalue("precedence", e->e_header); 950 if (p != NULL) 951 e->e_class = priencode(p); 952 if (e->e_class < 0) 953 e->e_timeoutclass = TOC_NONURGENT; 954 else if (e->e_class > 0) 955 e->e_timeoutclass = TOC_URGENT; 956 if (full) 957 { 958 e->e_msgpriority = e->e_msgsize 959 - e->e_class * WkClassFact 960 + e->e_nrcpts * WkRecipFact; 961 } 962 963 /* check for DSN to properly set e_timeoutclass */ 964 p = hvalue("content-type", e->e_header); 965 if (p != NULL) 966 { 967 bool oldsupr; 968 char **pvp; 969 char pvpbuf[MAXLINE]; 970 extern unsigned char MimeTokenTab[256]; 971 972 /* tokenize header */ 973 oldsupr = SuprErrs; 974 SuprErrs = true; 975 pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL, 976 MimeTokenTab, false); 977 SuprErrs = oldsupr; 978 979 /* Check if multipart/report */ 980 if (pvp != NULL && pvp[0] != NULL && 981 pvp[1] != NULL && pvp[2] != NULL && 982 sm_strcasecmp(*pvp++, "multipart") == 0 && 983 strcmp(*pvp++, "/") == 0 && 984 sm_strcasecmp(*pvp++, "report") == 0) 985 { 986 /* Look for report-type=delivery-status */ 987 while (*pvp != NULL) 988 { 989 /* skip to semicolon separator */ 990 while (*pvp != NULL && strcmp(*pvp, ";") != 0) 991 pvp++; 992 993 /* skip semicolon */ 994 if (*pvp++ == NULL || *pvp == NULL) 995 break; 996 997 /* look for report-type */ 998 if (sm_strcasecmp(*pvp++, "report-type") != 0) 999 continue; 1000 1001 /* skip equal */ 1002 if (*pvp == NULL || strcmp(*pvp, "=") != 0) 1003 continue; 1004 1005 /* check value */ 1006 if (*++pvp != NULL && 1007 sm_strcasecmp(*pvp, 1008 "delivery-status") == 0) 1009 e->e_timeoutclass = TOC_DSN; 1010 1011 /* found report-type, no need to continue */ 1012 break; 1013 } 1014 } 1015 } 1016 1017 /* message timeout priority */ 1018 p = hvalue("priority", e->e_header); 1019 if (p != NULL) 1020 { 1021 /* (this should be in the configuration file) */ 1022 if (sm_strcasecmp(p, "urgent") == 0) 1023 e->e_timeoutclass = TOC_URGENT; 1024 else if (sm_strcasecmp(p, "normal") == 0) 1025 e->e_timeoutclass = TOC_NORMAL; 1026 else if (sm_strcasecmp(p, "non-urgent") == 0) 1027 e->e_timeoutclass = TOC_NONURGENT; 1028 else if (bitset(EF_RESPONSE, e->e_flags)) 1029 e->e_timeoutclass = TOC_DSN; 1030 } 1031 else if (bitset(EF_RESPONSE, e->e_flags)) 1032 e->e_timeoutclass = TOC_DSN; 1033 1034 /* date message originated */ 1035 p = hvalue("posted-date", e->e_header); 1036 if (p == NULL) 1037 p = hvalue("date", e->e_header); 1038 if (p != NULL) 1039 macdefine(&e->e_macro, A_PERM, 'a', p); 1040 1041 /* check to see if this is a MIME message */ 1042 if ((e->e_bodytype != NULL && 1043 sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 1044 hvalue("MIME-Version", e->e_header) != NULL) 1045 { 1046 e->e_flags |= EF_IS_MIME; 1047 if (HasEightBits) 1048 e->e_bodytype = "8BITMIME"; 1049 } 1050 else if ((p = hvalue("Content-Type", e->e_header)) != NULL) 1051 { 1052 /* this may be an RFC 1049 message */ 1053 p = strpbrk(p, ";/"); 1054 if (p == NULL || *p == ';') 1055 { 1056 /* yep, it is */ 1057 e->e_flags |= EF_DONT_MIME; 1058 } 1059 } 1060 1061 /* 1062 ** From person in antiquated ARPANET mode 1063 ** required by UK Grey Book e-mail gateways (sigh) 1064 */ 1065 1066 if (OpMode == MD_ARPAFTP) 1067 { 1068 register struct hdrinfo *hi; 1069 1070 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 1071 { 1072 if (bitset(H_FROM, hi->hi_flags) && 1073 (!bitset(H_RESENT, hi->hi_flags) || 1074 bitset(EF_RESENT, e->e_flags)) && 1075 (p = hvalue(hi->hi_field, e->e_header)) != NULL) 1076 break; 1077 } 1078 if (hi->hi_field != NULL) 1079 { 1080 if (tTd(32, 2)) 1081 sm_dprintf("eatheader: setsender(*%s == %s)\n", 1082 hi->hi_field, p); 1083 setsender(p, e, NULL, '\0', true); 1084 } 1085 } 1086 1087 /* 1088 ** Log collection information. 1089 */ 1090 1091 if (tTd(92, 2)) 1092 sm_dprintf("eatheader: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d, log=%d\n", 1093 e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel, 1094 log); 1095 if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 1096 { 1097 logsender(e, e->e_msgid); 1098 e->e_flags &= ~EF_LOGSENDER; 1099 } 1100} 1101 1102/* 1103** LOGSENDER -- log sender information 1104** 1105** Parameters: 1106** e -- the envelope to log 1107** msgid -- the message id 1108** 1109** Returns: 1110** none 1111*/ 1112 1113void 1114logsender(e, msgid) 1115 register ENVELOPE *e; 1116 char *msgid; 1117{ 1118 char *name; 1119 register char *sbp; 1120 register char *p; 1121 char hbuf[MAXNAME + 1]; 1122 char sbuf[MAXLINE + 1]; 1123 char mbuf[MAXNAME + 1]; 1124 1125 /* don't allow newlines in the message-id */ 1126 /* XXX do we still need this? sm_syslog() replaces control chars */ 1127 if (msgid != NULL) 1128 { 1129 size_t l; 1130 1131 l = strlen(msgid); 1132 if (l > sizeof(mbuf) - 1) 1133 l = sizeof(mbuf) - 1; 1134 memmove(mbuf, msgid, l); 1135 mbuf[l] = '\0'; 1136 p = mbuf; 1137 while ((p = strchr(p, '\n')) != NULL) 1138 *p++ = ' '; 1139 } 1140 1141 if (bitset(EF_RESPONSE, e->e_flags)) 1142 name = "[RESPONSE]"; 1143 else if ((name = macvalue('_', e)) != NULL) 1144 /* EMPTY */ 1145 ; 1146 else if (RealHostName == NULL) 1147 name = "localhost"; 1148 else if (RealHostName[0] == '[') 1149 name = RealHostName; 1150 else 1151 { 1152 name = hbuf; 1153 (void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName); 1154 if (RealHostAddr.sa.sa_family != 0) 1155 { 1156 p = &hbuf[strlen(hbuf)]; 1157 (void) sm_snprintf(p, SPACELEFT(hbuf, p), 1158 " (%.100s)", 1159 anynet_ntoa(&RealHostAddr)); 1160 } 1161 } 1162 1163 /* some versions of syslog only take 5 printf args */ 1164#if (SYSLOG_BUFSIZE) >= 256 1165 sbp = sbuf; 1166 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1167 "from=%.200s, size=%ld, class=%d, nrcpts=%d", 1168 e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 1169 PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 1170 sbp += strlen(sbp); 1171 if (msgid != NULL) 1172 { 1173 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1174 ", msgid=%.100s", mbuf); 1175 sbp += strlen(sbp); 1176 } 1177 if (e->e_bodytype != NULL) 1178 { 1179 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1180 ", bodytype=%.20s", e->e_bodytype); 1181 sbp += strlen(sbp); 1182 } 1183 p = macvalue('r', e); 1184 if (p != NULL) 1185 { 1186 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1187 ", proto=%.20s", p); 1188 sbp += strlen(sbp); 1189 } 1190 p = macvalue(macid("{daemon_name}"), e); 1191 if (p != NULL) 1192 { 1193 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1194 ", daemon=%.20s", p); 1195 sbp += strlen(sbp); 1196 } 1197 sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name); 1198 1199#else /* (SYSLOG_BUFSIZE) >= 256 */ 1200 1201 sm_syslog(LOG_INFO, e->e_id, 1202 "from=%s", 1203 e->e_from.q_paddr == NULL ? "<NONE>" 1204 : shortenstring(e->e_from.q_paddr, 1205 83)); 1206 sm_syslog(LOG_INFO, e->e_id, 1207 "size=%ld, class=%ld, nrcpts=%d", 1208 PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 1209 if (msgid != NULL) 1210 sm_syslog(LOG_INFO, e->e_id, 1211 "msgid=%s", 1212 shortenstring(mbuf, 83)); 1213 sbp = sbuf; 1214 *sbp = '\0'; 1215 if (e->e_bodytype != NULL) 1216 { 1217 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1218 "bodytype=%.20s, ", e->e_bodytype); 1219 sbp += strlen(sbp); 1220 } 1221 p = macvalue('r', e); 1222 if (p != NULL) 1223 { 1224 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1225 "proto=%.20s, ", p); 1226 sbp += strlen(sbp); 1227 } 1228 sm_syslog(LOG_INFO, e->e_id, 1229 "%.400srelay=%s", sbuf, name); 1230#endif /* (SYSLOG_BUFSIZE) >= 256 */ 1231} 1232 1233/* 1234** PRIENCODE -- encode external priority names into internal values. 1235** 1236** Parameters: 1237** p -- priority in ascii. 1238** 1239** Returns: 1240** priority as a numeric level. 1241** 1242** Side Effects: 1243** none. 1244*/ 1245 1246static int 1247priencode(p) 1248 char *p; 1249{ 1250 register int i; 1251 1252 for (i = 0; i < NumPriorities; i++) 1253 { 1254 if (sm_strcasecmp(p, Priorities[i].pri_name) == 0) 1255 return Priorities[i].pri_val; 1256 } 1257 1258 /* unknown priority */ 1259 return 0; 1260} 1261 1262/* 1263** CRACKADDR -- parse an address and turn it into a macro 1264** 1265** This doesn't actually parse the address -- it just extracts 1266** it and replaces it with "$g". The parse is totally ad hoc 1267** and isn't even guaranteed to leave something syntactically 1268** identical to what it started with. However, it does leave 1269** something semantically identical if possible, else at least 1270** syntactically correct. 1271** 1272** For example, it changes "Real Name <real@example.com> (Comment)" 1273** to "Real Name <$g> (Comment)". 1274** 1275** This algorithm has been cleaned up to handle a wider range 1276** of cases -- notably quoted and backslash escaped strings. 1277** This modification makes it substantially better at preserving 1278** the original syntax. 1279** 1280** Parameters: 1281** addr -- the address to be cracked. 1282** e -- the current envelope. 1283** 1284** Returns: 1285** a pointer to the new version. 1286** 1287** Side Effects: 1288** none. 1289** 1290** Warning: 1291** The return value is saved in local storage and should 1292** be copied if it is to be reused. 1293*/ 1294 1295#define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend)) 1296 1297/* 1298** Append a character to bp if we have room. 1299** If not, punt and return $g. 1300*/ 1301 1302#define SM_APPEND_CHAR(c) \ 1303 do \ 1304 { \ 1305 if (SM_HAVE_ROOM) \ 1306 *bp++ = (c); \ 1307 else \ 1308 goto returng; \ 1309 } while (0) 1310 1311#if MAXNAME < 10 1312ERROR MAXNAME must be at least 10 1313#endif /* MAXNAME < 10 */ 1314 1315char * 1316crackaddr(addr, e) 1317 register char *addr; 1318 ENVELOPE *e; 1319{ 1320 register char *p; 1321 register char c; 1322 int cmtlev; /* comment level in input string */ 1323 int realcmtlev; /* comment level in output string */ 1324 int anglelev; /* angle level in input string */ 1325 int copylev; /* 0 == in address, >0 copying */ 1326 int bracklev; /* bracket level for IPv6 addr check */ 1327 bool addangle; /* put closing angle in output */ 1328 bool qmode; /* quoting in original string? */ 1329 bool realqmode; /* quoting in output string? */ 1330 bool putgmac = false; /* already wrote $g */ 1331 bool quoteit = false; /* need to quote next character */ 1332 bool gotangle = false; /* found first '<' */ 1333 bool gotcolon = false; /* found a ':' */ 1334 register char *bp; 1335 char *buflim; 1336 char *bufhead; 1337 char *addrhead; 1338 char *bufend; 1339 static char buf[MAXNAME + 1]; 1340 1341 if (tTd(33, 1)) 1342 sm_dprintf("crackaddr(%s)\n", addr); 1343 1344 buflim = bufend = &buf[sizeof(buf) - 1]; 1345 bp = bufhead = buf; 1346 1347 /* skip over leading spaces but preserve them */ 1348 while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 1349 { 1350 SM_APPEND_CHAR(*addr); 1351 addr++; 1352 } 1353 bufhead = bp; 1354 1355 /* 1356 ** Start by assuming we have no angle brackets. This will be 1357 ** adjusted later if we find them. 1358 */ 1359 1360 p = addrhead = addr; 1361 copylev = anglelev = cmtlev = realcmtlev = 0; 1362 bracklev = 0; 1363 qmode = realqmode = addangle = false; 1364 1365 while ((c = *p++) != '\0') 1366 { 1367 /* 1368 ** Try to keep legal syntax using spare buffer space 1369 ** (maintained by buflim). 1370 */ 1371 1372 if (copylev > 0) 1373 SM_APPEND_CHAR(c); 1374 1375 /* check for backslash escapes */ 1376 if (c == '\\') 1377 { 1378 /* arrange to quote the address */ 1379 if (cmtlev <= 0 && !qmode) 1380 quoteit = true; 1381 1382 if ((c = *p++) == '\0') 1383 { 1384 /* too far */ 1385 p--; 1386 goto putg; 1387 } 1388 if (copylev > 0) 1389 SM_APPEND_CHAR(c); 1390 goto putg; 1391 } 1392 1393 /* check for quoted strings */ 1394 if (c == '"' && cmtlev <= 0) 1395 { 1396 qmode = !qmode; 1397 if (copylev > 0 && SM_HAVE_ROOM) 1398 { 1399 if (realqmode) 1400 buflim--; 1401 else 1402 buflim++; 1403 realqmode = !realqmode; 1404 } 1405 continue; 1406 } 1407 if (qmode) 1408 goto putg; 1409 1410 /* check for comments */ 1411 if (c == '(') 1412 { 1413 cmtlev++; 1414 1415 /* allow space for closing paren */ 1416 if (SM_HAVE_ROOM) 1417 { 1418 buflim--; 1419 realcmtlev++; 1420 if (copylev++ <= 0) 1421 { 1422 if (bp != bufhead) 1423 SM_APPEND_CHAR(' '); 1424 SM_APPEND_CHAR(c); 1425 } 1426 } 1427 } 1428 if (cmtlev > 0) 1429 { 1430 if (c == ')') 1431 { 1432 cmtlev--; 1433 copylev--; 1434 if (SM_HAVE_ROOM) 1435 { 1436 realcmtlev--; 1437 buflim++; 1438 } 1439 } 1440 continue; 1441 } 1442 else if (c == ')') 1443 { 1444 /* syntax error: unmatched ) */ 1445 if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead) 1446 bp--; 1447 } 1448 1449 /* count nesting on [ ... ] (for IPv6 domain literals) */ 1450 if (c == '[') 1451 bracklev++; 1452 else if (c == ']') 1453 bracklev--; 1454 1455 /* check for group: list; syntax */ 1456 if (c == ':' && anglelev <= 0 && bracklev <= 0 && 1457 !gotcolon && !ColonOkInAddr) 1458 { 1459 register char *q; 1460 1461 /* 1462 ** Check for DECnet phase IV ``::'' (host::user) 1463 ** or DECnet phase V ``:.'' syntaxes. The latter 1464 ** covers ``user@DEC:.tay.myhost'' and 1465 ** ``DEC:.tay.myhost::user'' syntaxes (bletch). 1466 */ 1467 1468 if (*p == ':' || *p == '.') 1469 { 1470 if (cmtlev <= 0 && !qmode) 1471 quoteit = true; 1472 if (copylev > 0) 1473 { 1474 SM_APPEND_CHAR(c); 1475 SM_APPEND_CHAR(*p); 1476 } 1477 p++; 1478 goto putg; 1479 } 1480 1481 gotcolon = true; 1482 1483 bp = bufhead; 1484 if (quoteit) 1485 { 1486 SM_APPEND_CHAR('"'); 1487 1488 /* back up over the ':' and any spaces */ 1489 --p; 1490 while (p > addr && 1491 isascii(*--p) && isspace(*p)) 1492 continue; 1493 p++; 1494 } 1495 for (q = addrhead; q < p; ) 1496 { 1497 c = *q++; 1498 if (quoteit && c == '"') 1499 SM_APPEND_CHAR('\\'); 1500 SM_APPEND_CHAR(c); 1501 } 1502 if (quoteit) 1503 { 1504 if (bp == &bufhead[1]) 1505 bp--; 1506 else 1507 SM_APPEND_CHAR('"'); 1508 while ((c = *p++) != ':') 1509 SM_APPEND_CHAR(c); 1510 SM_APPEND_CHAR(c); 1511 } 1512 1513 /* any trailing white space is part of group: */ 1514 while (isascii(*p) && isspace(*p)) 1515 { 1516 SM_APPEND_CHAR(*p); 1517 p++; 1518 } 1519 copylev = 0; 1520 putgmac = quoteit = false; 1521 bufhead = bp; 1522 addrhead = p; 1523 continue; 1524 } 1525 1526 if (c == ';' && copylev <= 0 && !ColonOkInAddr) 1527 SM_APPEND_CHAR(c); 1528 1529 /* check for characters that may have to be quoted */ 1530 if (strchr(MustQuoteChars, c) != NULL) 1531 { 1532 /* 1533 ** If these occur as the phrase part of a <> 1534 ** construct, but are not inside of () or already 1535 ** quoted, they will have to be quoted. Note that 1536 ** now (but don't actually do the quoting). 1537 */ 1538 1539 if (cmtlev <= 0 && !qmode) 1540 quoteit = true; 1541 } 1542 1543 /* check for angle brackets */ 1544 if (c == '<') 1545 { 1546 register char *q; 1547 1548 /* assume first of two angles is bogus */ 1549 if (gotangle) 1550 quoteit = true; 1551 gotangle = true; 1552 1553 /* oops -- have to change our mind */ 1554 anglelev = 1; 1555 if (SM_HAVE_ROOM) 1556 { 1557 if (!addangle) 1558 buflim--; 1559 addangle = true; 1560 } 1561 1562 bp = bufhead; 1563 if (quoteit) 1564 { 1565 SM_APPEND_CHAR('"'); 1566 1567 /* back up over the '<' and any spaces */ 1568 --p; 1569 while (p > addr && 1570 isascii(*--p) && isspace(*p)) 1571 continue; 1572 p++; 1573 } 1574 for (q = addrhead; q < p; ) 1575 { 1576 c = *q++; 1577 if (quoteit && c == '"') 1578 { 1579 SM_APPEND_CHAR('\\'); 1580 SM_APPEND_CHAR(c); 1581 } 1582 else 1583 SM_APPEND_CHAR(c); 1584 } 1585 if (quoteit) 1586 { 1587 if (bp == &buf[1]) 1588 bp--; 1589 else 1590 SM_APPEND_CHAR('"'); 1591 while ((c = *p++) != '<') 1592 SM_APPEND_CHAR(c); 1593 SM_APPEND_CHAR(c); 1594 } 1595 copylev = 0; 1596 putgmac = quoteit = false; 1597 continue; 1598 } 1599 1600 if (c == '>') 1601 { 1602 if (anglelev > 0) 1603 { 1604 anglelev--; 1605 if (SM_HAVE_ROOM) 1606 { 1607 if (addangle) 1608 buflim++; 1609 addangle = false; 1610 } 1611 } 1612 else if (SM_HAVE_ROOM) 1613 { 1614 /* syntax error: unmatched > */ 1615 if (copylev > 0 && bp > bufhead) 1616 bp--; 1617 quoteit = true; 1618 continue; 1619 } 1620 if (copylev++ <= 0) 1621 SM_APPEND_CHAR(c); 1622 continue; 1623 } 1624 1625 /* must be a real address character */ 1626 putg: 1627 if (copylev <= 0 && !putgmac) 1628 { 1629 if (bp > buf && bp[-1] == ')') 1630 SM_APPEND_CHAR(' '); 1631 SM_APPEND_CHAR(MACROEXPAND); 1632 SM_APPEND_CHAR('g'); 1633 putgmac = true; 1634 } 1635 } 1636 1637 /* repair any syntactic damage */ 1638 if (realqmode && bp < bufend) 1639 *bp++ = '"'; 1640 while (realcmtlev-- > 0 && bp < bufend) 1641 *bp++ = ')'; 1642 if (addangle && bp < bufend) 1643 *bp++ = '>'; 1644 *bp = '\0'; 1645 if (bp < bufend) 1646 goto success; 1647 1648 returng: 1649 /* String too long, punt */ 1650 buf[0] = '<'; 1651 buf[1] = MACROEXPAND; 1652 buf[2]= 'g'; 1653 buf[3] = '>'; 1654 buf[4]= '\0'; 1655 sm_syslog(LOG_ALERT, e->e_id, 1656 "Dropped invalid comments from header address"); 1657 1658 success: 1659 if (tTd(33, 1)) 1660 { 1661 sm_dprintf("crackaddr=>`"); 1662 xputs(sm_debug_file(), buf); 1663 sm_dprintf("'\n"); 1664 } 1665 return buf; 1666} 1667 1668/* 1669** PUTHEADER -- put the header part of a message from the in-core copy 1670** 1671** Parameters: 1672** mci -- the connection information. 1673** hdr -- the header to put. 1674** e -- envelope to use. 1675** flags -- MIME conversion flags. 1676** 1677** Returns: 1678** true iff header part was written successfully 1679** 1680** Side Effects: 1681** none. 1682*/ 1683 1684bool 1685putheader(mci, hdr, e, flags) 1686 register MCI *mci; 1687 HDR *hdr; 1688 register ENVELOPE *e; 1689 int flags; 1690{ 1691 register HDR *h; 1692 char buf[SM_MAX(MAXLINE,BUFSIZ)]; 1693 char obuf[MAXLINE]; 1694 1695 if (tTd(34, 1)) 1696 sm_dprintf("--- putheader, mailer = %s ---\n", 1697 mci->mci_mailer->m_name); 1698 1699 /* 1700 ** If we're in MIME mode, we're not really in the header of the 1701 ** message, just the header of one of the parts of the body of 1702 ** the message. Therefore MCIF_INHEADER should not be turned on. 1703 */ 1704 1705 if (!bitset(MCIF_INMIME, mci->mci_flags)) 1706 mci->mci_flags |= MCIF_INHEADER; 1707 1708 for (h = hdr; h != NULL; h = h->h_link) 1709 { 1710 register char *p = h->h_value; 1711 char *q; 1712 1713 if (tTd(34, 11)) 1714 { 1715 sm_dprintf(" %s:", h->h_field); 1716 xputs(sm_debug_file(), p); 1717 } 1718 1719 /* Skip empty headers */ 1720 if (h->h_value == NULL) 1721 continue; 1722 1723 /* heuristic shortening of MIME fields to avoid MUA overflows */ 1724 if (MaxMimeFieldLength > 0 && 1725 wordinclass(h->h_field, 1726 macid("{checkMIMEFieldHeaders}"))) 1727 { 1728 size_t len; 1729 1730 len = fix_mime_header(h, e); 1731 if (len > 0) 1732 { 1733 sm_syslog(LOG_ALERT, e->e_id, 1734 "Truncated MIME %s header due to field size (length = %ld) (possible attack)", 1735 h->h_field, (unsigned long) len); 1736 if (tTd(34, 11)) 1737 sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", 1738 h->h_field, 1739 (unsigned long) len); 1740 } 1741 } 1742 1743 if (MaxMimeHeaderLength > 0 && 1744 wordinclass(h->h_field, 1745 macid("{checkMIMETextHeaders}"))) 1746 { 1747 size_t len; 1748 1749 len = strlen(h->h_value); 1750 if (len > (size_t) MaxMimeHeaderLength) 1751 { 1752 h->h_value[MaxMimeHeaderLength - 1] = '\0'; 1753 sm_syslog(LOG_ALERT, e->e_id, 1754 "Truncated long MIME %s header (length = %ld) (possible attack)", 1755 h->h_field, (unsigned long) len); 1756 if (tTd(34, 11)) 1757 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1758 h->h_field, 1759 (unsigned long) len); 1760 } 1761 } 1762 1763 if (MaxMimeHeaderLength > 0 && 1764 wordinclass(h->h_field, 1765 macid("{checkMIMEHeaders}"))) 1766 { 1767 size_t len; 1768 1769 len = strlen(h->h_value); 1770 if (shorten_rfc822_string(h->h_value, 1771 MaxMimeHeaderLength)) 1772 { 1773 if (len < MaxMimeHeaderLength) 1774 { 1775 /* we only rebalanced a bogus header */ 1776 sm_syslog(LOG_ALERT, e->e_id, 1777 "Fixed MIME %s header (possible attack)", 1778 h->h_field); 1779 if (tTd(34, 11)) 1780 sm_dprintf(" fixed MIME %s header (possible attack)\n", 1781 h->h_field); 1782 } 1783 else 1784 { 1785 /* we actually shortened header */ 1786 sm_syslog(LOG_ALERT, e->e_id, 1787 "Truncated long MIME %s header (length = %ld) (possible attack)", 1788 h->h_field, 1789 (unsigned long) len); 1790 if (tTd(34, 11)) 1791 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1792 h->h_field, 1793 (unsigned long) len); 1794 } 1795 } 1796 } 1797 1798 /* 1799 ** Suppress Content-Transfer-Encoding: if we are MIMEing 1800 ** and we are potentially converting from 8 bit to 7 bit 1801 ** MIME. If converting, add a new CTE header in 1802 ** mime8to7(). 1803 */ 1804 1805 if (bitset(H_CTE, h->h_flags) && 1806 bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 1807 mci->mci_flags) && 1808 !bitset(M87F_NO8TO7, flags)) 1809 { 1810 if (tTd(34, 11)) 1811 sm_dprintf(" (skipped (content-transfer-encoding))\n"); 1812 continue; 1813 } 1814 1815 if (bitset(MCIF_INMIME, mci->mci_flags)) 1816 { 1817 if (tTd(34, 11)) 1818 sm_dprintf("\n"); 1819 if (!put_vanilla_header(h, p, mci)) 1820 goto writeerr; 1821 continue; 1822 } 1823 1824 if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 1825 !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && 1826 (h->h_macro == '\0' || 1827 (q = macvalue(bitidx(h->h_macro), e)) == NULL || 1828 *q == '\0')) 1829 { 1830 if (tTd(34, 11)) 1831 sm_dprintf(" (skipped)\n"); 1832 continue; 1833 } 1834 1835 /* handle Resent-... headers specially */ 1836 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 1837 { 1838 if (tTd(34, 11)) 1839 sm_dprintf(" (skipped (resent))\n"); 1840 continue; 1841 } 1842 1843 /* suppress return receipts if requested */ 1844 if (bitset(H_RECEIPTTO, h->h_flags) && 1845 (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) 1846 { 1847 if (tTd(34, 11)) 1848 sm_dprintf(" (skipped (receipt))\n"); 1849 continue; 1850 } 1851 1852 /* macro expand value if generated internally */ 1853 if (bitset(H_DEFAULT, h->h_flags) || 1854 bitset(H_BINDLATE, h->h_flags)) 1855 { 1856 expand(p, buf, sizeof(buf), e); 1857 p = buf; 1858 if (*p == '\0') 1859 { 1860 if (tTd(34, 11)) 1861 sm_dprintf(" (skipped -- null value)\n"); 1862 continue; 1863 } 1864 } 1865 1866 if (bitset(H_BCC, h->h_flags)) 1867 { 1868 /* Bcc: field -- either truncate or delete */ 1869 if (bitset(EF_DELETE_BCC, e->e_flags)) 1870 { 1871 if (tTd(34, 11)) 1872 sm_dprintf(" (skipped -- bcc)\n"); 1873 } 1874 else 1875 { 1876 /* no other recipient headers: truncate value */ 1877 (void) sm_strlcpyn(obuf, sizeof(obuf), 2, 1878 h->h_field, ":"); 1879 if (!putline(obuf, mci)) 1880 goto writeerr; 1881 } 1882 continue; 1883 } 1884 1885 if (tTd(34, 11)) 1886 sm_dprintf("\n"); 1887 1888 if (bitset(H_FROM|H_RCPT, h->h_flags)) 1889 { 1890 /* address field */ 1891 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 1892 1893 if (bitset(H_FROM, h->h_flags)) 1894 oldstyle = false; 1895 commaize(h, p, oldstyle, mci, e, 1896 PXLF_HEADER | PXLF_STRIPMQUOTE); 1897 } 1898 else 1899 { 1900 if (!put_vanilla_header(h, p, mci)) 1901 goto writeerr; 1902 } 1903 } 1904 1905 /* 1906 ** If we are converting this to a MIME message, add the 1907 ** MIME headers (but not in MIME mode!). 1908 */ 1909 1910#if MIME8TO7 1911 if (bitset(MM_MIME8BIT, MimeMode) && 1912 bitset(EF_HAS8BIT, e->e_flags) && 1913 !bitset(EF_DONT_MIME, e->e_flags) && 1914 !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 1915 !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) && 1916 hvalue("MIME-Version", e->e_header) == NULL) 1917 { 1918 if (!putline("MIME-Version: 1.0", mci)) 1919 goto writeerr; 1920 if (hvalue("Content-Type", e->e_header) == NULL) 1921 { 1922 (void) sm_snprintf(obuf, sizeof(obuf), 1923 "Content-Type: text/plain; charset=%s", 1924 defcharset(e)); 1925 if (!putline(obuf, mci)) 1926 goto writeerr; 1927 } 1928 if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL 1929 && !putline("Content-Transfer-Encoding: 8bit", mci)) 1930 goto writeerr; 1931 } 1932#endif /* MIME8TO7 */ 1933 return true; 1934 1935 writeerr: 1936 return false; 1937} 1938 1939/* 1940** PUT_VANILLA_HEADER -- output a fairly ordinary header 1941** 1942** Parameters: 1943** h -- the structure describing this header 1944** v -- the value of this header 1945** mci -- the connection info for output 1946** 1947** Returns: 1948** true iff header was written successfully 1949*/ 1950 1951static bool 1952put_vanilla_header(h, v, mci) 1953 HDR *h; 1954 char *v; 1955 MCI *mci; 1956{ 1957 register char *nlp; 1958 register char *obp; 1959 int putflags; 1960 char obuf[MAXLINE + 256]; /* additional length for h_field */ 1961 1962 putflags = PXLF_HEADER | PXLF_STRIPMQUOTE; 1963 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1964 putflags |= PXLF_STRIP8BIT; 1965 (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field); 1966 obp = obuf + strlen(obuf); 1967 while ((nlp = strchr(v, '\n')) != NULL) 1968 { 1969 int l; 1970 1971 l = nlp - v; 1972 1973 /* 1974 ** XXX This is broken for SPACELEFT()==0 1975 ** However, SPACELEFT() is always > 0 unless MAXLINE==1. 1976 */ 1977 1978 if (SPACELEFT(obuf, obp) - 1 < (size_t) l) 1979 l = SPACELEFT(obuf, obp) - 1; 1980 1981 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); 1982 if (!putxline(obuf, strlen(obuf), mci, putflags)) 1983 goto writeerr; 1984 v += l + 1; 1985 obp = obuf; 1986 if (*v != ' ' && *v != '\t') 1987 *obp++ = ' '; 1988 } 1989 1990 /* XXX This is broken for SPACELEFT()==0 */ 1991 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", 1992 (int) (SPACELEFT(obuf, obp) - 1), v); 1993 return putxline(obuf, strlen(obuf), mci, putflags); 1994 1995 writeerr: 1996 return false; 1997} 1998 1999/* 2000** COMMAIZE -- output a header field, making a comma-translated list. 2001** 2002** Parameters: 2003** h -- the header field to output. 2004** p -- the value to put in it. 2005** oldstyle -- true if this is an old style header. 2006** mci -- the connection information. 2007** e -- the envelope containing the message. 2008** putflags -- flags for putxline() 2009** 2010** Returns: 2011** true iff header field was written successfully 2012** 2013** Side Effects: 2014** outputs "p" to "mci". 2015*/ 2016 2017bool 2018commaize(h, p, oldstyle, mci, e, putflags) 2019 register HDR *h; 2020 register char *p; 2021 bool oldstyle; 2022 register MCI *mci; 2023 register ENVELOPE *e; 2024 int putflags; 2025{ 2026 register char *obp; 2027 int opos, omax, spaces; 2028 bool firstone = true; 2029 char **res; 2030 char obuf[MAXLINE + 3]; 2031 2032 /* 2033 ** Output the address list translated by the 2034 ** mailer and with commas. 2035 */ 2036 2037 if (tTd(14, 2)) 2038 sm_dprintf("commaize(%s:%s)\n", h->h_field, p); 2039 2040 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 2041 putflags |= PXLF_STRIP8BIT; 2042 2043 obp = obuf; 2044 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field); 2045 /* opos = strlen(obp); instead of the next 3 lines? */ 2046 opos = strlen(h->h_field) + 1; 2047 if (opos > 201) 2048 opos = 201; 2049 obp += opos; 2050 2051 spaces = 0; 2052 while (*p != '\0' && isascii(*p) && isspace(*p)) 2053 { 2054 ++spaces; 2055 ++p; 2056 } 2057 if (spaces > 0) 2058 { 2059 SM_ASSERT(sizeof(obuf) > opos * 2); 2060 2061 /* 2062 ** Restrict number of spaces to half the length of buffer 2063 ** so the header field body can be put in here too. 2064 ** Note: this is a hack... 2065 */ 2066 2067 if (spaces > sizeof(obuf) / 2) 2068 spaces = sizeof(obuf) / 2; 2069 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces, 2070 ""); 2071 opos += spaces; 2072 obp += spaces; 2073 SM_ASSERT(obp < &obuf[MAXLINE]); 2074 } 2075 2076 omax = mci->mci_mailer->m_linelimit - 2; 2077 if (omax < 0 || omax > 78) 2078 omax = 78; 2079 2080 /* 2081 ** Run through the list of values. 2082 */ 2083 2084 while (*p != '\0') 2085 { 2086 register char *name; 2087 register int c; 2088 char savechar; 2089 int flags; 2090 auto int status; 2091 2092 /* 2093 ** Find the end of the name. New style names 2094 ** end with a comma, old style names end with 2095 ** a space character. However, spaces do not 2096 ** necessarily delimit an old-style name -- at 2097 ** signs mean keep going. 2098 */ 2099 2100 /* find end of name */ 2101 while ((isascii(*p) && isspace(*p)) || *p == ',') 2102 p++; 2103 name = p; 2104 res = NULL; 2105 for (;;) 2106 { 2107 auto char *oldp; 2108 char pvpbuf[PSBUFSIZE]; 2109 2110 res = prescan(p, oldstyle ? ' ' : ',', pvpbuf, 2111 sizeof(pvpbuf), &oldp, ExtTokenTab, false); 2112 p = oldp; 2113#if _FFR_IGNORE_BOGUS_ADDR 2114 /* ignore addresses that can't be parsed */ 2115 if (res == NULL) 2116 { 2117 name = p; 2118 continue; 2119 } 2120#endif /* _FFR_IGNORE_BOGUS_ADDR */ 2121 2122 /* look to see if we have an at sign */ 2123 while (*p != '\0' && isascii(*p) && isspace(*p)) 2124 p++; 2125 2126 if (*p != '@') 2127 { 2128 p = oldp; 2129 break; 2130 } 2131 ++p; 2132 while (*p != '\0' && isascii(*p) && isspace(*p)) 2133 p++; 2134 } 2135 /* at the end of one complete name */ 2136 2137 /* strip off trailing white space */ 2138 while (p >= name && 2139 ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 2140 p--; 2141 if (++p == name) 2142 continue; 2143 2144 /* 2145 ** if prescan() failed go a bit backwards; this is a hack, 2146 ** there should be some better error recovery. 2147 */ 2148 2149 if (res == NULL && p > name && 2150 !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 2151 --p; 2152 savechar = *p; 2153 *p = '\0'; 2154 2155 /* translate the name to be relative */ 2156 flags = RF_HEADERADDR|RF_ADDDOMAIN; 2157 if (bitset(H_FROM, h->h_flags)) 2158 flags |= RF_SENDERADDR; 2159#if USERDB 2160 else if (e->e_from.q_mailer != NULL && 2161 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 2162 { 2163 char *q; 2164 2165 q = udbsender(name, e->e_rpool); 2166 if (q != NULL) 2167 name = q; 2168 } 2169#endif /* USERDB */ 2170 status = EX_OK; 2171 name = remotename(name, mci->mci_mailer, flags, &status, e); 2172 if (*name == '\0') 2173 { 2174 *p = savechar; 2175 continue; 2176 } 2177 name = denlstring(name, false, true); 2178 2179 /* output the name with nice formatting */ 2180 opos += strlen(name); 2181 if (!firstone) 2182 opos += 2; 2183 if (opos > omax && !firstone) 2184 { 2185 (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp)); 2186 if (!putxline(obuf, strlen(obuf), mci, putflags)) 2187 goto writeerr; 2188 obp = obuf; 2189 (void) sm_strlcpy(obp, " ", sizeof(obuf)); 2190 opos = strlen(obp); 2191 obp += opos; 2192 opos += strlen(name); 2193 } 2194 else if (!firstone) 2195 { 2196 (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp)); 2197 obp += 2; 2198 } 2199 2200 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 2201 *obp++ = c; 2202 firstone = false; 2203 *p = savechar; 2204 } 2205 if (obp < &obuf[sizeof(obuf)]) 2206 *obp = '\0'; 2207 else 2208 obuf[sizeof(obuf) - 1] = '\0'; 2209 return putxline(obuf, strlen(obuf), mci, putflags); 2210 2211 writeerr: 2212 return false; 2213} 2214 2215/* 2216** COPYHEADER -- copy header list 2217** 2218** This routine is the equivalent of newstr for header lists 2219** 2220** Parameters: 2221** header -- list of header structures to copy. 2222** rpool -- resource pool, or NULL 2223** 2224** Returns: 2225** a copy of 'header'. 2226** 2227** Side Effects: 2228** none. 2229*/ 2230 2231HDR * 2232copyheader(header, rpool) 2233 register HDR *header; 2234 SM_RPOOL_T *rpool; 2235{ 2236 register HDR *newhdr; 2237 HDR *ret; 2238 register HDR **tail = &ret; 2239 2240 while (header != NULL) 2241 { 2242 newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr)); 2243 STRUCTCOPY(*header, *newhdr); 2244 *tail = newhdr; 2245 tail = &newhdr->h_link; 2246 header = header->h_link; 2247 } 2248 *tail = NULL; 2249 2250 return ret; 2251} 2252 2253/* 2254** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header 2255** 2256** Run through all of the parameters of a MIME header and 2257** possibly truncate and rebalance the parameter according 2258** to MaxMimeFieldLength. 2259** 2260** Parameters: 2261** h -- the header to truncate/rebalance 2262** e -- the current envelope 2263** 2264** Returns: 2265** length of last offending field, 0 if all ok. 2266** 2267** Side Effects: 2268** string modified in place 2269*/ 2270 2271static size_t 2272fix_mime_header(h, e) 2273 HDR *h; 2274 ENVELOPE *e; 2275{ 2276 char *begin = h->h_value; 2277 char *end; 2278 size_t len = 0; 2279 size_t retlen = 0; 2280 2281 if (begin == NULL || *begin == '\0') 2282 return 0; 2283 2284 /* Split on each ';' */ 2285 /* find_character() never returns NULL */ 2286 while ((end = find_character(begin, ';')) != NULL) 2287 { 2288 char save = *end; 2289 char *bp; 2290 2291 *end = '\0'; 2292 2293 len = strlen(begin); 2294 2295 /* Shorten individual parameter */ 2296 if (shorten_rfc822_string(begin, MaxMimeFieldLength)) 2297 { 2298 if (len < MaxMimeFieldLength) 2299 { 2300 /* we only rebalanced a bogus field */ 2301 sm_syslog(LOG_ALERT, e->e_id, 2302 "Fixed MIME %s header field (possible attack)", 2303 h->h_field); 2304 if (tTd(34, 11)) 2305 sm_dprintf(" fixed MIME %s header field (possible attack)\n", 2306 h->h_field); 2307 } 2308 else 2309 { 2310 /* we actually shortened the header */ 2311 retlen = len; 2312 } 2313 } 2314 2315 /* Collapse the possibly shortened string with rest */ 2316 bp = begin + strlen(begin); 2317 if (bp != end) 2318 { 2319 char *ep = end; 2320 2321 *end = save; 2322 end = bp; 2323 2324 /* copy character by character due to overlap */ 2325 while (*ep != '\0') 2326 *bp++ = *ep++; 2327 *bp = '\0'; 2328 } 2329 else 2330 *end = save; 2331 if (*end == '\0') 2332 break; 2333 2334 /* Move past ';' */ 2335 begin = end + 1; 2336 } 2337 return retlen; 2338} 2339