Hello! Steffen Nurpmeso wrote in <20200820232547.x0nbc%stef...@sdaoden.eu>: ... |Wietse Venema wrote in | <4bxstk189nzj...@spike.porcupine.org>: ||Steffen Nurpmeso: ||> Wietse Venema wrote in ||> <4bwxll093mzj...@spike.porcupine.org>: ||>|Steffen Nurpmeso: ... ||>|Short summary: Postfix does not implement a single iota of SASL ||>|AUTH support. Postfix simply propagates the names of mechanisms ||>|that the backend (Cyrus or Dovecot) claims to support, and Postfix | ... ||>|If Dovecot claims to support SASL EXTERNAL but does not handle it, ||>|that that is a bit of a WTF. ... ||> until SASL says it is done?!. How could EXTERNAL ever work like ||> that in a client/server->auth-server situation? || ||There's a chicken and egg question in there somewhere. || ||https://wiki1.dovecot.org/Authentication%20Protocol mentions ||two attributes that might be relevant, and that Postfix can send: || ||secured || Remote user has secured transport to auth client] (eg. localhost, \ || SSL, TLS) || ||valid-client-cert || Remote user has presented a valid SSL certificate. || ||But these are booleans. What protocol attribute would Postfix use ||to pass certificate name information (and which name, as there ||can be any number of them)? ... |the dovecot SASL wiki entry. So it seems postfixs SASL support |can be improved a bit. And, well, i think for EXTERNAL there has |to be user name as an immediate response, so this would be that. | |I would like to look into this tomorrow or on Saturday, maybe |i can produce a patch that adds the above keywords to the postfix/ |dovecot SASL interaction?
Well. I first wanted to pass the SMTPD_STATE through to the SASL support, but then i added a flag field, which avoided possibly undesired new header inclusions. (I never compiled that path.) Unfortunately that still does not help and bring EXTERNAL authentication support to postfix, because dovecot still complains about unknown user name, even if the user name comes with the initial response, even with Aug 23 01:39:29 arch-2020 dovecot[245]: auth: Debug: client in: AUTH 1 EXTERNAL service=smtp nologin lip=10.0.1.11 rip=10.0.0.1 secured valid-client-cert Aug 23 01:39:29 arch-2020 dovecot[245]: auth: external(?,10.0.0.1): username not known Aug 23 01:39:29 arch-2020 dovecot[245]: auth: Debug: auth(?,10.0.0.1): Auth request finished Aug 23 01:39:31 arch-2020 postfix/smtpd[6433]: warning: _gateway[10.0.0.1]: SASL EXTERNAL authentication failed: Aug 23 01:39:31 arch-2020 dovecot[245]: auth: Debug: client passdb out: FAIL 1 Aug 23 01:39:32 arch-2020 postfix/smtpd[6433]: too many errors after AUTH from _gateway[10.0.0.1] However, short of time (it will be no sooner than six o'clock in the morning until i will get home, sorry! Just in case anyone is interested), i blindly added another cert_username=steffen to the stuff in src/xsasl/xsasl_dovecot_server.c, and with that we will get the job done! So i added another "const char *certuser" and with that i can successfully use EXTERNAL authentication with postfix! Yay. However, my MUA also supports a "externanon" authentication which uses EXTERNAL with an empty immediate response, and that does not work out for now, but my code is currently in chaos, so that could also be it. Please find the first non-working approach in -try1.patch, the latter in -try2.patch. This is against v3.5.6. Of course i have no idea of the codebase say, let alone style, i hope i somehow got that tab/space .. hmmmmm ... Good night and a nice Sunday i wish! Ciao from Germany! --steffen | |Der Kragenbaer, The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt)
diff --git a/src/smtpd/smtpd_sasl_glue.c b/src/smtpd/smtpd_sasl_glue.c index 020c830..e16f1dc 100644 --- a/src/smtpd/smtpd_sasl_glue.c +++ b/src/smtpd/smtpd_sasl_glue.c @@ -288,15 +288,24 @@ int smtpd_sasl_authenticate(SMTPD_STATE *state, const char *sasl_method, const char *init_response) { - int status; + int flags, status; const char *sasl_username; + flags = 0; +#ifdef USE_TLS + if(state->tls_context != NULL){ + flags = XSASL_FLAG_SECURED; + if(TLS_CERT_IS_PRESENT(state->tls_context)) + flags |= XSASL_FLAG_CLIENT_CERT; + } +#endif + /* * SASL authentication protocol start-up. Process any initial client * response that was sent along in the AUTH command. */ for (status = xsasl_server_first(state->sasl_server, sasl_method, - init_response, state->sasl_reply); + init_response, state->sasl_reply, flags); status == XSASL_AUTH_MORE; status = xsasl_server_next(state->sasl_server, STR(state->buffer), state->sasl_reply)) { diff --git a/src/xsasl/xsasl.h b/src/xsasl/xsasl.h index b494d7e..a3c6bc9 100644 --- a/src/xsasl/xsasl.h +++ b/src/xsasl/xsasl.h @@ -24,15 +24,23 @@ */ typedef struct XSASL_SERVER { void (*free) (struct XSASL_SERVER *); - int (*first) (struct XSASL_SERVER *, const char *, const char *, VSTRING *); + int (*first) (struct XSASL_SERVER *, const char *, const char *, VSTRING *, int); int (*next) (struct XSASL_SERVER *, const char *, VSTRING *); const char *(*get_mechanism_list) (struct XSASL_SERVER *); const char *(*get_username) (struct XSASL_SERVER *); } XSASL_SERVER; +#ifdef USE_TLS +# define XSASL_FLAG_SECURED (1<<0) /* Connection is TLS secured */ +# define XSASL_FLAG_CLIENT_CERT (1<<1) /* Client presented validated certificate */ +#else +# define XSASL_FLAG_SECURED (0) +# define XSASL_FLAG_CLIENT_CERT (0) +#endif + #define xsasl_server_free(server) (server)->free(server) -#define xsasl_server_first(server, method, init_resp, reply) \ - (server)->first((server), (method), (init_resp), (reply)) +#define xsasl_server_first(server, method, init_resp, reply, flags) \ + (server)->first((server), (method), (init_resp), (reply), (flags)) #define xsasl_server_next(server, request, reply) \ (server)->next((server), (request), (reply)) #define xsasl_server_get_mechanism_list(server) \ diff --git a/src/xsasl/xsasl_cyrus_server.c b/src/xsasl/xsasl_cyrus_server.c index 89e1fc9..0df656c 100644 --- a/src/xsasl/xsasl_cyrus_server.c +++ b/src/xsasl/xsasl_cyrus_server.c @@ -167,7 +167,7 @@ static XSASL_SERVER *xsasl_cyrus_server_create(XSASL_SERVER_IMPL *, XSASL_SERVER_CREATE_ARGS *); static void xsasl_cyrus_server_free(XSASL_SERVER *); static int xsasl_cyrus_server_first(XSASL_SERVER *, const char *, - const char *, VSTRING *); + const char *, VSTRING *, int); static int xsasl_cyrus_server_next(XSASL_SERVER *, const char *, VSTRING *); static int xsasl_cyrus_server_set_security(XSASL_SERVER *, const char *); static const char *xsasl_cyrus_server_get_mechanism_list(XSASL_SERVER *); @@ -512,7 +512,8 @@ static int xsasl_cyrus_server_auth_response(int sasl_status, /* xsasl_cyrus_server_first - per-session authentication */ int xsasl_cyrus_server_first(XSASL_SERVER *xp, const char *sasl_method, - const char *init_response, VSTRING *reply) + const char *init_response, VSTRING *reply, + int unused_flags) { const char *myname = "xsasl_cyrus_server_first"; XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp; diff --git a/src/xsasl/xsasl_dovecot_server.c b/src/xsasl/xsasl_dovecot_server.c index 601f787..80ce96e 100644 --- a/src/xsasl/xsasl_dovecot_server.c +++ b/src/xsasl/xsasl_dovecot_server.c @@ -181,7 +181,7 @@ static XSASL_SERVER *xsasl_dovecot_server_create(XSASL_SERVER_IMPL *, XSASL_SERVER_CREATE_ARGS *); static void xsasl_dovecot_server_free(XSASL_SERVER *); static int xsasl_dovecot_server_first(XSASL_SERVER *, const char *, - const char *, VSTRING *); + const char *, VSTRING *, int); static int xsasl_dovecot_server_next(XSASL_SERVER *, const char *, VSTRING *); static const char *xsasl_dovecot_server_get_mechanism_list(XSASL_SERVER *); static const char *xsasl_dovecot_server_get_username(XSASL_SERVER *); @@ -637,7 +637,8 @@ static int is_valid_base64(const char *data) /* xsasl_dovecot_server_first - per-session authentication */ int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method, - const char *init_response, VSTRING *reply) + const char *init_response, VSTRING *reply, + int flags) { const char *myname = "xsasl_dovecot_server_first"; XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp; @@ -647,9 +648,12 @@ int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method, #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3)) if (msg_verbose) - msg_info("%s: sasl_method %s%s%s", myname, sasl_method, + msg_info("%s: sasl_method %s%s%s%s%s", myname, sasl_method, IFELSE(init_response, ", init_response ", ""), - IFELSE(init_response, init_response, "")); + IFELSE(init_response, init_response, ""), + IFELSE(flags & XSASL_FLAG_SECURED, ", secured", ""), + IFELSE(flags & XSASL_FLAG_CLIENT_CERT, + ", valid-client-cert", "")); if (server->mechanism_argv == 0) msg_panic("%s: no mechanism list", myname); @@ -676,13 +680,12 @@ int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method, server->last_request_id = ++server->impl->request_id_counter; /* XXX Encapsulate for logging. */ vstream_fprintf(server->impl->sasl_stream, - "AUTH\t%u\t%s\tservice=%s\tnologin\tlip=%s\trip=%s", + "AUTH\t%u\t%s\tservice=%s\tnologin\tlip=%s\trip=%s%s%s", server->last_request_id, sasl_method, server->service, server->server_addr, - server->client_addr); - if (server->tls_flag) - /* XXX Encapsulate for logging. */ - vstream_fputs("\tsecured", server->impl->sasl_stream); + server->client_addr, + (flags & XSASL_FLAG_SECURED ? "\tsecured" : ""), + (flags & XSASL_FLAG_CLIENT_CERT ? "\tvalid-client-cert" : "")); if (init_response) { /* diff --git a/src/xsasl/xsasl_server.c b/src/xsasl/xsasl_server.c index e8d7e16..9b64f18 100644 --- a/src/xsasl/xsasl_server.c +++ b/src/xsasl/xsasl_server.c @@ -41,11 +41,12 @@ /* void xsasl_server_free(server) /* XSASL_SERVER *server; /* -/* int xsasl_server_first(server, auth_method, init_resp, server_reply) +/* int xsasl_server_first(server, auth_method, init_resp, server_reply, flags) /* XSASL_SERVER *server; /* const char *auth_method; /* const char *init_resp; /* VSTRING *server_reply; +/* int flags; /* /* int xsasl_server_next(server, client_request, server_reply) /* XSASL_SERVER *server;
diff --git a/src/smtpd/smtpd_sasl_glue.c b/src/smtpd/smtpd_sasl_glue.c index 020c830..217f4dc 100644 --- a/src/smtpd/smtpd_sasl_glue.c +++ b/src/smtpd/smtpd_sasl_glue.c @@ -288,16 +288,43 @@ int smtpd_sasl_authenticate(SMTPD_STATE *state, const char *sasl_method, const char *init_response) { - int status; +#ifdef USE_TLS + VSTRING *peer_CN; +#endif + int flags, status; const char *sasl_username; + flags = 0; + sasl_username = NULL; +#ifdef USE_TLS + peer_CN = NULL; + if (state->tls_context != NULL) { + flags = XSASL_FLAG_SECURED; + if (TLS_CERT_IS_PRESENT(state->tls_context)) { + flags |= XSASL_FLAG_CLIENT_CERT; + peer_CN = state->tls_context->peer_CN; + if (peer_CN != NULL) { + peer_CN = vstring_strcpy(vstring_alloc(strlen(peer_CN) + 1), peer_CN); + sasl_username = STR(peer_CN); + } + } + } +#endif + /* * SASL authentication protocol start-up. Process any initial client * response that was sent along in the AUTH command. */ - for (status = xsasl_server_first(state->sasl_server, sasl_method, - init_response, state->sasl_reply); - status == XSASL_AUTH_MORE; + status = xsasl_server_first(state->sasl_server, sasl_method, + init_response, state->sasl_reply, + flags, sasl_username); + +#ifdef USE_TLS + if (peer_CN != NULL) + vstring_free(peer_CN); +#endif + + for (; status == XSASL_AUTH_MORE; status = xsasl_server_next(state->sasl_server, STR(state->buffer), state->sasl_reply)) { diff --git a/src/xsasl/xsasl.h b/src/xsasl/xsasl.h index b494d7e..383ecf5 100644 --- a/src/xsasl/xsasl.h +++ b/src/xsasl/xsasl.h @@ -24,15 +24,23 @@ */ typedef struct XSASL_SERVER { void (*free) (struct XSASL_SERVER *); - int (*first) (struct XSASL_SERVER *, const char *, const char *, VSTRING *); + int (*first) (struct XSASL_SERVER *, const char *, const char *, VSTRING *, int, const char *); int (*next) (struct XSASL_SERVER *, const char *, VSTRING *); const char *(*get_mechanism_list) (struct XSASL_SERVER *); const char *(*get_username) (struct XSASL_SERVER *); } XSASL_SERVER; +#ifdef USE_TLS +# define XSASL_FLAG_SECURED (1<<0) /* Connection is TLS secured */ +# define XSASL_FLAG_CLIENT_CERT (1<<1) /* Client presented validated certificate */ +#else +# define XSASL_FLAG_SECURED (0) +# define XSASL_FLAG_CLIENT_CERT (0) +#endif + #define xsasl_server_free(server) (server)->free(server) -#define xsasl_server_first(server, method, init_resp, reply) \ - (server)->first((server), (method), (init_resp), (reply)) +#define xsasl_server_first(server, method, init_resp, reply, flags, certuser) \ + (server)->first((server), (method), (init_resp), (reply), (flags), (certuser)) #define xsasl_server_next(server, request, reply) \ (server)->next((server), (request), (reply)) #define xsasl_server_get_mechanism_list(server) \ diff --git a/src/xsasl/xsasl_cyrus_server.c b/src/xsasl/xsasl_cyrus_server.c index 89e1fc9..8e3b811 100644 --- a/src/xsasl/xsasl_cyrus_server.c +++ b/src/xsasl/xsasl_cyrus_server.c @@ -167,7 +167,8 @@ static XSASL_SERVER *xsasl_cyrus_server_create(XSASL_SERVER_IMPL *, XSASL_SERVER_CREATE_ARGS *); static void xsasl_cyrus_server_free(XSASL_SERVER *); static int xsasl_cyrus_server_first(XSASL_SERVER *, const char *, - const char *, VSTRING *); + const char *, VSTRING *, + int, const char *); static int xsasl_cyrus_server_next(XSASL_SERVER *, const char *, VSTRING *); static int xsasl_cyrus_server_set_security(XSASL_SERVER *, const char *); static const char *xsasl_cyrus_server_get_mechanism_list(XSASL_SERVER *); @@ -512,7 +513,8 @@ static int xsasl_cyrus_server_auth_response(int sasl_status, /* xsasl_cyrus_server_first - per-session authentication */ int xsasl_cyrus_server_first(XSASL_SERVER *xp, const char *sasl_method, - const char *init_response, VSTRING *reply) + const char *init_response, VSTRING *reply, + int unused_flags, const char *unused_certuser) { const char *myname = "xsasl_cyrus_server_first"; XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp; diff --git a/src/xsasl/xsasl_dovecot_server.c b/src/xsasl/xsasl_dovecot_server.c index 601f787..1c7d3ed 100644 --- a/src/xsasl/xsasl_dovecot_server.c +++ b/src/xsasl/xsasl_dovecot_server.c @@ -181,7 +181,8 @@ static XSASL_SERVER *xsasl_dovecot_server_create(XSASL_SERVER_IMPL *, XSASL_SERVER_CREATE_ARGS *); static void xsasl_dovecot_server_free(XSASL_SERVER *); static int xsasl_dovecot_server_first(XSASL_SERVER *, const char *, - const char *, VSTRING *); + const char *, VSTRING *, + int, const char *); static int xsasl_dovecot_server_next(XSASL_SERVER *, const char *, VSTRING *); static const char *xsasl_dovecot_server_get_mechanism_list(XSASL_SERVER *); static const char *xsasl_dovecot_server_get_username(XSASL_SERVER *); @@ -637,7 +638,8 @@ static int is_valid_base64(const char *data) /* xsasl_dovecot_server_first - per-session authentication */ int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method, - const char *init_response, VSTRING *reply) + const char *init_response, VSTRING *reply, + int flags, const char *certuser) { const char *myname = "xsasl_dovecot_server_first"; XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp; @@ -647,9 +649,13 @@ int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method, #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3)) if (msg_verbose) - msg_info("%s: sasl_method %s%s%s", myname, sasl_method, + msg_info("%s: sasl_method %s%s%s%s%s%s%s", myname, sasl_method, IFELSE(init_response, ", init_response ", ""), - IFELSE(init_response, init_response, "")); + IFELSE(init_response, init_response, ""), + IFELSE(flags & XSASL_FLAG_SECURED, ", secured", ""), + IFELSE(flags & XSASL_FLAG_CLIENT_CERT, + ", valid-client-cert", ""), + IFELSE(certuser, ", ", ""), IFELSE(certuser, certuser, "")); if (server->mechanism_argv == 0) msg_panic("%s: no mechanism list", myname); @@ -676,13 +682,13 @@ int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method, server->last_request_id = ++server->impl->request_id_counter; /* XXX Encapsulate for logging. */ vstream_fprintf(server->impl->sasl_stream, - "AUTH\t%u\t%s\tservice=%s\tnologin\tlip=%s\trip=%s", + "AUTH\t%u\t%s\tservice=%s\tnologin\tlip=%s\trip=%s%s%s%s%s", server->last_request_id, sasl_method, server->service, server->server_addr, - server->client_addr); - if (server->tls_flag) - /* XXX Encapsulate for logging. */ - vstream_fputs("\tsecured", server->impl->sasl_stream); + server->client_addr, + (flags & XSASL_FLAG_SECURED ? "\tsecured" : ""), + (flags & XSASL_FLAG_CLIENT_CERT ? "\tvalid-client-cert" : ""), + (certuser ? "\tcert_username=" : ""), (certuser ? certuser : "")); if (init_response) { /* diff --git a/src/xsasl/xsasl_server.c b/src/xsasl/xsasl_server.c index e8d7e16..e029695 100644 --- a/src/xsasl/xsasl_server.c +++ b/src/xsasl/xsasl_server.c @@ -41,11 +41,13 @@ /* void xsasl_server_free(server) /* XSASL_SERVER *server; /* -/* int xsasl_server_first(server, auth_method, init_resp, server_reply) +/* int xsasl_server_first(server, auth_method, init_resp, server_reply, flags, certuser) /* XSASL_SERVER *server; /* const char *auth_method; /* const char *init_resp; /* VSTRING *server_reply; +/* int flags; +/* const char *certuser; /* /* int xsasl_server_next(server, client_request, server_reply) /* XSASL_SERVER *server;