5772970 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$ cat -n packet.c
  1 /* packet.c */  
  2 /* packet building functions */
  3 /*
  4 Copyright 2003 Aris Adamantiadis
  5 
  6 This file is part of the SSH Library
  7 
  8 The SSH Library is free software; you can redistribute it and/or modify
  9 it under the terms of the GNU Lesser General Public License as published by
 10 the Free Software Foundation; either version 2.1 of the License, or (at your
 11 option) any later version.
 12 
 13 The SSH Library is distributed in the hope that it will be useful, but
 14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 16 License for more details.
 17 
 18 You should have received a copy of the GNU Lesser General Public License
 19 along with the SSH Library; see the file COPYING.  If not, write to
 20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 21 MA 02111-1307, USA. */
 22 
 23 #include "libssh/priv.h"
 24 
 25 #include <stdlib.h>
 26 #include <stdio.h>
 27 #include <unistd.h>
 28 #include <string.h>
 29 #include "libssh/ssh2.h"
 30 #ifdef HAVE_NETDB_H
 31 #include <netdb.h>
 32 #endif
 33 #ifdef HAVE_WINDOWS_H
 34 #include <windows.h>
 35 #endif
 36 #ifdef HAVE_SYS_TYPES_H
 37 #include <sys/types.h>
 38 #endif
 39 #ifdef HAVE_SYS_SOCKET_H
 40 #include <sys/socket.h>
 41 #endif
 42 #include <errno.h>
 43 #include "libssh/crypto.h"
 44 
 45 /* XXX include selected mac size */
 46 static int macsize=SHA_DIGEST_LENGTH;
 47 
 48 /* completeread will read blocking until len bytes have been read */
 49 static int completeread(int fd, void *buffer, int len){
 50     int r;
 51     int total=0;
 52     int toread=len;
 53     while((r=recv(fd,buffer+total,toread,0))){
 54         if(r==-1)
 55             return -1;
 56         total += r;
 57         toread-=r;
 58         if(total==len)
 59             return len;
 60         if(r==0)
 61             return 0;
 62     }
 63     return total ; /* connection closed */
 64 }
 65 
 66 int packet_read(SSH_SESSION *session){
 67     u32 len;
 68     void *packet=NULL;
 69     char mac[30];
 70     char buffer[16];
 71     int be_read,i;
 72     int to_be_read;
 73     u8 padding;
 74     unsigned int blocksize=(session->current_crypto?session->current_crypto->in_cipher->blocksize:8);
 75     session->datatoread=0; /* clear the dataavailable flag */
 76     memset(&session->in_packet,0,sizeof(PACKET));
 77     if(session->in_buffer)
 78         buffer_free(session->in_buffer);
 79     session->in_buffer=buffer_new();
 80 
 81     be_read=completeread(session->fd,buffer,blocksize);
 82     if(be_read!=blocksize){
 83         if(be_read<=0){
 84             session->alive=0;
 85             close(session->fd);
 86             session->fd=-1;
 87             ssh_set_error((session->connected?session:NULL),SSH_FATAL,
 88             (be_read==0)?"Connection closed by remote host" : "Error reading socket");
 89             return -1;
 90         }
 91         ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): asked %d bytes, received
	%d",blocksize,be_read);
 92         return -1;
 93     }
 94     len=packet_decrypt_len(session,buffer);
 95     buffer_add_data(session->in_buffer,buffer,blocksize);
 96     
 97     if(len> MAX_PACKET_LEN){
 98         ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): Packet len too high(%uld
	%.8lx)",len,len);
 99         return -1;
