1
0
mirror of https://github.com/systemd/systemd synced 2026-03-17 10:34:46 +01:00

Compare commits

..

13 Commits

Author SHA1 Message Date
Lennart Poettering
8e1422036a
Merge pull request #19768 from poettering/homectl-fido2-lock-with
homed: catch up with FIDO2 features in cryptsetup + other fixes
2021-06-01 15:53:36 +02:00
Ondrej Kozina
358b1f68b0 cryptsetup-util: disable pbkdf benchmark in cryptsetup_set_minimal_pbkdf.
No need to benchmark pbkdf when asking for minimal values
anyway.

1000 iterations count is minimum for both LUKS1 and LUKS2
pbkdf2 keyslot parameters according to NIST SP 800-132, ch. 5.2.

Iterations count can not be lower than recommended minimum
when benchmark is disabled. The time_ms member is ignored with
benchmark disabled.
2021-06-01 15:53:14 +02:00
Lennart Poettering
c719805ecb dissect: the libcryptsetup code for Verity crypt_device objects too
Across the codebase we are pretty good at setting the per-crypt_device
log functions once we allocated the object. But we forgot one case. Fix
that.
2021-06-01 13:33:13 +02:00
Lennart Poettering
2f67864064 cryptsetup: explicitl set default log functions wherever needed
Code using libcryptsetup already sets the global log function if it uses
dlopen_cryptsetup(). Make sure we do the same for the three programs
that explicitly link against libcryptsetup and hence to not use
dlopen_cryptsetup().
2021-06-01 13:33:09 +02:00
Lennart Poettering
e9252faee9 cryptsetup: implicitly set global log functions when loading libcryptsetup dynamically
So far we only set the per-crypt_device log functions, but some
libcryptsetup calls we invoke without a crypt_device objects, and we
want those to redirect to our infra too.
2021-06-01 13:33:05 +02:00
Lennart Poettering
0608e2d3a5 homework: only default to LUKS storage if libcryptsetup is installed 2021-06-01 13:33:01 +02:00
Lennart Poettering
71eceff645 homework: make libcryptsetup dep runtime optional 2021-06-01 13:32:40 +02:00
Lennart Poettering
e49614278d homework: fix return codes when using fido2/pkcs11 cached passwords
Otherwise we'll accidently report a record we can safely decrypt as not
decrypted.
2021-06-01 13:32:36 +02:00
Lennart Poettering
bfc0cc1a25 userdb: make most loading of JSON user record data "permissive"
We want user records to be extensible, hence we shouldn't complain about
fields we can't parse. In particular we want them to be extensible for
our own future extensions.

Some code already turned the permissive flag when parsing the JSON data,
but most did not. Fix that. A few select cases remain where the bit is
not set: where we just gnerated the JSON data ourselves, and thus can be
reasonably sure that if we can't parse it it's our immediate programming
error and not just us processing a user record from some other tool or a
newer version of ourselves.
2021-06-01 13:32:31 +02:00
Lennart Poettering
17e7561a97 homectl: store FIDO2 up/uv/clientPin fields in user records too
This catches up homed's FIDO2 support with cryptsetup's: we'll now store
the uv/up/clientPin configuration at enrollment in the user record JSON
data, and use it when authenticating with it.

This also adds explicit "uv" support: we'll only allow it to happen when
the client explicity said it's OK. This is then used by clients to print
a nice message suggesting "uv" has to take place before retrying
allowing it this time. This is modelled after the existing handling for
"up".
2021-06-01 13:31:53 +02:00
Lennart Poettering
7dba77a67e
Merge pull request #17096 from eworm-de/ask-password
ask-password: allow to control emoji
2021-06-01 11:44:00 +02:00
Christian Hesse
9cb5bf913d ask-password: use FLAGS_SET()
Check for flags with FLAGS_SET() where possible.
2021-05-31 21:13:31 +02:00
Christian Hesse
e390c34d00 ask-password: allow to control lock and key emoji
Giving --echo to systemd-ask-password allows to echo the user input.
There's nothing secret, so do not show a lock and key emoji by default.

The behavior can be controlled with --emoji=yes|no|auto. The default is
auto, which defaults to yes, unless --echo is given.
2021-05-31 21:13:31 +02:00
41 changed files with 544 additions and 190 deletions

View File

@ -628,18 +628,21 @@ user records.
`fido2HmacSalt` → An array of objects, implementing authentication support with `fido2HmacSalt` → An array of objects, implementing authentication support with
FIDO2 devices that implement the `hmac-secret` extension. Each element of the FIDO2 devices that implement the `hmac-secret` extension. Each element of the
array should be an object consisting of three string fields: `credential`, array should be an object consisting of three string fields: `credential`,
`salt`, `hashedPassword`. The first two shall contain Base64-encoded binary `salt`, `hashedPassword`, and three boolean fields: `up`, `uv` and
`clientPin`. The first two string fields shall contain Base64-encoded binary
data: the FIDO2 credential ID and the salt value to pass to the FIDO2 data: the FIDO2 credential ID and the salt value to pass to the FIDO2
device. During authentication this salt along with the credential ID is sent to device. During authentication this salt along with the credential ID is sent to
the FIDO2 token, which will HMAC hash the salt with its internal secret key and the FIDO2 token, which will HMAC hash the salt with its internal secret key and
return the result. This resulting binary key should then be Base64-encoded and return the result. This resulting binary key should then be Base64-encoded and
used as string password for the further layers of the stack. The used as string password for the further layers of the stack. The
`hashedPassword` field of the `fido2HmacSalt` field shall be a UNIX password `hashedPassword` field of the `fido2HmacSalt` field shall be a UNIX password
hash to test this derived secret key against for authentication. It is hash to test this derived secret key against for authentication. The `up`, `uv`
generally recommended that for each entry in `fido2HmacSalt` there's also a and `clientPin` booleans map to the FIDO2 concepts of the same name and encode
matching one in `fido2HmacCredential`, and vice versa, with the same credential whether the `uv`/`up` options are enabled during the authentication, and
ID, appearing in the same order, but this should not be required by whether a PIN shall be required. It is generally recommended that for each
applications processing user records. entry in `fido2HmacSalt` there's also a matching one in `fido2HmacCredential`,
and vice versa, with the same credential ID, appearing in the same order, but
this should not be required by applications processing user records.
`recoveryKey`→ An array of objects, each defining a recovery key. The object `recoveryKey`→ An array of objects, each defining a recovery key. The object
has two mandatory fields: `type` indicates the type of recovery key. The only has two mandatory fields: `type` indicates the type of recovery key. The only
@ -927,8 +930,15 @@ user. If false or unset, authentication this way shall not be attempted.
`fido2UserPresencePermitted` → a boolean. If set to true allows the receiver to `fido2UserPresencePermitted` → a boolean. If set to true allows the receiver to
use the FIDO2 "user presence" flag. This is similar to the concept of use the FIDO2 "user presence" flag. This is similar to the concept of
`pkcs11ProtectedAuthenticationPathPermitted`, but exposes the FIDO2 concept `pkcs11ProtectedAuthenticationPathPermitted`, but exposes the FIDO2 "up"
behind it. If false or unset authentication this way shall not be attempted. concept behind it. If false or unset authentication this way shall not be
attempted.
`fido2UserVerificationPermitted` → a boolean. If set to true allows the
receiver to use the FIDO2 "user verification" flag. This is similar to the
concept of `pkcs11ProtectedAuthenticationPathPermitted`, but exposes the FIDO2
"uv" concept behind it. If false or unset authentication this way shall not be
attempted.
## Mapping to `struct passwd` and `struct spwd` ## Mapping to `struct passwd` and `struct spwd`

View File

@ -378,6 +378,35 @@
discussion see above.</para></listitem> discussion see above.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--fido2-with-client-pin=</option><replaceable>BOOL</replaceable></term>
<listitem><para>When enrolling a FIDO2 security token, controls whether to require the user to enter
a PIN when unlocking the account (the FIDO2 <literal>clientPin</literal> feature). Defaults to
<literal>yes</literal>. (Note: this setting is without effect if the security token does not support
the <literal>clientPin</literal> feature at all, or does not allow enabling or disabling
it.)</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--fido2-with-user-presence=</option><replaceable>BOOL</replaceable></term>
<listitem><para>When enrolling a FIDO2 security token, controls whether to require the user to
verify presence (tap the token, the FIDO2 <literal>up</literal> feature) when unlocking the account.
Defaults to <literal>yes</literal>. (Note: this setting is without effect if the security token does not support
the <literal>up</literal> feature at all, or does not allow enabling or disabling it.)
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--fido2-with-user-verification=</option><replaceable>BOOL</replaceable></term>
<listitem><para>When enrolling a FIDO2 security token, controls whether to require user verification
when unlocking the account (the FIDO2 <literal>uv</literal> feature). Defaults to
<literal>no</literal>. (Note: this setting is without effect if the security token does not support
the <literal>uv</literal> feature at all, or does not allow enabling or disabling it.)</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>--recovery-key=</option><replaceable>BOOL</replaceable></term> <term><option>--recovery-key=</option><replaceable>BOOL</replaceable></term>

View File

@ -165,6 +165,15 @@
usernames. </para></listitem> usernames. </para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--emoji=yes|no|auto</option></term>
<listitem><para>Controls whether or not to prefix the query with a
lock and key emoji (🔐), if the TTY settings permit this. The default
is <literal>auto</literal>, which defaults to <literal>yes</literal>,
unless <option>--echo</option> is given.</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>--no-tty</option></term> <term><option>--no-tty</option></term>

View File

