package ssh

import (
	
	
	
	
	
	
	
	
	
	

	
	gossh 
)

// ErrServerClosed is returned by the Server's Serve, ListenAndServe,
// and ListenAndServeTLS methods after a call to Shutdown or Close.
var ErrServerClosed = errors.New("ssh: Server closed")

// SubsystemHandler is a handler for a given SSH subsystem.
type SubsystemHandler func(s Session)

// DefaultSubsystemHandlers is the default set of subsystem handlers.
var DefaultSubsystemHandlers = map[string]SubsystemHandler{}

// RequestHandler is a callback for custom global SSH requests.
type RequestHandler func(ctx Context, srv *Server, req *gossh.Request) (ok bool, payload []byte)

// DefaultRequestHandlers is the default set of request handlers.
var DefaultRequestHandlers = map[string]RequestHandler{}

// ChannelHandler is a callback for custom channel types.
type ChannelHandler func(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx Context)

// DefaultChannelHandlers is the default set of channel handlers.
var DefaultChannelHandlers = map[string]ChannelHandler{
	"session": DefaultSessionHandler,
}

var permissionsPublicKeyExt = "gliderlabs/ssh.PublicKey"

// ErrPermissionDenied is returned when authentication fails.
var ErrPermissionDenied = errors.New("permission denied")

func ensureNoPKInPermissions( Context) error {
	if ,  := .Permissions().Extensions[permissionsPublicKeyExt];  {
		return errors.New("misconfigured server: public key incorrectly set")
	}

	return nil
}

// Server defines parameters for running an SSH server. The zero value for
// Server is a valid configuration. When both PasswordHandler and
// PublicKeyHandler are nil, no client authentication is performed.
type Server struct {
	Addr        string   // TCP address to listen on, ":22" if empty
	Handler     Handler  // handler to invoke, ssh.DefaultHandler if nil
	HostSigners []Signer // private keys for the host key, must have at least one
	Version     string   // server version to be sent before the initial handshake
	Banner      string   // server banner

	BannerHandler                 BannerHandler                 // server banner handler, overrides Banner
	KeyboardInteractiveHandler    KeyboardInteractiveHandler    // keyboard-interactive authentication handler
	PasswordHandler               PasswordHandler               // password authentication handler
	PublicKeyHandler              PublicKeyHandler              // public key authentication handler
	PtyCallback                   PtyCallback                   // callback for allocating and allowing PTY sessions, ssh.EmulatePtyCallback if nil
	PtyHandler                    PtyHandler                    // pty allocation handler, ssh.emulatePtyHandler if nil
	ConnCallback                  ConnCallback                  // optional callback for wrapping net.Conn before handling
	LocalPortForwardingCallback   LocalPortForwardingCallback   // callback for allowing local port forwarding, denies all if nil
	ReversePortForwardingCallback ReversePortForwardingCallback // callback for allowing reverse port forwarding, denies all if nil
	ServerConfigCallback          ServerConfigCallback          // callback for configuring detailed SSH options
	SessionRequestCallback        SessionRequestCallback        // callback for allowing or denying SSH sessions

	ConnectionFailedCallback ConnectionFailedCallback // callback to report connection failures
	ConnectionCloseCallback  ConnectionCloseCallback  // callback to report connection close

	HandshakeTimeout time.Duration // connection timeout until successful handshake, none if empty
	IdleTimeout      time.Duration // connection timeout when no activity, none if empty
	MaxTimeout       time.Duration // absolute connection timeout, none if empty

	EnableProxyProtocol bool // Enable support for HA Proxy's and NGinx's PROXY protocol

	// ChannelHandlers allow overriding the built-in session handlers or provide
	// extensions to the protocol, such as tcpip forwarding. By default only the
	// "session" handler is enabled.
	ChannelHandlers map[string]ChannelHandler

	// RequestHandlers allow overriding the server-level request handlers or
	// provide extensions to the protocol, such as tcpip forwarding. By default
	// no handlers are enabled.
	RequestHandlers map[string]RequestHandler

	// SubsystemHandlers are handlers which are similar to the usual SSH command
	// handlers, but handle named subsystems.
	SubsystemHandlers map[string]SubsystemHandler

	listenerWg sync.WaitGroup
	mu         sync.RWMutex
	started    atomic.Bool
	listeners  map[net.Listener]struct{}
	conns      map[*gossh.ServerConn]struct{}
	connWg     sync.WaitGroup
	doneChan   chan struct{}
}

func ( *Server) () error {
	.mu.Lock()
	defer .mu.Unlock()

	if len(.HostSigners) == 0 {
		,  := generateSigner()
		if  != nil {
			return 
		}
		.HostSigners = append(.HostSigners, )
	}
	return nil
}

