gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync fashion all the times, however in case the daemon had startup failures or was hanging for whatever reason (like due to devices probing, given that fprintd synchronously wait for them all to be initialized) we used to just fail, leaving gdm or the lockscreen in a not usable state. While this could be prevented with a try/catch statement, there's no much point to wait for fprintd if that's not the default authentication service, and so: - If we use gdm-fingerprint as default auth method, use a sync call to initialize it and in case of failures, just continue with fallback authentication mechanism (password) - Otherwise, asynchronously initialize fprintd and continue with the ShellUserVerifier without fingerprint support until we got a reply. In case the service fails to deliver us a result, we don't give up but we will try doing that at each authentication via _checkForFingerprintReader(). In case all works properly, as per the previous commit, once the initialization is done, we'll start the fingerprint PAM gdm service. Fixes #5168 Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
This commit is contained in:
parent
efb52899f5
commit
885f1391ab
104
js/gdm/util.js
104
js/gdm/util.js
@ -107,6 +107,7 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
|
||||
this._defaultService = null;
|
||||
this._preemptingService = null;
|
||||
this._fingerprintReaderType = FingerprintReaderType.NONE;
|
||||
|
||||
this._messageQueue = [];
|
||||
this._messageQueueTimeoutId = 0;
|
||||
@ -170,7 +171,8 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
this._userName = userName;
|
||||
this.reauthenticating = false;
|
||||
|
||||
this._checkForFingerprintReader().catch(logError);
|
||||
this._checkForFingerprintReader().catch(e =>
|
||||
this._handleFingerprintError(e));
|
||||
|
||||
// If possible, reauthenticate an already running session,
|
||||
// so any session specific credentials get updated appropriately
|
||||
@ -332,39 +334,85 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
this.emit('show-message', null, null, MessageType.NONE);
|
||||
}
|
||||
|
||||
_initFingerprintManager() {
|
||||
async _initFingerprintManager() {
|
||||
if (this._fprintManager)
|
||||
return;
|
||||
|
||||
this._fprintManager = new Gio.DBusProxy({
|
||||
const fprintManager = new Gio.DBusProxy({
|
||||
g_connection: Gio.DBus.system,
|
||||
g_name: 'net.reactivated.Fprint',
|
||||
g_object_path: '/net/reactivated/Fprint/Manager',
|
||||
g_interface_name: FprintManagerInfo.name,
|
||||
g_interface_info: FprintManagerInfo,
|
||||
g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES,
|
||||
g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES |
|
||||
Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION |
|
||||
Gio.DBusProxyFlags.DO_NOT_CONNECT_SIGNALS,
|
||||
});
|
||||
this._fprintManager.init(null);
|
||||
|
||||
try {
|
||||
if (!this._getDetectedDefaultService()) {
|
||||
// Other authentication methods would have already been detected by
|
||||
// now as possibilities if they were available.
|
||||
// If we're here it means that FINGERPRINT_AUTHENTICATION_KEY is
|
||||
// true and so fingerprint authentication is our last potential
|
||||
// option, so go ahead a synchronously look for a fingerprint device
|
||||
// during startup or default service update.
|
||||
fprintManager.init(null);
|
||||
const [devicePath] = fprintManager.GetDefaultDeviceSync();
|
||||
this._fprintManager = fprintManager;
|
||||
|
||||
const fprintDeviceProxy = new FprintDeviceProxy(Gio.DBus.system,
|
||||
'net.reactivated.Fprint', devicePath, null, null,
|
||||
Gio.DBusProxyFlags.NOT_CONNECT_SIGNALS);
|
||||
this._setFingerprintReaderType(fprintDeviceProxy['scan-type']);
|
||||
} else {
|
||||
// Ensure fingerprint service starts, but do not wait for it
|
||||
const cancellable = this._cancellable;
|
||||
await fprintManager.init_async(GLib.PRIORITY_DEFAULT, cancellable);
|
||||
await this._updateFingerprintReaderType(fprintManager, cancellable);
|
||||
this._fprintManager = fprintManager;
|
||||
}
|
||||
} catch (e) {
|
||||
this._handleFingerprintError(e);
|
||||
}
|
||||
}
|
||||
|
||||
_handleFingerprintError(e) {
|
||||
this._fingerprintReaderType = FingerprintReaderType.NONE;
|
||||
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
return;
|
||||
if (e.matches(Gio.DBusError, Gio.DBusError.SERVICE_UNKNOWN))
|
||||
return;
|
||||
|
||||
if (Gio.DBusError.is_remote_error(e) &&
|
||||
Gio.DBusError.get_remote_error(e) ===
|
||||
'net.reactivated.Fprint.Error.NoSuchDevice')
|
||||
return;
|
||||
|
||||
logError(e, 'Failed to interact with fprintd service');
|
||||
}
|
||||
|
||||
async _checkForFingerprintReader() {
|
||||
this._fingerprintReaderType = FingerprintReaderType.NONE;
|
||||
|
||||
if (!this._fprintManager) {
|
||||
this._updateDefaultService();
|
||||
return;
|
||||
}
|
||||
|
||||
const [devicePath] = await this._fprintManager.GetDefaultDeviceAsync(
|
||||
Gio.DBusCallFlags.NONE, this._cancellable);
|
||||
if (this._fingerprintReaderType !== FingerprintReaderType.NONE)
|
||||
return;
|
||||
|
||||
await this._updateFingerprintReaderType(this._fprintManager, this._cancellable);
|
||||
}
|
||||
|
||||
async _updateFingerprintReaderType(fprintManager, cancellable) {
|
||||
// Wrappers don't support null cancellable, so let's ignore it in case
|
||||
const args = cancellable ? [cancellable] : [];
|
||||
const [devicePath] = await fprintManager.GetDefaultDeviceAsync(...args);
|
||||
const fprintDeviceProxy = new FprintDeviceProxy(Gio.DBus.system,
|
||||
'net.reactivated.Fprint',
|
||||
devicePath);
|
||||
const fprintDeviceType = fprintDeviceProxy['scan-type'];
|
||||
|
||||
this._fingerprintReaderType = fprintDeviceType === 'swipe'
|
||||
? FingerprintReaderType.SWIPE
|
||||
: FingerprintReaderType.PRESS;
|
||||
this._setFingerprintReaderType(fprintDeviceProxy['scan-type']);
|
||||
this._updateDefaultService();
|
||||
|
||||
if (this._userVerifier &&
|
||||
@ -375,6 +423,14 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
_setFingerprintReaderType(fprintDeviceType) {
|
||||
this._fingerprintReaderType =
|
||||
FingerprintReaderType[fprintDeviceType.toUpperCase()];
|
||||
|
||||
if (this._fingerprintReaderType === undefined)
|
||||
throw new Error(`Unexpected fingerprint device type '${fprintDeviceType}'`);
|
||||
}
|
||||
|
||||
_onCredentialManagerAuthenticated(credentialManager, _token) {
|
||||
this._preemptingService = credentialManager.service;
|
||||
this.emit('credential-manager-authenticated');
|
||||
@ -547,7 +603,7 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
let needsReset = false;
|
||||
|
||||
if (this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY)) {
|
||||
this._initFingerprintManager();
|
||||
this._initFingerprintManager().catch(logError);
|
||||
} else if (this._fingerprintManager) {
|
||||
this._fingerprintManager = null;
|
||||
this._fingerprintReaderType = FingerprintReaderType.NONE;
|
||||
@ -570,15 +626,19 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
this._cancelAndReset();
|
||||
}
|
||||
|
||||
_getDetectedDefaultService() {
|
||||
if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
|
||||
return PASSWORD_SERVICE_NAME;
|
||||
else if (this._smartcardManager)
|
||||
return SMARTCARD_SERVICE_NAME;
|
||||
else if (this._fingerprintReaderType !== FingerprintReaderType.NONE)
|
||||
return FINGERPRINT_SERVICE_NAME;
|
||||
return null;
|
||||
}
|
||||
|
||||
_updateDefaultService() {
|
||||
const oldDefaultService = this._defaultService;
|
||||
|
||||
if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
|
||||
this._defaultService = PASSWORD_SERVICE_NAME;
|
||||
else if (this._smartcardManager)
|
||||
this._defaultService = SMARTCARD_SERVICE_NAME;
|
||||
else if (this._fingerprintReaderType !== FingerprintReaderType.NONE)
|
||||
this._defaultService = FINGERPRINT_SERVICE_NAME;
|
||||
this._defaultService = this._getDetectedDefaultService();
|
||||
|
||||
if (!this._defaultService) {
|
||||
log('no authentication service is enabled, using password authentication');
|
||||
|
Loading…
x
Reference in New Issue
Block a user