11

I recently purchased a U2F security key, and I have successfully configured my Ubuntu 18.04 machine to require authentication via the key as well as my usual password to log in. I am hoping to change my authentication configurations such that:

  1. When I first login to my machine, I need to both enter my password and insert my U2F key
  2. When I lock my already-logged-in machine, I need only to insert my U2F key to unlock it.

Is this something that is possible with the stock GNOME lock screen? If so, which pam configuration do I have to edit?

Currently the only thing I have changed is adding

auth    required  pam_u2f.so

to /etc/pam.d/gdm-password, under

@include common-auth

5 Answers 5

6

GNOME uses gdm-password as the PAM service name for both logins and unlocks, so it's not possible to distinguish them in PAM. To do so, you'd have to create a custom build of GNOME Shell, specifically editing js/gdm/util.js to use different service names depending on context. This would be a very useful feature to PR to them were you to do it.

2
  • Got it, that makes sense. Yeah I will look into that to determine if it's something that's within my capabilities. I rarely build linux utilities from source, though, so it may be beyond me.
    – Warmar
    Commented Oct 7, 2018 at 16:33
  • 2
    Created issue for this: gitlab.gnome.org/GNOME/gnome-shell/issues/1551 Commented Aug 28, 2019 at 9:30
1

As a better (than pam_alreadyloggedin I suggested above) workaround, you can also use a custom script to check whether the current session is locked and change behaviour depending on that. For this, you can use the pam_script module. E.g. in your pam config, put something like:

# Skip regular password checks when there is a current session and it is
# locked. This skips a number of modules from common-auth when
# succesful, so this breaks when extra primary modules are added there,
# but this seems to be the only way (using success=done prevents
# optional post-auth modules from running).
auth [success=2 default=ok] pam_script.so dir=/etc/pam.d/is-current-session-locked     

@include common-auth

auth    required  pam_u2f.so

Then, create a script called /etc/pam.d/is-current-session-locked/pam_script_auth with the following contents and make it executable:

#!/bin/sh                                                                                               

if [ -z "$XDG_SESSION_ID" ]; then
        return 1                                                                                        
fi
if ! loginctl show-session "$XDG_SESSION_ID" | grep '^LockedHint=yes$' > /dev/null; then                
        return 1
fi

# Current session is locked, return success
return 0

This script checks to see if there is a login session id and then asks loginctl whether the session is locked. This does require the desktop environment to tell logind when it locks the desktop, but it seems that Gnome does this (at least on Ubuntu Disco).

0

A possible workaround is to use the pam_alreadyloggedin module. This is normally used to login without a password when you are already logged in on a different tty, but with some creative pam configuration, it can also be used to differentiate between the first login (not logged in yet) and unlocking or second logins (already logged in). The selection it makes is not perfect, but might be sufficient for your needs.

One big caveat is that the module does not recognize X sessions, only terminal sessions (because it checks ownership of the tty device, which X sessions do not have, so it ends up looking for /dev/:0 which does not exist). In practice, this means it will recognize you as logged in if you have any terminal open inside your X session (but also a screen or tmux running in the background).

I think something like the following could work for your usecase:

# Skip regular password checks when already logged in (i.e. also when
# unlocking). This skips a number of modules from common-auth when
# succesful, so this breaks when extra primary modules are added there,
# but this seems to be the only way (using success=done prevents
# optional post-auth modules from running).
auth [success=2 default=ok] pam_alreadyloggedin.so debug

@include common-auth

auth    required  pam_u2f.so

You might need to adapt this depending on what your common-auth file contains.

0

pam_script method works, but requests password once before working.

My context is slightly different: no security key, but separate passwords for login and lockscreen. Relevant excerpt from my gdm-password file is:

auth    [success=2 default=ignore]  pam_script.so dir=/etc/pam.d/is-locked
auth    [success=1 default=ignore]  pam_unix.so nullok_secure nodelay
auth    requisite           pam_deny.so
auth    [success=2 default=ignore]  pam_script.so dir=/etc/pam.d/is-unlocked
auth    [success=1 default=ignore]  pam_userdb.so nodelay crypt=crypt db=/var/local/passwd
auth    requisite           pam_deny.so

Again, works fine, but first attempt to type password is ignored, no matter what it is. I'm a PAM newbie, so either there's a bug in my code, or pam_script.so is somehow triggering an extra password prompt.

(With apologies; don't have enough points to post as comment.)

[Note added: Yup; newbie error: try_first_pass is needed as argument to both pam_userdb.so and pam_unix.so so that originally-submitted password can be used. And the above code can be simplified so that only one script is needed.

Bottom line: pam_script does the job. Improved version below.]

auth    [success=ignore default=1]      pam_script.so dir=/etc/pam.d/is-locked
auth    [success=2 default=ignore]      pam_userdb.so nodelay try_first_pass crypt=crypt db=/var/local/sudopass
auth    [success=1 default=ignore]      pam_unix.so nullok_secure nodelay try_first_pass
auth    requisite                       pam_deny.so
0

Here is what worked for me, I had to adapt Matthijs Kooijman's answer because the XDG_SESSION_ID variable is not set on Ubuntu 22.04 LTS.

I created the /etc/pam.d/is-logged-in script

#!/bin/sh

TTY=$(basename "$PAM_TTY")
SESSION_ID=$(loginctl list-sessions --no-legend | grep -Ei "$TTY$" | head -n1 | cut -d' ' -f1)

if loginctl show-session "$SESSION_ID" | grep '^LockedHint=yes$' >/dev/null; then
    echo "Session $SESSION_ID is locked."
    return 0
else
    echo "Session $SESSION_ID is unlocked."
    return 1
fi

Then we mark it as executable with sudo chmod +x /etc/pam.d/is-logged-in

Now we can add two lines to /etc/pam.d/gdm-fingerprint

 auth   required        pam_succeed_if.so user != root quiet_success
+auth [success=1 default=ignore] pam_exec.so quiet seteuid /etc/pam.d/is-logged-in
+auth required pam_exec.so /bin/sleep infinity 
 auth   required        pam_fprintd.so

The first line will allow fingerprint authentication only if an active and locked session is present (so not for the login screen), the second line will make the pam module wait forever in case of failure so gdm will not go into a loop or show any errors.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .