📄 headers.c
字号:
}
}
if (quoteit)
{
if (bp == &buf[1])
bp--;
else
*bp++ = '"';
while ((c = *p++) != '<')
{
if (bp < buflim)
*bp++ = c;
}
*bp++ = c;
}
copylev = 0;
putgmac = quoteit = FALSE;
continue;
}
if (c == '>')
{
if (anglelev > 0)
{
anglelev--;
if (!skipping)
{
realanglelev--;
buflim++;
}
}
else if (!skipping)
{
/* syntax error: unmatched > */
if (copylev > 0)
bp--;
quoteit = TRUE;
continue;
}
if (copylev++ <= 0)
*bp++ = c;
continue;
}
/* must be a real address character */
putg:
if (copylev <= 0 && !putgmac)
{
if (bp > bufhead && bp[-1] == ')')
*bp++ = ' ';
*bp++ = MACROEXPAND;
*bp++ = 'g';
putgmac = TRUE;
}
}
/* repair any syntactic damage */
if (realqmode)
*bp++ = '"';
while (realcmtlev-- > 0)
*bp++ = ')';
while (realanglelev-- > 0)
*bp++ = '>';
*bp++ = '\0';
if (tTd(33, 1))
{
dprintf("crackaddr=>`");
xputs(buf);
dprintf("'\n");
}
return buf;
}
/*
** PUTHEADER -- put the header part of a message from the in-core copy
**
** Parameters:
** mci -- the connection information.
** hdr -- the header to put.
** e -- envelope to use.
** flags -- MIME conversion flags.
**
** Returns:
** none.
**
** Side Effects:
** none.
*/
/*
* Macro for fast max (not available in e.g. DG/UX, 386/ix).
*/
#ifndef MAX
# define MAX(a,b) (((a)>(b))?(a):(b))
#endif /* ! MAX */
void
putheader(mci, hdr, e, flags)
register MCI *mci;
HDR *hdr;
register ENVELOPE *e;
int flags;
{
register HDR *h;
char buf[MAX(MAXLINE,BUFSIZ)];
char obuf[MAXLINE];
if (tTd(34, 1))
dprintf("--- putheader, mailer = %s ---\n",
mci->mci_mailer->m_name);
/*
** If we're in MIME mode, we're not really in the header of the
** message, just the header of one of the parts of the body of
** the message. Therefore MCIF_INHEADER should not be turned on.
*/
if (!bitset(MCIF_INMIME, mci->mci_flags))
mci->mci_flags |= MCIF_INHEADER;
for (h = hdr; h != NULL; h = h->h_link)
{
register char *p = h->h_value;
if (tTd(34, 11))
{
dprintf(" %s: ", h->h_field);
xputs(p);
}
/* Skip empty headers */
if (h->h_value == NULL)
continue;
/* heuristic shortening of MIME fields to avoid MUA overflows */
if (MaxMimeFieldLength > 0 &&
wordinclass(h->h_field,
macid("{checkMIMEFieldHeaders}", NULL)))
{
if (fix_mime_header(h->h_value))
{
sm_syslog(LOG_ALERT, e->e_id,
"Truncated MIME %s header due to field size (possible attack)",
h->h_field);
if (tTd(34, 11))
dprintf(" truncated MIME %s header due to field size (possible attack)\n",
h->h_field);
}
}
if (MaxMimeHeaderLength > 0 &&
wordinclass(h->h_field,
macid("{checkMIMETextHeaders}", NULL)))
{
if (strlen(h->h_value) > (size_t)MaxMimeHeaderLength)
{
h->h_value[MaxMimeHeaderLength - 1] = '\0';
sm_syslog(LOG_ALERT, e->e_id,
"Truncated long MIME %s header (possible attack)",
h->h_field);
if (tTd(34, 11))
dprintf(" truncated long MIME %s header (possible attack)\n",
h->h_field);
}
}
if (MaxMimeHeaderLength > 0 &&
wordinclass(h->h_field,
macid("{checkMIMEHeaders}", NULL)))
{
if (shorten_rfc822_string(h->h_value, MaxMimeHeaderLength))
{
sm_syslog(LOG_ALERT, e->e_id,
"Truncated long MIME %s header (possible attack)",
h->h_field);
if (tTd(34, 11))
dprintf(" truncated long MIME %s header (possible attack)\n",
h->h_field);
}
}
/*
** Suppress Content-Transfer-Encoding: if we are MIMEing
** and we are potentially converting from 8 bit to 7 bit
** MIME. If converting, add a new CTE header in
** mime8to7().
*/
if (bitset(H_CTE, h->h_flags) &&
bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
mci->mci_flags) &&
!bitset(M87F_NO8TO7, flags))
{
if (tTd(34, 11))
dprintf(" (skipped (content-transfer-encoding))\n");
continue;
}
if (bitset(MCIF_INMIME, mci->mci_flags))
{
if (tTd(34, 11))
dprintf("\n");
put_vanilla_header(h, p, mci);
continue;
}
if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
!bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
(h->h_macro == '\0' ||
macvalue(h->h_macro & 0377, e) == NULL))
{
if (tTd(34, 11))
dprintf(" (skipped)\n");
continue;
}
/* handle Resent-... headers specially */
if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
{
if (tTd(34, 11))
dprintf(" (skipped (resent))\n");
continue;
}
/* suppress return receipts if requested */
if (bitset(H_RECEIPTTO, h->h_flags) &&
(RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
{
if (tTd(34, 11))
dprintf(" (skipped (receipt))\n");
continue;
}
/* macro expand value if generated internally */
if (bitset(H_DEFAULT, h->h_flags) ||
bitset(H_BINDLATE, h->h_flags))
{
expand(p, buf, sizeof buf, e);
p = buf;
if (*p == '\0')
{
if (tTd(34, 11))
dprintf(" (skipped -- null value)\n");
continue;
}
}
if (bitset(H_BCC, h->h_flags))
{
/* Bcc: field -- either truncate or delete */
if (bitset(EF_DELETE_BCC, e->e_flags))
{
if (tTd(34, 11))
dprintf(" (skipped -- bcc)\n");
}
else
{
/* no other recipient headers: truncate value */
(void) snprintf(obuf, sizeof obuf, "%s:",
h->h_field);
putline(obuf, mci);
}
continue;
}
if (tTd(34, 11))
dprintf("\n");
if (bitset(H_FROM|H_RCPT, h->h_flags))
{
/* address field */
bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
if (bitset(H_FROM, h->h_flags))
oldstyle = FALSE;
commaize(h, p, oldstyle, mci, e);
}
else
{
put_vanilla_header(h, p, mci);
}
}
/*
** If we are converting this to a MIME message, add the
** MIME headers (but not in MIME mode!).
*/
#if MIME8TO7
if (bitset(MM_MIME8BIT, MimeMode) &&
bitset(EF_HAS8BIT, e->e_flags) &&
!bitset(EF_DONT_MIME, e->e_flags) &&
!bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
!bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
hvalue("MIME-Version", e->e_header) == NULL)
{
putline("MIME-Version: 1.0", mci);
if (hvalue("Content-Type", e->e_header) == NULL)
{
snprintf(obuf, sizeof obuf,
"Content-Type: text/plain; charset=%s",
defcharset(e));
putline(obuf, mci);
}
if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
putline("Content-Transfer-Encoding: 8bit", mci);
}
#endif /* MIME8TO7 */
}
/*
** PUT_VANILLA_HEADER -- output a fairly ordinary header
**
** Parameters:
** h -- the structure describing this header
** v -- the value of this header
** mci -- the connection info for output
**
** Returns:
** none.
*/
static void
put_vanilla_header(h, v, mci)
HDR *h;
char *v;
MCI *mci;
{
register char *nlp;
register char *obp;
int putflags;
char obuf[MAXLINE];
putflags = PXLF_HEADER;
if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
putflags |= PXLF_STRIP8BIT;
(void) snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
obp = obuf + strlen(obuf);
while ((nlp = strchr(v, '\n')) != NULL)
{
int l;
l = nlp - v;
if (SPACELEFT(obuf, obp) - 1 < (size_t)l)
l = SPACELEFT(obuf, obp) - 1;
snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
putxline(obuf, strlen(obuf), mci, putflags);
v += l + 1;
obp = obuf;
if (*v != ' ' && *v != '\t')
*obp++ = ' ';
}
snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
(int) sizeof obuf - (obp - obuf) - 1, v);
putxline(obuf, strlen(obuf), mci, putflags);
}
/*
** COMMAIZE -- output a header field, making a comma-translated list.
**
** Parameters:
** h -- the header field to output.
** p -- the value to put in it.
** oldstyle -- TRUE if this is an old style header.
** mci -- the connection information.
** e -- the envelope containing the message.
**
** Returns:
** none.
**
** Side Effects:
** outputs "p" to file "fp".
*/
void
commaize(h, p, oldstyle, mci, e)
register HDR *h;
register char *p;
bool oldstyle;
register MCI *mci;
register ENVELOPE *e;
{
register char *obp;
int opos;
int omax;
bool firstone = TRUE;
int putflags = PXLF_HEADER;
char obuf[MAXLINE + 3];
/*
** Output the address list translated by the
** mailer and with commas.
*/
if (tTd(14, 2))
dprintf("commaize(%s: %s)\n", h->h_field, p);
if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
putflags |= PXLF_STRIP8BIT;
obp = obuf;
(void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", h->h_field);
opos = strlen(h->h_field) + 2;
if (opos > 202)
opos = 202;
obp += opos;
omax = mci->mci_mailer->m_linelimit - 2;
if (omax < 0 || omax > 78)
omax = 78;
/*
** Run through the list of values.
*/
while (*p != '\0')
{
register char *name;
register int c;
char savechar;
int flags;
auto int status;
/*
** Find the end of the name. New style names
** end with a comma, old style names end with
** a space character. However, spaces do not
** necessarily delimit an old-style name -- at
** signs mean keep going.
*/
/* find end of name */
while ((isascii(*p) && isspace(*p)) || *p == ',')
p++;
name = p;
for (;;)
{
auto char *oldp;
char pvpbuf[PSBUFSIZE];
(void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
sizeof pvpbuf, &oldp, NULL);
p = oldp;
/* look to see if we have an at sign */
while (*p != '\0' && isascii(*p) && isspace(*p))
p++;
if (*p != '@')
{
p = oldp;
break;
}
p += *p == '@' ? 1 : 2;
while (*p != '\0' && isascii(*p) && isspace(*p))
p++;
}
/* at the end of one complete name */
/* strip off trailing white space */
while (p >= name &&
((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
p--;
if (++p == name)
continue;
savechar = *p;
*p = '\0';
/* translate the name to be relative */
flags = RF_HEADERADDR|RF_ADDDOMAIN;
if (bitset(H_FROM, h->h_flags))
flags |= RF_SENDERADDR;
#if USERDB
else if (e->e_from.q_mailer != NULL &&
bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
{
char *q;
q = udbsender(name);
if (q != NULL)
name = q;
}
#endif /* USERDB */
status = EX_OK;
name = remotename(name, mci->mci_mailer, flags, &status, e);
if (*name == '\0')
{
*p = savechar;
continue;
}
name = denlstring(name, FALSE, TRUE);
/*
** record data progress so DNS timeouts
** don't cause DATA timeouts
*/
DataProgress = TRUE;
/* output the name with nice formatting */
opos += strlen(name);
if (!firstone)
opos += 2;
if (opos > omax && !firstone)
{
snprintf(obp, SPACELEFT(obuf, obp), ",\n");
putxline(obuf, strlen(obuf), mci, putflags);
obp = obuf;
(void) strlcpy(obp, " ", sizeof obp);
opos = strlen(obp);
obp += opos;
opos += strlen(name);
}
else if (!firstone)
{
snprintf(obp, SPACELEFT(obuf, obp), ", ");
obp += 2;
}
while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
*obp++ = c;
firstone = FALSE;
*p = savechar;
}
*obp = '\0';
putxline(obuf, strlen(obuf), mci, putflags);
}
/*
** COPYHEADER -- copy header list
**
** This routine is the equivalent of newstr for header lists
**
** Parameters:
** header -- list of header structures to copy.
**
** Returns:
** a copy of 'header'.
**
** Side Effects:
** none.
*/
HDR *
copyheader(header)
register HDR *header;
{
register HDR *newhdr;
HDR *ret;
register HDR **tail = &ret;
while (header != NULL)
{
newhdr = (HDR *) xalloc(sizeof *newhdr);
STRUCTCOPY(*header, *newhdr);
*tail = newhdr;
tail = &newhdr->h_link;
header = header->h_link;
}
*tail = NULL;
return ret;
}
/*
** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
**
** Run through all of the parameters of a MIME header and
** possibly truncate and rebalance the parameter according
** to MaxMimeFieldLength.
**
** Parameters:
** string -- the full header
**
** Returns:
** TRUE if the header was modified, FALSE otherwise
**
** Side Effects:
** string modified in place
*/
static bool
fix_mime_header(string)
char *string;
{
bool modified = FALSE;
char *begin = string;
char *end;
if (string == NULL || *string == '\0')
return FALSE;
/* Split on each ';' */
while ((end = find_character(begin, ';')) != NULL)
{
char save = *end;
char *bp;
*end = '\0';
/* Shorten individual parameter */
if (shorten_rfc822_string(begin, MaxMimeFieldLength))
modified = TRUE;
/* Collapse the possibly shortened string with rest */
bp = begin + strlen(begin);
if (bp != end)
{
char *ep = end;
*end = save;
end = bp;
/* copy character by character due to overlap */
while (*ep != '\0')
*bp++ = *ep++;
*bp = '\0';
}
else
*end = save;
if (*end == '\0')
break;
/* Move past ';' */
begin = end + 1;
}
return modified;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -