From 521bc94749af0dddee7330470a87ecdede24c50e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Tue, 26 Aug 2025 13:28:47 +0800 Subject: [PATCH] fix(keystone): upgrade ldap version (#23167) --- cmd/ldapcli/shell/search.go | 2 +- go.mod | 6 +- go.sum | 13 +- pkg/keystone/driver/ldap/ldap.go | 2 +- pkg/keystone/driver/ldap/sync.go | 2 +- pkg/util/ldaputils/ldaputils.go | 8 +- .../go-asn1-ber/asn1-ber}/LICENSE | 0 .../go-asn1-ber/asn1-ber}/README.md | 0 vendor/github.com/go-asn1-ber/asn1-ber/ber.go | 866 ++++++++++++++++++ .../go-asn1-ber/asn1-ber}/content_int.go | 2 +- .../go-asn1-ber/asn1-ber/generalizedTime.go | 105 +++ .../go-asn1-ber/asn1-ber}/header.go | 23 +- .../go-asn1-ber/asn1-ber}/identifier.go | 2 +- .../go-asn1-ber/asn1-ber}/length.go | 16 +- .../github.com/go-asn1-ber/asn1-ber/real.go | 163 ++++ .../go-asn1-ber/asn1-ber}/util.go | 12 +- .../go-ldap/ldap/v3}/LICENSE | 0 .../go-ldap/ldap/v3}/add.go | 62 +- .../go-ldap/ldap/v3}/bind.go | 83 +- vendor/github.com/go-ldap/ldap/v3/client.go | 30 + vendor/github.com/go-ldap/ldap/v3/compare.go | 61 ++ .../go-ldap/ldap/v3}/conn.go | 115 ++- .../go-ldap/ldap/v3}/control.go | 2 +- .../go-ldap/ldap/v3}/debug.go | 10 +- vendor/github.com/go-ldap/ldap/v3/del.go | 59 ++ .../go-ldap/ldap/v3}/dn.go | 46 +- .../go-ldap/ldap/v3}/doc.go | 0 .../go-ldap/ldap/v3}/error.go | 6 +- .../go-ldap/ldap/v3}/filter.go | 176 ++-- .../go-ldap/ldap/v3}/ldap.go | 8 +- vendor/github.com/go-ldap/ldap/v3/moddn.go | 75 ++ vendor/github.com/go-ldap/ldap/v3/modify.go | 132 +++ .../go-ldap/ldap/v3}/passwdmodify.go | 71 +- vendor/github.com/go-ldap/ldap/v3/request.go | 66 ++ .../go-ldap/ldap/v3}/search.go | 130 +-- vendor/gopkg.in/asn1-ber.v1/.travis.yml | 36 - vendor/gopkg.in/asn1-ber.v1/ber.go | 512 ----------- vendor/gopkg.in/ldap.v3/.gitignore | 0 vendor/gopkg.in/ldap.v3/.travis.yml | 31 - vendor/gopkg.in/ldap.v3/CONTRIBUTING.md | 12 - vendor/gopkg.in/ldap.v3/Makefile | 82 -- vendor/gopkg.in/ldap.v3/README.md | 54 -- vendor/gopkg.in/ldap.v3/client.go | 28 - vendor/gopkg.in/ldap.v3/compare.go | 83 -- vendor/gopkg.in/ldap.v3/del.go | 84 -- vendor/gopkg.in/ldap.v3/moddn.go | 104 --- vendor/gopkg.in/ldap.v3/modify.go | 173 ---- vendor/modules.txt | 14 +- vendor/yunion.io/x/pkg/utils/tags.go | 11 + 49 files changed, 1937 insertions(+), 1641 deletions(-) rename vendor/{gopkg.in/asn1-ber.v1 => github.com/go-asn1-ber/asn1-ber}/LICENSE (100%) rename vendor/{gopkg.in/asn1-ber.v1 => github.com/go-asn1-ber/asn1-ber}/README.md (100%) create mode 100644 vendor/github.com/go-asn1-ber/asn1-ber/ber.go rename vendor/{gopkg.in/asn1-ber.v1 => github.com/go-asn1-ber/asn1-ber}/content_int.go (87%) create mode 100644 vendor/github.com/go-asn1-ber/asn1-ber/generalizedTime.go rename vendor/{gopkg.in/asn1-ber.v1 => github.com/go-asn1-ber/asn1-ber}/header.go (75%) rename vendor/{gopkg.in/asn1-ber.v1 => github.com/go-asn1-ber/asn1-ber}/identifier.go (98%) rename vendor/{gopkg.in/asn1-ber.v1 => github.com/go-asn1-ber/asn1-ber}/length.go (82%) create mode 100644 vendor/github.com/go-asn1-ber/asn1-ber/real.go rename vendor/{gopkg.in/asn1-ber.v1 => github.com/go-asn1-ber/asn1-ber}/util.go (73%) rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/LICENSE (100%) rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/add.go (53%) rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/bind.go (59%) create mode 100644 vendor/github.com/go-ldap/ldap/v3/client.go create mode 100644 vendor/github.com/go-ldap/ldap/v3/compare.go rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/conn.go (87%) rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/control.go (99%) rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/debug.go (62%) create mode 100644 vendor/github.com/go-ldap/ldap/v3/del.go rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/dn.go (79%) rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/doc.go (100%) rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/error.go (99%) rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/filter.go (75%) rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/ldap.go (98%) create mode 100644 vendor/github.com/go-ldap/ldap/v3/moddn.go create mode 100644 vendor/github.com/go-ldap/ldap/v3/modify.go rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/passwdmodify.go (67%) create mode 100644 vendor/github.com/go-ldap/ldap/v3/request.go rename vendor/{gopkg.in/ldap.v3 => github.com/go-ldap/ldap/v3}/search.go (68%) delete mode 100644 vendor/gopkg.in/asn1-ber.v1/.travis.yml delete mode 100644 vendor/gopkg.in/asn1-ber.v1/ber.go delete mode 100644 vendor/gopkg.in/ldap.v3/.gitignore delete mode 100644 vendor/gopkg.in/ldap.v3/.travis.yml delete mode 100644 vendor/gopkg.in/ldap.v3/CONTRIBUTING.md delete mode 100644 vendor/gopkg.in/ldap.v3/Makefile delete mode 100644 vendor/gopkg.in/ldap.v3/README.md delete mode 100644 vendor/gopkg.in/ldap.v3/client.go delete mode 100644 vendor/gopkg.in/ldap.v3/compare.go delete mode 100644 vendor/gopkg.in/ldap.v3/del.go delete mode 100644 vendor/gopkg.in/ldap.v3/moddn.go delete mode 100644 vendor/gopkg.in/ldap.v3/modify.go diff --git a/cmd/ldapcli/shell/search.go b/cmd/ldapcli/shell/search.go index ff3252444d..6b9bfab9f0 100644 --- a/cmd/ldapcli/shell/search.go +++ b/cmd/ldapcli/shell/search.go @@ -18,7 +18,7 @@ import ( "fmt" "strings" - "gopkg.in/ldap.v3" + "github.com/go-ldap/ldap/v3" "yunion.io/x/pkg/util/shellutils" diff --git a/go.mod b/go.mod index 5fcf831519..45497d87e6 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/fsnotify/fsnotify v1.4.9 github.com/ghodss/yaml v1.0.0 github.com/gin-gonic/gin v1.7.7 + github.com/go-ldap/ldap/v3 v3.1.5 github.com/go-yaml/yaml v2.1.0+incompatible github.com/golang-plus/uuid v1.0.0 github.com/golang/mock v1.4.4 @@ -79,7 +80,6 @@ require ( google.golang.org/grpc v1.62.0 google.golang.org/protobuf v1.32.0 gopkg.in/fatih/set.v0 v0.2.1 - gopkg.in/ldap.v3 v3.0.3 gopkg.in/mail.v2 v2.3.1 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.19.3 @@ -92,7 +92,7 @@ require ( yunion.io/x/jsonutils v1.0.1-0.20250507052344-1abcf4f443b1 yunion.io/x/log v1.0.1-0.20240305175729-7cf2d6cd5a91 yunion.io/x/ovsdb v0.0.0-20230306173834-f164f413a900 - yunion.io/x/pkg v1.10.4-0.20250814065738-8df5d9d07297 + yunion.io/x/pkg v1.10.4-0.20250820035218-6008459eb4f0 yunion.io/x/s3cli v0.0.0-20241221171442-1c11599d28e1 yunion.io/x/sqlchemy v1.1.3-0.20250806073422-e37f5197cec0 yunion.io/x/structarg v0.0.0-20231017124457-df4d5009457c @@ -163,6 +163,7 @@ require ( github.com/frankban/quicktest v1.14.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect github.com/go-logfmt/logfmt v0.5.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -276,7 +277,6 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index c02600cad2..ecf2f100c8 100644 --- a/go.sum +++ b/go.sum @@ -281,12 +281,17 @@ github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493 h1:OTanQnFt0bi5iLFSdbEVA/idR6Q2WhCm+deb7ir2CcM= github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-ldap/ldap/v3 v3.1.5 h1:5o1ik2It7MJoXwoS7JXWUebf18L7E1VWBBgYV/iVsN0= +github.com/go-ldap/ldap/v3 v3.1.5/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= @@ -1200,8 +1205,6 @@ google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= -gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= -gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1216,8 +1219,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ldap.v3 v3.0.3 h1:YKRHW/2sIl05JsCtx/5ZuUueFuJyoj/6+DGXe3wp6ro= -gopkg.in/ldap.v3 v3.0.3/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -1285,8 +1286,8 @@ yunion.io/x/ovsdb v0.0.0-20230306173834-f164f413a900 h1:Hu/4ERvoWaN6aiFs4h4/yvVB yunion.io/x/ovsdb v0.0.0-20230306173834-f164f413a900/go.mod h1:0vLkNEhlmA64HViPBAnSTUMrx5QP1CLsxXmxDKQ80tc= yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= yunion.io/x/pkg v0.0.0-20190628082551-f4033ba2ea30/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= -yunion.io/x/pkg v1.10.4-0.20250814065738-8df5d9d07297 h1:rnU78gHJ+2nEgjpwWN+FclED/nFeuMkrrBWgnTz0ykc= -yunion.io/x/pkg v1.10.4-0.20250814065738-8df5d9d07297/go.mod h1:0Bwxqd9MA3ACi119/l02FprY/o9gHahmYC2bsSbnVpM= +yunion.io/x/pkg v1.10.4-0.20250820035218-6008459eb4f0 h1:/vHcYqzQInxqR1jjS+e7A0owRXj+/rvrIgES6uadUqs= +yunion.io/x/pkg v1.10.4-0.20250820035218-6008459eb4f0/go.mod h1:0Bwxqd9MA3ACi119/l02FprY/o9gHahmYC2bsSbnVpM= yunion.io/x/s3cli v0.0.0-20241221171442-1c11599d28e1 h1:1KJ3YYinydPHpDEQRXdr/T8SYcKZ5Er+m489H+PnaQ4= yunion.io/x/s3cli v0.0.0-20241221171442-1c11599d28e1/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo= yunion.io/x/sqlchemy v1.1.3-0.20250806073422-e37f5197cec0 h1:Eha/ywh4foMJm7VJ8ibFOi+WPHacuTWtosAGpOld5vo= diff --git a/pkg/keystone/driver/ldap/ldap.go b/pkg/keystone/driver/ldap/ldap.go index 6a33453a9c..15c4533146 100644 --- a/pkg/keystone/driver/ldap/ldap.go +++ b/pkg/keystone/driver/ldap/ldap.go @@ -20,7 +20,7 @@ import ( "strconv" "strings" - "gopkg.in/ldap.v3" + "github.com/go-ldap/ldap/v3" "yunion.io/x/jsonutils" "yunion.io/x/log" diff --git a/pkg/keystone/driver/ldap/sync.go b/pkg/keystone/driver/ldap/sync.go index 0dff636d14..0c4328b3bb 100644 --- a/pkg/keystone/driver/ldap/sync.go +++ b/pkg/keystone/driver/ldap/sync.go @@ -18,7 +18,7 @@ import ( "context" "database/sql" - "gopkg.in/ldap.v3" + "github.com/go-ldap/ldap/v3" "yunion.io/x/jsonutils" "yunion.io/x/log" diff --git a/pkg/util/ldaputils/ldaputils.go b/pkg/util/ldaputils/ldaputils.go index 2f889a6981..cf603a43f6 100644 --- a/pkg/util/ldaputils/ldaputils.go +++ b/pkg/util/ldaputils/ldaputils.go @@ -15,11 +15,12 @@ package ldaputils import ( + "crypto/tls" "encoding/hex" "fmt" "strings" - "gopkg.in/ldap.v3" + "github.com/go-ldap/ldap/v3" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -59,12 +60,11 @@ func NewLDAPClient(url, account, password string, baseDN string, isDebug bool) * } func (cli *SLDAPClient) Connect() error { - conn, err := ldap.DialURL(cli.url) + var err error + cli.conn, err = ldap.DialURL(cli.url, ldap.DialWithTLSConfig(&tls.Config{InsecureSkipVerify: true})) if err != nil { return errors.Wrap(err, "DiaURL") } - cli.conn = conn - return cli.bind() } diff --git a/vendor/gopkg.in/asn1-ber.v1/LICENSE b/vendor/github.com/go-asn1-ber/asn1-ber/LICENSE similarity index 100% rename from vendor/gopkg.in/asn1-ber.v1/LICENSE rename to vendor/github.com/go-asn1-ber/asn1-ber/LICENSE diff --git a/vendor/gopkg.in/asn1-ber.v1/README.md b/vendor/github.com/go-asn1-ber/asn1-ber/README.md similarity index 100% rename from vendor/gopkg.in/asn1-ber.v1/README.md rename to vendor/github.com/go-asn1-ber/asn1-ber/README.md diff --git a/vendor/github.com/go-asn1-ber/asn1-ber/ber.go b/vendor/github.com/go-asn1-ber/asn1-ber/ber.go new file mode 100644 index 0000000000..f27229ed60 --- /dev/null +++ b/vendor/github.com/go-asn1-ber/asn1-ber/ber.go @@ -0,0 +1,866 @@ +package ber + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "math" + "os" + "reflect" + "strconv" + "strings" + "time" + "unicode/utf8" +) + +// MaxPacketLengthBytes specifies the maximum allowed packet size when calling ReadPacket or DecodePacket. Set to 0 for +// no limit. +var MaxPacketLengthBytes int64 = math.MaxInt32 + +type Packet struct { + Identifier + Value interface{} + ByteValue []byte + Data *bytes.Buffer + Children []*Packet + Description string +} + +type Identifier struct { + ClassType Class + TagType Type + Tag Tag +} + +type Tag uint64 + +const ( + TagEOC Tag = 0x00 + TagBoolean Tag = 0x01 + TagInteger Tag = 0x02 + TagBitString Tag = 0x03 + TagOctetString Tag = 0x04 + TagNULL Tag = 0x05 + TagObjectIdentifier Tag = 0x06 + TagObjectDescriptor Tag = 0x07 + TagExternal Tag = 0x08 + TagRealFloat Tag = 0x09 + TagEnumerated Tag = 0x0a + TagEmbeddedPDV Tag = 0x0b + TagUTF8String Tag = 0x0c + TagRelativeOID Tag = 0x0d + TagSequence Tag = 0x10 + TagSet Tag = 0x11 + TagNumericString Tag = 0x12 + TagPrintableString Tag = 0x13 + TagT61String Tag = 0x14 + TagVideotexString Tag = 0x15 + TagIA5String Tag = 0x16 + TagUTCTime Tag = 0x17 + TagGeneralizedTime Tag = 0x18 + TagGraphicString Tag = 0x19 + TagVisibleString Tag = 0x1a + TagGeneralString Tag = 0x1b + TagUniversalString Tag = 0x1c + TagCharacterString Tag = 0x1d + TagBMPString Tag = 0x1e + TagBitmask Tag = 0x1f // xxx11111b + + // HighTag indicates the start of a high-tag byte sequence + HighTag Tag = 0x1f // xxx11111b + // HighTagContinueBitmask indicates the high-tag byte sequence should continue + HighTagContinueBitmask Tag = 0x80 // 10000000b + // HighTagValueBitmask obtains the tag value from a high-tag byte sequence byte + HighTagValueBitmask Tag = 0x7f // 01111111b +) + +const ( + // LengthLongFormBitmask is the mask to apply to the length byte to see if a long-form byte sequence is used + LengthLongFormBitmask = 0x80 + // LengthValueBitmask is the mask to apply to the length byte to get the number of bytes in the long-form byte sequence + LengthValueBitmask = 0x7f + + // LengthIndefinite is returned from readLength to indicate an indefinite length + LengthIndefinite = -1 +) + +var tagMap = map[Tag]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", +} + +type Class uint8 + +const ( + ClassUniversal Class = 0 // 00xxxxxxb + ClassApplication Class = 64 // 01xxxxxxb + ClassContext Class = 128 // 10xxxxxxb + ClassPrivate Class = 192 // 11xxxxxxb + ClassBitmask Class = 192 // 11xxxxxxb +) + +var ClassMap = map[Class]string{ + ClassUniversal: "Universal", + ClassApplication: "Application", + ClassContext: "Context", + ClassPrivate: "Private", +} + +type Type uint8 + +const ( + TypePrimitive Type = 0 // xx0xxxxxb + TypeConstructed Type = 32 // xx1xxxxxb + TypeBitmask Type = 32 // xx1xxxxxb +) + +var TypeMap = map[Type]string{ + TypePrimitive: "Primitive", + TypeConstructed: "Constructed", +} + +var Debug = false + +func PrintBytes(out io.Writer, buf []byte, indent string) { + dataLines := make([]string, (len(buf)/30)+1) + numLines := make([]string, (len(buf)/30)+1) + + for i, b := range buf { + dataLines[i/30] += fmt.Sprintf("%02x ", b) + numLines[i/30] += fmt.Sprintf("%02d ", (i+1)%100) + } + + for i := 0; i < len(dataLines); i++ { + _, _ = out.Write([]byte(indent + dataLines[i] + "\n")) + _, _ = out.Write([]byte(indent + numLines[i] + "\n\n")) + } +} + +func WritePacket(out io.Writer, p *Packet) { + printPacket(out, p, 0, false) +} + +func PrintPacket(p *Packet) { + printPacket(os.Stdout, p, 0, false) +} + +// Return a string describing packet content. This is not recursive, +// If the packet is a sequence, use `printPacket()`, or browse +// sequence yourself. +func DescribePacket(p *Packet) string { + + classStr := ClassMap[p.ClassType] + + tagTypeStr := TypeMap[p.TagType] + + tagStr := fmt.Sprintf("0x%02X", p.Tag) + + if p.ClassType == ClassUniversal { + tagStr = tagMap[p.Tag] + } + + value := fmt.Sprint(p.Value) + description := "" + + if p.Description != "" { + description = p.Description + ": " + } + + return fmt.Sprintf("%s(%s, %s, %s) Len=%d %q", description, classStr, tagTypeStr, tagStr, p.Data.Len(), value) +} + +func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) { + indentStr := "" + + for len(indentStr) != indent { + indentStr += " " + } + + _, _ = fmt.Fprintf(out, "%s%s\n", indentStr, DescribePacket(p)) + + if printBytes { + PrintBytes(out, p.Bytes(), indentStr) + } + + for _, child := range p.Children { + printPacket(out, child, indent+1, printBytes) + } +} + +// ReadPacket reads a single Packet from the reader. +func ReadPacket(reader io.Reader) (*Packet, error) { + p, _, err := readPacket(reader) + if err != nil { + return nil, err + } + return p, nil +} + +func DecodeString(data []byte) string { + return string(data) +} + +func ParseInt64(bytes []byte) (ret int64, err error) { + if len(bytes) > 8 { + // We'll overflow an int64 in this case. + err = fmt.Errorf("integer too large") + return + } + for bytesRead := 0; bytesRead < len(bytes); bytesRead++ { + ret <<= 8 + ret |= int64(bytes[bytesRead]) + } + + // Shift up and down in order to sign extend the result. + ret <<= 64 - uint8(len(bytes))*8 + ret >>= 64 - uint8(len(bytes))*8 + return +} + +func encodeInteger(i int64) []byte { + n := int64Length(i) + out := make([]byte, n) + + var j int + for ; n > 0; n-- { + out[j] = byte(i >> uint((n-1)*8)) + j++ + } + + return out +} + +func int64Length(i int64) (numBytes int) { + numBytes = 1 + + for i > 127 { + numBytes++ + i >>= 8 + } + + for i < -128 { + numBytes++ + i >>= 8 + } + + return +} + +// DecodePacket decodes the given bytes into a single Packet +// If a decode error is encountered, nil is returned. +func DecodePacket(data []byte) *Packet { + p, _, _ := readPacket(bytes.NewBuffer(data)) + + return p +} + +// DecodePacketErr decodes the given bytes into a single Packet +// If a decode error is encountered, nil is returned. +func DecodePacketErr(data []byte) (*Packet, error) { + p, _, err := readPacket(bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + return p, nil +} + +// readPacket reads a single Packet from the reader, returning the number of bytes read. +func readPacket(reader io.Reader) (*Packet, int, error) { + identifier, length, read, err := readHeader(reader) + if err != nil { + return nil, read, err + } + + p := &Packet{ + Identifier: identifier, + } + + p.Data = new(bytes.Buffer) + p.Children = make([]*Packet, 0, 2) + p.Value = nil + + if p.TagType == TypeConstructed { + // TODO: if universal, ensure tag type is allowed to be constructed + + // Track how much content we've read + contentRead := 0 + for { + if length != LengthIndefinite { + // End if we've read what we've been told to + if contentRead == length { + break + } + // Detect if a packet boundary didn't fall on the expected length + if contentRead > length { + return nil, read, fmt.Errorf("expected to read %d bytes, read %d", length, contentRead) + } + } + + // Read the next packet + child, r, err := readPacket(reader) + if err != nil { + return nil, read, unexpectedEOF(err) + } + contentRead += r + read += r + + // Test is this is the EOC marker for our packet + if isEOCPacket(child) { + if length == LengthIndefinite { + break + } + return nil, read, errors.New("eoc child not allowed with definite length") + } + + // Append and continue + p.AppendChild(child) + } + return p, read, nil + } + + if length == LengthIndefinite { + return nil, read, errors.New("indefinite length used with primitive type") + } + + // Read definite-length content + if MaxPacketLengthBytes > 0 && int64(length) > MaxPacketLengthBytes { + return nil, read, fmt.Errorf("length %d greater than maximum %d", length, MaxPacketLengthBytes) + } + + var content []byte + if length > 0 { + // Read the content and limit it to the parsed length. + // If the content is less than the length, we return an EOF error. + content, err = ioutil.ReadAll(io.LimitReader(reader, int64(length))) + if err == nil && len(content) < int(length) { + err = io.EOF + } + if err != nil { + return nil, read, unexpectedEOF(err) + } + read += len(content) + } else { + // If length == 0, we set the ByteValue to an empty slice + content = make([]byte, 0) + } + + if p.ClassType == ClassUniversal { + p.Data.Write(content) + p.ByteValue = content + + switch p.Tag { + case TagEOC: + case TagBoolean: + val, _ := ParseInt64(content) + + p.Value = val != 0 + case TagInteger: + p.Value, _ = ParseInt64(content) + case TagBitString: + case TagOctetString: + // the actual string encoding is not known here + // (e.g. for LDAP content is already an UTF8-encoded + // string). Return the data without further processing + p.Value = DecodeString(content) + case TagNULL: + case TagObjectIdentifier: + oid, err := parseObjectIdentifier(content) + if err == nil { + p.Value = OIDToString(oid) + } + case TagObjectDescriptor: + case TagExternal: + case TagRealFloat: + p.Value, err = ParseReal(content) + case TagEnumerated: + p.Value, _ = ParseInt64(content) + case TagEmbeddedPDV: + case TagUTF8String: + val := DecodeString(content) + if !utf8.Valid([]byte(val)) { + err = errors.New("invalid UTF-8 string") + } else { + p.Value = val + } + case TagRelativeOID: + oid, err := parseRelativeObjectIdentifier(content) + if err == nil { + p.Value = OIDToString(oid) + } + case TagSequence: + case TagSet: + case TagNumericString: + case TagPrintableString: + val := DecodeString(content) + if err = isPrintableString(val); err == nil { + p.Value = val + } + case TagT61String: + case TagVideotexString: + case TagIA5String: + val := DecodeString(content) + for i, c := range val { + if c >= 0x7F { + err = fmt.Errorf("invalid character for IA5String at pos %d: %c", i, c) + break + } + } + if err == nil { + p.Value = val + } + case TagUTCTime: + case TagGeneralizedTime: + p.Value, err = ParseGeneralizedTime(content) + case TagGraphicString: + case TagVisibleString: + case TagGeneralString: + case TagUniversalString: + case TagCharacterString: + case TagBMPString: + } + } else { + p.Data.Write(content) + } + + return p, read, err +} + +func isPrintableString(val string) error { + for i, c := range val { + switch { + case c >= 'a' && c <= 'z': + case c >= 'A' && c <= 'Z': + case c >= '0' && c <= '9': + default: + switch c { + case '\'', '(', ')', '+', ',', '-', '.', '=', '/', ':', '?', ' ': + default: + return fmt.Errorf("invalid character in position %d", i) + } + } + } + return nil +} + +func (p *Packet) Bytes() []byte { + var out bytes.Buffer + + out.Write(encodeIdentifier(p.Identifier)) + out.Write(encodeLength(p.Data.Len())) + out.Write(p.Data.Bytes()) + + return out.Bytes() +} + +func (p *Packet) AppendChild(child *Packet) { + p.Data.Write(child.Bytes()) + p.Children = append(p.Children, child) +} + +func Encode(classType Class, tagType Type, tag Tag, 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)) + } + case TagEnumerated: + bv, ok := v.Interface().([]byte) + if ok { + p.Data.Write(bv) + } + case TagEmbeddedPDV: + bv, ok := v.Interface().([]byte) + if ok { + p.Data.Write(bv) + } + } + } else if classType == ClassContext { + switch tag { + case TagEnumerated: + bv, ok := v.Interface().([]byte) + if ok { + p.Data.Write(bv) + } + case TagEmbeddedPDV: + bv, ok := v.Interface().([]byte) + if ok { + p.Data.Write(bv) + } + } + } + } + return p +} + +func NewSequence(description string) *Packet { + return Encode(ClassUniversal, TypeConstructed, TagSequence, nil, description) +} + +func NewBoolean(classType Class, tagType Type, tag Tag, value bool, description string) *Packet { + intValue := int64(0) + + if value { + intValue = 1 + } + + p := Encode(classType, tagType, tag, nil, description) + + p.Value = value + p.Data.Write(encodeInteger(intValue)) + + return p +} + +// NewLDAPBoolean returns a RFC 4511-compliant Boolean packet. +func NewLDAPBoolean(classType Class, tagType Type, tag Tag, value bool, description string) *Packet { + p := Encode(classType, tagType, tag, nil, description) + + p.Value = value + if value { + p.Data.Write([]byte{255}) + } else { + p.Data.Write([]byte{0}) + } + + return p +} + +func NewInteger(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet { + p := Encode(classType, tagType, tag, nil, description) + + p.Value = value + switch v := value.(type) { + case int: + p.Data.Write(encodeInteger(int64(v))) + case uint: + p.Data.Write(encodeInteger(int64(v))) + case int64: + p.Data.Write(encodeInteger(v)) + case uint64: + // TODO : check range or add encodeUInt... + p.Data.Write(encodeInteger(int64(v))) + case int32: + p.Data.Write(encodeInteger(int64(v))) + case uint32: + p.Data.Write(encodeInteger(int64(v))) + case int16: + p.Data.Write(encodeInteger(int64(v))) + case uint16: + p.Data.Write(encodeInteger(int64(v))) + case int8: + p.Data.Write(encodeInteger(int64(v))) + case uint8: + p.Data.Write(encodeInteger(int64(v))) + default: + // TODO : add support for big.Int ? + panic(fmt.Sprintf("Invalid type %T, expected {u|}int{64|32|16|8}", v)) + } + + return p +} + +func NewString(classType Class, tagType Type, tag Tag, value, description string) *Packet { + p := Encode(classType, tagType, tag, nil, description) + + p.Value = value + p.Data.Write([]byte(value)) + + return p +} + +func NewGeneralizedTime(classType Class, tagType Type, tag Tag, value time.Time, description string) *Packet { + p := Encode(classType, tagType, tag, nil, description) + var s string + if value.Nanosecond() != 0 { + s = value.Format(`20060102150405.000000000Z`) + } else { + s = value.Format(`20060102150405Z`) + } + p.Value = s + p.Data.Write([]byte(s)) + return p +} + +func NewReal(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet { + p := Encode(classType, tagType, tag, nil, description) + + switch v := value.(type) { + case float64: + p.Data.Write(encodeFloat(v)) + case float32: + p.Data.Write(encodeFloat(float64(v))) + default: + panic(fmt.Sprintf("Invalid type %T, expected float{64|32}", v)) + } + return p +} + +func NewOID(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet { + p := Encode(classType, tagType, tag, nil, description) + + switch v := value.(type) { + case string: + encoded, err := encodeOID(v) + if err != nil { + fmt.Printf("failed writing %v", err) + return nil + } + p.Value = v + p.Data.Write(encoded) + // TODO: support []int already ? + default: + panic(fmt.Sprintf("Invalid type %T, expected float{64|32}", v)) + } + return p +} + +func NewRelativeOID(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet { + p := Encode(classType, tagType, tag, nil, description) + + switch v := value.(type) { + case string: + encoded, err := encodeRelativeOID(v) + if err != nil { + fmt.Printf("failed writing %v", err) + return nil + } + p.Value = v + p.Data.Write(encoded) + // TODO: support []int already ? + default: + panic(fmt.Sprintf("Invalid type %T, expected float{64|32}", v)) + } + return p +} + +// encodeOID takes a string representation of an OID and returns its DER-encoded byte slice along with any error. +func encodeOID(oidString string) ([]byte, error) { + // Convert the string representation to an asn1.ObjectIdentifier + parts := strings.Split(oidString, ".") + oid := make([]int, len(parts)) + for i, part := range parts { + var val int + if _, err := fmt.Sscanf(part, "%d", &val); err != nil { + return nil, fmt.Errorf("invalid OID part '%s': %w", part, err) + } + oid[i] = val + } + if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) { + panic(fmt.Sprintf("invalid object identifier % d", oid)) // TODO: not elegant + } + encoded := make([]byte, 0) + + encoded = appendBase128Int(encoded[:0], int64(oid[0]*40+oid[1])) + for i := 2; i < len(oid); i++ { + encoded = appendBase128Int(encoded, int64(oid[i])) + } + + return encoded, nil +} + +func encodeRelativeOID(oidString string) ([]byte, error) { + parts := strings.Split(oidString, ".") + oid := make([]int, len(parts)) + for i, part := range parts { + var val int + if _, err := fmt.Sscanf(part, "%d", &val); err != nil { + return nil, fmt.Errorf("invalid RELATIVE OID part '%s': %w", part, err) + } + oid[i] = val + } + + encoded := make([]byte, 0) + + for i := 0; i < len(oid); i++ { + encoded = appendBase128Int(encoded, int64(oid[i])) + } + + return encoded, nil +} + +func appendBase128Int(dst []byte, n int64) []byte { + l := base128IntLength(n) + + for i := l - 1; i >= 0; i-- { + o := byte(n >> uint(i*7)) + o &= 0x7f + if i != 0 { + o |= 0x80 + } + + dst = append(dst, o) + } + + return dst +} +func base128IntLength(n int64) int { + if n == 0 { + return 1 + } + + l := 0 + for i := n; i > 0; i >>= 7 { + l++ + } + + return l +} + +func OIDToString(oi []int) string { + var s strings.Builder + s.Grow(32) + + buf := make([]byte, 0, 19) + for i, v := range oi { + if i > 0 { + s.WriteByte('.') + } + s.Write(strconv.AppendInt(buf, int64(v), 10)) + } + + return s.String() +} + +// parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and +// returns it. An object identifier is a sequence of variable length integers +// that are assigned in a hierarchy. +func parseObjectIdentifier(bytes []byte) (s []int, err error) { + if len(bytes) == 0 { + err = fmt.Errorf("zero length OBJECT IDENTIFIER") + return + } + + // In the worst case, we get two elements from the first byte (which is + // encoded differently) and then every varint is a single byte long. + s = make([]int, len(bytes)+1) + + // The first varint is 40*value1 + value2: + // According to this packing, value1 can take the values 0, 1 and 2 only. + // When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2, + // then there are no restrictions on value2. + v, offset, err := parseBase128Int(bytes, 0) + if err != nil { + return + } + if v < 80 { + s[0] = v / 40 + s[1] = v % 40 + } else { + s[0] = 2 + s[1] = v - 80 + } + + i := 2 + for ; offset < len(bytes); i++ { + v, offset, err = parseBase128Int(bytes, offset) + if err != nil { + return + } + s[i] = v + } + s = s[0:i] + return +} + +func parseRelativeObjectIdentifier(bytes []byte) (s []int, err error) { + if len(bytes) == 0 { + err = fmt.Errorf("zero length RELATIVE OBJECT IDENTIFIER") + return + } + + s = make([]int, len(bytes)+1) + + var v, offset int + i := 0 + for ; offset < len(bytes); i++ { + v, offset, err = parseBase128Int(bytes, offset) + if err != nil { + return + } + s[i] = v + } + s = s[0:i] + return +} + +// parseBase128Int parses a base-128 encoded int from the given offset in the +// given byte slice. It returns the value and the new offset. +func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) { + offset = initOffset + var ret64 int64 + for shifted := 0; offset < len(bytes); shifted++ { + // 5 * 7 bits per byte == 35 bits of data + // Thus the representation is either non-minimal or too large for an int32 + if shifted == 5 { + err = fmt.Errorf("base 128 integer too large") + return + } + ret64 <<= 7 + b := bytes[offset] + // integers should be minimally encoded, so the leading octet should + // never be 0x80 + if shifted == 0 && b == 0x80 { + err = fmt.Errorf("integer is not minimally encoded") + return + } + ret64 |= int64(b & 0x7f) + offset++ + if b&0x80 == 0 { + ret = int(ret64) + // Ensure that the returned value fits in an int on all platforms + if ret64 > math.MaxInt32 { + err = fmt.Errorf("base 128 integer too large") + } + return + } + } + err = fmt.Errorf("truncated base 128 integer") + return +} diff --git a/vendor/gopkg.in/asn1-ber.v1/content_int.go b/vendor/github.com/go-asn1-ber/asn1-ber/content_int.go similarity index 87% rename from vendor/gopkg.in/asn1-ber.v1/content_int.go rename to vendor/github.com/go-asn1-ber/asn1-ber/content_int.go index 1858b74b6d..20b500f553 100644 --- a/vendor/gopkg.in/asn1-ber.v1/content_int.go +++ b/vendor/github.com/go-asn1-ber/asn1-ber/content_int.go @@ -6,7 +6,7 @@ func encodeUnsignedInteger(i uint64) []byte { var j int for ; n > 0; n-- { - out[j] = (byte(i >> uint((n-1)*8))) + out[j] = byte(i >> uint((n-1)*8)) j++ } diff --git a/vendor/github.com/go-asn1-ber/asn1-ber/generalizedTime.go b/vendor/github.com/go-asn1-ber/asn1-ber/generalizedTime.go new file mode 100644 index 0000000000..51215f0619 --- /dev/null +++ b/vendor/github.com/go-asn1-ber/asn1-ber/generalizedTime.go @@ -0,0 +1,105 @@ +package ber + +import ( + "bytes" + "errors" + "fmt" + "strconv" + "time" +) + +// ErrInvalidTimeFormat is returned when the generalizedTime string was not correct. +var ErrInvalidTimeFormat = errors.New("invalid time format") + +var zeroTime = time.Time{} + +// ParseGeneralizedTime parses a string value and if it conforms to +// GeneralizedTime[^0] format, will return a time.Time for that value. +// +// [^0]: https://www.itu.int/rec/T-REC-X.690-201508-I/en Section 11.7 +func ParseGeneralizedTime(v []byte) (time.Time, error) { + var format string + var fract time.Duration + + str := []byte(DecodeString(v)) + tzIndex := bytes.IndexAny(str, "Z+-") + if tzIndex < 0 { + return zeroTime, ErrInvalidTimeFormat + } + + dot := bytes.IndexAny(str, ".,") + switch dot { + case -1: + switch tzIndex { + case 10: + format = `2006010215Z` + case 12: + format = `200601021504Z` + case 14: + format = `20060102150405Z` + default: + return zeroTime, ErrInvalidTimeFormat + } + + case 10, 12: + if tzIndex < dot { + return zeroTime, ErrInvalidTimeFormat + } + // a "," is also allowed, but would not be parsed by time.Parse(): + str[dot] = '.' + + // If is omitted, then represents a fraction of an + // hour; otherwise, if and are omitted, then + // represents a fraction of a minute; otherwise, + // represents a fraction of a second. + + // parse as float from dot to timezone + f, err := strconv.ParseFloat(string(str[dot:tzIndex]), 64) + if err != nil { + return zeroTime, fmt.Errorf("failed to parse float: %s", err) + } + // ...and strip that part + str = append(str[:dot], str[tzIndex:]...) + tzIndex = dot + + if dot == 10 { + fract = time.Duration(int64(f * float64(time.Hour))) + format = `2006010215Z` + } else { + fract = time.Duration(int64(f * float64(time.Minute))) + format = `200601021504Z` + } + + case 14: + if tzIndex < dot { + return zeroTime, ErrInvalidTimeFormat + } + str[dot] = '.' + // no need for fractional seconds, time.Parse() handles that + format = `20060102150405Z` + + default: + return zeroTime, ErrInvalidTimeFormat + } + + l := len(str) + switch l - tzIndex { + case 1: + if str[l-1] != 'Z' { + return zeroTime, ErrInvalidTimeFormat + } + case 3: + format += `0700` + str = append(str, []byte("00")...) + case 5: + format += `0700` + default: + return zeroTime, ErrInvalidTimeFormat + } + + t, err := time.Parse(format, string(str)) + if err != nil { + return zeroTime, fmt.Errorf("%s: %s", ErrInvalidTimeFormat, err) + } + return t.Add(fract), nil +} diff --git a/vendor/gopkg.in/asn1-ber.v1/header.go b/vendor/github.com/go-asn1-ber/asn1-ber/header.go similarity index 75% rename from vendor/gopkg.in/asn1-ber.v1/header.go rename to vendor/github.com/go-asn1-ber/asn1-ber/header.go index 71615621cb..7dfa6b9a7d 100644 --- a/vendor/gopkg.in/asn1-ber.v1/header.go +++ b/vendor/github.com/go-asn1-ber/asn1-ber/header.go @@ -7,19 +7,22 @@ import ( ) func readHeader(reader io.Reader) (identifier Identifier, length int, read int, err error) { - if i, c, err := readIdentifier(reader); err != nil { - return Identifier{}, 0, read, err - } else { - identifier = i - read += c - } + var ( + c, l int + i Identifier + ) - if l, c, err := readLength(reader); err != nil { + if i, c, err = readIdentifier(reader); err != nil { return Identifier{}, 0, read, err - } else { - length = l - read += c } + identifier = i + read += c + + if l, c, err = readLength(reader); err != nil { + return Identifier{}, 0, read, err + } + length = l + read += c // Validate length type with identifier (x.600, 8.1.3.2.a) if length == LengthIndefinite && identifier.TagType == TypePrimitive { diff --git a/vendor/gopkg.in/asn1-ber.v1/identifier.go b/vendor/github.com/go-asn1-ber/asn1-ber/identifier.go similarity index 98% rename from vendor/gopkg.in/asn1-ber.v1/identifier.go rename to vendor/github.com/go-asn1-ber/asn1-ber/identifier.go index e8c435749a..c501d8190c 100644 --- a/vendor/gopkg.in/asn1-ber.v1/identifier.go +++ b/vendor/github.com/go-asn1-ber/asn1-ber/identifier.go @@ -37,7 +37,7 @@ func readIdentifier(reader io.Reader) (Identifier, int, error) { if Debug { fmt.Printf("error reading high-tag-number tag byte %d: %v\n", tagBytes, err) } - return Identifier{}, read, err + return Identifier{}, read, unexpectedEOF(err) } tagBytes++ read++ diff --git a/vendor/gopkg.in/asn1-ber.v1/length.go b/vendor/github.com/go-asn1-ber/asn1-ber/length.go similarity index 82% rename from vendor/gopkg.in/asn1-ber.v1/length.go rename to vendor/github.com/go-asn1-ber/asn1-ber/length.go index 750e8f4436..2c81cc3fd2 100644 --- a/vendor/gopkg.in/asn1-ber.v1/length.go +++ b/vendor/github.com/go-asn1-ber/asn1-ber/length.go @@ -13,7 +13,7 @@ func readLength(reader io.Reader) (length int, read int, err error) { if Debug { fmt.Printf("error reading length byte: %v\n", err) } - return 0, 0, err + return 0, 0, unexpectedEOF(err) } read++ @@ -47,7 +47,7 @@ func readLength(reader io.Reader) (length int, read int, err error) { if Debug { fmt.Printf("error reading long-form length byte %d: %v\n", i, err) } - return 0, read, err + return 0, read, unexpectedEOF(err) } read++ @@ -71,11 +71,11 @@ func readLength(reader io.Reader) (length int, read int, err error) { } func encodeLength(length int) []byte { - length_bytes := encodeUnsignedInteger(uint64(length)) - if length > 127 || len(length_bytes) > 1 { - longFormBytes := []byte{(LengthLongFormBitmask | byte(len(length_bytes)))} - longFormBytes = append(longFormBytes, length_bytes...) - length_bytes = longFormBytes + lengthBytes := encodeUnsignedInteger(uint64(length)) + if length > 127 || len(lengthBytes) > 1 { + longFormBytes := []byte{LengthLongFormBitmask | byte(len(lengthBytes))} + longFormBytes = append(longFormBytes, lengthBytes...) + lengthBytes = longFormBytes } - return length_bytes + return lengthBytes } diff --git a/vendor/github.com/go-asn1-ber/asn1-ber/real.go b/vendor/github.com/go-asn1-ber/asn1-ber/real.go new file mode 100644 index 0000000000..9f637a572a --- /dev/null +++ b/vendor/github.com/go-asn1-ber/asn1-ber/real.go @@ -0,0 +1,163 @@ +package ber + +import ( + "bytes" + "errors" + "fmt" + "math" + "strconv" + "strings" +) + +func encodeFloat(v float64) []byte { + switch { + case math.IsInf(v, 1): + return []byte{0x40} + case math.IsInf(v, -1): + return []byte{0x41} + case math.IsNaN(v): + return []byte{0x42} + case v == 0.0: + if math.Signbit(v) { + return []byte{0x43} + } + return []byte{} + default: + // we take the easy part ;-) + value := []byte(strconv.FormatFloat(v, 'G', -1, 64)) + var ret []byte + if bytes.Contains(value, []byte{'E'}) { + ret = []byte{0x03} + } else { + ret = []byte{0x02} + } + ret = append(ret, value...) + return ret + } +} + +func ParseReal(v []byte) (val float64, err error) { + if len(v) == 0 { + return 0.0, nil + } + switch { + case v[0]&0x80 == 0x80: + val, err = parseBinaryFloat(v) + case v[0]&0xC0 == 0x40: + val, err = parseSpecialFloat(v) + case v[0]&0xC0 == 0x0: + val, err = parseDecimalFloat(v) + default: + return 0.0, fmt.Errorf("invalid info block") + } + if err != nil { + return 0.0, err + } + + if val == 0.0 && !math.Signbit(val) { + return 0.0, errors.New("REAL value +0 must be encoded with zero-length value block") + } + return val, nil +} + +func parseBinaryFloat(v []byte) (float64, error) { + var info byte + var buf []byte + + info, v = v[0], v[1:] + + var base int + switch info & 0x30 { + case 0x00: + base = 2 + case 0x10: + base = 8 + case 0x20: + base = 16 + case 0x30: + return 0.0, errors.New("bits 6 and 5 of information octet for REAL are equal to 11") + } + + scale := uint((info & 0x0c) >> 2) + + var expLen int + switch info & 0x03 { + case 0x00: + expLen = 1 + case 0x01: + expLen = 2 + case 0x02: + expLen = 3 + case 0x03: + if len(v) < 2 { + return 0.0, errors.New("invalid data") + } + expLen = int(v[0]) + if expLen > 8 { + return 0.0, errors.New("too big value of exponent") + } + v = v[1:] + } + if expLen > len(v) { + return 0.0, errors.New("too big value of exponent") + } + buf, v = v[:expLen], v[expLen:] + exponent, err := ParseInt64(buf) + if err != nil { + return 0.0, err + } + + if len(v) > 8 { + return 0.0, errors.New("too big value of mantissa") + } + + mant, err := ParseInt64(v) + if err != nil { + return 0.0, err + } + mantissa := mant << scale + + if info&0x40 == 0x40 { + mantissa = -mantissa + } + + return float64(mantissa) * math.Pow(float64(base), float64(exponent)), nil +} + +func parseDecimalFloat(v []byte) (val float64, err error) { + switch v[0] & 0x3F { + case 0x01: // NR form 1 + var iVal int64 + iVal, err = strconv.ParseInt(strings.TrimLeft(string(v[1:]), " "), 10, 64) + val = float64(iVal) + case 0x02, 0x03: // NR form 2, 3 + val, err = strconv.ParseFloat(strings.Replace(strings.TrimLeft(string(v[1:]), " "), ",", ".", -1), 64) + default: + err = errors.New("incorrect NR form") + } + if err != nil { + return 0.0, err + } + + if val == 0.0 && math.Signbit(val) { + return 0.0, errors.New("REAL value -0 must be encoded as a special value") + } + return val, nil +} + +func parseSpecialFloat(v []byte) (float64, error) { + if len(v) != 1 { + return 0.0, errors.New(`encoding of "special value" must not contain exponent and mantissa`) + } + switch v[0] { + case 0x40: + return math.Inf(1), nil + case 0x41: + return math.Inf(-1), nil + case 0x42: + return math.NaN(), nil + case 0x43: + return math.Copysign(0, -1), nil + } + return 0.0, errors.New(`encoding of "special value" not from ASN.1 standard`) +} diff --git a/vendor/gopkg.in/asn1-ber.v1/util.go b/vendor/github.com/go-asn1-ber/asn1-ber/util.go similarity index 73% rename from vendor/gopkg.in/asn1-ber.v1/util.go rename to vendor/github.com/go-asn1-ber/asn1-ber/util.go index 3e56b66c8c..da45e9fa55 100644 --- a/vendor/gopkg.in/asn1-ber.v1/util.go +++ b/vendor/github.com/go-asn1-ber/asn1-ber/util.go @@ -3,17 +3,21 @@ package ber import "io" func readByte(reader io.Reader) (byte, error) { - bytes := make([]byte, 1, 1) + bytes := make([]byte, 1) _, err := io.ReadFull(reader, bytes) if err != nil { - if err == io.EOF { - return 0, io.ErrUnexpectedEOF - } return 0, err } return bytes[0], nil } +func unexpectedEOF(err error) error { + if err == io.EOF { + return io.ErrUnexpectedEOF + } + return err +} + func isEOCPacket(p *Packet) bool { return p != nil && p.Tag == TagEOC && diff --git a/vendor/gopkg.in/ldap.v3/LICENSE b/vendor/github.com/go-ldap/ldap/v3/LICENSE similarity index 100% rename from vendor/gopkg.in/ldap.v3/LICENSE rename to vendor/github.com/go-ldap/ldap/v3/LICENSE diff --git a/vendor/gopkg.in/ldap.v3/add.go b/vendor/github.com/go-ldap/ldap/v3/add.go similarity index 53% rename from vendor/gopkg.in/ldap.v3/add.go rename to vendor/github.com/go-ldap/ldap/v3/add.go index 19bce1b75b..baecd787d2 100644 --- a/vendor/gopkg.in/ldap.v3/add.go +++ b/vendor/github.com/go-ldap/ldap/v3/add.go @@ -1,19 +1,9 @@ -// -// https://tools.ietf.org/html/rfc4511 -// -// AddRequest ::= [APPLICATION 8] SEQUENCE { -// entry LDAPDN, -// attributes AttributeList } -// -// AttributeList ::= SEQUENCE OF attribute Attribute - package ldap import ( - "errors" "log" - "gopkg.in/asn1-ber.v1" + ber "github.com/go-asn1-ber/asn1-ber" ) // Attribute represents an LDAP attribute @@ -45,20 +35,26 @@ type AddRequest struct { Controls []Control } -func (a AddRequest) encode() *ber.Packet { - request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationAddRequest, nil, "Add Request") - request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.DN, "DN")) +func (req *AddRequest) appendTo(envelope *ber.Packet) error { + pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationAddRequest, nil, "Add Request") + pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.DN, "DN")) attributes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes") - for _, attribute := range a.Attributes { + for _, attribute := range req.Attributes { attributes.AppendChild(attribute.encode()) } - request.AppendChild(attributes) - return request + pkt.AppendChild(attributes) + + envelope.AppendChild(pkt) + if len(req.Controls) > 0 { + envelope.AppendChild(encodeControls(req.Controls)) + } + + return nil } // Attribute adds an attribute with the given type and values -func (a *AddRequest) Attribute(attrType string, attrVals []string) { - a.Attributes = append(a.Attributes, Attribute{Type: attrType, Vals: attrVals}) +func (req *AddRequest) Attribute(attrType string, attrVals []string) { + req.Attributes = append(req.Attributes, Attribute{Type: attrType, Vals: attrVals}) } // NewAddRequest returns an AddRequest for the given DN, with no attributes @@ -72,39 +68,17 @@ func NewAddRequest(dn string, controls []Control) *AddRequest { // Add performs the given AddRequest func (l *Conn) Add(addRequest *AddRequest) error { - packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) - packet.AppendChild(addRequest.encode()) - if len(addRequest.Controls) > 0 { - packet.AppendChild(encodeControls(addRequest.Controls)) - } - - l.Debug.PrintPacket(packet) - - msgCtx, err := l.sendMessage(packet) + msgCtx, err := l.doRequest(addRequest) if err != nil { return err } defer l.finishMessage(msgCtx) - l.Debug.Printf("%d: waiting for response", msgCtx.id) - packetResponse, ok := <-msgCtx.responses - if !ok { - return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) - } - packet, err = packetResponse.ReadPacket() - l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + packet, err := l.readPacket(msgCtx) if err != nil { return err } - if l.Debug { - if err := addLDAPDescriptions(packet); err != nil { - return err - } - ber.PrintPacket(packet) - } - if packet.Children[1].Tag == ApplicationAddResponse { err := GetLDAPError(packet) if err != nil { @@ -113,7 +87,5 @@ func (l *Conn) Add(addRequest *AddRequest) error { } else { log.Printf("Unexpected Response: %d", packet.Children[1].Tag) } - - l.Debug.Printf("%d: returning", msgCtx.id) return nil } diff --git a/vendor/gopkg.in/ldap.v3/bind.go b/vendor/github.com/go-ldap/ldap/v3/bind.go similarity index 59% rename from vendor/gopkg.in/ldap.v3/bind.go rename to vendor/github.com/go-ldap/ldap/v3/bind.go index 59c3f5ef59..15307f50bb 100644 --- a/vendor/gopkg.in/ldap.v3/bind.go +++ b/vendor/github.com/go-ldap/ldap/v3/bind.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - "gopkg.in/asn1-ber.v1" + ber "github.com/go-asn1-ber/asn1-ber" ) // SimpleBindRequest represents a username/password bind operation @@ -35,13 +35,18 @@ func NewSimpleBindRequest(username string, password string, controls []Control) } } -func (bindRequest *SimpleBindRequest) encode() *ber.Packet { - request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request") - request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version")) - request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, bindRequest.Username, "User Name")) - request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, bindRequest.Password, "Password")) +func (req *SimpleBindRequest) appendTo(envelope *ber.Packet) error { + pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request") + pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version")) + pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.Username, "User Name")) + pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, req.Password, "Password")) - return request + envelope.AppendChild(pkt) + if len(req.Controls) > 0 { + envelope.AppendChild(encodeControls(req.Controls)) + } + + return nil } // SimpleBind performs the simple bind operation defined in the given request @@ -50,41 +55,17 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client")) } - packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) - encodedBindRequest := simpleBindRequest.encode() - packet.AppendChild(encodedBindRequest) - if len(simpleBindRequest.Controls) > 0 { - packet.AppendChild(encodeControls(simpleBindRequest.Controls)) - } - - if l.Debug { - ber.PrintPacket(packet) - } - - msgCtx, err := l.sendMessage(packet) + msgCtx, err := l.doRequest(simpleBindRequest) if err != nil { return nil, err } defer l.finishMessage(msgCtx) - packetResponse, ok := <-msgCtx.responses - if !ok { - return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) - } - packet, err = packetResponse.ReadPacket() - l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + packet, err := l.readPacket(msgCtx) if err != nil { return nil, err } - if l.Debug { - if err = addLDAPDescriptions(packet); err != nil { - return nil, err - } - ber.PrintPacket(packet) - } - result := &SimpleBindResult{ Controls: make([]Control, 0), } @@ -133,3 +114,39 @@ func (l *Conn) UnauthenticatedBind(username string) error { _, err := l.SimpleBind(req) return err } + +var externalBindRequest = requestFunc(func(envelope *ber.Packet) error { + pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request") + pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version")) + pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "User Name")) + + saslAuth := ber.Encode(ber.ClassContext, ber.TypeConstructed, 3, "", "authentication") + saslAuth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "EXTERNAL", "SASL Mech")) + saslAuth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "SASL Cred")) + + pkt.AppendChild(saslAuth) + + envelope.AppendChild(pkt) + + return nil +}) + +// ExternalBind performs SASL/EXTERNAL authentication. +// +// Use ldap.DialURL("ldapi://") to connect to the Unix socket before ExternalBind. +// +// See https://tools.ietf.org/html/rfc4422#appendix-A +func (l *Conn) ExternalBind() error { + msgCtx, err := l.doRequest(externalBindRequest) + if err != nil { + return err + } + defer l.finishMessage(msgCtx) + + packet, err := l.readPacket(msgCtx) + if err != nil { + return err + } + + return GetLDAPError(packet) +} diff --git a/vendor/github.com/go-ldap/ldap/v3/client.go b/vendor/github.com/go-ldap/ldap/v3/client.go new file mode 100644 index 0000000000..619677c779 --- /dev/null +++ b/vendor/github.com/go-ldap/ldap/v3/client.go @@ -0,0 +1,30 @@ +package ldap + +import ( + "crypto/tls" + "time" +) + +// Client knows how to interact with an LDAP server +type Client interface { + Start() + StartTLS(*tls.Config) error + Close() + SetTimeout(time.Duration) + + Bind(username, password string) error + UnauthenticatedBind(username string) error + SimpleBind(*SimpleBindRequest) (*SimpleBindResult, error) + ExternalBind() error + + Add(*AddRequest) error + Del(*DelRequest) error + Modify(*ModifyRequest) error + ModifyDN(*ModifyDNRequest) error + + Compare(dn, attribute, value string) (bool, error) + PasswordModify(*PasswordModifyRequest) (*PasswordModifyResult, error) + + Search(*SearchRequest) (*SearchResult, error) + SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) +} diff --git a/vendor/github.com/go-ldap/ldap/v3/compare.go b/vendor/github.com/go-ldap/ldap/v3/compare.go new file mode 100644 index 0000000000..cd43e4c53d --- /dev/null +++ b/vendor/github.com/go-ldap/ldap/v3/compare.go @@ -0,0 +1,61 @@ +package ldap + +import ( + "fmt" + + ber "github.com/go-asn1-ber/asn1-ber" +) + +// CompareRequest represents an LDAP CompareRequest operation. +type CompareRequest struct { + DN string + Attribute string + Value string +} + +func (req *CompareRequest) appendTo(envelope *ber.Packet) error { + pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationCompareRequest, nil, "Compare Request") + pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.DN, "DN")) + + ava := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "AttributeValueAssertion") + ava.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.Attribute, "AttributeDesc")) + ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.Value, "AssertionValue")) + + pkt.AppendChild(ava) + + envelope.AppendChild(pkt) + + return nil +} + +// Compare checks to see if the attribute of the dn matches value. Returns true if it does otherwise +// false with any error that occurs if any. +func (l *Conn) Compare(dn, attribute, value string) (bool, error) { + msgCtx, err := l.doRequest(&CompareRequest{ + DN: dn, + Attribute: attribute, + Value: value}) + if err != nil { + return false, err + } + defer l.finishMessage(msgCtx) + + packet, err := l.readPacket(msgCtx) + if err != nil { + return false, err + } + + if packet.Children[1].Tag == ApplicationCompareResponse { + err := GetLDAPError(packet) + + switch { + case IsErrorWithCode(err, LDAPResultCompareTrue): + return true, nil + case IsErrorWithCode(err, LDAPResultCompareFalse): + return false, nil + default: + return false, err + } + } + return false, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag) +} diff --git a/vendor/gopkg.in/ldap.v3/conn.go b/vendor/github.com/go-ldap/ldap/v3/conn.go similarity index 87% rename from vendor/gopkg.in/ldap.v3/conn.go rename to vendor/github.com/go-ldap/ldap/v3/conn.go index c20471fc20..b09b7aa0bc 100644 --- a/vendor/gopkg.in/ldap.v3/conn.go +++ b/vendor/github.com/go-ldap/ldap/v3/conn.go @@ -11,7 +11,7 @@ import ( "sync/atomic" "time" - "gopkg.in/asn1-ber.v1" + ber "github.com/go-asn1-ber/asn1-ber" ) const ( @@ -112,8 +112,63 @@ var _ Client = &Conn{} // multiple places will probably result in undesired behaviour. var DefaultTimeout = 60 * time.Second +// DialOpt configures DialContext. +type DialOpt func(*DialContext) + +// DialWithDialer updates net.Dialer in DialContext. +func DialWithDialer(d *net.Dialer) DialOpt { + return func(dc *DialContext) { + dc.d = d + } +} + +// DialWithTLSConfig updates tls.Config in DialContext. +func DialWithTLSConfig(tc *tls.Config) DialOpt { + return func(dc *DialContext) { + dc.tc = tc + } +} + +// DialContext contains necessary parameters to dial the given ldap URL. +type DialContext struct { + d *net.Dialer + tc *tls.Config +} + +func (dc *DialContext) dial(u *url.URL) (net.Conn, error) { + if u.Scheme == "ldapi" { + if u.Path == "" || u.Path == "/" { + u.Path = "/var/run/slapd/ldapi" + } + return dc.d.Dial("unix", u.Path) + } + + host, port, err := net.SplitHostPort(u.Host) + if err != nil { + // we asume that error is due to missing port + host = u.Host + port = "" + } + + switch u.Scheme { + case "ldap": + if port == "" { + port = DefaultLdapPort + } + return dc.d.Dial("tcp", net.JoinHostPort(host, port)) + case "ldaps": + if port == "" { + port = DefaultLdapsPort + } + return tls.DialWithDialer(dc.d, "tcp", net.JoinHostPort(host, port), dc.tc) + } + + return nil, fmt.Errorf("Unknown scheme '%s'", u.Scheme) +} + // Dial connects to the given address on the given network using net.Dial // and then returns a new Conn for the connection. +// @deprecated Use DialURL instead. func Dial(network, addr string) (*Conn, error) { c, err := net.DialTimeout(network, addr, DefaultTimeout) if err != nil { @@ -126,6 +181,7 @@ func Dial(network, addr string) (*Conn, error) { // DialTLS connects to the given address on the given network using tls.Dial // and then returns a new Conn for the connection. +// @deprecated Use DialURL instead. func DialTLS(network, addr string, config *tls.Config) (*Conn, error) { c, err := tls.DialWithDialer(&net.Dialer{Timeout: DefaultTimeout}, network, addr, config) if err != nil { @@ -136,40 +192,31 @@ func DialTLS(network, addr string, config *tls.Config) (*Conn, error) { return conn, nil } -// DialURL connects to the given ldap URL vie TCP using tls.Dial or net.Dial if ldaps:// -// or ldap:// specified as protocol. On success a new Conn for the connection -// is returned. -func DialURL(addr string) (*Conn, error) { - - lurl, err := url.Parse(addr) +// DialURL connects to the given ldap URL. +// The following schemas are supported: ldap://, ldaps://, ldapi://. +// On success a new Conn for the connection is returned. +func DialURL(addr string, opts ...DialOpt) (*Conn, error) { + u, err := url.Parse(addr) if err != nil { return nil, NewError(ErrorNetwork, err) } - host, port, err := net.SplitHostPort(lurl.Host) + var dc DialContext + for _, opt := range opts { + opt(&dc) + } + if dc.d == nil { + dc.d = &net.Dialer{Timeout: DefaultTimeout} + } + + c, err := dc.dial(u) if err != nil { - // we asume that error is due to missing port - host = lurl.Host - port = "" + return nil, NewError(ErrorNetwork, err) } - switch lurl.Scheme { - case "ldap": - if port == "" { - port = DefaultLdapPort - } - return Dial("tcp", net.JoinHostPort(host, port)) - case "ldaps": - if port == "" { - port = DefaultLdapsPort - } - tlsConf := &tls.Config{ - ServerName: host, - } - return DialTLS("tcp", net.JoinHostPort(host, port), tlsConf) - } - - return nil, NewError(ErrorNetwork, fmt.Errorf("Unknown scheme '%s'", lurl.Scheme)) + conn := NewConn(c, u.Scheme == "ldaps") + conn.Start() + return conn, nil } // NewConn returns a new Conn using conn for network I/O. @@ -187,9 +234,9 @@ func NewConn(conn net.Conn, isTLS bool) *Conn { // Start initializes goroutines to read responses and process messages func (l *Conn) Start() { + l.wgClose.Add(1) go l.reader() go l.processMessages() - l.wgClose.Add(1) } // IsClosing returns whether or not we're currently closing. @@ -274,7 +321,7 @@ func (l *Conn) StartTLS(config *tls.Config) error { l.Close() return err } - ber.PrintPacket(packet) + l.Debug.PrintPacket(packet) } if err := GetLDAPError(packet); err == nil { @@ -447,7 +494,7 @@ func (l *Conn) processMessages() { msgCtx.sendResponse(&PacketResponse{message.Packet, nil}) } else { log.Printf("Received unexpected message %d, %v", message.MessageID, l.IsClosing()) - ber.PrintPacket(message.Packet) + l.Debug.PrintPacket(message.Packet) } case MessageTimeout: // Handle the timeout by closing the channel @@ -490,11 +537,13 @@ func (l *Conn) reader() { // A read error is expected here if we are closing the connection... if !l.IsClosing() { l.closeErr.Store(fmt.Errorf("unable to read LDAP response packet: %s", err)) - l.Debug.Printf("reader error: %s", err.Error()) + l.Debug.Printf("reader error: %s", err) } return } - addLDAPDescriptions(packet) + if err := addLDAPDescriptions(packet); err != nil { + l.Debug.Printf("descriptions error: %s", err) + } if len(packet.Children) == 0 { l.Debug.Printf("Received bad ldap packet") continue diff --git a/vendor/gopkg.in/ldap.v3/control.go b/vendor/github.com/go-ldap/ldap/v3/control.go similarity index 99% rename from vendor/gopkg.in/ldap.v3/control.go rename to vendor/github.com/go-ldap/ldap/v3/control.go index 3f1819128f..463fe3a324 100644 --- a/vendor/gopkg.in/ldap.v3/control.go +++ b/vendor/github.com/go-ldap/ldap/v3/control.go @@ -4,7 +4,7 @@ import ( "fmt" "strconv" - "gopkg.in/asn1-ber.v1" + "github.com/go-asn1-ber/asn1-ber" ) const ( diff --git a/vendor/gopkg.in/ldap.v3/debug.go b/vendor/github.com/go-ldap/ldap/v3/debug.go similarity index 62% rename from vendor/gopkg.in/ldap.v3/debug.go rename to vendor/github.com/go-ldap/ldap/v3/debug.go index 7279fc2518..2c0b30c8d0 100644 --- a/vendor/gopkg.in/ldap.v3/debug.go +++ b/vendor/github.com/go-ldap/ldap/v3/debug.go @@ -3,20 +3,26 @@ package ldap import ( "log" - "gopkg.in/asn1-ber.v1" + ber "github.com/go-asn1-ber/asn1-ber" ) // debugging type // - has a Printf method to write the debug output type debugging bool -// write debug output +// Enable controls debugging mode. +func (debug *debugging) Enable(b bool) { + *debug = debugging(b) +} + +// Printf writes debug output. func (debug debugging) Printf(format string, args ...interface{}) { if debug { log.Printf(format, args...) } } +// PrintPacket dumps a packet. func (debug debugging) PrintPacket(packet *ber.Packet) { if debug { ber.PrintPacket(packet) diff --git a/vendor/github.com/go-ldap/ldap/v3/del.go b/vendor/github.com/go-ldap/ldap/v3/del.go new file mode 100644 index 0000000000..6e98726775 --- /dev/null +++ b/vendor/github.com/go-ldap/ldap/v3/del.go @@ -0,0 +1,59 @@ +package ldap + +import ( + "log" + + ber "github.com/go-asn1-ber/asn1-ber" +) + +// DelRequest implements an LDAP deletion request +type DelRequest struct { + // DN is the name of the directory entry to delete + DN string + // Controls hold optional controls to send with the request + Controls []Control +} + +func (req *DelRequest) appendTo(envelope *ber.Packet) error { + pkt := ber.Encode(ber.ClassApplication, ber.TypePrimitive, ApplicationDelRequest, req.DN, "Del Request") + pkt.Data.Write([]byte(req.DN)) + + envelope.AppendChild(pkt) + if len(req.Controls) > 0 { + envelope.AppendChild(encodeControls(req.Controls)) + } + + return nil +} + +// NewDelRequest creates a delete request for the given DN and controls +func NewDelRequest(DN string, Controls []Control) *DelRequest { + return &DelRequest{ + DN: DN, + Controls: Controls, + } +} + +// Del executes the given delete request +func (l *Conn) Del(delRequest *DelRequest) error { + msgCtx, err := l.doRequest(delRequest) + if err != nil { + return err + } + defer l.finishMessage(msgCtx) + + packet, err := l.readPacket(msgCtx) + if err != nil { + return err + } + + if packet.Children[1].Tag == ApplicationDelResponse { + err := GetLDAPError(packet) + if err != nil { + return err + } + } else { + log.Printf("Unexpected Response: %d", packet.Children[1].Tag) + } + return nil +} diff --git a/vendor/gopkg.in/ldap.v3/dn.go b/vendor/github.com/go-ldap/ldap/v3/dn.go similarity index 79% rename from vendor/gopkg.in/ldap.v3/dn.go rename to vendor/github.com/go-ldap/ldap/v3/dn.go index f89e73a9a6..bff137cc85 100644 --- a/vendor/gopkg.in/ldap.v3/dn.go +++ b/vendor/github.com/go-ldap/ldap/v3/dn.go @@ -1,44 +1,3 @@ -// File contains DN parsing functionality -// -// https://tools.ietf.org/html/rfc4514 -// -// distinguishedName = [ relativeDistinguishedName -// *( COMMA relativeDistinguishedName ) ] -// relativeDistinguishedName = attributeTypeAndValue -// *( PLUS attributeTypeAndValue ) -// attributeTypeAndValue = attributeType EQUALS attributeValue -// attributeType = descr / numericoid -// attributeValue = string / hexstring -// -// ; The following characters are to be escaped when they appear -// ; in the value to be encoded: ESC, one of , leading -// ; SHARP or SPACE, trailing SPACE, and NULL. -// string = [ ( leadchar / pair ) [ *( stringchar / pair ) -// ( trailchar / pair ) ] ] -// -// leadchar = LUTF1 / UTFMB -// LUTF1 = %x01-1F / %x21 / %x24-2A / %x2D-3A / -// %x3D / %x3F-5B / %x5D-7F -// -// trailchar = TUTF1 / UTFMB -// TUTF1 = %x01-1F / %x21 / %x23-2A / %x2D-3A / -// %x3D / %x3F-5B / %x5D-7F -// -// stringchar = SUTF1 / UTFMB -// SUTF1 = %x01-21 / %x23-2A / %x2D-3A / -// %x3D / %x3F-5B / %x5D-7F -// -// pair = ESC ( ESC / special / hexpair ) -// special = escaped / SPACE / SHARP / EQUALS -// escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE -// hexstring = SHARP 1*hexpair -// hexpair = HEX HEX -// -// where the productions , , , , -// , , , , , , , , -// , , and are defined in [RFC4512]. -// - package ldap import ( @@ -48,7 +7,7 @@ import ( "fmt" "strings" - "gopkg.in/asn1-ber.v1" + ber "github.com/go-asn1-ber/asn1-ber" ) // AttributeTypeAndValue represents an attributeTypeAndValue from https://tools.ietf.org/html/rfc4514 @@ -69,7 +28,8 @@ type DN struct { RDNs []*RelativeDN } -// ParseDN returns a distinguishedName or an error +// ParseDN returns a distinguishedName or an error. +// The function respects https://tools.ietf.org/html/rfc4514 func ParseDN(str string) (*DN, error) { dn := new(DN) dn.RDNs = make([]*RelativeDN, 0) diff --git a/vendor/gopkg.in/ldap.v3/doc.go b/vendor/github.com/go-ldap/ldap/v3/doc.go similarity index 100% rename from vendor/gopkg.in/ldap.v3/doc.go rename to vendor/github.com/go-ldap/ldap/v3/doc.go diff --git a/vendor/gopkg.in/ldap.v3/error.go b/vendor/github.com/go-ldap/ldap/v3/error.go similarity index 99% rename from vendor/gopkg.in/ldap.v3/error.go rename to vendor/github.com/go-ldap/ldap/v3/error.go index 639ed8243b..b1fda2d81b 100644 --- a/vendor/gopkg.in/ldap.v3/error.go +++ b/vendor/github.com/go-ldap/ldap/v3/error.go @@ -3,7 +3,7 @@ package ldap import ( "fmt" - "gopkg.in/asn1-ber.v1" + ber "github.com/go-asn1-ber/asn1-ber" ) // LDAP Result Codes @@ -196,7 +196,9 @@ func (e *Error) Error() string { func GetLDAPError(packet *ber.Packet) error { if packet == nil { return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty packet")} - } else if len(packet.Children) >= 2 { + } + + if len(packet.Children) >= 2 { response := packet.Children[1] if response == nil { return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty response in packet")} diff --git a/vendor/gopkg.in/ldap.v3/filter.go b/vendor/github.com/go-ldap/ldap/v3/filter.go similarity index 75% rename from vendor/gopkg.in/ldap.v3/filter.go rename to vendor/github.com/go-ldap/ldap/v3/filter.go index 4cc4207bec..73505e79b6 100644 --- a/vendor/gopkg.in/ldap.v3/filter.go +++ b/vendor/github.com/go-ldap/ldap/v3/filter.go @@ -5,10 +5,12 @@ import ( hexpac "encoding/hex" "errors" "fmt" + "io" "strings" + "unicode" "unicode/utf8" - "gopkg.in/asn1-ber.v1" + ber "github.com/go-asn1-ber/asn1-ber" ) // Filter choices @@ -69,6 +71,8 @@ var MatchingRuleAssertionMap = map[uint64]string{ MatchingRuleAssertionDNAttributes: "Matching Rule Assertion DN Attributes", } +var _SymbolAny = []byte{'*'} + // CompileFilter converts a string representation of a filter into a BER-encoded packet func CompileFilter(filter string) (*ber.Packet, error) { if len(filter) == 0 || filter[0] != '(' { @@ -88,74 +92,75 @@ func CompileFilter(filter string) (*ber.Packet, error) { } // DecompileFilter converts a packet representation of a filter into a string representation -func DecompileFilter(packet *ber.Packet) (ret string, err error) { +func DecompileFilter(packet *ber.Packet) (_ string, err error) { defer func() { if r := recover(); r != nil { err = NewError(ErrorFilterDecompile, errors.New("ldap: error decompiling filter")) } }() - ret = "(" - err = nil + + buf := bytes.NewBuffer(nil) + buf.WriteByte('(') childStr := "" switch packet.Tag { case FilterAnd: - ret += "&" + buf.WriteByte('&') for _, child := range packet.Children { childStr, err = DecompileFilter(child) if err != nil { return } - ret += childStr + buf.WriteString(childStr) } case FilterOr: - ret += "|" + buf.WriteByte('|') for _, child := range packet.Children { childStr, err = DecompileFilter(child) if err != nil { return } - ret += childStr + buf.WriteString(childStr) } case FilterNot: - ret += "!" + buf.WriteByte('!') childStr, err = DecompileFilter(packet.Children[0]) if err != nil { return } - ret += childStr + buf.WriteString(childStr) case FilterSubstrings: - ret += ber.DecodeString(packet.Children[0].Data.Bytes()) - ret += "=" + buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes())) + buf.WriteByte('=') for i, child := range packet.Children[1].Children { if i == 0 && child.Tag != FilterSubstringsInitial { - ret += "*" + buf.Write(_SymbolAny) } - ret += EscapeFilter(ber.DecodeString(child.Data.Bytes())) + buf.WriteString(EscapeFilter(ber.DecodeString(child.Data.Bytes()))) if child.Tag != FilterSubstringsFinal { - ret += "*" + buf.Write(_SymbolAny) } } case FilterEqualityMatch: - ret += ber.DecodeString(packet.Children[0].Data.Bytes()) - ret += "=" - ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) + buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes())) + buf.WriteByte('=') + buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))) case FilterGreaterOrEqual: - ret += ber.DecodeString(packet.Children[0].Data.Bytes()) - ret += ">=" - ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) + buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes())) + buf.WriteString(">=") + buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))) case FilterLessOrEqual: - ret += ber.DecodeString(packet.Children[0].Data.Bytes()) - ret += "<=" - ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) + buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes())) + buf.WriteString("<=") + buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))) case FilterPresent: - ret += ber.DecodeString(packet.Data.Bytes()) - ret += "=*" + buf.WriteString(ber.DecodeString(packet.Data.Bytes())) + buf.WriteString("=*") case FilterApproxMatch: - ret += ber.DecodeString(packet.Children[0].Data.Bytes()) - ret += "~=" - ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) + buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes())) + buf.WriteString("~=") + buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))) case FilterExtensibleMatch: attr := "" dnAttributes := false @@ -176,21 +181,22 @@ func DecompileFilter(packet *ber.Packet) (ret string, err error) { } if len(attr) > 0 { - ret += attr + buf.WriteString(attr) } if dnAttributes { - ret += ":dn" + buf.WriteString(":dn") } if len(matchingRule) > 0 { - ret += ":" - ret += matchingRule + buf.WriteString(":") + buf.WriteString(matchingRule) } - ret += ":=" - ret += EscapeFilter(value) + buf.WriteString(":=") + buf.WriteString(EscapeFilter(value)) } - ret += ")" - return + buf.WriteByte(')') + + return buf.String(), nil } func compileFilterSet(filter string, pos int, parent *ber.Packet) (int, error) { @@ -253,11 +259,10 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { ) state := stateReadingAttr - - attribute := "" + attribute := bytes.NewBuffer(nil) extensibleDNAttributes := false - extensibleMatchingRule := "" - condition := "" + extensibleMatchingRule := bytes.NewBuffer(nil) + condition := bytes.NewBuffer(nil) for newPos < len(filter) { remainingFilter := filter[newPos:] @@ -324,7 +329,7 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { // Still reading the attribute name default: - attribute += fmt.Sprintf("%c", currentRune) + attribute.WriteRune(currentRune) newPos += currentWidth } @@ -338,13 +343,13 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { // Still reading the matching rule oid default: - extensibleMatchingRule += fmt.Sprintf("%c", currentRune) + extensibleMatchingRule.WriteRune(currentRune) newPos += currentWidth } case stateReadingCondition: // append to the condition - condition += fmt.Sprintf("%c", currentRune) + condition.WriteRune(currentRune) newPos += currentWidth } } @@ -368,17 +373,17 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { // } // Include the matching rule oid, if specified - if len(extensibleMatchingRule) > 0 { - packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchingRule, extensibleMatchingRule, MatchingRuleAssertionMap[MatchingRuleAssertionMatchingRule])) + if extensibleMatchingRule.Len() > 0 { + packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchingRule, extensibleMatchingRule.String(), MatchingRuleAssertionMap[MatchingRuleAssertionMatchingRule])) } // Include the attribute, if specified - if len(attribute) > 0 { - packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionType, attribute, MatchingRuleAssertionMap[MatchingRuleAssertionType])) + if attribute.Len() > 0 { + packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionType, attribute.String(), MatchingRuleAssertionMap[MatchingRuleAssertionType])) } // Add the value (only required child) - encodedString, encodeErr := escapedStringToEncodedBytes(condition) + encodedString, encodeErr := decodeEscapedSymbols(condition.Bytes()) if encodeErr != nil { return packet, newPos, encodeErr } @@ -389,16 +394,16 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { packet.AppendChild(ber.NewBoolean(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionDNAttributes, extensibleDNAttributes, MatchingRuleAssertionMap[MatchingRuleAssertionDNAttributes])) } - case packet.Tag == FilterEqualityMatch && condition == "*": - packet = ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterPresent, attribute, FilterMap[FilterPresent]) - case packet.Tag == FilterEqualityMatch && strings.Contains(condition, "*"): - packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute")) + case packet.Tag == FilterEqualityMatch && bytes.Equal(condition.Bytes(), _SymbolAny): + packet = ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterPresent, attribute.String(), FilterMap[FilterPresent]) + case packet.Tag == FilterEqualityMatch && bytes.Index(condition.Bytes(), _SymbolAny) > -1: + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute.String(), "Attribute")) packet.Tag = FilterSubstrings packet.Description = FilterMap[uint64(packet.Tag)] seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings") - parts := strings.Split(condition, "*") + parts := bytes.Split(condition.Bytes(), _SymbolAny) for i, part := range parts { - if part == "" { + if len(part) == 0 { continue } var tag ber.Tag @@ -410,7 +415,7 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { default: tag = FilterSubstringsAny } - encodedString, encodeErr := escapedStringToEncodedBytes(part) + encodedString, encodeErr := decodeEscapedSymbols(part) if encodeErr != nil { return packet, newPos, encodeErr } @@ -418,11 +423,11 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { } packet.AppendChild(seq) default: - encodedString, encodeErr := escapedStringToEncodedBytes(condition) + encodedString, encodeErr := decodeEscapedSymbols(condition.Bytes()) if encodeErr != nil { return packet, newPos, encodeErr } - packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute")) + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute.String(), "Attribute")) packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, encodedString, "Condition")) } @@ -432,34 +437,51 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { } // Convert from "ABC\xx\xx\xx" form to literal bytes for transport -func escapedStringToEncodedBytes(escapedString string) (string, error) { - var buffer bytes.Buffer - i := 0 - for i < len(escapedString) { - currentRune, currentWidth := utf8.DecodeRuneInString(escapedString[i:]) - if currentRune == utf8.RuneError { - return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", i)) +func decodeEscapedSymbols(src []byte) (string, error) { + + var ( + buffer bytes.Buffer + offset int + reader = bytes.NewReader(src) + byteHex []byte + byteVal []byte + ) + + for { + runeVal, runeSize, err := reader.ReadRune() + if err == io.EOF { + return buffer.String(), nil + } else if err != nil { + return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: failed to read filter: %v", err)) + } else if runeVal == unicode.ReplacementChar { + return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", offset)) } - // Check for escaped hex characters and convert them to their literal value for transport. - if currentRune == '\\' { + if runeVal == '\\' { // http://tools.ietf.org/search/rfc4515 // \ (%x5C) is not a valid character unless it is followed by two HEX characters due to not // being a member of UTF1SUBSET. - if i+2 > len(escapedString) { - return "", NewError(ErrorFilterCompile, errors.New("ldap: missing characters for escape in filter")) + if byteHex == nil { + byteHex = make([]byte, 2) + byteVal = make([]byte, 1) } - escByte, decodeErr := hexpac.DecodeString(escapedString[i+1 : i+3]) - if decodeErr != nil { - return "", NewError(ErrorFilterCompile, errors.New("ldap: invalid characters for escape in filter")) + + if _, err := io.ReadFull(reader, byteHex); err != nil { + if err == io.ErrUnexpectedEOF { + return "", NewError(ErrorFilterCompile, errors.New("ldap: missing characters for escape in filter")) + } + return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: invalid characters for escape in filter: %v", err)) } - buffer.WriteByte(escByte[0]) - i += 2 // +1 from end of loop, so 3 total for \xx. + + if _, err := hexpac.Decode(byteVal, byteHex); err != nil { + return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: invalid characters for escape in filter: %v", err)) + } + + buffer.Write(byteVal) } else { - buffer.WriteRune(currentRune) + buffer.WriteRune(runeVal) } - i += currentWidth + offset += runeSize } - return buffer.String(), nil } diff --git a/vendor/gopkg.in/ldap.v3/ldap.go b/vendor/github.com/go-ldap/ldap/v3/ldap.go similarity index 98% rename from vendor/gopkg.in/ldap.v3/ldap.go rename to vendor/github.com/go-ldap/ldap/v3/ldap.go index d7666676fe..b29c018a48 100644 --- a/vendor/gopkg.in/ldap.v3/ldap.go +++ b/vendor/github.com/go-ldap/ldap/v3/ldap.go @@ -1,12 +1,11 @@ package ldap import ( - "errors" "fmt" "io/ioutil" "os" - "gopkg.in/asn1-ber.v1" + ber "github.com/go-asn1-ber/asn1-ber" ) // LDAP Application Codes @@ -87,7 +86,7 @@ var BeheraPasswordPolicyErrorMap = map[int8]string{ 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")) + err = NewError(ErrorDebugging, fmt.Errorf("ldap: cannot process packet to add descriptions: %s", r)) } }() packet.Description = "LDAP Response" @@ -271,6 +270,9 @@ func addRequestDescriptions(packet *ber.Packet) error { func addDefaultLDAPResponseDescriptions(packet *ber.Packet) error { err := GetLDAPError(packet) + if err == nil { + return nil + } packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[err.(*Error).ResultCode] + ")" packet.Children[1].Children[1].Description = "Matched DN (" + err.(*Error).MatchedDN + ")" packet.Children[1].Children[2].Description = "Error Message" diff --git a/vendor/github.com/go-ldap/ldap/v3/moddn.go b/vendor/github.com/go-ldap/ldap/v3/moddn.go new file mode 100644 index 0000000000..380b8cf6ab --- /dev/null +++ b/vendor/github.com/go-ldap/ldap/v3/moddn.go @@ -0,0 +1,75 @@ +package ldap + +import ( + "log" + + ber "github.com/go-asn1-ber/asn1-ber" +) + +// ModifyDNRequest holds the request to modify a DN +type ModifyDNRequest struct { + DN string + NewRDN string + DeleteOldRDN bool + NewSuperior string +} + +// NewModifyDNRequest creates a new request which can be passed to ModifyDN(). +// +// To move an object in the tree, set the "newSup" to the new parent entry DN. Use an +// empty string for just changing the object's RDN. +// +// For moving the object without renaming, the "rdn" must be the first +// RDN of the given DN. +// +// A call like +// mdnReq := NewModifyDNRequest("uid=someone,dc=example,dc=org", "uid=newname", true, "") +// will setup the request to just rename uid=someone,dc=example,dc=org to +// uid=newname,dc=example,dc=org. +func NewModifyDNRequest(dn string, rdn string, delOld bool, newSup string) *ModifyDNRequest { + return &ModifyDNRequest{ + DN: dn, + NewRDN: rdn, + DeleteOldRDN: delOld, + NewSuperior: newSup, + } +} + +func (req *ModifyDNRequest) appendTo(envelope *ber.Packet) error { + pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyDNRequest, nil, "Modify DN Request") + pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.DN, "DN")) + pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.NewRDN, "New RDN")) + pkt.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, req.DeleteOldRDN, "Delete old RDN")) + if req.NewSuperior != "" { + pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, req.NewSuperior, "New Superior")) + } + + envelope.AppendChild(pkt) + + return nil +} + +// ModifyDN renames the given DN and optionally move to another base (when the "newSup" argument +// to NewModifyDNRequest() is not ""). +func (l *Conn) ModifyDN(m *ModifyDNRequest) error { + msgCtx, err := l.doRequest(m) + if err != nil { + return err + } + defer l.finishMessage(msgCtx) + + packet, err := l.readPacket(msgCtx) + if err != nil { + return err + } + + if packet.Children[1].Tag == ApplicationModifyDNResponse { + err := GetLDAPError(packet) + if err != nil { + return err + } + } else { + log.Printf("Unexpected Response: %d", packet.Children[1].Tag) + } + return nil +} diff --git a/vendor/github.com/go-ldap/ldap/v3/modify.go b/vendor/github.com/go-ldap/ldap/v3/modify.go new file mode 100644 index 0000000000..ee712890ad --- /dev/null +++ b/vendor/github.com/go-ldap/ldap/v3/modify.go @@ -0,0 +1,132 @@ +package ldap + +import ( + "log" + + ber "github.com/go-asn1-ber/asn1-ber" +) + +// Change operation choices +const ( + AddAttribute = 0 + DeleteAttribute = 1 + ReplaceAttribute = 2 + IncrementAttribute = 3 // (https://tools.ietf.org/html/rfc4525) +) + +// PartialAttribute for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511 +type PartialAttribute struct { + // Type is the type of the partial attribute + Type string + // Vals are the values of the partial attribute + Vals []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.Type, "Type")) + set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue") + for _, value := range p.Vals { + set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals")) + } + seq.AppendChild(set) + return seq +} + +// Change for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511 +type Change struct { + // Operation is the type of change to be made + Operation uint + // Modification is the attribute to be modified + Modification PartialAttribute +} + +func (c *Change) encode() *ber.Packet { + change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change") + change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(c.Operation), "Operation")) + change.AppendChild(c.Modification.encode()) + return change +} + +// ModifyRequest as defined in https://tools.ietf.org/html/rfc4511 +type ModifyRequest struct { + // DN is the distinguishedName of the directory entry to modify + DN string + // Changes contain the attributes to modify + Changes []Change + // Controls hold optional controls to send with the request + Controls []Control +} + +// Add appends the given attribute to the list of changes to be made +func (req *ModifyRequest) Add(attrType string, attrVals []string) { + req.appendChange(AddAttribute, attrType, attrVals) +} + +// Delete appends the given attribute to the list of changes to be made +func (req *ModifyRequest) Delete(attrType string, attrVals []string) { + req.appendChange(DeleteAttribute, attrType, attrVals) +} + +// Replace appends the given attribute to the list of changes to be made +func (req *ModifyRequest) Replace(attrType string, attrVals []string) { + req.appendChange(ReplaceAttribute, attrType, attrVals) +} + +// Increment appends the given attribute to the list of changes to be made +func (req *ModifyRequest) Increment(attrType string, attrVal string) { + req.appendChange(IncrementAttribute, attrType, []string{attrVal}) +} + +func (req *ModifyRequest) appendChange(operation uint, attrType string, attrVals []string) { + req.Changes = append(req.Changes, Change{operation, PartialAttribute{Type: attrType, Vals: attrVals}}) +} + +func (req *ModifyRequest) appendTo(envelope *ber.Packet) error { + pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request") + pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.DN, "DN")) + changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes") + for _, change := range req.Changes { + changes.AppendChild(change.encode()) + } + pkt.AppendChild(changes) + + envelope.AppendChild(pkt) + if len(req.Controls) > 0 { + envelope.AppendChild(encodeControls(req.Controls)) + } + + return nil +} + +// NewModifyRequest creates a modify request for the given DN +func NewModifyRequest(dn string, controls []Control) *ModifyRequest { + return &ModifyRequest{ + DN: dn, + Controls: controls, + } +} + +// Modify performs the ModifyRequest +func (l *Conn) Modify(modifyRequest *ModifyRequest) error { + msgCtx, err := l.doRequest(modifyRequest) + if err != nil { + return err + } + defer l.finishMessage(msgCtx) + + packet, err := l.readPacket(msgCtx) + if err != nil { + return err + } + + if packet.Children[1].Tag == ApplicationModifyResponse { + err := GetLDAPError(packet) + if err != nil { + return err + } + } else { + log.Printf("Unexpected Response: %d", packet.Children[1].Tag) + } + return nil +} diff --git a/vendor/gopkg.in/ldap.v3/passwdmodify.go b/vendor/github.com/go-ldap/ldap/v3/passwdmodify.go similarity index 67% rename from vendor/gopkg.in/ldap.v3/passwdmodify.go rename to vendor/github.com/go-ldap/ldap/v3/passwdmodify.go index 06bc21db13..62a110843d 100644 --- a/vendor/gopkg.in/ldap.v3/passwdmodify.go +++ b/vendor/github.com/go-ldap/ldap/v3/passwdmodify.go @@ -1,15 +1,9 @@ -// This file contains the password modify extended operation as specified in rfc 3062 -// -// https://tools.ietf.org/html/rfc3062 -// - package ldap import ( - "errors" "fmt" - "gopkg.in/asn1-ber.v1" + ber "github.com/go-asn1-ber/asn1-ber" ) const ( @@ -36,30 +30,33 @@ type PasswordModifyResult struct { Referral string } -func (r *PasswordModifyRequest) encode() (*ber.Packet, error) { - request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Password Modify Extended Operation") - request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, passwordModifyOID, "Extended Request Name: Password Modify OID")) +func (req *PasswordModifyRequest) appendTo(envelope *ber.Packet) error { + pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Password Modify Extended Operation") + pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, passwordModifyOID, "Extended Request Name: Password Modify OID")) + extendedRequestValue := ber.Encode(ber.ClassContext, ber.TypePrimitive, 1, nil, "Extended Request Value: Password Modify Request") passwordModifyRequestValue := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Password Modify Request") - if r.UserIdentity != "" { - passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, r.UserIdentity, "User Identity")) + if req.UserIdentity != "" { + passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, req.UserIdentity, "User Identity")) } - if r.OldPassword != "" { - passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 1, r.OldPassword, "Old Password")) + if req.OldPassword != "" { + passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 1, req.OldPassword, "Old Password")) } - if r.NewPassword != "" { - passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 2, r.NewPassword, "New Password")) + if req.NewPassword != "" { + passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 2, req.NewPassword, "New Password")) } - extendedRequestValue.AppendChild(passwordModifyRequestValue) - request.AppendChild(extendedRequestValue) - return request, nil + pkt.AppendChild(extendedRequestValue) + + envelope.AppendChild(pkt) + + return nil } // NewPasswordModifyRequest creates a new PasswordModifyRequest // -// According to the RFC 3602: +// According to the RFC 3602 (https://tools.ietf.org/html/rfc3062): // userIdentity is a string representing the user associated with the request. // This string may or may not be an LDAPDN (RFC 2253). // If userIdentity is empty then the operation will act on the user associated @@ -84,46 +81,18 @@ func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPasswo // PasswordModify performs the modification request func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) { - packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) - - encodedPasswordModifyRequest, err := passwordModifyRequest.encode() - if err != nil { - return nil, err - } - packet.AppendChild(encodedPasswordModifyRequest) - - l.Debug.PrintPacket(packet) - - msgCtx, err := l.sendMessage(packet) + msgCtx, err := l.doRequest(passwordModifyRequest) if err != nil { return nil, err } defer l.finishMessage(msgCtx) - result := &PasswordModifyResult{} - - l.Debug.Printf("%d: waiting for response", msgCtx.id) - packetResponse, ok := <-msgCtx.responses - if !ok { - return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) - } - packet, err = packetResponse.ReadPacket() - l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + packet, err := l.readPacket(msgCtx) if err != nil { return nil, err } - 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) - } + result := &PasswordModifyResult{} if packet.Children[1].Tag == ApplicationExtendedResponse { err := GetLDAPError(packet) diff --git a/vendor/github.com/go-ldap/ldap/v3/request.go b/vendor/github.com/go-ldap/ldap/v3/request.go new file mode 100644 index 0000000000..8c68f34aaf --- /dev/null +++ b/vendor/github.com/go-ldap/ldap/v3/request.go @@ -0,0 +1,66 @@ +package ldap + +import ( + "errors" + + ber "github.com/go-asn1-ber/asn1-ber" +) + +var ( + errRespChanClosed = errors.New("ldap: response channel closed") + errCouldNotRetMsg = errors.New("ldap: could not retrieve message") +) + +type request interface { + appendTo(*ber.Packet) error +} + +type requestFunc func(*ber.Packet) error + +func (f requestFunc) appendTo(p *ber.Packet) error { + return f(p) +} + +func (l *Conn) doRequest(req request) (*messageContext, error) { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) + if err := req.appendTo(packet); err != nil { + return nil, err + } + + if l.Debug { + l.Debug.PrintPacket(packet) + } + + msgCtx, err := l.sendMessage(packet) + if err != nil { + return nil, err + } + l.Debug.Printf("%d: returning", msgCtx.id) + return msgCtx, nil +} + +func (l *Conn) readPacket(msgCtx *messageContext) (*ber.Packet, error) { + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return nil, NewError(ErrorNetwork, errRespChanClosed) + } + packet, err := packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return nil, err + } + + if packet == nil { + return nil, NewError(ErrorNetwork, errCouldNotRetMsg) + } + + if l.Debug { + if err = addLDAPDescriptions(packet); err != nil { + return nil, err + } + l.Debug.PrintPacket(packet) + } + return packet, nil +} diff --git a/vendor/gopkg.in/ldap.v3/search.go b/vendor/github.com/go-ldap/ldap/v3/search.go similarity index 68% rename from vendor/gopkg.in/ldap.v3/search.go rename to vendor/github.com/go-ldap/ldap/v3/search.go index 3aa6dac0c2..9a5c2c86bb 100644 --- a/vendor/gopkg.in/ldap.v3/search.go +++ b/vendor/github.com/go-ldap/ldap/v3/search.go @@ -1,58 +1,3 @@ -// 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 -// -- 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 ( @@ -61,7 +6,7 @@ import ( "sort" "strings" - "gopkg.in/asn1-ber.v1" + ber "github.com/go-asn1-ber/asn1-ber" ) // scope choices @@ -246,27 +191,33 @@ type SearchRequest struct { 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")) +func (req *SearchRequest) appendTo(envelope *ber.Packet) error { + pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request") + pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.BaseDN, "Base DN")) + pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(req.Scope), "Scope")) + pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(req.DerefAliases), "Deref Aliases")) + pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(req.SizeLimit), "Size Limit")) + pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(req.TimeLimit), "Time Limit")) + pkt.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, req.TypesOnly, "Types Only")) // compile and encode filter - filterPacket, err := CompileFilter(s.Filter) + filterPacket, err := CompileFilter(req.Filter) if err != nil { - return nil, err + return err } - request.AppendChild(filterPacket) + pkt.AppendChild(filterPacket) // encode attributes attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes") - for _, attribute := range s.Attributes { + for _, attribute := range req.Attributes { attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute")) } - request.AppendChild(attributesPacket) - return request, nil + pkt.AppendChild(attributesPacket) + + envelope.AppendChild(pkt) + if len(req.Controls) > 0 { + envelope.AppendChild(encodeControls(req.Controls)) + } + + return nil } // NewSearchRequest creates a new search request @@ -366,22 +317,7 @@ func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) // Search performs the given search request func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) { - packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) - // encode search request - encodedSearchRequest, err := searchRequest.encode() - if err != nil { - return nil, err - } - packet.AppendChild(encodedSearchRequest) - // encode search controls - if len(searchRequest.Controls) > 0 { - packet.AppendChild(encodeControls(searchRequest.Controls)) - } - - l.Debug.PrintPacket(packet) - - msgCtx, err := l.sendMessage(packet) + msgCtx, err := l.doRequest(searchRequest) if err != nil { return nil, err } @@ -392,26 +328,12 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) { Referrals: make([]string, 0), Controls: make([]Control, 0)} - foundSearchResultDone := false - for !foundSearchResultDone { - l.Debug.Printf("%d: waiting for response", msgCtx.id) - packetResponse, ok := <-msgCtx.responses - if !ok { - return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) - } - packet, err = packetResponse.ReadPacket() - l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + for { + packet, err := l.readPacket(msgCtx) if err != nil { return nil, err } - 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) @@ -440,11 +362,9 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) { result.Controls = append(result.Controls, decodedChild) } } - foundSearchResultDone = true + return result, nil case 19: result.Referrals = append(result.Referrals, packet.Children[1].Children[0].Value.(string)) } } - l.Debug.Printf("%d: returning", msgCtx.id) - return result, nil } diff --git a/vendor/gopkg.in/asn1-ber.v1/.travis.yml b/vendor/gopkg.in/asn1-ber.v1/.travis.yml deleted file mode 100644 index ecf413251b..0000000000 --- a/vendor/gopkg.in/asn1-ber.v1/.travis.yml +++ /dev/null @@ -1,36 +0,0 @@ -language: go -matrix: - include: - - go: 1.2.x - env: GOOS=linux GOARCH=amd64 - - go: 1.2.x - env: GOOS=linux GOARCH=386 - - go: 1.2.x - env: GOOS=windows GOARCH=amd64 - - go: 1.2.x - env: GOOS=windows GOARCH=386 - - go: 1.3.x - - go: 1.4.x - - go: 1.5.x - - go: 1.6.x - - go: 1.7.x - - go: 1.8.x - - go: 1.9.x - - go: 1.10.x - - go: 1.11.x - env: GOOS=linux GOARCH=amd64 - - go: 1.11.x - env: GOOS=linux GOARCH=386 - - go: 1.11.x - env: GOOS=windows GOARCH=amd64 - - go: 1.11.x - env: GOOS=windows GOARCH=386 - - go: tip -go_import_path: gopkg.in/asn-ber.v1 -install: - - go list -f '{{range .Imports}}{{.}} {{end}}' ./... | xargs go get -v - - go list -f '{{range .TestImports}}{{.}} {{end}}' ./... | xargs go get -v - - go get code.google.com/p/go.tools/cmd/cover || go get golang.org/x/tools/cmd/cover - - go build -v ./... -script: - - go test -v -cover ./... || go test -v ./... diff --git a/vendor/gopkg.in/asn1-ber.v1/ber.go b/vendor/gopkg.in/asn1-ber.v1/ber.go deleted file mode 100644 index 6153f46068..0000000000 --- a/vendor/gopkg.in/asn1-ber.v1/ber.go +++ /dev/null @@ -1,512 +0,0 @@ -package ber - -import ( - "bytes" - "errors" - "fmt" - "io" - "math" - "os" - "reflect" -) - -// MaxPacketLengthBytes specifies the maximum allowed packet size when calling ReadPacket or DecodePacket. Set to 0 for -// no limit. -var MaxPacketLengthBytes int64 = math.MaxInt32 - -type Packet struct { - Identifier - Value interface{} - ByteValue []byte - Data *bytes.Buffer - Children []*Packet - Description string -} - -type Identifier struct { - ClassType Class - TagType Type - Tag Tag -} - -type Tag uint64 - -const ( - TagEOC Tag = 0x00 - TagBoolean Tag = 0x01 - TagInteger Tag = 0x02 - TagBitString Tag = 0x03 - TagOctetString Tag = 0x04 - TagNULL Tag = 0x05 - TagObjectIdentifier Tag = 0x06 - TagObjectDescriptor Tag = 0x07 - TagExternal Tag = 0x08 - TagRealFloat Tag = 0x09 - TagEnumerated Tag = 0x0a - TagEmbeddedPDV Tag = 0x0b - TagUTF8String Tag = 0x0c - TagRelativeOID Tag = 0x0d - TagSequence Tag = 0x10 - TagSet Tag = 0x11 - TagNumericString Tag = 0x12 - TagPrintableString Tag = 0x13 - TagT61String Tag = 0x14 - TagVideotexString Tag = 0x15 - TagIA5String Tag = 0x16 - TagUTCTime Tag = 0x17 - TagGeneralizedTime Tag = 0x18 - TagGraphicString Tag = 0x19 - TagVisibleString Tag = 0x1a - TagGeneralString Tag = 0x1b - TagUniversalString Tag = 0x1c - TagCharacterString Tag = 0x1d - TagBMPString Tag = 0x1e - TagBitmask Tag = 0x1f // xxx11111b - - // HighTag indicates the start of a high-tag byte sequence - HighTag Tag = 0x1f // xxx11111b - // HighTagContinueBitmask indicates the high-tag byte sequence should continue - HighTagContinueBitmask Tag = 0x80 // 10000000b - // HighTagValueBitmask obtains the tag value from a high-tag byte sequence byte - HighTagValueBitmask Tag = 0x7f // 01111111b -) - -const ( - // LengthLongFormBitmask is the mask to apply to the length byte to see if a long-form byte sequence is used - LengthLongFormBitmask = 0x80 - // LengthValueBitmask is the mask to apply to the length byte to get the number of bytes in the long-form byte sequence - LengthValueBitmask = 0x7f - - // LengthIndefinite is returned from readLength to indicate an indefinite length - LengthIndefinite = -1 -) - -var tagMap = map[Tag]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", -} - -type Class uint8 - -const ( - ClassUniversal Class = 0 // 00xxxxxxb - ClassApplication Class = 64 // 01xxxxxxb - ClassContext Class = 128 // 10xxxxxxb - ClassPrivate Class = 192 // 11xxxxxxb - ClassBitmask Class = 192 // 11xxxxxxb -) - -var ClassMap = map[Class]string{ - ClassUniversal: "Universal", - ClassApplication: "Application", - ClassContext: "Context", - ClassPrivate: "Private", -} - -type Type uint8 - -const ( - TypePrimitive Type = 0 // xx0xxxxxb - TypeConstructed Type = 32 // xx1xxxxxb - TypeBitmask Type = 32 // xx1xxxxxb -) - -var TypeMap = map[Type]string{ - TypePrimitive: "Primitive", - TypeConstructed: "Constructed", -} - -var Debug bool = false - -func PrintBytes(out io.Writer, 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++ { - out.Write([]byte(indent + data_lines[i] + "\n")) - out.Write([]byte(indent + num_lines[i] + "\n\n")) - } -} - -func PrintPacket(p *Packet) { - printPacket(os.Stdout, p, 0, false) -} - -func printPacket(out io.Writer, 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.Fprintf(out, "%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(out, p.Bytes(), indent_str) - } - - for _, child := range p.Children { - printPacket(out, child, indent+1, printBytes) - } -} - -// ReadPacket reads a single Packet from the reader -func ReadPacket(reader io.Reader) (*Packet, error) { - p, _, err := readPacket(reader) - if err != nil { - return nil, err - } - return p, nil -} - -func DecodeString(data []byte) string { - return string(data) -} - -func ParseInt64(bytes []byte) (ret int64, err error) { - if len(bytes) > 8 { - // We'll overflow an int64 in this case. - err = fmt.Errorf("integer too large") - return - } - for bytesRead := 0; bytesRead < len(bytes); bytesRead++ { - ret <<= 8 - ret |= int64(bytes[bytesRead]) - } - - // Shift up and down in order to sign extend the result. - ret <<= 64 - uint8(len(bytes))*8 - ret >>= 64 - uint8(len(bytes))*8 - return -} - -func encodeInteger(i int64) []byte { - n := int64Length(i) - out := make([]byte, n) - - var j int - for ; n > 0; n-- { - out[j] = (byte(i >> uint((n-1)*8))) - j++ - } - - return out -} - -func int64Length(i int64) (numBytes int) { - numBytes = 1 - - for i > 127 { - numBytes++ - i >>= 8 - } - - for i < -128 { - numBytes++ - i >>= 8 - } - - return -} - -// DecodePacket decodes the given bytes into a single Packet -// If a decode error is encountered, nil is returned. -func DecodePacket(data []byte) *Packet { - p, _, _ := readPacket(bytes.NewBuffer(data)) - - return p -} - -// DecodePacketErr decodes the given bytes into a single Packet -// If a decode error is encountered, nil is returned -func DecodePacketErr(data []byte) (*Packet, error) { - p, _, err := readPacket(bytes.NewBuffer(data)) - if err != nil { - return nil, err - } - return p, nil -} - -// readPacket reads a single Packet from the reader, returning the number of bytes read -func readPacket(reader io.Reader) (*Packet, int, error) { - identifier, length, read, err := readHeader(reader) - if err != nil { - return nil, read, err - } - - p := &Packet{ - Identifier: identifier, - } - - p.Data = new(bytes.Buffer) - p.Children = make([]*Packet, 0, 2) - p.Value = nil - - if p.TagType == TypeConstructed { - // TODO: if universal, ensure tag type is allowed to be constructed - - // Track how much content we've read - contentRead := 0 - for { - if length != LengthIndefinite { - // End if we've read what we've been told to - if contentRead == length { - break - } - // Detect if a packet boundary didn't fall on the expected length - if contentRead > length { - return nil, read, fmt.Errorf("expected to read %d bytes, read %d", length, contentRead) - } - } - - // Read the next packet - child, r, err := readPacket(reader) - if err != nil { - return nil, read, err - } - contentRead += r - read += r - - // Test is this is the EOC marker for our packet - if isEOCPacket(child) { - if length == LengthIndefinite { - break - } - return nil, read, errors.New("eoc child not allowed with definite length") - } - - // Append and continue - p.AppendChild(child) - } - return p, read, nil - } - - if length == LengthIndefinite { - return nil, read, errors.New("indefinite length used with primitive type") - } - - // Read definite-length content - if MaxPacketLengthBytes > 0 && int64(length) > MaxPacketLengthBytes { - return nil, read, fmt.Errorf("length %d greater than maximum %d", length, MaxPacketLengthBytes) - } - content := make([]byte, length, length) - if length > 0 { - _, err := io.ReadFull(reader, content) - if err != nil { - if err == io.EOF { - return nil, read, io.ErrUnexpectedEOF - } - return nil, read, err - } - read += length - } - - if p.ClassType == ClassUniversal { - p.Data.Write(content) - p.ByteValue = content - - switch p.Tag { - case TagEOC: - case TagBoolean: - val, _ := ParseInt64(content) - - p.Value = val != 0 - case TagInteger: - p.Value, _ = ParseInt64(content) - case TagBitString: - case TagOctetString: - // the actual string encoding is not known here - // (e.g. for LDAP content is already an UTF8-encoded - // string). Return the data without further processing - p.Value = DecodeString(content) - case TagNULL: - case TagObjectIdentifier: - case TagObjectDescriptor: - case TagExternal: - case TagRealFloat: - case TagEnumerated: - p.Value, _ = ParseInt64(content) - case TagEmbeddedPDV: - case TagUTF8String: - p.Value = DecodeString(content) - case TagRelativeOID: - case TagSequence: - case TagSet: - case TagNumericString: - case TagPrintableString: - p.Value = DecodeString(content) - 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(content) - } - - return p, read, nil -} - -func (p *Packet) Bytes() []byte { - var out bytes.Buffer - - out.Write(encodeIdentifier(p.Identifier)) - out.Write(encodeLength(p.Data.Len())) - out.Write(p.Data.Bytes()) - - return out.Bytes() -} - -func (p *Packet) AppendChild(child *Packet) { - p.Data.Write(child.Bytes()) - p.Children = append(p.Children, child) -} - -func Encode(ClassType Class, TagType Type, Tag Tag, 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, TypeConstructed, TagSequence, nil, Description) -} - -func NewBoolean(ClassType Class, TagType Type, Tag Tag, Value bool, Description string) *Packet { - intValue := int64(0) - - if Value { - intValue = 1 - } - - p := Encode(ClassType, TagType, Tag, nil, Description) - - p.Value = Value - p.Data.Write(encodeInteger(intValue)) - - return p -} - -func NewInteger(ClassType Class, TagType Type, Tag Tag, Value interface{}, Description string) *Packet { - p := Encode(ClassType, TagType, Tag, nil, Description) - - p.Value = Value - switch v := Value.(type) { - case int: - p.Data.Write(encodeInteger(int64(v))) - case uint: - p.Data.Write(encodeInteger(int64(v))) - case int64: - p.Data.Write(encodeInteger(v)) - case uint64: - // TODO : check range or add encodeUInt... - p.Data.Write(encodeInteger(int64(v))) - case int32: - p.Data.Write(encodeInteger(int64(v))) - case uint32: - p.Data.Write(encodeInteger(int64(v))) - case int16: - p.Data.Write(encodeInteger(int64(v))) - case uint16: - p.Data.Write(encodeInteger(int64(v))) - case int8: - p.Data.Write(encodeInteger(int64(v))) - case uint8: - p.Data.Write(encodeInteger(int64(v))) - default: - // TODO : add support for big.Int ? - panic(fmt.Sprintf("Invalid type %T, expected {u|}int{64|32|16|8}", v)) - } - - return p -} - -func NewString(ClassType Class, TagType Type, Tag Tag, Value, Description string) *Packet { - p := Encode(ClassType, TagType, Tag, nil, Description) - - p.Value = Value - p.Data.Write([]byte(Value)) - - return p -} diff --git a/vendor/gopkg.in/ldap.v3/.gitignore b/vendor/gopkg.in/ldap.v3/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/vendor/gopkg.in/ldap.v3/.travis.yml b/vendor/gopkg.in/ldap.v3/.travis.yml deleted file mode 100644 index bb899b2aa1..0000000000 --- a/vendor/gopkg.in/ldap.v3/.travis.yml +++ /dev/null @@ -1,31 +0,0 @@ -sudo: false -language: go -go: - - "1.5.x" - - "1.6.x" - - "1.7.x" - - "1.8.x" - - "1.9.x" - - "1.10.x" - - "1.11.x" - - "1.12.x" - - tip - -git: - depth: 1 - -matrix: - fast_finish: true - allow_failures: - - go: tip -go_import_path: gopkg.in/ldap.v3 -install: - - go get gopkg.in/asn1-ber.v1 - - go get code.google.com/p/go.tools/cmd/cover || go get golang.org/x/tools/cmd/cover - - go get github.com/golang/lint/golint || go get golang.org/x/lint/golint || true - - go build -v ./... -script: - - make test - - make fmt - - make vet - - make lint diff --git a/vendor/gopkg.in/ldap.v3/CONTRIBUTING.md b/vendor/gopkg.in/ldap.v3/CONTRIBUTING.md deleted file mode 100644 index a7885231c7..0000000000 --- a/vendor/gopkg.in/ldap.v3/CONTRIBUTING.md +++ /dev/null @@ -1,12 +0,0 @@ -# Contribution Guidelines - -We welcome contribution and improvements. - -## Guiding Principles - -To begin with here is a draft from an email exchange: - - * take compatibility seriously (our semvers, compatibility with older go versions, etc) - * don't tag untested code for release - * beware of baking in implicit behavior based on other libraries/tools choices - * be as high-fidelity as possible in plumbing through LDAP data (don't mask errors or reduce power of someone using the library) diff --git a/vendor/gopkg.in/ldap.v3/Makefile b/vendor/gopkg.in/ldap.v3/Makefile deleted file mode 100644 index c49664722a..0000000000 --- a/vendor/gopkg.in/ldap.v3/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -.PHONY: default install build test quicktest fmt vet lint - -# List of all release tags "supported" by our current Go version -# E.g. ":go1.1:go1.2:go1.3:go1.4:go1.5:go1.6:go1.7:go1.8:go1.9:go1.10:go1.11:go1.12:" -GO_RELEASE_TAGS := $(shell go list -f ':{{join (context.ReleaseTags) ":"}}:' runtime) - -# Only use the `-race` flag on newer versions of Go (version 1.3 and newer) -ifeq (,$(findstring :go1.3:,$(GO_RELEASE_TAGS))) - RACE_FLAG := -else - RACE_FLAG := -race -cpu 1,2,4 -endif - -# Run `go vet` on Go 1.12 and newer. For Go 1.5-1.11, use `go tool vet` -ifneq (,$(findstring :go1.12:,$(GO_RELEASE_TAGS))) - GO_VET := go vet \ - -atomic \ - -bool \ - -copylocks \ - -nilfunc \ - -printf \ - -rangeloops \ - -unreachable \ - -unsafeptr \ - -unusedresult \ - . -else ifneq (,$(findstring :go1.5:,$(GO_RELEASE_TAGS))) - GO_VET := go tool vet \ - -atomic \ - -bool \ - -copylocks \ - -nilfunc \ - -printf \ - -shadow \ - -rangeloops \ - -unreachable \ - -unsafeptr \ - -unusedresult \ - . -else - GO_VET := @echo "go vet skipped -- not supported on this version of Go" -endif - -default: fmt vet lint build quicktest - -install: - go get -t -v ./... - -build: - go build -v ./... - -test: - go test -v $(RACE_FLAG) -cover ./... - -quicktest: - go test ./... - -# Capture output and force failure when there is non-empty output -fmt: - @echo gofmt -l . - @OUTPUT=`gofmt -l . 2>&1`; \ - if [ "$$OUTPUT" ]; then \ - echo "gofmt must be run on the following files:"; \ - echo "$$OUTPUT"; \ - exit 1; \ - fi - -vet: - $(GO_VET) - -# https://github.com/golang/lint -# go get github.com/golang/lint/golint -# Capture output and force failure when there is non-empty output -# Only run on go1.5+ -lint: - @echo golint ./... - @OUTPUT=`command -v golint >/dev/null 2>&1 && golint ./... 2>&1`; \ - if [ "$$OUTPUT" ]; then \ - echo "golint errors:"; \ - echo "$$OUTPUT"; \ - exit 1; \ - fi diff --git a/vendor/gopkg.in/ldap.v3/README.md b/vendor/gopkg.in/ldap.v3/README.md deleted file mode 100644 index 25cf730b4b..0000000000 --- a/vendor/gopkg.in/ldap.v3/README.md +++ /dev/null @@ -1,54 +0,0 @@ -[![GoDoc](https://godoc.org/gopkg.in/ldap.v3?status.svg)](https://godoc.org/gopkg.in/ldap.v3) -[![Build Status](https://travis-ci.org/go-ldap/ldap.svg)](https://travis-ci.org/go-ldap/ldap) - -# Basic LDAP v3 functionality for the GO programming language. - -## Install - -For the latest version use: - - go get gopkg.in/ldap.v3 - -Import the latest version with: - - import "gopkg.in/ldap.v3" - -## Required Libraries: - - - gopkg.in/asn1-ber.v1 - -## Features: - - - Connecting to LDAP server (non-TLS, TLS, STARTTLS) - - Binding to LDAP server - - Searching for entries - - Filter Compile / Decompile - - Paging Search Results - - Modify Requests / Responses - - Add Requests / Responses - - Delete Requests / Responses - - Modify DN Requests / Responses - -## Examples: - - - search - - modify - -## Contributing: - -Bug reports and pull requests are welcome! - -Before submitting a pull request, please make sure tests and verification scripts pass: -``` -make all -``` - -To set up a pre-push hook to run the tests and verify scripts before pushing: -``` -ln -s ../../.githooks/pre-push .git/hooks/pre-push -``` - ---- -The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/) -The design is licensed under the Creative Commons 3.0 Attributions license. -Read this article for more details: http://blog.golang.org/gopher diff --git a/vendor/gopkg.in/ldap.v3/client.go b/vendor/gopkg.in/ldap.v3/client.go deleted file mode 100644 index c7f41f6f90..0000000000 --- a/vendor/gopkg.in/ldap.v3/client.go +++ /dev/null @@ -1,28 +0,0 @@ -package ldap - -import ( - "crypto/tls" - "time" -) - -// Client knows how to interact with an LDAP server -type Client interface { - Start() - StartTLS(config *tls.Config) error - Close() - SetTimeout(time.Duration) - - Bind(username, password string) error - SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) - - Add(addRequest *AddRequest) error - Del(delRequest *DelRequest) error - Modify(modifyRequest *ModifyRequest) error - ModifyDN(modifyDNRequest *ModifyDNRequest) error - - Compare(dn, attribute, value string) (bool, error) - PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) - - Search(searchRequest *SearchRequest) (*SearchResult, error) - SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) -} diff --git a/vendor/gopkg.in/ldap.v3/compare.go b/vendor/gopkg.in/ldap.v3/compare.go deleted file mode 100644 index 5b5013cbed..0000000000 --- a/vendor/gopkg.in/ldap.v3/compare.go +++ /dev/null @@ -1,83 +0,0 @@ -// File contains Compare functionality -// -// https://tools.ietf.org/html/rfc4511 -// -// CompareRequest ::= [APPLICATION 14] SEQUENCE { -// entry LDAPDN, -// ava AttributeValueAssertion } -// -// AttributeValueAssertion ::= SEQUENCE { -// attributeDesc AttributeDescription, -// assertionValue AssertionValue } -// -// AttributeDescription ::= LDAPString -// -- Constrained to -// -- [RFC4512] -// -// AttributeValue ::= OCTET STRING -// - -package ldap - -import ( - "errors" - "fmt" - - "gopkg.in/asn1-ber.v1" -) - -// Compare checks to see if the attribute of the dn matches value. Returns true if it does otherwise -// false with any error that occurs if any. -func (l *Conn) Compare(dn, attribute, value string) (bool, error) { - packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) - - request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationCompareRequest, nil, "Compare Request") - request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, dn, "DN")) - - ava := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "AttributeValueAssertion") - ava.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "AttributeDesc")) - ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "AssertionValue")) - request.AppendChild(ava) - packet.AppendChild(request) - - l.Debug.PrintPacket(packet) - - msgCtx, err := l.sendMessage(packet) - if err != nil { - return false, err - } - defer l.finishMessage(msgCtx) - - l.Debug.Printf("%d: waiting for response", msgCtx.id) - packetResponse, ok := <-msgCtx.responses - if !ok { - return false, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) - } - packet, err = packetResponse.ReadPacket() - l.Debug.Printf("%d: got response %p", msgCtx.id, packet) - if err != nil { - return false, err - } - - if l.Debug { - if err := addLDAPDescriptions(packet); err != nil { - return false, err - } - ber.PrintPacket(packet) - } - - if packet.Children[1].Tag == ApplicationCompareResponse { - err := GetLDAPError(packet) - - switch { - case IsErrorWithCode(err, LDAPResultCompareTrue): - return true, nil - case IsErrorWithCode(err, LDAPResultCompareFalse): - return false, nil - default: - return false, err - } - } - return false, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag) -} diff --git a/vendor/gopkg.in/ldap.v3/del.go b/vendor/gopkg.in/ldap.v3/del.go deleted file mode 100644 index 6f78beb18e..0000000000 --- a/vendor/gopkg.in/ldap.v3/del.go +++ /dev/null @@ -1,84 +0,0 @@ -// -// https://tools.ietf.org/html/rfc4511 -// -// DelRequest ::= [APPLICATION 10] LDAPDN - -package ldap - -import ( - "errors" - "log" - - "gopkg.in/asn1-ber.v1" -) - -// DelRequest implements an LDAP deletion request -type DelRequest struct { - // DN is the name of the directory entry to delete - DN string - // Controls hold optional controls to send with the request - Controls []Control -} - -func (d DelRequest) encode() *ber.Packet { - request := ber.Encode(ber.ClassApplication, ber.TypePrimitive, ApplicationDelRequest, d.DN, "Del Request") - request.Data.Write([]byte(d.DN)) - return request -} - -// NewDelRequest creates a delete request for the given DN and controls -func NewDelRequest(DN string, - Controls []Control) *DelRequest { - return &DelRequest{ - DN: DN, - Controls: Controls, - } -} - -// Del executes the given delete request -func (l *Conn) Del(delRequest *DelRequest) error { - packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) - packet.AppendChild(delRequest.encode()) - if len(delRequest.Controls) > 0 { - packet.AppendChild(encodeControls(delRequest.Controls)) - } - - l.Debug.PrintPacket(packet) - - msgCtx, err := l.sendMessage(packet) - if err != nil { - return err - } - defer l.finishMessage(msgCtx) - - l.Debug.Printf("%d: waiting for response", msgCtx.id) - packetResponse, ok := <-msgCtx.responses - if !ok { - return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) - } - packet, err = packetResponse.ReadPacket() - l.Debug.Printf("%d: got response %p", msgCtx.id, packet) - if err != nil { - return err - } - - if l.Debug { - if err := addLDAPDescriptions(packet); err != nil { - return err - } - ber.PrintPacket(packet) - } - - if packet.Children[1].Tag == ApplicationDelResponse { - err := GetLDAPError(packet) - if err != nil { - return err - } - } else { - log.Printf("Unexpected Response: %d", packet.Children[1].Tag) - } - - l.Debug.Printf("%d: returning", msgCtx.id) - return nil -} diff --git a/vendor/gopkg.in/ldap.v3/moddn.go b/vendor/gopkg.in/ldap.v3/moddn.go deleted file mode 100644 index 803279d262..0000000000 --- a/vendor/gopkg.in/ldap.v3/moddn.go +++ /dev/null @@ -1,104 +0,0 @@ -// Package ldap - moddn.go contains ModifyDN functionality -// -// https://tools.ietf.org/html/rfc4511 -// ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { -// entry LDAPDN, -// newrdn RelativeLDAPDN, -// deleteoldrdn BOOLEAN, -// newSuperior [0] LDAPDN OPTIONAL } -// -// -package ldap - -import ( - "errors" - "log" - - "gopkg.in/asn1-ber.v1" -) - -// ModifyDNRequest holds the request to modify a DN -type ModifyDNRequest struct { - DN string - NewRDN string - DeleteOldRDN bool - NewSuperior string -} - -// NewModifyDNRequest creates a new request which can be passed to ModifyDN(). -// -// To move an object in the tree, set the "newSup" to the new parent entry DN. Use an -// empty string for just changing the object's RDN. -// -// For moving the object without renaming, the "rdn" must be the first -// RDN of the given DN. -// -// A call like -// mdnReq := NewModifyDNRequest("uid=someone,dc=example,dc=org", "uid=newname", true, "") -// will setup the request to just rename uid=someone,dc=example,dc=org to -// uid=newname,dc=example,dc=org. -func NewModifyDNRequest(dn string, rdn string, delOld bool, newSup string) *ModifyDNRequest { - return &ModifyDNRequest{ - DN: dn, - NewRDN: rdn, - DeleteOldRDN: delOld, - NewSuperior: newSup, - } -} - -func (m ModifyDNRequest) encode() *ber.Packet { - request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyDNRequest, nil, "Modify DN Request") - request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN")) - request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.NewRDN, "New RDN")) - request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, m.DeleteOldRDN, "Delete old RDN")) - if m.NewSuperior != "" { - request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, m.NewSuperior, "New Superior")) - } - return request -} - -// ModifyDN renames the given DN and optionally move to another base (when the "newSup" argument -// to NewModifyDNRequest() is not ""). -func (l *Conn) ModifyDN(m *ModifyDNRequest) error { - packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) - packet.AppendChild(m.encode()) - - l.Debug.PrintPacket(packet) - - msgCtx, err := l.sendMessage(packet) - if err != nil { - return err - } - defer l.finishMessage(msgCtx) - - l.Debug.Printf("%d: waiting for response", msgCtx.id) - packetResponse, ok := <-msgCtx.responses - if !ok { - return NewError(ErrorNetwork, errors.New("ldap: channel closed")) - } - packet, err = packetResponse.ReadPacket() - l.Debug.Printf("%d: got response %p", msgCtx.id, packet) - if err != nil { - return err - } - - if l.Debug { - if err := addLDAPDescriptions(packet); err != nil { - return err - } - ber.PrintPacket(packet) - } - - if packet.Children[1].Tag == ApplicationModifyDNResponse { - err := GetLDAPError(packet) - if err != nil { - return err - } - } else { - log.Printf("Unexpected Response: %d", packet.Children[1].Tag) - } - - l.Debug.Printf("%d: returning", msgCtx.id) - return nil -} diff --git a/vendor/gopkg.in/ldap.v3/modify.go b/vendor/gopkg.in/ldap.v3/modify.go deleted file mode 100644 index d83e6221fd..0000000000 --- a/vendor/gopkg.in/ldap.v3/modify.go +++ /dev/null @@ -1,173 +0,0 @@ -// 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 -// -- [RFC4512] -// -// AttributeValue ::= OCTET STRING -// - -package ldap - -import ( - "errors" - "log" - - "gopkg.in/asn1-ber.v1" -) - -// Change operation choices -const ( - AddAttribute = 0 - DeleteAttribute = 1 - ReplaceAttribute = 2 -) - -// PartialAttribute for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511 -type PartialAttribute struct { - // Type is the type of the partial attribute - Type string - // Vals are the values of the partial attribute - Vals []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.Type, "Type")) - set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue") - for _, value := range p.Vals { - set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals")) - } - seq.AppendChild(set) - return seq -} - -// Change for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511 -type Change struct { - // Operation is the type of change to be made - Operation uint - // Modification is the attribute to be modified - Modification PartialAttribute -} - -func (c *Change) encode() *ber.Packet { - change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change") - change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(c.Operation), "Operation")) - change.AppendChild(c.Modification.encode()) - return change -} - -// ModifyRequest as defined in https://tools.ietf.org/html/rfc4511 -type ModifyRequest struct { - // DN is the distinguishedName of the directory entry to modify - DN string - // Changes contain the attributes to modify - Changes []Change - // Controls hold optional controls to send with the request - Controls []Control -} - -// Add appends the given attribute to the list of changes to be made -func (m *ModifyRequest) Add(attrType string, attrVals []string) { - m.appendChange(AddAttribute, attrType, attrVals) -} - -// Delete appends the given attribute to the list of changes to be made -func (m *ModifyRequest) Delete(attrType string, attrVals []string) { - m.appendChange(DeleteAttribute, attrType, attrVals) -} - -// Replace appends the given attribute to the list of changes to be made -func (m *ModifyRequest) Replace(attrType string, attrVals []string) { - m.appendChange(ReplaceAttribute, attrType, attrVals) -} - -func (m *ModifyRequest) appendChange(operation uint, attrType string, attrVals []string) { - m.Changes = append(m.Changes, Change{operation, PartialAttribute{Type: attrType, Vals: 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 _, change := range m.Changes { - changes.AppendChild(change.encode()) - } - request.AppendChild(changes) - return request -} - -// NewModifyRequest creates a modify request for the given DN -func NewModifyRequest( - dn string, - controls []Control, -) *ModifyRequest { - return &ModifyRequest{ - DN: dn, - Controls: controls, - } -} - -// Modify performs the ModifyRequest -func (l *Conn) Modify(modifyRequest *ModifyRequest) error { - packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) - packet.AppendChild(modifyRequest.encode()) - if len(modifyRequest.Controls) > 0 { - packet.AppendChild(encodeControls(modifyRequest.Controls)) - } - - l.Debug.PrintPacket(packet) - - msgCtx, err := l.sendMessage(packet) - if err != nil { - return err - } - defer l.finishMessage(msgCtx) - - l.Debug.Printf("%d: waiting for response", msgCtx.id) - packetResponse, ok := <-msgCtx.responses - if !ok { - return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) - } - packet, err = packetResponse.ReadPacket() - l.Debug.Printf("%d: got response %p", msgCtx.id, packet) - if err != nil { - return err - } - - if l.Debug { - if err := addLDAPDescriptions(packet); err != nil { - return err - } - ber.PrintPacket(packet) - } - - if packet.Children[1].Tag == ApplicationModifyResponse { - err := GetLDAPError(packet) - if err != nil { - return err - } - } else { - log.Printf("Unexpected Response: %d", packet.Children[1].Tag) - } - - l.Debug.Printf("%d: returning", msgCtx.id) - return nil -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 37e0f2aa02..14ff831053 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -418,6 +418,12 @@ github.com/gin-gonic/gin/render # github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 ## explicit github.com/glycerine/go-unsnap-stream +# github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 +## explicit; go 1.13 +github.com/go-asn1-ber/asn1-ber +# github.com/go-ldap/ldap/v3 v3.1.5 +## explicit; go 1.13 +github.com/go-ldap/ldap/v3 # github.com/go-logfmt/logfmt v0.5.0 ## explicit; go 1.13 github.com/go-logfmt/logfmt @@ -1386,9 +1392,6 @@ google.golang.org/protobuf/types/known/timestamppb # gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc ## explicit gopkg.in/alexcesaro/quotedprintable.v3 -# gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d -## explicit -gopkg.in/asn1-ber.v1 # gopkg.in/fatih/set.v0 v0.2.1 ## explicit gopkg.in/fatih/set.v0 @@ -1398,9 +1401,6 @@ gopkg.in/inf.v0 # gopkg.in/ini.v1 v1.62.0 ## explicit gopkg.in/ini.v1 -# gopkg.in/ldap.v3 v3.0.3 -## explicit -gopkg.in/ldap.v3 # gopkg.in/mail.v2 v2.3.1 ## explicit gopkg.in/mail.v2 @@ -1671,7 +1671,7 @@ yunion.io/x/log/hooks yunion.io/x/ovsdb/cli_util yunion.io/x/ovsdb/schema/ovn_nb yunion.io/x/ovsdb/types -# yunion.io/x/pkg v1.10.4-0.20250814065738-8df5d9d07297 +# yunion.io/x/pkg v1.10.4-0.20250820035218-6008459eb4f0 ## explicit; go 1.18 yunion.io/x/pkg/appctx yunion.io/x/pkg/errors diff --git a/vendor/yunion.io/x/pkg/utils/tags.go b/vendor/yunion.io/x/pkg/utils/tags.go index 6bd4bef8a2..275329f850 100644 --- a/vendor/yunion.io/x/pkg/utils/tags.go +++ b/vendor/yunion.io/x/pkg/utils/tags.go @@ -109,6 +109,17 @@ func FindWords(str []byte, offset int) []string { return words } +func SplitWords(str string) ([]string, error) { + offset := 0 + words := make([]string, 0) + for offset < len(str) { + word, i := _findWord([]byte(str), offset, " \n\r\t", isQuoteCharInternal) + words = append(words, word) + offset = i + } + return words, nil +} + func FindWords2(str []byte, offset int, sepChars string, isQuoteChar func(ch byte) (bool, string)) ([]string, error) { words := make([]string, 0) for offset < len(str) {