updated dependencies

This commit is contained in:
Paul 2021-01-26 00:00:53 +01:00
parent 4ed08230a5
commit 891373a25e
362 changed files with 35678 additions and 84324 deletions

62
ci-build.sh Executable file
View File

@ -0,0 +1,62 @@
#!/bin/bash
set -e
PROJECTNAME=adradius
RELEASENAME=${PROJECTNAME}
VERSION="0"
GOOPTIONS="-mod=vendor"
SRCFILES=cmd/adradius/*.go
build() {
echo "Begin of build"
if [[ ! -z $DRONE_TAG ]]
then
echo "Drone tag set, let's do a release"
VERSION=$DRONE_TAG
echo "${PROJECTNAME} ${VERSION}" > /build/VERSION
elif [[ ! -z $DRONE_TAG ]]
then
echo "Drone not set, let's only do a build"
VERSION=$DRONE_COMMIT
fi
if [[ ! -z $VERSION && ! -z $GOOS && ! -z $GOARCH ]]
then
echo "Let's set a release name"
RELEASENAME=${PROJECTNAME}-${VERSION}-${GOOS}-${GOARCH}
fi
echo "Building project"
go build -o ${PROJECTNAME} ${GOOPTIONS} ${SRCFILES}
if [[ ! -z $DRONE_TAG ]]
then
echo "Let's make archives"
mkdir -p /build
tar -czvf /build/${RELEASENAME}.tar.gz ${PROJECTNAME}
fi
echo "Removing binary file"
rm ${PROJECTNAME}
echo "End of build"
}
clean() {
rm -rf $RELEASEDIR
}
case $1 in
"build")
build
;;
"clean")
clean
;;
*)
echo "No options choosen"
exit 1
;;
esac

13
go.mod
View File

@ -1,13 +1,16 @@
module git.paulbsd.com/paulbsd/adradius module git.paulbsd.com/paulbsd/adradius
go 1.13 go 1.15
require ( require (
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
github.com/go-ldap/ldap/v3 v3.2.4
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/sevlyar/go-daemon v0.1.5 github.com/sevlyar/go-daemon v0.1.5
github.com/smartystreets/goconvey v1.6.4 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect
golang.org/x/text v0.3.2 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
gopkg.in/ini.v1 v1.52.0 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
gopkg.in/ldap.v3 v3.1.0 golang.org/x/text v0.3.5
layeh.com/radius v0.0.0-20190322222518-890bc1058917 gopkg.in/ini.v1 v1.62.0
layeh.com/radius v0.0.0-20201203135236-838e26d0c9be
) )

37
go.sum
View File

@ -1,3 +1,11 @@
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28=
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-asn1-ber/asn1-ber v1.5.3 h1:u7utq56RUFiynqUzgVMFDymapcOtQ/MZkh3H4QYkxag=
github.com/go-asn1-ber/asn1-ber v1.5.3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-ldap/ldap/v3 v3.2.4 h1:PFavAq2xTgzo/loE8qNXcQaofAaqIpI4WgaLdv+1l3E=
github.com/go-ldap/ldap/v3 v3.2.4/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
@ -11,19 +19,28 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4= layeh.com/radius v0.0.0-20201203135236-838e26d0c9be h1:4YeDNYYOf9Pnn3pWEktFE+ZCZ5qX5ZVMaw3VAtfoXPk=
gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= layeh.com/radius v0.0.0-20201203135236-838e26d0c9be/go.mod h1:pFWM9De99EY9TPVyHIyA56QmoRViVck/x41WFkUlc9A=
gopkg.in/ldap.v3 v3.1.0 h1:DIDWEjI7vQWREh0S8X5/NFPCZ3MCVd55LmXKPW4XLGE=
gopkg.in/ldap.v3 v3.1.0/go.mod h1:dQjCc0R0kfyFjIlWNMH1DORwUASZyDxo2Ry1B51dXaQ=
layeh.com/radius v0.0.0-20190322222518-890bc1058917 h1:BDXFaFzUt5EIqe/4wrTc4AcYZWP6iC6Ult+jQWLh5eU=
layeh.com/radius v0.0.0-20190322222518-890bc1058917/go.mod h1:fywZKyu//X7iRzaxLgPWsvc0L26IUpVvE/aeIL2JtIQ=

View File

@ -1,6 +1,6 @@
package auth package auth
import ldap "gopkg.in/ldap.v3" import ldap "github.com/go-ldap/ldap/v3"
//Authenticate checks if the given credentials are valid, or returns an error if one occurred. //Authenticate checks if the given credentials are valid, or returns an error if one occurred.
//username may be either the sAMAccountName or the userPrincipalName. //username may be either the sAMAccountName or the userPrincipalName.

View File

@ -6,7 +6,7 @@ import (
"fmt" "fmt"
"log" "log"
ldap "gopkg.in/ldap.v3" ldap "github.com/go-ldap/ldap/v3"
) )
//Conn represents an Active Directory connection. //Conn represents an Active Directory connection.

View File

@ -4,8 +4,8 @@ import (
"errors" "errors"
"fmt" "fmt"
ldap "github.com/go-ldap/ldap/v3"
"golang.org/x/text/encoding/unicode" "golang.org/x/text/encoding/unicode"
ldap "gopkg.in/ldap.v3"
) )
//ModifyDNPassword sets a new password for the given user or returns an error if one occurred. //ModifyDNPassword sets a new password for the given user or returns an error if one occurred.

View File

@ -3,7 +3,7 @@ package auth
import ( import (
"fmt" "fmt"
ldap "gopkg.in/ldap.v3" ldap "github.com/go-ldap/ldap/v3"
) )
//Search returns the entries for the given search criteria or an error if one occurred. //Search returns the entries for the given search criteria or an error if one occurred.

17
vendor/github.com/Azure/go-ntlmssp/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,17 @@
sudo: false
language: go
before_script:
- go get -u golang.org/x/lint/golint
go:
- 1.10.x
- master
script:
- test -z "$(gofmt -s -l . | tee /dev/stderr)"
- test -z "$(golint ./... | tee /dev/stderr)"
- go vet ./...
- go build -v ./...
- go test -v ./...

21
vendor/github.com/Azure/go-ntlmssp/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Microsoft
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

29
vendor/github.com/Azure/go-ntlmssp/README.md generated vendored Normal file
View File

@ -0,0 +1,29 @@
# go-ntlmssp
Golang package that provides NTLM/Negotiate authentication over HTTP
[![GoDoc](https://godoc.org/github.com/Azure/go-ntlmssp?status.svg)](https://godoc.org/github.com/Azure/go-ntlmssp) [![Build Status](https://travis-ci.org/Azure/go-ntlmssp.svg?branch=dev)](https://travis-ci.org/Azure/go-ntlmssp)
Protocol details from https://msdn.microsoft.com/en-us/library/cc236621.aspx
Implementation hints from http://davenport.sourceforge.net/ntlm.html
This package only implements authentication, no key exchange or encryption. It
only supports Unicode (UTF16LE) encoding of protocol strings, no OEM encoding.
This package implements NTLMv2.
# Usage
```
url, user, password := "http://www.example.com/secrets", "robpike", "pw123"
client := &http.Client{
Transport: ntlmssp.Negotiator{
RoundTripper:&http.Transport{},
},
}
req, _ := http.NewRequest("GET", url, nil)
req.SetBasicAuth(user, password)
res, _ := client.Do(req)
```
-----
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

View File

@ -0,0 +1,183 @@
package ntlmssp
import (
"bytes"
"crypto/rand"
"encoding/binary"
"encoding/hex"
"errors"
"strings"
"time"
)
type authenicateMessage struct {
LmChallengeResponse []byte
NtChallengeResponse []byte
TargetName string
UserName string
// only set if negotiateFlag_NTLMSSP_NEGOTIATE_KEY_EXCH
EncryptedRandomSessionKey []byte
NegotiateFlags negotiateFlags
MIC []byte
}
type authenticateMessageFields struct {
messageHeader
LmChallengeResponse varField
NtChallengeResponse varField
TargetName varField
UserName varField
Workstation varField
_ [8]byte
NegotiateFlags negotiateFlags
}
func (m authenicateMessage) MarshalBinary() ([]byte, error) {
if !m.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEUNICODE) {
return nil, errors.New("Only unicode is supported")
}
target, user := toUnicode(m.TargetName), toUnicode(m.UserName)
workstation := toUnicode("go-ntlmssp")
ptr := binary.Size(&authenticateMessageFields{})
f := authenticateMessageFields{
messageHeader: newMessageHeader(3),
NegotiateFlags: m.NegotiateFlags,
LmChallengeResponse: newVarField(&ptr, len(m.LmChallengeResponse)),
NtChallengeResponse: newVarField(&ptr, len(m.NtChallengeResponse)),
TargetName: newVarField(&ptr, len(target)),
UserName: newVarField(&ptr, len(user)),
Workstation: newVarField(&ptr, len(workstation)),
}
f.NegotiateFlags.Unset(negotiateFlagNTLMSSPNEGOTIATEVERSION)
b := bytes.Buffer{}
if err := binary.Write(&b, binary.LittleEndian, &f); err != nil {
return nil, err
}
if err := binary.Write(&b, binary.LittleEndian, &m.LmChallengeResponse); err != nil {
return nil, err
}
if err := binary.Write(&b, binary.LittleEndian, &m.NtChallengeResponse); err != nil {
return nil, err
}
if err := binary.Write(&b, binary.LittleEndian, &target); err != nil {
return nil, err
}
if err := binary.Write(&b, binary.LittleEndian, &user); err != nil {
return nil, err
}
if err := binary.Write(&b, binary.LittleEndian, &workstation); err != nil {
return nil, err
}
return b.Bytes(), nil
}
//ProcessChallenge crafts an AUTHENTICATE message in response to the CHALLENGE message
//that was received from the server
func ProcessChallenge(challengeMessageData []byte, user, password string) ([]byte, error) {
if user == "" && password == "" {
return nil, errors.New("Anonymous authentication not supported")
}
var cm challengeMessage
if err := cm.UnmarshalBinary(challengeMessageData); err != nil {
return nil, err
}
if cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATELMKEY) {
return nil, errors.New("Only NTLM v2 is supported, but server requested v1 (NTLMSSP_NEGOTIATE_LM_KEY)")
}
if cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEKEYEXCH) {
return nil, errors.New("Key exchange requested but not supported (NTLMSSP_NEGOTIATE_KEY_EXCH)")
}
am := authenicateMessage{
UserName: user,
TargetName: cm.TargetName,
NegotiateFlags: cm.NegotiateFlags,
}
timestamp := cm.TargetInfo[avIDMsvAvTimestamp]
if timestamp == nil { // no time sent, take current time
ft := uint64(time.Now().UnixNano()) / 100
ft += 116444736000000000 // add time between unix & windows offset
timestamp = make([]byte, 8)
binary.LittleEndian.PutUint64(timestamp, ft)
}
clientChallenge := make([]byte, 8)
rand.Reader.Read(clientChallenge)
ntlmV2Hash := getNtlmV2Hash(password, user, cm.TargetName)
am.NtChallengeResponse = computeNtlmV2Response(ntlmV2Hash,
cm.ServerChallenge[:], clientChallenge, timestamp, cm.TargetInfoRaw)
if cm.TargetInfoRaw == nil {
am.LmChallengeResponse = computeLmV2Response(ntlmV2Hash,
cm.ServerChallenge[:], clientChallenge)
}
return am.MarshalBinary()
}
func ProcessChallengeWithHash(challengeMessageData []byte, user, hash string) ([]byte, error) {
if user == "" && hash == "" {
return nil, errors.New("Anonymous authentication not supported")
}
var cm challengeMessage
if err := cm.UnmarshalBinary(challengeMessageData); err != nil {
return nil, err
}
if cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATELMKEY) {
return nil, errors.New("Only NTLM v2 is supported, but server requested v1 (NTLMSSP_NEGOTIATE_LM_KEY)")
}
if cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEKEYEXCH) {
return nil, errors.New("Key exchange requested but not supported (NTLMSSP_NEGOTIATE_KEY_EXCH)")
}
am := authenicateMessage{
UserName: user,
TargetName: cm.TargetName,
NegotiateFlags: cm.NegotiateFlags,
}
timestamp := cm.TargetInfo[avIDMsvAvTimestamp]
if timestamp == nil { // no time sent, take current time
ft := uint64(time.Now().UnixNano()) / 100
ft += 116444736000000000 // add time between unix & windows offset
timestamp = make([]byte, 8)
binary.LittleEndian.PutUint64(timestamp, ft)
}
clientChallenge := make([]byte, 8)
rand.Reader.Read(clientChallenge)
hashParts := strings.Split(hash, ":")
if len(hashParts) > 1 {
hash = hashParts[1]
}
hashBytes, err := hex.DecodeString(hash)
if err != nil {
return nil, err
}
ntlmV2Hash := hmacMd5(hashBytes, toUnicode(strings.ToUpper(user)+cm.TargetName))
am.NtChallengeResponse = computeNtlmV2Response(ntlmV2Hash,
cm.ServerChallenge[:], clientChallenge, timestamp, cm.TargetInfoRaw)
if cm.TargetInfoRaw == nil {
am.LmChallengeResponse = computeLmV2Response(ntlmV2Hash,
cm.ServerChallenge[:], clientChallenge)
}
return am.MarshalBinary()
}

37
vendor/github.com/Azure/go-ntlmssp/authheader.go generated vendored Normal file
View File

@ -0,0 +1,37 @@
package ntlmssp
import (
"encoding/base64"
"strings"
)
type authheader string
func (h authheader) IsBasic() bool {
return strings.HasPrefix(string(h), "Basic ")
}
func (h authheader) IsNegotiate() bool {
return strings.HasPrefix(string(h), "Negotiate")
}
func (h authheader) IsNTLM() bool {
return strings.HasPrefix(string(h), "NTLM")
}
func (h authheader) GetData() ([]byte, error) {
p := strings.Split(string(h), " ")
if len(p) < 2 {
return nil, nil
}
return base64.StdEncoding.DecodeString(string(p[1]))
}
func (h authheader) GetBasicCreds() (username, password string, err error) {
d, err := h.GetData()
if err != nil {
return "", "", err
}
parts := strings.SplitN(string(d), ":", 2)
return parts[0], parts[1], nil
}

17
vendor/github.com/Azure/go-ntlmssp/avids.go generated vendored Normal file
View File

@ -0,0 +1,17 @@
package ntlmssp
type avID uint16
const (
avIDMsvAvEOL avID = iota
avIDMsvAvNbComputerName
avIDMsvAvNbDomainName
avIDMsvAvDNSComputerName
avIDMsvAvDNSDomainName
avIDMsvAvDNSTreeName
avIDMsvAvFlags
avIDMsvAvTimestamp
avIDMsvAvSingleHost
avIDMsvAvTargetName
avIDMsvChannelBindings
)

View File

@ -0,0 +1,82 @@
package ntlmssp
import (
"bytes"
"encoding/binary"
"fmt"
)
type challengeMessageFields struct {
messageHeader
TargetName varField
NegotiateFlags negotiateFlags
ServerChallenge [8]byte
_ [8]byte
TargetInfo varField
}
func (m challengeMessageFields) IsValid() bool {
return m.messageHeader.IsValid() && m.MessageType == 2
}
type challengeMessage struct {
challengeMessageFields
TargetName string
TargetInfo map[avID][]byte
TargetInfoRaw []byte
}
func (m *challengeMessage) UnmarshalBinary(data []byte) error {
r := bytes.NewReader(data)
err := binary.Read(r, binary.LittleEndian, &m.challengeMessageFields)
if err != nil {
return err
}
if !m.challengeMessageFields.IsValid() {
return fmt.Errorf("Message is not a valid challenge message: %+v", m.challengeMessageFields.messageHeader)
}
if m.challengeMessageFields.TargetName.Len > 0 {
m.TargetName, err = m.challengeMessageFields.TargetName.ReadStringFrom(data, m.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEUNICODE))
if err != nil {
return err
}
}
if m.challengeMessageFields.TargetInfo.Len > 0 {
d, err := m.challengeMessageFields.TargetInfo.ReadFrom(data)
m.TargetInfoRaw = d
if err != nil {
return err
}
m.TargetInfo = make(map[avID][]byte)
r := bytes.NewReader(d)
for {
var id avID
var l uint16
err = binary.Read(r, binary.LittleEndian, &id)
if err != nil {
return err
}
if id == avIDMsvAvEOL {
break
}
err = binary.Read(r, binary.LittleEndian, &l)
if err != nil {
return err
}
value := make([]byte, l)
n, err := r.Read(value)
if err != nil {
return err
}
if n != int(l) {
return fmt.Errorf("Expected to read %d bytes, got only %d", l, n)
}
m.TargetInfo[id] = value
}
}
return nil
}

21
vendor/github.com/Azure/go-ntlmssp/messageheader.go generated vendored Normal file
View File

@ -0,0 +1,21 @@
package ntlmssp
import (
"bytes"
)
var signature = [8]byte{'N', 'T', 'L', 'M', 'S', 'S', 'P', 0}
type messageHeader struct {
Signature [8]byte
MessageType uint32
}
func (h messageHeader) IsValid() bool {
return bytes.Equal(h.Signature[:], signature[:]) &&
h.MessageType > 0 && h.MessageType < 4
}
func newMessageHeader(messageType uint32) messageHeader {
return messageHeader{signature, messageType}
}

52
vendor/github.com/Azure/go-ntlmssp/negotiate_flags.go generated vendored Normal file
View File

@ -0,0 +1,52 @@
package ntlmssp
type negotiateFlags uint32
const (
/*A*/ negotiateFlagNTLMSSPNEGOTIATEUNICODE negotiateFlags = 1 << 0
/*B*/ negotiateFlagNTLMNEGOTIATEOEM = 1 << 1
/*C*/ negotiateFlagNTLMSSPREQUESTTARGET = 1 << 2
/*D*/
negotiateFlagNTLMSSPNEGOTIATESIGN = 1 << 4
/*E*/ negotiateFlagNTLMSSPNEGOTIATESEAL = 1 << 5
/*F*/ negotiateFlagNTLMSSPNEGOTIATEDATAGRAM = 1 << 6
/*G*/ negotiateFlagNTLMSSPNEGOTIATELMKEY = 1 << 7
/*H*/
negotiateFlagNTLMSSPNEGOTIATENTLM = 1 << 9
/*J*/
negotiateFlagANONYMOUS = 1 << 11
/*K*/ negotiateFlagNTLMSSPNEGOTIATEOEMDOMAINSUPPLIED = 1 << 12
/*L*/ negotiateFlagNTLMSSPNEGOTIATEOEMWORKSTATIONSUPPLIED = 1 << 13
/*M*/
negotiateFlagNTLMSSPNEGOTIATEALWAYSSIGN = 1 << 15
/*N*/ negotiateFlagNTLMSSPTARGETTYPEDOMAIN = 1 << 16
/*O*/ negotiateFlagNTLMSSPTARGETTYPESERVER = 1 << 17
/*P*/
negotiateFlagNTLMSSPNEGOTIATEEXTENDEDSESSIONSECURITY = 1 << 19
/*Q*/ negotiateFlagNTLMSSPNEGOTIATEIDENTIFY = 1 << 20
/*R*/
negotiateFlagNTLMSSPREQUESTNONNTSESSIONKEY = 1 << 22
/*S*/ negotiateFlagNTLMSSPNEGOTIATETARGETINFO = 1 << 23
/*T*/
negotiateFlagNTLMSSPNEGOTIATEVERSION = 1 << 25
/*U*/
negotiateFlagNTLMSSPNEGOTIATE128 = 1 << 29
/*V*/ negotiateFlagNTLMSSPNEGOTIATEKEYEXCH = 1 << 30
/*W*/ negotiateFlagNTLMSSPNEGOTIATE56 = 1 << 31
)
func (field negotiateFlags) Has(flags negotiateFlags) bool {
return field&flags == flags
}
func (field *negotiateFlags) Unset(flags negotiateFlags) {
*field = *field ^ (*field & flags)
}

