core: firewall integration with DynamicUserNFTSet=
New directive `DynamicUserNFTSet=` provides a method for integrating
configuration of dynamic users into firewall rules with NFT sets.
Example:
```
table inet filter {
set u {
typeof meta skuid
}
chain service_output {
meta skuid != @u drop
accept
}
}
```
```
/etc/systemd/system/dunft.service
[Service]
DynamicUser=yes
DynamicUserNFTSet=inet:filter:u
ExecStart=/bin/sleep 1000
[Install]
WantedBy=multi-user.target
```
```
$ sudo nft list set inet filter u
table inet filter {
set u {
typeof meta skuid
elements = { 64864 }
}
}
$ ps -n --format user,group,pid,command -p `pgrep sleep`
USER GROUP PID COMMAND
64864 64864 55158 /bin/sleep 1000
```
This commit is contained in:
committed by
Topi Miettinen
parent
c0548df0a2
commit
46c3b1ff88
@@ -2785,6 +2785,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b DynamicUser = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly a(iss) DynamicUserNFTSet = [...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b RemoveIPC = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly a(say) SetCredential = [...];
|
||||
@@ -3332,6 +3334,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<!--property DynamicUser is not documented!-->
|
||||
|
||||
<!--property DynamicUserNFTSet is not documented!-->
|
||||
|
||||
<!--property RemoveIPC is not documented!-->
|
||||
|
||||
<!--property SetCredential is not documented!-->
|
||||
@@ -3940,6 +3944,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUser"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUserNFTSet"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="RemoveIPC"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
|
||||
@@ -4679,6 +4685,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b DynamicUser = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly a(iss) DynamicUserNFTSet = [...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b RemoveIPC = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly a(say) SetCredential = [...];
|
||||
@@ -5250,6 +5258,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<!--property DynamicUser is not documented!-->
|
||||
|
||||
<!--property DynamicUserNFTSet is not documented!-->
|
||||
|
||||
<!--property RemoveIPC is not documented!-->
|
||||
|
||||
<!--property SetCredential is not documented!-->
|
||||
@@ -5852,6 +5862,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUser"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUserNFTSet"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="RemoveIPC"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
|
||||
@@ -6480,6 +6492,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b DynamicUser = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly a(iss) DynamicUserNFTSet = [...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b RemoveIPC = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly a(say) SetCredential = [...];
|
||||
@@ -6979,6 +6993,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<!--property DynamicUser is not documented!-->
|
||||
|
||||
<!--property DynamicUserNFTSet is not documented!-->
|
||||
|
||||
<!--property RemoveIPC is not documented!-->
|
||||
|
||||
<!--property SetCredential is not documented!-->
|
||||
@@ -7499,6 +7515,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUser"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUserNFTSet"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="RemoveIPC"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
|
||||
@@ -8254,6 +8272,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b DynamicUser = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly a(iss) DynamicUserNFTSet = [...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b RemoveIPC = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly a(say) SetCredential = [...];
|
||||
@@ -8739,6 +8759,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
|
||||
<!--property DynamicUser is not documented!-->
|
||||
|
||||
<!--property DynamicUserNFTSet is not documented!-->
|
||||
|
||||
<!--property RemoveIPC is not documented!-->
|
||||
|
||||
<!--property SetCredential is not documented!-->
|
||||
@@ -9245,6 +9267,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUser"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUserNFTSet"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="RemoveIPC"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
|
||||
|
||||
@@ -3163,6 +3163,40 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Firewall Integration</title>
|
||||
<variablelist class='unit-directives'>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>DynamicUserNFTSet=</varname><replaceable>family</replaceable>:<replaceable>table</replaceable>:<replaceable>set</replaceable></term>
|
||||
<listitem><para>This setting provides a method for integrating <varname>DynamicUser=</varname>
|
||||
configuration into firewall rules with NFT sets. This option expects a whitespace separated list of
|
||||
NFT set definitions. Each definition consists of a colon-separated tuple of NFT address family (one
|
||||
of <literal>arp</literal>, <literal>bridge</literal>, <literal>inet</literal>, <literal>ip</literal>,
|
||||
<literal>ip6</literal>, or <literal>netdev</literal>), table name and set name. The names of tables
|
||||
and sets must conform to lexical restrictions of NFT table names. When the unit starts, the user ID
|
||||
will be appended to the NFT sets and it will be removed when the unit is stopped. Failures to manage
|
||||
the sets will be ignored.</para>
|
||||
|
||||
<para>Example:
|
||||
<programlisting>[Service]
|
||||
DynamicUserNFTSet=inet:filter:u</programlisting>
|
||||
Corresponding NFT rules:
|
||||
<programlisting>table inet filter {
|
||||
set u {
|
||||
typeof meta skuid
|
||||
}
|
||||
chain service_output {
|
||||
meta skuid != @u drop
|
||||
accept
|
||||
}
|
||||
}</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>System V Compatibility</title>
|
||||
<variablelist class='unit-directives'>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "execute.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "firewall-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "io-util.h"
|
||||
#include "ioprio-util.h"
|
||||
@@ -1138,6 +1139,37 @@ static int bus_property_get_exec_dir_symlink(
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
static int property_get_dynamic_user_nft_set(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
ExecContext *c = userdata;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
assert(c);
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(iss)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (size_t i = 0; i < c->n_dynamic_user_nft_set_contexts; i++) {
|
||||
NFTSetContext *s = &c->dynamic_user_nft_set_context[i];
|
||||
|
||||
r = sd_bus_message_append(reply, "(iss)", s->nfproto, s->table, s->set);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
const sd_bus_vtable bus_exec_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@@ -1232,6 +1264,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||
SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DynamicUser", "b", bus_property_get_bool, offsetof(ExecContext, dynamic_user), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DynamicUserNFTSet", "a(iss)", property_get_dynamic_user_nft_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(ExecContext, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("SetCredential", "a(say)", property_get_set_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("SetCredentialEncrypted", "a(say)", property_get_set_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@@ -3503,6 +3536,58 @@ int bus_exec_context_set_transient_property(
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "DynamicUserNFTSet")) {
|
||||
int nfproto;
|
||||
const char *table, *set;
|
||||
bool empty = true;
|
||||
|
||||
r = sd_bus_message_enter_container(message, 'a', "(iss)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while ((r = sd_bus_message_read(message, "(iss)", &nfproto, &table, &set)) > 0) {
|
||||
const char *nfproto_name;
|
||||
|
||||
nfproto_name = nfproto_to_string(nfproto);
|
||||
if (!nfproto_name)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid protocol %d.", nfproto);
|
||||
|
||||
if (nft_identifier_bad(table))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NFT table name %s.", table);
|
||||
|
||||
if (nft_identifier_bad(set))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NFT set name %s.", set);
|
||||
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
r = nft_set_context_add(&c->dynamic_user_nft_set_context, &c->n_dynamic_user_nft_set_contexts, nfproto, table, set);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
unit_write_settingf(
|
||||
u, flags|UNIT_ESCAPE_SPECIFIERS, name,
|
||||
"%s=%s:%s:%s",
|
||||
name,
|
||||
nfproto_name,
|
||||
table,
|
||||
set);
|
||||
}
|
||||
|
||||
empty = false;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (empty) {
|
||||
c->dynamic_user_nft_set_context = nft_set_context_free_many(c->dynamic_user_nft_set_context, &c->n_dynamic_user_nft_set_contexts);
|
||||
unit_write_settingf(u, flags, name, "%s=", name);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else if ((suffix = startswith(name, "Limit"))) {
|
||||
const char *soft = NULL;
|
||||
int ri;
|
||||
|
||||
@@ -4083,6 +4083,43 @@ static int add_shifted_fd(int *fds, size_t fds_size, size_t *n_fds, int fd, int
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void exec_op_dynamic_user_nft_set(bool add, const ExecContext *c, uid_t uid) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
for (size_t i = 0; i < c->n_dynamic_user_nft_set_contexts; i++) {
|
||||
NFTSetContext *s = &c->dynamic_user_nft_set_context[i];
|
||||
if (add)
|
||||
r = nft_set_element_add_uint32(s, uid);
|
||||
else
|
||||
r = nft_set_element_del_uint32(s, uid);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "%s NFT family %s table %s set %s UID " UID_FMT " failed, ignoring: %m",
|
||||
add? "Adding" : "Deleting", nfproto_to_string(s->nfproto), s->table, s->set, uid);
|
||||
}
|
||||
}
|
||||
|
||||
static void exec_add_dynamic_user_nft_set(const ExecContext *c, uid_t uid) {
|
||||
exec_op_dynamic_user_nft_set(true, c, uid);
|
||||
}
|
||||
|
||||
void exec_delete_dynamic_user_nft_set(const ExecContext *c, DynamicUser *d) {
|
||||
int r;
|
||||
uid_t uid;
|
||||
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
r = dynamic_user_current(d, &uid);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Can't get current dynamic user, ignoring: %m");
|
||||
return;
|
||||
}
|
||||
|
||||
exec_op_dynamic_user_nft_set(false, c, uid);
|
||||
}
|
||||
|
||||
static int exec_child(
|
||||
Unit *unit,
|
||||
const ExecCommand *command,
|
||||
@@ -4284,6 +4321,8 @@ static int exec_child(
|
||||
if (dcreds->user)
|
||||
username = dcreds->user->name;
|
||||
|
||||
exec_add_dynamic_user_nft_set(context, uid);
|
||||
|
||||
} else {
|
||||
r = get_fixed_user(context, &username, &uid, &gid, &home, &shell);
|
||||
if (r < 0) {
|
||||
@@ -5346,6 +5385,8 @@ void exec_context_done(ExecContext *c) {
|
||||
c->user = mfree(c->user);
|
||||
c->group = mfree(c->group);
|
||||
|
||||
c->dynamic_user_nft_set_context = nft_set_context_free_many(c->dynamic_user_nft_set_context, &c->n_dynamic_user_nft_set_contexts);
|
||||
|
||||
c->supplementary_groups = strv_free(c->supplementary_groups);
|
||||
|
||||
c->pam_name = mfree(c->pam_name);
|
||||
@@ -6020,6 +6061,11 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||
fprintf(f, "%sGroup: %s\n", prefix, c->group);
|
||||
|
||||
fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
|
||||
for (size_t i = 0; i < c->n_dynamic_user_nft_set_contexts; i++)
|
||||
fprintf(f, "%sDynamicUserNFTSet: %s:%s:%s\n", prefix,
|
||||
nfproto_to_string(c->dynamic_user_nft_set_context[i].nfproto),
|
||||
c->dynamic_user_nft_set_context[i].table,
|
||||
c->dynamic_user_nft_set_context[i].set);
|
||||
|
||||
strv_dump(f, prefix, "SupplementaryGroups", c->supplementary_groups);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ typedef struct Manager Manager;
|
||||
#include "cpu-set-util.h"
|
||||
#include "exec-util.h"
|
||||
#include "fdset.h"
|
||||
#include "firewall-util.h"
|
||||
#include "list.h"
|
||||
#include "missing_resource.h"
|
||||
#include "namespace.h"
|
||||
@@ -313,6 +314,9 @@ struct ExecContext {
|
||||
bool mount_apivfs;
|
||||
|
||||
bool dynamic_user;
|
||||
size_t n_dynamic_user_nft_set_contexts;
|
||||
NFTSetContext *dynamic_user_nft_set_context;
|
||||
|
||||
bool remove_ipc;
|
||||
|
||||
bool memory_deny_write_execute;
|
||||
@@ -522,3 +526,5 @@ const char* exec_resource_type_to_string(ExecDirectoryType i) _const_;
|
||||
ExecDirectoryType exec_resource_type_from_string(const char *s) _pure_;
|
||||
|
||||
bool exec_needs_mount_namespace(const ExecContext *context, const ExecParameters *params, const ExecRuntime *runtime);
|
||||
|
||||
void exec_delete_dynamic_user_nft_set(const ExecContext *c, DynamicUser *d);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
{{type}}.PassEnvironment, config_parse_pass_environ, 0, offsetof({{type}}, exec_context.pass_environment)
|
||||
{{type}}.UnsetEnvironment, config_parse_unset_environ, 0, offsetof({{type}}, exec_context.unset_environment)
|
||||
{{type}}.DynamicUser, config_parse_bool, true, offsetof({{type}}, exec_context.dynamic_user)
|
||||
{{type}}.DynamicUserNFTSet, config_parse_dynamic_user_nft_set, 0, offsetof({{type}}, exec_context)
|
||||
{{type}}.RemoveIPC, config_parse_bool, 0, offsetof({{type}}, exec_context.remove_ipc)
|
||||
{{type}}.StandardInput, config_parse_exec_input, 0, offsetof({{type}}, exec_context)
|
||||
{{type}}.StandardOutput, config_parse_exec_output, 0, offsetof({{type}}, exec_context)
|
||||
|
||||
@@ -6607,3 +6607,20 @@ int config_parse_cgroup_nft_set(
|
||||
|
||||
return config_parse_nft_set(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &c->nft_set_context, &c->n_nft_set_contexts, u);
|
||||
}
|
||||
|
||||
int config_parse_dynamic_user_nft_set(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
ExecContext *c = data;
|
||||
Unit *u = userdata;
|
||||
|
||||
return config_parse_nft_set(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &c->dynamic_user_nft_set_context, &c->n_dynamic_user_nft_set_contexts, u);
|
||||
}
|
||||
|
||||
@@ -151,6 +151,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_restrict_network_interfaces);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_watchdog_sec);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_tty_size);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_cgroup_nft_set);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dynamic_user_nft_set);
|
||||
|
||||
/* gperf prototypes */
|
||||
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
|
||||
|
||||
@@ -1877,6 +1877,9 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||
/* Get rid of the IPC bits of the user */
|
||||
unit_unref_uid_gid(UNIT(s), true);
|
||||
|
||||
/* Delete DynamicUserNFTSet= */
|
||||
exec_delete_dynamic_user_nft_set(&s->exec_context, s->dynamic_creds.user);
|
||||
|
||||
/* Release the user, and destroy it if we are the only remaining owner */
|
||||
dynamic_creds_destroy(&s->dynamic_creds);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "exec-util.h"
|
||||
#include "exit-status.h"
|
||||
#include "fileio.h"
|
||||
#include "firewall-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "hostname-util.h"
|
||||
#include "in-addr-util.h"
|
||||
@@ -434,6 +435,91 @@ static int bus_append_ip_address_access(sd_bus_message *m, int family, const uni
|
||||
return sd_bus_message_close_container(m);
|
||||
}
|
||||
|
||||
static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (isempty(eq)) {
|
||||
r = sd_bus_message_append(m, "(sv)", field, "a(iss)", 0);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'v', "a(iss)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "(iss)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
int family;
|
||||
|
||||
r = extract_first_word(&eq, &word, ":", 0);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse %s: %m", field);
|
||||
if (isempty(word)) {
|
||||
log_error("Failed to parse %s", field);
|
||||
return 0;
|
||||
}
|
||||
|
||||
family = nfproto_from_string(word);
|
||||
if (family < 0)
|
||||
return log_error_errno(family, "Failed to parse %s: %m", field);
|
||||
|
||||
r = extract_first_word(&eq, &word, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse %s: %m", field);
|
||||
if (isempty(word) || isempty(eq)) {
|
||||
log_error("Failed to parse %s", field);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *unescaped = NULL;
|
||||
ssize_t l;
|
||||
|
||||
l = cunescape(eq, 0, &unescaped);
|
||||
if (l < 0)
|
||||
return log_error_errno(l, "Failed to unescape %s= value: %s", field, eq);
|
||||
|
||||
r = sd_bus_message_append(m, "(iss)", family, word, eq);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
|
||||
int r;
|
||||
|
||||
@@ -2051,6 +2137,9 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (STR_IN_SET(field, "DynamicUserNFTSet"))
|
||||
return bus_append_nft_set(m, field, eq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ DevicePolicy=
|
||||
DirectoryMode=
|
||||
DisableControllers=
|
||||
DynamicUser=
|
||||
DynamicUserNFTSet=
|
||||
Environment=
|
||||
EnvironmentFile=
|
||||
ExecPaths=
|
||||
|
||||
@@ -160,6 +160,7 @@ DeviceAllow=
|
||||
DevicePolicy=
|
||||
DisableControllers=
|
||||
DynamicUser=
|
||||
DynamicUserNFTSet=
|
||||
Environment=
|
||||
EnvironmentFile=
|
||||
ExecCondition=
|
||||
|
||||
@@ -44,6 +44,7 @@ DevicePolicy=
|
||||
DirectoryMode=
|
||||
DisableControllers=
|
||||
DynamicUser=
|
||||
DynamicUserNFTSet=
|
||||
Environment=
|
||||
EnvironmentFile=
|
||||
ExecPaths=
|
||||
|
||||
@@ -37,6 +37,7 @@ DeviceAllow=
|
||||
DevicePolicy=
|
||||
DisableControllers=
|
||||
DynamicUser=
|
||||
DynamicUserNFTSet=
|
||||
Environment=
|
||||
EnvironmentFile=
|
||||
ExecPaths=
|
||||
|
||||
Reference in New Issue
Block a user