summaryrefslogtreecommitdiffstats
path: root/vendor/github.com
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/denisenkom/go-mssqldb/README.md22
-rw-r--r--vendor/github.com/denisenkom/go-mssqldb/accesstokenconnector.go51
-rw-r--r--vendor/github.com/denisenkom/go-mssqldb/conn_str.go1
-rw-r--r--vendor/github.com/denisenkom/go-mssqldb/mssql.go5
-rw-r--r--vendor/github.com/denisenkom/go-mssqldb/ntlm.go173
-rw-r--r--vendor/github.com/denisenkom/go-mssqldb/tds.go146
-rw-r--r--vendor/github.com/denisenkom/go-mssqldb/token.go47
7 files changed, 391 insertions, 54 deletions
diff --git a/vendor/github.com/denisenkom/go-mssqldb/README.md b/vendor/github.com/denisenkom/go-mssqldb/README.md
index b655176bb6..94d87fe092 100644
--- a/vendor/github.com/denisenkom/go-mssqldb/README.md
+++ b/vendor/github.com/denisenkom/go-mssqldb/README.md
@@ -18,7 +18,7 @@ Other supported formats are listed below.
### Common parameters:
-* `user id` - enter the SQL Server Authentication user id or the Windows Authentication user id in the DOMAIN\User format. On Windows, if user id is empty or missing Single-Sign-On is used.
+* `user id` - enter the SQL Server Authentication user id or the Windows Authentication user id in the DOMAIN\User format. On Windows, if user id is empty or missing Single-Sign-On is used. The user domain sensitive to the case which is defined in the connection string.
* `password`
* `database`
* `connection timeout` - in seconds (default is 0 for no timeout), set to 0 for no timeout. Recommended to set to 0 and use context to manage query and connection timeouts.
@@ -106,6 +106,26 @@ Other supported formats are listed below.
* `odbc:server=localhost;user id=sa;password={foo{bar}` // Literal `{`, password is "foo{bar"
* `odbc:server=localhost;user id=sa;password={foo}}bar}` // Escaped `} with `}}`, password is "foo}bar"
+### Azure Active Directory authentication - preview
+
+The configuration of functionality might change in the future.
+
+Azure Active Directory (AAD) access tokens are relatively short lived and need to be
+valid when a new connection is made. Authentication is supported using a callback func that
+provides a fresh and valid token using a connector:
+``` golang
+conn, err := mssql.NewAccessTokenConnector(
+ "Server=test.database.windows.net;Database=testdb",
+ tokenProvider)
+if err != nil {
+ // handle errors in DSN
+}
+db := sql.OpenDB(conn)
+```
+Where `tokenProvider` is a function that returns a fresh access token or an error. None of these statements
+actually trigger the retrieval of a token, this happens when the first statment is issued and a connection
+is created.
+
## Executing Stored Procedures
To run a stored procedure, set the query text to the procedure name:
diff --git a/vendor/github.com/denisenkom/go-mssqldb/accesstokenconnector.go b/vendor/github.com/denisenkom/go-mssqldb/accesstokenconnector.go
new file mode 100644
index 0000000000..8dbe5099e4
--- /dev/null
+++ b/vendor/github.com/denisenkom/go-mssqldb/accesstokenconnector.go
@@ -0,0 +1,51 @@
+// +build go1.10
+
+package mssql
+
+import (
+ "context"
+ "database/sql/driver"
+ "errors"
+ "fmt"
+)
+
+var _ driver.Connector = &accessTokenConnector{}
+
+// accessTokenConnector wraps Connector and injects a
+// fresh access token when connecting to the database
+type accessTokenConnector struct {
+ Connector
+
+ accessTokenProvider func() (string, error)
+}
+
+// NewAccessTokenConnector creates a new connector from a DSN and a token provider.
+// The token provider func will be called when a new connection is requested and should return a valid access token.
+// The returned connector may be used with sql.OpenDB.
+func NewAccessTokenConnector(dsn string, tokenProvider func() (string, error)) (driver.Connector, error) {
+ if tokenProvider == nil {
+ return nil, errors.New("mssql: tokenProvider cannot be nil")
+ }
+
+ conn, err := NewConnector(dsn)
+ if err != nil {
+ return nil, err
+ }
+
+ c := &accessTokenConnector{
+ Connector: *conn,
+ accessTokenProvider: tokenProvider,
+ }
+ return c, nil
+}
+
+// Connect returns a new database connection
+func (c *accessTokenConnector) Connect(ctx context.Context) (driver.Conn, error) {
+ var err error
+ c.Connector.params.fedAuthAccessToken, err = c.accessTokenProvider()
+ if err != nil {
+ return nil, fmt.Errorf("mssql: error retrieving access token: %+v", err)
+ }
+
+ return c.Connector.Connect(ctx)
+}
diff --git a/vendor/github.com/denisenkom/go-mssqldb/conn_str.go b/vendor/github.com/denisenkom/go-mssqldb/conn_str.go
index 4ff54b8955..26ac50f38d 100644
--- a/vendor/github.com/denisenkom/go-mssqldb/conn_str.go
+++ b/vendor/github.com/denisenkom/go-mssqldb/conn_str.go
@@ -37,6 +37,7 @@ type connectParams struct {
failOverPartner string
failOverPort uint64
packetSize uint16
+ fedAuthAccessToken string
}
func parseConnectParams(dsn string) (connectParams, error) {
diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql.go b/vendor/github.com/denisenkom/go-mssqldb/mssql.go
index 5d81516919..a74bc7e3fc 100644
--- a/vendor/github.com/denisenkom/go-mssqldb/mssql.go
+++ b/vendor/github.com/denisenkom/go-mssqldb/mssql.go
@@ -397,7 +397,10 @@ func (s *Stmt) Close() error {
}
func (s *Stmt) SetQueryNotification(id, options string, timeout time.Duration) {
- to := uint32(timeout / time.Second)
+ // 2.2.5.3.1 Query Notifications Header
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/e168d373-a7b7-41aa-b6ca-25985466a7e0
+ // Timeout in milliseconds in TDS protocol.
+ to := uint32(timeout / time.Millisecond)
if to < 1 {
to = 1
}
diff --git a/vendor/github.com/denisenkom/go-mssqldb/ntlm.go b/vendor/github.com/denisenkom/go-mssqldb/ntlm.go
index 7c0cc4f785..ea9148aed0 100644
--- a/vendor/github.com/denisenkom/go-mssqldb/ntlm.go
+++ b/vendor/github.com/denisenkom/go-mssqldb/ntlm.go
@@ -4,11 +4,14 @@ package mssql
import (
"crypto/des"
+ "crypto/hmac"
"crypto/md5"
"crypto/rand"
"encoding/binary"
"errors"
+ "fmt"
"strings"
+ "time"
"unicode/utf16"
"golang.org/x/crypto/md4"
@@ -198,86 +201,204 @@ func ntlmSessionResponse(clientNonce [8]byte, serverChallenge [8]byte, password
return response(hash, passwordHash)
}
-func (auth *ntlmAuth) NextBytes(bytes []byte) ([]byte, error) {
- if string(bytes[0:8]) != "NTLMSSP\x00" {
- return nil, errorNTLM
+func ntlmHashNoPadding(val string) []byte {
+ hash := make([]byte, 16)
+ h := md4.New()
+ h.Write(utf16le(val))
+ h.Sum(hash[:0])
+
+ return hash
+}
+
+func hmacMD5(passwordHash, data []byte) []byte {
+ hmacEntity := hmac.New(md5.New, passwordHash)
+ hmacEntity.Write(data)
+
+ return hmacEntity.Sum(nil)
+}
+
+func getNTLMv2AndLMv2ResponsePayloads(userDomain, username, password string, challenge, nonce [8]byte, targetInfoFields []byte, timestamp time.Time) (ntlmV2Payload, lmV2Payload []byte) {
+ // NTLMv2 response payload: http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response
+
+ ntlmHash := ntlmHashNoPadding(password)
+ usernameAndTargetBytes := utf16le(strings.ToUpper(username) + userDomain)
+ ntlmV2Hash := hmacMD5(ntlmHash, usernameAndTargetBytes)
+ targetInfoLength := len(targetInfoFields)
+ blob := make([]byte, 32+targetInfoLength)
+ binary.BigEndian.PutUint32(blob[:4], 0x01010000)
+ binary.BigEndian.PutUint32(blob[4:8], 0x00000000)
+ binary.BigEndian.PutUint64(blob[8:16], uint64(timestamp.UnixNano()))
+ copy(blob[16:24], nonce[:])
+ binary.BigEndian.PutUint32(blob[24:28], 0x00000000)
+ copy(blob[28:], targetInfoFields)
+ binary.BigEndian.PutUint32(blob[28+targetInfoLength:], 0x00000000)
+ challengeLength := len(challenge)
+ blobLength := len(blob)
+ challengeAndBlob := make([]byte, challengeLength+blobLength)
+ copy(challengeAndBlob[:challengeLength], challenge[:])
+ copy(challengeAndBlob[challengeLength:], blob)
+ hashedChallenge := hmacMD5(ntlmV2Hash, challengeAndBlob)
+ ntlmV2Payload = append(hashedChallenge, blob...)
+
+ // LMv2 response payload: http://davenport.sourceforge.net/ntlm.html#theLmv2Response
+ ntlmV2hash := hmacMD5(ntlmHash, usernameAndTargetBytes)
+ challengeAndNonce := make([]byte, 16)
+ copy(challengeAndNonce[:8], challenge[:])
+ copy(challengeAndNonce[8:], nonce[:])
+ hashedChallenge = hmacMD5(ntlmV2hash, challengeAndNonce)
+ lmV2Payload = append(hashedChallenge, nonce[:]...)
+
+ return
+}
+
+func negotiateExtendedSessionSecurity(flags uint32, message []byte, challenge [8]byte, username, password, userDom string) (lm, nt []byte, err error) {
+ nonce := clientChallenge()
+
+ // Official specification: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/b38c36ed-2804-4868-a9ff-8dd3182128e4
+ // Unofficial walk through referenced by https://www.freetds.org/userguide/domains.htm: http://davenport.sourceforge.net/ntlm.html
+ if (flags & _NEGOTIATE_TARGET_INFO) != 0 {
+ targetInfoFields, err := getNTLMv2TargetInfoFields(message)
+ if err != nil {
+ return lm, nt, err
+ }
+
+ nt, lm = getNTLMv2AndLMv2ResponsePayloads(userDom, username, password, challenge, nonce, targetInfoFields, time.Now())
+
+ return lm, nt, nil
}
- if binary.LittleEndian.Uint32(bytes[8:12]) != _CHALLENGE_MESSAGE {
- return nil, errorNTLM
+
+ var lm_bytes [24]byte
+ copy(lm_bytes[:8], nonce[:])
+ lm = lm_bytes[:]
+ nt_bytes := ntlmSessionResponse(nonce, challenge, password)
+ nt = nt_bytes[:]
+
+ return lm, nt, nil
+}
+
+func getNTLMv2TargetInfoFields(type2Message []byte) (info []byte, err error) {
+ type2MessageError := "mssql: while parsing NTLMv2 type 2 message, length %d too small for offset %d"
+ type2MessageLength := len(type2Message)
+ if type2MessageLength < 20 {
+ return nil, fmt.Errorf(type2MessageError, type2MessageLength, 20)
}
- flags := binary.LittleEndian.Uint32(bytes[20:24])
- var challenge [8]byte
- copy(challenge[:], bytes[24:32])
- var lm, nt []byte
- if (flags & _NEGOTIATE_EXTENDED_SESSIONSECURITY) != 0 {
- nonce := clientChallenge()
- var lm_bytes [24]byte
- copy(lm_bytes[:8], nonce[:])
- lm = lm_bytes[:]
- nt_bytes := ntlmSessionResponse(nonce, challenge, auth.Password)
- nt = nt_bytes[:]
- } else {
- lm_bytes := lmResponse(challenge, auth.Password)
- lm = lm_bytes[:]
- nt_bytes := ntResponse(challenge, auth.Password)
- nt = nt_bytes[:]
+ targetNameAllocated := binary.LittleEndian.Uint16(type2Message[14:16])
+ targetNameOffset := binary.LittleEndian.Uint32(type2Message[16:20])
+ endOfOffset := int(targetNameOffset + uint32(targetNameAllocated))
+ if type2MessageLength < endOfOffset {
+ return nil, fmt.Errorf(type2MessageError, type2MessageLength, endOfOffset)
}
+
+ targetInformationAllocated := binary.LittleEndian.Uint16(type2Message[42:44])
+ targetInformationDataOffset := binary.LittleEndian.Uint32(type2Message[44:48])
+ endOfOffset = int(targetInformationDataOffset + uint32(targetInformationAllocated))
+ if type2MessageLength < endOfOffset {
+ return nil, fmt.Errorf(type2MessageError, type2MessageLength, endOfOffset)
+ }
+
+ targetInformationBytes := make([]byte, targetInformationAllocated)
+ copy(targetInformationBytes, type2Message[targetInformationDataOffset:targetInformationDataOffset+uint32(targetInformationAllocated)])
+
+ return targetInformationBytes, nil
+}
+
+func buildNTLMResponsePayload(lm, nt []byte, flags uint32, domain, workstation, username string) ([]byte, error) {
lm_len := len(lm)
nt_len := len(nt)
-
- domain16 := utf16le(auth.Domain)
+ domain16 := utf16le(domain)
domain_len := len(domain16)
- user16 := utf16le(auth.UserName)
+ user16 := utf16le(username)
user_len := len(user16)
- workstation16 := utf16le(auth.Workstation)
+ workstation16 := utf16le(workstation)
workstation_len := len(workstation16)
-
msg := make([]byte, 88+lm_len+nt_len+domain_len+user_len+workstation_len)
copy(msg, []byte("NTLMSSP\x00"))
binary.LittleEndian.PutUint32(msg[8:], _AUTHENTICATE_MESSAGE)
+
// Lm Challenge Response Fields
binary.LittleEndian.PutUint16(msg[12:], uint16(lm_len))
binary.LittleEndian.PutUint16(msg[14:], uint16(lm_len))
binary.LittleEndian.PutUint32(msg[16:], 88)
+
// Nt Challenge Response Fields
binary.LittleEndian.PutUint16(msg[20:], uint16(nt_len))
binary.LittleEndian.PutUint16(msg[22:], uint16(nt_len))
binary.LittleEndian.PutUint32(msg[24:], uint32(88+lm_len))
+
// Domain Name Fields
binary.LittleEndian.PutUint16(msg[28:], uint16(domain_len))
binary.LittleEndian.PutUint16(msg[30:], uint16(domain_len))
binary.LittleEndian.PutUint32(msg[32:], uint32(88+lm_len+nt_len))
+
// User Name Fields
binary.LittleEndian.PutUint16(msg[36:], uint16(user_len))
binary.LittleEndian.PutUint16(msg[38:], uint16(user_len))
binary.LittleEndian.PutUint32(msg[40:], uint32(88+lm_len+nt_len+domain_len))
+
// Workstation Fields
binary.LittleEndian.PutUint16(msg[44:], uint16(workstation_len))
binary.LittleEndian.PutUint16(msg[46:], uint16(workstation_len))
binary.LittleEndian.PutUint32(msg[48:], uint32(88+lm_len+nt_len+domain_len+user_len))
+
// Encrypted Random Session Key Fields
binary.LittleEndian.PutUint16(msg[52:], 0)
binary.LittleEndian.PutUint16(msg[54:], 0)
binary.LittleEndian.PutUint32(msg[56:], uint32(88+lm_len+nt_len+domain_len+user_len+workstation_len))
+
// Negotiate Flags
binary.LittleEndian.PutUint32(msg[60:], flags)
+
// Version
binary.LittleEndian.PutUint32(msg[64:], 0)
binary.LittleEndian.PutUint32(msg[68:], 0)
+
// MIC
binary.LittleEndian.PutUint32(msg[72:], 0)
binary.LittleEndian.PutUint32(msg[76:], 0)
binary.LittleEndian.PutUint32(msg[88:], 0)
binary.LittleEndian.PutUint32(msg[84:], 0)
+
// Payload
copy(msg[88:], lm)
copy(msg[88+lm_len:], nt)
copy(msg[88+lm_len+nt_len:], domain16)
copy(msg[88+lm_len+nt_len+domain_len:], user16)
copy(msg[88+lm_len+nt_len+domain_len+user_len:], workstation16)
+
return msg, nil
}
+func (auth *ntlmAuth) NextBytes(bytes []byte) ([]byte, error) {
+ signature := string(bytes[0:8])
+ if signature != "NTLMSSP\x00" {
+ return nil, errorNTLM
+ }
+
+ messageTypeIndicator := binary.LittleEndian.Uint32(bytes[8:12])
+ if messageTypeIndicator != _CHALLENGE_MESSAGE {
+ return nil, errorNTLM
+ }
+
+ var challenge [8]byte
+ copy(challenge[:], bytes[24:32])
+ flags := binary.LittleEndian.Uint32(bytes[20:24])
+ if (flags & _NEGOTIATE_EXTENDED_SESSIONSECURITY) != 0 {
+ lm, nt, err := negotiateExtendedSessionSecurity(flags, bytes, challenge, auth.UserName, auth.Password, auth.Domain)
+ if err != nil {
+ return nil, err
+ }
+
+ return buildNTLMResponsePayload(lm, nt, flags, auth.Domain, auth.Workstation, auth.UserName)
+ }
+
+ lm_bytes := lmResponse(challenge, auth.Password)
+ lm := lm_bytes[:]
+ nt_bytes := ntResponse(challenge, auth.Password)
+ nt := nt_bytes[:]
+
+ return buildNTLMResponsePayload(lm, nt, flags, auth.Domain, auth.Workstation, auth.UserName)
+}
+
func (auth *ntlmAuth) Free() {
}
diff --git a/vendor/github.com/denisenkom/go-mssqldb/tds.go b/vendor/github.com/denisenkom/go-mssqldb/tds.go
index 9419836448..832c4fd23a 100644
--- a/vendor/github.com/denisenkom/go-mssqldb/tds.go
+++ b/vendor/github.com/denisenkom/go-mssqldb/tds.go
@@ -100,13 +100,15 @@ const (
// prelogin fields
// http://msdn.microsoft.com/en-us/library/dd357559.aspx
const (
- preloginVERSION = 0
- preloginENCRYPTION = 1
- preloginINSTOPT = 2
- preloginTHREADID = 3
- preloginMARS = 4
- preloginTRACEID = 5
- preloginTERMINATOR = 0xff
+ preloginVERSION = 0
+ preloginENCRYPTION = 1
+ preloginINSTOPT = 2
+ preloginTHREADID = 3
+ preloginMARS = 4
+ preloginTRACEID = 5
+ preloginFEDAUTHREQUIRED = 6
+ preloginNONCEOPT = 7
+ preloginTERMINATOR = 0xff
)
const (
@@ -245,6 +247,12 @@ const (
fReadOnlyIntent = 32
)
+// OptionFlags3
+// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/773a62b6-ee89-4c02-9e5e-344882630aac
+const (
+ fExtension = 0x10
+)
+
type login struct {
TDSVersion uint32
PacketSize uint32
@@ -269,6 +277,89 @@ type login struct {
SSPI []byte
AtchDBFile string
ChangePassword string
+ FeatureExt featureExts
+}
+
+type featureExts struct {
+ features map[byte]featureExt
+}
+
+type featureExt interface {
+ featureID() byte
+ toBytes() []byte
+}
+
+func (e *featureExts) Add(f featureExt) error {
+ if f == nil {
+ return nil
+ }
+ id := f.featureID()
+ if _, exists := e.features[id]; exists {
+ f := "Login error: Feature with ID '%v' is already present in FeatureExt block."
+ return fmt.Errorf(f, id)
+ }
+ if e.features == nil {
+ e.features = make(map[byte]featureExt)
+ }
+ e.features[id] = f
+ return nil
+}
+
+func (e featureExts) toBytes() []byte {
+ if len(e.features) == 0 {
+ return nil
+ }
+ var d []byte
+ for featureID, f := range e.features {
+ featureData := f.toBytes()
+
+ hdr := make([]byte, 5)
+ hdr[0] = featureID // FedAuth feature extension BYTE
+ binary.LittleEndian.PutUint32(hdr[1:], uint32(len(featureData))) // FeatureDataLen DWORD
+ d = append(d, hdr...)
+
+ d = append(d, featureData...) // FeatureData *BYTE
+ }
+ if d != nil {
+ d = append(d, 0xff) // Terminator
+ }
+ return d
+}
+
+type featureExtFedAuthSTS struct {
+ FedAuthEcho bool
+ FedAuthToken string
+ Nonce []byte
+}
+
+func (e *featureExtFedAuthSTS) featureID() byte {
+ return 0x02
+}
+
+func (e *featureExtFedAuthSTS) toBytes() []byte {
+ if e == nil {
+ return nil
+ }
+
+ options := byte(0x01) << 1 // 0x01 => STS bFedAuthLibrary 7BIT
+ if e.FedAuthEcho {
+ options |= 1 // fFedAuthEcho
+ }
+
+ d := make([]byte, 5)
+ d[0] = options
+
+ // looks like string in
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/f88b63bb-b479-49e1-a87b-deda521da508
+ tokenBytes := str2ucs2(e.FedAuthToken)
+ binary.LittleEndian.PutUint32(d[1:], uint32(len(tokenBytes))) // Should be a signed int32, but since the length is relatively small, this should work
+ d = append(d, tokenBytes...)
+
+ if len(e.Nonce) == 32 {
+ d = append(d, e.Nonce...)
+ }
+
+ return d
}
type loginHeader struct {
@@ -295,7 +386,7 @@ type loginHeader struct {
ServerNameOffset uint16
ServerNameLength uint16
ExtensionOffset uint16
- ExtensionLenght uint16
+ ExtensionLength uint16
CtlIntNameOffset uint16
CtlIntNameLength uint16
LanguageOffset uint16
@@ -357,6 +448,8 @@ func sendLogin(w *tdsBuffer, login login) error {
database := str2ucs2(login.Database)
atchdbfile := str2ucs2(login.AtchDBFile)
changepassword := str2ucs2(login.ChangePassword)
+ featureExt := login.FeatureExt.toBytes()
+
hdr := loginHeader{
TDSVersion: login.TDSVersion,
PacketSize: login.PacketSize,
@@ -405,7 +498,18 @@ func sendLogin(w *tdsBuffer, login login) error {
offset += uint16(len(atchdbfile))
hdr.ChangePasswordOffset = offset
offset += uint16(len(changepassword))
- hdr.Length = uint32(offset)
+
+ featureExtOffset := uint32(0)
+ featureExtLen := len(featureExt)
+ if featureExtLen > 0 {
+ hdr.OptionFlags3 |= fExtension
+ hdr.ExtensionOffset = offset
+ hdr.ExtensionLength = 4
+ offset += hdr.ExtensionLength // DWORD
+ featureExtOffset = uint32(offset)
+ }
+ hdr.Length = uint32(offset) + uint32(featureExtLen)
+
var err error
err = binary.Write(w, binary.LittleEndian, &hdr)
if err != nil {
@@ -455,6 +559,16 @@ func sendLogin(w *tdsBuffer, login login) error {
if err != nil {
return err
}
+ if featureExtOffset > 0 {
+ err = binary.Write(w, binary.LittleEndian, featureExtOffset)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(featureExt)
+ if err != nil {
+ return err
+ }
+ }
return w.FinishPacket()
}
@@ -844,15 +958,23 @@ initiate_connection:
AppName: p.appname,
TypeFlags: p.typeFlags,
}
- auth, auth_ok := getAuth(p.user, p.password, p.serverSPN, p.workstation)
- if auth_ok {
+ auth, authOk := getAuth(p.user, p.password, p.serverSPN, p.workstation)
+ switch {
+ case p.fedAuthAccessToken != "": // accesstoken ignores user/password
+ featurext := &featureExtFedAuthSTS{
+ FedAuthEcho: len(fields[preloginFEDAUTHREQUIRED]) > 0 && fields[preloginFEDAUTHREQUIRED][0] == 1,
+ FedAuthToken: p.fedAuthAccessToken,
+ Nonce: fields[preloginNONCEOPT],
+ }
+ login.FeatureExt.Add(featurext)
+ case authOk:
login.SSPI, err = auth.InitialBytes()
if err != nil {
return nil, err
}
login.OptionFlags2 |= fIntSecurity
defer auth.Free()
- } else {
+ default:
login.UserName = p.user
login.Password = p.password
}
diff --git a/vendor/github.com/denisenkom/go-mssqldb/token.go b/vendor/github.com/denisenkom/go-mssqldb/token.go
index 1acac8a5d2..25385e89dc 100644
--- a/vendor/github.com/denisenkom/go-mssqldb/token.go
+++ b/vendor/github.com/denisenkom/go-mssqldb/token.go
@@ -17,20 +17,21 @@ type token byte
// token ids
const (
- tokenReturnStatus token = 121 // 0x79
- tokenColMetadata token = 129 // 0x81
- tokenOrder token = 169 // 0xA9
- tokenError token = 170 // 0xAA
- tokenInfo token = 171 // 0xAB
- tokenReturnValue token = 0xAC
- tokenLoginAck token = 173 // 0xad
- tokenRow token = 209 // 0xd1
- tokenNbcRow token = 210 // 0xd2
- tokenEnvChange token = 227 // 0xE3
- tokenSSPI token = 237 // 0xED
- tokenDone token = 253 // 0xFD
- tokenDoneProc token = 254
- tokenDoneInProc token = 255
+ tokenReturnStatus token = 121 // 0x79
+ tokenColMetadata token = 129 // 0x81
+ tokenOrder token = 169 // 0xA9
+ tokenError token = 170 // 0xAA
+ tokenInfo token = 171 // 0xAB
+ tokenReturnValue token = 0xAC
+ tokenLoginAck token = 173 // 0xad
+ tokenFeatureExtAck token = 174 // 0xae
+ tokenRow token = 209 // 0xd1
+ tokenNbcRow token = 210 // 0xd2
+ tokenEnvChange token = 227 // 0xE3
+ tokenSSPI token = 237 // 0xED
+ tokenDone token = 253 // 0xFD
+ tokenDoneProc token = 254
+ tokenDoneInProc token = 255
)
// done flags
@@ -447,6 +448,22 @@ func parseLoginAck(r *tdsBuffer) loginAckStruct {
return res
}
+// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/2eb82f8e-11f0-46dc-b42d-27302fa4701a
+func parseFeatureExtAck(r *tdsBuffer) {
+ // at most 1 featureAck per feature in featureExt
+ // go-mssqldb will add at most 1 feature, the spec defines 7 different features
+ for i := 0; i < 8; i++ {
+ featureID := r.byte() // FeatureID
+ if featureID == 0xff {
+ return
+ }
+ size := r.uint32() // FeatureAckDataLen
+ d := make([]byte, size)
+ r.ReadFull(d)
+ }
+ panic("parsed more than 7 featureAck's, protocol implementation error?")
+}
+
// http://msdn.microsoft.com/en-us/library/dd357363.aspx
func parseColMetadata72(r *tdsBuffer) (columns []columnStruct) {
count := r.uint16()
@@ -577,6 +594,8 @@ func processSingleResponse(sess *tdsSession, ch chan tokenStruct, outs map[strin
case tokenLoginAck:
loginAck := parseLoginAck(sess.buf)
ch <- loginAck
+ case tokenFeatureExtAck:
+ parseFeatureExtAck(sess.buf)
case tokenOrder:
order := parseOrder(sess.buf)
ch <- order