10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * Author: Tatu Ylonen <ylo@cs.hut.fi>
30Sstevel@tonic-gate * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
40Sstevel@tonic-gate * All rights reserved
50Sstevel@tonic-gate * This file contains code implementing the packet protocol and communication
60Sstevel@tonic-gate * with the other side. This same code is used both on client and server side.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * As far as I am concerned, the code I have written for this software
90Sstevel@tonic-gate * can be used freely for any purpose. Any derived versions of this
100Sstevel@tonic-gate * software must be clearly marked as such, and if the derived work is
110Sstevel@tonic-gate * incompatible with the protocol description in the RFC file, it must be
120Sstevel@tonic-gate * called by a name other than "ssh" or "Secure Shell".
130Sstevel@tonic-gate *
140Sstevel@tonic-gate *
150Sstevel@tonic-gate * SSH2 packet format added by Markus Friedl.
160Sstevel@tonic-gate * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
170Sstevel@tonic-gate *
180Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
190Sstevel@tonic-gate * modification, are permitted provided that the following conditions
200Sstevel@tonic-gate * are met:
210Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
220Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
230Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
240Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
250Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
260Sstevel@tonic-gate *
270Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
280Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
290Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
300Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
310Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
320Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
330Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
340Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
350Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
360Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
370Sstevel@tonic-gate */
380Sstevel@tonic-gate /*
399486SJan.Pechanec@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
400Sstevel@tonic-gate * Use is subject to license terms.
410Sstevel@tonic-gate */
420Sstevel@tonic-gate
435562Sjp161948 /* $OpenBSD: packet.c,v 1.148 2007/06/07 19:37:34 pvalchev Exp $ */
440Sstevel@tonic-gate
455562Sjp161948 #include "includes.h"
465562Sjp161948
475562Sjp161948 #include "sys-queue.h"
480Sstevel@tonic-gate #include "xmalloc.h"
490Sstevel@tonic-gate #include "buffer.h"
500Sstevel@tonic-gate #include "packet.h"
510Sstevel@tonic-gate #include "bufaux.h"
520Sstevel@tonic-gate #include "crc32.h"
530Sstevel@tonic-gate #include "getput.h"
540Sstevel@tonic-gate #include "compress.h"
550Sstevel@tonic-gate #include "deattack.h"
560Sstevel@tonic-gate #include "channels.h"
570Sstevel@tonic-gate #include "compat.h"
580Sstevel@tonic-gate #include "ssh1.h"
590Sstevel@tonic-gate #include "ssh2.h"
600Sstevel@tonic-gate #include "cipher.h"
610Sstevel@tonic-gate #include "kex.h"
620Sstevel@tonic-gate #include "mac.h"
630Sstevel@tonic-gate #include "log.h"
640Sstevel@tonic-gate #include "canohost.h"
650Sstevel@tonic-gate #include "misc.h"
660Sstevel@tonic-gate #include "ssh.h"
677574SJan.Pechanec@Sun.COM #include "engine.h"
687574SJan.Pechanec@Sun.COM
697574SJan.Pechanec@Sun.COM /* PKCS#11 engine */
707574SJan.Pechanec@Sun.COM ENGINE *e;
710Sstevel@tonic-gate
720Sstevel@tonic-gate #ifdef ALTPRIVSEP
730Sstevel@tonic-gate static int packet_server = 0;
740Sstevel@tonic-gate static int packet_monitor = 0;
750Sstevel@tonic-gate #endif /* ALTPRIVSEP */
760Sstevel@tonic-gate
770Sstevel@tonic-gate #ifdef PACKET_DEBUG
780Sstevel@tonic-gate #define DBG(x) x
790Sstevel@tonic-gate #else
800Sstevel@tonic-gate #define DBG(x)
810Sstevel@tonic-gate #endif
820Sstevel@tonic-gate
837574SJan.Pechanec@Sun.COM static void packet_send2(void);
847574SJan.Pechanec@Sun.COM
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate * This variable contains the file descriptors used for communicating with
870Sstevel@tonic-gate * the other side. connection_in is used for reading; connection_out for
880Sstevel@tonic-gate * writing. These can be the same descriptor, in which case it is assumed to
890Sstevel@tonic-gate * be a socket.
900Sstevel@tonic-gate */
910Sstevel@tonic-gate static int connection_in = -1;
920Sstevel@tonic-gate static int connection_out = -1;
930Sstevel@tonic-gate
940Sstevel@tonic-gate /* Protocol flags for the remote side. */
950Sstevel@tonic-gate static u_int remote_protocol_flags = 0;
960Sstevel@tonic-gate
970Sstevel@tonic-gate /* Encryption context for receiving data. This is only used for decryption. */
980Sstevel@tonic-gate static CipherContext receive_context;
990Sstevel@tonic-gate
1000Sstevel@tonic-gate /* Encryption context for sending data. This is only used for encryption. */
1010Sstevel@tonic-gate static CipherContext send_context;
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate /* Buffer for raw input data from the socket. */
1040Sstevel@tonic-gate Buffer input;
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate /* Buffer for raw output data going to the socket. */
1070Sstevel@tonic-gate Buffer output;
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate /* Buffer for the partial outgoing packet being constructed. */
1100Sstevel@tonic-gate static Buffer outgoing_packet;
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate /* Buffer for the incoming packet currently being processed. */
1130Sstevel@tonic-gate static Buffer incoming_packet;
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate /* Scratch buffer for packet compression/decompression. */
1160Sstevel@tonic-gate static Buffer compression_buffer;
1170Sstevel@tonic-gate static int compression_buffer_ready = 0;
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate /* Flag indicating whether packet compression/decompression is enabled. */
1200Sstevel@tonic-gate static int packet_compression = 0;
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate /* default maximum packet size */
1230Sstevel@tonic-gate int max_packet_size = 32768;
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate /* Flag indicating whether this module has been initialized. */
1260Sstevel@tonic-gate static int initialized = 0;
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate /* Set to true if the connection is interactive. */
1290Sstevel@tonic-gate static int interactive_mode = 0;
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate /* Session key information for Encryption and MAC */
1320Sstevel@tonic-gate Newkeys *newkeys[MODE_MAX];
1335562Sjp161948 static struct packet_state {
1345562Sjp161948 u_int32_t seqnr;
1355562Sjp161948 u_int32_t packets;
1365562Sjp161948 u_int64_t blocks;
1375562Sjp161948 } p_read, p_send;
1385562Sjp161948
1395562Sjp161948 static u_int64_t max_blocks_in, max_blocks_out;
1405562Sjp161948 static u_int32_t rekey_limit;
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate /* Session key for protocol v1 */
1430Sstevel@tonic-gate static u_char ssh1_key[SSH_SESSION_KEY_LENGTH];
1440Sstevel@tonic-gate static u_int ssh1_keylen;
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate /* roundup current message to extra_pad bytes */
1470Sstevel@tonic-gate static u_char extra_pad = 0;
1480Sstevel@tonic-gate
1495562Sjp161948 struct packet {
1505562Sjp161948 TAILQ_ENTRY(packet) next;
1515562Sjp161948 u_char type;
1525562Sjp161948 Buffer payload;
1535562Sjp161948 };
1545562Sjp161948 TAILQ_HEAD(, packet) outgoing;
1555562Sjp161948
1560Sstevel@tonic-gate /*
1577574SJan.Pechanec@Sun.COM * Part of what -f option and ~& escape sequence do in the client is that they
1587574SJan.Pechanec@Sun.COM * will force it to daemonize itself. Due to the fork safety rules inherent in
1597574SJan.Pechanec@Sun.COM * any PKCS#11 environment, if the engine is used we must do a key re-exchange
1607574SJan.Pechanec@Sun.COM * before forking a child to negotiate the new keys. Those keys will be used to
1617574SJan.Pechanec@Sun.COM * inicialize the new crypto contexts. This involves finishing the engine in the
1627574SJan.Pechanec@Sun.COM * parent and reinitializing it again in both processes after fork() returns.
1637574SJan.Pechanec@Sun.COM * This approach also leaves protocol 1 out since it doesn't support rekeying.
1647574SJan.Pechanec@Sun.COM */
1657574SJan.Pechanec@Sun.COM int will_daemonize;
1667574SJan.Pechanec@Sun.COM
1677574SJan.Pechanec@Sun.COM #ifdef PACKET_DEBUG
1687574SJan.Pechanec@Sun.COM /* This function dumps data onto stderr. This is for debugging only. */
1697574SJan.Pechanec@Sun.COM void
data_dump(void * data,u_int len)1707574SJan.Pechanec@Sun.COM data_dump(void *data, u_int len)
1717574SJan.Pechanec@Sun.COM {
1727574SJan.Pechanec@Sun.COM Buffer buf;
1737574SJan.Pechanec@Sun.COM
1747574SJan.Pechanec@Sun.COM buffer_init(&buf);
1757574SJan.Pechanec@Sun.COM buffer_append(&buf, data, len);
1767574SJan.Pechanec@Sun.COM buffer_dump(&buf);
1777574SJan.Pechanec@Sun.COM buffer_free(&buf);
1787574SJan.Pechanec@Sun.COM }
1797574SJan.Pechanec@Sun.COM #endif
1807574SJan.Pechanec@Sun.COM
1817574SJan.Pechanec@Sun.COM /*
1820Sstevel@tonic-gate * Sets the descriptors used for communication. Disables encryption until
1830Sstevel@tonic-gate * packet_set_encryption_key is called.
1840Sstevel@tonic-gate */
1850Sstevel@tonic-gate void
packet_set_connection(int fd_in,int fd_out)1860Sstevel@tonic-gate packet_set_connection(int fd_in, int fd_out)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate Cipher *none = cipher_by_name("none");
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate if (none == NULL)
1910Sstevel@tonic-gate fatal("packet_set_connection: cannot load cipher 'none'");
1920Sstevel@tonic-gate connection_in = fd_in;
1930Sstevel@tonic-gate connection_out = fd_out;
1940Sstevel@tonic-gate cipher_init(&send_context, none, (unsigned char *) "", 0, NULL, 0, CIPHER_ENCRYPT);
1950Sstevel@tonic-gate cipher_init(&receive_context, none, (unsigned char *) "", 0, NULL, 0, CIPHER_DECRYPT);
1960Sstevel@tonic-gate newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
1970Sstevel@tonic-gate if (!initialized) {
1980Sstevel@tonic-gate initialized = 1;
1990Sstevel@tonic-gate buffer_init(&input);
2000Sstevel@tonic-gate buffer_init(&output);
2010Sstevel@tonic-gate buffer_init(&outgoing_packet);
2020Sstevel@tonic-gate buffer_init(&incoming_packet);
2035562Sjp161948 TAILQ_INIT(&outgoing);
2040Sstevel@tonic-gate } else {
2050Sstevel@tonic-gate buffer_clear(&input);
2060Sstevel@tonic-gate buffer_clear(&output);
2070Sstevel@tonic-gate buffer_clear(&outgoing_packet);
2080Sstevel@tonic-gate buffer_clear(&incoming_packet);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate /*
2120Sstevel@tonic-gate * Prime the cache for get_remote_ipaddr() while we have a
2130Sstevel@tonic-gate * socket on which to do a getpeername().
2140Sstevel@tonic-gate */
2150Sstevel@tonic-gate (void) get_remote_ipaddr();
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate /* Kludge: arrange the close function to be called from fatal(). */
2180Sstevel@tonic-gate fatal_add_cleanup((void (*) (void *)) packet_close, NULL);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate /* Returns 1 if remote host is connected via socket, 0 if not. */
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate int
packet_connection_is_on_socket(void)2240Sstevel@tonic-gate packet_connection_is_on_socket(void)
2250Sstevel@tonic-gate {
2260Sstevel@tonic-gate struct sockaddr_storage from, to;
2270Sstevel@tonic-gate socklen_t fromlen, tolen;
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate /* filedescriptors in and out are the same, so it's a socket */
2300Sstevel@tonic-gate if (connection_in != -1 && connection_in == connection_out)
2310Sstevel@tonic-gate return 1;
2320Sstevel@tonic-gate fromlen = sizeof(from);
2330Sstevel@tonic-gate memset(&from, 0, sizeof(from));
2340Sstevel@tonic-gate if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0)
2350Sstevel@tonic-gate return 0;
2360Sstevel@tonic-gate tolen = sizeof(to);
2370Sstevel@tonic-gate memset(&to, 0, sizeof(to));
2380Sstevel@tonic-gate if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0)
2390Sstevel@tonic-gate return 0;
2400Sstevel@tonic-gate if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0)
2410Sstevel@tonic-gate return 0;
2420Sstevel@tonic-gate if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
2430Sstevel@tonic-gate return 0;
2440Sstevel@tonic-gate return 1;
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate /* returns 1 if connection is via ipv4 */
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate int
packet_connection_is_ipv4(void)2500Sstevel@tonic-gate packet_connection_is_ipv4(void)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate struct sockaddr_storage to;
2530Sstevel@tonic-gate socklen_t tolen = sizeof(to);
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate memset(&to, 0, sizeof(to));
2560Sstevel@tonic-gate if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0)
2570Sstevel@tonic-gate return 0;
2580Sstevel@tonic-gate if (to.ss_family == AF_INET)
2590Sstevel@tonic-gate return 1;
2600Sstevel@tonic-gate #ifdef IPV4_IN_IPV6
2610Sstevel@tonic-gate if (to.ss_family == AF_INET6 &&
2620Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr))
2630Sstevel@tonic-gate return 1;
2640Sstevel@tonic-gate #endif
2650Sstevel@tonic-gate return 0;
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate /* Sets the connection into non-blocking mode. */
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate void
packet_set_nonblocking(void)2710Sstevel@tonic-gate packet_set_nonblocking(void)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate /* Set the socket into non-blocking mode. */
2740Sstevel@tonic-gate if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0)
2750Sstevel@tonic-gate error("fcntl O_NONBLOCK: %.100s", strerror(errno));
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate if (connection_out != connection_in) {
2780Sstevel@tonic-gate if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0)
2790Sstevel@tonic-gate error("fcntl O_NONBLOCK: %.100s", strerror(errno));
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate /* Returns the socket used for reading. */
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate int
packet_get_connection_in(void)2860Sstevel@tonic-gate packet_get_connection_in(void)
2870Sstevel@tonic-gate {
2880Sstevel@tonic-gate return connection_in;
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate /* Returns the descriptor used for writing. */
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate int
packet_get_connection_out(void)2940Sstevel@tonic-gate packet_get_connection_out(void)
2950Sstevel@tonic-gate {
2960Sstevel@tonic-gate return connection_out;
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate /* Closes the connection and clears and frees internal data structures. */
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate void
packet_close(void)3020Sstevel@tonic-gate packet_close(void)
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate if (!initialized)
3050Sstevel@tonic-gate return;
3060Sstevel@tonic-gate initialized = 0;
3070Sstevel@tonic-gate if (connection_in == connection_out) {
3080Sstevel@tonic-gate shutdown(connection_out, SHUT_RDWR);
3090Sstevel@tonic-gate close(connection_out);
3100Sstevel@tonic-gate } else {
3110Sstevel@tonic-gate close(connection_in);
3120Sstevel@tonic-gate close(connection_out);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate buffer_free(&input);
3150Sstevel@tonic-gate buffer_free(&output);
3160Sstevel@tonic-gate buffer_free(&outgoing_packet);
3170Sstevel@tonic-gate buffer_free(&incoming_packet);
3180Sstevel@tonic-gate if (compression_buffer_ready) {
3190Sstevel@tonic-gate buffer_free(&compression_buffer);
3200Sstevel@tonic-gate buffer_compress_uninit();
3210Sstevel@tonic-gate compression_buffer_ready = 0;
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate cipher_cleanup(&send_context);
3240Sstevel@tonic-gate cipher_cleanup(&receive_context);
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate /* Sets remote side protocol flags. */
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate void
packet_set_protocol_flags(u_int protocol_flags)3300Sstevel@tonic-gate packet_set_protocol_flags(u_int protocol_flags)
3310Sstevel@tonic-gate {
3320Sstevel@tonic-gate remote_protocol_flags = protocol_flags;
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate /* Returns the remote protocol flags set earlier by the above function. */
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate u_int
packet_get_protocol_flags(void)3380Sstevel@tonic-gate packet_get_protocol_flags(void)
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate return remote_protocol_flags;
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate /*
3440Sstevel@tonic-gate * Starts packet compression from the next packet on in both directions.
3450Sstevel@tonic-gate * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
3460Sstevel@tonic-gate */
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate static void
packet_init_compression(void)3490Sstevel@tonic-gate packet_init_compression(void)
3500Sstevel@tonic-gate {
3510Sstevel@tonic-gate if (compression_buffer_ready == 1)
3520Sstevel@tonic-gate return;
3530Sstevel@tonic-gate compression_buffer_ready = 1;
3540Sstevel@tonic-gate buffer_init(&compression_buffer);
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate void
packet_start_compression(int level)3580Sstevel@tonic-gate packet_start_compression(int level)
3590Sstevel@tonic-gate {
3600Sstevel@tonic-gate #ifdef ALTPRIVSEP
3610Sstevel@tonic-gate /* shouldn't happen! */
3620Sstevel@tonic-gate if (packet_monitor)
3630Sstevel@tonic-gate fatal("INTERNAL ERROR: The monitor cannot compress.");
3640Sstevel@tonic-gate #endif /* ALTPRIVSEP */
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate if (packet_compression && !compat20)
3670Sstevel@tonic-gate fatal("Compression already enabled.");
3680Sstevel@tonic-gate packet_compression = 1;
3690Sstevel@tonic-gate packet_init_compression();
3700Sstevel@tonic-gate buffer_compress_init_send(level);
3710Sstevel@tonic-gate buffer_compress_init_recv();
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate /*
3750Sstevel@tonic-gate * Causes any further packets to be encrypted using the given key. The same
3760Sstevel@tonic-gate * key is used for both sending and reception. However, both directions are
3770Sstevel@tonic-gate * encrypted independently of each other.
3780Sstevel@tonic-gate */
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate void
packet_set_encryption_key(const u_char * key,u_int keylen,int number)3810Sstevel@tonic-gate packet_set_encryption_key(const u_char *key, u_int keylen,
3820Sstevel@tonic-gate int number)
3830Sstevel@tonic-gate {
3840Sstevel@tonic-gate Cipher *cipher = cipher_by_number(number);
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate if (cipher == NULL)
3870Sstevel@tonic-gate fatal("packet_set_encryption_key: unknown cipher number %d", number);
3880Sstevel@tonic-gate if (keylen < 20)
3890Sstevel@tonic-gate fatal("packet_set_encryption_key: keylen too small: %d", keylen);
3900Sstevel@tonic-gate if (keylen > SSH_SESSION_KEY_LENGTH)
3910Sstevel@tonic-gate fatal("packet_set_encryption_key: keylen too big: %d", keylen);
3920Sstevel@tonic-gate memcpy(ssh1_key, key, keylen);
3930Sstevel@tonic-gate ssh1_keylen = keylen;
3940Sstevel@tonic-gate cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT);
3950Sstevel@tonic-gate cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT);
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate u_int
packet_get_encryption_key(u_char * key)3990Sstevel@tonic-gate packet_get_encryption_key(u_char *key)
4000Sstevel@tonic-gate {
4010Sstevel@tonic-gate if (key == NULL)
4020Sstevel@tonic-gate return (ssh1_keylen);
4030Sstevel@tonic-gate memcpy(key, ssh1_key, ssh1_keylen);
4040Sstevel@tonic-gate return (ssh1_keylen);
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate /* Start constructing a packet to send. */
4080Sstevel@tonic-gate void
packet_start(u_char type)4090Sstevel@tonic-gate packet_start(u_char type)
4100Sstevel@tonic-gate {
4110Sstevel@tonic-gate u_char buf[9];
4120Sstevel@tonic-gate int len;
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate DBG(debug("packet_start[%d]", type));
4150Sstevel@tonic-gate len = compat20 ? 6 : 9;
4160Sstevel@tonic-gate memset(buf, 0, len - 1);
4170Sstevel@tonic-gate buf[len - 1] = type;
4180Sstevel@tonic-gate buffer_clear(&outgoing_packet);
4190Sstevel@tonic-gate buffer_append(&outgoing_packet, buf, len);
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate /* Append payload. */
4230Sstevel@tonic-gate void
packet_put_char(int value)4240Sstevel@tonic-gate packet_put_char(int value)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate char ch = value;
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate buffer_append(&outgoing_packet, &ch, 1);
4290Sstevel@tonic-gate }
4305562Sjp161948
4310Sstevel@tonic-gate void
packet_put_int(u_int value)4320Sstevel@tonic-gate packet_put_int(u_int value)
4330Sstevel@tonic-gate {
4340Sstevel@tonic-gate buffer_put_int(&outgoing_packet, value);
4350Sstevel@tonic-gate }
4365562Sjp161948
4370Sstevel@tonic-gate void
packet_put_string(const void * buf,u_int len)4380Sstevel@tonic-gate packet_put_string(const void *buf, u_int len)
4390Sstevel@tonic-gate {
4400Sstevel@tonic-gate buffer_put_string(&outgoing_packet, buf, len);
4410Sstevel@tonic-gate }
4425562Sjp161948
4430Sstevel@tonic-gate void
packet_put_cstring(const char * str)4440Sstevel@tonic-gate packet_put_cstring(const char *str)
4450Sstevel@tonic-gate {
4460Sstevel@tonic-gate buffer_put_cstring(&outgoing_packet, str);
4470Sstevel@tonic-gate }
4485562Sjp161948
4490Sstevel@tonic-gate void
packet_put_utf8_cstring(const char * str)4509600SNobutomo.Nakano@Sun.COM packet_put_utf8_cstring(const char *str)
4510Sstevel@tonic-gate {
4529600SNobutomo.Nakano@Sun.COM if (datafellows & SSH_BUG_STRING_ENCODING)
4539600SNobutomo.Nakano@Sun.COM buffer_put_cstring(&outgoing_packet, str);
4549600SNobutomo.Nakano@Sun.COM else
4559600SNobutomo.Nakano@Sun.COM buffer_put_utf8_cstring(&outgoing_packet, str);
4560Sstevel@tonic-gate }
4579600SNobutomo.Nakano@Sun.COM
4580Sstevel@tonic-gate void
packet_put_utf8_string(const char * str,uint_t len)4599600SNobutomo.Nakano@Sun.COM packet_put_utf8_string(const char *str, uint_t len)
4600Sstevel@tonic-gate {
4619600SNobutomo.Nakano@Sun.COM if (datafellows & SSH_BUG_STRING_ENCODING)
4629600SNobutomo.Nakano@Sun.COM buffer_put_string(&outgoing_packet, str, len);
4639600SNobutomo.Nakano@Sun.COM else
4649600SNobutomo.Nakano@Sun.COM buffer_put_utf8_string(&outgoing_packet, str, len);
4650Sstevel@tonic-gate }
4669600SNobutomo.Nakano@Sun.COM
4670Sstevel@tonic-gate void
packet_put_raw(const void * buf,u_int len)4680Sstevel@tonic-gate packet_put_raw(const void *buf, u_int len)
4690Sstevel@tonic-gate {
4700Sstevel@tonic-gate buffer_append(&outgoing_packet, buf, len);
4710Sstevel@tonic-gate }
4725562Sjp161948
4730Sstevel@tonic-gate void
packet_put_bignum(BIGNUM * value)4740Sstevel@tonic-gate packet_put_bignum(BIGNUM * value)
4750Sstevel@tonic-gate {
4760Sstevel@tonic-gate buffer_put_bignum(&outgoing_packet, value);
4770Sstevel@tonic-gate }
4785562Sjp161948
4790Sstevel@tonic-gate void
packet_put_bignum2(BIGNUM * value)4800Sstevel@tonic-gate packet_put_bignum2(BIGNUM * value)
4810Sstevel@tonic-gate {
4820Sstevel@tonic-gate buffer_put_bignum2(&outgoing_packet, value);
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate /*
4860Sstevel@tonic-gate * Finalizes and sends the packet. If the encryption key has been set,
4870Sstevel@tonic-gate * encrypts the packet before sending.
4880Sstevel@tonic-gate */
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate static void
packet_send1(void)4910Sstevel@tonic-gate packet_send1(void)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate u_char buf[8], *cp;
4940Sstevel@tonic-gate int i, padding, len;
4950Sstevel@tonic-gate u_int checksum;
4965562Sjp161948 u_int32_t rnd = 0;
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate * If using packet compression, compress the payload of the outgoing
5000Sstevel@tonic-gate * packet.
5010Sstevel@tonic-gate */
5020Sstevel@tonic-gate if (packet_compression) {
5030Sstevel@tonic-gate buffer_clear(&compression_buffer);
5040Sstevel@tonic-gate /* Skip padding. */
5050Sstevel@tonic-gate buffer_consume(&outgoing_packet, 8);
5060Sstevel@tonic-gate /* padding */
5070Sstevel@tonic-gate buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8);
5080Sstevel@tonic-gate buffer_compress(&outgoing_packet, &compression_buffer);
5090Sstevel@tonic-gate buffer_clear(&outgoing_packet);
5100Sstevel@tonic-gate buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
5110Sstevel@tonic-gate buffer_len(&compression_buffer));
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate /* Compute packet length without padding (add checksum, remove padding). */
5140Sstevel@tonic-gate len = buffer_len(&outgoing_packet) + 4 - 8;
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate /* Insert padding. Initialized to zero in packet_start1() */
5170Sstevel@tonic-gate padding = 8 - len % 8;
5180Sstevel@tonic-gate if (!send_context.plaintext) {
5190Sstevel@tonic-gate cp = buffer_ptr(&outgoing_packet);
5200Sstevel@tonic-gate for (i = 0; i < padding; i++) {
5210Sstevel@tonic-gate if (i % 4 == 0)
5225562Sjp161948 rnd = arc4random();
5235562Sjp161948 cp[7 - i] = rnd & 0xff;
5245562Sjp161948 rnd >>= 8;
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate buffer_consume(&outgoing_packet, 8 - padding);
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate /* Add check bytes. */
5300Sstevel@tonic-gate checksum = ssh_crc32(buffer_ptr(&outgoing_packet),
5310Sstevel@tonic-gate buffer_len(&outgoing_packet));
5320Sstevel@tonic-gate PUT_32BIT(buf, checksum);
5330Sstevel@tonic-gate buffer_append(&outgoing_packet, buf, 4);
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate #ifdef PACKET_DEBUG
5360Sstevel@tonic-gate fprintf(stderr, "packet_send plain: ");
5370Sstevel@tonic-gate buffer_dump(&outgoing_packet);
5380Sstevel@tonic-gate #endif
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate /* Append to output. */
5410Sstevel@tonic-gate PUT_32BIT(buf, len);
5420Sstevel@tonic-gate buffer_append(&output, buf, 4);
5430Sstevel@tonic-gate cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
5440Sstevel@tonic-gate cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
5450Sstevel@tonic-gate buffer_len(&outgoing_packet));
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate #ifdef PACKET_DEBUG
5487574SJan.Pechanec@Sun.COM debug("encrypted output queue now contains (%d bytes):\n",
5497574SJan.Pechanec@Sun.COM buffer_len(&output));
5500Sstevel@tonic-gate buffer_dump(&output);
5510Sstevel@tonic-gate #endif
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate buffer_clear(&outgoing_packet);
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate /*
5560Sstevel@tonic-gate * Note that the packet is now only buffered in output. It won\'t be
5570Sstevel@tonic-gate * actually sent until packet_write_wait or packet_write_poll is
5580Sstevel@tonic-gate * called.
5590Sstevel@tonic-gate */
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate
5620Sstevel@tonic-gate void
set_newkeys(int mode)5630Sstevel@tonic-gate set_newkeys(int mode)
5640Sstevel@tonic-gate {
5650Sstevel@tonic-gate Enc *enc;
5660Sstevel@tonic-gate Mac *mac;
5670Sstevel@tonic-gate Comp *comp;
5680Sstevel@tonic-gate CipherContext *cc;
5695562Sjp161948 u_int64_t *max_blocks;
5705562Sjp161948 int crypt_type;
5710Sstevel@tonic-gate
5725562Sjp161948 debug2("set_newkeys: mode %d", mode);
5730Sstevel@tonic-gate
5740Sstevel@tonic-gate if (mode == MODE_OUT) {
5750Sstevel@tonic-gate cc = &send_context;
5765562Sjp161948 crypt_type = CIPHER_ENCRYPT;
5775562Sjp161948 p_send.packets = p_send.blocks = 0;
5785562Sjp161948 max_blocks = &max_blocks_out;
5790Sstevel@tonic-gate } else {
5800Sstevel@tonic-gate cc = &receive_context;
5815562Sjp161948 crypt_type = CIPHER_DECRYPT;
5825562Sjp161948 p_read.packets = p_read.blocks = 0;
5835562Sjp161948 max_blocks = &max_blocks_in;
5840Sstevel@tonic-gate }
5857574SJan.Pechanec@Sun.COM
5867574SJan.Pechanec@Sun.COM debug("set_newkeys: setting new keys for '%s' mode",
5877574SJan.Pechanec@Sun.COM mode == MODE_IN ? "in" : "out");
5887574SJan.Pechanec@Sun.COM
5890Sstevel@tonic-gate if (newkeys[mode] != NULL) {
5900Sstevel@tonic-gate cipher_cleanup(cc);
5915562Sjp161948 free_keys(newkeys[mode]);
5920Sstevel@tonic-gate }
5937574SJan.Pechanec@Sun.COM
5940Sstevel@tonic-gate newkeys[mode] = kex_get_newkeys(mode);
5950Sstevel@tonic-gate if (newkeys[mode] == NULL)
5960Sstevel@tonic-gate fatal("newkeys: no keys for mode %d", mode);
5970Sstevel@tonic-gate enc = &newkeys[mode]->enc;
5980Sstevel@tonic-gate mac = &newkeys[mode]->mac;
5990Sstevel@tonic-gate comp = &newkeys[mode]->comp;
6009486SJan.Pechanec@Sun.COM if (mac_init(mac) == 0)
6010Sstevel@tonic-gate mac->enabled = 1;
6027574SJan.Pechanec@Sun.COM #ifdef PACKET_DEBUG
6037574SJan.Pechanec@Sun.COM debug("new encryption key:\n");
6047574SJan.Pechanec@Sun.COM data_dump(enc->key, enc->key_len);
6057574SJan.Pechanec@Sun.COM debug("new encryption IV:\n");
6067574SJan.Pechanec@Sun.COM data_dump(enc->iv, enc->block_size);
6077574SJan.Pechanec@Sun.COM debug("new MAC key:\n");
6087574SJan.Pechanec@Sun.COM data_dump(mac->key, mac->key_len);
6097574SJan.Pechanec@Sun.COM #endif
6100Sstevel@tonic-gate cipher_init(cc, enc->cipher, enc->key, enc->key_len,
6115562Sjp161948 enc->iv, enc->block_size, crypt_type);
6120Sstevel@tonic-gate /* Deleting the keys does not gain extra security */
6130Sstevel@tonic-gate /* memset(enc->iv, 0, enc->block_size);
6140Sstevel@tonic-gate memset(enc->key, 0, enc->key_len); */
6150Sstevel@tonic-gate if (comp->type != 0 && comp->enabled == 0) {
6160Sstevel@tonic-gate packet_init_compression();
6170Sstevel@tonic-gate if (mode == MODE_OUT)
6180Sstevel@tonic-gate buffer_compress_init_send(6);
6190Sstevel@tonic-gate else
6200Sstevel@tonic-gate buffer_compress_init_recv();
6210Sstevel@tonic-gate comp->enabled = 1;
6220Sstevel@tonic-gate }
6235562Sjp161948
6245562Sjp161948 /*
6255562Sjp161948 * In accordance to the RFCs listed below we enforce the key
6265562Sjp161948 * re-exchange for:
6275562Sjp161948 *
6285562Sjp161948 * - every 1GB of transmitted data if the selected cipher block size
6295562Sjp161948 * is less than 16 bytes (3DES, Blowfish)
6305562Sjp161948 * - every 2^(2*B) cipher blocks transmitted (B is block size in bytes)
6315562Sjp161948 * if the cipher block size is greater than or equal to 16 bytes (AES)
6325562Sjp161948 * - and we never send more than 2^32 SSH packets using the same keys.
6335562Sjp161948 * The recommendation of 2^31 packets is not enforced here but in
6345562Sjp161948 * packet_need_rekeying(). There is also a hard check in
6355562Sjp161948 * packet_send2_wrapped() that we don't send more than 2^32 packets.
6365562Sjp161948 *
6375562Sjp161948 * Note that if the SSH_BUG_NOREKEY compatibility flag is set then no
6385562Sjp161948 * automatic rekeying is performed nor do we enforce the 3rd rule.
6395562Sjp161948 * This means that we can be always forced by the opposite side to never
6405562Sjp161948 * initiate automatic key re-exchange. This might change in the future.
6415562Sjp161948 *
6425562Sjp161948 * The RekeyLimit option keyword may only enforce more frequent key
6435562Sjp161948 * renegotiation, never less. For more information on key renegotiation,
6445562Sjp161948 * see:
6455562Sjp161948 *
6465562Sjp161948 * - RFC 4253 (SSH Transport Layer Protocol), section "9. Key
6475562Sjp161948 * Re-Exchange"
6485562Sjp161948 * - RFC 4344 (SSH Transport Layer Encryption Modes), sections "3.
6495562Sjp161948 * Rekeying" and "6.1 Rekeying Considerations"
6505562Sjp161948 */
6515562Sjp161948 if (enc->block_size >= 16)
6525562Sjp161948 *max_blocks = (u_int64_t)1 << (enc->block_size * 2);
6535562Sjp161948 else
6545562Sjp161948 *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
6555562Sjp161948
6565562Sjp161948 if (rekey_limit)
6575562Sjp161948 *max_blocks = MIN(*max_blocks, rekey_limit / enc->block_size);
6585562Sjp161948 }
6595562Sjp161948
6605562Sjp161948 void
free_keys(Newkeys * keys)6615562Sjp161948 free_keys(Newkeys *keys)
6625562Sjp161948 {
6635562Sjp161948 Enc *enc;
6645562Sjp161948 Mac *mac;
6655562Sjp161948 Comp *comp;
6665562Sjp161948
6675562Sjp161948 enc = &keys->enc;
6685562Sjp161948 mac = &keys->mac;
6695562Sjp161948 comp = &keys->comp;
6705562Sjp161948 xfree(enc->name);
6715562Sjp161948 xfree(enc->iv);
6725562Sjp161948 xfree(enc->key);
6739486SJan.Pechanec@Sun.COM
6749486SJan.Pechanec@Sun.COM memset(mac->key, 0, mac->key_len);
6759486SJan.Pechanec@Sun.COM xfree(mac->key);
6765562Sjp161948 xfree(mac->name);
6779486SJan.Pechanec@Sun.COM mac_clear(mac);
6789486SJan.Pechanec@Sun.COM
6795562Sjp161948 xfree(comp->name);
6805562Sjp161948 xfree(keys);
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate
6830Sstevel@tonic-gate /*
6847574SJan.Pechanec@Sun.COM * Process SSH2_MSG_NEWKEYS message. If we are using the engine we must have
6857574SJan.Pechanec@Sun.COM * both SSH2_MSG_NEWKEYS processed before we can finish the engine, fork, and
6867574SJan.Pechanec@Sun.COM * reinitialize the crypto contexts. We can't fork before processing the 2nd
6877574SJan.Pechanec@Sun.COM * message otherwise we couldn't encrypt/decrypt that message at all - note that
6887574SJan.Pechanec@Sun.COM * parent's PKCS#11 sessions are useless after the fork and we must process
6897574SJan.Pechanec@Sun.COM * both SSH2_MSG_NEWKEYS messages using the old keys.
6907574SJan.Pechanec@Sun.COM */
6917574SJan.Pechanec@Sun.COM void
process_newkeys(int mode)6927574SJan.Pechanec@Sun.COM process_newkeys(int mode)
6937574SJan.Pechanec@Sun.COM {
6947733SJan.Pechanec@Sun.COM /* this function is for the client only */
6957574SJan.Pechanec@Sun.COM if (packet_is_server() != 0)
6967574SJan.Pechanec@Sun.COM return;
6977574SJan.Pechanec@Sun.COM
6987574SJan.Pechanec@Sun.COM if (will_daemonize == FIRST_NEWKEYS_PROCESSED) {
6997574SJan.Pechanec@Sun.COM debug3("both SSH2_MSG_NEWKEYS processed, will daemonize now");
7007574SJan.Pechanec@Sun.COM cipher_cleanup(&send_context);
7017574SJan.Pechanec@Sun.COM cipher_cleanup(&receive_context);
7027574SJan.Pechanec@Sun.COM pkcs11_engine_finish(e);
7037574SJan.Pechanec@Sun.COM if (daemon(1, 1) < 0) {
7047574SJan.Pechanec@Sun.COM fatal("daemon() failed: %.200s",
7057574SJan.Pechanec@Sun.COM strerror(errno));
7067574SJan.Pechanec@Sun.COM }
7077574SJan.Pechanec@Sun.COM e = pkcs11_engine_load(e != NULL ? 1 : 0);
7087574SJan.Pechanec@Sun.COM
7097574SJan.Pechanec@Sun.COM set_newkeys(MODE_OUT);
7107574SJan.Pechanec@Sun.COM set_newkeys(MODE_IN);
7117574SJan.Pechanec@Sun.COM will_daemonize = SECOND_NEWKEYS_PROCESSED;
7127574SJan.Pechanec@Sun.COM packet_send2();
7137574SJan.Pechanec@Sun.COM } else {
7147574SJan.Pechanec@Sun.COM if (will_daemonize == DAEMONIZING_REQUESTED)
7157574SJan.Pechanec@Sun.COM will_daemonize = FIRST_NEWKEYS_PROCESSED;
7167574SJan.Pechanec@Sun.COM else
7177574SJan.Pechanec@Sun.COM set_newkeys(mode);
7187574SJan.Pechanec@Sun.COM }
7197574SJan.Pechanec@Sun.COM }
7207574SJan.Pechanec@Sun.COM
7217574SJan.Pechanec@Sun.COM /*
7220Sstevel@tonic-gate * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
7230Sstevel@tonic-gate */
7240Sstevel@tonic-gate static void
packet_send2_wrapped(void)7255562Sjp161948 packet_send2_wrapped(void)
7260Sstevel@tonic-gate {
7270Sstevel@tonic-gate u_char type, *cp, *macbuf = NULL;
7280Sstevel@tonic-gate u_char padlen, pad;
7290Sstevel@tonic-gate u_int packet_length = 0;
7300Sstevel@tonic-gate u_int i, len;
7315562Sjp161948 u_int32_t rnd = 0;
7320Sstevel@tonic-gate Enc *enc = NULL;
7330Sstevel@tonic-gate Mac *mac = NULL;
7340Sstevel@tonic-gate Comp *comp = NULL;
7350Sstevel@tonic-gate int block_size;
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate if (newkeys[MODE_OUT] != NULL) {
7380Sstevel@tonic-gate enc = &newkeys[MODE_OUT]->enc;
7390Sstevel@tonic-gate mac = &newkeys[MODE_OUT]->mac;
7400Sstevel@tonic-gate comp = &newkeys[MODE_OUT]->comp;
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate block_size = enc ? enc->block_size : 8;
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate cp = buffer_ptr(&outgoing_packet);
7450Sstevel@tonic-gate type = cp[5];
7460Sstevel@tonic-gate
7470Sstevel@tonic-gate #ifdef PACKET_DEBUG
7487574SJan.Pechanec@Sun.COM debug("plain output packet to be processed (%d bytes):\n",
7497574SJan.Pechanec@Sun.COM buffer_len(&outgoing_packet));
7500Sstevel@tonic-gate buffer_dump(&outgoing_packet);
7510Sstevel@tonic-gate #endif
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate if (comp && comp->enabled) {
7540Sstevel@tonic-gate len = buffer_len(&outgoing_packet);
7550Sstevel@tonic-gate /* skip header, compress only payload */
7560Sstevel@tonic-gate buffer_consume(&outgoing_packet, 5);
7570Sstevel@tonic-gate buffer_clear(&compression_buffer);
7580Sstevel@tonic-gate buffer_compress(&outgoing_packet, &compression_buffer);
7590Sstevel@tonic-gate buffer_clear(&outgoing_packet);
7600Sstevel@tonic-gate buffer_append(&outgoing_packet, "\0\0\0\0\0", 5);
7610Sstevel@tonic-gate buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
7620Sstevel@tonic-gate buffer_len(&compression_buffer));
7630Sstevel@tonic-gate DBG(debug("compression: raw %d compressed %d", len,
7640Sstevel@tonic-gate buffer_len(&outgoing_packet)));
7650Sstevel@tonic-gate }
7660Sstevel@tonic-gate
7670Sstevel@tonic-gate /* sizeof (packet_len + pad_len + payload) */
7680Sstevel@tonic-gate len = buffer_len(&outgoing_packet);
7690Sstevel@tonic-gate
7700Sstevel@tonic-gate /*
7710Sstevel@tonic-gate * calc size of padding, alloc space, get random data,
7720Sstevel@tonic-gate * minimum padding is 4 bytes
7730Sstevel@tonic-gate */
7740Sstevel@tonic-gate padlen = block_size - (len % block_size);
7750Sstevel@tonic-gate if (padlen < 4)
7760Sstevel@tonic-gate padlen += block_size;
7770Sstevel@tonic-gate if (extra_pad) {
7780Sstevel@tonic-gate /* will wrap if extra_pad+padlen > 255 */
7790Sstevel@tonic-gate extra_pad = roundup(extra_pad, block_size);
7800Sstevel@tonic-gate pad = extra_pad - ((len + padlen) % extra_pad);
7810Sstevel@tonic-gate debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)",
7820Sstevel@tonic-gate pad, len, padlen, extra_pad);
7830Sstevel@tonic-gate padlen += pad;
7840Sstevel@tonic-gate extra_pad = 0;
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate cp = buffer_append_space(&outgoing_packet, padlen);
7870Sstevel@tonic-gate if (enc && !send_context.plaintext) {
7880Sstevel@tonic-gate /* random padding */
7890Sstevel@tonic-gate for (i = 0; i < padlen; i++) {
7900Sstevel@tonic-gate if (i % 4 == 0)
7915562Sjp161948 rnd = arc4random();
7925562Sjp161948 cp[i] = rnd & 0xff;
7935562Sjp161948 rnd >>= 8;
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate } else {
7960Sstevel@tonic-gate /* clear padding */
7970Sstevel@tonic-gate memset(cp, 0, padlen);
7980Sstevel@tonic-gate }
7990Sstevel@tonic-gate /* packet_length includes payload, padding and padding length field */
8000Sstevel@tonic-gate packet_length = buffer_len(&outgoing_packet) - 4;
8010Sstevel@tonic-gate cp = buffer_ptr(&outgoing_packet);
8020Sstevel@tonic-gate PUT_32BIT(cp, packet_length);
8030Sstevel@tonic-gate cp[4] = padlen;
8047574SJan.Pechanec@Sun.COM DBG(debug("will send %d bytes (includes padlen %d)",
8057574SJan.Pechanec@Sun.COM packet_length + 4, padlen));
8060Sstevel@tonic-gate
8070Sstevel@tonic-gate /* compute MAC over seqnr and packet(length fields, payload, padding) */
8080Sstevel@tonic-gate if (mac && mac->enabled) {
8095562Sjp161948 macbuf = mac_compute(mac, p_send.seqnr,
8100Sstevel@tonic-gate buffer_ptr(&outgoing_packet),
8110Sstevel@tonic-gate buffer_len(&outgoing_packet));
8125562Sjp161948 DBG(debug("done calc MAC out #%d", p_send.seqnr));
8130Sstevel@tonic-gate }
8140Sstevel@tonic-gate /* encrypt packet and append to output buffer. */
8150Sstevel@tonic-gate cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
8160Sstevel@tonic-gate cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
8170Sstevel@tonic-gate buffer_len(&outgoing_packet));
8180Sstevel@tonic-gate /* append unencrypted MAC */
8190Sstevel@tonic-gate if (mac && mac->enabled)
8200Sstevel@tonic-gate buffer_append(&output, (char *)macbuf, mac->mac_len);
8210Sstevel@tonic-gate #ifdef PACKET_DEBUG
8227574SJan.Pechanec@Sun.COM debug("encrypted output queue now contains (%d bytes):\n",
8237574SJan.Pechanec@Sun.COM buffer_len(&output));
8240Sstevel@tonic-gate buffer_dump(&output);
8250Sstevel@tonic-gate #endif
8260Sstevel@tonic-gate /* increment sequence number for outgoing packets */
8275562Sjp161948 if (++p_send.seqnr == 0)
8280Sstevel@tonic-gate log("outgoing seqnr wraps around");
8295562Sjp161948
8305562Sjp161948 /*
8315562Sjp161948 * RFC 4344: 3.1. First Rekeying Recommendation
8325562Sjp161948 *
8335562Sjp161948 * "Because of possible information leakage through the MAC tag after a
8345562Sjp161948 * key exchange, .... an SSH implementation SHOULD NOT send more than
8355562Sjp161948 * 2**32 packets before rekeying again."
8365562Sjp161948 *
8375562Sjp161948 * The code below is a hard check so that we are sure we don't go across
8385562Sjp161948 * the suggestion. However, since the largest cipher block size we have
8395562Sjp161948 * (AES) is 16 bytes we can't reach 2^32 SSH packets encrypted with the
8405562Sjp161948 * same key while performing periodic rekeying.
8415562Sjp161948 */
8425562Sjp161948 if (++p_send.packets == 0)
8435562Sjp161948 if (!(datafellows & SSH_BUG_NOREKEY))
8445562Sjp161948 fatal("too many packets encrypted with same key");
8455562Sjp161948 p_send.blocks += (packet_length + 4) / block_size;
8460Sstevel@tonic-gate buffer_clear(&outgoing_packet);
8470Sstevel@tonic-gate
8487574SJan.Pechanec@Sun.COM if (type == SSH2_MSG_NEWKEYS) {
8497574SJan.Pechanec@Sun.COM /*
8507574SJan.Pechanec@Sun.COM * set_newkeys(MODE_OUT) in the client. Note that in the
8517574SJan.Pechanec@Sun.COM * unprivileged child, set_newkeys() for MODE_OUT are set after
8527574SJan.Pechanec@Sun.COM * SSH2_MSG_NEWKEYS is read from the monitor and forwarded to
8537574SJan.Pechanec@Sun.COM * the client side.
8547574SJan.Pechanec@Sun.COM */
8557574SJan.Pechanec@Sun.COM process_newkeys(MODE_OUT);
8567574SJan.Pechanec@Sun.COM }
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate
8597574SJan.Pechanec@Sun.COM /*
8607574SJan.Pechanec@Sun.COM * Packets we deal with here are plain until we encrypt them in
8617574SJan.Pechanec@Sun.COM * packet_send2_wrapped().
8627574SJan.Pechanec@Sun.COM *
8637574SJan.Pechanec@Sun.COM * As already mentioned in a comment at process_newkeys() function we must not
8647574SJan.Pechanec@Sun.COM * fork() until both SSH2_MSG_NEWKEYS packets were processed. Until this is done
8657574SJan.Pechanec@Sun.COM * we must queue all packets so that they can be encrypted with the new keys and
8667574SJan.Pechanec@Sun.COM * then sent to the other side. However, what can happen here is that we get
8677574SJan.Pechanec@Sun.COM * SSH2_MSG_NEWKEYS after we sent it. In that situation we must call
8687574SJan.Pechanec@Sun.COM * packet_send2() anyway to empty the queue, and set the rekey flag to the
8697574SJan.Pechanec@Sun.COM * finished state. If we didn't do that we would just hang and enqueue data.
8707574SJan.Pechanec@Sun.COM */
8715562Sjp161948 static void
packet_send2(void)8725562Sjp161948 packet_send2(void)
8735562Sjp161948 {
8745562Sjp161948 static int rekeying = 0;
8755562Sjp161948 struct packet *p;
8765562Sjp161948 u_char type, *cp;
8775562Sjp161948
8787574SJan.Pechanec@Sun.COM if (will_daemonize != SECOND_NEWKEYS_PROCESSED) {
8797574SJan.Pechanec@Sun.COM cp = buffer_ptr(&outgoing_packet);
8807574SJan.Pechanec@Sun.COM type = cp[5];
8815562Sjp161948
8827574SJan.Pechanec@Sun.COM /* during rekeying we can only send key exchange messages */
8837574SJan.Pechanec@Sun.COM if (rekeying) {
8847574SJan.Pechanec@Sun.COM if (!((type >= SSH2_MSG_TRANSPORT_MIN) &&
8857574SJan.Pechanec@Sun.COM (type <= SSH2_MSG_TRANSPORT_MAX))) {
8867574SJan.Pechanec@Sun.COM debug("enqueue a plain packet because rekex in "
8877574SJan.Pechanec@Sun.COM "progress [type %u]", type);
8887574SJan.Pechanec@Sun.COM p = xmalloc(sizeof(*p));
8897574SJan.Pechanec@Sun.COM p->type = type;
8907574SJan.Pechanec@Sun.COM memcpy(&p->payload, &outgoing_packet, sizeof(Buffer));
8917574SJan.Pechanec@Sun.COM buffer_init(&outgoing_packet);
8927574SJan.Pechanec@Sun.COM TAILQ_INSERT_TAIL(&outgoing, p, next);
8937574SJan.Pechanec@Sun.COM return;
8947574SJan.Pechanec@Sun.COM }
8955562Sjp161948 }
8967574SJan.Pechanec@Sun.COM
8977574SJan.Pechanec@Sun.COM /* rekeying starts with sending KEXINIT */
8987574SJan.Pechanec@Sun.COM if (type == SSH2_MSG_KEXINIT)
8997574SJan.Pechanec@Sun.COM rekeying = 1;
9007574SJan.Pechanec@Sun.COM
9017574SJan.Pechanec@Sun.COM packet_send2_wrapped();
9025562Sjp161948 }
9035562Sjp161948
9047574SJan.Pechanec@Sun.COM /* after rekex is done we can process the queue of plain packets */
9057574SJan.Pechanec@Sun.COM if (will_daemonize == SECOND_NEWKEYS_PROCESSED ||
9067574SJan.Pechanec@Sun.COM (will_daemonize == NOT_DAEMONIZING && type == SSH2_MSG_NEWKEYS)) {
9075562Sjp161948 rekeying = 0;
9087574SJan.Pechanec@Sun.COM will_daemonize = NOT_DAEMONIZING;
9095562Sjp161948 while ((p = TAILQ_FIRST(&outgoing)) != NULL) {
9105562Sjp161948 type = p->type;
9117574SJan.Pechanec@Sun.COM debug("dequeuing a plain packet since rekex is over "
9127574SJan.Pechanec@Sun.COM "[type %u]", type);
9135562Sjp161948 buffer_free(&outgoing_packet);
9145562Sjp161948 memcpy(&outgoing_packet, &p->payload, sizeof(Buffer));
9155562Sjp161948 TAILQ_REMOVE(&outgoing, p, next);
9165562Sjp161948 xfree(p);
9175562Sjp161948 packet_send2_wrapped();
9185562Sjp161948 }
9195562Sjp161948 }
9205562Sjp161948 }
9215562Sjp161948
9220Sstevel@tonic-gate void
packet_send(void)9230Sstevel@tonic-gate packet_send(void)
9240Sstevel@tonic-gate {
9250Sstevel@tonic-gate if (compat20)
9260Sstevel@tonic-gate packet_send2();
9270Sstevel@tonic-gate else
9280Sstevel@tonic-gate packet_send1();
9290Sstevel@tonic-gate DBG(debug("packet_send done"));
9300Sstevel@tonic-gate }
9310Sstevel@tonic-gate
9320Sstevel@tonic-gate /*
9330Sstevel@tonic-gate * Waits until a packet has been received, and returns its type. Note that
9340Sstevel@tonic-gate * no other data is processed until this returns, so this function should not
9350Sstevel@tonic-gate * be used during the interactive session.
936*10515SJan.Pechanec@Sun.COM *
937*10515SJan.Pechanec@Sun.COM * The function is also used in the monitor to read the authentication context
938*10515SJan.Pechanec@Sun.COM * in aps_read_auth_context() via packet_read_seqnr(), before the monitor enters
939*10515SJan.Pechanec@Sun.COM * aps_monitor_loop() and starts using the process_input() function.
9400Sstevel@tonic-gate */
9410Sstevel@tonic-gate int
packet_read_seqnr(u_int32_t * seqnr_p)9420Sstevel@tonic-gate packet_read_seqnr(u_int32_t *seqnr_p)
9430Sstevel@tonic-gate {
9440Sstevel@tonic-gate int type, len;
9450Sstevel@tonic-gate fd_set *setp;
9460Sstevel@tonic-gate char buf[8192];
9470Sstevel@tonic-gate DBG(debug("packet_read()"));
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) *
9500Sstevel@tonic-gate sizeof(fd_mask));
9510Sstevel@tonic-gate
9520Sstevel@tonic-gate /* Since we are blocking, ensure that all written packets have been sent. */
9530Sstevel@tonic-gate packet_write_wait();
9540Sstevel@tonic-gate
9550Sstevel@tonic-gate /* Stay in the loop until we have received a complete packet. */
9560Sstevel@tonic-gate for (;;) {
9570Sstevel@tonic-gate /* Try to read a packet from the buffer. */
9580Sstevel@tonic-gate type = packet_read_poll_seqnr(seqnr_p);
9590Sstevel@tonic-gate if (!compat20 && (
9600Sstevel@tonic-gate type == SSH_SMSG_SUCCESS
9610Sstevel@tonic-gate || type == SSH_SMSG_FAILURE
9620Sstevel@tonic-gate || type == SSH_CMSG_EOF
9630Sstevel@tonic-gate || type == SSH_CMSG_EXIT_CONFIRMATION))
9640Sstevel@tonic-gate packet_check_eom();
9650Sstevel@tonic-gate /* If we got a packet, return it. */
9660Sstevel@tonic-gate if (type != SSH_MSG_NONE) {
9670Sstevel@tonic-gate xfree(setp);
9680Sstevel@tonic-gate return type;
9690Sstevel@tonic-gate }
9700Sstevel@tonic-gate /*
9710Sstevel@tonic-gate * Otherwise, wait for some data to arrive, add it to the
9720Sstevel@tonic-gate * buffer, and try again.
9730Sstevel@tonic-gate */
9740Sstevel@tonic-gate memset(setp, 0, howmany(connection_in + 1, NFDBITS) *
9750Sstevel@tonic-gate sizeof(fd_mask));
9760Sstevel@tonic-gate FD_SET(connection_in, setp);
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate /* Wait for some data to arrive. */
9790Sstevel@tonic-gate while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
9800Sstevel@tonic-gate (errno == EAGAIN || errno == EINTR))
9810Sstevel@tonic-gate ;
9820Sstevel@tonic-gate
9830Sstevel@tonic-gate /* Read data from the socket. */
9840Sstevel@tonic-gate len = read(connection_in, buf, sizeof(buf));
9850Sstevel@tonic-gate if (len == 0) {
986*10515SJan.Pechanec@Sun.COM if (packet_connection_is_on_socket())
987*10515SJan.Pechanec@Sun.COM log("Connection closed by %.200s",
988*10515SJan.Pechanec@Sun.COM get_remote_ipaddr());
989*10515SJan.Pechanec@Sun.COM else
990*10515SJan.Pechanec@Sun.COM debug("child closed the communication pipe "
991*10515SJan.Pechanec@Sun.COM "before user auth was finished");
9920Sstevel@tonic-gate fatal_cleanup();
9930Sstevel@tonic-gate }
994*10515SJan.Pechanec@Sun.COM if (len < 0) {
995*10515SJan.Pechanec@Sun.COM if (packet_connection_is_on_socket())
996*10515SJan.Pechanec@Sun.COM fatal("Read from socket failed: %.100s",
997*10515SJan.Pechanec@Sun.COM strerror(errno));
998*10515SJan.Pechanec@Sun.COM else
999*10515SJan.Pechanec@Sun.COM fatal("Read from communication pipe failed: "
1000*10515SJan.Pechanec@Sun.COM "%.100s", strerror(errno));
1001*10515SJan.Pechanec@Sun.COM }
10020Sstevel@tonic-gate /* Append it to the buffer. */
10030Sstevel@tonic-gate packet_process_incoming(buf, len);
10040Sstevel@tonic-gate }
10050Sstevel@tonic-gate /* NOTREACHED */
10060Sstevel@tonic-gate }
10070Sstevel@tonic-gate
10080Sstevel@tonic-gate int
packet_read(void)10090Sstevel@tonic-gate packet_read(void)
10100Sstevel@tonic-gate {
10110Sstevel@tonic-gate return packet_read_seqnr(NULL);
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate
10140Sstevel@tonic-gate /*
10150Sstevel@tonic-gate * Waits until a packet has been received, verifies that its type matches
10160Sstevel@tonic-gate * that given, and gives a fatal error and exits if there is a mismatch.
10170Sstevel@tonic-gate */
10180Sstevel@tonic-gate
10190Sstevel@tonic-gate void
packet_read_expect(int expected_type)10200Sstevel@tonic-gate packet_read_expect(int expected_type)
10210Sstevel@tonic-gate {
10220Sstevel@tonic-gate int type;
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate type = packet_read();
10250Sstevel@tonic-gate if (type != expected_type)
10260Sstevel@tonic-gate packet_disconnect("Protocol error: expected packet type %d, got %d",
10270Sstevel@tonic-gate expected_type, type);
10280Sstevel@tonic-gate }
10290Sstevel@tonic-gate
10300Sstevel@tonic-gate /* Checks if a full packet is available in the data received so far via
10310Sstevel@tonic-gate * packet_process_incoming. If so, reads the packet; otherwise returns
10320Sstevel@tonic-gate * SSH_MSG_NONE. This does not wait for data from the connection.
10330Sstevel@tonic-gate *
10340Sstevel@tonic-gate * SSH_MSG_DISCONNECT is handled specially here. Also,
10350Sstevel@tonic-gate * SSH_MSG_IGNORE messages are skipped by this function and are never returned
10360Sstevel@tonic-gate * to higher levels.
10370Sstevel@tonic-gate */
10380Sstevel@tonic-gate
10390Sstevel@tonic-gate static int
packet_read_poll1(void)10400Sstevel@tonic-gate packet_read_poll1(void)
10410Sstevel@tonic-gate {
10420Sstevel@tonic-gate u_int len, padded_len;
10430Sstevel@tonic-gate u_char *cp, type;
10440Sstevel@tonic-gate u_int checksum, stored_checksum;
10450Sstevel@tonic-gate
10460Sstevel@tonic-gate /* Check if input size is less than minimum packet size. */
10470Sstevel@tonic-gate if (buffer_len(&input) < 4 + 8)
10480Sstevel@tonic-gate return SSH_MSG_NONE;
10490Sstevel@tonic-gate /* Get length of incoming packet. */
10500Sstevel@tonic-gate cp = buffer_ptr(&input);
10510Sstevel@tonic-gate len = GET_32BIT(cp);
10520Sstevel@tonic-gate if (len < 1 + 2 + 2 || len > 256 * 1024)
10530Sstevel@tonic-gate packet_disconnect("Bad packet length %d.", len);
10540Sstevel@tonic-gate padded_len = (len + 8) & ~7;
10550Sstevel@tonic-gate
10560Sstevel@tonic-gate /* Check if the packet has been entirely received. */
10570Sstevel@tonic-gate if (buffer_len(&input) < 4 + padded_len)
10580Sstevel@tonic-gate return SSH_MSG_NONE;
10590Sstevel@tonic-gate
10600Sstevel@tonic-gate /* The entire packet is in buffer. */
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate /* Consume packet length. */
10630Sstevel@tonic-gate buffer_consume(&input, 4);
10640Sstevel@tonic-gate
10650Sstevel@tonic-gate /*
10660Sstevel@tonic-gate * Cryptographic attack detector for ssh
10670Sstevel@tonic-gate * (C)1998 CORE-SDI, Buenos Aires Argentina
10680Sstevel@tonic-gate * Ariel Futoransky(futo@core-sdi.com)
10690Sstevel@tonic-gate */
10703102Sjp161948 if (!receive_context.plaintext) {
10713102Sjp161948 switch (detect_attack(buffer_ptr(&input), padded_len, NULL)) {
10723102Sjp161948 case DEATTACK_DETECTED:
10733102Sjp161948 packet_disconnect("crc32 compensation attack: "
10743102Sjp161948 "network attack detected");
10753102Sjp161948 break;
10763102Sjp161948 case DEATTACK_DOS_DETECTED:
10773102Sjp161948 packet_disconnect("deattack denial of "
10783102Sjp161948 "service detected");
10793102Sjp161948 break;
10803102Sjp161948 }
10813102Sjp161948 }
10820Sstevel@tonic-gate
10830Sstevel@tonic-gate /* Decrypt data to incoming_packet. */
10840Sstevel@tonic-gate buffer_clear(&incoming_packet);
10850Sstevel@tonic-gate cp = buffer_append_space(&incoming_packet, padded_len);
10860Sstevel@tonic-gate cipher_crypt(&receive_context, cp, buffer_ptr(&input), padded_len);
10870Sstevel@tonic-gate
10880Sstevel@tonic-gate buffer_consume(&input, padded_len);
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate #ifdef PACKET_DEBUG
10917574SJan.Pechanec@Sun.COM debug("read_poll plain/full:\n");
10920Sstevel@tonic-gate buffer_dump(&incoming_packet);
10930Sstevel@tonic-gate #endif
10940Sstevel@tonic-gate
10950Sstevel@tonic-gate /* Compute packet checksum. */
10960Sstevel@tonic-gate checksum = ssh_crc32(buffer_ptr(&incoming_packet),
10970Sstevel@tonic-gate buffer_len(&incoming_packet) - 4);
10980Sstevel@tonic-gate
10990Sstevel@tonic-gate /* Skip padding. */
11000Sstevel@tonic-gate buffer_consume(&incoming_packet, 8 - len % 8);
11010Sstevel@tonic-gate
11020Sstevel@tonic-gate /* Test check bytes. */
11030Sstevel@tonic-gate if (len != buffer_len(&incoming_packet))
11040Sstevel@tonic-gate packet_disconnect("packet_read_poll1: len %d != buffer_len %d.",
11050Sstevel@tonic-gate len, buffer_len(&incoming_packet));
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4;
11080Sstevel@tonic-gate stored_checksum = GET_32BIT(cp);
11090Sstevel@tonic-gate if (checksum != stored_checksum)
11100Sstevel@tonic-gate packet_disconnect("Corrupted check bytes on input.");
11110Sstevel@tonic-gate buffer_consume_end(&incoming_packet, 4);
11120Sstevel@tonic-gate
11130Sstevel@tonic-gate if (packet_compression) {
11140Sstevel@tonic-gate buffer_clear(&compression_buffer);
11150Sstevel@tonic-gate buffer_uncompress(&incoming_packet, &compression_buffer);
11160Sstevel@tonic-gate buffer_clear(&incoming_packet);
11170Sstevel@tonic-gate buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
11180Sstevel@tonic-gate buffer_len(&compression_buffer));
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate type = buffer_get_char(&incoming_packet);
11210Sstevel@tonic-gate return type;
11220Sstevel@tonic-gate }
11230Sstevel@tonic-gate
11240Sstevel@tonic-gate static int
packet_read_poll2(u_int32_t * seqnr_p)11250Sstevel@tonic-gate packet_read_poll2(u_int32_t *seqnr_p)
11260Sstevel@tonic-gate {
11270Sstevel@tonic-gate static u_int packet_length = 0;
11280Sstevel@tonic-gate u_int padlen, need;
11290Sstevel@tonic-gate u_char *macbuf, *cp, type;
11300Sstevel@tonic-gate int maclen, block_size;
11310Sstevel@tonic-gate Enc *enc = NULL;
11320Sstevel@tonic-gate Mac *mac = NULL;
11330Sstevel@tonic-gate Comp *comp = NULL;
11340Sstevel@tonic-gate
11350Sstevel@tonic-gate if (newkeys[MODE_IN] != NULL) {
11360Sstevel@tonic-gate enc = &newkeys[MODE_IN]->enc;
11370Sstevel@tonic-gate mac = &newkeys[MODE_IN]->mac;
11380Sstevel@tonic-gate comp = &newkeys[MODE_IN]->comp;
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate maclen = mac && mac->enabled ? mac->mac_len : 0;
11410Sstevel@tonic-gate block_size = enc ? enc->block_size : 8;
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate if (packet_length == 0) {
11440Sstevel@tonic-gate /*
11450Sstevel@tonic-gate * check if input size is less than the cipher block size,
11460Sstevel@tonic-gate * decrypt first block and extract length of incoming packet
11470Sstevel@tonic-gate */
11480Sstevel@tonic-gate if (buffer_len(&input) < block_size)
11490Sstevel@tonic-gate return SSH_MSG_NONE;
11507574SJan.Pechanec@Sun.COM #ifdef PACKET_DEBUG
11517574SJan.Pechanec@Sun.COM debug("encrypted data we have in read queue (%d bytes):\n",
11527574SJan.Pechanec@Sun.COM buffer_len(&input));
11537574SJan.Pechanec@Sun.COM buffer_dump(&input);
11547574SJan.Pechanec@Sun.COM #endif
11550Sstevel@tonic-gate buffer_clear(&incoming_packet);
11560Sstevel@tonic-gate cp = buffer_append_space(&incoming_packet, block_size);
11570Sstevel@tonic-gate cipher_crypt(&receive_context, cp, buffer_ptr(&input),
11580Sstevel@tonic-gate block_size);
11590Sstevel@tonic-gate cp = buffer_ptr(&incoming_packet);
11600Sstevel@tonic-gate packet_length = GET_32BIT(cp);
11610Sstevel@tonic-gate if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
11628298SJan.Pechanec@Sun.COM packet_disconnect("Bad packet length.");
11630Sstevel@tonic-gate }
11645562Sjp161948 DBG(debug("input: packet len %u", packet_length + 4));
11650Sstevel@tonic-gate buffer_consume(&input, block_size);
11660Sstevel@tonic-gate }
11670Sstevel@tonic-gate /* we have a partial packet of block_size bytes */
11680Sstevel@tonic-gate need = 4 + packet_length - block_size;
11697574SJan.Pechanec@Sun.COM DBG(debug("partial packet %d, still need %d, maclen %d", block_size,
11700Sstevel@tonic-gate need, maclen));
11710Sstevel@tonic-gate if (need % block_size != 0)
11728298SJan.Pechanec@Sun.COM packet_disconnect("Bad packet length.");
11730Sstevel@tonic-gate /*
11740Sstevel@tonic-gate * check if the entire packet has been received and
11750Sstevel@tonic-gate * decrypt into incoming_packet
11760Sstevel@tonic-gate */
11770Sstevel@tonic-gate if (buffer_len(&input) < need + maclen)
11780Sstevel@tonic-gate return SSH_MSG_NONE;
11790Sstevel@tonic-gate #ifdef PACKET_DEBUG
11807574SJan.Pechanec@Sun.COM debug("in read_poll, the encrypted input queue now contains "
11817574SJan.Pechanec@Sun.COM "(%d bytes):\n", buffer_len(&input));
11820Sstevel@tonic-gate buffer_dump(&input);
11830Sstevel@tonic-gate #endif
11840Sstevel@tonic-gate cp = buffer_append_space(&incoming_packet, need);
11850Sstevel@tonic-gate cipher_crypt(&receive_context, cp, buffer_ptr(&input), need);
11860Sstevel@tonic-gate buffer_consume(&input, need);
11870Sstevel@tonic-gate /*
11880Sstevel@tonic-gate * compute MAC over seqnr and packet,
11890Sstevel@tonic-gate * increment sequence number for incoming packet
11900Sstevel@tonic-gate */
11910Sstevel@tonic-gate if (mac && mac->enabled) {
11925562Sjp161948 macbuf = mac_compute(mac, p_read.seqnr,
11930Sstevel@tonic-gate buffer_ptr(&incoming_packet),
11940Sstevel@tonic-gate buffer_len(&incoming_packet));
11950Sstevel@tonic-gate if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
11960Sstevel@tonic-gate packet_disconnect("Corrupted MAC on input.");
11975562Sjp161948 DBG(debug("MAC #%d ok", p_read.seqnr));
11980Sstevel@tonic-gate buffer_consume(&input, mac->mac_len);
11990Sstevel@tonic-gate }
12000Sstevel@tonic-gate if (seqnr_p != NULL)
12015562Sjp161948 *seqnr_p = p_read.seqnr;
12025562Sjp161948 if (++p_read.seqnr == 0)
12030Sstevel@tonic-gate log("incoming seqnr wraps around");
12040Sstevel@tonic-gate
12055562Sjp161948 /* see above for the comment on "First Rekeying Recommendation" */
12065562Sjp161948 if (++p_read.packets == 0)
12075562Sjp161948 if (!(datafellows & SSH_BUG_NOREKEY))
12085562Sjp161948 fatal("too many packets with same key");
12095562Sjp161948 p_read.blocks += (packet_length + 4) / block_size;
12105562Sjp161948
12110Sstevel@tonic-gate /* get padlen */
12120Sstevel@tonic-gate cp = buffer_ptr(&incoming_packet);
12130Sstevel@tonic-gate padlen = cp[4];
12140Sstevel@tonic-gate DBG(debug("input: padlen %d", padlen));
12150Sstevel@tonic-gate if (padlen < 4)
12160Sstevel@tonic-gate packet_disconnect("Corrupted padlen %d on input.", padlen);
12170Sstevel@tonic-gate
12180Sstevel@tonic-gate /* skip packet size + padlen, discard padding */
12190Sstevel@tonic-gate buffer_consume(&incoming_packet, 4 + 1);
12200Sstevel@tonic-gate buffer_consume_end(&incoming_packet, padlen);
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet)));
12230Sstevel@tonic-gate if (comp && comp->enabled) {
12240Sstevel@tonic-gate buffer_clear(&compression_buffer);
12250Sstevel@tonic-gate buffer_uncompress(&incoming_packet, &compression_buffer);
12260Sstevel@tonic-gate buffer_clear(&incoming_packet);
12270Sstevel@tonic-gate buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
12280Sstevel@tonic-gate buffer_len(&compression_buffer));
12290Sstevel@tonic-gate DBG(debug("input: len after de-compress %d",
12300Sstevel@tonic-gate buffer_len(&incoming_packet)));
12310Sstevel@tonic-gate }
12320Sstevel@tonic-gate /*
12330Sstevel@tonic-gate * get packet type, implies consume.
12340Sstevel@tonic-gate * return length of payload (without type field)
12350Sstevel@tonic-gate */
12360Sstevel@tonic-gate type = buffer_get_char(&incoming_packet);
12377574SJan.Pechanec@Sun.COM if (type == SSH2_MSG_NEWKEYS) {
12387574SJan.Pechanec@Sun.COM /*
12397574SJan.Pechanec@Sun.COM * set_newkeys(MODE_IN) in the client because it doesn't have a
12407574SJan.Pechanec@Sun.COM * dispatch function for SSH2_MSG_NEWKEYS in contrast to the
12417574SJan.Pechanec@Sun.COM * server processes. Note that in the unprivileged child,
12427574SJan.Pechanec@Sun.COM * set_newkeys() for MODE_IN are set in dispatch function
12437574SJan.Pechanec@Sun.COM * altprivsep_rekey() after SSH2_MSG_NEWKEYS packet is received
12447574SJan.Pechanec@Sun.COM * from the client.
12457574SJan.Pechanec@Sun.COM */
12467574SJan.Pechanec@Sun.COM process_newkeys(MODE_IN);
12477574SJan.Pechanec@Sun.COM }
12487574SJan.Pechanec@Sun.COM
12490Sstevel@tonic-gate #ifdef PACKET_DEBUG
12507574SJan.Pechanec@Sun.COM debug("decrypted input packet [type %d]:\n", type);
12510Sstevel@tonic-gate buffer_dump(&incoming_packet);
12520Sstevel@tonic-gate #endif
12530Sstevel@tonic-gate /* reset for next packet */
12540Sstevel@tonic-gate packet_length = 0;
12550Sstevel@tonic-gate return type;
12560Sstevel@tonic-gate }
12570Sstevel@tonic-gate
12587574SJan.Pechanec@Sun.COM /*
12597574SJan.Pechanec@Sun.COM * This tries to read a packet from the buffer of received data. Note that it
12607574SJan.Pechanec@Sun.COM * doesn't read() anything from the network socket.
12617574SJan.Pechanec@Sun.COM */
12620Sstevel@tonic-gate int
packet_read_poll_seqnr(u_int32_t * seqnr_p)12630Sstevel@tonic-gate packet_read_poll_seqnr(u_int32_t *seqnr_p)
12640Sstevel@tonic-gate {
12650Sstevel@tonic-gate u_int reason, seqnr;
12660Sstevel@tonic-gate u_char type;
12670Sstevel@tonic-gate char *msg;
12680Sstevel@tonic-gate
12690Sstevel@tonic-gate for (;;) {
12700Sstevel@tonic-gate if (compat20) {
12710Sstevel@tonic-gate type = packet_read_poll2(seqnr_p);
12720Sstevel@tonic-gate DBG(debug("received packet type %d", type));
12730Sstevel@tonic-gate switch (type) {
12740Sstevel@tonic-gate case SSH2_MSG_IGNORE:
12750Sstevel@tonic-gate break;
12760Sstevel@tonic-gate case SSH2_MSG_DEBUG:
12770Sstevel@tonic-gate packet_get_char();
12789600SNobutomo.Nakano@Sun.COM msg = packet_get_utf8_string(NULL);
12799600SNobutomo.Nakano@Sun.COM msg = g11n_filter_string(msg);
12800Sstevel@tonic-gate debug("Remote: %.900s", msg);
12810Sstevel@tonic-gate xfree(msg);
12820Sstevel@tonic-gate msg = packet_get_string(NULL);
12830Sstevel@tonic-gate xfree(msg);
12840Sstevel@tonic-gate break;
12850Sstevel@tonic-gate case SSH2_MSG_DISCONNECT:
12860Sstevel@tonic-gate reason = packet_get_int();
12879600SNobutomo.Nakano@Sun.COM msg = packet_get_utf8_string(NULL);
12889600SNobutomo.Nakano@Sun.COM msg = g11n_filter_string(msg);
12890Sstevel@tonic-gate log("Received disconnect from %s: %u: %.400s",
12900Sstevel@tonic-gate get_remote_ipaddr(), reason, msg);
12910Sstevel@tonic-gate xfree(msg);
12920Sstevel@tonic-gate fatal_cleanup();
12930Sstevel@tonic-gate break;
12940Sstevel@tonic-gate case SSH2_MSG_UNIMPLEMENTED:
12950Sstevel@tonic-gate seqnr = packet_get_int();
12960Sstevel@tonic-gate debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
12970Sstevel@tonic-gate seqnr);
12980Sstevel@tonic-gate break;
12990Sstevel@tonic-gate default:
13000Sstevel@tonic-gate return type;
13010Sstevel@tonic-gate break;
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate } else {
13040Sstevel@tonic-gate type = packet_read_poll1();
13050Sstevel@tonic-gate DBG(debug("received packet type %d", type));
13060Sstevel@tonic-gate switch (type) {
13070Sstevel@tonic-gate case SSH_MSG_IGNORE:
13080Sstevel@tonic-gate break;
13090Sstevel@tonic-gate case SSH_MSG_DEBUG:
13100Sstevel@tonic-gate msg = packet_get_string(NULL);
13110Sstevel@tonic-gate debug("Remote: %.900s", msg);
13120Sstevel@tonic-gate xfree(msg);
13130Sstevel@tonic-gate break;
13140Sstevel@tonic-gate case SSH_MSG_DISCONNECT:
13150Sstevel@tonic-gate msg = packet_get_string(NULL);
13160Sstevel@tonic-gate log("Received disconnect from %s: %.400s",
13170Sstevel@tonic-gate get_remote_ipaddr(), msg);
13180Sstevel@tonic-gate fatal_cleanup();
13190Sstevel@tonic-gate xfree(msg);
13200Sstevel@tonic-gate break;
13210Sstevel@tonic-gate default:
13220Sstevel@tonic-gate return type;
13230Sstevel@tonic-gate break;
13240Sstevel@tonic-gate }
13250Sstevel@tonic-gate }
13260Sstevel@tonic-gate }
13270Sstevel@tonic-gate }
13280Sstevel@tonic-gate
13290Sstevel@tonic-gate int
packet_read_poll(void)13300Sstevel@tonic-gate packet_read_poll(void)
13310Sstevel@tonic-gate {
13320Sstevel@tonic-gate return packet_read_poll_seqnr(NULL);
13330Sstevel@tonic-gate }
13340Sstevel@tonic-gate
13350Sstevel@tonic-gate /*
13360Sstevel@tonic-gate * Buffers the given amount of input characters. This is intended to be used
13370Sstevel@tonic-gate * together with packet_read_poll.
13380Sstevel@tonic-gate */
13390Sstevel@tonic-gate
13400Sstevel@tonic-gate void
packet_process_incoming(const char * buf,u_int len)13410Sstevel@tonic-gate packet_process_incoming(const char *buf, u_int len)
13420Sstevel@tonic-gate {
13430Sstevel@tonic-gate buffer_append(&input, buf, len);
13440Sstevel@tonic-gate }
13450Sstevel@tonic-gate
13460Sstevel@tonic-gate /* Returns a character from the packet. */
13470Sstevel@tonic-gate
13480Sstevel@tonic-gate u_int
packet_get_char(void)13490Sstevel@tonic-gate packet_get_char(void)
13500Sstevel@tonic-gate {
13510Sstevel@tonic-gate char ch;
13520Sstevel@tonic-gate
13530Sstevel@tonic-gate buffer_get(&incoming_packet, &ch, 1);
13540Sstevel@tonic-gate return (u_char) ch;
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate
13570Sstevel@tonic-gate /* Returns an integer from the packet data. */
13580Sstevel@tonic-gate
13590Sstevel@tonic-gate u_int
packet_get_int(void)13600Sstevel@tonic-gate packet_get_int(void)
13610Sstevel@tonic-gate {
13620Sstevel@tonic-gate return buffer_get_int(&incoming_packet);
13630Sstevel@tonic-gate }
13640Sstevel@tonic-gate
13650Sstevel@tonic-gate /*
13660Sstevel@tonic-gate * Returns an arbitrary precision integer from the packet data. The integer
13670Sstevel@tonic-gate * must have been initialized before this call.
13680Sstevel@tonic-gate */
13690Sstevel@tonic-gate
13700Sstevel@tonic-gate void
packet_get_bignum(BIGNUM * value)13710Sstevel@tonic-gate packet_get_bignum(BIGNUM * value)
13720Sstevel@tonic-gate {
13730Sstevel@tonic-gate buffer_get_bignum(&incoming_packet, value);
13740Sstevel@tonic-gate }
13750Sstevel@tonic-gate
13760Sstevel@tonic-gate void
packet_get_bignum2(BIGNUM * value)13770Sstevel@tonic-gate packet_get_bignum2(BIGNUM * value)
13780Sstevel@tonic-gate {
13790Sstevel@tonic-gate buffer_get_bignum2(&incoming_packet, value);
13800Sstevel@tonic-gate }
13810Sstevel@tonic-gate
13820Sstevel@tonic-gate void *
packet_get_raw(u_int * length_ptr)13830Sstevel@tonic-gate packet_get_raw(u_int *length_ptr)
13840Sstevel@tonic-gate {
13850Sstevel@tonic-gate u_int bytes = buffer_len(&incoming_packet);
13860Sstevel@tonic-gate
13870Sstevel@tonic-gate if (length_ptr != NULL)
13880Sstevel@tonic-gate *length_ptr = bytes;
13890Sstevel@tonic-gate return buffer_ptr(&incoming_packet);
13900Sstevel@tonic-gate }
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate int
packet_remaining(void)13930Sstevel@tonic-gate packet_remaining(void)
13940Sstevel@tonic-gate {
13950Sstevel@tonic-gate return buffer_len(&incoming_packet);
13960Sstevel@tonic-gate }
13970Sstevel@tonic-gate
13980Sstevel@tonic-gate /*
13990Sstevel@tonic-gate * Returns a string from the packet data. The string is allocated using
14000Sstevel@tonic-gate * xmalloc; it is the responsibility of the calling program to free it when
14010Sstevel@tonic-gate * no longer needed. The length_ptr argument may be NULL, or point to an
14020Sstevel@tonic-gate * integer into which the length of the string is stored.
14030Sstevel@tonic-gate */
14040Sstevel@tonic-gate
14050Sstevel@tonic-gate void *
packet_get_string(u_int * length_ptr)14060Sstevel@tonic-gate packet_get_string(u_int *length_ptr)
14070Sstevel@tonic-gate {
14080Sstevel@tonic-gate return buffer_get_string(&incoming_packet, length_ptr);
14090Sstevel@tonic-gate }
14109600SNobutomo.Nakano@Sun.COM
14110Sstevel@tonic-gate char *
packet_get_utf8_string(uint_t * length_ptr)14129600SNobutomo.Nakano@Sun.COM packet_get_utf8_string(uint_t *length_ptr)
14130Sstevel@tonic-gate {
14149600SNobutomo.Nakano@Sun.COM if (datafellows & SSH_BUG_STRING_ENCODING)
14159600SNobutomo.Nakano@Sun.COM return (buffer_get_string(&incoming_packet, length_ptr));
14169600SNobutomo.Nakano@Sun.COM else
14179600SNobutomo.Nakano@Sun.COM return (buffer_get_utf8_string(&incoming_packet, length_ptr));
14180Sstevel@tonic-gate }
14190Sstevel@tonic-gate
14200Sstevel@tonic-gate /*
14210Sstevel@tonic-gate * Sends a diagnostic message from the server to the client. This message
14220Sstevel@tonic-gate * can be sent at any time (but not while constructing another message). The
14230Sstevel@tonic-gate * message is printed immediately, but only if the client is being executed
14240Sstevel@tonic-gate * in verbose mode. These messages are primarily intended to ease debugging
14250Sstevel@tonic-gate * authentication problems. The length of the formatted message must not
14260Sstevel@tonic-gate * exceed 1024 bytes. This will automatically call packet_write_wait.
14270Sstevel@tonic-gate */
14280Sstevel@tonic-gate
14290Sstevel@tonic-gate void
packet_send_debug(const char * fmt,...)14300Sstevel@tonic-gate packet_send_debug(const char *fmt,...)
14310Sstevel@tonic-gate {
14320Sstevel@tonic-gate char buf[1024];
14330Sstevel@tonic-gate va_list args;
14340Sstevel@tonic-gate
14350Sstevel@tonic-gate if (compat20 && (datafellows & SSH_BUG_DEBUG))
14360Sstevel@tonic-gate return;
14370Sstevel@tonic-gate
14380Sstevel@tonic-gate va_start(args, fmt);
14390Sstevel@tonic-gate vsnprintf(buf, sizeof(buf), gettext(fmt), args);
14400Sstevel@tonic-gate va_end(args);
14410Sstevel@tonic-gate
14420Sstevel@tonic-gate #ifdef ALTPRIVSEP
14430Sstevel@tonic-gate /* shouldn't happen */
14440Sstevel@tonic-gate if (packet_monitor) {
14450Sstevel@tonic-gate debug("packet_send_debug: %s", buf);
14460Sstevel@tonic-gate return;
14470Sstevel@tonic-gate }
14480Sstevel@tonic-gate #endif /* ALTPRIVSEP */
14490Sstevel@tonic-gate
14500Sstevel@tonic-gate if (compat20) {
14510Sstevel@tonic-gate packet_start(SSH2_MSG_DEBUG);
14520Sstevel@tonic-gate packet_put_char(0); /* bool: always display */
14539600SNobutomo.Nakano@Sun.COM packet_put_utf8_cstring(buf);
14540Sstevel@tonic-gate packet_put_cstring("");
14550Sstevel@tonic-gate } else {
14560Sstevel@tonic-gate packet_start(SSH_MSG_DEBUG);
14570Sstevel@tonic-gate packet_put_cstring(buf);
14580Sstevel@tonic-gate }
14590Sstevel@tonic-gate packet_send();
14600Sstevel@tonic-gate packet_write_wait();
14610Sstevel@tonic-gate }
14620Sstevel@tonic-gate
14630Sstevel@tonic-gate /*
14640Sstevel@tonic-gate * Logs the error plus constructs and sends a disconnect packet, closes the
14650Sstevel@tonic-gate * connection, and exits. This function never returns. The error message
14660Sstevel@tonic-gate * should not contain a newline. The length of the formatted message must
14670Sstevel@tonic-gate * not exceed 1024 bytes.
14680Sstevel@tonic-gate */
14690Sstevel@tonic-gate
14700Sstevel@tonic-gate void
packet_disconnect(const char * fmt,...)14710Sstevel@tonic-gate packet_disconnect(const char *fmt,...)
14720Sstevel@tonic-gate {
14730Sstevel@tonic-gate char buf[1024];
14740Sstevel@tonic-gate va_list args;
14750Sstevel@tonic-gate static int disconnecting = 0;
14760Sstevel@tonic-gate
14770Sstevel@tonic-gate if (disconnecting) /* Guard against recursive invocations. */
14780Sstevel@tonic-gate fatal("packet_disconnect called recursively.");
14790Sstevel@tonic-gate disconnecting = 1;
14800Sstevel@tonic-gate
14810Sstevel@tonic-gate /*
14820Sstevel@tonic-gate * Format the message. Note that the caller must make sure the
14830Sstevel@tonic-gate * message is of limited size.
14840Sstevel@tonic-gate */
14850Sstevel@tonic-gate va_start(args, fmt);
14860Sstevel@tonic-gate vsnprintf(buf, sizeof(buf), fmt, args);
14870Sstevel@tonic-gate va_end(args);
14880Sstevel@tonic-gate
14890Sstevel@tonic-gate #ifdef ALTPRIVSEP
14900Sstevel@tonic-gate /*
14910Sstevel@tonic-gate * If we packet_disconnect() in the monitor the fatal cleanups will take
14920Sstevel@tonic-gate * care of the child. See main() in sshd.c. We don't send the packet
14930Sstevel@tonic-gate * disconnect message here because: a) the child might not be looking
14940Sstevel@tonic-gate * for it and b) because we don't really know if the child is compat20
14950Sstevel@tonic-gate * or not as we lost that information when packet_set_monitor() was
14960Sstevel@tonic-gate * called.
14970Sstevel@tonic-gate */
14980Sstevel@tonic-gate if (packet_monitor)
14990Sstevel@tonic-gate goto close_stuff;
15000Sstevel@tonic-gate #endif /* ALTPRIVSEP */
15010Sstevel@tonic-gate
15020Sstevel@tonic-gate /* Send the disconnect message to the other side, and wait for it to get sent. */
15030Sstevel@tonic-gate if (compat20) {
15040Sstevel@tonic-gate packet_start(SSH2_MSG_DISCONNECT);
15050Sstevel@tonic-gate packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR);
15069600SNobutomo.Nakano@Sun.COM packet_put_utf8_cstring(buf);
15070Sstevel@tonic-gate packet_put_cstring("");
15080Sstevel@tonic-gate } else {
15090Sstevel@tonic-gate packet_start(SSH_MSG_DISCONNECT);
15100Sstevel@tonic-gate packet_put_cstring(buf);
15110Sstevel@tonic-gate }
15120Sstevel@tonic-gate packet_send();
15130Sstevel@tonic-gate packet_write_wait();
15140Sstevel@tonic-gate
15150Sstevel@tonic-gate #ifdef ALTPRIVSEP
15160Sstevel@tonic-gate close_stuff:
15170Sstevel@tonic-gate #endif /* ALTPRIVSEP */
15180Sstevel@tonic-gate /* Stop listening for connections. */
15190Sstevel@tonic-gate channel_close_all();
15200Sstevel@tonic-gate
15210Sstevel@tonic-gate /* Close the connection. */
15220Sstevel@tonic-gate packet_close();
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate /* Display the error locally and exit. */
15250Sstevel@tonic-gate log("Disconnecting: %.100s", buf);
15260Sstevel@tonic-gate fatal_cleanup();
15270Sstevel@tonic-gate }
15280Sstevel@tonic-gate
15290Sstevel@tonic-gate /* Checks if there is any buffered output, and tries to write some of the output. */
15300Sstevel@tonic-gate
15310Sstevel@tonic-gate void
packet_write_poll(void)15320Sstevel@tonic-gate packet_write_poll(void)
15330Sstevel@tonic-gate {
15340Sstevel@tonic-gate int len = buffer_len(&output);
15350Sstevel@tonic-gate
15360Sstevel@tonic-gate if (len > 0) {
15370Sstevel@tonic-gate len = write(connection_out, buffer_ptr(&output), len);
15380Sstevel@tonic-gate if (len <= 0) {
15390Sstevel@tonic-gate if (errno == EAGAIN)
15400Sstevel@tonic-gate return;
15410Sstevel@tonic-gate else
15420Sstevel@tonic-gate fatal("Write failed: %.100s", strerror(errno));
15430Sstevel@tonic-gate }
15447574SJan.Pechanec@Sun.COM #ifdef PACKET_DEBUG
15457574SJan.Pechanec@Sun.COM debug("in packet_write_poll, %d bytes just sent to the "
15467574SJan.Pechanec@Sun.COM "remote side", len);
15477574SJan.Pechanec@Sun.COM #endif
15480Sstevel@tonic-gate buffer_consume(&output, len);
15490Sstevel@tonic-gate }
15500Sstevel@tonic-gate }
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate /*
15530Sstevel@tonic-gate * Calls packet_write_poll repeatedly until all pending output data has been
15540Sstevel@tonic-gate * written.
15550Sstevel@tonic-gate */
15560Sstevel@tonic-gate
15570Sstevel@tonic-gate void
packet_write_wait(void)15580Sstevel@tonic-gate packet_write_wait(void)
15590Sstevel@tonic-gate {
15600Sstevel@tonic-gate fd_set *setp;
15610Sstevel@tonic-gate
15620Sstevel@tonic-gate setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) *
15630Sstevel@tonic-gate sizeof(fd_mask));
15640Sstevel@tonic-gate packet_write_poll();
15650Sstevel@tonic-gate while (packet_have_data_to_write()) {
15660Sstevel@tonic-gate memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
15670Sstevel@tonic-gate sizeof(fd_mask));
15680Sstevel@tonic-gate FD_SET(connection_out, setp);
15690Sstevel@tonic-gate while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
15700Sstevel@tonic-gate (errno == EAGAIN || errno == EINTR))
15710Sstevel@tonic-gate ;
15720Sstevel@tonic-gate packet_write_poll();
15730Sstevel@tonic-gate }
15740Sstevel@tonic-gate xfree(setp);
15750Sstevel@tonic-gate }
15760Sstevel@tonic-gate
15770Sstevel@tonic-gate /* Returns true if there is buffered data to write to the connection. */
15780Sstevel@tonic-gate
15790Sstevel@tonic-gate int
packet_have_data_to_write(void)15800Sstevel@tonic-gate packet_have_data_to_write(void)
15810Sstevel@tonic-gate {
15820Sstevel@tonic-gate return buffer_len(&output) != 0;
15830Sstevel@tonic-gate }
15840Sstevel@tonic-gate
15850Sstevel@tonic-gate /* Returns true if there is not too much data to write to the connection. */
15860Sstevel@tonic-gate
15870Sstevel@tonic-gate int
packet_not_very_much_data_to_write(void)15880Sstevel@tonic-gate packet_not_very_much_data_to_write(void)
15890Sstevel@tonic-gate {
15900Sstevel@tonic-gate if (interactive_mode)
15910Sstevel@tonic-gate return buffer_len(&output) < 16384;
15920Sstevel@tonic-gate else
15930Sstevel@tonic-gate return buffer_len(&output) < 128 * 1024;
15940Sstevel@tonic-gate }
15950Sstevel@tonic-gate
15960Sstevel@tonic-gate /* Informs that the current session is interactive. Sets IP flags for that. */
15970Sstevel@tonic-gate
15980Sstevel@tonic-gate void
packet_set_interactive(int interactive)15990Sstevel@tonic-gate packet_set_interactive(int interactive)
16000Sstevel@tonic-gate {
16010Sstevel@tonic-gate static int called = 0;
16020Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
16030Sstevel@tonic-gate int lowdelay = IPTOS_LOWDELAY;
16040Sstevel@tonic-gate int throughput = IPTOS_THROUGHPUT;
16050Sstevel@tonic-gate #endif
16060Sstevel@tonic-gate
16070Sstevel@tonic-gate if (called)
16080Sstevel@tonic-gate return;
16090Sstevel@tonic-gate called = 1;
16100Sstevel@tonic-gate
16110Sstevel@tonic-gate /* Record that we are in interactive mode. */
16120Sstevel@tonic-gate interactive_mode = interactive;
16130Sstevel@tonic-gate
16140Sstevel@tonic-gate /* Only set socket options if using a socket. */
16150Sstevel@tonic-gate if (!packet_connection_is_on_socket())
16160Sstevel@tonic-gate return;
16170Sstevel@tonic-gate /*
16180Sstevel@tonic-gate * IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only
16190Sstevel@tonic-gate */
16200Sstevel@tonic-gate if (interactive) {
16210Sstevel@tonic-gate /*
16220Sstevel@tonic-gate * Set IP options for an interactive connection. Use
16230Sstevel@tonic-gate * IPTOS_LOWDELAY and TCP_NODELAY.
16240Sstevel@tonic-gate */
16250Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
16260Sstevel@tonic-gate if (packet_connection_is_ipv4()) {
16270Sstevel@tonic-gate if (setsockopt(connection_in, IPPROTO_IP, IP_TOS,
16280Sstevel@tonic-gate &lowdelay, sizeof(lowdelay)) < 0)
16290Sstevel@tonic-gate error("setsockopt IPTOS_LOWDELAY: %.100s",
16300Sstevel@tonic-gate strerror(errno));
16310Sstevel@tonic-gate }
16320Sstevel@tonic-gate #endif
16330Sstevel@tonic-gate set_nodelay(connection_in);
16340Sstevel@tonic-gate }
16350Sstevel@tonic-gate #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
16360Sstevel@tonic-gate else if (packet_connection_is_ipv4()) {
16370Sstevel@tonic-gate /*
16380Sstevel@tonic-gate * Set IP options for a non-interactive connection. Use
16390Sstevel@tonic-gate * IPTOS_THROUGHPUT.
16400Sstevel@tonic-gate */
16410Sstevel@tonic-gate if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &throughput,
16420Sstevel@tonic-gate sizeof(throughput)) < 0)
16430Sstevel@tonic-gate error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
16440Sstevel@tonic-gate }
16450Sstevel@tonic-gate #endif
16460Sstevel@tonic-gate }
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate /* Returns true if the current connection is interactive. */
16490Sstevel@tonic-gate
16500Sstevel@tonic-gate int
packet_is_interactive(void)16510Sstevel@tonic-gate packet_is_interactive(void)
16520Sstevel@tonic-gate {
16530Sstevel@tonic-gate return interactive_mode;
16540Sstevel@tonic-gate }
16550Sstevel@tonic-gate
16560Sstevel@tonic-gate int
packet_set_maxsize(int s)16570Sstevel@tonic-gate packet_set_maxsize(int s)
16580Sstevel@tonic-gate {
16590Sstevel@tonic-gate static int called = 0;
16600Sstevel@tonic-gate
16610Sstevel@tonic-gate if (called) {
16620Sstevel@tonic-gate log("packet_set_maxsize: called twice: old %d new %d",
16630Sstevel@tonic-gate max_packet_size, s);
16640Sstevel@tonic-gate return -1;
16650Sstevel@tonic-gate }
16660Sstevel@tonic-gate if (s < 4 * 1024 || s > 1024 * 1024) {
16670Sstevel@tonic-gate log("packet_set_maxsize: bad size %d", s);
16680Sstevel@tonic-gate return -1;
16690Sstevel@tonic-gate }
16700Sstevel@tonic-gate called = 1;
16710Sstevel@tonic-gate debug("packet_set_maxsize: setting to %d", s);
16720Sstevel@tonic-gate max_packet_size = s;
16730Sstevel@tonic-gate return s;
16740Sstevel@tonic-gate }
16750Sstevel@tonic-gate
16760Sstevel@tonic-gate /* roundup current message to pad bytes */
16770Sstevel@tonic-gate void
packet_add_padding(u_char pad)16780Sstevel@tonic-gate packet_add_padding(u_char pad)
16790Sstevel@tonic-gate {
16800Sstevel@tonic-gate extra_pad = pad;
16810Sstevel@tonic-gate }
16820Sstevel@tonic-gate
16830Sstevel@tonic-gate /*
16840Sstevel@tonic-gate * 9.2. Ignored Data Message
16850Sstevel@tonic-gate *
16860Sstevel@tonic-gate * byte SSH_MSG_IGNORE
16870Sstevel@tonic-gate * string data
16880Sstevel@tonic-gate *
16890Sstevel@tonic-gate * All implementations MUST understand (and ignore) this message at any
16900Sstevel@tonic-gate * time (after receiving the protocol version). No implementation is
16910Sstevel@tonic-gate * required to send them. This message can be used as an additional
16920Sstevel@tonic-gate * protection measure against advanced traffic analysis techniques.
16930Sstevel@tonic-gate */
16940Sstevel@tonic-gate void
packet_send_ignore(int nbytes)16950Sstevel@tonic-gate packet_send_ignore(int nbytes)
16960Sstevel@tonic-gate {
16975562Sjp161948 u_int32_t rnd = 0;
16980Sstevel@tonic-gate int i;
16990Sstevel@tonic-gate
17000Sstevel@tonic-gate #ifdef ALTPRIVSEP
17010Sstevel@tonic-gate /* shouldn't happen -- see packet_set_monitor() */
17020Sstevel@tonic-gate if (packet_monitor)
17030Sstevel@tonic-gate return;
17040Sstevel@tonic-gate #endif /* ALTPRIVSEP */
17050Sstevel@tonic-gate
17060Sstevel@tonic-gate packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE);
17070Sstevel@tonic-gate packet_put_int(nbytes);
17080Sstevel@tonic-gate for (i = 0; i < nbytes; i++) {
17090Sstevel@tonic-gate if (i % 4 == 0)
17105562Sjp161948 rnd = arc4random();
17115562Sjp161948 packet_put_char((u_char)rnd & 0xff);
17125562Sjp161948 rnd >>= 8;
17130Sstevel@tonic-gate }
17140Sstevel@tonic-gate }
17150Sstevel@tonic-gate
17165562Sjp161948 #define MAX_PACKETS (1U<<31)
17175562Sjp161948 int
packet_need_rekeying(void)17185562Sjp161948 packet_need_rekeying(void)
17195562Sjp161948 {
17205562Sjp161948 if (datafellows & SSH_BUG_NOREKEY)
17215562Sjp161948 return 0;
17225562Sjp161948 return
17235562Sjp161948 (p_send.packets > MAX_PACKETS) ||
17245562Sjp161948 (p_read.packets > MAX_PACKETS) ||
17255562Sjp161948 (max_blocks_out && (p_send.blocks > max_blocks_out)) ||
17265562Sjp161948 (max_blocks_in && (p_read.blocks > max_blocks_in));
17275562Sjp161948 }
17285562Sjp161948
17295562Sjp161948 void
packet_set_rekey_limit(u_int32_t bytes)17305562Sjp161948 packet_set_rekey_limit(u_int32_t bytes)
17315562Sjp161948 {
17325562Sjp161948 rekey_limit = bytes;
17335562Sjp161948 }
17345562Sjp161948
17350Sstevel@tonic-gate #ifdef ALTPRIVSEP
17360Sstevel@tonic-gate void
packet_set_server(void)17370Sstevel@tonic-gate packet_set_server(void)
17380Sstevel@tonic-gate {
17390Sstevel@tonic-gate packet_server = 1;
17400Sstevel@tonic-gate }
17410Sstevel@tonic-gate
17420Sstevel@tonic-gate int
packet_is_server(void)17430Sstevel@tonic-gate packet_is_server(void)
17440Sstevel@tonic-gate {
17450Sstevel@tonic-gate return (packet_server);
17460Sstevel@tonic-gate }
17470Sstevel@tonic-gate
17480Sstevel@tonic-gate void
packet_set_monitor(int pipe)17490Sstevel@tonic-gate packet_set_monitor(int pipe)
17500Sstevel@tonic-gate {
17510Sstevel@tonic-gate int dup_fd;
17520Sstevel@tonic-gate
17530Sstevel@tonic-gate packet_server = 1;
17540Sstevel@tonic-gate packet_monitor = 1;
17550Sstevel@tonic-gate
17560Sstevel@tonic-gate /*
17570Sstevel@tonic-gate * Awful hack follows.
17580Sstevel@tonic-gate *
17590Sstevel@tonic-gate * For SSHv1 the monitor does not process any SSHv1 packets, only
17600Sstevel@tonic-gate * ALTPRIVSEP packets. We take advantage of that here to keep changes
17610Sstevel@tonic-gate * to packet.c to a minimum by using the SSHv2 binary packet protocol,
17620Sstevel@tonic-gate * with cipher "none," mac "none" and compression alg "none," as the
17630Sstevel@tonic-gate * basis for the monitor protocol. And so to force packet.c to treat
17640Sstevel@tonic-gate * packets as SSHv2 we force compat20 == 1 here.
17650Sstevel@tonic-gate *
17660Sstevel@tonic-gate * For completeness and to help future developers catch this we also
17670Sstevel@tonic-gate * force compat20 == 1 in the monitor loop, in serverloop.c.
17680Sstevel@tonic-gate */
17690Sstevel@tonic-gate compat20 = 1;
17700Sstevel@tonic-gate
17710Sstevel@tonic-gate /*
17720Sstevel@tonic-gate * NOTE: Assumptions below!
17730Sstevel@tonic-gate *
17740Sstevel@tonic-gate * - lots of packet.c code assumes that (connection_in ==
17750Sstevel@tonic-gate * connection_out) -> connection is socket
17760Sstevel@tonic-gate *
17770Sstevel@tonic-gate * - packet_close() does not shutdown() the connection fildes
17780Sstevel@tonic-gate * if connection_in != connection_out
17790Sstevel@tonic-gate *
17800Sstevel@tonic-gate * - other code assumes the connection is a socket if
17810Sstevel@tonic-gate * connection_in == connection_out
17820Sstevel@tonic-gate */
17830Sstevel@tonic-gate
17840Sstevel@tonic-gate if ((dup_fd = dup(pipe)) < 0)
17850Sstevel@tonic-gate fatal("Monitor failed to start: %s", strerror(errno));
17860Sstevel@tonic-gate
17870Sstevel@tonic-gate /*
17880Sstevel@tonic-gate * make sure that the monitor's child's socket is not shutdown(3SOCKET)
17897574SJan.Pechanec@Sun.COM * when we packet_close(). Setting connection_out to -1 will take care
17907574SJan.Pechanec@Sun.COM * of that.
17910Sstevel@tonic-gate */
17920Sstevel@tonic-gate if (packet_connection_is_on_socket())
17930Sstevel@tonic-gate connection_out = -1;
17940Sstevel@tonic-gate
17957574SJan.Pechanec@Sun.COM /*
17967574SJan.Pechanec@Sun.COM * Now clean up the state related to the server socket. As a side
17977574SJan.Pechanec@Sun.COM * effect, we also clean up existing cipher contexts that were
17987574SJan.Pechanec@Sun.COM * initialized with 'none' cipher in packet_set_connection(). That
17997574SJan.Pechanec@Sun.COM * function was called in the child server process shortly after the
18007574SJan.Pechanec@Sun.COM * master SSH process forked. However, all of that is reinialized again
18017574SJan.Pechanec@Sun.COM * by another packet_set_connection() call right below.
18027574SJan.Pechanec@Sun.COM */
18030Sstevel@tonic-gate packet_close();
18040Sstevel@tonic-gate
18057574SJan.Pechanec@Sun.COM /*
18067574SJan.Pechanec@Sun.COM * Now make the monitor pipe look like the ssh connection which means
18077574SJan.Pechanec@Sun.COM * that connection_in and connection_out will be set to the
18087574SJan.Pechanec@Sun.COM * communication pipe descriptors.
18097574SJan.Pechanec@Sun.COM */
18100Sstevel@tonic-gate packet_set_connection(pipe, dup_fd);
18110Sstevel@tonic-gate }
18120Sstevel@tonic-gate
18137574SJan.Pechanec@Sun.COM /*
18147574SJan.Pechanec@Sun.COM * We temporarily need to set connection_in and connection_out descriptors so
18157574SJan.Pechanec@Sun.COM * that we can make use of existing code that gets the IP address and hostname
18167574SJan.Pechanec@Sun.COM * of the peer to write a login/logout record. It's not nice but we would have
18177574SJan.Pechanec@Sun.COM * to change more code when implementing the PKCS#11 engine support.
18187574SJan.Pechanec@Sun.COM */
18197574SJan.Pechanec@Sun.COM void
packet_set_fds(int fd,int restore)18207574SJan.Pechanec@Sun.COM packet_set_fds(int fd, int restore)
18217574SJan.Pechanec@Sun.COM {
18227574SJan.Pechanec@Sun.COM static int stored_fd;
18237574SJan.Pechanec@Sun.COM
18247574SJan.Pechanec@Sun.COM if (stored_fd == 0 && restore == 0) {
18257574SJan.Pechanec@Sun.COM debug3("packet_set_fds: saving %d, installing %d",
18267574SJan.Pechanec@Sun.COM connection_in, fd);
18277574SJan.Pechanec@Sun.COM stored_fd = connection_in;
18287574SJan.Pechanec@Sun.COM /* we don't have a socket in inetd mode */
18297574SJan.Pechanec@Sun.COM if (fd != -1)
18307574SJan.Pechanec@Sun.COM connection_in = connection_out = fd;
18317574SJan.Pechanec@Sun.COM return;
18327574SJan.Pechanec@Sun.COM }
18337574SJan.Pechanec@Sun.COM
18347574SJan.Pechanec@Sun.COM if (restore == 1) {
18357574SJan.Pechanec@Sun.COM debug3("restoring %d to connection_in/out", stored_fd);
18367574SJan.Pechanec@Sun.COM connection_in = connection_out = stored_fd;
18377574SJan.Pechanec@Sun.COM }
18387574SJan.Pechanec@Sun.COM }
18397574SJan.Pechanec@Sun.COM
18400Sstevel@tonic-gate int
packet_is_monitor(void)18410Sstevel@tonic-gate packet_is_monitor(void)
18420Sstevel@tonic-gate {
18430Sstevel@tonic-gate return (packet_monitor);
18440Sstevel@tonic-gate }
18450Sstevel@tonic-gate #endif /* ALTPRIVSEP */
1846