summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-sql-driver/mysql/utils.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-sql-driver/mysql/utils.go')
-rw-r--r--vendor/github.com/go-sql-driver/mysql/utils.go214
1 files changed, 92 insertions, 122 deletions
diff --git a/vendor/github.com/go-sql-driver/mysql/utils.go b/vendor/github.com/go-sql-driver/mysql/utils.go
index d523b7ffdf..84d595b6ba 100644
--- a/vendor/github.com/go-sql-driver/mysql/utils.go
+++ b/vendor/github.com/go-sql-driver/mysql/utils.go
@@ -9,23 +9,29 @@
package mysql
import (
- "crypto/sha1"
"crypto/tls"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"strings"
+ "sync"
+ "sync/atomic"
"time"
)
+// Registry for custom tls.Configs
var (
- tlsConfigRegister map[string]*tls.Config // Register for custom tls.Configs
+ tlsConfigLock sync.RWMutex
+ tlsConfigRegistry map[string]*tls.Config
)
// RegisterTLSConfig registers a custom tls.Config to be used with sql.Open.
// Use the key as a value in the DSN where tls=value.
//
+// Note: The provided tls.Config is exclusively owned by the driver after
+// registering it.
+//
// rootCertPool := x509.NewCertPool()
// pem, err := ioutil.ReadFile("/path/ca-cert.pem")
// if err != nil {
@@ -51,19 +57,32 @@ func RegisterTLSConfig(key string, config *tls.Config) error {
return fmt.Errorf("key '%s' is reserved", key)
}
- if tlsConfigRegister == nil {
- tlsConfigRegister = make(map[string]*tls.Config)
+ tlsConfigLock.Lock()
+ if tlsConfigRegistry == nil {
+ tlsConfigRegistry = make(map[string]*tls.Config)
}
- tlsConfigRegister[key] = config
+ tlsConfigRegistry[key] = config
+ tlsConfigLock.Unlock()
return nil
}
// DeregisterTLSConfig removes the tls.Config associated with key.
func DeregisterTLSConfig(key string) {
- if tlsConfigRegister != nil {
- delete(tlsConfigRegister, key)
+ tlsConfigLock.Lock()
+ if tlsConfigRegistry != nil {
+ delete(tlsConfigRegistry, key)
}
+ tlsConfigLock.Unlock()
+}
+
+func getTLSConfigClone(key string) (config *tls.Config) {
+ tlsConfigLock.RLock()
+ if v, ok := tlsConfigRegistry[key]; ok {
+ config = cloneTLSConfig(v)
+ }
+ tlsConfigLock.RUnlock()
+ return
}
// Returns the bool value of the input.
@@ -81,119 +100,6 @@ func readBool(input string) (value bool, valid bool) {
}
/******************************************************************************
-* Authentication *
-******************************************************************************/
-
-// Encrypt password using 4.1+ method
-func scramblePassword(scramble, password []byte) []byte {
- if len(password) == 0 {
- return nil
- }
-
- // stage1Hash = SHA1(password)
- crypt := sha1.New()
- crypt.Write(password)
- stage1 := crypt.Sum(nil)
-
- // scrambleHash = SHA1(scramble + SHA1(stage1Hash))
- // inner Hash
- crypt.Reset()
- crypt.Write(stage1)
- hash := crypt.Sum(nil)
-
- // outer Hash
- crypt.Reset()
- crypt.Write(scramble)
- crypt.Write(hash)
- scramble = crypt.Sum(nil)
-
- // token = scrambleHash XOR stage1Hash
- for i := range scramble {
- scramble[i] ^= stage1[i]
- }
- return scramble
-}
-
-// 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
-
-// Pseudo random number generator
-func newMyRnd(seed1, seed2 uint32) *myRnd {
- return &myRnd{
- seed1: seed1 % myRndMaxVal,
- seed2: seed2 % myRndMaxVal,
- }
-}
-
-// Tested to be equivalent to MariaDB's floating point variant
-// http://play.golang.org/p/QHvhd4qved
-// http://play.golang.org/p/RG0q4ElWDx
-func (r *myRnd) NextByte() byte {
- r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal
- r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal
-
- return byte(uint64(r.seed1) * 31 / myRndMaxVal)
-}
-
-// Generate binary hash from byte string using insecure pre 4.1 method
-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
- }
-
- // Remove sign bit (1<<31)-1)
- result[0] &= 0x7FFFFFFF
- result[1] &= 0x7FFFFFFF
-
- return
-}
-
-// Encrypt password using insecure pre 4.1 method
-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] = r.NextByte() + 64
- }
-
- mask := r.NextByte()
- for i := range out {
- out[i] ^= mask
- }
-
- return out[:]
-}
-
-/******************************************************************************
* Time related utils *
******************************************************************************/
@@ -519,7 +425,7 @@ func readLengthEncodedString(b []byte) ([]byte, bool, int, error) {
// Check data length
if len(b) >= n {
- return b[n-int(num) : n], false, n, nil
+ return b[n-int(num) : n : n], false, n, nil
}
return nil, false, n, io.EOF
}
@@ -548,8 +454,8 @@ func readLengthEncodedInteger(b []byte) (uint64, bool, int) {
if len(b) == 0 {
return 0, true, 1
}
- switch b[0] {
+ switch b[0] {
// 251: NULL
case 0xfb:
return 0, true, 1
@@ -738,3 +644,67 @@ func escapeStringQuotes(buf []byte, v string) []byte {
return buf[:pos]
}
+
+/******************************************************************************
+* Sync utils *
+******************************************************************************/
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://github.com/golang/go/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock() {}
+
+// atomicBool is a wrapper around uint32 for usage as a boolean value with
+// atomic access.
+type atomicBool struct {
+ _noCopy noCopy
+ value uint32
+}
+
+// IsSet returns wether the current boolean value is true
+func (ab *atomicBool) IsSet() bool {
+ return atomic.LoadUint32(&ab.value) > 0
+}
+
+// Set sets the value of the bool regardless of the previous value
+func (ab *atomicBool) Set(value bool) {
+ if value {
+ atomic.StoreUint32(&ab.value, 1)
+ } else {
+ atomic.StoreUint32(&ab.value, 0)
+ }
+}
+
+// TrySet sets the value of the bool and returns wether the value changed
+func (ab *atomicBool) TrySet(value bool) bool {
+ if value {
+ return atomic.SwapUint32(&ab.value, 1) == 0
+ }
+ return atomic.SwapUint32(&ab.value, 0) > 0
+}
+
+// atomicError is a wrapper for atomically accessed error values
+type atomicError struct {
+ _noCopy noCopy
+ value atomic.Value
+}
+
+// Set sets the error value regardless of the previous value.
+// The value must not be nil
+func (ae *atomicError) Set(value error) {
+ ae.value.Store(value)
+}
+
+// Value returns the current error value
+func (ae *atomicError) Value() error {
+ if v := ae.value.Load(); v != nil {
+ // this will panic if the value doesn't implement the error interface
+ return v.(error)
+ }
+ return nil
+}