Skip to content

pam: Set PAM_AUTHTOK on successful authentication - #1190

Merged
adombeck merged 11 commits into
mainfrom
UDENG-8799-pam-set-authtok
Jul 7, 2026
Merged

pam: Set PAM_AUTHTOK on successful authentication#1190
adombeck merged 11 commits into
mainfrom
UDENG-8799-pam-set-authtok

Conversation

@adombeck

@adombeck adombeck commented Jan 13, 2026

Copy link
Copy Markdown
Contributor

By setting PAM_AUTHTOK the GNOME keyring is unlocked.

Closes #944
UDENG-8799

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.64%. Comparing base (01cd78c) to head (22bc3d5).
⚠️ Report is 11 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1190      +/-   ##
==========================================
+ Coverage   87.53%   87.64%   +0.11%     
==========================================
  Files          91       91              
  Lines        6231     6231              
  Branches      111      111              
==========================================
+ Hits         5454     5461       +7     
+ Misses        717      714       -3     
+ Partials       60       56       -4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@adombeck
adombeck marked this pull request as ready for review January 13, 2026 16:09
@adombeck
adombeck requested a review from a team as a code owner January 13, 2026 16:09
@adombeck
adombeck requested a review from 3v1n0 January 13, 2026 16:09
@3v1n0

3v1n0 commented Jan 13, 2026

Copy link
Copy Markdown
Contributor

This would be fine per the current broker, but we have the problem that we don't handle the change password phase well (as per #944 (comment)).

And so, without it we may just end up having the token just set once and then be broken by a password change.

Then, the problem, daemon side, is that we do not have the information to know whether the broker supports secrets or not to be sure if we should set this all the times.

So the token that we are setting may be:

  • Unset (if we login without local password, in potential brokers without it)
  • Change depending on the authentication method that has been chosen (imagine a broker supporting a PIN or a Password)

Thus again, this is something that IMHO we should not do without the broker providing us the AuthTok to set.

My idea to have something more generic was:

  • The broker defines an unique token that is invisible to the user
  • The token is sent to PAM on auth and we use it as the keyring password.

PRO: Independent from authentication mode being used
CONS: If the user logout from a keyring inside the session, currently we have no way to unlock it (we could do it through PAM, but it needs some UI work)

For the current situation, we could workaround the problem by keeping a similar structure, but sending back the very same secret that has been used by the user to authenticate.

In this way we still leave the control to the broker, but also we should be able to use the information only if it's possible.

However, in general I'd personally prefer to handle it all together (I mean, also once the passwd case is fixed), rather than having half-baked solutions, since this is the reason why we did not do this in the beginning.

@adombeck

Copy link
Copy Markdown
Contributor Author

This would be fine per the current broker, but we have the problem that we don't handle the change password phase well (as per #944 (comment)).

I read that comment before opening the PR but I don't understand the issue. We only support changing the password after a successful device authentication, in which case the same code path is taken and we set PAM_AUTHTOK. I tested that after changing the password by doing device authentication again the keyring is still successfully unlocked.

@3v1n0

3v1n0 commented Jan 13, 2026

Copy link
Copy Markdown
Contributor

We only support changing the password after a successful device authentication, in which case the same code path is taken and we set PAM_AUTHTOK. I tested that after changing the password by doing device authentication again the keyring is still successfully unlocked.

I need to check again the keyring pam code, but that was expected I think when using passwd.

@adombeck

Copy link
Copy Markdown
Contributor Author

I need to check again the keyring pam code, but that was expected I think when using passwd.

I also tried passwd already, also works fine.

@3v1n0

3v1n0 commented Jan 13, 2026

Copy link
Copy Markdown
Contributor

Also if the one authenticating to use passwd is not the same user we change the password for?

@adombeck

Copy link
Copy Markdown
Contributor Author

Also if the one authenticating to use passwd is not the same user we change the password for?

I'll try that.

@adombeck

Copy link
Copy Markdown
Contributor Author

Also if the one authenticating to use passwd is not the same user we change the password for?

It's always asking for the password of the user actually: #851

@adombeck

Copy link
Copy Markdown
Contributor Author

Also if the one authenticating to use passwd is not the same user we change the password for?

Yes, the keyring is also unlocked when I change the password via sudo passwd in another user's session (which still requires the user's local password) and afterwards log in via GDM with the new password.

@adombeck

adombeck commented Feb 2, 2026

Copy link
Copy Markdown
Contributor Author

With #1234 we will have the case that there is no local password. I think authd could instead generate a secret the first time the user authenticates and set PAM_AUTHTOK to that when the user authenticates successfully. We could use systemd credentials to encrypt the secret with the TPM.

That is similar to your suggestion @3v1n0, but I think it makes more sense to let authd generate that secret than the broker, because there's nothing broker-specific about that secret. WDYT?

@adombeck
adombeck force-pushed the UDENG-8799-pam-set-authtok branch from 22bc3d5 to 2f5d0e1 Compare February 3, 2026 18:42
@codecov

codecov Bot commented Feb 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.89%. Comparing base (4bd2fba) to head (4359c7a).
⚠️ Report is 31 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1190   +/-   ##
=======================================
  Coverage   87.89%   87.89%           
