-
Notifications
You must be signed in to change notification settings - Fork 2.3k
old_passwords support #124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
b03abe2
e78fff0
83ed16b
0bc514d
ff8fee6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ import ( | |
"fmt" | ||
"io" | ||
"log" | ||
"math" | ||
"os" | ||
"regexp" | ||
"strings" | ||
|
@@ -125,6 +126,15 @@ func parseDSN(dsn string) (cfg *config, err error) { | |
return | ||
} | ||
|
||
// Use old authentication mode (pre MySQL 4.1) | ||
case "allowOldPasswords": | ||
var isBool bool | ||
cfg.allowOldPasswords, isBool = readBool(value) | ||
if !isBool { | ||
err = fmt.Errorf("Invalid Bool value: %s", value) | ||
return | ||
} | ||
|
||
// Time Location | ||
case "loc": | ||
cfg.loc, err = time.LoadLocation(value) | ||
|
@@ -182,6 +192,24 @@ func parseDSN(dsn string) (cfg *config, err error) { | |
return | ||
} | ||
|
||
// Returns the bool value of the input. | ||
// The 2nd return value indicates if the input was a valid bool value | ||
func readBool(input string) (value bool, valid bool) { | ||
switch input { | ||
case "1", "true", "TRUE", "True": | ||
return true, true | ||
case "0", "false", "FALSE", "False": | ||
return false, true | ||
} | ||
|
||
// Not a valid bool value | ||
return | ||
} | ||
|
||
/****************************************************************************** | ||
* Authentication * | ||
******************************************************************************/ | ||
|
||
// Encrypt password using 4.1+ method | ||
// http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#4.1_and_later | ||
func scramblePassword(scramble, password []byte) []byte { | ||
|
@@ -213,20 +241,76 @@ func scramblePassword(scramble, password []byte) []byte { | |
return scramble | ||
} | ||
|
||
// Returns the bool value of the input. | ||
// The 2nd return value indicates if the input was a valid bool value | ||
func readBool(input string) (value bool, valid bool) { | ||
switch input { | ||
case "1", "true", "TRUE", "True": | ||
return true, true | ||
case "0", "false", "FALSE", "False": | ||
return false, true | ||
// Encrypt password using pre 4.1 (old password) method | ||
// https://github.com/atcurtis/mariadb/blob/master/mysys/my_rnd.c | ||
type myRnd struct { | ||
seed1, seed2 uint32 | ||
} | ||
|
||
const myRndMaxVal = 0x3FFFFFFF | ||
|
||
func newMyRnd(seed1, seed2 uint32) *myRnd { | ||
r := new(myRnd) | ||
r.seed1 = seed1 % myRndMaxVal | ||
r.seed2 = seed2 % myRndMaxVal | ||
return r | ||
} | ||
|
||
func (r *myRnd) Float64() float64 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is only used with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tested and works as intended: |
||
r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal | ||
r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal | ||
return float64(r.seed1) / myRndMaxVal | ||
} | ||
|
||
func pwHash(password []byte) (result [2]uint32) { | ||
var add uint32 = 7 | ||
var tmp uint32 | ||
|
||
result[0] = 1345345333 | ||
result[1] = 0x12345671 | ||
|
||
for _, c := range password { | ||
// skip spaces and tabs in password | ||
if c == ' ' || c == '\t' { | ||
continue | ||
} | ||
|
||
tmp = uint32(c) | ||
result[0] ^= (((result[0] & 63) + add) * tmp) + (result[0] << 8) | ||
result[1] += (result[1] << 8) ^ result[0] | ||
add += tmp | ||
} | ||
|
||
// Not a valid bool value | ||
result[0] &= (1 << 31) - 1 // Don't use sign bit (str2int) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As this is not uint but uint32, I think |
||
result[1] &= (1 << 31) - 1 | ||
return | ||
} | ||
|
||
func scrambleOldPassword(scramble, password []byte) []byte { | ||
if len(password) == 0 { | ||
return nil | ||
} | ||
|
||
scramble = scramble[:8] | ||
|
||
hashPw := pwHash(password) | ||
hashSc := pwHash(scramble) | ||
|
||
r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1]) | ||
|
||
var out [8]byte | ||
for i := range out { | ||
out[i] = byte(math.Floor(r.Float64()*31) + 64) | ||
} | ||
|
||
mask := byte(math.Floor(r.Float64() * 31)) | ||
for i := range out { | ||
out[i] ^= mask | ||
} | ||
|
||
return out[:] | ||
} | ||
|
||
/****************************************************************************** | ||
* Time related utils * | ||
******************************************************************************/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not like this?