View File

@ -0,0 +1,64 @@
package ntlmssp
import (
"bytes"
"encoding/binary"
"errors"
"strings"
)
const expMsgBodyLen = 40
type negotiateMessageFields struct {
messageHeader
NegotiateFlags negotiateFlags
Domain varField
Workstation varField
Version
}
var defaultFlags = negotiateFlagNTLMSSPNEGOTIATETARGETINFO |
negotiateFlagNTLMSSPNEGOTIATE56 |
negotiateFlagNTLMSSPNEGOTIATE128 |
negotiateFlagNTLMSSPNEGOTIATEUNICODE |
negotiateFlagNTLMSSPNEGOTIATEEXTENDEDSESSIONSECURITY
//NewNegotiateMessage creates a new NEGOTIATE message with the
//flags that this package supports.
func NewNegotiateMessage(domainName, workstationName string) ([]byte, error) {
payloadOffset := expMsgBodyLen
flags := defaultFlags
if domainName != "" {
flags |= negotiateFlagNTLMSSPNEGOTIATEOEMDOMAINSUPPLIED
}
if workstationName != "" {
flags |= negotiateFlagNTLMSSPNEGOTIATEOEMWORKSTATIONSUPPLIED
}
msg := negotiateMessageFields{
messageHeader: newMessageHeader(1),
NegotiateFlags: flags,
Domain: newVarField(&payloadOffset, len(domainName)),
Workstation: newVarField(&payloadOffset, len(workstationName)),
Version: DefaultVersion(),
}
b := bytes.Buffer{}
if err := binary.Write(&b, binary.LittleEndian, &msg); err != nil {
return nil, err
}
if b.Len() != expMsgBodyLen {
return nil, errors.New("incorrect body length")
}
payload := strings.ToUpper(domainName + workstationName)
if _, err := b.WriteString(payload); err != nil {
return nil, err
}
return b.Bytes(), nil
}

144
vendor/github.com/Azure/go-ntlmssp/negotiator.go generated vendored Normal file
View File

@ -0,0 +1,144 @@
package ntlmssp
import (
"bytes"
"encoding/base64"
"io"
"io/ioutil"
"net/http"
"strings"
)
// GetDomain : parse domain name from based on slashes in the input
func GetDomain(user string) (string, string) {
domain := ""
if strings.Contains(user, "\\") {
ucomponents := strings.SplitN(user, "\\", 2)
domain = ucomponents[0]
user = ucomponents[1]
}
return user, domain
}
//Negotiator is a http.Roundtripper decorator that automatically
//converts basic authentication to NTLM/Negotiate authentication when appropriate.
type Negotiator struct{ http.RoundTripper }
//RoundTrip sends the request to the server, handling any authentication
//re-sends as needed.
func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error) {
// Use default round tripper if not provided
rt := l.RoundTripper
if rt == nil {
rt = http.DefaultTransport
}
// If it is not basic auth, just round trip the request as usual
reqauth := authheader(req.Header.Get("Authorization"))
if !reqauth.IsBasic() {
return rt.RoundTrip(req)
}
// Save request body
body := bytes.Buffer{}
if req.Body != nil {
_, err = body.ReadFrom(req.Body)
if err != nil {
return nil, err
}
req.Body.Close()
req.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))
}
// first try anonymous, in case the server still finds us
// authenticated from previous traffic
req.Header.Del("Authorization")
res, err = rt.RoundTrip(req)
if err != nil {
return nil, err
}
if res.StatusCode != http.StatusUnauthorized {
return res, err
}
resauth := authheader(res.Header.Get("Www-Authenticate"))
if !resauth.IsNegotiate() && !resauth.IsNTLM() {
// Unauthorized, Negotiate not requested, let's try with basic auth
req.Header.Set("Authorization", string(reqauth))
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()
req.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))
res, err = rt.RoundTrip(req)
if err != nil {
return nil, err
}
if res.StatusCode != http.StatusUnauthorized {
return res, err
}
resauth = authheader(res.Header.Get("Www-Authenticate"))
}
if resauth.IsNegotiate() || resauth.IsNTLM() {
// 401 with request:Basic and response:Negotiate
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()
// recycle credentials
u, p, err := reqauth.GetBasicCreds()
if err != nil {
return nil, err
}
// get domain from username
domain := ""
u, domain = GetDomain(u)
// send negotiate
negotiateMessage, err := NewNegotiateMessage(domain, "")
if err != nil {
return nil, err
}
if resauth.IsNTLM() {
req.Header.Set("Authorization", "NTLM "+base64.StdEncoding.EncodeToString(negotiateMessage))
} else {
req.Header.Set("Authorization", "Negotiate "+base64.StdEncoding.EncodeToString(negotiateMessage))
}
req.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))
res, err = rt.RoundTrip(req)
if err != nil {
return nil, err
}
// receive challenge?
resauth = authheader(res.Header.Get("Www-Authenticate"))
challengeMessage, err := resauth.GetData()
if err != nil {
return nil, err
}
if !(resauth.IsNegotiate() || resauth.IsNTLM()) || len(challengeMessage) == 0 {
// Negotiation failed, let client deal with response
return res, nil
}
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()
// send authenticate
authenticateMessage, err := ProcessChallenge(challengeMessage, u, p)
if err != nil {
return nil, err
}
if resauth.IsNTLM() {
req.Header.Set("Authorization", "NTLM "+base64.StdEncoding.EncodeToString(authenticateMessage))
} else {
req.Header.Set("Authorization", "Negotiate "+base64.StdEncoding.EncodeToString(authenticateMessage))
}
req.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))
return rt.RoundTrip(req)
}
return res, err
}

51
vendor/github.com/Azure/go-ntlmssp/nlmp.go generated vendored Normal file
View File

@ -0,0 +1,51 @@
// Package ntlmssp provides NTLM/Negotiate authentication over HTTP
//
// Protocol details from https://msdn.microsoft.com/en-us/library/cc236621.aspx,
// implementation hints from http://davenport.sourceforge.net/ntlm.html .
// This package only implements authentication, no key exchange or encryption. It
// only supports Unicode (UTF16LE) encoding of protocol strings, no OEM encoding.
// This package implements NTLMv2.
package ntlmssp
import (
"crypto/hmac"
"crypto/md5"
"golang.org/x/crypto/md4"
"strings"
)
func getNtlmV2Hash(password, username, target string) []byte {
return hmacMd5(getNtlmHash(password), toUnicode(strings.ToUpper(username)+target))
}
func getNtlmHash(password string) []byte {
hash := md4.New()
hash.Write(toUnicode(password))
return hash.Sum(nil)
}
func computeNtlmV2Response(ntlmV2Hash, serverChallenge, clientChallenge,
timestamp, targetInfo []byte) []byte {
temp := []byte{1, 1, 0, 0, 0, 0, 0, 0}
temp = append(temp, timestamp...)
temp = append(temp, clientChallenge...)
temp = append(temp, 0, 0, 0, 0)
temp = append(temp, targetInfo...)
temp = append(temp, 0, 0, 0, 0)
NTProofStr := hmacMd5(ntlmV2Hash, serverChallenge, temp)
return append(NTProofStr, temp...)
}
func computeLmV2Response(ntlmV2Hash, serverChallenge, clientChallenge []byte) []byte {
return append(hmacMd5(ntlmV2Hash, serverChallenge, clientChallenge), clientChallenge...)
}
func hmacMd5(key []byte, data ...[]byte) []byte {
mac := hmac.New(md5.New, key)
for _, d := range data {
mac.Write(d)
}
return mac.Sum(nil)
}

