1
0
mirror of https://github.com/systemd/systemd synced 2025-11-21 09:44:44 +01:00

Compare commits

..

No commits in common. "1353564b9d7bd11888b7ca068ffce771ce6d8e7e" and "dfb46b906ecd8391c00354f8ef97133ef0eade22" have entirely different histories.

17 changed files with 136 additions and 333 deletions

13
TODO
View File

@ -128,19 +128,6 @@ Deprecations and removals:
Features:
* systemd-repart: add --ghost, that creates file systems, updates the kernel's
partition table but does *not* update partition table on disk. This way, we
have disk backed file systems that go effectively disappear on reboot. This
is useful when booting from a "live" usb stick that is writable, as it means
we do not have to place everything in memory. Moreover, we could then migrate
the file systems to disk later (using btrfs device replacement), if needed as
part of an installer logic.
* add a concept of overlay directory stacks to image discovery, i.e. have a dir
with a name suffix of ".ovl" or so that contains DDIs and plain dirs (and
possible .v dirs) that are glued together on use via overlayfs. one special
subdir should be used as writable top layer.
* journald: log pidfid as another field, i.e. _PIDFDID=
* systemd-nspawn: something like --volatile= but that isn't volatile, but

View File

@ -175,7 +175,6 @@ method GetUserRecord(
dispositionMask: ?[]string,
uidMin: ?int,
uidMax: ?int,
uuid: ?string,
service : string
) -> (
record : object,
@ -189,7 +188,6 @@ method GetGroupRecord(
dispositionMask: ?[]string,
gidMin: ?int,
gidMax: ?int,
uuid: ?string,
service : string
) -> (
record : object,
@ -224,7 +222,7 @@ If neither of the two parameters are set the whole user database is enumerated.
In this case the method call needs to be made with `more` set, so that multiple method call replies may be generated as
effect, each carrying one user record.
The `fuzzyNames`, `dispositionMask`, `uidMin`, `uidMax` and `uuid` fields permit
The `fuzzyNames`, `dispositionMask`, `uidMin`, `uidMax` fields permit
*additional* filtering of the returned set of user records. The `fuzzyNames`
parameter shall be one or more strings that shall be searched for in "fuzzy"
way. What specifically this means is left for the backend to decide, but
@ -234,20 +232,19 @@ carry identifying information for the user. The `dispositionMask` field shall
be one of more user record `disposition` strings. If specified only user
records matching one of the specified dispositions should be enumerated. The
`uidMin` and `uidMax` fields specify a minimum and maximum value for the UID of
returned records. The `uuid` field specifies to search for the user record associated
with the specified UUID. Inline searching for `uid` and `userName` support for
returned records. Inline searching for `uid` and `userName` support for
filtering with these four additional parameters is optional, and clients are
expected to be able to do client-side filtering in case the parameters are not
supported by a service. The service should return the usual `InvalidParameter`
error for the relevant parameter if one is passed and it does not support
it. If a request is made specifying `uid` or `userName` and a suitable record
is found, but the specified filter via `fuzzyNames`, `dispositionMask`,
`uidMin`, `uidMax` or `uuid` does not match, a `NonMatchingRecordFound` error should
`uidMin`, or `uidMax` does not match, a `NonMatchingRecordFound` error should
be returned.
Or to say this differently: the *primary search keys* are
`userName`/`groupName` and `uid`/`gid` and the *secondary search filters* are
`fuzzyNames`, `dispositionMask`, `uidMin`, `uidMax`, `uuid`. If no entry matching
`fuzzyNames`, `dispositionMask`, `uidMin`, `uidMax`. If no entry matching
either of the primary search keys are found `NoRecordFound()` is returned. If
one is found that matches one but not the other primary search key
`ConflictingRecordFound()` is returned. If an entry is found that matches the

View File

@ -424,19 +424,11 @@
<varlistentry>
<term><option>--allow-null</option></term>
<listitem><para>Allow decrypting credentials that use a null key. By default decryption of credentials encrypted/authenticated with a null key is only allowed if UEFI SecureBoot is off.</para>
<listitem><para>Allow decrypting credentials that use an empty key.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--refuse-null</option></term>
<listitem><para>Refuse decrypting credentials that use a null key, regardless of the UEFI SecureBoot state (see above).</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--quiet</option></term>
<term><option>-q</option></term>

View File

@ -227,15 +227,6 @@
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--uuid=</option></term>
<listitem><para>When used with the <command>user</command> or <command>group</command> command,
filters the output to the record with the specified UUID. If unspecified, no UUID-based filtering is applied.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--boundaries=</option></term>

View File

@ -72,7 +72,7 @@ static bool arg_pretty = false;
static bool arg_quiet = false;
static bool arg_varlink = false;
static uid_t arg_uid = UID_INVALID;
static CredentialFlags arg_credential_flags = 0;
static bool arg_allow_null = false;
static bool arg_ask_password = true;
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep);
@ -99,7 +99,7 @@ typedef enum CredKeyType {
CRED_KEY_TYPE_HOST_TPM2_PUBLIC,
CRED_KEY_TYPE_TPM2_PUBLIC_HOST,
CRED_KEY_TYPE_NULL,
CRED_KEY_TYPE_TPM2_ABSENT,
CRED_KEY_TYPE_ABSENT,
_CRED_KEY_TYPE_MAX,
_CRED_KEY_TYPE_INVALID = -EINVAL,
} CredKeyType;
@ -115,7 +115,7 @@ static const char* cred_key_type_table[_CRED_KEY_TYPE_MAX] = {
[CRED_KEY_TYPE_HOST_TPM2_PUBLIC] = "host+tpm2-with-public-key",
[CRED_KEY_TYPE_TPM2_PUBLIC_HOST] = "tpm2-with-public-key+host",
[CRED_KEY_TYPE_NULL] = "null",
[CRED_KEY_TYPE_TPM2_ABSENT] = "tpm2-absent", /* legacy alias */
[CRED_KEY_TYPE_ABSENT] = "tpm2-absent",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(cred_key_type, CredKeyType);
@ -131,7 +131,7 @@ static sd_id128_t cred_key_id[_CRED_KEY_TYPE_MAX] = {
[CRED_KEY_TYPE_HOST_TPM2_PUBLIC] = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK,
[CRED_KEY_TYPE_TPM2_PUBLIC_HOST] = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK,
[CRED_KEY_TYPE_NULL] = CRED_AES256_GCM_BY_NULL,
[CRED_KEY_TYPE_TPM2_ABSENT] = CRED_AES256_GCM_BY_NULL,
[CRED_KEY_TYPE_ABSENT] = CRED_AES256_GCM_BY_NULL,
};
static int open_credential_directory(
@ -526,7 +526,7 @@ static int verb_cat(int argc, char **argv, void *userdata) {
timestamp,
uid_is_valid(arg_uid) ? arg_uid : getuid(),
&IOVEC_MAKE(data, size),
arg_credential_flags | CREDENTIAL_ANY_SCOPE,
CREDENTIAL_ANY_SCOPE,
&plaintext);
else
r = decrypt_credential_and_warn(
@ -536,7 +536,7 @@ static int verb_cat(int argc, char **argv, void *userdata) {
arg_tpm2_signature,
uid_is_valid(arg_uid) ? arg_uid : getuid(),
&IOVEC_MAKE(data, size),
arg_credential_flags | CREDENTIAL_ANY_SCOPE,
CREDENTIAL_ANY_SCOPE,
&plaintext);
if (r < 0)
return r;
@ -608,7 +608,7 @@ static int verb_encrypt(int argc, char **argv, void *userdata) {
arg_not_after,
arg_uid,
&plaintext,
arg_credential_flags,
arg_ask_password ? CREDENTIAL_IPC_ALLOW_INTERACTIVE : 0,
&output);
} else
r = encrypt_credential_and_warn(
@ -622,7 +622,7 @@ static int verb_encrypt(int argc, char **argv, void *userdata) {
arg_tpm2_public_key_pcr_mask,
arg_uid,
&plaintext,
arg_credential_flags,
/* flags= */ 0,
&output);
if (r < 0)
return r;
@ -713,7 +713,7 @@ static int verb_decrypt(int argc, char **argv, void *userdata) {
timestamp,
arg_uid,
&input,
arg_credential_flags,
arg_ask_password ? CREDENTIAL_IPC_ALLOW_INTERACTIVE : 0,
&plaintext);
} else
r = decrypt_credential_and_warn(
@ -723,7 +723,7 @@ static int verb_decrypt(int argc, char **argv, void *userdata) {
arg_tpm2_signature,
arg_uid,
&input,
arg_credential_flags,
arg_allow_null ? CREDENTIAL_ALLOW_NULL : 0,
&plaintext);
if (r < 0)
return r;
@ -815,8 +815,7 @@ static int verb_help(int argc, char **argv, void *userdata) {
" Specify signature for public key PCR policy\n"
" --user Select user-scoped credential encryption\n"
" --uid=UID Select user for scoped credentials\n"
" --allow-null Allow decrypting credentials with null key\n"
" --refuse-null Refuse decrypting credentials with null key\n"
" --allow-null Allow decrypting credentials with empty key\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@ -850,7 +849,6 @@ static int parse_argv(int argc, char *argv[]) {
ARG_USER,
ARG_UID,
ARG_ALLOW_NULL,
ARG_REFUSE_NULL,
ARG_NO_ASK_PASSWORD,
};
@ -877,7 +875,6 @@ static int parse_argv(int argc, char *argv[]) {
{ "user", no_argument, NULL, ARG_USER },
{ "uid", required_argument, NULL, ARG_UID },
{ "allow-null", no_argument, NULL, ARG_ALLOW_NULL },
{ "refuse-null", no_argument, NULL, ARG_REFUSE_NULL },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{}
};
@ -1071,13 +1068,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_ALLOW_NULL:
arg_credential_flags &= ~CREDENTIAL_REFUSE_NULL;
arg_credential_flags |= CREDENTIAL_ALLOW_NULL;
break;
case ARG_REFUSE_NULL:
arg_credential_flags |= CREDENTIAL_REFUSE_NULL;
arg_credential_flags &= ~CREDENTIAL_ALLOW_NULL;
arg_allow_null = true;
break;
case ARG_NO_ASK_PASSWORD:
@ -1096,8 +1087,6 @@ static int parse_argv(int argc, char *argv[]) {
}
}
SET_FLAG(arg_credential_flags, CREDENTIAL_IPC_ALLOW_INTERACTIVE, arg_ask_password);
if (uid_is_valid(arg_uid)) {
/* If a UID is specified, then switch to scoped credentials */
@ -1178,7 +1167,6 @@ typedef struct MethodEncryptParameters {
uint64_t timestamp;
uint64_t not_after;
CredentialScope scope;
sd_id128_t with_key;
uid_t uid;
} MethodEncryptParameters;
@ -1232,71 +1220,6 @@ static int settle_scope(
return 0;
}
static bool normalize_separator(char c) {
if (IN_SET(c, '-', '+', '_'))
return '_';
return c;
}
static bool enum_name_equal(const char *x, const char *y) {
if (x == y)
return true;
if (!x || !y)
return false;
for (;; x++, y++) {
char a = normalize_separator(*x), b = normalize_separator(*y);
if (a != b)
return false;
if (a == 0)
return true;
}
}
static CredKeyType cred_key_type_from_string_harder(const char *s) {
if (!s)
return _CRED_KEY_TYPE_INVALID;
CredKeyType t = cred_key_type_from_string(s);
if (t >= 0)
return t;
/* Varlink doesn't like dashes and plusses in enum names. Try to match when considering them equal to underscores */
for (t = 0; t < _CRED_KEY_TYPE_MAX; t++)
if (enum_name_equal(cred_key_type_table[t], s))
return t;
return _CRED_KEY_TYPE_INVALID;
}
static int dispatch_credential_key_type(
const char *name,
sd_json_variant *variant,
sd_json_dispatch_flags_t flags,
void *userdata) {
sd_id128_t *id = ASSERT_PTR(userdata);
if (sd_json_variant_is_null(variant)) {
*id = SD_ID128_NULL;
return 0;
}
const char *s = sd_json_variant_string(variant);
if (isempty(s)) {
*id = SD_ID128_NULL;
return 0;
}
CredKeyType t = cred_key_type_from_string_harder(s);
if (t < 0)
return json_log(variant, flags, t, "JSON field '%s' is not a valid key type.", strna(name));
*id = cred_key_id[t];
return 0;
}
static int vl_method_encrypt(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dispatch_table[] = {
@ -1306,7 +1229,6 @@ static int vl_method_encrypt(sd_varlink *link, sd_json_variant *parameters, sd_v
{ "timestamp", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(MethodEncryptParameters, timestamp), 0 },
{ "notAfter", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(MethodEncryptParameters, not_after), 0 },
{ "scope", SD_JSON_VARIANT_STRING, dispatch_credential_scope, offsetof(MethodEncryptParameters, scope), 0 },
{ "withKey", SD_JSON_VARIANT_STRING, dispatch_credential_key_type, offsetof(MethodEncryptParameters, with_key), SD_JSON_NULLABLE },
{ "uid", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, offsetof(MethodEncryptParameters, uid), 0 },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
@ -1367,7 +1289,7 @@ static int vl_method_encrypt(sd_varlink *link, sd_json_variant *parameters, sd_v
}
r = encrypt_credential_and_warn(
sd_id128_is_null(p.with_key) ? (p.scope == CREDENTIAL_USER ? _CRED_AUTO_SCOPED : _CRED_AUTO) : p.with_key,
p.scope == CREDENTIAL_USER ? _CRED_AUTO_SCOPED : _CRED_AUTO,
p.name,
p.timestamp,
p.not_after,
@ -1402,7 +1324,6 @@ typedef struct MethodDecryptParameters {
uint64_t timestamp;
CredentialScope scope;
uid_t uid;
int allow_null;
} MethodDecryptParameters;
static void method_decrypt_parameters_done(MethodDecryptParameters *p) {
@ -1414,12 +1335,11 @@ static void method_decrypt_parameters_done(MethodDecryptParameters *p) {
static int vl_method_decrypt(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dispatch_table[] = {
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MethodDecryptParameters, name), 0 },
{ "blob", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(MethodDecryptParameters, blob), SD_JSON_MANDATORY },
{ "timestamp", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(MethodDecryptParameters, timestamp), 0 },
{ "scope", SD_JSON_VARIANT_STRING, dispatch_credential_scope, offsetof(MethodDecryptParameters, scope), 0 },
{ "uid", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, offsetof(MethodDecryptParameters, uid), 0 },
{ "allowNull", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MethodDecryptParameters, allow_null), SD_JSON_NULLABLE },
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MethodDecryptParameters, name), 0 },
{ "blob", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(MethodDecryptParameters, blob), SD_JSON_MANDATORY },
{ "timestamp", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(MethodDecryptParameters, timestamp), 0 },
{ "scope", SD_JSON_VARIANT_STRING, dispatch_credential_scope, offsetof(MethodDecryptParameters, scope), 0 },
{ "uid", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, offsetof(MethodDecryptParameters, uid), 0 },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
};
@ -1427,7 +1347,6 @@ static int vl_method_decrypt(sd_varlink *link, sd_json_variant *parameters, sd_v
.timestamp = UINT64_MAX,
.scope = _CREDENTIAL_SCOPE_INVALID,
.uid = UID_INVALID,
.allow_null = -1,
};
bool timestamp_fresh, any_scope_after_polkit = false;
_cleanup_(iovec_done_erase) struct iovec output = {};
@ -1454,11 +1373,6 @@ static int vl_method_decrypt(sd_varlink *link, sd_json_variant *parameters, sd_v
if (r < 0)
return r;
if (p.allow_null > 0)
cflags |= CREDENTIAL_ALLOW_NULL;
else if (p.allow_null == 0)
cflags |= CREDENTIAL_REFUSE_NULL;
r = sd_varlink_get_peer_uid(link, &peer_uid);
if (r < 0)
return r;

View File

@ -222,9 +222,9 @@ static int context_open_root(Context *c) {
if (r > 0)
return 0;
c->rfd = open(arg_root, O_CLOEXEC | O_DIRECTORY | O_PATH);
c->rfd = open(empty_to_root(arg_root), O_CLOEXEC | O_DIRECTORY | O_PATH);
if (c->rfd < 0)
return log_error_errno(errno, "Failed to open root directory '%s': %m", arg_root);
return log_error_errno(errno, "Failed to open root directory '%s': %m", empty_to_root(arg_root));
return 0;
}

View File

@ -554,8 +554,8 @@ int json_dispatch_devnum(const char *name, sd_json_variant *variant, sd_json_dis
}
int json_dispatch_strv_environment(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
char ***l = ASSERT_PTR(userdata);
_cleanup_strv_free_ char **n = NULL;
char ***l = userdata;
int r;
if (sd_json_variant_is_null(variant)) {
@ -566,19 +566,20 @@ int json_dispatch_strv_environment(const char *name, sd_json_variant *variant, s
if (!sd_json_variant_is_array(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
sd_json_variant *i;
JSON_VARIANT_ARRAY_FOREACH(i, variant) {
const char *e;
for (size_t i = 0; i < sd_json_variant_elements(variant); i++) {
sd_json_variant *e;
const char *a;
if (!sd_json_variant_is_string(i))
e = sd_json_variant_by_index(variant, i);
if (!sd_json_variant_is_string(e))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of strings.", strna(name));
e = ASSERT_PTR(sd_json_variant_string(i));
if (!env_assignment_is_valid(e))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL),
"JSON field '%s' contains invalid environment variable assignment.", strna(name));
assert_se(a = sd_json_variant_string(e));
r = strv_env_replace_strdup(&n, e);
if (!env_assignment_is_valid(a))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of environment variables.", strna(name));
r = strv_env_replace_strdup(&n, a);
if (r < 0)
return json_log_oom(variant, flags);
}

View File

@ -812,9 +812,6 @@ int encrypt_credential_and_warn(
assert(iovec_is_valid(input));
assert(ret);
/* Only one of these two flags may be set at the same time */
assert(!FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL) || !FLAGS_SET(flags, CREDENTIAL_REFUSE_NULL));
if (!sd_id128_in_set(with_key,
_CRED_AUTO,
_CRED_AUTO_INITRD,
@ -1011,12 +1008,8 @@ int encrypt_credential_and_warn(
} else
id = with_key;
if (sd_id128_equal(id, CRED_AES256_GCM_BY_NULL)) {
if (FLAGS_SET(flags, CREDENTIAL_REFUSE_NULL))
return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON), "Attempted to encrypt with null key, but this is disallowed.");
if (!FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL))
log_warning("Using a null key for encryption and signing. Confidentiality or authenticity will not be provided.");
}
if (sd_id128_equal(id, CRED_AES256_GCM_BY_NULL) && !FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL))
log_warning("Using a null key for encryption and signing. Confidentiality or authenticity will not be provided.");
/* Let's now take the host key and the TPM2 key and hash it together, to use as encryption key for the data */
r = sha256_hash_host_and_tpm2_key(&host_key, &tpm2_key, md);
@ -1208,15 +1201,12 @@ int decrypt_credential_and_warn(
assert(iovec_is_valid(input));
assert(ret);
/* Only one of these two flags may be set at the same time */
assert(!FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL) || !FLAGS_SET(flags, CREDENTIAL_REFUSE_NULL));
/* Relevant error codes:
*
* -EBADMSG Corrupted file
* -EOPNOTSUPP Unsupported file type (could be: requires TPM but we have no TPM)
* -EHOSTDOWN Need PCR signature file, but couldn't find it
* -EHWPOISON Attempt to unlock with NULL key and either CREDENTIAL_ALLOW_REFUSE is on, or CREDENTIAL_ALLOW_NULL is off, but the system has a TPM and SecureBoot is on
* -EHWPOISON Attempt to decode NULL key (and CREDENTIAL_ALLOW_NULL is off), but the system has a TPM and SecureBoot is on
* -EMEDIUMTYPE File has unexpected scope, i.e. user-scoped credential is attempted to be unlocked in system scope, or vice versa
* -EDESTADDRREQ Credential is incorrectly named (i.e. the authenticated name does not match the actual name)
* -ESTALE Credential's validity has passed
@ -1247,30 +1237,24 @@ int decrypt_credential_and_warn(
return log_error_errno(r, "Failed to load PCR signature: %m");
}
if (with_null) {
if (FLAGS_SET(flags, CREDENTIAL_REFUSE_NULL))
return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON),
"Credential uses null key, but that's not allowed, refusing.");
if (with_null && !FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL)) {
/* So this is a credential encrypted with a zero length key. We support this to cover for the
* case where neither a host key not a TPM2 are available (specifically: initrd environments
* where the host key is not yet accessible and no TPM2 chip exists at all), to minimize
* different codeflow for TPM2 and non-TPM2 codepaths. Of course, credentials encoded this
* way offer no confidentiality nor authenticity. Because of that it's important we refuse to
* use them on systems that actually *do* have a TPM2 chip if we are in SecureBoot
* mode. Otherwise an attacker could hand us credentials like this and we'd use them thinking
* they are trusted, even though they are not. */
if (!FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL)) {
/* So this is a credential encrypted with a zero length key. We support this to cover for the
* case where neither a host key not a TPM2 are available (specifically: initrd environments
* where the host key is not yet accessible and no TPM2 chip exists at all), to minimize
* different codeflow for TPM2 and non-TPM2 codepaths. Of course, credentials encoded this
* way offer no confidentiality nor authenticity. Because of that it's important we refuse to
* use them on systems that actually *do* have a TPM2 chip if we are in SecureBoot
* mode. Otherwise an attacker could hand us credentials like this and we'd use them thinking
* they are trusted, even though they are not. */
if (efi_has_tpm2()) {
if (is_efi_secure_boot())
return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON),
"Credential uses fixed key for fallback use when TPM2 is absent — but TPM2 is present, and SecureBoot is enabled, refusing.");
if (efi_has_tpm2()) {
if (is_efi_secure_boot())
return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON),
"Credential uses null key intended for fallback use when TPM2 is absent — but TPM2 is present, and SecureBoot is enabled, refusing.");
log_warning("Credential uses null key intended for use when TPM2 is absent, but TPM2 is present! Accepting anyway, since SecureBoot is disabled.");
} else
log_debug("Credential uses null key intended for use when TPM2 is absent, and TPM2 indeed is absent. Accepting.");
}
log_warning("Credential uses fixed key for use when TPM2 is absent, but TPM2 is present! Accepting anyway, since SecureBoot is disabled.");
} else
log_debug("Credential uses fixed key for use when TPM2 is absent, and TPM2 indeed is absent. Accepting.");
}
if (with_scope) {
@ -1606,7 +1590,6 @@ int ipc_encrypt_credential(const char *name, usec_t timestamp, usec_t not_after,
SD_JSON_BUILD_PAIR_CONDITION(not_after != USEC_INFINITY, "notAfter", SD_JSON_BUILD_UNSIGNED(not_after)),
SD_JSON_BUILD_PAIR_CONDITION(!FLAGS_SET(flags, CREDENTIAL_ANY_SCOPE), "scope", SD_JSON_BUILD_STRING(uid_is_valid(uid) ? "user" : "system")),
SD_JSON_BUILD_PAIR_CONDITION(uid_is_valid(uid), "uid", SD_JSON_BUILD_UNSIGNED(uid)),
SD_JSON_BUILD_PAIR_CONDITION((flags & (CREDENTIAL_ALLOW_NULL|CREDENTIAL_REFUSE_NULL)) != 0, "allowNull", SD_JSON_BUILD_BOOLEAN(flags & CREDENTIAL_ALLOW_NULL)),
SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", FLAGS_SET(flags, CREDENTIAL_IPC_ALLOW_INTERACTIVE)));
if (r < 0)
return log_error_errno(r, "Failed to call Encrypt() varlink call.");

View File

@ -54,12 +54,11 @@ int get_credential_host_secret(CredentialSecretFlags flags, struct iovec *ret);
int get_credential_user_password(const char *username, char **ret_password, bool *ret_is_hashed);
typedef enum CredentialFlags {
CREDENTIAL_ALLOW_NULL = 1 << 0, /* allow decryption with NULL key, even if TPM is around */
CREDENTIAL_REFUSE_NULL = 1 << 1, /* deny decryption with NULL key, even if SecureBoot is off */
CREDENTIAL_ANY_SCOPE = 1 << 2, /* allow decryption of both system and user credentials */
CREDENTIAL_ALLOW_NULL = 1 << 0, /* allow decryption of NULL key, even if TPM is around */
CREDENTIAL_ANY_SCOPE = 1 << 1, /* allow decryption of both system and user credentials */
/* Only used by ipc_{encrypt,decrypt}_credential */
CREDENTIAL_IPC_ALLOW_INTERACTIVE = 1 << 3,
CREDENTIAL_IPC_ALLOW_INTERACTIVE = 1 << 2,
} CredentialFlags;
/* The four modes we support: keyed only by on-disk key, only by TPM2 HMAC key, and by the combination of

View File

@ -2777,8 +2777,7 @@ bool userdb_match_is_set(const UserDBMatch *match) {
return !strv_isempty(match->fuzzy_names) ||
!FLAGS_SET(match->disposition_mask, USER_DISPOSITION_MASK_ALL) ||
match->uid_min > 0 ||
match->uid_max < UID_INVALID-1 ||
!sd_id128_is_null(match->uuid);
match->uid_max < UID_INVALID-1;
}
void userdb_match_done(UserDBMatch *match) {
@ -2837,9 +2836,6 @@ bool user_record_match(UserRecord *u, const UserDBMatch *match) {
if (!BIT_SET(match->disposition_mask, user_record_disposition(u)))
return false;
if (!sd_id128_is_null(match->uuid) && !sd_id128_equal(match->uuid, u->uuid))
return false;
if (!strv_isempty(match->fuzzy_names)) {
/* Note this array of names is sparse, i.e. various entries listed in it will be

View File

@ -513,7 +513,6 @@ typedef struct UserDBMatch {
uid_t uid_max;
gid_t gid_max;
};
sd_id128_t uuid;
} UserDBMatch;
#define USER_DISPOSITION_MASK_ALL ((UINT64_C(1) << _USER_DISPOSITION_MAX) - UINT64_C(1))
@ -523,7 +522,6 @@ typedef struct UserDBMatch {
.disposition_mask = USER_DISPOSITION_MASK_ALL, \
.uid_min = 0, \
.uid_max = UID_INVALID-1, \
.uuid = SD_ID128_NULL, \
}
/* Maybe useful when we want to resolve root and system user/group but want to refuse nobody user/group. */

View File

@ -799,29 +799,27 @@ nomatch:
return 0;
}
static int query_append_common(sd_json_variant **query, const UserDBMatch *match) {
static int query_append_disposition_mask(sd_json_variant **query, uint64_t mask) {
int r;
_cleanup_strv_free_ char **dispositions = NULL;
assert(query);
uint64_t mask = match->disposition_mask;
if (FLAGS_SET(mask, USER_DISPOSITION_MASK_ALL)) {
for (UserDisposition d = 0; d < _USER_DISPOSITION_MAX; d++) {
if (!BIT_SET(mask, d))
continue;
if (FLAGS_SET(mask, USER_DISPOSITION_MASK_ALL))
return 0;
r = strv_extend(&dispositions, user_disposition_to_string(d));
if (r < 0)
return r;
}
_cleanup_strv_free_ char **dispositions = NULL;
for (UserDisposition d = 0; d < _USER_DISPOSITION_MAX; d++) {
if (!BITS_SET(mask, d))
continue;
r = strv_extend(&dispositions, user_disposition_to_string(d));
if (r < 0)
return r;
}
return sd_json_variant_merge_objectbo(
query,
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(match->fuzzy_names), "fuzzyNames", SD_JSON_BUILD_STRV(match->fuzzy_names)),
SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(match->uuid), "uuid", SD_JSON_BUILD_UUID(match->uuid)),
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(dispositions), "dispositionMask", SD_JSON_BUILD_STRV(dispositions)));
SD_JSON_BUILD_PAIR_STRV("dispositionMask", dispositions));
}
static int query_append_uid_match(sd_json_variant **query, const UserDBMatch *match) {
@ -834,12 +832,13 @@ static int query_append_uid_match(sd_json_variant **query, const UserDBMatch *ma
r = sd_json_variant_merge_objectbo(
query,
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(match->fuzzy_names), "fuzzyNames", SD_JSON_BUILD_STRV(match->fuzzy_names)),
SD_JSON_BUILD_PAIR_CONDITION(match->uid_min > 0, "uidMin", SD_JSON_BUILD_UNSIGNED(match->uid_min)),
SD_JSON_BUILD_PAIR_CONDITION(match->uid_max < UID_INVALID-1, "uidMax", SD_JSON_BUILD_UNSIGNED(match->uid_max)));
if (r < 0)
return r;
return query_append_common(query, match);
return query_append_disposition_mask(query, match->disposition_mask);
}
static int userdb_by_name_fallbacks(
@ -1299,13 +1298,13 @@ static int query_append_gid_match(sd_json_variant **query, const UserDBMatch *ma
r = sd_json_variant_merge_objectbo(
query,
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(match->fuzzy_names), "fuzzyNames", SD_JSON_BUILD_STRV(match->fuzzy_names)),
SD_JSON_BUILD_PAIR_CONDITION(match->gid_min > 0, "gidMin", SD_JSON_BUILD_UNSIGNED(match->gid_min)),
SD_JSON_BUILD_PAIR_CONDITION(match->gid_max < GID_INVALID-1, "gidMax", SD_JSON_BUILD_UNSIGNED(match->gid_max)));
if (r < 0)
return r;
return query_append_common(query, match);
return query_append_disposition_mask(query, match->disposition_mask);
}
static int groupdb_by_name_fallbacks(

View File

@ -3,32 +3,6 @@
#include "bus-polkit.h"
#include "varlink-io.systemd.Credentials.h"
static SD_VARLINK_DEFINE_ENUM_TYPE(
Scope,
SD_VARLINK_FIELD_COMMENT("Generate a system-bound credential"),
SD_VARLINK_DEFINE_ENUM_VALUE(system),
SD_VARLINK_FIELD_COMMENT("Generate a system and user bound credential"),
SD_VARLINK_DEFINE_ENUM_VALUE(user));
static SD_VARLINK_DEFINE_ENUM_TYPE(
WithKey,
SD_VARLINK_FIELD_COMMENT("Automatically pick the key to bind the credential to"),
SD_VARLINK_DEFINE_ENUM_VALUE(auto),
SD_VARLINK_FIELD_COMMENT("Automatically pick the key to bind the credential to, but ensure it is accessible in the initrd, thus potentially leaving it unencrypted."),
SD_VARLINK_DEFINE_ENUM_VALUE(auto_initrd),
SD_VARLINK_FIELD_COMMENT("Bind to the host key only, i.e. not the TPM"),
SD_VARLINK_DEFINE_ENUM_VALUE(host),
SD_VARLINK_FIELD_COMMENT("Bind to the TPM only, not the host key"),
SD_VARLINK_DEFINE_ENUM_VALUE(tpm2),
SD_VARLINK_FIELD_COMMENT("Bind to the TPM only (using a public key identifying the UKI), not the host key"),
SD_VARLINK_DEFINE_ENUM_VALUE(tpm2_with_public_key),
SD_VARLINK_FIELD_COMMENT("Bind to both the TPM and the host key"),
SD_VARLINK_DEFINE_ENUM_VALUE(host_tpm2),
SD_VARLINK_FIELD_COMMENT("Bind to both the TPM (using a public key identifying the UKI) and the host key"),
SD_VARLINK_DEFINE_ENUM_VALUE(host_tpm2_with_public_key),
SD_VARLINK_FIELD_COMMENT("Do not bind to either host key nor the TPM, thus using null encryption (this provides no authenticity nor confidentiality guarantees)"),
SD_VARLINK_DEFINE_ENUM_VALUE(null));
static SD_VARLINK_DEFINE_METHOD(
Encrypt,
SD_VARLINK_FIELD_COMMENT("The name for the encrypted credential, a string suitable for inclusion in a file name. If not specified no name is encoded in the credential. Typically, if this credential is stored on disk, this is how the file should be called, and permits authentication of the filename."),
@ -42,9 +16,7 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_FIELD_COMMENT("Timestamp when to the credential should be considered invalid. In µs since the UNIX epoch. If not specified, the credential remains valid forever."),
SD_VARLINK_DEFINE_INPUT(notAfter, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The intended scope for the credential. One of 'system' or 'user'. If not specified defaults to 'system', unless an uid is specified (see below), in which case it default to 'user'."),
SD_VARLINK_DEFINE_INPUT_BY_TYPE(scope, Scope, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Selects the type of key to encrypt this with"),
SD_VARLINK_DEFINE_INPUT_BY_TYPE(withKey, WithKey, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(scope, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The numeric UNIX UID of the user the credential shall be scoped to. Only relevant if 'user' scope is selected (see above). If not specified and 'user' scope is selected defaults to the UID of the calling user, if that can be determined."),
SD_VARLINK_DEFINE_INPUT(uid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
VARLINK_DEFINE_POLKIT_INPUT,
@ -60,11 +32,9 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_FIELD_COMMENT("The timestamp to use when validating the credential's time validity range. If not specified the current time is used."),
SD_VARLINK_DEFINE_INPUT(timestamp, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The scope for this credential. If not specified no restrictions on the credential scope are made."),
SD_VARLINK_DEFINE_INPUT_BY_TYPE(scope, Scope, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(scope, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("If the 'user' scope is selected, specifies the numeric UNIX UID of the user the credential is associated with. If not specified this is automatically derived from the UID of the calling user, if that can be determined."),
SD_VARLINK_DEFINE_INPUT(uid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("If true allows decryption of credentials encrypted with the null key, if false does not allow it, if unset/null the default depends on whether a TPM device exists and SecureBoot is enabled."),
SD_VARLINK_DEFINE_INPUT(allowNull, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
VARLINK_DEFINE_POLKIT_INPUT,
SD_VARLINK_FIELD_COMMENT("The decrypted plaintext data in Base64 encoding."),
SD_VARLINK_DEFINE_OUTPUT(data, SD_VARLINK_STRING, 0));
@ -84,10 +54,6 @@ SD_VARLINK_DEFINE_INTERFACE(
io_systemd_Credentials,
"io.systemd.Credentials",
SD_VARLINK_INTERFACE_COMMENT("APIs for encrypting and decrypting service credentials."),
SD_VARLINK_SYMBOL_COMMENT("The intended scope for the credential."),
&vl_type_Scope,
SD_VARLINK_SYMBOL_COMMENT("Selects the key(s) to encrypt the credentials with."),
&vl_type_WithKey,
SD_VARLINK_SYMBOL_COMMENT("Encrypts some plaintext data, returns an encrypted credential."),
&vl_method_Encrypt,
SD_VARLINK_SYMBOL_COMMENT("Decrypts an encrypted credential, returns plaintext data."),

View File

@ -16,21 +16,19 @@
#include "varlink-io.systemd.BootControl.h"
#include "varlink-io.systemd.Credentials.h"
#include "varlink-io.systemd.FactoryReset.h"
#include "varlink-io.systemd.Hostname.h"
#include "varlink-io.systemd.Import.h"
#include "varlink-io.systemd.Journal.h"
#include "varlink-io.systemd.Login.h"
#include "varlink-io.systemd.Machine.h"
#include "varlink-io.systemd.MachineImage.h"
#include "varlink-io.systemd.ManagedOOM.h"
#include "varlink-io.systemd.Manager.h"
#include "varlink-io.systemd.ManagedOOM.h"
#include "varlink-io.systemd.MountFileSystem.h"
#include "varlink-io.systemd.MuteConsole.h"
#include "varlink-io.systemd.NamespaceResource.h"
#include "varlink-io.systemd.Network.h"
#include "varlink-io.systemd.PCRExtend.h"
#include "varlink-io.systemd.PCRLock.h"
#include "varlink-io.systemd.Repart.h"
#include "varlink-io.systemd.Resolve.h"
#include "varlink-io.systemd.Resolve.Monitor.h"
#include "varlink-io.systemd.Udev.h"
@ -165,46 +163,61 @@ static void test_parse_format_one(const sd_varlink_interface *iface) {
}
TEST(parse_format) {
const sd_varlink_interface* const list[] = {
&vl_interface_io_systemd,
&vl_interface_io_systemd_AskPassword,
&vl_interface_io_systemd_BootControl,
&vl_interface_io_systemd_Credentials,
&vl_interface_io_systemd_FactoryReset,
&vl_interface_io_systemd_Hostname,
&vl_interface_io_systemd_Import,
&vl_interface_io_systemd_Journal,
&vl_interface_io_systemd_Login,
&vl_interface_io_systemd_Machine,
&vl_interface_io_systemd_MachineImage,
&vl_interface_io_systemd_ManagedOOM,
&vl_interface_io_systemd_Manager,
&vl_interface_io_systemd_MountFileSystem,
&vl_interface_io_systemd_MuteConsole,
&vl_interface_io_systemd_NamespaceResource,
&vl_interface_io_systemd_Network,
&vl_interface_io_systemd_PCRExtend,
&vl_interface_io_systemd_PCRLock,
&vl_interface_io_systemd_Repart,
&vl_interface_io_systemd_Resolve,
&vl_interface_io_systemd_Resolve_Monitor,
&vl_interface_io_systemd_Udev,
&vl_interface_io_systemd_Unit,
&vl_interface_io_systemd_UserDatabase,
&vl_interface_io_systemd_oom,
&vl_interface_io_systemd_service,
&vl_interface_io_systemd_sysext,
&vl_interface_org_varlink_service,
&vl_interface_xyz_test,
};
bool sep = false;
FOREACH_ELEMENT(i, list) {
if (sep)
print_separator();
test_parse_format_one(*i);
sep = true;
}
test_parse_format_one(&vl_interface_org_varlink_service);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_UserDatabase);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_MuteConsole);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_NamespaceResource);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Journal);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Resolve);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Resolve_Monitor);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_ManagedOOM);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_MountFileSystem);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Network);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_oom);
print_separator();
test_parse_format_one(&vl_interface_io_systemd);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_PCRExtend);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_PCRLock);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_service);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_sysext);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Credentials);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_BootControl);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Import);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Machine);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_MachineImage);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Manager);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_AskPassword);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Udev);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Login);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_FactoryReset);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Unit);
print_separator();
test_parse_format_one(&vl_interface_xyz_test);
}
TEST(parse) {

View File

@ -57,7 +57,6 @@ static bool arg_chain = false;
static uint64_t arg_disposition_mask = UINT64_MAX;
static uid_t arg_uid_min = 0;
static uid_t arg_uid_max = UID_INVALID-1;
static sd_id128_t arg_uuid = SD_ID128_NULL;
static bool arg_fuzzy = false;
static bool arg_boundaries = true;
static sd_json_variant *arg_from_file = NULL;
@ -412,7 +411,7 @@ static int display_user(int argc, char *argv[], void *userdata) {
int ret = 0, r;
if (arg_output < 0)
arg_output = arg_from_file || (argc > 1 && !arg_fuzzy) || !sd_id128_is_null(arg_uuid) ? OUTPUT_FRIENDLY : OUTPUT_TABLE;
arg_output = arg_from_file || (argc > 1 && !arg_fuzzy) ? OUTPUT_FRIENDLY : OUTPUT_TABLE;
if (arg_output == OUTPUT_TABLE) {
table = table_new(" ", "name", "disposition", "uid", "gid", "realname", "home", "shell", "order");
@ -432,7 +431,6 @@ static int display_user(int argc, char *argv[], void *userdata) {
.disposition_mask = arg_disposition_mask,
.uid_min = arg_uid_min,
.uid_max = arg_uid_max,
.uuid = arg_uuid,
};
if (arg_from_file) {
@ -755,7 +753,7 @@ static int display_group(int argc, char *argv[], void *userdata) {
int ret = 0, r;
if (arg_output < 0)
arg_output = arg_from_file || (argc > 1 && !arg_fuzzy) || !sd_id128_is_null(arg_uuid) ? OUTPUT_FRIENDLY : OUTPUT_TABLE;
arg_output = arg_from_file || (argc > 1 && !arg_fuzzy) ? OUTPUT_FRIENDLY : OUTPUT_TABLE;
if (arg_output == OUTPUT_TABLE) {
table = table_new(" ", "name", "disposition", "gid", "description", "order");
@ -774,7 +772,6 @@ static int display_group(int argc, char *argv[], void *userdata) {
.disposition_mask = arg_disposition_mask,
.gid_min = arg_uid_min,
.gid_max = arg_uid_max,
.uuid = arg_uuid,
};
if (arg_from_file) {
@ -1591,7 +1588,6 @@ static int parse_argv(int argc, char *argv[]) {
ARG_CHAIN,
ARG_UID_MIN,
ARG_UID_MAX,
ARG_UUID,
ARG_DISPOSITION,
ARG_BOUNDARIES,
};
@ -1612,7 +1608,6 @@ static int parse_argv(int argc, char *argv[]) {
{ "chain", no_argument, NULL, ARG_CHAIN },
{ "uid-min", required_argument, NULL, ARG_UID_MIN },
{ "uid-max", required_argument, NULL, ARG_UID_MAX },
{ "uuid", required_argument, NULL, ARG_UUID },
{ "fuzzy", no_argument, NULL, 'z' },
{ "disposition", required_argument, NULL, ARG_DISPOSITION },
{ "boundaries", required_argument, NULL, ARG_BOUNDARIES },
@ -1796,12 +1791,6 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(r, "Failed to parse --uid-max= value: %s", optarg);
break;
case ARG_UUID:
r = sd_id128_from_string(optarg, &arg_uuid);
if (r < 0)
return log_error_errno(r, "Failed to parse --uuid= value: %s", optarg);
break;
case 'z':
arg_fuzzy = true;
break;

View File

@ -149,7 +149,6 @@ static int vl_method_get_user_record(sd_varlink *link, sd_json_variant *paramete
{ "dispositionMask", SD_JSON_VARIANT_ARRAY, json_dispatch_dispositions_mask, offsetof(LookupParameters, match.disposition_mask), 0 },
{ "uidMin", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, offsetof(LookupParameters, match.uid_min), 0 },
{ "uidMax", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, offsetof(LookupParameters, match.uid_max), 0 },
{ "uuid", SD_JSON_VARIANT_STRING, sd_json_dispatch_id128, offsetof(LookupParameters, match.uuid), 0 },
{}
};
@ -294,7 +293,6 @@ static int vl_method_get_group_record(sd_varlink *link, sd_json_variant *paramet
{ "dispositionMask", SD_JSON_VARIANT_ARRAY, json_dispatch_dispositions_mask, offsetof(LookupParameters, match.disposition_mask), 0 },
{ "gidMin", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, offsetof(LookupParameters, match.gid_min), 0 },
{ "gidMax", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, offsetof(LookupParameters, match.gid_max), 0 },
{ "uuid", SD_JSON_VARIANT_STRING, sd_json_dispatch_id128, offsetof(LookupParameters, match.uuid), 0 },
{}
};

View File

@ -482,34 +482,14 @@ fi
# Decrypt/encrypt via varlink
DATA="Zm9vYmFyCg=="
echo "{\"data\":\"$DATA\"}" > /tmp/vlcredsdata
echo '{"data":"Zm9vYmFyCg=="}' > /tmp/vlcredsdata
varlinkctl call /run/systemd/io.systemd.Credentials io.systemd.Credentials.Encrypt "$(cat /tmp/vlcredsdata)" | \
varlinkctl call --json=short /run/systemd/io.systemd.Credentials io.systemd.Credentials.Decrypt > /tmp/vlcredsdata2
cmp /tmp/vlcredsdata /tmp/vlcredsdata2
rm /tmp/vlcredsdata2
# Pick a key type explicitly
varlinkctl call /run/systemd/io.systemd.Credentials io.systemd.Credentials.Encrypt "{\"data\":\"$DATA\",\"withKey\":\"host\"}" | \
varlinkctl call --json=short /run/systemd/io.systemd.Credentials io.systemd.Credentials.Decrypt > /tmp/vlcredsdata2
cmp /tmp/vlcredsdata /tmp/vlcredsdata2
rm /tmp/vlcredsdata2
varlinkctl call /run/systemd/io.systemd.Credentials io.systemd.Credentials.Encrypt "{\"data\":\"$DATA\",\"withKey\":\"null\"}" | \
jq '.["allowNull"] = true' |
varlinkctl call --json=short /run/systemd/io.systemd.Credentials io.systemd.Credentials.Decrypt > /tmp/vlcredsdata2
cmp /tmp/vlcredsdata /tmp/vlcredsdata2
rm /tmp/vlcredsdata /tmp/vlcredsdata2
# Ensure allowNull works
(! varlinkctl call /run/systemd/io.systemd.Credentials io.systemd.Credentials.Encrypt "{\"data\":\"$DATA\",\"withKey\":\"null\"}" | \
jq '.["allowNull"] = false' |
varlinkctl call --json=short /run/systemd/io.systemd.Credentials io.systemd.Credentials.Decrypt )
clean_usertest() {
rm -f /tmp/usertest.data /tmp/usertest.data /tmp/brummbaer.data
}