| @@ -37,8 +37,10 @@ github.com/Unknwon/paginater = commit:7748a72 | |||
| golang.org/x/net = | |||
| golang.org/x/text = | |||
| golang.org/x/crypto = | |||
| gopkg.in/asn1-ber.v1 = | |||
| gopkg.in/gomail.v2 = commit:df6fc79 | |||
| gopkg.in/ini.v1 = commit:2e44421 | |||
| gopkg.in/ldap.v2 = | |||
| gopkg.in/macaron.v1 = commit:1c6dd87 | |||
| gopkg.in/redis.v2 = commit:e617904962 | |||
| @@ -1,27 +0,0 @@ | |||
| Copyright (c) 2012 The Go Authors. All rights reserved. | |||
| Redistribution and use in source and binary forms, with or without | |||
| modification, are permitted provided that the following conditions are | |||
| met: | |||
| * Redistributions of source code must retain the above copyright | |||
| notice, this list of conditions and the following disclaimer. | |||
| * Redistributions in binary form must reproduce the above | |||
| copyright notice, this list of conditions and the following disclaimer | |||
| in the documentation and/or other materials provided with the | |||
| distribution. | |||
| * Neither the name of Google Inc. nor the names of its | |||
| contributors may be used to endorse or promote products derived from | |||
| this software without specific prior written permission. | |||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| @@ -1,11 +0,0 @@ | |||
| # Copyright 2009 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. | |||
| include $(GOROOT)/src/Make.inc | |||
| TARG=github.com/mmitton/asn1-ber | |||
| GOFILES=\ | |||
| ber.go\ | |||
| include $(GOROOT)/src/Make.pkg | |||
| @@ -1,14 +0,0 @@ | |||
| ASN1 BER Encoding / Decoding Library for the GO programming language. | |||
| Required Librarys: | |||
| None | |||
| Working: | |||
| Very basic encoding / decoding needed for LDAP protocol | |||
| Tests Implemented: | |||
| None | |||
| TODO: | |||
| Fix all encoding / decoding to conform to ASN1 BER spec | |||
| Implement Tests / Benchmarks | |||
| @@ -1,497 +0,0 @@ | |||
| package ber | |||
| import ( | |||
| "bytes" | |||
| "fmt" | |||
| "io" | |||
| "reflect" | |||
| "errors" | |||
| ) | |||
| type Packet struct { | |||
| ClassType uint8 | |||
| TagType uint8 | |||
| Tag uint8 | |||
| Value interface{} | |||
| ByteValue []byte | |||
| Data *bytes.Buffer | |||
| Children []*Packet | |||
| Description string | |||
| } | |||
| const ( | |||
| TagEOC = 0x00 | |||
| TagBoolean = 0x01 | |||
| TagInteger = 0x02 | |||
| TagBitString = 0x03 | |||
| TagOctetString = 0x04 | |||
| TagNULL = 0x05 | |||
| TagObjectIdentifier = 0x06 | |||
| TagObjectDescriptor = 0x07 | |||
| TagExternal = 0x08 | |||
| TagRealFloat = 0x09 | |||
| TagEnumerated = 0x0a | |||
| TagEmbeddedPDV = 0x0b | |||
| TagUTF8String = 0x0c | |||
| TagRelativeOID = 0x0d | |||
| TagSequence = 0x10 | |||
| TagSet = 0x11 | |||
| TagNumericString = 0x12 | |||
| TagPrintableString = 0x13 | |||
| TagT61String = 0x14 | |||
| TagVideotexString = 0x15 | |||
| TagIA5String = 0x16 | |||
| TagUTCTime = 0x17 | |||
| TagGeneralizedTime = 0x18 | |||
| TagGraphicString = 0x19 | |||
| TagVisibleString = 0x1a | |||
| TagGeneralString = 0x1b | |||
| TagUniversalString = 0x1c | |||
| TagCharacterString = 0x1d | |||
| TagBMPString = 0x1e | |||
| TagBitmask = 0x1f // xxx11111b | |||
| ) | |||
| var TagMap = map[uint8]string{ | |||
| TagEOC: "EOC (End-of-Content)", | |||
| TagBoolean: "Boolean", | |||
| TagInteger: "Integer", | |||
| TagBitString: "Bit String", | |||
| TagOctetString: "Octet String", | |||
| TagNULL: "NULL", | |||
| TagObjectIdentifier: "Object Identifier", | |||
| TagObjectDescriptor: "Object Descriptor", | |||
| TagExternal: "External", | |||
| TagRealFloat: "Real (float)", | |||
| TagEnumerated: "Enumerated", | |||
| TagEmbeddedPDV: "Embedded PDV", | |||
| TagUTF8String: "UTF8 String", | |||
| TagRelativeOID: "Relative-OID", | |||
| TagSequence: "Sequence and Sequence of", | |||
| TagSet: "Set and Set OF", | |||
| TagNumericString: "Numeric String", | |||
| TagPrintableString: "Printable String", | |||
| TagT61String: "T61 String", | |||
| TagVideotexString: "Videotex String", | |||
| TagIA5String: "IA5 String", | |||
| TagUTCTime: "UTC Time", | |||
| TagGeneralizedTime: "Generalized Time", | |||
| TagGraphicString: "Graphic String", | |||
| TagVisibleString: "Visible String", | |||
| TagGeneralString: "General String", | |||
| TagUniversalString: "Universal String", | |||
| TagCharacterString: "Character String", | |||
| TagBMPString: "BMP String", | |||
| } | |||
| const ( | |||
| ClassUniversal = 0 // 00xxxxxxb | |||
| ClassApplication = 64 // 01xxxxxxb | |||
| ClassContext = 128 // 10xxxxxxb | |||
| ClassPrivate = 192 // 11xxxxxxb | |||
| ClassBitmask = 192 // 11xxxxxxb | |||
| ) | |||
| var ClassMap = map[uint8]string{ | |||
| ClassUniversal: "Universal", | |||
| ClassApplication: "Application", | |||
| ClassContext: "Context", | |||
| ClassPrivate: "Private", | |||
| } | |||
| const ( | |||
| TypePrimitive = 0 // xx0xxxxxb | |||
| TypeConstructed = 32 // xx1xxxxxb | |||
| TypeBitmask = 32 // xx1xxxxxb | |||
| ) | |||
| var TypeMap = map[uint8]string{ | |||
| TypePrimitive: "Primative", | |||
| TypeConstructed: "Constructed", | |||
| } | |||
| var Debug bool = false | |||
| func PrintBytes(buf []byte, indent string) { | |||
| data_lines := make([]string, (len(buf)/30)+1) | |||
| num_lines := make([]string, (len(buf)/30)+1) | |||
| for i, b := range buf { | |||
| data_lines[i/30] += fmt.Sprintf("%02x ", b) | |||
| num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100) | |||
| } | |||
| for i := 0; i < len(data_lines); i++ { | |||
| fmt.Print(indent + data_lines[i] + "\n") | |||
| fmt.Print(indent + num_lines[i] + "\n\n") | |||
| } | |||
| } | |||
| func PrintPacket(p *Packet) { | |||
| printPacket(p, 0, false) | |||
| } | |||
| func printPacket(p *Packet, indent int, printBytes bool) { | |||
| indent_str := "" | |||
| for len(indent_str) != indent { | |||
| indent_str += " " | |||
| } | |||
| class_str := ClassMap[p.ClassType] | |||
| tagtype_str := TypeMap[p.TagType] | |||
| tag_str := fmt.Sprintf("0x%02X", p.Tag) | |||
| if p.ClassType == ClassUniversal { | |||
| tag_str = TagMap[p.Tag] | |||
| } | |||
| value := fmt.Sprint(p.Value) | |||
| description := "" | |||
| if p.Description != "" { | |||
| description = p.Description + ": " | |||
| } | |||
| fmt.Printf("%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value) | |||
| if printBytes { | |||
| PrintBytes(p.Bytes(), indent_str) | |||
| } | |||
| for _, child := range p.Children { | |||
| printPacket(child, indent+1, printBytes) | |||
| } | |||
| } | |||
| func resizeBuffer(in []byte, new_size uint64) (out []byte) { | |||
| out = make([]byte, new_size) | |||
| copy(out, in) | |||
| return | |||
| } | |||
| func readBytes(reader io.Reader, buf []byte) error { | |||
| idx := 0 | |||
| buflen := len(buf) | |||
| if reader == nil { | |||
| return errors.New("reader was nil, aborting") | |||
| } | |||
| for idx < buflen { | |||
| n, err := reader.Read(buf[idx:]) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| idx += n | |||
| } | |||
| return nil | |||
| } | |||
| func ReadPacket(reader io.Reader) (*Packet, error) { | |||
| buf := make([]byte, 2) | |||
| err := readBytes(reader, buf) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| idx := uint64(2) | |||
| datalen := uint64(buf[1]) | |||
| if Debug { | |||
| fmt.Printf("Read: datalen = %d len(buf) = %d ", datalen, len(buf)) | |||
| for _, b := range buf { | |||
| fmt.Printf("%02X ", b) | |||
| } | |||
| fmt.Printf("\n") | |||
| } | |||
| if datalen&128 != 0 { | |||
| a := datalen - 128 | |||
| idx += a | |||
| buf = resizeBuffer(buf, 2+a) | |||
| err := readBytes(reader, buf[2:]) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| datalen = DecodeInteger(buf[2 : 2+a]) | |||
| if Debug { | |||
| fmt.Printf("Read: a = %d idx = %d datalen = %d len(buf) = %d", a, idx, datalen, len(buf)) | |||
| for _, b := range buf { | |||
| fmt.Printf("%02X ", b) | |||
| } | |||
| fmt.Printf("\n") | |||
| } | |||
| } | |||
| buf = resizeBuffer(buf, idx+datalen) | |||
| err = readBytes(reader, buf[idx:]) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if Debug { | |||
| fmt.Printf("Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n", len(buf), idx, datalen, idx+datalen) | |||
| for _, b := range buf { | |||
| fmt.Printf("%02X ", b) | |||
| } | |||
| } | |||
| p := DecodePacket(buf) | |||
| return p, nil | |||
| } | |||
| func DecodeString(data []byte) (ret string) { | |||
| // for _, c := range data { | |||
| // ret += fmt.Sprintf("%c", c) | |||
| // } | |||
| return string(data) | |||
| } | |||
| func DecodeInteger(data []byte) (ret uint64) { | |||
| for _, i := range data { | |||
| ret = ret * 256 | |||
| ret = ret + uint64(i) | |||
| } | |||
| return | |||
| } | |||
| func EncodeInteger(val uint64) []byte { | |||
| var out bytes.Buffer | |||
| found := false | |||
| shift := uint(56) | |||
| mask := uint64(0xFF00000000000000) | |||
| for mask > 0 { | |||
| if !found && (val&mask != 0) { | |||
| found = true | |||
| } | |||
| if found || (shift == 0) { | |||
| out.Write([]byte{byte((val & mask) >> shift)}) | |||
| } | |||
| shift -= 8 | |||
| mask = mask >> 8 | |||
| } | |||
| return out.Bytes() | |||
| } | |||
| func DecodePacket(data []byte) *Packet { | |||
| p, _ := decodePacket(data) | |||
| return p | |||
| } | |||
| func decodePacket(data []byte) (*Packet, []byte) { | |||
| if Debug { | |||
| fmt.Printf("decodePacket: enter %d\n", len(data)) | |||
| } | |||
| p := new(Packet) | |||
| p.ClassType = data[0] & ClassBitmask | |||
| p.TagType = data[0] & TypeBitmask | |||
| p.Tag = data[0] & TagBitmask | |||
| datalen := DecodeInteger(data[1:2]) | |||
| datapos := uint64(2) | |||
| if datalen&128 != 0 { | |||
| datalen -= 128 | |||
| datapos += datalen | |||
| datalen = DecodeInteger(data[2 : 2+datalen]) | |||
| } | |||
| p.Data = new(bytes.Buffer) | |||
| p.Children = make([]*Packet, 0, 2) | |||
| p.Value = nil | |||
| value_data := data[datapos : datapos+datalen] | |||
| if p.TagType == TypeConstructed { | |||
| for len(value_data) != 0 { | |||
| var child *Packet | |||
| child, value_data = decodePacket(value_data) | |||
| p.AppendChild(child) | |||
| } | |||
| } else if p.ClassType == ClassUniversal { | |||
| p.Data.Write(data[datapos : datapos+datalen]) | |||
| p.ByteValue = value_data | |||
| switch p.Tag { | |||
| case TagEOC: | |||
| case TagBoolean: | |||
| val := DecodeInteger(value_data) | |||
| p.Value = val != 0 | |||
| case TagInteger: | |||
| p.Value = DecodeInteger(value_data) | |||
| case TagBitString: | |||
| case TagOctetString: | |||
| p.Value = DecodeString(value_data) | |||
| case TagNULL: | |||
| case TagObjectIdentifier: | |||
| case TagObjectDescriptor: | |||
| case TagExternal: | |||
| case TagRealFloat: | |||
| case TagEnumerated: | |||
| p.Value = DecodeInteger(value_data) | |||
| case TagEmbeddedPDV: | |||
| case TagUTF8String: | |||
| case TagRelativeOID: | |||
| case TagSequence: | |||
| case TagSet: | |||
| case TagNumericString: | |||
| case TagPrintableString: | |||
| p.Value = DecodeString(value_data) | |||
| case TagT61String: | |||
| case TagVideotexString: | |||
| case TagIA5String: | |||
| case TagUTCTime: | |||
| case TagGeneralizedTime: | |||
| case TagGraphicString: | |||
| case TagVisibleString: | |||
| case TagGeneralString: | |||
| case TagUniversalString: | |||
| case TagCharacterString: | |||
| case TagBMPString: | |||
| } | |||
| } else { | |||
| p.Data.Write(data[datapos : datapos+datalen]) | |||
| } | |||
| return p, data[datapos+datalen:] | |||
| } | |||
| func (p *Packet) DataLength() uint64 { | |||
| return uint64(p.Data.Len()) | |||
| } | |||
| func (p *Packet) Bytes() []byte { | |||
| var out bytes.Buffer | |||
| out.Write([]byte{p.ClassType | p.TagType | p.Tag}) | |||
| packet_length := EncodeInteger(p.DataLength()) | |||
| if p.DataLength() > 127 || len(packet_length) > 1 { | |||
| out.Write([]byte{byte(len(packet_length) | 128)}) | |||
| out.Write(packet_length) | |||
| } else { | |||
| out.Write(packet_length) | |||
| } | |||
| out.Write(p.Data.Bytes()) | |||
| return out.Bytes() | |||
| } | |||
| func (p *Packet) AppendChild(child *Packet) { | |||
| p.Data.Write(child.Bytes()) | |||
| if len(p.Children) == cap(p.Children) { | |||
| newChildren := make([]*Packet, cap(p.Children)*2) | |||
| copy(newChildren, p.Children) | |||
| p.Children = newChildren[0:len(p.Children)] | |||
| } | |||
| p.Children = p.Children[0 : len(p.Children)+1] | |||
| p.Children[len(p.Children)-1] = child | |||
| } | |||
| func Encode(ClassType, TagType, Tag uint8, Value interface{}, Description string) *Packet { | |||
| p := new(Packet) | |||
| p.ClassType = ClassType | |||
| p.TagType = TagType | |||
| p.Tag = Tag | |||
| p.Data = new(bytes.Buffer) | |||
| p.Children = make([]*Packet, 0, 2) | |||
| p.Value = Value | |||
| p.Description = Description | |||
| if Value != nil { | |||
| v := reflect.ValueOf(Value) | |||
| if ClassType == ClassUniversal { | |||
| switch Tag { | |||
| case TagOctetString: | |||
| sv, ok := v.Interface().(string) | |||
| if ok { | |||
| p.Data.Write([]byte(sv)) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return p | |||
| } | |||
| func NewSequence(Description string) *Packet { | |||
| return Encode(ClassUniversal, TypePrimitive, TagSequence, nil, Description) | |||
| } | |||
| func NewBoolean(ClassType, TagType, Tag uint8, Value bool, Description string) *Packet { | |||
| intValue := 0 | |||
| if Value { | |||
| intValue = 1 | |||
| } | |||
| p := Encode(ClassType, TagType, Tag, nil, Description) | |||
| p.Value = Value | |||
| p.Data.Write(EncodeInteger(uint64(intValue))) | |||
| return p | |||
| } | |||
| func NewInteger(ClassType, TagType, Tag uint8, Value uint64, Description string) *Packet { | |||
| p := Encode(ClassType, TagType, Tag, nil, Description) | |||
| p.Value = Value | |||
| p.Data.Write(EncodeInteger(Value)) | |||
| return p | |||
| } | |||
| func NewString(ClassType, TagType, Tag uint8, Value, Description string) *Packet { | |||
| p := Encode(ClassType, TagType, Tag, nil, Description) | |||
| p.Value = Value | |||
| p.Data.Write([]byte(Value)) | |||
| return p | |||
| } | |||
| @@ -11,7 +11,8 @@ import ( | |||
| "fmt" | |||
| "strings" | |||
| "github.com/gogits/gogs/modules/ldap" | |||
| "gopkg.in/ldap.v2" | |||
| "github.com/gogits/gogs/modules/log" | |||
| ) | |||
| @@ -1,27 +0,0 @@ | |||
| Copyright (c) 2012 The Go Authors. All rights reserved. | |||
| Redistribution and use in source and binary forms, with or without | |||
| modification, are permitted provided that the following conditions are | |||
| met: | |||
| * Redistributions of source code must retain the above copyright | |||
| notice, this list of conditions and the following disclaimer. | |||
| * Redistributions in binary form must reproduce the above | |||
| copyright notice, this list of conditions and the following disclaimer | |||
| in the documentation and/or other materials provided with the | |||
| distribution. | |||
| * Neither the name of Google Inc. nor the names of its | |||
| contributors may be used to endorse or promote products derived from | |||
| this software without specific prior written permission. | |||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| @@ -1,33 +0,0 @@ | |||
| Basic LDAP v3 functionality for the GO programming language. | |||
| Required Librarys: | |||
| github.com/johnweldon/asn1-ber | |||
| Working: | |||
| Connecting to LDAP server | |||
| Binding to LDAP server | |||
| Searching for entries | |||
| Compiling string filters to LDAP filters | |||
| Paging Search Results | |||
| Modify Requests / Responses | |||
| Examples: | |||
| search | |||
| modify | |||
| Tests Implemented: | |||
| Filter Compile / Decompile | |||
| TODO: | |||
| Add Requests / Responses | |||
| Delete Requests / Responses | |||
| Modify DN Requests / Responses | |||
| Compare Requests / Responses | |||
| Implement Tests / Benchmarks | |||
| This feature is disabled at the moment, because in some cases the "Search Request Done" packet will be handled before the last "Search Request Entry": | |||
| Mulitple internal goroutines to handle network traffic | |||
| Makes library goroutine safe | |||
| Can perform multiple search requests at the same time and return | |||
| the results to the proper goroutine. All requests are blocking | |||
| requests, so the goroutine does not need special handling | |||
| @@ -1,63 +0,0 @@ | |||
| dn: dc=enterprise,dc=org | |||
| objectClass: dcObject | |||
| objectClass: organization | |||
| o: acme | |||
| dn: cn=admin,dc=enterprise,dc=org | |||
| objectClass: person | |||
| cn: admin | |||
| sn: admin | |||
| description: "LDAP Admin" | |||
| dn: ou=crew,dc=enterprise,dc=org | |||
| ou: crew | |||
| objectClass: organizationalUnit | |||
| dn: cn=kirkj,ou=crew,dc=enterprise,dc=org | |||
| cn: kirkj | |||
| sn: Kirk | |||
| gn: James Tiberius | |||
| mail: james.kirk@enterprise.org | |||
| objectClass: inetOrgPerson | |||
| dn: cn=spock,ou=crew,dc=enterprise,dc=org | |||
| cn: spock | |||
| sn: Spock | |||
| mail: spock@enterprise.org | |||
| objectClass: inetOrgPerson | |||
| dn: cn=mccoyl,ou=crew,dc=enterprise,dc=org | |||
| cn: mccoyl | |||
| sn: McCoy | |||
| gn: Leonard | |||
| mail: leonard.mccoy@enterprise.org | |||
| objectClass: inetOrgPerson | |||
| dn: cn=scottm,ou=crew,dc=enterprise,dc=org | |||
| cn: scottm | |||
| sn: Scott | |||
| gn: Montgomery | |||
| mail: Montgomery.scott@enterprise.org | |||
| objectClass: inetOrgPerson | |||
| dn: cn=uhuran,ou=crew,dc=enterprise,dc=org | |||
| cn: uhuran | |||
| sn: Uhura | |||
| gn: Nyota | |||
| mail: nyota.uhura@enterprise.org | |||
| objectClass: inetOrgPerson | |||
| dn: cn=suluh,ou=crew,dc=enterprise,dc=org | |||
| cn: suluh | |||
| sn: Sulu | |||
| gn: Hikaru | |||
| mail: hikaru.sulu@enterprise.org | |||
| objectClass: inetOrgPerson | |||
| dn: cn=chekovp,ou=crew,dc=enterprise,dc=org | |||
| cn: chekovp | |||
| sn: Chekov | |||
| gn: pavel | |||
| mail: pavel.chekov@enterprise.org | |||
| objectClass: inetOrgPerson | |||
| @@ -1,89 +0,0 @@ | |||
| // Copyright 2014 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. | |||
| package main | |||
| import ( | |||
| "errors" | |||
| "fmt" | |||
| "log" | |||
| "github.com/gogits/gogs/modules/ldap" | |||
| ) | |||
| var ( | |||
| LdapServer string = "localhost" | |||
| LdapPort uint16 = 389 | |||
| BaseDN string = "dc=enterprise,dc=org" | |||
| BindDN string = "cn=admin,dc=enterprise,dc=org" | |||
| BindPW string = "enterprise" | |||
| Filter string = "(cn=kirkj)" | |||
| ) | |||
| func search(l *ldap.Conn, filter string, attributes []string) (*ldap.Entry, *ldap.Error) { | |||
| search := ldap.NewSearchRequest( | |||
| BaseDN, | |||
| ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, | |||
| filter, | |||
| attributes, | |||
| nil) | |||
| sr, err := l.Search(search) | |||
| if err != nil { | |||
| log.Fatalf("ERROR: %s\n", err) | |||
| return nil, err | |||
| } | |||
| log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries)) | |||
| if len(sr.Entries) == 0 { | |||
| return nil, ldap.NewError(ldap.ErrorDebugging, errors.New(fmt.Sprintf("no entries found for: %s", filter))) | |||
| } | |||
| return sr.Entries[0], nil | |||
| } | |||
| func main() { | |||
| l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", LdapServer, LdapPort)) | |||
| if err != nil { | |||
| log.Fatalf("ERROR: %s\n", err.Error()) | |||
| } | |||
| defer l.Close() | |||
| // l.Debug = true | |||
| l.Bind(BindDN, BindPW) | |||
| log.Printf("The Search for Kirk ... %s\n", Filter) | |||
| entry, err := search(l, Filter, []string{}) | |||
| if err != nil { | |||
| log.Fatal("could not get entry") | |||
| } | |||
| entry.PrettyPrint(0) | |||
| log.Printf("modify the mail address and add a description ... \n") | |||
| modify := ldap.NewModifyRequest(entry.DN) | |||
| modify.Add("description", []string{"Captain of the USS Enterprise"}) | |||
| modify.Replace("mail", []string{"captain@enterprise.org"}) | |||
| if err := l.Modify(modify); err != nil { | |||
| log.Fatalf("ERROR: %s\n", err.Error()) | |||
| } | |||
| entry, err = search(l, Filter, []string{}) | |||
| if err != nil { | |||
| log.Fatal("could not get entry") | |||
| } | |||
| entry.PrettyPrint(0) | |||
| log.Printf("reset the entry ... \n") | |||
| modify = ldap.NewModifyRequest(entry.DN) | |||
| modify.Delete("description", []string{}) | |||
| modify.Replace("mail", []string{"james.kirk@enterprise.org"}) | |||
| if err := l.Modify(modify); err != nil { | |||
| log.Fatalf("ERROR: %s\n", err.Error()) | |||
| } | |||
| entry, err = search(l, Filter, []string{}) | |||
| if err != nil { | |||
| log.Fatal("could not get entry") | |||
| } | |||
| entry.PrettyPrint(0) | |||
| } | |||
| @@ -1,52 +0,0 @@ | |||
| // Copyright 2014 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. | |||
| package main | |||
| import ( | |||
| "fmt" | |||
| "log" | |||
| "github.com/gogits/gogs/modules/ldap" | |||
| ) | |||
| var ( | |||
| ldapServer string = "adserver" | |||
| ldapPort uint16 = 3268 | |||
| baseDN string = "dc=*,dc=*" | |||
| filter string = "(&(objectClass=user)(sAMAccountName=*)(memberOf=CN=*,OU=*,DC=*,DC=*))" | |||
| Attributes []string = []string{"memberof"} | |||
| user string = "*" | |||
| passwd string = "*" | |||
| ) | |||
| func main() { | |||
| l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) | |||
| if err != nil { | |||
| log.Fatalf("ERROR: %s\n", err.Error()) | |||
| } | |||
| defer l.Close() | |||
| // l.Debug = true | |||
| err = l.Bind(user, passwd) | |||
| if err != nil { | |||
| log.Printf("ERROR: Cannot bind: %s\n", err.Error()) | |||
| return | |||
| } | |||
| search := ldap.NewSearchRequest( | |||
| baseDN, | |||
| ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, | |||
| filter, | |||
| Attributes, | |||
| nil) | |||
| sr, err := l.Search(search) | |||
| if err != nil { | |||
| log.Fatalf("ERROR: %s\n", err.Error()) | |||
| return | |||
| } | |||
| log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries)) | |||
| sr.PrettyPrint(0) | |||
| } | |||
| @@ -1,45 +0,0 @@ | |||
| // Copyright 2014 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. | |||
| package main | |||
| import ( | |||
| "fmt" | |||
| "log" | |||
| "github.com/gogits/gogs/modules/ldap" | |||
| ) | |||
| var ( | |||
| LdapServer string = "localhost" | |||
| LdapPort uint16 = 636 | |||
| BaseDN string = "dc=enterprise,dc=org" | |||
| Filter string = "(cn=kirkj)" | |||
| Attributes []string = []string{"mail"} | |||
| ) | |||
| func main() { | |||
| l, err := ldap.DialSSL("tcp", fmt.Sprintf("%s:%d", LdapServer, LdapPort), nil) | |||
| if err != nil { | |||
| log.Fatalf("ERROR: %s\n", err.String()) | |||
| } | |||
| defer l.Close() | |||
| // l.Debug = true | |||
| search := ldap.NewSearchRequest( | |||
| BaseDN, | |||
| ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, | |||
| Filter, | |||
| Attributes, | |||
| nil) | |||
| sr, err := l.Search(search) | |||
| if err != nil { | |||
| log.Fatalf("ERROR: %s\n", err.String()) | |||
| return | |||
| } | |||
| log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries)) | |||
| sr.PrettyPrint(0) | |||
| } | |||
| @@ -1,45 +0,0 @@ | |||
| // Copyright 2014 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. | |||
| package main | |||
| import ( | |||
| "fmt" | |||
| "log" | |||
| "github.com/gogits/gogs/modules/ldap" | |||
| ) | |||
| var ( | |||
| LdapServer string = "localhost" | |||
| LdapPort uint16 = 389 | |||
| BaseDN string = "dc=enterprise,dc=org" | |||
| Filter string = "(cn=kirkj)" | |||
| Attributes []string = []string{"mail"} | |||
| ) | |||
| func main() { | |||
| l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", LdapServer, LdapPort), nil) | |||
| if err != nil { | |||
| log.Fatalf("ERROR: %s\n", err.Error()) | |||
| } | |||
| defer l.Close() | |||
| // l.Debug = true | |||
| search := ldap.NewSearchRequest( | |||
| BaseDN, | |||
| ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, | |||
| Filter, | |||
| Attributes, | |||
| nil) | |||
| sr, err := l.Search(search) | |||
| if err != nil { | |||
| log.Fatalf("ERROR: %s\n", err.Error()) | |||
| return | |||
| } | |||
| log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries)) | |||
| sr.PrettyPrint(0) | |||
| } | |||
| @@ -1,67 +0,0 @@ | |||
| # | |||
| # See slapd.conf(5) for details on configuration options. | |||
| # This file should NOT be world readable. | |||
| # | |||
| include /private/etc/openldap/schema/core.schema | |||
| include /private/etc/openldap/schema/cosine.schema | |||
| include /private/etc/openldap/schema/inetorgperson.schema | |||
| # Define global ACLs to disable default read access. | |||
| # Do not enable referrals until AFTER you have a working directory | |||
| # service AND an understanding of referrals. | |||
| #referral ldap://root.openldap.org | |||
| pidfile /private/var/db/openldap/run/slapd.pid | |||
| argsfile /private/var/db/openldap/run/slapd.args | |||
| # Load dynamic backend modules: | |||
| # modulepath /usr/libexec/openldap | |||
| # moduleload back_bdb.la | |||
| # moduleload back_hdb.la | |||
| # moduleload back_ldap.la | |||
| # Sample security restrictions | |||
| # Require integrity protection (prevent hijacking) | |||
| # Require 112-bit (3DES or better) encryption for updates | |||
| # Require 63-bit encryption for simple bind | |||
| # security ssf=1 update_ssf=112 simple_bind=64 | |||
| # Sample access control policy: | |||
| # Root DSE: allow anyone to read it | |||
| # Subschema (sub)entry DSE: allow anyone to read it | |||
| # Other DSEs: | |||
| # Allow self write access | |||
| # Allow authenticated users read access | |||
| # Allow anonymous users to authenticate | |||
| # Directives needed to implement policy: | |||
| # access to dn.base="" by * read | |||
| # access to dn.base="cn=Subschema" by * read | |||
| # access to * | |||
| # by self write | |||
| # by users read | |||
| # by anonymous auth | |||
| # | |||
| # if no access controls are present, the default policy | |||
| # allows anyone and everyone to read anything but restricts | |||
| # updates to rootdn. (e.g., "access to * by * read") | |||
| # | |||
| # rootdn can always read and write EVERYTHING! | |||
| ####################################################################### | |||
| # BDB database definitions | |||
| ####################################################################### | |||
| database bdb | |||
| suffix "dc=enterprise,dc=org" | |||
| rootdn "cn=admin,dc=enterprise,dc=org" | |||
| # Cleartext passwords, especially for the rootdn, should | |||
| # be avoid. See slappasswd(8) and slapd.conf(5) for details. | |||
| # Use of strong authentication encouraged. | |||
| rootpw {SSHA}laO00HsgszhK1O0Z5qR0/i/US69Osfeu | |||
| # The database directory MUST exist prior to running slapd AND | |||
| # should only be accessible by the slapd and slap tools. | |||
| # Mode 700 recommended. | |||
| directory /private/var/db/openldap/openldap-data | |||
| # Indices to maintain | |||
| index objectClass eq | |||
| @@ -1,55 +0,0 @@ | |||
| // 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. | |||
| package ldap | |||
| import ( | |||
| "errors" | |||
| "github.com/gogits/gogs/modules/asn1-ber" | |||
| ) | |||
| func (l *Conn) Bind(username, password string) error { | |||
| messageID := l.nextMessageID() | |||
| packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") | |||
| packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) | |||
| bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request") | |||
| bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version")) | |||
| bindRequest.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, username, "User Name")) | |||
| bindRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, password, "Password")) | |||
| packet.AppendChild(bindRequest) | |||
| if l.Debug { | |||
| ber.PrintPacket(packet) | |||
| } | |||
| channel, err := l.sendMessage(packet) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| if channel == nil { | |||
| return NewError(ErrorNetwork, errors.New("ldap: could not send message")) | |||
| } | |||
| defer l.finishMessage(messageID) | |||
| packet = <-channel | |||
| if packet == nil { | |||
| return NewError(ErrorNetwork, errors.New("ldap: could not retrieve response")) | |||
| } | |||
| if l.Debug { | |||
| if err := addLDAPDescriptions(packet); err != nil { | |||
| return err | |||
| } | |||
| ber.PrintPacket(packet) | |||
| } | |||
| resultCode, resultDescription := getLDAPResultCode(packet) | |||
| if resultCode != 0 { | |||
| return NewError(resultCode, errors.New(resultDescription)) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,275 +0,0 @@ | |||
| // 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. | |||
| package ldap | |||
| import ( | |||
| "crypto/tls" | |||
| "errors" | |||
| "log" | |||
| "net" | |||
| "sync" | |||
| "github.com/gogits/gogs/modules/asn1-ber" | |||
| ) | |||
| const ( | |||
| MessageQuit = 0 | |||
| MessageRequest = 1 | |||
| MessageResponse = 2 | |||
| MessageFinish = 3 | |||
| ) | |||
| type messagePacket struct { | |||
| Op int | |||
| MessageID uint64 | |||
| Packet *ber.Packet | |||
| Channel chan *ber.Packet | |||
| } | |||
| // Conn represents an LDAP Connection | |||
| type Conn struct { | |||
| conn net.Conn | |||
| isTLS bool | |||
| isClosing bool | |||
| Debug debugging | |||
| chanConfirm chan bool | |||
| chanResults map[uint64]chan *ber.Packet | |||
| chanMessage chan *messagePacket | |||
| chanMessageID chan uint64 | |||
| wgSender sync.WaitGroup | |||
| wgClose sync.WaitGroup | |||
| once sync.Once | |||
| } | |||
| // Dial connects to the given address on the given network using net.Dial | |||
| // and then returns a new Conn for the connection. | |||
| func Dial(network, addr string) (*Conn, error) { | |||
| c, err := net.Dial(network, addr) | |||
| if err != nil { | |||
| return nil, NewError(ErrorNetwork, err) | |||
| } | |||
| conn := NewConn(c) | |||
| conn.start() | |||
| return conn, nil | |||
| } | |||
| // DialTLS connects to the given address on the given network using tls.Dial | |||
| // and then returns a new Conn for the connection. | |||
| func DialTLS(network, addr string, config *tls.Config) (*Conn, error) { | |||
| c, err := tls.Dial(network, addr, config) | |||
| if err != nil { | |||
| return nil, NewError(ErrorNetwork, err) | |||
| } | |||
| conn := NewConn(c) | |||
| conn.isTLS = true | |||
| conn.start() | |||
| return conn, nil | |||
| } | |||
| // NewConn returns a new Conn using conn for network I/O. | |||
| func NewConn(conn net.Conn) *Conn { | |||
| return &Conn{ | |||
| conn: conn, | |||
| chanConfirm: make(chan bool), | |||
| chanMessageID: make(chan uint64), | |||
| chanMessage: make(chan *messagePacket, 10), | |||
| chanResults: map[uint64]chan *ber.Packet{}, | |||
| } | |||
| } | |||
| func (l *Conn) start() { | |||
| go l.reader() | |||
| go l.processMessages() | |||
| l.wgClose.Add(1) | |||
| } | |||
| // Close closes the connection. | |||
| func (l *Conn) Close() { | |||
| l.once.Do(func() { | |||
| l.isClosing = true | |||
| l.wgSender.Wait() | |||
| l.Debug.Printf("Sending quit message and waiting for confirmation") | |||
| l.chanMessage <- &messagePacket{Op: MessageQuit} | |||
| <-l.chanConfirm | |||
| close(l.chanMessage) | |||
| l.Debug.Printf("Closing network connection") | |||
| if err := l.conn.Close(); err != nil { | |||
| log.Print(err) | |||
| } | |||
| l.conn = nil | |||
| l.wgClose.Done() | |||
| }) | |||
| l.wgClose.Wait() | |||
| } | |||
| // Returns the next available messageID | |||
| func (l *Conn) nextMessageID() uint64 { | |||
| if l.chanMessageID != nil { | |||
| if messageID, ok := <-l.chanMessageID; ok { | |||
| return messageID | |||
| } | |||
| } | |||
| return 0 | |||
| } | |||
| // StartTLS sends the command to start a TLS session and then creates a new TLS Client | |||
| func (l *Conn) StartTLS(config *tls.Config) error { | |||
| messageID := l.nextMessageID() | |||
| if l.isTLS { | |||
| return NewError(ErrorNetwork, errors.New("ldap: already encrypted")) | |||
| } | |||
| packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") | |||
| packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) | |||
| request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Start TLS") | |||
| request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, "1.3.6.1.4.1.1466.20037", "TLS Extended Command")) | |||
| packet.AppendChild(request) | |||
| l.Debug.PrintPacket(packet) | |||
| _, err := l.conn.Write(packet.Bytes()) | |||
| if err != nil { | |||
| return NewError(ErrorNetwork, err) | |||
| } | |||
| packet, err = ber.ReadPacket(l.conn) | |||
| if err != nil { | |||
| return NewError(ErrorNetwork, err) | |||
| } | |||
| if l.Debug { | |||
| if err := addLDAPDescriptions(packet); err != nil { | |||
| return err | |||
| } | |||
| ber.PrintPacket(packet) | |||
| } | |||
| if packet.Children[1].Children[0].Value.(uint64) == 0 { | |||
| conn := tls.Client(l.conn, config) | |||
| l.isTLS = true | |||
| l.conn = conn | |||
| } | |||
| return nil | |||
| } | |||
| func (l *Conn) sendMessage(packet *ber.Packet) (chan *ber.Packet, error) { | |||
| if l.isClosing { | |||
| return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed")) | |||
| } | |||
| out := make(chan *ber.Packet) | |||
| message := &messagePacket{ | |||
| Op: MessageRequest, | |||
| MessageID: packet.Children[0].Value.(uint64), | |||
| Packet: packet, | |||
| Channel: out, | |||
| } | |||
| l.sendProcessMessage(message) | |||
| return out, nil | |||
| } | |||
| func (l *Conn) finishMessage(messageID uint64) { | |||
| if l.isClosing { | |||
| return | |||
| } | |||
| message := &messagePacket{ | |||
| Op: MessageFinish, | |||
| MessageID: messageID, | |||
| } | |||
| l.sendProcessMessage(message) | |||
| } | |||
| func (l *Conn) sendProcessMessage(message *messagePacket) bool { | |||
| if l.isClosing { | |||
| return false | |||
| } | |||
| l.wgSender.Add(1) | |||
| l.chanMessage <- message | |||
| l.wgSender.Done() | |||
| return true | |||
| } | |||
| func (l *Conn) processMessages() { | |||
| defer func() { | |||
| for messageID, channel := range l.chanResults { | |||
| l.Debug.Printf("Closing channel for MessageID %d", messageID) | |||
| close(channel) | |||
| delete(l.chanResults, messageID) | |||
| } | |||
| close(l.chanMessageID) | |||
| l.chanConfirm <- true | |||
| close(l.chanConfirm) | |||
| }() | |||
| var messageID uint64 = 1 | |||
| for { | |||
| select { | |||
| case l.chanMessageID <- messageID: | |||
| messageID++ | |||
| case messagePacket, ok := <-l.chanMessage: | |||
| if !ok { | |||
| l.Debug.Printf("Shutting down - message channel is closed") | |||
| return | |||
| } | |||
| switch messagePacket.Op { | |||
| case MessageQuit: | |||
| l.Debug.Printf("Shutting down - quit message received") | |||
| return | |||
| case MessageRequest: | |||
| // Add to message list and write to network | |||
| l.Debug.Printf("Sending message %d", messagePacket.MessageID) | |||
| l.chanResults[messagePacket.MessageID] = messagePacket.Channel | |||
| // go routine | |||
| buf := messagePacket.Packet.Bytes() | |||
| _, err := l.conn.Write(buf) | |||
| if err != nil { | |||
| l.Debug.Printf("Error Sending Message: %s", err.Error()) | |||
| break | |||
| } | |||
| case MessageResponse: | |||
| l.Debug.Printf("Receiving message %d", messagePacket.MessageID) | |||
| if chanResult, ok := l.chanResults[messagePacket.MessageID]; ok { | |||
| chanResult <- messagePacket.Packet | |||
| } else { | |||
| log.Printf("Received unexpected message %d", messagePacket.MessageID) | |||
| ber.PrintPacket(messagePacket.Packet) | |||
| } | |||
| case MessageFinish: | |||
| // Remove from message list | |||
| l.Debug.Printf("Finished message %d", messagePacket.MessageID) | |||
| close(l.chanResults[messagePacket.MessageID]) | |||
| delete(l.chanResults, messagePacket.MessageID) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| func (l *Conn) reader() { | |||
| defer func() { | |||
| l.Close() | |||
| }() | |||
| for { | |||
| packet, err := ber.ReadPacket(l.conn) | |||
| if err != nil { | |||
| l.Debug.Printf("reader: %s", err.Error()) | |||
| return | |||
| } | |||
| addLDAPDescriptions(packet) | |||
| message := &messagePacket{ | |||
| Op: MessageResponse, | |||
| MessageID: packet.Children[0].Value.(uint64), | |||
| Packet: packet, | |||
| } | |||
| if !l.sendProcessMessage(message) { | |||
| return | |||
| } | |||
| } | |||
| } | |||
| @@ -1,157 +0,0 @@ | |||
| // 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. | |||
| package ldap | |||
| import ( | |||
| "fmt" | |||
| "github.com/gogits/gogs/modules/asn1-ber" | |||
| ) | |||
| const ( | |||
| ControlTypePaging = "1.2.840.113556.1.4.319" | |||
| ) | |||
| var ControlTypeMap = map[string]string{ | |||
| ControlTypePaging: "Paging", | |||
| } | |||
| type Control interface { | |||
| GetControlType() string | |||
| Encode() *ber.Packet | |||
| String() string | |||
| } | |||
| type ControlString struct { | |||
| ControlType string | |||
| Criticality bool | |||
| ControlValue string | |||
| } | |||
| func (c *ControlString) GetControlType() string { | |||
| return c.ControlType | |||
| } | |||
| func (c *ControlString) Encode() *ber.Packet { | |||
| packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") | |||
| packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlType, "Control Type ("+ControlTypeMap[c.ControlType]+")")) | |||
| if c.Criticality { | |||
| packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality")) | |||
| } | |||
| packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlValue, "Control Value")) | |||
| return packet | |||
| } | |||
| func (c *ControlString) String() string { | |||
| return fmt.Sprintf("Control Type: %s (%q) Criticality: %t Control Value: %s", ControlTypeMap[c.ControlType], c.ControlType, c.Criticality, c.ControlValue) | |||
| } | |||
| type ControlPaging struct { | |||
| PagingSize uint32 | |||
| Cookie []byte | |||
| } | |||
| func (c *ControlPaging) GetControlType() string { | |||
| return ControlTypePaging | |||
| } | |||
| func (c *ControlPaging) Encode() *ber.Packet { | |||
| packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") | |||
| packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypePaging, "Control Type ("+ControlTypeMap[ControlTypePaging]+")")) | |||
| p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Paging)") | |||
| seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Search Control Value") | |||
| seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(c.PagingSize), "Paging Size")) | |||
| cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie") | |||
| cookie.Value = c.Cookie | |||
| cookie.Data.Write(c.Cookie) | |||
| seq.AppendChild(cookie) | |||
| p2.AppendChild(seq) | |||
| packet.AppendChild(p2) | |||
| return packet | |||
| } | |||
| func (c *ControlPaging) String() string { | |||
| return fmt.Sprintf( | |||
| "Control Type: %s (%q) Criticality: %t PagingSize: %d Cookie: %q", | |||
| ControlTypeMap[ControlTypePaging], | |||
| ControlTypePaging, | |||
| false, | |||
| c.PagingSize, | |||
| c.Cookie) | |||
| } | |||
| func (c *ControlPaging) SetCookie(cookie []byte) { | |||
| c.Cookie = cookie | |||
| } | |||
| func FindControl(controls []Control, controlType string) Control { | |||
| for _, c := range controls { | |||
| if c.GetControlType() == controlType { | |||
| return c | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| func DecodeControl(packet *ber.Packet) Control { | |||
| ControlType := packet.Children[0].Value.(string) | |||
| Criticality := false | |||
| packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" | |||
| value := packet.Children[1] | |||
| if len(packet.Children) == 3 { | |||
| value = packet.Children[2] | |||
| packet.Children[1].Description = "Criticality" | |||
| Criticality = packet.Children[1].Value.(bool) | |||
| } | |||
| value.Description = "Control Value" | |||
| switch ControlType { | |||
| case ControlTypePaging: | |||
| value.Description += " (Paging)" | |||
| c := new(ControlPaging) | |||
| if value.Value != nil { | |||
| valueChildren := ber.DecodePacket(value.Data.Bytes()) | |||
| value.Data.Truncate(0) | |||
| value.Value = nil | |||
| value.AppendChild(valueChildren) | |||
| } | |||
| value = value.Children[0] | |||
| value.Description = "Search Control Value" | |||
| value.Children[0].Description = "Paging Size" | |||
| value.Children[1].Description = "Cookie" | |||
| c.PagingSize = uint32(value.Children[0].Value.(uint64)) | |||
| c.Cookie = value.Children[1].Data.Bytes() | |||
| value.Children[1].Value = c.Cookie | |||
| return c | |||
| } | |||
| c := new(ControlString) | |||
| c.ControlType = ControlType | |||
| c.Criticality = Criticality | |||
| c.ControlValue = value.Value.(string) | |||
| return c | |||
| } | |||
| func NewControlString(controlType string, criticality bool, controlValue string) *ControlString { | |||
| return &ControlString{ | |||
| ControlType: controlType, | |||
| Criticality: criticality, | |||
| ControlValue: controlValue, | |||
| } | |||
| } | |||
| func NewControlPaging(pagingSize uint32) *ControlPaging { | |||
| return &ControlPaging{PagingSize: pagingSize} | |||
| } | |||
| func encodeControls(controls []Control) *ber.Packet { | |||
| packet := ber.Encode(ber.ClassContext, ber.TypeConstructed, 0, nil, "Controls") | |||
| for _, control := range controls { | |||
| packet.AppendChild(control.Encode()) | |||
| } | |||
| return packet | |||
| } | |||
| @@ -1,24 +0,0 @@ | |||
| package ldap | |||
| import ( | |||
| "log" | |||
| "github.com/gogits/gogs/modules/asn1-ber" | |||
| ) | |||
| // debugging type | |||
| // - has a Printf method to write the debug output | |||
| type debugging bool | |||
| // write debug output | |||
| func (debug debugging) Printf(format string, args ...interface{}) { | |||
| if debug { | |||
| log.Printf(format, args...) | |||
| } | |||
| } | |||
| func (debug debugging) PrintPacket(packet *ber.Packet) { | |||
| if debug { | |||
| ber.PrintPacket(packet) | |||
| } | |||
| } | |||
| @@ -1,248 +0,0 @@ | |||
| // 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. | |||
| package ldap | |||
| import ( | |||
| "errors" | |||
| "fmt" | |||
| "github.com/gogits/gogs/modules/asn1-ber" | |||
| ) | |||
| const ( | |||
| FilterAnd = 0 | |||
| FilterOr = 1 | |||
| FilterNot = 2 | |||
| FilterEqualityMatch = 3 | |||
| FilterSubstrings = 4 | |||
| FilterGreaterOrEqual = 5 | |||
| FilterLessOrEqual = 6 | |||
| FilterPresent = 7 | |||
| FilterApproxMatch = 8 | |||
| FilterExtensibleMatch = 9 | |||
| ) | |||
| var FilterMap = map[uint64]string{ | |||
| FilterAnd: "And", | |||
| FilterOr: "Or", | |||
| FilterNot: "Not", | |||
| FilterEqualityMatch: "Equality Match", | |||
| FilterSubstrings: "Substrings", | |||
| FilterGreaterOrEqual: "Greater Or Equal", | |||
| FilterLessOrEqual: "Less Or Equal", | |||
| FilterPresent: "Present", | |||
| FilterApproxMatch: "Approx Match", | |||
| FilterExtensibleMatch: "Extensible Match", | |||
| } | |||
| const ( | |||
| FilterSubstringsInitial = 0 | |||
| FilterSubstringsAny = 1 | |||
| FilterSubstringsFinal = 2 | |||
| ) | |||
| var FilterSubstringsMap = map[uint64]string{ | |||
| FilterSubstringsInitial: "Substrings Initial", | |||
| FilterSubstringsAny: "Substrings Any", | |||
| FilterSubstringsFinal: "Substrings Final", | |||
| } | |||
| func CompileFilter(filter string) (*ber.Packet, error) { | |||
| if len(filter) == 0 || filter[0] != '(' { | |||
| return nil, NewError(ErrorFilterCompile, errors.New("ldap: filter does not start with an '('")) | |||
| } | |||
| packet, pos, err := compileFilter(filter, 1) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if pos != len(filter) { | |||
| return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:]))) | |||
| } | |||
| return packet, nil | |||
| } | |||
| func DecompileFilter(packet *ber.Packet) (ret string, err error) { | |||
| defer func() { | |||
| if r := recover(); r != nil { | |||
| err = NewError(ErrorFilterDecompile, errors.New("ldap: error decompiling filter")) | |||
| } | |||
| }() | |||
| ret = "(" | |||
| err = nil | |||
| childStr := "" | |||
| switch packet.Tag { | |||
| case FilterAnd: | |||
| ret += "&" | |||
| for _, child := range packet.Children { | |||
| childStr, err = DecompileFilter(child) | |||
| if err != nil { | |||
| return | |||
| } | |||
| ret += childStr | |||
| } | |||
| case FilterOr: | |||
| ret += "|" | |||
| for _, child := range packet.Children { | |||
| childStr, err = DecompileFilter(child) | |||
| if err != nil { | |||
| return | |||
| } | |||
| ret += childStr | |||
| } | |||
| case FilterNot: | |||
| ret += "!" | |||
| childStr, err = DecompileFilter(packet.Children[0]) | |||
| if err != nil { | |||
| return | |||
| } | |||
| ret += childStr | |||
| case FilterSubstrings: | |||
| ret += ber.DecodeString(packet.Children[0].Data.Bytes()) | |||
| ret += "=" | |||
| switch packet.Children[1].Children[0].Tag { | |||
| case FilterSubstringsInitial: | |||
| ret += ber.DecodeString(packet.Children[1].Children[0].Data.Bytes()) + "*" | |||
| case FilterSubstringsAny: | |||
| ret += "*" + ber.DecodeString(packet.Children[1].Children[0].Data.Bytes()) + "*" | |||
| case FilterSubstringsFinal: | |||
| ret += "*" + ber.DecodeString(packet.Children[1].Children[0].Data.Bytes()) | |||
| } | |||
| case FilterEqualityMatch: | |||
| ret += ber.DecodeString(packet.Children[0].Data.Bytes()) | |||
| ret += "=" | |||
| ret += ber.DecodeString(packet.Children[1].Data.Bytes()) | |||
| case FilterGreaterOrEqual: | |||
| ret += ber.DecodeString(packet.Children[0].Data.Bytes()) | |||
| ret += ">=" | |||
| ret += ber.DecodeString(packet.Children[1].Data.Bytes()) | |||
| case FilterLessOrEqual: | |||
| ret += ber.DecodeString(packet.Children[0].Data.Bytes()) | |||
| ret += "<=" | |||
| ret += ber.DecodeString(packet.Children[1].Data.Bytes()) | |||
| case FilterPresent: | |||
| ret += ber.DecodeString(packet.Children[0].Data.Bytes()) | |||
| ret += "=*" | |||
| case FilterApproxMatch: | |||
| ret += ber.DecodeString(packet.Children[0].Data.Bytes()) | |||
| ret += "~=" | |||
| ret += ber.DecodeString(packet.Children[1].Data.Bytes()) | |||
| } | |||
| ret += ")" | |||
| return | |||
| } | |||
| func compileFilterSet(filter string, pos int, parent *ber.Packet) (int, error) { | |||
| for pos < len(filter) && filter[pos] == '(' { | |||
| child, newPos, err := compileFilter(filter, pos+1) | |||
| if err != nil { | |||
| return pos, err | |||
| } | |||
| pos = newPos | |||
| parent.AppendChild(child) | |||
| } | |||
| if pos == len(filter) { | |||
| return pos, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter")) | |||
| } | |||
| return pos + 1, nil | |||
| } | |||
| func compileFilter(filter string, pos int) (*ber.Packet, int, error) { | |||
| var packet *ber.Packet | |||
| var err error | |||
| defer func() { | |||
| if r := recover(); r != nil { | |||
| err = NewError(ErrorFilterCompile, errors.New("ldap: error compiling filter")) | |||
| } | |||
| }() | |||
| newPos := pos | |||
| switch filter[pos] { | |||
| case '(': | |||
| packet, newPos, err = compileFilter(filter, pos+1) | |||
| newPos++ | |||
| return packet, newPos, err | |||
| case '&': | |||
| packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterAnd, nil, FilterMap[FilterAnd]) | |||
| newPos, err = compileFilterSet(filter, pos+1, packet) | |||
| return packet, newPos, err | |||
| case '|': | |||
| packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterOr, nil, FilterMap[FilterOr]) | |||
| newPos, err = compileFilterSet(filter, pos+1, packet) | |||
| return packet, newPos, err | |||
| case '!': | |||
| packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterNot, nil, FilterMap[FilterNot]) | |||
| var child *ber.Packet | |||
| child, newPos, err = compileFilter(filter, pos+1) | |||
| packet.AppendChild(child) | |||
| return packet, newPos, err | |||
| default: | |||
| attribute := "" | |||
| condition := "" | |||
| for newPos < len(filter) && filter[newPos] != ')' { | |||
| switch { | |||
| case packet != nil: | |||
| condition += fmt.Sprintf("%c", filter[newPos]) | |||
| case filter[newPos] == '=': | |||
| packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterEqualityMatch, nil, FilterMap[FilterEqualityMatch]) | |||
| case filter[newPos] == '>' && filter[newPos+1] == '=': | |||
| packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterGreaterOrEqual, nil, FilterMap[FilterGreaterOrEqual]) | |||
| newPos++ | |||
| case filter[newPos] == '<' && filter[newPos+1] == '=': | |||
| packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterLessOrEqual, nil, FilterMap[FilterLessOrEqual]) | |||
| newPos++ | |||
| case filter[newPos] == '~' && filter[newPos+1] == '=': | |||
| packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterApproxMatch, nil, FilterMap[FilterLessOrEqual]) | |||
| newPos++ | |||
| case packet == nil: | |||
| attribute += fmt.Sprintf("%c", filter[newPos]) | |||
| } | |||
| newPos++ | |||
| } | |||
| if newPos == len(filter) { | |||
| err = NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter")) | |||
| return packet, newPos, err | |||
| } | |||
| if packet == nil { | |||
| err = NewError(ErrorFilterCompile, errors.New("ldap: error parsing filter")) | |||
| return packet, newPos, err | |||
| } | |||
| packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute")) | |||
| switch { | |||
| case packet.Tag == FilterEqualityMatch && condition == "*": | |||
| packet.Tag = FilterPresent | |||
| packet.Description = FilterMap[uint64(packet.Tag)] | |||
| case packet.Tag == FilterEqualityMatch && condition[0] == '*' && condition[len(condition)-1] == '*': | |||
| // Any | |||
| packet.Tag = FilterSubstrings | |||
| packet.Description = FilterMap[uint64(packet.Tag)] | |||
| seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings") | |||
| seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterSubstringsAny, condition[1:len(condition)-1], "Any Substring")) | |||
| packet.AppendChild(seq) | |||
| case packet.Tag == FilterEqualityMatch && condition[0] == '*': | |||
| // Final | |||
| packet.Tag = FilterSubstrings | |||
| packet.Description = FilterMap[uint64(packet.Tag)] | |||
| seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings") | |||
| seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterSubstringsFinal, condition[1:], "Final Substring")) | |||
| packet.AppendChild(seq) | |||
| case packet.Tag == FilterEqualityMatch && condition[len(condition)-1] == '*': | |||
| // Initial | |||
| packet.Tag = FilterSubstrings | |||
| packet.Description = FilterMap[uint64(packet.Tag)] | |||
| seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings") | |||
| seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterSubstringsInitial, condition[:len(condition)-1], "Initial Substring")) | |||
| packet.AppendChild(seq) | |||
| default: | |||
| packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, condition, "Condition")) | |||
| } | |||
| newPos++ | |||
| return packet, newPos, err | |||
| } | |||
| } | |||
| @@ -1,78 +0,0 @@ | |||
| package ldap | |||
| import ( | |||
| "testing" | |||
| "github.com/gogits/gogs/modules/asn1-ber" | |||
| ) | |||
| type compileTest struct { | |||
| filterStr string | |||
| filterType int | |||
| } | |||
| var testFilters = []compileTest{ | |||
| compileTest{filterStr: "(&(sn=Miller)(givenName=Bob))", filterType: FilterAnd}, | |||
| compileTest{filterStr: "(|(sn=Miller)(givenName=Bob))", filterType: FilterOr}, | |||
| compileTest{filterStr: "(!(sn=Miller))", filterType: FilterNot}, | |||
| compileTest{filterStr: "(sn=Miller)", filterType: FilterEqualityMatch}, | |||
| compileTest{filterStr: "(sn=Mill*)", filterType: FilterSubstrings}, | |||
| compileTest{filterStr: "(sn=*Mill)", filterType: FilterSubstrings}, | |||
| compileTest{filterStr: "(sn=*Mill*)", filterType: FilterSubstrings}, | |||
| compileTest{filterStr: "(sn>=Miller)", filterType: FilterGreaterOrEqual}, | |||
| compileTest{filterStr: "(sn<=Miller)", filterType: FilterLessOrEqual}, | |||
| compileTest{filterStr: "(sn=*)", filterType: FilterPresent}, | |||
| compileTest{filterStr: "(sn~=Miller)", filterType: FilterApproxMatch}, | |||
| // compileTest{ filterStr: "()", filterType: FilterExtensibleMatch }, | |||
| } | |||
| func TestFilter(t *testing.T) { | |||
| // Test Compiler and Decompiler | |||
| for _, i := range testFilters { | |||
| filter, err := CompileFilter(i.filterStr) | |||
| if err != nil { | |||
| t.Errorf("Problem compiling %s - %s", i.filterStr, err.Error()) | |||
| } else if filter.Tag != uint8(i.filterType) { | |||
| t.Errorf("%q Expected %q got %q", i.filterStr, FilterMap[uint64(i.filterType)], FilterMap[uint64(filter.Tag)]) | |||
| } else { | |||
| o, err := DecompileFilter(filter) | |||
| if err != nil { | |||
| t.Errorf("Problem compiling %s - %s", i.filterStr, err.Error()) | |||
| } else if i.filterStr != o { | |||
| t.Errorf("%q expected, got %q", i.filterStr, o) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| func BenchmarkFilterCompile(b *testing.B) { | |||
| b.StopTimer() | |||
| filters := make([]string, len(testFilters)) | |||
| // Test Compiler and Decompiler | |||
| for idx, i := range testFilters { | |||
| filters[idx] = i.filterStr | |||
| } | |||
| maxIdx := len(filters) | |||
| b.StartTimer() | |||
| for i := 0; i < b.N; i++ { | |||
| CompileFilter(filters[i%maxIdx]) | |||
| } | |||
| } | |||
| func BenchmarkFilterDecompile(b *testing.B) { | |||
| b.StopTimer() | |||
| filters := make([]*ber.Packet, len(testFilters)) | |||
| // Test Compiler and Decompiler | |||
| for idx, i := range testFilters { | |||
| filters[idx], _ = CompileFilter(i.filterStr) | |||
| } | |||
| maxIdx := len(filters) | |||
| b.StartTimer() | |||
| for i := 0; i < b.N; i++ { | |||
| DecompileFilter(filters[i%maxIdx]) | |||
| } | |||
| } | |||
| @@ -1,302 +0,0 @@ | |||
| // 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. | |||
| package ldap | |||
| import ( | |||
| "errors" | |||
| "fmt" | |||
| "io/ioutil" | |||
| "github.com/gogits/gogs/modules/asn1-ber" | |||
| ) | |||
| // LDAP Application Codes | |||
| const ( | |||
| ApplicationBindRequest = 0 | |||
| ApplicationBindResponse = 1 | |||
| ApplicationUnbindRequest = 2 | |||
| ApplicationSearchRequest = 3 | |||
| ApplicationSearchResultEntry = 4 | |||
| ApplicationSearchResultDone = 5 | |||
| ApplicationModifyRequest = 6 | |||
| ApplicationModifyResponse = 7 | |||
| ApplicationAddRequest = 8 | |||
| ApplicationAddResponse = 9 | |||
| ApplicationDelRequest = 10 | |||
| ApplicationDelResponse = 11 | |||
| ApplicationModifyDNRequest = 12 | |||
| ApplicationModifyDNResponse = 13 | |||
| ApplicationCompareRequest = 14 | |||
| ApplicationCompareResponse = 15 | |||
| ApplicationAbandonRequest = 16 | |||
| ApplicationSearchResultReference = 19 | |||
| ApplicationExtendedRequest = 23 | |||
| ApplicationExtendedResponse = 24 | |||
| ) | |||
| var ApplicationMap = map[uint8]string{ | |||
| ApplicationBindRequest: "Bind Request", | |||
| ApplicationBindResponse: "Bind Response", | |||
| ApplicationUnbindRequest: "Unbind Request", | |||
| ApplicationSearchRequest: "Search Request", | |||
| ApplicationSearchResultEntry: "Search Result Entry", | |||
| ApplicationSearchResultDone: "Search Result Done", | |||
| ApplicationModifyRequest: "Modify Request", | |||
| ApplicationModifyResponse: "Modify Response", | |||
| ApplicationAddRequest: "Add Request", | |||
| ApplicationAddResponse: "Add Response", | |||
| ApplicationDelRequest: "Del Request", | |||
| ApplicationDelResponse: "Del Response", | |||
| ApplicationModifyDNRequest: "Modify DN Request", | |||
| ApplicationModifyDNResponse: "Modify DN Response", | |||
| ApplicationCompareRequest: "Compare Request", | |||
| ApplicationCompareResponse: "Compare Response", | |||
| ApplicationAbandonRequest: "Abandon Request", | |||
| ApplicationSearchResultReference: "Search Result Reference", | |||
| ApplicationExtendedRequest: "Extended Request", | |||
| ApplicationExtendedResponse: "Extended Response", | |||
| } | |||
| // LDAP Result Codes | |||
| const ( | |||
| LDAPResultSuccess = 0 | |||
| LDAPResultOperationsError = 1 | |||
| LDAPResultProtocolError = 2 | |||
| LDAPResultTimeLimitExceeded = 3 | |||
| LDAPResultSizeLimitExceeded = 4 | |||
| LDAPResultCompareFalse = 5 | |||
| LDAPResultCompareTrue = 6 | |||
| LDAPResultAuthMethodNotSupported = 7 | |||
| LDAPResultStrongAuthRequired = 8 | |||
| LDAPResultReferral = 10 | |||
| LDAPResultAdminLimitExceeded = 11 | |||
| LDAPResultUnavailableCriticalExtension = 12 | |||
| LDAPResultConfidentialityRequired = 13 | |||
| LDAPResultSaslBindInProgress = 14 | |||
| LDAPResultNoSuchAttribute = 16 | |||
| LDAPResultUndefinedAttributeType = 17 | |||
| LDAPResultInappropriateMatching = 18 | |||
| LDAPResultConstraintViolation = 19 | |||
| LDAPResultAttributeOrValueExists = 20 | |||
| LDAPResultInvalidAttributeSyntax = 21 | |||
| LDAPResultNoSuchObject = 32 | |||
| LDAPResultAliasProblem = 33 | |||
| LDAPResultInvalidDNSyntax = 34 | |||
| LDAPResultAliasDereferencingProblem = 36 | |||
| LDAPResultInappropriateAuthentication = 48 | |||
| LDAPResultInvalidCredentials = 49 | |||
| LDAPResultInsufficientAccessRights = 50 | |||
| LDAPResultBusy = 51 | |||
| LDAPResultUnavailable = 52 | |||
| LDAPResultUnwillingToPerform = 53 | |||
| LDAPResultLoopDetect = 54 | |||
| LDAPResultNamingViolation = 64 | |||
| LDAPResultObjectClassViolation = 65 | |||
| LDAPResultNotAllowedOnNonLeaf = 66 | |||
| LDAPResultNotAllowedOnRDN = 67 | |||
| LDAPResultEntryAlreadyExists = 68 | |||
| LDAPResultObjectClassModsProhibited = 69 | |||
| LDAPResultAffectsMultipleDSAs = 71 | |||
| LDAPResultOther = 80 | |||
| ErrorNetwork = 200 | |||
| ErrorFilterCompile = 201 | |||
| ErrorFilterDecompile = 202 | |||
| ErrorDebugging = 203 | |||
| ) | |||
| var LDAPResultCodeMap = map[uint8]string{ | |||
| LDAPResultSuccess: "Success", | |||
| LDAPResultOperationsError: "Operations Error", | |||
| LDAPResultProtocolError: "Protocol Error", | |||
| LDAPResultTimeLimitExceeded: "Time Limit Exceeded", | |||
| LDAPResultSizeLimitExceeded: "Size Limit Exceeded", | |||
| LDAPResultCompareFalse: "Compare False", | |||
| LDAPResultCompareTrue: "Compare True", | |||
| LDAPResultAuthMethodNotSupported: "Auth Method Not Supported", | |||
| LDAPResultStrongAuthRequired: "Strong Auth Required", | |||
| LDAPResultReferral: "Referral", | |||
| LDAPResultAdminLimitExceeded: "Admin Limit Exceeded", | |||
| LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension", | |||
| LDAPResultConfidentialityRequired: "Confidentiality Required", | |||
| LDAPResultSaslBindInProgress: "Sasl Bind In Progress", | |||
| LDAPResultNoSuchAttribute: "No Such Attribute", | |||
| LDAPResultUndefinedAttributeType: "Undefined Attribute Type", | |||
| LDAPResultInappropriateMatching: "Inappropriate Matching", | |||
| LDAPResultConstraintViolation: "Constraint Violation", | |||
| LDAPResultAttributeOrValueExists: "Attribute Or Value Exists", | |||
| LDAPResultInvalidAttributeSyntax: "Invalid Attribute Syntax", | |||
| LDAPResultNoSuchObject: "No Such Object", | |||
| LDAPResultAliasProblem: "Alias Problem", | |||
| LDAPResultInvalidDNSyntax: "Invalid DN Syntax", | |||
| LDAPResultAliasDereferencingProblem: "Alias Dereferencing Problem", | |||
| LDAPResultInappropriateAuthentication: "Inappropriate Authentication", | |||
| LDAPResultInvalidCredentials: "Invalid Credentials", | |||
| LDAPResultInsufficientAccessRights: "Insufficient Access Rights", | |||
| LDAPResultBusy: "Busy", | |||
| LDAPResultUnavailable: "Unavailable", | |||
| LDAPResultUnwillingToPerform: "Unwilling To Perform", | |||
| LDAPResultLoopDetect: "Loop Detect", | |||
| LDAPResultNamingViolation: "Naming Violation", | |||
| LDAPResultObjectClassViolation: "Object Class Violation", | |||
| LDAPResultNotAllowedOnNonLeaf: "Not Allowed On Non Leaf", | |||
| LDAPResultNotAllowedOnRDN: "Not Allowed On RDN", | |||
| LDAPResultEntryAlreadyExists: "Entry Already Exists", | |||
| LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited", | |||
| LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs", | |||
| LDAPResultOther: "Other", | |||
| } | |||
| // Adds descriptions to an LDAP Response packet for debugging | |||
| func addLDAPDescriptions(packet *ber.Packet) (err error) { | |||
| defer func() { | |||
| if r := recover(); r != nil { | |||
| err = NewError(ErrorDebugging, errors.New("ldap: cannot process packet to add descriptions")) | |||
| } | |||
| }() | |||
| packet.Description = "LDAP Response" | |||
| packet.Children[0].Description = "Message ID" | |||
| application := packet.Children[1].Tag | |||
| packet.Children[1].Description = ApplicationMap[application] | |||
| switch application { | |||
| case ApplicationBindRequest: | |||
| addRequestDescriptions(packet) | |||
| case ApplicationBindResponse: | |||
| addDefaultLDAPResponseDescriptions(packet) | |||
| case ApplicationUnbindRequest: | |||
| addRequestDescriptions(packet) | |||
| case ApplicationSearchRequest: | |||
| addRequestDescriptions(packet) | |||
| case ApplicationSearchResultEntry: | |||
| packet.Children[1].Children[0].Description = "Object Name" | |||
| packet.Children[1].Children[1].Description = "Attributes" | |||
| for _, child := range packet.Children[1].Children[1].Children { | |||
| child.Description = "Attribute" | |||
| child.Children[0].Description = "Attribute Name" | |||
| child.Children[1].Description = "Attribute Values" | |||
| for _, grandchild := range child.Children[1].Children { | |||
| grandchild.Description = "Attribute Value" | |||
| } | |||
| } | |||
| if len(packet.Children) == 3 { | |||
| addControlDescriptions(packet.Children[2]) | |||
| } | |||
| case ApplicationSearchResultDone: | |||
| addDefaultLDAPResponseDescriptions(packet) | |||
| case ApplicationModifyRequest: | |||
| addRequestDescriptions(packet) | |||
| case ApplicationModifyResponse: | |||
| case ApplicationAddRequest: | |||
| addRequestDescriptions(packet) | |||
| case ApplicationAddResponse: | |||
| case ApplicationDelRequest: | |||
| addRequestDescriptions(packet) | |||
| case ApplicationDelResponse: | |||
| case ApplicationModifyDNRequest: | |||
| addRequestDescriptions(packet) | |||
| case ApplicationModifyDNResponse: | |||
| case ApplicationCompareRequest: | |||
| addRequestDescriptions(packet) | |||
| case ApplicationCompareResponse: | |||
| case ApplicationAbandonRequest: | |||
| addRequestDescriptions(packet) | |||
| case ApplicationSearchResultReference: | |||
| case ApplicationExtendedRequest: | |||
| addRequestDescriptions(packet) | |||
| case ApplicationExtendedResponse: | |||
| } | |||
| return nil | |||
| } | |||
| func addControlDescriptions(packet *ber.Packet) { | |||
| packet.Description = "Controls" | |||
| for _, child := range packet.Children { | |||
| child.Description = "Control" | |||
| child.Children[0].Description = "Control Type (" + ControlTypeMap[child.Children[0].Value.(string)] + ")" | |||
| value := child.Children[1] | |||
| if len(child.Children) == 3 { | |||
| child.Children[1].Description = "Criticality" | |||
| value = child.Children[2] | |||
| } | |||
| value.Description = "Control Value" | |||
| switch child.Children[0].Value.(string) { | |||
| case ControlTypePaging: | |||
| value.Description += " (Paging)" | |||
| if value.Value != nil { | |||
| valueChildren := ber.DecodePacket(value.Data.Bytes()) | |||
| value.Data.Truncate(0) | |||
| value.Value = nil | |||
| valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes() | |||
| value.AppendChild(valueChildren) | |||
| } | |||
| value.Children[0].Description = "Real Search Control Value" | |||
| value.Children[0].Children[0].Description = "Paging Size" | |||
| value.Children[0].Children[1].Description = "Cookie" | |||
| } | |||
| } | |||
| } | |||
| func addRequestDescriptions(packet *ber.Packet) { | |||
| packet.Description = "LDAP Request" | |||
| packet.Children[0].Description = "Message ID" | |||
| packet.Children[1].Description = ApplicationMap[packet.Children[1].Tag] | |||
| if len(packet.Children) == 3 { | |||
| addControlDescriptions(packet.Children[2]) | |||
| } | |||
| } | |||
| func addDefaultLDAPResponseDescriptions(packet *ber.Packet) { | |||
| resultCode := packet.Children[1].Children[0].Value.(uint64) | |||
| packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[uint8(resultCode)] + ")" | |||
| packet.Children[1].Children[1].Description = "Matched DN" | |||
| packet.Children[1].Children[2].Description = "Error Message" | |||
| if len(packet.Children[1].Children) > 3 { | |||
| packet.Children[1].Children[3].Description = "Referral" | |||
| } | |||
| if len(packet.Children) == 3 { | |||
| addControlDescriptions(packet.Children[2]) | |||
| } | |||
| } | |||
| func DebugBinaryFile(fileName string) error { | |||
| file, err := ioutil.ReadFile(fileName) | |||
| if err != nil { | |||
| return NewError(ErrorDebugging, err) | |||
| } | |||
| ber.PrintBytes(file, "") | |||
| packet := ber.DecodePacket(file) | |||
| addLDAPDescriptions(packet) | |||
| ber.PrintPacket(packet) | |||
| return nil | |||
| } | |||
| type Error struct { | |||
| Err error | |||
| ResultCode uint8 | |||
| } | |||
| func (e *Error) Error() string { | |||
| return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error()) | |||
| } | |||
| func NewError(resultCode uint8, err error) error { | |||
| return &Error{ResultCode: resultCode, Err: err} | |||
| } | |||
| func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) { | |||
| if len(packet.Children) >= 2 { | |||
| response := packet.Children[1] | |||
| if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) == 3 { | |||
| return uint8(response.Children[0].Value.(uint64)), response.Children[2].Value.(string) | |||
| } | |||
| } | |||
| return ErrorNetwork, "Invalid packet format" | |||
| } | |||
| @@ -1,123 +0,0 @@ | |||
| package ldap | |||
| import ( | |||
| "fmt" | |||
| "testing" | |||
| ) | |||
| var ldapServer = "ldap.itd.umich.edu" | |||
| var ldapPort = uint16(389) | |||
| var baseDN = "dc=umich,dc=edu" | |||
| var filter = []string{ | |||
| "(cn=cis-fac)", | |||
| "(&(objectclass=rfc822mailgroup)(cn=*Computer*))", | |||
| "(&(objectclass=rfc822mailgroup)(cn=*Mathematics*))"} | |||
| var attributes = []string{ | |||
| "cn", | |||
| "description"} | |||
| func TestConnect(t *testing.T) { | |||
| fmt.Printf("TestConnect: starting...\n") | |||
| l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) | |||
| if err != nil { | |||
| t.Errorf(err.Error()) | |||
| return | |||
| } | |||
| defer l.Close() | |||
| fmt.Printf("TestConnect: finished...\n") | |||
| } | |||
| func TestSearch(t *testing.T) { | |||
| fmt.Printf("TestSearch: starting...\n") | |||
| l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) | |||
| if err != nil { | |||
| t.Errorf(err.Error()) | |||
| return | |||
| } | |||
| defer l.Close() | |||
| searchRequest := NewSearchRequest( | |||
| baseDN, | |||
| ScopeWholeSubtree, DerefAlways, 0, 0, false, | |||
| filter[0], | |||
| attributes, | |||
| nil) | |||
| sr, err := l.Search(searchRequest) | |||
| if err != nil { | |||
| t.Errorf(err.Error()) | |||
| return | |||
| } | |||
| fmt.Printf("TestSearch: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries)) | |||
| } | |||
| func TestSearchWithPaging(t *testing.T) { | |||
| fmt.Printf("TestSearchWithPaging: starting...\n") | |||
| l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) | |||
| if err != nil { | |||
| t.Errorf(err.Error()) | |||
| return | |||
| } | |||
| defer l.Close() | |||
| err = l.Bind("", "") | |||
| if err != nil { | |||
| t.Errorf(err.Error()) | |||
| return | |||
| } | |||
| searchRequest := NewSearchRequest( | |||
| baseDN, | |||
| ScopeWholeSubtree, DerefAlways, 0, 0, false, | |||
| filter[1], | |||
| attributes, | |||
| nil) | |||
| sr, err := l.SearchWithPaging(searchRequest, 5) | |||
| if err != nil { | |||
| t.Errorf(err.Error()) | |||
| return | |||
| } | |||
| fmt.Printf("TestSearchWithPaging: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries)) | |||
| } | |||
| func testMultiGoroutineSearch(t *testing.T, l *Conn, results chan *SearchResult, i int) { | |||
| searchRequest := NewSearchRequest( | |||
| baseDN, | |||
| ScopeWholeSubtree, DerefAlways, 0, 0, false, | |||
| filter[i], | |||
| attributes, | |||
| nil) | |||
| sr, err := l.Search(searchRequest) | |||
| if err != nil { | |||
| t.Errorf(err.Error()) | |||
| results <- nil | |||
| return | |||
| } | |||
| results <- sr | |||
| } | |||
| func TestMultiGoroutineSearch(t *testing.T) { | |||
| fmt.Printf("TestMultiGoroutineSearch: starting...\n") | |||
| l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) | |||
| if err != nil { | |||
| t.Errorf(err.Error()) | |||
| return | |||
| } | |||
| defer l.Close() | |||
| results := make([]chan *SearchResult, len(filter)) | |||
| for i := range filter { | |||
| results[i] = make(chan *SearchResult) | |||
| go testMultiGoroutineSearch(t, l, results[i], i) | |||
| } | |||
| for i := range filter { | |||
| sr := <-results[i] | |||
| if sr == nil { | |||
| t.Errorf("Did not receive results from goroutine for %q", filter[i]) | |||
| } else { | |||
| fmt.Printf("TestMultiGoroutineSearch(%d): %s -> num of entries = %d\n", i, filter[i], len(sr.Entries)) | |||
| } | |||
| } | |||
| } | |||
| @@ -1,156 +0,0 @@ | |||
| // Copyright 2014 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 Modify functionality | |||
| // | |||
| // https://tools.ietf.org/html/rfc4511 | |||
| // | |||
| // ModifyRequest ::= [APPLICATION 6] SEQUENCE { | |||
| // object LDAPDN, | |||
| // changes SEQUENCE OF change SEQUENCE { | |||
| // operation ENUMERATED { | |||
| // add (0), | |||
| // delete (1), | |||
| // replace (2), | |||
| // ... }, | |||
| // modification PartialAttribute } } | |||
| // | |||
| // PartialAttribute ::= SEQUENCE { | |||
| // type AttributeDescription, | |||
| // vals SET OF value AttributeValue } | |||
| // | |||
| // AttributeDescription ::= LDAPString | |||
| // -- Constrained to <attributedescription> | |||
| // -- [RFC4512] | |||
| // | |||
| // AttributeValue ::= OCTET STRING | |||
| // | |||
| package ldap | |||
| import ( | |||
| "errors" | |||
| "log" | |||
| "github.com/gogits/gogs/modules/asn1-ber" | |||
| ) | |||
| const ( | |||
| AddAttribute = 0 | |||
| DeleteAttribute = 1 | |||
| ReplaceAttribute = 2 | |||
| ) | |||
| type PartialAttribute struct { | |||
| attrType string | |||
| attrVals []string | |||
| } | |||
| func (p *PartialAttribute) encode() *ber.Packet { | |||
| seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PartialAttribute") | |||
| seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, p.attrType, "Type")) | |||
| set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue") | |||
| for _, value := range p.attrVals { | |||
| set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals")) | |||
| } | |||
| seq.AppendChild(set) | |||
| return seq | |||
| } | |||
| type ModifyRequest struct { | |||
| dn string | |||
| addAttributes []PartialAttribute | |||
| deleteAttributes []PartialAttribute | |||
| replaceAttributes []PartialAttribute | |||
| } | |||
| func (m *ModifyRequest) Add(attrType string, attrVals []string) { | |||
| m.addAttributes = append(m.addAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals}) | |||
| } | |||
| func (m *ModifyRequest) Delete(attrType string, attrVals []string) { | |||
| m.deleteAttributes = append(m.deleteAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals}) | |||
| } | |||
| func (m *ModifyRequest) Replace(attrType string, attrVals []string) { | |||
| m.replaceAttributes = append(m.replaceAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals}) | |||
| } | |||
| func (m ModifyRequest) encode() *ber.Packet { | |||
| request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request") | |||
| request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.dn, "DN")) | |||
| changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes") | |||
| for _, attribute := range m.addAttributes { | |||
| change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change") | |||
| change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(AddAttribute), "Operation")) | |||
| change.AppendChild(attribute.encode()) | |||
| changes.AppendChild(change) | |||
| } | |||
| for _, attribute := range m.deleteAttributes { | |||
| change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change") | |||
| change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(DeleteAttribute), "Operation")) | |||
| change.AppendChild(attribute.encode()) | |||
| changes.AppendChild(change) | |||
| } | |||
| for _, attribute := range m.replaceAttributes { | |||
| change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change") | |||
| change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(ReplaceAttribute), "Operation")) | |||
| change.AppendChild(attribute.encode()) | |||
| changes.AppendChild(change) | |||
| } | |||
| request.AppendChild(changes) | |||
| return request | |||
| } | |||
| func NewModifyRequest( | |||
| dn string, | |||
| ) *ModifyRequest { | |||
| return &ModifyRequest{ | |||
| dn: dn, | |||
| } | |||
| } | |||
| func (l *Conn) Modify(modifyRequest *ModifyRequest) error { | |||
| messageID := l.nextMessageID() | |||
| packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") | |||
| packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) | |||
| packet.AppendChild(modifyRequest.encode()) | |||
| l.Debug.PrintPacket(packet) | |||
| channel, err := l.sendMessage(packet) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| if channel == nil { | |||
| return NewError(ErrorNetwork, errors.New("ldap: could not send message")) | |||
| } | |||
| defer l.finishMessage(messageID) | |||
| l.Debug.Printf("%d: waiting for response", messageID) | |||
| packet = <-channel | |||
| l.Debug.Printf("%d: got response %p", messageID, packet) | |||
| if packet == nil { | |||
| return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) | |||
| } | |||
| if l.Debug { | |||
| if err := addLDAPDescriptions(packet); err != nil { | |||
| return err | |||
| } | |||
| ber.PrintPacket(packet) | |||
| } | |||
| if packet.Children[1].Tag == ApplicationModifyResponse { | |||
| resultCode, resultDescription := getLDAPResultCode(packet) | |||
| if resultCode != 0 { | |||
| return NewError(resultCode, errors.New(resultDescription)) | |||
| } | |||
| } else { | |||
| log.Printf("Unexpected Response: %d", packet.Children[1].Tag) | |||
| } | |||
| l.Debug.Printf("%d: returning", messageID) | |||
| return nil | |||
| } | |||
| @@ -1,350 +0,0 @@ | |||
| // 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 | |||
| // | |||
| // https://tools.ietf.org/html/rfc4511 | |||
| // | |||
| // SearchRequest ::= [APPLICATION 3] SEQUENCE { | |||
| // baseObject LDAPDN, | |||
| // scope ENUMERATED { | |||
| // baseObject (0), | |||
| // singleLevel (1), | |||
| // wholeSubtree (2), | |||
| // ... }, | |||
| // derefAliases ENUMERATED { | |||
| // neverDerefAliases (0), | |||
| // derefInSearching (1), | |||
| // derefFindingBaseObj (2), | |||
| // derefAlways (3) }, | |||
| // sizeLimit INTEGER (0 .. maxInt), | |||
| // timeLimit INTEGER (0 .. maxInt), | |||
| // typesOnly BOOLEAN, | |||
| // filter Filter, | |||
| // attributes AttributeSelection } | |||
| // | |||
| // AttributeSelection ::= SEQUENCE OF selector LDAPString | |||
| // -- The LDAPString is constrained to | |||
| // -- <attributeSelector> in Section 4.5.1.8 | |||
| // | |||
| // Filter ::= CHOICE { | |||
| // and [0] SET SIZE (1..MAX) OF filter Filter, | |||
| // or [1] SET SIZE (1..MAX) OF filter Filter, | |||
| // not [2] Filter, | |||
| // equalityMatch [3] AttributeValueAssertion, | |||
| // substrings [4] SubstringFilter, | |||
| // greaterOrEqual [5] AttributeValueAssertion, | |||
| // lessOrEqual [6] AttributeValueAssertion, | |||
| // present [7] AttributeDescription, | |||
| // approxMatch [8] AttributeValueAssertion, | |||
| // extensibleMatch [9] MatchingRuleAssertion, | |||
| // ... } | |||
| // | |||
| // SubstringFilter ::= SEQUENCE { | |||
| // type AttributeDescription, | |||
| // substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE { | |||
| // initial [0] AssertionValue, -- can occur at most once | |||
| // any [1] AssertionValue, | |||
| // final [2] AssertionValue } -- can occur at most once | |||
| // } | |||
| // | |||
| // MatchingRuleAssertion ::= SEQUENCE { | |||
| // matchingRule [1] MatchingRuleId OPTIONAL, | |||
| // type [2] AttributeDescription OPTIONAL, | |||
| // matchValue [3] AssertionValue, | |||
| // dnAttributes [4] BOOLEAN DEFAULT FALSE } | |||
| // | |||
| // | |||
| package ldap | |||
| import ( | |||
| "errors" | |||
| "fmt" | |||
| "strings" | |||
| "github.com/gogits/gogs/modules/asn1-ber" | |||
| ) | |||
| 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 | |||
| } | |||
| 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] | |||
| } | |||
| func (e *Entry) Print() { | |||
| fmt.Printf("DN: %s\n", e.DN) | |||
| for _, attr := range e.Attributes { | |||
| attr.Print() | |||
| } | |||
| } | |||
| func (e *Entry) PrettyPrint(indent int) { | |||
| fmt.Printf("%sDN: %s\n", strings.Repeat(" ", indent), e.DN) | |||
| for _, attr := range e.Attributes { | |||
| attr.PrettyPrint(indent + 2) | |||
| } | |||
| } | |||
| type EntryAttribute struct { | |||
| Name string | |||
| Values []string | |||
| } | |||
| func (e *EntryAttribute) Print() { | |||
| fmt.Printf("%s: %s\n", e.Name, e.Values) | |||
| } | |||
| func (e *EntryAttribute) PrettyPrint(indent int) { | |||
| fmt.Printf("%s%s: %s\n", strings.Repeat(" ", indent), e.Name, e.Values) | |||
| } | |||
| type SearchResult struct { | |||
| Entries []*Entry | |||
| Referrals []string | |||
| Controls []Control | |||
| } | |||
| func (s *SearchResult) Print() { | |||
| for _, entry := range s.Entries { | |||
| entry.Print() | |||
| } | |||
| } | |||
| func (s *SearchResult) PrettyPrint(indent int) { | |||
| for _, entry := range s.Entries { | |||
| entry.PrettyPrint(indent) | |||
| } | |||
| } | |||
| type SearchRequest struct { | |||
| BaseDN string | |||
| Scope int | |||
| DerefAliases int | |||
| SizeLimit int | |||
| TimeLimit int | |||
| TypesOnly bool | |||
| Filter string | |||
| Attributes []string | |||
| Controls []Control | |||
| } | |||
| func (s *SearchRequest) encode() (*ber.Packet, error) { | |||
| request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request") | |||
| request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, s.BaseDN, "Base DN")) | |||
| request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.Scope), "Scope")) | |||
| request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.DerefAliases), "Deref Aliases")) | |||
| request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.SizeLimit), "Size Limit")) | |||
| request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.TimeLimit), "Time Limit")) | |||
| request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, s.TypesOnly, "Types Only")) | |||
| // compile and encode filter | |||
| filterPacket, err := CompileFilter(s.Filter) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| request.AppendChild(filterPacket) | |||
| // encode attributes | |||
| attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes") | |||
| for _, attribute := range s.Attributes { | |||
| attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute")) | |||
| } | |||
| request.AppendChild(attributesPacket) | |||
| return request, nil | |||
| } | |||
| 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) | |||
| l.Debug.Printf("Looking for Paging Control...") | |||
| if err != nil { | |||
| return searchResult, err | |||
| } | |||
| if result == nil { | |||
| return searchResult, NewError(ErrorNetwork, errors.New("ldap: 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) | |||
| } | |||
| l.Debug.Printf("Looking for Paging Control...") | |||
| pagingResult := FindControl(result.Controls, ControlTypePaging) | |||
| if pagingResult == nil { | |||
| pagingControl = nil | |||
| l.Debug.Printf("Could not find paging control. Breaking...") | |||
| break | |||
| } | |||
| cookie := pagingResult.(*ControlPaging).Cookie | |||
| if len(cookie) == 0 { | |||
| pagingControl = nil | |||
| l.Debug.Printf("Could not find cookie. Breaking...") | |||
| break | |||
| } | |||
| pagingControl.SetCookie(cookie) | |||
| } | |||
| if pagingControl != nil { | |||
| l.Debug.Printf("Abandoning Paging...") | |||
| 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.TypePrimitive, ber.TagInteger, messageID, "MessageID")) | |||
| // encode search request | |||
| encodedSearchRequest, err := searchRequest.encode() | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| packet.AppendChild(encodedSearchRequest) | |||
| // encode search controls | |||
| if searchRequest.Controls != nil { | |||
| packet.AppendChild(encodeControls(searchRequest.Controls)) | |||
| } | |||
| l.Debug.PrintPacket(packet) | |||
| channel, err := l.sendMessage(packet) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if channel == nil { | |||
| return nil, NewError(ErrorNetwork, errors.New("ldap: 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 { | |||
| l.Debug.Printf("%d: waiting for response", messageID) | |||
| packet = <-channel | |||
| l.Debug.Printf("%d: got response %p", messageID, packet) | |||
| if packet == nil { | |||
| return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) | |||
| } | |||
| if l.Debug { | |||
| if err := addLDAPDescriptions(packet); err != nil { | |||
| return nil, 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: | |||
| resultCode, resultDescription := getLDAPResultCode(packet) | |||
| if resultCode != 0 { | |||
| return result, NewError(resultCode, errors.New(resultDescription)) | |||
| } | |||
| 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)) | |||
| } | |||
| } | |||
| l.Debug.Printf("%d: returning", messageID) | |||
| return result, nil | |||
| } | |||