1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3*0Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4*0Sstevel@tonic-gate  *                    All rights reserved
5*0Sstevel@tonic-gate  * This file contains code implementing the packet protocol and communication
6*0Sstevel@tonic-gate  * with the other side.  This same code is used both on client and server side.
7*0Sstevel@tonic-gate  *
8*0Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
9*0Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
10*0Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
11*0Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
12*0Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  *
15*0Sstevel@tonic-gate  * SSH2 packet format added by Markus Friedl.
16*0Sstevel@tonic-gate  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
17*0Sstevel@tonic-gate  *
18*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
19*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
20*0Sstevel@tonic-gate  * are met:
21*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
22*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
23*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
24*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
25*0Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
26*0Sstevel@tonic-gate  *
27*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28*0Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29*0Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30*0Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31*0Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32*0Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33*0Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34*0Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35*0Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36*0Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37*0Sstevel@tonic-gate  */
38*0Sstevel@tonic-gate /*
39*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
40*0Sstevel@tonic-gate  * Use is subject to license terms.
41*0Sstevel@tonic-gate  */
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #include "includes.h"
44*0Sstevel@tonic-gate RCSID("$OpenBSD: packet.c,v 1.97 2002/07/04 08:12:15 deraadt Exp $");
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #include "xmalloc.h"
49*0Sstevel@tonic-gate #include "buffer.h"
50*0Sstevel@tonic-gate #include "packet.h"
51*0Sstevel@tonic-gate #include "bufaux.h"
52*0Sstevel@tonic-gate #include "crc32.h"
53*0Sstevel@tonic-gate #include "getput.h"
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate #include "compress.h"
56*0Sstevel@tonic-gate #include "deattack.h"
57*0Sstevel@tonic-gate #include "channels.h"
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate #include "compat.h"
60*0Sstevel@tonic-gate #include "ssh1.h"
61*0Sstevel@tonic-gate #include "ssh2.h"
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate #include "cipher.h"
64*0Sstevel@tonic-gate #include "kex.h"
65*0Sstevel@tonic-gate #include "mac.h"
66*0Sstevel@tonic-gate #include "log.h"
67*0Sstevel@tonic-gate #include "canohost.h"
68*0Sstevel@tonic-gate #include "misc.h"
69*0Sstevel@tonic-gate #include "ssh.h"
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
72*0Sstevel@tonic-gate static int packet_server = 0;
73*0Sstevel@tonic-gate static int packet_monitor = 0;
74*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate #ifdef PACKET_DEBUG
77*0Sstevel@tonic-gate #define DBG(x) x
78*0Sstevel@tonic-gate #else
79*0Sstevel@tonic-gate #define DBG(x)
80*0Sstevel@tonic-gate #endif
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate /*
83*0Sstevel@tonic-gate  * This variable contains the file descriptors used for communicating with
84*0Sstevel@tonic-gate  * the other side.  connection_in is used for reading; connection_out for
85*0Sstevel@tonic-gate  * writing.  These can be the same descriptor, in which case it is assumed to
86*0Sstevel@tonic-gate  * be a socket.
87*0Sstevel@tonic-gate  */
88*0Sstevel@tonic-gate static int connection_in = -1;
89*0Sstevel@tonic-gate static int connection_out = -1;
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate /* Protocol flags for the remote side. */
92*0Sstevel@tonic-gate static u_int remote_protocol_flags = 0;
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate /* Encryption context for receiving data.  This is only used for decryption. */
95*0Sstevel@tonic-gate static CipherContext receive_context;
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate /* Encryption context for sending data.  This is only used for encryption. */
98*0Sstevel@tonic-gate static CipherContext send_context;
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate /* Buffer for raw input data from the socket. */
101*0Sstevel@tonic-gate Buffer input;
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate /* Buffer for raw output data going to the socket. */
104*0Sstevel@tonic-gate Buffer output;
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate /* Buffer for the partial outgoing packet being constructed. */
107*0Sstevel@tonic-gate static Buffer outgoing_packet;
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate /* Buffer for the incoming packet currently being processed. */
110*0Sstevel@tonic-gate static Buffer incoming_packet;
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate /* Scratch buffer for packet compression/decompression. */
113*0Sstevel@tonic-gate static Buffer compression_buffer;
114*0Sstevel@tonic-gate static int compression_buffer_ready = 0;
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate /* Flag indicating whether packet compression/decompression is enabled. */
117*0Sstevel@tonic-gate static int packet_compression = 0;
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate /* default maximum packet size */
120*0Sstevel@tonic-gate int max_packet_size = 32768;
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate /* Flag indicating whether this module has been initialized. */
123*0Sstevel@tonic-gate static int initialized = 0;
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate /* Set to true if the connection is interactive. */
126*0Sstevel@tonic-gate static int interactive_mode = 0;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate /* Session key information for Encryption and MAC */
129*0Sstevel@tonic-gate Newkeys *newkeys[MODE_MAX];
130*0Sstevel@tonic-gate static u_int32_t read_seqnr = 0;
131*0Sstevel@tonic-gate static u_int32_t send_seqnr = 0;
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate /* Session key for protocol v1 */
134*0Sstevel@tonic-gate static u_char ssh1_key[SSH_SESSION_KEY_LENGTH];
135*0Sstevel@tonic-gate static u_int ssh1_keylen;
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate /* roundup current message to extra_pad bytes */
138*0Sstevel@tonic-gate static u_char extra_pad = 0;
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate /*
141*0Sstevel@tonic-gate  * Sets the descriptors used for communication.  Disables encryption until
142*0Sstevel@tonic-gate  * packet_set_encryption_key is called.
143*0Sstevel@tonic-gate  */
144*0Sstevel@tonic-gate void
145*0Sstevel@tonic-gate packet_set_connection(int fd_in, int fd_out)
146*0Sstevel@tonic-gate {
147*0Sstevel@tonic-gate 	Cipher *none = cipher_by_name("none");
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 	if (none == NULL)
150*0Sstevel@tonic-gate 		fatal("packet_set_connection: cannot load cipher 'none'");
151*0Sstevel@tonic-gate 	connection_in = fd_in;
152*0Sstevel@tonic-gate 	connection_out = fd_out;
153*0Sstevel@tonic-gate 	cipher_init(&send_context, none, (unsigned char *) "", 0, NULL, 0, CIPHER_ENCRYPT);
154*0Sstevel@tonic-gate 	cipher_init(&receive_context, none, (unsigned char *) "", 0, NULL, 0, CIPHER_DECRYPT);
155*0Sstevel@tonic-gate 	newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
156*0Sstevel@tonic-gate 	if (!initialized) {
157*0Sstevel@tonic-gate 		initialized = 1;
158*0Sstevel@tonic-gate 		buffer_init(&input);
159*0Sstevel@tonic-gate 		buffer_init(&output);
160*0Sstevel@tonic-gate 		buffer_init(&outgoing_packet);
161*0Sstevel@tonic-gate 		buffer_init(&incoming_packet);
162*0Sstevel@tonic-gate 	} else {
163*0Sstevel@tonic-gate 		buffer_clear(&input);
164*0Sstevel@tonic-gate 		buffer_clear(&output);
165*0Sstevel@tonic-gate 		buffer_clear(&outgoing_packet);
166*0Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
167*0Sstevel@tonic-gate 	}
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	/*
170*0Sstevel@tonic-gate 	 * Prime the cache for get_remote_ipaddr() while we have a
171*0Sstevel@tonic-gate 	 * socket on which to do a getpeername().
172*0Sstevel@tonic-gate 	 */
173*0Sstevel@tonic-gate 	(void) get_remote_ipaddr();
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	/* Kludge: arrange the close function to be called from fatal(). */
176*0Sstevel@tonic-gate 	fatal_add_cleanup((void (*) (void *)) packet_close, NULL);
177*0Sstevel@tonic-gate }
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate /* Returns 1 if remote host is connected via socket, 0 if not. */
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate int
182*0Sstevel@tonic-gate packet_connection_is_on_socket(void)
183*0Sstevel@tonic-gate {
184*0Sstevel@tonic-gate 	struct sockaddr_storage from, to;
185*0Sstevel@tonic-gate 	socklen_t fromlen, tolen;
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	/* filedescriptors in and out are the same, so it's a socket */
188*0Sstevel@tonic-gate 	if (connection_in != -1 && connection_in == connection_out)
189*0Sstevel@tonic-gate 		return 1;
190*0Sstevel@tonic-gate 	fromlen = sizeof(from);
191*0Sstevel@tonic-gate 	memset(&from, 0, sizeof(from));
192*0Sstevel@tonic-gate 	if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0)
193*0Sstevel@tonic-gate 		return 0;
194*0Sstevel@tonic-gate 	tolen = sizeof(to);
195*0Sstevel@tonic-gate 	memset(&to, 0, sizeof(to));
196*0Sstevel@tonic-gate 	if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0)
197*0Sstevel@tonic-gate 		return 0;
198*0Sstevel@tonic-gate 	if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0)
199*0Sstevel@tonic-gate 		return 0;
200*0Sstevel@tonic-gate 	if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
201*0Sstevel@tonic-gate 		return 0;
202*0Sstevel@tonic-gate 	return 1;
203*0Sstevel@tonic-gate }
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate /*
206*0Sstevel@tonic-gate  * Exports an IV from the CipherContext required to export the key
207*0Sstevel@tonic-gate  * state back from the unprivileged child to the privileged parent
208*0Sstevel@tonic-gate  * process.
209*0Sstevel@tonic-gate  */
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate void
212*0Sstevel@tonic-gate packet_get_keyiv(int mode, u_char *iv, u_int len)
213*0Sstevel@tonic-gate {
214*0Sstevel@tonic-gate 	CipherContext *cc;
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	if (mode == MODE_OUT)
217*0Sstevel@tonic-gate 		cc = &send_context;
218*0Sstevel@tonic-gate 	else
219*0Sstevel@tonic-gate 		cc = &receive_context;
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	cipher_get_keyiv(cc, iv, len);
222*0Sstevel@tonic-gate }
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate int
225*0Sstevel@tonic-gate packet_get_keycontext(int mode, u_char *dat)
226*0Sstevel@tonic-gate {
227*0Sstevel@tonic-gate 	CipherContext *cc;
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	if (mode == MODE_OUT)
230*0Sstevel@tonic-gate 		cc = &send_context;
231*0Sstevel@tonic-gate 	else
232*0Sstevel@tonic-gate 		cc = &receive_context;
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	return (cipher_get_keycontext(cc, dat));
235*0Sstevel@tonic-gate }
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate void
238*0Sstevel@tonic-gate packet_set_keycontext(int mode, u_char *dat)
239*0Sstevel@tonic-gate {
240*0Sstevel@tonic-gate 	CipherContext *cc;
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	if (mode == MODE_OUT)
243*0Sstevel@tonic-gate 		cc = &send_context;
244*0Sstevel@tonic-gate 	else
245*0Sstevel@tonic-gate 		cc = &receive_context;
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 	cipher_set_keycontext(cc, dat);
248*0Sstevel@tonic-gate }
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate int
251*0Sstevel@tonic-gate packet_get_keyiv_len(int mode)
252*0Sstevel@tonic-gate {
253*0Sstevel@tonic-gate 	CipherContext *cc;
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	if (mode == MODE_OUT)
256*0Sstevel@tonic-gate 		cc = &send_context;
257*0Sstevel@tonic-gate 	else
258*0Sstevel@tonic-gate 		cc = &receive_context;
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	return (cipher_get_keyiv_len(cc));
261*0Sstevel@tonic-gate }
262*0Sstevel@tonic-gate void
263*0Sstevel@tonic-gate packet_set_iv(int mode, u_char *dat)
264*0Sstevel@tonic-gate {
265*0Sstevel@tonic-gate 	CipherContext *cc;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	if (mode == MODE_OUT)
268*0Sstevel@tonic-gate 		cc = &send_context;
269*0Sstevel@tonic-gate 	else
270*0Sstevel@tonic-gate 		cc = &receive_context;
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	cipher_set_keyiv(cc, dat);
273*0Sstevel@tonic-gate }
274*0Sstevel@tonic-gate int
275*0Sstevel@tonic-gate packet_get_ssh1_cipher()
276*0Sstevel@tonic-gate {
277*0Sstevel@tonic-gate 	return (cipher_get_number(receive_context.cipher));
278*0Sstevel@tonic-gate }
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate u_int32_t
282*0Sstevel@tonic-gate packet_get_seqnr(int mode)
283*0Sstevel@tonic-gate {
284*0Sstevel@tonic-gate 	return (mode == MODE_IN ? read_seqnr : send_seqnr);
285*0Sstevel@tonic-gate }
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate void
288*0Sstevel@tonic-gate packet_set_seqnr(int mode, u_int32_t seqnr)
289*0Sstevel@tonic-gate {
290*0Sstevel@tonic-gate 	if (mode == MODE_IN)
291*0Sstevel@tonic-gate 		read_seqnr = seqnr;
292*0Sstevel@tonic-gate 	else if (mode == MODE_OUT)
293*0Sstevel@tonic-gate 		send_seqnr = seqnr;
294*0Sstevel@tonic-gate 	else
295*0Sstevel@tonic-gate 		fatal("packet_set_seqnr: bad mode %d", mode);
296*0Sstevel@tonic-gate }
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate /* returns 1 if connection is via ipv4 */
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate int
301*0Sstevel@tonic-gate packet_connection_is_ipv4(void)
302*0Sstevel@tonic-gate {
303*0Sstevel@tonic-gate 	struct sockaddr_storage to;
304*0Sstevel@tonic-gate 	socklen_t tolen = sizeof(to);
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	memset(&to, 0, sizeof(to));
307*0Sstevel@tonic-gate 	if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0)
308*0Sstevel@tonic-gate 		return 0;
309*0Sstevel@tonic-gate 	if (to.ss_family == AF_INET)
310*0Sstevel@tonic-gate 		return 1;
311*0Sstevel@tonic-gate #ifdef IPV4_IN_IPV6
312*0Sstevel@tonic-gate 	if (to.ss_family == AF_INET6 &&
313*0Sstevel@tonic-gate 	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr))
314*0Sstevel@tonic-gate 		return 1;
315*0Sstevel@tonic-gate #endif
316*0Sstevel@tonic-gate 	return 0;
317*0Sstevel@tonic-gate }
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate /* Sets the connection into non-blocking mode. */
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate void
322*0Sstevel@tonic-gate packet_set_nonblocking(void)
323*0Sstevel@tonic-gate {
324*0Sstevel@tonic-gate 	/* Set the socket into non-blocking mode. */
325*0Sstevel@tonic-gate 	if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0)
326*0Sstevel@tonic-gate 		error("fcntl O_NONBLOCK: %.100s", strerror(errno));
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 	if (connection_out != connection_in) {
329*0Sstevel@tonic-gate 		if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0)
330*0Sstevel@tonic-gate 			error("fcntl O_NONBLOCK: %.100s", strerror(errno));
331*0Sstevel@tonic-gate 	}
332*0Sstevel@tonic-gate }
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate /* Returns the socket used for reading. */
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate int
337*0Sstevel@tonic-gate packet_get_connection_in(void)
338*0Sstevel@tonic-gate {
339*0Sstevel@tonic-gate 	return connection_in;
340*0Sstevel@tonic-gate }
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate /* Returns the descriptor used for writing. */
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate int
345*0Sstevel@tonic-gate packet_get_connection_out(void)
346*0Sstevel@tonic-gate {
347*0Sstevel@tonic-gate 	return connection_out;
348*0Sstevel@tonic-gate }
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate /* Closes the connection and clears and frees internal data structures. */
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate void
353*0Sstevel@tonic-gate packet_close(void)
354*0Sstevel@tonic-gate {
355*0Sstevel@tonic-gate 	if (!initialized)
356*0Sstevel@tonic-gate 		return;
357*0Sstevel@tonic-gate 	initialized = 0;
358*0Sstevel@tonic-gate 	if (connection_in == connection_out) {
359*0Sstevel@tonic-gate 		shutdown(connection_out, SHUT_RDWR);
360*0Sstevel@tonic-gate 		close(connection_out);
361*0Sstevel@tonic-gate 	} else {
362*0Sstevel@tonic-gate 		close(connection_in);
363*0Sstevel@tonic-gate 		close(connection_out);
364*0Sstevel@tonic-gate 	}
365*0Sstevel@tonic-gate 	buffer_free(&input);
366*0Sstevel@tonic-gate 	buffer_free(&output);
367*0Sstevel@tonic-gate 	buffer_free(&outgoing_packet);
368*0Sstevel@tonic-gate 	buffer_free(&incoming_packet);
369*0Sstevel@tonic-gate 	if (compression_buffer_ready) {
370*0Sstevel@tonic-gate 		buffer_free(&compression_buffer);
371*0Sstevel@tonic-gate 		buffer_compress_uninit();
372*0Sstevel@tonic-gate 		compression_buffer_ready = 0;
373*0Sstevel@tonic-gate 	}
374*0Sstevel@tonic-gate 	cipher_cleanup(&send_context);
375*0Sstevel@tonic-gate 	cipher_cleanup(&receive_context);
376*0Sstevel@tonic-gate }
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate /* Sets remote side protocol flags. */
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate void
381*0Sstevel@tonic-gate packet_set_protocol_flags(u_int protocol_flags)
382*0Sstevel@tonic-gate {
383*0Sstevel@tonic-gate 	remote_protocol_flags = protocol_flags;
384*0Sstevel@tonic-gate }
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate /* Returns the remote protocol flags set earlier by the above function. */
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate u_int
389*0Sstevel@tonic-gate packet_get_protocol_flags(void)
390*0Sstevel@tonic-gate {
391*0Sstevel@tonic-gate 	return remote_protocol_flags;
392*0Sstevel@tonic-gate }
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate /*
395*0Sstevel@tonic-gate  * Starts packet compression from the next packet on in both directions.
396*0Sstevel@tonic-gate  * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
397*0Sstevel@tonic-gate  */
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate static void
400*0Sstevel@tonic-gate packet_init_compression(void)
401*0Sstevel@tonic-gate {
402*0Sstevel@tonic-gate 	if (compression_buffer_ready == 1)
403*0Sstevel@tonic-gate 		return;
404*0Sstevel@tonic-gate 	compression_buffer_ready = 1;
405*0Sstevel@tonic-gate 	buffer_init(&compression_buffer);
406*0Sstevel@tonic-gate }
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate void
409*0Sstevel@tonic-gate packet_start_compression(int level)
410*0Sstevel@tonic-gate {
411*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
412*0Sstevel@tonic-gate 	/* shouldn't happen! */
413*0Sstevel@tonic-gate 	if (packet_monitor)
414*0Sstevel@tonic-gate 		fatal("INTERNAL ERROR: The monitor cannot compress.");
415*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	if (packet_compression && !compat20)
418*0Sstevel@tonic-gate 		fatal("Compression already enabled.");
419*0Sstevel@tonic-gate 	packet_compression = 1;
420*0Sstevel@tonic-gate 	packet_init_compression();
421*0Sstevel@tonic-gate 	buffer_compress_init_send(level);
422*0Sstevel@tonic-gate 	buffer_compress_init_recv();
423*0Sstevel@tonic-gate }
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate /*
426*0Sstevel@tonic-gate  * Causes any further packets to be encrypted using the given key.  The same
427*0Sstevel@tonic-gate  * key is used for both sending and reception.  However, both directions are
428*0Sstevel@tonic-gate  * encrypted independently of each other.
429*0Sstevel@tonic-gate  */
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate void
432*0Sstevel@tonic-gate packet_set_encryption_key(const u_char *key, u_int keylen,
433*0Sstevel@tonic-gate     int number)
434*0Sstevel@tonic-gate {
435*0Sstevel@tonic-gate 	Cipher *cipher = cipher_by_number(number);
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	if (cipher == NULL)
438*0Sstevel@tonic-gate 		fatal("packet_set_encryption_key: unknown cipher number %d", number);
439*0Sstevel@tonic-gate 	if (keylen < 20)
440*0Sstevel@tonic-gate 		fatal("packet_set_encryption_key: keylen too small: %d", keylen);
441*0Sstevel@tonic-gate 	if (keylen > SSH_SESSION_KEY_LENGTH)
442*0Sstevel@tonic-gate 		fatal("packet_set_encryption_key: keylen too big: %d", keylen);
443*0Sstevel@tonic-gate 	memcpy(ssh1_key, key, keylen);
444*0Sstevel@tonic-gate 	ssh1_keylen = keylen;
445*0Sstevel@tonic-gate 	cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT);
446*0Sstevel@tonic-gate 	cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT);
447*0Sstevel@tonic-gate }
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate u_int
450*0Sstevel@tonic-gate packet_get_encryption_key(u_char *key)
451*0Sstevel@tonic-gate {
452*0Sstevel@tonic-gate 	if (key == NULL)
453*0Sstevel@tonic-gate 		return (ssh1_keylen);
454*0Sstevel@tonic-gate 	memcpy(key, ssh1_key, ssh1_keylen);
455*0Sstevel@tonic-gate 	return (ssh1_keylen);
456*0Sstevel@tonic-gate }
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate /* Start constructing a packet to send. */
459*0Sstevel@tonic-gate void
460*0Sstevel@tonic-gate packet_start(u_char type)
461*0Sstevel@tonic-gate {
462*0Sstevel@tonic-gate 	u_char buf[9];
463*0Sstevel@tonic-gate 	int len;
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	DBG(debug("packet_start[%d]", type));
466*0Sstevel@tonic-gate 	len = compat20 ? 6 : 9;
467*0Sstevel@tonic-gate 	memset(buf, 0, len - 1);
468*0Sstevel@tonic-gate 	buf[len - 1] = type;
469*0Sstevel@tonic-gate 	buffer_clear(&outgoing_packet);
470*0Sstevel@tonic-gate 	buffer_append(&outgoing_packet, buf, len);
471*0Sstevel@tonic-gate }
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate /* Append payload. */
474*0Sstevel@tonic-gate void
475*0Sstevel@tonic-gate packet_put_char(int value)
476*0Sstevel@tonic-gate {
477*0Sstevel@tonic-gate 	char ch = value;
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 	buffer_append(&outgoing_packet, &ch, 1);
480*0Sstevel@tonic-gate }
481*0Sstevel@tonic-gate void
482*0Sstevel@tonic-gate packet_put_int(u_int value)
483*0Sstevel@tonic-gate {
484*0Sstevel@tonic-gate 	buffer_put_int(&outgoing_packet, value);
485*0Sstevel@tonic-gate }
486*0Sstevel@tonic-gate void
487*0Sstevel@tonic-gate packet_put_string(const void *buf, u_int len)
488*0Sstevel@tonic-gate {
489*0Sstevel@tonic-gate 	buffer_put_string(&outgoing_packet, buf, len);
490*0Sstevel@tonic-gate }
491*0Sstevel@tonic-gate void
492*0Sstevel@tonic-gate packet_put_cstring(const char *str)
493*0Sstevel@tonic-gate {
494*0Sstevel@tonic-gate 	buffer_put_cstring(&outgoing_packet, str);
495*0Sstevel@tonic-gate }
496*0Sstevel@tonic-gate void
497*0Sstevel@tonic-gate packet_put_ascii_cstring(const char *str)
498*0Sstevel@tonic-gate {
499*0Sstevel@tonic-gate 	buffer_put_ascii_cstring(&outgoing_packet, str);
500*0Sstevel@tonic-gate }
501*0Sstevel@tonic-gate void
502*0Sstevel@tonic-gate packet_put_utf8_cstring(const u_char *str)
503*0Sstevel@tonic-gate {
504*0Sstevel@tonic-gate 	buffer_put_utf8_cstring(&outgoing_packet, str);
505*0Sstevel@tonic-gate }
506*0Sstevel@tonic-gate #if 0
507*0Sstevel@tonic-gate void
508*0Sstevel@tonic-gate packet_put_ascii_string(const void *buf, u_int len)
509*0Sstevel@tonic-gate {
510*0Sstevel@tonic-gate 	buffer_put_ascii_string(&outgoing_packet, buf, len);
511*0Sstevel@tonic-gate }
512*0Sstevel@tonic-gate void
513*0Sstevel@tonic-gate packet_put_utf8_string(const void *buf, u_int len)
514*0Sstevel@tonic-gate {
515*0Sstevel@tonic-gate 	buffer_put_utf8_string(&outgoing_packet, buf, len);
516*0Sstevel@tonic-gate }
517*0Sstevel@tonic-gate #endif
518*0Sstevel@tonic-gate void
519*0Sstevel@tonic-gate packet_put_raw(const void *buf, u_int len)
520*0Sstevel@tonic-gate {
521*0Sstevel@tonic-gate 	buffer_append(&outgoing_packet, buf, len);
522*0Sstevel@tonic-gate }
523*0Sstevel@tonic-gate void
524*0Sstevel@tonic-gate packet_put_bignum(BIGNUM * value)
525*0Sstevel@tonic-gate {
526*0Sstevel@tonic-gate 	buffer_put_bignum(&outgoing_packet, value);
527*0Sstevel@tonic-gate }
528*0Sstevel@tonic-gate void
529*0Sstevel@tonic-gate packet_put_bignum2(BIGNUM * value)
530*0Sstevel@tonic-gate {
531*0Sstevel@tonic-gate 	buffer_put_bignum2(&outgoing_packet, value);
532*0Sstevel@tonic-gate }
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate /*
535*0Sstevel@tonic-gate  * Finalizes and sends the packet.  If the encryption key has been set,
536*0Sstevel@tonic-gate  * encrypts the packet before sending.
537*0Sstevel@tonic-gate  */
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate static void
540*0Sstevel@tonic-gate packet_send1(void)
541*0Sstevel@tonic-gate {
542*0Sstevel@tonic-gate 	u_char buf[8], *cp;
543*0Sstevel@tonic-gate 	int i, padding, len;
544*0Sstevel@tonic-gate 	u_int checksum;
545*0Sstevel@tonic-gate 	u_int32_t rand = 0;
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	/*
548*0Sstevel@tonic-gate 	 * If using packet compression, compress the payload of the outgoing
549*0Sstevel@tonic-gate 	 * packet.
550*0Sstevel@tonic-gate 	 */
551*0Sstevel@tonic-gate 	if (packet_compression) {
552*0Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
553*0Sstevel@tonic-gate 		/* Skip padding. */
554*0Sstevel@tonic-gate 		buffer_consume(&outgoing_packet, 8);
555*0Sstevel@tonic-gate 		/* padding */
556*0Sstevel@tonic-gate 		buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8);
557*0Sstevel@tonic-gate 		buffer_compress(&outgoing_packet, &compression_buffer);
558*0Sstevel@tonic-gate 		buffer_clear(&outgoing_packet);
559*0Sstevel@tonic-gate 		buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
560*0Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
561*0Sstevel@tonic-gate 	}
562*0Sstevel@tonic-gate 	/* Compute packet length without padding (add checksum, remove padding). */
563*0Sstevel@tonic-gate 	len = buffer_len(&outgoing_packet) + 4 - 8;
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	/* Insert padding. Initialized to zero in packet_start1() */
566*0Sstevel@tonic-gate 	padding = 8 - len % 8;
567*0Sstevel@tonic-gate 	if (!send_context.plaintext) {
568*0Sstevel@tonic-gate 		cp = buffer_ptr(&outgoing_packet);
569*0Sstevel@tonic-gate 		for (i = 0; i < padding; i++) {
570*0Sstevel@tonic-gate 			if (i % 4 == 0)
571*0Sstevel@tonic-gate 				rand = arc4random();
572*0Sstevel@tonic-gate 			cp[7 - i] = rand & 0xff;
573*0Sstevel@tonic-gate 			rand >>= 8;
574*0Sstevel@tonic-gate 		}
575*0Sstevel@tonic-gate 	}
576*0Sstevel@tonic-gate 	buffer_consume(&outgoing_packet, 8 - padding);
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	/* Add check bytes. */
579*0Sstevel@tonic-gate 	checksum = ssh_crc32(buffer_ptr(&outgoing_packet),
580*0Sstevel@tonic-gate 	    buffer_len(&outgoing_packet));
581*0Sstevel@tonic-gate 	PUT_32BIT(buf, checksum);
582*0Sstevel@tonic-gate 	buffer_append(&outgoing_packet, buf, 4);
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate #ifdef PACKET_DEBUG
585*0Sstevel@tonic-gate 	fprintf(stderr, "packet_send plain: ");
586*0Sstevel@tonic-gate 	buffer_dump(&outgoing_packet);
587*0Sstevel@tonic-gate #endif
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	/* Append to output. */
590*0Sstevel@tonic-gate 	PUT_32BIT(buf, len);
591*0Sstevel@tonic-gate 	buffer_append(&output, buf, 4);
592*0Sstevel@tonic-gate 	cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
593*0Sstevel@tonic-gate 	cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
594*0Sstevel@tonic-gate 	    buffer_len(&outgoing_packet));
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate #ifdef PACKET_DEBUG
597*0Sstevel@tonic-gate 	fprintf(stderr, "encrypted: ");
598*0Sstevel@tonic-gate 	buffer_dump(&output);
599*0Sstevel@tonic-gate #endif
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	buffer_clear(&outgoing_packet);
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 	/*
604*0Sstevel@tonic-gate 	 * Note that the packet is now only buffered in output.  It won\'t be
605*0Sstevel@tonic-gate 	 * actually sent until packet_write_wait or packet_write_poll is
606*0Sstevel@tonic-gate 	 * called.
607*0Sstevel@tonic-gate 	 */
608*0Sstevel@tonic-gate }
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate void
611*0Sstevel@tonic-gate set_newkeys(int mode)
612*0Sstevel@tonic-gate {
613*0Sstevel@tonic-gate 	Enc *enc;
614*0Sstevel@tonic-gate 	Mac *mac;
615*0Sstevel@tonic-gate 	Comp *comp;
616*0Sstevel@tonic-gate 	CipherContext *cc;
617*0Sstevel@tonic-gate 	int encrypt;
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	debug("newkeys: mode %d", mode);
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	if (mode == MODE_OUT) {
622*0Sstevel@tonic-gate 		cc = &send_context;
623*0Sstevel@tonic-gate 		encrypt = CIPHER_ENCRYPT;
624*0Sstevel@tonic-gate 	} else {
625*0Sstevel@tonic-gate 		cc = &receive_context;
626*0Sstevel@tonic-gate 		encrypt = CIPHER_DECRYPT;
627*0Sstevel@tonic-gate 	}
628*0Sstevel@tonic-gate 	if (newkeys[mode] != NULL) {
629*0Sstevel@tonic-gate 		debug("newkeys: rekeying");
630*0Sstevel@tonic-gate 		cipher_cleanup(cc);
631*0Sstevel@tonic-gate 		enc  = &newkeys[mode]->enc;
632*0Sstevel@tonic-gate 		mac  = &newkeys[mode]->mac;
633*0Sstevel@tonic-gate 		comp = &newkeys[mode]->comp;
634*0Sstevel@tonic-gate 		memset(mac->key, 0, mac->key_len);
635*0Sstevel@tonic-gate 		xfree(enc->name);
636*0Sstevel@tonic-gate 		xfree(enc->iv);
637*0Sstevel@tonic-gate 		xfree(enc->key);
638*0Sstevel@tonic-gate 		xfree(mac->name);
639*0Sstevel@tonic-gate 		xfree(mac->key);
640*0Sstevel@tonic-gate 		xfree(comp->name);
641*0Sstevel@tonic-gate 		xfree(newkeys[mode]);
642*0Sstevel@tonic-gate 	}
643*0Sstevel@tonic-gate 	newkeys[mode] = kex_get_newkeys(mode);
644*0Sstevel@tonic-gate 	if (newkeys[mode] == NULL)
645*0Sstevel@tonic-gate 		fatal("newkeys: no keys for mode %d", mode);
646*0Sstevel@tonic-gate 	enc  = &newkeys[mode]->enc;
647*0Sstevel@tonic-gate 	mac  = &newkeys[mode]->mac;
648*0Sstevel@tonic-gate 	comp = &newkeys[mode]->comp;
649*0Sstevel@tonic-gate 	if (mac->md != NULL)
650*0Sstevel@tonic-gate 		mac->enabled = 1;
651*0Sstevel@tonic-gate 	DBG(debug("cipher_init_context: %d", mode));
652*0Sstevel@tonic-gate 	cipher_init(cc, enc->cipher, enc->key, enc->key_len,
653*0Sstevel@tonic-gate 	    enc->iv, enc->block_size, encrypt);
654*0Sstevel@tonic-gate 	/* Deleting the keys does not gain extra security */
655*0Sstevel@tonic-gate 	/* memset(enc->iv,  0, enc->block_size);
656*0Sstevel@tonic-gate 	   memset(enc->key, 0, enc->key_len); */
657*0Sstevel@tonic-gate 	if (comp->type != 0 && comp->enabled == 0) {
658*0Sstevel@tonic-gate 		packet_init_compression();
659*0Sstevel@tonic-gate 		if (mode == MODE_OUT)
660*0Sstevel@tonic-gate 			buffer_compress_init_send(6);
661*0Sstevel@tonic-gate 		else
662*0Sstevel@tonic-gate 			buffer_compress_init_recv();
663*0Sstevel@tonic-gate 		comp->enabled = 1;
664*0Sstevel@tonic-gate 	}
665*0Sstevel@tonic-gate }
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate /*
668*0Sstevel@tonic-gate  * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
669*0Sstevel@tonic-gate  */
670*0Sstevel@tonic-gate static void
671*0Sstevel@tonic-gate packet_send2(void)
672*0Sstevel@tonic-gate {
673*0Sstevel@tonic-gate 	u_char type, *cp, *macbuf = NULL;
674*0Sstevel@tonic-gate 	u_char padlen, pad;
675*0Sstevel@tonic-gate 	u_int packet_length = 0;
676*0Sstevel@tonic-gate 	u_int i, len;
677*0Sstevel@tonic-gate 	u_int32_t rand = 0;
678*0Sstevel@tonic-gate 	Enc *enc   = NULL;
679*0Sstevel@tonic-gate 	Mac *mac   = NULL;
680*0Sstevel@tonic-gate 	Comp *comp = NULL;
681*0Sstevel@tonic-gate 	int block_size;
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 	if (newkeys[MODE_OUT] != NULL) {
684*0Sstevel@tonic-gate 		enc  = &newkeys[MODE_OUT]->enc;
685*0Sstevel@tonic-gate 		mac  = &newkeys[MODE_OUT]->mac;
686*0Sstevel@tonic-gate 		comp = &newkeys[MODE_OUT]->comp;
687*0Sstevel@tonic-gate 	}
688*0Sstevel@tonic-gate 	block_size = enc ? enc->block_size : 8;
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 	cp = buffer_ptr(&outgoing_packet);
691*0Sstevel@tonic-gate 	type = cp[5];
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate #ifdef PACKET_DEBUG
694*0Sstevel@tonic-gate 	fprintf(stderr, "plain:     ");
695*0Sstevel@tonic-gate 	buffer_dump(&outgoing_packet);
696*0Sstevel@tonic-gate #endif
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	if (comp && comp->enabled) {
699*0Sstevel@tonic-gate 		len = buffer_len(&outgoing_packet);
700*0Sstevel@tonic-gate 		/* skip header, compress only payload */
701*0Sstevel@tonic-gate 		buffer_consume(&outgoing_packet, 5);
702*0Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
703*0Sstevel@tonic-gate 		buffer_compress(&outgoing_packet, &compression_buffer);
704*0Sstevel@tonic-gate 		buffer_clear(&outgoing_packet);
705*0Sstevel@tonic-gate 		buffer_append(&outgoing_packet, "\0\0\0\0\0", 5);
706*0Sstevel@tonic-gate 		buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
707*0Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
708*0Sstevel@tonic-gate 		DBG(debug("compression: raw %d compressed %d", len,
709*0Sstevel@tonic-gate 		    buffer_len(&outgoing_packet)));
710*0Sstevel@tonic-gate 	}
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 	/* sizeof (packet_len + pad_len + payload) */
713*0Sstevel@tonic-gate 	len = buffer_len(&outgoing_packet);
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 	/*
716*0Sstevel@tonic-gate 	 * calc size of padding, alloc space, get random data,
717*0Sstevel@tonic-gate 	 * minimum padding is 4 bytes
718*0Sstevel@tonic-gate 	 */
719*0Sstevel@tonic-gate 	padlen = block_size - (len % block_size);
720*0Sstevel@tonic-gate 	if (padlen < 4)
721*0Sstevel@tonic-gate 		padlen += block_size;
722*0Sstevel@tonic-gate 	if (extra_pad) {
723*0Sstevel@tonic-gate 		/* will wrap if extra_pad+padlen > 255 */
724*0Sstevel@tonic-gate 		extra_pad  = roundup(extra_pad, block_size);
725*0Sstevel@tonic-gate 		pad = extra_pad - ((len + padlen) % extra_pad);
726*0Sstevel@tonic-gate 		debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)",
727*0Sstevel@tonic-gate 		    pad, len, padlen, extra_pad);
728*0Sstevel@tonic-gate 		padlen += pad;
729*0Sstevel@tonic-gate 		extra_pad = 0;
730*0Sstevel@tonic-gate 	}
731*0Sstevel@tonic-gate 	cp = buffer_append_space(&outgoing_packet, padlen);
732*0Sstevel@tonic-gate 	if (enc && !send_context.plaintext) {
733*0Sstevel@tonic-gate 		/* random padding */
734*0Sstevel@tonic-gate 		for (i = 0; i < padlen; i++) {
735*0Sstevel@tonic-gate 			if (i % 4 == 0)
736*0Sstevel@tonic-gate 				rand = arc4random();
737*0Sstevel@tonic-gate 			cp[i] = rand & 0xff;
738*0Sstevel@tonic-gate 			rand >>= 8;
739*0Sstevel@tonic-gate 		}
740*0Sstevel@tonic-gate 	} else {
741*0Sstevel@tonic-gate 		/* clear padding */
742*0Sstevel@tonic-gate 		memset(cp, 0, padlen);
743*0Sstevel@tonic-gate 	}
744*0Sstevel@tonic-gate 	/* packet_length includes payload, padding and padding length field */
745*0Sstevel@tonic-gate 	packet_length = buffer_len(&outgoing_packet) - 4;
746*0Sstevel@tonic-gate 	cp = buffer_ptr(&outgoing_packet);
747*0Sstevel@tonic-gate 	PUT_32BIT(cp, packet_length);
748*0Sstevel@tonic-gate 	cp[4] = padlen;
749*0Sstevel@tonic-gate 	DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen));
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate 	/* compute MAC over seqnr and packet(length fields, payload, padding) */
752*0Sstevel@tonic-gate 	if (mac && mac->enabled) {
753*0Sstevel@tonic-gate 		macbuf = mac_compute(mac, send_seqnr,
754*0Sstevel@tonic-gate 		    buffer_ptr(&outgoing_packet),
755*0Sstevel@tonic-gate 		    buffer_len(&outgoing_packet));
756*0Sstevel@tonic-gate 		DBG(debug("done calc MAC out #%d", send_seqnr));
757*0Sstevel@tonic-gate 	}
758*0Sstevel@tonic-gate 	/* encrypt packet and append to output buffer. */
759*0Sstevel@tonic-gate 	cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
760*0Sstevel@tonic-gate 	cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
761*0Sstevel@tonic-gate 	    buffer_len(&outgoing_packet));
762*0Sstevel@tonic-gate 	/* append unencrypted MAC */
763*0Sstevel@tonic-gate 	if (mac && mac->enabled)
764*0Sstevel@tonic-gate 		buffer_append(&output, (char *)macbuf, mac->mac_len);
765*0Sstevel@tonic-gate #ifdef PACKET_DEBUG
766*0Sstevel@tonic-gate 	fprintf(stderr, "encrypted: ");
767*0Sstevel@tonic-gate 	buffer_dump(&output);
768*0Sstevel@tonic-gate #endif
769*0Sstevel@tonic-gate 	/* increment sequence number for outgoing packets */
770*0Sstevel@tonic-gate 	if (++send_seqnr == 0)
771*0Sstevel@tonic-gate 		log("outgoing seqnr wraps around");
772*0Sstevel@tonic-gate 	buffer_clear(&outgoing_packet);
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate 	if (type == SSH2_MSG_NEWKEYS)
775*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
776*0Sstevel@tonic-gate 		/* set_newkeys(MODE_OUT) in client, server, but not monitor */
777*0Sstevel@tonic-gate 		if (!packet_is_server() && !packet_is_monitor())
778*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
779*0Sstevel@tonic-gate 		set_newkeys(MODE_OUT);
780*0Sstevel@tonic-gate }
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate void
783*0Sstevel@tonic-gate packet_send(void)
784*0Sstevel@tonic-gate {
785*0Sstevel@tonic-gate 	if (compat20)
786*0Sstevel@tonic-gate 		packet_send2();
787*0Sstevel@tonic-gate 	else
788*0Sstevel@tonic-gate 		packet_send1();
789*0Sstevel@tonic-gate 	DBG(debug("packet_send done"));
790*0Sstevel@tonic-gate }
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate /*
793*0Sstevel@tonic-gate  * Waits until a packet has been received, and returns its type.  Note that
794*0Sstevel@tonic-gate  * no other data is processed until this returns, so this function should not
795*0Sstevel@tonic-gate  * be used during the interactive session.
796*0Sstevel@tonic-gate  */
797*0Sstevel@tonic-gate 
798*0Sstevel@tonic-gate int
799*0Sstevel@tonic-gate packet_read_seqnr(u_int32_t *seqnr_p)
800*0Sstevel@tonic-gate {
801*0Sstevel@tonic-gate 	int type, len;
802*0Sstevel@tonic-gate 	fd_set *setp;
803*0Sstevel@tonic-gate 	char buf[8192];
804*0Sstevel@tonic-gate 	DBG(debug("packet_read()"));
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) *
807*0Sstevel@tonic-gate 	    sizeof(fd_mask));
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 	/* Since we are blocking, ensure that all written packets have been sent. */
810*0Sstevel@tonic-gate 	packet_write_wait();
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 	/* Stay in the loop until we have received a complete packet. */
813*0Sstevel@tonic-gate 	for (;;) {
814*0Sstevel@tonic-gate 		/* Try to read a packet from the buffer. */
815*0Sstevel@tonic-gate 		type = packet_read_poll_seqnr(seqnr_p);
816*0Sstevel@tonic-gate 		if (!compat20 && (
817*0Sstevel@tonic-gate 		    type == SSH_SMSG_SUCCESS
818*0Sstevel@tonic-gate 		    || type == SSH_SMSG_FAILURE
819*0Sstevel@tonic-gate 		    || type == SSH_CMSG_EOF
820*0Sstevel@tonic-gate 		    || type == SSH_CMSG_EXIT_CONFIRMATION))
821*0Sstevel@tonic-gate 			packet_check_eom();
822*0Sstevel@tonic-gate 		/* If we got a packet, return it. */
823*0Sstevel@tonic-gate 		if (type != SSH_MSG_NONE) {
824*0Sstevel@tonic-gate 			xfree(setp);
825*0Sstevel@tonic-gate 			return type;
826*0Sstevel@tonic-gate 		}
827*0Sstevel@tonic-gate 		/*
828*0Sstevel@tonic-gate 		 * Otherwise, wait for some data to arrive, add it to the
829*0Sstevel@tonic-gate 		 * buffer, and try again.
830*0Sstevel@tonic-gate 		 */
831*0Sstevel@tonic-gate 		memset(setp, 0, howmany(connection_in + 1, NFDBITS) *
832*0Sstevel@tonic-gate 		    sizeof(fd_mask));
833*0Sstevel@tonic-gate 		FD_SET(connection_in, setp);
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 		/* Wait for some data to arrive. */
836*0Sstevel@tonic-gate 		while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
837*0Sstevel@tonic-gate 		    (errno == EAGAIN || errno == EINTR))
838*0Sstevel@tonic-gate 			;
839*0Sstevel@tonic-gate 
840*0Sstevel@tonic-gate 		/* Read data from the socket. */
841*0Sstevel@tonic-gate 		len = read(connection_in, buf, sizeof(buf));
842*0Sstevel@tonic-gate 		if (len == 0) {
843*0Sstevel@tonic-gate 			log("Connection closed by %.200s", get_remote_ipaddr());
844*0Sstevel@tonic-gate 			fatal_cleanup();
845*0Sstevel@tonic-gate 		}
846*0Sstevel@tonic-gate 		if (len < 0)
847*0Sstevel@tonic-gate 			fatal("Read from socket failed: %.100s", strerror(errno));
848*0Sstevel@tonic-gate 		/* Append it to the buffer. */
849*0Sstevel@tonic-gate 		packet_process_incoming(buf, len);
850*0Sstevel@tonic-gate 	}
851*0Sstevel@tonic-gate 	/* NOTREACHED */
852*0Sstevel@tonic-gate }
853*0Sstevel@tonic-gate 
854*0Sstevel@tonic-gate int
855*0Sstevel@tonic-gate packet_read(void)
856*0Sstevel@tonic-gate {
857*0Sstevel@tonic-gate 	return packet_read_seqnr(NULL);
858*0Sstevel@tonic-gate }
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate /*
861*0Sstevel@tonic-gate  * Waits until a packet has been received, verifies that its type matches
862*0Sstevel@tonic-gate  * that given, and gives a fatal error and exits if there is a mismatch.
863*0Sstevel@tonic-gate  */
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate void
866*0Sstevel@tonic-gate packet_read_expect(int expected_type)
867*0Sstevel@tonic-gate {
868*0Sstevel@tonic-gate 	int type;
869*0Sstevel@tonic-gate 
870*0Sstevel@tonic-gate 	type = packet_read();
871*0Sstevel@tonic-gate 	if (type != expected_type)
872*0Sstevel@tonic-gate 		packet_disconnect("Protocol error: expected packet type %d, got %d",
873*0Sstevel@tonic-gate 		    expected_type, type);
874*0Sstevel@tonic-gate }
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate /* Checks if a full packet is available in the data received so far via
877*0Sstevel@tonic-gate  * packet_process_incoming.  If so, reads the packet; otherwise returns
878*0Sstevel@tonic-gate  * SSH_MSG_NONE.  This does not wait for data from the connection.
879*0Sstevel@tonic-gate  *
880*0Sstevel@tonic-gate  * SSH_MSG_DISCONNECT is handled specially here.  Also,
881*0Sstevel@tonic-gate  * SSH_MSG_IGNORE messages are skipped by this function and are never returned
882*0Sstevel@tonic-gate  * to higher levels.
883*0Sstevel@tonic-gate  */
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate static int
886*0Sstevel@tonic-gate packet_read_poll1(void)
887*0Sstevel@tonic-gate {
888*0Sstevel@tonic-gate 	u_int len, padded_len;
889*0Sstevel@tonic-gate 	u_char *cp, type;
890*0Sstevel@tonic-gate 	u_int checksum, stored_checksum;
891*0Sstevel@tonic-gate 
892*0Sstevel@tonic-gate 	/* Check if input size is less than minimum packet size. */
893*0Sstevel@tonic-gate 	if (buffer_len(&input) < 4 + 8)
894*0Sstevel@tonic-gate 		return SSH_MSG_NONE;
895*0Sstevel@tonic-gate 	/* Get length of incoming packet. */
896*0Sstevel@tonic-gate 	cp = buffer_ptr(&input);
897*0Sstevel@tonic-gate 	len = GET_32BIT(cp);
898*0Sstevel@tonic-gate 	if (len < 1 + 2 + 2 || len > 256 * 1024)
899*0Sstevel@tonic-gate 		packet_disconnect("Bad packet length %d.", len);
900*0Sstevel@tonic-gate 	padded_len = (len + 8) & ~7;
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	/* Check if the packet has been entirely received. */
903*0Sstevel@tonic-gate 	if (buffer_len(&input) < 4 + padded_len)
904*0Sstevel@tonic-gate 		return SSH_MSG_NONE;
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate 	/* The entire packet is in buffer. */
907*0Sstevel@tonic-gate 
908*0Sstevel@tonic-gate 	/* Consume packet length. */
909*0Sstevel@tonic-gate 	buffer_consume(&input, 4);
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate 	/*
912*0Sstevel@tonic-gate 	 * Cryptographic attack detector for ssh
913*0Sstevel@tonic-gate 	 * (C)1998 CORE-SDI, Buenos Aires Argentina
914*0Sstevel@tonic-gate 	 * Ariel Futoransky(futo@core-sdi.com)
915*0Sstevel@tonic-gate 	 */
916*0Sstevel@tonic-gate 	if (!receive_context.plaintext &&
917*0Sstevel@tonic-gate 	    detect_attack(buffer_ptr(&input), padded_len, NULL) == DEATTACK_DETECTED)
918*0Sstevel@tonic-gate 		packet_disconnect("crc32 compensation attack: network attack detected");
919*0Sstevel@tonic-gate 
920*0Sstevel@tonic-gate 	/* Decrypt data to incoming_packet. */
921*0Sstevel@tonic-gate 	buffer_clear(&incoming_packet);
922*0Sstevel@tonic-gate 	cp = buffer_append_space(&incoming_packet, padded_len);
923*0Sstevel@tonic-gate 	cipher_crypt(&receive_context, cp, buffer_ptr(&input), padded_len);
924*0Sstevel@tonic-gate 
925*0Sstevel@tonic-gate 	buffer_consume(&input, padded_len);
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate #ifdef PACKET_DEBUG
928*0Sstevel@tonic-gate 	fprintf(stderr, "read_poll plain: ");
929*0Sstevel@tonic-gate 	buffer_dump(&incoming_packet);
930*0Sstevel@tonic-gate #endif
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 	/* Compute packet checksum. */
933*0Sstevel@tonic-gate 	checksum = ssh_crc32(buffer_ptr(&incoming_packet),
934*0Sstevel@tonic-gate 	    buffer_len(&incoming_packet) - 4);
935*0Sstevel@tonic-gate 
936*0Sstevel@tonic-gate 	/* Skip padding. */
937*0Sstevel@tonic-gate 	buffer_consume(&incoming_packet, 8 - len % 8);
938*0Sstevel@tonic-gate 
939*0Sstevel@tonic-gate 	/* Test check bytes. */
940*0Sstevel@tonic-gate 	if (len != buffer_len(&incoming_packet))
941*0Sstevel@tonic-gate 		packet_disconnect("packet_read_poll1: len %d != buffer_len %d.",
942*0Sstevel@tonic-gate 		    len, buffer_len(&incoming_packet));
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 	cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4;
945*0Sstevel@tonic-gate 	stored_checksum = GET_32BIT(cp);
946*0Sstevel@tonic-gate 	if (checksum != stored_checksum)
947*0Sstevel@tonic-gate 		packet_disconnect("Corrupted check bytes on input.");
948*0Sstevel@tonic-gate 	buffer_consume_end(&incoming_packet, 4);
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	if (packet_compression) {
951*0Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
952*0Sstevel@tonic-gate 		buffer_uncompress(&incoming_packet, &compression_buffer);
953*0Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
954*0Sstevel@tonic-gate 		buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
955*0Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
956*0Sstevel@tonic-gate 	}
957*0Sstevel@tonic-gate 	type = buffer_get_char(&incoming_packet);
958*0Sstevel@tonic-gate 	return type;
959*0Sstevel@tonic-gate }
960*0Sstevel@tonic-gate 
961*0Sstevel@tonic-gate static int
962*0Sstevel@tonic-gate packet_read_poll2(u_int32_t *seqnr_p)
963*0Sstevel@tonic-gate {
964*0Sstevel@tonic-gate 	static u_int packet_length = 0;
965*0Sstevel@tonic-gate 	u_int padlen, need;
966*0Sstevel@tonic-gate 	u_char *macbuf, *cp, type;
967*0Sstevel@tonic-gate 	int maclen, block_size;
968*0Sstevel@tonic-gate 	Enc *enc   = NULL;
969*0Sstevel@tonic-gate 	Mac *mac   = NULL;
970*0Sstevel@tonic-gate 	Comp *comp = NULL;
971*0Sstevel@tonic-gate 
972*0Sstevel@tonic-gate 	if (newkeys[MODE_IN] != NULL) {
973*0Sstevel@tonic-gate 		enc  = &newkeys[MODE_IN]->enc;
974*0Sstevel@tonic-gate 		mac  = &newkeys[MODE_IN]->mac;
975*0Sstevel@tonic-gate 		comp = &newkeys[MODE_IN]->comp;
976*0Sstevel@tonic-gate 	}
977*0Sstevel@tonic-gate 	maclen = mac && mac->enabled ? mac->mac_len : 0;
978*0Sstevel@tonic-gate 	block_size = enc ? enc->block_size : 8;
979*0Sstevel@tonic-gate 
980*0Sstevel@tonic-gate 	if (packet_length == 0) {
981*0Sstevel@tonic-gate 		/*
982*0Sstevel@tonic-gate 		 * check if input size is less than the cipher block size,
983*0Sstevel@tonic-gate 		 * decrypt first block and extract length of incoming packet
984*0Sstevel@tonic-gate 		 */
985*0Sstevel@tonic-gate 		if (buffer_len(&input) < block_size)
986*0Sstevel@tonic-gate 			return SSH_MSG_NONE;
987*0Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
988*0Sstevel@tonic-gate 		cp = buffer_append_space(&incoming_packet, block_size);
989*0Sstevel@tonic-gate 		cipher_crypt(&receive_context, cp, buffer_ptr(&input),
990*0Sstevel@tonic-gate 		    block_size);
991*0Sstevel@tonic-gate 		cp = buffer_ptr(&incoming_packet);
992*0Sstevel@tonic-gate 		packet_length = GET_32BIT(cp);
993*0Sstevel@tonic-gate 		if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
994*0Sstevel@tonic-gate 			buffer_dump(&incoming_packet);
995*0Sstevel@tonic-gate 			packet_disconnect("Bad packet length %d.", packet_length);
996*0Sstevel@tonic-gate 		}
997*0Sstevel@tonic-gate 		DBG(debug("input: packet len %d", packet_length+4));
998*0Sstevel@tonic-gate 		buffer_consume(&input, block_size);
999*0Sstevel@tonic-gate 	}
1000*0Sstevel@tonic-gate 	/* we have a partial packet of block_size bytes */
1001*0Sstevel@tonic-gate 	need = 4 + packet_length - block_size;
1002*0Sstevel@tonic-gate 	DBG(debug("partial packet %d, need %d, maclen %d", block_size,
1003*0Sstevel@tonic-gate 	    need, maclen));
1004*0Sstevel@tonic-gate 	if (need % block_size != 0)
1005*0Sstevel@tonic-gate 		fatal("padding error: need %d block %d mod %d",
1006*0Sstevel@tonic-gate 		    need, block_size, need % block_size);
1007*0Sstevel@tonic-gate 	/*
1008*0Sstevel@tonic-gate 	 * check if the entire packet has been received and
1009*0Sstevel@tonic-gate 	 * decrypt into incoming_packet
1010*0Sstevel@tonic-gate 	 */
1011*0Sstevel@tonic-gate 	if (buffer_len(&input) < need + maclen)
1012*0Sstevel@tonic-gate 		return SSH_MSG_NONE;
1013*0Sstevel@tonic-gate #ifdef PACKET_DEBUG
1014*0Sstevel@tonic-gate 	fprintf(stderr, "read_poll enc/full: ");
1015*0Sstevel@tonic-gate 	buffer_dump(&input);
1016*0Sstevel@tonic-gate #endif
1017*0Sstevel@tonic-gate 	cp = buffer_append_space(&incoming_packet, need);
1018*0Sstevel@tonic-gate 	cipher_crypt(&receive_context, cp, buffer_ptr(&input), need);
1019*0Sstevel@tonic-gate 	buffer_consume(&input, need);
1020*0Sstevel@tonic-gate 	/*
1021*0Sstevel@tonic-gate 	 * compute MAC over seqnr and packet,
1022*0Sstevel@tonic-gate 	 * increment sequence number for incoming packet
1023*0Sstevel@tonic-gate 	 */
1024*0Sstevel@tonic-gate 	if (mac && mac->enabled) {
1025*0Sstevel@tonic-gate 		macbuf = mac_compute(mac, read_seqnr,
1026*0Sstevel@tonic-gate 		    buffer_ptr(&incoming_packet),
1027*0Sstevel@tonic-gate 		    buffer_len(&incoming_packet));
1028*0Sstevel@tonic-gate 		if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
1029*0Sstevel@tonic-gate 			packet_disconnect("Corrupted MAC on input.");
1030*0Sstevel@tonic-gate 		DBG(debug("MAC #%d ok", read_seqnr));
1031*0Sstevel@tonic-gate 		buffer_consume(&input, mac->mac_len);
1032*0Sstevel@tonic-gate 	}
1033*0Sstevel@tonic-gate 	if (seqnr_p != NULL)
1034*0Sstevel@tonic-gate 		*seqnr_p = read_seqnr;
1035*0Sstevel@tonic-gate 	if (++read_seqnr == 0)
1036*0Sstevel@tonic-gate 		log("incoming seqnr wraps around");
1037*0Sstevel@tonic-gate 
1038*0Sstevel@tonic-gate 	/* get padlen */
1039*0Sstevel@tonic-gate 	cp = buffer_ptr(&incoming_packet);
1040*0Sstevel@tonic-gate 	padlen = cp[4];
1041*0Sstevel@tonic-gate 	DBG(debug("input: padlen %d", padlen));
1042*0Sstevel@tonic-gate 	if (padlen < 4)
1043*0Sstevel@tonic-gate 		packet_disconnect("Corrupted padlen %d on input.", padlen);
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate 	/* skip packet size + padlen, discard padding */
1046*0Sstevel@tonic-gate 	buffer_consume(&incoming_packet, 4 + 1);
1047*0Sstevel@tonic-gate 	buffer_consume_end(&incoming_packet, padlen);
1048*0Sstevel@tonic-gate 
1049*0Sstevel@tonic-gate 	DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet)));
1050*0Sstevel@tonic-gate 	if (comp && comp->enabled) {
1051*0Sstevel@tonic-gate 		buffer_clear(&compression_buffer);
1052*0Sstevel@tonic-gate 		buffer_uncompress(&incoming_packet, &compression_buffer);
1053*0Sstevel@tonic-gate 		buffer_clear(&incoming_packet);
1054*0Sstevel@tonic-gate 		buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
1055*0Sstevel@tonic-gate 		    buffer_len(&compression_buffer));
1056*0Sstevel@tonic-gate 		DBG(debug("input: len after de-compress %d",
1057*0Sstevel@tonic-gate 		    buffer_len(&incoming_packet)));
1058*0Sstevel@tonic-gate 	}
1059*0Sstevel@tonic-gate 	/*
1060*0Sstevel@tonic-gate 	 * get packet type, implies consume.
1061*0Sstevel@tonic-gate 	 * return length of payload (without type field)
1062*0Sstevel@tonic-gate 	 */
1063*0Sstevel@tonic-gate 	type = buffer_get_char(&incoming_packet);
1064*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
1065*0Sstevel@tonic-gate 	if (type == SSH2_MSG_NEWKEYS)
1066*0Sstevel@tonic-gate 		/* set_newkeys(MODE_OUT) in client, server, but not monitor */
1067*0Sstevel@tonic-gate 		if (!packet_is_server() && !packet_is_monitor())
1068*0Sstevel@tonic-gate 			set_newkeys(MODE_IN);
1069*0Sstevel@tonic-gate #else /* ALTPRIVSEP */
1070*0Sstevel@tonic-gate 	if (type == SSH2_MSG_NEWKEYS)
1071*0Sstevel@tonic-gate 		set_newkeys(MODE_IN);
1072*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
1073*0Sstevel@tonic-gate #ifdef PACKET_DEBUG
1074*0Sstevel@tonic-gate 	fprintf(stderr, "read/plain[%d]:\r\n", type);
1075*0Sstevel@tonic-gate 	buffer_dump(&incoming_packet);
1076*0Sstevel@tonic-gate #endif
1077*0Sstevel@tonic-gate 	/* reset for next packet */
1078*0Sstevel@tonic-gate 	packet_length = 0;
1079*0Sstevel@tonic-gate 	return type;
1080*0Sstevel@tonic-gate }
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate int
1083*0Sstevel@tonic-gate packet_read_poll_seqnr(u_int32_t *seqnr_p)
1084*0Sstevel@tonic-gate {
1085*0Sstevel@tonic-gate 	u_int reason, seqnr;
1086*0Sstevel@tonic-gate 	u_char type;
1087*0Sstevel@tonic-gate 	char *msg;
1088*0Sstevel@tonic-gate 
1089*0Sstevel@tonic-gate 	for (;;) {
1090*0Sstevel@tonic-gate 		if (compat20) {
1091*0Sstevel@tonic-gate 			type = packet_read_poll2(seqnr_p);
1092*0Sstevel@tonic-gate 			DBG(debug("received packet type %d", type));
1093*0Sstevel@tonic-gate 			switch (type) {
1094*0Sstevel@tonic-gate 			case SSH2_MSG_IGNORE:
1095*0Sstevel@tonic-gate 				break;
1096*0Sstevel@tonic-gate 			case SSH2_MSG_DEBUG:
1097*0Sstevel@tonic-gate 				packet_get_char();
1098*0Sstevel@tonic-gate 				msg = packet_get_string(NULL);
1099*0Sstevel@tonic-gate 				debug("Remote: %.900s", msg);
1100*0Sstevel@tonic-gate 				xfree(msg);
1101*0Sstevel@tonic-gate 				msg = packet_get_string(NULL);
1102*0Sstevel@tonic-gate 				xfree(msg);
1103*0Sstevel@tonic-gate 				break;
1104*0Sstevel@tonic-gate 			case SSH2_MSG_DISCONNECT:
1105*0Sstevel@tonic-gate 				reason = packet_get_int();
1106*0Sstevel@tonic-gate 				msg = packet_get_string(NULL);
1107*0Sstevel@tonic-gate 				log("Received disconnect from %s: %u: %.400s",
1108*0Sstevel@tonic-gate 				    get_remote_ipaddr(), reason, msg);
1109*0Sstevel@tonic-gate 				xfree(msg);
1110*0Sstevel@tonic-gate 				fatal_cleanup();
1111*0Sstevel@tonic-gate 				break;
1112*0Sstevel@tonic-gate 			case SSH2_MSG_UNIMPLEMENTED:
1113*0Sstevel@tonic-gate 				seqnr = packet_get_int();
1114*0Sstevel@tonic-gate 				debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
1115*0Sstevel@tonic-gate 				    seqnr);
1116*0Sstevel@tonic-gate 				break;
1117*0Sstevel@tonic-gate 			default:
1118*0Sstevel@tonic-gate 				return type;
1119*0Sstevel@tonic-gate 				break;
1120*0Sstevel@tonic-gate 			}
1121*0Sstevel@tonic-gate 		} else {
1122*0Sstevel@tonic-gate 			type = packet_read_poll1();
1123*0Sstevel@tonic-gate 			DBG(debug("received packet type %d", type));
1124*0Sstevel@tonic-gate 			switch (type) {
1125*0Sstevel@tonic-gate 			case SSH_MSG_IGNORE:
1126*0Sstevel@tonic-gate 				break;
1127*0Sstevel@tonic-gate 			case SSH_MSG_DEBUG:
1128*0Sstevel@tonic-gate 				msg = packet_get_string(NULL);
1129*0Sstevel@tonic-gate 				debug("Remote: %.900s", msg);
1130*0Sstevel@tonic-gate 				xfree(msg);
1131*0Sstevel@tonic-gate 				break;
1132*0Sstevel@tonic-gate 			case SSH_MSG_DISCONNECT:
1133*0Sstevel@tonic-gate 				msg = packet_get_string(NULL);
1134*0Sstevel@tonic-gate 				log("Received disconnect from %s: %.400s",
1135*0Sstevel@tonic-gate 				    get_remote_ipaddr(), msg);
1136*0Sstevel@tonic-gate 				fatal_cleanup();
1137*0Sstevel@tonic-gate 				xfree(msg);
1138*0Sstevel@tonic-gate 				break;
1139*0Sstevel@tonic-gate 			default:
1140*0Sstevel@tonic-gate 				return type;
1141*0Sstevel@tonic-gate 				break;
1142*0Sstevel@tonic-gate 			}
1143*0Sstevel@tonic-gate 		}
1144*0Sstevel@tonic-gate 	}
1145*0Sstevel@tonic-gate }
1146*0Sstevel@tonic-gate 
1147*0Sstevel@tonic-gate int
1148*0Sstevel@tonic-gate packet_read_poll(void)
1149*0Sstevel@tonic-gate {
1150*0Sstevel@tonic-gate 	return packet_read_poll_seqnr(NULL);
1151*0Sstevel@tonic-gate }
1152*0Sstevel@tonic-gate 
1153*0Sstevel@tonic-gate /*
1154*0Sstevel@tonic-gate  * Buffers the given amount of input characters.  This is intended to be used
1155*0Sstevel@tonic-gate  * together with packet_read_poll.
1156*0Sstevel@tonic-gate  */
1157*0Sstevel@tonic-gate 
1158*0Sstevel@tonic-gate void
1159*0Sstevel@tonic-gate packet_process_incoming(const char *buf, u_int len)
1160*0Sstevel@tonic-gate {
1161*0Sstevel@tonic-gate 	buffer_append(&input, buf, len);
1162*0Sstevel@tonic-gate }
1163*0Sstevel@tonic-gate 
1164*0Sstevel@tonic-gate /* Returns a character from the packet. */
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate u_int
1167*0Sstevel@tonic-gate packet_get_char(void)
1168*0Sstevel@tonic-gate {
1169*0Sstevel@tonic-gate 	char ch;
1170*0Sstevel@tonic-gate 
1171*0Sstevel@tonic-gate 	buffer_get(&incoming_packet, &ch, 1);
1172*0Sstevel@tonic-gate 	return (u_char) ch;
1173*0Sstevel@tonic-gate }
1174*0Sstevel@tonic-gate 
1175*0Sstevel@tonic-gate /* Returns an integer from the packet data. */
1176*0Sstevel@tonic-gate 
1177*0Sstevel@tonic-gate u_int
1178*0Sstevel@tonic-gate packet_get_int(void)
1179*0Sstevel@tonic-gate {
1180*0Sstevel@tonic-gate 	return buffer_get_int(&incoming_packet);
1181*0Sstevel@tonic-gate }
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate /*
1184*0Sstevel@tonic-gate  * Returns an arbitrary precision integer from the packet data.  The integer
1185*0Sstevel@tonic-gate  * must have been initialized before this call.
1186*0Sstevel@tonic-gate  */
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate void
1189*0Sstevel@tonic-gate packet_get_bignum(BIGNUM * value)
1190*0Sstevel@tonic-gate {
1191*0Sstevel@tonic-gate 	buffer_get_bignum(&incoming_packet, value);
1192*0Sstevel@tonic-gate }
1193*0Sstevel@tonic-gate 
1194*0Sstevel@tonic-gate void
1195*0Sstevel@tonic-gate packet_get_bignum2(BIGNUM * value)
1196*0Sstevel@tonic-gate {
1197*0Sstevel@tonic-gate 	buffer_get_bignum2(&incoming_packet, value);
1198*0Sstevel@tonic-gate }
1199*0Sstevel@tonic-gate 
1200*0Sstevel@tonic-gate void *
1201*0Sstevel@tonic-gate packet_get_raw(u_int *length_ptr)
1202*0Sstevel@tonic-gate {
1203*0Sstevel@tonic-gate 	u_int bytes = buffer_len(&incoming_packet);
1204*0Sstevel@tonic-gate 
1205*0Sstevel@tonic-gate 	if (length_ptr != NULL)
1206*0Sstevel@tonic-gate 		*length_ptr = bytes;
1207*0Sstevel@tonic-gate 	return buffer_ptr(&incoming_packet);
1208*0Sstevel@tonic-gate }
1209*0Sstevel@tonic-gate 
1210*0Sstevel@tonic-gate int
1211*0Sstevel@tonic-gate packet_remaining(void)
1212*0Sstevel@tonic-gate {
1213*0Sstevel@tonic-gate 	return buffer_len(&incoming_packet);
1214*0Sstevel@tonic-gate }
1215*0Sstevel@tonic-gate 
1216*0Sstevel@tonic-gate /*
1217*0Sstevel@tonic-gate  * Returns a string from the packet data.  The string is allocated using
1218*0Sstevel@tonic-gate  * xmalloc; it is the responsibility of the calling program to free it when
1219*0Sstevel@tonic-gate  * no longer needed.  The length_ptr argument may be NULL, or point to an
1220*0Sstevel@tonic-gate  * integer into which the length of the string is stored.
1221*0Sstevel@tonic-gate  */
1222*0Sstevel@tonic-gate 
1223*0Sstevel@tonic-gate void *
1224*0Sstevel@tonic-gate packet_get_string(u_int *length_ptr)
1225*0Sstevel@tonic-gate {
1226*0Sstevel@tonic-gate 	return buffer_get_string(&incoming_packet, length_ptr);
1227*0Sstevel@tonic-gate }
1228*0Sstevel@tonic-gate char *
1229*0Sstevel@tonic-gate packet_get_ascii_cstring()
1230*0Sstevel@tonic-gate {
1231*0Sstevel@tonic-gate 	return buffer_get_ascii_cstring(&incoming_packet);
1232*0Sstevel@tonic-gate }
1233*0Sstevel@tonic-gate u_char *
1234*0Sstevel@tonic-gate packet_get_utf8_cstring()
1235*0Sstevel@tonic-gate {
1236*0Sstevel@tonic-gate 	return buffer_get_utf8_cstring(&incoming_packet);
1237*0Sstevel@tonic-gate }
1238*0Sstevel@tonic-gate 
1239*0Sstevel@tonic-gate /*
1240*0Sstevel@tonic-gate  * Sends a diagnostic message from the server to the client.  This message
1241*0Sstevel@tonic-gate  * can be sent at any time (but not while constructing another message). The
1242*0Sstevel@tonic-gate  * message is printed immediately, but only if the client is being executed
1243*0Sstevel@tonic-gate  * in verbose mode.  These messages are primarily intended to ease debugging
1244*0Sstevel@tonic-gate  * authentication problems.   The length of the formatted message must not
1245*0Sstevel@tonic-gate  * exceed 1024 bytes.  This will automatically call packet_write_wait.
1246*0Sstevel@tonic-gate  */
1247*0Sstevel@tonic-gate 
1248*0Sstevel@tonic-gate void
1249*0Sstevel@tonic-gate packet_send_debug(const char *fmt,...)
1250*0Sstevel@tonic-gate {
1251*0Sstevel@tonic-gate 	char buf[1024];
1252*0Sstevel@tonic-gate 	va_list args;
1253*0Sstevel@tonic-gate 
1254*0Sstevel@tonic-gate 	if (compat20 && (datafellows & SSH_BUG_DEBUG))
1255*0Sstevel@tonic-gate 		return;
1256*0Sstevel@tonic-gate 
1257*0Sstevel@tonic-gate 	va_start(args, fmt);
1258*0Sstevel@tonic-gate 	vsnprintf(buf, sizeof(buf), gettext(fmt), args);
1259*0Sstevel@tonic-gate 	va_end(args);
1260*0Sstevel@tonic-gate 
1261*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
1262*0Sstevel@tonic-gate 	/* shouldn't happen */
1263*0Sstevel@tonic-gate 	if (packet_monitor) {
1264*0Sstevel@tonic-gate 		debug("packet_send_debug: %s", buf);
1265*0Sstevel@tonic-gate 		return;
1266*0Sstevel@tonic-gate 	}
1267*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
1268*0Sstevel@tonic-gate 
1269*0Sstevel@tonic-gate 	if (compat20) {
1270*0Sstevel@tonic-gate 		packet_start(SSH2_MSG_DEBUG);
1271*0Sstevel@tonic-gate 		packet_put_char(0);	/* bool: always display */
1272*0Sstevel@tonic-gate 		packet_put_cstring(buf);
1273*0Sstevel@tonic-gate 		packet_put_cstring("");
1274*0Sstevel@tonic-gate 	} else {
1275*0Sstevel@tonic-gate 		packet_start(SSH_MSG_DEBUG);
1276*0Sstevel@tonic-gate 		packet_put_cstring(buf);
1277*0Sstevel@tonic-gate 	}
1278*0Sstevel@tonic-gate 	packet_send();
1279*0Sstevel@tonic-gate 	packet_write_wait();
1280*0Sstevel@tonic-gate }
1281*0Sstevel@tonic-gate 
1282*0Sstevel@tonic-gate /*
1283*0Sstevel@tonic-gate  * Logs the error plus constructs and sends a disconnect packet, closes the
1284*0Sstevel@tonic-gate  * connection, and exits.  This function never returns. The error message
1285*0Sstevel@tonic-gate  * should not contain a newline.  The length of the formatted message must
1286*0Sstevel@tonic-gate  * not exceed 1024 bytes.
1287*0Sstevel@tonic-gate  */
1288*0Sstevel@tonic-gate 
1289*0Sstevel@tonic-gate void
1290*0Sstevel@tonic-gate packet_disconnect(const char *fmt,...)
1291*0Sstevel@tonic-gate {
1292*0Sstevel@tonic-gate 	char buf[1024];
1293*0Sstevel@tonic-gate 	va_list args;
1294*0Sstevel@tonic-gate 	static int disconnecting = 0;
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate 	if (disconnecting)	/* Guard against recursive invocations. */
1297*0Sstevel@tonic-gate 		fatal("packet_disconnect called recursively.");
1298*0Sstevel@tonic-gate 	disconnecting = 1;
1299*0Sstevel@tonic-gate 
1300*0Sstevel@tonic-gate 	/*
1301*0Sstevel@tonic-gate 	 * Format the message.  Note that the caller must make sure the
1302*0Sstevel@tonic-gate 	 * message is of limited size.
1303*0Sstevel@tonic-gate 	 */
1304*0Sstevel@tonic-gate 	va_start(args, fmt);
1305*0Sstevel@tonic-gate 	vsnprintf(buf, sizeof(buf), fmt, args);
1306*0Sstevel@tonic-gate 	va_end(args);
1307*0Sstevel@tonic-gate 
1308*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
1309*0Sstevel@tonic-gate 	/*
1310*0Sstevel@tonic-gate 	 * If we packet_disconnect() in the monitor the fatal cleanups will take
1311*0Sstevel@tonic-gate 	 * care of the child.  See main() in sshd.c.  We don't send the packet
1312*0Sstevel@tonic-gate 	 * disconnect message here because: a) the child might not be looking
1313*0Sstevel@tonic-gate 	 * for it and b) because we don't really know if the child is compat20
1314*0Sstevel@tonic-gate 	 * or not as we lost that information when packet_set_monitor() was
1315*0Sstevel@tonic-gate 	 * called.
1316*0Sstevel@tonic-gate 	 */
1317*0Sstevel@tonic-gate 	if (packet_monitor)
1318*0Sstevel@tonic-gate 		goto close_stuff;
1319*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
1320*0Sstevel@tonic-gate 
1321*0Sstevel@tonic-gate 	/* Send the disconnect message to the other side, and wait for it to get sent. */
1322*0Sstevel@tonic-gate 	if (compat20) {
1323*0Sstevel@tonic-gate 		packet_start(SSH2_MSG_DISCONNECT);
1324*0Sstevel@tonic-gate 		packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR);
1325*0Sstevel@tonic-gate 		packet_put_cstring(buf);
1326*0Sstevel@tonic-gate 		packet_put_cstring("");
1327*0Sstevel@tonic-gate 	} else {
1328*0Sstevel@tonic-gate 		packet_start(SSH_MSG_DISCONNECT);
1329*0Sstevel@tonic-gate 		packet_put_cstring(buf);
1330*0Sstevel@tonic-gate 	}
1331*0Sstevel@tonic-gate 	packet_send();
1332*0Sstevel@tonic-gate 	packet_write_wait();
1333*0Sstevel@tonic-gate 
1334*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
1335*0Sstevel@tonic-gate close_stuff:
1336*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
1337*0Sstevel@tonic-gate 	/* Stop listening for connections. */
1338*0Sstevel@tonic-gate 	channel_close_all();
1339*0Sstevel@tonic-gate 
1340*0Sstevel@tonic-gate 	/* Close the connection. */
1341*0Sstevel@tonic-gate 	packet_close();
1342*0Sstevel@tonic-gate 
1343*0Sstevel@tonic-gate 	/* Display the error locally and exit. */
1344*0Sstevel@tonic-gate 	log("Disconnecting: %.100s", buf);
1345*0Sstevel@tonic-gate 	fatal_cleanup();
1346*0Sstevel@tonic-gate }
1347*0Sstevel@tonic-gate 
1348*0Sstevel@tonic-gate /* Checks if there is any buffered output, and tries to write some of the output. */
1349*0Sstevel@tonic-gate 
1350*0Sstevel@tonic-gate void
1351*0Sstevel@tonic-gate packet_write_poll(void)
1352*0Sstevel@tonic-gate {
1353*0Sstevel@tonic-gate 	int len = buffer_len(&output);
1354*0Sstevel@tonic-gate 
1355*0Sstevel@tonic-gate 	if (len > 0) {
1356*0Sstevel@tonic-gate 		len = write(connection_out, buffer_ptr(&output), len);
1357*0Sstevel@tonic-gate 		if (len <= 0) {
1358*0Sstevel@tonic-gate 			if (errno == EAGAIN)
1359*0Sstevel@tonic-gate 				return;
1360*0Sstevel@tonic-gate 			else
1361*0Sstevel@tonic-gate 				fatal("Write failed: %.100s", strerror(errno));
1362*0Sstevel@tonic-gate 		}
1363*0Sstevel@tonic-gate 		buffer_consume(&output, len);
1364*0Sstevel@tonic-gate 	}
1365*0Sstevel@tonic-gate }
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate /*
1368*0Sstevel@tonic-gate  * Calls packet_write_poll repeatedly until all pending output data has been
1369*0Sstevel@tonic-gate  * written.
1370*0Sstevel@tonic-gate  */
1371*0Sstevel@tonic-gate 
1372*0Sstevel@tonic-gate void
1373*0Sstevel@tonic-gate packet_write_wait(void)
1374*0Sstevel@tonic-gate {
1375*0Sstevel@tonic-gate 	fd_set *setp;
1376*0Sstevel@tonic-gate 
1377*0Sstevel@tonic-gate 	setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) *
1378*0Sstevel@tonic-gate 	    sizeof(fd_mask));
1379*0Sstevel@tonic-gate 	packet_write_poll();
1380*0Sstevel@tonic-gate 	while (packet_have_data_to_write()) {
1381*0Sstevel@tonic-gate 		memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
1382*0Sstevel@tonic-gate 		    sizeof(fd_mask));
1383*0Sstevel@tonic-gate 		FD_SET(connection_out, setp);
1384*0Sstevel@tonic-gate 		while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
1385*0Sstevel@tonic-gate 		    (errno == EAGAIN || errno == EINTR))
1386*0Sstevel@tonic-gate 			;
1387*0Sstevel@tonic-gate 		packet_write_poll();
1388*0Sstevel@tonic-gate 	}
1389*0Sstevel@tonic-gate 	xfree(setp);
1390*0Sstevel@tonic-gate }
1391*0Sstevel@tonic-gate 
1392*0Sstevel@tonic-gate /* Returns true if there is buffered data to write to the connection. */
1393*0Sstevel@tonic-gate 
1394*0Sstevel@tonic-gate int
1395*0Sstevel@tonic-gate packet_have_data_to_write(void)
1396*0Sstevel@tonic-gate {
1397*0Sstevel@tonic-gate 	return buffer_len(&output) != 0;
1398*0Sstevel@tonic-gate }
1399*0Sstevel@tonic-gate 
1400*0Sstevel@tonic-gate /* Returns true if there is not too much data to write to the connection. */
1401*0Sstevel@tonic-gate 
1402*0Sstevel@tonic-gate int
1403*0Sstevel@tonic-gate packet_not_very_much_data_to_write(void)
1404*0Sstevel@tonic-gate {
1405*0Sstevel@tonic-gate 	if (interactive_mode)
1406*0Sstevel@tonic-gate 		return buffer_len(&output) < 16384;
1407*0Sstevel@tonic-gate 	else
1408*0Sstevel@tonic-gate 		return buffer_len(&output) < 128 * 1024;
1409*0Sstevel@tonic-gate }
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate /* Informs that the current session is interactive.  Sets IP flags for that. */
1412*0Sstevel@tonic-gate 
1413*0Sstevel@tonic-gate void
1414*0Sstevel@tonic-gate packet_set_interactive(int interactive)
1415*0Sstevel@tonic-gate {
1416*0Sstevel@tonic-gate 	static int called = 0;
1417*0Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
1418*0Sstevel@tonic-gate 	int lowdelay = IPTOS_LOWDELAY;
1419*0Sstevel@tonic-gate 	int throughput = IPTOS_THROUGHPUT;
1420*0Sstevel@tonic-gate #endif
1421*0Sstevel@tonic-gate 
1422*0Sstevel@tonic-gate 	if (called)
1423*0Sstevel@tonic-gate 		return;
1424*0Sstevel@tonic-gate 	called = 1;
1425*0Sstevel@tonic-gate 
1426*0Sstevel@tonic-gate 	/* Record that we are in interactive mode. */
1427*0Sstevel@tonic-gate 	interactive_mode = interactive;
1428*0Sstevel@tonic-gate 
1429*0Sstevel@tonic-gate 	/* Only set socket options if using a socket.  */
1430*0Sstevel@tonic-gate 	if (!packet_connection_is_on_socket())
1431*0Sstevel@tonic-gate 		return;
1432*0Sstevel@tonic-gate 	/*
1433*0Sstevel@tonic-gate 	 * IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only
1434*0Sstevel@tonic-gate 	 */
1435*0Sstevel@tonic-gate 	if (interactive) {
1436*0Sstevel@tonic-gate 		/*
1437*0Sstevel@tonic-gate 		 * Set IP options for an interactive connection.  Use
1438*0Sstevel@tonic-gate 		 * IPTOS_LOWDELAY and TCP_NODELAY.
1439*0Sstevel@tonic-gate 		 */
1440*0Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
1441*0Sstevel@tonic-gate 		if (packet_connection_is_ipv4()) {
1442*0Sstevel@tonic-gate 			if (setsockopt(connection_in, IPPROTO_IP, IP_TOS,
1443*0Sstevel@tonic-gate 			    &lowdelay, sizeof(lowdelay)) < 0)
1444*0Sstevel@tonic-gate 				error("setsockopt IPTOS_LOWDELAY: %.100s",
1445*0Sstevel@tonic-gate 				    strerror(errno));
1446*0Sstevel@tonic-gate 		}
1447*0Sstevel@tonic-gate #endif
1448*0Sstevel@tonic-gate 		set_nodelay(connection_in);
1449*0Sstevel@tonic-gate 	}
1450*0Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
1451*0Sstevel@tonic-gate 	else if (packet_connection_is_ipv4()) {
1452*0Sstevel@tonic-gate 		/*
1453*0Sstevel@tonic-gate 		 * Set IP options for a non-interactive connection.  Use
1454*0Sstevel@tonic-gate 		 * IPTOS_THROUGHPUT.
1455*0Sstevel@tonic-gate 		 */
1456*0Sstevel@tonic-gate 		if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &throughput,
1457*0Sstevel@tonic-gate 		    sizeof(throughput)) < 0)
1458*0Sstevel@tonic-gate 			error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
1459*0Sstevel@tonic-gate 	}
1460*0Sstevel@tonic-gate #endif
1461*0Sstevel@tonic-gate }
1462*0Sstevel@tonic-gate 
1463*0Sstevel@tonic-gate /* Returns true if the current connection is interactive. */
1464*0Sstevel@tonic-gate 
1465*0Sstevel@tonic-gate int
1466*0Sstevel@tonic-gate packet_is_interactive(void)
1467*0Sstevel@tonic-gate {
1468*0Sstevel@tonic-gate 	return interactive_mode;
1469*0Sstevel@tonic-gate }
1470*0Sstevel@tonic-gate 
1471*0Sstevel@tonic-gate int
1472*0Sstevel@tonic-gate packet_set_maxsize(int s)
1473*0Sstevel@tonic-gate {
1474*0Sstevel@tonic-gate 	static int called = 0;
1475*0Sstevel@tonic-gate 
1476*0Sstevel@tonic-gate 	if (called) {
1477*0Sstevel@tonic-gate 		log("packet_set_maxsize: called twice: old %d new %d",
1478*0Sstevel@tonic-gate 		    max_packet_size, s);
1479*0Sstevel@tonic-gate 		return -1;
1480*0Sstevel@tonic-gate 	}
1481*0Sstevel@tonic-gate 	if (s < 4 * 1024 || s > 1024 * 1024) {
1482*0Sstevel@tonic-gate 		log("packet_set_maxsize: bad size %d", s);
1483*0Sstevel@tonic-gate 		return -1;
1484*0Sstevel@tonic-gate 	}
1485*0Sstevel@tonic-gate 	called = 1;
1486*0Sstevel@tonic-gate 	debug("packet_set_maxsize: setting to %d", s);
1487*0Sstevel@tonic-gate 	max_packet_size = s;
1488*0Sstevel@tonic-gate 	return s;
1489*0Sstevel@tonic-gate }
1490*0Sstevel@tonic-gate 
1491*0Sstevel@tonic-gate /* roundup current message to pad bytes */
1492*0Sstevel@tonic-gate void
1493*0Sstevel@tonic-gate packet_add_padding(u_char pad)
1494*0Sstevel@tonic-gate {
1495*0Sstevel@tonic-gate 	extra_pad = pad;
1496*0Sstevel@tonic-gate }
1497*0Sstevel@tonic-gate 
1498*0Sstevel@tonic-gate /*
1499*0Sstevel@tonic-gate  * 9.2.  Ignored Data Message
1500*0Sstevel@tonic-gate  *
1501*0Sstevel@tonic-gate  *   byte      SSH_MSG_IGNORE
1502*0Sstevel@tonic-gate  *   string    data
1503*0Sstevel@tonic-gate  *
1504*0Sstevel@tonic-gate  * All implementations MUST understand (and ignore) this message at any
1505*0Sstevel@tonic-gate  * time (after receiving the protocol version). No implementation is
1506*0Sstevel@tonic-gate  * required to send them. This message can be used as an additional
1507*0Sstevel@tonic-gate  * protection measure against advanced traffic analysis techniques.
1508*0Sstevel@tonic-gate  */
1509*0Sstevel@tonic-gate void
1510*0Sstevel@tonic-gate packet_send_ignore(int nbytes)
1511*0Sstevel@tonic-gate {
1512*0Sstevel@tonic-gate 	u_int32_t rand = 0;
1513*0Sstevel@tonic-gate 	int i;
1514*0Sstevel@tonic-gate 
1515*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
1516*0Sstevel@tonic-gate 	/* shouldn't happen -- see packet_set_monitor() */
1517*0Sstevel@tonic-gate 	if (packet_monitor)
1518*0Sstevel@tonic-gate 		return;
1519*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
1520*0Sstevel@tonic-gate 
1521*0Sstevel@tonic-gate 	packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE);
1522*0Sstevel@tonic-gate 	packet_put_int(nbytes);
1523*0Sstevel@tonic-gate 	for (i = 0; i < nbytes; i++) {
1524*0Sstevel@tonic-gate 		if (i % 4 == 0)
1525*0Sstevel@tonic-gate 			rand = arc4random();
1526*0Sstevel@tonic-gate 		packet_put_char(rand & 0xff);
1527*0Sstevel@tonic-gate 		rand >>= 8;
1528*0Sstevel@tonic-gate 	}
1529*0Sstevel@tonic-gate }
1530*0Sstevel@tonic-gate 
1531*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
1532*0Sstevel@tonic-gate void
1533*0Sstevel@tonic-gate packet_set_server(void)
1534*0Sstevel@tonic-gate {
1535*0Sstevel@tonic-gate 	packet_server = 1;
1536*0Sstevel@tonic-gate }
1537*0Sstevel@tonic-gate 
1538*0Sstevel@tonic-gate void
1539*0Sstevel@tonic-gate packet_set_no_monitor(void)
1540*0Sstevel@tonic-gate {
1541*0Sstevel@tonic-gate 	packet_server = 0;
1542*0Sstevel@tonic-gate }
1543*0Sstevel@tonic-gate 
1544*0Sstevel@tonic-gate int
1545*0Sstevel@tonic-gate packet_is_server(void)
1546*0Sstevel@tonic-gate {
1547*0Sstevel@tonic-gate 	return (packet_server);
1548*0Sstevel@tonic-gate }
1549*0Sstevel@tonic-gate 
1550*0Sstevel@tonic-gate void
1551*0Sstevel@tonic-gate packet_set_monitor(int pipe)
1552*0Sstevel@tonic-gate {
1553*0Sstevel@tonic-gate 	int dup_fd;
1554*0Sstevel@tonic-gate 
1555*0Sstevel@tonic-gate 	packet_server = 1;
1556*0Sstevel@tonic-gate 	packet_monitor = 1;
1557*0Sstevel@tonic-gate 
1558*0Sstevel@tonic-gate 	/*
1559*0Sstevel@tonic-gate 	 * Awful hack follows.
1560*0Sstevel@tonic-gate 	 *
1561*0Sstevel@tonic-gate 	 * For SSHv1 the monitor does not process any SSHv1 packets, only
1562*0Sstevel@tonic-gate 	 * ALTPRIVSEP packets.  We take advantage of that here to keep changes
1563*0Sstevel@tonic-gate 	 * to packet.c to a minimum by using the SSHv2 binary packet protocol,
1564*0Sstevel@tonic-gate 	 * with cipher "none," mac "none" and compression alg "none," as the
1565*0Sstevel@tonic-gate 	 * basis for the monitor protocol.  And so to force packet.c to treat
1566*0Sstevel@tonic-gate 	 * packets as SSHv2 we force compat20 == 1 here.
1567*0Sstevel@tonic-gate 	 *
1568*0Sstevel@tonic-gate 	 * For completeness and to help future developers catch this we also
1569*0Sstevel@tonic-gate 	 * force compat20 == 1 in the monitor loop, in serverloop.c.
1570*0Sstevel@tonic-gate 	 */
1571*0Sstevel@tonic-gate 	compat20 = 1;
1572*0Sstevel@tonic-gate 
1573*0Sstevel@tonic-gate 	/*
1574*0Sstevel@tonic-gate 	 * NOTE:  Assumptions below!
1575*0Sstevel@tonic-gate 	 *
1576*0Sstevel@tonic-gate 	 *  - lots of packet.c code assumes that (connection_in ==
1577*0Sstevel@tonic-gate 	 *  connection_out) -> connection is socket
1578*0Sstevel@tonic-gate 	 *
1579*0Sstevel@tonic-gate 	 *  - packet_close() does not shutdown() the connection fildes
1580*0Sstevel@tonic-gate 	 *  if connection_in != connection_out
1581*0Sstevel@tonic-gate 	 *
1582*0Sstevel@tonic-gate 	 *  - other code assumes the connection is a socket if
1583*0Sstevel@tonic-gate 	 *  connection_in == connection_out
1584*0Sstevel@tonic-gate 	 */
1585*0Sstevel@tonic-gate 
1586*0Sstevel@tonic-gate 	if ((dup_fd = dup(pipe)) < 0)
1587*0Sstevel@tonic-gate 		fatal("Monitor failed to start: %s", strerror(errno));
1588*0Sstevel@tonic-gate 
1589*0Sstevel@tonic-gate 	/*
1590*0Sstevel@tonic-gate 	 * make sure that the monitor's child's socket is not shutdown(3SOCKET)
1591*0Sstevel@tonic-gate 	 * when we packet_close()
1592*0Sstevel@tonic-gate 	 */
1593*0Sstevel@tonic-gate 	if (packet_connection_is_on_socket())
1594*0Sstevel@tonic-gate 		connection_out = -1;
1595*0Sstevel@tonic-gate 
1596*0Sstevel@tonic-gate 	/* now cleanup state related to ssh socket */
1597*0Sstevel@tonic-gate 	packet_close();
1598*0Sstevel@tonic-gate 
1599*0Sstevel@tonic-gate 	/* now make the monitor pipe look like the ssh connection */
1600*0Sstevel@tonic-gate 	packet_set_connection(pipe, dup_fd);
1601*0Sstevel@tonic-gate }
1602*0Sstevel@tonic-gate 
1603*0Sstevel@tonic-gate int
1604*0Sstevel@tonic-gate packet_is_monitor(void)
1605*0Sstevel@tonic-gate {
1606*0Sstevel@tonic-gate 	return (packet_monitor);
1607*0Sstevel@tonic-gate }
1608*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
1609