> 1. You set pwdChangeNext=1 for a user in UDM > 2. If the user was already logged in the last minutes, dovecot will "Cache" that behavior for some seconds, still serving the directory index. That's no problem so far, but important to remember > 3. If the dovecot cache has been invalidated or dovecot is restarted, the "state" is as follows: > > ``` > # udm users/user list --filter uid=lehrer.s401 | grep -E "DN:|pwdChangeNext" > DN: uid=lehrer.s401,cn=lehrer,cn=users,ou=S40,dc=… > pwdChangeNextLogin: 0 > ``` > > -> The user tries to login by IMAP and gets rejected from the PAM Stack, as a password change is required: > > ``` > ~ # curl imaps://$(hostname -f) --user 'lehrer.s401:nixda' -k root@ucs-ox > curl: (67) Login denied > ``` > > 4. This failed Login attempt causes the pwdChangeNextLogin to be changed back to 0 -> removes the requirement to change the password for the user, if you try the same commands 1 second later: > > ``` > > ~ # udm users/user list --filter uid=lehrer.s401 | grep -E "DN:|pwdChangeNext" > DN: uid=lehrer.s401,cn=lehrer,cn=users,ou=S40,… > pwdChangeNextLogin: 0 > > ~ # curl imaps://$(hostname -f) --user 'lehrer.s401:nixda' -k root@ucs-ox > * LIST (\HasNoChildren \UnMarked \Sent) "/" "Gesendete Objekte" > * LIST (\HasNoChildren \UnMarked \Trash) "/" Papierkorb > * LIST (\HasNoChildren \UnMarked \Drafts) "/" Entw&APw-rfe > * LIST (\HasNoChildren) "/" confirmed-ham > * LIST (\HasNoChildren \Junk) "/" confirmed-spam > * LIST (\HasNoChildren \Junk) "/" Spam > * LIST (\HasNoChildren) "/" INBOX > ``` > > I had the same issue like a week ago on my test environment but couldn't reproduce it on fresh installed servers, causing me to think about a error in my environment. The clients tellings they had actual wars going on in their office because they suspected team members to not set the pwdChangeNext flag as mail accounts got hijacked over and over again without actual password changes made me pretty certain about a product bug.
Reproducer: name="foo" dn="uid=$name,cn=users,dc=univention,dc=intranet" pw="Start2020" udm users/user modify --dn "$dn" --set password="$pw" --set overridePWHistory=1 udm users/user modify --dn "$dn" --set pwdChangeNextLogin=1 udm users/user list --filter uid="$name"| grep -E "DN:|pwd" cat > repro.py <<-EOF from PAM import * from univention.management.console.pam import PamAuth p = PamAuth() p.pam = pam() p.pam.start('dovecot') p.authenticate('$name', '$pw') EOF python3 repro.py sleep 3 python3 repro.py sleep 3 udm users/user list --filter uid=$name | grep -E "DN:|pwd" → this now says "pwdChangeNextLogin: 0" instead of still "1"
Dovecot logins happen via the pam stack "dovecot" which uses "pam-krb5". pam-krb5 detects the expired password and contacts the kerberos server(heimdal) in Samba, which somehow forces a password change without prompting it - resulting in the "pwdLastSet" in Samba being set to "0". The S4-Connector then syncs that to UCS, which makes the corresponding LDAP changes for "pwdChangeNextLogin" → "0".
The solution is to use the `defer_pwchange` pam-krb5 option: ``` diff --git mail/univention-mail-dovecot/conffiles/etc/pam.d/50_dovecot mail/univention-mail-dovecot/conffiles/etc/pam.d/50_dovecot index b347ce9a688..6786a4ebad8 100644 --- mail/univention-mail-dovecot/conffiles/etc/pam.d/50_dovecot +++ mail/univention-mail-dovecot/conffiles/etc/pam.d/50_dovecot @@ -13,7 +13,7 @@ auth += " ldap_port=%s" % configRegistry.get("ldap/server/port", "7389") print(auth) print(f''' auth sufficient pam_sss.so -auth required pam_krb5.so use_first_pass minimum_uid={krb5_minimum_uid} +auth required pam_krb5.so use_first_pass defer_pwchange minimum_uid={krb5_minimum_uid} account sufficient pam_unix.so account required pam_sss.so ``` I am not sure, why we don't use `account pam_krb5.so` here but only pam_sss.so but I think that is enough. From https://github.com/rra/pam-krb5/blob/main/README.md > By default, pam_authenticate intentionally does not follow the PAM standard for handling expired accounts and instead returns failure from pam_authenticate unless the Kerberos libraries are able to change the account password during authentication. Too many applications either do not call pam_acct_mgmt or ignore its exit status. The fully correct PAM behavior (returning success from pam_authenticate and PAM_NEW_AUTHTOK_REQD from pam_acct_mgmt) can be enabled with the defer_pwchange option. > The defer_pwchange option is unfortunately somewhat tricky to implement. In this case, the calling sequence is: >· > pam_authenticate > pam_acct_mgmt > pam_chauthtok > pam_setcred > pam_open_session > During the first pam_authenticate, we can't obtain credentials and therefore a ticket cache since the password is expired. But pam_authenticate isn't called again after pam_chauthtok, so pam_chauthtok has to create a ticket cache. We however don't want it to do this for the normal password change (passwd) case. > What we do is set a flag in our PAM data structure saying that we're processing an expired password, and pam_chauthtok, if it sees that flag, redoes the authentication with password prompting disabled after it finishes changing the password. > Unfortunately, when handling password changes this way, pam_chauthtok will always have to prompt the user for their current password again even though they just typed it. This is because the saved authentication tokens are cleared after pam_authenticate returns, for security reasons. We could hack around this by saving the password in our PAM data structure, but this would let the application gain access to it (exactly what the clearing is intended to prevent) and breaks a PAM library guarantee. We could also work around this by having pam_authenticate get the kadmin/changepw authenticator in the expired password case and store it for pam_chauthtok, but it doesn't seem worth the hassle.
univention-mail-dovecot.yaml b6db87f4d14f | fix(dovecot): prevent dovecot PAM stack from resetting `pwdChangeNextLogin=1` state during authentication univention-mail-dovecot (8.1.0) b6db87f4d14f | fix(dovecot): prevent dovecot PAM stack from resetting `pwdChangeNextLogin=1` state during authentication
errata-yaml ok debian-package ok code-review ok discussed with PO ok
<https://errata.software-univention.de/#/?erratum=5.2x65>