100     }
101     to_be_read=len-be_read+sizeof(u32);
102     if(to_be_read<0){
103         /* remote sshd is trying to get me ?*/
104         ssh_set_error((session->connected?session:NULL),SSH_FATAL,"given numbers of bytes left to be read <0
	(%d)!",to_be_read);
105         return -1;
106     }
107     /* handle the case in which the whole packet size = blocksize */
108     if(to_be_read !=0){
109         packet=malloc(to_be_read);
110         i=completeread(session->fd,packet,to_be_read);
111         if(i<=0){
112             session->alive=0;
113             close(session->fd);
114             session->fd=-1;
115             ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Server closed connection");
116             return -1;
117         }
118         if(i!=to_be_read){
119             free(packet);
120             packet=NULL;
121             ssh_say(3,"Read only %d, wanted %d\n",i,to_be_read);
122             ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): read only %d, wanted
	%d",i,to_be_read);
123             return -1;
124         }
125         ssh_say(3,"Read a %d bytes packet\n",len);
126         buffer_add_data(session->in_buffer,packet,to_be_read);
127         free(packet);
128     }
129     if(session->current_crypto){
130         packet_decrypt(session,buffer_get(session->in_buffer)+blocksize,buffer_get_len(session->in_buffer)-blocksize);
131         if((i=completeread(session->fd,mac,macsize))!=macsize){
132             if(i<=0){
133                 session->alive=0;
134                 close(session->fd);
135                 session->fd=-1;
136                 ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Server closed connection");
137                 return -1;
138             }
139             ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): wanted %d, had %d",i,macsize);
140             return -1;
141         }
142         if(packet_hmac_verify(session,session->in_buffer,mac)){
143             ssh_set_error((session->connected?session:NULL),SSH_FATAL,"HMAC error");
144             return -1;
145         }
146     }
147     buffer_pass_bytes(session->in_buffer,sizeof(u32));   /*pass the size which has been processed before*/
148     if(!buffer_get_u8(session->in_buffer,&padding)){
149         ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Packet too short to read padding");
150         return -1;
151     }
152     ssh_say(3,"%hhd bytes padding\n",padding);
153     if(padding > buffer_get_rest_len(session->in_buffer)){
154         ssh_set_error((session->connected?session:NULL),SSH_FATAL,"invalid padding: %d (%d
	resting)",padding,buffer_get_rest_len(session->in_buffer));
155         ssh_print_hexa("incrimined packet",buffer_get(session->in_buffer),buffer_get_len(session->in_buffer));
156         return -1;
157     }
158     buffer_pass_bytes_end(session->in_buffer,padding);
159 #ifdef HAVE_LIBZ
160     if(session->current_crypto && session->current_crypto->do_compress_in){
161         decompress_buffer(session,session->in_buffer);
162     }
163 #endif
164     session->recv_seq++;
165     return 0;
166 }
167 
168 int packet_translate(SSH_SESSION *session){
169     memset(&session->in_packet,0,sizeof(PACKET));
170     if(!session->in_buffer)
171         return -1;
172     ssh_say(3,"Final size %d\n",buffer_get_rest_len(session->in_buffer));
173     if(!buffer_get_u8(session->in_buffer,&session->in_packet.type)){
174         ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Packet too short to read type");
175         return -1;
176     }
177     ssh_say(3,"type %hhd\n",session->in_packet.type);
178     session->in_packet.valid=1;
179     return 0;
180 }
181 
182 static int atomic_write(int fd, void *buffer, int len){
183     int written;
184     int total=0;
185     do {
186         written=send(fd,buffer,len,0);
187         if(written==0)
188             return 0;
189         if(written==-1)
190             return total;
191         total+=written;
192         len-=written;
193         buffer+=written;
194     } while (len > 0);
195     return total;
196 }
197 
198 int packet_send(SSH_SESSION *session){
199     char padstring[32];
200     u32 finallen;
201     u8 padding;
202     u32 currentlen=buffer_get_len(session->out_buffer);
203     char *hmac;
204     int ret=0;
205     unsigned int blocksize=(session->current_crypto?session->current_crypto->out_cipher->blocksize:8);
206     ssh_say(3,"Writing on the wire a packet having %ld bytes before",currentlen);
207 #ifdef HAVE_LIBZ
208     if(session->current_crypto && session->current_crypto->do_compress_out){
209         compress_buffer(session,session->out_buffer);
210         currentlen=buffer_get_len(session->out_buffer);
211     }
212 #endif
213     padding=(blocksize- ((currentlen+5) % blocksize));
214     if(padding<4)
215         padding+=blocksize;
216     if(session->current_crypto)
217         ssh_get_random(padstring,padding);
218     else
219         memset(padstring,0,padding);
220     finallen=htonl(currentlen+padding+1);
221     ssh_say(3,",%d bytes after comp + %d padding bytes = %d bytes packet\n",currentlen,padding,(ntohl(finallen)));
222     buffer_add_data_begin(session->out_buffer,&padding,sizeof(u8));
223     buffer_add_data_begin(session->out_buffer,&finallen,sizeof(u32));
224     buffer_add_data(session->out_buffer,padstring,padding);
225     hmac=packet_encrypt(session,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer));
226     if(hmac)
227         buffer_add_data(session->out_buffer,hmac,20);
228    
	if(atomic_write(session->fd,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer))!=buffer_get_len(sessio
	n->out_buffer)){
229         session->alive=0;
230         close(session->fd);
231         session->fd=-1;
232         ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Writing packet : error on socket (or connection
	closed): %s",
233             strerror(errno));
234         ret=-1;
235     }
236     session->send_seq++;
237     buffer_reinit(session->out_buffer);
238     return ret;
239 }
240 
241 void packet_parse(SSH_SESSION *session){
242     int type=session->in_packet.type;
243     u32 foo;
244     STRING *error_s;
245     char *error=NULL;
246     
247     switch(type){
248         case SSH2_MSG_DISCONNECT:
249             buffer_get_u32(session->in_buffer,&foo);
250             error_s=buffer_get_ssh_string(session->in_buffer);
251             if(error_s)
252                 error=string_to_char(error_s);
253             ssh_say(2,"Received SSH_MSG_DISCONNECT\n");
254             ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Received SSH_MSG_DISCONNECT : %s",error);
255             if(error_s){
256                 free(error_s);
257                 free(error);
258             }
259             close(session->fd);
260             session->fd=-1;
261             session->alive=0;
262             return;
263         case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
264         case SSH2_MSG_CHANNEL_DATA:
265         case SSH2_MSG_CHANNEL_EXTENDED_DATA:
266         case SSH2_MSG_CHANNEL_REQUEST:
267         case SSH2_MSG_CHANNEL_EOF:
268         case SSH2_MSG_CHANNEL_CLOSE:
269 
270             channel_handle(session,type);
271         case SSH2_MSG_IGNORE:
272             return;
273         default:
274             ssh_say(0,"Received unhandled msg %d\n",type);
275     }
276 }    
277 int packet_wait(SSH_SESSION *session,int type,int blocking){
278     while(1){
279         if(packet_read(session))
280             return -1;
281         if(packet_translate(session))
282             return -1;
283         switch(session->in_packet.type){
284            case SSH2_MSG_DISCONNECT:
285                packet_parse(session);
286                 return -1;
287            case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
288            case SSH2_MSG_CHANNEL_DATA:
289            case SSH2_MSG_CHANNEL_EXTENDED_DATA:
290            case SSH2_MSG_CHANNEL_REQUEST:
291            case SSH2_MSG_CHANNEL_EOF:
292            case SSH2_MSG_CHANNEL_CLOSE:
293                packet_parse(session);
294                 break;;
295            case SSH2_MSG_IGNORE:
296                break;
297            default:
298                if(type && (type != session->in_packet.type)){
299                    ssh_set_error((session->connected?session:NULL),SSH_FATAL,"waitpacket(): Received a %d type packet,
	was waiting for a %d\n",session->in_packet.type,type);
300                    return -1;
301                }
302                return 0;
303            }
304         if(blocking==0)
305             return 0;
306     }
307     return 0;
308 }
309 
310 void packet_clear_out(SSH_SESSION *session){
311     if(session->out_buffer)
312         buffer_reinit(session->out_buffer);
313     else
314         session->out_buffer=buffer_new();
315 }
5772971 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2007-02-17 17:46:50