1c2aa98e2SPeter Wemm /* 2567a2fc9SGregory Neil Shapiro * Copyright (c) 1998-2004, 2006 Sendmail, Inc. and its suppliers. 33299c2f1SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 127660b554SGregory Neil Shapiro * $FreeBSD$ 13c2aa98e2SPeter Wemm */ 14c2aa98e2SPeter Wemm 1512ed1c7cSGregory Neil Shapiro #include <sendmail.h> 16c2aa98e2SPeter Wemm 17355d91e3SGregory Neil Shapiro SM_RCSID("@(#)$Id: headers.c,v 8.291 2006/03/24 01:01:56 ca Exp $") 183299c2f1SGregory Neil Shapiro 19bfb62e91SGregory Neil Shapiro static HDR *allocheader __P((char *, char *, int, SM_RPOOL_T *)); 20f9218d3dSGregory Neil Shapiro static size_t fix_mime_header __P((HDR *, ENVELOPE *)); 213299c2f1SGregory Neil Shapiro static int priencode __P((char *)); 22567a2fc9SGregory Neil Shapiro static bool put_vanilla_header __P((HDR *, char *, MCI *)); 23c2aa98e2SPeter Wemm 24c2aa98e2SPeter Wemm /* 25c2aa98e2SPeter Wemm ** SETUPHEADERS -- initialize headers in symbol table 26c2aa98e2SPeter Wemm ** 27c2aa98e2SPeter Wemm ** Parameters: 28c2aa98e2SPeter Wemm ** none 29c2aa98e2SPeter Wemm ** 30c2aa98e2SPeter Wemm ** Returns: 31c2aa98e2SPeter Wemm ** none 32c2aa98e2SPeter Wemm */ 33c2aa98e2SPeter Wemm 34c2aa98e2SPeter Wemm void 35c2aa98e2SPeter Wemm setupheaders() 36c2aa98e2SPeter Wemm { 37c2aa98e2SPeter Wemm struct hdrinfo *hi; 38c2aa98e2SPeter Wemm STAB *s; 39c2aa98e2SPeter Wemm 40c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 41c2aa98e2SPeter Wemm { 42c2aa98e2SPeter Wemm s = stab(hi->hi_field, ST_HEADER, ST_ENTER); 43c2aa98e2SPeter Wemm s->s_header.hi_flags = hi->hi_flags; 44c2aa98e2SPeter Wemm s->s_header.hi_ruleset = NULL; 45c2aa98e2SPeter Wemm } 46c2aa98e2SPeter Wemm } 4712ed1c7cSGregory Neil Shapiro /* 48c2aa98e2SPeter Wemm ** CHOMPHEADER -- process and save a header line. 49c2aa98e2SPeter Wemm ** 503299c2f1SGregory Neil Shapiro ** Called by collect, readcf, and readqf to deal with header lines. 51c2aa98e2SPeter Wemm ** 52c2aa98e2SPeter Wemm ** Parameters: 53c2aa98e2SPeter Wemm ** line -- header as a text line. 54d995d2baSGregory Neil Shapiro ** pflag -- flags for chompheader() (from sendmail.h) 55c2aa98e2SPeter Wemm ** hdrp -- a pointer to the place to save the header. 56c2aa98e2SPeter Wemm ** e -- the envelope including this header. 57c2aa98e2SPeter Wemm ** 58c2aa98e2SPeter Wemm ** Returns: 59c2aa98e2SPeter Wemm ** flags for this header. 60c2aa98e2SPeter Wemm ** 61c2aa98e2SPeter Wemm ** Side Effects: 62c2aa98e2SPeter Wemm ** The header is saved on the header list. 63c2aa98e2SPeter Wemm ** Contents of 'line' are destroyed. 64c2aa98e2SPeter Wemm */ 65c2aa98e2SPeter Wemm 663299c2f1SGregory Neil Shapiro static struct hdrinfo NormalHeader = { NULL, 0, NULL }; 67c2aa98e2SPeter Wemm 6812ed1c7cSGregory Neil Shapiro unsigned long 693299c2f1SGregory Neil Shapiro chompheader(line, pflag, hdrp, e) 70c2aa98e2SPeter Wemm char *line; 713299c2f1SGregory Neil Shapiro int pflag; 72c2aa98e2SPeter Wemm HDR **hdrp; 73c2aa98e2SPeter Wemm register ENVELOPE *e; 74c2aa98e2SPeter Wemm { 7512ed1c7cSGregory Neil Shapiro unsigned char mid = '\0'; 76c2aa98e2SPeter Wemm register char *p; 77c2aa98e2SPeter Wemm register HDR *h; 78c2aa98e2SPeter Wemm HDR **hp; 79c2aa98e2SPeter Wemm char *fname; 80c2aa98e2SPeter Wemm char *fvalue; 8112ed1c7cSGregory Neil Shapiro bool cond = false; 823299c2f1SGregory Neil Shapiro bool dropfrom; 83c2aa98e2SPeter Wemm bool headeronly; 84c2aa98e2SPeter Wemm STAB *s; 85c2aa98e2SPeter Wemm struct hdrinfo *hi; 8612ed1c7cSGregory Neil Shapiro bool nullheader = false; 873299c2f1SGregory Neil Shapiro BITMAP256 mopts; 88c2aa98e2SPeter Wemm 89c2aa98e2SPeter Wemm if (tTd(31, 6)) 90c2aa98e2SPeter Wemm { 9112ed1c7cSGregory Neil Shapiro sm_dprintf("chompheader: "); 92bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), line); 9312ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 94c2aa98e2SPeter Wemm } 95c2aa98e2SPeter Wemm 96c2aa98e2SPeter Wemm headeronly = hdrp != NULL; 97c2aa98e2SPeter Wemm if (!headeronly) 98c2aa98e2SPeter Wemm hdrp = &e->e_header; 99c2aa98e2SPeter Wemm 100c2aa98e2SPeter Wemm /* strip off options */ 101c2aa98e2SPeter Wemm clrbitmap(mopts); 102c2aa98e2SPeter Wemm p = line; 1033299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_USER) && *p == '?') 104c2aa98e2SPeter Wemm { 1053299c2f1SGregory Neil Shapiro int c; 1063299c2f1SGregory Neil Shapiro register char *q; 107c2aa98e2SPeter Wemm 1083299c2f1SGregory Neil Shapiro q = strchr(++p, '?'); 1093299c2f1SGregory Neil Shapiro if (q == NULL) 1103299c2f1SGregory Neil Shapiro goto hse; 1113299c2f1SGregory Neil Shapiro 1123299c2f1SGregory Neil Shapiro *q = '\0'; 1133299c2f1SGregory Neil Shapiro c = *p & 0377; 1143299c2f1SGregory Neil Shapiro 1153299c2f1SGregory Neil Shapiro /* possibly macro conditional */ 1163299c2f1SGregory Neil Shapiro if (c == MACROEXPAND) 117c2aa98e2SPeter Wemm { 1183299c2f1SGregory Neil Shapiro /* catch ?$? */ 1193299c2f1SGregory Neil Shapiro if (*++p == '\0') 1203299c2f1SGregory Neil Shapiro { 1213299c2f1SGregory Neil Shapiro *q = '?'; 1223299c2f1SGregory Neil Shapiro goto hse; 1233299c2f1SGregory Neil Shapiro } 1243299c2f1SGregory Neil Shapiro 12512ed1c7cSGregory Neil Shapiro mid = (unsigned char) *p++; 1263299c2f1SGregory Neil Shapiro 1273299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1283299c2f1SGregory Neil Shapiro if (*p != '\0') 1293299c2f1SGregory Neil Shapiro { 1303299c2f1SGregory Neil Shapiro *q = '?'; 1313299c2f1SGregory Neil Shapiro goto hse; 1323299c2f1SGregory Neil Shapiro } 1333299c2f1SGregory Neil Shapiro } 1343299c2f1SGregory Neil Shapiro else if (*p == '$') 1353299c2f1SGregory Neil Shapiro { 1363299c2f1SGregory Neil Shapiro /* catch ?$? */ 1373299c2f1SGregory Neil Shapiro if (*++p == '\0') 1383299c2f1SGregory Neil Shapiro { 1393299c2f1SGregory Neil Shapiro *q = '?'; 1403299c2f1SGregory Neil Shapiro goto hse; 1413299c2f1SGregory Neil Shapiro } 1423299c2f1SGregory Neil Shapiro 14312ed1c7cSGregory Neil Shapiro mid = (unsigned char) macid(p); 1443299c2f1SGregory Neil Shapiro if (bitset(0200, mid)) 1457660b554SGregory Neil Shapiro { 1463299c2f1SGregory Neil Shapiro p += strlen(macname(mid)) + 2; 1477660b554SGregory Neil Shapiro SM_ASSERT(p <= q); 1487660b554SGregory Neil Shapiro } 1493299c2f1SGregory Neil Shapiro else 1503299c2f1SGregory Neil Shapiro p++; 1513299c2f1SGregory Neil Shapiro 1523299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1533299c2f1SGregory Neil Shapiro if (*p != '\0') 1543299c2f1SGregory Neil Shapiro { 1553299c2f1SGregory Neil Shapiro *q = '?'; 1563299c2f1SGregory Neil Shapiro goto hse; 1573299c2f1SGregory Neil Shapiro } 158c2aa98e2SPeter Wemm } 159c2aa98e2SPeter Wemm else 1603299c2f1SGregory Neil Shapiro { 1613299c2f1SGregory Neil Shapiro while (*p != '\0') 1623299c2f1SGregory Neil Shapiro { 1633299c2f1SGregory Neil Shapiro if (!isascii(*p)) 1643299c2f1SGregory Neil Shapiro { 1653299c2f1SGregory Neil Shapiro *q = '?'; 1663299c2f1SGregory Neil Shapiro goto hse; 1673299c2f1SGregory Neil Shapiro } 1683299c2f1SGregory Neil Shapiro 169c46d91b7SGregory Neil Shapiro setbitn(bitidx(*p), mopts); 17012ed1c7cSGregory Neil Shapiro cond = true; 1713299c2f1SGregory Neil Shapiro p++; 1723299c2f1SGregory Neil Shapiro } 1733299c2f1SGregory Neil Shapiro } 1743299c2f1SGregory Neil Shapiro p = q + 1; 175c2aa98e2SPeter Wemm } 176c2aa98e2SPeter Wemm 177c2aa98e2SPeter Wemm /* find canonical name */ 178c2aa98e2SPeter Wemm fname = p; 179c2aa98e2SPeter Wemm while (isascii(*p) && isgraph(*p) && *p != ':') 180c2aa98e2SPeter Wemm p++; 181c2aa98e2SPeter Wemm fvalue = p; 182c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 183c2aa98e2SPeter Wemm p++; 184c2aa98e2SPeter Wemm if (*p++ != ':' || fname == fvalue) 185c2aa98e2SPeter Wemm { 1863299c2f1SGregory Neil Shapiro hse: 1873299c2f1SGregory Neil Shapiro syserr("553 5.3.0 header syntax error, line \"%s\"", line); 188c2aa98e2SPeter Wemm return 0; 189c2aa98e2SPeter Wemm } 190c2aa98e2SPeter Wemm *fvalue = '\0'; 191c2aa98e2SPeter Wemm 192c2aa98e2SPeter Wemm /* strip field value on front */ 193e01d6f61SPeter Wemm if (*p == ' ') 194e01d6f61SPeter Wemm p++; 195e01d6f61SPeter Wemm fvalue = p; 196e01d6f61SPeter Wemm 197e01d6f61SPeter Wemm /* if the field is null, go ahead and use the default */ 198e01d6f61SPeter Wemm while (isascii(*p) && isspace(*p)) 199e01d6f61SPeter Wemm p++; 200e01d6f61SPeter Wemm if (*p == '\0') 20112ed1c7cSGregory Neil Shapiro nullheader = true; 202c2aa98e2SPeter Wemm 203c2aa98e2SPeter Wemm /* security scan: long field names are end-of-header */ 204c2aa98e2SPeter Wemm if (strlen(fname) > 100) 205c2aa98e2SPeter Wemm return H_EOH; 206c2aa98e2SPeter Wemm 207c2aa98e2SPeter Wemm /* check to see if it represents a ruleset call */ 2083299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 209c2aa98e2SPeter Wemm { 210c2aa98e2SPeter Wemm char hbuf[50]; 211c2aa98e2SPeter Wemm 212c2aa98e2SPeter Wemm (void) expand(fvalue, hbuf, sizeof hbuf, e); 213c2aa98e2SPeter Wemm for (p = hbuf; isascii(*p) && isspace(*p); ) 214c2aa98e2SPeter Wemm p++; 215c2aa98e2SPeter Wemm if ((*p++ & 0377) == CALLSUBR) 216c2aa98e2SPeter Wemm { 217c2aa98e2SPeter Wemm auto char *endp; 2183299c2f1SGregory Neil Shapiro bool strc; 219c2aa98e2SPeter Wemm 2203299c2f1SGregory Neil Shapiro strc = *p == '+'; /* strip comments? */ 2213299c2f1SGregory Neil Shapiro if (strc) 2223299c2f1SGregory Neil Shapiro ++p; 223c2aa98e2SPeter Wemm if (strtorwset(p, &endp, ST_ENTER) > 0) 224c2aa98e2SPeter Wemm { 225c2aa98e2SPeter Wemm *endp = '\0'; 226c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_ENTER); 22712ed1c7cSGregory Neil Shapiro if (LogLevel > 9 && 22812ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset != NULL) 22912ed1c7cSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 23012ed1c7cSGregory Neil Shapiro "Warning: redefined ruleset for header=%s, old=%s, new=%s", 23112ed1c7cSGregory Neil Shapiro fname, 23212ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset, p); 233c2aa98e2SPeter Wemm s->s_header.hi_ruleset = newstr(p); 2343299c2f1SGregory Neil Shapiro if (!strc) 2353299c2f1SGregory Neil Shapiro s->s_header.hi_flags |= H_STRIPCOMM; 236c2aa98e2SPeter Wemm } 237c2aa98e2SPeter Wemm return 0; 238c2aa98e2SPeter Wemm } 239c2aa98e2SPeter Wemm } 240c2aa98e2SPeter Wemm 241c2aa98e2SPeter Wemm /* see if it is a known type */ 242c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_FIND); 243c2aa98e2SPeter Wemm if (s != NULL) 244c2aa98e2SPeter Wemm hi = &s->s_header; 245c2aa98e2SPeter Wemm else 246c2aa98e2SPeter Wemm hi = &NormalHeader; 247c2aa98e2SPeter Wemm 248c2aa98e2SPeter Wemm if (tTd(31, 9)) 249c2aa98e2SPeter Wemm { 250c2aa98e2SPeter Wemm if (s == NULL) 25112ed1c7cSGregory Neil Shapiro sm_dprintf("no header flags match\n"); 252c2aa98e2SPeter Wemm else 25312ed1c7cSGregory Neil Shapiro sm_dprintf("header match, flags=%lx, ruleset=%s\n", 254c2aa98e2SPeter Wemm hi->hi_flags, 25512ed1c7cSGregory Neil Shapiro hi->hi_ruleset == NULL ? "<NULL>" 25612ed1c7cSGregory Neil Shapiro : hi->hi_ruleset); 257c2aa98e2SPeter Wemm } 258c2aa98e2SPeter Wemm 259c2aa98e2SPeter Wemm /* see if this is a resent message */ 2603299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 2613299c2f1SGregory Neil Shapiro bitset(H_RESENT, hi->hi_flags)) 262c2aa98e2SPeter Wemm e->e_flags |= EF_RESENT; 263c2aa98e2SPeter Wemm 264c2aa98e2SPeter Wemm /* if this is an Errors-To: header keep track of it now */ 2653299c2f1SGregory Neil Shapiro if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly && 266c2aa98e2SPeter Wemm bitset(H_ERRORSTO, hi->hi_flags)) 267c2aa98e2SPeter Wemm (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 268c2aa98e2SPeter Wemm 269c2aa98e2SPeter Wemm /* if this means "end of header" quit now */ 270c2aa98e2SPeter Wemm if (!headeronly && bitset(H_EOH, hi->hi_flags)) 271c2aa98e2SPeter Wemm return hi->hi_flags; 272c2aa98e2SPeter Wemm 273c2aa98e2SPeter Wemm /* 274c2aa98e2SPeter Wemm ** Horrible hack to work around problem with Lotus Notes SMTP 275c2aa98e2SPeter Wemm ** mail gateway, which generates From: headers with newlines in 276c2aa98e2SPeter Wemm ** them and the <address> on the second line. Although this is 277c2aa98e2SPeter Wemm ** legal RFC 822, many MUAs don't handle this properly and thus 278c2aa98e2SPeter Wemm ** never find the actual address. 279c2aa98e2SPeter Wemm */ 280c2aa98e2SPeter Wemm 281c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader) 282c2aa98e2SPeter Wemm { 283c2aa98e2SPeter Wemm while ((p = strchr(fvalue, '\n')) != NULL) 284c2aa98e2SPeter Wemm *p = ' '; 285c2aa98e2SPeter Wemm } 286c2aa98e2SPeter Wemm 287c2aa98e2SPeter Wemm /* 288c2aa98e2SPeter Wemm ** If there is a check ruleset, verify it against the header. 289c2aa98e2SPeter Wemm */ 290c2aa98e2SPeter Wemm 2913299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_CHECK)) 2923299c2f1SGregory Neil Shapiro { 2939d8fddc1SGregory Neil Shapiro int rscheckflags; 2943299c2f1SGregory Neil Shapiro char *rs; 2953299c2f1SGregory Neil Shapiro 2969d8fddc1SGregory Neil Shapiro rscheckflags = RSF_COUNT; 2979d8fddc1SGregory Neil Shapiro if (!bitset(hi->hi_flags, H_FROM|H_RCPT)) 2989d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_UNSTRUCTURED; 299bfb62e91SGregory Neil Shapiro 300bfb62e91SGregory Neil Shapiro /* no ruleset? look for default */ 301bfb62e91SGregory Neil Shapiro rs = hi->hi_ruleset; 3023299c2f1SGregory Neil Shapiro if (rs == NULL) 3033299c2f1SGregory Neil Shapiro { 3043299c2f1SGregory Neil Shapiro s = stab("*", ST_HEADER, ST_FIND); 3053299c2f1SGregory Neil Shapiro if (s != NULL) 3063299c2f1SGregory Neil Shapiro { 3073299c2f1SGregory Neil Shapiro rs = (&s->s_header)->hi_ruleset; 3089d8fddc1SGregory Neil Shapiro if (bitset((&s->s_header)->hi_flags, 3099d8fddc1SGregory Neil Shapiro H_STRIPCOMM)) 3109d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM; 3113299c2f1SGregory Neil Shapiro } 3123299c2f1SGregory Neil Shapiro } 3139d8fddc1SGregory Neil Shapiro else if (bitset(hi->hi_flags, H_STRIPCOMM)) 3149d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM; 3153299c2f1SGregory Neil Shapiro if (rs != NULL) 3163299c2f1SGregory Neil Shapiro { 31712ed1c7cSGregory Neil Shapiro int l, k; 3183299c2f1SGregory Neil Shapiro char qval[MAXNAME]; 3193299c2f1SGregory Neil Shapiro 3203299c2f1SGregory Neil Shapiro l = 0; 32112ed1c7cSGregory Neil Shapiro qval[l++] = '"'; 32212ed1c7cSGregory Neil Shapiro 32312ed1c7cSGregory Neil Shapiro /* - 3 to avoid problems with " at the end */ 3247660b554SGregory Neil Shapiro /* should be sizeof(qval), not MAXNAME */ 32512ed1c7cSGregory Neil Shapiro for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++) 3263299c2f1SGregory Neil Shapiro { 32712ed1c7cSGregory Neil Shapiro switch (fvalue[k]) 3283299c2f1SGregory Neil Shapiro { 32912ed1c7cSGregory Neil Shapiro /* XXX other control chars? */ 3303299c2f1SGregory Neil Shapiro case '\011': /* ht */ 3313299c2f1SGregory Neil Shapiro case '\012': /* nl */ 3323299c2f1SGregory Neil Shapiro case '\013': /* vt */ 3333299c2f1SGregory Neil Shapiro case '\014': /* np */ 3343299c2f1SGregory Neil Shapiro case '\015': /* cr */ 33512ed1c7cSGregory Neil Shapiro qval[l++] = ' '; 3363299c2f1SGregory Neil Shapiro break; 3373299c2f1SGregory Neil Shapiro case '"': 33812ed1c7cSGregory Neil Shapiro qval[l++] = '\\'; 3393299c2f1SGregory Neil Shapiro /* FALLTHROUGH */ 3403299c2f1SGregory Neil Shapiro default: 34112ed1c7cSGregory Neil Shapiro qval[l++] = fvalue[k]; 3423299c2f1SGregory Neil Shapiro break; 3433299c2f1SGregory Neil Shapiro } 3443299c2f1SGregory Neil Shapiro } 34512ed1c7cSGregory Neil Shapiro qval[l++] = '"'; 34612ed1c7cSGregory Neil Shapiro qval[l] = '\0'; 34712ed1c7cSGregory Neil Shapiro k += strlen(fvalue + k); 34812ed1c7cSGregory Neil Shapiro if (k >= MAXNAME) 3493299c2f1SGregory Neil Shapiro { 3503299c2f1SGregory Neil Shapiro if (LogLevel > 9) 3513299c2f1SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 3523299c2f1SGregory Neil Shapiro "Warning: truncated header '%s' before check with '%s' len=%d max=%d", 35312ed1c7cSGregory Neil Shapiro fname, rs, k, MAXNAME - 1); 3543299c2f1SGregory Neil Shapiro } 35512ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 35612ed1c7cSGregory Neil Shapiro macid("{currHeader}"), qval); 35712ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 35812ed1c7cSGregory Neil Shapiro macid("{hdr_name}"), fname); 35912ed1c7cSGregory Neil Shapiro 36012ed1c7cSGregory Neil Shapiro (void) sm_snprintf(qval, sizeof qval, "%d", k); 36112ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval); 36212ed1c7cSGregory Neil Shapiro #if _FFR_HDR_TYPE 363bfb62e91SGregory Neil Shapiro if (bitset(H_FROM, hi->hi_flags)) 36412ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 36512ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h s"); 366bfb62e91SGregory Neil Shapiro else if (bitset(H_RCPT, hi->hi_flags)) 36712ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 36812ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h r"); 36912ed1c7cSGregory Neil Shapiro else 37012ed1c7cSGregory Neil Shapiro #endif /* _FFR_HDR_TYPE */ 37112ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 37212ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h"); 3739d8fddc1SGregory Neil Shapiro (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3, 37412ed1c7cSGregory Neil Shapiro NULL, e->e_id); 3753299c2f1SGregory Neil Shapiro } 3763299c2f1SGregory Neil Shapiro } 377c2aa98e2SPeter Wemm 378c2aa98e2SPeter Wemm /* 379c2aa98e2SPeter Wemm ** Drop explicit From: if same as what we would generate. 380c2aa98e2SPeter Wemm ** This is to make MH (which doesn't always give a full name) 381c2aa98e2SPeter Wemm ** insert the full name information in all circumstances. 382c2aa98e2SPeter Wemm */ 383c2aa98e2SPeter Wemm 38412ed1c7cSGregory Neil Shapiro dropfrom = false; 385c2aa98e2SPeter Wemm p = "resent-from"; 386c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 387c2aa98e2SPeter Wemm p += 7; 3883299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 38912ed1c7cSGregory Neil Shapiro !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0) 390c2aa98e2SPeter Wemm { 391c2aa98e2SPeter Wemm if (tTd(31, 2)) 392c2aa98e2SPeter Wemm { 39312ed1c7cSGregory Neil Shapiro sm_dprintf("comparing header from (%s) against default (%s or %s)\n", 394c2aa98e2SPeter Wemm fvalue, e->e_from.q_paddr, e->e_from.q_user); 395c2aa98e2SPeter Wemm } 396c2aa98e2SPeter Wemm if (e->e_from.q_paddr != NULL && 3973299c2f1SGregory Neil Shapiro e->e_from.q_mailer != NULL && 3983299c2f1SGregory Neil Shapiro bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && 399c2aa98e2SPeter Wemm (strcmp(fvalue, e->e_from.q_paddr) == 0 || 400c2aa98e2SPeter Wemm strcmp(fvalue, e->e_from.q_user) == 0)) 40112ed1c7cSGregory Neil Shapiro dropfrom = true; 402c2aa98e2SPeter Wemm } 403c2aa98e2SPeter Wemm 404c2aa98e2SPeter Wemm /* delete default value for this header */ 405c2aa98e2SPeter Wemm for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 406c2aa98e2SPeter Wemm { 40712ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(fname, h->h_field) == 0 && 4083299c2f1SGregory Neil Shapiro !bitset(H_USER, h->h_flags) && 409c2aa98e2SPeter Wemm !bitset(H_FORCE, h->h_flags)) 410c2aa98e2SPeter Wemm { 411e01d6f61SPeter Wemm if (nullheader) 412e01d6f61SPeter Wemm { 413e01d6f61SPeter Wemm /* user-supplied value was null */ 414e01d6f61SPeter Wemm return 0; 415e01d6f61SPeter Wemm } 4163299c2f1SGregory Neil Shapiro if (dropfrom) 4173299c2f1SGregory Neil Shapiro { 4183299c2f1SGregory Neil Shapiro /* make this look like the user entered it */ 4193299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 4203299c2f1SGregory Neil Shapiro return hi->hi_flags; 4213299c2f1SGregory Neil Shapiro } 422c2aa98e2SPeter Wemm h->h_value = NULL; 423c2aa98e2SPeter Wemm if (!cond) 424c2aa98e2SPeter Wemm { 425c2aa98e2SPeter Wemm /* copy conditions from default case */ 4263299c2f1SGregory Neil Shapiro memmove((char *) mopts, (char *) h->h_mflags, 427c2aa98e2SPeter Wemm sizeof mopts); 428c2aa98e2SPeter Wemm } 4293299c2f1SGregory Neil Shapiro h->h_macro = mid; 430c2aa98e2SPeter Wemm } 431c2aa98e2SPeter Wemm } 432c2aa98e2SPeter Wemm 433c2aa98e2SPeter Wemm /* create a new node */ 43412ed1c7cSGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h); 43512ed1c7cSGregory Neil Shapiro h->h_field = sm_rpool_strdup_x(e->e_rpool, fname); 43612ed1c7cSGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue); 437c2aa98e2SPeter Wemm h->h_link = NULL; 4383299c2f1SGregory Neil Shapiro memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts); 4393299c2f1SGregory Neil Shapiro h->h_macro = mid; 440c2aa98e2SPeter Wemm *hp = h; 441c2aa98e2SPeter Wemm h->h_flags = hi->hi_flags; 442d995d2baSGregory Neil Shapiro if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE)) 4433299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 444c2aa98e2SPeter Wemm 445c2aa98e2SPeter Wemm /* strip EOH flag if parsing MIME headers */ 446c2aa98e2SPeter Wemm if (headeronly) 447c2aa98e2SPeter Wemm h->h_flags &= ~H_EOH; 4483299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 449c2aa98e2SPeter Wemm h->h_flags |= H_DEFAULT; 4503299c2f1SGregory Neil Shapiro if (cond || mid != '\0') 451c2aa98e2SPeter Wemm h->h_flags |= H_CHECK; 452c2aa98e2SPeter Wemm 453c2aa98e2SPeter Wemm /* hack to see if this is a new format message */ 4543299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 4553299c2f1SGregory Neil Shapiro bitset(H_RCPT|H_FROM, h->h_flags) && 456c2aa98e2SPeter Wemm (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 457c2aa98e2SPeter Wemm strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 458c2aa98e2SPeter Wemm { 459c2aa98e2SPeter Wemm e->e_flags &= ~EF_OLDSTYLE; 460c2aa98e2SPeter Wemm } 461c2aa98e2SPeter Wemm 462c2aa98e2SPeter Wemm return h->h_flags; 463c2aa98e2SPeter Wemm } 46412ed1c7cSGregory Neil Shapiro /* 465bfb62e91SGregory Neil Shapiro ** ALLOCHEADER -- allocate a header entry 466bfb62e91SGregory Neil Shapiro ** 467bfb62e91SGregory Neil Shapiro ** Parameters: 468bfb62e91SGregory Neil Shapiro ** field -- the name of the header field. 469bfb62e91SGregory Neil Shapiro ** value -- the value of the field. 470bfb62e91SGregory Neil Shapiro ** flags -- flags to add to h_flags. 471bfb62e91SGregory Neil Shapiro ** rp -- resource pool for allocations 472bfb62e91SGregory Neil Shapiro ** 473bfb62e91SGregory Neil Shapiro ** Returns: 474bfb62e91SGregory Neil Shapiro ** Pointer to a newly allocated and populated HDR. 475bfb62e91SGregory Neil Shapiro */ 476bfb62e91SGregory Neil Shapiro 477bfb62e91SGregory Neil Shapiro static HDR * 478bfb62e91SGregory Neil Shapiro allocheader(field, value, flags, rp) 479bfb62e91SGregory Neil Shapiro char *field; 480bfb62e91SGregory Neil Shapiro char *value; 481bfb62e91SGregory Neil Shapiro int flags; 482bfb62e91SGregory Neil Shapiro SM_RPOOL_T *rp; 483bfb62e91SGregory Neil Shapiro { 484bfb62e91SGregory Neil Shapiro HDR *h; 485bfb62e91SGregory Neil Shapiro STAB *s; 486bfb62e91SGregory Neil Shapiro 487bfb62e91SGregory Neil Shapiro /* find info struct */ 488bfb62e91SGregory Neil Shapiro s = stab(field, ST_HEADER, ST_FIND); 489bfb62e91SGregory Neil Shapiro 490bfb62e91SGregory Neil Shapiro /* allocate space for new header */ 491bfb62e91SGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_x(rp, sizeof *h); 492bfb62e91SGregory Neil Shapiro h->h_field = field; 493bfb62e91SGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(rp, value); 494bfb62e91SGregory Neil Shapiro h->h_flags = flags; 495bfb62e91SGregory Neil Shapiro if (s != NULL) 496bfb62e91SGregory Neil Shapiro h->h_flags |= s->s_header.hi_flags; 497bfb62e91SGregory Neil Shapiro clrbitmap(h->h_mflags); 498bfb62e91SGregory Neil Shapiro h->h_macro = '\0'; 499bfb62e91SGregory Neil Shapiro 500bfb62e91SGregory Neil Shapiro return h; 501bfb62e91SGregory Neil Shapiro } 502bfb62e91SGregory Neil Shapiro /* 503c2aa98e2SPeter Wemm ** ADDHEADER -- add a header entry to the end of the queue. 504c2aa98e2SPeter Wemm ** 505c2aa98e2SPeter Wemm ** This bypasses the special checking of chompheader. 506c2aa98e2SPeter Wemm ** 507c2aa98e2SPeter Wemm ** Parameters: 508c2aa98e2SPeter Wemm ** field -- the name of the header field. 509c2aa98e2SPeter Wemm ** value -- the value of the field. 5103299c2f1SGregory Neil Shapiro ** flags -- flags to add to h_flags. 51112ed1c7cSGregory Neil Shapiro ** e -- envelope. 512c2aa98e2SPeter Wemm ** 513c2aa98e2SPeter Wemm ** Returns: 514c2aa98e2SPeter Wemm ** none. 515c2aa98e2SPeter Wemm ** 516c2aa98e2SPeter Wemm ** Side Effects: 517c2aa98e2SPeter Wemm ** adds the field on the list of headers for this envelope. 518c2aa98e2SPeter Wemm */ 519c2aa98e2SPeter Wemm 520c2aa98e2SPeter Wemm void 52112ed1c7cSGregory Neil Shapiro addheader(field, value, flags, e) 522c2aa98e2SPeter Wemm char *field; 523c2aa98e2SPeter Wemm char *value; 5243299c2f1SGregory Neil Shapiro int flags; 52512ed1c7cSGregory Neil Shapiro ENVELOPE *e; 526c2aa98e2SPeter Wemm { 527c2aa98e2SPeter Wemm register HDR *h; 528c2aa98e2SPeter Wemm HDR **hp; 52912ed1c7cSGregory Neil Shapiro HDR **hdrlist = &e->e_header; 530c2aa98e2SPeter Wemm 531c2aa98e2SPeter Wemm /* find current place in list -- keep back pointer? */ 532c2aa98e2SPeter Wemm for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 533c2aa98e2SPeter Wemm { 53412ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(field, h->h_field) == 0) 535c2aa98e2SPeter Wemm break; 536c2aa98e2SPeter Wemm } 537c2aa98e2SPeter Wemm 538c2aa98e2SPeter Wemm /* allocate space for new header */ 539bfb62e91SGregory Neil Shapiro h = allocheader(field, value, flags, e->e_rpool); 540c2aa98e2SPeter Wemm h->h_link = *hp; 541c2aa98e2SPeter Wemm *hp = h; 542c2aa98e2SPeter Wemm } 54312ed1c7cSGregory Neil Shapiro /* 544bfb62e91SGregory Neil Shapiro ** INSHEADER -- insert a header entry at the specified index 545bfb62e91SGregory Neil Shapiro ** 546bfb62e91SGregory Neil Shapiro ** This bypasses the special checking of chompheader. 547bfb62e91SGregory Neil Shapiro ** 548bfb62e91SGregory Neil Shapiro ** Parameters: 549bfb62e91SGregory Neil Shapiro ** idx -- index into the header list at which to insert 550bfb62e91SGregory Neil Shapiro ** field -- the name of the header field. 551bfb62e91SGregory Neil Shapiro ** value -- the value of the field. 552bfb62e91SGregory Neil Shapiro ** flags -- flags to add to h_flags. 553bfb62e91SGregory Neil Shapiro ** e -- envelope. 554bfb62e91SGregory Neil Shapiro ** 555bfb62e91SGregory Neil Shapiro ** Returns: 556bfb62e91SGregory Neil Shapiro ** none. 557bfb62e91SGregory Neil Shapiro ** 558bfb62e91SGregory Neil Shapiro ** Side Effects: 559bfb62e91SGregory Neil Shapiro ** inserts the field on the list of headers for this envelope. 560bfb62e91SGregory Neil Shapiro */ 561bfb62e91SGregory Neil Shapiro 562bfb62e91SGregory Neil Shapiro void 563bfb62e91SGregory Neil Shapiro insheader(idx, field, value, flags, e) 564bfb62e91SGregory Neil Shapiro int idx; 565bfb62e91SGregory Neil Shapiro char *field; 566bfb62e91SGregory Neil Shapiro char *value; 567bfb62e91SGregory Neil Shapiro int flags; 568bfb62e91SGregory Neil Shapiro ENVELOPE *e; 569bfb62e91SGregory Neil Shapiro { 570bfb62e91SGregory Neil Shapiro HDR *h, *srch, *last = NULL; 571bfb62e91SGregory Neil Shapiro 572bfb62e91SGregory Neil Shapiro /* allocate space for new header */ 573bfb62e91SGregory Neil Shapiro h = allocheader(field, value, flags, e->e_rpool); 574bfb62e91SGregory Neil Shapiro 575bfb62e91SGregory Neil Shapiro /* find insertion position */ 576bfb62e91SGregory Neil Shapiro for (srch = e->e_header; srch != NULL && idx > 0; 577bfb62e91SGregory Neil Shapiro srch = srch->h_link, idx--) 578bfb62e91SGregory Neil Shapiro last = srch; 579bfb62e91SGregory Neil Shapiro 580bfb62e91SGregory Neil Shapiro if (e->e_header == NULL) 581bfb62e91SGregory Neil Shapiro { 582bfb62e91SGregory Neil Shapiro e->e_header = h; 583bfb62e91SGregory Neil Shapiro h->h_link = NULL; 584bfb62e91SGregory Neil Shapiro } 585bfb62e91SGregory Neil Shapiro else if (srch == NULL) 586bfb62e91SGregory Neil Shapiro { 587bfb62e91SGregory Neil Shapiro SM_ASSERT(last != NULL); 588bfb62e91SGregory Neil Shapiro last->h_link = h; 589bfb62e91SGregory Neil Shapiro h->h_link = NULL; 590bfb62e91SGregory Neil Shapiro } 591bfb62e91SGregory Neil Shapiro else 592bfb62e91SGregory Neil Shapiro { 593bfb62e91SGregory Neil Shapiro h->h_link = srch->h_link; 594bfb62e91SGregory Neil Shapiro srch->h_link = h; 595bfb62e91SGregory Neil Shapiro } 596bfb62e91SGregory Neil Shapiro } 597bfb62e91SGregory Neil Shapiro /* 598c2aa98e2SPeter Wemm ** HVALUE -- return value of a header. 599c2aa98e2SPeter Wemm ** 600c2aa98e2SPeter Wemm ** Only "real" fields (i.e., ones that have not been supplied 601c2aa98e2SPeter Wemm ** as a default) are used. 602c2aa98e2SPeter Wemm ** 603c2aa98e2SPeter Wemm ** Parameters: 604c2aa98e2SPeter Wemm ** field -- the field name. 605c2aa98e2SPeter Wemm ** header -- the header list. 606c2aa98e2SPeter Wemm ** 607c2aa98e2SPeter Wemm ** Returns: 608c2aa98e2SPeter Wemm ** pointer to the value part. 609c2aa98e2SPeter Wemm ** NULL if not found. 610c2aa98e2SPeter Wemm ** 611c2aa98e2SPeter Wemm ** Side Effects: 612c2aa98e2SPeter Wemm ** none. 613c2aa98e2SPeter Wemm */ 614c2aa98e2SPeter Wemm 615c2aa98e2SPeter Wemm char * 616c2aa98e2SPeter Wemm hvalue(field, header) 617c2aa98e2SPeter Wemm char *field; 618c2aa98e2SPeter Wemm HDR *header; 619c2aa98e2SPeter Wemm { 620c2aa98e2SPeter Wemm register HDR *h; 621c2aa98e2SPeter Wemm 622c2aa98e2SPeter Wemm for (h = header; h != NULL; h = h->h_link) 623c2aa98e2SPeter Wemm { 624c2aa98e2SPeter Wemm if (!bitset(H_DEFAULT, h->h_flags) && 62512ed1c7cSGregory Neil Shapiro sm_strcasecmp(h->h_field, field) == 0) 6263299c2f1SGregory Neil Shapiro return h->h_value; 627c2aa98e2SPeter Wemm } 6283299c2f1SGregory Neil Shapiro return NULL; 629c2aa98e2SPeter Wemm } 63012ed1c7cSGregory Neil Shapiro /* 631c2aa98e2SPeter Wemm ** ISHEADER -- predicate telling if argument is a header. 632c2aa98e2SPeter Wemm ** 633c2aa98e2SPeter Wemm ** A line is a header if it has a single word followed by 634c2aa98e2SPeter Wemm ** optional white space followed by a colon. 635c2aa98e2SPeter Wemm ** 636c2aa98e2SPeter Wemm ** Header fields beginning with two dashes, although technically 637c2aa98e2SPeter Wemm ** permitted by RFC822, are automatically rejected in order 638c2aa98e2SPeter Wemm ** to make MIME work out. Without this we could have a technically 639c2aa98e2SPeter Wemm ** legal header such as ``--"foo:bar"'' that would also be a legal 640c2aa98e2SPeter Wemm ** MIME separator. 641c2aa98e2SPeter Wemm ** 642c2aa98e2SPeter Wemm ** Parameters: 643c2aa98e2SPeter Wemm ** h -- string to check for possible headerness. 644c2aa98e2SPeter Wemm ** 645c2aa98e2SPeter Wemm ** Returns: 64612ed1c7cSGregory Neil Shapiro ** true if h is a header. 64712ed1c7cSGregory Neil Shapiro ** false otherwise. 648c2aa98e2SPeter Wemm ** 649c2aa98e2SPeter Wemm ** Side Effects: 650c2aa98e2SPeter Wemm ** none. 651c2aa98e2SPeter Wemm */ 652c2aa98e2SPeter Wemm 653c2aa98e2SPeter Wemm bool 654c2aa98e2SPeter Wemm isheader(h) 655c2aa98e2SPeter Wemm char *h; 656c2aa98e2SPeter Wemm { 657c2aa98e2SPeter Wemm register char *s = h; 658c2aa98e2SPeter Wemm 659c2aa98e2SPeter Wemm if (s[0] == '-' && s[1] == '-') 66012ed1c7cSGregory Neil Shapiro return false; 661c2aa98e2SPeter Wemm 662c2aa98e2SPeter Wemm while (*s > ' ' && *s != ':' && *s != '\0') 663c2aa98e2SPeter Wemm s++; 664c2aa98e2SPeter Wemm 665c2aa98e2SPeter Wemm if (h == s) 66612ed1c7cSGregory Neil Shapiro return false; 667c2aa98e2SPeter Wemm 668c2aa98e2SPeter Wemm /* following technically violates RFC822 */ 669c2aa98e2SPeter Wemm while (isascii(*s) && isspace(*s)) 670c2aa98e2SPeter Wemm s++; 671c2aa98e2SPeter Wemm 672c2aa98e2SPeter Wemm return (*s == ':'); 673c2aa98e2SPeter Wemm } 67412ed1c7cSGregory Neil Shapiro /* 675c2aa98e2SPeter Wemm ** EATHEADER -- run through the stored header and extract info. 676c2aa98e2SPeter Wemm ** 677c2aa98e2SPeter Wemm ** Parameters: 678c2aa98e2SPeter Wemm ** e -- the envelope to process. 679c2aa98e2SPeter Wemm ** full -- if set, do full processing (e.g., compute 680c2aa98e2SPeter Wemm ** message priority). This should not be set 681c2aa98e2SPeter Wemm ** when reading a queue file because some info 682c2aa98e2SPeter Wemm ** needed to compute the priority is wrong. 68312ed1c7cSGregory Neil Shapiro ** log -- call logsender()? 684c2aa98e2SPeter Wemm ** 685c2aa98e2SPeter Wemm ** Returns: 686c2aa98e2SPeter Wemm ** none. 687c2aa98e2SPeter Wemm ** 688c2aa98e2SPeter Wemm ** Side Effects: 689c2aa98e2SPeter Wemm ** Sets a bunch of global variables from information 690c2aa98e2SPeter Wemm ** in the collected header. 691c2aa98e2SPeter Wemm */ 692c2aa98e2SPeter Wemm 693c2aa98e2SPeter Wemm void 69412ed1c7cSGregory Neil Shapiro eatheader(e, full, log) 695c2aa98e2SPeter Wemm register ENVELOPE *e; 696c2aa98e2SPeter Wemm bool full; 69712ed1c7cSGregory Neil Shapiro bool log; 698c2aa98e2SPeter Wemm { 699c2aa98e2SPeter Wemm register HDR *h; 700c2aa98e2SPeter Wemm register char *p; 701c2aa98e2SPeter Wemm int hopcnt = 0; 702c2aa98e2SPeter Wemm char buf[MAXLINE]; 703c2aa98e2SPeter Wemm 704c2aa98e2SPeter Wemm /* 705c2aa98e2SPeter Wemm ** Set up macros for possible expansion in headers. 706c2aa98e2SPeter Wemm */ 707c2aa98e2SPeter Wemm 70812ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'f', e->e_sender); 70912ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', e->e_sender); 710c2aa98e2SPeter Wemm if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 71112ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt); 712c2aa98e2SPeter Wemm else 71312ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', NULL); 714c2aa98e2SPeter Wemm 715c2aa98e2SPeter Wemm /* full name of from person */ 716c2aa98e2SPeter Wemm p = hvalue("full-name", e->e_header); 717c2aa98e2SPeter Wemm if (p != NULL) 718c2aa98e2SPeter Wemm { 719c2aa98e2SPeter Wemm if (!rfc822_string(p)) 720c2aa98e2SPeter Wemm { 721c2aa98e2SPeter Wemm /* 722c2aa98e2SPeter Wemm ** Quote a full name with special characters 723c2aa98e2SPeter Wemm ** as a comment so crackaddr() doesn't destroy 724c2aa98e2SPeter Wemm ** the name portion of the address. 725c2aa98e2SPeter Wemm */ 72612ed1c7cSGregory Neil Shapiro 72712ed1c7cSGregory Neil Shapiro p = addquotes(p, e->e_rpool); 728c2aa98e2SPeter Wemm } 72912ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'x', p); 730c2aa98e2SPeter Wemm } 731c2aa98e2SPeter Wemm 732c2aa98e2SPeter Wemm if (tTd(32, 1)) 73312ed1c7cSGregory Neil Shapiro sm_dprintf("----- collected header -----\n"); 73412ed1c7cSGregory Neil Shapiro e->e_msgid = NULL; 735c2aa98e2SPeter Wemm for (h = e->e_header; h != NULL; h = h->h_link) 736c2aa98e2SPeter Wemm { 737c2aa98e2SPeter Wemm if (tTd(32, 1)) 73812ed1c7cSGregory Neil Shapiro sm_dprintf("%s: ", h->h_field); 739c2aa98e2SPeter Wemm if (h->h_value == NULL) 740c2aa98e2SPeter Wemm { 741c2aa98e2SPeter Wemm if (tTd(32, 1)) 74212ed1c7cSGregory Neil Shapiro sm_dprintf("<NULL>\n"); 743c2aa98e2SPeter Wemm continue; 744c2aa98e2SPeter Wemm } 745c2aa98e2SPeter Wemm 746c2aa98e2SPeter Wemm /* do early binding */ 7473299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) && 7483299c2f1SGregory Neil Shapiro !bitset(H_BINDLATE, h->h_flags)) 749c2aa98e2SPeter Wemm { 750c2aa98e2SPeter Wemm if (tTd(32, 1)) 751c2aa98e2SPeter Wemm { 75212ed1c7cSGregory Neil Shapiro sm_dprintf("("); 753bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), h->h_value); 75412ed1c7cSGregory Neil Shapiro sm_dprintf(") "); 755c2aa98e2SPeter Wemm } 756c2aa98e2SPeter Wemm expand(h->h_value, buf, sizeof buf, e); 757c2aa98e2SPeter Wemm if (buf[0] != '\0') 758c2aa98e2SPeter Wemm { 759c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 760f9218d3dSGregory Neil Shapiro expand(crackaddr(buf, e), 761f9218d3dSGregory Neil Shapiro buf, sizeof buf, e); 76212ed1c7cSGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, buf); 763c2aa98e2SPeter Wemm h->h_flags &= ~H_DEFAULT; 764c2aa98e2SPeter Wemm } 765c2aa98e2SPeter Wemm } 766c2aa98e2SPeter Wemm if (tTd(32, 1)) 767c2aa98e2SPeter Wemm { 768bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), h->h_value); 76912ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 770c2aa98e2SPeter Wemm } 771c2aa98e2SPeter Wemm 772c2aa98e2SPeter Wemm /* count the number of times it has been processed */ 773c2aa98e2SPeter Wemm if (bitset(H_TRACE, h->h_flags)) 774c2aa98e2SPeter Wemm hopcnt++; 775c2aa98e2SPeter Wemm 776c2aa98e2SPeter Wemm /* send to this person if we so desire */ 777c2aa98e2SPeter Wemm if (GrabTo && bitset(H_RCPT, h->h_flags) && 778c2aa98e2SPeter Wemm !bitset(H_DEFAULT, h->h_flags) && 77912ed1c7cSGregory Neil Shapiro (!bitset(EF_RESENT, e->e_flags) || 78012ed1c7cSGregory Neil Shapiro bitset(H_RESENT, h->h_flags))) 781c2aa98e2SPeter Wemm { 782c2aa98e2SPeter Wemm #if 0 783c2aa98e2SPeter Wemm int saveflags = e->e_flags; 7843299c2f1SGregory Neil Shapiro #endif /* 0 */ 785c2aa98e2SPeter Wemm 78612ed1c7cSGregory Neil Shapiro (void) sendtolist(denlstring(h->h_value, true, false), 78712ed1c7cSGregory Neil Shapiro NULLADDR, &e->e_sendqueue, 0, e); 788c2aa98e2SPeter Wemm 789c2aa98e2SPeter Wemm #if 0 790c2aa98e2SPeter Wemm /* 791c2aa98e2SPeter Wemm ** Change functionality so a fatal error on an 792c2aa98e2SPeter Wemm ** address doesn't affect the entire envelope. 793c2aa98e2SPeter Wemm */ 794c2aa98e2SPeter Wemm 795c2aa98e2SPeter Wemm /* delete fatal errors generated by this address */ 796c2aa98e2SPeter Wemm if (!bitset(EF_FATALERRS, saveflags)) 797c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 7983299c2f1SGregory Neil Shapiro #endif /* 0 */ 799c2aa98e2SPeter Wemm } 800c2aa98e2SPeter Wemm 801c2aa98e2SPeter Wemm /* save the message-id for logging */ 802c2aa98e2SPeter Wemm p = "resent-message-id"; 803c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 804c2aa98e2SPeter Wemm p += 7; 80512ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(h->h_field, p) == 0) 806c2aa98e2SPeter Wemm { 80712ed1c7cSGregory Neil Shapiro e->e_msgid = h->h_value; 80812ed1c7cSGregory Neil Shapiro while (isascii(*e->e_msgid) && isspace(*e->e_msgid)) 80912ed1c7cSGregory Neil Shapiro e->e_msgid++; 8101ae5b8d4SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{msg_id}"), 8111ae5b8d4SGregory Neil Shapiro e->e_msgid); 812c2aa98e2SPeter Wemm } 813c2aa98e2SPeter Wemm } 814c2aa98e2SPeter Wemm if (tTd(32, 1)) 81512ed1c7cSGregory Neil Shapiro sm_dprintf("----------------------------\n"); 816c2aa98e2SPeter Wemm 817c2aa98e2SPeter Wemm /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 818c2aa98e2SPeter Wemm if (OpMode == MD_VERIFY) 819c2aa98e2SPeter Wemm return; 820c2aa98e2SPeter Wemm 821c2aa98e2SPeter Wemm /* store hop count */ 822c2aa98e2SPeter Wemm if (hopcnt > e->e_hopcount) 82312ed1c7cSGregory Neil Shapiro { 824c2aa98e2SPeter Wemm e->e_hopcount = hopcnt; 82512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount); 82612ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 'c', buf); 82712ed1c7cSGregory Neil Shapiro } 828c2aa98e2SPeter Wemm 829c2aa98e2SPeter Wemm /* message priority */ 830c2aa98e2SPeter Wemm p = hvalue("precedence", e->e_header); 831c2aa98e2SPeter Wemm if (p != NULL) 832c2aa98e2SPeter Wemm e->e_class = priencode(p); 833c2aa98e2SPeter Wemm if (e->e_class < 0) 834c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 835c2aa98e2SPeter Wemm else if (e->e_class > 0) 836c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 837c2aa98e2SPeter Wemm if (full) 838c2aa98e2SPeter Wemm { 839c2aa98e2SPeter Wemm e->e_msgpriority = e->e_msgsize 840c2aa98e2SPeter Wemm - e->e_class * WkClassFact 841c2aa98e2SPeter Wemm + e->e_nrcpts * WkRecipFact; 842c2aa98e2SPeter Wemm } 843c2aa98e2SPeter Wemm 844bfb62e91SGregory Neil Shapiro /* check for DSN to properly set e_timeoutclass */ 845bfb62e91SGregory Neil Shapiro p = hvalue("content-type", e->e_header); 846bfb62e91SGregory Neil Shapiro if (p != NULL) 847bfb62e91SGregory Neil Shapiro { 848bfb62e91SGregory Neil Shapiro bool oldsupr; 849bfb62e91SGregory Neil Shapiro char **pvp; 850bfb62e91SGregory Neil Shapiro char pvpbuf[MAXLINE]; 851bfb62e91SGregory Neil Shapiro extern unsigned char MimeTokenTab[256]; 852bfb62e91SGregory Neil Shapiro 853bfb62e91SGregory Neil Shapiro /* tokenize header */ 854bfb62e91SGregory Neil Shapiro oldsupr = SuprErrs; 855bfb62e91SGregory Neil Shapiro SuprErrs = true; 856bfb62e91SGregory Neil Shapiro pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, 857bfb62e91SGregory Neil Shapiro MimeTokenTab, false); 858bfb62e91SGregory Neil Shapiro SuprErrs = oldsupr; 859bfb62e91SGregory Neil Shapiro 860bfb62e91SGregory Neil Shapiro /* Check if multipart/report */ 861bfb62e91SGregory Neil Shapiro if (pvp != NULL && pvp[0] != NULL && 862bfb62e91SGregory Neil Shapiro pvp[1] != NULL && pvp[2] != NULL && 863bfb62e91SGregory Neil Shapiro sm_strcasecmp(*pvp++, "multipart") == 0 && 864bfb62e91SGregory Neil Shapiro strcmp(*pvp++, "/") == 0 && 865bfb62e91SGregory Neil Shapiro sm_strcasecmp(*pvp++, "report") == 0) 866bfb62e91SGregory Neil Shapiro { 867bfb62e91SGregory Neil Shapiro /* Look for report-type=delivery-status */ 868bfb62e91SGregory Neil Shapiro while (*pvp != NULL) 869bfb62e91SGregory Neil Shapiro { 870bfb62e91SGregory Neil Shapiro /* skip to semicolon separator */ 871bfb62e91SGregory Neil Shapiro while (*pvp != NULL && strcmp(*pvp, ";") != 0) 872bfb62e91SGregory Neil Shapiro pvp++; 873bfb62e91SGregory Neil Shapiro 874bfb62e91SGregory Neil Shapiro /* skip semicolon */ 875bfb62e91SGregory Neil Shapiro if (*pvp++ == NULL || *pvp == NULL) 876bfb62e91SGregory Neil Shapiro break; 877bfb62e91SGregory Neil Shapiro 878bfb62e91SGregory Neil Shapiro /* look for report-type */ 879bfb62e91SGregory Neil Shapiro if (sm_strcasecmp(*pvp++, "report-type") != 0) 880bfb62e91SGregory Neil Shapiro continue; 881bfb62e91SGregory Neil Shapiro 882bfb62e91SGregory Neil Shapiro /* skip equal */ 883bfb62e91SGregory Neil Shapiro if (*pvp == NULL || strcmp(*pvp, "=") != 0) 884bfb62e91SGregory Neil Shapiro continue; 885bfb62e91SGregory Neil Shapiro 886bfb62e91SGregory Neil Shapiro /* check value */ 887bfb62e91SGregory Neil Shapiro if (*++pvp != NULL && 888bfb62e91SGregory Neil Shapiro sm_strcasecmp(*pvp, 889bfb62e91SGregory Neil Shapiro "delivery-status") == 0) 890bfb62e91SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 891bfb62e91SGregory Neil Shapiro 892bfb62e91SGregory Neil Shapiro /* found report-type, no need to continue */ 893bfb62e91SGregory Neil Shapiro break; 894bfb62e91SGregory Neil Shapiro } 895bfb62e91SGregory Neil Shapiro } 896bfb62e91SGregory Neil Shapiro } 897bfb62e91SGregory Neil Shapiro 898c2aa98e2SPeter Wemm /* message timeout priority */ 899c2aa98e2SPeter Wemm p = hvalue("priority", e->e_header); 900c2aa98e2SPeter Wemm if (p != NULL) 901c2aa98e2SPeter Wemm { 902c2aa98e2SPeter Wemm /* (this should be in the configuration file) */ 90312ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(p, "urgent") == 0) 904c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 90512ed1c7cSGregory Neil Shapiro else if (sm_strcasecmp(p, "normal") == 0) 906c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NORMAL; 90712ed1c7cSGregory Neil Shapiro else if (sm_strcasecmp(p, "non-urgent") == 0) 908c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 9091ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags)) 9101ae5b8d4SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 9111ae5b8d4SGregory Neil Shapiro } 9121ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags)) 91372936242SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN; 91472936242SGregory Neil Shapiro 915c2aa98e2SPeter Wemm /* date message originated */ 916c2aa98e2SPeter Wemm p = hvalue("posted-date", e->e_header); 917c2aa98e2SPeter Wemm if (p == NULL) 918c2aa98e2SPeter Wemm p = hvalue("date", e->e_header); 919c2aa98e2SPeter Wemm if (p != NULL) 92012ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'a', p); 921c2aa98e2SPeter Wemm 922c2aa98e2SPeter Wemm /* check to see if this is a MIME message */ 923c2aa98e2SPeter Wemm if ((e->e_bodytype != NULL && 92412ed1c7cSGregory Neil Shapiro sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 925c2aa98e2SPeter Wemm hvalue("MIME-Version", e->e_header) != NULL) 926c2aa98e2SPeter Wemm { 927c2aa98e2SPeter Wemm e->e_flags |= EF_IS_MIME; 928c2aa98e2SPeter Wemm if (HasEightBits) 929c2aa98e2SPeter Wemm e->e_bodytype = "8BITMIME"; 930c2aa98e2SPeter Wemm } 931c2aa98e2SPeter Wemm else if ((p = hvalue("Content-Type", e->e_header)) != NULL) 932c2aa98e2SPeter Wemm { 933c2aa98e2SPeter Wemm /* this may be an RFC 1049 message */ 934c2aa98e2SPeter Wemm p = strpbrk(p, ";/"); 935c2aa98e2SPeter Wemm if (p == NULL || *p == ';') 936c2aa98e2SPeter Wemm { 937c2aa98e2SPeter Wemm /* yep, it is */ 938c2aa98e2SPeter Wemm e->e_flags |= EF_DONT_MIME; 939c2aa98e2SPeter Wemm } 940c2aa98e2SPeter Wemm } 941c2aa98e2SPeter Wemm 942c2aa98e2SPeter Wemm /* 943c2aa98e2SPeter Wemm ** From person in antiquated ARPANET mode 944c2aa98e2SPeter Wemm ** required by UK Grey Book e-mail gateways (sigh) 945c2aa98e2SPeter Wemm */ 946c2aa98e2SPeter Wemm 947c2aa98e2SPeter Wemm if (OpMode == MD_ARPAFTP) 948c2aa98e2SPeter Wemm { 949c2aa98e2SPeter Wemm register struct hdrinfo *hi; 950c2aa98e2SPeter Wemm 951c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 952c2aa98e2SPeter Wemm { 953c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && 954c2aa98e2SPeter Wemm (!bitset(H_RESENT, hi->hi_flags) || 955c2aa98e2SPeter Wemm bitset(EF_RESENT, e->e_flags)) && 956c2aa98e2SPeter Wemm (p = hvalue(hi->hi_field, e->e_header)) != NULL) 957c2aa98e2SPeter Wemm break; 958c2aa98e2SPeter Wemm } 959c2aa98e2SPeter Wemm if (hi->hi_field != NULL) 960c2aa98e2SPeter Wemm { 961c2aa98e2SPeter Wemm if (tTd(32, 2)) 96212ed1c7cSGregory Neil Shapiro sm_dprintf("eatheader: setsender(*%s == %s)\n", 963c2aa98e2SPeter Wemm hi->hi_field, p); 96412ed1c7cSGregory Neil Shapiro setsender(p, e, NULL, '\0', true); 965c2aa98e2SPeter Wemm } 966c2aa98e2SPeter Wemm } 967c2aa98e2SPeter Wemm 968c2aa98e2SPeter Wemm /* 969c2aa98e2SPeter Wemm ** Log collection information. 970c2aa98e2SPeter Wemm */ 971c2aa98e2SPeter Wemm 97212ed1c7cSGregory Neil Shapiro if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 97312ed1c7cSGregory Neil Shapiro { 97412ed1c7cSGregory Neil Shapiro logsender(e, e->e_msgid); 975c2aa98e2SPeter Wemm e->e_flags &= ~EF_LOGSENDER; 976c2aa98e2SPeter Wemm } 97712ed1c7cSGregory Neil Shapiro } 97812ed1c7cSGregory Neil Shapiro /* 979c2aa98e2SPeter Wemm ** LOGSENDER -- log sender information 980c2aa98e2SPeter Wemm ** 981c2aa98e2SPeter Wemm ** Parameters: 982c2aa98e2SPeter Wemm ** e -- the envelope to log 983c2aa98e2SPeter Wemm ** msgid -- the message id 984c2aa98e2SPeter Wemm ** 985c2aa98e2SPeter Wemm ** Returns: 986c2aa98e2SPeter Wemm ** none 987c2aa98e2SPeter Wemm */ 988c2aa98e2SPeter Wemm 989c2aa98e2SPeter Wemm void 990c2aa98e2SPeter Wemm logsender(e, msgid) 991c2aa98e2SPeter Wemm register ENVELOPE *e; 992c2aa98e2SPeter Wemm char *msgid; 993c2aa98e2SPeter Wemm { 994c2aa98e2SPeter Wemm char *name; 995c2aa98e2SPeter Wemm register char *sbp; 996c2aa98e2SPeter Wemm register char *p; 997c2aa98e2SPeter Wemm char hbuf[MAXNAME + 1]; 998c2aa98e2SPeter Wemm char sbuf[MAXLINE + 1]; 999c2aa98e2SPeter Wemm char mbuf[MAXNAME + 1]; 1000c2aa98e2SPeter Wemm 1001c2aa98e2SPeter Wemm /* don't allow newlines in the message-id */ 100212ed1c7cSGregory Neil Shapiro /* XXX do we still need this? sm_syslog() replaces control chars */ 1003c2aa98e2SPeter Wemm if (msgid != NULL) 1004c2aa98e2SPeter Wemm { 1005567a2fc9SGregory Neil Shapiro size_t l; 1006567a2fc9SGregory Neil Shapiro 1007c2aa98e2SPeter Wemm l = strlen(msgid); 1008c2aa98e2SPeter Wemm if (l > sizeof mbuf - 1) 1009c2aa98e2SPeter Wemm l = sizeof mbuf - 1; 10103299c2f1SGregory Neil Shapiro memmove(mbuf, msgid, l); 1011c2aa98e2SPeter Wemm mbuf[l] = '\0'; 1012c2aa98e2SPeter Wemm p = mbuf; 1013c2aa98e2SPeter Wemm while ((p = strchr(p, '\n')) != NULL) 1014c2aa98e2SPeter Wemm *p++ = ' '; 1015c2aa98e2SPeter Wemm } 1016c2aa98e2SPeter Wemm 1017c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags)) 1018c2aa98e2SPeter Wemm name = "[RESPONSE]"; 1019c2aa98e2SPeter Wemm else if ((name = macvalue('_', e)) != NULL) 10203299c2f1SGregory Neil Shapiro /* EMPTY */ 1021c2aa98e2SPeter Wemm ; 1022c2aa98e2SPeter Wemm else if (RealHostName == NULL) 1023c2aa98e2SPeter Wemm name = "localhost"; 1024c2aa98e2SPeter Wemm else if (RealHostName[0] == '[') 1025c2aa98e2SPeter Wemm name = RealHostName; 1026c2aa98e2SPeter Wemm else 1027c2aa98e2SPeter Wemm { 1028c2aa98e2SPeter Wemm name = hbuf; 102912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName); 1030c2aa98e2SPeter Wemm if (RealHostAddr.sa.sa_family != 0) 1031c2aa98e2SPeter Wemm { 1032c2aa98e2SPeter Wemm p = &hbuf[strlen(hbuf)]; 103312ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 103412ed1c7cSGregory Neil Shapiro " (%.100s)", 1035c2aa98e2SPeter Wemm anynet_ntoa(&RealHostAddr)); 1036c2aa98e2SPeter Wemm } 1037c2aa98e2SPeter Wemm } 1038c2aa98e2SPeter Wemm 1039c2aa98e2SPeter Wemm /* some versions of syslog only take 5 printf args */ 1040c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256 1041c2aa98e2SPeter Wemm sbp = sbuf; 104212ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 10433299c2f1SGregory Neil Shapiro "from=%.200s, size=%ld, class=%d, nrcpts=%d", 1044c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 10453299c2f1SGregory Neil Shapiro e->e_msgsize, e->e_class, e->e_nrcpts); 1046c2aa98e2SPeter Wemm sbp += strlen(sbp); 1047c2aa98e2SPeter Wemm if (msgid != NULL) 1048c2aa98e2SPeter Wemm { 104912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 105012ed1c7cSGregory Neil Shapiro ", msgid=%.100s", mbuf); 1051c2aa98e2SPeter Wemm sbp += strlen(sbp); 1052c2aa98e2SPeter Wemm } 1053c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 1054c2aa98e2SPeter Wemm { 105512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 105612ed1c7cSGregory Neil Shapiro ", bodytype=%.20s", e->e_bodytype); 1057c2aa98e2SPeter Wemm sbp += strlen(sbp); 1058c2aa98e2SPeter Wemm } 1059c2aa98e2SPeter Wemm p = macvalue('r', e); 1060c2aa98e2SPeter Wemm if (p != NULL) 10613299c2f1SGregory Neil Shapiro { 106212ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 106312ed1c7cSGregory Neil Shapiro ", proto=%.20s", p); 10643299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 10653299c2f1SGregory Neil Shapiro } 106612ed1c7cSGregory Neil Shapiro p = macvalue(macid("{daemon_name}"), e); 10673299c2f1SGregory Neil Shapiro if (p != NULL) 10683299c2f1SGregory Neil Shapiro { 106912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 107012ed1c7cSGregory Neil Shapiro ", daemon=%.20s", p); 10713299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 10723299c2f1SGregory Neil Shapiro } 10732ef40764SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name); 1074c2aa98e2SPeter Wemm 10753299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */ 1076c2aa98e2SPeter Wemm 1077c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 1078c2aa98e2SPeter Wemm "from=%s", 1079c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>" 108012ed1c7cSGregory Neil Shapiro : shortenstring(e->e_from.q_paddr, 108112ed1c7cSGregory Neil Shapiro 83)); 1082c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 10833299c2f1SGregory Neil Shapiro "size=%ld, class=%ld, nrcpts=%d", 10843299c2f1SGregory Neil Shapiro e->e_msgsize, e->e_class, e->e_nrcpts); 1085c2aa98e2SPeter Wemm if (msgid != NULL) 1086c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 1087c2aa98e2SPeter Wemm "msgid=%s", 1088c2aa98e2SPeter Wemm shortenstring(mbuf, 83)); 1089c2aa98e2SPeter Wemm sbp = sbuf; 1090c2aa98e2SPeter Wemm *sbp = '\0'; 1091c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 1092c2aa98e2SPeter Wemm { 109312ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 109412ed1c7cSGregory Neil Shapiro "bodytype=%.20s, ", e->e_bodytype); 1095c2aa98e2SPeter Wemm sbp += strlen(sbp); 1096c2aa98e2SPeter Wemm } 1097c2aa98e2SPeter Wemm p = macvalue('r', e); 1098c2aa98e2SPeter Wemm if (p != NULL) 1099c2aa98e2SPeter Wemm { 110012ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 110112ed1c7cSGregory Neil Shapiro "proto=%.20s, ", p); 1102c2aa98e2SPeter Wemm sbp += strlen(sbp); 1103c2aa98e2SPeter Wemm } 1104c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 11052ef40764SGregory Neil Shapiro "%.400srelay=%s", sbuf, name); 11063299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 1107c2aa98e2SPeter Wemm } 110812ed1c7cSGregory Neil Shapiro /* 1109c2aa98e2SPeter Wemm ** PRIENCODE -- encode external priority names into internal values. 1110c2aa98e2SPeter Wemm ** 1111c2aa98e2SPeter Wemm ** Parameters: 1112c2aa98e2SPeter Wemm ** p -- priority in ascii. 1113c2aa98e2SPeter Wemm ** 1114c2aa98e2SPeter Wemm ** Returns: 1115c2aa98e2SPeter Wemm ** priority as a numeric level. 1116c2aa98e2SPeter Wemm ** 1117c2aa98e2SPeter Wemm ** Side Effects: 1118c2aa98e2SPeter Wemm ** none. 1119c2aa98e2SPeter Wemm */ 1120c2aa98e2SPeter Wemm 11213299c2f1SGregory Neil Shapiro static int 1122c2aa98e2SPeter Wemm priencode(p) 1123c2aa98e2SPeter Wemm char *p; 1124c2aa98e2SPeter Wemm { 1125c2aa98e2SPeter Wemm register int i; 1126c2aa98e2SPeter Wemm 1127c2aa98e2SPeter Wemm for (i = 0; i < NumPriorities; i++) 1128c2aa98e2SPeter Wemm { 112912ed1c7cSGregory Neil Shapiro if (sm_strcasecmp(p, Priorities[i].pri_name) == 0) 11303299c2f1SGregory Neil Shapiro return Priorities[i].pri_val; 1131c2aa98e2SPeter Wemm } 1132c2aa98e2SPeter Wemm 1133c2aa98e2SPeter Wemm /* unknown priority */ 11343299c2f1SGregory Neil Shapiro return 0; 1135c2aa98e2SPeter Wemm } 113612ed1c7cSGregory Neil Shapiro /* 1137c2aa98e2SPeter Wemm ** CRACKADDR -- parse an address and turn it into a macro 1138c2aa98e2SPeter Wemm ** 1139c2aa98e2SPeter Wemm ** This doesn't actually parse the address -- it just extracts 1140c2aa98e2SPeter Wemm ** it and replaces it with "$g". The parse is totally ad hoc 1141c2aa98e2SPeter Wemm ** and isn't even guaranteed to leave something syntactically 1142c2aa98e2SPeter Wemm ** identical to what it started with. However, it does leave 1143f9218d3dSGregory Neil Shapiro ** something semantically identical if possible, else at least 1144f9218d3dSGregory Neil Shapiro ** syntactically correct. 1145f9218d3dSGregory Neil Shapiro ** 1146f9218d3dSGregory Neil Shapiro ** For example, it changes "Real Name <real@example.com> (Comment)" 1147f9218d3dSGregory Neil Shapiro ** to "Real Name <$g> (Comment)". 1148c2aa98e2SPeter Wemm ** 1149c2aa98e2SPeter Wemm ** This algorithm has been cleaned up to handle a wider range 1150c2aa98e2SPeter Wemm ** of cases -- notably quoted and backslash escaped strings. 1151c2aa98e2SPeter Wemm ** This modification makes it substantially better at preserving 1152c2aa98e2SPeter Wemm ** the original syntax. 1153c2aa98e2SPeter Wemm ** 1154c2aa98e2SPeter Wemm ** Parameters: 1155c2aa98e2SPeter Wemm ** addr -- the address to be cracked. 1156f9218d3dSGregory Neil Shapiro ** e -- the current envelope. 1157c2aa98e2SPeter Wemm ** 1158c2aa98e2SPeter Wemm ** Returns: 1159c2aa98e2SPeter Wemm ** a pointer to the new version. 1160c2aa98e2SPeter Wemm ** 1161c2aa98e2SPeter Wemm ** Side Effects: 1162c2aa98e2SPeter Wemm ** none. 1163c2aa98e2SPeter Wemm ** 1164c2aa98e2SPeter Wemm ** Warning: 1165c2aa98e2SPeter Wemm ** The return value is saved in local storage and should 1166c2aa98e2SPeter Wemm ** be copied if it is to be reused. 1167c2aa98e2SPeter Wemm */ 1168c2aa98e2SPeter Wemm 1169f9218d3dSGregory Neil Shapiro #define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend)) 1170f9218d3dSGregory Neil Shapiro 1171f9218d3dSGregory Neil Shapiro /* 1172f9218d3dSGregory Neil Shapiro ** Append a character to bp if we have room. 1173f9218d3dSGregory Neil Shapiro ** If not, punt and return $g. 1174f9218d3dSGregory Neil Shapiro */ 1175f9218d3dSGregory Neil Shapiro 1176f9218d3dSGregory Neil Shapiro #define SM_APPEND_CHAR(c) \ 1177f9218d3dSGregory Neil Shapiro do \ 1178f9218d3dSGregory Neil Shapiro { \ 1179f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) \ 1180f9218d3dSGregory Neil Shapiro *bp++ = (c); \ 1181f9218d3dSGregory Neil Shapiro else \ 1182f9218d3dSGregory Neil Shapiro goto returng; \ 1183f9218d3dSGregory Neil Shapiro } while (0) 1184f9218d3dSGregory Neil Shapiro 1185f9218d3dSGregory Neil Shapiro #if MAXNAME < 10 1186f9218d3dSGregory Neil Shapiro ERROR MAXNAME must be at least 10 1187f9218d3dSGregory Neil Shapiro #endif /* MAXNAME < 10 */ 1188f9218d3dSGregory Neil Shapiro 1189c2aa98e2SPeter Wemm char * 1190f9218d3dSGregory Neil Shapiro crackaddr(addr, e) 1191c2aa98e2SPeter Wemm register char *addr; 1192f9218d3dSGregory Neil Shapiro ENVELOPE *e; 1193c2aa98e2SPeter Wemm { 1194c2aa98e2SPeter Wemm register char *p; 1195c2aa98e2SPeter Wemm register char c; 1196f9218d3dSGregory Neil Shapiro int cmtlev; /* comment level in input string */ 1197f9218d3dSGregory Neil Shapiro int realcmtlev; /* comment level in output string */ 1198f9218d3dSGregory Neil Shapiro int anglelev; /* angle level in input string */ 1199f9218d3dSGregory Neil Shapiro int copylev; /* 0 == in address, >0 copying */ 1200f9218d3dSGregory Neil Shapiro int bracklev; /* bracket level for IPv6 addr check */ 1201f9218d3dSGregory Neil Shapiro bool addangle; /* put closing angle in output */ 1202f9218d3dSGregory Neil Shapiro bool qmode; /* quoting in original string? */ 1203f9218d3dSGregory Neil Shapiro bool realqmode; /* quoting in output string? */ 1204f9218d3dSGregory Neil Shapiro bool putgmac = false; /* already wrote $g */ 1205f9218d3dSGregory Neil Shapiro bool quoteit = false; /* need to quote next character */ 1206f9218d3dSGregory Neil Shapiro bool gotangle = false; /* found first '<' */ 1207f9218d3dSGregory Neil Shapiro bool gotcolon = false; /* found a ':' */ 1208c2aa98e2SPeter Wemm register char *bp; 1209c2aa98e2SPeter Wemm char *buflim; 1210c2aa98e2SPeter Wemm char *bufhead; 1211c2aa98e2SPeter Wemm char *addrhead; 1212f9218d3dSGregory Neil Shapiro char *bufend; 1213c2aa98e2SPeter Wemm static char buf[MAXNAME + 1]; 1214c2aa98e2SPeter Wemm 1215c2aa98e2SPeter Wemm if (tTd(33, 1)) 121612ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr(%s)\n", addr); 1217c2aa98e2SPeter Wemm 1218c2aa98e2SPeter Wemm /* strip leading spaces */ 1219c2aa98e2SPeter Wemm while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 1220c2aa98e2SPeter Wemm addr++; 1221c2aa98e2SPeter Wemm 1222c2aa98e2SPeter Wemm /* 1223c2aa98e2SPeter Wemm ** Start by assuming we have no angle brackets. This will be 1224c2aa98e2SPeter Wemm ** adjusted later if we find them. 1225c2aa98e2SPeter Wemm */ 1226c2aa98e2SPeter Wemm 1227f9218d3dSGregory Neil Shapiro buflim = bufend = &buf[sizeof(buf) - 1]; 1228c2aa98e2SPeter Wemm bp = bufhead = buf; 1229c2aa98e2SPeter Wemm p = addrhead = addr; 1230f9218d3dSGregory Neil Shapiro copylev = anglelev = cmtlev = realcmtlev = 0; 1231c2aa98e2SPeter Wemm bracklev = 0; 1232f9218d3dSGregory Neil Shapiro qmode = realqmode = addangle = false; 1233c2aa98e2SPeter Wemm 1234c2aa98e2SPeter Wemm while ((c = *p++) != '\0') 1235c2aa98e2SPeter Wemm { 1236c2aa98e2SPeter Wemm /* 1237f9218d3dSGregory Neil Shapiro ** Try to keep legal syntax using spare buffer space 1238f9218d3dSGregory Neil Shapiro ** (maintained by buflim). 1239c2aa98e2SPeter Wemm */ 1240c2aa98e2SPeter Wemm 1241f9218d3dSGregory Neil Shapiro if (copylev > 0) 1242f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1243c2aa98e2SPeter Wemm 1244c2aa98e2SPeter Wemm /* check for backslash escapes */ 1245c2aa98e2SPeter Wemm if (c == '\\') 1246c2aa98e2SPeter Wemm { 1247c2aa98e2SPeter Wemm /* arrange to quote the address */ 1248c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 124912ed1c7cSGregory Neil Shapiro quoteit = true; 1250c2aa98e2SPeter Wemm 1251c2aa98e2SPeter Wemm if ((c = *p++) == '\0') 1252c2aa98e2SPeter Wemm { 1253c2aa98e2SPeter Wemm /* too far */ 1254c2aa98e2SPeter Wemm p--; 1255c2aa98e2SPeter Wemm goto putg; 1256c2aa98e2SPeter Wemm } 1257f9218d3dSGregory Neil Shapiro if (copylev > 0) 1258f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1259c2aa98e2SPeter Wemm goto putg; 1260c2aa98e2SPeter Wemm } 1261c2aa98e2SPeter Wemm 1262c2aa98e2SPeter Wemm /* check for quoted strings */ 1263c2aa98e2SPeter Wemm if (c == '"' && cmtlev <= 0) 1264c2aa98e2SPeter Wemm { 1265c2aa98e2SPeter Wemm qmode = !qmode; 1266f9218d3dSGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM) 1267f9218d3dSGregory Neil Shapiro { 1268f9218d3dSGregory Neil Shapiro if (realqmode) 1269f9218d3dSGregory Neil Shapiro buflim--; 1270f9218d3dSGregory Neil Shapiro else 1271f9218d3dSGregory Neil Shapiro buflim++; 1272c2aa98e2SPeter Wemm realqmode = !realqmode; 1273f9218d3dSGregory Neil Shapiro } 1274c2aa98e2SPeter Wemm continue; 1275c2aa98e2SPeter Wemm } 1276c2aa98e2SPeter Wemm if (qmode) 1277c2aa98e2SPeter Wemm goto putg; 1278c2aa98e2SPeter Wemm 1279c2aa98e2SPeter Wemm /* check for comments */ 1280c2aa98e2SPeter Wemm if (c == '(') 1281c2aa98e2SPeter Wemm { 1282c2aa98e2SPeter Wemm cmtlev++; 1283c2aa98e2SPeter Wemm 1284c2aa98e2SPeter Wemm /* allow space for closing paren */ 1285f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1286c2aa98e2SPeter Wemm { 1287c2aa98e2SPeter Wemm buflim--; 1288c2aa98e2SPeter Wemm realcmtlev++; 1289c2aa98e2SPeter Wemm if (copylev++ <= 0) 1290c2aa98e2SPeter Wemm { 1291c2aa98e2SPeter Wemm if (bp != bufhead) 1292f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' '); 1293f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1294c2aa98e2SPeter Wemm } 1295c2aa98e2SPeter Wemm } 1296c2aa98e2SPeter Wemm } 1297c2aa98e2SPeter Wemm if (cmtlev > 0) 1298c2aa98e2SPeter Wemm { 1299c2aa98e2SPeter Wemm if (c == ')') 1300c2aa98e2SPeter Wemm { 1301c2aa98e2SPeter Wemm cmtlev--; 1302c2aa98e2SPeter Wemm copylev--; 1303f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1304c2aa98e2SPeter Wemm { 1305c2aa98e2SPeter Wemm realcmtlev--; 1306c2aa98e2SPeter Wemm buflim++; 1307c2aa98e2SPeter Wemm } 1308c2aa98e2SPeter Wemm } 1309c2aa98e2SPeter Wemm continue; 1310c2aa98e2SPeter Wemm } 1311c2aa98e2SPeter Wemm else if (c == ')') 1312c2aa98e2SPeter Wemm { 1313c2aa98e2SPeter Wemm /* syntax error: unmatched ) */ 13147660b554SGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead) 1315c2aa98e2SPeter Wemm bp--; 1316c2aa98e2SPeter Wemm } 1317c2aa98e2SPeter Wemm 1318c2aa98e2SPeter Wemm /* count nesting on [ ... ] (for IPv6 domain literals) */ 1319c2aa98e2SPeter Wemm if (c == '[') 1320c2aa98e2SPeter Wemm bracklev++; 1321c2aa98e2SPeter Wemm else if (c == ']') 1322c2aa98e2SPeter Wemm bracklev--; 1323c2aa98e2SPeter Wemm 1324c2aa98e2SPeter Wemm /* check for group: list; syntax */ 1325c2aa98e2SPeter Wemm if (c == ':' && anglelev <= 0 && bracklev <= 0 && 1326c2aa98e2SPeter Wemm !gotcolon && !ColonOkInAddr) 1327c2aa98e2SPeter Wemm { 1328c2aa98e2SPeter Wemm register char *q; 1329c2aa98e2SPeter Wemm 1330c2aa98e2SPeter Wemm /* 1331c2aa98e2SPeter Wemm ** Check for DECnet phase IV ``::'' (host::user) 1332f9218d3dSGregory Neil Shapiro ** or DECnet phase V ``:.'' syntaxes. The latter 1333c2aa98e2SPeter Wemm ** covers ``user@DEC:.tay.myhost'' and 1334c2aa98e2SPeter Wemm ** ``DEC:.tay.myhost::user'' syntaxes (bletch). 1335c2aa98e2SPeter Wemm */ 1336c2aa98e2SPeter Wemm 1337c2aa98e2SPeter Wemm if (*p == ':' || *p == '.') 1338c2aa98e2SPeter Wemm { 1339c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 134012ed1c7cSGregory Neil Shapiro quoteit = true; 1341f9218d3dSGregory Neil Shapiro if (copylev > 0) 1342c2aa98e2SPeter Wemm { 1343f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1344f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p); 1345c2aa98e2SPeter Wemm } 1346c2aa98e2SPeter Wemm p++; 1347c2aa98e2SPeter Wemm goto putg; 1348c2aa98e2SPeter Wemm } 1349c2aa98e2SPeter Wemm 135012ed1c7cSGregory Neil Shapiro gotcolon = true; 1351c2aa98e2SPeter Wemm 1352c2aa98e2SPeter Wemm bp = bufhead; 1353c2aa98e2SPeter Wemm if (quoteit) 1354c2aa98e2SPeter Wemm { 1355f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1356c2aa98e2SPeter Wemm 1357c2aa98e2SPeter Wemm /* back up over the ':' and any spaces */ 1358c2aa98e2SPeter Wemm --p; 1359f9218d3dSGregory Neil Shapiro while (p > addr && 1360f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p)) 1361c2aa98e2SPeter Wemm continue; 1362c2aa98e2SPeter Wemm p++; 1363c2aa98e2SPeter Wemm } 1364c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1365c2aa98e2SPeter Wemm { 1366c2aa98e2SPeter Wemm c = *q++; 1367c2aa98e2SPeter Wemm if (quoteit && c == '"') 1368f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\'); 1369f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1370c2aa98e2SPeter Wemm } 1371c2aa98e2SPeter Wemm if (quoteit) 1372c2aa98e2SPeter Wemm { 1373c2aa98e2SPeter Wemm if (bp == &bufhead[1]) 1374c2aa98e2SPeter Wemm bp--; 1375c2aa98e2SPeter Wemm else 1376f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1377c2aa98e2SPeter Wemm while ((c = *p++) != ':') 1378f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1379f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1380c2aa98e2SPeter Wemm } 1381c2aa98e2SPeter Wemm 1382c2aa98e2SPeter Wemm /* any trailing white space is part of group: */ 1383f9218d3dSGregory Neil Shapiro while (isascii(*p) && isspace(*p)) 1384f9218d3dSGregory Neil Shapiro { 1385f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p); 1386f9218d3dSGregory Neil Shapiro p++; 1387f9218d3dSGregory Neil Shapiro } 1388c2aa98e2SPeter Wemm copylev = 0; 138912ed1c7cSGregory Neil Shapiro putgmac = quoteit = false; 1390c2aa98e2SPeter Wemm bufhead = bp; 1391c2aa98e2SPeter Wemm addrhead = p; 1392c2aa98e2SPeter Wemm continue; 1393c2aa98e2SPeter Wemm } 1394c2aa98e2SPeter Wemm 1395c2aa98e2SPeter Wemm if (c == ';' && copylev <= 0 && !ColonOkInAddr) 1396f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1397c2aa98e2SPeter Wemm 1398c2aa98e2SPeter Wemm /* check for characters that may have to be quoted */ 1399c2aa98e2SPeter Wemm if (strchr(MustQuoteChars, c) != NULL) 1400c2aa98e2SPeter Wemm { 1401c2aa98e2SPeter Wemm /* 1402c2aa98e2SPeter Wemm ** If these occur as the phrase part of a <> 1403c2aa98e2SPeter Wemm ** construct, but are not inside of () or already 1404c2aa98e2SPeter Wemm ** quoted, they will have to be quoted. Note that 1405c2aa98e2SPeter Wemm ** now (but don't actually do the quoting). 1406c2aa98e2SPeter Wemm */ 1407c2aa98e2SPeter Wemm 1408c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 140912ed1c7cSGregory Neil Shapiro quoteit = true; 1410c2aa98e2SPeter Wemm } 1411c2aa98e2SPeter Wemm 1412c2aa98e2SPeter Wemm /* check for angle brackets */ 1413c2aa98e2SPeter Wemm if (c == '<') 1414c2aa98e2SPeter Wemm { 1415c2aa98e2SPeter Wemm register char *q; 1416c2aa98e2SPeter Wemm 1417c2aa98e2SPeter Wemm /* assume first of two angles is bogus */ 1418c2aa98e2SPeter Wemm if (gotangle) 141912ed1c7cSGregory Neil Shapiro quoteit = true; 142012ed1c7cSGregory Neil Shapiro gotangle = true; 1421c2aa98e2SPeter Wemm 1422c2aa98e2SPeter Wemm /* oops -- have to change our mind */ 1423c2aa98e2SPeter Wemm anglelev = 1; 1424f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1425f9218d3dSGregory Neil Shapiro { 1426f9218d3dSGregory Neil Shapiro if (!addangle) 1427f9218d3dSGregory Neil Shapiro buflim--; 1428f9218d3dSGregory Neil Shapiro addangle = true; 1429f9218d3dSGregory Neil Shapiro } 1430c2aa98e2SPeter Wemm 1431c2aa98e2SPeter Wemm bp = bufhead; 1432c2aa98e2SPeter Wemm if (quoteit) 1433c2aa98e2SPeter Wemm { 1434f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1435c2aa98e2SPeter Wemm 1436c2aa98e2SPeter Wemm /* back up over the '<' and any spaces */ 1437c2aa98e2SPeter Wemm --p; 1438f9218d3dSGregory Neil Shapiro while (p > addr && 1439f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p)) 1440c2aa98e2SPeter Wemm continue; 1441c2aa98e2SPeter Wemm p++; 1442c2aa98e2SPeter Wemm } 1443c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1444c2aa98e2SPeter Wemm { 1445c2aa98e2SPeter Wemm c = *q++; 1446c2aa98e2SPeter Wemm if (quoteit && c == '"') 1447f9218d3dSGregory Neil Shapiro { 1448f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\'); 1449f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1450c2aa98e2SPeter Wemm } 1451f9218d3dSGregory Neil Shapiro else 1452f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1453c2aa98e2SPeter Wemm } 1454c2aa98e2SPeter Wemm if (quoteit) 1455c2aa98e2SPeter Wemm { 1456c2aa98e2SPeter Wemm if (bp == &buf[1]) 1457c2aa98e2SPeter Wemm bp--; 1458c2aa98e2SPeter Wemm else 1459f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"'); 1460c2aa98e2SPeter Wemm while ((c = *p++) != '<') 1461f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1462f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1463c2aa98e2SPeter Wemm } 1464c2aa98e2SPeter Wemm copylev = 0; 146512ed1c7cSGregory Neil Shapiro putgmac = quoteit = false; 1466c2aa98e2SPeter Wemm continue; 1467c2aa98e2SPeter Wemm } 1468c2aa98e2SPeter Wemm 1469c2aa98e2SPeter Wemm if (c == '>') 1470c2aa98e2SPeter Wemm { 1471c2aa98e2SPeter Wemm if (anglelev > 0) 1472c2aa98e2SPeter Wemm { 1473c2aa98e2SPeter Wemm anglelev--; 1474f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) 1475c2aa98e2SPeter Wemm { 1476f9218d3dSGregory Neil Shapiro if (addangle) 1477c2aa98e2SPeter Wemm buflim++; 1478f9218d3dSGregory Neil Shapiro addangle = false; 1479c2aa98e2SPeter Wemm } 1480c2aa98e2SPeter Wemm } 1481f9218d3dSGregory Neil Shapiro else if (SM_HAVE_ROOM) 1482c2aa98e2SPeter Wemm { 1483c2aa98e2SPeter Wemm /* syntax error: unmatched > */ 14847660b554SGregory Neil Shapiro if (copylev > 0 && bp > bufhead) 1485c2aa98e2SPeter Wemm bp--; 148612ed1c7cSGregory Neil Shapiro quoteit = true; 1487c2aa98e2SPeter Wemm continue; 1488c2aa98e2SPeter Wemm } 1489c2aa98e2SPeter Wemm if (copylev++ <= 0) 1490f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c); 1491c2aa98e2SPeter Wemm continue; 1492c2aa98e2SPeter Wemm } 1493c2aa98e2SPeter Wemm 1494c2aa98e2SPeter Wemm /* must be a real address character */ 1495c2aa98e2SPeter Wemm putg: 1496c2aa98e2SPeter Wemm if (copylev <= 0 && !putgmac) 1497c2aa98e2SPeter Wemm { 1498f9218d3dSGregory Neil Shapiro if (bp > buf && bp[-1] == ')') 1499f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' '); 1500f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(MACROEXPAND); 1501f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('g'); 150212ed1c7cSGregory Neil Shapiro putgmac = true; 1503c2aa98e2SPeter Wemm } 1504c2aa98e2SPeter Wemm } 1505c2aa98e2SPeter Wemm 1506c2aa98e2SPeter Wemm /* repair any syntactic damage */ 1507f9218d3dSGregory Neil Shapiro if (realqmode && bp < bufend) 1508c2aa98e2SPeter Wemm *bp++ = '"'; 1509f9218d3dSGregory Neil Shapiro while (realcmtlev-- > 0 && bp < bufend) 1510c2aa98e2SPeter Wemm *bp++ = ')'; 1511f9218d3dSGregory Neil Shapiro if (addangle && bp < bufend) 1512c2aa98e2SPeter Wemm *bp++ = '>'; 1513f9218d3dSGregory Neil Shapiro *bp = '\0'; 1514f9218d3dSGregory Neil Shapiro if (bp < bufend) 1515f9218d3dSGregory Neil Shapiro goto success; 1516c2aa98e2SPeter Wemm 1517f9218d3dSGregory Neil Shapiro returng: 1518f9218d3dSGregory Neil Shapiro /* String too long, punt */ 1519f9218d3dSGregory Neil Shapiro buf[0] = '<'; 1520f9218d3dSGregory Neil Shapiro buf[1] = MACROEXPAND; 1521f9218d3dSGregory Neil Shapiro buf[2]= 'g'; 1522f9218d3dSGregory Neil Shapiro buf[3] = '>'; 1523f9218d3dSGregory Neil Shapiro buf[4]= '\0'; 1524f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 1525f9218d3dSGregory Neil Shapiro "Dropped invalid comments from header address"); 1526f9218d3dSGregory Neil Shapiro 1527f9218d3dSGregory Neil Shapiro success: 1528c2aa98e2SPeter Wemm if (tTd(33, 1)) 1529c2aa98e2SPeter Wemm { 153012ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr=>`"); 1531bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), buf); 153212ed1c7cSGregory Neil Shapiro sm_dprintf("'\n"); 1533c2aa98e2SPeter Wemm } 15343299c2f1SGregory Neil Shapiro return buf; 1535c2aa98e2SPeter Wemm } 153612ed1c7cSGregory Neil Shapiro /* 1537c2aa98e2SPeter Wemm ** PUTHEADER -- put the header part of a message from the in-core copy 1538c2aa98e2SPeter Wemm ** 1539c2aa98e2SPeter Wemm ** Parameters: 1540c2aa98e2SPeter Wemm ** mci -- the connection information. 15413299c2f1SGregory Neil Shapiro ** hdr -- the header to put. 1542c2aa98e2SPeter Wemm ** e -- envelope to use. 1543e01d6f61SPeter Wemm ** flags -- MIME conversion flags. 1544c2aa98e2SPeter Wemm ** 1545c2aa98e2SPeter Wemm ** Returns: 1546355d91e3SGregory Neil Shapiro ** true iff header part was written successfully 1547c2aa98e2SPeter Wemm ** 1548c2aa98e2SPeter Wemm ** Side Effects: 1549c2aa98e2SPeter Wemm ** none. 1550c2aa98e2SPeter Wemm */ 1551c2aa98e2SPeter Wemm 1552567a2fc9SGregory Neil Shapiro bool 1553e01d6f61SPeter Wemm putheader(mci, hdr, e, flags) 1554c2aa98e2SPeter Wemm register MCI *mci; 1555c2aa98e2SPeter Wemm HDR *hdr; 1556c2aa98e2SPeter Wemm register ENVELOPE *e; 1557e01d6f61SPeter Wemm int flags; 1558c2aa98e2SPeter Wemm { 1559c2aa98e2SPeter Wemm register HDR *h; 156012ed1c7cSGregory Neil Shapiro char buf[SM_MAX(MAXLINE,BUFSIZ)]; 1561c2aa98e2SPeter Wemm char obuf[MAXLINE]; 1562c2aa98e2SPeter Wemm 1563c2aa98e2SPeter Wemm if (tTd(34, 1)) 156412ed1c7cSGregory Neil Shapiro sm_dprintf("--- putheader, mailer = %s ---\n", 1565c2aa98e2SPeter Wemm mci->mci_mailer->m_name); 1566c2aa98e2SPeter Wemm 1567c2aa98e2SPeter Wemm /* 1568c2aa98e2SPeter Wemm ** If we're in MIME mode, we're not really in the header of the 1569c2aa98e2SPeter Wemm ** message, just the header of one of the parts of the body of 1570c2aa98e2SPeter Wemm ** the message. Therefore MCIF_INHEADER should not be turned on. 1571c2aa98e2SPeter Wemm */ 1572c2aa98e2SPeter Wemm 1573c2aa98e2SPeter Wemm if (!bitset(MCIF_INMIME, mci->mci_flags)) 1574c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 1575c2aa98e2SPeter Wemm 1576c2aa98e2SPeter Wemm for (h = hdr; h != NULL; h = h->h_link) 1577c2aa98e2SPeter Wemm { 1578c2aa98e2SPeter Wemm register char *p = h->h_value; 157912ed1c7cSGregory Neil Shapiro char *q; 1580c2aa98e2SPeter Wemm 1581c2aa98e2SPeter Wemm if (tTd(34, 11)) 1582c2aa98e2SPeter Wemm { 158312ed1c7cSGregory Neil Shapiro sm_dprintf(" %s: ", h->h_field); 1584bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), p); 1585c2aa98e2SPeter Wemm } 1586c2aa98e2SPeter Wemm 15873299c2f1SGregory Neil Shapiro /* Skip empty headers */ 15883299c2f1SGregory Neil Shapiro if (h->h_value == NULL) 15893299c2f1SGregory Neil Shapiro continue; 15903299c2f1SGregory Neil Shapiro 159176b7bf71SPeter Wemm /* heuristic shortening of MIME fields to avoid MUA overflows */ 159276b7bf71SPeter Wemm if (MaxMimeFieldLength > 0 && 159376b7bf71SPeter Wemm wordinclass(h->h_field, 159412ed1c7cSGregory Neil Shapiro macid("{checkMIMEFieldHeaders}"))) 159576b7bf71SPeter Wemm { 1596c46d91b7SGregory Neil Shapiro size_t len; 1597c46d91b7SGregory Neil Shapiro 1598f9218d3dSGregory Neil Shapiro len = fix_mime_header(h, e); 1599c46d91b7SGregory Neil Shapiro if (len > 0) 160076b7bf71SPeter Wemm { 160176b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1602c46d91b7SGregory Neil Shapiro "Truncated MIME %s header due to field size (length = %ld) (possible attack)", 1603c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 160476b7bf71SPeter Wemm if (tTd(34, 11)) 160512ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", 1606c46d91b7SGregory Neil Shapiro h->h_field, 1607c46d91b7SGregory Neil Shapiro (unsigned long) len); 160876b7bf71SPeter Wemm } 160976b7bf71SPeter Wemm } 161076b7bf71SPeter Wemm 161176b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 161276b7bf71SPeter Wemm wordinclass(h->h_field, 161312ed1c7cSGregory Neil Shapiro macid("{checkMIMETextHeaders}"))) 161476b7bf71SPeter Wemm { 1615c46d91b7SGregory Neil Shapiro size_t len; 1616c46d91b7SGregory Neil Shapiro 1617c46d91b7SGregory Neil Shapiro len = strlen(h->h_value); 1618c46d91b7SGregory Neil Shapiro if (len > (size_t) MaxMimeHeaderLength) 161976b7bf71SPeter Wemm { 162076b7bf71SPeter Wemm h->h_value[MaxMimeHeaderLength - 1] = '\0'; 162176b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1622c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1623c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 162476b7bf71SPeter Wemm if (tTd(34, 11)) 162512ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1626c46d91b7SGregory Neil Shapiro h->h_field, 1627c46d91b7SGregory Neil Shapiro (unsigned long) len); 162876b7bf71SPeter Wemm } 162976b7bf71SPeter Wemm } 163076b7bf71SPeter Wemm 163176b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 163276b7bf71SPeter Wemm wordinclass(h->h_field, 163312ed1c7cSGregory Neil Shapiro macid("{checkMIMEHeaders}"))) 163476b7bf71SPeter Wemm { 1635c46d91b7SGregory Neil Shapiro size_t len; 1636c46d91b7SGregory Neil Shapiro 1637c46d91b7SGregory Neil Shapiro len = strlen(h->h_value); 1638c46d91b7SGregory Neil Shapiro if (shorten_rfc822_string(h->h_value, 1639c46d91b7SGregory Neil Shapiro MaxMimeHeaderLength)) 164076b7bf71SPeter Wemm { 1641f9218d3dSGregory Neil Shapiro if (len < MaxMimeHeaderLength) 1642f9218d3dSGregory Neil Shapiro { 1643f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus header */ 1644f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 1645f9218d3dSGregory Neil Shapiro "Fixed MIME %s header (possible attack)", 1646f9218d3dSGregory Neil Shapiro h->h_field); 1647f9218d3dSGregory Neil Shapiro if (tTd(34, 11)) 1648f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header (possible attack)\n", 1649f9218d3dSGregory Neil Shapiro h->h_field); 1650f9218d3dSGregory Neil Shapiro } 1651f9218d3dSGregory Neil Shapiro else 1652f9218d3dSGregory Neil Shapiro { 1653f9218d3dSGregory Neil Shapiro /* we actually shortened header */ 165476b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1655c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1656f9218d3dSGregory Neil Shapiro h->h_field, 1657f9218d3dSGregory Neil Shapiro (unsigned long) len); 165876b7bf71SPeter Wemm if (tTd(34, 11)) 165912ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1660c46d91b7SGregory Neil Shapiro h->h_field, 1661c46d91b7SGregory Neil Shapiro (unsigned long) len); 166276b7bf71SPeter Wemm } 166376b7bf71SPeter Wemm } 1664f9218d3dSGregory Neil Shapiro } 166576b7bf71SPeter Wemm 1666e01d6f61SPeter Wemm /* 1667e01d6f61SPeter Wemm ** Suppress Content-Transfer-Encoding: if we are MIMEing 1668e01d6f61SPeter Wemm ** and we are potentially converting from 8 bit to 7 bit 1669e01d6f61SPeter Wemm ** MIME. If converting, add a new CTE header in 1670e01d6f61SPeter Wemm ** mime8to7(). 1671e01d6f61SPeter Wemm */ 167212ed1c7cSGregory Neil Shapiro 1673c2aa98e2SPeter Wemm if (bitset(H_CTE, h->h_flags) && 1674e01d6f61SPeter Wemm bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 1675e01d6f61SPeter Wemm mci->mci_flags) && 1676e01d6f61SPeter Wemm !bitset(M87F_NO8TO7, flags)) 1677c2aa98e2SPeter Wemm { 1678c2aa98e2SPeter Wemm if (tTd(34, 11)) 167912ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (content-transfer-encoding))\n"); 1680c2aa98e2SPeter Wemm continue; 1681c2aa98e2SPeter Wemm } 1682c2aa98e2SPeter Wemm 1683c2aa98e2SPeter Wemm if (bitset(MCIF_INMIME, mci->mci_flags)) 1684c2aa98e2SPeter Wemm { 1685c2aa98e2SPeter Wemm if (tTd(34, 11)) 168612ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 1687567a2fc9SGregory Neil Shapiro if (!put_vanilla_header(h, p, mci)) 1688567a2fc9SGregory Neil Shapiro goto writeerr; 1689c2aa98e2SPeter Wemm continue; 1690c2aa98e2SPeter Wemm } 1691c2aa98e2SPeter Wemm 1692c2aa98e2SPeter Wemm if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 16933299c2f1SGregory Neil Shapiro !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && 16943299c2f1SGregory Neil Shapiro (h->h_macro == '\0' || 169512ed1c7cSGregory Neil Shapiro (q = macvalue(bitidx(h->h_macro), e)) == NULL || 169612ed1c7cSGregory Neil Shapiro *q == '\0')) 1697c2aa98e2SPeter Wemm { 1698c2aa98e2SPeter Wemm if (tTd(34, 11)) 169912ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped)\n"); 1700c2aa98e2SPeter Wemm continue; 1701c2aa98e2SPeter Wemm } 1702c2aa98e2SPeter Wemm 1703c2aa98e2SPeter Wemm /* handle Resent-... headers specially */ 1704c2aa98e2SPeter Wemm if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 1705c2aa98e2SPeter Wemm { 1706c2aa98e2SPeter Wemm if (tTd(34, 11)) 170712ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (resent))\n"); 1708c2aa98e2SPeter Wemm continue; 1709c2aa98e2SPeter Wemm } 1710c2aa98e2SPeter Wemm 1711c2aa98e2SPeter Wemm /* suppress return receipts if requested */ 1712c2aa98e2SPeter Wemm if (bitset(H_RECEIPTTO, h->h_flags) && 1713c2aa98e2SPeter Wemm (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) 1714c2aa98e2SPeter Wemm { 1715c2aa98e2SPeter Wemm if (tTd(34, 11)) 171612ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (receipt))\n"); 1717c2aa98e2SPeter Wemm continue; 1718c2aa98e2SPeter Wemm } 1719c2aa98e2SPeter Wemm 1720c2aa98e2SPeter Wemm /* macro expand value if generated internally */ 17213299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) || 17223299c2f1SGregory Neil Shapiro bitset(H_BINDLATE, h->h_flags)) 1723c2aa98e2SPeter Wemm { 1724c2aa98e2SPeter Wemm expand(p, buf, sizeof buf, e); 1725c2aa98e2SPeter Wemm p = buf; 1726c2aa98e2SPeter Wemm if (*p == '\0') 1727c2aa98e2SPeter Wemm { 1728c2aa98e2SPeter Wemm if (tTd(34, 11)) 172912ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- null value)\n"); 1730c2aa98e2SPeter Wemm continue; 1731c2aa98e2SPeter Wemm } 1732c2aa98e2SPeter Wemm } 1733c2aa98e2SPeter Wemm 1734c2aa98e2SPeter Wemm if (bitset(H_BCC, h->h_flags)) 1735c2aa98e2SPeter Wemm { 1736c2aa98e2SPeter Wemm /* Bcc: field -- either truncate or delete */ 1737c2aa98e2SPeter Wemm if (bitset(EF_DELETE_BCC, e->e_flags)) 1738c2aa98e2SPeter Wemm { 1739c2aa98e2SPeter Wemm if (tTd(34, 11)) 174012ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- bcc)\n"); 1741c2aa98e2SPeter Wemm } 1742c2aa98e2SPeter Wemm else 1743c2aa98e2SPeter Wemm { 1744c2aa98e2SPeter Wemm /* no other recipient headers: truncate value */ 174512ed1c7cSGregory Neil Shapiro (void) sm_strlcpyn(obuf, sizeof obuf, 2, 174612ed1c7cSGregory Neil Shapiro h->h_field, ":"); 1747567a2fc9SGregory Neil Shapiro if (!putline(obuf, mci)) 1748567a2fc9SGregory Neil Shapiro goto writeerr; 1749c2aa98e2SPeter Wemm } 1750c2aa98e2SPeter Wemm continue; 1751c2aa98e2SPeter Wemm } 1752c2aa98e2SPeter Wemm 1753c2aa98e2SPeter Wemm if (tTd(34, 11)) 175412ed1c7cSGregory Neil Shapiro sm_dprintf("\n"); 1755c2aa98e2SPeter Wemm 1756c2aa98e2SPeter Wemm if (bitset(H_FROM|H_RCPT, h->h_flags)) 1757c2aa98e2SPeter Wemm { 1758c2aa98e2SPeter Wemm /* address field */ 1759c2aa98e2SPeter Wemm bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 1760c2aa98e2SPeter Wemm 1761c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 176212ed1c7cSGregory Neil Shapiro oldstyle = false; 1763c2aa98e2SPeter Wemm commaize(h, p, oldstyle, mci, e); 1764c2aa98e2SPeter Wemm } 1765c2aa98e2SPeter Wemm else 1766c2aa98e2SPeter Wemm { 1767567a2fc9SGregory Neil Shapiro if (!put_vanilla_header(h, p, mci)) 1768567a2fc9SGregory Neil Shapiro goto writeerr; 1769c2aa98e2SPeter Wemm } 1770c2aa98e2SPeter Wemm } 1771c2aa98e2SPeter Wemm 1772c2aa98e2SPeter Wemm /* 1773c2aa98e2SPeter Wemm ** If we are converting this to a MIME message, add the 17743299c2f1SGregory Neil Shapiro ** MIME headers (but not in MIME mode!). 1775c2aa98e2SPeter Wemm */ 1776c2aa98e2SPeter Wemm 1777c2aa98e2SPeter Wemm #if MIME8TO7 1778c2aa98e2SPeter Wemm if (bitset(MM_MIME8BIT, MimeMode) && 1779c2aa98e2SPeter Wemm bitset(EF_HAS8BIT, e->e_flags) && 1780c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 1781c2aa98e2SPeter Wemm !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 17823299c2f1SGregory Neil Shapiro !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) && 17833299c2f1SGregory Neil Shapiro hvalue("MIME-Version", e->e_header) == NULL) 1784c2aa98e2SPeter Wemm { 1785567a2fc9SGregory Neil Shapiro if (!putline("MIME-Version: 1.0", mci)) 1786567a2fc9SGregory Neil Shapiro goto writeerr; 1787c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL) 1788c2aa98e2SPeter Wemm { 178912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof obuf, 1790c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s", 1791c2aa98e2SPeter Wemm defcharset(e)); 1792567a2fc9SGregory Neil Shapiro if (!putline(obuf, mci)) 1793567a2fc9SGregory Neil Shapiro goto writeerr; 1794c2aa98e2SPeter Wemm } 1795567a2fc9SGregory Neil Shapiro if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL 1796567a2fc9SGregory Neil Shapiro && !putline("Content-Transfer-Encoding: 8bit", mci)) 1797567a2fc9SGregory Neil Shapiro goto writeerr; 1798c2aa98e2SPeter Wemm } 17993299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */ 1800567a2fc9SGregory Neil Shapiro return true; 1801567a2fc9SGregory Neil Shapiro 1802567a2fc9SGregory Neil Shapiro writeerr: 1803567a2fc9SGregory Neil Shapiro return false; 1804c2aa98e2SPeter Wemm } 180512ed1c7cSGregory Neil Shapiro /* 1806c2aa98e2SPeter Wemm ** PUT_VANILLA_HEADER -- output a fairly ordinary header 1807c2aa98e2SPeter Wemm ** 1808c2aa98e2SPeter Wemm ** Parameters: 1809c2aa98e2SPeter Wemm ** h -- the structure describing this header 1810c2aa98e2SPeter Wemm ** v -- the value of this header 1811c2aa98e2SPeter Wemm ** mci -- the connection info for output 1812c2aa98e2SPeter Wemm ** 1813c2aa98e2SPeter Wemm ** Returns: 1814355d91e3SGregory Neil Shapiro ** true iff header was written successfully 1815c2aa98e2SPeter Wemm */ 1816c2aa98e2SPeter Wemm 1817567a2fc9SGregory Neil Shapiro static bool 1818c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci) 1819c2aa98e2SPeter Wemm HDR *h; 1820c2aa98e2SPeter Wemm char *v; 1821c2aa98e2SPeter Wemm MCI *mci; 1822c2aa98e2SPeter Wemm { 1823c2aa98e2SPeter Wemm register char *nlp; 1824c2aa98e2SPeter Wemm register char *obp; 1825c2aa98e2SPeter Wemm int putflags; 1826684b2a5fSGregory Neil Shapiro char obuf[MAXLINE + 256]; /* additional length for h_field */ 1827c2aa98e2SPeter Wemm 1828c2aa98e2SPeter Wemm putflags = PXLF_HEADER; 1829c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1830c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 183112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field); 1832c2aa98e2SPeter Wemm obp = obuf + strlen(obuf); 1833c2aa98e2SPeter Wemm while ((nlp = strchr(v, '\n')) != NULL) 1834c2aa98e2SPeter Wemm { 1835c2aa98e2SPeter Wemm int l; 1836c2aa98e2SPeter Wemm 1837c2aa98e2SPeter Wemm l = nlp - v; 18387660b554SGregory Neil Shapiro 18397660b554SGregory Neil Shapiro /* 18407660b554SGregory Neil Shapiro ** XXX This is broken for SPACELEFT()==0 18417660b554SGregory Neil Shapiro ** However, SPACELEFT() is always > 0 unless MAXLINE==1. 18427660b554SGregory Neil Shapiro */ 18437660b554SGregory Neil Shapiro 18443299c2f1SGregory Neil Shapiro if (SPACELEFT(obuf, obp) - 1 < (size_t) l) 1845c2aa98e2SPeter Wemm l = SPACELEFT(obuf, obp) - 1; 1846c2aa98e2SPeter Wemm 184712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); 1848567a2fc9SGregory Neil Shapiro if (!putxline(obuf, strlen(obuf), mci, putflags)) 1849567a2fc9SGregory Neil Shapiro goto writeerr; 1850c2aa98e2SPeter Wemm v += l + 1; 1851c2aa98e2SPeter Wemm obp = obuf; 1852c2aa98e2SPeter Wemm if (*v != ' ' && *v != '\t') 1853c2aa98e2SPeter Wemm *obp++ = ' '; 1854c2aa98e2SPeter Wemm } 18557660b554SGregory Neil Shapiro 18567660b554SGregory Neil Shapiro /* XXX This is broken for SPACELEFT()==0 */ 185712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", 185812ed1c7cSGregory Neil Shapiro (int) (SPACELEFT(obuf, obp) - 1), v); 1859567a2fc9SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags); 1860567a2fc9SGregory Neil Shapiro 1861567a2fc9SGregory Neil Shapiro writeerr: 1862567a2fc9SGregory Neil Shapiro return false; 1863c2aa98e2SPeter Wemm } 186412ed1c7cSGregory Neil Shapiro /* 1865c2aa98e2SPeter Wemm ** COMMAIZE -- output a header field, making a comma-translated list. 1866c2aa98e2SPeter Wemm ** 1867c2aa98e2SPeter Wemm ** Parameters: 1868c2aa98e2SPeter Wemm ** h -- the header field to output. 1869c2aa98e2SPeter Wemm ** p -- the value to put in it. 187012ed1c7cSGregory Neil Shapiro ** oldstyle -- true if this is an old style header. 1871c2aa98e2SPeter Wemm ** mci -- the connection information. 1872c2aa98e2SPeter Wemm ** e -- the envelope containing the message. 1873c2aa98e2SPeter Wemm ** 1874c2aa98e2SPeter Wemm ** Returns: 1875355d91e3SGregory Neil Shapiro ** true iff header field was written successfully 1876c2aa98e2SPeter Wemm ** 1877c2aa98e2SPeter Wemm ** Side Effects: 1878c2aa98e2SPeter Wemm ** outputs "p" to file "fp". 1879c2aa98e2SPeter Wemm */ 1880c2aa98e2SPeter Wemm 1881567a2fc9SGregory Neil Shapiro bool 1882c2aa98e2SPeter Wemm commaize(h, p, oldstyle, mci, e) 1883c2aa98e2SPeter Wemm register HDR *h; 1884c2aa98e2SPeter Wemm register char *p; 1885c2aa98e2SPeter Wemm bool oldstyle; 1886c2aa98e2SPeter Wemm register MCI *mci; 1887c2aa98e2SPeter Wemm register ENVELOPE *e; 1888c2aa98e2SPeter Wemm { 1889c2aa98e2SPeter Wemm register char *obp; 1890c2aa98e2SPeter Wemm int opos; 1891c2aa98e2SPeter Wemm int omax; 189212ed1c7cSGregory Neil Shapiro bool firstone = true; 1893c2aa98e2SPeter Wemm int putflags = PXLF_HEADER; 18947660b554SGregory Neil Shapiro char **res; 1895c2aa98e2SPeter Wemm char obuf[MAXLINE + 3]; 1896c2aa98e2SPeter Wemm 1897c2aa98e2SPeter Wemm /* 1898c2aa98e2SPeter Wemm ** Output the address list translated by the 1899c2aa98e2SPeter Wemm ** mailer and with commas. 1900c2aa98e2SPeter Wemm */ 1901c2aa98e2SPeter Wemm 1902c2aa98e2SPeter Wemm if (tTd(14, 2)) 190312ed1c7cSGregory Neil Shapiro sm_dprintf("commaize(%s: %s)\n", h->h_field, p); 1904c2aa98e2SPeter Wemm 1905c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1906c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 1907c2aa98e2SPeter Wemm 1908c2aa98e2SPeter Wemm obp = obuf; 190912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", 191012ed1c7cSGregory Neil Shapiro h->h_field); 19117660b554SGregory Neil Shapiro 19127660b554SGregory Neil Shapiro /* opos = strlen(obp); */ 1913c2aa98e2SPeter Wemm opos = strlen(h->h_field) + 2; 1914c2aa98e2SPeter Wemm if (opos > 202) 1915c2aa98e2SPeter Wemm opos = 202; 1916c2aa98e2SPeter Wemm obp += opos; 1917c2aa98e2SPeter Wemm omax = mci->mci_mailer->m_linelimit - 2; 1918c2aa98e2SPeter Wemm if (omax < 0 || omax > 78) 1919c2aa98e2SPeter Wemm omax = 78; 1920c2aa98e2SPeter Wemm 1921c2aa98e2SPeter Wemm /* 1922c2aa98e2SPeter Wemm ** Run through the list of values. 1923c2aa98e2SPeter Wemm */ 1924c2aa98e2SPeter Wemm 1925c2aa98e2SPeter Wemm while (*p != '\0') 1926c2aa98e2SPeter Wemm { 1927c2aa98e2SPeter Wemm register char *name; 1928c2aa98e2SPeter Wemm register int c; 1929c2aa98e2SPeter Wemm char savechar; 1930c2aa98e2SPeter Wemm int flags; 19313299c2f1SGregory Neil Shapiro auto int status; 1932c2aa98e2SPeter Wemm 1933c2aa98e2SPeter Wemm /* 1934c2aa98e2SPeter Wemm ** Find the end of the name. New style names 1935c2aa98e2SPeter Wemm ** end with a comma, old style names end with 1936c2aa98e2SPeter Wemm ** a space character. However, spaces do not 1937c2aa98e2SPeter Wemm ** necessarily delimit an old-style name -- at 1938c2aa98e2SPeter Wemm ** signs mean keep going. 1939c2aa98e2SPeter Wemm */ 1940c2aa98e2SPeter Wemm 1941c2aa98e2SPeter Wemm /* find end of name */ 1942c2aa98e2SPeter Wemm while ((isascii(*p) && isspace(*p)) || *p == ',') 1943c2aa98e2SPeter Wemm p++; 1944c2aa98e2SPeter Wemm name = p; 19457660b554SGregory Neil Shapiro res = NULL; 1946c2aa98e2SPeter Wemm for (;;) 1947c2aa98e2SPeter Wemm { 1948c2aa98e2SPeter Wemm auto char *oldp; 1949c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 1950c2aa98e2SPeter Wemm 19517660b554SGregory Neil Shapiro res = prescan(p, oldstyle ? ' ' : ',', pvpbuf, 1952bfb62e91SGregory Neil Shapiro sizeof pvpbuf, &oldp, NULL, false); 1953c2aa98e2SPeter Wemm p = oldp; 19547660b554SGregory Neil Shapiro #if _FFR_IGNORE_BOGUS_ADDR 19557660b554SGregory Neil Shapiro /* ignore addresses that can't be parsed */ 19567660b554SGregory Neil Shapiro if (res == NULL) 19577660b554SGregory Neil Shapiro { 19587660b554SGregory Neil Shapiro name = p; 19597660b554SGregory Neil Shapiro continue; 19607660b554SGregory Neil Shapiro } 19617660b554SGregory Neil Shapiro #endif /* _FFR_IGNORE_BOGUS_ADDR */ 1962c2aa98e2SPeter Wemm 1963c2aa98e2SPeter Wemm /* look to see if we have an at sign */ 1964c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 1965c2aa98e2SPeter Wemm p++; 1966c2aa98e2SPeter Wemm 1967c2aa98e2SPeter Wemm if (*p != '@') 1968c2aa98e2SPeter Wemm { 1969c2aa98e2SPeter Wemm p = oldp; 1970c2aa98e2SPeter Wemm break; 1971c2aa98e2SPeter Wemm } 197212ed1c7cSGregory Neil Shapiro ++p; 1973c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 1974c2aa98e2SPeter Wemm p++; 1975c2aa98e2SPeter Wemm } 1976c2aa98e2SPeter Wemm /* at the end of one complete name */ 1977c2aa98e2SPeter Wemm 1978c2aa98e2SPeter Wemm /* strip off trailing white space */ 1979c2aa98e2SPeter Wemm while (p >= name && 1980c2aa98e2SPeter Wemm ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 1981c2aa98e2SPeter Wemm p--; 1982c2aa98e2SPeter Wemm if (++p == name) 1983c2aa98e2SPeter Wemm continue; 19847660b554SGregory Neil Shapiro 19857660b554SGregory Neil Shapiro /* 19867660b554SGregory Neil Shapiro ** if prescan() failed go a bit backwards; this is a hack, 19877660b554SGregory Neil Shapiro ** there should be some better error recovery. 19887660b554SGregory Neil Shapiro */ 19897660b554SGregory Neil Shapiro 19907660b554SGregory Neil Shapiro if (res == NULL && p > name && 19917660b554SGregory Neil Shapiro !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 19927660b554SGregory Neil Shapiro --p; 1993c2aa98e2SPeter Wemm savechar = *p; 1994c2aa98e2SPeter Wemm *p = '\0'; 1995c2aa98e2SPeter Wemm 1996c2aa98e2SPeter Wemm /* translate the name to be relative */ 1997c2aa98e2SPeter Wemm flags = RF_HEADERADDR|RF_ADDDOMAIN; 1998c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 1999c2aa98e2SPeter Wemm flags |= RF_SENDERADDR; 2000c2aa98e2SPeter Wemm #if USERDB 2001c2aa98e2SPeter Wemm else if (e->e_from.q_mailer != NULL && 2002c2aa98e2SPeter Wemm bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 2003c2aa98e2SPeter Wemm { 2004c2aa98e2SPeter Wemm char *q; 2005c2aa98e2SPeter Wemm 200612ed1c7cSGregory Neil Shapiro q = udbsender(name, e->e_rpool); 2007c2aa98e2SPeter Wemm if (q != NULL) 2008c2aa98e2SPeter Wemm name = q; 2009c2aa98e2SPeter Wemm } 20103299c2f1SGregory Neil Shapiro #endif /* USERDB */ 20113299c2f1SGregory Neil Shapiro status = EX_OK; 20123299c2f1SGregory Neil Shapiro name = remotename(name, mci->mci_mailer, flags, &status, e); 2013c2aa98e2SPeter Wemm if (*name == '\0') 2014c2aa98e2SPeter Wemm { 2015c2aa98e2SPeter Wemm *p = savechar; 2016c2aa98e2SPeter Wemm continue; 2017c2aa98e2SPeter Wemm } 201812ed1c7cSGregory Neil Shapiro name = denlstring(name, false, true); 2019c2aa98e2SPeter Wemm 2020c2aa98e2SPeter Wemm /* output the name with nice formatting */ 2021c2aa98e2SPeter Wemm opos += strlen(name); 2022c2aa98e2SPeter Wemm if (!firstone) 2023c2aa98e2SPeter Wemm opos += 2; 2024c2aa98e2SPeter Wemm if (opos > omax && !firstone) 2025c2aa98e2SPeter Wemm { 202612ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp)); 2027567a2fc9SGregory Neil Shapiro if (!putxline(obuf, strlen(obuf), mci, putflags)) 2028567a2fc9SGregory Neil Shapiro goto writeerr; 2029c2aa98e2SPeter Wemm obp = obuf; 20307660b554SGregory Neil Shapiro (void) sm_strlcpy(obp, " ", sizeof obuf); 2031c2aa98e2SPeter Wemm opos = strlen(obp); 2032c2aa98e2SPeter Wemm obp += opos; 2033c2aa98e2SPeter Wemm opos += strlen(name); 2034c2aa98e2SPeter Wemm } 2035c2aa98e2SPeter Wemm else if (!firstone) 2036c2aa98e2SPeter Wemm { 203712ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp)); 2038c2aa98e2SPeter Wemm obp += 2; 2039c2aa98e2SPeter Wemm } 2040c2aa98e2SPeter Wemm 2041c2aa98e2SPeter Wemm while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 2042c2aa98e2SPeter Wemm *obp++ = c; 204312ed1c7cSGregory Neil Shapiro firstone = false; 2044c2aa98e2SPeter Wemm *p = savechar; 2045c2aa98e2SPeter Wemm } 20467660b554SGregory Neil Shapiro if (obp < &obuf[sizeof obuf]) 2047c2aa98e2SPeter Wemm *obp = '\0'; 20487660b554SGregory Neil Shapiro else 20497660b554SGregory Neil Shapiro obuf[sizeof obuf - 1] = '\0'; 2050567a2fc9SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags); 2051567a2fc9SGregory Neil Shapiro 2052567a2fc9SGregory Neil Shapiro writeerr: 2053567a2fc9SGregory Neil Shapiro return false; 2054c2aa98e2SPeter Wemm } 2055567a2fc9SGregory Neil Shapiro 205612ed1c7cSGregory Neil Shapiro /* 2057c2aa98e2SPeter Wemm ** COPYHEADER -- copy header list 2058c2aa98e2SPeter Wemm ** 2059c2aa98e2SPeter Wemm ** This routine is the equivalent of newstr for header lists 2060c2aa98e2SPeter Wemm ** 2061c2aa98e2SPeter Wemm ** Parameters: 2062c2aa98e2SPeter Wemm ** header -- list of header structures to copy. 206312ed1c7cSGregory Neil Shapiro ** rpool -- resource pool, or NULL 2064c2aa98e2SPeter Wemm ** 2065c2aa98e2SPeter Wemm ** Returns: 2066c2aa98e2SPeter Wemm ** a copy of 'header'. 2067c2aa98e2SPeter Wemm ** 2068c2aa98e2SPeter Wemm ** Side Effects: 2069c2aa98e2SPeter Wemm ** none. 2070c2aa98e2SPeter Wemm */ 2071c2aa98e2SPeter Wemm 2072c2aa98e2SPeter Wemm HDR * 207312ed1c7cSGregory Neil Shapiro copyheader(header, rpool) 2074c2aa98e2SPeter Wemm register HDR *header; 207512ed1c7cSGregory Neil Shapiro SM_RPOOL_T *rpool; 2076c2aa98e2SPeter Wemm { 2077c2aa98e2SPeter Wemm register HDR *newhdr; 2078c2aa98e2SPeter Wemm HDR *ret; 2079c2aa98e2SPeter Wemm register HDR **tail = &ret; 2080c2aa98e2SPeter Wemm 2081c2aa98e2SPeter Wemm while (header != NULL) 2082c2aa98e2SPeter Wemm { 208312ed1c7cSGregory Neil Shapiro newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr); 2084c2aa98e2SPeter Wemm STRUCTCOPY(*header, *newhdr); 2085c2aa98e2SPeter Wemm *tail = newhdr; 2086c2aa98e2SPeter Wemm tail = &newhdr->h_link; 2087c2aa98e2SPeter Wemm header = header->h_link; 2088c2aa98e2SPeter Wemm } 2089c2aa98e2SPeter Wemm *tail = NULL; 2090c2aa98e2SPeter Wemm 2091c2aa98e2SPeter Wemm return ret; 2092c2aa98e2SPeter Wemm } 209312ed1c7cSGregory Neil Shapiro /* 209476b7bf71SPeter Wemm ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header 209576b7bf71SPeter Wemm ** 209676b7bf71SPeter Wemm ** Run through all of the parameters of a MIME header and 209776b7bf71SPeter Wemm ** possibly truncate and rebalance the parameter according 209876b7bf71SPeter Wemm ** to MaxMimeFieldLength. 209976b7bf71SPeter Wemm ** 210076b7bf71SPeter Wemm ** Parameters: 2101f9218d3dSGregory Neil Shapiro ** h -- the header to truncate/rebalance 2102f9218d3dSGregory Neil Shapiro ** e -- the current envelope 210376b7bf71SPeter Wemm ** 210476b7bf71SPeter Wemm ** Returns: 2105c46d91b7SGregory Neil Shapiro ** length of last offending field, 0 if all ok. 210676b7bf71SPeter Wemm ** 210776b7bf71SPeter Wemm ** Side Effects: 210876b7bf71SPeter Wemm ** string modified in place 210976b7bf71SPeter Wemm */ 211076b7bf71SPeter Wemm 2111c46d91b7SGregory Neil Shapiro static size_t 2112f9218d3dSGregory Neil Shapiro fix_mime_header(h, e) 2113f9218d3dSGregory Neil Shapiro HDR *h; 2114f9218d3dSGregory Neil Shapiro ENVELOPE *e; 211576b7bf71SPeter Wemm { 2116f9218d3dSGregory Neil Shapiro char *begin = h->h_value; 211776b7bf71SPeter Wemm char *end; 2118c46d91b7SGregory Neil Shapiro size_t len = 0; 2119c46d91b7SGregory Neil Shapiro size_t retlen = 0; 212076b7bf71SPeter Wemm 2121f9218d3dSGregory Neil Shapiro if (begin == NULL || *begin == '\0') 2122c46d91b7SGregory Neil Shapiro return 0; 212376b7bf71SPeter Wemm 212476b7bf71SPeter Wemm /* Split on each ';' */ 21257660b554SGregory Neil Shapiro /* find_character() never returns NULL */ 212676b7bf71SPeter Wemm while ((end = find_character(begin, ';')) != NULL) 212776b7bf71SPeter Wemm { 212876b7bf71SPeter Wemm char save = *end; 212976b7bf71SPeter Wemm char *bp; 213076b7bf71SPeter Wemm 213176b7bf71SPeter Wemm *end = '\0'; 213276b7bf71SPeter Wemm 2133c46d91b7SGregory Neil Shapiro len = strlen(begin); 2134c46d91b7SGregory Neil Shapiro 213576b7bf71SPeter Wemm /* Shorten individual parameter */ 213676b7bf71SPeter Wemm if (shorten_rfc822_string(begin, MaxMimeFieldLength)) 2137f9218d3dSGregory Neil Shapiro { 2138f9218d3dSGregory Neil Shapiro if (len < MaxMimeFieldLength) 2139f9218d3dSGregory Neil Shapiro { 2140f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus field */ 2141f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id, 2142f9218d3dSGregory Neil Shapiro "Fixed MIME %s header field (possible attack)", 2143f9218d3dSGregory Neil Shapiro h->h_field); 2144f9218d3dSGregory Neil Shapiro if (tTd(34, 11)) 2145f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header field (possible attack)\n", 2146f9218d3dSGregory Neil Shapiro h->h_field); 2147f9218d3dSGregory Neil Shapiro } 2148f9218d3dSGregory Neil Shapiro else 2149f9218d3dSGregory Neil Shapiro { 2150f9218d3dSGregory Neil Shapiro /* we actually shortened the header */ 2151c46d91b7SGregory Neil Shapiro retlen = len; 2152f9218d3dSGregory Neil Shapiro } 2153f9218d3dSGregory Neil Shapiro } 215476b7bf71SPeter Wemm 215576b7bf71SPeter Wemm /* Collapse the possibly shortened string with rest */ 215676b7bf71SPeter Wemm bp = begin + strlen(begin); 215776b7bf71SPeter Wemm if (bp != end) 215876b7bf71SPeter Wemm { 215976b7bf71SPeter Wemm char *ep = end; 216076b7bf71SPeter Wemm 216176b7bf71SPeter Wemm *end = save; 216276b7bf71SPeter Wemm end = bp; 216376b7bf71SPeter Wemm 216476b7bf71SPeter Wemm /* copy character by character due to overlap */ 216576b7bf71SPeter Wemm while (*ep != '\0') 216676b7bf71SPeter Wemm *bp++ = *ep++; 216776b7bf71SPeter Wemm *bp = '\0'; 216876b7bf71SPeter Wemm } 216976b7bf71SPeter Wemm else 217076b7bf71SPeter Wemm *end = save; 217176b7bf71SPeter Wemm if (*end == '\0') 217276b7bf71SPeter Wemm break; 217376b7bf71SPeter Wemm 217476b7bf71SPeter Wemm /* Move past ';' */ 217576b7bf71SPeter Wemm begin = end + 1; 217676b7bf71SPeter Wemm } 2177c46d91b7SGregory Neil Shapiro return retlen; 217876b7bf71SPeter Wemm } 2179