summaryrefslogtreecommitdiffstats
path: root/src/doveadm/doveadm-proxy.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
commitf7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch)
treea3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/doveadm/doveadm-proxy.c
parentInitial commit. (diff)
downloaddovecot-upstream.tar.xz
dovecot-upstream.zip
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/doveadm/doveadm-proxy.c')
-rw-r--r--src/doveadm/doveadm-proxy.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/doveadm/doveadm-proxy.c b/src/doveadm/doveadm-proxy.c
new file mode 100644
index 0000000..04fde52
--- /dev/null
+++ b/src/doveadm/doveadm-proxy.c
@@ -0,0 +1,214 @@
+/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "str.h"
+#include "strescape.h"
+#include "ipc-client.h"
+#include "doveadm.h"
+#include "doveadm-print.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+struct proxy_context {
+ struct ipc_client *ipc;
+ const char *username_field;
+ const char *kick_hosts;
+};
+
+extern struct doveadm_cmd_ver2 doveadm_cmd_proxy[];
+
+static void proxy_cmd_help(struct doveadm_cmd_context *cctx) ATTR_NORETURN;
+
+static struct proxy_context *
+cmd_proxy_init(struct doveadm_cmd_context *cctx)
+{
+ struct proxy_context *ctx;
+ const char *socket_path;
+
+ ctx = t_new(struct proxy_context, 1);
+ if (!doveadm_cmd_param_str(cctx, "socket-path", &socket_path)) {
+ socket_path = t_strconcat(doveadm_settings->base_dir,
+ "/ipc", NULL);
+ }
+ (void)doveadm_cmd_param_str(cctx, "passdb-field", &ctx->username_field);
+ (void)doveadm_cmd_param_str(cctx, "host", &ctx->kick_hosts);
+ ctx->ipc = ipc_client_init(socket_path);
+ return ctx;
+}
+
+static void cmd_proxy_list_header(const char *const *args)
+{
+ struct {
+ const char *key;
+ const char *title;
+ } header_map[] = {
+ { "service", "proto" },
+ { "src-ip", "src ip" },
+ { "dest-ip", "dest ip" },
+ { "dest-port", "port" },
+ };
+ for (unsigned int i = 0; args[i] != NULL; i++) {
+ const char *arg = args[i];
+
+ if (strcmp(arg, "username") == 0 ||
+ str_begins(arg, "user_")) {
+ doveadm_print_header(arg, arg,
+ DOVEADM_PRINT_HEADER_FLAG_EXPAND);
+ continue;
+ }
+ const char *title = arg;
+ for (unsigned int j = 0; j < N_ELEMENTS(header_map); j++) {
+ if (strcmp(header_map[j].key, arg) == 0) {
+ title = header_map[j].title;
+ break;
+ }
+ }
+ doveadm_print_header(arg, title, 0);
+ }
+}
+
+static void cmd_proxy_list_callback(enum ipc_client_cmd_state state,
+ const char *data, void *context)
+{
+ bool *seen_header = context;
+
+ switch (state) {
+ case IPC_CLIENT_CMD_STATE_REPLY: {
+ const char *const *args = t_strsplit_tabescaped(data);
+
+ if (!*seen_header) {
+ cmd_proxy_list_header(args);
+ *seen_header = TRUE;
+ } else {
+ for (; *args != NULL; args++)
+ doveadm_print(*args);
+ }
+ return;
+ }
+ case IPC_CLIENT_CMD_STATE_OK:
+ break;
+ case IPC_CLIENT_CMD_STATE_ERROR:
+ i_error("LIST-FULL failed: %s", data);
+ break;
+ }
+ io_loop_stop(current_ioloop);
+}
+
+static void cmd_proxy_list(struct doveadm_cmd_context *cctx)
+{
+ struct proxy_context *ctx;
+ bool seen_header = FALSE;
+
+ ctx = cmd_proxy_init(cctx);
+
+ doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
+
+ io_loop_set_running(current_ioloop);
+ ipc_client_cmd(ctx->ipc, "proxy\t*\tLIST-FULL",
+ cmd_proxy_list_callback, &seen_header);
+ if (io_loop_is_running(current_ioloop))
+ io_loop_run(current_ioloop);
+ ipc_client_deinit(&ctx->ipc);
+}
+
+static void cmd_proxy_kick_callback(enum ipc_client_cmd_state state,
+ const char *data, void *context ATTR_UNUSED)
+{
+ switch (state) {
+ case IPC_CLIENT_CMD_STATE_REPLY:
+ return;
+ case IPC_CLIENT_CMD_STATE_OK:
+ if (data[0] == '\0')
+ data = "0";
+ doveadm_print(data);
+ break;
+ case IPC_CLIENT_CMD_STATE_ERROR:
+ i_error("KICK failed: %s", data);
+ doveadm_exit_code = EX_TEMPFAIL;
+ break;
+ }
+ io_loop_stop(current_ioloop);
+}
+
+static void cmd_proxy_kick(struct doveadm_cmd_context *cctx)
+{
+ struct proxy_context *ctx;
+ const char *const *users = NULL;
+ string_t *cmd;
+
+ ctx = cmd_proxy_init(cctx);
+ (void)doveadm_cmd_param_array(cctx, "user", &users);
+ if (users == NULL && ctx->kick_hosts == NULL) {
+ proxy_cmd_help(cctx);
+ return;
+ }
+
+ doveadm_print_init(DOVEADM_PRINT_TYPE_FORMATTED);
+ doveadm_print_formatted_set_format("%{count} connections kicked\n");
+ doveadm_print_header_simple("count");
+
+ cmd = t_str_new(128);
+ str_append(cmd, "proxy\t*\t");
+ if (ctx->kick_hosts != NULL) {
+ str_append(cmd, "KICK-HOST\t");
+ str_append(cmd, ctx->kick_hosts);
+ }
+ else if (ctx->username_field == NULL)
+ str_append(cmd, "KICK");
+ else {
+ str_append(cmd, "KICK-ALT\t");
+ str_append_tabescaped(cmd, ctx->username_field);
+ }
+ if (users != NULL) {
+ for (unsigned int i = 0; users[i] != NULL; i++) {
+ str_append_c(cmd, '\t');
+ str_append_tabescaped(cmd, users[i]);
+ }
+ }
+ ipc_client_cmd(ctx->ipc, str_c(cmd), cmd_proxy_kick_callback, NULL);
+ io_loop_run(current_ioloop);
+ ipc_client_deinit(&ctx->ipc);
+}
+
+struct doveadm_cmd_ver2 doveadm_cmd_proxy[] = {
+{
+ .name = "proxy list",
+ .usage = "[-a <ipc socket path>]",
+ .cmd = cmd_proxy_list,
+DOVEADM_CMD_PARAMS_START
+DOVEADM_CMD_PARAM('a', "socket-path", CMD_PARAM_STR, 0)
+DOVEADM_CMD_PARAMS_END
+},
+{
+ .name = "proxy kick",
+ .usage = "[-a <ipc socket path>] [-f <passdb field>] [-h <host> [...] | <user> [...]]",
+ .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('h', "host", CMD_PARAM_STR, 0)
+DOVEADM_CMD_PARAM('\0', "user", CMD_PARAM_ARRAY, CMD_PARAM_FLAG_POSITIONAL)
+DOVEADM_CMD_PARAMS_END
+}
+};
+
+static void proxy_cmd_help(struct doveadm_cmd_context *cctx)
+{
+ unsigned int i;
+
+ for (i = 0; i < N_ELEMENTS(doveadm_cmd_proxy); i++) {
+ if (doveadm_cmd_proxy[i].cmd == cctx->cmd->cmd)
+ help_ver2(&doveadm_cmd_proxy[i]);
+ }
+ i_unreached();
+}
+
+void doveadm_register_proxy_commands(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < N_ELEMENTS(doveadm_cmd_proxy); i++)
+ doveadm_cmd_register_ver2(&doveadm_cmd_proxy[i]);
+}