diff --git a/Gopkg.lock b/Gopkg.lock
index 0fe028a5ea..fa2a58a1a3 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -1094,12 +1094,12 @@
   version = "v1.31.1"
 
 [[projects]]
-  digest = "1:7e1c00b9959544fa1ccca7cf0407a5b29ac6d5201059c4fac6f599cb99bfd24d"
-  name = "gopkg.in/ldap.v2"
+  digest = "1:8a502dedecf5b6d56e36f0d0e6196392baf616634af2c23108b6e8bb89ec57fc"
+  name = "gopkg.in/ldap.v3"
   packages = ["."]
   pruneopts = "NUT"
-  revision = "bb7a9ca6e4fbc2129e3db588a34bc970ffe811a9"
-  version = "v2.5.1"
+  revision = "214f299a0ecb2a6c6f6d2b0f13977032b207dc58"
+  version = "v3.0.1"
 
 [[projects]]
   digest = "1:de2e7294c9bd0b7d07ada8e98ad02cbbaabacff90eedebe7454ebdbab50d0d19"
@@ -1309,7 +1309,7 @@
     "gopkg.in/editorconfig/editorconfig-core-go.v1",
     "gopkg.in/gomail.v2",
     "gopkg.in/ini.v1",
-    "gopkg.in/ldap.v2",
+    "gopkg.in/ldap.v3",
     "gopkg.in/macaron.v1",
     "gopkg.in/testfixtures.v2",
     "strk.kbt.io/projects/go/libravatar",
diff --git a/Gopkg.toml b/Gopkg.toml
index 94f15079ba..3a981f5296 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -95,8 +95,8 @@ ignored = ["google.golang.org/appengine*"]
   version = "1.31.1"
 
 [[constraint]]
-  name = "gopkg.in/ldap.v2"
-  version = "2.4.1"
+  name = "gopkg.in/ldap.v3"
+  version = "3.0.1"
 
 [[constraint]]
   name = "gopkg.in/macaron.v1"
diff --git a/modules/auth/ldap/ldap.go b/modules/auth/ldap/ldap.go
index c68af25408..f202f94086 100644
--- a/modules/auth/ldap/ldap.go
+++ b/modules/auth/ldap/ldap.go
@@ -11,9 +11,9 @@ import (
 	"fmt"
 	"strings"
 
-	"gopkg.in/ldap.v2"
-
 	"code.gitea.io/gitea/modules/log"
+
+	ldap "gopkg.in/ldap.v3"
 )
 
 // SecurityProtocol protocol type
diff --git a/vendor/gopkg.in/ldap.v2/atomic_value.go b/vendor/gopkg.in/ldap.v2/atomic_value.go
deleted file mode 100644
index bccf7573e0..0000000000
--- a/vendor/gopkg.in/ldap.v2/atomic_value.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// +build go1.4
-
-package ldap
-
-import (
-	"sync/atomic"
-)
-
-// For compilers that support it, we just use the underlying sync/atomic.Value
-// type.
-type atomicValue struct {
-	atomic.Value
-}
diff --git a/vendor/gopkg.in/ldap.v2/atomic_value_go13.go b/vendor/gopkg.in/ldap.v2/atomic_value_go13.go
deleted file mode 100644
index 04920bb260..0000000000
--- a/vendor/gopkg.in/ldap.v2/atomic_value_go13.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// +build !go1.4
-
-package ldap
-
-import (
-	"sync"
-)
-
-// This is a helper type that emulates the use of the "sync/atomic.Value"
-// struct that's available in Go 1.4 and up.
-type atomicValue struct {
-	value interface{}
-	lock  sync.RWMutex
-}
-
-func (av *atomicValue) Store(val interface{}) {
-	av.lock.Lock()
-	av.value = val
-	av.lock.Unlock()
-}
-
-func (av *atomicValue) Load() interface{} {
-	av.lock.RLock()
-	ret := av.value
-	av.lock.RUnlock()
-
-	return ret
-}
diff --git a/vendor/gopkg.in/ldap.v2/error.go b/vendor/gopkg.in/ldap.v2/error.go
deleted file mode 100644
index 4cccb537fd..0000000000
--- a/vendor/gopkg.in/ldap.v2/error.go
+++ /dev/null
@@ -1,155 +0,0 @@
-package ldap
-
-import (
-	"fmt"
-
-	"gopkg.in/asn1-ber.v1"
-)
-
-// LDAP Result Codes
-const (
-	LDAPResultSuccess                      = 0
-	LDAPResultOperationsError              = 1
-	LDAPResultProtocolError                = 2
-	LDAPResultTimeLimitExceeded            = 3
-	LDAPResultSizeLimitExceeded            = 4
-	LDAPResultCompareFalse                 = 5
-	LDAPResultCompareTrue                  = 6
-	LDAPResultAuthMethodNotSupported       = 7
-	LDAPResultStrongAuthRequired           = 8
-	LDAPResultReferral                     = 10
-	LDAPResultAdminLimitExceeded           = 11
-	LDAPResultUnavailableCriticalExtension = 12
-	LDAPResultConfidentialityRequired      = 13
-	LDAPResultSaslBindInProgress           = 14
-	LDAPResultNoSuchAttribute              = 16
-	LDAPResultUndefinedAttributeType       = 17
-	LDAPResultInappropriateMatching        = 18
-	LDAPResultConstraintViolation          = 19
-	LDAPResultAttributeOrValueExists       = 20
-	LDAPResultInvalidAttributeSyntax       = 21
-	LDAPResultNoSuchObject                 = 32
-	LDAPResultAliasProblem                 = 33
-	LDAPResultInvalidDNSyntax              = 34
-	LDAPResultAliasDereferencingProblem    = 36
-	LDAPResultInappropriateAuthentication  = 48
-	LDAPResultInvalidCredentials           = 49
-	LDAPResultInsufficientAccessRights     = 50
-	LDAPResultBusy                         = 51
-	LDAPResultUnavailable                  = 52
-	LDAPResultUnwillingToPerform           = 53
-	LDAPResultLoopDetect                   = 54
-	LDAPResultNamingViolation              = 64
-	LDAPResultObjectClassViolation         = 65
-	LDAPResultNotAllowedOnNonLeaf          = 66
-	LDAPResultNotAllowedOnRDN              = 67
-	LDAPResultEntryAlreadyExists           = 68
-	LDAPResultObjectClassModsProhibited    = 69
-	LDAPResultAffectsMultipleDSAs          = 71
-	LDAPResultOther                        = 80
-
-	ErrorNetwork            = 200
-	ErrorFilterCompile      = 201
-	ErrorFilterDecompile    = 202
-	ErrorDebugging          = 203
-	ErrorUnexpectedMessage  = 204
-	ErrorUnexpectedResponse = 205
-)
-
-// LDAPResultCodeMap contains string descriptions for LDAP error codes
-var LDAPResultCodeMap = map[uint8]string{
-	LDAPResultSuccess:                      "Success",
-	LDAPResultOperationsError:              "Operations Error",
-	LDAPResultProtocolError:                "Protocol Error",
-	LDAPResultTimeLimitExceeded:            "Time Limit Exceeded",
-	LDAPResultSizeLimitExceeded:            "Size Limit Exceeded",
-	LDAPResultCompareFalse:                 "Compare False",
-	LDAPResultCompareTrue:                  "Compare True",
-	LDAPResultAuthMethodNotSupported:       "Auth Method Not Supported",
-	LDAPResultStrongAuthRequired:           "Strong Auth Required",
-	LDAPResultReferral:                     "Referral",
-	LDAPResultAdminLimitExceeded:           "Admin Limit Exceeded",
-	LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension",
-	LDAPResultConfidentialityRequired:      "Confidentiality Required",
-	LDAPResultSaslBindInProgress:           "Sasl Bind In Progress",
-	LDAPResultNoSuchAttribute:              "No Such Attribute",
-	LDAPResultUndefinedAttributeType:       "Undefined Attribute Type",
-	LDAPResultInappropriateMatching:        "Inappropriate Matching",
-	LDAPResultConstraintViolation:          "Constraint Violation",
-	LDAPResultAttributeOrValueExists:       "Attribute Or Value Exists",
-	LDAPResultInvalidAttributeSyntax:       "Invalid Attribute Syntax",
-	LDAPResultNoSuchObject:                 "No Such Object",
-	LDAPResultAliasProblem:                 "Alias Problem",
-	LDAPResultInvalidDNSyntax:              "Invalid DN Syntax",
-	LDAPResultAliasDereferencingProblem:    "Alias Dereferencing Problem",
-	LDAPResultInappropriateAuthentication:  "Inappropriate Authentication",
-	LDAPResultInvalidCredentials:           "Invalid Credentials",
-	LDAPResultInsufficientAccessRights:     "Insufficient Access Rights",
-	LDAPResultBusy:                         "Busy",
-	LDAPResultUnavailable:                  "Unavailable",
-	LDAPResultUnwillingToPerform:           "Unwilling To Perform",
-	LDAPResultLoopDetect:                   "Loop Detect",
-	LDAPResultNamingViolation:              "Naming Violation",
-	LDAPResultObjectClassViolation:         "Object Class Violation",
-	LDAPResultNotAllowedOnNonLeaf:          "Not Allowed On Non Leaf",
-	LDAPResultNotAllowedOnRDN:              "Not Allowed On RDN",
-	LDAPResultEntryAlreadyExists:           "Entry Already Exists",
-	LDAPResultObjectClassModsProhibited:    "Object Class Mods Prohibited",
-	LDAPResultAffectsMultipleDSAs:          "Affects Multiple DSAs",
-	LDAPResultOther:                        "Other",
-
-	ErrorNetwork:            "Network Error",
-	ErrorFilterCompile:      "Filter Compile Error",
-	ErrorFilterDecompile:    "Filter Decompile Error",
-	ErrorDebugging:          "Debugging Error",
-	ErrorUnexpectedMessage:  "Unexpected Message",
-	ErrorUnexpectedResponse: "Unexpected Response",
-}
-
-func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) {
-	if packet == nil {
-		return ErrorUnexpectedResponse, "Empty packet"
-	} else if len(packet.Children) >= 2 {
-		response := packet.Children[1]
-		if response == nil {
-			return ErrorUnexpectedResponse, "Empty response in packet"
-		}
-		if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
-			// Children[1].Children[2] is the diagnosticMessage which is guaranteed to exist as seen here: https://tools.ietf.org/html/rfc4511#section-4.1.9
-			return uint8(response.Children[0].Value.(int64)), response.Children[2].Value.(string)
-		}
-	}
-
-	return ErrorNetwork, "Invalid packet format"
-}
-
-// Error holds LDAP error information
-type Error struct {
-	// Err is the underlying error
-	Err error
-	// ResultCode is the LDAP error code
-	ResultCode uint8
-}
-
-func (e *Error) Error() string {
-	return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
-}
-
-// NewError creates an LDAP error with the given code and underlying error
-func NewError(resultCode uint8, err error) error {
-	return &Error{ResultCode: resultCode, Err: err}
-}
-
-// IsErrorWithCode returns true if the given error is an LDAP error with the given result code
-func IsErrorWithCode(err error, desiredResultCode uint8) bool {
-	if err == nil {
-		return false
-	}
-
-	serverError, ok := err.(*Error)
-	if !ok {
-		return false
-	}
-
-	return serverError.ResultCode == desiredResultCode
-}
diff --git a/vendor/gopkg.in/ldap.v2/LICENSE b/vendor/gopkg.in/ldap.v3/LICENSE
similarity index 100%
rename from vendor/gopkg.in/ldap.v2/LICENSE
rename to vendor/gopkg.in/ldap.v3/LICENSE
diff --git a/vendor/gopkg.in/ldap.v2/add.go b/vendor/gopkg.in/ldap.v3/add.go
similarity index 90%
rename from vendor/gopkg.in/ldap.v2/add.go
rename to vendor/gopkg.in/ldap.v3/add.go
index 0e5f6cdba1..19bce1b75b 100644
--- a/vendor/gopkg.in/ldap.v2/add.go
+++ b/vendor/gopkg.in/ldap.v3/add.go
@@ -41,6 +41,8 @@ type AddRequest struct {
 	DN string
 	// Attributes list the attributes of the new entry
 	Attributes []Attribute
+	// Controls hold optional controls to send with the request
+	Controls []Control
 }
 
 func (a AddRequest) encode() *ber.Packet {
@@ -60,9 +62,10 @@ func (a *AddRequest) Attribute(attrType string, attrVals []string) {
 }
 
 // NewAddRequest returns an AddRequest for the given DN, with no attributes
-func NewAddRequest(dn string) *AddRequest {
+func NewAddRequest(dn string, controls []Control) *AddRequest {
 	return &AddRequest{
-		DN: dn,
+		DN:       dn,
+		Controls: controls,
 	}
 
 }
@@ -72,6 +75,9 @@ func (l *Conn) Add(addRequest *AddRequest) error {
 	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
 	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
 	packet.AppendChild(addRequest.encode())
+	if len(addRequest.Controls) > 0 {
+		packet.AppendChild(encodeControls(addRequest.Controls))
+	}
 
 	l.Debug.PrintPacket(packet)
 
@@ -100,9 +106,9 @@ func (l *Conn) Add(addRequest *AddRequest) error {
 	}
 
 	if packet.Children[1].Tag == ApplicationAddResponse {
-		resultCode, resultDescription := getLDAPResultCode(packet)
-		if resultCode != 0 {
-			return NewError(resultCode, errors.New(resultDescription))
+		err := GetLDAPError(packet)
+		if err != nil {
+			return err
 		}
 	} else {
 		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
diff --git a/vendor/gopkg.in/ldap.v2/bind.go b/vendor/gopkg.in/ldap.v3/bind.go
similarity index 54%
rename from vendor/gopkg.in/ldap.v2/bind.go
rename to vendor/gopkg.in/ldap.v3/bind.go
index 26b3cc7270..59c3f5ef59 100644
--- a/vendor/gopkg.in/ldap.v2/bind.go
+++ b/vendor/gopkg.in/ldap.v3/bind.go
@@ -1,11 +1,8 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
 package ldap
 
 import (
 	"errors"
+	"fmt"
 
 	"gopkg.in/asn1-ber.v1"
 )
@@ -18,6 +15,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 +28,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,
 	}
 }
 
@@ -40,17 +41,22 @@ func (bindRequest *SimpleBindRequest) encode() *ber.Packet {
 	request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, bindRequest.Username, "User Name"))
 	request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, bindRequest.Password, "Password"))
 
