From 0f0551127adff263aa5622e51bfe12743947652c Mon Sep 17 00:00:00 2001 From: Neil Date: Sat, 8 Mar 2025 12:55:27 +1300 Subject: [PATCH 1/2] If session->localhost is NULL then first try to populate it using /etc/mailname (if available). --- protocol.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/protocol.c b/protocol.c index e946020..86a7a6c 100644 --- a/protocol.c +++ b/protocol.c @@ -54,6 +54,8 @@ #include "headers.h" #include "protocol.h" +#define FQDN_MAX_LEN 253 + struct protocol_states { void (*cmd) (siobuf_t conn, smtp_session_t session); @@ -135,6 +137,25 @@ do_session (smtp_session_t session) int nresp, status, want_flush, fast; char *nodename; + if (session->localhost == NULL) + { + FILE *f = fopen ("/etc/mailname", "r"); + // If the file is open.. + if (f) + { + char buf [FQDN_MAX_LEN+1+1]; // Plus newline plus terminator. + // Read a single line. + if (fgets (buf, sizeof buf, f)) + { + // If a newline was included then replace it with a terminator. + char *pnl = strchr (buf, '\n'); + if (pnl) + *pnl = '\0'; + session->localhost = strdup (buf); + } + fclose (f); + } + } #if HAVE_UNAME if (session->localhost == NULL) { From 4c014c5b36b1ddcda1618e4ef4d1f25e5773bafe Mon Sep 17 00:00:00 2001 From: Neil Date: Wed, 12 Mar 2025 17:16:13 +1300 Subject: [PATCH 2/2] When the environment variable LIBESMTP_EHLO_FQDN is set then it now indicates either that canonical hostnames be looked up and used in place of unqualified hostnames, or an explicit hostname to use. --- protocol.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/protocol.c b/protocol.c index 86a7a6c..e9c13a0 100644 --- a/protocol.c +++ b/protocol.c @@ -26,6 +26,7 @@ #include +#include #include #include #include @@ -127,6 +128,43 @@ set_first_message (smtp_session_t session) * The main protocol engine. *****************************************************************************/ +/* Indicates whether the specified `hostname` is a FQDN (Such + as"myhost.example.com"), or unqualified (Such as "myhost"). */ +static bool +is_fqdn (const char *hostname) +{ + return strrchr (hostname, '.') != NULL; +} + +/* Provides the canonical name of `hostname`. Returns 0 on success, or a + non-zero error code, in which case `canonical_name` will be undefined. + On success, `canonical_name` will refer to a new string that must be + `free`d. */ +static int +get_canonical_name (const char *hostname, char **canonical_name) +{ + int err; + char *service = NULL; + struct addrinfo hints; + struct addrinfo *ai; + + memset (&hints, 0, sizeof hints); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + err = getaddrinfo (hostname, service, &hints, &ai); + if (err == 0) + { + *canonical_name = strdup (ai->ai_canonname); + if (canonical_name == NULL) + { + err = (ENOMEM); + } + freeaddrinfo (ai); + } + return err; +} + int do_session (smtp_session_t session) { @@ -192,6 +230,32 @@ do_session (smtp_session_t session) } #endif + /* If session->localhost is not a FQDN and LIBESMTP_EHLO_FDQN is set then + either use LIBESMTP_EHLO_FDQN if it looks like a FQDN or convert the + unqualified hostname to its FQDN. */ + char *env_ehlo_fqdn = getenv ("LIBESMTP_EHLO_FQDN"); + if (! is_fqdn (session->localhost) && env_ehlo_fqdn != NULL) + { + if (is_fqdn (env_ehlo_fqdn)) + { + session->localhost = strdup (env_ehlo_fqdn); + if (session->localhost == NULL) + { + set_errno (ENOMEM); + return 0; + } + } + else + { + err = get_canonical_name (session->localhost, &session->localhost); + if (err != 0) + { + set_errno (err); + return 0; + } + } + } + /* Initialise the current message and recipient variables in the session. This returns zero if there is no work to do. */ #ifndef USE_ETRN