1
1
libssh/libssh/session.c
Andreas Schneider 3441e77ddc Normalize the license in all files and add vim tab instructions.
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@305 7dcaeef0-15fb-0310-b436-a5af3365683c
2009-03-29 20:19:18 +00:00

249 строки
7.6 KiB
C

/*
* session.c - non-networking functions
*
* This file is part of the SSH Library
*
* Copyright (c) 2005-2008 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* 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
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*
* vim: ts=2 sw=2 et cindent
*/
#include <string.h>
#include <stdlib.h>
#include "libssh/libssh.h"
#include "libssh/priv.h"
#include "libssh/server.h"
#define FIRST_CHANNEL 42 // why not ? it helps to find bugs.
/** \defgroup ssh_session SSH Session
* \brief functions that manage a session
*/
/** \addtogroup ssh_session
* @{ */
/** \brief creates a new ssh session
* \returns new ssh_session pointer
*/
SSH_SESSION *ssh_new(void) {
SSH_SESSION *session=malloc(sizeof (SSH_SESSION));
memset(session,0,sizeof(SSH_SESSION));
session->next_crypto=crypto_new();
session->maxchannel=FIRST_CHANNEL;
session->socket=ssh_socket_new(session);
session->alive=0;
session->auth_methods=0;
session->blocking=1;
session->log_indent=0;
session->out_buffer=buffer_new();
session->in_buffer=buffer_new();
#ifndef _WIN32
session->agent=agent_new(session);
#endif /* _WIN32 */
return session;
}
void ssh_cleanup(SSH_SESSION *session){
int i;
enter_function();
if(session->serverbanner)
free(session->serverbanner);
if(session->clientbanner)
free(session->clientbanner);
if(session->in_buffer)
buffer_free(session->in_buffer);
if(session->out_buffer)
buffer_free(session->out_buffer);
if(session->banner)
free(session->banner);
if(session->options)
ssh_options_free(session->options);
if(session->current_crypto)
crypto_free(session->current_crypto);
if(session->next_crypto)
crypto_free(session->next_crypto);
if(session->socket)
ssh_socket_free(session->socket);
// delete all channels
while(session->channels)
channel_free(session->channels);
#ifndef _WIN32
if (session->agent)
agent_free(session->agent);
#endif /* _WIN32 */
if(session->client_kex.methods)
for(i=0;i<10;i++)
if(session->client_kex.methods[i])
free(session->client_kex.methods[i]);
if(session->server_kex.methods)
for(i=0;i<10;++i)
if(session->server_kex.methods[i])
free(session->server_kex.methods[i]);
free(session->client_kex.methods);
free(session->server_kex.methods);
if(session->dsa_key)
private_key_free(session->dsa_key);
if(session->rsa_key)
private_key_free(session->rsa_key);
if(session->ssh_message){
ssh_message_free(session->ssh_message);
free(session->ssh_message);
}
memset(session,'X',sizeof(SSH_SESSION)); /* burn connection, it could hangs
sensitive datas */
free(session);
//leave_function();
}
/** \brief disconnect impolitely from remote host
* \param session current ssh session
*/
void ssh_silent_disconnect(SSH_SESSION *session){
enter_function();
ssh_socket_close(session->socket);
session->alive=0;
ssh_disconnect(session);
//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){
session->options=options;
session->log_verbosity=options->log_verbosity;
}
/** \brief set the session in blocking/nonblocking mode
* \param session ssh session
* \param blocking zero for nonblocking mode
* \bug nonblocking code is in development and won't work as expected
*/
void ssh_set_blocking(SSH_SESSION *session,int blocking){
session->blocking=blocking?1:0;
}
/** In case you'd need the file descriptor of the connection
* to the server/client
* \brief recover the fd of connection
* \param session ssh session
* \return file descriptor of the connection, or -1 if it is
* not connected
*/
socket_t ssh_get_fd(SSH_SESSION *session){
return ssh_socket_get_fd(session->socket);
}
/** \brief say to the session it has data to read on the file descriptor without blocking
* \param session ssh session
*/
void ssh_set_fd_toread(SSH_SESSION *session){
ssh_socket_set_toread(session->socket);
}
/** \brief say the session it may write to the file descriptor without blocking
* \param session ssh session
*/
void ssh_set_fd_towrite(SSH_SESSION *session){
ssh_socket_set_towrite(session->socket);
}
/** \brief say the session it has an exception to catch on the file descriptor
* \param session ssh session
*/
void ssh_set_fd_except(SSH_SESSION *session){
ssh_socket_set_except(session->socket);
}
/** \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. */
int ssh_handle_packets(SSH_SESSION *session){
int w,err,r,i=0;
enter_function();
do {
r=ssh_socket_poll(session->socket,&w,&err);
if(r<=0){
leave_function();
return r; // error or no data available
}
/* if an exception happened, it will be trapped by packet_read() */
if(packet_read(session)||packet_translate(session)){
leave_function();
return -1;
}
packet_parse(session);
++i;
} while(r>0);
leave_function();
return r;
}
/** \brief get session status
* \param session ssh session
* \returns a bitmask including SSH_CLOSED, SSH_READ_PENDING or SSH_CLOSED_ERROR
* which respectively means the session is closed, has data to read on the connection socket and session was closed due to an error
*/
int ssh_get_status(SSH_SESSION *session){
int ret=0;
int socketstate=ssh_socket_get_status(session->socket);
if(session->closed)
ret |= SSH_CLOSED;
if(socketstate & SSH_READ_PENDING)
ret |= SSH_READ_PENDING;
if(session->closed && socketstate & SSH_CLOSED_ERROR)
ret |= SSH_CLOSED_ERROR;
return ret;
}
/** \brief get the disconnect message from the server
* \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.
* \see ssh_get_error()
*/
const char *ssh_get_disconnect_message(SSH_SESSION *session){
if(!session->closed)
ssh_set_error(session,SSH_REQUEST_DENIED,"Connection not closed"
" yet");
else if(session->closed_by_except)
ssh_set_error(session,SSH_REQUEST_DENIED,"Connection closed by "
"socket error");
else if(!session->discon_msg)
ssh_set_error(session,SSH_FATAL,"Connection correctly closed but "
"no disconnect message");
else
return session->discon_msg;
return NULL;
}
/** \brief get the protocol version of the session
* \param session ssh session
* \return 1 or 2, for ssh1 or ssh2
*/
int ssh_get_version(SSH_SESSION *session){
return session->version;
}
/** @} */