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 } |