_cleanup_strv_free_erase_ char **pins = NULL;
_cleanup_free_ void *loaded_salt = NULL;
+ bool device_exists = false;
const char *salt;
size_t salt_size;
char *e;
-ENOANO, /* needs pin */
-ENOLCK)) /* pin incorrect */
return r;
- }
- pins = strv_free_erase(pins);
+ device_exists = true; /* that a PIN is needed/wasn't correct means that we managed to
+ * talk to a device */
+ }
if (headless)
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable.");
+ if (!device_exists) {
+ /* Before we inquire for the PIN we'll need, if we never talked to the device, check
+ * if the device actually is plugged in. Otherwise we'll ask for the PIN already when
+ * the device is not plugged in, which is confusing. */
+
+ r = fido2_have_device(device);
+ if (r < 0)
+ return r;
+ if (r == 0) /* no device found, return EAGAIN so that caller will wait/watch udev */
+ return -EAGAIN;
+
+ device_exists = true; /* now we know for sure, a device exists, no need to ask again */
+ }
+
+ pins = strv_free_erase(pins);
r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, ask_password_flags, &pins);
if (r < 0)
return log_error_errno(r, "Failed to ask for user password: %m");