diff options
Diffstat (limited to '')
-rw-r--r-- | src/doveadm/doveadm-auth.c | 787 |
1 files changed, 787 insertions, 0 deletions
diff --git a/src/doveadm/doveadm-auth.c b/src/doveadm/doveadm-auth.c new file mode 100644 index 0000000..d89befe --- /dev/null +++ b/src/doveadm/doveadm-auth.c @@ -0,0 +1,787 @@ +/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ioloop.h" +#include "array.h" +#include "askpass.h" +#include "base64.h" +#include "hex-binary.h" +#include "str.h" +#include "strescape.h" +#include "var-expand.h" +#include "wildcard-match.h" +#include "settings-parser.h" +#include "master-service.h" +#include "master-service-settings.h" +#include "auth-client.h" +#include "auth-master.h" +#include "master-auth.h" +#include "master-login-auth.h" +#include "mail-storage-service.h" +#include "mail-user.h" +#include "doveadm.h" +#include "doveadm-print.h" + +#include <stdio.h> +#include <unistd.h> + +static struct event_category event_category_auth = { + .name = "auth", +}; + +struct authtest_input { + pool_t pool; + const char *username; + const char *master_user; + const char *password; + struct auth_user_info info; + bool success; + + struct auth_client_request *request; + struct master_auth_request master_auth_req; + + unsigned int auth_id; + unsigned int auth_pid; + const char *auth_cookie; + +}; + +static void auth_cmd_help(struct doveadm_cmd_context *cctx); + +static struct auth_master_connection * +doveadm_get_auth_master_conn(const char *auth_socket_path) +{ + enum auth_master_flags flags = 0; + + if (doveadm_debug) + flags |= AUTH_MASTER_FLAG_DEBUG; + return auth_master_init(auth_socket_path, flags); +} + +static int +cmd_user_input(struct auth_master_connection *conn, + const struct authtest_input *input, + const char *show_field, bool userdb) +{ + const char *lookup_name = userdb ? "userdb lookup" : "passdb lookup"; + pool_t pool; + const char *updated_username = NULL, *const *fields, *p; + int ret; + + pool = pool_alloconly_create("auth master lookup", 1024); + + if (userdb) { + ret = auth_master_user_lookup(conn, input->username, &input->info, + pool, &updated_username, &fields); + } else { + ret = auth_master_pass_lookup(conn, input->username, &input->info, + pool, &fields); + } + if (ret < 0) { + if (fields[0] == NULL) + i_error("%s failed for %s", lookup_name, input->username); + else { + i_error("%s failed for %s: %s", lookup_name, + input->username, fields[0]); + } + ret = -1; + } else if (ret == 0) { + fprintf(show_field == NULL ? stdout : stderr, + "%s: user %s doesn't exist\n", lookup_name, + input->username); + } else if (show_field != NULL) { + size_t show_field_len = strlen(show_field); + + for (; *fields != NULL; fields++) { + if (strncmp(*fields, show_field, show_field_len) == 0 && + (*fields)[show_field_len] == '=') + printf("%s\n", *fields + show_field_len + 1); + } + } else { + printf("%s: %s\n", userdb ? "userdb" : "passdb", input->username); + + if (updated_username != NULL) + printf(" %-10s: %s\n", "user", updated_username); + for (; *fields != NULL; fields++) { + p = strchr(*fields, '='); + if (p == NULL) + printf(" %-10s\n", *fields); + else { + printf(" %-10s: %s\n", + t_strcut(*fields, '='), p + 1); + } + } + } + pool_unref(&pool); + return ret; +} + +static void +auth_callback(struct auth_client_request *request ATTR_UNUSED, + enum auth_request_status status, + const char *data_base64 ATTR_UNUSED, + const char *const *args, void *context) +{ + struct authtest_input *input = context; + + input->request = NULL; + input->auth_id = auth_client_request_get_id(request); + input->auth_pid = auth_client_request_get_server_pid(request); + input->auth_cookie = input->pool == NULL ? NULL : + p_strdup(input->pool, auth_client_request_get_cookie(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(); + case AUTH_REQUEST_STATUS_INTERNAL_FAIL: + case AUTH_REQUEST_STATUS_FAIL: + 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; + case AUTH_REQUEST_STATUS_OK: + input->success = TRUE; + printf("passdb: %s auth succeeded\n", input->username); + break; + } + + if (args != NULL && *args != NULL) { + printf("extra fields:\n"); + for (; *args != NULL; args++) + printf(" %s\n", *args); + } + io_loop_stop(current_ioloop); +} + +static void auth_connected(struct auth_client *client, + bool connected, void *context) +{ + struct event *event_auth; + struct authtest_input *input = context; + struct auth_request_info info; + string_t *init_resp, *base64_resp; + + if (!connected) + i_fatal("Couldn't connect to auth socket"); + event_auth = event_create(NULL); + event_add_category(event_auth, &event_category_auth); + + 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); + + i_zero(&info); + info.mech = "PLAIN"; + info.service = input->info.service; + info.session_id = input->info.session_id; + info.local_name = input->info.local_name; + info.local_ip = input->info.local_ip; + info.local_port = input->info.local_port; + info.remote_ip = input->info.remote_ip; + info.remote_port = input->info.remote_port; + info.real_local_ip = input->info.real_local_ip; + info.real_remote_ip = input->info.real_remote_ip; + info.real_local_port = input->info.real_local_port; + 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); + if (doveadm_settings->auth_debug || + event_want_debug_log(event_auth)) + info.flags |= AUTH_REQUEST_FLAG_DEBUG; + + input->request = auth_client_request_new(client, &info, + auth_callback, input); + event_unref(&event_auth); +} + +static void +cmd_auth_input(const char *auth_socket_path, struct authtest_input *input) +{ + struct auth_client *client; + + if (auth_socket_path == NULL) { + auth_socket_path = t_strconcat(doveadm_settings->base_dir, + "/auth-client", NULL); + } + + client = auth_client_init(auth_socket_path, getpid(), FALSE); + auth_client_connect(client); + auth_client_set_connect_notify(client, auth_connected, input); + + if (!auth_client_is_disconnected(client)) + io_loop_run(current_ioloop); + + auth_client_set_connect_notify(client, NULL, NULL); + auth_client_deinit(&client); +} + +static void +auth_user_info_parse_arg(struct auth_user_info *info, const char *arg) +{ + if (str_begins(arg, "service=")) + info->service = arg + 8; + else if (str_begins(arg, "session=")) + info->session_id = arg + 8; + else if (str_begins(arg, "local_name=")) + info->local_name = arg + 11; + else if (str_begins(arg, "lip=")) { + if (net_addr2ip(arg + 4, &info->local_ip) < 0) + i_fatal("lip: Invalid ip"); + } else if (str_begins(arg, "rip=")) { + if (net_addr2ip(arg + 4, &info->remote_ip) < 0) + i_fatal("rip: Invalid ip"); + } else if (str_begins(arg, "lport=")) { + if (net_str2port(arg + 6, &info->local_port) < 0) + i_fatal("lport: Invalid port number"); + } else if (str_begins(arg, "rport=")) { + if (net_str2port(arg + 6, &info->remote_port) < 0) + i_fatal("rport: Invalid port number"); + } else if (str_begins(arg, "real_lip=")) { + if (net_addr2ip(arg + 9, &info->real_local_ip) < 0) + i_fatal("real_lip: Invalid ip"); + } else if (str_begins(arg, "real_rip=")) { + if (net_addr2ip(arg + 9, &info->real_remote_ip) < 0) + i_fatal("real_rip: Invalid ip"); + } else if (str_begins(arg, "real_lport=")) { + if (net_str2port(arg + 11, &info->real_local_port) < 0) + i_fatal("real_lport: Invalid port number"); + } else if (str_begins(arg, "real_rport=")) { + if (net_str2port(arg + 11, &info->real_remote_port) < 0) + i_fatal("real_rport: Invalid port number"); + } else if (str_begins(arg, "forward_")) { + const char *key = arg+8; + const char *value = strchr(arg+8, '='); + + if (value == NULL) + value = ""; + else + key = t_strdup_until(key, value++); + key = str_tabescape(key); + value = str_tabescape(value); + if (info->forward_fields == NULL) { + info->forward_fields = + t_strdup_printf("%s=%s", key, value); + } else { + info->forward_fields = + t_strdup_printf("%s\t%s=%s", info->forward_fields, key, value); + } + } else { + if (!array_is_created(&info->extra_fields)) + t_array_init(&info->extra_fields, 4); + array_push_back(&info->extra_fields, &arg); + } +} + +static void +auth_user_info_parse(struct auth_user_info *info, const char *const *args) +{ + for (unsigned int i = 0; args[i] != NULL; i++) + auth_user_info_parse_arg(info, args[i]); +} + +static void +cmd_user_list(struct auth_master_connection *conn, + const struct authtest_input *input, + const char *const *users) +{ + struct auth_master_user_list_ctx *ctx; + const char *username, *user_mask = "*"; + unsigned int i; + + if (users[0] != NULL && users[1] == NULL) + user_mask = users[0]; + + ctx = auth_master_user_list_init(conn, user_mask, &input->info); + while ((username = auth_master_user_list_next(ctx)) != NULL) { + for (i = 0; users[i] != NULL; i++) { + if (wildcard_match_icase(username, users[i])) + break; + } + if (users[i] != NULL) + printf("%s\n", username); + } + if (auth_master_user_list_deinit(&ctx) < 0) + i_fatal("user listing failed"); +} + +static void cmd_auth_cache_flush(struct doveadm_cmd_context *cctx) +{ + const char *master_socket_path; + struct auth_master_connection *conn; + const char *const *users = NULL; + unsigned int count; + + if (!doveadm_cmd_param_str(cctx, "socket-path", &master_socket_path)) { + master_socket_path = t_strconcat(doveadm_settings->base_dir, + "/auth-master", NULL); + } + (void)doveadm_cmd_param_array(cctx, "user", &users); + + conn = doveadm_get_auth_master_conn(master_socket_path); + if (auth_master_cache_flush(conn, users, &count) < 0) { + i_error("Cache flush failed"); + doveadm_exit_code = EX_TEMPFAIL; + } else { + printf("%u cache entries flushed\n", count); + } + auth_master_deinit(&conn); +} + +static void authtest_input_init(struct authtest_input *input) +{ + i_zero(input); + input->info.service = "doveadm"; + input->info.debug = doveadm_settings->auth_debug; +} + +static void cmd_auth_test(struct doveadm_cmd_context *cctx) +{ + const char *auth_socket_path = NULL; + const char *const *auth_info; + struct authtest_input input; + + 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); + 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)) + auth_cmd_help(cctx); + if (!doveadm_cmd_param_str(cctx, "password", &input.password)) + input.password = t_askpass("Password: "); + cmd_auth_input(auth_socket_path, &input); + if (!input.success) + doveadm_exit_code = EX_NOPERM; +} + +static void +master_auth_callback(const char *const *auth_args, + const char *errormsg, void *context) +{ + struct authtest_input *input = context; + unsigned int i; + + io_loop_stop(current_ioloop); + if (errormsg != NULL) { + i_error("userdb lookup failed: %s", errormsg); + return; + } + printf("userdb extra fields:\n"); + for (i = 0; auth_args[i] != NULL; i++) + printf(" %s\n", auth_args[i]); + input->success = TRUE; +} + +static void +cmd_auth_master_input(const char *auth_master_socket_path, + struct authtest_input *input) +{ + struct master_login_auth *master_auth; + struct master_auth_request master_auth_req; + buffer_t buf; + + i_zero(&master_auth_req); + master_auth_req.tag = 1; + master_auth_req.auth_pid = input->auth_pid; + master_auth_req.auth_id = input->auth_id; + master_auth_req.client_pid = getpid(); + master_auth_req.local_ip = input->info.local_ip; + master_auth_req.remote_ip = input->info.remote_ip; + + buffer_create_from_data(&buf, master_auth_req.cookie, + sizeof(master_auth_req.cookie)); + if (strlen(input->auth_cookie) == MASTER_AUTH_COOKIE_SIZE*2) + (void)hex_to_binary(input->auth_cookie, &buf); + + input->success = FALSE; + master_auth = master_login_auth_init(auth_master_socket_path, FALSE); + io_loop_set_running(current_ioloop); + master_login_auth_request(master_auth, &master_auth_req, + master_auth_callback, input); + if (io_loop_is_running(current_ioloop)) + io_loop_run(current_ioloop); + master_login_auth_deinit(&master_auth); +} + +static void cmd_auth_login(struct doveadm_cmd_context *cctx) +{ + const char *auth_login_socket_path, *auth_master_socket_path; + const char *const *auth_info; + struct auth_client *auth_client; + struct authtest_input input; + + authtest_input_init(&input); + if (!doveadm_cmd_param_str(cctx, "auth-login-socket-path", + &auth_login_socket_path)) { + auth_login_socket_path = + t_strconcat(doveadm_settings->base_dir, + "/auth-login", NULL); + } + if (!doveadm_cmd_param_str(cctx, "auth-master-socket-path", + &auth_master_socket_path)) { + auth_master_socket_path = + t_strconcat(doveadm_settings->base_dir, + "/auth-master", NULL); + } + (void)doveadm_cmd_param_str(cctx, "master-user", &input.master_user); + 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)) + auth_cmd_help(cctx); + if (!doveadm_cmd_param_str(cctx, "password", &input.password)) + input.password = t_askpass("Password: "); + + input.pool = pool_alloconly_create("auth login", 256); + /* authenticate */ + auth_client = auth_client_init(auth_login_socket_path, getpid(), FALSE); + auth_client_connect(auth_client); + auth_client_set_connect_notify(auth_client, auth_connected, &input); + if (!auth_client_is_disconnected(auth_client)) + io_loop_run(current_ioloop); + auth_client_set_connect_notify(auth_client, NULL, NULL); + /* finish login with userdb lookup */ + if (input.success) + cmd_auth_master_input(auth_master_socket_path, &input); + if (!input.success) + doveadm_exit_code = EX_NOPERM; + auth_client_deinit(&auth_client); + pool_unref(&input.pool); +} + +static void cmd_auth_lookup(struct doveadm_cmd_context *cctx) +{ + const char *auth_socket_path; + struct auth_master_connection *conn; + struct authtest_input input; + const char *show_field = NULL; + const char *const *auth_info, *const *users; + bool first = TRUE; + int ret; + + authtest_input_init(&input); + if (!doveadm_cmd_param_str(cctx, "socket-path", &auth_socket_path)) + auth_socket_path = doveadm_settings->auth_socket_path; + (void)doveadm_cmd_param_str(cctx, "field", &show_field); + if (doveadm_cmd_param_array(cctx, "auth-info", &auth_info)) + auth_user_info_parse(&input.info, auth_info); + if (!doveadm_cmd_param_array(cctx, "user", &users)) + auth_cmd_help(cctx); + + conn = doveadm_get_auth_master_conn(auth_socket_path); + for (unsigned int i = 0; users[i] != NULL; i++) { + input.username = users[i]; + if (first) + first = FALSE; + else + putchar('\n'); + + ret = cmd_user_input(conn, &input, show_field, FALSE); + switch (ret) { + case -1: + doveadm_exit_code = EX_TEMPFAIL; + break; + case 0: + doveadm_exit_code = EX_NOUSER; + break; + } + } + auth_master_deinit(&conn); +} + +static void cmd_user_mail_input_field(const char *key, const char *value, + const char *show_field) +{ + if (show_field == NULL) { + doveadm_print(key); + doveadm_print(value); + } else if (strcmp(show_field, key) == 0) { + printf("%s\n", value); + } +} + +static void +cmd_user_mail_print_fields(const struct authtest_input *input, + struct mail_user *user, + const char *const *userdb_fields, + const char *show_field) +{ + const struct mail_storage_settings *mail_set; + const char *key, *value; + unsigned int i; + + if (strcmp(input->username, user->username) != 0) + cmd_user_mail_input_field("user", user->username, show_field); + cmd_user_mail_input_field("uid", user->set->mail_uid, show_field); + cmd_user_mail_input_field("gid", user->set->mail_gid, show_field); + cmd_user_mail_input_field("home", user->set->mail_home, show_field); + + mail_set = mail_user_set_get_storage_set(user); + cmd_user_mail_input_field("mail", mail_set->mail_location, show_field); + + if (userdb_fields != NULL) { + for (i = 0; userdb_fields[i] != NULL; i++) { + value = strchr(userdb_fields[i], '='); + if (value != NULL) + key = t_strdup_until(userdb_fields[i], value++); + else { + key = userdb_fields[i]; + value = ""; + } + if (strcmp(key, "uid") != 0 && + strcmp(key, "gid") != 0 && + strcmp(key, "home") != 0 && + strcmp(key, "mail") != 0) + cmd_user_mail_input_field(key, value, show_field); + } + } +} + +static int +cmd_user_mail_input(struct mail_storage_service_ctx *storage_service, + const struct authtest_input *input, + const char *show_field, const char *expand_field) +{ + struct mail_storage_service_input service_input; + struct mail_storage_service_user *service_user; + struct mail_user *user; + const char *error, *const *userdb_fields; + pool_t pool; + int ret; + + i_zero(&service_input); + service_input.module = "mail"; + service_input.service = input->info.service; + service_input.username = input->username; + service_input.local_ip = input->info.local_ip; + service_input.local_port = input->info.local_port; + service_input.remote_ip = input->info.remote_ip; + service_input.remote_port = input->info.remote_port; + service_input.debug = input->info.debug; + + pool = pool_alloconly_create("userdb fields", 1024); + mail_storage_service_save_userdb_fields(storage_service, pool, + &userdb_fields); + + if ((ret = mail_storage_service_lookup_next(storage_service, &service_input, + &service_user, &user, + &error)) <= 0) { + pool_unref(&pool); + if (ret < 0) + return -1; + fprintf(show_field == NULL && expand_field == NULL ? stdout : stderr, + "\nuserdb lookup: user %s doesn't exist\n", + input->username); + return 0; + } + + if (expand_field == NULL) + cmd_user_mail_print_fields(input, user, userdb_fields, show_field); + else { + string_t *str = t_str_new(128); + if (var_expand_with_funcs(str, expand_field, + mail_user_var_expand_table(user), + mail_user_var_expand_func_table, user, + &error) <= 0) { + i_error("Failed to expand %s: %s", expand_field, error); + } else { + printf("%s\n", str_c(str)); + } + } + + mail_user_deinit(&user); + mail_storage_service_user_unref(&service_user); + pool_unref(&pool); + return 1; +} + +static void cmd_user(struct doveadm_cmd_context *cctx) +{ + const char *auth_socket_path; + struct auth_master_connection *conn; + struct authtest_input input; + const char *show_field = NULL, *expand_field = NULL; + const char *const *user_masks, *const *auth_info; + struct mail_storage_service_ctx *storage_service = NULL; + unsigned int i; + bool have_wildcards, userdb_only = FALSE, first = TRUE; + int ret; + + authtest_input_init(&input); + if (!doveadm_cmd_param_str(cctx, "socket-path", &auth_socket_path)) + auth_socket_path = doveadm_settings->auth_socket_path; + (void)doveadm_cmd_param_str(cctx, "field", &show_field); + (void)doveadm_cmd_param_str(cctx, "expand-field", &expand_field); + (void)doveadm_cmd_param_bool(cctx, "userdb-only", &userdb_only); + if (doveadm_cmd_param_array(cctx, "auth-info", &auth_info)) + auth_user_info_parse(&input.info, auth_info); + if (!doveadm_cmd_param_array(cctx, "user-mask", &user_masks)) + auth_cmd_help(cctx); + + if (expand_field != NULL && userdb_only) { + i_error("-e can't be used with -u"); + doveadm_exit_code = EX_USAGE; + return; + } + if (expand_field != NULL && show_field != NULL) { + i_error("-e can't be used with -f"); + doveadm_exit_code = EX_USAGE; + return; + } + + conn = doveadm_get_auth_master_conn(auth_socket_path); + + have_wildcards = FALSE; + for (i = 0; user_masks[i] != NULL; i++) { + if (strchr(user_masks[i], '*') != NULL || + strchr(user_masks[i], '?') != NULL) { + have_wildcards = TRUE; + break; + } + } + + if (have_wildcards) { + cmd_user_list(conn, &input, user_masks); + auth_master_deinit(&conn); + return; + } + + if (!userdb_only) { + storage_service = mail_storage_service_init(master_service, NULL, + MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP | + MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR | + MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT | + MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS | + MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES | + MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS); + mail_storage_service_set_auth_conn(storage_service, conn); + conn = NULL; + if (show_field == NULL && expand_field == NULL) { + doveadm_print_init(DOVEADM_PRINT_TYPE_TAB); + doveadm_print_header_simple("field"); + doveadm_print_header_simple("value"); + } + } + + for (i = 0; user_masks[i] != NULL; i++) { + input.username = user_masks[i]; + if (first) + first = FALSE; + else + putchar('\n'); + + ret = !userdb_only ? + cmd_user_mail_input(storage_service, &input, show_field, expand_field) : + cmd_user_input(conn, &input, show_field, TRUE); + switch (ret) { + case -1: + doveadm_exit_code = EX_TEMPFAIL; + break; + case 0: + doveadm_exit_code = EX_NOUSER; + break; + } + } + if (storage_service != NULL) + mail_storage_service_deinit(&storage_service); + if (conn != NULL) + auth_master_deinit(&conn); +} + +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>]", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_PARAM('a', "socket-path", 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) +DOVEADM_CMD_PARAM('\0', "password", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +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>]", +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('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) +DOVEADM_CMD_PARAM('\0', "password", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}, +{ + .cmd = cmd_auth_lookup, + .name = "auth lookup", + .usage = "[-a <userdb socket path>] [-x <auth info>] [-f field] <user> [<user> [...]]", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_PARAM('a', "socket-path", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('x', "auth-info", CMD_PARAM_ARRAY, 0) +DOVEADM_CMD_PARAM('f', "field", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('\0', "user", CMD_PARAM_ARRAY, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}, +{ + .cmd = cmd_auth_cache_flush, + .name = "auth cache flush", + .usage = "[-a <master socket path>] [<user> [...]]", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_PARAM('a', "socket-path", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('\0', "user", CMD_PARAM_ARRAY, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}, +{ + .cmd = cmd_user, + .name = "user", + .usage = "[-a <userdb socket path>] [-x <auth info>] [-f field] [-e <value>] [-u] <user mask> [<user mask> [...]]", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_PARAM('a', "socket-path", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('x', "auth-info", CMD_PARAM_ARRAY, 0) +DOVEADM_CMD_PARAM('f', "field", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('e', "expand-field", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('u', "userdb-only", CMD_PARAM_BOOL, 0) +DOVEADM_CMD_PARAM('\0', "user-mask", CMD_PARAM_ARRAY, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +} +}; + +static void auth_cmd_help(struct doveadm_cmd_context *cctx) +{ + unsigned int i; + + for (i = 0; i < N_ELEMENTS(doveadm_cmd_auth); i++) { + if (doveadm_cmd_auth[i].cmd == cctx->cmd->cmd) + help_ver2(&doveadm_cmd_auth[i]); + } + i_unreached(); +} + +void doveadm_register_auth_commands(void) +{ + unsigned int i; + + for (i = 0; i < N_ELEMENTS(doveadm_cmd_auth); i++) + doveadm_cmd_register_ver2(&doveadm_cmd_auth[i]); +} |