grim/hgkeeper

00140ff02051
Update the page to keep. Fixes HGKEEPER-10
package ssh
import (
"fmt"
"github.com/gliderlabs/ssh"
log "github.com/sirupsen/logrus"
gossh "golang.org/x/crypto/ssh"
"keep.imfreedom.org/grim/hgkeeper/access"
"keep.imfreedom.org/grim/hgkeeper/ssh/commands"
)
type Server struct {
reposPath string
server *ssh.Server
}
func NewServer(hostKeysPath, reposPath, adminRepo string) (*Server, error) {
s := &Server{
reposPath: reposPath,
}
s.server = &ssh.Server{
PublicKeyHandler: s.publicKeyHandler,
Handler: s.sessionHandler,
PtyCallback: func(ctx ssh.Context, pty ssh.Pty) bool {
return false
},
}
if err := s.setHostKeysPath(hostKeysPath); err != nil {
return nil, err
}
return s, nil
}
func (s *Server) publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool {
username, err := access.UsernameFromPubkey(key)
if err != nil {
log.Warnf("authentication failure, unknown key %s", gossh.FingerprintSHA256(key))
return false
}
ctx.SetValue("username", username)
log.Infof(
"%q authenticated with %s",
username,
gossh.FingerprintSHA256(key),
)
return true
}
func (s *Server) sessionHandler(session ssh.Session) {
username := session.Context().Value("username").(string)
// per the docs, session.Command is empty if the user is requesting a shell.
// we only support execs, which means command should be non-empty.
if len(session.Command()) == 0 {
fmt.Fprintf(session, "logged in as %s\n\nShell access is disabled\n", username)
return
}
log.Infof(
"%s@%s requested command %q",
username,
session.RemoteAddr(),
session.RawCommand(),
)
cmd, err := commands.Find(session.RawCommand(), s.reposPath)
if err != nil {
log.Warnf("failed to find command for %q, %v", session.RawCommand(), err)
return
}
if err := cmd.Run(session, username); err != nil {
log.Warnf(
"%s@%s command %q failed: %v",
username,
session.RemoteAddr(),
session.RawCommand(),
err,
)
if err := session.Exit(255); err != nil {
log.Errorf("session failed to exit: %v", err)
}
} else {
log.Infof(
"%s@%s command %q succeed",
username,
session.RemoteAddr(),
session.RawCommand(),
)
if err := session.Exit(0); err != nil {
log.Errorf("session failed to exit: %v", err)
}
}
}
func (s *Server) Listen(addr string) error {
s.server.Addr = addr
log.Infof("ssh listening on %s", s.server.Addr)
if err := s.server.ListenAndServe(); err != nil {
if err != ssh.ErrServerClosed {
return err
}
}
return nil
}
func (s *Server) Close() error {
if s.server != nil {
if err := s.server.Close(); err != nil {
s.server = nil
}
}
return nil
}