bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "imap-urlauth-common.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "array.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "ioloop.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "fdpass.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "istream.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "ostream.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "str.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "strescape.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "eacces-error.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "llist.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "hostpid.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "execv-const.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "env-util.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "var-expand.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "restrict-access.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "master-service.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "master-interface.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include <unistd.h>
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include <sys/wait.h>
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#define IMAP_URLAUTH_PROTOCOL_MAJOR_VERSION 1
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#define IMAP_URLAUTH_PROTOCOL_MINOR_VERSION 0
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#define IMAP_URLAUTH_WORKER_SOCKET "imap-urlauth-worker"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch/* max. length of input lines (URLs) */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#define MAX_INBUF_SIZE 2048
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch/* Disconnect client after idling this many milliseconds */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#define CLIENT_IDLE_TIMEOUT_MSECS (10*60*1000)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#define USER_EXECUTABLE "imap-urlauth-worker"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#define IS_STANDALONE() \
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (getenv(MASTER_IS_PARENT_ENV) == NULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstruct client *imap_urlauth_clients;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschunsigned int imap_urlauth_client_count;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int client_worker_connect(struct client *client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void client_worker_disconnect(struct client *client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void client_worker_input(struct client *client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Boschint client_create(const char *service, const char *username,
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch int fd_in, int fd_out, const struct imap_urlauth_settings *set,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct client **client_r)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct client *client;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *app;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* always use nonblocking I/O */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch net_set_nonblock(fd_in, TRUE);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch net_set_nonblock(fd_out, TRUE);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client = i_new(struct client, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->fd_in = fd_in;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->fd_out = fd_out;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->fd_ctrl = -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->set = set;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client_worker_connect(client) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_free(client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* determine user's special privileges */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_array_init(&client->access_apps, 4);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (username != NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (set->imap_urlauth_submit_user != NULL &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch strcmp(set->imap_urlauth_submit_user, username) == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (set->mail_debug)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_debug("User %s has URLAUTH submit access", username);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch app = "submit+";
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch array_append(&client->access_apps, &app, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (set->imap_urlauth_stream_user != NULL &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch strcmp(set->imap_urlauth_stream_user, username) == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (set->mail_debug)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_debug("User %s has URLAUTH stream access", username);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch app = "stream";
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch array_append(&client->access_apps, &app, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch client->username = i_strdup(username);
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch client->service = i_strdup(service);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi client->output = o_stream_create_fd(fd_out, (size_t)-1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_urlauth_client_count++;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch DLLIST_PREPEND(&imap_urlauth_clients, client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_urlauth_refresh_proctitle();
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *client_r = client;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschvoid client_send_line(struct client *client, const char *fmt, ...)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch va_list va;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ssize_t ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client->output->closed)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch va_start(va, fmt);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch T_BEGIN {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch string_t *str;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str = t_str_new(256);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_vprintfa(str, fmt, va);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(str, "\n");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ret = o_stream_send(client->output,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_data(str), str_len(str));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(ret < 0 || (size_t)ret == str_len(str));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } T_END;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch va_end(va);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int client_worker_connect(struct client *client)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch static const char handshake[] = "VERSION\timap-urlauth-worker\t2\t0\n";
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *socket_path;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ssize_t ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned char data;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch socket_path = t_strconcat(client->set->base_dir,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "/"IMAP_URLAUTH_WORKER_SOCKET, NULL);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client->set->mail_debug)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_debug("Connecting to worker socket %s", socket_path);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->fd_ctrl = net_connect_unix_with_retries(socket_path, 1000);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client->fd_ctrl < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (errno == EACCES) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("imap-urlauth-client: %s",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch eacces_error_get("net_connect_unix",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch socket_path));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("imap-urlauth-client: net_connect_unix(%s) failed: %m",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch socket_path);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* transfer one or two fds */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch data = (client->fd_in == client->fd_out ? '0' : '1');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ret = fd_send(client->fd_ctrl, client->fd_in, &data, sizeof(data));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret > 0 && client->fd_in != client->fd_out) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch data = '0';
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ret = fd_send(client->fd_ctrl, client->fd_out,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch &data, sizeof(data));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret <= 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("fd_send(%s, %d) failed: %m",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch socket_path, client->fd_ctrl);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("fd_send(%s, %d) failed to send byte",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch socket_path, client->fd_ctrl);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_worker_disconnect(client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi client->ctrl_output = o_stream_create_fd(client->fd_ctrl, (size_t)-1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* send protocol version handshake */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (o_stream_send_str(client->ctrl_output, handshake) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("Error sending handshake to imap-urlauth worker: %m");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_worker_disconnect(client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->ctrl_input =
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi i_stream_create_fd(client->fd_ctrl, MAX_INBUF_SIZE);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->ctrl_io =
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch io_add(client->fd_ctrl, IO_READ, client_worker_input, client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschvoid client_worker_disconnect(struct client *client)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->worker_state = IMAP_URLAUTH_WORKER_STATE_INACTIVE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&client->ctrl_io);
be5773cb4d6edae8a5d9f300c3c7375cdd33826eJosef 'Jeff' Sipek o_stream_destroy(&client->ctrl_output);
be5773cb4d6edae8a5d9f300c3c7375cdd33826eJosef 'Jeff' Sipek i_stream_destroy(&client->ctrl_input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client->fd_ctrl >= 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch net_disconnect(client->fd_ctrl);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->fd_ctrl = -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschclient_worker_input_line(struct client *client, const char *response)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *const *apps;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int count, i;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch bool restart;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch string_t *str;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch int ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch switch (client->worker_state) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case IMAP_URLAUTH_WORKER_STATE_INACTIVE:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (strcasecmp(response, "OK") != 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_disconnect(client, "Worker handshake failed");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->worker_state = IMAP_URLAUTH_WORKER_STATE_CONNECTED;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str = t_str_new(256);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(str, "ACCESS\t");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client->username != NULL)
d03a871a77f8ec36f48f5fea98d810e51b186fdbTimo Sirainen str_append_tabescaped(str, client->username);
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch str_append(str, "\t");
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch str_append_tabescaped(str, client->service);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client->set->mail_debug)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(str, "\tdebug");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (array_count(&client->access_apps) > 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(str, "\tapps=");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch apps = array_get(&client->access_apps, &count);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(str, apps[0]);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch for (i = 1; i < count; i++) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(str, ',');
d03a871a77f8ec36f48f5fea98d810e51b186fdbTimo Sirainen str_append_tabescaped(str, apps[i]);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(str, "\n");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ret = o_stream_send(client->ctrl_output,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_data(str), str_len(str));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(ret < 0 || (size_t)ret == str_len(str));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_disconnect(client,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "Failed to send ACCESS control command to worker");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case IMAP_URLAUTH_WORKER_STATE_CONNECTED:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (strcasecmp(response, "OK") != 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_disconnect(client,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "Failed to negotiate access parameters");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->worker_state = IMAP_URLAUTH_WORKER_STATE_ACTIVE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case IMAP_URLAUTH_WORKER_STATE_ACTIVE:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch restart = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (strcasecmp(response, "DISCONNECTED") == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* worker detected client disconnect */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch restart = FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else if (strcasecmp(response, "FINISHED") != 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* unknown response */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_disconnect(client,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "Worker finished with unknown response");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client->set->mail_debug)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_debug("Worker finished successfully");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (restart) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* connect to new worker for accessing different user */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_worker_disconnect(client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client_worker_connect(client) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_disconnect(client,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "Failed to connect to new worker");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* indicate success of "END" command */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_line(client, "OK");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_disconnect(client, "Client disconnected");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch default:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_unreached();
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschvoid client_worker_input(struct client *client)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct istream *input = client->ctrl_input;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *line;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (input->closed) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* disconnected */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_disconnect(client, "Worker disconnected unexpectedly");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch switch (i_stream_read(input)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case -1:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* disconnected */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_disconnect(client, "Worker disconnected unexpectedly");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case -2:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* input buffer full */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_disconnect(client, "Worker sent too large input");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch while ((line = i_stream_next_line(input)) != NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client_worker_input_line(client, line) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschvoid client_destroy(struct client *client, const char *reason)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen i_set_failure_prefix("%s: ", master_service_get_name(master_service));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!client->disconnected) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (reason == NULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch reason = "Connection closed";
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_info("Disconnected: %s", reason);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_urlauth_client_count--;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch DLLIST_REMOVE(&imap_urlauth_clients, client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_idle);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_worker_disconnect(client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch o_stream_destroy(&client->output);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
33a80622828063f5be6f743855d5273fabe8ae58Timo Sirainen fd_close_maybe_stdio(&client->fd_in, &client->fd_out);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch i_free(client->username);
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch i_free(client->service);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch array_free(&client->access_apps);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_free(client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch master_service_client_connection_destroyed(master_service);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_urlauth_refresh_proctitle();
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void client_destroy_timeout(struct client *client)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_destroy(client, NULL);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschvoid client_disconnect(struct client *client, const char *reason)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (client->disconnected)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->disconnected = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_info("Disconnected: %s", reason);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->to_idle = timeout_add(0, client_destroy_timeout, client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschvoid clients_destroy_all(void)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch while (imap_urlauth_clients != NULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_destroy(imap_urlauth_clients, "Server shutting down.");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}