diff --git a/src/doveadm/doveadm-proxy.c b/src/doveadm/doveadm-proxy.c index aba622240e..b1d4761e05 100644 --- a/src/doveadm/doveadm-proxy.c +++ b/src/doveadm/doveadm-proxy.c @@ -2,6 +2,8 @@ #include "lib.h" #include "ioloop.h" +#include "str.h" +#include "strescape.h" #include "ipc-client.h" #include "doveadm.h" #include "doveadm-print.h" @@ -11,6 +13,7 @@ struct proxy_context { struct ipc_client *ipc; + const char *username_field; }; extern struct doveadm_cmd_ver2 doveadm_cmd_proxy[]; @@ -33,6 +36,9 @@ cmd_proxy_init(int argc, char *argv[], const char *getopt_args, case 'a': socket_path = optarg; break; + case 'f': + ctx->username_field = optarg; + break; default: proxy_cmd_help(cmd); } @@ -138,8 +144,9 @@ static void cmd_proxy_kick_callback(enum ipc_client_cmd_state state, static void cmd_proxy_kick(int argc, char *argv[]) { struct proxy_context *ctx; + string_t *cmd; - ctx = cmd_proxy_init(argc, argv, "a:", cmd_proxy_kick); + ctx = cmd_proxy_init(argc, argv, "a:f:", cmd_proxy_kick); if (argv[optind] == NULL) { proxy_cmd_help(cmd_proxy_kick); @@ -149,8 +156,18 @@ static void cmd_proxy_kick(int argc, char *argv[]) doveadm_print_init(DOVEADM_PRINT_TYPE_FORMATTED); doveadm_print_formatted_set_format("%{count} connections kicked"); doveadm_print_header_simple("count"); - ipc_client_cmd(ctx->ipc, t_strdup_printf("proxy\t*\tKICK\t%s", argv[optind]), - cmd_proxy_kick_callback, NULL); + + cmd = t_str_new(128); + str_append(cmd, "proxy\t*\t"); + if (ctx->username_field == NULL) + str_append(cmd, "KICK"); + else { + str_append(cmd, "KICK-ALT\t"); + str_append_tabescaped(cmd, ctx->username_field); + } + str_append_c(cmd, '\t'); + str_append_tabescaped(cmd, argv[optind]); + ipc_client_cmd(ctx->ipc, str_c(cmd), cmd_proxy_kick_callback, NULL); io_loop_run(current_ioloop); ipc_client_deinit(&ctx->ipc); } @@ -166,10 +183,11 @@ DOVEADM_CMD_PARAMS_END }, { .name = "proxy kick", - .usage = "[-a ] ", + .usage = "[-a ] [-f ] ", .old_cmd = cmd_proxy_kick, DOVEADM_CMD_PARAMS_START DOVEADM_CMD_PARAM('a', "socket-path", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('f', "passdb-field", CMD_PARAM_STR, 0) DOVEADM_CMD_PARAM('\0', "user", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAMS_END } diff --git a/src/login-common/login-proxy.c b/src/login-common/login-proxy.c index 8f587c26d0..0b87a09171 100644 --- a/src/login-common/login-proxy.c +++ b/src/login-common/login-proxy.c @@ -839,8 +839,32 @@ void login_proxy_kill_idle(void) } } +static bool +want_kick_virtual_user(struct client *client, const char *const *args, + unsigned int key_idx ATTR_UNUSED) +{ + return str_array_find(args, client->virtual_user); +} + +static bool +want_kick_alt_username(struct client *client, const char *const *args, + unsigned int key_idx) +{ + unsigned int i; + + if (client->alt_usernames == NULL) + return FALSE; + for (i = 0; i < key_idx; i++) { + if (client->alt_usernames[i] == NULL) + return FALSE; + } + return str_array_find(args, client->alt_usernames[i]); +} + static void -login_proxy_cmd_kick(struct ipc_cmd *cmd, const char *const *args) +login_proxy_cmd_kick_full(struct ipc_cmd *cmd, const char *const *args, + bool (*want_kick)(struct client *, const char *const *, + unsigned int), unsigned int key_idx) { struct login_proxy *proxy, *next; unsigned int count = 0; @@ -853,7 +877,7 @@ login_proxy_cmd_kick(struct ipc_cmd *cmd, const char *const *args) for (proxy = login_proxies; proxy != NULL; proxy = next) { next = proxy->next; - if (strcmp(proxy->client->virtual_user, args[0]) == 0) { + if (want_kick(proxy->client, args, key_idx)) { login_proxy_free_delayed(&proxy, KILLED_BY_ADMIN_REASON); count++; } @@ -861,7 +885,7 @@ login_proxy_cmd_kick(struct ipc_cmd *cmd, const char *const *args) for (proxy = login_proxies_pending; proxy != NULL; proxy = next) { next = proxy->next; - if (strcmp(proxy->client->virtual_user, args[0]) == 0) { + if (want_kick(proxy->client, args, key_idx)) { client_destroy(proxy->client, "Connection kicked"); count++; } @@ -869,6 +893,36 @@ login_proxy_cmd_kick(struct ipc_cmd *cmd, const char *const *args) ipc_cmd_success_reply(&cmd, t_strdup_printf("%u", count)); } +static void +login_proxy_cmd_kick(struct ipc_cmd *cmd, const char *const *args) +{ + login_proxy_cmd_kick_full(cmd, args, want_kick_virtual_user, 0); +} + +static void +login_proxy_cmd_kick_alt(struct ipc_cmd *cmd, const char *const *args) +{ + char *const *fields; + unsigned int i, count; + + if (args[0] == NULL) { + ipc_cmd_fail(&cmd, "Missing parameter"); + return; + } + fields = array_get(&global_alt_usernames, &count); + for (i = 0; i < count; i++) { + if (strcmp(fields[i], args[0]) == 0) + break; + } + if (i == count) { + /* field doesn't exist, but it's not an error necessarily */ + ipc_cmd_success_reply(&cmd, "0"); + return; + } + + login_proxy_cmd_kick_full(cmd, args+1, want_kick_alt_username, i); +} + static unsigned int director_username_hash(struct client *client) { return mail_user_hash(client->virtual_user, @@ -973,6 +1027,8 @@ static void login_proxy_ipc_cmd(struct ipc_cmd *cmd, const char *line) args++; if (strcmp(name, "KICK") == 0) login_proxy_cmd_kick(cmd, args); + else if (strcmp(name, "KICK-ALT") == 0) + login_proxy_cmd_kick_alt(cmd, args); else if (strcmp(name, "KICK-DIRECTOR-HASH") == 0) login_proxy_cmd_kick_director_hash(cmd, args); else if (strcmp(name, "LIST-FULL") == 0)