sshpiper/plugin/workingdir/skel.go
Josh Bleecher Snyder 297b8c60e7
extract skel into its own package (#596)
This breaks the dependency of libplugin
on x/crypto, enabling people to use libplugin
without having conflicts over the crypto module.
2025-05-23 12:42:44 -07:00

178 lines
3.7 KiB
Go

package main
import (
"fmt"
"os"
"path"
"path/filepath"
log "github.com/sirupsen/logrus"
"github.com/tg123/sshpiper/libplugin"
"github.com/tg123/sshpiper/libplugin/skel"
)
type workdingdirFactory struct {
root string
allowBadUsername bool
noPasswordAuth bool
noCheckPerm bool
strictHostKey bool
recursiveSearch bool
}
type skelpipeWrapper struct {
dir *workingdir
host string
username string
}
type skelpipeFromWrapper struct {
skelpipeWrapper
}
type skelpipePasswordWrapper struct {
skelpipeFromWrapper
}
type skelpipePublicKeyWrapper struct {
skelpipeFromWrapper
}
type skelpipeToWrapper struct {
skelpipeWrapper
}
type skelpipeToPasswordWrapper struct {
skelpipeToWrapper
}
type skelpipeToPrivateKeyWrapper struct {
skelpipeToWrapper
}
func (s *skelpipeWrapper) From() []skel.SkelPipeFrom {
w := skelpipeFromWrapper{
skelpipeWrapper: *s,
}
if s.dir.Exists(userAuthorizedKeysFile) && s.dir.Exists(userKeyFile) {
return []skel.SkelPipeFrom{&skelpipePublicKeyWrapper{
skelpipeFromWrapper: w,
}}
} else {
return []skel.SkelPipeFrom{&skelpipePasswordWrapper{
skelpipeFromWrapper: w,
}}
}
}
func (s *skelpipeToWrapper) User(conn libplugin.ConnMetadata) string {
return s.username
}
func (s *skelpipeToWrapper) Host(conn libplugin.ConnMetadata) string {
return s.host
}
func (s *skelpipeToWrapper) IgnoreHostKey(conn libplugin.ConnMetadata) bool {
return !s.dir.Strict
}
func (s *skelpipeToWrapper) KnownHosts(conn libplugin.ConnMetadata) ([]byte, error) {
return s.dir.Readfile(userKnownHosts)
}
func (s *skelpipeFromWrapper) MatchConn(conn libplugin.ConnMetadata) (skel.SkelPipeTo, error) {
if s.dir.Exists(userKeyFile) {
return &skelpipeToPrivateKeyWrapper{
skelpipeToWrapper: skelpipeToWrapper(*s),
}, nil
}
return &skelpipeToPasswordWrapper{
skelpipeToWrapper: skelpipeToWrapper(*s),
}, nil
}
func (s *skelpipePasswordWrapper) TestPassword(conn libplugin.ConnMetadata, password []byte) (bool, error) {
return true, nil // TODO support later
}
func (s *skelpipePublicKeyWrapper) AuthorizedKeys(conn libplugin.ConnMetadata) ([]byte, error) {
return s.dir.Readfile(userAuthorizedKeysFile)
}
func (s *skelpipePublicKeyWrapper) TrustedUserCAKeys(conn libplugin.ConnMetadata) ([]byte, error) {
return nil, nil // TODO support this
}
func (s *skelpipeToPrivateKeyWrapper) PrivateKey(conn libplugin.ConnMetadata) ([]byte, []byte, error) {
k, err := s.dir.Readfile(userKeyFile)
if err != nil {
return nil, nil, err
}
return k, nil, nil
}
func (s *skelpipeToPasswordWrapper) OverridePassword(conn libplugin.ConnMetadata) ([]byte, error) {
return nil, nil
}
func (wf *workdingdirFactory) listPipe(conn libplugin.ConnMetadata) ([]skel.SkelPipe, error) {
user := conn.User()
if !wf.allowBadUsername {
if !isUsernameSecure(user) {
return nil, fmt.Errorf("bad username: %s", user)
}
}
var pipes []skel.SkelPipe
userdir := path.Join(wf.root, conn.User())
_ = filepath.Walk(userdir, func(path string, info os.FileInfo, err error) (stop error) {
log.Infof("search upstreams in path: %v", path)
if err != nil {
log.Infof("error walking path: %v", err)
return
}
if !info.IsDir() {
return
}
if !wf.recursiveSearch {
stop = fmt.Errorf("stop")
}
w := &workingdir{
Path: path,
NoCheckPerm: wf.noCheckPerm,
Strict: wf.strictHostKey,
}
data, err := w.Readfile(userUpstreamFile)
if err != nil {
log.Infof("error reading upstream file: %v in %v", err, w.Path)
return
}
host, user, err := parseUpstreamFile(string(data))
if err != nil {
log.Infof("ignore upstream folder %v due to: %v", w.Path, err)
return
}
pipes = append(pipes, &skelpipeWrapper{
dir: w,
host: host,
username: user,
})
return
})
return pipes, nil
}