support sending password to remote

This commit is contained in:
sawka 2022-09-30 17:22:28 -07:00
parent 23759b7283
commit 3beb00998b
4 changed files with 86 additions and 10 deletions

View File

@ -378,11 +378,11 @@ func main() {
fmt.Printf("[error] ensuring test01 remote: %v\n", err) fmt.Printf("[error] ensuring test01 remote: %v\n", err)
return return
} }
err = sstore.AddTest02Remote(context.Background()) //err = sstore.AddTest02Remote(context.Background())
if err != nil { //if err != nil {
fmt.Printf("[error] ensuring test02 remote: %v\n", err) // fmt.Printf("[error] ensuring test02 remote: %v\n", err)
return // return
} //}
_, err = sstore.EnsureDefaultSession(context.Background()) _, err = sstore.EnsureDefaultSession(context.Background())
if err != nil { if err != nil {
fmt.Printf("[error] ensuring default session: %v\n", err) fmt.Printf("[error] ensuring default session: %v\n", err)

View File

@ -593,6 +593,9 @@ func RemoteNewCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ss
} }
remoteOpts.Color = color remoteOpts.Color = color
} }
if pk.Kwargs["password"] != "" {
sshOpts.SSHPassword = pk.Kwargs["password"]
}
r := &sstore.RemoteType{ r := &sstore.RemoteType{
RemoteId: scbase.GenSCUUID(), RemoteId: scbase.GenSCUUID(),
PhysicalId: "", PhysicalId: "",
@ -737,12 +740,15 @@ func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
if newRemote == "" { if newRemote == "" {
return nil, nil return nil, nil
} }
remoteName, rptr, _, _, err := resolveRemote(ctx, newRemote, ids.SessionId, ids.WindowId) remoteName, rptr, _, rstate, err := resolveRemote(ctx, newRemote, ids.SessionId, ids.WindowId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if rptr == nil { if rptr == nil {
return nil, fmt.Errorf("/cr error: remote [%s] not found", newRemote) return nil, fmt.Errorf("/cr error: remote %q not found", newRemote)
}
if rstate.Archived {
return nil, fmt.Errorf("/cr error: remote %q cannot switch to archived remote", newRemote)
} }
err = sstore.UpdateCurRemote(ctx, ids.SessionId, ids.WindowId, *rptr) err = sstore.UpdateCurRemote(ctx, ids.SessionId, ids.WindowId, *rptr)
if err != nil { if err != nil {
@ -755,7 +761,7 @@ func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
CurRemote: *rptr, CurRemote: *rptr,
}, },
Info: &sstore.InfoMsgType{ Info: &sstore.InfoMsgType{
InfoMsg: fmt.Sprintf("current remote = %s", remoteName), InfoMsg: fmt.Sprintf("current remote = %q", remoteName),
TimeoutMs: 2000, TimeoutMs: 2000,
}, },
} }

View File

@ -15,6 +15,7 @@ import (
"strings" "strings"
"sync" "sync"
"syscall" "syscall"
"time"
"github.com/armon/circbuf" "github.com/armon/circbuf"
"github.com/creack/pty" "github.com/creack/pty"
@ -111,10 +112,11 @@ type RemoteRuntimeState struct {
DefaultState *sstore.RemoteState `json:"defaultstate"` DefaultState *sstore.RemoteState `json:"defaultstate"`
ConnectMode string `json:"connectmode"` ConnectMode string `json:"connectmode"`
AutoInstall bool `json:"autoinstall"` AutoInstall bool `json:"autoinstall"`
Archived bool `json:"archived"` Archived bool `json:"archived,omitempty"`
RemoteIdx int64 `json:"remoteidx"` RemoteIdx int64 `json:"remoteidx"`
UName string `json:"uname"` UName string `json:"uname"`
MShellVersion string `json:"mshellversion"` MShellVersion string `json:"mshellversion"`
WaitingForPassword bool `json:"waitingforpassword,omitempty"`
} }
func (state RemoteRuntimeState) IsConnected() bool { func (state RemoteRuntimeState) IsConnected() bool {
@ -391,6 +393,9 @@ func (msh *MShellProc) GetRemoteRuntimeState() RemoteRuntimeState {
if msh.InstallErr != nil { if msh.InstallErr != nil {
state.InstallErrorStr = msh.InstallErr.Error() state.InstallErrorStr = msh.InstallErr.Error()
} }
if msh.Status == StatusConnecting {
state.WaitingForPassword = msh.isWaitingForPassword_nolock()
}
local := (msh.Remote.SSHOpts == nil || msh.Remote.SSHOpts.Local) local := (msh.Remote.SSHOpts == nil || msh.Remote.SSHOpts.Local)
vars := make(map[string]string) vars := make(map[string]string)
vars["user"] = msh.Remote.RemoteUser vars["user"] = msh.Remote.RemoteUser
@ -659,8 +664,25 @@ func sendRemotePtyUpdate(remoteId string, dataOffset int64, data []byte) {
sstore.MainBus.SendUpdate("", update) sstore.MainBus.SendUpdate("", update)
} }
func (msh *MShellProc) isWaitingForPassword_nolock() bool {
barr := msh.PtyBuffer.Bytes()
if len(barr) == 0 {
return false
}
nlIdx := bytes.LastIndex(barr, []byte{'\n'})
var lastLine string
if nlIdx == -1 {
lastLine = string(barr)
} else {
lastLine = string(barr[nlIdx+1:])
}
pwIdx := strings.Index(lastLine, "assword")
return pwIdx != -1
}
func (msh *MShellProc) RunPtyReadLoop(cmdPty *os.File) { func (msh *MShellProc) RunPtyReadLoop(cmdPty *os.File) {
buf := make([]byte, PtyReadBufSize) buf := make([]byte, PtyReadBufSize)
var isWaiting bool
for { for {
n, readErr := cmdPty.Read(buf) n, readErr := cmdPty.Read(buf)
if readErr == io.EOF { if readErr == io.EOF {
@ -670,11 +692,55 @@ func (msh *MShellProc) RunPtyReadLoop(cmdPty *os.File) {
msh.WriteToPtyBuffer("*error reading from controlling-pty: %v\n", readErr) msh.WriteToPtyBuffer("*error reading from controlling-pty: %v\n", readErr)
break break
} }
var newIsWaiting bool
msh.WithLock(func() { msh.WithLock(func() {
curOffset := msh.PtyBuffer.TotalWritten() curOffset := msh.PtyBuffer.TotalWritten()
msh.PtyBuffer.Write(buf[0:n]) msh.PtyBuffer.Write(buf[0:n])
sendRemotePtyUpdate(msh.Remote.RemoteId, curOffset, buf[0:n]) sendRemotePtyUpdate(msh.Remote.RemoteId, curOffset, buf[0:n])
newIsWaiting = msh.isWaitingForPassword_nolock()
}) })
if newIsWaiting != isWaiting {
isWaiting = newIsWaiting
go msh.NotifyRemoteUpdate()
}
}
}
func (msh *MShellProc) WaitAndSendPassword(pw string) {
var numWaits int
for {
var isWaiting bool
var isConnecting bool
msh.WithLock(func() {
isWaiting = msh.isWaitingForPassword_nolock()
isConnecting = msh.Status == StatusConnecting
})
if !isConnecting {
break
}
if !isWaiting {
numWaits = 0
time.Sleep(100 * time.Millisecond)
continue
}
numWaits++
if numWaits < 10 {
time.Sleep(100 * time.Millisecond)
} else {
// send password
msh.WithLock(func() {
if msh.ControllingPty == nil {
return
}
pwBytes := []byte(pw + "\r")
msh.writeToPtyBuffer_nolock("~[sent password]\r\n")
_, err := msh.ControllingPty.Write(pwBytes)
if err != nil {
msh.writeToPtyBuffer_nolock("*cannot write password to controlling pty: %v\n", err)
}
})
break
}
} }
} }
@ -770,7 +836,7 @@ func (msh *MShellProc) Launch() {
msh.WriteToPtyBuffer("connecting to %s...\n", remoteCopy.RemoteCanonicalName) msh.WriteToPtyBuffer("connecting to %s...\n", remoteCopy.RemoteCanonicalName)
sshOpts := convertSSHOpts(remoteCopy.SSHOpts) sshOpts := convertSSHOpts(remoteCopy.SSHOpts)
sshOpts.SSHErrorsToTty = true sshOpts.SSHErrorsToTty = true
if remoteCopy.ConnectMode != sstore.ConnectModeManual { if remoteCopy.ConnectMode != sstore.ConnectModeManual && remoteCopy.SSHOpts.SSHPassword == "" {
sshOpts.BatchMode = true sshOpts.BatchMode = true
} }
cmdStr := MakeServerCommandStr() cmdStr := MakeServerCommandStr()
@ -788,6 +854,9 @@ func (msh *MShellProc) Launch() {
} }
}() }()
go msh.RunPtyReadLoop(cmdPty) go msh.RunPtyReadLoop(cmdPty)
if remoteCopy.SSHOpts.SSHPassword != "" {
go msh.WaitAndSendPassword(remoteCopy.SSHOpts.SSHPassword)
}
makeClientCtx, makeClientCancelFn := context.WithCancel(context.Background()) makeClientCtx, makeClientCancelFn := context.WithCancel(context.Background())
defer makeClientCancelFn() defer makeClientCancelFn()
msh.WithLock(func() { msh.WithLock(func() {

View File

@ -476,6 +476,7 @@ type SSHOpts struct {
SSHOptsStr string `json:"sshopts,omitempty"` SSHOptsStr string `json:"sshopts,omitempty"`
SSHIdentity string `json:"sshidentity,omitempty"` SSHIdentity string `json:"sshidentity,omitempty"`
SSHPort int `json:"sshport,omitempty"` SSHPort int `json:"sshport,omitempty"`
SSHPassword string `json:"sshpassword,omitempty"`
} }
type RemoteOptsType struct { type RemoteOptsType struct {