#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"
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;
}
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);
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();
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);
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;
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;
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)
{
"/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);
auth_client_set_connect_notify(client, NULL, NULL);
auth_client_deinit(&client);
+
+ cmd_auth_deinit_sasl_client(input);
}
static void
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);
"/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))
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 */
doveadm_exit_code = EX_NOPERM;
auth_client_deinit(&auth_client);
event_unref(&input.event);
+ cmd_auth_deinit_sasl_client(&input);
pool_unref(&input.pool);
}
{
.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)
{
.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)