]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #19768 from poettering/homectl-fido2-lock-with
authorLennart Poettering <lennart@poettering.net>
Tue, 1 Jun 2021 13:53:36 +0000 (15:53 +0200)
committerGitHub <noreply@github.com>
Tue, 1 Jun 2021 13:53:36 +0000 (15:53 +0200)
homed: catch up with FIDO2 features in cryptsetup + other fixes

37 files changed:
docs/USER_RECORD.md
man/homectl.xml
meson.build
src/cryptenroll/cryptenroll.c
src/cryptsetup/cryptsetup.c
src/home/homectl-fido2.c
src/home/homectl-fido2.h
src/home/homectl.c
src/home/homed-bus.c
src/home/homed-home-bus.c
src/home/homed-home.c
src/home/homed-manager-bus.c
src/home/homed-manager.c
src/home/homed-varlink.c
src/home/homework-cifs.c
src/home/homework-directory.c
src/home/homework-fido2.c
src/home/homework-fscrypt.c
src/home/homework-luks.c
src/home/homework-luks.h
src/home/homework.c
src/home/pam_systemd_home.c
src/home/user-record-sign.c
src/home/user-record-util.c
src/home/user-record-util.h
src/libsystemd/sd-bus/bus-common-errors.c
src/libsystemd/sd-bus/bus-common-errors.h
src/login/pam_systemd.c
src/nspawn/nspawn-bind-user.c
src/shared/cryptsetup-util.c
src/shared/cryptsetup-util.h
src/shared/dissect-image.c
src/shared/user-record.c
src/shared/user-record.h
src/shared/userdb-dropin.c
src/userdb/userwork.c
src/veritysetup/veritysetup.c

index 6435d2cf5f5f1a6b9a543f9e89293701b2b49370..11ab31b93319ea738b00f9d820ecbd58300cdcfe 100644 (file)
@@ -628,18 +628,21 @@ user records.
 `fido2HmacSalt` → An array of objects, implementing authentication support with
 FIDO2 devices that implement the `hmac-secret` extension. Each element of the
 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
 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
 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
 `hashedPassword` field of the `fido2HmacSalt` field shall be a UNIX password
-hash to test this derived secret key against for authentication. It is
-generally recommended that for each 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.
+hash to test this derived secret key against for authentication. The `up`, `uv`
+and `clientPin` booleans map to the FIDO2 concepts of the same name and encode
+whether the `uv`/`up` options are enabled during the authentication, and
+whether a PIN shall be required. It is generally recommended that for each
+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
 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
 use the FIDO2 "user presence" flag. This is similar to the concept of
