From 9b8ba69a61f09fbcd40574d0b912846eeaaaa1e2 Mon Sep 17 00:00:00 2001 From: Ryo Nakamura Date: Sun, 31 Mar 2024 16:47:55 +0900 Subject: add ssh keyboard interactive authentication Supporting keyboard-interactive authentication enables login with Cisco DUO MFA (#2). --- src/ssh.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/src/ssh.c b/src/ssh.c index fe6e24f..f21200f 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -11,6 +11,7 @@ #include static int ssh_verify_known_hosts(ssh_session session); +static int ssh_authenticate_kbdint(ssh_session session); static int ssh_set_opts(ssh_session ssh, struct mscp_ssh_opts *opts) { @@ -100,17 +101,18 @@ static int ssh_authenticate(ssh_session ssh, struct mscp_ssh_opts *opts) return 0; auth_bit_mask = ssh_userauth_list(ssh, NULL); - if (auth_bit_mask & SSH_AUTH_METHOD_NONE && ssh_userauth_none(ssh, NULL) == SSH_AUTH_SUCCESS) return 0; + auth_bit_mask = ssh_userauth_list(ssh, NULL); if (auth_bit_mask & SSH_AUTH_METHOD_PUBLICKEY) { char *p = opts->passphrase ? opts->passphrase : NULL; if (ssh_userauth_publickey_auto(ssh, NULL, p) == SSH_AUTH_SUCCESS) return 0; } + auth_bit_mask = ssh_userauth_list(ssh, NULL); if (auth_bit_mask & SSH_AUTH_METHOD_PASSWORD) { if (!opts->password) { char buf[128] = {}; @@ -128,6 +130,12 @@ static int ssh_authenticate(ssh_session ssh, struct mscp_ssh_opts *opts) return 0; } + auth_bit_mask = ssh_userauth_list(ssh, NULL); + if (auth_bit_mask & SSH_AUTH_METHOD_INTERACTIVE) { + if (ssh_authenticate_kbdint(ssh) == SSH_AUTH_SUCCESS) + return 0; + } + return -1; } @@ -319,6 +327,54 @@ static int ssh_verify_known_hosts(ssh_session session) return 0; } +static int ssh_authenticate_kbdint(ssh_session ssh) +{ + /* Copied and bit modified from + * https://api.libssh.org/stable/libssh_tutor_authentication.html */ + int rc; + + rc = ssh_userauth_kbdint(ssh, NULL, NULL); + while (rc == SSH_AUTH_INFO) { + const char *name, *instruction; + int nprompts, iprompt; + + name = ssh_userauth_kbdint_getname(ssh); + instruction = ssh_userauth_kbdint_getinstruction(ssh); + nprompts = ssh_userauth_kbdint_getnprompts(ssh); + + if (strlen(name) > 0) + printf("%s\n", name); + if (strlen(instruction) > 0) + printf("%s\n", instruction); + for (iprompt = 0; iprompt < nprompts; iprompt++) { + const char *prompt; + char echo; + + prompt = ssh_userauth_kbdint_getprompt(ssh, iprompt, &echo); + if (echo) { + char buf[128], *ptr; + + printf("%s", prompt); + if (fgets(buf, sizeof(buf), stdin) == NULL) + return SSH_AUTH_ERROR; + buf[sizeof(buf) - 1] = '\0'; + if ((ptr = strchr(buf, '\n')) != NULL) + *ptr = '\0'; + if (ssh_userauth_kbdint_setanswer(ssh, iprompt, buf) < 0) + return SSH_AUTH_ERROR; + memset(buf, 0, strlen(buf)); + } else { + char *ptr; + ptr = getpass(prompt); + if (ssh_userauth_kbdint_setanswer(ssh, iprompt, ptr) < 0) + return SSH_AUTH_ERROR; + } + } + rc = ssh_userauth_kbdint(ssh, NULL, NULL); + } + return rc; +} + void ssh_sftp_close(sftp_session sftp) { ssh_session ssh = sftp_ssh(sftp); -- cgit v1.2.3