From ed367f9a6f0e85dc327c311d629d28f2cad4ed8d Mon Sep 17 00:00:00 2001 From: tgic Date: Tue, 23 Dec 2014 19:37:52 +0800 Subject: [PATCH] config file and env config introduced --- sshpiperd/config.go | 125 +++++++++++++++++++++++++++++++++++ sshpiperd/sshpiperd.go | 55 +++++++-------- sshpiperd/workingdir.go | 2 +- sshpiperd/workingdir_test.go | 19 +++--- 4 files changed, 161 insertions(+), 40 deletions(-) create mode 100644 sshpiperd/config.go diff --git a/sshpiperd/config.go b/sshpiperd/config.go new file mode 100644 index 00000000..85956616 --- /dev/null +++ b/sshpiperd/config.go @@ -0,0 +1,125 @@ +// Copyright 2014, 2015 tgic. All rights reserved. +// this file is governed by MIT-license +// +// https://github.com/tg123/sshpiper + +package main + +import ( + "flag" + "os" + "strings" + "text/template" + + "github.com/docker/docker/pkg/mflag" + "github.com/rakyll/globalconf" +) + +var ( + config = struct { + ListenAddr string + Port uint + WorkingDir string + PiperKeyFile string + ShowHelp bool + Challenger string + ShowVersion bool + }{} + + out = os.Stdout + + configTemplate *template.Template + versionTemplate *template.Template +) + +func initTemplate() { + configTemplate = template.Must(template.New("config").Parse(` +Listening : {{.ListenAddr}}:{{.Port}} +Server Key File : {{.PiperKeyFile}} +Working Dir : {{.WorkingDir}} +Additional Challenger : {{.Challenger}} + +`[1:])) + + versionTemplate = template.Must(template.New("ver").Parse(` +SSHPiper ver: {{.}} by tgic +https://github.com/tg123/sshpiper + +`[1:])) +} + +func init() { + + initTemplate() + + configfile := mflag.String([]string{"-config"}, "/etc/sshpiperd.conf", "Config file path. Note: any option will be overwrite if it is set by commandline") + + mflag.StringVar(&config.ListenAddr, []string{"l", "-listen_addr"}, "0.0.0.0", "Listening Address") + mflag.UintVar(&config.Port, []string{"p", "-port"}, 2222, "Listening Port") + mflag.StringVar(&config.WorkingDir, []string{"w", "-working_dir"}, "/var/sshpiper", "Working Dir") + mflag.StringVar(&config.PiperKeyFile, []string{"i", "-server_key"}, "/etc/ssh/ssh_host_rsa_key", "Key file for SSH Piper") + mflag.StringVar(&config.Challenger, []string{"c", "-challenger"}, "", "Additional challenger name, e.g. pam, emtpy for no additional challenge") + mflag.BoolVar(&config.ShowHelp, []string{"h", "-help"}, false, "Print help and exit") + mflag.BoolVar(&config.ShowVersion, []string{"-version"}, false, "Print version and exit") + + mflag.Parse() + + if _, err := os.Stat(*configfile); os.IsNotExist(err) { + if !mflag.IsSet("-config") { + *configfile = "" + } else { + logger.Fatalf("config file %v not found", *configfile) + } + } + + gconf, err := globalconf.NewWithOptions(&globalconf.Options{ + Filename: *configfile, + EnvPrefix: "SSHPIPERD_", + }) + + if err != nil { // this error will happen only if file error + logger.Fatalln("load config file error %v: %v", *configfile, err) + } + + // build a dummy flag set for globalconf to parse + fs := flag.NewFlagSet("", flag.ContinueOnError) + + ignoreSet := make(map[string]bool) + mflag.Visit(func(f *mflag.Flag) { + for _, n := range f.Names { + ignoreSet[n] = true + } + }) + + // should be ignored + ignoreSet["-help"] = true + ignoreSet["-version"] = true + + mflag.VisitAll(func(f *mflag.Flag) { + for _, n := range f.Names { + if len(n) < 2 { + continue + } + + if !ignoreSet[n] { + n = strings.TrimPrefix(n, "-") + fs.Var(f.Value, n, f.Usage) + } + } + }) + + gconf.ParseSet("", fs) +} + +func showHelp() { + mflag.Usage() +} + +func showVersion() { + // TODO to build flag + versionTemplate.Execute(out, "v0.1") +} + +func showConfig() { + configTemplate.Execute(out, config) +} diff --git a/sshpiperd/sshpiperd.go b/sshpiperd/sshpiperd.go index 0a5da2fe..794511de 100644 --- a/sshpiperd/sshpiperd.go +++ b/sshpiperd/sshpiperd.go @@ -6,43 +6,38 @@ package main import ( - "flag" "fmt" - "github.com/tg123/sshpiper/ssh" - "github.com/tg123/sshpiper/sshpiperd/challenger" "io/ioutil" "log" "net" "os" + + "github.com/tg123/sshpiper/ssh" + "github.com/tg123/sshpiper/sshpiperd/challenger" ) var ( - ListenAddr string - Port uint - WorkingDir string - PiperKeyFile string - ShowHelp bool - Challenger string - logger = log.New(os.Stdout, "", log.Ldate|log.Ltime) ) -func init() { - flag.StringVar(&ListenAddr, "l", "0.0.0.0", "Listening Address") - flag.UintVar(&Port, "p", 2222, "Listening Port") - flag.StringVar(&WorkingDir, "w", "/var/sshpiper", "Working Dir") - flag.StringVar(&PiperKeyFile, "i", "/etc/ssh/ssh_host_rsa_key", "Key file for SSH Piper") - flag.StringVar(&Challenger, "c", "", "Additional challenger name, e.g. pam, emtpy for no additional challenge") - flag.BoolVar(&ShowHelp, "h", false, "Print help and exit") - flag.Parse() +func showHelpOrVersion() { + if config.ShowHelp { + showHelp() + os.Exit(0) + } + + if config.ShowVersion { + showVersion() + os.Exit(0) + } } func main() { - if ShowHelp { - flag.PrintDefaults() - return - } + showHelpOrVersion() + + showVersion() + showConfig() // TODO make this pluggable piper := &ssh.SSHPiperConfig{ @@ -50,17 +45,17 @@ func main() { MapPublicKey: mapPublicKeyFromUserfile, } - if Challenger != "" { - ac, err := challenger.GetChallenger(Challenger) + if config.Challenger != "" { + ac, err := challenger.GetChallenger(config.Challenger) if err != nil { - logger.Fatalln(err) + logger.Fatalln("failed to load challenger", err) } - logger.Printf("using additional challenger %s", Challenger) + logger.Printf("using additional challenger %s", config.Challenger) piper.AdditionalChallenge = ac } - privateBytes, err := ioutil.ReadFile(PiperKeyFile) + privateBytes, err := ioutil.ReadFile(config.PiperKeyFile) if err != nil { logger.Fatalln(err) } @@ -72,13 +67,13 @@ func main() { piper.AddHostKey(private) - listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", ListenAddr, Port)) + listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.ListenAddr, config.Port)) if err != nil { - logger.Fatalln("failed to listen for connection") + logger.Fatalln("failed to listen for connection: %v", err) } defer listener.Close() - logger.Printf("listening at %s:%d, server key file %s, working dir %s", ListenAddr, Port, PiperKeyFile, WorkingDir) + logger.Printf("SSHPiperd started") for { c, err := listener.Accept() diff --git a/sshpiperd/workingdir.go b/sshpiperd/workingdir.go index 00b4fd96..d91e327f 100644 --- a/sshpiperd/workingdir.go +++ b/sshpiperd/workingdir.go @@ -24,7 +24,7 @@ var ( ) func userSpecFile(user, file string) string { - return fmt.Sprintf("%s/%s/%s", WorkingDir, user, file) + return fmt.Sprintf("%s/%s/%s", config.WorkingDir, user, file) } func (file userFile) read(user string) ([]byte, error) { diff --git a/sshpiperd/workingdir_test.go b/sshpiperd/workingdir_test.go index 2f5e5685..2ef7dd7b 100644 --- a/sshpiperd/workingdir_test.go +++ b/sshpiperd/workingdir_test.go @@ -7,14 +7,15 @@ package main import ( "bytes" - "github.com/tg123/sshpiper/ssh" - "github.com/tg123/sshpiper/ssh/testdata" "io" "io/ioutil" "log" "net" "os" "testing" + + "github.com/tg123/sshpiper/ssh" + "github.com/tg123/sshpiper/ssh/testdata" ) func init() { @@ -24,30 +25,30 @@ func init() { } func buildWorkingDir(users []string, t *testing.T) { - WorkingDir = "" + config.WorkingDir = "" dir, err := ioutil.TempDir(os.TempDir(), "sshpiperd_workingdir") if err != nil { t.Fatalf("setup temp dir:%v", err) } - WorkingDir = dir + config.WorkingDir = dir for _, u := range users { - os.Mkdir(WorkingDir+"/"+u, os.ModePerm) + os.Mkdir(config.WorkingDir+"/"+u, os.ModePerm) } - t.Logf("switch workingdir to %v", WorkingDir) + t.Logf("switch workingdir to %v", config.WorkingDir) } func cleanupWorkdir(t *testing.T) { - if WorkingDir == "" { + if config.WorkingDir == "" { return } - t.Logf("cleaning workingdir %v", WorkingDir) + t.Logf("cleaning workingdir %v", config.WorkingDir) - os.RemoveAll(WorkingDir) + os.RemoveAll(config.WorkingDir) } func TestReadUserFile(t *testing.T) {