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

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2005-03-04 19:54:59