Skip to content
Snippets Groups Projects
Commit e357b3fd authored by Tobias Quathamer's avatar Tobias Quathamer
Browse files

Require explicit intention for empty password.

This is normally used for unauthenticated bind, and
https://tools.ietf.org/html/rfc4513#section-5.1.2 recommends:

> Clients SHOULD disallow an empty password input to a Name/Password
> Authentication user interface

This is (mostly) a cherry-pick of 95ede12 from upstream. I've removed
the bit in ldap_test.go, which is unrelated to the security issue.

This fixes CVE-2017-14623.

https://github.com/go-ldap/ldap/commit/95ede1266b237bf8e9aa5dce0b3250e51bfefe66

Closes: #876404
parent 9f19cec1
No related branches found
No related tags found
No related merge requests found
From: "Dr. Tobias Quathamer" <toddy@debian.org>
Date: Wed, 29 Nov 2017 14:34:16 +0100
Subject: Require explicit intention for empty password.
This is normally used for unauthenticated bind, and
https://tools.ietf.org/html/rfc4513#section-5.1.2 recommends:
> Clients SHOULD disallow an empty password input to a Name/Password
> Authentication user interface
This is (mostly) a cherry-pick of 95ede12 from upstream. I've removed
the bit in ldap_test.go, which is unrelated to the security issue.
This fixes CVE-2017-14623.
https://github.com/go-ldap/ldap/commit/95ede1266b237bf8e9aa5dce0b3250e51bfefe66
---
bind.go | 80 ++++++++++++++++++++++++++++++----------------------------------
error.go | 9 ++++++++
2 files changed, 46 insertions(+), 43 deletions(-)
diff --git a/bind.go b/bind.go
index 26b3cc7..432efa7 100644
--- a/bind.go
+++ b/bind.go
@@ -7,7 +7,7 @@ package ldap
import (
"errors"
- "gopkg.in/asn1-ber.v1"
+ ber "gopkg.in/asn1-ber.v1"
)
// SimpleBindRequest represents a username/password bind operation
@@ -18,6 +18,9 @@ type SimpleBindRequest struct {
Password string
// Controls are optional controls to send with the bind request
Controls []Control
+ // AllowEmptyPassword sets whether the client allows binding with an empty password
+ // (normally used for unauthenticated bind).
+ AllowEmptyPassword bool
}
// SimpleBindResult contains the response from the server
@@ -28,9 +31,10 @@ type SimpleBindResult struct {
// NewSimpleBindRequest returns a bind request
func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest {
return &SimpleBindRequest{
- Username: username,
- Password: password,
- Controls: controls,
+ Username: username,
+ Password: password,
+ Controls: controls,
+ AllowEmptyPassword: false,
}
}
@@ -47,6 +51,10 @@ func (bindRequest *SimpleBindRequest) encode() *ber.Packet {
// SimpleBind performs the simple bind operation defined in the given request
func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) {
+ if simpleBindRequest.Password == "" && !simpleBindRequest.AllowEmptyPassword {
+ return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client"))
+ }
+
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
encodedBindRequest := simpleBindRequest.encode()
@@ -97,47 +105,33 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
return result, nil
}
-// Bind performs a bind with the given username and password
+// Bind performs a bind with the given username and password.
+//
+// It does not allow unauthenticated bind (i.e. empty password). Use the UnauthenticatedBind method
+// for that.
func (l *Conn) Bind(username, password string) error {
- packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
- packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
- bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
- bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
- bindRequest.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, username, "User Name"))
- bindRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, password, "Password"))
- packet.AppendChild(bindRequest)
-
- if l.Debug {
- ber.PrintPacket(packet)
- }
-
- msgCtx, err := l.sendMessage(packet)
- if err != nil {
- return err
- }
- defer l.finishMessage(msgCtx)
-
- packetResponse, ok := <-msgCtx.responses
- if !ok {
- return NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
- }
- packet, err = packetResponse.ReadPacket()
- l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
- if err != nil {
- return err
- }
-
- if l.Debug {
- if err := addLDAPDescriptions(packet); err != nil {
- return err
- }
- ber.PrintPacket(packet)
+ req := &SimpleBindRequest{
+ Username: username,
+ Password: password,
+ AllowEmptyPassword: false,
}
+ _, err := l.SimpleBind(req)
+ return err
+}
- resultCode, resultDescription := getLDAPResultCode(packet)
- if resultCode != 0 {
- return NewError(resultCode, errors.New(resultDescription))
+// UnauthenticatedBind performs an unauthenticated bind.
+//
+// A username may be provided for trace (e.g. logging) purpose only, but it is normally not
+// authenticated or otherwise validated by the LDAP server.
+//
+// See https://tools.ietf.org/html/rfc4513#section-5.1.2 .
+// See https://tools.ietf.org/html/rfc4513#section-6.3.1 .
+func (l *Conn) UnauthenticatedBind(username string) error {
+ req := &SimpleBindRequest{
+ Username: username,
+ Password: "",
+ AllowEmptyPassword: true,
}
-
- return nil
+ _, err := l.SimpleBind(req)
+ return err
}
diff --git a/error.go b/error.go
index ff69787..6e1277f 100644
--- a/error.go
+++ b/error.go
@@ -54,6 +54,7 @@ const (
ErrorDebugging = 203
ErrorUnexpectedMessage = 204
ErrorUnexpectedResponse = 205
+ ErrorEmptyPassword = 206
)
// LDAPResultCodeMap contains string descriptions for LDAP error codes
@@ -97,6 +98,14 @@ var LDAPResultCodeMap = map[uint8]string{
LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited",
LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs",
LDAPResultOther: "Other",
+
+ ErrorNetwork: "Network Error",
+ ErrorFilterCompile: "Filter Compile Error",
+ ErrorFilterDecompile: "Filter Decompile Error",
+ ErrorDebugging: "Debugging Error",
+ ErrorUnexpectedMessage: "Unexpected Message",
+ ErrorUnexpectedResponse: "Unexpected Response",
+ ErrorEmptyPassword: "Empty password not allowed by the client",
}
func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) {
disable-internet-tests.patch
0002-Require-explicit-intention-for-empty-password.patch
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment