/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 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 #include #include #include #include #include #include #include #include #include #ifdef IP_PORT_VXWORKS #include #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 **************************************************************************** */