From 5b1cfd14f1b8321df8185a483e1893a229f3214f Mon Sep 17 00:00:00 2001 From: Mikkel Krautz Date: Thu, 19 May 2011 23:37:02 +0200 Subject: [PATCH] Add SetSuperUserPassword ctl option. --- ctl.go | 20 ++++++++++++++++---- ctlrpc.go | 24 +++++++++++++++++------- freeze.go | 2 -- murmurdb.go | 6 ++++-- server.go | 36 +++++++++++++++++++++++++++++------- 5 files changed, 66 insertions(+), 22 deletions(-) diff --git a/ctl.go b/ctl.go index c2865d7..d2e4df5 100644 --- a/ctl.go +++ b/ctl.go @@ -21,6 +21,9 @@ var CtlUsage = `grumble ctl stop [id] Stop a server + supw [id] [password] + Set the SuperUser password for server with id + setconf [id] [key] [value] Set a config value for server with id @@ -56,12 +59,21 @@ func GrumbleCtl(args []string) { log.Fatalf("Unable to stop: %v", err) } log.Printf("[%v] Stopped", sid) + case "supw": + if len(args) < 3 { + return + } + err := client.Call("ctl.SetSuperUserPassword", &KeyValuePair{sid, "", args[2]}, nil) + if err != nil { + log.Fatalf("Unable to set SuperUser password: %v", err) + } + log.Printf("[%v] Set SuperUser password", sid) case "setconf": if len(args) < 4 { return } - result := &ConfigValue{} - err := client.Call("ctl.SetConfig", &ConfigValue{sid, args[2], args[3]}, result) + result := &KeyValuePair{} + err := client.Call("ctl.SetConfig", &KeyValuePair{sid, args[2], args[3]}, result) if err != nil { log.Fatalf("Unable to set config: %v", err) } @@ -70,8 +82,8 @@ func GrumbleCtl(args []string) { if len(args) < 3 { return } - result := &ConfigValue{} - err := client.Call("ctl.GetConfig", &ConfigValue{sid, args[2], ""}, result) + result := &KeyValuePair{} + err := client.Call("ctl.GetConfig", &KeyValuePair{sid, args[2], ""}, result) if err != nil { log.Fatalf("Unable to get config: %v", err) } diff --git a/ctlrpc.go b/ctlrpc.go index 0b930bb..ae6055b 100644 --- a/ctlrpc.go +++ b/ctlrpc.go @@ -9,11 +9,16 @@ import ( ) type ControlRPC struct { +} +type KeyValuePair struct { + Id int64 + Key string + Value string } // Start a server -func (c *ControlRPC) Start(Id int64, out *int) os.Error { +func (c *ControlRPC) Start(Id int64, out *int64) os.Error { server, exists := servers[Id] if !exists { return os.NewError("no such server") @@ -32,14 +37,19 @@ func (c *ControlRPC) Stop(Id int64, out *int) os.Error { return nil } -type ConfigValue struct { - Id int64 - Key string - Value string +// Set SuperUser password +func (c *ControlRPC) SetSuperUserPassword(in *KeyValuePair, out *int64) os.Error { + server, exists := servers[in.Id] + if !exists { + return os.NewError("no such server") + } + server.SetSuperUserPassword(in.Value) + *out = in.Id + return nil } // Set a config value -func (c *ControlRPC) SetConfig(in *ConfigValue, out *ConfigValue) os.Error { +func (c *ControlRPC) SetConfig(in *KeyValuePair, out *KeyValuePair) os.Error { server, exists := servers[in.Id] if !exists { return os.NewError("no such server") @@ -52,7 +62,7 @@ func (c *ControlRPC) SetConfig(in *ConfigValue, out *ConfigValue) os.Error { } // Get a config value -func (c *ControlRPC) GetConfig(in *ConfigValue, out *ConfigValue) os.Error { +func (c *ControlRPC) GetConfig(in *KeyValuePair, out *KeyValuePair) os.Error { server, exists := servers[in.Id] if !exists { return os.NewError("no such server") diff --git a/freeze.go b/freeze.go index b2909ce..1453549 100644 --- a/freeze.go +++ b/freeze.go @@ -199,7 +199,6 @@ func (channel *Channel) Freeze() (fc frozenChannel, err os.Error) { func (user *User) Freeze() (fu frozenUser, err os.Error) { fu.Id = user.Id fu.Name = user.Name - fu.Password = user.Password fu.CertHash = user.CertHash fu.Email = user.Email fu.TextureBlob = user.TextureBlob @@ -320,7 +319,6 @@ func NewServerFromFrozen(filename string) (s *Server, err os.Error) { return nil, err } - u.Password = fu.Password u.CertHash = fu.CertHash u.Email = fu.Email u.TextureBlob = fu.TextureBlob diff --git a/murmurdb.go b/murmurdb.go index 5b98c32..10b386a 100644 --- a/murmurdb.go +++ b/murmurdb.go @@ -355,13 +355,15 @@ func populateUsers(server *Server, db *sqlite.Conn) (err os.Error) { continue } + if UserId == 0 { + server.SuperUserPassword = "sha1$$" + SHA1Password + } + user, err := NewUser(uint32(UserId), UserName) if err != nil { return err } - user.Password = "sha1$$" + SHA1Password - key, err := blobstore.Put(Texture) if err != nil { return err diff --git a/server.go b/server.go index a9e4631..63b3b54 100644 --- a/server.go +++ b/server.go @@ -13,6 +13,7 @@ import ( "bufio" "bytes" "compress/gzip" + "crypto/rand" "encoding/binary" "encoding/hex" "sync" @@ -86,6 +87,9 @@ type Server struct { root *Channel Channels map[int]*Channel + // Administration + SuperUserPassword string + // Users Users map[uint32]*User UserCertMap map[string]*User @@ -150,6 +154,7 @@ func NewServer(id int64, addr string, port int) (s *Server, err os.Error) { s.freezeRequest = make(chan *freezeRequest) s.clientAuthenticated = make(chan *Client) + s.Users[0], err = NewUser(0, "SuperUser") s.Channels = make(map[int]*Channel) s.root = s.NewChannel(0, "Root") s.aclcache = NewACLCache() @@ -159,14 +164,27 @@ func NewServer(id int64, addr string, port int) (s *Server, err os.Error) { return } -// Check whether password matches the set SuperUser password. -func (server *Server) CheckSuperUserPassword(password string) bool { - superUser, exists := server.Users[0] - if !exists { - server.Panicf("Fatal error: No SuperUser for server %v", server.Id) +// Set password as the new SuperUser password +func (server *Server) SetSuperUserPassword(password string) { + saltBytes := make([]byte, 24) + _, err := rand.Read(saltBytes) + if err != nil { + server.Fatalf("Unable to read from crypto/rand: %v", err) } - parts := strings.Split(superUser.Password, "$", -1) + salt := hex.EncodeToString(saltBytes) + hasher := sha1.New() + hasher.Write(saltBytes) + hasher.Write([]byte(password)) + digest := hex.EncodeToString(hasher.Sum()) + + // Could be racy, but shouldn't really matter... + server.SuperUserPassword = "sha1$" + salt + "$" + digest +} + +// Check whether password matches the set SuperUser password. +func (server *Server) CheckSuperUserPassword(password string) bool { + parts := strings.Split(server.SuperUserPassword, "$", -1) if len(parts) != 3 { return false } @@ -186,7 +204,11 @@ func (server *Server) CheckSuperUserPassword(password string) bool { // salt if len(parts[1]) > 0 { - h.Write([]byte(parts[1])) + saltBytes, err := hex.DecodeString(parts[1]) + if err != nil { + server.Fatalf("Unable to decode salt: %v", err) + } + h.Write(saltBytes) } // password