From 9c0320e7abda82f78c448c2b173d2809dac6bfb1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 23 Dec 2017 18:47:33 +0900 Subject: core: implement transient socket unit --- src/core/dbus-socket.c | 486 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 485 insertions(+), 1 deletion(-) (limited to 'src/core/dbus-socket.c') diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 930b7fa87d..6c5d5944fc 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -22,10 +22,17 @@ #include "bus-util.h" #include "dbus-cgroup.h" #include "dbus-execute.h" +#include "dbus-kill.h" #include "dbus-socket.h" +#include "fd-util.h" +#include "parse-util.h" +#include "path-util.h" #include "socket.h" +#include "socket-util.h" #include "string-util.h" #include "unit.h" +#include "user-util.h" +#include "utf8.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); @@ -141,6 +148,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), @@ -162,6 +170,457 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_VTABLE_END }; +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 (STR_IN_SET(name, + "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast", + "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet")) { + int b; + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (streq(name, "Accept")) + s->accept = b; + else if (streq(name, "Writable")) + s->writable = b; + else if (streq(name, "KeepAlive")) + s->keep_alive = b; + else if (streq(name, "NoDelay")) + s->no_delay = b; + else if (streq(name, "FreeBind")) + s->free_bind = b; + else if (streq(name, "Transparent")) + s->transparent = b; + else if (streq(name, "Broadcast")) + s->broadcast = b; + else if (streq(name, "PassCredentials")) + s->pass_cred = b; + else if (streq(name, "PassSecurity")) + s->pass_sec = b; + else if (streq(name, "ReusePort")) + s->reuse_port = b; + else if (streq(name, "RemoveOnStop")) + s->remove_on_stop = b; + else /* "SELinuxContextFromNet" */ + s->selinux_context_from_net = b; + + unit_write_settingf(u, flags, name, "%s=%s", name, yes_no(b)); + } + + return 1; + + } else if (STR_IN_SET(name, "Priority", "IPTTL", "Mark")) { + int32_t i; + + r = sd_bus_message_read(message, "i", &i); + if (r < 0) + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (streq(name, "Priority")) + s->priority = i; + else if (streq(name, "IPTTL")) + s->ip_ttl = i; + else /* "Mark" */ + s->mark = i; + + unit_write_settingf(u, flags, name, "%s=%i", name, i); + } + + return 1; + + } else if (streq(name, "IPTOS")) { + _cleanup_free_ char *str = NULL; + int32_t i; + + r = sd_bus_message_read(message, "i", &i); + if (r < 0) + return r; + + r = ip_tos_to_string_alloc(i, &str); + if (r < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %i", name, i); + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + s->ip_tos = i; + + unit_write_settingf(u, flags, name, "%s=%s", name, str); + } + + return 1; + + } else if (streq(name, "SocketProtocol")) { + int32_t i; + + r = sd_bus_message_read(message, "i", &i); + if (r < 0) + return r; + + if (!IN_SET(i, IPPROTO_UDPLITE, IPPROTO_SCTP)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %i", name, i); + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + s->socket_protocol = i; + unit_write_settingf(u, flags, name, "%s=%s", name, i == IPPROTO_UDPLITE ? "udplite" : "sctp"); + } + + return 1; + + } else if (STR_IN_SET(name, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst")) { + uint32_t n; + + r = sd_bus_message_read(message, "u", &n); + if (r < 0) + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (streq(name, "Backlog")) + s->backlog = n; + else if (streq(name, "MaxConnections")) + s->max_connections = n; + else if (streq(name, "MaxConnectionsPerSource")) + s->max_connections_per_source = n; + else if (streq(name, "KeepAliveProbes")) + s->keep_alive_cnt = n; + else /* "TriggerLimitBurst" */ + s->trigger_limit.burst = n; + + unit_write_settingf(u, flags, name, "%s=%u", name, n); + } + + return 1; + + } else if (STR_IN_SET(name, "SocketMode", "DirectoryMode")) { + mode_t m; + + r = sd_bus_message_read(message, "u", &m); + if (r < 0) + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (streq(name, "SocketMode")) + s->socket_mode = m; + else /* "DirectoryMode" */ + s->directory_mode = m; + + unit_write_settingf(u, flags, name, "%s=%040o", name, m); + } + + return 1; + + } else if (STR_IN_SET(name, "MessageQueueMaxMessages", "MessageQueueMessageSize")) { + int64_t n; + + r = sd_bus_message_read(message, "x", &n); + if (r < 0) + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (streq(name, "MessageQueueMaxMessages")) + s->mq_maxmsg = (long) n; + else /* "MessageQueueMessageSize" */ + s->mq_msgsize = (long) n; + + unit_write_settingf(u, flags, name, "%s=%" PRIi64, name, n); + } + + return 1; + + } else if (STR_IN_SET(name, "TimeoutUSec", "KeepAliveTimeUSec", "KeepAliveIntervalUSec", "DeferAcceptUSec", "TriggerLimitIntervalUSec")) { + usec_t t; + + r = sd_bus_message_read(message, "t", &t); + if (r < 0) + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (streq(name, "TimeoutUSec")) + s->timeout_usec = t ?: USEC_INFINITY; + else if (streq(name, "KeepAliveTimeUSec")) + s->keep_alive_time = t; + else if (streq(name, "KeepAliveIntervalUSec")) + s->keep_alive_interval = t; + else if (streq(name, "DeferAcceptUSec")) + s->defer_accept = t; + else /* "TriggerLimitIntervalUSec" */ + s->trigger_limit.interval = t; + + unit_write_settingf(u, flags, name, "%s=" USEC_FMT, name, t); + } + + return 1; + + } else if (STR_IN_SET(name, "ReceiveBuffer", "SendBuffer", "PipeSize")) { + uint64_t t; + + r = sd_bus_message_read(message, "t", &t); + if (r < 0) + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (streq(name, "ReceiveBuffer")) + s->receive_buffer = t; + else if (streq(name, "SendBuffer")) + s->send_buffer = t; + else /* "PipeSize" */ + s->pipe_size = t; + + unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, t); + } + + return 1; + + } else if (STR_IN_SET(name, "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion")) { + const char *n; + + r = sd_bus_message_read(message, "s", &n); + if (r < 0) + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + + if (streq(name, "SmackLabel")) + r = free_and_strdup(&s->smack, empty_to_null(n)); + else if (streq(name, "SmackLabelIPin")) + r = free_and_strdup(&s->smack_ip_in, empty_to_null(n)); + else if (streq(name, "SmackLabelIPOut")) + r = free_and_strdup(&s->smack_ip_out, empty_to_null(n)); + else /* "TCPCongestion" */ + r = free_and_strdup(&s->tcp_congestion, empty_to_null(n)); + if (r < 0) + return r; + + unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n)); + } + + return 1; + + } else if (streq(name, "BindToDevice")) { + const char *n; + + r = sd_bus_message_read(message, "s", &n); + if (r < 0) + return r; + + if (n[0] && !streq(n, "*")) { + if (!ifname_valid(n)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface name for %s: %s", name, n); + } else + n = NULL; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + + r = free_and_strdup(&s->bind_to_device, empty_to_null(n)); + if (r < 0) + return r; + + unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n)); + } + + return 1; + + } else if (streq(name, "BindIPv6Only")) { + SocketAddressBindIPv6Only b; + const char *n; + + r = sd_bus_message_read(message, "s", &n); + if (r < 0) + return r; + + b = socket_address_bind_ipv6_only_from_string(n); + if (b < 0) { + r = parse_boolean(n); + if (r < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %s", name, n); + + b = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH; + } + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + s->bind_ipv6_only = b; + unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, n); + } + + return 1; + + } else if (streq(name, "FileDescriptorName")) { + const char *n; + + r = sd_bus_message_read(message, "s", &n); + if (r < 0) + return r; + + if (!isempty(n) && !fdname_is_valid(n)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %s", name, n); + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + r = free_and_strdup(&s->fdname, empty_to_null(n)); + if (r < 0) + return r; + + unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n)); + } + + return 1; + + } else if (STR_IN_SET(name, "SocketUser", "SocketGroup")) { + const char *n; + + r = sd_bus_message_read(message, "s", &n); + if (r < 0) + return r; + + if (!isempty(n) && !valid_user_group_name_or_id(n)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %s", name, n); + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + + if (streq(name, "SocketUser")) + r = free_and_strdup(&s->user, empty_to_null(n)); + else /* "SocketGroup" */ + r = free_and_strdup(&s->user, empty_to_null(n)); + if (r < 0) + return r; + + unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n)); + } + + return 1; + + } else 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 (!utf8_is_valid(*p)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "String is not UTF-8 clean, ignoring assignment: %s", *p); + + 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 = new0(SocketPort, 1); + if (!p) + return log_oom(); + + p->type = socket_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) { + p->path = strdup(a); + path_kill_slashes(p->path); + + } 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); + } + + p->fd = -1; + p->auxiliary_fds = NULL; + p->n_auxiliary_fds = 0; + p->socket = s; + + empty = false; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + SocketPort *tail; + + LIST_FIND_TAIL(port, s->ports, tail); + LIST_INSERT_AFTER(port, s->ports, tail, p); + + p = NULL; + + 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; + + } else if ((ci = socket_exec_command_from_string(name)) >= 0) + return bus_exec_command_set_transient_property(UNIT(s), name, &s->exec_command[ci], message, flags, error); + + return 0; +} + int bus_socket_set_property( Unit *u, const char *name, @@ -170,12 +629,37 @@ int bus_socket_set_property( sd_bus_error *error) { Socket *s = SOCKET(u); + int r; + + assert(s); + assert(name); + assert(message); assert(s); assert(name); assert(message); - return bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error); + 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) { -- cgit v1.2.1