bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainen#include "lib.h"
02aedbc20af0160091670233383d228f10b168afTimo Sirainen#include "ioloop.h"
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen#include "str.h"
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen#include "strescape.h"
02aedbc20af0160091670233383d228f10b168afTimo Sirainen#include "ipc-client.h"
02aedbc20af0160091670233383d228f10b168afTimo Sirainen#include "doveadm.h"
02aedbc20af0160091670233383d228f10b168afTimo Sirainen#include "doveadm-print.h"
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainen#include <stdio.h>
02aedbc20af0160091670233383d228f10b168afTimo Sirainen#include <unistd.h>
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainenstruct proxy_context {
02aedbc20af0160091670233383d228f10b168afTimo Sirainen struct ipc_client *ipc;
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen const char *username_field;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen};
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomiextern struct doveadm_cmd_ver2 doveadm_cmd_proxy[];
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainenstatic void proxy_cmd_help(doveadm_command_t *cmd) ATTR_NORETURN;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainenstatic struct proxy_context *
02aedbc20af0160091670233383d228f10b168afTimo Sirainencmd_proxy_init(int argc, char *argv[], const char *getopt_args,
02aedbc20af0160091670233383d228f10b168afTimo Sirainen doveadm_command_t *cmd)
02aedbc20af0160091670233383d228f10b168afTimo Sirainen{
02aedbc20af0160091670233383d228f10b168afTimo Sirainen struct proxy_context *ctx;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen const char *socket_path;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen int c;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainen ctx = t_new(struct proxy_context, 1);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen socket_path = t_strconcat(doveadm_settings->base_dir, "/ipc", NULL);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainen while ((c = getopt(argc, argv, getopt_args)) > 0) {
02aedbc20af0160091670233383d228f10b168afTimo Sirainen switch (c) {
02aedbc20af0160091670233383d228f10b168afTimo Sirainen case 'a':
02aedbc20af0160091670233383d228f10b168afTimo Sirainen socket_path = optarg;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen break;
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen case 'f':
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen ctx->username_field = optarg;
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen break;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen default:
02aedbc20af0160091670233383d228f10b168afTimo Sirainen proxy_cmd_help(cmd);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen }
02aedbc20af0160091670233383d228f10b168afTimo Sirainen }
02aedbc20af0160091670233383d228f10b168afTimo Sirainen ctx->ipc = ipc_client_init(socket_path);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen return ctx;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen}
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainenstatic void cmd_proxy_list_header(const char *const *args)
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen{
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen struct {
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen const char *key;
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen const char *title;
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen } header_map[] = {
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen { "service", "proto" },
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen { "src-ip", "src ip" },
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen { "dest-ip", "dest ip" },
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen { "dest-port", "port" },
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen };
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen for (unsigned int i = 0; args[i] != NULL; i++) {
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen const char *arg = args[i];
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen if (strcmp(arg, "username") == 0 ||
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen strncmp(arg, "user_", 5) == 0) {
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen doveadm_print_header(arg, arg,
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen DOVEADM_PRINT_HEADER_FLAG_EXPAND);
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen continue;
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen }
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen const char *title = arg;
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen for (unsigned int j = 0; j < N_ELEMENTS(header_map); j++) {
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen if (strcmp(header_map[j].key, arg) == 0) {
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen title = header_map[j].title;
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen break;
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen }
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen }
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen doveadm_print_header(arg, title, 0);
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen }
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen}
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainenstatic void cmd_proxy_list_callback(enum ipc_client_cmd_state state,
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen const char *data, void *context)
02aedbc20af0160091670233383d228f10b168afTimo Sirainen{
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen bool *seen_header = context;
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainen switch (state) {
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen case IPC_CLIENT_CMD_STATE_REPLY: {
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen const char *const *args = t_strsplit_tabescaped(data);
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen if (!*seen_header) {
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen cmd_proxy_list_header(args);
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen *seen_header = TRUE;
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen } else {
02aedbc20af0160091670233383d228f10b168afTimo Sirainen for (; *args != NULL; args++)
02aedbc20af0160091670233383d228f10b168afTimo Sirainen doveadm_print(*args);
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen }
02aedbc20af0160091670233383d228f10b168afTimo Sirainen return;
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen }
02aedbc20af0160091670233383d228f10b168afTimo Sirainen case IPC_CLIENT_CMD_STATE_OK:
02aedbc20af0160091670233383d228f10b168afTimo Sirainen break;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen case IPC_CLIENT_CMD_STATE_ERROR:
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen i_error("LIST-FULL failed: %s", data);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen break;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen }
02aedbc20af0160091670233383d228f10b168afTimo Sirainen io_loop_stop(current_ioloop);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen}
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainenstatic void cmd_proxy_list(int argc, char *argv[])
02aedbc20af0160091670233383d228f10b168afTimo Sirainen{
02aedbc20af0160091670233383d228f10b168afTimo Sirainen struct proxy_context *ctx;
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen bool seen_header = FALSE;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainen ctx = cmd_proxy_init(argc, argv, "a:", cmd_proxy_list);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainen doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
cbcc083b53cc2e263f039edd4e4c7cb74830651eTimo Sirainen io_loop_set_running(current_ioloop);
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen ipc_client_cmd(ctx->ipc, "proxy\t*\tLIST-FULL",
adad68df4602d80639d7f28e4c7550fbafbd8d60Timo Sirainen cmd_proxy_list_callback, &seen_header);
cbcc083b53cc2e263f039edd4e4c7cb74830651eTimo Sirainen if (io_loop_is_running(current_ioloop))
cbcc083b53cc2e263f039edd4e4c7cb74830651eTimo Sirainen io_loop_run(current_ioloop);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen ipc_client_deinit(&ctx->ipc);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen}
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
ac1118842c3d80285e32d2cd53bda3e95e5be217Timo Sirainenstatic void cmd_proxy_kick_callback(enum ipc_client_cmd_state state,
02aedbc20af0160091670233383d228f10b168afTimo Sirainen const char *data, void *context ATTR_UNUSED)
02aedbc20af0160091670233383d228f10b168afTimo Sirainen{
02aedbc20af0160091670233383d228f10b168afTimo Sirainen switch (state) {
02aedbc20af0160091670233383d228f10b168afTimo Sirainen case IPC_CLIENT_CMD_STATE_REPLY:
02aedbc20af0160091670233383d228f10b168afTimo Sirainen return;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen case IPC_CLIENT_CMD_STATE_OK:
350d6194f7336f3c89d641a01b31c7417d67b08aTimo Sirainen if (data[0] == '\0')
350d6194f7336f3c89d641a01b31c7417d67b08aTimo Sirainen data = "0";
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi doveadm_print(data);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen break;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen case IPC_CLIENT_CMD_STATE_ERROR:
ac1118842c3d80285e32d2cd53bda3e95e5be217Timo Sirainen i_error("KICK failed: %s", data);
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi doveadm_exit_code = EX_TEMPFAIL;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen break;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen }
02aedbc20af0160091670233383d228f10b168afTimo Sirainen io_loop_stop(current_ioloop);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen}
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
ac1118842c3d80285e32d2cd53bda3e95e5be217Timo Sirainenstatic void cmd_proxy_kick(int argc, char *argv[])
02aedbc20af0160091670233383d228f10b168afTimo Sirainen{
02aedbc20af0160091670233383d228f10b168afTimo Sirainen struct proxy_context *ctx;
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen string_t *cmd;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen ctx = cmd_proxy_init(argc, argv, "a:f:", cmd_proxy_kick);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainen if (argv[optind] == NULL) {
ac1118842c3d80285e32d2cd53bda3e95e5be217Timo Sirainen proxy_cmd_help(cmd_proxy_kick);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen return;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen }
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi doveadm_print_init(DOVEADM_PRINT_TYPE_FORMATTED);
1f58bee818868d7261224766b66182c8eaf31ba8Aki Tuomi doveadm_print_formatted_set_format("%{count} connections kicked\n");
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi doveadm_print_header_simple("count");
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen cmd = t_str_new(128);
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen str_append(cmd, "proxy\t*\t");
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen if (ctx->username_field == NULL)
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen str_append(cmd, "KICK");
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen else {
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen str_append(cmd, "KICK-ALT\t");
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen str_append_tabescaped(cmd, ctx->username_field);
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen }
9fc9965693110c250c6d6aa36ab60a77c934cc49Timo Sirainen for (; argv[optind] != NULL; optind++) {
9fc9965693110c250c6d6aa36ab60a77c934cc49Timo Sirainen str_append_c(cmd, '\t');
9fc9965693110c250c6d6aa36ab60a77c934cc49Timo Sirainen str_append_tabescaped(cmd, argv[optind]);
9fc9965693110c250c6d6aa36ab60a77c934cc49Timo Sirainen }
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo Sirainen ipc_client_cmd(ctx->ipc, str_c(cmd), cmd_proxy_kick_callback, NULL);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen io_loop_run(current_ioloop);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen ipc_client_deinit(&ctx->ipc);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen}
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomistruct doveadm_cmd_ver2 doveadm_cmd_proxy[] = {
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi{
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi .name = "proxy list",
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi .usage = "[-a <ipc socket path>]",
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi .old_cmd = cmd_proxy_list,
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki TuomiDOVEADM_CMD_PARAMS_START
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki TuomiDOVEADM_CMD_PARAM('a', "socket-path", CMD_PARAM_STR, 0)
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki TuomiDOVEADM_CMD_PARAMS_END
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi},
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi{
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi .name = "proxy kick",
9fc9965693110c250c6d6aa36ab60a77c934cc49Timo Sirainen .usage = "[-a <ipc socket path>] [-f <passdb field>] <user> [...]",
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi .old_cmd = cmd_proxy_kick,
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki TuomiDOVEADM_CMD_PARAMS_START
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki TuomiDOVEADM_CMD_PARAM('a', "socket-path", CMD_PARAM_STR, 0)
75af6e5ca2c4685e2316d27364ac7b00def7fed7Timo SirainenDOVEADM_CMD_PARAM('f', "passdb-field", CMD_PARAM_STR, 0)
9fc9965693110c250c6d6aa36ab60a77c934cc49Timo SirainenDOVEADM_CMD_PARAM('\0', "user", CMD_PARAM_ARRAY, CMD_PARAM_FLAG_POSITIONAL)
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki TuomiDOVEADM_CMD_PARAMS_END
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi}
02aedbc20af0160091670233383d228f10b168afTimo Sirainen};
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainenstatic void proxy_cmd_help(doveadm_command_t *cmd)
02aedbc20af0160091670233383d228f10b168afTimo Sirainen{
02aedbc20af0160091670233383d228f10b168afTimo Sirainen unsigned int i;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainen for (i = 0; i < N_ELEMENTS(doveadm_cmd_proxy); i++) {
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi if (doveadm_cmd_proxy[i].old_cmd == cmd)
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi help_ver2(&doveadm_cmd_proxy[i]);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen }
02aedbc20af0160091670233383d228f10b168afTimo Sirainen i_unreached();
02aedbc20af0160091670233383d228f10b168afTimo Sirainen}
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainenvoid doveadm_register_proxy_commands(void)
02aedbc20af0160091670233383d228f10b168afTimo Sirainen{
02aedbc20af0160091670233383d228f10b168afTimo Sirainen unsigned int i;
02aedbc20af0160091670233383d228f10b168afTimo Sirainen
02aedbc20af0160091670233383d228f10b168afTimo Sirainen for (i = 0; i < N_ELEMENTS(doveadm_cmd_proxy); i++)
76537b1991e7815c7a867a997f7fa2b3c17412d4Aki Tuomi doveadm_cmd_register_ver2(&doveadm_cmd_proxy[i]);
02aedbc20af0160091670233383d228f10b168afTimo Sirainen}