Skip to content

Commit b03abe2

Browse files
theniksojulienschmidt
authored andcommitted
Added support for old_password authentication method
1 parent 9786892 commit b03abe2

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

packets.go

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,29 @@ func (mc *mysqlConn) writeAuthPacket() error {
307307
return mc.writePacket(data)
308308
}
309309

310+
// Client old authentication packet
311+
// http://dev.mysql.com/doc/internals/en/connection-phase.html#packet-Protocol::AuthSwitchResponse
312+
func (mc *mysqlConn) writeOldAuthPacket() error {
313+
// User password
314+
scrambleBuff := scrambleOldPassword(mc.cipher, []byte(mc.cfg.passwd))
315+
mc.cipher = nil
316+
317+
// Calculate the packet lenght and add a tailing 0
318+
pktLen := len(scrambleBuff) + 1
319+
data := make([]byte, pktLen+4)
320+
321+
// Add the packet header [24bit length + 1 byte sequence]
322+
data[0] = byte(pktLen)
323+
data[1] = byte(pktLen >> 8)
324+
data[2] = byte(pktLen >> 16)
325+
data[3] = mc.sequence
326+
327+
// Add the scrambled password (it will be terminated by 0)
328+
copy(data[4:], scrambleBuff)
329+
330+
return mc.writePacket(data)
331+
}
332+
310333
/******************************************************************************
311334
* Command Packets *
312335
******************************************************************************/
@@ -388,8 +411,13 @@ func (mc *mysqlConn) readResultOK() error {
388411
case iOK:
389412
return mc.handleOkPacket(data)
390413

391-
case iEOF: // someone is using old_passwords
392-
return errOldPassword
414+
case iEOF:
415+
// someone is using old_passwords
416+
err = mc.writeOldAuthPacket()
417+
if err != nil {
418+
return err
419+
}
420+
return mc.readResultOK()
393421

394422
default: // Error otherwise
395423
return mc.handleErrorPacket(data)

utils.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"fmt"
1818
"io"
1919
"log"
20+
"math"
2021
"os"
2122
"regexp"
2223
"strings"
@@ -213,6 +214,67 @@ func scramblePassword(scramble, password []byte) []byte {
213214
return scramble
214215
}
215216

217+
// Encrypt password using pre 4.1 (old password) method
218+
// https://github.com/atcurtis/mariadb/blob/master/mysys/my_rnd.c
219+
type myRnd struct {
220+
seed1, seed2 uint32
221+
}
222+
223+
const myRndMaxVal = 0x3FFFFFFF
224+
225+
func newMyRnd(seed1, seed2 uint32) *myRnd {
226+
r := new(myRnd)
227+
r.seed1 = seed1 % myRndMaxVal
228+
r.seed2 = seed2 % myRndMaxVal
229+
return r
230+
}
231+
232+
func (r *myRnd) Float64() float64 {
233+
r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal
234+
r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal
235+
return float64(r.seed1) / myRndMaxVal
236+
}
237+
238+
// https://github.com/atcurtis/mariadb/blob/master/sql/password.c
239+
func pwHash(password []byte) (result [2]uint32) {
240+
var nr, add, nr2, tmp uint32
241+
nr, add, nr2 = 1345345333, 7, 0x12345671
242+
243+
for _, c := range password {
244+
if c == ' ' || c == '\t' {
245+
continue // skip space in password
246+
}
247+
248+
tmp = uint32(c)
249+
nr ^= (((nr & 63) + add) * tmp) + (nr << 8)
250+
nr2 += (nr2 << 8) ^ nr
251+
add += tmp
252+
}
253+
254+
result[0] = nr & ((1 << 31) - 1) // Don't use sign bit (str2int)
255+
result[1] = nr2 & ((1 << 31) - 1)
256+
return
257+
}
258+
259+
func scrambleOldPassword(scramble, password []byte) []byte {
260+
if len(password) == 0 {
261+
return nil
262+
}
263+
scramble = scramble[:8]
264+
hashPw := pwHash(password)
265+
hashSc := pwHash(scramble)
266+
r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1])
267+
var out [8]byte
268+
for i := range out {
269+
out[i] = byte(math.Floor(r.Float64()*31) + 64)
270+
}
271+
extra := byte(math.Floor(r.Float64() * 31))
272+
for i := range out {
273+
out[i] ^= extra
274+
}
275+
return out[:]
276+
}
277+
216278
// Returns the bool value of the input.
217279
// The 2nd return value indicates if the input was a valid bool value
218280
func readBool(input string) (value bool, valid bool) {

0 commit comments

Comments
 (0)