From: gilles@poolp.org Subject: smtpd: table auth offloading To: tech@openbsd.org Date: Thu, 23 May 2024 21:55:50 +0000 Hello, Just a mail to propose an idea that I discussed with op@ in private. In smtpd, there are two codepaths for authentication: 1- if no table was provided, smtpd relies on bsd_auth(3) 2- if a table is provided, it performs a K_CREDENTIALS lookup which, given a username as a key, looks up the crypt(3)-ed password that is then compared to the one that the user provided. When you provide a table to the auth keyword, ie: listen on all [...] auth Regardless of the backend used by you take the second path, which is great because any backend that supports key-value lookup is usable as an authentication backend in smtpd: inline, file, db, ... Problem is that some backends do not expect to be queried this way. For example, OpenLDAP and OpenBSD's ldapd have an existing attribute userPassword which is mandatory but which we can't use because it is not in the format we expect and not meant to be fed to crypt(3) like we do for all other table backends. In such cases, we'd rather let a table backend do the validation and tell us if it succeeded. This diff introduces a new lookup service K_AUTH which is only meant to be used by table backends that need custom auth validation. If we authenticate against a table that supports K_AUTH, then instead of a K_CREDENTIALS lookup we forward the username:password so the backend can tell us if authentication succeeded or not. ok ? Index: lka.c =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/lka.c,v diff -u -p -r1.248 lka.c --- lka.c 20 Jan 2024 09:01:03 -0000 1.248 +++ lka.c 23 May 2024 21:07:15 -0000 @@ -720,6 +720,7 @@ static int lka_authenticate(const char *tablename, const char *user, const char *password) { struct table *table; + char offloadkey[LINE_MAX]; union lookup lk; log_debug("debug: lka: authenticating for %s:%s", tablename, user); @@ -728,6 +729,25 @@ lka_authenticate(const char *tablename, log_warnx("warn: could not find table %s needed for authentication", tablename); return (LKA_TEMPFAIL); + } + + /* table backend supports authentication offloading */ + if (table_check_service(table, K_AUTH)) { + if (!bsnprintf(offloadkey, sizeof(offloadkey), "%s:%s", user, password)) { + log_warnx("warn: offload key serialization failed for %s:%s", + tablename, user); + return (LKA_TEMPFAIL); + } + switch (table_match(table, K_AUTH, offloadkey)) { + case -1: + log_warnx("warn: user credentials lookup fail for %s:%s", + tablename, user); + return (LKA_TEMPFAIL); + case 0: + return (LKA_PERMFAIL); + default: + return (LKA_OK); + } } switch (table_lookup(table, K_CREDENTIALS, user, &lk)) { Index: smtpd-api.h =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/smtpd-api.h,v diff -u -p -r1.36 smtpd-api.h --- smtpd-api.h 23 Dec 2018 16:06:24 -0000 1.36 +++ smtpd-api.h 23 May 2024 21:07:15 -0000 @@ -135,8 +135,9 @@ enum table_service { K_RELAYHOST = 0x200, /* returns struct relayhost */ K_STRING = 0x400, K_REGEX = 0x800, + K_AUTH = 0x1000, }; -#define K_ANY 0xfff +#define K_ANY 0xffff enum { PROC_TABLE_OK, Index: table.5 =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/table.5,v diff -u -p -r1.14 table.5 --- table.5 2 May 2024 18:14:33 -0000 1.14 +++ table.5 23 May 2024 21:07:15 -0000 @@ -113,6 +113,19 @@ Here, the user is allowed to send mail f .Bd -unfilled -offset indent .Ic listen on Ar interface Cm auth Oo Ar ... Oc Cm senders Pf < Ar table Ns > .Ed +.Ss Authentication tables +In most cases, +authentication is best served by a credentials table which provide information that +.Nm smtpd 8 +can use to validate itself using +.Nm bsd_auth 3 +or +.Nm crypt 3 . +.Pp +In some cases, +this is not desireable and the validation needs to be offloaded. +The authentication tables support doing a check on a username and password, +returning success or failure based on custom logic. .Ss Domain tables Domain tables are simple lists of domains or hosts. .Bd -unfilled -offset indent Index: table.c =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/table.c,v diff -u -p -r1.52 table.c --- table.c 7 May 2024 12:10:06 -0000 1.52 +++ table.c 23 May 2024 21:07:15 -0000 @@ -83,6 +83,7 @@ table_service_name(enum table_service s) case K_RELAYHOST: return "relayhost"; case K_STRING: return "string"; case K_REGEX: return "regex"; + case K_AUTH: return "auth"; } return "???"; } @@ -116,6 +117,8 @@ table_service_from_name(const char *serv return K_STRING; if (!strcmp(service, "regex")) return K_REGEX; + if (!strcmp(service, "auth")) + return K_AUTH; return (-1); }