// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // File contains Search functionality package ldap import ( "github.com/mmitton/asn1-ber" "fmt" "os" ) const ( ScopeBaseObject = 0 ScopeSingleLevel = 1 ScopeWholeSubtree = 2 ) var ScopeMap = map[ int ] string { ScopeBaseObject : "Base Object", ScopeSingleLevel : "Single Level", ScopeWholeSubtree : "Whole Subtree", } const ( NeverDerefAliases = 0 DerefInSearching = 1 DerefFindingBaseObj = 2 DerefAlways = 3 ) var DerefMap = map[ int ] string { NeverDerefAliases : "NeverDerefAliases", DerefInSearching : "DerefInSearching", DerefFindingBaseObj : "DerefFindingBaseObj", DerefAlways : "DerefAlways", } type Entry struct { DN string Attributes []*EntryAttribute } type EntryAttribute struct { Name string Values []string } type SearchResult struct { Entries []*Entry Referrals []string Controls []Control } func (e *Entry) GetAttributeValues( Attribute string ) []string { for _, attr := range e.Attributes { if attr.Name == Attribute { return attr.Values } } return []string{ } } func (e *Entry) GetAttributeValue( Attribute string ) string { values := e.GetAttributeValues( Attribute ) if len( values ) == 0 { return "" } return values[ 0 ] } type SearchRequest struct { BaseDN string Scope int DerefAliases int SizeLimit int TimeLimit int TypesOnly bool Filter string Attributes []string Controls []Control } func NewSearchRequest( BaseDN string, Scope, DerefAliases, SizeLimit, TimeLimit int, TypesOnly bool, Filter string, Attributes []string, Controls []Control, ) (*SearchRequest) { return &SearchRequest{ BaseDN: BaseDN, Scope: Scope, DerefAliases: DerefAliases, SizeLimit: SizeLimit, TimeLimit: TimeLimit, TypesOnly: TypesOnly, Filter: Filter, Attributes: Attributes, Controls: Controls, } } func (l *Conn) SearchWithPaging( SearchRequest *SearchRequest, PagingSize uint32 ) (*SearchResult, *Error) { if SearchRequest.Controls == nil { SearchRequest.Controls = make( []Control, 0 ) } PagingControl := NewControlPaging( PagingSize ) SearchRequest.Controls = append( SearchRequest.Controls, PagingControl ) SearchResult := new( SearchResult ) for { result, err := l.Search( SearchRequest ) if l.Debug { fmt.Printf( "Looking for Paging Control...\n" ) } if err != nil { return SearchResult, err } if result == nil { return SearchResult, NewError( ErrorNetwork, os.NewError( "Packet not received" ) ) } for _, entry := range result.Entries { SearchResult.Entries = append( SearchResult.Entries, entry ) } for _, referral := range result.Referrals { SearchResult.Referrals = append( SearchResult.Referrals, referral ) } for _, control := range result.Controls { SearchResult.Controls = append( SearchResult.Controls, control ) } if l.Debug { fmt.Printf( "Looking for Paging Control...\n" ) } paging_result := FindControl( result.Controls, ControlTypePaging ) if paging_result == nil { PagingControl = nil if l.Debug { fmt.Printf( "Could not find paging control. Breaking...\n" ) } break } cookie := paging_result.(*ControlPaging).Cookie if len( cookie ) == 0 { PagingControl = nil if l.Debug { fmt.Printf( "Could not find cookie. Breaking...\n" ) } break } PagingControl.SetCookie( cookie ) } if PagingControl != nil { if l.Debug { fmt.Printf( "Abandoning Paging...\n" ) } PagingControl.PagingSize = 0 l.Search( SearchRequest ) } return SearchResult, nil } func (l *Conn) Search( SearchRequest *SearchRequest ) (*SearchResult, *Error) { messageID := l.nextMessageID() packet := ber.Encode( ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request" ) packet.AppendChild( ber.NewInteger( ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, messageID, "MessageID" ) ) searchRequest := ber.Encode( ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request" ) searchRequest.AppendChild( ber.NewString( ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, SearchRequest.BaseDN, "Base DN" ) ) searchRequest.AppendChild( ber.NewInteger( ber.ClassUniversal, ber.TypePrimative, ber.TagEnumerated, uint64(SearchRequest.Scope), "Scope" ) ) searchRequest.AppendChild( ber.NewInteger( ber.ClassUniversal, ber.TypePrimative, ber.TagEnumerated, uint64(SearchRequest.DerefAliases), "Deref Aliases" ) ) searchRequest.AppendChild( ber.NewInteger( ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, uint64(SearchRequest.SizeLimit), "Size Limit" ) ) searchRequest.AppendChild( ber.NewInteger( ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, uint64(SearchRequest.TimeLimit), "Time Limit" ) ) searchRequest.AppendChild( ber.NewBoolean( ber.ClassUniversal, ber.TypePrimative, ber.TagBoolean, SearchRequest.TypesOnly, "Types Only" ) ) filterPacket, err := CompileFilter( SearchRequest.Filter ) if err != nil { return nil, err } searchRequest.AppendChild( filterPacket ) attributesPacket := ber.Encode( ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes" ) for _, attribute := range SearchRequest.Attributes { attributesPacket.AppendChild( ber.NewString( ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, attribute, "Attribute" ) ) } searchRequest.AppendChild( attributesPacket ) packet.AppendChild( searchRequest ) if SearchRequest.Controls != nil { packet.AppendChild( encodeControls( SearchRequest.Controls ) ) } if l.Debug { ber.PrintPacket( packet ) } channel, err := l.sendMessage( packet ) if err != nil { return nil, err } if channel == nil { return nil, NewError( ErrorNetwork, os.NewError( "Could not send message" ) ) } defer l.finishMessage( messageID ) result := &SearchResult{ Entries: make( []*Entry, 0 ), Referrals: make( []string, 0 ), Controls: make( []Control, 0 ) } foundSearchResultDone := false for !foundSearchResultDone { if l.Debug { fmt.Printf( "%d: waiting for response\n", messageID ) } packet = <-channel if l.Debug { fmt.Printf( "%d: got response %p\n", messageID, packet ) } if packet == nil { return nil, NewError( ErrorNetwork, os.NewError( "Could not retrieve message" ) ) } if l.Debug { if err := addLDAPDescriptions( packet ); err != nil { return nil, NewError( ErrorDebugging, err ) } ber.PrintPacket( packet ) } switch packet.Children[ 1 ].Tag { case 4: entry := new( Entry ) entry.DN = packet.Children[ 1 ].Children[ 0 ].Value.(string) for _, child := range packet.Children[ 1 ].Children[ 1 ].Children { attr := new( EntryAttribute ) attr.Name = child.Children[ 0 ].Value.(string) for _, value := range child.Children[ 1 ].Children { attr.Values = append( attr.Values, value.Value.(string) ) } entry.Attributes = append( entry.Attributes, attr ) } result.Entries = append( result.Entries, entry ) case 5: result_code, result_description := getLDAPResultCode( packet ) if result_code != 0 { return result, NewError( result_code, os.NewError( result_description ) ) } if len( packet.Children ) == 3 { for _, child := range packet.Children[ 2 ].Children { result.Controls = append( result.Controls, DecodeControl( child ) ) } } foundSearchResultDone = true case 19: result.Referrals = append( result.Referrals, packet.Children[ 1 ].Children[ 0 ].Value.(string) ) } } if l.Debug { fmt.Printf( "%d: returning\n", messageID ) } return result, nil }