Jump to content

Active Directory: allow Password Change


Marc
 Share

Recommended Posts

Hi,

I'm writing a small administration tool to check a users account in active directory. The adfunctions.au3 have been a great help to me, and I'm quite happy with it, but...

One part of it should be to detect whether a user is allowed to change his password (or not), to display this status - and I want to add a button to simply toggle this state.

At first I thought "great, there's a flag PASSWD_CANT_CHANGE 0x0040 64" but that ain't work.

Found this vbs code:

Const ADS_ACETYPE_ACCESS_DENIED_OBJECT = &H6
    Const CHANGE_PASSWORD_GUID  = "{ab721a53-1e2f-11d0-9819-00aa0040529b}"
     
    Set objUser = GetObject ("LDAP://cn=myerken,ou=management,dc=fabrikam,dc=com")
    Set objSD   = objUser.Get("nTSecurityDescriptor")
    Set objDACL = objSD.DiscretionaryAcl
    arrTrustees = Array("nt authority\self", "everyone")
     
    For Each strTrustee In arrTrustees
      For Each ace In objDACL
        If(LCase(ace.Trustee) = strTrustee) Then
          If((ace.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT) And (LCase(ace.ObjectType) = CHANGE_PASSWORD_GUID)) Then
            objDACL.RemoveAce ace
          End If
        End If
      Next
    Next
    objUser.Put "nTSecurityDescriptor", objSD
    objUser.SetInfo

and tried to convert it to AutoIt.

Func passwort_changeable($user)
    Local $oUsr
    Local $oSecDesc
    $strQuery = "<LDAP://" & $strHostServer & "/" & $strDNSDomain & ">;(sAMAccountName=" & $user & ");ADsPath;subtree"
    $objRecordSet = $objConnection.Execute($strQuery) ; Retrieve the FQDN for the logged on user
    $ldap_entry = $objRecordSet.fields(0).value
    $oUsr = ObjGet($ldap_entry) ; Retrieve the COM Object for the user
        
    $oSecDesc = $oUsr.Get("ntSecurityDescriptor")
    $oACL = $oSecDesc.DiscretionaryACL
        
    For $oACE In $oACL
        $tmp = StringUpper($oACE.Trustee)
        If ($oACE.ObjectType = $USER_CHANGE_PASSWORD) And (($tmp = "EVERYONE") or ($tmp = "NT AUTHORITY\SELF")) Then
            If ($oACE.AceType = $ADS_ACETYPE_ACCESS_ALLOWED_OBJECT) Then
            $oACE.AceType = $ADS_ACETYPE_ACCESS_DENIED_OBJECT
            ElseIf ($oACE.AceType = $ADS_ACETYPE_ACCESS_DENIED_OBJECT) Then
            ;               $oACL.RemoveAce ($oACE)
            $oACE.AceType = $ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
            EndIf
        EndIf
    Next
    $oSecDesc.DiscretionaryACL = $oACL
    $oUsr.Put("ntSecurityDescriptor", $oSecDesc)
    $oUsr.SetInfo

; check and display status
    $oSecDesc = $oUsr.Get("ntSecurityDescriptor")
    $oACL = $oSecDesc.DiscretionaryACL
    For $oACE In $oACL
        If ($oACE.ObjectType = $USER_CHANGE_PASSWORD) And ($oACE.Trustee = "Everyone") Then
            If ($oACE.AceType = $ADS_ACETYPE_ACCESS_ALLOWED_OBJECT) Then
                GUICtrlSetData($lbl_change, "erlaubt")
                GUICtrlSetColor($lbl_change, 0x00aa00)
            Else
                GUICtrlSetData($lbl_change, "gesperrt")
                GUICtrlSetColor($lbl_change, 0xff0000)
            EndIf
        EndIf
    Next
EndFunc   ;==>passwort_changeable

Reading the status works, so it can display whether a user is allowed to change his password or not.

However, every time I try to toggle the status, the status changes and after a second

the status is automatically set back to the previous one.

Tried to convert another vbs example I've found