-	request.AppendChild(encodeControls(bindRequest.Controls))
-
 	return request
 }
 
 // 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()
 	packet.AppendChild(encodedBindRequest)
+	if len(simpleBindRequest.Controls) > 0 {
+		packet.AppendChild(encodeControls(simpleBindRequest.Controls))
+	}
 
 	if l.Debug {
 		ber.PrintPacket(packet)
@@ -73,7 +79,7 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
 	}
 
 	if l.Debug {
-		if err := addLDAPDescriptions(packet); err != nil {
+		if err = addLDAPDescriptions(packet); err != nil {
 			return nil, err
 		}
 		ber.PrintPacket(packet)
@@ -85,59 +91,45 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
 
 	if len(packet.Children) == 3 {
 		for _, child := range packet.Children[2].Children {
-			result.Controls = append(result.Controls, DecodeControl(child))
+			decodedChild, decodeErr := DecodeControl(child)
+			if decodeErr != nil {
+				return nil, fmt.Errorf("failed to decode child control: %s", decodeErr)
+			}
+			result.Controls = append(result.Controls, decodedChild)
 		}
 	}
 
-	resultCode, resultDescription := getLDAPResultCode(packet)
-	if resultCode != 0 {
-		return result, NewError(resultCode, errors.New(resultDescription))
-	}
-
-	return result, nil
+	err = GetLDAPError(packet)
+	return result, err
 }
 
-// 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)
+	req := &SimpleBindRequest{
+		Username:           username,
+		Password:           password,
+		AllowEmptyPassword: false,
 	}
-
-	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)
-	}
-
-	resultCode, resultDescription := getLDAPResultCode(packet)
-	if resultCode != 0 {
-		return NewError(resultCode, errors.New(resultDescription))
-	}
-
-	return nil
+	_, err := l.SimpleBind(req)
+	return err
+}
+
+// UnauthenticatedBind performs an unauthenticated bind.
+//
+// A username may be provided for trace (e.g. logging) purpose only, but it is normally not
+// authenticated or otherwise validated by the LDAP server.
+//
+// See https://tools.ietf.org/html/rfc4513#section-5.1.2 .
+// See https://tools.ietf.org/html/rfc4513#section-6.3.1 .
+func (l *Conn) UnauthenticatedBind(username string) error {
+	req := &SimpleBindRequest{
+		Username:           username,
+		Password:           "",
+		AllowEmptyPassword: true,
+	}
+	_, err := l.SimpleBind(req)
+	return err
 }
diff --git a/vendor/gopkg.in/ldap.v2/client.go b/vendor/gopkg.in/ldap.v3/client.go
similarity index 93%
rename from vendor/gopkg.in/ldap.v2/client.go
rename to vendor/gopkg.in/ldap.v3/client.go
index 055b27b5fc..c7f41f6f90 100644
--- a/vendor/gopkg.in/ldap.v2/client.go
+++ b/vendor/gopkg.in/ldap.v3/client.go
@@ -18,6 +18,7 @@ type Client interface {
 	Add(addRequest *AddRequest) error
 	Del(delRequest *DelRequest) error
 	Modify(modifyRequest *ModifyRequest) error
+	ModifyDN(modifyDNRequest *ModifyDNRequest) error
 
 	Compare(dn, attribute, value string) (bool, error)
 	PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error)
diff --git a/vendor/gopkg.in/ldap.v2/compare.go b/vendor/gopkg.in/ldap.v3/compare.go
similarity index 80%
rename from vendor/gopkg.in/ldap.v2/compare.go
rename to vendor/gopkg.in/ldap.v3/compare.go
index cc6d2af5e5..5b5013cbed 100644
--- a/vendor/gopkg.in/ldap.v2/compare.go
+++ b/vendor/gopkg.in/ldap.v3/compare.go
@@ -1,7 +1,3 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-//
 // File contains Compare functionality
 //
 // https://tools.ietf.org/html/rfc4511
@@ -41,7 +37,7 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
 
 	ava := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "AttributeValueAssertion")
 	ava.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "AttributeDesc"))
-	ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagOctetString, value, "AssertionValue"))
+	ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "AssertionValue"))
 	request.AppendChild(ava)
 	packet.AppendChild(request)
 
@@ -72,14 +68,16 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
 	}
 
 	if packet.Children[1].Tag == ApplicationCompareResponse {
-		resultCode, resultDescription := getLDAPResultCode(packet)
-		if resultCode == LDAPResultCompareTrue {
+		err := GetLDAPError(packet)
+
+		switch {
+		case IsErrorWithCode(err, LDAPResultCompareTrue):
 			return true, nil
-		} else if resultCode == LDAPResultCompareFalse {
+		case IsErrorWithCode(err, LDAPResultCompareFalse):
 			return false, nil
-		} else {
-			return false, NewError(resultCode, errors.New(resultDescription))
+		default:
+			return false, err
 		}
 	}
-	return false, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag)
+	return false, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag)
 }
diff --git a/vendor/gopkg.in/ldap.v2/conn.go b/vendor/gopkg.in/ldap.v3/conn.go
similarity index 86%
rename from vendor/gopkg.in/ldap.v2/conn.go
rename to vendor/gopkg.in/ldap.v3/conn.go
index eb28eb4726..c20471fc20 100644
--- a/vendor/gopkg.in/ldap.v2/conn.go
+++ b/vendor/gopkg.in/ldap.v3/conn.go
@@ -1,7 +1,3 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
 package ldap
 
 import (
@@ -10,6 +6,7 @@ import (
 	"fmt"
 	"log"
 	"net"
+	"net/url"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -30,6 +27,13 @@ const (
 	MessageTimeout = 4
 )
 
+const (
+	// DefaultLdapPort default ldap port for pure TCP connection
+	DefaultLdapPort = "389"
+	// DefaultLdapsPort default ldap port for SSL connection
+	DefaultLdapsPort = "636"
+)
+
 // PacketResponse contains the packet or error encountered reading a response
 type PacketResponse struct {
 	// Packet is the packet read from the server
@@ -81,10 +85,13 @@ const (
 
 // Conn represents an LDAP Connection
 type Conn struct {
+	// requestTimeout is loaded atomically
+	// so we need to ensure 64-bit alignment on 32-bit platforms.
+	requestTimeout      int64
 	conn                net.Conn
 	isTLS               bool
 	closing             uint32
-	closeErr            atomicValue
+	closeErr            atomic.Value
 	isStartingTLS       bool
 	Debug               debugging
 	chanConfirm         chan struct{}
@@ -94,7 +101,6 @@ type Conn struct {
 	wgClose             sync.WaitGroup
 	outstandingRequests uint
 	messageMutex        sync.Mutex
-	requestTimeout      int64
 }
 
 var _ Client = &Conn{}
@@ -121,22 +127,51 @@ func Dial(network, addr string) (*Conn, error) {
 // DialTLS connects to the given address on the given network using tls.Dial
 // and then returns a new Conn for the connection.
 func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
-	dc, err := net.DialTimeout(network, addr, DefaultTimeout)
+	c, err := tls.DialWithDialer(&net.Dialer{Timeout: DefaultTimeout}, network, addr, config)
 	if err != nil {
 		return nil, NewError(ErrorNetwork, err)
 	}
-	c := tls.Client(dc, config)
-	err = c.Handshake()
-	if err != nil {
-		// Handshake error, close the established connection before we return an error
-		dc.Close()
-		return nil, NewError(ErrorNetwork, err)
-	}
 	conn := NewConn(c, true)
 	conn.Start()
 	return conn, nil
 }
 
+// DialURL connects to the given ldap URL vie TCP using tls.Dial or net.Dial if ldaps://
+// or ldap:// specified as protocol. On success a new Conn for the connection
+// is returned.
+func DialURL(addr string) (*Conn, error) {
+
+	lurl, err := url.Parse(addr)
+	if err != nil {
+		return nil, NewError(ErrorNetwork, err)
+	}
+
+	host, port, err := net.SplitHostPort(lurl.Host)
+	if err != nil {
+		// we asume that error is due to missing port
+		host = lurl.Host
+		port = ""
+	}
+
+	switch lurl.Scheme {
+	case "ldap":
+		if port == "" {
+			port = DefaultLdapPort
+		}
+		return Dial("tcp", net.JoinHostPort(host, port))
+	case "ldaps":
+		if port == "" {
+			port = DefaultLdapsPort
+		}
+		tlsConf := &tls.Config{
+			ServerName: host,
+		}
+		return DialTLS("tcp", net.JoinHostPort(host, port), tlsConf)
+	}
+
+	return nil, NewError(ErrorNetwork, fmt.Errorf("Unknown scheme '%s'", lurl.Scheme))
+}
+
 // NewConn returns a new Conn using conn for network I/O.
 func NewConn(conn net.Conn, isTLS bool) *Conn {
 	return &Conn{
@@ -157,8 +192,8 @@ func (l *Conn) Start() {
 	l.wgClose.Add(1)
 }
 
-// isClosing returns whether or not we're currently closing.
-func (l *Conn) isClosing() bool {
+// IsClosing returns whether or not we're currently closing.
+func (l *Conn) IsClosing() bool {
 	return atomic.LoadUint32(&l.closing) == 1
 }
 
@@ -242,30 +277,41 @@ func (l *Conn) StartTLS(config *tls.Config) error {
 		ber.PrintPacket(packet)
 	}
 
-	if resultCode, message := getLDAPResultCode(packet); resultCode == LDAPResultSuccess {
+	if err := GetLDAPError(packet); err == nil {
 		conn := tls.Client(l.conn, config)
 
-		if err := conn.Handshake(); err != nil {
+		if connErr := conn.Handshake(); connErr != nil {
 			l.Close()
-			return NewError(ErrorNetwork, fmt.Errorf("TLS handshake failed (%v)", err))
+			return NewError(ErrorNetwork, fmt.Errorf("TLS handshake failed (%v)", connErr))
 		}
 
 		l.isTLS = true
 		l.conn = conn
 	} else {
-		return NewError(resultCode, fmt.Errorf("ldap: cannot StartTLS (%s)", message))
+		return err
 	}
 	go l.reader()
 
 	return nil
 }
 
+// TLSConnectionState returns the client's TLS connection state.
+// The return values are their zero values if StartTLS did
+// not succeed.
+func (l *Conn) TLSConnectionState() (state tls.ConnectionState, ok bool) {
+	tc, ok := l.conn.(*tls.Conn)
+	if !ok {
+		return
+	}
+	return tc.ConnectionState(), true
+}
+
 func (l *Conn) sendMessage(packet *ber.Packet) (*messageContext, error) {
 	return l.sendMessageWithFlags(packet, 0)
 }
 
 func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (*messageContext, error) {
-	if l.isClosing() {
+	if l.IsClosing() {
 		return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed"))
 	}
 	l.messageMutex.Lock()
@@ -304,7 +350,7 @@ func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags)
 func (l *Conn) finishMessage(msgCtx *messageContext) {
 	close(msgCtx.done)
 
-	if l.isClosing() {
+	if l.IsClosing() {
 		return
 	}
 
@@ -325,7 +371,7 @@ func (l *Conn) finishMessage(msgCtx *messageContext) {
 func (l *Conn) sendProcessMessage(message *messagePacket) bool {
 	l.messageMutex.Lock()
 	defer l.messageMutex.Unlock()
-	if l.isClosing() {
+	if l.IsClosing() {
 		return false
 	}
 	l.chanMessage <- message
@@ -340,7 +386,7 @@ func (l *Conn) processMessages() {
 		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 {
+			if l.IsClosing() && l.closeErr.Load() != nil {
 				msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)})
 			}
 			l.Debug.Printf("Closing channel for MessageID %d", messageID)
@@ -400,7 +446,7 @@ func (l *Conn) processMessages() {
 				if msgCtx, ok := l.messageContexts[message.MessageID]; ok {
 					msgCtx.sendResponse(&PacketResponse{message.Packet, nil})
 				} else {
-					log.Printf("Received unexpected message %d, %v", message.MessageID, l.isClosing())
+					log.Printf("Received unexpected message %d, %v", message.MessageID, l.IsClosing())
 					ber.PrintPacket(message.Packet)
 				}
 			case MessageTimeout:
@@ -442,7 +488,7 @@ func (l *Conn) reader() {
 		packet, err := ber.ReadPacket(l.conn)
 		if err != nil {
 			// A read error is expected here if we are closing the connection...
-			if !l.isClosing() {
+			if !l.IsClosing() {
 				l.closeErr.Store(fmt.Errorf("unable to read LDAP response packet: %s", err))
 				l.Debug.Printf("reader error: %s", err.Error())
 			}
diff --git a/vendor/gopkg.in/ldap.v2/control.go b/vendor/gopkg.in/ldap.v3/control.go
similarity index 75%
rename from vendor/gopkg.in/ldap.v2/control.go
rename to vendor/gopkg.in/ldap.v3/control.go
index 342f325ca6..4439a865d9 100644
--- a/vendor/gopkg.in/ldap.v2/control.go
+++ b/vendor/gopkg.in/ldap.v3/control.go
@@ -1,7 +1,3 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
 package ldap
 
 import (
@@ -22,13 +18,20 @@ const (
 	ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5"
 	// ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296
 	ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2"
+
+	// ControlTypeMicrosoftNotification - https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
+	ControlTypeMicrosoftNotification = "1.2.840.113556.1.4.528"
+	// ControlTypeMicrosoftShowDeleted - https://msdn.microsoft.com/en-us/library/aa366989(v=vs.85).aspx
+	ControlTypeMicrosoftShowDeleted = "1.2.840.113556.1.4.417"
 )
 
 // ControlTypeMap maps controls to text descriptions
 var ControlTypeMap = map[string]string{
-	ControlTypePaging:               "Paging",
-	ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
-	ControlTypeManageDsaIT:          "Manage DSA IT",
+	ControlTypePaging:                "Paging",
+	ControlTypeBeheraPasswordPolicy:  "Password Policy - Behera Draft",
+	ControlTypeManageDsaIT:           "Manage DSA IT",
+	ControlTypeMicrosoftNotification: "Change Notification - Microsoft",
+	ControlTypeMicrosoftShowDeleted:  "Show Deleted Objects - Microsoft",
 }
 
 // Control defines an interface controls provide to encode and describe themselves
@@ -242,6 +245,64 @@ func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT {
 	return &ControlManageDsaIT{Criticality: Criticality}
 }
 
+// ControlMicrosoftNotification implements the control described in https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
+type ControlMicrosoftNotification struct{}
+
+// GetControlType returns the OID
+func (c *ControlMicrosoftNotification) GetControlType() string {
+	return ControlTypeMicrosoftNotification
+}
+
+// Encode returns the ber packet representation
+func (c *ControlMicrosoftNotification) Encode() *ber.Packet {
+	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
+	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeMicrosoftNotification, "Control Type ("+ControlTypeMap[ControlTypeMicrosoftNotification]+")"))
+
+	return packet
+}
+
+// String returns a human-readable description
+func (c *ControlMicrosoftNotification) String() string {
+	return fmt.Sprintf(
+		"Control Type: %s (%q)",
+		ControlTypeMap[ControlTypeMicrosoftNotification],
+		ControlTypeMicrosoftNotification)
+}
+
+// NewControlMicrosoftNotification returns a ControlMicrosoftNotification control
+func NewControlMicrosoftNotification() *ControlMicrosoftNotification {
+	return &ControlMicrosoftNotification{}
+}
+
+// ControlMicrosoftShowDeleted implements the control described in https://msdn.microsoft.com/en-us/library/aa366989(v=vs.85).aspx
+type ControlMicrosoftShowDeleted struct{}
+
+// GetControlType returns the OID
+func (c *ControlMicrosoftShowDeleted) GetControlType() string {
+	return ControlTypeMicrosoftShowDeleted
+}
+
+// Encode returns the ber packet representation
+func (c *ControlMicrosoftShowDeleted) Encode() *ber.Packet {
+	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
+	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeMicrosoftShowDeleted, "Control Type ("+ControlTypeMap[ControlTypeMicrosoftShowDeleted]+")"))
+
+	return packet
+}
+
+// String returns a human-readable description
+func (c *ControlMicrosoftShowDeleted) String() string {
+	return fmt.Sprintf(
+		"Control Type: %s (%q)",
+		ControlTypeMap[ControlTypeMicrosoftShowDeleted],
+		ControlTypeMicrosoftShowDeleted)
+}
+
+// NewControlMicrosoftShowDeleted returns a ControlMicrosoftShowDeleted control
+func NewControlMicrosoftShowDeleted() *ControlMicrosoftShowDeleted {
+	return &ControlMicrosoftShowDeleted{}
+}
+
 // FindControl returns the first control of the given type in the list, or nil
 func FindControl(controls []Control, controlType string) Control {
 	for _, c := range controls {
@@ -253,7 +314,7 @@ func FindControl(controls []Control, controlType string) Control {
 }
 
 // DecodeControl returns a control read from the given packet, or nil if no recognized control can be made
-func DecodeControl(packet *ber.Packet) Control {
+func DecodeControl(packet *ber.Packet) (Control, error) {
 	var (
 		ControlType = ""
 		Criticality = false
@@ -263,7 +324,7 @@ func DecodeControl(packet *ber.Packet) Control {
 	switch len(packet.Children) {
 	case 0:
 		// at least one child is required for control type
-		return nil
+		return nil, fmt.Errorf("at least one child is required for control type")
 
 	case 1:
 		// just type, no criticality or value
@@ -296,17 +357,20 @@ func DecodeControl(packet *ber.Packet) Control {
 
 	default:
 		// more than 3 children is invalid
-		return nil
+		return nil, fmt.Errorf("more than 3 children is invalid for controls")
 	}
 
 	switch ControlType {
 	case ControlTypeManageDsaIT:
-		return NewControlManageDsaIT(Criticality)
+		return NewControlManageDsaIT(Criticality), nil
 	case ControlTypePaging:
 		value.Description += " (Paging)"
 		c := new(ControlPaging)
 		if value.Value != nil {
-			valueChildren := ber.DecodePacket(value.Data.Bytes())
+			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)
@@ -318,12 +382,15 @@ func DecodeControl(packet *ber.Packet) Control {
 		c.PagingSize = uint32(value.Children[0].Value.(int64))
 		c.Cookie = value.Children[1].Data.Bytes()
 		value.Children[1].Value = c.Cookie
-		return c
+		return c, nil
 	case ControlTypeBeheraPasswordPolicy:
 		value.Description += " (Password Policy - Behera)"
 		c := NewControlBeheraPasswordPolicy()
 		if value.Value != nil {
-			valueChildren := ber.DecodePacket(value.Data.Bytes())
+			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)
@@ -335,7 +402,10 @@ func DecodeControl(packet *ber.Packet) Control {
 			if child.Tag == 0 {
 				//Warning
 				warningPacket := child.Children[0]
-				packet := ber.DecodePacket(warningPacket.Data.Bytes())
+				packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes())
+				if err != nil {
+					return nil, fmt.Errorf("failed to decode data bytes: %s", err)
+				}
 				val, ok := packet.Value.(int64)
 				if ok {
 					if warningPacket.Tag == 0 {
@@ -350,7 +420,10 @@ func DecodeControl(packet *ber.Packet) Control {
 				}
 			} else if child.Tag == 1 {
 				// Error
-				packet := ber.DecodePacket(child.Data.Bytes())
+				packet, err := ber.DecodePacketErr(child.Data.Bytes())
+				if err != nil {
+					return nil, fmt.Errorf("failed to decode data bytes: %s", err)
+				}
 				val, ok := packet.Value.(int8)
 				if !ok {
 					// what to do?
@@ -361,22 +434,26 @@ func DecodeControl(packet *ber.Packet) Control {
 				c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error]
 			}
 		}
-		return c
+		return c, nil
 	case ControlTypeVChuPasswordMustChange:
 		c := &ControlVChuPasswordMustChange{MustChange: true}
-		return c
+		return c, nil
 	case ControlTypeVChuPasswordWarning:
 		c := &ControlVChuPasswordWarning{Expire: -1}
 		expireStr := ber.DecodeString(value.Data.Bytes())
 
 		expire, err := strconv.ParseInt(expireStr, 10, 64)
 		if err != nil {
-			return nil
+			return nil, fmt.Errorf("failed to parse value as int: %s", err)
 		}
 		c.Expire = expire
 		value.Value = c.Expire
 
-		return c
+		return c, nil
+	case ControlTypeMicrosoftNotification:
+		return NewControlMicrosoftNotification(), nil
+	case ControlTypeMicrosoftShowDeleted:
+		return NewControlMicrosoftShowDeleted(), nil
 	default:
 		c := new(ControlString)
 		c.ControlType = ControlType
@@ -384,7 +461,7 @@ func DecodeControl(packet *ber.Packet) Control {
 		if value != nil {
 			c.ControlValue = value.Value.(string)
 		}
-		return c
+		return c, nil
 	}
 }
 
diff --git a/vendor/gopkg.in/ldap.v2/debug.go b/vendor/gopkg.in/ldap.v3/debug.go
similarity index 100%
rename from vendor/gopkg.in/ldap.v2/debug.go
rename to vendor/gopkg.in/ldap.v3/debug.go
diff --git a/vendor/gopkg.in/ldap.v2/del.go b/vendor/gopkg.in/ldap.v3/del.go
similarity index 91%
rename from vendor/gopkg.in/ldap.v2/del.go
rename to vendor/gopkg.in/ldap.v3/del.go
index 4fd63dc3f2..6f78beb18e 100644
--- a/vendor/gopkg.in/ldap.v2/del.go
+++ b/vendor/gopkg.in/ldap.v3/del.go
@@ -40,7 +40,7 @@ func (l *Conn) Del(delRequest *DelRequest) error {
 	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
 	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
 	packet.AppendChild(delRequest.encode())
-	if delRequest.Controls != nil {
+	if len(delRequest.Controls) > 0 {
 		packet.AppendChild(encodeControls(delRequest.Controls))
 	}
 
@@ -71,9 +71,9 @@ func (l *Conn) Del(delRequest *DelRequest) error {
 	}
 
 	if packet.Children[1].Tag == ApplicationDelResponse {
-		resultCode, resultDescription := getLDAPResultCode(packet)
-		if resultCode != 0 {
-			return NewError(resultCode, errors.New(resultDescription))
+		err := GetLDAPError(packet)
+		if err != nil {
+			return err
 		}
 	} else {
 		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
diff --git a/vendor/gopkg.in/ldap.v2/dn.go b/vendor/gopkg.in/ldap.v3/dn.go
similarity index 91%
rename from vendor/gopkg.in/ldap.v2/dn.go
rename to vendor/gopkg.in/ldap.v3/dn.go
index 34e9023af9..f89e73a9a6 100644
--- a/vendor/gopkg.in/ldap.v2/dn.go
+++ b/vendor/gopkg.in/ldap.v3/dn.go
@@ -1,7 +1,3 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-//
 // File contains DN parsing functionality
 //
 // https://tools.ietf.org/html/rfc4514
@@ -94,7 +90,8 @@ func ParseDN(str string) (*DN, error) {
 
 	for i := 0; i < len(str); i++ {
 		char := str[i]
-		if escaping {
+		switch {
+		case escaping:
 			unescapedTrailingSpaces = 0
 			escaping = false
 			switch char {
@@ -104,22 +101,22 @@ func ParseDN(str string) (*DN, error) {
 			}
 			// Not a special character, assume hex encoded octet
 			if len(str) == i+1 {
-				return nil, errors.New("Got corrupted escaped character")
+				return nil, errors.New("got corrupted escaped character")
 			}
 
 			dst := []byte{0}
 			n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2]))
 			if err != nil {
-				return nil, fmt.Errorf("Failed to decode escaped character: %s", err)
+				return nil, fmt.Errorf("failed to decode escaped character: %s", err)
 			} else if n != 1 {
-				return nil, fmt.Errorf("Expected 1 byte when un-escaping, got %d", n)
+				return nil, fmt.Errorf("expected 1 byte when un-escaping, got %d", n)
 			}
 			buffer.WriteByte(dst[0])
 			i++
-		} else if char == '\\' {
+		case char == '\\':
 			unescapedTrailingSpaces = 0
 			escaping = true
-		} else if char == '=' {
+		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
@@ -135,13 +132,16 @@ func ParseDN(str string) (*DN, error) {
 				}
 				rawBER, err := enchex.DecodeString(data)
 				if err != nil {
-					return nil, fmt.Errorf("Failed to decode BER encoding: %s", err)
+					return nil, fmt.Errorf("failed to decode BER encoding: %s", err)
+				}
+				packet, err := ber.DecodePacketErr(rawBER)
+				if err != nil {
+					return nil, fmt.Errorf("failed to decode BER packet: %s", err)
 				}
-				packet := ber.DecodePacket(rawBER)
 				buffer.WriteString(packet.Data.String())
 				i += len(data) - 1
 			}
-		} else if 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")
@@ -154,10 +154,10 @@ func ParseDN(str string) (*DN, error) {
 				rdn = new(RelativeDN)
 				rdn.Attributes = make([]*AttributeTypeAndValue, 0)
 			}
-		} else if char == ' ' && buffer.Len() == 0 {
+		case char == ' ' && buffer.Len() == 0:
 			// ignore unescaped leading spaces
 			continue
-		} else {
+		default:
 			if char == ' ' {
 				// Track unescaped spaces in case they are trailing and we need to remove them
 				unescapedTrailingSpaces++
diff --git a/vendor/gopkg.in/ldap.v2/doc.go b/vendor/gopkg.in/ldap.v3/doc.go
similarity index 100%
rename from vendor/gopkg.in/ldap.v2/doc.go
rename to vendor/gopkg.in/ldap.v3/doc.go
diff --git a/vendor/gopkg.in/ldap.v3/error.go b/vendor/gopkg.in/ldap.v3/error.go
new file mode 100644
index 0000000000..50ed8ab3fe
--- /dev/null
+++ b/vendor/gopkg.in/ldap.v3/error.go
@@ -0,0 +1,234 @@
+package ldap
+
+import (
+	"fmt"
+
+	"gopkg.in/asn1-ber.v1"
+)
+
+// LDAP Result Codes
+const (
+	LDAPResultSuccess                            = 0
+	LDAPResultOperationsError                    = 1
+	LDAPResultProtocolError                      = 2
+	LDAPResultTimeLimitExceeded                  = 3
+	LDAPResultSizeLimitExceeded                  = 4
+	LDAPResultCompareFalse                       = 5
+	LDAPResultCompareTrue                        = 6
+	LDAPResultAuthMethodNotSupported             = 7
+	LDAPResultStrongAuthRequired                 = 8
+	LDAPResultReferral                           = 10
+	LDAPResultAdminLimitExceeded                 = 11
+	LDAPResultUnavailableCriticalExtension       = 12
+	LDAPResultConfidentialityRequired            = 13
+	LDAPResultSaslBindInProgress                 = 14
+	LDAPResultNoSuchAttribute                    = 16
+	LDAPResultUndefinedAttributeType             = 17
+	LDAPResultInappropriateMatching              = 18
+	LDAPResultConstraintViolation                = 19
+	LDAPResultAttributeOrValueExists             = 20
+	LDAPResultInvalidAttributeSyntax             = 21
+	LDAPResultNoSuchObject                       = 32
+	LDAPResultAliasProblem                       = 33
+	LDAPResultInvalidDNSyntax                    = 34
+	LDAPResultIsLeaf                             = 35
+	LDAPResultAliasDereferencingProblem          = 36
+	LDAPResultInappropriateAuthentication        = 48
+	LDAPResultInvalidCredentials                 = 49
+	LDAPResultInsufficientAccessRights           = 50
+	LDAPResultBusy                               = 51
+	LDAPResultUnavailable                        = 52
+	LDAPResultUnwillingToPerform                 = 53
+	LDAPResultLoopDetect                         = 54
+	LDAPResultSortControlMissing                 = 60
+	LDAPResultOffsetRangeError                   = 61
+	LDAPResultNamingViolation                    = 64
+	LDAPResultObjectClassViolation               = 65
+	LDAPResultNotAllowedOnNonLeaf                = 66
+	LDAPResultNotAllowedOnRDN                    = 67
+	LDAPResultEntryAlreadyExists                 = 68
+	LDAPResultObjectClassModsProhibited          = 69
+	LDAPResultResultsTooLarge                    = 70
+	LDAPResultAffectsMultipleDSAs                = 71
+	LDAPResultVirtualListViewErrorOrControlError = 76
+	LDAPResultOther                              = 80
+	LDAPResultServerDown                         = 81
+	LDAPResultLocalError                         = 82
+	LDAPResultEncodingError                      = 83
+	LDAPResultDecodingError                      = 84
+	LDAPResultTimeout                            = 85
+	LDAPResultAuthUnknown                        = 86
+	LDAPResultFilterError                        = 87
+	LDAPResultUserCanceled                       = 88
+	LDAPResultParamError                         = 89
+	LDAPResultNoMemory                           = 90
+	LDAPResultConnectError                       = 91
+	LDAPResultNotSupported                       = 92
+	LDAPResultControlNotFound                    = 93
+	LDAPResultNoResultsReturned                  = 94
+	LDAPResultMoreResultsToReturn                = 95
+	LDAPResultClientLoop                         = 96
+	LDAPResultReferralLimitExceeded              = 97
+	LDAPResultInvalidResponse                    = 100
+	LDAPResultAmbiguousResponse                  = 101
+	LDAPResultTLSNotSupported                    = 112
+	LDAPResultIntermediateResponse               = 113
+	LDAPResultUnknownType                        = 114
+	LDAPResultCanceled                           = 118
+	LDAPResultNoSuchOperation                    = 119
+	LDAPResultTooLate                            = 120
+	LDAPResultCannotCancel                       = 121
+	LDAPResultAssertionFailed                    = 122
+	LDAPResultAuthorizationDenied                = 123
+	LDAPResultSyncRefreshRequired                = 4096
+
+	ErrorNetwork            = 200
+	ErrorFilterCompile      = 201
+	ErrorFilterDecompile    = 202
+	ErrorDebugging          = 203
+	ErrorUnexpectedMessage  = 204
+	ErrorUnexpectedResponse = 205
+	ErrorEmptyPassword      = 206
+)
+
+// LDAPResultCodeMap contains string descriptions for LDAP error codes
+var LDAPResultCodeMap = map[uint16]string{
+	LDAPResultSuccess:                            "Success",
+	LDAPResultOperationsError:                    "Operations Error",
+	LDAPResultProtocolError:                      "Protocol Error",
+	LDAPResultTimeLimitExceeded:                  "Time Limit Exceeded",
+	LDAPResultSizeLimitExceeded:                  "Size Limit Exceeded",
+	LDAPResultCompareFalse:                       "Compare False",
+	LDAPResultCompareTrue:                        "Compare True",
+	LDAPResultAuthMethodNotSupported:             "Auth Method Not Supported",
+	LDAPResultStrongAuthRequired:                 "Strong Auth Required",
+	LDAPResultReferral:                           "Referral",
+	LDAPResultAdminLimitExceeded:                 "Admin Limit Exceeded",
+	LDAPResultUnavailableCriticalExtension:       "Unavailable Critical Extension",
+	LDAPResultConfidentialityRequired:            "Confidentiality Required",
+	LDAPResultSaslBindInProgress:                 "Sasl Bind In Progress",
+	LDAPResultNoSuchAttribute:                    "No Such Attribute",
+	LDAPResultUndefinedAttributeType:             "Undefined Attribute Type",
+	LDAPResultInappropriateMatching:              "Inappropriate Matching",
+	LDAPResultConstraintViolation:                "Constraint Violation",
+	LDAPResultAttributeOrValueExists:             "Attribute Or Value Exists",
+	LDAPResultInvalidAttributeSyntax:             "Invalid Attribute Syntax",
+	LDAPResultNoSuchObject:                       "No Such Object",
+	LDAPResultAliasProblem:                       "Alias Problem",
+	LDAPResultInvalidDNSyntax:                    "Invalid DN Syntax",
+	LDAPResultIsLeaf:                             "Is Leaf",
+	LDAPResultAliasDereferencingProblem:          "Alias Dereferencing Problem",
+	LDAPResultInappropriateAuthentication:        "Inappropriate Authentication",
+	LDAPResultInvalidCredentials:                 "Invalid Credentials",
+	LDAPResultInsufficientAccessRights:           "Insufficient Access Rights",
+	LDAPResultBusy:                               "Busy",
+	LDAPResultUnavailable:                        "Unavailable",
+	LDAPResultUnwillingToPerform:                 "Unwilling To Perform",
+	LDAPResultLoopDetect:                         "Loop Detect",
+	LDAPResultSortControlMissing:                 "Sort Control Missing",
+	LDAPResultOffsetRangeError:                   "Result Offset Range Error",
+	LDAPResultNamingViolation:                    "Naming Violation",
+	LDAPResultObjectClassViolation:               "Object Class Violation",
+	LDAPResultResultsTooLarge:                    "Results Too Large",
+	LDAPResultNotAllowedOnNonLeaf:                "Not Allowed On Non Leaf",
+	LDAPResultNotAllowedOnRDN:                    "Not Allowed On RDN",
+	LDAPResultEntryAlreadyExists:                 "Entry Already Exists",
+	LDAPResultObjectClassModsProhibited:          "Object Class Mods Prohibited",
+	LDAPResultAffectsMultipleDSAs:                "Affects Multiple DSAs",
+	LDAPResultVirtualListViewErrorOrControlError: "Failed because of a problem related to the virtual list view",
+	LDAPResultOther:                              "Other",
+	LDAPResultServerDown:                         "Cannot establish a connection",
+	LDAPResultLocalError:                         "An error occurred",
+	LDAPResultEncodingError:                      "LDAP encountered an error while encoding",
+	LDAPResultDecodingError:                      "LDAP encountered an error while decoding",
+	LDAPResultTimeout:                            "LDAP timeout while waiting for a response from the server",
+	LDAPResultAuthUnknown:                        "The auth method requested in a bind request is unknown",
+	LDAPResultFilterError:                        "An error occurred while encoding the given search filter",
+	LDAPResultUserCanceled:                       "The user canceled the operation",
+	LDAPResultParamError:                         "An invalid parameter was specified",
+	LDAPResultNoMemory:                           "Out of memory error",
+	LDAPResultConnectError:                       "A connection to the server could not be established",
+	LDAPResultNotSupported:                       "An attempt has been made to use a feature not supported LDAP",
+	LDAPResultControlNotFound:                    "The controls required to perform the requested operation were not found",
+	LDAPResultNoResultsReturned:                  "No results were returned from the server",
+	LDAPResultMoreResultsToReturn:                "There are more results in the chain of results",
+	LDAPResultClientLoop:                         "A loop has been detected. For example when following referrals",
+	LDAPResultReferralLimitExceeded:              "The referral hop limit has been exceeded",
+	LDAPResultCanceled:                           "Operation was canceled",
+	LDAPResultNoSuchOperation:                    "Server has no knowledge of the operation requested for cancellation",
+	LDAPResultTooLate:                            "Too late to cancel the outstanding operation",
+	LDAPResultCannotCancel:                       "The identified operation does not support cancellation or the cancel operation cannot be performed",
+	LDAPResultAssertionFailed:                    "An assertion control given in the LDAP operation evaluated to false causing the operation to not be performed",
+	LDAPResultSyncRefreshRequired:                "Refresh Required",
+	LDAPResultInvalidResponse:                    "Invalid Response",
+	LDAPResultAmbiguousResponse:                  "Ambiguous Response",
+	LDAPResultTLSNotSupported:                    "Tls Not Supported",
+	LDAPResultIntermediateResponse:               "Intermediate Response",
+	LDAPResultUnknownType:                        "Unknown Type",
+	LDAPResultAuthorizationDenied:                "Authorization Denied",
+
+	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",
+}
+
+// Error holds LDAP error information
+type Error struct {
+	// Err is the underlying error
+	Err error
+	// ResultCode is the LDAP error code
+	ResultCode uint16
+	// MatchedDN is the matchedDN returned if any
+	MatchedDN string
+}
+
+func (e *Error) Error() string {
+	return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
+}
+
+// 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).
+func GetLDAPError(packet *ber.Packet) error {
+	if packet == nil {
+		return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty packet")}
+	} else if len(packet.Children) >= 2 {
+		response := packet.Children[1]
+		if response == nil {
+			return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty response in packet")}
+		}
+		if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
+			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(response.Children[2].Value.(string))}
+		}
+	}
+
+	return &Error{ResultCode: ErrorNetwork, Err: fmt.Errorf("Invalid packet format")}
+}
+
+// NewError creates an LDAP error with the given code and underlying error
+func NewError(resultCode uint16, err error) error {
+	return &Error{ResultCode: resultCode, Err: err}
+}
+
+// IsErrorWithCode returns true if the given error is an LDAP error with the given result code
+func IsErrorWithCode(err error, desiredResultCode uint16) bool {
+	if err == nil {
+		return false
+	}
+
+	serverError, ok := err.(*Error)
+	if !ok {
+		return false
+	}
+
+	return serverError.ResultCode == desiredResultCode
+}
diff --git a/vendor/gopkg.in/ldap.v2/filter.go b/vendor/gopkg.in/ldap.v3/filter.go
similarity index 98%
rename from vendor/gopkg.in/ldap.v2/filter.go
rename to vendor/gopkg.in/ldap.v3/filter.go
index 3858a2865c..4cc4207bec 100644
--- a/vendor/gopkg.in/ldap.v2/filter.go
+++ b/vendor/gopkg.in/ldap.v3/filter.go
@@ -1,7 +1,3 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
 package ldap
 
 import (
diff --git a/vendor/gopkg.in/ldap.v2/ldap.go b/vendor/gopkg.in/ldap.v3/ldap.go
similarity index 82%
rename from vendor/gopkg.in/ldap.v2/ldap.go
rename to vendor/gopkg.in/ldap.v3/ldap.go
index 4969247569..d7666676fe 100644
--- a/vendor/gopkg.in/ldap.v2/ldap.go
+++ b/vendor/gopkg.in/ldap.v3/ldap.go
@@ -1,11 +1,8 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
 package ldap
 
 import (
 	"errors"
+	"fmt"
 	"io/ioutil"
 	"os"
 
@@ -101,13 +98,13 @@ func addLDAPDescriptions(packet *ber.Packet) (err error) {
 
 	switch application {
 	case ApplicationBindRequest:
-		addRequestDescriptions(packet)
+		err = addRequestDescriptions(packet)
 	case ApplicationBindResponse:
-		addDefaultLDAPResponseDescriptions(packet)
+		err = addDefaultLDAPResponseDescriptions(packet)
 	case ApplicationUnbindRequest:
-		addRequestDescriptions(packet)
+		err = addRequestDescriptions(packet)
 	case ApplicationSearchRequest:
-		addRequestDescriptions(packet)
+		err = addRequestDescriptions(packet)
 	case ApplicationSearchResultEntry:
 		packet.Children[1].Children[0].Description = "Object Name"
 		packet.Children[1].Children[1].Description = "Attributes"
@@ -120,37 +117,37 @@ func addLDAPDescriptions(packet *ber.Packet) (err error) {
 			}
 		}
 		if len(packet.Children) == 3 {
-			addControlDescriptions(packet.Children[2])
+			err = addControlDescriptions(packet.Children[2])
 		}
 	case ApplicationSearchResultDone:
-		addDefaultLDAPResponseDescriptions(packet)
+		err = addDefaultLDAPResponseDescriptions(packet)
 	case ApplicationModifyRequest:
-		addRequestDescriptions(packet)
+		err = addRequestDescriptions(packet)
 	case ApplicationModifyResponse:
 	case ApplicationAddRequest:
-		addRequestDescriptions(packet)
+		err = addRequestDescriptions(packet)
 	case ApplicationAddResponse:
 	case ApplicationDelRequest:
-		addRequestDescriptions(packet)
+		err = addRequestDescriptions(packet)
 	case ApplicationDelResponse:
 	case ApplicationModifyDNRequest:
-		addRequestDescriptions(packet)
+		err = addRequestDescriptions(packet)
 	case ApplicationModifyDNResponse:
 	case ApplicationCompareRequest:
-		addRequestDescriptions(packet)
+		err = addRequestDescriptions(packet)
 	case ApplicationCompareResponse:
 	case ApplicationAbandonRequest:
-		addRequestDescriptions(packet)
+		err = addRequestDescriptions(packet)
 	case ApplicationSearchResultReference:
 	case ApplicationExtendedRequest:
-		addRequestDescriptions(packet)
+		err = addRequestDescriptions(packet)
 	case ApplicationExtendedResponse:
 	}
 
-	return nil
+	return err
 }
 
-func addControlDescriptions(packet *ber.Packet) {
+func addControlDescriptions(packet *ber.Packet) error {
 	packet.Description = "Controls"
 	for _, child := range packet.Children {
 		var value *ber.Packet
@@ -159,7 +156,7 @@ func addControlDescriptions(packet *ber.Packet) {
 		switch len(child.Children) {
 		case 0:
 			// at least one child is required for control type
-			continue
+			return fmt.Errorf("at least one child is required for control type")
 
 		case 1:
 			// just type, no criticality or value
@@ -188,8 +185,9 @@ func addControlDescriptions(packet *ber.Packet) {
 
 		default:
 			// more than 3 children is invalid
-			continue
+			return fmt.Errorf("more than 3 children for control packet found")
 		}
+
 		if value == nil {
 			continue
 		}
@@ -197,7 +195,10 @@ func addControlDescriptions(packet *ber.Packet) {
 		case ControlTypePaging:
 			value.Description += " (Paging)"
 			if value.Value != nil {
-				valueChildren := ber.DecodePacket(value.Data.Bytes())
+				valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
+				if err != nil {
+					return fmt.Errorf("failed to decode data bytes: %s", err)
+				}
 				value.Data.Truncate(0)
 				value.Value = nil
 				valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes()
@@ -210,7 +211,10 @@ func addControlDescriptions(packet *ber.Packet) {
 		case ControlTypeBeheraPasswordPolicy:
 			value.Description += " (Password Policy - Behera Draft)"
 			if value.Value != nil {
-				valueChildren := ber.DecodePacket(value.Data.Bytes())
+				valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
+				if err != nil {
+					return fmt.Errorf("failed to decode data bytes: %s", err)
+				}
 				value.Data.Truncate(0)
 				value.Value = nil
 				value.AppendChild(valueChildren)
@@ -220,7 +224,10 @@ func addControlDescriptions(packet *ber.Packet) {
 				if child.Tag == 0 {
 					//Warning
 					warningPacket := child.Children[0]
-					packet := ber.DecodePacket(warningPacket.Data.Bytes())
+					packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes())
+					if err != nil {
+						return fmt.Errorf("failed to decode data bytes: %s", err)
+					}
 					val, ok := packet.Value.(int64)
 					if ok {
 						if warningPacket.Tag == 0 {
@@ -235,7 +242,10 @@ func addControlDescriptions(packet *ber.Packet) {
 					}
 				} else if child.Tag == 1 {
 					// Error
-					packet := ber.DecodePacket(child.Data.Bytes())
+					packet, err := ber.DecodePacketErr(child.Data.Bytes())
+					if err != nil {
+						return fmt.Errorf("failed to decode data bytes: %s", err)
+					}
 					val, ok := packet.Value.(int8)
 					if !ok {
 						val = -1
@@ -246,28 +256,31 @@ func addControlDescriptions(packet *ber.Packet) {
 			}
 		}
 	}
+	return nil
 }
 
-func addRequestDescriptions(packet *ber.Packet) {
+func addRequestDescriptions(packet *ber.Packet) error {
 	packet.Description = "LDAP Request"
 	packet.Children[0].Description = "Message ID"
 	packet.Children[1].Description = ApplicationMap[uint8(packet.Children[1].Tag)]
 	if len(packet.Children) == 3 {
-		addControlDescriptions(packet.Children[2])
+		return addControlDescriptions(packet.Children[2])
 	}
+	return nil
 }
 
-func addDefaultLDAPResponseDescriptions(packet *ber.Packet) {
-	resultCode, _ := getLDAPResultCode(packet)
-	packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[resultCode] + ")"
-	packet.Children[1].Children[1].Description = "Matched DN"
+func addDefaultLDAPResponseDescriptions(packet *ber.Packet) error {
+	err := GetLDAPError(packet)
+	packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[err.(*Error).ResultCode] + ")"
+	packet.Children[1].Children[1].Description = "Matched DN (" + err.(*Error).MatchedDN + ")"
 	packet.Children[1].Children[2].Description = "Error Message"
 	if len(packet.Children[1].Children) > 3 {
 		packet.Children[1].Children[3].Description = "Referral"
 	}
 	if len(packet.Children) == 3 {
-		addControlDescriptions(packet.Children[2])
+		return addControlDescriptions(packet.Children[2])
 	}
+	return nil
 }
 
 // DebugBinaryFile reads and prints packets from the given filename
@@ -277,8 +290,13 @@ func DebugBinaryFile(fileName string) error {
 		return NewError(ErrorDebugging, err)
 	}
 	ber.PrintBytes(os.Stdout, file, "")
-	packet := ber.DecodePacket(file)
-	addLDAPDescriptions(packet)
+	packet, err := ber.DecodePacketErr(file)
+	if err != nil {
+		return fmt.Errorf("failed to decode packet: %s", err)
+	}
+	if err := addLDAPDescriptions(packet); err != nil {
+		return err
+	}
 	ber.PrintPacket(packet)
 
 	return nil
diff --git a/vendor/gopkg.in/ldap.v3/moddn.go b/vendor/gopkg.in/ldap.v3/moddn.go
new file mode 100644
index 0000000000..803279d262
--- /dev/null
+++ b/vendor/gopkg.in/ldap.v3/moddn.go
@@ -0,0 +1,104 @@
+// Package ldap - moddn.go contains ModifyDN functionality
+//
+// https://tools.ietf.org/html/rfc4511
+// ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+//      entry           LDAPDN,
+//      newrdn          RelativeLDAPDN,
+//      deleteoldrdn    BOOLEAN,
+//      newSuperior     [0] LDAPDN OPTIONAL }
+//
+//
+package ldap
+
+import (
+	"errors"
+	"log"
+
+	"gopkg.in/asn1-ber.v1"
+)
+
+// ModifyDNRequest holds the request to modify a DN
+type ModifyDNRequest struct {
+	DN           string
+	NewRDN       string
+	DeleteOldRDN bool
+	NewSuperior  string
+}
+
+// NewModifyDNRequest creates a new request which can be passed to ModifyDN().
+//
+// To move an object in the tree, set the "newSup" to the new parent entry DN. Use an
+// empty string for just changing the object's RDN.
+//
+// For moving the object without renaming, the "rdn" must be the first
+// RDN of the given DN.
+//
+// A call like
+//   mdnReq := NewModifyDNRequest("uid=someone,dc=example,dc=org", "uid=newname", true, "")
+// will setup the request to just rename uid=someone,dc=example,dc=org to
+// uid=newname,dc=example,dc=org.
+func NewModifyDNRequest(dn string, rdn string, delOld bool, newSup string) *ModifyDNRequest {
+	return &ModifyDNRequest{
+		DN:           dn,
+		NewRDN:       rdn,
+		DeleteOldRDN: delOld,
+		NewSuperior:  newSup,
+	}
+}
+
+func (m ModifyDNRequest) encode() *ber.Packet {
+	request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyDNRequest, nil, "Modify DN Request")
+	request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN"))
+	request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.NewRDN, "New RDN"))
+	request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, m.DeleteOldRDN, "Delete old RDN"))
+	if m.NewSuperior != "" {
+		request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, m.NewSuperior, "New Superior"))
+	}
+	return request
+}
+
+// ModifyDN renames the given DN and optionally move to another base (when the "newSup" argument
+// to NewModifyDNRequest() is not "").
+func (l *Conn) ModifyDN(m *ModifyDNRequest) error {
+	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
+	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
+	packet.AppendChild(m.encode())
+
+	l.Debug.PrintPacket(packet)
+
+	msgCtx, err := l.sendMessage(packet)
+	if err != nil {
+		return err
+	}
+	defer l.finishMessage(msgCtx)
+
+	l.Debug.Printf("%d: waiting for response", msgCtx.id)
+	packetResponse, ok := <-msgCtx.responses
+	if !ok {
+		return NewError(ErrorNetwork, errors.New("ldap: channel closed"))
+	}
+	packet, err = packetResponse.ReadPacket()
+	l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
+	if err != nil {
+		return err
+	}
+
+	if l.Debug {
+		if err := addLDAPDescriptions(packet); err != nil {
+			return err
+		}
+		ber.PrintPacket(packet)
+	}
+
+	if packet.Children[1].Tag == ApplicationModifyDNResponse {
+		err := GetLDAPError(packet)
+		if err != nil {
+			return err
+		}
+	} else {
+		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
+	}
+
+	l.Debug.Printf("%d: returning", msgCtx.id)
+	return nil
+}
diff --git a/vendor/gopkg.in/ldap.v2/modify.go b/vendor/gopkg.in/ldap.v3/modify.go
similarity index 63%
rename from vendor/gopkg.in/ldap.v2/modify.go
rename to vendor/gopkg.in/ldap.v3/modify.go
index e4ab6cefc7..d83e6221fd 100644
--- a/vendor/gopkg.in/ldap.v2/modify.go
+++ b/vendor/gopkg.in/ldap.v3/modify.go
@@ -1,7 +1,3 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-//
 // File contains Modify functionality
 //
 // https://tools.ietf.org/html/rfc4511
@@ -62,54 +58,56 @@ func (p *PartialAttribute) encode() *ber.Packet {
 	return seq
 }
 
+// Change for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
+type Change struct {
+	// Operation is the type of change to be made
+	Operation uint
+	// Modification is the attribute to be modified
+	Modification PartialAttribute
+}
+
+func (c *Change) encode() *ber.Packet {
+	change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
+	change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(c.Operation), "Operation"))
+	change.AppendChild(c.Modification.encode())
+	return change
+}
+
 // ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
 type ModifyRequest struct {
 	// DN is the distinguishedName of the directory entry to modify
 	DN string
-	// AddAttributes contain the attributes to add
-	AddAttributes []PartialAttribute
-	// DeleteAttributes contain the attributes to delete
-	DeleteAttributes []PartialAttribute
-	// ReplaceAttributes contain the attributes to replace
-	ReplaceAttributes []PartialAttribute
+	// Changes contain the attributes to modify
+	Changes []Change
+	// Controls hold optional controls to send with the request
+	Controls []Control
 }
 
-// Add inserts the given attribute to the list of attributes to add
+// Add appends the given attribute to the list of changes to be made
 func (m *ModifyRequest) Add(attrType string, attrVals []string) {
-	m.AddAttributes = append(m.AddAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
+	m.appendChange(AddAttribute, attrType, attrVals)
 }
 
-// Delete inserts the given attribute to the list of attributes to delete
+// Delete appends the given attribute to the list of changes to be made
 func (m *ModifyRequest) Delete(attrType string, attrVals []string) {
-	m.DeleteAttributes = append(m.DeleteAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
+	m.appendChange(DeleteAttribute, attrType, attrVals)
 }
 
-// Replace inserts the given attribute to the list of attributes to replace
+// Replace appends the given attribute to the list of changes to be made
 func (m *ModifyRequest) Replace(attrType string, attrVals []string) {
-	m.ReplaceAttributes = append(m.ReplaceAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
+	m.appendChange(ReplaceAttribute, attrType, attrVals)
+}
+
+func (m *ModifyRequest) appendChange(operation uint, attrType string, attrVals []string) {
+	m.Changes = append(m.Changes, Change{operation, PartialAttribute{Type: attrType, Vals: attrVals}})
 }
 
 func (m ModifyRequest) encode() *ber.Packet {
 	request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
 	request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN"))
 	changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
-	for _, attribute := range m.AddAttributes {
-		change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
-		change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(AddAttribute), "Operation"))
-		change.AppendChild(attribute.encode())
-		changes.AppendChild(change)
-	}
-	for _, attribute := range m.DeleteAttributes {
-		change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
-		change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(DeleteAttribute), "Operation"))
-		change.AppendChild(attribute.encode())
-		changes.AppendChild(change)
-	}
-	for _, attribute := range m.ReplaceAttributes {
-		change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
-		change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(ReplaceAttribute), "Operation"))
-		change.AppendChild(attribute.encode())
-		changes.AppendChild(change)
+	for _, change := range m.Changes {
+		changes.AppendChild(change.encode())
 	}
 	request.AppendChild(changes)
 	return request
@@ -118,9 +116,11 @@ func (m ModifyRequest) encode() *ber.Packet {
 // NewModifyRequest creates a modify request for the given DN
 func NewModifyRequest(
 	dn string,
+	controls []Control,
 ) *ModifyRequest {
 	return &ModifyRequest{
-		DN: dn,
+		DN:       dn,
+		Controls: controls,
 	}
 }
 
@@ -129,6 +129,9 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
 	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
 	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
 	packet.AppendChild(modifyRequest.encode())
+	if len(modifyRequest.Controls) > 0 {
+		packet.AppendChild(encodeControls(modifyRequest.Controls))
+	}
 
 	l.Debug.PrintPacket(packet)
 
@@ -157,9 +160,9 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
 	}
 
 	if packet.Children[1].Tag == ApplicationModifyResponse {
-		resultCode, resultDescription := getLDAPResultCode(packet)
-		if resultCode != 0 {
-			return NewError(resultCode, errors.New(resultDescription))
+		err := GetLDAPError(packet)
+		if err != nil {
+			return err
 		}
 	} else {
 		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
diff --git a/vendor/gopkg.in/ldap.v2/passwdmodify.go b/vendor/gopkg.in/ldap.v3/passwdmodify.go
similarity index 92%
rename from vendor/gopkg.in/ldap.v2/passwdmodify.go
rename to vendor/gopkg.in/ldap.v3/passwdmodify.go
index 7d8246fd18..06bc21db13 100644
--- a/vendor/gopkg.in/ldap.v2/passwdmodify.go
+++ b/vendor/gopkg.in/ldap.v3/passwdmodify.go
@@ -32,6 +32,8 @@ type PasswordModifyRequest struct {
 type PasswordModifyResult struct {
 	// GeneratedPassword holds a password generated by the server, if present
 	GeneratedPassword string
+	// Referral are the returned referral
+	Referral string
 }
 
 func (r *PasswordModifyRequest) encode() (*ber.Packet, error) {
@@ -124,12 +126,19 @@ func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*Pa
 	}
 
 	if packet.Children[1].Tag == ApplicationExtendedResponse {
-		resultCode, resultDescription := getLDAPResultCode(packet)
-		if resultCode != 0 {
-			return nil, NewError(resultCode, errors.New(resultDescription))
+		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 {
-		return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag))
+		return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag))
 	}
 
 	extendedResponse := packet.Children[1]
diff --git a/vendor/gopkg.in/ldap.v2/search.go b/vendor/gopkg.in/ldap.v3/search.go
similarity index 96%
rename from vendor/gopkg.in/ldap.v2/search.go
rename to vendor/gopkg.in/ldap.v3/search.go
index 2a99894c94..3aa6dac0c2 100644
--- a/vendor/gopkg.in/ldap.v2/search.go
+++ b/vendor/gopkg.in/ldap.v3/search.go
@@ -1,7 +1,3 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-//
 // File contains Search functionality
 //
 // https://tools.ietf.org/html/rfc4511
@@ -313,10 +309,10 @@ func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32)
 	} else {
 		castControl, ok := control.(*ControlPaging)
 		if !ok {
-			return nil, fmt.Errorf("Expected paging control to be of type *ControlPaging, got %v", control)
+			return nil, fmt.Errorf("expected paging control to be of type *ControlPaging, got %v", control)
 		}
 		if castControl.PagingSize != pagingSize {
-			return nil, fmt.Errorf("Paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
+			return nil, fmt.Errorf("paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
 		}
 		pagingControl = castControl
 	}
@@ -379,7 +375,7 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
 	}
 	packet.AppendChild(encodedSearchRequest)
 	// encode search controls
-	if searchRequest.Controls != nil {
+	if len(searchRequest.Controls) > 0 {
 		packet.AppendChild(encodeControls(searchRequest.Controls))
 	}
 
@@ -431,13 +427,17 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
 			}
 			result.Entries = append(result.Entries, entry)
 		case 5:
-			resultCode, resultDescription := getLDAPResultCode(packet)
-			if resultCode != 0 {
-				return result, NewError(resultCode, errors.New(resultDescription))
+			err := GetLDAPError(packet)
+			if err != nil {
+				return nil, err
 			}
 			if len(packet.Children) == 3 {
 				for _, child := range packet.Children[2].Children {
-					result.Controls = append(result.Controls, DecodeControl(child))
+					decodedChild, err := DecodeControl(child)
+					if err != nil {
+						return nil, fmt.Errorf("failed to decode child control: %s", err)
+					}
+					result.Controls = append(result.Controls, decodedChild)
 				}
 			}
 			foundSearchResultDone = true