From 609f8fbb7a74f47b935da1f0731f943a94e1c92a Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 23 Aug 2011 18:44:32 +0200 Subject: [PATCH] auth: Add ssh_userauth_try_publickey(). --- include/libssh/libssh.h | 10 ++- src/auth.c | 166 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+), 2 deletions(-) diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h index a5ea9616..f37f8395 100644 --- a/include/libssh/libssh.h +++ b/include/libssh/libssh.h @@ -490,6 +490,14 @@ LIBSSH_API void ssh_set_fd_toread(ssh_session session); LIBSSH_API void ssh_set_fd_towrite(ssh_session session); LIBSSH_API void ssh_silent_disconnect(ssh_session session); LIBSSH_API int ssh_set_pcap_file(ssh_session session, ssh_pcap_file pcapfile); + +/* USERAUTH */ +LIBSSH_API int ssh_userauth_none(ssh_session session, const char *username); +LIBSSH_API int ssh_userauth_list(ssh_session session, const char *username); +LIBSSH_API int ssh_userauth_try_publickey(ssh_session session, + const char *username, + const ssh_key pubkey); + #ifndef _WIN32 LIBSSH_API int ssh_userauth_agent_pubkey(ssh_session session, const char *username, ssh_public_key publickey); @@ -504,8 +512,6 @@ LIBSSH_API int ssh_userauth_kbdint_getnanswers(ssh_session session); LIBSSH_API const char *ssh_userauth_kbdint_getanswer(ssh_session session, unsigned int i); LIBSSH_API int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i, const char *answer); -LIBSSH_API int ssh_userauth_list(ssh_session session, const char *username); -LIBSSH_API int ssh_userauth_none(ssh_session session, const char *username); LIBSSH_API int ssh_userauth_offer_pubkey(ssh_session session, const char *username, int type, ssh_string publickey); LIBSSH_API int ssh_userauth_password(ssh_session session, const char *username, const char *password); LIBSSH_API int ssh_userauth_pubkey(ssh_session session, const char *username, ssh_string publickey, ssh_private_key privatekey); diff --git a/src/auth.c b/src/auth.c index b1fbdc41..88a1e5e2 100644 --- a/src/auth.c +++ b/src/auth.c @@ -461,6 +461,172 @@ fail: return SSH_AUTH_ERROR; } +/** + * @brief Try to authenticate with the given public key. + * + * To avoid unnecessary processing and user interaction, the following method + * is provided for querying whether authentication using the 'pubkey' would + * be possible. + * + * @param[in] ssh_session The SSH session. + * + * @param[in] username The username, this SHOULD be NULL. + * + * @param[in] pubkey The public key to try. + * + * @return SSH_AUTH_ERROR: A serious error happened.\n + * SSH_AUTH_DENIED: The server doesn't accept that public key as an + * authentication token. Try another key or another + * method.\n + * SSH_AUTH_PARTIAL: You've been partially authenticated, you still + * have to use another method.\n + * SSH_AUTH_SUCCESS: The public key is accepted, you want now to use + * ssh_userauth_pubkey(). + * SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again + * later. + * + * @note Most server implementations do not permit changing the username during + * authentication. The username should only be set with ssh_optoins_set() only + * before you connect to the server. + */ +int ssh_userauth_try_publickey(ssh_session session, + const char *username, + const ssh_key pubkey) +{ + ssh_string str; + int rc; + + if (session == NULL) { + return SSH_AUTH_ERROR; + } + + if (pubkey == NULL || !ssh_key_is_public(pubkey)) { + ssh_set_error(session, SSH_FATAL, "Invalid pubkey"); + return SSH_AUTH_ERROR; + } + +#ifdef WITH_SSH1 + if (session->version == 1) { + return SSH_AUTH_DENIED; + } +#endif + + switch(session->pending_call_state) { + case SSH_PENDING_CALL_NONE: + break; + case SSH_PENDING_CALL_AUTH_OFFER_PUBKEY: + goto pending; + default: + ssh_set_error(session, + SSH_FATAL, + "Bad call during pending SSH call in ssh_userauth_try_pubkey"); + return SSH_ERROR; + } + + rc = ssh_userauth_request_service(session); + if (rc == SSH_AGAIN) { + return SSH_AUTH_AGAIN; + } else if (rc == SSH_ERROR) { + return SSH_AUTH_ERROR; + } + + /* request */ + rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST); + if (rc < 0) { + goto fail; + } + + /* username */ + if (username) { + str = ssh_string_from_char(username); + } else { + str = ssh_string_from_char(session->username); + } + if (str == NULL) { + goto fail; + } + + rc = buffer_add_ssh_string(session->out_buffer, str); + ssh_string_free(str); + if (rc < 0) { + goto fail; + } + + /* service */ + str = ssh_string_from_char("ssh-connection"); + if (str == NULL) { + goto fail; + } + + rc = buffer_add_ssh_string(session->out_buffer, str); + ssh_string_free(str); + if (rc < 0) { + goto fail; + } + + /* method */ + str = ssh_string_from_char("publickey"); + if (str == NULL) { + goto fail; + } + + rc = buffer_add_ssh_string(session->out_buffer, str); + ssh_string_free(str); + if (rc < 0) { + goto fail; + } + + /* private key? */ + rc = buffer_add_u8(session->out_buffer, 0); + if (rc < 0) { + goto fail; + } + + /* algo */ + str = ssh_string_from_char(pubkey->type_c); + if (rc < 0) { + goto fail; + } + + rc = buffer_add_ssh_string(session->out_buffer, str); + ssh_string_free(str); + if (rc < 0) { + goto fail; + } + + /* public key */ + str = ssh_pki_export_pubkey_blob(pubkey); + if (str == NULL) { + goto fail; + } + + rc = buffer_add_ssh_string(session->out_buffer, str); + ssh_string_free(str); + if (rc < 0) { + goto fail; + } + + session->auth_state = SSH_AUTH_STATE_NONE; + session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY; + rc = packet_send(session); + if (rc == SSH_ERROR) { + return SSH_AUTH_ERROR; + } + +pending: + rc = ssh_userauth_get_response(session); + if (rc != SSH_AUTH_AGAIN) { + session->pending_call_state = SSH_PENDING_CALL_NONE; + } + + return rc; +fail: + ssh_set_error_oom(session); + buffer_reinit(session->out_buffer); + + return SSH_AUTH_ERROR; +} + /** * @brief Try to authenticate through public key. *