-`pkcs11ProtectedAuthenticationPathPermitted`, but exposes the FIDO2 concept
-behind it. If false or unset authentication this way shall not be attempted.
+`pkcs11ProtectedAuthenticationPathPermitted`, but exposes the FIDO2 "up"
+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`
 
index f2858166f7babdde64d67265d4bb9ed83ab532fc..4b0b120ca8c23ba7abc0c62b2cd4fec6cba2766f 100644 (file)
         discussion see above.</para></listitem>
       </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>
         <term><option>--recovery-key=</option><replaceable>BOOL</replaceable></term>
 
index 0ce978f8e529b15c550d3a5524853c3bdd2fb721..65d0a0f6eaaf71e5cc98402716bc898651c483e0 100644 (file)
@@ -2254,7 +2254,6 @@ if conf.get('ENABLE_HOMED') == 1
                 include_directories : includes,
                 link_with : [libshared],
                 dependencies : [threads,
-                                libcryptsetup,
                                 libblkid,
                                 libcrypt,
                                 libopenssl,
index 030296cc0252d5120024cdc924c1faa4a6e0260f..460e895a02ba771877171eb75816e89f986c541e 100644 (file)
@@ -510,6 +510,8 @@ static int run(int argc, char *argv[]) {
         if (r <= 0)
                 return r;
 
+        cryptsetup_enable_logging(NULL);
+
         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 */
         else
index 024909f7334b07f970b4358d2bc45b09c6f676f9..28ac78cd3783612bb1674998b2b206d775f29d01 100644 (file)
@@ -1449,7 +1449,7 @@ static int run(int argc, char *argv[]) {
 
         log_setup();
 
-        cryptsetup_enable_logging(cd);
+        cryptsetup_enable_logging(NULL);
 
         umask(0022);
 
index e8e9826bb9177ed1c97097380a566222114384b1..d0457d8e29f4b41651543b6f6649a190f88edb4d 100644 (file)
@@ -68,7 +68,8 @@ static int add_fido2_salt(
                 const void *fido2_salt,
                 size_t fido2_salt_size,
                 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_(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(
                                        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("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)
                 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(
                 JsonVariant **v,
-                const char *device) {
+                const char *device,
+                Fido2EnrollFlags lock_with) {
 
 #if HAVE_LIBFIDO2
         JsonVariant *un, *realm, *rn;
@@ -158,12 +164,12 @@ int identity_add_fido2_parameters(
                         /* user_display_name= */ rn ? json_variant_string(rn) : NULL,
                         /* user_icon_name= */ NULL,
                         /* askpw_icon_name= */ "user-home",
-                        FIDO2ENROLL_PIN | FIDO2ENROLL_UP, // FIXME: add a --lock-with-pin/up parameter like cryptenroll
+                        lock_with,
                         &cid, &cid_size,
                         &salt, &salt_size,
                         &secret, &secret_size,
                         &used_pin,
-                        NULL);
+                        &lock_with);
         if (r < 0)
                 return r;
 
@@ -181,7 +187,8 @@ int identity_add_fido2_parameters(
                         salt,
                         salt_size,
                         secret,
-                        secret_size);
+                        secret_size,
+                        lock_with);
         if (r < 0)
                 return r;
 
index 7b8d9f60acd10dda6f8e22d0921943a6ab4eb909..5087069c3c153580abd590ec45e76754bf75f199 100644 (file)
@@ -2,5 +2,6 @@
 #pragma once
 
 #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);
index 09d424734783f1ede7237666843c228b7b1daf75..6273cb6c90693bf09c57cdad0019d01590e08069 100644 (file)
@@ -57,6 +57,7 @@ static uint64_t arg_disk_size = UINT64_MAX;
 static uint64_t arg_disk_size_relative = UINT64_MAX;
 static char **arg_pkcs11_token_uri = NULL;
 static char **arg_fido2_device = NULL;
+static Fido2EnrollFlags arg_fido2_lock_with = FIDO2ENROLL_PIN | FIDO2ENROLL_UP;
 static bool arg_recovery_key = false;
 static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
 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)) {
 
-                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() ? " " : "");
 
@@ -388,6 +389,16 @@ static int handle_generic_user_record_error(
                 if (r < 0)
                         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))
                 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;
 
                 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)
-                        r = user_record_clone(hr, USER_RECORD_EXTRACT_SIGNABLE, &stripped);
+                        r = user_record_clone(hr, USER_RECORD_EXTRACT_SIGNABLE|USER_RECORD_PERMISSIVE, &stripped);
                 else
                         r = 0;
                 if (r < 0)
@@ -667,7 +678,7 @@ static int inspect_home(int argc, char *argv[], void *userdata) {
                 if (!hr)
                         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 (ret == 0)
                                 ret = r;
@@ -1027,7 +1038,7 @@ static int acquire_new_home_record(UserRecord **ret) {
         }
 
         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)
                         return r;
         }
@@ -1049,7 +1060,7 @@ static int acquire_new_home_record(UserRecord **ret) {
         if (!hr)
                 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)
                 return r;
 
@@ -1397,7 +1408,7 @@ static int acquire_updated_home_record(
         }
 
         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)
                         return r;
         }
@@ -1415,7 +1426,7 @@ static int acquire_updated_home_record(
         if (!hr)
                 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)
                 return r;
 
@@ -1440,6 +1451,10 @@ static int home_record_reset_human_interaction_permission(UserRecord *hr) {
         if (r < 0)
                 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;
 }
 
@@ -2071,6 +2086,15 @@ static int help(int argc, char *argv[], void *userdata) {
                "                              private key and matching X.509 certificate\n"
                "     --fido2-device=PATH      Path to FIDO2 hidraw device with hmac-secret\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"
                "\n%4$sAccount Management User Record Properties:%5$s\n"
                "     --locked=BOOL            Set locked account state\n"
@@ -2220,6 +2244,9 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_AUTO_LOGIN,
                 ARG_PKCS11_TOKEN_URI,
                 ARG_FIDO2_DEVICE,
+                ARG_FIDO2_WITH_PIN,
+                ARG_FIDO2_WITH_UP,
+                ARG_FIDO2_WITH_UV,
                 ARG_RECOVERY_KEY,
                 ARG_AND_RESIZE,
                 ARG_AND_CHANGE_PASSWORD,
@@ -2299,6 +2326,9 @@ static int parse_argv(int argc, char *argv[]) {
                 { "export-format",               required_argument, NULL, ARG_EXPORT_FORMAT               },
                 { "pkcs11-token-uri",            required_argument, NULL, ARG_PKCS11_TOKEN_URI            },
                 { "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                },
                 { "and-resize",                  required_argument, NULL, ARG_AND_RESIZE                  },
                 { "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));
                         } else
                                 r = strv_extend(&arg_fido2_device, optarg);
-
                         if (r < 0)
                                 return r;
 
@@ -3331,6 +3360,39 @@ static int parse_argv(int argc, char *argv[]) {
                         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: {
                         const char *p;
 
index 8f7a646d4a7efdaa548d175103280dffd3af2052..24b421a58c076aa6c28febb2248380117285ab4d 100644 (file)
@@ -28,7 +28,7 @@ int bus_message_read_secret(sd_bus_message *m, UserRecord **ret, sd_bus_error *e
         if (!hr)
                 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)
                 return r;
 
index 2a58ecbc1a84b3f5f950abb0dba7e5dcb0e35a6f..c71256d15e55b0ae48ab6ca36df7d3bd7b719e7d 100644 (file)
@@ -95,7 +95,7 @@ int bus_home_get_record_json(
                 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)
                 flags |= USER_RECORD_ALLOW_PRIVILEGED;
         else
@@ -443,7 +443,7 @@ int bus_home_method_update(
         assert(message);
         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)
                 return r;
 
index dc9a446c71474ffed9751607cb11e6daaa807fe1..39dd501a32e8b480ba3fa22025787ced9be37fb0 100644 (file)
@@ -145,7 +145,7 @@ int home_new(Manager *m, UserRecord *hr, const char *sysfs, Home **ret) {
                         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)
                 return r;
 
@@ -243,7 +243,7 @@ int home_set_record(Home *h, UserRecord *hr) {
                 if (!new_hr)
                         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)
                         return r;
 
@@ -384,7 +384,7 @@ static int home_parse_worker_stdout(int _fd, UserRecord **ret) {
         if (!hr)
                 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)
                 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:
                 return sd_bus_error_set(error, BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED, "Security token requires protected authentication path.");
         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:
                 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:
@@ -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.");
 
         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)
                         return r;
 
@@ -1443,7 +1445,7 @@ static int home_update_internal(
                 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)
                 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 */
                         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)
                         return r;
 
@@ -1626,7 +1628,7 @@ int home_passwd(Home *h,
         if (r < 0)
                 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)
                 return r;
 
index 8a06bb62bf76cae80bffee9b61028f0e73bfa071..7ac5b8d0fc7c3a9741dba95eab34866b6fb80b0a 100644 (file)
@@ -398,7 +398,7 @@ static int method_register_home(
         assert(message);
         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)
                 return r;
 
@@ -513,7 +513,7 @@ static int method_update_home(sd_bus_message *message, void *userdata, sd_bus_er
         assert(message);
         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)
                 return r;
 
index f8dfa272b93101099d202fc6dff6cca43afa5469..b25542638250ffdc32eeae062808b03db0f9cf88 100644 (file)
@@ -364,7 +364,7 @@ static int manager_add_home_by_record(
         if (!hr)
                 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)
                 return r;
 
index c42908349a54d61a592165ada596046d6a981fc1..96a6ea754e14e19607c8f4663e18151aadf1884e 100644 (file)
@@ -42,7 +42,7 @@ static int build_user_json(Home *h, bool trusted, JsonVariant **ret) {
         assert(h);
         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)
                 flags |= USER_RECORD_ALLOW_PRIVILEGED;
         else
index 2736095f939789839c40a16b336c9237b483ab46..2254eb59cd742b87c1485603299dba85a7e0d54c 100644 (file)
@@ -185,7 +185,7 @@ int home_create_cifs(UserRecord *h, UserRecord **ret_home) {
         if (r < 0)
                 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)
                 return log_error_errno(r, "Failed to clone record: %m");
 
index 2d800033ee65a12fc299c9e1c9819df480a79b15..b35d24c85a09e012b8c2a0dbdb08885d77ef6451 100644 (file)
@@ -158,7 +158,7 @@ int home_create_directory_or_subvolume(UserRecord *h, UserRecord **ret_home) {
         if (r < 0)
                 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)
                 return log_error_errno(r, "Failed to clone record: %m");
 
index 8811c00550df80f26531bfbad5eb2b2be3bbc0b6..23fda4a355af227354933d7351b331a8f437936d 100644 (file)
@@ -6,6 +6,7 @@
 #include "homework-fido2.h"
 #include "libfido2-util.h"
 #include "memory-util.h"
+#include "strv.h"
 
 int fido2_use_token(
                 UserRecord *h,
@@ -15,6 +16,7 @@ int fido2_use_token(
 
         _cleanup_(erase_and_freep) void *hmac = NULL;
         size_t hmac_size;
+        Fido2EnrollFlags flags = 0;
         int r;
 
         assert(h);
@@ -22,13 +24,42 @@ int fido2_use_token(
         assert(salt);
         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(
                         NULL,
                         "io.systemd.home",
                         salt->salt, salt->salt_size,
                         salt->credential.id, salt->credential.size,
                         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_size);
         if (r < 0)
index 037e4853fd349f1b9a98c532132681b2adf871e9..86dde4b78b0b730765a7b97fb6a27c3184d8aa01 100644 (file)
@@ -550,7 +550,7 @@ int home_create_fscrypt(
         if (r < 0)
                 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)
                 return log_error_errno(r, "Failed to clone record: %m");
 
index 543195914fb3632c7ddb603a6eeebf054cd9d58c..87c999b6e3031541cb35374b2aa43a792e78c719 100644 (file)
@@ -243,7 +243,7 @@ static int luks_try_passwords(
         STRV_FOREACH(pp, passwords) {
                 size_t vks = *volume_key_size;
 
-                r = crypt_volume_key_get(
+                r = sym_crypt_volume_key_get(
                                 cd,
                                 CRYPT_ANY_SLOT,
                                 volume_key,
@@ -276,7 +276,7 @@ static int luks_setup(
                 void **ret_volume_key,
                 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;
         sd_id128_t p;
         size_t vks;
@@ -287,17 +287,17 @@ static int luks_setup(
         assert(dm_name);
         assert(ret);
 
-        r = crypt_init(&cd, node);
+        r = sym_crypt_init(&cd, node);
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate libcryptsetup context: %m");
 
         cryptsetup_enable_logging(cd);
 
-        r = crypt_load(cd, CRYPT_LUKS2, NULL);
+        r = sym_crypt_load(cd, CRYPT_LUKS2, NULL);
         if (r < 0)
                 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)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size");
         vks = (size_t) r;
@@ -305,7 +305,7 @@ static int luks_setup(
         if (!sd_id128_is_null(uuid) || ret_found_uuid) {
                 const char *s;
 
-                s = crypt_get_uuid(cd);
+                s = sym_crypt_get_uuid(cd);
                 if (!s)
                         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.");
         }
 
-        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.");
 
-        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.");
 
         if (volume_key_size != UINT64_MAX && vks != volume_key_size)
@@ -343,7 +343,7 @@ static int luks_setup(
         if (r < 0)
                 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,
                         dm_name,
                         vk, vks,
@@ -374,7 +374,7 @@ static int luks_open(
                 void **ret_volume_key,
                 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;
         sd_id128_t p;
         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
          * 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)
                 return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name);
 
         cryptsetup_enable_logging(cd);
 
-        r = crypt_load(cd, CRYPT_LUKS2, NULL);
+        r = sym_crypt_load(cd, CRYPT_LUKS2, NULL);
         if (r < 0)
                 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)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size");
         vks = (size_t) r;
@@ -405,7 +405,7 @@ static int luks_open(
         if (ret_found_uuid) {
                 const char *s;
 
-                s = crypt_get_uuid(cd);
+                s = sym_crypt_get_uuid(cd);
                 if (!s)
                         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
          * 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)
                 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
          * device */
 
-        cipher = crypt_get_cipher(cd);
+        cipher = sym_crypt_get_cipher(cd);
         if (!cipher)
                 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)
                 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)
                 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)
                 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;
                 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 */
                         break;
                 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"))
                         continue;
 
-                r = crypt_token_json_get(cd, token, &text);
+                r = sym_crypt_token_json_get(cd, token, &text);
                 if (r < 0)
                         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)
                         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)
                         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
          * 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)
                 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;
                 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 */
                         break;
                 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"))
                         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)
                         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;
         _cleanup_(user_record_unrefp) UserRecord *luks_home = 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_close_ int root_fd = -1, image_fd = -1;
         bool dm_activated = false, mounted = false;
@@ -1064,6 +1064,10 @@ int home_prepare_luks(
 
         assert(user_record_storage(h) == USER_LUKS);
 
+        r = dlopen_cryptsetup();
+        if (r < 0)
+                return r;
+
         if (already_activated) {
                 struct loop_info64 info;
                 const char *n;
@@ -1082,7 +1086,7 @@ int home_prepare_luks(
                 if (r < 0)
                         return r;
 
-                n = crypt_get_device_name(cd);
+                n = sym_crypt_get_device_name(cd);
                 if (!n)
                         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);
 
         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)
                 (void) run_mark_dirty(image_fd, false);
@@ -1301,6 +1305,10 @@ int home_activate_luks(
         assert(user_record_storage(h) == USER_LUKS);
         assert(ret_home);
 
+        r = dlopen_cryptsetup();
+        if (r < 0)
+                return r;
+
         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 */
 
@@ -1358,7 +1366,7 @@ int home_activate_luks(
 
         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)
                 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) {
-        _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;
         bool we_detached;
         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
          * name. */
 
+        r = dlopen_cryptsetup();
+        if (r < 0)
+                return r;
+
         r = make_dm_names(h->user_name, &dm_name, &dm_node);
         if (r < 0)
                 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)) {
                 log_debug_errno(r, "LUKS device %s has already been detached.", dm_name);
                 we_detached = false;
@@ -1401,7 +1413,7 @@ int home_deactivate_luks(UserRecord *h) {
 
                 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)) {
                         log_debug_errno(r, "LUKS device %s is already detached.", dm_node);
                         we_detached = false;
@@ -1477,7 +1489,7 @@ static int luks_format(
                 struct crypt_device **ret) {
 
         _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;
         struct crypt_pbkdf_type good_pbkdf, minimal_pbkdf;
         char suuid[ID128_UUID_STRING_MAX], **pp;
@@ -1490,7 +1502,7 @@ static int luks_format(
         assert(hr);
         assert(ret);
 
-        r = crypt_init(&cd, node);
+        r = sym_crypt_init(&cd, node);
         if (r < 0)
                 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
         /* 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)
                 return log_error_errno(r, "Failed to change LUKS2 metadata size: %m");
 #endif
@@ -1519,7 +1531,7 @@ static int luks_format(
         build_good_pbkdf(&good_pbkdf, hr);
         build_minimal_pbkdf(&minimal_pbkdf, hr);
 
-        r = crypt_format(cd,
+        r = sym_crypt_format(cd,
                          CRYPT_LUKS2,
                          user_record_luks_cipher(hr),
                          user_record_luks_cipher_mode(hr),
@@ -1542,15 +1554,15 @@ static int luks_format(
                 if (strv_contains(cache->pkcs11_passwords, *pp) ||
                     strv_contains(cache->fido2_passwords, *pp)) {
                         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 {
                         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)
                         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,
                                 slot,
                                 volume_key,
@@ -1564,7 +1576,7 @@ static int luks_format(
                 slot++;
         }
 
-        r = crypt_activate_by_volume_key(
+        r = sym_crypt_activate_by_volume_key(
                         cd,
                         dm_name,
                         volume_key,
@@ -1575,7 +1587,7 @@ static int luks_format(
 
         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)
                 return log_error_errno(r, "Failed to prepare home record for LUKS: %m");
 
@@ -1583,7 +1595,7 @@ static int luks_format(
         if (r < 0)
                 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)
                 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;
         sd_id128_t partition_uuid, fs_uuid, luks_uuid, disk_uuid;
         _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;
         const char *fstype, *ip;
         struct statfs sfs;
@@ -1886,6 +1898,10 @@ int home_create_luks(
         assert(h->storage < 0 || h->storage == USER_LUKS);
         assert(ret_home);
 
+        r = dlopen_cryptsetup();
+        if (r < 0)
+                return r;
+
         assert_se(ip = user_record_image_path(h));
 
         fstype = user_record_file_system_type(h);
@@ -2139,7 +2155,7 @@ int home_create_luks(
         if (r < 0)
                 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) {
                 log_error_errno(r, "Failed to clone record: %m");
                 goto fail;
@@ -2152,8 +2168,8 @@ int home_create_luks(
                         partition_uuid,
                         luks_uuid,
                         fs_uuid,
-                        crypt_get_cipher(cd),
-                        crypt_get_cipher_mode(cd),
+                        sym_crypt_get_cipher(cd),
+                        sym_crypt_get_cipher_mode(cd),
                         luks_volume_key_size_convert(cd),
                         fstype,
                         NULL,
@@ -2178,13 +2194,13 @@ int home_create_luks(
 
         mounted = false;
 
-        r = crypt_deactivate(cd, dm_name);
+        r = sym_crypt_deactivate_by_name(cd, dm_name, 0);
         if (r < 0) {
                 log_error_errno(r, "Failed to deactivate LUKS device: %m");
                 goto fail;
         }
 
-        crypt_free(cd);
+        sym_crypt_free(cd);
         cd = NULL;
 
         dm_activated = false;
@@ -2245,7 +2261,7 @@ fail:
                 (void) umount_verbose(LOG_WARNING, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW);
 
         if (dm_activated)
-                (void) crypt_deactivate(cd, dm_name);
+                (void) sym_crypt_deactivate_by_name(cd, dm_name, 0);
 
         loop = loop_device_unref(loop);
 
@@ -2633,6 +2649,10 @@ int home_resize_luks(
         assert(setup);
         assert(ret_home);
 
+        r = dlopen_cryptsetup();
+        if (r < 0)
+                return r;
+
         assert_se(ipo = user_record_image_path(h));
         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)
                 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)
                 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)
@@ -2797,7 +2817,7 @@ int home_resize_luks(
                         log_debug_errno(errno, "BLKRRPART failed on block device, ignoring: %m");
 
                 /* 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)
                         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) {
 
                 /* 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)
                         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(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)
                 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)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine number of key slots.");
         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)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine volume key size.");
         volume_key_size = (size_t) r;
@@ -2954,7 +2978,7 @@ int home_passwd_luks(
         build_minimal_pbkdf(&minimal_pbkdf, h);
 
         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 */
                         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]) ||
                     strv_contains(cache->fido2_passwords, effective_passwords[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 {
                         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)
                         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,
                                 i,
                                 volume_key,
@@ -2992,7 +3016,7 @@ int home_passwd_luks(
 }
 
 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_close_ int root_fd = -1;
         const char *p;
@@ -3009,7 +3033,11 @@ int home_lock_luks(UserRecord *h) {
         if (r < 0)
                 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)
                 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 */
 
-        r = crypt_suspend(cd, dm_name);
+        r = sym_crypt_suspend(cd, dm_name);
         if (r < 0)
                 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);
 
         STRV_FOREACH(pp, password) {
-                r = crypt_resume_by_passphrase(
+                r = sym_crypt_resume_by_passphrase(
                                 cd,
                                 dm_name,
                                 CRYPT_ANY_SLOT,
@@ -3064,7 +3092,7 @@ static int luks_try_resume(
 
 int home_unlock_luks(UserRecord *h, PasswordCache *cache) {
         _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;
         int r;
 
@@ -3074,7 +3102,11 @@ int home_unlock_luks(UserRecord *h, PasswordCache *cache) {
         if (r < 0)
                 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)
                 return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name);
 
index c43bdfcba3f31c039ead6cc385d7eb20f63669a7..8764862bd2cb47821bdb3b07adb166c95874e6aa 100644 (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. */
 
-        k = crypt_get_volume_key_size(cd);
+        k = sym_crypt_get_volume_key_size(cd);
         if (k <= 0)
                 return UINT64_MAX;
 
index bb5a774f81c0992547965f1e2db189547054b97b..073d12e50e15682a8aafb17f3aeba6ef2859ac56 100644 (file)
@@ -48,8 +48,10 @@ int user_record_authenticate(
                 PasswordCache *cache,
                 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,
-                pin_locked = false, pin_incorrect = false, pin_incorrect_few_tries_left = false, pin_incorrect_one_try_left = false, token_action_timeout = false;
+        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,
+                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;
 
         assert(h);
@@ -125,7 +127,7 @@ int user_record_authenticate(
                                 return log_error_errno(r, "Failed to check supplied FIDO2 password: %m");
                         if (r > 0) {
                                 log_info("Previously acquired FIDO2 password unlocks user record.");
-                                return 0;
+                                return 1;
                         }
                 }
         }
@@ -178,7 +180,7 @@ int user_record_authenticate(
                         if (r < 0)
                                 return log_oom();
 
-                        return 0;
+                        return 1;
                 }
 #else
                 need_token = true;
@@ -208,6 +210,9 @@ int user_record_authenticate(
                 case -EMEDIUMTYPE:
                         need_user_presence_permitted = true;
                         break;
+                case -ENOCSI:
+                        need_user_verification_permitted = true;
+                        break;
                 case -ENOSTR:
                         token_action_timeout = true;
                         break;
@@ -250,6 +255,8 @@ int user_record_authenticate(
                 return -ERFKILL;
         if (need_user_presence_permitted)
                 return -EMEDIUMTYPE;
+        if (need_user_verification_permitted)
+                return -ENOCSI;
         if (need_pin)
                 return -ENOANO;
         if (need_token)
@@ -297,7 +304,7 @@ int home_setup_undo(HomeSetup *setup) {
         }
 
         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)
                         r = q;
         }
@@ -328,8 +335,10 @@ int home_setup_undo(HomeSetup *setup) {
         setup->dm_node = mfree(setup->dm_node);
 
         setup->loop = loop_device_unref(setup->loop);
-        crypt_free(setup->crypt_device);
-        setup->crypt_device = NULL;
+        if (setup->crypt_device) {
+                sym_crypt_free(setup->crypt_device);
+                setup->crypt_device = NULL;
+        }
 
         explicit_bzero_safe(setup->volume_key, setup->volume_key_size);
         setup->volume_key = mfree(setup->volume_key);
@@ -517,7 +526,7 @@ int home_load_embedded_identity(
         if (!embedded_home)
                 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)
                 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(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)
                 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_luks_uuid,
                         setup->found_fs_uuid,
-                        setup->crypt_device ? 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(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,
                         file_system_type_fd(setup->root_fd),
                         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");
         if (r == 0) {
                 r = path_is_encrypted("/home");
-                if (r < 0)
-                        log_warning_errno(r, "Failed to determine if /home is encrypted, ignoring: %m");
-                if (r <= 0) {
-                        log_info("Using automatic default storage of '%s'.", user_storage_to_string(USER_LUKS));
-                        *ret = USER_LUKS;
-                        return 0;
-                }
+                if (r > 0)
+                        log_info("/home is encrypted, not using '%s' storage, in order to avoid double encryption.", user_storage_to_string(USER_LUKS));
+                else {
+                        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));
+                        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
                 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)
                 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)
                 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
          * 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
+         * 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
          * EOWNERDEAD      → suitable PKCS#11/FIDO2 device found, but its PIN is locked
          * ENOLCK          → suitable PKCS#11/FIDO2 device found, but PIN incorrect
index 64dc5325778e5e4c8e6d9fc3ba85abf3461123e4..b7db39dab9cc9d271b31f3ff2bd9a3beb0c9e1a6 100644 (file)
@@ -216,7 +216,7 @@ static int acquire_user_record(
         if (!ur)
                 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) {
                 pam_syslog(handle, LOG_ERR, "Failed to load user record: %s", strerror_safe(r));
                 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)) {
 
-                (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);
                 if (r < 0) {
@@ -385,6 +385,16 @@ static int handle_generic_user_record_error(
                         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)) {
 
                 (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN is locked, please unlock it first. (Hint: Removal and re-insertion might suffice.)");
index 5ac92255c8b02a54d00f6a8cd4cf9fa389a4ac7a..ab73fba93fa4c087066c9c32bc093c6c08a93a0b 100644 (file)
@@ -14,7 +14,7 @@ static int user_record_signable_json(UserRecord *ur, char **ret) {
         assert(ur);
         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)
                 return r;
 
@@ -95,7 +95,7 @@ int user_record_sign(UserRecord *ur, EVP_PKEY *private_key, UserRecord **ret) {
         if (!signed_ur)
                 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)
                 return r;
 
index e244ba5772a106baf574d6c853ab8d6d6b4c644b..b205f1d1e66e01bbf0f3d82ab95bb8833f98e26f 100644 (file)
@@ -252,7 +252,7 @@ int user_record_reconcile(
                 if (!merged)
                         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)
                         return r;
 
@@ -261,7 +261,7 @@ int user_record_reconcile(
         }
 
         /* 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)
                 return r;
 
@@ -1065,6 +1065,34 @@ int user_record_set_fido2_user_presence_permitted(UserRecord *h, int b) {
         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) {
         const char *k;
         _unused_ JsonVariant *e;
@@ -1167,6 +1195,14 @@ int user_record_merge_secret(UserRecord *h, UserRecord *secret) {
                         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;
 }
 
index f7cc4e04eb1f5508bcf5423d059e8d879bd7183f..74f4a0eaab28fe6c170a29aa7b9122173435a2be 100644 (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_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_verification_permitted(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_good_authentication(UserRecord *h);
index dc6211bc978f608f33b1d968781db71d46bcc784..43f9a7bdaadadd3c6aa489bf9f9aa1ae35024403 100644 (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_PROTECTED_AUTHENTICATION_PATH_NEEDED, ERFKILL),
         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_PIN_LOCKED,             EOWNERDEAD),
         SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_BAD_PIN,                ENOLCK),
index e56b5d139dea5a2396d1f2f5ef08e2fc002c62e6..fd8f0c240e96a5c8bfb410eb0bef6ef1f1960d18 100644 (file)
 #define BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED \
                                                "org.freedesktop.home1.TokenProtectedAuthenticationPathNeeded"
 #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_PIN_LOCKED             "org.freedesktop.home1.TokenPinLocked"
 #define BUS_ERROR_TOKEN_BAD_PIN                "org.freedesktop.home1.BadPin"
index 2021c31bd5227e3ce28c86daf057f2253e89f45a..f8bd17eefecaafe87fd6d587f769003677e93151 100644 (file)
@@ -141,7 +141,7 @@ static int acquire_user_record(
                 if (!ur)
                         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) {
                         pam_syslog(handle, LOG_ERR, "Failed to load user record: %s", strerror_safe(r));
                         return PAM_SERVICE_ERR;
index 801a52b7a8d7dbbc476ef02596fa71169596a66d..6852125b9d33dc31e23589cf99414b5df33bb798 100644 (file)
@@ -377,14 +377,16 @@ int bind_user_setup(
                 USER_RECORD_STRIP_PRIVILEGED|
                 USER_RECORD_ALLOW_PER_MACHINE|
                 USER_RECORD_ALLOW_BINDING|
-                USER_RECORD_ALLOW_SIGNATURE;
+                USER_RECORD_ALLOW_SIGNATURE|
+                USER_RECORD_PERMISSIVE;
         static const UserRecordLoadFlags shadow_flags = /* Extracts privileged info */
                 USER_RECORD_STRIP_REGULAR|
                 USER_RECORD_ALLOW_PRIVILEGED|
                 USER_RECORD_STRIP_PER_MACHINE|
                 USER_RECORD_STRIP_BINDING|
                 USER_RECORD_STRIP_SIGNATURE|
-                USER_RECORD_EMPTY_OK;
+                USER_RECORD_EMPTY_OK|
+                USER_RECORD_PERMISSIVE;
         int r;
 
         assert(root);
index e2b018c0ca77ee7915d4395e5373b33628dc3638..f747966bab7ad790aab264a6c2f075cbc23ccf6d 100644 (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_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);
+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_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_volume_key_size)(struct crypt_device *cd);
 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_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_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);
 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);
-int (*sym_crypt_set_pbkdf_type)(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf) = NULL;
-int (*sym_crypt_token_json_get)(struct crypt_device *cd, int token, const char **json) = NULL;
-int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const char *json) = NULL;
-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_SET_METADATA_SIZE
+int (*sym_crypt_set_metadata_size)(struct crypt_device *cd, uint64_t metadata_size, uint64_t keyslots_size);
+#endif
+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
 int (*sym_crypt_token_max)(const char *type);
 #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) {
         _cleanup_(dlclosep) void *dl = NULL;
@@ -58,23 +73,38 @@ int dlopen_cryptsetup(void) {
                         DLSYM_ARG(crypt_deactivate_by_name),
                         DLSYM_ARG(crypt_format),
                         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_type),
+                        DLSYM_ARG(crypt_get_uuid),
                         DLSYM_ARG(crypt_get_verity_info),
+                        DLSYM_ARG(crypt_get_volume_key_size),
                         DLSYM_ARG(crypt_init),
                         DLSYM_ARG(crypt_init_by_name),
                         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_resize),
+                        DLSYM_ARG(crypt_resume_by_passphrase),
                         DLSYM_ARG(crypt_set_data_device),
                         DLSYM_ARG(crypt_set_debug_level),
                         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_suspend),
                         DLSYM_ARG(crypt_token_json_get),
                         DLSYM_ARG(crypt_token_json_set),
-                        DLSYM_ARG(crypt_volume_key_get),
 #if HAVE_CRYPT_TOKEN_MAX
                         DLSYM_ARG(crypt_token_max),
 #endif
+                        DLSYM_ARG(crypt_token_status),
+                        DLSYM_ARG(crypt_volume_key_get),
                         NULL);
         if (r < 0)
                 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
          * was traditionally a regular shared library dependency which lives forever too. */
         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;
 }
 
@@ -109,13 +146,17 @@ static void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
 }
 
 void cryptsetup_enable_logging(struct crypt_device *cd) {
-        if (!cd)
-                return;
-
-        if (dlopen_cryptsetup() < 0) /* If this fails, let's gracefully ignore the issue, this is just debug
-                                      * logging after all, and if this failed we already generated a debug
-                                      * log message that should help to track things down. */
-                return;
+        /* It's OK to call this with a NULL parameter, in which case libcryptsetup will set the defaut log
+         * 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)
+                return; /* If this fails, let's gracefully ignore the issue, this is just debug logging after
+                         * all, and if this failed we already generated a debug log message that should help
+                         * to track things down. */
 
         sym_crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
         sym_crypt_set_debug_level(DEBUG_LOGGING ? CRYPT_DEBUG_ALL : CRYPT_DEBUG_NONE);
index 855997f3354c26383fad1b5801b1a813bd52b7ff..1bf9830a7daad2b68e44bcb3ba3e9d46dec5f773 100644 (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_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 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_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_volume_key_size)(struct crypt_device *cd);
 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_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_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 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);
+#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_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_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
 extern int (*sym_crypt_token_max)(const char *type);
 #else
@@ -47,6 +60,8 @@ static inline int sym_crypt_token_max(_unused_ const char *type) {
     return 32;
 }
 #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);
 
index a8402c1dcd1a3d07ee7ee54519bfe9eb0f5f85b6..476e514c52e67fef0693f3f8fbb13903635b9c3c 100644 (file)
@@ -1926,6 +1926,8 @@ static int verity_can_reuse(
         if (r < 0)
                 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);
         if (r < 0)
                 return log_debug_errno(r, "Error opening verity device, crypt_get_verity_info failed: %m");
index d82b4d36361efcee057a444a7473469eeb503ea1..de949c57e36ecc9bae899ec75a278f825c258035 100644 (file)
@@ -200,6 +200,7 @@ UserRecord* user_record_new(void) {
                 .password_change_now = -1,
                 .pkcs11_protected_authentication_path_permitted = -1,
                 .fido2_user_presence_permitted = -1,
+                .fido2_user_verification_permitted = -1,
         };
 
         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 },
                 { "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 },
+                { "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;
 
                 static const JsonDispatch fido2_hmac_salt_dispatch_table[] = {
-                        { "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 },
-                        { "hashedPassword", JSON_VARIANT_STRING, json_dispatch_string,           offsetof(Fido2HmacSalt, hashed_password), 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 },
+                        { "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;
                 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);
                 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 */
 
         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)
                         return r;
 
@@ -2113,7 +2122,7 @@ int user_record_masked_equal(UserRecord *a, UserRecord *b, UserRecordMask mask)
         }
 
         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)
                         return r;
 
index 66dceecfdddaf151c891f92904d0f2f2943e2d95..fa58dfdb6e6e33662e36403d3c47f76cdebaa9d5 100644 (file)
@@ -236,6 +236,9 @@ typedef struct Fido2HmacSalt {
 
         /* What to test the hashed salt value against, usually UNIX password hash here. */
         char *hashed_password;
+
+        /* Whether the 'up', 'uv', 'clientPin' features are enabled. */
+        int uv, up, client_pin;
 } Fido2HmacSalt;
 
 typedef struct RecoveryKey {
@@ -371,6 +374,7 @@ typedef struct UserRecord {
         Fido2HmacSalt *fido2_hmac_salt;
         size_t n_fido2_hmac_salt;
         int fido2_user_presence_permitted;
+        int fido2_user_verification_permitted;
 
         char **recovery_key_type;
         RecoveryKey *recovery_key;
index 442c6c952bb9fbb85eef579934c95ef1ceab4719..5d79f4688a00c11e35f727b4c32dbb3776f8bda2 100644 (file)
@@ -82,7 +82,8 @@ static int load_user(
                         USER_RECORD_ALLOW_PER_MACHINE|
                         USER_RECORD_ALLOW_BINDING|
                         USER_RECORD_ALLOW_SIGNATURE|
-                        (have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0));
+                        (have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0)|
+                        USER_RECORD_PERMISSIVE);
         if (r < 0)
                 return r;
 
@@ -225,7 +226,8 @@ static int load_group(
                         USER_RECORD_ALLOW_PER_MACHINE|
                         USER_RECORD_ALLOW_BINDING|
                         USER_RECORD_ALLOW_SIGNATURE|
-                        (have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0));
+                        (have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0)|
+                        USER_RECORD_PERMISSIVE);
         if (r < 0)
                 return r;
 
index 21caa540965d56469f214edb3d75d03556a86bb7..8b7a20b08d4cb8c2dcd063fc90949cd6becb5f68 100644 (file)
@@ -88,7 +88,7 @@ static int build_user_json(Varlink *link, UserRecord *ur, JsonVariant **ret) {
         } else
                 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)
                 flags |= USER_RECORD_ALLOW_PRIVILEGED;
         else
@@ -232,7 +232,7 @@ static int build_group_json(Varlink *link, GroupRecord *gr, JsonVariant **ret) {
         } else
                 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)
                 flags |= USER_RECORD_ALLOW_PRIVILEGED;
         else
index 2b54065437fe49f1375cfcc6a8811feed04ee7ea..34208dcd87659e5da4501e169aa9856fd5344783 100644 (file)
@@ -138,6 +138,8 @@ static int run(int argc, char *argv[]) {
 
         log_setup();
 
+        cryptsetup_enable_logging(NULL);
+
         umask(0022);
 
         if (streq(argv[1], "attach")) {