Page MenuHomePureOS Tracker

Automatically lock the screen when Librem Key is removed
Closed, ResolvedPublic

Description

As a nice add-on for the Librem Key in PureOS, we would like to automatically lock the screen for the user when they remove their Librem Key. This is a relatively simple addition and I will leave the implementation details (what package to use, etc.) up to you, but ideally this would be in a package that automatically gets installed in PureOS.

This integration requires two files: /etc/udev/rules.d/85-libremkey.rules:

ACTION=="remove", ENV{PRODUCT}=="316d/4c4b/101" RUN+="/usr/local/bin/gnome-screensaver-lock"

and /usr/local/bin/gnome-screensaver-lock:

#!/bin/sh

user=`ps aux | egrep "gdm-(wayland|x)-session" | head -n 1 | awk '{print $1}'`

if [ -n $user ]; then
        su $user -c "/usr/bin/dbus-send --type=method_call --dest=org.gnome.ScreenSaver /org/gnome/ScreenSaver org.gnome.ScreenSaver.Lock"
fi

I leave it up to you whether we keep the script at /usr/local/bin or not. If its location changes, it will also need to change in the udev rule.

The package will need to trigger udev to reload upon installation so it picks up the new rule.

Event Timeline

kyle.rankin created this task.Feb 7 2019, 11:26
jeremiah.foster triaged this task as Normal priority.
hansolo added a subscriber: hansolo.Feb 8 2019, 11:24

The gnome-screensaver-lock works well. I cannot get the udev rule to be discovered on my L15v3 however. There is some information on this available on the Nitrokey from upstream where they publish their own udev rules but that fails to work for me as well.

The rules file is in the right location (/etc/udev/rules.d) and it gets read according to systemd-udev:

Apr 23 10:02:36 slate systemd-udevd[386]: Reading rules file: /etc/udev/rules.d/85-libremkey.rules

So to get this straight, the udev rule works with your particular Librem Key on one laptop but not another? I wonder if for some reason the ID_VENDOR value changed from "Nitrokey" to something else in newer revisions of the Librem Key.

For instance, unplug the Librem Key, plug it back in, and look in dmesg output for the long device string under /devices/pci0000:00/ etc for it. then paste that full device path to

sudo udevadm info -a -p /device/pci000:000/whatever   | grep ID_VENDOR

Then you should be able to see which ID_VENDOR tag is getting applied to your device and we can add an *additional* udev rule in our ruleset to capture that variation.

