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