1
1
refactoring of the socket class. Now the buffering happens in the socket class.
enhanced the logging system. Cleaned up some debugging messages.
Verified the working with ssh-1.
If this cleanup introduced bugs (it did but corrected the found ones) at least, they will be easier to find

also added the (c) and fixed dates for updated files


git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@169 7dcaeef0-15fb-0310-b436-a5af3365683c
Этот коммит содержится в:
Aris Adamantiadis 2008-06-16 23:02:49 +00:00
родитель 5367581ce1
Коммит 77603dbc5a
15 изменённых файлов: 414 добавлений и 337 удалений

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright 2003,04 Aris Adamantiadis
Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@ -122,15 +122,37 @@ char *ssh_get_error(void *error);
int ssh_get_error_code(void *error);
void ssh_say(int priority,char *format,...);
void ssh_set_verbosity(int num);
/** \addtogroup ssh_log
* @{
*/
/** \brief Verbosity level for logging and help to debugging
*/
/* There is a verbosity level */
#define SSH_LOG_NOLOG 0 // no log
enum {
/** No logging at all
*/
SSH_LOG_NOLOG=0,
/** Only rare and noteworthy events
*/
SSH_LOG_RARE,
/** High level protocol informations
*/
SSH_LOG_PROTOCOL,
/** Lower level protocol infomations, packet level
*/
SSH_LOG_PACKET,
/** Every function path
*/
SSH_LOG_FUNCTIONS
};
/** @}
*/
/*#define SSH_LOG_NOLOG 0 // no log
#define SSH_LOG_RARE 1 // rare conditions
#define SSH_LOG_ENTRY 2 // user-accessible entrypoints
#define SSH_LOG_PACKET 3 // packet id and size
#define SSH_LOG_FUNCTIONS 4 // every function in and return
*/
/* log.c */
void ssh_log(SSH_SESSION *session, int prioriry, char *format, ...);

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright 2003,04 Aris Adamantiadis
Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@ -322,10 +322,7 @@ struct ssh_session {
BUFFER *in_buffer;
PACKET in_packet;
BUFFER *out_buffer;
BUFFER *out_socket_buffer;
BUFFER *in_socket_buffer;
/* the states are used by the nonblocking stuff to remember */
/* where it was before being interrupted */
int packet_state;
@ -426,11 +423,11 @@ struct ssh_message {
struct ssh_channel_request channel_request;
};
/* socketc.c */
/* socket.c */
struct socket;
void ssh_socket_init();
struct socket *ssh_socket_new();
struct socket *ssh_socket_new(SSH_SESSION *session);
void ssh_socket_free(struct socket *s);
void ssh_socket_set_fd(struct socket *s, socket_t fd);
socket_t ssh_socket_get_fd(struct socket *s);
@ -441,6 +438,10 @@ int ssh_socket_is_open(struct socket *s);
int ssh_socket_fd_isset(struct socket *s, fd_set *set);
void ssh_socket_fd_set(struct socket *s, fd_set *set, int *fd_max);
int ssh_socket_completeread(struct socket *s, void *buffer, int len);
int ssh_socket_wait_for_data(struct socket *s, SSH_SESSION *session,int len);
int ssh_socket_nonblocking_flush(struct socket *s);
int ssh_socket_blocking_flush(struct socket *s);
int ssh_socket_poll(struct socket *s, int *write, int *except);
/* session.c */
@ -486,7 +487,7 @@ unsigned char *packet_encrypt(SSH_SESSION *session,void *packet,unsigned int len
int packet_hmac_verify(SSH_SESSION *session,BUFFER *buffer,unsigned char *mac);
/* in packet.c */
void packet_clear_out(SSH_SESSION *session);
void packet_parse(SSH_SESSION *session);
int packet_send(SSH_SESSION *session);
@ -546,8 +547,8 @@ void buffer_add_ssh_string(BUFFER *buffer,STRING *string);
void buffer_add_u8(BUFFER *buffer, u8 data);
void buffer_add_u32(BUFFER *buffer, u32 data);
void buffer_add_u64(BUFFER *buffer,u64 data);
void buffer_add_data(BUFFER *buffer, void *data, int len);
void buffer_add_data_begin(BUFFER *buffer,void *data,int len);
void buffer_add_data(BUFFER *buffer,const void *data, int len);
void buffer_add_data_begin(BUFFER *buffer,const void *data,int len);
void buffer_add_buffer(BUFFER *buffer, BUFFER *source);
void buffer_reinit(BUFFER *buffer);

Просмотреть файл

@ -1,6 +1,6 @@
/* auth.c deals with authentication methods */
/*
Copyright 2003-2005 Aris Adamantiadis
Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@ -160,7 +160,6 @@ int ssh_userauth_none(SSH_SESSION *session,char *username){
user=string_from_char(username);
method=string_from_char("none");
service=string_from_char("ssh-connection");
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
buffer_add_ssh_string(session->out_buffer,user);
buffer_add_ssh_string(session->out_buffer,service);
@ -220,7 +219,6 @@ int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STR
method=string_from_char("publickey");
algo=string_from_char(ssh_type_to_char(type));
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
buffer_add_ssh_string(session->out_buffer,user);
buffer_add_ssh_string(session->out_buffer,service);
@ -284,7 +282,6 @@ int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey,
/* we said previously the public key was accepted */
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
buffer_add_ssh_string(session->out_buffer,user);
buffer_add_ssh_string(session->out_buffer,service);
@ -352,7 +349,6 @@ int ssh_userauth_password(SSH_SESSION *session,char *username,char *password){
method=string_from_char("password");
password_s=string_from_char(password);
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
buffer_add_ssh_string(session->out_buffer,user);
buffer_add_ssh_string(session->out_buffer,service);
@ -567,7 +563,6 @@ static int kbdauth_init(SSH_SESSION *session,
STRING *method=string_from_char("keyboard-interactive");
int err;
enter_function();
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
buffer_add_ssh_string(session->out_buffer,user_s);
buffer_add_ssh_string(session->out_buffer,service);
@ -650,7 +645,6 @@ static int kbdauth_send(SSH_SESSION *session) {
int i;
int err;
enter_function();
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_INFO_RESPONSE);
buffer_add_u32(session->out_buffer,htonl(session->kbdint->nprompts));
for(i=0;i<session->kbdint->nprompts;++i){

Просмотреть файл

@ -1,6 +1,6 @@
/* auth1.c deals with authentication with SSH-1 protocol */
/*
Copyright 2005 Aris Adamantiadis
Copyright (c) 2005-2008 Aris Adamantiadis
This file is part of the SSH Library
@ -52,7 +52,6 @@ static int send_username(SSH_SESSION *session, char *username){
/* returns SSH_AUTH_SUCCESS or SSH_AUTH_DENIED */
if(session->auth_service_asked)
return session->auth_service_asked;
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_USER);
if(!username)
if(!(username=session->options->username)){
@ -192,7 +191,6 @@ int ssh_userauth1_password(SSH_SESSION *session,char *username,char *password){
strcpy((char *)password_s->string,password);
}
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_AUTH_PASSWORD);
buffer_add_ssh_string(session->out_buffer,password_s);
string_burn(password_s);

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright 2003-2008 Aris Adamantiadis
Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@ -75,7 +75,7 @@ static void realloc_buffer(BUFFER *buffer,int needed){
* \param data data pointer
* \param len length of data
*/
void buffer_add_data(BUFFER *buffer,void *data,int len){
void buffer_add_data(BUFFER *buffer,const void *data,int len){
if(buffer->allocated < buffer->used+len)
realloc_buffer(buffer,buffer->used+len);
memcpy(buffer->data+buffer->used,data,len);
@ -105,7 +105,7 @@ void buffer_add_u8(BUFFER *buffer,u8 data){
* \param data data to add
* \param len length of data
*/
void buffer_add_data_begin(BUFFER *buffer, void *data, int len){
void buffer_add_data_begin(BUFFER *buffer, const void *data, int len){
if(buffer->allocated < buffer->used + len)
realloc_buffer(buffer,buffer->used+len);
memmove(buffer->data+len,buffer->data,buffer->used);

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright 2003-2008 Aris Adamantiadis
Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@ -72,7 +72,6 @@ static int channel_open(CHANNEL *channel,char *type_c,int window,
u32 foo;
int err;
enter_function();
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_OPEN);
channel->local_channel=ssh_channel_new_id(session);
channel->local_maxpacket=maxpacket;
@ -152,7 +151,6 @@ CHANNEL *ssh_channel_from_local(SSH_SESSION *session,u32 num){
static void grow_window(SSH_SESSION *session, CHANNEL *channel){
u32 new_window=WINDOWBASE;
enter_function();
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_WINDOW_ADJUST);
buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
buffer_add_u32(session->out_buffer,htonl(new_window));
@ -473,7 +471,6 @@ int channel_send_eof(CHANNEL *channel){
SSH_SESSION *session=channel->session;
int ret;
enter_function();
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_EOF);
buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
ret=packet_send(session);
@ -503,7 +500,6 @@ int channel_close(CHANNEL *channel){
leave_function();
return ret;
}
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_CLOSE);
buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
ret=packet_send(session);
@ -527,6 +523,7 @@ int channel_write(CHANNEL *channel ,void *data,int len){
SSH_SESSION *session=channel->session;
int effectivelen;
int origlen=len;
int err;
enter_function();
if(channel->local_eof){
ssh_set_error(session,SSH_REQUEST_DENIED,"Can't write to channel %d:%d"
@ -544,6 +541,7 @@ int channel_write(CHANNEL *channel ,void *data,int len){
err = channel_write1(channel,data,len);
leave_function();
return err;
}
#endif
while(len >0){
if(channel->remote_window<len){
@ -558,7 +556,6 @@ int channel_write(CHANNEL *channel ,void *data,int len){
effectivelen=len>channel->remote_window?channel->remote_window:len;
} else
effectivelen=len;
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_DATA);
buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
buffer_add_u32(session->out_buffer,htonl(effectivelen));
@ -619,7 +616,6 @@ static int channel_request(CHANNEL *channel,char *request, BUFFER *buffer,int re
SSH_SESSION *session=channel->session;
int err;
enter_function();
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_REQUEST);
buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
buffer_add_ssh_string(session->out_buffer,request_s);

Просмотреть файл

@ -67,7 +67,6 @@ int channel_request_pty_size1(CHANNEL *channel, char *terminal, int col,
STRING *str;
SSH_SESSION *session=channel->session;
str=string_from_char(terminal);
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_REQUEST_PTY);
buffer_add_ssh_string(session->out_buffer,str);
free(str);
@ -105,7 +104,6 @@ int channel_request_pty_size1(CHANNEL *channel, char *terminal, int col,
int channel_change_pty_size1(CHANNEL *channel, int cols, int rows){
SSH_SESSION *session=channel->session;
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_WINDOW_SIZE);
buffer_add_u32(session->out_buffer,ntohl(rows));
buffer_add_u32(session->out_buffer,ntohl(cols));
@ -132,7 +130,6 @@ int channel_change_pty_size1(CHANNEL *channel, int cols, int rows){
int channel_request_shell1(CHANNEL *channel){
SSH_SESSION *session=channel->session;
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_SHELL);
if(packet_send(session))
return -1;
@ -143,7 +140,6 @@ int channel_request_shell1(CHANNEL *channel){
int channel_request_exec1(CHANNEL *channel, char *cmd){
SSH_SESSION *session=channel->session;
STRING *command=string_from_char(cmd);
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_CMD);
buffer_add_ssh_string(session->out_buffer,command);
free(command);
@ -179,7 +175,6 @@ static void channel_rcv_close1(SSH_SESSION *session){
/* actually status is lost somewhere */
channel->open=0;
channel->remote_eof=1;
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_EXIT_CONFIRMATION);
packet_send(session);
}
@ -204,7 +199,6 @@ int channel_write1(CHANNEL *channel, void *data, int len){
int origlen=len;
int effectivelen;
while(len>0){
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_STDIN_DATA);
if(len > 32000)
effectivelen=32000;

Просмотреть файл

@ -1,6 +1,6 @@
/* client.c file */
/*
Copyright 2003-2005 Aris Adamantiadis
Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@ -37,7 +37,7 @@ char *ssh_get_banner(SSH_SESSION *session){
char *ret;
enter_function();
while (i < 127) {
if(!ssh_socket_is_open(session->socket) || ssh_socket_read(session->socket, &buffer[i], 1)<=0){
if(ssh_socket_read(session->socket, &buffer[i], 1)!= SSH_OK){
ssh_set_error(session,SSH_FATAL,"Remote host closed connection");
leave_function();
return NULL;
@ -105,6 +105,7 @@ int ssh_send_banner(SSH_SESSION *session,int server){
session->clientbanner=strdup(banner);
snprintf(buffer,128,"%s\r\n",banner);
ssh_socket_write(session->socket,buffer,strlen(buffer));
ssh_socket_blocking_flush(session->socket);
leave_function();
return 0;
}
@ -121,7 +122,6 @@ static int dh_handshake(SSH_SESSION *session){
enter_function();
switch(session->dh_handshake_state){
case DH_STATE_INIT:
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT);
dh_generate_x(session);
dh_generate_e(session);
@ -170,7 +170,6 @@ static int dh_handshake(SSH_SESSION *session){
session->dh_server_signature=signature;
dh_build_k(session);
// send the MSG_NEWKEYS
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS);
packet_send(session);
session->dh_handshake_state=DH_STATE_NEWKEYS_TO_SEND;
@ -228,7 +227,6 @@ static int dh_handshake(SSH_SESSION *session){
int ssh_service_request(SSH_SESSION *session,char *service){
STRING *service_s;
enter_function();
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_SERVICE_REQUEST);
service_s=string_from_char(service);
buffer_add_ssh_string(session->out_buffer,service_s);
@ -376,7 +374,6 @@ void ssh_disconnect(SSH_SESSION *session){
STRING *str;
enter_function();
if(ssh_socket_is_open(session->socket)) {
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_DISCONNECT);
buffer_add_u32(session->out_buffer,htonl(SSH2_DISCONNECT_BY_APPLICATION));
str=string_from_char("Bye Bye");

Просмотреть файл

@ -1,7 +1,7 @@
/* connect.c */
/* it handles connections to ssh servers */
/*
Copyright 2003 Aris Adamantiadis
Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@ -220,47 +220,7 @@ socket_t ssh_connect_host(SSH_SESSION *session, const char *host, const char
* \return 1 if it is possible to read, 0 otherwise, -1 on error
*/
int ssh_fd_poll(SSH_SESSION *session, int *write, int *except){
struct timeval sometime;
fd_set rdes; // read set
fd_set wdes; // writing set
fd_set edes; // exception set
int fdmax=-1;
enter_function();
FD_ZERO(&rdes);
FD_ZERO(&wdes);
FD_ZERO(&edes);
if(!session->alive || !ssh_socket_is_open(session->socket)){
*except=1;
*write=0;
session->alive=0;
leave_function();
return 0;
}
if(!session->data_to_read)
ssh_socket_fd_set(session->socket,&rdes,&fdmax);
if(!session->data_to_write)
ssh_socket_fd_set(session->socket,&wdes,&fdmax);
ssh_socket_fd_set(session->socket,&edes,&fdmax);
/* Set to return immediately (no blocking) */
sometime.tv_sec = 0;
sometime.tv_usec = 0;
/* Make the call, and listen for errors */
if (select(fdmax, &rdes,&wdes,&edes, &sometime) < 0) {
ssh_set_error(session,SSH_FATAL, "select: %s", strerror(errno));
leave_function();
return -1;
}
if(!session->data_to_read)
session->data_to_read=ssh_socket_fd_isset(session->socket,&rdes);
if(!session->data_to_write)
session->data_to_write=ssh_socket_fd_isset(session->socket,&wdes);
*except=ssh_socket_fd_isset(session->socket,&edes);
*write=session->data_to_write;
leave_function();
return session->data_to_read;
return ssh_socket_poll(session->socket,write,except);
}

Просмотреть файл

@ -1,6 +1,6 @@
/* kex.c is used well, in key exchange :-) */
/*
Copyright 2003 Aris Adamantiadis
Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@ -254,7 +254,6 @@ void ssh_send_kex(SSH_SESSION *session, int server_kex){
int i=0;
KEX *kex=(server_kex ? &session->server_kex : &session->client_kex);
enter_function();
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_KEXINIT);
buffer_add_data(session->out_buffer,kex->cookie,16);
hashbufout_add_cookie(session);
@ -412,12 +411,12 @@ int ssh_get_kex1(SSH_SESSION *session){
int ko;
u16 bits;
enter_function();
ssh_say(3,"Waiting for a SSH_SMSG_PUBLIC_KEY\n");
ssh_log(session,SSH_LOG_PROTOCOL,"Waiting for a SSH_SMSG_PUBLIC_KEY");
if(packet_wait(session,SSH_SMSG_PUBLIC_KEY,1)){
leave_function();
return -1;
}
ssh_say(3,"Got a SSH_SMSG_PUBLIC_KEY\n");
ssh_log(session,SSH_LOG_PROTOCOL,"Got a SSH_SMSG_PUBLIC_KEY");
if(buffer_get_data(session->in_buffer,session->server_kex.cookie,8)!=8){
ssh_set_error(session,SSH_FATAL,"Can't get cookie in buffer");
leave_function();
@ -433,7 +432,7 @@ int ssh_get_kex1(SSH_SESSION *session){
buffer_get_u32(session->in_buffer,&supported_ciphers_mask);
ko=buffer_get_u32(session->in_buffer,&supported_authentications_mask);
if((ko!=sizeof(u32)) || !host_mod || !host_exp || !server_mod || !server_exp){
ssh_say(2,"Invalid SSH_SMSG_PUBLIC_KEY packet\n");
ssh_log(session,SSH_LOG_RARE,"Invalid SSH_SMSG_PUBLIC_KEY packet");
ssh_set_error(session,SSH_FATAL,"Invalid SSH_SMSG_PUBLIC_KEY packet");
if(host_mod)
free(host_mod);
@ -451,8 +450,8 @@ int ssh_get_kex1(SSH_SESSION *session){
protocol_flags=ntohl(protocol_flags);
supported_ciphers_mask=ntohl(supported_ciphers_mask);
supported_authentications_mask=ntohl(supported_authentications_mask);
ssh_say(1,"server bits: %d ; host bits: %d\nProtocol flags : %.8lx ; "
"cipher mask : %.8lx ; auth mask: %.8lx\n",server_bits,
ssh_log(session,SSH_LOG_PROTOCOL,"server bits: %d ; host bits: %d Protocol flags : %.8lx ; "
"cipher mask : %.8lx ; auth mask: %.8lx",server_bits,
host_bits,protocol_flags,supported_ciphers_mask,
supported_authentications_mask);
serverkey=make_rsa1_string(server_exp,server_mod);
@ -474,14 +473,14 @@ int ssh_get_kex1(SSH_SESSION *session){
leave_function();
return -1;
}
packet_clear_out(session);
ssh_log(session,SSH_LOG_PROTOCOL,"sending SSH_CMSG_SESSION_KEY");
buffer_add_u8(session->out_buffer,SSH_CMSG_SESSION_KEY);
buffer_add_u8(session->out_buffer,SSH_CIPHER_3DES);
buffer_add_data(session->out_buffer,session->server_kex.cookie,8);
enc_session=encrypt_session_key(session,svr,host,server_bits, host_bits);
bits=string_len(enc_session)*8 - 7;
ssh_say(2,"%d bits,%d bytes encrypted session\n",bits,string_len(enc_session));
ssh_log(session,SSH_LOG_PROTOCOL,"%d bits,%d bytes encrypted session",bits,string_len(enc_session));
bits=htons(bits);
/* the encrypted mpint */
buffer_add_data(session->out_buffer,&bits,sizeof(u16));
@ -505,7 +504,7 @@ int ssh_get_kex1(SSH_SESSION *session){
leave_function();
return -1;
}
ssh_say(1,"received SSH_SMSG_SUCCESS\n");
ssh_log(session,SSH_LOG_PROTOCOL,"received SSH_SMSG_SUCCESS\n");
leave_function();
return 0;

Просмотреть файл

@ -58,7 +58,6 @@ static int handle_service_request(SSH_SESSION *session){
service_c=string_to_char(service);
ssh_say(2,"Sending a SERVICE_ACCEPT for service %s\n",service_c);
free(service_c);
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_SERVICE_ACCEPT);
buffer_add_ssh_string(session->out_buffer,service);
packet_send(session);
@ -68,7 +67,6 @@ static int handle_service_request(SSH_SESSION *session){
}
static void handle_unimplemented(SSH_SESSION *session){
packet_clear_out(session);
buffer_add_u32(session->out_buffer,htonl(session->recv_seq-1));
packet_send(session);
}
@ -131,7 +129,6 @@ static int ssh_message_auth_reply_default(SSH_MESSAGE *msg,int partial){
SSH_SESSION *session=msg->session;
int ret;
enter_function();
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_FAILURE);
if(session->auth_methods==0){
session->auth_methods=SSH_AUTH_PUBLICKEY|SSH_AUTH_PASSWORD;
@ -162,7 +159,6 @@ static int ssh_message_auth_reply_default(SSH_MESSAGE *msg,int partial){
int ssh_message_auth_reply_success(SSH_MESSAGE *msg,int partial){
if(partial)
return ssh_message_auth_reply_default(msg,partial);
packet_clear_out(msg->session);
buffer_add_u8(msg->session->out_buffer,SSH2_MSG_USERAUTH_SUCCESS);
return packet_send(msg->session);
}
@ -205,7 +201,6 @@ CHANNEL *ssh_message_channel_request_open_reply_accept(SSH_MESSAGE *msg){
chan->remote_maxpacket=msg->channel_request_open.packet_size;
chan->remote_window=msg->channel_request_open.window;
chan->open=1;
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
buffer_add_u32(session->out_buffer,htonl(chan->remote_channel));
buffer_add_u32(session->out_buffer,htonl(chan->local_channel));
@ -223,7 +218,6 @@ CHANNEL *ssh_message_channel_request_open_reply_accept(SSH_MESSAGE *msg){
static int ssh_message_channel_request_open_reply_default(SSH_MESSAGE *msg){
ssh_say(2,"Refusing a channel\n");
packet_clear_out(msg->session);
buffer_add_u8(msg->session->out_buffer,SSH2_MSG_CHANNEL_OPEN_FAILURE);
buffer_add_u32(msg->session->out_buffer,htonl(msg->channel_request_open.sender));
buffer_add_u32(msg->session->out_buffer,htonl(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED));
@ -309,7 +303,6 @@ int ssh_message_channel_request_reply_success(SSH_MESSAGE *msg){
if(msg->channel_request.want_reply){
channel=msg->channel_request.channel->remote_channel;
ssh_say(2,"Sending a channel_request success to channel %d\n",channel);
packet_clear_out(msg->session);
buffer_add_u8(msg->session->out_buffer,SSH2_MSG_CHANNEL_SUCCESS);
buffer_add_u32(msg->session->out_buffer,htonl(channel));
return packet_send(msg->session);
@ -324,7 +317,6 @@ static int ssh_message_channel_request_reply_default(SSH_MESSAGE *msg){
if(msg->channel_request.want_reply){
channel=msg->channel_request.channel->remote_channel;
ssh_say(2,"Sending a default channel_request denied to channel %d\n",channel);
packet_clear_out(msg->session);
buffer_add_u8(msg->session->out_buffer,SSH2_MSG_CHANNEL_FAILURE);
buffer_add_u32(msg->session->out_buffer,htonl(channel));
return packet_send(msg->session);

Просмотреть файл

@ -1,7 +1,7 @@
/* packet.c */
/* packet building functions */
/*
Copyright 2003 Aris Adamantiadis
Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@ -37,66 +37,6 @@ static int macsize=SHA_DIGEST_LEN;
/* SSH_OK if it has read at least len bytes, otherwise, SSH_AGAIN. */
/* in blocking mode, it will read at least len bytes and will block until it's ok. */
static int socket_read(SSH_SESSION *session,int len){
enter_function();
int except, can_write;
int to_read;
int r;
char *buf;
char buffer[4096];
if(!session->in_socket_buffer)
session->in_socket_buffer=buffer_new();
to_read=len - buffer_get_rest_len(session->in_socket_buffer);
if(to_read <= 0){
leave_function();
return SSH_OK;
}
if(session->blocking){
buf=malloc(to_read);
r=ssh_socket_completeread(session->socket,buf,to_read);
session->data_to_read=0;
if(r==SSH_ERROR || r ==0){
ssh_set_error(session,SSH_FATAL,
(r==0)?"Connection closed by remote host" : "Error reading socket");
ssh_socket_close(session->socket);
session->alive=0;
session->data_except=1;
leave_function();
return SSH_ERROR;
}
buffer_add_data(session->in_socket_buffer,buf,to_read);
free(buf);
leave_function();
return SSH_OK;
}
/* nonblocking read */
do {
ssh_fd_poll(session,&can_write,&except); /* internally sets data_to_read */
if(!session->data_to_read){
leave_function();
return SSH_AGAIN;
}
session->data_to_read=0;
/* read as much as we can */
if(ssh_socket_is_open(session->socket))
r=ssh_socket_read(session->socket,buffer,sizeof(buffer));
else
r=-1;
if(r<=0){
ssh_set_error(session,SSH_FATAL,
(r==0)?"Connection closed by remote host" : "Error reading socket");
ssh_socket_close(session->socket);
session->data_except=1;
session->alive=0;
leave_function();
return SSH_ERROR;
}
buffer_add_data(session->in_socket_buffer,buffer,r);
} while(buffer_get_rest_len(session->in_socket_buffer)<len);
leave_function();
return SSH_OK;
}
#define PACKET_STATE_INIT 0
#define PACKET_STATE_SIZEREAD 1
@ -123,14 +63,14 @@ static int packet_read2(SSH_SESSION *session){
buffer_reinit(session->in_buffer);
else
session->in_buffer=buffer_new();
ret=socket_read(session,blocksize);
ret=ssh_socket_wait_for_data(session->socket,session,blocksize);
if(ret != SSH_OK){
leave_function();
return ret; // can be SSH_ERROR or SSH_AGAIN
}
// be_read=completeread(session->fd,buffer,blocksize);
memcpy(buffer,buffer_get_rest(session->in_socket_buffer),blocksize);
buffer_pass_bytes(session->in_socket_buffer,blocksize); // mark them as read
// can't fail since we're sure there is enough data in socket buffer
ssh_socket_read(session->socket,buffer,blocksize);
len=packet_decrypt_len(session,buffer);
buffer_add_data(session->in_buffer,buffer,blocksize);
if(len> MAX_PACKET_LEN){
@ -153,14 +93,13 @@ static int packet_read2(SSH_SESSION *session){
to_be_read=len-blocksize+sizeof(u32) + current_macsize;
/* if to_be_read is zero, the whole packet was blocksize bytes. */
if(to_be_read != 0){
ret=socket_read(session,to_be_read);
ret=ssh_socket_wait_for_data(session->socket,session,to_be_read);
if(ret!=SSH_OK){
leave_function();
return ret;
}
packet=malloc(to_be_read);
memcpy(packet,buffer_get_rest(session->in_socket_buffer),to_be_read-current_macsize);
buffer_pass_bytes(session->in_socket_buffer,to_be_read-current_macsize);
ssh_socket_read(session->socket,packet,to_be_read-current_macsize);
ssh_log(session,SSH_LOG_PACKET,"Read a %d bytes packet",len);
buffer_add_data(session->in_buffer,packet,to_be_read-current_macsize);
free(packet);
@ -169,8 +108,7 @@ static int packet_read2(SSH_SESSION *session){
/* decrypt the rest of the packet (blocksize bytes already have been decrypted */
packet_decrypt(session,buffer_get(session->in_buffer)+blocksize,
buffer_get_len(session->in_buffer)-blocksize);
memcpy(mac,buffer_get_rest(session->in_socket_buffer),macsize);
buffer_pass_bytes(session->in_socket_buffer,macsize);
ssh_socket_read(session->socket,mac,macsize);
if(packet_hmac_verify(session,session->in_buffer,mac)){
ssh_set_error(session,SSH_FATAL,"HMAC error");
leave_function();
@ -223,9 +161,11 @@ static int packet_read1(SSH_SESSION *session){
int to_be_read;
u32 padding;
u32 crc;
ssh_say(3,"packet_read1()\n");
if(!session->alive || session->data_except)
return SSH_ERROR; // the error message was already set
enter_function();
if(!session->alive || session->data_except){
leave_function();
return SSH_ERROR; // the error message was already set
}
switch (session->packet_state){
case PACKET_STATE_INIT:
memset(&session->in_packet,0,sizeof(PACKET));
@ -233,18 +173,19 @@ static int packet_read1(SSH_SESSION *session){
buffer_reinit(session->in_buffer);
else
session->in_buffer=buffer_new();
ret=socket_read(session,sizeof(u32));
if(ret!=SSH_OK)
return ret; // could be SSH_AGAIN
buffer_get_u32(session->in_socket_buffer,&len);
/* be_read=completeread(session->fd,&len,sizeof(u32)); */
ret=ssh_socket_read(session->socket,&len,sizeof(u32));
if(ret!=SSH_OK){
leave_function();
return ret; // could be SSH_AGAIN
}
/* len is not encrypted */
len=ntohl(len);
if(len> MAX_PACKET_LEN){
ssh_set_error(session,SSH_FATAL,"read_packet(): Packet len too high(%uld %.8lx)",len,len);
leave_function();
return SSH_ERROR;
}
ssh_say(3,"%d bytes packet\n",len);
ssh_log(session,SSH_LOG_PACKET,"reading a %d bytes packet",len);
session->in_packet.len=len;
session->packet_state=PACKET_STATE_SIZEREAD;
case PACKET_STATE_SIZEREAD:
@ -253,12 +194,13 @@ static int packet_read1(SSH_SESSION *session){
padding=8-(len % 8);
to_be_read=len+padding;
/* it is *not* possible that to_be_read be < 8. */
ret=socket_read(session,to_be_read);
if(ret != SSH_OK)
return ret; // can be SSH_ERROR or SSH_AGAIN
packet=malloc(to_be_read);
memcpy(packet,buffer_get_rest(session->in_socket_buffer),to_be_read);
buffer_pass_bytes(session->in_socket_buffer,to_be_read);
ret=ssh_socket_read(session->socket,packet,to_be_read);
if(ret != SSH_OK){
free(packet);
leave_function();
return ret; // can be SSH_ERROR or SSH_AGAIN
}
buffer_add_data(session->in_buffer,packet,to_be_read);
free(packet);
@ -276,10 +218,11 @@ static int packet_read1(SSH_SESSION *session){
ssh_print_hexa("read packet decrypted:",
buffer_get(session->in_buffer),buffer_get_len(session->in_buffer));
#endif
ssh_say(3,"%d bytes padding\n",padding);
ssh_log(session,SSH_LOG_PACKET,"%d bytes padding",padding);
if((len+padding) != buffer_get_rest_len(session->in_buffer) || (len+padding) < sizeof(u32)){
ssh_say(2,"no crc32 in packet\n");
ssh_log(session,SSH_LOG_RARE,"no crc32 in packet");
ssh_set_error(session,SSH_FATAL,"no crc32 in packet");
leave_function();
return SSH_ERROR;
}
memcpy(&crc,buffer_get_rest(session->in_buffer)+(len+padding)-sizeof(u32),
@ -291,14 +234,15 @@ static int packet_read1(SSH_SESSION *session){
ssh_print_hexa("crc32 on",buffer_get_rest(session->in_buffer),
len + padding - sizeof(u32));
#endif
ssh_say(2,"invalid crc32\n");
ssh_log(session,SSH_LOG_RARE,"invalid crc32");
ssh_set_error(session,SSH_FATAL,"invalid crc32 : expected %.8lx, "
"got %.8lx",crc,
ssh_crc32(buffer_get_rest(session->in_buffer),len+padding-sizeof(u32)) );
leave_function();
return SSH_ERROR;
}
buffer_pass_bytes(session->in_buffer,padding); /*pass the padding*/
ssh_say(3,"the packet is valid\n");
ssh_log(session,SSH_LOG_PACKET,"the packet is valid");
/* will do that later
#ifdef HAVE_LIBZ
if(session->current_crypto && session->current_crypto->do_compress_in){
@ -308,9 +252,11 @@ static int packet_read1(SSH_SESSION *session){
*/
session->recv_seq++;
session->packet_state=PACKET_STATE_INIT;
leave_function();
return SSH_OK;
}
ssh_set_error(session,SSH_FATAL,"Invalid state into packet_read2() : %d",session->packet_state);
ssh_set_error(session,SSH_FATAL,"Invalid state into packet_read1() : %d",session->packet_state);
leave_function();
return SSH_ERROR;
}
@ -345,123 +291,23 @@ int packet_translate(SSH_SESSION *session){
return 0;
}
// FIXME moves it in socket.c and rename it ssh_socket_completewrite()
static int atomic_write(struct socket *s, void *buffer, int len){
int written;
if(!ssh_socket_is_open(s))
return SSH_ERROR;
while(len >0) {
written=ssh_socket_write(s,buffer,len);
if(written==0 || written==-1)
return SSH_ERROR;
len-=written;
buffer+=written;
}
return SSH_OK;
}
/* when doing a nonblocking write, you should issue the packet_write only once, then
* do packet_nonblocking_flush() until you get a SSH_OK or a SSH_ERROR */
static int packet_nonblocking_flush(SSH_SESSION *session){
int except, can_write;
int w;
enter_function();
ssh_fd_poll(session,&can_write,&except); /* internally sets data_to_write */
if(!ssh_socket_is_open(session->socket)){
session->alive=0;
// FIXME use ssh_socket_get_errno
ssh_set_error(session,SSH_FATAL,"Writing packet : error on socket (or connection closed): %s",strerror(errno));
leave_function();
return SSH_ERROR;
}
while(session->data_to_write && buffer_get_rest_len(session->out_socket_buffer)>0){
if(ssh_socket_is_open(session->socket)){
w=ssh_socket_write(session->socket,buffer_get_rest(session->out_socket_buffer),
buffer_get_rest_len(session->out_socket_buffer));
session->data_to_write=0;
} else
w=-1; /* write failed */
if(w<0){
session->data_to_write=0;
session->data_except=1;
session->alive=0;
ssh_socket_close(session->socket);
// FIXME use ssh_socket_get_errno()
ssh_set_error(session,SSH_FATAL,"Writing packet : error on socket (or connection closed): %s",
strerror(errno));
leave_function();
return SSH_ERROR;
}
buffer_pass_bytes(session->out_socket_buffer,w);
/* refresh the socket status */
ssh_fd_poll(session,&can_write,&except);
}
if(buffer_get_rest_len(session->out_socket_buffer)>0){
leave_function();
return SSH_AGAIN; /* there is data pending */
}
leave_function();
return SSH_OK; // all data written
}
/* blocking packet flush */
static int packet_blocking_flush(SSH_SESSION *session){
enter_function();
if(!ssh_socket_is_open(session->socket)) {
session->alive=0;
leave_function();
return SSH_ERROR;
}
if(session->data_except){
leave_function();
return SSH_ERROR;
}
if(buffer_get_rest(session->out_socket_buffer)==0){
leave_function();
return SSH_OK;
}
if(atomic_write(session->socket,buffer_get_rest(session->out_socket_buffer),
buffer_get_rest_len(session->out_socket_buffer))){
session->data_to_write=0;
session->data_except=1;
session->alive=0;
ssh_socket_close(session->socket);
// FIXME use the proper errno
ssh_set_error(session,SSH_FATAL,"Writing packet : error on socket (or connection closed): %s",
strerror(errno));
leave_function();
return SSH_ERROR;
}
session->data_to_write=0;
buffer_reinit(session->out_socket_buffer);
leave_function();
return SSH_OK; // no data pending
}
/* Write the the bufferized output. If the session is blocking, or enforce_blocking
* is set, the call may block. Otherwise, it won't block.
* return SSH°OK if everything has been sent, SSH_AGAIN if there are still things
* to send on buffer, SSH_ERROR if there is an error. */
int packet_flush(SSH_SESSION *session, int enforce_blocking){
if(enforce_blocking || session->blocking)
return packet_blocking_flush(session);
return packet_nonblocking_flush(session);
return ssh_socket_blocking_flush(session->socket);
return ssh_socket_nonblocking_flush(session->socket);
}
/* this function places the outgoing packet buffer into an outgoing socket buffer */
static int socket_write(SSH_SESSION *session){
static int packet_write(SSH_SESSION *session){
int ret;
enter_function();
if(!session->out_socket_buffer){
session->out_socket_buffer=buffer_new();
}
buffer_add_data(session->out_socket_buffer,
buffer_get(session->out_buffer),buffer_get_len(session->out_buffer));
if(!session->blocking)
ret = packet_nonblocking_flush(session);
else
ret = packet_blocking_flush(session);
leave_function();
ssh_socket_write(session->socket,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer));
ret=packet_flush(session,0);
leave_function();
return ret;
}
@ -497,7 +343,7 @@ static int packet_send2(SSH_SESSION *session){
hmac=packet_encrypt(session,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer));
if(hmac)
buffer_add_data(session->out_buffer,hmac,20);
ret=socket_write(session);
ret=packet_write(session);
session->send_seq++;
buffer_reinit(session->out_buffer);
leave_function();
@ -513,7 +359,8 @@ static int packet_send1(SSH_SESSION *session){
u32 currentlen=buffer_get_len(session->out_buffer)+sizeof(u32);
int ret=0;
unsigned int blocksize=(session->current_crypto?session->current_crypto->out_cipher->blocksize:8);
ssh_say(3,"Writing on the wire a packet having %ld bytes before",currentlen);
enter_function();
ssh_log(session,SSH_LOG_PACKET,"Sending a %d bytes long packet",currentlen);
/*
#ifdef HAVE_LIBZ
if(session->current_crypto && session->current_crypto->do_compress_out){
@ -528,7 +375,7 @@ static int packet_send1(SSH_SESSION *session){
else
memset(padstring,0,padding);
finallen=htonl(currentlen);
ssh_say(3,",%d bytes after comp + %d padding bytes = %d bytes packet\n",currentlen,padding,(ntohl(finallen)));
ssh_log(session,SSH_LOG_PACKET,"%d bytes after comp + %d padding bytes = %d bytes packet",currentlen,padding,(ntohl(finallen)));
buffer_add_data_begin(session->out_buffer,&padstring,padding);
buffer_add_data_begin(session->out_buffer,&finallen,sizeof(u32));
crc=ssh_crc32(buffer_get(session->out_buffer)+sizeof(u32),buffer_get_len(session->out_buffer)-sizeof(u32));
@ -542,9 +389,11 @@ static int packet_send1(SSH_SESSION *session){
ssh_print_hexa("encrypted packet",buffer_get(session->out_buffer),
buffer_get_len(session->out_buffer));
#endif
ret=socket_write(session);
ssh_socket_write(session->socket,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer));
ret=packet_flush(session,0);
session->send_seq++;
buffer_reinit(session->out_buffer);
leave_function();
return ret; /* SSH_OK, AGAIN or ERROR */
}
@ -620,16 +469,18 @@ void packet_parse(SSH_SESSION *session){
#ifdef HAVE_SSH1
static int packet_wait1(SSH_SESSION *session,int type,int blocking){
ssh_say(3,"packet_wait1 waiting for %d\n",type);
enter_function();
ssh_log(session,SSH_LOG_PROTOCOL,"packet_wait1 waiting for %d",type);
while(1){
if(packet_read1(session))
if(packet_read1(session) || packet_translate(session)){
leave_function();
return -1;
if(packet_translate(session))
return -1;
ssh_say(3,"packet_wait 1 received %d\n",session->in_packet.type);
}
ssh_log(session,SSH_LOG_PACKET,"packet_wait 1 received a type %d packet",session->in_packet.type);
switch(session->in_packet.type){
case SSH_MSG_DISCONNECT:
packet_parse(session);
leave_function();
return -1;
case SSH_SMSG_STDOUT_DATA:
case SSH_SMSG_STDERR_DATA:
@ -645,13 +496,18 @@ static int packet_wait1(SSH_SESSION *session,int type,int blocking){
default:
if(type && (type != session->in_packet.type)){
ssh_set_error(session,SSH_FATAL,"waitpacket(): Received a %d type packet, was waiting for a %d\n",session->in_packet.type,type);
leave_function();
return -1;
}
leave_function();
return 0;
}
if(blocking==0)
return 0;
if(blocking==0){
leave_function();
return 0;
}
}
leave_function();
return 0;
}
#endif /* HAVE_SSH1 */
@ -709,12 +565,3 @@ int packet_wait(SSH_SESSION *session, int type, int block){
#endif
return packet_wait2(session,type,block);
}
void packet_clear_out(SSH_SESSION *session){
if(session->out_buffer)
buffer_reinit(session->out_buffer);
else
session->out_buffer=buffer_new();
}

Просмотреть файл

@ -163,7 +163,7 @@ SSH_SESSION *ssh_bind_accept(SSH_BIND *ssh_bind){
session=ssh_new();
session->server=1;
session->version=2;
session->socket=ssh_socket_new();
session->socket=ssh_socket_new(session);
ssh_socket_set_fd(session->socket,fd);
session->options=ssh_options_copy(ssh_bind->options);
session->dsa_key=dsa;
@ -260,7 +260,6 @@ static int dh_handshake_server(SSH_SESSION *session){
free(sign);
packet_send(session);
free(f);
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS);
packet_send(session);
ssh_say(2,"SSH_MSG_NEWKEYS sent\n");

Просмотреть файл

@ -1,7 +1,7 @@
/* session.c */
/* contains the non-networking functions ssh_* */
/*
* Copyright 2005-2008 Aris Adamantiadis
* Copyright (c) 2005-2008 Aris Adamantiadis
*
* This file is part of the SSH Library
*
@ -41,10 +41,12 @@ SSH_SESSION *ssh_new() {
memset(session,0,sizeof(SSH_SESSION));
session->next_crypto=crypto_new();
session->maxchannel=FIRST_CHANNEL;
session->socket=ssh_socket_new();
session->socket=ssh_socket_new(session);
session->alive=0;
session->blocking=1;
session->log_indent=0;
session->out_buffer=buffer_new();
session->in_buffer=buffer_new();
return session;
}
@ -59,10 +61,6 @@ void ssh_cleanup(SSH_SESSION *session){
buffer_free(session->in_buffer);
if(session->out_buffer)
buffer_free(session->out_buffer);
if(session->in_socket_buffer)
buffer_free(session->in_socket_buffer);
if(session->out_socket_buffer)
buffer_free(session->out_socket_buffer);
if(session->banner)
free(session->banner);
if(session->options)
@ -105,7 +103,6 @@ void ssh_cleanup(SSH_SESSION *session){
*/
void ssh_silent_disconnect(SSH_SESSION *session){
enter_function();
ssh_log(session,SSH_LOG_ENTRY,"ssh_silent_disconnect()");
ssh_socket_close(session->socket);
session->alive=0;
ssh_disconnect(session);

Просмотреть файл

@ -1,7 +1,7 @@
/* socket.c */
/* the Socket class */
/*
* Copyright 2008 Aris Adamantiadis
* Copyright (c) 2008 Aris Adamantiadis
*
* This file is part of the SSH Library
*
@ -22,6 +22,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
#ifdef _WIN32
#include <winsock2.h>
#else
@ -30,9 +31,17 @@
#endif
#include "libssh/priv.h"
/** \defgroup ssh_socket Sockets
* \addtogroup ssh_socket
* @{
*/
struct socket {
socket_t fd;
int last_errno;
BUFFER *out_buffer;
BUFFER *in_buffer;
SSH_SESSION *session;
};
/*
@ -51,10 +60,13 @@ void ssh_socket_init(){
* \internal
* \brief creates a new Socket object
*/
struct socket *ssh_socket_new(){
struct socket *ssh_socket_new(SSH_SESSION *session){
struct socket *s=malloc(sizeof(struct socket));
s->fd=-1;
s->last_errno=-1;
s->session=session;
s->in_buffer=buffer_new();
s->out_buffer=buffer_new();
return s;
}
@ -63,6 +75,8 @@ struct socket *ssh_socket_new(){
*/
void ssh_socket_free(struct socket *s){
ssh_socket_close(s);
buffer_free(s->in_buffer);
buffer_free(s->out_buffer);
free(s);
}
@ -106,7 +120,7 @@ int ssh_socket_is_open(struct socket *s){
/* \internal
* \brief read len bytes from socket into buffer
*/
int ssh_socket_read(struct socket *s, void *buffer, int len){
int ssh_socket_unbuffered_read(struct socket *s, void *buffer, int len){
int r=recv(s->fd,buffer,len,0);
#ifndef _WIN32
s->last_errno=errno;
@ -117,9 +131,9 @@ int ssh_socket_read(struct socket *s, void *buffer, int len){
}
/* \internal
* \brief writes len bytes from byffer to socket
* \brief writes len bytes from buffer to socket
*/
int ssh_socket_write(struct socket *s,const void *buffer, int len){
int ssh_socket_unbuffered_write(struct socket *s,const void *buffer, int len){
int w=send(s->fd,buffer,len,0);
#ifndef _WIN32
s->last_errno=errno;
@ -152,7 +166,7 @@ void ssh_socket_fd_set(struct socket *s, fd_set *set, int *fd_max){
}
}
/* \internal
/** \internal
* \brief reads blocking until len bytes have been read
*/
int ssh_socket_completeread(struct socket *s, void *buffer, int len){
@ -161,7 +175,7 @@ int ssh_socket_completeread(struct socket *s, void *buffer, int len){
int toread=len;
if(!ssh_socket_is_open(s))
return SSH_ERROR;
while((r=ssh_socket_read(s,buffer+total,toread))){
while((r=ssh_socket_unbuffered_read(s,buffer+total,toread))){
if(r==-1)
return SSH_ERROR;
total += r;
@ -173,3 +187,270 @@ int ssh_socket_completeread(struct socket *s, void *buffer, int len){
}
return total ; /* connection closed */
}
/** \internal
* \brief Blocking write of len bytes
*/
int ssh_socket_completewrite(struct socket *s, void *buffer, int len){
SSH_SESSION *session=s->session;
enter_function();
int written;
if(!ssh_socket_is_open(s)){
leave_function();
return SSH_ERROR;
}
while(len >0) {
written=ssh_socket_unbuffered_write(s,buffer,len);
if(written==0 || written==-1){
leave_function();
return SSH_ERROR;
}
len-=written;
buffer+=written;
}
leave_function();
return SSH_OK;
}
/** \internal
* \brief buffered read of data (complete)
* \returns SSH_OK or SSH_ERROR.
* \returns SSH_AGAIN in nonblocking mode
*/
int ssh_socket_read(struct socket *s, void *buffer, int len){
SSH_SESSION *session=s->session;
enter_function();
int ret=ssh_socket_wait_for_data(s,s->session,len);
if(ret != SSH_OK){
leave_function();
return ret;
}
memcpy(buffer,buffer_get_rest(s->in_buffer),len);
buffer_pass_bytes(s->in_buffer,len);
leave_function();
return SSH_OK;
}
#define WRITE_BUFFERING_THRESHOLD 65536
/** \internal
* \brief buffered write of data
* \returns SSH_OK, or SSH_ERROR
* \warning has no effect on socket before a flush
*/
int ssh_socket_write(struct socket *s,const void *buffer, int len){
SSH_SESSION *session=s->session;
enter_function();
int ret;
buffer_add_data(s->out_buffer,buffer,len);
if(buffer_get_rest_len(s->out_buffer) > WRITE_BUFFERING_THRESHOLD)
ret=ssh_socket_nonblocking_flush(s);
else
ret=len;
leave_function();
return ret;
}
/** \internal
* \brief wait for data on socket
* \param s socket
* \param session the ssh session
* \param len number of bytes to be read
* \returns SSH_OK bytes are available on socket
* \returns SSH_AGAIN need to call later for data
* \returns SSH_ERROR error happened
*/
int ssh_socket_wait_for_data(struct socket *s, SSH_SESSION *session,int len){
int except, can_write;
int to_read;
int r;
char *buf;
char buffer[4096];
enter_function();
to_read=len - buffer_get_rest_len(s->in_buffer);
if(to_read <= 0){
leave_function();
return SSH_OK;
}
if(session->blocking){
buf=malloc(to_read);
r=ssh_socket_completeread(session->socket,buf,to_read);
session->data_to_read=0;
if(r==SSH_ERROR || r ==0){
ssh_set_error(session,SSH_FATAL,
(r==0)?"Connection closed by remote host" : "Error reading socket");
ssh_socket_close(session->socket);
session->alive=0;
session->data_except=1;
leave_function();
return SSH_ERROR;
}
buffer_add_data(s->in_buffer,buf,to_read);
free(buf);
leave_function();
return SSH_OK;
}
/* nonblocking read */
do {
ssh_socket_poll(s,&can_write,&except); /* internally sets data_to_read */
if(!session->data_to_read){
leave_function();
return SSH_AGAIN;
}
session->data_to_read=0;
/* read as much as we can */
if(ssh_socket_is_open(session->socket))
r=ssh_socket_unbuffered_read(session->socket,buffer,sizeof(buffer));
else
r=-1;
if(r<=0){
ssh_set_error(session,SSH_FATAL,
(r==0)?"Connection closed by remote host" : "Error reading socket");
ssh_socket_close(session->socket);
session->data_except=1;
session->alive=0;
leave_function();
return SSH_ERROR;
}
buffer_add_data(s->in_buffer,buffer,r);
} while(buffer_get_rest_len(s->in_buffer)<len);
leave_function();
return SSH_OK;
}
/* \internal
* \brief polls the socket for data
* \param session ssh session
* \param write value pointed to set to 1 if it is possible to write
* \param except value pointed to set to 1 if there is an exception
* \return 1 if it is possible to read, 0 otherwise, -1 on error
*/
int ssh_socket_poll(struct socket *s, int *write, int *except){
SSH_SESSION *session=s->session;
struct timeval sometime;
fd_set rdes; // read set
fd_set wdes; // writing set
fd_set edes; // exception set
int fdmax=-1;
FD_ZERO(&rdes);
FD_ZERO(&wdes);
FD_ZERO(&edes);
if(!ssh_socket_is_open(s)){
*except=1;
*write=0;
return 0;
}
if(!session->data_to_read)
ssh_socket_fd_set(s,&rdes,&fdmax);
if(!session->data_to_write)
ssh_socket_fd_set(s,&wdes,&fdmax);
ssh_socket_fd_set(s,&edes,&fdmax);
/* Set to return immediately (no blocking) */
sometime.tv_sec = 0;
sometime.tv_usec = 0;
/* Make the call, and listen for errors */
if (select(fdmax, &rdes,&wdes,&edes, &sometime) < 0) {
ssh_set_error(session,SSH_FATAL, "select: %s", strerror(errno));
leave_function();
return -1;
}
if(!session->data_to_read)
session->data_to_read=ssh_socket_fd_isset(session->socket,&rdes);
if(!session->data_to_write)
session->data_to_write=ssh_socket_fd_isset(session->socket,&wdes);
*except=ssh_socket_fd_isset(session->socket,&edes);
*write=session->data_to_write;
return session->data_to_read;
}
/** \internal
* \brief nonblocking flush of the output buffer
*/
int ssh_socket_nonblocking_flush(struct socket *s){
int except, can_write;
int w;
SSH_SESSION *session=s->session;
enter_function();
ssh_socket_poll(s,&can_write,&except); /* internally sets data_to_write */
if(!ssh_socket_is_open(s)){
session->alive=0;
// FIXME use ssh_socket_get_errno
ssh_set_error(session,SSH_FATAL,"Writing packet : error on socket (or connection closed): %s",strerror(errno));
leave_function();
return SSH_ERROR;
}
while(session->data_to_write && buffer_get_rest_len(s->out_buffer)>0){
if(ssh_socket_is_open(s)){
w=ssh_socket_unbuffered_write(s,buffer_get_rest(s->out_buffer),
buffer_get_rest_len(s->out_buffer));
session->data_to_write=0;
} else
w=-1; /* write failed */
if(w<0){
session->data_to_write=0;
session->data_except=1;
session->alive=0;
ssh_socket_close(s);
// FIXME use ssh_socket_get_errno()
ssh_set_error(session,SSH_FATAL,"Writing packet : error on socket (or connection closed): %s",
strerror(errno));
leave_function();
return SSH_ERROR;
}
buffer_pass_bytes(s->out_buffer,w);
/* refresh the socket status */
ssh_fd_poll(session,&can_write,&except);
}
if(buffer_get_rest_len(s->out_buffer)>0){
leave_function();
return SSH_AGAIN; /* there is data pending */
}
leave_function();
return SSH_OK; // all data written
}
/** \internal
* \brief locking flush of the output buffer
*/
int ssh_socket_blocking_flush(struct socket *s){
SSH_SESSION *session=s->session;
enter_function();
if(!ssh_socket_is_open(s)) {
session->alive=0;
leave_function();
return SSH_ERROR;
}
if(session->data_except){
leave_function();
return SSH_ERROR;
}
if(buffer_get_rest_len(s->out_buffer)==0){
leave_function();
return SSH_OK;
}
if(ssh_socket_completewrite(s,buffer_get_rest(s->out_buffer),
buffer_get_rest_len(s->out_buffer))){
session->data_to_write=0;
session->data_except=1;
session->alive=0;
ssh_socket_close(s);
// FIXME use the proper errno
ssh_set_error(session,SSH_FATAL,"Writing packet : error on socket (or connection closed): %s",
strerror(errno));
leave_function();
return SSH_ERROR;
}
session->data_to_write=0;
buffer_reinit(s->out_buffer);
leave_function();
return SSH_OK; // no data pending
}
/** @}
*/