packet.c revision 98937
157429Smarkm/* 257429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 357429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 457429Smarkm * All rights reserved 557429Smarkm * This file contains code implementing the packet protocol and communication 657429Smarkm * with the other side. This same code is used both on client and server side. 760573Skris * 865668Skris * As far as I am concerned, the code I have written for this software 965668Skris * can be used freely for any purpose. Any derived versions of this 1065668Skris * software must be clearly marked as such, and if the derived work is 1165668Skris * incompatible with the protocol description in the RFC file, it must be 1265668Skris * called by a name other than "ssh" or "Secure Shell". 1365668Skris * 1465668Skris * 1560573Skris * SSH2 packet format added by Markus Friedl. 1692555Sdes * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 1760573Skris * 1865668Skris * Redistribution and use in source and binary forms, with or without 1965668Skris * modification, are permitted provided that the following conditions 2065668Skris * are met: 2165668Skris * 1. Redistributions of source code must retain the above copyright 2265668Skris * notice, this list of conditions and the following disclaimer. 2365668Skris * 2. Redistributions in binary form must reproduce the above copyright 2465668Skris * notice, this list of conditions and the following disclaimer in the 2565668Skris * documentation and/or other materials provided with the distribution. 2665668Skris * 2765668Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2865668Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2965668Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 3065668Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3165668Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3265668Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3365668Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3465668Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3565668Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3665668Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3757429Smarkm */ 3857429Smarkm 3957429Smarkm#include "includes.h" 4098675SdesRCSID("$OpenBSD: packet.c,v 1.95 2002/06/19 18:01:00 markus Exp $"); 4157429Smarkm 4257429Smarkm#include "xmalloc.h" 4357429Smarkm#include "buffer.h" 4457429Smarkm#include "packet.h" 4557429Smarkm#include "bufaux.h" 4657429Smarkm#include "crc32.h" 4757429Smarkm#include "getput.h" 4857429Smarkm 4957429Smarkm#include "compress.h" 5057429Smarkm#include "deattack.h" 5160573Skris#include "channels.h" 5257429Smarkm 5360573Skris#include "compat.h" 5476259Sgreen#include "ssh1.h" 5560573Skris#include "ssh2.h" 5660573Skris 5769587Sgreen#include "cipher.h" 5860573Skris#include "kex.h" 5976259Sgreen#include "mac.h" 6076259Sgreen#include "log.h" 6176259Sgreen#include "canohost.h" 6292555Sdes#include "misc.h" 6398675Sdes#include "ssh.h" 6460573Skris 6560573Skris#ifdef PACKET_DEBUG 6660573Skris#define DBG(x) x 6760573Skris#else 6860573Skris#define DBG(x) 6960573Skris#endif 7060573Skris 7157429Smarkm/* 7257429Smarkm * This variable contains the file descriptors used for communicating with 7357429Smarkm * the other side. connection_in is used for reading; connection_out for 7457429Smarkm * writing. These can be the same descriptor, in which case it is assumed to 7557429Smarkm * be a socket. 7657429Smarkm */ 7757429Smarkmstatic int connection_in = -1; 7857429Smarkmstatic int connection_out = -1; 7957429Smarkm 8057429Smarkm/* Protocol flags for the remote side. */ 8176259Sgreenstatic u_int remote_protocol_flags = 0; 8257429Smarkm 8357429Smarkm/* Encryption context for receiving data. This is only used for decryption. */ 8457429Smarkmstatic CipherContext receive_context; 8557429Smarkm 8657429Smarkm/* Encryption context for sending data. This is only used for encryption. */ 8757429Smarkmstatic CipherContext send_context; 8857429Smarkm 8957429Smarkm/* Buffer for raw input data from the socket. */ 9098675SdesBuffer input; 9157429Smarkm 9257429Smarkm/* Buffer for raw output data going to the socket. */ 9398675SdesBuffer output; 9457429Smarkm 9557429Smarkm/* Buffer for the partial outgoing packet being constructed. */ 9657429Smarkmstatic Buffer outgoing_packet; 9757429Smarkm 9857429Smarkm/* Buffer for the incoming packet currently being processed. */ 9957429Smarkmstatic Buffer incoming_packet; 10057429Smarkm 10157429Smarkm/* Scratch buffer for packet compression/decompression. */ 10257429Smarkmstatic Buffer compression_buffer; 10376259Sgreenstatic int compression_buffer_ready = 0; 10457429Smarkm 10557429Smarkm/* Flag indicating whether packet compression/decompression is enabled. */ 10657429Smarkmstatic int packet_compression = 0; 10757429Smarkm 10857429Smarkm/* default maximum packet size */ 10957429Smarkmint max_packet_size = 32768; 11057429Smarkm 11157429Smarkm/* Flag indicating whether this module has been initialized. */ 11257429Smarkmstatic int initialized = 0; 11357429Smarkm 11457429Smarkm/* Set to true if the connection is interactive. */ 11557429Smarkmstatic int interactive_mode = 0; 11657429Smarkm 11760573Skris/* Session key information for Encryption and MAC */ 11876259SgreenNewkeys *newkeys[MODE_MAX]; 11998675Sdesstatic u_int32_t read_seqnr = 0; 12098675Sdesstatic u_int32_t send_seqnr = 0; 12160573Skris 12298675Sdes/* Session key for protocol v1 */ 12398675Sdesstatic u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; 12498675Sdesstatic u_int ssh1_keylen; 12598675Sdes 12692555Sdes/* roundup current message to extra_pad bytes */ 12792555Sdesstatic u_char extra_pad = 0; 12860573Skris 12957429Smarkm/* 13057429Smarkm * Sets the descriptors used for communication. Disables encryption until 13157429Smarkm * packet_set_encryption_key is called. 13257429Smarkm */ 13357429Smarkmvoid 13457429Smarkmpacket_set_connection(int fd_in, int fd_out) 13557429Smarkm{ 13669587Sgreen Cipher *none = cipher_by_name("none"); 13769587Sgreen if (none == NULL) 13869587Sgreen fatal("packet_set_connection: cannot load cipher 'none'"); 13957429Smarkm connection_in = fd_in; 14057429Smarkm connection_out = fd_out; 14192555Sdes cipher_init(&send_context, none, "", 0, NULL, 0, CIPHER_ENCRYPT); 14292555Sdes cipher_init(&receive_context, none, "", 0, NULL, 0, CIPHER_DECRYPT); 14392555Sdes newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL; 14457429Smarkm if (!initialized) { 14557429Smarkm initialized = 1; 14657429Smarkm buffer_init(&input); 14757429Smarkm buffer_init(&output); 14857429Smarkm buffer_init(&outgoing_packet); 14957429Smarkm buffer_init(&incoming_packet); 15057429Smarkm } 15157429Smarkm /* Kludge: arrange the close function to be called from fatal(). */ 15257429Smarkm fatal_add_cleanup((void (*) (void *)) packet_close, NULL); 15357429Smarkm} 15457429Smarkm 15557429Smarkm/* Returns 1 if remote host is connected via socket, 0 if not. */ 15657429Smarkm 15757429Smarkmint 15892555Sdespacket_connection_is_on_socket(void) 15957429Smarkm{ 16057429Smarkm struct sockaddr_storage from, to; 16157429Smarkm socklen_t fromlen, tolen; 16257429Smarkm 16357429Smarkm /* filedescriptors in and out are the same, so it's a socket */ 16457429Smarkm if (connection_in == connection_out) 16557429Smarkm return 1; 16657429Smarkm fromlen = sizeof(from); 16757429Smarkm memset(&from, 0, sizeof(from)); 16857429Smarkm if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0) 16957429Smarkm return 0; 17057429Smarkm tolen = sizeof(to); 17157429Smarkm memset(&to, 0, sizeof(to)); 17257429Smarkm if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0) 17357429Smarkm return 0; 17457429Smarkm if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0) 17557429Smarkm return 0; 17657429Smarkm if (from.ss_family != AF_INET && from.ss_family != AF_INET6) 17757429Smarkm return 0; 17857429Smarkm return 1; 17957429Smarkm} 18057429Smarkm 18198675Sdes/* 18298675Sdes * Exports an IV from the CipherContext required to export the key 18398675Sdes * state back from the unprivileged child to the privileged parent 18498675Sdes * process. 18598675Sdes */ 18698675Sdes 18798675Sdesvoid 18898675Sdespacket_get_keyiv(int mode, u_char *iv, u_int len) 18998675Sdes{ 19098675Sdes CipherContext *cc; 19198675Sdes 19298675Sdes if (mode == MODE_OUT) 19398675Sdes cc = &send_context; 19498675Sdes else 19598675Sdes cc = &receive_context; 19698675Sdes 19798675Sdes cipher_get_keyiv(cc, iv, len); 19898675Sdes} 19998675Sdes 20098675Sdesint 20198675Sdespacket_get_keycontext(int mode, u_char *dat) 20298675Sdes{ 20398675Sdes CipherContext *cc; 20498675Sdes 20598675Sdes if (mode == MODE_OUT) 20698675Sdes cc = &send_context; 20798675Sdes else 20898675Sdes cc = &receive_context; 20998675Sdes 21098675Sdes return (cipher_get_keycontext(cc, dat)); 21198675Sdes} 21298675Sdes 21398675Sdesvoid 21498675Sdespacket_set_keycontext(int mode, u_char *dat) 21598675Sdes{ 21698675Sdes CipherContext *cc; 21798675Sdes 21898675Sdes if (mode == MODE_OUT) 21998675Sdes cc = &send_context; 22098675Sdes else 22198675Sdes cc = &receive_context; 22298675Sdes 22398675Sdes cipher_set_keycontext(cc, dat); 22498675Sdes} 22598675Sdes 22698675Sdesint 22798675Sdespacket_get_keyiv_len(int mode) 22898675Sdes{ 22998675Sdes CipherContext *cc; 23098675Sdes 23198675Sdes if (mode == MODE_OUT) 23298675Sdes cc = &send_context; 23398675Sdes else 23498675Sdes cc = &receive_context; 23598675Sdes 23698675Sdes return (cipher_get_keyiv_len(cc)); 23798675Sdes} 23898675Sdesvoid 23998675Sdespacket_set_iv(int mode, u_char *dat) 24098675Sdes{ 24198675Sdes CipherContext *cc; 24298675Sdes 24398675Sdes if (mode == MODE_OUT) 24498675Sdes cc = &send_context; 24598675Sdes else 24698675Sdes cc = &receive_context; 24798675Sdes 24898675Sdes cipher_set_keyiv(cc, dat); 24998675Sdes} 25098675Sdesint 25198675Sdespacket_get_ssh1_cipher() 25298675Sdes{ 25398675Sdes return (cipher_get_number(receive_context.cipher)); 25498675Sdes} 25598675Sdes 25698675Sdes 25798675Sdesu_int32_t 25898675Sdespacket_get_seqnr(int mode) 25998675Sdes{ 26098675Sdes return (mode == MODE_IN ? read_seqnr : send_seqnr); 26198675Sdes} 26298675Sdes 26398675Sdesvoid 26498675Sdespacket_set_seqnr(int mode, u_int32_t seqnr) 26598675Sdes{ 26698675Sdes if (mode == MODE_IN) 26798675Sdes read_seqnr = seqnr; 26898675Sdes else if (mode == MODE_OUT) 26998675Sdes send_seqnr = seqnr; 27098675Sdes else 27198675Sdes fatal("packet_set_seqnr: bad mode %d", mode); 27298675Sdes} 27398675Sdes 27457429Smarkm/* returns 1 if connection is via ipv4 */ 27557429Smarkm 27657429Smarkmint 27792555Sdespacket_connection_is_ipv4(void) 27857429Smarkm{ 27957429Smarkm struct sockaddr_storage to; 28057429Smarkm socklen_t tolen = sizeof(to); 28157429Smarkm 28257429Smarkm memset(&to, 0, sizeof(to)); 28357429Smarkm if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0) 28457429Smarkm return 0; 28598937Sdes if (to.ss_family == AF_INET) 28698937Sdes return 1; 28798937Sdes#ifdef IPV4_IN_IPV6 28898937Sdes if (to.ss_family == AF_INET6 && 28998937Sdes IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr)) 29098937Sdes return 1; 29198937Sdes#endif 29298937Sdes return 0; 29357429Smarkm} 29457429Smarkm 29557429Smarkm/* Sets the connection into non-blocking mode. */ 29657429Smarkm 29757429Smarkmvoid 29892555Sdespacket_set_nonblocking(void) 29957429Smarkm{ 30057429Smarkm /* Set the socket into non-blocking mode. */ 30157429Smarkm if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0) 30257429Smarkm error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 30357429Smarkm 30457429Smarkm if (connection_out != connection_in) { 30557429Smarkm if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0) 30657429Smarkm error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 30757429Smarkm } 30857429Smarkm} 30957429Smarkm 31057429Smarkm/* Returns the socket used for reading. */ 31157429Smarkm 31257429Smarkmint 31392555Sdespacket_get_connection_in(void) 31457429Smarkm{ 31557429Smarkm return connection_in; 31657429Smarkm} 31757429Smarkm 31857429Smarkm/* Returns the descriptor used for writing. */ 31957429Smarkm 32057429Smarkmint 32192555Sdespacket_get_connection_out(void) 32257429Smarkm{ 32357429Smarkm return connection_out; 32457429Smarkm} 32557429Smarkm 32657429Smarkm/* Closes the connection and clears and frees internal data structures. */ 32757429Smarkm 32857429Smarkmvoid 32992555Sdespacket_close(void) 33057429Smarkm{ 33157429Smarkm if (!initialized) 33257429Smarkm return; 33357429Smarkm initialized = 0; 33457429Smarkm if (connection_in == connection_out) { 33557429Smarkm shutdown(connection_out, SHUT_RDWR); 33657429Smarkm close(connection_out); 33757429Smarkm } else { 33857429Smarkm close(connection_in); 33957429Smarkm close(connection_out); 34057429Smarkm } 34157429Smarkm buffer_free(&input); 34257429Smarkm buffer_free(&output); 34357429Smarkm buffer_free(&outgoing_packet); 34457429Smarkm buffer_free(&incoming_packet); 34576259Sgreen if (compression_buffer_ready) { 34657429Smarkm buffer_free(&compression_buffer); 34757429Smarkm buffer_compress_uninit(); 34857429Smarkm } 34992555Sdes cipher_cleanup(&send_context); 35092555Sdes cipher_cleanup(&receive_context); 35157429Smarkm} 35257429Smarkm 35357429Smarkm/* Sets remote side protocol flags. */ 35457429Smarkm 35557429Smarkmvoid 35676259Sgreenpacket_set_protocol_flags(u_int protocol_flags) 35757429Smarkm{ 35857429Smarkm remote_protocol_flags = protocol_flags; 35957429Smarkm} 36057429Smarkm 36157429Smarkm/* Returns the remote protocol flags set earlier by the above function. */ 36257429Smarkm 36376259Sgreenu_int 36492555Sdespacket_get_protocol_flags(void) 36557429Smarkm{ 36657429Smarkm return remote_protocol_flags; 36757429Smarkm} 36857429Smarkm 36957429Smarkm/* 37057429Smarkm * Starts packet compression from the next packet on in both directions. 37157429Smarkm * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. 37257429Smarkm */ 37357429Smarkm 37492555Sdesstatic void 37592555Sdespacket_init_compression(void) 37676259Sgreen{ 37776259Sgreen if (compression_buffer_ready == 1) 37876259Sgreen return; 37976259Sgreen compression_buffer_ready = 1; 38076259Sgreen buffer_init(&compression_buffer); 38176259Sgreen} 38276259Sgreen 38376259Sgreenvoid 38457429Smarkmpacket_start_compression(int level) 38557429Smarkm{ 38692555Sdes if (packet_compression && !compat20) 38757429Smarkm fatal("Compression already enabled."); 38857429Smarkm packet_compression = 1; 38976259Sgreen packet_init_compression(); 39076259Sgreen buffer_compress_init_send(level); 39176259Sgreen buffer_compress_init_recv(); 39257429Smarkm} 39357429Smarkm 39457429Smarkm/* 39557429Smarkm * Causes any further packets to be encrypted using the given key. The same 39657429Smarkm * key is used for both sending and reception. However, both directions are 39757429Smarkm * encrypted independently of each other. 39857429Smarkm */ 39998675Sdes 40057429Smarkmvoid 40176259Sgreenpacket_set_encryption_key(const u_char *key, u_int keylen, 40269587Sgreen int number) 40357429Smarkm{ 40469587Sgreen Cipher *cipher = cipher_by_number(number); 40569587Sgreen if (cipher == NULL) 40669587Sgreen fatal("packet_set_encryption_key: unknown cipher number %d", number); 40760573Skris if (keylen < 20) 40869587Sgreen fatal("packet_set_encryption_key: keylen too small: %d", keylen); 40998675Sdes if (keylen > SSH_SESSION_KEY_LENGTH) 41098675Sdes fatal("packet_set_encryption_key: keylen too big: %d", keylen); 41198675Sdes memcpy(ssh1_key, key, keylen); 41298675Sdes ssh1_keylen = keylen; 41392555Sdes cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT); 41492555Sdes cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT); 41557429Smarkm} 41657429Smarkm 41798675Sdesu_int 41898675Sdespacket_get_encryption_key(u_char *key) 41998675Sdes{ 42098675Sdes if (key == NULL) 42198675Sdes return (ssh1_keylen); 42298675Sdes memcpy(key, ssh1_key, ssh1_keylen); 42398675Sdes return (ssh1_keylen); 42498675Sdes} 42598675Sdes 42692555Sdes/* Start constructing a packet to send. */ 42757429Smarkmvoid 42892555Sdespacket_start(u_char type) 42957429Smarkm{ 43092555Sdes u_char buf[9]; 43192555Sdes int len; 43257429Smarkm 43392555Sdes DBG(debug("packet_start[%d]", type)); 43492555Sdes len = compat20 ? 6 : 9; 43592555Sdes memset(buf, 0, len - 1); 43692555Sdes buf[len - 1] = type; 43757429Smarkm buffer_clear(&outgoing_packet); 43892555Sdes buffer_append(&outgoing_packet, buf, len); 43957429Smarkm} 44057429Smarkm 44192555Sdes/* Append payload. */ 44260573Skrisvoid 44357429Smarkmpacket_put_char(int value) 44457429Smarkm{ 44557429Smarkm char ch = value; 44657429Smarkm buffer_append(&outgoing_packet, &ch, 1); 44757429Smarkm} 44857429Smarkmvoid 44976259Sgreenpacket_put_int(u_int value) 45057429Smarkm{ 45157429Smarkm buffer_put_int(&outgoing_packet, value); 45257429Smarkm} 45357429Smarkmvoid 45492555Sdespacket_put_string(const void *buf, u_int len) 45557429Smarkm{ 45657429Smarkm buffer_put_string(&outgoing_packet, buf, len); 45757429Smarkm} 45860573Skrisvoid 45960573Skrispacket_put_cstring(const char *str) 46060573Skris{ 46192555Sdes buffer_put_cstring(&outgoing_packet, str); 46260573Skris} 46360573Skrisvoid 46492555Sdespacket_put_raw(const void *buf, u_int len) 46560573Skris{ 46660573Skris buffer_append(&outgoing_packet, buf, len); 46760573Skris} 46857429Smarkmvoid 46957429Smarkmpacket_put_bignum(BIGNUM * value) 47057429Smarkm{ 47157429Smarkm buffer_put_bignum(&outgoing_packet, value); 47257429Smarkm} 47360573Skrisvoid 47460573Skrispacket_put_bignum2(BIGNUM * value) 47560573Skris{ 47660573Skris buffer_put_bignum2(&outgoing_packet, value); 47760573Skris} 47857429Smarkm 47957429Smarkm/* 48057429Smarkm * Finalizes and sends the packet. If the encryption key has been set, 48157429Smarkm * encrypts the packet before sending. 48257429Smarkm */ 48357429Smarkm 48492555Sdesstatic void 48576259Sgreenpacket_send1(void) 48657429Smarkm{ 48792555Sdes u_char buf[8], *cp; 48857429Smarkm int i, padding, len; 48976259Sgreen u_int checksum; 49057429Smarkm u_int32_t rand = 0; 49157429Smarkm 49257429Smarkm /* 49357429Smarkm * If using packet compression, compress the payload of the outgoing 49457429Smarkm * packet. 49557429Smarkm */ 49657429Smarkm if (packet_compression) { 49757429Smarkm buffer_clear(&compression_buffer); 49857429Smarkm /* Skip padding. */ 49957429Smarkm buffer_consume(&outgoing_packet, 8); 50057429Smarkm /* padding */ 50157429Smarkm buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8); 50257429Smarkm buffer_compress(&outgoing_packet, &compression_buffer); 50357429Smarkm buffer_clear(&outgoing_packet); 50457429Smarkm buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), 50592555Sdes buffer_len(&compression_buffer)); 50657429Smarkm } 50757429Smarkm /* Compute packet length without padding (add checksum, remove padding). */ 50857429Smarkm len = buffer_len(&outgoing_packet) + 4 - 8; 50957429Smarkm 51060573Skris /* Insert padding. Initialized to zero in packet_start1() */ 51157429Smarkm padding = 8 - len % 8; 51292555Sdes if (!send_context.plaintext) { 51357429Smarkm cp = buffer_ptr(&outgoing_packet); 51457429Smarkm for (i = 0; i < padding; i++) { 51557429Smarkm if (i % 4 == 0) 51657429Smarkm rand = arc4random(); 51757429Smarkm cp[7 - i] = rand & 0xff; 51857429Smarkm rand >>= 8; 51957429Smarkm } 52057429Smarkm } 52157429Smarkm buffer_consume(&outgoing_packet, 8 - padding); 52257429Smarkm 52357429Smarkm /* Add check bytes. */ 52492555Sdes checksum = ssh_crc32(buffer_ptr(&outgoing_packet), 52565668Skris buffer_len(&outgoing_packet)); 52657429Smarkm PUT_32BIT(buf, checksum); 52757429Smarkm buffer_append(&outgoing_packet, buf, 4); 52857429Smarkm 52957429Smarkm#ifdef PACKET_DEBUG 53057429Smarkm fprintf(stderr, "packet_send plain: "); 53157429Smarkm buffer_dump(&outgoing_packet); 53257429Smarkm#endif 53357429Smarkm 53457429Smarkm /* Append to output. */ 53557429Smarkm PUT_32BIT(buf, len); 53657429Smarkm buffer_append(&output, buf, 4); 53792555Sdes cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); 53892555Sdes cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet), 53992555Sdes buffer_len(&outgoing_packet)); 54057429Smarkm 54157429Smarkm#ifdef PACKET_DEBUG 54257429Smarkm fprintf(stderr, "encrypted: "); 54357429Smarkm buffer_dump(&output); 54457429Smarkm#endif 54557429Smarkm 54657429Smarkm buffer_clear(&outgoing_packet); 54757429Smarkm 54857429Smarkm /* 54957429Smarkm * Note that the packet is now only buffered in output. It won\'t be 55057429Smarkm * actually sent until packet_write_wait or packet_write_poll is 55157429Smarkm * called. 55257429Smarkm */ 55357429Smarkm} 55457429Smarkm 55598675Sdesvoid 55676259Sgreenset_newkeys(int mode) 55776259Sgreen{ 55876259Sgreen Enc *enc; 55976259Sgreen Mac *mac; 56076259Sgreen Comp *comp; 56176259Sgreen CipherContext *cc; 56292555Sdes int encrypt; 56376259Sgreen 56476259Sgreen debug("newkeys: mode %d", mode); 56576259Sgreen 56692555Sdes if (mode == MODE_OUT) { 56792555Sdes cc = &send_context; 56892555Sdes encrypt = CIPHER_ENCRYPT; 56992555Sdes } else { 57092555Sdes cc = &receive_context; 57192555Sdes encrypt = CIPHER_DECRYPT; 57292555Sdes } 57376259Sgreen if (newkeys[mode] != NULL) { 57476259Sgreen debug("newkeys: rekeying"); 57592555Sdes cipher_cleanup(cc); 57676259Sgreen enc = &newkeys[mode]->enc; 57776259Sgreen mac = &newkeys[mode]->mac; 57876259Sgreen comp = &newkeys[mode]->comp; 57976259Sgreen memset(mac->key, 0, mac->key_len); 58076259Sgreen xfree(enc->name); 58176259Sgreen xfree(enc->iv); 58276259Sgreen xfree(enc->key); 58376259Sgreen xfree(mac->name); 58476259Sgreen xfree(mac->key); 58576259Sgreen xfree(comp->name); 58676259Sgreen xfree(newkeys[mode]); 58776259Sgreen } 58876259Sgreen newkeys[mode] = kex_get_newkeys(mode); 58976259Sgreen if (newkeys[mode] == NULL) 59076259Sgreen fatal("newkeys: no keys for mode %d", mode); 59176259Sgreen enc = &newkeys[mode]->enc; 59276259Sgreen mac = &newkeys[mode]->mac; 59376259Sgreen comp = &newkeys[mode]->comp; 59476259Sgreen if (mac->md != NULL) 59576259Sgreen mac->enabled = 1; 59676259Sgreen DBG(debug("cipher_init_context: %d", mode)); 59792555Sdes cipher_init(cc, enc->cipher, enc->key, enc->key_len, 59892555Sdes enc->iv, enc->block_size, encrypt); 59998675Sdes /* Deleting the keys does not gain extra security */ 60098675Sdes /* memset(enc->iv, 0, enc->block_size); 60198675Sdes memset(enc->key, 0, enc->key_len); */ 60276259Sgreen if (comp->type != 0 && comp->enabled == 0) { 60376259Sgreen packet_init_compression(); 60476259Sgreen if (mode == MODE_OUT) 60576259Sgreen buffer_compress_init_send(6); 60676259Sgreen else 60776259Sgreen buffer_compress_init_recv(); 60876259Sgreen comp->enabled = 1; 60976259Sgreen } 61076259Sgreen} 61176259Sgreen 61257429Smarkm/* 61360573Skris * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) 61460573Skris */ 61592555Sdesstatic void 61676259Sgreenpacket_send2(void) 61760573Skris{ 61892555Sdes u_char type, *cp, *macbuf = NULL; 61992555Sdes u_char padlen, pad; 62076259Sgreen u_int packet_length = 0; 62192555Sdes u_int i, len; 62260573Skris u_int32_t rand = 0; 62360573Skris Enc *enc = NULL; 62460573Skris Mac *mac = NULL; 62560573Skris Comp *comp = NULL; 62660573Skris int block_size; 62760573Skris 62876259Sgreen if (newkeys[MODE_OUT] != NULL) { 62976259Sgreen enc = &newkeys[MODE_OUT]->enc; 63076259Sgreen mac = &newkeys[MODE_OUT]->mac; 63176259Sgreen comp = &newkeys[MODE_OUT]->comp; 63260573Skris } 63392555Sdes block_size = enc ? enc->block_size : 8; 63460573Skris 63560573Skris cp = buffer_ptr(&outgoing_packet); 63692555Sdes type = cp[5]; 63760573Skris 63860573Skris#ifdef PACKET_DEBUG 63960573Skris fprintf(stderr, "plain: "); 64060573Skris buffer_dump(&outgoing_packet); 64160573Skris#endif 64260573Skris 64360573Skris if (comp && comp->enabled) { 64460573Skris len = buffer_len(&outgoing_packet); 64560573Skris /* skip header, compress only payload */ 64660573Skris buffer_consume(&outgoing_packet, 5); 64760573Skris buffer_clear(&compression_buffer); 64860573Skris buffer_compress(&outgoing_packet, &compression_buffer); 64960573Skris buffer_clear(&outgoing_packet); 65060573Skris buffer_append(&outgoing_packet, "\0\0\0\0\0", 5); 65160573Skris buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), 65260573Skris buffer_len(&compression_buffer)); 65360573Skris DBG(debug("compression: raw %d compressed %d", len, 65460573Skris buffer_len(&outgoing_packet))); 65560573Skris } 65660573Skris 65760573Skris /* sizeof (packet_len + pad_len + payload) */ 65860573Skris len = buffer_len(&outgoing_packet); 65960573Skris 66060573Skris /* 66160573Skris * calc size of padding, alloc space, get random data, 66260573Skris * minimum padding is 4 bytes 66360573Skris */ 66460573Skris padlen = block_size - (len % block_size); 66560573Skris if (padlen < 4) 66660573Skris padlen += block_size; 66792555Sdes if (extra_pad) { 66892555Sdes /* will wrap if extra_pad+padlen > 255 */ 66992555Sdes extra_pad = roundup(extra_pad, block_size); 67092555Sdes pad = extra_pad - ((len + padlen) % extra_pad); 67198675Sdes debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)", 67292555Sdes pad, len, padlen, extra_pad); 67392555Sdes padlen += pad; 67492555Sdes extra_pad = 0; 67592555Sdes } 67692555Sdes cp = buffer_append_space(&outgoing_packet, padlen); 67792555Sdes if (enc && !send_context.plaintext) { 67860573Skris /* random padding */ 67960573Skris for (i = 0; i < padlen; i++) { 68060573Skris if (i % 4 == 0) 68160573Skris rand = arc4random(); 68260573Skris cp[i] = rand & 0xff; 68376259Sgreen rand >>= 8; 68460573Skris } 68560573Skris } else { 68660573Skris /* clear padding */ 68760573Skris memset(cp, 0, padlen); 68860573Skris } 68960573Skris /* packet_length includes payload, padding and padding length field */ 69060573Skris packet_length = buffer_len(&outgoing_packet) - 4; 69160573Skris cp = buffer_ptr(&outgoing_packet); 69260573Skris PUT_32BIT(cp, packet_length); 69392555Sdes cp[4] = padlen; 69460573Skris DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen)); 69560573Skris 69660573Skris /* compute MAC over seqnr and packet(length fields, payload, padding) */ 69760573Skris if (mac && mac->enabled) { 69898675Sdes macbuf = mac_compute(mac, send_seqnr, 69992555Sdes buffer_ptr(&outgoing_packet), 70076259Sgreen buffer_len(&outgoing_packet)); 70198675Sdes DBG(debug("done calc MAC out #%d", send_seqnr)); 70260573Skris } 70360573Skris /* encrypt packet and append to output buffer. */ 70492555Sdes cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); 70592555Sdes cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet), 70660573Skris buffer_len(&outgoing_packet)); 70760573Skris /* append unencrypted MAC */ 70860573Skris if (mac && mac->enabled) 70960573Skris buffer_append(&output, (char *)macbuf, mac->mac_len); 71060573Skris#ifdef PACKET_DEBUG 71160573Skris fprintf(stderr, "encrypted: "); 71260573Skris buffer_dump(&output); 71360573Skris#endif 71460573Skris /* increment sequence number for outgoing packets */ 71598675Sdes if (++send_seqnr == 0) 71660573Skris log("outgoing seqnr wraps around"); 71760573Skris buffer_clear(&outgoing_packet); 71860573Skris 71976259Sgreen if (type == SSH2_MSG_NEWKEYS) 72076259Sgreen set_newkeys(MODE_OUT); 72160573Skris} 72260573Skris 72360573Skrisvoid 72492555Sdespacket_send(void) 72560573Skris{ 72692555Sdes if (compat20) 72760573Skris packet_send2(); 72860573Skris else 72960573Skris packet_send1(); 73060573Skris DBG(debug("packet_send done")); 73160573Skris} 73260573Skris 73360573Skris/* 73457429Smarkm * Waits until a packet has been received, and returns its type. Note that 73557429Smarkm * no other data is processed until this returns, so this function should not 73657429Smarkm * be used during the interactive session. 73757429Smarkm */ 73857429Smarkm 73957429Smarkmint 74092555Sdespacket_read_seqnr(u_int32_t *seqnr_p) 74157429Smarkm{ 74257429Smarkm int type, len; 74376259Sgreen fd_set *setp; 74457429Smarkm char buf[8192]; 74560573Skris DBG(debug("packet_read()")); 74657429Smarkm 74776259Sgreen setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) * 74876259Sgreen sizeof(fd_mask)); 74976259Sgreen 75057429Smarkm /* Since we are blocking, ensure that all written packets have been sent. */ 75157429Smarkm packet_write_wait(); 75257429Smarkm 75357429Smarkm /* Stay in the loop until we have received a complete packet. */ 75457429Smarkm for (;;) { 75557429Smarkm /* Try to read a packet from the buffer. */ 75692555Sdes type = packet_read_poll_seqnr(seqnr_p); 75792555Sdes if (!compat20 && ( 75860573Skris type == SSH_SMSG_SUCCESS 75957429Smarkm || type == SSH_SMSG_FAILURE 76057429Smarkm || type == SSH_CMSG_EOF 76160573Skris || type == SSH_CMSG_EXIT_CONFIRMATION)) 76292555Sdes packet_check_eom(); 76357429Smarkm /* If we got a packet, return it. */ 76476259Sgreen if (type != SSH_MSG_NONE) { 76576259Sgreen xfree(setp); 76657429Smarkm return type; 76776259Sgreen } 76857429Smarkm /* 76957429Smarkm * Otherwise, wait for some data to arrive, add it to the 77057429Smarkm * buffer, and try again. 77157429Smarkm */ 77276259Sgreen memset(setp, 0, howmany(connection_in + 1, NFDBITS) * 77376259Sgreen sizeof(fd_mask)); 77476259Sgreen FD_SET(connection_in, setp); 77557429Smarkm 77657429Smarkm /* Wait for some data to arrive. */ 77776259Sgreen while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 && 77876259Sgreen (errno == EAGAIN || errno == EINTR)) 77976259Sgreen ; 78057429Smarkm 78157429Smarkm /* Read data from the socket. */ 78257429Smarkm len = read(connection_in, buf, sizeof(buf)); 78357429Smarkm if (len == 0) { 78457429Smarkm log("Connection closed by %.200s", get_remote_ipaddr()); 78557429Smarkm fatal_cleanup(); 78657429Smarkm } 78757429Smarkm if (len < 0) 78857429Smarkm fatal("Read from socket failed: %.100s", strerror(errno)); 78957429Smarkm /* Append it to the buffer. */ 79057429Smarkm packet_process_incoming(buf, len); 79157429Smarkm } 79257429Smarkm /* NOTREACHED */ 79357429Smarkm} 79457429Smarkm 79592555Sdesint 79692555Sdespacket_read(void) 79792555Sdes{ 79892555Sdes return packet_read_seqnr(NULL); 79992555Sdes} 80092555Sdes 80157429Smarkm/* 80257429Smarkm * Waits until a packet has been received, verifies that its type matches 80357429Smarkm * that given, and gives a fatal error and exits if there is a mismatch. 80457429Smarkm */ 80557429Smarkm 80657429Smarkmvoid 80792555Sdespacket_read_expect(int expected_type) 80857429Smarkm{ 80957429Smarkm int type; 81057429Smarkm 81192555Sdes type = packet_read(); 81257429Smarkm if (type != expected_type) 81357429Smarkm packet_disconnect("Protocol error: expected packet type %d, got %d", 81460573Skris expected_type, type); 81557429Smarkm} 81657429Smarkm 81757429Smarkm/* Checks if a full packet is available in the data received so far via 81857429Smarkm * packet_process_incoming. If so, reads the packet; otherwise returns 81957429Smarkm * SSH_MSG_NONE. This does not wait for data from the connection. 82057429Smarkm * 82157429Smarkm * SSH_MSG_DISCONNECT is handled specially here. Also, 82257429Smarkm * SSH_MSG_IGNORE messages are skipped by this function and are never returned 82357429Smarkm * to higher levels. 82457429Smarkm */ 82557429Smarkm 82692555Sdesstatic int 82792555Sdespacket_read_poll1(void) 82857429Smarkm{ 82976259Sgreen u_int len, padded_len; 83092555Sdes u_char *cp, type; 83176259Sgreen u_int checksum, stored_checksum; 83257429Smarkm 83357429Smarkm /* Check if input size is less than minimum packet size. */ 83457429Smarkm if (buffer_len(&input) < 4 + 8) 83557429Smarkm return SSH_MSG_NONE; 83657429Smarkm /* Get length of incoming packet. */ 83792555Sdes cp = buffer_ptr(&input); 83892555Sdes len = GET_32BIT(cp); 83957429Smarkm if (len < 1 + 2 + 2 || len > 256 * 1024) 84057429Smarkm packet_disconnect("Bad packet length %d.", len); 84157429Smarkm padded_len = (len + 8) & ~7; 84257429Smarkm 84357429Smarkm /* Check if the packet has been entirely received. */ 84457429Smarkm if (buffer_len(&input) < 4 + padded_len) 84557429Smarkm return SSH_MSG_NONE; 84657429Smarkm 84757429Smarkm /* The entire packet is in buffer. */ 84857429Smarkm 84957429Smarkm /* Consume packet length. */ 85057429Smarkm buffer_consume(&input, 4); 85157429Smarkm 85292555Sdes /* 85392555Sdes * Cryptographic attack detector for ssh 85492555Sdes * (C)1998 CORE-SDI, Buenos Aires Argentina 85592555Sdes * Ariel Futoransky(futo@core-sdi.com) 85692555Sdes */ 85792555Sdes if (!receive_context.plaintext && 85892555Sdes detect_attack(buffer_ptr(&input), padded_len, NULL) == DEATTACK_DETECTED) 85992555Sdes packet_disconnect("crc32 compensation attack: network attack detected"); 86092555Sdes 86192555Sdes /* Decrypt data to incoming_packet. */ 86257429Smarkm buffer_clear(&incoming_packet); 86392555Sdes cp = buffer_append_space(&incoming_packet, padded_len); 86492555Sdes cipher_crypt(&receive_context, cp, buffer_ptr(&input), padded_len); 86592555Sdes 86657429Smarkm buffer_consume(&input, padded_len); 86757429Smarkm 86857429Smarkm#ifdef PACKET_DEBUG 86957429Smarkm fprintf(stderr, "read_poll plain: "); 87057429Smarkm buffer_dump(&incoming_packet); 87157429Smarkm#endif 87257429Smarkm 87357429Smarkm /* Compute packet checksum. */ 87492555Sdes checksum = ssh_crc32(buffer_ptr(&incoming_packet), 87560573Skris buffer_len(&incoming_packet) - 4); 87657429Smarkm 87757429Smarkm /* Skip padding. */ 87857429Smarkm buffer_consume(&incoming_packet, 8 - len % 8); 87957429Smarkm 88057429Smarkm /* Test check bytes. */ 88157429Smarkm if (len != buffer_len(&incoming_packet)) 88292555Sdes packet_disconnect("packet_read_poll1: len %d != buffer_len %d.", 88360573Skris len, buffer_len(&incoming_packet)); 88457429Smarkm 88592555Sdes cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4; 88692555Sdes stored_checksum = GET_32BIT(cp); 88757429Smarkm if (checksum != stored_checksum) 88857429Smarkm packet_disconnect("Corrupted check bytes on input."); 88957429Smarkm buffer_consume_end(&incoming_packet, 4); 89057429Smarkm 89157429Smarkm if (packet_compression) { 89257429Smarkm buffer_clear(&compression_buffer); 89357429Smarkm buffer_uncompress(&incoming_packet, &compression_buffer); 89457429Smarkm buffer_clear(&incoming_packet); 89557429Smarkm buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), 89660573Skris buffer_len(&compression_buffer)); 89757429Smarkm } 89892555Sdes type = buffer_get_char(&incoming_packet); 89992555Sdes return type; 90060573Skris} 90157429Smarkm 90292555Sdesstatic int 90392555Sdespacket_read_poll2(u_int32_t *seqnr_p) 90460573Skris{ 90576259Sgreen static u_int packet_length = 0; 90676259Sgreen u_int padlen, need; 90792555Sdes u_char *macbuf, *cp, type; 90860573Skris int maclen, block_size; 90960573Skris Enc *enc = NULL; 91060573Skris Mac *mac = NULL; 91160573Skris Comp *comp = NULL; 91257429Smarkm 91376259Sgreen if (newkeys[MODE_IN] != NULL) { 91476259Sgreen enc = &newkeys[MODE_IN]->enc; 91576259Sgreen mac = &newkeys[MODE_IN]->mac; 91676259Sgreen comp = &newkeys[MODE_IN]->comp; 91757429Smarkm } 91860573Skris maclen = mac && mac->enabled ? mac->mac_len : 0; 91992555Sdes block_size = enc ? enc->block_size : 8; 92060573Skris 92160573Skris if (packet_length == 0) { 92260573Skris /* 92360573Skris * check if input size is less than the cipher block size, 92460573Skris * decrypt first block and extract length of incoming packet 92560573Skris */ 92660573Skris if (buffer_len(&input) < block_size) 92760573Skris return SSH_MSG_NONE; 92860573Skris buffer_clear(&incoming_packet); 92992555Sdes cp = buffer_append_space(&incoming_packet, block_size); 93092555Sdes cipher_crypt(&receive_context, cp, buffer_ptr(&input), 93160573Skris block_size); 93292555Sdes cp = buffer_ptr(&incoming_packet); 93392555Sdes packet_length = GET_32BIT(cp); 93460573Skris if (packet_length < 1 + 4 || packet_length > 256 * 1024) { 93560573Skris buffer_dump(&incoming_packet); 93660573Skris packet_disconnect("Bad packet length %d.", packet_length); 93760573Skris } 93860573Skris DBG(debug("input: packet len %d", packet_length+4)); 93960573Skris buffer_consume(&input, block_size); 94060573Skris } 94160573Skris /* we have a partial packet of block_size bytes */ 94260573Skris need = 4 + packet_length - block_size; 94360573Skris DBG(debug("partial packet %d, need %d, maclen %d", block_size, 94460573Skris need, maclen)); 94560573Skris if (need % block_size != 0) 94660573Skris fatal("padding error: need %d block %d mod %d", 94760573Skris need, block_size, need % block_size); 94860573Skris /* 94960573Skris * check if the entire packet has been received and 95060573Skris * decrypt into incoming_packet 95160573Skris */ 95260573Skris if (buffer_len(&input) < need + maclen) 95360573Skris return SSH_MSG_NONE; 95460573Skris#ifdef PACKET_DEBUG 95560573Skris fprintf(stderr, "read_poll enc/full: "); 95660573Skris buffer_dump(&input); 95760573Skris#endif 95892555Sdes cp = buffer_append_space(&incoming_packet, need); 95992555Sdes cipher_crypt(&receive_context, cp, buffer_ptr(&input), need); 96060573Skris buffer_consume(&input, need); 96160573Skris /* 96260573Skris * compute MAC over seqnr and packet, 96360573Skris * increment sequence number for incoming packet 96460573Skris */ 96560573Skris if (mac && mac->enabled) { 96698675Sdes macbuf = mac_compute(mac, read_seqnr, 96792555Sdes buffer_ptr(&incoming_packet), 96876259Sgreen buffer_len(&incoming_packet)); 96960573Skris if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) 97069587Sgreen packet_disconnect("Corrupted MAC on input."); 97198675Sdes DBG(debug("MAC #%d ok", read_seqnr)); 97260573Skris buffer_consume(&input, mac->mac_len); 97360573Skris } 97492555Sdes if (seqnr_p != NULL) 97598675Sdes *seqnr_p = read_seqnr; 97698675Sdes if (++read_seqnr == 0) 97760573Skris log("incoming seqnr wraps around"); 97860573Skris 97960573Skris /* get padlen */ 98092555Sdes cp = buffer_ptr(&incoming_packet); 98192555Sdes padlen = cp[4]; 98260573Skris DBG(debug("input: padlen %d", padlen)); 98360573Skris if (padlen < 4) 98460573Skris packet_disconnect("Corrupted padlen %d on input.", padlen); 98560573Skris 98660573Skris /* skip packet size + padlen, discard padding */ 98760573Skris buffer_consume(&incoming_packet, 4 + 1); 98860573Skris buffer_consume_end(&incoming_packet, padlen); 98960573Skris 99060573Skris DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet))); 99160573Skris if (comp && comp->enabled) { 99260573Skris buffer_clear(&compression_buffer); 99360573Skris buffer_uncompress(&incoming_packet, &compression_buffer); 99460573Skris buffer_clear(&incoming_packet); 99560573Skris buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), 99660573Skris buffer_len(&compression_buffer)); 99760573Skris DBG(debug("input: len after de-compress %d", buffer_len(&incoming_packet))); 99860573Skris } 99960573Skris /* 100060573Skris * get packet type, implies consume. 100160573Skris * return length of payload (without type field) 100260573Skris */ 100392555Sdes type = buffer_get_char(&incoming_packet); 100476259Sgreen if (type == SSH2_MSG_NEWKEYS) 100576259Sgreen set_newkeys(MODE_IN); 100660573Skris#ifdef PACKET_DEBUG 100776259Sgreen fprintf(stderr, "read/plain[%d]:\r\n", type); 100860573Skris buffer_dump(&incoming_packet); 100960573Skris#endif 101092555Sdes /* reset for next packet */ 101192555Sdes packet_length = 0; 101292555Sdes return type; 101357429Smarkm} 101457429Smarkm 101560573Skrisint 101692555Sdespacket_read_poll_seqnr(u_int32_t *seqnr_p) 101760573Skris{ 101892555Sdes int reason, seqnr; 101992555Sdes u_char type; 102060573Skris char *msg; 102192555Sdes 102260573Skris for (;;) { 102392555Sdes if (compat20) { 102492555Sdes type = packet_read_poll2(seqnr_p); 102592555Sdes if (type) 102660573Skris DBG(debug("received packet type %d", type)); 102792555Sdes switch (type) { 102860573Skris case SSH2_MSG_IGNORE: 102960573Skris break; 103060573Skris case SSH2_MSG_DEBUG: 103160573Skris packet_get_char(); 103260573Skris msg = packet_get_string(NULL); 103360573Skris debug("Remote: %.900s", msg); 103460573Skris xfree(msg); 103560573Skris msg = packet_get_string(NULL); 103660573Skris xfree(msg); 103760573Skris break; 103860573Skris case SSH2_MSG_DISCONNECT: 103960573Skris reason = packet_get_int(); 104060573Skris msg = packet_get_string(NULL); 104176259Sgreen log("Received disconnect from %s: %d: %.400s", get_remote_ipaddr(), 104276259Sgreen reason, msg); 104360573Skris xfree(msg); 104460573Skris fatal_cleanup(); 104560573Skris break; 104692555Sdes case SSH2_MSG_UNIMPLEMENTED: 104792555Sdes seqnr = packet_get_int(); 104892555Sdes debug("Received SSH2_MSG_UNIMPLEMENTED for %d", seqnr); 104992555Sdes break; 105060573Skris default: 105160573Skris return type; 105260573Skris break; 105376259Sgreen } 105460573Skris } else { 105592555Sdes type = packet_read_poll1(); 105692555Sdes switch (type) { 105760573Skris case SSH_MSG_IGNORE: 105860573Skris break; 105960573Skris case SSH_MSG_DEBUG: 106060573Skris msg = packet_get_string(NULL); 106160573Skris debug("Remote: %.900s", msg); 106260573Skris xfree(msg); 106360573Skris break; 106460573Skris case SSH_MSG_DISCONNECT: 106560573Skris msg = packet_get_string(NULL); 106676259Sgreen log("Received disconnect from %s: %.400s", get_remote_ipaddr(), 106776259Sgreen msg); 106860573Skris fatal_cleanup(); 106960573Skris xfree(msg); 107060573Skris break; 107160573Skris default: 107292555Sdes if (type) 107360573Skris DBG(debug("received packet type %d", type)); 107460573Skris return type; 107560573Skris break; 107676259Sgreen } 107760573Skris } 107860573Skris } 107960573Skris} 108060573Skris 108192555Sdesint 108292555Sdespacket_read_poll(void) 108392555Sdes{ 108492555Sdes return packet_read_poll_seqnr(NULL); 108592555Sdes} 108692555Sdes 108757429Smarkm/* 108857429Smarkm * Buffers the given amount of input characters. This is intended to be used 108957429Smarkm * together with packet_read_poll. 109057429Smarkm */ 109157429Smarkm 109257429Smarkmvoid 109376259Sgreenpacket_process_incoming(const char *buf, u_int len) 109457429Smarkm{ 109557429Smarkm buffer_append(&input, buf, len); 109657429Smarkm} 109757429Smarkm 109857429Smarkm/* Returns a character from the packet. */ 109957429Smarkm 110076259Sgreenu_int 110192555Sdespacket_get_char(void) 110257429Smarkm{ 110357429Smarkm char ch; 110457429Smarkm buffer_get(&incoming_packet, &ch, 1); 110576259Sgreen return (u_char) ch; 110657429Smarkm} 110757429Smarkm 110857429Smarkm/* Returns an integer from the packet data. */ 110957429Smarkm 111076259Sgreenu_int 111192555Sdespacket_get_int(void) 111257429Smarkm{ 111357429Smarkm return buffer_get_int(&incoming_packet); 111457429Smarkm} 111557429Smarkm 111657429Smarkm/* 111757429Smarkm * Returns an arbitrary precision integer from the packet data. The integer 111857429Smarkm * must have been initialized before this call. 111957429Smarkm */ 112057429Smarkm 112157429Smarkmvoid 112292555Sdespacket_get_bignum(BIGNUM * value) 112357429Smarkm{ 112492555Sdes buffer_get_bignum(&incoming_packet, value); 112557429Smarkm} 112657429Smarkm 112760573Skrisvoid 112892555Sdespacket_get_bignum2(BIGNUM * value) 112960573Skris{ 113092555Sdes buffer_get_bignum2(&incoming_packet, value); 113160573Skris} 113260573Skris 113392555Sdesvoid * 113460573Skrispacket_get_raw(int *length_ptr) 113560573Skris{ 113660573Skris int bytes = buffer_len(&incoming_packet); 113760573Skris if (length_ptr != NULL) 113860573Skris *length_ptr = bytes; 113960573Skris return buffer_ptr(&incoming_packet); 114060573Skris} 114160573Skris 114260573Skrisint 114360573Skrispacket_remaining(void) 114460573Skris{ 114560573Skris return buffer_len(&incoming_packet); 114660573Skris} 114760573Skris 114857429Smarkm/* 114957429Smarkm * Returns a string from the packet data. The string is allocated using 115057429Smarkm * xmalloc; it is the responsibility of the calling program to free it when 115157429Smarkm * no longer needed. The length_ptr argument may be NULL, or point to an 115257429Smarkm * integer into which the length of the string is stored. 115357429Smarkm */ 115457429Smarkm 115592555Sdesvoid * 115676259Sgreenpacket_get_string(u_int *length_ptr) 115757429Smarkm{ 115857429Smarkm return buffer_get_string(&incoming_packet, length_ptr); 115957429Smarkm} 116057429Smarkm 116157429Smarkm/* 116257429Smarkm * Sends a diagnostic message from the server to the client. This message 116357429Smarkm * can be sent at any time (but not while constructing another message). The 116457429Smarkm * message is printed immediately, but only if the client is being executed 116557429Smarkm * in verbose mode. These messages are primarily intended to ease debugging 116657429Smarkm * authentication problems. The length of the formatted message must not 116757429Smarkm * exceed 1024 bytes. This will automatically call packet_write_wait. 116857429Smarkm */ 116957429Smarkm 117057429Smarkmvoid 117157429Smarkmpacket_send_debug(const char *fmt,...) 117257429Smarkm{ 117357429Smarkm char buf[1024]; 117457429Smarkm va_list args; 117557429Smarkm 117676259Sgreen if (compat20 && (datafellows & SSH_BUG_DEBUG)) 117776259Sgreen return; 117876259Sgreen 117957429Smarkm va_start(args, fmt); 118057429Smarkm vsnprintf(buf, sizeof(buf), fmt, args); 118157429Smarkm va_end(args); 118257429Smarkm 118360573Skris if (compat20) { 118460573Skris packet_start(SSH2_MSG_DEBUG); 118560573Skris packet_put_char(0); /* bool: always display */ 118660573Skris packet_put_cstring(buf); 118760573Skris packet_put_cstring(""); 118860573Skris } else { 118960573Skris packet_start(SSH_MSG_DEBUG); 119060573Skris packet_put_cstring(buf); 119160573Skris } 119257429Smarkm packet_send(); 119357429Smarkm packet_write_wait(); 119457429Smarkm} 119557429Smarkm 119657429Smarkm/* 119757429Smarkm * Logs the error plus constructs and sends a disconnect packet, closes the 119857429Smarkm * connection, and exits. This function never returns. The error message 119957429Smarkm * should not contain a newline. The length of the formatted message must 120057429Smarkm * not exceed 1024 bytes. 120157429Smarkm */ 120257429Smarkm 120357429Smarkmvoid 120457429Smarkmpacket_disconnect(const char *fmt,...) 120557429Smarkm{ 120657429Smarkm char buf[1024]; 120757429Smarkm va_list args; 120857429Smarkm static int disconnecting = 0; 120957429Smarkm if (disconnecting) /* Guard against recursive invocations. */ 121057429Smarkm fatal("packet_disconnect called recursively."); 121157429Smarkm disconnecting = 1; 121257429Smarkm 121357429Smarkm /* 121457429Smarkm * Format the message. Note that the caller must make sure the 121557429Smarkm * message is of limited size. 121657429Smarkm */ 121757429Smarkm va_start(args, fmt); 121857429Smarkm vsnprintf(buf, sizeof(buf), fmt, args); 121957429Smarkm va_end(args); 122057429Smarkm 122157429Smarkm /* Send the disconnect message to the other side, and wait for it to get sent. */ 122260573Skris if (compat20) { 122360573Skris packet_start(SSH2_MSG_DISCONNECT); 122460573Skris packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR); 122560573Skris packet_put_cstring(buf); 122660573Skris packet_put_cstring(""); 122760573Skris } else { 122860573Skris packet_start(SSH_MSG_DISCONNECT); 122992555Sdes packet_put_cstring(buf); 123060573Skris } 123157429Smarkm packet_send(); 123257429Smarkm packet_write_wait(); 123357429Smarkm 123457429Smarkm /* Stop listening for connections. */ 123592555Sdes channel_close_all(); 123657429Smarkm 123757429Smarkm /* Close the connection. */ 123857429Smarkm packet_close(); 123957429Smarkm 124057429Smarkm /* Display the error locally and exit. */ 124157429Smarkm log("Disconnecting: %.100s", buf); 124257429Smarkm fatal_cleanup(); 124357429Smarkm} 124457429Smarkm 124557429Smarkm/* Checks if there is any buffered output, and tries to write some of the output. */ 124657429Smarkm 124757429Smarkmvoid 124892555Sdespacket_write_poll(void) 124957429Smarkm{ 125057429Smarkm int len = buffer_len(&output); 125157429Smarkm if (len > 0) { 125257429Smarkm len = write(connection_out, buffer_ptr(&output), len); 125357429Smarkm if (len <= 0) { 125457429Smarkm if (errno == EAGAIN) 125557429Smarkm return; 125657429Smarkm else 125757429Smarkm fatal("Write failed: %.100s", strerror(errno)); 125857429Smarkm } 125957429Smarkm buffer_consume(&output, len); 126057429Smarkm } 126157429Smarkm} 126257429Smarkm 126357429Smarkm/* 126457429Smarkm * Calls packet_write_poll repeatedly until all pending output data has been 126557429Smarkm * written. 126657429Smarkm */ 126757429Smarkm 126857429Smarkmvoid 126992555Sdespacket_write_wait(void) 127057429Smarkm{ 127176259Sgreen fd_set *setp; 127276259Sgreen 127376259Sgreen setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) * 127476259Sgreen sizeof(fd_mask)); 127557429Smarkm packet_write_poll(); 127657429Smarkm while (packet_have_data_to_write()) { 127776259Sgreen memset(setp, 0, howmany(connection_out + 1, NFDBITS) * 127876259Sgreen sizeof(fd_mask)); 127976259Sgreen FD_SET(connection_out, setp); 128076259Sgreen while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 && 128176259Sgreen (errno == EAGAIN || errno == EINTR)) 128276259Sgreen ; 128357429Smarkm packet_write_poll(); 128457429Smarkm } 128576259Sgreen xfree(setp); 128657429Smarkm} 128757429Smarkm 128857429Smarkm/* Returns true if there is buffered data to write to the connection. */ 128957429Smarkm 129057429Smarkmint 129192555Sdespacket_have_data_to_write(void) 129257429Smarkm{ 129357429Smarkm return buffer_len(&output) != 0; 129457429Smarkm} 129557429Smarkm 129657429Smarkm/* Returns true if there is not too much data to write to the connection. */ 129757429Smarkm 129857429Smarkmint 129992555Sdespacket_not_very_much_data_to_write(void) 130057429Smarkm{ 130157429Smarkm if (interactive_mode) 130257429Smarkm return buffer_len(&output) < 16384; 130357429Smarkm else 130457429Smarkm return buffer_len(&output) < 128 * 1024; 130557429Smarkm} 130657429Smarkm 130757429Smarkm/* Informs that the current session is interactive. Sets IP flags for that. */ 130857429Smarkm 130957429Smarkmvoid 131076259Sgreenpacket_set_interactive(int interactive) 131157429Smarkm{ 131276259Sgreen static int called = 0; 131398937Sdes#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) 131476259Sgreen int lowdelay = IPTOS_LOWDELAY; 131576259Sgreen int throughput = IPTOS_THROUGHPUT; 131698937Sdes#endif 131757429Smarkm 131876259Sgreen if (called) 131976259Sgreen return; 132076259Sgreen called = 1; 132176259Sgreen 132257429Smarkm /* Record that we are in interactive mode. */ 132357429Smarkm interactive_mode = interactive; 132457429Smarkm 132557429Smarkm /* Only set socket options if using a socket. */ 132657429Smarkm if (!packet_connection_is_on_socket()) 132757429Smarkm return; 132857429Smarkm /* 132976259Sgreen * IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only 133057429Smarkm */ 133157429Smarkm if (interactive) { 133257429Smarkm /* 133357429Smarkm * Set IP options for an interactive connection. Use 133457429Smarkm * IPTOS_LOWDELAY and TCP_NODELAY. 133557429Smarkm */ 133698937Sdes#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) 133776259Sgreen if (packet_connection_is_ipv4()) { 133876259Sgreen if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, 133992555Sdes &lowdelay, sizeof(lowdelay)) < 0) 134076259Sgreen error("setsockopt IPTOS_LOWDELAY: %.100s", 134176259Sgreen strerror(errno)); 134276259Sgreen } 134398937Sdes#endif 134492555Sdes set_nodelay(connection_in); 134576259Sgreen } else if (packet_connection_is_ipv4()) { 134657429Smarkm /* 134757429Smarkm * Set IP options for a non-interactive connection. Use 134857429Smarkm * IPTOS_THROUGHPUT. 134957429Smarkm */ 135098937Sdes#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) 135192555Sdes if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &throughput, 135257429Smarkm sizeof(throughput)) < 0) 135357429Smarkm error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno)); 135498937Sdes#endif 135557429Smarkm } 135657429Smarkm} 135757429Smarkm 135857429Smarkm/* Returns true if the current connection is interactive. */ 135957429Smarkm 136057429Smarkmint 136192555Sdespacket_is_interactive(void) 136257429Smarkm{ 136357429Smarkm return interactive_mode; 136457429Smarkm} 136557429Smarkm 136657429Smarkmint 136757429Smarkmpacket_set_maxsize(int s) 136857429Smarkm{ 136957429Smarkm static int called = 0; 137057429Smarkm if (called) { 137160573Skris log("packet_set_maxsize: called twice: old %d new %d", 137260573Skris max_packet_size, s); 137357429Smarkm return -1; 137457429Smarkm } 137557429Smarkm if (s < 4 * 1024 || s > 1024 * 1024) { 137657429Smarkm log("packet_set_maxsize: bad size %d", s); 137757429Smarkm return -1; 137857429Smarkm } 137992555Sdes called = 1; 138092555Sdes debug("packet_set_maxsize: setting to %d", s); 138157429Smarkm max_packet_size = s; 138257429Smarkm return s; 138357429Smarkm} 138476259Sgreen 138592555Sdes/* roundup current message to pad bytes */ 138692555Sdesvoid 138792555Sdespacket_add_padding(u_char pad) 138892555Sdes{ 138992555Sdes extra_pad = pad; 139092555Sdes} 139192555Sdes 139276259Sgreen/* 139376259Sgreen * 9.2. Ignored Data Message 139476259Sgreen * 139576259Sgreen * byte SSH_MSG_IGNORE 139676259Sgreen * string data 139776259Sgreen * 139876259Sgreen * All implementations MUST understand (and ignore) this message at any 139976259Sgreen * time (after receiving the protocol version). No implementation is 140076259Sgreen * required to send them. This message can be used as an additional 140176259Sgreen * protection measure against advanced traffic analysis techniques. 140276259Sgreen */ 140376259Sgreenvoid 140476259Sgreenpacket_send_ignore(int nbytes) 140576259Sgreen{ 140676259Sgreen u_int32_t rand = 0; 140776259Sgreen int i; 140876259Sgreen 140976259Sgreen packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE); 141076259Sgreen packet_put_int(nbytes); 141192555Sdes for (i = 0; i < nbytes; i++) { 141276259Sgreen if (i % 4 == 0) 141376259Sgreen rand = arc4random(); 141476259Sgreen packet_put_char(rand & 0xff); 141576259Sgreen rand >>= 8; 141676259Sgreen } 141776259Sgreen} 1418