client.c   client.c 
skipping to change at line 34 skipping to change at line 34
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifndef _WIN32 #ifndef _WIN32
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#include "libssh/priv.h" #include "libssh/priv.h"
#include "libssh/ssh2.h" #include "libssh/ssh2.h"
#include "libssh/buffer.h"
#define set_status(opt,status) do {\ #include "libssh/packet.h"
if (opt->connect_status_function) \ #include "libssh/socket.h"
opt->connect_status_function(opt->connect_status_arg, status); #include "libssh/session.h"
\ #include "libssh/dh.h"
#define set_status(session, status) do {\
if (session->callbacks && session->callbacks->connect_status_functi
on) \
session->callbacks->connect_status_function(session->callbacks-
>userdata, status); \
} while (0) } while (0)
/** /**
* @internal * @internal
* *
* @brief Get a banner from a socket. * @brief Get a banner from a socket.
* *
* The caller has to free memroy. * The caller has to free memroy.
* *
* @param session The session to get the banner from. * @param session The session to get the banner from.
* *
* @return A newly allocated string with the banner or NULL on error. * @return A newly allocated string with the banner or NULL on error.
*/ */
char *ssh_get_banner(SSH_SESSION *session) { char *ssh_get_banner(ssh_session session) {
char buffer[128] = {0}; char buffer[128] = {0};
char *str = NULL; char *str = NULL;
int i; int i;
enter_function(); enter_function();
for (i = 0; i < 127; i++) { for (i = 0; i < 127; i++) {
if (ssh_socket_read(session->socket, &buffer[i], 1) != SSH_OK) { if (ssh_socket_read(session->socket, &buffer[i], 1) != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Remote host closed connection"); ssh_set_error(session, SSH_FATAL, "Remote host closed connection");
leave_function(); leave_function();
return NULL; return NULL;
} }
#ifdef WITH_PCAP
if(session->pcap_ctx && buffer[i] == '\n'){
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,
i+1);
}
#endif
if (buffer[i] == '\r') { if (buffer[i] == '\r') {
buffer[i] = '\0'; buffer[i] = '\0';
} }
if (buffer[i] == '\n') { if (buffer[i] == '\n') {
buffer[i] = '\0'; buffer[i] = '\0';
str = strdup(buffer); str = strdup(buffer);
if (str == NULL) { if (str == NULL) {
leave_function(); leave_function();
return NULL; return NULL;
} }
skipping to change at line 100 skipping to change at line 109
* server. * server.
* *
* @param session The session to analyze the banner from. * @param session The session to analyze the banner from.
* @param ssh1 The variable which is set if it is a SSHv1 server. * @param ssh1 The variable which is set if it is a SSHv1 server.
* @param ssh2 The variable which is set if it is a SSHv2 server. * @param ssh2 The variable which is set if it is a SSHv2 server.
* *
* @return 0 on success, < 0 on error. * @return 0 on success, < 0 on error.
* *
* @see ssh_get_banner() * @see ssh_get_banner()
*/ */
static int ssh_analyze_banner(SSH_SESSION *session, int *ssh1, int *ssh2) { static int ssh_analyze_banner(ssh_session session, int *ssh1, int *ssh2) {
const char *banner = session->serverbanner; const char *banner = session->serverbanner;
const char *openssh; const char *openssh;
ssh_log(session, SSH_LOG_RARE, "Analyzing banner: %s", banner); ssh_log(session, SSH_LOG_RARE, "Analyzing banner: %s", banner);
if (strncmp(banner, "SSH-", 4) != 0) { if (strncmp(banner, "SSH-", 4) != 0) {
ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner); ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
return -1; return -1;
} }
skipping to change at line 158 skipping to change at line 167
/** @internal /** @internal
* @brief Sends a SSH banner to the server. * @brief Sends a SSH banner to the server.
* *
* @param session The SSH session to use. * @param session The SSH session to use.
* *
* @param server Send client or server banner. * @param server Send client or server banner.
* *
* @return 0 on success, < 0 on error. * @return 0 on success, < 0 on error.
*/ */
int ssh_send_banner(SSH_SESSION *session, int server) { int ssh_send_banner(ssh_session session, int server) {
const char *banner = NULL; const char *banner = NULL;
char buffer[128] = {0}; char buffer[128] = {0};
enter_function(); enter_function();
banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2; banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
if (session->options->banner) { if (session->xbanner) {
banner = session->options->banner; banner = session->xbanner;
} }
if (server) { if (server) {
session->serverbanner = strdup(banner); session->serverbanner = strdup(banner);
if (session->serverbanner == NULL) { if (session->serverbanner == NULL) {
leave_function(); leave_function();
return -1; return -1;
} }
} else { } else {
session->clientbanner = strdup(banner); session->clientbanner = strdup(banner);
skipping to change at line 195 skipping to change at line 204
if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERRO R) { if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERRO R) {
leave_function(); leave_function();
return -1; return -1;
} }
if (ssh_socket_blocking_flush(session->socket) != SSH_OK) { if (ssh_socket_blocking_flush(session->socket) != SSH_OK) {
leave_function(); leave_function();
return -1; return -1;
} }
#ifdef WITH_PCAP
if(session->pcap_ctx)
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,buffer,str
len(buffer),strlen(buffer));
#endif
leave_function(); leave_function();
return 0; return 0;
} }
#define DH_STATE_INIT 0 #define DH_STATE_INIT 0
#define DH_STATE_INIT_TO_SEND 1 #define DH_STATE_INIT_TO_SEND 1
#define DH_STATE_INIT_SENT 2 #define DH_STATE_INIT_SENT 2
#define DH_STATE_NEWKEYS_TO_SEND 3 #define DH_STATE_NEWKEYS_TO_SEND 3
#define DH_STATE_NEWKEYS_SENT 4 #define DH_STATE_NEWKEYS_SENT 4
#define DH_STATE_FINISHED 5 #define DH_STATE_FINISHED 5
static int dh_handshake(SSH_SESSION *session) { static int dh_handshake(ssh_session session) {
STRING *e = NULL; ssh_string e = NULL;
STRING *f = NULL; ssh_string f = NULL;
STRING *pubkey = NULL; ssh_string pubkey = NULL;
STRING *signature = NULL; ssh_string signature = NULL;
int rc = SSH_ERROR; int rc = SSH_ERROR;
enter_function(); enter_function();
switch (session->dh_handshake_state) { switch (session->dh_handshake_state) {
case DH_STATE_INIT: case DH_STATE_INIT:
if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_INIT) < 0) { if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_INIT) < 0) {
goto error; goto error;
} }
skipping to change at line 416 skipping to change at line 428
* *
* @brief Request a service from the SSH server. * @brief Request a service from the SSH server.
* *
* Service requests are for example: ssh-userauth, ssh-connection, etc. * Service requests are for example: ssh-userauth, ssh-connection, etc.
* *
* @param session The session to use to ask for a service request. * @param session The session to use to ask for a service request.
* @param service The service request. * @param service The service request.
* *
* @return 0 on success, < 0 on error. * @return 0 on success, < 0 on error.
*/ */
int ssh_service_request(SSH_SESSION *session, const char *service) { int ssh_service_request(ssh_session session, const char *service) {
STRING *service_s = NULL; ssh_string service_s = NULL;
enter_function(); enter_function();
if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_REQUEST) < 0) { if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_REQUEST) < 0) {
leave_function(); leave_function();
return -1; return -1;
} }
service_s = string_from_char(service); service_s = string_from_char(service);
if (service_s == NULL) { if (service_s == NULL) {
skipping to change at line 472 skipping to change at line 484
/** \addtogroup ssh_session /** \addtogroup ssh_session
* @{ * @{
*/ */
/** \brief connect to the ssh server /** \brief connect to the ssh server
* \param session ssh session * \param session ssh session
* \return SSH_OK on success, SSH_ERROR on error * \return SSH_OK on success, SSH_ERROR on error
* \see ssh_new() * \see ssh_new()
* \see ssh_disconnect() * \see ssh_disconnect()
*/ */
int ssh_connect(SSH_SESSION *session) { int ssh_connect(ssh_session session) {
SSH_OPTIONS *options = session->options;
int ssh1 = 0; int ssh1 = 0;
int ssh2 = 0; int ssh2 = 0;
int fd = -1; int fd = -1;
if (session == NULL) { if (session == NULL) {
ssh_set_error(session, SSH_FATAL, "Invalid session pointer"); ssh_set_error(session, SSH_FATAL, "Invalid session pointer");
return SSH_ERROR; return SSH_ERROR;
} }
if (session->options == NULL) {
ssh_set_error(session, SSH_FATAL, "No options set");
return SSH_ERROR;
}
options = session->options;
enter_function(); enter_function();
session->alive = 0; session->alive = 0;
session->client = 1; session->client = 1;
if (ssh_init() < 0) { if (ssh_init() < 0) {
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
if (options->fd == -1 && options->host == NULL) { if (session->fd == -1 && session->host == NULL) {
ssh_set_error(session, SSH_FATAL, "Hostname required"); ssh_set_error(session, SSH_FATAL, "Hostname required");
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
if (options->fd != -1) { if (session->fd != -1) {
fd = options->fd; fd = session->fd;
} else { } else {
fd = ssh_connect_host(session, options->host, options->bindaddr, fd = ssh_connect_host(session, session->host, session->bindaddr,
options->port, options->timeout, options->timeout_usec); session->port, session->timeout, session->timeout_usec);
} }
if (fd < 0) { if (fd < 0) {
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
set_status(options, 0.2); set_status(session, 0.2);
ssh_socket_set_fd(session->socket, fd); ssh_socket_set_fd(session->socket, fd);
session->alive = 1; session->alive = 1;
session->serverbanner = ssh_get_banner(session); session->serverbanner = ssh_get_banner(session);
if (session->serverbanner == NULL) { if (session->serverbanner == NULL) {
ssh_socket_close(session->socket); ssh_socket_close(session->socket);
session->alive = 0; session->alive = 0;
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
set_status(options, 0.4); set_status(session, 0.4);
ssh_log(session, SSH_LOG_RARE, ssh_log(session, SSH_LOG_RARE,
"SSH server banner: %s", session->serverbanner); "SSH server banner: %s", session->serverbanner);
/* Here we analyse the different protocols the server allows. */ /* Here we analyse the different protocols the server allows. */
if (ssh_analyze_banner(session, &ssh1, &ssh2) < 0) { if (ssh_analyze_banner(session, &ssh1, &ssh2) < 0) {
ssh_socket_close(session->socket); ssh_socket_close(session->socket);
session->alive = 0; session->alive = 0;
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
/* Here we decide which version of the protocol to use. */ /* Here we decide which version of the protocol to use. */
if (ssh2 && options->ssh2allowed) { if (ssh2 && session->ssh2) {
session->version = 2; session->version = 2;
} else if(ssh1 && options->ssh1allowed) { } else if(ssh1 && session->ssh1) {
session->version = 1; session->version = 1;
} else { } else {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"No version of SSH protocol usable (banner: %s)", "No version of SSH protocol usable (banner: %s)",
session->serverbanner); session->serverbanner);
ssh_socket_close(session->socket); ssh_socket_close(session->socket);
session->alive = 0; session->alive = 0;
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
if (ssh_send_banner(session, 0) < 0) { if (ssh_send_banner(session, 0) < 0) {
ssh_set_error(session, SSH_FATAL, "Sending the banner failed"); ssh_set_error(session, SSH_FATAL, "Sending the banner failed");
ssh_socket_close(session->socket); ssh_socket_close(session->socket);
session->alive = 0; session->alive = 0;
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
set_status(options, 0.5); set_status(session, 0.5);
switch (session->version) { switch (session->version) {
case 2: case 2:
if (ssh_get_kex(session,0) < 0) { if (ssh_get_kex(session,0) < 0) {
ssh_socket_close(session->socket); ssh_socket_close(session->socket);
session->alive = 0; session->alive = 0;
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
set_status(options,0.6); set_status(session,0.6);
ssh_list_kex(session, &session->server_kex); ssh_list_kex(session, &session->server_kex);
if (set_kex(session) < 0) { if (set_kex(session) < 0) {
ssh_socket_close(session->socket); ssh_socket_close(session->socket);
session->alive = 0; session->alive = 0;
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
if (ssh_send_kex(session, 0) < 0) { if (ssh_send_kex(session, 0) < 0) {
ssh_socket_close(session->socket); ssh_socket_close(session->socket);
session->alive = 0; session->alive = 0;
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
set_status(options,0.8); set_status(session,0.8);
if (dh_handshake(session) < 0) { if (dh_handshake(session) < 0) {
ssh_socket_close(session->socket); ssh_socket_close(session->socket);
session->alive = 0; session->alive = 0;
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
set_status(options,1.0); set_status(session,1.0);
session->connected = 1; session->connected = 1;
break; break;
case 1: case 1:
if (ssh_get_kex1(session) < 0) { if (ssh_get_kex1(session) < 0) {
ssh_socket_close(session->socket); ssh_socket_close(session->socket);
session->alive = 0; session->alive = 0;
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
set_status(options,0.6); set_status(session,0.6);
session->connected = 1; session->connected = 1;
break; break;
} }
leave_function(); leave_function();
return 0; return 0;
} }
/** /**
* @brief Get the issue banner from the server. * @brief Get the issue banner from the server.
* *
* This is the banner showing a disclaimer to users who log in, * This is the banner showing a disclaimer to users who log in,
* typically their right or the fact that they will be monitored. * typically their right or the fact that they will be monitored.
* *
* @param session The SSH session to use. * @param session The SSH session to use.
* *
* @return A newly allocated string with the banner, NULL on error. * @return A newly allocated string with the banner, NULL on error.
*/ */
char *ssh_get_issue_banner(SSH_SESSION *session) { char *ssh_get_issue_banner(ssh_session session) {
if (session == NULL || session->banner == NULL) { if (session == NULL || session->banner == NULL) {
return NULL; return NULL;
} }
return string_to_char(session->banner); return string_to_char(session->banner);
} }
/** /**
* @brief Get the version of the OpenSSH server, if it is not an OpenSSH se rver * @brief Get the version of the OpenSSH server, if it is not an OpenSSH se rver
* then 0 will be returned. * then 0 will be returned.
* *
* You can use the SSH_VERSION_INT macro to compare version numbers. * You can use the SSH_VERSION_INT macro to compare version numbers.
* *
* @param session The SSH session to use. * @param session The SSH session to use.
* *
* @return The version number if available, 0 otherwise. * @return The version number if available, 0 otherwise.
*/ */
int ssh_get_openssh_version(SSH_SESSION *session) { int ssh_get_openssh_version(ssh_session session) {
if (session == NULL) { if (session == NULL) {
return 0; return 0;
} }
return session->openssh; return session->openssh;
} }
/** /**
* @brief Disconnect from a session (client or server). * @brief Disconnect from a session (client or server).
* The session can then be reused to open a new session.
* *
* @param session The SSH session to disconnect. * @param session The SSH session to disconnect.
*/ */
void ssh_disconnect(SSH_SESSION *session) { void ssh_disconnect(ssh_session session) {
STRING *str = NULL; ssh_string str = NULL;
if (session == NULL) { if (session == NULL) {
return; return;
} }
enter_function(); enter_function();
if (ssh_socket_is_open(session->socket)) { if (ssh_socket_is_open(session->socket)) {
if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) { if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) {
goto error; goto error;
skipping to change at line 691 skipping to change at line 697
} }
string_free(str); string_free(str);
packet_send(session); packet_send(session);
ssh_socket_close(session->socket); ssh_socket_close(session->socket);
} }
session->alive = 0; session->alive = 0;
error: error:
leave_function(); leave_function();
ssh_cleanup(session);
} }
const char *ssh_copyright(void) { const char *ssh_copyright(void) {
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2008 Aris Adamantiadis " return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2008 Aris Adamantiadis "
"(aris@0xbadc0de.be) Distributed under the LGPL, please refer to COPYIN G" "(aris@0xbadc0de.be) Distributed under the LGPL, please refer to COPYIN G"
"file for informations about your rights"; "file for informations about your rights";
} }
/** @} */ /** @} */
/* vim: set ts=2 sw=2 et cindent: */ /* vim: set ts=2 sw=2 et cindent: */
 End of changes. 28 change blocks. 
46 lines changed or deleted 54 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/