=======================================
  Files          96       96           
  Lines        6965     6974    +9     
  Branches      111      111           
=======================================
+ Hits         6122     6130    +8     
- Misses        787      788    +1     
  Partials       56       56           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@adombeck
adombeck force-pushed the UDENG-8799-pam-set-authtok branch from 2f5d0e1 to 2dac51d Compare February 3, 2026 19:45
@adombeck

adombeck commented Feb 3, 2026

Copy link
Copy Markdown
Contributor Author

@3v1n0 and I discussed this today.

A reason to let the broker decide which secret to use is that it allows using the local password if there is one, which allows the user to unlock the keyring themself with that password in case that the keyring is locked during a session. That won't be possible without UI changes if we use an authd-generated secret instead. However, locking and unlocking the screen could be a workaround to also unlock the keyring in that case.

An issue if we do use the local password as the keyring secret is that it won't be updated if the disable_local_password setting is activated after a user already set a local password. That case would be fixed if we would always use an authd-generated secret instead.

@adombeck
adombeck force-pushed the UDENG-8799-pam-set-authtok branch from 2dac51d to cfab192 Compare February 3, 2026 23:37
@adombeck

adombeck commented Feb 4, 2026

Copy link
Copy Markdown
Contributor Author

braindumping an idea:

  1. local password enabled -> broker returns that with the auth result and PAM module sets PAM_AUTHTOK to it
  2. local password is disabled -> broker sees that local password was disabled but that there is one already stored in the data dir (the hashed password file), so it knows that we need the local password to change the keyring password
    2.1. broker only offers local password but sets next auth mode to device auth
    2.2 auth result contains local password, authd generates a random secret and stores it in its data directory as a systemd credential
    2.3 PAM module changes the keyring password from the local password to the generated secret
    2.4 user continues with device authentication
    2.5 broker deletes hashed password file

@shiv-tyagi

shiv-tyagi commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

2. broker sees that local password was disabled but that there is one already stored in the data dir (the hashed password file), so it knows that we need the local password to change the keyring password

What do we do in the other scenario where the local password is enabled back and there is a secret but no password file?

Do we perform the similar steps with password and secret swapped, i.e., changing the keyring password with secret and moving ahead with the local password?

@3v1n0

3v1n0 commented Feb 10, 2026

Copy link
Copy Markdown
Contributor

Do we perform the similar steps with password and secret swapped, i.e., changing the keyring password with secret and moving ahead with the local password?

That is technically possible, although risky (as the module may fail and us not discover it), but it's currently the only possibility.

Ideally having a keyring that supports multiple secrets would be nice.

@shiv-tyagi

Copy link
Copy Markdown
Contributor

Ok. Please feel free to let me know if my help is needed there, I will be happy to help. I will rebase #1234 after that.

@adombeck
adombeck force-pushed the UDENG-8799-pam-set-authtok branch from cfab192 to d0544ad Compare April 16, 2026 13:38
@adombeck

Copy link
Copy Markdown
Contributor Author

@3v1n0, regarding our discussion, this would handle the MFA case you mentioned, right?

