From 2fff64512910bca945869f9f2075f42b43759772 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 Mar 2020 22:38:38 +0100 Subject: [PATCH] Stop accessing user data in downstreamConn.authenticate This becomes racy once user.Password is updated on-the-fly. --- db.go | 15 +++++++++++++++ downstream.go | 20 ++++++++++++-------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/db.go b/db.go index d67fca9..9cac960 100644 --- a/db.go +++ b/db.go @@ -106,6 +106,21 @@ func (db *DB) ListUsers() ([]User, error) { return users, nil } +func (db *DB) GetUser(username string) (*User, error) { + db.lock.RLock() + defer db.lock.RUnlock() + + user := &User{Username: username} + + var password *string + row := db.db.QueryRow("SELECT password FROM User WHERE username = ?", username) + if err := row.Scan(&password); err != nil { + return nil, err + } + user.Password = fromStringPtr(password) + return user, nil +} + func (db *DB) CreateUser(user *User) error { db.lock.Lock() defer db.lock.Unlock() diff --git a/downstream.go b/downstream.go index e7fb6d4..006a14f 100644 --- a/downstream.go +++ b/downstream.go @@ -586,19 +586,23 @@ func unmarshalUsername(rawUsername string) (username, network string) { func (dc *downstreamConn) authenticate(username, password string) error { username, networkName := unmarshalUsername(username) - u := dc.srv.getUser(username) - if u == nil { - dc.logger.Printf("failed authentication for %q: unknown username", username) - return errAuthFailed - } - - err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) + u, err := dc.srv.db.GetUser(username) if err != nil { dc.logger.Printf("failed authentication for %q: %v", username, err) return errAuthFailed } - dc.user = u + err = bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) + if err != nil { + dc.logger.Printf("failed authentication for %q: %v", username, err) + return errAuthFailed + } + + dc.user = dc.srv.getUser(username) + if dc.user == nil { + dc.logger.Printf("failed authentication for %q: user not active", username) + return errAuthFailed + } dc.networkName = networkName return nil }