thanks Obaid,

Yes that helps!

My original question (https://lists.samba.org/archive/cifs-protocol/2025-September/004579.html) was whether MS-SAMR 3.1.1.7.1 should mention this. I think this means it should.

Also MS-ADTS 3.1.1.3.4.1.27 should probably mention password age.

Later (https://lists.samba.org/archive/cifs-protocol/2025-October/004600.html) I also talked about

https://learn.microsoft.com/en-us/entra/identity/authentication/concept-sspr-writeback

which says

  Enforcement of on-premises Active Directory Domain Services (AD DS)
  password policies: When a user resets their password, it's checked to
  ensure it meets your on-premises AD DS policy before committing it to
  that directory. This review includes checking the history, complexity,
  age, password filters, and any other password restrictions that you
  define in AD DS.

I am guessing based on what you have found that these other constraints apply equally to password set and password change, but I will test and let you know if it seems otherwise.

cheers,
Douglas


On 18/12/2025 10:06, Obaid Farooqi wrote:
Hi Douglas:
When I analyzed your ttt traces, my focus was on LDAP_SERVER_POLICY_HINTS_OID 
since I believe this is control you are interested in. So, I found four LDAP 
requests with this control in them.

First, here is what I found out about this control.
1. It is only meaningful for password set operation
2. If it is set to 1, it checks the following two condition
         a. has there enough time passed since the last password was set. This 
is governed by minimum password age
3. if above test passes, then password history is checked i.e. has the new 
password been used in the past. If yes then the operation fails otherwise 
operation continues.

So, based on the above, here is what I found out. Minimum password age is 0 so 
it is irrelevant.

In the first case, operation is set and control is 1. Password was not found in 
the history and therefore password was updated.

In the second instance, operation is password set and control is 1. Password 
set operation failed since the password was found in history.

In the third case, operation is set, control is 1. Password is found in history 
so the password set fails again.

In the fourth case, operation is set and control is 2 therefore password time 
restrictions are not checked and history is not checked is set successfully.

Please let me know if you have any further question on this control.

Regards,
Obaid Farooqi
Sr. Escalation Engineer | Microsoft

-----Original Message-----
From: Douglas Bagnall <[email protected]>
Sent: Tuesday, December 9, 2025 10:01 PM
To: Obaid Farooqi <[email protected]>
Cc: [email protected]; Microsoft Support <[email protected]>
Subject: Re: [cifs-protocol] [EXTERNAL] [MS-SAMR] 3.1.1.7.1 General Password 
Policy -- interaction with LDAP_SERVER_POLICY_HINTS_OID - 
TrackingID#2512020040011213

hi Obaid.

I think Jennifer used TTD.exe. But never mind -- I found TTTracer, and it 
produced something, which I uploaded.

In case it helps, this is the python test in Samba, which maybe gives a high level view 
of what is going on. The second to last "self._replace_unicode_pwd" is doing a 
reset with the policy hints oid and a value of 1, which fails with unwilling to perform.


      def test_unicodePwd_clear_change_with_hints(self):
          """Performs a password cleartext reset operation on 'unicodePwd',
          but expect failure due to history"""

          # User password update (...1 -> ...2)
          self._replace_unicode_pwd(self.ldb2,
                                    "thatsAcomplPASS1",
                                    "thatsAcomplPASS2")

          # An ADMIN reset to the old password will work, ignoring history.
          self._replace_unicode_pwd(self.ldb,
                                    None,
                                    "thatsAcomplPASS1")
          self._replace_unicode_pwd(self.ldb,
                                    None,
                                    "thatsAcomplPASS2")
          # An Admin reset with policy hints works if password is new
          self._replace_unicode_pwd(self.ldb,
                                    None,
                                    "thatsAcomplPASS7",
                                    ["policy_hints:1:1"])
          self._replace_unicode_pwd(self.ldb,
                                    None,
                                    "thatsAcomplPASS2")

          # User change with wrong old password will fail
          with self.assertRaises(LdbError) as e:
              self._replace_unicode_pwd(self.ldb2,
                                        "thatsAcomplPASS3",
                                        "thatsAcomplPASS4")

          num, msg = e.exception.args
          self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)

          # A reset to the old password again will not work, using ldb2,
          # which has the users credentials, because ordinary users
          # can't reset their own passwords.
          with self.assertRaises(LdbError) as e:
              self._replace_unicode_pwd(self.ldb2,
                                        None,
                                        "thatsAcomplPASS1",
                                        ["policy_hints:1:1"])
          num, msg = e.exception.args
          self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)

          # An ADMIN reset to the old password again will not work, if
          # we give it the policy hints oid.
          with self.assertRaises(LdbError) as e:
              self._replace_unicode_pwd(self.ldb,
                                        None,
                                        "thatsAcomplPASS1",
                                        ["policy_hints:1:1"])
          num, msg = e.exception.args
          self.assertEqual(num, ERR_UNWILLING_TO_PERFORM)

          # An ADMIN reset to the old password will work, if
          # we give it the policy hints oid with a BAD VALUE.
          self._replace_unicode_pwd(self.ldb,
                                    None,
                                    "thatsAcomplPASS1",
                                    ["policy_hints:1:2"])



