headers.c revision 77352
1296077Sadrian/* 2296077Sadrian * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. 3296077Sadrian * All rights reserved. 4296077Sadrian * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5296077Sadrian * Copyright (c) 1988, 1993 6296077Sadrian * The Regents of the University of California. All rights reserved. 7296077Sadrian * 8296077Sadrian * By using this file, you agree to the terms and conditions set 9296077Sadrian * forth in the LICENSE file which can be found at the top level of 10296077Sadrian * the sendmail distribution. 11296077Sadrian * 12296077Sadrian */ 13296077Sadrian 14296077Sadrian#ifndef lint 15296077Sadrianstatic char id[] = "@(#)$Id: headers.c,v 8.203.4.13 2001/05/03 17:24:06 gshapiro Exp $"; 16296077Sadrian#endif /* ! lint */ 17296077Sadrian 18296077Sadrian/* $FreeBSD: head/contrib/sendmail/src/headers.c 77352 2001-05-28 17:10:35Z gshapiro $ */ 19296077Sadrian 20296077Sadrian#include <sendmail.h> 21296077Sadrian 22296077Sadrianstatic size_t fix_mime_header __P((char *)); 23296077Sadrianstatic int priencode __P((char *)); 24296077Sadrianstatic void put_vanilla_header __P((HDR *, char *, MCI *)); 25296077Sadrian 26296077Sadrian/* 27296077Sadrian** SETUPHEADERS -- initialize headers in symbol table 28296077Sadrian** 29296077Sadrian** Parameters: 30296077Sadrian** none 31296077Sadrian** 32296077Sadrian** Returns: 33296077Sadrian** none 34296077Sadrian*/ 35296077Sadrian 36296077Sadrianvoid 37296077Sadriansetupheaders() 38296077Sadrian{ 39296077Sadrian struct hdrinfo *hi; 40296077Sadrian STAB *s; 41296077Sadrian 42296077Sadrian for (hi = HdrInfo; hi->hi_field != NULL; hi++) 43296077Sadrian { 44296077Sadrian s = stab(hi->hi_field, ST_HEADER, ST_ENTER); 45296077Sadrian s->s_header.hi_flags = hi->hi_flags; 46296077Sadrian s->s_header.hi_ruleset = NULL; 47296077Sadrian } 48296077Sadrian} 49296077Sadrian/* 50296077Sadrian** CHOMPHEADER -- process and save a header line. 51296077Sadrian** 52296077Sadrian** Called by collect, readcf, and readqf to deal with header lines. 53296077Sadrian** 54296077Sadrian** Parameters: 55296077Sadrian** line -- header as a text line. 56296077Sadrian** pflag -- flags for chompheader() (from sendmail.h) 57296077Sadrian** hdrp -- a pointer to the place to save the header. 58296077Sadrian** e -- the envelope including this header. 59296077Sadrian** 60296077Sadrian** Returns: 61296077Sadrian** flags for this header. 62296077Sadrian** 63296077Sadrian** Side Effects: 64296077Sadrian** The header is saved on the header list. 65296077Sadrian** Contents of 'line' are destroyed. 66296077Sadrian*/ 67296077Sadrian 68296077Sadrianstatic struct hdrinfo NormalHeader = { NULL, 0, NULL }; 69296077Sadrian 70296077Sadrianu_long 71296077Sadrianchompheader(line, pflag, hdrp, e) 72296077Sadrian char *line; 73296077Sadrian int pflag; 74296077Sadrian HDR **hdrp; 75296077Sadrian register ENVELOPE *e; 76296077Sadrian{ 77296077Sadrian u_char mid = '\0'; 78296077Sadrian register char *p; 79296077Sadrian register HDR *h; 80296077Sadrian HDR **hp; 81296077Sadrian char *fname; 82296077Sadrian char *fvalue; 83296077Sadrian bool cond = FALSE; 84296077Sadrian bool dropfrom; 85296077Sadrian bool headeronly; 86296077Sadrian STAB *s; 87296077Sadrian struct hdrinfo *hi; 88296077Sadrian bool nullheader = FALSE; 89296077Sadrian BITMAP256 mopts; 90296077Sadrian 91296077Sadrian if (tTd(31, 6)) 92296077Sadrian { 93296077Sadrian dprintf("chompheader: "); 94296077Sadrian xputs(line); 95296077Sadrian dprintf("\n"); 96296077Sadrian } 97296077Sadrian 98296077Sadrian headeronly = hdrp != NULL; 99296077Sadrian if (!headeronly) 100296077Sadrian hdrp = &e->e_header; 101296077Sadrian 102296077Sadrian /* strip off options */ 103296077Sadrian clrbitmap(mopts); 104296077Sadrian p = line; 105296077Sadrian if (!bitset(pflag, CHHDR_USER) && *p == '?') 106296077Sadrian { 107296077Sadrian int c; 108296077Sadrian register char *q; 109296077Sadrian 110296077Sadrian q = strchr(++p, '?'); 111296077Sadrian if (q == NULL) 112296077Sadrian goto hse; 113296077Sadrian 114296077Sadrian *q = '\0'; 115296077Sadrian c = *p & 0377; 116296077Sadrian 117296077Sadrian /* possibly macro conditional */ 118296077Sadrian if (c == MACROEXPAND) 119296077Sadrian { 120296077Sadrian /* catch ?$? */ 121296077Sadrian if (*++p == '\0') 122296077Sadrian { 123296077Sadrian *q = '?'; 124296077Sadrian goto hse; 125296077Sadrian } 126296077Sadrian 127296077Sadrian mid = (u_char) *p++; 128296077Sadrian 129296077Sadrian /* catch ?$abc? */ 130296077Sadrian if (*p != '\0') 131296077Sadrian { 132296077Sadrian *q = '?'; 133296077Sadrian goto hse; 134296077Sadrian } 135296077Sadrian } 136296077Sadrian else if (*p == '$') 137296077Sadrian { 138296077Sadrian /* catch ?$? */ 139296077Sadrian if (*++p == '\0') 140296077Sadrian { 141296077Sadrian *q = '?'; 142296077Sadrian goto hse; 143296077Sadrian } 144296077Sadrian 145296077Sadrian mid = (u_char)macid(p, NULL); 146296077Sadrian if (bitset(0200, mid)) 147296077Sadrian p += strlen(macname(mid)) + 2; 148296077Sadrian else 149296077Sadrian p++; 150296077Sadrian 151296077Sadrian /* catch ?$abc? */ 152296077Sadrian if (*p != '\0') 153296077Sadrian { 154296077Sadrian *q = '?'; 155296077Sadrian goto hse; 156296077Sadrian } 157296077Sadrian 158296077Sadrian } 159296077Sadrian else 160296077Sadrian { 161296077Sadrian while (*p != '\0') 162296077Sadrian { 163296077Sadrian if (!isascii(*p)) 164296077Sadrian { 165296077Sadrian *q = '?'; 166296077Sadrian goto hse; 167296077Sadrian } 168296077Sadrian 169296077Sadrian setbitn(bitidx(*p), mopts); 170296077Sadrian cond = TRUE; 171296077Sadrian p++; 172296077Sadrian } 173296077Sadrian } 174296077Sadrian p = q + 1; 175296077Sadrian } 176296077Sadrian 177296077Sadrian /* find canonical name */ 178296077Sadrian fname = p; 179296077Sadrian while (isascii(*p) && isgraph(*p) && *p != ':') 180296077Sadrian p++; 181296077Sadrian fvalue = p; 182296077Sadrian while (isascii(*p) && isspace(*p)) 183296077Sadrian p++; 184296077Sadrian if (*p++ != ':' || fname == fvalue) 185296077Sadrian { 186296077Sadrianhse: 187296077Sadrian syserr("553 5.3.0 header syntax error, line \"%s\"", line); 188296077Sadrian return 0; 189296077Sadrian } 190296077Sadrian *fvalue = '\0'; 191296077Sadrian 192296077Sadrian /* strip field value on front */ 193296077Sadrian if (*p == ' ') 194296077Sadrian p++; 195296077Sadrian fvalue = p; 196296077Sadrian 197296077Sadrian /* if the field is null, go ahead and use the default */ 198296077Sadrian while (isascii(*p) && isspace(*p)) 199296077Sadrian p++; 200296077Sadrian if (*p == '\0') 201296077Sadrian nullheader = TRUE; 202296077Sadrian 203296077Sadrian /* security scan: long field names are end-of-header */ 204296077Sadrian if (strlen(fname) > 100) 205296077Sadrian return H_EOH; 206296077Sadrian 207296077Sadrian /* check to see if it represents a ruleset call */ 208296077Sadrian if (bitset(pflag, CHHDR_DEF)) 209296077Sadrian { 210296077Sadrian char hbuf[50]; 211296077Sadrian 212296077Sadrian (void) expand(fvalue, hbuf, sizeof hbuf, e); 213296077Sadrian for (p = hbuf; isascii(*p) && isspace(*p); ) 214296077Sadrian p++; 215296077Sadrian if ((*p++ & 0377) == CALLSUBR) 216296077Sadrian { 217296077Sadrian auto char *endp; 218296077Sadrian bool strc; 219296077Sadrian 220296077Sadrian strc = *p == '+'; /* strip comments? */ 221296077Sadrian if (strc) 222296077Sadrian ++p; 223296077Sadrian if (strtorwset(p, &endp, ST_ENTER) > 0) 224296077Sadrian { 225296077Sadrian *endp = '\0'; 226296077Sadrian s = stab(fname, ST_HEADER, ST_ENTER); 227296077Sadrian s->s_header.hi_ruleset = newstr(p); 228296077Sadrian if (!strc) 229296077Sadrian s->s_header.hi_flags |= H_STRIPCOMM; 230296077Sadrian } 231296077Sadrian return 0; 232296077Sadrian } 233296077Sadrian } 234296077Sadrian 235296077Sadrian /* see if it is a known type */ 236296077Sadrian s = stab(fname, ST_HEADER, ST_FIND); 237296077Sadrian if (s != NULL) 238296077Sadrian hi = &s->s_header; 239296077Sadrian else 240296077Sadrian hi = &NormalHeader; 241296077Sadrian 242296077Sadrian if (tTd(31, 9)) 243296077Sadrian { 244296077Sadrian if (s == NULL) 245296077Sadrian dprintf("no header flags match\n"); 246296077Sadrian else 247296077Sadrian dprintf("header match, flags=%lx, ruleset=%s\n", 248296077Sadrian hi->hi_flags, 249296077Sadrian hi->hi_ruleset == NULL ? "<NULL>" : hi->hi_ruleset); 250296077Sadrian } 251296077Sadrian 252296077Sadrian /* see if this is a resent message */ 253296077Sadrian if (!bitset(pflag, CHHDR_DEF) && !headeronly && 254296077Sadrian bitset(H_RESENT, hi->hi_flags)) 255296077Sadrian e->e_flags |= EF_RESENT; 256296077Sadrian 257296077Sadrian /* if this is an Errors-To: header keep track of it now */ 258296077Sadrian if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly && 259296077Sadrian bitset(H_ERRORSTO, hi->hi_flags)) 260296077Sadrian (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 261296077Sadrian 262296077Sadrian /* if this means "end of header" quit now */ 263296077Sadrian if (!headeronly && bitset(H_EOH, hi->hi_flags)) 264296077Sadrian return hi->hi_flags; 265296077Sadrian 266296077Sadrian /* 267296077Sadrian ** Horrible hack to work around problem with Lotus Notes SMTP 268296077Sadrian ** mail gateway, which generates From: headers with newlines in 269296077Sadrian ** them and the <address> on the second line. Although this is 270296077Sadrian ** legal RFC 822, many MUAs don't handle this properly and thus 271296077Sadrian ** never find the actual address. 272296077Sadrian */ 273296077Sadrian 274296077Sadrian if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader) 275296077Sadrian { 276296077Sadrian while ((p = strchr(fvalue, '\n')) != NULL) 277296077Sadrian *p = ' '; 278296077Sadrian } 279296077Sadrian 280296077Sadrian /* 281296077Sadrian ** If there is a check ruleset, verify it against the header. 282296077Sadrian */ 283296077Sadrian 284296077Sadrian if (bitset(pflag, CHHDR_CHECK)) 285296077Sadrian { 286296077Sadrian bool stripcom = FALSE; 287296077Sadrian char *rs; 288296077Sadrian 289296077Sadrian /* no ruleset? look for default */ 290296077Sadrian rs = hi->hi_ruleset; 291296077Sadrian if (rs == NULL) 292296077Sadrian { 293296077Sadrian s = stab("*", ST_HEADER, ST_FIND); 294296077Sadrian if (s != NULL) 295296077Sadrian { 296296077Sadrian rs = (&s->s_header)->hi_ruleset; 297296077Sadrian stripcom = bitset((&s->s_header)->hi_flags, 298296077Sadrian H_STRIPCOMM); 299296077Sadrian } 300296077Sadrian } 301296077Sadrian else 302296077Sadrian stripcom = bitset(hi->hi_flags, H_STRIPCOMM); 303296077Sadrian if (rs != NULL) 304296077Sadrian { 305296077Sadrian int l; 306296077Sadrian char qval[MAXNAME]; 307296077Sadrian char hlen[16]; 308296077Sadrian char *sp, *dp; 309296077Sadrian 310296077Sadrian dp = qval; 311296077Sadrian l = 0; 312296077Sadrian dp[l++] = '"'; 313296077Sadrian for (sp = fvalue; *sp != '\0' && l < MAXNAME - 3; sp++) 314296077Sadrian { 315296077Sadrian switch(*sp) 316296077Sadrian { 317296077Sadrian case '\011': /* ht */ 318296077Sadrian case '\012': /* nl */ 319296077Sadrian case '\013': /* vt */ 320296077Sadrian case '\014': /* np */ 321296077Sadrian case '\015': /* cr */ 322296077Sadrian dp[l++] = ' '; 323296077Sadrian break; 324296077Sadrian case '"': 325296077Sadrian dp[l++] = '\\'; 326296077Sadrian /* FALLTHROUGH */ 327296077Sadrian default: 328296077Sadrian dp[l++] = *sp; 329296077Sadrian break; 330296077Sadrian } 331296077Sadrian } 332296077Sadrian dp[l++] = '"'; 333296077Sadrian dp[l++] = '\0'; 334296077Sadrian l = strlen(fvalue); 335296077Sadrian snprintf(hlen, sizeof hlen, "%d", l); 336296077Sadrian define(macid("{hdrlen}", NULL), newstr(hlen), e); 337296077Sadrian if (l >= MAXNAME) 338296077Sadrian { 339296077Sadrian if (LogLevel > 9) 340296077Sadrian sm_syslog(LOG_WARNING, e->e_id, 341296077Sadrian "Warning: truncated header '%s' before check with '%s' len=%d max=%d", 342296077Sadrian fname, rs, l, MAXNAME - 1); 343296077Sadrian } 344296077Sadrian if ((sp = macvalue(macid("{currHeader}", NULL), e)) != 345296077Sadrian NULL) 346296077Sadrian sm_free(sp); 347296077Sadrian define(macid("{currHeader}", NULL), newstr(qval), e); 348296077Sadrian define(macid("{hdr_name}", NULL), newstr(fname), e); 349296077Sadrian (void) rscheck(rs, fvalue, NULL, e, stripcom, TRUE, 4, 350296077Sadrian NULL); 351296077Sadrian } 352296077Sadrian } 353296077Sadrian 354296077Sadrian /* 355296077Sadrian ** Drop explicit From: if same as what we would generate. 356296077Sadrian ** This is to make MH (which doesn't always give a full name) 357296077Sadrian ** insert the full name information in all circumstances. 358296077Sadrian */ 359296077Sadrian 360296077Sadrian dropfrom = FALSE; 361296077Sadrian p = "resent-from"; 362296077Sadrian if (!bitset(EF_RESENT, e->e_flags)) 363296077Sadrian p += 7; 364296077Sadrian if (!bitset(pflag, CHHDR_DEF) && !headeronly && 365296077Sadrian !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0) 366296077Sadrian { 367296077Sadrian if (tTd(31, 2)) 368296077Sadrian { 369296077Sadrian dprintf("comparing header from (%s) against default (%s or %s)\n", 370296077Sadrian fvalue, e->e_from.q_paddr, e->e_from.q_user); 371296077Sadrian } 372296077Sadrian if (e->e_from.q_paddr != NULL && 373296077Sadrian e->e_from.q_mailer != NULL && 374296077Sadrian bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && 375296077Sadrian (strcmp(fvalue, e->e_from.q_paddr) == 0 || 376296077Sadrian strcmp(fvalue, e->e_from.q_user) == 0)) 377296077Sadrian dropfrom = TRUE; 378296077Sadrian } 379296077Sadrian 380296077Sadrian /* delete default value for this header */ 381296077Sadrian for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 382296077Sadrian { 383296077Sadrian if (strcasecmp(fname, h->h_field) == 0 && 384296077Sadrian !bitset(H_USER, h->h_flags) && 385296077Sadrian !bitset(H_FORCE, h->h_flags)) 386296077Sadrian { 387296077Sadrian if (nullheader) 388296077Sadrian { 389296077Sadrian /* user-supplied value was null */ 390296077Sadrian return 0; 391296077Sadrian } 392296077Sadrian if (dropfrom) 393296077Sadrian { 394296077Sadrian /* make this look like the user entered it */ 395296077Sadrian h->h_flags |= H_USER; 396296077Sadrian return hi->hi_flags; 397296077Sadrian } 398296077Sadrian h->h_value = NULL; 399296077Sadrian if (!cond) 400296077Sadrian { 401296077Sadrian /* copy conditions from default case */ 402296077Sadrian memmove((char *)mopts, (char *)h->h_mflags, 403296077Sadrian sizeof mopts); 404296077Sadrian } 405296077Sadrian h->h_macro = mid; 406296077Sadrian } 407296077Sadrian } 408296077Sadrian 409296077Sadrian /* create a new node */ 410296077Sadrian h = (HDR *) xalloc(sizeof *h); 411296077Sadrian h->h_field = newstr(fname); 412296077Sadrian h->h_value = newstr(fvalue); 413296077Sadrian h->h_link = NULL; 414296077Sadrian memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts); 415296077Sadrian h->h_macro = mid; 416296077Sadrian *hp = h; 417296077Sadrian h->h_flags = hi->hi_flags; 418296077Sadrian if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE)) 419296077Sadrian h->h_flags |= H_USER; 420296077Sadrian 421296077Sadrian /* strip EOH flag if parsing MIME headers */ 422296077Sadrian if (headeronly) 423296077Sadrian h->h_flags &= ~H_EOH; 424296077Sadrian if (bitset(pflag, CHHDR_DEF)) 425296077Sadrian h->h_flags |= H_DEFAULT; 426296077Sadrian if (cond || mid != '\0') 427296077Sadrian h->h_flags |= H_CHECK; 428296077Sadrian 429296077Sadrian /* hack to see if this is a new format message */ 430296077Sadrian if (!bitset(pflag, CHHDR_DEF) && !headeronly && 431296077Sadrian bitset(H_RCPT|H_FROM, h->h_flags) && 432296077Sadrian (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 433296077Sadrian strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 434296077Sadrian { 435296077Sadrian e->e_flags &= ~EF_OLDSTYLE; 436296077Sadrian } 437296077Sadrian 438296077Sadrian return h->h_flags; 439296077Sadrian} 440296077Sadrian/* 441296077Sadrian** ADDHEADER -- add a header entry to the end of the queue. 442296077Sadrian** 443296077Sadrian** This bypasses the special checking of chompheader. 444296077Sadrian** 445296077Sadrian** Parameters: 446296077Sadrian** field -- the name of the header field. 447296077Sadrian** value -- the value of the field. 448296077Sadrian** flags -- flags to add to h_flags. 449296077Sadrian** hdrlist -- an indirect pointer to the header structure list. 450296077Sadrian** 451296077Sadrian** Returns: 452296077Sadrian** none. 453296077Sadrian** 454296077Sadrian** Side Effects: 455296077Sadrian** adds the field on the list of headers for this envelope. 456296077Sadrian*/ 457296077Sadrian 458296077Sadrianvoid 459296077Sadrianaddheader(field, value, flags, hdrlist) 460296077Sadrian char *field; 461296077Sadrian char *value; 462296077Sadrian int flags; 463296077Sadrian HDR **hdrlist; 464296077Sadrian{ 465296077Sadrian register HDR *h; 466296077Sadrian STAB *s; 467296077Sadrian HDR **hp; 468296077Sadrian 469296077Sadrian /* find info struct */ 470296077Sadrian s = stab(field, ST_HEADER, ST_FIND); 471296077Sadrian 472296077Sadrian /* find current place in list -- keep back pointer? */ 473296077Sadrian for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 474296077Sadrian { 475296077Sadrian if (strcasecmp(field, h->h_field) == 0) 476296077Sadrian break; 477296077Sadrian } 478296077Sadrian 479296077Sadrian /* allocate space for new header */ 480296077Sadrian h = (HDR *) xalloc(sizeof *h); 481296077Sadrian h->h_field = field; 482296077Sadrian h->h_value = newstr(value); 483296077Sadrian h->h_link = *hp; 484296077Sadrian h->h_flags = flags; 485296077Sadrian if (s != NULL) 486296077Sadrian h->h_flags |= s->s_header.hi_flags; 487296077Sadrian clrbitmap(h->h_mflags); 488296077Sadrian h->h_macro = '\0'; 489296077Sadrian *hp = h; 490296077Sadrian} 491296077Sadrian/* 492296077Sadrian** HVALUE -- return value of a header. 493296077Sadrian** 494296077Sadrian** Only "real" fields (i.e., ones that have not been supplied 495296077Sadrian** as a default) are used. 496296077Sadrian** 497296077Sadrian** Parameters: 498296077Sadrian** field -- the field name. 499296077Sadrian** header -- the header list. 500296077Sadrian** 501296077Sadrian** Returns: 502296077Sadrian** pointer to the value part. 503296077Sadrian** NULL if not found. 504296077Sadrian** 505296077Sadrian** Side Effects: 506296077Sadrian** none. 507296077Sadrian*/ 508296077Sadrian 509296077Sadrianchar * 510296077Sadrianhvalue(field, header) 511296077Sadrian char *field; 512296077Sadrian HDR *header; 513296077Sadrian{ 514296077Sadrian register HDR *h; 515296077Sadrian 516296077Sadrian for (h = header; h != NULL; h = h->h_link) 517296077Sadrian { 518296077Sadrian if (!bitset(H_DEFAULT, h->h_flags) && 519296077Sadrian strcasecmp(h->h_field, field) == 0) 520296077Sadrian return h->h_value; 521296077Sadrian } 522296077Sadrian return NULL; 523296077Sadrian} 524296077Sadrian/* 525296077Sadrian** ISHEADER -- predicate telling if argument is a header. 526296077Sadrian** 527296077Sadrian** A line is a header if it has a single word followed by 528296077Sadrian** optional white space followed by a colon. 529296077Sadrian** 530296077Sadrian** Header fields beginning with two dashes, although technically 531296077Sadrian** permitted by RFC822, are automatically rejected in order 532296077Sadrian** to make MIME work out. Without this we could have a technically 533296077Sadrian** legal header such as ``--"foo:bar"'' that would also be a legal 534296077Sadrian** MIME separator. 535296077Sadrian** 536296077Sadrian** Parameters: 537296077Sadrian** h -- string to check for possible headerness. 538296077Sadrian** 539296077Sadrian** Returns: 540296077Sadrian** TRUE if h is a header. 541296077Sadrian** FALSE otherwise. 542296077Sadrian** 543296077Sadrian** Side Effects: 544296077Sadrian** none. 545296077Sadrian*/ 546296077Sadrian 547296077Sadrianbool 548296077Sadrianisheader(h) 549296077Sadrian char *h; 550296077Sadrian{ 551296077Sadrian register char *s = h; 552296077Sadrian 553296077Sadrian if (s[0] == '-' && s[1] == '-') 554296077Sadrian return FALSE; 555296077Sadrian 556296077Sadrian while (*s > ' ' && *s != ':' && *s != '\0') 557296077Sadrian s++; 558296077Sadrian 559296077Sadrian if (h == s) 560296077Sadrian return FALSE; 561296077Sadrian 562296077Sadrian /* following technically violates RFC822 */ 563296077Sadrian while (isascii(*s) && isspace(*s)) 564296077Sadrian s++; 565296077Sadrian 566296077Sadrian return (*s == ':'); 567296077Sadrian} 568296077Sadrian/* 569296077Sadrian** EATHEADER -- run through the stored header and extract info. 570297793Spfg** 571296077Sadrian** Parameters: 572296077Sadrian** e -- the envelope to process. 573296077Sadrian** full -- if set, do full processing (e.g., compute 574296077Sadrian** message priority). This should not be set 575296077Sadrian** when reading a queue file because some info 576296077Sadrian** needed to compute the priority is wrong. 577296077Sadrian** 578296077Sadrian** Returns: 579296077Sadrian** none. 580296077Sadrian** 581296077Sadrian** Side Effects: 582296077Sadrian** Sets a bunch of global variables from information 583296077Sadrian** in the collected header. 584296077Sadrian** Aborts the message if the hop count is exceeded. 585296077Sadrian*/ 586296077Sadrian 587296077Sadrianvoid 588296077Sadrianeatheader(e, full) 589296077Sadrian register ENVELOPE *e; 590296077Sadrian bool full; 591296077Sadrian{ 592296077Sadrian register HDR *h; 593296077Sadrian register char *p; 594296077Sadrian int hopcnt = 0; 595296077Sadrian char *msgid; 596296077Sadrian char buf[MAXLINE]; 597296077Sadrian 598296077Sadrian /* 599296077Sadrian ** Set up macros for possible expansion in headers. 600296077Sadrian */ 601296077Sadrian 602296077Sadrian define('f', e->e_sender, e); 603296077Sadrian define('g', e->e_sender, e); 604296077Sadrian if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 605296077Sadrian define('u', e->e_origrcpt, e); 606296077Sadrian else 607296077Sadrian define('u', NULL, e); 608296077Sadrian 609296077Sadrian /* full name of from person */ 610296077Sadrian p = hvalue("full-name", e->e_header); 611296077Sadrian if (p != NULL) 612296077Sadrian { 613296077Sadrian if (!rfc822_string(p)) 614296077Sadrian { 615296077Sadrian /* 616296077Sadrian ** Quote a full name with special characters 617296077Sadrian ** as a comment so crackaddr() doesn't destroy 618296077Sadrian ** the name portion of the address. 619296077Sadrian */ 620296077Sadrian p = addquotes(p); 621296077Sadrian } 622296077Sadrian define('x', p, e); 623296077Sadrian } 624296077Sadrian 625296077Sadrian if (tTd(32, 1)) 626296077Sadrian dprintf("----- collected header -----\n"); 627296077Sadrian msgid = NULL; 628297793Spfg for (h = e->e_header; h != NULL; h = h->h_link) 629296077Sadrian { 630296077Sadrian if (tTd(32, 1)) 631296077Sadrian dprintf("%s: ", h->h_field); 632296077Sadrian if (h->h_value == NULL) 633296077Sadrian { 634296077Sadrian if (tTd(32, 1)) 635296077Sadrian dprintf("<NULL>\n"); 636296077Sadrian continue; 637296077Sadrian } 638296077Sadrian 639296077Sadrian /* do early binding */ 640296077Sadrian if (bitset(H_DEFAULT, h->h_flags) && 641296077Sadrian !bitset(H_BINDLATE, h->h_flags)) 642296077Sadrian { 643296077Sadrian if (tTd(32, 1)) 644296077Sadrian { 645296077Sadrian dprintf("("); 646296077Sadrian xputs(h->h_value); 647296077Sadrian dprintf(") "); 648296077Sadrian } 649296077Sadrian expand(h->h_value, buf, sizeof buf, e); 650296077Sadrian if (buf[0] != '\0') 651296077Sadrian { 652296077Sadrian if (bitset(H_FROM, h->h_flags)) 653296077Sadrian expand(crackaddr(buf), buf, sizeof buf, e); 654296077Sadrian h->h_value = newstr(buf); 655296077Sadrian h->h_flags &= ~H_DEFAULT; 656296077Sadrian } 657296077Sadrian } 658296077Sadrian 659296077Sadrian if (tTd(32, 1)) 660296077Sadrian { 661296077Sadrian xputs(h->h_value); 662296077Sadrian dprintf("\n"); 663296077Sadrian } 664296077Sadrian 665296077Sadrian /* count the number of times it has been processed */ 666296077Sadrian if (bitset(H_TRACE, h->h_flags)) 667296077Sadrian hopcnt++; 668296077Sadrian 669296077Sadrian /* send to this person if we so desire */ 670296077Sadrian if (GrabTo && bitset(H_RCPT, h->h_flags) && 671296077Sadrian !bitset(H_DEFAULT, h->h_flags) && 672296077Sadrian (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 673296077Sadrian { 674296077Sadrian#if 0 675296077Sadrian int saveflags = e->e_flags; 676296077Sadrian#endif /* 0 */ 677296077Sadrian 678296077Sadrian (void) sendtolist(h->h_value, NULLADDR, 679296077Sadrian &e->e_sendqueue, 0, e); 680296077Sadrian 681296077Sadrian#if 0 682296077Sadrian /* 683296077Sadrian ** Change functionality so a fatal error on an 684296077Sadrian ** address doesn't affect the entire envelope. 685296077Sadrian */ 686296077Sadrian 687296077Sadrian /* delete fatal errors generated by this address */ 688296077Sadrian if (!bitset(EF_FATALERRS, saveflags)) 689296077Sadrian e->e_flags &= ~EF_FATALERRS; 690296077Sadrian#endif /* 0 */ 691296077Sadrian } 692296077Sadrian 693296077Sadrian /* save the message-id for logging */ 694296077Sadrian p = "resent-message-id"; 695296077Sadrian if (!bitset(EF_RESENT, e->e_flags)) 696296077Sadrian p += 7; 697296077Sadrian if (strcasecmp(h->h_field, p) == 0) 698296077Sadrian { 699296077Sadrian msgid = h->h_value; 700296077Sadrian while (isascii(*msgid) && isspace(*msgid)) 701296077Sadrian msgid++; 702296077Sadrian } 703296077Sadrian } 704296077Sadrian if (tTd(32, 1)) 705296077Sadrian dprintf("----------------------------\n"); 706296077Sadrian 707296077Sadrian /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 708296077Sadrian if (OpMode == MD_VERIFY) 709296077Sadrian return; 710296077Sadrian 711296077Sadrian /* store hop count */ 712296077Sadrian if (hopcnt > e->e_hopcount) 713296077Sadrian e->e_hopcount = hopcnt; 714296077Sadrian 715296077Sadrian /* message priority */ 716296077Sadrian p = hvalue("precedence", e->e_header); 717296077Sadrian if (p != NULL) 718296077Sadrian e->e_class = priencode(p); 719296077Sadrian if (e->e_class < 0) 720296077Sadrian e->e_timeoutclass = TOC_NONURGENT; 721296077Sadrian else if (e->e_class > 0) 722296077Sadrian e->e_timeoutclass = TOC_URGENT; 723296077Sadrian if (full) 724296077Sadrian { 725296077Sadrian e->e_msgpriority = e->e_msgsize 726296077Sadrian - e->e_class * WkClassFact 727296077Sadrian + e->e_nrcpts * WkRecipFact; 728296077Sadrian } 729296077Sadrian 730296077Sadrian /* message timeout priority */ 731296077Sadrian p = hvalue("priority", e->e_header); 732296077Sadrian if (p != NULL) 733296077Sadrian { 734296077Sadrian /* (this should be in the configuration file) */ 735296077Sadrian if (strcasecmp(p, "urgent") == 0) 736296077Sadrian e->e_timeoutclass = TOC_URGENT; 737296077Sadrian else if (strcasecmp(p, "normal") == 0) 738296077Sadrian e->e_timeoutclass = TOC_NORMAL; 739296077Sadrian else if (strcasecmp(p, "non-urgent") == 0) 740296077Sadrian e->e_timeoutclass = TOC_NONURGENT; 741296077Sadrian } 742296077Sadrian 743296077Sadrian /* date message originated */ 744296077Sadrian p = hvalue("posted-date", e->e_header); 745296077Sadrian if (p == NULL) 746296077Sadrian p = hvalue("date", e->e_header); 747296077Sadrian if (p != NULL) 748296077Sadrian define('a', p, e); 749296077Sadrian 750296077Sadrian /* check to see if this is a MIME message */ 751296077Sadrian if ((e->e_bodytype != NULL && 752296077Sadrian strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 753296077Sadrian hvalue("MIME-Version", e->e_header) != NULL) 754296077Sadrian { 755296077Sadrian e->e_flags |= EF_IS_MIME; 756296077Sadrian if (HasEightBits) 757296077Sadrian e->e_bodytype = "8BITMIME"; 758296077Sadrian } 759296077Sadrian else if ((p = hvalue("Content-Type", e->e_header)) != NULL) 760296077Sadrian { 761296077Sadrian /* this may be an RFC 1049 message */ 762296077Sadrian p = strpbrk(p, ";/"); 763296077Sadrian if (p == NULL || *p == ';') 764296077Sadrian { 765296077Sadrian /* yep, it is */ 766296077Sadrian e->e_flags |= EF_DONT_MIME; 767296077Sadrian } 768296077Sadrian } 769296077Sadrian 770296077Sadrian /* 771296077Sadrian ** From person in antiquated ARPANET mode 772296077Sadrian ** required by UK Grey Book e-mail gateways (sigh) 773296077Sadrian */ 774296077Sadrian 775296077Sadrian if (OpMode == MD_ARPAFTP) 776296077Sadrian { 777296077Sadrian register struct hdrinfo *hi; 778296077Sadrian 779296077Sadrian for (hi = HdrInfo; hi->hi_field != NULL; hi++) 780296077Sadrian { 781296077Sadrian if (bitset(H_FROM, hi->hi_flags) && 782296077Sadrian (!bitset(H_RESENT, hi->hi_flags) || 783296077Sadrian bitset(EF_RESENT, e->e_flags)) && 784296077Sadrian (p = hvalue(hi->hi_field, e->e_header)) != NULL) 785296077Sadrian break; 786296077Sadrian } 787296077Sadrian if (hi->hi_field != NULL) 788296077Sadrian { 789296077Sadrian if (tTd(32, 2)) 790296077Sadrian dprintf("eatheader: setsender(*%s == %s)\n", 791296077Sadrian hi->hi_field, p); 792296077Sadrian setsender(p, e, NULL, '\0', TRUE); 793296077Sadrian } 794296077Sadrian } 795296077Sadrian 796296077Sadrian /* 797296077Sadrian ** Log collection information. 798296077Sadrian */ 799296077Sadrian 800296077Sadrian if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 801296077Sadrian logsender(e, msgid); 802296077Sadrian e->e_flags &= ~EF_LOGSENDER; 803296077Sadrian} 804296077Sadrian/* 805296077Sadrian** LOGSENDER -- log sender information 806296077Sadrian** 807296077Sadrian** Parameters: 808296077Sadrian** e -- the envelope to log 809296077Sadrian** msgid -- the message id 810296077Sadrian** 811296077Sadrian** Returns: 812296077Sadrian** none 813296077Sadrian*/ 814296077Sadrian 815296077Sadrianvoid 816296077Sadrianlogsender(e, msgid) 817296077Sadrian register ENVELOPE *e; 818296077Sadrian char *msgid; 819296077Sadrian{ 820296077Sadrian char *name; 821296077Sadrian register char *sbp; 822296077Sadrian register char *p; 823296077Sadrian int l; 824296077Sadrian char hbuf[MAXNAME + 1]; 825296077Sadrian char sbuf[MAXLINE + 1]; 826296077Sadrian char mbuf[MAXNAME + 1]; 827296077Sadrian 828296077Sadrian /* don't allow newlines in the message-id */ 829296077Sadrian if (msgid != NULL) 830296077Sadrian { 831296077Sadrian l = strlen(msgid); 832296077Sadrian if (l > sizeof mbuf - 1) 833296077Sadrian l = sizeof mbuf - 1; 834296077Sadrian memmove(mbuf, msgid, l); 835296077Sadrian mbuf[l] = '\0'; 836296077Sadrian p = mbuf; 837296077Sadrian while ((p = strchr(p, '\n')) != NULL) 838296077Sadrian *p++ = ' '; 839296077Sadrian } 840296077Sadrian 841296077Sadrian if (bitset(EF_RESPONSE, e->e_flags)) 842296077Sadrian name = "[RESPONSE]"; 843296077Sadrian else if ((name = macvalue('_', e)) != NULL) 844296077Sadrian /* EMPTY */ 845296077Sadrian ; 846296077Sadrian else if (RealHostName == NULL) 847296077Sadrian name = "localhost"; 848296077Sadrian else if (RealHostName[0] == '[') 849296077Sadrian name = RealHostName; 850296077Sadrian else 851296077Sadrian { 852296077Sadrian name = hbuf; 853296077Sadrian (void) snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName); 854296077Sadrian if (RealHostAddr.sa.sa_family != 0) 855296077Sadrian { 856296077Sadrian p = &hbuf[strlen(hbuf)]; 857296077Sadrian (void) snprintf(p, SPACELEFT(hbuf, p), " (%.100s)", 858296077Sadrian anynet_ntoa(&RealHostAddr)); 859296077Sadrian } 860296077Sadrian } 861296077Sadrian 862296077Sadrian /* some versions of syslog only take 5 printf args */ 863296077Sadrian#if (SYSLOG_BUFSIZE) >= 256 864296077Sadrian sbp = sbuf; 865296077Sadrian snprintf(sbp, SPACELEFT(sbuf, sbp), 866296077Sadrian "from=%.200s, size=%ld, class=%d, nrcpts=%d", 867296077Sadrian e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 868296077Sadrian e->e_msgsize, e->e_class, e->e_nrcpts); 869296077Sadrian sbp += strlen(sbp); 870296077Sadrian if (msgid != NULL) 871296077Sadrian { 872296077Sadrian snprintf(sbp, SPACELEFT(sbuf, sbp), ", msgid=%.100s", mbuf); 873296077Sadrian sbp += strlen(sbp); 874296077Sadrian } 875296077Sadrian if (e->e_bodytype != NULL) 876296077Sadrian { 877296077Sadrian (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", bodytype=%.20s", 878296077Sadrian e->e_bodytype); 879296077Sadrian sbp += strlen(sbp); 880296077Sadrian } 881299314Sadrian p = macvalue('r', e); 882299314Sadrian if (p != NULL) 883299314Sadrian { 884299314Sadrian (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", proto=%.20s", p); 885299314Sadrian sbp += strlen(sbp); 886299314Sadrian } 887299314Sadrian p = macvalue(macid("{daemon_name}", NULL), e); 888299314Sadrian if (p != NULL) 889299314Sadrian { 890299314Sadrian (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", daemon=%.20s", p); 891299314Sadrian sbp += strlen(sbp); 892299314Sadrian } 893299314Sadrian# if SASL 894299314Sadrian p = macvalue(macid("{auth_type}", NULL), e); 895299314Sadrian if (p != NULL) 896299314Sadrian { 897299314Sadrian (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", mech=%.12s", p); 898299314Sadrian sbp += strlen(sbp); 899299314Sadrian } 900299314Sadrian p = macvalue(macid("{auth_author}", NULL), e); 901296077Sadrian if (p != NULL) 902296077Sadrian { 903296077Sadrian (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.30s", p); 904296077Sadrian sbp += strlen(sbp); 905296077Sadrian } 906296077Sadrian# endif /* SASL */ 907296077Sadrian sm_syslog(LOG_INFO, e->e_id, 908296077Sadrian "%.850s, relay=%.100s", 909296077Sadrian sbuf, name); 910296077Sadrian 911296077Sadrian#else /* (SYSLOG_BUFSIZE) >= 256 */ 912296077Sadrian 913296077Sadrian sm_syslog(LOG_INFO, e->e_id, 914296077Sadrian "from=%s", 915296077Sadrian e->e_from.q_paddr == NULL ? "<NONE>" 916296077Sadrian : shortenstring(e->e_from.q_paddr, 83)); 917 sm_syslog(LOG_INFO, e->e_id, 918 "size=%ld, class=%ld, nrcpts=%d", 919 e->e_msgsize, e->e_class, e->e_nrcpts); 920 if (msgid != NULL) 921 sm_syslog(LOG_INFO, e->e_id, 922 "msgid=%s", 923 shortenstring(mbuf, 83)); 924 sbp = sbuf; 925 *sbp = '\0'; 926 if (e->e_bodytype != NULL) 927 { 928 snprintf(sbp, SPACELEFT(sbuf, sbp), "bodytype=%.20s, ", e->e_bodytype); 929 sbp += strlen(sbp); 930 } 931 p = macvalue('r', e); 932 if (p != NULL) 933 { 934 snprintf(sbp, SPACELEFT(sbuf, sbp), "proto=%.20s, ", p); 935 sbp += strlen(sbp); 936 } 937 sm_syslog(LOG_INFO, e->e_id, 938 "%.400srelay=%.100s", sbuf, name); 939#endif /* (SYSLOG_BUFSIZE) >= 256 */ 940} 941/* 942** PRIENCODE -- encode external priority names into internal values. 943** 944** Parameters: 945** p -- priority in ascii. 946** 947** Returns: 948** priority as a numeric level. 949** 950** Side Effects: 951** none. 952*/ 953 954static int 955priencode(p) 956 char *p; 957{ 958 register int i; 959 960 for (i = 0; i < NumPriorities; i++) 961 { 962 if (strcasecmp(p, Priorities[i].pri_name) == 0) 963 return Priorities[i].pri_val; 964 } 965 966 /* unknown priority */ 967 return 0; 968} 969/* 970** CRACKADDR -- parse an address and turn it into a macro 971** 972** This doesn't actually parse the address -- it just extracts 973** it and replaces it with "$g". The parse is totally ad hoc 974** and isn't even guaranteed to leave something syntactically 975** identical to what it started with. However, it does leave 976** something semantically identical. 977** 978** This algorithm has been cleaned up to handle a wider range 979** of cases -- notably quoted and backslash escaped strings. 980** This modification makes it substantially better at preserving 981** the original syntax. 982** 983** Parameters: 984** addr -- the address to be cracked. 985** 986** Returns: 987** a pointer to the new version. 988** 989** Side Effects: 990** none. 991** 992** Warning: 993** The return value is saved in local storage and should 994** be copied if it is to be reused. 995*/ 996 997char * 998crackaddr(addr) 999 register char *addr; 1000{ 1001 register char *p; 1002 register char c; 1003 int cmtlev; 1004 int realcmtlev; 1005 int anglelev, realanglelev; 1006 int copylev; 1007 int bracklev; 1008 bool qmode; 1009 bool realqmode; 1010 bool skipping; 1011 bool putgmac = FALSE; 1012 bool quoteit = FALSE; 1013 bool gotangle = FALSE; 1014 bool gotcolon = FALSE; 1015 register char *bp; 1016 char *buflim; 1017 char *bufhead; 1018 char *addrhead; 1019 static char buf[MAXNAME + 1]; 1020 1021 if (tTd(33, 1)) 1022 dprintf("crackaddr(%s)\n", addr); 1023 1024 /* strip leading spaces */ 1025 while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 1026 addr++; 1027 1028 /* 1029 ** Start by assuming we have no angle brackets. This will be 1030 ** adjusted later if we find them. 1031 */ 1032 1033 bp = bufhead = buf; 1034 buflim = &buf[sizeof buf - 7]; 1035 p = addrhead = addr; 1036 copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 1037 bracklev = 0; 1038 qmode = realqmode = FALSE; 1039 1040 while ((c = *p++) != '\0') 1041 { 1042 /* 1043 ** If the buffer is overful, go into a special "skipping" 1044 ** mode that tries to keep legal syntax but doesn't actually 1045 ** output things. 1046 */ 1047 1048 skipping = bp >= buflim; 1049 1050 if (copylev > 0 && !skipping) 1051 *bp++ = c; 1052 1053 /* check for backslash escapes */ 1054 if (c == '\\') 1055 { 1056 /* arrange to quote the address */ 1057 if (cmtlev <= 0 && !qmode) 1058 quoteit = TRUE; 1059 1060 if ((c = *p++) == '\0') 1061 { 1062 /* too far */ 1063 p--; 1064 goto putg; 1065 } 1066 if (copylev > 0 && !skipping) 1067 *bp++ = c; 1068 goto putg; 1069 } 1070 1071 /* check for quoted strings */ 1072 if (c == '"' && cmtlev <= 0) 1073 { 1074 qmode = !qmode; 1075 if (copylev > 0 && !skipping) 1076 realqmode = !realqmode; 1077 continue; 1078 } 1079 if (qmode) 1080 goto putg; 1081 1082 /* check for comments */ 1083 if (c == '(') 1084 { 1085 cmtlev++; 1086 1087 /* allow space for closing paren */ 1088 if (!skipping) 1089 { 1090 buflim--; 1091 realcmtlev++; 1092 if (copylev++ <= 0) 1093 { 1094 if (bp != bufhead) 1095 *bp++ = ' '; 1096 *bp++ = c; 1097 } 1098 } 1099 } 1100 if (cmtlev > 0) 1101 { 1102 if (c == ')') 1103 { 1104 cmtlev--; 1105 copylev--; 1106 if (!skipping) 1107 { 1108 realcmtlev--; 1109 buflim++; 1110 } 1111 } 1112 continue; 1113 } 1114 else if (c == ')') 1115 { 1116 /* syntax error: unmatched ) */ 1117 if (copylev > 0 && !skipping) 1118 bp--; 1119 } 1120 1121 /* count nesting on [ ... ] (for IPv6 domain literals) */ 1122 if (c == '[') 1123 bracklev++; 1124 else if (c == ']') 1125 bracklev--; 1126 1127 /* check for group: list; syntax */ 1128 if (c == ':' && anglelev <= 0 && bracklev <= 0 && 1129 !gotcolon && !ColonOkInAddr) 1130 { 1131 register char *q; 1132 1133 /* 1134 ** Check for DECnet phase IV ``::'' (host::user) 1135 ** or ** DECnet phase V ``:.'' syntaxes. The latter 1136 ** covers ``user@DEC:.tay.myhost'' and 1137 ** ``DEC:.tay.myhost::user'' syntaxes (bletch). 1138 */ 1139 1140 if (*p == ':' || *p == '.') 1141 { 1142 if (cmtlev <= 0 && !qmode) 1143 quoteit = TRUE; 1144 if (copylev > 0 && !skipping) 1145 { 1146 *bp++ = c; 1147 *bp++ = *p; 1148 } 1149 p++; 1150 goto putg; 1151 } 1152 1153 gotcolon = TRUE; 1154 1155 bp = bufhead; 1156 if (quoteit) 1157 { 1158 *bp++ = '"'; 1159 1160 /* back up over the ':' and any spaces */ 1161 --p; 1162 while (isascii(*--p) && isspace(*p)) 1163 continue; 1164 p++; 1165 } 1166 for (q = addrhead; q < p; ) 1167 { 1168 c = *q++; 1169 if (bp < buflim) 1170 { 1171 if (quoteit && c == '"') 1172 *bp++ = '\\'; 1173 *bp++ = c; 1174 } 1175 } 1176 if (quoteit) 1177 { 1178 if (bp == &bufhead[1]) 1179 bp--; 1180 else 1181 *bp++ = '"'; 1182 while ((c = *p++) != ':') 1183 { 1184 if (bp < buflim) 1185 *bp++ = c; 1186 } 1187 *bp++ = c; 1188 } 1189 1190 /* any trailing white space is part of group: */ 1191 while (isascii(*p) && isspace(*p) && bp < buflim) 1192 *bp++ = *p++; 1193 copylev = 0; 1194 putgmac = quoteit = FALSE; 1195 bufhead = bp; 1196 addrhead = p; 1197 continue; 1198 } 1199 1200 if (c == ';' && copylev <= 0 && !ColonOkInAddr) 1201 { 1202 if (bp < buflim) 1203 *bp++ = c; 1204 } 1205 1206 /* check for characters that may have to be quoted */ 1207 if (strchr(MustQuoteChars, c) != NULL) 1208 { 1209 /* 1210 ** If these occur as the phrase part of a <> 1211 ** construct, but are not inside of () or already 1212 ** quoted, they will have to be quoted. Note that 1213 ** now (but don't actually do the quoting). 1214 */ 1215 1216 if (cmtlev <= 0 && !qmode) 1217 quoteit = TRUE; 1218 } 1219 1220 /* check for angle brackets */ 1221 if (c == '<') 1222 { 1223 register char *q; 1224 1225 /* assume first of two angles is bogus */ 1226 if (gotangle) 1227 quoteit = TRUE; 1228 gotangle = TRUE; 1229 1230 /* oops -- have to change our mind */ 1231 anglelev = 1; 1232 if (!skipping) 1233 realanglelev = 1; 1234 1235 bp = bufhead; 1236 if (quoteit) 1237 { 1238 *bp++ = '"'; 1239 1240 /* back up over the '<' and any spaces */ 1241 --p; 1242 while (isascii(*--p) && isspace(*p)) 1243 continue; 1244 p++; 1245 } 1246 for (q = addrhead; q < p; ) 1247 { 1248 c = *q++; 1249 if (bp < buflim) 1250 { 1251 if (quoteit && c == '"') 1252 *bp++ = '\\'; 1253 *bp++ = c; 1254 } 1255 } 1256 if (quoteit) 1257 { 1258 if (bp == &buf[1]) 1259 bp--; 1260 else 1261 *bp++ = '"'; 1262 while ((c = *p++) != '<') 1263 { 1264 if (bp < buflim) 1265 *bp++ = c; 1266 } 1267 *bp++ = c; 1268 } 1269 copylev = 0; 1270 putgmac = quoteit = FALSE; 1271 continue; 1272 } 1273 1274 if (c == '>') 1275 { 1276 if (anglelev > 0) 1277 { 1278 anglelev--; 1279 if (!skipping) 1280 { 1281 realanglelev--; 1282 buflim++; 1283 } 1284 } 1285 else if (!skipping) 1286 { 1287 /* syntax error: unmatched > */ 1288 if (copylev > 0) 1289 bp--; 1290 quoteit = TRUE; 1291 continue; 1292 } 1293 if (copylev++ <= 0) 1294 *bp++ = c; 1295 continue; 1296 } 1297 1298 /* must be a real address character */ 1299 putg: 1300 if (copylev <= 0 && !putgmac) 1301 { 1302 if (bp > bufhead && bp[-1] == ')') 1303 *bp++ = ' '; 1304 *bp++ = MACROEXPAND; 1305 *bp++ = 'g'; 1306 putgmac = TRUE; 1307 } 1308 } 1309 1310 /* repair any syntactic damage */ 1311 if (realqmode) 1312 *bp++ = '"'; 1313 while (realcmtlev-- > 0) 1314 *bp++ = ')'; 1315 while (realanglelev-- > 0) 1316 *bp++ = '>'; 1317 *bp++ = '\0'; 1318 1319 if (tTd(33, 1)) 1320 { 1321 dprintf("crackaddr=>`"); 1322 xputs(buf); 1323 dprintf("'\n"); 1324 } 1325 1326 return buf; 1327} 1328/* 1329** PUTHEADER -- put the header part of a message from the in-core copy 1330** 1331** Parameters: 1332** mci -- the connection information. 1333** hdr -- the header to put. 1334** e -- envelope to use. 1335** flags -- MIME conversion flags. 1336** 1337** Returns: 1338** none. 1339** 1340** Side Effects: 1341** none. 1342*/ 1343 1344/* 1345 * Macro for fast max (not available in e.g. DG/UX, 386/ix). 1346 */ 1347#ifndef MAX 1348# define MAX(a,b) (((a)>(b))?(a):(b)) 1349#endif /* ! MAX */ 1350 1351void 1352putheader(mci, hdr, e, flags) 1353 register MCI *mci; 1354 HDR *hdr; 1355 register ENVELOPE *e; 1356 int flags; 1357{ 1358 register HDR *h; 1359 char buf[MAX(MAXLINE,BUFSIZ)]; 1360 char obuf[MAXLINE]; 1361 1362 if (tTd(34, 1)) 1363 dprintf("--- putheader, mailer = %s ---\n", 1364 mci->mci_mailer->m_name); 1365 1366 /* 1367 ** If we're in MIME mode, we're not really in the header of the 1368 ** message, just the header of one of the parts of the body of 1369 ** the message. Therefore MCIF_INHEADER should not be turned on. 1370 */ 1371 1372 if (!bitset(MCIF_INMIME, mci->mci_flags)) 1373 mci->mci_flags |= MCIF_INHEADER; 1374 1375 for (h = hdr; h != NULL; h = h->h_link) 1376 { 1377 register char *p = h->h_value; 1378 1379 if (tTd(34, 11)) 1380 { 1381 dprintf(" %s: ", h->h_field); 1382 xputs(p); 1383 } 1384 1385 /* Skip empty headers */ 1386 if (h->h_value == NULL) 1387 continue; 1388 1389 /* heuristic shortening of MIME fields to avoid MUA overflows */ 1390 if (MaxMimeFieldLength > 0 && 1391 wordinclass(h->h_field, 1392 macid("{checkMIMEFieldHeaders}", NULL))) 1393 { 1394 size_t len; 1395 1396 len = fix_mime_header(h->h_value); 1397 if (len > 0) 1398 { 1399 sm_syslog(LOG_ALERT, e->e_id, 1400 "Truncated MIME %s header due to field size (length = %ld) (possible attack)", 1401 h->h_field, (unsigned long) len); 1402 if (tTd(34, 11)) 1403 dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", 1404 h->h_field, 1405 (unsigned long) len); 1406 } 1407 } 1408 1409 if (MaxMimeHeaderLength > 0 && 1410 wordinclass(h->h_field, 1411 macid("{checkMIMETextHeaders}", NULL))) 1412 { 1413 size_t len; 1414 1415 len = strlen(h->h_value); 1416 if (len > (size_t) MaxMimeHeaderLength) 1417 { 1418 h->h_value[MaxMimeHeaderLength - 1] = '\0'; 1419 sm_syslog(LOG_ALERT, e->e_id, 1420 "Truncated long MIME %s header (length = %ld) (possible attack)", 1421 h->h_field, (unsigned long) len); 1422 if (tTd(34, 11)) 1423 dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1424 h->h_field, 1425 (unsigned long) len); 1426 } 1427 } 1428 1429 if (MaxMimeHeaderLength > 0 && 1430 wordinclass(h->h_field, 1431 macid("{checkMIMEHeaders}", NULL))) 1432 { 1433 size_t len; 1434 1435 len = strlen(h->h_value); 1436 if (shorten_rfc822_string(h->h_value, 1437 MaxMimeHeaderLength)) 1438 { 1439 sm_syslog(LOG_ALERT, e->e_id, 1440 "Truncated long MIME %s header (length = %ld) (possible attack)", 1441 h->h_field, (unsigned long) len); 1442 if (tTd(34, 11)) 1443 dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1444 h->h_field, 1445 (unsigned long) len); 1446 } 1447 } 1448 1449 /* 1450 ** Suppress Content-Transfer-Encoding: if we are MIMEing 1451 ** and we are potentially converting from 8 bit to 7 bit 1452 ** MIME. If converting, add a new CTE header in 1453 ** mime8to7(). 1454 */ 1455 if (bitset(H_CTE, h->h_flags) && 1456 bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 1457 mci->mci_flags) && 1458 !bitset(M87F_NO8TO7, flags)) 1459 { 1460 if (tTd(34, 11)) 1461 dprintf(" (skipped (content-transfer-encoding))\n"); 1462 continue; 1463 } 1464 1465 if (bitset(MCIF_INMIME, mci->mci_flags)) 1466 { 1467 if (tTd(34, 11)) 1468 dprintf("\n"); 1469 put_vanilla_header(h, p, mci); 1470 continue; 1471 } 1472 1473 if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 1474 !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && 1475 (h->h_macro == '\0' || 1476 macvalue(bitidx(h->h_macro), e) == NULL)) 1477 { 1478 if (tTd(34, 11)) 1479 dprintf(" (skipped)\n"); 1480 continue; 1481 } 1482 1483 /* handle Resent-... headers specially */ 1484 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 1485 { 1486 if (tTd(34, 11)) 1487 dprintf(" (skipped (resent))\n"); 1488 continue; 1489 } 1490 1491 /* suppress return receipts if requested */ 1492 if (bitset(H_RECEIPTTO, h->h_flags) && 1493 (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) 1494 { 1495 if (tTd(34, 11)) 1496 dprintf(" (skipped (receipt))\n"); 1497 continue; 1498 } 1499 1500 /* macro expand value if generated internally */ 1501 if (bitset(H_DEFAULT, h->h_flags) || 1502 bitset(H_BINDLATE, h->h_flags)) 1503 { 1504 expand(p, buf, sizeof buf, e); 1505 p = buf; 1506 if (*p == '\0') 1507 { 1508 if (tTd(34, 11)) 1509 dprintf(" (skipped -- null value)\n"); 1510 continue; 1511 } 1512 } 1513 1514 if (bitset(H_BCC, h->h_flags)) 1515 { 1516 /* Bcc: field -- either truncate or delete */ 1517 if (bitset(EF_DELETE_BCC, e->e_flags)) 1518 { 1519 if (tTd(34, 11)) 1520 dprintf(" (skipped -- bcc)\n"); 1521 } 1522 else 1523 { 1524 /* no other recipient headers: truncate value */ 1525 (void) snprintf(obuf, sizeof obuf, "%s:", 1526 h->h_field); 1527 putline(obuf, mci); 1528 } 1529 continue; 1530 } 1531 1532 if (tTd(34, 11)) 1533 dprintf("\n"); 1534 1535 if (bitset(H_FROM|H_RCPT, h->h_flags)) 1536 { 1537 /* address field */ 1538 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 1539 1540 if (bitset(H_FROM, h->h_flags)) 1541 oldstyle = FALSE; 1542 commaize(h, p, oldstyle, mci, e); 1543 } 1544 else 1545 { 1546 put_vanilla_header(h, p, mci); 1547 } 1548 } 1549 1550 /* 1551 ** If we are converting this to a MIME message, add the 1552 ** MIME headers (but not in MIME mode!). 1553 */ 1554 1555#if MIME8TO7 1556 if (bitset(MM_MIME8BIT, MimeMode) && 1557 bitset(EF_HAS8BIT, e->e_flags) && 1558 !bitset(EF_DONT_MIME, e->e_flags) && 1559 !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 1560 !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) && 1561 hvalue("MIME-Version", e->e_header) == NULL) 1562 { 1563 putline("MIME-Version: 1.0", mci); 1564 if (hvalue("Content-Type", e->e_header) == NULL) 1565 { 1566 snprintf(obuf, sizeof obuf, 1567 "Content-Type: text/plain; charset=%s", 1568 defcharset(e)); 1569 putline(obuf, mci); 1570 } 1571 if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL) 1572 putline("Content-Transfer-Encoding: 8bit", mci); 1573 } 1574#endif /* MIME8TO7 */ 1575} 1576/* 1577** PUT_VANILLA_HEADER -- output a fairly ordinary header 1578** 1579** Parameters: 1580** h -- the structure describing this header 1581** v -- the value of this header 1582** mci -- the connection info for output 1583** 1584** Returns: 1585** none. 1586*/ 1587 1588static void 1589put_vanilla_header(h, v, mci) 1590 HDR *h; 1591 char *v; 1592 MCI *mci; 1593{ 1594 register char *nlp; 1595 register char *obp; 1596 int putflags; 1597 char obuf[MAXLINE]; 1598 1599 putflags = PXLF_HEADER; 1600 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1601 putflags |= PXLF_STRIP8BIT; 1602 (void) snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field); 1603 obp = obuf + strlen(obuf); 1604 while ((nlp = strchr(v, '\n')) != NULL) 1605 { 1606 int l; 1607 1608 l = nlp - v; 1609 if (SPACELEFT(obuf, obp) - 1 < (size_t)l) 1610 l = SPACELEFT(obuf, obp) - 1; 1611 1612 snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); 1613 putxline(obuf, strlen(obuf), mci, putflags); 1614 v += l + 1; 1615 obp = obuf; 1616 if (*v != ' ' && *v != '\t') 1617 *obp++ = ' '; 1618 } 1619 snprintf(obp, SPACELEFT(obuf, obp), "%.*s", 1620 (int) sizeof obuf - (obp - obuf) - 1, v); 1621 putxline(obuf, strlen(obuf), mci, putflags); 1622} 1623/* 1624** COMMAIZE -- output a header field, making a comma-translated list. 1625** 1626** Parameters: 1627** h -- the header field to output. 1628** p -- the value to put in it. 1629** oldstyle -- TRUE if this is an old style header. 1630** mci -- the connection information. 1631** e -- the envelope containing the message. 1632** 1633** Returns: 1634** none. 1635** 1636** Side Effects: 1637** outputs "p" to file "fp". 1638*/ 1639 1640void 1641commaize(h, p, oldstyle, mci, e) 1642 register HDR *h; 1643 register char *p; 1644 bool oldstyle; 1645 register MCI *mci; 1646 register ENVELOPE *e; 1647{ 1648 register char *obp; 1649 int opos; 1650 int omax; 1651 bool firstone = TRUE; 1652 int putflags = PXLF_HEADER; 1653 char obuf[MAXLINE + 3]; 1654 1655 /* 1656 ** Output the address list translated by the 1657 ** mailer and with commas. 1658 */ 1659 1660 if (tTd(14, 2)) 1661 dprintf("commaize(%s: %s)\n", h->h_field, p); 1662 1663 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1664 putflags |= PXLF_STRIP8BIT; 1665 1666 obp = obuf; 1667 (void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", h->h_field); 1668 opos = strlen(h->h_field) + 2; 1669 if (opos > 202) 1670 opos = 202; 1671 obp += opos; 1672 omax = mci->mci_mailer->m_linelimit - 2; 1673 if (omax < 0 || omax > 78) 1674 omax = 78; 1675 1676 /* 1677 ** Run through the list of values. 1678 */ 1679 1680 while (*p != '\0') 1681 { 1682 register char *name; 1683 register int c; 1684 char savechar; 1685 int flags; 1686 auto int status; 1687 1688 /* 1689 ** Find the end of the name. New style names 1690 ** end with a comma, old style names end with 1691 ** a space character. However, spaces do not 1692 ** necessarily delimit an old-style name -- at 1693 ** signs mean keep going. 1694 */ 1695 1696 /* find end of name */ 1697 while ((isascii(*p) && isspace(*p)) || *p == ',') 1698 p++; 1699 name = p; 1700 for (;;) 1701 { 1702 auto char *oldp; 1703 char pvpbuf[PSBUFSIZE]; 1704 1705 (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, 1706 sizeof pvpbuf, &oldp, NULL); 1707 p = oldp; 1708 1709 /* look to see if we have an at sign */ 1710 while (*p != '\0' && isascii(*p) && isspace(*p)) 1711 p++; 1712 1713 if (*p != '@') 1714 { 1715 p = oldp; 1716 break; 1717 } 1718 p += *p == '@' ? 1 : 2; 1719 while (*p != '\0' && isascii(*p) && isspace(*p)) 1720 p++; 1721 } 1722 /* at the end of one complete name */ 1723 1724 /* strip off trailing white space */ 1725 while (p >= name && 1726 ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 1727 p--; 1728 if (++p == name) 1729 continue; 1730 savechar = *p; 1731 *p = '\0'; 1732 1733 /* translate the name to be relative */ 1734 flags = RF_HEADERADDR|RF_ADDDOMAIN; 1735 if (bitset(H_FROM, h->h_flags)) 1736 flags |= RF_SENDERADDR; 1737#if USERDB 1738 else if (e->e_from.q_mailer != NULL && 1739 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 1740 { 1741 char *q; 1742 1743 q = udbsender(name); 1744 if (q != NULL) 1745 name = q; 1746 } 1747#endif /* USERDB */ 1748 status = EX_OK; 1749 name = remotename(name, mci->mci_mailer, flags, &status, e); 1750 if (*name == '\0') 1751 { 1752 *p = savechar; 1753 continue; 1754 } 1755 name = denlstring(name, FALSE, TRUE); 1756 1757 /* 1758 ** record data progress so DNS timeouts 1759 ** don't cause DATA timeouts 1760 */ 1761 1762 DataProgress = TRUE; 1763 1764 /* output the name with nice formatting */ 1765 opos += strlen(name); 1766 if (!firstone) 1767 opos += 2; 1768 if (opos > omax && !firstone) 1769 { 1770 snprintf(obp, SPACELEFT(obuf, obp), ",\n"); 1771 putxline(obuf, strlen(obuf), mci, putflags); 1772 obp = obuf; 1773 (void) strlcpy(obp, " ", sizeof obp); 1774 opos = strlen(obp); 1775 obp += opos; 1776 opos += strlen(name); 1777 } 1778 else if (!firstone) 1779 { 1780 snprintf(obp, SPACELEFT(obuf, obp), ", "); 1781 obp += 2; 1782 } 1783 1784 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 1785 *obp++ = c; 1786 firstone = FALSE; 1787 *p = savechar; 1788 } 1789 *obp = '\0'; 1790 putxline(obuf, strlen(obuf), mci, putflags); 1791} 1792/* 1793** COPYHEADER -- copy header list 1794** 1795** This routine is the equivalent of newstr for header lists 1796** 1797** Parameters: 1798** header -- list of header structures to copy. 1799** 1800** Returns: 1801** a copy of 'header'. 1802** 1803** Side Effects: 1804** none. 1805*/ 1806 1807HDR * 1808copyheader(header) 1809 register HDR *header; 1810{ 1811 register HDR *newhdr; 1812 HDR *ret; 1813 register HDR **tail = &ret; 1814 1815 while (header != NULL) 1816 { 1817 newhdr = (HDR *) xalloc(sizeof *newhdr); 1818 STRUCTCOPY(*header, *newhdr); 1819 *tail = newhdr; 1820 tail = &newhdr->h_link; 1821 header = header->h_link; 1822 } 1823 *tail = NULL; 1824 1825 return ret; 1826} 1827/* 1828** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header 1829** 1830** Run through all of the parameters of a MIME header and 1831** possibly truncate and rebalance the parameter according 1832** to MaxMimeFieldLength. 1833** 1834** Parameters: 1835** string -- the full header 1836** 1837** Returns: 1838** length of last offending field, 0 if all ok. 1839** 1840** Side Effects: 1841** string modified in place 1842*/ 1843 1844static size_t 1845fix_mime_header(string) 1846 char *string; 1847{ 1848 char *begin = string; 1849 char *end; 1850 size_t len = 0; 1851 size_t retlen = 0; 1852 1853 if (string == NULL || *string == '\0') 1854 return 0; 1855 1856 /* Split on each ';' */ 1857 while ((end = find_character(begin, ';')) != NULL) 1858 { 1859 char save = *end; 1860 char *bp; 1861 1862 *end = '\0'; 1863 1864 len = strlen(begin); 1865 1866 /* Shorten individual parameter */ 1867 if (shorten_rfc822_string(begin, MaxMimeFieldLength)) 1868 retlen = len; 1869 1870 /* Collapse the possibly shortened string with rest */ 1871 bp = begin + strlen(begin); 1872 if (bp != end) 1873 { 1874 char *ep = end; 1875 1876 *end = save; 1877 end = bp; 1878 1879 /* copy character by character due to overlap */ 1880 while (*ep != '\0') 1881 *bp++ = *ep++; 1882 *bp = '\0'; 1883 } 1884 else 1885 *end = save; 1886 if (*end == '\0') 1887 break; 1888 1889 /* Move past ';' */ 1890 begin = end + 1; 1891 } 1892 return retlen; 1893} 1894