diff options
Diffstat (limited to 'libssh/auth.c')
-rw-r--r-- | libssh/auth.c | 1682 |
1 files changed, 0 insertions, 1682 deletions
diff --git a/libssh/auth.c b/libssh/auth.c deleted file mode 100644 index f0443db0..00000000 --- a/libssh/auth.c +++ /dev/null @@ -1,1682 +0,0 @@ -/* - * auth1.c - authentication with SSH protocols - * - * This file is part of the SSH Library - * - * Copyright (c) 2003-2008 by Aris Adamantiadis - * Copyright (c) 2008-2009 Andreas Schneider <mail@cynapses.org> - * - * The SSH Library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * The SSH Library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the SSH Library; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#ifndef _WIN32 -#include <arpa/inet.h> -#endif - -#include "libssh/priv.h" -#include "libssh/ssh2.h" -#include "libssh/buffer.h" -#include "libssh/agent.h" -#include "libssh/keyfiles.h" -#include "libssh/misc.h" -#include "libssh/packet.h" -#include "libssh/session.h" -#include "libssh/keys.h" -#include "libssh/auth.h" - -/** - * @defgroup libssh_auth The SSH authentication functions. - * @ingroup libssh - * - * Functions to authenticate with a server. - * - * @{ - */ - -/** - * @internal - * - * @brief Ask access to the ssh-userauth service. - * - * @param[in] session The SSH session handle. - * - * @returns SSH_OK on success, SSH_ERROR on error. - * - * @bug current implementation is blocking - */ -static int ask_userauth(ssh_session session) { - int rc = 0; - - enter_function(); - do { - rc=ssh_service_request(session,"ssh-userauth"); - if(rc==SSH_AGAIN) - ssh_handle_packets(session,-1); - } while(rc==SSH_AGAIN); - leave_function(); - return rc; -} - -/** - * @internal - * - * @brief Handles a SSH_USERAUTH_BANNER packet. - * - * This banner should be shown to user prior to authentication - */ -SSH_PACKET_CALLBACK(ssh_packet_userauth_banner){ - ssh_string banner; - (void)type; - (void)user; - enter_function(); - banner = buffer_get_ssh_string(packet); - if (banner == NULL) { - ssh_log(session, SSH_LOG_RARE, - "Invalid SSH_USERAUTH_BANNER packet"); - } else { - ssh_log(session, SSH_LOG_PACKET, - "Received SSH_USERAUTH_BANNER packet"); - if(session->banner != NULL) - ssh_string_free(session->banner); - session->banner = banner; - } - leave_function(); - return SSH_PACKET_USED; -} - -/** - * @internal - * - * @brief Handles a SSH_USERAUTH_FAILURE packet. - * - * This handles the complete or partial authentication failure. - */ -SSH_PACKET_CALLBACK(ssh_packet_userauth_failure){ - char *auth_methods = NULL; - ssh_string auth; - uint8_t partial = 0; - (void) type; - (void) user; - enter_function(); - - auth = buffer_get_ssh_string(packet); - if (auth == NULL || buffer_get_u8(packet, &partial) != 1) { - ssh_set_error(session, SSH_FATAL, - "Invalid SSH_MSG_USERAUTH_FAILURE message"); - session->auth_state=SSH_AUTH_STATE_ERROR; - goto end; - } - - auth_methods = ssh_string_to_char(auth); - if (auth_methods == NULL) { - ssh_set_error_oom(session); - goto end; - } - - if (partial) { - session->auth_state=SSH_AUTH_STATE_PARTIAL; - ssh_log(session,SSH_LOG_PROTOCOL, - "Partial success. Authentication that can continue: %s", - auth_methods); - } else { - session->auth_state=SSH_AUTH_STATE_FAILED; - ssh_log(session, SSH_LOG_PROTOCOL, - "Access denied. Authentication that can continue: %s", - auth_methods); - ssh_set_error(session, SSH_REQUEST_DENIED, - "Access denied. Authentication that can continue: %s", - auth_methods); - - session->auth_methods = 0; - } - if (strstr(auth_methods, "password") != NULL) { - session->auth_methods |= SSH_AUTH_METHOD_PASSWORD; - } - if (strstr(auth_methods, "keyboard-interactive") != NULL) { - session->auth_methods |= SSH_AUTH_METHOD_INTERACTIVE; - } - if (strstr(auth_methods, "publickey") != NULL) { - session->auth_methods |= SSH_AUTH_METHOD_PUBLICKEY; - } - if (strstr(auth_methods, "hostbased") != NULL) { - session->auth_methods |= SSH_AUTH_METHOD_HOSTBASED; - } - -end: - ssh_string_free(auth); - SAFE_FREE(auth_methods); - leave_function(); - return SSH_PACKET_USED; -} - -/** - * @internal - * - * @brief Handles a SSH_USERAUTH_SUCCESS packet. - * - * It is also used to communicate the new to the upper levels. - */ -SSH_PACKET_CALLBACK(ssh_packet_userauth_success){ - enter_function(); - (void)packet; - (void)type; - (void)user; - ssh_log(session,SSH_LOG_PACKET,"Received SSH_USERAUTH_SUCCESS"); - ssh_log(session,SSH_LOG_PROTOCOL,"Authentication successful"); - session->auth_state=SSH_AUTH_STATE_SUCCESS; - session->session_state=SSH_SESSION_STATE_AUTHENTICATED; - leave_function(); - return SSH_PACKET_USED; -} - -/** - * @internal - * - * @brief Handles a SSH_USERAUTH_PK_OK or SSH_USERAUTH_INFO_REQUEST packet. - * - * Since the two types of packets share the same code, additional work is done - * to understand if we are in a public key or keyboard-interactive context. - */ -SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok){ - int rc; - enter_function(); - ssh_log(session,SSH_LOG_PACKET,"Received SSH_USERAUTH_PK_OK/INFO_REQUEST"); - if(session->auth_state==SSH_AUTH_STATE_KBDINT_SENT){ - /* Assuming we are in keyboard-interactive context */ - ssh_log(session,SSH_LOG_PACKET,"keyboard-interactive context, assuming SSH_USERAUTH_INFO_REQUEST"); - rc=ssh_packet_userauth_info_request(session,type,packet,user); - } else { - session->auth_state=SSH_AUTH_STATE_PK_OK; - ssh_log(session,SSH_LOG_PACKET,"assuming SSH_USERAUTH_PK_OK"); - rc=SSH_PACKET_USED; - } - leave_function(); - return rc; -} - -static int wait_auth_status(ssh_session session) { - int rc = SSH_AUTH_ERROR; - - enter_function(); - - while (session->auth_state == SSH_AUTH_STATE_NONE || - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT) { - if (ssh_handle_packets(session,-1) != SSH_OK) - break; - } - switch(session->auth_state){ - case SSH_AUTH_STATE_ERROR: - rc=SSH_AUTH_ERROR; - break; - case SSH_AUTH_STATE_FAILED: - rc=SSH_AUTH_DENIED; - break; - case SSH_AUTH_STATE_INFO: - rc=SSH_AUTH_INFO; - break; - case SSH_AUTH_STATE_PARTIAL: - rc=SSH_AUTH_PARTIAL; - break; - case SSH_AUTH_STATE_PK_OK: - case SSH_AUTH_STATE_SUCCESS: - rc=SSH_AUTH_SUCCESS; - break; - case SSH_AUTH_STATE_KBDINT_SENT: - case SSH_AUTH_STATE_NONE: - /* not reached */ - rc=SSH_AUTH_ERROR; - break; - } - leave_function(); - return rc; -} - -/** - * @brief retrieves available authentication methods for this session - * @deprecated - * @see ssh_userauth_list - */ -int ssh_auth_list(ssh_session session) { - return ssh_userauth_list(session, NULL); -} - -/** - * @brief retrieves available authentication methods for this session - * @param[in] session the SSH session - * @param[in] username set to NULL - * @returns A bitfield of values SSH_AUTH_METHOD_NONE, SSH_AUTH_METHOD_PASSWORD, - SSH_AUTH_METHOD_PUBLICKEY, SSH_AUTH_METHOD_HOSTBASED, - SSH_AUTH_METHOD_INTERACTIVE. - @warning Other reserved flags may appear in future versions. - */ -int ssh_userauth_list(ssh_session session, const char *username) { - if (session == NULL) { - return SSH_AUTH_ERROR; - } - -#ifdef WITH_SSH1 - if(session->version==1){ - return SSH_AUTH_METHOD_PASSWORD; - } -#endif - if (session->auth_methods == 0) { - ssh_userauth_none(session, username); - } - return session->auth_methods; -} - -/* use the "none" authentication question */ - -/** - * @brief Try to authenticate through the "none" method. - * - * @param[in] session The ssh session to use. - * - * @param[in] username Deprecated, set 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 - */ -int ssh_userauth_none(ssh_session session, const char *username) { - ssh_string user = NULL; - ssh_string service = NULL; - ssh_string method = NULL; - int rc = SSH_AUTH_ERROR; - - enter_function(); - -#ifdef WITH_SSH1 - if (session->version == 1) { - rc = ssh_userauth1_none(session, username); - leave_function(); - return rc; - } -#endif - if(session->auth_methods != 0){ - /* userauth_none or other method was already tried before */ - ssh_set_error(session,SSH_REQUEST_DENIED,"None method rejected by server"); - leave_function(); - return SSH_AUTH_DENIED; - } - if (username == NULL) { - if (session->username == NULL) { - if (ssh_options_apply(session) < 0) { - leave_function(); - return rc; - } - } - user = ssh_string_from_char(session->username); - } else { - user = ssh_string_from_char(username); - } - - if (user == NULL) { - leave_function(); - return rc; - } - - if (ask_userauth(session) < 0) { - ssh_string_free(user); - leave_function(); - return rc; - } - - method = ssh_string_from_char("none"); - if (method == NULL) { - goto error; - } - service = ssh_string_from_char("ssh-connection"); - if (service == NULL) { - goto error; - } - - if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 || - buffer_add_ssh_string(session->out_buffer, user) < 0 || - buffer_add_ssh_string(session->out_buffer, service) < 0 || - buffer_add_ssh_string(session->out_buffer, method) < 0) { - goto error; - } - - ssh_string_free(service); - ssh_string_free(method); - ssh_string_free(user); - session->auth_state=SSH_AUTH_STATE_NONE; - if (packet_send(session) == SSH_ERROR) { - leave_function(); - return rc; - } - rc = wait_auth_status(session); - - leave_function(); - return rc; -error: - buffer_reinit(session->out_buffer); - ssh_string_free(service); - ssh_string_free(method); - ssh_string_free(user); - - leave_function(); - return rc; -} - -/** - * @brief Try to authenticate through public key. - * - * @param[in] session The ssh session to use. - * - * @param[in] username 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[in] type The type of the public key. This value is given by - * publickey_from_file() or ssh_privatekey_type(). - * - * @param[in] publickey A public key returned by publickey_from_file(). - * - * @returns 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(). - * - * @see publickey_from_file() - * @see privatekey_from_file() - * @see ssh_privatekey_type() - * @see ssh_userauth_pubkey() - */ -int ssh_userauth_offer_pubkey(ssh_session session, const char *username, - int type, ssh_string publickey) { - ssh_string user = NULL; - ssh_string service = NULL; - ssh_string method = NULL; - ssh_string algo = NULL; - int rc = SSH_AUTH_ERROR; - - enter_function(); - -#ifdef WITH_SSH1 - if (session->version == 1) { - ssh_userauth1_offer_pubkey(session, username, type, publickey); - leave_function(); - return rc; - } -#endif - - if (username == NULL) { - if (session->username == NULL) { - if (ssh_options_apply(session) < 0) { - leave_function(); - return rc; - } - } - user = ssh_string_from_char(session->username); - } else { - user = ssh_string_from_char(username); - } - - if (user == NULL) { - leave_function(); - return rc; - } - - if (ask_userauth(session) < 0) { - ssh_string_free(user); - leave_function(); - return rc; - } - - service = ssh_string_from_char("ssh-connection"); - if (service == NULL) { - goto error; - } - method = ssh_string_from_char("publickey"); - if (method == NULL) { - goto error; - } - algo = ssh_string_from_char(ssh_type_to_char(type)); - if (algo == NULL) { - goto error; - } - - if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 || - buffer_add_ssh_string(session->out_buffer, user) < 0 || - buffer_add_ssh_string(session->out_buffer, service) < 0 || - buffer_add_ssh_string(session->out_buffer, method) < 0 || - buffer_add_u8(session->out_buffer, 0) < 0 || - buffer_add_ssh_string(session->out_buffer, algo) < 0 || - buffer_add_ssh_string(session->out_buffer, publickey) < 0) { - goto error; - } - - ssh_string_free(user); - ssh_string_free(method); - ssh_string_free(service); - ssh_string_free(algo); - session->auth_state=SSH_AUTH_STATE_NONE; - if (packet_send(session) == SSH_ERROR) { - leave_function(); - return rc; - } - rc = wait_auth_status(session); - - leave_function(); - return rc; -error: - buffer_reinit(session->out_buffer); - ssh_string_free(user); - ssh_string_free(method); - ssh_string_free(service); - ssh_string_free(algo); - - leave_function(); - return rc; -} - - -/** - * @brief Try to authenticate through public key. - * - * @param[in] session The ssh session to use. - * - * @param[in] username 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[in] publickey A public key returned by publickey_from_file(), or NULL - * to generate automatically from privatekey. - * - * @param[in] privatekey A private key returned by privatekey_from_file(). - * - * @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 successful. - * - * @see publickey_from_file() - * @see privatekey_from_file() - * @see privatekey_free() - * @see ssh_userauth_offer_pubkey() - */ -int ssh_userauth_pubkey(ssh_session session, const char *username, - ssh_string publickey, ssh_private_key privatekey) { - ssh_string user = NULL; - ssh_string service = NULL; - ssh_string method = NULL; - ssh_string algo = NULL; - ssh_string sign = NULL; - ssh_public_key pk = NULL; - ssh_string pkstr = NULL; - int rc = SSH_AUTH_ERROR; - - enter_function(); - -#if 0 - if (session->version == 1) { - return ssh_userauth1_pubkey(session, username, publickey, privatekey); - } -#endif - - if (username == NULL) { - if (session->username == NULL) { - if (ssh_options_apply(session) < 0) { - leave_function(); - return rc; - } - } - user = ssh_string_from_char(session->username); - } else { - user = ssh_string_from_char(username); - } - - if (user == NULL) { - leave_function(); - return rc; - } - - if (ask_userauth(session) < 0) { - ssh_string_free(user); - leave_function(); - return rc; - } - - service = ssh_string_from_char("ssh-connection"); - if (service == NULL) { - goto error; - } - method = ssh_string_from_char("publickey"); - if (method == NULL) { - goto error; - } - algo = ssh_string_from_char(ssh_type_to_char(privatekey->type)); - if (algo == NULL) { - goto error; - } - if (publickey == NULL) { - pk = publickey_from_privatekey(privatekey); - if (pk == NULL) { - goto error; - } - pkstr = publickey_to_string(pk); - publickey_free(pk); - if (pkstr == NULL) { - goto error; - } - } - - /* we said previously the public key was accepted */ - if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 || - buffer_add_ssh_string(session->out_buffer, user) < 0 || - buffer_add_ssh_string(session->out_buffer, service) < 0 || - buffer_add_ssh_string(session->out_buffer, method) < 0 || - buffer_add_u8(session->out_buffer, 1) < 0 || - buffer_add_ssh_string(session->out_buffer, algo) < 0 || - buffer_add_ssh_string(session->out_buffer, (publickey == NULL ? pkstr : publickey)) < 0) { - goto error; - } - - ssh_string_free(user); - ssh_string_free(service); - ssh_string_free(method); - ssh_string_free(algo); - ssh_string_free(pkstr); - - sign = ssh_do_sign(session,session->out_buffer, privatekey); - if (sign) { - if (buffer_add_ssh_string(session->out_buffer,sign) < 0) { - goto error; - } - ssh_string_free(sign); - session->auth_state=SSH_AUTH_STATE_NONE; - if (packet_send(session) == SSH_ERROR) { - leave_function(); - return rc; - } - rc = wait_auth_status(session); - } - - leave_function(); - return rc; -error: - buffer_reinit(session->out_buffer); - ssh_string_free(user); - ssh_string_free(service); - ssh_string_free(method); - ssh_string_free(algo); - ssh_string_free(pkstr); - - leave_function(); - return rc; -} - -/** - * @brief Try to authenticate through a private key file. - * - * @param[in] session The ssh session to use. - * - * @param[in] username 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[in] filename Filename containing the private key. - * - * @param[in] passphrase Passphrase to decrypt the private key. Set to null if - * none is needed or it is unknown. - * - * @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 successful. - * - * @see publickey_from_file() - * @see privatekey_from_file() - * @see privatekey_free() - * @see ssh_userauth_pubkey() - */ -int ssh_userauth_privatekey_file(ssh_session session, const char *username, - const char *filename, const char *passphrase) { - char *pubkeyfile = NULL; - ssh_string pubkey = NULL; - ssh_private_key privkey = NULL; - int type = 0; - int rc = SSH_AUTH_ERROR; - - enter_function(); - - pubkeyfile = malloc(strlen(filename) + 1 + 4); - if (pubkeyfile == NULL) { - leave_function(); - return SSH_AUTH_ERROR; - } - sprintf(pubkeyfile, "%s.pub", filename); - - pubkey = publickey_from_file(session, pubkeyfile, &type); - if (pubkey == NULL) { - ssh_log(session, SSH_LOG_RARE, "Public key file %s not found. Trying to generate it.", pubkeyfile); - /* auto-detect the key type with type=0 */ - privkey = privatekey_from_file(session, filename, 0, passphrase); - } else { - ssh_log(session, SSH_LOG_RARE, "Public key file %s loaded.", pubkeyfile); - privkey = privatekey_from_file(session, filename, type, passphrase); - } - if (privkey == NULL) { - goto error; - } - /* ssh_userauth_pubkey is responsible for taking care of null-pubkey */ - rc = ssh_userauth_pubkey(session, username, pubkey, privkey); - privatekey_free(privkey); - -error: - SAFE_FREE(pubkeyfile); - ssh_string_free(pubkey); - - leave_function(); - return rc; -} - -#ifndef _WIN32 -/** - * @brief Try to authenticate through public key with an ssh agent. - * - * @param[in] session The ssh session to use. - * - * @param[in] username 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[in] publickey The public key provided by the agent. - * - * @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 successful. - * - * @see publickey_from_file() - * @see privatekey_from_file() - * @see privatekey_free() - * @see ssh_userauth_offer_pubkey() - */ -int ssh_userauth_agent_pubkey(ssh_session session, const char *username, - ssh_public_key publickey) { - ssh_string user = NULL; - ssh_string service = NULL; - ssh_string method = NULL; - ssh_string algo = NULL; - ssh_string key = NULL; - ssh_string sign = NULL; - int rc = SSH_AUTH_ERROR; - - enter_function(); - - if (! agent_is_running(session)) { - return rc; - } - - if (username == NULL) { - if (session->username == NULL) { - if (ssh_options_apply(session) < 0) { - leave_function(); - return rc; - } - } - user = ssh_string_from_char(session->username); - } else { - user = ssh_string_from_char(username); - } - - if (user == NULL) { - leave_function(); - return rc; - } - - if (ask_userauth(session) < 0) { - ssh_string_free(user); - leave_function(); - return rc; - } - - service = ssh_string_from_char("ssh-connection"); - if (service == NULL) { - goto error; - } - method = ssh_string_from_char("publickey"); - if (method == NULL) { - goto error; - } - algo = ssh_string_from_char(ssh_type_to_char(publickey->type)); - if (algo == NULL) { - goto error; - } - key = publickey_to_string(publickey); - if (key == NULL) { - goto error; - } - - /* we said previously the public key was accepted */ - if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 || - buffer_add_ssh_string(session->out_buffer, user) < 0 || - buffer_add_ssh_string(session->out_buffer, service) < 0 || - buffer_add_ssh_string(session->out_buffer, method) < 0 || - buffer_add_u8(session->out_buffer, 1) < 0 || - buffer_add_ssh_string(session->out_buffer, algo) < 0 || - buffer_add_ssh_string(session->out_buffer, key) < 0) { - goto error; - } - - sign = ssh_do_sign_with_agent(session, session->out_buffer, publickey); - - if (sign) { - if (buffer_add_ssh_string(session->out_buffer, sign) < 0) { - goto error; - } - ssh_string_free(sign); - session->auth_state=SSH_AUTH_STATE_NONE; - if (packet_send(session) == SSH_ERROR) { - leave_function(); - return rc; - } - rc = wait_auth_status(session); - } - - ssh_string_free(user); - ssh_string_free(service); - ssh_string_free(method); - ssh_string_free(algo); - ssh_string_free(key); - - leave_function(); - - return rc; -error: - buffer_reinit(session->out_buffer); - ssh_string_free(sign); - ssh_string_free(user); - ssh_string_free(service); - ssh_string_free(method); - ssh_string_free(algo); - ssh_string_free(key); - - leave_function(); - return rc; -} -#endif /* _WIN32 */ - -/** - * @brief Try to authenticate by password. - * - * @param[in] session The ssh session to use. - * - * @param[in] username 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[in] password The password to use. Take care to clean it after - * the authentication. - * - * @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 successful. - * - * @see ssh_userauth_kbdint() - * @see BURN_STRING - */ -int ssh_userauth_password(ssh_session session, const char *username, - const char *password) { - ssh_string user = NULL; - ssh_string service = NULL; - ssh_string method = NULL; - ssh_string pwd = NULL; - int rc = SSH_AUTH_ERROR; - - enter_function(); - -#ifdef WITH_SSH1 - if (session->version == 1) { - rc = ssh_userauth1_password(session, username, password); - leave_function(); - return rc; - } -#endif - - if (username == NULL) { - if (session->username == NULL) { - if (ssh_options_apply(session) < 0) { - leave_function(); - return rc; - } - } - user = ssh_string_from_char(session->username); - } else { - user = ssh_string_from_char(username); - } - - if (user == NULL) { - leave_function(); - return rc; - } - - if (ask_userauth(session) < 0) { - ssh_string_free(user); - leave_function(); - return rc; - } - - service = ssh_string_from_char("ssh-connection"); - if (service == NULL) { - goto error; - } - method = ssh_string_from_char("password"); - if (method == NULL) { - goto error; - } - pwd = ssh_string_from_char(password); - if (pwd == NULL) { - goto error; - } - - if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 || - buffer_add_ssh_string(session->out_buffer, user) < 0 || - buffer_add_ssh_string(session->out_buffer, service) < 0 || - buffer_add_ssh_string(session->out_buffer, method) < 0 || - buffer_add_u8(session->out_buffer, 0) < 0 || - buffer_add_ssh_string(session->out_buffer, pwd) < 0) { - goto error; - } - - ssh_string_free(user); - ssh_string_free(service); - ssh_string_free(method); - ssh_string_burn(pwd); - ssh_string_free(pwd); - session->auth_state=SSH_AUTH_STATE_NONE; - if (packet_send(session) == SSH_ERROR) { - leave_function(); - return rc; - } - rc = wait_auth_status(session); - - leave_function(); - return rc; -error: - buffer_reinit(session->out_buffer); - ssh_string_free(user); - ssh_string_free(service); - ssh_string_free(method); - ssh_string_burn(pwd); - ssh_string_free(pwd); - - leave_function(); - return rc; -} - -/** - * @brief Tries to automatically authenticate with public key and "none" - * - * It may fail, for instance it doesn't ask for a password and uses a default - * asker for passphrases (in case the private key is encrypted). - * - * @param[in] session The ssh session to authenticate with. - * - * @param[in] passphrase Use this passphrase to unlock the privatekey. Use NULL - * if you don't want to use a passphrase or the user - * should be asked. - * - * @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 - * - * @see ssh_userauth_kbdint() - * @see ssh_userauth_password() - */ -int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) { - struct ssh_iterator *it; - ssh_private_key privkey; - ssh_public_key pubkey; - ssh_string pubkey_string; - int type = 0; - int rc; - - enter_function(); - - /* Always test none authentication */ - rc = ssh_userauth_none(session, NULL); - if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_SUCCESS) { - leave_function(); - return rc; - } - - /* Try authentication with ssh-agent first */ -#ifndef _WIN32 - if (agent_is_running(session)) { - char *privkey_file = NULL; - - ssh_log(session, SSH_LOG_RARE, - "Trying to authenticate with SSH agent keys as user: %s", - session->username); - - for (pubkey = agent_get_first_ident(session, &privkey_file); - pubkey != NULL; - pubkey = agent_get_next_ident(session, &privkey_file)) { - - ssh_log(session, SSH_LOG_RARE, "Trying identity %s", privkey_file); - - pubkey_string = publickey_to_string(pubkey); - if (pubkey_string) { - rc = ssh_userauth_offer_pubkey(session, NULL, pubkey->type, pubkey_string); - ssh_string_free(pubkey_string); - if (rc == SSH_AUTH_ERROR) { - SAFE_FREE(privkey_file); - publickey_free(pubkey); - leave_function(); - - return rc; - } else if (rc != SSH_AUTH_SUCCESS) { - ssh_log(session, SSH_LOG_PROTOCOL, "Public key refused by server"); - SAFE_FREE(privkey_file); - publickey_free(pubkey); - continue; - } - ssh_log(session, SSH_LOG_PROTOCOL, "Public key accepted"); - /* pubkey accepted by server ! */ - rc = ssh_userauth_agent_pubkey(session, NULL, pubkey); - if (rc == SSH_AUTH_ERROR) { - SAFE_FREE(privkey_file); - publickey_free(pubkey); - leave_function(); - - return rc; - } else if (rc != SSH_AUTH_SUCCESS) { - ssh_log(session, SSH_LOG_RARE, - "Server accepted public key but refused the signature ;" - " It might be a bug of libssh"); - SAFE_FREE(privkey_file); - publickey_free(pubkey); - continue; - } - /* auth success */ - ssh_log(session, SSH_LOG_PROTOCOL, "Authentication using %s success", - privkey_file); - SAFE_FREE(privkey_file); - publickey_free(pubkey); - - leave_function(); - - return SSH_AUTH_SUCCESS; - } /* if pubkey */ - SAFE_FREE(privkey_file); - publickey_free(pubkey); - } /* for each privkey */ - } /* if agent is running */ -#endif - - - for (it = ssh_list_get_iterator(session->identity); - it != NULL; - it = it->next) { - const char *privkey_file = it->data; - int privkey_open = 0; - - privkey = NULL; - - ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s", privkey_file); - - rc = ssh_try_publickey_from_file(session, privkey_file, &pubkey_string, &type); - if (rc == 1) { - char *publickey_file; - size_t len; - - privkey = privatekey_from_file(session, privkey_file, type, passphrase); - if (privkey == NULL) { - ssh_log(session, SSH_LOG_RARE, - "Reading private key %s failed (bad passphrase ?)", - privkey_file); - leave_function(); - return SSH_AUTH_ERROR; - } - privkey_open = 1; - - pubkey = publickey_from_privatekey(privkey); - if (pubkey == NULL) { - privatekey_free(privkey); - ssh_set_error_oom(session); - leave_function(); - return SSH_AUTH_ERROR; - } - - pubkey_string = publickey_to_string(pubkey); - type = pubkey->type; - publickey_free(pubkey); - if (pubkey_string == NULL) { - ssh_set_error_oom(session); - leave_function(); - return SSH_AUTH_ERROR; - } - - len = strlen(privkey_file) + 5; - publickey_file = malloc(len); - if (publickey_file == NULL) { - ssh_set_error_oom(session); - leave_function(); - return SSH_AUTH_ERROR; - } - snprintf(publickey_file, len, "%s.pub", privkey_file); - rc = ssh_publickey_to_file(session, publickey_file, pubkey_string, type); - if (rc < 0) { - ssh_log(session, SSH_LOG_PACKET, - "Could not write public key to file: %s", publickey_file); - } - SAFE_FREE(publickey_file); - } else if (rc < 0) { - continue; - } - - rc = ssh_userauth_offer_pubkey(session, NULL, type, pubkey_string); - if (rc == SSH_AUTH_ERROR){ - ssh_string_free(pubkey_string); - ssh_log(session, SSH_LOG_RARE, "Publickey authentication error"); - leave_function(); - return rc; - } else { - if (rc != SSH_AUTH_SUCCESS){ - ssh_log(session, SSH_LOG_PROTOCOL, "Publickey refused by server"); - ssh_string_free(pubkey_string); - continue; - } - } - - /* Public key accepted by server! */ - if (!privkey_open) { - ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s", - privkey_file); - privkey = privatekey_from_file(session, privkey_file, type, passphrase); - if (privkey == NULL) { - ssh_log(session, SSH_LOG_RARE, - "Reading private key %s failed (bad passphrase ?)", - privkey_file); - ssh_string_free(pubkey_string); - continue; /* continue the loop with other pubkey */ - } - } - - rc = ssh_userauth_pubkey(session, NULL, pubkey_string, privkey); - if (rc == SSH_AUTH_ERROR) { - ssh_string_free(pubkey_string); - privatekey_free(privkey); - leave_function(); - return rc; - } else { - if (rc != SSH_AUTH_SUCCESS){ - ssh_log(session, SSH_LOG_RARE, - "The server accepted the public key but refused the signature"); - ssh_string_free(pubkey_string); - privatekey_free(privkey); - continue; - } - } - - /* auth success */ - ssh_log(session, SSH_LOG_PROTOCOL, - "Successfully authenticated using %s", privkey_file); - ssh_string_free(pubkey_string); - privatekey_free(privkey); - - leave_function(); - return SSH_AUTH_SUCCESS; - } - - /* at this point, pubkey is NULL and so is privkeyfile */ - ssh_log(session, SSH_LOG_PROTOCOL, - "Tried every public key, none matched"); - ssh_set_error(session,SSH_NO_ERROR,"No public key matched"); - - leave_function(); - return SSH_AUTH_DENIED; -} - -struct ssh_kbdint_struct { - uint32_t nprompts; - char *name; - char *instruction; - char **prompts; - unsigned char *echo; /* bool array */ - char **answers; -}; - -static ssh_kbdint kbdint_new(void) { - ssh_kbdint kbd; - - kbd = malloc(sizeof (struct ssh_kbdint_struct)); - if (kbd == NULL) { - return NULL; - } - ZERO_STRUCTP(kbd); - - return kbd; -} - - -static void kbdint_free(ssh_kbdint kbd) { - int i, n; - - if (kbd == NULL) { - return; - } - - n = kbd->nprompts; - - SAFE_FREE(kbd->name); - SAFE_FREE(kbd->instruction); - SAFE_FREE(kbd->echo); - - if (kbd->prompts) { - for (i = 0; i < n; i++) { - BURN_STRING(kbd->prompts[i]); - SAFE_FREE(kbd->prompts[i]); - } - SAFE_FREE(kbd->prompts); - } - if (kbd->answers) { - for (i = 0; i < n; i++) { - BURN_STRING(kbd->answers[i]); - SAFE_FREE(kbd->answers[i]); - } - SAFE_FREE(kbd->answers); - } - - SAFE_FREE(kbd); -} - -static void kbdint_clean(ssh_kbdint kbd) { - int i, n; - - if (kbd == NULL) { - return; - } - - n = kbd->nprompts; - - SAFE_FREE(kbd->name); - SAFE_FREE(kbd->instruction); - SAFE_FREE(kbd->echo); - - if (kbd->prompts) { - for (i = 0; i < n; i++) { - BURN_STRING(kbd->prompts[i]); - SAFE_FREE(kbd->prompts[i]); - } - SAFE_FREE(kbd->prompts); - } - - if (kbd->answers) { - for (i = 0; i < n; i++) { - BURN_STRING(kbd->answers[i]); - SAFE_FREE(kbd->answers[i]); - } - SAFE_FREE(kbd->answers); - } - - kbd->nprompts = 0; -} - -/* this function sends the first packet as explained in section 3.1 - * of the draft */ -static int kbdauth_init(ssh_session session, const char *user, - const char *submethods) { - ssh_string usr = NULL; - ssh_string sub = NULL; - ssh_string service = NULL; - ssh_string method = NULL; - int rc = SSH_AUTH_ERROR; - - enter_function(); - - usr = ssh_string_from_char(user); - if (usr == NULL) { - goto error; - } - sub = (submethods ? ssh_string_from_char(submethods) : ssh_string_from_char("")); - if (sub == NULL) { - goto error; - } - service = ssh_string_from_char("ssh-connection"); - if (service == NULL) { - goto error; - } - method = ssh_string_from_char("keyboard-interactive"); - if (method == NULL) { - goto error; - } - - if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 || - buffer_add_ssh_string(session->out_buffer, usr) < 0 || - buffer_add_ssh_string(session->out_buffer, service) < 0 || - buffer_add_ssh_string(session->out_buffer, method) < 0 || - buffer_add_u32(session->out_buffer, 0) < 0 || - buffer_add_ssh_string(session->out_buffer, sub) < 0) { - goto error; - } - - ssh_string_free(usr); - ssh_string_free(service); - ssh_string_free(method); - ssh_string_free(sub); - session->auth_state=SSH_AUTH_STATE_KBDINT_SENT; - if (packet_send(session) == SSH_ERROR) { - leave_function(); - return rc; - } - rc = wait_auth_status(session); - - leave_function(); - return rc; -error: - buffer_reinit(session->out_buffer); - ssh_string_free(usr); - ssh_string_free(service); - ssh_string_free(method); - ssh_string_free(sub); - - leave_function(); - return rc; -} - -/** - * @internal - * @brief handles a SSH_USERAUTH_INFO_REQUEST packet, as used in - * keyboard-interactive authentication, and changes the - * authentication state. - */ -SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { - ssh_string name; /* name of the "asking" window showed to client */ - ssh_string instruction; - ssh_string tmp; - uint32_t nprompts; - uint32_t i; - (void)user; - (void)type; - enter_function(); - - name = buffer_get_ssh_string(packet); - instruction = buffer_get_ssh_string(packet); - tmp = buffer_get_ssh_string(packet); - buffer_get_u32(packet, &nprompts); - - if (name == NULL || instruction == NULL || tmp == NULL) { - ssh_string_free(name); - ssh_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_PACKET_USED; - } - ssh_string_free(tmp); - - if (session->kbdint == NULL) { - session->kbdint = kbdint_new(); - if (session->kbdint == NULL) { - ssh_set_error_oom(session); - ssh_string_free(name); - ssh_string_free(instruction); - - leave_function(); - return SSH_PACKET_USED; - } - } else { - kbdint_clean(session->kbdint); - } - - session->kbdint->name = ssh_string_to_char(name); - ssh_string_free(name); - if (session->kbdint->name == NULL) { - ssh_set_error_oom(session); - kbdint_free(session->kbdint); - leave_function(); - return SSH_PACKET_USED; - } - - session->kbdint->instruction = ssh_string_to_char(instruction); - ssh_string_free(instruction); - if (session->kbdint->instruction == NULL) { - ssh_set_error_oom(session); - kbdint_free(session->kbdint); - session->kbdint = NULL; - leave_function(); - return SSH_PACKET_USED; - } - - nprompts = ntohl(nprompts); - ssh_log(session,SSH_LOG_PACKET,"kbdint: %d prompts",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_PACKET_USED; - } - - session->kbdint->nprompts = nprompts; - session->kbdint->prompts = malloc(nprompts * sizeof(char *)); - if (session->kbdint->prompts == NULL) { - session->kbdint->nprompts = 0; - ssh_set_error_oom(session); - kbdint_free(session->kbdint); - session->kbdint = NULL; - leave_function(); - return SSH_PACKET_USED; - } - 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_oom(session); - kbdint_free(session->kbdint); - session->kbdint = NULL; - leave_function(); - return SSH_PACKET_USED; - } - memset(session->kbdint->echo, 0, nprompts); - - for (i = 0; i < nprompts; i++) { - tmp = buffer_get_ssh_string(packet); - buffer_get_u8(packet, &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_PACKET_USED; - } - session->kbdint->prompts[i] = ssh_string_to_char(tmp); - ssh_string_free(tmp); - if (session->kbdint->prompts[i] == NULL) { - ssh_set_error_oom(session); - kbdint_free(session->kbdint); - session->kbdint = NULL; - leave_function(); - return SSH_PACKET_USED; - } - } - session->auth_state=SSH_AUTH_STATE_INFO; - leave_function(); - return SSH_PACKET_USED; -} - -/** - * @internal - * @brief Sends the current challenge response and wait for a - * reply from the server - * @returns SSH_AUTH_INFO if more info is needed - * @returns SSH_AUTH_SUCCESS - * @returns SSH_AUTH_FAILURE - * @returns SSH_AUTH_PARTIAL - */ -static int kbdauth_send(ssh_session session) { - ssh_string answer = NULL; - int rc = SSH_AUTH_ERROR; - uint32_t i; - - enter_function(); - - if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_INFO_RESPONSE) < 0 || - buffer_add_u32(session->out_buffer, - htonl(session->kbdint->nprompts)) < 0) { - goto error; - } - - for (i = 0; i < session->kbdint->nprompts; i++) { - if (session->kbdint->answers[i]) { - answer = ssh_string_from_char(session->kbdint->answers[i]); - } else { - answer = ssh_string_from_char(""); - } - if (answer == NULL) { - goto error; - } - - if (buffer_add_ssh_string(session->out_buffer, answer) < 0) { - goto error; - } - - ssh_string_burn(answer); - ssh_string_free(answer); - } - session->auth_state=SSH_AUTH_STATE_KBDINT_SENT; - kbdint_free(session->kbdint); - session->kbdint = NULL; - if (packet_send(session) == SSH_ERROR) { - leave_function(); - return rc; - } - rc = wait_auth_status(session); - - leave_function(); - return rc; -error: - buffer_reinit(session->out_buffer); - ssh_string_burn(answer); - ssh_string_free(answer); - - leave_function(); - return rc; -} - -/** - * @brief Try to authenticate through the "keyboard-interactive" method. - * - * @param[in] session The ssh session to use. - * - * @param[in] 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[in] 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); - - leave_function(); - return rc; - } - - /* - * If we are at this point, it is 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); - - leave_function(); - return rc; -} - -/** - * @brief Get the number of prompts (questions) the server has given. - * - * You have called ssh_userauth_kbdint() and got SSH_AUTH_INFO. This - * function returns the questions from the server. - * - * @param[in] session The ssh session to use. - * - * @returns The number of prompts. - */ -int ssh_userauth_kbdint_getnprompts(ssh_session session) { - return session->kbdint->nprompts; -} - -/** - * @brief Get the "name" of the message block. - * - * You have called ssh_userauth_kbdint() and got SSH_AUTH_INFO. This - * function returns the questions from the server. - * - * @param[in] session The ssh session to use. - * - * @returns The name of the message block. Do not free it. - */ -const char *ssh_userauth_kbdint_getname(ssh_session session) { - return session->kbdint->name; -} - -/** - * @brief Get the "instruction" of the message block. - * - * You have called ssh_userauth_kbdint() and got SSH_AUTH_INFO. This - * function returns the questions from the server. - * - * @param[in] session The ssh session to use. - * - * @returns The instruction of the message block. - */ - -const char *ssh_userauth_kbdint_getinstruction(ssh_session session) { - return session->kbdint->instruction; -} - -/** - * @brief Get a prompt from a message block. - * - * You have called ssh_userauth_kbdint() and got SSH_AUTH_INFO. This - * function returns the questions from the server. - * - * @param[in] session The ssh session to use. - * - * @param[in] i The index number of the i'th prompt. - * - * @param[in] echo When different of NULL, it will obtain a boolean meaning - * that the resulting user input should be echoed or not - * (like passwords). - * - * @returns A pointer to the prompt. Do not free it. - */ -const char *ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i, - char *echo) { - if (i > session->kbdint->nprompts) { - return NULL; - } - - if (echo) { - *echo = session->kbdint->echo[i]; - } - - return session->kbdint->prompts[i]; -} - -/** - * @brief Set the answer for a question from a message block. - * - * If you have called ssh_userauth_kbdint() and got SSH_AUTH_INFO, this - * function returns the questions from the server. - * - * @param[in] session The ssh session to use. - * - * @param[in] i index The number of the ith prompt. - * - * @param[in] answer The answer to give to the server. - * - * @return 0 on success, < 0 on error. - */ -int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i, - const char *answer) { - if (session == NULL || answer == NULL || i > session->kbdint->nprompts) { - return -1; - } - - if (session->kbdint->answers == NULL) { - session->kbdint->answers = malloc(sizeof(char*) * session->kbdint->nprompts); - if (session->kbdint->answers == NULL) { - return -1; - } - memset(session->kbdint->answers, 0, sizeof(char *) * session->kbdint->nprompts); - } - - if (session->kbdint->answers[i]) { - BURN_STRING(session->kbdint->answers[i]); - SAFE_FREE(session->kbdint->answers[i]); - } - - session->kbdint->answers[i] = strdup(answer); - if (session->kbdint->answers[i] == NULL) { - return -1; - } - - return 0; -} - -/** @} */ - -/* vim: set ts=4 sw=4 et cindent: */ |