The trace is entirely synthetic test data, so sharing it is OK.


Douglas


On 09/12/2025 05:30, Obaid Farooqi wrote:
Hi Douglas:
TTT does not require any installation. You just run the tttracer.exe -attach <PID 
of lsass> and then reproduce the problem. Jennifer has recently done that so maybe 
she can help.

Once you will get the traces, upload them to the following link:

https://supp/
ort.microsoft.com%2Ffiles%3Fworkspace%3DeyJhbGciOiJSUzI1NiIsImtpZCI6Ik
NBRjFBNjdERDUxQjI4QzVCNjg0N0Y5NTFCQTM2QkVDNDk0MkQ4NEYiLCJ0eXAiOiJKV1Qi
fQ.eyJ3c2lkIjoiMTMyY2RiODQtZDI2NC00YmMyLWI4ZjMtMTI4ODljZWExMzIyIiwic3I
iOiIyNTEyMDIwMDQwMDExMjEzIiwic3YiOiJ2MSIsInJzIjoiRXh0ZXJuYWwiLCJ3dGlkI
joiZWUxZDhmY2QtNmQ3OS00MThlLTliNTAtNzNjZmEzMGQ4MjBkIiwiYXBwaWQiOiI0ZTc
2ODkxZC04NDUwLTRlNWUtYmUzOC1lYTNiZDZlZjIxZTUiLCJuYmYiOjE3NjUyMTExMTIsI
mV4cCI6MTc3Mjk4NzExMiwiaWF0IjoxNzY1MjExMTEyLCJpc3MiOiJodHRwczovL2FwaS5
kdG1uZWJ1bGEubWljcm9zb2Z0LmNvbSIsImF1ZCI6Imh0dHA6Ly9zbWMifQ.wJ8xLGWVl7
hyZPCsCGXUPEQdkwym6Z946X2snNhHRBeu1HEPs3KSHLAjwMdEjhU1eCeD9cmt-8DP3CO8
KNMvewPiaFZeAv0PO7cSSZiVMeAQUj4MVwhD-txzq7tQzRckak30oVhIOgDBG33KYiC0V_
aWFxpsNdB38_SL0Nbw-2uIhv2z3ckTeo6VMtM6h5-XqyN9bzx8H1k4U_otP9TL_ADxouzk
anyi-e8u4LrddEc3-pN48WM1vlD1m431a5yYakMxYOInQA7oVRQotwEBGaiJYwYRsNMXXz
Gb7zzUFv5ATt5UoB5rGF-nYgbLyacBrQVmwAml88iSp3dWszrUIg%26wid%3D132cdb84-
d264-4bc2-b8f3-12889cea1322&data=05%7C02%7Cobaidf%40microsoft.com%7Cd1
3f02a8736442fe41dd08de37a0bb99%7C72f988bf86f141af91ab2d7cd011db47%7C1%
7C0%7C639009360657286251%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRyd
WUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3
D%7C0%7C%7C%7C&sdata=8hloNWT1wPVECe0uWMWLlfiMjYUT7zOHMz3ubWqjWHs%3D&re
served=0