func ( *Server) () {
	.mu.Lock()
	defer .mu.Unlock()

	if .RequestHandlers == nil {
		.RequestHandlers = map[string]RequestHandler{}
		for ,  := range DefaultRequestHandlers {
			.RequestHandlers[] = 
		}
	}
	if .ChannelHandlers == nil {
		.ChannelHandlers = map[string]ChannelHandler{}
		for ,  := range DefaultChannelHandlers {
			.ChannelHandlers[] = 
		}
	}
	if .SubsystemHandlers == nil {
		.SubsystemHandlers = map[string]SubsystemHandler{}
		for ,  := range DefaultSubsystemHandlers {
			.SubsystemHandlers[] = 
		}
	}
}

func ( *Server) ( Context) *gossh.ServerConfig {
	.mu.Lock()
	defer .mu.Unlock()

	var  *gossh.ServerConfig
	if .ServerConfigCallback == nil {
		 = &gossh.ServerConfig{}
	} else {
		 = .ServerConfigCallback()
	}
	for ,  := range .HostSigners {
		.AddHostKey()
	}
	if .PasswordHandler == nil && .PublicKeyHandler == nil && .KeyboardInteractiveHandler == nil &&
		.PasswordCallback == nil && .PublicKeyCallback == nil && .KeyboardInteractiveCallback == nil {
		.NoClientAuth = true
	}
	if .PtyHandler == nil {
		.PtyHandler = emulatePtyHandler
	}
	if .Version != "" {
		.ServerVersion = "SSH-2.0-" + .Version
	}
	if .Banner != "" {
		.BannerCallback = func( gossh.ConnMetadata) string {
			return .Banner
		}
	}
	if .BannerHandler != nil {
		.BannerCallback = func( gossh.ConnMetadata) string {
			applyConnMetadata(, )
			return .BannerHandler()
		}
	}
	if .PasswordHandler != nil {
		.PasswordCallback = func( gossh.ConnMetadata,  []byte) (*gossh.Permissions, error) {
			resetPermissions()
			applyConnMetadata(, )
			 := ensureNoPKInPermissions()
			if  != nil {
				return .Permissions().Permissions, 
			}
			 := .PasswordHandler(, string())
			if ! {
				return .Permissions().Permissions, ErrPermissionDenied
			}
			return .Permissions().Permissions, nil
		}
	}
	if .PublicKeyHandler != nil {
		.PublicKeyCallback = func( gossh.ConnMetadata,  gossh.PublicKey) (*gossh.Permissions, error) {
			resetPermissions()
			applyConnMetadata(, )
			 := ensureNoPKInPermissions()
			if  != nil {
				return .Permissions().Permissions, 
			}
			 := .PublicKeyHandler(, )
			if ! {
				return .Permissions().Permissions, ErrPermissionDenied
			}

			 := base64.StdEncoding.EncodeToString(.Marshal())
			if .Permissions().Extensions == nil {
				.Permissions().Extensions = map[string]string{}
			}
			.Permissions().Extensions[permissionsPublicKeyExt] = 

			return .Permissions().Permissions, nil
		}
	}
	if .KeyboardInteractiveHandler != nil {
		.KeyboardInteractiveCallback = func( gossh.ConnMetadata,  gossh.KeyboardInteractiveChallenge) (*gossh.Permissions, error) {
			resetPermissions()
			applyConnMetadata(, )
			 := .KeyboardInteractiveHandler(, )
			 := ensureNoPKInPermissions()
			if  != nil {
				return .Permissions().Permissions, 
			}
			if ! {
				return .Permissions().Permissions, ErrPermissionDenied
			}
			return .Permissions().Permissions, nil
		}
	}
	return 
}

// Handle sets the Handler for the server.
func ( *Server) ( Handler) {
	.mu.Lock()
	defer .mu.Unlock()

	.Handler = 
}

// Close immediately closes all active listeners and all active
// connections.
//
// Close returns any error returned from closing the Server's
// underlying Listener(s).
func ( *Server) () error {
	.mu.Lock()
	defer .mu.Unlock()

	.closeDoneChanLocked()
	 := .closeListenersLocked()
	for  := range .conns {
		_ = .Close()
		delete(.conns, )
	}
	return 
}

// Shutdown gracefully shuts down the server without interrupting any
// active connections. Shutdown works by first closing all open
// listeners, and then waiting indefinitely for connections to close.
// If the provided context expires before the shutdown is complete,
// then the context's error is returned.
func ( *Server) ( context.Context) error {
	.mu.Lock()
	 := .closeListenersLocked()
	.closeDoneChanLocked()
	.mu.Unlock()

	 := make(chan struct{}, 1)
	go func() {
		.listenerWg.Wait()
		.connWg.Wait()
		 <- struct{}{}
	}()

	select {
	case <-.Done():
		return .Err()
	case <-:
		return 
	}
}