@ -2254,7 +2254,6 @@ if conf.get('ENABLE_HOMED') == 1
include_directories : includes, include_directories : includes,
link_with : [libshared], link_with : [libshared],
dependencies : [threads, dependencies : [threads,
libcryptsetup,
libblkid, libblkid,
libcrypt, libcrypt,
libopenssl, libopenssl,

View File

@ -10,6 +10,7 @@
#include "log.h" #include "log.h"
#include "macro.h" #include "macro.h"
#include "main-func.h" #include "main-func.h"
#include "parse-argument.h"
#include "pretty-print.h" #include "pretty-print.h"
#include "strv.h" #include "strv.h"
#include "terminal-util.h" #include "terminal-util.h"
@ -45,6 +46,8 @@ static int help(void) {
" credentials\n" " credentials\n"
" --timeout=SEC Timeout in seconds\n" " --timeout=SEC Timeout in seconds\n"
" --echo Do not mask input (useful for usernames)\n" " --echo Do not mask input (useful for usernames)\n"
" --emoji=yes|no|auto\n"
" Show a lock and key emoji\n"
" --no-tty Ask question via agent even on TTY\n" " --no-tty Ask question via agent even on TTY\n"
" --accept-cached Accept cached passwords\n" " --accept-cached Accept cached passwords\n"
" --multiple List multiple passwords if available\n" " --multiple List multiple passwords if available\n"
@ -64,6 +67,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_ICON = 0x100, ARG_ICON = 0x100,
ARG_TIMEOUT, ARG_TIMEOUT,
ARG_ECHO, ARG_ECHO,
ARG_EMOJI,
ARG_NO_TTY, ARG_NO_TTY,
ARG_ACCEPT_CACHED, ARG_ACCEPT_CACHED,
ARG_MULTIPLE, ARG_MULTIPLE,
@ -80,6 +84,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "icon", required_argument, NULL, ARG_ICON }, { "icon", required_argument, NULL, ARG_ICON },
{ "timeout", required_argument, NULL, ARG_TIMEOUT }, { "timeout", required_argument, NULL, ARG_TIMEOUT },
{ "echo", no_argument, NULL, ARG_ECHO }, { "echo", no_argument, NULL, ARG_ECHO },
{ "emoji", required_argument, NULL, ARG_EMOJI },
{ "no-tty", no_argument, NULL, ARG_NO_TTY }, { "no-tty", no_argument, NULL, ARG_NO_TTY },
{ "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED }, { "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED },
{ "multiple", no_argument, NULL, ARG_MULTIPLE }, { "multiple", no_argument, NULL, ARG_MULTIPLE },
@ -90,6 +95,7 @@ static int parse_argv(int argc, char *argv[]) {
{} {}
}; };
const char *emoji = NULL;
int c; int c;
assert(argc >= 0); assert(argc >= 0);
@ -120,6 +126,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_flags |= ASK_PASSWORD_ECHO; arg_flags |= ASK_PASSWORD_ECHO;
break; break;
case ARG_EMOJI:
emoji = optarg;
break;
case ARG_NO_TTY: case ARG_NO_TTY:
arg_flags |= ASK_PASSWORD_NO_TTY; arg_flags |= ASK_PASSWORD_NO_TTY;
break; break;
@ -155,6 +165,18 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option"); assert_not_reached("Unhandled option");
} }
if (isempty(emoji) || streq(emoji, "auto"))
SET_FLAG(arg_flags, ASK_PASSWORD_HIDE_EMOJI, FLAGS_SET(arg_flags, ASK_PASSWORD_ECHO));
else {
int r;
bool b;
r = parse_boolean_argument("--emoji=", emoji, &b);
if (r < 0)
return r;
SET_FLAG(arg_flags, ASK_PASSWORD_HIDE_EMOJI, !b);
}
if (argc > optind) { if (argc > optind) {
arg_message = strv_join(argv + optind, " "); arg_message = strv_join(argv + optind, " ");
if (!arg_message) if (!arg_message)

View File

@ -510,6 +510,8 @@ static int run(int argc, char *argv[]) {
if (r <= 0) if (r <= 0)
return r; return r;
cryptsetup_enable_logging(NULL);
if (arg_enroll_type < 0) if (arg_enroll_type < 0)
r = prepare_luks(&cd, NULL, NULL); /* No need to unlock device if we don't need the volume key because we don't need to enroll anything */ r = prepare_luks(&cd, NULL, NULL); /* No need to unlock device if we don't need the volume key because we don't need to enroll anything */
else else

View File

@ -1449,7 +1449,7 @@ static int run(int argc, char *argv[]) {
log_setup(); log_setup();
cryptsetup_enable_logging(cd); cryptsetup_enable_logging(NULL);
umask(0022); umask(0022);

View File

@ -68,7 +68,8 @@ static int add_fido2_salt(
const void *fido2_salt, const void *fido2_salt,
size_t fido2_salt_size, size_t fido2_salt_size,
const void *secret, const void *secret,
size_t secret_size) { size_t secret_size,
Fido2EnrollFlags lock_with) {
_cleanup_(json_variant_unrefp) JsonVariant *l = NULL, *w = NULL, *e = NULL; _cleanup_(json_variant_unrefp) JsonVariant *l = NULL, *w = NULL, *e = NULL;
_cleanup_(erase_and_freep) char *base64_encoded = NULL, *hashed = NULL; _cleanup_(erase_and_freep) char *base64_encoded = NULL, *hashed = NULL;
@ -87,7 +88,11 @@ static int add_fido2_salt(
r = json_build(&e, JSON_BUILD_OBJECT( r = json_build(&e, JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("credential", JSON_BUILD_BASE64(cid, cid_size)), JSON_BUILD_PAIR("credential", JSON_BUILD_BASE64(cid, cid_size)),
JSON_BUILD_PAIR("salt", JSON_BUILD_BASE64(fido2_salt, fido2_salt_size)), JSON_BUILD_PAIR("salt", JSON_BUILD_BASE64(fido2_salt, fido2_salt_size)),
JSON_BUILD_PAIR("hashedPassword", JSON_BUILD_STRING(hashed)))); JSON_BUILD_PAIR("hashedPassword", JSON_BUILD_STRING(hashed)),
JSON_BUILD_PAIR("up", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_UP))),
JSON_BUILD_PAIR("uv", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_UV))),
JSON_BUILD_PAIR("clientPin", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_PIN)))));
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to build FIDO2 salt JSON key object: %m"); return log_error_errno(r, "Failed to build FIDO2 salt JSON key object: %m");
@ -112,7 +117,8 @@ static int add_fido2_salt(
int identity_add_fido2_parameters( int identity_add_fido2_parameters(
JsonVariant **v, JsonVariant **v,
const char *device) { const char *device,
Fido2EnrollFlags lock_with) {
#if HAVE_LIBFIDO2 #if HAVE_LIBFIDO2
JsonVariant *un, *realm, *rn; JsonVariant *un, *realm, *rn;
@ -158,12 +164,12 @@ int identity_add_fido2_parameters(
/* user_display_name= */ rn ? json_variant_string(rn) : NULL, /* user_display_name= */ rn ? json_variant_string(rn) : NULL,
/* user_icon_name= */ NULL, /* user_icon_name= */ NULL,
/* askpw_icon_name= */ "user-home", /* askpw_icon_name= */ "user-home",
FIDO2ENROLL_PIN | FIDO2ENROLL_UP, // FIXME: add a --lock-with-pin/up parameter like cryptenroll lock_with,
&cid, &cid_size, &cid, &cid_size,
&salt, &salt_size, &salt, &salt_size,
&secret, &secret_size, &secret, &secret_size,
&used_pin, &used_pin,
NULL); &lock_with);
if (r < 0) if (r < 0)
return r; return r;
@ -181,7 +187,8 @@ int identity_add_fido2_parameters(
salt, salt,
salt_size, salt_size,
secret, secret,
secret_size); secret_size,
lock_with);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -2,5 +2,6 @@
#pragma once #pragma once
#include "json.h" #include "json.h"
#include "libfido2-util.h"
int identity_add_fido2_parameters(JsonVariant **v, const char *device); int identity_add_fido2_parameters(JsonVariant **v, const char *device, Fido2EnrollFlags lock_with);

View File

@ -57,6 +57,7 @@ static uint64_t arg_disk_size = UINT64_MAX;
static uint64_t arg_disk_size_relative = UINT64_MAX; static uint64_t arg_disk_size_relative = UINT64_MAX;
static char **arg_pkcs11_token_uri = NULL; static char **arg_pkcs11_token_uri = NULL;
static char **arg_fido2_device = NULL; static char **arg_fido2_device = NULL;
static Fido2EnrollFlags arg_fido2_lock_with = FIDO2ENROLL_PIN | FIDO2ENROLL_UP;
static bool arg_recovery_key = false; static bool arg_recovery_key = false;
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
static bool arg_and_resize = false; static bool arg_and_resize = false;
@ -380,7 +381,7 @@ static int handle_generic_user_record_error(
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED)) { } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED)) {
log_notice("%s%sAuthentication requires presence verification on security token.", log_notice("%s%sPlease confirm presence on security token.",
emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "", emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "",
emoji_enabled() ? " " : ""); emoji_enabled() ? " " : "");
@ -388,6 +389,16 @@ static int handle_generic_user_record_error(
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to set FIDO2 user presence permitted flag: %m"); return log_error_errno(r, "Failed to set FIDO2 user presence permitted flag: %m");
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED)) {
log_notice("%s%sPlease verify user on security token.",
emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "",
emoji_enabled() ? " " : "");
r = user_record_set_fido2_user_verification_permitted(hr, true);
if (r < 0)
return log_error_errno(r, "Failed to set FIDO2 user verification permitted flag: %m");
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PIN_LOCKED)) } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PIN_LOCKED))
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Security token PIN is locked, please unlock it first. (Hint: Removal and re-insertion might suffice.)"); return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Security token PIN is locked, please unlock it first. (Hint: Removal and re-insertion might suffice.)");
@ -560,9 +571,9 @@ static void dump_home_record(UserRecord *hr) {
_cleanup_(user_record_unrefp) UserRecord *stripped = NULL; _cleanup_(user_record_unrefp) UserRecord *stripped = NULL;
if (arg_export_format == EXPORT_FORMAT_STRIPPED) if (arg_export_format == EXPORT_FORMAT_STRIPPED)
r = user_record_clone(hr, USER_RECORD_EXTRACT_EMBEDDED, &stripped); r = user_record_clone(hr, USER_RECORD_EXTRACT_EMBEDDED|USER_RECORD_PERMISSIVE, &stripped);
else if (arg_export_format == EXPORT_FORMAT_MINIMAL) else if (arg_export_format == EXPORT_FORMAT_MINIMAL)
r = user_record_clone(hr, USER_RECORD_EXTRACT_SIGNABLE, &stripped); r = user_record_clone(hr, USER_RECORD_EXTRACT_SIGNABLE|USER_RECORD_PERMISSIVE, &stripped);
else else
r = 0; r = 0;
if (r < 0) if (r < 0)
@ -667,7 +678,7 @@ static int inspect_home(int argc, char *argv[], void *userdata) {
if (!hr) if (!hr)
return log_oom(); return log_oom();
r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG); r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0) { if (r < 0) {
if (ret == 0) if (ret == 0)
ret = r; ret = r;
@ -1027,7 +1038,7 @@ static int acquire_new_home_record(UserRecord **ret) {
} }
STRV_FOREACH(i, arg_fido2_device) { STRV_FOREACH(i, arg_fido2_device) {
r = identity_add_fido2_parameters(&v, *i); r = identity_add_fido2_parameters(&v, *i, arg_fido2_lock_with);
if (r < 0) if (r < 0)
return r; return r;
} }
@ -1049,7 +1060,7 @@ static int acquire_new_home_record(UserRecord **ret) {
if (!hr) if (!hr)
return log_oom(); return log_oom();
r = user_record_load(hr, v, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_LOG); r = user_record_load(hr, v, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return r; return r;
@ -1397,7 +1408,7 @@ static int acquire_updated_home_record(
} }
STRV_FOREACH(i, arg_fido2_device) { STRV_FOREACH(i, arg_fido2_device) {
r = identity_add_fido2_parameters(&json, *i); r = identity_add_fido2_parameters(&json, *i, arg_fido2_lock_with);
if (r < 0) if (r < 0)
return r; return r;
} }
@ -1415,7 +1426,7 @@ static int acquire_updated_home_record(
if (!hr) if (!hr)
return log_oom(); return log_oom();
r = user_record_load(hr, json, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_LOG); r = user_record_load(hr, json, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return r; return r;
@ -1440,6 +1451,10 @@ static int home_record_reset_human_interaction_permission(UserRecord *hr) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to reset FIDO2 user presence permission flag: %m"); return log_error_errno(r, "Failed to reset FIDO2 user presence permission flag: %m");
r = user_record_set_fido2_user_verification_permitted(hr, -1);
if (r < 0)
return log_error_errno(r, "Failed to reset FIDO2 user verification permission flag: %m");
return 0; return 0;
} }
@ -2071,6 +2086,15 @@ static int help(int argc, char *argv[], void *userdata) {
" private key and matching X.509 certificate\n" " private key and matching X.509 certificate\n"
" --fido2-device=PATH Path to FIDO2 hidraw device with hmac-secret\n" " --fido2-device=PATH Path to FIDO2 hidraw device with hmac-secret\n"
" extension\n" " extension\n"
" --fido2-with-client-pin=BOOL\n"
" Whether to require entering a PIN to unlock the\n"
" account\n"
" --fido2-with-user-presence=BOOL\n"
" Whether to require user presence to unlock the\n"
" account\n"
" --fido2-with-user-verification=BOOL\n"
" Whether to require user verification to unlock the\n"
" account\n"
" --recovery-key=BOOL Add a recovery key\n" " --recovery-key=BOOL Add a recovery key\n"
"\n%4$sAccount Management User Record Properties:%5$s\n" "\n%4$sAccount Management User Record Properties:%5$s\n"
" --locked=BOOL Set locked account state\n" " --locked=BOOL Set locked account state\n"
@ -2220,6 +2244,9 @@ static int parse_argv(int argc, char *argv[]) {
ARG_AUTO_LOGIN, ARG_AUTO_LOGIN,
ARG_PKCS11_TOKEN_URI, ARG_PKCS11_TOKEN_URI,
ARG_FIDO2_DEVICE, ARG_FIDO2_DEVICE,
ARG_FIDO2_WITH_PIN,
ARG_FIDO2_WITH_UP,
ARG_FIDO2_WITH_UV,
ARG_RECOVERY_KEY, ARG_RECOVERY_KEY,
ARG_AND_RESIZE, ARG_AND_RESIZE,
ARG_AND_CHANGE_PASSWORD, ARG_AND_CHANGE_PASSWORD,
@ -2299,6 +2326,9 @@ static int parse_argv(int argc, char *argv[]) {
{ "export-format", required_argument, NULL, ARG_EXPORT_FORMAT }, { "export-format", required_argument, NULL, ARG_EXPORT_FORMAT },
{ "pkcs11-token-uri", required_argument, NULL, ARG_PKCS11_TOKEN_URI }, { "pkcs11-token-uri", required_argument, NULL, ARG_PKCS11_TOKEN_URI },
{ "fido2-device", required_argument, NULL, ARG_FIDO2_DEVICE }, { "fido2-device", required_argument, NULL, ARG_FIDO2_DEVICE },
{ "fido2-with-client-pin", required_argument, NULL, ARG_FIDO2_WITH_PIN },
{ "fido2-with-user-presence", required_argument, NULL, ARG_FIDO2_WITH_UP },
{ "fido2-with-user-verification",required_argument, NULL, ARG_FIDO2_WITH_UV },
{ "recovery-key", required_argument, NULL, ARG_RECOVERY_KEY }, { "recovery-key", required_argument, NULL, ARG_RECOVERY_KEY },
{ "and-resize", required_argument, NULL, ARG_AND_RESIZE }, { "and-resize", required_argument, NULL, ARG_AND_RESIZE },
{ "and-change-password", required_argument, NULL, ARG_AND_CHANGE_PASSWORD }, { "and-change-password", required_argument, NULL, ARG_AND_CHANGE_PASSWORD },
@ -3323,7 +3353,6 @@ static int parse_argv(int argc, char *argv[]) {
r = strv_consume(&arg_fido2_device, TAKE_PTR(found)); r = strv_consume(&arg_fido2_device, TAKE_PTR(found));
} else } else
r = strv_extend(&arg_fido2_device, optarg); r = strv_extend(&arg_fido2_device, optarg);
if (r < 0) if (r < 0)
return r; return r;
@ -3331,6 +3360,39 @@ static int parse_argv(int argc, char *argv[]) {
break; break;
} }
case ARG_FIDO2_WITH_PIN: {
bool lock_with_pin;
r = parse_boolean_argument("--fido2-with-client-pin=", optarg, &lock_with_pin);
if (r < 0)
return r;
SET_FLAG(arg_fido2_lock_with, FIDO2ENROLL_PIN, lock_with_pin);
break;
}
case ARG_FIDO2_WITH_UP: {
bool lock_with_up;
r = parse_boolean_argument("--fido2-with-user-presence=", optarg, &lock_with_up);
if (r < 0)
return r;
SET_FLAG(arg_fido2_lock_with, FIDO2ENROLL_UP, lock_with_up);
break;
}
case ARG_FIDO2_WITH_UV: {
bool lock_with_uv;
r = parse_boolean_argument("--fido2-with-user-verification=", optarg, &lock_with_uv);
if (r < 0)
return r;
SET_FLAG(arg_fido2_lock_with, FIDO2ENROLL_UV, lock_with_uv);
break;
}
case ARG_RECOVERY_KEY: { case ARG_RECOVERY_KEY: {
const char *p; const char *p;

View File

@ -28,7 +28,7 @@ int bus_message_read_secret(sd_bus_message *m, UserRecord **ret, sd_bus_error *e
if (!hr) if (!hr)
return -ENOMEM; return -ENOMEM;
r = user_record_load(hr, full, USER_RECORD_REQUIRE_SECRET); r = user_record_load(hr, full, USER_RECORD_REQUIRE_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -95,7 +95,7 @@ int bus_home_get_record_json(
trusted = false; trusted = false;
} }
flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE; flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE;
if (trusted) if (trusted)
flags |= USER_RECORD_ALLOW_PRIVILEGED; flags |= USER_RECORD_ALLOW_PRIVILEGED;
else else
@ -443,7 +443,7 @@ int bus_home_method_update(
assert(message); assert(message);
assert(h); assert(h);
r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_REQUIRE_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE, &hr, error); r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_REQUIRE_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE, &hr, error);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -145,7 +145,7 @@ int home_new(Manager *m, UserRecord *hr, const char *sysfs, Home **ret) {
return r; return r;
} }
r = user_record_clone(hr, USER_RECORD_LOAD_MASK_SECRET, &home->record); r = user_record_clone(hr, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &home->record);
if (r < 0) if (r < 0)
return r; return r;
@ -243,7 +243,7 @@ int home_set_record(Home *h, UserRecord *hr) {
if (!new_hr) if (!new_hr)
return -ENOMEM; return -ENOMEM;
r = user_record_load(new_hr, v, USER_RECORD_LOAD_REFUSE_SECRET); r = user_record_load(new_hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return r; return r;
@ -384,7 +384,7 @@ static int home_parse_worker_stdout(int _fd, UserRecord **ret) {
if (!hr) if (!hr)
return log_oom(); return log_oom();
r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET); r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to load home record identity: %m"); return log_error_errno(r, "Failed to load home record identity: %m");
@ -461,7 +461,9 @@ static int convert_worker_errno(Home *h, int e, sd_bus_error *error) {
case -ERFKILL: case -ERFKILL:
return sd_bus_error_set(error, BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED, "Security token requires protected authentication path."); return sd_bus_error_set(error, BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED, "Security token requires protected authentication path.");
case -EMEDIUMTYPE: case -EMEDIUMTYPE:
return sd_bus_error_set(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED, "Security token requires user presence."); return sd_bus_error_set(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED, "Security token requires presence confirmation.");
case -ENOCSI:
return sd_bus_error_set(error, BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED, "Security token requires user verification.");
case -ENOSTR: case -ENOSTR:
return sd_bus_error_set(error, BUS_ERROR_TOKEN_ACTION_TIMEOUT, "Token action timeout. (User was supposed to verify presence or similar, by interacting with the token, and didn't do that in time.)"); return sd_bus_error_set(error, BUS_ERROR_TOKEN_ACTION_TIMEOUT, "Token action timeout. (User was supposed to verify presence or similar, by interacting with the token, and didn't do that in time.)");
case -EOWNERDEAD: case -EOWNERDEAD:
@ -1408,7 +1410,7 @@ static int home_update_internal(
return sd_bus_error_set(error, BUS_ERROR_HOME_RECORD_DOWNGRADE, "Refusing to update to older home record."); return sd_bus_error_set(error, BUS_ERROR_HOME_RECORD_DOWNGRADE, "Refusing to update to older home record.");
if (!secret && FLAGS_SET(hr->mask, USER_RECORD_SECRET)) { if (!secret && FLAGS_SET(hr->mask, USER_RECORD_SECRET)) {
r = user_record_clone(hr, USER_RECORD_EXTRACT_SECRET, &saved_secret); r = user_record_clone(hr, USER_RECORD_EXTRACT_SECRET|USER_RECORD_PERMISSIVE, &saved_secret);
if (r < 0) if (r < 0)
return r; return r;
@ -1443,7 +1445,7 @@ static int home_update_internal(
return r; return r;
} }
r = user_record_extend_with_binding(hr, h->record, USER_RECORD_LOAD_MASK_SECRET, &new_hr); r = user_record_extend_with_binding(hr, h->record, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &new_hr);
if (r < 0) if (r < 0)
return r; return r;
@ -1537,7 +1539,7 @@ int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, sd_bus_error *e
if (h->signed_locally <= 0) /* Don't allow changing of records not signed only by us */ if (h->signed_locally <= 0) /* Don't allow changing of records not signed only by us */
return sd_bus_error_setf(error, BUS_ERROR_HOME_RECORD_SIGNED, "Home %s is signed and cannot be modified locally.", h->user_name); return sd_bus_error_setf(error, BUS_ERROR_HOME_RECORD_SIGNED, "Home %s is signed and cannot be modified locally.", h->user_name);
r = user_record_clone(h->record, USER_RECORD_LOAD_REFUSE_SECRET, &c); r = user_record_clone(h->record, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE, &c);
if (r < 0) if (r < 0)
return r; return r;
@ -1626,7 +1628,7 @@ int home_passwd(Home *h,
if (r < 0) if (r < 0)
return r; return r;
r = user_record_clone(h->record, USER_RECORD_LOAD_REFUSE_SECRET, &c); r = user_record_clone(h->record, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE, &c);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -398,7 +398,7 @@ static int method_register_home(
assert(message); assert(message);
assert(m); assert(m);
r = bus_message_read_home_record(message, USER_RECORD_LOAD_EMBEDDED, &hr, error); r = bus_message_read_home_record(message, USER_RECORD_LOAD_EMBEDDED|USER_RECORD_PERMISSIVE, &hr, error);
if (r < 0) if (r < 0)
return r; return r;
@ -513,7 +513,7 @@ static int method_update_home(sd_bus_message *message, void *userdata, sd_bus_er
assert(message); assert(message);
assert(m); assert(m);
r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE, &hr, error); r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE, &hr, error);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -364,7 +364,7 @@ static int manager_add_home_by_record(
if (!hr) if (!hr)
return log_oom(); return log_oom();
r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG); r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -42,7 +42,7 @@ static int build_user_json(Home *h, bool trusted, JsonVariant **ret) {
assert(h); assert(h);
assert(ret); assert(ret);
flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE; flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE;
if (trusted) if (trusted)
flags |= USER_RECORD_ALLOW_PRIVILEGED; flags |= USER_RECORD_ALLOW_PRIVILEGED;
else else

View File

@ -185,7 +185,7 @@ int home_create_cifs(UserRecord *h, UserRecord **ret_home) {
if (r < 0) if (r < 0)
return r; return r;
r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET, &new_home); r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &new_home);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to clone record: %m"); return log_error_errno(r, "Failed to clone record: %m");

View File

@ -158,7 +158,7 @@ int home_create_directory_or_subvolume(UserRecord *h, UserRecord **ret_home) {
if (r < 0) if (r < 0)
return r; return r;
r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET, &new_home); r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &new_home);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to clone record: %m"); return log_error_errno(r, "Failed to clone record: %m");

View File

@ -6,6 +6,7 @@
#include "homework-fido2.h" #include "homework-fido2.h"
#include "libfido2-util.h" #include "libfido2-util.h"
#include "memory-util.h" #include "memory-util.h"
#include "strv.h"
int fido2_use_token( int fido2_use_token(
UserRecord *h, UserRecord *h,
@ -15,6 +16,7 @@ int fido2_use_token(
_cleanup_(erase_and_freep) void *hmac = NULL; _cleanup_(erase_and_freep) void *hmac = NULL;
size_t hmac_size; size_t hmac_size;
Fido2EnrollFlags flags = 0;
int r; int r;
assert(h); assert(h);
@ -22,13 +24,42 @@ int fido2_use_token(
assert(salt); assert(salt);
assert(ret); assert(ret);
/* If we know the up/uv/clientPin settings used during enrollment, let's pass this on for
* authentication, or generate errors immediately if interactivity of the specified kind is not
* allowed. */
if (salt->up > 0) {
if (h->fido2_user_presence_permitted <= 0)
return -EMEDIUMTYPE;
flags |= FIDO2ENROLL_UP;
} else if (salt->up < 0) /* unset? */
flags |= FIDO2ENROLL_UP_IF_NEEDED; /* compat with pre-248 */
if (salt->uv > 0) {
if (h->fido2_user_verification_permitted <= 0)
return -ENOCSI;
flags |= FIDO2ENROLL_UV;
} else if (salt->uv < 0)
flags |= FIDO2ENROLL_UV_OMIT; /* compat with pre-248 */
if (salt->client_pin > 0) {
if (strv_isempty(secret->token_pin))
return -ENOANO;
flags |= FIDO2ENROLL_PIN;
} else if (salt->client_pin < 0)
flags |= FIDO2ENROLL_PIN_IF_NEEDED; /* compat with pre-248 */
r = fido2_use_hmac_hash( r = fido2_use_hmac_hash(
NULL, NULL,
"io.systemd.home", "io.systemd.home",
salt->salt, salt->salt_size, salt->salt, salt->salt_size,
salt->credential.id, salt->credential.size, salt->credential.id, salt->credential.size,
secret->token_pin, secret->token_pin,
FIDO2ENROLL_PIN | (h->fido2_user_presence_permitted > 0 ? FIDO2ENROLL_UP : 0), // FIXME: add a --lock-with-pin parameter like cryptenroll flags,
&hmac, &hmac,
&hmac_size); &hmac_size);
if (r < 0) if (r < 0)

View File

@ -550,7 +550,7 @@ int home_create_fscrypt(
if (r < 0) if (r < 0)
return r; return r;
r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET, &new_home); r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &new_home);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to clone record: %m"); return log_error_errno(r, "Failed to clone record: %m");

View File

@ -243,7 +243,7 @@ static int luks_try_passwords(
STRV_FOREACH(pp, passwords) { STRV_FOREACH(pp, passwords) {
size_t vks = *volume_key_size; size_t vks = *volume_key_size;
r = crypt_volume_key_get( r = sym_crypt_volume_key_get(
cd, cd,
CRYPT_ANY_SLOT, CRYPT_ANY_SLOT,
volume_key, volume_key,
@ -276,7 +276,7 @@ static int luks_setup(
void **ret_volume_key, void **ret_volume_key,
size_t *ret_volume_key_size) { size_t *ret_volume_key_size) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL; _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *vk = NULL; _cleanup_(erase_and_freep) void *vk = NULL;
sd_id128_t p; sd_id128_t p;
size_t vks; size_t vks;
@ -287,17 +287,17 @@ static int luks_setup(
assert(dm_name); assert(dm_name);
assert(ret); assert(ret);
r = crypt_init(&cd, node); r = sym_crypt_init(&cd, node);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to allocate libcryptsetup context: %m"); return log_error_errno(r, "Failed to allocate libcryptsetup context: %m");
cryptsetup_enable_logging(cd); cryptsetup_enable_logging(cd);
r = crypt_load(cd, CRYPT_LUKS2, NULL); r = sym_crypt_load(cd, CRYPT_LUKS2, NULL);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to load LUKS superblock: %m"); return log_error_errno(r, "Failed to load LUKS superblock: %m");
r = crypt_get_volume_key_size(cd); r = sym_crypt_get_volume_key_size(cd);
if (r <= 0) if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size"); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size");
vks = (size_t) r; vks = (size_t) r;
@ -305,7 +305,7 @@ static int luks_setup(
if (!sd_id128_is_null(uuid) || ret_found_uuid) { if (!sd_id128_is_null(uuid) || ret_found_uuid) {
const char *s; const char *s;
s = crypt_get_uuid(cd); s = sym_crypt_get_uuid(cd);
if (!s) if (!s)
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock has no UUID."); return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock has no UUID.");
@ -319,10 +319,10 @@ static int luks_setup(
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock has wrong UUID."); return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock has wrong UUID.");
} }
if (cipher && !streq_ptr(cipher, crypt_get_cipher(cd))) if (cipher && !streq_ptr(cipher, sym_crypt_get_cipher(cd)))
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock declares wrong cipher."); return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock declares wrong cipher.");
if (cipher_mode && !streq_ptr(cipher_mode, crypt_get_cipher_mode(cd))) if (cipher_mode && !streq_ptr(cipher_mode, sym_crypt_get_cipher_mode(cd)))
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock declares wrong cipher mode."); return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock declares wrong cipher mode.");
if (volume_key_size != UINT64_MAX && vks != volume_key_size) if (volume_key_size != UINT64_MAX && vks != volume_key_size)
@ -343,7 +343,7 @@ static int luks_setup(
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to unlocks LUKS superblock: %m"); return log_error_errno(r, "Failed to unlocks LUKS superblock: %m");
r = crypt_activate_by_volume_key( r = sym_crypt_activate_by_volume_key(
cd, cd,
dm_name, dm_name,
vk, vks, vk, vks,
@ -374,7 +374,7 @@ static int luks_open(
void **ret_volume_key, void **ret_volume_key,
size_t *ret_volume_key_size) { size_t *ret_volume_key_size) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL; _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *vk = NULL; _cleanup_(erase_and_freep) void *vk = NULL;
sd_id128_t p; sd_id128_t p;
char **list; char **list;
@ -387,17 +387,17 @@ static int luks_open(
/* Opens a LUKS device that is already set up. Re-validates the password while doing so (which also /* Opens a LUKS device that is already set up. Re-validates the password while doing so (which also
* provides us with the volume key, which we want). */ * provides us with the volume key, which we want). */
r = crypt_init_by_name(&cd, dm_name); r = sym_crypt_init_by_name(&cd, dm_name);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name); return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name);
cryptsetup_enable_logging(cd); cryptsetup_enable_logging(cd);
r = crypt_load(cd, CRYPT_LUKS2, NULL); r = sym_crypt_load(cd, CRYPT_LUKS2, NULL);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to load LUKS superblock: %m"); return log_error_errno(r, "Failed to load LUKS superblock: %m");
r = crypt_get_volume_key_size(cd); r = sym_crypt_get_volume_key_size(cd);
if (r <= 0) if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size"); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size");
vks = (size_t) r; vks = (size_t) r;
@ -405,7 +405,7 @@ static int luks_open(
if (ret_found_uuid) { if (ret_found_uuid) {
const char *s; const char *s;
s = crypt_get_uuid(cd); s = sym_crypt_get_uuid(cd);
if (!s) if (!s)
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock has no UUID."); return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock has no UUID.");
@ -433,7 +433,7 @@ static int luks_open(
/* This is needed so that crypt_resize() can operate correctly for pre-existing LUKS devices. We need /* This is needed so that crypt_resize() can operate correctly for pre-existing LUKS devices. We need
* to tell libcryptsetup the volume key explicitly, so that it is in the kernel keyring. */ * to tell libcryptsetup the volume key explicitly, so that it is in the kernel keyring. */
r = crypt_activate_by_volume_key(cd, NULL, vk, vks, CRYPT_ACTIVATE_KEYRING_KEY); r = sym_crypt_activate_by_volume_key(cd, NULL, vk, vks, CRYPT_ACTIVATE_KEYRING_KEY);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to upload volume key again: %m"); return log_error_errno(r, "Failed to upload volume key again: %m");
@ -640,11 +640,11 @@ static int crypt_device_to_evp_cipher(struct crypt_device *cd, const EVP_CIPHER
/* Let's find the right OpenSSL EVP_CIPHER object that matches the encryption settings of the LUKS /* Let's find the right OpenSSL EVP_CIPHER object that matches the encryption settings of the LUKS
* device */ * device */
cipher = crypt_get_cipher(cd); cipher = sym_crypt_get_cipher(cd);
if (!cipher) if (!cipher)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot get cipher from LUKS device."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot get cipher from LUKS device.");
cipher_mode = crypt_get_cipher_mode(cd); cipher_mode = sym_crypt_get_cipher_mode(cd);
if (!cipher_mode) if (!cipher_mode)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot get cipher mode from LUKS device."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot get cipher mode from LUKS device.");
@ -652,7 +652,7 @@ static int crypt_device_to_evp_cipher(struct crypt_device *cd, const EVP_CIPHER
if (e) if (e)
cipher_mode = strndupa(cipher_mode, e - cipher_mode); cipher_mode = strndupa(cipher_mode, e - cipher_mode);
r = crypt_get_volume_key_size(cd); r = sym_crypt_get_volume_key_size(cd);
if (r <= 0) if (r <= 0)
return log_error_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Cannot get volume key size from LUKS device."); return log_error_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Cannot get volume key size from LUKS device.");
@ -703,7 +703,7 @@ static int luks_validate_home_record(
unsigned line, column; unsigned line, column;
const EVP_CIPHER *cc; const EVP_CIPHER *cc;
state = crypt_token_status(cd, token, &type); state = sym_crypt_token_status(cd, token, &type);
if (state == CRYPT_TOKEN_INACTIVE) /* First unconfigured token, give up */ if (state == CRYPT_TOKEN_INACTIVE) /* First unconfigured token, give up */
break; break;
if (IN_SET(state, CRYPT_TOKEN_INTERNAL, CRYPT_TOKEN_INTERNAL_UNKNOWN, CRYPT_TOKEN_EXTERNAL)) if (IN_SET(state, CRYPT_TOKEN_INTERNAL, CRYPT_TOKEN_INTERNAL_UNKNOWN, CRYPT_TOKEN_EXTERNAL))
@ -714,7 +714,7 @@ static int luks_validate_home_record(
if (!streq(type, "systemd-homed")) if (!streq(type, "systemd-homed"))
continue; continue;
r = crypt_token_json_get(cd, token, &text); r = sym_crypt_token_json_get(cd, token, &text);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to read LUKS token %i: %m", token); return log_error_errno(r, "Failed to read LUKS token %i: %m", token);
@ -779,7 +779,7 @@ static int luks_validate_home_record(
if (!lhr) if (!lhr)
return log_oom(); return log_oom();
r = user_record_load(lhr, rr, USER_RECORD_LOAD_EMBEDDED); r = user_record_load(lhr, rr, USER_RECORD_LOAD_EMBEDDED|USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse user record: %m"); return log_error_errno(r, "Failed to parse user record: %m");
@ -902,7 +902,7 @@ int home_store_header_identity_luks(
* the file system, so that we can validate it first, and only then mount the file system. To keep * the file system, so that we can validate it first, and only then mount the file system. To keep
* things simple we use the same encryption settings for this record as for the file system itself. */ * things simple we use the same encryption settings for this record as for the file system itself. */
r = user_record_clone(h, USER_RECORD_EXTRACT_EMBEDDED, &header_home); r = user_record_clone(h, USER_RECORD_EXTRACT_EMBEDDED|USER_RECORD_PERMISSIVE, &header_home);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to determine new header record: %m"); return log_error_errno(r, "Failed to determine new header record: %m");
@ -919,7 +919,7 @@ int home_store_header_identity_luks(
crypt_token_info state; crypt_token_info state;
const char *type; const char *type;
state = crypt_token_status(setup->crypt_device, token, &type); state = sym_crypt_token_status(setup->crypt_device, token, &type);
if (state == CRYPT_TOKEN_INACTIVE) /* First unconfigured token, we are done */ if (state == CRYPT_TOKEN_INACTIVE) /* First unconfigured token, we are done */
break; break;
if (IN_SET(state, CRYPT_TOKEN_INTERNAL, CRYPT_TOKEN_INTERNAL_UNKNOWN, CRYPT_TOKEN_EXTERNAL)) if (IN_SET(state, CRYPT_TOKEN_INTERNAL, CRYPT_TOKEN_INTERNAL_UNKNOWN, CRYPT_TOKEN_EXTERNAL))
@ -930,7 +930,7 @@ int home_store_header_identity_luks(
if (!streq(type, "systemd-homed")) if (!streq(type, "systemd-homed"))
continue; continue;
r = crypt_token_json_set(setup->crypt_device, token, text); r = sym_crypt_token_json_set(setup->crypt_device, token, text);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to set JSON token for slot %i: %m", token); return log_error_errno(r, "Failed to set JSON token for slot %i: %m", token);
@ -1048,7 +1048,7 @@ int home_prepare_luks(
sd_id128_t found_partition_uuid, found_luks_uuid, found_fs_uuid; sd_id128_t found_partition_uuid, found_luks_uuid, found_fs_uuid;
_cleanup_(user_record_unrefp) UserRecord *luks_home = NULL; _cleanup_(user_record_unrefp) UserRecord *luks_home = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL; _cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL; _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *volume_key = NULL; _cleanup_(erase_and_freep) void *volume_key = NULL;
_cleanup_close_ int root_fd = -1, image_fd = -1; _cleanup_close_ int root_fd = -1, image_fd = -1;
bool dm_activated = false, mounted = false; bool dm_activated = false, mounted = false;
@ -1064,6 +1064,10 @@ int home_prepare_luks(
assert(user_record_storage(h) == USER_LUKS); assert(user_record_storage(h) == USER_LUKS);
r = dlopen_cryptsetup();
if (r < 0)
return r;
if (already_activated) { if (already_activated) {
struct loop_info64 info; struct loop_info64 info;
const char *n; const char *n;
@ -1082,7 +1086,7 @@ int home_prepare_luks(
if (r < 0) if (r < 0)
return r; return r;
n = crypt_get_device_name(cd); n = sym_crypt_get_device_name(cd);
if (!n) if (!n)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine backing device for DM %s.", setup->dm_name); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine backing device for DM %s.", setup->dm_name);
@ -1265,7 +1269,7 @@ fail:
(void) umount_verbose(LOG_ERR, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW); (void) umount_verbose(LOG_ERR, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW);
if (dm_activated) if (dm_activated)
(void) crypt_deactivate(cd, setup->dm_name); (void) sym_crypt_deactivate_by_name(cd, setup->dm_name, 0);
if (image_fd >= 0 && marked_dirty) if (image_fd >= 0 && marked_dirty)
(void) run_mark_dirty(image_fd, false); (void) run_mark_dirty(image_fd, false);
@ -1301,6 +1305,10 @@ int home_activate_luks(
assert(user_record_storage(h) == USER_LUKS); assert(user_record_storage(h) == USER_LUKS);
assert(ret_home); assert(ret_home);
r = dlopen_cryptsetup();
if (r < 0)
return r;
assert_se(hdo = user_record_home_directory(h)); assert_se(hdo = user_record_home_directory(h));
hd = strdupa(hdo); /* copy the string out, since it might change later in the home record object */ hd = strdupa(hdo); /* copy the string out, since it might change later in the home record object */
@ -1358,7 +1366,7 @@ int home_activate_luks(
loop_device_relinquish(setup.loop); loop_device_relinquish(setup.loop);
r = crypt_deactivate_by_name(NULL, setup.dm_name, CRYPT_DEACTIVATE_DEFERRED); r = sym_crypt_deactivate_by_name(NULL, setup.dm_name, CRYPT_DEACTIVATE_DEFERRED);
if (r < 0) if (r < 0)
log_warning_errno(r, "Failed to relinquish DM device, ignoring: %m"); log_warning_errno(r, "Failed to relinquish DM device, ignoring: %m");
@ -1375,7 +1383,7 @@ int home_activate_luks(
} }
int home_deactivate_luks(UserRecord *h) { int home_deactivate_luks(UserRecord *h) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL; _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_free_ char *dm_name = NULL, *dm_node = NULL; _cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
bool we_detached; bool we_detached;
int r; int r;
@ -1386,11 +1394,15 @@ int home_deactivate_luks(UserRecord *h) {
* don't bother about the loopback device because unlike the DM device it doesn't have a fixed * don't bother about the loopback device because unlike the DM device it doesn't have a fixed
* name. */ * name. */
r = dlopen_cryptsetup();
if (r < 0)
return r;
r = make_dm_names(h->user_name, &dm_name, &dm_node); r = make_dm_names(h->user_name, &dm_name, &dm_node);
if (r < 0) if (r < 0)
return r; return r;
r = crypt_init_by_name(&cd, dm_name); r = sym_crypt_init_by_name(&cd, dm_name);
if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) { if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
log_debug_errno(r, "LUKS device %s has already been detached.", dm_name); log_debug_errno(r, "LUKS device %s has already been detached.", dm_name);
we_detached = false; we_detached = false;
@ -1401,7 +1413,7 @@ int home_deactivate_luks(UserRecord *h) {
cryptsetup_enable_logging(cd); cryptsetup_enable_logging(cd);
r = crypt_deactivate(cd, dm_name); r = sym_crypt_deactivate_by_name(cd, dm_name, 0);
if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) { if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
log_debug_errno(r, "LUKS device %s is already detached.", dm_node); log_debug_errno(r, "LUKS device %s is already detached.", dm_node);
we_detached = false; we_detached = false;
@ -1477,7 +1489,7 @@ static int luks_format(
struct crypt_device **ret) { struct crypt_device **ret) {
_cleanup_(user_record_unrefp) UserRecord *reduced = NULL; _cleanup_(user_record_unrefp) UserRecord *reduced = NULL;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL; _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *volume_key = NULL; _cleanup_(erase_and_freep) void *volume_key = NULL;
struct crypt_pbkdf_type good_pbkdf, minimal_pbkdf; struct crypt_pbkdf_type good_pbkdf, minimal_pbkdf;
char suuid[ID128_UUID_STRING_MAX], **pp; char suuid[ID128_UUID_STRING_MAX], **pp;
@ -1490,7 +1502,7 @@ static int luks_format(
assert(hr); assert(hr);
assert(ret); assert(ret);
r = crypt_init(&cd, node); r = sym_crypt_init(&cd, node);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to allocate libcryptsetup context: %m"); return log_error_errno(r, "Failed to allocate libcryptsetup context: %m");
@ -1511,7 +1523,7 @@ static int luks_format(
#if HAVE_CRYPT_SET_METADATA_SIZE #if HAVE_CRYPT_SET_METADATA_SIZE
/* Increase the metadata space to 4M, the largest LUKS2 supports */ /* Increase the metadata space to 4M, the largest LUKS2 supports */
r = crypt_set_metadata_size(cd, 4096U*1024U, 0); r = sym_crypt_set_metadata_size(cd, 4096U*1024U, 0);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to change LUKS2 metadata size: %m"); return log_error_errno(r, "Failed to change LUKS2 metadata size: %m");
#endif #endif
@ -1519,7 +1531,7 @@ static int luks_format(
build_good_pbkdf(&good_pbkdf, hr); build_good_pbkdf(&good_pbkdf, hr);
build_minimal_pbkdf(&minimal_pbkdf, hr); build_minimal_pbkdf(&minimal_pbkdf, hr);
r = crypt_format(cd, r = sym_crypt_format(cd,
CRYPT_LUKS2, CRYPT_LUKS2,
user_record_luks_cipher(hr), user_record_luks_cipher(hr),
user_record_luks_cipher_mode(hr), user_record_luks_cipher_mode(hr),
@ -1542,15 +1554,15 @@ static int luks_format(
if (strv_contains(cache->pkcs11_passwords, *pp) || if (strv_contains(cache->pkcs11_passwords, *pp) ||
strv_contains(cache->fido2_passwords, *pp)) { strv_contains(cache->fido2_passwords, *pp)) {
log_debug("Using minimal PBKDF for slot %i", slot); log_debug("Using minimal PBKDF for slot %i", slot);
r = crypt_set_pbkdf_type(cd, &minimal_pbkdf); r = sym_crypt_set_pbkdf_type(cd, &minimal_pbkdf);
} else { } else {
log_debug("Using good PBKDF for slot %i", slot); log_debug("Using good PBKDF for slot %i", slot);
r = crypt_set_pbkdf_type(cd, &good_pbkdf); r = sym_crypt_set_pbkdf_type(cd, &good_pbkdf);
} }
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to tweak PBKDF for slot %i: %m", slot); return log_error_errno(r, "Failed to tweak PBKDF for slot %i: %m", slot);
r = crypt_keyslot_add_by_volume_key( r = sym_crypt_keyslot_add_by_volume_key(
cd, cd,
slot, slot,
volume_key, volume_key,
@ -1564,7 +1576,7 @@ static int luks_format(
slot++; slot++;
} }
r = crypt_activate_by_volume_key( r = sym_crypt_activate_by_volume_key(
cd, cd,
dm_name, dm_name,
volume_key, volume_key,
@ -1575,7 +1587,7 @@ static int luks_format(
log_info("LUKS activation by volume key succeeded."); log_info("LUKS activation by volume key succeeded.");
r = user_record_clone(hr, USER_RECORD_EXTRACT_EMBEDDED, &reduced); r = user_record_clone(hr, USER_RECORD_EXTRACT_EMBEDDED|USER_RECORD_PERMISSIVE, &reduced);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to prepare home record for LUKS: %m"); return log_error_errno(r, "Failed to prepare home record for LUKS: %m");
@ -1583,7 +1595,7 @@ static int luks_format(
if (r < 0) if (r < 0)
return r; return r;
r = crypt_token_json_set(cd, CRYPT_ANY_TOKEN, text); r = sym_crypt_token_json_set(cd, CRYPT_ANY_TOKEN, text);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to set LUKS JSON token: %m"); return log_error_errno(r, "Failed to set LUKS JSON token: %m");
@ -1876,7 +1888,7 @@ int home_create_luks(
_cleanup_(user_record_unrefp) UserRecord *new_home = NULL; _cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
sd_id128_t partition_uuid, fs_uuid, luks_uuid, disk_uuid; sd_id128_t partition_uuid, fs_uuid, luks_uuid, disk_uuid;
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL; _cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL; _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_close_ int image_fd = -1, root_fd = -1; _cleanup_close_ int image_fd = -1, root_fd = -1;
const char *fstype, *ip; const char *fstype, *ip;
struct statfs sfs; struct statfs sfs;
@ -1886,6 +1898,10 @@ int home_create_luks(
assert(h->storage < 0 || h->storage == USER_LUKS); assert(h->storage < 0 || h->storage == USER_LUKS);
assert(ret_home); assert(ret_home);
r = dlopen_cryptsetup();
if (r < 0)
return r;
assert_se(ip = user_record_image_path(h)); assert_se(ip = user_record_image_path(h));
fstype = user_record_file_system_type(h); fstype = user_record_file_system_type(h);
@ -2139,7 +2155,7 @@ int home_create_luks(
if (r < 0) if (r < 0)
goto fail; goto fail;
r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_LOG, &new_home); r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_LOG|USER_RECORD_PERMISSIVE, &new_home);
if (r < 0) { if (r < 0) {
log_error_errno(r, "Failed to clone record: %m"); log_error_errno(r, "Failed to clone record: %m");
goto fail; goto fail;
@ -2152,8 +2168,8 @@ int home_create_luks(
partition_uuid, partition_uuid,
luks_uuid, luks_uuid,
fs_uuid, fs_uuid,
crypt_get_cipher(cd), sym_crypt_get_cipher(cd),
crypt_get_cipher_mode(cd), sym_crypt_get_cipher_mode(cd),
luks_volume_key_size_convert(cd), luks_volume_key_size_convert(cd),
fstype, fstype,
NULL, NULL,
@ -2178,13 +2194,13 @@ int home_create_luks(
mounted = false; mounted = false;
r = crypt_deactivate(cd, dm_name); r = sym_crypt_deactivate_by_name(cd, dm_name, 0);
if (r < 0) { if (r < 0) {
log_error_errno(r, "Failed to deactivate LUKS device: %m"); log_error_errno(r, "Failed to deactivate LUKS device: %m");
goto fail; goto fail;
} }
crypt_free(cd); sym_crypt_free(cd);
cd = NULL; cd = NULL;
dm_activated = false; dm_activated = false;
@ -2245,7 +2261,7 @@ fail:
(void) umount_verbose(LOG_WARNING, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW); (void) umount_verbose(LOG_WARNING, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW);
if (dm_activated) if (dm_activated)
(void) crypt_deactivate(cd, dm_name); (void) sym_crypt_deactivate_by_name(cd, dm_name, 0);
loop = loop_device_unref(loop); loop = loop_device_unref(loop);
@ -2633,6 +2649,10 @@ int home_resize_luks(
assert(setup); assert(setup);
assert(ret_home); assert(ret_home);
r = dlopen_cryptsetup();
if (r < 0)
return r;
assert_se(ipo = user_record_image_path(h)); assert_se(ipo = user_record_image_path(h));
ip = strdupa(ipo); /* copy out since original might change later in home record object */ ip = strdupa(ipo); /* copy out since original might change later in home record object */
@ -2733,7 +2753,7 @@ int home_resize_luks(
setup->partition_offset + new_partition_size > new_image_size) setup->partition_offset + new_partition_size > new_image_size)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "New partition doesn't fit into backing storage, refusing."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "New partition doesn't fit into backing storage, refusing.");
crypto_offset = crypt_get_data_offset(setup->crypt_device); crypto_offset = sym_crypt_get_data_offset(setup->crypt_device);
if (setup->partition_size / 512U <= crypto_offset) if (setup->partition_size / 512U <= crypto_offset)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Weird, old crypto payload offset doesn't actually fit in partition size?"); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Weird, old crypto payload offset doesn't actually fit in partition size?");
if (new_partition_size / 512U <= crypto_offset) if (new_partition_size / 512U <= crypto_offset)
@ -2797,7 +2817,7 @@ int home_resize_luks(
log_debug_errno(errno, "BLKRRPART failed on block device, ignoring: %m"); log_debug_errno(errno, "BLKRRPART failed on block device, ignoring: %m");
/* Tell LUKS about the new bigger size too */ /* Tell LUKS about the new bigger size too */
r = crypt_resize(setup->crypt_device, setup->dm_name, new_fs_size / 512U); r = sym_crypt_resize(setup->crypt_device, setup->dm_name, new_fs_size / 512U);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to grow LUKS device: %m"); return log_error_errno(r, "Failed to grow LUKS device: %m");
@ -2838,7 +2858,7 @@ int home_resize_luks(
if (new_fs_size < old_fs_size) { if (new_fs_size < old_fs_size) {
/* Shrink the LUKS device now, matching the new file system size */ /* Shrink the LUKS device now, matching the new file system size */
r = crypt_resize(setup->crypt_device, setup->dm_name, new_fs_size / 512); r = sym_crypt_resize(setup->crypt_device, setup->dm_name, new_fs_size / 512);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to shrink LUKS device: %m"); return log_error_errno(r, "Failed to shrink LUKS device: %m");
@ -2919,16 +2939,20 @@ int home_passwd_luks(
assert(user_record_storage(h) == USER_LUKS); assert(user_record_storage(h) == USER_LUKS);
assert(setup); assert(setup);
type = crypt_get_type(setup->crypt_device); r = dlopen_cryptsetup();
if (r < 0)
return r;
type = sym_crypt_get_type(setup->crypt_device);
if (!type) if (!type)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine crypto device type."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine crypto device type.");
r = crypt_keyslot_max(type); r = sym_crypt_keyslot_max(type);
if (r <= 0) if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine number of key slots."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine number of key slots.");
max_key_slots = r; max_key_slots = r;
r = crypt_get_volume_key_size(setup->crypt_device); r = sym_crypt_get_volume_key_size(setup->crypt_device);
if (r <= 0) if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine volume key size."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine volume key size.");
volume_key_size = (size_t) r; volume_key_size = (size_t) r;
@ -2954,7 +2978,7 @@ int home_passwd_luks(
build_minimal_pbkdf(&minimal_pbkdf, h); build_minimal_pbkdf(&minimal_pbkdf, h);
for (size_t i = 0; i < max_key_slots; i++) { for (size_t i = 0; i < max_key_slots; i++) {
r = crypt_keyslot_destroy(setup->crypt_device, i); r = sym_crypt_keyslot_destroy(setup->crypt_device, i);
if (r < 0 && !IN_SET(r, -ENOENT, -EINVAL)) /* Returns EINVAL or ENOENT if there's no key in this slot already */ if (r < 0 && !IN_SET(r, -ENOENT, -EINVAL)) /* Returns EINVAL or ENOENT if there's no key in this slot already */
return log_error_errno(r, "Failed to destroy LUKS password: %m"); return log_error_errno(r, "Failed to destroy LUKS password: %m");
@ -2967,15 +2991,15 @@ int home_passwd_luks(
if (strv_contains(cache->pkcs11_passwords, effective_passwords[i]) || if (strv_contains(cache->pkcs11_passwords, effective_passwords[i]) ||
strv_contains(cache->fido2_passwords, effective_passwords[i])) { strv_contains(cache->fido2_passwords, effective_passwords[i])) {
log_debug("Using minimal PBKDF for slot %zu", i); log_debug("Using minimal PBKDF for slot %zu", i);
r = crypt_set_pbkdf_type(setup->crypt_device, &minimal_pbkdf); r = sym_crypt_set_pbkdf_type(setup->crypt_device, &minimal_pbkdf);
} else { } else {
log_debug("Using good PBKDF for slot %zu", i); log_debug("Using good PBKDF for slot %zu", i);
r = crypt_set_pbkdf_type(setup->crypt_device, &good_pbkdf); r = sym_crypt_set_pbkdf_type(setup->crypt_device, &good_pbkdf);
} }
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to tweak PBKDF for slot %zu: %m", i); return log_error_errno(r, "Failed to tweak PBKDF for slot %zu: %m", i);
r = crypt_keyslot_add_by_volume_key( r = sym_crypt_keyslot_add_by_volume_key(
setup->crypt_device, setup->crypt_device,
i, i,
volume_key, volume_key,
@ -2992,7 +3016,7 @@ int home_passwd_luks(
} }
int home_lock_luks(UserRecord *h) { int home_lock_luks(UserRecord *h) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL; _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_free_ char *dm_name = NULL, *dm_node = NULL; _cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
_cleanup_close_ int root_fd = -1; _cleanup_close_ int root_fd = -1;
const char *p; const char *p;
@ -3009,7 +3033,11 @@ int home_lock_luks(UserRecord *h) {
if (r < 0) if (r < 0)
return r; return r;
r = crypt_init_by_name(&cd, dm_name); r = dlopen_cryptsetup();
if (r < 0)
return r;
r = sym_crypt_init_by_name(&cd, dm_name);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name); return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name);
@ -3025,7 +3053,7 @@ int home_lock_luks(UserRecord *h) {
/* Note that we don't invoke FIFREEZE here, it appears libcryptsetup/device-mapper already does that on its own for us */ /* Note that we don't invoke FIFREEZE here, it appears libcryptsetup/device-mapper already does that on its own for us */
r = crypt_suspend(cd, dm_name); r = sym_crypt_suspend(cd, dm_name);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to suspend cryptsetup device: %s: %m", dm_node); return log_error_errno(r, "Failed to suspend cryptsetup device: %s: %m", dm_node);
@ -3045,7 +3073,7 @@ static int luks_try_resume(
assert(dm_name); assert(dm_name);
STRV_FOREACH(pp, password) { STRV_FOREACH(pp, password) {
r = crypt_resume_by_passphrase( r = sym_crypt_resume_by_passphrase(
cd, cd,
dm_name, dm_name,
CRYPT_ANY_SLOT, CRYPT_ANY_SLOT,
@ -3064,7 +3092,7 @@ static int luks_try_resume(
int home_unlock_luks(UserRecord *h, PasswordCache *cache) { int home_unlock_luks(UserRecord *h, PasswordCache *cache) {
_cleanup_free_ char *dm_name = NULL, *dm_node = NULL; _cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL; _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
char **list; char **list;
int r; int r;
@ -3074,7 +3102,11 @@ int home_unlock_luks(UserRecord *h, PasswordCache *cache) {
if (r < 0) if (r < 0)
return r; return r;
r = crypt_init_by_name(&cd, dm_name); r = dlopen_cryptsetup();
if (r < 0)
return r;
r = sym_crypt_init_by_name(&cd, dm_name);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name); return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name);

View File

@ -31,7 +31,7 @@ static inline uint64_t luks_volume_key_size_convert(struct crypt_device *cd) {
/* Convert the "int" to uint64_t, which we usually use for byte sizes stored on disk. */ /* Convert the "int" to uint64_t, which we usually use for byte sizes stored on disk. */
k = crypt_get_volume_key_size(cd); k = sym_crypt_get_volume_key_size(cd);
if (k <= 0) if (k <= 0)
return UINT64_MAX; return UINT64_MAX;

View File

@ -48,8 +48,10 @@ int user_record_authenticate(
PasswordCache *cache, PasswordCache *cache,
bool strict_verify) { bool strict_verify) {
bool need_password = false, need_recovery_key = false, need_token = false, need_pin = false, need_protected_authentication_path_permitted = false, need_user_presence_permitted = false, bool need_password = false, need_recovery_key = false, need_token = false, need_pin = false,
pin_locked = false, pin_incorrect = false, pin_incorrect_few_tries_left = false, pin_incorrect_one_try_left = false, token_action_timeout = false; need_protected_authentication_path_permitted = false, need_user_presence_permitted = false,
need_user_verification_permitted = false, pin_locked = false, pin_incorrect = false,
pin_incorrect_few_tries_left = false, pin_incorrect_one_try_left = false, token_action_timeout = false;
int r; int r;
assert(h); assert(h);
@ -125,7 +127,7 @@ int user_record_authenticate(
return log_error_errno(r, "Failed to check supplied FIDO2 password: %m"); return log_error_errno(r, "Failed to check supplied FIDO2 password: %m");
if (r > 0) { if (r > 0) {
log_info("Previously acquired FIDO2 password unlocks user record."); log_info("Previously acquired FIDO2 password unlocks user record.");
return 0; return 1;
} }
} }
} }
@ -178,7 +180,7 @@ int user_record_authenticate(
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
return 0; return 1;
} }
#else #else
need_token = true; need_token = true;
@ -208,6 +210,9 @@ int user_record_authenticate(
case -EMEDIUMTYPE: case -EMEDIUMTYPE:
need_user_presence_permitted = true; need_user_presence_permitted = true;
break; break;
case -ENOCSI:
need_user_verification_permitted = true;
break;
case -ENOSTR: case -ENOSTR:
token_action_timeout = true; token_action_timeout = true;
break; break;
@ -250,6 +255,8 @@ int user_record_authenticate(
return -ERFKILL; return -ERFKILL;
if (need_user_presence_permitted) if (need_user_presence_permitted)
return -EMEDIUMTYPE; return -EMEDIUMTYPE;
if (need_user_verification_permitted)
return -ENOCSI;
if (need_pin) if (need_pin)
return -ENOANO; return -ENOANO;
if (need_token) if (need_token)
@ -297,7 +304,7 @@ int home_setup_undo(HomeSetup *setup) {
} }
if (setup->undo_dm && setup->crypt_device && setup->dm_name) { if (setup->undo_dm && setup->crypt_device && setup->dm_name) {
q = crypt_deactivate(setup->crypt_device, setup->dm_name); q = sym_crypt_deactivate_by_name(setup->crypt_device, setup->dm_name, 0);
if (q < 0) if (q < 0)
r = q; r = q;
} }
@ -328,8 +335,10 @@ int home_setup_undo(HomeSetup *setup) {
setup->dm_node = mfree(setup->dm_node); setup->dm_node = mfree(setup->dm_node);
setup->loop = loop_device_unref(setup->loop); setup->loop = loop_device_unref(setup->loop);
crypt_free(setup->crypt_device); if (setup->crypt_device) {
setup->crypt_device = NULL; sym_crypt_free(setup->crypt_device);
setup->crypt_device = NULL;
}
explicit_bzero_safe(setup->volume_key, setup->volume_key_size); explicit_bzero_safe(setup->volume_key, setup->volume_key_size);
setup->volume_key = mfree(setup->volume_key); setup->volume_key = mfree(setup->volume_key);
@ -517,7 +526,7 @@ int home_load_embedded_identity(
if (!embedded_home) if (!embedded_home)
return log_oom(); return log_oom();
r = user_record_load(embedded_home, v, USER_RECORD_LOAD_EMBEDDED); r = user_record_load(embedded_home, v, USER_RECORD_LOAD_EMBEDDED|USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return r; return r;
@ -602,7 +611,7 @@ int home_store_embedded_identity(UserRecord *h, int root_fd, uid_t uid, UserReco
assert(root_fd >= 0); assert(root_fd >= 0);
assert(uid_is_valid(uid)); assert(uid_is_valid(uid));
r = user_record_clone(h, USER_RECORD_EXTRACT_EMBEDDED, &embedded); r = user_record_clone(h, USER_RECORD_EXTRACT_EMBEDDED|USER_RECORD_PERMISSIVE, &embedded);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to determine new embedded record: %m"); return log_error_errno(r, "Failed to determine new embedded record: %m");
@ -653,8 +662,8 @@ int home_extend_embedded_identity(UserRecord *h, UserRecord *used, HomeSetup *se
setup->found_partition_uuid, setup->found_partition_uuid,
setup->found_luks_uuid, setup->found_luks_uuid,
setup->found_fs_uuid, setup->found_fs_uuid,
setup->crypt_device ? crypt_get_cipher(setup->crypt_device) : NULL, setup->crypt_device ? sym_crypt_get_cipher(setup->crypt_device) : NULL,
setup->crypt_device ? crypt_get_cipher_mode(setup->crypt_device) : NULL, setup->crypt_device ? sym_crypt_get_cipher_mode(setup->crypt_device) : NULL,
setup->crypt_device ? luks_volume_key_size_convert(setup->crypt_device) : UINT64_MAX, setup->crypt_device ? luks_volume_key_size_convert(setup->crypt_device) : UINT64_MAX,
file_system_type_fd(setup->root_fd), file_system_type_fd(setup->root_fd),
user_record_home_directory(used), user_record_home_directory(used),
@ -1086,15 +1095,21 @@ static int determine_default_storage(UserStorage *ret) {
return log_error_errno(r, "Failed to determine whether we are in a container: %m"); return log_error_errno(r, "Failed to determine whether we are in a container: %m");
if (r == 0) { if (r == 0) {
r = path_is_encrypted("/home"); r = path_is_encrypted("/home");
if (r < 0) if (r > 0)
log_warning_errno(r, "Failed to determine if /home is encrypted, ignoring: %m"); log_info("/home is encrypted, not using '%s' storage, in order to avoid double encryption.", user_storage_to_string(USER_LUKS));
if (r <= 0) { else {
log_info("Using automatic default storage of '%s'.", user_storage_to_string(USER_LUKS)); if (r < 0)
*ret = USER_LUKS; log_warning_errno(r, "Failed to determine if /home is encrypted, ignoring: %m");
return 0;
}
log_info("/home is encrypted, not using '%s' storage, in order to avoid double encryption.", user_storage_to_string(USER_LUKS)); r = dlopen_cryptsetup();
if (r < 0)
log_info("Not using '%s' storage, since libcryptsetup could not be loaded.", user_storage_to_string(USER_LUKS));
else {
log_info("Using automatic default storage of '%s'.", user_storage_to_string(USER_LUKS));
*ret = USER_LUKS;
return 0;
}
}
} else } else
log_info("Running in container, not using '%s' storage.", user_storage_to_string(USER_LUKS)); log_info("Running in container, not using '%s' storage.", user_storage_to_string(USER_LUKS));
@ -1661,7 +1676,7 @@ static int run(int argc, char *argv[]) {
if (!home) if (!home)
return log_oom(); return log_oom();
r = user_record_load(home, v, USER_RECORD_LOAD_FULL|USER_RECORD_LOG); r = user_record_load(home, v, USER_RECORD_LOAD_FULL|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return r; return r;
@ -1680,6 +1695,7 @@ static int run(int argc, char *argv[]) {
* ENOANO suitable PKCS#11/FIDO2 device found, but PIN is missing to unlock it * ENOANO suitable PKCS#11/FIDO2 device found, but PIN is missing to unlock it
* ERFKILL suitable PKCS#11 device found, but OK to ask for on-device interactive authentication not given * ERFKILL suitable PKCS#11 device found, but OK to ask for on-device interactive authentication not given
* EMEDIUMTYPE suitable FIDO2 device found, but OK to ask for user presence not given * EMEDIUMTYPE suitable FIDO2 device found, but OK to ask for user presence not given
* ENOCSI suitable FIDO2 device found, but OK to ask for user verification not given
* ENOSTR suitable FIDO2 device found, but user didn't react to action request on token quickly enough * ENOSTR suitable FIDO2 device found, but user didn't react to action request on token quickly enough
* EOWNERDEAD suitable PKCS#11/FIDO2 device found, but its PIN is locked * EOWNERDEAD suitable PKCS#11/FIDO2 device found, but its PIN is locked
* ENOLCK suitable PKCS#11/FIDO2 device found, but PIN incorrect * ENOLCK suitable PKCS#11/FIDO2 device found, but PIN incorrect

View File

@ -216,7 +216,7 @@ static int acquire_user_record(
if (!ur) if (!ur)
return pam_log_oom(handle); return pam_log_oom(handle);
r = user_record_load(ur, v, USER_RECORD_LOAD_REFUSE_SECRET); r = user_record_load(ur, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0) { if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to load user record: %s", strerror_safe(r)); pam_syslog(handle, LOG_ERR, "Failed to load user record: %s", strerror_safe(r));
return PAM_SERVICE_ERR; return PAM_SERVICE_ERR;
@ -377,7 +377,7 @@ static int handle_generic_user_record_error(
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED)) { } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED)) {
(void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Please verify presence on security token of user %s.", user_name); (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Please confirm presence on security token of user %s.", user_name);
r = user_record_set_fido2_user_presence_permitted(secret, true); r = user_record_set_fido2_user_presence_permitted(secret, true);
if (r < 0) { if (r < 0) {
@ -385,6 +385,16 @@ static int handle_generic_user_record_error(
return PAM_SERVICE_ERR; return PAM_SERVICE_ERR;
} }
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED)) {
(void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Please verify user on security token of user %s.", user_name);
r = user_record_set_fido2_user_verification_permitted(secret, true);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to set FIDO2 user verification permitted flag: %s", strerror_safe(r));
return PAM_SERVICE_ERR;
}
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PIN_LOCKED)) { } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PIN_LOCKED)) {
(void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN is locked, please unlock it first. (Hint: Removal and re-insertion might suffice.)"); (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN is locked, please unlock it first. (Hint: Removal and re-insertion might suffice.)");

View File

@ -14,7 +14,7 @@ static int user_record_signable_json(UserRecord *ur, char **ret) {
assert(ur); assert(ur);
assert(ret); assert(ret);
r = user_record_clone(ur, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_STRIP_SECRET|USER_RECORD_STRIP_BINDING|USER_RECORD_STRIP_STATUS|USER_RECORD_STRIP_SIGNATURE, &reduced); r = user_record_clone(ur, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_STRIP_SECRET|USER_RECORD_STRIP_BINDING|USER_RECORD_STRIP_STATUS|USER_RECORD_STRIP_SIGNATURE|USER_RECORD_PERMISSIVE, &reduced);
if (r < 0) if (r < 0)
return r; return r;
@ -95,7 +95,7 @@ int user_record_sign(UserRecord *ur, EVP_PKEY *private_key, UserRecord **ret) {
if (!signed_ur) if (!signed_ur)
return log_oom(); return log_oom();
r = user_record_load(signed_ur, v, USER_RECORD_LOAD_FULL); r = user_record_load(signed_ur, v, USER_RECORD_LOAD_FULL|USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -252,7 +252,7 @@ int user_record_reconcile(
if (!merged) if (!merged)
return -ENOMEM; return -ENOMEM;
r = user_record_load(merged, extended, USER_RECORD_LOAD_MASK_SECRET); r = user_record_load(merged, extended, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return r; return r;
@ -261,7 +261,7 @@ int user_record_reconcile(
} }
/* Strip out secrets */ /* Strip out secrets */
r = user_record_clone(host, USER_RECORD_LOAD_MASK_SECRET, ret); r = user_record_clone(host, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, ret);
if (r < 0) if (r < 0)
return r; return r;
@ -1065,6 +1065,34 @@ int user_record_set_fido2_user_presence_permitted(UserRecord *h, int b) {
return 0; return 0;
} }
int user_record_set_fido2_user_verification_permitted(UserRecord *h, int b) {
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
int r;
assert(h);
w = json_variant_ref(json_variant_by_key(h->json, "secret"));
if (b < 0)
r = json_variant_filter(&w, STRV_MAKE("fido2UserVerificationPermitted"));
else
r = json_variant_set_field_boolean(&w, "fido2UserVerificationPermitted", b);
if (r < 0)
return r;
if (json_variant_is_blank_object(w))
r = json_variant_filter(&h->json, STRV_MAKE("secret"));
else
r = json_variant_set_field(&h->json, "secret", w);
if (r < 0)
return r;
h->fido2_user_verification_permitted = b;
SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
return 0;
}
static bool per_machine_entry_empty(JsonVariant *v) { static bool per_machine_entry_empty(JsonVariant *v) {
const char *k; const char *k;
_unused_ JsonVariant *e; _unused_ JsonVariant *e;
@ -1167,6 +1195,14 @@ int user_record_merge_secret(UserRecord *h, UserRecord *secret) {
return r; return r;
} }
if (secret->fido2_user_verification_permitted >= 0) {
r = user_record_set_fido2_user_verification_permitted(
h,
secret->fido2_user_verification_permitted);
if (r < 0)
return r;
}
return 0; return 0;
} }

View File

@ -52,6 +52,7 @@ int user_record_set_hashed_password(UserRecord *h, char **hashed_password);
int user_record_set_token_pin(UserRecord *h, char **pin, bool prepend); int user_record_set_token_pin(UserRecord *h, char **pin, bool prepend);
int user_record_set_pkcs11_protected_authentication_path_permitted(UserRecord *h, int b); int user_record_set_pkcs11_protected_authentication_path_permitted(UserRecord *h, int b);
int user_record_set_fido2_user_presence_permitted(UserRecord *h, int b); int user_record_set_fido2_user_presence_permitted(UserRecord *h, int b);
int user_record_set_fido2_user_verification_permitted(UserRecord *h, int b);
int user_record_set_password_change_now(UserRecord *h, int b); int user_record_set_password_change_now(UserRecord *h, int b);
int user_record_merge_secret(UserRecord *h, UserRecord *secret); int user_record_merge_secret(UserRecord *h, UserRecord *secret);
int user_record_good_authentication(UserRecord *h); int user_record_good_authentication(UserRecord *h);

View File

@ -125,6 +125,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_PIN_NEEDED, ENOANO), SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_PIN_NEEDED, ENOANO),
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED, ERFKILL), SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED, ERFKILL),
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED, EMEDIUMTYPE), SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED, EMEDIUMTYPE),
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED, ENOCSI),
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_ACTION_TIMEOUT, ENOSTR), SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_ACTION_TIMEOUT, ENOSTR),
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_PIN_LOCKED, EOWNERDEAD), SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_PIN_LOCKED, EOWNERDEAD),
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_BAD_PIN, ENOLCK), SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_BAD_PIN, ENOLCK),

View File

@ -107,6 +107,8 @@
#define BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED \ #define BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED \
"org.freedesktop.home1.TokenProtectedAuthenticationPathNeeded" "org.freedesktop.home1.TokenProtectedAuthenticationPathNeeded"
#define BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED "org.freedesktop.home1.TokenUserPresenceNeeded" #define BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED "org.freedesktop.home1.TokenUserPresenceNeeded"
#define BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED \
"org.freedesktop.home1.TokenUserVerificationNeeded"
#define BUS_ERROR_TOKEN_ACTION_TIMEOUT "org.freedesktop.home1.TokenActionTimeout" #define BUS_ERROR_TOKEN_ACTION_TIMEOUT "org.freedesktop.home1.TokenActionTimeout"
#define BUS_ERROR_TOKEN_PIN_LOCKED "org.freedesktop.home1.TokenPinLocked" #define BUS_ERROR_TOKEN_PIN_LOCKED "org.freedesktop.home1.TokenPinLocked"
#define BUS_ERROR_TOKEN_BAD_PIN "org.freedesktop.home1.BadPin" #define BUS_ERROR_TOKEN_BAD_PIN "org.freedesktop.home1.BadPin"

View File

@ -141,7 +141,7 @@ static int acquire_user_record(
if (!ur) if (!ur)
return pam_log_oom(handle); return pam_log_oom(handle);
r = user_record_load(ur, v, USER_RECORD_LOAD_REFUSE_SECRET); r = user_record_load(ur, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0) { if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to load user record: %s", strerror_safe(r)); pam_syslog(handle, LOG_ERR, "Failed to load user record: %s", strerror_safe(r));
return PAM_SERVICE_ERR; return PAM_SERVICE_ERR;

View File

@ -377,14 +377,16 @@ int bind_user_setup(
USER_RECORD_STRIP_PRIVILEGED| USER_RECORD_STRIP_PRIVILEGED|
USER_RECORD_ALLOW_PER_MACHINE| USER_RECORD_ALLOW_PER_MACHINE|
USER_RECORD_ALLOW_BINDING| USER_RECORD_ALLOW_BINDING|
USER_RECORD_ALLOW_SIGNATURE; USER_RECORD_ALLOW_SIGNATURE|
USER_RECORD_PERMISSIVE;
static const UserRecordLoadFlags shadow_flags = /* Extracts privileged info */ static const UserRecordLoadFlags shadow_flags = /* Extracts privileged info */
USER_RECORD_STRIP_REGULAR| USER_RECORD_STRIP_REGULAR|
USER_RECORD_ALLOW_PRIVILEGED| USER_RECORD_ALLOW_PRIVILEGED|
USER_RECORD_STRIP_PER_MACHINE| USER_RECORD_STRIP_PER_MACHINE|
USER_RECORD_STRIP_BINDING| USER_RECORD_STRIP_BINDING|
USER_RECORD_STRIP_SIGNATURE| USER_RECORD_STRIP_SIGNATURE|
USER_RECORD_EMPTY_OK; USER_RECORD_EMPTY_OK|
USER_RECORD_PERMISSIVE;
int r; int r;
assert(root); assert(root);

View File

@ -107,7 +107,7 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa
assert(keyname); assert(keyname);
if (!(flags & ASK_PASSWORD_PUSH_CACHE)) if (!FLAGS_SET(flags, ASK_PASSWORD_PUSH_CACHE))
return 0; return 0;
if (strv_isempty(passwords)) if (strv_isempty(passwords))
return 0; return 0;
@ -165,7 +165,7 @@ static int ask_password_keyring(const char *keyname, AskPasswordFlags flags, cha
assert(keyname); assert(keyname);
assert(ret); assert(ret);
if (!(flags & ASK_PASSWORD_ACCEPT_CACHED)) if (!FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED))
return -EUNATCH; return -EUNATCH;
r = lookup_key(keyname, &serial); r = lookup_key(keyname, &serial);
@ -258,7 +258,7 @@ int ask_password_plymouth(
if (r < 0) if (r < 0)
return -errno; return -errno;
if (flags & ASK_PASSWORD_ACCEPT_CACHED) { if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED)) {
packet = strdup("c"); packet = strdup("c");
n = 1; n = 1;
} else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) } else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
@ -320,7 +320,7 @@ int ask_password_plymouth(
if (buffer[0] == 5) { if (buffer[0] == 5) {
if (flags & ASK_PASSWORD_ACCEPT_CACHED) { if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED)) {
/* Hmm, first try with cached /* Hmm, first try with cached
* passwords failed, so let's retry * passwords failed, so let's retry
* with a normal password request */ * with a normal password request */
@ -415,16 +415,16 @@ int ask_password_tty(
assert(ret); assert(ret);
if (flags & ASK_PASSWORD_NO_TTY) if (FLAGS_SET(flags, ASK_PASSWORD_NO_TTY))
return -EUNATCH; return -EUNATCH;
if (!message) if (!message)
message = "Password:"; message = "Password:";
if (emoji_enabled()) if (!FLAGS_SET(flags, ASK_PASSWORD_HIDE_EMOJI) && emoji_enabled())
message = strjoina(special_glyph(SPECIAL_GLYPH_LOCK_AND_KEY), " ", message); message = strjoina(special_glyph(SPECIAL_GLYPH_LOCK_AND_KEY), " ", message);
if (flag_file || ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname)) { if (flag_file || (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && keyname)) {
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK); notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
if (notify < 0) if (notify < 0)
return -errno; return -errno;
@ -433,7 +433,7 @@ int ask_password_tty(
if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0)
return -errno; return -errno;
} }
if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) { if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
r = ask_password_keyring(keyname, flags, ret); r = ask_password_keyring(keyname, flags, ret);
if (r >= 0) if (r >= 0)
return 0; return 0;
@ -452,7 +452,7 @@ int ask_password_tty(
if (tcgetattr(ttyfd, &old_termios) < 0) if (tcgetattr(ttyfd, &old_termios) < 0)
return -errno; return -errno;
if (flags & ASK_PASSWORD_CONSOLE_COLOR) if (FLAGS_SET(flags, ASK_PASSWORD_CONSOLE_COLOR))
use_color = dev_console_colors_enabled(); use_color = dev_console_colors_enabled();
else else
use_color = colors_enabled(); use_color = colors_enabled();
@ -463,7 +463,7 @@ int ask_password_tty(
(void) loop_write(ttyfd, message, strlen(message), false); (void) loop_write(ttyfd, message, strlen(message), false);
(void) loop_write(ttyfd, " ", 1, false); (void) loop_write(ttyfd, " ", 1, false);
if (!(flags & ASK_PASSWORD_SILENT) && !(flags & ASK_PASSWORD_ECHO)) { if (!FLAGS_SET(flags, ASK_PASSWORD_SILENT) && !FLAGS_SET(flags, ASK_PASSWORD_ECHO)) {
if (use_color) if (use_color)
(void) loop_write(ttyfd, ansi_grey(), strlen(ansi_grey()), false); (void) loop_write(ttyfd, ansi_grey(), strlen(ansi_grey()), false);
(void) loop_write(ttyfd, PRESS_TAB, strlen(PRESS_TAB), false); (void) loop_write(ttyfd, PRESS_TAB, strlen(PRESS_TAB), false);
@ -564,7 +564,7 @@ int ask_password_tty(
if (c == 21) { /* C-u */ if (c == 21) { /* C-u */
if (!(flags & ASK_PASSWORD_SILENT)) if (!FLAGS_SET(flags, ASK_PASSWORD_SILENT))
(void) backspace_string(ttyfd, passphrase); (void) backspace_string(ttyfd, passphrase);
explicit_bzero_safe(passphrase, sizeof(passphrase)); explicit_bzero_safe(passphrase, sizeof(passphrase));
@ -575,7 +575,7 @@ int ask_password_tty(
if (p > 0) { if (p > 0) {
size_t q; size_t q;
if (!(flags & ASK_PASSWORD_SILENT)) if (!FLAGS_SET(flags, ASK_PASSWORD_SILENT))
(void) backspace_chars(ttyfd, 1); (void) backspace_chars(ttyfd, 1);
/* Remove a full UTF-8 codepoint from the end. For that, figure out where the /* Remove a full UTF-8 codepoint from the end. For that, figure out where the
@ -599,7 +599,7 @@ int ask_password_tty(
p = codepoint = q == SIZE_MAX ? p - 1 : q; p = codepoint = q == SIZE_MAX ? p - 1 : q;
explicit_bzero_safe(passphrase + p, sizeof(passphrase) - p); explicit_bzero_safe(passphrase + p, sizeof(passphrase) - p);
} else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) { } else if (!dirty && !FLAGS_SET(flags, ASK_PASSWORD_SILENT)) {
flags |= ASK_PASSWORD_SILENT; flags |= ASK_PASSWORD_SILENT;
@ -612,7 +612,7 @@ int ask_password_tty(
} else if (ttyfd >= 0) } else if (ttyfd >= 0)
(void) loop_write(ttyfd, "\a", 1, false); (void) loop_write(ttyfd, "\a", 1, false);
} else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) { } else if (c == '\t' && !FLAGS_SET(flags, ASK_PASSWORD_SILENT)) {
(void) backspace_string(ttyfd, passphrase); (void) backspace_string(ttyfd, passphrase);
flags |= ASK_PASSWORD_SILENT; flags |= ASK_PASSWORD_SILENT;
@ -631,11 +631,11 @@ int ask_password_tty(
} else { } else {
passphrase[p++] = c; passphrase[p++] = c;
if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) { if (!FLAGS_SET(flags, ASK_PASSWORD_SILENT) && ttyfd >= 0) {
/* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */ /* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */
n = utf8_encoded_valid_unichar(passphrase + codepoint, SIZE_MAX); n = utf8_encoded_valid_unichar(passphrase + codepoint, SIZE_MAX);
if (n >= 0) { if (n >= 0) {
if (flags & ASK_PASSWORD_ECHO) if (FLAGS_SET(flags, ASK_PASSWORD_ECHO))
(void) loop_write(ttyfd, passphrase + codepoint, n, false); (void) loop_write(ttyfd, passphrase + codepoint, n, false);
else else
(void) loop_write(ttyfd, "*", 1, false); (void) loop_write(ttyfd, "*", 1, false);
@ -739,7 +739,7 @@ int ask_password_agent(
assert(ret); assert(ret);
if (flags & ASK_PASSWORD_NO_AGENT) if (FLAGS_SET(flags, ASK_PASSWORD_NO_AGENT))
return -EUNATCH; return -EUNATCH;
assert_se(sigemptyset(&mask) >= 0); assert_se(sigemptyset(&mask) >= 0);
@ -748,7 +748,7 @@ int ask_password_agent(
(void) mkdir_p_label("/run/systemd/ask-password", 0755); (void) mkdir_p_label("/run/systemd/ask-password", 0755);
if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) { if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
r = ask_password_keyring(keyname, flags, ret); r = ask_password_keyring(keyname, flags, ret);
if (r >= 0) { if (r >= 0) {
r = 0; r = 0;
@ -803,10 +803,10 @@ int ask_password_agent(
"Silent=%i\n", "Silent=%i\n",
getpid_cached(), getpid_cached(),
socket_name, socket_name,
(flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0, FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED),
(flags & ASK_PASSWORD_ECHO) ? 1 : 0, FLAGS_SET(flags, ASK_PASSWORD_ECHO),
until, until,
(flags & ASK_PASSWORD_SILENT) ? 1 : 0); FLAGS_SET(flags, ASK_PASSWORD_SILENT));
if (message) if (message)
fprintf(f, "Message=%s\n", message); fprintf(f, "Message=%s\n", message);
@ -1009,25 +1009,25 @@ int ask_password_auto(
assert(ret); assert(ret);
if (!(flags & ASK_PASSWORD_NO_CREDENTIAL) && credential_name) { if (!FLAGS_SET(flags, ASK_PASSWORD_NO_CREDENTIAL) && credential_name) {
r = ask_password_credential(credential_name, flags, ret); r = ask_password_credential(credential_name, flags, ret);
if (r != -ENOKEY) if (r != -ENOKEY)
return r; return r;
} }
if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) &&
key_name && key_name &&
((flags & ASK_PASSWORD_NO_TTY) || !isatty(STDIN_FILENO)) && (FLAGS_SET(flags, ASK_PASSWORD_NO_TTY) || !isatty(STDIN_FILENO)) &&
(flags & ASK_PASSWORD_NO_AGENT)) { FLAGS_SET(flags, ASK_PASSWORD_NO_AGENT)) {
r = ask_password_keyring(key_name, flags, ret); r = ask_password_keyring(key_name, flags, ret);
if (r != -ENOKEY) if (r != -ENOKEY)
return r; return r;
} }
if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) if (!FLAGS_SET(flags, ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO))
return ask_password_tty(-1, message, key_name, until, flags, NULL, ret); return ask_password_tty(-1, message, key_name, until, flags, NULL, ret);
if (!(flags & ASK_PASSWORD_NO_AGENT)) if (!FLAGS_SET(flags, ASK_PASSWORD_NO_AGENT))
return ask_password_agent(message, icon, id, key_name, until, flags, ret); return ask_password_agent(message, icon, id, key_name, until, flags, ret);
return -EUNATCH; return -EUNATCH;

View File

@ -14,6 +14,7 @@ typedef enum AskPasswordFlags {
ASK_PASSWORD_NO_AGENT = 1 << 5, /* never ask for password via agent */ ASK_PASSWORD_NO_AGENT = 1 << 5, /* never ask for password via agent */
ASK_PASSWORD_CONSOLE_COLOR = 1 << 6, /* Use color if /dev/console points to a console that supports color */ ASK_PASSWORD_CONSOLE_COLOR = 1 << 6, /* Use color if /dev/console points to a console that supports color */
ASK_PASSWORD_NO_CREDENTIAL = 1 << 7, /* never use $CREDENTIALS_DIRECTORY data */ ASK_PASSWORD_NO_CREDENTIAL = 1 << 7, /* never use $CREDENTIALS_DIRECTORY data */
ASK_PASSWORD_HIDE_EMOJI = 1 << 8, /* hide the lock and key emoji */
} AskPasswordFlags; } AskPasswordFlags;
int ask_password_tty(int tty_fd, const char *message, const char *key_name, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret); int ask_password_tty(int tty_fd, const char *message, const char *key_name, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret);

View File

@ -17,23 +17,38 @@ int (*sym_crypt_activate_by_volume_key)(struct crypt_device *cd, const char *nam
int (*sym_crypt_deactivate_by_name)(struct crypt_device *cd, const char *name, uint32_t flags); int (*sym_crypt_deactivate_by_name)(struct crypt_device *cd, const char *name, uint32_t flags);
int (*sym_crypt_format)(struct crypt_device *cd, const char *type, const char *cipher, const char *cipher_mode, const char *uuid, const char *volume_key, size_t volume_key_size, void *params); int (*sym_crypt_format)(struct crypt_device *cd, const char *type, const char *cipher, const char *cipher_mode, const char *uuid, const char *volume_key, size_t volume_key_size, void *params);
void (*sym_crypt_free)(struct crypt_device *cd); void (*sym_crypt_free)(struct crypt_device *cd);
const char *(*sym_crypt_get_cipher)(struct crypt_device *cd);
const char *(*sym_crypt_get_cipher_mode)(struct crypt_device *cd);
uint64_t (*sym_crypt_get_data_offset)(struct crypt_device *cd);
const char *(*sym_crypt_get_device_name)(struct crypt_device *cd);
const char *(*sym_crypt_get_dir)(void); const char *(*sym_crypt_get_dir)(void);
const char *(*sym_crypt_get_type)(struct crypt_device *cd);
const char *(*sym_crypt_get_uuid)(struct crypt_device *cd);
int (*sym_crypt_get_verity_info)(struct crypt_device *cd, struct crypt_params_verity *vp); int (*sym_crypt_get_verity_info)(struct crypt_device *cd, struct crypt_params_verity *vp);
int (*sym_crypt_get_volume_key_size)(struct crypt_device *cd);
int (*sym_crypt_init)(struct crypt_device **cd, const char *device); int (*sym_crypt_init)(struct crypt_device **cd, const char *device);
int (*sym_crypt_init_by_name)(struct crypt_device **cd, const char *name); int (*sym_crypt_init_by_name)(struct crypt_device **cd, const char *name);
int (*sym_crypt_keyslot_add_by_volume_key)(struct crypt_device *cd, int keyslot, const char *volume_key, size_t volume_key_size, const char *passphrase, size_t passphrase_size); int (*sym_crypt_keyslot_add_by_volume_key)(struct crypt_device *cd, int keyslot, const char *volume_key, size_t volume_key_size, const char *passphrase, size_t passphrase_size);
int (*sym_crypt_keyslot_destroy)(struct crypt_device *cd, int keyslot);
int (*sym_crypt_keyslot_max)(const char *type);
int (*sym_crypt_load)(struct crypt_device *cd, const char *requested_type, void *params); int (*sym_crypt_load)(struct crypt_device *cd, const char *requested_type, void *params);
int (*sym_crypt_resize)(struct crypt_device *cd, const char *name, uint64_t new_size); int (*sym_crypt_resize)(struct crypt_device *cd, const char *name, uint64_t new_size);
int (*sym_crypt_resume_by_passphrase)(struct crypt_device *cd, const char *name, int keyslot, const char *passphrase, size_t passphrase_size);
int (*sym_crypt_set_data_device)(struct crypt_device *cd, const char *device); int (*sym_crypt_set_data_device)(struct crypt_device *cd, const char *device);
void (*sym_crypt_set_debug_level)(int level); void (*sym_crypt_set_debug_level)(int level);
void (*sym_crypt_set_log_callback)(struct crypt_device *cd, void (*log)(int level, const char *msg, void *usrptr), void *usrptr); void (*sym_crypt_set_log_callback)(struct crypt_device *cd, void (*log)(int level, const char *msg, void *usrptr), void *usrptr);
int (*sym_crypt_set_pbkdf_type)(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf) = NULL; #if HAVE_CRYPT_SET_METADATA_SIZE
int (*sym_crypt_token_json_get)(struct crypt_device *cd, int token, const char **json) = NULL; int (*sym_crypt_set_metadata_size)(struct crypt_device *cd, uint64_t metadata_size, uint64_t keyslots_size);
int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const char *json) = NULL; #endif
int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size); int (*sym_crypt_set_pbkdf_type)(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf);
int (*sym_crypt_suspend)(struct crypt_device *cd, const char *name);
int (*sym_crypt_token_json_get)(struct crypt_device *cd, int token, const char **json);
int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const char *json);
#if HAVE_CRYPT_TOKEN_MAX #if HAVE_CRYPT_TOKEN_MAX
int (*sym_crypt_token_max)(const char *type); int (*sym_crypt_token_max)(const char *type);
#endif #endif
crypt_token_info (*sym_crypt_token_status)(struct crypt_device *cd, int token, const char **type);
int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
int dlopen_cryptsetup(void) { int dlopen_cryptsetup(void) {
_cleanup_(dlclosep) void *dl = NULL; _cleanup_(dlclosep) void *dl = NULL;
@ -58,23 +73,38 @@ int dlopen_cryptsetup(void) {
DLSYM_ARG(crypt_deactivate_by_name), DLSYM_ARG(crypt_deactivate_by_name),
DLSYM_ARG(crypt_format), DLSYM_ARG(crypt_format),
DLSYM_ARG(crypt_free), DLSYM_ARG(crypt_free),
DLSYM_ARG(crypt_get_cipher),
DLSYM_ARG(crypt_get_cipher_mode),
DLSYM_ARG(crypt_get_data_offset),
DLSYM_ARG(crypt_get_device_name),
DLSYM_ARG(crypt_get_dir), DLSYM_ARG(crypt_get_dir),
DLSYM_ARG(crypt_get_type),
DLSYM_ARG(crypt_get_uuid),
DLSYM_ARG(crypt_get_verity_info), DLSYM_ARG(crypt_get_verity_info),
DLSYM_ARG(crypt_get_volume_key_size),
DLSYM_ARG(crypt_init), DLSYM_ARG(crypt_init),
DLSYM_ARG(crypt_init_by_name), DLSYM_ARG(crypt_init_by_name),
DLSYM_ARG(crypt_keyslot_add_by_volume_key), DLSYM_ARG(crypt_keyslot_add_by_volume_key),
DLSYM_ARG(crypt_keyslot_destroy),
DLSYM_ARG(crypt_keyslot_max),
DLSYM_ARG(crypt_load), DLSYM_ARG(crypt_load),
DLSYM_ARG(crypt_resize), DLSYM_ARG(crypt_resize),
DLSYM_ARG(crypt_resume_by_passphrase),
DLSYM_ARG(crypt_set_data_device), DLSYM_ARG(crypt_set_data_device),
DLSYM_ARG(crypt_set_debug_level), DLSYM_ARG(crypt_set_debug_level),
DLSYM_ARG(crypt_set_log_callback), DLSYM_ARG(crypt_set_log_callback),
#if HAVE_CRYPT_SET_METADATA_SIZE
DLSYM_ARG(crypt_set_metadata_size),
#endif
DLSYM_ARG(crypt_set_pbkdf_type), DLSYM_ARG(crypt_set_pbkdf_type),
DLSYM_ARG(crypt_suspend),
DLSYM_ARG(crypt_token_json_get), DLSYM_ARG(crypt_token_json_get),
DLSYM_ARG(crypt_token_json_set), DLSYM_ARG(crypt_token_json_set),
DLSYM_ARG(crypt_volume_key_get),
#if HAVE_CRYPT_TOKEN_MAX #if HAVE_CRYPT_TOKEN_MAX
DLSYM_ARG(crypt_token_max), DLSYM_ARG(crypt_token_max),
#endif #endif
DLSYM_ARG(crypt_token_status),
DLSYM_ARG(crypt_volume_key_get),
NULL); NULL);
if (r < 0) if (r < 0)
return r; return r;
@ -82,6 +112,13 @@ int dlopen_cryptsetup(void) {
/* Note that we never release the reference here, because there's no real reason to, after all this /* Note that we never release the reference here, because there's no real reason to, after all this
* was traditionally a regular shared library dependency which lives forever too. */ * was traditionally a regular shared library dependency which lives forever too. */
cryptsetup_dl = TAKE_PTR(dl); cryptsetup_dl = TAKE_PTR(dl);
/* Redirect the default logging calls of libcryptsetup to our own logging infra. (Note that
* libcryptsetup also maintains per-"struct crypt_device" log functions, which we'll also set
* whenever allocating a "struct crypt_device" context. Why set both? To be defensive: maybe some
* other code loaded into this process also changes the global log functions of libcryptsetup, who
* knows? And if so, we still want our own objects to log via our own infra, at the very least.) */
cryptsetup_enable_logging(NULL);
return 1; return 1;
} }
@ -109,13 +146,17 @@ static void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
} }
void cryptsetup_enable_logging(struct crypt_device *cd) { void cryptsetup_enable_logging(struct crypt_device *cd) {
if (!cd) /* It's OK to call this with a NULL parameter, in which case libcryptsetup will set the defaut log
return; * function.
*
* Note that this is also called from dlopen_cryptsetup(), which we call here too. Sounds like an
* endless loop, but isn't because we break it via the check for 'cryptsetup_dl' early in
* dlopen_cryptsetup(). */
if (dlopen_cryptsetup() < 0) /* If this fails, let's gracefully ignore the issue, this is just debug if (dlopen_cryptsetup() < 0)
* logging after all, and if this failed we already generated a debug return; /* If this fails, let's gracefully ignore the issue, this is just debug logging after
* log message that should help to track things down. */ * all, and if this failed we already generated a debug log message that should help
return; * to track things down. */
sym_crypt_set_log_callback(cd, cryptsetup_log_glue, NULL); sym_crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
sym_crypt_set_debug_level(DEBUG_LOGGING ? CRYPT_DEBUG_ALL : CRYPT_DEBUG_NONE); sym_crypt_set_debug_level(DEBUG_LOGGING ? CRYPT_DEBUG_ALL : CRYPT_DEBUG_NONE);
@ -123,11 +164,15 @@ void cryptsetup_enable_logging(struct crypt_device *cd) {
int cryptsetup_set_minimal_pbkdf(struct crypt_device *cd) { int cryptsetup_set_minimal_pbkdf(struct crypt_device *cd) {
/* With CRYPT_PBKDF_NO_BENCHMARK flag set .time_ms member is ignored
* while .iterations must be set at least to recommended minimum value. */
static const struct crypt_pbkdf_type minimal_pbkdf = { static const struct crypt_pbkdf_type minimal_pbkdf = {
.hash = "sha512", .hash = "sha512",
.type = CRYPT_KDF_PBKDF2, .type = CRYPT_KDF_PBKDF2,
.iterations = 1, .iterations = 1000, /* recommended minimum count for pbkdf2
.time_ms = 1, * according to NIST SP 800-132, ch. 5.2 */
.flags = CRYPT_PBKDF_NO_BENCHMARK
}; };
int r; int r;

View File

@ -23,20 +23,33 @@ extern int (*sym_crypt_activate_by_volume_key)(struct crypt_device *cd, const ch
extern int (*sym_crypt_deactivate_by_name)(struct crypt_device *cd, const char *name, uint32_t flags); extern int (*sym_crypt_deactivate_by_name)(struct crypt_device *cd, const char *name, uint32_t flags);
extern int (*sym_crypt_format)(struct crypt_device *cd, const char *type, const char *cipher, const char *cipher_mode, const char *uuid, const char *volume_key, size_t volume_key_size, void *params); extern int (*sym_crypt_format)(struct crypt_device *cd, const char *type, const char *cipher, const char *cipher_mode, const char *uuid, const char *volume_key, size_t volume_key_size, void *params);
extern void (*sym_crypt_free)(struct crypt_device *cd); extern void (*sym_crypt_free)(struct crypt_device *cd);
extern const char *(*sym_crypt_get_cipher)(struct crypt_device *cd);
extern const char *(*sym_crypt_get_cipher_mode)(struct crypt_device *cd);
extern uint64_t (*sym_crypt_get_data_offset)(struct crypt_device *cd);
extern const char *(*sym_crypt_get_device_name)(struct crypt_device *cd);
extern const char *(*sym_crypt_get_dir)(void); extern const char *(*sym_crypt_get_dir)(void);
extern const char *(*sym_crypt_get_type)(struct crypt_device *cd);
extern const char *(*sym_crypt_get_uuid)(struct crypt_device *cd);
extern int (*sym_crypt_get_verity_info)(struct crypt_device *cd, struct crypt_params_verity *vp); extern int (*sym_crypt_get_verity_info)(struct crypt_device *cd, struct crypt_params_verity *vp);
extern int (*sym_crypt_get_volume_key_size)(struct crypt_device *cd);
extern int (*sym_crypt_init)(struct crypt_device **cd, const char *device); extern int (*sym_crypt_init)(struct crypt_device **cd, const char *device);
extern int (*sym_crypt_init_by_name)(struct crypt_device **cd, const char *name); extern int (*sym_crypt_init_by_name)(struct crypt_device **cd, const char *name);
extern int (*sym_crypt_keyslot_add_by_volume_key)(struct crypt_device *cd, int keyslot, const char *volume_key, size_t volume_key_size, const char *passphrase, size_t passphrase_size); extern int (*sym_crypt_keyslot_add_by_volume_key)(struct crypt_device *cd, int keyslot, const char *volume_key, size_t volume_key_size, const char *passphrase, size_t passphrase_size);
extern int (*sym_crypt_keyslot_destroy)(struct crypt_device *cd, int keyslot);
extern int (*sym_crypt_keyslot_max)(const char *type);
extern int (*sym_crypt_load)(struct crypt_device *cd, const char *requested_type, void *params); extern int (*sym_crypt_load)(struct crypt_device *cd, const char *requested_type, void *params);
extern int (*sym_crypt_resize)(struct crypt_device *cd, const char *name, uint64_t new_size); extern int (*sym_crypt_resize)(struct crypt_device *cd, const char *name, uint64_t new_size);
extern int (*sym_crypt_resume_by_passphrase)(struct crypt_device *cd, const char *name, int keyslot, const char *passphrase, size_t passphrase_size);
extern int (*sym_crypt_set_data_device)(struct crypt_device *cd, const char *device); extern int (*sym_crypt_set_data_device)(struct crypt_device *cd, const char *device);
extern void (*sym_crypt_set_debug_level)(int level); extern void (*sym_crypt_set_debug_level)(int level);
extern void (*sym_crypt_set_log_callback)(struct crypt_device *cd, void (*log)(int level, const char *msg, void *usrptr), void *usrptr); extern void (*sym_crypt_set_log_callback)(struct crypt_device *cd, void (*log)(int level, const char *msg, void *usrptr), void *usrptr);
#if HAVE_CRYPT_SET_METADATA_SIZE
extern int (*sym_crypt_set_metadata_size)(struct crypt_device *cd, uint64_t metadata_size, uint64_t keyslots_size);
#endif
extern int (*sym_crypt_set_pbkdf_type)(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf); extern int (*sym_crypt_set_pbkdf_type)(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf);
extern int (*sym_crypt_suspend)(struct crypt_device *cd, const char *name);
extern int (*sym_crypt_token_json_get)(struct crypt_device *cd, int token, const char **json); extern int (*sym_crypt_token_json_get)(struct crypt_device *cd, int token, const char **json);
extern int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const char *json); extern int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const char *json);
extern int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
#if HAVE_CRYPT_TOKEN_MAX #if HAVE_CRYPT_TOKEN_MAX
extern int (*sym_crypt_token_max)(const char *type); extern int (*sym_crypt_token_max)(const char *type);
#else #else
@ -47,6 +60,8 @@ static inline int sym_crypt_token_max(_unused_ const char *type) {
return 32; return 32;
} }
#endif #endif
extern crypt_token_info (*sym_crypt_token_status)(struct crypt_device *cd, int token, const char **type);
extern int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
int dlopen_cryptsetup(void); int dlopen_cryptsetup(void);

View File

@ -1926,6 +1926,8 @@ static int verity_can_reuse(
if (r < 0) if (r < 0)
return log_debug_errno(r, "Error opening verity device, crypt_init_by_name failed: %m"); return log_debug_errno(r, "Error opening verity device, crypt_init_by_name failed: %m");
cryptsetup_enable_logging(cd);
r = sym_crypt_get_verity_info(cd, &crypt_params); r = sym_crypt_get_verity_info(cd, &crypt_params);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Error opening verity device, crypt_get_verity_info failed: %m"); return log_debug_errno(r, "Error opening verity device, crypt_get_verity_info failed: %m");

View File

@ -200,6 +200,7 @@ UserRecord* user_record_new(void) {
.password_change_now = -1, .password_change_now = -1,
.pkcs11_protected_authentication_path_permitted = -1, .pkcs11_protected_authentication_path_permitted = -1,
.fido2_user_presence_permitted = -1, .fido2_user_presence_permitted = -1,
.fido2_user_verification_permitted = -1,
}; };
return h; return h;
@ -774,6 +775,7 @@ static int dispatch_secret(const char *name, JsonVariant *variant, JsonDispatchF
{ "pkcs11Pin", /* legacy alias */ _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, token_pin), 0 }, { "pkcs11Pin", /* legacy alias */ _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, token_pin), 0 },
{ "pkcs11ProtectedAuthenticationPathPermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, pkcs11_protected_authentication_path_permitted), 0 }, { "pkcs11ProtectedAuthenticationPathPermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, pkcs11_protected_authentication_path_permitted), 0 },
{ "fido2UserPresencePermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, fido2_user_presence_permitted), 0 }, { "fido2UserPresencePermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, fido2_user_presence_permitted), 0 },
{ "fido2UserVerificationPermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, fido2_user_verification_permitted), 0 },
{}, {},
}; };
@ -1016,9 +1018,12 @@ static int dispatch_fido2_hmac_salt(const char *name, JsonVariant *variant, Json
Fido2HmacSalt *array, *k; Fido2HmacSalt *array, *k;
static const JsonDispatch fido2_hmac_salt_dispatch_table[] = { static const JsonDispatch fido2_hmac_salt_dispatch_table[] = {
{ "credential", JSON_VARIANT_STRING, dispatch_fido2_hmac_credential, offsetof(Fido2HmacSalt, credential), JSON_MANDATORY }, { "credential", JSON_VARIANT_STRING, dispatch_fido2_hmac_credential, offsetof(Fido2HmacSalt, credential), JSON_MANDATORY },
{ "salt", JSON_VARIANT_STRING, dispatch_fido2_hmac_salt_value, 0, JSON_MANDATORY }, { "salt", JSON_VARIANT_STRING, dispatch_fido2_hmac_salt_value, 0, JSON_MANDATORY },
{ "hashedPassword", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Fido2HmacSalt, hashed_password), JSON_MANDATORY }, { "hashedPassword", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Fido2HmacSalt, hashed_password), JSON_MANDATORY },
{ "up", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(Fido2HmacSalt, up), 0 },
{ "uv", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(Fido2HmacSalt, uv), 0 },
{ "clientPin", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(Fido2HmacSalt, client_pin), 0 },
{}, {},
}; };
@ -1031,7 +1036,11 @@ static int dispatch_fido2_hmac_salt(const char *name, JsonVariant *variant, Json
h->fido2_hmac_salt = array; h->fido2_hmac_salt = array;
k = h->fido2_hmac_salt + h->n_fido2_hmac_salt; k = h->fido2_hmac_salt + h->n_fido2_hmac_salt;
*k = (Fido2HmacSalt) {}; *k = (Fido2HmacSalt) {
.uv = -1,
.up = -1,
.client_pin = -1,
};
r = json_dispatch(e, fido2_hmac_salt_dispatch_table, NULL, flags, k); r = json_dispatch(e, fido2_hmac_salt_dispatch_table, NULL, flags, k);
if (r < 0) { if (r < 0) {
@ -2105,7 +2114,7 @@ int user_record_masked_equal(UserRecord *a, UserRecord *b, UserRecordMask mask)
/* Compares the two records, but ignores anything not listed in the specified mask */ /* Compares the two records, but ignores anything not listed in the specified mask */
if ((a->mask & ~mask) != 0) { if ((a->mask & ~mask) != 0) {
r = user_record_clone(a, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX), &x); r = user_record_clone(a, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX) | USER_RECORD_PERMISSIVE, &x);
if (r < 0) if (r < 0)
return r; return r;
@ -2113,7 +2122,7 @@ int user_record_masked_equal(UserRecord *a, UserRecord *b, UserRecordMask mask)
} }
if ((b->mask & ~mask) != 0) { if ((b->mask & ~mask) != 0) {
r = user_record_clone(b, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX), &y); r = user_record_clone(b, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX) | USER_RECORD_PERMISSIVE, &y);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -236,6 +236,9 @@ typedef struct Fido2HmacSalt {
/* What to test the hashed salt value against, usually UNIX password hash here. */ /* What to test the hashed salt value against, usually UNIX password hash here. */
char *hashed_password; char *hashed_password;
/* Whether the 'up', 'uv', 'clientPin' features are enabled. */
int uv, up, client_pin;
} Fido2HmacSalt; } Fido2HmacSalt;
typedef struct RecoveryKey { typedef struct RecoveryKey {
@ -371,6 +374,7 @@ typedef struct UserRecord {
Fido2HmacSalt *fido2_hmac_salt; Fido2HmacSalt *fido2_hmac_salt;
size_t n_fido2_hmac_salt; size_t n_fido2_hmac_salt;
int fido2_user_presence_permitted; int fido2_user_presence_permitted;
int fido2_user_verification_permitted;
char **recovery_key_type; char **recovery_key_type;
RecoveryKey *recovery_key; RecoveryKey *recovery_key;

View File

@ -82,7 +82,8 @@ static int load_user(
USER_RECORD_ALLOW_PER_MACHINE| USER_RECORD_ALLOW_PER_MACHINE|
USER_RECORD_ALLOW_BINDING| USER_RECORD_ALLOW_BINDING|
USER_RECORD_ALLOW_SIGNATURE| USER_RECORD_ALLOW_SIGNATURE|
(have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0)); (have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0)|
USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return r; return r;
@ -225,7 +226,8 @@ static int load_group(
USER_RECORD_ALLOW_PER_MACHINE| USER_RECORD_ALLOW_PER_MACHINE|
USER_RECORD_ALLOW_BINDING| USER_RECORD_ALLOW_BINDING|
USER_RECORD_ALLOW_SIGNATURE| USER_RECORD_ALLOW_SIGNATURE|
(have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0)); (have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0)|
USER_RECORD_PERMISSIVE);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -88,7 +88,7 @@ static int build_user_json(Varlink *link, UserRecord *ur, JsonVariant **ret) {
} else } else
trusted = peer_uid == 0 || peer_uid == ur->uid; trusted = peer_uid == 0 || peer_uid == ur->uid;
flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE; flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE;
if (trusted) if (trusted)
flags |= USER_RECORD_ALLOW_PRIVILEGED; flags |= USER_RECORD_ALLOW_PRIVILEGED;
else else
@ -232,7 +232,7 @@ static int build_group_json(Varlink *link, GroupRecord *gr, JsonVariant **ret) {
} else } else
trusted = peer_uid == 0; trusted = peer_uid == 0;
flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE; flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE;
if (trusted) if (trusted)
flags |= USER_RECORD_ALLOW_PRIVILEGED; flags |= USER_RECORD_ALLOW_PRIVILEGED;
else else

View File

@ -138,6 +138,8 @@ static int run(int argc, char *argv[]) {
log_setup(); log_setup();
cryptsetup_enable_logging(NULL);
umask(0022); umask(0022);
if (streq(argv[1], "attach")) { if (streq(argv[1], "attach")) {