doveadm-proxy.c revision 350d6194f7336f3c89d641a01b31c7417d67b08a
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen/* Copyright (c) 2011-2016 Dovecot authors, see the included COPYING file */
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen#include "lib.h"
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen#include "ioloop.h"
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen#include "ipc-client.h"
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen#include "doveadm.h"
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen#include "doveadm-print.h"
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen#include <stdio.h>
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen#include <unistd.h>
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainenstruct proxy_context {
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen struct ipc_client *ipc;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen};
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainenextern struct doveadm_cmd_ver2 doveadm_cmd_proxy[];
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainenstatic void proxy_cmd_help(doveadm_command_t *cmd) ATTR_NORETURN;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainenstatic struct proxy_context *
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainencmd_proxy_init(int argc, char *argv[], const char *getopt_args,
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen doveadm_command_t *cmd)
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen{
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen struct proxy_context *ctx;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen const char *socket_path;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen int c;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen ctx = t_new(struct proxy_context, 1);
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen socket_path = t_strconcat(doveadm_settings->base_dir, "/ipc", NULL);
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen while ((c = getopt(argc, argv, getopt_args)) > 0) {
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen switch (c) {
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen case 'a':
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen socket_path = optarg;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen break;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen default:
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen proxy_cmd_help(cmd);
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen }
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen }
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen ctx->ipc = ipc_client_init(socket_path);
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen return ctx;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen}
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainenstatic void cmd_proxy_list_callback(enum ipc_client_cmd_state state,
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen const char *data, void *context ATTR_UNUSED)
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen{
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen switch (state) {
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen case IPC_CLIENT_CMD_STATE_REPLY:
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen T_BEGIN {
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen const char *const *args = t_strsplit_tab(data);
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen for (; *args != NULL; args++)
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen doveadm_print(*args);
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen } T_END;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen return;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen case IPC_CLIENT_CMD_STATE_OK:
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen break;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen case IPC_CLIENT_CMD_STATE_ERROR:
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen i_error("LIST failed: %s", data);
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen break;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen }
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen io_loop_stop(current_ioloop);
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen}
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainenstatic void cmd_proxy_list(int argc, char *argv[])
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen{
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen struct proxy_context *ctx;
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen
3c57664b9dce82cd3e43347394b92ef3591b8901Timo Sirainen ctx = cmd_proxy_init(argc, argv, "a:", cmd_proxy_list);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen doveadm_print_header("username", "username", DOVEADM_PRINT_HEADER_FLAG_EXPAND);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen doveadm_print_header("service", "proto", 0);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen doveadm_print_header("src-ip", "src ip", 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen doveadm_print_header("dest-ip", "dest ip", 0);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen doveadm_print_header("dest-port", "port", 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen io_loop_set_running(current_ioloop);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen ipc_client_cmd(ctx->ipc, "proxy\t*\tLIST",
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen cmd_proxy_list_callback, NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (io_loop_is_running(current_ioloop))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen io_loop_run(current_ioloop);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ipc_client_deinit(&ctx->ipc);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainenstatic void cmd_proxy_kick_callback(enum ipc_client_cmd_state state,
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen const char *data, void *context ATTR_UNUSED)
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen{
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen switch (state) {
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen case IPC_CLIENT_CMD_STATE_REPLY:
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen return;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen case IPC_CLIENT_CMD_STATE_OK:
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen if (data[0] == '\0')
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen data = "0";
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen doveadm_print(data);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen break;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen case IPC_CLIENT_CMD_STATE_ERROR:
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_error("KICK failed: %s", data);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen break;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen io_loop_stop(current_ioloop);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen}
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainenstatic void cmd_proxy_kick(int argc, char *argv[])
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen{
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen struct proxy_context *ctx;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen ctx = cmd_proxy_init(argc, argv, "a:", cmd_proxy_kick);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (argv[optind] == NULL) {
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen proxy_cmd_help(cmd_proxy_kick);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen }
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen doveadm_print_init(DOVEADM_PRINT_TYPE_FORMATTED);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen doveadm_print_formatted_set_format("%{count} connections kicked");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen doveadm_print_header_simple("count");
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen ipc_client_cmd(ctx->ipc, t_strdup_printf("proxy\t*\tKICK\t%s", argv[optind]),
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen cmd_proxy_kick_callback, NULL);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen io_loop_run(current_ioloop);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen ipc_client_deinit(&ctx->ipc);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstruct doveadm_cmd_ver2 doveadm_cmd_proxy[] = {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen{
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen .name = "proxy list",
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen .usage = "[-a <ipc socket path>]",
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen .old_cmd = cmd_proxy_list,
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo SirainenDOVEADM_CMD_PARAMS_START
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo SirainenDOVEADM_CMD_PARAM('a', "socket-path", CMD_PARAM_STR, 0)
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo SirainenDOVEADM_CMD_PARAMS_END
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen},
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen .name = "proxy kick",
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen .usage = "[-a <ipc socket path>] <user>",
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen .old_cmd = cmd_proxy_kick,
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo SirainenDOVEADM_CMD_PARAMS_START
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo SirainenDOVEADM_CMD_PARAM('a', "socket-path", CMD_PARAM_STR, 0)
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo SirainenDOVEADM_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]);
}