29
vendor/github.com/Azure/go-ntlmssp/unicode.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
package ntlmssp
import (
"bytes"
"encoding/binary"
"errors"
"unicode/utf16"
)
// helper func's for dealing with Windows Unicode (UTF16LE)
func fromUnicode(d []byte) (string, error) {
if len(d)%2 > 0 {
return "", errors.New("Unicode (UTF 16 LE) specified, but uneven data length")
}
s := make([]uint16, len(d)/2)
err := binary.Read(bytes.NewReader(d), binary.LittleEndian, &s)
if err != nil {
return "", err
}
return string(utf16.Decode(s)), nil
}
func toUnicode(s string) []byte {
uints := utf16.Encode([]rune(s))
b := bytes.Buffer{}
binary.Write(&b, binary.LittleEndian, &uints)
return b.Bytes()
}

40
vendor/github.com/Azure/go-ntlmssp/varfield.go generated vendored Normal file
View File

@ -0,0 +1,40 @@
package ntlmssp
import (
"errors"
)
type varField struct {
Len uint16
MaxLen uint16
BufferOffset uint32
}
func (f varField) ReadFrom(buffer []byte) ([]byte, error) {
if len(buffer) < int(f.BufferOffset+uint32(f.Len)) {
return nil, errors.New("Error reading data, varField extends beyond buffer")
}
return buffer[f.BufferOffset : f.BufferOffset+uint32(f.Len)], nil
}
func (f varField) ReadStringFrom(buffer []byte, unicode bool) (string, error) {
d, err := f.ReadFrom(buffer)
if err != nil {
return "", err
}
if unicode { // UTF-16LE encoding scheme
return fromUnicode(d)
}
// OEM encoding, close enough to ASCII, since no code page is specified
return string(d), err
}
func newVarField(ptr *int, fieldsize int) varField {
f := varField{
Len: uint16(fieldsize),
MaxLen: uint16(fieldsize),
BufferOffset: uint32(*ptr),
}
*ptr += fieldsize
return f
}

20
vendor/github.com/Azure/go-ntlmssp/version.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
package ntlmssp
// Version is a struct representing https://msdn.microsoft.com/en-us/library/cc236654.aspx
type Version struct {
ProductMajorVersion uint8
ProductMinorVersion uint8
ProductBuild uint16
_ [3]byte
NTLMRevisionCurrent uint8
}
// DefaultVersion returns a Version with "sensible" defaults (Windows 7)
func DefaultVersion() Version {
return Version{
ProductMajorVersion: 6,
ProductMinorVersion: 1,
ProductBuild: 7601,
NTLMRevisionCurrent: 15,
}
}

43
vendor/github.com/go-asn1-ber/asn1-ber/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,43 @@
language: go
go:
- 1.2.x
- 1.6.x
- 1.9.x
- 1.10.x
- 1.11.x
- 1.12.x
- 1.14.x
- tip
os:
- linux
arch:
- amd64
- ppc64le
dist: xenial
env:
- GOARCH=amd64
jobs:
include:
- os: windows
go: 1.14.x
- os: osx
go: 1.14.x
- os: linux
go: 1.14.x
arch: arm64
- os: linux
go: 1.14.x
env:
- GOARCH=386
script:
- go test -v -cover ./... || go test -v ./...
matrix:
allowfailures:
go: 1.2.x

View File

