Basic LDAP Viewer

Share your advanced PureBasic knowledge/code with the community.
TeddyLM
Enthusiast
Enthusiast
Posts: 133
Joined: Wed Apr 30, 2003 2:04 pm
Location: Germany (French expat)

Basic LDAP Viewer

Post by TeddyLM »

Hi,

i needed a few functions to get informations from Active Directory.
Maybe it can be of use for someone else.
(A connection with SSL-encryption is strongely recommended - if available)

A+
TeddyLM

Code: Select all

#LDAP_PORT = 389
#LDAP_SSL_PORT = 636

#LDAP_SCOPE_BASE = 0 ;Searches the base entry only. 
#LDAP_SCOPE_ONELEVEL = 1 ;Searches all entries in the first level below the base entry, excluding the base entry. 
#LDAP_SCOPE_SUBTREE = 2 ;Searches the base entry and all entries in the tree below the base.

#LDAP_OPT_ON = 1
#LDAP_OPT_TIMELIMIT = 4 ;A limit on the number of seconds the server will wait To complete a bind. This also specifies the limit on the number of seconds the server spends on a search.
#LDAP_OPT_SIZELIMIT = 3 ;The limit on the number of entries To Return from a search.
#LDAP_OPT_SSL = 10
#LDAP_OPT_PROTOCOL_VERSION = 17
#LDAP_AUTH_SIMPLE = 128
#LDAP_OPT_SERVER_CERTIFICATE = 129
#LDAP_SUCCESS = 0       ;The call completed successfully. 

