packet.c revision 60573
157429Smarkm/* 260573Skris * 357429Smarkm * packet.c 460573Skris * 557429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 660573Skris * 757429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 857429Smarkm * All rights reserved 960573Skris * 1057429Smarkm * Created: Sat Mar 18 02:40:40 1995 ylo 1160573Skris * 1257429Smarkm * This file contains code implementing the packet protocol and communication 1357429Smarkm * with the other side. This same code is used both on client and server side. 1460573Skris * 1560573Skris * SSH2 packet format added by Markus Friedl. 1660573Skris * 1757429Smarkm */ 1857429Smarkm 1957429Smarkm#include "includes.h" 2060573SkrisRCSID("$Id: packet.c,v 1.32 2000/05/04 22:22:43 markus Exp $"); 2157429Smarkm 2257429Smarkm#include "xmalloc.h" 2357429Smarkm#include "buffer.h" 2457429Smarkm#include "packet.h" 2557429Smarkm#include "bufaux.h" 2657429Smarkm#include "ssh.h" 2757429Smarkm#include "crc32.h" 2857429Smarkm#include "cipher.h" 2957429Smarkm#include "getput.h" 3057429Smarkm 3157429Smarkm#include "compress.h" 3257429Smarkm#include "deattack.h" 3360573Skris#include "channels.h" 3457429Smarkm 3560573Skris#include "compat.h" 3660573Skris#include "ssh2.h" 3760573Skris 3860573Skris#include <openssl/bn.h> 3960573Skris#include <openssl/dh.h> 4060573Skris#include <openssl/hmac.h> 4160573Skris#include "buffer.h" 4260573Skris#include "kex.h" 4360573Skris#include "hmac.h" 4460573Skris 4560573Skris#ifdef PACKET_DEBUG 4660573Skris#define DBG(x) x 4760573Skris#else 4860573Skris#define DBG(x) 4960573Skris#endif 5060573Skris 5157429Smarkm/* 5257429Smarkm * This variable contains the file descriptors used for communicating with 5357429Smarkm * the other side. connection_in is used for reading; connection_out for 5457429Smarkm * writing. These can be the same descriptor, in which case it is assumed to 5557429Smarkm * be a socket. 5657429Smarkm */ 5757429Smarkmstatic int connection_in = -1; 5857429Smarkmstatic int connection_out = -1; 5957429Smarkm 6057429Smarkm/* 6157429Smarkm * Cipher type. This value is only used to determine whether to pad the 6257429Smarkm * packets with zeroes or random data. 6357429Smarkm */ 6457429Smarkmstatic int cipher_type = SSH_CIPHER_NONE; 6557429Smarkm 6657429Smarkm/* Protocol flags for the remote side. */ 6757429Smarkmstatic unsigned int remote_protocol_flags = 0; 6857429Smarkm 6957429Smarkm/* Encryption context for receiving data. This is only used for decryption. */ 7057429Smarkmstatic CipherContext receive_context; 7157429Smarkm 7257429Smarkm/* Encryption context for sending data. This is only used for encryption. */ 7357429Smarkmstatic CipherContext send_context; 7457429Smarkm 7557429Smarkm/* Buffer for raw input data from the socket. */ 7657429Smarkmstatic Buffer input; 7757429Smarkm 7857429Smarkm/* Buffer for raw output data going to the socket. */ 7957429Smarkmstatic Buffer output; 8057429Smarkm 8157429Smarkm/* Buffer for the partial outgoing packet being constructed. */ 8257429Smarkmstatic Buffer outgoing_packet; 8357429Smarkm 8457429Smarkm/* Buffer for the incoming packet currently being processed. */ 8557429Smarkmstatic Buffer incoming_packet; 8657429Smarkm 8757429Smarkm/* Scratch buffer for packet compression/decompression. */ 8857429Smarkmstatic Buffer compression_buffer; 8957429Smarkm 9057429Smarkm/* Flag indicating whether packet compression/decompression is enabled. */ 9157429Smarkmstatic int packet_compression = 0; 9257429Smarkm 9357429Smarkm/* default maximum packet size */ 9457429Smarkmint max_packet_size = 32768; 9557429Smarkm 9657429Smarkm/* Flag indicating whether this module has been initialized. */ 9757429Smarkmstatic int initialized = 0; 9857429Smarkm 9957429Smarkm/* Set to true if the connection is interactive. */ 10057429Smarkmstatic int interactive_mode = 0; 10157429Smarkm 10260573Skris/* True if SSH2 packet format is used */ 10360573Skrisint use_ssh2_packet_format = 0; 10460573Skris 10560573Skris/* Session key information for Encryption and MAC */ 10660573SkrisKex *kex = NULL; 10760573Skris 10860573Skrisvoid 10960573Skrispacket_set_kex(Kex *k) 11060573Skris{ 11160573Skris if( k->mac[MODE_IN ].key == NULL || 11260573Skris k->enc[MODE_IN ].key == NULL || 11360573Skris k->enc[MODE_IN ].iv == NULL || 11460573Skris k->mac[MODE_OUT].key == NULL || 11560573Skris k->enc[MODE_OUT].key == NULL || 11660573Skris k->enc[MODE_OUT].iv == NULL) 11760573Skris fatal("bad KEX"); 11860573Skris kex = k; 11960573Skris} 12060573Skrisvoid 12160573Skrisclear_enc_keys(Enc *enc, int len) 12260573Skris{ 12360573Skris memset(enc->iv, 0, len); 12460573Skris memset(enc->key, 0, len); 12560573Skris xfree(enc->iv); 12660573Skris xfree(enc->key); 12760573Skris enc->iv = NULL; 12860573Skris enc->key = NULL; 12960573Skris} 13060573Skrisvoid 13160573Skrispacket_set_ssh2_format(void) 13260573Skris{ 13360573Skris DBG(debug("use_ssh2_packet_format")); 13460573Skris use_ssh2_packet_format = 1; 13560573Skris} 13660573Skris 13757429Smarkm/* 13857429Smarkm * Sets the descriptors used for communication. Disables encryption until 13957429Smarkm * packet_set_encryption_key is called. 14057429Smarkm */ 14157429Smarkmvoid 14257429Smarkmpacket_set_connection(int fd_in, int fd_out) 14357429Smarkm{ 14457429Smarkm connection_in = fd_in; 14557429Smarkm connection_out = fd_out; 14657429Smarkm cipher_type = SSH_CIPHER_NONE; 14760573Skris cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *) "", 0); 14860573Skris cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *) "", 0); 14957429Smarkm if (!initialized) { 15057429Smarkm initialized = 1; 15157429Smarkm buffer_init(&input); 15257429Smarkm buffer_init(&output); 15357429Smarkm buffer_init(&outgoing_packet); 15457429Smarkm buffer_init(&incoming_packet); 15557429Smarkm } 15657429Smarkm /* Kludge: arrange the close function to be called from fatal(). */ 15757429Smarkm fatal_add_cleanup((void (*) (void *)) packet_close, NULL); 15857429Smarkm} 15957429Smarkm 16057429Smarkm/* Returns 1 if remote host is connected via socket, 0 if not. */ 16157429Smarkm 16257429Smarkmint 16357429Smarkmpacket_connection_is_on_socket() 16457429Smarkm{ 16557429Smarkm struct sockaddr_storage from, to; 16657429Smarkm socklen_t fromlen, tolen; 16757429Smarkm 16857429Smarkm /* filedescriptors in and out are the same, so it's a socket */ 16957429Smarkm if (connection_in == connection_out) 17057429Smarkm return 1; 17157429Smarkm fromlen = sizeof(from); 17257429Smarkm memset(&from, 0, sizeof(from)); 17357429Smarkm if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0) 17457429Smarkm return 0; 17557429Smarkm tolen = sizeof(to); 17657429Smarkm memset(&to, 0, sizeof(to)); 17757429Smarkm if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0) 17857429Smarkm return 0; 17957429Smarkm if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0) 18057429Smarkm return 0; 18157429Smarkm if (from.ss_family != AF_INET && from.ss_family != AF_INET6) 18257429Smarkm return 0; 18357429Smarkm return 1; 18457429Smarkm} 18557429Smarkm 18657429Smarkm/* returns 1 if connection is via ipv4 */ 18757429Smarkm 18857429Smarkmint 18957429Smarkmpacket_connection_is_ipv4() 19057429Smarkm{ 19157429Smarkm struct sockaddr_storage to; 19257429Smarkm socklen_t tolen = sizeof(to); 19357429Smarkm 19457429Smarkm memset(&to, 0, sizeof(to)); 19557429Smarkm if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0) 19657429Smarkm return 0; 19757429Smarkm if (to.ss_family != AF_INET) 19857429Smarkm return 0; 19957429Smarkm return 1; 20057429Smarkm} 20157429Smarkm 20257429Smarkm/* Sets the connection into non-blocking mode. */ 20357429Smarkm 20457429Smarkmvoid 20557429Smarkmpacket_set_nonblocking() 20657429Smarkm{ 20757429Smarkm /* Set the socket into non-blocking mode. */ 20857429Smarkm if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0) 20957429Smarkm error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 21057429Smarkm 21157429Smarkm if (connection_out != connection_in) { 21257429Smarkm if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0) 21357429Smarkm error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 21457429Smarkm } 21557429Smarkm} 21657429Smarkm 21757429Smarkm/* Returns the socket used for reading. */ 21857429Smarkm 21957429Smarkmint 22057429Smarkmpacket_get_connection_in() 22157429Smarkm{ 22257429Smarkm return connection_in; 22357429Smarkm} 22457429Smarkm 22557429Smarkm/* Returns the descriptor used for writing. */ 22657429Smarkm 22757429Smarkmint 22857429Smarkmpacket_get_connection_out() 22957429Smarkm{ 23057429Smarkm return connection_out; 23157429Smarkm} 23257429Smarkm 23357429Smarkm/* Closes the connection and clears and frees internal data structures. */ 23457429Smarkm 23557429Smarkmvoid 23657429Smarkmpacket_close() 23757429Smarkm{ 23857429Smarkm if (!initialized) 23957429Smarkm return; 24057429Smarkm initialized = 0; 24157429Smarkm if (connection_in == connection_out) { 24257429Smarkm shutdown(connection_out, SHUT_RDWR); 24357429Smarkm close(connection_out); 24457429Smarkm } else { 24557429Smarkm close(connection_in); 24657429Smarkm close(connection_out); 24757429Smarkm } 24857429Smarkm buffer_free(&input); 24957429Smarkm buffer_free(&output); 25057429Smarkm buffer_free(&outgoing_packet); 25157429Smarkm buffer_free(&incoming_packet); 25257429Smarkm if (packet_compression) { 25357429Smarkm buffer_free(&compression_buffer); 25457429Smarkm buffer_compress_uninit(); 25557429Smarkm } 25657429Smarkm} 25757429Smarkm 25857429Smarkm/* Sets remote side protocol flags. */ 25957429Smarkm 26057429Smarkmvoid 26157429Smarkmpacket_set_protocol_flags(unsigned int protocol_flags) 26257429Smarkm{ 26357429Smarkm remote_protocol_flags = protocol_flags; 26457429Smarkm channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0); 26557429Smarkm} 26657429Smarkm 26757429Smarkm/* Returns the remote protocol flags set earlier by the above function. */ 26857429Smarkm 26957429Smarkmunsigned int 27057429Smarkmpacket_get_protocol_flags() 27157429Smarkm{ 27257429Smarkm return remote_protocol_flags; 27357429Smarkm} 27457429Smarkm 27557429Smarkm/* 27657429Smarkm * Starts packet compression from the next packet on in both directions. 27757429Smarkm * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. 27857429Smarkm */ 27957429Smarkm 28060573Skris/*** XXXXX todo: kex means re-init */ 28157429Smarkmvoid 28257429Smarkmpacket_start_compression(int level) 28357429Smarkm{ 28457429Smarkm if (packet_compression) 28557429Smarkm fatal("Compression already enabled."); 28657429Smarkm packet_compression = 1; 28757429Smarkm buffer_init(&compression_buffer); 28857429Smarkm buffer_compress_init(level); 28957429Smarkm} 29057429Smarkm 29157429Smarkm/* 29257429Smarkm * Encrypts the given number of bytes, copying from src to dest. bytes is 29357429Smarkm * known to be a multiple of 8. 29457429Smarkm */ 29557429Smarkm 29657429Smarkmvoid 29757429Smarkmpacket_encrypt(CipherContext * cc, void *dest, void *src, 29860573Skris unsigned int bytes) 29957429Smarkm{ 30057429Smarkm cipher_encrypt(cc, dest, src, bytes); 30157429Smarkm} 30257429Smarkm 30357429Smarkm/* 30457429Smarkm * Decrypts the given number of bytes, copying from src to dest. bytes is 30557429Smarkm * known to be a multiple of 8. 30657429Smarkm */ 30757429Smarkm 30857429Smarkmvoid 30957429Smarkmpacket_decrypt(CipherContext * cc, void *dest, void *src, 31060573Skris unsigned int bytes) 31157429Smarkm{ 31257429Smarkm int i; 31357429Smarkm 31457429Smarkm if ((bytes % 8) != 0) 31557429Smarkm fatal("packet_decrypt: bad ciphertext length %d", bytes); 31657429Smarkm 31757429Smarkm /* 31857429Smarkm * Cryptographic attack detector for ssh - Modifications for packet.c 31957429Smarkm * (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com) 32057429Smarkm */ 32157429Smarkm 32260573Skris if (cc->type == SSH_CIPHER_NONE || compat20) { 32357429Smarkm i = DEATTACK_OK; 32460573Skris } else { 32557429Smarkm i = detect_attack(src, bytes, NULL); 32657429Smarkm } 32757429Smarkm if (i == DEATTACK_DETECTED) 32857429Smarkm packet_disconnect("crc32 compensation attack: network attack detected"); 32957429Smarkm 33057429Smarkm cipher_decrypt(cc, dest, src, bytes); 33157429Smarkm} 33257429Smarkm 33357429Smarkm/* 33457429Smarkm * Causes any further packets to be encrypted using the given key. The same 33557429Smarkm * key is used for both sending and reception. However, both directions are 33657429Smarkm * encrypted independently of each other. 33757429Smarkm */ 33857429Smarkm 33957429Smarkmvoid 34057429Smarkmpacket_set_encryption_key(const unsigned char *key, unsigned int keylen, 34160573Skris int cipher) 34257429Smarkm{ 34360573Skris if (keylen < 20) 34460573Skris fatal("keylen too small: %d", keylen); 34560573Skris 34657429Smarkm /* All other ciphers use the same key in both directions for now. */ 34760573Skris cipher_set_key(&receive_context, cipher, key, keylen); 34860573Skris cipher_set_key(&send_context, cipher, key, keylen); 34957429Smarkm} 35057429Smarkm 35157429Smarkm/* Starts constructing a packet to send. */ 35257429Smarkm 35357429Smarkmvoid 35460573Skrispacket_start1(int type) 35557429Smarkm{ 35657429Smarkm char buf[9]; 35757429Smarkm 35857429Smarkm buffer_clear(&outgoing_packet); 35957429Smarkm memset(buf, 0, 8); 36057429Smarkm buf[8] = type; 36157429Smarkm buffer_append(&outgoing_packet, buf, 9); 36257429Smarkm} 36357429Smarkm 36460573Skrisvoid 36560573Skrispacket_start2(int type) 36660573Skris{ 36760573Skris char buf[4+1+1]; 36860573Skris 36960573Skris buffer_clear(&outgoing_packet); 37060573Skris memset(buf, 0, sizeof buf); 37160573Skris /* buf[0..3] = payload_len; */ 37260573Skris /* buf[4] = pad_len; */ 37360573Skris buf[5] = type & 0xff; 37460573Skris buffer_append(&outgoing_packet, buf, sizeof buf); 37560573Skris} 37660573Skris 37760573Skrisvoid 37860573Skrispacket_start(int type) 37960573Skris{ 38060573Skris DBG(debug("packet_start[%d]",type)); 38160573Skris if (use_ssh2_packet_format) 38260573Skris packet_start2(type); 38360573Skris else 38460573Skris packet_start1(type); 38560573Skris} 38660573Skris 38757429Smarkm/* Appends a character to the packet data. */ 38857429Smarkm 38957429Smarkmvoid 39057429Smarkmpacket_put_char(int value) 39157429Smarkm{ 39257429Smarkm char ch = value; 39357429Smarkm buffer_append(&outgoing_packet, &ch, 1); 39457429Smarkm} 39557429Smarkm 39657429Smarkm/* Appends an integer to the packet data. */ 39757429Smarkm 39857429Smarkmvoid 39957429Smarkmpacket_put_int(unsigned int value) 40057429Smarkm{ 40157429Smarkm buffer_put_int(&outgoing_packet, value); 40257429Smarkm} 40357429Smarkm 40457429Smarkm/* Appends a string to packet data. */ 40557429Smarkm 40657429Smarkmvoid 40757429Smarkmpacket_put_string(const char *buf, unsigned int len) 40857429Smarkm{ 40957429Smarkm buffer_put_string(&outgoing_packet, buf, len); 41057429Smarkm} 41160573Skrisvoid 41260573Skrispacket_put_cstring(const char *str) 41360573Skris{ 41460573Skris buffer_put_string(&outgoing_packet, str, strlen(str)); 41560573Skris} 41657429Smarkm 41760573Skrisvoid 41860573Skrispacket_put_raw(const char *buf, unsigned int len) 41960573Skris{ 42060573Skris buffer_append(&outgoing_packet, buf, len); 42160573Skris} 42260573Skris 42360573Skris 42457429Smarkm/* Appends an arbitrary precision integer to packet data. */ 42557429Smarkm 42657429Smarkmvoid 42757429Smarkmpacket_put_bignum(BIGNUM * value) 42857429Smarkm{ 42957429Smarkm buffer_put_bignum(&outgoing_packet, value); 43057429Smarkm} 43160573Skrisvoid 43260573Skrispacket_put_bignum2(BIGNUM * value) 43360573Skris{ 43460573Skris buffer_put_bignum2(&outgoing_packet, value); 43560573Skris} 43657429Smarkm 43757429Smarkm/* 43857429Smarkm * Finalizes and sends the packet. If the encryption key has been set, 43957429Smarkm * encrypts the packet before sending. 44057429Smarkm */ 44157429Smarkm 44257429Smarkmvoid 44360573Skrispacket_send1() 44457429Smarkm{ 44557429Smarkm char buf[8], *cp; 44657429Smarkm int i, padding, len; 44757429Smarkm unsigned int checksum; 44857429Smarkm u_int32_t rand = 0; 44957429Smarkm 45057429Smarkm /* 45157429Smarkm * If using packet compression, compress the payload of the outgoing 45257429Smarkm * packet. 45357429Smarkm */ 45457429Smarkm if (packet_compression) { 45557429Smarkm buffer_clear(&compression_buffer); 45657429Smarkm /* Skip padding. */ 45757429Smarkm buffer_consume(&outgoing_packet, 8); 45857429Smarkm /* padding */ 45957429Smarkm buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8); 46057429Smarkm buffer_compress(&outgoing_packet, &compression_buffer); 46157429Smarkm buffer_clear(&outgoing_packet); 46257429Smarkm buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), 46357429Smarkm buffer_len(&compression_buffer)); 46457429Smarkm } 46557429Smarkm /* Compute packet length without padding (add checksum, remove padding). */ 46657429Smarkm len = buffer_len(&outgoing_packet) + 4 - 8; 46757429Smarkm 46860573Skris /* Insert padding. Initialized to zero in packet_start1() */ 46957429Smarkm padding = 8 - len % 8; 47057429Smarkm if (cipher_type != SSH_CIPHER_NONE) { 47157429Smarkm cp = buffer_ptr(&outgoing_packet); 47257429Smarkm for (i = 0; i < padding; i++) { 47357429Smarkm if (i % 4 == 0) 47457429Smarkm rand = arc4random(); 47557429Smarkm cp[7 - i] = rand & 0xff; 47657429Smarkm rand >>= 8; 47757429Smarkm } 47857429Smarkm } 47957429Smarkm buffer_consume(&outgoing_packet, 8 - padding); 48057429Smarkm 48157429Smarkm /* Add check bytes. */ 48257429Smarkm checksum = crc32((unsigned char *) buffer_ptr(&outgoing_packet), 48357429Smarkm buffer_len(&outgoing_packet)); 48457429Smarkm PUT_32BIT(buf, checksum); 48557429Smarkm buffer_append(&outgoing_packet, buf, 4); 48657429Smarkm 48757429Smarkm#ifdef PACKET_DEBUG 48857429Smarkm fprintf(stderr, "packet_send plain: "); 48957429Smarkm buffer_dump(&outgoing_packet); 49057429Smarkm#endif 49157429Smarkm 49257429Smarkm /* Append to output. */ 49357429Smarkm PUT_32BIT(buf, len); 49457429Smarkm buffer_append(&output, buf, 4); 49557429Smarkm buffer_append_space(&output, &cp, buffer_len(&outgoing_packet)); 49657429Smarkm packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet), 49757429Smarkm buffer_len(&outgoing_packet)); 49857429Smarkm 49957429Smarkm#ifdef PACKET_DEBUG 50057429Smarkm fprintf(stderr, "encrypted: "); 50157429Smarkm buffer_dump(&output); 50257429Smarkm#endif 50357429Smarkm 50457429Smarkm buffer_clear(&outgoing_packet); 50557429Smarkm 50657429Smarkm /* 50757429Smarkm * Note that the packet is now only buffered in output. It won\'t be 50857429Smarkm * actually sent until packet_write_wait or packet_write_poll is 50957429Smarkm * called. 51057429Smarkm */ 51157429Smarkm} 51257429Smarkm 51357429Smarkm/* 51460573Skris * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) 51560573Skris */ 51660573Skrisvoid 51760573Skrispacket_send2() 51860573Skris{ 51960573Skris unsigned char *macbuf = NULL; 52060573Skris char *cp; 52160573Skris unsigned int packet_length = 0; 52260573Skris unsigned int i, padlen, len; 52360573Skris u_int32_t rand = 0; 52460573Skris static unsigned int seqnr = 0; 52560573Skris int type; 52660573Skris Enc *enc = NULL; 52760573Skris Mac *mac = NULL; 52860573Skris Comp *comp = NULL; 52960573Skris int block_size; 53060573Skris 53160573Skris if (kex != NULL) { 53260573Skris enc = &kex->enc[MODE_OUT]; 53360573Skris mac = &kex->mac[MODE_OUT]; 53460573Skris comp = &kex->comp[MODE_OUT]; 53560573Skris } 53660573Skris block_size = enc ? enc->block_size : 8; 53760573Skris 53860573Skris cp = buffer_ptr(&outgoing_packet); 53960573Skris type = cp[5] & 0xff; 54060573Skris 54160573Skris#ifdef PACKET_DEBUG 54260573Skris fprintf(stderr, "plain: "); 54360573Skris buffer_dump(&outgoing_packet); 54460573Skris#endif 54560573Skris 54660573Skris if (comp && comp->enabled) { 54760573Skris len = buffer_len(&outgoing_packet); 54860573Skris /* skip header, compress only payload */ 54960573Skris buffer_consume(&outgoing_packet, 5); 55060573Skris buffer_clear(&compression_buffer); 55160573Skris buffer_compress(&outgoing_packet, &compression_buffer); 55260573Skris buffer_clear(&outgoing_packet); 55360573Skris buffer_append(&outgoing_packet, "\0\0\0\0\0", 5); 55460573Skris buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), 55560573Skris buffer_len(&compression_buffer)); 55660573Skris DBG(debug("compression: raw %d compressed %d", len, 55760573Skris buffer_len(&outgoing_packet))); 55860573Skris } 55960573Skris 56060573Skris /* sizeof (packet_len + pad_len + payload) */ 56160573Skris len = buffer_len(&outgoing_packet); 56260573Skris 56360573Skris /* 56460573Skris * calc size of padding, alloc space, get random data, 56560573Skris * minimum padding is 4 bytes 56660573Skris */ 56760573Skris padlen = block_size - (len % block_size); 56860573Skris if (padlen < 4) 56960573Skris padlen += block_size; 57060573Skris buffer_append_space(&outgoing_packet, &cp, padlen); 57160573Skris if (enc && enc->type != SSH_CIPHER_NONE) { 57260573Skris /* random padding */ 57360573Skris for (i = 0; i < padlen; i++) { 57460573Skris if (i % 4 == 0) 57560573Skris rand = arc4random(); 57660573Skris cp[i] = rand & 0xff; 57760573Skris rand <<= 8; 57860573Skris } 57960573Skris } else { 58060573Skris /* clear padding */ 58160573Skris memset(cp, 0, padlen); 58260573Skris } 58360573Skris /* packet_length includes payload, padding and padding length field */ 58460573Skris packet_length = buffer_len(&outgoing_packet) - 4; 58560573Skris cp = buffer_ptr(&outgoing_packet); 58660573Skris PUT_32BIT(cp, packet_length); 58760573Skris cp[4] = padlen & 0xff; 58860573Skris DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen)); 58960573Skris 59060573Skris /* compute MAC over seqnr and packet(length fields, payload, padding) */ 59160573Skris if (mac && mac->enabled) { 59260573Skris macbuf = hmac( mac->md, seqnr, 59360573Skris (unsigned char *) buffer_ptr(&outgoing_packet), 59460573Skris buffer_len(&outgoing_packet), 59560573Skris mac->key, mac->key_len 59660573Skris ); 59760573Skris DBG(debug("done calc HMAC out #%d", seqnr)); 59860573Skris } 59960573Skris /* encrypt packet and append to output buffer. */ 60060573Skris buffer_append_space(&output, &cp, buffer_len(&outgoing_packet)); 60160573Skris packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet), 60260573Skris buffer_len(&outgoing_packet)); 60360573Skris /* append unencrypted MAC */ 60460573Skris if (mac && mac->enabled) 60560573Skris buffer_append(&output, (char *)macbuf, mac->mac_len); 60660573Skris#ifdef PACKET_DEBUG 60760573Skris fprintf(stderr, "encrypted: "); 60860573Skris buffer_dump(&output); 60960573Skris#endif 61060573Skris /* increment sequence number for outgoing packets */ 61160573Skris if (++seqnr == 0) 61260573Skris log("outgoing seqnr wraps around"); 61360573Skris buffer_clear(&outgoing_packet); 61460573Skris 61560573Skris if (type == SSH2_MSG_NEWKEYS) { 61660573Skris if (kex==NULL || mac==NULL || enc==NULL || comp==NULL) 61760573Skris fatal("packet_send2: no KEX"); 61860573Skris if (mac->md != NULL) 61960573Skris mac->enabled = 1; 62060573Skris DBG(debug("cipher_set_key_iv send_context")); 62160573Skris cipher_set_key_iv(&send_context, enc->type, 62260573Skris enc->key, enc->key_len, 62360573Skris enc->iv, enc->iv_len); 62460573Skris clear_enc_keys(enc, kex->we_need); 62560573Skris if (comp->type != 0 && comp->enabled == 0) { 62660573Skris comp->enabled = 1; 62760573Skris if (! packet_compression) 62860573Skris packet_start_compression(6); 62960573Skris } 63060573Skris } 63160573Skris} 63260573Skris 63360573Skrisvoid 63460573Skrispacket_send() 63560573Skris{ 63660573Skris if (use_ssh2_packet_format) 63760573Skris packet_send2(); 63860573Skris else 63960573Skris packet_send1(); 64060573Skris DBG(debug("packet_send done")); 64160573Skris} 64260573Skris 64360573Skris/* 64457429Smarkm * Waits until a packet has been received, and returns its type. Note that 64557429Smarkm * no other data is processed until this returns, so this function should not 64657429Smarkm * be used during the interactive session. 64757429Smarkm */ 64857429Smarkm 64957429Smarkmint 65057429Smarkmpacket_read(int *payload_len_ptr) 65157429Smarkm{ 65257429Smarkm int type, len; 65357429Smarkm fd_set set; 65457429Smarkm char buf[8192]; 65560573Skris DBG(debug("packet_read()")); 65657429Smarkm 65757429Smarkm /* Since we are blocking, ensure that all written packets have been sent. */ 65857429Smarkm packet_write_wait(); 65957429Smarkm 66057429Smarkm /* Stay in the loop until we have received a complete packet. */ 66157429Smarkm for (;;) { 66257429Smarkm /* Try to read a packet from the buffer. */ 66357429Smarkm type = packet_read_poll(payload_len_ptr); 66460573Skris if (!use_ssh2_packet_format && ( 66560573Skris type == SSH_SMSG_SUCCESS 66657429Smarkm || type == SSH_SMSG_FAILURE 66757429Smarkm || type == SSH_CMSG_EOF 66860573Skris || type == SSH_CMSG_EXIT_CONFIRMATION)) 66957429Smarkm packet_integrity_check(*payload_len_ptr, 0, type); 67057429Smarkm /* If we got a packet, return it. */ 67157429Smarkm if (type != SSH_MSG_NONE) 67257429Smarkm return type; 67357429Smarkm /* 67457429Smarkm * Otherwise, wait for some data to arrive, add it to the 67557429Smarkm * buffer, and try again. 67657429Smarkm */ 67757429Smarkm FD_ZERO(&set); 67857429Smarkm FD_SET(connection_in, &set); 67957429Smarkm 68057429Smarkm /* Wait for some data to arrive. */ 68157429Smarkm select(connection_in + 1, &set, NULL, NULL, NULL); 68257429Smarkm 68357429Smarkm /* Read data from the socket. */ 68457429Smarkm len = read(connection_in, buf, sizeof(buf)); 68557429Smarkm if (len == 0) { 68657429Smarkm log("Connection closed by %.200s", get_remote_ipaddr()); 68757429Smarkm fatal_cleanup(); 68857429Smarkm } 68957429Smarkm if (len < 0) 69057429Smarkm fatal("Read from socket failed: %.100s", strerror(errno)); 69157429Smarkm /* Append it to the buffer. */ 69257429Smarkm packet_process_incoming(buf, len); 69357429Smarkm } 69457429Smarkm /* NOTREACHED */ 69557429Smarkm} 69657429Smarkm 69757429Smarkm/* 69857429Smarkm * Waits until a packet has been received, verifies that its type matches 69957429Smarkm * that given, and gives a fatal error and exits if there is a mismatch. 70057429Smarkm */ 70157429Smarkm 70257429Smarkmvoid 70357429Smarkmpacket_read_expect(int *payload_len_ptr, int expected_type) 70457429Smarkm{ 70557429Smarkm int type; 70657429Smarkm 70757429Smarkm type = packet_read(payload_len_ptr); 70857429Smarkm if (type != expected_type) 70957429Smarkm packet_disconnect("Protocol error: expected packet type %d, got %d", 71060573Skris expected_type, type); 71157429Smarkm} 71257429Smarkm 71357429Smarkm/* Checks if a full packet is available in the data received so far via 71457429Smarkm * packet_process_incoming. If so, reads the packet; otherwise returns 71557429Smarkm * SSH_MSG_NONE. This does not wait for data from the connection. 71657429Smarkm * 71757429Smarkm * SSH_MSG_DISCONNECT is handled specially here. Also, 71857429Smarkm * SSH_MSG_IGNORE messages are skipped by this function and are never returned 71957429Smarkm * to higher levels. 72057429Smarkm * 72157429Smarkm * The returned payload_len does include space consumed by: 72257429Smarkm * Packet length 72357429Smarkm * Padding 72457429Smarkm * Packet type 72557429Smarkm * Check bytes 72657429Smarkm */ 72757429Smarkm 72857429Smarkmint 72960573Skrispacket_read_poll1(int *payload_len_ptr) 73057429Smarkm{ 73157429Smarkm unsigned int len, padded_len; 73257429Smarkm unsigned char *ucp; 73360573Skris char buf[8], *cp; 73457429Smarkm unsigned int checksum, stored_checksum; 73557429Smarkm 73657429Smarkm /* Check if input size is less than minimum packet size. */ 73757429Smarkm if (buffer_len(&input) < 4 + 8) 73857429Smarkm return SSH_MSG_NONE; 73957429Smarkm /* Get length of incoming packet. */ 74057429Smarkm ucp = (unsigned char *) buffer_ptr(&input); 74157429Smarkm len = GET_32BIT(ucp); 74257429Smarkm if (len < 1 + 2 + 2 || len > 256 * 1024) 74357429Smarkm packet_disconnect("Bad packet length %d.", len); 74457429Smarkm padded_len = (len + 8) & ~7; 74557429Smarkm 74657429Smarkm /* Check if the packet has been entirely received. */ 74757429Smarkm if (buffer_len(&input) < 4 + padded_len) 74857429Smarkm return SSH_MSG_NONE; 74957429Smarkm 75057429Smarkm /* The entire packet is in buffer. */ 75157429Smarkm 75257429Smarkm /* Consume packet length. */ 75357429Smarkm buffer_consume(&input, 4); 75457429Smarkm 75557429Smarkm /* Copy data to incoming_packet. */ 75657429Smarkm buffer_clear(&incoming_packet); 75757429Smarkm buffer_append_space(&incoming_packet, &cp, padded_len); 75857429Smarkm packet_decrypt(&receive_context, cp, buffer_ptr(&input), padded_len); 75957429Smarkm buffer_consume(&input, padded_len); 76057429Smarkm 76157429Smarkm#ifdef PACKET_DEBUG 76257429Smarkm fprintf(stderr, "read_poll plain: "); 76357429Smarkm buffer_dump(&incoming_packet); 76457429Smarkm#endif 76557429Smarkm 76657429Smarkm /* Compute packet checksum. */ 76757429Smarkm checksum = crc32((unsigned char *) buffer_ptr(&incoming_packet), 76860573Skris buffer_len(&incoming_packet) - 4); 76957429Smarkm 77057429Smarkm /* Skip padding. */ 77157429Smarkm buffer_consume(&incoming_packet, 8 - len % 8); 77257429Smarkm 77357429Smarkm /* Test check bytes. */ 77457429Smarkm 77557429Smarkm if (len != buffer_len(&incoming_packet)) 77657429Smarkm packet_disconnect("packet_read_poll: len %d != buffer_len %d.", 77760573Skris len, buffer_len(&incoming_packet)); 77857429Smarkm 77957429Smarkm ucp = (unsigned char *) buffer_ptr(&incoming_packet) + len - 4; 78057429Smarkm stored_checksum = GET_32BIT(ucp); 78157429Smarkm if (checksum != stored_checksum) 78257429Smarkm packet_disconnect("Corrupted check bytes on input."); 78357429Smarkm buffer_consume_end(&incoming_packet, 4); 78457429Smarkm 78557429Smarkm /* If using packet compression, decompress the packet. */ 78657429Smarkm if (packet_compression) { 78757429Smarkm buffer_clear(&compression_buffer); 78857429Smarkm buffer_uncompress(&incoming_packet, &compression_buffer); 78957429Smarkm buffer_clear(&incoming_packet); 79057429Smarkm buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), 79160573Skris buffer_len(&compression_buffer)); 79257429Smarkm } 79357429Smarkm /* Get packet type. */ 79457429Smarkm buffer_get(&incoming_packet, &buf[0], 1); 79557429Smarkm 79657429Smarkm /* Return length of payload (without type field). */ 79757429Smarkm *payload_len_ptr = buffer_len(&incoming_packet); 79857429Smarkm 79960573Skris /* Return type. */ 80060573Skris return (unsigned char) buf[0]; 80160573Skris} 80257429Smarkm 80360573Skrisint 80460573Skrispacket_read_poll2(int *payload_len_ptr) 80560573Skris{ 80660573Skris unsigned int padlen, need; 80760573Skris unsigned char buf[8], *macbuf; 80860573Skris unsigned char *ucp; 80960573Skris char *cp; 81060573Skris static unsigned int packet_length = 0; 81160573Skris static unsigned int seqnr = 0; 81260573Skris int type; 81360573Skris int maclen, block_size; 81460573Skris Enc *enc = NULL; 81560573Skris Mac *mac = NULL; 81660573Skris Comp *comp = NULL; 81757429Smarkm 81860573Skris if (kex != NULL) { 81960573Skris enc = &kex->enc[MODE_IN]; 82060573Skris mac = &kex->mac[MODE_IN]; 82160573Skris comp = &kex->comp[MODE_IN]; 82257429Smarkm } 82360573Skris maclen = mac && mac->enabled ? mac->mac_len : 0; 82460573Skris block_size = enc ? enc->block_size : 8; 82560573Skris 82660573Skris if (packet_length == 0) { 82760573Skris /* 82860573Skris * check if input size is less than the cipher block size, 82960573Skris * decrypt first block and extract length of incoming packet 83060573Skris */ 83160573Skris if (buffer_len(&input) < block_size) 83260573Skris return SSH_MSG_NONE; 83360573Skris buffer_clear(&incoming_packet); 83460573Skris buffer_append_space(&incoming_packet, &cp, block_size); 83560573Skris packet_decrypt(&receive_context, cp, buffer_ptr(&input), 83660573Skris block_size); 83760573Skris ucp = (unsigned char *) buffer_ptr(&incoming_packet); 83860573Skris packet_length = GET_32BIT(ucp); 83960573Skris if (packet_length < 1 + 4 || packet_length > 256 * 1024) { 84060573Skris buffer_dump(&incoming_packet); 84160573Skris packet_disconnect("Bad packet length %d.", packet_length); 84260573Skris } 84360573Skris DBG(debug("input: packet len %d", packet_length+4)); 84460573Skris buffer_consume(&input, block_size); 84560573Skris } 84660573Skris /* we have a partial packet of block_size bytes */ 84760573Skris need = 4 + packet_length - block_size; 84860573Skris DBG(debug("partial packet %d, need %d, maclen %d", block_size, 84960573Skris need, maclen)); 85060573Skris if (need % block_size != 0) 85160573Skris fatal("padding error: need %d block %d mod %d", 85260573Skris need, block_size, need % block_size); 85360573Skris /* 85460573Skris * check if the entire packet has been received and 85560573Skris * decrypt into incoming_packet 85660573Skris */ 85760573Skris if (buffer_len(&input) < need + maclen) 85860573Skris return SSH_MSG_NONE; 85960573Skris#ifdef PACKET_DEBUG 86060573Skris fprintf(stderr, "read_poll enc/full: "); 86160573Skris buffer_dump(&input); 86260573Skris#endif 86360573Skris buffer_append_space(&incoming_packet, &cp, need); 86460573Skris packet_decrypt(&receive_context, cp, buffer_ptr(&input), need); 86560573Skris buffer_consume(&input, need); 86660573Skris /* 86760573Skris * compute MAC over seqnr and packet, 86860573Skris * increment sequence number for incoming packet 86960573Skris */ 87060573Skris if (mac && mac->enabled) { 87160573Skris macbuf = hmac( mac->md, seqnr, 87260573Skris (unsigned char *) buffer_ptr(&incoming_packet), 87360573Skris buffer_len(&incoming_packet), 87460573Skris mac->key, mac->key_len 87560573Skris ); 87660573Skris if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) 87760573Skris packet_disconnect("Corrupted HMAC on input."); 87860573Skris DBG(debug("HMAC #%d ok", seqnr)); 87960573Skris buffer_consume(&input, mac->mac_len); 88060573Skris } 88160573Skris if (++seqnr == 0) 88260573Skris log("incoming seqnr wraps around"); 88360573Skris 88460573Skris /* get padlen */ 88560573Skris cp = buffer_ptr(&incoming_packet) + 4; 88660573Skris padlen = *cp & 0xff; 88760573Skris DBG(debug("input: padlen %d", padlen)); 88860573Skris if (padlen < 4) 88960573Skris packet_disconnect("Corrupted padlen %d on input.", padlen); 89060573Skris 89160573Skris /* skip packet size + padlen, discard padding */ 89260573Skris buffer_consume(&incoming_packet, 4 + 1); 89360573Skris buffer_consume_end(&incoming_packet, padlen); 89460573Skris 89560573Skris DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet))); 89660573Skris if (comp && comp->enabled) { 89760573Skris buffer_clear(&compression_buffer); 89860573Skris buffer_uncompress(&incoming_packet, &compression_buffer); 89960573Skris buffer_clear(&incoming_packet); 90060573Skris buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), 90160573Skris buffer_len(&compression_buffer)); 90260573Skris DBG(debug("input: len after de-compress %d", buffer_len(&incoming_packet))); 90360573Skris } 90460573Skris /* 90560573Skris * get packet type, implies consume. 90660573Skris * return length of payload (without type field) 90760573Skris */ 90860573Skris buffer_get(&incoming_packet, (char *)&buf[0], 1); 90960573Skris *payload_len_ptr = buffer_len(&incoming_packet); 91060573Skris 91160573Skris /* reset for next packet */ 91260573Skris packet_length = 0; 91360573Skris 91460573Skris /* extract packet type */ 91560573Skris type = (unsigned char)buf[0]; 91660573Skris 91760573Skris if (type == SSH2_MSG_NEWKEYS) { 91860573Skris if (kex==NULL || mac==NULL || enc==NULL || comp==NULL) 91960573Skris fatal("packet_read_poll2: no KEX"); 92060573Skris if (mac->md != NULL) 92160573Skris mac->enabled = 1; 92260573Skris DBG(debug("cipher_set_key_iv receive_context")); 92360573Skris cipher_set_key_iv(&receive_context, enc->type, 92460573Skris enc->key, enc->key_len, 92560573Skris enc->iv, enc->iv_len); 92660573Skris clear_enc_keys(enc, kex->we_need); 92760573Skris if (comp->type != 0 && comp->enabled == 0) { 92860573Skris comp->enabled = 1; 92960573Skris if (! packet_compression) 93060573Skris packet_start_compression(6); 93160573Skris } 93260573Skris } 93360573Skris 93460573Skris#ifdef PACKET_DEBUG 93560573Skris fprintf(stderr, "read/plain[%d]:\r\n",type); 93660573Skris buffer_dump(&incoming_packet); 93760573Skris#endif 93860573Skris return (unsigned char)type; 93957429Smarkm} 94057429Smarkm 94160573Skrisint 94260573Skrispacket_read_poll(int *payload_len_ptr) 94360573Skris{ 94460573Skris char *msg; 94560573Skris for (;;) { 94660573Skris int type = use_ssh2_packet_format ? 94760573Skris packet_read_poll2(payload_len_ptr): 94860573Skris packet_read_poll1(payload_len_ptr); 94960573Skris 95060573Skris if(compat20) { 95160573Skris int reason; 95260573Skris if (type != 0) 95360573Skris DBG(debug("received packet type %d", type)); 95460573Skris switch(type) { 95560573Skris case SSH2_MSG_IGNORE: 95660573Skris break; 95760573Skris case SSH2_MSG_DEBUG: 95860573Skris packet_get_char(); 95960573Skris msg = packet_get_string(NULL); 96060573Skris debug("Remote: %.900s", msg); 96160573Skris xfree(msg); 96260573Skris msg = packet_get_string(NULL); 96360573Skris xfree(msg); 96460573Skris break; 96560573Skris case SSH2_MSG_DISCONNECT: 96660573Skris reason = packet_get_int(); 96760573Skris msg = packet_get_string(NULL); 96860573Skris log("Received disconnect: %d: %.900s", reason, msg); 96960573Skris xfree(msg); 97060573Skris fatal_cleanup(); 97160573Skris break; 97260573Skris default: 97360573Skris return type; 97460573Skris break; 97560573Skris } 97660573Skris } else { 97760573Skris switch(type) { 97860573Skris case SSH_MSG_IGNORE: 97960573Skris break; 98060573Skris case SSH_MSG_DEBUG: 98160573Skris msg = packet_get_string(NULL); 98260573Skris debug("Remote: %.900s", msg); 98360573Skris xfree(msg); 98460573Skris break; 98560573Skris case SSH_MSG_DISCONNECT: 98660573Skris msg = packet_get_string(NULL); 98760573Skris log("Received disconnect: %.900s", msg); 98860573Skris fatal_cleanup(); 98960573Skris xfree(msg); 99060573Skris break; 99160573Skris default: 99260573Skris if (type != 0) 99360573Skris DBG(debug("received packet type %d", type)); 99460573Skris return type; 99560573Skris break; 99660573Skris } 99760573Skris } 99860573Skris } 99960573Skris} 100060573Skris 100157429Smarkm/* 100257429Smarkm * Buffers the given amount of input characters. This is intended to be used 100357429Smarkm * together with packet_read_poll. 100457429Smarkm */ 100557429Smarkm 100657429Smarkmvoid 100757429Smarkmpacket_process_incoming(const char *buf, unsigned int len) 100857429Smarkm{ 100957429Smarkm buffer_append(&input, buf, len); 101057429Smarkm} 101157429Smarkm 101257429Smarkm/* Returns a character from the packet. */ 101357429Smarkm 101457429Smarkmunsigned int 101557429Smarkmpacket_get_char() 101657429Smarkm{ 101757429Smarkm char ch; 101857429Smarkm buffer_get(&incoming_packet, &ch, 1); 101957429Smarkm return (unsigned char) ch; 102057429Smarkm} 102157429Smarkm 102257429Smarkm/* Returns an integer from the packet data. */ 102357429Smarkm 102457429Smarkmunsigned int 102557429Smarkmpacket_get_int() 102657429Smarkm{ 102757429Smarkm return buffer_get_int(&incoming_packet); 102857429Smarkm} 102957429Smarkm 103057429Smarkm/* 103157429Smarkm * Returns an arbitrary precision integer from the packet data. The integer 103257429Smarkm * must have been initialized before this call. 103357429Smarkm */ 103457429Smarkm 103557429Smarkmvoid 103657429Smarkmpacket_get_bignum(BIGNUM * value, int *length_ptr) 103757429Smarkm{ 103857429Smarkm *length_ptr = buffer_get_bignum(&incoming_packet, value); 103957429Smarkm} 104057429Smarkm 104160573Skrisvoid 104260573Skrispacket_get_bignum2(BIGNUM * value, int *length_ptr) 104360573Skris{ 104460573Skris *length_ptr = buffer_get_bignum2(&incoming_packet, value); 104560573Skris} 104660573Skris 104760573Skrischar * 104860573Skrispacket_get_raw(int *length_ptr) 104960573Skris{ 105060573Skris int bytes = buffer_len(&incoming_packet); 105160573Skris if (length_ptr != NULL) 105260573Skris *length_ptr = bytes; 105360573Skris return buffer_ptr(&incoming_packet); 105460573Skris} 105560573Skris 105660573Skrisint 105760573Skrispacket_remaining(void) 105860573Skris{ 105960573Skris return buffer_len(&incoming_packet); 106060573Skris} 106160573Skris 106257429Smarkm/* 106357429Smarkm * Returns a string from the packet data. The string is allocated using 106457429Smarkm * xmalloc; it is the responsibility of the calling program to free it when 106557429Smarkm * no longer needed. The length_ptr argument may be NULL, or point to an 106657429Smarkm * integer into which the length of the string is stored. 106757429Smarkm */ 106857429Smarkm 106957429Smarkmchar * 107057429Smarkmpacket_get_string(unsigned int *length_ptr) 107157429Smarkm{ 107257429Smarkm return buffer_get_string(&incoming_packet, length_ptr); 107357429Smarkm} 107457429Smarkm 107557429Smarkm/* 107657429Smarkm * Sends a diagnostic message from the server to the client. This message 107757429Smarkm * can be sent at any time (but not while constructing another message). The 107857429Smarkm * message is printed immediately, but only if the client is being executed 107957429Smarkm * in verbose mode. These messages are primarily intended to ease debugging 108057429Smarkm * authentication problems. The length of the formatted message must not 108157429Smarkm * exceed 1024 bytes. This will automatically call packet_write_wait. 108257429Smarkm */ 108357429Smarkm 108457429Smarkmvoid 108557429Smarkmpacket_send_debug(const char *fmt,...) 108657429Smarkm{ 108757429Smarkm char buf[1024]; 108857429Smarkm va_list args; 108957429Smarkm 109057429Smarkm va_start(args, fmt); 109157429Smarkm vsnprintf(buf, sizeof(buf), fmt, args); 109257429Smarkm va_end(args); 109357429Smarkm 109460573Skris if (compat20) { 109560573Skris packet_start(SSH2_MSG_DEBUG); 109660573Skris packet_put_char(0); /* bool: always display */ 109760573Skris packet_put_cstring(buf); 109860573Skris packet_put_cstring(""); 109960573Skris } else { 110060573Skris packet_start(SSH_MSG_DEBUG); 110160573Skris packet_put_cstring(buf); 110260573Skris } 110357429Smarkm packet_send(); 110457429Smarkm packet_write_wait(); 110557429Smarkm} 110657429Smarkm 110757429Smarkm/* 110857429Smarkm * Logs the error plus constructs and sends a disconnect packet, closes the 110957429Smarkm * connection, and exits. This function never returns. The error message 111057429Smarkm * should not contain a newline. The length of the formatted message must 111157429Smarkm * not exceed 1024 bytes. 111257429Smarkm */ 111357429Smarkm 111457429Smarkmvoid 111557429Smarkmpacket_disconnect(const char *fmt,...) 111657429Smarkm{ 111757429Smarkm char buf[1024]; 111857429Smarkm va_list args; 111957429Smarkm static int disconnecting = 0; 112057429Smarkm if (disconnecting) /* Guard against recursive invocations. */ 112157429Smarkm fatal("packet_disconnect called recursively."); 112257429Smarkm disconnecting = 1; 112357429Smarkm 112457429Smarkm /* 112557429Smarkm * Format the message. Note that the caller must make sure the 112657429Smarkm * message is of limited size. 112757429Smarkm */ 112857429Smarkm va_start(args, fmt); 112957429Smarkm vsnprintf(buf, sizeof(buf), fmt, args); 113057429Smarkm va_end(args); 113157429Smarkm 113257429Smarkm /* Send the disconnect message to the other side, and wait for it to get sent. */ 113360573Skris if (compat20) { 113460573Skris packet_start(SSH2_MSG_DISCONNECT); 113560573Skris packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR); 113660573Skris packet_put_cstring(buf); 113760573Skris packet_put_cstring(""); 113860573Skris } else { 113960573Skris packet_start(SSH_MSG_DISCONNECT); 114060573Skris packet_put_string(buf, strlen(buf)); 114160573Skris } 114257429Smarkm packet_send(); 114357429Smarkm packet_write_wait(); 114457429Smarkm 114557429Smarkm /* Stop listening for connections. */ 114657429Smarkm channel_stop_listening(); 114757429Smarkm 114857429Smarkm /* Close the connection. */ 114957429Smarkm packet_close(); 115057429Smarkm 115157429Smarkm /* Display the error locally and exit. */ 115257429Smarkm log("Disconnecting: %.100s", buf); 115357429Smarkm fatal_cleanup(); 115457429Smarkm} 115557429Smarkm 115657429Smarkm/* Checks if there is any buffered output, and tries to write some of the output. */ 115757429Smarkm 115857429Smarkmvoid 115957429Smarkmpacket_write_poll() 116057429Smarkm{ 116157429Smarkm int len = buffer_len(&output); 116257429Smarkm if (len > 0) { 116357429Smarkm len = write(connection_out, buffer_ptr(&output), len); 116457429Smarkm if (len <= 0) { 116557429Smarkm if (errno == EAGAIN) 116657429Smarkm return; 116757429Smarkm else 116857429Smarkm fatal("Write failed: %.100s", strerror(errno)); 116957429Smarkm } 117057429Smarkm buffer_consume(&output, len); 117157429Smarkm } 117257429Smarkm} 117357429Smarkm 117457429Smarkm/* 117557429Smarkm * Calls packet_write_poll repeatedly until all pending output data has been 117657429Smarkm * written. 117757429Smarkm */ 117857429Smarkm 117957429Smarkmvoid 118057429Smarkmpacket_write_wait() 118157429Smarkm{ 118257429Smarkm packet_write_poll(); 118357429Smarkm while (packet_have_data_to_write()) { 118457429Smarkm fd_set set; 118557429Smarkm FD_ZERO(&set); 118657429Smarkm FD_SET(connection_out, &set); 118757429Smarkm select(connection_out + 1, NULL, &set, NULL, NULL); 118857429Smarkm packet_write_poll(); 118957429Smarkm } 119057429Smarkm} 119157429Smarkm 119257429Smarkm/* Returns true if there is buffered data to write to the connection. */ 119357429Smarkm 119457429Smarkmint 119557429Smarkmpacket_have_data_to_write() 119657429Smarkm{ 119757429Smarkm return buffer_len(&output) != 0; 119857429Smarkm} 119957429Smarkm 120057429Smarkm/* Returns true if there is not too much data to write to the connection. */ 120157429Smarkm 120257429Smarkmint 120357429Smarkmpacket_not_very_much_data_to_write() 120457429Smarkm{ 120557429Smarkm if (interactive_mode) 120657429Smarkm return buffer_len(&output) < 16384; 120757429Smarkm else 120857429Smarkm return buffer_len(&output) < 128 * 1024; 120957429Smarkm} 121057429Smarkm 121157429Smarkm/* Informs that the current session is interactive. Sets IP flags for that. */ 121257429Smarkm 121357429Smarkmvoid 121457429Smarkmpacket_set_interactive(int interactive, int keepalives) 121557429Smarkm{ 121657429Smarkm int on = 1; 121757429Smarkm 121857429Smarkm /* Record that we are in interactive mode. */ 121957429Smarkm interactive_mode = interactive; 122057429Smarkm 122157429Smarkm /* Only set socket options if using a socket. */ 122257429Smarkm if (!packet_connection_is_on_socket()) 122357429Smarkm return; 122457429Smarkm if (keepalives) { 122557429Smarkm /* Set keepalives if requested. */ 122657429Smarkm if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *) &on, 122757429Smarkm sizeof(on)) < 0) 122857429Smarkm error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); 122957429Smarkm } 123057429Smarkm /* 123157429Smarkm * IPTOS_LOWDELAY, TCP_NODELAY and IPTOS_THROUGHPUT are IPv4 only 123257429Smarkm */ 123357429Smarkm if (!packet_connection_is_ipv4()) 123457429Smarkm return; 123557429Smarkm if (interactive) { 123657429Smarkm /* 123757429Smarkm * Set IP options for an interactive connection. Use 123857429Smarkm * IPTOS_LOWDELAY and TCP_NODELAY. 123957429Smarkm */ 124057429Smarkm int lowdelay = IPTOS_LOWDELAY; 124157429Smarkm if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay, 124257429Smarkm sizeof(lowdelay)) < 0) 124357429Smarkm error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno)); 124457429Smarkm if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *) &on, 124557429Smarkm sizeof(on)) < 0) 124657429Smarkm error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 124757429Smarkm } else { 124857429Smarkm /* 124957429Smarkm * Set IP options for a non-interactive connection. Use 125057429Smarkm * IPTOS_THROUGHPUT. 125157429Smarkm */ 125257429Smarkm int throughput = IPTOS_THROUGHPUT; 125357429Smarkm if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput, 125457429Smarkm sizeof(throughput)) < 0) 125557429Smarkm error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno)); 125657429Smarkm } 125757429Smarkm} 125857429Smarkm 125957429Smarkm/* Returns true if the current connection is interactive. */ 126057429Smarkm 126157429Smarkmint 126257429Smarkmpacket_is_interactive() 126357429Smarkm{ 126457429Smarkm return interactive_mode; 126557429Smarkm} 126657429Smarkm 126757429Smarkmint 126857429Smarkmpacket_set_maxsize(int s) 126957429Smarkm{ 127057429Smarkm static int called = 0; 127157429Smarkm if (called) { 127260573Skris log("packet_set_maxsize: called twice: old %d new %d", 127360573Skris max_packet_size, s); 127457429Smarkm return -1; 127557429Smarkm } 127657429Smarkm if (s < 4 * 1024 || s > 1024 * 1024) { 127757429Smarkm log("packet_set_maxsize: bad size %d", s); 127857429Smarkm return -1; 127957429Smarkm } 128057429Smarkm log("packet_set_maxsize: setting to %d", s); 128157429Smarkm max_packet_size = s; 128257429Smarkm return s; 128357429Smarkm} 1284