@@ -84,43 +84,23 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
8484 // Reading Handshake Initialization Packet
8585 cipher , err := mc .readInitPacket ()
8686 if err != nil {
87- mc .Close ()
87+ mc .cleanup ()
8888 return nil , err
8989 }
9090
9191 // Send Client Authentication Packet
9292 if err = mc .writeAuthPacket (cipher ); err != nil {
93- mc .Close ()
93+ mc .cleanup ()
9494 return nil , err
9595 }
9696
97- // Read Result Packet
98- err = mc .readResultOK ()
99- if err != nil {
100- // Retry with old authentication method, if allowed
101- if mc .cfg != nil && mc .cfg .allowOldPasswords && err == ErrOldPassword {
102- if err = mc .writeOldAuthPacket (cipher ); err != nil {
103- mc .Close ()
104- return nil , err
105- }
106- if err = mc .readResultOK (); err != nil {
107- mc .Close ()
108- return nil , err
109- }
110- } else if mc .cfg != nil && mc .cfg .allowCleartextPasswords && err == ErrCleartextPassword {
111- if err = mc .writeClearAuthPacket (); err != nil {
112- mc .Close ()
113- return nil , err
114- }
115- if err = mc .readResultOK (); err != nil {
116- mc .Close ()
117- return nil , err
118- }
119- } else {
120- mc .Close ()
121- return nil , err
122- }
123-
97+ // Handle response to auth packet, switch methods if possible
98+ if err = handleAuthResult (mc , cipher ); err != nil {
99+ // Authentication failed and MySQL has already closed the connection
100+ // (https://dev.mysql.com/doc/internals/en/authentication-fails.html).
101+ // Do not send COM_QUIT, just cleanup and return the error.
102+ mc .cleanup ()
103+ return nil , err
124104 }
125105
126106 // Get max allowed packet size
@@ -144,6 +124,38 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
144124 return mc , nil
145125}
146126
127+ func handleAuthResult (mc * mysqlConn , cipher []byte ) error {
128+ // Read Result Packet
129+ err := mc .readResultOK ()
130+ if err == nil {
131+ return nil // auth successful
132+ }
133+
134+ if mc .cfg == nil {
135+ return err // auth failed and retry not possible
136+ }
137+
138+ // Retry auth if configured to do so.
139+ if mc .cfg .allowOldPasswords && err == ErrOldPassword {
140+ // Retry with old authentication method. Note: there are edge cases
141+ // where this should work but doesn't; this is currently "wontfix":
142+ // https://github.com/go-sql-driver/mysql/issues/184
143+ if err = mc .writeOldAuthPacket (cipher ); err != nil {
144+ return err
145+ }
146+ err = mc .readResultOK ()
147+ } else if mc .cfg .allowCleartextPasswords && err == ErrCleartextPassword {
148+ // Retry with clear text password for
149+ // http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html
150+ // http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html
151+ if err = mc .writeClearAuthPacket (); err != nil {
152+ return err
153+ }
154+ err = mc .readResultOK ()
155+ }
156+ return err
157+ }
158+
147159func init () {
148160 sql .Register ("mysql" , & MySQLDriver {})
149161}
0 commit comments