ChocolateLoverRaj / pam-any

A PAM module that runs multiple other PAM modules in parallel, succeeding as long as one of them succeeds.
Apache License 2.0
8 stars 0 forks source link

Don't block non-promt conversations services while another service is promting #2

Closed skruppy closed 5 months ago

skruppy commented 5 months ago

Test setup

In order to authenticate to su suing password OR fingerprint I used the following setup. Relevant contents of /etc/pam.d/su:

[...]
auth            required        pam_any.so {"any-fingerprint": "Fingerprint", "any-password": "Password"}
[...]

Content of /etc/pam.d/any-fingerprint:

auth            required        pam_fprintd.so
account         required        pam_permit.so

Content of /etc/pam.d/any-password:

auth            required        pam_unix.so
account         required        pam_permit.so

Problem description

When trying to authenticate using a fingerprint, the authentication does not succeed until a (invalid/empty) password is provided as shown here:

$ pamtester su skruppy authenticate
[Password] Password: 
[Fingerprint] Place your right index finger on the fingerprint reader
pamtester: successfully authenticated

Cause of the issue

This is caused by pam_unix always being faster asking for a password than pam_fprintd wanting to print some informational notices. Due to the mutex placed on the upstream conversation, the progress of pam_fprintd is halted at the output request of the info message until an user input has been provided to pam_unix. Hence the pam_fprintd module never returns any result before pam_unix.

Possible solutions

Reply non-promt requests from queue

For non promt_* calls like info() or error() add them to a queue during an ongoing promt-call and reply them once the promt is done.

Combine non-promt requests

For non promt_* calls like info() or error() collect the messages in a single concatenated message during an ongoing promt-call. Send this concatenated message once the promt-call has finished.

This has the advantage that GUIs which might only show a single message at a time do not only show the last queued message, but all of them.

ChocolateLoverRaj commented 5 months ago

I think the key part of both possible solutions is adding to a queue instead of blocking. Maybe there can be an option to combine non-prompt requests.

ChocolateLoverRaj commented 5 months ago

The simplest (but may not be best) solution I can think of is to create a new thread which acquires a mutex lock and sends info messages instead of directly acquiring a mutex lock.