client-connection.c revision ef0c36aa8114feee80aa696d9cb8106140371243
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "lib.h"
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "lib-signals.h"
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen#include "base64.h"
5bda841ca9e2ddd90702dc7e2a15326e4068066eTimo Sirainen#include "ioloop.h"
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen#include "istream.h"
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "ostream.h"
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "strescape.h"
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen#include "process-title.h"
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen#include "settings-parser.h"
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen#include "iostream-ssl.h"
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "master-service.h"
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "master-service-ssl.h"
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "master-service-settings.h"
33502e55a9bf4cafcd184ca9b114c126e420f856Timo Sirainen#include "mail-storage-service.h"
33502e55a9bf4cafcd184ca9b114c126e420f856Timo Sirainen#include "doveadm-util.h"
33502e55a9bf4cafcd184ca9b114c126e420f856Timo Sirainen#include "doveadm-server.h"
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen#include "doveadm-mail.h"
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen#include "doveadm-print.h"
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen#include "doveadm-settings.h"
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen#include "client-connection-private.h"
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen#include <unistd.h>
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen#define MAX_INBUF_SIZE (1024*1024)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstatic struct {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen int code;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *str;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen} exit_code_strings[] = {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen { EX_TEMPFAIL, "TEMPFAIL" },
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen { EX_USAGE, "USAGE" },
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen { EX_NOUSER, "NOUSER" },
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen { EX_NOPERM, "NOPERM" },
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen { EX_PROTOCOL, "PROTOCOL" },
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen { EX_DATAERR, "DATAERR" },
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen { DOVEADM_EX_NOTFOUND, "NOTFOUND" }
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen};
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstatic void client_connection_input(struct client_connection *conn);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstatic void
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainendoveadm_cmd_server_post(struct client_connection *conn, const char *cmd_name)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen{
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *str = NULL;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen unsigned int i;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (doveadm_exit_code == 0) {
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen o_stream_nsend(conn->output, "\n+\n", 3);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen return;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen }
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen for (i = 0; i < N_ELEMENTS(exit_code_strings); i++) {
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen if (exit_code_strings[i].code == doveadm_exit_code) {
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen str = exit_code_strings[i].str;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen break;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen }
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen }
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen if (str != NULL) {
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen o_stream_nsend_str(conn->output,
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen t_strdup_printf("\n-%s\n", str));
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen } else {
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen o_stream_nsend_str(conn->output, "\n-\n");
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen i_error("BUG: Command '%s' returned unknown error code %d",
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen cmd_name, doveadm_exit_code);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen }
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen}
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainenstatic void
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainendoveadm_cmd_server_run_ver2(struct client_connection *conn,
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen int argc, const char *const argv[],
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen struct doveadm_cmd_context *cctx)
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen{
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen i_getopt_reset();
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen if (doveadm_cmd_run_ver2(argc, argv, cctx) < 0)
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen doveadm_exit_code = EX_USAGE;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen doveadm_cmd_server_post(conn, cctx->cmd->name);
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen}
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainenstatic void
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainendoveadm_cmd_server_run(struct client_connection *conn,
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen int argc, const char *const argv[],
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen const struct doveadm_cmd *cmd)
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen{
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen i_getopt_reset();
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen cmd->cmd(argc, (char **)argv);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen doveadm_cmd_server_post(conn, cmd->name);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen}
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainenstatic int
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainendoveadm_mail_cmd_server_parse(const struct doveadm_mail_cmd *cmd,
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen const struct doveadm_settings *set,
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen int argc, const char *const argv[],
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen struct doveadm_cmd_context *cctx,
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen struct doveadm_mail_cmd_context **mctx_r)
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen{
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen struct doveadm_mail_cmd_context *mctx;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen const char *getopt_args;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen bool add_username_header = FALSE;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen int c;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen mctx = doveadm_mail_cmd_init(cmd, set);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen mctx->full_args = argv+1;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen mctx->proxying = TRUE;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen mctx->cur_username = cctx->username;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen mctx->service_flags |=
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT |
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen if (doveadm_debug)
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen mctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen i_getopt_reset();
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen getopt_args = t_strconcat("AF:S:u:", mctx->getopt_args, NULL);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen while ((c = getopt(argc, (char **)argv, getopt_args)) > 0) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen switch (c) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen case 'A':
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen case 'F':
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen add_username_header = TRUE;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen break;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen case 'S':
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen /* ignore */
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen break;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen case 'u':
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen if (strchr(optarg, '*') != NULL ||
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen strchr(optarg, '?') != NULL)
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen add_username_header = TRUE;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen break;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen default:
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen if ((mctx->v.parse_arg == NULL ||
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen !mctx->v.parse_arg(mctx, c))) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen i_error("doveadm %s: "
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen "Client sent unknown parameter: %c",
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen cmd->name, c);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen mctx->v.deinit(mctx);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen pool_unref(&mctx->pool);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen return -1;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen }
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen }
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen }
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen if (argv[optind] != NULL && cmd->usage_args == NULL) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen i_error("doveadm %s: Client sent unknown parameter: %s",
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen cmd->name, argv[optind]);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen mctx->v.deinit(mctx);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen pool_unref(&mctx->pool);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen return -1;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen }
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen mctx->args = argv+optind;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen if (mctx->cur_username != NULL) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen if (strchr(mctx->cur_username, '*') != NULL ||
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen strchr(mctx->cur_username, '?') != NULL) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen add_username_header = TRUE;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen }
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen }
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen if (doveadm_print_is_initialized() && add_username_header) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen doveadm_print_header("username", "Username",
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen DOVEADM_PRINT_HEADER_FLAG_STICKY |
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen doveadm_print_sticky("username", cctx->username);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen }
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen *mctx_r = mctx;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen return 0;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen}
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstatic void
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainendoveadm_mail_cmd_server_run(struct client_connection *conn,
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen struct doveadm_mail_cmd_context *mctx,
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen struct doveadm_cmd_context *cctx)
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen{
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *error;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen int ret;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen mctx->conn = conn;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen o_stream_cork(conn->output);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (mctx->v.preinit != NULL)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen mctx->v.preinit(mctx);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen ret = doveadm_mail_single_user(mctx, cctx, &error);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen doveadm_mail_server_flush();
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen mctx->v.deinit(mctx);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen doveadm_print_flush();
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen mail_storage_service_deinit(&mctx->storage_service);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (ret < 0) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen i_error("%s: %s", mctx->cmd->name, error);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen o_stream_nsend(conn->output, "\n-\n", 3);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen } else if (ret == 0) {
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen o_stream_nsend_str(conn->output, "\n-NOUSER\n");
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen } else if (mctx->exit_code != 0) {
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen /* maybe not an error, but not a full success either */
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen o_stream_nsend_str(conn->output,
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen t_strdup_printf("\n-%u\n", mctx->exit_code));
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen } else {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen o_stream_nsend(conn->output, "\n+\n", 3);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen o_stream_uncork(conn->output);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen pool_unref(&mctx->pool);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen}
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainenbool doveadm_client_is_allowed_command(const struct doveadm_settings *set,
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen const char *cmd_name)
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen{
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen bool ret = FALSE;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen if (*set->doveadm_allowed_commands == '\0')
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen return TRUE;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen T_BEGIN {
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen const char *const *cmds =
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen t_strsplit(set->doveadm_allowed_commands, ",");
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen for (; *cmds != NULL; cmds++) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen if (strcmp(*cmds, cmd_name) == 0) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen ret = TRUE;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen break;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen }
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen }
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen } T_END;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen return ret;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen}
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainenstatic int doveadm_cmd_handle(struct client_connection *conn,
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen const char *cmd_name,
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen int argc, const char *const argv[],
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen struct doveadm_cmd_context *cctx)
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen{
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen struct ioloop *ioloop, *prev_ioloop = current_ioloop;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const struct doveadm_cmd *cmd = NULL;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const struct doveadm_mail_cmd *mail_cmd;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen struct doveadm_mail_cmd_context *mctx;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const struct doveadm_cmd_ver2 *cmd_ver2;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if ((cmd_ver2 = doveadm_cmd_find_with_args_ver2(cmd_name, &argc, &argv)) == NULL) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen mail_cmd = doveadm_mail_cmd_find(cmd_name);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (mail_cmd == NULL) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen cmd = doveadm_cmd_find_with_args(cmd_name, &argc, &argv);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (cmd == NULL) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen i_error("doveadm: Client sent unknown command: %s", cmd_name);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen return -1;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen } else {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (doveadm_mail_cmd_server_parse(mail_cmd, conn->set,
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen argc, argv,
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen cctx, &mctx) < 0)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return -1;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen } else {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen cctx->cmd = cmd_ver2;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen /* some commands will want to call io_loop_run(), but we're already
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen running one and we can't call the original one recursively, so
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen create a new ioloop. */
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen ioloop = io_loop_create();
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen lib_signals_reset_ioloop();
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (cmd_ver2 != NULL)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen doveadm_cmd_server_run_ver2(conn, argc, argv, cctx);
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen else if (cmd != NULL)
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen doveadm_cmd_server_run(conn, argc, argv, cmd);
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen else
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen doveadm_mail_cmd_server_run(conn, mctx, cctx);
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen io_loop_set_current(prev_ioloop);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen lib_signals_reset_ioloop();
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen o_stream_switch_ioloop(conn->output);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen io_loop_set_current(ioloop);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen io_loop_destroy(&ioloop);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen /* clear all headers */
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen doveadm_print_deinit();
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen doveadm_print_init(DOVEADM_PRINT_TYPE_SERVER);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return doveadm_exit_code == 0 ? 0 : -1;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen}
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstatic bool client_handle_command(struct client_connection *conn,
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *const *args)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen{
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen struct doveadm_cmd_context cctx;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *flags, *cmd_name;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen unsigned int argc = str_array_length(args);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen if (argc < 3) {
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen i_error("doveadm client: No command given");
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return FALSE;
dce232dfbb2244555299dffb3618a4724748d260Timo Sirainen }
dce232dfbb2244555299dffb3618a4724748d260Timo Sirainen memset(&cctx, 0, sizeof(cctx));
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen cctx.cli = FALSE;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen cctx.tcp_server = TRUE;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen cctx.local_ip = conn->local_ip;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen cctx.remote_ip = conn->remote_ip;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen cctx.local_port = conn->local_port;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen cctx.remote_port = conn->remote_port;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen cctx.conn = conn;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen doveadm_exit_code = 0;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen flags = args[0];
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen cctx.username = args[1];
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen cmd_name = args[2];
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen doveadm_debug = FALSE;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen doveadm_verbose = FALSE;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen for (; *flags != '\0'; flags++) {
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen switch (*flags) {
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen case 'D':
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen doveadm_debug = TRUE;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen doveadm_verbose = TRUE;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen break;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen case 'v':
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen doveadm_verbose = TRUE;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen break;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen default:
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen i_error("doveadm client: Unknown flag: %c", *flags);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen return FALSE;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen }
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen }
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen if (!doveadm_client_is_allowed_command(conn->set, cmd_name)) {
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen i_error("doveadm client isn't allowed to use command: %s",
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen cmd_name);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen return FALSE;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen }
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen client_connection_set_proctitle(conn, cmd_name);
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen o_stream_cork(conn->output);
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen if (doveadm_cmd_handle(conn, cmd_name, argc-2, args+2, &cctx) < 0)
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen o_stream_nsend(conn->output, "\n-\n", 3);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen o_stream_uncork(conn->output);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen client_connection_set_proctitle(conn, "");
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen /* flush the output and possibly run next command */
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen net_set_nonblock(conn->fd, FALSE);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen (void)o_stream_flush(conn->output);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen net_set_nonblock(conn->fd, TRUE);
dce232dfbb2244555299dffb3618a4724748d260Timo Sirainen return TRUE;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen}
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen
37f96554a5734557cd454691d163e602d36384b4Timo Sirainenstatic int
37f96554a5734557cd454691d163e602d36384b4Timo Sirainenclient_connection_authenticate(struct client_connection *conn)
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen{
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen const char *line, *pass;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen buffer_t *plain;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const unsigned char *data;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen size_t size;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen if ((line = i_stream_read_next_line(conn->input)) == NULL) {
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen if (conn->input->eof)
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen return -1;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen return 0;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen }
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen if (*conn->set->doveadm_password == '\0') {
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen i_error("doveadm_password not set, "
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen "remote authentication disabled");
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return -1;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen /* FIXME: some day we should probably let auth process do this and
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen support all kinds of authentication */
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen if (strncmp(line, "PLAIN\t", 6) != 0) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen i_error("doveadm client attempted non-PLAIN authentication: %s", line);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen return -1;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen }
dce232dfbb2244555299dffb3618a4724748d260Timo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen plain = buffer_create_dynamic(pool_datastack_create(), 128);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (base64_decode(line + 6, strlen(line + 6), NULL, plain) < 0) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen i_error("doveadm client sent invalid base64 auth PLAIN data");
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return -1;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen data = plain->data;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen size = plain->used;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (size < 10 || data[0] != '\0' ||
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen memcmp(data+1, "doveadm", 7) != 0 || data[8] != '\0') {
33502e55a9bf4cafcd184ca9b114c126e420f856Timo Sirainen i_error("doveadm client didn't authenticate as 'doveadm'");
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen return -1;
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen }
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen pass = t_strndup(data + 9, size - 9);
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen if (strcmp(pass, conn->set->doveadm_password) != 0) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen i_error("doveadm client authenticated with wrong password");
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return -1;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return 1;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen}
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstatic void client_log_disconnect_error(struct client_connection *conn)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen{
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *error;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen error = conn->ssl_iostream == NULL ? NULL :
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen ssl_iostream_get_last_error(conn->ssl_iostream);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (error == NULL) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen error = conn->input->stream_errno == 0 ? "EOF" :
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen strerror(conn->input->stream_errno);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen i_error("doveadm client disconnected before handshake: %s", error);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen}
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstatic void client_connection_input(struct client_connection *conn)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen{
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *line;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen bool ok = TRUE;
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen int ret;
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (!conn->handshaked) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if ((line = i_stream_read_next_line(conn->input)) == NULL) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (conn->input->eof || conn->input->stream_errno != 0) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen client_log_disconnect_error(conn);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen client_connection_destroy(&conn);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return;
5bda841ca9e2ddd90702dc7e2a15326e4068066eTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
6a866d5d5533cb744c78bc2f1ca47beaee690d2fTimo Sirainen if (!version_string_verify(line, "doveadm-server",
6a866d5d5533cb744c78bc2f1ca47beaee690d2fTimo Sirainen DOVEADM_SERVER_PROTOCOL_VERSION_MAJOR)) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen i_error("doveadm client not compatible with this server "
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen "(mixed old and new binaries?)");
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen client_connection_destroy(&conn);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen conn->handshaked = TRUE;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (!conn->authenticated) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if ((ret = client_connection_authenticate(conn)) <= 0) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (ret < 0) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen o_stream_nsend(conn->output, "-\n", 2);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen client_connection_destroy(&conn);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen return;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen o_stream_nsend(conn->output, "+\n", 2);
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen conn->authenticated = TRUE;
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen }
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen while (ok && !conn->input->closed &&
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen (line = i_stream_read_next_line(conn->input)) != NULL) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen T_BEGIN {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *const *args;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen args = t_strsplit_tabescaped(line);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen ok = client_handle_command(conn, args);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen } T_END;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen }
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen if (conn->input->eof || conn->input->stream_errno != 0 || !ok)
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen client_connection_destroy(&conn);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen}
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
37f96554a5734557cd454691d163e602d36384b4Timo Sirainenstatic int client_connection_read_settings(struct client_connection *conn)
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen{
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen const struct setting_parser_info *set_roots[] = {
dce232dfbb2244555299dffb3618a4724748d260Timo Sirainen &doveadm_setting_parser_info,
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen NULL
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen };
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen struct master_service_settings_input input;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen struct master_service_settings_output output;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen const char *error;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen void *set;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen memset(&input, 0, sizeof(input));
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen input.roots = set_roots;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen input.service = "doveadm";
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen input.local_ip = conn->local_ip;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen input.remote_ip = conn->remote_ip;
dce232dfbb2244555299dffb3618a4724748d260Timo Sirainen
dce232dfbb2244555299dffb3618a4724748d260Timo Sirainen if (master_service_settings_read(master_service, &input,
dce232dfbb2244555299dffb3618a4724748d260Timo Sirainen &output, &error) < 0) {
dce232dfbb2244555299dffb3618a4724748d260Timo Sirainen i_error("Error reading configuration: %s", error);
dce232dfbb2244555299dffb3618a4724748d260Timo Sirainen return -1;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen }
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen set = master_service_settings_get_others(master_service)[0];
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen conn->set = settings_dup(&doveadm_setting_parser_info, set, conn->pool);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen return 0;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen}
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstatic int client_connection_init_ssl(struct client_connection *conn)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen{
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *error;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (master_service_ssl_init(master_service,
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen &conn->input, &conn->output,
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen &conn->ssl_iostream, &error) < 0) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen i_error("SSL init failed: %s", error);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return -1;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (ssl_iostream_handshake(conn->ssl_iostream) < 0) {
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen i_error("SSL handshake failed: %s",
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen ssl_iostream_get_last_error(conn->ssl_iostream));
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return -1;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return 0;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen}
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstatic void
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenclient_connection_send_auth_handshake(struct client_connection *
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen conn, int listen_fd)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen{
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *listen_path;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen struct stat st;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen /* we'll have to do this with stat(), because at least in Linux
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen fstat() always returns mode as 0777 */
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen if (net_getunixname(listen_fd, &listen_path) == 0 &&
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen stat(listen_path, &st) == 0 && S_ISSOCK(st.st_mode) &&
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen (st.st_mode & 0777) == 0600) {
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen /* no need for client to authenticate */
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen conn->authenticated = TRUE;
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen o_stream_nsend(conn->output, "+\n", 2);
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen } else {
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen o_stream_nsend(conn->output, "-\n", 2);
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen }
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen}
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainenint client_connection_init(struct client_connection *conn, int fd)
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen{
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen const char *ip;
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen conn->fd = fd;
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen (void)net_getsockname(fd, &conn->local_ip, &conn->local_port);
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen (void)net_getpeername(fd, &conn->remote_ip, &conn->remote_port);
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen ip = net_ip2addr(&conn->remote_ip);
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen if (ip[0] != '\0')
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen i_set_failure_prefix("doveadm(%s): ", ip);
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen if (client_connection_read_settings(conn) < 0) {
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen client_connection_destroy(&conn);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen return -1;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen }
6a866d5d5533cb744c78bc2f1ca47beaee690d2fTimo Sirainen return 0;
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen}
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainenstruct client_connection *
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainenclient_connection_create(int fd, int listen_fd, bool ssl)
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen{
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen struct client_connection *conn;
6a866d5d5533cb744c78bc2f1ca47beaee690d2fTimo Sirainen pool_t pool;
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen
6a866d5d5533cb744c78bc2f1ca47beaee690d2fTimo Sirainen pool = pool_alloconly_create("doveadm client", 1024*16);
6a866d5d5533cb744c78bc2f1ca47beaee690d2fTimo Sirainen conn = p_new(pool, struct client_connection, 1);
6a866d5d5533cb744c78bc2f1ca47beaee690d2fTimo Sirainen conn->pool = pool;
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen
be044d4f3d08652d7332cdec5aaf8391474908bbTimo Sirainen if (client_connection_init(conn, fd) < 0)
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen return NULL;
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen doveadm_print_init(DOVEADM_PRINT_TYPE_SERVER);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen conn->name = p_strdup(pool, net_ip2addr(&conn->remote_ip));
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen conn->io = io_add(fd, IO_READ, client_connection_input, conn);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE);
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen conn->output = o_stream_create_fd(fd, (size_t)-1);
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen i_stream_set_name(conn->input, conn->name);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen o_stream_set_name(conn->output, conn->name);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (ssl) {
33502e55a9bf4cafcd184ca9b114c126e420f856Timo Sirainen if (client_connection_init_ssl(conn) < 0) {
33502e55a9bf4cafcd184ca9b114c126e420f856Timo Sirainen client_connection_destroy(&conn);
33502e55a9bf4cafcd184ca9b114c126e420f856Timo Sirainen return NULL;
5bda841ca9e2ddd90702dc7e2a15326e4068066eTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
6a866d5d5533cb744c78bc2f1ca47beaee690d2fTimo Sirainen client_connection_send_auth_handshake(conn, listen_fd);
6a866d5d5533cb744c78bc2f1ca47beaee690d2fTimo Sirainen client_connection_set_proctitle(conn, "");
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen doveadm_print_ostream = conn->output;
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen return conn;
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen}
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainenvoid client_connection_destroy(struct client_connection **_conn)
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen{
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen struct client_connection *conn = *_conn;
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen *_conn = NULL;
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen if (conn->ssl_iostream != NULL)
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen ssl_iostream_destroy(&conn->ssl_iostream);
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen if (conn->output != NULL)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen o_stream_destroy(&conn->output);
33502e55a9bf4cafcd184ca9b114c126e420f856Timo Sirainen
33502e55a9bf4cafcd184ca9b114c126e420f856Timo Sirainen if (conn->io != NULL) {
33502e55a9bf4cafcd184ca9b114c126e420f856Timo Sirainen io_remove(&conn->io);
33502e55a9bf4cafcd184ca9b114c126e420f856Timo Sirainen }
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen if (conn->input != NULL) {
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen i_stream_destroy(&conn->input);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen }
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (conn->fd > 0 && close(conn->fd) < 0)
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen i_error("close(client) failed: %m");
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen pool_unref(&conn->pool);
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen doveadm_print_ostream = NULL;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen doveadm_client = NULL;
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen master_service_client_connection_destroyed(master_service);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainen if (doveadm_verbose_proctitle)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen process_title_set("[idling]");
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen}
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenvoid client_connection_set_proctitle(struct client_connection *conn,
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *text)
37f96554a5734557cd454691d163e602d36384b4Timo Sirainen{
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen const char *str;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (!doveadm_verbose_proctitle)
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen return;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen if (text[0] == '\0')
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen str = t_strdup_printf("[%s]", conn->name);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen else
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen str = t_strdup_printf("[%s %s]", conn->name, text);
031d075daf75b74b286711c1b6f64c3ae70e541bTimo Sirainen process_title_set(str);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen}
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen