@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(say) SetCredential = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(say) SetCredentialEncrypted = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ss) LoadCredential = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(ss) LoadCredentialEncrypted = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as SupplementaryGroups = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s PAMName = '...';
<!--property SetCredential is not documented!-->
+ <!--property SetCredentialEncrypted is not documented!-->
+
<!--property LoadCredential is not documented!-->
+ <!--property LoadCredentialEncrypted is not documented!-->
+
<!--property SupplementaryGroups is not documented!-->
<!--property PAMName is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="SetCredentialEncrypted"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="LoadCredential"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="LoadCredentialEncrypted"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
<variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(say) SetCredential = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(say) SetCredentialEncrypted = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ss) LoadCredential = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(ss) LoadCredentialEncrypted = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as SupplementaryGroups = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s PAMName = '...';
<!--property SetCredential is not documented!-->
+ <!--property SetCredentialEncrypted is not documented!-->
+
<!--property LoadCredential is not documented!-->
+ <!--property LoadCredentialEncrypted is not documented!-->
+
<!--property SupplementaryGroups is not documented!-->
<!--property PAMName is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="SetCredentialEncrypted"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="LoadCredential"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="LoadCredentialEncrypted"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
<variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(say) SetCredential = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(say) SetCredentialEncrypted = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ss) LoadCredential = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(ss) LoadCredentialEncrypted = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as SupplementaryGroups = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s PAMName = '...';
<!--property SetCredential is not documented!-->
+ <!--property SetCredentialEncrypted is not documented!-->
+
<!--property LoadCredential is not documented!-->
+ <!--property LoadCredentialEncrypted is not documented!-->
+
<!--property SupplementaryGroups is not documented!-->
<!--property PAMName is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="SetCredentialEncrypted"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="LoadCredential"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="LoadCredentialEncrypted"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
<variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(say) SetCredential = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(say) SetCredentialEncrypted = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ss) LoadCredential = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(ss) LoadCredentialEncrypted = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as SupplementaryGroups = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s PAMName = '...';
<!--property SetCredential is not documented!-->
+ <!--property SetCredentialEncrypted is not documented!-->
+
<!--property LoadCredential is not documented!-->
+ <!--property LoadCredentialEncrypted is not documented!-->
+
<!--property SupplementaryGroups is not documented!-->
<!--property PAMName is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="SetCredentialEncrypted"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="LoadCredential"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="LoadCredentialEncrypted"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
<variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
HASHMAP_FOREACH(sc, c->set_credentials) {
+ if (sc->encrypted != streq(property, "SetCredentialEncrypted"))
+ continue;
+
r = sd_bus_message_open_container(reply, 'r', "say");
if (r < 0)
return r;
sd_bus_error *error) {
ExecContext *c = userdata;
- char **i, **j;
+ ExecLoadCredential *lc;
int r;
assert(bus);
if (r < 0)
return r;
- STRV_FOREACH_PAIR(i, j, c->load_credentials) {
- r = sd_bus_message_append(reply, "(ss)", *i, *j);
+ HASHMAP_FOREACH(lc, c->load_credentials) {
+
+ if (lc->encrypted != streq(property, "LoadCredentialEncrypted"))
+ continue;
+
+ r = sd_bus_message_append(reply, "(ss)", lc->id, lc->path);
if (r < 0)
return r;
}
SD_BUS_PROPERTY("DynamicUser", "b", bus_property_get_bool, offsetof(ExecContext, dynamic_user), 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),
SD_BUS_PROPERTY("LoadCredential", "a(ss)", property_get_load_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LoadCredentialEncrypted", "a(ss)", property_get_load_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST),
return 1;
- } else if (streq(name, "SetCredential")) {
+ } else if (STR_IN_SET(name, "SetCredential", "SetCredentialEncrypted")) {
bool isempty = true;
r = sd_bus_message_enter_container(message, 'a', "(say)");
if (old) {
free_and_replace(old->data, copy);
old->size = sz;
+ old->encrypted = streq(name, "SetCredentialEncrypted");
} else {
_cleanup_(exec_set_credential_freep) ExecSetCredential *sc = NULL;
- sc = new0(ExecSetCredential, 1);
+ sc = new(ExecSetCredential, 1);
if (!sc)
return -ENOMEM;
- sc->id = strdup(id);
+ *sc = (ExecSetCredential) {
+ .id = strdup(id),
+ .data = TAKE_PTR(copy),
+ .size = sz,
+ .encrypted = streq(name, "SetCredentialEncrypted"),
+ };
+
if (!sc->id)
return -ENOMEM;
- sc->data = TAKE_PTR(copy);
- sc->size = sz;
-
r = hashmap_ensure_put(&c->set_credentials, &exec_set_credential_hash_ops, sc->id, sc);
if (r < 0)
return r;
return 1;
- } else if (streq(name, "LoadCredential")) {
+ } else if (STR_IN_SET(name, "LoadCredential", "LoadCredentialEncrypted")) {
bool isempty = true;
r = sd_bus_message_enter_container(message, 'a', "(ss)");
isempty = false;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- r = strv_extend_strv(&c->load_credentials, STRV_MAKE(id, source), /* filter_duplicates = */ false);
- if (r < 0)
- return r;
+ _cleanup_free_ char *copy = NULL;
+ ExecLoadCredential *old;
+
+ copy = strdup(source);
+ if (!copy)
+ return -ENOMEM;
+
+ old = hashmap_get(c->load_credentials, id);
+ if (old) {
+ free_and_replace(old->path, copy);
+ old->encrypted = streq(name, "LoadCredentialEncrypted");
+ } else {
+ _cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
+
+ lc = new(ExecLoadCredential, 1);
+ if (!lc)
+ return -ENOMEM;
+
+ *lc = (ExecLoadCredential) {
+ .id = strdup(id),
+ .path = TAKE_PTR(copy),
+ .encrypted = streq(name, "LoadCredentialEncrypted"),
+ };
+
+ if (!lc->id)
+ return -ENOMEM;
+
+ r = hashmap_ensure_put(&c->load_credentials, &exec_load_credential_hash_ops, lc->id, lc);
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(lc);
+ }
(void) unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s:%s", name, id, source);
}
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags) && isempty) {
- c->load_credentials = strv_free(c->load_credentials);
+ c->load_credentials = hashmap_free(c->load_credentials);
(void) unit_write_settingf(u, flags, name, "%s=", name);
}
#include "cgroup-setup.h"
#include "chown-recursive.h"
#include "cpu-set-util.h"
+#include "creds-util.h"
#include "data-fd-util.h"
#include "def.h"
#include "env-file.h"
assert(context);
return !hashmap_isempty(context->set_credentials) ||
- context->load_credentials;
+ !hashmap_isempty(context->load_credentials);
}
#if HAVE_SECCOMP
return -errno;
}
- r = loop_write(fd, data, size, /* do_pool = */ false);
+ r = loop_write(fd, data, size, /* do_poll = */ false);
if (r < 0)
return r;
return 0;
}
-#define CREDENTIALS_BYTES_MAX (1024LU * 1024LU) /* Refuse to pass more than 1M, after all this is unswappable memory */
-
static int acquire_credentials(
const ExecContext *context,
const ExecParameters *params,
uid_t uid,
bool ownership_ok) {
- uint64_t left = CREDENTIALS_BYTES_MAX;
+ uint64_t left = CREDENTIALS_TOTAL_SIZE_MAX;
_cleanup_close_ int dfd = -1;
+ ExecLoadCredential *lc;
ExecSetCredential *sc;
- char **id, **fn;
int r;
assert(context);
if (dfd < 0)
return -errno;
- /* First we use the literally specified credentials. Note that they might be overridden again below,
- * and thus act as a "default" if the same credential is specified multiple times */
- HASHMAP_FOREACH(sc, context->set_credentials) {
- size_t add;
-
- add = strlen(sc->id) + sc->size;
- if (add > left)
- return -E2BIG;
-
- r = write_credential(dfd, sc->id, sc->data, sc->size, uid, ownership_ok);
- if (r < 0)
- return r;
-
- left -= add;
- }
-
- /* Then, load credential off disk (or acquire via AF_UNIX socket) */
- STRV_FOREACH_PAIR(id, fn, context->load_credentials) {
- ReadFullFileFlags flags = READ_FULL_FILE_SECURE;
+ /* First, load credentials off disk (or acquire via AF_UNIX socket) */
+ HASHMAP_FOREACH(lc, context->load_credentials) {
+ ReadFullFileFlags flags = READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER;
_cleanup_(erase_and_freep) char *data = NULL;
_cleanup_free_ char *j = NULL, *bindname = NULL;
bool missing_ok = true;
const char *source;
size_t size, add;
- if (path_is_absolute(*fn)) {
+ if (path_is_absolute(lc->path)) {
/* If this is an absolute path, read the data directly from it, and support AF_UNIX sockets */
- source = *fn;
+ source = lc->path;
flags |= READ_FULL_FILE_CONNECT_SOCKET;
/* Pass some minimal info about the unit and the credential name we are looking to acquire
* via the source socket address in case we read off an AF_UNIX socket. */
- if (asprintf(&bindname, "@%" PRIx64"/unit/%s/%s", random_u64(), unit, *id) < 0)
+ if (asprintf(&bindname, "@%" PRIx64"/unit/%s/%s", random_u64(), unit, lc->id) < 0)
return -ENOMEM;
missing_ok = false;
/* If this is a relative path, take it relative to the credentials we received
* ourselves. We don't support the AF_UNIX stuff in this mode, since we are operating
* on a credential store, i.e. this is guaranteed to be regular files. */
- j = path_join(params->received_credentials, *fn);
+ j = path_join(params->received_credentials, lc->path);
if (!j)
return -ENOMEM;
source = NULL;
if (source)
- r = read_full_file_full(AT_FDCWD, source, UINT64_MAX, SIZE_MAX, flags, bindname, &data, &size);
+ r = read_full_file_full(
+ AT_FDCWD, source,
+ UINT64_MAX,
+ lc->encrypted ? CREDENTIAL_ENCRYPTED_SIZE_MAX : CREDENTIAL_SIZE_MAX,
+ flags | (lc->encrypted ? READ_FULL_FILE_UNBASE64 : 0),
+ bindname,
+ &data, &size);
else
r = -ENOENT;
- if (r == -ENOENT && (missing_ok || faccessat(dfd, *id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)) {
+ if (r == -ENOENT && (missing_ok || hashmap_contains(context->set_credentials, lc->id))) {
/* Make a missing inherited credential non-fatal, let's just continue. After all apps
* will get clear errors if we don't pass such a missing credential on as they
* themselves will get ENOENT when trying to read them, which should not be much
* worse than when we handle the error here and make it fatal.
*
- * Also, if the source file doesn't exist, but we already acquired the key otherwise,
- * then don't fail either. */
- log_debug_errno(r, "Couldn't read inherited credential '%s', skipping: %m", *fn);
+ * Also, if the source file doesn't exist, but a fallback is set via SetCredentials=
+ * we are fine, too. */
+ log_debug_errno(r, "Couldn't read inherited credential '%s', skipping: %m", lc->path);
continue;
}
if (r < 0)
- return log_debug_errno(r, "Failed to read credential '%s': %m", *fn);
+ return log_debug_errno(r, "Failed to read credential '%s': %m", lc->path);
+
+ if (lc->encrypted) {
+ _cleanup_free_ void *plaintext = NULL;
+ size_t plaintext_size = 0;
+
+ r = decrypt_credential_and_warn(lc->id, now(CLOCK_REALTIME), NULL, data, size, &plaintext, &plaintext_size);
+ if (r < 0)
+ return r;
- add = strlen(*id) + size;
+ free_and_replace(data, plaintext);
+ size = plaintext_size;
+ }
+
+ add = strlen(lc->id) + size;
if (add > left)
return -E2BIG;
- r = write_credential(dfd, *id, data, size, uid, ownership_ok);
+ r = write_credential(dfd, lc->id, data, size, uid, ownership_ok);
if (r < 0)
return r;
left -= add;
}
+ /* First we use the literally specified credentials. Note that they might be overridden again below,
+ * and thus act as a "default" if the same credential is specified multiple times */
+ HASHMAP_FOREACH(sc, context->set_credentials) {
+ _cleanup_(erase_and_freep) void *plaintext = NULL;
+ const char *data;
+ size_t size, add;
+
+ if (faccessat(dfd, sc->id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
+ continue;
+ if (errno != ENOENT)
+ return log_debug_errno(errno, "Failed to test if credential %s exists: %m", sc->id);
+
+ if (sc->encrypted) {
+ r = decrypt_credential_and_warn(sc->id, now(CLOCK_REALTIME), NULL, sc->data, sc->size, &plaintext, &size);
+ if (r < 0)
+ return r;
+
+ data = plaintext;
+ } else {
+ data = sc->data;
+ size = sc->size;
+ }
+
+ add = strlen(sc->id) + size;
+ if (add > left)
+ return -E2BIG;
+
+ r = write_credential(dfd, sc->id, data, size, uid, ownership_ok);
+ if (r < 0)
+ return r;
+
+
+ left -= add;
+ }
+
if (fchmod(dfd, 0500) < 0) /* Now take away the "w" bit */
return -errno;
} else if (try == 1) {
_cleanup_free_ char *opts = NULL;
- if (asprintf(&opts, "mode=0700,nr_inodes=1024,size=%lu", CREDENTIALS_BYTES_MAX) < 0)
+ if (asprintf(&opts, "mode=0700,nr_inodes=1024,size=%zu", (size_t) CREDENTIALS_TOTAL_SIZE_MAX) < 0)
return -ENOMEM;
/* Fall back to "tmpfs" otherwise */
c->log_namespace = mfree(c->log_namespace);
- c->load_credentials = strv_free(c->load_credentials);
+ c->load_credentials = hashmap_free(c->load_credentials);
c->set_credentials = hashmap_free(c->set_credentials);
}
return mfree(sc);
}
+ExecLoadCredential *exec_load_credential_free(ExecLoadCredential *lc) {
+ if (!lc)
+ return NULL;
+
+ free(lc->id);
+ free(lc->path);
+ return mfree(lc);
+}
+
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(exec_set_credential_hash_ops, char, string_hash_func, string_compare_func, ExecSetCredential, exec_set_credential_free);
+DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(exec_load_credential_hash_ops, char, string_hash_func, string_compare_func, ExecLoadCredential, exec_load_credential_free);
static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
[EXEC_INPUT_NULL] = "null",
_EXEC_CLEAN_MASK_INVALID = -EINVAL,
} ExecCleanMask;
+/* A credential configured with LoadCredential= */
+typedef struct ExecLoadCredential {
+ char *id, *path;
+ bool encrypted;
+} ExecLoadCredential;
+
/* A credential configured with SetCredential= */
typedef struct ExecSetCredential {
char *id;
+ bool encrypted;
void *data;
size_t size;
} ExecSetCredential;
usec_t timeout_clean_usec;
Hashmap *set_credentials; /* output id → ExecSetCredential */
- char **load_credentials; /* pairs of output id, path/input id */
+ Hashmap *load_credentials; /* output id → ExecLoadCredential */
};
static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) {
ExecSetCredential *exec_set_credential_free(ExecSetCredential *sc);
DEFINE_TRIVIAL_CLEANUP_FUNC(ExecSetCredential*, exec_set_credential_free);
+ExecLoadCredential *exec_load_credential_free(ExecLoadCredential *lc);
+DEFINE_TRIVIAL_CLEANUP_FUNC(ExecLoadCredential*, exec_load_credential_free);
+
extern const struct hash_ops exec_set_credential_hash_ops;
+extern const struct hash_ops exec_load_credential_hash_ops;
const char* exec_output_to_string(ExecOutput i) _const_;
ExecOutput exec_output_from_string(const char *s) _pure_;
{{type}}.ConfigurationDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].mode)
{{type}}.ConfigurationDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].paths)
{{type}}.SetCredential, config_parse_set_credential, 0, offsetof({{type}}, exec_context)
+{{type}}.SetCredentialEncrypted, config_parse_set_credential, 1, offsetof({{type}}, exec_context)
{{type}}.LoadCredential, config_parse_load_credential, 0, offsetof({{type}}, exec_context)
+{{type}}.LoadCredentialEncrypted, config_parse_load_credential, 1, offsetof({{type}}, exec_context)
{{type}}.TimeoutCleanSec, config_parse_sec, 0, offsetof({{type}}, exec_context.timeout_clean_usec)
{% if HAVE_PAM %}
{{type}}.PAMName, config_parse_unit_string_printf, 0, offsetof({{type}}, exec_context.pam_name)
void *data,
void *userdata) {
- _cleanup_free_ char *word = NULL, *k = NULL, *unescaped = NULL;
+ _cleanup_free_ char *word = NULL, *k = NULL;
+ _cleanup_free_ void *d = NULL;
ExecContext *context = data;
ExecSetCredential *old;
Unit *u = userdata;
- const char *p;
- int r, l;
+ bool encrypted = ltype;
+ const char *p = rvalue;
+ size_t size;
+ int r;
assert(filename);
assert(lvalue);
return 0;
}
- p = rvalue;
r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r == -ENOMEM)
return log_oom();
return 0;
}
- /* We support escape codes here, so that users can insert trailing \n if they like */
- l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
- if (l < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, l, "Can't unescape \"%s\", ignoring: %m", p);
- return 0;
+ if (encrypted) {
+ r = unbase64mem_full(p, SIZE_MAX, true, &d, &size);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Encrypted credential data not valid Base64 data, ignoring.");
+ return 0;
+ }
+ } else {
+ char *unescaped = NULL;
+ int l;
+
+ /* We support escape codes here, so that users can insert trailing \n if they like */
+ l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
+ if (l < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, l, "Can't unescape \"%s\", ignoring: %m", p);
+ return 0;
+ }
+
+ d = unescaped;
+ size = l;
}
old = hashmap_get(context->set_credentials, k);
if (old) {
- free_and_replace(old->data, unescaped);
- old->size = l;
+ free_and_replace(old->data, d);
+ old->size = size;
+ old->encrypted = encrypted;
} else {
_cleanup_(exec_set_credential_freep) ExecSetCredential *sc = NULL;
- sc = new0(ExecSetCredential, 1);
+ sc = new(ExecSetCredential, 1);
if (!sc)
return log_oom();
- sc->id = TAKE_PTR(k);
- sc->data = TAKE_PTR(unescaped);
- sc->size = l;
+ *sc = (ExecSetCredential) {
+ .id = TAKE_PTR(k),
+ .data = TAKE_PTR(d),
+ .size = size,
+ .encrypted = encrypted,
+ };
r = hashmap_ensure_put(&context->set_credentials, &exec_set_credential_hash_ops, sc->id, sc);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, l,
+ log_syntax(unit, LOG_WARNING, filename, line, r,
"Duplicated credential value '%s', ignoring assignment: %s", sc->id, rvalue);
return 0;
}
_cleanup_free_ char *word = NULL, *k = NULL, *q = NULL;
ExecContext *context = data;
+ ExecLoadCredential *old;
+ bool encrypted = ltype;
Unit *u = userdata;
const char *p;
int r;
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- context->load_credentials = strv_free(context->load_credentials);
+ context->load_credentials = hashmap_free(context->load_credentials);
return 0;
}
return 0;
}
if (path_is_absolute(q) ? !path_is_normalized(q) : !credential_name_valid(q)) {
- log_syntax(unit, LOG_WARNING, filename, line, r, "Credential source \"%s\" not valid, ignoring.", q);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential source \"%s\" not valid, ignoring.", q);
return 0;
}
}
- r = strv_consume_pair(&context->load_credentials, TAKE_PTR(k), TAKE_PTR(q));
- if (r < 0)
- return log_oom();
+ old = hashmap_get(context->load_credentials, k);
+ if (old) {
+ free_and_replace(old->path, q);
+ old->encrypted = encrypted;
+ } else {
+ _cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
+
+ lc = new(ExecLoadCredential, 1);
+ if (!lc)
+ return log_oom();
+
+ *lc = (ExecLoadCredential) {
+ .id = TAKE_PTR(k),
+ .path = TAKE_PTR(q),
+ .encrypted = encrypted,
+ };
+
+ r = hashmap_ensure_put(&context->load_credentials, &exec_load_credential_hash_ops, lc->id, lc);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Duplicated credential value '%s', ignoring assignment: %s", lc->id, rvalue);
+ return 0;
+ }
+
+ TAKE_PTR(lc);
+ }
return 0;
}
return 1;
}
- if (streq(field, "SetCredential")) {
+ if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) {
r = sd_bus_message_open_container(m, 'r', "sv");
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append_basic(m, 's', "SetCredential");
+ r = sd_bus_message_append_basic(m, 's', field);
if (r < 0)
return bus_log_create_error(r);
if (isempty(eq))
r = sd_bus_message_append(m, "a(say)", 0);
else {
- _cleanup_free_ char *word = NULL, *unescaped = NULL;
+ _cleanup_free_ char *word = NULL;
const char *p = eq;
- int l;
r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
- return log_error_errno(r, "Failed to parse SetCredential= parameter: %s", eq);
+ return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
if (r == 0 || !p)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to SetCredential=.");
-
- l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
- if (l < 0)
- return log_error_errno(l, "Failed to unescape SetCredential= value: %s", p);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
r = sd_bus_message_open_container(m, 'a', "(say)");
if (r < 0)
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append_array(m, 'y', unescaped, l);
+ if (streq(field, "SetCredentialEncrypted")) {
+ _cleanup_free_ void *decoded = NULL;
+ size_t decoded_size;
+
+ r = unbase64mem(p, SIZE_MAX, &decoded, &decoded_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
+
+ r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
+ } else {
+ _cleanup_free_ char *unescaped = NULL;
+ int l;
+
+ l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
+ if (l < 0)
+ return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
+
+ r = sd_bus_message_append_array(m, 'y', unescaped, l);
+ }
if (r < 0)
return bus_log_create_error(r);
return 1;
}
- if (streq(field, "LoadCredential")) {
+ if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) {
r = sd_bus_message_open_container(m, 'r', "sv");
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append_basic(m, 's', "LoadCredential");
+ r = sd_bus_message_append_basic(m, 's', field);
if (r < 0)
return bus_log_create_error(r);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
- return log_error_errno(r, "Failed to parse LoadCredential= parameter: %s", eq);
+ return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
if (r == 0 || !p)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to LoadCredential=.");
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
r = sd_bus_message_append(m, "a(ss)", 1, word, p);
}
LimitSIGPENDING=
LimitSTACK=
LoadCredential=
+LoadCredentialEncrypted=
LockPersonality=
LogExtraFields=
LogLevelMax=
SendSIGHUP=
SendSIGKILL=
SetCredential=
+SetCredentialEncrypted=
Slice=
SloppyOptions=
SmackProcessLabel=
LimitSIGPENDING=
LimitSTACK=
LoadCredential=
+LoadCredentialEncrypted=
LockPersonality=
LogExtraFields=
LogLevelMax=
SendSIGHUP=
SendSIGKILL=
SetCredential=
+SetCredentialEncrypted=
Slice=
SmackProcessLabel=
Sockets=
ListenStream=
ListenUSBFunction=
LoadCredential=
+LoadCredentialEncrypted=
LockPersonality=
LogExtraFields=
LogLevelMax=
SendSIGKILL=
Service=
SetCredential=
+SetCredentialEncrypted=
Slice=
SmackLabel=
SmackLabelIPIn=
LimitSIGPENDING=
LimitSTACK=
LoadCredential=
+LoadCredentialEncrypted=
LockPersonality=
LogExtraFields=
LogLevelMax=
SendSIGHUP=
SendSIGKILL=
SetCredential=
+SetCredentialEncrypted=
Slice=
SmackProcessLabel=
SocketBindAllow=