From 17f558ae93fb98e4664f2cd7d3faa2a3f44a3339 Mon Sep 17 00:00:00 2001 From: Boshi Lian Date: Mon, 4 Jul 2022 16:42:28 +0000 Subject: [PATCH] remove old dir --- sshpiperd/cmd.go | 275 ------- sshpiperd/e2e/Dockerfile-grpcremote | 8 - sshpiperd/e2e/docker-compose.yml | 241 ------ sshpiperd/e2e/piper.sh | 12 - sshpiperd/e2e/sshpiperd.yaml | 82 -- sshpiperd/e2e/test.sh | 85 --- sshpiperd/e2e/wait.sh | 13 - sshpiperd/example/showme.sh | 45 -- sshpiperd/loader.go | 15 - sshpiperd/log.go | 42 -- sshpiperd/log_test.go | 40 - sshpiperd/pipemgr.go | 89 --- sshpiperd/registry/plugin.go | 19 - sshpiperd/registry/registry.go | 51 -- sshpiperd/registry/registry_test.go | 71 -- sshpiperd/snap/docker-compose.yml | 32 - sshpiperd/snap/snap/hooks/configure | 37 - sshpiperd/snap/snap/hooks/install | 7 - sshpiperd/snap/snapcraft.yaml | 23 - sshpiperd/sshpiperd.go | 272 ------- sshpiperd/sshpiperd_test.go | 362 --------- sshpiperd/upstream/database/README.md | 12 - sshpiperd/upstream/database/handler.go | 256 ------- sshpiperd/upstream/database/handler_test.go | 202 ----- sshpiperd/upstream/database/model.go | 74 -- sshpiperd/upstream/database/mssql.go | 58 -- sshpiperd/upstream/database/mysql.go | 55 -- sshpiperd/upstream/database/pipemgr.go | 76 -- sshpiperd/upstream/database/plugin.go | 61 -- sshpiperd/upstream/database/postgres.go | 62 -- sshpiperd/upstream/database/sqlite.go | 40 - sshpiperd/upstream/grpcupstream/grpc.go | 124 --- sshpiperd/upstream/grpcupstream/pipemgr.go | 20 - sshpiperd/upstream/grpcupstream/plugin.go | 92 --- .../grpcupstream/simpleserver/impl.go | 72 -- .../grpcupstream/simpleserver/main.go | 73 -- .../upstream/grpcupstream/upstream.pb.go | 710 ------------------ .../upstream/grpcupstream/upstream.proto | 58 -- .../upstream/grpcupstream/upstream_grpc.pb.go | 173 ----- sshpiperd/upstream/kubernetes/README.md | 79 -- sshpiperd/upstream/kubernetes/TODO | 4 - sshpiperd/upstream/kubernetes/crd.yaml | 75 -- .../kubernetes/example/deploy-sftp.yaml | 118 --- .../upstream/kubernetes/example/sshpiper.yaml | 80 -- sshpiperd/upstream/kubernetes/kubernetes.go | 124 --- sshpiperd/upstream/kubernetes/pipemgr.go | 57 -- sshpiperd/upstream/kubernetes/plugin.go | 39 - sshpiperd/upstream/provider.go | 124 --- sshpiperd/upstream/yaml/pipemgr.go | 250 ------ sshpiperd/upstream/yaml/plugin.go | 41 - sshpiperd/upstream/yaml/schema.json | 165 ---- sshpiperd/upstream/yaml/yaml.go | 380 ---------- sshpiperd/utils/common.go | 17 - sshpiperd/v0bridge/v0bridge.go | 200 ----- sshpiperd/ver.go | 46 -- 55 files changed, 5838 deletions(-) delete mode 100644 sshpiperd/cmd.go delete mode 100644 sshpiperd/e2e/Dockerfile-grpcremote delete mode 100644 sshpiperd/e2e/docker-compose.yml delete mode 100755 sshpiperd/e2e/piper.sh delete mode 100644 sshpiperd/e2e/sshpiperd.yaml delete mode 100755 sshpiperd/e2e/test.sh delete mode 100755 sshpiperd/e2e/wait.sh delete mode 100755 sshpiperd/example/showme.sh delete mode 100644 sshpiperd/loader.go delete mode 100644 sshpiperd/log.go delete mode 100644 sshpiperd/log_test.go delete mode 100644 sshpiperd/pipemgr.go delete mode 100644 sshpiperd/registry/plugin.go delete mode 100644 sshpiperd/registry/registry.go delete mode 100644 sshpiperd/registry/registry_test.go delete mode 100644 sshpiperd/snap/docker-compose.yml delete mode 100755 sshpiperd/snap/snap/hooks/configure delete mode 100755 sshpiperd/snap/snap/hooks/install delete mode 100644 sshpiperd/snap/snapcraft.yaml delete mode 100644 sshpiperd/sshpiperd.go delete mode 100644 sshpiperd/sshpiperd_test.go delete mode 100644 sshpiperd/upstream/database/README.md delete mode 100644 sshpiperd/upstream/database/handler.go delete mode 100644 sshpiperd/upstream/database/handler_test.go delete mode 100644 sshpiperd/upstream/database/model.go delete mode 100644 sshpiperd/upstream/database/mssql.go delete mode 100644 sshpiperd/upstream/database/mysql.go delete mode 100644 sshpiperd/upstream/database/pipemgr.go delete mode 100644 sshpiperd/upstream/database/plugin.go delete mode 100644 sshpiperd/upstream/database/postgres.go delete mode 100644 sshpiperd/upstream/database/sqlite.go delete mode 100644 sshpiperd/upstream/grpcupstream/grpc.go delete mode 100644 sshpiperd/upstream/grpcupstream/pipemgr.go delete mode 100644 sshpiperd/upstream/grpcupstream/plugin.go delete mode 100644 sshpiperd/upstream/grpcupstream/simpleserver/impl.go delete mode 100644 sshpiperd/upstream/grpcupstream/simpleserver/main.go delete mode 100644 sshpiperd/upstream/grpcupstream/upstream.pb.go delete mode 100644 sshpiperd/upstream/grpcupstream/upstream.proto delete mode 100644 sshpiperd/upstream/grpcupstream/upstream_grpc.pb.go delete mode 100644 sshpiperd/upstream/kubernetes/README.md delete mode 100644 sshpiperd/upstream/kubernetes/TODO delete mode 100644 sshpiperd/upstream/kubernetes/crd.yaml delete mode 100644 sshpiperd/upstream/kubernetes/example/deploy-sftp.yaml delete mode 100644 sshpiperd/upstream/kubernetes/example/sshpiper.yaml delete mode 100644 sshpiperd/upstream/kubernetes/kubernetes.go delete mode 100644 sshpiperd/upstream/kubernetes/pipemgr.go delete mode 100644 sshpiperd/upstream/kubernetes/plugin.go delete mode 100644 sshpiperd/upstream/provider.go delete mode 100644 sshpiperd/upstream/yaml/pipemgr.go delete mode 100644 sshpiperd/upstream/yaml/plugin.go delete mode 100644 sshpiperd/upstream/yaml/schema.json delete mode 100644 sshpiperd/upstream/yaml/yaml.go delete mode 100644 sshpiperd/utils/common.go delete mode 100644 sshpiperd/v0bridge/v0bridge.go delete mode 100644 sshpiperd/ver.go diff --git a/sshpiperd/cmd.go b/sshpiperd/cmd.go deleted file mode 100644 index fe1c4cc5..00000000 --- a/sshpiperd/cmd.go +++ /dev/null @@ -1,275 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "os" - "strings" - - log "github.com/sirupsen/logrus" - - "github.com/jessevdk/go-flags" - "github.com/tg123/sshkey" - - "github.com/tg123/sshpiper/sshpiperd/auditor" - "github.com/tg123/sshpiper/sshpiperd/challenger" - "github.com/tg123/sshpiper/sshpiperd/registry" - "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -type subCommand struct{ callback func(args []string) error } - -func (s *subCommand) Execute(args []string) error { - return s.callback(args) -} - -func addSubCommand(command *flags.Command, name, desc string, callback interface{}) *flags.Command { - c, err := command.AddCommand(name, desc, "", callback) - - if err != nil { - panic(err) - } - - return c -} - -func addOpt(group *flags.Group, name string, data interface{}) { - _, err := group.AddGroup(name, "", data) - - if err != nil { - panic(err) - } -} - -func addPlugins(group *flags.Group, name string, pluginNames []string, getter func(n string) registry.Plugin) { - for _, n := range pluginNames { - - p := getter(n) - - opt := p.GetOpts() - - if opt == nil { - continue - } - - _, err := group.AddGroup(name+"."+p.GetName(), "", opt) - - if err != nil { - panic(err) - } - } -} - -func populateFromConfig(ini *flags.IniParser, data interface{}, longopt string) error { - - parser := flags.NewParser(data, flags.IgnoreUnknown) - _, _ = parser.Parse() - - o := parser.FindOptionByLongName(longopt) - file := o.Value().(flags.Filename) - err := ini.ParseFile(string(file)) - - if err != nil { - // set by user - if !o.IsSetDefault() { - return err - } - } - - return nil -} - -func main() { - - parser := flags.NewNamedParser("sshpiperd", flags.Default) - parser.LongDescription = "SSH Piper works as a proxy-like ware, and route connections by username, src ip , etc. Please see for more information" - - // public config - configFile := &struct { - ConfigFile flags.Filename `long:"config" description:"Config file path. Will be overwritten by arg options and environment variables" default:"/etc/sshpiperd.ini" env:"SSHPIPERD_CONFIG_FILE" no-ini:"true"` - }{} - addOpt(parser.Group, "sshpiperd", configFile) - - loadFromConfigFile := func(c *flags.Command) { - parser := flags.NewNamedParser("sshpiperd", flags.IgnoreUnknown) - parser.Command = c - ini := flags.NewIniParser(parser) - ini.ParseAsDefaults = true - err := populateFromConfig(ini, configFile, "config") - if err != nil { - fmt.Printf("load config file failed %v", err) - os.Exit(1) - } - } - - // version - { - addSubCommand(parser.Command, "version", "Show version", &subCommand{func(args []string) error { - showVersion() - return nil - }}) - } - - // manpage - addSubCommand(parser.Command, "manpage", "Write man page to stdout", &subCommand{func(args []string) error { - parser.WriteManPage(os.Stdout) - return nil - }}) - - // plugins - addSubCommand(parser.Command, "plugins", "List support plugins, e.g. sshpiperd plugins upstream", &subCommand{func(args []string) error { - - output := func(all []string) { - for _, p := range all { - fmt.Println(p) - } - } - - if len(args) == 0 { - args = []string{"upstream", "challenger", "auditor"} - } - - for _, n := range args { - switch n { - case "upstream": - output(upstream.All()) - case "challenger": - output(challenger.All()) - case "auditor": - output(auditor.All()) - } - } - - return nil - }}) - - // generate key tools - { - addSubCommand(parser.Command, "genkey", "generate a 2048 rsa key to stdout", &subCommand{func(args []string) error { - key, err := sshkey.GenerateKey(sshkey.KEY_RSA, 2048) - if err != nil { - return err - } - - out, err := sshkey.MarshalPrivate(key, "") - if err != nil { - return err - } - - _, err = fmt.Fprint(os.Stdout, string(out)) - - return err - }}) - } - - // pipe management - { - config := &struct { - UpstreamDriver string `long:"upstream-driver" description:"Upstream provider driver" default:"workingdir" env:"SSHPIPERD_UPSTREAM_DRIVER" ini-name:"upstream-driver"` - }{} - - var c *flags.Command - c = addSubCommand(parser.Command, "pipe", "manage pipe on current upstream driver", createPipeMgr(func() (upstream.Provider, error) { - - loadFromConfigFile(c) - - if config.UpstreamDriver == "" { - return nil, fmt.Errorf("must provider upstream driver") - } - - provider := upstream.Get(config.UpstreamDriver) - logger := log.New() - logger.SetOutput(ioutil.Discard) - err := provider.Init(logger) - if err != nil { - return nil, err - } - - return provider, nil - })) - - addOpt(c.Group, "sshpiperd", config) - addPlugins(c.Group, "upstream", upstream.All(), func(n string) registry.Plugin { return upstream.Get(n) }) - } - - // daemon command - { - config := &struct { - piperdConfig - loggerConfig - }{} - - var c *flags.Command - c = addSubCommand(parser.Command, "daemon", "run in daemon mode, serving traffic", &subCommand{func(args []string) error { - // populate by config - loadFromConfigFile(c) - - showVersion() - - // dump used configure only - { - fmt.Println() - for _, gk := range []string{"sshpiperd", "upstream." + config.UpstreamDriver, "challenger." + config.ChallengerDriver, "auditor." + config.AuditorDriver} { - - g := c.Group.Find(gk) - if g == nil { - continue - } - - fmt.Println("[" + g.ShortDescription + "]") - for _, o := range g.Options() { - if strings.HasSuffix(o.LongName, "password") { - fmt.Printf("%v = %v", o.LongName, "******") - } else { - fmt.Printf("%v = %v", o.LongName, o.Value()) - } - fmt.Println() - } - fmt.Println() - } - } - - return startPiper(&config.piperdConfig, config.createLogger()) - }}) - c.SubcommandsOptional = true - - addOpt(c.Group, "sshpiperd", config) - addPlugins(c.Group, "upstream", upstream.All(), func(n string) registry.Plugin { return upstream.Get(n) }) - addPlugins(c.Group, "challenger", challenger.All(), func(n string) registry.Plugin { return challenger.Get(n) }) - addPlugins(c.Group, "auditor", auditor.All(), func(n string) registry.Plugin { return auditor.Get(n) }) - - // dumpini for daemon - addSubCommand(c, "dumpconfig", "dump current config for daemon ini to stdout", &subCommand{func(args []string) error { - loadFromConfigFile(c) - - parser := flags.NewNamedParser("sshpiperd", flags.Default) - parser.Command = c - ini := flags.NewIniParser(parser) - ini.Write(os.Stdout, flags.IniIncludeDefaults) - return nil - }}) - - // options, for snap only at the moment - addSubCommand(c, "options", "list all options for daemon mode", &subCommand{func(args []string) error { - var printOpts func(*flags.Group) - - printOpts = func(group *flags.Group) { - for _, o := range group.Options() { - fmt.Println(o.LongName) - } - - for _, g := range group.Groups() { - printOpts(g) - } - } - - printOpts(c.Group) - return nil - }}) - } - - _, err := parser.Parse() - if err != nil { - os.Exit(1) - } -} diff --git a/sshpiperd/e2e/Dockerfile-grpcremote b/sshpiperd/e2e/Dockerfile-grpcremote deleted file mode 100644 index 6b7e1d08..00000000 --- a/sshpiperd/e2e/Dockerfile-grpcremote +++ /dev/null @@ -1,8 +0,0 @@ -FROM golang - -ADD . /go/src/github.com/tg123/sshpiper/ -WORKDIR /go/src/github.com/tg123/sshpiper/sshpiperd/upstream/grpcupstream/simpleserver - -RUN go build -o /simpleserver - - diff --git a/sshpiperd/e2e/docker-compose.yml b/sshpiperd/e2e/docker-compose.yml deleted file mode 100644 index e1875103..00000000 --- a/sshpiperd/e2e/docker-compose.yml +++ /dev/null @@ -1,241 +0,0 @@ -version: '3' - -services: - host1: - image: rastasheep/ubuntu-sshd - volumes: - - host1ssh:/root/.ssh - - names:/names - host2: - image: rastasheep/ubuntu-sshd - volumes: - - names:/names - client: - image: valudio/docker-sshpass - volumes: - - workingdir:/workingdir - - localkey:/local - - host1ssh:/host1 - - names:/names - - ./test.sh:/test.sh - - ./wait.sh:/wait.sh - command: - - "/bin/sh" - - "/test.sh" - depends_on: - - piper - - piper_yaml - # - piper_mysql - # - piper_pg - # - piper_mssql - # - piper_sqlite - # - piper_grpc_privatekey_host1 - # - piper_grpc_remotesigner_host1 - # - piper_grpc_host2 - piper: - environment: - - "SSHPIPERD_UPSTREAM_WORKINGDIR_NOCHECKPERM=true" - - "SSHPIPERD_AUDITOR=typescript-logger" - - "SSHPIPERD_BANNERTEXT=hellopiper" - - "SSHPIPERD_LOG_LEVEL=trace" - build: ../.. - volumes: - - workingdir:/var/sshpiper - - ./piper.sh:/piper.sh - - ./wait.sh:/wait.sh - command: - - "/bin/sh" - - "/piper.sh" - depends_on: - - host1 - - host2 - piper_yaml: - environment: - - "SSHPIPERD_UPSTREAM_DRIVER=yaml" - - "SSHPIPERD_UPSTREAM_YAML_NOCHECKPERM=true" - - "SSHPIPERD_UPSTREAM_YAML_FILE=/sshpiperd.yaml" - - "SSHPIPERD_AUDITOR=typescript-logger" - - "SSHPIPERD_BANNERTEXT=hellopiper" - - "SSHPIPERD_LOG_LEVEL=trace" - build: ../.. - volumes: - - localkey:/local - - workingdir:/var/sshpiper - - ./sshpiperd.yaml:/sshpiperd.yaml - depends_on: - - host1 - - host2 - # piper_sqlite: - # environment: - # - "SSHPIPERD_UPSTREAM_DRIVER=sqlite" - # - "SSHPIPERD_AUDITOR=typescript-logger" - # - "SSHPIPERD_BANNERTEXT=hellopiper" - # build: ../.. - # volumes: - # - workingdir:/var/sshpiper - # - ./piper.sh:/piper.sh - # - ./wait.sh:/wait.sh - # command: - # - "/bin/sh" - # - "/piper.sh" - # depends_on: - # - host1 - # - host2 - # piper_mysql: - # environment: - # - "WAIT_HOST=mysql" - # - "WAIT_PORT=3306" - # - "SSHPIPERD_UPSTREAM_DRIVER=mysql" - # - "SSHPIPERD_UPSTREAM_MYSQL_HOST=mysql" - # - "SSHPIPERD_AUDITOR=typescript-logger" - # - "SSHPIPERD_BANNERTEXT=hellopiper" - # - "SSHPIPERD_LOG_LEVEL=trace" - # build: ../.. - # volumes: - # - ./piper.sh:/piper.sh - # - workingdir:/var/sshpiper - # - ./wait.sh:/wait.sh - # command: - # - "/bin/sh" - # - "/piper.sh" - # depends_on: - # - mysql - # - host1 - # - host2 - # mysql: - # image: mysql - # environment: - # - "MYSQL_ALLOW_EMPTY_PASSWORD=true" - # - "MYSQL_DATABASE=sshpiper" - # tmpfs: - # - /var/lib/mysql - # piper_pg: - # environment: - # - "WAIT_HOST=postgres" - # - "WAIT_PORT=5432" - # - "SSHPIPERD_UPSTREAM_DRIVER=postgres" - # - "SSHPIPERD_UPSTREAM_POSTGRES_HOST=postgres" - # - "SSHPIPERD_UPSTREAM_POSTGRES_SSLMODE=disable" - # - "SSHPIPERD_AUDITOR=typescript-logger" - # - "SSHPIPERD_BANNERTEXT=hellopiper" - # - "SSHPIPERD_LOG_LEVEL=trace" - # build: ../.. - # volumes: - # - ./piper.sh:/piper.sh - # - workingdir:/var/sshpiper - # - ./wait.sh:/wait.sh - # command: - # - "/bin/sh" - # - "/piper.sh" - # depends_on: - # - postgres - # - host1 - # - host2 - # postgres: - # image: postgres - # environment: - # - "POSTGRES_DB=sshpiper" - # - "POSTGRES_HOST_AUTH_METHOD=trust" - # tmpfs: - # - /var/lib/postgresql/data - # piper_mssql: - # environment: - # - "WAIT_HOST=mssql" - # - "WAIT_PORT=1433" - # - "EXTRA_WAIT=5" - # - "SSHPIPERD_UPSTREAM_DRIVER=mssql" - # - "SSHPIPERD_UPSTREAM_MSSQL_HOST=mssql" - # - "SSHPIPERD_UPSTREAM_MSSQL_PASSWORD=yourStrong(!)Password" - # - "SSHPIPERD_UPSTREAM_MSSQL_DBNAME=master" - # - "SSHPIPERD_AUDITOR=typescript-logger" - # - "SSHPIPERD_BANNERTEXT=hellopiper" - # - "SSHPIPERD_LOG_LEVEL=trace" - # build: ../.. - # volumes: - # - ./piper.sh:/piper.sh - # - workingdir:/var/sshpiper - # - ./wait.sh:/wait.sh - # command: - # - "/bin/sh" - # - "/piper.sh" - # depends_on: - # - mssql - # - host1 - # - host2 - # mssql: - # image: mcr.microsoft.com/mssql/server - # environment: - # - "ACCEPT_EULA=y" - # - "SA_PASSWORD=yourStrong(!)Password" - # - "MSSQL_PID=Developer" - # grpc_remotesigner_host1: - # build: - # context: ../.. - # dockerfile: sshpiperd/e2e/Dockerfile-grpcremote - # command: ["/simpleserver", "--toaddr", "host1", "--totype", "REMOTESIGNER", "--mappeduser", "root", "--privatekey", "/workingdir/host1/id_rsa"] - # volumes: - # - workingdir:/workingdir - # depends_on: - # - host1 - # piper_grpc_remotesigner_host1: - # environment: - # - "SSHPIPERD_UPSTREAM_DRIVER=grpc" - # - "SSHPIPERD_UPSTREAM_GRPC_INSECURE=true" - # - "SSHPIPERD_UPSTREAM_GRPC_ENDPOINT=grpc_remotesigner_host1:2233" - # - "SSHPIPERD_AUDITOR=typescript-logger" - # - "SSHPIPERD_BANNERTEXT=hellopiper" - # - "SSHPIPERD_LOG_LEVEL=trace" - # build: ../.. - # volumes: - # - workingdir:/var/sshpiper - # depends_on: - # - grpc_remotesigner_host1 - # grpc_privatekey_host1: - # build: - # context: ../.. - # dockerfile: sshpiperd/e2e/Dockerfile-grpcremote - # command: ["/simpleserver", "--toaddr", "host1", "--totype", "REMOTESIGNER", "--mappeduser", "root", "--privatekey", "/workingdir/host1/id_rsa"] - # volumes: - # - workingdir:/workingdir - # depends_on: - # - host1 - # piper_grpc_privatekey_host1: - # environment: - # - "SSHPIPERD_UPSTREAM_DRIVER=grpc" - # - "SSHPIPERD_UPSTREAM_GRPC_INSECURE=true" - # - "SSHPIPERD_UPSTREAM_GRPC_ENDPOINT=grpc_privatekey_host1:2233" - # - "SSHPIPERD_AUDITOR=typescript-logger" - # - "SSHPIPERD_BANNERTEXT=hellopiper" - # - "SSHPIPERD_LOG_LEVEL=trace" - # build: ../.. - # volumes: - # - workingdir:/var/sshpiper - # depends_on: - # - grpc_privatekey_host1 - # grpc_remotepass_host2: - # build: - # context: ../.. - # dockerfile: sshpiperd/e2e/Dockerfile-grpcremote - # command: ["/simpleserver", "--toaddr", "host2", "--totype", "PASSWORD", "--mappeduser", "root", "--password", "root"] - # depends_on: - # - host2 - # piper_grpc_host2: - # environment: - # - "SSHPIPERD_UPSTREAM_DRIVER=grpc" - # - "SSHPIPERD_UPSTREAM_GRPC_INSECURE=true" - # - "SSHPIPERD_UPSTREAM_GRPC_ENDPOINT=grpc_remotepass_host2:2233" - # - "SSHPIPERD_AUDITOR=typescript-logger" - # - "SSHPIPERD_BANNERTEXT=hellopiper" - # - "SSHPIPERD_LOG_LEVEL=trace" - # build: ../.. - # depends_on: - # - grpc_remotepass_host2 - # volumes: - # - workingdir:/var/sshpiper - - -volumes: - workingdir: - localkey: - host1ssh: - names: diff --git a/sshpiperd/e2e/piper.sh b/sshpiperd/e2e/piper.sh deleted file mode 100755 index bda437ff..00000000 --- a/sshpiperd/e2e/piper.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -if [ ! -z $WAIT_HOST ]; then - /wait.sh $WAIT_HOST $WAIT_PORT $EXTRA_WAIT -fi - -/sshpiperd pipe add -n host1 -u host1 --upstream-username root -/sshpiperd pipe add -n host2 -u host2 --upstream-username root -/sshpiperd pipe list - - -/sshpiperd daemon diff --git a/sshpiperd/e2e/sshpiperd.yaml b/sshpiperd/e2e/sshpiperd.yaml deleted file mode 100644 index 13936b63..00000000 --- a/sshpiperd/e2e/sshpiperd.yaml +++ /dev/null @@ -1,82 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/tg123/sshpiper/master/sshpiperd/upstream/yaml/schema.json -version: "0.1" -pipes: - - username: passthrough - upstream_host: host2 - ignore_hostkey: true - authmap: - mapped_username: root - - username: mappasspass - upstream_host: host2 - ignore_hostkey: true - authmap: - mapped_username: root - from: - - type: password - password: pass - to: - type: password - password: root - - username: mappasskey - upstream_host: host1 - ignore_hostkey: true - authmap: - mapped_username: root - from: - - type: password - password: pass - to: - type: privatekey - private_key: /var/sshpiper/host1/id_rsa - - username: mapkeypass - upstream_host: host2 - ignore_hostkey: true - authmap: - mapped_username: root - from: - - type: publickey - authorized_keys: /local/id_rsa2.pub - to: - type: password - password: root - - username: mapkeykey - upstream_host: host1 - ignore_hostkey: true - authmap: - mapped_username: root - from: - - type: publickey - authorized_keys: /local/id_rsa2.pub - to: - type: privatekey - private_key: /var/sshpiper/host1/id_rsa - - username: mapkeykey2 - upstream_host: host1 - ignore_hostkey: true - authmap: - mapped_username: root - from: - - type: publickey - allow_any_public_key: true - to: - type: privatekey - key_map: - - authorized_keys: /local/id_rsa2.pub - private_key: /var/sshpiper/host1/id_rsa - - username: ^regex.*$ - username_regex_match: true - upstream_host: host2 - ignore_hostkey: true - authmap: - mapped_username: root - - username: ^host.*$ - username_regex_match: true - upstream_host: host1 - ignore_hostkey: true - authmap: - mapped_username: root - from: - - type: any - to: - type: privatekey - private_key: /var/sshpiper/$USER/id_rsa \ No newline at end of file diff --git a/sshpiperd/e2e/test.sh b/sshpiperd/e2e/test.sh deleted file mode 100755 index a0c080c5..00000000 --- a/sshpiperd/e2e/test.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/sh - - -/wait.sh piper 2222 -/wait.sh piper_yaml 2222 -#/wait.sh piper_sqlite 2222 -# /wait.sh piper_mysql 2222 -# /wait.sh piper_pg 2222 -# /wait.sh piper_mssql 2222 -# /wait.sh piper_grpc_remotesigner_host1 2222 -# /wait.sh piper_grpc_privatekey_host1 2222 -# /wait.sh piper_grpc_host2 2222 - - -# TODO to python - -mkdir -p /local -mkdir -p /workingdir/host{1,2} - -ssh-keygen -N '' -f /local/id_rsa -ssh-keygen -N '' -f /workingdir/host1/id_rsa #TODO pipe cmd - -ssh-keygen -N '' -f /local/id_rsa2 - - -/bin/cp /local/id_rsa.pub /workingdir/host1/authorized_keys -/bin/cp /workingdir/host1/id_rsa.pub /host1/authorized_keys - -fail="\033[0;31mFAIL\033[0m" -succ="\033[0;32mSUCC\033[0m" - -runtest(){ - casename=$1 - host=$2 - user=$3 - cmd=$4 - - rnd=`head -c 20 /dev/urandom | base64` - echo $rnd > /names/$host - rm -f /tmp/$host.stderr - t=$($cmd 2>/tmp/$host.stderr) - - if [ "$t" != "$rnd" ];then - echo -e $casename $fail - exit 1 - else - echo -e $casename $succ - fi - - grep $rnd /workingdir/$user/* - - if [ $? -ne 0 ];then - echo -e "grep typescript logger" $fail - exit 1 - fi - - grep "hellopiper" /tmp/$host.stderr - - if [ $? -ne 0 ];then - echo -e "welcome text" $fail - exit 1 - fi -} - -runtest "host1 with public key:" "host1" "host1" "ssh -v host1@piper -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /local/id_rsa cat /names/host1" -runtest "host2 with password:" "host2" "host2" "sshpass -p root ssh -v host2@piper -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" - -#runtest "sqlite host2 with password:" "host2" "host2" "sshpass -p root ssh host2@piper_sqlite -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" -# runtest "mysql host2 with password:" "host2" "host2" "sshpass -p root ssh host2@piper_mysql -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" -# runtest "pg host2 with password:" "host2" "host2" "sshpass -p root ssh host2@piper_pg -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" -# runtest "msql host2 with password:" "host2" "host2" "sshpass -p root ssh host2@piper_mssql -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" - - -runtest "yaml host2 with password passthrough:" "host2" "passthrough" "sshpass -p root ssh passthrough@piper_yaml -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" -runtest "yaml host2 with password mappasspass:" "host2" "mappasspass" "sshpass -p pass ssh mappasspass@piper_yaml -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" -runtest "yaml host1 with password mappasskey:" "host1" "mappasskey" "sshpass -p pass ssh mappasskey@piper_yaml -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host1" -runtest "yaml host2 with password mapkeypass:" "host2" "mapkeypass" "ssh mapkeypass@piper_yaml -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /local/id_rsa2 cat /names/host2" -runtest "yaml host2 with key mapkeykey:" "host1" "mapkeykey" "ssh mapkeykey@piper_yaml -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /local/id_rsa2 cat /names/host1" -runtest "yaml host2 with key mapkeykey2:" "host1" "mapkeykey2" "ssh mapkeykey2@piper_yaml -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /local/id_rsa2 cat /names/host1" -runtest "yaml host2 with password regex:" "host2" "regex000" "sshpass -p root ssh regex000@piper_yaml -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" -runtest "yaml host1 with none host1:" "host1" "host1" "ssh host1@piper_yaml -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host1" - -# runtest "grpc host1 with remotesigner:" "host1" "host1" "ssh host1@piper_grpc_remotesigner_host1 -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PubkeyAuthentication=no -o PasswordAuthentication=no cat /names/host1" -# runtest "grpc host1 with privatekey:" "host1" "host1" "ssh host1@piper_grpc_privatekey_host1 -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PubkeyAuthentication=no -o PasswordAuthentication=no cat /names/host1" -# runtest "grpc host2 with password:" "host2" "host2" "sshpass -p wrongpassword ssh host2@piper_grpc_host2 -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" \ No newline at end of file diff --git a/sshpiperd/e2e/wait.sh b/sshpiperd/e2e/wait.sh deleted file mode 100755 index 422e38c2..00000000 --- a/sshpiperd/e2e/wait.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -for i in `seq 300`; do - nc -w 1 -z "$1" "$2" - if [ $? -eq 0 ]; then - break - fi - sleep 1 -done - -if [ -n "$3" ]; then - sleep $3; -fi \ No newline at end of file diff --git a/sshpiperd/example/showme.sh b/sshpiperd/example/showme.sh deleted file mode 100755 index aa4ab2ef..00000000 --- a/sshpiperd/example/showme.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -set -e - -CURRENT_DIR=$(dirname $(realpath $0)) -SSHPIPERD_SRC=$CURRENT_DIR/.. -BASEDIR=$(mktemp -d) -go build -o $BASEDIR/sshpiperd $SSHPIPERD_SRC - -SSHPIPERD_BIN="$BASEDIR/sshpiperd" - -if [ ! -f $BASEDIR/sshpiperd_key ];then - $SSHPIPERD_BIN genkey > $BASEDIR/sshpiperd_key -fi - -$SSHPIPERD_BIN pipe --upstream-workingdir=$BASEDIR/workingdir add -n github -u github.com --upstream-username git -$SSHPIPERD_BIN pipe --upstream-workingdir=$BASEDIR/workingdir add -n gitlab -u gitlab.com --upstream-username git -$SSHPIPERD_BIN pipe --upstream-workingdir=$BASEDIR/workingdir add -n bitbucket -u bitbucket.org --upstream-username git - -IFS=" -" - -echo "#### CURRENT PIPES" -echo "# " -echo "# test using ssh 127.0.0.1 -p 2222 -l username" -echo - -for p in `$SSHPIPERD_BIN pipe --upstream-workingdir=$BASEDIR/workingdir list`; do - user=`echo $p | cut -f 1 -d ' '` - echo "$p # ssh 127.0.0.1 -p 2222 -l $user" -done - -echo -echo "#### " -echo "#### git clone example" - -echo "# cp ~/.ssh/id_rsa $BASEDIR/workingdir/github/" -echo "# ssh-keygen -y -f ~/.ssh/id_rsa > $BASEDIR/workingdir/github/authorized_keys" -echo "# chmod 400 $BASEDIR/workingdir/github/authorized_keys" -echo "git clone git clone ssh://github@127.0.0.1:2222/[youruser]/[yourproj]# e.g. ssh://github@127.0.0.1:2222/tg123/sshpiper" - -echo "#### " -echo "Starting piper" - -$SSHPIPERD_BIN daemon -i $BASEDIR/sshpiperd_key --upstream-workingdir=$BASEDIR/workingdir diff --git a/sshpiperd/loader.go b/sshpiperd/loader.go deleted file mode 100644 index ab2d6c80..00000000 --- a/sshpiperd/loader.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - // _ "github.com/tg123/sshpiper/sshpiperd/upstream/database" - // _ "github.com/tg123/sshpiper/sshpiperd/upstream/grpcupstream" - // _ "github.com/tg123/sshpiper/sshpiperd/upstream/kubernetes" - _ "github.com/tg123/sshpiper/sshpiperd/upstream/workingdir" - _ "github.com/tg123/sshpiper/sshpiperd/upstream/yaml" - - // _ "github.com/tg123/sshpiper/sshpiperd/challenger/authy" - // _ "github.com/tg123/sshpiper/sshpiperd/challenger/azdevicecode" - // _ "github.com/tg123/sshpiper/sshpiperd/challenger/pome" - - _ "github.com/tg123/sshpiper/sshpiperd/auditor/typescriptlogger" -) diff --git a/sshpiperd/log.go b/sshpiperd/log.go deleted file mode 100644 index 97898a48..00000000 --- a/sshpiperd/log.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "os" - - log "github.com/sirupsen/logrus" -) - -type loggerConfig struct { - LogFile string `long:"log" description:"LogFile path. Leave empty or any error occurs will fall back to stdout" env:"SSHPIPERD_LOG_PATH" ini-name:"log-path"` - - LogLevel string `long:"log-level" default:"info" description:"These are the different logging levels, see https://pkg.go.dev/github.com/sirupsen/logrus#Level" env:"SSHPIPERD_LOG_LEVEL" ini-name:"log-level"` -} - -func (l loggerConfig) createLogger() (logger *log.Logger) { - - logger = log.New() - - if l.LogFile != "" { - f, err := os.OpenFile(l.LogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) - if err != nil { - logger.Printf("cannot open log file %v", err) - return - } - - logger.SetOutput(f) - } - - if l.LogLevel == "" { - l.LogLevel = "info" - } - - level, err := log.ParseLevel(l.LogLevel) - if err != nil { - log.Fatalf("parse log level %v error %v", l.LogLevel, err) - return - } - - logger.SetLevel(level) - - return -} diff --git a/sshpiperd/log_test.go b/sshpiperd/log_test.go deleted file mode 100644 index 840e21e9..00000000 --- a/sshpiperd/log_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "io/ioutil" - "os" - "strings" - "testing" -) - -func TestCreateLogger(t *testing.T) { - - // flags - { - logger := loggerConfig{LogLevel: "trace"}.createLogger() - - if logger.GetLevel().String() != "trace" { - t.Errorf("logger level not set") - } - } - - // file - { - tmpfile, err := ioutil.TempFile("", "sshpiperlog") - if err != nil { - t.Errorf("failed to create tmp file %v", err) - } - defer os.Remove(tmpfile.Name()) // clean up - - logger := loggerConfig{LogFile: tmpfile.Name()}.createLogger() - - logger.Print("test123") - - s, _ := ioutil.ReadFile(tmpfile.Name()) - - if !strings.Contains(string(s), "test123") { - - t.Errorf("log failed") - } - } -} diff --git a/sshpiperd/pipemgr.go b/sshpiperd/pipemgr.go deleted file mode 100644 index 815cbc02..00000000 --- a/sshpiperd/pipemgr.go +++ /dev/null @@ -1,89 +0,0 @@ -package main - -import ( - "fmt" - "os" - "text/template" - - "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -func createPipeMgr(load func() (upstream.Provider, error)) interface{} { - // pipe management - pipeMgrCmd := struct { - List struct { - subCommand - } `command:"list" description:"list all pipes"` - Add struct { - subCommand - - PiperUserName string `short:"n" long:"piper-username" description:"" required:"true" no-ini:"true"` - // PiperAuthorizedKeysFile flags.Filename - - UpstreamUserName string `long:"upstream-username" description:"mapped user name" no-ini:"true"` - UpstreamHost string `short:"u" long:"host" description:"upstream sshd host" required:"true" no-ini:"true"` - UpstreamPort int `short:"p" long:"port" description:"upstream sshd port" default:"22" no-ini:"true"` - // UpstreamKeyFile flags.Filename - - // UpstreamHostKey - // MapType - - } `command:"add" description:"add a pipe to current upstream"` - Remove struct { - subCommand - - Name string `short:"n" long:"piper-username" required:"true" no-ini:"true"` - } `command:"remove" description:"remove a pipe from current upstream"` - }{} - - pipeMgrCmd.List.callback = func(args []string) error { - p, err := load() - if err != nil { - return err - } - - // opt := pipeMgrCmd.List - pipes, err := p.ListPipe() - if err != nil { - return err - } - - t := template.Must(template.New("").Parse(`{{.Username}} -> {{.UpstreamUsername}}@{{.Host}}:{{.Port}}`)) - - for _, pipe := range pipes { - _ = t.Execute(os.Stdout, pipe) - fmt.Println() - } - - return nil - } - - pipeMgrCmd.Add.callback = func(args []string) error { - p, err := load() - if err != nil { - return err - } - - opt := pipeMgrCmd.Add - - return p.CreatePipe(upstream.CreatePipeOption{ - Username: opt.PiperUserName, - UpstreamUsername: opt.UpstreamUserName, - Host: opt.UpstreamHost, - Port: opt.UpstreamPort, - }) - } - - pipeMgrCmd.Remove.callback = func(args []string) error { - p, err := load() - if err != nil { - return err - } - - opt := pipeMgrCmd.Remove - - return p.RemovePipe(opt.Name) - } - - return &pipeMgrCmd -} diff --git a/sshpiperd/registry/plugin.go b/sshpiperd/registry/plugin.go deleted file mode 100644 index 6a9fb145..00000000 --- a/sshpiperd/registry/plugin.go +++ /dev/null @@ -1,19 +0,0 @@ -package registry - -import ( - log "github.com/sirupsen/logrus" -) - -// Plugin is to be registered with sshpiper to provide additional functions -type Plugin interface { - - // The name of the Plugin - GetName() string - - // A ref to a struct which holds the options for the plugins - // will be populated by cmd or other plugin runners - GetOpts() interface{} - - // Will be called before the Plugin is used to ensure the Plugin is ready - Init(logger *log.Logger) error -} diff --git a/sshpiperd/registry/registry.go b/sshpiperd/registry/registry.go deleted file mode 100644 index 28e6024a..00000000 --- a/sshpiperd/registry/registry.go +++ /dev/null @@ -1,51 +0,0 @@ -package registry - -import ( - "sort" - "sync" -) - -// Registry is a place to hold all plugins -type Registry struct { - driversMu sync.RWMutex - drivers map[string]interface{} -} - -// NewRegistry creates a new Registry -func NewRegistry() *Registry { - return &Registry{drivers: make(map[string]interface{})} -} - -// Register adds a Plugin with given name to Registry -func (r *Registry) Register(name string, driver interface{}) { - // copy from database/sql - r.driversMu.Lock() - defer r.driversMu.Unlock() - if driver == nil { - panic("Register driver is nil") - } - if _, dup := r.drivers[name]; dup { - panic("Register called twice for driver " + name) - } - r.drivers[name] = driver -} - -// Drivers return all registered Plugins -func (r *Registry) Drivers() []string { - r.driversMu.RLock() - defer r.driversMu.RUnlock() - var list []string - for name := range r.drivers { - list = append(list, name) - } - sort.Strings(list) - return list -} - -// Get returns an Plugins by name, return nil if not found -func (r *Registry) Get(name string) interface{} { - r.driversMu.RLock() - defer r.driversMu.RUnlock() - - return r.drivers[name] -} diff --git a/sshpiperd/registry/registry_test.go b/sshpiperd/registry/registry_test.go deleted file mode 100644 index ca940321..00000000 --- a/sshpiperd/registry/registry_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package registry - -import ( - "reflect" - "testing" - - log "github.com/sirupsen/logrus" -) - -type testplugin struct { - name string -} - -func (p *testplugin) GetName() string { - return p.name -} - -func (p *testplugin) GetOpts() interface{} { - return nil -} - -func (p *testplugin) Init(logger *log.Logger) error { - return nil -} - -func TestRegistry_Register(t *testing.T) { - r := NewRegistry() - - r.Register("x", &testplugin{"x"}) - r.Register("y", &testplugin{"y"}) - - if r.Get("x") == nil { - t.Errorf("cannot find x in registry") - } - - all := r.Drivers() - - if !reflect.DeepEqual(all, []string{"x", "y"}) { - t.Errorf("should contain x y in registry") - } - - if r.Get("z") != nil { - t.Errorf("should not find z in registry") - } - - // duplicate name - func() { - defer func() { - if r := recover(); r == nil { - t.Errorf("should panic") - } - }() - - r := NewRegistry() - r.Register("x", &testplugin{"x"}) - r.Register("x", &testplugin{"x"}) - - }() - - // nil driver - func() { - defer func() { - if r := recover(); r == nil { - t.Errorf("should panic") - } - }() - - r := NewRegistry() - r.Register("nil", nil) - }() -} diff --git a/sshpiperd/snap/docker-compose.yml b/sshpiperd/snap/docker-compose.yml deleted file mode 100644 index 6886afd0..00000000 --- a/sshpiperd/snap/docker-compose.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: '3' - -services: - snap: - image: snapcore/snapcraft - volumes: - - build:/build - - stage:/stage - - ./snapcraft.yaml:/stage/snapcraft.yaml - - ./snap:/stage/snap - - .:/output - working_dir: /stage - depends_on: - - piper - command: - - "/bin/sh" - - "-c" - - "snapcraft clean && snapcraft && cp /stage/*.snap /output" - piper: - build: - context: ../.. - args: - - VER=devel - volumes: - - build:/build - command: - - "/bin/sh" - - "-c" - - "/bin/cp /sshpiperd /build/sshpiperd && /build/sshpiperd version && sleep 1h" -volumes: - build: - stage: diff --git a/sshpiperd/snap/snap/hooks/configure b/sshpiperd/snap/snap/hooks/configure deleted file mode 100755 index 8f332dd8..00000000 --- a/sshpiperd/snap/snap/hooks/configure +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -set -e - -bin=$SNAP/sshpiperd -config=$SNAP_DATA/sshpiperd.ini - -args="" -for opt in $($bin daemon options); do - v=$(snapctl get $opt) - - if [ "$v" != "" ]; then - v=$(eval echo $v) - - if [ "$v" = "true" ];then - args="$args --$opt" - else - args="$args --$opt=$v" - fi - - # special default - elif [ "$opt" = "upstream-workingdir" ]; then - mkdir -p $SNAP_COMMON/workingdir - args="$args --$opt=$SNAP_COMMON/workingdir" - elif [ "$opt" = "upstream-sqlite-dbfile" ]; then - args="$args --$opt=$SNAP_COMMON/sshpiperd.sqlite3" - elif [ "$opt" = "auditor-typescriptlogger-outputdir" ]; then - mkdir -p $SNAP_COMMON/typescriptlog - args="$args --$opt=$SNAP_COMMON/typescriptlog" - elif [ "$opt" = "server-key" ]; then - args="$args --$opt=$SNAP_COMMON/host_rsa_key" - elif [ "$opt" = "log-flags" ]; then - args="$args --$opt=0" - fi -done - -echo ";DO NOT MODIFY, USE snap set sshpiperd key=val, AUTO GENERATED" $(date) > $config -$bin daemon --config /dev/null $args dumpconfig >> $config diff --git a/sshpiperd/snap/snap/hooks/install b/sshpiperd/snap/snap/hooks/install deleted file mode 100755 index d13297f3..00000000 --- a/sshpiperd/snap/snap/hooks/install +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -set -e - -bin=$SNAP/sshpiperd -key=$SNAP_COMMON/host_rsa_key - -$bin genkey > $key diff --git a/sshpiperd/snap/snapcraft.yaml b/sshpiperd/snap/snapcraft.yaml deleted file mode 100644 index c7fea44d..00000000 --- a/sshpiperd/snap/snapcraft.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: sshpiperd -version: devel -summary: The missing reverse proxy for ssh scp -description: | - SSH Piper works as a proxy-like ware, and route connections by username, src ip , etc. -grade: stable -confinement: strict -parts: - sshpiperd: - plugin: dump - source: /build -apps: - sshpiperd-daemon: - command: sshpiperd daemon --config $SNAP_DATA/sshpiperd.ini - plugs: [network-bind] - daemon: simple - sshpiperd: - command: sshpiperd --config $SNAP_DATA/sshpiperd.ini -hooks: - configure: - plugs: [home] - install: - plugs: [home] diff --git a/sshpiperd/sshpiperd.go b/sshpiperd/sshpiperd.go deleted file mode 100644 index 17818497..00000000 --- a/sshpiperd/sshpiperd.go +++ /dev/null @@ -1,272 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "net" - "path/filepath" - "time" - - "golang.org/x/crypto/ssh" - - log "github.com/sirupsen/logrus" - - "github.com/tg123/sshpiper/sshpiperd/auditor" - "github.com/tg123/sshpiper/sshpiperd/registry" - "github.com/tg123/sshpiper/sshpiperd/upstream" - "github.com/tg123/sshpiper/sshpiperd/v0bridge" -) - -type piperdConfig struct { - ListenAddr string `short:"l" long:"listen" description:"Listening Address" default:"0.0.0.0" env:"SSHPIPERD_LISTENADDR" ini-name:"listen-address"` - Port uint `short:"p" long:"port" description:"Listening Port" default:"2222" env:"SSHPIPERD_PORT" ini-name:"listen-port"` - PiperKeyFile string `short:"i" long:"server-key" description:"Server key file for SSH Piper" default:"/etc/ssh/ssh_host_rsa_key" env:"SSHPIPERD_SERVER_KEY" ini-name:"server-key"` - LoginGraceTime time.Duration `long:"login-grace-time" description:"Piper disconnects after this time if the pipe has not successfully established" default:"30s" env:"SSHPIPERD_LOGIN_GRACETIME" ini-name:"login-grace-time"` - - UpstreamDriver string `short:"u" long:"upstream-driver" description:"Upstream provider driver" default:"workingdir" env:"SSHPIPERD_UPSTREAM_DRIVER" ini-name:"upstream-driver"` - ChallengerDriver string `short:"c" long:"challenger-driver" description:"Additional challenger name, e.g. pam, empty for no additional challenge" env:"SSHPIPERD_CHALLENGER" ini-name:"challenger-driver"` - AuditorDriver string `long:"auditor-driver" description:"Auditor for ssh connections piped by SSH Piper" env:"SSHPIPERD_AUDITOR" ini-name:"auditor-driver"` - - BannerText string `long:"banner-text" description:"Display a banner before authentication, would be ignored if banner file was set" env:"SSHPIPERD_BANNERTEXT" ini-name:"banner-text" ` - BannerFile string `long:"banner-file" description:"Display a banner from file before authentication" env:"SSHPIPERD_BANNERFILE" ini-name:"banner-file" ` -} - -func getAndInstall(reg, name string, get func(n string) registry.Plugin, install func(plugin registry.Plugin) error, logger *log.Logger) error { - if name == "" { - return nil - } - - p := get(name) - - if p == nil { - return fmt.Errorf("%v driver %v not found", reg, name) - } - - err := p.Init(logger) - if err != nil { - return err - } - return install(p) -} - -func installDrivers(piper *ssh.PiperConfig, config *piperdConfig, logger *log.Logger) (auditor.Provider, error) { - - // install upstreamProvider driver - if config.UpstreamDriver == "" { - return nil, fmt.Errorf("must provider upstream driver") - } - - var bigbro auditor.Provider - - for _, d := range []struct { - reg string - name string - get func(n string) registry.Plugin - install func(plugin registry.Plugin) error - }{ - // upstream driver - { - "Upstream", - config.UpstreamDriver, - func(n string) registry.Plugin { - return upstream.Get(n) - }, - func(plugin registry.Plugin) error { - - v1, ok := plugin.(upstream.V1Provider) - if ok { - return v1.InstallUpstream(piper) - } - - handler := plugin.(upstream.Provider).GetHandler() - - if handler == nil { - return fmt.Errorf("upstream driver return nil handler") - } - - v0bridge.InstallUpstream(piper, func(conn ssh.ConnMetadata, challengeCtx ssh.ChallengeContext) (net.Conn, *v0bridge.AuthPipe, error) { - c, a, err := handler(conn, challengeCtx) - if err != nil { - logger.Errorf("upstream driver [%v] cannot find upstream due to [%v]", plugin.GetName(), err) - } else { - logger.Debugf("upstream driver [%v] found upstream connection [%v]", plugin.GetName(), c.RemoteAddr().String()) - } - - return c, a, err - }) - return nil - }, - }, - // challenger driver - // { - // "Challenger", - // config.ChallengerDriver, - // func(n string) registry.Plugin { - // return challenger.Get(n) - // }, - // func(plugin registry.Plugin) error { - // handler := plugin.(challenger.Provider).GetHandler() - - // if handler == nil { - // return fmt.Errorf("challenger driver return nil handler") - // } - - // piper.AdditionalChallenge = func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (ssh.AdditionalChallengeContext, error) { - // c, err := handler(conn, client) - // if err != nil { - // logger.Errorf("challenger [%v] failed [%v]", plugin.GetName(), err) - // } else { - // if c != nil { - // logger.Infof("challenger [%v] success with challenged username [%v]", plugin.GetName(), c.ChallengedUsername()) - // } else { - // logger.Debugf("challenger [%v] success with empty context", plugin.GetName()) - // } - // } - - // return c, err - // } - - // return nil - // }, - // }, - // auditor driver - { - "Auditor", - config.AuditorDriver, - func(n string) registry.Plugin { - return auditor.Get(n) - }, - func(plugin registry.Plugin) error { - bigbro = plugin.(auditor.Provider) - return nil - }, - }, - } { - err := getAndInstall(d.reg, d.name, d.get, d.install, logger) - if err != nil { - return nil, err - } - } - - return bigbro, nil -} - -func startPiper(config *piperdConfig, logger *log.Logger) error { - - logger.Println("sshpiper is about to start") - - piper := &ssh.PiperConfig{} - - // // drivers - bigbro, err := installDrivers(piper, config, logger) - if err != nil { - return err - } - - // listeners - privateKeys, err := filepath.Glob(config.PiperKeyFile) - if err != nil { - return err - } - - logger.Println("Found host keys", privateKeys) - for _, privateKey := range privateKeys { - logger.Println("Loading host key", privateKey) - privateBytes, err := ioutil.ReadFile(privateKey) - if err != nil { - return err - } - - private, err := ssh.ParsePrivateKey(privateBytes) - if err != nil { - return err - } - - piper.AddHostKey(private) - } - - listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.ListenAddr, config.Port)) - if err != nil { - return fmt.Errorf("failed to listen for connection: %v", err) - } - defer listener.Close() - - // banner - if config.BannerFile != "" { - piper.BannerCallback = func(conn ssh.ConnMetadata, _ ssh.ChallengeContext) string { - msg, err := ioutil.ReadFile(config.BannerFile) - - if err != nil { - logger.Printf("failed to read banner file: %v", err) - return "" - } - - return string(msg) - } - } else if config.BannerText != "" { - piper.BannerCallback = func(conn ssh.ConnMetadata, _ ssh.ChallengeContext) string { - return config.BannerText + "\n" - } - } - - logger.Printf("sshpiperd started") - - for { - conn, err := listener.Accept() - if err != nil { - logger.Debugf("failed to accept connection: %v", err) - continue - } - - logger.Debugf("connection accepted: %v", conn.RemoteAddr()) - - go func(c net.Conn) { - defer c.Close() - - pipec := make(chan *ssh.PiperConn) - errorc := make(chan error) - - go func() { - p, err := ssh.NewSSHPiperConn(c, piper) - - if err != nil { - errorc <- err - return - } - - pipec <- p - }() - - var p *ssh.PiperConn - - select { - case p = <-pipec: - case err := <-errorc: - logger.Debugf("connection from %v establishing failed reason: %v", c.RemoteAddr(), err) - return - case <-time.After(config.LoginGraceTime): - logger.Debugf("pipe establishing timeout, disconnected connection from %v", c.RemoteAddr()) - return - } - - defer p.Close() - - logger.Infof("ssh connection accepted from %v", c.RemoteAddr()) - if bigbro != nil { - a, err := bigbro.Create(p.DownstreamConnMeta()) - if err != nil { - logger.Printf("connection from %v failed to create auditor reason: %v", c.RemoteAddr(), err) - return - } - defer a.Close() - - err = p.WaitWithHook(a.GetUpstreamHook(), a.GetDownstreamHook()) - } else { - err = p.Wait() - - } - - logger.Infof("connection from %v closed reason: %v", c.RemoteAddr(), err) - }(conn) - } -} diff --git a/sshpiperd/sshpiperd_test.go b/sshpiperd/sshpiperd_test.go deleted file mode 100644 index ba46bd18..00000000 --- a/sshpiperd/sshpiperd_test.go +++ /dev/null @@ -1,362 +0,0 @@ -package main - -import ( - "testing" - - log "github.com/sirupsen/logrus" - - "fmt" - "net" - "time" - - "github.com/tg123/sshpiper/sshpiperd/auditor" - "github.com/tg123/sshpiper/sshpiperd/challenger" - "github.com/tg123/sshpiper/sshpiperd/registry" - "github.com/tg123/sshpiper/sshpiperd/upstream" - "golang.org/x/crypto/ssh" -) - -type testplugin struct { - name string - init func(logger *log.Logger) error -} - -func (p *testplugin) GetName() string { - return p.name -} - -func (p *testplugin) GetOpts() interface{} { - return nil -} - -func (p *testplugin) Init(logger *log.Logger) error { - if p.init == nil { - return nil - } - return p.init(logger) -} - -func Test_getAndInstall(t *testing.T) { - var err error - - // ignore empty - _ = getAndInstall("", "", func(n string) registry.Plugin { - t.Errorf("should not call get") - return nil - }, func(plugin registry.Plugin) error { - t.Errorf("should not call install") - return nil - }, log.StandardLogger()) - - // fail when not found - err = getAndInstall("", "test", func(n string) registry.Plugin { - if n != "test" { - t.Errorf("plugin name changed") - } - return nil - }, func(plugin registry.Plugin) error { - t.Errorf("should not call install") - return nil - }, log.StandardLogger()) - - if err == nil { - t.Errorf("should err when not found") - } - - // init err - err = getAndInstall("", "test", func(n string) registry.Plugin { - return &testplugin{ - init: func(logger *log.Logger) error { - return fmt.Errorf("init failed") - }, - } - }, func(plugin registry.Plugin) error { - return fmt.Errorf("test") - }, log.StandardLogger()) - - if err == nil { - t.Errorf("should err when not found") - } - - // call init - inited := false - installed := false - err = getAndInstall("", "test", func(n string) registry.Plugin { - if n != "test" { - t.Errorf("plugin name changed") - } - return &testplugin{ - init: func(logger *log.Logger) error { - inited = true - return nil - }, - } - }, func(plugin registry.Plugin) error { - if !inited { - t.Errorf("not inited") - } - - installed = true - return nil - }, log.StandardLogger()) - - if !installed { - t.Errorf("not installed") - } - - if err != nil { - t.Errorf("should err when not found") - } -} - -type testupstream struct { - testplugin - - h upstream.Handler -} - -func (t *testupstream) ListPipe() ([]upstream.Pipe, error) { - return nil, nil -} - -func (t *testupstream) CreatePipe(opt upstream.CreatePipeOption) error { - return nil -} - -func (t *testupstream) RemovePipe(name string) error { - return nil -} - -func (t *testupstream) GetHandler() upstream.Handler { - return t.h -} - -type testchallenger struct { - testplugin - - h challenger.Handler -} - -func (t *testchallenger) GetHandler() challenger.Handler { - return t.h -} - -type testauditorprovider struct { - testplugin - - a auditor.Auditor -} - -func (t *testauditorprovider) Create(ssh.ConnMetadata) (auditor.Auditor, error) { - return t.a, nil -} - -type testauditor struct { - up auditor.Hook - down auditor.Hook -} - -func (t *testauditor) GetUpstreamHook() auditor.Hook { - return t.up -} - -func (t *testauditor) GetDownstreamHook() auditor.Hook { - return t.down -} - -func (t *testauditor) Close() error { - return nil -} - -func Test_installDriver(t *testing.T) { - var ( - upstreamName = fmt.Sprintf("u_%v", time.Now().UTC().UnixNano()) - challengerName = fmt.Sprintf("c_%v", time.Now().UTC().UnixNano()) - auditorName = fmt.Sprintf("a_%v", time.Now().UTC().UnixNano()) - upstreamErrName = fmt.Sprintf("ue_%v", time.Now().UTC().UnixNano()) - upstreamNilName = fmt.Sprintf("un_%v", time.Now().UTC().UnixNano()) - ) - - findUpstream := func(conn ssh.ConnMetadata, challengeContext ssh.AdditionalChallengeContext) (net.Conn, *ssh.AuthPipe, error) { - c, s := net.Pipe() - defer c.Close() - defer s.Close() - return c, nil, nil - } - - upstream.Register(upstreamName, &testupstream{ - testplugin: testplugin{ - name: upstreamName, - }, - h: findUpstream, - }) - - upstream.Register(upstreamErrName, &testupstream{ - testplugin: testplugin{ - name: upstreamErrName, - init: func(logger *log.Logger) error { - return fmt.Errorf("test err") - }, - }, - h: findUpstream, - }) - - upstream.Register(upstreamNilName, &testupstream{ - testplugin: testplugin{ - name: upstreamNilName, - }, - h: nil, - }) - - challenger.Register(challengerName, &testchallenger{ - testplugin: testplugin{ - name: upstreamName, - }, - h: func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (ssh.AdditionalChallengeContext, error) { - return nil, nil - }, - }) - - auditor.Register(auditorName, &testauditorprovider{}) - - // empty driver name - { - piper := &ssh.PiperConfig{} - _, err := installDrivers(piper, &piperdConfig{ - UpstreamDriver: "", - }, log.StandardLogger()) - - if err == nil { - t.Errorf("should fail when empty driver") - } - } - - // install upstream - { - piper := &ssh.PiperConfig{} - _, err := installDrivers(piper, &piperdConfig{ - UpstreamDriver: upstreamName, - }, log.StandardLogger()) - - if err != nil { - t.Errorf("install failed %v", err) - } - - if _, _, err := piper.FindUpstream(nil, nil); err != nil { - t.Errorf("install wrong func") - } - - if piper.AdditionalChallenge != nil { - t.Errorf("should not install challenger") - } - } - - // install upstream with failed init - { - piper := &ssh.PiperConfig{} - _, err := installDrivers(piper, &piperdConfig{ - UpstreamDriver: upstreamErrName, - }, log.StandardLogger()) - - if err == nil { - t.Errorf("install should fail") - } - - if piper.FindUpstream != nil { - t.Errorf("should not install upstream provider") - } - - if piper.AdditionalChallenge != nil { - t.Errorf("should not install challenger") - } - } - - // install upstream with nil handler - { - piper := &ssh.PiperConfig{} - _, err := installDrivers(piper, &piperdConfig{ - UpstreamDriver: upstreamNilName, - }, log.StandardLogger()) - - if err == nil { - t.Errorf("install should fail") - } - - if piper.FindUpstream != nil { - t.Errorf("should not install upstream provider") - } - - if piper.AdditionalChallenge != nil { - t.Errorf("should not install challenger") - } - } - - // install challenger - { - piper := &ssh.PiperConfig{} - _, err := installDrivers(piper, &piperdConfig{ - UpstreamDriver: upstreamName, - ChallengerDriver: challengerName, - }, log.StandardLogger()) - - if err != nil { - t.Errorf("install failed %v", err) - } - - if _, err := piper.AdditionalChallenge(nil, nil); err != nil { - t.Errorf("should install challenger") - } - } - - // install auditor - { - piper := &ssh.PiperConfig{} - ap, err := installDrivers(piper, &piperdConfig{ - UpstreamDriver: upstreamName, - AuditorDriver: auditorName, - }, log.StandardLogger()) - - if err != nil { - t.Errorf("install failed %v", err) - } - - if ap == nil { - t.Errorf("nil auditor provider") - } - - ap0 := ap.(*testauditorprovider) - - ap0.a = &testauditor{ - up: func(conn ssh.ConnMetadata, msg []byte) ([]byte, error) { - msg[0] = 42 - return msg, nil - }, - down: func(conn ssh.ConnMetadata, msg []byte) ([]byte, error) { - msg[0] = 100 - return msg, nil - }, - } - - a, err := ap.Create(nil) - if err != nil { - t.Errorf("install failed %v", err) - } - - m := []byte{0} - - if _, err := a.GetUpstreamHook()(nil, m); err != nil { - t.Errorf("run upstream hook %v", err) - } - - if m[0] != 42 { - t.Errorf("upstream not handled") - } - - if _, err := a.GetDownstreamHook()(nil, m); err != nil { - t.Errorf("run downstream hook %v", err) - } - if m[0] != 100 { - t.Errorf("downstream not handled") - } - } -} diff --git a/sshpiperd/upstream/database/README.md b/sshpiperd/upstream/database/README.md deleted file mode 100644 index aac54de1..00000000 --- a/sshpiperd/upstream/database/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Database upstream for SSHPiper - -Database is a ideally place to store upstream and downstream relationship. sshpiperd provides 4 database support: - - * MySQL - * PostgreSQL - * SQLite 3 - * SQL Server - -![Imgur](https://i.imgur.com/lxdIK3K.png) - -You may want to use `sshpiperd pipe add ` to manage them. diff --git a/sshpiperd/upstream/database/handler.go b/sshpiperd/upstream/database/handler.go deleted file mode 100644 index a13c168e..00000000 --- a/sshpiperd/upstream/database/handler.go +++ /dev/null @@ -1,256 +0,0 @@ -package database - -import ( - "bytes" - "fmt" - "net" - - "github.com/jinzhu/gorm" - - "golang.org/x/crypto/ssh" - "golang.org/x/crypto/ssh/knownhosts" - - upstreamprovider "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -type pipeConfig struct { - Username string - UpstreamHost string - MappedUsername string - FromType authMapType - FromPassword string - FromPrivateKey keydata - FromAuthorizedKeys keydata - FromAllowAnyPublicKey bool - ToType authMapType - ToPassword string - ToPrivateKey keydata - ToAuthorizedKeys keydata - NoPassthrough bool - KnownHosts string - KnownHostsData string - IgnoreHostkey bool -} - -func (p *plugin) loadPipeFromDB(conn ssh.ConnMetadata) (pipeConfig, error) { - - user := conn.User() - d, err := lookupDownstreamWithFallback(p.db, user) - - if err != nil { - return pipeConfig{}, err - } - - pipe := pipeConfig{ - Username: user, - UpstreamHost: d.Upstream.Server.Address, - MappedUsername: d.Upstream.Username, - FromType: d.AuthMapType, - FromPassword: d.Password, - FromAuthorizedKeys: d.AuthorizedKeys, - FromAllowAnyPublicKey: d.AllowAnyPublicKey, - ToType: d.Upstream.AuthMapType, - ToPassword: d.Upstream.Password, - ToPrivateKey: d.Upstream.PrivateKey, - NoPassthrough: d.NoPassthrough, - KnownHosts: d.Upstream.KnownHosts, - IgnoreHostkey: d.Upstream.Server.IgnoreHostKey, - } - - return pipe, nil -} - -func (p *plugin) createAuthPipe(pipe pipeConfig, conn ssh.ConnMetadata, challengeContext ssh.AdditionalChallengeContext) (*ssh.AuthPipe, error) { - - hostKeyCallback := ssh.InsecureIgnoreHostKey() - if !pipe.IgnoreHostkey { - - var err error - data := []byte(pipe.KnownHosts) - - if len(data) == 0 { - return nil, fmt.Errorf("no known hosts specified") - } - - hostKeyCallback, err = knownhosts.NewFromReader(bytes.NewReader(data)) - if err != nil { - return nil, err - } - } - - to := func() (ssh.AuthPipeType, ssh.AuthMethod, error) { - switch pipe.ToType { - case authMapTypeNone: - return ssh.AuthPipeTypeNone, nil, nil - - case authMapTypePassword: - return ssh.AuthPipeTypeMap, ssh.Password(pipe.ToPassword), nil - - case authMapTypePrivateKey: - privateBytes := []byte(pipe.ToPrivateKey.Data) - - if len(privateBytes) == 0 { - return ssh.AuthPipeTypeDiscard, nil, fmt.Errorf("no private key found") - } - - private, err := ssh.ParsePrivateKey(privateBytes) - if err != nil { - return ssh.AuthPipeTypeDiscard, nil, err - } - - return ssh.AuthPipeTypeMap, ssh.PublicKeys(private), nil - - default: - logger.Printf("unsupport type [%v] fallback to passthrough", pipe.ToType) - } - - if pipe.NoPassthrough { - return ssh.AuthPipeTypeDiscard, nil, nil - } - - return ssh.AuthPipeTypePassThrough, nil, nil - } - - a := &ssh.AuthPipe{ - User: pipe.MappedUsername, - UpstreamHostKeyCallback: hostKeyCallback, - } - - noneauth := func(conn ssh.ConnMetadata) (ssh.AuthPipeType, ssh.AuthMethod, error) { - return to() - } - - passauth := func(conn ssh.ConnMetadata, password []byte) (ssh.AuthPipeType, ssh.AuthMethod, error) { - if string(password) == pipe.FromPassword { - return to() - } - - if pipe.NoPassthrough { - return ssh.AuthPipeTypeDiscard, nil, nil - } - - return ssh.AuthPipeTypePassThrough, nil, nil - } - - var allowPubKeys []ssh.PublicKey - allowAnyPubKey := pipe.FromAllowAnyPublicKey - if !allowAnyPubKey { - var err error - rest := []byte(pipe.FromAuthorizedKeys.Data) - - var authedPubkey ssh.PublicKey - - for len(rest) > 0 { - authedPubkey, _, _, rest, err = ssh.ParseAuthorizedKey(rest) - if err != nil { - return nil, err - } - - allowPubKeys = append(allowPubKeys, authedPubkey) - } - } - - keyuath := func(conn ssh.ConnMetadata, key ssh.PublicKey) (ssh.AuthPipeType, ssh.AuthMethod, error) { - - if allowAnyPubKey { - return to() - } - - keydata := key.Marshal() - - for _, authedPubkey := range allowPubKeys { - if bytes.Equal(authedPubkey.Marshal(), keydata) { - return to() - } - } - - if pipe.NoPassthrough { - return ssh.AuthPipeTypeDiscard, nil, nil - } - - // will fail but discard will lead a timeout - return ssh.AuthPipeTypePassThrough, nil, nil - } - - switch pipe.FromType { - case authMapTypeNone: - a.NoneAuthCallback = noneauth - - case authMapTypePassword: - a.PasswordCallback = passauth - - case authMapTypePrivateKey: - a.PublicKeyCallback = keyuath - - case authMapTypeAny: - a.NoneAuthCallback = noneauth - a.PasswordCallback = passauth - a.PublicKeyCallback = keyuath - - default: - return nil, fmt.Errorf("unsupported auth type [%v],", pipe.FromType) - } - - return a, nil - -} - -func (p *plugin) findUpstream(conn ssh.ConnMetadata, challengeContext ssh.AdditionalChallengeContext) (net.Conn, *ssh.AuthPipe, error) { - - pipe, err := p.loadPipeFromDB(conn) - if err != nil { - return nil, nil, err - } - - if pipe.Username != "" { - - logger.Printf("mapping [%v] to [%v@%v] from %v to %v", pipe.Username, pipe.MappedUsername, pipe.UpstreamHost, pipe.FromType, pipe.ToType) - - c, err := upstreamprovider.DialForSSH(pipe.UpstreamHost) - if err != nil { - return nil, nil, err - } - a, err := p.createAuthPipe(pipe, conn, challengeContext) - if err != nil { - return nil, nil, err - } - return c, a, nil - } - - return nil, nil, fmt.Errorf("username should not be empty") - -} - -func lookupDownstreamWithFallback(db *gorm.DB, user string) (*downstream, error) { - d, err := lookupDownstream(db, user) - - if gorm.IsRecordNotFoundError(err) { - fallback, _ := lookupConfigValue(db, fallbackUserEntry) - - if len(fallback) > 0 { - return lookupDownstream(db, fallback) - } - } - - return d, err -} - -func lookupDownstream(db *gorm.DB, user string) (*downstream, error) { - d := downstream{} - - if err := db.Set("gorm:auto_preload", true).Where(&downstream{Username: user}).First(&d).Error; err != nil { - - return nil, err - } - - return &d, nil -} - -func lookupConfigValue(db *gorm.DB, entry string) (string, error) { - c := config{} - if err := db.Where(&config{Entry: entry}).First(&c).Error; err != nil { - return "", err - } - - return c.Value, nil -} diff --git a/sshpiperd/upstream/database/handler_test.go b/sshpiperd/upstream/database/handler_test.go deleted file mode 100644 index d761f4ce..00000000 --- a/sshpiperd/upstream/database/handler_test.go +++ /dev/null @@ -1,202 +0,0 @@ -package database - -import ( - "net" - "testing" - - log "github.com/sirupsen/logrus" - - "github.com/tg123/sshkey" - "golang.org/x/crypto/ssh" - - "github.com/jinzhu/gorm" - upstreamprovider "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -func generateKeyPair() (string, string, error) { - priv, err := sshkey.GenerateKey(sshkey.KEY_RSA, 2048) - if err != nil { - return "", "", err - } - - privb, err := sshkey.MarshalPrivate(priv, "") - if err != nil { - return "", "", err - } - - pub := sshkey.NewPublic(priv, "") - - return string(sshkey.MarshalPublic(pub)), string(privb), nil - -} - -func newTestPlugin(t *testing.T) *plugin { - p := upstreamprovider.Get("sqlite").(*sqliteplugin) - - p.Config.File = "file::memory:?mode=memory&cache=shared" - - err := p.Init(log.New()) - if err != nil { - t.Fatal(err) - } - - return &p.plugin -} - -type testconn struct { - user string -} - -func (c testconn) User() string { - return c.user -} - -func (testconn) SessionID() []byte { - return nil -} - -func (testconn) ClientVersion() []byte { - return nil -} - -func (testconn) ServerVersion() []byte { - return nil -} - -func (testconn) RemoteAddr() net.Addr { - return nil -} - -func (testconn) LocalAddr() net.Addr { - return nil -} - -func createEntry(t *testing.T, db *gorm.DB, downUser, upUser, serverAddr string, ignoreServerKey bool) (string, string) { - - pub, priv, err := generateKeyPair() - - if err != nil { - t.Fatal(err) - } - - err = db.Create(&downstream{ - Username: downUser, - AuthMapType: authMapTypeAny, - AuthorizedKeys: keydata{ - Data: pub, - Type: "rsa", - }, - Upstream: upstream{ - Username: upUser, - AuthMapType: authMapTypePrivateKey, - PrivateKey: keydata{ - Data: priv, - Type: "rsa", - }, - Server: server{ - Address: serverAddr, - IgnoreHostKey: ignoreServerKey, - HostKey: keydata{ - Data: pub, - Type: "rsa", - }, - }, - }, - }).Error - - if err != nil { - t.Fatal(err) - } - - return pub, priv -} - -func TestFindUpstream(t *testing.T) { - - p := newTestPlugin(t) - defer p.db.Close() - db := p.db - h := p.GetHandler() - - listener, err := createListener(t) - if err != nil { - t.Fatal(err) - } - defer listener.Close() - - createEntry(t, db, "finddown0", "findup0", listener.Addr().String(), true) - createEntry(t, db, "finddown1", "findup1", listener.Addr().String(), true) - createEntry(t, db, "finddown2", "findup2", listener.Addr().String(), true) - - _, auth, err := h(testconn{"finddown0"}, nil) - if err != nil { - t.Fatal(err) - } - - if auth.User != "findup0" { - t.Error("auth pipe user name is not correct") - } - - db.Delete(&config{Entry: fallbackUserEntry}) - _, _, err = h(testconn{"not_exists"}, nil) - if err == nil { - t.Error("should not found any user") - } - - db.NewRecord(&config{Entry: fallbackUserEntry, Value: "findup0"}) - _, auth, err = h(testconn{"finddown0"}, nil) - if err != nil { - t.Fatal(err) - } - if auth.User != "findup0" { - t.Error("auth pipe user name is not correct (fallback)") - } -} - -func TestPublicKeyCallback(t *testing.T) { - - p := newTestPlugin(t) - defer p.db.Close() - db := p.db - h := p.GetHandler() - - listener, err := createListener(t) - if err != nil { - t.Fatal(err) - } - defer listener.Close() - - pub, _ := createEntry(t, db, "pkdown", "pkdown", listener.Addr().String(), true) - - _, auth, err := h(testconn{"pkdown"}, nil) - if err != nil { - t.Fatal(err) - } - - publicKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(pub)) - if err != nil { - t.Fatal(err) - } - - authType, method, err := auth.PublicKeyCallback(nil, publicKey) - if err != nil { - t.Fatal(err) - } - - if authType != ssh.AuthPipeTypeMap { - t.Error("auth type map should be AuthPipeTypeMap") - } - - if method == nil { - t.Error("auth method is missing") - } -} - -func createListener(t *testing.T) (net.Listener, error) { - listener, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatalf("cant create fake server: %v", err) - } - // go listener.Accept() - return listener, err -} diff --git a/sshpiperd/upstream/database/model.go b/sshpiperd/upstream/database/model.go deleted file mode 100644 index fd85593e..00000000 --- a/sshpiperd/upstream/database/model.go +++ /dev/null @@ -1,74 +0,0 @@ -package database - -import ( - "github.com/jinzhu/gorm" -) - -type authMapType int - -const ( - authMapTypeNone = iota - authMapTypePassword - authMapTypePrivateKey - authMapTypeAny -) - -const fallbackUserEntry = "FALLBACK_USER" - -type keydata struct { - gorm.Model - - Name string `gorm:"type:varchar(45)"` - Data string `gorm:"type:text"` - Type string `gorm:"type:varchar(45)"` -} - -type server struct { - gorm.Model - - Name string `gorm:"type:varchar(45)"` - Address string `gorm:"type:varchar(100)"` - - HostKeyID int - HostKey keydata - IgnoreHostKey bool -} - -type upstream struct { - gorm.Model - - Name string `gorm:"type:varchar(45)"` - ServerID int - Server server - - Username string `gorm:"type:varchar(45)"` - Password string `gorm:"type:varchar(60)"` - PrivateKeyID int - PrivateKey keydata - AuthMapType authMapType - KnownHosts string `gorm:"type:varchar(100)"` -} - -type downstream struct { - gorm.Model - - Name string `gorm:"type:varchar(45)"` - Username string `gorm:"type:varchar(45);unique_index"` - Password string `gorm:"type:varchar(60)"` - AuthMapType authMapType - AllowAnyPublicKey bool - NoPassthrough bool - - UpstreamID int - Upstream upstream - - AuthorizedKeysID int - AuthorizedKeys keydata -} - -type config struct { - gorm.Model - - Entry string `gorm:"type:varchar(45);unique_index"` - Value string `gorm:"type:varchar(100)"` -} diff --git a/sshpiperd/upstream/database/mssql.go b/sshpiperd/upstream/database/mssql.go deleted file mode 100644 index 67b53faf..00000000 --- a/sshpiperd/upstream/database/mssql.go +++ /dev/null @@ -1,58 +0,0 @@ -package database - -import ( - "fmt" - "net/url" - - "github.com/jinzhu/gorm" - _ "github.com/jinzhu/gorm/dialects/mssql" // gorm dialect - - upstreamprovider "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -type mssqlplugin struct { - plugin - - Config struct { - Host string `long:"upstream-mssql-host" default:"127.0.0.1" description:"SQL Server host" env:"SSHPIPERD_UPSTREAM_MSSQL_HOST" ini-name:"upstream-mssql-host"` - User string `long:"upstream-mssql-user" default:"sa" description:"SQL Server user" env:"SSHPIPERD_UPSTREAM_MSSQL_USER" ini-name:"upstream-mssql-user"` - Password string `long:"upstream-mssql-password" default:"" description:"SQL Server password" env:"SSHPIPERD_UPSTREAM_MSSQL_PASSWORD" ini-name:"upstream-mssql-password"` - Port uint `long:"upstream-mssql-port" default:"1433" description:"SQL Server port" env:"SSHPIPERD_UPSTREAM_MSSQL_PORT" ini-name:"upstream-mssql-port"` - Dbname string `long:"upstream-mssql-dbname" default:"sshpiper" description:"SQL server database name" env:"SSHPIPERD_UPSTREAM_MSSQL_DBNAME" ini-name:"upstream-mssql-dbname"` - Instance string `long:"upstream-mssql-instance" description:"SQL Server database instance" env:"SSHPIPERD_UPSTREAM_MSSQL_INSTANCE" ini-name:"upstream-mssql-instance"` - } -} - -func (p *mssqlplugin) create() (*gorm.DB, error) { - query := url.Values{} - query.Add("database", p.Config.Dbname) - - u := &url.URL{ - Scheme: "sqlserver", - User: url.UserPassword(p.Config.User, p.Config.Password), - Host: fmt.Sprintf("%s:%d", p.Config.Host, p.Config.Port), - Path: p.Config.Instance, - RawQuery: query.Encode(), - } - - db, err := gorm.Open("mssql", u.String()) - if err != nil { - return nil, err - } - - return db, nil -} - -func (mssqlplugin) GetName() string { - return "mssql" -} - -func (p *mssqlplugin) GetOpts() interface{} { - return &p.Config -} - -func init() { - p := &mssqlplugin{} - p.createdb = p - upstreamprovider.Register("mssql", p) -} diff --git a/sshpiperd/upstream/database/mysql.go b/sshpiperd/upstream/database/mysql.go deleted file mode 100644 index 261522f4..00000000 --- a/sshpiperd/upstream/database/mysql.go +++ /dev/null @@ -1,55 +0,0 @@ -package database - -import ( - "fmt" - - mysqldriver "github.com/go-sql-driver/mysql" - "github.com/jinzhu/gorm" - _ "github.com/jinzhu/gorm/dialects/mysql" // gorm dialiect - - upstreamprovider "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -type mysqlplugin struct { - plugin - - Config struct { - Host string `long:"upstream-mysql-host" default:"127.0.0.1" description:"MySQL host" env:"SSHPIPERD_UPSTREAM_MYSQL_HOST" ini-name:"upstream-mysql-host"` - User string `long:"upstream-mysql-user" default:"root" description:"MySQL user" env:"SSHPIPERD_UPSTREAM_MYSQL_USER" ini-name:"upstream-mysql-user"` - Password string `long:"upstream-mysql-password" default:"" description:"MySQL password" env:"SSHPIPERD_UPSTREAM_MYSQL_PASSWORD" ini-name:"upstream-mysql-password"` - Port uint `long:"upstream-mysql-port" default:"3306" description:"MySQL port" env:"SSHPIPERD_UPSTREAM_MYSQL_PORT" ini-name:"upstream-mysql-port"` - Dbname string `long:"upstream-mysql-dbname" default:"sshpiper" description:"MySQL database name" env:"SSHPIPERD_UPSTREAM_MYSQL_DBNAME" ini-name:"upstream-mysql-dbname"` - } -} - -func (p *mysqlplugin) create() (*gorm.DB, error) { - - config := mysqldriver.NewConfig() - config.User = p.Config.User - config.Passwd = p.Config.Password - config.Net = "tcp" - config.Addr = fmt.Sprintf("%v:%v", p.Config.Host, p.Config.Port) - config.DBName = p.Config.Dbname - config.ParseTime = true - - db, err := gorm.Open("mysql", config.FormatDSN()) - if err != nil { - return nil, err - } - - return db, nil -} - -func (mysqlplugin) GetName() string { - return "mysql" -} - -func (p *mysqlplugin) GetOpts() interface{} { - return &p.Config -} - -func init() { - p := &mysqlplugin{} - p.createdb = p - upstreamprovider.Register("mysql", p) -} diff --git a/sshpiperd/upstream/database/pipemgr.go b/sshpiperd/upstream/database/pipemgr.go deleted file mode 100644 index 6e2c137c..00000000 --- a/sshpiperd/upstream/database/pipemgr.go +++ /dev/null @@ -1,76 +0,0 @@ -package database - -import ( - "fmt" - - "github.com/jinzhu/gorm" - - upstreamprovider "github.com/tg123/sshpiper/sshpiperd/upstream" - "github.com/tg123/sshpiper/sshpiperd/utils" -) - -func (p *plugin) ListPipe() ([]upstreamprovider.Pipe, error) { - db := p.db - - downstreams := make([]downstream, 0) - err := db.Set("gorm:auto_preload", true).Find(&downstreams).Error - if err != nil { - return nil, err - } - - pipes := make([]upstreamprovider.Pipe, 0, len(downstreams)) - for _, d := range downstreams { - - host, port, err := upstreamprovider.SplitHostPortForSSH(d.Upstream.Server.Address) - - if err != nil { - continue - } - - upuser := d.Upstream.Username - - if upuser == "" { - upuser = d.Username - } - - pipes = append(pipes, upstreamprovider.Pipe{ - Host: utils.FormatIPAddress(host), - Port: port, - Username: d.Username, - UpstreamUsername: upuser, - }) - } - - return pipes, nil -} - -func (p *plugin) CreatePipe(opt upstreamprovider.CreatePipeOption) error { - db := p.db - - return db.Create(&downstream{ - Username: opt.Username, - Upstream: upstream{ - Username: opt.UpstreamUsername, - AuthMapType: authMapTypeNone, - Server: server{ - Address: fmt.Sprintf("%v:%v", opt.Host, opt.Port), - IgnoreHostKey: true, - }, - }, - }).Error -} - -func (p *plugin) RemovePipe(name string) error { - db := p.db - - d, err := lookupDownstream(db, name) - if err != nil { - - if gorm.IsRecordNotFoundError(err) { - return nil - } - - return err - } - return db.Unscoped().Delete(d).Error -} diff --git a/sshpiperd/upstream/database/plugin.go b/sshpiperd/upstream/database/plugin.go deleted file mode 100644 index 9f5a4048..00000000 --- a/sshpiperd/upstream/database/plugin.go +++ /dev/null @@ -1,61 +0,0 @@ -package database - -import ( - log "github.com/sirupsen/logrus" - - "github.com/jinzhu/gorm" - - upstreamprovider "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -var logger *log.Logger - -type createdb interface { - create() (*gorm.DB, error) -} - -type plugin struct { - createdb - - db *gorm.DB -} - -func (p *plugin) GetHandler() upstreamprovider.Handler { - return p.findUpstream -} - -func (p *plugin) Init(glogger *log.Logger) error { - - logger = glogger - - db, err := p.create() - - if err != nil { - return err - } - - logger.Printf("upstream provider: Database driver [%v] initializing", db.Dialect().GetName()) - - err = db.AutoMigrate( - new(keydata), - new(server), - new(upstream), - new(downstream), - new(config), - ).Error - - if err != nil { - logger.Printf("AutoMigrate error: %v", err) - } - - // TODO add config - // db.SetLogger(logger) - // db.LogMode(true) - - p.db = db - - // plugin is alive within program lifecycle, close when unload added - // defer db.Close() - - return nil -} diff --git a/sshpiperd/upstream/database/postgres.go b/sshpiperd/upstream/database/postgres.go deleted file mode 100644 index 3275094c..00000000 --- a/sshpiperd/upstream/database/postgres.go +++ /dev/null @@ -1,62 +0,0 @@ -package database - -import ( - "fmt" - - "github.com/jinzhu/gorm" - _ "github.com/jinzhu/gorm/dialects/postgres" // gorm dialect - - upstreamprovider "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -type postgresplugin struct { - plugin - - Config struct { - Host string `long:"upstream-postgres-host" default:"127.0.0.1" description:"PostgreSQL host" env:"SSHPIPERD_UPSTREAM_POSTGRES_HOST" ini-name:"upstream-postgres-host"` - User string `long:"upstream-postgres-user" default:"postgres" description:"PostgreSQL user" env:"SSHPIPERD_UPSTREAM_POSTGRES_USER" ini-name:"upstream-postgres-user"` - Password string `long:"upstream-postgres-password" description:"PostgreSQL password" env:"SSHPIPERD_UPSTREAM_POSTGRES_PASSWORD" ini-name:"upstream-postgres-password"` - Port uint `long:"upstream-postgres-port" default:"5432" description:"PostgreSQL port" env:"SSHPIPERD_UPSTREAM_POSTGRES_PORT" ini-name:"upstream-postgres-port"` - Dbname string `long:"upstream-postgres-dbname" default:"sshpiper" description:"PostgreSQL database name" env:"SSHPIPERD_UPSTREAM_POSTGRES_DBNAME" ini-name:"upstream-postgres-dbname"` - SslMode string `long:"upstream-postgres-sslmode" default:"require" description:"PostgreSQL ssl mode" env:"SSHPIPERD_UPSTREAM_POSTGRES_SSLMODE" ini-name:"upstream-postgres-sslmode"` - SslCert string `long:"upstream-postgres-sslcert" description:"PostgreSQL ssl cert path" env:"SSHPIPERD_UPSTREAM_POSTGRES_SSLCERT" ini-name:"upstream-postgres-sslcert"` - SslKey string `long:"upstream-postgres-sslkey" description:"PostgreSQL ssl key path" env:"SSHPIPERD_UPSTREAM_POSTGRES_SSLKEY" ini-name:"upstream-postgres-sslkey"` - SslRootCert string `long:"upstream-postgres-sslrootcert" description:"PostgreSQL ssl root cert path" env:"SSHPIPERD_UPSTREAM_POSTGRES_SSLROOTCERT" ini-name:"upstream-postgres-sslrootcert"` - } -} - -func (p *postgresplugin) create() (*gorm.DB, error) { - - conn := fmt.Sprintf("host=%v port=%v user=%v password=%v dbname=%v sslmode=%v sslcert=%v sslkey=%v sslrootcert=%v", - p.Config.Host, - p.Config.Port, - p.Config.User, - p.Config.Password, - p.Config.Dbname, - p.Config.SslMode, - p.Config.SslCert, - p.Config.SslKey, - p.Config.SslRootCert, - ) - - db, err := gorm.Open("postgres", conn) - if err != nil { - return nil, err - } - - return db, nil -} - -func (postgresplugin) GetName() string { - return "postgres" -} - -func (p *postgresplugin) GetOpts() interface{} { - return &p.Config -} - -func init() { - p := &postgresplugin{} - p.createdb = p - upstreamprovider.Register("postgres", p) -} diff --git a/sshpiperd/upstream/database/sqlite.go b/sshpiperd/upstream/database/sqlite.go deleted file mode 100644 index 1dd2ecea..00000000 --- a/sshpiperd/upstream/database/sqlite.go +++ /dev/null @@ -1,40 +0,0 @@ -package database - -import ( - "github.com/jinzhu/gorm" - _ "github.com/jinzhu/gorm/dialects/sqlite" // gorm dialect - - upstreamprovider "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -type sqliteplugin struct { - plugin - - Config struct { - File string `long:"upstream-sqlite-dbfile" default:"file:sshpiper.sqlite" description:"Database file path for SQLite 3" env:"SSHPIPERD_UPSTREAM_SQLITE_FILE" ini-name:"upstream-sqlite-file"` - } -} - -func (p *sqliteplugin) create() (*gorm.DB, error) { - - db, err := gorm.Open("sqlite3", p.Config.File) - if err != nil { - return nil, err - } - - return db, nil -} - -func (sqliteplugin) GetName() string { - return "sqlite" -} - -func (p *sqliteplugin) GetOpts() interface{} { - return &p.Config -} - -func init() { - p := &sqliteplugin{} - p.createdb = p - upstreamprovider.Register("sqlite", p) -} diff --git a/sshpiperd/upstream/grpcupstream/grpc.go b/sshpiperd/upstream/grpcupstream/grpc.go deleted file mode 100644 index 4bd6fe67..00000000 --- a/sshpiperd/upstream/grpcupstream/grpc.go +++ /dev/null @@ -1,124 +0,0 @@ -package grpcupstream - -import ( - "context" - "fmt" - "net" - "time" - - "github.com/tg123/remotesigner" - "github.com/tg123/remotesigner/grpcsigner" - "github.com/tg123/sshpiper/sshpiperd/upstream" - "golang.org/x/crypto/ssh" -) - -func (p *plugin) timeoutCtx() (context.Context, context.CancelFunc) { - d := time.Now().Add(time.Duration(p.Config.Timeout) * time.Second) - return context.WithDeadline(context.Background(), d) -} - -func (p *plugin) mapauth(conn ssh.ConnMetadata, metadata string, typ MapAuthRequest_Authtype, param []byte) (ssh.AuthPipeType, ssh.AuthMethod, error) { - ctx, cancel := p.timeoutCtx() - defer cancel() - - a, err := p.upstreamClient.MapAuth(ctx, &MapAuthRequest{ - UserName: conn.User(), - FromAddr: conn.RemoteAddr().String(), - AuthType: typ, - AuthParam: param, - Metadata: metadata, - }) - - if err != nil { - return ssh.AuthPipeTypeDiscard, nil, err - } - - switch a.MappedAuthType { - case MapAuthReply_PASSTHROUGH: - return ssh.AuthPipeTypePassThrough, nil, nil - case MapAuthReply_DISCARD: - return ssh.AuthPipeTypeDiscard, nil, nil - case MapAuthReply_NONE: - return ssh.AuthPipeTypeNone, nil, nil - - case MapAuthReply_PASSWORD: - return ssh.AuthPipeTypeMap, ssh.Password(string(a.MappedAuthParam)), nil - case MapAuthReply_PRIVATEKEY: - - private, err := ssh.ParsePrivateKey(a.MappedAuthParam) - if err != nil { - return ssh.AuthPipeTypeDiscard, nil, err - } - - return ssh.AuthPipeTypeMap, ssh.PublicKeys(private), nil - case MapAuthReply_REMOTESIGNER: - rs := remotesigner.New(grpcsigner.New(p.remotesignerClient, string(a.MappedAuthParam))) - signer, err := ssh.NewSignerFromSigner(rs) - if err != nil { - return ssh.AuthPipeTypeDiscard, nil, err - } - - return ssh.AuthPipeTypeMap, ssh.PublicKeys(signer), nil - default: - return ssh.AuthPipeTypeDiscard, nil, nil - } -} - -func (p *plugin) verifyHostKey(hostname string, remote net.Addr, key ssh.PublicKey) error { - - ctx, cancel := p.timeoutCtx() - defer cancel() - - v, err := p.upstreamClient.VerifyHostKey(ctx, &VerifyHostKeyRequest{ - Hostname: hostname, - Address: remote.String(), - Key: key.Marshal(), - }) - - if err != nil { - return err - } - - if !v.Verified { - return fmt.Errorf("host key mismatch") - } - - return nil -} - -func (p *plugin) findUpstream(conn ssh.ConnMetadata, challengeContext ssh.AdditionalChallengeContext) (net.Conn, *ssh.AuthPipe, error) { - ctx, cancel := p.timeoutCtx() - defer cancel() - - u, err := p.upstreamClient.FindUpstream(ctx, &FindUpstreamRequest{ - UserName: conn.User(), - FromAddr: conn.RemoteAddr().String(), - }) - if err != nil { - return nil, nil, err - } - - c, err := upstream.DialForSSH(u.ToAddr) - if err != nil { - return nil, nil, err - } - - a := &ssh.AuthPipe{ - User: u.MappedUserName, - UpstreamHostKeyCallback: p.verifyHostKey, - } - - a.NoneAuthCallback = func(conn ssh.ConnMetadata) (ssh.AuthPipeType, ssh.AuthMethod, error) { - return p.mapauth(conn, u.Metadata, MapAuthRequest_NONE, nil) - } - - a.PasswordCallback = func(conn ssh.ConnMetadata, password []byte) (ssh.AuthPipeType, ssh.AuthMethod, error) { - return p.mapauth(conn, u.Metadata, MapAuthRequest_PASSWORD, password) - } - - a.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (ssh.AuthPipeType, ssh.AuthMethod, error) { - return p.mapauth(conn, u.Metadata, MapAuthRequest_PUBLICKEY, key.Marshal()) - } - - return c, a, nil -} diff --git a/sshpiperd/upstream/grpcupstream/pipemgr.go b/sshpiperd/upstream/grpcupstream/pipemgr.go deleted file mode 100644 index 6805f269..00000000 --- a/sshpiperd/upstream/grpcupstream/pipemgr.go +++ /dev/null @@ -1,20 +0,0 @@ -package grpcupstream - -import ( - "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -// Return All pipes inside upstream -func (p *plugin) ListPipe() ([]upstream.Pipe, error) { - return nil, nil -} - -// Create a pipe inside upstream -func (p *plugin) CreatePipe(opt upstream.CreatePipeOption) error { - return nil -} - -// Remove a pipe from upstream -func (p *plugin) RemovePipe(name string) error { - return nil -} diff --git a/sshpiperd/upstream/grpcupstream/plugin.go b/sshpiperd/upstream/grpcupstream/plugin.go deleted file mode 100644 index a75701ea..00000000 --- a/sshpiperd/upstream/grpcupstream/plugin.go +++ /dev/null @@ -1,92 +0,0 @@ -package grpcupstream - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "io/ioutil" - - log "github.com/sirupsen/logrus" - - "github.com/tg123/remotesigner/grpcsigner" - "github.com/tg123/sshpiper/sshpiperd/upstream" - grpc "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" -) - -type plugin struct { - Config struct { - Endpoint string `long:"upstream-grpc-endpoint" description:"grpc endpoint of the upstream" env:"SSHPIPERD_UPSTREAM_GRPC_ENDPOINT" ini-name:"upstream-grpc-endpoint"` - Insecure bool `long:"upstream-grpc-insecure" description:"disable secure grpc connection" env:"SSHPIPERD_UPSTREAM_GRPC_INSECURE" ini-name:"upstream-grpc-insecure"` - CA string `long:"upstream-grpc-ca" description:"ca file path" env:"SSHPIPERD_UPSTREAM_GRPC_CA" ini-name:"upstream-grpc-ca"` - Cert string `long:"upstream-grpc-cert" description:"certificate file path" env:"SSHPIPERD_UPSTREAM_GRPC_CERT" ini-name:"upstream-grpc-cert"` - Key string `long:"upstream-grpc-key" description:"key file path" env:"SSHPIPERD_UPSTREAM_GRPC_KEY" ini-name:"upstream-grpc-key"` - Timeout int `long:"upstream-grpc-timeout" description:"grpc call timeout in second" default:"10" env:"SSHPIPERD_UPSTREAM_GRPC_TIMEOUT" ini-name:"upstream-grpc-timeout"` - } - - logger *log.Logger - upstreamClient UpstreamRegistryClient - remotesignerClient grpcsigner.SignerClient -} - -// The name of the Plugin -func (p *plugin) GetName() string { - return "grpc" -} - -func (p *plugin) GetOpts() interface{} { - return &p.Config -} - -func (p *plugin) Init(logger *log.Logger) error { - p.logger = logger - - var secopt grpc.DialOption - if p.Config.Insecure { - secopt = grpc.WithTransportCredentials(insecure.NewCredentials()) - } else { - - clientCert, err := tls.LoadX509KeyPair(p.Config.Cert, p.Config.Key) - if err != nil { - return err - } - - config := &tls.Config{ - Certificates: []tls.Certificate{clientCert}, - } - - if p.Config.CA != "" { - ca, err := ioutil.ReadFile(p.Config.CA) - if err != nil { - return err - } - certPool := x509.NewCertPool() - if !certPool.AppendCertsFromPEM(ca) { - return fmt.Errorf("failed to append ca") - } - - config.RootCAs = certPool - } - - secopt = grpc.WithTransportCredentials(credentials.NewTLS(config)) - } - - conn, err := grpc.Dial(p.Config.Endpoint, secopt, grpc.WithBlock()) - if err != nil { - return err - } - - p.upstreamClient = NewUpstreamRegistryClient(conn) - p.remotesignerClient = grpcsigner.NewSignerClient(conn) - - return nil -} - -func (p *plugin) GetHandler() upstream.Handler { - return p.findUpstream -} - -func init() { - upstream.Register("grpc", &plugin{}) -} diff --git a/sshpiperd/upstream/grpcupstream/simpleserver/impl.go b/sshpiperd/upstream/grpcupstream/simpleserver/impl.go deleted file mode 100644 index 9dc0642b..00000000 --- a/sshpiperd/upstream/grpcupstream/simpleserver/impl.go +++ /dev/null @@ -1,72 +0,0 @@ -package main - -import ( - "context" - "fmt" - "io/ioutil" - - log "github.com/sirupsen/logrus" - - "github.com/tg123/sshpiper/sshpiperd/upstream/grpcupstream" -) - -type server struct { - grpcupstream.UnimplementedUpstreamRegistryServer - - ToType string `long:"totype" default:"PASSTHROUGH"` - ToAddr string `long:"toaddr"` - MappedUserName string `long:"mappeduser"` - Password string `long:"password"` - PrivateKey string `long:"privatekey"` -} - -func (s *server) FindUpstream(_ context.Context, request *grpcupstream.FindUpstreamRequest) (*grpcupstream.FindUpstreamReply, error) { - log.Printf("mapping [%v@%v] to [%v@%v]", request.UserName, request.FromAddr, s.MappedUserName, s.ToAddr) - return &grpcupstream.FindUpstreamReply{ - ToAddr: s.ToAddr, - MappedUserName: s.MappedUserName, - }, nil -} - -func (s *server) VerifyHostKey(context.Context, *grpcupstream.VerifyHostKeyRequest) (*grpcupstream.VerifyHostKeyReply, error) { - return &grpcupstream.VerifyHostKeyReply{ - Verified: true, - }, nil -} - -func (s *server) MapAuth(_ context.Context, request *grpcupstream.MapAuthRequest) (*grpcupstream.MapAuthReply, error) { - totype := grpcupstream.MapAuthReply_Authtype(grpcupstream.MapAuthReply_Authtype_value[s.ToType]) - log.Printf("mapping auth [%v] to [%v]", request.AuthType, totype) - - // add your own auth here - switch totype { - case grpcupstream.MapAuthReply_PASSTHROUGH, grpcupstream.MapAuthReply_DISCARD, grpcupstream.MapAuthReply_NONE: - return &grpcupstream.MapAuthReply{ - MappedAuthType: totype, - }, nil - case grpcupstream.MapAuthReply_PASSWORD: - return &grpcupstream.MapAuthReply{ - MappedAuthType: grpcupstream.MapAuthReply_PASSWORD, - MappedAuthParam: []byte(s.Password), - }, nil - case grpcupstream.MapAuthReply_PRIVATEKEY: - - b, err := ioutil.ReadFile(s.PrivateKey) - if err != nil { - return nil, err - } - - return &grpcupstream.MapAuthReply{ - MappedAuthType: grpcupstream.MapAuthReply_PRIVATEKEY, - MappedAuthParam: b, - }, nil - - case grpcupstream.MapAuthReply_REMOTESIGNER: - return &grpcupstream.MapAuthReply{ - MappedAuthType: grpcupstream.MapAuthReply_REMOTESIGNER, - MappedAuthParam: []byte(s.PrivateKey), - }, nil - } - - return nil, fmt.Errorf("unsupported to type") -} diff --git a/sshpiperd/upstream/grpcupstream/simpleserver/main.go b/sshpiperd/upstream/grpcupstream/simpleserver/main.go deleted file mode 100644 index e1fd0730..00000000 --- a/sshpiperd/upstream/grpcupstream/simpleserver/main.go +++ /dev/null @@ -1,73 +0,0 @@ -package main - -import ( - "crypto" - "fmt" - "io/ioutil" - "net" - "reflect" - "unsafe" - - log "github.com/sirupsen/logrus" - - "github.com/jessevdk/go-flags" - "github.com/tg123/remotesigner/grpcsigner" - "github.com/tg123/sshpiper/sshpiperd/upstream/grpcupstream" - "golang.org/x/crypto/ssh" - "google.golang.org/grpc" -) - -type args struct { - ListenAddr string `short:"l" long:"listen" default:"0.0.0.0"` - Port uint `short:"p" long:"port" default:"2233"` - server -} - -func main() { - var c args - - if _, err := flags.Parse(&c); err != nil { - log.Fatalf("parse args %v", err) - } - - addr := fmt.Sprintf("%v:%v", c.ListenAddr, c.Port) - l, err := net.Listen("tcp", addr) - if err != nil { - log.Fatalf("listen on %v failed %v", addr, err) - } - - if _, ok := grpcupstream.MapAuthReply_Authtype_value[c.ToType]; !ok { - log.Fatalf("totype [%v] not allowed", c.ToType) - } - - s := grpc.NewServer() - grpcupstream.RegisterUpstreamRegistryServer(s, &c.server) - - if c.PrivateKey != "" { - gs, err := grpcsigner.NewSignerServer(func(string) crypto.Signer { - b, err := ioutil.ReadFile(c.PrivateKey) - if err != nil { - log.Fatalf("private key [%v] load failed %v", c.PrivateKey, err) - } - - private, err := ssh.ParsePrivateKey(b) - if err != nil { - log.Fatalf("private key [%v] parse failed %v", c.PrivateKey, err) - } - - field := reflect.ValueOf(private).Elem().FieldByName("signer") - signer := reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface().(crypto.Signer) - - log.Printf("remote signing with %v", c.PrivateKey) - return signer - }) - if err != nil { - log.Fatalf("start grpc signer failed %v", err) - } - - grpcsigner.RegisterSignerServer(s, gs) - } - - log.Printf("serving on %v", addr) - panic(s.Serve(l)) -} diff --git a/sshpiperd/upstream/grpcupstream/upstream.pb.go b/sshpiperd/upstream/grpcupstream/upstream.pb.go deleted file mode 100644 index 49924222..00000000 --- a/sshpiperd/upstream/grpcupstream/upstream.pb.go +++ /dev/null @@ -1,710 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.25.0-devel -// protoc v3.14.0 -// source: upstream.proto - -package grpcupstream - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type MapAuthRequest_Authtype int32 - -const ( - MapAuthRequest_NONE MapAuthRequest_Authtype = 0 - MapAuthRequest_PASSWORD MapAuthRequest_Authtype = 1 - MapAuthRequest_PUBLICKEY MapAuthRequest_Authtype = 2 -) - -// Enum value maps for MapAuthRequest_Authtype. -var ( - MapAuthRequest_Authtype_name = map[int32]string{ - 0: "NONE", - 1: "PASSWORD", - 2: "PUBLICKEY", - } - MapAuthRequest_Authtype_value = map[string]int32{ - "NONE": 0, - "PASSWORD": 1, - "PUBLICKEY": 2, - } -) - -func (x MapAuthRequest_Authtype) Enum() *MapAuthRequest_Authtype { - p := new(MapAuthRequest_Authtype) - *p = x - return p -} - -func (x MapAuthRequest_Authtype) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (MapAuthRequest_Authtype) Descriptor() protoreflect.EnumDescriptor { - return file_upstream_proto_enumTypes[0].Descriptor() -} - -func (MapAuthRequest_Authtype) Type() protoreflect.EnumType { - return &file_upstream_proto_enumTypes[0] -} - -func (x MapAuthRequest_Authtype) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use MapAuthRequest_Authtype.Descriptor instead. -func (MapAuthRequest_Authtype) EnumDescriptor() ([]byte, []int) { - return file_upstream_proto_rawDescGZIP(), []int{4, 0} -} - -type MapAuthReply_Authtype int32 - -const ( - MapAuthReply_PASSTHROUGH MapAuthReply_Authtype = 0 - MapAuthReply_DISCARD MapAuthReply_Authtype = 1 - MapAuthReply_NONE MapAuthReply_Authtype = 2 - MapAuthReply_PASSWORD MapAuthReply_Authtype = 3 - MapAuthReply_PRIVATEKEY MapAuthReply_Authtype = 4 - MapAuthReply_REMOTESIGNER MapAuthReply_Authtype = 5 -) - -// Enum value maps for MapAuthReply_Authtype. -var ( - MapAuthReply_Authtype_name = map[int32]string{ - 0: "PASSTHROUGH", - 1: "DISCARD", - 2: "NONE", - 3: "PASSWORD", - 4: "PRIVATEKEY", - 5: "REMOTESIGNER", - } - MapAuthReply_Authtype_value = map[string]int32{ - "PASSTHROUGH": 0, - "DISCARD": 1, - "NONE": 2, - "PASSWORD": 3, - "PRIVATEKEY": 4, - "REMOTESIGNER": 5, - } -) - -func (x MapAuthReply_Authtype) Enum() *MapAuthReply_Authtype { - p := new(MapAuthReply_Authtype) - *p = x - return p -} - -func (x MapAuthReply_Authtype) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (MapAuthReply_Authtype) Descriptor() protoreflect.EnumDescriptor { - return file_upstream_proto_enumTypes[1].Descriptor() -} - -func (MapAuthReply_Authtype) Type() protoreflect.EnumType { - return &file_upstream_proto_enumTypes[1] -} - -func (x MapAuthReply_Authtype) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use MapAuthReply_Authtype.Descriptor instead. -func (MapAuthReply_Authtype) EnumDescriptor() ([]byte, []int) { - return file_upstream_proto_rawDescGZIP(), []int{5, 0} -} - -type FindUpstreamRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - UserName string `protobuf:"bytes,1,opt,name=userName,proto3" json:"userName,omitempty"` - FromAddr string `protobuf:"bytes,2,opt,name=fromAddr,proto3" json:"fromAddr,omitempty"` -} - -func (x *FindUpstreamRequest) Reset() { - *x = FindUpstreamRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_upstream_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FindUpstreamRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FindUpstreamRequest) ProtoMessage() {} - -func (x *FindUpstreamRequest) ProtoReflect() protoreflect.Message { - mi := &file_upstream_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FindUpstreamRequest.ProtoReflect.Descriptor instead. -func (*FindUpstreamRequest) Descriptor() ([]byte, []int) { - return file_upstream_proto_rawDescGZIP(), []int{0} -} - -func (x *FindUpstreamRequest) GetUserName() string { - if x != nil { - return x.UserName - } - return "" -} - -func (x *FindUpstreamRequest) GetFromAddr() string { - if x != nil { - return x.FromAddr - } - return "" -} - -type FindUpstreamReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ToAddr string `protobuf:"bytes,1,opt,name=toAddr,proto3" json:"toAddr,omitempty"` - MappedUserName string `protobuf:"bytes,2,opt,name=mappedUserName,proto3" json:"mappedUserName,omitempty"` - Metadata string `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` -} - -func (x *FindUpstreamReply) Reset() { - *x = FindUpstreamReply{} - if protoimpl.UnsafeEnabled { - mi := &file_upstream_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FindUpstreamReply) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FindUpstreamReply) ProtoMessage() {} - -func (x *FindUpstreamReply) ProtoReflect() protoreflect.Message { - mi := &file_upstream_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FindUpstreamReply.ProtoReflect.Descriptor instead. -func (*FindUpstreamReply) Descriptor() ([]byte, []int) { - return file_upstream_proto_rawDescGZIP(), []int{1} -} - -func (x *FindUpstreamReply) GetToAddr() string { - if x != nil { - return x.ToAddr - } - return "" -} - -func (x *FindUpstreamReply) GetMappedUserName() string { - if x != nil { - return x.MappedUserName - } - return "" -} - -func (x *FindUpstreamReply) GetMetadata() string { - if x != nil { - return x.Metadata - } - return "" -} - -type VerifyHostKeyRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Hostname string `protobuf:"bytes,1,opt,name=hostname,proto3" json:"hostname,omitempty"` - Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` - Key []byte `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` -} - -func (x *VerifyHostKeyRequest) Reset() { - *x = VerifyHostKeyRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_upstream_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VerifyHostKeyRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VerifyHostKeyRequest) ProtoMessage() {} - -func (x *VerifyHostKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_upstream_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VerifyHostKeyRequest.ProtoReflect.Descriptor instead. -func (*VerifyHostKeyRequest) Descriptor() ([]byte, []int) { - return file_upstream_proto_rawDescGZIP(), []int{2} -} - -func (x *VerifyHostKeyRequest) GetHostname() string { - if x != nil { - return x.Hostname - } - return "" -} - -func (x *VerifyHostKeyRequest) GetAddress() string { - if x != nil { - return x.Address - } - return "" -} - -func (x *VerifyHostKeyRequest) GetKey() []byte { - if x != nil { - return x.Key - } - return nil -} - -type VerifyHostKeyReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Verified bool `protobuf:"varint,1,opt,name=verified,proto3" json:"verified,omitempty"` -} - -func (x *VerifyHostKeyReply) Reset() { - *x = VerifyHostKeyReply{} - if protoimpl.UnsafeEnabled { - mi := &file_upstream_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VerifyHostKeyReply) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VerifyHostKeyReply) ProtoMessage() {} - -func (x *VerifyHostKeyReply) ProtoReflect() protoreflect.Message { - mi := &file_upstream_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VerifyHostKeyReply.ProtoReflect.Descriptor instead. -func (*VerifyHostKeyReply) Descriptor() ([]byte, []int) { - return file_upstream_proto_rawDescGZIP(), []int{3} -} - -func (x *VerifyHostKeyReply) GetVerified() bool { - if x != nil { - return x.Verified - } - return false -} - -type MapAuthRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - UserName string `protobuf:"bytes,1,opt,name=userName,proto3" json:"userName,omitempty"` - FromAddr string `protobuf:"bytes,2,opt,name=fromAddr,proto3" json:"fromAddr,omitempty"` - Metadata string `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` - AuthType MapAuthRequest_Authtype `protobuf:"varint,4,opt,name=authType,proto3,enum=grpcupstream.MapAuthRequest_Authtype" json:"authType,omitempty"` - AuthParam []byte `protobuf:"bytes,5,opt,name=authParam,proto3" json:"authParam,omitempty"` -} - -func (x *MapAuthRequest) Reset() { - *x = MapAuthRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_upstream_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MapAuthRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MapAuthRequest) ProtoMessage() {} - -func (x *MapAuthRequest) ProtoReflect() protoreflect.Message { - mi := &file_upstream_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MapAuthRequest.ProtoReflect.Descriptor instead. -func (*MapAuthRequest) Descriptor() ([]byte, []int) { - return file_upstream_proto_rawDescGZIP(), []int{4} -} - -func (x *MapAuthRequest) GetUserName() string { - if x != nil { - return x.UserName - } - return "" -} - -func (x *MapAuthRequest) GetFromAddr() string { - if x != nil { - return x.FromAddr - } - return "" -} - -func (x *MapAuthRequest) GetMetadata() string { - if x != nil { - return x.Metadata - } - return "" -} - -func (x *MapAuthRequest) GetAuthType() MapAuthRequest_Authtype { - if x != nil { - return x.AuthType - } - return MapAuthRequest_NONE -} - -func (x *MapAuthRequest) GetAuthParam() []byte { - if x != nil { - return x.AuthParam - } - return nil -} - -type MapAuthReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - MappedAuthType MapAuthReply_Authtype `protobuf:"varint,1,opt,name=mappedAuthType,proto3,enum=grpcupstream.MapAuthReply_Authtype" json:"mappedAuthType,omitempty"` - MappedAuthParam []byte `protobuf:"bytes,2,opt,name=mappedAuthParam,proto3" json:"mappedAuthParam,omitempty"` -} - -func (x *MapAuthReply) Reset() { - *x = MapAuthReply{} - if protoimpl.UnsafeEnabled { - mi := &file_upstream_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MapAuthReply) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MapAuthReply) ProtoMessage() {} - -func (x *MapAuthReply) ProtoReflect() protoreflect.Message { - mi := &file_upstream_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MapAuthReply.ProtoReflect.Descriptor instead. -func (*MapAuthReply) Descriptor() ([]byte, []int) { - return file_upstream_proto_rawDescGZIP(), []int{5} -} - -func (x *MapAuthReply) GetMappedAuthType() MapAuthReply_Authtype { - if x != nil { - return x.MappedAuthType - } - return MapAuthReply_PASSTHROUGH -} - -func (x *MapAuthReply) GetMappedAuthParam() []byte { - if x != nil { - return x.MappedAuthParam - } - return nil -} - -var File_upstream_proto protoreflect.FileDescriptor - -var file_upstream_proto_rawDesc = []byte{ - 0x0a, 0x0e, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x0c, 0x67, 0x72, 0x70, 0x63, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x22, 0x4d, - 0x0a, 0x13, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x22, 0x6f, 0x0a, - 0x11, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x6d, 0x61, - 0x70, 0x70, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x5e, - 0x0a, 0x14, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x30, - 0x0a, 0x12, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x22, 0xf8, 0x01, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x1a, 0x0a, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x54, - 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x4d, 0x61, 0x70, 0x41, 0x75, 0x74, 0x68, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x74, 0x79, 0x70, 0x65, - 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x75, - 0x74, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x61, - 0x75, 0x74, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x22, 0x31, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0c, - 0x0a, 0x08, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, - 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x4b, 0x45, 0x59, 0x10, 0x02, 0x22, 0xe9, 0x01, 0x0a, 0x0c, - 0x4d, 0x61, 0x70, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x4b, 0x0a, 0x0e, - 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x75, 0x70, 0x73, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x2e, 0x4d, 0x61, 0x70, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x2e, 0x41, 0x75, 0x74, 0x68, 0x74, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x6d, 0x61, 0x70, 0x70, 0x65, - 0x64, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x6d, 0x61, 0x70, - 0x70, 0x65, 0x64, 0x41, 0x75, 0x74, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0f, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x41, 0x75, 0x74, 0x68, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x22, 0x62, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x0f, 0x0a, 0x0b, 0x50, 0x41, 0x53, 0x53, 0x54, 0x48, 0x52, 0x4f, 0x55, 0x47, 0x48, 0x10, 0x00, - 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x49, 0x53, 0x43, 0x41, 0x52, 0x44, 0x10, 0x01, 0x12, 0x08, 0x0a, - 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x41, 0x53, 0x53, 0x57, - 0x4f, 0x52, 0x44, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, - 0x4b, 0x45, 0x59, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x53, - 0x49, 0x47, 0x4e, 0x45, 0x52, 0x10, 0x05, 0x32, 0x88, 0x02, 0x0a, 0x10, 0x55, 0x70, 0x73, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x12, 0x54, 0x0a, 0x0c, - 0x46, 0x69, 0x6e, 0x64, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x21, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x46, 0x69, 0x6e, 0x64, - 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x46, - 0x69, 0x6e, 0x64, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x00, 0x12, 0x57, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x48, 0x6f, 0x73, 0x74, - 0x4b, 0x65, 0x79, 0x12, 0x22, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x4b, 0x65, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x75, 0x70, - 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x48, 0x6f, 0x73, - 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x07, 0x4d, - 0x61, 0x70, 0x41, 0x75, 0x74, 0x68, 0x12, 0x1c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x75, 0x70, 0x73, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x4d, 0x61, 0x70, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x75, 0x70, 0x73, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x2e, 0x4d, 0x61, 0x70, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x00, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x74, 0x67, 0x31, 0x32, 0x33, 0x2f, 0x73, 0x73, 0x68, 0x70, 0x69, 0x70, 0x65, 0x72, 0x2f, - 0x73, 0x73, 0x68, 0x70, 0x69, 0x70, 0x65, 0x72, 0x64, 0x2f, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_upstream_proto_rawDescOnce sync.Once - file_upstream_proto_rawDescData = file_upstream_proto_rawDesc -) - -func file_upstream_proto_rawDescGZIP() []byte { - file_upstream_proto_rawDescOnce.Do(func() { - file_upstream_proto_rawDescData = protoimpl.X.CompressGZIP(file_upstream_proto_rawDescData) - }) - return file_upstream_proto_rawDescData -} - -var file_upstream_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_upstream_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_upstream_proto_goTypes = []interface{}{ - (MapAuthRequest_Authtype)(0), // 0: grpcupstream.MapAuthRequest.Authtype - (MapAuthReply_Authtype)(0), // 1: grpcupstream.MapAuthReply.Authtype - (*FindUpstreamRequest)(nil), // 2: grpcupstream.FindUpstreamRequest - (*FindUpstreamReply)(nil), // 3: grpcupstream.FindUpstreamReply - (*VerifyHostKeyRequest)(nil), // 4: grpcupstream.VerifyHostKeyRequest - (*VerifyHostKeyReply)(nil), // 5: grpcupstream.VerifyHostKeyReply - (*MapAuthRequest)(nil), // 6: grpcupstream.MapAuthRequest - (*MapAuthReply)(nil), // 7: grpcupstream.MapAuthReply -} -var file_upstream_proto_depIdxs = []int32{ - 0, // 0: grpcupstream.MapAuthRequest.authType:type_name -> grpcupstream.MapAuthRequest.Authtype - 1, // 1: grpcupstream.MapAuthReply.mappedAuthType:type_name -> grpcupstream.MapAuthReply.Authtype - 2, // 2: grpcupstream.UpstreamRegistry.FindUpstream:input_type -> grpcupstream.FindUpstreamRequest - 4, // 3: grpcupstream.UpstreamRegistry.VerifyHostKey:input_type -> grpcupstream.VerifyHostKeyRequest - 6, // 4: grpcupstream.UpstreamRegistry.MapAuth:input_type -> grpcupstream.MapAuthRequest - 3, // 5: grpcupstream.UpstreamRegistry.FindUpstream:output_type -> grpcupstream.FindUpstreamReply - 5, // 6: grpcupstream.UpstreamRegistry.VerifyHostKey:output_type -> grpcupstream.VerifyHostKeyReply - 7, // 7: grpcupstream.UpstreamRegistry.MapAuth:output_type -> grpcupstream.MapAuthReply - 5, // [5:8] is the sub-list for method output_type - 2, // [2:5] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name -} - -func init() { file_upstream_proto_init() } -func file_upstream_proto_init() { - if File_upstream_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_upstream_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FindUpstreamRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_upstream_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FindUpstreamReply); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_upstream_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VerifyHostKeyRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_upstream_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VerifyHostKeyReply); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_upstream_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MapAuthRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_upstream_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MapAuthReply); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_upstream_proto_rawDesc, - NumEnums: 2, - NumMessages: 6, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_upstream_proto_goTypes, - DependencyIndexes: file_upstream_proto_depIdxs, - EnumInfos: file_upstream_proto_enumTypes, - MessageInfos: file_upstream_proto_msgTypes, - }.Build() - File_upstream_proto = out.File - file_upstream_proto_rawDesc = nil - file_upstream_proto_goTypes = nil - file_upstream_proto_depIdxs = nil -} diff --git a/sshpiperd/upstream/grpcupstream/upstream.proto b/sshpiperd/upstream/grpcupstream/upstream.proto deleted file mode 100644 index b1095f40..00000000 --- a/sshpiperd/upstream/grpcupstream/upstream.proto +++ /dev/null @@ -1,58 +0,0 @@ -syntax = "proto3"; - -package grpcupstream; - -option go_package = "github.com/tg123/sshpiper/sshpiperd/upstream/grpcupstream"; - -service UpstreamRegistry { - rpc FindUpstream (FindUpstreamRequest) returns (FindUpstreamReply) {} - rpc VerifyHostKey (VerifyHostKeyRequest) returns (VerifyHostKeyReply) {} - rpc MapAuth(MapAuthRequest) returns (MapAuthReply) {} -} - -message FindUpstreamRequest { - string userName = 1; - string fromAddr = 2; -} - -message FindUpstreamReply { - string toAddr = 1; - string mappedUserName = 2; - string metadata = 3; -} - -message VerifyHostKeyRequest { - string hostname = 1; - string address = 2; - bytes key = 3; -} - -message VerifyHostKeyReply { - bool verified = 1; -} - -message MapAuthRequest { - string userName = 1; - string fromAddr = 2; - string metadata = 3; - enum Authtype { - NONE = 0; - PASSWORD = 1; - PUBLICKEY = 2; - } - Authtype authType = 4; - bytes authParam = 5; -} - -message MapAuthReply { - enum Authtype { - PASSTHROUGH = 0; - DISCARD = 1; - NONE = 2; - PASSWORD = 3; - PRIVATEKEY = 4; - REMOTESIGNER = 5; - } - Authtype mappedAuthType = 1; - bytes mappedAuthParam = 2; -} \ No newline at end of file diff --git a/sshpiperd/upstream/grpcupstream/upstream_grpc.pb.go b/sshpiperd/upstream/grpcupstream/upstream_grpc.pb.go deleted file mode 100644 index 7c8044a1..00000000 --- a/sshpiperd/upstream/grpcupstream/upstream_grpc.pb.go +++ /dev/null @@ -1,173 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. - -package grpcupstream - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// UpstreamRegistryClient is the client API for UpstreamRegistry service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type UpstreamRegistryClient interface { - FindUpstream(ctx context.Context, in *FindUpstreamRequest, opts ...grpc.CallOption) (*FindUpstreamReply, error) - VerifyHostKey(ctx context.Context, in *VerifyHostKeyRequest, opts ...grpc.CallOption) (*VerifyHostKeyReply, error) - MapAuth(ctx context.Context, in *MapAuthRequest, opts ...grpc.CallOption) (*MapAuthReply, error) -} - -type upstreamRegistryClient struct { - cc grpc.ClientConnInterface -} - -func NewUpstreamRegistryClient(cc grpc.ClientConnInterface) UpstreamRegistryClient { - return &upstreamRegistryClient{cc} -} - -func (c *upstreamRegistryClient) FindUpstream(ctx context.Context, in *FindUpstreamRequest, opts ...grpc.CallOption) (*FindUpstreamReply, error) { - out := new(FindUpstreamReply) - err := c.cc.Invoke(ctx, "/grpcupstream.UpstreamRegistry/FindUpstream", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *upstreamRegistryClient) VerifyHostKey(ctx context.Context, in *VerifyHostKeyRequest, opts ...grpc.CallOption) (*VerifyHostKeyReply, error) { - out := new(VerifyHostKeyReply) - err := c.cc.Invoke(ctx, "/grpcupstream.UpstreamRegistry/VerifyHostKey", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *upstreamRegistryClient) MapAuth(ctx context.Context, in *MapAuthRequest, opts ...grpc.CallOption) (*MapAuthReply, error) { - out := new(MapAuthReply) - err := c.cc.Invoke(ctx, "/grpcupstream.UpstreamRegistry/MapAuth", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// UpstreamRegistryServer is the server API for UpstreamRegistry service. -// All implementations must embed UnimplementedUpstreamRegistryServer -// for forward compatibility -type UpstreamRegistryServer interface { - FindUpstream(context.Context, *FindUpstreamRequest) (*FindUpstreamReply, error) - VerifyHostKey(context.Context, *VerifyHostKeyRequest) (*VerifyHostKeyReply, error) - MapAuth(context.Context, *MapAuthRequest) (*MapAuthReply, error) - mustEmbedUnimplementedUpstreamRegistryServer() -} - -// UnimplementedUpstreamRegistryServer must be embedded to have forward compatible implementations. -type UnimplementedUpstreamRegistryServer struct { -} - -func (UnimplementedUpstreamRegistryServer) FindUpstream(context.Context, *FindUpstreamRequest) (*FindUpstreamReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method FindUpstream not implemented") -} -func (UnimplementedUpstreamRegistryServer) VerifyHostKey(context.Context, *VerifyHostKeyRequest) (*VerifyHostKeyReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method VerifyHostKey not implemented") -} -func (UnimplementedUpstreamRegistryServer) MapAuth(context.Context, *MapAuthRequest) (*MapAuthReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method MapAuth not implemented") -} -func (UnimplementedUpstreamRegistryServer) mustEmbedUnimplementedUpstreamRegistryServer() {} - -// UnsafeUpstreamRegistryServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to UpstreamRegistryServer will -// result in compilation errors. -type UnsafeUpstreamRegistryServer interface { - mustEmbedUnimplementedUpstreamRegistryServer() -} - -func RegisterUpstreamRegistryServer(s grpc.ServiceRegistrar, srv UpstreamRegistryServer) { - s.RegisterService(&UpstreamRegistry_ServiceDesc, srv) -} - -func _UpstreamRegistry_FindUpstream_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FindUpstreamRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UpstreamRegistryServer).FindUpstream(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpcupstream.UpstreamRegistry/FindUpstream", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UpstreamRegistryServer).FindUpstream(ctx, req.(*FindUpstreamRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _UpstreamRegistry_VerifyHostKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(VerifyHostKeyRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UpstreamRegistryServer).VerifyHostKey(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpcupstream.UpstreamRegistry/VerifyHostKey", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UpstreamRegistryServer).VerifyHostKey(ctx, req.(*VerifyHostKeyRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _UpstreamRegistry_MapAuth_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MapAuthRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UpstreamRegistryServer).MapAuth(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpcupstream.UpstreamRegistry/MapAuth", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UpstreamRegistryServer).MapAuth(ctx, req.(*MapAuthRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// UpstreamRegistry_ServiceDesc is the grpc.ServiceDesc for UpstreamRegistry service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var UpstreamRegistry_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "grpcupstream.UpstreamRegistry", - HandlerType: (*UpstreamRegistryServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "FindUpstream", - Handler: _UpstreamRegistry_FindUpstream_Handler, - }, - { - MethodName: "VerifyHostKey", - Handler: _UpstreamRegistry_VerifyHostKey_Handler, - }, - { - MethodName: "MapAuth", - Handler: _UpstreamRegistry_MapAuth_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "upstream.proto", -} diff --git a/sshpiperd/upstream/kubernetes/README.md b/sshpiperd/upstream/kubernetes/README.md deleted file mode 100644 index 093ddcb3..00000000 --- a/sshpiperd/upstream/kubernetes/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# Kubernetes upstream for SSHPiper - -Kubernetes api is called to retreive sshpiper configuration. - -## Usage - -First install CRD - -``` -$ kubectl apply -f https://raw.githubusercontent.com/pockost/sshpipe-k8s-lib/v0.0.3/artifacts/sshpipe.yaml -``` - -You can now add a new sshpipe object - -``` -apiVersion: pockost.com/v1beta1 -kind: SshPipe -metadata: - name: sftp2 -spec: - users: - - user2 - target: - name: sftp2 -``` - -You can find more example in [the example folder](example) - -## ssh host key - -If the `/etc/ssh/ssh_host_rsa_key` does not exist at startup the -sshpiper container generate one. This mean each time the `sshpiper` pod -is recreated a new `ssh_host_rsa_key` will be generated. - -To prevent this you can generate a new `ssh_host_rsa_key` and store this -one in a Secret object. - -``` -$ docker run --rm farmer1992/sshpiperd /sshpiperd genkey > ssh_host_rsa_key -$ kubectl -n sshpiper create secret generic sshpiper --from-file ssh_host_rsa_key -``` - -You can now inject this secret in /etc/ssh/ssh_host_rsa_key. - -``` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: sshpiper - namespace: sshpiper -spec: - replicas: 1 - selector: - matchLabels: - app: sshpiper - template: - metadata: - labels: - app: sshpiper - spec: - serviceAccountName: sshpiper - containers: - - name: sshpiper - image: lermit/sshpiper - imagePullPolicy: Always - env: - - name: SSHPIPERD_UPSTREAM_DRIVER - value: kubernetes - volumeMounts: - - name: secrets - mountPath: /etc/ssh/ssh_host_rsa_key - subPath: ssh_host_rsa_key - volumes: - - name: secrets - secret: - secretName: sshpiper -``` - -**Note**: You can uncomment corresponding line in the example folder. diff --git a/sshpiperd/upstream/kubernetes/TODO b/sshpiperd/upstream/kubernetes/TODO deleted file mode 100644 index 0cac772c..00000000 --- a/sshpiperd/upstream/kubernetes/TODO +++ /dev/null @@ -1,4 +0,0 @@ -* Permit connection with KUBECONFIG env var -* Detect port from service -* Use Watch in order to subscribe to SshPipe CRD change in order to reduce api call -* Create helm chart diff --git a/sshpiperd/upstream/kubernetes/crd.yaml b/sshpiperd/upstream/kubernetes/crd.yaml deleted file mode 100644 index 243f4e79..00000000 --- a/sshpiperd/upstream/kubernetes/crd.yaml +++ /dev/null @@ -1,75 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - # name must match the spec fields below, and be in the form: . - name: sshpipes.pockost.com -spec: - # group name to use for REST API: /apis// - group: pockost.com - # list of versions supported by this CustomResourceDefinition - versions: - - name: v1beta1 - # Each version can be enabled/disabled by Served flag. - served: true - # One and only one version must be marked as the storage version. - storage: true - additionalPrinterColumns: - - jsonPath: .spec.users - name: Users - type: string - - jsonPath: .spec.target.name - name: Service - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: Sshpipe is a pipe configuration for sshpipe - type: object - required: - - metadata - - spec - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - type: object - required: - - users - - target - properties: - users: - description: list of users that should be routed to selected target service. - type: array - items: - type: string - target: - description: service to route ssh/sftp connection to. - type: object - required: - - name - properties: - name: - description: The service name - type: string - port: - description: The service port - type: integer - default: 22 - # either Namespaced or Cluster - scope: Namespaced - names: - # plural name to be used in the URL: /apis/// - plural: sshpipes - # singular name to be used as an alias on the CLI and for display - singular: sshpipe - # kind is normally the CamelCased singular type. Your resource manifests use this. - kind: SshPipe diff --git a/sshpiperd/upstream/kubernetes/example/deploy-sftp.yaml b/sshpiperd/upstream/kubernetes/example/deploy-sftp.yaml deleted file mode 100644 index ccae479a..00000000 --- a/sshpiperd/upstream/kubernetes/example/deploy-sftp.yaml +++ /dev/null @@ -1,118 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: sftp1 -spec: - replicas: 1 - selector: - matchLabels: - app: sftp1 - template: - metadata: - labels: - app: sftp1 - spec: - containers: - - name: sftp - image: atmoz/sftp - volumeMounts: - - name: data - mountPath: /home/user1/ - args: - - "user1:pass" - volumes: - - name: data - persistentVolumeClaim: - claimName: sftp1-data ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: sftp1-data -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - # The amount of the volume's storage to request - storage: 1Gi ---- -apiVersion: v1 -kind: Service -metadata: - name: sftp1 -spec: - ports: - - port: 22 - selector: - app: sftp1 ---- -apiVersion: pockost.com/v1beta1 -kind: SshPipe -metadata: - name: sftp1 -spec: - users: - - user1 - target: - name: sftp1 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: sftp2 -spec: - replicas: 1 - selector: - matchLabels: - app: sftp2 - template: - metadata: - labels: - app: sftp2 - spec: - containers: - - name: sftp - image: atmoz/sftp - volumeMounts: - - name: data - mountPath: /home/user2/ - args: - - "user2:pass" - volumes: - - name: data - persistentVolumeClaim: - claimName: sftp2-data ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: sftp2-data -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - # The amount of the volume's storage to request - storage: 1Gi ---- -apiVersion: v1 -kind: Service -metadata: - name: sftp2 -spec: - ports: - - port: 22 - selector: - app: sftp2 ---- -apiVersion: pockost.com/v1beta1 -kind: SshPipe -metadata: - name: sftp2 -spec: - users: - - user2 - target: - name: sftp2 diff --git a/sshpiperd/upstream/kubernetes/example/sshpiper.yaml b/sshpiperd/upstream/kubernetes/example/sshpiper.yaml deleted file mode 100644 index b7a6f37a..00000000 --- a/sshpiperd/upstream/kubernetes/example/sshpiper.yaml +++ /dev/null @@ -1,80 +0,0 @@ ---- -apiVersion: v1 -kind: Namespace -metadata: - name: sshpiper ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: sshpiper - namespace: sshpiper -spec: - replicas: 1 - selector: - matchLabels: - app: sshpiper - template: - metadata: - labels: - app: sshpiper - spec: - serviceAccountName: sshpiper - containers: - - name: sshpiper - image: lermit/sshpiper - imagePullPolicy: Always - env: - - name: SSHPIPERD_UPSTREAM_DRIVER - value: kubernetes -# volumeMounts: -# - name: secrets -# mountPath: /etc/ssh/ssh_host_rsa_key -# subPath: ssh_host_rsa_key -# volumes: -# - name: secrets -# secret: -# secretName: sshpiper ---- -apiVersion: v1 -kind: Service -metadata: - name: sshpiper - namespace: sshpiper -spec: - type: LoadBalancer - ports: - - port: 2222 - targetPort: 2222 - selector: - app: sshpiper ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: sshpiper - namespace: sshpiper ---- -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: sshpiper - namespace: sshpiper -rules: -- apiGroups: ["pockost.com"] - resources: ["sshpipes"] - verbs: ["watch", "get", "list"] ---- -# This role binding allows "jane" to read pods in the "default" namespace. -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: sshpiper -subjects: -- kind: ServiceAccount - name: sshpiper - namespace: sshpiper -roleRef: - kind: ClusterRole #this must be Role or ClusterRole - name: sshpiper - apiGroup: rbac.authorization.k8s.io diff --git a/sshpiperd/upstream/kubernetes/kubernetes.go b/sshpiperd/upstream/kubernetes/kubernetes.go deleted file mode 100644 index 5dc14bfd..00000000 --- a/sshpiperd/upstream/kubernetes/kubernetes.go +++ /dev/null @@ -1,124 +0,0 @@ -package kubernetes - -import ( - "context" - "fmt" - "net" - - //"path/filepath" - //"strings" - - "github.com/tg123/sshpiper/sshpiperd/upstream" - "golang.org/x/crypto/ssh" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/rest" - - //"k8s.io/client-go/util/homedir" - //"k8s.io/client-go/tools/clientcmd" - sshpipeclientset "github.com/pockost/sshpipe-k8s-lib/pkg/client/clientset/versioned" -) - -type pipeConfig struct { - Username string `kubernetes:"username"` - UpstreamHost string `kubernetes:"upstream_host"` -} - -// type createPipeCtx struct { -// pipe pipeConfig -// conn ssh.ConnMetadata -// challengeContext ssh.AdditionalChallengeContext -// } - -func (p *plugin) getClientSet() (*sshpipeclientset.Clientset, error) { - - // var kubeconfig string - // home := homedir.HomeDir() - // kubeconfig = filepath.Join(home, ".kube", "config") - - // // use the current context in kubeconfig - // config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) - // if err != nil { - // return nil, err - // } - config, err := rest.InClusterConfig() - if err != nil { - return nil, err - } - - // create the clientset - clientset, err := sshpipeclientset.NewForConfig(config) - if err != nil { - return nil, err - } - - return clientset, nil -} - -func (p *plugin) getConfig(clientset *sshpipeclientset.Clientset, sshPipeName string) (pipeConfig, error) { - listOptions := metav1.ListOptions{} - - pipes, err := clientset.PockostV1beta1().SshPipes("").List(context.TODO(), listOptions) - if err != nil { - return pipeConfig{}, err - } - - if err != nil { - return pipeConfig{}, err - } - - for _, pipe := range pipes.Items { - if pipe.Name == sshPipeName { - targetHost := fmt.Sprintf("%s.%s", pipe.Spec.Target.Name, pipe.ObjectMeta.Namespace) - return pipeConfig{ - Username: pipe.Spec.Users[0], - UpstreamHost: targetHost, - }, nil - } - } - - return pipeConfig{}, fmt.Errorf("sshPipe [%s] not found", sshPipeName) -} - -func (p *plugin) createAuthPipe(pipe pipeConfig, conn ssh.ConnMetadata, challengeContext ssh.AdditionalChallengeContext) (*ssh.AuthPipe, error) { - hostKeyCallback := ssh.InsecureIgnoreHostKey() - - a := &ssh.AuthPipe{ - User: pipe.Username, - UpstreamHostKeyCallback: hostKeyCallback, - } - - a.PasswordCallback = func(conn ssh.ConnMetadata, password []byte) (ssh.AuthPipeType, ssh.AuthMethod, error) { - return ssh.AuthPipeTypePassThrough, nil, nil - } - - return a, nil -} - -func (p *plugin) findUpstream(conn ssh.ConnMetadata, challengeContext ssh.AdditionalChallengeContext) (net.Conn, *ssh.AuthPipe, error) { - user := conn.User() - - clientset, err := p.getClientSet() - if err != nil { - return nil, nil, err - } - - // Get config from k8s - pipeConfig, err := p.getConfig(clientset, user) - if err != nil { - return nil, nil, err - } - - // Retreive corresponding configuration - c, err := upstream.DialForSSH(pipeConfig.UpstreamHost) - if err != nil { - return nil, nil, err - } - - a, err := p.createAuthPipe(pipeConfig, conn, challengeContext) - if err != nil { - return nil, nil, err - } - - p.logger.Printf("SSH Pipe [%s] forwarding connection to [%s] with user [%s]", user, pipeConfig.UpstreamHost, pipeConfig.Username) - return c, a, nil -} diff --git a/sshpiperd/upstream/kubernetes/pipemgr.go b/sshpiperd/upstream/kubernetes/pipemgr.go deleted file mode 100644 index 185e948a..00000000 --- a/sshpiperd/upstream/kubernetes/pipemgr.go +++ /dev/null @@ -1,57 +0,0 @@ -package kubernetes - -import ( - "context" - "fmt" - - "github.com/tg123/sshpiper/sshpiperd/upstream" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// Return All pipes inside upstream -func (p *plugin) ListPipe() ([]upstream.Pipe, error) { - pipes := []upstream.Pipe{} - clientset, err := p.getClientSet() - if err != nil { - return nil, err - } - pipeList, err := clientset.PockostV1beta1().SshPipes("").List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return nil, err - } - for _, p := range pipeList.Items { - targetHost := fmt.Sprintf("%s.%s", p.Spec.Target.Name, p.ObjectMeta.Namespace) - pipes = append(pipes, upstream.Pipe{ - Username: p.Name, - UpstreamUsername: p.Spec.Users[0], - Host: targetHost, - Port: 22, - }) - } - return pipes, nil -} - -// Create a pipe inside upstream -func (p *plugin) CreatePipe(opt upstream.CreatePipeOption) error { - return nil -} - -// Remove a pipe from upstream -func (p *plugin) RemovePipe(name string) error { - clientset, err := p.getClientSet() - if err != nil { - return err - } - pipeList, err := clientset.PockostV1beta1().SshPipes("").List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return err - } - - for _, p := range pipeList.Items { - if p.Name == name { - return clientset.PockostV1beta1().SshPipes(p.ObjectMeta.Namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}) - } - } - - return fmt.Errorf("SSH Pipe [%s] not found", name) -} diff --git a/sshpiperd/upstream/kubernetes/plugin.go b/sshpiperd/upstream/kubernetes/plugin.go deleted file mode 100644 index bca52380..00000000 --- a/sshpiperd/upstream/kubernetes/plugin.go +++ /dev/null @@ -1,39 +0,0 @@ -package kubernetes - -import ( - log "github.com/sirupsen/logrus" - - "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -type plugin struct { - Config struct { - } - - logger *log.Logger -} - -// The name of the Plugin -func (p *plugin) GetName() string { - return "kubernetes" -} - -// A ref to a struct which holds the options for the plugins -// will be populated by cmd or other plugin runners -func (p *plugin) GetOpts() interface{} { - return &p.Config -} - -// Will be called before the Plugin is used to ensure the Plugin is ready -func (p *plugin) Init(logger *log.Logger) error { - p.logger = logger - return nil -} - -func (p *plugin) GetHandler() upstream.Handler { - return p.findUpstream -} - -func init() { - upstream.Register("kubernetes", &plugin{}) -} diff --git a/sshpiperd/upstream/provider.go b/sshpiperd/upstream/provider.go deleted file mode 100644 index 7659504d..00000000 --- a/sshpiperd/upstream/provider.go +++ /dev/null @@ -1,124 +0,0 @@ -package upstream - -import ( - "fmt" - "net" - "strconv" - - "golang.org/x/crypto/ssh" - - "github.com/tg123/sshpiper/sshpiperd/registry" - "github.com/tg123/sshpiper/sshpiperd/v0bridge" -) - -// Handler will be installed into sshpiper and help to establish the connection to upstream -// the returned auth pipe is to map/convert downstream auth method to another auth for -// connecting to upstream. -// e.g. map downstream public key to another upstream private key -type Handler func(conn ssh.ConnMetadata, challengeContext ssh.ChallengeContext) (net.Conn, *v0bridge.AuthPipe, error) - -// CreatePipeOption contains options for creating a pipe to upstream -type CreatePipeOption struct { - Username string - UpstreamUsername string - Host string - Port int -} - -// Pipe is a connection which linked downstream and upstream -// SSHPiper searches pipe base on username -type Pipe struct { - Username string - UpstreamUsername string - Host string - Port int -} - -// PipeManager manages pipe inside upstream -type PipeManager interface { - - // Return All pipes inside upstream - ListPipe() ([]Pipe, error) - - // Create a pipe inside upstream - CreatePipe(opt CreatePipeOption) error - - // Remove a pipe from upstream - RemovePipe(name string) error -} - -// Provider is a factory for Upstream Provider -type Provider interface { - registry.Plugin - PipeManager - - GetHandler() Handler -} - -// temp -type V1Provider interface { - registry.Plugin - InstallUpstream(config *ssh.PiperConfig) error -} - -var ( - drivers = registry.NewRegistry() -) - -// Register adds an upstream provider with given name to registry -func Register(name string, driver Provider) { - drivers.Register(name, driver) -} - -// All return all registered upstream providers -func All() []string { - return drivers.Drivers() -} - -// Get returns an upstream provider by name, return nil if not found -func Get(name string) Provider { - if d, ok := drivers.Get(name).(Provider); ok { - return d - - } - - return nil -} - -// SplitHostPortForSSH is the modified version of net.SplitHostPort but return port 22 is no port is specified -func SplitHostPortForSSH(addr string) (host string, port int, err error) { - host = addr - h, p, err := net.SplitHostPort(host) - if err == nil { - host = h - port, err = strconv.Atoi(p) - - if err != nil { - return - } - } else if host != "" { - // test valid after concat :22 - if _, _, err = net.SplitHostPort(host + ":22"); err == nil { - port = 22 - } - } - - if host == "" { - err = fmt.Errorf("empty addr") - } - - return -} - -// DialForSSH is the modified version of net.Dial, would add ":22" automaticlly -func DialForSSH(addr string) (net.Conn, error) { - - if _, _, err := net.SplitHostPort(addr); err != nil && addr != "" { - // test valid after concat :22 - if _, _, err := net.SplitHostPort(addr + ":22"); err == nil { - addr += ":22" - } - } - - return net.Dial("tcp", addr) -} diff --git a/sshpiperd/upstream/yaml/pipemgr.go b/sshpiperd/upstream/yaml/pipemgr.go deleted file mode 100644 index 9621feb5..00000000 --- a/sshpiperd/upstream/yaml/pipemgr.go +++ /dev/null @@ -1,250 +0,0 @@ -package yaml - -import ( - "bytes" - "fmt" - "io/ioutil" - - "github.com/tg123/sshpiper/sshpiperd/upstream" - "gopkg.in/yaml.v3" -) - -// Return All pipes inside upstream -func (p *plugin) ListPipe() ([]upstream.Pipe, error) { - - config, err := p.loadConfig() - - if err != nil { - return nil, err - } - - out, err := yaml.Marshal(config) - if err != nil { - return nil, err - } - - fmt.Println(string(out)) - - var pipes []upstream.Pipe - - for _, pipe := range config.Pipes { - host, port, err := upstream.SplitHostPortForSSH(pipe.UpstreamHost) - - if err != nil { - return nil, err - } - - mappeduser := pipe.Authmap.MappedUsername - - if mappeduser == "" { - mappeduser = pipe.Username - } - - pipes = append(pipes, upstream.Pipe{ - Host: host, - Port: port, - UpstreamUsername: mappeduser, - Username: pipe.Username, - }) - } - - return pipes, nil -} - -// func findnode(root *yaml.Node, test func(*yaml.Node) bool) *yaml.Node { -// var q []*yaml.Node - -// q = append(q, root) - -// for len(q) > 0 { -// e := q[0] -// q = q[1:] - -// if test(e) { -// return e -// } - -// for _, n := range e.Content { -// q = append(q, n) -// } -// } - -// return nil -// } - -func findByMapKey(m *yaml.Node, k string) (*yaml.Node, int) { - for i := 1; i < len(m.Content); i += 2 { - if m.Content[i-1].Value == k { - return m.Content[i], i - } - } - - return nil, -1 -} - -func toYamlNode(s interface{}) (*yaml.Node, error) { - t := yaml.Node{} - - out, err := yaml.Marshal(s) - if err != nil { - return nil, err - } - - err = yaml.Unmarshal(out, &t) - if err != nil { - return nil, err - } - - return t.Content[0], nil -} - -func (p *plugin) loadConfigRaw() ([]byte, *yaml.Node, error) { - var config yaml.Node - - configbyte, err := ioutil.ReadFile(p.Config.File) - if err != nil { - return nil, nil, err - } - - err = yaml.Unmarshal(configbyte, &config) - if err != nil { - return nil, nil, err - } - - return configbyte, &config, nil -} - -func (p *plugin) writeConfig(config []byte) error { - return ioutil.WriteFile(p.Config.File, config, 0600) -} - -func toPipeConfig(opt upstream.CreatePipeOption) pipeConfig { - p := pipeConfig{ - Username: opt.Username, - UpstreamHost: fmt.Sprintf("%v:%v", opt.Host, opt.Port), - } - - if len(opt.UpstreamUsername) > 0 { - p.Authmap.MappedUsername = opt.UpstreamUsername - } - - return p -} - -// Create a pipe inside upstream -func (p *plugin) CreatePipe(opt upstream.CreatePipeOption) error { - configbyte, config, err := p.loadConfigRaw() - - if err != nil { - return err - } - - if len(config.Content) == 0 { - var buf bytes.Buffer - buf.Write(configbyte) - fmt.Fprintln(&buf) - - out, err := yaml.Marshal(piperConfig{ - Version: "0.1", - Pipes: []pipeConfig{toPipeConfig(opt)}, - }) - - if err != nil { - return err - } - - buf.Write(out) - - return p.writeConfig(buf.Bytes()) - } - - pipes, idx := findByMapKey(config.Content[0], "pipes") - - if idx > 0 && pipes.Tag == "!!null" { - // replace null - t, err := toYamlNode([]pipeConfig{toPipeConfig(opt)}) - if err != nil { - return err - } - - config.Content[0].Content[idx] = t - - out, err := yaml.Marshal(config) - if err != nil { - return err - } - - return p.writeConfig(out) - } - - if pipes.Kind != yaml.SequenceNode { - return fmt.Errorf("pipes should be !!seq") - } - - for _, pnode := range pipes.Content { - pipe, _ := findByMapKey(pnode, "username") - - if pipe != nil && pipe.Value == opt.Username { - return fmt.Errorf("username [%v] already exists", opt.Username) - } - } - - // append - - { - t, err := toYamlNode(toPipeConfig(opt)) - if err != nil { - return err - } - - pipes.Content = append(pipes.Content, t) - - out, err := yaml.Marshal(config) - if err != nil { - return err - } - - return p.writeConfig(out) - } -} - -// Remove a pipe from upstream -func (p *plugin) RemovePipe(name string) error { - _, config, err := p.loadConfigRaw() - - if err != nil { - return err - } - - if len(config.Content) == 0 { - return nil - } - - pipes, idx := findByMapKey(config.Content[0], "pipes") - - if idx > 0 && pipes.Tag == "!!null" { - return nil - } - - if pipes.Kind != yaml.SequenceNode { - return fmt.Errorf("pipes should be !!seq") - } - - for i, pnode := range pipes.Content { - pipe, _ := findByMapKey(pnode, "username") - - if pipe != nil && pipe.Value == name { - rest := pipes.Content[i+1:] - pipes.Content = append(pipes.Content[:i], rest...) - - out, err := yaml.Marshal(config) - if err != nil { - return err - } - - return p.writeConfig(out) - } - } - - return nil -} diff --git a/sshpiperd/upstream/yaml/plugin.go b/sshpiperd/upstream/yaml/plugin.go deleted file mode 100644 index 385f17ba..00000000 --- a/sshpiperd/upstream/yaml/plugin.go +++ /dev/null @@ -1,41 +0,0 @@ -package yaml - -import ( - log "github.com/sirupsen/logrus" - - "github.com/tg123/sshpiper/sshpiperd/upstream" -) - -type plugin struct { - Config struct { - File string `long:"upstream-yaml-file" default:"/var/sshpiper/sshpiperd.yaml" description:"Yaml config file path" env:"SSHPIPERD_UPSTREAM_YAML_FILE" ini-name:"upstream-yaml-file"` - NoCheckPerm bool `long:"upstream-yaml-nocheckperm" description:"Disable 0400 checking when using config file" env:"SSHPIPERD_UPSTREAM_YAML_NOCHECKPERM" ini-name:"upstream-yaml-nocheckperm"` - } - - logger *log.Logger -} - -// The name of the Plugin -func (p *plugin) GetName() string { - return "yaml" -} - -// A ref to a struct which holds the options for the plugins -// will be populated by cmd or other plugin runners -func (p *plugin) GetOpts() interface{} { - return &p.Config -} - -// Will be called before the Plugin is used to ensure the Plugin is ready -func (p *plugin) Init(logger *log.Logger) error { - p.logger = logger - return nil -} - -func (p *plugin) GetHandler() upstream.Handler { - return p.findUpstream -} - -func init() { - upstream.Register("yaml", &plugin{}) -} diff --git a/sshpiperd/upstream/yaml/schema.json b/sshpiperd/upstream/yaml/schema.json deleted file mode 100644 index 408e5b76..00000000 --- a/sshpiperd/upstream/yaml/schema.json +++ /dev/null @@ -1,165 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-06/schema#", - "$ref": "#/definitions/sshpiperd", - "definitions": { - "sshpiperd": { - "type": "object", - "additionalProperties": false, - "properties": { - "version": { - "type": "string" - }, - "pipes": { - "type": "array", - "items": { - "$ref": "#/definitions/pipe" - } - } - }, - "required": [ - "pipes", - "version" - ] - }, - "pipe": { - "type": "object", - "additionalProperties": false, - "properties": { - "username": { - "type": "string" - }, - "upstream_host": { - "type": "string" - }, - "ignore_hostkey": { - "type": "boolean" - }, - "authmap": { - "$ref": "#/definitions/authmap" - }, - "username_regex_match": { - "type": "boolean" - }, - "known_hosts": { - "type": "string" - }, - "known_hosts_data": { - "type": "string" - } - }, - "required": [ - "authmap", - "upstream_host" - ] - }, - "authmap": { - "type": "object", - "additionalProperties": false, - "properties": { - "mapped_username": { - "type": "string" - }, - "from": { - "type": "array", - "items": { - "$ref": "#/definitions/from" - } - }, - "to": { - "$ref": "#/definitions/to" - }, - "no_passthrough": { - "type": "boolean" - } - } - }, - "from": { - "type": "object", - "additionalProperties": false, - "properties": { - "type": { - "type": "string", - "oneOf": [ - { - "enum": [ - "none", - "password", - "publickey", - "any" - ] - } - ] - }, - "password": { - "type": "string" - }, - "authorized_keys": { - "type": "string" - }, - "authorized_keys_data": { - "type": "string" - }, - "allow_any_public_key": { - "type": "boolean" - } - }, - "required": [ - "type" - ] - }, - "to": { - "type": "object", - "additionalProperties": false, - "properties": { - "type": { - "type": "string", - "oneOf": [ - { - "enum": [ - "none", - "password", - "privatekey" - ] - } - ] - }, - "password": { - "type": "string" - }, - "private_key": { - "type": "string" - }, - "private_key_data": { - "type": "string" - }, - "key_map": { - "type": "array", - "items": { - "$ref": "#/definitions/keymap" - } - } - }, - "required": [ - "type" - ] - }, - "keymap": { - "type": "object", - "additionalProperties": false, - "properties": { - "authorized_keys": { - "type": "string" - }, - "authorized_keys_data": { - "type": "string" - }, - "private_key": { - "type": "string" - }, - "private_key_data": { - "type": "string" - } - } - } - } -} diff --git a/sshpiperd/upstream/yaml/yaml.go b/sshpiperd/upstream/yaml/yaml.go deleted file mode 100644 index 40f45f05..00000000 --- a/sshpiperd/upstream/yaml/yaml.go +++ /dev/null @@ -1,380 +0,0 @@ -package yaml - -import ( - "bytes" - "encoding/base64" - "fmt" - "io/ioutil" - "net" - "os" - "path/filepath" - "regexp" - - "github.com/tg123/sshpiper/sshpiperd/upstream" - "github.com/tg123/sshpiper/sshpiperd/v0bridge" - "golang.org/x/crypto/ssh" - "golang.org/x/crypto/ssh/knownhosts" - "gopkg.in/yaml.v3" -) - -type pipeConfig struct { - Username string `yaml:"username"` - UsernameRegexMatch bool `yaml:"username_regex_match,omitempty"` - UpstreamHost string `yaml:"upstream_host"` - Authmap struct { - MappedUsername string `yaml:"mapped_username,omitempty"` - From []struct { - Type string `yaml:"type"` - Password string `yaml:"password,omitempty"` - AuthorizedKeys string `yaml:"authorized_keys,omitempty"` - AuthorizedKeysData string `yaml:"authorized_keys_data,omitempty"` - AllowAnyPublicKey bool `yaml:"allow_any_public_key,omitempty"` - } `yaml:"from,flow"` - - To struct { - Type string `yaml:"type"` - Password string `yaml:"password,omitempty"` - PrivateKey string `yaml:"private_key,omitempty"` - PrivateKeyData string `yaml:"private_key_data,omitempty"` - KeyMap []struct { - AuthorizedKeys string `yaml:"authorized_keys,omitempty"` - AuthorizedKeysData string `yaml:"authorized_keys_data,omitempty"` - PrivateKey string `yaml:"private_key,omitempty"` - PrivateKeyData string `yaml:"private_key_data,omitempty"` - } `yaml:"key_map,flow"` - } `yaml:"to,flow"` - - NoPassthrough bool `yaml:"no_passthrough,omitempty"` - } `yaml:"authmap,omitempty,flow"` - - KnownHosts string `yaml:"known_hosts,omitempty"` - KnownHostsData string `yaml:"known_hosts_data,omitempty"` - IgnoreHostkey bool `yaml:"ignore_hostkey,omitempty"` -} - -type piperConfig struct { - Version string `yaml:"version"` - Pipes []pipeConfig `yaml:"pipes,flow"` -} - -func (p *plugin) checkPerm() error { - filename := p.Config.File - f, err := os.Open(filename) - if err != nil { - return err - } - defer f.Close() - - fi, err := f.Stat() - if err != nil { - return err - } - - if p.Config.NoCheckPerm { - return nil - } - - if fi.Mode().Perm()&0077 != 0 { - return fmt.Errorf("%v's perm is too open", filename) - } - - return nil -} - -func (p *plugin) loadConfig() (piperConfig, error) { - var config piperConfig - - err := p.checkPerm() - - if err != nil { - return config, err - } - - configbyte, err := ioutil.ReadFile(p.Config.File) - if err != nil { - return config, err - } - - err = yaml.Unmarshal(configbyte, &config) - if err != nil { - return config, err - } - - return config, nil -} - -type createPipeCtx struct { - pipe pipeConfig - conn ssh.ConnMetadata - challengeContext ssh.ChallengeContext -} - -func (p *plugin) loadFileOrDecode(file string, base64data string, ctx createPipeCtx) ([]byte, error) { - if file != "" { - - file = os.Expand(file, func(placeholderName string) string { - switch placeholderName { - case "USER": - return ctx.conn.User() - case "MAPPED_USER": - return ctx.pipe.Authmap.MappedUsername - } - - return os.Getenv(placeholderName) - }) - - if !filepath.IsAbs(file) { - file = filepath.Join(filepath.Dir(p.Config.File), file) - } - - return ioutil.ReadFile(file) - } - - if base64data != "" { - return base64.StdEncoding.DecodeString(base64data) - } - - return nil, nil -} - -func (p *plugin) createAuthPipe(pipe pipeConfig, conn ssh.ConnMetadata, challengeContext ssh.ChallengeContext) (*v0bridge.AuthPipe, error) { - ctx := createPipeCtx{pipe, conn, challengeContext} - - hostKeyCallback := ssh.InsecureIgnoreHostKey() - if !pipe.IgnoreHostkey { - - data, err := p.loadFileOrDecode(pipe.KnownHosts, pipe.KnownHostsData, ctx) - if err != nil { - return nil, err - } - - if len(data) == 0 { - return nil, fmt.Errorf("no known hosts spicified") - } - - hostKeyCallback, err = knownhosts.NewFromReader(bytes.NewReader(data)) - if err != nil { - return nil, err - } - } - - to := func(key ssh.PublicKey) (v0bridge.AuthPipeType, ssh.AuthMethod, error) { - - switch pipe.Authmap.To.Type { - case "none": - return v0bridge.AuthPipeTypeNone, nil, nil - - case "password": - return v0bridge.AuthPipeTypeMap, ssh.Password(pipe.Authmap.To.Password), nil - - case "privatekey": - - privateBytes, err := p.loadFileOrDecode(pipe.Authmap.To.PrivateKey, pipe.Authmap.To.PrivateKeyData, ctx) - if err != nil { - return v0bridge.AuthPipeTypeDiscard, nil, err - } - - // did not find to 1 private key try key map - if len(privateBytes) == 0 && key != nil { - for _, privkey := range pipe.Authmap.To.KeyMap { - rest, err := p.loadFileOrDecode(privkey.AuthorizedKeys, privkey.AuthorizedKeysData, ctx) - if err != nil { - return v0bridge.AuthPipeTypeDiscard, nil, err - } - - var authedPubkey ssh.PublicKey - - for len(rest) > 0 { - authedPubkey, _, _, rest, err = ssh.ParseAuthorizedKey(rest) - if err != nil { - return v0bridge.AuthPipeTypeDiscard, nil, err - } - - keydata := key.Marshal() - - if bytes.Equal(authedPubkey.Marshal(), keydata) { - privateBytes, err = p.loadFileOrDecode(privkey.PrivateKey, privkey.PrivateKeyData, ctx) - - if err != nil { - return v0bridge.AuthPipeTypeDiscard, nil, err - } - - if len(privateBytes) > 0 { - // found mapped - break - } - } - } - - } - } - - if len(privateBytes) == 0 { - return v0bridge.AuthPipeTypeDiscard, nil, fmt.Errorf("no private key found") - } - - private, err := ssh.ParsePrivateKey(privateBytes) - if err != nil { - return v0bridge.AuthPipeTypeDiscard, nil, err - } - - return v0bridge.AuthPipeTypeMap, ssh.PublicKeys(private), nil - - default: - p.logger.Printf("unsupport type [%v] fallback to passthrough", pipe.Authmap.To.Type) - } - - if pipe.Authmap.NoPassthrough { - return v0bridge.AuthPipeTypeDiscard, nil, nil - } - - return v0bridge.AuthPipeTypePassThrough, nil, nil - } - - allowPasswords := make(map[string]bool) - var allowPubKeys []ssh.PublicKey - allowAnyPubKey := false - - a := &v0bridge.AuthPipe{ - User: pipe.Authmap.MappedUsername, - - UpstreamHostKeyCallback: hostKeyCallback, - } - - for _, from := range pipe.Authmap.From { - switch from.Type { - case "none": - - if a.NoneAuthCallback == nil { - a.NoneAuthCallback = func(conn ssh.ConnMetadata) (v0bridge.AuthPipeType, ssh.AuthMethod, error) { - return to(nil) - } - } - - case "password": - allowPasswords[from.Password] = true - - if a.PasswordCallback == nil { - a.PasswordCallback = func(conn ssh.ConnMetadata, password []byte) (v0bridge.AuthPipeType, ssh.AuthMethod, error) { - - _, ok := allowPasswords[string(password)] - - if ok { - return to(nil) - } - - if pipe.Authmap.NoPassthrough { - return v0bridge.AuthPipeTypeDiscard, nil, nil - } - - return v0bridge.AuthPipeTypePassThrough, nil, nil - } - } - - case "publickey": - - allowAnyPubKey = allowAnyPubKey || from.AllowAnyPublicKey - - if !allowAnyPubKey { - - rest, err := p.loadFileOrDecode(from.AuthorizedKeys, from.AuthorizedKeysData, ctx) - if err != nil { - return nil, err - } - - var authedPubkey ssh.PublicKey - - for len(rest) > 0 { - authedPubkey, _, _, rest, err = ssh.ParseAuthorizedKey(rest) - if err != nil { - return nil, err - } - - allowPubKeys = append(allowPubKeys, authedPubkey) - } - } - - if a.PublicKeyCallback == nil { - a.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (v0bridge.AuthPipeType, ssh.AuthMethod, error) { - - if allowAnyPubKey { - return to(key) - } - - keydata := key.Marshal() - - for _, authedPubkey := range allowPubKeys { - if bytes.Equal(authedPubkey.Marshal(), keydata) { - return to(key) - } - } - - if pipe.Authmap.NoPassthrough { - return v0bridge.AuthPipeTypeDiscard, nil, nil - } - - // will fail but discard will lead a timeout - return v0bridge.AuthPipeTypePassThrough, nil, nil - } - } - - case "any": - a.NoneAuthCallback = func(conn ssh.ConnMetadata) (v0bridge.AuthPipeType, ssh.AuthMethod, error) { - return to(nil) - } - - a.PasswordCallback = func(conn ssh.ConnMetadata, password []byte) (v0bridge.AuthPipeType, ssh.AuthMethod, error) { - return to(nil) - } - - a.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (v0bridge.AuthPipeType, ssh.AuthMethod, error) { - return to(key) - } - - return a, nil - - default: - p.logger.Printf("unsupport type [%v], ignore section", from.Type) - } - - } - - return a, nil -} - -func (p *plugin) findUpstream(conn ssh.ConnMetadata, challengeContext ssh.ChallengeContext) (net.Conn, *v0bridge.AuthPipe, error) { - user := conn.User() - - config, err := p.loadConfig() - - if err != nil { - return nil, nil, err - } - - for _, pipe := range config.Pipes { - matched := pipe.Username == user - - if pipe.UsernameRegexMatch { - matched, _ = regexp.MatchString(pipe.Username, user) - } - - if matched { - - p.logger.Printf("mapping [%v] to [%v@%v]", user, pipe.Authmap.MappedUsername, pipe.UpstreamHost) - - c, err := upstream.DialForSSH(pipe.UpstreamHost) - if err != nil { - return nil, nil, err - } - - a, err := p.createAuthPipe(pipe, conn, challengeContext) - if err != nil { - return nil, nil, err - } - - return c, a, nil - } - } - - return nil, nil, fmt.Errorf("username [%v] not found", user) -} diff --git a/sshpiperd/utils/common.go b/sshpiperd/utils/common.go deleted file mode 100644 index b5b85466..00000000 --- a/sshpiperd/utils/common.go +++ /dev/null @@ -1,17 +0,0 @@ -package utils - -import ( - "fmt" - "net" - "strings" -) - -func FormatIPAddress(host string) string { - ip4 := net.ParseIP(host).To4() - - if ip4 != nil || !strings.Contains(host, ":") { - return host - } - - return fmt.Sprintf("[%s]", host) -} diff --git a/sshpiperd/v0bridge/v0bridge.go b/sshpiperd/v0bridge/v0bridge.go deleted file mode 100644 index 216c796f..00000000 --- a/sshpiperd/v0bridge/v0bridge.go +++ /dev/null @@ -1,200 +0,0 @@ -package v0bridge - -import ( - "fmt" - "net" - - "golang.org/x/crypto/ssh" -) - -type AuthPipeType int - -const ( - // AuthPipeTypePassThrough does nothing but pass auth message to upstream - AuthPipeTypePassThrough AuthPipeType = iota - - // AuthPipeTypeMap converts auth message to AuthMetod return by callback and pass it to upstream - AuthPipeTypeMap - - // AuthPipeTypeDiscard discards auth message, do not pass it to uptream - AuthPipeTypeDiscard - - // AuthPipeTypeNone converts auth message to NoneAuth and pass it to upstream - AuthPipeTypeNone -) - -// AuthPipe contains the callbacks of auth msg mapping from downstream to upstream -// -// when AuthPipeType == AuthPipeTypeMap && AuthMethod == PublicKey -// SSHPiper will sign the auth packet message using the returned Signer. -// This func might be called twice, one is for query message, the other -// is real auth packet message. -// If any error occurs during this period, a NoneAuth packet will be sent to -// upstream ssh server instead. -// More info: https://github.com/tg123/sshpiper#publickey-sign-again -type AuthPipe struct { - // Username to upstream - User string - - // NoneAuthCallback, if non-nil, is called when downstream requests a none auth, - // typically the first auth msg from client to see what auth methods can be used.. - NoneAuthCallback func(conn ssh.ConnMetadata) (AuthPipeType, ssh.AuthMethod, error) - - // PublicKeyCallback, if non-nil, is called when downstream requests a password auth. - PasswordCallback func(conn ssh.ConnMetadata, password []byte) (AuthPipeType, ssh.AuthMethod, error) - - // PublicKeyCallback, if non-nil, is called when downstream requests a publickey auth. - PublicKeyCallback func(conn ssh.ConnMetadata, key ssh.PublicKey) (AuthPipeType, ssh.AuthMethod, error) - - // UpstreamHostKeyCallback is called during the cryptographic - // handshake to validate the uptream server's host key. The piper - // configuration must supply this callback for the connection - // to succeed. The functions InsecureIgnoreHostKey or - // FixedHostKey can be used for simplistic host key checks. - UpstreamHostKeyCallback ssh.HostKeyCallback -} - -type proxy struct { - handler func(conn ssh.ConnMetadata, challengeContext ssh.ChallengeContext) (net.Conn, *AuthPipe, error) - allowedMethod map[string]bool -} - -// ChallengedUsername unused -func (p *proxy) ChallengedUsername() string { - return "" -} - -// Meta unused -func (p *proxy) Meta() interface{} { - return nil -} - -func (p *proxy) CreateChallengeContext(conn ssh.ConnMetadata) (ssh.ChallengeContext, error) { - return p, nil -} - -func CreateUpstream(conn net.Conn, pipe *AuthPipe, authType AuthPipeType, oldMethod, mappedMethod ssh.AuthMethod) (*ssh.Upstream, error) { - - clientConfig := ssh.ClientConfig{ - User: pipe.User, - HostKeyCallback: pipe.UpstreamHostKeyCallback, - } - - switch authType { - case AuthPipeTypePassThrough: - clientConfig.Auth = []ssh.AuthMethod{oldMethod} - - case AuthPipeTypeMap: - clientConfig.Auth = []ssh.AuthMethod{mappedMethod} - case AuthPipeTypeDiscard: - return nil, fmt.Errorf("msg is discarded") - case AuthPipeTypeNone: - clientConfig.Auth = []ssh.AuthMethod{ssh.NoneAuth()} - } - - return &ssh.Upstream{ - Conn: conn, - ClientConfig: clientConfig, - }, nil -} - -func (p *proxy) NextAuthMethods(conn ssh.ConnMetadata, challengeCtx ssh.ChallengeContext) ([]string, error) { - var allow []string - - for k, v := range p.allowedMethod { - if v { - allow = append(allow, k) - } - } - - return allow, nil -} - -func (p *proxy) UpstreamAuthFailureCallback(onn ssh.ConnMetadata, method string, err error, challengeCtx ssh.ChallengeContext) { - noMoreMethodErr, ok := err.(ssh.NoMoreMethodsErr) - if ok { - for _, allowed := range noMoreMethodErr.Allowed { - p.allowedMethod[allowed] = true - } - - return - } - - p.allowedMethod[method] = false -} - -func (p *proxy) NoneAuthCallback(conn ssh.ConnMetadata, challengeCtx ssh.ChallengeContext) (*ssh.Upstream, error) { - c, pipe, err := p.handler(conn, challengeCtx) - if err != nil { - return nil, err - } - - if pipe.NoneAuthCallback == nil { - return CreateUpstream(c, pipe, AuthPipeTypePassThrough, ssh.NoneAuth(), nil) - } - - t, m, err := pipe.NoneAuthCallback(conn) - if err != nil { - return nil, err - } - - return CreateUpstream(c, pipe, t, ssh.NoneAuth(), m) -} - -func (p *proxy) PasswordCallback(conn ssh.ConnMetadata, password []byte, challengeCtx ssh.ChallengeContext) (*ssh.Upstream, error) { - c, pipe, err := p.handler(conn, challengeCtx) - if err != nil { - return nil, err - } - - if pipe.PasswordCallback == nil { - return CreateUpstream(c, pipe, AuthPipeTypePassThrough, ssh.Password(string(password)), nil) - } - - t, m, err := pipe.PasswordCallback(conn, password) - if err != nil { - return nil, err - } - - return CreateUpstream(c, pipe, t, ssh.Password(string(password)), m) -} - -func (p *proxy) PublicKeyCallback(conn ssh.ConnMetadata, key ssh.PublicKey, challengeCtx ssh.ChallengeContext) (*ssh.Upstream, error) { - c, pipe, err := p.handler(conn, challengeCtx) - if err != nil { - return nil, err - } - - if pipe.PublicKeyCallback == nil { - return CreateUpstream(c, pipe, AuthPipeTypePassThrough, ssh.NoneAuth(), nil) - } - - t, m, err := pipe.PublicKeyCallback(conn, key) - if err != nil { - return nil, err - } - - return CreateUpstream(c, pipe, t, ssh.NoneAuth(), m) // cannt passthrough public key, use none instead -} - -func InstallUpstream(config *ssh.PiperConfig, handler func(conn ssh.ConnMetadata, challengeContext ssh.ChallengeContext) (net.Conn, *AuthPipe, error)) error { - if handler == nil { - return fmt.Errorf("handler is nil") - } - - p := &proxy{ - handler: handler, - allowedMethod: map[string]bool{ - "none": true, - }, - } - - config.CreateChallengeContext = p.CreateChallengeContext - config.NextAuthMethods = p.NextAuthMethods - config.UpstreamAuthFailureCallback = p.UpstreamAuthFailureCallback - config.NoneAuthCallback = p.NoneAuthCallback - config.PasswordCallback = p.PasswordCallback - config.PublicKeyCallback = p.PublicKeyCallback - - return nil -} diff --git a/sshpiperd/ver.go b/sshpiperd/ver.go deleted file mode 100644 index ce3fa63c..00000000 --- a/sshpiperd/ver.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "os" - "runtime/debug" - "text/template" -) - -var version = "(devel)" - -func showVersion() { - versionTemplate := template.Must(template.New("ver").Parse(` -sshpiperd by Boshi Lian -https://github.com/tg123/sshpiper - -Version : {{.VER}} -Go Runtime : {{.GOVER}} -Git Commit : {{.GITHASH}} -Timestamp : {{.TIMESTAMP}} -`[1:])) - - data := struct { - VER string - GOVER string - GITHASH string - TIMESTAMP string - }{ - VER: version, - } - - bi, ok := debug.ReadBuildInfo() - if ok { - for _, s := range bi.Settings { - switch s.Key { - case "vcs.revision": - data.GITHASH = s.Value[:9] - case "vcs.time": - data.TIMESTAMP = s.Value - } - } - - data.GOVER = bi.GoVersion - } - - _ = versionTemplate.Execute(os.Stdout, data) -}