config-connection.c revision 50fe5e053d565b40b0ed2cc7a64b6b98971c0305
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2005-2009 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "llist.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "istream.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ostream.h"
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen#include "settings-parser.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "master-service.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "config-request.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "config-parser.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "config-connection.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include <stdlib.h>
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen#include <unistd.h>
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen#define MAX_INBUF_SIZE 1024
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen#define CONFIG_CLIENT_PROTOCOL_MAJOR_VERSION 1
5411e6f71afb0f753cdf831f4da4ee73e928796eTimo Sirainen#define CONFIG_CLIENT_PROTOCOL_MINOR_VERSION 0
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainenstruct config_connection {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct config_connection *prev, *next;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct istream *input;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ostream *output;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct io *io;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int version_received:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int handshaked:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct config_connection *config_connections = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic const char *const *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenconfig_connection_next_line(struct config_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *line;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen line = i_stream_next_line(conn->input);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (line == NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen return t_strsplit(line, "\t");
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen}
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainenstatic void
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenconfig_request_output(const char *key, const char *value,
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen enum config_key_type type ATTR_UNUSED, void *context)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ostream *output = context;
c4900d31385344bfadaee53a897daeafdb3063d8Timo Sirainen const char *p;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send_str(output, key);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send_str(output, "=");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while ((p = strchr(value, '\n')) != NULL) {
34a45b80c8ed18861c6e343fe40adbe360fc6badTimo Sirainen o_stream_send(output, value, p-value);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send(output, SETTING_STREAM_LF_CHAR, 1);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen value = p+1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send_str(output, value);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send_str(output, "\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int config_connection_request(struct config_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct config_filter filter;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *path, *error, *module = "";
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* [<args>] */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen memset(&filter, 0, sizeof(filter));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen for (; *args != NULL; args++) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strncmp(*args, "service=", 8) == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen filter.service = *args + 8;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else if (strncmp(*args, "module=", 7) == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen module = *args + 7;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else if (strncmp(*args, "lip=", 4) == 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (net_addr2ip(*args + 4, &filter.local_net) == 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen filter.local_bits =
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen IPADDR_IS_V4(&filter.local_net) ?
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen 32 : 128;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (strncmp(*args, "rip=", 4) == 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (net_addr2ip(*args + 4, &filter.remote_net) == 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen filter.remote_bits =
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen IPADDR_IS_V4(&filter.remote_net) ?
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen 32 : 128;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (strcmp(module, "master") == 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* master reads configuration only when reloading settings */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen path = master_service_get_config_path(master_service);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (config_parse_file(path, TRUE, &error) <= 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_send_str(conn->output,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen t_strconcat("ERROR ", error, "\n", NULL));
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen config_connection_destroy(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen o_stream_cork(conn->output);
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen if (config_request_handle(&filter, module, CONFIG_DUMP_SCOPE_SET, 0,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen config_request_output, conn->output) < 0) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen config_connection_destroy(conn);
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send_str(conn->output, "\n");
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen o_stream_uncork(conn->output);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return 0;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic void config_connection_input(void *context)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct config_connection *conn = context;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen const char *const *args, *line;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen switch (i_stream_read(conn->input)) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen case -2:
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_error("BUG: Config client connection sent too much data");
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen config_connection_destroy(conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case -1:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen config_connection_destroy(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->version_received) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen line = i_stream_next_line(conn->input);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (line == NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strncmp(line, "VERSION\tconfig\t", 15) != 0 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen atoi(t_strcut(line + 15, '\t')) !=
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen CONFIG_CLIENT_PROTOCOL_MAJOR_VERSION) {
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen i_error("Config client not compatible with this server "
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen "(mixed old and new binaries?)");
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen config_connection_destroy(conn);
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen return;
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen }
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen conn->version_received = TRUE;
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while ((args = config_connection_next_line(conn)) != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (args[0] == NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen continue;
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen if (strcmp(args[0], "REQ") == 0) {
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen if (config_connection_request(conn, args + 1) < 0)
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen break;
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstruct config_connection *config_connection_create(int fd)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct config_connection *conn;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn = i_new(struct config_connection, 1);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->fd = fd;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->io = io_add(fd, IO_READ, config_connection_input, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DLLIST_PREPEND(&config_connections, conn);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen return conn;
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid config_connection_destroy(struct config_connection *conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen DLLIST_REMOVE(&config_connections, conn);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen io_remove(&conn->io);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_stream_destroy(&conn->input);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen o_stream_destroy(&conn->output);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen if (close(conn->fd) < 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("close(config conn) failed: %m");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_free(conn);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen master_service_client_connection_destroyed(master_service);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid config_connections_destroy_all(void)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen while (config_connections != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen config_connection_destroy(config_connections);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen