app-init
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
package mysqlserver
|
||||
|
||||
import "crypto/rand"
|
||||
|
||||
func buildHandshake(connID uint32, scramble []byte) []byte {
|
||||
if len(scramble) < 20 {
|
||||
s := make([]byte, 20)
|
||||
copy(s, scramble)
|
||||
scramble = s
|
||||
}
|
||||
b := []byte{ProtocolVersion}
|
||||
b = appendNUL(b, ServerVersion)
|
||||
b = appendU32(b, connID)
|
||||
b = append(b, scramble[:8]...)
|
||||
b = append(b, 0x00)
|
||||
b = appendU16(b, uint16(serverCapabilities))
|
||||
b = append(b, charsetUTF8MB4)
|
||||
b = appendU16(b, serverStatusAutocommit)
|
||||
b = appendU16(b, uint16(serverCapabilities>>16))
|
||||
b = append(b, 21) // auth plugin data len: 20 bytes + NUL
|
||||
b = append(b, make([]byte, 10)...)
|
||||
b = append(b, scramble[8:20]...)
|
||||
b = append(b, 0x00)
|
||||
b = appendNUL(b, AuthPluginNative)
|
||||
return b
|
||||
}
|
||||
|
||||
func randomScramble() ([]byte, error) {
|
||||
s := make([]byte, 20)
|
||||
if _, err := rand.Read(s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i, c := range s {
|
||||
if c == 0 {
|
||||
s[i] = 1
|
||||
}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type handshakeResponse struct {
|
||||
Capabilities uint32
|
||||
MaxPacket uint32
|
||||
Charset byte
|
||||
Username string
|
||||
Auth []byte
|
||||
Database string
|
||||
Plugin string
|
||||
SSL bool
|
||||
}
|
||||
|
||||
func parseHandshakeResponse(payload []byte) (handshakeResponse, error) {
|
||||
var hr handshakeResponse
|
||||
if len(payload) < 32 {
|
||||
return hr, errPacket("handshake response too short")
|
||||
}
|
||||
hr.Capabilities = uint32(payload[0]) | uint32(payload[1])<<8 | uint32(payload[2])<<16 | uint32(payload[3])<<24
|
||||
hr.MaxPacket = uint32(payload[4]) | uint32(payload[5])<<8 | uint32(payload[6])<<16 | uint32(payload[7])<<24
|
||||
hr.Charset = payload[8]
|
||||
hr.SSL = hr.Capabilities&clientSSL != 0
|
||||
if hr.SSL && len(payload) <= 32 {
|
||||
return hr, nil
|
||||
}
|
||||
if hr.Capabilities&clientProtocol41 == 0 {
|
||||
return hr, errPacket("CLIENT_PROTOCOL_41 required")
|
||||
}
|
||||
off := 32
|
||||
user, off, err := readNUL(payload, off)
|
||||
if err != nil {
|
||||
return hr, err
|
||||
}
|
||||
hr.Username = user
|
||||
|
||||
switch {
|
||||
case hr.Capabilities&clientPluginAuthLenencClientData != 0:
|
||||
n, nOff, err := readLenencInt(payload, off)
|
||||
if err != nil {
|
||||
return hr, err
|
||||
}
|
||||
off = nOff
|
||||
end := off + int(n)
|
||||
if end > len(payload) {
|
||||
return hr, errPacket("auth-response truncated")
|
||||
}
|
||||
hr.Auth = append([]byte(nil), payload[off:end]...)
|
||||
off = end
|
||||
case hr.Capabilities&clientSecureConnection != 0:
|
||||
if off >= len(payload) {
|
||||
return hr, errPacket("auth-response truncated")
|
||||
}
|
||||
n := int(payload[off])
|
||||
off++
|
||||
end := off + n
|
||||
if end > len(payload) {
|
||||
return hr, errPacket("auth-response truncated")
|
||||
}
|
||||
hr.Auth = append([]byte(nil), payload[off:end]...)
|
||||
off = end
|
||||
default:
|
||||
s, nOff, err := readNUL(payload, off)
|
||||
if err != nil {
|
||||
return hr, err
|
||||
}
|
||||
hr.Auth = []byte(s)
|
||||
off = nOff
|
||||
}
|
||||
|
||||
if hr.Capabilities&clientConnectWithDB != 0 && off < len(payload) {
|
||||
db, nOff, err := readNUL(payload, off)
|
||||
if err != nil {
|
||||
return hr, err
|
||||
}
|
||||
hr.Database = db
|
||||
off = nOff
|
||||
}
|
||||
if hr.Capabilities&clientPluginAuth != 0 && off < len(payload) {
|
||||
plugin, _, err := readNUL(payload, off)
|
||||
if err != nil {
|
||||
return hr, err
|
||||
}
|
||||
hr.Plugin = plugin
|
||||
}
|
||||
return hr, nil
|
||||
}
|
||||
|
||||
func encodeAuthSwitch(plugin string, scramble []byte) []byte {
|
||||
b := []byte{markerEOF} // 0xFE AuthSwitchRequest
|
||||
b = appendNUL(b, plugin)
|
||||
b = append(b, scramble...)
|
||||
b = append(b, 0x00)
|
||||
return b
|
||||
}
|
||||
|
||||
type protoError struct{ s string }
|
||||
|
||||
func (e protoError) Error() string { return e.s }
|
||||
|
||||
func errPacket(s string) error { return protoError{s} }
|
||||
Reference in New Issue
Block a user