]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/dbus-socket.c
util: rename socket_protocol_{from,to}_name() to ip_protocol_{from,to}_name()
[thirdparty/systemd.git] / src / core / dbus-socket.c
index 21adb64e1500b11a93c0107ebf6c448702851805..37cf9d204c726a66c6e0216398c21858c8065a62 100644 (file)
@@ -1,33 +1,24 @@
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+/* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "alloc-util.h"
 #include "bus-util.h"
 #include "dbus-cgroup.h"
 #include "dbus-execute.h"
+#include "dbus-kill.h"
 #include "dbus-socket.h"
+#include "dbus-util.h"
+#include "fd-util.h"
+#include "ip-protocol-list.h"
+#include "parse-util.h"
+#include "path-util.h"
 #include "socket.h"
+#include "socket-util.h"
 #include "string-util.h"
 #include "unit.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult);
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
+static BUS_DEFINE_PROPERTY_GET(property_get_fdname, "s", Socket, socket_fdname);
 
 static int property_get_listen(
                 sd_bus *bus,
@@ -38,7 +29,6 @@ static int property_get_listen(
                 void *userdata,
                 sd_bus_error *error) {
 
-
         Socket *s = SOCKET(userdata);
         SocketPort *p;
         int r;
@@ -84,25 +74,6 @@ static int property_get_listen(
         return sd_bus_message_close_container(reply);
 }
 
-
-static int property_get_fdname(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *reply,
-                void *userdata,
-                sd_bus_error *error) {
-
-        Socket *s = SOCKET(userdata);
-
-        assert(bus);
-        assert(reply);
-        assert(s);
-
-        return sd_bus_message_append(reply, "s", socket_fdname(s));
-}
-
 const sd_bus_vtable bus_socket_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -140,6 +111,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
         SD_BUS_PROPERTY("MaxConnectionsPerSource", "u", bus_property_get_unsigned, offsetof(Socket, max_connections_per_source), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("MessageQueueMaxMessages", "x", bus_property_get_long, offsetof(Socket, mq_maxmsg), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("MessageQueueMessageSize", "x", bus_property_get_long, offsetof(Socket, mq_msgsize), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("TCPCongestion", "s", NULL, offsetof(Socket, tcp_congestion), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ReusePort", "b",  bus_property_get_bool, offsetof(Socket, reuse_port), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SmackLabel", "s", NULL, offsetof(Socket, smack), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SmackLabelIPIn", "s", NULL, offsetof(Socket, smack_ip_in), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -148,12 +120,13 @@ const sd_bus_vtable bus_socket_vtable[] = {
         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Socket, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), 0),
         SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
+        SD_BUS_PROPERTY("NRefused", "u", bus_property_get_unsigned, offsetof(Socket, n_refused), 0),
         SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
         SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("TriggerLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("UID", "u", NULL, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("GID", "u", NULL, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
@@ -161,26 +134,334 @@ const sd_bus_vtable bus_socket_vtable[] = {
         SD_BUS_VTABLE_END
 };
 
+static inline bool check_size_t_truncation(uint64_t t) {
+        return (size_t) t == t;
+}
+
+static inline const char* socket_protocol_to_string(int32_t i) {
+        if (i == IPPROTO_IP)
+                return "";
+
+        if (!IN_SET(i, IPPROTO_UDPLITE, IPPROTO_SCTP))
+                return NULL;
+
+        return ip_protocol_to_name(i);
+}
+
+static BUS_DEFINE_SET_TRANSIENT(int, "i", int32_t, int, "%" PRIi32);
+static BUS_DEFINE_SET_TRANSIENT(message_queue, "x", int64_t, long, "%" PRIi64);
+static BUS_DEFINE_SET_TRANSIENT_IS_VALID(size_t_check_truncation, "t", uint64_t, size_t, "%" PRIu64, check_size_t_truncation);
+static BUS_DEFINE_SET_TRANSIENT_PARSE(bind_ipv6_only, SocketAddressBindIPv6Only, socket_address_bind_ipv6_only_or_bool_from_string);
+static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(fdname, fdname_is_valid);
+static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(ifname, ifname_valid);
+static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(ip_tos, "i", int32_t, int, "%" PRIi32, ip_tos_to_string_alloc);
+static BUS_DEFINE_SET_TRANSIENT_TO_STRING(socket_protocol, "i", int32_t, int, "%" PRIi32, socket_protocol_to_string);
+
+static int bus_socket_set_transient_property(
+                Socket *s,
+                const char *name,
+                sd_bus_message *message,
+                UnitWriteFlags flags,
+                sd_bus_error *error) {
+
+        SocketExecCommand ci;
+        Unit *u = UNIT(s);
+        int r;
+
+        assert(s);
+        assert(name);
+        assert(message);
+
+        flags |= UNIT_PRIVATE;
+
+        if (streq(name, "Accept"))
+                return bus_set_transient_bool(u, name, &s->accept, message, flags, error);
+
+        if (streq(name, "Writable"))
+                return bus_set_transient_bool(u, name, &s->writable, message, flags, error);
+
+        if (streq(name, "KeepAlive"))
+                return bus_set_transient_bool(u, name, &s->keep_alive, message, flags, error);
+
+        if (streq(name, "NoDelay"))
+                return bus_set_transient_bool(u, name, &s->no_delay, message, flags, error);
+
+        if (streq(name, "FreeBind"))
+                return bus_set_transient_bool(u, name, &s->free_bind, message, flags, error);
+
+        if (streq(name, "Transparent"))
+                return bus_set_transient_bool(u, name, &s->transparent, message, flags, error);
+
+        if (streq(name, "Broadcast"))
+                return bus_set_transient_bool(u, name, &s->broadcast, message, flags, error);
+
+        if (streq(name, "PassCredentials"))
+                return bus_set_transient_bool(u, name, &s->pass_cred, message, flags, error);
+
+        if (streq(name, "PassSecurity"))
+                return bus_set_transient_bool(u, name, &s->pass_sec, message, flags, error);
+
+        if (streq(name, "ReusePort"))
+                return bus_set_transient_bool(u, name, &s->reuse_port, message, flags, error);
+
+        if (streq(name, "RemoveOnStop"))
+                return bus_set_transient_bool(u, name, &s->remove_on_stop, message, flags, error);
+
+        if (streq(name, "SELinuxContextFromNet"))
+                return bus_set_transient_bool(u, name, &s->selinux_context_from_net, message, flags, error);
+
+        if (streq(name, "Priority"))
+                return bus_set_transient_int(u, name, &s->priority, message, flags, error);
+
+        if (streq(name, "IPTTL"))
+                return bus_set_transient_int(u, name, &s->ip_ttl, message, flags, error);
+
+        if (streq(name, "Mark"))
+                return bus_set_transient_int(u, name, &s->mark, message, flags, error);
+
+        if (streq(name, "Backlog"))
+                return bus_set_transient_unsigned(u, name, &s->backlog, message, flags, error);
+
+        if (streq(name, "MaxConnections"))
+                return bus_set_transient_unsigned(u, name, &s->max_connections, message, flags, error);
+
+        if (streq(name, "MaxConnectionsPerSource"))
+                return bus_set_transient_unsigned(u, name, &s->max_connections_per_source, message, flags, error);
+
+        if (streq(name, "KeepAliveProbes"))
+                return bus_set_transient_unsigned(u, name, &s->keep_alive_cnt, message, flags, error);
+
+        if (streq(name, "TriggerLimitBurst"))
+                return bus_set_transient_unsigned(u, name, &s->trigger_limit.burst, message, flags, error);
+
+        if (streq(name, "SocketMode"))
+                return bus_set_transient_mode_t(u, name, &s->socket_mode, message, flags, error);
+
+        if (streq(name, "DirectoryMode"))
+                return bus_set_transient_mode_t(u, name, &s->directory_mode, message, flags, error);
+
+        if (streq(name, "MessageQueueMaxMessages"))
+                return bus_set_transient_message_queue(u, name, &s->mq_maxmsg, message, flags, error);
+
+        if (streq(name, "MessageQueueMessageSize"))
+                return bus_set_transient_message_queue(u, name, &s->mq_msgsize, message, flags, error);
+
+        if (streq(name, "TimeoutUSec"))
+                return bus_set_transient_usec_fix_0(u, name, &s->timeout_usec, message, flags, error);
+
+        if (streq(name, "KeepAliveTimeUSec"))
+                return bus_set_transient_usec(u, name, &s->keep_alive_time, message, flags, error);
+
+        if (streq(name, "KeepAliveIntervalUSec"))
+                return bus_set_transient_usec(u, name, &s->keep_alive_interval, message, flags, error);
+
+        if (streq(name, "DeferAcceptUSec"))
+                return bus_set_transient_usec(u, name, &s->defer_accept, message, flags, error);
+
+        if (streq(name, "TriggerLimitIntervalUSec"))
+                return bus_set_transient_usec(u, name, &s->trigger_limit.interval, message, flags, error);
+
+        if (streq(name, "SmackLabel"))
+                return bus_set_transient_string(u, name, &s->smack, message, flags, error);
+
+        if (streq(name, "SmackLabelIPin"))
+                return bus_set_transient_string(u, name, &s->smack_ip_in, message, flags, error);
+
+        if (streq(name, "SmackLabelIPOut"))
+                return bus_set_transient_string(u, name, &s->smack_ip_out, message, flags, error);
+
+        if (streq(name, "TCPCongestion"))
+                return bus_set_transient_string(u, name, &s->tcp_congestion, message, flags, error);
+
+        if (streq(name, "FileDescriptorName"))
+                return bus_set_transient_fdname(u, name, &s->fdname, message, flags, error);
+
+        if (streq(name, "SocketUser"))
+                return bus_set_transient_user(u, name, &s->user, message, flags, error);
+
+        if (streq(name, "SocketGroup"))
+                return bus_set_transient_user(u, name, &s->group, message, flags, error);
+
+        if (streq(name, "BindIPv6Only"))
+                return bus_set_transient_bind_ipv6_only(u, name, &s->bind_ipv6_only, message, flags, error);
+
+        if (streq(name, "ReceiveBuffer"))
+                return bus_set_transient_size_t_check_truncation(u, name, &s->receive_buffer, message, flags, error);
+
+        if (streq(name, "SendBuffer"))
+                return bus_set_transient_size_t_check_truncation(u, name, &s->send_buffer, message, flags, error);
+
+        if (streq(name, "PipeSize"))
+                return bus_set_transient_size_t_check_truncation(u, name, &s->pipe_size, message, flags, error);
+
+        if (streq(name, "BindToDevice"))
+                return bus_set_transient_ifname(u, name, &s->bind_to_device, message, flags, error);
+
+        if (streq(name, "IPTOS"))
+                return bus_set_transient_ip_tos(u, name, &s->ip_tos, message, flags, error);
+
+        if (streq(name, "SocketProtocol"))
+                return bus_set_transient_socket_protocol(u, name, &s->socket_protocol, message, flags, error);
+
+        if ((ci = socket_exec_command_from_string(name)) >= 0)
+                return bus_set_transient_exec_command(u, name, &s->exec_command[ci], message, flags, error);
+
+        if (streq(name, "Symlinks")) {
+                _cleanup_strv_free_ char **l = NULL;
+                char **p;
+
+                r = sd_bus_message_read_strv(message, &l);
+                if (r < 0)
+                        return r;
+
+                STRV_FOREACH(p, l) {
+                        if (!path_is_absolute(*p))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Symlink path is not absolute: %s", *p);
+                }
+
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        if (strv_isempty(l)) {
+                                s->symlinks = strv_free(s->symlinks);
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=", name);
+                        } else {
+                                _cleanup_free_ char *joined = NULL;
+
+                                r = strv_extend_strv(&s->symlinks, l, true);
+                                if (r < 0)
+                                        return -ENOMEM;
+
+                                joined = strv_join(l, " ");
+                                if (!joined)
+                                        return -ENOMEM;
+
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, joined);
+                        }
+                }
+
+                return 1;
+
+        } else if (streq(name, "Listen")) {
+                const char *t, *a;
+                bool empty = true;
+
+                r = sd_bus_message_enter_container(message, 'a', "(ss)");
+                if (r < 0)
+                        return r;
+
+                while ((r = sd_bus_message_read(message, "(ss)", &t, &a)) > 0) {
+                        _cleanup_free_ SocketPort *p = NULL;
+
+                        p = new(SocketPort, 1);
+                        if (!p)
+                                return log_oom();
+
+                        *p = (SocketPort) {
+                                .fd = -1,
+                                .socket = s,
+                        };
+
+                        p->type = socket_port_type_from_string(t);
+                        if (p->type < 0)
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown Socket type: %s", t);
+
+                        if (p->type != SOCKET_SOCKET) {
+                                if (!path_is_valid(p->path))
+                                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid socket path: %s", t);
+
+                                p->path = strdup(a);
+                                if (!p->path)
+                                        return log_oom();
+
+                                path_simplify(p->path, false);
+
+                        } else if (streq(t, "Netlink")) {
+                                r = socket_address_parse_netlink(&p->address, a);
+                                if (r < 0)
+                                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid netlink address: %s", a);
+
+                        } else {
+                                r = socket_address_parse(&p->address, a);
+                                if (r < 0)
+                                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address: %s", a);
+
+                                p->address.type = socket_address_type_from_string(t);
+                                if (p->address.type < 0)
+                                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address type: %s", t);
+
+                                if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET)
+                                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Address family not supported: %s", a);
+                        }
+
+                        empty = false;
+
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                                LIST_APPEND(port, s->ports, TAKE_PTR(p));
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "Listen%s=%s", t, a);
+                        }
+                }
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
+
+                if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
+                        socket_free_ports(s);
+                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "ListenStream=");
+                }
+
+                return 1;
+        }
+
+        return 0;
+}
+
 int bus_socket_set_property(
                 Unit *u,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         Socket *s = SOCKET(u);
+        int r;
 
         assert(s);
         assert(name);
         assert(message);
 
-        return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
+        assert(s);
+        assert(name);
+        assert(message);
+
+        r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
+        if (r != 0)
+                return r;
+
+        if (u->transient && u->load_state == UNIT_STUB) {
+                /* This is a transient unit, let's load a little more */
+
+                r = bus_socket_set_transient_property(s, name, message, flags, error);
+                if (r != 0)
+                        return r;
+
+                r = bus_exec_context_set_transient_property(u, &s->exec_context, name, message, flags, error);
+                if (r != 0)
+                        return r;
+
+                r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
+                if (r != 0)
+                        return r;
+        }
+
+        return 0;
 }
 
 int bus_socket_commit_properties(Unit *u) {
         assert(u);
 
-        unit_update_cgroup_members_masks(u);
+        unit_invalidate_cgroup_members_masks(u);
         unit_realize_cgroup(u);
 
         return 0;