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

Design: Handle complex PAM authentifications #244

Open
VannTen opened this issue Jun 8, 2022 · 16 comments
Open

Design: Handle complex PAM authentifications #244

VannTen opened this issue Jun 8, 2022 · 16 comments

Comments

@VannTen
Copy link

VannTen commented Jun 8, 2022

Hello,

I started to play with my Yubikeys recently and would like to work on swaylock
so it can handle the UI part a bit better.

(The objective would be to fix #61 and #213)

I'm not super familiar with the codebase so I wanted to check with you before
starting to code.

As I understand, currently, swaylock handle the auth process in a separate
process, which communicates with the main one (doing rendering, event looping
etc) using pipes. (in pam.c and comm.c). The main process pass the password
string and the "auth" process respond with ok/ko (it's a simplification)

In order to support "richer" conversation with PAM, we need:

  1. A way to send back a string from the "auth" process to the main one, so it
    can displays prompts from PAM.
  2. Displaying that string, so probably a new surface in the rendering part.
  3. Some modification the control flow in the "auth" process.

My first question, should I re-use the same pipe used to communicate the
password string to the child process to send back prompt string, or should I use
a dedicated one, something else altogether ? (Is there a particular policy on
how the password is handled, or something like that ?)

Secondly, I think the control flow should be driven by the code in pam.c,
particularly in the handle_converstation fonction. The initial state of
swaylock (requiring a password, prompting user to insert a token, etc) will
depend on the particular pam configuration and what msg_style pam has sent us.
That seems like a big change so would it be ok ?

I think we need two new states (for lack of a better word):

  1. prompting the user for action, then confirm (ex: insert u2f keys, press
    ENTER)
  2. prompting the user for action, pass control to PAM (ex: touch your u2f key).

Those two could be assimilated, to, respectively, the AUTH_SPACE_INPUT (writing
the password) and AUTH_STATE_VALIDATING ("verifying") (which is mostly what's
going on currently I think) but it's not a very clear UX.

I'm only testing with a Yubikey (using pam_u2f) so I'm only considering those
states/action right now but if you see other cases don't hesitate to mention it.


I would very much appreciate feedback on this very rough sketch, or things you
think I should think about, or questions if I'm not clear.

@NgoHuy
Copy link

NgoHuy commented Dec 9, 2022

I have another case, if I used auth required bose yubikey and password, swaylock never asks for password, only once for yubikey pin. I tested on KDE, it's same as swaylock.

@hramrach
Copy link

So basically you have multiple passwords. That generally falls into the 'control flow should be driven by pam' as in if and when a password is requested depends on pam configuration, and the hardcoded flow to send one password and wait for something to happen is not suited for all cases.

@hramrach
Copy link

Also this would be #270

@VannTen
Copy link
Author

VannTen commented Sep 12, 2024 via email

@hramrach
Copy link

I do not really see how that conversation function is text-specific. The only obvious problem is that the prompt sent by PAM may be much longer than what can fit into the swaylock circle. That is, however, swaylock design choice, not limitation of graphic applications in general.

@hramrach
Copy link

I see, it does not tell you if it expects an in-band (eg. password) or out-of-band (eg. touching sensor) response from the user.

@VannTen
Copy link
Author

VannTen commented Sep 12, 2024 via email

@hramrach
Copy link

The input to misc_conv are the callback pointers. So if you want callback pointers then you should not call the function, and use the pointers.

@kennylevinsen
Copy link
Member

As long as the sequence is strictly ordered with nothing happening in parallel (e.g., not attempting to allow fingerprint or password, whichever is first), the only issues are:

  1. swaylock does not show conversation questions and prompts, and instead assumes that it will only need to answer 1 secret question. This could be extended to allow displaying prompts, but we would like to maintain the "no prompt" mode for passwords.

  2. PAM conversations are blocking, so if a PAM module prompts you to interact with e.g. a security key, the PAM module is stuck waiting for swaylock to advance the flow, which in turn requires pressing enter even on plain notice messages.

That is, if swaylock is made to show notices and wait for enter on these, and take input as many times as PAM asks for it rather than assume only one input, then it should work.

It read and writes from tty (look at the read_string helper)

Nothing within swaylock or PAM modules should read from/write to a tty.


If you guys want to do a live discussion, maybe consider #sway-devel @ irc.libera.chat.

@hramrach
Copy link

What blocks the flow, though?

Why is pressing enter required to use a security key, that looks superfluous.

And why can't swaylock advance the flow, even if pam itself would block (provided that the information that the prompt does not require a reply is available)?

@kennylevinsen
Copy link
Member

PAM is a blocking API. swaylock cannot continue past pam_authenticate until all the PAM modules in the PAM stack are done, and a PAM module in that stack making conversation cannot continue until swaylock returns from the conversation function.

swaylock cannot return from the conversation function until the requested response is obtained, as obtaining the response is the whole point of the conversation function. There is also no way for a PAM module to "cancel" a conversation, so once a question or notice is presented, you're stuck until a response is given. The only way for a PAM module to wait for something other than the user is to not ask a question in the first place, but then you have no UI.

Advancing blindly on info or error conversations might lead to problems. E.g., if you assume that you can just show an info prompt in a sticky way and advance, if that info message is the last message in the authentication flow and nothing further is required from the user, swaylock will end up exiting before the user had a chance to read it. This isn't as much of an issue when dealing with login(1), sudo(1) or ssh(1) where any messages stay on the terminal after successful or attempted login.

Note that all this is discussion about adding the support for info and error messages. Right now, swaylock ignores any info and error message, and answers any question with the typed password, no matter what the questions are and how many times they ask.

@VannTen
Copy link
Author

VannTen commented Sep 12, 2024

Regarding the "parallel auth", (out of scope here)

For more details why the "any of " scheme is hard/not doable with PAM, see linux-pam/linux-pam#301

As long as the sequence is strictly ordered with nothing happening in parallel (e.g., not attempting to allow fingerprint or password, whichever is first)

Theoretically, with the current stack PAM, I think 'no-input' methods could happen in parallel, because swaylock can
just display some stuff and return (in the conversation function, I mean), and the PAM module would handle the rest
(something like the pam-any alluded to in the above discussion, there is apparently a POC).

(as long as swaylock handle all of the PAM messages in the array received by the conversation function)

Anything that needs a actual pam response with content would prevent that though, for the reasons you mention.

But that's not really swaylock problem, so, out of scope for this discussion


the only issues are:

  1. swaylock does not show conversation questions and prompts, and instead assumes that it will only need to answer 1 secret question. This could be extended to allow displaying prompts, but we would like to maintain the "no prompt" mode for passwords.

This should be handled by treating PAM_PROMPT_ECHO_OFF and PAM_PROMPT_ECHO_ON differently (from man 3 pam_conv).

  1. PAM conversations are blocking, so if a PAM module prompts you to interact with e.g. a security key, the PAM module is stuck waiting for swaylock to advance the flow, which in turn requires pressing enter even on plain notice messages.

-> PAM_TEXT_INFO

That is, if swaylock is made to show notices and wait for enter on these, and take input as many times as PAM asks for it rather than assume only one input, then it should work.

What I'm wondering is how should multiples PAM messages (in one call to the conversation function) should be handled,
UI-wise, in particular when there is more than one PAM_PROMPT_* message, because it would mean multiple input fields.
Should there be one circle per message, maybe a different form or some distinguishing details for the one requiring input,
and some way to switch between input fields and to indicate which one has focus ?

@hramrach
Copy link

While theoretically possible are there PAM modules that would require more than one input at once?

Designing the UI for multiple inputs would be challenging, and there is no point going through that if it's never used in practice.

@kennylevinsen
Copy link
Member

What I'm wondering is how should multiples PAM messages (in one call to the conversation function) should be handled,

You'd go with the same style as for a text-based prompt: presenting and processing them in sequence. A fancier UI with actual input fields could handle it differently, but swaylock is not that.

-> PAM_TEXT_INFO

See note from above:

Advancing blindly on info or error conversations might lead to problems. E.g., if you assume that you can just show an info prompt in a sticky way and advance, if that info message is the last message in the authentication flow and nothing further is required from the user, swaylock will end up exiting before the user had a chance to read it. This isn't as much of an issue when dealing with login(1), sudo(1) or ssh(1) where any messages stay on the terminal after successful or attempted login.

@hramrach
Copy link

Advancing blindly on info or error conversations might lead to problems. E.g., if you assume that you can just show an info prompt in a sticky way and advance, if that info message is the last message in the authentication flow and nothing further is required from the user, swaylock will end up exiting before the user had a chance to read it.

That special case that it's the last message can be detected, there is no reason to block on informational messages otherwise.
There is still the problem that swaylock is not really set up for displaying messages longer than one word, and complex PAM authentication flows may require that to be intelligible.

@VannTen
Copy link
Author

VannTen commented Sep 13, 2024 via email

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

No branches or pull requests

4 participants