// Serve accepts incoming connections on the Listener l, creating a new
// connection goroutine for each. The connection goroutines read requests and then
// calls srv.Handler to handle sessions.
//
// Serve always returns a non-nil error.
func ( *Server) ( net.Listener) error {
	if .EnableProxyProtocol {
		,  := .(*proxyproto.Listener)
		if ! {
			 = &proxyproto.Listener{Listener: }
		}
	}

	.ensureHandlers()
	defer func() { _ = .Close() }()
	if  := .ensureHostSigner();  != nil {
		return 
	}
	if .Handler == nil {
		.Handler = DefaultHandler
	}
	var  time.Duration

	.trackListener(, true)
	.started.Store(true)
	defer .trackListener(, false)
	for {
		,  := .Accept()
		if  != nil {
			select {
			case <-.getDoneChan():
				return ErrServerClosed
			default:
			}
			if ,  := .(net.Error);  && .Temporary() { //nolint:staticcheck // SA1019: same pattern as net/http
				if  == 0 {
					 = 5 * time.Millisecond
				} else {
					 *= 2
				}
				if  := 1 * time.Second;  >  {
					 = 
				}
				time.Sleep()
				continue
			}
			return 
		}
		go .HandleConn()
	}
}

// HandleConn handles a new SSH connection.
//
// A panic while handling the connection is recovered and logged rather than
// allowed to escape. Connections are served on their own goroutine, and Go has
// no process-wide panic handler, so an unrecovered panic here would terminate
// the whole server process along with every other connection. That includes
// panics raised inside the SSH handshake, before authentication has happened,
// which would otherwise let an unauthenticated client take the server down.
func ( *Server) ( net.Conn) {
	defer recoverAndLog("panic serving connection", , func() {
		// The deferred close inside handleConn did not get to run.
		_ = .Close()
	})

	.handleConn()
}

// recoverAndLog recovers a panic on the current goroutine, logs it with a
// stack trace, and runs cleanup if one is given.
//
// This must be deferred directly on the goroutine to be protected: a recover
// only sees panics unwinding its own stack, so every goroutine the server
// starts needs its own call.
func recoverAndLog( string,  net.Conn,  func()) {
	 := recover()
	if  == nil {
		return
	}
	slog.Error("ssh: "+,
		"remote", remoteAddrString(),
		"panic", ,
		"stack", string(debug.Stack()),
	)
	if  != nil {
		// Cleanup runs while already unwinding a panic, so a second panic
		// raised here would escape this recover and kill the process, undoing
		// the containment. Contain it separately.
		defer func() {
			if  := recover();  != nil {
				slog.Error("ssh: panic during "++" cleanup", "panic", )
			}
		}()
		()
	}
}

// remoteAddrString returns conn's remote address for logging, tolerating a nil
// conn or address so that the panic handler cannot itself panic.
func remoteAddrString( net.Conn) string {
	if  == nil {
		return "unknown"
	}
	if  := .RemoteAddr();  != nil {
		return .String()
	}
	return "unknown"
}

func ( *Server) ( net.Conn) {
	,  := newContext()
	if .ConnCallback != nil {
		 := .ConnCallback(, )
		if  == nil {
			_ = .Close()
			return
		}
		 = 
	}
	 := &serverConn{
		Conn:          ,
		idleTimeout:   .IdleTimeout,
		closeCanceler: ,
	}
	if .MaxTimeout > 0 {
		.maxDeadline = time.Now().Add(.MaxTimeout)
	}
	if .HandshakeTimeout > 0 {
		.setHandshakeDeadline(time.Now().Add(.HandshakeTimeout))
	}
	.updateDeadline()
	defer func() { _ = .Close() }()
	defer func() {
		if .ConnectionCloseCallback != nil {
			.ConnectionCloseCallback()
		}
	}()
	, , ,  := gossh.NewServerConn(, .config())
	if  != nil {
		if .ConnectionFailedCallback != nil {
			.ConnectionFailedCallback(, )
		}
		return
	}
	.clearHandshakeDeadline()

	if  := extractPublicKeyFromPermissions(, );  != nil {
		if .ConnectionFailedCallback != nil {
			.ConnectionFailedCallback(, )
		}
		return
	}

	// Additionally, now that the connection was authed, we can take the
	// permissions off of the gossh.Conn and re-attach them to the Permissions
	// object stored in the Context.
	.Permissions().Permissions = .Permissions

	.trackConn(, true)
	defer .trackConn(, false)

	.SetValue(ContextKeyConn, )
	applyConnMetadata(, )
	// go gossh.DiscardRequests(reqs)
	go func() {
		defer recoverAndLog("panic handling requests", , nil)
		.handleRequests(, )
	}()
	for  := range  {
		 := .ChannelHandlers[.ChannelType()]
		if  == nil {
			 = .ChannelHandlers["default"]
		}
		if  == nil {
			_ = .Reject(gossh.UnknownChannelType, "unsupported channel type")
			continue
		}
		go func( gossh.NewChannel) {
			defer recoverAndLog("panic handling channel", , nil)
			(, , , )
		}()
	}
}

