1/*
2 * packet.c - packet building functions
3 *
4 * This file is part of the SSH Library
5 *
6 * Copyright (c) 2003-2013 by Aris Adamantiadis
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
24#include "config.h"
25
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29#include <errno.h>
30
31#ifndef _WIN32
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#endif
35
36#include "libssh/priv.h"
37#include "libssh/ssh2.h"
38#include "libssh/crypto.h"
39#include "libssh/buffer.h"
40#include "libssh/packet.h"
41#include "libssh/socket.h"
42#include "libssh/channels.h"
43#include "libssh/misc.h"
44#include "libssh/session.h"
45#include "libssh/messages.h"
46#include "libssh/pcap.h"
47#include "libssh/kex.h"
48#include "libssh/auth.h"
49#include "libssh/gssapi.h"
50
51static ssh_packet_callback default_packet_handlers[]= {
52 ssh_packet_disconnect_callback, // SSH2_MSG_DISCONNECT 1
53 ssh_packet_ignore_callback, // SSH2_MSG_IGNORE 2
54 ssh_packet_unimplemented, // SSH2_MSG_UNIMPLEMENTED 3
55 ssh_packet_ignore_callback, // SSH2_MSG_DEBUG 4
56#if WITH_SERVER
57 ssh_packet_service_request, // SSH2_MSG_SERVICE_REQUEST 5
58#else
59 NULL,
60#endif
61 ssh_packet_service_accept, // SSH2_MSG_SERVICE_ACCEPT 6
62 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
63 NULL, NULL, NULL, NULL, NULL, NULL, // 7-19
64 ssh_packet_kexinit, // SSH2_MSG_KEXINIT 20
65 ssh_packet_newkeys, // SSH2_MSG_NEWKEYS 21
66 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
67 NULL, // 22-29
68#if WITH_SERVER
69 ssh_packet_kexdh_init, // SSH2_MSG_KEXDH_INIT 30
70 // SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
71#else
72 NULL,
73#endif
74 ssh_packet_dh_reply, // SSH2_MSG_KEXDH_REPLY 31
75 // SSH2_MSG_KEX_DH_GEX_GROUP 31
76 NULL, // SSH2_MSG_KEX_DH_GEX_INIT 32
77 NULL, // SSH2_MSG_KEX_DH_GEX_REPLY 33
78 NULL, // SSH2_MSG_KEX_DH_GEX_REQUEST 34
79 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
80 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
81 NULL, // 35-49
82#if WITH_SERVER
83 ssh_packet_userauth_request, // SSH2_MSG_USERAUTH_REQUEST 50
84#else
85 NULL,
86#endif
87 ssh_packet_userauth_failure, // SSH2_MSG_USERAUTH_FAILURE 51
88 ssh_packet_userauth_success, // SSH2_MSG_USERAUTH_SUCCESS 52
89 ssh_packet_userauth_banner, // SSH2_MSG_USERAUTH_BANNER 53
90 NULL,NULL,NULL,NULL,NULL,NULL, // 54-59
91 ssh_packet_userauth_pk_ok, // SSH2_MSG_USERAUTH_PK_OK 60
92 // SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
93 // SSH2_MSG_USERAUTH_INFO_REQUEST 60
94 // SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60
95 ssh_packet_userauth_info_response, // SSH2_MSG_USERAUTH_INFO_RESPONSE 61
96 // SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61
97 NULL, // 62
98 NULL, // SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63
99 NULL, // SSH2_MSG_USERAUTH_GSSAPI_ERROR 64
100 NULL, // SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65
101#if defined(WITH_GSSAPI) && defined(WITH_SERVER)
102 ssh_packet_userauth_gssapi_mic, // SSH2_MSG_USERAUTH_GSSAPI_MIC 66
103#else /* WITH_GSSAPI && WITH_SERVER */
104 NULL,
105#endif /* WITH_GSSAPI && WITH_SERVER */
106 NULL, NULL,
107 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
108 NULL, NULL, NULL, NULL, // 67-79
109#ifdef WITH_SERVER
110 ssh_packet_global_request, // SSH2_MSG_GLOBAL_REQUEST 80
111#else /* WITH_SERVER */
112 NULL,
113#endif /* WITH_SERVER */
114 ssh_request_success, // SSH2_MSG_REQUEST_SUCCESS 81
115 ssh_request_denied, // SSH2_MSG_REQUEST_FAILURE 82
116 NULL, NULL, NULL, NULL, NULL, NULL, NULL,// 83-89
117 ssh_packet_channel_open, // SSH2_MSG_CHANNEL_OPEN 90
118 ssh_packet_channel_open_conf, // SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
119 ssh_packet_channel_open_fail, // SSH2_MSG_CHANNEL_OPEN_FAILURE 92
120 channel_rcv_change_window, // SSH2_MSG_CHANNEL_WINDOW_ADJUST 93
121 channel_rcv_data, // SSH2_MSG_CHANNEL_DATA 94
122 channel_rcv_data, // SSH2_MSG_CHANNEL_EXTENDED_DATA 95
123 channel_rcv_eof, // SSH2_MSG_CHANNEL_EOF 96
124 channel_rcv_close, // SSH2_MSG_CHANNEL_CLOSE 97
125 channel_rcv_request, // SSH2_MSG_CHANNEL_REQUEST 98
126 ssh_packet_channel_success, // SSH2_MSG_CHANNEL_SUCCESS 99
127 ssh_packet_channel_failure, // SSH2_MSG_CHANNEL_FAILURE 100
128};
129
130/* in nonblocking mode, socket_read will read as much as it can, and return */
131/* SSH_OK if it has read at least len bytes, otherwise, SSH_AGAIN. */
132/* in blocking mode, it will read at least len bytes and will block until it's ok. */
133
134/** @internal
135 * @handles a data received event. It then calls the handlers for the different packet types
136 * or and exception handler callback.
137 * @param user pointer to current ssh_session
138 * @param data pointer to the data received
139 * @len length of data received. It might not be enough for a complete packet
140 * @returns number of bytes read and processed.
141 */
142int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
143{
144 ssh_session session= (ssh_session) user;
145 unsigned int blocksize = (session->current_crypto ?
146 session->current_crypto->in_cipher->blocksize : 8);
147 unsigned char mac[DIGEST_MAX_LEN] = {0};
148 char buffer[16] = {0};
149 size_t current_macsize = 0;
150 const uint8_t *packet;
151 int to_be_read;
152 int rc;
153 uint32_t len, compsize, payloadsize;
154 uint8_t padding;
155 size_t processed = 0; /* number of byte processed from the callback */
156
157 if(session->current_crypto != NULL) {
158 current_macsize = hmac_digest_len(session->current_crypto->in_hmac);
159 }
160
161 if (data == NULL) {
162 goto error;
163 }
164
165 if (session->session_state == SSH_SESSION_STATE_ERROR) {
166 goto error;
167 }
168
169 switch(session->packet_state) {
170 case PACKET_STATE_INIT:
171 if (receivedlen < blocksize) {
172 /*
173 * We didn't receive enough data to read at least one
174 * block size, give up
175 */
176 return 0;
177 }
178
179 memset(&session->in_packet, 0, sizeof(PACKET));
180
181 if (session->in_buffer) {
182 rc = ssh_buffer_reinit(session->in_buffer);
183 if (rc < 0) {
184 goto error;
185 }
186 } else {
187 session->in_buffer = ssh_buffer_new();
188 if (session->in_buffer == NULL) {
189 goto error;
190 }
191 }
192
193 memcpy(buffer, data, blocksize);
194 processed += blocksize;
195 len = packet_decrypt_len(session, buffer);
196
197 rc = ssh_buffer_add_data(session->in_buffer, buffer, blocksize);
198 if (rc < 0) {
199 goto error;
200 }
201
202 if (len > MAX_PACKET_LEN) {
203 ssh_set_error(session,
204 SSH_FATAL,
205 "read_packet(): Packet len too high(%u %.4x)",
206 len, len);
207 goto error;
208 }
209
210 to_be_read = len - blocksize + sizeof(uint32_t);
211 if (to_be_read < 0) {
212 /* remote sshd sends invalid sizes? */
213 ssh_set_error(session,
214 SSH_FATAL,
215 "Given numbers of bytes left to be read < 0 (%d)!",
216 to_be_read);
217 goto error;
218 }
219
220 /* Saves the status of the current operations */
221 session->in_packet.len = len;
222 session->packet_state = PACKET_STATE_SIZEREAD;
223 /* FALL TROUGH */
224 case PACKET_STATE_SIZEREAD:
225 len = session->in_packet.len;
226 to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize;
227 /* if to_be_read is zero, the whole packet was blocksize bytes. */
228 if (to_be_read != 0) {
229 if (receivedlen - processed < (unsigned int)to_be_read) {
230 /* give up, not enough data in buffer */
231 SSH_LOG(SSH_LOG_PACKET,"packet: partial packet (read len) [len=%d]",len);
232 return processed;
233 }
234
235 packet = ((uint8_t*)data) + processed;
236#if 0
237 ssh_socket_read(session->socket,
238 packet,
239 to_be_read - current_macsize);
240#endif
241
242 rc = ssh_buffer_add_data(session->in_buffer,
243 packet,
244 to_be_read - current_macsize);
245 if (rc < 0) {
246 goto error;
247 }
248 processed += to_be_read - current_macsize;
249 }
250
251 if (session->current_crypto) {
252 /*
253 * Decrypt the rest of the packet (blocksize bytes already
254 * have been decrypted)
255 */
256 uint32_t buffer_len = buffer_get_rest_len(session->in_buffer);
257
258 /* The following check avoids decrypting zero bytes */
259 if (buffer_len > blocksize) {
260 uint8_t *payload = ((uint8_t*)buffer_get_rest(session->in_buffer) + blocksize);
261 uint32_t plen = buffer_len - blocksize;
262
263 rc = packet_decrypt(session, payload, plen);
264 if (rc < 0) {
265 ssh_set_error(session, SSH_FATAL, "Decrypt error");
266 goto error;
267 }
268 }
269
270 /* copy the last part from the incoming buffer */
271 packet = ((uint8_t *)data) + processed;
272 memcpy(mac, packet, current_macsize);
273
274 rc = packet_hmac_verify(session, session->in_buffer, mac, session->current_crypto->in_hmac);
275 if (rc < 0) {
276 ssh_set_error(session, SSH_FATAL, "HMAC error");
277 goto error;
278 }
279 processed += current_macsize;
280 }
281
282 /* skip the size field which has been processed before */
283 buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));
284
285 rc = buffer_get_u8(session->in_buffer, &padding);
286 if (rc == 0) {
287 ssh_set_error(session,
288 SSH_FATAL,
289 "Packet too short to read padding");
290 goto error;
291 }
292
293 if (padding > buffer_get_rest_len(session->in_buffer)) {
294 ssh_set_error(session,
295 SSH_FATAL,
296 "Invalid padding: %d (%d left)",
297 padding,
298 buffer_get_rest_len(session->in_buffer));
299 goto error;
300 }
301 buffer_pass_bytes_end(session->in_buffer, padding);
302 compsize = buffer_get_rest_len(session->in_buffer);
303
304#ifdef WITH_ZLIB
305 if (session->current_crypto
306 && session->current_crypto->do_compress_in
307 && buffer_get_rest_len(session->in_buffer) > 0) {
308 rc = decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN);
309 if (rc < 0) {
310 goto error;
311 }
312 }
313#endif /* WITH_ZLIB */
314 payloadsize = buffer_get_rest_len(session->in_buffer);
315 session->recv_seq++;
316 if (session->raw_counter != NULL) {
317 session->raw_counter->in_bytes += payloadsize;
318 session->raw_counter->in_packets++;
319 }
320
321 /*
322 * We don't want to rewrite a new packet while still executing the
323 * packet callbacks
324 */
325 session->packet_state = PACKET_STATE_PROCESSING;
326 ssh_packet_parse_type(session);
327 SSH_LOG(SSH_LOG_PACKET,
328 "packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
329 session->in_packet.type, len, padding, compsize, payloadsize);
330
331 /* Execute callbacks */
332 ssh_packet_process(session, session->in_packet.type);
333 session->packet_state = PACKET_STATE_INIT;
334 if (processed < receivedlen) {
335 /* Handle a potential packet left in socket buffer */
336 SSH_LOG(SSH_LOG_PACKET,
337 "Processing %" PRIdS " bytes left in socket buffer",
338 receivedlen-processed);
339
340 packet = ((uint8_t*)data) + processed;
341
342 rc = ssh_packet_socket_callback(packet, receivedlen - processed,user);
343 processed += rc;
344 }
345
346 return processed;
347 case PACKET_STATE_PROCESSING:
348 SSH_LOG(SSH_LOG_PACKET, "Nested packet processing. Delaying.");
349 return 0;
350 }
351
352 ssh_set_error(session,
353 SSH_FATAL,
354 "Invalid state into packet_read2(): %d",
355 session->packet_state);
356
357error:
358 session->session_state= SSH_SESSION_STATE_ERROR;
359
360 return processed;
361}
362
363void ssh_packet_register_socket_callback(ssh_session session, ssh_socket s){
364 session->socket_callbacks.data=ssh_packet_socket_callback;
365 session->socket_callbacks.connected=NULL;
366 session->socket_callbacks.controlflow=NULL;
367 session->socket_callbacks.exception=NULL;
368 session->socket_callbacks.userdata=session;
369 ssh_socket_set_callbacks(s,&session->socket_callbacks);
370}
371
372/** @internal
373 * @brief sets the callbacks for the packet layer
374 */
375void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks){
376 if(session->packet_callbacks == NULL){
377 session->packet_callbacks = ssh_list_new();
378 }
379 if (session->packet_callbacks != NULL) {
380 ssh_list_append(session->packet_callbacks, callbacks);
381 }
382}
383
384/** @internal
385 * @brief sets the default packet handlers
386 */
387void ssh_packet_set_default_callbacks(ssh_session session){
388#ifdef WITH_SSH1
389 if(session->version==1){
390 ssh_packet_set_default_callbacks1(session);
391 return;
392 }
393#endif
394 session->default_packet_callbacks.start=1;
395 session->default_packet_callbacks.n_callbacks=sizeof(default_packet_handlers)/sizeof(ssh_packet_callback);
396 session->default_packet_callbacks.user=session;
397 session->default_packet_callbacks.callbacks=default_packet_handlers;
398 ssh_packet_set_callbacks(session, &session->default_packet_callbacks);
399}
400
401/** @internal
402 * @brief dispatch the call of packet handlers callbacks for a received packet
403 * @param type type of packet
404 */
405void ssh_packet_process(ssh_session session, uint8_t type){
406 struct ssh_iterator *i;
407 int r=SSH_PACKET_NOT_USED;
408 ssh_packet_callbacks cb;
409
410 SSH_LOG(SSH_LOG_PACKET, "Dispatching handler for packet type %d",type);
411 if(session->packet_callbacks == NULL){
412 SSH_LOG(SSH_LOG_RARE,"Packet callback is not initialized !");
413
414 return;
415 }
416 i=ssh_list_get_iterator(session->packet_callbacks);
417 while(i != NULL){
418 cb=ssh_iterator_value(ssh_packet_callbacks,i);
419 i=i->next;
420 if(!cb)
421 continue;
422 if(cb->start > type)
423 continue;
424 if(cb->start + cb->n_callbacks <= type)
425 continue;
426 if(cb->callbacks[type - cb->start]==NULL)
427 continue;
428 r=cb->callbacks[type - cb->start](session,type,session->in_buffer,cb->user);
429 if(r==SSH_PACKET_USED)
430 break;
431 }
432 if(r==SSH_PACKET_NOT_USED){
433 SSH_LOG(SSH_LOG_RARE,"Couldn't do anything with packet type %d",type);
434 ssh_packet_send_unimplemented(session, session->recv_seq-1);
435 }
436}
437
438/** @internal
439 * @brief sends a SSH_MSG_UNIMPLEMENTED answer to an unhandled packet
440 * @param session the SSH session
441 * @param seqnum the sequence number of the unknown packet
442 * @return SSH_ERROR on error, else SSH_OK
443 */
444int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum){
445 int rc;
446
447 rc = ssh_buffer_pack(session->out_buffer,
448 "bd",
449 SSH2_MSG_UNIMPLEMENTED,
450 seqnum);
451 if (rc != SSH_OK) {
452 ssh_set_error_oom(session);
453 return SSH_ERROR;
454 }
455 rc = packet_send(session);
456
457 return rc;
458}
459
460/** @internal
461 * @brief handles a SSH_MSG_UNIMPLEMENTED packet
462 */
463SSH_PACKET_CALLBACK(ssh_packet_unimplemented){
464 uint32_t seq;
465 int rc;
466
467 (void)session; /* unused */
468 (void)type;
469 (void)user;
470
471 rc = ssh_buffer_unpack(packet, "d", &seq);
472 if (rc != SSH_OK) {
473 SSH_LOG(SSH_LOG_WARNING,
474 "Could not unpack SSH_MSG_UNIMPLEMENTED packet");
475 }
476
477 SSH_LOG(SSH_LOG_RARE,
478 "Received SSH_MSG_UNIMPLEMENTED (sequence number %d)",seq);
479
480 return SSH_PACKET_USED;
481}
482
483/** @internal
484 * @parse the "Type" header field of a packet and updates the session
485 */
486int ssh_packet_parse_type(ssh_session session) {
487 memset(&session->in_packet, 0, sizeof(PACKET));
488 if(session->in_buffer == NULL) {
489 return SSH_ERROR;
490 }
491
492 if(buffer_get_u8(session->in_buffer, &session->in_packet.type) == 0) {
493 ssh_set_error(session, SSH_FATAL, "Packet too short to read type");
494 return SSH_ERROR;
495 }
496
497 session->in_packet.valid = 1;
498
499 return SSH_OK;
500}
501
502/*
503 * This function places the outgoing packet buffer into an outgoing
504 * socket buffer
505 */
506static int ssh_packet_write(ssh_session session) {
507 int rc = SSH_ERROR;
508
509 rc=ssh_socket_write(session->socket,
510 buffer_get_rest(session->out_buffer),
511 buffer_get_rest_len(session->out_buffer));
512
513 return rc;
514}
515
516static int packet_send2(ssh_session session) {
517 unsigned int blocksize = (session->current_crypto ?
518 session->current_crypto->out_cipher->blocksize : 8);
519 enum ssh_hmac_e hmac_type = (session->current_crypto ?
520 session->current_crypto->out_hmac : session->next_crypto->out_hmac);
521 uint32_t currentlen = buffer_get_rest_len(session->out_buffer);
522 unsigned char *hmac = NULL;
523 char padstring[32] = { 0 };
524 int rc = SSH_ERROR;
525 uint32_t finallen,payloadsize,compsize;
526 uint8_t padding;
527
528 uint8_t header[sizeof(padding) + sizeof(finallen)] = { 0 };
529
530 payloadsize = currentlen;
531#ifdef WITH_ZLIB
532 if (session->current_crypto
533 && session->current_crypto->do_compress_out
534 && buffer_get_rest_len(session->out_buffer)) {
535 if (compress_buffer(session,session->out_buffer) < 0) {
536 goto error;
537 }
538 currentlen = buffer_get_rest_len(session->out_buffer);
539 }
540#endif /* WITH_ZLIB */
541 compsize = currentlen;
542 padding = (blocksize - ((currentlen +5) % blocksize));
543 if(padding < 4) {
544 padding += blocksize;
545 }
546
547 if (session->current_crypto) {
548 ssh_get_random(padstring, padding, 0);
549 }
550
551 finallen = htonl(currentlen + padding + 1);
552
553 memcpy(&header[0], &finallen, sizeof(finallen));
554 header[sizeof(finallen)] = padding;
555 rc = buffer_prepend_data(session->out_buffer, &header, sizeof(header));
556 if (rc < 0) {
557 goto error;
558 }
559 rc = ssh_buffer_add_data(session->out_buffer, padstring, padding);
560 if (rc < 0) {
561 goto error;
562 }
563#ifdef WITH_PCAP
564 if(session->pcap_ctx){
565 ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,
566 buffer_get_rest(session->out_buffer),buffer_get_rest_len(session->out_buffer)
567 ,buffer_get_rest_len(session->out_buffer));
568 }
569#endif
570 hmac = packet_encrypt(session, buffer_get_rest(session->out_buffer),
571 buffer_get_rest_len(session->out_buffer));
572 if (hmac) {
573 rc = ssh_buffer_add_data(session->out_buffer, hmac, hmac_digest_len(hmac_type));
574 if (rc < 0) {
575 goto error;
576 }
577 }
578
579 rc = ssh_packet_write(session);
580 session->send_seq++;
581 if (session->raw_counter != NULL) {
582 session->raw_counter->out_bytes += payloadsize;
583 session->raw_counter->out_packets++;
584 }
585
586 SSH_LOG(SSH_LOG_PACKET,
587 "packet: wrote [len=%d,padding=%hhd,comp=%d,payload=%d]",
588 ntohl(finallen), padding, compsize, payloadsize);
589 if (ssh_buffer_reinit(session->out_buffer) < 0) {
590 rc = SSH_ERROR;
591 }
592error:
593
594 return rc; /* SSH_OK, AGAIN or ERROR */
595}
596
597
598int packet_send(ssh_session session) {
599#ifdef WITH_SSH1
600 if (session->version == 1) {
601 return packet_send1(session);
602 }
603#endif
604 return packet_send2(session);
605}
606