I know the code path so I'll see if I can explain the behavior you are 
observing without the ttt traces while you work on collecting traces.

Regards,
Obaid Farooqi
Sr. Escalation Engineer | Microsoft

-----Original Message-----
From: Douglas Bagnall <[email protected]>
Sent: Tuesday, November 25, 2025 7:17 PM
To: Obaid Farooqi <[email protected]>
Cc: [email protected]; Microsoft Support
<[email protected]>
Subject: Re: [cifs-protocol] [EXTERNAL] [MS-SAMR] 3.1.1.7.1 General
Password Policy -- interaction with LDAP_SERVER_POLICY_HINTS_OID -
TrackingID#2509240040013358

hi Obaid,

I have tested against Windows 2022.

If I do this as Administrator:

dn: cn=testuser,cn=users,DC=samba,DC=example,DC=com
changetype: modify
replace: unicodePwd
unicodePwd:: <base64 encoded recent password>

it fails (unwillingToPerform) if the LDAP_SERVER_POLICY_HINTS_OID control is 
set with a value of 1.

If I have control unset, or the value set to a different number, the reset 
succeeds.

It also succeeds with the control set to 1 if the password is not a recent 
password.

I am struggling to install TTD, but I will keep trying!

Douglas


On 16/10/2025 12:24, Obaid Farooqi wrote:
Hi Douglas:
This is what I did:
1. logged in on a workstation as admin 2. Open ADSI edit 3. Modified
the unicodePwd attribute of a user (just an ordinary user testuser) 4.
Logged in as testuser using new password and it worked.
5. this IMO is a password reset scenario since I am not the user whose password 
is being changed.
5. debugged the scenario and here is what I found
           LDAP operation is modify
           ADSI editor does not send the control
LDAP_SERVER_POLICY_HINTS_OID

Since after debugging I know where to look, I browse the code to where else 
this control is meaningful. It is only meaningful in modify operation and here 
what happens:
If (the attribute being modified is password or Unicode password) {
           If (LDAP_SERVER_POLICY_HINTS_OID is 1)
           {
                   Calculate the time when user is allowed to change
the password by using when the password last change and what is
minimum time after which the password can be changed

                   If (calculated time > current time)
                   {
                           Return error STATUS_PASSWORD_RESTRICTION
                   }

           }
}

This is all this control do.

If you can send the exact LDAP message in a test environment that entra ID 
sends to Windows DC and collect TTD traces for that, I'll look at it.



Regards,
Obaid Farooqi
Sr. Escalation Engineer | Microsoft

-----Original Message-----
From: Douglas Bagnall <[email protected]>
Sent: Tuesday, October 14, 2025 8:22 PM
To: Obaid Farooqi <[email protected]>
Cc: [email protected]; Microsoft Support
<[email protected]>
Subject: Re: [cifs-protocol] [EXTERNAL] [MS-SAMR] 3.1.1.7.1 General
Password Policy -- interaction with LDAP_SERVER_POLICY_HINTS_OID -
TrackingID#2509240040013358

hi Obaid,

That doesn't quite answer everything.

I understand that it isn't used for a password set for a new user, but I think 
it is used for a password *reset* for an existing user.

My understanding is a password reset doesn't require the existing password, and 
it ignores or wipes password history. A password change requires the user enter 
their old password and checks it against history.

A password change in Entra ID using the self-service password reset writeback 
system wants to enforce on-premises password policy, even though it is not 
providing the old password to the on-prem AD server:

https://lear/
n.microsoft.com%2Fen-us%2Fentra%2Fidentity%2Fauthentication%2Fconcept
-
sspr-writeback&data=05%7C02%7Cobaidf%40microsoft.com%7Cdd59203959fd47
4
8647708de2c8986d4%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C638997
1
66524173660%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwL
j
AuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%
7
C&sdata=nWHeXCyxIJpQlYMkZ%2Bpy6ryEPCACcGGmUWox6YnDVaw%3D&reserved=0

      Enforcement of on-premises Active Directory Domain Services (AD DS)
      password policies: When a user resets their password, it's checked to
      ensure it meets your on-premises AD DS policy before committing it to
      that directory. This review includes checking the history, complexity,
      age, password filters, and any other password restrictions that you
      define in AD DS.

I *think* it does this by sending a reset message with the OID, and the OID means 
"this reset should check policy as if it were a change". But MS-SAMR 3.1.1.7.1 
doesn't mention it. Should it? that was my original question.

Now that I look at that passage again, it seems like the OID should also affect the minimum password length constraint 
in MS-SAMR 3.1.1.7.1, but MS-ADTS does not mention that (just the history). The complexity and "other password 
restrictions" looks to refer to MS-SAMR 3.1.1.7.2, which doesn't use the language of "change" or 
"set", but says "this constraint is referenced when a cleartext password is updated". Should 
MS-ADTS also mention that? Or is the self-service password reset document wrong?

I am not able to get a trace of the this happening with Entra ID, but I have 
seen a pcap showing that the (deprecated) OID is set in this case.
I am able to write a test case that mimics it.

cheers,
Douglas



On 15/10/25 12:31, Obaid Farooqi wrote:
Hi Douglas:
Based on my research LDAP_SERVER_POLICY_HINTS_OID is only used for change 
password. I did not see evidence for it to be used in the add scenario for a 
new user. This is based on code browsing.

I have filed a bug to fix MS-ADTS. If my above assumption is incorrect (highly 
unlikely) and the control is used for both set and change, I'll update you.

Please let me know if this does not answer your question.

Regards,
Obaid Farooqi
Sr. Escalation Engineer | Microsoft

-----Original Message-----
From: Douglas Bagnall <[email protected]>
Sent: Wednesday, October 8, 2025 6:38 PM
To: Obaid Farooqi <[email protected]>
Cc: [email protected]; Microsoft Support
<[email protected]>
Subject: Re: [cifs-protocol] [EXTERNAL] [MS-SAMR] 3.1.1.7.1 General
Password Policy -- interaction with LDAP_SERVER_POLICY_HINTS_OID -
TrackingID#2509240040013358

hi again.

I noticed from this message to the Samba users list

https://list/
s.samba.org%2Farchive%2Fsamba%2F2024-August%2F249724.html&data=05%7C
0
2
%7Cobaidf%40microsoft.com%7C404c0c2b3f264975954008de0b894dd3%7C72f98
8
b
f86f141af91ab2d7cd011db47%7C1%7C0%7C638960881535058119%7CUnknown%7CT
W
F
pbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiI
s
I
kFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=MhyxSJvWbPxWBF9y2
q
J
Tu%2BaKyoApimkXl2JqFiQDv7s%3D&reserved=0

that Keycloak also uses the LDAP_SERVER_POLICY_HINTS_OID.

The way they document it is "if [some option is] on, then updating password of 
MSAD user will use LDAP_SERVER_POLICY_HINTS_OID extension, which means that advanced 
MSAD password policies like 'password history'
or 'minimal password age' will be applied. This extension works just for MSAD 2008 
R2 or newer."

(https://github.com/keycloak/keycloak/blob/main/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties#L97).

I guess Keycloak is trying to do the same thing as Entra, enforcing password 
change semantics without giving AD the old password.

Douglas


On 1/10/25 10:33, Douglas Bagnall via cifs-protocol wrote:
hi Obaid,

Thanks for looking.

If it helps, Azure Self-Service Password Reset does set the control
(actually LDAP_SERVER_POLICY_HINTS_DEPRECATED_OID which does the
same
thing) when doing a password set.

I think maybe it looks like a password change on the Entra side
(that is, the user needs their old password), but Entra wants to
forward the change as an unconditional set but maintain history.

This page

https://lear/
n.microsoft.com%2Fen-us%2Fentra%2Fidentity%2Fauthentication%2F&data
=
0
5
%7C02%7Cobaidf%40microsoft.com%7C37bbfc9a6456405eed3508de06c3c419%7
C
7
2
f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C638955635072994735%7CUnkno
w
n
%
7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXa
W
4
z
MiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=WyH8Xrqt8E9
l
J
y
%2FS%2F5aPpuOXRis2oIV%2FeEDytOpGQEc%3D&reserved=0
troubleshoot-sspr-writeback#if-the-source-of-the-event-is-adsync

talks a bit about it around "33008 ADPasswordPolicyError".
Elsewhere it mentions LDAP_SERVER_POLICY_HINTS_OID but gives it the
value
1.2.840.113556.1.4.2066 which is the one now called _DEPRECATED_,
presumably because the oid is also used for the
ms-DS-Required-Domain- Behavior-Version attribute.

Douglas



On 1/10/25 10:02, Obaid Farooqi wrote:
Hi Douglas:
To me, the quote from MS-ADTS looks more problematic than the MS-SMAR's.
There will not be a password history if we are setting a password.

I am looking into it and I think this is a bug in MS-ADTS.

Regards,
Obaid Farooqi
Sr. Escalation Engineer | Microsoft

-----Original Message-----
From: Michael Bowen <[email protected]>
Sent: Wednesday, September 24, 2025 6:17 PM
To: Douglas Bagnall <[email protected]>; cifs-
[email protected]
Cc: Microsoft Support <[email protected]>
Subject: RE: [EXTERNAL] [MS-SAMR] 3.1.1.7.1 General Password
Policy
-- interaction with LDAP_SERVER_POLICY_HINTS_OID -
TrackingID#2509240040013358

[DocHelp to bcc]

Hi Douglas,

Thanks for your question. I've created case number
2509240040013358 to track this issue. Please leave the number in
the subject line and use reply all your correspondence. One of our
engineers will contact you soon.

Best regards,
Michael Bowen

Sr. Escalation Engineer - Microsoft(r) Corporation


-----Original Message-----
From: Douglas Bagnall <[email protected]>
Sent: Wednesday, September 24, 2025 3:39 PM
To: Interoperability Documentation Help <[email protected]>;
cifs- [email protected]
Subject: [EXTERNAL] [MS-SAMR] 3.1.1.7.1 General Password Policy --
interaction with LDAP_SERVER_POLICY_HINTS_OID

hi Dochelp,

MS-ADTS 3.1.1.3.4.1.27 says that when LDAP_SERVER_POLICY_HINTS_OID
is used with a control value of 1, the password history length
constraint is enforced on password-set operations.

I think that means at the bottom of MS-SAMR 3.1.1.7.1 General
Password Policy, where it says:

5. The requesting protocol message is a password change (as
compared to a password set).

it should say something like

5. The requesting protocol message is a password change (as
compared to a password set), or the message is a password set with
the LDAP_SERVER_POLICY_HINTS_OID control set with the value 0x1.

Is that right?

Douglas



_______________________________________________
cifs-protocol mailing list
[email protected]
https://list/
s.samba.org%2Fmailman%2Flistinfo%2Fcifs-protocol&data=05%7C02%7Coba
i
d
f
%40microsoft.com%7C37bbfc9a6456405eed3508de06c3c419%7C72f988bf86f14
1
a
f
91ab2d7cd011db47%7C1%7C0%7C638955635073003873%7CUnknown%7CTWFpbGZsb
3
d
8
eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjo
i
T
W
FpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=Y2rxWtoBTT%2FLV%2Fjs8SkTo
X
s
Y
snQe%2FbZ5C6q0jIj3QAc%3D&reserved=0






_______________________________________________
cifs-protocol mailing list
[email protected]
https://lists.samba.org/mailman/listinfo/cifs-protocol

Reply via email to