func ( *Server) ( Context,  <-chan *gossh.Request) {
	for  := range  {
		 := .RequestHandlers[.Type]
		if  == nil {
			 = .RequestHandlers["default"]
		}
		if  == nil {
			_ = .Reply(false, nil)
			continue
		}
		/*reqCtx, cancel := context.WithCancel(ctx)
		defer cancel() */
		,  := (, , )
		_ = .Reply(, )
	}
}

// ListenAndServe listens on the TCP network address srv.Addr and then calls
// Serve to handle incoming connections. If srv.Addr is blank, ":22" is used.
// ListenAndServe always returns a non-nil error.
func ( *Server) () error {
	 := .Addr
	if  == "" {
		 = ":22"
	}
	,  := net.Listen("tcp", )
	if  != nil {
		return 
	}
	return .Serve()
}

// AddHostKey adds a private key as a host key. If an existing host key exists
// with the same algorithm, it is overwritten. Each server config must have at
// least one host key.
func ( *Server) ( Signer) {
	.mu.Lock()
	defer .mu.Unlock()

	// these are later added via AddHostKey on ServerConfig, which performs the
	// check for one of every algorithm.

	// This check is based on the AddHostKey method from the x/crypto/ssh
	// library. This allows us to only keep one active key for each type on a
	// server at once. So, if you're dynamically updating keys at runtime, this
	// list will not keep growing.
	for ,  := range .HostSigners {
		if .PublicKey().Type() == .PublicKey().Type() {
			.HostSigners[] = 
			return
		}
	}

	.HostSigners = append(.HostSigners, )
}

// SetOption runs a functional option against the server.
// It returns an error if the server has already been started.
func ( *Server) ( Option) error {
	if .started.Load() {
		return fmt.Errorf("ssh: cannot set option after server has started")
	}

	// NOTE: there is a potential race here for any option that doesn't call an
	// internal method. We can't actually lock here because if something calls
	// (as an example) AddHostKey, it will deadlock.

	// srv.mu.Lock()
	// defer srv.mu.Unlock()

	return ()
}

func ( *Server) () <-chan struct{} {
	.mu.Lock()
	defer .mu.Unlock()

	return .getDoneChanLocked()
}

func ( *Server) () chan struct{} {
	if .doneChan == nil {
		.doneChan = make(chan struct{})
	}
	return .doneChan
}

func ( *Server) () {
	 := .getDoneChanLocked()
	select {
	case <-:
		// Already closed. Don't close again.
	default:
		// Safe to close here. We're the only closer, guarded
		// by srv.mu.
		close()
	}
}

func ( *Server) () error {
	var  error
	for  := range .listeners {
		if  := .Close();  != nil &&  == nil {
			 = 
		}
		delete(.listeners, )
	}
	return 
}

func ( *Server) ( net.Listener,  bool) {
	.mu.Lock()
	defer .mu.Unlock()

	if .listeners == nil {
		.listeners = make(map[net.Listener]struct{})
	}
	if  {
		// If the *Server is being reused after a previous
		// Close or Shutdown, reset its doneChan:
		if len(.listeners) == 0 && len(.conns) == 0 {
			.doneChan = nil
		}
		.listeners[] = struct{}{}
		.listenerWg.Add(1)
	} else {
		delete(.listeners, )
		.listenerWg.Done()
	}
}

func ( *Server) ( *gossh.ServerConn,  bool) {
	.mu.Lock()
	defer .mu.Unlock()

	if .conns == nil {
		.conns = make(map[*gossh.ServerConn]struct{})
	}
	if  {
		.conns[] = struct{}{}
		.connWg.Add(1)
	} else {
		delete(.conns, )
		.connWg.Done()
	}
}

// extractPublicKeyFromPermissions re-parses the public key from the
// permissions extensions and stores it in the context.
func extractPublicKeyFromPermissions( Context,  *gossh.ServerConn) error {
	if .Permissions == nil {
		return nil
	}
	,  := .Permissions.Extensions[permissionsPublicKeyExt]
	if ! {
		return nil
	}
	,  := base64.StdEncoding.DecodeString()
	if  != nil {
		return 
	}
	,  := gossh.ParsePublicKey()
	if  != nil {
		return 
	}
	.SetValue(ContextKeyPublicKey, )
	return nil
}