Mercurial > dovecot > core-2.2
view src/doveadm/doveadm-kick.c @ 18137:3009a1a6f6d5
global: freshen copyright
Robomatically:
git ls-files | xargs perl -p -i -e 's/(\d+)-201[0-4]/$1-2015/g;s/ (201[0-4]) Dovecot/ $1-2015 Dovecot/'
Happy 2015 everyone!
Signed-off-by: Phil Carmody <phil@dovecot.fi>
author | Phil Carmody <phil@dovecot.fi> |
---|---|
date | Mon, 05 Jan 2015 22:20:10 +0200 |
parents | add8c00fb3cc |
children | 9e120590e0ef |
line wrap: on
line source
/* Copyright (c) 2010-2015 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "array.h" #include "net.h" #include "hash.h" #include "doveadm.h" #include "doveadm-who.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <signal.h> struct kick_user { const char *username; bool kick_me; /* true if username and/or ip[/mask] matches. ignored when the -f switch is given. */ }; struct kick_pid { pid_t pid; ARRAY(struct kick_user) users; bool kick; }; struct kick_context { struct who_context who; HASH_TABLE(void *, struct kick_pid *) pids; bool force_kick; ARRAY(const char *) kicked_users; }; static void kick_aggregate_line(struct who_context *_ctx, const struct who_line *line) { struct kick_context *ctx = (struct kick_context *)_ctx; const bool user_match = who_line_filter_match(line, &ctx->who.filter); struct kick_pid *k_pid; struct kick_user new_user, *user; memset(&new_user, 0, sizeof(new_user)); k_pid = hash_table_lookup(ctx->pids, POINTER_CAST(line->pid)); if (k_pid == NULL) { k_pid = p_new(ctx->who.pool, struct kick_pid, 1); k_pid->pid = line->pid; p_array_init(&k_pid->users, ctx->who.pool, 5); hash_table_insert(ctx->pids, POINTER_CAST(line->pid), k_pid); } array_foreach_modifiable(&k_pid->users, user) { if (strcmp(line->username, user->username) == 0) { if (user_match) user->kick_me = TRUE; return; } } new_user.username = p_strdup(ctx->who.pool, line->username); new_user.kick_me = user_match; array_append(&k_pid->users, &new_user, 1); } static bool kick_pid_want_kicked(struct kick_context *ctx, const struct kick_pid *k_pid, bool *show_warning) { unsigned int kick_count = 0; const struct kick_user *user; if (array_count(&k_pid->users) == 1) { user = array_idx(&k_pid->users, 0); if (!user->kick_me) return FALSE; } else { array_foreach(&k_pid->users, user) { if (user->kick_me) kick_count++; } if (kick_count == 0) return FALSE; if (kick_count < array_count(&k_pid->users) && !ctx->force_kick) { array_foreach(&k_pid->users, user) { if (!user->kick_me) { array_append(&ctx->kicked_users, &user->username, 1); } } *show_warning = TRUE; return FALSE; } } return TRUE; } static void kick_print_kicked(struct kick_context *ctx, const bool show_warning) { unsigned int i, count; const char *const *users; if (array_count(&ctx->kicked_users) == 0) { printf("no users kicked\n"); doveadm_exit_code = DOVEADM_EX_NOTFOUND; return; } if (show_warning) { printf("warning: other connections would also be " "kicked from following users:\n"); } else printf("kicked connections from the following users:\n"); array_sort(&ctx->kicked_users, i_strcmp_p); users = array_get(&ctx->kicked_users, &count); printf("%s ", users[0]); for (i = 1; i < count; i++) { if (strcmp(users[i-1], users[i]) != 0) printf("%s ", users[i]); } printf("\n"); if (show_warning) printf("Use the '-f' option to enforce the disconnect.\n"); } static void kick_users(struct kick_context *ctx) { bool show_enforce_warning = FALSE; struct hash_iterate_context *iter; void *key; struct kick_pid *k_pid; const struct kick_user *user; p_array_init(&ctx->kicked_users, ctx->who.pool, 10); iter = hash_table_iterate_init(ctx->pids); while (hash_table_iterate(iter, ctx->pids, &key, &k_pid)) { if (kick_pid_want_kicked(ctx, k_pid, &show_enforce_warning)) k_pid->kick = TRUE; } hash_table_iterate_deinit(&iter); if (show_enforce_warning) { kick_print_kicked(ctx, show_enforce_warning); return; } iter = hash_table_iterate_init(ctx->pids); while (hash_table_iterate(iter, ctx->pids, &key, &k_pid)) { if (!k_pid->kick) continue; if (kill(k_pid->pid, SIGTERM) < 0 && errno != ESRCH) { fprintf(stderr, "kill(%s, SIGTERM) failed: %m\n", dec2str(k_pid->pid)); } else { array_foreach(&k_pid->users, user) { array_append(&ctx->kicked_users, &user->username, 1); } } } hash_table_iterate_deinit(&iter); kick_print_kicked(ctx, show_enforce_warning); } static void cmd_kick(int argc, char *argv[]) { struct kick_context ctx; int c; memset(&ctx, 0, sizeof(ctx)); ctx.who.anvil_path = t_strconcat(doveadm_settings->base_dir, "/anvil", NULL); ctx.force_kick = FALSE; ctx.who.pool = pool_alloconly_create("kick pids", 10240); hash_table_create_direct(&ctx.pids, ctx.who.pool, 0); while ((c = getopt(argc, argv, "a:f")) > 0) { switch (c) { case 'a': ctx.who.anvil_path = optarg; break; case 'f': ctx.force_kick = TRUE; break; default: help(&doveadm_cmd_kick); } } argv += optind - 1; if (argv[1] == NULL) { i_fatal_status(EX_USAGE, "user and/or ip[/bits] must be specified."); } who_parse_args(&ctx.who, argv); who_lookup(&ctx.who, kick_aggregate_line); kick_users(&ctx); hash_table_destroy(&ctx.pids); pool_unref(&ctx.who.pool); } struct doveadm_cmd doveadm_cmd_kick = { cmd_kick, "kick", "[-a <anvil socket path>] [-f] <user mask>[|]<ip/bits>" };