PrototypeC.i Proto_ldap_getlasterror()
PrototypeC.i Proto_ldap_memfree(Block.l)
PrototypeC.i Proto_ldap_sslinit(Domainname$, PortNumber.l, Secure.l=#True)
PrototypeC.i Proto_ldap_init(Domainname$, PortNumber.l)
PrototypeC.i Proto_ldap_simple_bind(ld.l, Username$, Password$)
PrototypeC.i Proto_ldap_unbind(ld.l)
PrototypeC.i Proto_ldap_setoption(ld.l, option.l, invalue.l)
PrototypeC.i Proto_ldap_getoption(ld.l, option.l, outvalue.l)
PrototypeC.i Proto_ldap_search(ld.l, Base$, Scope.l, Filter$, Attrs.l, AttrsOnly.l, Result.l)
PrototypeC.i Proto_ldap_countentries(ld.l, res.l)
PrototypeC.i Proto_ldap_firstentry(ld.l, res.l)
PrototypeC.i Proto_ldap_nextentry(ld.l, res.l)
PrototypeC.i Proto_ldap_getdn(ld.l, entry.l)
PrototypeC.i Proto_ldap_firstattribute(ld.l, entry.l, ptr.l) 
PrototypeC.i Proto_ldap_Nextattribute(ld.l, entry.l, ptr.l)
PrototypeC.i Proto_ldap_getvaluesstring(ld.l, entry.l, attr.l)
PrototypeC.i Proto_ldap_valuefree(vals.l)
PrototypeC.i Proto_ldap_getvaluesbinary(ld.l, entry.l, attr.l)
PrototypeC.i Proto_ldap_valuefreelen(vals.l)
PrototypeC.i Proto_ldap_countvalues(vals.l)

LibNr.i = OpenLibrary(#PB_Any, "wldap32.dll")
If LibNr
    CompilerSelect #PB_Compiler_Unicode
        CompilerCase 0       
            Global LdapGetLastError.Proto_ldap_getlasterror = GetFunction(LibNr, "LdapGetLastError")
            Global LdapMemFree.Proto_ldap_memfree = GetFunction(LibNr, "Ldap_memfreeA")
            Global LdapSslInit.Proto_ldap_sslinit = GetFunction(LibNr, "ldap_sslinitA")
            Global LdapInit.Proto_ldap_init = GetFunction(LibNr, "ldap_initA")
            Global LdapBind.Proto_ldap_simple_bind = GetFunction(LibNr, "ldap_simple_bind_sA")
            Global LdapUnbind.Proto_ldap_unbind = GetFunction(LibNr, "ldap_unbind_s") 
            Global LdapSetOption.Proto_ldap_setoption = GetFunction(LibNr, "ldap_set_optionA")
            Global LdapGetOption.Proto_ldap_getoption = GetFunction(LibNr, "ldap_get_option")
            Global LdapSearch.Proto_ldap_search = GetFunction(LibNr, "ldap_search_sA") 
            Global LdapCountEntries.Proto_ldap_countentries = GetFunction(LibNr, "ldap_count_entries") 
            Global LdapFirstEntry.Proto_ldap_firstentry = GetFunction(LibNr, "ldap_first_entry") 
            Global LdapNextEntry.Proto_ldap_nextentry = GetFunction(LibNr, "ldap_next_entry") 
            Global LdapGetDN.Proto_ldap_getdn = GetFunction(LibNr, "ldap_get_dnA") 
            Global LdapFirstAttribute.Proto_ldap_firstattribute = GetFunction(LibNr, "ldap_first_attributeA") 
            Global LdapNextAttribute.Proto_ldap_nextattribute = GetFunction(LibNr, "ldap_next_attributeA") 
            Global LdapGetValuesString.Proto_ldap_getvaluesstring = GetFunction(LibNr, "ldap_get_valuesA") 
            Global LdapValueFree.Proto_ldap_valuefree = GetFunction(LibNr, "ldap_value_freeA") 
            Global LdapGetValuesBinary.Proto_ldap_getvaluesbinary = GetFunction(LibNr, "ldap_get_values_lenA") 
            Global LdapValueFreeLen.Proto_ldap_valuefreelen = GetFunction(LibNr, "ldap_value_free_len") 
            Global LdapCountValues.Proto_ldap_countvalues = GetFunction(LibNr, "ldap_count_valuesA")             
        CompilerCase 1   
            Global LdapGetLastError.Proto_ldap_getlasterror = GetFunction(LibNr, "LdapGetLastError")
            Global LdapMemFree.Proto_ldap_memfree = GetFunction(LibNr, "Ldap_memfreeW")
            Global LdapSslInit.Proto_ldap_sslinit = GetFunction(LibNr, "ldap_sslinitW")
            Global LdapInit.Proto_ldap_init = GetFunction(LibNr, "ldap_initW")
            Global LdapBind.Proto_ldap_simple_bind = GetFunction(LibNr, "ldap_simple_bind_sW")
            Global LdapUnbind.Proto_ldap_unbind = GetFunction(LibNr, "ldap_unbind_s")
            Global LdapSetOption.Proto_ldap_setoption = GetFunction(LibNr, "ldap_set_optionW")
            Global LdapGetOption.Proto_ldap_getoption = GetFunction(LibNr, "ldap_get_optionW")
            Global LdapSearch.Proto_ldap_search = GetFunction(LibNr, "ldap_search_sW")
            Global LdapCountEntries.Proto_ldap_countentries = GetFunction(LibNr, "ldap_count_entries")
            Global LdapFirstEntry.Proto_ldap_firstentry = GetFunction(LibNr, "ldap_first_entry")
            Global LdapNextEntry.Proto_ldap_nextentry = GetFunction(LibNr, "ldap_next_entry") 
            Global LdapGetDN.Proto_ldap_getdn = GetFunction(LibNr, "ldap_get_dnW")
            Global LdapFirstAttribute.Proto_ldap_firstattribute = GetFunction(LibNr, "ldap_first_attributeW") 
            Global LdapNextAttribute.Proto_ldap_nextattribute = GetFunction(LibNr, "ldap_next_attributeW") 
            Global LdapGetValuesString.Proto_ldap_getvaluesstring = GetFunction(LibNr, "ldap_get_valuesW")
            Global LdapValueFree.Proto_ldap_valuefree = GetFunction(LibNr, "ldap_value_freeW")            
            Global LdapGetValuesBinary.Proto_ldap_getvaluesbinary = GetFunction(LibNr, "ldap_get_values_lenW")
            Global LdapValueFreeLen.Proto_ldap_valuefreelen = GetFunction(LibNr, "ldap_value_free_len") 
            Global LdapCountValues.Proto_ldap_countvalues = GetFunction(LibNr, "ldap_count_valuesW")                         
    CompilerEndSelect    
Else
    MessageRequester("Error", "Unable to open the LDAP library", 16) : End    
EndIf

;UseJPEGImageDecoder()     

Global NewList LDAP_ENTRIES.i()
Global NewList LDAP_ATTRIBUTES.s()
Global NewList LDAP_VALUES.s()

;========================================
;========================================
;========================================
Procedure.i LDAP_CONNECT(Domainname$, Username$, Password$, SecuredConnection.i=#True, PortNr.i=0)
    *LDAP_HANDLE = 0
    ;INITIALIZE A SESSION WITH A LDAP SERVER
    Select SecuredConnection
        Case #True   
             If PortNr = 0 : PortNr = #LDAP_SSL_PORT : EndIf
            *LDAP_HANDLE = LdapSslInit(Domainname$, PortNr) 
        Default
            If PortNr = 0 : PortNr = #LDAP_PORT : EndIf
            *LDAP_HANDLE = LdapInit(Domainname$, PortNr) 
    EndSelect
    ;AUTHENTICATE THE CLIENT TO THE LDAP SERVER
    If *LDAP_HANDLE
        If LdapBind(*LDAP_HANDLE, Username$, Password$) <> -1
            ;SET LDAP OPTIONS
            LDAPVersion.l = 3 :     LdapSetOption(*LDAP_HANDLE, #LDAP_OPT_PROTOCOL_VERSION, @Version)
            TimeOut.i = 120 :       LdapSetOption(*LDAP_HANDLE, #LDAP_OPT_TIMELIMIT, @TimeOut) 
            SizeLimit.i = 1000 :    LdapSetOption(*LDAP_HANDLE, #LDAP_OPT_SIZELIMIT, @SizeLimit) 
            ;FOR SECURED SESSION ONLY
            If SecuredConnection = #True
                ;CHECK IF SSL IS ENABLED OTHERWISE ENABLE IT
                SSL.l = 0
                If LdapGetOption(*LDAP_HANDLE, #LDAP_OPT_SSL, @SSL) = #LDAP_SUCCESS
                    If SSL <> 1
                        Value.l = 1
                        LdapSetOption(*LDAP_HANDLE, #LDAP_OPT_SSL, @Value)
                        LdapGetOption(*LDAP_HANDLE, #LDAP_OPT_SSL, @SSL)
                    EndIf                
                EndIf                
                ;STOP IF SSL IS NOT ENABLED
                If SSL = 0
                    MessageRequester("Error", "SSL cound not be enabled.", 16) : End
                Else
                    Result = #True
                EndIf
            EndIf    
        Else
            MessageRequester("Error", "Unable to bind to the server.", 16)    
        EndIf
    Else
        MessageRequester("Error", "Incorrect LDAP session handle.", 16)    
    EndIf
    ProcedureReturn *LDAP_HANDLE
EndProcedure            
;========================================
Procedure.i LDAP_DISCONNECT(*LDAP_HANDLE)
    If *LDAP_HANDLE : LdapUnbind(*LDAP_HANDLE) : EndIf    
EndProcedure
;========================================
Procedure.i LDAP_GET_ENTRIES(*LDAP_HANDLE, Base$, Filter$, Scope.i)
    ClearList(LDAP_ENTRIES())
    If *LDAP_HANDLE
        ;SEARCH THE LDAP DIRECTORY FOR ENTRIES THAT MATCH THE 'SEARCH SCOPE' AND 'SEARCH FILTER' 
        If LdapSearch(*LDAP_HANDLE, Base$, Scope, Filter$, 0, 0, @*LDAP_RESULT) = #LDAP_SUCCESS
            If *LDAP_RESULT
                *LDAP_ENTRY = LdapFirstEntry(*LDAP_HANDLE, *LDAP_RESULT)
                AddElement(LDAP_ENTRIES()) : LDAP_ENTRIES() = *LDAP_ENTRY                
                While *LDAP_ENTRY 
                    *LDAP_ENTRY = LdapNextEntry(*LDAP_HANDLE, *LDAP_ENTRY)
                    If *LDAP_ENTRY : AddElement(LDAP_ENTRIES()) : LDAP_ENTRIES() = *LDAP_ENTRY : EndIf
                Wend
            EndIf
        Else
            MessageRequester("Error", "Unable to search for entries.", 16)
        EndIf        
    Else
        MessageRequester("Error", "Incorrect LDAP session handle.", 16)        
    EndIf 
    ProcedureReturn ListSize(LDAP_ENTRIES())
EndProcedure
;========================================
Procedure.s LDAP_GET_DISTINGUISHEDNAME(*LDAP_HANDLE, *LDAP_ENTRY)
    If *LDAP_HANDLE 
        If *LDAP_ENTRY
            *DN = LdapGetDN(*LDAP_HANDLE, *LDAP_ENTRY) 
            If *DN 
                ProcedureReturn PeekS(*DN)
            EndIf
        Else
            MessageRequester("Error", "Incorrect result entry.", 16)        
        EndIf
    Else
        MessageRequester("Error", "Incorrect LDAP session handle.", 16)        
    EndIf
EndProcedure
;========================================
Procedure.i LDAP_GET_ATTRIBUTES(*LDAP_HANDLE, *LDAP_ENTRY)
    ClearList(LDAP_ATTRIBUTES())
    If *LDAP_HANDLE 
        If *LDAP_ENTRY 
            *BerElement = 0
            *LDAP_ATTRIBUTE = LdapFirstAttribute(*LDAP_HANDLE, *LDAP_ENTRY, @*BerElement)
            If *LDAP_ATTRIBUTE
                AddElement(LDAP_ATTRIBUTES()) : LDAP_ATTRIBUTES() = PeekS(*LDAP_ATTRIBUTE)
                While *LDAP_ATTRIBUTE And *BerElement
                    *LDAP_ATTRIBUTE = LdapNextAttribute(*LDAP_HANDLE, *LDAP_ENTRY, *BerElement) 
                    If *LDAP_ATTRIBUTE
                        AddElement(LDAP_ATTRIBUTES()) : LDAP_ATTRIBUTES() = PeekS(*LDAP_ATTRIBUTE)
                    EndIf
                Wend
            EndIf
        Else
            MessageRequester("Error", "Incorrect result entry.", 16)        
        EndIf
    Else
        MessageRequester("Error", "Incorrect LDAP session handle.", 16)        
    EndIf
    ProcedureReturn ListSize(LDAP_ATTRIBUTES())
EndProcedure 
;========================================
Procedure.i LDAP_GET_VALUES_STR(*LDAP_HANDLE, *LDAP_ENTRY, Attributename$)
    ClearList(LDAP_VALUES())
    Attributename$ = UCase(Attributename$)
    If *LDAP_HANDLE 
        If *LDAP_ENTRY     
            *BerElement = 0
            *LDAP_ATTRIBUTE = LdapFirstAttribute(*LDAP_HANDLE, *LDAP_ENTRY, @*BerElement)
            While *BerElement And *LDAP_ATTRIBUTE
                If UCase(PeekS(*LDAP_ATTRIBUTE)) = Attributename$                            
                    *ValueArray = LdapGetValuesString(*LDAP_HANDLE, *LDAP_ENTRY, *LDAP_ATTRIBUTE)
                    If *ValueArray
                        NbrValues.i = LdapCountValues(*ValueArray)
                        If NbrValues
                            For counter = 0 To (NbrValues*4)-1 Step 4
                                Debug PeekL(*ValueArray + counter)
                                AddElement(LDAP_VALUES()) : LDAP_VALUES() = PeekS(PeekL(*ValueArray + counter))
                            Next
                        EndIf 
                        LdapValueFree(*ValueArray)
                    EndIf
                EndIf
                *LDAP_ATTRIBUTE = LdapNextAttribute(*LDAP_HANDLE, *LDAP_ENTRY, *BerElement)
            Wend            
        Else
            MessageRequester("Error", "Incorrect result entry.", 16)        
        EndIf
    Else
        MessageRequester("Error", "Incorrect LDAP session handle.", 16)        
    EndIf
    ProcedureReturn ListSize(LDAP_VALUES())            
EndProcedure
;========================================
Procedure.i LDAP_GET_VALUES_BIN(*LDAP_HANDLE, *LDAP_ENTRY, Attributename$)
    ClearList(LDAP_VALUES())
    Attributename$ = UCase(Attributename$)
    If *LDAP_HANDLE 
        If *LDAP_ENTRY 
            *BerElement = 0
            *LDAP_ATTRIBUTE = LdapFirstAttribute(*LDAP_HANDLE, *LDAP_ENTRY, @*BerElement)
            While *BerElement And *LDAP_ATTRIBUTE
                If UCase(PeekS(*LDAP_ATTRIBUTE)) = Attributename$ 
                    *BerElementValArray = LdapGetValuesBinary(*LDAP_HANDLE, *LDAP_ENTRY, *LDAP_ATTRIBUTE)
                    If *BerElementValArray
                        NbrValues.i = LdapCountValues(*BerElementValArray)
                        If NbrValues                             
                            For counter = 0 To (NbrValues*8)-1 Step 8
                                OffsetBerval.i = PeekL(*BerElementValArray + counter)
                                Length.i = PeekL(OffsetBerval) 
                                *Pointer = PeekL(OffsetBerval + 4)
                                If Length And *Pointer
                                    *Buffer = AllocateMemory(Length)
                                    If *Buffer
                                        CopyMemory(*Pointer, *Buffer, Length) 
                                        AddElement(LDAP_VALUES()) : LDAP_VALUES() = Str(*Buffer) + ";" + Str(Length)
                                    EndIf
                                EndIf
                            Next    
                            Ldapvaluefreelen(*BerElementValArray)
                        EndIf
                    EndIf
                EndIf
                *LDAP_ATTRIBUTE = LdapNextAttribute(*LDAP_HANDLE, *LDAP_ENTRY, *BerElement)
            Wend            
        Else
            MessageRequester("Error", "Incorrect result entry.", 16)        
        EndIf
    Else
        MessageRequester("Error", "Incorrect LDAP session handle.", 16)        
    EndIf
    ProcedureReturn ListSize(LDAP_VALUES())            
EndProcedure

;========================================
;========================================
;========================================
Domainname$ = "xxxx"     
Username$ = "xxxx" 
Password$ = "xxxx" 
Base$ = "dc=xxxx,dc=xxxx"        
;Base$ = "ou=xxxx,dc=xxxx,dc=xxxx"
Scope.i = #LDAP_SCOPE_SUBTREE
Filter$ = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=e*))"                                       ;All users with username starting with e
;Filter$ = "(&(objectCategory=person)(objectClass=user))"                                                           ;All users
;Filter$ = "(&(objectCategory=person)(objectClass=user)(cn=schm*))"                                                 ;All users with CN starting with schm...
;Filter$ = "(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))"         ;All users with "Password Never Expires" set 
;Filter$ = "(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))"             ;All disabled user objects
;Filter$ = "(&(objectCategory=person)(objectClass=user)(accountExpires>=1)(accountExpires<=9223372036854775806))"   ;Users with accounts that do expire
;Filter$ = "(&(objectCategory=person)(objectClass=user)(pwdLastSet=0))"                                             ;All users that must change their password at next logon
;Filter$ = "(&(objectClass=user)(!lockoutTime>=1)(lockoutDuration=*))" 
;Filter$ = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=a*)(lockoutTime>=1))" 
;Filter$ = "(&(objectCategory=person)(objectClass=user)(lockoutTime>=1))"                                           ;All users with locked account
;Filter$ = "(&(objectCategory=person)(objectClass=user)(thumbnailPhoto=*))"                                         ;All users with photo

*LDAP_HANDLE = LDAP_CONNECT(Domainname$, Username$, Password$, #True)   ;#True=SSL-encryption  #False=NoEncryption
If *LDAP_HANDLE        
    LDAP_GET_ENTRIES(*LDAP_HANDLE, Base$, Filter$, Scope) 
    ForEach LDAP_ENTRIES() 
        ;=============    
        ;This function returns the DN for the current entry
        DN$ = LDAP_GET_DISTINGUISHEDNAME(*LDAP_HANDLE, LDAP_ENTRIES())
        Debug DN$
        ;=============    
;         ;This function returns a list of available attributes for the current entry
;         LDAP_GET_ATTRIBUTES(*LDAP_HANDLE, LDAP_ENTRIES()) 
;         ForEach LDAP_ATTRIBUTES() : Debug LDAP_ATTRIBUTES() : Next
        ;=============    
;         ;This function returns a list of string values for the provided attribute for the current entry        
;         LDAP_GET_VALUES_STR(*LDAP_HANDLE, LDAP_ENTRIES(), "memberof")
;         ForEach LDAP_VALUES() : Debug LDAP_VALUES() : Next
        ;=============    
;         ;This function allocates a buffer for each binary value for the provided attribute for the current entry and returns the list of Bufferaddr and Bufferlength as a semicolon separated string.
;         ;DON'T FORGET TO FREE THE BUFFERS AS SOON AS THEY ARE NOT NEEDED ANYMORE
;         LDAP_GET_VALUES_BIN(*LDAP_HANDLE, LDAP_ENTRIES(), "thumbnailPhoto")
;         ForEach LDAP_VALUES() : Debug LDAP_VALUES()
;        
;             ; EXAMPLE WITH THE ATTRIBUTE 'thumbnailPhoto' (JPEG)  
;             *Buffer = Val(StringField(LDAP_VALUES(),1,";"))
;             Length = Val(StringField(LDAP_VALUES(),2,";"))
;             If *Buffer
;                 If CatchImage(0, *Buffer)
;                     If OpenWindow(0, 0, 0, ImageWidth(0), ImageHeight(0), "thumbnailPhoto", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
;                        ImageGadget(0, 0, 0, ImageWidth(0), ImageHeight(0), ImageID(0))  
;                        Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
;                     EndIf
;                 EndIf
;                 FreeMemory(*Buffer)
;             EndIf
;        
;         Next
        ;=============  
    Next  
    LDAP_DISCONNECT(*LDAP_HANDLE)
EndIf 

FreeList(LDAP_ENTRIES.i())
FreeList(LDAP_ATTRIBUTES.s())
FreeList(LDAP_VALUES.s())
End
User avatar
Kukulkan
Addict
Addict
Posts: 1352
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: Basic LDAP Viewer

Post by Kukulkan »

Very nice, thanks for sharing! :D
dige
Addict
Addict
Posts: 1247
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Re: Basic LDAP Viewer

Post by dige »

Thx TeddyLM for sharing.

I am looking for a simple login check via active directory.

Unfortunately, LdapBind(*LDAP_HANDLE, Username$, Password$) does not seem to be suitable for this.
It always returns <> -1, even if the password is wrong.

Does anyone else have a tip?

EDIT:
I just found out that it works like this:

Code: Select all

If LdapBind(*LDAP_HANDLE, Username$ + "@" + Domainname$, Password$) = #LDAP_SUCCESS
"Daddy, I'll run faster, then it is not so far..."
Post Reply