diff --git a/pam/internal/adapter/authentication.go b/pam/internal/adapter/authentication.go
index 9c920c52d..67eeefa91 100644
--- a/pam/internal/adapter/authentication.go
+++ b/pam/internal/adapter/authentication.go
@@ -349,6 +349,8 @@ func (m authenticationModel) Update(msg tea.Msg) (authModel authenticationModel,
 			var secret string
 			if msg.secret != nil {
 				secret = *msg.secret
+			} else if m.currentSecret != "" {
+				secret = m.currentSecret
 			} else {
 				log.Warningf(context.Background(), "authentication granted, but no secret returned, cannot set PAM_AUTHTOK")
 			}

@adombeck
adombeck force-pushed the UDENG-8799-pam-set-authtok branch from d0544ad to c44302e Compare April 17, 2026 11:54
@3v1n0

3v1n0 commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

@3v1n0, regarding our discussion, this would handle the MFA case you mentioned, right?

diff --git a/pam/internal/adapter/authentication.go b/pam/internal/adapter/authentication.go
index 9c920c52d..67eeefa91 100644
--- a/pam/internal/adapter/authentication.go
+++ b/pam/internal/adapter/authentication.go
@@ -349,6 +349,8 @@ func (m authenticationModel) Update(msg tea.Msg) (authModel authenticationModel,
 			var secret string
 			if msg.secret != nil {
 				secret = *msg.secret
+			} else if m.currentSecret != "" {
+				secret = m.currentSecret
 			} else {
 				log.Warningf(context.Background(), "authentication granted, but no secret returned, cannot set PAM_AUTHTOK")
 			}

Yeah, unless the fact that if there are multiple fields, we may pick the wrong one (so I'd still use the last secret if that it's the one that provided the granted access)... But in case that there is one form and then a non-form entry, it would work.

It's tricky in the case that we have a Password authentication first and then an OTP for example, we can maybe do assumptions on the visibility of the form.. But well, as you know this is the reason why I liked the broker to drive all this.

@adombeck

Copy link
Copy Markdown
Contributor Author

It's tricky in the case that we have a Password authentication first and then an OTP for example.

True, but changing the password is also broken in that case. Like I said in our discussion, I would leave solving that to later, when we actually have a broker that supports these kind of flows.

@3v1n0

3v1n0 commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Let's add some FIXME and TODO comments at least

@adombeck

Copy link
Copy Markdown
Contributor Author

Let's add some FIXME and TODO comments at least

done

@adombeck

Copy link
Copy Markdown
Contributor Author

Rebased on main and resolved conflicts

Comment thread pam/go-exec/module.c Outdated
@adombeck
adombeck force-pushed the UDENG-8799-pam-set-authtok branch from 406e936 to f381360 Compare June 22, 2026 14:08
@adombeck
adombeck requested a review from 3v1n0 June 22, 2026 14:08
@adombeck

Copy link
Copy Markdown
Contributor Author

@3v1n0 anything missing for this to be merged?

@adombeck

Copy link
Copy Markdown
Contributor Author

@3v1n0 anything missing for this to be merged?

@3v1n0 ping

@adombeck
adombeck force-pushed the UDENG-8799-pam-set-authtok branch from f381360 to d2a2f9d Compare July 1, 2026 14:54
@adombeck adombeck added the e2e-tests This issue is related to end-to-end tests / Run end-to-end tests on this pull request label Jul 1, 2026
Comment thread pam/internal/adapter/authentication.go
@adombeck
adombeck force-pushed the UDENG-8799-pam-set-authtok branch 5 times, most recently from 10b2c75 to 95efad7 Compare July 7, 2026 18:49
adombeck and others added 11 commits July 7, 2026 23:30
Call the PAM return value a "return value" instead of an "exit status"
because I found the naming confusing.
By setting PAM_AUTHTOK the GNOME keyring is unlocked.

UDENG-8799
Ensure that VM_NAME is exported to the environment of the ssh script to
avoid

  Error: Missing required argument <release>
For example to pipe the output of one command into another.
I'm repeatedly seeing the launch of ptyxis time out after 30 seconds.
Let's see if bumping the timeout fixes it.
…iles

PAM_AUTHTOK can only be read by service modules — applications get
PAM_BAD_ITEM from pam_get_item(3). Since pam-runner is an application,
it cannot read the token directly after pam_authenticate/pam_chauthtok
returns.

Instead, use a reportAuthtok hook in pam.go (no-op by default, following
the debugMessageFormatter pattern) that is overridden under the pam_debug
build tag to print the token to stdout. This works for both the exec child
(which inherits the PAM module's stdout so output reaches pam-runner's PTY)
and the GDM native .so path (also built with pam_debug in tests). The print
happens right after SetItem, so it appears before pam-runner's printPamResult
output, and the existing waitForRunnerResult regex captures it naturally in
the final snapshot.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Writing these e2e tests blind is hard for an agent: most assertions go
through OCR, which is non-deterministic, and there was no documented way
to verify an OCR match without running a full suite against the VM.

Add an agent-facing authoring guide and a wrapper that launches YARF's
interactive console against the live VM. The console gives the missing
feedback loop: drive the screen to a state and probe what the OCR
actually reads before committing a match, instead of guessing.

The guide also records the assertion priority order (SSH/journal over
OCR) and the OCR/keyword idioms the existing suite relies on, so agents
compose from them rather than reinventing brittle sequences.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
After changing their local password with passwd, a user's GNOME login
keyring would no longer unlock at login: the keyring stayed locked under
the old password and secret-tool would hang waiting on an unlock prompt.

pam_gnome_keyring re-keys an existing keyring during chauthtok using
PAM_OLDAUTHTOK (to open it) and PAM_AUTHTOK (the new passphrase). We set
PAM_AUTHTOK but never PAM_OLDAUTHTOK, so the keyring could not be re-keyed
and was orphaned under the old password.

During a password change the user authenticates with their old local
password before setting the new one, so the previous step's secret is the
old password. Carry it through to PAM_OLDAUTHTOK, but only for a
CHANGE_PASSWORD session and only when the old and new secrets differ, so
plain authentication never sets a spurious PAM_OLDAUTHTOK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Guards against the login keyring being orphaned when a remote user changes
their local password: log in with device auth, store a secret in the
keyring, change the password with passwd, log back in with the new
password, and require the stored secret to still be retrievable.

The secret round-trip is what makes this discriminating: if the password
change left the old keyring locked (or a fresh one was created), the
lookup after re-login fails.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@adombeck
adombeck force-pushed the UDENG-8799-pam-set-authtok branch from 95efad7 to 4359c7a Compare July 7, 2026 21:31
@adombeck
adombeck merged commit 3813a7e into main Jul 7, 2026
21 of 22 checks passed
@adombeck
adombeck deleted the UDENG-8799-pam-set-authtok branch July 7, 2026 21:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

e2e-tests This issue is related to end-to-end tests / Run end-to-end tests on this pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Issue: GNOME Keyring Unable to be Automatically Unlocked on Login

6 participants