ETRN_CMD, /* This by analogy with TURN from the RFC */
STARTTLS_CMD, /* Required by the STARTTLS RFC */
TLS_AUTH_CMD, /* auto-command at start of SSL */
+#ifdef EXPERIMENTAL_XCLIENT
+ XCLIENT_CMD, /* per xlexkiro implementation */
+#endif
/* This is a dummy to identify the non-sync commands when pipelining */
tls_auth is a pseudo-command, never expected in input. It is activated
on TLS startup and looks for a tls authenticator. */
-enum { CL_RSET, CL_HELO, CL_EHLO, CL_AUTH,
+enum {
+ CL_RSET = 0,
+ CL_HELO,
+ CL_EHLO,
+ CL_AUTH,
#ifndef DISABLE_TLS
- CL_STLS, CL_TLAU,
+ CL_STLS,
+ CL_TLAU,
+#endif
+#ifdef EXPERIMENTAL_XCLIENT
+ CL_XCLI,
#endif
};
static smtp_cmd_list cmd_list[] = {
- /* name len cmd has_arg is_mail_cmd */
+ /* name len cmd has_arg is_mail_cmd */
[CL_RSET] = { "rset", sizeof("rset")-1, RSET_CMD, FALSE, FALSE }, /* First */
[CL_HELO] = { "helo", sizeof("helo")-1, HELO_CMD, TRUE, FALSE },
[CL_STLS] = { "starttls", sizeof("starttls")-1, STARTTLS_CMD, FALSE, FALSE },
[CL_TLAU] = { "tls_auth", 0, TLS_AUTH_CMD, FALSE, FALSE },
#endif
-
-/* If you change anything above here, also fix the definitions below. */
+#ifdef EXPERIMENTAL_XCLIENT
+ [CL_XCLI] = { "xclient", sizeof("xclient")-1, XCLIENT_CMD, TRUE, FALSE },
+#endif
{ "mail from:", sizeof("mail from:")-1, MAIL_CMD, TRUE, TRUE },
{ "rcpt to:", sizeof("rcpt to:")-1, RCPT_CMD, TRUE, TRUE },
[SCH_RSET] = US"RSET",
[SCH_STARTTLS] = US"STARTTLS",
[SCH_VRFY] = US"VRFY",
+#ifdef EXPERIMENTAL_XCLIENT
+ [SCH_XCLIENT] = US"XCLIENT",
+#endif
};
static uschar *protocols_local[] = {
+
/*************************************************
* Forced closedown of call *
*************************************************/
bsmtp_transaction_linecount = receive_linecount;
break;
-
/* The MAIL FROM command requires an address as an operand. All we
do here is to parse it for syntactic correctness. The form "<>" is
a special case which converts into an empty string. The start/end
/* Now output the banner */
/*XXX the ehlo-resp code does its own tls/nontls bit. Maybe subroutine that? */
-smtp_printf("%s",
+smtp_printf("%Y",
#ifndef DISABLE_PIPE_CONNECT
fl.pipe_connect_acceptable && pipeline_connect_sends(),
#else
FALSE,
#endif
- string_from_gstring(ss));
+ ss);
/* Attempt to see if we sent the banner before the last ACK of the 3-way
handshake arrived. If so we must have managed a TFO. */
{
yield = 1;
log_write(0, LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many "
- "syntax or protocol errors (last command was \"%s\", %s)",
+ "syntax or protocol errors (last command was \"%s\", %Y)",
host_and_ident(FALSE), string_printing(smtp_cmd_buffer),
- string_from_gstring(s_connhad_log(NULL))
+ s_connhad_log(NULL)
);
}
va_start(ap, defaultrespond);
g = string_vformat(NULL, SVFMT_EXTEND|SVFMT_REBUFFER, CS defaultrespond, ap);
va_end(ap);
- smtp_printf("%s %s\r\n", FALSE, code, string_from_gstring(g));
+ smtp_printf("%s %Y\r\n", FALSE, code, g);
}
mac_smtp_fflush();
}
if (++synprot_error_count > smtp_max_synprot_errors)
{
log_write(0, LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many "
- "syntax or protocol errors (last command was \"%s\", %s)",
+ "syntax or protocol errors (last command was \"%s\", %Y)",
host_and_ident(FALSE), string_printing(smtp_cmd_buffer),
- string_from_gstring(s_connhad_log(NULL))
+ s_connhad_log(NULL)
);
done = 1;
}
fl.tls_advertised = TRUE;
}
#endif
-
+#ifdef EXPERIMENTAL_XCLIENT
+ if (proxy_session || verify_check_host(&hosts_xclient) != FAIL)
+ {
+ g = string_catn(g, smtp_code, 3);
+ g = xclient_smtp_advertise_str(g);
+ }
+#endif
#ifndef DISABLE_PRDR
/* Per Recipient Data Response, draft by Eric A. Hall extending RFC */
if (prdr_enable)
toomany = FALSE;
break; /* HELO/EHLO */
+#ifdef EXPERIMENTAL_XCLIENT
+ case XCLIENT_CMD:
+ {
+ BOOL fatal = fl.helo_seen;
+ uschar * errmsg;
+ int resp;
+
+ HAD(SCH_XCLIENT);
+ smtp_mailcmd_count++;
+
+ if ((errmsg = xclient_smtp_command(smtp_cmd_data, &resp, &fatal)))
+ if (fatal)
+ done = synprot_error(L_smtp_syntax_error, resp, NULL, errmsg);
+ else
+ {
+ smtp_printf("%d %s\r\n", FALSE, resp, errmsg);
+ log_write(0, LOG_MAIN|LOG_REJECT, "rejected XCLIENT from %s: %s",
+ host_and_ident(FALSE), errmsg);
+ }
+ else
+ {
+ fl.helo_seen = FALSE; /* Require another EHLO */
+ smtp_code = string_sprintf("%d", resp);
+
+ /*XXX unclear in spec. if this needs to be an ESMTP banner,
+ nor whether we get the original client's HELO after (or a proxy fake).
+ We require that we do; the following HELO/EHLO handling will set
+ sender_helo_name as normal. */
+
+ smtp_printf("%s XCLIENT success\r\n", FALSE, smtp_code);
+ }
+ break; /* XCLIENT */
+ }
+#endif
+
/* The MAIL command requires an address as an operand. All we do
here is to parse it for syntactic correctness. The form "<>" is
if (acl_smtp_etrn) smtp_printf(" ETRN", TRUE);
if (acl_smtp_expn) smtp_printf(" EXPN", TRUE);
if (acl_smtp_vrfy) smtp_printf(" VRFY", TRUE);
+#ifdef EXPERIMENTAL_XCLIENT
+ if (proxy_session || verify_check_host(&hosts_xclient) != FAIL)
+ smtp_printf(" XCLIENT", TRUE);
+#endif
smtp_printf("\r\n", FALSE);
break;
BOOL rc;
etrn_command = smtp_etrn_command;
deliver_domain = smtp_cmd_data;
- rc = transport_set_up_command(&argv, smtp_etrn_command, TRUE, 0, NULL,
- FALSE, US"ETRN processing", &error);
+ rc = transport_set_up_command(&argv, smtp_etrn_command, TSUC_EXPAND_ARGS, 0, NULL,
+ US"ETRN processing", &error);
deliver_domain = NULL;
if (!rc)
{
case BADSYN_CMD:
SYNC_FAILURE:
- if (smtp_inend >= smtp_inbuffer + IN_BUFFER_SIZE)
- smtp_inend = smtp_inbuffer + IN_BUFFER_SIZE - 1;
- c = smtp_inend - smtp_inptr;
- if (c > 150) c = 150; /* limit logged amount */
- smtp_inptr[c] = 0;
- incomplete_transaction_log(US"sync failure");
- log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol synchronization error "
- "(next input sent too soon: pipelining was%s advertised): "
- "rejected \"%s\" %s next input=\"%s\"",
- f.smtp_in_pipelining_advertised ? "" : " not",
- smtp_cmd_buffer, host_and_ident(TRUE),
- string_printing(smtp_inptr));
- smtp_notquit_exit(US"synchronization-error", US"554",
- US"SMTP synchronization error");
- done = 1; /* Pretend eof - drops connection */
- break;
+ {
+ unsigned nchars = 150;
+ uschar * buf = receive_getbuf(&nchars); /* destructive read */
+ buf[nchars] = '\0';
+ incomplete_transaction_log(US"sync failure");
+ log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol synchronization error "
+ "(next input sent too soon: pipelining was%s advertised): "
+ "rejected \"%s\" %s next input=\"%s\" (%u bytes)",
+ f.smtp_in_pipelining_advertised ? "" : " not",
+ smtp_cmd_buffer, host_and_ident(TRUE),
+ string_printing(buf), nchars);
+ smtp_notquit_exit(US"synchronization-error", US"554",
+ US"SMTP synchronization error");
+ done = 1; /* Pretend eof - drops connection */
+ break;
+ }
case TOO_MANY_NONMAIL_CMD:
s = smtp_cmd_buffer;
- while (*s != 0 && !isspace(*s)) s++;
+ while (*s && !isspace(*s)) s++;
incomplete_transaction_log(US"too many non-mail commands");
log_write(0, LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many "
"nonmail commands (last was \"%.*s\")", host_and_ident(FALSE),