bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk#include "lib.h"
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk#include "array.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk#include "hash.h"
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk#include "doveadm.h"
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk#include "doveadm-who.h"
633a1bf10559b9a8d85bfab662fa2a7ba97d45baAki Tuomi#include "doveadm-print.h"
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk#include <stdio.h>
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk#include <unistd.h>
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk#include <sys/types.h>
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk#include <signal.h>
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volkstruct kick_user {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk const char *username;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk bool kick_me; /* true if username and/or ip[/mask] matches.
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk ignored when the -f switch is given. */
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk};
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volkstruct kick_pid {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk pid_t pid;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct kick_user) users;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk bool kick;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk};
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volkstruct kick_context {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk struct who_context who;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen HASH_TABLE(void *, struct kick_pid *) pids;
6fc40674e5a33787ae7fcd47a77a77ea20977994Aki Tuomi enum doveadm_client_type conn_type;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk bool force_kick;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(const char *) kicked_users;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk};
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volkstatic void
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volkkick_aggregate_line(struct who_context *_ctx, const struct who_line *line)
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk{
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk struct kick_context *ctx = (struct kick_context *)_ctx;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk const bool user_match = who_line_filter_match(line, &ctx->who.filter);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk struct kick_pid *k_pid;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk struct kick_user new_user, *user;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&new_user);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen k_pid = hash_table_lookup(ctx->pids, POINTER_CAST(line->pid));
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (k_pid == NULL) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk k_pid = p_new(ctx->who.pool, struct kick_pid, 1);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk k_pid->pid = line->pid;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk p_array_init(&k_pid->users, ctx->who.pool, 5);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_insert(ctx->pids, POINTER_CAST(line->pid), k_pid);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk array_foreach_modifiable(&k_pid->users, user) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (strcmp(line->username, user->username) == 0) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (user_match)
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk user->kick_me = TRUE;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk return;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk new_user.username = p_strdup(ctx->who.pool, line->username);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk new_user.kick_me = user_match;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk array_append(&k_pid->users, &new_user, 1);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk}
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volkstatic bool
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volkkick_pid_want_kicked(struct kick_context *ctx, const struct kick_pid *k_pid,
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk bool *show_warning)
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk{
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk unsigned int kick_count = 0;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk const struct kick_user *user;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (array_count(&k_pid->users) == 1) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk user = array_idx(&k_pid->users, 0);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (!user->kick_me)
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk return FALSE;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk } else {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk array_foreach(&k_pid->users, user) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (user->kick_me)
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk kick_count++;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (kick_count == 0)
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk return FALSE;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (kick_count < array_count(&k_pid->users) &&
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk !ctx->force_kick) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk array_foreach(&k_pid->users, user) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (!user->kick_me) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk array_append(&ctx->kicked_users,
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk &user->username, 1);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk *show_warning = TRUE;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk return FALSE;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk return TRUE;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk}
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volkstatic void
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volkkick_print_kicked(struct kick_context *ctx, const bool show_warning)
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk{
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk unsigned int i, count;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk const char *const *users;
6fc40674e5a33787ae7fcd47a77a77ea20977994Aki Tuomi bool cli = (ctx->conn_type == DOVEADM_CONNECTION_TYPE_CLI);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (array_count(&ctx->kicked_users) == 0) {
1b58508a918279d773ef32518f5d5d933023c252Stephan Bosch if (cli)
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi printf("no users kicked\n");
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk return;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
1b58508a918279d773ef32518f5d5d933023c252Stephan Bosch if (cli) {
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi if (show_warning) {
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi printf("warning: other connections would also be "
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi "kicked from following users:\n");
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi } else {
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi printf("kicked connections from the following users:\n");
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi }
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk array_sort(&ctx->kicked_users, i_strcmp_p);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk users = array_get(&ctx->kicked_users, &count);
633a1bf10559b9a8d85bfab662fa2a7ba97d45baAki Tuomi doveadm_print(users[0]);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk for (i = 1; i < count; i++) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (strcmp(users[i-1], users[i]) != 0)
633a1bf10559b9a8d85bfab662fa2a7ba97d45baAki Tuomi doveadm_print(users[i]);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
1b58508a918279d773ef32518f5d5d933023c252Stephan Bosch if (cli)
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi printf("\n");
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (show_warning)
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk printf("Use the '-f' option to enforce the disconnect.\n");
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk}
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volkstatic void kick_users(struct kick_context *ctx)
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk{
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk bool show_enforce_warning = FALSE;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk struct hash_iterate_context *iter;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen void *key;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct kick_pid *k_pid;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk const struct kick_user *user;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk p_array_init(&ctx->kicked_users, ctx->who.pool, 10);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk iter = hash_table_iterate_init(ctx->pids);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, ctx->pids, &key, &k_pid)) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (kick_pid_want_kicked(ctx, k_pid, &show_enforce_warning))
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk k_pid->kick = TRUE;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk hash_table_iterate_deinit(&iter);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (show_enforce_warning) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk kick_print_kicked(ctx, show_enforce_warning);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk return;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk iter = hash_table_iterate_init(ctx->pids);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, ctx->pids, &key, &k_pid)) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (!k_pid->kick)
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk continue;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk if (kill(k_pid->pid, SIGTERM) < 0 && errno != ESRCH) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk fprintf(stderr, "kill(%s, SIGTERM) failed: %m\n",
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk dec2str(k_pid->pid));
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk } else {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk array_foreach(&k_pid->users, user) {
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk array_append(&ctx->kicked_users,
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk &user->username, 1);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk hash_table_iterate_deinit(&iter);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk kick_print_kicked(ctx, show_enforce_warning);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk}
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomistatic void cmd_kick(struct doveadm_cmd_context *cctx)
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk{
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi const char *const *masks;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk struct kick_context ctx;
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&ctx);
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi if (!doveadm_cmd_param_str(cctx, "socket-path", &(ctx.who.anvil_path)))
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi ctx.who.anvil_path = t_strconcat(doveadm_settings->base_dir, "/anvil", NULL);
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi (void)doveadm_cmd_param_bool(cctx, "force", &(ctx.force_kick));
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi if (!doveadm_cmd_param_array(cctx, "mask", &masks)) {
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi doveadm_exit_code = EX_USAGE;
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi i_error("user and/or ip[/bits] must be specified.");
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi return;
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi }
1b58508a918279d773ef32518f5d5d933023c252Stephan Bosch ctx.conn_type = cctx->conn_type;
6fc40674e5a33787ae7fcd47a77a77ea20977994Aki Tuomi if (ctx.conn_type != DOVEADM_CONNECTION_TYPE_CLI) {
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi /* force-kick is a pretty ugly option. its output can't be
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi nicely translated to an API reply. it also wouldn't be very
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi useful in scripts, only for preventing a new admin from
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi accidentally kicking too many users. it's also useful only
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi in a non-recommended setup where processes are handling
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi multiple connections. so for now we'll preserve the option
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi for CLI, but always do a force-kick with non-CLI. */
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi ctx.force_kick = TRUE;
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk ctx.who.pool = pool_alloconly_create("kick pids", 10240);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create_direct(&ctx.pids, ctx.who.pool, 0);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi if (who_parse_args(&ctx.who, masks)!=0) {
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi hash_table_destroy(&ctx.pids);
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi pool_unref(&ctx.who.pool);
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi return;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen }
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
633a1bf10559b9a8d85bfab662fa2a7ba97d45baAki Tuomi doveadm_print_init(DOVEADM_PRINT_TYPE_FORMATTED);
633a1bf10559b9a8d85bfab662fa2a7ba97d45baAki Tuomi doveadm_print_formatted_set_format("%{result} ");
633a1bf10559b9a8d85bfab662fa2a7ba97d45baAki Tuomi doveadm_print_header_simple("result");
633a1bf10559b9a8d85bfab662fa2a7ba97d45baAki Tuomi
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk who_lookup(&ctx.who, kick_aggregate_line);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk kick_users(&ctx);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk hash_table_destroy(&ctx.pids);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk pool_unref(&ctx.who.pool);
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk}
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomistruct doveadm_cmd_ver2 doveadm_cmd_kick_ver2 = {
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi .name = "kick",
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi .cmd = cmd_kick,
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi .usage = "[-a <anvil socket path>] <user mask>[|]<ip/bits>",
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki TuomiDOVEADM_CMD_PARAMS_START
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki TuomiDOVEADM_CMD_PARAM('a',"socket-path",CMD_PARAM_STR,0)
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki TuomiDOVEADM_CMD_PARAM('f',"force",CMD_PARAM_BOOL,0)
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki TuomiDOVEADM_CMD_PARAM('\0',"mask",CMD_PARAM_ARRAY,CMD_PARAM_FLAG_POSITIONAL)
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki TuomiDOVEADM_CMD_PARAMS_END
381daab1e3b56a0bc94d2191cf62beba0df51af9Pascal Volk};