Const ADS_ACETYPE_ACCESS_DENIED_OBJECT = &H6
        Const ADS_ACEFLAG_OBJECT_TYPE_PRESENT = &H1
        Const CHANGE_PASSWORD_GUID = "{ab721a53-1e2f-11d0-9819-00aa0040529b}"
        Const ADS_RIGHT_DS_CONTROL_ACCESS = &H100
        
        Set objUser = GetObject ("LDAP://cn=myerken,ou=management,dc=fabrikam,dc=com")
        Set objSD = objUser.Get("ntSecurityDescriptor")
        Set objDACL = objSD.DiscretionaryAcl
        arrTrustees = array("nt authority\self", "EVERYONE")
        
        For Each strTrustee in arrTrustees
        Set objACE = CreateObject("AccessControlEntry")
        objACE.Trustee = strTrustee
        objACE.AceFlags = 0
        objACE.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT
        objACE.Flags = ADS_ACEFLAG_OBJECT_TYPE_PRESENT
        objACE.ObjectType = CHANGE_PASSWORD_GUID
        objACE.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS
        objDACL.AddAce objACE
        Next
        
        objSD.DiscretionaryAcl = objDACL
        objUser.Put "nTSecurityDescriptor", objSD
        objUser. SetInfo
    #ce

but the result is the same, except sometimes I get a hangup of the script during the .AddAce command (in my AutoIt conversion).

Any suggestions, or even better, a working code to achieve my goal?

Best regards,

Marc

Any of my own codes posted on the forum are free for use by others without any restriction of any kind. (WTFPL)

Link to comment
Share on other sites

@MArc

This runs fine on my side.

Maybe you forgot to include the constants values ?

#include <array.au3>

Const $ADS_ACETYPE_ACCESS_DENIED_OBJECT = 6
Const $CHANGE_PASSWORD_GUID  = "{ab721a53-1e2f-11d0-9819-00aa0040529b}"
     
    $objUser = ObjGet ("LDAP://cn=Patrick Taels,ou=IT,dc=Plastiflex,dc=be")
    $objSD   = $objUser.Get("nTSecurityDescriptor")
    $objDACL = $objSD.DiscretionaryAcl
    $arrTrustees = _ArrayCreate("nt authority\self", "everyone")
     
For $strTrustee In $arrTrustees
    For $ace In $objDACL
        If(StringLower($ace.Trustee) = $strTrustee) Then
            ConsoleWrite(StringLower($ace.Trustee)& " " & $ace.ObjectType & @LF)
            ConsoleWrite("Type " & $ace.ACETYPE & @LF)
            ConsoleWrite( @LF)
            If(($ace.ACETYPE = $ADS_ACETYPE_ACCESS_DENIED_OBJECT) And (StringLower($ace.ObjectType) = $CHANGE_PASSWORD_GUID)) Then
            ;   $objDACL.RemoveAce ($ace)
            ConsoleWrite($ace.ACETYPE )
            EndIf
        EndIf
    Next
Next
;$objUser.Put ("nTSecurityDescriptor", $objSD)
;$objUser.SetInfo()

I did comment out the action lines.

regards

ptrex

Link to comment
Share on other sites

Hi ptrex,

thanks for your help!

Integrated your code - same result. If I re-check in AD, the box "cannot change password" is still checked. :)

So I tried to run your code as a standalone script - except the fact I had to use a custom error handler to prevent

==> The requested action with this object has failed.: 
$objUser.SetInfo()
the result is quite the same. Funny.

Seems I'll have some fun with this.... ^^

Best regards,

Marc

Any of my own codes posted on the forum are free for use by others without any restriction of any kind. (WTFPL)

Link to comment
Share on other sites

Hi all, back to work... :)

Error Number: 80020009 "Es ist eine Beschränkungsverletzung aufgetreten".

translation should be "a constraint violation has occured".

Hmmm, seems to me like I'd not be allowed to change this attribute.

Funny thing, because using the Microsoft Active Directory tool, I can enable/disable the account as I wish.

Googled a little and found http://support.microsoft.com/kb/239835/EN-US/

but to be honest, I don't get it...

Using .PutEx instead of .Put creats an 80020005 Type Conflict Error.

So I tested both the .vbs scripts included in my first posting to check if the problem resides in the autoit code, but amazingly the vbs scripts generate a different error: 8007202F "a constraint violation occured". Same Message, but different number...

http://prijks.esgeroth.org/log/viewentry.php?id=1435 suggests it could be a invalid value to be inserted into a field. Hmmmmm....

Tried it with several accounts, same result.

Any suggestions? :)

Marc

Any of my own codes posted on the forum are free for use by others without any restriction of any kind. (WTFPL)

Link to comment
Share on other sites

  • 15 years later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...