diff options
-rw-r--r-- | include/libssh/libssh.h | 34 | ||||
-rw-r--r-- | include/libssh/priv.h | 21 | ||||
-rw-r--r-- | libssh/auth.c | 8 | ||||
-rw-r--r-- | libssh/auth1.c | 4 | ||||
-rw-r--r-- | libssh/buffer.c | 6 | ||||
-rw-r--r-- | libssh/channels.c | 10 | ||||
-rw-r--r-- | libssh/channels1.c | 6 | ||||
-rw-r--r-- | libssh/client.c | 9 | ||||
-rw-r--r-- | libssh/connect.c | 44 | ||||
-rw-r--r-- | libssh/kex.c | 19 | ||||
-rw-r--r-- | libssh/messages.c | 8 | ||||
-rw-r--r-- | libssh/packet.c | 275 | ||||
-rw-r--r-- | libssh/server.c | 3 | ||||
-rw-r--r-- | libssh/session.c | 11 | ||||
-rw-r--r-- | libssh/socket.c | 295 |
15 files changed, 415 insertions, 338 deletions
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h index c7f0d5c0..36fd0925 100644 --- a/include/libssh/libssh.h +++ b/include/libssh/libssh.h @@ -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); - - /* There is a verbosity level */ - -#define SSH_LOG_NOLOG 0 // no log +/** \addtogroup ssh_log + * @{ + */ + /** \brief Verbosity level for logging and help to debugging + */ + +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, ...); diff --git a/include/libssh/priv.h b/include/libssh/priv.h index d5aeda82..db8fe955 100644 --- a/include/libssh/priv.h +++ b/include/libssh/priv.h @@ -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); diff --git a/libssh/auth.c b/libssh/auth.c index a2fd722d..57d0bd61 100644 --- a/libssh/auth.c +++ b/libssh/auth.c @@ -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){ diff --git a/libssh/auth1.c b/libssh/auth1.c index 865f2257..7844d9ba 100644 --- a/libssh/auth1.c +++ b/libssh/auth1.c @@ -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); diff --git a/libssh/buffer.c b/libssh/buffer.c index 88cca409..3dea65d1 100644 --- a/libssh/buffer.c +++ b/libssh/buffer.c @@ -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); diff --git a/libssh/channels.c b/libssh/channels.c index be87ca3e..10e9223b 100644 --- a/libssh/channels.c +++ b/libssh/channels.c @@ -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); diff --git a/libssh/channels1.c b/libssh/channels1.c index c8ab3e24..d90d2398 100644 --- a/libssh/channels1.c +++ b/libssh/channels1.c @@ -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; diff --git a/libssh/client.c b/libssh/client.c index f06a7363..c1dc6daf 100644 --- a/libssh/client.c +++ b/libssh/client.c @@ -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"); diff --git a/libssh/connect.c b/libssh/connect.c index 8a42b0c1..a5156763 100644 --- a/libssh/connect.c +++ b/libssh/connect.c @@ -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); } diff --git a/libssh/kex.c b/libssh/kex.c index 0856fdfe..f63dbf26 100644 --- a/libssh/kex.c +++ b/libssh/kex.c @@ -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; diff --git a/libssh/messages.c b/libssh/messages.c index be785e4a..e609cbc6 100644 --- a/libssh/messages.c +++ b/libssh/messages.c @@ -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); diff --git a/libssh/packet.c b/libssh/packet.c index 295ef13c..c81ff289 100644 --- a/libssh/packet.c +++ b/libssh/packet.c @@ -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)) - return -1; - if(packet_translate(session)) + if(packet_read1(session) || packet_translate(session)){ + leave_function(); 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(); -} - diff --git a/libssh/server.c b/libssh/server.c index ee9f6d4a..58fbb615 100644 --- a/libssh/server.c +++ b/libssh/server.c @@ -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"); diff --git a/libssh/session.c b/libssh/session.c index f8344fa8..80b9e3a1 100644 --- a/libssh/session.c +++ b/libssh/session.c @@ -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); diff --git a/libssh/socket.c b/libssh/socket.c index 2d82ec66..0aefa017 100644 --- a/libssh/socket.c +++ b/libssh/socket.c @@ -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 +} + +/** @} + */ |