#endif
BOOL dsn_advertised :1;
BOOL esmtp :1;
- BOOL helo_required :1;
+ BOOL helo_verify_required :1;
BOOL helo_verify :1;
BOOL helo_seen :1;
BOOL helo_accept_junk :1;
BOOL smtputf8_advertised :1;
#endif
} fl = {
- .helo_required = FALSE,
+ .helo_verify_required = FALSE,
.helo_verify = FALSE,
.smtp_exit_function_called = FALSE,
};
return *smtp_inptr++;
}
+BOOL
+smtp_hasc(void)
+{
+return smtp_inptr < smtp_inend;
+}
+
uschar *
smtp_getbuf(unsigned * len)
{
}
void
-smtp_get_cache(void)
+smtp_get_cache(unsigned lim)
{
#ifndef DISABLE_DKIM
int n = smtp_inend - smtp_inptr;
-if (chunking_state == CHUNKING_LAST && chunking_data_left < n)
- n = chunking_data_left;
+if (n > lim)
+ n = lim;
if (n > 0)
dkim_exim_verify_feed(smtp_inptr, n);
#endif
if (chunking_state == CHUNKING_LAST)
{
#ifndef DISABLE_DKIM
+ dkim_collect_input = dkim_save;
dkim_exim_verify_feed(NULL, 0); /* notify EOD */
+ dkim_collect_input = 0;
#endif
return EOD;
}
}
}
+BOOL
+bdat_hasc(void)
+{
+if (chunking_data_left > 0)
+ return lwr_receive_hasc();
+return TRUE;
+}
+
uschar *
bdat_getbuf(unsigned * len)
{
/* push the current receive_* function on the "stack", and
replace them by bdat_getc(), which in turn will use the lwr_receive_*
functions to do the dirty work. */
-if (lwr_receive_getc == NULL)
+if (!lwr_receive_getc)
{
lwr_receive_getc = receive_getc;
lwr_receive_getbuf = receive_getbuf;
+ lwr_receive_hasc = receive_hasc;
lwr_receive_ungetc = receive_ungetc;
}
else
receive_getc = bdat_getc;
receive_getbuf = bdat_getbuf;
+receive_hasc = bdat_hasc;
receive_ungetc = bdat_ungetc;
}
static inline void
bdat_pop_receive_functions(void)
{
-if (lwr_receive_getc == NULL)
+if (!lwr_receive_getc)
{
DEBUG(D_receive) debug_printf("chunking double-pop receive functions\n");
return;
}
receive_getc = lwr_receive_getc;
receive_getbuf = lwr_receive_getbuf;
+receive_hasc = lwr_receive_hasc;
receive_ungetc = lwr_receive_ungetc;
lwr_receive_getc = NULL;
lwr_receive_getbuf = NULL;
+lwr_receive_hasc = NULL;
lwr_receive_ungetc = NULL;
}
int
smtp_ungetc(int ch)
{
+if (smtp_inptr <= smtp_inbuffer)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "buffer underflow in smtp_ungetc");
+
*--smtp_inptr = ch;
return ch;
}
bdat_ungetc(int ch)
{
chunking_data_left++;
+bdat_push_receive_functions(); /* we're not done yet, calling push is safe, because it checks the state before pushing anything */
return lwr_receive_ungetc(ch);
}
extract_option(uschar **name, uschar **value)
{
uschar *n;
-uschar *v = smtp_cmd_data + Ustrlen(smtp_cmd_data) - 1;
-while (isspace(*v)) v--;
-v[1] = '\0';
+uschar *v;
+if (Ustrlen(smtp_cmd_data) <= 0) return FALSE;
+v = smtp_cmd_data + Ustrlen(smtp_cmd_data) - 1;
+while (v > smtp_cmd_data && isspace(*v)) v--;
+v[1] = 0;
+
while (v > smtp_cmd_data && *v != '=' && !isspace(*v))
{
/* Take care to not stop at a space embedded in a quoted local-part */
-
- if ((*v == '"') && (v > smtp_cmd_data + 1))
- do v--; while (*v != '"' && v > smtp_cmd_data+1);
+ if (*v == '"')
+ {
+ do v--; while (v > smtp_cmd_data && *v != '"');
+ if (v <= smtp_cmd_data) return FALSE;
+ }
v--;
}
+if (v <= smtp_cmd_data) return FALSE;
n = v;
if (*v == '=')
{
- while(isalpha(n[-1])) n--;
+ while (n > smtp_cmd_data && isalpha(n[-1])) n--;
/* RFC says SP, but TAB seen in wild and other major MTAs accept it */
- if (!isspace(n[-1])) return FALSE;
+ if (n <= smtp_cmd_data || !isspace(n[-1])) return FALSE;
n[-1] = 0;
}
else
{
n++;
- if (v == smtp_cmd_data) return FALSE;
}
*v++ = 0;
*name = n;
receive_getc = smtp_getc;
receive_getbuf = smtp_getbuf;
receive_get_cache = smtp_get_cache;
+receive_hasc = smtp_hasc;
receive_ungetc = smtp_ungetc;
receive_feof = smtp_feof;
receive_ferror = smtp_ferror;
receive_smtp_buffered = smtp_buffered;
lwr_receive_getc = NULL;
lwr_receive_getbuf = NULL;
+lwr_receive_hasc = NULL;
lwr_receive_ungetc = NULL;
smtp_inptr = smtp_inend = smtp_inbuffer;
smtp_had_eof = smtp_had_error = 0;
/* Determine whether HELO/EHLO is required for this host. The requirement
can be hard or soft. */
- fl.helo_required = verify_check_host(&helo_verify_hosts) == OK;
- if (!fl.helo_required)
+ fl.helo_verify_required = verify_check_host(&helo_verify_hosts) == OK;
+ if (!fl.helo_verify_required)
fl.helo_verify = verify_check_host(&helo_try_verify_hosts) == OK;
/* Determine whether this hosts is permitted to send syntactic junk
p = s + Ustrlen(s);
while (p > s && isspace(p[-1])) p--;
-*p = 0;
+s = string_copyn(s, p-s);
/* It seems that CC:Mail is braindead, and assumes that the greeting message
is all contained in a single IP packet. The original code wrote out the
if (fl.rcpt_in_progress)
{
- if (rcpt_smtp_response == NULL)
+ if (!rcpt_smtp_response)
rcpt_smtp_response = string_copy(msg);
else if (fl.rcpt_smtp_response_same &&
Ustrcmp(rcpt_smtp_response, msg) != 0)
for (;;)
{
uschar *nl = Ustrchr(msg, '\n');
- if (nl == NULL)
+ if (!nl)
{
smtp_printf("%.3s%c%.*s%s\r\n", !final, code, final ? ' ':'-', esclen, esc, msg);
return;
smtp_message_code(uschar **code, int *codelen, uschar **msg, uschar **log_msg,
BOOL check_valid)
{
-int n;
-int ovector[3];
+uschar * match;
+int len;
-if (!msg || !*msg) return;
-
-if ((n = pcre_exec(regex_smtp_code, NULL, CS *msg, Ustrlen(*msg), 0,
- PCRE_EOPT, ovector, sizeof(ovector)/sizeof(int))) < 0) return;
+if (!msg || !*msg || !regex_match(regex_smtp_code, *msg, -1, &match))
+ return;
+len = Ustrlen(match);
if (check_valid && (*msg)[0] != (*code)[0])
{
log_write(0, LOG_MAIN|LOG_PANIC, "configured error code starts with "
"incorrect digit (expected %c) in \"%s\"", (*code)[0], *msg);
- if (log_msg != NULL && *log_msg == *msg)
- *log_msg = string_sprintf("%s %s", *code, *log_msg + ovector[1]);
+ if (log_msg && *log_msg == *msg)
+ *log_msg = string_sprintf("%s %s", *code, *log_msg + len);
}
else
{
*code = *msg;
- *codelen = ovector[1]; /* Includes final space */
+ *codelen = len; /* Includes final space */
}
-*msg += ovector[1]; /* Chop the code off the message */
+*msg += len; /* Chop the code off the message */
return;
}
smtp_setup_msg(void)
{
int done = 0;
-int mailmax = -1;
BOOL toomany = FALSE;
BOOL discarded = FALSE;
BOOL last_was_rej_mail = FALSE;
/* If sender_host_unknown is true, we have got here via the -bs interface,
not called from inetd. Otherwise, we are running an IP connection and the
host address will be set. If the helo name is the primary name of this
- host and we haven't done a reverse lookup, force one now. If helo_required
+ host and we haven't done a reverse lookup, force one now. If helo_verify_required
is set, ensure that the HELO name matches the actual host. If helo_verify
is set, do the same check, but softly. */
tls_in.active.sock >= 0 ? " TLS" : "", host_and_ident(FALSE));
/* Verify if configured. This doesn't give much security, but it does
- make some people happy to be able to do it. If helo_required is set,
+ make some people happy to be able to do it. If helo_verify_required is set,
(host matches helo_verify_hosts) failure forces rejection. If helo_verify
is set (host matches helo_try_verify_hosts), it does not. This is perhaps
now obsolescent, since the verification can now be requested selectively
at ACL time. */
f.helo_verified = f.helo_verify_failed = sender_helo_dnssec = FALSE;
- if (fl.helo_required || fl.helo_verify)
+ if (fl.helo_verify_required || fl.helo_verify)
{
BOOL tempfail = !smtp_verify_helo();
if (!f.helo_verified)
{
- if (fl.helo_required)
+ if (fl.helo_verify_required)
{
smtp_printf("%d %s argument does not match calling host\r\n", FALSE,
tempfail? 451 : 550, hello);
#endif
/* Expand the per-connection message count limit option */
- mailmax = expand_mailmax(smtp_accept_max_per_connection);
+ smtp_mailcmd_max = expand_mailmax(smtp_accept_max_per_connection);
smtp_code = US"250 "; /* Default response code plus space*/
if (!user_msg)
}
#ifdef EXPERIMENTAL_ESMTP_LIMITS
- if ( (mailmax > 0 || recipients_max)
+ if ( (smtp_mailcmd_max > 0 || recipients_max)
&& verify_check_host(&limits_advertise_hosts) == OK)
{
g = string_fmt_append(g, "%.3s-LIMITS", smtp_code);
- if (mailmax > 0)
- g = string_fmt_append(g, " MAILMAX=%d", mailmax);
+ if (smtp_mailcmd_max > 0)
+ g = string_fmt_append(g, " MAILMAX=%d", smtp_mailcmd_max);
if (recipients_max)
g = string_fmt_append(g, " RCPTMAX=%d", recipients_max);
g = string_catn(g, US"\r\n", 2);
env_mail_type_t * mail_args; /* Sanity check & validate args */
if (!fl.helo_seen)
- if (fl.helo_required)
+ if ( fl.helo_verify_required
+ || verify_check_host(&hosts_require_helo) == OK)
{
smtp_printf("503 HELO or EHLO required\r\n", FALSE);
log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no "
"HELO/EHLO given", host_and_ident(FALSE));
break;
}
- else if (mailmax < 0)
- mailmax = expand_mailmax(smtp_accept_max_per_connection);
+ else if (smtp_mailcmd_max < 0)
+ smtp_mailcmd_max = expand_mailmax(smtp_accept_max_per_connection);
if (sender_address)
{
/* Check to see if the limit for messages per connection would be
exceeded by accepting further messages. */
- if (mailmax > 0 && smtp_mailcmd_count > mailmax)
+ if (smtp_mailcmd_max > 0 && smtp_mailcmd_count > smtp_mailcmd_max)
{
smtp_printf("421 too many messages in this connection\r\n", FALSE);
log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL command %s: too many "