doveadm-util.c revision 250a06cde50c4004ac1cc72279b75a229a7f90f5
5e0ce63bb65db34d7f48b34bbb5545fa791781c4Timo Sirainen/* Copyright (c) 2009-2013 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "array.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "net.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "time-util.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "master-service.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "module-dir.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "doveadm-settings.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "doveadm-mail.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "doveadm-util.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <time.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <dirent.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <sys/stat.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenbool doveadm_verbose = FALSE, doveadm_debug = FALSE, doveadm_server = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic struct module *modules = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid doveadm_load_modules(void)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct module_dir_load_settings mod_set;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* some doveadm plugins have dependencies to mail plugins. we can load
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen only those whose dependencies have been loaded earlier, the rest are
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ignored. */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen memset(&mod_set, 0, sizeof(mod_set));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mod_set.abi_version = DOVECOT_ABI_VERSION;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mod_set.require_init_funcs = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mod_set.debug = doveadm_debug;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen mod_set.ignore_dlopen_errors = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen modules = module_dir_load_missing(modules, DOVEADM_MODULEDIR,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen NULL, &mod_set);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen module_dir_init(modules);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid doveadm_unload_modules(void)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen module_dir_unload(&modules);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenbool doveadm_has_unloaded_plugin(const char *name)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct module *module;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen DIR *dir;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct dirent *d;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *plugin_name;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int name_len = strlen(name);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen bool found = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* first check that it's not actually loaded */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (module = modules; module != NULL; module = module->next) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (strcmp(module_get_plugin_name(module), name) == 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen dir = opendir(DOVEADM_MODULEDIR);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (dir == NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return FALSE;
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen while ((d = readdir(dir)) != NULL) {
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen plugin_name = module_file_get_name(d->d_name);
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen if (strncmp(plugin_name, "doveadm_", 8) == 0)
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen plugin_name += 8;
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen if (strncmp(plugin_name, name, name_len) == 0 &&
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen (plugin_name[name_len] == '\0' ||
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen strcmp(plugin_name + name_len, "_plugin") == 0)) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen found = TRUE;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen break;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen (void)closedir(dir);
af81f402ddc897c74c1e85abd02879612ce44882Timo Sirainen return found;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenconst char *unixdate2str(time_t timestamp)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return t_strflocaltime("%Y-%m-%d %H:%M:%S", timestamp);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenconst char *doveadm_plugin_getenv(const char *name)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen const char *const *envs;
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen unsigned int i, count;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen if (!array_is_created(&doveadm_settings->plugin_envs))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen envs = array_get(&doveadm_settings->plugin_envs, &count);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (i = 0; i < count; i += 2) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (strcmp(envs[i], name) == 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return envs[i+1];
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic bool
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenparse_hostport(const char *str, unsigned int default_port,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char **host_r, unsigned int *port_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *p;
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen
af81f402ddc897c74c1e85abd02879612ce44882Timo Sirainen /* host:port */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen p = strrchr(str, ':');
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (p == NULL && default_port != 0) {
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen *host_r = str;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *port_r = default_port;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen } else {
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen if (p == NULL || str_to_uint(p+1, port_r) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *host_r = t_strdup_until(str, p);
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen }
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen /* there is any '/' character (unlikely to be found from host names),
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen assume ':' is part of a file path */
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen if (strchr(str, '/') != NULL)
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen return FALSE;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen return TRUE;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen}
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainenint doveadm_connect_with_default_port(const char *path,
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen unsigned int default_port)
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen{
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen struct stat st;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen const char *host;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct ip_addr *ips;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int port, ips_count;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen int fd, ret;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (parse_hostport(path, default_port, &host, &port) &&
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen stat(path, &st) < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* it's a host:port, connect via TCP */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = net_gethostbyname(host, &ips, &ips_count);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (ret != 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_fatal("Lookup of host %s failed: %s",
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen host, net_gethosterror(ret));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fd = net_connect_ip_blocking(&ips[0], port, NULL);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (fd == -1) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_fatal("connect(%s:%u) failed: %m",
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen net_ip2addr(&ips[0]), port);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else {
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen fd = net_connect_unix(path);
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen if (fd == -1)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_fatal("net_connect_unix(%s) failed: %m", path);
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return fd;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainenint doveadm_connect(const char *path)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return doveadm_connect_with_default_port(path, 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen