Skip to content
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

Add native PAM module #484

Merged
merged 61 commits into from
Apr 18, 2022
Merged

Add native PAM module #484

merged 61 commits into from
Apr 18, 2022

Conversation

saidsay-so
Copy link
Collaborator

@saidsay-so saidsay-so commented Dec 26, 2020

Summary

This pull request introduces a native PAM module (written in C++) which waits for user input and asynchronously perform the face comparison.

Based on #9, I first tried to wait for the first event which responds, but since pam_get_authtok (the function which ask the user password) is blocking on the application-side, we have to wait for the user to fill the password and can't perform authentication on background.

What approach should we use then?

Related

#99, #9, #478, #456

Signed-off-by: MusiKid <musikid@outlook.com>
@boltgolt
Copy link
Owner

Thank you so much for this implementation! I tried writing this exact thing before but I'm just not good enough in C++, as you've probably read in one of the issues you've linked

The blocking issue is an annoying one. I tried to figure out how fingerprint-gui managed to get that to work. The fingerprint PAM module accepts both a password or your fingerprint and authenthecates based on whatever it got first. Maybe the answer is burried in its (pretty hard to read) source?

@saidsay-so
Copy link
Collaborator Author

I read the FingerprintGui source code, and the method that it uses to circumvent the blocking issue is dirty...
It spawns an helper process which sends Enter when the user validates the fingerprint. I'm not sure of how reliable it is since the user could change the focused application and the input could not be sent then to the prompt. We would also have to write an helper process, which increases the difficulty.
Our best chance would be to wait for linux-pam/linux-pam#301 (hopefully) getting a proper implementation.

@boltgolt
Copy link
Owner

Waiting for the PAM implementation is going to take a long while though. Not only does it have to be coded and merged, it's going to take years to be reliably available on all the distros

I really like the suggestion @X-Ryl669 posted in that thread though, could we write our own internal version of pam_any? Where waiting for the user password and running howdy are separate threads?

@saidsay-so
Copy link
Collaborator Author

You are right about the time that it would take to wait before an implementation 😅️.
For pam_any, I don't think it's possible because like I said before, pam_get_authtok is blocking on application-side. The problem is not writing a module which supports waiting asynchronously, but rather the fact that PAM functions cannot be canceled safely.

@boltgolt
Copy link
Owner

Ah sorry, i misunderstood what you meant by blocking on the application-side in your first post. Very annoying that PAM has no way to make this work without a hack.

Do you think it would be acceptable to implement the hacky workaround (sending a keypress from the Howdy python thread) as an experimental config option that is disabled by default?

@saidsay-so
Copy link
Collaborator Author

It's definitely possible, but it would require more work and also granting root access to the Python process because if we want to simulate a key press, we need to use /dev/uinput, which by default is only accessible to root.

@boltgolt
Copy link
Owner

boltgolt commented Jan 1, 2021

I've done some small testing with the python pam.py and i seem to be able to access /dev/uinput. As far as i know PAM modules run with root-like rights

@saidsay-so
Copy link
Collaborator Author

PAM modules runs with root rights only if the application is setuid and the owner is set to root (see http://www.linux-pam.org/Linux-PAM-html/mwg-see-programming-sec.html). Even if it's uncommon and I am not aware of a real use case, it's possible to run a PAM module without root rights. You can test it easily with pamtester and geteuid().

@boltgolt
Copy link
Owner

boltgolt commented Jan 2, 2021

Well, that solves the /dev/uinput problem then, right? The current implementation runs python as root too although that might not be ideal

@saidsay-so
Copy link
Collaborator Author

I think yes. The only problem now is how to communicate to PAM module that the Enter key was pressed by the comparator. I'm thinking about implementing it like FingerprintGui, which means using a pipe between Python and the module.

@saidsay-so
Copy link
Collaborator Author

We also need to think about how we should handle the failure of the face recognition.

@boltgolt
Copy link
Owner

boltgolt commented Jan 6, 2021

I've been thinking about this over the last few days. We could simply use the returned status code from the python process to see if enter was pressed or not. Certain codes should only be used if enter is pressed successfully. I've made a quick chart:

image

src/compare.py Outdated Show resolved Hide resolved
src/compare.py Outdated Show resolved Hide resolved
src/compare.py Outdated Show resolved Hide resolved
src/compare.py Outdated Show resolved Hide resolved
@saidsay-so saidsay-so force-pushed the native_pam branch 3 times, most recently from 45a152f to 13800c9 Compare January 17, 2021 16:26
Signed-off-by: MusiKid <musikid@outlook.com>
@saidsay-so
Copy link
Collaborator Author

Nice chart!
It should work now... I put some instructions in the README to build it. It needs way more testing to be considered stable but it is usable.

@ccat3z
Copy link

ccat3z commented Jan 18, 2021

Perhaps asking for the password in a new thread would avoid simulating enter press. Just cancel password prompt thread after howdy python process was returned.
I tried to use pthread to wrap pam_get_authtok to an asynchronous version in C and it seems work. Maybe useful for this pr.
See pam_async_ext.h and pam_async_ext.c.

@saidsay-so
Copy link
Collaborator Author

I'm confused...
It is written nowhere that the conversation function (used by pam_get_authtok under hood) is a cancellation point and yet, doing what said @ccat3z works! (not all time though)
Do you encounter a problem with sudo? It needs the enter key press on my machine.

@saidsay-so
Copy link
Collaborator Author

Thanks @ccat3z for the tip BTW!

@saidsay-so
Copy link
Collaborator Author

It seems to work only on some programs (only pamtester AFAIK).

@ccat3z
Copy link

ccat3z commented Jan 18, 2021

I'm confused...
It is written nowhere that the conversation function (used by pam_get_authtok under hood) is a cancellation point and yet, doing what said @ccat3z works! (not all time though)
Do you encounter a problem with sudo? It needs the enter key press on my machine.

No such problem on my laptop. sudo/pkexec/gdm works without press enter key.

@saidsay-so
Copy link
Collaborator Author

Nevermind, it was just a stupid bug. Thanks a lot for the tip!

@boltgolt
Copy link
Owner

This is amazing input @ccat3z! I think we're branding this as experimental anyway so if it does not work in some instances that's okay

Signed-off-by: MusiKid <musikid@outlook.com>
@ccat3z
Copy link

ccat3z commented Jan 24, 2021

After several days of daily use, I found that it is not always safe to cancel conv's threads. As @musikid said in linux-pam/linux-pam#301 (comment), conv is not always a cancellation point and resources may not be released too.
Here are some instances:

  1. pamtester or other cli applications like sudo will turn off echo when retrieve password (stty -echo), input will not print after pam success. (pamtester -v test-howdy username authenticate; read and type in anything.)
  2. ligthdm with lightdm-gtk-greeter hangup randomly after cancel conv thread. I'm not sure what happened, I'm not familiar with lightdm.

@saidsay-so
Copy link
Collaborator Author

Should I change the base branch for the beta one?

@boltgolt
Copy link
Owner

Yes that would be perfect! The beta branch will be 3.0.0 in a future that's hopefully soon (next few months?)

Thank you so much for all the hours you have put into this PR and the repo as a whole!

@saidsay-so saidsay-so changed the base branch from master to beta February 5, 2022 13:16
])


# Make sure we were given an username to tast against
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Misspell] "tast" is a misspelling of "taste" (view)

Rule Correct Incorrect
taste taste tast

You can close this issue if no need to fix it. Learn more.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think that's quite right...

@saidsay-so
Copy link
Collaborator Author

Hmm, I should probably reverse the last commit and resolve the conflicts manually...

@saidsay-so
Copy link
Collaborator Author

I was able to resolve the conflicts and rebase against beta, however it implies that I need to force-push the entire branch.
All metadata should be preserved, of course, but is it a problem if I do it?

@boltgolt
Copy link
Owner

boltgolt commented Apr 2, 2022

@musikid if that's the only solution then try it. This is force pushing your own branch right, not boltgolt/howdy?

@saidsay-so
Copy link
Collaborator Author

Yes, it will not touch it, of course! It's just that it will “pollute” a little more the log.

@boltgolt boltgolt merged commit 1c5dab4 into boltgolt:beta Apr 18, 2022
@boltgolt
Copy link
Owner

Took 1,5 years but this is finally merged! Thanks so much to @musikid and all others in this thread

@wmmc88
Copy link

wmmc88 commented May 13, 2022

This removes the dependency on python2(as mentioned in #535 ), right? Is there going to be a 3.0.0 release soon?

@boltgolt
Copy link
Owner

I would like that too, but there is still work to be done on getting this out as a beta and after that we can do a general release, probably late summer?

@boltgolt
Copy link
Owner

boltgolt commented Jun 19, 2022

@muskid testing the beta release of 3.0.0 i'm getting this error in the PAM log:

pkexec: PAM unable to dlopen(/lib/security/howdy/pam_howdy.so): /lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by /lib/security/howdy/pam_howdy.so)

Seems to be one symbol that's the issue:

$ readelf --dyn-syms pam_howdy.so | grep '@GLIBCXX_3.4.29'
24: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZNSt28__atomic_futex_uns@GLIBCXX_3.4.29 (11)

You're more comfortable with the whole c++ part of it, how would i go about using no version higher than GLIBCXX_3.4.28 that's available on Ubuntu 20.04?

@saidsay-so
Copy link
Collaborator Author

This shouldn't cause any problem AFAIK.

@boltgolt
Copy link
Owner

Welll it's a fatal error, so howdy does not start up at all because of that

@saidsay-so
Copy link
Collaborator Author

saidsay-so commented Jun 19, 2022

You also need to rebuild it against the lower version of libstdc++. If I understand correctly, since you target Ubuntu 20.04, then you need to build the module on it too.

@saschaeggi
Copy link

saschaeggi commented Nov 6, 2023

@musikid can we get a new release which includes this new awesome feature?

@saidsay-so
Copy link
Collaborator Author

The release is still in the works but should come out ASAP.

@Doomsdayrs
Copy link

The release is still in the works but should come out ASAP.

do you need any help?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.