]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm: doveadm-auth - Add support for SASL mechanism in test and login commands.
authorStephan Bosch <stephan.bosch@open-xchange.com>
Thu, 12 Nov 2020 00:32:09 +0000 (01:32 +0100)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 27 Jan 2023 09:34:54 +0000 (09:34 +0000)
src/doveadm/Makefile.am
src/doveadm/doveadm-auth.c

index ee30ce755dc36b98932ac15fa51a66a81967086c..0705995b96d580721d6bff9951e89ae13741da1b 100644 (file)
@@ -26,6 +26,7 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib-imap-storage \
        -I$(top_srcdir)/src/lib-http \
        -I$(top_srcdir)/src/lib-dcrypt \
+       -I$(top_srcdir)/src/lib-sasl \
        -I$(top_srcdir)/src/stats \
        -DMODULEDIR=\""$(moduledir)"\" \
        -DAUTH_MODULE_DIR=\""$(moduledir)/auth"\" \
index 6abc9fb34f8180cb64c536227b5a09b8ad0fad7b..5105f777df98ae12e1688b69e6ca94035c5b2b27 100644 (file)
@@ -10,6 +10,7 @@
 #include "strescape.h"
 #include "var-expand.h"
 #include "wildcard-match.h"
+#include "dsasl-client.h"
 #include "settings-parser.h"
 #include "master-service.h"
 #include "master-service-settings.h"
