bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainenstatic unsigned int service_get_backlog(struct service *service)
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen /* as unlikely as it is, avoid overflows */
f6f50f528f6dce764065780bf88ee1acb2422b0aTimo Sirainen if (service->client_limit > INT_MAX / service->process_limit)
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen backlog = service->process_limit * service->client_limit;
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainenservice_file_chown(const struct service_listener *l)
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen if ((uid == (uid_t)-1 || uid == master_uid) &&
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen if (chown(l->set.fileset.set->path, uid, gid) < 0) {
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen service_error(l->service, "chown(%s, %lld, %lld) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int service_unix_listener_listen(struct service_listener *l)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct file_listener_settings *set = l->set.fileset.set;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0;; i++) {
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen fd = net_listen_unix(set->path, service_get_backlog(service));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* looks like the path doesn't exist. */
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "net_listen_unix(%s) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* already in use - see if it really exists.
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen after 3 times just fail here. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fd != -1 || errno != ECONNREFUSED || i >= 3) {
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "Socket already exists: %s",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* delete and try again */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (unlink(set->path) < 0 && errno != ENOENT) {
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "unlink(%s) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int service_fifo_listener_listen(struct service_listener *l)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct file_listener_settings *set = l->set.fileset.set;
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen unsigned int i;
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen for (i = 0;; i++) {
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen service_error(service, "mkfifo(%s) failed: %m",
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen service_error(service, "unlink(%s) failed: %m",
7cbdafb1d58561aff031faf3b10b6f64c2ead49fTimo Sirainen /* open as RDWR, so that even if the last writer closes,
7cbdafb1d58561aff031faf3b10b6f64c2ead49fTimo Sirainen we won't get EOF errors */
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "open(%s) failed: %m", set->path);
009217abb57a24a4076092e8e4e165545747839eStephan Boschsystemd_listen_fd(const struct ip_addr *ip, in_port_t port, int *fd_r)
27f5066c781a8a5ca4eaa5e928c43171f2d986d9Timo Sirainen i_error("sd_listen_fds() failed: %s", strerror(-sd_fds));
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen for (fd = SD_LISTEN_FDS_START; fd <= fd_max; fd++) {
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen if (sd_is_socket_inet(fd, ip->family, SOCK_STREAM, 1, port)) {
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen /* when systemd didn't provide a usable socket,
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen fall back to the regular socket creation code */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int service_inet_listener_listen(struct service_listener *l)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct inet_listener_settings *set = l->set.inetset.set;
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen if (systemd_listen_fd(&l->set.inetset.ip, port, &fd) < 0)
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen fd = net_listen_full(&l->set.inetset.ip, &port, &flags,
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen service_error(service, "listen(%s, %u) failed: %m",
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen l->reuse_port = (flags & NET_LISTEN_FLAG_REUSEPORT) != 0;
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainenint service_listener_listen(struct service_listener *l)
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen switch (l->type) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int service_listen(struct service *service)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(&service->listeners, listeners) {
009217abb57a24a4076092e8e4e165545747839eStephan Boschstatic int get_socket_info(int fd, unsigned int *family, in_port_t *port)
009217abb57a24a4076092e8e4e165545747839eStephan Bosch // FIXME(Stephan): why -1?
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (l < sizeof(struct sockaddr_in))
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (l < sizeof(struct sockaddr_in6))
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainenstatic int services_verify_systemd(struct service_list *service_list)
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen for (fd = SD_LISTEN_FDS_START; fd <= fd_max; fd++) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (sd_is_socket_inet(fd, 0, SOCK_STREAM, 1, 0) > 0) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen array_foreach(&service_list->services, services) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen array_foreach(&(*services)->listeners, listeners) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen i_error("systemd listens on port %d, but it's not configured in Dovecot. Closing.",port);
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (shutdown(fd, SHUT_RDWR) < 0 && errno != ENOTCONN)
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainenstatic int services_listen_master(struct service_list *service_list)
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen path = t_strdup_printf("%s/master", service_list->set->base_dir);
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen service_list->master_fd = net_listen_unix(path, 16);
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen if (service_list->master_fd == -1 && errno == EADDRINUSE) {
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen /* already in use. all the other sockets were fine, so just
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen delete this and retry. */
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen service_list->master_fd = net_listen_unix(path, 16);
9b7a4aa38539a9723586e150b13b14722f965f5eTimo Sirainen i_error("net_listen_unix(%s) failed: %m", path);
cf6118fe7f4fdd4b7153e320ace71c48d29c3fc9Timo Sirainen fd_close_on_exec(service_list->master_fd, TRUE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint services_listen(struct service_list *service_list)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(&service_list->services, services) {
b39dd48436b5894d15ec0c632c8a65f936c2c487Timo Sirainen /* reloading config wants to continue even when we're returning 0. */
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainenstatic bool listener_equals(const struct service_listener *l1,
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen /* We could just keep using the same listener, but it's more
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen likely to cause problems if old process accepts a connection
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen before it knows that it should die. So just always unlink
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen and recreate unix/fifo listeners. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (memcmp(&l1->set.inetset.ip, &l2->set.inetset.ip,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (l1->set.inetset.set->port != l2->set.inetset.set->port)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint services_listen_using(struct service_list *new_service_list,
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen struct service *const *services, *old_service, *new_service;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct service_listener *) new_listeners_arr;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct service_listener *) old_listeners_arr;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_listener *const *new_listeners, *const *old_listeners;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i, j, count, new_count, old_count;
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen /* rescue anvil's UNIX socket listener */
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen new_service = service_lookup_type(new_service_list, SERVICE_TYPE_ANVIL);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen old_service = service_lookup_type(old_service_list, SERVICE_TYPE_ANVIL);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (old_service != NULL && new_service != NULL) {
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen new_listeners = array_get(&new_service->listeners, &new_count);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen old_listeners = array_get(&old_service->listeners, &old_count);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen for (i = 0; i < old_count && i < new_count; i++) {
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (new_listeners[i]->type != old_listeners[i]->type)
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen i_error("Can't change anvil's listeners on the fly");
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen for (i = 0; i < new_count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* first create an arrays of all listeners to make things easier */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen services = array_get(&new_service_list->services, &count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < count; i++)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_append_array(&new_listeners_arr, &services[i]->listeners);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen services = array_get(&old_service_list->services, &count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < count; i++)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_append_array(&old_listeners_arr, &services[i]->listeners);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* then start moving fds */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen new_listeners = array_get(&new_listeners_arr, &new_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_listeners = array_get(&old_listeners_arr, &old_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < new_count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (j = 0; j < old_count; j++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* close what's left */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (j = 0; j < old_count; j++) {
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen i_unlink(old_listeners[j]->set.fileset.set->path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* and let services_listen() deal with the remaining fds */