The udev rule doesn't work in either machine; neither the L13v3 or L15v3. With regard to identifying the device, I'm included dmesg output (which I've not found super helpful) and udevadm output (which is better.)

Output of the following command is captured in the udev-path file.

udevadm info -a -p $(udevadm info -q path -n /dev/usb/hiddev0) > udev-path

Here's the output from dmesg; (removing the USB card, then re-inserting it.)

[13978.001098] usb 1-3: USB disconnect, device number 6
[13981.043970] usb 1-3: new full-speed USB device number 8 using xhci_hcd
[13981.193504] usb 1-3: New USB device found, idVendor=20a0, idProduct=4108, bcdDevice= 1.01
[13981.193506] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[13981.193507] usb 1-3: Product: Nitrokey Pro
[13981.193508] usb 1-3: Manufacturer: Nitrokey
[13981.193509] usb 1-3: SerialNumber: 000000000000000000006B87
[13981.195479] hid-generic 0003:20A0:4108.0004: hiddev0,hidraw0: USB HID v1.10 Device [Nitrokey Nitrokey Pro] on usb-0000:00:14.0-3/input0

The format of the udev rule in the file itself may be the issue, I'm still trying to determine. Nitrokey offers packages: https://www.nitrokey.com/download/debian I'm going to see if they provide any inspiration.

Based on this:

ATTRS{ID_VENDOR}=="Nitrokey"

The rule should definitely match. Are you sure the script is set to be executable, the path is correct, the filename is correct and all of those basic things? I hate to ask I just want to rule all that out. Does the script work when you run it by itself?

The script does work when it runs by itself (always worth asking :-)

Regarding the rules file, I think we had ENV{ID_VENDOR}, at least I did in my file.

Do we not need a SUBSYSTEM var? I.e. SUBSYSTEM=="usb"? Also, I note that Nitrokey themselves uses ATTR{idVendor}=="20a0".

Yes, ENV{ID_VENDOR} is what we'd want, as ID_VENDOR is being set in an environment variable that gets passed along to these udev rules. I was just flagging that in your udevadm output it had set ID_VENDOR (via ATTRS{ID_VENDOR}) to Nitrokey.

When troubleshooting udev rules, it's better to be less specific instead of more specific if you can. Our rule would trigger on *any* device that has a ID_VENDOR set to "Nitrokey" which is OK for us.

If we made it more specific, we'd be adding *more* things that could be wrong instead of fewer.

Barring some kind of syntax error in the rule that I'm missing, or the script not existing at that exact /usr/local/bin path, or using underscores in the name instead of dashes, I'm puzzled as to why this isn't working for you.

At least I haven't partitioned the USB drive. :}

Can it be that it asks for a password when I run the command with the full path? The script has jeremiah:jeremiah as the user:group and perms are 755 and the command in the script (

ps aux | egrep "gdm-(wayland|x)-session" | head -n 1 | awk '{print $1}'

prints 'jeremiah'.

jeremiah@slate:~$ /usr/local/bin/gnome-screensaver-lock
Password:

That's because of the 'su $user' command that's in there. Root doesn't have to type the user's password but a regular user (even the same user) does.

Can you add debugging into the script (set > /tmp/foobarbaz ) so we can confirm the script does get executed when you remove the key?

jeremiah.foster raised the priority of this task from Normal to High.Aug 5 2019, 08:29

I added the debugging info and the file was not created when I removed the key, so I don't think the script is being run. I tested the script as root without the key and the script outputs info to /tmp correctly.

When I run the command on the command line

/usr/bin/dbus-send --print-reply --type=method_call --dest=org.gnome.ScreenSaver /org/gnome/ScreenSaver org.gnome.ScreenSaver.Lock

I get;

Error org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.ScreenSaver was not provided by any .service files

I've gotten the script to lock the screen when run. There are problems using 'remove' however in the udev rule, I don't think that our Vendor ID is showing up. At lease when I run

udevadm monitor

the Vendor ID is not picked up and consequently the script is not run. I'll test via other means and other parameters.

neil.lawhead added a subscriber: neil.lawhead.EditedOct 16 2019, 16:06

@jeremiah.foster

After running the following command

udevadm monitor --environment --udev

and removing the Librem Key, I was given a list of variables:

UDEV  [76.262990] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-3 (usb)
ACTION=remove
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-3
SUBSYSTEM=usb
DEVNAME=/dev/bus/usb/001/004
DEVTYPE=usb_device
PRODUCT=316d/4c4b/101
TYPE=0/0/0
BUSNUM=001
DEVNUM=004
SEQNUM=2886
USEC_INITIALIZED=76257597
MAJOR=189
MINOR=3

Then, in the /etc/udev/rules.d/85-libremkey.rules file, I replaced

ENV{ID_VENDOR}=="NitroKey"

with

ENV{PRODUCT}=="316d/4c4b/101"

found in the above list of variables, and now the setup works.

Wow, that is really cool Neil. I ran udevadm monitor as well, but I did not try to change the ENV variable to {PRODUCT}. I'll test that now.

d3vid added a subscriber: d3vid.Oct 17 2019, 08:32

Confirmed that using ENV{PRODUCT}=="316d/4c4b/101" works as expected. Closing this issue, going to add documentation here: https://docs.puri.sm/Librem_Key/Getting_Started/User_Manual.html#automatically-lock-the-desktop-when-removing-the-librem-key

Merge request sent.

jeremiah.foster closed this task as Resolved.Oct 17 2019, 11:54
mladen added a subscriber: mladen.Oct 27 2019, 06:56

Actually, the Librem Key I have is different, its PRODUCT env is 20a0/4108/100. Could we use more general solution?

neil.lawhead added a comment.EditedOct 27 2019, 19:47

Using the following text in the "85-libremkey.rules" file also works:

ACTION=="remove", ENV{HID_NAME}=="Purism, SPC Librem Key", RUN+="/usr/local/bin/gnome-screensaver-lock"

The HID_NAME variable was found after typing the following command and removing the Librem Key:

udevadm monitor --property

We have two different Librem Key models at this point. The original which was made by Nitrokey and the "Made in USA" one. Each one has a different product ID and probably HID_NAME as well.

The solution would be for the file to contain *two* lines, one for each PRODUCT env variable. udev will ignore the one that doesn't match.

for anyone reading this thread, here are 4 different udev rules you might use to make this work:

ACTION=="remove", ENV{PRODUCT}=="316d/4c4b/101" RUN+="/usr/local/bin/gnome-screensaver-lock"
ACTION=="remove", ENV{PRODUCT}=="20a0/4108/100" RUN+="/usr/local/bin/gnome-screensaver-lock"
ACTION=="remove", ENV{HID_NAME}=="Purism, SPC Librem Key", RUN+="/usr/local/bin/gnome-screensaver-lock"
ACTION=="remove", ENV{HID_NAME}=="Nitrokey Nitrokey Pro", RUN+="/usr/local/bin/gnome-screensaver-lock"

What about the status of the original request which was to add a package to do this work for the user?

Now, a bigger issue I see is that the usb key is not required for login. Having it launch the screensaver automatically is cute but not really that helpful. Are there other librem key docs that detail adding more security such as two factor logins? Should we be using the nitro key site?

I've tried the nitro key howto for pam and poldi but it doesn't work on my pureos setup. not even sure where I should post about it. here or on nitro key site? somewhere else?
https://support.nitrokey.com/t/error-while-following-linux-login-with-pam-err-100663414-ungultige-id-scd/766

mladen added a comment.Feb 18 2020, 06:27

I use this:

ACTION=="remove", ENV{PRODUCT}=="20a0/4108/100" ENV{ID_SERIAL_SHORT}=="00000000000000000000XXXX" RUN+="/usr/local/bin/session-lock"
ACTION=="add", ENV{PRODUCT}=="20a0/4108/100" ENV{ID_SERIAL_SHORT}=="00000000000000000000XXXX" RUN+="/usr/local/bin/session-unlock"

Where XXXX is the serial number of my LK.

/usr/local/bin scripts are:

session-lock:

#!/bin/sh

user=`ps aux | egrep "/usr/bin/plasma_session" | head -n 1 | awk '{print $1}'`
session=`loginctl | grep $user | awk '{print $1}'`

if [ -n $session ]; then
        loginctl lock-session $session
fi

session-unlock:

#!/bin/sh

user=`ps aux | egrep "/usr/bin/plasma_session" | head -n 1 | awk '{print $1}'`
session=`loginctl | grep $user | awk '{print $1}'`

if [ -n $session ]; then    
        loginctl unlock-session $session
fi

As you can see, I am using Plasma, but you can simply change /usr/bin/plasma_session to gdm-(wayland|x)-session for GNOME.

I know this thread is closed but it's the only place anyone seems to be discussing this. Im happy to open a new issue or post to another.

In this case, the original poster asked or this setup to be included in pureos as a package. I see the issue is marked resolved but no one has mentioned anything about a package.

@mladen
i will try your configuration but putting the serial # in the udev rules does not work for a package that would install the same file for everyone. The check for a specific id/device/token/key would need to be done in the scripts that get called.

for that matter, it seems that no solution I have seen so far ties any of the events (add,remove) to a specific id/device/token/key. Your serial number idea is the first I've seen in these forums or the librem key docs that actually attempts security but I could do the same thing with any usb device. This is not specific to the librem key.