Skip to content

Commit

Permalink
net_smtp: Allow exemptions to STARTTLS requirement.
Browse files Browse the repository at this point in the history
STARTTLS is typically required to use AUTH commands,
to prevent credentials from leaking on plaintext
connections. However, this may not be a concern on
private local networks, and so the ability to exempt
IPs or CIDR ranges from having to use STARTTLS is added
so that encryption is not needlessly required in these
scenarios.
  • Loading branch information
InterLinked1 committed Dec 27, 2023
1 parent 638fcd8 commit fca411e
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 3 deletions.
7 changes: 7 additions & 0 deletions configs/net_smtp.conf
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ requirestarttls=yes ; Require STARTTLS for message submission agents. Default is
; In practice, this option must always be effectively enabled, since PLAIN and LOGIN authentication
; are only supported on secure connections, and authentication is required for message submission agents.

[starttls_exempt] ; This option complements the requirestarttls setting in [msa].
; Even when that option is enabled, specific hostnames/IP addresses/CIDR ranges can be exempted from this requirement,
; e.g. to allow hosts on a private intranet to submit outgoing mail without using TLS
; while requiring it for all public connections.
; Only the key is used to define an exemption, the config value is ignored.
127.0.0.1 = exempt

[blacklist] ; Domains or email addresses that we will not accept mail from (empty by default)
; WARNING: The blacklist applies to ALL MAILBOXES. Be careful about adding things here.
;example.com = no ; The actual value does not matter, just specify the domain to blacklist on the left hand side of the assignment.
Expand Down
30 changes: 27 additions & 3 deletions nets/net_smtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ static int validatespf = 1;
static int add_received_msa = 0;
static int archivelists = 1;

struct stringlist starttls_exempt;

static FILE *smtplogfp = NULL;
static unsigned int smtp_log_level = 5;
static pthread_mutex_t loglock = PTHREAD_MUTEX_INITIALIZER;
Expand Down Expand Up @@ -483,6 +485,19 @@ static int smtp_ip_mismatch(const char *actual, const char *hostname)
return 0;
}

static int exempt_from_starttls(struct smtp_session *smtp)
{
const char *s;
struct stringitem *i = NULL;

while ((s = stringlist_next(&starttls_exempt, &i))) {
if (bbs_ip_match_ipv4(smtp->node->ip, s)) {
return 1;
}
}
return 0;
}

static int handle_helo(struct smtp_session *smtp, char *s, int ehlo)
{
if (strlen_zero(s)) {
Expand Down Expand Up @@ -540,7 +555,7 @@ static int handle_helo(struct smtp_session *smtp, char *s, int ehlo)
smtp_reply0_nostatus(smtp, 250, "%s at your service [%s]", bbs_hostname(), smtp->node->ip);
/* The RFC says that login should only be allowed on secure connections,
* but if we don't allow login on plaintext connections, then they're functionally useless. */
if (smtp->secure || !require_starttls) {
if (smtp->secure || !require_starttls || exempt_from_starttls(smtp)) {
smtp_reply0_nostatus(smtp, 250, "AUTH LOGIN PLAIN"); /* RFC-complaint way */
smtp_reply0_nostatus(smtp, 250, "AUTH=LOGIN PLAIN"); /* For non-compliant user agents, e.g. Outlook 2003 and older */
}
Expand Down Expand Up @@ -2501,15 +2516,15 @@ static int smtp_process(struct smtp_session *smtp, char *s, struct readline_data
} else {
smtp_reply(smtp, 454, 5.5.1, "STARTTLS may not be repeated");
}
} else if (smtp->msa && !smtp->secure && require_starttls) {
} else if (smtp->msa && !smtp->secure && require_starttls && !exempt_from_starttls(smtp)) {
smtp_reply(smtp, 504, 5.5.4, "Must issue a STARTTLS command first");
} else if (!strcasecmp(command, "AUTH")) {
/* https://www.samlogic.net/articles/smtp-commands-reference-auth.htm */
if (smtp->tflags.inauth) { /* Already in authorization */
smtp_reply(smtp, 503, 5.5.1, "Bad sequence of commands.");
} else if (bbs_user_is_registered(smtp->node->user)) { /* Already authed */
smtp_reply(smtp, 503, 5.7.0, "Already authenticated, no identity changes permitted");
} else if (!smtp->secure && require_starttls) {
} else if (!smtp->secure && require_starttls && !exempt_from_starttls(smtp)) {
/* Must not offer PLAIN or LOGIN on insecure connections. */
smtp_reply(smtp, 504, 5.5.4, "Must issue a STARTTLS command first");
} else {
Expand Down Expand Up @@ -2719,6 +2734,14 @@ static int load_config(void)
val = bbs_keyval_val(keyval);
add_authorized_relay(key, val);
}
} else if (!strcmp(bbs_config_section_name(section), "starttls_exempt")) {
while ((keyval = bbs_config_section_walk(section, keyval))) {
key = bbs_keyval_key(keyval);
val = bbs_keyval_val(keyval);
if (!stringlist_contains(&starttls_exempt, key)) {
stringlist_push(&starttls_exempt, key);
}
}
} else if (strcasecmp(bbs_config_section_name(section), "general")) {
bbs_warning("Invalid section name '%s'\n", bbs_config_section_name(section));
}
Expand Down Expand Up @@ -2796,6 +2819,7 @@ static int unload_module(void)
}
stringlist_empty(&blacklist);
RWLIST_WRLOCK_REMOVE_ALL(&authorized_relays, entry, relay_free);
stringlist_empty(&starttls_exempt);
if (!RWLIST_EMPTY(&filters)) {
bbs_error("Filter(s) still registered at unload?\n");
}
Expand Down

0 comments on commit fca411e

Please sign in to comment.