/* the heart of the whole keyboard interactive login */ int ssh_userauth_kbdint(SSH_SESSION *session, const char *user, const char *submethods){ int err; if(session->version==1) return SSH_AUTH_DENIED; // no keyb-interactive for ssh1 enter_function(); if( !session->kbdint){ /* first time we call. we must ask for a challenge */ if(!user) if(!(user=session->options->username)){ if(ssh_options_default_username(session->options)){ leave_function(); return SSH_AUTH_ERROR; } else user=session->options->username; } if(ask_userauth(session)){ leave_function(); return SSH_AUTH_ERROR; } err=kbdauth_init(session,user,submethods); if(err!=SSH_AUTH_INFO){ leave_function(); return err; /* error or first try success */ } err=kbdauth_info_get(session); if(err==SSH_AUTH_ERROR){ kbdint_free(session->kbdint); session->kbdint=NULL; } leave_function(); return err; } /* if we are at this point, it's because session->kbdint exists */ /* it means the user has set some informations there we need to send * * the server. and then we need to ack the status (new questions or ok * * pass in */ err=kbdauth_send(session); kbdint_free(session->kbdint); session->kbdint=NULL; if(err!=SSH_AUTH_INFO){ leave_function(); return err; } err=kbdauth_info_get(session); if(err==SSH_AUTH_ERROR){ kbdint_free(session->kbdint); session->kbdint=NULL; } leave_function(); return err; }
/* unregister kbd-int callbacks and context */ void auth2_challenge_stop(Authctxt *authctxt) { /* unregister callback */ dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); if (authctxt->kbdintctxt != NULL) { kbdint_free(authctxt->kbdintctxt); authctxt->kbdintctxt = NULL; } }
/* unregister kbd-int callbacks and context */ static void auth2_challenge_stop(Authctxt *authctxt) { /* unregister callback */ dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); if (authctxt->method->method_data != NULL) { kbdint_free((KbdintAuthctxt *) authctxt->method->method_data); authctxt->method->method_data = NULL; } }
/* unregister kbd-int callbacks and context */ void auth2_challenge_stop(struct ssh *ssh) { struct authctxt *authctxt = ssh->authctxt; /* unregister callback */ ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); if (authctxt->kbdintctxt != NULL) { kbdint_free(authctxt->kbdintctxt); authctxt->kbdintctxt = NULL; } }
/** * @brief Try to authenticate through the "keyboard-interactive" method. * * @param session The ssh session to use. * * @param user The username to authenticate. You can specify NULL if * ssh_option_set_username() has been used. You cannot try * two different logins in a row. * * @param submethods Undocumented. Set it to NULL. * * @returns SSH_AUTH_ERROR: A serious error happened\n * SSH_AUTH_DENIED: Authentication failed : use another method\n * SSH_AUTH_PARTIAL: You've been partially authenticated, you still * have to use another method\n * SSH_AUTH_SUCCESS: Authentication success\n * SSH_AUTH_INFO: The server asked some questions. Use * ssh_userauth_kbdint_getnprompts() and such. * * @see ssh_userauth_kbdint_getnprompts() * @see ssh_userauth_kbdint_getname() * @see ssh_userauth_kbdint_getinstruction() * @see ssh_userauth_kbdint_getprompt() * @see ssh_userauth_kbdint_setanswer() */ int ssh_userauth_kbdint(ssh_session session, const char *user, const char *submethods) { int rc = SSH_AUTH_ERROR; if (session->version == 1) { /* No keyb-interactive for ssh1 */ return SSH_AUTH_DENIED; } enter_function(); if (session->kbdint == NULL) { /* first time we call. we must ask for a challenge */ if (user == NULL) { if ((user = session->username) == NULL) { if (ssh_options_apply(session) < 0) { leave_function(); return SSH_AUTH_ERROR; } else { user = session->username; } } } if (ask_userauth(session)) { leave_function(); return SSH_AUTH_ERROR; } rc = kbdauth_init(session, user, submethods); if (rc != SSH_AUTH_INFO) { leave_function(); return rc; /* error or first try success */ } rc = kbdauth_info_get(session); if (rc == SSH_AUTH_ERROR) { kbdint_free(session->kbdint); session->kbdint = NULL; } leave_function(); return rc; } /* * If we are at this point, it ss because session->kbdint exists. * It means the user has set some information there we need to send * the server and then we need to ack the status (new questions or ok * pass in). */ rc = kbdauth_send(session); kbdint_free(session->kbdint); session->kbdint = NULL; if(rc != SSH_AUTH_INFO) { leave_function(); return rc; } rc = kbdauth_info_get(session); if (rc == SSH_AUTH_ERROR) { kbdint_free(session->kbdint); session->kbdint = NULL; } leave_function(); return rc; }
static int kbdauth_info_get(ssh_session session) { ssh_string name; /* name of the "asking" window showed to client */ ssh_string instruction; ssh_string tmp; uint32_t nprompts; uint32_t i; enter_function(); name = buffer_get_ssh_string(session->in_buffer); instruction = buffer_get_ssh_string(session->in_buffer); tmp = buffer_get_ssh_string(session->in_buffer); buffer_get_u32(session->in_buffer, &nprompts); if (name == NULL || instruction == NULL || tmp == NULL) { string_free(name); string_free(instruction); /* tmp if empty if we got here */ ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg"); leave_function(); return SSH_AUTH_ERROR; } string_free(tmp); if (session->kbdint == NULL) { session->kbdint = kbdint_new(); if (session->kbdint == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); string_free(name); string_free(instruction); leave_function(); return SSH_AUTH_ERROR; } } else { kbdint_clean(session->kbdint); } session->kbdint->name = string_to_char(name); string_free(name); if (session->kbdint->name == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); kbdint_free(session->kbdint); leave_function(); return SSH_AUTH_ERROR; } session->kbdint->instruction = string_to_char(instruction); string_free(instruction); if (session->kbdint->instruction == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); kbdint_free(session->kbdint); session->kbdint = NULL; leave_function(); return SSH_AUTH_ERROR; } nprompts = ntohl(nprompts); if (nprompts > KBDINT_MAX_PROMPT) { ssh_set_error(session, SSH_FATAL, "Too much prompt asked from server: %u (0x%.4x)", nprompts, nprompts); kbdint_free(session->kbdint); session->kbdint = NULL; leave_function(); return SSH_AUTH_ERROR; } session->kbdint->nprompts = nprompts; session->kbdint->prompts = malloc(nprompts * sizeof(char *)); if (session->kbdint->prompts == NULL) { session->kbdint->nprompts = 0; ssh_set_error(session, SSH_FATAL, "No space left"); kbdint_free(session->kbdint); session->kbdint = NULL; leave_function(); return SSH_AUTH_ERROR; } memset(session->kbdint->prompts, 0, nprompts * sizeof(char *)); session->kbdint->echo = malloc(nprompts); if (session->kbdint->echo == NULL) { session->kbdint->nprompts = 0; ssh_set_error(session, SSH_FATAL, "No space left"); kbdint_free(session->kbdint); session->kbdint = NULL; leave_function(); return SSH_AUTH_ERROR; } memset(session->kbdint->echo, 0, nprompts); for (i = 0; i < nprompts; i++) { tmp = buffer_get_ssh_string(session->in_buffer); buffer_get_u8(session->in_buffer, &session->kbdint->echo[i]); if (tmp == NULL) { ssh_set_error(session, SSH_FATAL, "Short INFO_REQUEST packet"); kbdint_free(session->kbdint); session->kbdint = NULL; leave_function(); return SSH_AUTH_ERROR; } session->kbdint->prompts[i] = string_to_char(tmp); string_free(tmp); if (session->kbdint->prompts[i] == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); kbdint_free(session->kbdint); session->kbdint = NULL; leave_function(); return SSH_AUTH_ERROR; } } leave_function(); return SSH_AUTH_INFO; /* we are not auth. but we parsed the packet */ }