doveadm-proxy.c revision adad68df4602d80639d7f28e4c7550fbafbd8d60
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2011-2016 Dovecot authors, see the included COPYING file */
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "lib.h"
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen#include "ioloop.h"
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen#include "ipc-client.h"
64f30df0bee5218c9a69915e796d9d1376cfbf29Timo Sirainen#include "doveadm.h"
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen#include "doveadm-print.h"
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include <stdio.h>
bd63b5b860658b01b1f46f26d406e1e4a9dc019aTimo Sirainen#include <unistd.h>
f6c1297c26b355c4aec2a08978f51ec3efecb351Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenstruct proxy_context {
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen struct ipc_client *ipc;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen};
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenextern struct doveadm_cmd_ver2 doveadm_cmd_proxy[];
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenstatic void proxy_cmd_help(doveadm_command_t *cmd) ATTR_NORETURN;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenstatic struct proxy_context *
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainencmd_proxy_init(int argc, char *argv[], const char *getopt_args,
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen doveadm_command_t *cmd)
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen{
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen struct proxy_context *ctx;
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen const char *socket_path;
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen int c;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen ctx = t_new(struct proxy_context, 1);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen socket_path = t_strconcat(doveadm_settings->base_dir, "/ipc", NULL);
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen while ((c = getopt(argc, argv, getopt_args)) > 0) {
88b9f9eb91da632d3e941fe4276f8ace03205b25Timo Sirainen switch (c) {
88b9f9eb91da632d3e941fe4276f8ace03205b25Timo Sirainen case 'a':
f26ef7a3a562dc42a1e9a4dde546bd30df3241e8Timo Sirainen socket_path = optarg;
f26ef7a3a562dc42a1e9a4dde546bd30df3241e8Timo Sirainen break;
57b523eeb99ed5d7f5002907a409cdef54353ce5Timo Sirainen default:
57b523eeb99ed5d7f5002907a409cdef54353ce5Timo Sirainen proxy_cmd_help(cmd);
4f4daf7df84f450c7342de569bf25195e93d6bc7Timo Sirainen }
4f4daf7df84f450c7342de569bf25195e93d6bc7Timo Sirainen }
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen ctx->ipc = ipc_client_init(socket_path);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen return ctx;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen}
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenstatic void cmd_proxy_list_header(const char *const *args)
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen{
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen struct {
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen const char *key;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen const char *title;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen } header_map[] = {
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen { "service", "proto" },
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen { "src-ip", "src ip" },
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen { "dest-ip", "dest ip" },
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen { "dest-port", "port" },
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen };
db9ad8c821c01a18a520c2a07b2d6dc501b4017aTimo Sirainen for (unsigned int i = 0; args[i] != NULL; i++) {
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen const char *arg = args[i];
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen if (strcmp(arg, "username") == 0 ||
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen strncmp(arg, "user_", 5) == 0) {
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen doveadm_print_header(arg, arg,
57a712a4998e4bb0073080232225380cd2cea625Timo Sirainen DOVEADM_PRINT_HEADER_FLAG_EXPAND);
57a712a4998e4bb0073080232225380cd2cea625Timo Sirainen continue;
57a712a4998e4bb0073080232225380cd2cea625Timo Sirainen }
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen const char *title = arg;
db9ad8c821c01a18a520c2a07b2d6dc501b4017aTimo Sirainen for (unsigned int j = 0; j < N_ELEMENTS(header_map); j++) {
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen if (strcmp(header_map[j].key, arg) == 0) {
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen title = header_map[j].title;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen break;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen }
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen }
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen doveadm_print_header(arg, title, 0);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen }
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen}
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainenstatic void cmd_proxy_list_callback(enum ipc_client_cmd_state state,
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen const char *data, void *context)
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen{
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen bool *seen_header = context;
4f4daf7df84f450c7342de569bf25195e93d6bc7Timo Sirainen
4f4daf7df84f450c7342de569bf25195e93d6bc7Timo Sirainen switch (state) {
4f4daf7df84f450c7342de569bf25195e93d6bc7Timo Sirainen case IPC_CLIENT_CMD_STATE_REPLY: {
bfcca12a441275b7f4cd510b95669b163263b2e7Timo Sirainen const char *const *args = t_strsplit_tab(data);
bfcca12a441275b7f4cd510b95669b163263b2e7Timo Sirainen
bfcca12a441275b7f4cd510b95669b163263b2e7Timo Sirainen if (!*seen_header) {
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen cmd_proxy_list_header(args);
88b9f9eb91da632d3e941fe4276f8ace03205b25Timo Sirainen *seen_header = TRUE;
88b9f9eb91da632d3e941fe4276f8ace03205b25Timo Sirainen } else {
f26ef7a3a562dc42a1e9a4dde546bd30df3241e8Timo Sirainen for (; *args != NULL; args++)
f26ef7a3a562dc42a1e9a4dde546bd30df3241e8Timo Sirainen doveadm_print(*args);
57b523eeb99ed5d7f5002907a409cdef54353ce5Timo Sirainen }
57b523eeb99ed5d7f5002907a409cdef54353ce5Timo Sirainen return;
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen }
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen case IPC_CLIENT_CMD_STATE_OK:
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen break;
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen case IPC_CLIENT_CMD_STATE_ERROR:
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen i_error("LIST-FULL failed: %s", data);
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen break;
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen }
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen io_loop_stop(current_ioloop);
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen}
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainenstatic void cmd_proxy_list(int argc, char *argv[])
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen{
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen struct proxy_context *ctx;
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen bool seen_header = FALSE;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen ctx = cmd_proxy_init(argc, argv, "a:", cmd_proxy_list);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen io_loop_set_running(current_ioloop);
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen ipc_client_cmd(ctx->ipc, "proxy\t*\tLIST-FULL",
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen cmd_proxy_list_callback, &seen_header);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen if (io_loop_is_running(current_ioloop))
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen io_loop_run(current_ioloop);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen ipc_client_deinit(&ctx->ipc);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen}
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainenstatic void cmd_proxy_kick_callback(enum ipc_client_cmd_state state,
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen const char *data, void *context ATTR_UNUSED)
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen{
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen switch (state) {
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen case IPC_CLIENT_CMD_STATE_REPLY:
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen return;
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen case IPC_CLIENT_CMD_STATE_OK:
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen if (data[0] == '\0')
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen data = "0";
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen doveadm_print(data);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen break;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen case IPC_CLIENT_CMD_STATE_ERROR:
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen i_error("KICK failed: %s", data);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen break;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen }
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen io_loop_stop(current_ioloop);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen}
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenstatic void cmd_proxy_kick(int argc, char *argv[])
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen{
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen struct proxy_context *ctx;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen ctx = cmd_proxy_init(argc, argv, "a:", cmd_proxy_kick);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen if (argv[optind] == NULL) {
64f30df0bee5218c9a69915e796d9d1376cfbf29Timo Sirainen proxy_cmd_help(cmd_proxy_kick);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen }
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
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);
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>]",
.old_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>] <user>",
.old_cmd = cmd_proxy_kick,
DOVEADM_CMD_PARAMS_START
DOVEADM_CMD_PARAM('a', "socket-path", CMD_PARAM_STR, 0)
DOVEADM_CMD_PARAM('\0', "user", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL)
DOVEADM_CMD_PARAMS_END
}
};
static void proxy_cmd_help(doveadm_command_t *cmd)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(doveadm_cmd_proxy); i++) {
if (doveadm_cmd_proxy[i].old_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]);
}