server-connection.c revision 7d359c1719bf6ff228a96c66d27f5cfa239cb31d
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2010-2012 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "array.h"
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen#include "base64.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen#include "network.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "istream.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "ostream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include "strescape.h"
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include "master-service.h"
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include "master-service-settings.h"
3ed2d0f6b5e67e2663d44489d9da3176823789a8Timo Sirainen#include "settings-parser.h"
65f8fb656051f1059f7b5a2da9c5555adcc30439Timo Sirainen#include "doveadm-print.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "doveadm-util.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "doveadm-server.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "doveadm-settings.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "server-connection.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include <unistd.h>
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define MAX_INBUF_SIZE (1024*32)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenenum server_reply_state {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen SERVER_REPLY_STATE_DONE = 0,
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen SERVER_REPLY_STATE_PRINT,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen SERVER_REPLY_STATE_RET
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenstruct server_connection {
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen struct doveadm_server *server;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen pool_t pool;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct doveadm_settings *set;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen int fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct io *io;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen struct istream *input;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen struct ostream *output;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen const char *delayed_cmd;
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainen server_cmd_callback_t *callback;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen void *context;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen enum server_reply_state state;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int handshaked:1;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int authenticated:1;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int streaming:1;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen};
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenstatic struct server_connection *printing_conn = NULL;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainenstatic void server_connection_input(struct server_connection *conn);
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainenstatic void print_connection_released(void)
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen{
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen struct doveadm_server *server = printing_conn->server;
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen struct server_connection *const *conns;
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen unsigned int i, count;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen printing_conn = NULL;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
57a8c6a95e4bce3eeaba36985adb81c07dd683ffTimo Sirainen conns = array_get(&server->connections, &count);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen for (i = 0; i < count; i++) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (conns[i]->io != NULL)
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conns[i]->io = io_add(conns[i]->fd, IO_READ,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen server_connection_input, conns[i]);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen server_connection_input(conns[i]);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen if (printing_conn != NULL)
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen break;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen }
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen}
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainenstatic void
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenserver_connection_callback(struct server_connection *conn,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen enum server_cmd_reply reply)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen{
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen server_cmd_callback_t *callback = conn->callback;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
f1743785713e7632459d623d5df2108f4b93accbTimo Sirainen conn->callback = NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen callback(reply, conn->context);
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainenstatic void stream_data(string_t *str, const unsigned char *data, size_t size)
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen{
8d630c15a8ed6f85553467c3a231a273defca5f6Timo Sirainen const char *text;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen str_truncate(str, 0);
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen str_append_n(str, data, size);
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen text = str_tabunescape(str_c_modifiable(str));
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen doveadm_print_stream(text, strlen(text));
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void server_flush_field(struct server_connection *conn, string_t *str,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const unsigned char *data, size_t size)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (conn->streaming) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen conn->streaming = FALSE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen stream_data(str, data, size);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen doveadm_print_stream("", 0);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen } else {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen const char *text;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen str_truncate(str, 0);
c29216637957d4b3126c6929ac5ba98138256ce1Timo Sirainen str_append_n(str, data, size);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen text = str_tabunescape(str_c_modifiable(str));
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen doveadm_print(text);
e03d986a74128f5ba30fcfda9f6e36578f5d8decTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainenstatic void
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainenserver_handle_input(struct server_connection *conn,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen const unsigned char *data, size_t size)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen{
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen string_t *str;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen size_t i, start;
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainen
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainen if (printing_conn == conn) {
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen /* continue printing */
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen } else if (printing_conn == NULL) {
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen printing_conn = conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen /* someone else is printing. don't continue until it
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen goes away */
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen io_remove(&conn->io);
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen return;
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen }
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen if (data[size-1] == '\001') {
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen /* last character is an escape */
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen size--;
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen str = t_str_new(128);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen for (i = start = 0; i < size; i++) {
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen if (data[i] == '\n') {
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen if (i != start)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen i_error("doveadm server sent broken input");
2584e86cc2d8c31ba30a4109cf4ba09d1e37e28aTimo Sirainen conn->state = SERVER_REPLY_STATE_RET;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen i_stream_skip(conn->input, i + 1);
4b41116563110d00330896a568eff1078c382827Timo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainen print_connection_released();
4b41116563110d00330896a568eff1078c382827Timo Sirainen return;
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen }
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen if (data[i] == '\t') {
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen server_flush_field(conn, str, data + start, i - start);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen start = i + 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (start != size) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen conn->streaming = TRUE;
b2c1349cf07410aefab0f5b17153af9e5cfcf48fTimo Sirainen stream_data(str, data + start, size - start);
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_skip(conn->input, size);
dbe64f3893616a4005c8946be75d2dc8f6823d72Timo Sirainen}
8a13b020f90e080570658b18c042e7e352c8b14fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void server_connection_authenticated(struct server_connection *conn)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen conn->authenticated = TRUE;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (conn->delayed_cmd != NULL) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen o_stream_send_str(conn->output, conn->delayed_cmd);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen conn->delayed_cmd = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenserver_connection_authenticate(struct server_connection *conn)
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen{
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen string_t *plain = t_str_new(128);
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen string_t *cmd = t_str_new(128);
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*conn->set->doveadm_password == '\0') {
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen i_error("doveadm_password not set, "
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen "can't authenticate to remote server");
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen return -1;
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen }
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen str_append_c(plain, '\0');
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen str_append(plain, "doveadm");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append_c(plain, '\0');
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen str_append(plain, conn->set->doveadm_password);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(cmd, "PLAIN\t");
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen base64_encode(plain->data, plain->used, cmd);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen str_append_c(cmd, '\n');
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen o_stream_send(conn->output, cmd->data, cmd->used);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return 0;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen}
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainenstatic void server_connection_input(struct server_connection *conn)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen{
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen const unsigned char *data;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen size_t size;
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen const char *line;
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen enum server_cmd_reply reply;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (!conn->handshaked) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if ((line = i_stream_read_next_line(conn->input)) == NULL) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (conn->input->eof || conn->input->stream_errno != 0)
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen server_connection_destroy(&conn);
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen return;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen conn->handshaked = TRUE;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen if (strcmp(line, "+") == 0)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen server_connection_authenticated(conn);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen else if (strcmp(line, "-") == 0) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (server_connection_authenticate(conn) < 0) {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen server_connection_destroy(&conn);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen return;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen }
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen return;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen } else {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen i_error("doveadm server sent invalid handshake: %s",
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen line);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen server_connection_destroy(&conn);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen return;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen }
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen }
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (i_stream_read(conn->input) == -1) {
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen /* disconnected */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen server_connection_destroy(&conn);
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen return;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen }
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen if (!conn->authenticated) {
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen if ((line = i_stream_next_line(conn->input)) == NULL)
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen return;
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen if (strcmp(line, "+") == 0)
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen server_connection_authenticated(conn);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen else {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen i_error("doveadm authentication failed (%s)", line+1);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen server_connection_destroy(&conn);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen }
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen data = i_stream_get_data(conn->input, &size);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen if (size == 0)
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen return;
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen switch (conn->state) {
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen case SERVER_REPLY_STATE_DONE:
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen i_error("doveadm server sent unexpected input");
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen server_connection_destroy(&conn);
6b0d8106ae51ffc6ce45636b34d2e21cbefca7fdTimo Sirainen return;
6b0d8106ae51ffc6ce45636b34d2e21cbefca7fdTimo Sirainen case SERVER_REPLY_STATE_PRINT:
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen server_handle_input(conn, data, size);
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen if (conn->state != SERVER_REPLY_STATE_RET)
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen break;
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen /* fall through */
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen case SERVER_REPLY_STATE_RET:
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen line = i_stream_next_line(conn->input);
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen if (line == NULL)
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen return;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (line[0] == '+')
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen server_connection_callback(conn, SERVER_CMD_REPLY_OK);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen else if (line[0] == '-') {
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen reply = strcmp(line+1, "NOUSER") == 0 ?
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen SERVER_CMD_REPLY_UNKNOWN_USER :
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen SERVER_CMD_REPLY_FAIL;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen server_connection_callback(conn, reply);
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen } else
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_error("doveadm server sent broken input");
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* we're finished, close the connection */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen server_connection_destroy(&conn);
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen break;
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen }
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int server_connection_read_settings(struct server_connection *conn)
c0225f7f6b43d34dc58c17d3304f0fd60ab89894Timo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const struct setting_parser_info *set_roots[] = {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen &doveadm_setting_parser_info,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen NULL
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen };
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen struct master_service_settings_input input;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen struct master_service_settings_output output;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const char *error;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen unsigned int port;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen void *set;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen memset(&input, 0, sizeof(input));
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen input.roots = set_roots;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen input.service = "doveadm";
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen (void)net_getsockname(conn->fd, &input.local_ip, &port);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen (void)net_getpeername(conn->fd, &input.remote_ip, &port);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (master_service_settings_read(master_service, &input,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen &output, &error) < 0) {
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainen i_error("Error reading configuration: %s", error);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return -1;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen }
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen set = master_service_settings_get_others(master_service)[0];
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen conn->set = settings_dup(&doveadm_setting_parser_info, set, conn->pool);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen return 0;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen}
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstruct server_connection *
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainenserver_connection_create(struct doveadm_server *server)
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen{
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen#define DOVEADM_SERVER_HANDSHAKE "VERSION\tdoveadm-server\t1\t0\n"
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct server_connection *conn;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen pool_t pool;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen pool = pool_alloconly_create("doveadm server connection", 1024*16);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen conn = p_new(pool, struct server_connection, 1);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen conn->pool = pool;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen conn->server = server;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen conn->fd = doveadm_connect(server->name);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen net_set_nonblock(conn->fd, TRUE);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen conn->io = io_add(conn->fd, IO_READ, server_connection_input, conn);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE, FALSE);
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen conn->state = SERVER_REPLY_STATE_DONE;
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen o_stream_send_str(conn->output, DOVEADM_SERVER_HANDSHAKE);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen array_append(&conn->server->connections, &conn, 1);
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen server_connection_read_settings(conn);
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainen return conn;
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainen}
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainen
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainenvoid server_connection_destroy(struct server_connection **_conn)
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainen{
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainen struct server_connection *conn = *_conn;
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen struct server_connection *const *conns;
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen unsigned int i, count;
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen *_conn = NULL;
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen conns = array_get(&conn->server->connections, &count);
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen for (i = 0; i < count; i++) {
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen if (conns[i] == conn) {
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen array_delete(&conn->server->connections, i, 1);
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen break;
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen }
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen }
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen if (conn->callback != NULL) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen server_connection_callback(conn,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen SERVER_CMD_REPLY_INTERNAL_FAILURE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (printing_conn == conn)
e4c90f0b88e40a8f92b8f5e1f1a3ea701e5c965cTimo Sirainen print_connection_released();
defb12ecd360df672ffb2f4dbf4d1218a0a9549cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_destroy(&conn->input);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen o_stream_destroy(&conn->output);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (conn->io != NULL)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen io_remove(&conn->io);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (close(conn->fd) < 0)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_error("close(server) failed: %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pool_unref(&conn->pool);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainen
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainenstruct doveadm_server *
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainenserver_connection_get_server(struct server_connection *conn)
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen{
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen return conn->server;
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen}
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainenvoid server_connection_cmd(struct server_connection *conn, const char *line,
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen server_cmd_callback_t *callback, void *context)
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen{
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen i_assert(conn->delayed_cmd == NULL);
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen conn->state = SERVER_REPLY_STATE_PRINT;
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen if (conn->authenticated)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen o_stream_send_str(conn->output, line);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen else
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen conn->delayed_cmd = p_strdup(conn->pool, line);
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen conn->callback = callback;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen conn->context = context;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenbool server_connection_is_idle(struct server_connection *conn)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return conn->callback == NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen