2007-02-02 23:23:36 +00:00
|
|
|
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
2004-12-07 21:17:20 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms,
|
|
|
|
* with or without modification, are permitted provided
|
|
|
|
* that the following conditions are met:
|
|
|
|
*
|
|
|
|
* Redistributions of source code must retain the above
|
|
|
|
* copyright notice, this list of conditions and the
|
|
|
|
* following disclaimer.
|
|
|
|
*
|
|
|
|
* Redistributions in binary form must reproduce the above
|
|
|
|
* copyright notice, this list of conditions and the following
|
|
|
|
* disclaimer in the documentation and/or other materials
|
|
|
|
* provided with the distribution.
|
|
|
|
*
|
|
|
|
* Neither the name of the copyright holder nor the names
|
|
|
|
* of any other contributors may be used to endorse or
|
|
|
|
* promote products derived from this software without
|
|
|
|
* specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
|
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
|
|
* OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "libssh2_priv.h"
|
2005-03-21 21:26:08 +00:00
|
|
|
|
2006-11-13 11:33:03 +00:00
|
|
|
#include <ctype.h>
|
2007-01-15 21:12:00 +00:00
|
|
|
#include <stdio.h>
|
2006-11-13 11:33:03 +00:00
|
|
|
|
2005-03-21 21:26:08 +00:00
|
|
|
/* Needed for struct iovec on some platforms */
|
|
|
|
#ifdef HAVE_SYS_UIO_H
|
|
|
|
#include <sys/uio.h>
|
|
|
|
#endif
|
|
|
|
|
2004-12-07 21:17:20 +00:00
|
|
|
|
|
|
|
/* {{{ proto libssh2_userauth_list
|
|
|
|
* List authentication methods
|
|
|
|
* Will yield successful login if "none" happens to be allowable for this user
|
|
|
|
* Not a common configuration for any SSH server though
|
|
|
|
* username should be NULL, or a null terminated string
|
|
|
|
*/
|
2006-11-04 19:30:31 +00:00
|
|
|
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2007-05-28 17:56:08 +00:00
|
|
|
static const unsigned char reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
|
2007-06-06 12:34:06 +00:00
|
|
|
/* packet_type(1) + username_len(4) + service_len(4) +
|
|
|
|
service(14)"ssh-connection" + method_len(4) + method(4)"none" */
|
2007-05-28 17:56:08 +00:00
|
|
|
unsigned long methods_len;
|
2007-06-06 12:34:06 +00:00
|
|
|
unsigned char *s;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (session->userauth_state == libssh2_NB_state_idle) {
|
|
|
|
/* Zero the whole thing out */
|
|
|
|
memset(&session->userauth_packet_requirev_state, 0, sizeof(session->userauth_packet_requirev_state));
|
|
|
|
|
|
|
|
session->userauth_data_len = username_len + 31;
|
|
|
|
|
|
|
|
s = session->userauth_data = LIBSSH2_ALLOC(session, session->userauth_data_len);
|
|
|
|
if (!session->userauth_data) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth_list", 0);
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
*(s++) = SSH_MSG_USERAUTH_REQUEST;
|
|
|
|
libssh2_htonu32(s, username_len); s += 4;
|
|
|
|
if (username) {
|
|
|
|
memcpy(s, username, username_len); s += username_len;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(s, 14); s += 4;
|
|
|
|
memcpy(s, "ssh-connection", 14); s += 14;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(s, 4); s += 4;
|
|
|
|
memcpy(s, "none", 4); s += 4;
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_created;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_state == libssh2_NB_state_created) {
|
|
|
|
rc = libssh2_packet_write(session, session->userauth_data, session->userauth_data_len);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block requesting userauth list", 0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-none request", 0);
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_sent;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_state == libssh2_NB_state_sent) {
|
|
|
|
rc = libssh2_packet_requirev_ex(session, reply_codes, &session->userauth_data, &session->userauth_data_len,
|
|
|
|
0, NULL, 0, &session->userauth_packet_requirev_state);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block requesting userauth list", 0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
|
|
|
/* Wow, who'dve thought... */
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
methods_len = libssh2_ntohu32(session->userauth_data + 1);
|
|
|
|
memcpy(session->userauth_data, session->userauth_data + 5, methods_len);
|
|
|
|
session->userauth_data[methods_len] = '\0';
|
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s", session->userauth_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return (char *)session->userauth_data;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ libssh2_userauth_authenticated
|
|
|
|
* 0 if not yet authenticated
|
|
|
|
* non-zero is already authenticated
|
|
|
|
*/
|
|
|
|
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session)
|
|
|
|
{
|
2007-05-28 17:56:08 +00:00
|
|
|
return session->state & LIBSSH2_STATE_AUTHENTICATED;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ libssh2_userauth_password
|
|
|
|
* Plain ol' login
|
|
|
|
*/
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_API int
|
|
|
|
libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len, const char *password,
|
|
|
|
unsigned int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2007-06-06 12:34:06 +00:00
|
|
|
unsigned char *s;
|
2007-05-28 17:56:08 +00:00
|
|
|
static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0 };
|
2007-06-06 12:34:06 +00:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (session->userauth_state == libssh2_NB_state_idle) {
|
|
|
|
/* Zero the whole thing out */
|
|
|
|
memset(&session->userauth_packet_requirev_state, 0, sizeof(session->userauth_packet_requirev_state));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 40 = acket_type(1) + username_len(4) + service_len(4) +
|
|
|
|
* service(14)"ssh-connection" + method_len(4) + method(8)"password" +
|
|
|
|
* chgpwdbool(1) + password_len(4) */
|
|
|
|
session->userauth_data_len = username_len + password_len + 40;
|
|
|
|
|
|
|
|
session->userauth_data0 = ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
|
|
|
|
|
|
|
|
s = session->userauth_data = LIBSSH2_ALLOC(session, session->userauth_data_len);
|
|
|
|
if (!session->userauth_data) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth-password request", 0);
|
|
|
|
return -1;
|
|
|
|
}
|
2004-12-07 21:17:20 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
*(s++) = SSH_MSG_USERAUTH_REQUEST;
|
|
|
|
libssh2_htonu32(s, username_len); s += 4;
|
|
|
|
memcpy(s, username, username_len); s += username_len;
|
2004-12-07 21:17:20 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
|
|
|
|
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
|
2004-12-07 21:17:20 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(s, sizeof("password") - 1); s += 4;
|
|
|
|
memcpy(s, "password", sizeof("password") - 1); s += sizeof("password") - 1;
|
2004-12-07 21:17:20 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
*s = '\0'; s++;
|
2004-12-07 21:17:20 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(s, password_len); s += 4;
|
|
|
|
memcpy(s, password, password_len); s += password_len;
|
2004-12-07 21:17:20 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting to login using password authentication");
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_created;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
|
|
|
|
if (session->userauth_state == libssh2_NB_state_created) {
|
|
|
|
rc = libssh2_packet_write(session, session->userauth_data, session->userauth_data_len);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password request", 0);
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_sent;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
password_response:
|
|
|
|
|
|
|
|
if ((session->userauth_state == libssh2_NB_state_sent) || (session->userauth_state == libssh2_NB_state_sent1) ||
|
|
|
|
(session->userauth_state == libssh2_NB_state_sent2)) {
|
|
|
|
if (session->userauth_state == libssh2_NB_state_sent) {
|
|
|
|
rc = libssh2_packet_requirev_ex(session, reply_codes, &session->userauth_data, &session->userauth_data_len,
|
|
|
|
0, NULL, 0, &session->userauth_packet_requirev_state);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
else if (rc) {
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Password authentication successful");
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->userauth_newpw = NULL;
|
|
|
|
session->userauth_newpw_len = 0;
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_sent1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((session->userauth_data[0] == SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) ||
|
|
|
|
(session->userauth_data0 == SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)) {
|
|
|
|
session->userauth_data0 = SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
|
|
|
|
|
|
|
|
if ((session->userauth_state == libssh2_NB_state_sent1) || (session->userauth_state == libssh2_NB_state_sent2)) {
|
|
|
|
if (session->userauth_state == libssh2_NB_state_sent1) {
|
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Password change required");
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
}
|
|
|
|
if (passwd_change_cb) {
|
|
|
|
if (session->userauth_state == libssh2_NB_state_sent1) {
|
|
|
|
passwd_change_cb(session, &session->userauth_newpw, &session->userauth_newpw_len, &session->abstract);
|
|
|
|
if (!session->userauth_newpw) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password expired, and callback failed", 0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* basic data_len + newpw_len(4) */
|
|
|
|
session->userauth_data_len = username_len + password_len + 44 + session->userauth_newpw_len;
|
|
|
|
|
|
|
|
s = session->userauth_data = LIBSSH2_ALLOC(session, session->userauth_data_len);
|
|
|
|
if (!session->userauth_data) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate memory for userauth-password-change request", 0);
|
|
|
|
LIBSSH2_FREE(session, session->userauth_newpw);
|
2007-06-07 16:43:20 +00:00
|
|
|
session->userauth_newpw = NULL;
|
2007-06-06 12:34:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*(s++) = SSH_MSG_USERAUTH_REQUEST;
|
|
|
|
libssh2_htonu32(s, username_len); s += 4;
|
|
|
|
memcpy(s, username, username_len); s += username_len;
|
|
|
|
|
|
|
|
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
|
|
|
|
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
|
|
|
|
|
|
|
|
libssh2_htonu32(s, sizeof("password") - 1); s += 4;
|
|
|
|
memcpy(s, "password", sizeof("password") - 1); s += sizeof("password") - 1;
|
|
|
|
|
|
|
|
*s = 0xFF; s++;
|
|
|
|
|
|
|
|
libssh2_htonu32(s, password_len); s += 4;
|
|
|
|
memcpy(s, password, password_len); s += password_len;
|
|
|
|
|
|
|
|
libssh2_htonu32(s, session->userauth_newpw_len); s += 4;
|
|
|
|
memcpy(s, session->userauth_newpw, session->userauth_newpw_len);
|
|
|
|
s += session->userauth_newpw_len;
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_sent2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session->userauth_state == libssh2_NB_state_sent2) {
|
|
|
|
rc = libssh2_packet_write(session, session->userauth_data, session->userauth_data_len);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
|
|
|
"Unable to send userauth-password-change request", 0);
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_newpw);
|
|
|
|
session->userauth_newpw = NULL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_newpw);
|
|
|
|
session->userauth_newpw = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ugliest use of goto ever. Blame it on the
|
|
|
|
* askN => requirev migration.
|
|
|
|
*/
|
|
|
|
session->userauth_state = libssh2_NB_state_sent;
|
|
|
|
goto password_response;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password Expired, and no callback specified", 0);
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FAILURE */
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return -1;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ libssh2_file_read_publickey
|
|
|
|
* Read a public key from an id_???.pub style file
|
|
|
|
*/
|
2007-06-06 12:34:06 +00:00
|
|
|
static int
|
|
|
|
libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char **method, unsigned long *method_len,
|
|
|
|
unsigned char **pubkeydata, unsigned long *pubkeydata_len, const char *pubkeyfile)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2007-05-28 17:56:08 +00:00
|
|
|
FILE *fd;
|
|
|
|
char c;
|
|
|
|
unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;
|
|
|
|
size_t pubkey_len = 0;
|
|
|
|
unsigned int tmp_len;
|
|
|
|
|
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s", pubkeyfile);
|
|
|
|
/* Read Public Key */
|
|
|
|
fd = fopen(pubkeyfile, "r");
|
|
|
|
if (!fd) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to open public key file", 0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
while (!feof(fd) && (c = fgetc(fd)) != '\r' && c != '\n') pubkey_len++;
|
|
|
|
if (feof(fd)) {
|
|
|
|
/* the last character was EOF */
|
|
|
|
pubkey_len--;
|
|
|
|
}
|
|
|
|
rewind(fd);
|
|
|
|
|
|
|
|
if (pubkey_len <= 1) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid data in public key file", 0);
|
|
|
|
fclose(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pubkey = LIBSSH2_ALLOC(session, pubkey_len);
|
|
|
|
if (!pubkey) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for public key data", 0);
|
|
|
|
fclose(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (fread(pubkey, 1, pubkey_len, fd) != pubkey_len) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to read public key from file", 0);
|
|
|
|
LIBSSH2_FREE(session, pubkey);
|
|
|
|
fclose(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
fclose(fd);
|
|
|
|
/*
|
|
|
|
* Remove trailing whitespace
|
|
|
|
*/
|
|
|
|
while (pubkey_len && isspace(pubkey[pubkey_len-1])) pubkey_len--;
|
|
|
|
|
|
|
|
if (!pubkey_len) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_FILE, "Missing public key data", 0);
|
|
|
|
LIBSSH2_FREE(session, pubkey);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data", 0);
|
|
|
|
LIBSSH2_FREE(session, pubkey);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* Wasting some bytes here (okay, more than some),
|
|
|
|
* but since it's likely to be freed soon anyway,
|
|
|
|
* we'll just avoid the extra free/alloc and call it a wash */
|
|
|
|
*method = pubkey;
|
|
|
|
*method_len = sp1 - pubkey;
|
|
|
|
|
|
|
|
sp1++;
|
|
|
|
|
|
|
|
if ((sp2 = memchr(sp1, ' ', pubkey_len - *method_len)) == NULL) {
|
|
|
|
/* Assume that the id string is missing, but that it's okay */
|
|
|
|
sp2 = pubkey + pubkey_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (libssh2_base64_decode(session, (char **)&tmp, &tmp_len, (char *)sp1, sp2 - sp1)) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid key data, not base64 encoded", 0);
|
|
|
|
LIBSSH2_FREE(session, pubkey);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*pubkeydata = tmp;
|
|
|
|
*pubkeydata_len = tmp_len;
|
|
|
|
|
|
|
|
return 0;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2005-06-18 10:41:59 +00:00
|
|
|
/* {{{ libssh2_file_read_privatekey
|
2004-12-07 21:17:20 +00:00
|
|
|
* Read a PEM encoded private key from an id_??? style file
|
|
|
|
*/
|
2007-06-06 12:34:06 +00:00
|
|
|
static int
|
|
|
|
libssh2_file_read_privatekey(LIBSSH2_SESSION *session, const LIBSSH2_HOSTKEY_METHOD **hostkey_method, void **hostkey_abstract,
|
|
|
|
const unsigned char *method, int method_len, const char *privkeyfile, const char *passphrase)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2007-05-28 17:56:08 +00:00
|
|
|
const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = libssh2_hostkey_methods();
|
|
|
|
|
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading private key file: %s", privkeyfile);
|
|
|
|
*hostkey_method = NULL;
|
|
|
|
*hostkey_abstract = NULL;
|
|
|
|
while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
|
2007-06-06 12:34:06 +00:00
|
|
|
if ((*hostkey_methods_avail)->initPEM && strncmp((*hostkey_methods_avail)->name, (const char *)method, method_len) == 0) {
|
2007-05-28 17:56:08 +00:00
|
|
|
*hostkey_method = *hostkey_methods_avail;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
hostkey_methods_avail++;
|
|
|
|
}
|
|
|
|
if (!*hostkey_method) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, "No handler for specified private key", 0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if ((*hostkey_method)->initPEM(session, privkeyfile, (unsigned char *)passphrase, hostkey_abstract)) {
|
2007-05-28 17:56:08 +00:00
|
|
|
libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to initialize private key from file", 0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2005-02-14 05:51:06 +00:00
|
|
|
/* {{{ libssh2_userauth_hostbased_fromfile_ex
|
|
|
|
* Authenticate using a keypair found in the named files
|
|
|
|
*/
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_API int
|
|
|
|
libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
|
|
|
const char *publickey, const char *privatekey, const char *passphrase, const char *hostname,
|
|
|
|
unsigned int hostname_len, const char *local_username, unsigned int local_username_len)
|
2005-02-14 05:51:06 +00:00
|
|
|
{
|
2007-05-28 17:56:08 +00:00
|
|
|
const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
|
|
|
void *abstract;
|
|
|
|
unsigned char buf[5];
|
|
|
|
struct iovec datavec[4];
|
2007-06-06 12:34:06 +00:00
|
|
|
unsigned char *pubkeydata, *sig;
|
2007-05-28 17:56:08 +00:00
|
|
|
static const unsigned char reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
|
2007-06-06 12:34:06 +00:00
|
|
|
unsigned long pubkeydata_len, sig_len, data_len;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (session->userauth_state == libssh2_NB_state_idle) {
|
|
|
|
/* Zero the whole thing out */
|
|
|
|
memset(&session->userauth_packet_requirev_state, 0, sizeof(session->userauth_packet_requirev_state));
|
|
|
|
|
|
|
|
if (libssh2_file_read_publickey(session, &session->userauth_method, &session->userauth_method_len,
|
|
|
|
&pubkeydata, &pubkeydata_len, publickey)) {
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/*
|
|
|
|
* 48 = packet_type(1) + username_len(4) + servicename_len(4) +
|
|
|
|
* service_name(14)"ssh-connection" + authmethod_len(4) +
|
|
|
|
* authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) +
|
|
|
|
* local_username_len(4)
|
|
|
|
*/
|
|
|
|
session->userauth_packet_len = username_len + session->userauth_method_len + hostname_len +
|
|
|
|
local_username_len + pubkeydata_len + 48;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Preallocate space for an overall length, method name again,
|
|
|
|
* and the signature, which won't be any larger than the size of
|
|
|
|
* the publickeydata itself
|
|
|
|
*/
|
|
|
|
session->userauth_s = session->userauth_packet =
|
|
|
|
LIBSSH2_ALLOC(session, session->userauth_packet_len + 4 + (4 + session->userauth_method_len) +(4 + pubkeydata_len));
|
|
|
|
if (!session->userauth_packet) {
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
*(session->userauth_s++) = SSH_MSG_USERAUTH_REQUEST;
|
|
|
|
libssh2_htonu32(session->userauth_s, username_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, username, username_len); session->userauth_s += username_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, 14); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, "ssh-connection", 14); session->userauth_s += 14;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, 9); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, "hostbased", 9); session->userauth_s += 9;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, session->userauth_method_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, session->userauth_method, session->userauth_method_len);
|
|
|
|
session->userauth_s += session->userauth_method_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, pubkeydata_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, pubkeydata, pubkeydata_len); session->userauth_s += pubkeydata_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, hostname_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, hostname, hostname_len); session->userauth_s += hostname_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, local_username_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, local_username, local_username_len); session->userauth_s += local_username_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, session->userauth_method,
|
|
|
|
session->userauth_method_len, privatekey, passphrase)) {
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(buf, session->session_id_len);
|
|
|
|
datavec[0].iov_base = buf;
|
|
|
|
datavec[0].iov_len = 4;
|
|
|
|
datavec[1].iov_base = session->session_id;
|
|
|
|
datavec[1].iov_len = session->session_id_len;
|
|
|
|
datavec[2].iov_base = session->userauth_packet;
|
|
|
|
datavec[2].iov_len = session->userauth_packet_len;
|
|
|
|
|
|
|
|
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
if (privkeyobj->dtor) {
|
|
|
|
privkeyobj->dtor(session, &abstract);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
|
|
|
if (privkeyobj->dtor) {
|
|
|
|
privkeyobj->dtor(session, &abstract);
|
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (sig_len > pubkeydata_len) {
|
|
|
|
unsigned char *newpacket;
|
|
|
|
/* Should *NEVER* happen, but...well.. better safe than sorry */
|
|
|
|
newpacket = LIBSSH2_REALLOC(session, session->userauth_packet, session->userauth_packet_len + 4 +
|
|
|
|
(4 + session->userauth_method_len) + (4 + sig_len)); /* PK sigblob */
|
|
|
|
if (!newpacket) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC,"Failed allocating additional space for userauth-hostbased packet", 0);
|
|
|
|
LIBSSH2_FREE(session, sig);
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
session->userauth_packet = newpacket;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->userauth_s = session->userauth_packet + session->userauth_packet_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, 4 + session->userauth_method_len + 4 + sig_len);
|
|
|
|
session->userauth_s += 4;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, session->userauth_method_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, session->userauth_method, session->userauth_method_len);
|
|
|
|
session->userauth_s += session->userauth_method_len;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, sig_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, sig, sig_len); session->userauth_s += sig_len;
|
|
|
|
LIBSSH2_FREE(session, sig);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting hostbased authentication");
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_created;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
|
|
|
|
if (session->userauth_state == libssh2_NB_state_created) {
|
|
|
|
rc = libssh2_packet_write(session, session->userauth_packet, session->userauth_s - session->userauth_packet);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-hostbased request", 0);
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_sent;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_state == libssh2_NB_state_sent) {
|
|
|
|
rc = libssh2_packet_requirev_ex(session, reply_codes, &session->userauth_data, &data_len,
|
|
|
|
0, NULL, 0, &session->userauth_packet_requirev_state);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session->userauth_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Hostbased authentication successful");
|
|
|
|
/* We are us and we've proved it. */
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This public key is not allowed for this user on this server */
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
|
|
|
|
"Invalid signature for supplied public key, or bad username/public key combination", 0);
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return -1;
|
2005-02-14 05:51:06 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2004-12-07 21:17:20 +00:00
|
|
|
/* {{{ libssh2_userauth_publickey_fromfile_ex
|
|
|
|
* Authenticate using a keypair found in the named files
|
|
|
|
*/
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_API int
|
|
|
|
libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
|
|
|
const char *publickey, const char *privatekey, const char *passphrase)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2007-05-28 17:56:08 +00:00
|
|
|
const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
|
|
|
void *abstract;
|
|
|
|
unsigned char buf[5];
|
|
|
|
struct iovec datavec[4];
|
2007-06-06 12:34:06 +00:00
|
|
|
unsigned char *pubkeydata, *sig;
|
2007-05-28 17:56:08 +00:00
|
|
|
unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PK_OK, 0 };
|
2007-06-06 12:34:06 +00:00
|
|
|
unsigned long pubkeydata_len, sig_len;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (session->userauth_state == libssh2_NB_state_idle) {
|
|
|
|
/* Zero the whole thing out */
|
|
|
|
memset(&session->userauth_packet_requirev_state, 0, sizeof(session->userauth_packet_requirev_state));
|
|
|
|
|
|
|
|
if (libssh2_file_read_publickey(session, &session->userauth_method, &session->userauth_method_len,
|
|
|
|
&pubkeydata, &pubkeydata_len, publickey)) {
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/*
|
|
|
|
* 45 = packet_type(1) + username_len(4) + servicename_len(4) +
|
|
|
|
* service_name(14)"ssh-connection" + authmethod_len(4) +
|
|
|
|
* authmethod(9)"publickey" + sig_included(1)'\0' + algmethod_len(4) +
|
|
|
|
* publickey_len(4)
|
|
|
|
*/
|
|
|
|
session->userauth_packet_len = username_len + session->userauth_method_len + pubkeydata_len + 45;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Preallocate space for an overall length, method name again, and
|
|
|
|
* the signature, which won't be any larger than the size of the
|
|
|
|
* publickeydata itself
|
|
|
|
*/
|
|
|
|
session->userauth_s = session->userauth_packet =
|
|
|
|
LIBSSH2_ALLOC(session, session->userauth_packet_len + 4 + (4 + session->userauth_method_len) + (4 + pubkeydata_len));
|
|
|
|
if (!session->userauth_packet) {
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
LIBSSH2_FREE(session, pubkeydata);
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
*(session->userauth_s++) = SSH_MSG_USERAUTH_REQUEST;
|
|
|
|
libssh2_htonu32(session->userauth_s, username_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, username, username_len); session->userauth_s += username_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, 14); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, "ssh-connection", 14); session->userauth_s += 14;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, 9); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, "publickey", 9); session->userauth_s += 9;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->userauth_b = session->userauth_s;
|
|
|
|
/* Not sending signature with *this* packet */
|
|
|
|
*(session->userauth_s++) = 0;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, session->userauth_method_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, session->userauth_method, session->userauth_method_len);
|
|
|
|
session->userauth_s += session->userauth_method_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, pubkeydata_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, pubkeydata, pubkeydata_len); session->userauth_s += pubkeydata_len;
|
|
|
|
LIBSSH2_FREE(session, pubkeydata);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication");
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_created;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
|
|
|
|
if (session->userauth_state == libssh2_NB_state_created) {
|
|
|
|
rc = libssh2_packet_write(session, session->userauth_packet, session->userauth_packet_len);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_sent;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_state == libssh2_NB_state_sent) {
|
|
|
|
rc = libssh2_packet_requirev_ex(session, reply_codes, &session->userauth_data, &session->userauth_data_len, 0, NULL, 0,
|
|
|
|
&session->userauth_packet_requirev_state);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Pubkey authentication prematurely successful");
|
|
|
|
/*
|
|
|
|
* God help any SSH server that allows an UNVERIFIED
|
|
|
|
* public key to validate the user
|
|
|
|
*/
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_data[0] == SSH_MSG_USERAUTH_FAILURE) {
|
|
|
|
/* This public key is not allowed for this user on this server */
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED, "Username/PublicKey combination invalid", 0);
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* Semi-Success! */
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
|
|
|
|
if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, session->userauth_method,
|
|
|
|
session->userauth_method_len, privatekey, passphrase)) {
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
*session->userauth_b = 0xFF;
|
|
|
|
|
|
|
|
libssh2_htonu32(buf, session->session_id_len);
|
|
|
|
datavec[0].iov_base = buf;
|
|
|
|
datavec[0].iov_len = 4;
|
|
|
|
datavec[1].iov_base = session->session_id;
|
|
|
|
datavec[1].iov_len = session->session_id_len;
|
|
|
|
datavec[2].iov_base = session->userauth_packet;
|
|
|
|
datavec[2].iov_len = session->userauth_packet_len;
|
|
|
|
|
|
|
|
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
if (privkeyobj->dtor) {
|
|
|
|
privkeyobj->dtor(session, &abstract);
|
|
|
|
}
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
|
|
|
if (privkeyobj->dtor) {
|
|
|
|
privkeyobj->dtor(session, &abstract);
|
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (sig_len > pubkeydata_len) {
|
|
|
|
unsigned char *newpacket;
|
|
|
|
/* Should *NEVER* happen, but...well.. better safe than sorry */
|
|
|
|
newpacket = LIBSSH2_REALLOC(session, session->userauth_packet, session->userauth_packet_len + 4 +
|
|
|
|
(4 + session->userauth_method_len) + (4 + sig_len)); /* PK sigblob */
|
|
|
|
if (!newpacket) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating additional space for userauth-publickey packet", 0);
|
|
|
|
LIBSSH2_FREE(session, sig);
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
session->userauth_packet = newpacket;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->userauth_s = session->userauth_packet + session->userauth_packet_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, 4 + session->userauth_method_len + 4 + sig_len); session->userauth_s += 4;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, session->userauth_method_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, session->userauth_method, session->userauth_method_len);
|
|
|
|
session->userauth_s += session->userauth_method_len;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_method);
|
|
|
|
session->userauth_method = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
libssh2_htonu32(session->userauth_s, sig_len); session->userauth_s += 4;
|
|
|
|
memcpy(session->userauth_s, sig, sig_len); session->userauth_s += sig_len;
|
|
|
|
LIBSSH2_FREE(session, sig);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication -- phase 2");
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_sent1;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
|
|
|
|
if (session->userauth_state == libssh2_NB_state_sent1) {
|
|
|
|
rc = libssh2_packet_write(session, session->userauth_packet, session->userauth_s - session->userauth_packet);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
LIBSSH2_FREE(session, session->userauth_packet);
|
|
|
|
session->userauth_packet = NULL;
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_sent2;
|
|
|
|
}
|
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
/* PK_OK is no longer valid */
|
|
|
|
reply_codes[2] = 0;
|
2007-06-06 12:34:06 +00:00
|
|
|
|
|
|
|
rc = libssh2_packet_requirev_ex(session, reply_codes, &session->userauth_data, &session->userauth_data_len, 0, NULL, 0,
|
|
|
|
&session->userauth_packet_requirev_state);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
2007-05-28 17:56:08 +00:00
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Publickey authentication successful");
|
|
|
|
/* We are us and we've proved it. */
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
2007-06-06 12:34:06 +00:00
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This public key is not allowed for this user on this server */
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
|
|
|
|
"Invalid signature for supplied public key, or bad username/public key combination", 0);
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return -1;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
2005-06-11 19:18:06 +00:00
|
|
|
|
|
|
|
/* {{{ libssh2_userauth_keyboard_interactive
|
|
|
|
* Authenticate using a challenge-response authentication
|
|
|
|
*/
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_API int
|
|
|
|
libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
|
|
|
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
|
2005-06-11 19:18:06 +00:00
|
|
|
{
|
2007-06-06 12:34:06 +00:00
|
|
|
unsigned char *s;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS,
|
|
|
|
SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 };
|
|
|
|
unsigned int language_tag_len;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (session->userauth_state == libssh2_NB_state_idle) {
|
|
|
|
session->userauth_auth_name = NULL;
|
|
|
|
session->userauth_auth_instruction = NULL;
|
|
|
|
session->userauth_num_prompts = 0;
|
|
|
|
session->userauth_auth_failure = 1;
|
|
|
|
session->userauth_prompts = NULL;
|
|
|
|
session->userauth_responses = NULL;
|
|
|
|
|
|
|
|
/* Zero the whole thing out */
|
|
|
|
memset(&session->userauth_packet_requirev_state, 0, sizeof(session->userauth_packet_requirev_state));
|
|
|
|
|
|
|
|
session->userauth_packet_len =
|
|
|
|
1 /* byte SSH_MSG_USERAUTH_REQUEST */
|
|
|
|
+ 4 + username_len /* string user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
|
|
|
|
+ 4 + 14 /* string service name (US-ASCII) */
|
|
|
|
+ 4 + 20 /* string "keyboard-interactive" (US-ASCII) */
|
|
|
|
+ 4 + 0 /* string language tag (as defined in [RFC-3066]) */
|
|
|
|
+ 4 + 0 /* string submethods (ISO-10646 UTF-8) */
|
|
|
|
;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->userauth_data = s = LIBSSH2_ALLOC(session, session->userauth_packet_len);
|
|
|
|
if (s) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive authentication", 0);
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
*s++ = SSH_MSG_USERAUTH_REQUEST;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* user name */
|
|
|
|
libssh2_htonu32(s, username_len); s += 4;
|
|
|
|
memcpy(s, username, username_len); s += username_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* service name */
|
|
|
|
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
|
|
|
|
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* "keyboard-interactive" */
|
|
|
|
libssh2_htonu32(s, sizeof("keyboard-interactive") - 1); s += 4;
|
|
|
|
memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1); s += sizeof("keyboard-interactive") - 1;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* language tag */
|
|
|
|
libssh2_htonu32(s, 0); s += 4;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* submethods */
|
|
|
|
libssh2_htonu32(s, 0); s += 4;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting keyboard-interactive authentication");
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_created;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_state == libssh2_NB_state_created) {
|
|
|
|
rc = libssh2_packet_write(session, session->userauth_data, session->userauth_packet_len);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
else if (rc) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send keyboard-interactive request", 0);
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_sent;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
for (;;) {
|
|
|
|
if (session->userauth_state == libssh2_NB_state_sent) {
|
|
|
|
rc = libssh2_packet_requirev_ex(session, reply_codes, &session->userauth_data, &session->userauth_data_len,
|
|
|
|
0, NULL, 0, &session->userauth_packet_requirev_state);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive authentication successful");
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_data[0] == SSH_MSG_USERAUTH_FAILURE) {
|
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
|
|
|
return -1;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* server requested PAM-like conversation */
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
s = session->userauth_data + 1;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* string name (ISO-10646 UTF-8) */
|
|
|
|
session->userauth_auth_name_len = libssh2_ntohu32(s); s += 4;
|
|
|
|
session->userauth_auth_name = LIBSSH2_ALLOC(session, session->userauth_auth_name_len);
|
|
|
|
if (!session->userauth_auth_name) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate memory for keyboard-interactive 'name' request field", 0);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
memcpy(session->userauth_auth_name, s, session->userauth_auth_name_len); s += session->userauth_auth_name_len;
|
|
|
|
|
|
|
|
/* string instruction (ISO-10646 UTF-8) */
|
|
|
|
session->userauth_auth_instruction_len = libssh2_ntohu32(s); s += 4;
|
|
|
|
session->userauth_auth_instruction = LIBSSH2_ALLOC(session, session->userauth_auth_instruction_len);
|
|
|
|
if (!session->userauth_auth_instruction) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate memory for keyboard-interactive 'instruction' request field", 0);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
memcpy(session->userauth_auth_instruction, s, session->userauth_auth_instruction_len);
|
|
|
|
s += session->userauth_auth_instruction_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* string language tag (as defined in [RFC-3066]) */
|
|
|
|
language_tag_len = libssh2_ntohu32(s); s += 4;
|
|
|
|
/* ignoring this field as deprecated */
|
|
|
|
s += language_tag_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* int num-prompts */
|
|
|
|
session->userauth_num_prompts = libssh2_ntohu32(s); s += 4;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->userauth_prompts =
|
|
|
|
LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * session->userauth_num_prompts);
|
|
|
|
if (!session->userauth_prompts) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompts array", 0);
|
2007-05-28 17:56:08 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
memset(session->userauth_prompts, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * session->userauth_num_prompts);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->userauth_responses =
|
|
|
|
LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * session->userauth_num_prompts);
|
|
|
|
if (!session->userauth_responses) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate memory for keyboard-interactive responses array", 0);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
memset(session->userauth_responses, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * session->userauth_num_prompts);
|
|
|
|
|
|
|
|
for(i = 0; i != session->userauth_num_prompts; ++i) {
|
|
|
|
/* string prompt[1] (ISO-10646 UTF-8) */
|
|
|
|
session->userauth_prompts[i].length = libssh2_ntohu32(s); s += 4;
|
|
|
|
session->userauth_prompts[i].text = LIBSSH2_ALLOC(session, session->userauth_prompts[i].length);
|
|
|
|
if (!session->userauth_prompts[i].text) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate memory for keyboard-interactive prompt message", 0);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
memcpy(session->userauth_prompts[i].text, s, session->userauth_prompts[i].length);
|
|
|
|
s += session->userauth_prompts[i].length;
|
|
|
|
|
|
|
|
/* boolean echo[1] */
|
|
|
|
session->userauth_prompts[i].echo = *s++;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
response_callback(session->userauth_auth_name, session->userauth_auth_name_len, session->userauth_auth_instruction,
|
|
|
|
session->userauth_auth_instruction_len, session->userauth_num_prompts, session->userauth_prompts,
|
|
|
|
session->userauth_responses, &session->abstract);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive response callback function invoked");
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->userauth_packet_len =
|
|
|
|
1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
|
|
|
|
+ 4 /* int num-responses */
|
|
|
|
;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
for (i = 0; i != session->userauth_num_prompts; ++i) {
|
|
|
|
/* string response[1] (ISO-10646 UTF-8) */
|
|
|
|
session->userauth_packet_len += 4 + session->userauth_responses[i].length;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->userauth_data = s = LIBSSH2_ALLOC(session, session->userauth_packet_len);
|
|
|
|
if (!s) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate memory for keyboard-interactive response packet", 0);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
*s = SSH_MSG_USERAUTH_INFO_RESPONSE; s++;
|
|
|
|
libssh2_htonu32(s, session->userauth_num_prompts); s += 4;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
for (i = 0; i != session->userauth_num_prompts; ++i) {
|
|
|
|
libssh2_htonu32(s, session->userauth_responses[i].length); s += 4;
|
|
|
|
memcpy(s, session->userauth_responses[i].text, session->userauth_responses[i].length);
|
|
|
|
s += session->userauth_responses[i].length;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_sent1;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_state == libssh2_NB_state_sent1) {
|
|
|
|
rc = libssh2_packet_write(session, session->userauth_data, session->userauth_packet_len);
|
|
|
|
if (rc == PACKET_EAGAIN) {
|
|
|
|
return PACKET_EAGAIN;
|
|
|
|
}
|
|
|
|
if (rc) {
|
|
|
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-keyboard-interactive request", 0);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->userauth_auth_failure = 0;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
|
|
|
cleanup:
|
2007-06-06 12:34:06 +00:00
|
|
|
/*
|
|
|
|
* It's safe to clean all the data here, because unallocated pointers
|
2007-05-28 17:56:08 +00:00
|
|
|
* are filled by zeroes
|
|
|
|
*/
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->userauth_data);
|
|
|
|
session->userauth_data = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_prompts) {
|
|
|
|
for (i = 0; i != session->userauth_num_prompts; ++i) {
|
|
|
|
LIBSSH2_FREE(session, session->userauth_prompts[i].text);
|
|
|
|
session->userauth_prompts[i].text = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_responses) {
|
|
|
|
for (i = 0; i != session->userauth_num_prompts; ++i) {
|
|
|
|
LIBSSH2_FREE(session, session->userauth_responses[i].text);
|
|
|
|
session->userauth_responses[i].text = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->userauth_prompts);
|
|
|
|
session->userauth_prompts = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->userauth_responses);
|
|
|
|
session->userauth_responses = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->userauth_auth_failure) {
|
|
|
|
session->userauth_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
|
|
|
|
session->userauth_state = libssh2_NB_state_sent;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2005-06-11 19:18:06 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|