From ba51409c3c8a621cde6d6b82e8dccef7d5c5b592 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 29 Dec 2020 17:15:16 +0000 Subject: [PATCH] sftp: implement keyboard interactive authentication - fixes #4177 Some ssh servers are set up with keyboard interactive authentication which previously the sftp backkend was ignoring. --- backend/sftp/sftp.go | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/backend/sftp/sftp.go b/backend/sftp/sftp.go index fdf41cc0a..60be731b2 100644 --- a/backend/sftp/sftp.go +++ b/backend/sftp/sftp.go @@ -584,18 +584,41 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e if err != nil { return nil, err } - sshConfig.Auth = append(sshConfig.Auth, ssh.Password(clearpass)) + sshConfig.Auth = append(sshConfig.Auth, + ssh.Password(clearpass), + ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) ([]string, error) { + return f.keyboardInteractiveReponse(user, instruction, questions, echos, clearpass) + }), + ) } // Config for password if none was defined and we're allowed to // We don't ask now; we ask if the ssh connection succeeds if opt.Pass == "" && opt.AskPassword { - sshConfig.Auth = append(sshConfig.Auth, ssh.PasswordCallback(f.getPass)) + sshConfig.Auth = append(sshConfig.Auth, + ssh.PasswordCallback(f.getPass), + ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) ([]string, error) { + pass, _ := f.getPass() + return f.keyboardInteractiveReponse(user, instruction, questions, echos, pass) + }), + ) } return NewFsWithConnection(ctx, f, name, root, m, opt, sshConfig) } +// Do the keyboard interactive challenge +// +// Just send the password back for all questions +func (f *Fs) keyboardInteractiveReponse(user, instruction string, questions []string, echos []bool, pass string) ([]string, error) { + fs.Debugf(f, "keyboard interactive auth requested") + answers := make([]string, len(questions)) + for i := range answers { + answers[i] = pass + } + return answers, nil +} + // If we're in password mode and ssh connection succeeds then this // callback is called. First time around we ask the user, and then // save it so on reconnection we give back the previous string.