Hello and good evening! Please excuse the late replay.
Wietse Venema wrote in <4bzhbq2rngzj...@spike.porcupine.org>: |Viktor Dukhovni: |> On Sun, Aug 23, 2020 at 02:36:51AM +0200, Steffen Nurpmeso wrote: ... |Annd if you must pass additional information to the Dovecot auth |server, the proper way is to extend the xsasl_server_create() API, |not adding ad-hoc arguments here and there to poke data through the |abstraction layers. So i have rewritten the patch, and extended XSASL_SERVER_CREATE_ARGS instead, it makes things much easier! I also adjusted the documentation in xsasl_server.c accordingly, i had not seen that on Saturday. I can successfully authentificate with the EXTERNAL SASL mechanism. 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..830d5c9 100644 --- a/src/smtpd/smtpd_sasl_glue.c +++ b/src/smtpd/smtpd_sasl_glue.c @@ -185,9 +185,9 @@ void smtpd_sasl_initialize(void) void smtpd_sasl_activate(SMTPD_STATE *state, const char *sasl_opts_name, const char *sasl_opts_val) { - const char *mechanism_list; + const char *tls_cert_username, *mechanism_list; XSASL_SERVER_CREATE_ARGS create_args; - int tls_flag; + int tls_flags; /* * Sanity check. @@ -207,10 +207,16 @@ void smtpd_sasl_activate(SMTPD_STATE *state, const char *sasl_opts_name, /* * Set up a new server context for this connection. */ + tls_cert_username = 0; #ifdef USE_TLS - tls_flag = state->tls_context != 0; + tls_flags = (state->tls_context != 0) ? XSASL_TLS_SECURED : 0; + if (tls_flags && TLS_CERT_IS_PRESENT(state->tls_context)) { + tls_flags |= XSASL_TLS_CLIENT_CERT; + tls_cert_username = state->tls_context->peer_CN; + } + #else - tls_flag = 0; + tls_flags = 0; #endif #define ADDR_OR_EMPTY(addr, unknown) (strcmp(addr, unknown) ? addr : "") #define REALM_OR_NULL(realm) (*(realm) ? (realm) : (char *) 0) @@ -228,9 +234,10 @@ void smtpd_sasl_activate(SMTPD_STATE *state, const char *sasl_opts_name, client_port = ADDR_OR_EMPTY(state->port, CLIENT_PORT_UNKNOWN), service = var_smtpd_sasl_service, - user_realm = REALM_OR_NULL(var_smtpd_sasl_realm), + user_realm = REALM_OR_NULL(var_smtpd_sasl_realm), security_options = sasl_opts_val, - tls_flag = tls_flag)) == 0) + tls_flags = tls_flags, + tls_cert_username = tls_cert_username)) == 0) msg_fatal("SASL per-connection initialization failed"); /* diff --git a/src/xsasl/xsasl.h b/src/xsasl/xsasl.h index b494d7e..2cbff64 100644 --- a/src/xsasl/xsasl.h +++ b/src/xsasl/xsasl.h @@ -54,7 +54,8 @@ typedef struct XSASL_SERVER_CREATE_ARGS { const char *service; const char *user_realm; const char *security_options; - int tls_flag; + int tls_flags; + const char *tls_cert_username; /* (Or 0; only used if tls_flags!=0!) */ } XSASL_SERVER_CREATE_ARGS; typedef struct XSASL_SERVER_IMPL { @@ -65,12 +66,15 @@ typedef struct XSASL_SERVER_IMPL { extern XSASL_SERVER_IMPL *xsasl_server_init(const char *, const char *); extern ARGV *xsasl_server_types(void); +#define XSASL_TLS_SECURED (1<<0) /* (In fact: .tls_flags not 0) */ +#define XSASL_TLS_CLIENT_CERT (1<<1) + #define xsasl_server_create(impl, args) \ (impl)->create((impl), (args)) -#define XSASL_SERVER_CREATE(impl, args, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ +#define XSASL_SERVER_CREATE(impl, args, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) \ xsasl_server_create((impl), (((args)->a1), ((args)->a2), ((args)->a3), \ ((args)->a4), ((args)->a5), ((args)->a6), ((args)->a7), ((args)->a8), \ - ((args)->a9), ((args)->a10), (args))) + ((args)->a9), ((args)->a10), ((args)->a11), (args))) #define xsasl_server_done(impl) (impl)->done((impl)); /* diff --git a/src/xsasl/xsasl_dovecot_server.c b/src/xsasl/xsasl_dovecot_server.c index 601f787..9b849b4 100644 --- a/src/xsasl/xsasl_dovecot_server.c +++ b/src/xsasl/xsasl_dovecot_server.c @@ -166,7 +166,8 @@ typedef struct { char *username; /* authenticated user */ VSTRING *sasl_line; unsigned int sec_props; /* Postfix mechanism filter */ - int tls_flag; /* TLS enabled in this session */ + int tls_flags; /* TLS flags of this session */ + char *tls_cert_username; /* If .tls_flags, maybe commonName */ char *mechanism_list; /* filtered mechanism list */ ARGV *mechanism_argv; /* ditto */ char *client_addr; /* remote IP address */ @@ -450,7 +451,9 @@ static XSASL_SERVER *xsasl_dovecot_server_create(XSASL_SERVER_IMPL *impl, server->last_request_id = 0; server->mechanism_list = 0; server->mechanism_argv = 0; - server->tls_flag = args->tls_flag; + server->tls_flags = args->tls_flags; + server->tls_cert_username = (args->tls_flags && args->tls_cert_username) + ? mystrdup(args->tls_cert_username) : 0; server->sec_props = name_mask_opt(myname, xsasl_dovecot_conf_sec_props, args->security_options, @@ -502,6 +505,8 @@ static void xsasl_dovecot_server_free(XSASL_SERVER *xp) vstring_free(server->sasl_line); if (server->username) myfree(server->username); + if (server->tls_cert_username) + myfree(server->tls_cert_username); if (server->mechanism_list) { myfree(server->mechanism_list); argv_free(server->mechanism_argv); @@ -680,9 +685,20 @@ int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method, server->last_request_id, sasl_method, server->service, server->server_addr, server->client_addr); - if (server->tls_flag) + if (server->tls_flags) { /* XXX Encapsulate for logging. */ vstream_fputs("\tsecured", server->impl->sasl_stream); + if (server->tls_flags & XSASL_TLS_CLIENT_CERT) { + /* XXX Encapsulate for logging. */ + vstream_fputs("\tvalid-client-cert", + server->impl->sasl_stream); + if (server->tls_cert_username) + /* XXX Encapsulate for logging. */ + vstream_fprintf(server->impl->sasl_stream, + "\tcert_username=%s", + server->tls_cert_username); + } + } if (init_response) { /* diff --git a/src/xsasl/xsasl_server.c b/src/xsasl/xsasl_server.c index e8d7e16..dfdde0c 100644 --- a/src/xsasl/xsasl_server.c +++ b/src/xsasl/xsasl_server.c @@ -18,12 +18,16 @@ /* .in +4 /* typedef struct XSASL_SERVER_CREATE_ARGS { /* VSTREAM *stream; +/* int addr_family; /* const char *server_addr; +/* const char *server_port; /* const char *client_addr; +/* const char *client_port; /* const char *service; /* const char *user_realm; /* const char *security_options; -/* int tls_flag; +/* int tls_flags; +/* const char *tls_cert_username; /* } XSASL_SERVER_CREATE_ARGS; /* .in -4 /* @@ -34,7 +38,7 @@ /* XSASL_SERVER *XSASL_SERVER_CREATE(implementation, args, /* stream = stream_value, /* ..., -/* tls_flag = tls_flag_value) +/* tls_cert_username = tls_cert_username_value) /* XSASL_SERVER_IMPL *implementation; /* XSASL_SERVER_CREATE_ARGS *args; /* @@ -169,6 +173,16 @@ /* The connection between client and server. When SASL /* encryption is negotiated, the plug-in will transparently /* intercept the socket read/write operations. +/* .IP tls_flags +/* 0 or with XSASL_TLS_SECURED bit set if the connection is over +/* secured transport. +/* If the XSASL_TLS_CLIENT_CERT bit is also set then the client +/* presented a valid client certificate. +/* .IP tls_cert_username +/* Only inspected during session authentication if +/* XSASL_TLS_CLIENT_CERT is set in tls_flags, this is the +/* commonName presented by the client certificate. +/* The storage must be duplicated. /* .IP user_realm /* Authentication domain or null pointer. /* SECURITY