-
Notifications
You must be signed in to change notification settings - Fork 404
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make i3lock support PAM prompts (better support for PAM messages and passwordless PAM methods like fingerprint-gui) #217
Comments
This is largely a duplicate of i3/i3#852. The question there still stands: we need some way to know when a fingerprint has been scanned to trigger pam. |
Well... I guess you have to trigger PAM to make it read a fingerprint and check it. Not sure how other screensavers (like gnome) does this, but they seem to managet to do it. |
I would expect the workflow to go the other way and the sensor to be always ready and somehow informing the kernel of the read, which pam hooks into. We certainly don't want to do this ourselves, so we'd need some connection through pam. But however it works, if someone can investigate and report back it would help making a decision here. |
@Airblader that's a typo. Which one did you mean? |
|
Yes, correct issue number, wrong repository. Sorry :-) |
@Airblader it probably makes sense to edit the original comment ;) |
Oh, and does it have to rely on i3 itself? I'm using just i3lock without i3, for example... |
No, the issue over at i3 is just so old that it predates Github. This is the correct repository. |
The suggestion is that |
Yes, I was gonna update the comment, I just didn't wanna do it from mobile. Willdo now, thanks ;-) |
Reading around seems that one way to do it (at least the way I understood it from reading this proposal in GDM) is to start multiple PAM calls in parallel using different service names (e.g. i3lock, i3lock_1, i3lock_2, etc) where the system admin could configure independent auth flows (password, fingerprint, smartcard, etc) and the application would accept any of these flows to successfully authenticate the user. |
This is the way fprintd seems to expect it to be done as well: https://github.com/freedesktop/libfprint-fprintd/tree/master/pam
|
I've started (attempting) to implement multiple PAM stacks here: (evamvid@a703e99). As of right now, it will accept the correct password or you can hit enter and scan your fingerprint (or theoretically any other pan module you like). The improvement here is that previously, with fprintd, I could just hit enter and scan my fingerprint (it didn't matter whether or not a password was entered), but if I entered the password I'd still have to scan my fingerprint for i3 to accept it. This is literally the first thing I've ever done in c/cpp, so I'm a bit over my head! I'm frankly not even quite sure if this adds any functionality that wasn't already there, because I think there's a possibility my pam might have been misconfigured. Any guidance would be much appreciated! I set the PAM config to by default ignore the second stack (with pam_deny.so), but I included the config that I'd use for fprintd. Note that this still requires you to hit enter to trigger the PAM call, but it doesn't require you to have entered a password. |
Wouldn't it be simple to just fork, execve PAM is the better solution but seems a lot more complicated. |
I think it’d be better to not run subprocesses from i3lock. This should be done via PAM. |
I absolutely agree; however, I am tired of pressing enter everytime first. Is there a way around that? |
I looked at the code and you need to refactor the logic a bit. The current logic is to only trigger a pam authentication request after you pressed enter. In a PAM friendlier world you would trigger the general authentication request first, then read what kind of input is expected (fingerprint, password, yubikey) so you can print this out to the screen. After that you can provide the input (or password that has to be read by i3lock). I implemented in a local POC already the option to read what PAM needs and print this out on the lock screen. But this still requires pressing return. To not require this return, which leads to a refactoring of the logic of i3lock, will be in my limited opinion the biggest obstacle. |
Hi there, I took a quick look into this over the weekend. My understanding from this thread and a bit of experimenting so far is:
A quick search into lightdm and gdm shows that they both have a worker handling the PAM conversation (see session-child.c and gdm-session-worker.c) with some kind of IPC (respectively I wrote a quick proof of concept patch for i3lock at https://github.com/kAworu/i3lock/tree/fprintd. The indicator blink pink when the fingerprint is ready. Once you failed a defined number of time (can be tweaked in the PAM service but default is 3 on my machine) it will count as an auth failure and the fingerprint will not be available anymore. Technically it To test you need to create echo "auth sufficient pam_fprintd.so" > /etc/pam.d/i3lock-fprint Then, build and launch i3lock with the Please note that this is very much a work in progress. There is a ton of thing that need improvement (signal handling, feedback UI) as I am not familiar yet with libev, X, nor PAM. |
Thank you very much for looking into this and summarizing, this is very helpful. In my cursory read, it seems like you only ever look at The overall architecture of spawning a helper process to handle this seems reasonable to me. |
@stapelberg correct, at the moment only |
@kaworu I don't think you need two pam stacks. A single one should be sufficient. You just need to start that one earlier so you can get the message from PAM on what input is expected. If you trigger PAM right after i3lock starts, the issue is that there can be timeouts in case you don't provide the fingerprint input in a timely manner which will never be the case. In a POC I modified the There are be two main changes/open questions required for it.
(1) is import due to the input timeout issue described above. Maybe there is a way to skip it but I am not sure. (2) the current process is to store the password on the first input. This password is stored and used as soon as PAM expects an input. If your first PAM rule is to use fingerprint and it fails, it will jump to the password and hand over that password. This isn't logical (enter password while you can still use fingerprint) and can be confusing (first input is the password? Or can I enter it again? But on the 2nd run the first authentication will be fingerprint again, ...). Backward compatibility to not confuse existing users will be one challenge here. One user presses enter to use fingerprint, but if it fails the user expects to get a way to input the password. Another user wants to use the password only but doesn't want to enter it twice. |
The advantage of @kaworu’s approach is that you don’t need to worry about this. The fingerprint reader will be picked up when used, and doesn’t require extra steps. That is what we should strive for. |
After digging, I'm not sure we can get away without interaction to trigger PAM. From the libfprint-fprintd README:
This mean we should avoid having the fingerprint reader always on. The default timeout is 30 seconds. Once fprintd timeout, I think we need to wait some kind of interaction (being mouse event or keyboard) before triggering it again.
@volker-fr from my experimentation fprint will block while reading the fingerprint and during that time we are unable to collect and/or submit the password input. The README hint towards two PAM stack, but if there's a way to handle both password and fingerprint with only one PAM stack I am all ears as PAM is new to me. |
I am still slowly making progress on this. My latest diff is at https://github.com/kAworu/i3lock/tree/fprintd-without-imsg. This patch simply use pipes for IPC as suggested by @stapelberg. After thinking a bit we're not a PAM friendly application (i.e. we don't display conversation messages) so I agree that it is better to avoid the complexity of bringing imsg & al. in tree. We start the fingerprint reader when i3lock is launched with
Notice that outside of the PAM conversation there is no way to tell the difference between a timeout and an auth failure as in both cases we get Other than that, here is what I think is also required before it could be made a PR:
Any testing, feedback, and comment welcome! |
@kaworu Thanks so much! I wish I was a C developer and could help with development, but unfortunately I'm not. I help with testing if possible. |
Great work. I actually would suggest printing the PAM message to the screen. Even if you have a fingerprint reader, how do you know which finger to put on? How do you know if you have to put your finger on it again after it timed out or failed at the first try? See volker-fr@2ce7800 for a way on how you could hand over the pam msg to the screen. |
Any update on this issue? |
@f0s3 I haven't found time to make progress on this sadly. The items outlined here are still TODO. Additionally, I'm having trouble with fprintd after suspend. My patch will repeatedly trigger authentication failure and unable to login. This could be a driver bug but we need to check whether we can disable fprintd when it behave like this (I think it is possible because sudo / login seems to do so). |
Any updates on this? Also does i3lock really not support it, or something else is there on the issue? I see somebody using it without any problem https://www.reddit.com/r/i3wm/comments/gzk4hw/i3lock_fingerprint_only just like in any display manager, adding a line to the i3lock pam config placed at /etc |
I just saw a reddit post posted about a month ago, they also seem to confirm they are able to use it with PAM methods https://www.reddit.com/r/i3wm/comments/no2u72/unlocking_i3lock_with_your_fingerprint I'm not able to understand if this issue is an active issue, or is it just resolved already? |
It does seem to work, it's just not very user friendly (at least for me). I have to submit a random password to get the fingerprint sensor to listen and there is no visual feedback for when the fingerprint sensor is listening, if the scan fails etc. |
for me this is the exact problem. my setup is slightly different, using howdy instead of fingerprint, but I would like to be able to unlock my screen while in tablet mode with the help of howdy. I can have it as a fallback, so entering a faulty password works to unlock it. but I would like to be able to trigger the unlock call in another way. what might be a solution for me is: have some other key then enter that can trigger a unlock. this way I could for example have the "power on" button triggering the unlock. |
* Clarify brace behaviour (i3#217) * Add comment Co-authored-by: Raymond Li <[email protected]>
I have read through this issue again, and also the other related issues (#210, #286, #38). A common theme is that i3lock’s current architecture is not well-suited to PAM’s model of calling back into the application with request/response messages. Currently, i3lock just answers all requests with the password buffer and hopes for the best. I think I have an idea for how to change i3lock’s design to better match PAM: we could change i3lock to work in a prompt-oriented fashion, where the main event loop returns (using In terms of code changes, the following changes would be required (at the very least): --- i/i3lock.c
+++ w/i3lock.c
@@ -224,7 +224,7 @@ static void finish_input(void) {
password[input_position] = '\0';
unlock_state = STATE_KEY_PRESSED;
redraw_screen();
- input_done();
+ ev_break(main_loop, EVBREAK_ONE);
}
/*
@@ -269,6 +269,8 @@ static void discard_passwd_cb(EV_P_ ev_timer *w, int revents) {
STOP_TIMER(discard_passwd_timeout);
}
+static bool successfully_authenticated = false;
+
static void input_done(void) {
STOP_TIMER(clear_auth_wrong_timeout);
auth_state = STATE_AUTH_VERIFY;
@@ -292,6 +294,7 @@ static void input_done(void) {
if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
DEBUG("successfully authenticated\n");
clear_password_memory();
+ successfully_authenticated = true;
/* PAM credentials should be refreshed, this will for example update any kerberos tickets.
* Related to credentials pam_end() needs to be called to cleanup any temporary
@@ -1267,7 +1276,11 @@ int main(int argc, char *argv[]) {
* received up until now. ev will only pick up new events (when the X11
* file descriptor becomes readable). */
ev_invoke(main_loop, xcb_check, 0);
- ev_loop(main_loop, 0);
+ while (!successfully_authenticated) {
+ ev_run(main_loop, 0);
+ DEBUG("break called, input done\n");
+ input_done();
+ }
#ifndef __OpenBSD__
if (pam_cleanup) {
What this design makes possible is that we now can run a nested main loop from within the PAM --- i/i3lock.c
+++ w/i3lock.c
@@ -806,6 +808,10 @@ static int conv_callback(int num_msg, const struct pam_message **msg,
msg[c]->msg_style != PAM_PROMPT_ECHO_ON)
continue;
+ DEBUG("--- nested i3lock main loop ----\n");
+ ev_run(main_loop, 0);
+ DEBUG("--- nested i3lock main loop RETURNED ----\n");
+
/* return code is currently not used but should be set to zero */
replies[c].resp_retcode = 0;
if ((replies[c].resp = strdup(password)) == NULL) { This means we can change the rendering code to display a prompt, and ask the user different questions as PAM asks for: We would set the prompt, run the main loop with I’m thinking in terms of rendering, the current prompt (if any) should go above the unlock indicator. Any PAM informational messages or PAM error messages can be displayed below the unlock indicator (think like smartphone notifications). From a UX perspective, i3lock displays the lock screen and waits for you to answer its prompt, either with a password (matching the current usage), or with an empty password buffer just pressing enter. If PAM is configured to directly prompt for a password, i3lock takes the password that the user entered and unlocks (current behavior) or, for more complex PAM configurations, i3lock asks for a challenge, fingerprint, password, etc. until PAM returns success or failure. If anyone wants to give this approach a shot, please post here and send a PR :) In case you have more questions about the design, or notice something that would break or wouldn’t work, feel free to ask! PS: For testing, I found it helpful to install the https://sources.debian.org/src/mariadb-10.6/1:10.6.9-1/plugin/auth_pam/testing/pam_mariadb_mtr.c/ PAM test module. |
I want to point out this fork of swaylock: swaywm/swaylock@master...SL-RU:swaylock-fprintd:fprintd It adds fingerprint scanning support by calling the fprintd dbus service directly. It activates the fingerprint scanner while the lockscreen is running, to unlock as soon as the fingerprint is scanned. This allows you to still enter a password and authenticate with the password without using the fingerprint. I quite like this solution. Then there's this fork of i3lock: main...YiPrograms:i3lock-powerbtn-fingerprint:main |
I'd like to restate und +1 i3/i3lock#286.705256134:
Seeing that message in the lock screen is crucial, no matter the mechanism. |
I'm submitting a…
Current Behavior
Currently you need to submit a password to trigger any PAM method, so just fingerprint won't work. For some reason I actually need to supply both a valid password and fingerprint when fingerprint-gui is enabled.
Expected Behavior
Unlock with just fingerprint, or just password.
Environment
Output of
i3lock --version
:The text was updated successfully, but these errors were encountered: