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