Add upstream banner mode and refactor banner callbacks (#594)
* feat: add upstream banner mode and refactor banner callbacks * chore: update crypto submodule to latest commit * fix: improve usage description for upstream banner mode flag * Update cmd/sshpiperd/daemon.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
2c2d378f86
commit
e6d3bb694b
6 changed files with 31 additions and 12 deletions
|
|
@ -134,7 +134,7 @@ func newDaemon(ctx *cli.Context) (*daemon, error) {
|
||||||
bannerfile := ctx.String("banner-file")
|
bannerfile := ctx.String("banner-file")
|
||||||
|
|
||||||
if bannertext != "" || bannerfile != "" {
|
if bannertext != "" || bannerfile != "" {
|
||||||
config.BannerCallback = func(_ ssh.ConnMetadata, _ ssh.ChallengeContext) string {
|
config.DownstreamBannerCallback = func(_ ssh.ConnMetadata, _ ssh.ChallengeContext) string {
|
||||||
if bannerfile != "" {
|
if bannerfile != "" {
|
||||||
text, err := os.ReadFile(bannerfile)
|
text, err := os.ReadFile(bannerfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -147,6 +147,18 @@ func newDaemon(ctx *cli.Context) (*daemon, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch ctx.String("upstream-banner-mode") {
|
||||||
|
case "passthrough":
|
||||||
|
// library will handle the banner to client
|
||||||
|
case "ignore":
|
||||||
|
config.UpstreamBannerCallback = func(downconn ssh.ServerPreAuthConn, banner string, challengeCtx ssh.ChallengeContext) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// case "dedup":
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown upstream banner mode %q; allowed: 'passthrough' or 'ignore'", ctx.String("upstream-banner-mode"))
|
||||||
|
}
|
||||||
|
|
||||||
return &daemon{
|
return &daemon{
|
||||||
config: config,
|
config: config,
|
||||||
lis: lis,
|
lis: lis,
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ type chainConnMeta struct {
|
||||||
current int
|
current int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *ChainPlugins) CreateChallengeContext(conn ssh.ConnMetadata) (ssh.ChallengeContext, error) {
|
func (cp *ChainPlugins) CreateChallengeContext(conn ssh.ServerPreAuthConn) (ssh.ChallengeContext, error) {
|
||||||
uiq, err := uuid.NewRandom()
|
uiq, err := uuid.NewRandom()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -109,7 +109,7 @@ func (cp *ChainPlugins) NextAuthMethods(conn ssh.ConnMetadata, challengeCtx ssh.
|
||||||
|
|
||||||
func (cp *ChainPlugins) InstallPiperConfig(config *GrpcPluginConfig) error {
|
func (cp *ChainPlugins) InstallPiperConfig(config *GrpcPluginConfig) error {
|
||||||
|
|
||||||
config.CreateChallengeContext = func(conn ssh.ConnMetadata) (ssh.ChallengeContext, error) {
|
config.CreateChallengeContext = func(conn ssh.ServerPreAuthConn) (ssh.ChallengeContext, error) {
|
||||||
ctx, err := cp.CreateChallengeContext(conn)
|
ctx, err := cp.CreateChallengeContext(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("cannot create challenge context %v", err)
|
log.Errorf("cannot create challenge context %v", err)
|
||||||
|
|
@ -143,10 +143,10 @@ func (cp *ChainPlugins) InstallPiperConfig(config *GrpcPluginConfig) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config.BannerCallback = func(conn ssh.ConnMetadata, challengeCtx ssh.ChallengeContext) string {
|
config.DownstreamBannerCallback = func(conn ssh.ConnMetadata, challengeCtx ssh.ChallengeContext) string {
|
||||||
cur := cp.pluginsCallback[challengeCtx.(*chainConnMeta).current]
|
cur := cp.pluginsCallback[challengeCtx.(*chainConnMeta).current]
|
||||||
if cur.BannerCallback != nil {
|
if cur.DownstreamBannerCallback != nil {
|
||||||
return cur.BannerCallback(conn, challengeCtx)
|
return cur.DownstreamBannerCallback(conn, challengeCtx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ func (g *GrpcPlugin) InstallPiperConfig(config *GrpcPluginConfig) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
config.CreateChallengeContext = func(conn ssh.ConnMetadata) (ssh.ChallengeContext, error) {
|
config.CreateChallengeContext = func(conn ssh.ServerPreAuthConn) (ssh.ChallengeContext, error) {
|
||||||
ctx, err := g.CreateChallengeContext(conn)
|
ctx, err := g.CreateChallengeContext(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("cannot create challenge context %v", err)
|
log.Errorf("cannot create challenge context %v", err)
|
||||||
|
|
@ -121,7 +121,7 @@ func (g *GrpcPlugin) InstallPiperConfig(config *GrpcPluginConfig) error {
|
||||||
g.UpstreamAuthFailureCallbackRemote(conn, method, err, challengeCtx)
|
g.UpstreamAuthFailureCallbackRemote(conn, method, err, challengeCtx)
|
||||||
}
|
}
|
||||||
case "Banner":
|
case "Banner":
|
||||||
config.BannerCallback = g.BannerCallback
|
config.DownstreamBannerCallback = g.DownstreamBannerCallback
|
||||||
case "VerifyHostKey":
|
case "VerifyHostKey":
|
||||||
// ignore
|
// ignore
|
||||||
case "PipeStart":
|
case "PipeStart":
|
||||||
|
|
@ -155,7 +155,7 @@ func (m *connMeta) Meta() interface{} {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GrpcPlugin) CreateChallengeContext(conn ssh.ConnMetadata) (ssh.ChallengeContext, error) {
|
func (g *GrpcPlugin) CreateChallengeContext(conn ssh.ServerPreAuthConn) (ssh.ChallengeContext, error) {
|
||||||
uiq, err := uuid.NewRandom()
|
uiq, err := uuid.NewRandom()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -494,7 +494,7 @@ func (g *GrpcPlugin) KeyboardInteractiveCallback(conn ssh.ConnMetadata, client s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GrpcPlugin) BannerCallback(conn ssh.ConnMetadata, challengeCtx ssh.ChallengeContext) string {
|
func (g *GrpcPlugin) DownstreamBannerCallback(conn ssh.ConnMetadata, challengeCtx ssh.ChallengeContext) string {
|
||||||
meta := toMeta(challengeCtx, conn)
|
meta := toMeta(challengeCtx, conn)
|
||||||
reply, err := g.client.Banner(context.Background(), &libplugin.BannerRequest{
|
reply, err := g.client.Banner(context.Background(), &libplugin.BannerRequest{
|
||||||
Meta: meta,
|
Meta: meta,
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,12 @@ func main() {
|
||||||
Usage: "display a banner from file before authentication",
|
Usage: "display a banner from file before authentication",
|
||||||
EnvVars: []string{"SSHPIPERD_BANNERFILE"},
|
EnvVars: []string{"SSHPIPERD_BANNERFILE"},
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "upstream-banner-mode",
|
||||||
|
Value: "passthrough",
|
||||||
|
Usage: "upstream banner mode, allowed values: 'passthrough' (pass the banner from upstream to client) or 'ignore' (ignore the banner from upstream)",
|
||||||
|
EnvVars: []string{"SSHPIPERD_UPSTREAM_BANNER_MODE"},
|
||||||
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "drop-hostkeys-message",
|
Name: "drop-hostkeys-message",
|
||||||
Value: false,
|
Value: false,
|
||||||
|
|
@ -299,6 +305,7 @@ func main() {
|
||||||
log.Errorf("plugin %v recv logs error: %v", p.Name, err)
|
log.Errorf("plugin %v recv logs error: %v", p.Name, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
plugins = append(plugins, p)
|
plugins = append(plugins, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
2
crypto
2
crypto
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2a4b9c2448bc0257714a950e5d61a55d3633eb65
|
Subproject commit ff1e56f4b7ef0bf248a7bba9c996414504ffa09a
|
||||||
|
|
@ -1 +1 @@
|
||||||
sshpiper banner from upstream test
|
sshpiper banner from upstream test
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue