Files
m241Neelima/components/ip_net2-6.9/ipssh/src/ipssh_auth.c
T
2026-07-30 11:19:44 +05:30

1852 lines
58 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipssh_auth.c,v $ $Revision: 1.77.10.12 $
* $Source: /home/interpeak/CVSRoot/ipssh/src/ipssh_auth.c,v $
* $Author: xjiang1 $ $Date: 2018-11-09 10:31:10 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Roger Boden <roger@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include "ipssh_h.h"
#include "ipssh_transport.h"
#include "ipssh_auth.h"
#include "ipssh_sftp.h"
#include "ipssh_buffer.h"
#include <ipcom_clib.h>
#include <ipssh_config.h>
#include <ipcom_type.h>
#include <ipcom_cstyle.h>
#include <ipcom_buffer.h>
#include <ipcom_err.h>
#include <ipcom_shell.h>
#include <ipcom_sysvar.h>
#include <ipcom_sock2.h>
#include <openssl/evp.h>
#ifdef IP_PORT_VXWORKS
#include <shellHook.h>
#endif
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
IP_EXTERN int ipssh_dsa_verify(int type, const unsigned char *dgst, int dgst_len,
unsigned char *sigbuf, int siglen, DSA *dsa);
IP_EXTERN EVP_MD *ipssh_evp_dss1(void);
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
#define IPSSH_AUTH_PW_DONE 1
#define IPSSH_AUTH_PUBKEY_DONE 2
#define IPSSH_AUTH_HOSTBASED_DONE 4
#define IPSSH_AUTH_FAILED 0
#define IPSSH_AUTH_OK 1
#define IPSSH_AUTH_PUBKEY_OK 2
#define IPSSH_AUTH_FATAL 3
#define IPSSH_FQDN_MAXLEN 256
#define IPSSH_SIG_BUF_LEN 2048
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_GLOBAL Ip_err ipssh_send_userauth_failure_msg(Ipssh_conn* ssh_conn, char* supported_meths, Ip_u8 success);
IP_GLOBAL Ip_err ipssh_send_userauth_passwd_changereq(Ipssh_conn* ssh_conn);
IP_GLOBAL Ip_err ipssh_send_userauth_success_msg(Ipssh_conn* ssh_conn);
IP_GLOBAL Ip_err ipssh_send_msg_userauth_pk_ok(Ipssh_conn* ssh_conn, char* alg_name, Ip_u8* pub_key, Ip_size_t pub_key_len);
IP_GLOBAL Ip_err ipssh_send_userauth_banner_msg(Ipssh_conn* ssh_conn, const char* auth_banner);
IP_STATIC Ip_bool ipssh_more_auth_needed(Ipssh_conn* ssh_conn);
IP_STATIC void ipssh_get_auth_methods(Ipssh_conn* ssh_conn, char* buf, int buf_size);
IP_STATIC Ip_s32 ipssh_handle_publickey_auth(Ipssh_conn* ssh_conn, char* user);
IP_STATIC Ip_s32 ipssh_handle_hostbased_auth(Ipssh_conn* ssh_conn, char* user);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipssh_more_auth_needed
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipssh_more_auth_needed(Ipssh_conn* ssh_conn)
{
if (ssh_conn->config.auth_none_allowed != 0)
return IP_FALSE;
if (ssh_conn->auth_state == 0)
return IP_TRUE;
if (ssh_conn->config.pw_required && !(ssh_conn->auth_state & IPSSH_AUTH_PW_DONE))
return IP_TRUE;
if (ssh_conn->config.pub_key_required && !(ssh_conn->auth_state & IPSSH_AUTH_PUBKEY_DONE))
return IP_TRUE;
if (ssh_conn->config.hostbased_required && !(ssh_conn->auth_state & IPSSH_AUTH_HOSTBASED_DONE))
return IP_TRUE;
return IP_FALSE;
}
/*
*===========================================================================
* ipssh_get_auth_methods
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipssh_get_auth_methods(Ipssh_conn* ssh_conn, char* buf, int buf_size)
{
int pw_on, pub_key_on;
int pw_req, pub_key_req;
int pub_key_first;
int hb_on;
int hb_req;
Ip_bool has_one = IP_FALSE;
ipcom_memset(buf, 0, buf_size);
pw_on = ssh_conn->config.pw_allowed;
pw_req = ssh_conn->config.pw_required;
pub_key_on = ssh_conn->config.pub_key_allowed;
pub_key_req = ssh_conn->config.pub_key_required;
pub_key_first = ssh_conn->config.pub_key_first;
hb_on = ssh_conn->config.hostbased_allowed;
hb_req = ssh_conn->config.hostbased_required;
/* Remove authentication methods already used. */
if (ssh_conn->auth_state & IPSSH_AUTH_PW_DONE)
pw_on = 0;
if (ssh_conn->auth_state & IPSSH_AUTH_PUBKEY_DONE)
pub_key_on = 0;
if (ssh_conn->auth_state & IPSSH_AUTH_HOSTBASED_DONE)
hb_on = 0;
/* Check if several auth methods are required and pub key shall be
* the first method to use */
if (pw_on && pw_req
&& hb_on && hb_req
&& pub_key_on && pub_key_req
&& pub_key_first)
{
if (ssh_conn->auth_state == 0)
{
pw_on = 0;
hb_on = 0;
}
}
if (pub_key_on == 1)
{
has_one = IP_TRUE;
ipcom_strncat(buf, IPSSH_PUBKEY_AUTH_STR, buf_size);
}
if (pw_on == 1)
{
if(has_one)
{
ipcom_strncat(buf, ",", buf_size);
}
has_one = IP_TRUE;
ipcom_strncat(buf, IPSSH_PW_AUTH_STR, buf_size);
}
if (hb_on == 1)
{
if(has_one)
{
ipcom_strncat(buf, ",", buf_size);
}
has_one = IP_TRUE;
ipcom_strncat(buf, IPSSH_HOSTBASED_AUTH_STR, buf_size);
}
if (!has_one)
{
ipcom_strncat(buf, IPSSH_NONE_STR, buf_size);
}
}
/*
*===========================================================================
* ipssh_unpack_signature
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_u8*
ipssh_unpack_signature(Ipcom_buffer* buf, Ip_u32* len)
{
char* sig_type;
Ip_u32 dummy;
*len = 0;
if (ipssh_buffer_get_uint(buf, &dummy) != IPCOM_SUCCESS)
return IP_NULL;
sig_type = ipssh_buffer_get_sshstr(buf);
if (!sig_type)
return IP_NULL;
if (ipcom_strcmp(sig_type, IPSSH_DSA_STR) == 0)
{
/* Convert to openssl DSA_SIG binary format */
DSA_SIG* dsa_sig;
Ip_u8* dsa_sig_der = IP_NULL;
Ip_u8* tmp_dsa_sig_der;
Ip_u32 sig_len;
Ip_s32 tmp_len;
ipcom_free(sig_type);
if (ipssh_buffer_get_uint(buf, &sig_len) != IPCOM_SUCCESS)
return IP_NULL;
if (sig_len != 40 || ipcom_buffer_len(buf)<40)
return IP_NULL;
dsa_sig = DSA_SIG_new();
if (!dsa_sig)
return IP_NULL;
dsa_sig->r = BN_bin2bn(ipcom_buffer_start_ptr(buf), 20, dsa_sig->r);
dsa_sig->s = BN_bin2bn(ipcom_buffer_start_ptr(buf)+20, 20, dsa_sig->s);
if (!dsa_sig->r || !dsa_sig->s)
goto cleanup;
(void)ipcom_buffer_consume(buf, 40);
dsa_sig_der = ipcom_malloc(64);
if (!dsa_sig_der)
goto cleanup;
tmp_dsa_sig_der = dsa_sig_der;
tmp_len = i2d_DSA_SIG(dsa_sig, &tmp_dsa_sig_der);
if (tmp_len < 0)
{
ipcom_free(dsa_sig_der);
dsa_sig_der = IP_NULL;
goto cleanup;
}
*len = (Ip_u32)tmp_len;
cleanup:
DSA_SIG_free(dsa_sig);
return dsa_sig_der;
}
else
{
ipcom_free(sig_type);
return ipssh_buffer_get_sshbuf(buf, len);
}
}
/*
*===========================================================================
* ipssh_unpack_dsa_key
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC EVP_PKEY*
ipssh_unpack_dsa_key(Ipcom_buffer* buf, Ip_u8** pub_key, Ip_u32* key_len)
{
EVP_PKEY* pkey;
DSA* dsa;
char* key_type = IP_NULL;
pkey = EVP_PKEY_new();
dsa = DSA_new();
if (!pkey || !dsa)
{
goto err;
}
*pub_key = (Ip_u8*)ipcom_buffer_ptr2pos(buf, 4); /* Make pointer point to pub key value and not to the length field. */
if (ipssh_buffer_get_uint(buf, key_len) ||
(key_type = ipssh_buffer_get_sshstr(buf)) == IP_NULL ||
ipssh_buffer_get_ssh_mpint2(buf, &(dsa->p)) ||
ipssh_buffer_get_ssh_mpint2(buf, &(dsa->q)) ||
ipssh_buffer_get_ssh_mpint2(buf, &(dsa->g)) ||
ipssh_buffer_get_ssh_mpint2(buf, &(dsa->pub_key)))
{
IPCOM_LOG0(ERR,"ipssh_unpack_dsa_key :: failed to unpack key");
goto err;
}
ipcom_free(key_type);
(void)EVP_PKEY_assign_DSA(pkey, dsa);
return pkey;
err:
if (pkey)
EVP_PKEY_free(pkey);
if (dsa)
DSA_free(dsa);
if (key_type)
ipcom_free(key_type);
return IP_NULL;
}
/*
*===========================================================================
* ipssh_unpack_rsa_key
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
#ifdef IPSSH_USE_RSA
IP_STATIC EVP_PKEY*
ipssh_unpack_rsa_key(Ipcom_buffer* buf, Ip_u8** pub_key, Ip_u32* key_len)
{
EVP_PKEY* pkey;
RSA* rsa;
char* key_type = IP_NULL;
pkey = EVP_PKEY_new();
rsa = RSA_new();
if (!pkey || !rsa)
{
if (rsa)
RSA_free(rsa);
if (pkey)
EVP_PKEY_free(pkey);
return IP_NULL;
}
*pub_key = (Ip_u8*)ipcom_buffer_ptr2pos(buf, 4);/* Make pointer point to pub key value and not to the length field. */
if (ipssh_buffer_get_uint(buf, key_len) ||
(key_type = ipssh_buffer_get_sshstr(buf)) == IP_NULL ||
ipssh_buffer_get_ssh_mpint2(buf, &(rsa->e)) ||
ipssh_buffer_get_ssh_mpint2(buf, &(rsa->n)))
{
IPCOM_LOG0(ERR,"ipssh_unpack_rsa_key :: failed to unpack key");
goto fail;
}
ipcom_free(key_type);
(void)EVP_PKEY_assign_RSA(pkey, rsa);
return pkey;
fail:
if (pkey)
EVP_PKEY_free(pkey);
if (rsa)
RSA_free(rsa);
if (key_type)
ipcom_free(key_type);
return IP_NULL;
}
#endif
/*
*===========================================================================
* ipssh_handle_password_auth
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_s32
ipssh_handle_password_auth(Ipssh_conn* ssh_conn, char* user)
{
Ip_u8 flag;
Ip_s32 rc = IPSSH_AUTH_FAILED, pw_result;
char* pw;
char* new_pw = IP_NULL;
if (ipcom_buffer_get_char(ssh_conn->recv_plain_buf, &flag) != IPCOM_SUCCESS)
return IPSSH_AUTH_FATAL;
pw = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf);
if (flag)
new_pw = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf);
if (!pw || (!new_pw && flag))
{
IPCOM_LOG0(ERR, "ipssh_handle_password_auth :: out of memory");
rc = IPSSH_AUTH_FATAL;
goto cleanup;
}
IPCOM_LOG2(DEBUG2, "ipssh_handle_password_auth :: pw=%s, new pw=%s", pw, new_pw ? new_pw : "");
pw_result = ipssh_validate_userid_pw_cb(user, pw, ssh_conn->sh_ctx);
switch(pw_result)
{
case IPCOM_SUCCESS:
rc = IPSSH_AUTH_OK;
ssh_conn->auth_state |= IPSSH_AUTH_PW_DONE;
break;
case IPCOM_ERR_AUTH_FAILED:
default:
ssh_conn->auth_failure_count++;
IPCOM_LOG2(INFO, "ipssh_handle_password_auth :: pw authentication failed, userid=%s, count=%d",
user, ssh_conn->auth_failure_count);
}
ssh_conn->auth_meth = IPSSH_AUTH_METH_PW;
cleanup:
if (pw)
ipcom_free(pw);
if (new_pw)
ipcom_free(new_pw);
return rc;
}
/*
*===========================================================================
* ipssh_handle_publickey_auth
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_s32
ipssh_handle_publickey_auth(Ipssh_conn* ssh_conn, char* user)
{
Ip_u8 flag;
char* pk_alg_name = IP_NULL;
Ip_u8* pub_key;
Ip_u32 pub_key_len;
Ip_s32 rc = IPSSH_AUTH_FATAL;
EVP_PKEY* clt_pub_key = IP_NULL;
EVP_MD_CTX md_ctx;
Ip_u8* sig = IP_NULL;
Ip_u32 sig_len;
Ipcom_buffer* sig_buf = IP_NULL;
ipcom_memset(&md_ctx, 0, sizeof(md_ctx));
/* Unpack message, except the public key */
if (ipcom_buffer_get_char(ssh_conn->recv_plain_buf, &flag) ||
(pk_alg_name = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf)) == IP_NULL)
{
IPCOM_LOG0(ERR, "ipssh_handle_publickey_auth :: failed to unpack algorithm name");
goto cleanup;
}
#ifdef IPSSH_USE_RSA
if (ipcom_strcmp(pk_alg_name, IPSSH_RSA_STR) == 0)
{
clt_pub_key = ipssh_unpack_rsa_key(ssh_conn->recv_plain_buf, &pub_key, &pub_key_len);
if (IP_NULL == clt_pub_key)
{
IPCOM_LOG0(ERR, "ipssh_handle_publickey_auth :: ipssh_unpack_rsa_key() failed");
goto cleanup;
}
if (!EVP_VerifyInit(&md_ctx, EVP_sha1()))
{
IPCOM_LOG0(ERR, "ipssh_handle_publickey_auth :: EVP_VerifyInit() failed");
goto cleanup;
}
}
else
#endif
if (ipcom_strcmp(pk_alg_name, IPSSH_DSA_STR) == 0)
{
clt_pub_key = ipssh_unpack_dsa_key(ssh_conn->recv_plain_buf, &pub_key, &pub_key_len);
if (IP_NULL == clt_pub_key)
{
IPCOM_LOG0(ERR, "ipssh_handle_publickey_auth :: ipssh_unpack_dsa_key() failed");
goto cleanup;
}
if (!EVP_VerifyInit(&md_ctx, EVP_dss1()))
{
rc = IPSSH_AUTH_FAILED;
IPCOM_LOG0(ERR, "ipssh_handle_publickey_auth :: EVP_VerifyInit() failed");
goto cleanup;
}
}
else
{
IPCOM_LOG1(ERR, "ipssh_handle_publickey_auth :: unknown keytype: %s", pk_alg_name);
rc = IPSSH_AUTH_FAILED;
goto cleanup;
}
/* Verify public key */
if (ipssh_validate_pubkey_cb(user, clt_pub_key, ssh_conn->sh_ctx) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_handle_publickey_auth :: failed to validate public key");
rc = IPSSH_AUTH_FAILED;
goto cleanup;
}
if (flag)
{
/* Unpack signature */
sig = ipssh_unpack_signature(ssh_conn->recv_plain_buf, &sig_len);
if (!sig)
{
IPCOM_LOG0(ERR,"ipssh_handle_publickey_auth :: failed to unpack signature");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
/* Verify signature */
sig_buf = ipcom_buffer_new(2048);
if (!sig_buf)
{
IPCOM_LOG0(ERR,"ipssh_handle_publickey_auth :: out of memory");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if (ipssh_buffer_put_sshbuf(sig_buf, ssh_conn->sess_id, ssh_conn->sess_id_len) ||
ipcom_buffer_put_char(sig_buf, IPSSH_MSG_USERAUTH_REQUEST) ||
ipssh_buffer_put_sshstr(sig_buf, ssh_conn->user) ||
ipssh_buffer_put_sshstr(sig_buf, ssh_conn->service) ||
ipssh_buffer_put_sshstr(sig_buf, IPSSH_PUBKEY_AUTH_STR) ||
ipcom_buffer_put_char(sig_buf, 1) ||
ipssh_buffer_put_sshstr(sig_buf, pk_alg_name) ||
ipssh_buffer_put_sshbuf(sig_buf, pub_key, pub_key_len))
{
IPCOM_LOG0(ERR, "ipssh_handle_publickey_auth :: failed to pack signature data");
rc = IPCOM_ERR_FAILED; /* Disconnect client */
goto cleanup;
}
#ifdef IPSSH_DEBUG_PK_AUTH
ipcom_buffer_dump(sig_buf);
#endif
if (EVP_VerifyUpdate(&md_ctx, ipcom_buffer_start_ptr(sig_buf), ipcom_buffer_len(sig_buf)) == 0)
{
IPCOM_LOG0(ERR, "ipssh_handle_publickey_auth :: EVP_VerifyUpdate");
(void)ipssh_send_userauth_failure_msg(ssh_conn, IPSSH_NONE_STR, 0);
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if (EVP_VerifyFinal(&md_ctx, sig, sig_len, clt_pub_key) != 1)
{
IPCOM_LOG0(ERR, "ipssh_handle_publickey_auth :: failed to verify signature");
(void)ipssh_send_userauth_failure_msg(ssh_conn, IPSSH_NONE_STR, 0);
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
ssh_conn->auth_state |= IPSSH_AUTH_PUBKEY_DONE;
ssh_conn->auth_meth = IPSSH_AUTH_METH_PUBLIC_KEY;
rc = IPSSH_AUTH_OK;
}
else
{
/* The client only sent the public key and no signature */
rc = IPSSH_AUTH_PUBKEY_OK;
if (ipssh_send_msg_userauth_pk_ok(ssh_conn, pk_alg_name, pub_key, pub_key_len))
{
IPCOM_LOG0(ERR, "ipssh_handle_publickey_auth :: ipssh_send_msg_userauth_pk_ok() failed");
rc = IPSSH_AUTH_PUBKEY_OK;
goto cleanup;
}
}
cleanup:
if (clt_pub_key)
EVP_PKEY_free(clt_pub_key);
if (pk_alg_name)
ipcom_free(pk_alg_name);
if (sig_buf)
ipcom_buffer_free(sig_buf);
if (sig)
ipcom_free(sig);
(void)EVP_MD_CTX_cleanup(&md_ctx);
return rc;
}
/*
*===========================================================================
* ipssh_handle_hostbased_auth
*===========================================================================
* Description: ssh server parses the hostbased authentication msg and
* check if the authentication passes.
* Parameters: ssh_conn - The pointer for the ssh connection structure.
* user - user name for client.
* Returns: IPSSH_AUTH_OK - authentication passes
* IPSSH_AUTH_FATAL - authentication fails
*/
IP_STATIC Ip_s32
ipssh_handle_hostbased_auth(Ipssh_conn* ssh_conn, char* user)
{
/* byte SSH_MSG_USERAUTH_REQUEST
* string user name
* string service name
* string "hostbased"
* string public key algorithm for host key
* string public host key and certificates for client host
* string client host name expressed as the FQDN in US-ASCII
* string user name on the client host in ISO-10646 UTF-8 encoding
* [RFC3629]
* string signature
*/
char* pk_alg_name = IP_NULL;
char* cl_host_name = IP_NULL;
char* cl_user_name = IP_NULL;
Ip_u8* pub_key;
Ip_u32 pub_key_len;
Ip_s32 rc = IPSSH_AUTH_FATAL;
EVP_PKEY* clt_pub_key = IP_NULL;
EVP_MD_CTX md_ctx;
Ip_u8* sig = IP_NULL;
Ip_u32 sig_len;
Ipcom_buffer* sig_buf = IP_NULL;
ipcom_memset(&md_ctx, 0, sizeof(md_ctx));
/* Unpack message */
if ((pk_alg_name = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf)) == IP_NULL)
{
IPCOM_LOG0(ERR, "ipssh_handle_hostbased_auth :: failed to unpack algorithm name");
goto cleanup;
}
#ifdef IPSSH_USE_RSA
if (ipcom_strcmp(pk_alg_name, IPSSH_RSA_STR) == 0)
{
clt_pub_key = ipssh_unpack_rsa_key(ssh_conn->recv_plain_buf, &pub_key, &pub_key_len);
if (IP_NULL == clt_pub_key)
{
IPCOM_LOG0(ERR, "ipssh_handle_hostbased_auth :: ipssh_unpack_rsa_key() failed");
goto cleanup;
}
if (!EVP_VerifyInit(&md_ctx, EVP_sha1()))
{
IPCOM_LOG0(ERR, "ipssh_handle_hostbased_auth :: EVP_VerifyInit() failed");
goto cleanup;
}
}
else
#endif
if (ipcom_strcmp(pk_alg_name, IPSSH_DSA_STR) == 0)
{
clt_pub_key = ipssh_unpack_dsa_key(ssh_conn->recv_plain_buf, &pub_key, &pub_key_len);
if (IP_NULL == clt_pub_key)
{
IPCOM_LOG0(ERR, "ipssh_handle_hostbased_auth :: ipssh_unpack_dsa_key() failed");
goto cleanup;
}
if (!EVP_VerifyInit(&md_ctx, EVP_dss1()))
{
IPCOM_LOG0(ERR, "ipssh_handle_hostbased_auth :: EVP_VerifyInit() failed");
goto cleanup;
}
}
else
{
IPCOM_LOG1(ERR, "ipssh_handle_hostbased_auth :: unknown keytype: %s", pk_alg_name);
rc = IPSSH_AUTH_FAILED;
goto cleanup;
}
/* Unpack the client hostname */
if ((cl_host_name = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf)) == IP_NULL)
{
IPCOM_LOG0(ERR, "ipssh_handle_hostbased_auth :: failed to unpack client host name");
goto cleanup;
}
/* Unpack the client username */
if ((cl_user_name = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf)) == IP_NULL)
{
IPCOM_LOG0(ERR, "ipssh_handle_hostbased_auth :: failed to unpack client user name");
goto cleanup;
}
/* Unpack signature */
sig = ipssh_unpack_signature(ssh_conn->recv_plain_buf, &sig_len);
if (!sig)
{
IPCOM_LOG0(ERR,"ipssh_handle_hostbased_auth :: failed to unpack signature");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
/* Verify signature */
sig_buf = ipcom_buffer_new(IPSSH_SIG_BUF_LEN);
if (!sig_buf)
{
IPCOM_LOG0(ERR,"ipssh_handle_hostbased_auth :: out of memory");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if (ipssh_buffer_put_sshbuf(sig_buf, ssh_conn->sess_id, (Ip_size_t)ssh_conn->sess_id_len) ||
ipcom_buffer_put_char(sig_buf, IPSSH_MSG_USERAUTH_REQUEST) ||
ipssh_buffer_put_sshstr(sig_buf, ssh_conn->user) ||
ipssh_buffer_put_sshstr(sig_buf, ssh_conn->service) ||
ipssh_buffer_put_sshstr(sig_buf, IPSSH_HOSTBASED_AUTH_STR) ||
ipssh_buffer_put_sshstr(sig_buf, pk_alg_name) ||
ipssh_buffer_put_sshbuf(sig_buf, pub_key, (Ip_size_t)pub_key_len) ||
ipssh_buffer_put_sshstr(sig_buf, cl_host_name) ||
ipssh_buffer_put_sshstr(sig_buf, cl_user_name))
{
IPCOM_LOG0(ERR, "ipssh_handle_hostbased_auth :: failed to pack signature data");
rc = IPCOM_ERR_FAILED; /* Disconnect client */
goto cleanup;
}
#ifdef IPSSH_DEBUG_PK_AUTH
ipcom_buffer_dump(sig_buf);
#endif
/* Verify hostbased information including user name, hostname & public key */
if (ipssh_validate_hostbased_cb(user, cl_host_name, clt_pub_key, ssh_conn->sh_ctx) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_handle_hostbased_auth :: failed to validate public key");
rc = IPSSH_AUTH_FAILED;
goto cleanup;
}
if (EVP_VerifyUpdate(&md_ctx, ipcom_buffer_start_ptr(sig_buf), ipcom_buffer_len(sig_buf)) == 0)
{
IPCOM_LOG0(ERR, "ipssh_handle_hostbased_auth :: EVP_VerifyUpdate");
(void)ipssh_send_userauth_failure_msg(ssh_conn, IPSSH_NONE_STR, 0);
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if (EVP_VerifyFinal(&md_ctx, sig, sig_len, clt_pub_key) == 0)
{
IPCOM_LOG0(ERR, "ipssh_handle_hostbased_auth :: failed to verify signature");
(void)ipssh_send_userauth_failure_msg(ssh_conn, IPSSH_NONE_STR, 0);
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
ssh_conn->auth_state |= IPSSH_AUTH_HOSTBASED_DONE;
ssh_conn->auth_meth = IPSSH_AUTH_METH_HOSTBASED;
rc = IPSSH_AUTH_OK;
cleanup:
if (clt_pub_key)
EVP_PKEY_free(clt_pub_key);
if (pk_alg_name)
ipcom_free(pk_alg_name);
if (cl_host_name)
ipcom_free(cl_host_name);
if (cl_user_name)
ipcom_free(cl_user_name);
if (sig_buf)
ipcom_buffer_free(sig_buf);
if (sig)
ipcom_free(sig);
(void)EVP_MD_CTX_cleanup(&md_ctx);
return rc;
}
/*
*===========================================================================
* ipssh_send_userauth_req_pubkey
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
ipssh_send_userauth_req_pubkey(Ipssh_conn* ssh_conn)
{
Ip_size_t sig_blob_len_pos;
unsigned int sig_len;
Ip_u32 len;
Ip_size_t buf_size;
Ipcom_buffer* sig_buf = IP_NULL;
Ipcom_buffer* pkt = IP_NULL;
EVP_MD_CTX md_ctx;
Ip_err rc = IPCOM_ERR_FAILED;
char* key_type_str;
int sig_len_pos = 0;
char* dsa_sig_buf = IP_NULL;
unsigned char* tmp_dsa_sig_buf;
DSA_SIG* dsa_sig = IP_NULL;
ipcom_memset(&md_ctx, 0, sizeof(md_ctx));
buf_size = 512 + EVP_PKEY_bits(ssh_conn->data.clt.key)/2;
pkt = ipssh_buffer_new_v2_pkt(buf_size, IPSSH_MSG_USERAUTH_REQUEST);
sig_buf = ipcom_buffer_new(buf_size);
if (!sig_buf || !pkt)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_pubkey :: out of memory");
goto cleanup;
}
switch (ssh_conn->data.clt.key->type)
{
case NID_dsa:
key_type_str = IPSSH_DSA_STR;
break;
case NID_rsaEncryption:
key_type_str = IPSSH_RSA_STR;
break;
default:
IP_PANIC();
key_type_str = "Unknown key type";
}
/* Create first part of message */
if (ipssh_buffer_put_sshstr(pkt, ssh_conn->data.clt.userid)
|| ipssh_buffer_put_sshstr(pkt, IPSSH_CONNECTION_STR)
|| ipssh_buffer_put_sshstr(pkt, IPSSH_PUBKEY_AUTH_STR)
|| ipcom_buffer_put_char(pkt, 1)
|| ipssh_buffer_put_sshstr(pkt, key_type_str)
|| ipssh_buffer_put_pub_key(pkt, ssh_conn->data.clt.key))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_pubkey :: failed to assemble USERAUTH_REQ for pubkey");
goto cleanup;
}
sig_blob_len_pos = ipcom_buffer_len(pkt);
if (ipcom_buffer_decr_cap(pkt, 4) || ipssh_buffer_put_sshstr(pkt, key_type_str))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_pubkey :: failed to assemble USERAUTH_REQ for pubkey");
goto cleanup;
}
/* Create signature */
if (ipssh_buffer_put_sshbuf(sig_buf, ssh_conn->sess_id, ssh_conn->sess_id_len)
|| ipcom_buffer_put_char(sig_buf, IPSSH_MSG_USERAUTH_REQUEST)
|| ipssh_buffer_put_sshstr(sig_buf, ssh_conn->data.clt.userid)
|| ipssh_buffer_put_sshstr(sig_buf, IPSSH_CONNECTION_STR)
|| ipssh_buffer_put_sshstr(sig_buf, IPSSH_PUBKEY_AUTH_STR)
|| ipcom_buffer_put_char(sig_buf, 1)
|| ipssh_buffer_put_sshstr(sig_buf, key_type_str)
|| ipssh_buffer_put_pub_key(sig_buf, ssh_conn->data.clt.key))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_pubkey :: failed to assemble sig data");
goto cleanup;
}
#ifdef IPSSH_DEBUG_PK_AUTH
ipcom_buffer_dump(sig_buf);
#endif
sig_len_pos = ipcom_buffer_len(pkt);
if (ipcom_buffer_decr_cap(pkt, 4))
goto cleanup;
switch (ssh_conn->data.clt.key->type)
{
case NID_dsa:
dsa_sig_buf = ipcom_malloc(EVP_PKEY_size(ssh_conn->data.clt.key));
if (!dsa_sig_buf)
goto cleanup;
tmp_dsa_sig_buf = dsa_sig_buf;
if (!EVP_SignInit(&md_ctx, EVP_dss1()) ||
!EVP_SignUpdate(&md_ctx, ipcom_buffer_start_ptr(sig_buf), ipcom_buffer_len(sig_buf)) ||
!EVP_SignFinal(&md_ctx, dsa_sig_buf , &sig_len, ssh_conn->data.clt.key))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_pubkey :: EVP_Sign*(&md_ctx, EVP_dss1())) failed");
goto cleanup;
}
ip_assert(sig_len <= EVP_PKEY_size(ssh_conn->data.clt.key));
dsa_sig = d2i_DSA_SIG(IP_NULL, &tmp_dsa_sig_buf, sig_len);
if (!dsa_sig)
goto cleanup;
if (ipssh_buffer_put_dsa_sig(pkt, dsa_sig))
goto cleanup;
IP_SET_32ON8(ipcom_buffer_ptr2pos(pkt, sig_len_pos), ip_htonl(ipcom_buffer_len(pkt)-sig_len_pos-4));
break;
case NID_rsaEncryption:
if (!EVP_SignInit(&md_ctx, EVP_sha1()) ||
!EVP_SignUpdate(&md_ctx, ipcom_buffer_start_ptr(sig_buf), ipcom_buffer_len(sig_buf)) ||
!EVP_SignFinal(&md_ctx, ipcom_buffer_end_ptr(pkt), &sig_len, ssh_conn->data.clt.key))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_pubkey :: sign operation failed");
goto cleanup;
}
if (ipcom_buffer_decr_cap(pkt, sig_len))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_pubkey :: failed to assemble USERAUTH_REQ for pubkey");
goto cleanup;
}
IP_SET_32ON8(ipcom_buffer_ptr2pos(pkt, sig_len_pos), ip_htonl(sig_len));
break;
default:
IP_PANIC();
goto cleanup;
}
len = (Ip_u32)(ipcom_buffer_len(pkt) - sig_blob_len_pos);
IP_SET_32ON8(ipcom_buffer_ptr2pos(pkt, sig_blob_len_pos), ip_htonl(len-4));
if (ipssh_send_pkt(ssh_conn, pkt, IP_FALSE) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_pubkey :: ipssh_send_pkt failed");
goto cleanup;
}
rc = IPCOM_SUCCESS;
cleanup:
if (dsa_sig)
DSA_SIG_free(dsa_sig);
if (dsa_sig_buf)
ipcom_free(dsa_sig_buf);
ipcom_free(sig_buf);
ipcom_free(pkt);
(void)EVP_MD_CTX_cleanup(&md_ctx);
return rc;
}
/*
*===========================================================================
* ipssh_send_userauth_req_hostbased
*===========================================================================
* Description: Send the hostbased authentication request msg.
* Parameters:ssh_conn - ssh connection pointer
* Returns:IPCOM_SUCCESS for send ok
* <0 for failure
*
*/
IP_STATIC Ip_err
ipssh_send_userauth_req_hostbased(Ipssh_conn* ssh_conn)
{
/* byte SSH_MSG_USERAUTH_REQUEST
* string user name
* string service name
* string "hostbased"
* string public key algorithm for host key
* string public host key and certificates for client host
* string client host name expressed as the FQDN in US-ASCII
* string user name on the client host in ISO-10646 UTF-8 encoding
[RFC3629]
* string signature
*/
Ip_size_t sig_blob_len_pos;
unsigned int sig_len;
Ip_u32 len;
Ip_size_t buf_size;
Ipcom_buffer* sig_buf = IP_NULL;
Ipcom_buffer* pkt = IP_NULL;
EVP_MD_CTX md_ctx;
Ip_err rc = IPCOM_ERR_FAILED;
char* key_type_str;
int sig_len_pos = 0;
char hostname[IPSSH_FQDN_MAXLEN];
char *domain = IP_NULL;
char* dsa_sig_buf = IP_NULL;
char* tmp_dsa_sig_buf;
DSA_SIG* dsa_sig = IP_NULL;
ipcom_memset(&md_ctx, 0, sizeof(md_ctx));
ipcom_memset(hostname, 0, IPSSH_FQDN_MAXLEN);
buf_size = 512 + EVP_PKEY_bits(ssh_conn->data.clt.host_key)/2;
pkt = ipssh_buffer_new_v2_pkt(buf_size, IPSSH_MSG_USERAUTH_REQUEST);
sig_buf = ipcom_buffer_new(buf_size);
if (!sig_buf || !pkt)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_hostbased :: out of memory");
goto cleanup;
}
switch (ssh_conn->data.clt.host_key->type)
{
case NID_dsa:
key_type_str = IPSSH_DSA_STR;
break;
case NID_rsaEncryption:
key_type_str = IPSSH_RSA_STR;
break;
default:
IP_PANIC();
key_type_str = "Unknown key type";
}
/* Get domain name */
domain = ipcom_sysvar_get("ipdnsc.domainname", IP_NULL, IP_NULL);
if (IP_NULL == domain)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_hostbased :: get domain name failed");
goto cleanup;
}
/* Get local hostname first */
if (ipcom_gethostname(hostname, sizeof(hostname)) != 0)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_hostbased :: get hostname failed");
goto cleanup;
}
/* We must consider the "." between domain name and host name and also the "." in the end */
if (ipcom_strlen (domain) + ipcom_strlen (hostname) > IPSSH_FQDN_MAXLEN - 2)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_hostbased :: fqdn hostname too long");
goto cleanup;
}
ipcom_strcat(hostname, ".");
ipcom_strcat(hostname, domain);
/* The fqdn is ended by a "." */
ipcom_strcat(hostname, ".");
/* Create first part of message */
if (ipssh_buffer_put_sshstr(pkt, ssh_conn->data.clt.userid)
|| ipssh_buffer_put_sshstr(pkt, IPSSH_CONNECTION_STR)
|| ipssh_buffer_put_sshstr(pkt, IPSSH_HOSTBASED_AUTH_STR)
|| ipssh_buffer_put_sshstr(pkt, key_type_str)
|| ipssh_buffer_put_pub_key(pkt, ssh_conn->data.clt.host_key)
|| ipssh_buffer_put_sshstr(pkt, hostname)
|| ipssh_buffer_put_sshstr(pkt, ssh_conn->data.clt.userid))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_hostbased :: failed to assemble USERAUTH_REQ for hostbased");
goto cleanup;
}
sig_blob_len_pos = ipcom_buffer_len(pkt);
if (ipcom_buffer_decr_cap(pkt, 4) || ipssh_buffer_put_sshstr(pkt, key_type_str))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_hostbased :: failed to assemble USERAUTH_REQ for hostbased");
goto cleanup;
}
/* Create signature */
if (ipssh_buffer_put_sshbuf(sig_buf, ssh_conn->sess_id, (Ip_size_t)ssh_conn->sess_id_len)
|| ipcom_buffer_put_char(sig_buf, IPSSH_MSG_USERAUTH_REQUEST)
|| ipssh_buffer_put_sshstr(sig_buf, ssh_conn->data.clt.userid)
|| ipssh_buffer_put_sshstr(sig_buf, IPSSH_CONNECTION_STR)
|| ipssh_buffer_put_sshstr(sig_buf, IPSSH_HOSTBASED_AUTH_STR)
|| ipssh_buffer_put_sshstr(sig_buf, key_type_str)
|| ipssh_buffer_put_pub_key(sig_buf, ssh_conn->data.clt.host_key)
|| ipssh_buffer_put_sshstr(sig_buf, hostname)
|| ipssh_buffer_put_sshstr(sig_buf, ssh_conn->data.clt.userid))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_hostbased :: failed to assemble sig data");
goto cleanup;
}
sig_len_pos = ipcom_buffer_len(pkt);
if (ipcom_buffer_decr_cap(pkt, 4))
goto cleanup;
switch (ssh_conn->data.clt.host_key->type)
{
case NID_dsa:
dsa_sig_buf = ipcom_malloc(EVP_PKEY_size(ssh_conn->data.clt.host_key));
if (!dsa_sig_buf)
goto cleanup;
tmp_dsa_sig_buf = dsa_sig_buf;
if (!EVP_SignInit(&md_ctx, EVP_dss1())
|| !EVP_SignUpdate(&md_ctx, ipcom_buffer_start_ptr(sig_buf), ipcom_buffer_len(sig_buf))
|| !EVP_SignFinal(&md_ctx, dsa_sig_buf, &sig_len, ssh_conn->data.clt.host_key))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_hostbased :: DSA sign operation failed");
goto cleanup;
}
ip_assert(sig_len <= EVP_PKEY_size(ssh_conn->data.clt.host_key));
dsa_sig = d2i_DSA_SIG(IP_NULL, &tmp_dsa_sig_buf, sig_len);
if (!dsa_sig)
goto cleanup;
if (ipssh_buffer_put_dsa_sig(pkt, dsa_sig))
goto cleanup;
IP_SET_32ON8(ipcom_buffer_ptr2pos(pkt, sig_len_pos), ip_htonl(ipcom_buffer_len(pkt)-sig_len_pos-4));
break;
case NID_rsaEncryption:
if (!EVP_SignInit(&md_ctx, EVP_sha1())
|| !EVP_SignUpdate(&md_ctx, ipcom_buffer_start_ptr(sig_buf), ipcom_buffer_len(sig_buf))
|| !EVP_SignFinal(&md_ctx, ipcom_buffer_end_ptr(pkt), &sig_len, ssh_conn->data.clt.host_key))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_hostbased :: RSA sign operation failed");
goto cleanup;
}
IP_SET_32ON8(ipcom_buffer_ptr2pos(pkt, (Ip_size_t)sig_len_pos), ip_htonl(sig_len));
if (ipcom_buffer_decr_cap(pkt, (Ip_size_t)sig_len))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_hostbased :: failed to assemble USERAUTH_REQ for pubkey");
goto cleanup;
}
break;
default:
IP_PANIC();
goto cleanup;
}
len = (Ip_u32)(ipcom_buffer_len(pkt) - sig_blob_len_pos);
IP_SET_32ON8(ipcom_buffer_ptr2pos(pkt, sig_blob_len_pos), ip_htonl(len-4));
if (ipssh_send_pkt(ssh_conn, pkt, IP_FALSE) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_hostbased :: ipssh_send_pkt failed");
goto cleanup;
}
rc = IPCOM_SUCCESS;
cleanup:
if (domain)
{
ipcom_free(domain);
}
if (sig_buf)
{
ipcom_free(sig_buf);
}
if (pkt)
{
ipcom_free(pkt);
}
if (dsa_sig_buf)
ipcom_free(dsa_sig_buf);
if (dsa_sig)
DSA_SIG_free(dsa_sig);
(void)EVP_MD_CTX_cleanup(&md_ctx);
return rc;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipssh_send_msg_userauth_pk_ok
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_send_msg_userauth_pk_ok(Ipssh_conn* ssh_conn, char* alg_name, Ip_u8* pub_key, Ip_size_t pub_key_len)
{
Ipcom_buffer* pkt;
IPCOM_LOG0(DEBUG, "ipssh_send_msg_userauth_pk_ok :: ");
pkt = ipssh_buffer_new_v2_pkt(128 + pub_key_len, IPSSH_MSG_USERAUTH_PK_OK);
if (!pkt)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_pk_ok :: out of memory");
return IPCOM_ERR_FAILED;
}
(void)ipssh_buffer_put_sshstr(pkt, alg_name);
(void)ipssh_buffer_put_sshbuf(pkt, pub_key, pub_key_len);
if (ipssh_send_pkt(ssh_conn, pkt, IP_TRUE))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_pk_ok :: ipssh_send_pkt() failed");
return IPCOM_ERR_FAILED;
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_send_userauth_failure_msg
*===========================================================================
*/
IP_GLOBAL Ip_err
ipssh_send_userauth_failure_msg(Ipssh_conn* ssh_conn, char* supported_meths, Ip_u8 success)
{
Ipcom_buffer* pkt;
IPCOM_LOG1(DEBUG, "ipssh_send_userauth_failure_msg :: success: %d", success);
pkt = ipssh_buffer_new_v2_pkt(128 + ipcom_strlen(supported_meths), IPSSH_MSG_USERAUTH_FAILURE);
if (!pkt)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_failure_msg :: out of memory");
return IPCOM_ERR_FAILED;
}
(void)ipssh_buffer_put_sshstr(pkt, supported_meths);
(void)ipcom_buffer_put_char(pkt, success);
if (ipssh_send_pkt(ssh_conn, pkt, IP_TRUE))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_failure_msg :: ipssh_send_pkt() failed");
return IPCOM_ERR_FAILED;
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_send_userauth_success_msg
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_send_userauth_success_msg(Ipssh_conn* ssh_conn)
{
Ipcom_buffer* pkt;
IPCOM_LOG0(DEBUG, "ipssh_send_userauth_success_msg :: ");
pkt = ipssh_buffer_new_v2_pkt(128, IPSSH_MSG_USERAUTH_SUCCESS);
if (!pkt)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_success_msg :: out of memory");
return IPCOM_ERR_FAILED;
}
if (ipssh_send_pkt(ssh_conn, pkt, IP_TRUE))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_success_msg :: ipssh_send_pkt() failed");
return IPCOM_ERR_FAILED;
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_msg_userauth_failure
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_msg_userauth_failure(Ipssh_conn* ssh_conn)
{
Ipcom_buffer* pkt = IP_NULL;
char* auth_methods;
char* auth_meth;
char* last;
Ip_u8 success;
Ip_err rc = IPCOM_ERR_FAILED;
Ip_bool pw_auth = IP_FALSE;
Ip_bool pubkey_auth = IP_FALSE;
Ip_bool hostbsd_auth = IP_FALSE;
EVP_MD_CTX md_ctx;
ipcom_memset(&md_ctx, 0, sizeof(md_ctx));
(void)ipcom_buffer_consume(ssh_conn->recv_plain_buf, 6);
if ((auth_methods = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf)) == IP_NULL
|| ipcom_buffer_get_char(ssh_conn->recv_plain_buf, &success) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_failure :: failed to unpack msg");
goto cleanup;
}
IPCOM_LOG2(DEBUG, "ipssh_msg_userauth_failure :: methods: %s, success: %d", auth_methods, success);
for(auth_meth = ipcom_strtok_r(auth_methods, ",", &last);
auth_meth;
auth_meth = ipcom_strtok_r(IP_NULL, ",", &last))
{
if (ipcom_strcmp(auth_meth, IPSSH_PW_AUTH_STR) == 0)
pw_auth = IP_TRUE;
else if (ipcom_strcmp(auth_meth, IPSSH_PUBKEY_AUTH_STR) == 0)
pubkey_auth = IP_TRUE;
else if (ipcom_strcmp(auth_meth, IPSSH_HOSTBASED_AUTH_STR) == 0)
hostbsd_auth = IP_TRUE;
else
{
IPCOM_LOG1(DEBUG2, "ipssh_msg_userauth_failure :: unknown auth method: %s", auth_meth);
}
}
if (!pw_auth && !pubkey_auth && !hostbsd_auth)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_failure :: no supported auth methods offered by server");
goto cleanup;
}
if (pubkey_auth /* Does server allow pubkey auth? */
&& ssh_conn->data.clt.key /* Do we have a pubkey? */
&& !(ssh_conn->data.clt.auth_flags & IPSSH_AUTH_METH_PUBLIC_KEY)) /* Have we tried pubkey auth already? */
{
if (ipssh_send_userauth_req_pubkey(ssh_conn) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_failure :: ipssh_send_userauth_req_pubkey() failed");
goto cleanup;
}
ssh_conn->data.clt.auth_flags |= IPSSH_AUTH_METH_PUBLIC_KEY;
}
else if (pw_auth /* Does server accept password authentication?*/
&& ssh_conn->data.clt.userid[0] && ssh_conn->data.clt.pw[0] /* Do we have pw auth data? */
&& !(ssh_conn->data.clt.auth_flags & IPSSH_AUTH_METH_PW)) /* Have we tried pw auth already? */
{
pkt = ipssh_buffer_new_v2_pkt(128, IPSSH_MSG_USERAUTH_REQUEST);
if (!pkt)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_failure :: no supported auth methods offered by server");
goto cleanup;
}
if (ipssh_buffer_put_sshstr(pkt, ssh_conn->data.clt.userid) != IPCOM_SUCCESS
|| ipssh_buffer_put_sshstr(pkt, IPSSH_CONNECTION_STR) != IPCOM_SUCCESS
|| ipssh_buffer_put_sshstr(pkt, IPSSH_PW_AUTH_STR) != IPCOM_SUCCESS
|| ipcom_buffer_put_char(pkt, 0) != IPCOM_SUCCESS
|| ipssh_buffer_put_sshstr(pkt, ssh_conn->data.clt.pw) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_failure :: failed to create USERAUTH_REQUEST msg (pw)");
goto cleanup;
}
ssh_conn->data.clt.auth_flags |= IPSSH_AUTH_METH_PW;
if (ipssh_send_pkt(ssh_conn, pkt, IP_FALSE) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_failure :: ipssh_send_pkt failed");
}
}
else if (hostbsd_auth /* Does server allow hostbased auth? */
&& ssh_conn->data.clt.host_key/* Do we have a hostbased pubkey? */
&& !(ssh_conn->data.clt.auth_flags & IPSSH_AUTH_METH_HOSTBASED)) /* Have we tried hostbased auth already? */
{
if (ipssh_send_userauth_req_hostbased(ssh_conn) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_failure :: ipssh_send_userauth_req_hostbased() failed");
goto cleanup;
}
ssh_conn->data.clt.auth_flags |= IPSSH_AUTH_METH_HOSTBASED;
}
else
{
/* No auth method available, or all available methods failed */
rc = IPCOM_ERR_AUTH_FAILED;
goto cleanup;
}
rc = IPCOM_SUCCESS;
cleanup:
EVP_MD_CTX_cleanup(&md_ctx);
if (auth_methods)
ipcom_free(auth_methods);
if (pkt)
ipcom_buffer_free(pkt);
return rc;
}
/*
*===========================================================================
* ipssh_msg_userauth_success
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_msg_userauth_success(Ipssh_conn* ssh_conn)
{
(void)ipcom_buffer_consume(ssh_conn->recv_plain_buf, 6);
ssh_conn->conn_state = IPSSH_CONN_STATE_CLT_CONNECTED;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_msg_userauth_req
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_msg_userauth_req(Ipssh_conn* ssh_conn)
{
Ip_s32 rc = IPCOM_SUCCESS;
char* user, *service, *auth_meth;
int auth_ret = IPSSH_AUTH_FAILED;
char auth_methods[29]; /* max length: "publickey,password,hostbased" */
#if defined(IP_PORT_VXWORKS) && defined(LOGINEVENT_CHECK_AUTH_STAT)
int event_err;
int auth_result = 0;
#endif
ipcom_memset(auth_methods, 0, sizeof(auth_methods));
(void)ipcom_buffer_consume(ssh_conn->recv_plain_buf, 6);
user = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf);
service = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf);
auth_meth = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf);
if (!user || !service || !auth_meth)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: out of memory");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
IPCOM_LOG3(DEBUG, "ipssh_msg_userauth_req :: user: %s, service: %s, auth_meth: %s",
user, service, auth_meth);
if (!(ssh_conn->user))
{
ssh_conn->service = service;
service = IP_NULL;
ssh_conn->user = user;
user = IP_NULL;
}
else
{
if (ipcom_strcmp(ssh_conn->user, user) || ipcom_strcmp(ssh_conn->service, service))
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: user or service changed, dropping connection");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
}
if(!ssh_conn->auth_banner_sent)
ipssh_get_banner_config(&ssh_conn->config);
#ifdef IPSSH_SUPPORT_LONG_BANNER
if (!ssh_conn->auth_banner_sent && ssh_conn->config.auth_banner)
#else
if (!ssh_conn->auth_banner_sent && ssh_conn->config.auth_banner[0])
#endif
{
ssh_conn->auth_banner_sent = IP_TRUE;
if (ipssh_send_userauth_banner_msg(ssh_conn, ssh_conn->config.auth_banner) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: ipssh_send_userauth_banner_msg failed");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if (ipssh_send_userauth_banner_msg(ssh_conn, "\r\n") != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: ipssh_send_userauth_banner_msg failed");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
}
if (ipcom_strcmp(auth_meth, IPSSH_NONE_STR) == 0)
{
if (ssh_conn->config.auth_none_allowed != 0)
auth_ret = IPSSH_AUTH_OK;
}
else if (ipcom_strcmp(auth_meth, IPSSH_PW_AUTH_STR) == 0)
{
if (!ssh_conn->config.pw_allowed)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: password auth not turned on");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
auth_ret = ipssh_handle_password_auth(ssh_conn, ssh_conn->user);
#ifdef IP_PORT_VXWORKS
#ifdef LOGINEVENT_CHECK_AUTH_STAT
if (auth_ret == IPSSH_AUTH_FAILED)
auth_result = SEC_EVENT_AUTH_FAILED;
else
auth_result = SEC_EVENT_AUTH_SUCCESS;
if (_func_loginEvent != IP_NULL)
event_err = _func_loginEvent(SEC_EVENT_SSH_LOGIN, ssh_conn->user, ssh_conn->sock, SEC_EVENT_AUTH_PASSWD, auth_result);
if (event_err != 0)
auth_ret = IPSSH_AUTH_FAILED;
#else
if (auth_ret != IPSSH_AUTH_FAILED)
{
if (_func_loginEvent != IP_NULL)
_func_loginEvent(SEC_EVENT_SSH_LOGIN, ssh_conn->user, ssh_conn->sock, SEC_EVENT_AUTH_PASSWD);
}
#endif
#endif
if (auth_ret == IPSSH_AUTH_FAILED)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: ipssh_handle_password_auth() failed");
}
}
else if (ipcom_strcmp(auth_meth, IPSSH_PUBKEY_AUTH_STR) == 0)
{
if (!ssh_conn->config.pub_key_allowed)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: publickey auth not turned on");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
auth_ret = ipssh_handle_publickey_auth(ssh_conn, ssh_conn->user);
#ifdef IP_PORT_VXWORKS
#ifdef LOGINEVENT_CHECK_AUTH_STAT
if (auth_ret == IPSSH_AUTH_FAILED)
auth_result = SEC_EVENT_AUTH_FAILED;
else
auth_result = SEC_EVENT_AUTH_SUCCESS;
if (_func_loginEvent != IP_NULL)
event_err = _func_loginEvent(SEC_EVENT_SSH_LOGIN, ssh_conn->user, ssh_conn->sock, SEC_EVENT_AUTH_PUBKEY, auth_result);
if (event_err != 0)
auth_ret = IPSSH_AUTH_FAILED;
#else
if (auth_ret != IPSSH_AUTH_FAILED)
{
if (_func_loginEvent != IP_NULL)
_func_loginEvent(SEC_EVENT_SSH_LOGIN, ssh_conn->user, ssh_conn->sock, SEC_EVENT_AUTH_PUBKEY);
}
#endif
#endif
if (auth_ret == IPSSH_AUTH_FAILED)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: ipssh_handle_publickey_auth() failed");
}
}
else if (ipcom_strcmp(auth_meth, IPSSH_HOSTBASED_AUTH_STR) == 0)
{
if (!ssh_conn->config.hostbased_allowed)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: hostbased auth not turned on");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
auth_ret = ipssh_handle_hostbased_auth(ssh_conn, ssh_conn->user);
#ifdef IP_PORT_VXWORKS
#ifdef LOGINEVENT_CHECK_AUTH_STAT
if (auth_ret == IPSSH_AUTH_FAILED)
auth_result = SEC_EVENT_AUTH_FAILED;
else
auth_result = SEC_EVENT_AUTH_SUCCESS;
if (_func_loginEvent != IP_NULL)
event_err = _func_loginEvent(SEC_EVENT_SSH_LOGIN, ssh_conn->user, ssh_conn->sock, SEC_EVENT_AUTH_HOSTBASED, auth_result);
if (event_err != 0)
auth_ret = IPSSH_AUTH_FAILED;
#else
if (auth_ret != IPSSH_AUTH_FAILED)
{
if (_func_loginEvent != IP_NULL)
_func_loginEvent(SEC_EVENT_SSH_LOGIN, ssh_conn->user, ssh_conn->sock, SEC_EVENT_AUTH_HOSTBASED);
}
#endif
#endif
if (auth_ret == IPSSH_AUTH_FAILED)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: ipssh_handle_hostbased_auth() failed");
}
}
else
{
IPCOM_LOG1(ERR, "ipssh_msg_userauth_req :: unknown authentication method requested: %s", auth_meth);
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
switch(auth_ret)
{
case IPSSH_AUTH_FAILED:
if (ssh_conn->config.max_fail != 0 && ssh_conn->auth_failure_count >= ssh_conn->config.max_fail)
{
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
/* Deliberate pass-through to next case */
case IPSSH_AUTH_OK:
if (ipssh_more_auth_needed(ssh_conn) == IP_TRUE)
{
ipssh_get_auth_methods(ssh_conn, auth_methods, sizeof(auth_methods));
if (ipssh_send_userauth_failure_msg(ssh_conn, auth_methods, (Ip_u8)auth_ret) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: ipssh_send_userauth_failure_msg() failed");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
}
else
{
/* Send success message and update the connection state, authentication is complete */
if (ipssh_send_userauth_success_msg(ssh_conn))
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: ipssh_send_userauth_success_msg() failed");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
(void)ipcom_shell_ctx_add_user(ssh_conn->sh_ctx, ssh_conn->user);
if (ipssh_auth_complete_cb(ssh_conn->user, ssh_conn->sh_ctx) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_msg_userauth_req :: ipssh_auth_complete_cb() failed");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
ssh_conn->conn_state = IPSSH_CONN_STATE_SRV_TERM;
}
break;
case IPSSH_AUTH_PUBKEY_OK:
break;
case IPCOM_ERR_FAILED:
case IPSSH_AUTH_FATAL:
rc = IPCOM_ERR_FAILED;
goto cleanup;
default:
IP_PANIC();
rc = IPCOM_ERR_FAILED;
}
cleanup:
if (user)
ipcom_free(user);
if (service)
ipcom_free(service);
if (auth_meth)
ipcom_free(auth_meth);
return rc;
}
/*
*===========================================================================
* ipssh_send_userauth_req_none
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_send_userauth_req_none(Ipssh_conn* ssh_conn, const char* user)
{
Ipcom_buffer* pkt;
IPCOM_LOG0(DEBUG, "ipssh_send_userauth_req_none :: ");
pkt = ipssh_buffer_new_v2_pkt(64+ipcom_strlen(user), IPSSH_MSG_USERAUTH_REQUEST);
if (!pkt)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_none :: out of memory");
return IPCOM_ERR_FAILED;
}
(void)ipssh_buffer_put_sshstr(pkt, user);
(void)ipssh_buffer_put_sshstr(pkt, IPSSH_CONNECTION_STR);
(void)ipssh_buffer_put_sshstr(pkt, IPSSH_NONE_STR);
if (ipssh_send_pkt(ssh_conn, pkt, IP_TRUE))
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_req_none :: ipssh_send_pkt() failed");
return IPCOM_ERR_FAILED;
}
ssh_conn->conn_state = IPSSH_CONN_STATE_CLT_USER_AUTH;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_do_user_auth_clt
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_do_user_auth_clt(Ipssh_conn* ssh_conn)
{
Ip_err rc;
while(ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED)
{
switch(ssh_conn->conn_state)
{
case IPSSH_CONN_STATE_SERVICE_REQ:
rc = ipssh_send_service_request(ssh_conn, IPSSH_USERAUTH_STR);
if (rc != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_do_user_auth_clt :: ipssh_send_service_request");
return rc;
}
break;
case IPSSH_CONN_STATE_CLT_USER_AUTH:
case IPSSH_CONN_STATE_SERVICE_ACCEPT:
rc = ipssh_read_v2_pkt(ssh_conn);
if (rc != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_do_user_auth_clt :: ipssh_read_v2_pkt_type failed");
return rc;
}
rc = ipssh_pkt_dispatch(ssh_conn);
if (rc != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_do_user_auth_clt :: ipssh_pkt_dispatch failed");
return rc;
}
break;
case IPSSH_CONN_STATE_CLT_USER_AUTH_START:
rc = ipssh_send_userauth_req_none(ssh_conn, ssh_conn->data.clt.userid);
if (rc != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_do_user_auth_clt :: ipssh_send_userauth_req failed");
return rc;
}
break;
default:
break;
}
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_msg_userauth_banner
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_msg_userauth_banner(Ipssh_conn* ssh_conn)
{
char* msg;
char* lang_tag;
(void)ipcom_buffer_consume(ssh_conn->recv_plain_buf, 6);
msg = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf);
lang_tag = ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf);
if(msg)
{
IPCOM_LOG1(DEBUG, "USERAUTH banner: msg %s", msg);
}
if(msg)
ipcom_free(msg);
if(lang_tag)
ipcom_free(lang_tag);
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_send_userauth_banner_msg
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_send_userauth_banner_msg(Ipssh_conn* ssh_conn, const char* auth_banner)
{
Ipcom_buffer* pkt;
IPCOM_LOG0(DEBUG, "ipssh_send_userauth_banner_msg :: ");
pkt = ipssh_buffer_new_v2_pkt(64+ipcom_strlen(auth_banner), IPSSH_MSG_USERAUTH_BANNER);
if (!pkt)
{
IPCOM_LOG0(ERR, "ipssh_send_userauth_banner_msg :: out of memory");
return IPCOM_ERR_FAILED;
}
(void)ipssh_buffer_put_sshstr(pkt, auth_banner);
(void)ipssh_buffer_put_sshstr(pkt, ""); /* Language tag, not used */
return ipssh_send_pkt(ssh_conn, pkt, IP_TRUE);
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/