From 076e884873315131363a4350c538fac6a028da53 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis Date: Sat, 5 Dec 2009 15:05:02 +0100 Subject: More callback stuff in connection I have coded it, not actually tested it :) It still needs work to get past the banner exchange. --- include/libssh/priv.h | 1 - include/libssh/session.h | 1 + libssh/client.c | 181 +++++++++++++++++++++++------------------------ libssh/server.c | 7 ++ 4 files changed, 97 insertions(+), 93 deletions(-) diff --git a/include/libssh/priv.h b/include/libssh/priv.h index d86c0d96..c251140a 100644 --- a/include/libssh/priv.h +++ b/include/libssh/priv.h @@ -120,7 +120,6 @@ SSH_PACKET_CALLBACK(ssh_packet_ignore_callback); /* client.c */ int ssh_send_banner(ssh_session session, int is_server); -char *ssh_get_banner(ssh_session session); /* config.c */ int ssh_config_parse_file(ssh_session session, const char *filename); diff --git a/include/libssh/session.h b/include/libssh/session.h index c8736dde..cea2f739 100644 --- a/include/libssh/session.h +++ b/include/libssh/session.h @@ -34,6 +34,7 @@ enum ssh_session_state_e { SSH_SESSION_STATE_SOCKET_CONNECTED, SSH_SESSION_STATE_BANNER_RECEIVED, SSH_SESSION_STATE_INITIAL_KEX, + SSH_SESSION_STATE_AUTHENTICATING, SSH_SESSION_STATE_AUTHENTICATED, SSH_SESSION_STATE_ERROR }; diff --git a/libssh/client.c b/libssh/client.c index 0c9357af..d4f5f5ca 100644 --- a/libssh/client.c +++ b/libssh/client.c @@ -42,6 +42,7 @@ session->callbacks->connect_status_function(session->callbacks->userdata, status); \ } while (0) +static void connection_callback(ssh_session session); /** * @internal * @brief Callback to be called when the socket is connected or had a @@ -60,6 +61,7 @@ static void socket_callback_connected(int code, int errno, void *user){ session->session_state=SSH_SESSION_STATE_ERROR; ssh_set_error(session,SSH_FATAL,"Connection failed: %s",strerror(errno)); } + connection_callback(session); leave_function(); } @@ -96,6 +98,7 @@ static int callback_receive_banner(const void *data, size_t len, void *user) { ret=i+1; session->remotebanner=str; session->session_state=SSH_SESSION_STATE_BANNER_RECEIVED; + connection_callback(session); leave_function(); return ret; } @@ -494,6 +497,88 @@ int ssh_service_request(ssh_session session, const char *service) { * @{ */ +/** @internal + * @function to be called each time a step has been done in the connection + */ +static void connection_callback(ssh_session session){ + int ssh1,ssh2; + enter_function(); + switch(session->session_state){ + case SSH_SESSION_STATE_NONE: + case SSH_SESSION_STATE_CONNECTING: + case SSH_SESSION_STATE_SOCKET_CONNECTED: + case SSH_SESSION_STATE_BANNER_RECEIVED: + if (session->serverbanner == NULL) { + goto error; + } + set_status(session, 0.4); + ssh_log(session, SSH_LOG_RARE, + "SSH server banner: %s", session->serverbanner); + + /* Here we analyse the different protocols the server allows. */ + if (ssh_analyze_banner(session, &ssh1, &ssh2) < 0) { + goto error; + } + /* Here we decide which version of the protocol to use. */ + if (ssh2 && session->ssh2) { + session->version = 2; + } else if(ssh1 && session->ssh1) { + session->version = 1; + } else { + ssh_set_error(session, SSH_FATAL, + "No version of SSH protocol usable (banner: %s)", + session->serverbanner); + goto error; + } + /* from now, the packet layer is handling incoming packets */ + session->socket_callbacks.data=ssh_packet_socket_callback; + ssh_send_banner(session, 0); + set_status(session, 0.5); + session->session_state=SSH_SESSION_STATE_INITIAL_KEX; + case SSH_SESSION_STATE_INITIAL_KEX: + switch (session->version) { + case 2: + ssh_get_kex(session,0); + set_status(session,0.6); + + ssh_list_kex(session, &session->server_kex); + if (set_kex(session) < 0) { + goto error; + } + if (ssh_send_kex(session, 0) < 0) { + goto error; + } + set_status(session,0.8); + + if (dh_handshake(session) < 0) { + goto error; + } + set_status(session,1.0); + session->connected = 1; + break; + case 1: + if (ssh_get_kex1(session) < 0) + goto error; + set_status(session,0.6); + + session->connected = 1; + break; + } + session->session_state=SSH_SESSION_STATE_AUTHENTICATING; + case SSH_SESSION_STATE_AUTHENTICATING: + break; + default: + ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state); + } + leave_function(); + return; + error: + ssh_socket_close(session->socket); + session->alive = 0; + session->session_state=SSH_SESSION_STATE_ERROR; + leave_function(); +} + /** \brief connect to the ssh server * \param session ssh session * \return SSH_OK on success, SSH_ERROR on error @@ -501,8 +586,6 @@ int ssh_service_request(ssh_session session, const char *service) { * \see ssh_disconnect() */ int ssh_connect(ssh_session session) { - int ssh1 = 0; - int ssh2 = 0; int ret; if (session == NULL) { @@ -545,98 +628,12 @@ int ssh_connect(ssh_session session) { set_status(session, 0.2); session->alive = 1; - session->serverbanner = ssh_get_banner(session); - if (session->serverbanner == NULL) { - ssh_socket_close(session->socket); - session->alive = 0; - leave_function(); - return SSH_ERROR; - } - set_status(session, 0.4); - - ssh_log(session, SSH_LOG_RARE, - "SSH server banner: %s", session->serverbanner); - - /* Here we analyse the different protocols the server allows. */ - if (ssh_analyze_banner(session, &ssh1, &ssh2) < 0) { - ssh_socket_close(session->socket); - session->alive = 0; - leave_function(); - return SSH_ERROR; - } - - /* Here we decide which version of the protocol to use. */ - if (ssh2 && session->ssh2) { - session->version = 2; - } else if(ssh1 && session->ssh1) { - session->version = 1; - } else { - ssh_set_error(session, SSH_FATAL, - "No version of SSH protocol usable (banner: %s)", - session->serverbanner); - ssh_socket_close(session->socket); - session->alive = 0; - leave_function(); - return SSH_ERROR; - } - - if (ssh_send_banner(session, 0) < 0) { - ssh_set_error(session, SSH_FATAL, "Sending the banner failed"); - ssh_socket_close(session->socket); - session->alive = 0; - leave_function(); - return SSH_ERROR; - } - set_status(session, 0.5); - - switch (session->version) { - case 2: - if (ssh_get_kex(session,0) < 0) { - ssh_socket_close(session->socket); - session->alive = 0; - leave_function(); - return SSH_ERROR; - } - set_status(session,0.6); - - ssh_list_kex(session, &session->server_kex); - if (set_kex(session) < 0) { - ssh_socket_close(session->socket); - session->alive = 0; - leave_function(); - return SSH_ERROR; - } - if (ssh_send_kex(session, 0) < 0) { - ssh_socket_close(session->socket); - session->alive = 0; - leave_function(); - return SSH_ERROR; - } - set_status(session,0.8); - - if (dh_handshake(session) < 0) { - ssh_socket_close(session->socket); - session->alive = 0; - leave_function(); - return SSH_ERROR; - } - set_status(session,1.0); + while(session->session_state != SSH_SESSION_STATE_ERROR && + session->session_state != SSH_SESSION_STATE_AUTHENTICATING){ + /* loop until SSH_SESSION_STATE_BANNER_RECEIVED or + * SSH_SESSION_STATE_ERROR */ - session->connected = 1; - break; - case 1: - if (ssh_get_kex1(session) < 0) { - ssh_socket_close(session->socket); - session->alive = 0; - leave_function(); - return SSH_ERROR; - } - set_status(session,0.6); - - session->connected = 1; - break; } - leave_function(); return 0; } diff --git a/libssh/server.c b/libssh/server.c index e0502ccd..ee00f7c1 100644 --- a/libssh/server.c +++ b/libssh/server.c @@ -500,6 +500,13 @@ static int dh_handshake_server(ssh_session session) { return 0; } +/* FIXME TODO BUG + * Makes linker happy until I work on server code + */ +static char *ssh_get_banner(ssh_session session){ + (void)session; + return strdup("BUG"); +} /* Do the banner and key exchange */ int ssh_accept(ssh_session session) { if (ssh_send_banner(session, 1) < 0) { -- cgit v1.2.3