2005-07-05 01:21:44 +00:00
|
|
|
/*
|
2011-08-23 17:58:44 +02:00
|
|
|
* auth.c - Authentication with SSH protocols
|
2009-03-29 20:19:18 +00:00
|
|
|
*
|
|
|
|
* This file is part of the SSH Library
|
|
|
|
*
|
|
|
|
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
2011-08-23 17:58:44 +02:00
|
|
|
* Copyright (c) 2008-2011 Andreas Schneider <asn@cryptomilk.org>
|
2009-03-29 20:19:18 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2005-07-05 01:21:44 +00:00
|
|
|
|
2005-10-04 22:11:19 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
2005-07-05 01:21:44 +00:00
|
|
|
#include <string.h>
|
2008-03-12 01:27:21 +00:00
|
|
|
|
2009-06-09 12:03:00 +00:00
|
|
|
#ifndef _WIN32
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "libssh/priv.h"
|
|
|
|
#include "libssh/ssh2.h"
|
2009-09-23 23:51:04 +02:00
|
|
|
#include "libssh/buffer.h"
|
|
|
|
#include "libssh/agent.h"
|
2010-02-28 22:51:21 +01:00
|
|
|
#include "libssh/misc.h"
|
2009-09-23 23:51:04 +02:00
|
|
|
#include "libssh/packet.h"
|
|
|
|
#include "libssh/session.h"
|
2009-09-26 01:15:48 +02:00
|
|
|
#include "libssh/keys.h"
|
2009-12-26 20:24:07 +01:00
|
|
|
#include "libssh/auth.h"
|
2011-03-17 10:22:46 +01:00
|
|
|
#include "libssh/pki.h"
|
2009-06-09 12:03:00 +00:00
|
|
|
|
2011-08-23 19:01:22 +02:00
|
|
|
#include "libssh/legacy.h"
|
|
|
|
|
2010-04-04 14:33:08 +02:00
|
|
|
/**
|
|
|
|
* @defgroup libssh_auth The SSH authentication functions.
|
|
|
|
* @ingroup libssh
|
|
|
|
*
|
|
|
|
* Functions to authenticate with a server.
|
|
|
|
*
|
|
|
|
* @{
|
2006-11-12 00:14:55 +00:00
|
|
|
*/
|
|
|
|
|
2009-12-26 16:51:33 +01:00
|
|
|
/**
|
|
|
|
* @internal
|
2010-04-04 14:33:08 +02:00
|
|
|
*
|
|
|
|
* @brief Ask access to the ssh-userauth service.
|
|
|
|
*
|
|
|
|
* @param[in] session The SSH session handle.
|
|
|
|
*
|
|
|
|
* @returns SSH_OK on success, SSH_ERROR on error.
|
2011-01-16 18:05:47 +01:00
|
|
|
* @returns SSH_AGAIN on nonblocking mode, if calling that function
|
|
|
|
* again is necessary
|
2009-12-26 16:51:33 +01:00
|
|
|
*/
|
2011-08-23 16:11:46 +02:00
|
|
|
static int ssh_userauth_request_service(ssh_session session)
|
|
|
|
{
|
|
|
|
int rc = SSH_OK;
|
2009-04-30 14:00:07 +00:00
|
|
|
|
2011-08-05 03:00:21 +02:00
|
|
|
do {
|
|
|
|
rc = ssh_service_request(session,"ssh-userauth");
|
|
|
|
if (ssh_is_blocking(session)) {
|
2011-08-26 23:56:49 +02:00
|
|
|
if (rc == SSH_AGAIN) {
|
|
|
|
int err = ssh_handle_packets(session, -2);
|
|
|
|
if (err != SSH_OK) {
|
|
|
|
/* error or timeout */
|
|
|
|
return SSH_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2011-08-05 03:00:21 +02:00
|
|
|
} else {
|
|
|
|
/* nonblocking */
|
|
|
|
ssh_handle_packets(session, 0);
|
|
|
|
rc = ssh_service_request(session, "ssh-userauth");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (rc == SSH_AGAIN);
|
2011-08-23 16:11:46 +02:00
|
|
|
|
2011-08-05 03:00:21 +02:00
|
|
|
return rc;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
|
|
|
|
2011-08-23 16:42:25 +02:00
|
|
|
static int auth_status_termination(void *user) {
|
|
|
|
ssh_session session = (ssh_session) user;
|
|
|
|
|
|
|
|
switch(session->auth_state) {
|
|
|
|
case SSH_AUTH_STATE_NONE:
|
|
|
|
case SSH_AUTH_STATE_KBDINT_SENT:
|
|
|
|
return 0;
|
|
|
|
case SSH_AUTH_STATE_PARTIAL:
|
|
|
|
case SSH_AUTH_STATE_SUCCESS:
|
|
|
|
case SSH_AUTH_STATE_INFO:
|
|
|
|
case SSH_AUTH_STATE_FAILED:
|
|
|
|
case SSH_AUTH_STATE_ERROR:
|
|
|
|
case SSH_AUTH_STATE_PK_OK:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* should never been reached */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @brief Wait for a response of an authentication function.
|
|
|
|
*
|
|
|
|
* @param[in] session The SSH session.
|
|
|
|
*
|
|
|
|
* @returns SSH_AUTH_SUCCESS Authentication success, or pubkey accepted
|
|
|
|
* SSH_AUTH_PARTIAL Authentication succeeded but another mean
|
|
|
|
* of authentication is needed.
|
|
|
|
* SSH_AUTH_INFO Data for keyboard-interactive
|
|
|
|
* SSH_AUTH_AGAIN In nonblocking mode, call has to be made again
|
|
|
|
* SSH_AUTH_ERROR Error during the process.
|
|
|
|
*/
|
|
|
|
static int ssh_userauth_get_response(ssh_session session) {
|
|
|
|
int rc = SSH_AUTH_ERROR;
|
|
|
|
|
|
|
|
if (ssh_is_blocking(session)) {
|
|
|
|
rc = ssh_handle_packets_termination(session,
|
|
|
|
-2,
|
|
|
|
auth_status_termination,
|
|
|
|
session);
|
|
|
|
if (rc == SSH_ERROR) {
|
|
|
|
leave_function();
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = ssh_handle_packets(session, 0);
|
|
|
|
if (rc == SSH_ERROR) {
|
|
|
|
leave_function();
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
if (!auth_status_termination(session)){
|
|
|
|
leave_function();
|
|
|
|
return SSH_AUTH_AGAIN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-04-04 14:33:08 +02:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*
|
|
|
|
* @brief Handles a SSH_USERAUTH_BANNER packet.
|
|
|
|
*
|
2009-12-26 20:24:07 +01:00
|
|
|
* 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)
|
2010-05-14 00:51:08 +02:00
|
|
|
ssh_string_free(session->banner);
|
2009-12-26 20:24:07 +01:00
|
|
|
session->banner = banner;
|
|
|
|
}
|
|
|
|
leave_function();
|
|
|
|
return SSH_PACKET_USED;
|
|
|
|
}
|
|
|
|
|
2010-04-04 14:33:08 +02:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*
|
|
|
|
* @brief Handles a SSH_USERAUTH_FAILURE packet.
|
|
|
|
*
|
|
|
|
* This handles the complete or partial authentication failure.
|
2009-12-26 21:59:37 +01:00
|
|
|
*/
|
|
|
|
SSH_PACKET_CALLBACK(ssh_packet_userauth_failure){
|
2009-04-30 14:18:44 +00:00
|
|
|
char *auth_methods = NULL;
|
2009-07-24 21:45:41 +02:00
|
|
|
ssh_string auth;
|
2009-07-25 23:19:41 +02:00
|
|
|
uint8_t partial = 0;
|
2009-12-26 21:59:37 +01:00
|
|
|
(void) type;
|
|
|
|
(void) user;
|
2009-04-30 14:18:44 +00:00
|
|
|
enter_function();
|
|
|
|
|
2009-12-26 21:59:37 +01:00
|
|
|
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;
|
|
|
|
}
|
2009-04-30 14:18:44 +00:00
|
|
|
|
2010-05-14 00:51:08 +02:00
|
|
|
auth_methods = ssh_string_to_char(auth);
|
2009-12-26 21:59:37 +01:00
|
|
|
if (auth_methods == NULL) {
|
|
|
|
ssh_set_error_oom(session);
|
|
|
|
goto end;
|
|
|
|
}
|
2009-04-30 14:18:44 +00:00
|
|
|
|
2009-12-26 21:59:37 +01:00
|
|
|
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);
|
2009-04-30 14:18:44 +00:00
|
|
|
|
2009-12-26 21:59:37 +01:00
|
|
|
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;
|
|
|
|
}
|
2009-04-30 14:18:44 +00:00
|
|
|
|
2009-12-26 21:59:37 +01:00
|
|
|
end:
|
2010-05-14 00:51:08 +02:00
|
|
|
ssh_string_free(auth);
|
2009-12-26 21:59:37 +01:00
|
|
|
SAFE_FREE(auth_methods);
|
|
|
|
leave_function();
|
|
|
|
return SSH_PACKET_USED;
|
|
|
|
}
|
|
|
|
|
2010-04-04 14:33:08 +02:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*
|
|
|
|
* @brief Handles a SSH_USERAUTH_SUCCESS packet.
|
|
|
|
*
|
|
|
|
* It is also used to communicate the new to the upper levels.
|
2009-12-26 21:59:37 +01:00
|
|
|
*/
|
|
|
|
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;
|
2010-10-04 16:19:20 +02:00
|
|
|
if(session->current_crypto && session->current_crypto->delayed_compress_out){
|
|
|
|
ssh_log(session,SSH_LOG_PROTOCOL,"Enabling delayed compression OUT");
|
|
|
|
session->current_crypto->do_compress_out=1;
|
|
|
|
}
|
|
|
|
if(session->current_crypto && session->current_crypto->delayed_compress_in){
|
|
|
|
ssh_log(session,SSH_LOG_PROTOCOL,"Enabling delayed compression IN");
|
|
|
|
session->current_crypto->do_compress_in=1;
|
|
|
|
}
|
2009-12-26 21:59:37 +01:00
|
|
|
leave_function();
|
|
|
|
return SSH_PACKET_USED;
|
|
|
|
}
|
|
|
|
|
2010-04-04 14:33:08 +02:00
|
|
|
/**
|
|
|
|
* @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.
|
2009-12-26 21:59:37 +01:00
|
|
|
*/
|
|
|
|
SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok){
|
2010-05-19 14:07:40 +02:00
|
|
|
int rc;
|
|
|
|
enter_function();
|
2009-12-26 21:59:37 +01:00
|
|
|
ssh_log(session,SSH_LOG_PACKET,"Received SSH_USERAUTH_PK_OK/INFO_REQUEST");
|
2010-05-19 14:07:40 +02:00
|
|
|
if(session->auth_state==SSH_AUTH_STATE_KBDINT_SENT){
|
2009-12-26 21:59:37 +01:00
|
|
|
/* Assuming we are in keyboard-interactive context */
|
2010-05-19 14:07:40 +02:00
|
|
|
ssh_log(session,SSH_LOG_PACKET,"keyboard-interactive context, assuming SSH_USERAUTH_INFO_REQUEST");
|
|
|
|
rc=ssh_packet_userauth_info_request(session,type,packet,user);
|
2009-12-26 21:59:37 +01:00
|
|
|
} else {
|
|
|
|
session->auth_state=SSH_AUTH_STATE_PK_OK;
|
|
|
|
ssh_log(session,SSH_LOG_PACKET,"assuming SSH_USERAUTH_PK_OK");
|
2010-05-19 14:07:40 +02:00
|
|
|
rc=SSH_PACKET_USED;
|
2009-04-30 14:18:44 +00:00
|
|
|
}
|
2009-12-26 21:59:37 +01:00
|
|
|
leave_function();
|
2010-05-19 14:07:40 +02:00
|
|
|
return rc;
|
2009-12-26 21:59:37 +01:00
|
|
|
}
|
|
|
|
|
2011-09-02 13:58:37 +03:00
|
|
|
static int auth_status_termination(void *user){
|
|
|
|
ssh_session session=(ssh_session)user;
|
|
|
|
switch(session->auth_state){
|
|
|
|
case SSH_AUTH_STATE_NONE:
|
|
|
|
case SSH_AUTH_STATE_KBDINT_SENT:
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-19 19:51:18 +02:00
|
|
|
/**
|
2011-08-23 16:27:03 +02:00
|
|
|
* @brief Get available authentication methods from the server.
|
|
|
|
*
|
|
|
|
* This requires the function ssh_userauth_none() to be called before the
|
|
|
|
* methods are available. The server MAY return a list of methods that may
|
|
|
|
* continue.
|
|
|
|
*
|
|
|
|
* @param[in] session The SSH session.
|
|
|
|
*
|
|
|
|
* @param[in] username Deprecated, set to NULL.
|
|
|
|
*
|
|
|
|
* @returns A bitfield of the fllowing values:
|
|
|
|
* - 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.
|
|
|
|
* @see ssh_userauth_none()
|
2010-08-19 19:51:18 +02:00
|
|
|
*/
|
2011-08-23 16:27:03 +02:00
|
|
|
int ssh_userauth_list(ssh_session session, const char *username)
|
|
|
|
{
|
|
|
|
(void) username; /* unused */
|
|
|
|
|
|
|
|
if (session == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
2010-08-19 19:51:18 +02:00
|
|
|
|
2010-01-25 23:23:01 +01:00
|
|
|
#ifdef WITH_SSH1
|
2011-08-23 16:27:03 +02:00
|
|
|
if(session->version == 1) {
|
|
|
|
return SSH_AUTH_METHOD_PASSWORD;
|
|
|
|
}
|
2010-01-25 23:23:01 +01:00
|
|
|
#endif
|
2011-08-23 16:27:03 +02:00
|
|
|
|
|
|
|
return session->auth_methods;
|
2008-12-14 21:46:31 +00:00
|
|
|
}
|
|
|
|
|
2009-04-30 14:34:36 +00:00
|
|
|
/**
|
|
|
|
* @brief Try to authenticate through the "none" method.
|
|
|
|
*
|
2010-04-04 14:33:08 +02:00
|
|
|
* @param[in] session The ssh session to use.
|
2009-04-30 14:34:36 +00:00
|
|
|
*
|
2011-08-23 18:51:53 +02:00
|
|
|
* @param[in] username The username, this SHOULD be NULL.
|
2009-04-30 14:34:36 +00:00
|
|
|
*
|
|
|
|
* @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
|
2011-05-17 04:54:57 -07:00
|
|
|
* SSH_AUTH_SUCCESS: Authentication success\n
|
2011-01-16 21:57:11 +01:00
|
|
|
* SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again
|
|
|
|
* later.
|
2011-08-23 18:51:53 +02:00
|
|
|
*
|
|
|
|
* @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.
|
2006-11-12 00:14:55 +00:00
|
|
|
*/
|
2009-09-23 21:55:54 +02:00
|
|
|
int ssh_userauth_none(ssh_session session, const char *username) {
|
2011-08-23 18:51:53 +02:00
|
|
|
ssh_string str;
|
|
|
|
int rc;
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2009-07-27 23:17:35 +02:00
|
|
|
#ifdef WITH_SSH1
|
2011-08-23 18:51:53 +02:00
|
|
|
if (session->version == 1) {
|
|
|
|
return ssh_userauth1_none(session, username);
|
|
|
|
}
|
2009-04-30 14:34:36 +00:00
|
|
|
#endif
|
2011-08-23 18:51:53 +02:00
|
|
|
|
|
|
|
switch(session->pending_call_state){
|
|
|
|
case SSH_PENDING_CALL_NONE:
|
|
|
|
break;
|
|
|
|
case SSH_PENDING_CALL_AUTH_NONE:
|
|
|
|
goto pending;
|
|
|
|
default:
|
|
|
|
ssh_set_error(session,SSH_FATAL,"Bad call during pending SSH call in ssh_userauth_none");
|
|
|
|
return SSH_AUTH_ERROR;
|
2008-06-12 20:14:17 +00:00
|
|
|
}
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-23 18:51:53 +02:00
|
|
|
rc = ssh_userauth_request_service(session);
|
|
|
|
if (rc == SSH_AGAIN) {
|
|
|
|
return SSH_AUTH_AGAIN;
|
|
|
|
} else if (rc == SSH_ERROR) {
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-23 18:51:53 +02:00
|
|
|
/* request */
|
|
|
|
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-23 18:51:53 +02:00
|
|
|
/* username */
|
|
|
|
if (username) {
|
|
|
|
str = ssh_string_from_char(username);
|
|
|
|
} else {
|
|
|
|
str = ssh_string_from_char(session->username);
|
|
|
|
}
|
|
|
|
if (str == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-23 18:51:53 +02:00
|
|
|
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("none");
|
|
|
|
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_NONE;
|
|
|
|
rc = packet_send(session);
|
|
|
|
if (rc == SSH_ERROR) {
|
2011-08-23 18:44:32 +02:00
|
|
|
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 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.
|
|
|
|
*
|
2011-08-27 13:58:08 +02:00
|
|
|
* @param[in] session The SSH session.
|
2011-08-23 18:44:32 +02:00
|
|
|
*
|
|
|
|
* @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 */
|
2011-08-30 10:16:53 +02:00
|
|
|
rc = ssh_pki_export_pubkey_blob(pubkey, &str);
|
|
|
|
if (rc < 0) {
|
2011-08-23 20:19:24 +02:00
|
|
|
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 Authenticate with public/private key.
|
|
|
|
*
|
2011-08-27 13:58:08 +02:00
|
|
|
* @param[in] session The SSH session.
|
2011-08-23 20:19:24 +02:00
|
|
|
*
|
|
|
|
* @param[in] username The username, this SHOULD be NULL.
|
|
|
|
*
|
|
|
|
* @param[in] privkey The private key for authentication.
|
|
|
|
*
|
|
|
|
* @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_publickey(ssh_session session,
|
|
|
|
const char *username,
|
|
|
|
const ssh_key privkey)
|
|
|
|
{
|
|
|
|
ssh_string str;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (session == NULL) {
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (privkey == NULL || !ssh_key_is_private(privkey)) {
|
|
|
|
ssh_set_error(session, SSH_FATAL, "Invalid private key");
|
|
|
|
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;
|
2011-08-26 13:18:36 +02:00
|
|
|
case SSH_PENDING_CALL_AUTH_PUBKEY:
|
2011-08-23 20:19:24 +02:00
|
|
|
goto pending;
|
|
|
|
default:
|
|
|
|
ssh_set_error(session,
|
|
|
|
SSH_FATAL,
|
|
|
|
"Bad call during pending SSH call in ssh_userauth_try_pubkey");
|
2011-08-26 13:18:36 +02:00
|
|
|
return SSH_AUTH_ERROR;
|
2011-08-23 20:19:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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, 1);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* algo */
|
|
|
|
str = ssh_string_from_char(privkey->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 */
|
2011-08-30 10:16:53 +02:00
|
|
|
rc = ssh_pki_export_pubkey_blob(privkey, &str);
|
|
|
|
if (rc < 0) {
|
2011-08-23 20:19:24 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sign the buffer with the private key */
|
|
|
|
str = ssh_pki_do_sign(session, session->out_buffer, privkey);
|
2011-08-23 18:44:32 +02:00
|
|
|
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;
|
2011-08-26 13:18:36 +02:00
|
|
|
session->pending_call_state = SSH_PENDING_CALL_AUTH_PUBKEY;
|
2011-08-23 18:44:32 +02:00
|
|
|
rc = packet_send(session);
|
|
|
|
if (rc == SSH_ERROR) {
|
2011-08-23 18:51:53 +02:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
2009-04-30 14:34:36 +00:00
|
|
|
|
2011-01-16 21:23:50 +01:00
|
|
|
pending:
|
2011-08-23 18:51:53 +02:00
|
|
|
rc = ssh_userauth_get_response(session);
|
|
|
|
if (rc != SSH_AUTH_AGAIN) {
|
|
|
|
session->pending_call_state = SSH_PENDING_CALL_NONE;
|
|
|
|
}
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-23 18:51:53 +02:00
|
|
|
return rc;
|
|
|
|
fail:
|
|
|
|
ssh_set_error_oom(session);
|
|
|
|
buffer_reinit(session->out_buffer);
|
|
|
|
|
|
|
|
return SSH_AUTH_ERROR;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
#ifndef _WIN32
|
|
|
|
static int ssh_userauth_agent_publickey(ssh_session session,
|
|
|
|
const char *username,
|
|
|
|
ssh_key pubkey)
|
|
|
|
{
|
|
|
|
ssh_string str;
|
|
|
|
int rc;
|
2011-03-17 10:22:46 +01:00
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
switch(session->pending_call_state) {
|
|
|
|
case SSH_PENDING_CALL_NONE:
|
|
|
|
break;
|
2011-08-26 13:30:41 +02:00
|
|
|
case SSH_PENDING_CALL_AUTH_PUBKEY:
|
2011-08-23 21:28:14 +02:00
|
|
|
goto pending;
|
|
|
|
default:
|
|
|
|
ssh_set_error(session,
|
|
|
|
SSH_FATAL,
|
|
|
|
"Bad call during pending SSH call in ssh_userauth_try_pubkey");
|
|
|
|
return SSH_ERROR;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
rc = ssh_userauth_request_service(session);
|
|
|
|
if (rc == SSH_AGAIN) {
|
|
|
|
return SSH_AUTH_AGAIN;
|
|
|
|
} else if (rc == SSH_ERROR) {
|
2011-03-17 10:22:46 +01:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
/* request */
|
|
|
|
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
/* username */
|
|
|
|
if (username) {
|
|
|
|
str = ssh_string_from_char(username);
|
2011-03-17 10:22:46 +01:00
|
|
|
} else {
|
2011-08-23 21:28:14 +02:00
|
|
|
str = ssh_string_from_char(session->username);
|
|
|
|
}
|
|
|
|
if (str == NULL) {
|
|
|
|
goto fail;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
/* service */
|
|
|
|
str = ssh_string_from_char("ssh-connection");
|
|
|
|
if (str == NULL) {
|
|
|
|
goto fail;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
2011-08-23 16:11:46 +02:00
|
|
|
if (rc < 0) {
|
2011-08-23 21:28:14 +02:00
|
|
|
goto fail;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
/* method */
|
|
|
|
str = ssh_string_from_char("publickey");
|
|
|
|
if (str == NULL) {
|
|
|
|
goto fail;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
2011-08-23 21:28:14 +02:00
|
|
|
|
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
2011-08-23 21:28:14 +02:00
|
|
|
|
|
|
|
/* private key? */
|
|
|
|
rc = buffer_add_u8(session->out_buffer, 1);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
/* algo */
|
|
|
|
str = ssh_string_from_char(pubkey->type_c);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2011-03-17 10:22:46 +01:00
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
/* public key */
|
2011-08-30 10:16:53 +02:00
|
|
|
rc = ssh_pki_export_pubkey_blob(pubkey, &str);
|
|
|
|
if (rc < 0) {
|
2011-08-23 21:28:14 +02:00
|
|
|
goto fail;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sign the buffer with the private key */
|
|
|
|
str = ssh_pki_do_sign_agent(session, session->out_buffer, pubkey);
|
|
|
|
if (str == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
session->auth_state = SSH_AUTH_STATE_NONE;
|
2011-08-26 13:30:41 +02:00
|
|
|
session->pending_call_state = SSH_PENDING_CALL_AUTH_PUBKEY;
|
2011-08-23 21:28:14 +02:00
|
|
|
rc = packet_send(session);
|
|
|
|
if (rc == SSH_ERROR) {
|
|
|
|
return SSH_AUTH_ERROR;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pending:
|
2011-08-23 16:42:25 +02:00
|
|
|
rc = ssh_userauth_get_response(session);
|
2011-08-23 21:28:14 +02:00
|
|
|
if (rc != SSH_AUTH_AGAIN) {
|
2011-03-17 10:22:46 +01:00
|
|
|
session->pending_call_state = SSH_PENDING_CALL_NONE;
|
2011-08-23 21:28:14 +02:00
|
|
|
}
|
2011-03-17 10:22:46 +01:00
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
return rc;
|
|
|
|
fail:
|
|
|
|
ssh_set_error_oom(session);
|
2011-03-17 10:22:46 +01:00
|
|
|
buffer_reinit(session->out_buffer);
|
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Try to do public key authentication with ssh agent.
|
|
|
|
*
|
|
|
|
* @param[in] session The ssh session to use.
|
|
|
|
*
|
|
|
|
* @param[in] username The username, this SHOULD be NULL.
|
|
|
|
*
|
|
|
|
* @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_agent(ssh_session session,
|
|
|
|
const char *username)
|
|
|
|
{
|
|
|
|
ssh_key pubkey;
|
|
|
|
char *comment;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (session == NULL) {
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!agent_is_running(session)) {
|
|
|
|
return SSH_AUTH_DENIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pubkey = ssh_agent_get_first_ident(session, &comment);
|
|
|
|
pubkey != NULL;
|
|
|
|
pubkey = ssh_agent_get_next_ident(session, &comment)) {
|
|
|
|
ssh_log(session, SSH_LOG_RARE, "Trying identity %s", comment);
|
|
|
|
|
|
|
|
rc = ssh_userauth_try_publickey(session, username, pubkey);
|
|
|
|
if (rc == SSH_AUTH_ERROR) {
|
|
|
|
ssh_string_free_char(comment);
|
|
|
|
ssh_key_free(pubkey);
|
|
|
|
return rc;
|
|
|
|
} else if (rc != SSH_AUTH_SUCCESS) {
|
|
|
|
ssh_log(session, SSH_LOG_PROTOCOL, "Public key of %s refused by server", comment);
|
|
|
|
ssh_string_free_char(comment);
|
|
|
|
ssh_key_free(pubkey);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssh_log(session, SSH_LOG_PROTOCOL, "Public key of %s accepted by server", comment);
|
|
|
|
|
|
|
|
rc = ssh_userauth_agent_publickey(session, username, pubkey);
|
|
|
|
ssh_string_free_char(comment);
|
|
|
|
ssh_key_free(pubkey);
|
|
|
|
if (rc == SSH_AUTH_ERROR) {
|
|
|
|
return rc;
|
|
|
|
} else if (rc != SSH_AUTH_SUCCESS) {
|
|
|
|
ssh_log(session,
|
|
|
|
SSH_LOG_RARE,
|
|
|
|
"Server accepted public key but refused the signature");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SSH_AUTH_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SSH_AUTH_ERROR;
|
2011-03-17 10:22:46 +01:00
|
|
|
}
|
2011-08-23 21:28:14 +02:00
|
|
|
#endif
|
2011-03-17 10:22:46 +01:00
|
|
|
|
2011-08-25 09:44:59 +02:00
|
|
|
/**
|
|
|
|
* @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).
|
|
|
|
*
|
2011-08-27 13:58:08 +02:00
|
|
|
* @param[in] session The SSH session.
|
2011-08-25 09:44:59 +02:00
|
|
|
*
|
|
|
|
* @param[in] username The username, this SHOULD be NULL.
|
|
|
|
*
|
|
|
|
* @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.
|
|
|
|
*
|
|
|
|
* @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_publickey_auto(ssh_session session,
|
|
|
|
const char *username,
|
|
|
|
const char *passphrase)
|
|
|
|
{
|
|
|
|
struct ssh_iterator *it;
|
|
|
|
ssh_auth_callback auth_fn = NULL;
|
|
|
|
void *auth_data = NULL;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (session == NULL) {
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session->common.callbacks) {
|
|
|
|
auth_fn = session->common.callbacks->auth_function;
|
|
|
|
auth_data = session->common.callbacks->userdata;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
/* Try authentication with ssh-agent first */
|
|
|
|
rc = ssh_userauth_agent(session, username);
|
|
|
|
if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_SUCCESS) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (it = ssh_list_get_iterator(session->identity);
|
|
|
|
it != NULL;
|
|
|
|
it = it->next) {
|
|
|
|
const char *privkey_file = it->data;
|
|
|
|
char pubkey_file[1024] = {0};
|
|
|
|
ssh_key privkey = NULL;
|
|
|
|
ssh_key pubkey;
|
|
|
|
|
|
|
|
ssh_log(session,
|
|
|
|
SSH_LOG_PROTOCOL,
|
|
|
|
"Trying to authenticate with %s",
|
|
|
|
privkey_file);
|
|
|
|
|
|
|
|
snprintf(pubkey_file, sizeof(pubkey_file), "%s.pub", privkey_file);
|
|
|
|
|
|
|
|
rc = ssh_pki_import_pubkey_file(pubkey_file, &pubkey);
|
|
|
|
if (rc == SSH_ERROR) {
|
|
|
|
ssh_set_error(session,
|
|
|
|
SSH_FATAL,
|
|
|
|
"Failed to import public key: %s",
|
|
|
|
pubkey_file);
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
} else if (rc == SSH_EOF) {
|
|
|
|
/* Read the private key and save the public key to file */
|
|
|
|
rc = ssh_pki_import_privkey_file(privkey_file,
|
|
|
|
passphrase,
|
|
|
|
auth_fn,
|
|
|
|
auth_data,
|
|
|
|
&privkey);
|
|
|
|
if (rc == SSH_ERROR) {
|
|
|
|
ssh_set_error(session,
|
|
|
|
SSH_FATAL,
|
|
|
|
"Failed to read private key: %s",
|
|
|
|
privkey_file);
|
2011-08-26 13:22:09 +02:00
|
|
|
continue;
|
2011-08-25 09:44:59 +02:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
} else if (rc == SSH_EOF) {
|
|
|
|
/* If the file doesn't exist, continue */
|
|
|
|
ssh_log(session,
|
|
|
|
SSH_LOG_PACKET,
|
|
|
|
"Private key %s doesn't exist.",
|
|
|
|
privkey_file);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-08-30 10:28:57 +02:00
|
|
|
rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey);
|
|
|
|
if (rc == SSH_ERROR) {
|
2011-08-25 09:44:59 +02:00
|
|
|
ssh_key_free(privkey);
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = ssh_pki_export_pubkey_file(pubkey, pubkey_file);
|
|
|
|
if (rc == SSH_ERROR) {
|
|
|
|
ssh_log(session,
|
|
|
|
SSH_LOG_PACKET,
|
|
|
|
"Could not write public key to file: %s",
|
|
|
|
pubkey_file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = ssh_userauth_try_publickey(session, username, pubkey);
|
|
|
|
if (rc == SSH_AUTH_ERROR) {
|
|
|
|
ssh_log(session,
|
|
|
|
SSH_LOG_RARE,
|
|
|
|
"Public key authentication error for %s",
|
|
|
|
privkey_file);
|
|
|
|
ssh_key_free(privkey);
|
|
|
|
ssh_key_free(pubkey);
|
|
|
|
return rc;
|
|
|
|
} else if (rc != SSH_AUTH_SUCCESS) {
|
|
|
|
ssh_log(session,
|
|
|
|
SSH_LOG_PROTOCOL,
|
|
|
|
"Public key for %s refused by server",
|
|
|
|
privkey_file);
|
|
|
|
ssh_key_free(privkey);
|
|
|
|
ssh_key_free(pubkey);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Public key has been accepted by the server */
|
|
|
|
if (privkey == NULL) {
|
|
|
|
rc = ssh_pki_import_privkey_file(privkey_file,
|
|
|
|
passphrase,
|
|
|
|
auth_fn,
|
|
|
|
auth_data,
|
|
|
|
&privkey);
|
|
|
|
if (rc == SSH_ERROR) {
|
2011-08-26 13:22:09 +02:00
|
|
|
ssh_key_free(pubkey);
|
2011-08-25 09:44:59 +02:00
|
|
|
ssh_set_error(session,
|
|
|
|
SSH_FATAL,
|
|
|
|
"Failed to read private key: %s",
|
|
|
|
privkey_file);
|
2011-08-26 13:22:09 +02:00
|
|
|
continue;
|
2011-08-25 09:44:59 +02:00
|
|
|
} else if (rc == SSH_EOF) {
|
|
|
|
/* If the file doesn't exist, continue */
|
2011-08-26 13:22:09 +02:00
|
|
|
ssh_key_free(pubkey);
|
2011-08-25 09:44:59 +02:00
|
|
|
ssh_log(session,
|
|
|
|
SSH_LOG_PACKET,
|
|
|
|
"Private key %s doesn't exist.",
|
|
|
|
privkey_file);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = ssh_userauth_publickey(session, username, privkey);
|
|
|
|
ssh_key_free(privkey);
|
|
|
|
ssh_key_free(pubkey);
|
|
|
|
if (rc == SSH_AUTH_ERROR) {
|
|
|
|
return rc;
|
|
|
|
} else if (rc == SSH_AUTH_SUCCESS) {
|
|
|
|
ssh_log(session,
|
|
|
|
SSH_LOG_PROTOCOL,
|
|
|
|
"Successfully authenticated using %s",
|
|
|
|
privkey_file);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssh_log(session,
|
|
|
|
SSH_LOG_RARE,
|
|
|
|
"The server accepted the public key but refused the signature");
|
|
|
|
/* continue */
|
|
|
|
}
|
|
|
|
ssh_log(session,
|
|
|
|
SSH_LOG_PROTOCOL,
|
|
|
|
"Tried every public key, none matched");
|
|
|
|
|
|
|
|
return SSH_AUTH_DENIED;
|
|
|
|
}
|
|
|
|
|
2011-08-25 16:09:28 +02:00
|
|
|
/**
|
|
|
|
* @brief Try to authenticate by password.
|
|
|
|
*
|
|
|
|
* This authentication method is normally disabled on SSHv2 server. You should
|
|
|
|
* use keyboard-interactive mode.
|
|
|
|
*
|
|
|
|
* The 'password' value MUST be encoded UTF-8. It is up to the server how to
|
|
|
|
* interpret the password and validate it against the password database.
|
|
|
|
* However, if you read the password in some other encoding, you MUST convert
|
|
|
|
* the password to UTF-8.
|
|
|
|
*
|
|
|
|
* @param[in] session The ssh session to use.
|
|
|
|
*
|
|
|
|
* @param[in] username The username, this SHOULD be NULL.
|
|
|
|
*
|
2011-08-27 13:58:08 +02:00
|
|
|
* @param[in] password The password to authenticate in UTF-8.
|
2011-08-25 16:09:28 +02:00
|
|
|
*
|
|
|
|
* @returns A bitfield of the fllowing values:
|
|
|
|
* - SSH_AUTH_METHOD_PASSWORD
|
|
|
|
* - SSH_AUTH_METHOD_PUBLICKEY
|
|
|
|
* - SSH_AUTH_METHOD_HOSTBASED
|
|
|
|
* - SSH_AUTH_METHOD_INTERACTIVE
|
|
|
|
*
|
|
|
|
* @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.
|
|
|
|
*
|
|
|
|
* @see ssh_userauth_none()
|
|
|
|
* @see ssh_userauth_kbdint()
|
|
|
|
*/
|
|
|
|
int ssh_userauth_password(ssh_session session,
|
|
|
|
const char *username,
|
|
|
|
const char *password) {
|
|
|
|
ssh_string str;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
#ifdef WITH_SSH1
|
|
|
|
if (session->version == 1) {
|
|
|
|
rc = ssh_userauth1_password(session, username, password);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
#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("password");
|
|
|
|
if (str == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FALSE */
|
|
|
|
rc = buffer_add_u8(session->out_buffer, 0);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* password */
|
|
|
|
str = ssh_string_from_char(password);
|
|
|
|
if (rc < 0) {
|
|
|
|
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;
|
|
|
|
}
|
2011-08-25 09:44:59 +02:00
|
|
|
|
2011-08-25 16:09:28 +02:00
|
|
|
return rc;
|
|
|
|
fail:
|
|
|
|
ssh_set_error_oom(session);
|
|
|
|
buffer_reinit(session->out_buffer);
|
|
|
|
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
2009-12-30 12:02:36 +08:00
|
|
|
|
2009-02-06 13:37:43 +00:00
|
|
|
#ifndef _WIN32
|
2011-08-25 16:14:29 +02:00
|
|
|
/* LEGACY */
|
2011-08-23 21:28:14 +02:00
|
|
|
int ssh_userauth_agent_pubkey(ssh_session session,
|
|
|
|
const char *username,
|
|
|
|
ssh_public_key publickey)
|
|
|
|
{
|
|
|
|
ssh_key key;
|
|
|
|
int rc;
|
2009-02-06 09:46:10 +00:00
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
key = ssh_key_new();
|
|
|
|
if (key == NULL) {
|
|
|
|
return SSH_AUTH_ERROR;
|
2009-04-07 13:40:40 +00:00
|
|
|
}
|
2009-04-30 14:51:53 +00:00
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
key->type = publickey->type;
|
|
|
|
key->type_c = ssh_key_type_to_char(key->type);
|
|
|
|
key->flags = SSH_KEY_FLAG_PUBLIC;
|
|
|
|
key->dsa = publickey->dsa_pub;
|
|
|
|
key->rsa = publickey->rsa_pub;
|
2009-04-30 14:51:53 +00:00
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
rc = ssh_userauth_agent_publickey(session, username, key);
|
2009-02-06 09:46:10 +00:00
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
key->dsa = NULL;
|
|
|
|
key->rsa = NULL;
|
|
|
|
ssh_key_free(key);
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-23 21:28:14 +02:00
|
|
|
return rc;
|
2009-02-06 09:46:10 +00:00
|
|
|
}
|
2009-02-06 12:51:37 +00:00
|
|
|
#endif /* _WIN32 */
|
2009-02-06 09:46:10 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
ssh_kbdint ssh_kbdint_new(void) {
|
|
|
|
ssh_kbdint kbd;
|
2009-04-01 10:05:15 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
kbd = malloc(sizeof(struct ssh_kbdint_struct));
|
|
|
|
if (kbd == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ZERO_STRUCTP(kbd);
|
2009-04-29 09:53:55 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
return kbd;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
void ssh_kbdint_free(ssh_kbdint kbd) {
|
|
|
|
int i, n;
|
2009-04-29 09:57:12 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
if (kbd == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2009-04-29 09:57:12 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
SAFE_FREE(kbd->name);
|
|
|
|
SAFE_FREE(kbd->instruction);
|
|
|
|
SAFE_FREE(kbd->echo);
|
2009-04-29 09:57:12 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
n = kbd->nprompts;
|
|
|
|
if (kbd->prompts) {
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
BURN_STRING(kbd->prompts[i]);
|
|
|
|
SAFE_FREE(kbd->prompts[i]);
|
|
|
|
}
|
|
|
|
SAFE_FREE(kbd->prompts);
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
2011-02-08 00:40:18 +01:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
n = kbd->nanswers;
|
|
|
|
if (kbd->answers) {
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
BURN_STRING(kbd->answers[i]);
|
|
|
|
SAFE_FREE(kbd->answers[i]);
|
|
|
|
}
|
|
|
|
SAFE_FREE(kbd->answers);
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
2009-04-29 09:57:12 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
SAFE_FREE(kbd);
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
2008-12-14 21:46:31 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
void ssh_kbdint_clean(ssh_kbdint kbd) {
|
|
|
|
int i, n;
|
2009-04-29 10:04:32 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
if (kbd == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2009-04-29 10:04:32 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
SAFE_FREE(kbd->name);
|
|
|
|
SAFE_FREE(kbd->instruction);
|
|
|
|
SAFE_FREE(kbd->echo);
|
2009-04-29 10:04:32 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
n = kbd->nprompts;
|
|
|
|
if (kbd->prompts) {
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
BURN_STRING(kbd->prompts[i]);
|
|
|
|
SAFE_FREE(kbd->prompts[i]);
|
|
|
|
}
|
|
|
|
SAFE_FREE(kbd->prompts);
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
2009-04-29 10:04:32 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
n = kbd->nanswers;
|
2011-02-08 00:40:18 +01:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
if (kbd->answers) {
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
BURN_STRING(kbd->answers[i]);
|
|
|
|
SAFE_FREE(kbd->answers[i]);
|
|
|
|
}
|
|
|
|
SAFE_FREE(kbd->answers);
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
2009-04-29 10:04:32 +00:00
|
|
|
|
2011-08-25 16:26:12 +02:00
|
|
|
kbd->nprompts = 0;
|
|
|
|
kbd->nanswers = 0;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
|
|
|
|
2011-08-25 16:41:14 +02:00
|
|
|
/*
|
|
|
|
* This function sends the first packet as explained in RFC 3066 section 3.1.
|
|
|
|
*/
|
|
|
|
static int ssh_userauth_kbdint_init(ssh_session session,
|
|
|
|
const char *username,
|
|
|
|
const char *submethods)
|
|
|
|
{
|
|
|
|
ssh_string str;
|
|
|
|
int rc;
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-25 16:41:14 +02:00
|
|
|
rc = ssh_userauth_request_service(session);
|
2011-08-26 13:31:23 +02:00
|
|
|
if (rc != SSH_OK) {
|
2011-08-25 16:41:14 +02:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-25 16:41:14 +02:00
|
|
|
/* request */
|
|
|
|
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-25 16:41:14 +02:00
|
|
|
/* username */
|
|
|
|
if (username) {
|
|
|
|
str = ssh_string_from_char(username);
|
|
|
|
} else {
|
|
|
|
str = ssh_string_from_char(session->username);
|
|
|
|
}
|
|
|
|
if (str == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-25 16:41:14 +02:00
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-25 16:41:14 +02:00
|
|
|
/* service */
|
|
|
|
str = ssh_string_from_char("ssh-connection");
|
|
|
|
if (str == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2009-04-07 13:40:40 +00:00
|
|
|
|
2011-08-25 16:41:14 +02:00
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* method */
|
|
|
|
str = ssh_string_from_char("keyboard-interactive");
|
|
|
|
if (str == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* lang string (ignore it) */
|
2011-08-26 13:31:23 +02:00
|
|
|
str = ssh_string_from_char("");
|
|
|
|
if (str == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
2011-08-25 16:41:14 +02:00
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* submethods */
|
2011-08-26 09:00:39 +02:00
|
|
|
if (submethods == NULL) {
|
|
|
|
submethods = "";
|
|
|
|
}
|
|
|
|
|
2011-08-25 16:41:14 +02:00
|
|
|
str = ssh_string_from_char(submethods);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, str);
|
|
|
|
ssh_string_free(str);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2011-08-26 13:31:23 +02:00
|
|
|
session->auth_state = SSH_AUTH_STATE_KBDINT_SENT;
|
2011-08-25 16:41:14 +02:00
|
|
|
rc = packet_send(session);
|
|
|
|
if (rc == SSH_ERROR) {
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = ssh_userauth_get_response(session);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
fail:
|
|
|
|
ssh_set_error_oom(session);
|
|
|
|
buffer_reinit(session->out_buffer);
|
|
|
|
|
|
|
|
return SSH_AUTH_ERROR;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
|
|
|
|
2011-08-28 12:54:49 +02:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*
|
|
|
|
* @brief Send 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 ssh_userauth_kbdint_send(ssh_session session)
|
|
|
|
{
|
|
|
|
ssh_string answer;
|
|
|
|
uint32_t i;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_INFO_RESPONSE);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = buffer_add_u32(session->out_buffer, htonl(session->kbdint->nprompts));
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < session->kbdint->nprompts; i++) {
|
|
|
|
if (session->kbdint->answers && session->kbdint->answers[i]) {
|
|
|
|
answer = ssh_string_from_char(session->kbdint->answers[i]);
|
|
|
|
} else {
|
|
|
|
answer = ssh_string_from_char("");
|
|
|
|
}
|
|
|
|
if (answer == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = buffer_add_ssh_string(session->out_buffer, answer);
|
|
|
|
string_burn(answer);
|
|
|
|
string_free(answer);
|
|
|
|
if (rc < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
session->auth_state = SSH_AUTH_STATE_KBDINT_SENT;
|
|
|
|
ssh_kbdint_free(session->kbdint);
|
|
|
|
session->kbdint = NULL;
|
|
|
|
|
|
|
|
rc = packet_send(session);
|
|
|
|
if (rc == SSH_ERROR) {
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = ssh_userauth_get_response(session);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
fail:
|
|
|
|
ssh_set_error_oom(session);
|
|
|
|
buffer_reinit(session->out_buffer);
|
|
|
|
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
|
2010-05-19 14:07:40 +02:00
|
|
|
/**
|
|
|
|
* @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) {
|
2009-07-24 21:45:41 +02:00
|
|
|
ssh_string name; /* name of the "asking" window showed to client */
|
|
|
|
ssh_string instruction;
|
|
|
|
ssh_string tmp;
|
2009-07-25 23:19:41 +02:00
|
|
|
uint32_t nprompts;
|
|
|
|
uint32_t i;
|
2010-05-19 14:07:40 +02:00
|
|
|
(void)user;
|
|
|
|
(void)type;
|
2009-04-29 10:22:59 +00:00
|
|
|
enter_function();
|
|
|
|
|
2010-05-19 14:07:40 +02:00
|
|
|
name = buffer_get_ssh_string(packet);
|
|
|
|
instruction = buffer_get_ssh_string(packet);
|
|
|
|
tmp = buffer_get_ssh_string(packet);
|
|
|
|
buffer_get_u32(packet, &nprompts);
|
2009-04-29 10:22:59 +00:00
|
|
|
|
|
|
|
if (name == NULL || instruction == NULL || tmp == NULL) {
|
2010-05-14 00:51:08 +02:00
|
|
|
ssh_string_free(name);
|
|
|
|
ssh_string_free(instruction);
|
2009-04-29 10:22:59 +00:00
|
|
|
/* tmp if empty if we got here */
|
|
|
|
ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg");
|
|
|
|
leave_function();
|
2010-05-19 14:07:40 +02:00
|
|
|
return SSH_PACKET_USED;
|
2009-04-29 10:22:59 +00:00
|
|
|
}
|
2010-05-14 00:51:08 +02:00
|
|
|
ssh_string_free(tmp);
|
2009-04-29 10:22:59 +00:00
|
|
|
|
|
|
|
if (session->kbdint == NULL) {
|
2011-08-25 16:26:12 +02:00
|
|
|
session->kbdint = ssh_kbdint_new();
|
2009-04-29 10:22:59 +00:00
|
|
|
if (session->kbdint == NULL) {
|
2010-05-19 14:07:40 +02:00
|
|
|
ssh_set_error_oom(session);
|
2010-05-14 00:51:08 +02:00
|
|
|
ssh_string_free(name);
|
|
|
|
ssh_string_free(instruction);
|
2009-04-29 10:22:59 +00:00
|
|
|
|
2009-04-01 10:05:15 +00:00
|
|
|
leave_function();
|
2010-05-19 14:07:40 +02:00
|
|
|
return SSH_PACKET_USED;
|
2009-04-01 10:05:15 +00:00
|
|
|
}
|
2009-04-29 10:22:59 +00:00
|
|
|
} else {
|
2011-08-25 16:26:12 +02:00
|
|
|
ssh_kbdint_clean(session->kbdint);
|
2009-04-29 10:22:59 +00:00
|
|
|
}
|
|
|
|
|
2010-05-14 00:51:08 +02:00
|
|
|
session->kbdint->name = ssh_string_to_char(name);
|
|
|
|
ssh_string_free(name);
|
2009-04-29 10:22:59 +00:00
|
|
|
if (session->kbdint->name == NULL) {
|
2010-05-19 14:07:40 +02:00
|
|
|
ssh_set_error_oom(session);
|
2011-08-25 16:26:12 +02:00
|
|
|
ssh_kbdint_free(session->kbdint);
|
2009-04-29 10:22:59 +00:00
|
|
|
leave_function();
|
2010-05-19 14:07:40 +02:00
|
|
|
return SSH_PACKET_USED;
|
2009-04-29 10:22:59 +00:00
|
|
|
}
|
|
|
|
|
2010-05-14 00:51:08 +02:00
|
|
|
session->kbdint->instruction = ssh_string_to_char(instruction);
|
|
|
|
ssh_string_free(instruction);
|
2009-04-29 10:22:59 +00:00
|
|
|
if (session->kbdint->instruction == NULL) {
|
2010-05-19 14:07:40 +02:00
|
|
|
ssh_set_error_oom(session);
|
2011-08-25 16:26:12 +02:00
|
|
|
ssh_kbdint_free(session->kbdint);
|
2009-04-29 10:22:59 +00:00
|
|
|
session->kbdint = NULL;
|
|
|
|
leave_function();
|
2010-05-19 14:07:40 +02:00
|
|
|
return SSH_PACKET_USED;
|
2009-04-29 10:22:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nprompts = ntohl(nprompts);
|
2010-05-19 14:07:40 +02:00
|
|
|
ssh_log(session,SSH_LOG_PACKET,"kbdint: %d prompts",nprompts);
|
2009-04-29 10:22:59 +00:00
|
|
|
if (nprompts > KBDINT_MAX_PROMPT) {
|
|
|
|
ssh_set_error(session, SSH_FATAL,
|
|
|
|
"Too much prompt asked from server: %u (0x%.4x)",
|
|
|
|
nprompts, nprompts);
|
2011-08-25 16:26:12 +02:00
|
|
|
ssh_kbdint_free(session->kbdint);
|
2009-04-29 10:22:59 +00:00
|
|
|
session->kbdint = NULL;
|
|
|
|
leave_function();
|
2010-05-19 14:07:40 +02:00
|
|
|
return SSH_PACKET_USED;
|
2009-04-29 10:22:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
session->kbdint->nprompts = nprompts;
|
2011-02-13 11:03:24 +01:00
|
|
|
session->kbdint->nanswers = nprompts;
|
2009-04-29 10:22:59 +00:00
|
|
|
session->kbdint->prompts = malloc(nprompts * sizeof(char *));
|
|
|
|
if (session->kbdint->prompts == NULL) {
|
|
|
|
session->kbdint->nprompts = 0;
|
2010-05-19 14:07:40 +02:00
|
|
|
ssh_set_error_oom(session);
|
2011-08-25 16:26:12 +02:00
|
|
|
ssh_kbdint_free(session->kbdint);
|
2009-04-29 10:22:59 +00:00
|
|
|
session->kbdint = NULL;
|
|
|
|
leave_function();
|
2010-05-19 14:07:40 +02:00
|
|
|
return SSH_PACKET_USED;
|
2009-04-29 10:22:59 +00:00
|
|
|
}
|
|
|
|
memset(session->kbdint->prompts, 0, nprompts * sizeof(char *));
|
|
|
|
|
|
|
|
session->kbdint->echo = malloc(nprompts);
|
|
|
|
if (session->kbdint->echo == NULL) {
|
|
|
|
session->kbdint->nprompts = 0;
|
2010-05-19 14:07:40 +02:00
|
|
|
ssh_set_error_oom(session);
|
2011-08-25 16:26:12 +02:00
|
|
|
ssh_kbdint_free(session->kbdint);
|
2009-04-29 10:22:59 +00:00
|
|
|
session->kbdint = NULL;
|
|
|
|
leave_function();
|
2010-05-19 14:07:40 +02:00
|
|
|
return SSH_PACKET_USED;
|
2009-04-29 10:22:59 +00:00
|
|
|
}
|
|
|
|
memset(session->kbdint->echo, 0, nprompts);
|
|
|
|
|
|
|
|
for (i = 0; i < nprompts; i++) {
|
2010-05-19 14:07:40 +02:00
|
|
|
tmp = buffer_get_ssh_string(packet);
|
|
|
|
buffer_get_u8(packet, &session->kbdint->echo[i]);
|
2009-04-29 10:22:59 +00:00
|
|
|
if (tmp == NULL) {
|
|
|
|
ssh_set_error(session, SSH_FATAL, "Short INFO_REQUEST packet");
|
2011-08-25 16:26:12 +02:00
|
|
|
ssh_kbdint_free(session->kbdint);
|
2009-04-29 10:22:59 +00:00
|
|
|
session->kbdint = NULL;
|
2009-04-01 10:05:15 +00:00
|
|
|
leave_function();
|
2010-05-19 14:07:40 +02:00
|
|
|
return SSH_PACKET_USED;
|
2009-04-01 10:05:15 +00:00
|
|
|
}
|
2010-05-14 00:51:08 +02:00
|
|
|
session->kbdint->prompts[i] = ssh_string_to_char(tmp);
|
|
|
|
ssh_string_free(tmp);
|
2009-04-29 10:22:59 +00:00
|
|
|
if (session->kbdint->prompts[i] == NULL) {
|
2010-05-19 14:07:40 +02:00
|
|
|
ssh_set_error_oom(session);
|
2011-02-08 00:40:18 +01:00
|
|
|
session->kbdint->nprompts = i;
|
2011-08-25 16:26:12 +02:00
|
|
|
ssh_kbdint_free(session->kbdint);
|
2009-04-29 10:22:59 +00:00
|
|
|
session->kbdint = NULL;
|
|
|
|
leave_function();
|
2010-05-19 14:07:40 +02:00
|
|
|
return SSH_PACKET_USED;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
2009-04-29 10:22:59 +00:00
|
|
|
}
|
2010-05-19 14:07:40 +02:00
|
|
|
session->auth_state=SSH_AUTH_STATE_INFO;
|
2009-04-29 10:22:59 +00:00
|
|
|
leave_function();
|
2010-05-19 14:07:40 +02:00
|
|
|
return SSH_PACKET_USED;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
|
|
|
|
2009-04-29 10:46:45 +00:00
|
|
|
/**
|
|
|
|
* @brief Try to authenticate through the "keyboard-interactive" method.
|
|
|
|
*
|
2010-04-04 14:33:08 +02:00
|
|
|
* @param[in] session The ssh session to use.
|
2009-04-29 10:46:45 +00:00
|
|
|
*
|
2010-04-04 14:33:08 +02:00
|
|
|
* @param[in] user The username to authenticate. You can specify NULL if
|
2009-04-29 10:46:45 +00:00
|
|
|
* ssh_option_set_username() has been used. You cannot try
|
|
|
|
* two different logins in a row.
|
|
|
|
*
|
2010-04-04 14:33:08 +02:00
|
|
|
* @param[in] submethods Undocumented. Set it to NULL.
|
2009-04-29 10:46:45 +00:00
|
|
|
*
|
|
|
|
* @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
|
2011-05-17 04:54:57 -07:00
|
|
|
* ssh_userauth_kbdint_getnprompts() and such.\n
|
|
|
|
* SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again
|
|
|
|
* later.
|
2009-04-29 10:46:45 +00:00
|
|
|
*
|
|
|
|
* @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()
|
2006-11-12 00:14:55 +00:00
|
|
|
*/
|
2009-09-23 21:55:54 +02:00
|
|
|
int ssh_userauth_kbdint(ssh_session session, const char *user,
|
2009-04-29 10:46:45 +00:00
|
|
|
const char *submethods) {
|
2011-08-26 13:31:23 +02:00
|
|
|
int rc = SSH_AUTH_ERROR;
|
2009-04-29 10:46:45 +00:00
|
|
|
|
2011-08-26 13:31:23 +02:00
|
|
|
if (session == NULL) {
|
|
|
|
return SSH_AUTH_ERROR;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
2009-04-29 10:46:45 +00:00
|
|
|
|
2011-08-26 13:31:23 +02:00
|
|
|
#ifdef WITH_SSH1
|
|
|
|
if (session->version == 1) {
|
|
|
|
return SSH_AUTH_DENIED;
|
2009-04-29 10:46:45 +00:00
|
|
|
}
|
2011-08-26 13:31:23 +02:00
|
|
|
#endif
|
2009-04-29 10:46:45 +00:00
|
|
|
|
2011-08-26 13:31:23 +02:00
|
|
|
if (session->kbdint == NULL) {
|
|
|
|
rc = ssh_userauth_kbdint_init(session, user, submethods);
|
2009-04-29 10:46:45 +00:00
|
|
|
|
2011-08-26 13:31:23 +02:00
|
|
|
return rc;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* 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).
|
|
|
|
*/
|
2011-08-28 12:54:49 +02:00
|
|
|
rc = ssh_userauth_kbdint_send(session);
|
2009-04-29 10:46:45 +00:00
|
|
|
|
2011-08-26 13:31:23 +02:00
|
|
|
return rc;
|
|
|
|
}
|
2009-04-29 10:46:45 +00:00
|
|
|
|
2011-08-26 13:31:23 +02:00
|
|
|
return SSH_AUTH_DENIED;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
|
|
|
|
2009-04-29 10:50:47 +00:00
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*
|
2010-04-04 14:33:08 +02:00
|
|
|
* @param[in] session The ssh session to use.
|
2009-04-29 10:50:47 +00:00
|
|
|
*
|
|
|
|
* @returns The number of prompts.
|
2006-11-12 00:14:55 +00:00
|
|
|
*/
|
2009-09-23 21:55:54 +02:00
|
|
|
int ssh_userauth_kbdint_getnprompts(ssh_session session) {
|
2011-02-12 19:35:53 +01:00
|
|
|
if(session==NULL)
|
|
|
|
return SSH_ERROR;
|
|
|
|
if(session->kbdint == NULL) {
|
|
|
|
ssh_set_error_invalid(session, __FUNCTION__);
|
|
|
|
return SSH_ERROR;
|
|
|
|
}
|
2009-04-29 10:50:47 +00:00
|
|
|
return session->kbdint->nprompts;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
|
|
|
|
2009-04-29 10:50:47 +00:00
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*
|
2010-04-04 14:33:08 +02:00
|
|
|
* @param[in] session The ssh session to use.
|
2009-04-29 10:50:47 +00:00
|
|
|
*
|
|
|
|
* @returns The name of the message block. Do not free it.
|
2006-11-12 00:14:55 +00:00
|
|
|
*/
|
2009-09-23 21:55:54 +02:00
|
|
|
const char *ssh_userauth_kbdint_getname(ssh_session session) {
|
2011-02-12 19:35:53 +01:00
|
|
|
if(session==NULL)
|
|
|
|
return NULL;
|
|
|
|
if(session->kbdint == NULL) {
|
|
|
|
ssh_set_error_invalid(session, __FUNCTION__);
|
2010-10-20 14:47:11 +02:00
|
|
|
return NULL;
|
2011-02-12 19:35:53 +01:00
|
|
|
}
|
2009-04-29 10:50:47 +00:00
|
|
|
return session->kbdint->name;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
|
|
|
|
2009-04-29 10:50:47 +00:00
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*
|
2010-04-04 14:33:08 +02:00
|
|
|
* @param[in] session The ssh session to use.
|
2009-04-29 10:50:47 +00:00
|
|
|
*
|
|
|
|
* @returns The instruction of the message block.
|
2006-11-12 00:14:55 +00:00
|
|
|
*/
|
|
|
|
|
2009-09-23 21:55:54 +02:00
|
|
|
const char *ssh_userauth_kbdint_getinstruction(ssh_session session) {
|
2011-02-12 19:35:53 +01:00
|
|
|
if(session==NULL)
|
|
|
|
return NULL;
|
|
|
|
if(session->kbdint == NULL) {
|
|
|
|
ssh_set_error_invalid(session, __FUNCTION__);
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-04-29 10:50:47 +00:00
|
|
|
return session->kbdint->instruction;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
|
|
|
|
2009-04-29 10:53:23 +00:00
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*
|
2010-04-04 14:33:08 +02:00
|
|
|
* @param[in] session The ssh session to use.
|
2009-04-29 10:53:23 +00:00
|
|
|
*
|
2010-04-04 14:33:08 +02:00
|
|
|
* @param[in] i The index number of the i'th prompt.
|
2009-04-29 10:53:23 +00:00
|
|
|
*
|
2010-04-04 14:33:08 +02:00
|
|
|
* @param[in] echo When different of NULL, it will obtain a boolean meaning
|
2009-04-29 10:53:23 +00:00
|
|
|
* that the resulting user input should be echoed or not
|
|
|
|
* (like passwords).
|
|
|
|
*
|
|
|
|
* @returns A pointer to the prompt. Do not free it.
|
2006-11-12 00:14:55 +00:00
|
|
|
*/
|
2009-09-23 21:55:54 +02:00
|
|
|
const char *ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i,
|
2009-04-29 10:53:23 +00:00
|
|
|
char *echo) {
|
2011-02-12 19:35:53 +01:00
|
|
|
if(session==NULL)
|
2010-10-20 14:47:11 +02:00
|
|
|
return NULL;
|
2011-02-12 19:35:53 +01:00
|
|
|
if(session->kbdint == NULL) {
|
|
|
|
ssh_set_error_invalid(session, __FUNCTION__);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (i > session->kbdint->nprompts) {
|
|
|
|
ssh_set_error_invalid(session, __FUNCTION__);
|
2009-04-29 10:53:23 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (echo) {
|
|
|
|
*echo = session->kbdint->echo[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return session->kbdint->prompts[i];
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
|
|
|
|
2011-02-08 00:40:18 +01:00
|
|
|
#ifdef WITH_SERVER
|
|
|
|
/**
|
|
|
|
* @brief Get the number of answers the client has given.
|
|
|
|
*
|
|
|
|
* @param[in] session The ssh session to use.
|
|
|
|
*
|
|
|
|
* @returns The number of answers.
|
|
|
|
*/
|
|
|
|
int ssh_userauth_kbdint_getnanswers(ssh_session session) {
|
|
|
|
if(session==NULL || session->kbdint == NULL)
|
|
|
|
return SSH_ERROR;
|
|
|
|
return session->kbdint->nanswers;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get the answer for a question from a message block.
|
|
|
|
*
|
|
|
|
* @param[in] session The ssh session to use.
|
|
|
|
*
|
|
|
|
* @param[in] i index The number of the ith answer.
|
|
|
|
*
|
|
|
|
* @return 0 on success, < 0 on error.
|
|
|
|
*/
|
|
|
|
const char *ssh_userauth_kbdint_getanswer(ssh_session session, unsigned int i) {
|
2011-05-02 17:30:43 +02:00
|
|
|
if(session==NULL || session->kbdint == NULL
|
|
|
|
|| session->kbdint->answers == NULL) {
|
2011-02-08 00:40:18 +01:00
|
|
|
return NULL;
|
2011-05-02 17:30:43 +02:00
|
|
|
}
|
2011-02-08 00:40:18 +01:00
|
|
|
if (i > session->kbdint->nanswers) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return session->kbdint->answers[i];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-04-04 14:33:08 +02:00
|
|
|
/**
|
|
|
|
* @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.
|
2006-11-12 00:14:55 +00:00
|
|
|
*/
|
2009-09-23 21:55:54 +02:00
|
|
|
int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
|
2009-04-02 09:24:46 +00:00
|
|
|
const char *answer) {
|
2011-02-12 19:35:53 +01:00
|
|
|
if (session == NULL)
|
|
|
|
return -1;
|
|
|
|
if (answer == NULL || session->kbdint == NULL ||
|
2010-10-20 14:47:11 +02:00
|
|
|
i > session->kbdint->nprompts) {
|
2011-02-12 19:35:53 +01:00
|
|
|
ssh_set_error_invalid(session, __FUNCTION__);
|
2009-04-02 09:24:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2006-11-12 00:14:55 +00:00
|
|
|
|
2009-04-02 09:24:46 +00:00
|
|
|
if (session->kbdint->answers == NULL) {
|
|
|
|
session->kbdint->answers = malloc(sizeof(char*) * session->kbdint->nprompts);
|
2009-04-01 10:05:15 +00:00
|
|
|
if (session->kbdint->answers == NULL) {
|
2011-02-12 19:35:53 +01:00
|
|
|
ssh_set_error_oom(session);
|
2009-04-02 09:24:46 +00:00
|
|
|
return -1;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
2009-04-02 09:24:46 +00:00
|
|
|
memset(session->kbdint->answers, 0, sizeof(char *) * session->kbdint->nprompts);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session->kbdint->answers[i]) {
|
2009-04-30 14:07:33 +00:00
|
|
|
BURN_STRING(session->kbdint->answers[i]);
|
2009-04-02 09:24:46 +00:00
|
|
|
SAFE_FREE(session->kbdint->answers[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
session->kbdint->answers[i] = strdup(answer);
|
|
|
|
if (session->kbdint->answers[i] == NULL) {
|
2011-02-12 19:35:53 +01:00
|
|
|
ssh_set_error_oom(session);
|
2009-04-02 09:24:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2005-07-05 01:21:44 +00:00
|
|
|
}
|
2006-11-12 00:14:55 +00:00
|
|
|
|
2010-08-28 21:32:08 +02:00
|
|
|
/** @} */
|
2010-04-04 14:33:08 +02:00
|
|
|
|
|
|
|
/* vim: set ts=4 sw=4 et cindent: */
|