17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * Author: Tatu Ylonen <ylo@cs.hut.fi>
37c478bd9Sstevel@tonic-gate * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
47c478bd9Sstevel@tonic-gate * All rights reserved
57c478bd9Sstevel@tonic-gate * This file contains code implementing the packet protocol and communication
67c478bd9Sstevel@tonic-gate * with the other side. This same code is used both on client and server side.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * As far as I am concerned, the code I have written for this software
97c478bd9Sstevel@tonic-gate * can be used freely for any purpose. Any derived versions of this
107c478bd9Sstevel@tonic-gate * software must be clearly marked as such, and if the derived work is
117c478bd9Sstevel@tonic-gate * incompatible with the protocol description in the RFC file, it must be
127c478bd9Sstevel@tonic-gate * called by a name other than "ssh" or "Secure Shell".
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate *
157c478bd9Sstevel@tonic-gate * SSH2 packet format added by Markus Friedl.
167c478bd9Sstevel@tonic-gate * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
177c478bd9Sstevel@tonic-gate *
187c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
197c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions
207c478bd9Sstevel@tonic-gate * are met:
217c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
227c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
237c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
247c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
257c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
267c478bd9Sstevel@tonic-gate *
277c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
287c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
297c478bd9Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
307c478bd9Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
317c478bd9Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
327c478bd9Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
337c478bd9Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
347c478bd9Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
357c478bd9Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
367c478bd9Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
377c478bd9Sstevel@tonic-gate */
387c478bd9Sstevel@tonic-gate /*
398caf082fSJan Pechanec * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
407c478bd9Sstevel@tonic-gate * Use is subject to license terms.
417c478bd9Sstevel@tonic-gate */
427c478bd9Sstevel@tonic-gate
439a8058b5Sjp161948 /* $OpenBSD: packet.c,v 1.148 2007/06/07 19:37:34 pvalchev Exp $ */
447c478bd9Sstevel@tonic-gate
459a8058b5Sjp161948 #include "includes.h"
469a8058b5Sjp161948
479a8058b5Sjp161948 #include "sys-queue.h"
487c478bd9Sstevel@tonic-gate #include "xmalloc.h"
497c478bd9Sstevel@tonic-gate #include "buffer.h"
507c478bd9Sstevel@tonic-gate #include "packet.h"
517c478bd9Sstevel@tonic-gate #include "bufaux.h"
527c478bd9Sstevel@tonic-gate #include "crc32.h"
537c478bd9Sstevel@tonic-gate #include "getput.h"
547c478bd9Sstevel@tonic-gate #include "compress.h"
557c478bd9Sstevel@tonic-gate #include "deattack.h"
567c478bd9Sstevel@tonic-gate #include "channels.h"
577c478bd9Sstevel@tonic-gate #include "compat.h"
587c478bd9Sstevel@tonic-gate #include "ssh1.h"
597c478bd9Sstevel@tonic-gate #include "ssh2.h"
607c478bd9Sstevel@tonic-gate #include "cipher.h"
617c478bd9Sstevel@tonic-gate #include "kex.h"
627c478bd9Sstevel@tonic-gate #include "mac.h"
637c478bd9Sstevel@tonic-gate #include "log.h"
647c478bd9Sstevel@tonic-gate #include "canohost.h"
657c478bd9Sstevel@tonic-gate #include "misc.h"
667c478bd9Sstevel@tonic-gate #include "ssh.h"
67cd7d5fafSJan Pechanec #include "engine.h"
68cd7d5fafSJan Pechanec
69cd7d5fafSJan Pechanec /* PKCS#11 engine */
70cd7d5fafSJan Pechanec ENGINE *e;
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate #ifdef ALTPRIVSEP
737c478bd9Sstevel@tonic-gate static int packet_server = 0;
747c478bd9Sstevel@tonic-gate static int packet_monitor = 0;
757c478bd9Sstevel@tonic-gate #endif /* ALTPRIVSEP */
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate #ifdef PACKET_DEBUG
787c478bd9Sstevel@tonic-gate #define DBG(x) x
797c478bd9Sstevel@tonic-gate #else
807c478bd9Sstevel@tonic-gate #define DBG(x)
817c478bd9Sstevel@tonic-gate #endif
827c478bd9Sstevel@tonic-gate
83cd7d5fafSJan Pechanec static void packet_send2(void);
84cd7d5fafSJan Pechanec
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate * This variable contains the file descriptors used for communicating with
877c478bd9Sstevel@tonic-gate * the other side. connection_in is used for reading; connection_out for
887c478bd9Sstevel@tonic-gate * writing. These can be the same descriptor, in which case it is assumed to
897c478bd9Sstevel@tonic-gate * be a socket.
907c478bd9Sstevel@tonic-gate */
917c478bd9Sstevel@tonic-gate static int connection_in = -1;
927c478bd9Sstevel@tonic-gate static int connection_out = -1;
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate /* Protocol flags for the remote side. */
957c478bd9Sstevel@tonic-gate static u_int remote_protocol_flags = 0;
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate /* Encryption context for receiving data. This is only used for decryption. */
987c478bd9Sstevel@tonic-gate static CipherContext receive_context;
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate /* Encryption context for sending data. This is only used for encryption. */
1017c478bd9Sstevel@tonic-gate static CipherContext send_context;
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate /* Buffer for raw input data from the socket. */
1047c478bd9Sstevel@tonic-gate Buffer input;
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate /* Buffer for raw output data going to the socket. */
1077c478bd9Sstevel@tonic-gate Buffer output;
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate /* Buffer for the partial outgoing packet being constructed. */
1107c478bd9Sstevel@tonic-gate static Buffer outgoing_packet;
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate /* Buffer for the incoming packet currently being processed. */
1137c478bd9Sstevel@tonic-gate static Buffer incoming_packet;
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate /* Scratch buffer for packet compression/decompression. */
1167c478bd9Sstevel@tonic-gate static Buffer compression_buffer;
1177c478bd9Sstevel@tonic-gate static int compression_buffer_ready = 0;
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate /* Flag indicating whether packet compression/decompression is enabled. */
1207c478bd9Sstevel@tonic-gate static int packet_compression = 0;
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate /* default maximum packet size */
1237c478bd9Sstevel@tonic-gate int max_packet_size = 32768;
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate /* Flag indicating whether this module has been initialized. */
1267c478bd9Sstevel@tonic-gate static int initialized = 0;
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate /* Set to true if the connection is interactive. */
1297c478bd9Sstevel@tonic-gate static int interactive_mode = 0;
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate /* Session key information for Encryption and MAC */
1327c478bd9Sstevel@tonic-gate Newkeys *newkeys[MODE_MAX];
1339a8058b5Sjp161948 static struct packet_state {
1349a8058b5Sjp161948 u_int32_t seqnr;
1359a8058b5Sjp161948 u_int32_t packets;
1369a8058b5Sjp161948 u_int64_t blocks;
1379a8058b5Sjp161948 } p_read, p_send;
1389a8058b5Sjp161948
1399a8058b5Sjp161948 static u_int64_t max_blocks_in, max_blocks_out;
1409a8058b5Sjp161948 static u_int32_t rekey_limit;
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate /* Session key for protocol v1 */
1437c478bd9Sstevel@tonic-gate static u_char ssh1_key[SSH_SESSION_KEY_LENGTH];
1447c478bd9Sstevel@tonic-gate static u_int ssh1_keylen;
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate /* roundup current message to extra_pad bytes */
1477c478bd9Sstevel@tonic-gate static u_char extra_pad = 0;
1487c478bd9Sstevel@tonic-gate
1499a8058b5Sjp161948 struct packet {
1509a8058b5Sjp161948 TAILQ_ENTRY(packet) next;
1519a8058b5Sjp161948 u_char type;
1529a8058b5Sjp161948 Buffer payload;
1539a8058b5Sjp161948 };
1549a8058b5Sjp161948 TAILQ_HEAD(, packet) outgoing;
1559a8058b5Sjp161948
1567c478bd9Sstevel@tonic-gate /*
157cd7d5fafSJan Pechanec * Part of what -f option and ~& escape sequence do in the client is that they
158cd7d5fafSJan Pechanec * will force it to daemonize itself. Due to the fork safety rules inherent in
159cd7d5fafSJan Pechanec * any PKCS#11 environment, if the engine is used we must do a key re-exchange
160cd7d5fafSJan Pechanec * before forking a child to negotiate the new keys. Those keys will be used to
161cd7d5fafSJan Pechanec * inicialize the new crypto contexts. This involves finishing the engine in the
162cd7d5fafSJan Pechanec * parent and reinitializing it again in both processes after fork() returns.
163cd7d5fafSJan Pechanec * This approach also leaves protocol 1 out since it doesn't support rekeying.
164cd7d5fafSJan Pechanec */
165cd7d5fafSJan Pechanec int will_daemonize;
166cd7d5fafSJan Pechanec
167cd7d5fafSJan Pechanec #ifdef PACKET_DEBUG
168cd7d5fafSJan Pechanec /* This function dumps data onto stderr. This is for debugging only. */
169cd7d5fafSJan Pechanec void
data_dump(void * data,u_int len)170cd7d5fafSJan Pechanec data_dump(void *data, u_int len)
171cd7d5fafSJan Pechanec {
172cd7d5fafSJan Pechanec Buffer buf;
173cd7d5fafSJan Pechanec
174cd7d5fafSJan Pechanec buffer_init(&buf);
175cd7d5fafSJan Pechanec buffer_append(&buf, data, len);
176cd7d5fafSJan Pechanec buffer_dump(&buf);
177cd7d5fafSJan Pechanec buffer_free(&buf);
178cd7d5fafSJan Pechanec }
179cd7d5fafSJan Pechanec #endif
180cd7d5fafSJan Pechanec
181cd7d5fafSJan Pechanec /*
1827c478bd9Sstevel@tonic-gate * Sets the descriptors used for communication. Disables encryption until
1837c478bd9Sstevel@tonic-gate * packet_set_encryption_key is called.
1847c478bd9Sstevel@tonic-gate */
1857c478bd9Sstevel@tonic-gate void
packet_set_connection(int fd_in,int fd_out)1867c478bd9Sstevel@tonic-gate packet_set_connection(int fd_in, int fd_out)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate Cipher *none = cipher_by_name("none");
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate if (none == NULL)
1917c478bd9Sstevel@tonic-gate fatal("packet_set_connection: cannot load cipher 'none'");
1927c478bd9Sstevel@tonic-gate connection_in = fd_in;
1937c478bd9Sstevel@tonic-gate connection_out = fd_out;
1947c478bd9Sstevel@tonic-gate cipher_init(&send_context, none, (unsigned char *) "", 0, NULL, 0, CIPHER_ENCRYPT);
1957c478bd9Sstevel@tonic-gate cipher_init(&receive_context, none, (unsigned char *) "", 0, NULL, 0, CIPHER_DECRYPT);
1967c478bd9Sstevel@tonic-gate newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
1977c478bd9Sstevel@tonic-gate if (!initialized) {
1987c478bd9Sstevel@tonic-gate initialized = 1;
1997c478bd9Sstevel@tonic-gate buffer_init(&input);
2007c478bd9Sstevel@tonic-gate buffer_init(&output);
2017c478bd9Sstevel@tonic-gate buffer_init(&outgoing_packet);
2027c478bd9Sstevel@tonic-gate buffer_init(&incoming_packet);
2039a8058b5Sjp161948 TAILQ_INIT(&outgoing);
2047c478bd9Sstevel@tonic-gate } else {
2057c478bd9Sstevel@tonic-gate buffer_clear(&input);
2067c478bd9Sstevel@tonic-gate buffer_clear(&output);
2077c478bd9Sstevel@tonic-gate buffer_clear(&outgoing_packet);
2087c478bd9Sstevel@tonic-gate buffer_clear(&incoming_packet);
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate * Prime the cache for get_remote_ipaddr() while we have a
2137c478bd9Sstevel@tonic-gate * socket on which to do a getpeername().
2147c478bd9Sstevel@tonic-gate */
2157c478bd9Sstevel@tonic-gate (void) get_remote_ipaddr();
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate /* Kludge: arrange the close function to be called from fatal(). */
2187c478bd9Sstevel@tonic-gate fatal_add_cleanup((void (*) (void *)) packet_close, NULL);
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate /* Returns 1 if remote host is connected via socket, 0 if not. */
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate int
packet_connection_is_on_socket(void)2247c478bd9Sstevel@tonic-gate packet_connection_is_on_socket(void)
2257c478bd9Sstevel@tonic-gate {
2267c478bd9Sstevel@tonic-gate struct sockaddr_storage from, to;
2277c478bd9Sstevel@tonic-gate socklen_t fromlen, tolen;
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate /* filedescriptors in and out are the same, so it's a socket */
2307c478bd9Sstevel@tonic-gate if (connection_in != -1 && connection_in == connection_out)
2317c478bd9Sstevel@tonic-gate return 1;
2327c478bd9Sstevel@tonic-gate fromlen = sizeof(from);
2337c478bd9Sstevel@tonic-gate memset(&from, 0, sizeof(from));
2347c478bd9Sstevel@tonic-gate if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0)
2357c478bd9Sstevel@tonic-gate return 0;
2367c478bd9Sstevel@tonic-gate tolen = sizeof(to);
2377c478bd9Sstevel@tonic-gate memset(&to, 0, sizeof(to));
2387c478bd9Sstevel@tonic-gate if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0)
2397c478bd9Sstevel@tonic-gate return 0;
2407c478bd9Sstevel@tonic-gate if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0)
2417c478bd9Sstevel@tonic-gate return 0;
2427c478bd9Sstevel@tonic-gate if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
2437c478bd9Sstevel@tonic-gate return 0;
2447c478bd9Sstevel@tonic-gate return 1;
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate /* returns 1 if connection is via ipv4 */
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate int
packet_connection_is_ipv4(void)2507c478bd9Sstevel@tonic-gate packet_connection_is_ipv4(void)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate struct sockaddr_storage to;
2537c478bd9Sstevel@tonic-gate socklen_t tolen = sizeof(to);
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate memset(&to, 0, sizeof(to));
2567c478bd9Sstevel@tonic-gate if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0)
2577c478bd9Sstevel@tonic-gate return 0;
2587c478bd9Sstevel@tonic-gate if (to.ss_family == AF_INET)
2597c478bd9Sstevel@tonic-gate return 1;
2607c478bd9Sstevel@tonic-gate #ifdef IPV4_IN_IPV6
2617c478bd9Sstevel@tonic-gate if (to.ss_family == AF_INET6 &&
2627c478bd9Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr))
2637c478bd9Sstevel@tonic-gate return 1;
2647c478bd9Sstevel@tonic-gate #endif
2657c478bd9Sstevel@tonic-gate return 0;
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate /* Sets the connection into non-blocking mode. */
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate void
packet_set_nonblocking(void)2717c478bd9Sstevel@tonic-gate packet_set_nonblocking(void)
2727c478bd9Sstevel@tonic-gate {
2737c478bd9Sstevel@tonic-gate /* Set the socket into non-blocking mode. */
2747c478bd9Sstevel@tonic-gate if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0)
2757c478bd9Sstevel@tonic-gate error("fcntl O_NONBLOCK: %.100s", strerror(errno));
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate if (connection_out != connection_in) {
2787c478bd9Sstevel@tonic-gate if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0)
2797c478bd9Sstevel@tonic-gate error("fcntl O_NONBLOCK: %.100s", strerror(errno));
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate /* Returns the socket used for reading. */
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate int
packet_get_connection_in(void)2867c478bd9Sstevel@tonic-gate packet_get_connection_in(void)
2877c478bd9Sstevel@tonic-gate {
2887c478bd9Sstevel@tonic-gate return connection_in;
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate /* Returns the descriptor used for writing. */
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate int
packet_get_connection_out(void)2947c478bd9Sstevel@tonic-gate packet_get_connection_out(void)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate return connection_out;
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate /* Closes the connection and clears and frees internal data structures. */
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate void
packet_close(void)3027c478bd9Sstevel@tonic-gate packet_close(void)
3037c478bd9Sstevel@tonic-gate {
3047c478bd9Sstevel@tonic-gate if (!initialized)
3057c478bd9Sstevel@tonic-gate return;
3067c478bd9Sstevel@tonic-gate initialized = 0;
3077c478bd9Sstevel@tonic-gate if (connection_in == connection_out) {
3087c478bd9Sstevel@tonic-gate shutdown(connection_out, SHUT_RDWR);
3097c478bd9Sstevel@tonic-gate close(connection_out);
3107c478bd9Sstevel@tonic-gate } else {
3117c478bd9Sstevel@tonic-gate close(connection_in);
3127c478bd9Sstevel@tonic-gate close(connection_out);
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate buffer_free(&input);
3157c478bd9Sstevel@tonic-gate buffer_free(&output);
3167c478bd9Sstevel@tonic-gate buffer_free(&outgoing_packet);
3177c478bd9Sstevel@tonic-gate buffer_free(&incoming_packet);
3187c478bd9Sstevel@tonic-gate if (compression_buffer_ready) {
3197c478bd9Sstevel@tonic-gate buffer_free(&compression_buffer);
3207c478bd9Sstevel@tonic-gate buffer_compress_uninit();
3217c478bd9Sstevel@tonic-gate compression_buffer_ready = 0;
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate cipher_cleanup(&send_context);
3247c478bd9Sstevel@tonic-gate cipher_cleanup(&receive_context);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate /* Sets remote side protocol flags. */
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate void
packet_set_protocol_flags(u_int protocol_flags)3307c478bd9Sstevel@tonic-gate packet_set_protocol_flags(u_int protocol_flags)
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate remote_protocol_flags = protocol_flags;
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate /* Returns the remote protocol flags set earlier by the above function. */
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate u_int
packet_get_protocol_flags(void)3387c478bd9Sstevel@tonic-gate packet_get_protocol_flags(void)
3397c478bd9Sstevel@tonic-gate {
3407c478bd9Sstevel@tonic-gate return remote_protocol_flags;
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate /*
3447c478bd9Sstevel@tonic-gate * Starts packet compression from the next packet on in both directions.
3457c478bd9Sstevel@tonic-gate * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
3467c478bd9Sstevel@tonic-gate */
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate static void
packet_init_compression(void)3497c478bd9Sstevel@tonic-gate packet_init_compression(void)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate if (compression_buffer_ready == 1)
3527c478bd9Sstevel@tonic-gate return;
3537c478bd9Sstevel@tonic-gate compression_buffer_ready = 1;
3547c478bd9Sstevel@tonic-gate buffer_init(&compression_buffer);
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate void
packet_start_compression(int level)3587c478bd9Sstevel@tonic-gate packet_start_compression(int level)
3597c478bd9Sstevel@tonic-gate {
3607c478bd9Sstevel@tonic-gate #ifdef ALTPRIVSEP
3617c478bd9Sstevel@tonic-gate /* shouldn't happen! */
3627c478bd9Sstevel@tonic-gate if (packet_monitor)
3637c478bd9Sstevel@tonic-gate fatal("INTERNAL ERROR: The monitor cannot compress.");
3647c478bd9Sstevel@tonic-gate #endif /* ALTPRIVSEP */
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate if (packet_compression && !compat20)
3677c478bd9Sstevel@tonic-gate fatal("Compression already enabled.");
3687c478bd9Sstevel@tonic-gate packet_compression = 1;
3697c478bd9Sstevel@tonic-gate packet_init_compression();
3707c478bd9Sstevel@tonic-gate buffer_compress_init_send(level);
3717c478bd9Sstevel@tonic-gate buffer_compress_init_recv();
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate
3747c478bd9Sstevel@tonic-gate /*
3757c478bd9Sstevel@tonic-gate * Causes any further packets to be encrypted using the given key. The same
3767c478bd9Sstevel@tonic-gate * key is used for both sending and reception. However, both directions are
3777c478bd9Sstevel@tonic-gate * encrypted independently of each other.
3787c478bd9Sstevel@tonic-gate */
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate void
packet_set_encryption_key(const u_char * key,u_int keylen,int number)3817c478bd9Sstevel@tonic-gate packet_set_encryption_key(const u_char *key, u_int keylen,
3827c478bd9Sstevel@tonic-gate int number)
3837c478bd9Sstevel@tonic-gate {
3847c478bd9Sstevel@tonic-gate Cipher *cipher = cipher_by_number(number);
3857c478bd9Sstevel@tonic-gate
3867c478bd9Sstevel@tonic-gate if (cipher == NULL)
3877c478bd9Sstevel@tonic-gate fatal("packet_set_encryption_key: unknown cipher number %d", number);
3887c478bd9Sstevel@tonic-gate if (keylen < 20)
3897c478bd9Sstevel@tonic-gate fatal("packet_set_encryption_key: keylen too small: %d", keylen);
3907c478bd9Sstevel@tonic-gate if (keylen > SSH_SESSION_KEY_LENGTH)
3917c478bd9Sstevel@tonic-gate fatal("packet_set_encryption_key: keylen too big: %d", keylen);
3927c478bd9Sstevel@tonic-gate memcpy(ssh1_key, key, keylen);
3937c478bd9Sstevel@tonic-gate ssh1_keylen = keylen;
3947c478bd9Sstevel@tonic-gate cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT);
3957c478bd9Sstevel@tonic-gate cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate u_int
packet_get_encryption_key(u_char * key)3997c478bd9Sstevel@tonic-gate packet_get_encryption_key(u_char *key)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate if (key == NULL)
4027c478bd9Sstevel@tonic-gate return (ssh1_keylen);
4037c478bd9Sstevel@tonic-gate memcpy(key, ssh1_key, ssh1_keylen);
4047c478bd9Sstevel@tonic-gate return (ssh1_keylen);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate /* Start constructing a packet to send. */
4087c478bd9Sstevel@tonic-gate void
packet_start(u_char type)4097c478bd9Sstevel@tonic-gate packet_start(u_char type)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate u_char buf[9];
4127c478bd9Sstevel@tonic-gate int len;
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate DBG(debug("packet_start[%d]", type));
4157c478bd9Sstevel@tonic-gate len = compat20 ? 6 : 9;
4167c478bd9Sstevel@tonic-gate memset(buf, 0, len - 1);
4177c478bd9Sstevel@tonic-gate buf[len - 1] = type;
4187c478bd9Sstevel@tonic-gate buffer_clear(&outgoing_packet);
4197c478bd9Sstevel@tonic-gate buffer_append(&outgoing_packet, buf, len);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate /* Append payload. */
4237c478bd9Sstevel@tonic-gate void
packet_put_char(int value)4247c478bd9Sstevel@tonic-gate packet_put_char(int value)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate char ch = value;
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate buffer_append(&outgoing_packet, &ch, 1);
4297c478bd9Sstevel@tonic-gate }
4309a8058b5Sjp161948
4317c478bd9Sstevel@tonic-gate void
packet_put_int(u_int value)4327c478bd9Sstevel@tonic-gate packet_put_int(u_int value)
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate buffer_put_int(&outgoing_packet, value);
4357c478bd9Sstevel@tonic-gate }
4369a8058b5Sjp161948
4377c478bd9Sstevel@tonic-gate void
packet_put_string(const void * buf,u_int len)4387c478bd9Sstevel@tonic-gate packet_put_string(const void *buf, u_int len)
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate buffer_put_string(&outgoing_packet, buf, len);
4417c478bd9Sstevel@tonic-gate }
4429a8058b5Sjp161948
4437c478bd9Sstevel@tonic-gate void
packet_put_cstring(const char * str)4447c478bd9Sstevel@tonic-gate packet_put_cstring(const char *str)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate buffer_put_cstring(&outgoing_packet, str);
4477c478bd9Sstevel@tonic-gate }
4489a8058b5Sjp161948
4497c478bd9Sstevel@tonic-gate void
packet_put_utf8_cstring(const char * str)4506f786aceSNobutomo Nakano packet_put_utf8_cstring(const char *str)
4517c478bd9Sstevel@tonic-gate {
4526f786aceSNobutomo Nakano if (datafellows & SSH_BUG_STRING_ENCODING)
4536f786aceSNobutomo Nakano buffer_put_cstring(&outgoing_packet, str);
4546f786aceSNobutomo Nakano else
4557c478bd9Sstevel@tonic-gate buffer_put_utf8_cstring(&outgoing_packet, str);
4567c478bd9Sstevel@tonic-gate }
4576f786aceSNobutomo Nakano
4587c478bd9Sstevel@tonic-gate void
packet_put_utf8_string(const char * str,uint_t len)4596f786aceSNobutomo Nakano packet_put_utf8_string(const char *str, uint_t len)
4607c478bd9Sstevel@tonic-gate {
4616f786aceSNobutomo Nakano if (datafellows & SSH_BUG_STRING_ENCODING)
4626f786aceSNobutomo Nakano buffer_put_string(&outgoing_packet, str, len);
4636f786aceSNobutomo Nakano else
4646f786aceSNobutomo Nakano buffer_put_utf8_string(&outgoing_packet, str, len);
4657c478bd9Sstevel@tonic-gate }
4666f786aceSNobutomo Nakano
4677c478bd9Sstevel@tonic-gate void
packet_put_raw(const void * buf,u_int len)4687c478bd9Sstevel@tonic-gate packet_put_raw(const void *buf, u_int len)
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate buffer_append(&outgoing_packet, buf, len);
4717c478bd9Sstevel@tonic-gate }
4729a8058b5Sjp161948
4737c478bd9Sstevel@tonic-gate void
packet_put_bignum(BIGNUM * value)4747c478bd9Sstevel@tonic-gate packet_put_bignum(BIGNUM * value)
4757c478bd9Sstevel@tonic-gate {
4767c478bd9Sstevel@tonic-gate buffer_put_bignum(&outgoing_packet, value);
4777c478bd9Sstevel@tonic-gate }
4789a8058b5Sjp161948
4797c478bd9Sstevel@tonic-gate void
packet_put_bignum2(BIGNUM * value)4807c478bd9Sstevel@tonic-gate packet_put_bignum2(BIGNUM * value)
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate buffer_put_bignum2(&outgoing_packet, value);
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate * Finalizes and sends the packet. If the encryption key has been set,
4877c478bd9Sstevel@tonic-gate * encrypts the packet before sending.
4887c478bd9Sstevel@tonic-gate */
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate static void
packet_send1(void)4917c478bd9Sstevel@tonic-gate packet_send1(void)
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate u_char buf[8], *cp;
4947c478bd9Sstevel@tonic-gate int i, padding, len;
4957c478bd9Sstevel@tonic-gate u_int checksum;
4969a8058b5Sjp161948 u_int32_t rnd = 0;
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate /*
4997c478bd9Sstevel@tonic-gate * If using packet compression, compress the payload of the outgoing
5007c478bd9Sstevel@tonic-gate * packet.
5017c478bd9Sstevel@tonic-gate */
5027c478bd9Sstevel@tonic-gate if (packet_compression) {
5037c478bd9Sstevel@tonic-gate buffer_clear(&compression_buffer);
5047c478bd9Sstevel@tonic-gate /* Skip padding. */
5057c478bd9Sstevel@tonic-gate buffer_consume(&outgoing_packet, 8);
5067c478bd9Sstevel@tonic-gate /* padding */
5077c478bd9Sstevel@tonic-gate buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8);
5087c478bd9Sstevel@tonic-gate buffer_compress(&outgoing_packet, &compression_buffer);
5097c478bd9Sstevel@tonic-gate buffer_clear(&outgoing_packet);
5107c478bd9Sstevel@tonic-gate buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
5117c478bd9Sstevel@tonic-gate buffer_len(&compression_buffer));
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate /* Compute packet length without padding (add checksum, remove padding). */
5147c478bd9Sstevel@tonic-gate len = buffer_len(&outgoing_packet) + 4 - 8;
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate /* Insert padding. Initialized to zero in packet_start1() */
5177c478bd9Sstevel@tonic-gate padding = 8 - len % 8;
5187c478bd9Sstevel@tonic-gate if (!send_context.plaintext) {
5197c478bd9Sstevel@tonic-gate cp = buffer_ptr(&outgoing_packet);
5207c478bd9Sstevel@tonic-gate for (i = 0; i < padding; i++) {
5217c478bd9Sstevel@tonic-gate if (i % 4 == 0)
5229a8058b5Sjp161948 rnd = arc4random();
5239a8058b5Sjp161948 cp[7 - i] = rnd & 0xff;
5249a8058b5Sjp161948 rnd >>= 8;
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate buffer_consume(&outgoing_packet, 8 - padding);
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate /* Add check bytes. */
5307c478bd9Sstevel@tonic-gate checksum = ssh_crc32(buffer_ptr(&outgoing_packet),
5317c478bd9Sstevel@tonic-gate buffer_len(&outgoing_packet));
5327c478bd9Sstevel@tonic-gate PUT_32BIT(buf, checksum);
5337c478bd9Sstevel@tonic-gate buffer_append(&outgoing_packet, buf, 4);
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate #ifdef PACKET_DEBUG
5367c478bd9Sstevel@tonic-gate fprintf(stderr, "packet_send plain: ");
5377c478bd9Sstevel@tonic-gate buffer_dump(&outgoing_packet);
5387c478bd9Sstevel@tonic-gate #endif
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate /* Append to output. */
5417c478bd9Sstevel@tonic-gate PUT_32BIT(buf, len);
5427c478bd9Sstevel@tonic-gate buffer_append(&output, buf, 4);
5437c478bd9Sstevel@tonic-gate cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
5447c478bd9Sstevel@tonic-gate cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
5457c478bd9Sstevel@tonic-gate buffer_len(&outgoing_packet));
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate #ifdef PACKET_DEBUG
548cd7d5fafSJan Pechanec debug("encrypted output queue now contains (%d bytes):\n",
549cd7d5fafSJan Pechanec buffer_len(&output));
5507c478bd9Sstevel@tonic-gate buffer_dump(&output);
5517c478bd9Sstevel@tonic-gate #endif
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate buffer_clear(&outgoing_packet);
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate /*
5567c478bd9Sstevel@tonic-gate * Note that the packet is now only buffered in output. It won\'t be
5577c478bd9Sstevel@tonic-gate * actually sent until packet_write_wait or packet_write_poll is
5587c478bd9Sstevel@tonic-gate * called.
5597c478bd9Sstevel@tonic-gate */
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate void
set_newkeys(int mode)5637c478bd9Sstevel@tonic-gate set_newkeys(int mode)
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate Enc *enc;
5667c478bd9Sstevel@tonic-gate Mac *mac;
5677c478bd9Sstevel@tonic-gate Comp *comp;
5687c478bd9Sstevel@tonic-gate CipherContext *cc;
5699a8058b5Sjp161948 u_int64_t *max_blocks;
5709a8058b5Sjp161948 int crypt_type;
5717c478bd9Sstevel@tonic-gate
5729a8058b5Sjp161948 debug2("set_newkeys: mode %d", mode);
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate if (mode == MODE_OUT) {
5757c478bd9Sstevel@tonic-gate cc = &send_context;
5769a8058b5Sjp161948 crypt_type = CIPHER_ENCRYPT;
5779a8058b5Sjp161948 p_send.packets = p_send.blocks = 0;
5789a8058b5Sjp161948 max_blocks = &max_blocks_out;
5797c478bd9Sstevel@tonic-gate } else {
5807c478bd9Sstevel@tonic-gate cc = &receive_context;
5819a8058b5Sjp161948 crypt_type = CIPHER_DECRYPT;
5829a8058b5Sjp161948 p_read.packets = p_read.blocks = 0;
5839a8058b5Sjp161948 max_blocks = &max_blocks_in;
5847c478bd9Sstevel@tonic-gate }
585cd7d5fafSJan Pechanec
586dbe3f931Sjp161948 debug("set_newkeys: setting new keys for '%s' mode",
587dbe3f931Sjp161948 mode == MODE_IN ? "in" : "out");
588cd7d5fafSJan Pechanec
589cd7d5fafSJan Pechanec if (newkeys[mode] != NULL) {
5907c478bd9Sstevel@tonic-gate cipher_cleanup(cc);
5919a8058b5Sjp161948 free_keys(newkeys[mode]);
5927c478bd9Sstevel@tonic-gate }
593cd7d5fafSJan Pechanec
5947c478bd9Sstevel@tonic-gate newkeys[mode] = kex_get_newkeys(mode);
5957c478bd9Sstevel@tonic-gate if (newkeys[mode] == NULL)
5967c478bd9Sstevel@tonic-gate fatal("newkeys: no keys for mode %d", mode);
5977c478bd9Sstevel@tonic-gate enc = &newkeys[mode]->enc;
5987c478bd9Sstevel@tonic-gate mac = &newkeys[mode]->mac;
5997c478bd9Sstevel@tonic-gate comp = &newkeys[mode]->comp;
6008caf082fSJan Pechanec if (mac_init(mac) == 0)
6017c478bd9Sstevel@tonic-gate mac->enabled = 1;
602cd7d5fafSJan Pechanec #ifdef PACKET_DEBUG
603cd7d5fafSJan Pechanec debug("new encryption key:\n");
604cd7d5fafSJan Pechanec data_dump(enc->key, enc->key_len);
605cd7d5fafSJan Pechanec debug("new encryption IV:\n");
606cd7d5fafSJan Pechanec data_dump(enc->iv, enc->block_size);
607cd7d5fafSJan Pechanec debug("new MAC key:\n");
608cd7d5fafSJan Pechanec data_dump(mac->key, mac->key_len);
609cd7d5fafSJan Pechanec #endif
6107c478bd9Sstevel@tonic-gate cipher_init(cc, enc->cipher, enc->key, enc->key_len,
6119a8058b5Sjp161948 enc->iv, enc->block_size, crypt_type);
6127c478bd9Sstevel@tonic-gate /* Deleting the keys does not gain extra security */
6137c478bd9Sstevel@tonic-gate /* memset(enc->iv, 0, enc->block_size);
6147c478bd9Sstevel@tonic-gate memset(enc->key, 0, enc->key_len); */
6157c478bd9Sstevel@tonic-gate if (comp->type != 0 && comp->enabled == 0) {
6167c478bd9Sstevel@tonic-gate packet_init_compression();
6177c478bd9Sstevel@tonic-gate if (mode == MODE_OUT)
6187c478bd9Sstevel@tonic-gate buffer_compress_init_send(6);
6197c478bd9Sstevel@tonic-gate else
6207c478bd9Sstevel@tonic-gate buffer_compress_init_recv();
6217c478bd9Sstevel@tonic-gate comp->enabled = 1;
6227c478bd9Sstevel@tonic-gate }
6239a8058b5Sjp161948
6249a8058b5Sjp161948 /*
6259a8058b5Sjp161948 * In accordance to the RFCs listed below we enforce the key
6269a8058b5Sjp161948 * re-exchange for:
6279a8058b5Sjp161948 *
6289a8058b5Sjp161948 * - every 1GB of transmitted data if the selected cipher block size
6299a8058b5Sjp161948 * is less than 16 bytes (3DES, Blowfish)
6309a8058b5Sjp161948 * - every 2^(2*B) cipher blocks transmitted (B is block size in bytes)
6319a8058b5Sjp161948 * if the cipher block size is greater than or equal to 16 bytes (AES)
6329a8058b5Sjp161948 * - and we never send more than 2^32 SSH packets using the same keys.
6339a8058b5Sjp161948 * The recommendation of 2^31 packets is not enforced here but in
6349a8058b5Sjp161948 * packet_need_rekeying(). There is also a hard check in
6359a8058b5Sjp161948 * packet_send2_wrapped() that we don't send more than 2^32 packets.
6369a8058b5Sjp161948 *
6379a8058b5Sjp161948 * Note that if the SSH_BUG_NOREKEY compatibility flag is set then no
6389a8058b5Sjp161948 * automatic rekeying is performed nor do we enforce the 3rd rule.
6399a8058b5Sjp161948 * This means that we can be always forced by the opposite side to never
6409a8058b5Sjp161948 * initiate automatic key re-exchange. This might change in the future.
6419a8058b5Sjp161948 *
6429a8058b5Sjp161948 * The RekeyLimit option keyword may only enforce more frequent key
6439a8058b5Sjp161948 * renegotiation, never less. For more information on key renegotiation,
6449a8058b5Sjp161948 * see:
6459a8058b5Sjp161948 *
6469a8058b5Sjp161948 * - RFC 4253 (SSH Transport Layer Protocol), section "9. Key
6479a8058b5Sjp161948 * Re-Exchange"
6489a8058b5Sjp161948 * - RFC 4344 (SSH Transport Layer Encryption Modes), sections "3.
6499a8058b5Sjp161948 * Rekeying" and "6.1 Rekeying Considerations"
6509a8058b5Sjp161948 */
6519a8058b5Sjp161948 if (enc->block_size >= 16)
6529a8058b5Sjp161948 *max_blocks = (u_int64_t)1 << (enc->block_size * 2);
6539a8058b5Sjp161948 else
6549a8058b5Sjp161948 *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
6559a8058b5Sjp161948
6569a8058b5Sjp161948 if (rekey_limit)
6579a8058b5Sjp161948 *max_blocks = MIN(*max_blocks, rekey_limit / enc->block_size);
6589a8058b5Sjp161948 }
6599a8058b5Sjp161948
6609a8058b5Sjp161948 void
free_keys(Newkeys * keys)6619a8058b5Sjp161948 free_keys(Newkeys *keys)
6629a8058b5Sjp161948 {
6639a8058b5Sjp161948 Enc *enc;
6649a8058b5Sjp161948 Mac *mac;
6659a8058b5Sjp161948 Comp *comp;
6669a8058b5Sjp161948
6679a8058b5Sjp161948 enc = &keys->enc;
6689a8058b5Sjp161948 mac = &keys->mac;
6699a8058b5Sjp161948 comp = &keys->comp;
6709a8058b5Sjp161948 xfree(enc->name);
6719a8058b5Sjp161948 xfree(enc->iv);
6729a8058b5Sjp161948 xfree(enc->key);
6738caf082fSJan Pechanec
6748caf082fSJan Pechanec memset(mac->key, 0, mac->key_len);
6759a8058b5Sjp161948 xfree(mac->key);
6768caf082fSJan Pechanec xfree(mac->name);
6778caf082fSJan Pechanec mac_clear(mac);
6788caf082fSJan Pechanec
6799a8058b5Sjp161948 xfree(comp->name);
6809a8058b5Sjp161948 xfree(keys);
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate /*
684cd7d5fafSJan Pechanec * Process SSH2_MSG_NEWKEYS message. If we are using the engine we must have
685cd7d5fafSJan Pechanec * both SSH2_MSG_NEWKEYS processed before we can finish the engine, fork, and
686cd7d5fafSJan Pechanec * reinitialize the crypto contexts. We can't fork before processing the 2nd
687cd7d5fafSJan Pechanec * message otherwise we couldn't encrypt/decrypt that message at all - note that
688cd7d5fafSJan Pechanec * parent's PKCS#11 sessions are useless after the fork and we must process
689cd7d5fafSJan Pechanec * both SSH2_MSG_NEWKEYS messages using the old keys.
690cd7d5fafSJan Pechanec */
691cd7d5fafSJan Pechanec void
process_newkeys(int mode)692cd7d5fafSJan Pechanec process_newkeys(int mode)
693cd7d5fafSJan Pechanec {
69423b4d00cSJan Pechanec /* this function is for the client only */
695cd7d5fafSJan Pechanec if (packet_is_server() != 0)
696cd7d5fafSJan Pechanec return;
697cd7d5fafSJan Pechanec
698cd7d5fafSJan Pechanec if (will_daemonize == FIRST_NEWKEYS_PROCESSED) {
699cd7d5fafSJan Pechanec debug3("both SSH2_MSG_NEWKEYS processed, will daemonize now");
700cd7d5fafSJan Pechanec cipher_cleanup(&send_context);
701cd7d5fafSJan Pechanec cipher_cleanup(&receive_context);
702cd7d5fafSJan Pechanec pkcs11_engine_finish(e);
703cd7d5fafSJan Pechanec if (daemon(1, 1) < 0) {
704cd7d5fafSJan Pechanec fatal("daemon() failed: %.200s",
705cd7d5fafSJan Pechanec strerror(errno));
706cd7d5fafSJan Pechanec }
707cd7d5fafSJan Pechanec e = pkcs11_engine_load(e != NULL ? 1 : 0);
708cd7d5fafSJan Pechanec
709cd7d5fafSJan Pechanec set_newkeys(MODE_OUT);
710cd7d5fafSJan Pechanec set_newkeys(MODE_IN);
711cd7d5fafSJan Pechanec will_daemonize = SECOND_NEWKEYS_PROCESSED;
712cd7d5fafSJan Pechanec packet_send2();
713cd7d5fafSJan Pechanec } else {
714cd7d5fafSJan Pechanec if (will_daemonize == DAEMONIZING_REQUESTED)
715cd7d5fafSJan Pechanec will_daemonize = FIRST_NEWKEYS_PROCESSED;
716cd7d5fafSJan Pechanec else
717cd7d5fafSJan Pechanec set_newkeys(mode);
718cd7d5fafSJan Pechanec }
719cd7d5fafSJan Pechanec }
720cd7d5fafSJan Pechanec
721cd7d5fafSJan Pechanec /*
7227c478bd9Sstevel@tonic-gate * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
7237c478bd9Sstevel@tonic-gate */
7247c478bd9Sstevel@tonic-gate static void
packet_send2_wrapped(void)7259a8058b5Sjp161948 packet_send2_wrapped(void)
7267c478bd9Sstevel@tonic-gate {
7277c478bd9Sstevel@tonic-gate u_char type, *cp, *macbuf = NULL;
7287c478bd9Sstevel@tonic-gate u_char padlen, pad;
7297c478bd9Sstevel@tonic-gate u_int packet_length = 0;
7307c478bd9Sstevel@tonic-gate u_int i, len;
7319a8058b5Sjp161948 u_int32_t rnd = 0;
7327c478bd9Sstevel@tonic-gate Enc *enc = NULL;
7337c478bd9Sstevel@tonic-gate Mac *mac = NULL;
7347c478bd9Sstevel@tonic-gate Comp *comp = NULL;
7357c478bd9Sstevel@tonic-gate int block_size;
7367c478bd9Sstevel@tonic-gate
7377c478bd9Sstevel@tonic-gate if (newkeys[MODE_OUT] != NULL) {
7387c478bd9Sstevel@tonic-gate enc = &newkeys[MODE_OUT]->enc;
7397c478bd9Sstevel@tonic-gate mac = &newkeys[MODE_OUT]->mac;
7407c478bd9Sstevel@tonic-gate comp = &newkeys[MODE_OUT]->comp;
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate block_size = enc ? enc->block_size : 8;
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate cp = buffer_ptr(&outgoing_packet);
7457c478bd9Sstevel@tonic-gate type = cp[5];
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate #ifdef PACKET_DEBUG
748cd7d5fafSJan Pechanec debug("plain output packet to be processed (%d bytes):\n",
749cd7d5fafSJan Pechanec buffer_len(&outgoing_packet));
7507c478bd9Sstevel@tonic-gate buffer_dump(&outgoing_packet);
7517c478bd9Sstevel@tonic-gate #endif
7527c478bd9Sstevel@tonic-gate
7537c478bd9Sstevel@tonic-gate if (comp && comp->enabled) {
7547c478bd9Sstevel@tonic-gate len = buffer_len(&outgoing_packet);
7557c478bd9Sstevel@tonic-gate /* skip header, compress only payload */
7567c478bd9Sstevel@tonic-gate buffer_consume(&outgoing_packet, 5);
7577c478bd9Sstevel@tonic-gate buffer_clear(&compression_buffer);
7587c478bd9Sstevel@tonic-gate buffer_compress(&outgoing_packet, &compression_buffer);
7597c478bd9Sstevel@tonic-gate buffer_clear(&outgoing_packet);
7607c478bd9Sstevel@tonic-gate buffer_append(&outgoing_packet, "\0\0\0\0\0", 5);
7617c478bd9Sstevel@tonic-gate buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
7627c478bd9Sstevel@tonic-gate buffer_len(&compression_buffer));
7637c478bd9Sstevel@tonic-gate DBG(debug("compression: raw %d compressed %d", len,
7647c478bd9Sstevel@tonic-gate buffer_len(&outgoing_packet)));
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate /* sizeof (packet_len + pad_len + payload) */
7687c478bd9Sstevel@tonic-gate len = buffer_len(&outgoing_packet);
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate /*
7717c478bd9Sstevel@tonic-gate * calc size of padding, alloc space, get random data,
7727c478bd9Sstevel@tonic-gate * minimum padding is 4 bytes
7737c478bd9Sstevel@tonic-gate */
7747c478bd9Sstevel@tonic-gate padlen = block_size - (len % block_size);
7757c478bd9Sstevel@tonic-gate if (padlen < 4)
7767c478bd9Sstevel@tonic-gate padlen += block_size;
7777c478bd9Sstevel@tonic-gate if (extra_pad) {
7787c478bd9Sstevel@tonic-gate /* will wrap if extra_pad+padlen > 255 */
7797c478bd9Sstevel@tonic-gate extra_pad = roundup(extra_pad, block_size);
7807c478bd9Sstevel@tonic-gate pad = extra_pad - ((len + padlen) % extra_pad);
7817c478bd9Sstevel@tonic-gate debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)",
7827c478bd9Sstevel@tonic-gate pad, len, padlen, extra_pad);
7837c478bd9Sstevel@tonic-gate padlen += pad;
7847c478bd9Sstevel@tonic-gate extra_pad = 0;
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate cp = buffer_append_space(&outgoing_packet, padlen);
7877c478bd9Sstevel@tonic-gate if (enc && !send_context.plaintext) {
7887c478bd9Sstevel@tonic-gate /* random padding */
7897c478bd9Sstevel@tonic-gate for (i = 0; i < padlen; i++) {
7907c478bd9Sstevel@tonic-gate if (i % 4 == 0)
7919a8058b5Sjp161948 rnd = arc4random();
7929a8058b5Sjp161948 cp[i] = rnd & 0xff;
7939a8058b5Sjp161948 rnd >>= 8;
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate } else {
7967c478bd9Sstevel@tonic-gate /* clear padding */
7977c478bd9Sstevel@tonic-gate memset(cp, 0, padlen);
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate /* packet_length includes payload, padding and padding length field */
8007c478bd9Sstevel@tonic-gate packet_length = buffer_len(&outgoing_packet) - 4;
8017c478bd9Sstevel@tonic-gate cp = buffer_ptr(&outgoing_packet);
8027c478bd9Sstevel@tonic-gate PUT_32BIT(cp, packet_length);
8037c478bd9Sstevel@tonic-gate cp[4] = padlen;
804cd7d5fafSJan Pechanec DBG(debug("will send %d bytes (includes padlen %d)",
805cd7d5fafSJan Pechanec packet_length + 4, padlen));
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate /* compute MAC over seqnr and packet(length fields, payload, padding) */
8087c478bd9Sstevel@tonic-gate if (mac && mac->enabled) {
8099a8058b5Sjp161948 macbuf = mac_compute(mac, p_send.seqnr,
8107c478bd9Sstevel@tonic-gate buffer_ptr(&outgoing_packet),
8117c478bd9Sstevel@tonic-gate buffer_len(&outgoing_packet));
8129a8058b5Sjp161948 DBG(debug("done calc MAC out #%d", p_send.seqnr));
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate /* encrypt packet and append to output buffer. */
8157c478bd9Sstevel@tonic-gate cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
8167c478bd9Sstevel@tonic-gate cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
8177c478bd9Sstevel@tonic-gate buffer_len(&outgoing_packet));
8187c478bd9Sstevel@tonic-gate /* append unencrypted MAC */
8197c478bd9Sstevel@tonic-gate if (mac && mac->enabled)
8207c478bd9Sstevel@tonic-gate buffer_append(&output, (char *)macbuf, mac->mac_len);
8217c478bd9Sstevel@tonic-gate #ifdef PACKET_DEBUG
822cd7d5fafSJan Pechanec debug("encrypted output queue now contains (%d bytes):\n",
823cd7d5fafSJan Pechanec buffer_len(&output));
8247c478bd9Sstevel@tonic-gate buffer_dump(&output);
8257c478bd9Sstevel@tonic-gate #endif
8267c478bd9Sstevel@tonic-gate /* increment sequence number for outgoing packets */
8279a8058b5Sjp161948 if (++p_send.seqnr == 0)
8287c478bd9Sstevel@tonic-gate log("outgoing seqnr wraps around");
8299a8058b5Sjp161948
8309a8058b5Sjp161948 /*
8319a8058b5Sjp161948 * RFC 4344: 3.1. First Rekeying Recommendation
8329a8058b5Sjp161948 *
8339a8058b5Sjp161948 * "Because of possible information leakage through the MAC tag after a
8349a8058b5Sjp161948 * key exchange, .... an SSH implementation SHOULD NOT send more than
8359a8058b5Sjp161948 * 2**32 packets before rekeying again."
8369a8058b5Sjp161948 *
8379a8058b5Sjp161948 * The code below is a hard check so that we are sure we don't go across
8389a8058b5Sjp161948 * the suggestion. However, since the largest cipher block size we have
8399a8058b5Sjp161948 * (AES) is 16 bytes we can't reach 2^32 SSH packets encrypted with the
8409a8058b5Sjp161948 * same key while performing periodic rekeying.
8419a8058b5Sjp161948 */
8429a8058b5Sjp161948 if (++p_send.packets == 0)
8439a8058b5Sjp161948 if (!(datafellows & SSH_BUG_NOREKEY))
8449a8058b5Sjp161948 fatal("too many packets encrypted with same key");
8459a8058b5Sjp161948 p_send.blocks += (packet_length + 4) / block_size;
8467c478bd9Sstevel@tonic-gate buffer_clear(&outgoing_packet);
8477c478bd9Sstevel@tonic-gate
848cd7d5fafSJan Pechanec if (type == SSH2_MSG_NEWKEYS) {
849cd7d5fafSJan Pechanec /*
850cd7d5fafSJan Pechanec * set_newkeys(MODE_OUT) in the client. Note that in the
851cd7d5fafSJan Pechanec * unprivileged child, set_newkeys() for MODE_OUT are set after
852cd7d5fafSJan Pechanec * SSH2_MSG_NEWKEYS is read from the monitor and forwarded to
853cd7d5fafSJan Pechanec * the client side.
854cd7d5fafSJan Pechanec */
855cd7d5fafSJan Pechanec process_newkeys(MODE_OUT);
856cd7d5fafSJan Pechanec }
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate
859cd7d5fafSJan Pechanec /*
860cd7d5fafSJan Pechanec * Packets we deal with here are plain until we encrypt them in
861cd7d5fafSJan Pechanec * packet_send2_wrapped().
862cd7d5fafSJan Pechanec *
863cd7d5fafSJan Pechanec * As already mentioned in a comment at process_newkeys() function we must not
864cd7d5fafSJan Pechanec * fork() until both SSH2_MSG_NEWKEYS packets were processed. Until this is done
865cd7d5fafSJan Pechanec * we must queue all packets so that they can be encrypted with the new keys and
866cd7d5fafSJan Pechanec * then sent to the other side. However, what can happen here is that we get
867cd7d5fafSJan Pechanec * SSH2_MSG_NEWKEYS after we sent it. In that situation we must call
868cd7d5fafSJan Pechanec * packet_send2() anyway to empty the queue, and set the rekey flag to the
869cd7d5fafSJan Pechanec * finished state. If we didn't do that we would just hang and enqueue data.
870cd7d5fafSJan Pechanec */
8719a8058b5Sjp161948 static void
packet_send2(void)8729a8058b5Sjp161948 packet_send2(void)
8739a8058b5Sjp161948 {
8749a8058b5Sjp161948 static int rekeying = 0;
8759a8058b5Sjp161948 struct packet *p;
8769a8058b5Sjp161948 u_char type, *cp;
8779a8058b5Sjp161948
878cd7d5fafSJan Pechanec if (will_daemonize != SECOND_NEWKEYS_PROCESSED) {
8799a8058b5Sjp161948 cp = buffer_ptr(&outgoing_packet);
8809a8058b5Sjp161948 type = cp[5];
8819a8058b5Sjp161948
8829a8058b5Sjp161948 /* during rekeying we can only send key exchange messages */
8839a8058b5Sjp161948 if (rekeying) {
8849a8058b5Sjp161948 if (!((type >= SSH2_MSG_TRANSPORT_MIN) &&
8859a8058b5Sjp161948 (type <= SSH2_MSG_TRANSPORT_MAX))) {
886cd7d5fafSJan Pechanec debug("enqueue a plain packet because rekex in "
887cd7d5fafSJan Pechanec "progress [type %u]", type);
8889a8058b5Sjp161948 p = xmalloc(sizeof(*p));
8899a8058b5Sjp161948 p->type = type;
8909a8058b5Sjp161948 memcpy(&p->payload, &outgoing_packet, sizeof(Buffer));
8919a8058b5Sjp161948 buffer_init(&outgoing_packet);
8929a8058b5Sjp161948 TAILQ_INSERT_TAIL(&outgoing, p, next);
8939a8058b5Sjp161948 return;
8949a8058b5Sjp161948 }
8959a8058b5Sjp161948 }
8969a8058b5Sjp161948
8979a8058b5Sjp161948 /* rekeying starts with sending KEXINIT */
8989a8058b5Sjp161948 if (type == SSH2_MSG_KEXINIT)
8999a8058b5Sjp161948 rekeying = 1;
9009a8058b5Sjp161948
9019a8058b5Sjp161948 packet_send2_wrapped();
902cd7d5fafSJan Pechanec }
9039a8058b5Sjp161948
904cd7d5fafSJan Pechanec /* after rekex is done we can process the queue of plain packets */
905cd7d5fafSJan Pechanec if (will_daemonize == SECOND_NEWKEYS_PROCESSED ||
906cd7d5fafSJan Pechanec (will_daemonize == NOT_DAEMONIZING && type == SSH2_MSG_NEWKEYS)) {
9079a8058b5Sjp161948 rekeying = 0;
908cd7d5fafSJan Pechanec will_daemonize = NOT_DAEMONIZING;
9099a8058b5Sjp161948 while ((p = TAILQ_FIRST(&outgoing)) != NULL) {
9109a8058b5Sjp161948 type = p->type;
911cd7d5fafSJan Pechanec debug("dequeuing a plain packet since rekex is over "
912cd7d5fafSJan Pechanec "[type %u]", type);
9139a8058b5Sjp161948 buffer_free(&outgoing_packet);
9149a8058b5Sjp161948 memcpy(&outgoing_packet, &p->payload, sizeof(Buffer));
9159a8058b5Sjp161948 TAILQ_REMOVE(&outgoing, p, next);
9169a8058b5Sjp161948 xfree(p);
9179a8058b5Sjp161948 packet_send2_wrapped();
9189a8058b5Sjp161948 }
9199a8058b5Sjp161948 }
9209a8058b5Sjp161948 }
9219a8058b5Sjp161948
9227c478bd9Sstevel@tonic-gate void
packet_send(void)9237c478bd9Sstevel@tonic-gate packet_send(void)
9247c478bd9Sstevel@tonic-gate {
9257c478bd9Sstevel@tonic-gate if (compat20)
9267c478bd9Sstevel@tonic-gate packet_send2();
9277c478bd9Sstevel@tonic-gate else
9287c478bd9Sstevel@tonic-gate packet_send1();
9297c478bd9Sstevel@tonic-gate DBG(debug("packet_send done"));
9307c478bd9Sstevel@tonic-gate }
9317c478bd9Sstevel@tonic-gate
9327c478bd9Sstevel@tonic-gate /*
9337c478bd9Sstevel@tonic-gate * Waits until a packet has been received, and returns its type. Note that
9347c478bd9Sstevel@tonic-gate * no other data is processed until this returns, so this function should not
9357c478bd9Sstevel@tonic-gate * be used during the interactive session.
936*3a7bd039SJan Pechanec *
937*3a7bd039SJan Pechanec * The function is also used in the monitor to read the authentication context
938*3a7bd039SJan Pechanec * in aps_read_auth_context() via packet_read_seqnr(), before the monitor enters
939*3a7bd039SJan Pechanec * aps_monitor_loop() and starts using the process_input() function.
9407c478bd9Sstevel@tonic-gate */
9417c478bd9Sstevel@tonic-gate int
packet_read_seqnr(u_int32_t * seqnr_p)9427c478bd9Sstevel@tonic-gate packet_read_seqnr(u_int32_t *seqnr_p)
9437c478bd9Sstevel@tonic-gate {
9447c478bd9Sstevel@tonic-gate int type, len;
9457c478bd9Sstevel@tonic-gate fd_set *setp;
9467c478bd9Sstevel@tonic-gate char buf[8192];
9477c478bd9Sstevel@tonic-gate DBG(debug("packet_read()"));
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) *
9507c478bd9Sstevel@tonic-gate sizeof(fd_mask));
9517c478bd9Sstevel@tonic-gate
9527c478bd9Sstevel@tonic-gate /* Since we are blocking, ensure that all written packets have been sent. */
9537c478bd9Sstevel@tonic-gate packet_write_wait();
9547c478bd9Sstevel@tonic-gate
9557c478bd9Sstevel@tonic-gate /* Stay in the loop until we have received a complete packet. */
9567c478bd9Sstevel@tonic-gate for (;;) {
9577c478bd9Sstevel@tonic-gate /* Try to read a packet from the buffer. */
9587c478bd9Sstevel@tonic-gate type = packet_read_poll_seqnr(seqnr_p);
9597c478bd9Sstevel@tonic-gate if (!compat20 && (
9607c478bd9Sstevel@tonic-gate type == SSH_SMSG_SUCCESS
9617c478bd9Sstevel@tonic-gate || type == SSH_SMSG_FAILURE
9627c478bd9Sstevel@tonic-gate || type == SSH_CMSG_EOF
9637c478bd9Sstevel@tonic-gate || type == SSH_CMSG_EXIT_CONFIRMATION))
9647c478bd9Sstevel@tonic-gate packet_check_eom();
9657c478bd9Sstevel@tonic-gate /* If we got a packet, return it. */
9667c478bd9Sstevel@tonic-gate if (type != SSH_MSG_NONE) {
9677c478bd9Sstevel@tonic-gate xfree(setp);
9687c478bd9Sstevel@tonic-gate return type;
9697c478bd9Sstevel@tonic-gate }
9707c478bd9Sstevel@tonic-gate /*
9717c478bd9Sstevel@tonic-gate * Otherwise, wait for some data to arrive, add it to the
9727c478bd9Sstevel@tonic-gate * buffer, and try again.
9737c478bd9Sstevel@tonic-gate */
9747c478bd9Sstevel@tonic-gate memset(setp, 0, howmany(connection_in + 1, NFDBITS) *
9757c478bd9Sstevel@tonic-gate sizeof(fd_mask));
9767c478bd9Sstevel@tonic-gate FD_SET(connection_in, setp);
9777c478bd9Sstevel@tonic-gate
9787c478bd9Sstevel@tonic-gate /* Wait for some data to arrive. */
9797c478bd9Sstevel@tonic-gate while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
9807c478bd9Sstevel@tonic-gate (errno == EAGAIN || errno == EINTR))
9817c478bd9Sstevel@tonic-gate ;
9827c478bd9Sstevel@tonic-gate
9837c478bd9Sstevel@tonic-gate /* Read data from the socket. */
9847c478bd9Sstevel@tonic-gate len = read(connection_in, buf, sizeof(buf));
9857c478bd9Sstevel@tonic-gate if (len == 0) {
986*3a7bd039SJan Pechanec if (packet_connection_is_on_socket())
987*3a7bd039SJan Pechanec log("Connection closed by %.200s",
988*3a7bd039SJan Pechanec get_remote_ipaddr());
989*3a7bd039SJan Pechanec else
990*3a7bd039SJan Pechanec debug("child closed the communication pipe "
991*3a7bd039SJan Pechanec "before user auth was finished");
9927c478bd9Sstevel@tonic-gate fatal_cleanup();
9937c478bd9Sstevel@tonic-gate }
994*3a7bd039SJan Pechanec if (len < 0) {
995*3a7bd039SJan Pechanec if (packet_connection_is_on_socket())
996*3a7bd039SJan Pechanec fatal("Read from socket failed: %.100s",
997*3a7bd039SJan Pechanec strerror(errno));
998*3a7bd039SJan Pechanec else
999*3a7bd039SJan Pechanec fatal("Read from communication pipe failed: "
1000*3a7bd039SJan Pechanec "%.100s", strerror(errno));
1001*3a7bd039SJan Pechanec }
10027c478bd9Sstevel@tonic-gate /* Append it to the buffer. */
10037c478bd9Sstevel@tonic-gate packet_process_incoming(buf, len);
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate /* NOTREACHED */
10067c478bd9Sstevel@tonic-gate }
10077c478bd9Sstevel@tonic-gate
10087c478bd9Sstevel@tonic-gate int
packet_read(void)10097c478bd9Sstevel@tonic-gate packet_read(void)
10107c478bd9Sstevel@tonic-gate {
10117c478bd9Sstevel@tonic-gate return packet_read_seqnr(NULL);
10127c478bd9Sstevel@tonic-gate }
10137c478bd9Sstevel@tonic-gate
10147c478bd9Sstevel@tonic-gate /*
10157c478bd9Sstevel@tonic-gate * Waits until a packet has been received, verifies that its type matches
10167c478bd9Sstevel@tonic-gate * that given, and gives a fatal error and exits if there is a mismatch.
10177c478bd9Sstevel@tonic-gate */
10187c478bd9Sstevel@tonic-gate
10197c478bd9Sstevel@tonic-gate void
packet_read_expect(int expected_type)10207c478bd9Sstevel@tonic-gate packet_read_expect(int expected_type)
10217c478bd9Sstevel@tonic-gate {
10227c478bd9Sstevel@tonic-gate int type;
10237c478bd9Sstevel@tonic-gate
10247c478bd9Sstevel@tonic-gate type = packet_read();
10257c478bd9Sstevel@tonic-gate if (type != expected_type)
10267c478bd9Sstevel@tonic-gate packet_disconnect("Protocol error: expected packet type %d, got %d",
10277c478bd9Sstevel@tonic-gate expected_type, type);
10287c478bd9Sstevel@tonic-gate }
10297c478bd9Sstevel@tonic-gate
10307c478bd9Sstevel@tonic-gate /* Checks if a full packet is available in the data received so far via
10317c478bd9Sstevel@tonic-gate * packet_process_incoming. If so, reads the packet; otherwise returns
10327c478bd9Sstevel@tonic-gate * SSH_MSG_NONE. This does not wait for data from the connection.
10337c478bd9Sstevel@tonic-gate *
10347c478bd9Sstevel@tonic-gate * SSH_MSG_DISCONNECT is handled specially here. Also,
10357c478bd9Sstevel@tonic-gate * SSH_MSG_IGNORE messages are skipped by this function and are never returned
10367c478bd9Sstevel@tonic-gate * to higher levels.
10377c478bd9Sstevel@tonic-gate */
10387c478bd9Sstevel@tonic-gate
10397c478bd9Sstevel@tonic-gate static int
packet_read_poll1(void)10407c478bd9Sstevel@tonic-gate packet_read_poll1(void)
10417c478bd9Sstevel@tonic-gate {
10427c478bd9Sstevel@tonic-gate u_int len, padded_len;
10437c478bd9Sstevel@tonic-gate u_char *cp, type;
10447c478bd9Sstevel@tonic-gate u_int checksum, stored_checksum;
10457c478bd9Sstevel@tonic-gate
10467c478bd9Sstevel@tonic-gate /* Check if input size is less than minimum packet size. */
10477c478bd9Sstevel@tonic-gate if (buffer_len(&input) < 4 + 8)
10487c478bd9Sstevel@tonic-gate return SSH_MSG_NONE;
10497c478bd9Sstevel@tonic-gate /* Get length of incoming packet. */
10507c478bd9Sstevel@tonic-gate cp = buffer_ptr(&input);
10517c478bd9Sstevel@tonic-gate len = GET_32BIT(cp);
10527c478bd9Sstevel@tonic-gate if (len < 1 + 2 + 2 || len > 256 * 1024)
10537c478bd9Sstevel@tonic-gate packet_disconnect("Bad packet length %d.", len);
10547c478bd9Sstevel@tonic-gate padded_len = (len + 8) & ~7;
10557c478bd9Sstevel@tonic-gate
10567c478bd9Sstevel@tonic-gate /* Check if the packet has been entirely received. */
10577c478bd9Sstevel@tonic-gate if (buffer_len(&input) < 4 + padded_len)
10587c478bd9Sstevel@tonic-gate return SSH_MSG_NONE;
10597c478bd9Sstevel@tonic-gate
10607c478bd9Sstevel@tonic-gate /* The entire packet is in buffer. */
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate /* Consume packet length. */
10637c478bd9Sstevel@tonic-gate buffer_consume(&input, 4);
10647c478bd9Sstevel@tonic-gate
10657c478bd9Sstevel@tonic-gate /*
10667c478bd9Sstevel@tonic-gate * Cryptographic attack detector for ssh
10677c478bd9Sstevel@tonic-gate * (C)1998 CORE-SDI, Buenos Aires Argentina
10687c478bd9Sstevel@tonic-gate * Ariel Futoransky(futo@core-sdi.com)
10697c478bd9Sstevel@tonic-gate */
107060779adbSjp161948 if (!receive_context.plaintext) {
107160779adbSjp161948 switch (detect_attack(buffer_ptr(&input), padded_len, NULL)) {
107260779adbSjp161948 case DEATTACK_DETECTED:
107360779adbSjp161948 packet_disconnect("crc32 compensation attack: "
107460779adbSjp161948 "network attack detected");
107560779adbSjp161948 break;
107660779adbSjp161948 case DEATTACK_DOS_DETECTED:
107760779adbSjp161948 packet_disconnect("deattack denial of "
107860779adbSjp161948 "service detected");
107960779adbSjp161948 break;
108060779adbSjp161948 }
108160779adbSjp161948 }
10827c478bd9Sstevel@tonic-gate
10837c478bd9Sstevel@tonic-gate /* Decrypt data to incoming_packet. */
10847c478bd9Sstevel@tonic-gate buffer_clear(&incoming_packet);
10857c478bd9Sstevel@tonic-gate cp = buffer_append_space(&incoming_packet, padded_len);
10867c478bd9Sstevel@tonic-gate cipher_crypt(&receive_context, cp, buffer_ptr(&input), padded_len);
10877c478bd9Sstevel@tonic-gate
10887c478bd9Sstevel@tonic-gate buffer_consume(&input, padded_len);
10897c478bd9Sstevel@tonic-gate
10907c478bd9Sstevel@tonic-gate #ifdef PACKET_DEBUG
1091cd7d5fafSJan Pechanec debug("read_poll plain/full:\n");
10927c478bd9Sstevel@tonic-gate buffer_dump(&incoming_packet);
10937c478bd9Sstevel@tonic-gate #endif
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate /* Compute packet checksum. */
10967c478bd9Sstevel@tonic-gate checksum = ssh_crc32(buffer_ptr(&incoming_packet),
10977c478bd9Sstevel@tonic-gate buffer_len(&incoming_packet) - 4);
10987c478bd9Sstevel@tonic-gate
10997c478bd9Sstevel@tonic-gate /* Skip padding. */
11007c478bd9Sstevel@tonic-gate buffer_consume(&incoming_packet, 8 - len % 8);
11017c478bd9Sstevel@tonic-gate
11027c478bd9Sstevel@tonic-gate /* Test check bytes. */
11037c478bd9Sstevel@tonic-gate if (len != buffer_len(&incoming_packet))
11047c478bd9Sstevel@tonic-gate packet_disconnect("packet_read_poll1: len %d != buffer_len %d.",
11057c478bd9Sstevel@tonic-gate len, buffer_len(&incoming_packet));
11067c478bd9Sstevel@tonic-gate
11077c478bd9Sstevel@tonic-gate cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4;
11087c478bd9Sstevel@tonic-gate stored_checksum = GET_32BIT(cp);
11097c478bd9Sstevel@tonic-gate if (checksum != stored_checksum)
11107c478bd9Sstevel@tonic-gate packet_disconnect("Corrupted check bytes on input.");
11117c478bd9Sstevel@tonic-gate buffer_consume_end(&incoming_packet, 4);
11127c478bd9Sstevel@tonic-gate
11137c478bd9Sstevel@tonic-gate if (packet_compression) {
11147c478bd9Sstevel@tonic-gate buffer_clear(&compression_buffer);
11157c478bd9Sstevel@tonic-gate buffer_uncompress(&incoming_packet, &compression_buffer);
11167c478bd9Sstevel@tonic-gate buffer_clear(&incoming_packet);
11177c478bd9Sstevel@tonic-gate buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
11187c478bd9Sstevel@tonic-gate buffer_len(&compression_buffer));
11197c478bd9Sstevel@tonic-gate }
11207c478bd9Sstevel@tonic-gate type = buffer_get_char(&incoming_packet);
11217c478bd9Sstevel@tonic-gate return type;
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate
11247c478bd9Sstevel@tonic-gate static int
packet_read_poll2(u_int32_t * seqnr_p)11257c478bd9Sstevel@tonic-gate packet_read_poll2(u_int32_t *seqnr_p)
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate static u_int packet_length = 0;
11287c478bd9Sstevel@tonic-gate u_int padlen, need;
11297c478bd9Sstevel@tonic-gate u_char *macbuf, *cp, type;
11307c478bd9Sstevel@tonic-gate int maclen, block_size;
11317c478bd9Sstevel@tonic-gate Enc *enc = NULL;
11327c478bd9Sstevel@tonic-gate Mac *mac = NULL;
11337c478bd9Sstevel@tonic-gate Comp *comp = NULL;
11347c478bd9Sstevel@tonic-gate
11357c478bd9Sstevel@tonic-gate if (newkeys[MODE_IN] != NULL) {
11367c478bd9Sstevel@tonic-gate enc = &newkeys[MODE_IN]->enc;
11377c478bd9Sstevel@tonic-gate mac = &newkeys[MODE_IN]->mac;
11387c478bd9Sstevel@tonic-gate comp = &newkeys[MODE_IN]->comp;
11397c478bd9Sstevel@tonic-gate }
11407c478bd9Sstevel@tonic-gate maclen = mac && mac->enabled ? mac->mac_len : 0;
11417c478bd9Sstevel@tonic-gate block_size = enc ? enc->block_size : 8;
11427c478bd9Sstevel@tonic-gate
11437c478bd9Sstevel@tonic-gate if (packet_length == 0) {
11447c478bd9Sstevel@tonic-gate /*
11457c478bd9Sstevel@tonic-gate * check if input size is less than the cipher block size,
11467c478bd9Sstevel@tonic-gate * decrypt first block and extract length of incoming packet
11477c478bd9Sstevel@tonic-gate */
11487c478bd9Sstevel@tonic-gate if (buffer_len(&input) < block_size)
11497c478bd9Sstevel@tonic-gate return SSH_MSG_NONE;
1150cd7d5fafSJan Pechanec #ifdef PACKET_DEBUG
1151cd7d5fafSJan Pechanec debug("encrypted data we have in read queue (%d bytes):\n",
1152cd7d5fafSJan Pechanec buffer_len(&input));
1153cd7d5fafSJan Pechanec buffer_dump(&input);
1154cd7d5fafSJan Pechanec #endif
11557c478bd9Sstevel@tonic-gate buffer_clear(&incoming_packet);
11567c478bd9Sstevel@tonic-gate cp = buffer_append_space(&incoming_packet, block_size);
11577c478bd9Sstevel@tonic-gate cipher_crypt(&receive_context, cp, buffer_ptr(&input),
11587c478bd9Sstevel@tonic-gate block_size);
11597c478bd9Sstevel@tonic-gate cp = buffer_ptr(&incoming_packet);
11607c478bd9Sstevel@tonic-gate packet_length = GET_32BIT(cp);
11617c478bd9Sstevel@tonic-gate if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
11620868d822SJan Pechanec packet_disconnect("Bad packet length.");
11637c478bd9Sstevel@tonic-gate }
11649a8058b5Sjp161948 DBG(debug("input: packet len %u", packet_length + 4));
11657c478bd9Sstevel@tonic-gate buffer_consume(&input, block_size);
11667c478bd9Sstevel@tonic-gate }
11677c478bd9Sstevel@tonic-gate /* we have a partial packet of block_size bytes */
11687c478bd9Sstevel@tonic-gate need = 4 + packet_length - block_size;
1169cd7d5fafSJan Pechanec DBG(debug("partial packet %d, still need %d, maclen %d", block_size,
11707c478bd9Sstevel@tonic-gate need, maclen));
11717c478bd9Sstevel@tonic-gate if (need % block_size != 0)
11720868d822SJan Pechanec packet_disconnect("Bad packet length.");
11737c478bd9Sstevel@tonic-gate /*
11747c478bd9Sstevel@tonic-gate * check if the entire packet has been received and
11757c478bd9Sstevel@tonic-gate * decrypt into incoming_packet
11767c478bd9Sstevel@tonic-gate */
11777c478bd9Sstevel@tonic-gate if (buffer_len(&input) < need + maclen)
11787c478bd9Sstevel@tonic-gate return SSH_MSG_NONE;
11797c478bd9Sstevel@tonic-gate #ifdef PACKET_DEBUG
1180cd7d5fafSJan Pechanec debug("in read_poll, the encrypted input queue now contains "
1181cd7d5fafSJan Pechanec "(%d bytes):\n", buffer_len(&input));
11827c478bd9Sstevel@tonic-gate buffer_dump(&input);
11837c478bd9Sstevel@tonic-gate #endif
11847c478bd9Sstevel@tonic-gate cp = buffer_append_space(&incoming_packet, need);
11857c478bd9Sstevel@tonic-gate cipher_crypt(&receive_context, cp, buffer_ptr(&input), need);
11867c478bd9Sstevel@tonic-gate buffer_consume(&input, need);
11877c478bd9Sstevel@tonic-gate /*
11887c478bd9Sstevel@tonic-gate * compute MAC over seqnr and packet,
11897c478bd9Sstevel@tonic-gate * increment sequence number for incoming packet
11907c478bd9Sstevel@tonic-gate */
11917c478bd9Sstevel@tonic-gate if (mac && mac->enabled) {
11929a8058b5Sjp161948 macbuf = mac_compute(mac, p_read.seqnr,
11937c478bd9Sstevel@tonic-gate buffer_ptr(&incoming_packet),
11947c478bd9Sstevel@tonic-gate buffer_len(&incoming_packet));
11957c478bd9Sstevel@tonic-gate if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
11967c478bd9Sstevel@tonic-gate packet_disconnect("Corrupted MAC on input.");
11979a8058b5Sjp161948 DBG(debug("MAC #%d ok", p_read.seqnr));
11987c478bd9Sstevel@tonic-gate buffer_consume(&input, mac->mac_len);
11997c478bd9Sstevel@tonic-gate }
12007c478bd9Sstevel@tonic-gate if (seqnr_p != NULL)
12019a8058b5Sjp161948 *seqnr_p = p_read.seqnr;
12029a8058b5Sjp161948 if (++p_read.seqnr == 0)
12037c478bd9Sstevel@tonic-gate log("incoming seqnr wraps around");
12047c478bd9Sstevel@tonic-gate
12059a8058b5Sjp161948 /* see above for the comment on "First Rekeying Recommendation" */
12069a8058b5Sjp161948 if (++p_read.packets == 0)
12079a8058b5Sjp161948 if (!(datafellows & SSH_BUG_NOREKEY))
12089a8058b5Sjp161948 fatal("too many packets with same key");
12099a8058b5Sjp161948 p_read.blocks += (packet_length + 4) / block_size;
12109a8058b5Sjp161948
12117c478bd9Sstevel@tonic-gate /* get padlen */
12127c478bd9Sstevel@tonic-gate cp = buffer_ptr(&incoming_packet);
12137c478bd9Sstevel@tonic-gate padlen = cp[4];
12147c478bd9Sstevel@tonic-gate DBG(debug("input: padlen %d", padlen));
12157c478bd9Sstevel@tonic-gate if (padlen < 4)
12167c478bd9Sstevel@tonic-gate packet_disconnect("Corrupted padlen %d on input.", padlen);
12177c478bd9Sstevel@tonic-gate
12187c478bd9Sstevel@tonic-gate /* skip packet size + padlen, discard padding */
12197c478bd9Sstevel@tonic-gate buffer_consume(&incoming_packet, 4 + 1);
12207c478bd9Sstevel@tonic-gate buffer_consume_end(&incoming_packet, padlen);
12217c478bd9Sstevel@tonic-gate
12227c478bd9Sstevel@tonic-gate DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet)));
12237c478bd9Sstevel@tonic-gate if (comp && comp->enabled) {
12247c478bd9Sstevel@tonic-gate buffer_clear(&compression_buffer);
12257c478bd9Sstevel@tonic-gate buffer_uncompress(&incoming_packet, &compression_buffer);
12267c478bd9Sstevel@tonic-gate buffer_clear(&incoming_packet);
12277c478bd9Sstevel@tonic-gate buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
12287c478bd9Sstevel@tonic-gate buffer_len(&compression_buffer));
12297c478bd9Sstevel@tonic-gate DBG(debug("input: len after de-compress %d",
12307c478bd9Sstevel@tonic-gate buffer_len(&incoming_packet)));
12317c478bd9Sstevel@tonic-gate }
12327c478bd9Sstevel@tonic-gate /*
12337c478bd9Sstevel@tonic-gate * get packet type, implies consume.
12347c478bd9Sstevel@tonic-gate * return length of payload (without type field)
12357c478bd9Sstevel@tonic-gate */
12367c478bd9Sstevel@tonic-gate type = buffer_get_char(&incoming_packet);
1237cd7d5fafSJan Pechanec if (type == SSH2_MSG_NEWKEYS) {
1238cd7d5fafSJan Pechanec /*
1239cd7d5fafSJan Pechanec * set_newkeys(MODE_IN) in the client because it doesn't have a
1240cd7d5fafSJan Pechanec * dispatch function for SSH2_MSG_NEWKEYS in contrast to the
1241cd7d5fafSJan Pechanec * server processes. Note that in the unprivileged child,
1242cd7d5fafSJan Pechanec * set_newkeys() for MODE_IN are set in dispatch function
1243cd7d5fafSJan Pechanec * altprivsep_rekey() after SSH2_MSG_NEWKEYS packet is received
1244cd7d5fafSJan Pechanec * from the client.
1245cd7d5fafSJan Pechanec */
1246cd7d5fafSJan Pechanec process_newkeys(MODE_IN);
1247cd7d5fafSJan Pechanec }
1248cd7d5fafSJan Pechanec
12497c478bd9Sstevel@tonic-gate #ifdef PACKET_DEBUG
1250cd7d5fafSJan Pechanec debug("decrypted input packet [type %d]:\n", type);
12517c478bd9Sstevel@tonic-gate buffer_dump(&incoming_packet);
12527c478bd9Sstevel@tonic-gate #endif
12537c478bd9Sstevel@tonic-gate /* reset for next packet */
12547c478bd9Sstevel@tonic-gate packet_length = 0;
12557c478bd9Sstevel@tonic-gate return type;
12567c478bd9Sstevel@tonic-gate }
12577c478bd9Sstevel@tonic-gate
1258cd7d5fafSJan Pechanec /*
1259cd7d5fafSJan Pechanec * This tries to read a packet from the buffer of received data. Note that it
1260cd7d5fafSJan Pechanec * doesn't read() anything from the network socket.
1261cd7d5fafSJan Pechanec */
12627c478bd9Sstevel@tonic-gate int
packet_read_poll_seqnr(u_int32_t * seqnr_p)12637c478bd9Sstevel@tonic-gate packet_read_poll_seqnr(u_int32_t *seqnr_p)
12647c478bd9Sstevel@tonic-gate {
12657c478bd9Sstevel@tonic-gate u_int reason, seqnr;
12667c478bd9Sstevel@tonic-gate u_char type;
12677c478bd9Sstevel@tonic-gate char *msg;
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate for (;;) {
12707c478bd9Sstevel@tonic-gate if (compat20) {
12717c478bd9Sstevel@tonic-gate type = packet_read_poll2(seqnr_p);
12727c478bd9Sstevel@tonic-gate DBG(debug("received packet type %d", type));
12737c478bd9Sstevel@tonic-gate switch (type) {
12747c478bd9Sstevel@tonic-gate case SSH2_MSG_IGNORE:
12757c478bd9Sstevel@tonic-gate break;
12767c478bd9Sstevel@tonic-gate case SSH2_MSG_DEBUG:
12777c478bd9Sstevel@tonic-gate packet_get_char();
12786f786aceSNobutomo Nakano msg = packet_get_utf8_string(NULL);
12796f786aceSNobutomo Nakano msg = g11n_filter_string(msg);
12807c478bd9Sstevel@tonic-gate debug("Remote: %.900s", msg);
12817c478bd9Sstevel@tonic-gate xfree(msg);
12827c478bd9Sstevel@tonic-gate msg = packet_get_string(NULL);
12837c478bd9Sstevel@tonic-gate xfree(msg);
12847c478bd9Sstevel@tonic-gate break;
12857c478bd9Sstevel@tonic-gate case SSH2_MSG_DISCONNECT:
12867c478bd9Sstevel@tonic-gate reason = packet_get_int();
12876f786aceSNobutomo Nakano msg = packet_get_utf8_string(NULL);
12886f786aceSNobutomo Nakano msg = g11n_filter_string(msg);
12897c478bd9Sstevel@tonic-gate log("Received disconnect from %s: %u: %.400s",
12907c478bd9Sstevel@tonic-gate get_remote_ipaddr(), reason, msg);
12917c478bd9Sstevel@tonic-gate xfree(msg);
12927c478bd9Sstevel@tonic-gate fatal_cleanup();
12937c478bd9Sstevel@tonic-gate break;
12947c478bd9Sstevel@tonic-gate case SSH2_MSG_UNIMPLEMENTED:
12957c478bd9Sstevel@tonic-gate seqnr = packet_get_int();
12967c478bd9Sstevel@tonic-gate debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
12977c478bd9Sstevel@tonic-gate seqnr);
12987c478bd9Sstevel@tonic-gate break;
12997c478bd9Sstevel@tonic-gate default:
13007c478bd9Sstevel@tonic-gate return type;
13017c478bd9Sstevel@tonic-gate break;
13027c478bd9Sstevel@tonic-gate }
13037c478bd9Sstevel@tonic-gate } else {
13047c478bd9Sstevel@tonic-gate type = packet_read_poll1();
13057c478bd9Sstevel@tonic-gate DBG(debug("received packet type %d", type));
13067c478bd9Sstevel@tonic-gate switch (type) {
13077c478bd9Sstevel@tonic-gate case SSH_MSG_IGNORE:
13087c478bd9Sstevel@tonic-gate break;
13097c478bd9Sstevel@tonic-gate case SSH_MSG_DEBUG:
13107c478bd9Sstevel@tonic-gate msg = packet_get_string(NULL);
13117c478bd9Sstevel@tonic-gate debug("Remote: %.900s", msg);
13127c478bd9Sstevel@tonic-gate xfree(msg);
13137c478bd9Sstevel@tonic-gate break;
13147c478bd9Sstevel@tonic-gate case SSH_MSG_DISCONNECT:
13157c478bd9Sstevel@tonic-gate msg = packet_get_string(NULL);
13167c478bd9Sstevel@tonic-gate log("Received disconnect from %s: %.400s",
13177c478bd9Sstevel@tonic-gate get_remote_ipaddr(), msg);
13187c478bd9Sstevel@tonic-gate fatal_cleanup();
13197c478bd9Sstevel@tonic-gate xfree(msg);
13207c478bd9Sstevel@tonic-gate break;
13217c478bd9Sstevel@tonic-gate default:
13227c478bd9Sstevel@tonic-gate return type;
13237c478bd9Sstevel@tonic-gate break;
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate }
13267c478bd9Sstevel@tonic-gate }
13277c478bd9Sstevel@tonic-gate }
13287c478bd9Sstevel@tonic-gate
13297c478bd9Sstevel@tonic-gate int
packet_read_poll(void)13307c478bd9Sstevel@tonic-gate packet_read_poll(void)
13317c478bd9Sstevel@tonic-gate {
13327c478bd9Sstevel@tonic-gate return packet_read_poll_seqnr(NULL);
13337c478bd9Sstevel@tonic-gate }
13347c478bd9Sstevel@tonic-gate
13357c478bd9Sstevel@tonic-gate /*
13367c478bd9Sstevel@tonic-gate * Buffers the given amount of input characters. This is intended to be used
13377c478bd9Sstevel@tonic-gate * together with packet_read_poll.
13387c478bd9Sstevel@tonic-gate */
13397c478bd9Sstevel@tonic-gate
13407c478bd9Sstevel@tonic-gate void
packet_process_incoming(const char * buf,u_int len)13417c478bd9Sstevel@tonic-gate packet_process_incoming(const char *buf, u_int len)
13427c478bd9Sstevel@tonic-gate {
13437c478bd9Sstevel@tonic-gate buffer_append(&input, buf, len);
13447c478bd9Sstevel@tonic-gate }
13457c478bd9Sstevel@tonic-gate
13467c478bd9Sstevel@tonic-gate /* Returns a character from the packet. */
13477c478bd9Sstevel@tonic-gate
13487c478bd9Sstevel@tonic-gate u_int
packet_get_char(void)13497c478bd9Sstevel@tonic-gate packet_get_char(void)
13507c478bd9Sstevel@tonic-gate {
13517c478bd9Sstevel@tonic-gate char ch;
13527c478bd9Sstevel@tonic-gate
13537c478bd9Sstevel@tonic-gate buffer_get(&incoming_packet, &ch, 1);
13547c478bd9Sstevel@tonic-gate return (u_char) ch;
13557c478bd9Sstevel@tonic-gate }
13567c478bd9Sstevel@tonic-gate
13577c478bd9Sstevel@tonic-gate /* Returns an integer from the packet data. */
13587c478bd9Sstevel@tonic-gate
13597c478bd9Sstevel@tonic-gate u_int
packet_get_int(void)13607c478bd9Sstevel@tonic-gate packet_get_int(void)
13617c478bd9Sstevel@tonic-gate {
13627c478bd9Sstevel@tonic-gate return buffer_get_int(&incoming_packet);
13637c478bd9Sstevel@tonic-gate }
13647c478bd9Sstevel@tonic-gate
13657c478bd9Sstevel@tonic-gate /*
13667c478bd9Sstevel@tonic-gate * Returns an arbitrary precision integer from the packet data. The integer
13677c478bd9Sstevel@tonic-gate * must have been initialized before this call.
13687c478bd9Sstevel@tonic-gate */
13697c478bd9Sstevel@tonic-gate
13707c478bd9Sstevel@tonic-gate void
packet_get_bignum(BIGNUM * value)13717c478bd9Sstevel@tonic-gate packet_get_bignum(BIGNUM * value)
13727c478bd9Sstevel@tonic-gate {
13737c478bd9Sstevel@tonic-gate buffer_get_bignum(&incoming_packet, value);
13747c478bd9Sstevel@tonic-gate }
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate void
packet_get_bignum2(BIGNUM * value)13777c478bd9Sstevel@tonic-gate packet_get_bignum2(BIGNUM * value)
13787c478bd9Sstevel@tonic-gate {
13797c478bd9Sstevel@tonic-gate buffer_get_bignum2(&incoming_packet, value);
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate
13827c478bd9Sstevel@tonic-gate void *
packet_get_raw(u_int * length_ptr)13837c478bd9Sstevel@tonic-gate packet_get_raw(u_int *length_ptr)
13847c478bd9Sstevel@tonic-gate {
13857c478bd9Sstevel@tonic-gate u_int bytes = buffer_len(&incoming_packet);
13867c478bd9Sstevel@tonic-gate
13877c478bd9Sstevel@tonic-gate if (length_ptr != NULL)
13887c478bd9Sstevel@tonic-gate *length_ptr = bytes;
13897c478bd9Sstevel@tonic-gate return buffer_ptr(&incoming_packet);
13907c478bd9Sstevel@tonic-gate }
13917c478bd9Sstevel@tonic-gate
13927c478bd9Sstevel@tonic-gate int
packet_remaining(void)13937c478bd9Sstevel@tonic-gate packet_remaining(void)
13947c478bd9Sstevel@tonic-gate {
13957c478bd9Sstevel@tonic-gate return buffer_len(&incoming_packet);
13967c478bd9Sstevel@tonic-gate }
13977c478bd9Sstevel@tonic-gate
13987c478bd9Sstevel@tonic-gate /*
13997c478bd9Sstevel@tonic-gate * Returns a string from the packet data. The string is allocated using
14007c478bd9Sstevel@tonic-gate * xmalloc; it is the responsibility of the calling program to free it when
14017c478bd9Sstevel@tonic-gate * no longer needed. The length_ptr argument may be NULL, or point to an
14027c478bd9Sstevel@tonic-gate * integer into which the length of the string is stored.
14037c478bd9Sstevel@tonic-gate */
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate void *
packet_get_string(u_int * length_ptr)14067c478bd9Sstevel@tonic-gate packet_get_string(u_int *length_ptr)
14077c478bd9Sstevel@tonic-gate {
14087c478bd9Sstevel@tonic-gate return buffer_get_string(&incoming_packet, length_ptr);
14097c478bd9Sstevel@tonic-gate }
14106f786aceSNobutomo Nakano
14117c478bd9Sstevel@tonic-gate char *
packet_get_utf8_string(uint_t * length_ptr)14126f786aceSNobutomo Nakano packet_get_utf8_string(uint_t *length_ptr)
14137c478bd9Sstevel@tonic-gate {
14146f786aceSNobutomo Nakano if (datafellows & SSH_BUG_STRING_ENCODING)
14156f786aceSNobutomo Nakano return (buffer_get_string(&incoming_packet, length_ptr));
14166f786aceSNobutomo Nakano else
14176f786aceSNobutomo Nakano return (buffer_get_utf8_string(&incoming_packet, length_ptr));
14187c478bd9Sstevel@tonic-gate }
14197c478bd9Sstevel@tonic-gate
14207c478bd9Sstevel@tonic-gate /*
14217c478bd9Sstevel@tonic-gate * Sends a diagnostic message from the server to the client. This message
14227c478bd9Sstevel@tonic-gate * can be sent at any time (but not while constructing another message). The
14237c478bd9Sstevel@tonic-gate * message is printed immediately, but only if the client is being executed
14247c478bd9Sstevel@tonic-gate * in verbose mode. These messages are primarily intended to ease debugging
14257c478bd9Sstevel@tonic-gate * authentication problems. The length of the formatted message must not
14267c478bd9Sstevel@tonic-gate * exceed 1024 bytes. This will automatically call packet_write_wait.
14277c478bd9Sstevel@tonic-gate */
14287c478bd9Sstevel@tonic-gate
14297c478bd9Sstevel@tonic-gate void
packet_send_debug(const char * fmt,...)14307c478bd9Sstevel@tonic-gate packet_send_debug(const char *fmt,...)
14317c478bd9Sstevel@tonic-gate {
14327c478bd9Sstevel@tonic-gate char buf[1024];
14337c478bd9Sstevel@tonic-gate va_list args;
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate if (compat20 && (datafellows & SSH_BUG_DEBUG))
14367c478bd9Sstevel@tonic-gate return;
14377c478bd9Sstevel@tonic-gate
14387c478bd9Sstevel@tonic-gate va_start(args, fmt);
14397c478bd9Sstevel@tonic-gate vsnprintf(buf, sizeof(buf), gettext(fmt), args);
14407c478bd9Sstevel@tonic-gate va_end(args);
14417c478bd9Sstevel@tonic-gate
14427c478bd9Sstevel@tonic-gate #ifdef ALTPRIVSEP
14437c478bd9Sstevel@tonic-gate /* shouldn't happen */
14447c478bd9Sstevel@tonic-gate if (packet_monitor) {
14457c478bd9Sstevel@tonic-gate debug("packet_send_debug: %s", buf);
14467c478bd9Sstevel@tonic-gate return;
14477c478bd9Sstevel@tonic-gate }
14487c478bd9Sstevel@tonic-gate #endif /* ALTPRIVSEP */
14497c478bd9Sstevel@tonic-gate
14507c478bd9Sstevel@tonic-gate if (compat20) {
14517c478bd9Sstevel@tonic-gate packet_start(SSH2_MSG_DEBUG);
14527c478bd9Sstevel@tonic-gate packet_put_char(0); /* bool: always display */
14536f786aceSNobutomo Nakano packet_put_utf8_cstring(buf);
14547c478bd9Sstevel@tonic-gate packet_put_cstring("");
14557c478bd9Sstevel@tonic-gate } else {
14567c478bd9Sstevel@tonic-gate packet_start(SSH_MSG_DEBUG);
14577c478bd9Sstevel@tonic-gate packet_put_cstring(buf);
14587c478bd9Sstevel@tonic-gate }
14597c478bd9Sstevel@tonic-gate packet_send();
14607c478bd9Sstevel@tonic-gate packet_write_wait();
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate
14637c478bd9Sstevel@tonic-gate /*
14647c478bd9Sstevel@tonic-gate * Logs the error plus constructs and sends a disconnect packet, closes the
14657c478bd9Sstevel@tonic-gate * connection, and exits. This function never returns. The error message
14667c478bd9Sstevel@tonic-gate * should not contain a newline. The length of the formatted message must
14677c478bd9Sstevel@tonic-gate * not exceed 1024 bytes.
14687c478bd9Sstevel@tonic-gate */
14697c478bd9Sstevel@tonic-gate
14707c478bd9Sstevel@tonic-gate void
packet_disconnect(const char * fmt,...)14717c478bd9Sstevel@tonic-gate packet_disconnect(const char *fmt,...)
14727c478bd9Sstevel@tonic-gate {
14737c478bd9Sstevel@tonic-gate char buf[1024];
14747c478bd9Sstevel@tonic-gate va_list args;
14757c478bd9Sstevel@tonic-gate static int disconnecting = 0;
14767c478bd9Sstevel@tonic-gate
14777c478bd9Sstevel@tonic-gate if (disconnecting) /* Guard against recursive invocations. */
14787c478bd9Sstevel@tonic-gate fatal("packet_disconnect called recursively.");
14797c478bd9Sstevel@tonic-gate disconnecting = 1;
14807c478bd9Sstevel@tonic-gate
14817c478bd9Sstevel@tonic-gate /*
14827c478bd9Sstevel@tonic-gate * Format the message. Note that the caller must make sure the
14837c478bd9Sstevel@tonic-gate * message is of limited size.
14847c478bd9Sstevel@tonic-gate */
14857c478bd9Sstevel@tonic-gate va_start(args, fmt);
14867c478bd9Sstevel@tonic-gate vsnprintf(buf, sizeof(buf), fmt, args);
14877c478bd9Sstevel@tonic-gate va_end(args);
14887c478bd9Sstevel@tonic-gate
14897c478bd9Sstevel@tonic-gate #ifdef ALTPRIVSEP
14907c478bd9Sstevel@tonic-gate /*
14917c478bd9Sstevel@tonic-gate * If we packet_disconnect() in the monitor the fatal cleanups will take
14927c478bd9Sstevel@tonic-gate * care of the child. See main() in sshd.c. We don't send the packet
14937c478bd9Sstevel@tonic-gate * disconnect message here because: a) the child might not be looking
14947c478bd9Sstevel@tonic-gate * for it and b) because we don't really know if the child is compat20
14957c478bd9Sstevel@tonic-gate * or not as we lost that information when packet_set_monitor() was
14967c478bd9Sstevel@tonic-gate * called.
14977c478bd9Sstevel@tonic-gate */
14987c478bd9Sstevel@tonic-gate if (packet_monitor)
14997c478bd9Sstevel@tonic-gate goto close_stuff;
15007c478bd9Sstevel@tonic-gate #endif /* ALTPRIVSEP */
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate /* Send the disconnect message to the other side, and wait for it to get sent. */
15037c478bd9Sstevel@tonic-gate if (compat20) {
15047c478bd9Sstevel@tonic-gate packet_start(SSH2_MSG_DISCONNECT);
15057c478bd9Sstevel@tonic-gate packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR);
15066f786aceSNobutomo Nakano packet_put_utf8_cstring(buf);
15077c478bd9Sstevel@tonic-gate packet_put_cstring("");
15087c478bd9Sstevel@tonic-gate } else {
15097c478bd9Sstevel@tonic-gate packet_start(SSH_MSG_DISCONNECT);
15107c478bd9Sstevel@tonic-gate packet_put_cstring(buf);
15117c478bd9Sstevel@tonic-gate }
15127c478bd9Sstevel@tonic-gate packet_send();
15137c478bd9Sstevel@tonic-gate packet_write_wait();
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate #ifdef ALTPRIVSEP
15167c478bd9Sstevel@tonic-gate close_stuff:
15177c478bd9Sstevel@tonic-gate #endif /* ALTPRIVSEP */
15187c478bd9Sstevel@tonic-gate /* Stop listening for connections. */
15197c478bd9Sstevel@tonic-gate channel_close_all();
15207c478bd9Sstevel@tonic-gate
15217c478bd9Sstevel@tonic-gate /* Close the connection. */
15227c478bd9Sstevel@tonic-gate packet_close();
15237c478bd9Sstevel@tonic-gate
15247c478bd9Sstevel@tonic-gate /* Display the error locally and exit. */
15257c478bd9Sstevel@tonic-gate log("Disconnecting: %.100s", buf);
15267c478bd9Sstevel@tonic-gate fatal_cleanup();
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate /* Checks if there is any buffered output, and tries to write some of the output. */
15307c478bd9Sstevel@tonic-gate
15317c478bd9Sstevel@tonic-gate void
packet_write_poll(void)15327c478bd9Sstevel@tonic-gate packet_write_poll(void)
15337c478bd9Sstevel@tonic-gate {
15347c478bd9Sstevel@tonic-gate int len = buffer_len(&output);
15357c478bd9Sstevel@tonic-gate
15367c478bd9Sstevel@tonic-gate if (len > 0) {
15377c478bd9Sstevel@tonic-gate len = write(connection_out, buffer_ptr(&output), len);
15387c478bd9Sstevel@tonic-gate if (len <= 0) {
15397c478bd9Sstevel@tonic-gate if (errno == EAGAIN)
15407c478bd9Sstevel@tonic-gate return;
15417c478bd9Sstevel@tonic-gate else
15427c478bd9Sstevel@tonic-gate fatal("Write failed: %.100s", strerror(errno));
15437c478bd9Sstevel@tonic-gate }
1544cd7d5fafSJan Pechanec #ifdef PACKET_DEBUG
1545cd7d5fafSJan Pechanec debug("in packet_write_poll, %d bytes just sent to the "
1546cd7d5fafSJan Pechanec "remote side", len);
1547cd7d5fafSJan Pechanec #endif
15487c478bd9Sstevel@tonic-gate buffer_consume(&output, len);
15497c478bd9Sstevel@tonic-gate }
15507c478bd9Sstevel@tonic-gate }
15517c478bd9Sstevel@tonic-gate
15527c478bd9Sstevel@tonic-gate /*
15537c478bd9Sstevel@tonic-gate * Calls packet_write_poll repeatedly until all pending output data has been
15547c478bd9Sstevel@tonic-gate * written.
15557c478bd9Sstevel@tonic-gate */
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate void
packet_write_wait(void)15587c478bd9Sstevel@tonic-gate packet_write_wait(void)
15597c478bd9Sstevel@tonic-gate {
15607c478bd9Sstevel@tonic-gate fd_set *setp;
15617c478bd9Sstevel@tonic-gate
15627c478bd9Sstevel@tonic-gate setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) *
15637c478bd9Sstevel@tonic-gate sizeof(fd_mask));
15647c478bd9Sstevel@tonic-gate packet_write_poll();
15657c478bd9Sstevel@tonic-gate while (packet_have_data_to_write()) {
15667c478bd9Sstevel@tonic-gate memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
15677c478bd9Sstevel@tonic-gate sizeof(fd_mask));
15687c478bd9Sstevel@tonic-gate FD_SET(connection_out, setp);
15697c478bd9Sstevel@tonic-gate while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
15707c478bd9Sstevel@tonic-gate (errno == EAGAIN || errno == EINTR))
15717c478bd9Sstevel@tonic-gate ;
15727c478bd9Sstevel@tonic-gate packet_write_poll();
15737c478bd9Sstevel@tonic-gate }
15747c478bd9Sstevel@tonic-gate xfree(setp);
15757c478bd9Sstevel@tonic-gate }
15767c478bd9Sstevel@tonic-gate
15777c478bd9Sstevel@tonic-gate /* Returns true if there is buffered data to write to the connection. */
15787c478bd9Sstevel@tonic-gate
15797c478bd9Sstevel@tonic-gate int
packet_have_data_to_write(void)15807c478bd9Sstevel@tonic-gate packet_have_data_to_write(void)
15817c478bd9Sstevel@tonic-gate {
15827c478bd9Sstevel@tonic-gate return buffer_len(&output) != 0;
15837c478bd9Sstevel@tonic-gate }
15847c478bd9Sstevel@tonic-gate
15857c478bd9Sstevel@tonic-gate /* Returns true if there is not too much data to write to the connection. */
15867c478bd9Sstevel@tonic-gate
15877c478bd9Sstevel@tonic-gate int
packet_not_very_much_data_to_write(void)15887c478bd9Sstevel@tonic-gate packet_not_very_much_data_to_write(void)
15897c478bd9Sstevel@tonic-gate {
15907c478bd9Sstevel@tonic-gate if (interactive_mode)
15917c478bd9Sstevel@tonic-gate return buffer_len(&output) < 16384;
15927c478bd9Sstevel@tonic-gate else
15937c478bd9Sstevel@tonic-gate return buffer_len(&output) < 128 * 1024;
15947c478bd9Sstevel@tonic-gate }
15957c478bd9Sstevel@tonic-gate
15967c478bd9Sstevel@tonic-gate /* Informs that the current session is interactive. Sets IP flags for that. */
15977c478bd9Sstevel@tonic-gate
15987c478bd9Sstevel@tonic-gate void
packet_set_interactive(int interactive)15997c478bd9Sstevel@tonic-gate packet_set_interactive(int interactive)
16007c478bd9Sstevel@tonic-gate {
16017c478bd9Sstevel@tonic-gate static int called = 0;
16027c478bd9Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
16037c478bd9Sstevel@tonic-gate int lowdelay = IPTOS_LOWDELAY;
16047c478bd9Sstevel@tonic-gate int throughput = IPTOS_THROUGHPUT;
16057c478bd9Sstevel@tonic-gate #endif
16067c478bd9Sstevel@tonic-gate
16077c478bd9Sstevel@tonic-gate if (called)
16087c478bd9Sstevel@tonic-gate return;
16097c478bd9Sstevel@tonic-gate called = 1;
16107c478bd9Sstevel@tonic-gate
16117c478bd9Sstevel@tonic-gate /* Record that we are in interactive mode. */
16127c478bd9Sstevel@tonic-gate interactive_mode = interactive;
16137c478bd9Sstevel@tonic-gate
16147c478bd9Sstevel@tonic-gate /* Only set socket options if using a socket. */
16157c478bd9Sstevel@tonic-gate if (!packet_connection_is_on_socket())
16167c478bd9Sstevel@tonic-gate return;
16177c478bd9Sstevel@tonic-gate /*
16187c478bd9Sstevel@tonic-gate * IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only
16197c478bd9Sstevel@tonic-gate */
16207c478bd9Sstevel@tonic-gate if (interactive) {
16217c478bd9Sstevel@tonic-gate /*
16227c478bd9Sstevel@tonic-gate * Set IP options for an interactive connection. Use
16237c478bd9Sstevel@tonic-gate * IPTOS_LOWDELAY and TCP_NODELAY.
16247c478bd9Sstevel@tonic-gate */
16257c478bd9Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
16267c478bd9Sstevel@tonic-gate if (packet_connection_is_ipv4()) {
16277c478bd9Sstevel@tonic-gate if (setsockopt(connection_in, IPPROTO_IP, IP_TOS,
16287c478bd9Sstevel@tonic-gate &lowdelay, sizeof(lowdelay)) < 0)
16297c478bd9Sstevel@tonic-gate error("setsockopt IPTOS_LOWDELAY: %.100s",
16307c478bd9Sstevel@tonic-gate strerror(errno));
16317c478bd9Sstevel@tonic-gate }
16327c478bd9Sstevel@tonic-gate #endif
16337c478bd9Sstevel@tonic-gate set_nodelay(connection_in);
16347c478bd9Sstevel@tonic-gate }
16357c478bd9Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
16367c478bd9Sstevel@tonic-gate else if (packet_connection_is_ipv4()) {
16377c478bd9Sstevel@tonic-gate /*
16387c478bd9Sstevel@tonic-gate * Set IP options for a non-interactive connection. Use
16397c478bd9Sstevel@tonic-gate * IPTOS_THROUGHPUT.
16407c478bd9Sstevel@tonic-gate */
16417c478bd9Sstevel@tonic-gate if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &throughput,
16427c478bd9Sstevel@tonic-gate sizeof(throughput)) < 0)
16437c478bd9Sstevel@tonic-gate error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
16447c478bd9Sstevel@tonic-gate }
16457c478bd9Sstevel@tonic-gate #endif
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate
16487c478bd9Sstevel@tonic-gate /* Returns true if the current connection is interactive. */
16497c478bd9Sstevel@tonic-gate
16507c478bd9Sstevel@tonic-gate int
packet_is_interactive(void)16517c478bd9Sstevel@tonic-gate packet_is_interactive(void)
16527c478bd9Sstevel@tonic-gate {
16537c478bd9Sstevel@tonic-gate return interactive_mode;
16547c478bd9Sstevel@tonic-gate }
16557c478bd9Sstevel@tonic-gate
16567c478bd9Sstevel@tonic-gate int
packet_set_maxsize(int s)16577c478bd9Sstevel@tonic-gate packet_set_maxsize(int s)
16587c478bd9Sstevel@tonic-gate {
16597c478bd9Sstevel@tonic-gate static int called = 0;
16607c478bd9Sstevel@tonic-gate
16617c478bd9Sstevel@tonic-gate if (called) {
16627c478bd9Sstevel@tonic-gate log("packet_set_maxsize: called twice: old %d new %d",
16637c478bd9Sstevel@tonic-gate max_packet_size, s);
16647c478bd9Sstevel@tonic-gate return -1;
16657c478bd9Sstevel@tonic-gate }
16667c478bd9Sstevel@tonic-gate if (s < 4 * 1024 || s > 1024 * 1024) {
16677c478bd9Sstevel@tonic-gate log("packet_set_maxsize: bad size %d", s);
16687c478bd9Sstevel@tonic-gate return -1;
16697c478bd9Sstevel@tonic-gate }
16707c478bd9Sstevel@tonic-gate called = 1;
16717c478bd9Sstevel@tonic-gate debug("packet_set_maxsize: setting to %d", s);
16727c478bd9Sstevel@tonic-gate max_packet_size = s;
16737c478bd9Sstevel@tonic-gate return s;
16747c478bd9Sstevel@tonic-gate }
16757c478bd9Sstevel@tonic-gate
16767c478bd9Sstevel@tonic-gate /* roundup current message to pad bytes */
16777c478bd9Sstevel@tonic-gate void
packet_add_padding(u_char pad)16787c478bd9Sstevel@tonic-gate packet_add_padding(u_char pad)
16797c478bd9Sstevel@tonic-gate {
16807c478bd9Sstevel@tonic-gate extra_pad = pad;
16817c478bd9Sstevel@tonic-gate }
16827c478bd9Sstevel@tonic-gate
16837c478bd9Sstevel@tonic-gate /*
16847c478bd9Sstevel@tonic-gate * 9.2. Ignored Data Message
16857c478bd9Sstevel@tonic-gate *
16867c478bd9Sstevel@tonic-gate * byte SSH_MSG_IGNORE
16877c478bd9Sstevel@tonic-gate * string data
16887c478bd9Sstevel@tonic-gate *
16897c478bd9Sstevel@tonic-gate * All implementations MUST understand (and ignore) this message at any
16907c478bd9Sstevel@tonic-gate * time (after receiving the protocol version). No implementation is
16917c478bd9Sstevel@tonic-gate * required to send them. This message can be used as an additional
16927c478bd9Sstevel@tonic-gate * protection measure against advanced traffic analysis techniques.
16937c478bd9Sstevel@tonic-gate */
16947c478bd9Sstevel@tonic-gate void
packet_send_ignore(int nbytes)16957c478bd9Sstevel@tonic-gate packet_send_ignore(int nbytes)
16967c478bd9Sstevel@tonic-gate {
16979a8058b5Sjp161948 u_int32_t rnd = 0;
16987c478bd9Sstevel@tonic-gate int i;
16997c478bd9Sstevel@tonic-gate
17007c478bd9Sstevel@tonic-gate #ifdef ALTPRIVSEP
17017c478bd9Sstevel@tonic-gate /* shouldn't happen -- see packet_set_monitor() */
17027c478bd9Sstevel@tonic-gate if (packet_monitor)
17037c478bd9Sstevel@tonic-gate return;
17047c478bd9Sstevel@tonic-gate #endif /* ALTPRIVSEP */
17057c478bd9Sstevel@tonic-gate
17067c478bd9Sstevel@tonic-gate packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE);
17077c478bd9Sstevel@tonic-gate packet_put_int(nbytes);
17087c478bd9Sstevel@tonic-gate for (i = 0; i < nbytes; i++) {
17097c478bd9Sstevel@tonic-gate if (i % 4 == 0)
17109a8058b5Sjp161948 rnd = arc4random();
17119a8058b5Sjp161948 packet_put_char((u_char)rnd & 0xff);
17129a8058b5Sjp161948 rnd >>= 8;
17137c478bd9Sstevel@tonic-gate }
17147c478bd9Sstevel@tonic-gate }
17157c478bd9Sstevel@tonic-gate
17169a8058b5Sjp161948 #define MAX_PACKETS (1U<<31)
17179a8058b5Sjp161948 int
packet_need_rekeying(void)17189a8058b5Sjp161948 packet_need_rekeying(void)
17199a8058b5Sjp161948 {
17209a8058b5Sjp161948 if (datafellows & SSH_BUG_NOREKEY)
17219a8058b5Sjp161948 return 0;
17229a8058b5Sjp161948 return
17239a8058b5Sjp161948 (p_send.packets > MAX_PACKETS) ||
17249a8058b5Sjp161948 (p_read.packets > MAX_PACKETS) ||
17259a8058b5Sjp161948 (max_blocks_out && (p_send.blocks > max_blocks_out)) ||
17269a8058b5Sjp161948 (max_blocks_in && (p_read.blocks > max_blocks_in));
17279a8058b5Sjp161948 }
17289a8058b5Sjp161948
17299a8058b5Sjp161948 void
packet_set_rekey_limit(u_int32_t bytes)17309a8058b5Sjp161948 packet_set_rekey_limit(u_int32_t bytes)
17319a8058b5Sjp161948 {
17329a8058b5Sjp161948 rekey_limit = bytes;
17339a8058b5Sjp161948 }
17349a8058b5Sjp161948
17357c478bd9Sstevel@tonic-gate #ifdef ALTPRIVSEP
17367c478bd9Sstevel@tonic-gate void
packet_set_server(void)17377c478bd9Sstevel@tonic-gate packet_set_server(void)
17387c478bd9Sstevel@tonic-gate {
17397c478bd9Sstevel@tonic-gate packet_server = 1;
17407c478bd9Sstevel@tonic-gate }
17417c478bd9Sstevel@tonic-gate
17427c478bd9Sstevel@tonic-gate int
packet_is_server(void)17437c478bd9Sstevel@tonic-gate packet_is_server(void)
17447c478bd9Sstevel@tonic-gate {
17457c478bd9Sstevel@tonic-gate return (packet_server);
17467c478bd9Sstevel@tonic-gate }
17477c478bd9Sstevel@tonic-gate
17487c478bd9Sstevel@tonic-gate void
packet_set_monitor(int pipe)17497c478bd9Sstevel@tonic-gate packet_set_monitor(int pipe)
17507c478bd9Sstevel@tonic-gate {
17517c478bd9Sstevel@tonic-gate int dup_fd;
17527c478bd9Sstevel@tonic-gate
17537c478bd9Sstevel@tonic-gate packet_server = 1;
17547c478bd9Sstevel@tonic-gate packet_monitor = 1;
17557c478bd9Sstevel@tonic-gate
17567c478bd9Sstevel@tonic-gate /*
17577c478bd9Sstevel@tonic-gate * Awful hack follows.
17587c478bd9Sstevel@tonic-gate *
17597c478bd9Sstevel@tonic-gate * For SSHv1 the monitor does not process any SSHv1 packets, only
17607c478bd9Sstevel@tonic-gate * ALTPRIVSEP packets. We take advantage of that here to keep changes
17617c478bd9Sstevel@tonic-gate * to packet.c to a minimum by using the SSHv2 binary packet protocol,
17627c478bd9Sstevel@tonic-gate * with cipher "none," mac "none" and compression alg "none," as the
17637c478bd9Sstevel@tonic-gate * basis for the monitor protocol. And so to force packet.c to treat
17647c478bd9Sstevel@tonic-gate * packets as SSHv2 we force compat20 == 1 here.
17657c478bd9Sstevel@tonic-gate *
17667c478bd9Sstevel@tonic-gate * For completeness and to help future developers catch this we also
17677c478bd9Sstevel@tonic-gate * force compat20 == 1 in the monitor loop, in serverloop.c.
17687c478bd9Sstevel@tonic-gate */
17697c478bd9Sstevel@tonic-gate compat20 = 1;
17707c478bd9Sstevel@tonic-gate
17717c478bd9Sstevel@tonic-gate /*
17727c478bd9Sstevel@tonic-gate * NOTE: Assumptions below!
17737c478bd9Sstevel@tonic-gate *
17747c478bd9Sstevel@tonic-gate * - lots of packet.c code assumes that (connection_in ==
17757c478bd9Sstevel@tonic-gate * connection_out) -> connection is socket
17767c478bd9Sstevel@tonic-gate *
17777c478bd9Sstevel@tonic-gate * - packet_close() does not shutdown() the connection fildes
17787c478bd9Sstevel@tonic-gate * if connection_in != connection_out
17797c478bd9Sstevel@tonic-gate *
17807c478bd9Sstevel@tonic-gate * - other code assumes the connection is a socket if
17817c478bd9Sstevel@tonic-gate * connection_in == connection_out
17827c478bd9Sstevel@tonic-gate */
17837c478bd9Sstevel@tonic-gate
17847c478bd9Sstevel@tonic-gate if ((dup_fd = dup(pipe)) < 0)
17857c478bd9Sstevel@tonic-gate fatal("Monitor failed to start: %s", strerror(errno));
17867c478bd9Sstevel@tonic-gate
17877c478bd9Sstevel@tonic-gate /*
17887c478bd9Sstevel@tonic-gate * make sure that the monitor's child's socket is not shutdown(3SOCKET)
1789cd7d5fafSJan Pechanec * when we packet_close(). Setting connection_out to -1 will take care
1790cd7d5fafSJan Pechanec * of that.
17917c478bd9Sstevel@tonic-gate */
17927c478bd9Sstevel@tonic-gate if (packet_connection_is_on_socket())
17937c478bd9Sstevel@tonic-gate connection_out = -1;
17947c478bd9Sstevel@tonic-gate
1795cd7d5fafSJan Pechanec /*
1796cd7d5fafSJan Pechanec * Now clean up the state related to the server socket. As a side
1797cd7d5fafSJan Pechanec * effect, we also clean up existing cipher contexts that were
1798cd7d5fafSJan Pechanec * initialized with 'none' cipher in packet_set_connection(). That
1799cd7d5fafSJan Pechanec * function was called in the child server process shortly after the
1800cd7d5fafSJan Pechanec * master SSH process forked. However, all of that is reinialized again
1801cd7d5fafSJan Pechanec * by another packet_set_connection() call right below.
1802cd7d5fafSJan Pechanec */
18037c478bd9Sstevel@tonic-gate packet_close();
18047c478bd9Sstevel@tonic-gate
1805cd7d5fafSJan Pechanec /*
1806cd7d5fafSJan Pechanec * Now make the monitor pipe look like the ssh connection which means
1807cd7d5fafSJan Pechanec * that connection_in and connection_out will be set to the
1808cd7d5fafSJan Pechanec * communication pipe descriptors.
1809cd7d5fafSJan Pechanec */
18107c478bd9Sstevel@tonic-gate packet_set_connection(pipe, dup_fd);
18117c478bd9Sstevel@tonic-gate }
18127c478bd9Sstevel@tonic-gate
1813cd7d5fafSJan Pechanec /*
1814cd7d5fafSJan Pechanec * We temporarily need to set connection_in and connection_out descriptors so
1815cd7d5fafSJan Pechanec * that we can make use of existing code that gets the IP address and hostname
1816cd7d5fafSJan Pechanec * of the peer to write a login/logout record. It's not nice but we would have
1817cd7d5fafSJan Pechanec * to change more code when implementing the PKCS#11 engine support.
1818cd7d5fafSJan Pechanec */
1819cd7d5fafSJan Pechanec void
packet_set_fds(int fd,int restore)1820cd7d5fafSJan Pechanec packet_set_fds(int fd, int restore)
1821cd7d5fafSJan Pechanec {
1822cd7d5fafSJan Pechanec static int stored_fd;
1823cd7d5fafSJan Pechanec
1824cd7d5fafSJan Pechanec if (stored_fd == 0 && restore == 0) {
1825cd7d5fafSJan Pechanec debug3("packet_set_fds: saving %d, installing %d",
1826cd7d5fafSJan Pechanec connection_in, fd);
1827cd7d5fafSJan Pechanec stored_fd = connection_in;
1828cd7d5fafSJan Pechanec /* we don't have a socket in inetd mode */
1829cd7d5fafSJan Pechanec if (fd != -1)
1830cd7d5fafSJan Pechanec connection_in = connection_out = fd;
1831cd7d5fafSJan Pechanec return;
1832cd7d5fafSJan Pechanec }
1833cd7d5fafSJan Pechanec
1834cd7d5fafSJan Pechanec if (restore == 1) {
1835cd7d5fafSJan Pechanec debug3("restoring %d to connection_in/out", stored_fd);
1836cd7d5fafSJan Pechanec connection_in = connection_out = stored_fd;
1837cd7d5fafSJan Pechanec }
1838cd7d5fafSJan Pechanec }
1839cd7d5fafSJan Pechanec
18407c478bd9Sstevel@tonic-gate int
packet_is_monitor(void)18417c478bd9Sstevel@tonic-gate packet_is_monitor(void)
18427c478bd9Sstevel@tonic-gate {
18437c478bd9Sstevel@tonic-gate return (packet_monitor);
18447c478bd9Sstevel@tonic-gate }
18457c478bd9Sstevel@tonic-gate #endif /* ALTPRIVSEP */
1846