This commit is contained in:
Boshi LIAN 2018-02-23 18:33:40 +08:00 committed by Boshi Lian
parent 46eef25212
commit c9027f707e
17 changed files with 106 additions and 249 deletions

View file

@ -1,5 +1,5 @@
package loader
import (
_ "github.com/tg123/sshpiper/sshpiperd/auditor/typescript_logger"
_ "github.com/tg123/sshpiper/sshpiperd/auditor/typescriptlogger" // init plugin
)

View file

@ -6,35 +6,51 @@ import (
"github.com/tg123/sshpiper/sshpiperd/registry"
)
type AuditorHook func(conn ssh.ConnMetadata, msg []byte) ([]byte, error)
// Hook is called after ssh connection pipe is established and all msg will be
// put into the hook and msg will be converted to the return value of this func
type Hook func(conn ssh.ConnMetadata, msg []byte) ([]byte, error)
// Auditor holds Hooks for upstream and downstream
type Auditor interface {
GetUpstreamHook() AuditorHook
GetDownstreamHook() AuditorHook
// All msg between piper and upstream will be put into the hook
// nil for ignore
GetUpstreamHook() Hook
// All msg between piper and downstream will be put into the hook
// nil for ignore
GetDownstreamHook() Hook
// Will be called when connection closed
Close() error
}
type AuditorProvider interface {
// Provider is a factory for Auditor
type Provider interface {
registry.Plugin
CreateAuditor(ssh.ConnMetadata) (Auditor, error)
// Will be called when piped connection established
// nil for no Auditor needed for this connection
Create(ssh.ConnMetadata) (Auditor, error)
}
var (
drivers = registry.NewRegistry()
)
func Register(name string, driver AuditorProvider) {
// Register adds an auditor with given name to registry
func Register(name string, driver Provider) {
drivers.Register(name, driver)
}
// All return all registerd auditors
func All() []string {
return drivers.Drivers()
}
func Get(name string) AuditorProvider {
if d, ok := drivers.Get(name).(AuditorProvider); ok {
// Get returns an auditor by name, return nil if not found
func Get(name string) Provider {
if d, ok := drivers.Get(name).(Provider); ok {
return d
}

View file

@ -1,86 +0,0 @@
package typescript_logger
import (
"fmt"
"os"
"path"
"time"
"golang.org/x/crypto/ssh"
)
const (
msgChannelData = 94
)
type filePtyLogger struct {
typescript *os.File
timing *os.File
oldtime time.Time
}
func newFilePtyLogger(outputdir string) (*filePtyLogger, error) {
now := time.Now()
filename := fmt.Sprintf("%d", now.Unix())
typescript, err := os.OpenFile(path.Join(outputdir, fmt.Sprintf("%v.typescript", filename)), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return nil, err
}
_, err = typescript.Write([]byte(fmt.Sprintf("Script started on %v\n", now.Format(time.ANSIC))))
if err != nil {
return nil, err
}
timing, err := os.OpenFile(path.Join(outputdir, fmt.Sprintf("%v.timing", filename)), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return nil, err
}
return &filePtyLogger{
typescript: typescript,
timing: timing,
oldtime: time.Now(),
}, nil
}
func (l *filePtyLogger) loggingTty(conn ssh.ConnMetadata, msg []byte) ([]byte, error) {
if msg[0] == msgChannelData {
buf := msg[9:]
now := time.Now()
delta := now.Sub(l.oldtime)
// see term-utils/script.c
fmt.Fprintf(l.timing, "%v.%06v %v\n", int64(delta/time.Second), int64(delta/time.Microsecond), len(buf))
l.oldtime = now
_, err := l.typescript.Write(buf)
if err != nil {
return msg, err
}
}
return msg, nil
}
func (l *filePtyLogger) Close() (err error) {
_, err = l.typescript.Write([]byte(fmt.Sprintf("Script done on %v\n", time.Now().Format(time.ANSIC))))
l.typescript.Close()
l.timing.Close()
return nil // TODO
}

View file

@ -1,52 +0,0 @@
package typescript_logger
import (
"log"
"os"
"path"
"golang.org/x/crypto/ssh"
"github.com/tg123/sshpiper/sshpiperd/auditor"
)
type plugin struct {
Config struct {
OutputDir string `long:"auditor-typescriptlogger-outputdir" default:"/var/sshpiper" description:"Place where logged typescript files were saved" env:"SSHPIPERD_AUDITOR_TYPESCRIPTLOGGER_OUTPUTDIR" ini-name:"auditor-typescriptlogger-outputdir"`
}
}
func (p *plugin) GetName() string {
return "typescript-logger"
}
func (p *plugin) GetOpts() interface{} {
return &p.Config
}
func (p *plugin) CreateAuditor(conn ssh.ConnMetadata) (auditor.Auditor, error) {
dir := path.Join(p.Config.OutputDir, conn.User())
err := os.MkdirAll(dir, 0700)
if err != nil {
return nil, err
}
return newFilePtyLogger(dir)
}
func (p *plugin) Init(logger *log.Logger) error {
return nil
}
func (l *filePtyLogger) GetUpstreamHook() auditor.AuditorHook {
return l.loggingTty
}
func (l *filePtyLogger) GetDownstreamHook() auditor.AuditorHook {
return nil
}
func init() {
auditor.Register("typescript-logger", new(plugin))
}

View file

@ -1,6 +1,6 @@
package loader
import (
_ "github.com/tg123/sshpiper/sshpiperd/challenger/pam"
_ "github.com/tg123/sshpiper/sshpiperd/challenger/welcometext"
_ "github.com/tg123/sshpiper/sshpiperd/challenger/pam" // init plugin
_ "github.com/tg123/sshpiper/sshpiperd/challenger/welcometext" // init plugin
)

View file

@ -70,5 +70,5 @@ func init() {
return
}
challenger.Register("pam", challenger.NewFromHandler("pam", func() challenger.ChallengerHandler { return pamChallenger }, nil, nil))
challenger.Register("pam", challenger.NewFromHandler("pam", func() challenger.Handler { return pamChallenger }, nil, nil))
}

View file

@ -8,7 +8,7 @@ type plugin struct {
name string
init func(logger *log.Logger) error
opts interface{}
gethandler func() ChallengerHandler
gethandler func() Handler
}
func (p *plugin) GetName() string {
@ -19,7 +19,7 @@ func (p *plugin) GetOpts() interface{} {
return p.opts
}
func (p *plugin) GetChallengerHandler() ChallengerHandler {
func (p *plugin) GetHandler() Handler {
return p.gethandler()
}
@ -32,7 +32,8 @@ func (p *plugin) Init(logger *log.Logger) error {
return nil
}
func NewFromHandler(name string, gethandler func() ChallengerHandler, opts interface{}, init func(glogger *log.Logger) error) Challenger {
// NewFromHandler creates a Challenger with given functions
func NewFromHandler(name string, gethandler func() Handler, opts interface{}, init func(glogger *log.Logger) error) Provider {
return &plugin{
name: name,
init: init,

View file

@ -6,28 +6,35 @@ import (
"github.com/tg123/sshpiper/sshpiperd/registry"
)
type ChallengerHandler func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (bool, error)
// Handler is the callback for additional challenger
// use args client ssh.KeyboardInteractiveChallenge to interact with downstream
// return bool to indicate whether if the challenge is passed
type Handler func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (bool, error)
type Challenger interface {
// Provider is a factory for Challenger
type Provider interface {
registry.Plugin
GetChallengerHandler() ChallengerHandler
GetHandler() Handler
}
var (
drivers = registry.NewRegistry()
)
func Register(name string, driver Challenger) {
// Register adds an challenger with given name to registry
func Register(name string, driver Provider) {
drivers.Register(name, driver)
}
// All return all registerd challenger
func All() []string {
return drivers.Drivers()
}
func Get(name string) Challenger {
if d, ok := drivers.Get(name).(Challenger); ok {
// Get returns an challenger by name, return nil if not found
func Get(name string) Provider {
if d, ok := drivers.Get(name).(Provider); ok {
return d
}

View file

@ -8,7 +8,7 @@ import (
"github.com/tg123/sshpiper/sshpiperd/challenger"
)
func makeWelcomeChallenger(text string) challenger.ChallengerHandler {
func makeWelcomeChallenger(text string) challenger.Handler {
return func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (bool, error) {
client(conn.User(), text, nil, nil)
@ -19,13 +19,13 @@ func makeWelcomeChallenger(text string) challenger.ChallengerHandler {
func init() {
var h challenger.ChallengerHandler
var h challenger.Handler
config := &struct {
WelcomeText string `long:"challenger-welcometext" description:"Show a welcome text when connect to sshpiper server" env:"SSHPIPERD_CHALLENGER_WELCOMETEXT" ini-name:"challenger-welcometext"`
}{}
challenger.Register("welcometext", challenger.NewFromHandler("welcometext", func() challenger.ChallengerHandler {
challenger.Register("welcometext", challenger.NewFromHandler("welcometext", func() challenger.Handler {
return h
}, config, func(logger *log.Logger) error {
h = makeWelcomeChallenger(config.WelcomeText)

View file

@ -190,7 +190,7 @@ func main() {
if command == nil {
if len(args) > 0 {
return fmt.Errorf("Unknown command %v", args)
return fmt.Errorf("unknown command %v", args)
}
// init log

View file

@ -26,15 +26,15 @@ func startPiper(config *piperdConfig) {
logger.Println("sshpiper is about to start")
// install upstream driver
upstream := upstream.Get(config.UpstreamDriver)
if upstream == nil {
logger.Fatalf("upstream driver %v not found", config.UpstreamDriver)
// install upstreamProvider driver
upstreamProvider := upstream.Get(config.UpstreamDriver)
if upstreamProvider == nil {
logger.Fatalf("upstreamProvider driver %v not found", config.UpstreamDriver)
}
upstream.Init(logger)
upstreamProvider.Init(logger)
piper := &ssh.SSHPiperConfig{
FindUpstream: upstream.GetFindUpstreamHandle(),
FindUpstream: upstreamProvider.GetHandler(),
}
// install challenger
@ -47,10 +47,10 @@ func startPiper(config *piperdConfig) {
logger.Printf("using additional challenger %s", config.ChallengerDriver)
ac.Init(logger)
piper.AdditionalChallenge = ac.GetChallengerHandler()
piper.AdditionalChallenge = ac.GetHandler()
}
var bigbro auditor.AuditorProvider
var bigbro auditor.Provider
// install auditor
if config.AuditorDriver != "" {
bigbro = auditor.Get(config.AuditorDriver)
@ -100,7 +100,7 @@ func startPiper(config *piperdConfig) {
}
if bigbro != nil {
a, err := bigbro.CreateAuditor(p.DownstreamConnMeta())
a, err := bigbro.Create(p.DownstreamConnMeta())
if err != nil {
logger.Printf("connection from %v failed to create auditor reason: %v", c.RemoteAddr(), err)
return

View file

@ -1,6 +1,6 @@
package loader
import (
_ "github.com/tg123/sshpiper/sshpiperd/upstream/mysql"
_ "github.com/tg123/sshpiper/sshpiperd/upstream/workingdir"
_ "github.com/tg123/sshpiper/sshpiperd/upstream/mysql" // init plugin
_ "github.com/tg123/sshpiper/sshpiperd/upstream/workingdir" // init plugin
)

View file

@ -20,11 +20,11 @@ type PubkeyUpstreamMap struct {
tx *sql.Tx
}
func NewPubkeyUpstreamMap(db *sql.DB) *PubkeyUpstreamMap {
return &PubkeyUpstreamMap{
db: db,
}
}
//func NewPubkeyUpstreamMap(db *sql.DB) *PubkeyUpstreamMap {
// return &PubkeyUpstreamMap{
// db: db,
// }
//}
// Function to help make the api feel cleaner
func (t *PubkeyUpstreamMap) Commit() error {

View file

@ -19,7 +19,7 @@ type plugin struct {
Dbname string `long:"upstream-mysql-dbname" default:"sshpiper" description:"mysql dbname for driver" env:"SSHPIPERD_UPSTREAM_MYSQL_DBNAME" ini-name:"upstream-mysql-dbname"`
}
w MysqlWorkingDir
w mysqlWorkingDir
}
func (p *plugin) GetName() string {
@ -30,7 +30,7 @@ func (p *plugin) GetOpts() interface{} {
return &p.Config
}
func (p *plugin) GetFindUpstreamHandle() upstream.UpstreamHandler {
func (p *plugin) GetHandler() upstream.Handler {
return p.w.FindUpstream
}

View file

@ -11,7 +11,7 @@ import (
"github.com/tg123/sshpiper/sshpiperd/upstream/mysql/crud"
)
type MysqlWorkingDir struct {
type mysqlWorkingDir struct {
ConnectDB func() (*sql.DB, error)
}
@ -39,7 +39,7 @@ func connectServer(db *sql.DB, sid int64) (net.Conn, error) {
return net.Dial("tcp", addr)
}
func (w *MysqlWorkingDir) connectUpstream(db *sql.DB, uid int64, defuser string) (net.Conn, *ssh.SSHPiperAuthPipe, error) {
func (w *mysqlWorkingDir) connectUpstream(db *sql.DB, uid int64, defuser string) (net.Conn, *ssh.SSHPiperAuthPipe, error) {
o := crud.NewUpstream(db)
@ -98,26 +98,26 @@ func findPKId(db *sql.DB, key ssh.PublicKey) (int64, error) {
return -1, nil
}
func findByPublicKey(db *sql.DB, downkey ssh.PublicKey) (int64, error) {
kid, err := findPKId(db, downkey)
if err != nil {
return -1, err
}
if kid > 0 {
opum := crud.NewPubkeyUpstreamMap(db)
u, err := opum.GetFirstByPubkeyId(kid)
if err != nil {
return -1, err
}
if u != nil {
return u.UpstreamId, nil
}
}
return -1, nil
}
//func findByPublicKey(db *sql.DB, downkey ssh.PublicKey) (int64, error) {
// kid, err := findPKId(db, downkey)
// if err != nil {
// return -1, err
// }
//
// if kid > 0 {
// opum := crud.NewPubkeyUpstreamMap(db)
// u, err := opum.GetFirstByPubkeyId(kid)
// if err != nil {
// return -1, err
// }
//
// if u != nil {
// return u.UpstreamId, nil
// }
// }
//
// return -1, nil
//}
func findByUsername(db *sql.DB, username string) (int64, error) {
ouum := crud.NewUserUpstreamMap(db)
@ -133,8 +133,8 @@ func findByUsername(db *sql.DB, username string) (int64, error) {
return -1, nil
}
//func (w *MysqlWorkingDir) FindUpstream(conn ssh.ConnMetadata, downkey ssh.PublicKey) (net.Conn, *ssh.SSHPiperAuthPipe, error) {
func (w *MysqlWorkingDir) FindUpstream(conn ssh.ConnMetadata) (net.Conn, *ssh.SSHPiperAuthPipe, error) {
//func (w *mysqlWorkingDir) FindUpstream(conn ssh.ConnMetadata, downkey ssh.PublicKey) (net.Conn, *ssh.SSHPiperAuthPipe, error) {
func (w *mysqlWorkingDir) FindUpstream(conn ssh.ConnMetadata) (net.Conn, *ssh.SSHPiperAuthPipe, error) {
db, err := w.ConnectDB()
defer db.Close()
@ -171,7 +171,7 @@ func (w *MysqlWorkingDir) FindUpstream(conn ssh.ConnMetadata) (net.Conn, *ssh.SS
return nil, nil, fmt.Errorf("no upstream found")
}
func (w *MysqlWorkingDir) MapPublicKey(conn ssh.ConnMetadata, key ssh.PublicKey) (ssh.Signer, error) {
func (w *mysqlWorkingDir) MapPublicKey(conn ssh.ConnMetadata, key ssh.PublicKey) (ssh.Signer, error) {
db, err := w.ConnectDB()
defer db.Close()
if err != nil {

View file

@ -8,28 +8,36 @@ import (
"github.com/tg123/sshpiper/sshpiperd/registry"
)
type UpstreamHandler func(conn ssh.ConnMetadata) (net.Conn, *ssh.SSHPiperAuthPipe, error)
// 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 upstrem.
// e.g. map downstream public key to another upstream private key
type Handler func(conn ssh.ConnMetadata) (net.Conn, *ssh.SSHPiperAuthPipe, error)
type UpstreamProvider interface {
// Provider is a factory for Upstream Provider
type Provider interface {
registry.Plugin
GetFindUpstreamHandle() UpstreamHandler
GetHandler() Handler
}
var (
drivers = registry.NewRegistry()
)
func Register(name string, driver UpstreamProvider) {
// Register adds an upstream provider with given name to registry
func Register(name string, driver Provider) {
drivers.Register(name, driver)
}
// All return all registerd upstream providers
func All() []string {
return drivers.Drivers()
}
func Get(name string) UpstreamProvider {
if d, ok := drivers.Get(name).(UpstreamProvider); ok {
// 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
}

View file

@ -1,37 +0,0 @@
package workingdir
import (
"log"
"github.com/tg123/sshpiper/sshpiperd/upstream"
)
var logger *log.Logger
type plugin struct {
}
func (p *plugin) GetName() string {
return "workingdir"
}
func (p *plugin) GetOpts() interface{} {
return &config
}
func (p *plugin) GetFindUpstreamHandle() upstream.UpstreamHandler {
return findUpstreamFromUserfile
}
func (p *plugin) Init(glogger *log.Logger) error {
logger = glogger
logger.Printf("upstream provider: workingdir %v init", config.WorkingDir)
return nil
}
func init() {
upstream.Register("workingdir", &plugin{})
}