From 94f6a62d775366237c979b34bae930f71384bf19 Mon Sep 17 00:00:00 2001 From: rubenseyer Date: Wed, 14 Feb 2018 15:29:16 +0100 Subject: [PATCH] SuperUser CLI flags, fix #20 Also adds some Murmur CLI flags, see #25 Since the only way right now to set the SuperUser pw is through the CLI on start, this commit also drops the config updates through the freezelog (probably a remnant of RPC), which the SetSuperUserPassword function was the last user of. --- cmd/grumble/args.go | 40 +++++++++++++++++++++++++++++++--------- cmd/grumble/freeze.go | 8 ++++---- cmd/grumble/grumble.go | 40 +++++++++++++++++++++++++++++++++++++--- cmd/grumble/server.go | 22 +++++++++++----------- 4 files changed, 83 insertions(+), 27 deletions(-) diff --git a/cmd/grumble/args.go b/cmd/grumble/args.go index 37fd47e..3ca7101 100644 --- a/cmd/grumble/args.go +++ b/cmd/grumble/args.go @@ -21,7 +21,7 @@ var usageTmpl = `usage: grumble [options] grumble {{.Version}} ({{.BuildDate}}) target: {{.OS}}, {{.Arch}} - --help + --help, --version Shows this help listing. --datadir (default: {{.DefaultDataDir}}) @@ -30,9 +30,20 @@ var usageTmpl = `usage: grumble [options] --log (default: $DATADIR/grumble.log) Log file path. - --config, --ini (default: $DATADIR/grumble.ini) + --config, --ini (default: $DATADIR/grumble.ini) Config file path. + --supw [server-id] + Set password for SuperUser account. Optionally takes + the virtual server to modify as the first positional argument. + + --readsupw [server-id] + Like --supw, but reads from stdin instead. + + --disablesu [server-id] + Disables the SuperUser account. Optionally takes + the virtual server to modify as the first positional argument. + --regen-keys Force grumble to regenerate its global RSA keypair (and certificate). @@ -49,13 +60,17 @@ var usageTmpl = `usage: grumble [options] ` type args struct { - ShowHelp bool - DataDir string - LogPath string - ConfigPath string - RegenKeys bool - SQLiteDB string - CleanUp bool + ShowHelp bool + DataDir string + LogPath string + ConfigPath string + SuperUserPW string + ReadPass bool + DisablePass bool + RegenKeys bool + ServerId int64 + SQLiteDB string + CleanUp bool } func defaultDataDir() string { @@ -90,11 +105,18 @@ var Args args func init() { flag.Usage = Usage + flag.BoolVar(&Args.ShowHelp, "version", false, "") flag.BoolVar(&Args.ShowHelp, "help", false, "") + flag.StringVar(&Args.DataDir, "datadir", defaultDataDir(), "") flag.StringVar(&Args.LogPath, "log", "", "") flag.StringVar(&Args.ConfigPath, "ini", "", "") flag.StringVar(&Args.ConfigPath, "config", "", "") + + flag.StringVar(&Args.SuperUserPW, "supw", "", "") + flag.BoolVar(&Args.ReadPass, "readsupw", false, "") + flag.BoolVar(&Args.DisablePass, "disablesu", false, "") + flag.BoolVar(&Args.RegenKeys, "regen-keys", false, "") flag.StringVar(&Args.SQLiteDB, "import-murmurdb", "", "") diff --git a/cmd/grumble/freeze.go b/cmd/grumble/freeze.go index a2c991c..bedef13 100644 --- a/cmd/grumble/freeze.go +++ b/cmd/grumble/freeze.go @@ -834,7 +834,7 @@ func (server *Server) UpdateFrozenBans(bans []ban.Ban) { } // Write an updated config value to the datastore. -func (server *Server) UpdateConfig(key, value string) { +/*func (server *Server) UpdateConfig(key, value string) { fcfg := &freezer.ConfigKeyValuePair{ Key: proto.String(key), Value: proto.String(value), @@ -844,11 +844,11 @@ func (server *Server) UpdateConfig(key, value string) { server.Fatal(err) } server.numLogOps += 1 -} +}*/ // Write to the freezelog that the config with key // has been reset to its default value. -func (server *Server) ResetConfig(key string) { +/*func (server *Server) ResetConfig(key string) { fcfg := &freezer.ConfigKeyValuePair{ Key: proto.String(key), } @@ -857,4 +857,4 @@ func (server *Server) ResetConfig(key string) { server.Fatal(err) } server.numLogOps += 1 -} +}*/ diff --git a/cmd/grumble/grumble.go b/cmd/grumble/grumble.go index c0d3187..bc98f19 100644 --- a/cmd/grumble/grumble.go +++ b/cmd/grumble/grumble.go @@ -7,10 +7,12 @@ package main import ( "flag" "fmt" + "io/ioutil" "log" "os" "path/filepath" "regexp" + "strconv" "mumble.info/grumble/pkg/blobstore" "mumble.info/grumble/pkg/logtarget" @@ -29,6 +31,20 @@ func main() { Usage() return } + if Args.ReadPass { + data, err := ioutil.ReadAll(os.Stdin) + if err != nil { + log.Fatalf("Failed to read password from stdin: %v", err) + } + Args.SuperUserPW = string(data) + } + if flag.NArg() > 0 && (Args.SuperUserPW != "" || Args.DisablePass) { + Args.ServerId, err = strconv.ParseInt(flag.Arg(0), 10, 64) + if err != nil { + log.Fatalf("Failed to parse server id %v: %v", flag.Arg(0), err) + return + } + } // Open the data dir to check whether it exists. dataDir, err := os.Open(Args.DataDir) @@ -97,9 +113,7 @@ func main() { // Check whether we should regenerate the default global keypair // and corresponding certificate. - // These are used as the default certificate of all virtual servers - // and the SSH admin console, but can be overridden using the "key" - // and "cert" arguments to Grumble. todo(rubenseyer) implement override by cli + // These are used as the default certificate of all virtual servers. certFn := config.PathValue("CertPath", Args.DataDir) keyFn := config.PathValue("KeyPath", Args.DataDir) shouldRegen := false @@ -215,6 +229,18 @@ func main() { if err != nil { log.Fatalf("Unable to load server: %v", err.Error()) } + + // Check if SuperUser password should be updated. + if Args.ServerId == 0 || Args.ServerId == s.Id { + if Args.DisablePass { + s.cfg.Reset("SuperUserPassword") + log.Printf("Disabled SuperUser for server %v", name) + } else if Args.SuperUserPW != "" { + s.SetSuperUserPassword(Args.SuperUserPW) + log.Printf("Set SuperUser password for server %v", name) + } + } + err = s.FreezeToFile() if err != nil { log.Fatalf("Unable to freeze server to disk: %v", err.Error()) @@ -223,6 +249,14 @@ func main() { } } + // If SuperUser password flags were passed, the servers should not start. + if Args.SuperUserPW != "" || Args.DisablePass { + if len(servers) == 0 { + log.Fatalf("No servers found to set password for") + } + return + } + // If no servers were found, create the default virtual server. if len(servers) == 0 { s, err := NewServer(1, configFile.ServerConfig(1, nil)) diff --git a/cmd/grumble/server.go b/cmd/grumble/server.go index c1ef291..c2517fd 100644 --- a/cmd/grumble/server.go +++ b/cmd/grumble/server.go @@ -74,8 +74,8 @@ type Server struct { incoming chan *Message voicebroadcast chan *VoiceBroadcast - cfgUpdate chan *KeyValuePair - tempRemove chan *Channel + //cfgUpdate chan *KeyValuePair + tempRemove chan *Channel // Signals to the server that a client has been successfully // authenticated. @@ -196,7 +196,7 @@ func (server *Server) SetSuperUserPassword(password string) { key := "SuperUserPassword" val := "sha1$" + salt + "$" + digest server.cfg.Set(key, val) - server.cfgUpdate <- &KeyValuePair{Key: key, Value: val} + //server.cfgUpdate <- &KeyValuePair{Key: key, Value: val} } // Check whether password matches the set SuperUser password. @@ -416,12 +416,12 @@ func (server *Server) handlerLoop() { server.finishAuthenticate(client) // Disk freeze config update - case kvp := <-server.cfgUpdate: - if !kvp.Reset { - server.UpdateConfig(kvp.Key, kvp.Value) - } else { - server.ResetConfig(kvp.Key) - } + /*case kvp := <-server.cfgUpdate: + if !kvp.Reset { + server.UpdateConfig(kvp.Key, kvp.Value) + } else { + server.ResetConfig(kvp.Key) + }*/ // Server registration update // Tick every hour + a minute offset based on the server id. @@ -1328,7 +1328,7 @@ func (server *Server) initPerLaunchData() { server.bye = make(chan bool) server.incoming = make(chan *Message) server.voicebroadcast = make(chan *VoiceBroadcast) - server.cfgUpdate = make(chan *KeyValuePair) + //server.cfgUpdate = make(chan *KeyValuePair) server.tempRemove = make(chan *Channel, 1) server.clientAuthenticated = make(chan *Client) } @@ -1343,7 +1343,7 @@ func (server *Server) cleanPerLaunchData() { server.bye = nil server.incoming = nil server.voicebroadcast = nil - server.cfgUpdate = nil + //server.cfgUpdate = nil server.tempRemove = nil server.clientAuthenticated = nil }