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*3102Sjp161948  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
400Sstevel@tonic-gate  * Use is subject to license terms.
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include "includes.h"
440Sstevel@tonic-gate RCSID("$OpenBSD: packet.c,v 1.97 2002/07/04 08:12:15 deraadt Exp $");
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include "xmalloc.h"
490Sstevel@tonic-gate #include "buffer.h"
500Sstevel@tonic-gate #include "packet.h"
510Sstevel@tonic-gate #include "bufaux.h"
520Sstevel@tonic-gate #include "crc32.h"
530Sstevel@tonic-gate #include "getput.h"
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #include "compress.h"
560Sstevel@tonic-gate #include "deattack.h"
570Sstevel@tonic-gate #include "channels.h"
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #include "compat.h"
600Sstevel@tonic-gate #include "ssh1.h"
610Sstevel@tonic-gate #include "ssh2.h"
620Sstevel@tonic-gate 
630Sstevel@tonic-gate #include "cipher.h"
640Sstevel@tonic-gate #include "kex.h"
650Sstevel@tonic-gate #include "mac.h"
660Sstevel@tonic-gate #include "log.h"
670Sstevel@tonic-gate #include "canohost.h"
680Sstevel@tonic-gate #include "misc.h"
690Sstevel@tonic-gate #include "ssh.h"
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #ifdef ALTPRIVSEP
720Sstevel@tonic-gate static int packet_server = 0;
730Sstevel@tonic-gate static int packet_monitor = 0;
740Sstevel@tonic-gate #endif /* ALTPRIVSEP */
750Sstevel@tonic-gate 
760Sstevel@tonic-gate #ifdef PACKET_DEBUG
770Sstevel@tonic-gate #define DBG(x) x
780Sstevel@tonic-gate #else
790Sstevel@tonic-gate #define DBG(x)
800Sstevel@tonic-gate #endif
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /*
830Sstevel@tonic-gate  * This variable contains the file descriptors used for communicating with
840Sstevel@tonic-gate  * the other side.  connection_in is used for reading; connection_out for
850Sstevel@tonic-gate  * writing.  These can be the same descriptor, in which case it is assumed to
860Sstevel@tonic-gate  * be a socket.
870Sstevel@tonic-gate  */
880Sstevel@tonic-gate static int connection_in = -1;
890Sstevel@tonic-gate static int connection_out = -1;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /* Protocol flags for the remote side. */
920Sstevel@tonic-gate static u_int remote_protocol_flags = 0;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /* Encryption context for receiving data.  This is only used for decryption. */
950Sstevel@tonic-gate static CipherContext receive_context;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate /* Encryption context for sending data.  This is only used for encryption. */
980Sstevel@tonic-gate static CipherContext send_context;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate /* Buffer for raw input data from the socket. */
1010Sstevel@tonic-gate Buffer input;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate /* Buffer for raw output data going to the socket. */
1040Sstevel@tonic-gate Buffer output;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate /* Buffer for the partial outgoing packet being constructed. */
1070Sstevel@tonic-gate static Buffer outgoing_packet;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate /* Buffer for the incoming packet currently being processed. */
1100Sstevel@tonic-gate static Buffer incoming_packet;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /* Scratch buffer for packet compression/decompression. */
1130Sstevel@tonic-gate static Buffer compression_buffer;
1140Sstevel@tonic-gate static int compression_buffer_ready = 0;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /* Flag indicating whether packet compression/decompression is enabled. */
1170Sstevel@tonic-gate static int packet_compression = 0;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /* default maximum packet size */
1200Sstevel@tonic-gate int max_packet_size = 32768;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate /* Flag indicating whether this module has been initialized. */
1230Sstevel@tonic-gate static int initialized = 0;
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /* Set to true if the connection is interactive. */
1260Sstevel@tonic-gate static int interactive_mode = 0;
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate /* Session key information for Encryption and MAC */
1290Sstevel@tonic-gate Newkeys *newkeys[MODE_MAX];
1300Sstevel@tonic-gate static u_int32_t read_seqnr = 0;
1310Sstevel@tonic-gate static u_int32_t send_seqnr = 0;
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate /* Session key for protocol v1 */
1340Sstevel@tonic-gate static u_char ssh1_key[SSH_SESSION_KEY_LENGTH];
1350Sstevel@tonic-gate static u_int ssh1_keylen;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate /* roundup current message to extra_pad bytes */
1380Sstevel@tonic-gate static u_char extra_pad = 0;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /*
1410Sstevel@tonic-gate  * Sets the descriptors used for communication.  Disables encryption until
1420Sstevel@tonic-gate  * packet_set_encryption_key is called.
1430Sstevel@tonic-gate  */
1440Sstevel@tonic-gate void
1450Sstevel@tonic-gate packet_set_connection(int fd_in, int fd_out)
1460Sstevel@tonic-gate {
1470Sstevel@tonic-gate 	Cipher *none = cipher_by_name("none");
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	if (none == NULL)
1500Sstevel@tonic-gate 		fatal("packet_set_connection: cannot load cipher 'none'");
1510Sstevel@tonic-gate 	connection_in = fd_in;
1520Sstevel@tonic-gate 	connection_out = fd_out;
1530Sstevel@tonic-gate 	cipher_init(&send_context, none, (unsigned char *) "", 0, NULL, 0, CIPHER_ENCRYPT);
1540Sstevel@tonic-gate 	cipher_init(&receive_context, none, (unsigned char *) "", 0, NULL, 0, CIPHER_DECRYPT);
1550Sstevel@tonic-gate 	newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
1560Sstevel@tonic-gate 	if (!initialized) {
1570Sstevel@tonic-gate 		initialized = 1;
1580Sstevel@tonic-gate 		buffer_init(&input);
1590Sstevel@tonic-gate 		buffer_init(&output);
1600Sstevel@tonic-gate 		buffer_init(&outgoing_packet);
1610Sstevel@tonic-gate 		buffer_init(&incoming_packet);
1620Sstevel@tonic-gate 	} else {
1630Sstevel@tonic-gate 		buffer_clear(&input);
1640Sstevel@tonic-gate 		buffer_clear(&output);
1650Sstevel@tonic-gate 		buffer_clear(&outgoing_packet);
1660Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	/*
1700Sstevel@tonic-gate 	 * Prime the cache for get_remote_ipaddr() while we have a
1710Sstevel@tonic-gate 	 * socket on which to do a getpeername().
1720Sstevel@tonic-gate 	 */
1730Sstevel@tonic-gate 	(void) get_remote_ipaddr();
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	/* Kludge: arrange the close function to be called from fatal(). */
1760Sstevel@tonic-gate 	fatal_add_cleanup((void (*) (void *)) packet_close, NULL);
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /* Returns 1 if remote host is connected via socket, 0 if not. */
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate int
1820Sstevel@tonic-gate packet_connection_is_on_socket(void)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	struct sockaddr_storage from, to;
1850Sstevel@tonic-gate 	socklen_t fromlen, tolen;
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	/* filedescriptors in and out are the same, so it's a socket */
1880Sstevel@tonic-gate 	if (connection_in != -1 && connection_in == connection_out)
1890Sstevel@tonic-gate 		return 1;
1900Sstevel@tonic-gate 	fromlen = sizeof(from);
1910Sstevel@tonic-gate 	memset(&from, 0, sizeof(from));
1920Sstevel@tonic-gate 	if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0)
1930Sstevel@tonic-gate 		return 0;
1940Sstevel@tonic-gate 	tolen = sizeof(to);
1950Sstevel@tonic-gate 	memset(&to, 0, sizeof(to));
1960Sstevel@tonic-gate 	if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0)
1970Sstevel@tonic-gate 		return 0;
1980Sstevel@tonic-gate 	if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0)
1990Sstevel@tonic-gate 		return 0;
2000Sstevel@tonic-gate 	if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
2010Sstevel@tonic-gate 		return 0;
2020Sstevel@tonic-gate 	return 1;
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate /*
2060Sstevel@tonic-gate  * Exports an IV from the CipherContext required to export the key
2070Sstevel@tonic-gate  * state back from the unprivileged child to the privileged parent
2080Sstevel@tonic-gate  * process.
2090Sstevel@tonic-gate  */
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate void
2120Sstevel@tonic-gate packet_get_keyiv(int mode, u_char *iv, u_int len)
2130Sstevel@tonic-gate {
2140Sstevel@tonic-gate 	CipherContext *cc;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	if (mode == MODE_OUT)
2170Sstevel@tonic-gate 		cc = &send_context;
2180Sstevel@tonic-gate 	else
2190Sstevel@tonic-gate 		cc = &receive_context;
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	cipher_get_keyiv(cc, iv, len);
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate int
2250Sstevel@tonic-gate packet_get_keycontext(int mode, u_char *dat)
2260Sstevel@tonic-gate {
2270Sstevel@tonic-gate 	CipherContext *cc;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	if (mode == MODE_OUT)
2300Sstevel@tonic-gate 		cc = &send_context;
2310Sstevel@tonic-gate 	else
2320Sstevel@tonic-gate 		cc = &receive_context;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	return (cipher_get_keycontext(cc, dat));
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate void
2380Sstevel@tonic-gate packet_set_keycontext(int mode, u_char *dat)
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate 	CipherContext *cc;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	if (mode == MODE_OUT)
2430Sstevel@tonic-gate 		cc = &send_context;
2440Sstevel@tonic-gate 	else
2450Sstevel@tonic-gate 		cc = &receive_context;
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	cipher_set_keycontext(cc, dat);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate int
2510Sstevel@tonic-gate packet_get_keyiv_len(int mode)
2520Sstevel@tonic-gate {
2530Sstevel@tonic-gate 	CipherContext *cc;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	if (mode == MODE_OUT)
2560Sstevel@tonic-gate 		cc = &send_context;
2570Sstevel@tonic-gate 	else
2580Sstevel@tonic-gate 		cc = &receive_context;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	return (cipher_get_keyiv_len(cc));
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate void
2630Sstevel@tonic-gate packet_set_iv(int mode, u_char *dat)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate 	CipherContext *cc;
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	if (mode == MODE_OUT)
2680Sstevel@tonic-gate 		cc = &send_context;
2690Sstevel@tonic-gate 	else
2700Sstevel@tonic-gate 		cc = &receive_context;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	cipher_set_keyiv(cc, dat);
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate int
2750Sstevel@tonic-gate packet_get_ssh1_cipher()
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate 	return (cipher_get_number(receive_context.cipher));
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate u_int32_t
2820Sstevel@tonic-gate packet_get_seqnr(int mode)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	return (mode == MODE_IN ? read_seqnr : send_seqnr);
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate void
2880Sstevel@tonic-gate packet_set_seqnr(int mode, u_int32_t seqnr)
2890Sstevel@tonic-gate {
2900Sstevel@tonic-gate 	if (mode == MODE_IN)
2910Sstevel@tonic-gate 		read_seqnr = seqnr;
2920Sstevel@tonic-gate 	else if (mode == MODE_OUT)
2930Sstevel@tonic-gate 		send_seqnr = seqnr;
2940Sstevel@tonic-gate 	else
2950Sstevel@tonic-gate 		fatal("packet_set_seqnr: bad mode %d", mode);
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate /* returns 1 if connection is via ipv4 */
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate int
3010Sstevel@tonic-gate packet_connection_is_ipv4(void)
3020Sstevel@tonic-gate {
3030Sstevel@tonic-gate 	struct sockaddr_storage to;
3040Sstevel@tonic-gate 	socklen_t tolen = sizeof(to);
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	memset(&to, 0, sizeof(to));
3070Sstevel@tonic-gate 	if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0)
3080Sstevel@tonic-gate 		return 0;
3090Sstevel@tonic-gate 	if (to.ss_family == AF_INET)
3100Sstevel@tonic-gate 		return 1;
3110Sstevel@tonic-gate #ifdef IPV4_IN_IPV6
3120Sstevel@tonic-gate 	if (to.ss_family == AF_INET6 &&
3130Sstevel@tonic-gate 	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr))
3140Sstevel@tonic-gate 		return 1;
3150Sstevel@tonic-gate #endif
3160Sstevel@tonic-gate 	return 0;
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate /* Sets the connection into non-blocking mode. */
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate void
3220Sstevel@tonic-gate packet_set_nonblocking(void)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate 	/* Set the socket into non-blocking mode. */
3250Sstevel@tonic-gate 	if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0)
3260Sstevel@tonic-gate 		error("fcntl O_NONBLOCK: %.100s", strerror(errno));
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	if (connection_out != connection_in) {
3290Sstevel@tonic-gate 		if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0)
3300Sstevel@tonic-gate 			error("fcntl O_NONBLOCK: %.100s", strerror(errno));
3310Sstevel@tonic-gate 	}
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate /* Returns the socket used for reading. */
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate int
3370Sstevel@tonic-gate packet_get_connection_in(void)
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate 	return connection_in;
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate /* Returns the descriptor used for writing. */
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate int
3450Sstevel@tonic-gate packet_get_connection_out(void)
3460Sstevel@tonic-gate {
3470Sstevel@tonic-gate 	return connection_out;
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate /* Closes the connection and clears and frees internal data structures. */
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate void
3530Sstevel@tonic-gate packet_close(void)
3540Sstevel@tonic-gate {
3550Sstevel@tonic-gate 	if (!initialized)
3560Sstevel@tonic-gate 		return;
3570Sstevel@tonic-gate 	initialized = 0;
3580Sstevel@tonic-gate 	if (connection_in == connection_out) {
3590Sstevel@tonic-gate 		shutdown(connection_out, SHUT_RDWR);
3600Sstevel@tonic-gate 		close(connection_out);
3610Sstevel@tonic-gate 	} else {
3620Sstevel@tonic-gate 		close(connection_in);
3630Sstevel@tonic-gate 		close(connection_out);
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 	buffer_free(&input);
3660Sstevel@tonic-gate 	buffer_free(&output);
3670Sstevel@tonic-gate 	buffer_free(&outgoing_packet);
3680Sstevel@tonic-gate 	buffer_free(&incoming_packet);
3690Sstevel@tonic-gate 	if (compression_buffer_ready) {
3700Sstevel@tonic-gate 		buffer_free(&compression_buffer);
3710Sstevel@tonic-gate 		buffer_compress_uninit();
3720Sstevel@tonic-gate 		compression_buffer_ready = 0;
3730Sstevel@tonic-gate 	}
3740Sstevel@tonic-gate 	cipher_cleanup(&send_context);
3750Sstevel@tonic-gate 	cipher_cleanup(&receive_context);
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate /* Sets remote side protocol flags. */
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate void
3810Sstevel@tonic-gate packet_set_protocol_flags(u_int protocol_flags)
3820Sstevel@tonic-gate {
3830Sstevel@tonic-gate 	remote_protocol_flags = protocol_flags;
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate /* Returns the remote protocol flags set earlier by the above function. */
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate u_int
3890Sstevel@tonic-gate packet_get_protocol_flags(void)
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate 	return remote_protocol_flags;
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate /*
3950Sstevel@tonic-gate  * Starts packet compression from the next packet on in both directions.
3960Sstevel@tonic-gate  * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
3970Sstevel@tonic-gate  */
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate static void
4000Sstevel@tonic-gate packet_init_compression(void)
4010Sstevel@tonic-gate {
4020Sstevel@tonic-gate 	if (compression_buffer_ready == 1)
4030Sstevel@tonic-gate 		return;
4040Sstevel@tonic-gate 	compression_buffer_ready = 1;
4050Sstevel@tonic-gate 	buffer_init(&compression_buffer);
4060Sstevel@tonic-gate }
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate void
4090Sstevel@tonic-gate packet_start_compression(int level)
4100Sstevel@tonic-gate {
4110Sstevel@tonic-gate #ifdef ALTPRIVSEP
4120Sstevel@tonic-gate 	/* shouldn't happen! */
4130Sstevel@tonic-gate 	if (packet_monitor)
4140Sstevel@tonic-gate 		fatal("INTERNAL ERROR: The monitor cannot compress.");
4150Sstevel@tonic-gate #endif /* ALTPRIVSEP */
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	if (packet_compression && !compat20)
4180Sstevel@tonic-gate 		fatal("Compression already enabled.");
4190Sstevel@tonic-gate 	packet_compression = 1;
4200Sstevel@tonic-gate 	packet_init_compression();
4210Sstevel@tonic-gate 	buffer_compress_init_send(level);
4220Sstevel@tonic-gate 	buffer_compress_init_recv();
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate /*
4260Sstevel@tonic-gate  * Causes any further packets to be encrypted using the given key.  The same
4270Sstevel@tonic-gate  * key is used for both sending and reception.  However, both directions are
4280Sstevel@tonic-gate  * encrypted independently of each other.
4290Sstevel@tonic-gate  */
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate void
4320Sstevel@tonic-gate packet_set_encryption_key(const u_char *key, u_int keylen,
4330Sstevel@tonic-gate     int number)
4340Sstevel@tonic-gate {
4350Sstevel@tonic-gate 	Cipher *cipher = cipher_by_number(number);
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	if (cipher == NULL)
4380Sstevel@tonic-gate 		fatal("packet_set_encryption_key: unknown cipher number %d", number);
4390Sstevel@tonic-gate 	if (keylen < 20)
4400Sstevel@tonic-gate 		fatal("packet_set_encryption_key: keylen too small: %d", keylen);
4410Sstevel@tonic-gate 	if (keylen > SSH_SESSION_KEY_LENGTH)
4420Sstevel@tonic-gate 		fatal("packet_set_encryption_key: keylen too big: %d", keylen);
4430Sstevel@tonic-gate 	memcpy(ssh1_key, key, keylen);
4440Sstevel@tonic-gate 	ssh1_keylen = keylen;
4450Sstevel@tonic-gate 	cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT);
4460Sstevel@tonic-gate 	cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT);
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate u_int
4500Sstevel@tonic-gate packet_get_encryption_key(u_char *key)
4510Sstevel@tonic-gate {
4520Sstevel@tonic-gate 	if (key == NULL)
4530Sstevel@tonic-gate 		return (ssh1_keylen);
4540Sstevel@tonic-gate 	memcpy(key, ssh1_key, ssh1_keylen);
4550Sstevel@tonic-gate 	return (ssh1_keylen);
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate /* Start constructing a packet to send. */
4590Sstevel@tonic-gate void
4600Sstevel@tonic-gate packet_start(u_char type)
4610Sstevel@tonic-gate {
4620Sstevel@tonic-gate 	u_char buf[9];
4630Sstevel@tonic-gate 	int len;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	DBG(debug("packet_start[%d]", type));
4660Sstevel@tonic-gate 	len = compat20 ? 6 : 9;
4670Sstevel@tonic-gate 	memset(buf, 0, len - 1);
4680Sstevel@tonic-gate 	buf[len - 1] = type;
4690Sstevel@tonic-gate 	buffer_clear(&outgoing_packet);
4700Sstevel@tonic-gate 	buffer_append(&outgoing_packet, buf, len);
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate /* Append payload. */
4740Sstevel@tonic-gate void
4750Sstevel@tonic-gate packet_put_char(int value)
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate 	char ch = value;
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	buffer_append(&outgoing_packet, &ch, 1);
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate void
4820Sstevel@tonic-gate packet_put_int(u_int value)
4830Sstevel@tonic-gate {
4840Sstevel@tonic-gate 	buffer_put_int(&outgoing_packet, value);
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate void
4870Sstevel@tonic-gate packet_put_string(const void *buf, u_int len)
4880Sstevel@tonic-gate {
4890Sstevel@tonic-gate 	buffer_put_string(&outgoing_packet, buf, len);
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate void
4920Sstevel@tonic-gate packet_put_cstring(const char *str)
4930Sstevel@tonic-gate {
4940Sstevel@tonic-gate 	buffer_put_cstring(&outgoing_packet, str);
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate void
4970Sstevel@tonic-gate packet_put_ascii_cstring(const char *str)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	buffer_put_ascii_cstring(&outgoing_packet, str);
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate void
5020Sstevel@tonic-gate packet_put_utf8_cstring(const u_char *str)
5030Sstevel@tonic-gate {
5040Sstevel@tonic-gate 	buffer_put_utf8_cstring(&outgoing_packet, str);
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate #if 0
5070Sstevel@tonic-gate void
5080Sstevel@tonic-gate packet_put_ascii_string(const void *buf, u_int len)
5090Sstevel@tonic-gate {
5100Sstevel@tonic-gate 	buffer_put_ascii_string(&outgoing_packet, buf, len);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate void
5130Sstevel@tonic-gate packet_put_utf8_string(const void *buf, u_int len)
5140Sstevel@tonic-gate {
5150Sstevel@tonic-gate 	buffer_put_utf8_string(&outgoing_packet, buf, len);
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate #endif
5180Sstevel@tonic-gate void
5190Sstevel@tonic-gate packet_put_raw(const void *buf, u_int len)
5200Sstevel@tonic-gate {
5210Sstevel@tonic-gate 	buffer_append(&outgoing_packet, buf, len);
5220Sstevel@tonic-gate }
5230Sstevel@tonic-gate void
5240Sstevel@tonic-gate packet_put_bignum(BIGNUM * value)
5250Sstevel@tonic-gate {
5260Sstevel@tonic-gate 	buffer_put_bignum(&outgoing_packet, value);
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate void
5290Sstevel@tonic-gate packet_put_bignum2(BIGNUM * value)
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate 	buffer_put_bignum2(&outgoing_packet, value);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate /*
5350Sstevel@tonic-gate  * Finalizes and sends the packet.  If the encryption key has been set,
5360Sstevel@tonic-gate  * encrypts the packet before sending.
5370Sstevel@tonic-gate  */
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate static void
5400Sstevel@tonic-gate packet_send1(void)
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate 	u_char buf[8], *cp;
5430Sstevel@tonic-gate 	int i, padding, len;
5440Sstevel@tonic-gate 	u_int checksum;
5450Sstevel@tonic-gate 	u_int32_t rand = 0;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	/*
5480Sstevel@tonic-gate 	 * If using packet compression, compress the payload of the outgoing
5490Sstevel@tonic-gate 	 * packet.
5500Sstevel@tonic-gate 	 */
5510Sstevel@tonic-gate 	if (packet_compression) {
5520Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
5530Sstevel@tonic-gate 		/* Skip padding. */
5540Sstevel@tonic-gate 		buffer_consume(&outgoing_packet, 8);
5550Sstevel@tonic-gate 		/* padding */
5560Sstevel@tonic-gate 		buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8);
5570Sstevel@tonic-gate 		buffer_compress(&outgoing_packet, &compression_buffer);
5580Sstevel@tonic-gate 		buffer_clear(&outgoing_packet);
5590Sstevel@tonic-gate 		buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
5600Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 	/* Compute packet length without padding (add checksum, remove padding). */
5630Sstevel@tonic-gate 	len = buffer_len(&outgoing_packet) + 4 - 8;
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	/* Insert padding. Initialized to zero in packet_start1() */
5660Sstevel@tonic-gate 	padding = 8 - len % 8;
5670Sstevel@tonic-gate 	if (!send_context.plaintext) {
5680Sstevel@tonic-gate 		cp = buffer_ptr(&outgoing_packet);
5690Sstevel@tonic-gate 		for (i = 0; i < padding; i++) {
5700Sstevel@tonic-gate 			if (i % 4 == 0)
5710Sstevel@tonic-gate 				rand = arc4random();
5720Sstevel@tonic-gate 			cp[7 - i] = rand & 0xff;
5730Sstevel@tonic-gate 			rand >>= 8;
5740Sstevel@tonic-gate 		}
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 	buffer_consume(&outgoing_packet, 8 - padding);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	/* Add check bytes. */
5790Sstevel@tonic-gate 	checksum = ssh_crc32(buffer_ptr(&outgoing_packet),
5800Sstevel@tonic-gate 	    buffer_len(&outgoing_packet));
5810Sstevel@tonic-gate 	PUT_32BIT(buf, checksum);
5820Sstevel@tonic-gate 	buffer_append(&outgoing_packet, buf, 4);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate #ifdef PACKET_DEBUG
5850Sstevel@tonic-gate 	fprintf(stderr, "packet_send plain: ");
5860Sstevel@tonic-gate 	buffer_dump(&outgoing_packet);
5870Sstevel@tonic-gate #endif
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	/* Append to output. */
5900Sstevel@tonic-gate 	PUT_32BIT(buf, len);
5910Sstevel@tonic-gate 	buffer_append(&output, buf, 4);
5920Sstevel@tonic-gate 	cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
5930Sstevel@tonic-gate 	cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
5940Sstevel@tonic-gate 	    buffer_len(&outgoing_packet));
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate #ifdef PACKET_DEBUG
5970Sstevel@tonic-gate 	fprintf(stderr, "encrypted: ");
5980Sstevel@tonic-gate 	buffer_dump(&output);
5990Sstevel@tonic-gate #endif
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	buffer_clear(&outgoing_packet);
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	/*
6040Sstevel@tonic-gate 	 * Note that the packet is now only buffered in output.  It won\'t be
6050Sstevel@tonic-gate 	 * actually sent until packet_write_wait or packet_write_poll is
6060Sstevel@tonic-gate 	 * called.
6070Sstevel@tonic-gate 	 */
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate void
6110Sstevel@tonic-gate set_newkeys(int mode)
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate 	Enc *enc;
6140Sstevel@tonic-gate 	Mac *mac;
6150Sstevel@tonic-gate 	Comp *comp;
6160Sstevel@tonic-gate 	CipherContext *cc;
6170Sstevel@tonic-gate 	int encrypt;
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	debug("newkeys: mode %d", mode);
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	if (mode == MODE_OUT) {
6220Sstevel@tonic-gate 		cc = &send_context;
6230Sstevel@tonic-gate 		encrypt = CIPHER_ENCRYPT;
6240Sstevel@tonic-gate 	} else {
6250Sstevel@tonic-gate 		cc = &receive_context;
6260Sstevel@tonic-gate 		encrypt = CIPHER_DECRYPT;
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 	if (newkeys[mode] != NULL) {
6290Sstevel@tonic-gate 		debug("newkeys: rekeying");
6300Sstevel@tonic-gate 		cipher_cleanup(cc);
6310Sstevel@tonic-gate 		enc  = &newkeys[mode]->enc;
6320Sstevel@tonic-gate 		mac  = &newkeys[mode]->mac;
6330Sstevel@tonic-gate 		comp = &newkeys[mode]->comp;
6340Sstevel@tonic-gate 		memset(mac->key, 0, mac->key_len);
6350Sstevel@tonic-gate 		xfree(enc->name);
6360Sstevel@tonic-gate 		xfree(enc->iv);
6370Sstevel@tonic-gate 		xfree(enc->key);
6380Sstevel@tonic-gate 		xfree(mac->name);
6390Sstevel@tonic-gate 		xfree(mac->key);
6400Sstevel@tonic-gate 		xfree(comp->name);
6410Sstevel@tonic-gate 		xfree(newkeys[mode]);
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 	newkeys[mode] = kex_get_newkeys(mode);
6440Sstevel@tonic-gate 	if (newkeys[mode] == NULL)
6450Sstevel@tonic-gate 		fatal("newkeys: no keys for mode %d", mode);
6460Sstevel@tonic-gate 	enc  = &newkeys[mode]->enc;
6470Sstevel@tonic-gate 	mac  = &newkeys[mode]->mac;
6480Sstevel@tonic-gate 	comp = &newkeys[mode]->comp;
6490Sstevel@tonic-gate 	if (mac->md != NULL)
6500Sstevel@tonic-gate 		mac->enabled = 1;
6510Sstevel@tonic-gate 	DBG(debug("cipher_init_context: %d", mode));
6520Sstevel@tonic-gate 	cipher_init(cc, enc->cipher, enc->key, enc->key_len,
6530Sstevel@tonic-gate 	    enc->iv, enc->block_size, encrypt);
6540Sstevel@tonic-gate 	/* Deleting the keys does not gain extra security */
6550Sstevel@tonic-gate 	/* memset(enc->iv,  0, enc->block_size);
6560Sstevel@tonic-gate 	   memset(enc->key, 0, enc->key_len); */
6570Sstevel@tonic-gate 	if (comp->type != 0 && comp->enabled == 0) {
6580Sstevel@tonic-gate 		packet_init_compression();
6590Sstevel@tonic-gate 		if (mode == MODE_OUT)
6600Sstevel@tonic-gate 			buffer_compress_init_send(6);
6610Sstevel@tonic-gate 		else
6620Sstevel@tonic-gate 			buffer_compress_init_recv();
6630Sstevel@tonic-gate 		comp->enabled = 1;
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate /*
6680Sstevel@tonic-gate  * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
6690Sstevel@tonic-gate  */
6700Sstevel@tonic-gate static void
6710Sstevel@tonic-gate packet_send2(void)
6720Sstevel@tonic-gate {
6730Sstevel@tonic-gate 	u_char type, *cp, *macbuf = NULL;
6740Sstevel@tonic-gate 	u_char padlen, pad;
6750Sstevel@tonic-gate 	u_int packet_length = 0;
6760Sstevel@tonic-gate 	u_int i, len;
6770Sstevel@tonic-gate 	u_int32_t rand = 0;
6780Sstevel@tonic-gate 	Enc *enc   = NULL;
6790Sstevel@tonic-gate 	Mac *mac   = NULL;
6800Sstevel@tonic-gate 	Comp *comp = NULL;
6810Sstevel@tonic-gate 	int block_size;
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	if (newkeys[MODE_OUT] != NULL) {
6840Sstevel@tonic-gate 		enc  = &newkeys[MODE_OUT]->enc;
6850Sstevel@tonic-gate 		mac  = &newkeys[MODE_OUT]->mac;
6860Sstevel@tonic-gate 		comp = &newkeys[MODE_OUT]->comp;
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 	block_size = enc ? enc->block_size : 8;
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	cp = buffer_ptr(&outgoing_packet);
6910Sstevel@tonic-gate 	type = cp[5];
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate #ifdef PACKET_DEBUG
6940Sstevel@tonic-gate 	fprintf(stderr, "plain:     ");
6950Sstevel@tonic-gate 	buffer_dump(&outgoing_packet);
6960Sstevel@tonic-gate #endif
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	if (comp && comp->enabled) {
6990Sstevel@tonic-gate 		len = buffer_len(&outgoing_packet);
7000Sstevel@tonic-gate 		/* skip header, compress only payload */
7010Sstevel@tonic-gate 		buffer_consume(&outgoing_packet, 5);
7020Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
7030Sstevel@tonic-gate 		buffer_compress(&outgoing_packet, &compression_buffer);
7040Sstevel@tonic-gate 		buffer_clear(&outgoing_packet);
7050Sstevel@tonic-gate 		buffer_append(&outgoing_packet, "\0\0\0\0\0", 5);
7060Sstevel@tonic-gate 		buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
7070Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
7080Sstevel@tonic-gate 		DBG(debug("compression: raw %d compressed %d", len,
7090Sstevel@tonic-gate 		    buffer_len(&outgoing_packet)));
7100Sstevel@tonic-gate 	}
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	/* sizeof (packet_len + pad_len + payload) */
7130Sstevel@tonic-gate 	len = buffer_len(&outgoing_packet);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	/*
7160Sstevel@tonic-gate 	 * calc size of padding, alloc space, get random data,
7170Sstevel@tonic-gate 	 * minimum padding is 4 bytes
7180Sstevel@tonic-gate 	 */
7190Sstevel@tonic-gate 	padlen = block_size - (len % block_size);
7200Sstevel@tonic-gate 	if (padlen < 4)
7210Sstevel@tonic-gate 		padlen += block_size;
7220Sstevel@tonic-gate 	if (extra_pad) {
7230Sstevel@tonic-gate 		/* will wrap if extra_pad+padlen > 255 */
7240Sstevel@tonic-gate 		extra_pad  = roundup(extra_pad, block_size);
7250Sstevel@tonic-gate 		pad = extra_pad - ((len + padlen) % extra_pad);
7260Sstevel@tonic-gate 		debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)",
7270Sstevel@tonic-gate 		    pad, len, padlen, extra_pad);
7280Sstevel@tonic-gate 		padlen += pad;
7290Sstevel@tonic-gate 		extra_pad = 0;
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 	cp = buffer_append_space(&outgoing_packet, padlen);
7320Sstevel@tonic-gate 	if (enc && !send_context.plaintext) {
7330Sstevel@tonic-gate 		/* random padding */
7340Sstevel@tonic-gate 		for (i = 0; i < padlen; i++) {
7350Sstevel@tonic-gate 			if (i % 4 == 0)
7360Sstevel@tonic-gate 				rand = arc4random();
7370Sstevel@tonic-gate 			cp[i] = rand & 0xff;
7380Sstevel@tonic-gate 			rand >>= 8;
7390Sstevel@tonic-gate 		}
7400Sstevel@tonic-gate 	} else {
7410Sstevel@tonic-gate 		/* clear padding */
7420Sstevel@tonic-gate 		memset(cp, 0, padlen);
7430Sstevel@tonic-gate 	}
7440Sstevel@tonic-gate 	/* packet_length includes payload, padding and padding length field */
7450Sstevel@tonic-gate 	packet_length = buffer_len(&outgoing_packet) - 4;
7460Sstevel@tonic-gate 	cp = buffer_ptr(&outgoing_packet);
7470Sstevel@tonic-gate 	PUT_32BIT(cp, packet_length);
7480Sstevel@tonic-gate 	cp[4] = padlen;
7490Sstevel@tonic-gate 	DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen));
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	/* compute MAC over seqnr and packet(length fields, payload, padding) */
7520Sstevel@tonic-gate 	if (mac && mac->enabled) {
7530Sstevel@tonic-gate 		macbuf = mac_compute(mac, send_seqnr,
7540Sstevel@tonic-gate 		    buffer_ptr(&outgoing_packet),
7550Sstevel@tonic-gate 		    buffer_len(&outgoing_packet));
7560Sstevel@tonic-gate 		DBG(debug("done calc MAC out #%d", send_seqnr));
7570Sstevel@tonic-gate 	}
7580Sstevel@tonic-gate 	/* encrypt packet and append to output buffer. */
7590Sstevel@tonic-gate 	cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
7600Sstevel@tonic-gate 	cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
7610Sstevel@tonic-gate 	    buffer_len(&outgoing_packet));
7620Sstevel@tonic-gate 	/* append unencrypted MAC */
7630Sstevel@tonic-gate 	if (mac && mac->enabled)
7640Sstevel@tonic-gate 		buffer_append(&output, (char *)macbuf, mac->mac_len);
7650Sstevel@tonic-gate #ifdef PACKET_DEBUG
7660Sstevel@tonic-gate 	fprintf(stderr, "encrypted: ");
7670Sstevel@tonic-gate 	buffer_dump(&output);
7680Sstevel@tonic-gate #endif
7690Sstevel@tonic-gate 	/* increment sequence number for outgoing packets */
7700Sstevel@tonic-gate 	if (++send_seqnr == 0)
7710Sstevel@tonic-gate 		log("outgoing seqnr wraps around");
7720Sstevel@tonic-gate 	buffer_clear(&outgoing_packet);
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	if (type == SSH2_MSG_NEWKEYS)
7750Sstevel@tonic-gate #ifdef ALTPRIVSEP
7760Sstevel@tonic-gate 		/* set_newkeys(MODE_OUT) in client, server, but not monitor */
7770Sstevel@tonic-gate 		if (!packet_is_server() && !packet_is_monitor())
7780Sstevel@tonic-gate #endif /* ALTPRIVSEP */
7790Sstevel@tonic-gate 		set_newkeys(MODE_OUT);
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate void
7830Sstevel@tonic-gate packet_send(void)
7840Sstevel@tonic-gate {
7850Sstevel@tonic-gate 	if (compat20)
7860Sstevel@tonic-gate 		packet_send2();
7870Sstevel@tonic-gate 	else
7880Sstevel@tonic-gate 		packet_send1();
7890Sstevel@tonic-gate 	DBG(debug("packet_send done"));
7900Sstevel@tonic-gate }
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate /*
7930Sstevel@tonic-gate  * Waits until a packet has been received, and returns its type.  Note that
7940Sstevel@tonic-gate  * no other data is processed until this returns, so this function should not
7950Sstevel@tonic-gate  * be used during the interactive session.
7960Sstevel@tonic-gate  */
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate int
7990Sstevel@tonic-gate packet_read_seqnr(u_int32_t *seqnr_p)
8000Sstevel@tonic-gate {
8010Sstevel@tonic-gate 	int type, len;
8020Sstevel@tonic-gate 	fd_set *setp;
8030Sstevel@tonic-gate 	char buf[8192];
8040Sstevel@tonic-gate 	DBG(debug("packet_read()"));
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) *
8070Sstevel@tonic-gate 	    sizeof(fd_mask));
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	/* Since we are blocking, ensure that all written packets have been sent. */
8100Sstevel@tonic-gate 	packet_write_wait();
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	/* Stay in the loop until we have received a complete packet. */
8130Sstevel@tonic-gate 	for (;;) {
8140Sstevel@tonic-gate 		/* Try to read a packet from the buffer. */
8150Sstevel@tonic-gate 		type = packet_read_poll_seqnr(seqnr_p);
8160Sstevel@tonic-gate 		if (!compat20 && (
8170Sstevel@tonic-gate 		    type == SSH_SMSG_SUCCESS
8180Sstevel@tonic-gate 		    || type == SSH_SMSG_FAILURE
8190Sstevel@tonic-gate 		    || type == SSH_CMSG_EOF
8200Sstevel@tonic-gate 		    || type == SSH_CMSG_EXIT_CONFIRMATION))
8210Sstevel@tonic-gate 			packet_check_eom();
8220Sstevel@tonic-gate 		/* If we got a packet, return it. */
8230Sstevel@tonic-gate 		if (type != SSH_MSG_NONE) {
8240Sstevel@tonic-gate 			xfree(setp);
8250Sstevel@tonic-gate 			return type;
8260Sstevel@tonic-gate 		}
8270Sstevel@tonic-gate 		/*
8280Sstevel@tonic-gate 		 * Otherwise, wait for some data to arrive, add it to the
8290Sstevel@tonic-gate 		 * buffer, and try again.
8300Sstevel@tonic-gate 		 */
8310Sstevel@tonic-gate 		memset(setp, 0, howmany(connection_in + 1, NFDBITS) *
8320Sstevel@tonic-gate 		    sizeof(fd_mask));
8330Sstevel@tonic-gate 		FD_SET(connection_in, setp);
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 		/* Wait for some data to arrive. */
8360Sstevel@tonic-gate 		while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
8370Sstevel@tonic-gate 		    (errno == EAGAIN || errno == EINTR))
8380Sstevel@tonic-gate 			;
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 		/* Read data from the socket. */
8410Sstevel@tonic-gate 		len = read(connection_in, buf, sizeof(buf));
8420Sstevel@tonic-gate 		if (len == 0) {
8430Sstevel@tonic-gate 			log("Connection closed by %.200s", get_remote_ipaddr());
8440Sstevel@tonic-gate 			fatal_cleanup();
8450Sstevel@tonic-gate 		}
8460Sstevel@tonic-gate 		if (len < 0)
8470Sstevel@tonic-gate 			fatal("Read from socket failed: %.100s", strerror(errno));
8480Sstevel@tonic-gate 		/* Append it to the buffer. */
8490Sstevel@tonic-gate 		packet_process_incoming(buf, len);
8500Sstevel@tonic-gate 	}
8510Sstevel@tonic-gate 	/* NOTREACHED */
8520Sstevel@tonic-gate }
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate int
8550Sstevel@tonic-gate packet_read(void)
8560Sstevel@tonic-gate {
8570Sstevel@tonic-gate 	return packet_read_seqnr(NULL);
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate /*
8610Sstevel@tonic-gate  * Waits until a packet has been received, verifies that its type matches
8620Sstevel@tonic-gate  * that given, and gives a fatal error and exits if there is a mismatch.
8630Sstevel@tonic-gate  */
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate void
8660Sstevel@tonic-gate packet_read_expect(int expected_type)
8670Sstevel@tonic-gate {
8680Sstevel@tonic-gate 	int type;
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	type = packet_read();
8710Sstevel@tonic-gate 	if (type != expected_type)
8720Sstevel@tonic-gate 		packet_disconnect("Protocol error: expected packet type %d, got %d",
8730Sstevel@tonic-gate 		    expected_type, type);
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate /* Checks if a full packet is available in the data received so far via
8770Sstevel@tonic-gate  * packet_process_incoming.  If so, reads the packet; otherwise returns
8780Sstevel@tonic-gate  * SSH_MSG_NONE.  This does not wait for data from the connection.
8790Sstevel@tonic-gate  *
8800Sstevel@tonic-gate  * SSH_MSG_DISCONNECT is handled specially here.  Also,
8810Sstevel@tonic-gate  * SSH_MSG_IGNORE messages are skipped by this function and are never returned
8820Sstevel@tonic-gate  * to higher levels.
8830Sstevel@tonic-gate  */
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate static int
8860Sstevel@tonic-gate packet_read_poll1(void)
8870Sstevel@tonic-gate {
8880Sstevel@tonic-gate 	u_int len, padded_len;
8890Sstevel@tonic-gate 	u_char *cp, type;
8900Sstevel@tonic-gate 	u_int checksum, stored_checksum;
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	/* Check if input size is less than minimum packet size. */
8930Sstevel@tonic-gate 	if (buffer_len(&input) < 4 + 8)
8940Sstevel@tonic-gate 		return SSH_MSG_NONE;
8950Sstevel@tonic-gate 	/* Get length of incoming packet. */
8960Sstevel@tonic-gate 	cp = buffer_ptr(&input);
8970Sstevel@tonic-gate 	len = GET_32BIT(cp);
8980Sstevel@tonic-gate 	if (len < 1 + 2 + 2 || len > 256 * 1024)
8990Sstevel@tonic-gate 		packet_disconnect("Bad packet length %d.", len);
9000Sstevel@tonic-gate 	padded_len = (len + 8) & ~7;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	/* Check if the packet has been entirely received. */
9030Sstevel@tonic-gate 	if (buffer_len(&input) < 4 + padded_len)
9040Sstevel@tonic-gate 		return SSH_MSG_NONE;
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	/* The entire packet is in buffer. */
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	/* Consume packet length. */
9090Sstevel@tonic-gate 	buffer_consume(&input, 4);
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	/*
9120Sstevel@tonic-gate 	 * Cryptographic attack detector for ssh
9130Sstevel@tonic-gate 	 * (C)1998 CORE-SDI, Buenos Aires Argentina
9140Sstevel@tonic-gate 	 * Ariel Futoransky(futo@core-sdi.com)
9150Sstevel@tonic-gate 	 */
916*3102Sjp161948 	if (!receive_context.plaintext) {
917*3102Sjp161948 		switch (detect_attack(buffer_ptr(&input), padded_len, NULL)) {
918*3102Sjp161948 		case DEATTACK_DETECTED:
919*3102Sjp161948 			packet_disconnect("crc32 compensation attack: "
920*3102Sjp161948 			    "network attack detected");
921*3102Sjp161948 			break;
922*3102Sjp161948 		case DEATTACK_DOS_DETECTED:
923*3102Sjp161948 			packet_disconnect("deattack denial of "
924*3102Sjp161948 			    "service detected");
925*3102Sjp161948 			break;
926*3102Sjp161948 		}
927*3102Sjp161948 	}
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	/* Decrypt data to incoming_packet. */
9300Sstevel@tonic-gate 	buffer_clear(&incoming_packet);
9310Sstevel@tonic-gate 	cp = buffer_append_space(&incoming_packet, padded_len);
9320Sstevel@tonic-gate 	cipher_crypt(&receive_context, cp, buffer_ptr(&input), padded_len);
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	buffer_consume(&input, padded_len);
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate #ifdef PACKET_DEBUG
9370Sstevel@tonic-gate 	fprintf(stderr, "read_poll plain: ");
9380Sstevel@tonic-gate 	buffer_dump(&incoming_packet);
9390Sstevel@tonic-gate #endif
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	/* Compute packet checksum. */
9420Sstevel@tonic-gate 	checksum = ssh_crc32(buffer_ptr(&incoming_packet),
9430Sstevel@tonic-gate 	    buffer_len(&incoming_packet) - 4);
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	/* Skip padding. */
9460Sstevel@tonic-gate 	buffer_consume(&incoming_packet, 8 - len % 8);
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	/* Test check bytes. */
9490Sstevel@tonic-gate 	if (len != buffer_len(&incoming_packet))
9500Sstevel@tonic-gate 		packet_disconnect("packet_read_poll1: len %d != buffer_len %d.",
9510Sstevel@tonic-gate 		    len, buffer_len(&incoming_packet));
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4;
9540Sstevel@tonic-gate 	stored_checksum = GET_32BIT(cp);
9550Sstevel@tonic-gate 	if (checksum != stored_checksum)
9560Sstevel@tonic-gate 		packet_disconnect("Corrupted check bytes on input.");
9570Sstevel@tonic-gate 	buffer_consume_end(&incoming_packet, 4);
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	if (packet_compression) {
9600Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
9610Sstevel@tonic-gate 		buffer_uncompress(&incoming_packet, &compression_buffer);
9620Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
9630Sstevel@tonic-gate 		buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
9640Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
9650Sstevel@tonic-gate 	}
9660Sstevel@tonic-gate 	type = buffer_get_char(&incoming_packet);
9670Sstevel@tonic-gate 	return type;
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate static int
9710Sstevel@tonic-gate packet_read_poll2(u_int32_t *seqnr_p)
9720Sstevel@tonic-gate {
9730Sstevel@tonic-gate 	static u_int packet_length = 0;
9740Sstevel@tonic-gate 	u_int padlen, need;
9750Sstevel@tonic-gate 	u_char *macbuf, *cp, type;
9760Sstevel@tonic-gate 	int maclen, block_size;
9770Sstevel@tonic-gate 	Enc *enc   = NULL;
9780Sstevel@tonic-gate 	Mac *mac   = NULL;
9790Sstevel@tonic-gate 	Comp *comp = NULL;
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	if (newkeys[MODE_IN] != NULL) {
9820Sstevel@tonic-gate 		enc  = &newkeys[MODE_IN]->enc;
9830Sstevel@tonic-gate 		mac  = &newkeys[MODE_IN]->mac;
9840Sstevel@tonic-gate 		comp = &newkeys[MODE_IN]->comp;
9850Sstevel@tonic-gate 	}
9860Sstevel@tonic-gate 	maclen = mac && mac->enabled ? mac->mac_len : 0;
9870Sstevel@tonic-gate 	block_size = enc ? enc->block_size : 8;
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	if (packet_length == 0) {
9900Sstevel@tonic-gate 		/*
9910Sstevel@tonic-gate 		 * check if input size is less than the cipher block size,
9920Sstevel@tonic-gate 		 * decrypt first block and extract length of incoming packet
9930Sstevel@tonic-gate 		 */
9940Sstevel@tonic-gate 		if (buffer_len(&input) < block_size)
9950Sstevel@tonic-gate 			return SSH_MSG_NONE;
9960Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
9970Sstevel@tonic-gate 		cp = buffer_append_space(&incoming_packet, block_size);
9980Sstevel@tonic-gate 		cipher_crypt(&receive_context, cp, buffer_ptr(&input),
9990Sstevel@tonic-gate 		    block_size);
10000Sstevel@tonic-gate 		cp = buffer_ptr(&incoming_packet);
10010Sstevel@tonic-gate 		packet_length = GET_32BIT(cp);
10020Sstevel@tonic-gate 		if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
10030Sstevel@tonic-gate 			buffer_dump(&incoming_packet);
10040Sstevel@tonic-gate 			packet_disconnect("Bad packet length %d.", packet_length);
10050Sstevel@tonic-gate 		}
10060Sstevel@tonic-gate 		DBG(debug("input: packet len %d", packet_length+4));
10070Sstevel@tonic-gate 		buffer_consume(&input, block_size);
10080Sstevel@tonic-gate 	}
10090Sstevel@tonic-gate 	/* we have a partial packet of block_size bytes */
10100Sstevel@tonic-gate 	need = 4 + packet_length - block_size;
10110Sstevel@tonic-gate 	DBG(debug("partial packet %d, need %d, maclen %d", block_size,
10120Sstevel@tonic-gate 	    need, maclen));
10130Sstevel@tonic-gate 	if (need % block_size != 0)
10140Sstevel@tonic-gate 		fatal("padding error: need %d block %d mod %d",
10150Sstevel@tonic-gate 		    need, block_size, need % block_size);
10160Sstevel@tonic-gate 	/*
10170Sstevel@tonic-gate 	 * check if the entire packet has been received and
10180Sstevel@tonic-gate 	 * decrypt into incoming_packet
10190Sstevel@tonic-gate 	 */
10200Sstevel@tonic-gate 	if (buffer_len(&input) < need + maclen)
10210Sstevel@tonic-gate 		return SSH_MSG_NONE;
10220Sstevel@tonic-gate #ifdef PACKET_DEBUG
10230Sstevel@tonic-gate 	fprintf(stderr, "read_poll enc/full: ");
10240Sstevel@tonic-gate 	buffer_dump(&input);
10250Sstevel@tonic-gate #endif
10260Sstevel@tonic-gate 	cp = buffer_append_space(&incoming_packet, need);
10270Sstevel@tonic-gate 	cipher_crypt(&receive_context, cp, buffer_ptr(&input), need);
10280Sstevel@tonic-gate 	buffer_consume(&input, need);
10290Sstevel@tonic-gate 	/*
10300Sstevel@tonic-gate 	 * compute MAC over seqnr and packet,
10310Sstevel@tonic-gate 	 * increment sequence number for incoming packet
10320Sstevel@tonic-gate 	 */
10330Sstevel@tonic-gate 	if (mac && mac->enabled) {
10340Sstevel@tonic-gate 		macbuf = mac_compute(mac, read_seqnr,
10350Sstevel@tonic-gate 		    buffer_ptr(&incoming_packet),
10360Sstevel@tonic-gate 		    buffer_len(&incoming_packet));
10370Sstevel@tonic-gate 		if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
10380Sstevel@tonic-gate 			packet_disconnect("Corrupted MAC on input.");
10390Sstevel@tonic-gate 		DBG(debug("MAC #%d ok", read_seqnr));
10400Sstevel@tonic-gate 		buffer_consume(&input, mac->mac_len);
10410Sstevel@tonic-gate 	}
10420Sstevel@tonic-gate 	if (seqnr_p != NULL)
10430Sstevel@tonic-gate 		*seqnr_p = read_seqnr;
10440Sstevel@tonic-gate 	if (++read_seqnr == 0)
10450Sstevel@tonic-gate 		log("incoming seqnr wraps around");
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	/* get padlen */
10480Sstevel@tonic-gate 	cp = buffer_ptr(&incoming_packet);
10490Sstevel@tonic-gate 	padlen = cp[4];
10500Sstevel@tonic-gate 	DBG(debug("input: padlen %d", padlen));
10510Sstevel@tonic-gate 	if (padlen < 4)
10520Sstevel@tonic-gate 		packet_disconnect("Corrupted padlen %d on input.", padlen);
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	/* skip packet size + padlen, discard padding */
10550Sstevel@tonic-gate 	buffer_consume(&incoming_packet, 4 + 1);
10560Sstevel@tonic-gate 	buffer_consume_end(&incoming_packet, padlen);
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet)));
10590Sstevel@tonic-gate 	if (comp && comp->enabled) {
10600Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
10610Sstevel@tonic-gate 		buffer_uncompress(&incoming_packet, &compression_buffer);
10620Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
10630Sstevel@tonic-gate 		buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
10640Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
10650Sstevel@tonic-gate 		DBG(debug("input: len after de-compress %d",
10660Sstevel@tonic-gate 		    buffer_len(&incoming_packet)));
10670Sstevel@tonic-gate 	}
10680Sstevel@tonic-gate 	/*
10690Sstevel@tonic-gate 	 * get packet type, implies consume.
10700Sstevel@tonic-gate 	 * return length of payload (without type field)
10710Sstevel@tonic-gate 	 */
10720Sstevel@tonic-gate 	type = buffer_get_char(&incoming_packet);
10730Sstevel@tonic-gate #ifdef ALTPRIVSEP
10740Sstevel@tonic-gate 	if (type == SSH2_MSG_NEWKEYS)
10750Sstevel@tonic-gate 		/* set_newkeys(MODE_OUT) in client, server, but not monitor */
10760Sstevel@tonic-gate 		if (!packet_is_server() && !packet_is_monitor())
10770Sstevel@tonic-gate 			set_newkeys(MODE_IN);
10780Sstevel@tonic-gate #else /* ALTPRIVSEP */
10790Sstevel@tonic-gate 	if (type == SSH2_MSG_NEWKEYS)
10800Sstevel@tonic-gate 		set_newkeys(MODE_IN);
10810Sstevel@tonic-gate #endif /* ALTPRIVSEP */
10820Sstevel@tonic-gate #ifdef PACKET_DEBUG
10830Sstevel@tonic-gate 	fprintf(stderr, "read/plain[%d]:\r\n", type);
10840Sstevel@tonic-gate 	buffer_dump(&incoming_packet);
10850Sstevel@tonic-gate #endif
10860Sstevel@tonic-gate 	/* reset for next packet */
10870Sstevel@tonic-gate 	packet_length = 0;
10880Sstevel@tonic-gate 	return type;
10890Sstevel@tonic-gate }
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate int
10920Sstevel@tonic-gate packet_read_poll_seqnr(u_int32_t *seqnr_p)
10930Sstevel@tonic-gate {
10940Sstevel@tonic-gate 	u_int reason, seqnr;
10950Sstevel@tonic-gate 	u_char type;
10960Sstevel@tonic-gate 	char *msg;
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	for (;;) {
10990Sstevel@tonic-gate 		if (compat20) {
11000Sstevel@tonic-gate 			type = packet_read_poll2(seqnr_p);
11010Sstevel@tonic-gate 			DBG(debug("received packet type %d", type));
11020Sstevel@tonic-gate 			switch (type) {
11030Sstevel@tonic-gate 			case SSH2_MSG_IGNORE:
11040Sstevel@tonic-gate 				break;
11050Sstevel@tonic-gate 			case SSH2_MSG_DEBUG:
11060Sstevel@tonic-gate 				packet_get_char();
11070Sstevel@tonic-gate 				msg = packet_get_string(NULL);
11080Sstevel@tonic-gate 				debug("Remote: %.900s", msg);
11090Sstevel@tonic-gate 				xfree(msg);
11100Sstevel@tonic-gate 				msg = packet_get_string(NULL);
11110Sstevel@tonic-gate 				xfree(msg);
11120Sstevel@tonic-gate 				break;
11130Sstevel@tonic-gate 			case SSH2_MSG_DISCONNECT:
11140Sstevel@tonic-gate 				reason = packet_get_int();
11150Sstevel@tonic-gate 				msg = packet_get_string(NULL);
11160Sstevel@tonic-gate 				log("Received disconnect from %s: %u: %.400s",
11170Sstevel@tonic-gate 				    get_remote_ipaddr(), reason, msg);
11180Sstevel@tonic-gate 				xfree(msg);
11190Sstevel@tonic-gate 				fatal_cleanup();
11200Sstevel@tonic-gate 				break;
11210Sstevel@tonic-gate 			case SSH2_MSG_UNIMPLEMENTED:
11220Sstevel@tonic-gate 				seqnr = packet_get_int();
11230Sstevel@tonic-gate 				debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
11240Sstevel@tonic-gate 				    seqnr);
11250Sstevel@tonic-gate 				break;
11260Sstevel@tonic-gate 			default:
11270Sstevel@tonic-gate 				return type;
11280Sstevel@tonic-gate 				break;
11290Sstevel@tonic-gate 			}
11300Sstevel@tonic-gate 		} else {
11310Sstevel@tonic-gate 			type = packet_read_poll1();
11320Sstevel@tonic-gate 			DBG(debug("received packet type %d", type));
11330Sstevel@tonic-gate 			switch (type) {
11340Sstevel@tonic-gate 			case SSH_MSG_IGNORE:
11350Sstevel@tonic-gate 				break;
11360Sstevel@tonic-gate 			case SSH_MSG_DEBUG:
11370Sstevel@tonic-gate 				msg = packet_get_string(NULL);
11380Sstevel@tonic-gate 				debug("Remote: %.900s", msg);
11390Sstevel@tonic-gate 				xfree(msg);
11400Sstevel@tonic-gate 				break;
11410Sstevel@tonic-gate 			case SSH_MSG_DISCONNECT:
11420Sstevel@tonic-gate 				msg = packet_get_string(NULL);
11430Sstevel@tonic-gate 				log("Received disconnect from %s: %.400s",
11440Sstevel@tonic-gate 				    get_remote_ipaddr(), msg);
11450Sstevel@tonic-gate 				fatal_cleanup();
11460Sstevel@tonic-gate 				xfree(msg);
11470Sstevel@tonic-gate 				break;
11480Sstevel@tonic-gate 			default:
11490Sstevel@tonic-gate 				return type;
11500Sstevel@tonic-gate 				break;
11510Sstevel@tonic-gate 			}
11520Sstevel@tonic-gate 		}
11530Sstevel@tonic-gate 	}
11540Sstevel@tonic-gate }
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate int
11570Sstevel@tonic-gate packet_read_poll(void)
11580Sstevel@tonic-gate {
11590Sstevel@tonic-gate 	return packet_read_poll_seqnr(NULL);
11600Sstevel@tonic-gate }
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate /*
11630Sstevel@tonic-gate  * Buffers the given amount of input characters.  This is intended to be used
11640Sstevel@tonic-gate  * together with packet_read_poll.
11650Sstevel@tonic-gate  */
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate void
11680Sstevel@tonic-gate packet_process_incoming(const char *buf, u_int len)
11690Sstevel@tonic-gate {
11700Sstevel@tonic-gate 	buffer_append(&input, buf, len);
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate /* Returns a character from the packet. */
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate u_int
11760Sstevel@tonic-gate packet_get_char(void)
11770Sstevel@tonic-gate {
11780Sstevel@tonic-gate 	char ch;
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 	buffer_get(&incoming_packet, &ch, 1);
11810Sstevel@tonic-gate 	return (u_char) ch;
11820Sstevel@tonic-gate }
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate /* Returns an integer from the packet data. */
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate u_int
11870Sstevel@tonic-gate packet_get_int(void)
11880Sstevel@tonic-gate {
11890Sstevel@tonic-gate 	return buffer_get_int(&incoming_packet);
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate /*
11930Sstevel@tonic-gate  * Returns an arbitrary precision integer from the packet data.  The integer
11940Sstevel@tonic-gate  * must have been initialized before this call.
11950Sstevel@tonic-gate  */
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate void
11980Sstevel@tonic-gate packet_get_bignum(BIGNUM * value)
11990Sstevel@tonic-gate {
12000Sstevel@tonic-gate 	buffer_get_bignum(&incoming_packet, value);
12010Sstevel@tonic-gate }
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate void
12040Sstevel@tonic-gate packet_get_bignum2(BIGNUM * value)
12050Sstevel@tonic-gate {
12060Sstevel@tonic-gate 	buffer_get_bignum2(&incoming_packet, value);
12070Sstevel@tonic-gate }
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate void *
12100Sstevel@tonic-gate packet_get_raw(u_int *length_ptr)
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate 	u_int bytes = buffer_len(&incoming_packet);
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	if (length_ptr != NULL)
12150Sstevel@tonic-gate 		*length_ptr = bytes;
12160Sstevel@tonic-gate 	return buffer_ptr(&incoming_packet);
12170Sstevel@tonic-gate }
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate int
12200Sstevel@tonic-gate packet_remaining(void)
12210Sstevel@tonic-gate {
12220Sstevel@tonic-gate 	return buffer_len(&incoming_packet);
12230Sstevel@tonic-gate }
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate /*
12260Sstevel@tonic-gate  * Returns a string from the packet data.  The string is allocated using
12270Sstevel@tonic-gate  * xmalloc; it is the responsibility of the calling program to free it when
12280Sstevel@tonic-gate  * no longer needed.  The length_ptr argument may be NULL, or point to an
12290Sstevel@tonic-gate  * integer into which the length of the string is stored.
12300Sstevel@tonic-gate  */
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate void *
12330Sstevel@tonic-gate packet_get_string(u_int *length_ptr)
12340Sstevel@tonic-gate {
12350Sstevel@tonic-gate 	return buffer_get_string(&incoming_packet, length_ptr);
12360Sstevel@tonic-gate }
12370Sstevel@tonic-gate char *
12380Sstevel@tonic-gate packet_get_ascii_cstring()
12390Sstevel@tonic-gate {
12400Sstevel@tonic-gate 	return buffer_get_ascii_cstring(&incoming_packet);
12410Sstevel@tonic-gate }
12420Sstevel@tonic-gate u_char *
12430Sstevel@tonic-gate packet_get_utf8_cstring()
12440Sstevel@tonic-gate {
12450Sstevel@tonic-gate 	return buffer_get_utf8_cstring(&incoming_packet);
12460Sstevel@tonic-gate }
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate /*
12490Sstevel@tonic-gate  * Sends a diagnostic message from the server to the client.  This message
12500Sstevel@tonic-gate  * can be sent at any time (but not while constructing another message). The
12510Sstevel@tonic-gate  * message is printed immediately, but only if the client is being executed
12520Sstevel@tonic-gate  * in verbose mode.  These messages are primarily intended to ease debugging
12530Sstevel@tonic-gate  * authentication problems.   The length of the formatted message must not
12540Sstevel@tonic-gate  * exceed 1024 bytes.  This will automatically call packet_write_wait.
12550Sstevel@tonic-gate  */
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate void
12580Sstevel@tonic-gate packet_send_debug(const char *fmt,...)
12590Sstevel@tonic-gate {
12600Sstevel@tonic-gate 	char buf[1024];
12610Sstevel@tonic-gate 	va_list args;
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 	if (compat20 && (datafellows & SSH_BUG_DEBUG))
12640Sstevel@tonic-gate 		return;
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	va_start(args, fmt);
12670Sstevel@tonic-gate 	vsnprintf(buf, sizeof(buf), gettext(fmt), args);
12680Sstevel@tonic-gate 	va_end(args);
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate #ifdef ALTPRIVSEP
12710Sstevel@tonic-gate 	/* shouldn't happen */
12720Sstevel@tonic-gate 	if (packet_monitor) {
12730Sstevel@tonic-gate 		debug("packet_send_debug: %s", buf);
12740Sstevel@tonic-gate 		return;
12750Sstevel@tonic-gate 	}
12760Sstevel@tonic-gate #endif /* ALTPRIVSEP */
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	if (compat20) {
12790Sstevel@tonic-gate 		packet_start(SSH2_MSG_DEBUG);
12800Sstevel@tonic-gate 		packet_put_char(0);	/* bool: always display */
12810Sstevel@tonic-gate 		packet_put_cstring(buf);
12820Sstevel@tonic-gate 		packet_put_cstring("");
12830Sstevel@tonic-gate 	} else {
12840Sstevel@tonic-gate 		packet_start(SSH_MSG_DEBUG);
12850Sstevel@tonic-gate 		packet_put_cstring(buf);
12860Sstevel@tonic-gate 	}
12870Sstevel@tonic-gate 	packet_send();
12880Sstevel@tonic-gate 	packet_write_wait();
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate /*
12920Sstevel@tonic-gate  * Logs the error plus constructs and sends a disconnect packet, closes the
12930Sstevel@tonic-gate  * connection, and exits.  This function never returns. The error message
12940Sstevel@tonic-gate  * should not contain a newline.  The length of the formatted message must
12950Sstevel@tonic-gate  * not exceed 1024 bytes.
12960Sstevel@tonic-gate  */
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate void
12990Sstevel@tonic-gate packet_disconnect(const char *fmt,...)
13000Sstevel@tonic-gate {
13010Sstevel@tonic-gate 	char buf[1024];
13020Sstevel@tonic-gate 	va_list args;
13030Sstevel@tonic-gate 	static int disconnecting = 0;
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	if (disconnecting)	/* Guard against recursive invocations. */
13060Sstevel@tonic-gate 		fatal("packet_disconnect called recursively.");
13070Sstevel@tonic-gate 	disconnecting = 1;
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 	/*
13100Sstevel@tonic-gate 	 * Format the message.  Note that the caller must make sure the
13110Sstevel@tonic-gate 	 * message is of limited size.
13120Sstevel@tonic-gate 	 */
13130Sstevel@tonic-gate 	va_start(args, fmt);
13140Sstevel@tonic-gate 	vsnprintf(buf, sizeof(buf), fmt, args);
13150Sstevel@tonic-gate 	va_end(args);
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate #ifdef ALTPRIVSEP
13180Sstevel@tonic-gate 	/*
13190Sstevel@tonic-gate 	 * If we packet_disconnect() in the monitor the fatal cleanups will take
13200Sstevel@tonic-gate 	 * care of the child.  See main() in sshd.c.  We don't send the packet
13210Sstevel@tonic-gate 	 * disconnect message here because: a) the child might not be looking
13220Sstevel@tonic-gate 	 * for it and b) because we don't really know if the child is compat20
13230Sstevel@tonic-gate 	 * or not as we lost that information when packet_set_monitor() was
13240Sstevel@tonic-gate 	 * called.
13250Sstevel@tonic-gate 	 */
13260Sstevel@tonic-gate 	if (packet_monitor)
13270Sstevel@tonic-gate 		goto close_stuff;
13280Sstevel@tonic-gate #endif /* ALTPRIVSEP */
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	/* Send the disconnect message to the other side, and wait for it to get sent. */
13310Sstevel@tonic-gate 	if (compat20) {
13320Sstevel@tonic-gate 		packet_start(SSH2_MSG_DISCONNECT);
13330Sstevel@tonic-gate 		packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR);
13340Sstevel@tonic-gate 		packet_put_cstring(buf);
13350Sstevel@tonic-gate 		packet_put_cstring("");
13360Sstevel@tonic-gate 	} else {
13370Sstevel@tonic-gate 		packet_start(SSH_MSG_DISCONNECT);
13380Sstevel@tonic-gate 		packet_put_cstring(buf);
13390Sstevel@tonic-gate 	}
13400Sstevel@tonic-gate 	packet_send();
13410Sstevel@tonic-gate 	packet_write_wait();
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate #ifdef ALTPRIVSEP
13440Sstevel@tonic-gate close_stuff:
13450Sstevel@tonic-gate #endif /* ALTPRIVSEP */
13460Sstevel@tonic-gate 	/* Stop listening for connections. */
13470Sstevel@tonic-gate 	channel_close_all();
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	/* Close the connection. */
13500Sstevel@tonic-gate 	packet_close();
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate 	/* Display the error locally and exit. */
13530Sstevel@tonic-gate 	log("Disconnecting: %.100s", buf);
13540Sstevel@tonic-gate 	fatal_cleanup();
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate /* Checks if there is any buffered output, and tries to write some of the output. */
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate void
13600Sstevel@tonic-gate packet_write_poll(void)
13610Sstevel@tonic-gate {
13620Sstevel@tonic-gate 	int len = buffer_len(&output);
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 	if (len > 0) {
13650Sstevel@tonic-gate 		len = write(connection_out, buffer_ptr(&output), len);
13660Sstevel@tonic-gate 		if (len <= 0) {
13670Sstevel@tonic-gate 			if (errno == EAGAIN)
13680Sstevel@tonic-gate 				return;
13690Sstevel@tonic-gate 			else
13700Sstevel@tonic-gate 				fatal("Write failed: %.100s", strerror(errno));
13710Sstevel@tonic-gate 		}
13720Sstevel@tonic-gate 		buffer_consume(&output, len);
13730Sstevel@tonic-gate 	}
13740Sstevel@tonic-gate }
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate /*
13770Sstevel@tonic-gate  * Calls packet_write_poll repeatedly until all pending output data has been
13780Sstevel@tonic-gate  * written.
13790Sstevel@tonic-gate  */
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate void
13820Sstevel@tonic-gate packet_write_wait(void)
13830Sstevel@tonic-gate {
13840Sstevel@tonic-gate 	fd_set *setp;
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) *
13870Sstevel@tonic-gate 	    sizeof(fd_mask));
13880Sstevel@tonic-gate 	packet_write_poll();
13890Sstevel@tonic-gate 	while (packet_have_data_to_write()) {
13900Sstevel@tonic-gate 		memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
13910Sstevel@tonic-gate 		    sizeof(fd_mask));
13920Sstevel@tonic-gate 		FD_SET(connection_out, setp);
13930Sstevel@tonic-gate 		while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
13940Sstevel@tonic-gate 		    (errno == EAGAIN || errno == EINTR))
13950Sstevel@tonic-gate 			;
13960Sstevel@tonic-gate 		packet_write_poll();
13970Sstevel@tonic-gate 	}
13980Sstevel@tonic-gate 	xfree(setp);
13990Sstevel@tonic-gate }
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate /* Returns true if there is buffered data to write to the connection. */
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate int
14040Sstevel@tonic-gate packet_have_data_to_write(void)
14050Sstevel@tonic-gate {
14060Sstevel@tonic-gate 	return buffer_len(&output) != 0;
14070Sstevel@tonic-gate }
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate /* Returns true if there is not too much data to write to the connection. */
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate int
14120Sstevel@tonic-gate packet_not_very_much_data_to_write(void)
14130Sstevel@tonic-gate {
14140Sstevel@tonic-gate 	if (interactive_mode)
14150Sstevel@tonic-gate 		return buffer_len(&output) < 16384;
14160Sstevel@tonic-gate 	else
14170Sstevel@tonic-gate 		return buffer_len(&output) < 128 * 1024;
14180Sstevel@tonic-gate }
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate /* Informs that the current session is interactive.  Sets IP flags for that. */
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate void
14230Sstevel@tonic-gate packet_set_interactive(int interactive)
14240Sstevel@tonic-gate {
14250Sstevel@tonic-gate 	static int called = 0;
14260Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
14270Sstevel@tonic-gate 	int lowdelay = IPTOS_LOWDELAY;
14280Sstevel@tonic-gate 	int throughput = IPTOS_THROUGHPUT;
14290Sstevel@tonic-gate #endif
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	if (called)
14320Sstevel@tonic-gate 		return;
14330Sstevel@tonic-gate 	called = 1;
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	/* Record that we are in interactive mode. */
14360Sstevel@tonic-gate 	interactive_mode = interactive;
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	/* Only set socket options if using a socket.  */
14390Sstevel@tonic-gate 	if (!packet_connection_is_on_socket())
14400Sstevel@tonic-gate 		return;
14410Sstevel@tonic-gate 	/*
14420Sstevel@tonic-gate 	 * IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only
14430Sstevel@tonic-gate 	 */
14440Sstevel@tonic-gate 	if (interactive) {
14450Sstevel@tonic-gate 		/*
14460Sstevel@tonic-gate 		 * Set IP options for an interactive connection.  Use
14470Sstevel@tonic-gate 		 * IPTOS_LOWDELAY and TCP_NODELAY.
14480Sstevel@tonic-gate 		 */
14490Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
14500Sstevel@tonic-gate 		if (packet_connection_is_ipv4()) {
14510Sstevel@tonic-gate 			if (setsockopt(connection_in, IPPROTO_IP, IP_TOS,
14520Sstevel@tonic-gate 			    &lowdelay, sizeof(lowdelay)) < 0)
14530Sstevel@tonic-gate 				error("setsockopt IPTOS_LOWDELAY: %.100s",
14540Sstevel@tonic-gate 				    strerror(errno));
14550Sstevel@tonic-gate 		}
14560Sstevel@tonic-gate #endif
14570Sstevel@tonic-gate 		set_nodelay(connection_in);
14580Sstevel@tonic-gate 	}
14590Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
14600Sstevel@tonic-gate 	else if (packet_connection_is_ipv4()) {
14610Sstevel@tonic-gate 		/*
14620Sstevel@tonic-gate 		 * Set IP options for a non-interactive connection.  Use
14630Sstevel@tonic-gate 		 * IPTOS_THROUGHPUT.
14640Sstevel@tonic-gate 		 */
14650Sstevel@tonic-gate 		if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &throughput,
14660Sstevel@tonic-gate 		    sizeof(throughput)) < 0)
14670Sstevel@tonic-gate 			error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
14680Sstevel@tonic-gate 	}
14690Sstevel@tonic-gate #endif
14700Sstevel@tonic-gate }
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate /* Returns true if the current connection is interactive. */
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate int
14750Sstevel@tonic-gate packet_is_interactive(void)
14760Sstevel@tonic-gate {
14770Sstevel@tonic-gate 	return interactive_mode;
14780Sstevel@tonic-gate }
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate int
14810Sstevel@tonic-gate packet_set_maxsize(int s)
14820Sstevel@tonic-gate {
14830Sstevel@tonic-gate 	static int called = 0;
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate 	if (called) {
14860Sstevel@tonic-gate 		log("packet_set_maxsize: called twice: old %d new %d",
14870Sstevel@tonic-gate 		    max_packet_size, s);
14880Sstevel@tonic-gate 		return -1;
14890Sstevel@tonic-gate 	}
14900Sstevel@tonic-gate 	if (s < 4 * 1024 || s > 1024 * 1024) {
14910Sstevel@tonic-gate 		log("packet_set_maxsize: bad size %d", s);
14920Sstevel@tonic-gate 		return -1;
14930Sstevel@tonic-gate 	}
14940Sstevel@tonic-gate 	called = 1;
14950Sstevel@tonic-gate 	debug("packet_set_maxsize: setting to %d", s);
14960Sstevel@tonic-gate 	max_packet_size = s;
14970Sstevel@tonic-gate 	return s;
14980Sstevel@tonic-gate }
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate /* roundup current message to pad bytes */
15010Sstevel@tonic-gate void
15020Sstevel@tonic-gate packet_add_padding(u_char pad)
15030Sstevel@tonic-gate {
15040Sstevel@tonic-gate 	extra_pad = pad;
15050Sstevel@tonic-gate }
15060Sstevel@tonic-gate 
15070Sstevel@tonic-gate /*
15080Sstevel@tonic-gate  * 9.2.  Ignored Data Message
15090Sstevel@tonic-gate  *
15100Sstevel@tonic-gate  *   byte      SSH_MSG_IGNORE
15110Sstevel@tonic-gate  *   string    data
15120Sstevel@tonic-gate  *
15130Sstevel@tonic-gate  * All implementations MUST understand (and ignore) this message at any
15140Sstevel@tonic-gate  * time (after receiving the protocol version). No implementation is
15150Sstevel@tonic-gate  * required to send them. This message can be used as an additional
15160Sstevel@tonic-gate  * protection measure against advanced traffic analysis techniques.
15170Sstevel@tonic-gate  */
15180Sstevel@tonic-gate void
15190Sstevel@tonic-gate packet_send_ignore(int nbytes)
15200Sstevel@tonic-gate {
15210Sstevel@tonic-gate 	u_int32_t rand = 0;
15220Sstevel@tonic-gate 	int i;
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate #ifdef ALTPRIVSEP
15250Sstevel@tonic-gate 	/* shouldn't happen -- see packet_set_monitor() */
15260Sstevel@tonic-gate 	if (packet_monitor)
15270Sstevel@tonic-gate 		return;
15280Sstevel@tonic-gate #endif /* ALTPRIVSEP */
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 	packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE);
15310Sstevel@tonic-gate 	packet_put_int(nbytes);
15320Sstevel@tonic-gate 	for (i = 0; i < nbytes; i++) {
15330Sstevel@tonic-gate 		if (i % 4 == 0)
15340Sstevel@tonic-gate 			rand = arc4random();
15350Sstevel@tonic-gate 		packet_put_char(rand & 0xff);
15360Sstevel@tonic-gate 		rand >>= 8;
15370Sstevel@tonic-gate 	}
15380Sstevel@tonic-gate }
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate #ifdef ALTPRIVSEP
15410Sstevel@tonic-gate void
15420Sstevel@tonic-gate packet_set_server(void)
15430Sstevel@tonic-gate {
15440Sstevel@tonic-gate 	packet_server = 1;
15450Sstevel@tonic-gate }
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate void
15480Sstevel@tonic-gate packet_set_no_monitor(void)
15490Sstevel@tonic-gate {
15500Sstevel@tonic-gate 	packet_server = 0;
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate int
15540Sstevel@tonic-gate packet_is_server(void)
15550Sstevel@tonic-gate {
15560Sstevel@tonic-gate 	return (packet_server);
15570Sstevel@tonic-gate }
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate void
15600Sstevel@tonic-gate packet_set_monitor(int pipe)
15610Sstevel@tonic-gate {
15620Sstevel@tonic-gate 	int dup_fd;
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	packet_server = 1;
15650Sstevel@tonic-gate 	packet_monitor = 1;
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate 	/*
15680Sstevel@tonic-gate 	 * Awful hack follows.
15690Sstevel@tonic-gate 	 *
15700Sstevel@tonic-gate 	 * For SSHv1 the monitor does not process any SSHv1 packets, only
15710Sstevel@tonic-gate 	 * ALTPRIVSEP packets.  We take advantage of that here to keep changes
15720Sstevel@tonic-gate 	 * to packet.c to a minimum by using the SSHv2 binary packet protocol,
15730Sstevel@tonic-gate 	 * with cipher "none," mac "none" and compression alg "none," as the
15740Sstevel@tonic-gate 	 * basis for the monitor protocol.  And so to force packet.c to treat
15750Sstevel@tonic-gate 	 * packets as SSHv2 we force compat20 == 1 here.
15760Sstevel@tonic-gate 	 *
15770Sstevel@tonic-gate 	 * For completeness and to help future developers catch this we also
15780Sstevel@tonic-gate 	 * force compat20 == 1 in the monitor loop, in serverloop.c.
15790Sstevel@tonic-gate 	 */
15800Sstevel@tonic-gate 	compat20 = 1;
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 	/*
15830Sstevel@tonic-gate 	 * NOTE:  Assumptions below!
15840Sstevel@tonic-gate 	 *
15850Sstevel@tonic-gate 	 *  - lots of packet.c code assumes that (connection_in ==
15860Sstevel@tonic-gate 	 *  connection_out) -> connection is socket
15870Sstevel@tonic-gate 	 *
15880Sstevel@tonic-gate 	 *  - packet_close() does not shutdown() the connection fildes
15890Sstevel@tonic-gate 	 *  if connection_in != connection_out
15900Sstevel@tonic-gate 	 *
15910Sstevel@tonic-gate 	 *  - other code assumes the connection is a socket if
15920Sstevel@tonic-gate 	 *  connection_in == connection_out
15930Sstevel@tonic-gate 	 */
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	if ((dup_fd = dup(pipe)) < 0)
15960Sstevel@tonic-gate 		fatal("Monitor failed to start: %s", strerror(errno));
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	/*
15990Sstevel@tonic-gate 	 * make sure that the monitor's child's socket is not shutdown(3SOCKET)
16000Sstevel@tonic-gate 	 * when we packet_close()
16010Sstevel@tonic-gate 	 */
16020Sstevel@tonic-gate 	if (packet_connection_is_on_socket())
16030Sstevel@tonic-gate 		connection_out = -1;
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	/* now cleanup state related to ssh socket */
16060Sstevel@tonic-gate 	packet_close();
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 	/* now make the monitor pipe look like the ssh connection */
16090Sstevel@tonic-gate 	packet_set_connection(pipe, dup_fd);
16100Sstevel@tonic-gate }
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate int
16130Sstevel@tonic-gate packet_is_monitor(void)
16140Sstevel@tonic-gate {
16150Sstevel@tonic-gate 	return (packet_monitor);
16160Sstevel@tonic-gate }
16170Sstevel@tonic-gate #endif /* ALTPRIVSEP */
1618