10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
30Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
40Sstevel@tonic-gate  *                    All rights reserved
50Sstevel@tonic-gate  * This file contains code implementing the packet protocol and communication
60Sstevel@tonic-gate  * with the other side.  This same code is used both on client and server side.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
90Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
100Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
110Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
120Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  *
150Sstevel@tonic-gate  * SSH2 packet format added by Markus Friedl.
160Sstevel@tonic-gate  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
170Sstevel@tonic-gate  *
180Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
190Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
200Sstevel@tonic-gate  * are met:
210Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
220Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
230Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
240Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
250Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
260Sstevel@tonic-gate  *
270Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
280Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
290Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
300Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
310Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
320Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
330Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
340Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
350Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
360Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
370Sstevel@tonic-gate  */
380Sstevel@tonic-gate /*
39*6375Sjp161948  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
400Sstevel@tonic-gate  * Use is subject to license terms.
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate 
435562Sjp161948 /* $OpenBSD: packet.c,v 1.148 2007/06/07 19:37:34 pvalchev Exp $ */
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
460Sstevel@tonic-gate 
475562Sjp161948 #include "includes.h"
485562Sjp161948 
495562Sjp161948 #include "sys-queue.h"
500Sstevel@tonic-gate #include "xmalloc.h"
510Sstevel@tonic-gate #include "buffer.h"
520Sstevel@tonic-gate #include "packet.h"
530Sstevel@tonic-gate #include "bufaux.h"
540Sstevel@tonic-gate #include "crc32.h"
550Sstevel@tonic-gate #include "getput.h"
560Sstevel@tonic-gate #include "compress.h"
570Sstevel@tonic-gate #include "deattack.h"
580Sstevel@tonic-gate #include "channels.h"
590Sstevel@tonic-gate #include "compat.h"
600Sstevel@tonic-gate #include "ssh1.h"
610Sstevel@tonic-gate #include "ssh2.h"
620Sstevel@tonic-gate #include "cipher.h"
630Sstevel@tonic-gate #include "kex.h"
640Sstevel@tonic-gate #include "mac.h"
650Sstevel@tonic-gate #include "log.h"
660Sstevel@tonic-gate #include "canohost.h"
670Sstevel@tonic-gate #include "misc.h"
680Sstevel@tonic-gate #include "ssh.h"
690Sstevel@tonic-gate 
700Sstevel@tonic-gate #ifdef ALTPRIVSEP
710Sstevel@tonic-gate static int packet_server = 0;
720Sstevel@tonic-gate static int packet_monitor = 0;
730Sstevel@tonic-gate #endif /* ALTPRIVSEP */
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #ifdef PACKET_DEBUG
760Sstevel@tonic-gate #define DBG(x) x
770Sstevel@tonic-gate #else
780Sstevel@tonic-gate #define DBG(x)
790Sstevel@tonic-gate #endif
800Sstevel@tonic-gate 
810Sstevel@tonic-gate /*
820Sstevel@tonic-gate  * This variable contains the file descriptors used for communicating with
830Sstevel@tonic-gate  * the other side.  connection_in is used for reading; connection_out for
840Sstevel@tonic-gate  * writing.  These can be the same descriptor, in which case it is assumed to
850Sstevel@tonic-gate  * be a socket.
860Sstevel@tonic-gate  */
870Sstevel@tonic-gate static int connection_in = -1;
880Sstevel@tonic-gate static int connection_out = -1;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /* Protocol flags for the remote side. */
910Sstevel@tonic-gate static u_int remote_protocol_flags = 0;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /* Encryption context for receiving data.  This is only used for decryption. */
940Sstevel@tonic-gate static CipherContext receive_context;
950Sstevel@tonic-gate 
960Sstevel@tonic-gate /* Encryption context for sending data.  This is only used for encryption. */
970Sstevel@tonic-gate static CipherContext send_context;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /* Buffer for raw input data from the socket. */
1000Sstevel@tonic-gate Buffer input;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /* Buffer for raw output data going to the socket. */
1030Sstevel@tonic-gate Buffer output;
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate /* Buffer for the partial outgoing packet being constructed. */
1060Sstevel@tonic-gate static Buffer outgoing_packet;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /* Buffer for the incoming packet currently being processed. */
1090Sstevel@tonic-gate static Buffer incoming_packet;
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /* Scratch buffer for packet compression/decompression. */
1120Sstevel@tonic-gate static Buffer compression_buffer;
1130Sstevel@tonic-gate static int compression_buffer_ready = 0;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate /* Flag indicating whether packet compression/decompression is enabled. */
1160Sstevel@tonic-gate static int packet_compression = 0;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate /* default maximum packet size */
1190Sstevel@tonic-gate int max_packet_size = 32768;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /* Flag indicating whether this module has been initialized. */
1220Sstevel@tonic-gate static int initialized = 0;
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /* Set to true if the connection is interactive. */
1250Sstevel@tonic-gate static int interactive_mode = 0;
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate /* Session key information for Encryption and MAC */
1280Sstevel@tonic-gate Newkeys *newkeys[MODE_MAX];
1295562Sjp161948 static struct packet_state {
1305562Sjp161948 	u_int32_t seqnr;
1315562Sjp161948 	u_int32_t packets;
1325562Sjp161948 	u_int64_t blocks;
1335562Sjp161948 } p_read, p_send;
1345562Sjp161948 
1355562Sjp161948 static u_int64_t max_blocks_in, max_blocks_out;
1365562Sjp161948 static u_int32_t rekey_limit;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate /* Session key for protocol v1 */
1390Sstevel@tonic-gate static u_char ssh1_key[SSH_SESSION_KEY_LENGTH];
1400Sstevel@tonic-gate static u_int ssh1_keylen;
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate /* roundup current message to extra_pad bytes */
1430Sstevel@tonic-gate static u_char extra_pad = 0;
1440Sstevel@tonic-gate 
1455562Sjp161948 struct packet {
1465562Sjp161948 	TAILQ_ENTRY(packet) next;
1475562Sjp161948 	u_char type;
1485562Sjp161948 	Buffer payload;
1495562Sjp161948 };
1505562Sjp161948 TAILQ_HEAD(, packet) outgoing;
1515562Sjp161948 
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate  * Sets the descriptors used for communication.  Disables encryption until
1540Sstevel@tonic-gate  * packet_set_encryption_key is called.
1550Sstevel@tonic-gate  */
1560Sstevel@tonic-gate void
1570Sstevel@tonic-gate packet_set_connection(int fd_in, int fd_out)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate 	Cipher *none = cipher_by_name("none");
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	if (none == NULL)
1620Sstevel@tonic-gate 		fatal("packet_set_connection: cannot load cipher 'none'");
1630Sstevel@tonic-gate 	connection_in = fd_in;
1640Sstevel@tonic-gate 	connection_out = fd_out;
1650Sstevel@tonic-gate 	cipher_init(&send_context, none, (unsigned char *) "", 0, NULL, 0, CIPHER_ENCRYPT);
1660Sstevel@tonic-gate 	cipher_init(&receive_context, none, (unsigned char *) "", 0, NULL, 0, CIPHER_DECRYPT);
1670Sstevel@tonic-gate 	newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
1680Sstevel@tonic-gate 	if (!initialized) {
1690Sstevel@tonic-gate 		initialized = 1;
1700Sstevel@tonic-gate 		buffer_init(&input);
1710Sstevel@tonic-gate 		buffer_init(&output);
1720Sstevel@tonic-gate 		buffer_init(&outgoing_packet);
1730Sstevel@tonic-gate 		buffer_init(&incoming_packet);
1745562Sjp161948 		TAILQ_INIT(&outgoing);
1750Sstevel@tonic-gate 	} else {
1760Sstevel@tonic-gate 		buffer_clear(&input);
1770Sstevel@tonic-gate 		buffer_clear(&output);
1780Sstevel@tonic-gate 		buffer_clear(&outgoing_packet);
1790Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/*
1830Sstevel@tonic-gate 	 * Prime the cache for get_remote_ipaddr() while we have a
1840Sstevel@tonic-gate 	 * socket on which to do a getpeername().
1850Sstevel@tonic-gate 	 */
1860Sstevel@tonic-gate 	(void) get_remote_ipaddr();
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	/* Kludge: arrange the close function to be called from fatal(). */
1890Sstevel@tonic-gate 	fatal_add_cleanup((void (*) (void *)) packet_close, NULL);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate /* Returns 1 if remote host is connected via socket, 0 if not. */
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate int
1950Sstevel@tonic-gate packet_connection_is_on_socket(void)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	struct sockaddr_storage from, to;
1980Sstevel@tonic-gate 	socklen_t fromlen, tolen;
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/* filedescriptors in and out are the same, so it's a socket */
2010Sstevel@tonic-gate 	if (connection_in != -1 && connection_in == connection_out)
2020Sstevel@tonic-gate 		return 1;
2030Sstevel@tonic-gate 	fromlen = sizeof(from);
2040Sstevel@tonic-gate 	memset(&from, 0, sizeof(from));
2050Sstevel@tonic-gate 	if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0)
2060Sstevel@tonic-gate 		return 0;
2070Sstevel@tonic-gate 	tolen = sizeof(to);
2080Sstevel@tonic-gate 	memset(&to, 0, sizeof(to));
2090Sstevel@tonic-gate 	if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0)
2100Sstevel@tonic-gate 		return 0;
2110Sstevel@tonic-gate 	if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0)
2120Sstevel@tonic-gate 		return 0;
2130Sstevel@tonic-gate 	if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
2140Sstevel@tonic-gate 		return 0;
2150Sstevel@tonic-gate 	return 1;
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /* returns 1 if connection is via ipv4 */
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate int
2210Sstevel@tonic-gate packet_connection_is_ipv4(void)
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate 	struct sockaddr_storage to;
2240Sstevel@tonic-gate 	socklen_t tolen = sizeof(to);
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	memset(&to, 0, sizeof(to));
2270Sstevel@tonic-gate 	if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0)
2280Sstevel@tonic-gate 		return 0;
2290Sstevel@tonic-gate 	if (to.ss_family == AF_INET)
2300Sstevel@tonic-gate 		return 1;
2310Sstevel@tonic-gate #ifdef IPV4_IN_IPV6
2320Sstevel@tonic-gate 	if (to.ss_family == AF_INET6 &&
2330Sstevel@tonic-gate 	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr))
2340Sstevel@tonic-gate 		return 1;
2350Sstevel@tonic-gate #endif
2360Sstevel@tonic-gate 	return 0;
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate /* Sets the connection into non-blocking mode. */
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate void
2420Sstevel@tonic-gate packet_set_nonblocking(void)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	/* Set the socket into non-blocking mode. */
2450Sstevel@tonic-gate 	if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0)
2460Sstevel@tonic-gate 		error("fcntl O_NONBLOCK: %.100s", strerror(errno));
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	if (connection_out != connection_in) {
2490Sstevel@tonic-gate 		if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0)
2500Sstevel@tonic-gate 			error("fcntl O_NONBLOCK: %.100s", strerror(errno));
2510Sstevel@tonic-gate 	}
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate /* Returns the socket used for reading. */
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate int
2570Sstevel@tonic-gate packet_get_connection_in(void)
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 	return connection_in;
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate /* Returns the descriptor used for writing. */
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate int
2650Sstevel@tonic-gate packet_get_connection_out(void)
2660Sstevel@tonic-gate {
2670Sstevel@tonic-gate 	return connection_out;
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate /* Closes the connection and clears and frees internal data structures. */
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate void
2730Sstevel@tonic-gate packet_close(void)
2740Sstevel@tonic-gate {
2750Sstevel@tonic-gate 	if (!initialized)
2760Sstevel@tonic-gate 		return;
2770Sstevel@tonic-gate 	initialized = 0;
2780Sstevel@tonic-gate 	if (connection_in == connection_out) {
2790Sstevel@tonic-gate 		shutdown(connection_out, SHUT_RDWR);
2800Sstevel@tonic-gate 		close(connection_out);
2810Sstevel@tonic-gate 	} else {
2820Sstevel@tonic-gate 		close(connection_in);
2830Sstevel@tonic-gate 		close(connection_out);
2840Sstevel@tonic-gate 	}
2850Sstevel@tonic-gate 	buffer_free(&input);
2860Sstevel@tonic-gate 	buffer_free(&output);
2870Sstevel@tonic-gate 	buffer_free(&outgoing_packet);
2880Sstevel@tonic-gate 	buffer_free(&incoming_packet);
2890Sstevel@tonic-gate 	if (compression_buffer_ready) {
2900Sstevel@tonic-gate 		buffer_free(&compression_buffer);
2910Sstevel@tonic-gate 		buffer_compress_uninit();
2920Sstevel@tonic-gate 		compression_buffer_ready = 0;
2930Sstevel@tonic-gate 	}
2940Sstevel@tonic-gate 	cipher_cleanup(&send_context);
2950Sstevel@tonic-gate 	cipher_cleanup(&receive_context);
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate /* Sets remote side protocol flags. */
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate void
3010Sstevel@tonic-gate packet_set_protocol_flags(u_int protocol_flags)
3020Sstevel@tonic-gate {
3030Sstevel@tonic-gate 	remote_protocol_flags = protocol_flags;
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate /* Returns the remote protocol flags set earlier by the above function. */
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate u_int
3090Sstevel@tonic-gate packet_get_protocol_flags(void)
3100Sstevel@tonic-gate {
3110Sstevel@tonic-gate 	return remote_protocol_flags;
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate /*
3150Sstevel@tonic-gate  * Starts packet compression from the next packet on in both directions.
3160Sstevel@tonic-gate  * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
3170Sstevel@tonic-gate  */
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate static void
3200Sstevel@tonic-gate packet_init_compression(void)
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate 	if (compression_buffer_ready == 1)
3230Sstevel@tonic-gate 		return;
3240Sstevel@tonic-gate 	compression_buffer_ready = 1;
3250Sstevel@tonic-gate 	buffer_init(&compression_buffer);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate void
3290Sstevel@tonic-gate packet_start_compression(int level)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate #ifdef ALTPRIVSEP
3320Sstevel@tonic-gate 	/* shouldn't happen! */
3330Sstevel@tonic-gate 	if (packet_monitor)
3340Sstevel@tonic-gate 		fatal("INTERNAL ERROR: The monitor cannot compress.");
3350Sstevel@tonic-gate #endif /* ALTPRIVSEP */
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	if (packet_compression && !compat20)
3380Sstevel@tonic-gate 		fatal("Compression already enabled.");
3390Sstevel@tonic-gate 	packet_compression = 1;
3400Sstevel@tonic-gate 	packet_init_compression();
3410Sstevel@tonic-gate 	buffer_compress_init_send(level);
3420Sstevel@tonic-gate 	buffer_compress_init_recv();
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate /*
3460Sstevel@tonic-gate  * Causes any further packets to be encrypted using the given key.  The same
3470Sstevel@tonic-gate  * key is used for both sending and reception.  However, both directions are
3480Sstevel@tonic-gate  * encrypted independently of each other.
3490Sstevel@tonic-gate  */
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate void
3520Sstevel@tonic-gate packet_set_encryption_key(const u_char *key, u_int keylen,
3530Sstevel@tonic-gate     int number)
3540Sstevel@tonic-gate {
3550Sstevel@tonic-gate 	Cipher *cipher = cipher_by_number(number);
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	if (cipher == NULL)
3580Sstevel@tonic-gate 		fatal("packet_set_encryption_key: unknown cipher number %d", number);
3590Sstevel@tonic-gate 	if (keylen < 20)
3600Sstevel@tonic-gate 		fatal("packet_set_encryption_key: keylen too small: %d", keylen);
3610Sstevel@tonic-gate 	if (keylen > SSH_SESSION_KEY_LENGTH)
3620Sstevel@tonic-gate 		fatal("packet_set_encryption_key: keylen too big: %d", keylen);
3630Sstevel@tonic-gate 	memcpy(ssh1_key, key, keylen);
3640Sstevel@tonic-gate 	ssh1_keylen = keylen;
3650Sstevel@tonic-gate 	cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT);
3660Sstevel@tonic-gate 	cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT);
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate u_int
3700Sstevel@tonic-gate packet_get_encryption_key(u_char *key)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate 	if (key == NULL)
3730Sstevel@tonic-gate 		return (ssh1_keylen);
3740Sstevel@tonic-gate 	memcpy(key, ssh1_key, ssh1_keylen);
3750Sstevel@tonic-gate 	return (ssh1_keylen);
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate /* Start constructing a packet to send. */
3790Sstevel@tonic-gate void
3800Sstevel@tonic-gate packet_start(u_char type)
3810Sstevel@tonic-gate {
3820Sstevel@tonic-gate 	u_char buf[9];
3830Sstevel@tonic-gate 	int len;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	DBG(debug("packet_start[%d]", type));
3860Sstevel@tonic-gate 	len = compat20 ? 6 : 9;
3870Sstevel@tonic-gate 	memset(buf, 0, len - 1);
3880Sstevel@tonic-gate 	buf[len - 1] = type;
3890Sstevel@tonic-gate 	buffer_clear(&outgoing_packet);
3900Sstevel@tonic-gate 	buffer_append(&outgoing_packet, buf, len);
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate /* Append payload. */
3940Sstevel@tonic-gate void
3950Sstevel@tonic-gate packet_put_char(int value)
3960Sstevel@tonic-gate {
3970Sstevel@tonic-gate 	char ch = value;
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	buffer_append(&outgoing_packet, &ch, 1);
4000Sstevel@tonic-gate }
4015562Sjp161948 
4020Sstevel@tonic-gate void
4030Sstevel@tonic-gate packet_put_int(u_int value)
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate 	buffer_put_int(&outgoing_packet, value);
4060Sstevel@tonic-gate }
4075562Sjp161948 
4080Sstevel@tonic-gate void
4090Sstevel@tonic-gate packet_put_string(const void *buf, u_int len)
4100Sstevel@tonic-gate {
4110Sstevel@tonic-gate 	buffer_put_string(&outgoing_packet, buf, len);
4120Sstevel@tonic-gate }
4135562Sjp161948 
4140Sstevel@tonic-gate void
4150Sstevel@tonic-gate packet_put_cstring(const char *str)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate 	buffer_put_cstring(&outgoing_packet, str);
4180Sstevel@tonic-gate }
4195562Sjp161948 
4200Sstevel@tonic-gate void
4210Sstevel@tonic-gate packet_put_ascii_cstring(const char *str)
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate 	buffer_put_ascii_cstring(&outgoing_packet, str);
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate void
4260Sstevel@tonic-gate packet_put_utf8_cstring(const u_char *str)
4270Sstevel@tonic-gate {
4280Sstevel@tonic-gate 	buffer_put_utf8_cstring(&outgoing_packet, str);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate #if 0
4310Sstevel@tonic-gate void
4320Sstevel@tonic-gate packet_put_ascii_string(const void *buf, u_int len)
4330Sstevel@tonic-gate {
4340Sstevel@tonic-gate 	buffer_put_ascii_string(&outgoing_packet, buf, len);
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate void
4370Sstevel@tonic-gate packet_put_utf8_string(const void *buf, u_int len)
4380Sstevel@tonic-gate {
4390Sstevel@tonic-gate 	buffer_put_utf8_string(&outgoing_packet, buf, len);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate #endif
4420Sstevel@tonic-gate void
4430Sstevel@tonic-gate packet_put_raw(const void *buf, u_int len)
4440Sstevel@tonic-gate {
4450Sstevel@tonic-gate 	buffer_append(&outgoing_packet, buf, len);
4460Sstevel@tonic-gate }
4475562Sjp161948 
4480Sstevel@tonic-gate void
4490Sstevel@tonic-gate packet_put_bignum(BIGNUM * value)
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	buffer_put_bignum(&outgoing_packet, value);
4520Sstevel@tonic-gate }
4535562Sjp161948 
4540Sstevel@tonic-gate void
4550Sstevel@tonic-gate packet_put_bignum2(BIGNUM * value)
4560Sstevel@tonic-gate {
4570Sstevel@tonic-gate 	buffer_put_bignum2(&outgoing_packet, value);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate /*
4610Sstevel@tonic-gate  * Finalizes and sends the packet.  If the encryption key has been set,
4620Sstevel@tonic-gate  * encrypts the packet before sending.
4630Sstevel@tonic-gate  */
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate static void
4660Sstevel@tonic-gate packet_send1(void)
4670Sstevel@tonic-gate {
4680Sstevel@tonic-gate 	u_char buf[8], *cp;
4690Sstevel@tonic-gate 	int i, padding, len;
4700Sstevel@tonic-gate 	u_int checksum;
4715562Sjp161948 	u_int32_t rnd = 0;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	/*
4740Sstevel@tonic-gate 	 * If using packet compression, compress the payload of the outgoing
4750Sstevel@tonic-gate 	 * packet.
4760Sstevel@tonic-gate 	 */
4770Sstevel@tonic-gate 	if (packet_compression) {
4780Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
4790Sstevel@tonic-gate 		/* Skip padding. */
4800Sstevel@tonic-gate 		buffer_consume(&outgoing_packet, 8);
4810Sstevel@tonic-gate 		/* padding */
4820Sstevel@tonic-gate 		buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8);
4830Sstevel@tonic-gate 		buffer_compress(&outgoing_packet, &compression_buffer);
4840Sstevel@tonic-gate 		buffer_clear(&outgoing_packet);
4850Sstevel@tonic-gate 		buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
4860Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
4870Sstevel@tonic-gate 	}
4880Sstevel@tonic-gate 	/* Compute packet length without padding (add checksum, remove padding). */
4890Sstevel@tonic-gate 	len = buffer_len(&outgoing_packet) + 4 - 8;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	/* Insert padding. Initialized to zero in packet_start1() */
4920Sstevel@tonic-gate 	padding = 8 - len % 8;
4930Sstevel@tonic-gate 	if (!send_context.plaintext) {
4940Sstevel@tonic-gate 		cp = buffer_ptr(&outgoing_packet);
4950Sstevel@tonic-gate 		for (i = 0; i < padding; i++) {
4960Sstevel@tonic-gate 			if (i % 4 == 0)
4975562Sjp161948 				rnd = arc4random();
4985562Sjp161948 			cp[7 - i] = rnd & 0xff;
4995562Sjp161948 			rnd >>= 8;
5000Sstevel@tonic-gate 		}
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 	buffer_consume(&outgoing_packet, 8 - padding);
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	/* Add check bytes. */
5050Sstevel@tonic-gate 	checksum = ssh_crc32(buffer_ptr(&outgoing_packet),
5060Sstevel@tonic-gate 	    buffer_len(&outgoing_packet));
5070Sstevel@tonic-gate 	PUT_32BIT(buf, checksum);
5080Sstevel@tonic-gate 	buffer_append(&outgoing_packet, buf, 4);
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate #ifdef PACKET_DEBUG
5110Sstevel@tonic-gate 	fprintf(stderr, "packet_send plain: ");
5120Sstevel@tonic-gate 	buffer_dump(&outgoing_packet);
5130Sstevel@tonic-gate #endif
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	/* Append to output. */
5160Sstevel@tonic-gate 	PUT_32BIT(buf, len);
5170Sstevel@tonic-gate 	buffer_append(&output, buf, 4);
5180Sstevel@tonic-gate 	cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
5190Sstevel@tonic-gate 	cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
5200Sstevel@tonic-gate 	    buffer_len(&outgoing_packet));
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate #ifdef PACKET_DEBUG
5230Sstevel@tonic-gate 	fprintf(stderr, "encrypted: ");
5240Sstevel@tonic-gate 	buffer_dump(&output);
5250Sstevel@tonic-gate #endif
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	buffer_clear(&outgoing_packet);
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	/*
5300Sstevel@tonic-gate 	 * Note that the packet is now only buffered in output.  It won\'t be
5310Sstevel@tonic-gate 	 * actually sent until packet_write_wait or packet_write_poll is
5320Sstevel@tonic-gate 	 * called.
5330Sstevel@tonic-gate 	 */
5340Sstevel@tonic-gate }
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate void
5370Sstevel@tonic-gate set_newkeys(int mode)
5380Sstevel@tonic-gate {
5390Sstevel@tonic-gate 	Enc *enc;
5400Sstevel@tonic-gate 	Mac *mac;
5410Sstevel@tonic-gate 	Comp *comp;
5420Sstevel@tonic-gate 	CipherContext *cc;
5435562Sjp161948 	u_int64_t *max_blocks;
5445562Sjp161948 	int crypt_type;
5450Sstevel@tonic-gate 
5465562Sjp161948 	debug2("set_newkeys: mode %d", mode);
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	if (mode == MODE_OUT) {
5490Sstevel@tonic-gate 		cc = &send_context;
5505562Sjp161948 		crypt_type = CIPHER_ENCRYPT;
5515562Sjp161948 		p_send.packets = p_send.blocks = 0;
5525562Sjp161948 		max_blocks = &max_blocks_out;
5530Sstevel@tonic-gate 	} else {
5540Sstevel@tonic-gate 		cc = &receive_context;
5555562Sjp161948 		crypt_type = CIPHER_DECRYPT;
5565562Sjp161948 		p_read.packets = p_read.blocks = 0;
5575562Sjp161948 		max_blocks = &max_blocks_in;
5580Sstevel@tonic-gate 	}
5590Sstevel@tonic-gate 	if (newkeys[mode] != NULL) {
560*6375Sjp161948 		debug("set_newkeys: setting new keys for '%s' mode",
561*6375Sjp161948 		    mode == MODE_IN ? "in" : "out");
5620Sstevel@tonic-gate 		cipher_cleanup(cc);
5635562Sjp161948 		free_keys(newkeys[mode]);
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 	newkeys[mode] = kex_get_newkeys(mode);
5660Sstevel@tonic-gate 	if (newkeys[mode] == NULL)
5670Sstevel@tonic-gate 		fatal("newkeys: no keys for mode %d", mode);
5680Sstevel@tonic-gate 	enc  = &newkeys[mode]->enc;
5690Sstevel@tonic-gate 	mac  = &newkeys[mode]->mac;
5700Sstevel@tonic-gate 	comp = &newkeys[mode]->comp;
5710Sstevel@tonic-gate 	if (mac->md != NULL)
5720Sstevel@tonic-gate 		mac->enabled = 1;
5730Sstevel@tonic-gate 	DBG(debug("cipher_init_context: %d", mode));
5740Sstevel@tonic-gate 	cipher_init(cc, enc->cipher, enc->key, enc->key_len,
5755562Sjp161948 	    enc->iv, enc->block_size, crypt_type);
5760Sstevel@tonic-gate 	/* Deleting the keys does not gain extra security */
5770Sstevel@tonic-gate 	/* memset(enc->iv,  0, enc->block_size);
5780Sstevel@tonic-gate 	   memset(enc->key, 0, enc->key_len); */
5790Sstevel@tonic-gate 	if (comp->type != 0 && comp->enabled == 0) {
5800Sstevel@tonic-gate 		packet_init_compression();
5810Sstevel@tonic-gate 		if (mode == MODE_OUT)
5820Sstevel@tonic-gate 			buffer_compress_init_send(6);
5830Sstevel@tonic-gate 		else
5840Sstevel@tonic-gate 			buffer_compress_init_recv();
5850Sstevel@tonic-gate 		comp->enabled = 1;
5860Sstevel@tonic-gate 	}
5875562Sjp161948 
5885562Sjp161948 	/*
5895562Sjp161948 	 * In accordance to the RFCs listed below we enforce the key
5905562Sjp161948 	 * re-exchange for:
5915562Sjp161948 	 *
5925562Sjp161948 	 * - every 1GB of transmitted data if the selected cipher block size
5935562Sjp161948 	 *   is less than 16 bytes (3DES, Blowfish)
5945562Sjp161948 	 * - every 2^(2*B) cipher blocks transmitted (B is block size in bytes)
5955562Sjp161948 	 *   if the cipher block size is greater than or equal to 16 bytes (AES)
5965562Sjp161948 	 * - and we never send more than 2^32 SSH packets using the same keys.
5975562Sjp161948 	 *   The recommendation of 2^31 packets is not enforced here but in
5985562Sjp161948 	 *   packet_need_rekeying(). There is also a hard check in
5995562Sjp161948 	 *   packet_send2_wrapped() that we don't send more than 2^32 packets.
6005562Sjp161948 	 *
6015562Sjp161948 	 * Note that if the SSH_BUG_NOREKEY compatibility flag is set then no
6025562Sjp161948 	 * automatic rekeying is performed nor do we enforce the 3rd rule.
6035562Sjp161948 	 * This means that we can be always forced by the opposite side to never
6045562Sjp161948 	 * initiate automatic key re-exchange. This might change in the future.
6055562Sjp161948 	 *
6065562Sjp161948 	 * The RekeyLimit option keyword may only enforce more frequent key
6075562Sjp161948 	 * renegotiation, never less. For more information on key renegotiation,
6085562Sjp161948 	 * see:
6095562Sjp161948 	 *
6105562Sjp161948 	 * - RFC 4253 (SSH Transport Layer Protocol), section "9. Key
6115562Sjp161948 	 *   Re-Exchange"
6125562Sjp161948 	 * - RFC 4344 (SSH Transport Layer Encryption Modes), sections "3.
6135562Sjp161948 	 *   Rekeying" and "6.1 Rekeying Considerations"
6145562Sjp161948 	 */
6155562Sjp161948 	if (enc->block_size >= 16)
6165562Sjp161948 		*max_blocks = (u_int64_t)1 << (enc->block_size * 2);
6175562Sjp161948 	else
6185562Sjp161948 		*max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
6195562Sjp161948 
6205562Sjp161948 	if (rekey_limit)
6215562Sjp161948 		*max_blocks = MIN(*max_blocks, rekey_limit / enc->block_size);
6225562Sjp161948 }
6235562Sjp161948 
6245562Sjp161948 void
6255562Sjp161948 free_keys(Newkeys *keys)
6265562Sjp161948 {
6275562Sjp161948 	Enc *enc;
6285562Sjp161948 	Mac *mac;
6295562Sjp161948 	Comp *comp;
6305562Sjp161948 
6315562Sjp161948 	enc  = &keys->enc;
6325562Sjp161948 	mac  = &keys->mac;
6335562Sjp161948 	comp = &keys->comp;
6345562Sjp161948 	memset(mac->key, 0, mac->key_len);
6355562Sjp161948 	xfree(enc->name);
6365562Sjp161948 	xfree(enc->iv);
6375562Sjp161948 	xfree(enc->key);
6385562Sjp161948 	xfree(mac->name);
6395562Sjp161948 	xfree(mac->key);
6405562Sjp161948 	xfree(comp->name);
6415562Sjp161948 	xfree(keys);
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate /*
6450Sstevel@tonic-gate  * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
6460Sstevel@tonic-gate  */
6470Sstevel@tonic-gate static void
6485562Sjp161948 packet_send2_wrapped(void)
6490Sstevel@tonic-gate {
6500Sstevel@tonic-gate 	u_char type, *cp, *macbuf = NULL;
6510Sstevel@tonic-gate 	u_char padlen, pad;
6520Sstevel@tonic-gate 	u_int packet_length = 0;
6530Sstevel@tonic-gate 	u_int i, len;
6545562Sjp161948 	u_int32_t rnd = 0;
6550Sstevel@tonic-gate 	Enc *enc   = NULL;
6560Sstevel@tonic-gate 	Mac *mac   = NULL;
6570Sstevel@tonic-gate 	Comp *comp = NULL;
6580Sstevel@tonic-gate 	int block_size;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	if (newkeys[MODE_OUT] != NULL) {
6610Sstevel@tonic-gate 		enc  = &newkeys[MODE_OUT]->enc;
6620Sstevel@tonic-gate 		mac  = &newkeys[MODE_OUT]->mac;
6630Sstevel@tonic-gate 		comp = &newkeys[MODE_OUT]->comp;
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate 	block_size = enc ? enc->block_size : 8;
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	cp = buffer_ptr(&outgoing_packet);
6680Sstevel@tonic-gate 	type = cp[5];
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate #ifdef PACKET_DEBUG
6710Sstevel@tonic-gate 	fprintf(stderr, "plain:     ");
6720Sstevel@tonic-gate 	buffer_dump(&outgoing_packet);
6730Sstevel@tonic-gate #endif
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	if (comp && comp->enabled) {
6760Sstevel@tonic-gate 		len = buffer_len(&outgoing_packet);
6770Sstevel@tonic-gate 		/* skip header, compress only payload */
6780Sstevel@tonic-gate 		buffer_consume(&outgoing_packet, 5);
6790Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
6800Sstevel@tonic-gate 		buffer_compress(&outgoing_packet, &compression_buffer);
6810Sstevel@tonic-gate 		buffer_clear(&outgoing_packet);
6820Sstevel@tonic-gate 		buffer_append(&outgoing_packet, "\0\0\0\0\0", 5);
6830Sstevel@tonic-gate 		buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
6840Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
6850Sstevel@tonic-gate 		DBG(debug("compression: raw %d compressed %d", len,
6860Sstevel@tonic-gate 		    buffer_len(&outgoing_packet)));
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	/* sizeof (packet_len + pad_len + payload) */
6900Sstevel@tonic-gate 	len = buffer_len(&outgoing_packet);
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	/*
6930Sstevel@tonic-gate 	 * calc size of padding, alloc space, get random data,
6940Sstevel@tonic-gate 	 * minimum padding is 4 bytes
6950Sstevel@tonic-gate 	 */
6960Sstevel@tonic-gate 	padlen = block_size - (len % block_size);
6970Sstevel@tonic-gate 	if (padlen < 4)
6980Sstevel@tonic-gate 		padlen += block_size;
6990Sstevel@tonic-gate 	if (extra_pad) {
7000Sstevel@tonic-gate 		/* will wrap if extra_pad+padlen > 255 */
7010Sstevel@tonic-gate 		extra_pad  = roundup(extra_pad, block_size);
7020Sstevel@tonic-gate 		pad = extra_pad - ((len + padlen) % extra_pad);
7030Sstevel@tonic-gate 		debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)",
7040Sstevel@tonic-gate 		    pad, len, padlen, extra_pad);
7050Sstevel@tonic-gate 		padlen += pad;
7060Sstevel@tonic-gate 		extra_pad = 0;
7070Sstevel@tonic-gate 	}
7080Sstevel@tonic-gate 	cp = buffer_append_space(&outgoing_packet, padlen);
7090Sstevel@tonic-gate 	if (enc && !send_context.plaintext) {
7100Sstevel@tonic-gate 		/* random padding */
7110Sstevel@tonic-gate 		for (i = 0; i < padlen; i++) {
7120Sstevel@tonic-gate 			if (i % 4 == 0)
7135562Sjp161948 				rnd = arc4random();
7145562Sjp161948 			cp[i] = rnd & 0xff;
7155562Sjp161948 			rnd >>= 8;
7160Sstevel@tonic-gate 		}
7170Sstevel@tonic-gate 	} else {
7180Sstevel@tonic-gate 		/* clear padding */
7190Sstevel@tonic-gate 		memset(cp, 0, padlen);
7200Sstevel@tonic-gate 	}
7210Sstevel@tonic-gate 	/* packet_length includes payload, padding and padding length field */
7220Sstevel@tonic-gate 	packet_length = buffer_len(&outgoing_packet) - 4;
7230Sstevel@tonic-gate 	cp = buffer_ptr(&outgoing_packet);
7240Sstevel@tonic-gate 	PUT_32BIT(cp, packet_length);
7250Sstevel@tonic-gate 	cp[4] = padlen;
7260Sstevel@tonic-gate 	DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen));
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	/* compute MAC over seqnr and packet(length fields, payload, padding) */
7290Sstevel@tonic-gate 	if (mac && mac->enabled) {
7305562Sjp161948 		macbuf = mac_compute(mac, p_send.seqnr,
7310Sstevel@tonic-gate 		    buffer_ptr(&outgoing_packet),
7320Sstevel@tonic-gate 		    buffer_len(&outgoing_packet));
7335562Sjp161948 		DBG(debug("done calc MAC out #%d", p_send.seqnr));
7340Sstevel@tonic-gate 	}
7350Sstevel@tonic-gate 	/* encrypt packet and append to output buffer. */
7360Sstevel@tonic-gate 	cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
7370Sstevel@tonic-gate 	cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
7380Sstevel@tonic-gate 	    buffer_len(&outgoing_packet));
7390Sstevel@tonic-gate 	/* append unencrypted MAC */
7400Sstevel@tonic-gate 	if (mac && mac->enabled)
7410Sstevel@tonic-gate 		buffer_append(&output, (char *)macbuf, mac->mac_len);
7420Sstevel@tonic-gate #ifdef PACKET_DEBUG
7430Sstevel@tonic-gate 	fprintf(stderr, "encrypted: ");
7440Sstevel@tonic-gate 	buffer_dump(&output);
7450Sstevel@tonic-gate #endif
7460Sstevel@tonic-gate 	/* increment sequence number for outgoing packets */
7475562Sjp161948 	if (++p_send.seqnr == 0)
7480Sstevel@tonic-gate 		log("outgoing seqnr wraps around");
7495562Sjp161948 
7505562Sjp161948 	/*
7515562Sjp161948 	 * RFC 4344: 3.1. First Rekeying Recommendation
7525562Sjp161948 	 *
7535562Sjp161948 	 * "Because of possible information leakage through the MAC tag after a
7545562Sjp161948 	 * key exchange, .... an SSH implementation SHOULD NOT send more than
7555562Sjp161948 	 * 2**32 packets before rekeying again."
7565562Sjp161948 	 *
7575562Sjp161948 	 * The code below is a hard check so that we are sure we don't go across
7585562Sjp161948 	 * the suggestion. However, since the largest cipher block size we have
7595562Sjp161948 	 * (AES) is 16 bytes we can't reach 2^32 SSH packets encrypted with the
7605562Sjp161948 	 * same key while performing periodic rekeying.
7615562Sjp161948 	 */
7625562Sjp161948 	if (++p_send.packets == 0)
7635562Sjp161948 		if (!(datafellows & SSH_BUG_NOREKEY))
7645562Sjp161948 			fatal("too many packets encrypted with same key");
7655562Sjp161948 	p_send.blocks += (packet_length + 4) / block_size;
7660Sstevel@tonic-gate 	buffer_clear(&outgoing_packet);
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	if (type == SSH2_MSG_NEWKEYS)
7690Sstevel@tonic-gate #ifdef ALTPRIVSEP
7700Sstevel@tonic-gate 		/* set_newkeys(MODE_OUT) in client, server, but not monitor */
7710Sstevel@tonic-gate 		if (!packet_is_server() && !packet_is_monitor())
7720Sstevel@tonic-gate #endif /* ALTPRIVSEP */
7730Sstevel@tonic-gate 		set_newkeys(MODE_OUT);
7740Sstevel@tonic-gate }
7750Sstevel@tonic-gate 
7765562Sjp161948 static void
7775562Sjp161948 packet_send2(void)
7785562Sjp161948 {
7795562Sjp161948 	static int rekeying = 0;
7805562Sjp161948 	struct packet *p;
7815562Sjp161948 	u_char type, *cp;
7825562Sjp161948 
7835562Sjp161948 	cp = buffer_ptr(&outgoing_packet);
7845562Sjp161948 	type = cp[5];
7855562Sjp161948 
7865562Sjp161948 	/* during rekeying we can only send key exchange messages */
7875562Sjp161948 	if (rekeying) {
7885562Sjp161948 		if (!((type >= SSH2_MSG_TRANSPORT_MIN) &&
7895562Sjp161948 		    (type <= SSH2_MSG_TRANSPORT_MAX))) {
7905562Sjp161948 			debug("enqueue packet: %u", type);
7915562Sjp161948 			p = xmalloc(sizeof(*p));
7925562Sjp161948 			p->type = type;
7935562Sjp161948 			memcpy(&p->payload, &outgoing_packet, sizeof(Buffer));
7945562Sjp161948 			buffer_init(&outgoing_packet);
7955562Sjp161948 			TAILQ_INSERT_TAIL(&outgoing, p, next);
7965562Sjp161948 			return;
7975562Sjp161948 		}
7985562Sjp161948 	}
7995562Sjp161948 
8005562Sjp161948 	/* rekeying starts with sending KEXINIT */
8015562Sjp161948 	if (type == SSH2_MSG_KEXINIT)
8025562Sjp161948 		rekeying = 1;
8035562Sjp161948 
8045562Sjp161948 	packet_send2_wrapped();
8055562Sjp161948 
8065562Sjp161948 	/* after a NEWKEYS message we can send the complete queue */
8075562Sjp161948 	if (type == SSH2_MSG_NEWKEYS) {
8085562Sjp161948 		rekeying = 0;
8095562Sjp161948 		while ((p = TAILQ_FIRST(&outgoing)) != NULL) {
8105562Sjp161948 			type = p->type;
8115562Sjp161948 			debug("dequeue packet: %u", type);
8125562Sjp161948 			buffer_free(&outgoing_packet);
8135562Sjp161948 			memcpy(&outgoing_packet, &p->payload, sizeof(Buffer));
8145562Sjp161948 			TAILQ_REMOVE(&outgoing, p, next);
8155562Sjp161948 			xfree(p);
8165562Sjp161948 			packet_send2_wrapped();
8175562Sjp161948 		}
8185562Sjp161948 	}
8195562Sjp161948 }
8205562Sjp161948 
8210Sstevel@tonic-gate void
8220Sstevel@tonic-gate packet_send(void)
8230Sstevel@tonic-gate {
8240Sstevel@tonic-gate 	if (compat20)
8250Sstevel@tonic-gate 		packet_send2();
8260Sstevel@tonic-gate 	else
8270Sstevel@tonic-gate 		packet_send1();
8280Sstevel@tonic-gate 	DBG(debug("packet_send done"));
8290Sstevel@tonic-gate }
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate /*
8320Sstevel@tonic-gate  * Waits until a packet has been received, and returns its type.  Note that
8330Sstevel@tonic-gate  * no other data is processed until this returns, so this function should not
8340Sstevel@tonic-gate  * be used during the interactive session.
8350Sstevel@tonic-gate  */
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate int
8380Sstevel@tonic-gate packet_read_seqnr(u_int32_t *seqnr_p)
8390Sstevel@tonic-gate {
8400Sstevel@tonic-gate 	int type, len;
8410Sstevel@tonic-gate 	fd_set *setp;
8420Sstevel@tonic-gate 	char buf[8192];
8430Sstevel@tonic-gate 	DBG(debug("packet_read()"));
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) *
8460Sstevel@tonic-gate 	    sizeof(fd_mask));
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	/* Since we are blocking, ensure that all written packets have been sent. */
8490Sstevel@tonic-gate 	packet_write_wait();
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	/* Stay in the loop until we have received a complete packet. */
8520Sstevel@tonic-gate 	for (;;) {
8530Sstevel@tonic-gate 		/* Try to read a packet from the buffer. */
8540Sstevel@tonic-gate 		type = packet_read_poll_seqnr(seqnr_p);
8550Sstevel@tonic-gate 		if (!compat20 && (
8560Sstevel@tonic-gate 		    type == SSH_SMSG_SUCCESS
8570Sstevel@tonic-gate 		    || type == SSH_SMSG_FAILURE
8580Sstevel@tonic-gate 		    || type == SSH_CMSG_EOF
8590Sstevel@tonic-gate 		    || type == SSH_CMSG_EXIT_CONFIRMATION))
8600Sstevel@tonic-gate 			packet_check_eom();
8610Sstevel@tonic-gate 		/* If we got a packet, return it. */
8620Sstevel@tonic-gate 		if (type != SSH_MSG_NONE) {
8630Sstevel@tonic-gate 			xfree(setp);
8640Sstevel@tonic-gate 			return type;
8650Sstevel@tonic-gate 		}
8660Sstevel@tonic-gate 		/*
8670Sstevel@tonic-gate 		 * Otherwise, wait for some data to arrive, add it to the
8680Sstevel@tonic-gate 		 * buffer, and try again.
8690Sstevel@tonic-gate 		 */
8700Sstevel@tonic-gate 		memset(setp, 0, howmany(connection_in + 1, NFDBITS) *
8710Sstevel@tonic-gate 		    sizeof(fd_mask));
8720Sstevel@tonic-gate 		FD_SET(connection_in, setp);
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 		/* Wait for some data to arrive. */
8750Sstevel@tonic-gate 		while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
8760Sstevel@tonic-gate 		    (errno == EAGAIN || errno == EINTR))
8770Sstevel@tonic-gate 			;
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 		/* Read data from the socket. */
8800Sstevel@tonic-gate 		len = read(connection_in, buf, sizeof(buf));
8810Sstevel@tonic-gate 		if (len == 0) {
8820Sstevel@tonic-gate 			log("Connection closed by %.200s", get_remote_ipaddr());
8830Sstevel@tonic-gate 			fatal_cleanup();
8840Sstevel@tonic-gate 		}
8850Sstevel@tonic-gate 		if (len < 0)
8860Sstevel@tonic-gate 			fatal("Read from socket failed: %.100s", strerror(errno));
8870Sstevel@tonic-gate 		/* Append it to the buffer. */
8880Sstevel@tonic-gate 		packet_process_incoming(buf, len);
8890Sstevel@tonic-gate 	}
8900Sstevel@tonic-gate 	/* NOTREACHED */
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate int
8940Sstevel@tonic-gate packet_read(void)
8950Sstevel@tonic-gate {
8960Sstevel@tonic-gate 	return packet_read_seqnr(NULL);
8970Sstevel@tonic-gate }
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate /*
9000Sstevel@tonic-gate  * Waits until a packet has been received, verifies that its type matches
9010Sstevel@tonic-gate  * that given, and gives a fatal error and exits if there is a mismatch.
9020Sstevel@tonic-gate  */
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate void
9050Sstevel@tonic-gate packet_read_expect(int expected_type)
9060Sstevel@tonic-gate {
9070Sstevel@tonic-gate 	int type;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	type = packet_read();
9100Sstevel@tonic-gate 	if (type != expected_type)
9110Sstevel@tonic-gate 		packet_disconnect("Protocol error: expected packet type %d, got %d",
9120Sstevel@tonic-gate 		    expected_type, type);
9130Sstevel@tonic-gate }
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate /* Checks if a full packet is available in the data received so far via
9160Sstevel@tonic-gate  * packet_process_incoming.  If so, reads the packet; otherwise returns
9170Sstevel@tonic-gate  * SSH_MSG_NONE.  This does not wait for data from the connection.
9180Sstevel@tonic-gate  *
9190Sstevel@tonic-gate  * SSH_MSG_DISCONNECT is handled specially here.  Also,
9200Sstevel@tonic-gate  * SSH_MSG_IGNORE messages are skipped by this function and are never returned
9210Sstevel@tonic-gate  * to higher levels.
9220Sstevel@tonic-gate  */
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate static int
9250Sstevel@tonic-gate packet_read_poll1(void)
9260Sstevel@tonic-gate {
9270Sstevel@tonic-gate 	u_int len, padded_len;
9280Sstevel@tonic-gate 	u_char *cp, type;
9290Sstevel@tonic-gate 	u_int checksum, stored_checksum;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	/* Check if input size is less than minimum packet size. */
9320Sstevel@tonic-gate 	if (buffer_len(&input) < 4 + 8)
9330Sstevel@tonic-gate 		return SSH_MSG_NONE;
9340Sstevel@tonic-gate 	/* Get length of incoming packet. */
9350Sstevel@tonic-gate 	cp = buffer_ptr(&input);
9360Sstevel@tonic-gate 	len = GET_32BIT(cp);
9370Sstevel@tonic-gate 	if (len < 1 + 2 + 2 || len > 256 * 1024)
9380Sstevel@tonic-gate 		packet_disconnect("Bad packet length %d.", len);
9390Sstevel@tonic-gate 	padded_len = (len + 8) & ~7;
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	/* Check if the packet has been entirely received. */
9420Sstevel@tonic-gate 	if (buffer_len(&input) < 4 + padded_len)
9430Sstevel@tonic-gate 		return SSH_MSG_NONE;
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	/* The entire packet is in buffer. */
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	/* Consume packet length. */
9480Sstevel@tonic-gate 	buffer_consume(&input, 4);
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	/*
9510Sstevel@tonic-gate 	 * Cryptographic attack detector for ssh
9520Sstevel@tonic-gate 	 * (C)1998 CORE-SDI, Buenos Aires Argentina
9530Sstevel@tonic-gate 	 * Ariel Futoransky(futo@core-sdi.com)
9540Sstevel@tonic-gate 	 */
9553102Sjp161948 	if (!receive_context.plaintext) {
9563102Sjp161948 		switch (detect_attack(buffer_ptr(&input), padded_len, NULL)) {
9573102Sjp161948 		case DEATTACK_DETECTED:
9583102Sjp161948 			packet_disconnect("crc32 compensation attack: "
9593102Sjp161948 			    "network attack detected");
9603102Sjp161948 			break;
9613102Sjp161948 		case DEATTACK_DOS_DETECTED:
9623102Sjp161948 			packet_disconnect("deattack denial of "
9633102Sjp161948 			    "service detected");
9643102Sjp161948 			break;
9653102Sjp161948 		}
9663102Sjp161948 	}
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	/* Decrypt data to incoming_packet. */
9690Sstevel@tonic-gate 	buffer_clear(&incoming_packet);
9700Sstevel@tonic-gate 	cp = buffer_append_space(&incoming_packet, padded_len);
9710Sstevel@tonic-gate 	cipher_crypt(&receive_context, cp, buffer_ptr(&input), padded_len);
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	buffer_consume(&input, padded_len);
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate #ifdef PACKET_DEBUG
9760Sstevel@tonic-gate 	fprintf(stderr, "read_poll plain: ");
9770Sstevel@tonic-gate 	buffer_dump(&incoming_packet);
9780Sstevel@tonic-gate #endif
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	/* Compute packet checksum. */
9810Sstevel@tonic-gate 	checksum = ssh_crc32(buffer_ptr(&incoming_packet),
9820Sstevel@tonic-gate 	    buffer_len(&incoming_packet) - 4);
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	/* Skip padding. */
9850Sstevel@tonic-gate 	buffer_consume(&incoming_packet, 8 - len % 8);
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	/* Test check bytes. */
9880Sstevel@tonic-gate 	if (len != buffer_len(&incoming_packet))
9890Sstevel@tonic-gate 		packet_disconnect("packet_read_poll1: len %d != buffer_len %d.",
9900Sstevel@tonic-gate 		    len, buffer_len(&incoming_packet));
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4;
9930Sstevel@tonic-gate 	stored_checksum = GET_32BIT(cp);
9940Sstevel@tonic-gate 	if (checksum != stored_checksum)
9950Sstevel@tonic-gate 		packet_disconnect("Corrupted check bytes on input.");
9960Sstevel@tonic-gate 	buffer_consume_end(&incoming_packet, 4);
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	if (packet_compression) {
9990Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
10000Sstevel@tonic-gate 		buffer_uncompress(&incoming_packet, &compression_buffer);
10010Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
10020Sstevel@tonic-gate 		buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
10030Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
10040Sstevel@tonic-gate 	}
10050Sstevel@tonic-gate 	type = buffer_get_char(&incoming_packet);
10060Sstevel@tonic-gate 	return type;
10070Sstevel@tonic-gate }
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate static int
10100Sstevel@tonic-gate packet_read_poll2(u_int32_t *seqnr_p)
10110Sstevel@tonic-gate {
10120Sstevel@tonic-gate 	static u_int packet_length = 0;
10130Sstevel@tonic-gate 	u_int padlen, need;
10140Sstevel@tonic-gate 	u_char *macbuf, *cp, type;
10150Sstevel@tonic-gate 	int maclen, block_size;
10160Sstevel@tonic-gate 	Enc *enc   = NULL;
10170Sstevel@tonic-gate 	Mac *mac   = NULL;
10180Sstevel@tonic-gate 	Comp *comp = NULL;
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 	if (newkeys[MODE_IN] != NULL) {
10210Sstevel@tonic-gate 		enc  = &newkeys[MODE_IN]->enc;
10220Sstevel@tonic-gate 		mac  = &newkeys[MODE_IN]->mac;
10230Sstevel@tonic-gate 		comp = &newkeys[MODE_IN]->comp;
10240Sstevel@tonic-gate 	}
10250Sstevel@tonic-gate 	maclen = mac && mac->enabled ? mac->mac_len : 0;
10260Sstevel@tonic-gate 	block_size = enc ? enc->block_size : 8;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	if (packet_length == 0) {
10290Sstevel@tonic-gate 		/*
10300Sstevel@tonic-gate 		 * check if input size is less than the cipher block size,
10310Sstevel@tonic-gate 		 * decrypt first block and extract length of incoming packet
10320Sstevel@tonic-gate 		 */
10330Sstevel@tonic-gate 		if (buffer_len(&input) < block_size)
10340Sstevel@tonic-gate 			return SSH_MSG_NONE;
10350Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
10360Sstevel@tonic-gate 		cp = buffer_append_space(&incoming_packet, block_size);
10370Sstevel@tonic-gate 		cipher_crypt(&receive_context, cp, buffer_ptr(&input),
10380Sstevel@tonic-gate 		    block_size);
10390Sstevel@tonic-gate 		cp = buffer_ptr(&incoming_packet);
10400Sstevel@tonic-gate 		packet_length = GET_32BIT(cp);
10410Sstevel@tonic-gate 		if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
10420Sstevel@tonic-gate 			buffer_dump(&incoming_packet);
10430Sstevel@tonic-gate 			packet_disconnect("Bad packet length %d.", packet_length);
10440Sstevel@tonic-gate 		}
10455562Sjp161948 		DBG(debug("input: packet len %u", packet_length + 4));
10460Sstevel@tonic-gate 		buffer_consume(&input, block_size);
10470Sstevel@tonic-gate 	}
10480Sstevel@tonic-gate 	/* we have a partial packet of block_size bytes */
10490Sstevel@tonic-gate 	need = 4 + packet_length - block_size;
10500Sstevel@tonic-gate 	DBG(debug("partial packet %d, need %d, maclen %d", block_size,
10510Sstevel@tonic-gate 	    need, maclen));
10520Sstevel@tonic-gate 	if (need % block_size != 0)
10530Sstevel@tonic-gate 		fatal("padding error: need %d block %d mod %d",
10540Sstevel@tonic-gate 		    need, block_size, need % block_size);
10550Sstevel@tonic-gate 	/*
10560Sstevel@tonic-gate 	 * check if the entire packet has been received and
10570Sstevel@tonic-gate 	 * decrypt into incoming_packet
10580Sstevel@tonic-gate 	 */
10590Sstevel@tonic-gate 	if (buffer_len(&input) < need + maclen)
10600Sstevel@tonic-gate 		return SSH_MSG_NONE;
10610Sstevel@tonic-gate #ifdef PACKET_DEBUG
10620Sstevel@tonic-gate 	fprintf(stderr, "read_poll enc/full: ");
10630Sstevel@tonic-gate 	buffer_dump(&input);
10640Sstevel@tonic-gate #endif
10650Sstevel@tonic-gate 	cp = buffer_append_space(&incoming_packet, need);
10660Sstevel@tonic-gate 	cipher_crypt(&receive_context, cp, buffer_ptr(&input), need);
10670Sstevel@tonic-gate 	buffer_consume(&input, need);
10680Sstevel@tonic-gate 	/*
10690Sstevel@tonic-gate 	 * compute MAC over seqnr and packet,
10700Sstevel@tonic-gate 	 * increment sequence number for incoming packet
10710Sstevel@tonic-gate 	 */
10720Sstevel@tonic-gate 	if (mac && mac->enabled) {
10735562Sjp161948 		macbuf = mac_compute(mac, p_read.seqnr,
10740Sstevel@tonic-gate 		    buffer_ptr(&incoming_packet),
10750Sstevel@tonic-gate 		    buffer_len(&incoming_packet));
10760Sstevel@tonic-gate 		if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
10770Sstevel@tonic-gate 			packet_disconnect("Corrupted MAC on input.");
10785562Sjp161948 		DBG(debug("MAC #%d ok", p_read.seqnr));
10790Sstevel@tonic-gate 		buffer_consume(&input, mac->mac_len);
10800Sstevel@tonic-gate 	}
10810Sstevel@tonic-gate 	if (seqnr_p != NULL)
10825562Sjp161948 		*seqnr_p = p_read.seqnr;
10835562Sjp161948 	if (++p_read.seqnr == 0)
10840Sstevel@tonic-gate 		log("incoming seqnr wraps around");
10850Sstevel@tonic-gate 
10865562Sjp161948 	/* see above for the comment on "First Rekeying Recommendation" */
10875562Sjp161948 	if (++p_read.packets == 0)
10885562Sjp161948 		if (!(datafellows & SSH_BUG_NOREKEY))
10895562Sjp161948 			fatal("too many packets with same key");
10905562Sjp161948 	p_read.blocks += (packet_length + 4) / block_size;
10915562Sjp161948 
10920Sstevel@tonic-gate 	/* get padlen */
10930Sstevel@tonic-gate 	cp = buffer_ptr(&incoming_packet);
10940Sstevel@tonic-gate 	padlen = cp[4];
10950Sstevel@tonic-gate 	DBG(debug("input: padlen %d", padlen));
10960Sstevel@tonic-gate 	if (padlen < 4)
10970Sstevel@tonic-gate 		packet_disconnect("Corrupted padlen %d on input.", padlen);
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 	/* skip packet size + padlen, discard padding */
11000Sstevel@tonic-gate 	buffer_consume(&incoming_packet, 4 + 1);
11010Sstevel@tonic-gate 	buffer_consume_end(&incoming_packet, padlen);
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet)));
11040Sstevel@tonic-gate 	if (comp && comp->enabled) {
11050Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
11060Sstevel@tonic-gate 		buffer_uncompress(&incoming_packet, &compression_buffer);
11070Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
11080Sstevel@tonic-gate 		buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
11090Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
11100Sstevel@tonic-gate 		DBG(debug("input: len after de-compress %d",
11110Sstevel@tonic-gate 		    buffer_len(&incoming_packet)));
11120Sstevel@tonic-gate 	}
11130Sstevel@tonic-gate 	/*
11140Sstevel@tonic-gate 	 * get packet type, implies consume.
11150Sstevel@tonic-gate 	 * return length of payload (without type field)
11160Sstevel@tonic-gate 	 */
11170Sstevel@tonic-gate 	type = buffer_get_char(&incoming_packet);
11180Sstevel@tonic-gate #ifdef ALTPRIVSEP
11190Sstevel@tonic-gate 	if (type == SSH2_MSG_NEWKEYS)
11200Sstevel@tonic-gate 		/* set_newkeys(MODE_OUT) in client, server, but not monitor */
11210Sstevel@tonic-gate 		if (!packet_is_server() && !packet_is_monitor())
11220Sstevel@tonic-gate 			set_newkeys(MODE_IN);
11230Sstevel@tonic-gate #else /* ALTPRIVSEP */
11240Sstevel@tonic-gate 	if (type == SSH2_MSG_NEWKEYS)
11250Sstevel@tonic-gate 		set_newkeys(MODE_IN);
11260Sstevel@tonic-gate #endif /* ALTPRIVSEP */
11270Sstevel@tonic-gate #ifdef PACKET_DEBUG
11280Sstevel@tonic-gate 	fprintf(stderr, "read/plain[%d]:\r\n", type);
11290Sstevel@tonic-gate 	buffer_dump(&incoming_packet);
11300Sstevel@tonic-gate #endif
11310Sstevel@tonic-gate 	/* reset for next packet */
11320Sstevel@tonic-gate 	packet_length = 0;
11330Sstevel@tonic-gate 	return type;
11340Sstevel@tonic-gate }
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate int
11370Sstevel@tonic-gate packet_read_poll_seqnr(u_int32_t *seqnr_p)
11380Sstevel@tonic-gate {
11390Sstevel@tonic-gate 	u_int reason, seqnr;
11400Sstevel@tonic-gate 	u_char type;
11410Sstevel@tonic-gate 	char *msg;
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	for (;;) {
11440Sstevel@tonic-gate 		if (compat20) {
11450Sstevel@tonic-gate 			type = packet_read_poll2(seqnr_p);
11460Sstevel@tonic-gate 			DBG(debug("received packet type %d", type));
11470Sstevel@tonic-gate 			switch (type) {
11480Sstevel@tonic-gate 			case SSH2_MSG_IGNORE:
11490Sstevel@tonic-gate 				break;
11500Sstevel@tonic-gate 			case SSH2_MSG_DEBUG:
11510Sstevel@tonic-gate 				packet_get_char();
11520Sstevel@tonic-gate 				msg = packet_get_string(NULL);
11530Sstevel@tonic-gate 				debug("Remote: %.900s", msg);
11540Sstevel@tonic-gate 				xfree(msg);
11550Sstevel@tonic-gate 				msg = packet_get_string(NULL);
11560Sstevel@tonic-gate 				xfree(msg);
11570Sstevel@tonic-gate 				break;
11580Sstevel@tonic-gate 			case SSH2_MSG_DISCONNECT:
11590Sstevel@tonic-gate 				reason = packet_get_int();
11600Sstevel@tonic-gate 				msg = packet_get_string(NULL);
11610Sstevel@tonic-gate 				log("Received disconnect from %s: %u: %.400s",
11620Sstevel@tonic-gate 				    get_remote_ipaddr(), reason, msg);
11630Sstevel@tonic-gate 				xfree(msg);
11640Sstevel@tonic-gate 				fatal_cleanup();
11650Sstevel@tonic-gate 				break;
11660Sstevel@tonic-gate 			case SSH2_MSG_UNIMPLEMENTED:
11670Sstevel@tonic-gate 				seqnr = packet_get_int();
11680Sstevel@tonic-gate 				debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
11690Sstevel@tonic-gate 				    seqnr);
11700Sstevel@tonic-gate 				break;
11710Sstevel@tonic-gate 			default:
11720Sstevel@tonic-gate 				return type;
11730Sstevel@tonic-gate 				break;
11740Sstevel@tonic-gate 			}
11750Sstevel@tonic-gate 		} else {
11760Sstevel@tonic-gate 			type = packet_read_poll1();
11770Sstevel@tonic-gate 			DBG(debug("received packet type %d", type));
11780Sstevel@tonic-gate 			switch (type) {
11790Sstevel@tonic-gate 			case SSH_MSG_IGNORE:
11800Sstevel@tonic-gate 				break;
11810Sstevel@tonic-gate 			case SSH_MSG_DEBUG:
11820Sstevel@tonic-gate 				msg = packet_get_string(NULL);
11830Sstevel@tonic-gate 				debug("Remote: %.900s", msg);
11840Sstevel@tonic-gate 				xfree(msg);
11850Sstevel@tonic-gate 				break;
11860Sstevel@tonic-gate 			case SSH_MSG_DISCONNECT:
11870Sstevel@tonic-gate 				msg = packet_get_string(NULL);
11880Sstevel@tonic-gate 				log("Received disconnect from %s: %.400s",
11890Sstevel@tonic-gate 				    get_remote_ipaddr(), msg);
11900Sstevel@tonic-gate 				fatal_cleanup();
11910Sstevel@tonic-gate 				xfree(msg);
11920Sstevel@tonic-gate 				break;
11930Sstevel@tonic-gate 			default:
11940Sstevel@tonic-gate 				return type;
11950Sstevel@tonic-gate 				break;
11960Sstevel@tonic-gate 			}
11970Sstevel@tonic-gate 		}
11980Sstevel@tonic-gate 	}
11990Sstevel@tonic-gate }
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate int
12020Sstevel@tonic-gate packet_read_poll(void)
12030Sstevel@tonic-gate {
12040Sstevel@tonic-gate 	return packet_read_poll_seqnr(NULL);
12050Sstevel@tonic-gate }
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate /*
12080Sstevel@tonic-gate  * Buffers the given amount of input characters.  This is intended to be used
12090Sstevel@tonic-gate  * together with packet_read_poll.
12100Sstevel@tonic-gate  */
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate void
12130Sstevel@tonic-gate packet_process_incoming(const char *buf, u_int len)
12140Sstevel@tonic-gate {
12150Sstevel@tonic-gate 	buffer_append(&input, buf, len);
12160Sstevel@tonic-gate }
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate /* Returns a character from the packet. */
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate u_int
12210Sstevel@tonic-gate packet_get_char(void)
12220Sstevel@tonic-gate {
12230Sstevel@tonic-gate 	char ch;
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	buffer_get(&incoming_packet, &ch, 1);
12260Sstevel@tonic-gate 	return (u_char) ch;
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate /* Returns an integer from the packet data. */
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate u_int
12320Sstevel@tonic-gate packet_get_int(void)
12330Sstevel@tonic-gate {
12340Sstevel@tonic-gate 	return buffer_get_int(&incoming_packet);
12350Sstevel@tonic-gate }
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate /*
12380Sstevel@tonic-gate  * Returns an arbitrary precision integer from the packet data.  The integer
12390Sstevel@tonic-gate  * must have been initialized before this call.
12400Sstevel@tonic-gate  */
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate void
12430Sstevel@tonic-gate packet_get_bignum(BIGNUM * value)
12440Sstevel@tonic-gate {
12450Sstevel@tonic-gate 	buffer_get_bignum(&incoming_packet, value);
12460Sstevel@tonic-gate }
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate void
12490Sstevel@tonic-gate packet_get_bignum2(BIGNUM * value)
12500Sstevel@tonic-gate {
12510Sstevel@tonic-gate 	buffer_get_bignum2(&incoming_packet, value);
12520Sstevel@tonic-gate }
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate void *
12550Sstevel@tonic-gate packet_get_raw(u_int *length_ptr)
12560Sstevel@tonic-gate {
12570Sstevel@tonic-gate 	u_int bytes = buffer_len(&incoming_packet);
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	if (length_ptr != NULL)
12600Sstevel@tonic-gate 		*length_ptr = bytes;
12610Sstevel@tonic-gate 	return buffer_ptr(&incoming_packet);
12620Sstevel@tonic-gate }
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate int
12650Sstevel@tonic-gate packet_remaining(void)
12660Sstevel@tonic-gate {
12670Sstevel@tonic-gate 	return buffer_len(&incoming_packet);
12680Sstevel@tonic-gate }
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate /*
12710Sstevel@tonic-gate  * Returns a string from the packet data.  The string is allocated using
12720Sstevel@tonic-gate  * xmalloc; it is the responsibility of the calling program to free it when
12730Sstevel@tonic-gate  * no longer needed.  The length_ptr argument may be NULL, or point to an
12740Sstevel@tonic-gate  * integer into which the length of the string is stored.
12750Sstevel@tonic-gate  */
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate void *
12780Sstevel@tonic-gate packet_get_string(u_int *length_ptr)
12790Sstevel@tonic-gate {
12800Sstevel@tonic-gate 	return buffer_get_string(&incoming_packet, length_ptr);
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate char *
12830Sstevel@tonic-gate packet_get_ascii_cstring()
12840Sstevel@tonic-gate {
12850Sstevel@tonic-gate 	return buffer_get_ascii_cstring(&incoming_packet);
12860Sstevel@tonic-gate }
12870Sstevel@tonic-gate u_char *
12880Sstevel@tonic-gate packet_get_utf8_cstring()
12890Sstevel@tonic-gate {
12900Sstevel@tonic-gate 	return buffer_get_utf8_cstring(&incoming_packet);
12910Sstevel@tonic-gate }
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate /*
12940Sstevel@tonic-gate  * Sends a diagnostic message from the server to the client.  This message
12950Sstevel@tonic-gate  * can be sent at any time (but not while constructing another message). The
12960Sstevel@tonic-gate  * message is printed immediately, but only if the client is being executed
12970Sstevel@tonic-gate  * in verbose mode.  These messages are primarily intended to ease debugging
12980Sstevel@tonic-gate  * authentication problems.   The length of the formatted message must not
12990Sstevel@tonic-gate  * exceed 1024 bytes.  This will automatically call packet_write_wait.
13000Sstevel@tonic-gate  */
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate void
13030Sstevel@tonic-gate packet_send_debug(const char *fmt,...)
13040Sstevel@tonic-gate {
13050Sstevel@tonic-gate 	char buf[1024];
13060Sstevel@tonic-gate 	va_list args;
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	if (compat20 && (datafellows & SSH_BUG_DEBUG))
13090Sstevel@tonic-gate 		return;
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 	va_start(args, fmt);
13120Sstevel@tonic-gate 	vsnprintf(buf, sizeof(buf), gettext(fmt), args);
13130Sstevel@tonic-gate 	va_end(args);
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate #ifdef ALTPRIVSEP
13160Sstevel@tonic-gate 	/* shouldn't happen */
13170Sstevel@tonic-gate 	if (packet_monitor) {
13180Sstevel@tonic-gate 		debug("packet_send_debug: %s", buf);
13190Sstevel@tonic-gate 		return;
13200Sstevel@tonic-gate 	}
13210Sstevel@tonic-gate #endif /* ALTPRIVSEP */
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	if (compat20) {
13240Sstevel@tonic-gate 		packet_start(SSH2_MSG_DEBUG);
13250Sstevel@tonic-gate 		packet_put_char(0);	/* bool: always display */
13260Sstevel@tonic-gate 		packet_put_cstring(buf);
13270Sstevel@tonic-gate 		packet_put_cstring("");
13280Sstevel@tonic-gate 	} else {
13290Sstevel@tonic-gate 		packet_start(SSH_MSG_DEBUG);
13300Sstevel@tonic-gate 		packet_put_cstring(buf);
13310Sstevel@tonic-gate 	}
13320Sstevel@tonic-gate 	packet_send();
13330Sstevel@tonic-gate 	packet_write_wait();
13340Sstevel@tonic-gate }
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate /*
13370Sstevel@tonic-gate  * Logs the error plus constructs and sends a disconnect packet, closes the
13380Sstevel@tonic-gate  * connection, and exits.  This function never returns. The error message
13390Sstevel@tonic-gate  * should not contain a newline.  The length of the formatted message must
13400Sstevel@tonic-gate  * not exceed 1024 bytes.
13410Sstevel@tonic-gate  */
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate void
13440Sstevel@tonic-gate packet_disconnect(const char *fmt,...)
13450Sstevel@tonic-gate {
13460Sstevel@tonic-gate 	char buf[1024];
13470Sstevel@tonic-gate 	va_list args;
13480Sstevel@tonic-gate 	static int disconnecting = 0;
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	if (disconnecting)	/* Guard against recursive invocations. */
13510Sstevel@tonic-gate 		fatal("packet_disconnect called recursively.");
13520Sstevel@tonic-gate 	disconnecting = 1;
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 	/*
13550Sstevel@tonic-gate 	 * Format the message.  Note that the caller must make sure the
13560Sstevel@tonic-gate 	 * message is of limited size.
13570Sstevel@tonic-gate 	 */
13580Sstevel@tonic-gate 	va_start(args, fmt);
13590Sstevel@tonic-gate 	vsnprintf(buf, sizeof(buf), fmt, args);
13600Sstevel@tonic-gate 	va_end(args);
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate #ifdef ALTPRIVSEP
13630Sstevel@tonic-gate 	/*
13640Sstevel@tonic-gate 	 * If we packet_disconnect() in the monitor the fatal cleanups will take
13650Sstevel@tonic-gate 	 * care of the child.  See main() in sshd.c.  We don't send the packet
13660Sstevel@tonic-gate 	 * disconnect message here because: a) the child might not be looking
13670Sstevel@tonic-gate 	 * for it and b) because we don't really know if the child is compat20
13680Sstevel@tonic-gate 	 * or not as we lost that information when packet_set_monitor() was
13690Sstevel@tonic-gate 	 * called.
13700Sstevel@tonic-gate 	 */
13710Sstevel@tonic-gate 	if (packet_monitor)
13720Sstevel@tonic-gate 		goto close_stuff;
13730Sstevel@tonic-gate #endif /* ALTPRIVSEP */
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate 	/* Send the disconnect message to the other side, and wait for it to get sent. */
13760Sstevel@tonic-gate 	if (compat20) {
13770Sstevel@tonic-gate 		packet_start(SSH2_MSG_DISCONNECT);
13780Sstevel@tonic-gate 		packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR);
13790Sstevel@tonic-gate 		packet_put_cstring(buf);
13800Sstevel@tonic-gate 		packet_put_cstring("");
13810Sstevel@tonic-gate 	} else {
13820Sstevel@tonic-gate 		packet_start(SSH_MSG_DISCONNECT);
13830Sstevel@tonic-gate 		packet_put_cstring(buf);
13840Sstevel@tonic-gate 	}
13850Sstevel@tonic-gate 	packet_send();
13860Sstevel@tonic-gate 	packet_write_wait();
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate #ifdef ALTPRIVSEP
13890Sstevel@tonic-gate close_stuff:
13900Sstevel@tonic-gate #endif /* ALTPRIVSEP */
13910Sstevel@tonic-gate 	/* Stop listening for connections. */
13920Sstevel@tonic-gate 	channel_close_all();
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 	/* Close the connection. */
13950Sstevel@tonic-gate 	packet_close();
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 	/* Display the error locally and exit. */
13980Sstevel@tonic-gate 	log("Disconnecting: %.100s", buf);
13990Sstevel@tonic-gate 	fatal_cleanup();
14000Sstevel@tonic-gate }
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate /* Checks if there is any buffered output, and tries to write some of the output. */
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate void
14050Sstevel@tonic-gate packet_write_poll(void)
14060Sstevel@tonic-gate {
14070Sstevel@tonic-gate 	int len = buffer_len(&output);
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 	if (len > 0) {
14100Sstevel@tonic-gate 		len = write(connection_out, buffer_ptr(&output), len);
14110Sstevel@tonic-gate 		if (len <= 0) {
14120Sstevel@tonic-gate 			if (errno == EAGAIN)
14130Sstevel@tonic-gate 				return;
14140Sstevel@tonic-gate 			else
14150Sstevel@tonic-gate 				fatal("Write failed: %.100s", strerror(errno));
14160Sstevel@tonic-gate 		}
14170Sstevel@tonic-gate 		buffer_consume(&output, len);
14180Sstevel@tonic-gate 	}
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate /*
14220Sstevel@tonic-gate  * Calls packet_write_poll repeatedly until all pending output data has been
14230Sstevel@tonic-gate  * written.
14240Sstevel@tonic-gate  */
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate void
14270Sstevel@tonic-gate packet_write_wait(void)
14280Sstevel@tonic-gate {
14290Sstevel@tonic-gate 	fd_set *setp;
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) *
14320Sstevel@tonic-gate 	    sizeof(fd_mask));
14330Sstevel@tonic-gate 	packet_write_poll();
14340Sstevel@tonic-gate 	while (packet_have_data_to_write()) {
14350Sstevel@tonic-gate 		memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
14360Sstevel@tonic-gate 		    sizeof(fd_mask));
14370Sstevel@tonic-gate 		FD_SET(connection_out, setp);
14380Sstevel@tonic-gate 		while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
14390Sstevel@tonic-gate 		    (errno == EAGAIN || errno == EINTR))
14400Sstevel@tonic-gate 			;
14410Sstevel@tonic-gate 		packet_write_poll();
14420Sstevel@tonic-gate 	}
14430Sstevel@tonic-gate 	xfree(setp);
14440Sstevel@tonic-gate }
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate /* Returns true if there is buffered data to write to the connection. */
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate int
14490Sstevel@tonic-gate packet_have_data_to_write(void)
14500Sstevel@tonic-gate {
14510Sstevel@tonic-gate 	return buffer_len(&output) != 0;
14520Sstevel@tonic-gate }
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate /* Returns true if there is not too much data to write to the connection. */
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate int
14570Sstevel@tonic-gate packet_not_very_much_data_to_write(void)
14580Sstevel@tonic-gate {
14590Sstevel@tonic-gate 	if (interactive_mode)
14600Sstevel@tonic-gate 		return buffer_len(&output) < 16384;
14610Sstevel@tonic-gate 	else
14620Sstevel@tonic-gate 		return buffer_len(&output) < 128 * 1024;
14630Sstevel@tonic-gate }
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate /* Informs that the current session is interactive.  Sets IP flags for that. */
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate void
14680Sstevel@tonic-gate packet_set_interactive(int interactive)
14690Sstevel@tonic-gate {
14700Sstevel@tonic-gate 	static int called = 0;
14710Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
14720Sstevel@tonic-gate 	int lowdelay = IPTOS_LOWDELAY;
14730Sstevel@tonic-gate 	int throughput = IPTOS_THROUGHPUT;
14740Sstevel@tonic-gate #endif
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	if (called)
14770Sstevel@tonic-gate 		return;
14780Sstevel@tonic-gate 	called = 1;
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	/* Record that we are in interactive mode. */
14810Sstevel@tonic-gate 	interactive_mode = interactive;
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	/* Only set socket options if using a socket.  */
14840Sstevel@tonic-gate 	if (!packet_connection_is_on_socket())
14850Sstevel@tonic-gate 		return;
14860Sstevel@tonic-gate 	/*
14870Sstevel@tonic-gate 	 * IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only
14880Sstevel@tonic-gate 	 */
14890Sstevel@tonic-gate 	if (interactive) {
14900Sstevel@tonic-gate 		/*
14910Sstevel@tonic-gate 		 * Set IP options for an interactive connection.  Use
14920Sstevel@tonic-gate 		 * IPTOS_LOWDELAY and TCP_NODELAY.
14930Sstevel@tonic-gate 		 */
14940Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
14950Sstevel@tonic-gate 		if (packet_connection_is_ipv4()) {
14960Sstevel@tonic-gate 			if (setsockopt(connection_in, IPPROTO_IP, IP_TOS,
14970Sstevel@tonic-gate 			    &lowdelay, sizeof(lowdelay)) < 0)
14980Sstevel@tonic-gate 				error("setsockopt IPTOS_LOWDELAY: %.100s",
14990Sstevel@tonic-gate 				    strerror(errno));
15000Sstevel@tonic-gate 		}
15010Sstevel@tonic-gate #endif
15020Sstevel@tonic-gate 		set_nodelay(connection_in);
15030Sstevel@tonic-gate 	}
15040Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
15050Sstevel@tonic-gate 	else if (packet_connection_is_ipv4()) {
15060Sstevel@tonic-gate 		/*
15070Sstevel@tonic-gate 		 * Set IP options for a non-interactive connection.  Use
15080Sstevel@tonic-gate 		 * IPTOS_THROUGHPUT.
15090Sstevel@tonic-gate 		 */
15100Sstevel@tonic-gate 		if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &throughput,
15110Sstevel@tonic-gate 		    sizeof(throughput)) < 0)
15120Sstevel@tonic-gate 			error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
15130Sstevel@tonic-gate 	}
15140Sstevel@tonic-gate #endif
15150Sstevel@tonic-gate }
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate /* Returns true if the current connection is interactive. */
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate int
15200Sstevel@tonic-gate packet_is_interactive(void)
15210Sstevel@tonic-gate {
15220Sstevel@tonic-gate 	return interactive_mode;
15230Sstevel@tonic-gate }
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate int
15260Sstevel@tonic-gate packet_set_maxsize(int s)
15270Sstevel@tonic-gate {
15280Sstevel@tonic-gate 	static int called = 0;
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 	if (called) {
15310Sstevel@tonic-gate 		log("packet_set_maxsize: called twice: old %d new %d",
15320Sstevel@tonic-gate 		    max_packet_size, s);
15330Sstevel@tonic-gate 		return -1;
15340Sstevel@tonic-gate 	}
15350Sstevel@tonic-gate 	if (s < 4 * 1024 || s > 1024 * 1024) {
15360Sstevel@tonic-gate 		log("packet_set_maxsize: bad size %d", s);
15370Sstevel@tonic-gate 		return -1;
15380Sstevel@tonic-gate 	}
15390Sstevel@tonic-gate 	called = 1;
15400Sstevel@tonic-gate 	debug("packet_set_maxsize: setting to %d", s);
15410Sstevel@tonic-gate 	max_packet_size = s;
15420Sstevel@tonic-gate 	return s;
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate /* roundup current message to pad bytes */
15460Sstevel@tonic-gate void
15470Sstevel@tonic-gate packet_add_padding(u_char pad)
15480Sstevel@tonic-gate {
15490Sstevel@tonic-gate 	extra_pad = pad;
15500Sstevel@tonic-gate }
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate /*
15530Sstevel@tonic-gate  * 9.2.  Ignored Data Message
15540Sstevel@tonic-gate  *
15550Sstevel@tonic-gate  *   byte      SSH_MSG_IGNORE
15560Sstevel@tonic-gate  *   string    data
15570Sstevel@tonic-gate  *
15580Sstevel@tonic-gate  * All implementations MUST understand (and ignore) this message at any
15590Sstevel@tonic-gate  * time (after receiving the protocol version). No implementation is
15600Sstevel@tonic-gate  * required to send them. This message can be used as an additional
15610Sstevel@tonic-gate  * protection measure against advanced traffic analysis techniques.
15620Sstevel@tonic-gate  */
15630Sstevel@tonic-gate void
15640Sstevel@tonic-gate packet_send_ignore(int nbytes)
15650Sstevel@tonic-gate {
15665562Sjp161948 	u_int32_t rnd = 0;
15670Sstevel@tonic-gate 	int i;
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate #ifdef ALTPRIVSEP
15700Sstevel@tonic-gate 	/* shouldn't happen -- see packet_set_monitor() */
15710Sstevel@tonic-gate 	if (packet_monitor)
15720Sstevel@tonic-gate 		return;
15730Sstevel@tonic-gate #endif /* ALTPRIVSEP */
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate 	packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE);
15760Sstevel@tonic-gate 	packet_put_int(nbytes);
15770Sstevel@tonic-gate 	for (i = 0; i < nbytes; i++) {
15780Sstevel@tonic-gate 		if (i % 4 == 0)
15795562Sjp161948 			rnd = arc4random();
15805562Sjp161948 		packet_put_char((u_char)rnd & 0xff);
15815562Sjp161948 		rnd >>= 8;
15820Sstevel@tonic-gate 	}
15830Sstevel@tonic-gate }
15840Sstevel@tonic-gate 
15855562Sjp161948 #define MAX_PACKETS	(1U<<31)
15865562Sjp161948 int
15875562Sjp161948 packet_need_rekeying(void)
15885562Sjp161948 {
15895562Sjp161948 	if (datafellows & SSH_BUG_NOREKEY)
15905562Sjp161948 		return 0;
15915562Sjp161948 	return
15925562Sjp161948 	    (p_send.packets > MAX_PACKETS) ||
15935562Sjp161948 	    (p_read.packets > MAX_PACKETS) ||
15945562Sjp161948 	    (max_blocks_out && (p_send.blocks > max_blocks_out)) ||
15955562Sjp161948 	    (max_blocks_in  && (p_read.blocks > max_blocks_in));
15965562Sjp161948 }
15975562Sjp161948 
15985562Sjp161948 void
15995562Sjp161948 packet_set_rekey_limit(u_int32_t bytes)
16005562Sjp161948 {
16015562Sjp161948 	rekey_limit = bytes;
16025562Sjp161948 }
16035562Sjp161948 
16040Sstevel@tonic-gate #ifdef ALTPRIVSEP
16050Sstevel@tonic-gate void
16060Sstevel@tonic-gate packet_set_server(void)
16070Sstevel@tonic-gate {
16080Sstevel@tonic-gate 	packet_server = 1;
16090Sstevel@tonic-gate }
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate void
16120Sstevel@tonic-gate packet_set_no_monitor(void)
16130Sstevel@tonic-gate {
16140Sstevel@tonic-gate 	packet_server = 0;
16150Sstevel@tonic-gate }
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate int
16180Sstevel@tonic-gate packet_is_server(void)
16190Sstevel@tonic-gate {
16200Sstevel@tonic-gate 	return (packet_server);
16210Sstevel@tonic-gate }
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate void
16240Sstevel@tonic-gate packet_set_monitor(int pipe)
16250Sstevel@tonic-gate {
16260Sstevel@tonic-gate 	int dup_fd;
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 	packet_server = 1;
16290Sstevel@tonic-gate 	packet_monitor = 1;
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 	/*
16320Sstevel@tonic-gate 	 * Awful hack follows.
16330Sstevel@tonic-gate 	 *
16340Sstevel@tonic-gate 	 * For SSHv1 the monitor does not process any SSHv1 packets, only
16350Sstevel@tonic-gate 	 * ALTPRIVSEP packets.  We take advantage of that here to keep changes
16360Sstevel@tonic-gate 	 * to packet.c to a minimum by using the SSHv2 binary packet protocol,
16370Sstevel@tonic-gate 	 * with cipher "none," mac "none" and compression alg "none," as the
16380Sstevel@tonic-gate 	 * basis for the monitor protocol.  And so to force packet.c to treat
16390Sstevel@tonic-gate 	 * packets as SSHv2 we force compat20 == 1 here.
16400Sstevel@tonic-gate 	 *
16410Sstevel@tonic-gate 	 * For completeness and to help future developers catch this we also
16420Sstevel@tonic-gate 	 * force compat20 == 1 in the monitor loop, in serverloop.c.
16430Sstevel@tonic-gate 	 */
16440Sstevel@tonic-gate 	compat20 = 1;
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 	/*
16470Sstevel@tonic-gate 	 * NOTE:  Assumptions below!
16480Sstevel@tonic-gate 	 *
16490Sstevel@tonic-gate 	 *  - lots of packet.c code assumes that (connection_in ==
16500Sstevel@tonic-gate 	 *  connection_out) -> connection is socket
16510Sstevel@tonic-gate 	 *
16520Sstevel@tonic-gate 	 *  - packet_close() does not shutdown() the connection fildes
16530Sstevel@tonic-gate 	 *  if connection_in != connection_out
16540Sstevel@tonic-gate 	 *
16550Sstevel@tonic-gate 	 *  - other code assumes the connection is a socket if
16560Sstevel@tonic-gate 	 *  connection_in == connection_out
16570Sstevel@tonic-gate 	 */
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	if ((dup_fd = dup(pipe)) < 0)
16600Sstevel@tonic-gate 		fatal("Monitor failed to start: %s", strerror(errno));
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 	/*
16630Sstevel@tonic-gate 	 * make sure that the monitor's child's socket is not shutdown(3SOCKET)
16640Sstevel@tonic-gate 	 * when we packet_close()
16650Sstevel@tonic-gate 	 */
16660Sstevel@tonic-gate 	if (packet_connection_is_on_socket())
16670Sstevel@tonic-gate 		connection_out = -1;
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 	/* now cleanup state related to ssh socket */
16700Sstevel@tonic-gate 	packet_close();
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 	/* now make the monitor pipe look like the ssh connection */
16730Sstevel@tonic-gate 	packet_set_connection(pipe, dup_fd);
16740Sstevel@tonic-gate }
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate int
16770Sstevel@tonic-gate packet_is_monitor(void)
16780Sstevel@tonic-gate {
16790Sstevel@tonic-gate 	return (packet_monitor);
16800Sstevel@tonic-gate }
16810Sstevel@tonic-gate #endif /* ALTPRIVSEP */
1682