From a1fa8a79bbd7f6385d312cce709768944506d960 Mon Sep 17 00:00:00 2001 From: Alexander Golubev Date: Fri, 19 Jan 2024 09:29:00 +0300 Subject: tdeioslave/sftp: fix keyboard-interactive authentication This is a partial fix to the sftp ioslave. Subsequent commits will fix other issues. Closes: https://mirror.git.trinitydesktop.org/gitea/TDE/tdebase/issues/443 Signed-off-by: Alexander Golubev --- tdeioslave/sftp/tdeio_sftp.cpp | 128 +++++++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 43 deletions(-) (limited to 'tdeioslave/sftp') diff --git a/tdeioslave/sftp/tdeio_sftp.cpp b/tdeioslave/sftp/tdeio_sftp.cpp index 8b74023c0..cc086d5aa 100644 --- a/tdeioslave/sftp/tdeio_sftp.cpp +++ b/tdeioslave/sftp/tdeio_sftp.cpp @@ -180,11 +180,20 @@ int sftpProtocol::authenticateKeyboardInteractive(AuthInfo &info) { kdDebug(TDEIO_SFTP_DB) << "Entering keyboard interactive function" << endl; - err = ssh_userauth_kbdint(mSession, mUsername.utf8().data(), NULL); - while (err == SSH_AUTH_INFO) { + while (1) { int n = 0; int i = 0; + err = ssh_userauth_kbdint(mSession, NULL, NULL); + + if (err != SSH_AUTH_INFO) { + kdDebug(TDEIO_SFTP_DB) << "Finishing kbdint auth err=" << err + << " ssh_err=" << ssh_get_error_code(mSession) + << " (" << ssh_get_error(mSession) << ")" << endl; + + break; + } + name = TQString::fromUtf8(ssh_userauth_kbdint_getname(mSession)); instruction = TQString::fromUtf8(ssh_userauth_kbdint_getinstruction(mSession)); n = ssh_userauth_kbdint_getnprompts(mSession); @@ -193,22 +202,58 @@ int sftpProtocol::authenticateKeyboardInteractive(AuthInfo &info) { << " prompts" << n << endl; for (i = 0; i < n; ++i) { + // See RFC4256 Section 3.3 User Interface char echo; - const char *answer = ""; + TQString answer; prompt = TQString::fromUtf8(ssh_userauth_kbdint_getprompt(mSession, i, &echo)); kdDebug(TDEIO_SFTP_DB) << "prompt=" << prompt << " echo=" << TQString::number(echo) << endl; - if (echo) { - // See RFC4256 Section 3.3 User Interface - TQString newPrompt; - TDEIO::AuthInfo infoKbdInt; - infoKbdInt.url.setProtocol("sftp"); - infoKbdInt.url.setHost(mHost); - infoKbdInt.url.setPort(mPort); + TDEIO::AuthInfo infoKbdInt(info); - infoKbdInt.caption = i18n("SFTP Login"); - infoKbdInt.comment = "sftp://" + mUsername + "@" + mHost; + if (!echo) { + // ssh server requests us to ask user a question without displaying an answer. In normal + // circumstances this is probably a password, but it might be something else depending + // on the server configuration. + bool isPassword = false; + if (prompt.lower().startsWith("password")) { + // We can assume that the ssh server asks for a password and we want a more + // user-friendly prompt in that case + infoKbdInt.prompt = i18n("Please enter your password."); + isPassword = true; + infoKbdInt.keepPassword = true; + if (!mPassword.isNull()) { // if we have a cached password we might use it + kdDebug(TDEIO_SFTP_DB) << "Using cached password" << endl; + answer = mPassword; + } + } else { + // If the server's request doesn't look like a password, keep the servers prompt and + // don't bother saving it + infoKbdInt.prompt = prompt; + infoKbdInt.keepPassword = false; + } + + infoKbdInt.readOnly = true; // set username readonly + /* FIXME: We can query a new user name but we will have to reinitialize the connection if + * it changes <2024-01-10 Fat-Zer> */ + if (answer.isNull()) { + if (openPassDlg(infoKbdInt)) { + kdDebug(TDEIO_SFTP_DB) << "Got the answer from the password dialog" << endl; + answer = infoKbdInt.password; + if(isPassword) { + info.password = infoKbdInt.password; // return the answer to the caller + } + } else { + /* FIXME: Some reasonable action upon cancellation? <2024-01-10 Fat-Zer> */ + } + } + } else { + // ssh server asks for some clear-text information from a user (e.g. a one-time + // identification code) which should be echoed while user enters it. As for now tdeio has + // no means of handle that correctly, so we will have to be creative with the password + // dialog. + TQString newPrompt; + infoKbdInt.comment = "sftp://" + infoKbdInt.username + "@" + mHost; if (!name.isEmpty()) { infoKbdInt.caption = TQString(i18n("SFTP Login") + " - " + name); @@ -221,42 +266,25 @@ int sftpProtocol::authenticateKeyboardInteractive(AuthInfo &info) { newPrompt.append(prompt + "\n\n"); infoKbdInt.readOnly = false; infoKbdInt.keepPassword = false; - infoKbdInt.prompt = i18n("Use the username input field to answer this question."); - + newPrompt.append(i18n("Use the username input field to answer this question.")); + infoKbdInt.prompt = newPrompt; if (openPassDlg(infoKbdInt)) { - kdDebug(TDEIO_SFTP_DB) << "Got the answer from the password dialog" << endl; - answer = info.username.utf8().data(); - } - - if (ssh_userauth_kbdint_setanswer(mSession, i, answer) < 0) { - kdDebug(TDEIO_SFTP_DB) << "An error occurred setting the answer: " - << ssh_get_error(mSession) << endl; - return SSH_AUTH_ERROR; - } - break; - } else { - if (prompt.lower().startsWith("password")) { - answer = mPassword.utf8().data(); + answer = infoKbdInt.username; + kdDebug(TDEIO_SFTP_DB) << "Got the answer from the password dialog: " << answer << endl; } else { - info.readOnly = true; // set username readonly - info.prompt = prompt; - - if (openPassDlg(info)) { - kdDebug(TDEIO_SFTP_DB) << "Got the answer from the password dialog" << endl; - answer = info.password.utf8().data(); - } + /* FIXME: Some reasonable action upon cancellation? <2024-01-10 Fat-Zer> */ } + } - if (ssh_userauth_kbdint_setanswer(mSession, i, answer) < 0) { - kdDebug(TDEIO_SFTP_DB) << "An error occurred setting the answer: " - << ssh_get_error(mSession) << endl; - return SSH_AUTH_ERROR; - } + if (ssh_userauth_kbdint_setanswer(mSession, i, answer.utf8().data()) < 0) { + kdDebug(TDEIO_SFTP_DB) << "An error occurred setting the answer: " + << ssh_get_error(mSession) << endl; + /* FIXME: display the error to the user <2024-01-10 Fat-Zer> */ + return SSH_AUTH_ERROR; } - } - err = ssh_userauth_kbdint(mSession, mUsername.utf8().data(), NULL); - } + } // for each ssh_userauth_kbdint_getprompt() + } // while (1) return err; } @@ -733,6 +761,18 @@ void sftpProtocol::openConnection() { kdDebug(TDEIO_SFTP_DB) << "Trying to authenticate with the server" << endl; + // If no username was set upon connection, get the name from connection + // (probably it'd be the current user's name) + if (mUsername.isEmpty()) { + char *ssh_username = NULL; + rc = ssh_options_get(mSession, SSH_OPTIONS_USER, &ssh_username); + if (rc == 0 && ssh_username && ssh_username[0]) { + mUsername = ssh_username; + info.username = mUsername; + } + ssh_string_free_char(ssh_username); + } + // Try to authenticate rc = ssh_userauth_none(mSession, NULL); if (rc == SSH_AUTH_ERROR) { @@ -786,6 +826,8 @@ void sftpProtocol::openConnection() { if (rc == SSH_AUTH_SUCCESS) { info = tmpInfo; + mUsername = info.username; + mPassword = info.password; } else if (rc == SSH_AUTH_ERROR) { @@ -794,7 +836,7 @@ void sftpProtocol::openConnection() { .arg(i18n("keyboard interactive"))); return; } - } + } // Try to authenticate with password if (rc != SSH_AUTH_SUCCESS && (method & SSH_AUTH_METHOD_PASSWORD)) -- cgit v1.2.3