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