1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-18 20:59:43 +02:00

Prep 5.11.3

This commit is contained in:
Harvey Kandola 2024-02-16 10:53:02 -05:00
parent 69940cb7f1
commit f2ba294be8
47 changed files with 169 additions and 3090 deletions

View file

@ -41,8 +41,8 @@ func main() {
rt.Product = domain.Product{}
rt.Product.Major = "5"
rt.Product.Minor = "11"
rt.Product.Patch = "2"
rt.Product.Revision = "1705427184"
rt.Product.Patch = "3"
rt.Product.Revision = "1708098744"
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
rt.Product.Edition = domain.CommunityEdition
rt.Product.Title = "Community"

5
go.mod
View file

@ -11,7 +11,7 @@ require (
github.com/documize/glick v0.0.0-20160503134043-a8ccbef88237
github.com/documize/html-diff v0.0.0-20160503140253-f61c192c7796
github.com/documize/slug v1.1.1
github.com/go-ldap/ldap/v3 v3.4.6
github.com/go-ldap/ldap/v3 v3.4.1
github.com/go-sql-driver/mysql v1.7.1
github.com/golang/glog v1.2.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
@ -36,7 +36,7 @@ require (
)
require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
@ -44,7 +44,6 @@ require (
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/trivago/tgo v1.0.7 // indirect
)

20
go.sum
View file

@ -1,13 +1,11 @@
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
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/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/andygrunwald/go-jira v1.16.0 h1:PU7C7Fkk5L96JvPc6vDVIrd99vdPnYudHu4ju2c2ikQ=
github.com/andygrunwald/go-jira v1.16.0/go.mod h1:UQH4IBVxIYWbgagc0LF/k9FRs9xjIiQ8hIcC6HfLwFU=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
@ -34,10 +32,11 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
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.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A=
github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc=
github.com/go-ldap/ldap/v3 v3.4.1 h1:fU/0xli6HY02ocbMuozHAYsaHLcnkLjvho2r5a34BUU=
github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
@ -59,8 +58,6 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
@ -127,15 +124,16 @@ github.com/trivago/tgo v1.0.7 h1:uaWH/XIy9aWYWpjm2CU3RpcqZXmX2ysQ9/Go+d9gyrM=
github.com/trivago/tgo v1.0.7/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@ -150,6 +148,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -159,21 +158,18 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

View file

@ -1,6 +1,6 @@
{
"name": "documize",
"version": "5.11.2",
"version": "5.11.3",
"private": true,
"description": "Documize Community",
"repository": "",

View file

@ -1,41 +0,0 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.8 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->

View file

@ -42,7 +42,7 @@ func (m authenicateMessage) MarshalBinary() ([]byte, error) {
}
target, user := toUnicode(m.TargetName), toUnicode(m.UserName)
workstation := toUnicode("")
workstation := toUnicode("go-ntlmssp")
ptr := binary.Size(&authenticateMessageFields{})
f := authenticateMessageFields{
@ -82,7 +82,7 @@ func (m authenicateMessage) MarshalBinary() ([]byte, error) {
//ProcessChallenge crafts an AUTHENTICATE message in response to the CHALLENGE message
//that was received from the server
func ProcessChallenge(challengeMessageData []byte, user, password string, domainNeeded bool) ([]byte, error) {
func ProcessChallenge(challengeMessageData []byte, user, password string) ([]byte, error) {
if user == "" && password == "" {
return nil, errors.New("Anonymous authentication not supported")
}
@ -98,10 +98,6 @@ func ProcessChallenge(challengeMessageData []byte, user, password string, domain
if cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEKEYEXCH) {
return nil, errors.New("Key exchange requested but not supported (NTLMSSP_NEGOTIATE_KEY_EXCH)")
}
if !domainNeeded {
cm.TargetName = ""
}
am := authenicateMessage{
UserName: user,

View file

@ -5,55 +5,26 @@ import (
"strings"
)
type authheader []string
type authheader string
func (h authheader) IsBasic() bool {
for _, s := range h {
if strings.HasPrefix(string(s), "Basic ") {
return true
}
}
return false
}
func (h authheader) Basic() string {
for _, s := range h {
if strings.HasPrefix(string(s), "Basic ") {
return s
}
}
return ""
return strings.HasPrefix(string(h), "Basic ")
}
func (h authheader) IsNegotiate() bool {
for _, s := range h {
if strings.HasPrefix(string(s), "Negotiate") {
return true
}
}
return false
return strings.HasPrefix(string(h), "Negotiate")
}
func (h authheader) IsNTLM() bool {
for _, s := range h {
if strings.HasPrefix(string(s), "NTLM") {
return true
}
}
return false
return strings.HasPrefix(string(h), "NTLM")
}
func (h authheader) GetData() ([]byte, error) {
for _, s := range h {
if strings.HasPrefix(string(s), "NTLM") || strings.HasPrefix(string(s), "Negotiate") || strings.HasPrefix(string(s), "Basic ") {
p := strings.Split(string(s), " ")
if len(p) < 2 {
return nil, nil
}
return base64.StdEncoding.DecodeString(string(p[1]))
}
p := strings.Split(string(h), " ")
if len(p) < 2 {
return nil, nil
}
return nil, nil
return base64.StdEncoding.DecodeString(string(p[1]))
}
func (h authheader) GetBasicCreds() (username, password string, err error) {

View file

@ -10,22 +10,15 @@ import (
)
// GetDomain : parse domain name from based on slashes in the input
// Need to check for upn as well
func GetDomain(user string) (string, string, bool) {
func GetDomain(user string) (string, string) {
domain := ""
domainNeeded := false
if strings.Contains(user, "\\") {
ucomponents := strings.SplitN(user, "\\", 2)
domain = ucomponents[0]
user = ucomponents[1]
domainNeeded = true
} else if strings.Contains(user, "@") {
domainNeeded = false
} else {
domainNeeded = true
}
return user, domain, domainNeeded
return user, domain
}
//Negotiator is a http.Roundtripper decorator that automatically
@ -41,11 +34,10 @@ func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error)
rt = http.DefaultTransport
}
// If it is not basic auth, just round trip the request as usual
reqauth := authheader(req.Header.Values("Authorization"))
reqauth := authheader(req.Header.Get("Authorization"))
if !reqauth.IsBasic() {
return rt.RoundTrip(req)
}
reqauthBasic := reqauth.Basic()
// Save request body
body := bytes.Buffer{}
if req.Body != nil {
@ -67,10 +59,11 @@ func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error)
if res.StatusCode != http.StatusUnauthorized {
return res, err
}
resauth := authheader(res.Header.Values("Www-Authenticate"))
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(reqauthBasic))
req.Header.Set("Authorization", string(reqauth))
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()
req.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))
@ -82,7 +75,7 @@ func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error)
if res.StatusCode != http.StatusUnauthorized {
return res, err
}
resauth = authheader(res.Header.Values("Www-Authenticate"))
resauth = authheader(res.Header.Get("Www-Authenticate"))
}
if resauth.IsNegotiate() || resauth.IsNTLM() {
@ -98,7 +91,7 @@ func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error)
// get domain from username
domain := ""
u, domain, domainNeeded := GetDomain(u)
u, domain = GetDomain(u)
// send negotiate
negotiateMessage, err := NewNegotiateMessage(domain, "")
@ -119,7 +112,7 @@ func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error)
}
// receive challenge?
resauth = authheader(res.Header.Values("Www-Authenticate"))
resauth = authheader(res.Header.Get("Www-Authenticate"))
challengeMessage, err := resauth.GetData()
if err != nil {
return nil, err
@ -132,7 +125,7 @@ func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error)
res.Body.Close()
// send authenticate
authenticateMessage, err := ProcessChallenge(challengeMessage, u, p, domainNeeded)
authenticateMessage, err := ProcessChallenge(challengeMessage, u, p)
if err != nil {
return nil, err
}

View file

@ -1,7 +1,8 @@
package ldap
import (
"fmt"
"log"
ber "github.com/go-asn1-ber/asn1-ber"
)
@ -62,6 +63,7 @@ func NewAddRequest(dn string, controls []Control) *AddRequest {
DN: dn,
Controls: controls,
}
}
// Add performs the given AddRequest
@ -83,7 +85,7 @@ func (l *Conn) Add(addRequest *AddRequest) error {
return err
}
} else {
return fmt.Errorf("ldap: unexpected response: %d", packet.Children[1].Tag)
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
}
return nil
}

View file

@ -261,7 +261,7 @@ func parseParams(str string) (map[string]string, error) {
var state int
for i := 0; i <= len(str); i++ {
switch state {
case 0: // reading key
case 0: //reading key
if i == len(str) {
return nil, fmt.Errorf("syntax error on %d", i)
}
@ -270,7 +270,7 @@ func parseParams(str string) (map[string]string, error) {
continue
}
state = 1
case 1: // reading value
case 1: //reading value
if i == len(str) {
m[key] = value
break
@ -289,7 +289,7 @@ func parseParams(str string) (map[string]string, error) {
default:
value += string(str[i])
}
case 2: // inside quotes
case 2: //inside quotes
if i == len(str) {
return nil, fmt.Errorf("syntax error on %d", i)
}
@ -399,9 +399,6 @@ type NTLMBindRequest struct {
Username string
// Password is the credentials to bind with
Password string
// AllowEmptyPassword sets whether the client allows binding with an empty password
// (normally used for unauthenticated bind).
AllowEmptyPassword bool
// 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
@ -445,22 +442,6 @@ func (l *Conn) NTLMBind(domain, username, password string) error {
return err
}
// NTLMUnauthenticatedBind performs an bind with an empty password.
//
// A username is required. The anonymous bind is not (yet) supported by the go-ntlmssp library (https://github.com/Azure/go-ntlmssp/blob/819c794454d067543bc61d29f61fef4b3c3df62c/authenticate_message.go#L87)
//
// See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/b38c36ed-2804-4868-a9ff-8dd3182128e4 part 3.2.5.1.2
func (l *Conn) NTLMUnauthenticatedBind(domain, username string) error {
req := &NTLMBindRequest{
Domain: domain,
Username: username,
Password: "",
AllowEmptyPassword: true,
}
_, 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{
@ -474,7 +455,7 @@ func (l *Conn) NTLMBindWithHash(domain, username, hash string) error {
// NTLMChallengeBind performs the NTLMSSP bind operation defined in the given request
func (l *Conn) NTLMChallengeBind(ntlmBindRequest *NTLMBindRequest) (*NTLMBindResult, error) {
if !ntlmBindRequest.AllowEmptyPassword && ntlmBindRequest.Password == "" && ntlmBindRequest.Hash == "" {
if ntlmBindRequest.Password == "" && ntlmBindRequest.Hash == "" {
return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client"))
}
@ -515,11 +496,10 @@ func (l *Conn) NTLMChallengeBind(ntlmBindRequest *NTLMBindRequest) (*NTLMBindRes
var err error
var responseMessage []byte
// generate a response message to the challenge with the given Username/Password if password is provided
if ntlmBindRequest.Hash != "" {
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 if ntlmBindRequest.Password != "" || ntlmBindRequest.AllowEmptyPassword {
_, _, domainNeeded := ntlmssp.GetDomain(ntlmBindRequest.Username)
responseMessage, err = ntlmssp.ProcessChallenge(ntlmsspChallenge, ntlmBindRequest.Username, ntlmBindRequest.Password, domainNeeded)
} else {
err = fmt.Errorf("need a password or hash to generate reply")
}
@ -558,178 +538,3 @@ func (l *Conn) NTLMChallengeBind(ntlmBindRequest *NTLMBindRequest) (*NTLMBindRes
err = GetLDAPError(packet)
return result, err
}
// GSSAPIClient interface is used as the client-side implementation for the
// GSSAPI SASL mechanism.
// Interface inspired by GSSAPIClient from golang.org/x/crypto/ssh
type GSSAPIClient interface {
// InitSecContext initiates the establishment of a security context for
// GSS-API between the client and server.
// Initially the token parameter should be specified as nil.
// The routine may return a outputToken which should be transferred to
// the server, where the server will present it to AcceptSecContext.
// If no token need be sent, InitSecContext will indicate this by setting
// needContinue to false. To complete the context
// establishment, one or more reply tokens may be required from the server;
// if so, InitSecContext will return a needContinue which is true.
// In this case, InitSecContext should be called again when the
// reply token is received from the server, passing the reply token
// to InitSecContext via the token parameters.
// See RFC 4752 section 3.1.
InitSecContext(target string, token []byte) (outputToken []byte, needContinue bool, err error)
// NegotiateSaslAuth performs the last step of the Sasl handshake.
// It takes a token, which, when unwrapped, describes the servers supported
// security layers (first octet) and maximum receive buffer (remaining
// three octets).
// If the received token is unacceptable an error must be returned to abort
// the handshake.
// Outputs a signed token describing the client's selected security layer
// and receive buffer size and optionally an authorization identity.
// The returned token will be sent to the server and the handshake considered
// completed successfully and the server authenticated.
// See RFC 4752 section 3.1.
NegotiateSaslAuth(token []byte, authzid string) ([]byte, error)
// DeleteSecContext destroys any established secure context.
DeleteSecContext() error
}
// GSSAPIBindRequest represents a GSSAPI SASL mechanism bind request.
// See rfc4752 and rfc4513 section 5.2.1.2.
type GSSAPIBindRequest struct {
// Service Principal Name user for the service ticket. Eg. "ldap/<host>"
ServicePrincipalName string
// (Optional) Authorization entity
AuthZID string
// (Optional) Controls to send with the bind request
Controls []Control
}
// GSSAPIBind performs the GSSAPI SASL bind using the provided GSSAPI client.
func (l *Conn) GSSAPIBind(client GSSAPIClient, servicePrincipal, authzid string) error {
return l.GSSAPIBindRequest(client, &GSSAPIBindRequest{
ServicePrincipalName: servicePrincipal,
AuthZID: authzid,
})
}
// GSSAPIBindRequest performs the GSSAPI SASL bind using the provided GSSAPI client.
func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) error {
//nolint:errcheck
defer client.DeleteSecContext()
var err error
var reqToken []byte
var recvToken []byte
needInit := true
for {
if needInit {
// Establish secure context between client and server.
reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken)
if err != nil {
return err
}
} else {
// Secure context is set up, perform the last step of SASL handshake.
reqToken, err = client.NegotiateSaslAuth(recvToken, req.AuthZID)
if err != nil {
return err
}
}
// Send Bind request containing the current token and extract the
// token sent by server.
recvToken, err = l.saslBindTokenExchange(req.Controls, reqToken)
if err != nil {
return err
}
if !needInit && len(recvToken) == 0 {
break
}
}
return nil
}
func (l *Conn) saslBindTokenExchange(reqControls []Control, reqToken []byte) ([]byte, error) {
// Construct LDAP Bind request with GSSAPI SASL mechanism.
envelope := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
envelope.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, "GSSAPI", "SASL Mech"))
if len(reqToken) > 0 {
auth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, string(reqToken), "Credentials"))
}
request.AppendChild(auth)
envelope.AppendChild(request)
if len(reqControls) > 0 {
envelope.AppendChild(encodeControls(reqControls))
}
msgCtx, err := l.sendMessage(envelope)
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)
}
// https://www.rfc-editor.org/rfc/rfc4511#section-4.1.1
// packet is an envelope
// child 0 is message id
// child 1 is protocolOp
if len(packet.Children) != 2 {
return nil, fmt.Errorf("bad bind response")
}
protocolOp := packet.Children[1]
RESP:
switch protocolOp.Description {
case "Bind Response": // Bind Response
// Bind Reponse is an LDAP Response (https://www.rfc-editor.org/rfc/rfc4511#section-4.1.9)
// with an additional optional serverSaslCreds string (https://www.rfc-editor.org/rfc/rfc4511#section-4.2.2)
// child 0 is resultCode
resultCode := protocolOp.Children[0]
if resultCode.Tag != ber.TagEnumerated {
break RESP
}
switch resultCode.Value.(int64) {
case 14: // Sasl bind in progress
if len(protocolOp.Children) < 3 {
break RESP
}
referral := protocolOp.Children[3]
switch referral.Description {
case "Referral":
if referral.ClassType != ber.ClassContext || referral.Tag != ber.TagObjectDescriptor {
break RESP
}
return ioutil.ReadAll(referral.Data)
}
// Optional:
//if len(protocolOp.Children) == 4 {
// serverSaslCreds := protocolOp.Children[4]
//}
case 0: // Success - Bind OK.
// SASL layer in effect (if any) (See https://www.rfc-editor.org/rfc/rfc4513#section-5.2.1.4)
// NOTE: SASL security layers are not supported currently.
return nil, nil
}
}
return nil, GetLDAPError(packet)
}

View file

@ -1,7 +1,6 @@
package ldap
import (
"context"
"crypto/tls"
"time"
)
@ -10,18 +9,14 @@ import (
type Client interface {
Start()
StartTLS(*tls.Config) error
Close() error
GetLastError() error
Close()
IsClosing() bool
SetTimeout(time.Duration)
TLSConnectionState() (tls.ConnectionState, bool)
Bind(username, password string) error
UnauthenticatedBind(username string) error
SimpleBind(*SimpleBindRequest) (*SimpleBindResult, error)
ExternalBind() error
NTLMUnauthenticatedBind(domain, username string) error
Unbind() error
Add(*AddRequest) error
Del(*DelRequest) error
@ -33,9 +28,5 @@ type Client interface {
PasswordModify(*PasswordModifyRequest) (*PasswordModifyResult, error)
Search(*SearchRequest) (*SearchResult, error)
SearchAsync(ctx context.Context, searchRequest *SearchRequest, bufferSize int) Response
SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error)
DirSync(searchRequest *SearchRequest, flags, maxAttrCount int64, cookie []byte) (*SearchResult, error)
DirSyncAsync(ctx context.Context, searchRequest *SearchRequest, bufferSize int, flags, maxAttrCount int64, cookie []byte) Response
Syncrepl(ctx context.Context, searchRequest *SearchRequest, bufferSize int, mode ControlSyncRequestMode, cookie []byte, reloadHint bool) Response
}

View file

@ -34,8 +34,7 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
msgCtx, err := l.doRequest(&CompareRequest{
DN: dn,
Attribute: attribute,
Value: value,
})
Value: value})
if err != nil {
return false, err
}

View file

@ -2,10 +2,10 @@ package ldap
import (
"bufio"
"context"
"crypto/tls"
"errors"
"fmt"
"log"
"net"
"net/url"
"sync"
@ -61,21 +61,13 @@ type messageContext struct {
// sendResponse should only be called within the processMessages() loop which
// is also responsible for closing the responses channel.
func (msgCtx *messageContext) sendResponse(packet *PacketResponse, timeout time.Duration) {
timeoutCtx := context.Background()
if timeout > 0 {
var cancelFunc context.CancelFunc
timeoutCtx, cancelFunc = context.WithTimeout(context.Background(), timeout)
defer cancelFunc()
}
func (msgCtx *messageContext) sendResponse(packet *PacketResponse) {
select {
case msgCtx.responses <- packet:
// Successfully sent packet to message handler.
case <-msgCtx.done:
// The request handler is done and will not receive more
// packets.
case <-timeoutCtx.Done():
// The timeout was reached before the packet was sent.
}
}
@ -96,7 +88,6 @@ const (
type Conn struct {
// requestTimeout is loaded atomically
// so we need to ensure 64-bit alignment on 32-bit platforms.
// https://github.com/go-ldap/ldap/pull/199
requestTimeout int64
conn net.Conn
isTLS bool
@ -111,8 +102,6 @@ type Conn struct {
wgClose sync.WaitGroup
outstandingRequests uint
messageMutex sync.Mutex
err error
}
var _ Client = &Conn{}
@ -130,31 +119,30 @@ type DialOpt func(*DialContext)
// DialWithDialer updates net.Dialer in DialContext.
func DialWithDialer(d *net.Dialer) DialOpt {
return func(dc *DialContext) {
dc.dialer = d
dc.d = d
}
}
// DialWithTLSConfig updates tls.Config in DialContext.
func DialWithTLSConfig(tc *tls.Config) DialOpt {
return func(dc *DialContext) {
dc.tlsConfig = tc
dc.tc = tc
}
}
// DialWithTLSDialer is a wrapper for DialWithTLSConfig with the option to
// specify a net.Dialer to for example define a timeout or a custom resolver.
// @deprecated Use DialWithDialer and DialWithTLSConfig instead
func DialWithTLSDialer(tlsConfig *tls.Config, dialer *net.Dialer) DialOpt {
return func(dc *DialContext) {
dc.tlsConfig = tlsConfig
dc.dialer = dialer
dc.tc = tlsConfig
dc.d = dialer
}
}
// DialContext contains necessary parameters to dial the given ldap URL.
type DialContext struct {
dialer *net.Dialer
tlsConfig *tls.Config
d *net.Dialer
tc *tls.Config
}
func (dc *DialContext) dial(u *url.URL) (net.Conn, error) {
@ -162,7 +150,7 @@ func (dc *DialContext) dial(u *url.URL) (net.Conn, error) {
if u.Path == "" || u.Path == "/" {
u.Path = "/var/run/slapd/ldapi"
}
return dc.dialer.Dial("unix", u.Path)
return dc.d.Dial("unix", u.Path)
}
host, port, err := net.SplitHostPort(u.Host)
@ -173,21 +161,16 @@ func (dc *DialContext) dial(u *url.URL) (net.Conn, error) {
}
switch u.Scheme {
case "cldap":
if port == "" {
port = DefaultLdapPort
}
return dc.dialer.Dial("udp", net.JoinHostPort(host, port))
case "ldap":
if port == "" {
port = DefaultLdapPort
}
return dc.dialer.Dial("tcp", net.JoinHostPort(host, port))
return dc.d.Dial("tcp", net.JoinHostPort(host, port))
case "ldaps":
if port == "" {
port = DefaultLdapsPort
}
return tls.DialWithDialer(dc.dialer, "tcp", net.JoinHostPort(host, port), dc.tlsConfig)
return tls.DialWithDialer(dc.d, "tcp", net.JoinHostPort(host, port), dc.tc)
}
return nil, fmt.Errorf("Unknown scheme '%s'", u.Scheme)
@ -220,8 +203,7 @@ func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
}
// DialURL connects to the given ldap URL.
// The following schemas are supported: ldap://, ldaps://, ldapi://,
// and cldap:// (RFC1798, deprecated but used by Active Directory).
// The following schemas are supported: ldap://, ldaps://, ldapi://.
// On success a new Conn for the connection is returned.
func DialURL(addr string, opts ...DialOpt) (*Conn, error) {
u, err := url.Parse(addr)
@ -233,8 +215,8 @@ func DialURL(addr string, opts ...DialOpt) (*Conn, error) {
for _, opt := range opts {
opt(&dc)
}
if dc.dialer == nil {
dc.dialer = &net.Dialer{Timeout: DefaultTimeout}
if dc.d == nil {
dc.d = &net.Dialer{Timeout: DefaultTimeout}
}
c, err := dc.dial(u)
@ -249,7 +231,7 @@ func DialURL(addr string, opts ...DialOpt) (*Conn, error) {
// NewConn returns a new Conn using conn for network I/O.
func NewConn(conn net.Conn, isTLS bool) *Conn {
l := &Conn{
return &Conn{
conn: conn,
chanConfirm: make(chan struct{}),
chanMessageID: make(chan int64),
@ -258,12 +240,11 @@ func NewConn(conn net.Conn, isTLS bool) *Conn {
requestTimeout: 0,
isTLS: isTLS,
}
l.wgClose.Add(1)
return l
}
// Start initializes goroutines to read responses and process messages
func (l *Conn) Start() {
l.wgClose.Add(1)
go l.reader()
go l.processMessages()
}
@ -279,45 +260,31 @@ func (l *Conn) setClosing() bool {
}
// Close closes the connection.
func (l *Conn) Close() (err error) {
func (l *Conn) Close() {
l.messageMutex.Lock()
defer l.messageMutex.Unlock()
if l.setClosing() {
l.Debug.Printf("Sending quit message and waiting for confirmation")
l.chanMessage <- &messagePacket{Op: MessageQuit}
timeoutCtx := context.Background()
if l.getTimeout() > 0 {
var cancelFunc context.CancelFunc
timeoutCtx, cancelFunc = context.WithTimeout(timeoutCtx, time.Duration(l.getTimeout()))
defer cancelFunc()
}
select {
case <-l.chanConfirm:
// Confirmation was received.
case <-timeoutCtx.Done():
// The timeout was reached before confirmation was received.
}
<-l.chanConfirm
close(l.chanMessage)
l.Debug.Printf("Closing network connection")
err = l.conn.Close()
if err := l.conn.Close(); err != nil {
log.Println(err)
}
l.wgClose.Done()
}
l.wgClose.Wait()
return err
}
// SetTimeout sets the time after a request is sent that a MessageTimeout triggers
func (l *Conn) SetTimeout(timeout time.Duration) {
atomic.StoreInt64(&l.requestTimeout, int64(timeout))
}
func (l *Conn) getTimeout() int64 {
return atomic.LoadInt64(&l.requestTimeout)
if timeout > 0 {
atomic.StoreInt64(&l.requestTimeout, int64(timeout))
}
}
// Returns the next available messageID
@ -328,14 +295,6 @@ func (l *Conn) nextMessageID() int64 {
return 0
}
// GetLastError returns the last recorded error from goroutines like processMessages and reader.
// Only the last recorded error will be returned.
func (l *Conn) GetLastError() error {
l.messageMutex.Lock()
defer l.messageMutex.Unlock()
return l.err
}
// StartTLS sends the command to start a TLS session and then creates a new TLS Client
func (l *Conn) StartTLS(config *tls.Config) error {
if l.isTLS {
@ -484,13 +443,13 @@ func (l *Conn) sendProcessMessage(message *messagePacket) bool {
func (l *Conn) processMessages() {
defer func() {
if err := recover(); err != nil {
l.err = fmt.Errorf("ldap: recovered panic in processMessages: %v", err)
log.Printf("ldap: recovered panic in processMessages: %v", err)
}
for messageID, msgCtx := range l.messageContexts {
// If we are closing due to an error, inform anyone who
// is waiting about the error.
if l.IsClosing() && l.closeErr.Load() != nil {
msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)}, time.Duration(l.getTimeout()))
msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)})
}
l.Debug.Printf("Closing channel for MessageID %d", messageID)
close(msgCtx.responses)
@ -518,7 +477,7 @@ func (l *Conn) processMessages() {
_, err := l.conn.Write(buf)
if err != nil {
l.Debug.Printf("Error Sending Message: %s", err.Error())
message.Context.sendResponse(&PacketResponse{Error: fmt.Errorf("unable to send request: %s", err)}, time.Duration(l.getTimeout()))
message.Context.sendResponse(&PacketResponse{Error: fmt.Errorf("unable to send request: %s", err)})
close(message.Context.responses)
break
}
@ -528,35 +487,28 @@ func (l *Conn) processMessages() {
l.messageContexts[message.MessageID] = message.Context
// Add timeout if defined
requestTimeout := l.getTimeout()
requestTimeout := time.Duration(atomic.LoadInt64(&l.requestTimeout))
if requestTimeout > 0 {
go func() {
timer := time.NewTimer(time.Duration(requestTimeout))
defer func() {
if err := recover(); err != nil {
l.err = fmt.Errorf("ldap: recovered panic in RequestTimeout: %v", err)
log.Printf("ldap: recovered panic in RequestTimeout: %v", err)
}
timer.Stop()
}()
select {
case <-timer.C:
timeoutMessage := &messagePacket{
Op: MessageTimeout,
MessageID: message.MessageID,
}
l.sendProcessMessage(timeoutMessage)
case <-message.Context.done:
time.Sleep(requestTimeout)
timeoutMessage := &messagePacket{
Op: MessageTimeout,
MessageID: message.MessageID,
}
l.sendProcessMessage(timeoutMessage)
}()
}
case MessageResponse:
l.Debug.Printf("Receiving message %d", message.MessageID)
if msgCtx, ok := l.messageContexts[message.MessageID]; ok {
msgCtx.sendResponse(&PacketResponse{message.Packet, nil}, time.Duration(l.getTimeout()))
msgCtx.sendResponse(&PacketResponse{message.Packet, nil})
} else {
l.err = fmt.Errorf("ldap: received unexpected message %d, %v", message.MessageID, l.IsClosing())
log.Printf("Received unexpected message %d, %v", message.MessageID, l.IsClosing())
l.Debug.PrintPacket(message.Packet)
}
case MessageTimeout:
@ -564,7 +516,7 @@ func (l *Conn) processMessages() {
// All reads will return immediately
if msgCtx, ok := l.messageContexts[message.MessageID]; ok {
l.Debug.Printf("Receiving message timeout for %d", message.MessageID)
msgCtx.sendResponse(&PacketResponse{message.Packet, NewError(ErrorNetwork, errors.New("ldap: connection timed out"))}, time.Duration(l.getTimeout()))
msgCtx.sendResponse(&PacketResponse{message.Packet, NewError(ErrorNetwork, errors.New("ldap: connection timed out"))})
delete(l.messageContexts, message.MessageID)
close(msgCtx.responses)
}
@ -583,7 +535,7 @@ func (l *Conn) reader() {
cleanstop := false
defer func() {
if err := recover(); err != nil {
l.err = fmt.Errorf("ldap: recovered panic in reader: %v", err)
log.Printf("ldap: recovered panic in reader: %v", err)
}
if !cleanstop {
l.Close()

View file

@ -5,7 +5,6 @@ import (
"strconv"
ber "github.com/go-asn1-ber/asn1-ber"
"github.com/google/uuid"
)
const (
@ -21,13 +20,6 @@ const (
ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2"
// ControlTypeWhoAmI - https://tools.ietf.org/html/rfc4532
ControlTypeWhoAmI = "1.3.6.1.4.1.4203.1.11.3"
// ControlTypeSubtreeDelete - https://datatracker.ietf.org/doc/html/draft-armijo-ldap-treedelete-02
ControlTypeSubtreeDelete = "1.2.840.113556.1.4.805"
// ControlTypeServerSideSorting - https://www.ietf.org/rfc/rfc2891.txt
ControlTypeServerSideSorting = "1.2.840.113556.1.4.473"
// ControlTypeServerSideSorting - https://www.ietf.org/rfc/rfc2891.txt
ControlTypeServerSideSortingResult = "1.2.840.113556.1.4.474"
// ControlTypeMicrosoftNotification - https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
ControlTypeMicrosoftNotification = "1.2.840.113556.1.4.528"
@ -35,43 +27,16 @@ const (
ControlTypeMicrosoftShowDeleted = "1.2.840.113556.1.4.417"
// ControlTypeMicrosoftServerLinkTTL - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/f4f523a8-abc0-4b3a-a471-6b2fef135481?redirectedfrom=MSDN
ControlTypeMicrosoftServerLinkTTL = "1.2.840.113556.1.4.2309"
// ControlTypeDirSync - Active Directory DirSync - https://msdn.microsoft.com/en-us/library/aa366978(v=vs.85).aspx
ControlTypeDirSync = "1.2.840.113556.1.4.841"
// ControlTypeSyncRequest - https://www.ietf.org/rfc/rfc4533.txt
ControlTypeSyncRequest = "1.3.6.1.4.1.4203.1.9.1.1"
// ControlTypeSyncState - https://www.ietf.org/rfc/rfc4533.txt
ControlTypeSyncState = "1.3.6.1.4.1.4203.1.9.1.2"
// ControlTypeSyncDone - https://www.ietf.org/rfc/rfc4533.txt
ControlTypeSyncDone = "1.3.6.1.4.1.4203.1.9.1.3"
// ControlTypeSyncInfo - https://www.ietf.org/rfc/rfc4533.txt
ControlTypeSyncInfo = "1.3.6.1.4.1.4203.1.9.1.4"
)
// Flags for DirSync control
const (
DirSyncIncrementalValues int64 = 2147483648
DirSyncPublicDataOnly int64 = 8192
DirSyncAncestorsFirstOrder int64 = 2048
DirSyncObjectSecurity int64 = 1
)
// ControlTypeMap maps controls to text descriptions
var ControlTypeMap = map[string]string{
ControlTypePaging: "Paging",
ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
ControlTypeManageDsaIT: "Manage DSA IT",
ControlTypeSubtreeDelete: "Subtree Delete Control",
ControlTypeMicrosoftNotification: "Change Notification - Microsoft",
ControlTypeMicrosoftShowDeleted: "Show Deleted Objects - Microsoft",
ControlTypeMicrosoftServerLinkTTL: "Return TTL-DNs for link values with associated expiry times - Microsoft",
ControlTypeServerSideSorting: "Server Side Sorting Request - LDAP Control Extension for Server Side Sorting of Search Results (RFC2891)",
ControlTypeServerSideSortingResult: "Server Side Sorting Results - LDAP Control Extension for Server Side Sorting of Search Results (RFC2891)",
ControlTypeDirSync: "DirSync",
ControlTypeSyncRequest: "Sync Request",
ControlTypeSyncState: "Sync State",
ControlTypeSyncDone: "Sync Done",
ControlTypeSyncInfo: "Sync Info",
ControlTypePaging: "Paging",
ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
ControlTypeManageDsaIT: "Manage DSA IT",
ControlTypeMicrosoftNotification: "Change Notification - Microsoft",
ControlTypeMicrosoftShowDeleted: "Show Deleted Objects - Microsoft",
ControlTypeMicrosoftServerLinkTTL: "Return TTL-DNs for link values with associated expiry times - Microsoft",
}
// Control defines an interface controls provide to encode and describe themselves
@ -264,7 +229,7 @@ func (c *ControlManageDsaIT) GetControlType() string {
// Encode returns the ber packet representation
func (c *ControlManageDsaIT) Encode() *ber.Packet {
// FIXME
//FIXME
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeManageDsaIT, "Control Type ("+ControlTypeMap[ControlTypeManageDsaIT]+")"))
if c.Criticality {
@ -404,13 +369,7 @@ func DecodeControl(packet *ber.Packet) (Control, error) {
case 2:
packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
if packet.Children[0].Value != nil {
ControlType = packet.Children[0].Value.(string)
} else if packet.Children[0].Data != nil {
ControlType = packet.Children[0].Data.String()
} else {
return nil, fmt.Errorf("not found where to get the control type")
}
ControlType = packet.Children[0].Value.(string)
// Children[1] could be criticality or value (both are optional)
// duck-type on whether this is a boolean
@ -477,18 +436,18 @@ func DecodeControl(packet *ber.Packet) (Control, error) {
for _, child := range sequence.Children {
if child.Tag == 0 {
// Warning
//Warning
warningPacket := child.Children[0]
val, err := ber.ParseInt64(warningPacket.Data.Bytes())
if err != nil {
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
}
if warningPacket.Tag == 0 {
// timeBeforeExpiration
//timeBeforeExpiration
c.Expire = val
warningPacket.Value = c.Expire
} else if warningPacket.Tag == 1 {
// graceAuthNsRemaining
//graceAuthNsRemaining
c.Grace = val
warningPacket.Value = c.Grace
}
@ -526,36 +485,6 @@ func DecodeControl(packet *ber.Packet) (Control, error) {
return NewControlMicrosoftShowDeleted(), nil
case ControlTypeMicrosoftServerLinkTTL:
return NewControlMicrosoftServerLinkTTL(), nil
case ControlTypeSubtreeDelete:
return NewControlSubtreeDelete(), nil
case ControlTypeServerSideSorting:
return NewControlServerSideSorting(value)
case ControlTypeServerSideSortingResult:
return NewControlServerSideSortingResult(value)
case ControlTypeDirSync:
value.Description += " (DirSync)"
return NewResponseControlDirSync(value)
case ControlTypeSyncState:
value.Description += " (Sync State)"
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
if err != nil {
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
}
return NewControlSyncState(valueChildren)
case ControlTypeSyncDone:
value.Description += " (Sync Done)"
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
if err != nil {
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
}
return NewControlSyncDone(valueChildren)
case ControlTypeSyncInfo:
value.Description += " (Sync Info)"
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
if err != nil {
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
}
return NewControlSyncInfo(valueChildren)
default:
c := new(ControlString)
c.ControlType = ControlType
@ -590,35 +519,6 @@ func NewControlBeheraPasswordPolicy() *ControlBeheraPasswordPolicy {
}
}
// ControlSubtreeDelete implements the subtree delete control described in
// https://datatracker.ietf.org/doc/html/draft-armijo-ldap-treedelete-02
type ControlSubtreeDelete struct{}
// GetControlType returns the OID
func (c *ControlSubtreeDelete) GetControlType() string {
return ControlTypeSubtreeDelete
}
// NewControlSubtreeDelete returns a ControlSubtreeDelete control.
func NewControlSubtreeDelete() *ControlSubtreeDelete {
return &ControlSubtreeDelete{}
}
// Encode returns the ber packet representation
func (c *ControlSubtreeDelete) Encode() *ber.Packet {
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeSubtreeDelete, "Control Type ("+ControlTypeMap[ControlTypeSubtreeDelete]+")"))
return packet
}
func (c *ControlSubtreeDelete) String() string {
return fmt.Sprintf(
"Control Type: %s (%q)",
ControlTypeMap[ControlTypeSubtreeDelete],
ControlTypeSubtreeDelete)
}
func encodeControls(controls []Control) *ber.Packet {
packet := ber.Encode(ber.ClassContext, ber.TypeConstructed, 0, nil, "Controls")
for _, control := range controls {
@ -626,669 +526,3 @@ func encodeControls(controls []Control) *ber.Packet {
}
return packet
}
// ControlDirSync implements the control described in https://msdn.microsoft.com/en-us/library/aa366978(v=vs.85).aspx
type ControlDirSync struct {
Criticality bool
Flags int64
MaxAttrCount int64
Cookie []byte
}
// @deprecated Use NewRequestControlDirSync instead
func NewControlDirSync(flags int64, maxAttrCount int64, cookie []byte) *ControlDirSync {
return NewRequestControlDirSync(flags, maxAttrCount, cookie)
}
// NewRequestControlDirSync returns a dir sync control
func NewRequestControlDirSync(
flags int64, maxAttrCount int64, cookie []byte,
) *ControlDirSync {
return &ControlDirSync{
Criticality: true,
Flags: flags,
MaxAttrCount: maxAttrCount,
Cookie: cookie,
}
}
// NewResponseControlDirSync returns a dir sync control
func NewResponseControlDirSync(value *ber.Packet) (*ControlDirSync, error) {
if value.Value != nil {
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
if err != nil {
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
}
value.Data.Truncate(0)
value.Value = nil
value.AppendChild(valueChildren)
}
child := value.Children[0]
if len(child.Children) != 3 { // also on initial creation, Cookie is an empty string
return nil, fmt.Errorf("invalid number of children in dirSync control")
}
child.Description = "DirSync Control Value"
child.Children[0].Description = "Flags"
child.Children[1].Description = "MaxAttrCount"
child.Children[2].Description = "Cookie"
cookie := child.Children[2].Data.Bytes()
child.Children[2].Value = cookie
return &ControlDirSync{
Criticality: true,
Flags: child.Children[0].Value.(int64),
MaxAttrCount: child.Children[1].Value.(int64),
Cookie: cookie,
}, nil
}
// GetControlType returns the OID
func (c *ControlDirSync) GetControlType() string {
return ControlTypeDirSync
}
// String returns a human-readable description
func (c *ControlDirSync) String() string {
return fmt.Sprintf(
"ControlType: %s (%q) Criticality: %t ControlValue: Flags: %d MaxAttrCount: %d",
ControlTypeMap[ControlTypeDirSync],
ControlTypeDirSync,
c.Criticality,
c.Flags,
c.MaxAttrCount,
)
}
// Encode returns the ber packet representation
func (c *ControlDirSync) Encode() *ber.Packet {
cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "Cookie")
if len(c.Cookie) != 0 {
cookie.Value = c.Cookie
cookie.Data.Write(c.Cookie)
}
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeDirSync, "Control Type ("+ControlTypeMap[ControlTypeDirSync]+")"))
packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality")) // must be true always
val := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (DirSync)")
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "DirSync Control Value")
seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.Flags), "Flags"))
seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.MaxAttrCount), "MaxAttrCount"))
seq.AppendChild(cookie)
val.AppendChild(seq)
packet.AppendChild(val)
return packet
}
// SetCookie stores the given cookie in the dirSync control
func (c *ControlDirSync) SetCookie(cookie []byte) {
c.Cookie = cookie
}
// ControlServerSideSorting
type SortKey struct {
Reverse bool
AttributeType string
MatchingRule string
}
type ControlServerSideSorting struct {
SortKeys []*SortKey
}
func (c *ControlServerSideSorting) GetControlType() string {
return ControlTypeServerSideSorting
}
func NewControlServerSideSorting(value *ber.Packet) (*ControlServerSideSorting, error) {
sortKeys := []*SortKey{}
val := value.Children[1].Children
if len(val) != 1 {
return nil, fmt.Errorf("no sequence value in packet")
}
sequences := val[0].Children
for i, sequence := range sequences {
sortKey := &SortKey{}
if len(sequence.Children) < 2 {
return nil, fmt.Errorf("attributeType or matchingRule is missing from sequence %d", i)
}
sortKey.AttributeType = sequence.Children[0].Value.(string)
sortKey.MatchingRule = sequence.Children[1].Value.(string)
if len(sequence.Children) == 3 {
sortKey.Reverse = sequence.Children[2].Value.(bool)
}
sortKeys = append(sortKeys, sortKey)
}
return &ControlServerSideSorting{SortKeys: sortKeys}, nil
}
func NewControlServerSideSortingWithSortKeys(sortKeys []*SortKey) *ControlServerSideSorting {
return &ControlServerSideSorting{SortKeys: sortKeys}
}
func (c *ControlServerSideSorting) Encode() *ber.Packet {
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
control := ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.GetControlType(), "Control Type")
value := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value")
seqs := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "SortKeyList")
for _, f := range c.SortKeys {
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "")
seq.AppendChild(
ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, f.AttributeType, "attributeType"),
)
seq.AppendChild(
ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, f.MatchingRule, "orderingRule"),
)
if f.Reverse {
seq.AppendChild(
ber.NewBoolean(ber.ClassContext, ber.TypePrimitive, 1, f.Reverse, "reverseOrder"),
)
}
seqs.AppendChild(seq)
}
value.AppendChild(seqs)
packet.AppendChild(control)
packet.AppendChild(value)
return packet
}
func (c *ControlServerSideSorting) String() string {
return fmt.Sprintf(
"Control Type: %s (%q) Criticality:%t %+v",
"Server Side Sorting",
c.GetControlType(),
false,
c.SortKeys,
)
}
// ControlServerSideSortingResponse
const (
ControlServerSideSortingCodeSuccess ControlServerSideSortingCode = 0
ControlServerSideSortingCodeOperationsError ControlServerSideSortingCode = 1
ControlServerSideSortingCodeTimeLimitExceeded ControlServerSideSortingCode = 2
ControlServerSideSortingCodeStrongAuthRequired ControlServerSideSortingCode = 8
ControlServerSideSortingCodeAdminLimitExceeded ControlServerSideSortingCode = 11
ControlServerSideSortingCodeNoSuchAttribute ControlServerSideSortingCode = 16
ControlServerSideSortingCodeInappropriateMatching ControlServerSideSortingCode = 18
ControlServerSideSortingCodeInsufficientAccessRights ControlServerSideSortingCode = 50
ControlServerSideSortingCodeBusy ControlServerSideSortingCode = 51
ControlServerSideSortingCodeUnwillingToPerform ControlServerSideSortingCode = 53
ControlServerSideSortingCodeOther ControlServerSideSortingCode = 80
)
var ControlServerSideSortingCodes = []ControlServerSideSortingCode{
ControlServerSideSortingCodeSuccess,
ControlServerSideSortingCodeOperationsError,
ControlServerSideSortingCodeTimeLimitExceeded,
ControlServerSideSortingCodeStrongAuthRequired,
ControlServerSideSortingCodeAdminLimitExceeded,
ControlServerSideSortingCodeNoSuchAttribute,
ControlServerSideSortingCodeInappropriateMatching,
ControlServerSideSortingCodeInsufficientAccessRights,
ControlServerSideSortingCodeBusy,
ControlServerSideSortingCodeUnwillingToPerform,
ControlServerSideSortingCodeOther,
}
type ControlServerSideSortingCode int64
// Valid test the code contained in the control against the ControlServerSideSortingCodes slice and return an error if the code is unknown.
func (c ControlServerSideSortingCode) Valid() error {
for _, validRet := range ControlServerSideSortingCodes {
if c == validRet {
return nil
}
}
return fmt.Errorf("unknown return code : %d", c)
}
func NewControlServerSideSortingResult(pkt *ber.Packet) (*ControlServerSideSortingResult, error) {
control := &ControlServerSideSortingResult{}
if pkt == nil || len(pkt.Children) == 0 {
return nil, fmt.Errorf("bad packet")
}
codeInt, err := ber.ParseInt64(pkt.Children[0].Data.Bytes())
if err != nil {
return nil, err
}
code := ControlServerSideSortingCode(codeInt)
if err := code.Valid(); err != nil {
return nil, err
}
return control, nil
}
type ControlServerSideSortingResult struct {
Criticality bool
Result ControlServerSideSortingCode
// Not populated for now. I can't get openldap to send me this value, so I think this is specific to other directory server
// AttributeType string
}
func (control *ControlServerSideSortingResult) GetControlType() string {
return ControlTypeServerSideSortingResult
}
func (c *ControlServerSideSortingResult) Encode() *ber.Packet {
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "SortResult sequence")
sortResult := ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, int64(c.Result), "SortResult")
packet.AppendChild(sortResult)
return packet
}
func (c *ControlServerSideSortingResult) String() string {
return fmt.Sprintf(
"Control Type: %s (%q) Criticality:%t ResultCode:%+v",
"Server Side Sorting Result",
c.GetControlType(),
c.Criticality,
c.Result,
)
}
// Mode for ControlTypeSyncRequest
type ControlSyncRequestMode int64
const (
SyncRequestModeRefreshOnly ControlSyncRequestMode = 1
SyncRequestModeRefreshAndPersist ControlSyncRequestMode = 3
)
// ControlSyncRequest implements the Sync Request Control described in https://www.ietf.org/rfc/rfc4533.txt
type ControlSyncRequest struct {
Criticality bool
Mode ControlSyncRequestMode
Cookie []byte
ReloadHint bool
}
func NewControlSyncRequest(
mode ControlSyncRequestMode, cookie []byte, reloadHint bool,
) *ControlSyncRequest {
return &ControlSyncRequest{
Criticality: true,
Mode: mode,
Cookie: cookie,
ReloadHint: reloadHint,
}
}
// GetControlType returns the OID
func (c *ControlSyncRequest) GetControlType() string {
return ControlTypeSyncRequest
}
// Encode encodes the control
func (c *ControlSyncRequest) Encode() *ber.Packet {
_mode := int64(c.Mode)
mode := ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, _mode, "Mode")
var cookie *ber.Packet
if len(c.Cookie) > 0 {
cookie = ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie")
cookie.Value = c.Cookie
cookie.Data.Write(c.Cookie)
}
reloadHint := ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.ReloadHint, "Reload Hint")
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeSyncRequest, "Control Type ("+ControlTypeMap[ControlTypeSyncRequest]+")"))
packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality"))
val := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Sync Request)")
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Sync Request Value")
seq.AppendChild(mode)
if cookie != nil {
seq.AppendChild(cookie)
}
seq.AppendChild(reloadHint)
val.AppendChild(seq)
packet.AppendChild(val)
return packet
}
// String returns a human-readable description
func (c *ControlSyncRequest) String() string {
return fmt.Sprintf(
"Control Type: %s (%q) Criticality: %t Mode: %d Cookie: %s ReloadHint: %t",
ControlTypeMap[ControlTypeSyncRequest],
ControlTypeSyncRequest,
c.Criticality,
c.Mode,
string(c.Cookie),
c.ReloadHint,
)
}
// State for ControlSyncState
type ControlSyncStateState int64
const (
SyncStatePresent ControlSyncStateState = 0
SyncStateAdd ControlSyncStateState = 1
SyncStateModify ControlSyncStateState = 2
SyncStateDelete ControlSyncStateState = 3
)
// ControlSyncState implements the Sync State Control described in https://www.ietf.org/rfc/rfc4533.txt
type ControlSyncState struct {
Criticality bool
State ControlSyncStateState
EntryUUID uuid.UUID
Cookie []byte
}
func NewControlSyncState(pkt *ber.Packet) (*ControlSyncState, error) {
var (
state ControlSyncStateState
entryUUID uuid.UUID
cookie []byte
err error
)
switch len(pkt.Children) {
case 0, 1:
return nil, fmt.Errorf("at least two children are required: %d", len(pkt.Children))
case 2:
state = ControlSyncStateState(pkt.Children[0].Value.(int64))
entryUUID, err = uuid.FromBytes(pkt.Children[1].ByteValue)
if err != nil {
return nil, fmt.Errorf("failed to decode uuid: %w", err)
}
case 3:
state = ControlSyncStateState(pkt.Children[0].Value.(int64))
entryUUID, err = uuid.FromBytes(pkt.Children[1].ByteValue)
if err != nil {
return nil, fmt.Errorf("failed to decode uuid: %w", err)
}
cookie = pkt.Children[2].ByteValue
}
return &ControlSyncState{
Criticality: false,
State: state,
EntryUUID: entryUUID,
Cookie: cookie,
}, nil
}
// GetControlType returns the OID
func (c *ControlSyncState) GetControlType() string {
return ControlTypeSyncState
}
// Encode encodes the control
func (c *ControlSyncState) Encode() *ber.Packet {
return nil
}
// String returns a human-readable description
func (c *ControlSyncState) String() string {
return fmt.Sprintf(
"Control Type: %s (%q) Criticality: %t State: %d EntryUUID: %s Cookie: %s",
ControlTypeMap[ControlTypeSyncState],
ControlTypeSyncState,
c.Criticality,
c.State,
c.EntryUUID.String(),
string(c.Cookie),
)
}
// ControlSyncDone implements the Sync Done Control described in https://www.ietf.org/rfc/rfc4533.txt
type ControlSyncDone struct {
Criticality bool
Cookie []byte
RefreshDeletes bool
}
func NewControlSyncDone(pkt *ber.Packet) (*ControlSyncDone, error) {
var (
cookie []byte
refreshDeletes bool
)
switch len(pkt.Children) {
case 0:
// have nothing to do
case 1:
cookie = pkt.Children[0].ByteValue
case 2:
cookie = pkt.Children[0].ByteValue
refreshDeletes = pkt.Children[1].Value.(bool)
}
return &ControlSyncDone{
Criticality: false,
Cookie: cookie,
RefreshDeletes: refreshDeletes,
}, nil
}
// GetControlType returns the OID
func (c *ControlSyncDone) GetControlType() string {
return ControlTypeSyncDone
}
// Encode encodes the control
func (c *ControlSyncDone) Encode() *ber.Packet {
return nil
}
// String returns a human-readable description
func (c *ControlSyncDone) String() string {
return fmt.Sprintf(
"Control Type: %s (%q) Criticality: %t Cookie: %s RefreshDeletes: %t",
ControlTypeMap[ControlTypeSyncDone],
ControlTypeSyncDone,
c.Criticality,
string(c.Cookie),
c.RefreshDeletes,
)
}
// Tag For ControlSyncInfo
type ControlSyncInfoValue uint64
const (
SyncInfoNewcookie ControlSyncInfoValue = 0
SyncInfoRefreshDelete ControlSyncInfoValue = 1
SyncInfoRefreshPresent ControlSyncInfoValue = 2
SyncInfoSyncIdSet ControlSyncInfoValue = 3
)
// ControlSyncInfoNewCookie implements a part of syncInfoValue described in https://www.ietf.org/rfc/rfc4533.txt
type ControlSyncInfoNewCookie struct {
Cookie []byte
}
// String returns a human-readable description
func (c *ControlSyncInfoNewCookie) String() string {
return fmt.Sprintf(
"NewCookie[Cookie: %s]",
string(c.Cookie),
)
}
// ControlSyncInfoRefreshDelete implements a part of syncInfoValue described in https://www.ietf.org/rfc/rfc4533.txt
type ControlSyncInfoRefreshDelete struct {
Cookie []byte
RefreshDone bool
}
// String returns a human-readable description
func (c *ControlSyncInfoRefreshDelete) String() string {
return fmt.Sprintf(
"RefreshDelete[Cookie: %s RefreshDone: %t]",
string(c.Cookie),
c.RefreshDone,
)
}
// ControlSyncInfoRefreshPresent implements a part of syncInfoValue described in https://www.ietf.org/rfc/rfc4533.txt
type ControlSyncInfoRefreshPresent struct {
Cookie []byte
RefreshDone bool
}
// String returns a human-readable description
func (c *ControlSyncInfoRefreshPresent) String() string {
return fmt.Sprintf(
"RefreshPresent[Cookie: %s RefreshDone: %t]",
string(c.Cookie),
c.RefreshDone,
)
}
// ControlSyncInfoSyncIdSet implements a part of syncInfoValue described in https://www.ietf.org/rfc/rfc4533.txt
type ControlSyncInfoSyncIdSet struct {
Cookie []byte
RefreshDeletes bool
SyncUUIDs []uuid.UUID
}
// String returns a human-readable description
func (c *ControlSyncInfoSyncIdSet) String() string {
return fmt.Sprintf(
"SyncIdSet[Cookie: %s RefreshDeletes: %t SyncUUIDs: %v]",
string(c.Cookie),
c.RefreshDeletes,
c.SyncUUIDs,
)
}
// ControlSyncInfo implements the Sync Info Control described in https://www.ietf.org/rfc/rfc4533.txt
type ControlSyncInfo struct {
Criticality bool
Value ControlSyncInfoValue
NewCookie *ControlSyncInfoNewCookie
RefreshDelete *ControlSyncInfoRefreshDelete
RefreshPresent *ControlSyncInfoRefreshPresent
SyncIdSet *ControlSyncInfoSyncIdSet
}
func NewControlSyncInfo(pkt *ber.Packet) (*ControlSyncInfo, error) {
var (
cookie []byte
refreshDone = true
refreshDeletes bool
syncUUIDs []uuid.UUID
)
c := &ControlSyncInfo{Criticality: false}
switch ControlSyncInfoValue(pkt.Identifier.Tag) {
case SyncInfoNewcookie:
c.Value = SyncInfoNewcookie
c.NewCookie = &ControlSyncInfoNewCookie{
Cookie: pkt.ByteValue,
}
case SyncInfoRefreshDelete:
c.Value = SyncInfoRefreshDelete
switch len(pkt.Children) {
case 0:
// have nothing to do
case 1:
cookie = pkt.Children[0].ByteValue
case 2:
cookie = pkt.Children[0].ByteValue
refreshDone = pkt.Children[1].Value.(bool)
}
c.RefreshDelete = &ControlSyncInfoRefreshDelete{
Cookie: cookie,
RefreshDone: refreshDone,
}
case SyncInfoRefreshPresent:
c.Value = SyncInfoRefreshPresent
switch len(pkt.Children) {
case 0:
// have nothing to do
case 1:
cookie = pkt.Children[0].ByteValue
case 2:
cookie = pkt.Children[0].ByteValue
refreshDone = pkt.Children[1].Value.(bool)
}
c.RefreshPresent = &ControlSyncInfoRefreshPresent{
Cookie: cookie,
RefreshDone: refreshDone,
}
case SyncInfoSyncIdSet:
c.Value = SyncInfoSyncIdSet
switch len(pkt.Children) {
case 0:
// have nothing to do
case 1:
cookie = pkt.Children[0].ByteValue
case 2:
cookie = pkt.Children[0].ByteValue
refreshDeletes = pkt.Children[1].Value.(bool)
case 3:
cookie = pkt.Children[0].ByteValue
refreshDeletes = pkt.Children[1].Value.(bool)
syncUUIDs = make([]uuid.UUID, 0, len(pkt.Children[2].Children))
for _, child := range pkt.Children[2].Children {
u, err := uuid.FromBytes(child.ByteValue)
if err != nil {
return nil, fmt.Errorf("failed to decode uuid: %w", err)
}
syncUUIDs = append(syncUUIDs, u)
}
}
c.SyncIdSet = &ControlSyncInfoSyncIdSet{
Cookie: cookie,
RefreshDeletes: refreshDeletes,
SyncUUIDs: syncUUIDs,
}
default:
return nil, fmt.Errorf("unknown sync info value: %d", pkt.Identifier.Tag)
}
return c, nil
}
// GetControlType returns the OID
func (c *ControlSyncInfo) GetControlType() string {
return ControlTypeSyncInfo
}
// Encode encodes the control
func (c *ControlSyncInfo) Encode() *ber.Packet {
return nil
}
// String returns a human-readable description
func (c *ControlSyncInfo) String() string {
return fmt.Sprintf(
"Control Type: %s (%q) Criticality: %t Value: %d %s %s %s %s",
ControlTypeMap[ControlTypeSyncInfo],
ControlTypeSyncInfo,
c.Criticality,
c.Value,
c.NewCookie,
c.RefreshDelete,
c.RefreshPresent,
c.SyncIdSet,
)
}

View file

@ -1,11 +1,13 @@
package ldap
import (
"log"
ber "github.com/go-asn1-ber/asn1-ber"
)
// debugging type
// - has a Printf method to write the debug output
// - has a Printf method to write the debug output
type debugging bool
// Enable controls debugging mode.
@ -16,13 +18,13 @@ func (debug *debugging) Enable(b bool) {
// Printf writes debug output.
func (debug debugging) Printf(format string, args ...interface{}) {
if debug {
logger.Printf(format, args...)
log.Printf(format, args...)
}
}
// PrintPacket dumps a packet.
func (debug debugging) PrintPacket(packet *ber.Packet) {
if debug {
ber.WritePacket(logger.Writer(), packet)
ber.WritePacket(log.Writer(), packet)
}
}

View file

@ -1,7 +1,8 @@
package ldap
import (
"fmt"
"log"
ber "github.com/go-asn1-ber/asn1-ber"
)
@ -52,8 +53,7 @@ func (l *Conn) Del(delRequest *DelRequest) error {
return err
}
} else {
return fmt.Errorf("ldap: unexpected response: %d", packet.Children[1].Tag)
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
}
return nil
}

View file

@ -5,7 +5,6 @@ import (
enchex "encoding/hex"
"errors"
"fmt"
"sort"
"strings"
ber "github.com/go-asn1-ber/asn1-ber"
@ -19,95 +18,16 @@ type AttributeTypeAndValue struct {
Value string
}
// String returns a normalized string representation of this attribute type and
// value pair which is the a lowercased join of the Type and Value with a "=".
func (a *AttributeTypeAndValue) String() string {
return strings.ToLower(a.Type) + "=" + a.encodeValue()
}
func (a *AttributeTypeAndValue) encodeValue() string {
// Normalize the value first.
// value := strings.ToLower(a.Value)
value := a.Value
encodedBuf := bytes.Buffer{}
escapeChar := func(c byte) {
encodedBuf.WriteByte('\\')
encodedBuf.WriteByte(c)
}
escapeHex := func(c byte) {
encodedBuf.WriteByte('\\')
encodedBuf.WriteString(enchex.EncodeToString([]byte{c}))
}
for i := 0; i < len(value); i++ {
char := value[i]
if i == 0 && char == ' ' || char == '#' {
// Special case leading space or number sign.
escapeChar(char)
continue
}
if i == len(value)-1 && char == ' ' {
// Special case trailing space.
escapeChar(char)
continue
}
switch char {
case '"', '+', ',', ';', '<', '>', '\\':
// Each of these special characters must be escaped.
escapeChar(char)
continue
}
if char < ' ' || char > '~' {
// All special character escapes are handled first
// above. All bytes less than ASCII SPACE and all bytes
// greater than ASCII TILDE must be hex-escaped.
escapeHex(char)
continue
}
// Any other character does not require escaping.
encodedBuf.WriteByte(char)
}
return encodedBuf.String()
}
// RelativeDN represents a relativeDistinguishedName from https://tools.ietf.org/html/rfc4514
type RelativeDN struct {
Attributes []*AttributeTypeAndValue
}
// String returns a normalized string representation of this relative DN which
// is the a join of all attributes (sorted in increasing order) with a "+".
func (r *RelativeDN) String() string {
attrs := make([]string, len(r.Attributes))
for i := range r.Attributes {
attrs[i] = r.Attributes[i].String()
}
sort.Strings(attrs)
return strings.Join(attrs, "+")
}
// DN represents a distinguishedName from https://tools.ietf.org/html/rfc4514
type DN struct {
RDNs []*RelativeDN
}
// String returns a normalized string representation of this DN which is the
// join of all relative DNs with a ",".
func (d *DN) String() string {
rdns := make([]string, len(d.RDNs))
for i := range d.RDNs {
rdns[i] = d.RDNs[i].String()
}
return strings.Join(rdns, ",")
}
// ParseDN returns a distinguishedName or an error.
// The function respects https://tools.ietf.org/html/rfc4514
func ParseDN(str string) (*DN, error) {
@ -156,7 +76,7 @@ func ParseDN(str string) (*DN, error) {
case char == '\\':
unescapedTrailingSpaces = 0
escaping = true
case char == '=' && attribute.Type == "":
case char == '=':
attribute.Type = stringFromBuffer()
// Special case: If the first character in the value is # the
// following data is BER encoded so we can just fast forward
@ -164,7 +84,7 @@ func ParseDN(str string) (*DN, error) {
if len(str) > i+1 && str[i+1] == '#' {
i += 2
index := strings.IndexAny(str[i:], ",+")
var data string
data := str
if index > 0 {
data = str[i : i+index]
} else {
@ -181,7 +101,7 @@ func ParseDN(str string) (*DN, error) {
buffer.WriteString(packet.Data.String())
i += len(data) - 1
}
case char == ',' || char == '+' || char == ';':
case char == ',' || char == '+':
// We're done with this RDN or value, push it
if len(attribute.Type) == 0 {
return nil, errors.New("incomplete type, value pair")
@ -189,7 +109,7 @@ func ParseDN(str string) (*DN, error) {
attribute.Value = stringFromBuffer()
rdn.Attributes = append(rdn.Attributes, attribute)
attribute = new(AttributeTypeAndValue)
if char == ',' || char == ';' {
if char == ',' {
dn.RDNs = append(dn.RDNs, rdn)
rdn = new(RelativeDN)
rdn.Attributes = make([]*AttributeTypeAndValue, 0)
@ -286,7 +206,7 @@ func (a *AttributeTypeAndValue) Equal(other *AttributeTypeAndValue) bool {
return strings.EqualFold(a.Type, other.Type) && a.Value == other.Value
}
// EqualFold returns true if the DNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch).
// Equal returns true if the DNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch).
// Returns true if they have the same number of relative distinguished names
// and corresponding relative distinguished names (by position) are the same.
// Case of the attribute type and value is not significant
@ -318,7 +238,7 @@ func (d *DN) AncestorOfFold(other *DN) bool {
return true
}
// EqualFold returns true if the RelativeDNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch).
// Equal returns true if the RelativeDNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch).
// Case of the attribute type is not significant
func (r *RelativeDN) EqualFold(other *RelativeDN) bool {
if len(r.Attributes) != len(other.Attributes) {

View file

@ -192,8 +192,6 @@ func (e *Error) Error() string {
return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
}
func (e *Error) Unwrap() error { return e.Err }
// GetLDAPError creates an Error out of a BER packet representing a LDAPResult
// The return is an error object. It can be casted to a Error structure.
// This function returns nil if resultCode in the LDAPResult sequence is success(0).
@ -208,21 +206,15 @@ func GetLDAPError(packet *ber.Packet) error {
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 ber.Type(response.Children[0].Tag) == ber.Type(ber.TagInteger) || ber.Type(response.Children[0].Tag) == ber.Type(ber.TagEnumerated) {
resultCode := uint16(response.Children[0].Value.(int64))
if resultCode == 0 { // No error
return nil
}
if ber.Type(response.Children[1].Tag) == ber.Type(ber.TagOctetString) &&
ber.Type(response.Children[2].Tag) == ber.Type(ber.TagOctetString) {
return &Error{
ResultCode: resultCode,
MatchedDN: response.Children[1].Value.(string),
Err: fmt.Errorf("%s", response.Children[2].Value.(string)),
Packet: packet,
}
}
resultCode := uint16(response.Children[0].Value.(int64))
if resultCode == 0 { // No error
return nil
}
return &Error{
ResultCode: resultCode,
MatchedDN: response.Children[1].Value.(string),
Err: fmt.Errorf("%s", response.Children[2].Value.(string)),
Packet: packet,
}
}
}

View file

@ -396,7 +396,7 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
case packet.Tag == FilterEqualityMatch && bytes.Equal(condition.Bytes(), _SymbolAny):
packet = ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterPresent, attribute.String(), FilterMap[FilterPresent])
case packet.Tag == FilterEqualityMatch && bytes.Contains(condition.Bytes(), _SymbolAny):
case packet.Tag == FilterEqualityMatch && bytes.Index(condition.Bytes(), _SymbolAny) > -1:
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute.String(), "Attribute"))
packet.Tag = FilterSubstrings
packet.Description = FilterMap[uint64(packet.Tag)]
@ -438,6 +438,7 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
// Convert from "ABC\xx\xx\xx" form to literal bytes for transport
func decodeEscapedSymbols(src []byte) (string, error) {
var (
buffer bytes.Buffer
offset int

View file

@ -3,9 +3,7 @@ package ldap
import (
"fmt"
"io/ioutil"
"log"
"os"
"strings"
ber "github.com/go-asn1-ber/asn1-ber"
)
@ -32,7 +30,6 @@ const (
ApplicationSearchResultReference = 19
ApplicationExtendedRequest = 23
ApplicationExtendedResponse = 24
ApplicationIntermediateResponse = 25
)
// ApplicationMap contains human readable descriptions of LDAP Application Codes
@ -57,7 +54,6 @@ var ApplicationMap = map[uint8]string{
ApplicationSearchResultReference: "Search Result Reference",
ApplicationExtendedRequest: "Extended Request",
ApplicationExtendedResponse: "Extended Response",
ApplicationIntermediateResponse: "Intermediate Response",
}
// Ldap Behera Password Policy Draft 10 (https://tools.ietf.org/html/draft-behera-ldap-password-policy-10)
@ -86,13 +82,6 @@ var BeheraPasswordPolicyErrorMap = map[int8]string{
BeheraPasswordInHistory: "New password is in list of old passwords",
}
var logger = log.New(os.Stderr, "", log.LstdFlags)
// Logger allows clients to override the default logger
func Logger(l *log.Logger) {
logger = l
}
// Adds descriptions to an LDAP Response packet for debugging
func addLDAPDescriptions(packet *ber.Packet) (err error) {
defer func() {
@ -232,18 +221,18 @@ func addControlDescriptions(packet *ber.Packet) error {
sequence := value.Children[0]
for _, child := range sequence.Children {
if child.Tag == 0 {
// Warning
//Warning
warningPacket := child.Children[0]
val, err := ber.ParseInt64(warningPacket.Data.Bytes())
if err != nil {
return fmt.Errorf("failed to decode data bytes: %s", err)
}
if warningPacket.Tag == 0 {
// timeBeforeExpiration
//timeBeforeExpiration
value.Description += " (TimeBeforeExpiration)"
warningPacket.Value = val
} else if warningPacket.Tag == 1 {
// graceAuthNsRemaining
//graceAuthNsRemaining
value.Description += " (GraceAuthNsRemaining)"
warningPacket.Value = val
}
@ -348,43 +337,3 @@ func EscapeFilter(filter string) string {
}
return string(buf)
}
// EscapeDN escapes distinguished names as described in RFC4514. Characters in the
// set `"+,;<>\` are escaped by prepending a backslash, which is also done for trailing
// spaces or a leading `#`. Null bytes are replaced with `\00`.
func EscapeDN(dn string) string {
if dn == "" {
return ""
}
builder := strings.Builder{}
for i, r := range dn {
// Escape leading and trailing spaces
if (i == 0 || i == len(dn)-1) && r == ' ' {
builder.WriteRune('\\')
builder.WriteRune(r)
continue
}
// Escape leading '#'
if i == 0 && r == '#' {
builder.WriteRune('\\')
builder.WriteRune(r)
continue
}
// Escape characters as defined in RFC4514
switch r {
case '"', '+', ',', ';', '<', '>', '\\':
builder.WriteRune('\\')
builder.WriteRune(r)
case '\x00': // Null byte may not be escaped by a leading backslash
builder.WriteString("\\00")
default:
builder.WriteRune(r)
}
}
return builder.String()
}

View file

@ -1,7 +1,8 @@
package ldap
import (
"fmt"
"log"
ber "github.com/go-asn1-ber/asn1-ber"
)
@ -24,9 +25,7 @@ type ModifyDNRequest struct {
// RDN of the given DN.
//
// A call like
//
// mdnReq := NewModifyDNRequest("uid=someone,dc=example,dc=org", "uid=newname", true, "")
//
// mdnReq := NewModifyDNRequest("uid=someone,dc=example,dc=org", "uid=newname", true, "")
// will setup the request to just rename uid=someone,dc=example,dc=org to
// uid=newname,dc=example,dc=org.
func NewModifyDNRequest(dn string, rdn string, delOld bool, newSup string) *ModifyDNRequest {
@ -95,8 +94,7 @@ func (l *Conn) ModifyDN(m *ModifyDNRequest) error {
return err
}
} else {
return fmt.Errorf("ldap: unexpected response: %d", packet.Children[1].Tag)
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
}
return nil
}

View file

@ -2,7 +2,7 @@ package ldap
import (
"errors"
"fmt"
"log"
ber "github.com/go-asn1-ber/asn1-ber"
)
@ -127,9 +127,8 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
return err
}
} else {
return fmt.Errorf("ldap: unexpected response: %d", packet.Children[1].Tag)
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
}
return nil
}
@ -137,8 +136,6 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
type ModifyResult struct {
// Controls are the returned controls
Controls []Control
// Referral is the returned referral
Referral string
}
// ModifyWithResult performs the ModifyRequest and returns the result
@ -161,10 +158,9 @@ func (l *Conn) ModifyWithResult(modifyRequest *ModifyRequest) (*ModifyResult, er
switch packet.Children[1].Tag {
case ApplicationModifyResponse:
if err = GetLDAPError(packet); err != nil {
result.Referral = getReferral(err, packet)
return result, err
err := GetLDAPError(packet)
if err != nil {
return nil, err
}
if len(packet.Children) == 3 {
for _, child := range packet.Children[2].Children {

View file

@ -70,6 +70,7 @@ func (req *PasswordModifyRequest) appendTo(envelope *ber.Packet) error {
// newPassword is the desired user's password. If empty the server can return
// an error or generate a new password that will be available in the
// PasswordModifyResult.GeneratedPassword
//
func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPassword string) *PasswordModifyRequest {
return &PasswordModifyRequest{
UserIdentity: userIdentity,
@ -94,9 +95,15 @@ func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*Pa
result := &PasswordModifyResult{}
if packet.Children[1].Tag == ApplicationExtendedResponse {
if err = GetLDAPError(packet); err != nil {
result.Referral = getReferral(err, packet)
err := GetLDAPError(packet)
if err != nil {
if IsErrorWithCode(err, LDAPResultReferral) {
for _, child := range packet.Children[1].Children {
if child.Tag == 3 {
result.Referral = child.Children[0].Value.(string)
}
}
}
return result, err
}
} else {
@ -105,10 +112,10 @@ func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*Pa
extendedResponse := packet.Children[1]
for _, child := range extendedResponse.Children {
if child.Tag == ber.TagEmbeddedPDV {
if child.Tag == 11 {
passwordModifyResponseValue := ber.DecodePacket(child.Data.Bytes())
if len(passwordModifyResponseValue.Children) == 1 {
if passwordModifyResponseValue.Children[0].Tag == ber.TagEOC {
if passwordModifyResponseValue.Children[0].Tag == 0 {
result.GeneratedPassword = ber.DecodeString(passwordModifyResponseValue.Children[0].Data.Bytes())
}
}

View file

@ -9,8 +9,7 @@ import (
var (
errRespChanClosed = errors.New("ldap: response channel closed")
errCouldNotRetMsg = errors.New("ldap: could not retrieve message")
// ErrNilConnection is returned if doRequest is called with a nil connection.
ErrNilConnection = errors.New("ldap: conn is nil, expected net.Conn")
ErrNilConnection = errors.New("ldap: conn is nil, expected net.Conn")
)
type request interface {
@ -70,41 +69,3 @@ func (l *Conn) readPacket(msgCtx *messageContext) (*ber.Packet, error) {
}
return packet, nil
}
func getReferral(err error, packet *ber.Packet) (referral string) {
if !IsErrorWithCode(err, LDAPResultReferral) {
return ""
}
if len(packet.Children) < 2 {
return ""
}
// The packet Tag itself (of child 2) is generally a ber.TagObjectDescriptor with referrals however OpenLDAP
// seemingly returns a ber.Tag.GeneralizedTime. Every currently tested LDAP server which returns referrals returns
// an ASN.1 BER packet with the Type of ber.TypeConstructed and Class of ber.ClassApplication however. Thus this
// check expressly checks these fields instead.
//
// Related Issues:
// - https://github.com/authelia/authelia/issues/4199 (downstream)
if len(packet.Children[1].Children) == 0 || (packet.Children[1].TagType != ber.TypeConstructed || packet.Children[1].ClassType != ber.ClassApplication) {
return ""
}
var ok bool
for _, child := range packet.Children[1].Children {
// The referral URI itself should be contained within a child which has a Tag of ber.BitString or
// ber.TagPrintableString, and the Type of ber.TypeConstructed and the Class of ClassContext. As soon as any of
// these conditions is not true we can skip this child.
if (child.Tag != ber.TagBitString && child.Tag != ber.TagPrintableString) || child.TagType != ber.TypeConstructed || child.ClassType != ber.ClassContext {
continue
}
if referral, ok = child.Children[0].Value.(string); ok {
return referral
}
}
return ""
}

View file

@ -1,207 +0,0 @@
package ldap
import (
"context"
"errors"
"fmt"
ber "github.com/go-asn1-ber/asn1-ber"
)
// Response defines an interface to get data from an LDAP server
type Response interface {
Entry() *Entry
Referral() string
Controls() []Control
Err() error
Next() bool
}
type searchResponse struct {
conn *Conn
ch chan *SearchSingleResult
entry *Entry
referral string
controls []Control
err error
}
// Entry returns an entry from the given search request
func (r *searchResponse) Entry() *Entry {
return r.entry
}
// Referral returns a referral from the given search request
func (r *searchResponse) Referral() string {
return r.referral
}
// Controls returns controls from the given search request
func (r *searchResponse) Controls() []Control {
return r.controls
}
// Err returns an error when the given search request was failed
func (r *searchResponse) Err() error {
return r.err
}
// Next returns whether next data exist or not
func (r *searchResponse) Next() bool {
res, ok := <-r.ch
if !ok {
return false
}
if res == nil {
return false
}
r.err = res.Error
if r.err != nil {
return false
}
r.entry = res.Entry
r.referral = res.Referral
r.controls = res.Controls
return true
}
func (r *searchResponse) start(ctx context.Context, searchRequest *SearchRequest) {
go func() {
defer func() {
close(r.ch)
if err := recover(); err != nil {
r.conn.err = fmt.Errorf("ldap: recovered panic in searchResponse: %v", err)
}
}()
if r.conn.IsClosing() {
return
}
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, r.conn.nextMessageID(), "MessageID"))
// encode search request
err := searchRequest.appendTo(packet)
if err != nil {
r.ch <- &SearchSingleResult{Error: err}
return
}
r.conn.Debug.PrintPacket(packet)
msgCtx, err := r.conn.sendMessage(packet)
if err != nil {
r.ch <- &SearchSingleResult{Error: err}
return
}
defer r.conn.finishMessage(msgCtx)
foundSearchSingleResultDone := false
for !foundSearchSingleResultDone {
select {
case <-ctx.Done():
r.conn.Debug.Printf("%d: %s", msgCtx.id, ctx.Err().Error())
return
default:
r.conn.Debug.Printf("%d: waiting for response", msgCtx.id)
packetResponse, ok := <-msgCtx.responses
if !ok {
err := NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
r.ch <- &SearchSingleResult{Error: err}
return
}
packet, err = packetResponse.ReadPacket()
r.conn.Debug.Printf("%d: got response %p", msgCtx.id, packet)
if err != nil {
r.ch <- &SearchSingleResult{Error: err}
return
}
if r.conn.Debug {
if err := addLDAPDescriptions(packet); err != nil {
r.ch <- &SearchSingleResult{Error: err}
return
}
ber.PrintPacket(packet)
}
switch packet.Children[1].Tag {
case ApplicationSearchResultEntry:
result := &SearchSingleResult{
Entry: &Entry{
DN: packet.Children[1].Children[0].Value.(string),
Attributes: unpackAttributes(packet.Children[1].Children[1].Children),
},
}
if len(packet.Children) != 3 {
r.ch <- result
continue
}
decoded, err := DecodeControl(packet.Children[2].Children[0])
if err != nil {
werr := fmt.Errorf("failed to decode search result entry: %w", err)
result.Error = werr
r.ch <- result
return
}
result.Controls = append(result.Controls, decoded)
r.ch <- result
case ApplicationSearchResultDone:
if err := GetLDAPError(packet); err != nil {
r.ch <- &SearchSingleResult{Error: err}
return
}
if len(packet.Children) == 3 {
result := &SearchSingleResult{}
for _, child := range packet.Children[2].Children {
decodedChild, err := DecodeControl(child)
if err != nil {
werr := fmt.Errorf("failed to decode child control: %w", err)
r.ch <- &SearchSingleResult{Error: werr}
return
}
result.Controls = append(result.Controls, decodedChild)
}
r.ch <- result
}
foundSearchSingleResultDone = true
case ApplicationSearchResultReference:
ref := packet.Children[1].Children[0].Value.(string)
r.ch <- &SearchSingleResult{Referral: ref}
case ApplicationIntermediateResponse:
decoded, err := DecodeControl(packet.Children[1])
if err != nil {
werr := fmt.Errorf("failed to decode intermediate response: %w", err)
r.ch <- &SearchSingleResult{Error: werr}
return
}
result := &SearchSingleResult{}
result.Controls = append(result.Controls, decoded)
r.ch <- result
default:
err := fmt.Errorf("unknown tag: %d", packet.Children[1].Tag)
r.ch <- &SearchSingleResult{Error: err}
return
}
}
}
r.conn.Debug.Printf("%d: returning", msgCtx.id)
}()
}
func newSearchResponse(conn *Conn, bufferSize int) *searchResponse {
var ch chan *SearchSingleResult
if bufferSize > 0 {
ch = make(chan *SearchSingleResult, bufferSize)
} else {
ch = make(chan *SearchSingleResult)
}
return &searchResponse{
conn: conn,
ch: ch,
}
}

View file

@ -1,14 +1,10 @@
package ldap
import (
"context"
"errors"
"fmt"
"reflect"
"sort"
"strconv"
"strings"
"time"
ber "github.com/go-asn1-ber/asn1-ber"
)
@ -165,155 +161,6 @@ func (e *Entry) PrettyPrint(indent int) {
}
}
// Describe the tag to use for struct field tags
const decoderTagName = "ldap"
// readTag will read the reflect.StructField value for
// the key defined in decoderTagName. If omitempty is
// specified, the field may not be filled.
func readTag(f reflect.StructField) (string, bool) {
val, ok := f.Tag.Lookup(decoderTagName)
if !ok {
return f.Name, false
}
opts := strings.Split(val, ",")
omit := false
if len(opts) == 2 {
omit = opts[1] == "omitempty"
}
return opts[0], omit
}
// Unmarshal parses the Entry in the value pointed to by i
//
// Currently, this methods only supports struct fields of type
// string, []string, int, int64, []byte, *DN, []*DN or time.Time. Other field types
// will not be regarded. If the field type is a string or int but multiple
// attribute values are returned, the first value will be used to fill the field.
//
// Example:
//
// type UserEntry struct {
// // Fields with the tag key `dn` are automatically filled with the
// // objects distinguishedName. This can be used multiple times.
// DN string `ldap:"dn"`
//
// // This field will be filled with the attribute value for
// // userPrincipalName. An attribute can be read into a struct field
// // multiple times. Missing attributes will not result in an error.
// UserPrincipalName string `ldap:"userPrincipalName"`
//
// // memberOf may have multiple values. If you don't
// // know the amount of attribute values at runtime, use a string array.
// MemberOf []string `ldap:"memberOf"`
//
// // ID is an integer value, it will fail unmarshaling when the given
// // attribute value cannot be parsed into an integer.
// ID int `ldap:"id"`
//
// // LongID is similar to ID but uses an int64 instead.
// LongID int64 `ldap:"longId"`
//
// // Data is similar to MemberOf a slice containing all attribute
// // values.
// Data []byte `ldap:"data"`
//
// // Time is parsed with the generalizedTime spec into a time.Time
// Created time.Time `ldap:"createdTimestamp"`
//
// // *DN is parsed with the ParseDN
// Owner *ldap.DN `ldap:"owner"`
//
// // []*DN is parsed with the ParseDN
// Children []*ldap.DN `ldap:"children"`
//
// // This won't work, as the field is not of type string. For this
// // to work, you'll have to temporarily store the result in string
// // (or string array) and convert it to the desired type afterwards.
// UserAccountControl uint32 `ldap:"userPrincipalName"`
// }
// user := UserEntry{}
//
// if err := result.Unmarshal(&user); err != nil {
// // ...
// }
func (e *Entry) Unmarshal(i interface{}) (err error) {
// Make sure it's a ptr
if vo := reflect.ValueOf(i).Kind(); vo != reflect.Ptr {
return fmt.Errorf("ldap: cannot use %s, expected pointer to a struct", vo)
}
sv, st := reflect.ValueOf(i).Elem(), reflect.TypeOf(i).Elem()
// Make sure it's pointing to a struct
if sv.Kind() != reflect.Struct {
return fmt.Errorf("ldap: expected pointer to a struct, got %s", sv.Kind())
}
for n := 0; n < st.NumField(); n++ {
// Holds struct field value and type
fv, ft := sv.Field(n), st.Field(n)
// skip unexported fields
if ft.PkgPath != "" {
continue
}
// omitempty can be safely discarded, as it's not needed when unmarshalling
fieldTag, _ := readTag(ft)
// Fill the field with the distinguishedName if the tag key is `dn`
if fieldTag == "dn" {
fv.SetString(e.DN)
continue
}
values := e.GetAttributeValues(fieldTag)
if len(values) == 0 {
continue
}
switch fv.Interface().(type) {
case []string:
for _, item := range values {
fv.Set(reflect.Append(fv, reflect.ValueOf(item)))
}
case string:
fv.SetString(values[0])
case []byte:
fv.SetBytes([]byte(values[0]))
case int, int64:
intVal, err := strconv.ParseInt(values[0], 10, 64)
if err != nil {
return fmt.Errorf("ldap: could not parse value '%s' into int field", values[0])
}
fv.SetInt(intVal)
case time.Time:
t, err := ber.ParseGeneralizedTime([]byte(values[0]))
if err != nil {
return fmt.Errorf("ldap: could not parse value '%s' into time.Time field", values[0])
}
fv.Set(reflect.ValueOf(t))
case *DN:
dn, err := ParseDN(values[0])
if err != nil {
return fmt.Errorf("ldap: could not parse value '%s' into *ldap.DN field", values[0])
}
fv.Set(reflect.ValueOf(dn))
case []*DN:
for _, item := range values {
dn, err := ParseDN(item)
if err != nil {
return fmt.Errorf("ldap: could not parse value '%s' into *ldap.DN field", item)
}
fv.Set(reflect.Append(fv, reflect.ValueOf(dn)))
}
default:
return fmt.Errorf("ldap: expected field to be of type string, []string, int, int64, []byte, *DN, []*DN or time.Time, got %v", ft.Type)
}
}
return
}
// NewEntryAttribute returns a new EntryAttribute with the desired key-value pair
func NewEntryAttribute(name string, values []string) *EntryAttribute {
var bytes [][]byte
@ -371,35 +218,6 @@ func (s *SearchResult) PrettyPrint(indent int) {
}
}
// appendTo appends all entries of `s` to `r`
func (s *SearchResult) appendTo(r *SearchResult) {
r.Entries = append(r.Entries, s.Entries...)
r.Referrals = append(r.Referrals, s.Referrals...)
r.Controls = append(r.Controls, s.Controls...)
}
// SearchSingleResult holds the server's single entry response to a search request
type SearchSingleResult struct {
// Entry is the returned entry
Entry *Entry
// Referral is the returned referral
Referral string
// Controls are the returned controls
Controls []Control
// Error is set when the search request was failed
Error error
}
// Print outputs a human-readable description
func (s *SearchSingleResult) Print() {
s.Entry.Print()
}
// PrettyPrint outputs a human-readable description with indenting
func (s *SearchSingleResult) PrettyPrint(indent int) {
s.Entry.PrettyPrint(indent)
}
// SearchRequest represents a search request to send to the server
type SearchRequest struct {
BaseDN string
@ -467,11 +285,10 @@ func NewSearchRequest(
// SearchWithPaging accepts a search request and desired page size in order to execute LDAP queries to fulfill the
// search request. All paged LDAP query responses will be buffered and the final result will be returned atomically.
// The following four cases are possible given the arguments:
// - given SearchRequest missing a control of type ControlTypePaging: we will add one with the desired paging size
// - given SearchRequest contains a control of type ControlTypePaging that isn't actually a ControlPaging: fail without issuing any queries
// - given SearchRequest contains a control of type ControlTypePaging with pagingSize equal to the size requested: no change to the search request
// - given SearchRequest contains a control of type ControlTypePaging with pagingSize not equal to the size requested: fail without issuing any queries
//
// - given SearchRequest missing a control of type ControlTypePaging: we will add one with the desired paging size
// - given SearchRequest contains a control of type ControlTypePaging that isn't actually a ControlPaging: fail without issuing any queries
// - given SearchRequest contains a control of type ControlTypePaging with pagingSize equal to the size requested: no change to the search request
// - given SearchRequest contains a control of type ControlTypePaging with pagingSize not equal to the size requested: fail without issuing any queries
// A requested pagingSize of 0 is interpreted as no limit by LDAP servers.
func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) {
var pagingControl *ControlPaging
@ -494,19 +311,23 @@ func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32)
searchResult := new(SearchResult)
for {
result, err := l.Search(searchRequest)
if result != nil {
result.appendTo(searchResult)
} else {
if err == nil {
// We have to do this beautifulness in case something absolutely strange happens, which
// should only occur in case there is no packet, but also no error.
return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received"))
}
}
l.Debug.Printf("Looking for Paging Control...")
if err != nil {
// If an error occurred, all results that have been received so far will be returned
return searchResult, err
}
if result == nil {
return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received"))
}
for _, entry := range result.Entries {
searchResult.Entries = append(searchResult.Entries, entry)
}
for _, referral := range result.Referrals {
searchResult.Referrals = append(searchResult.Referrals, referral)
}
for _, control := range result.Controls {
searchResult.Controls = append(searchResult.Controls, control)
}
l.Debug.Printf("Looking for Paging Control...")
pagingResult := FindControl(result.Controls, ControlTypePaging)
@ -528,9 +349,7 @@ func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32)
if pagingControl != nil {
l.Debug.Printf("Abandoning Paging...")
pagingControl.PagingSize = 0
if _, err := l.Search(searchRequest); err != nil {
return searchResult, err
}
l.Search(searchRequest)
}
return searchResult, nil
@ -547,8 +366,7 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
result := &SearchResult{
Entries: make([]*Entry, 0),
Referrals: make([]string, 0),
Controls: make([]Control, 0),
}
Controls: make([]Control, 0)}
for {
packet, err := l.readPacket(msgCtx)
@ -584,32 +402,6 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
}
}
// SearchAsync performs a search request and returns all search results asynchronously.
// This means you get all results until an error happens (or the search successfully finished),
// e.g. for size / time limited requests all are recieved until the limit is reached.
// To stop the search, call cancel function of the context.
func (l *Conn) SearchAsync(
ctx context.Context, searchRequest *SearchRequest, bufferSize int) Response {
r := newSearchResponse(l, bufferSize)
r.start(ctx, searchRequest)
return r
}
// Syncrepl is a short name for LDAP Sync Replication engine that works on the
// consumer-side. This can perform a persistent search and returns an entry
// when the entry is updated on the server side.
// To stop the search, call cancel function of the context.
func (l *Conn) Syncrepl(
ctx context.Context, searchRequest *SearchRequest, bufferSize int,
mode ControlSyncRequestMode, cookie []byte, reloadHint bool,
) Response {
control := NewControlSyncRequest(mode, cookie, reloadHint)
searchRequest.Controls = append(searchRequest.Controls, control)
r := newSearchResponse(l, bufferSize)
r.start(ctx, searchRequest)
return r
}
// unpackAttributes will extract all given LDAP attributes and it's values
// from the ber.Packet
func unpackAttributes(children []*ber.Packet) []*EntryAttribute {
@ -633,58 +425,3 @@ func unpackAttributes(children []*ber.Packet) []*EntryAttribute {
return entries
}
// DirSync does a Search with dirSync Control.
func (l *Conn) DirSync(
searchRequest *SearchRequest, flags int64, maxAttrCount int64, cookie []byte,
) (*SearchResult, error) {
control := FindControl(searchRequest.Controls, ControlTypeDirSync)
if control == nil {
c := NewRequestControlDirSync(flags, maxAttrCount, cookie)
searchRequest.Controls = append(searchRequest.Controls, c)
} else {
c := control.(*ControlDirSync)
if c.Flags != flags {
return nil, fmt.Errorf("flags given in search request (%d) conflicts with flags given in search call (%d)", c.Flags, flags)
}
if c.MaxAttrCount != maxAttrCount {
return nil, fmt.Errorf("MaxAttrCnt given in search request (%d) conflicts with maxAttrCount given in search call (%d)", c.MaxAttrCount, maxAttrCount)
}
}
searchResult, err := l.Search(searchRequest)
l.Debug.Printf("Looking for result...")
if err != nil {
return nil, err
}
if searchResult == nil {
return nil, NewError(ErrorNetwork, errors.New("ldap: packet not received"))
}
l.Debug.Printf("Looking for DirSync Control...")
resultControl := FindControl(searchResult.Controls, ControlTypeDirSync)
if resultControl == nil {
l.Debug.Printf("Could not find dirSyncControl control. Breaking...")
return searchResult, nil
}
cookie = resultControl.(*ControlDirSync).Cookie
if len(cookie) == 0 {
l.Debug.Printf("Could not find cookie. Breaking...")
return searchResult, nil
}
return searchResult, nil
}
// DirSyncDirSyncAsync performs a search request and returns all search results
// asynchronously. This is efficient when the server returns lots of entries.
func (l *Conn) DirSyncAsync(
ctx context.Context, searchRequest *SearchRequest, bufferSize int,
flags, maxAttrCount int64, cookie []byte,
) Response {
control := NewRequestControlDirSync(flags, maxAttrCount, cookie)
searchRequest.Controls = append(searchRequest.Controls, control)
r := newSearchResponse(l, bufferSize)
r.start(ctx, searchRequest)
return r
}

View file

@ -6,7 +6,6 @@ import (
ber "github.com/go-asn1-ber/asn1-ber"
)
// ErrConnUnbound is returned when Unbind is called on an already closing connection.
var ErrConnUnbound = NewError(ErrorNetwork, errors.New("ldap: connection is closed"))
type unbindRequest struct{}

View file

@ -1,10 +0,0 @@
# Changelog
## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18)
### Bug Fixes
* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0))
## Changelog

View file

@ -1,26 +0,0 @@
# How to contribute
We definitely welcome patches and contribution to this project!
### Tips
Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org).
Always try to include a test case! If it is not possible or not necessary,
please explain why in the pull request description.
### Releasing
Commits that would precipitate a SemVer change, as desrcibed in the Conventional
Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action)
to create a release candidate pull request. Once submitted, `release-please`
will create a release.
For tips on how to work with `release-please`, see its documentation.
### Legal requirements
In order to protect both you and ourselves, you will need to sign the
[Contributor License Agreement](https://cla.developers.google.com/clas).
You may have already signed it for other Google projects.

View file

@ -1,9 +0,0 @@
Paul Borman <borman@google.com>
bmatsuo
shawnps
theory
jboverfelt
dsymonds
cd1
wallclockbuilder
dansouza

View file

@ -1,27 +0,0 @@
Copyright (c) 2009,2014 Google Inc. 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.

View file

@ -1,21 +0,0 @@
# uuid
The uuid package generates and inspects UUIDs based on
[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122)
and DCE 1.1: Authentication and Security Services.
This package is based on the github.com/pborman/uuid package (previously named
code.google.com/p/go-uuid). It differs from these earlier packages in that
a UUID is a 16 byte array rather than a byte slice. One loss due to this
change is the ability to represent an invalid UUID (vs a NIL UUID).
###### Install
```sh
go get github.com/google/uuid
```
###### Documentation
[![Go Reference](https://pkg.go.dev/badge/github.com/google/uuid.svg)](https://pkg.go.dev/github.com/google/uuid)
Full `go doc` style documentation for the package can be viewed online without
installing this package by using the GoDoc site here:
http://pkg.go.dev/github.com/google/uuid

80
vendor/github.com/google/uuid/dce.go generated vendored
View file

@ -1,80 +0,0 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"fmt"
"os"
)
// A Domain represents a Version 2 domain
type Domain byte
// Domain constants for DCE Security (Version 2) UUIDs.
const (
Person = Domain(0)
Group = Domain(1)
Org = Domain(2)
)
// NewDCESecurity returns a DCE Security (Version 2) UUID.
//
// The domain should be one of Person, Group or Org.
// On a POSIX system the id should be the users UID for the Person
// domain and the users GID for the Group. The meaning of id for
// the domain Org or on non-POSIX systems is site defined.
//
// For a given domain/id pair the same token may be returned for up to
// 7 minutes and 10 seconds.
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
uuid, err := NewUUID()
if err == nil {
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
uuid[9] = byte(domain)
binary.BigEndian.PutUint32(uuid[0:], id)
}
return uuid, err
}
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
// domain with the id returned by os.Getuid.
//
// NewDCESecurity(Person, uint32(os.Getuid()))
func NewDCEPerson() (UUID, error) {
return NewDCESecurity(Person, uint32(os.Getuid()))
}
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
// domain with the id returned by os.Getgid.
//
// NewDCESecurity(Group, uint32(os.Getgid()))
func NewDCEGroup() (UUID, error) {
return NewDCESecurity(Group, uint32(os.Getgid()))
}
// Domain returns the domain for a Version 2 UUID. Domains are only defined
// for Version 2 UUIDs.
func (uuid UUID) Domain() Domain {
return Domain(uuid[9])
}
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
// UUIDs.
func (uuid UUID) ID() uint32 {
return binary.BigEndian.Uint32(uuid[0:4])
}
func (d Domain) String() string {
switch d {
case Person:
return "Person"
case Group:
return "Group"
case Org:
return "Org"
}
return fmt.Sprintf("Domain%d", int(d))
}

12
vendor/github.com/google/uuid/doc.go generated vendored
View file

@ -1,12 +0,0 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package uuid generates and inspects UUIDs.
//
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
// Services.
//
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
// maps or compared directly.
package uuid

View file

@ -1,53 +0,0 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"crypto/md5"
"crypto/sha1"
"hash"
)
// Well known namespace IDs and UUIDs
var (
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
Nil UUID // empty UUID, all zeros
)
// NewHash returns a new UUID derived from the hash of space concatenated with
// data generated by h. The hash should be at least 16 byte in length. The
// first 16 bytes of the hash are used to form the UUID. The version of the
// UUID will be the lower 4 bits of version. NewHash is used to implement
// NewMD5 and NewSHA1.
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
h.Reset()
h.Write(space[:]) //nolint:errcheck
h.Write(data) //nolint:errcheck
s := h.Sum(nil)
var uuid UUID
copy(uuid[:], s)
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
return uuid
}
// NewMD5 returns a new MD5 (Version 3) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(md5.New(), space, data, 3)
func NewMD5(space UUID, data []byte) UUID {
return NewHash(md5.New(), space, data, 3)
}
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(sha1.New(), space, data, 5)
func NewSHA1(space UUID, data []byte) UUID {
return NewHash(sha1.New(), space, data, 5)
}

View file

@ -1,38 +0,0 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "fmt"
// MarshalText implements encoding.TextMarshaler.
func (uuid UUID) MarshalText() ([]byte, error) {
var js [36]byte
encodeHex(js[:], uuid)
return js[:], nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (uuid *UUID) UnmarshalText(data []byte) error {
id, err := ParseBytes(data)
if err != nil {
return err
}
*uuid = id
return nil
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (uuid UUID) MarshalBinary() ([]byte, error) {
return uuid[:], nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (uuid *UUID) UnmarshalBinary(data []byte) error {
if len(data) != 16 {
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
}
copy(uuid[:], data)
return nil
}

View file

@ -1,90 +0,0 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"sync"
)
var (
nodeMu sync.Mutex
ifname string // name of interface being used
nodeID [6]byte // hardware for version 1 UUIDs
zeroID [6]byte // nodeID with only 0's
)
// NodeInterface returns the name of the interface from which the NodeID was
// derived. The interface "user" is returned if the NodeID was set by
// SetNodeID.
func NodeInterface() string {
defer nodeMu.Unlock()
nodeMu.Lock()
return ifname
}
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
// If name is "" then the first usable interface found will be used or a random
// Node ID will be generated. If a named interface cannot be found then false
// is returned.
//
// SetNodeInterface never fails when name is "".
func SetNodeInterface(name string) bool {
defer nodeMu.Unlock()
nodeMu.Lock()
return setNodeInterface(name)
}
func setNodeInterface(name string) bool {
iname, addr := getHardwareInterface(name) // null implementation for js
if iname != "" && addr != nil {
ifname = iname
copy(nodeID[:], addr)
return true
}
// We found no interfaces with a valid hardware address. If name
// does not specify a specific interface generate a random Node ID
// (section 4.1.6)
if name == "" {
ifname = "random"
randomBits(nodeID[:])
return true
}
return false
}
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
// if not already set.
func NodeID() []byte {
defer nodeMu.Unlock()
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
nid := nodeID
return nid[:]
}
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
// of id are used. If id is less than 6 bytes then false is returned and the
// Node ID is not set.
func SetNodeID(id []byte) bool {
if len(id) < 6 {
return false
}
defer nodeMu.Unlock()
nodeMu.Lock()
copy(nodeID[:], id)
ifname = "user"
return true
}
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) NodeID() []byte {
var node [6]byte
copy(node[:], uuid[10:])
return node[:]
}

View file

@ -1,12 +0,0 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build js
package uuid
// getHardwareInterface returns nil values for the JS version of the code.
// This removes the "net" dependency, because it is not used in the browser.
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
func getHardwareInterface(name string) (string, []byte) { return "", nil }

View file

@ -1,33 +0,0 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !js
package uuid
import "net"
var interfaces []net.Interface // cached list of interfaces
// getHardwareInterface returns the name and hardware address of interface name.
// If name is "" then the name and hardware address of one of the system's
// interfaces is returned. If no interfaces are found (name does not exist or
// there are no interfaces) then "", nil is returned.
//
// Only addresses of at least 6 bytes are returned.
func getHardwareInterface(name string) (string, []byte) {
if interfaces == nil {
var err error
interfaces, err = net.Interfaces()
if err != nil {
return "", nil
}
}
for _, ifs := range interfaces {
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
return ifs.Name, ifs.HardwareAddr
}
}
return "", nil
}

118
vendor/github.com/google/uuid/null.go generated vendored
View file

@ -1,118 +0,0 @@
// Copyright 2021 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
)
var jsonNull = []byte("null")
// NullUUID represents a UUID that may be null.
// NullUUID implements the SQL driver.Scanner interface so
// it can be used as a scan destination:
//
// var u uuid.NullUUID
// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u)
// ...
// if u.Valid {
// // use u.UUID
// } else {
// // NULL value
// }
//
type NullUUID struct {
UUID UUID
Valid bool // Valid is true if UUID is not NULL
}
// Scan implements the SQL driver.Scanner interface.
func (nu *NullUUID) Scan(value interface{}) error {
if value == nil {
nu.UUID, nu.Valid = Nil, false
return nil
}
err := nu.UUID.Scan(value)
if err != nil {
nu.Valid = false
return err
}
nu.Valid = true
return nil
}
// Value implements the driver Valuer interface.
func (nu NullUUID) Value() (driver.Value, error) {
if !nu.Valid {
return nil, nil
}
// Delegate to UUID Value function
return nu.UUID.Value()
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (nu NullUUID) MarshalBinary() ([]byte, error) {
if nu.Valid {
return nu.UUID[:], nil
}
return []byte(nil), nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (nu *NullUUID) UnmarshalBinary(data []byte) error {
if len(data) != 16 {
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
}
copy(nu.UUID[:], data)
nu.Valid = true
return nil
}
// MarshalText implements encoding.TextMarshaler.
func (nu NullUUID) MarshalText() ([]byte, error) {
if nu.Valid {
return nu.UUID.MarshalText()
}
return jsonNull, nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (nu *NullUUID) UnmarshalText(data []byte) error {
id, err := ParseBytes(data)
if err != nil {
nu.Valid = false
return err
}
nu.UUID = id
nu.Valid = true
return nil
}
// MarshalJSON implements json.Marshaler.
func (nu NullUUID) MarshalJSON() ([]byte, error) {
if nu.Valid {
return json.Marshal(nu.UUID)
}
return jsonNull, nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (nu *NullUUID) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, jsonNull) {
*nu = NullUUID{}
return nil // valid null UUID
}
err := json.Unmarshal(data, &nu.UUID)
nu.Valid = err == nil
return err
}

59
vendor/github.com/google/uuid/sql.go generated vendored
View file

@ -1,59 +0,0 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"database/sql/driver"
"fmt"
)
// Scan implements sql.Scanner so UUIDs can be read from databases transparently.
// Currently, database types that map to string and []byte are supported. Please
// consult database-specific driver documentation for matching types.
func (uuid *UUID) Scan(src interface{}) error {
switch src := src.(type) {
case nil:
return nil
case string:
// if an empty UUID comes from a table, we return a null UUID
if src == "" {
return nil
}
// see Parse for required string format
u, err := Parse(src)
if err != nil {
return fmt.Errorf("Scan: %v", err)
}
*uuid = u
case []byte:
// if an empty UUID comes from a table, we return a null UUID
if len(src) == 0 {
return nil
}
// assumes a simple slice of bytes if 16 bytes
// otherwise attempts to parse
if len(src) != 16 {
return uuid.Scan(string(src))
}
copy((*uuid)[:], src)
default:
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
}
return nil
}
// Value implements sql.Valuer so that UUIDs can be written to databases
// transparently. Currently, UUIDs map to strings. Please consult
// database-specific driver documentation for matching types.
func (uuid UUID) Value() (driver.Value, error) {
return uuid.String(), nil
}

123
vendor/github.com/google/uuid/time.go generated vendored
View file

@ -1,123 +0,0 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"sync"
"time"
)
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
// 1582.
type Time int64
const (
lillian = 2299160 // Julian day of 15 Oct 1582
unix = 2440587 // Julian day of 1 Jan 1970
epoch = unix - lillian // Days between epochs
g1582 = epoch * 86400 // seconds between epochs
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
)
var (
timeMu sync.Mutex
lasttime uint64 // last time we returned
clockSeq uint16 // clock sequence for this run
timeNow = time.Now // for testing
)
// UnixTime converts t the number of seconds and nanoseconds using the Unix
// epoch of 1 Jan 1970.
func (t Time) UnixTime() (sec, nsec int64) {
sec = int64(t - g1582ns100)
nsec = (sec % 10000000) * 100
sec /= 10000000
return sec, nsec
}
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
// clock sequence as well as adjusting the clock sequence as needed. An error
// is returned if the current time cannot be determined.
func GetTime() (Time, uint16, error) {
defer timeMu.Unlock()
timeMu.Lock()
return getTime()
}
func getTime() (Time, uint16, error) {
t := timeNow()
// If we don't have a clock sequence already, set one.
if clockSeq == 0 {
setClockSequence(-1)
}
now := uint64(t.UnixNano()/100) + g1582ns100
// If time has gone backwards with this clock sequence then we
// increment the clock sequence
if now <= lasttime {
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
}
lasttime = now
return Time(now), clockSeq, nil
}
// ClockSequence returns the current clock sequence, generating one if not
// already set. The clock sequence is only used for Version 1 UUIDs.
//
// The uuid package does not use global static storage for the clock sequence or
// the last time a UUID was generated. Unless SetClockSequence is used, a new
// random clock sequence is generated the first time a clock sequence is
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
func ClockSequence() int {
defer timeMu.Unlock()
timeMu.Lock()
return clockSequence()
}
func clockSequence() int {
if clockSeq == 0 {
setClockSequence(-1)
}
return int(clockSeq & 0x3fff)
}
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
// -1 causes a new sequence to be generated.
func SetClockSequence(seq int) {
defer timeMu.Unlock()
timeMu.Lock()
setClockSequence(seq)
}
func setClockSequence(seq int) {
if seq == -1 {
var b [2]byte
randomBits(b[:]) // clock sequence
seq = int(b[0])<<8 | int(b[1])
}
oldSeq := clockSeq
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
if oldSeq != clockSeq {
lasttime = 0
}
}
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
// uuid. The time is only defined for version 1 and 2 UUIDs.
func (uuid UUID) Time() Time {
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
return Time(time)
}
// ClockSequence returns the clock sequence encoded in uuid.
// The clock sequence is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) ClockSequence() int {
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
}

View file

@ -1,43 +0,0 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"io"
)
// randomBits completely fills slice b with random data.
func randomBits(b []byte) {
if _, err := io.ReadFull(rander, b); err != nil {
panic(err.Error()) // rand should never fail
}
}
// xvalues returns the value of a byte as a hexadecimal digit or 255.
var xvalues = [256]byte{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
}
// xtob converts hex characters x1 and x2 into a byte.
func xtob(x1, x2 byte) (byte, bool) {
b1 := xvalues[x1]
b2 := xvalues[x2]
return (b1 << 4) | b2, b1 != 255 && b2 != 255
}

296
vendor/github.com/google/uuid/uuid.go generated vendored
View file

@ -1,296 +0,0 @@
// Copyright 2018 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"strings"
"sync"
)
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
// 4122.
type UUID [16]byte
// A Version represents a UUID's version.
type Version byte
// A Variant represents a UUID's variant.
type Variant byte
// Constants returned by Variant.
const (
Invalid = Variant(iota) // Invalid UUID
RFC4122 // The variant specified in RFC4122
Reserved // Reserved, NCS backward compatibility.
Microsoft // Reserved, Microsoft Corporation backward compatibility.
Future // Reserved for future definition.
)
const randPoolSize = 16 * 16
var (
rander = rand.Reader // random function
poolEnabled = false
poolMu sync.Mutex
poolPos = randPoolSize // protected with poolMu
pool [randPoolSize]byte // protected with poolMu
)
type invalidLengthError struct{ len int }
func (err invalidLengthError) Error() string {
return fmt.Sprintf("invalid UUID length: %d", err.len)
}
// IsInvalidLengthError is matcher function for custom error invalidLengthError
func IsInvalidLengthError(err error) bool {
_, ok := err.(invalidLengthError)
return ok
}
// Parse decodes s into a UUID or returns an error. Both the standard UUID
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex
// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
func Parse(s string) (UUID, error) {
var uuid UUID
switch len(s) {
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36:
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9:
if !strings.EqualFold(s[:9], "urn:uuid:") {
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
}
s = s[9:]
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
case 36 + 2:
s = s[1:]
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
case 32:
var ok bool
for i := range uuid {
uuid[i], ok = xtob(s[i*2], s[i*2+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
}
return uuid, nil
default:
return uuid, invalidLengthError{len(s)}
}
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return uuid, errors.New("invalid UUID format")
}
for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34,
} {
v, ok := xtob(s[x], s[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
uuid[i] = v
}
return uuid, nil
}
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
func ParseBytes(b []byte) (UUID, error) {
var uuid UUID
switch len(b) {
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) {
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
}
b = b[9:]
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
b = b[1:]
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
var ok bool
for i := 0; i < 32; i += 2 {
uuid[i/2], ok = xtob(b[i], b[i+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
}
return uuid, nil
default:
return uuid, invalidLengthError{len(b)}
}
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
return uuid, errors.New("invalid UUID format")
}
for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34,
} {
v, ok := xtob(b[x], b[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
uuid[i] = v
}
return uuid, nil
}
// MustParse is like Parse but panics if the string cannot be parsed.
// It simplifies safe initialization of global variables holding compiled UUIDs.
func MustParse(s string) UUID {
uuid, err := Parse(s)
if err != nil {
panic(`uuid: Parse(` + s + `): ` + err.Error())
}
return uuid
}
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
// does not have a length of 16. The bytes are copied from the slice.
func FromBytes(b []byte) (uuid UUID, err error) {
err = uuid.UnmarshalBinary(b)
return uuid, err
}
// Must returns uuid if err is nil and panics otherwise.
func Must(uuid UUID, err error) UUID {
if err != nil {
panic(err)
}
return uuid
}
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {
var buf [36]byte
encodeHex(buf[:], uuid)
return string(buf[:])
}
// URN returns the RFC 2141 URN form of uuid,
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
func (uuid UUID) URN() string {
var buf [36 + 9]byte
copy(buf[:], "urn:uuid:")
encodeHex(buf[9:], uuid)
return string(buf[:])
}
func encodeHex(dst []byte, uuid UUID) {
hex.Encode(dst, uuid[:4])
dst[8] = '-'
hex.Encode(dst[9:13], uuid[4:6])
dst[13] = '-'
hex.Encode(dst[14:18], uuid[6:8])
dst[18] = '-'
hex.Encode(dst[19:23], uuid[8:10])
dst[23] = '-'
hex.Encode(dst[24:], uuid[10:])
}
// Variant returns the variant encoded in uuid.
func (uuid UUID) Variant() Variant {
switch {
case (uuid[8] & 0xc0) == 0x80:
return RFC4122
case (uuid[8] & 0xe0) == 0xc0:
return Microsoft
case (uuid[8] & 0xe0) == 0xe0:
return Future
default:
return Reserved
}
}
// Version returns the version of uuid.
func (uuid UUID) Version() Version {
return Version(uuid[6] >> 4)
}
func (v Version) String() string {
if v > 15 {
return fmt.Sprintf("BAD_VERSION_%d", v)
}
return fmt.Sprintf("VERSION_%d", v)
}
func (v Variant) String() string {
switch v {
case RFC4122:
return "RFC4122"
case Reserved:
return "Reserved"
case Microsoft:
return "Microsoft"
case Future:
return "Future"
case Invalid:
return "Invalid"
}
return fmt.Sprintf("BadVariant%d", int(v))
}
// SetRand sets the random number generator to r, which implements io.Reader.
// If r.Read returns an error when the package requests random data then
// a panic will be issued.
//
// Calling SetRand with nil sets the random number generator to the default
// generator.
func SetRand(r io.Reader) {
if r == nil {
rander = rand.Reader
return
}
rander = r
}
// EnableRandPool enables internal randomness pool used for Random
// (Version 4) UUID generation. The pool contains random bytes read from
// the random number generator on demand in batches. Enabling the pool
// may improve the UUID generation throughput significantly.
//
// Since the pool is stored on the Go heap, this feature may be a bad fit
// for security sensitive applications.
//
// Both EnableRandPool and DisableRandPool are not thread-safe and should
// only be called when there is no possibility that New or any other
// UUID Version 4 generation function will be called concurrently.
func EnableRandPool() {
poolEnabled = true
}
// DisableRandPool disables the randomness pool if it was previously
// enabled with EnableRandPool.
//
// Both EnableRandPool and DisableRandPool are not thread-safe and should
// only be called when there is no possibility that New or any other
// UUID Version 4 generation function will be called concurrently.
func DisableRandPool() {
poolEnabled = false
defer poolMu.Unlock()
poolMu.Lock()
poolPos = randPoolSize
}

View file

@ -1,44 +0,0 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
)
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
// sequence, and the current time. If the NodeID has not been set by SetNodeID
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
// be set NewUUID returns nil. If clock sequence has not been set by
// SetClockSequence then it will be set automatically. If GetTime fails to
// return the current NewUUID returns nil and an error.
//
// In most cases, New should be used.
func NewUUID() (UUID, error) {
var uuid UUID
now, seq, err := GetTime()
if err != nil {
return uuid, err
}
timeLow := uint32(now & 0xffffffff)
timeMid := uint16((now >> 32) & 0xffff)
timeHi := uint16((now >> 48) & 0x0fff)
timeHi |= 0x1000 // Version 1
binary.BigEndian.PutUint32(uuid[0:], timeLow)
binary.BigEndian.PutUint16(uuid[4:], timeMid)
binary.BigEndian.PutUint16(uuid[6:], timeHi)
binary.BigEndian.PutUint16(uuid[8:], seq)
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
copy(uuid[10:], nodeID[:])
nodeMu.Unlock()
return uuid, nil
}

View file

@ -1,76 +0,0 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "io"
// New creates a new random UUID or panics. New is equivalent to
// the expression
//
// uuid.Must(uuid.NewRandom())
func New() UUID {
return Must(NewRandom())
}
// NewString creates a new random UUID and returns it as a string or panics.
// NewString is equivalent to the expression
//
// uuid.New().String()
func NewString() string {
return Must(NewRandom()).String()
}
// NewRandom returns a Random (Version 4) UUID.
//
// The strength of the UUIDs is based on the strength of the crypto/rand
// package.
//
// Uses the randomness pool if it was enabled with EnableRandPool.
//
// A note about uniqueness derived from the UUID Wikipedia entry:
//
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
// hit by a meteorite is estimated to be one chance in 17 billion, that
// means the probability is about 0.00000000006 (6 × 1011),
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
// year and having one duplicate.
func NewRandom() (UUID, error) {
if !poolEnabled {
return NewRandomFromReader(rander)
}
return newRandomFromPool()
}
// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader.
func NewRandomFromReader(r io.Reader) (UUID, error) {
var uuid UUID
_, err := io.ReadFull(r, uuid[:])
if err != nil {
return Nil, err
}
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
return uuid, nil
}
func newRandomFromPool() (UUID, error) {
var uuid UUID
poolMu.Lock()
if poolPos == randPoolSize {
_, err := io.ReadFull(rander, pool[:])
if err != nil {
poolMu.Unlock()
return Nil, err
}
poolPos = 0
}
copy(uuid[:], pool[poolPos:(poolPos+16)])
poolPos += 16
poolMu.Unlock()
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
return uuid, nil
}

9
vendor/modules.txt vendored
View file

@ -1,4 +1,4 @@
# github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
# github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c
## explicit
github.com/Azure/go-ntlmssp
# github.com/BurntSushi/toml v1.3.2
@ -39,8 +39,8 @@ github.com/felixge/httpsnoop
# github.com/go-asn1-ber/asn1-ber v1.5.5
## explicit; go 1.13
github.com/go-asn1-ber/asn1-ber
# github.com/go-ldap/ldap/v3 v3.4.6
## explicit; go 1.14
# github.com/go-ldap/ldap/v3 v3.4.1
## explicit; go 1.13
github.com/go-ldap/ldap/v3
# github.com/go-sql-driver/mysql v1.7.1
## explicit; go 1.13
@ -62,9 +62,6 @@ github.com/golang/glog/internal/stackdump
# github.com/google/go-querystring v1.1.0
## explicit; go 1.10
github.com/google/go-querystring/query
# github.com/google/uuid v1.3.1
## explicit
github.com/google/uuid
# github.com/gorilla/css v1.0.1
## explicit; go 1.20
github.com/gorilla/css/scanner