@@ -32,12 +33,16 @@ static struct event_category event_category_auth = {
 struct authtest_input {
        pool_t pool;
        struct event *event;
+       const char *mechanism;
        const char *username;
        const char *master_user;
        const char *password;
        struct auth_user_info info;
        bool success;
 
+       const struct dsasl_client_mech *sasl_mech;
+       struct dsasl_client *sasl_client;
+
        struct auth_client_request *request;
 
        unsigned int auth_id;
@@ -133,12 +138,16 @@ cmd_user_input(struct auth_master_connection *conn,
 }
 
 static void
-auth_callback(struct auth_client_request *request ATTR_UNUSED,
-             enum auth_request_status status,
-             const char *data_base64 ATTR_UNUSED,
+auth_callback(struct auth_client_request *request,
+             enum auth_request_status status, const char *data_base64,
              const char *const *args, void *context)
 {
        struct authtest_input *input = context;
+       const unsigned char *sasl_output;
+       string_t *base64_output;
+       size_t input_len, sasl_output_len;
+       buffer_t *buf;
+       const char *error;
 
        input->request = NULL;
        input->auth_id = auth_client_request_get_id(request);
@@ -149,9 +158,6 @@ auth_callback(struct auth_client_request *request ATTR_UNUSED,
        if (!io_loop_is_running(current_ioloop))
                return;
 
-       if (status == 0)
-               i_fatal("passdb expects SASL continuation");
-
        switch (status) {
        case AUTH_REQUEST_STATUS_ABORT:
                i_unreached();
@@ -160,9 +166,26 @@ auth_callback(struct auth_client_request *request ATTR_UNUSED,
                printf("passdb: %s auth failed\n", input->username);
                break;
        case AUTH_REQUEST_STATUS_CONTINUE:
-               printf("passdb: %s auth unexpectedly requested continuation\n",
-                      input->username);
-               break;
+               input_len = strlen(data_base64);
+               buf = t_buffer_create(MAX_BASE64_DECODED_SIZE(input_len));
+               if (base64_decode(data_base64, input_len, buf) < 0)
+                       i_fatal("Server sent invalid base64 input");
+               if (dsasl_client_input(input->sasl_client, buf->data, buf->used,
+                                      &error) < 0) {
+                       printf("passdb: %s auth failed: %s\n",
+                              input->username, error);
+                       break;
+               } else if (dsasl_client_output(input->sasl_client, &sasl_output,
+                                              &sasl_output_len, &error) < 0) {
+                       printf("passdb: %s auth failed: %s\n",
+                              input->username, error);
+                       break;
+               }
+               base64_output =
+                       t_str_new(MAX_BASE64_ENCODED_SIZE(sasl_output_len)+2);
+               base64_encode(sasl_output, sasl_output_len, base64_output);
+               auth_client_request_continue(request, str_c(base64_output));
+               return;
        case AUTH_REQUEST_STATUS_OK:
                input->success = TRUE;
                printf("passdb: %s auth succeeded\n", input->username);
@@ -181,27 +204,27 @@ static void auth_connected(struct auth_client *client,
                           bool connected, void *context)
 {
        struct authtest_input *input = context;
+       const char *mech = dsasl_client_mech_get_name(input->sasl_mech);
        struct auth_request_info info;
-       string_t *init_resp, *base64_resp;
+       const unsigned char *sasl_output;
+       size_t sasl_output_len;
+       string_t *sasl_output_base64;
+       const char *error;
 
        if (!connected)
                i_fatal("Couldn't connect to auth socket");
+       if (auth_client_find_mech(client, mech) == NULL)
+               i_fatal("SASL mechanism '%s' not supported by server", mech);
 
-       init_resp = t_str_new(128);
-       str_append(init_resp, input->username);
-       str_append_c(init_resp, '\0');
-       if (input->master_user != NULL)
-               str_append(init_resp, input->master_user);
-       else
-               str_append(init_resp, input->username);
-       str_append_c(init_resp, '\0');
-       str_append(init_resp, input->password);
-
-       base64_resp = t_str_new(128);
-       base64_encode(str_data(init_resp), str_len(init_resp), base64_resp);
+       if (dsasl_client_output(input->sasl_client, &sasl_output,
+                               &sasl_output_len, &error) < 0)
+               i_fatal("Failed to create initial SASL reply: %s", error);
+       sasl_output_base64 =
+               t_str_new(MAX_BASE64_ENCODED_SIZE(sasl_output_len));
+       base64_encode(sasl_output, sasl_output_len, sasl_output_base64);
 
        i_zero(&info);
-       info.mech = "PLAIN";
+       info.mech = mech;
        info.service = input->info.service;
        info.session_id = input->info.session_id;
        info.local_name = input->info.local_name;
@@ -215,7 +238,7 @@ static void auth_connected(struct auth_client *client,
        info.real_remote_port = input->info.real_remote_port;
        info.extra_fields = input->info.extra_fields;
        info.forward_fields = input->info.forward_fields;
-       info.initial_resp_base64 = str_c(base64_resp);
+       info.initial_resp_base64 = str_c(sasl_output_base64);
        if (auth_want_log_debug())
                info.flags |= AUTH_REQUEST_FLAG_DEBUG;
 
@@ -223,6 +246,36 @@ static void auth_connected(struct auth_client *client,
                                                 auth_callback, input);
 }
 
+static void cmd_auth_init_sasl_client(struct authtest_input *input)
+{
+       struct dsasl_client_settings sasl_set;
+
+       if (input->mechanism != NULL) {
+               input->sasl_mech = dsasl_client_mech_find(input->mechanism);
+               if (input->sasl_mech == NULL)
+                       i_fatal("SASL mechanism '%s' not supported by client",
+                               input->mechanism);
+       }
+       if (input->sasl_mech == NULL)
+               input->sasl_mech = &dsasl_client_mech_plain;
+
+       i_zero(&sasl_set);
+       if (input->master_user == NULL)
+               sasl_set.authid = input->username;
+       else {
+               sasl_set.authid = input->master_user;
+               sasl_set.authzid = input->username;
+       }
+       sasl_set.password = input->password;
+
+       input->sasl_client = dsasl_client_new(input->sasl_mech, &sasl_set);
+}
+
+static void cmd_auth_deinit_sasl_client(struct authtest_input *input)
+{
+       dsasl_client_free(&input->sasl_client);
+}
+
 static void
 cmd_auth_input(const char *auth_socket_path, struct authtest_input *input)
 {
@@ -233,6 +286,8 @@ cmd_auth_input(const char *auth_socket_path, struct authtest_input *input)
                                               "/auth-client", NULL);
        }
 
+       cmd_auth_init_sasl_client(input);
+
        client = auth_client_init(auth_socket_path, getpid(), FALSE);
        auth_client_connect(client);
        auth_client_set_connect_notify(client, auth_connected, input);
@@ -242,6 +297,8 @@ cmd_auth_input(const char *auth_socket_path, struct authtest_input *input)
 
        auth_client_set_connect_notify(client, NULL, NULL);
        auth_client_deinit(&client);
+
+       cmd_auth_deinit_sasl_client(input);
 }
 
 static void
@@ -366,6 +423,7 @@ static void cmd_auth_test(struct doveadm_cmd_context *cctx)
        authtest_input_init(&input);
        (void)doveadm_cmd_param_str(cctx, "socket-path", &auth_socket_path);
        (void)doveadm_cmd_param_str(cctx, "master-user", &input.master_user);
+       (void)doveadm_cmd_param_str(cctx, "sasl-mech", &input.mechanism);
        if (doveadm_cmd_param_array(cctx, "auth-info", &auth_info))
                auth_user_info_parse(&input.info, auth_info);
 
@@ -448,6 +506,7 @@ static void cmd_auth_login(struct doveadm_cmd_context *cctx)
                                    "/auth-master", NULL);
        }
        (void)doveadm_cmd_param_str(cctx, "master-user", &input.master_user);
+       (void)doveadm_cmd_param_str(cctx, "sasl-mech", &input.mechanism);
        if (doveadm_cmd_param_array(cctx, "auth-info", &auth_info))
                auth_user_info_parse(&input.info, auth_info);
        if (!doveadm_cmd_param_str(cctx, "user", &input.username))
@@ -455,6 +514,8 @@ static void cmd_auth_login(struct doveadm_cmd_context *cctx)
        if (!doveadm_cmd_param_str(cctx, "password", &input.password))
                input.password = t_askpass("Password: ");
 
+       cmd_auth_init_sasl_client(&input);
+
        input.pool = pool_alloconly_create("auth login", 256);
        input.event = event_create(cctx->event);
        /* authenticate */
@@ -471,6 +532,7 @@ static void cmd_auth_login(struct doveadm_cmd_context *cctx)
                doveadm_exit_code = EX_NOPERM;
        auth_client_deinit(&auth_client);
        event_unref(&input.event);
+       cmd_auth_deinit_sasl_client(&input);
        pool_unref(&input.pool);
 }
 
@@ -719,9 +781,10 @@ struct doveadm_cmd_ver2 doveadm_cmd_auth[] = {
 {
        .cmd = cmd_auth_test,
        .name = "auth test",
-       .usage = "[-a <auth socket path>] [-x <auth info>] [-M <master user>] <user> [<password>]",
+       .usage = "[-a <auth socket path>] [-A <sasl mech>] [-x <auth info>] [-M <master user>] <user> [<password>]",
 DOVEADM_CMD_PARAMS_START
 DOVEADM_CMD_PARAM('a', "socket-path", CMD_PARAM_STR, 0)
+DOVEADM_CMD_PARAM('A', "sasl-mech", CMD_PARAM_STR, 0)
 DOVEADM_CMD_PARAM('x', "auth-info", CMD_PARAM_ARRAY, 0)
 DOVEADM_CMD_PARAM('M', "master-user", CMD_PARAM_STR, 0)
 DOVEADM_CMD_PARAM('\0', "user", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL)
@@ -731,10 +794,11 @@ DOVEADM_CMD_PARAMS_END
 {
        .cmd = cmd_auth_login,
        .name = "auth login",
-       .usage = "[-a <auth-login socket path>] [-m <auth-master socket path>] [-x <auth info>] [-M <master user>] <user> [<password>]",
+       .usage = "[-a <auth-login socket path>] [-m <auth-master socket path>] [-A <sasl mech>] [-x <auth info>] [-M <master user>] <user> [<password>]",
 DOVEADM_CMD_PARAMS_START
 DOVEADM_CMD_PARAM('a', "auth-login-socket-path", CMD_PARAM_STR, 0)
 DOVEADM_CMD_PARAM('m', "auth-master-socket-path", CMD_PARAM_STR, 0)
+DOVEADM_CMD_PARAM('A', "sasl-mech", CMD_PARAM_STR, 0)
 DOVEADM_CMD_PARAM('x', "auth-info", CMD_PARAM_ARRAY, 0)
 DOVEADM_CMD_PARAM('M', "master-user", CMD_PARAM_STR, 0)
 DOVEADM_CMD_PARAM('\0', "user", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL)