session.c | session.c | |||
---|---|---|---|---|
skipping to change at line 24 | skipping to change at line 24 | |||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY | |||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | |||
* License for more details. | * License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Lesser General Public License | * You should have received a copy of the GNU Lesser General Public License | |||
* along with the SSH Library; see the file COPYING. If not, write to | * along with the SSH Library; see the file COPYING. If not, write to | |||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |||
* MA 02111-1307, USA. | * MA 02111-1307, USA. | |||
*/ | */ | |||
#include "config.h" | ||||
#include <string.h> | #include <string.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include "libssh/libssh.h" | #include "libssh/libssh.h" | |||
#include "libssh/priv.h" | #include "libssh/priv.h" | |||
#include "libssh/server.h" | #include "libssh/server.h" | |||
#include "libssh/socket.h" | ||||
#include "libssh/agent.h" | ||||
#include "libssh/packet.h" | ||||
#include "libssh/session.h" | ||||
#include "libssh/misc.h" | ||||
#define FIRST_CHANNEL 42 // why not ? it helps to find bugs. | #define FIRST_CHANNEL 42 // why not ? it helps to find bugs. | |||
/** \defgroup ssh_session SSH Session | /** \defgroup ssh_session SSH Session | |||
* \brief functions that manage a session | * \brief functions that manage a session | |||
*/ | */ | |||
/** \addtogroup ssh_session | /** \addtogroup ssh_session | |||
* @{ */ | * @{ */ | |||
/** \brief creates a new ssh session | /** \brief creates a new ssh session | |||
* \returns new ssh_session pointer | * \returns new ssh_session pointer | |||
*/ | */ | |||
SSH_SESSION *ssh_new(void) { | ssh_session ssh_new(void) { | |||
SSH_SESSION *session; | ssh_session session; | |||
session = malloc(sizeof (SSH_SESSION)); | session = malloc(sizeof (struct ssh_session_struct)); | |||
if (session == NULL) { | if (session == NULL) { | |||
return NULL; | return NULL; | |||
} | } | |||
ZERO_STRUCTP(session); | ||||
memset(session, 0, sizeof(SSH_SESSION)); | ||||
session->next_crypto = crypto_new(); | session->next_crypto = crypto_new(); | |||
if (session->next_crypto == NULL) { | if (session->next_crypto == NULL) { | |||
goto err; | goto err; | |||
} | } | |||
session->maxchannel = FIRST_CHANNEL; | ||||
session->socket = ssh_socket_new(session); | session->socket = ssh_socket_new(session); | |||
if (session->socket == NULL) { | if (session->socket == NULL) { | |||
goto err; | goto err; | |||
} | } | |||
session->alive = 0; | ||||
session->auth_methods = 0; | ||||
session->blocking = 1; | ||||
session->log_indent = 0; | ||||
session->out_buffer = buffer_new(); | session->out_buffer = buffer_new(); | |||
if (session->out_buffer == NULL) { | if (session->out_buffer == NULL) { | |||
goto err; | goto err; | |||
} | } | |||
session->in_buffer=buffer_new(); | session->in_buffer=buffer_new(); | |||
if (session->in_buffer == NULL) { | if (session->in_buffer == NULL) { | |||
goto err; | goto err; | |||
} | } | |||
session->alive = 0; | ||||
session->auth_methods = 0; | ||||
session->blocking = 1; | ||||
session->log_indent = 0; | ||||
session->maxchannel = FIRST_CHANNEL; | ||||
/* options */ | ||||
session->port = 22; | ||||
session->fd = -1; | ||||
session->ssh2 = 1; | ||||
#ifdef WITH_SSH1 | ||||
session->ssh1 = 1; | ||||
#else | ||||
session->ssh1 = 0; | ||||
#endif | ||||
#ifndef _WIN32 | #ifndef _WIN32 | |||
session->agent = agent_new(session); | session->agent = agent_new(session); | |||
if (session->agent == NULL) { | if (session->agent == NULL) { | |||
goto err; | goto err; | |||
} | } | |||
#endif /* _WIN32 */ | #endif /* _WIN32 */ | |||
return session; | return session; | |||
err: | err: | |||
ssh_cleanup(session); | ssh_free(session); | |||
return NULL; | return NULL; | |||
} | } | |||
void ssh_cleanup(SSH_SESSION *session) { | /** | |||
* @brief deallocate a session handle | ||||
* @see ssh_disconnect() | ||||
* @see ssh_new() | ||||
*/ | ||||
void ssh_free(ssh_session session) { | ||||
int i; | int i; | |||
enter_function(); | enter_function(); | |||
if (session == NULL) { | if (session == NULL) { | |||
return; | return; | |||
} | } | |||
SAFE_FREE(session->serverbanner); | SAFE_FREE(session->serverbanner); | |||
SAFE_FREE(session->clientbanner); | SAFE_FREE(session->clientbanner); | |||
SAFE_FREE(session->banner); | SAFE_FREE(session->banner); | |||
#ifdef WITH_PCAP | ||||
if(session->pcap_ctx){ | ||||
ssh_pcap_context_free(session->pcap_ctx); | ||||
session->pcap_ctx=NULL; | ||||
} | ||||
#endif | ||||
buffer_free(session->in_buffer); | buffer_free(session->in_buffer); | |||
buffer_free(session->out_buffer); | buffer_free(session->out_buffer); | |||
session->in_buffer=session->out_buffer=NULL; | session->in_buffer=session->out_buffer=NULL; | |||
crypto_free(session->current_crypto); | crypto_free(session->current_crypto); | |||
crypto_free(session->next_crypto); | crypto_free(session->next_crypto); | |||
ssh_socket_free(session->socket); | ssh_socket_free(session->socket); | |||
/* delete all channels */ | /* delete all channels */ | |||
while (session->channels) { | while (session->channels) { | |||
channel_free(session->channels); | channel_free(session->channels); | |||
} | } | |||
skipping to change at line 129 | skipping to change at line 156 | |||
if (session->server_kex.methods) { | if (session->server_kex.methods) { | |||
for (i = 0; i < 10; i++) { | for (i = 0; i < 10; i++) { | |||
SAFE_FREE(session->server_kex.methods[i]); | SAFE_FREE(session->server_kex.methods[i]); | |||
} | } | |||
} | } | |||
SAFE_FREE(session->client_kex.methods); | SAFE_FREE(session->client_kex.methods); | |||
SAFE_FREE(session->server_kex.methods); | SAFE_FREE(session->server_kex.methods); | |||
privatekey_free(session->dsa_key); | privatekey_free(session->dsa_key); | |||
privatekey_free(session->rsa_key); | privatekey_free(session->rsa_key); | |||
ssh_message_free(session->ssh_message); | if(session->ssh_message_list){ | |||
ssh_options_free(session->options); | ssh_message msg; | |||
while((msg=ssh_list_get_head(ssh_message ,session->ssh_message_list)) | ||||
!= NULL){ | ||||
ssh_message_free(msg); | ||||
} | ||||
ssh_list_free(session->ssh_message_list); | ||||
} | ||||
/* burn connection, it could hang sensitive datas */ | /* options */ | |||
memset(session,'X',sizeof(SSH_SESSION)); | SAFE_FREE(session->username); | |||
SAFE_FREE(session->host); | ||||
SAFE_FREE(session->identity); | ||||
SAFE_FREE(session->sshdir); | ||||
SAFE_FREE(session->knownhosts); | ||||
for (i = 0; i < 10; i++) { | ||||
if (session->wanted_methods[i]) { | ||||
SAFE_FREE(session->wanted_methods[i]); | ||||
} | ||||
} | ||||
/* burn connection, it could hang sensitive datas */ | ||||
ZERO_STRUCTP(session); | ||||
SAFE_FREE(session); | SAFE_FREE(session); | |||
/* FIXME: leave_function(); ??? */ | ||||
} | } | |||
/** \brief disconnect impolitely from remote host | /** \brief disconnect impolitely from remote host by closing the socket. | |||
* Suitable if you forked and want to destroy this session. | ||||
* \param session current ssh session | * \param session current ssh session | |||
*/ | */ | |||
void ssh_silent_disconnect(SSH_SESSION *session) { | void ssh_silent_disconnect(ssh_session session) { | |||
enter_function(); | enter_function(); | |||
if (session == NULL) { | if (session == NULL) { | |||
return; | return; | |||
} | } | |||
ssh_socket_close(session->socket); | ssh_socket_close(session->socket); | |||
session->alive = 0; | session->alive = 0; | |||
ssh_disconnect(session); | ssh_disconnect(session); | |||
/* FIXME: leave_function(); ??? */ | leave_function(); | |||
} | ||||
/** \brief set the options for the current session | ||||
* \param session ssh session | ||||
* \param options options structure | ||||
* \see ssh_new() | ||||
* \see ssh_options_new() | ||||
*/ | ||||
void ssh_set_options(SSH_SESSION *session, SSH_OPTIONS *options) { | ||||
if (session == NULL || options == NULL) { | ||||
return; | ||||
} | ||||
session->options = options; | ||||
session->log_verbosity = options->log_verbosity; | ||||
} | } | |||
/** \brief set the session in blocking/nonblocking mode | /** \brief set the session in blocking/nonblocking mode | |||
* \param session ssh session | * \param session ssh session | |||
* \param blocking zero for nonblocking mode | * \param blocking zero for nonblocking mode | |||
* \bug nonblocking code is in development and won't work as expected | * \bug nonblocking code is in development and won't work as expected | |||
*/ | */ | |||
void ssh_set_blocking(SSH_SESSION *session, int blocking) { | void ssh_set_blocking(ssh_session session, int blocking) { | |||
if (session == NULL) { | if (session == NULL) { | |||
return; | return; | |||
} | } | |||
session->blocking = blocking ? 1 : 0; | session->blocking = blocking ? 1 : 0; | |||
} | } | |||
/** In case you'd need the file descriptor of the connection | /** In case you'd need the file descriptor of the connection | |||
* to the server/client | * to the server/client | |||
* \brief recover the fd of connection | * \brief recover the fd of connection | |||
* \param session ssh session | * \param session ssh session | |||
* \return file descriptor of the connection, or -1 if it is | * \return file descriptor of the connection, or -1 if it is | |||
* not connected | * not connected | |||
*/ | */ | |||
socket_t ssh_get_fd(SSH_SESSION *session) { | socket_t ssh_get_fd(ssh_session session) { | |||
if (session == NULL) { | if (session == NULL) { | |||
return -1; | return -1; | |||
} | } | |||
return ssh_socket_get_fd(session->socket); | return ssh_socket_get_fd(session->socket); | |||
} | } | |||
/** \brief say to the session it has data to read on the file descriptor wi thout blocking | /** \brief say to the session it has data to read on the file descriptor wi thout blocking | |||
* \param session ssh session | * \param session ssh session | |||
*/ | */ | |||
void ssh_set_fd_toread(SSH_SESSION *session) { | void ssh_set_fd_toread(ssh_session session) { | |||
if (session == NULL) { | if (session == NULL) { | |||
return; | return; | |||
} | } | |||
ssh_socket_set_toread(session->socket); | ssh_socket_set_toread(session->socket); | |||
} | } | |||
/** \brief say the session it may write to the file descriptor without bloc king | /** \brief say the session it may write to the file descriptor without bloc king | |||
* \param session ssh session | * \param session ssh session | |||
*/ | */ | |||
void ssh_set_fd_towrite(SSH_SESSION *session) { | void ssh_set_fd_towrite(ssh_session session) { | |||
if (session == NULL) { | if (session == NULL) { | |||
return; | return; | |||
} | } | |||
ssh_socket_set_towrite(session->socket); | ssh_socket_set_towrite(session->socket); | |||
} | } | |||
/** \brief say the session it has an exception to catch on the file descrip tor | /** \brief say the session it has an exception to catch on the file descrip tor | |||
* \param session ssh session | * \param session ssh session | |||
*/ | */ | |||
void ssh_set_fd_except(SSH_SESSION *session) { | void ssh_set_fd_except(ssh_session session) { | |||
if (session == NULL) { | if (session == NULL) { | |||
return; | return; | |||
} | } | |||
ssh_socket_set_except(session->socket); | ssh_socket_set_except(session->socket); | |||
} | } | |||
/** \warning I don't remember if this should be internal or not | /** \warning I don't remember if this should be internal or not | |||
*/ | */ | |||
/* looks if there is data to read on the socket and parse it. */ | /* looks if there is data to read on the socket and parse it. */ | |||
int ssh_handle_packets(SSH_SESSION *session) { | int ssh_handle_packets(ssh_session session) { | |||
int w = 0; | int w = 0; | |||
int e = 0; | int e = 0; | |||
int rc = -1; | int rc = -1; | |||
enter_function(); | enter_function(); | |||
do { | do { | |||
rc = ssh_socket_poll(session->socket, &w, &e); | rc = ssh_socket_poll(session->socket, &w, &e); | |||
if (rc <= 0) { | if (rc <= 0) { | |||
/* error or no data available */ | /* error or no data available */ | |||
skipping to change at line 272 | skipping to change at line 302 | |||
/** | /** | |||
* @brief Get session status | * @brief Get session status | |||
* | * | |||
* @param session The ssh session to use. | * @param session The ssh session to use. | |||
* | * | |||
* @returns A bitmask including SSH_CLOSED, SSH_READ_PENDING or SSH_CLOSED_ ERROR | * @returns A bitmask including SSH_CLOSED, SSH_READ_PENDING or SSH_CLOSED_ ERROR | |||
* which respectively means the session is closed, has data to rea d on | * which respectively means the session is closed, has data to rea d on | |||
* the connection socket and session was closed due to an error. | * the connection socket and session was closed due to an error. | |||
*/ | */ | |||
int ssh_get_status(SSH_SESSION *session) { | int ssh_get_status(ssh_session session) { | |||
int socketstate; | int socketstate; | |||
int r = 0; | int r = 0; | |||
if (session == NULL) { | if (session == NULL) { | |||
return 0; | return 0; | |||
} | } | |||
socketstate = ssh_socket_get_status(session->socket); | socketstate = ssh_socket_get_status(session->socket); | |||
if (session->closed) { | if (session->closed) { | |||
skipping to change at line 300 | skipping to change at line 330 | |||
} | } | |||
return r; | return r; | |||
} | } | |||
/** \brief get the disconnect message from the server | /** \brief get the disconnect message from the server | |||
* \param session ssh session | * \param session ssh session | |||
* \return message sent by the server along with the disconnect, or NULL in which case the reason of the disconnect may be found with ssh_get_error. | * \return message sent by the server along with the disconnect, or NULL in which case the reason of the disconnect may be found with ssh_get_error. | |||
* \see ssh_get_error() | * \see ssh_get_error() | |||
*/ | */ | |||
const char *ssh_get_disconnect_message(SSH_SESSION *session) { | const char *ssh_get_disconnect_message(ssh_session session) { | |||
if (session == NULL) { | if (session == NULL) { | |||
return NULL; | return NULL; | |||
} | } | |||
if (!session->closed) { | if (!session->closed) { | |||
ssh_set_error(session, SSH_REQUEST_DENIED, | ssh_set_error(session, SSH_REQUEST_DENIED, | |||
"Connection not closed yet"); | "Connection not closed yet"); | |||
} else if(session->closed_by_except) { | } else if(session->closed_by_except) { | |||
ssh_set_error(session, SSH_REQUEST_DENIED, | ssh_set_error(session, SSH_REQUEST_DENIED, | |||
"Connection closed by socket error"); | "Connection closed by socket error"); | |||
skipping to change at line 328 | skipping to change at line 358 | |||
return NULL; | return NULL; | |||
} | } | |||
/** | /** | |||
* @brief Get the protocol version of the session. | * @brief Get the protocol version of the session. | |||
* | * | |||
* @param session The ssh session to use. | * @param session The ssh session to use. | |||
* | * | |||
* @return 1 or 2, for ssh1 or ssh2, < 0 on error. | * @return 1 or 2, for ssh1 or ssh2, < 0 on error. | |||
*/ | */ | |||
int ssh_get_version(SSH_SESSION *session) { | int ssh_get_version(ssh_session session) { | |||
if (session == NULL) { | if (session == NULL) { | |||
return -1; | return -1; | |||
} | } | |||
return session->version; | return session->version; | |||
} | } | |||
/** @} */ | /** @} */ | |||
/* vim: set ts=2 sw=2 et cindent: */ | /* vim: set ts=2 sw=2 et cindent: */ | |||
End of changes. 27 change blocks. | ||||
45 lines changed or deleted | 75 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/ |