@ -8,6 +8,8 @@ import (
"math" "math"
"os" "os"
"reflect" "reflect"
"time"
"unicode/utf8"
) )
// MaxPacketLengthBytes specifies the maximum allowed packet size when calling ReadPacket or DecodePacket. Set to 0 for // MaxPacketLengthBytes specifies the maximum allowed packet size when calling ReadPacket or DecodePacket. Set to 0 for
@ -143,42 +145,46 @@ var TypeMap = map[Type]string{
TypeConstructed: "Constructed", TypeConstructed: "Constructed",
} }
var Debug bool = false var Debug = false
func PrintBytes(out io.Writer, buf []byte, indent string) { func PrintBytes(out io.Writer, buf []byte, indent string) {
data_lines := make([]string, (len(buf)/30)+1) dataLines := make([]string, (len(buf)/30)+1)
num_lines := make([]string, (len(buf)/30)+1) numLines := make([]string, (len(buf)/30)+1)
for i, b := range buf { for i, b := range buf {
data_lines[i/30] += fmt.Sprintf("%02x ", b) dataLines[i/30] += fmt.Sprintf("%02x ", b)
num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100) numLines[i/30] += fmt.Sprintf("%02d ", (i+1)%100)
} }
for i := 0; i < len(data_lines); i++ { for i := 0; i < len(dataLines); i++ {
out.Write([]byte(indent + data_lines[i] + "\n")) _, _ = out.Write([]byte(indent + dataLines[i] + "\n"))
out.Write([]byte(indent + num_lines[i] + "\n\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) { func PrintPacket(p *Packet) {
printPacket(os.Stdout, p, 0, false) printPacket(os.Stdout, p, 0, false)
} }
func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) { func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) {
indent_str := "" indentStr := ""
for len(indent_str) != indent { for len(indentStr) != indent {
indent_str += " " indentStr += " "
} }
class_str := ClassMap[p.ClassType] classStr := ClassMap[p.ClassType]
tagtype_str := TypeMap[p.TagType] tagTypeStr := TypeMap[p.TagType]
tag_str := fmt.Sprintf("0x%02X", p.Tag) tagStr := fmt.Sprintf("0x%02X", p.Tag)
if p.ClassType == ClassUniversal { if p.ClassType == ClassUniversal {
tag_str = tagMap[p.Tag] tagStr = tagMap[p.Tag]
} }
value := fmt.Sprint(p.Value) value := fmt.Sprint(p.Value)
@ -188,10 +194,10 @@ func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) {
description = 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) _, _ = fmt.Fprintf(out, "%s%s(%s, %s, %s) Len=%d %q\n", indentStr, description, classStr, tagTypeStr, tagStr, p.Data.Len(), value)
if printBytes { if printBytes {
PrintBytes(out, p.Bytes(), indent_str) PrintBytes(out, p.Bytes(), indentStr)
} }
for _, child := range p.Children { for _, child := range p.Children {
@ -199,7 +205,7 @@ func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) {
} }
} }
// ReadPacket reads a single Packet from the reader // ReadPacket reads a single Packet from the reader.
func ReadPacket(reader io.Reader) (*Packet, error) { func ReadPacket(reader io.Reader) (*Packet, error) {
p, _, err := readPacket(reader) p, _, err := readPacket(reader)
if err != nil { if err != nil {
@ -235,7 +241,7 @@ func encodeInteger(i int64) []byte {
var j int var j int
for ; n > 0; n-- { for ; n > 0; n-- {
out[j] = (byte(i >> uint((n-1)*8))) out[j] = byte(i >> uint((n-1)*8))
j++ j++
} }
@ -267,7 +273,7 @@ func DecodePacket(data []byte) *Packet {
} }
// DecodePacketErr decodes the given bytes into a single Packet // DecodePacketErr decodes the given bytes into a single Packet
// If a decode error is encountered, nil is returned // If a decode error is encountered, nil is returned.
func DecodePacketErr(data []byte) (*Packet, error) { func DecodePacketErr(data []byte) (*Packet, error) {
p, _, err := readPacket(bytes.NewBuffer(data)) p, _, err := readPacket(bytes.NewBuffer(data))
if err != nil { if err != nil {
@ -276,7 +282,7 @@ func DecodePacketErr(data []byte) (*Packet, error) {
return p, nil return p, nil
} }
// readPacket reads a single Packet from the reader, returning the number of bytes read // readPacket reads a single Packet from the reader, returning the number of bytes read.
func readPacket(reader io.Reader) (*Packet, int, error) { func readPacket(reader io.Reader) (*Packet, int, error) {
identifier, length, read, err := readHeader(reader) identifier, length, read, err := readHeader(reader)
if err != nil { if err != nil {
@ -338,7 +344,7 @@ func readPacket(reader io.Reader) (*Packet, int, error) {
if MaxPacketLengthBytes > 0 && int64(length) > MaxPacketLengthBytes { if MaxPacketLengthBytes > 0 && int64(length) > MaxPacketLengthBytes {
return nil, read, fmt.Errorf("length %d greater than maximum %d", length, MaxPacketLengthBytes) return nil, read, fmt.Errorf("length %d greater than maximum %d", length, MaxPacketLengthBytes)
} }
content := make([]byte, length, length) content := make([]byte, length)
if length > 0 { if length > 0 {
_, err := io.ReadFull(reader, content) _, err := io.ReadFull(reader, content)
if err != nil { if err != nil {
@ -373,22 +379,42 @@ func readPacket(reader io.Reader) (*Packet, int, error) {
case TagObjectDescriptor: case TagObjectDescriptor:
case TagExternal: case TagExternal:
case TagRealFloat: case TagRealFloat:
p.Value, err = ParseReal(content)
case TagEnumerated: case TagEnumerated:
p.Value, _ = ParseInt64(content) p.Value, _ = ParseInt64(content)
case TagEmbeddedPDV: case TagEmbeddedPDV:
case TagUTF8String: case TagUTF8String:
p.Value = DecodeString(content) val := DecodeString(content)
if !utf8.Valid([]byte(val)) {
err = errors.New("invalid UTF-8 string")
} else {
p.Value = val
}
case TagRelativeOID: case TagRelativeOID:
case TagSequence: case TagSequence:
case TagSet: case TagSet:
case TagNumericString: case TagNumericString:
case TagPrintableString: case TagPrintableString:
p.Value = DecodeString(content) val := DecodeString(content)
if err = isPrintableString(val); err == nil {
p.Value = val
}
case TagT61String: case TagT61String:
case TagVideotexString: case TagVideotexString:
case TagIA5String: 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 TagUTCTime:
case TagGeneralizedTime: case TagGeneralizedTime:
p.Value, err = ParseGeneralizedTime(content)
case TagGraphicString: case TagGraphicString:
case TagVisibleString: case TagVisibleString:
case TagGeneralString: case TagGeneralString:
@ -400,7 +426,24 @@ func readPacket(reader io.Reader) (*Packet, int, error) {
p.Data.Write(content) p.Data.Write(content)
} }
return p, read, nil 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 { func (p *Packet) Bytes() []byte {
@ -418,61 +461,99 @@ func (p *Packet) AppendChild(child *Packet) {
p.Children = append(p.Children, child) p.Children = append(p.Children, child)
} }
func Encode(ClassType Class, TagType Type, Tag Tag, Value interface{}, Description string) *Packet { func Encode(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet {
p := new(Packet) p := new(Packet)
p.ClassType = ClassType p.ClassType = classType
p.TagType = TagType p.TagType = tagType
p.Tag = Tag p.Tag = tag
p.Data = new(bytes.Buffer) p.Data = new(bytes.Buffer)
p.Children = make([]*Packet, 0, 2) p.Children = make([]*Packet, 0, 2)
p.Value = Value p.Value = value
p.Description = Description p.Description = description
if Value != nil { if value != nil {
v := reflect.ValueOf(Value) v := reflect.ValueOf(value)
if ClassType == ClassUniversal { if classType == ClassUniversal {
switch Tag { switch tag {
case TagOctetString: case TagOctetString:
sv, ok := v.Interface().(string) sv, ok := v.Interface().(string)
if ok { if ok {
p.Data.Write([]byte(sv)) 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 return p
} }
func NewSequence(Description string) *Packet { func NewSequence(description string) *Packet {
return Encode(ClassUniversal, TypeConstructed, TagSequence, nil, Description) return Encode(ClassUniversal, TypeConstructed, TagSequence, nil, description)
} }
func NewBoolean(ClassType Class, TagType Type, Tag Tag, Value bool, Description string) *Packet { func NewBoolean(classType Class, tagType Type, tag Tag, value bool, description string) *Packet {
intValue := int64(0) intValue := int64(0)
if Value { if value {
intValue = 1 intValue = 1
} }
p := Encode(ClassType, TagType, Tag, nil, Description) p := Encode(classType, tagType, tag, nil, description)
p.Value = Value p.Value = value
p.Data.Write(encodeInteger(intValue)) p.Data.Write(encodeInteger(intValue))
return p return p
} }
func NewInteger(ClassType Class, TagType Type, Tag Tag, Value interface{}, Description string) *Packet { // NewLDAPBoolean returns a RFC 4511-compliant Boolean packet.
p := Encode(ClassType, TagType, Tag, nil, Description) func NewLDAPBoolean(classType Class, tagType Type, tag Tag, value bool, description string) *Packet {
intValue := int64(0)
p.Value = Value if value {
switch v := Value.(type) { intValue = 255
}
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: case int:
p.Data.Write(encodeInteger(int64(v))) p.Data.Write(encodeInteger(int64(v)))
case uint: case uint:
@ -502,11 +583,38 @@ func NewInteger(ClassType Class, TagType Type, Tag Tag, Value interface{}, Descr
return p return p
} }
func NewString(ClassType Class, TagType Type, Tag Tag, Value, Description string) *Packet { func NewString(classType Class, tagType Type, tag Tag, value, description string) *Packet {
p := Encode(ClassType, TagType, Tag, nil, Description) p := Encode(classType, tagType, tag, nil, description)
p.Value = Value p.Value = value
p.Data.Write([]byte(Value)) p.Data.Write([]byte(value))
return p 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
}

View File

@ -6,7 +6,7 @@ func encodeUnsignedInteger(i uint64) []byte {
var j int var j int
for ; n > 0; n-- { for ; n > 0; n-- {
out[j] = (byte(i >> uint((n-1)*8))) out[j] = byte(i >> uint((n-1)*8))
j++ j++
} }

View File

@ -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 <minute> is omitted, then <fraction> represents a fraction of an
// hour; otherwise, if <second> and <leap-second> are omitted, then
// <fraction> represents a fraction of a minute; otherwise, <fraction>
// 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
}

3
vendor/github.com/go-asn1-ber/asn1-ber/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/go-asn1-ber/asn1-ber
go 1.13

View File

@ -7,19 +7,22 @@ import (
) )
func readHeader(reader io.Reader) (identifier Identifier, length int, read int, err error) { func readHeader(reader io.Reader) (identifier Identifier, length int, read int, err error) {
if i, c, err := readIdentifier(reader); err != nil { var (
return Identifier{}, 0, read, err c, l int
} else { i Identifier
identifier = i )
read += c
}
if l, c, err := readLength(reader); err != nil { if i, c, err = readIdentifier(reader); err != nil {
return Identifier{}, 0, read, err 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) // Validate length type with identifier (x.600, 8.1.3.2.a)
if length == LengthIndefinite && identifier.TagType == TypePrimitive { if length == LengthIndefinite && identifier.TagType == TypePrimitive {

View File

@ -71,11 +71,11 @@ func readLength(reader io.Reader) (length int, read int, err error) {
} }
func encodeLength(length int) []byte { func encodeLength(length int) []byte {
length_bytes := encodeUnsignedInteger(uint64(length)) lengthBytes := encodeUnsignedInteger(uint64(length))
if length > 127 || len(length_bytes) > 1 { if length > 127 || len(lengthBytes) > 1 {
longFormBytes := []byte{(LengthLongFormBitmask | byte(len(length_bytes)))} longFormBytes := []byte{LengthLongFormBitmask | byte(len(lengthBytes))}
longFormBytes = append(longFormBytes, length_bytes...) longFormBytes = append(longFormBytes, lengthBytes...)
length_bytes = longFormBytes lengthBytes = longFormBytes
} }
return length_bytes return lengthBytes
} }

157
vendor/github.com/go-asn1-ber/asn1-ber/real.go generated vendored Normal file
View File

@ -0,0 +1,157 @@
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:
expLen = int(v[0])
if expLen > 8 {
return 0.0, errors.New("too big value of exponent")
}
v = v[1:]
}
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`)
}

View File

@ -3,7 +3,7 @@ package ber
import "io" import "io"
func readByte(reader io.Reader) (byte, error) { func readByte(reader io.Reader) (byte, error) {
bytes := make([]byte, 1, 1) bytes := make([]byte, 1)
_, err := io.ReadFull(reader, bytes) _, err := io.ReadFull(reader, bytes)
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {

View File

@ -1,18 +1,9 @@
//
// https://tools.ietf.org/html/rfc4511
//
// AddRequest ::= [APPLICATION 8] SEQUENCE {
// entry LDAPDN,
// attributes AttributeList }
//
// AttributeList ::= SEQUENCE OF attribute Attribute
package ldap package ldap
import ( import (
"log" "log"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
// Attribute represents an LDAP attribute // Attribute represents an LDAP attribute

540
vendor/github.com/go-ldap/ldap/v3/bind.go generated vendored Normal file
View File

@ -0,0 +1,540 @@
package ldap
import (
"bytes"
"crypto/md5"
enchex "encoding/hex"
"errors"
"fmt"
"io/ioutil"
"math/rand"
"strings"
"github.com/Azure/go-ntlmssp"
ber "github.com/go-asn1-ber/asn1-ber"
)
// SimpleBindRequest represents a username/password bind operation
type SimpleBindRequest struct {
// Username is the name of the Directory object that the client wishes to bind as
Username string
// Password is the credentials to bind with
Password string
// Controls are optional controls to send with the bind request
Controls []Control
// AllowEmptyPassword sets whether the client allows binding with an empty password
// (normally used for unauthenticated bind).
AllowEmptyPassword bool
}
// SimpleBindResult contains the response from the server
type SimpleBindResult struct {
Controls []Control
}
// NewSimpleBindRequest returns a bind request
func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest {
return &SimpleBindRequest{
Username: username,
Password: password,
Controls: controls,
AllowEmptyPassword: false,
}
}
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"))
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
func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) {
if simpleBindRequest.Password == "" && !simpleBindRequest.AllowEmptyPassword {
return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client"))
}
msgCtx, err := l.doRequest(simpleBindRequest)
if err != nil {
return nil, err
}
defer l.finishMessage(msgCtx)
packet, err := l.readPacket(msgCtx)
if err != nil {
return nil, err
}
result := &SimpleBindResult{
Controls: make([]Control, 0),
}
if len(packet.Children) == 3 {
for _, child := range packet.Children[2].Children {
decodedChild, decodeErr := DecodeControl(child)
if decodeErr != nil {
return nil, fmt.Errorf("failed to decode child control: %s", decodeErr)
}
result.Controls = append(result.Controls, decodedChild)
}
}
err = GetLDAPError(packet)
return result, err
}
// Bind performs a bind with the given username and password.
//
// It does not allow unauthenticated bind (i.e. empty password). Use the UnauthenticatedBind method
// for that.
func (l *Conn) Bind(username, password string) error {
req := &SimpleBindRequest{
Username: username,
Password: password,
AllowEmptyPassword: false,
}
_, err := l.SimpleBind(req)
return err
}
// UnauthenticatedBind performs an unauthenticated bind.
//
// A username may be provided for trace (e.g. logging) purpose only, but it is normally not
// authenticated or otherwise validated by the LDAP server.
//
// See https://tools.ietf.org/html/rfc4513#section-5.1.2 .
// See https://tools.ietf.org/html/rfc4513#section-6.3.1 .
func (l *Conn) UnauthenticatedBind(username string) error {
req := &SimpleBindRequest{
Username: username,
Password: "",
AllowEmptyPassword: true,
}
_, err := l.SimpleBind(req)
return err
}
// DigestMD5BindRequest represents a digest-md5 bind operation
type DigestMD5BindRequest struct {
Host string
// Username is the name of the Directory object that the client wishes to bind as
Username string
// Password is the credentials to bind with
Password string
// Controls are optional controls to send with the bind request
Controls []Control
}
func (req *DigestMD5BindRequest) appendTo(envelope *ber.Packet) error {
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, "", "User Name"))
auth := ber.Encode(ber.ClassContext, ber.TypeConstructed, 3, "", "authentication")
auth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "DIGEST-MD5", "SASL Mech"))
request.AppendChild(auth)
envelope.AppendChild(request)
if len(req.Controls) > 0 {
envelope.AppendChild(encodeControls(req.Controls))
}
return nil
}
// DigestMD5BindResult contains the response from the server
type DigestMD5BindResult struct {
Controls []Control
}
// MD5Bind performs a digest-md5 bind with the given host, username and password.
func (l *Conn) MD5Bind(host, username, password string) error {
req := &DigestMD5BindRequest{
Host: host,
Username: username,
Password: password,
}
_, err := l.DigestMD5Bind(req)
return err
}
// DigestMD5Bind performs the digest-md5 bind operation defined in the given request
func (l *Conn) DigestMD5Bind(digestMD5BindRequest *DigestMD5BindRequest) (*DigestMD5BindResult, error) {
if digestMD5BindRequest.Password == "" {
return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client"))
}
msgCtx, err := l.doRequest(digestMD5BindRequest)
if err != nil {
return nil, err
}
defer l.finishMessage(msgCtx)
packet, err := l.readPacket(msgCtx)
if err != nil {
return nil, err
}
l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
if l.Debug {
if err = addLDAPDescriptions(packet); err != nil {
return nil, err
}
ber.PrintPacket(packet)
}
result := &DigestMD5BindResult{
Controls: make([]Control, 0),
}
var params map[string]string
if len(packet.Children) == 2 {
if len(packet.Children[1].Children) == 4 {
child := packet.Children[1].Children[0]
if child.Tag != ber.TagEnumerated {
return result, GetLDAPError(packet)
}
if child.Value.(int64) != 14 {
return result, GetLDAPError(packet)
}
child = packet.Children[1].Children[3]
if child.Tag != ber.TagObjectDescriptor {
return result, GetLDAPError(packet)
}
if child.Data == nil {
return result, GetLDAPError(packet)
}
data, _ := ioutil.ReadAll(child.Data)
params, err = parseParams(string(data))
if err != nil {
return result, fmt.Errorf("parsing digest-challenge: %s", err)
}
}
}
if params != nil {
resp := computeResponse(
params,
"ldap/"+strings.ToLower(digestMD5BindRequest.Host),
digestMD5BindRequest.Username,
digestMD5BindRequest.Password,
)
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, 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, "", "User Name"))
auth := ber.Encode(ber.ClassContext, ber.TypeConstructed, 3, "", "authentication")
auth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "DIGEST-MD5", "SASL Mech"))
auth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, resp, "Credentials"))
request.AppendChild(auth)
packet.AppendChild(request)
msgCtx, err = l.sendMessage(packet)
if err != nil {
return nil, fmt.Errorf("send message: %s", 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)
if err != nil {
return nil, fmt.Errorf("read packet: %s", err)
}
}
err = GetLDAPError(packet)
return result, err
}
func parseParams(str string) (map[string]string, error) {
m := make(map[string]string)
var key, value string
var state int
for i := 0; i <= len(str); i++ {
switch state {
case 0: //reading key
if i == len(str) {
return nil, fmt.Errorf("syntax error on %d", i)
}
if str[i] != '=' {
key += string(str[i])
continue
}
state = 1
case 1: //reading value
if i == len(str) {
m[key] = value
break
}
switch str[i] {
case ',':
m[key] = value
state = 0
key = ""
value = ""
case '"':
if value != "" {
return nil, fmt.Errorf("syntax error on %d", i)
}
state = 2
default:
value += string(str[i])
}
case 2: //inside quotes
if i == len(str) {
return nil, fmt.Errorf("syntax error on %d", i)
}
if str[i] != '"' {
value += string(str[i])
} else {
state = 1
}
}
}
return m, nil
}
func computeResponse(params map[string]string, uri, username, password string) string {
nc := "00000001"
qop := "auth"
cnonce := enchex.EncodeToString(randomBytes(16))
x := username + ":" + params["realm"] + ":" + password
y := md5Hash([]byte(x))
a1 := bytes.NewBuffer(y)
a1.WriteString(":" + params["nonce"] + ":" + cnonce)
if len(params["authzid"]) > 0 {
a1.WriteString(":" + params["authzid"])
}
a2 := bytes.NewBuffer([]byte("AUTHENTICATE"))
a2.WriteString(":" + uri)
ha1 := enchex.EncodeToString(md5Hash(a1.Bytes()))
ha2 := enchex.EncodeToString(md5Hash(a2.Bytes()))
kd := ha1
kd += ":" + params["nonce"]
kd += ":" + nc
kd += ":" + cnonce
kd += ":" + qop
kd += ":" + ha2
resp := enchex.EncodeToString(md5Hash([]byte(kd)))
return fmt.Sprintf(
`username="%s",realm="%s",nonce="%s",cnonce="%s",nc=00000001,qop=%s,digest-uri="%s",response=%s`,
username,
params["realm"],
params["nonce"],
cnonce,
qop,
uri,
resp,
)
}
func md5Hash(b []byte) []byte {
hasher := md5.New()
hasher.Write(b)
return hasher.Sum(nil)
}
func randomBytes(len int) []byte {
b := make([]byte, len)
for i := 0; i < len; i++ {
b[i] = byte(rand.Intn(256))
}
return b
}
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)
}
// NTLMBind performs an NTLMSSP bind leveraging https://github.com/Azure/go-ntlmssp
// NTLMBindRequest represents an NTLMSSP bind operation
type NTLMBindRequest struct {
// Domain is the AD Domain to authenticate too. If not specified, it will be grabbed from the NTLMSSP Challenge
Domain string
// Username is the name of the Directory object that the client wishes to bind as
Username string
// Password is the credentials to bind with
Password string
// Hash is the hex NTLM hash to bind with. Password or hash must be provided
Hash string
// Controls are optional controls to send with the bind request
Controls []Control
}
func (req *NTLMBindRequest) appendTo(envelope *ber.Packet) error {
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, "", "User Name"))
// generate an NTLMSSP Negotiation message for the specified domain (it can be blank)
negMessage, err := ntlmssp.NewNegotiateMessage(req.Domain, "")
if err != nil {
return fmt.Errorf("err creating negmessage: %s", err)
}
// append the generated NTLMSSP message as a TagEnumerated BER value
auth := ber.Encode(ber.ClassContext, ber.TypePrimitive, ber.TagEnumerated, negMessage, "authentication")
request.AppendChild(auth)
envelope.AppendChild(request)
if len(req.Controls) > 0 {
envelope.AppendChild(encodeControls(req.Controls))
}
return nil
}
// NTLMBindResult contains the response from the server
type NTLMBindResult struct {
Controls []Control
}
// NTLMBind performs an NTLMSSP Bind with the given domain, username and password
func (l *Conn) NTLMBind(domain, username, password string) error {
req := &NTLMBindRequest{
Domain: domain,
Username: username,
Password: password,
}
_, err := l.NTLMChallengeBind(req)
return err
}
// NTLMBindWithHash performs an NTLM Bind with an NTLM hash instead of plaintext password (pass-the-hash)
func (l *Conn) NTLMBindWithHash(domain, username, hash string) error {
req := &NTLMBindRequest{
Domain: domain,
Username: username,
Hash: hash,
}
_, err := l.NTLMChallengeBind(req)
return err
}
// NTLMChallengeBind performs the NTLMSSP bind operation defined in the given request
func (l *Conn) NTLMChallengeBind(ntlmBindRequest *NTLMBindRequest) (*NTLMBindResult, error) {
if ntlmBindRequest.Password == "" && ntlmBindRequest.Hash == "" {
return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client"))
}
msgCtx, err := l.doRequest(ntlmBindRequest)
if err != nil {
return nil, err
}
defer l.finishMessage(msgCtx)
packet, err := l.readPacket(msgCtx)
if err != nil {
return nil, err
}
l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
if l.Debug {
if err = addLDAPDescriptions(packet); err != nil {
return nil, err
}
ber.PrintPacket(packet)
}
result := &NTLMBindResult{
Controls: make([]Control, 0),
}
var ntlmsspChallenge []byte
// now find the NTLM Response Message
if len(packet.Children) == 2 {
if len(packet.Children[1].Children) == 3 {
child := packet.Children[1].Children[1]
ntlmsspChallenge = child.ByteValue
// Check to make sure we got the right message. It will always start with NTLMSSP
if !bytes.Equal(ntlmsspChallenge[:7], []byte("NTLMSSP")) {
return result, GetLDAPError(packet)
}
l.Debug.Printf("%d: found ntlmssp challenge", msgCtx.id)
}
}
if ntlmsspChallenge != nil {
var err error
var responseMessage []byte
// generate a response message to the challenge with the given Username/Password if password is provided
if ntlmBindRequest.Password != "" {
responseMessage, err = ntlmssp.ProcessChallenge(ntlmsspChallenge, ntlmBindRequest.Username, ntlmBindRequest.Password)
} else if ntlmBindRequest.Hash != "" {
responseMessage, err = ntlmssp.ProcessChallengeWithHash(ntlmsspChallenge, ntlmBindRequest.Username, ntlmBindRequest.Hash)
} else {
err = fmt.Errorf("need a password or hash to generate reply")
}
if err != nil {
return result, fmt.Errorf("parsing ntlm-challenge: %s", err)
}
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, 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, "", "User Name"))
// append the challenge response message as a TagEmbeddedPDV BER value
auth := ber.Encode(ber.ClassContext, ber.TypePrimitive, ber.TagEmbeddedPDV, responseMessage, "authentication")
request.AppendChild(auth)
packet.AppendChild(request)
msgCtx, err = l.sendMessage(packet)
if err != nil {
return nil, fmt.Errorf("send message: %s", 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)
if err != nil {
return nil, fmt.Errorf("read packet: %s", err)
}
}
err = GetLDAPError(packet)
return result, err
}

View File

@ -1,28 +1,9 @@
// 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 <attributedescription>
// -- [RFC4512]
//
// AttributeValue ::= OCTET STRING
//
package ldap package ldap
import ( import (
"fmt" "fmt"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
// CompareRequest represents an LDAP CompareRequest operation. // CompareRequest represents an LDAP CompareRequest operation.

View File

@ -11,7 +11,7 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
const ( const (
@ -112,8 +112,63 @@ var _ Client = &Conn{}
// multiple places will probably result in undesired behaviour. // multiple places will probably result in undesired behaviour.
var DefaultTimeout = 60 * time.Second 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 assume 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 // Dial connects to the given address on the given network using net.Dial
// and then returns a new Conn for the connection. // and then returns a new Conn for the connection.
// @deprecated Use DialURL instead.
func Dial(network, addr string) (*Conn, error) { func Dial(network, addr string) (*Conn, error) {
c, err := net.DialTimeout(network, addr, DefaultTimeout) c, err := net.DialTimeout(network, addr, DefaultTimeout)
if err != nil { 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 // DialTLS connects to the given address on the given network using tls.Dial
// and then returns a new Conn for the connection. // and then returns a new Conn for the connection.
// @deprecated Use DialURL instead.
func DialTLS(network, addr string, config *tls.Config) (*Conn, error) { func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
c, err := tls.DialWithDialer(&net.Dialer{Timeout: DefaultTimeout}, network, addr, config) c, err := tls.DialWithDialer(&net.Dialer{Timeout: DefaultTimeout}, network, addr, config)
if err != nil { if err != nil {
@ -136,44 +192,31 @@ func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
return conn, nil return conn, nil
} }
// DialURL connects to the given ldap URL vie TCP using tls.Dial or net.Dial if ldaps:// // DialURL connects to the given ldap URL.
// or ldap:// specified as protocol. On success a new Conn for the connection // The following schemas are supported: ldap://, ldaps://, ldapi://.
// is returned. // On success a new Conn for the connection is returned.
func DialURL(addr string) (*Conn, error) { func DialURL(addr string, opts ...DialOpt) (*Conn, error) {
lurl, err := url.Parse(addr) u, err := url.Parse(addr)
if err != nil { if err != nil {
return nil, NewError(ErrorNetwork, err) 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 { if err != nil {
// we asume that error is due to missing port return nil, NewError(ErrorNetwork, err)
host = lurl.Host
port = ""
} }
switch lurl.Scheme { conn := NewConn(c, u.Scheme == "ldaps")
case "ldapi": conn.Start()
if lurl.Path == "" || lurl.Path == "/" { return conn, nil
lurl.Path = "/var/run/slapd/ldapi"
}
return Dial("unix", lurl.Path)
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))
} }
// NewConn returns a new Conn using conn for network I/O. // NewConn returns a new Conn using conn for network I/O.
@ -191,9 +234,9 @@ func NewConn(conn net.Conn, isTLS bool) *Conn {
// Start initializes goroutines to read responses and process messages // Start initializes goroutines to read responses and process messages
func (l *Conn) Start() { func (l *Conn) Start() {
l.wgClose.Add(1)
go l.reader() go l.reader()
go l.processMessages() go l.processMessages()
l.wgClose.Add(1)
} }
// IsClosing returns whether or not we're currently closing. // IsClosing returns whether or not we're currently closing.
@ -278,7 +321,7 @@ func (l *Conn) StartTLS(config *tls.Config) error {
l.Close() l.Close()
return err return err
} }
ber.PrintPacket(packet) l.Debug.PrintPacket(packet)
} }
if err := GetLDAPError(packet); err == nil { if err := GetLDAPError(packet); err == nil {
@ -347,7 +390,12 @@ func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags)
responses: responses, responses: responses,
}, },
} }
l.sendProcessMessage(message) if !l.sendProcessMessage(message) {
if l.IsClosing() {
return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed"))
}
return nil, NewError(ErrorNetwork, errors.New("ldap: could not send message for unknown reason"))
}
return message.Context, nil return message.Context, nil
} }
@ -451,7 +499,7 @@ func (l *Conn) processMessages() {
msgCtx.sendResponse(&PacketResponse{message.Packet, nil}) msgCtx.sendResponse(&PacketResponse{message.Packet, nil})
} else { } else {
log.Printf("Received unexpected message %d, %v", message.MessageID, l.IsClosing()) log.Printf("Received unexpected message %d, %v", message.MessageID, l.IsClosing())
ber.PrintPacket(message.Packet) l.Debug.PrintPacket(message.Packet)
} }
case MessageTimeout: case MessageTimeout:
// Handle the timeout by closing the channel // Handle the timeout by closing the channel

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
const ( const (
@ -404,33 +404,26 @@ func DecodeControl(packet *ber.Packet) (Control, error) {
if child.Tag == 0 { if child.Tag == 0 {
//Warning //Warning
warningPacket := child.Children[0] warningPacket := child.Children[0]
packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes()) val, err := ber.ParseInt64(warningPacket.Data.Bytes())
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to decode data bytes: %s", err) return nil, fmt.Errorf("failed to decode data bytes: %s", err)
} }
val, ok := packet.Value.(int64) if warningPacket.Tag == 0 {
if ok { //timeBeforeExpiration
if warningPacket.Tag == 0 { c.Expire = val
//timeBeforeExpiration warningPacket.Value = c.Expire
c.Expire = val } else if warningPacket.Tag == 1 {
warningPacket.Value = c.Expire //graceAuthNsRemaining
} else if warningPacket.Tag == 1 { c.Grace = val
//graceAuthNsRemaining warningPacket.Value = c.Grace
c.Grace = val
warningPacket.Value = c.Grace
}
} }
} else if child.Tag == 1 { } else if child.Tag == 1 {
// Error // Error
packet, err := ber.DecodePacketErr(child.Data.Bytes()) bs := child.Data.Bytes()
if err != nil { if len(bs) != 1 || bs[0] > 8 {
return nil, fmt.Errorf("failed to decode data bytes: %s", err) return nil, fmt.Errorf("failed to decode data bytes: %s", "invalid PasswordPolicyResponse enum value")
}
val, ok := packet.Value.(int8)
if !ok {
// what to do?
val = -1
} }
val := int8(bs[0])
c.Error = val c.Error = val
child.Value = c.Error child.Value = c.Error
c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error] c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error]

View File

@ -3,7 +3,7 @@ package ldap
import ( import (
"log" "log"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
// debugging type // debugging type

View File

@ -1,14 +1,9 @@
//
// https://tools.ietf.org/html/rfc4511
//
// DelRequest ::= [APPLICATION 10] LDAPDN
package ldap package ldap
import ( import (
"log" "log"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
// DelRequest implements an LDAP deletion request // DelRequest implements an LDAP deletion request

View File

@ -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 <escaped>, 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 <descr>, <numericoid>, <COMMA>, <DQUOTE>,
// <EQUALS>, <ESC>, <HEX>, <LANGLE>, <NULL>, <PLUS>, <RANGLE>, <SEMI>,
// <SPACE>, <SHARP>, and <UTFMB> are defined in [RFC4512].
//
package ldap package ldap
import ( import (
@ -48,7 +7,7 @@ import (
"fmt" "fmt"
"strings" "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 // AttributeTypeAndValue represents an attributeTypeAndValue from https://tools.ietf.org/html/rfc4514
@ -69,7 +28,8 @@ type DN struct {
RDNs []*RelativeDN 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) { func ParseDN(str string) (*DN, error) {
dn := new(DN) dn := new(DN)
dn.RDNs = make([]*RelativeDN, 0) dn.RDNs = make([]*RelativeDN, 0)

View File

@ -3,7 +3,7 @@ package ldap
import ( import (
"fmt" "fmt"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
// LDAP Result Codes // LDAP Result Codes
@ -184,6 +184,8 @@ type Error struct {
ResultCode uint16 ResultCode uint16
// MatchedDN is the matchedDN returned if any // MatchedDN is the matchedDN returned if any
MatchedDN string MatchedDN string
// Packet is the returned packet if any
Packet *ber.Packet
} }
func (e *Error) Error() string { func (e *Error) Error() string {
@ -201,19 +203,23 @@ func GetLDAPError(packet *ber.Packet) error {
if len(packet.Children) >= 2 { if len(packet.Children) >= 2 {
response := packet.Children[1] response := packet.Children[1]
if response == nil { if response == nil {
return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty response in packet")} return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty response in packet"), Packet: packet}
} }
if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 { if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
resultCode := uint16(response.Children[0].Value.(int64)) resultCode := uint16(response.Children[0].Value.(int64))
if resultCode == 0 { // No error if resultCode == 0 { // No error
return nil return nil
} }
return &Error{ResultCode: resultCode, MatchedDN: response.Children[1].Value.(string), return &Error{
Err: fmt.Errorf("%s", response.Children[2].Value.(string))} ResultCode: resultCode,
MatchedDN: response.Children[1].Value.(string),
Err: fmt.Errorf("%s", response.Children[2].Value.(string)),
Packet: packet,
}
} }
} }
return &Error{ResultCode: ErrorNetwork, Err: fmt.Errorf("Invalid packet format")} return &Error{ResultCode: ErrorNetwork, Err: fmt.Errorf("Invalid packet format"), Packet: packet}
} }
// NewError creates an LDAP error with the given code and underlying error // NewError creates an LDAP error with the given code and underlying error
@ -221,8 +227,8 @@ func NewError(resultCode uint16, err error) error {
return &Error{ResultCode: resultCode, Err: err} return &Error{ResultCode: resultCode, Err: err}
} }
// IsErrorWithCode returns true if the given error is an LDAP error with the given result code // IsErrorAnyOf returns true if the given error is an LDAP error with any one of the given result codes
func IsErrorWithCode(err error, desiredResultCode uint16) bool { func IsErrorAnyOf(err error, codes ...uint16) bool {
if err == nil { if err == nil {
return false return false
} }
@ -232,5 +238,16 @@ func IsErrorWithCode(err error, desiredResultCode uint16) bool {
return false return false
} }
return serverError.ResultCode == desiredResultCode for _, code := range codes {
if serverError.ResultCode == code {
return true
}
}
return false
}
// IsErrorWithCode returns true if the given error is an LDAP error with the given result code
func IsErrorWithCode(err error, desiredResultCode uint16) bool {
return IsErrorAnyOf(err, desiredResultCode)
} }

View File

@ -5,10 +5,12 @@ import (
hexpac "encoding/hex" hexpac "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"io"
"strings" "strings"
"unicode"
"unicode/utf8" "unicode/utf8"
"gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
// Filter choices // Filter choices
@ -69,6 +71,8 @@ var MatchingRuleAssertionMap = map[uint64]string{
MatchingRuleAssertionDNAttributes: "Matching Rule Assertion DN Attributes", MatchingRuleAssertionDNAttributes: "Matching Rule Assertion DN Attributes",
} }
var _SymbolAny = []byte{'*'}
// CompileFilter converts a string representation of a filter into a BER-encoded packet // CompileFilter converts a string representation of a filter into a BER-encoded packet
func CompileFilter(filter string) (*ber.Packet, error) { func CompileFilter(filter string) (*ber.Packet, error) {
if len(filter) == 0 || filter[0] != '(' { 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 // 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() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
err = NewError(ErrorFilterDecompile, errors.New("ldap: error decompiling filter")) err = NewError(ErrorFilterDecompile, errors.New("ldap: error decompiling filter"))
} }
}() }()
ret = "("
err = nil buf := bytes.NewBuffer(nil)
buf.WriteByte('(')
childStr := "" childStr := ""
switch packet.Tag { switch packet.Tag {
case FilterAnd: case FilterAnd:
ret += "&" buf.WriteByte('&')
for _, child := range packet.Children { for _, child := range packet.Children {
childStr, err = DecompileFilter(child) childStr, err = DecompileFilter(child)
if err != nil { if err != nil {
return return
} }
ret += childStr buf.WriteString(childStr)
} }
case FilterOr: case FilterOr:
ret += "|" buf.WriteByte('|')
for _, child := range packet.Children { for _, child := range packet.Children {
childStr, err = DecompileFilter(child) childStr, err = DecompileFilter(child)
if err != nil { if err != nil {
return return
} }
ret += childStr buf.WriteString(childStr)
} }
case FilterNot: case FilterNot:
ret += "!" buf.WriteByte('!')
childStr, err = DecompileFilter(packet.Children[0]) childStr, err = DecompileFilter(packet.Children[0])
if err != nil { if err != nil {
return return
} }
ret += childStr buf.WriteString(childStr)
case FilterSubstrings: case FilterSubstrings:
ret += ber.DecodeString(packet.Children[0].Data.Bytes()) buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes()))
ret += "=" buf.WriteByte('=')
for i, child := range packet.Children[1].Children { for i, child := range packet.Children[1].Children {
if i == 0 && child.Tag != FilterSubstringsInitial { 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 { if child.Tag != FilterSubstringsFinal {
ret += "*" buf.Write(_SymbolAny)
} }
} }
case FilterEqualityMatch: case FilterEqualityMatch:
ret += ber.DecodeString(packet.Children[0].Data.Bytes()) buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes()))
ret += "=" buf.WriteByte('=')
ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())))
case FilterGreaterOrEqual: case FilterGreaterOrEqual:
ret += ber.DecodeString(packet.Children[0].Data.Bytes()) buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes()))
ret += ">=" buf.WriteString(">=")
ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())))
case FilterLessOrEqual: case FilterLessOrEqual:
ret += ber.DecodeString(packet.Children[0].Data.Bytes()) buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes()))
ret += "<=" buf.WriteString("<=")
ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())))
case FilterPresent: case FilterPresent:
ret += ber.DecodeString(packet.Data.Bytes()) buf.WriteString(ber.DecodeString(packet.Data.Bytes()))
ret += "=*" buf.WriteString("=*")
case FilterApproxMatch: case FilterApproxMatch:
ret += ber.DecodeString(packet.Children[0].Data.Bytes()) buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes()))
ret += "~=" buf.WriteString("~=")
ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())))
case FilterExtensibleMatch: case FilterExtensibleMatch:
attr := "" attr := ""
dnAttributes := false dnAttributes := false
@ -176,21 +181,22 @@ func DecompileFilter(packet *ber.Packet) (ret string, err error) {
} }
if len(attr) > 0 { if len(attr) > 0 {
ret += attr buf.WriteString(attr)
} }
if dnAttributes { if dnAttributes {
ret += ":dn" buf.WriteString(":dn")
} }
if len(matchingRule) > 0 { if len(matchingRule) > 0 {
ret += ":" buf.WriteString(":")
ret += matchingRule buf.WriteString(matchingRule)
} }
ret += ":=" buf.WriteString(":=")
ret += EscapeFilter(value) buf.WriteString(EscapeFilter(value))
} }
ret += ")" buf.WriteByte(')')
return
return buf.String(), nil
} }
func compileFilterSet(filter string, pos int, parent *ber.Packet) (int, error) { 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 state := stateReadingAttr
attribute := bytes.NewBuffer(nil)
attribute := ""
extensibleDNAttributes := false extensibleDNAttributes := false
extensibleMatchingRule := "" extensibleMatchingRule := bytes.NewBuffer(nil)
condition := "" condition := bytes.NewBuffer(nil)
for newPos < len(filter) { for newPos < len(filter) {
remainingFilter := filter[newPos:] remainingFilter := filter[newPos:]
@ -324,7 +329,7 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
// Still reading the attribute name // Still reading the attribute name
default: default:
attribute += fmt.Sprintf("%c", currentRune) attribute.WriteRune(currentRune)
newPos += currentWidth newPos += currentWidth
} }
@ -338,13 +343,13 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
// Still reading the matching rule oid // Still reading the matching rule oid
default: default:
extensibleMatchingRule += fmt.Sprintf("%c", currentRune) extensibleMatchingRule.WriteRune(currentRune)
newPos += currentWidth newPos += currentWidth
} }
case stateReadingCondition: case stateReadingCondition:
// append to the condition // append to the condition
condition += fmt.Sprintf("%c", currentRune) condition.WriteRune(currentRune)
newPos += currentWidth newPos += currentWidth
} }
} }
@ -368,17 +373,17 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
// } // }
// Include the matching rule oid, if specified // Include the matching rule oid, if specified
if len(extensibleMatchingRule) > 0 { if extensibleMatchingRule.Len() > 0 {
packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchingRule, extensibleMatchingRule, MatchingRuleAssertionMap[MatchingRuleAssertionMatchingRule])) packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchingRule, extensibleMatchingRule.String(), MatchingRuleAssertionMap[MatchingRuleAssertionMatchingRule]))
} }
// Include the attribute, if specified // Include the attribute, if specified
if len(attribute) > 0 { if attribute.Len() > 0 {
packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionType, attribute, MatchingRuleAssertionMap[MatchingRuleAssertionType])) packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionType, attribute.String(), MatchingRuleAssertionMap[MatchingRuleAssertionType]))
} }
// Add the value (only required child) // Add the value (only required child)
encodedString, encodeErr := escapedStringToEncodedBytes(condition) encodedString, encodeErr := decodeEscapedSymbols(condition.Bytes())
if encodeErr != nil { if encodeErr != nil {
return packet, newPos, encodeErr 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])) packet.AppendChild(ber.NewBoolean(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionDNAttributes, extensibleDNAttributes, MatchingRuleAssertionMap[MatchingRuleAssertionDNAttributes]))
} }
case packet.Tag == FilterEqualityMatch && condition == "*": case packet.Tag == FilterEqualityMatch && bytes.Equal(condition.Bytes(), _SymbolAny):
packet = ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterPresent, attribute, FilterMap[FilterPresent]) packet = ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterPresent, attribute.String(), FilterMap[FilterPresent])
case packet.Tag == FilterEqualityMatch && strings.Contains(condition, "*"): case packet.Tag == FilterEqualityMatch && bytes.Index(condition.Bytes(), _SymbolAny) > -1:
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.Tag = FilterSubstrings packet.Tag = FilterSubstrings
packet.Description = FilterMap[uint64(packet.Tag)] packet.Description = FilterMap[uint64(packet.Tag)]
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings") 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 { for i, part := range parts {
if part == "" { if len(part) == 0 {
continue continue
} }
var tag ber.Tag var tag ber.Tag
@ -410,7 +415,7 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
default: default:
tag = FilterSubstringsAny tag = FilterSubstringsAny
} }
encodedString, encodeErr := escapedStringToEncodedBytes(part) encodedString, encodeErr := decodeEscapedSymbols(part)
if encodeErr != nil { if encodeErr != nil {
return packet, newPos, encodeErr return packet, newPos, encodeErr
} }
@ -418,11 +423,11 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
} }
packet.AppendChild(seq) packet.AppendChild(seq)
default: default:
encodedString, encodeErr := escapedStringToEncodedBytes(condition) encodedString, encodeErr := decodeEscapedSymbols(condition.Bytes())
if encodeErr != nil { if encodeErr != nil {
return packet, newPos, encodeErr 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")) 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 // Convert from "ABC\xx\xx\xx" form to literal bytes for transport
func escapedStringToEncodedBytes(escapedString string) (string, error) { func decodeEscapedSymbols(src []byte) (string, error) {
var buffer bytes.Buffer
i := 0 var (
for i < len(escapedString) { buffer bytes.Buffer
currentRune, currentWidth := utf8.DecodeRuneInString(escapedString[i:]) offset int
if currentRune == utf8.RuneError { reader = bytes.NewReader(src)
return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", i)) 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 runeVal == '\\' {
if currentRune == '\\' {
// http://tools.ietf.org/search/rfc4515 // http://tools.ietf.org/search/rfc4515
// \ (%x5C) is not a valid character unless it is followed by two HEX characters due to not // \ (%x5C) is not a valid character unless it is followed by two HEX characters due to not
// being a member of UTF1SUBSET. // being a member of UTF1SUBSET.
if i+2 > len(escapedString) { if byteHex == nil {
return "", NewError(ErrorFilterCompile, errors.New("ldap: missing characters for escape in filter")) byteHex = make([]byte, 2)
byteVal = make([]byte, 1)
} }
escByte, decodeErr := hexpac.DecodeString(escapedString[i+1 : i+3])
if decodeErr != nil { if _, err := io.ReadFull(reader, byteHex); err != nil {
return "", NewError(ErrorFilterCompile, errors.New("ldap: invalid characters for escape in filter")) 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 { } else {
buffer.WriteRune(currentRune) buffer.WriteRune(runeVal)
} }
i += currentWidth offset += runeSize
} }
return buffer.String(), nil
} }

9
vendor/github.com/go-ldap/ldap/v3/go.mod generated vendored Normal file
View File

@ -0,0 +1,9 @@
module github.com/go-ldap/ldap/v3
go 1.13
require (
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c
github.com/go-asn1-ber/asn1-ber v1.5.1
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 // indirect
)

11
vendor/github.com/go-ldap/ldap/v3/go.sum generated vendored Normal file
View File

@ -0,0 +1,11 @@
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28=
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -5,7 +5,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
// LDAP Application Codes // LDAP Application Codes
@ -223,32 +223,26 @@ func addControlDescriptions(packet *ber.Packet) error {
if child.Tag == 0 { if child.Tag == 0 {
//Warning //Warning
warningPacket := child.Children[0] warningPacket := child.Children[0]
packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes()) val, err := ber.ParseInt64(warningPacket.Data.Bytes())
if err != nil { if err != nil {
return fmt.Errorf("failed to decode data bytes: %s", err) return fmt.Errorf("failed to decode data bytes: %s", err)
} }
val, ok := packet.Value.(int64) if warningPacket.Tag == 0 {
if ok { //timeBeforeExpiration
if warningPacket.Tag == 0 { value.Description += " (TimeBeforeExpiration)"
//timeBeforeExpiration warningPacket.Value = val
value.Description += " (TimeBeforeExpiration)" } else if warningPacket.Tag == 1 {
warningPacket.Value = val //graceAuthNsRemaining
} else if warningPacket.Tag == 1 { value.Description += " (GraceAuthNsRemaining)"
//graceAuthNsRemaining warningPacket.Value = val
value.Description += " (GraceAuthNsRemaining)"
warningPacket.Value = val
}
} }
} else if child.Tag == 1 { } else if child.Tag == 1 {
// Error // Error
packet, err := ber.DecodePacketErr(child.Data.Bytes()) bs := child.Data.Bytes()
if err != nil { if len(bs) != 1 || bs[0] > 8 {
return fmt.Errorf("failed to decode data bytes: %s", err) return fmt.Errorf("failed to decode data bytes: %s", "invalid PasswordPolicyResponse enum value")
}
val, ok := packet.Value.(int8)
if !ok {
val = -1
} }
val := int8(bs[0])
child.Description = "Error" child.Description = "Error"
child.Value = val child.Value = val
} }
@ -269,13 +263,18 @@ func addRequestDescriptions(packet *ber.Packet) error {
} }
func addDefaultLDAPResponseDescriptions(packet *ber.Packet) error { func addDefaultLDAPResponseDescriptions(packet *ber.Packet) error {
err := GetLDAPError(packet) resultCode := uint16(LDAPResultSuccess)
if err == nil { matchedDN := ""
return nil description := "Success"
if err := GetLDAPError(packet); err != nil {
resultCode = err.(*Error).ResultCode
matchedDN = err.(*Error).MatchedDN
description = "Error Message"
} }
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[0].Description = "Result Code (" + LDAPResultCodeMap[resultCode] + ")"
packet.Children[1].Children[2].Description = "Error Message" packet.Children[1].Children[1].Description = "Matched DN (" + matchedDN + ")"
packet.Children[1].Children[2].Description = description
if len(packet.Children[1].Children) > 3 { if len(packet.Children[1].Children) > 3 {
packet.Children[1].Children[3].Description = "Referral" packet.Children[1].Children[3].Description = "Referral"
} }

View File

@ -1,19 +1,9 @@
// 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 package ldap
import ( import (
"log" "log"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
// ModifyDNRequest holds the request to modify a DN // ModifyDNRequest holds the request to modify a DN
@ -49,7 +39,12 @@ func (req *ModifyDNRequest) appendTo(envelope *ber.Packet) error {
pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyDNRequest, nil, "Modify DN Request") 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.DN, "DN"))
pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.NewRDN, "New RDN")) 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.DeleteOldRDN {
buf := []byte{0xff}
pkt.AppendChild(ber.NewString(ber.ClassUniversal,ber.TypePrimitive,ber.TagBoolean, string(buf),"Delete old RDN"))
}else{
pkt.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, req.DeleteOldRDN, "Delete old RDN"))
}
if req.NewSuperior != "" { if req.NewSuperior != "" {
pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, req.NewSuperior, "New Superior")) pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, req.NewSuperior, "New Superior"))
} }

View File

@ -1,41 +1,17 @@
// File contains Modify functionality
//
// https://tools.ietf.org/html/rfc4511
//
// ModifyRequest ::= [APPLICATION 6] SEQUENCE {
// object LDAPDN,
// changes SEQUENCE OF change SEQUENCE {
// operation ENUMERATED {
// add (0),
// delete (1),
// replace (2),
// ... },
// modification PartialAttribute } }
//
// PartialAttribute ::= SEQUENCE {
// type AttributeDescription,
// vals SET OF value AttributeValue }
//
// AttributeDescription ::= LDAPString
// -- Constrained to <attributedescription>
// -- [RFC4512]
//
// AttributeValue ::= OCTET STRING
//
package ldap package ldap
import ( import (
"log" "log"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
// Change operation choices // Change operation choices
const ( const (
AddAttribute = 0 AddAttribute = 0
DeleteAttribute = 1 DeleteAttribute = 1
ReplaceAttribute = 2 ReplaceAttribute = 2
IncrementAttribute = 3 // (https://tools.ietf.org/html/rfc4525)
) )
// PartialAttribute for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511 // PartialAttribute for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
@ -97,6 +73,11 @@ func (req *ModifyRequest) Replace(attrType string, attrVals []string) {
req.appendChange(ReplaceAttribute, attrType, attrVals) 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) { func (req *ModifyRequest) appendChange(operation uint, attrType string, attrVals []string) {
req.Changes = append(req.Changes, Change{operation, PartialAttribute{Type: attrType, Vals: attrVals}}) req.Changes = append(req.Changes, Change{operation, PartialAttribute{Type: attrType, Vals: attrVals}})
} }

View File

@ -1,14 +1,9 @@
// This file contains the password modify extended operation as specified in rfc 3062
//
// https://tools.ietf.org/html/rfc3062
//
package ldap package ldap
import ( import (
"fmt" "fmt"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
const ( const (
@ -61,7 +56,7 @@ func (req *PasswordModifyRequest) appendTo(envelope *ber.Packet) error {
// NewPasswordModifyRequest creates a new PasswordModifyRequest // 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. // userIdentity is a string representing the user associated with the request.
// This string may or may not be an LDAPDN (RFC 2253). // This string may or may not be an LDAPDN (RFC 2253).
// If userIdentity is empty then the operation will act on the user associated // If userIdentity is empty then the operation will act on the user associated

View File

@ -3,7 +3,7 @@ package ldap
import ( import (
"errors" "errors"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
var ( var (
@ -29,7 +29,7 @@ func (l *Conn) doRequest(req request) (*messageContext, error) {
} }
if l.Debug { if l.Debug {
ber.PrintPacket(packet) l.Debug.PrintPacket(packet)
} }
msgCtx, err := l.sendMessage(packet) msgCtx, err := l.sendMessage(packet)
@ -60,7 +60,7 @@ func (l *Conn) readPacket(msgCtx *messageContext) (*ber.Packet, error) {
if err = addLDAPDescriptions(packet); err != nil { if err = addLDAPDescriptions(packet); err != nil {
return nil, err return nil, err
} }
ber.PrintPacket(packet) l.Debug.PrintPacket(packet)
} }
return packet, nil return packet, nil
} }

View File

@ -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
// -- <attributeSelector> in Section 4.5.1.8
//
// Filter ::= CHOICE {
// and [0] SET SIZE (1..MAX) OF filter Filter,
// or [1] SET SIZE (1..MAX) OF filter Filter,
// not [2] Filter,
// equalityMatch [3] AttributeValueAssertion,
// substrings [4] SubstringFilter,
// greaterOrEqual [5] AttributeValueAssertion,
// lessOrEqual [6] AttributeValueAssertion,
// present [7] AttributeDescription,
// approxMatch [8] AttributeValueAssertion,
// extensibleMatch [9] MatchingRuleAssertion,
// ... }
//
// SubstringFilter ::= SEQUENCE {
// type AttributeDescription,
// substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
// initial [0] AssertionValue, -- can occur at most once
// any [1] AssertionValue,
// final [2] AssertionValue } -- can occur at most once
// }
//
// MatchingRuleAssertion ::= SEQUENCE {
// matchingRule [1] MatchingRuleId OPTIONAL,
// type [2] AttributeDescription OPTIONAL,
// matchValue [3] AssertionValue,
// dnAttributes [4] BOOLEAN DEFAULT FALSE }
//
//
package ldap package ldap
import ( import (
@ -61,7 +6,7 @@ import (
"sort" "sort"
"strings" "strings"
ber "gopkg.in/asn1-ber.v1" ber "github.com/go-asn1-ber/asn1-ber"
) )
// scope choices // scope choices
@ -132,6 +77,17 @@ func (e *Entry) GetAttributeValues(attribute string) []string {
return []string{} return []string{}
} }
// GetEqualFoldAttributeValues returns the values for the named attribute, or an
// empty list. Attribute matching is done with strings.EqualFold.
func (e *Entry) GetEqualFoldAttributeValues(attribute string) []string {
for _, attr := range e.Attributes {
if strings.EqualFold(attribute, attr.Name) {
return attr.Values
}
}
return []string{}
}
// GetRawAttributeValues returns the byte values for the named attribute, or an empty list // GetRawAttributeValues returns the byte values for the named attribute, or an empty list
func (e *Entry) GetRawAttributeValues(attribute string) [][]byte { func (e *Entry) GetRawAttributeValues(attribute string) [][]byte {
for _, attr := range e.Attributes { for _, attr := range e.Attributes {
@ -142,6 +98,16 @@ func (e *Entry) GetRawAttributeValues(attribute string) [][]byte {
return [][]byte{} return [][]byte{}
} }
// GetEqualFoldRawAttributeValues returns the byte values for the named attribute, or an empty list
func (e *Entry) GetEqualFoldRawAttributeValues(attribute string) [][]byte {
for _, attr := range e.Attributes {
if strings.EqualFold(attr.Name, attribute) {
return attr.ByteValues
}
}
return [][]byte{}
}
// GetAttributeValue returns the first value for the named attribute, or "" // GetAttributeValue returns the first value for the named attribute, or ""
func (e *Entry) GetAttributeValue(attribute string) string { func (e *Entry) GetAttributeValue(attribute string) string {
values := e.GetAttributeValues(attribute) values := e.GetAttributeValues(attribute)
@ -151,6 +117,16 @@ func (e *Entry) GetAttributeValue(attribute string) string {
return values[0] return values[0]
} }
// GetEqualFoldAttributeValue returns the first value for the named attribute, or "".
// Attribute comparison is done with strings.EqualFold.
func (e *Entry) GetEqualFoldAttributeValue(attribute string) string {
values := e.GetEqualFoldAttributeValues(attribute)
if len(values) == 0 {
return ""
}
return values[0]
}
// GetRawAttributeValue returns the first value for the named attribute, or an empty slice // GetRawAttributeValue returns the first value for the named attribute, or an empty slice
func (e *Entry) GetRawAttributeValue(attribute string) []byte { func (e *Entry) GetRawAttributeValue(attribute string) []byte {
values := e.GetRawAttributeValues(attribute) values := e.GetRawAttributeValues(attribute)
@ -160,6 +136,15 @@ func (e *Entry) GetRawAttributeValue(attribute string) []byte {
return values[0] return values[0]
} }
// GetEqualFoldRawAttributeValue returns the first value for the named attribute, or an empty slice
func (e *Entry) GetEqualFoldRawAttributeValue(attribute string) []byte {
values := e.GetEqualFoldRawAttributeValues(attribute)
if len(values) == 0 {
return []byte{}
}
return values[0]
}
// Print outputs a human-readable description // Print outputs a human-readable description
func (e *Entry) Print() { func (e *Entry) Print() {
fmt.Printf("DN: %s\n", e.DN) fmt.Printf("DN: %s\n", e.DN)
@ -386,7 +371,7 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
for { for {
packet, err := l.readPacket(msgCtx) packet, err := l.readPacket(msgCtx)
if err != nil { if err != nil {
return nil, err return result, err
} }
switch packet.Children[1].Tag { switch packet.Children[1].Tag {
@ -406,13 +391,13 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
case 5: case 5:
err := GetLDAPError(packet) err := GetLDAPError(packet)
if err != nil { if err != nil {
return nil, err return result, err
} }
if len(packet.Children) == 3 { if len(packet.Children) == 3 {
for _, child := range packet.Children[2].Children { for _, child := range packet.Children[2].Children {
decodedChild, err := DecodeControl(child) decodedChild, err := DecodeControl(child)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to decode child control: %s", err) return result, fmt.Errorf("failed to decode child control: %s", err)
} }
result.Controls = append(result.Controls, decodedChild) result.Controls = append(result.Controls, decodedChild)
} }

3
vendor/golang.org/x/crypto/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at https://tip.golang.org/AUTHORS.

3
vendor/golang.org/x/crypto/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at https://tip.golang.org/CONTRIBUTORS.

27
vendor/golang.org/x/crypto/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
vendor/golang.org/x/crypto/PATENTS generated vendored Normal file
View File

@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

122
vendor/golang.org/x/crypto/md4/md4.go generated vendored Normal file
View File

@ -0,0 +1,122 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package md4 implements the MD4 hash algorithm as defined in RFC 1320.
//
// Deprecated: MD4 is cryptographically broken and should should only be used
// where compatibility with legacy systems, not security, is the goal. Instead,
// use a secure hash like SHA-256 (from crypto/sha256).
package md4 // import "golang.org/x/crypto/md4"
import (
"crypto"
"hash"
)
func init() {
crypto.RegisterHash(crypto.MD4, New)
}
// The size of an MD4 checksum in bytes.
const Size = 16
// The blocksize of MD4 in bytes.
const BlockSize = 64
const (
_Chunk = 64
_Init0 = 0x67452301
_Init1 = 0xEFCDAB89
_Init2 = 0x98BADCFE
_Init3 = 0x10325476
)
// digest represents the partial evaluation of a checksum.
type digest struct {
s [4]uint32
x [_Chunk]byte
nx int
len uint64
}
func (d *digest) Reset() {
d.s[0] = _Init0
d.s[1] = _Init1
d.s[2] = _Init2
d.s[3] = _Init3
d.nx = 0
d.len = 0
}
// New returns a new hash.Hash computing the MD4 checksum.
func New() hash.Hash {
d := new(digest)
d.Reset()
return d
}
func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
n := len(p)
if n > _Chunk-d.nx {
n = _Chunk - d.nx
}
for i := 0; i < n; i++ {
d.x[d.nx+i] = p[i]
}
d.nx += n
if d.nx == _Chunk {
_Block(d, d.x[0:])
d.nx = 0
}
p = p[n:]
}
n := _Block(d, p)
p = p[n:]
if len(p) > 0 {
d.nx = copy(d.x[:], p)
}
return
}
func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0, so that caller can keep writing and summing.
d := new(digest)
*d = *d0
// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
len := d.len
var tmp [64]byte
tmp[0] = 0x80
if len%64 < 56 {
d.Write(tmp[0 : 56-len%64])
} else {
d.Write(tmp[0 : 64+56-len%64])
}
// Length in bits.
len <<= 3
for i := uint(0); i < 8; i++ {
tmp[i] = byte(len >> (8 * i))
}
d.Write(tmp[0:8])
if d.nx != 0 {
panic("d.nx != 0")
}
for _, s := range d.s {
in = append(in, byte(s>>0))
in = append(in, byte(s>>8))
in = append(in, byte(s>>16))
in = append(in, byte(s>>24))
}
return in
}

89
vendor/golang.org/x/crypto/md4/md4block.go generated vendored Normal file
View File

@ -0,0 +1,89 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// MD4 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
package md4
var shift1 = []uint{3, 7, 11, 19}
var shift2 = []uint{3, 5, 9, 13}
var shift3 = []uint{3, 9, 11, 15}
var xIndex2 = []uint{0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}
var xIndex3 = []uint{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}
func _Block(dig *digest, p []byte) int {
a := dig.s[0]
b := dig.s[1]
c := dig.s[2]
d := dig.s[3]
n := 0
var X [16]uint32
for len(p) >= _Chunk {
aa, bb, cc, dd := a, b, c, d
j := 0
for i := 0; i < 16; i++ {
X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
j += 4
}
// If this needs to be made faster in the future,
// the usual trick is to unroll each of these
// loops by a factor of 4; that lets you replace
// the shift[] lookups with constants and,
// with suitable variable renaming in each
// unrolled body, delete the a, b, c, d = d, a, b, c
// (or you can let the optimizer do the renaming).
//
// The index variables are uint so that % by a power
// of two can be optimized easily by a compiler.
// Round 1.
for i := uint(0); i < 16; i++ {
x := i
s := shift1[i%4]
f := ((c ^ d) & b) ^ d
a += f + X[x]
a = a<<s | a>>(32-s)
a, b, c, d = d, a, b, c
}
// Round 2.
for i := uint(0); i < 16; i++ {
x := xIndex2[i]
s := shift2[i%4]
g := (b & c) | (b & d) | (c & d)
a += g + X[x] + 0x5a827999
a = a<<s | a>>(32-s)
a, b, c, d = d, a, b, c
}
// Round 3.
for i := uint(0); i < 16; i++ {
x := xIndex3[i]
s := shift3[i%4]
h := b ^ c ^ d
a += h + X[x] + 0x6ed9eba1
a = a<<s | a>>(32-s)
a, b, c, d = d, a, b, c
}
a += aa
b += bb
c += cc
d += dd
p = p[_Chunk:]
n += _Chunk
}
dig.s[0] = a
dig.s[1] = b
dig.s[2] = c
dig.s[3] = d
return n
}

View File

@ -0,0 +1,30 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package unsafeheader contains header declarations for the Go runtime's
// slice and string implementations.
//
// This package allows x/sys to use types equivalent to
// reflect.SliceHeader and reflect.StringHeader without introducing
// a dependency on the (relatively heavy) "reflect" package.
package unsafeheader
import (
"unsafe"
)
// Slice is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may change in a later release.
type Slice struct {
Data unsafe.Pointer
Len int
Cap int
}
// String is the runtime representation of a string.
// It cannot be used safely or portably and its representation may change in a later release.
type String struct {
Data unsafe.Pointer
Len int
}

View File

@ -89,7 +89,7 @@ constants.
Adding new syscall numbers is mostly done by running the build on a sufficiently Adding new syscall numbers is mostly done by running the build on a sufficiently
new installation of the target OS (or updating the source checkouts for the new installation of the target OS (or updating the source checkouts for the
new build system). However, depending on the OS, you make need to update the new build system). However, depending on the OS, you may need to update the
parsing in mksysnum. parsing in mksysnum.
### mksyscall.go ### mksyscall.go
@ -149,10 +149,21 @@ To add a constant, add the header that includes it to the appropriate variable.
Then, edit the regex (if necessary) to match the desired constant. Avoid making Then, edit the regex (if necessary) to match the desired constant. Avoid making
the regex too broad to avoid matching unintended constants. the regex too broad to avoid matching unintended constants.
### mkmerge.go
This program is used to extract duplicate const, func, and type declarations
from the generated architecture-specific files listed below, and merge these
into a common file for each OS.
The merge is performed in the following steps:
1. Construct the set of common code that is idential in all architecture-specific files.
2. Write this common code to the merged file.
3. Remove the common code from all architecture-specific files.
## Generated files ## Generated files
### `zerror_${GOOS}_${GOARCH}.go` ### `zerrors_${GOOS}_${GOARCH}.go`
A file containing all of the system's generated error numbers, error strings, A file containing all of the system's generated error numbers, error strings,
signal numbers, and constants. Generated by `mkerrors.sh` (see above). signal numbers, and constants. Generated by `mkerrors.sh` (see above).

View File

@ -7,6 +7,7 @@
package unix package unix
import ( import (
"math/bits"
"unsafe" "unsafe"
) )
@ -79,46 +80,7 @@ func (s *CPUSet) IsSet(cpu int) bool {
func (s *CPUSet) Count() int { func (s *CPUSet) Count() int {
c := 0 c := 0
for _, b := range s { for _, b := range s {
c += onesCount64(uint64(b)) c += bits.OnesCount64(uint64(b))
} }
return c return c
} }
// onesCount64 is a copy of Go 1.9's math/bits.OnesCount64.
// Once this package can require Go 1.9, we can delete this
// and update the caller to use bits.OnesCount64.
func onesCount64(x uint64) int {
const m0 = 0x5555555555555555 // 01010101 ...
const m1 = 0x3333333333333333 // 00110011 ...
const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
const m3 = 0x00ff00ff00ff00ff // etc.
const m4 = 0x0000ffff0000ffff
// Implementation: Parallel summing of adjacent bits.
// See "Hacker's Delight", Chap. 5: Counting Bits.
// The following pattern shows the general approach:
//
// x = x>>1&(m0&m) + x&(m0&m)
// x = x>>2&(m1&m) + x&(m1&m)
// x = x>>4&(m2&m) + x&(m2&m)
// x = x>>8&(m3&m) + x&(m3&m)
// x = x>>16&(m4&m) + x&(m4&m)
// x = x>>32&(m5&m) + x&(m5&m)
// return int(x)
//
// Masking (& operations) can be left away when there's no
// danger that a field's sum will carry over into the next
// field: Since the result cannot be > 64, 8 bits is enough
// and we can ignore the masks for the shifts by 8 and up.
// Per "Hacker's Delight", the first line can be simplified
// more, but it saves at best one instruction, so we leave
// it alone for clarity.
const m = 1<<64 - 1
x = x>>1&(m0&m) + x&(m0&m)
x = x>>2&(m1&m) + x&(m1&m)
x = (x>>4 + x) & (m2 & m)
x += x >> 8
x += x >> 16
x += x >> 32
return int(x) & (1<<7 - 1)
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
// +build arm,darwin // +build arm,darwin
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
// +build arm64,darwin // +build arm64,darwin
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -4,7 +4,7 @@
// +build linux // +build linux
// +build arm64 // +build arm64
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -4,7 +4,7 @@
// +build linux // +build linux
// +build mips64 mips64le // +build mips64 mips64le
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -4,7 +4,7 @@
// +build linux // +build linux
// +build mips mipsle // +build mips mipsle
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -4,7 +4,7 @@
// +build linux // +build linux
// +build ppc64 ppc64le // +build ppc64 ppc64le
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

47
vendor/golang.org/x/sys/unix/asm_linux_riscv64.s generated vendored Normal file
View File

@ -0,0 +1,47 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build riscv64,gc
#include "textflag.h"
//
// System calls for linux/riscv64.
//
// Where available, just jump to package syscall's implementation of
// these functions.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
CALL runtime·entersyscall(SB)
MOV a1+8(FP), A0
MOV a2+16(FP), A1
MOV a3+24(FP), A2
MOV trap+0(FP), A7 // syscall entry
ECALL
MOV A0, r1+32(FP) // r1
MOV A1, r2+40(FP) // r2
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOV a1+8(FP), A0
MOV a2+16(FP), A1
MOV a3+24(FP), A2
MOV trap+0(FP), A7 // syscall entry
ECALL
MOV A0, r1+32(FP)
MOV A1, r2+40(FP)
RET

View File

@ -4,7 +4,7 @@
// +build s390x // +build s390x
// +build linux // +build linux
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

29
vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build gc
#include "textflag.h"
//
// System call support for arm64, OpenBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

29
vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build gc
#include "textflag.h"
//
// System call support for mips64, OpenBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -23,6 +23,7 @@ const (
HCI_CHANNEL_USER = 1 HCI_CHANNEL_USER = 1
HCI_CHANNEL_MONITOR = 2 HCI_CHANNEL_MONITOR = 2
HCI_CHANNEL_CONTROL = 3 HCI_CHANNEL_CONTROL = 3
HCI_CHANNEL_LOGGING = 4
) )
// Socketoption Level // Socketoption Level

View File

@ -2,16 +2,101 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package unix package unix
import "syscall" import "unsafe"
// readInt returns the size-bytes unsigned integer in native byte order at offset off.
func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
if len(b) < int(off+size) {
return 0, false
}
if isBigEndian {
return readIntBE(b[off:], size), true
}
return readIntLE(b[off:], size), true
}
func readIntBE(b []byte, size uintptr) uint64 {
switch size {
case 1:
return uint64(b[0])
case 2:
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[1]) | uint64(b[0])<<8
case 4:
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
case 8:
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
default:
panic("syscall: readInt with unsupported size")
}
}
func readIntLE(b []byte, size uintptr) uint64 {
switch size {
case 1:
return uint64(b[0])
case 2:
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8
case 4:
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
case 8:
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
default:
panic("syscall: readInt with unsupported size")
}
}
// ParseDirent parses up to max directory entries in buf, // ParseDirent parses up to max directory entries in buf,
// appending the names to names. It returns the number of // appending the names to names. It returns the number of
// bytes consumed from buf, the number of entries added // bytes consumed from buf, the number of entries added
// to names, and the new names slice. // to names, and the new names slice.
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
return syscall.ParseDirent(buf, max, names) origlen := len(buf)
count = 0
for max != 0 && len(buf) > 0 {
reclen, ok := direntReclen(buf)
if !ok || reclen > uint64(len(buf)) {
return origlen, count, names
}
rec := buf[:reclen]
buf = buf[reclen:]
ino, ok := direntIno(rec)
if !ok {
break
}
if ino == 0 { // File absent in directory.
continue
}
const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
namlen, ok := direntNamlen(rec)
if !ok || namoff+namlen > uint64(len(rec)) {
break
}
name := rec[namoff : namoff+namlen]
for i, c := range name {
if c == 0 {
name = name[:i]
break
}
}
// Check for useless names before allocating a string.
if string(name) == "." || string(name) == ".." {
continue
}
max--
count++
names = append(names, string(name))
}
return origlen - len(buf), count, names
} }

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// //
// +build ppc64 s390x mips mips64 // +build armbe arm64be m68k mips mips64 mips64p32 ppc ppc64 s390 s390x shbe sparc sparc64
package unix package unix

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// //
// +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le // +build 386 amd64 amd64p32 alpha arm arm64 mipsle mips64le mips64p32le nios2 ppc64le riscv riscv64 sh
package unix package unix

View File

@ -8,6 +8,7 @@
package unix package unix
const ( const (
DLT_HHDLC = 0x79
IFF_SMART = 0x20 IFF_SMART = 0x20
IFT_1822 = 0x2 IFT_1822 = 0x2
IFT_A12MPPSWITCH = 0x82 IFT_A12MPPSWITCH = 0x82
@ -210,13 +211,18 @@ const (
IFT_XETHER = 0x1a IFT_XETHER = 0x1a
IPPROTO_MAXID = 0x34 IPPROTO_MAXID = 0x34
IPV6_FAITH = 0x1d IPV6_FAITH = 0x1d
IPV6_MIN_MEMBERSHIPS = 0x1f
IP_FAITH = 0x16 IP_FAITH = 0x16
IP_MAX_SOURCE_FILTER = 0x400
IP_MIN_MEMBERSHIPS = 0x1f
MAP_NORESERVE = 0x40 MAP_NORESERVE = 0x40
MAP_RENAME = 0x20 MAP_RENAME = 0x20
NET_RT_MAXID = 0x6 NET_RT_MAXID = 0x6
RTF_PRCLONING = 0x10000 RTF_PRCLONING = 0x10000
RTM_OLDADD = 0x9 RTM_OLDADD = 0x9
RTM_OLDDEL = 0xa RTM_OLDDEL = 0xa
RT_CACHING_CONTEXT = 0x1
RT_NORTREF = 0x2
SIOCADDRT = 0x8030720a SIOCADDRT = 0x8030720a
SIOCALIFADDR = 0x8118691b SIOCALIFADDR = 0x8118691b
SIOCDELRT = 0x8030720b SIOCDELRT = 0x8030720b

View File

@ -8,6 +8,7 @@
package unix package unix
const ( const (
DLT_HHDLC = 0x79
IFF_SMART = 0x20 IFF_SMART = 0x20
IFT_1822 = 0x2 IFT_1822 = 0x2
IFT_A12MPPSWITCH = 0x82 IFT_A12MPPSWITCH = 0x82
@ -210,13 +211,18 @@ const (
IFT_XETHER = 0x1a IFT_XETHER = 0x1a
IPPROTO_MAXID = 0x34 IPPROTO_MAXID = 0x34
IPV6_FAITH = 0x1d IPV6_FAITH = 0x1d
IPV6_MIN_MEMBERSHIPS = 0x1f
IP_FAITH = 0x16 IP_FAITH = 0x16
IP_MAX_SOURCE_FILTER = 0x400
IP_MIN_MEMBERSHIPS = 0x1f
MAP_NORESERVE = 0x40 MAP_NORESERVE = 0x40
MAP_RENAME = 0x20 MAP_RENAME = 0x20
NET_RT_MAXID = 0x6 NET_RT_MAXID = 0x6
RTF_PRCLONING = 0x10000 RTF_PRCLONING = 0x10000
RTM_OLDADD = 0x9 RTM_OLDADD = 0x9
RTM_OLDDEL = 0xa RTM_OLDDEL = 0xa
RT_CACHING_CONTEXT = 0x1
RT_NORTREF = 0x2
SIOCADDRT = 0x8040720a SIOCADDRT = 0x8040720a
SIOCALIFADDR = 0x8118691b SIOCALIFADDR = 0x8118691b
SIOCDELRT = 0x8040720b SIOCDELRT = 0x8040720b

17
vendor/golang.org/x/sys/unix/errors_freebsd_arm64.go generated vendored Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
// them here for backwards compatibility.
package unix
const (
DLT_HHDLC = 0x79
IPV6_MIN_MEMBERSHIPS = 0x1f
IP_MAX_SOURCE_FILTER = 0x400
IP_MIN_MEMBERSHIPS = 0x1f
RT_CACHING_CONTEXT = 0x1
RT_NORTREF = 0x2
)

Some files were not shown because too many files have changed in this diff Show More