summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-sql-driver/mysql/driver.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-sql-driver/mysql/driver.go')
-rw-r--r--vendor/github.com/go-sql-driver/mysql/driver.go117
1 files changed, 81 insertions, 36 deletions
diff --git a/vendor/github.com/go-sql-driver/mysql/driver.go b/vendor/github.com/go-sql-driver/mysql/driver.go
index c0375fe18..0022d1f1e 100644
--- a/vendor/github.com/go-sql-driver/mysql/driver.go
+++ b/vendor/github.com/go-sql-driver/mysql/driver.go
@@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
-// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+// Package mysql provides a MySQL driver for Go's database/sql package
//
// The driver should be used via the database/sql package:
//
@@ -22,7 +22,7 @@ import (
"net"
)
-// This struct is exported to make the driver directly accessible.
+// MySQLDriver is exported to make the driver directly accessible.
// In general the driver is used via the database/sql package.
type MySQLDriver struct{}
@@ -50,20 +50,22 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
// New mysqlConn
mc := &mysqlConn{
- maxPacketAllowed: maxPacketSize,
+ maxAllowedPacket: maxPacketSize,
maxWriteSize: maxPacketSize - 1,
}
- mc.cfg, err = parseDSN(dsn)
+ mc.cfg, err = ParseDSN(dsn)
if err != nil {
return nil, err
}
+ mc.parseTime = mc.cfg.ParseTime
+ mc.strict = mc.cfg.Strict
// Connect to Server
- if dial, ok := dials[mc.cfg.net]; ok {
- mc.netConn, err = dial(mc.cfg.addr)
+ if dial, ok := dials[mc.cfg.Net]; ok {
+ mc.netConn, err = dial(mc.cfg.Addr)
} else {
- nd := net.Dialer{Timeout: mc.cfg.timeout}
- mc.netConn, err = nd.Dial(mc.cfg.net, mc.cfg.addr)
+ nd := net.Dialer{Timeout: mc.cfg.Timeout}
+ mc.netConn, err = nd.Dial(mc.cfg.Net, mc.cfg.Addr)
}
if err != nil {
return nil, err
@@ -72,55 +74,54 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
// Enable TCP Keepalives on TCP connections
if tc, ok := mc.netConn.(*net.TCPConn); ok {
if err := tc.SetKeepAlive(true); err != nil {
- mc.Close()
+ // Don't send COM_QUIT before handshake.
+ mc.netConn.Close()
+ mc.netConn = nil
return nil, err
}
}
mc.buf = newBuffer(mc.netConn)
+ // Set I/O timeouts
+ mc.buf.timeout = mc.cfg.ReadTimeout
+ mc.writeTimeout = mc.cfg.WriteTimeout
+
// Reading Handshake Initialization Packet
cipher, err := mc.readInitPacket()
if err != nil {
- mc.Close()
+ mc.cleanup()
return nil, err
}
// Send Client Authentication Packet
if err = mc.writeAuthPacket(cipher); err != nil {
- mc.Close()
+ mc.cleanup()
return nil, err
}
- // Read Result Packet
- err = mc.readResultOK()
- if err != nil {
- // Retry with old authentication method, if allowed
- if mc.cfg != nil && mc.cfg.allowOldPasswords && err == ErrOldPassword {
- if err = mc.writeOldAuthPacket(cipher); err != nil {
- mc.Close()
- return nil, err
- }
- if err = mc.readResultOK(); err != nil {
- mc.Close()
- return nil, err
- }
- } else {
+ // Handle response to auth packet, switch methods if possible
+ if err = handleAuthResult(mc, cipher); err != nil {
+ // Authentication failed and MySQL has already closed the connection
+ // (https://dev.mysql.com/doc/internals/en/authentication-fails.html).
+ // Do not send COM_QUIT, just cleanup and return the error.
+ mc.cleanup()
+ return nil, err
+ }
+
+ if mc.cfg.MaxAllowedPacket > 0 {
+ mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket
+ } else {
+ // Get max allowed packet size
+ maxap, err := mc.getSystemVar("max_allowed_packet")
+ if err != nil {
mc.Close()
return nil, err
}
-
- }
-
- // Get max allowed packet size
- maxap, err := mc.getSystemVar("max_allowed_packet")
- if err != nil {
- mc.Close()
- return nil, err
+ mc.maxAllowedPacket = stringToInt(maxap) - 1
}
- mc.maxPacketAllowed = stringToInt(maxap) - 1
- if mc.maxPacketAllowed < maxPacketSize {
- mc.maxWriteSize = mc.maxPacketAllowed
+ if mc.maxAllowedPacket < maxPacketSize {
+ mc.maxWriteSize = mc.maxAllowedPacket
}
// Handle DSN Params
@@ -133,6 +134,50 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
return mc, nil
}
+func handleAuthResult(mc *mysqlConn, oldCipher []byte) error {
+ // Read Result Packet
+ cipher, err := mc.readResultOK()
+ if err == nil {
+ return nil // auth successful
+ }
+
+ if mc.cfg == nil {
+ return err // auth failed and retry not possible
+ }
+
+ // Retry auth if configured to do so.
+ if mc.cfg.AllowOldPasswords && err == ErrOldPassword {
+ // Retry with old authentication method. Note: there are edge cases
+ // where this should work but doesn't; this is currently "wontfix":
+ // https://github.com/go-sql-driver/mysql/issues/184
+
+ // If CLIENT_PLUGIN_AUTH capability is not supported, no new cipher is
+ // sent and we have to keep using the cipher sent in the init packet.
+ if cipher == nil {
+ cipher = oldCipher
+ }
+
+ if err = mc.writeOldAuthPacket(cipher); err != nil {
+ return err
+ }
+ _, err = mc.readResultOK()
+ } else if mc.cfg.AllowCleartextPasswords && err == ErrCleartextPassword {
+ // Retry with clear text password for
+ // http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html
+ // http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html
+ if err = mc.writeClearAuthPacket(); err != nil {
+ return err
+ }
+ _, err = mc.readResultOK()
+ } else if mc.cfg.AllowNativePasswords && err == ErrNativePassword {
+ if err = mc.writeNativeAuthPacket(cipher); err != nil {
+ return err
+ }
+ _, err = mc.readResultOK()
+ }
+ return err
+}
+
func init() {
sql.Register("mysql", &MySQLDriver{})
}