Add support for user authentication and also server password authentication

This commit is contained in:
Ola Bini 2020-01-13 18:03:11 +00:00
parent db518d7b16
commit d24046b1b7
No known key found for this signature in database
GPG key ID: 6786A150F6A2B28F

View file

@ -10,6 +10,7 @@ import (
"context" "context"
"crypto/rand" "crypto/rand"
"crypto/sha1" "crypto/sha1"
"crypto/sha256"
"crypto/tls" "crypto/tls"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
@ -175,8 +176,7 @@ func (server *Server) RootChannel() *Channel {
return root return root
} }
// Set password as the new SuperUser password func (server *Server) setConfigPassword(key, password string) {
func (server *Server) SetSuperUserPassword(password string) {
saltBytes := make([]byte, 24) saltBytes := make([]byte, 24)
_, err := rand.Read(saltBytes) _, err := rand.Read(saltBytes)
if err != nil { if err != nil {
@ -190,15 +190,23 @@ func (server *Server) SetSuperUserPassword(password string) {
digest := hex.EncodeToString(hasher.Sum(nil)) digest := hex.EncodeToString(hasher.Sum(nil))
// Could be racy, but shouldn't really matter... // Could be racy, but shouldn't really matter...
key := "SuperUserPassword"
val := "sha1$" + salt + "$" + digest val := "sha1$" + salt + "$" + digest
server.cfg.Set(key, val) server.cfg.Set(key, val)
server.cfgUpdate <- &KeyValuePair{Key: key, Value: val} server.cfgUpdate <- &KeyValuePair{Key: key, Value: val}
} }
// CheckSuperUserPassword checks whether password matches the set SuperUser password. // Set password as the new SuperUser password
func (server *Server) CheckSuperUserPassword(password string) bool { func (server *Server) SetSuperUserPassword(password string) {
parts := strings.Split(server.cfg.StringValue("SuperUserPassword"), "$") server.setConfigPassword("SuperUserPassword", password)
}
// Set password as the new Server password
func (server *Server) SetServerPassword(password string) {
server.setConfigPassword("ServerPassword", password)
}
func (server *Server) checkPassword(key, password string) bool {
parts := strings.Split(server.cfg.StringValue(key), "$")
if len(parts) != 3 { if len(parts) != 3 {
return false return false
} }
@ -236,6 +244,11 @@ func (server *Server) CheckSuperUserPassword(password string) bool {
return false return false
} }
// CheckSuperUserPassword checks whether password matches the set SuperUser password.
func (server *Server) CheckSuperUserPassword(password string) bool {
return server.checkPassword("SuperUserPassword", password)
}
// Called by the server to initiate a new client connection. // Called by the server to initiate a new client connection.
func (server *Server) handleIncomingClient(conn net.Conn) (err error) { func (server *Server) handleIncomingClient(conn net.Conn) (err error) {
client := new(Client) client := new(Client)
@ -439,6 +452,20 @@ func (server *Server) handlerLoop() {
} }
} }
func constantTimeEqual(s1, s2 string) bool {
one := sha256.Sum256([]byte(s1))
two := sha256.Sum256([]byte(s2))
return bytes.Compare(one[:], two[:]) == 0
}
func (server *Server) hasServerPassword() bool {
return server.cfg.StringValue("ServerPassword") != ""
}
func (server *Server) checkServerPassword(password string) bool {
return server.checkPassword("ServerPassword", password)
}
// Handle an Authenticate protobuf message. This is handled in a separate // Handle an Authenticate protobuf message. This is handled in a separate
// goroutine to allow for remote authenticators that are slow to respond. // goroutine to allow for remote authenticators that are slow to respond.
// //
@ -498,12 +525,16 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
// First look up registration by name. // First look up registration by name.
user, exists := server.UserNameMap[client.Username] user, exists := server.UserNameMap[client.Username]
if exists { if exists {
if client.HasCertificate() && user.CertHash == client.CertHash() { if client.HasCertificate() {
client.user = user if user.CertHash != client.CertHash() {
} else { client.RejectAuth(mumbleproto.Reject_WrongUserPW, "Wrong certificate or password for existing user")
client.RejectAuth(mumbleproto.Reject_WrongUserPW, "Wrong certificate hash") return
}
} else if *auth.Password != "" && user.Password != "" && !constantTimeEqual(*auth.Password, user.Password) {
client.RejectAuth(mumbleproto.Reject_WrongUserPW, "Wrong certificate or password for existing user")
return return
} }
client.user = user
} }
// Name matching didn't do. Try matching by certificate. // Name matching didn't do. Try matching by certificate.
@ -515,6 +546,18 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
} }
} }
if client.user == nil && server.hasServerPassword() {
if auth.Password == nil {
client.RejectAuth(mumbleproto.Reject_WrongServerPW, "Invalid server password")
return
} else {
if !server.checkServerPassword(*auth.Password) {
client.RejectAuth(mumbleproto.Reject_WrongServerPW, "Invalid server password")
return
}
}
}
// Setup the cryptstate for the client. // Setup the cryptstate for the client.
err = client.crypt.GenerateKey(client.CryptoMode) err = client.crypt.GenerateKey(client.CryptoMode)
if err != nil { if err != nil {