bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include "lib.h"
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include "array.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
b1f37113a5760bee842c5a7678bb5fa6f5bd8b60Timo Sirainen#include "time-util.h"
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include "master-service.h"
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include "module-dir.h"
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include "doveadm-settings.h"
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include "doveadm-mail.h"
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include "doveadm-util.h"
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include <time.h>
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include <dirent.h>
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include <sys/stat.h>
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi#include <ctype.h>
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
530b5909a99e7575156496f1b8e4d1ff5b058484Timo Sirainen#define DOVEADM_TCP_CONNECT_TIMEOUT_SECS 30
530b5909a99e7575156496f1b8e4d1ff5b058484Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainenbool doveadm_verbose = FALSE, doveadm_debug = FALSE, doveadm_server = FALSE;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenstatic struct module *modules = NULL;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenvoid doveadm_load_modules(void)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen{
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen struct module_dir_load_settings mod_set;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen /* some doveadm plugins have dependencies to mail plugins. we can load
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen only those whose dependencies have been loaded earlier, the rest are
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen ignored. */
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&mod_set);
bd63b5b860658b01b1f46f26d406e1e4a9dc019aTimo Sirainen mod_set.abi_version = DOVECOT_ABI_VERSION;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen mod_set.require_init_funcs = TRUE;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen mod_set.debug = doveadm_debug;
70ac869db925653b57f721cd045c467612fd5ee9Timo Sirainen mod_set.ignore_dlopen_errors = TRUE;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen modules = module_dir_load_missing(modules, DOVEADM_MODULEDIR,
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen NULL, &mod_set);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen module_dir_init(modules);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen}
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenvoid doveadm_unload_modules(void)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen{
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen module_dir_unload(&modules);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen}
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenbool doveadm_has_unloaded_plugin(const char *name)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen{
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen struct module *module;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen DIR *dir;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen struct dirent *d;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen const char *plugin_name;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t name_len = strlen(name);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen bool found = FALSE;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen /* first check that it's not actually loaded */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen for (module = modules; module != NULL; module = module->next) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (strcmp(module_get_plugin_name(module), name) == 0)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return FALSE;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen dir = opendir(DOVEADM_MODULEDIR);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (dir == NULL)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return FALSE;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen while ((d = readdir(dir)) != NULL) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen plugin_name = module_file_get_name(d->d_name);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (strncmp(plugin_name, "doveadm_", 8) == 0)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen plugin_name += 8;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (strncmp(plugin_name, name, name_len) == 0 &&
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen (plugin_name[name_len] == '\0' ||
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen strcmp(plugin_name + name_len, "_plugin") == 0)) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen found = TRUE;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen break;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen (void)closedir(dir);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return found;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen}
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenconst char *unixdate2str(time_t timestamp)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen{
b1f37113a5760bee842c5a7678bb5fa6f5bd8b60Timo Sirainen return t_strflocaltime("%Y-%m-%d %H:%M:%S", timestamp);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen}
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenconst char *doveadm_plugin_getenv(const char *name)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen{
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen const char *const *envs;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen unsigned int i, count;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (!array_is_created(&doveadm_settings->plugin_envs))
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return NULL;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen envs = array_get(&doveadm_settings->plugin_envs, &count);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen for (i = 0; i < count; i += 2) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (strcmp(envs[i], name) == 0)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return envs[i+1];
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return NULL;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen}
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainenstatic int
009217abb57a24a4076092e8e4e165545747839eStephan Boschdoveadm_tcp_connect_port(const char *host, in_port_t port)
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen{
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen struct ip_addr *ips;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen unsigned int ips_count;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen int ret, fd;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen
530b5909a99e7575156496f1b8e4d1ff5b058484Timo Sirainen alarm(DOVEADM_TCP_CONNECT_TIMEOUT_SECS);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen ret = net_gethostbyname(host, &ips, &ips_count);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen if (ret != 0) {
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen i_fatal("Lookup of host %s failed: %s",
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen host, net_gethosterror(ret));
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen }
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen fd = net_connect_ip_blocking(&ips[0], port, NULL);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen if (fd == -1) {
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen i_fatal("connect(%s:%u) failed: %m",
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen net_ip2addr(&ips[0]), port);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen }
530b5909a99e7575156496f1b8e4d1ff5b058484Timo Sirainen alarm(0);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen return fd;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen}
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen
009217abb57a24a4076092e8e4e165545747839eStephan Boschint doveadm_tcp_connect(const char *target, in_port_t default_port)
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen{
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen const char *host;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen
7c925149e49f7cce41c90d562ff3835b66ddca29Timo Sirainen if (net_str2hostport(target, default_port, &host, &port) < 0) {
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen i_fatal("Port not known for %s. Either set proxy_port "
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen "or use %s:port", target, target);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen }
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen return doveadm_tcp_connect_port(host, port);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen}
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainenint doveadm_connect_with_default_port(const char *path,
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t default_port)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen{
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen int fd;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen /* we'll assume UNIX sockets typically have an absolute path,
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen or at the very least '/' somewhere. */
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen if (strchr(path, '/') == NULL)
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen fd = doveadm_tcp_connect(path, default_port);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen else {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen fd = net_connect_unix(path);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (fd == -1)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen i_fatal("net_connect_unix(%s) failed: %m", path);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return fd;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen}
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainenint doveadm_connect(const char *path)
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen{
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen return doveadm_connect_with_default_port(path, 0);
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen}
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomiint i_strccdascmp(const char *a, const char *b)
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi{
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen while(*a != '\0' && *b != '\0') {
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi if ((*a == ' ' || *a == '-') && *a != *b && *b != ' ' && *b != '-') {
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi if (i_toupper(*(a+1)) == *(b)) a++;
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi else break;
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi } else if ((*b == ' ' || *b == '-') && *a != *b && *a != ' ' && *a != '-') {
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi if (*a == i_toupper(*(b+1))) b++;
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi else break;
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi } else if (!((*a == ' ' || *a == '-') &&
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi (*b == ' ' || *b == '-')) &&
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi (*a != *b)) break;
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi a++; b++;
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi }
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi return *a-*b;
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi}
a23210844b06c53ebca34b162f3a268d5f1cd4d1Aki Tuomi
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomichar doveadm_log_type_to_char(enum log_type type)
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi{
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi switch(type) {
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case LOG_TYPE_DEBUG:
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi return '\x01';
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case LOG_TYPE_INFO:
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi return '\x02';
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case LOG_TYPE_WARNING:
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi return '\x03';
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case LOG_TYPE_ERROR:
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi return '\x04';
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case LOG_TYPE_FATAL:
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi return '\x05';
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case LOG_TYPE_PANIC:
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi return '\x06';
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi default:
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi i_unreached();
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi }
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi}
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomibool doveadm_log_type_from_char(char c, enum log_type *type_r)
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi{
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi switch(c) {
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case '\x01':
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi *type_r = LOG_TYPE_DEBUG;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi break;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case '\x02':
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi *type_r = LOG_TYPE_INFO;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi break;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case '\x03':
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi *type_r = LOG_TYPE_WARNING;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi break;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case '\x04':
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi *type_r = LOG_TYPE_ERROR;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi break;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case '\x05':
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi *type_r = LOG_TYPE_FATAL;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi break;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi case '\x06':
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi *type_r = LOG_TYPE_PANIC;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi break;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi default:
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi *type_r = LOG_TYPE_WARNING;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi return FALSE;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi }
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi return TRUE;
c9dd53f7180a78668cbc1e6eb34d5b1722beccb9Aki Tuomi}