Compare commits
17 Commits
bdf2357c12
...
78af8a798a
Author | SHA1 | Date |
---|---|---|
Zbigniew Jędrzejewski-Szmek | 78af8a798a | |
Zbigniew Jędrzejewski-Szmek | 58c0663b97 | |
Pascal de Bruijn | b4e2236a72 | |
Zbigniew Jędrzejewski-Szmek | 62092b2fae | |
Lennart Poettering | f1194f5d59 | |
Lennart Poettering | c4fe0cbc17 | |
Lennart Poettering | 88a36d3690 | |
Lennart Poettering | a0c41de277 | |
Lennart Poettering | 45a6c96598 | |
Zbigniew Jędrzejewski-Szmek | 698876640d | |
Zbigniew Jędrzejewski-Szmek | eec12b7756 | |
Zbigniew Jędrzejewski-Szmek | a01ecfa982 | |
Zbigniew Jędrzejewski-Szmek | af22794712 | |
Zbigniew Jędrzejewski-Szmek | f47bd09749 | |
Zbigniew Jędrzejewski-Szmek | ec56251533 | |
Zbigniew Jędrzejewski-Szmek | 8a99bd0c46 | |
Zbigniew Jędrzejewski-Szmek | 7f95bb22d3 |
|
@ -754,7 +754,7 @@
|
|||
container, with the exception of the loopback device and those
|
||||
specified with <option>--network-interface=</option> and
|
||||
configured with <option>--network-veth</option>. If this
|
||||
option is specified, the CAP_NET_ADMIN capability will be
|
||||
option is specified, the <constant>CAP_NET_ADMIN</constant> capability will be
|
||||
added to the set of capabilities the container retains. The
|
||||
latter may be disabled by using <option>--drop-capability=</option>.
|
||||
If this option is not specified (or implied by one of the options
|
||||
|
@ -943,17 +943,27 @@
|
|||
<varlistentry>
|
||||
<term><option>--capability=</option></term>
|
||||
|
||||
<listitem><para>List one or more additional capabilities to grant the container.
|
||||
Takes a comma-separated list of capability names, see
|
||||
<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
<listitem><para>List one or more additional capabilities to grant the container. Takes a
|
||||
comma-separated list of capability names, see <citerefentry
|
||||
project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
for more information. Note that the following capabilities will be granted in any way:
|
||||
CAP_AUDIT_CONTROL, CAP_AUDIT_WRITE, CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH,
|
||||
CAP_FOWNER, CAP_FSETID, CAP_IPC_OWNER, CAP_KILL, CAP_LEASE, CAP_LINUX_IMMUTABLE,
|
||||
CAP_MKNOD, CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, CAP_NET_RAW, CAP_SETFCAP,
|
||||
CAP_SETGID, CAP_SETPCAP, CAP_SETUID, CAP_SYS_ADMIN, CAP_SYS_BOOT, CAP_SYS_CHROOT,
|
||||
CAP_SYS_NICE, CAP_SYS_PTRACE, CAP_SYS_RESOURCE, CAP_SYS_TTY_CONFIG. Also CAP_NET_ADMIN
|
||||
is retained if <option>--private-network</option> is specified. If the special value
|
||||
<literal>all</literal> is passed, all capabilities are retained.</para></listitem>
|
||||
<constant>CAP_AUDIT_CONTROL</constant>, <constant>CAP_AUDIT_WRITE</constant>,
|
||||
<constant>CAP_CHOWN</constant>, <constant>CAP_DAC_OVERRIDE</constant>,
|
||||
<constant>CAP_DAC_READ_SEARCH</constant>, <constant>CAP_FOWNER</constant>,
|
||||
<constant>CAP_FSETID</constant>, <constant>CAP_IPC_OWNER</constant>, <constant>CAP_KILL</constant>,
|
||||
<constant>CAP_LEASE</constant>, <constant>CAP_LINUX_IMMUTABLE</constant>,
|
||||
<constant>CAP_MKNOD</constant>, <constant>CAP_NET_BIND_SERVICE</constant>,
|
||||
<constant>CAP_NET_BROADCAST</constant>, <constant>CAP_NET_RAW</constant>,
|
||||
<constant>CAP_SETFCAP</constant>, <constant>CAP_SETGID</constant>, <constant>CAP_SETPCAP</constant>,
|
||||
<constant>CAP_SETUID</constant>, <constant>CAP_SYS_ADMIN</constant>,
|
||||
<constant>CAP_SYS_BOOT</constant>, <constant>CAP_SYS_CHROOT</constant>,
|
||||
<constant>CAP_SYS_NICE</constant>, <constant>CAP_SYS_PTRACE</constant>,
|
||||
<constant>CAP_SYS_RESOURCE</constant>, <constant>CAP_SYS_TTY_CONFIG</constant>. Also
|
||||
<constant>CAP_NET_ADMIN</constant> is retained if <option>--private-network</option> is specified.
|
||||
If the special value <literal>all</literal> is passed, all capabilities are retained.</para>
|
||||
|
||||
<para>If the special value of <literal>help</literal> is passed, the program will print known
|
||||
capability names and exit.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -962,7 +972,10 @@
|
|||
<listitem><para>Specify one or more additional capabilities to
|
||||
drop for the container. This allows running the container with
|
||||
fewer capabilities than the default (see
|
||||
above).</para></listitem>
|
||||
above).</para>
|
||||
|
||||
<para>If the special value of <literal>help</literal> is passed, the program will print known
|
||||
capability names and exit.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1+
|
||||
|
||||
project('systemd', 'c',
|
||||
version : '243',
|
||||
version : '244',
|
||||
license : 'LGPLv2+',
|
||||
default_options: [
|
||||
'c_std=gnu99',
|
||||
|
@ -13,8 +13,8 @@ project('systemd', 'c',
|
|||
meson_version : '>= 0.46',
|
||||
)
|
||||
|
||||
libsystemd_version = '0.27.0'
|
||||
libudev_version = '1.6.15'
|
||||
libsystemd_version = '0.27.1'
|
||||
libudev_version = '1.6.16'
|
||||
|
||||
# We need the same data in two different formats, ugh!
|
||||
# Also, for hysterical reasons, we use different variable
|
||||
|
|
|
@ -330,36 +330,107 @@ int machine_load(Machine *m) {
|
|||
return r;
|
||||
}
|
||||
|
||||
static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
|
||||
static int machine_start_scope(
|
||||
Machine *machine,
|
||||
sd_bus_message *more_properties,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
||||
_cleanup_free_ char *escaped = NULL, *unit = NULL;
|
||||
const char *description;
|
||||
int r;
|
||||
|
||||
assert(machine);
|
||||
assert(machine->leader > 0);
|
||||
assert(!machine->unit);
|
||||
|
||||
escaped = unit_name_escape(machine->name);
|
||||
if (!escaped)
|
||||
return log_oom();
|
||||
|
||||
unit = strjoin("machine-", escaped, ".scope");
|
||||
if (!unit)
|
||||
return log_oom();
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
machine->manager->bus,
|
||||
&m,
|
||||
"org.freedesktop.systemd1",
|
||||
"/org/freedesktop/systemd1",
|
||||
"org.freedesktop.systemd1.Manager",
|
||||
"StartTransientUnit");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "ss", unit, "fail");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "(sv)", "Slice", "s", SPECIAL_MACHINE_SLICE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
description = strjoina(machine->class == MACHINE_VM ? "Virtual Machine " : "Container ", machine->name);
|
||||
r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)",
|
||||
"PIDs", "au", 1, machine->leader,
|
||||
"Delegate", "b", 1,
|
||||
"CollectMode", "s", "inactive-or-failed",
|
||||
"AddRef", "b", 1,
|
||||
"TasksMax", "t", UINT64_C(16384));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (more_properties) {
|
||||
r = sd_bus_message_copy(m, more_properties, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "a(sa(sv))", 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_call(NULL, m, 0, error, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
machine->unit = TAKE_PTR(unit);
|
||||
machine->referenced = true;
|
||||
|
||||
const char *job;
|
||||
r = sd_bus_message_read(reply, "o", &job);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return free_and_strdup(&machine->scope_job, job);
|
||||
}
|
||||
|
||||
static int machine_ensure_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(m->class != MACHINE_HOST);
|
||||
|
||||
if (!m->unit) {
|
||||
_cleanup_free_ char *escaped = NULL, *scope = NULL;
|
||||
char *description, *job = NULL;
|
||||
int r;
|
||||
|
||||
escaped = unit_name_escape(m->name);
|
||||
if (!escaped)
|
||||
return log_oom();
|
||||
|
||||
scope = strjoin("machine-", escaped, ".scope");
|
||||
if (!scope)
|
||||
return log_oom();
|
||||
|
||||
description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
|
||||
|
||||
r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
|
||||
r = machine_start_scope(m, properties, error);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to start machine scope: %s", bus_error_message(error, r));
|
||||
|
||||
m->unit = TAKE_PTR(scope);
|
||||
m->referenced = true;
|
||||
free_and_replace(m->scope_job, job);
|
||||
}
|
||||
|
||||
if (m->unit)
|
||||
hashmap_put(m->manager->machine_units, m->unit, m);
|
||||
assert(m->unit);
|
||||
hashmap_put(m->manager->machine_units, m->unit, m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -380,7 +451,7 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
|
|||
return r;
|
||||
|
||||
/* Create cgroup */
|
||||
r = machine_start_scope(m, properties, error);
|
||||
r = machine_ensure_scope(m, properties, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -404,49 +475,31 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int machine_stop_scope(Machine *m) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
char *job = NULL;
|
||||
int r, q;
|
||||
|
||||
assert(m);
|
||||
assert(m->class != MACHINE_HOST);
|
||||
|
||||
if (!m->unit)
|
||||
return 0;
|
||||
|
||||
r = manager_stop_unit(m->manager, m->unit, &error, &job);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to stop machine scope: %s", bus_error_message(&error, r));
|
||||
sd_bus_error_free(&error);
|
||||
} else
|
||||
free_and_replace(m->scope_job, job);
|
||||
|
||||
if (m->referenced) {
|
||||
q = manager_unref_unit(m->manager, m->unit, &error);
|
||||
if (q < 0)
|
||||
log_warning_errno(q, "Failed to drop reference to machine scope, ignoring: %s", bus_error_message(&error, r));
|
||||
m->referenced = false;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int machine_stop(Machine *m) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
r = machine_stop_scope(m);
|
||||
if (m->unit) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
char *job = NULL;
|
||||
|
||||
r = manager_stop_unit(m->manager, m->unit, &error, &job);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to stop machine scope: %s", bus_error_message(&error, r));
|
||||
|
||||
free_and_replace(m->scope_job, job);
|
||||
}
|
||||
|
||||
m->stopping = true;
|
||||
|
||||
machine_save(m);
|
||||
(void) manager_enqueue_nscd_cache_flush(m->manager);
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int machine_finalize(Machine *m) {
|
||||
|
@ -583,6 +636,18 @@ void machine_release_unit(Machine *m) {
|
|||
if (!m->unit)
|
||||
return;
|
||||
|
||||
if (m->referenced) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
int r;
|
||||
|
||||
r = manager_unref_unit(m->manager, m->unit, &error);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to drop reference to machine scope, ignoring: %s",
|
||||
bus_error_message(&error, r));
|
||||
|
||||
m->referenced = false;
|
||||
}
|
||||
|
||||
(void) hashmap_remove(m->manager->machine_units, m->unit);
|
||||
m->unit = mfree(m->unit);
|
||||
}
|
||||
|
|
|
@ -1294,98 +1294,6 @@ int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error
|
|||
return 0;
|
||||
}
|
||||
|
||||
int manager_start_scope(
|
||||
Manager *manager,
|
||||
const char *scope,
|
||||
pid_t pid,
|
||||
const char *slice,
|
||||
const char *description,
|
||||
sd_bus_message *more_properties,
|
||||
sd_bus_error *error,
|
||||
char **job) {
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
||||
int r;
|
||||
|
||||
assert(manager);
|
||||
assert(scope);
|
||||
assert(pid > 1);
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
manager->bus,
|
||||
&m,
|
||||
"org.freedesktop.systemd1",
|
||||
"/org/freedesktop/systemd1",
|
||||
"org.freedesktop.systemd1.Manager",
|
||||
"StartTransientUnit");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!isempty(slice)) {
|
||||
r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!isempty(description)) {
|
||||
r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)",
|
||||
"PIDs", "au", 1, pid,
|
||||
"Delegate", "b", 1,
|
||||
"CollectMode", "s", "inactive-or-failed",
|
||||
"AddRef", "b", 1,
|
||||
"TasksMax", "t", UINT64_C(16384));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (more_properties) {
|
||||
r = sd_bus_message_copy(m, more_properties, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "a(sa(sv))", 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_call(manager->bus, m, 0, error, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (job) {
|
||||
const char *j;
|
||||
char *copy;
|
||||
|
||||
r = sd_bus_message_read(reply, "o", &j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
copy = strdup(j);
|
||||
if (!copy)
|
||||
return -ENOMEM;
|
||||
|
||||
*job = copy;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int manager_unref_unit(
|
||||
Manager *m,
|
||||
const char *unit,
|
||||
|
|
|
@ -49,7 +49,6 @@ int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *er
|
|||
int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
|
||||
int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, sd_bus_message *more_properties, sd_bus_error *error, char **job);
|
||||
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
|
||||
int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error);
|
||||
int manager_unref_unit(Manager *m, const char *unit, sd_bus_error *error);
|
||||
|
|
|
@ -139,11 +139,10 @@ static int seccomp_add_default_syscall_filter(
|
|||
*/
|
||||
};
|
||||
|
||||
int r;
|
||||
size_t i;
|
||||
char **p;
|
||||
int r;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(whitelist); i++) {
|
||||
for (size_t i = 0; i < ELEMENTSOF(whitelist); i++) {
|
||||
if (whitelist[i].capability != 0 && (cap_list_retain & (1ULL << whitelist[i].capability)) == 0)
|
||||
continue;
|
||||
|
||||
|
@ -153,7 +152,7 @@ static int seccomp_add_default_syscall_filter(
|
|||
}
|
||||
|
||||
STRV_FOREACH(p, syscall_whitelist) {
|
||||
r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, false);
|
||||
r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, true);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m",
|
||||
*p, seccomp_arch_to_string(arch));
|
||||
|
|
|
@ -492,6 +492,46 @@ static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int parse_capability_spec(const char *spec, uint64_t *ret_mask) {
|
||||
uint64_t mask = 0;
|
||||
int r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
r = extract_first_word(&spec, &t, ",", 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse capability %s.", t);
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (streq(t, "help")) {
|
||||
for (int i = 0; i < capability_list_length(); i++) {
|
||||
const char *name;
|
||||
|
||||
name = capability_to_name(i);
|
||||
if (name)
|
||||
puts(name);
|
||||
}
|
||||
|
||||
return 0; /* quit */
|
||||
}
|
||||
|
||||
if (streq(t, "all"))
|
||||
mask = (uint64_t) -1;
|
||||
else {
|
||||
r = capability_from_name(t);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse capability %s.", t);
|
||||
|
||||
mask |= 1ULL << r;
|
||||
}
|
||||
}
|
||||
|
||||
*ret_mask = mask;
|
||||
return 1; /* continue */
|
||||
}
|
||||
|
||||
static int parse_share_ns_env(const char *name, unsigned long ns_flag) {
|
||||
int r;
|
||||
|
||||
|
@ -695,7 +735,6 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
};
|
||||
|
||||
int c, r;
|
||||
const char *p;
|
||||
uint64_t plus = 0, minus = 0;
|
||||
bool mask_all_settings = false, mask_no_settings = false;
|
||||
|
||||
|
@ -937,37 +976,18 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
|
||||
case ARG_CAPABILITY:
|
||||
case ARG_DROP_CAPABILITY: {
|
||||
p = optarg;
|
||||
for (;;) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
r = extract_first_word(&p, &t, ",", 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse capability %s.", t);
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (streq(t, "all")) {
|
||||
if (c == ARG_CAPABILITY)
|
||||
plus = (uint64_t) -1;
|
||||
else
|
||||
minus = (uint64_t) -1;
|
||||
} else {
|
||||
r = capability_from_name(t);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse capability %s.", t);
|
||||
|
||||
if (c == ARG_CAPABILITY)
|
||||
plus |= 1ULL << r;
|
||||
else
|
||||
minus |= 1ULL << r;
|
||||
}
|
||||
}
|
||||
uint64_t m;
|
||||
r = parse_capability_spec(optarg, &m);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (c == ARG_CAPABILITY)
|
||||
plus |= m;
|
||||
else
|
||||
minus |= m;
|
||||
arg_settings_mask |= SETTING_CAPABILITY;
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_NO_NEW_PRIVILEGES:
|
||||
r = parse_boolean(optarg);
|
||||
if (r < 0)
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "resolved-dns-stream.h"
|
||||
#include "resolved-dnstls.h"
|
||||
|
||||
#define PRIORTY_STRING "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2"
|
||||
#define TLS_PROTOCOL_PRIORITY "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2"
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(gnutls_session_t, gnutls_deinit);
|
||||
|
||||
static ssize_t dnstls_stream_writev(gnutls_transport_ptr_t p, const giovec_t *iov, int iovcnt) {
|
||||
|
@ -38,7 +38,7 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
|
|||
return r;
|
||||
|
||||
/* As DNS-over-TLS is a recent protocol, older TLS versions can be disabled */
|
||||
r = gnutls_priority_set_direct(gs, PRIORTY_STRING, NULL);
|
||||
r = gnutls_priority_set_direct(gs, TLS_PROTOCOL_PRIORITY, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ typedef enum VarlinkState {
|
|||
/* Client side states */
|
||||
VARLINK_IDLE_CLIENT,
|
||||
VARLINK_AWAITING_REPLY,
|
||||
VARLINK_AWAITING_REPLY_MORE,
|
||||
VARLINK_CALLING,
|
||||
VARLINK_CALLED,
|
||||
VARLINK_PROCESSING_REPLY,
|
||||
|
@ -39,7 +40,6 @@ typedef enum VarlinkState {
|
|||
VARLINK_PROCESSING_METHOD_MORE,
|
||||
VARLINK_PROCESSING_METHOD_ONEWAY,
|
||||
VARLINK_PROCESSED_METHOD,
|
||||
VARLINK_PROCESSED_METHOD_MORE,
|
||||
VARLINK_PENDING_METHOD,
|
||||
VARLINK_PENDING_METHOD_MORE,
|
||||
|
||||
|
@ -63,6 +63,7 @@ typedef enum VarlinkState {
|
|||
IN_SET(state, \
|
||||
VARLINK_IDLE_CLIENT, \
|
||||
VARLINK_AWAITING_REPLY, \
|
||||
VARLINK_AWAITING_REPLY_MORE, \
|
||||
VARLINK_CALLING, \
|
||||
VARLINK_CALLED, \
|
||||
VARLINK_PROCESSING_REPLY, \
|
||||
|
@ -71,7 +72,6 @@ typedef enum VarlinkState {
|
|||
VARLINK_PROCESSING_METHOD_MORE, \
|
||||
VARLINK_PROCESSING_METHOD_ONEWAY, \
|
||||
VARLINK_PROCESSED_METHOD, \
|
||||
VARLINK_PROCESSED_METHOD_MORE, \
|
||||
VARLINK_PENDING_METHOD, \
|
||||
VARLINK_PENDING_METHOD_MORE)
|
||||
|
||||
|
@ -185,6 +185,7 @@ struct VarlinkServer {
|
|||
static const char* const varlink_state_table[_VARLINK_STATE_MAX] = {
|
||||
[VARLINK_IDLE_CLIENT] = "idle-client",
|
||||
[VARLINK_AWAITING_REPLY] = "awaiting-reply",
|
||||
[VARLINK_AWAITING_REPLY_MORE] = "awaiting-reply-more",
|
||||
[VARLINK_CALLING] = "calling",
|
||||
[VARLINK_CALLED] = "called",
|
||||
[VARLINK_PROCESSING_REPLY] = "processing-reply",
|
||||
|
@ -193,7 +194,6 @@ static const char* const varlink_state_table[_VARLINK_STATE_MAX] = {
|
|||
[VARLINK_PROCESSING_METHOD_MORE] = "processing-method-more",
|
||||
[VARLINK_PROCESSING_METHOD_ONEWAY] = "processing-method-oneway",
|
||||
[VARLINK_PROCESSED_METHOD] = "processed-method",
|
||||
[VARLINK_PROCESSED_METHOD_MORE] = "processed-method-more",
|
||||
[VARLINK_PENDING_METHOD] = "pending-method",
|
||||
[VARLINK_PENDING_METHOD_MORE] = "pending-method-more",
|
||||
[VARLINK_PENDING_DISCONNECT] = "pending-disconnect",
|
||||
|
@ -287,6 +287,8 @@ int varlink_connect_address(Varlink **ret, const char *address) {
|
|||
if (v->fd < 0)
|
||||
return -errno;
|
||||
|
||||
v->fd = fd_move_above_stdio(v->fd);
|
||||
|
||||
if (connect(v->fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0) {
|
||||
if (!IN_SET(errno, EAGAIN, EINPROGRESS))
|
||||
return -errno;
|
||||
|
@ -341,11 +343,8 @@ static void varlink_detach_event_sources(Varlink *v) {
|
|||
assert(v);
|
||||
|
||||
v->io_event_source = sd_event_source_disable_unref(v->io_event_source);
|
||||
|
||||
v->time_event_source = sd_event_source_disable_unref(v->time_event_source);
|
||||
|
||||
v->quit_event_source = sd_event_source_disable_unref(v->quit_event_source);
|
||||
|
||||
v->defer_event_source = sd_event_source_disable_unref(v->defer_event_source);
|
||||
}
|
||||
|
||||
|
@ -405,7 +404,7 @@ static int varlink_test_disconnect(Varlink *v) {
|
|||
goto disconnect;
|
||||
|
||||
/* If we are waiting for incoming data but the read side is shut down, disconnect. */
|
||||
if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER) && v->read_disconnected)
|
||||
if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING, VARLINK_IDLE_SERVER) && v->read_disconnected)
|
||||
goto disconnect;
|
||||
|
||||
/* Similar, if are a client that hasn't written anything yet but the write side is dead, also
|
||||
|
@ -478,7 +477,7 @@ static int varlink_read(Varlink *v) {
|
|||
|
||||
assert(v);
|
||||
|
||||
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER))
|
||||
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING, VARLINK_IDLE_SERVER))
|
||||
return 0;
|
||||
if (v->connecting) /* read() on a socket while we are in connect() will fail with EINVAL, hence exit early here */
|
||||
return 0;
|
||||
|
@ -596,7 +595,7 @@ static int varlink_parse_message(Varlink *v) {
|
|||
static int varlink_test_timeout(Varlink *v) {
|
||||
assert(v);
|
||||
|
||||
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING))
|
||||
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING))
|
||||
return 0;
|
||||
if (v->timeout == USEC_INFINITY)
|
||||
return 0;
|
||||
|
@ -673,7 +672,7 @@ static int varlink_dispatch_reply(Varlink *v) {
|
|||
|
||||
assert(v);
|
||||
|
||||
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING))
|
||||
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING))
|
||||
return 0;
|
||||
if (!v->current)
|
||||
return 0;
|
||||
|
@ -715,6 +714,11 @@ static int varlink_dispatch_reply(Varlink *v) {
|
|||
goto invalid;
|
||||
}
|
||||
|
||||
/* Replies with 'continue' set are only OK if we set 'more' when the method call was initiated */
|
||||
if (v->state != VARLINK_AWAITING_REPLY_MORE && FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
|
||||
goto invalid;
|
||||
|
||||
/* An error is final */
|
||||
if (error && FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
|
||||
goto invalid;
|
||||
|
||||
|
@ -722,7 +726,7 @@ static int varlink_dispatch_reply(Varlink *v) {
|
|||
if (r < 0)
|
||||
goto invalid;
|
||||
|
||||
if (v->state == VARLINK_AWAITING_REPLY) {
|
||||
if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE)) {
|
||||
varlink_set_state(v, VARLINK_PROCESSING_REPLY);
|
||||
|
||||
if (v->reply_callback) {
|
||||
|
@ -734,17 +738,18 @@ static int varlink_dispatch_reply(Varlink *v) {
|
|||
v->current = json_variant_unref(v->current);
|
||||
|
||||
if (v->state == VARLINK_PROCESSING_REPLY) {
|
||||
assert(v->n_pending > 0);
|
||||
v->n_pending--;
|
||||
|
||||
varlink_set_state(v, v->n_pending == 0 ? VARLINK_IDLE_CLIENT : VARLINK_AWAITING_REPLY);
|
||||
assert(v->n_pending > 0);
|
||||
|
||||
if (!FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
|
||||
v->n_pending--;
|
||||
|
||||
varlink_set_state(v,
|
||||
FLAGS_SET(flags, VARLINK_REPLY_CONTINUES) ? VARLINK_AWAITING_REPLY_MORE :
|
||||
v->n_pending == 0 ? VARLINK_IDLE_CLIENT : VARLINK_AWAITING_REPLY);
|
||||
}
|
||||
} else {
|
||||
assert(v->state == VARLINK_CALLING);
|
||||
|
||||
if (FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
|
||||
goto invalid;
|
||||
|
||||
varlink_set_state(v, VARLINK_CALLED);
|
||||
}
|
||||
|
||||
|
@ -878,7 +883,6 @@ static int varlink_dispatch_method(Varlink *v) {
|
|||
varlink_set_state(v, VARLINK_PENDING_METHOD);
|
||||
break;
|
||||
|
||||
case VARLINK_PROCESSED_METHOD_MORE: /* One reply for a "more" message was sent, more to come */
|
||||
case VARLINK_PROCESSING_METHOD_MORE: /* No reply for a "more" message was sent, more to come */
|
||||
varlink_set_state(v, VARLINK_PENDING_METHOD_MORE);
|
||||
break;
|
||||
|
@ -1073,7 +1077,7 @@ int varlink_get_events(Varlink *v) {
|
|||
return EPOLLOUT;
|
||||
|
||||
if (!v->read_disconnected &&
|
||||
IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER) &&
|
||||
IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING, VARLINK_IDLE_SERVER) &&
|
||||
!v->current &&
|
||||
v->input_buffer_unscanned <= 0)
|
||||
ret |= EPOLLIN;
|
||||
|
@ -1091,7 +1095,7 @@ int varlink_get_timeout(Varlink *v, usec_t *ret) {
|
|||
if (v->state == VARLINK_DISCONNECTED)
|
||||
return -ENOTCONN;
|
||||
|
||||
if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING) &&
|
||||
if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING) &&
|
||||
v->timeout != USEC_INFINITY) {
|
||||
if (ret)
|
||||
*ret = usec_add(v->timestamp, v->timeout);
|
||||
|
@ -1259,6 +1263,8 @@ int varlink_send(Varlink *v, const char *method, JsonVariant *parameters) {
|
|||
|
||||
if (v->state == VARLINK_DISCONNECTED)
|
||||
return -ENOTCONN;
|
||||
|
||||
/* We allow enqueuing multiple method calls at once! */
|
||||
if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY))
|
||||
return -EBUSY;
|
||||
|
||||
|
@ -1308,6 +1314,8 @@ int varlink_invoke(Varlink *v, const char *method, JsonVariant *parameters) {
|
|||
|
||||
if (v->state == VARLINK_DISCONNECTED)
|
||||
return -ENOTCONN;
|
||||
|
||||
/* We allow enqueing multiple method calls at once! */
|
||||
if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY))
|
||||
return -EBUSY;
|
||||
|
||||
|
@ -1349,6 +1357,60 @@ int varlink_invokeb(Varlink *v, const char *method, ...) {
|
|||
return varlink_invoke(v, method, parameters);
|
||||
}
|
||||
|
||||
int varlink_observe(Varlink *v, const char *method, JsonVariant *parameters) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *m = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(v, -EINVAL);
|
||||
assert_return(method, -EINVAL);
|
||||
|
||||
if (v->state == VARLINK_DISCONNECTED)
|
||||
return -ENOTCONN;
|
||||
/* Note that we don't allow enqueuing multiple method calls when we are in more/continues mode! We
|
||||
* thus insist on an idle client here. */
|
||||
if (v->state != VARLINK_IDLE_CLIENT)
|
||||
return -EBUSY;
|
||||
|
||||
r = varlink_sanitize_parameters(¶meters);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = json_build(&m, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)),
|
||||
JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)),
|
||||
JSON_BUILD_PAIR("more", JSON_BUILD_BOOLEAN(true))));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = varlink_enqueue_json(v, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
varlink_set_state(v, VARLINK_AWAITING_REPLY_MORE);
|
||||
v->n_pending++;
|
||||
v->timestamp = now(CLOCK_MONOTONIC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int varlink_observeb(Varlink *v, const char *method, ...) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL;
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
assert_return(v, -EINVAL);
|
||||
|
||||
va_start(ap, method);
|
||||
r = json_buildv(¶meters, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return varlink_observe(v, method, parameters);
|
||||
}
|
||||
|
||||
int varlink_call(
|
||||
Varlink *v,
|
||||
const char *method,
|
||||
|
@ -1769,6 +1831,7 @@ static int prepare_callback(sd_event_source *s, void *userdata) {
|
|||
Varlink *v = userdata;
|
||||
int r, e;
|
||||
usec_t until;
|
||||
bool have_timeout;
|
||||
|
||||
assert(s);
|
||||
assert(v);
|
||||
|
@ -1784,13 +1847,15 @@ static int prepare_callback(sd_event_source *s, void *userdata) {
|
|||
r = varlink_get_timeout(v, &until);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
have_timeout = r > 0;
|
||||
|
||||
if (have_timeout) {
|
||||
r = sd_event_source_set_time(v->time_event_source, until);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_event_source_set_enabled(v->time_event_source, r > 0 ? SD_EVENT_ON : SD_EVENT_OFF);
|
||||
r = sd_event_source_set_enabled(v->time_event_source, have_timeout ? SD_EVENT_ON : SD_EVENT_OFF);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -2157,6 +2222,8 @@ int varlink_server_listen_address(VarlinkServer *s, const char *address, mode_t
|
|||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
fd = fd_move_above_stdio(fd);
|
||||
|
||||
(void) sockaddr_un_unlink(&sockaddr.un);
|
||||
|
||||
RUN_WITH_UMASK(~m & 0777)
|
||||
|
@ -2339,17 +2406,18 @@ int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect callback) {
|
|||
}
|
||||
|
||||
unsigned varlink_server_connections_max(VarlinkServer *s) {
|
||||
struct rlimit rl;
|
||||
int dts;
|
||||
|
||||
/* If a server is specified, return the setting for that server, otherwise the default value */
|
||||
if (s)
|
||||
return s->connections_max;
|
||||
|
||||
assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
|
||||
dts = getdtablesize();
|
||||
assert_se(dts > 0);
|
||||
|
||||
/* Make sure we never use up more than ¾th of RLIMIT_NOFILE for IPC */
|
||||
if (VARLINK_DEFAULT_CONNECTIONS_MAX > rl.rlim_cur / 4 * 3)
|
||||
return rl.rlim_cur / 4 * 3;
|
||||
if (VARLINK_DEFAULT_CONNECTIONS_MAX > (unsigned) dts / 4 * 3)
|
||||
return dts / 4 * 3;
|
||||
|
||||
return VARLINK_DEFAULT_CONNECTIONS_MAX;
|
||||
}
|
||||
|
|
|
@ -86,6 +86,10 @@ int varlink_callb(Varlink *v, const char *method, JsonVariant **ret_parameters,
|
|||
int varlink_invoke(Varlink *v, const char *method, JsonVariant *parameters);
|
||||
int varlink_invokeb(Varlink *v, const char *method, ...);
|
||||
|
||||
/* Enqueue method call, expect a reply now, and possibly more later, which are all delivered to the reply callback */
|
||||
int varlink_observe(Varlink *v, const char *method, JsonVariant *parameters);
|
||||
int varlink_observeb(Varlink *v, const char *method, ...);
|
||||
|
||||
/* Enqueue a final reply */
|
||||
int varlink_reply(Varlink *v, JsonVariant *parameters);
|
||||
int varlink_replyb(Varlink *v, ...);
|
||||
|
|
|
@ -98,7 +98,7 @@ units = [
|
|||
['systemd-poweroff.service', ''],
|
||||
['systemd-reboot.service', ''],
|
||||
['systemd-rfkill.socket', 'ENABLE_RFKILL'],
|
||||
['systemd-tmpfiles-clean.timer', '',
|
||||
['systemd-tmpfiles-clean.timer', 'ENABLE_TMPFILES',
|
||||
'timers.target.wants/'],
|
||||
['systemd-udevd-control.socket', '',
|
||||
'sockets.target.wants/'],
|
||||
|
|
Loading…
Reference in New Issue