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 functions for generic socket connection forwarding. 60Sstevel@tonic-gate * There is also code for initiating connection forwarding for X11 connections, 70Sstevel@tonic-gate * arbitrary tcp/ip connections, and the authentication agent connection. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * As far as I am concerned, the code I have written for this software 100Sstevel@tonic-gate * can be used freely for any purpose. Any derived versions of this 110Sstevel@tonic-gate * software must be clearly marked as such, and if the derived work is 120Sstevel@tonic-gate * incompatible with the protocol description in the RFC file, it must be 130Sstevel@tonic-gate * called by a name other than "ssh" or "Secure Shell". 140Sstevel@tonic-gate * 150Sstevel@tonic-gate * SSH2 support added by Markus Friedl. 160Sstevel@tonic-gate * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. 170Sstevel@tonic-gate * Copyright (c) 1999 Dug Song. All rights reserved. 180Sstevel@tonic-gate * Copyright (c) 1999 Theo de Raadt. All rights reserved. 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 210Sstevel@tonic-gate * modification, are permitted provided that the following conditions 220Sstevel@tonic-gate * are met: 230Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 240Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 250Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 260Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 270Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 280Sstevel@tonic-gate * 290Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 300Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 310Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 320Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 330Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 340Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 350Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 360Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 370Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 380Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 390Sstevel@tonic-gate */ 40*5334Sjp161948 /* 41*5334Sjp161948 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 42*5334Sjp161948 * Use is subject to license terms. 43*5334Sjp161948 */ 440Sstevel@tonic-gate 450Sstevel@tonic-gate #include "includes.h" 460Sstevel@tonic-gate RCSID("$OpenBSD: channels.c,v 1.183 2002/09/17 07:47:02 itojun Exp $"); 470Sstevel@tonic-gate 480Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 490Sstevel@tonic-gate 500Sstevel@tonic-gate #include "ssh.h" 510Sstevel@tonic-gate #include "ssh1.h" 520Sstevel@tonic-gate #include "ssh2.h" 530Sstevel@tonic-gate #include "packet.h" 540Sstevel@tonic-gate #include "xmalloc.h" 550Sstevel@tonic-gate #include "log.h" 560Sstevel@tonic-gate #include "misc.h" 570Sstevel@tonic-gate #include "channels.h" 580Sstevel@tonic-gate #include "compat.h" 590Sstevel@tonic-gate #include "canohost.h" 600Sstevel@tonic-gate #include "key.h" 610Sstevel@tonic-gate #include "authfd.h" 620Sstevel@tonic-gate #include "pathnames.h" 634764Sjp161948 #include "bufaux.h" 640Sstevel@tonic-gate 650Sstevel@tonic-gate 660Sstevel@tonic-gate /* -- channel core */ 670Sstevel@tonic-gate 680Sstevel@tonic-gate /* 690Sstevel@tonic-gate * Pointer to an array containing all allocated channels. The array is 700Sstevel@tonic-gate * dynamically extended as needed. 710Sstevel@tonic-gate */ 720Sstevel@tonic-gate static Channel **channels = NULL; 730Sstevel@tonic-gate 740Sstevel@tonic-gate /* 750Sstevel@tonic-gate * Size of the channel array. All slots of the array must always be 760Sstevel@tonic-gate * initialized (at least the type field); unused slots set to NULL 770Sstevel@tonic-gate */ 780Sstevel@tonic-gate static int channels_alloc = 0; 790Sstevel@tonic-gate 800Sstevel@tonic-gate /* 810Sstevel@tonic-gate * Maximum file descriptor value used in any of the channels. This is 820Sstevel@tonic-gate * updated in channel_new. 830Sstevel@tonic-gate */ 840Sstevel@tonic-gate static int channel_max_fd = 0; 850Sstevel@tonic-gate 860Sstevel@tonic-gate 870Sstevel@tonic-gate /* -- tcp forwarding */ 880Sstevel@tonic-gate 890Sstevel@tonic-gate /* 900Sstevel@tonic-gate * Data structure for storing which hosts are permitted for forward requests. 910Sstevel@tonic-gate * The local sides of any remote forwards are stored in this array to prevent 920Sstevel@tonic-gate * a corrupt remote server from accessing arbitrary TCP/IP ports on our local 930Sstevel@tonic-gate * network (which might be behind a firewall). 940Sstevel@tonic-gate */ 950Sstevel@tonic-gate typedef struct { 960Sstevel@tonic-gate char *host_to_connect; /* Connect to 'host'. */ 970Sstevel@tonic-gate u_short port_to_connect; /* Connect to 'port'. */ 980Sstevel@tonic-gate u_short listen_port; /* Remote side should listen port number. */ 990Sstevel@tonic-gate } ForwardPermission; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate /* List of all permitted host/port pairs to connect. */ 1020Sstevel@tonic-gate static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate /* Number of permitted host/port pairs in the array. */ 1050Sstevel@tonic-gate static int num_permitted_opens = 0; 1060Sstevel@tonic-gate /* 1070Sstevel@tonic-gate * If this is true, all opens are permitted. This is the case on the server 1080Sstevel@tonic-gate * on which we have to trust the client anyway, and the user could do 1090Sstevel@tonic-gate * anything after logging in anyway. 1100Sstevel@tonic-gate */ 1110Sstevel@tonic-gate static int all_opens_permitted = 0; 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate /* -- X11 forwarding */ 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate /* Maximum number of fake X11 displays to try. */ 1170Sstevel@tonic-gate #define MAX_DISPLAYS 1000 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* Saved X11 authentication protocol name. */ 1200Sstevel@tonic-gate static char *x11_saved_proto = NULL; 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate /* Saved X11 authentication data. This is the real data. */ 1230Sstevel@tonic-gate static char *x11_saved_data = NULL; 1240Sstevel@tonic-gate static u_int x11_saved_data_len = 0; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate /* 1270Sstevel@tonic-gate * Fake X11 authentication data. This is what the server will be sending us; 1280Sstevel@tonic-gate * we should replace any occurrences of this by the real data. 1290Sstevel@tonic-gate */ 1304907Sjp161948 static u_char *x11_fake_data = NULL; 1310Sstevel@tonic-gate static u_int x11_fake_data_len; 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate /* -- agent forwarding */ 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate #define NUM_SOCKS 10 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /* AF_UNSPEC or AF_INET or AF_INET6 */ 1390Sstevel@tonic-gate static int IPv4or6 = AF_UNSPEC; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate /* helper */ 1420Sstevel@tonic-gate static void port_open_helper(Channel *c, char *rtype); 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate /* -- channel core */ 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate Channel * 1470Sstevel@tonic-gate channel_lookup(int id) 1480Sstevel@tonic-gate { 1490Sstevel@tonic-gate Channel *c; 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate if (id < 0 || id >= channels_alloc) { 1520Sstevel@tonic-gate log("channel_lookup: %d: bad id", id); 1530Sstevel@tonic-gate return NULL; 1540Sstevel@tonic-gate } 1550Sstevel@tonic-gate c = channels[id]; 1560Sstevel@tonic-gate if (c == NULL) { 1570Sstevel@tonic-gate log("channel_lookup: %d: bad id: channel free", id); 1580Sstevel@tonic-gate return NULL; 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate return c; 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate /* 1640Sstevel@tonic-gate * Register filedescriptors for a channel, used when allocating a channel or 1650Sstevel@tonic-gate * when the channel consumer/producer is ready, e.g. shell exec'd 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate static void 1690Sstevel@tonic-gate channel_register_fds(Channel *c, int rfd, int wfd, int efd, 1700Sstevel@tonic-gate int extusage, int nonblock) 1710Sstevel@tonic-gate { 1720Sstevel@tonic-gate /* Update the maximum file descriptor value. */ 1730Sstevel@tonic-gate channel_max_fd = MAX(channel_max_fd, rfd); 1740Sstevel@tonic-gate channel_max_fd = MAX(channel_max_fd, wfd); 1750Sstevel@tonic-gate channel_max_fd = MAX(channel_max_fd, efd); 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate /* XXX set close-on-exec -markus */ 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate c->rfd = rfd; 1800Sstevel@tonic-gate c->wfd = wfd; 1810Sstevel@tonic-gate c->sock = (rfd == wfd) ? rfd : -1; 1820Sstevel@tonic-gate c->efd = efd; 1830Sstevel@tonic-gate c->extended_usage = extusage; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /* XXX ugly hack: nonblock is only set by the server */ 1860Sstevel@tonic-gate if (nonblock && isatty(c->rfd)) { 1870Sstevel@tonic-gate debug("channel %d: rfd %d isatty", c->self, c->rfd); 1880Sstevel@tonic-gate c->isatty = 1; 1890Sstevel@tonic-gate if (!isatty(c->wfd)) { 1900Sstevel@tonic-gate error("channel %d: wfd %d is not a tty?", 1910Sstevel@tonic-gate c->self, c->wfd); 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate } else { 1940Sstevel@tonic-gate c->isatty = 0; 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate c->wfd_isatty = isatty(c->wfd); 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate /* enable nonblocking mode */ 1990Sstevel@tonic-gate if (nonblock) { 2000Sstevel@tonic-gate if (rfd != -1) 2010Sstevel@tonic-gate set_nonblock(rfd); 2020Sstevel@tonic-gate if (wfd != -1) 2030Sstevel@tonic-gate set_nonblock(wfd); 2040Sstevel@tonic-gate if (efd != -1) 2050Sstevel@tonic-gate set_nonblock(efd); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate /* 2100Sstevel@tonic-gate * Allocate a new channel object and set its type and socket. This will cause 2110Sstevel@tonic-gate * remote_name to be freed. 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate Channel * 2150Sstevel@tonic-gate channel_new(char *ctype, int type, int rfd, int wfd, int efd, 2160Sstevel@tonic-gate u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) 2170Sstevel@tonic-gate { 2180Sstevel@tonic-gate int i, found; 2190Sstevel@tonic-gate Channel *c; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate /* Do initial allocation if this is the first call. */ 2220Sstevel@tonic-gate if (channels_alloc == 0) { 2230Sstevel@tonic-gate channels_alloc = 10; 2240Sstevel@tonic-gate channels = xmalloc(channels_alloc * sizeof(Channel *)); 2250Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) 2260Sstevel@tonic-gate channels[i] = NULL; 2270Sstevel@tonic-gate fatal_add_cleanup((void (*) (void *)) channel_free_all, NULL); 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate /* Try to find a free slot where to put the new channel. */ 2300Sstevel@tonic-gate for (found = -1, i = 0; i < channels_alloc; i++) 2310Sstevel@tonic-gate if (channels[i] == NULL) { 2320Sstevel@tonic-gate /* Found a free slot. */ 2330Sstevel@tonic-gate found = i; 2340Sstevel@tonic-gate break; 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate if (found == -1) { 2370Sstevel@tonic-gate /* There are no free slots. Take last+1 slot and expand the array. */ 2380Sstevel@tonic-gate found = channels_alloc; 2390Sstevel@tonic-gate if (channels_alloc > 10000) 2400Sstevel@tonic-gate fatal("channel_new: internal error: channels_alloc %d " 2410Sstevel@tonic-gate "too big.", channels_alloc); 2420Sstevel@tonic-gate channels = xrealloc(channels, 2430Sstevel@tonic-gate (channels_alloc + 10) * sizeof(Channel *)); 2440Sstevel@tonic-gate channels_alloc += 10; 2450Sstevel@tonic-gate debug2("channel: expanding %d", channels_alloc); 2460Sstevel@tonic-gate for (i = found; i < channels_alloc; i++) 2470Sstevel@tonic-gate channels[i] = NULL; 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate /* Initialize and return new channel. */ 2500Sstevel@tonic-gate c = channels[found] = xmalloc(sizeof(Channel)); 2510Sstevel@tonic-gate memset(c, 0, sizeof(Channel)); 2520Sstevel@tonic-gate buffer_init(&c->input); 2530Sstevel@tonic-gate buffer_init(&c->output); 2540Sstevel@tonic-gate buffer_init(&c->extended); 2550Sstevel@tonic-gate c->ostate = CHAN_OUTPUT_OPEN; 2560Sstevel@tonic-gate c->istate = CHAN_INPUT_OPEN; 2570Sstevel@tonic-gate c->flags = 0; 2580Sstevel@tonic-gate channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); 2590Sstevel@tonic-gate c->self = found; 2600Sstevel@tonic-gate c->type = type; 2610Sstevel@tonic-gate c->ctype = ctype; 2620Sstevel@tonic-gate c->local_window = window; 2630Sstevel@tonic-gate c->local_window_max = window; 2640Sstevel@tonic-gate c->local_consumed = 0; 2650Sstevel@tonic-gate c->local_maxpacket = maxpack; 2660Sstevel@tonic-gate c->remote_id = -1; 2670Sstevel@tonic-gate c->remote_name = remote_name; 2680Sstevel@tonic-gate c->remote_window = 0; 2690Sstevel@tonic-gate c->remote_maxpacket = 0; 2700Sstevel@tonic-gate c->force_drain = 0; 2710Sstevel@tonic-gate c->single_connection = 0; 2720Sstevel@tonic-gate c->detach_user = NULL; 2730Sstevel@tonic-gate c->confirm = NULL; 2740Sstevel@tonic-gate c->input_filter = NULL; 2750Sstevel@tonic-gate debug("channel %d: new [%s]", found, remote_name); 2760Sstevel@tonic-gate return c; 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate static int 2800Sstevel@tonic-gate channel_find_maxfd(void) 2810Sstevel@tonic-gate { 2820Sstevel@tonic-gate int i, max = 0; 2830Sstevel@tonic-gate Channel *c; 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 2860Sstevel@tonic-gate c = channels[i]; 2870Sstevel@tonic-gate if (c != NULL) { 2880Sstevel@tonic-gate max = MAX(max, c->rfd); 2890Sstevel@tonic-gate max = MAX(max, c->wfd); 2900Sstevel@tonic-gate max = MAX(max, c->efd); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate return max; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate int 2970Sstevel@tonic-gate channel_close_fd(int *fdp) 2980Sstevel@tonic-gate { 2990Sstevel@tonic-gate int ret = 0, fd = *fdp; 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate if (fd != -1) { 3020Sstevel@tonic-gate ret = close(fd); 3030Sstevel@tonic-gate *fdp = -1; 3040Sstevel@tonic-gate if (fd == channel_max_fd) 3050Sstevel@tonic-gate channel_max_fd = channel_find_maxfd(); 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate return ret; 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate /* Close all channel fd/socket. */ 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate static void 3130Sstevel@tonic-gate channel_close_fds(Channel *c) 3140Sstevel@tonic-gate { 3150Sstevel@tonic-gate debug3("channel_close_fds: channel %d: r %d w %d e %d", 3160Sstevel@tonic-gate c->self, c->rfd, c->wfd, c->efd); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate channel_close_fd(&c->sock); 3190Sstevel@tonic-gate channel_close_fd(&c->rfd); 3200Sstevel@tonic-gate channel_close_fd(&c->wfd); 3210Sstevel@tonic-gate channel_close_fd(&c->efd); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate /* Free the channel and close its fd/socket. */ 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate void 3270Sstevel@tonic-gate channel_free(Channel *c) 3280Sstevel@tonic-gate { 3290Sstevel@tonic-gate char *s; 3300Sstevel@tonic-gate int i, n; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate for (n = 0, i = 0; i < channels_alloc; i++) 3330Sstevel@tonic-gate if (channels[i]) 3340Sstevel@tonic-gate n++; 3350Sstevel@tonic-gate debug("channel_free: channel %d: %s, nchannels %d", c->self, 3360Sstevel@tonic-gate c->remote_name ? c->remote_name : "???", n); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate s = channel_open_message(); 3390Sstevel@tonic-gate debug3("channel_free: status: %s", s); 3400Sstevel@tonic-gate xfree(s); 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate if (c->sock != -1) 3430Sstevel@tonic-gate shutdown(c->sock, SHUT_RDWR); 3440Sstevel@tonic-gate channel_close_fds(c); 3450Sstevel@tonic-gate buffer_free(&c->input); 3460Sstevel@tonic-gate buffer_free(&c->output); 3470Sstevel@tonic-gate buffer_free(&c->extended); 3480Sstevel@tonic-gate if (c->remote_name) { 3490Sstevel@tonic-gate xfree(c->remote_name); 3500Sstevel@tonic-gate c->remote_name = NULL; 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate channels[c->self] = NULL; 3530Sstevel@tonic-gate xfree(c); 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate void 3570Sstevel@tonic-gate channel_free_all(void) 3580Sstevel@tonic-gate { 3590Sstevel@tonic-gate int i; 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) 3620Sstevel@tonic-gate if (channels[i] != NULL) 3630Sstevel@tonic-gate channel_free(channels[i]); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate /* 3670Sstevel@tonic-gate * Closes the sockets/fds of all channels. This is used to close extra file 3680Sstevel@tonic-gate * descriptors after a fork. 3690Sstevel@tonic-gate */ 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate void 3720Sstevel@tonic-gate channel_close_all(void) 3730Sstevel@tonic-gate { 3740Sstevel@tonic-gate int i; 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) 3770Sstevel@tonic-gate if (channels[i] != NULL) 3780Sstevel@tonic-gate channel_close_fds(channels[i]); 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate /* 3820Sstevel@tonic-gate * Stop listening to channels. 3830Sstevel@tonic-gate */ 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate void 3860Sstevel@tonic-gate channel_stop_listening(void) 3870Sstevel@tonic-gate { 3880Sstevel@tonic-gate int i; 3890Sstevel@tonic-gate Channel *c; 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 3920Sstevel@tonic-gate c = channels[i]; 3930Sstevel@tonic-gate if (c != NULL) { 3940Sstevel@tonic-gate switch (c->type) { 3950Sstevel@tonic-gate case SSH_CHANNEL_AUTH_SOCKET: 3960Sstevel@tonic-gate case SSH_CHANNEL_PORT_LISTENER: 3970Sstevel@tonic-gate case SSH_CHANNEL_RPORT_LISTENER: 3980Sstevel@tonic-gate case SSH_CHANNEL_X11_LISTENER: 3990Sstevel@tonic-gate channel_close_fd(&c->sock); 4000Sstevel@tonic-gate channel_free(c); 4010Sstevel@tonic-gate break; 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate } 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate /* 4080Sstevel@tonic-gate * Returns true if no channel has too much buffered data, and false if one or 4090Sstevel@tonic-gate * more channel is overfull. 4100Sstevel@tonic-gate */ 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate int 4130Sstevel@tonic-gate channel_not_very_much_buffered_data(void) 4140Sstevel@tonic-gate { 4150Sstevel@tonic-gate u_int i; 4160Sstevel@tonic-gate Channel *c; 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 4190Sstevel@tonic-gate c = channels[i]; 4200Sstevel@tonic-gate if (c != NULL && c->type == SSH_CHANNEL_OPEN) { 4210Sstevel@tonic-gate #if 0 4220Sstevel@tonic-gate if (!compat20 && 4230Sstevel@tonic-gate buffer_len(&c->input) > packet_get_maxsize()) { 4240Sstevel@tonic-gate debug("channel %d: big input buffer %d", 4250Sstevel@tonic-gate c->self, buffer_len(&c->input)); 4260Sstevel@tonic-gate return 0; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate #endif 4290Sstevel@tonic-gate if (buffer_len(&c->output) > packet_get_maxsize()) { 4300Sstevel@tonic-gate debug("channel %d: big output buffer %d > %d", 4310Sstevel@tonic-gate c->self, buffer_len(&c->output), 4320Sstevel@tonic-gate packet_get_maxsize()); 4330Sstevel@tonic-gate return 0; 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate } 4370Sstevel@tonic-gate return 1; 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate /* Returns true if any channel is still open. */ 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate int 4430Sstevel@tonic-gate channel_still_open(void) 4440Sstevel@tonic-gate { 4450Sstevel@tonic-gate int i; 4460Sstevel@tonic-gate Channel *c; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 4490Sstevel@tonic-gate c = channels[i]; 4500Sstevel@tonic-gate if (c == NULL) 4510Sstevel@tonic-gate continue; 4520Sstevel@tonic-gate switch (c->type) { 4530Sstevel@tonic-gate case SSH_CHANNEL_X11_LISTENER: 4540Sstevel@tonic-gate case SSH_CHANNEL_PORT_LISTENER: 4550Sstevel@tonic-gate case SSH_CHANNEL_RPORT_LISTENER: 4560Sstevel@tonic-gate case SSH_CHANNEL_CLOSED: 4570Sstevel@tonic-gate case SSH_CHANNEL_AUTH_SOCKET: 4580Sstevel@tonic-gate case SSH_CHANNEL_DYNAMIC: 4590Sstevel@tonic-gate case SSH_CHANNEL_CONNECTING: 4600Sstevel@tonic-gate case SSH_CHANNEL_ZOMBIE: 4610Sstevel@tonic-gate continue; 4620Sstevel@tonic-gate case SSH_CHANNEL_LARVAL: 4630Sstevel@tonic-gate if (!compat20) 4640Sstevel@tonic-gate fatal("cannot happen: SSH_CHANNEL_LARVAL"); 4650Sstevel@tonic-gate continue; 4660Sstevel@tonic-gate case SSH_CHANNEL_OPENING: 4670Sstevel@tonic-gate case SSH_CHANNEL_OPEN: 4680Sstevel@tonic-gate case SSH_CHANNEL_X11_OPEN: 4690Sstevel@tonic-gate return 1; 4700Sstevel@tonic-gate case SSH_CHANNEL_INPUT_DRAINING: 4710Sstevel@tonic-gate case SSH_CHANNEL_OUTPUT_DRAINING: 4720Sstevel@tonic-gate if (!compat13) 4730Sstevel@tonic-gate fatal("cannot happen: OUT_DRAIN"); 4740Sstevel@tonic-gate return 1; 4750Sstevel@tonic-gate default: 4760Sstevel@tonic-gate fatal("channel_still_open: bad channel type %d", c->type); 4770Sstevel@tonic-gate /* NOTREACHED */ 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate return 0; 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate /* Returns the id of an open channel suitable for keepaliving */ 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate int 4860Sstevel@tonic-gate channel_find_open(void) 4870Sstevel@tonic-gate { 4880Sstevel@tonic-gate int i; 4890Sstevel@tonic-gate Channel *c; 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 4920Sstevel@tonic-gate c = channels[i]; 4930Sstevel@tonic-gate if (c == NULL) 4940Sstevel@tonic-gate continue; 4950Sstevel@tonic-gate switch (c->type) { 4960Sstevel@tonic-gate case SSH_CHANNEL_CLOSED: 4970Sstevel@tonic-gate case SSH_CHANNEL_DYNAMIC: 4980Sstevel@tonic-gate case SSH_CHANNEL_X11_LISTENER: 4990Sstevel@tonic-gate case SSH_CHANNEL_PORT_LISTENER: 5000Sstevel@tonic-gate case SSH_CHANNEL_RPORT_LISTENER: 5010Sstevel@tonic-gate case SSH_CHANNEL_OPENING: 5020Sstevel@tonic-gate case SSH_CHANNEL_CONNECTING: 5030Sstevel@tonic-gate case SSH_CHANNEL_ZOMBIE: 5040Sstevel@tonic-gate continue; 5050Sstevel@tonic-gate case SSH_CHANNEL_LARVAL: 5060Sstevel@tonic-gate case SSH_CHANNEL_AUTH_SOCKET: 5070Sstevel@tonic-gate case SSH_CHANNEL_OPEN: 5080Sstevel@tonic-gate case SSH_CHANNEL_X11_OPEN: 5090Sstevel@tonic-gate return i; 5100Sstevel@tonic-gate case SSH_CHANNEL_INPUT_DRAINING: 5110Sstevel@tonic-gate case SSH_CHANNEL_OUTPUT_DRAINING: 5120Sstevel@tonic-gate if (!compat13) 5130Sstevel@tonic-gate fatal("cannot happen: OUT_DRAIN"); 5140Sstevel@tonic-gate return i; 5150Sstevel@tonic-gate default: 5160Sstevel@tonic-gate fatal("channel_find_open: bad channel type %d", c->type); 5170Sstevel@tonic-gate /* NOTREACHED */ 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate return -1; 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate /* 5250Sstevel@tonic-gate * Returns a message describing the currently open forwarded connections, 5260Sstevel@tonic-gate * suitable for sending to the client. The message contains crlf pairs for 5270Sstevel@tonic-gate * newlines. 5280Sstevel@tonic-gate */ 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate char * 5310Sstevel@tonic-gate channel_open_message(void) 5320Sstevel@tonic-gate { 5330Sstevel@tonic-gate Buffer buffer; 5340Sstevel@tonic-gate Channel *c; 5350Sstevel@tonic-gate char buf[1024], *cp; 5360Sstevel@tonic-gate int i; 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate buffer_init(&buffer); 5390Sstevel@tonic-gate snprintf(buf, sizeof buf, "The following connections are open:\r\n"); 5400Sstevel@tonic-gate buffer_append(&buffer, buf, strlen(buf)); 5410Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 5420Sstevel@tonic-gate c = channels[i]; 5430Sstevel@tonic-gate if (c == NULL) 5440Sstevel@tonic-gate continue; 5450Sstevel@tonic-gate switch (c->type) { 5460Sstevel@tonic-gate case SSH_CHANNEL_X11_LISTENER: 5470Sstevel@tonic-gate case SSH_CHANNEL_PORT_LISTENER: 5480Sstevel@tonic-gate case SSH_CHANNEL_RPORT_LISTENER: 5490Sstevel@tonic-gate case SSH_CHANNEL_CLOSED: 5500Sstevel@tonic-gate case SSH_CHANNEL_AUTH_SOCKET: 5510Sstevel@tonic-gate case SSH_CHANNEL_ZOMBIE: 5520Sstevel@tonic-gate continue; 5530Sstevel@tonic-gate case SSH_CHANNEL_LARVAL: 5540Sstevel@tonic-gate case SSH_CHANNEL_OPENING: 5550Sstevel@tonic-gate case SSH_CHANNEL_CONNECTING: 5560Sstevel@tonic-gate case SSH_CHANNEL_DYNAMIC: 5570Sstevel@tonic-gate case SSH_CHANNEL_OPEN: 5580Sstevel@tonic-gate case SSH_CHANNEL_X11_OPEN: 5590Sstevel@tonic-gate case SSH_CHANNEL_INPUT_DRAINING: 5600Sstevel@tonic-gate case SSH_CHANNEL_OUTPUT_DRAINING: 5610Sstevel@tonic-gate snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n", 5620Sstevel@tonic-gate c->self, c->remote_name, 5630Sstevel@tonic-gate c->type, c->remote_id, 5640Sstevel@tonic-gate c->istate, buffer_len(&c->input), 5650Sstevel@tonic-gate c->ostate, buffer_len(&c->output), 5660Sstevel@tonic-gate c->rfd, c->wfd); 5670Sstevel@tonic-gate buffer_append(&buffer, buf, strlen(buf)); 5680Sstevel@tonic-gate continue; 5690Sstevel@tonic-gate default: 5700Sstevel@tonic-gate fatal("channel_open_message: bad channel type %d", c->type); 5710Sstevel@tonic-gate /* NOTREACHED */ 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate buffer_append(&buffer, "\0", 1); 5750Sstevel@tonic-gate cp = xstrdup(buffer_ptr(&buffer)); 5760Sstevel@tonic-gate buffer_free(&buffer); 5770Sstevel@tonic-gate return cp; 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate void 5810Sstevel@tonic-gate channel_send_open(int id) 5820Sstevel@tonic-gate { 5830Sstevel@tonic-gate Channel *c = channel_lookup(id); 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate if (c == NULL) { 5860Sstevel@tonic-gate log("channel_send_open: %d: bad id", id); 5870Sstevel@tonic-gate return; 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate debug("send channel open %d", id); 5900Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN); 5910Sstevel@tonic-gate packet_put_cstring(c->ctype); 5920Sstevel@tonic-gate packet_put_int(c->self); 5930Sstevel@tonic-gate packet_put_int(c->local_window); 5940Sstevel@tonic-gate packet_put_int(c->local_maxpacket); 5950Sstevel@tonic-gate packet_send(); 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate void 5990Sstevel@tonic-gate channel_request_start(int local_id, char *service, int wantconfirm) 6000Sstevel@tonic-gate { 6010Sstevel@tonic-gate Channel *c = channel_lookup(local_id); 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate if (c == NULL) { 6040Sstevel@tonic-gate log("channel_request_start: %d: unknown channel id", local_id); 6050Sstevel@tonic-gate return; 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate debug("channel request %d: %s", local_id, service) ; 6080Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_REQUEST); 6090Sstevel@tonic-gate packet_put_int(c->remote_id); 6100Sstevel@tonic-gate packet_put_cstring(service); 6110Sstevel@tonic-gate packet_put_char(wantconfirm); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate void 6140Sstevel@tonic-gate channel_register_confirm(int id, channel_callback_fn *fn) 6150Sstevel@tonic-gate { 6160Sstevel@tonic-gate Channel *c = channel_lookup(id); 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate if (c == NULL) { 6190Sstevel@tonic-gate log("channel_register_comfirm: %d: bad id", id); 6200Sstevel@tonic-gate return; 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate c->confirm = fn; 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate void 6250Sstevel@tonic-gate channel_register_cleanup(int id, channel_callback_fn *fn) 6260Sstevel@tonic-gate { 6270Sstevel@tonic-gate Channel *c = channel_lookup(id); 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate if (c == NULL) { 6300Sstevel@tonic-gate log("channel_register_cleanup: %d: bad id", id); 6310Sstevel@tonic-gate return; 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate c->detach_user = fn; 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate void 6360Sstevel@tonic-gate channel_cancel_cleanup(int id) 6370Sstevel@tonic-gate { 6380Sstevel@tonic-gate Channel *c = channel_lookup(id); 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate if (c == NULL) { 6410Sstevel@tonic-gate log("channel_cancel_cleanup: %d: bad id", id); 6420Sstevel@tonic-gate return; 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate c->detach_user = NULL; 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate void 6470Sstevel@tonic-gate channel_register_filter(int id, channel_filter_fn *fn) 6480Sstevel@tonic-gate { 6490Sstevel@tonic-gate Channel *c = channel_lookup(id); 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate if (c == NULL) { 6520Sstevel@tonic-gate log("channel_register_filter: %d: bad id", id); 6530Sstevel@tonic-gate return; 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate c->input_filter = fn; 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate void 6590Sstevel@tonic-gate channel_set_fds(int id, int rfd, int wfd, int efd, 6600Sstevel@tonic-gate int extusage, int nonblock, u_int window_max) 6610Sstevel@tonic-gate { 6620Sstevel@tonic-gate Channel *c = channel_lookup(id); 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate if (c == NULL || c->type != SSH_CHANNEL_LARVAL) 6650Sstevel@tonic-gate fatal("channel_activate for non-larval channel %d.", id); 6660Sstevel@tonic-gate channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); 6670Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 6680Sstevel@tonic-gate c->local_window = c->local_window_max = window_max; 6690Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); 6700Sstevel@tonic-gate packet_put_int(c->remote_id); 6710Sstevel@tonic-gate packet_put_int(c->local_window); 6720Sstevel@tonic-gate packet_send(); 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate void 6760Sstevel@tonic-gate channel_set_wait_for_exit(int id, int wait_for_exit) 6770Sstevel@tonic-gate { 6780Sstevel@tonic-gate Channel *c = channel_lookup(id); 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate if (c == NULL || c->type != SSH_CHANNEL_OPEN) 6810Sstevel@tonic-gate fatal("channel_set_wait_for_exit for non-open channel %d.", id); 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate debug3("channel_set_wait_for_exit %d, %d (type: %d)", id, wait_for_exit, c->type); 6840Sstevel@tonic-gate c->wait_for_exit = wait_for_exit; 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate /* 6880Sstevel@tonic-gate * 'channel_pre*' are called just before select() to add any bits relevant to 6890Sstevel@tonic-gate * channels in the select bitmasks. 6900Sstevel@tonic-gate */ 6910Sstevel@tonic-gate /* 6920Sstevel@tonic-gate * 'channel_post*': perform any appropriate operations for channels which 6930Sstevel@tonic-gate * have events pending. 6940Sstevel@tonic-gate */ 6950Sstevel@tonic-gate typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset); 6960Sstevel@tonic-gate chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE]; 6970Sstevel@tonic-gate chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE]; 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate static void 7000Sstevel@tonic-gate channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset) 7010Sstevel@tonic-gate { 7020Sstevel@tonic-gate FD_SET(c->sock, readset); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate static void 7060Sstevel@tonic-gate channel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset) 7070Sstevel@tonic-gate { 7080Sstevel@tonic-gate debug3("channel %d: waiting for connection", c->self); 7090Sstevel@tonic-gate FD_SET(c->sock, writeset); 7100Sstevel@tonic-gate } 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate static void 7130Sstevel@tonic-gate channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset) 7140Sstevel@tonic-gate { 7150Sstevel@tonic-gate if (buffer_len(&c->input) < packet_get_maxsize()) 7160Sstevel@tonic-gate FD_SET(c->sock, readset); 7170Sstevel@tonic-gate if (buffer_len(&c->output) > 0) 7180Sstevel@tonic-gate FD_SET(c->sock, writeset); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate static void 7220Sstevel@tonic-gate channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset) 7230Sstevel@tonic-gate { 7240Sstevel@tonic-gate u_int limit = compat20 ? c->remote_window : packet_get_maxsize(); 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate if (c->istate == CHAN_INPUT_OPEN && 7270Sstevel@tonic-gate limit > 0 && 7280Sstevel@tonic-gate buffer_len(&c->input) < limit) 7290Sstevel@tonic-gate FD_SET(c->rfd, readset); 7300Sstevel@tonic-gate if (c->ostate == CHAN_OUTPUT_OPEN || 7310Sstevel@tonic-gate c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { 7320Sstevel@tonic-gate if (buffer_len(&c->output) > 0) { 7330Sstevel@tonic-gate FD_SET(c->wfd, writeset); 7340Sstevel@tonic-gate } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { 7350Sstevel@tonic-gate if (CHANNEL_EFD_OUTPUT_ACTIVE(c)) 7360Sstevel@tonic-gate debug2("channel %d: obuf_empty delayed efd %d/(%d)", 7370Sstevel@tonic-gate c->self, c->efd, buffer_len(&c->extended)); 7380Sstevel@tonic-gate else 7390Sstevel@tonic-gate chan_obuf_empty(c); 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate /** XXX check close conditions, too */ 7430Sstevel@tonic-gate if (compat20 && c->efd != -1) { 7440Sstevel@tonic-gate if (c->extended_usage == CHAN_EXTENDED_WRITE && 7450Sstevel@tonic-gate buffer_len(&c->extended) > 0) 7460Sstevel@tonic-gate FD_SET(c->efd, writeset); 7470Sstevel@tonic-gate else if (!(c->flags & CHAN_EOF_SENT) && 7480Sstevel@tonic-gate c->extended_usage == CHAN_EXTENDED_READ && 7490Sstevel@tonic-gate buffer_len(&c->extended) < c->remote_window) 7500Sstevel@tonic-gate FD_SET(c->efd, readset); 7510Sstevel@tonic-gate } 7520Sstevel@tonic-gate } 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate static void 7550Sstevel@tonic-gate channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) 7560Sstevel@tonic-gate { 7570Sstevel@tonic-gate if (buffer_len(&c->input) == 0) { 7580Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_CLOSE); 7590Sstevel@tonic-gate packet_put_int(c->remote_id); 7600Sstevel@tonic-gate packet_send(); 7610Sstevel@tonic-gate c->type = SSH_CHANNEL_CLOSED; 7620Sstevel@tonic-gate debug("channel %d: closing after input drain.", c->self); 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate static void 7670Sstevel@tonic-gate channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) 7680Sstevel@tonic-gate { 7690Sstevel@tonic-gate if (buffer_len(&c->output) == 0) 7700Sstevel@tonic-gate chan_mark_dead(c); 7710Sstevel@tonic-gate else 7720Sstevel@tonic-gate FD_SET(c->sock, writeset); 7730Sstevel@tonic-gate } 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate /* 7760Sstevel@tonic-gate * This is a special state for X11 authentication spoofing. An opened X11 7770Sstevel@tonic-gate * connection (when authentication spoofing is being done) remains in this 7780Sstevel@tonic-gate * state until the first packet has been completely read. The authentication 7790Sstevel@tonic-gate * data in that packet is then substituted by the real data if it matches the 7800Sstevel@tonic-gate * fake data, and the channel is put into normal mode. 7810Sstevel@tonic-gate * XXX All this happens at the client side. 7820Sstevel@tonic-gate * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok 7830Sstevel@tonic-gate */ 7840Sstevel@tonic-gate static int 7850Sstevel@tonic-gate x11_open_helper(Buffer *b) 7860Sstevel@tonic-gate { 7870Sstevel@tonic-gate u_char *ucp; 7880Sstevel@tonic-gate u_int proto_len, data_len; 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate /* Check if the fixed size part of the packet is in buffer. */ 7910Sstevel@tonic-gate if (buffer_len(b) < 12) 7920Sstevel@tonic-gate return 0; 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate /* Parse the lengths of variable-length fields. */ 7950Sstevel@tonic-gate ucp = buffer_ptr(b); 7960Sstevel@tonic-gate if (ucp[0] == 0x42) { /* Byte order MSB first. */ 7970Sstevel@tonic-gate proto_len = 256 * ucp[6] + ucp[7]; 7980Sstevel@tonic-gate data_len = 256 * ucp[8] + ucp[9]; 7990Sstevel@tonic-gate } else if (ucp[0] == 0x6c) { /* Byte order LSB first. */ 8000Sstevel@tonic-gate proto_len = ucp[6] + 256 * ucp[7]; 8010Sstevel@tonic-gate data_len = ucp[8] + 256 * ucp[9]; 8020Sstevel@tonic-gate } else { 8030Sstevel@tonic-gate debug("Initial X11 packet contains bad byte order byte: 0x%x", 8040Sstevel@tonic-gate ucp[0]); 8050Sstevel@tonic-gate return -1; 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate /* Check if the whole packet is in buffer. */ 8090Sstevel@tonic-gate if (buffer_len(b) < 8100Sstevel@tonic-gate 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) 8110Sstevel@tonic-gate return 0; 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate /* Check if authentication protocol matches. */ 8140Sstevel@tonic-gate if (proto_len != strlen(x11_saved_proto) || 8150Sstevel@tonic-gate memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { 8160Sstevel@tonic-gate debug("X11 connection uses different authentication protocol."); 8170Sstevel@tonic-gate return -1; 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate /* Check if authentication data matches our fake data. */ 8200Sstevel@tonic-gate if (data_len != x11_fake_data_len || 8210Sstevel@tonic-gate memcmp(ucp + 12 + ((proto_len + 3) & ~3), 8220Sstevel@tonic-gate x11_fake_data, x11_fake_data_len) != 0) { 8230Sstevel@tonic-gate debug("X11 auth data does not match fake data."); 8240Sstevel@tonic-gate return -1; 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate /* Check fake data length */ 8270Sstevel@tonic-gate if (x11_fake_data_len != x11_saved_data_len) { 8280Sstevel@tonic-gate error("X11 fake_data_len %d != saved_data_len %d", 8290Sstevel@tonic-gate x11_fake_data_len, x11_saved_data_len); 8300Sstevel@tonic-gate return -1; 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate /* 8330Sstevel@tonic-gate * Received authentication protocol and data match 8340Sstevel@tonic-gate * our fake data. Substitute the fake data with real 8350Sstevel@tonic-gate * data. 8360Sstevel@tonic-gate */ 8370Sstevel@tonic-gate memcpy(ucp + 12 + ((proto_len + 3) & ~3), 8380Sstevel@tonic-gate x11_saved_data, x11_saved_data_len); 8390Sstevel@tonic-gate return 1; 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate static void 8430Sstevel@tonic-gate channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset) 8440Sstevel@tonic-gate { 8450Sstevel@tonic-gate int ret = x11_open_helper(&c->output); 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate if (ret == 1) { 8480Sstevel@tonic-gate /* Start normal processing for the channel. */ 8490Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 8500Sstevel@tonic-gate channel_pre_open_13(c, readset, writeset); 8510Sstevel@tonic-gate } else if (ret == -1) { 8520Sstevel@tonic-gate /* 8530Sstevel@tonic-gate * We have received an X11 connection that has bad 8540Sstevel@tonic-gate * authentication information. 8550Sstevel@tonic-gate */ 8560Sstevel@tonic-gate log("X11 connection rejected because of wrong authentication."); 8570Sstevel@tonic-gate buffer_clear(&c->input); 8580Sstevel@tonic-gate buffer_clear(&c->output); 8590Sstevel@tonic-gate channel_close_fd(&c->sock); 8600Sstevel@tonic-gate c->sock = -1; 8610Sstevel@tonic-gate c->type = SSH_CHANNEL_CLOSED; 8620Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_CLOSE); 8630Sstevel@tonic-gate packet_put_int(c->remote_id); 8640Sstevel@tonic-gate packet_send(); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate } 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate static void 8690Sstevel@tonic-gate channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) 8700Sstevel@tonic-gate { 8710Sstevel@tonic-gate int ret = x11_open_helper(&c->output); 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate /* c->force_drain = 1; */ 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate if (ret == 1) { 8760Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 8770Sstevel@tonic-gate channel_pre_open(c, readset, writeset); 8780Sstevel@tonic-gate } else if (ret == -1) { 8790Sstevel@tonic-gate log("X11 connection rejected because of wrong authentication."); 8800Sstevel@tonic-gate debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate); 8810Sstevel@tonic-gate chan_read_failed(c); 8820Sstevel@tonic-gate buffer_clear(&c->input); 8830Sstevel@tonic-gate chan_ibuf_empty(c); 8840Sstevel@tonic-gate buffer_clear(&c->output); 8850Sstevel@tonic-gate /* for proto v1, the peer will send an IEOF */ 8860Sstevel@tonic-gate if (compat20) 8870Sstevel@tonic-gate chan_write_failed(c); 8880Sstevel@tonic-gate else 8890Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 8900Sstevel@tonic-gate debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate /* try to decode a socks4 header */ 8950Sstevel@tonic-gate static int 8960Sstevel@tonic-gate channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) 8970Sstevel@tonic-gate { 8980Sstevel@tonic-gate char *p, *host; 8990Sstevel@tonic-gate int len, have, i, found; 9000Sstevel@tonic-gate char username[256]; 9010Sstevel@tonic-gate struct { 9020Sstevel@tonic-gate u_int8_t version; 9030Sstevel@tonic-gate u_int8_t command; 9040Sstevel@tonic-gate u_int16_t dest_port; 9050Sstevel@tonic-gate struct in_addr dest_addr; 9060Sstevel@tonic-gate } s4_req, s4_rsp; 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate debug2("channel %d: decode socks4", c->self); 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate have = buffer_len(&c->input); 9110Sstevel@tonic-gate len = sizeof(s4_req); 9120Sstevel@tonic-gate if (have < len) 9130Sstevel@tonic-gate return 0; 9140Sstevel@tonic-gate p = buffer_ptr(&c->input); 9150Sstevel@tonic-gate for (found = 0, i = len; i < have; i++) { 9160Sstevel@tonic-gate if (p[i] == '\0') { 9170Sstevel@tonic-gate found = 1; 9180Sstevel@tonic-gate break; 9190Sstevel@tonic-gate } 9200Sstevel@tonic-gate if (i > 1024) { 9210Sstevel@tonic-gate /* the peer is probably sending garbage */ 9220Sstevel@tonic-gate debug("channel %d: decode socks4: too long", 9230Sstevel@tonic-gate c->self); 9240Sstevel@tonic-gate return -1; 9250Sstevel@tonic-gate } 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate if (!found) 9280Sstevel@tonic-gate return 0; 9290Sstevel@tonic-gate buffer_get(&c->input, (char *)&s4_req.version, 1); 9300Sstevel@tonic-gate buffer_get(&c->input, (char *)&s4_req.command, 1); 9310Sstevel@tonic-gate buffer_get(&c->input, (char *)&s4_req.dest_port, 2); 9320Sstevel@tonic-gate buffer_get(&c->input, (char *)&s4_req.dest_addr, 4); 9330Sstevel@tonic-gate have = buffer_len(&c->input); 9340Sstevel@tonic-gate p = buffer_ptr(&c->input); 9350Sstevel@tonic-gate len = strlen(p); 9360Sstevel@tonic-gate debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); 9370Sstevel@tonic-gate if (len > have) 9380Sstevel@tonic-gate fatal("channel %d: decode socks4: len %d > have %d", 9390Sstevel@tonic-gate c->self, len, have); 9400Sstevel@tonic-gate strlcpy(username, p, sizeof(username)); 9410Sstevel@tonic-gate buffer_consume(&c->input, len); 9420Sstevel@tonic-gate buffer_consume(&c->input, 1); /* trailing '\0' */ 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate host = inet_ntoa(s4_req.dest_addr); 9450Sstevel@tonic-gate strlcpy(c->path, host, sizeof(c->path)); 9460Sstevel@tonic-gate c->host_port = ntohs(s4_req.dest_port); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate debug("channel %d: dynamic request: socks4 host %s port %u command %u", 9490Sstevel@tonic-gate c->self, host, c->host_port, s4_req.command); 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate if (s4_req.command != 1) { 9520Sstevel@tonic-gate debug("channel %d: cannot handle: socks4 cn %d", 9530Sstevel@tonic-gate c->self, s4_req.command); 9540Sstevel@tonic-gate return -1; 9550Sstevel@tonic-gate } 9560Sstevel@tonic-gate s4_rsp.version = 0; /* vn: 0 for reply */ 9570Sstevel@tonic-gate s4_rsp.command = 90; /* cd: req granted */ 9580Sstevel@tonic-gate s4_rsp.dest_port = 0; /* ignored */ 9590Sstevel@tonic-gate s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ 9600Sstevel@tonic-gate buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp)); 9610Sstevel@tonic-gate return 1; 9620Sstevel@tonic-gate } 9630Sstevel@tonic-gate 9644764Sjp161948 /* try to decode a socks5 header */ 9654764Sjp161948 #define SSH_SOCKS5_AUTHDONE 0x1000 9664764Sjp161948 #define SSH_SOCKS5_NOAUTH 0x00 9674764Sjp161948 #define SSH_SOCKS5_IPV4 0x01 9684764Sjp161948 #define SSH_SOCKS5_DOMAIN 0x03 9694764Sjp161948 #define SSH_SOCKS5_IPV6 0x04 9704764Sjp161948 #define SSH_SOCKS5_CONNECT 0x01 9714764Sjp161948 #define SSH_SOCKS5_SUCCESS 0x00 9724764Sjp161948 9734764Sjp161948 /* ARGSUSED */ 9744764Sjp161948 static int 9754764Sjp161948 channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) 9764764Sjp161948 { 9774764Sjp161948 struct { 9784764Sjp161948 u_int8_t version; 9794764Sjp161948 u_int8_t command; 9804764Sjp161948 u_int8_t reserved; 9814764Sjp161948 u_int8_t atyp; 9824764Sjp161948 } s5_req, s5_rsp; 9834764Sjp161948 u_int16_t dest_port; 9844764Sjp161948 u_char *p, dest_addr[255+1]; 9854764Sjp161948 u_int have, need, i, found, nmethods, addrlen; 9864764Sjp161948 struct in_addr bnd_addr; 9874764Sjp161948 int af; 9884764Sjp161948 9894764Sjp161948 debug2("channel %d: decode socks5", c->self); 9904764Sjp161948 p = buffer_ptr(&c->input); 9914764Sjp161948 if (p[0] != 0x05) 9924764Sjp161948 return -1; 9934764Sjp161948 have = buffer_len(&c->input); 9944764Sjp161948 if (!(c->flags & SSH_SOCKS5_AUTHDONE)) { 9954764Sjp161948 /* format: ver | nmethods | methods */ 9964764Sjp161948 if (have < 2) 9974764Sjp161948 return 0; 9984764Sjp161948 nmethods = p[1]; 9994764Sjp161948 if (have < nmethods + 2) 10004764Sjp161948 return 0; 10014764Sjp161948 /* look for method: "NO AUTHENTICATION REQUIRED" */ 10024764Sjp161948 for (found = 0, i = 2 ; i < nmethods + 2; i++) { 10034764Sjp161948 if (p[i] == SSH_SOCKS5_NOAUTH) { 10044764Sjp161948 found = 1; 10054764Sjp161948 break; 10064764Sjp161948 } 10074764Sjp161948 } 10084764Sjp161948 if (!found) { 10094764Sjp161948 error("channel %d: socks5 authentication methods not implemented", 10104764Sjp161948 c->self); 10114764Sjp161948 error("channel %d: forwarding failed: " 10124764Sjp161948 "SSH_SOCKS5_NOAUTH method not found", c->self); 10134764Sjp161948 return -1; 10144764Sjp161948 } 10154764Sjp161948 buffer_consume(&c->input, nmethods + 2); 10164764Sjp161948 buffer_put_char(&c->output, 0x05); /* version */ 10174764Sjp161948 buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH); /* method */ 10184764Sjp161948 FD_SET(c->sock, writeset); 10194764Sjp161948 c->flags |= SSH_SOCKS5_AUTHDONE; 10204764Sjp161948 debug2("channel %d: socks5 auth done", c->self); 10214764Sjp161948 return 0; /* need more */ 10224764Sjp161948 } 10234764Sjp161948 debug2("channel %d: socks5 post auth", c->self); 10244764Sjp161948 if (have < sizeof(s5_req)+1) 10254764Sjp161948 return 0; /* need more */ 10264764Sjp161948 memcpy(&s5_req, p, sizeof(s5_req)); 10274764Sjp161948 if (s5_req.version != 0x05 || 10284764Sjp161948 s5_req.command != SSH_SOCKS5_CONNECT || 10294764Sjp161948 s5_req.reserved != 0x00) { 10304764Sjp161948 error("channel %d: forwarding failed: " 10314764Sjp161948 "only socks5 connect is supported", c->self); 10324764Sjp161948 return -1; 10334764Sjp161948 } 10344764Sjp161948 switch (s5_req.atyp){ 10354764Sjp161948 case SSH_SOCKS5_IPV4: 10364764Sjp161948 addrlen = 4; 10374764Sjp161948 af = AF_INET; 10384764Sjp161948 break; 10394764Sjp161948 case SSH_SOCKS5_DOMAIN: 10404764Sjp161948 addrlen = p[sizeof(s5_req)]; 10414764Sjp161948 af = -1; 10424764Sjp161948 break; 10434764Sjp161948 case SSH_SOCKS5_IPV6: 10444764Sjp161948 addrlen = 16; 10454764Sjp161948 af = AF_INET6; 10464764Sjp161948 break; 10474764Sjp161948 default: 10484764Sjp161948 error("channel %d: forwarding failed: " 10494764Sjp161948 "bad socks5 atyp %d", c->self, s5_req.atyp); 10504764Sjp161948 return -1; 10514764Sjp161948 } 10524764Sjp161948 need = sizeof(s5_req) + addrlen + 2; 10534764Sjp161948 if (s5_req.atyp == SSH_SOCKS5_DOMAIN) 10544764Sjp161948 need++; 10554764Sjp161948 if (have < need) 10564764Sjp161948 return 0; 10574764Sjp161948 buffer_consume(&c->input, sizeof(s5_req)); 10584764Sjp161948 if (s5_req.atyp == SSH_SOCKS5_DOMAIN) 10594764Sjp161948 buffer_consume(&c->input, 1); /* host string length */ 10604764Sjp161948 buffer_get(&c->input, (char *)&dest_addr, addrlen); 10614764Sjp161948 buffer_get(&c->input, (char *)&dest_port, 2); 10624764Sjp161948 dest_addr[addrlen] = '\0'; 10634764Sjp161948 if (s5_req.atyp == SSH_SOCKS5_DOMAIN) 10644764Sjp161948 strlcpy(c->path, (char *)dest_addr, sizeof(c->path)); 10654764Sjp161948 else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL) 10664764Sjp161948 return -1; 10674764Sjp161948 c->host_port = ntohs(dest_port); 10684764Sjp161948 10694764Sjp161948 debug2("channel %d: dynamic request: socks5 host %s port %u command %u", 10704764Sjp161948 c->self, c->path, c->host_port, s5_req.command); 10714764Sjp161948 10724764Sjp161948 s5_rsp.version = 0x05; 10734764Sjp161948 s5_rsp.command = SSH_SOCKS5_SUCCESS; 10744764Sjp161948 s5_rsp.reserved = 0; /* ignored */ 10754764Sjp161948 s5_rsp.atyp = SSH_SOCKS5_IPV4; 10764764Sjp161948 bzero(&bnd_addr, sizeof(bnd_addr)); 10774764Sjp161948 bnd_addr.s_addr = htonl(INADDR_ANY); 10784764Sjp161948 dest_port = 0; /* ignored */ 10794764Sjp161948 10804764Sjp161948 buffer_append(&c->output, &s5_rsp, sizeof(s5_rsp)); 10814764Sjp161948 buffer_append(&c->output, &bnd_addr, sizeof(struct in_addr)); 10824764Sjp161948 buffer_append(&c->output, &dest_port, sizeof(dest_port)); 10834764Sjp161948 return 1; 10844764Sjp161948 } 10854764Sjp161948 10860Sstevel@tonic-gate /* dynamic port forwarding */ 10870Sstevel@tonic-gate static void 10880Sstevel@tonic-gate channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) 10890Sstevel@tonic-gate { 10900Sstevel@tonic-gate u_char *p; 10910Sstevel@tonic-gate int have, ret; 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate have = buffer_len(&c->input); 10940Sstevel@tonic-gate c->delayed = 0; 10950Sstevel@tonic-gate debug2("channel %d: pre_dynamic: have %d", c->self, have); 10960Sstevel@tonic-gate /* buffer_dump(&c->input); */ 10970Sstevel@tonic-gate /* check if the fixed size part of the packet is in buffer. */ 10984764Sjp161948 if (have < 3) { 10990Sstevel@tonic-gate /* need more */ 11000Sstevel@tonic-gate FD_SET(c->sock, readset); 11010Sstevel@tonic-gate return; 11020Sstevel@tonic-gate } 11030Sstevel@tonic-gate /* try to guess the protocol */ 11040Sstevel@tonic-gate p = buffer_ptr(&c->input); 11050Sstevel@tonic-gate switch (p[0]) { 11060Sstevel@tonic-gate case 0x04: 11070Sstevel@tonic-gate ret = channel_decode_socks4(c, readset, writeset); 11080Sstevel@tonic-gate break; 11094764Sjp161948 case 0x05: 11104764Sjp161948 ret = channel_decode_socks5(c, readset, writeset); 11114764Sjp161948 break; 11120Sstevel@tonic-gate default: 11134764Sjp161948 error("channel %d: forwarding failed: unknown socks " 11144764Sjp161948 "version 0x%02X", c->self, p[0]); 11150Sstevel@tonic-gate ret = -1; 11160Sstevel@tonic-gate break; 11170Sstevel@tonic-gate } 11180Sstevel@tonic-gate if (ret < 0) { 11190Sstevel@tonic-gate chan_mark_dead(c); 11200Sstevel@tonic-gate } else if (ret == 0) { 11210Sstevel@tonic-gate debug2("channel %d: pre_dynamic: need more", c->self); 11220Sstevel@tonic-gate /* need more */ 11230Sstevel@tonic-gate FD_SET(c->sock, readset); 11240Sstevel@tonic-gate } else { 11250Sstevel@tonic-gate /* switch to the next state */ 11260Sstevel@tonic-gate c->type = SSH_CHANNEL_OPENING; 11270Sstevel@tonic-gate port_open_helper(c, "direct-tcpip"); 11280Sstevel@tonic-gate } 11290Sstevel@tonic-gate } 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate /* This is our fake X11 server socket. */ 11320Sstevel@tonic-gate static void 11330Sstevel@tonic-gate channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) 11340Sstevel@tonic-gate { 11350Sstevel@tonic-gate Channel *nc; 11360Sstevel@tonic-gate struct sockaddr addr; 11370Sstevel@tonic-gate int newsock; 11380Sstevel@tonic-gate socklen_t addrlen; 11390Sstevel@tonic-gate char buf[16384], *remote_ipaddr; 11400Sstevel@tonic-gate int remote_port; 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate if (FD_ISSET(c->sock, readset)) { 11430Sstevel@tonic-gate debug("X11 connection requested."); 11440Sstevel@tonic-gate addrlen = sizeof(addr); 11450Sstevel@tonic-gate newsock = accept(c->sock, &addr, &addrlen); 11460Sstevel@tonic-gate if (c->single_connection) { 11470Sstevel@tonic-gate debug("single_connection: closing X11 listener."); 11480Sstevel@tonic-gate channel_close_fd(&c->sock); 11490Sstevel@tonic-gate chan_mark_dead(c); 11500Sstevel@tonic-gate } 11510Sstevel@tonic-gate if (newsock < 0) { 11520Sstevel@tonic-gate error("accept: %.100s", strerror(errno)); 11530Sstevel@tonic-gate return; 11540Sstevel@tonic-gate } 11550Sstevel@tonic-gate set_nodelay(newsock); 11560Sstevel@tonic-gate remote_ipaddr = get_peer_ipaddr(newsock); 11570Sstevel@tonic-gate remote_port = get_peer_port(newsock); 11580Sstevel@tonic-gate snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", 11590Sstevel@tonic-gate remote_ipaddr, remote_port); 11600Sstevel@tonic-gate 11610Sstevel@tonic-gate nc = channel_new("accepted x11 socket", 11620Sstevel@tonic-gate SSH_CHANNEL_OPENING, newsock, newsock, -1, 11630Sstevel@tonic-gate c->local_window_max, c->local_maxpacket, 11640Sstevel@tonic-gate 0, xstrdup(buf), 1); 11650Sstevel@tonic-gate if (compat20) { 11660Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN); 11670Sstevel@tonic-gate packet_put_cstring("x11"); 11680Sstevel@tonic-gate packet_put_int(nc->self); 11690Sstevel@tonic-gate packet_put_int(nc->local_window_max); 11700Sstevel@tonic-gate packet_put_int(nc->local_maxpacket); 11710Sstevel@tonic-gate /* originator ipaddr and port */ 11720Sstevel@tonic-gate packet_put_cstring(remote_ipaddr); 11730Sstevel@tonic-gate if (datafellows & SSH_BUG_X11FWD) { 11740Sstevel@tonic-gate debug("ssh2 x11 bug compat mode"); 11750Sstevel@tonic-gate } else { 11760Sstevel@tonic-gate packet_put_int(remote_port); 11770Sstevel@tonic-gate } 11780Sstevel@tonic-gate packet_send(); 11790Sstevel@tonic-gate } else { 11800Sstevel@tonic-gate packet_start(SSH_SMSG_X11_OPEN); 11810Sstevel@tonic-gate packet_put_int(nc->self); 11820Sstevel@tonic-gate if (packet_get_protocol_flags() & 11830Sstevel@tonic-gate SSH_PROTOFLAG_HOST_IN_FWD_OPEN) 11840Sstevel@tonic-gate packet_put_cstring(buf); 11850Sstevel@tonic-gate packet_send(); 11860Sstevel@tonic-gate } 11870Sstevel@tonic-gate xfree(remote_ipaddr); 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate } 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate static void 11920Sstevel@tonic-gate port_open_helper(Channel *c, char *rtype) 11930Sstevel@tonic-gate { 11940Sstevel@tonic-gate int direct; 11950Sstevel@tonic-gate char buf[1024]; 11960Sstevel@tonic-gate char *remote_ipaddr = get_peer_ipaddr(c->sock); 11970Sstevel@tonic-gate u_short remote_port = get_peer_port(c->sock); 11980Sstevel@tonic-gate 11990Sstevel@tonic-gate direct = (strcmp(rtype, "direct-tcpip") == 0); 12000Sstevel@tonic-gate 12010Sstevel@tonic-gate snprintf(buf, sizeof buf, 12020Sstevel@tonic-gate "%s: listening port %d for %.100s port %d, " 12030Sstevel@tonic-gate "connect from %.200s port %d", 12040Sstevel@tonic-gate rtype, c->listening_port, c->path, c->host_port, 12050Sstevel@tonic-gate remote_ipaddr, remote_port); 12060Sstevel@tonic-gate 12070Sstevel@tonic-gate xfree(c->remote_name); 12080Sstevel@tonic-gate c->remote_name = xstrdup(buf); 12090Sstevel@tonic-gate 12100Sstevel@tonic-gate if (compat20) { 12110Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN); 12120Sstevel@tonic-gate packet_put_cstring(rtype); 12130Sstevel@tonic-gate packet_put_int(c->self); 12140Sstevel@tonic-gate packet_put_int(c->local_window_max); 12150Sstevel@tonic-gate packet_put_int(c->local_maxpacket); 12160Sstevel@tonic-gate if (direct) { 12170Sstevel@tonic-gate /* target host, port */ 12180Sstevel@tonic-gate packet_put_cstring(c->path); 12190Sstevel@tonic-gate packet_put_int(c->host_port); 12200Sstevel@tonic-gate } else { 12210Sstevel@tonic-gate /* listen address, port */ 12220Sstevel@tonic-gate packet_put_cstring(c->path); 12230Sstevel@tonic-gate packet_put_int(c->listening_port); 12240Sstevel@tonic-gate } 12250Sstevel@tonic-gate /* originator host and port */ 12260Sstevel@tonic-gate packet_put_cstring(remote_ipaddr); 12270Sstevel@tonic-gate packet_put_int(remote_port); 12280Sstevel@tonic-gate packet_send(); 12290Sstevel@tonic-gate } else { 12300Sstevel@tonic-gate packet_start(SSH_MSG_PORT_OPEN); 12310Sstevel@tonic-gate packet_put_int(c->self); 12320Sstevel@tonic-gate packet_put_cstring(c->path); 12330Sstevel@tonic-gate packet_put_int(c->host_port); 12340Sstevel@tonic-gate if (packet_get_protocol_flags() & 12350Sstevel@tonic-gate SSH_PROTOFLAG_HOST_IN_FWD_OPEN) 12360Sstevel@tonic-gate packet_put_cstring(c->remote_name); 12370Sstevel@tonic-gate packet_send(); 12380Sstevel@tonic-gate } 12390Sstevel@tonic-gate xfree(remote_ipaddr); 12400Sstevel@tonic-gate } 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate /* 12430Sstevel@tonic-gate * This socket is listening for connections to a forwarded TCP/IP port. 12440Sstevel@tonic-gate */ 12450Sstevel@tonic-gate static void 12460Sstevel@tonic-gate channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) 12470Sstevel@tonic-gate { 12480Sstevel@tonic-gate Channel *nc; 12490Sstevel@tonic-gate struct sockaddr addr; 12500Sstevel@tonic-gate int newsock, nextstate; 12510Sstevel@tonic-gate socklen_t addrlen; 12520Sstevel@tonic-gate char *rtype; 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate if (FD_ISSET(c->sock, readset)) { 12550Sstevel@tonic-gate debug("Connection to port %d forwarding " 12560Sstevel@tonic-gate "to %.100s port %d requested.", 12570Sstevel@tonic-gate c->listening_port, c->path, c->host_port); 12580Sstevel@tonic-gate 12590Sstevel@tonic-gate if (c->type == SSH_CHANNEL_RPORT_LISTENER) { 12600Sstevel@tonic-gate nextstate = SSH_CHANNEL_OPENING; 12610Sstevel@tonic-gate rtype = "forwarded-tcpip"; 12620Sstevel@tonic-gate } else { 12630Sstevel@tonic-gate if (c->host_port == 0) { 12640Sstevel@tonic-gate nextstate = SSH_CHANNEL_DYNAMIC; 12650Sstevel@tonic-gate rtype = "dynamic-tcpip"; 12660Sstevel@tonic-gate } else { 12670Sstevel@tonic-gate nextstate = SSH_CHANNEL_OPENING; 12680Sstevel@tonic-gate rtype = "direct-tcpip"; 12690Sstevel@tonic-gate } 12700Sstevel@tonic-gate } 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate addrlen = sizeof(addr); 12730Sstevel@tonic-gate newsock = accept(c->sock, &addr, &addrlen); 12740Sstevel@tonic-gate if (newsock < 0) { 12750Sstevel@tonic-gate error("accept: %.100s", strerror(errno)); 12760Sstevel@tonic-gate return; 12770Sstevel@tonic-gate } 12780Sstevel@tonic-gate set_nodelay(newsock); 12790Sstevel@tonic-gate nc = channel_new(rtype, 12800Sstevel@tonic-gate nextstate, newsock, newsock, -1, 12810Sstevel@tonic-gate c->local_window_max, c->local_maxpacket, 12820Sstevel@tonic-gate 0, xstrdup(rtype), 1); 12830Sstevel@tonic-gate nc->listening_port = c->listening_port; 12840Sstevel@tonic-gate nc->host_port = c->host_port; 12850Sstevel@tonic-gate strlcpy(nc->path, c->path, sizeof(nc->path)); 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate if (nextstate == SSH_CHANNEL_DYNAMIC) { 12880Sstevel@tonic-gate /* 12890Sstevel@tonic-gate * do not call the channel_post handler until 12900Sstevel@tonic-gate * this flag has been reset by a pre-handler. 12910Sstevel@tonic-gate * otherwise the FD_ISSET calls might overflow 12920Sstevel@tonic-gate */ 12930Sstevel@tonic-gate nc->delayed = 1; 12940Sstevel@tonic-gate } else { 12950Sstevel@tonic-gate port_open_helper(nc, rtype); 12960Sstevel@tonic-gate } 12970Sstevel@tonic-gate } 12980Sstevel@tonic-gate } 12990Sstevel@tonic-gate 13000Sstevel@tonic-gate /* 13010Sstevel@tonic-gate * This is the authentication agent socket listening for connections from 13020Sstevel@tonic-gate * clients. 13030Sstevel@tonic-gate */ 13040Sstevel@tonic-gate static void 13050Sstevel@tonic-gate channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) 13060Sstevel@tonic-gate { 13070Sstevel@tonic-gate Channel *nc; 13080Sstevel@tonic-gate char *name; 13090Sstevel@tonic-gate int newsock; 13100Sstevel@tonic-gate struct sockaddr addr; 13110Sstevel@tonic-gate socklen_t addrlen; 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate if (FD_ISSET(c->sock, readset)) { 13140Sstevel@tonic-gate addrlen = sizeof(addr); 13150Sstevel@tonic-gate newsock = accept(c->sock, &addr, &addrlen); 13160Sstevel@tonic-gate if (newsock < 0) { 13170Sstevel@tonic-gate error("accept from auth socket: %.100s", strerror(errno)); 13180Sstevel@tonic-gate return; 13190Sstevel@tonic-gate } 13200Sstevel@tonic-gate name = xstrdup("accepted auth socket"); 13210Sstevel@tonic-gate nc = channel_new("accepted auth socket", 13220Sstevel@tonic-gate SSH_CHANNEL_OPENING, newsock, newsock, -1, 13230Sstevel@tonic-gate c->local_window_max, c->local_maxpacket, 13240Sstevel@tonic-gate 0, name, 1); 13250Sstevel@tonic-gate if (compat20) { 13260Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN); 13270Sstevel@tonic-gate packet_put_cstring("auth-agent@openssh.com"); 13280Sstevel@tonic-gate packet_put_int(nc->self); 13290Sstevel@tonic-gate packet_put_int(c->local_window_max); 13300Sstevel@tonic-gate packet_put_int(c->local_maxpacket); 13310Sstevel@tonic-gate } else { 13320Sstevel@tonic-gate packet_start(SSH_SMSG_AGENT_OPEN); 13330Sstevel@tonic-gate packet_put_int(nc->self); 13340Sstevel@tonic-gate } 13350Sstevel@tonic-gate packet_send(); 13360Sstevel@tonic-gate } 13370Sstevel@tonic-gate } 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate static void 13400Sstevel@tonic-gate channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset) 13410Sstevel@tonic-gate { 13420Sstevel@tonic-gate int err = 0; 13430Sstevel@tonic-gate socklen_t sz = sizeof(err); 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate if (FD_ISSET(c->sock, writeset)) { 13460Sstevel@tonic-gate if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) { 13470Sstevel@tonic-gate err = errno; 13480Sstevel@tonic-gate error("getsockopt SO_ERROR failed"); 13490Sstevel@tonic-gate } 13500Sstevel@tonic-gate if (err == 0) { 13510Sstevel@tonic-gate debug("channel %d: connected", c->self); 13520Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 13530Sstevel@tonic-gate if (compat20) { 13540Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); 13550Sstevel@tonic-gate packet_put_int(c->remote_id); 13560Sstevel@tonic-gate packet_put_int(c->self); 13570Sstevel@tonic-gate packet_put_int(c->local_window); 13580Sstevel@tonic-gate packet_put_int(c->local_maxpacket); 13590Sstevel@tonic-gate } else { 13600Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 13610Sstevel@tonic-gate packet_put_int(c->remote_id); 13620Sstevel@tonic-gate packet_put_int(c->self); 13630Sstevel@tonic-gate } 13640Sstevel@tonic-gate } else { 13650Sstevel@tonic-gate debug("channel %d: not connected: %s", 13660Sstevel@tonic-gate c->self, strerror(err)); 13670Sstevel@tonic-gate if (compat20) { 13680Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); 13690Sstevel@tonic-gate packet_put_int(c->remote_id); 13700Sstevel@tonic-gate packet_put_int(SSH2_OPEN_CONNECT_FAILED); 13710Sstevel@tonic-gate if (!(datafellows & SSH_BUG_OPENFAILURE)) { 13720Sstevel@tonic-gate packet_put_cstring(strerror(err)); 13730Sstevel@tonic-gate packet_put_cstring(""); 13740Sstevel@tonic-gate } 13750Sstevel@tonic-gate } else { 13760Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 13770Sstevel@tonic-gate packet_put_int(c->remote_id); 13780Sstevel@tonic-gate } 13790Sstevel@tonic-gate chan_mark_dead(c); 13800Sstevel@tonic-gate } 13810Sstevel@tonic-gate packet_send(); 13820Sstevel@tonic-gate } 13830Sstevel@tonic-gate } 13840Sstevel@tonic-gate 13850Sstevel@tonic-gate static int 13860Sstevel@tonic-gate channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) 13870Sstevel@tonic-gate { 13880Sstevel@tonic-gate char buf[16*1024]; 13890Sstevel@tonic-gate int len; 13900Sstevel@tonic-gate 13910Sstevel@tonic-gate if (c->rfd != -1 && 13920Sstevel@tonic-gate FD_ISSET(c->rfd, readset)) { 13930Sstevel@tonic-gate len = read(c->rfd, buf, sizeof(buf)); 13940Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) 13950Sstevel@tonic-gate return 1; 13960Sstevel@tonic-gate if (len <= 0) { 13970Sstevel@tonic-gate debug("channel %d: read<=0 rfd %d len %d", 13980Sstevel@tonic-gate c->self, c->rfd, len); 13990Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN) { 14000Sstevel@tonic-gate debug("channel %d: not open", c->self); 14010Sstevel@tonic-gate chan_mark_dead(c); 14020Sstevel@tonic-gate return -1; 14030Sstevel@tonic-gate } else if (compat13) { 14040Sstevel@tonic-gate buffer_clear(&c->output); 14050Sstevel@tonic-gate c->type = SSH_CHANNEL_INPUT_DRAINING; 14060Sstevel@tonic-gate debug("channel %d: input draining.", c->self); 14070Sstevel@tonic-gate } else { 14080Sstevel@tonic-gate chan_read_failed(c); 14090Sstevel@tonic-gate } 14100Sstevel@tonic-gate return -1; 14110Sstevel@tonic-gate } 14120Sstevel@tonic-gate if (c->input_filter != NULL) { 14130Sstevel@tonic-gate if (c->input_filter(c, buf, len) == -1) { 14140Sstevel@tonic-gate debug("channel %d: filter stops", c->self); 14150Sstevel@tonic-gate chan_read_failed(c); 14160Sstevel@tonic-gate } 14170Sstevel@tonic-gate } else { 14180Sstevel@tonic-gate buffer_append(&c->input, buf, len); 14190Sstevel@tonic-gate } 14200Sstevel@tonic-gate } 14210Sstevel@tonic-gate return 1; 14220Sstevel@tonic-gate } 14230Sstevel@tonic-gate static int 14240Sstevel@tonic-gate channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) 14250Sstevel@tonic-gate { 14260Sstevel@tonic-gate struct termios tio; 14270Sstevel@tonic-gate u_char *data; 14280Sstevel@tonic-gate u_int dlen; 14290Sstevel@tonic-gate int len; 14300Sstevel@tonic-gate 14310Sstevel@tonic-gate /* Send buffered output data to the socket. */ 14320Sstevel@tonic-gate if (c->wfd != -1 && 14330Sstevel@tonic-gate FD_ISSET(c->wfd, writeset) && 14340Sstevel@tonic-gate buffer_len(&c->output) > 0) { 14350Sstevel@tonic-gate data = buffer_ptr(&c->output); 14360Sstevel@tonic-gate dlen = buffer_len(&c->output); 14370Sstevel@tonic-gate #ifdef _AIX 14380Sstevel@tonic-gate /* XXX: Later AIX versions can't push as much data to tty */ 14390Sstevel@tonic-gate if (compat20 && c->wfd_isatty && dlen > 8*1024) 14400Sstevel@tonic-gate dlen = 8*1024; 14410Sstevel@tonic-gate #endif 14420Sstevel@tonic-gate len = write(c->wfd, data, dlen); 14430Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) 14440Sstevel@tonic-gate return 1; 14450Sstevel@tonic-gate if (len <= 0) { 14460Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN) { 14470Sstevel@tonic-gate debug("channel %d: not open", c->self); 14480Sstevel@tonic-gate chan_mark_dead(c); 14490Sstevel@tonic-gate return -1; 14500Sstevel@tonic-gate } else if (compat13) { 14510Sstevel@tonic-gate buffer_clear(&c->output); 14520Sstevel@tonic-gate debug("channel %d: input draining.", c->self); 14530Sstevel@tonic-gate c->type = SSH_CHANNEL_INPUT_DRAINING; 14540Sstevel@tonic-gate } else { 14550Sstevel@tonic-gate chan_write_failed(c); 14560Sstevel@tonic-gate } 14570Sstevel@tonic-gate return -1; 14580Sstevel@tonic-gate } 14590Sstevel@tonic-gate if (compat20 && c->isatty && dlen >= 1 && data[0] != '\r') { 14600Sstevel@tonic-gate if (tcgetattr(c->wfd, &tio) == 0 && 14610Sstevel@tonic-gate !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { 14620Sstevel@tonic-gate /* 14630Sstevel@tonic-gate * Simulate echo to reduce the impact of 14640Sstevel@tonic-gate * traffic analysis. We need to match the 14650Sstevel@tonic-gate * size of a SSH2_MSG_CHANNEL_DATA message 14660Sstevel@tonic-gate * (4 byte channel id + data) 14670Sstevel@tonic-gate */ 14680Sstevel@tonic-gate packet_send_ignore(4 + len); 14690Sstevel@tonic-gate packet_send(); 14700Sstevel@tonic-gate } 14710Sstevel@tonic-gate } 14720Sstevel@tonic-gate buffer_consume(&c->output, len); 14730Sstevel@tonic-gate if (compat20 && len > 0) { 14740Sstevel@tonic-gate c->local_consumed += len; 14750Sstevel@tonic-gate } 14760Sstevel@tonic-gate } 14770Sstevel@tonic-gate return 1; 14780Sstevel@tonic-gate } 14790Sstevel@tonic-gate static int 14800Sstevel@tonic-gate channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) 14810Sstevel@tonic-gate { 14820Sstevel@tonic-gate char buf[16*1024]; 14830Sstevel@tonic-gate int len; 14840Sstevel@tonic-gate 14850Sstevel@tonic-gate /** XXX handle drain efd, too */ 14860Sstevel@tonic-gate if (c->efd != -1) { 14870Sstevel@tonic-gate if (c->extended_usage == CHAN_EXTENDED_WRITE && 14880Sstevel@tonic-gate FD_ISSET(c->efd, writeset) && 14890Sstevel@tonic-gate buffer_len(&c->extended) > 0) { 14900Sstevel@tonic-gate len = write(c->efd, buffer_ptr(&c->extended), 14910Sstevel@tonic-gate buffer_len(&c->extended)); 14920Sstevel@tonic-gate debug2("channel %d: written %d to efd %d", 14930Sstevel@tonic-gate c->self, len, c->efd); 14940Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) 14950Sstevel@tonic-gate return 1; 14960Sstevel@tonic-gate if (len <= 0) { 14970Sstevel@tonic-gate debug2("channel %d: closing write-efd %d", 14980Sstevel@tonic-gate c->self, c->efd); 14990Sstevel@tonic-gate channel_close_fd(&c->efd); 15000Sstevel@tonic-gate } else { 15010Sstevel@tonic-gate buffer_consume(&c->extended, len); 15020Sstevel@tonic-gate c->local_consumed += len; 15030Sstevel@tonic-gate } 15040Sstevel@tonic-gate } else if (c->extended_usage == CHAN_EXTENDED_READ && 15050Sstevel@tonic-gate FD_ISSET(c->efd, readset)) { 15060Sstevel@tonic-gate len = read(c->efd, buf, sizeof(buf)); 15070Sstevel@tonic-gate debug2("channel %d: read %d from efd %d", 15080Sstevel@tonic-gate c->self, len, c->efd); 15090Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) 15100Sstevel@tonic-gate return 1; 15110Sstevel@tonic-gate if (len <= 0) { 15120Sstevel@tonic-gate debug2("channel %d: closing read-efd %d", 15130Sstevel@tonic-gate c->self, c->efd); 15140Sstevel@tonic-gate channel_close_fd(&c->efd); 15150Sstevel@tonic-gate } else { 15160Sstevel@tonic-gate buffer_append(&c->extended, buf, len); 15170Sstevel@tonic-gate } 15180Sstevel@tonic-gate } 15190Sstevel@tonic-gate } 15200Sstevel@tonic-gate return 1; 15210Sstevel@tonic-gate } 15220Sstevel@tonic-gate static int 15230Sstevel@tonic-gate channel_check_window(Channel *c) 15240Sstevel@tonic-gate { 15250Sstevel@tonic-gate if (c->type == SSH_CHANNEL_OPEN && 15260Sstevel@tonic-gate !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && 15270Sstevel@tonic-gate c->local_window < c->local_window_max/2 && 15280Sstevel@tonic-gate c->local_consumed > 0) { 15290Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); 15300Sstevel@tonic-gate packet_put_int(c->remote_id); 15310Sstevel@tonic-gate packet_put_int(c->local_consumed); 15320Sstevel@tonic-gate packet_send(); 15330Sstevel@tonic-gate debug2("channel %d: window %d sent adjust %d", 15340Sstevel@tonic-gate c->self, c->local_window, 15350Sstevel@tonic-gate c->local_consumed); 15360Sstevel@tonic-gate c->local_window += c->local_consumed; 15370Sstevel@tonic-gate c->local_consumed = 0; 15380Sstevel@tonic-gate } 15390Sstevel@tonic-gate return 1; 15400Sstevel@tonic-gate } 15410Sstevel@tonic-gate 15420Sstevel@tonic-gate static void 15430Sstevel@tonic-gate channel_post_open(Channel *c, fd_set * readset, fd_set * writeset) 15440Sstevel@tonic-gate { 15450Sstevel@tonic-gate if (c->delayed) 15460Sstevel@tonic-gate return; 15470Sstevel@tonic-gate channel_handle_rfd(c, readset, writeset); 15480Sstevel@tonic-gate channel_handle_wfd(c, readset, writeset); 15490Sstevel@tonic-gate if (!compat20) 15500Sstevel@tonic-gate return; 15510Sstevel@tonic-gate channel_handle_efd(c, readset, writeset); 15520Sstevel@tonic-gate channel_check_window(c); 15530Sstevel@tonic-gate } 15540Sstevel@tonic-gate 15550Sstevel@tonic-gate static void 15560Sstevel@tonic-gate channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) 15570Sstevel@tonic-gate { 15580Sstevel@tonic-gate int len; 15590Sstevel@tonic-gate 15600Sstevel@tonic-gate /* Send buffered output data to the socket. */ 15610Sstevel@tonic-gate if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) { 15620Sstevel@tonic-gate len = write(c->sock, buffer_ptr(&c->output), 15630Sstevel@tonic-gate buffer_len(&c->output)); 15640Sstevel@tonic-gate if (len <= 0) 15650Sstevel@tonic-gate buffer_clear(&c->output); 15660Sstevel@tonic-gate else 15670Sstevel@tonic-gate buffer_consume(&c->output, len); 15680Sstevel@tonic-gate } 15690Sstevel@tonic-gate } 15700Sstevel@tonic-gate 15710Sstevel@tonic-gate static void 15720Sstevel@tonic-gate channel_handler_init_20(void) 15730Sstevel@tonic-gate { 15740Sstevel@tonic-gate channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open; 15750Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; 15760Sstevel@tonic-gate channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; 15770Sstevel@tonic-gate channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; 15780Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; 15790Sstevel@tonic-gate channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 15800Sstevel@tonic-gate channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 15810Sstevel@tonic-gate channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; 15820Sstevel@tonic-gate 15830Sstevel@tonic-gate channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; 15840Sstevel@tonic-gate channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 15850Sstevel@tonic-gate channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; 15860Sstevel@tonic-gate channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; 15870Sstevel@tonic-gate channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 15880Sstevel@tonic-gate channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 15890Sstevel@tonic-gate channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; 15900Sstevel@tonic-gate } 15910Sstevel@tonic-gate 15920Sstevel@tonic-gate static void 15930Sstevel@tonic-gate channel_handler_init_13(void) 15940Sstevel@tonic-gate { 15950Sstevel@tonic-gate channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13; 15960Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open_13; 15970Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; 15980Sstevel@tonic-gate channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; 15990Sstevel@tonic-gate channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 16000Sstevel@tonic-gate channel_pre[SSH_CHANNEL_INPUT_DRAINING] = &channel_pre_input_draining; 16010Sstevel@tonic-gate channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining; 16020Sstevel@tonic-gate channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 16030Sstevel@tonic-gate channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; 16060Sstevel@tonic-gate channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; 16070Sstevel@tonic-gate channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 16080Sstevel@tonic-gate channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 16090Sstevel@tonic-gate channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13; 16100Sstevel@tonic-gate channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 16110Sstevel@tonic-gate channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; 16120Sstevel@tonic-gate } 16130Sstevel@tonic-gate 16140Sstevel@tonic-gate static void 16150Sstevel@tonic-gate channel_handler_init_15(void) 16160Sstevel@tonic-gate { 16170Sstevel@tonic-gate channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open; 16180Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; 16190Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; 16200Sstevel@tonic-gate channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; 16210Sstevel@tonic-gate channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 16220Sstevel@tonic-gate channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 16230Sstevel@tonic-gate channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; 16240Sstevel@tonic-gate 16250Sstevel@tonic-gate channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; 16260Sstevel@tonic-gate channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 16270Sstevel@tonic-gate channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 16280Sstevel@tonic-gate channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; 16290Sstevel@tonic-gate channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 16300Sstevel@tonic-gate channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; 16310Sstevel@tonic-gate } 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate static void 16340Sstevel@tonic-gate channel_handler_init(void) 16350Sstevel@tonic-gate { 16360Sstevel@tonic-gate int i; 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) { 16390Sstevel@tonic-gate channel_pre[i] = NULL; 16400Sstevel@tonic-gate channel_post[i] = NULL; 16410Sstevel@tonic-gate } 16420Sstevel@tonic-gate if (compat20) 16430Sstevel@tonic-gate channel_handler_init_20(); 16440Sstevel@tonic-gate else if (compat13) 16450Sstevel@tonic-gate channel_handler_init_13(); 16460Sstevel@tonic-gate else 16470Sstevel@tonic-gate channel_handler_init_15(); 16480Sstevel@tonic-gate } 16490Sstevel@tonic-gate 16500Sstevel@tonic-gate /* gc dead channels */ 16510Sstevel@tonic-gate static void 16520Sstevel@tonic-gate channel_garbage_collect(Channel *c) 16530Sstevel@tonic-gate { 16540Sstevel@tonic-gate if (c == NULL) 16550Sstevel@tonic-gate return; 16560Sstevel@tonic-gate if (c->detach_user != NULL) { 16570Sstevel@tonic-gate if (!chan_is_dead(c, 0)) 16580Sstevel@tonic-gate return; 16590Sstevel@tonic-gate debug("channel %d: gc: notify user", c->self); 16600Sstevel@tonic-gate c->detach_user(c->self, NULL); 16610Sstevel@tonic-gate /* if we still have a callback */ 16620Sstevel@tonic-gate if (c->detach_user != NULL) 16630Sstevel@tonic-gate return; 16640Sstevel@tonic-gate debug("channel %d: gc: user detached", c->self); 16650Sstevel@tonic-gate } 16660Sstevel@tonic-gate if (!c->wait_for_exit && !chan_is_dead(c, 1)) 16670Sstevel@tonic-gate return; 16680Sstevel@tonic-gate debug("channel %d: garbage collecting", c->self); 16690Sstevel@tonic-gate channel_free(c); 16700Sstevel@tonic-gate } 16710Sstevel@tonic-gate 16720Sstevel@tonic-gate static void 16730Sstevel@tonic-gate channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) 16740Sstevel@tonic-gate { 16750Sstevel@tonic-gate static int did_init = 0; 16760Sstevel@tonic-gate int i; 16770Sstevel@tonic-gate Channel *c; 16780Sstevel@tonic-gate 16790Sstevel@tonic-gate if (!did_init) { 16800Sstevel@tonic-gate channel_handler_init(); 16810Sstevel@tonic-gate did_init = 1; 16820Sstevel@tonic-gate } 16830Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 16840Sstevel@tonic-gate c = channels[i]; 16850Sstevel@tonic-gate if (c == NULL) 16860Sstevel@tonic-gate continue; 16870Sstevel@tonic-gate if (ftab[c->type] != NULL) 16880Sstevel@tonic-gate (*ftab[c->type])(c, readset, writeset); 16890Sstevel@tonic-gate channel_garbage_collect(c); 16900Sstevel@tonic-gate } 16910Sstevel@tonic-gate } 16920Sstevel@tonic-gate 16930Sstevel@tonic-gate /* 16940Sstevel@tonic-gate * Allocate/update select bitmasks and add any bits relevant to channels in 16950Sstevel@tonic-gate * select bitmasks. 16960Sstevel@tonic-gate */ 16970Sstevel@tonic-gate void 16980Sstevel@tonic-gate channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, 16990Sstevel@tonic-gate int *nallocp, int rekeying) 17000Sstevel@tonic-gate { 17010Sstevel@tonic-gate int n; 17020Sstevel@tonic-gate u_int sz; 17030Sstevel@tonic-gate 17040Sstevel@tonic-gate n = MAX(*maxfdp, channel_max_fd); 17050Sstevel@tonic-gate 17060Sstevel@tonic-gate sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); 17070Sstevel@tonic-gate /* perhaps check sz < nalloc/2 and shrink? */ 17080Sstevel@tonic-gate if (*readsetp == NULL || sz > *nallocp) { 17090Sstevel@tonic-gate *readsetp = xrealloc(*readsetp, sz); 17100Sstevel@tonic-gate *writesetp = xrealloc(*writesetp, sz); 17110Sstevel@tonic-gate *nallocp = sz; 17120Sstevel@tonic-gate } 17130Sstevel@tonic-gate *maxfdp = n; 17140Sstevel@tonic-gate memset(*readsetp, 0, sz); 17150Sstevel@tonic-gate memset(*writesetp, 0, sz); 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate if (!rekeying) 17180Sstevel@tonic-gate channel_handler(channel_pre, *readsetp, *writesetp); 17190Sstevel@tonic-gate } 17200Sstevel@tonic-gate 17210Sstevel@tonic-gate /* 17220Sstevel@tonic-gate * After select, perform any appropriate operations for channels which have 17230Sstevel@tonic-gate * events pending. 17240Sstevel@tonic-gate */ 17250Sstevel@tonic-gate void 17260Sstevel@tonic-gate channel_after_select(fd_set * readset, fd_set * writeset) 17270Sstevel@tonic-gate { 17280Sstevel@tonic-gate channel_handler(channel_post, readset, writeset); 17290Sstevel@tonic-gate } 17300Sstevel@tonic-gate 17310Sstevel@tonic-gate 17320Sstevel@tonic-gate /* If there is data to send to the connection, enqueue some of it now. */ 17330Sstevel@tonic-gate 17340Sstevel@tonic-gate void 17350Sstevel@tonic-gate channel_output_poll(void) 17360Sstevel@tonic-gate { 17370Sstevel@tonic-gate Channel *c; 17380Sstevel@tonic-gate int i; 17390Sstevel@tonic-gate u_int len; 17400Sstevel@tonic-gate 17410Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 17420Sstevel@tonic-gate c = channels[i]; 17430Sstevel@tonic-gate if (c == NULL) 17440Sstevel@tonic-gate continue; 17450Sstevel@tonic-gate 17460Sstevel@tonic-gate /* 17470Sstevel@tonic-gate * We are only interested in channels that can have buffered 17480Sstevel@tonic-gate * incoming data. 17490Sstevel@tonic-gate */ 17500Sstevel@tonic-gate if (compat13) { 17510Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN && 17520Sstevel@tonic-gate c->type != SSH_CHANNEL_INPUT_DRAINING) 17530Sstevel@tonic-gate continue; 17540Sstevel@tonic-gate } else { 17550Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN) 17560Sstevel@tonic-gate continue; 17570Sstevel@tonic-gate } 17580Sstevel@tonic-gate if (compat20 && 17590Sstevel@tonic-gate (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { 17600Sstevel@tonic-gate /* XXX is this true? */ 17610Sstevel@tonic-gate debug3("channel %d: will not send data after close", c->self); 17620Sstevel@tonic-gate continue; 17630Sstevel@tonic-gate } 17640Sstevel@tonic-gate 17650Sstevel@tonic-gate /* Get the amount of buffered data for this channel. */ 17660Sstevel@tonic-gate if ((c->istate == CHAN_INPUT_OPEN || 17670Sstevel@tonic-gate c->istate == CHAN_INPUT_WAIT_DRAIN) && 17680Sstevel@tonic-gate (len = buffer_len(&c->input)) > 0) { 17690Sstevel@tonic-gate /* 17700Sstevel@tonic-gate * Send some data for the other side over the secure 17710Sstevel@tonic-gate * connection. 17720Sstevel@tonic-gate */ 17730Sstevel@tonic-gate if (compat20) { 17740Sstevel@tonic-gate if (len > c->remote_window) 17750Sstevel@tonic-gate len = c->remote_window; 17760Sstevel@tonic-gate if (len > c->remote_maxpacket) 17770Sstevel@tonic-gate len = c->remote_maxpacket; 17780Sstevel@tonic-gate } else { 17790Sstevel@tonic-gate if (packet_is_interactive()) { 17800Sstevel@tonic-gate if (len > 1024) 17810Sstevel@tonic-gate len = 512; 17820Sstevel@tonic-gate } else { 17830Sstevel@tonic-gate /* Keep the packets at reasonable size. */ 17840Sstevel@tonic-gate if (len > packet_get_maxsize()/2) 17850Sstevel@tonic-gate len = packet_get_maxsize()/2; 17860Sstevel@tonic-gate } 17870Sstevel@tonic-gate } 17880Sstevel@tonic-gate if (len > 0) { 17890Sstevel@tonic-gate packet_start(compat20 ? 17900Sstevel@tonic-gate SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA); 17910Sstevel@tonic-gate packet_put_int(c->remote_id); 17920Sstevel@tonic-gate packet_put_string(buffer_ptr(&c->input), len); 17930Sstevel@tonic-gate packet_send(); 17940Sstevel@tonic-gate buffer_consume(&c->input, len); 17950Sstevel@tonic-gate c->remote_window -= len; 17960Sstevel@tonic-gate } 17970Sstevel@tonic-gate } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) { 17980Sstevel@tonic-gate if (compat13) 17990Sstevel@tonic-gate fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); 18000Sstevel@tonic-gate /* 18010Sstevel@tonic-gate * input-buffer is empty and read-socket shutdown: 18020Sstevel@tonic-gate * tell peer, that we will not send more data: send IEOF. 18030Sstevel@tonic-gate * hack for extended data: delay EOF if EFD still in use. 18040Sstevel@tonic-gate */ 18050Sstevel@tonic-gate if (CHANNEL_EFD_INPUT_ACTIVE(c)) 18060Sstevel@tonic-gate debug2("channel %d: ibuf_empty delayed efd %d/(%d)", 18070Sstevel@tonic-gate c->self, c->efd, buffer_len(&c->extended)); 18080Sstevel@tonic-gate else 18090Sstevel@tonic-gate chan_ibuf_empty(c); 18100Sstevel@tonic-gate } 18110Sstevel@tonic-gate /* Send extended data, i.e. stderr */ 18120Sstevel@tonic-gate if (compat20 && 18130Sstevel@tonic-gate !(c->flags & CHAN_EOF_SENT) && 18140Sstevel@tonic-gate c->remote_window > 0 && 18150Sstevel@tonic-gate (len = buffer_len(&c->extended)) > 0 && 18160Sstevel@tonic-gate c->extended_usage == CHAN_EXTENDED_READ) { 18170Sstevel@tonic-gate debug2("channel %d: rwin %u elen %u euse %d", 18180Sstevel@tonic-gate c->self, c->remote_window, buffer_len(&c->extended), 18190Sstevel@tonic-gate c->extended_usage); 18200Sstevel@tonic-gate if (len > c->remote_window) 18210Sstevel@tonic-gate len = c->remote_window; 18220Sstevel@tonic-gate if (len > c->remote_maxpacket) 18230Sstevel@tonic-gate len = c->remote_maxpacket; 18240Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA); 18250Sstevel@tonic-gate packet_put_int(c->remote_id); 18260Sstevel@tonic-gate packet_put_int(SSH2_EXTENDED_DATA_STDERR); 18270Sstevel@tonic-gate packet_put_string(buffer_ptr(&c->extended), len); 18280Sstevel@tonic-gate packet_send(); 18290Sstevel@tonic-gate buffer_consume(&c->extended, len); 18300Sstevel@tonic-gate c->remote_window -= len; 18310Sstevel@tonic-gate debug2("channel %d: sent ext data %d", c->self, len); 18320Sstevel@tonic-gate } 18330Sstevel@tonic-gate } 18340Sstevel@tonic-gate } 18350Sstevel@tonic-gate 18360Sstevel@tonic-gate 18370Sstevel@tonic-gate /* -- protocol input */ 18380Sstevel@tonic-gate 18390Sstevel@tonic-gate void 18400Sstevel@tonic-gate channel_input_data(int type, u_int32_t seq, void *ctxt) 18410Sstevel@tonic-gate { 18420Sstevel@tonic-gate int id; 18430Sstevel@tonic-gate char *data; 18440Sstevel@tonic-gate u_int data_len; 18450Sstevel@tonic-gate Channel *c; 18460Sstevel@tonic-gate 18470Sstevel@tonic-gate /* Get the channel number and verify it. */ 18480Sstevel@tonic-gate id = packet_get_int(); 18490Sstevel@tonic-gate c = channel_lookup(id); 18500Sstevel@tonic-gate if (c == NULL) 18510Sstevel@tonic-gate packet_disconnect("Received data for nonexistent channel %d.", id); 18520Sstevel@tonic-gate 18530Sstevel@tonic-gate /* Ignore any data for non-open channels (might happen on close) */ 18540Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN && 18550Sstevel@tonic-gate c->type != SSH_CHANNEL_X11_OPEN) 18560Sstevel@tonic-gate return; 18570Sstevel@tonic-gate 18580Sstevel@tonic-gate /* same for protocol 1.5 if output end is no longer open */ 18590Sstevel@tonic-gate if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) 18600Sstevel@tonic-gate return; 18610Sstevel@tonic-gate 18620Sstevel@tonic-gate /* Get the data. */ 18630Sstevel@tonic-gate data = packet_get_string(&data_len); 18640Sstevel@tonic-gate 18650Sstevel@tonic-gate if (compat20) { 18660Sstevel@tonic-gate if (data_len > c->local_maxpacket) { 18670Sstevel@tonic-gate log("channel %d: rcvd big packet %d, maxpack %d", 18680Sstevel@tonic-gate c->self, data_len, c->local_maxpacket); 18690Sstevel@tonic-gate } 18700Sstevel@tonic-gate if (data_len > c->local_window) { 18710Sstevel@tonic-gate log("channel %d: rcvd too much data %d, win %d", 18720Sstevel@tonic-gate c->self, data_len, c->local_window); 18730Sstevel@tonic-gate xfree(data); 18740Sstevel@tonic-gate return; 18750Sstevel@tonic-gate } 18760Sstevel@tonic-gate c->local_window -= data_len; 18770Sstevel@tonic-gate } 18780Sstevel@tonic-gate packet_check_eom(); 18790Sstevel@tonic-gate buffer_append(&c->output, data, data_len); 18800Sstevel@tonic-gate xfree(data); 18810Sstevel@tonic-gate } 18820Sstevel@tonic-gate 18830Sstevel@tonic-gate void 18840Sstevel@tonic-gate channel_input_extended_data(int type, u_int32_t seq, void *ctxt) 18850Sstevel@tonic-gate { 18860Sstevel@tonic-gate int id; 18870Sstevel@tonic-gate char *data; 18880Sstevel@tonic-gate u_int data_len, tcode; 18890Sstevel@tonic-gate Channel *c; 18900Sstevel@tonic-gate 18910Sstevel@tonic-gate /* Get the channel number and verify it. */ 18920Sstevel@tonic-gate id = packet_get_int(); 18930Sstevel@tonic-gate c = channel_lookup(id); 18940Sstevel@tonic-gate 18950Sstevel@tonic-gate if (c == NULL) 18960Sstevel@tonic-gate packet_disconnect("Received extended_data for bad channel %d.", id); 18970Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN) { 18980Sstevel@tonic-gate log("channel %d: ext data for non open", id); 18990Sstevel@tonic-gate return; 19000Sstevel@tonic-gate } 19010Sstevel@tonic-gate if (c->flags & CHAN_EOF_RCVD) { 19020Sstevel@tonic-gate if (datafellows & SSH_BUG_EXTEOF) 19030Sstevel@tonic-gate debug("channel %d: accepting ext data after eof", id); 19040Sstevel@tonic-gate else 19050Sstevel@tonic-gate packet_disconnect("Received extended_data after EOF " 19060Sstevel@tonic-gate "on channel %d.", id); 19070Sstevel@tonic-gate } 19080Sstevel@tonic-gate tcode = packet_get_int(); 19090Sstevel@tonic-gate if (c->efd == -1 || 19100Sstevel@tonic-gate c->extended_usage != CHAN_EXTENDED_WRITE || 19110Sstevel@tonic-gate tcode != SSH2_EXTENDED_DATA_STDERR) { 19120Sstevel@tonic-gate log("channel %d: bad ext data", c->self); 19130Sstevel@tonic-gate return; 19140Sstevel@tonic-gate } 19150Sstevel@tonic-gate data = packet_get_string(&data_len); 19160Sstevel@tonic-gate packet_check_eom(); 19170Sstevel@tonic-gate if (data_len > c->local_window) { 19180Sstevel@tonic-gate log("channel %d: rcvd too much extended_data %d, win %d", 19190Sstevel@tonic-gate c->self, data_len, c->local_window); 19200Sstevel@tonic-gate xfree(data); 19210Sstevel@tonic-gate return; 19220Sstevel@tonic-gate } 19230Sstevel@tonic-gate debug2("channel %d: rcvd ext data %d", c->self, data_len); 19240Sstevel@tonic-gate c->local_window -= data_len; 19250Sstevel@tonic-gate buffer_append(&c->extended, data, data_len); 19260Sstevel@tonic-gate xfree(data); 19270Sstevel@tonic-gate } 19280Sstevel@tonic-gate 19290Sstevel@tonic-gate void 19300Sstevel@tonic-gate channel_input_ieof(int type, u_int32_t seq, void *ctxt) 19310Sstevel@tonic-gate { 19320Sstevel@tonic-gate int id; 19330Sstevel@tonic-gate Channel *c; 19340Sstevel@tonic-gate 19350Sstevel@tonic-gate id = packet_get_int(); 19360Sstevel@tonic-gate packet_check_eom(); 19370Sstevel@tonic-gate c = channel_lookup(id); 19380Sstevel@tonic-gate if (c == NULL) 19390Sstevel@tonic-gate packet_disconnect("Received ieof for nonexistent channel %d.", id); 19400Sstevel@tonic-gate chan_rcvd_ieof(c); 19410Sstevel@tonic-gate 19420Sstevel@tonic-gate /* XXX force input close */ 19430Sstevel@tonic-gate if (c->force_drain && c->istate == CHAN_INPUT_OPEN) { 19440Sstevel@tonic-gate debug("channel %d: FORCE input drain", c->self); 19450Sstevel@tonic-gate c->istate = CHAN_INPUT_WAIT_DRAIN; 19460Sstevel@tonic-gate if (buffer_len(&c->input) == 0) 19470Sstevel@tonic-gate chan_ibuf_empty(c); 19480Sstevel@tonic-gate } 19490Sstevel@tonic-gate 19500Sstevel@tonic-gate } 19510Sstevel@tonic-gate 19520Sstevel@tonic-gate void 19530Sstevel@tonic-gate channel_input_close(int type, u_int32_t seq, void *ctxt) 19540Sstevel@tonic-gate { 19550Sstevel@tonic-gate int id; 19560Sstevel@tonic-gate Channel *c; 19570Sstevel@tonic-gate 19580Sstevel@tonic-gate id = packet_get_int(); 19590Sstevel@tonic-gate packet_check_eom(); 19600Sstevel@tonic-gate c = channel_lookup(id); 19610Sstevel@tonic-gate if (c == NULL) 19620Sstevel@tonic-gate packet_disconnect("Received close for nonexistent channel %d.", id); 19630Sstevel@tonic-gate 19640Sstevel@tonic-gate /* 19650Sstevel@tonic-gate * Send a confirmation that we have closed the channel and no more 19660Sstevel@tonic-gate * data is coming for it. 19670Sstevel@tonic-gate */ 19680Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); 19690Sstevel@tonic-gate packet_put_int(c->remote_id); 19700Sstevel@tonic-gate packet_send(); 19710Sstevel@tonic-gate 19720Sstevel@tonic-gate /* 19730Sstevel@tonic-gate * If the channel is in closed state, we have sent a close request, 19740Sstevel@tonic-gate * and the other side will eventually respond with a confirmation. 19750Sstevel@tonic-gate * Thus, we cannot free the channel here, because then there would be 19760Sstevel@tonic-gate * no-one to receive the confirmation. The channel gets freed when 19770Sstevel@tonic-gate * the confirmation arrives. 19780Sstevel@tonic-gate */ 19790Sstevel@tonic-gate if (c->type != SSH_CHANNEL_CLOSED) { 19800Sstevel@tonic-gate /* 19810Sstevel@tonic-gate * Not a closed channel - mark it as draining, which will 19820Sstevel@tonic-gate * cause it to be freed later. 19830Sstevel@tonic-gate */ 19840Sstevel@tonic-gate buffer_clear(&c->input); 19850Sstevel@tonic-gate c->type = SSH_CHANNEL_OUTPUT_DRAINING; 19860Sstevel@tonic-gate } 19870Sstevel@tonic-gate } 19880Sstevel@tonic-gate 19890Sstevel@tonic-gate /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ 19900Sstevel@tonic-gate void 19910Sstevel@tonic-gate channel_input_oclose(int type, u_int32_t seq, void *ctxt) 19920Sstevel@tonic-gate { 19930Sstevel@tonic-gate int id = packet_get_int(); 19940Sstevel@tonic-gate Channel *c = channel_lookup(id); 19950Sstevel@tonic-gate 19960Sstevel@tonic-gate packet_check_eom(); 19970Sstevel@tonic-gate if (c == NULL) 19980Sstevel@tonic-gate packet_disconnect("Received oclose for nonexistent channel %d.", id); 19990Sstevel@tonic-gate chan_rcvd_oclose(c); 20000Sstevel@tonic-gate } 20010Sstevel@tonic-gate 20020Sstevel@tonic-gate void 20030Sstevel@tonic-gate channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt) 20040Sstevel@tonic-gate { 20050Sstevel@tonic-gate int id = packet_get_int(); 20060Sstevel@tonic-gate Channel *c = channel_lookup(id); 20070Sstevel@tonic-gate 20080Sstevel@tonic-gate packet_check_eom(); 20090Sstevel@tonic-gate if (c == NULL) 20100Sstevel@tonic-gate packet_disconnect("Received close confirmation for " 20110Sstevel@tonic-gate "out-of-range channel %d.", id); 20120Sstevel@tonic-gate if (c->type != SSH_CHANNEL_CLOSED) 20130Sstevel@tonic-gate packet_disconnect("Received close confirmation for " 20140Sstevel@tonic-gate "non-closed channel %d (type %d).", id, c->type); 20150Sstevel@tonic-gate channel_free(c); 20160Sstevel@tonic-gate } 20170Sstevel@tonic-gate 20180Sstevel@tonic-gate void 20190Sstevel@tonic-gate channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) 20200Sstevel@tonic-gate { 20210Sstevel@tonic-gate int id, remote_id; 20220Sstevel@tonic-gate Channel *c; 20230Sstevel@tonic-gate 20240Sstevel@tonic-gate id = packet_get_int(); 20250Sstevel@tonic-gate c = channel_lookup(id); 20260Sstevel@tonic-gate 20270Sstevel@tonic-gate if (c==NULL || c->type != SSH_CHANNEL_OPENING) 20280Sstevel@tonic-gate packet_disconnect("Received open confirmation for " 20290Sstevel@tonic-gate "non-opening channel %d.", id); 20300Sstevel@tonic-gate remote_id = packet_get_int(); 20310Sstevel@tonic-gate /* Record the remote channel number and mark that the channel is now open. */ 20320Sstevel@tonic-gate c->remote_id = remote_id; 20330Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 20340Sstevel@tonic-gate 20350Sstevel@tonic-gate if (compat20) { 20360Sstevel@tonic-gate c->remote_window = packet_get_int(); 20370Sstevel@tonic-gate c->remote_maxpacket = packet_get_int(); 20380Sstevel@tonic-gate if (c->confirm) { 20390Sstevel@tonic-gate debug2("callback start"); 20400Sstevel@tonic-gate c->confirm(c->self, NULL); 20410Sstevel@tonic-gate debug2("callback done"); 20420Sstevel@tonic-gate } 20430Sstevel@tonic-gate debug("channel %d: open confirm rwindow %u rmax %u", c->self, 20440Sstevel@tonic-gate c->remote_window, c->remote_maxpacket); 20450Sstevel@tonic-gate } 20460Sstevel@tonic-gate packet_check_eom(); 20470Sstevel@tonic-gate } 20480Sstevel@tonic-gate 20490Sstevel@tonic-gate static char * 20500Sstevel@tonic-gate reason2txt(int reason) 20510Sstevel@tonic-gate { 20520Sstevel@tonic-gate switch (reason) { 20530Sstevel@tonic-gate case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED: 20540Sstevel@tonic-gate return "administratively prohibited"; 20550Sstevel@tonic-gate case SSH2_OPEN_CONNECT_FAILED: 20560Sstevel@tonic-gate return "connect failed"; 20570Sstevel@tonic-gate case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE: 20580Sstevel@tonic-gate return "unknown channel type"; 20590Sstevel@tonic-gate case SSH2_OPEN_RESOURCE_SHORTAGE: 20600Sstevel@tonic-gate return "resource shortage"; 20610Sstevel@tonic-gate } 20620Sstevel@tonic-gate return "unknown reason"; 20630Sstevel@tonic-gate } 20640Sstevel@tonic-gate 20650Sstevel@tonic-gate void 20660Sstevel@tonic-gate channel_input_open_failure(int type, u_int32_t seq, void *ctxt) 20670Sstevel@tonic-gate { 20680Sstevel@tonic-gate int id, reason; 20690Sstevel@tonic-gate char *msg = NULL, *lang = NULL; 20700Sstevel@tonic-gate Channel *c; 20710Sstevel@tonic-gate 20720Sstevel@tonic-gate id = packet_get_int(); 20730Sstevel@tonic-gate c = channel_lookup(id); 20740Sstevel@tonic-gate 20750Sstevel@tonic-gate if (c==NULL || c->type != SSH_CHANNEL_OPENING) 20760Sstevel@tonic-gate packet_disconnect("Received open failure for " 20770Sstevel@tonic-gate "non-opening channel %d.", id); 20780Sstevel@tonic-gate if (compat20) { 20790Sstevel@tonic-gate reason = packet_get_int(); 20800Sstevel@tonic-gate if (!(datafellows & SSH_BUG_OPENFAILURE)) { 20810Sstevel@tonic-gate msg = packet_get_string(NULL); 20820Sstevel@tonic-gate lang = packet_get_string(NULL); 20830Sstevel@tonic-gate } 20840Sstevel@tonic-gate log("channel %d: open failed: %s%s%s", id, 20850Sstevel@tonic-gate reason2txt(reason), msg ? ": ": "", msg ? msg : ""); 20860Sstevel@tonic-gate if (msg != NULL) 20870Sstevel@tonic-gate xfree(msg); 20880Sstevel@tonic-gate if (lang != NULL) 20890Sstevel@tonic-gate xfree(lang); 20900Sstevel@tonic-gate } 20910Sstevel@tonic-gate packet_check_eom(); 20920Sstevel@tonic-gate /* Free the channel. This will also close the socket. */ 20930Sstevel@tonic-gate channel_free(c); 20940Sstevel@tonic-gate } 20950Sstevel@tonic-gate 20960Sstevel@tonic-gate void 20970Sstevel@tonic-gate channel_input_window_adjust(int type, u_int32_t seq, void *ctxt) 20980Sstevel@tonic-gate { 20990Sstevel@tonic-gate Channel *c; 21000Sstevel@tonic-gate int id; 21010Sstevel@tonic-gate u_int adjust; 21020Sstevel@tonic-gate 21030Sstevel@tonic-gate if (!compat20) 21040Sstevel@tonic-gate return; 21050Sstevel@tonic-gate 21060Sstevel@tonic-gate /* Get the channel number and verify it. */ 21070Sstevel@tonic-gate id = packet_get_int(); 21080Sstevel@tonic-gate c = channel_lookup(id); 21090Sstevel@tonic-gate 21100Sstevel@tonic-gate if (c == NULL || c->type != SSH_CHANNEL_OPEN) { 21110Sstevel@tonic-gate log("Received window adjust for " 21120Sstevel@tonic-gate "non-open channel %d.", id); 21130Sstevel@tonic-gate return; 21140Sstevel@tonic-gate } 21150Sstevel@tonic-gate adjust = packet_get_int(); 21160Sstevel@tonic-gate packet_check_eom(); 21170Sstevel@tonic-gate debug2("channel %d: rcvd adjust %u", id, adjust); 21180Sstevel@tonic-gate c->remote_window += adjust; 21190Sstevel@tonic-gate } 21200Sstevel@tonic-gate 21210Sstevel@tonic-gate void 21220Sstevel@tonic-gate channel_input_port_open(int type, u_int32_t seq, void *ctxt) 21230Sstevel@tonic-gate { 21240Sstevel@tonic-gate Channel *c = NULL; 21250Sstevel@tonic-gate u_short host_port; 21260Sstevel@tonic-gate char *host, *originator_string; 21270Sstevel@tonic-gate int remote_id, sock = -1; 21280Sstevel@tonic-gate 21290Sstevel@tonic-gate remote_id = packet_get_int(); 21300Sstevel@tonic-gate host = packet_get_string(NULL); 21310Sstevel@tonic-gate host_port = packet_get_int(); 21320Sstevel@tonic-gate 21330Sstevel@tonic-gate if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) { 21340Sstevel@tonic-gate originator_string = packet_get_string(NULL); 21350Sstevel@tonic-gate } else { 21360Sstevel@tonic-gate originator_string = xstrdup("unknown (remote did not supply name)"); 21370Sstevel@tonic-gate } 21380Sstevel@tonic-gate packet_check_eom(); 21390Sstevel@tonic-gate sock = channel_connect_to(host, host_port); 21400Sstevel@tonic-gate if (sock != -1) { 21410Sstevel@tonic-gate c = channel_new("connected socket", 21420Sstevel@tonic-gate SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0, 21430Sstevel@tonic-gate originator_string, 1); 21440Sstevel@tonic-gate c->remote_id = remote_id; 21450Sstevel@tonic-gate } 21460Sstevel@tonic-gate if (c == NULL) { 21470Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 21480Sstevel@tonic-gate packet_put_int(remote_id); 21490Sstevel@tonic-gate packet_send(); 21500Sstevel@tonic-gate } 21510Sstevel@tonic-gate xfree(host); 21520Sstevel@tonic-gate } 21530Sstevel@tonic-gate 21540Sstevel@tonic-gate 21550Sstevel@tonic-gate /* -- tcp forwarding */ 21560Sstevel@tonic-gate 21570Sstevel@tonic-gate void 21580Sstevel@tonic-gate channel_set_af(int af) 21590Sstevel@tonic-gate { 21600Sstevel@tonic-gate IPv4or6 = af; 21610Sstevel@tonic-gate } 21620Sstevel@tonic-gate 21630Sstevel@tonic-gate static int 21640Sstevel@tonic-gate channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, 21650Sstevel@tonic-gate const char *host_to_connect, u_short port_to_connect, int gateway_ports) 21660Sstevel@tonic-gate { 21670Sstevel@tonic-gate Channel *c; 2168*5334Sjp161948 int sock, r, is_client, on = 1, wildcard = 0, success = 0; 21690Sstevel@tonic-gate struct addrinfo hints, *ai, *aitop; 2170*5334Sjp161948 const char *host, *addr; 21710Sstevel@tonic-gate char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 21720Sstevel@tonic-gate 21730Sstevel@tonic-gate host = (type == SSH_CHANNEL_RPORT_LISTENER) ? 21740Sstevel@tonic-gate listen_addr : host_to_connect; 2175*5334Sjp161948 is_client = (type == SSH_CHANNEL_PORT_LISTENER); 21760Sstevel@tonic-gate 21770Sstevel@tonic-gate if (host == NULL) { 21780Sstevel@tonic-gate error("No forward host name."); 2179*5334Sjp161948 return 0; 21800Sstevel@tonic-gate } 21810Sstevel@tonic-gate if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) { 21820Sstevel@tonic-gate error("Forward host name too long."); 2183*5334Sjp161948 return 0; 21840Sstevel@tonic-gate } 21850Sstevel@tonic-gate 21860Sstevel@tonic-gate /* 2187*5334Sjp161948 * Determine whether or not a port forward listens to loopback, 2188*5334Sjp161948 * specified address or wildcard. On the client, a specified bind 2189*5334Sjp161948 * address will always override gateway_ports. On the server, a 2190*5334Sjp161948 * gateway_ports of 1 (``yes'') will override the client's 2191*5334Sjp161948 * specification and force a wildcard bind, whereas a value of 2 2192*5334Sjp161948 * (``clientspecified'') will bind to whatever address the client 2193*5334Sjp161948 * asked for. 2194*5334Sjp161948 * 2195*5334Sjp161948 * Special-case listen_addrs are: 2196*5334Sjp161948 * 2197*5334Sjp161948 * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR 2198*5334Sjp161948 * "" (empty string), "*" -> wildcard v4/v6 2199*5334Sjp161948 * "localhost" -> loopback v4/v6 2200*5334Sjp161948 */ 2201*5334Sjp161948 addr = NULL; 2202*5334Sjp161948 if (listen_addr == NULL) { 2203*5334Sjp161948 /* No address specified: default to gateway_ports setting */ 2204*5334Sjp161948 if (gateway_ports) 2205*5334Sjp161948 wildcard = 1; 2206*5334Sjp161948 } else if (gateway_ports || is_client) { 2207*5334Sjp161948 if (((datafellows & SSH_OLD_FORWARD_ADDR) && 2208*5334Sjp161948 strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) || 2209*5334Sjp161948 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 || 2210*5334Sjp161948 (!is_client && gateway_ports == 1)) 2211*5334Sjp161948 wildcard = 1; 2212*5334Sjp161948 else if (strcmp(listen_addr, "localhost") != 0) 2213*5334Sjp161948 addr = listen_addr; 2214*5334Sjp161948 } 2215*5334Sjp161948 2216*5334Sjp161948 debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s", 2217*5334Sjp161948 type, wildcard, (addr == NULL) ? "NULL" : addr); 2218*5334Sjp161948 2219*5334Sjp161948 /* 22200Sstevel@tonic-gate * getaddrinfo returns a loopback address if the hostname is 22210Sstevel@tonic-gate * set to NULL and hints.ai_flags is not AI_PASSIVE 22220Sstevel@tonic-gate */ 22230Sstevel@tonic-gate memset(&hints, 0, sizeof(hints)); 22240Sstevel@tonic-gate hints.ai_family = IPv4or6; 2225*5334Sjp161948 hints.ai_flags = wildcard ? AI_PASSIVE : 0; 22260Sstevel@tonic-gate hints.ai_socktype = SOCK_STREAM; 22270Sstevel@tonic-gate snprintf(strport, sizeof strport, "%d", listen_port); 2228*5334Sjp161948 if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { 2229*5334Sjp161948 if (addr == NULL) { 2230*5334Sjp161948 /* This really shouldn't happen */ 2231*5334Sjp161948 packet_disconnect("getaddrinfo: fatal error: %s", 2232*5334Sjp161948 gai_strerror(r)); 2233*5334Sjp161948 } else { 2234*5334Sjp161948 error("channel_setup_fwd_listener: " 2235*5334Sjp161948 "getaddrinfo(%.64s): %s", addr, gai_strerror(r)); 2236*5334Sjp161948 } 2237*5334Sjp161948 return 0; 2238*5334Sjp161948 } 22390Sstevel@tonic-gate 22400Sstevel@tonic-gate for (ai = aitop; ai; ai = ai->ai_next) { 22410Sstevel@tonic-gate if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 22420Sstevel@tonic-gate continue; 22430Sstevel@tonic-gate if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), 22440Sstevel@tonic-gate strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 22450Sstevel@tonic-gate error("channel_setup_fwd_listener: getnameinfo failed"); 22460Sstevel@tonic-gate continue; 22470Sstevel@tonic-gate } 22480Sstevel@tonic-gate /* Create a port to listen for the host. */ 2249*5334Sjp161948 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 22500Sstevel@tonic-gate if (sock < 0) { 22510Sstevel@tonic-gate /* this is no error since kernel may not support ipv6 */ 22520Sstevel@tonic-gate verbose("socket: %.100s", strerror(errno)); 22530Sstevel@tonic-gate continue; 22540Sstevel@tonic-gate } 22550Sstevel@tonic-gate /* 22560Sstevel@tonic-gate * Set socket options. 22570Sstevel@tonic-gate * Allow local port reuse in TIME_WAIT. 22580Sstevel@tonic-gate */ 22590Sstevel@tonic-gate if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, 22600Sstevel@tonic-gate sizeof(on)) == -1) 22610Sstevel@tonic-gate error("setsockopt SO_REUSEADDR: %s", strerror(errno)); 22620Sstevel@tonic-gate 22630Sstevel@tonic-gate debug("Local forwarding listening on %s port %s.", ntop, strport); 22640Sstevel@tonic-gate 22650Sstevel@tonic-gate /* Bind the socket to the address. */ 22660Sstevel@tonic-gate if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 22670Sstevel@tonic-gate /* address can be in use ipv6 address is already bound */ 22680Sstevel@tonic-gate if (!ai->ai_next) 22690Sstevel@tonic-gate error("bind: %.100s", strerror(errno)); 22700Sstevel@tonic-gate else 22710Sstevel@tonic-gate verbose("bind: %.100s", strerror(errno)); 22720Sstevel@tonic-gate 22730Sstevel@tonic-gate close(sock); 22740Sstevel@tonic-gate continue; 22750Sstevel@tonic-gate } 22760Sstevel@tonic-gate /* Start listening for connections on the socket. */ 22770Sstevel@tonic-gate if (listen(sock, 5) < 0) { 22780Sstevel@tonic-gate error("listen: %.100s", strerror(errno)); 22790Sstevel@tonic-gate close(sock); 22800Sstevel@tonic-gate continue; 22810Sstevel@tonic-gate } 22820Sstevel@tonic-gate /* Allocate a channel number for the socket. */ 22830Sstevel@tonic-gate c = channel_new("port listener", type, sock, sock, -1, 22840Sstevel@tonic-gate CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 22850Sstevel@tonic-gate 0, xstrdup("port listener"), 1); 22860Sstevel@tonic-gate strlcpy(c->path, host, sizeof(c->path)); 22870Sstevel@tonic-gate c->host_port = port_to_connect; 22880Sstevel@tonic-gate c->listening_port = listen_port; 22890Sstevel@tonic-gate success = 1; 22900Sstevel@tonic-gate } 22910Sstevel@tonic-gate if (success == 0) 22920Sstevel@tonic-gate error("channel_setup_fwd_listener: cannot listen to port: %d", 22930Sstevel@tonic-gate listen_port); 22940Sstevel@tonic-gate freeaddrinfo(aitop); 22950Sstevel@tonic-gate return success; 22960Sstevel@tonic-gate } 22970Sstevel@tonic-gate 2298*5334Sjp161948 int 2299*5334Sjp161948 channel_cancel_rport_listener(const char *host, u_short port) 2300*5334Sjp161948 { 2301*5334Sjp161948 u_int i; 2302*5334Sjp161948 int found = 0; 2303*5334Sjp161948 2304*5334Sjp161948 for (i = 0; i < channels_alloc; i++) { 2305*5334Sjp161948 Channel *c = channels[i]; 2306*5334Sjp161948 2307*5334Sjp161948 if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER && 2308*5334Sjp161948 strncmp(c->path, host, sizeof(c->path)) == 0 && 2309*5334Sjp161948 c->listening_port == port) { 2310*5334Sjp161948 debug2("%s: close channel %d", __func__, i); 2311*5334Sjp161948 channel_free(c); 2312*5334Sjp161948 found = 1; 2313*5334Sjp161948 } 2314*5334Sjp161948 } 2315*5334Sjp161948 2316*5334Sjp161948 return (found); 2317*5334Sjp161948 } 2318*5334Sjp161948 23190Sstevel@tonic-gate /* protocol local port fwd, used by ssh (and sshd in v1) */ 23200Sstevel@tonic-gate int 2321*5334Sjp161948 channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port, 23220Sstevel@tonic-gate const char *host_to_connect, u_short port_to_connect, int gateway_ports) 23230Sstevel@tonic-gate { 23240Sstevel@tonic-gate return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, 2325*5334Sjp161948 listen_host, listen_port, host_to_connect, port_to_connect, 2326*5334Sjp161948 gateway_ports); 23270Sstevel@tonic-gate } 23280Sstevel@tonic-gate 23290Sstevel@tonic-gate /* protocol v2 remote port fwd, used by sshd */ 23300Sstevel@tonic-gate int 23310Sstevel@tonic-gate channel_setup_remote_fwd_listener(const char *listen_address, 23320Sstevel@tonic-gate u_short listen_port, int gateway_ports) 23330Sstevel@tonic-gate { 23340Sstevel@tonic-gate return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, 23350Sstevel@tonic-gate listen_address, listen_port, NULL, 0, gateway_ports); 23360Sstevel@tonic-gate } 23370Sstevel@tonic-gate 23380Sstevel@tonic-gate /* 23390Sstevel@tonic-gate * Initiate forwarding of connections to port "port" on remote host through 23400Sstevel@tonic-gate * the secure channel to host:port from local side. 23410Sstevel@tonic-gate */ 23420Sstevel@tonic-gate 2343*5334Sjp161948 int 2344*5334Sjp161948 channel_request_remote_forwarding(const char *listen_host, u_short listen_port, 23450Sstevel@tonic-gate const char *host_to_connect, u_short port_to_connect) 23460Sstevel@tonic-gate { 23470Sstevel@tonic-gate int type, success = 0; 23480Sstevel@tonic-gate 23490Sstevel@tonic-gate /* Record locally that connection to this host/port is permitted. */ 23500Sstevel@tonic-gate if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) 23510Sstevel@tonic-gate fatal("channel_request_remote_forwarding: too many forwards"); 23520Sstevel@tonic-gate 2353*5334Sjp161948 if (listen_host != NULL && 2354*5334Sjp161948 strlen(listen_host) > SSH_CHANNEL_PATH_LEN - 1) { 2355*5334Sjp161948 error("Binding address too long."); 2356*5334Sjp161948 return -1; 2357*5334Sjp161948 } 2358*5334Sjp161948 23590Sstevel@tonic-gate /* Send the forward request to the remote side. */ 23600Sstevel@tonic-gate if (compat20) { 2361*5334Sjp161948 const char *address_to_bind; 2362*5334Sjp161948 if (listen_host == NULL) { 2363*5334Sjp161948 if (datafellows & SSH_BUG_RFWD_ADDR) 2364*5334Sjp161948 address_to_bind = "127.0.0.1"; 2365*5334Sjp161948 else 2366*5334Sjp161948 address_to_bind = "localhost"; 2367*5334Sjp161948 } else if (*listen_host == '\0' || 2368*5334Sjp161948 strcmp(listen_host, "*") == 0) { 2369*5334Sjp161948 if (datafellows & SSH_BUG_RFWD_ADDR) 2370*5334Sjp161948 address_to_bind = "0.0.0.0"; 2371*5334Sjp161948 else 2372*5334Sjp161948 address_to_bind = ""; 2373*5334Sjp161948 } else 2374*5334Sjp161948 address_to_bind = listen_host; 2375*5334Sjp161948 23760Sstevel@tonic-gate packet_start(SSH2_MSG_GLOBAL_REQUEST); 23770Sstevel@tonic-gate packet_put_cstring("tcpip-forward"); 23780Sstevel@tonic-gate packet_put_char(1); /* boolean: want reply */ 23790Sstevel@tonic-gate packet_put_cstring(address_to_bind); 23800Sstevel@tonic-gate packet_put_int(listen_port); 23810Sstevel@tonic-gate packet_send(); 23820Sstevel@tonic-gate packet_write_wait(); 23830Sstevel@tonic-gate /* Assume that server accepts the request */ 23840Sstevel@tonic-gate success = 1; 23850Sstevel@tonic-gate } else { 23860Sstevel@tonic-gate packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); 23870Sstevel@tonic-gate packet_put_int(listen_port); 23880Sstevel@tonic-gate packet_put_cstring(host_to_connect); 23890Sstevel@tonic-gate packet_put_int(port_to_connect); 23900Sstevel@tonic-gate packet_send(); 23910Sstevel@tonic-gate packet_write_wait(); 23920Sstevel@tonic-gate 23930Sstevel@tonic-gate /* Wait for response from the remote side. */ 23940Sstevel@tonic-gate type = packet_read(); 23950Sstevel@tonic-gate switch (type) { 23960Sstevel@tonic-gate case SSH_SMSG_SUCCESS: 23970Sstevel@tonic-gate success = 1; 23980Sstevel@tonic-gate break; 23990Sstevel@tonic-gate case SSH_SMSG_FAILURE: 24000Sstevel@tonic-gate log("Warning: Server denied remote port forwarding."); 24010Sstevel@tonic-gate break; 24020Sstevel@tonic-gate default: 24030Sstevel@tonic-gate /* Unknown packet */ 24040Sstevel@tonic-gate packet_disconnect("Protocol error for port forward request:" 24050Sstevel@tonic-gate "received packet type %d.", type); 24060Sstevel@tonic-gate } 24070Sstevel@tonic-gate } 24080Sstevel@tonic-gate if (success) { 24090Sstevel@tonic-gate permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); 24100Sstevel@tonic-gate permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; 24110Sstevel@tonic-gate permitted_opens[num_permitted_opens].listen_port = listen_port; 24120Sstevel@tonic-gate num_permitted_opens++; 24130Sstevel@tonic-gate } 2414*5334Sjp161948 return (success ? 0 : -1); 2415*5334Sjp161948 } 2416*5334Sjp161948 2417*5334Sjp161948 /* 2418*5334Sjp161948 * Request cancellation of remote forwarding of connection host:port from 2419*5334Sjp161948 * local side. 2420*5334Sjp161948 */ 2421*5334Sjp161948 void 2422*5334Sjp161948 channel_request_rforward_cancel(const char *host, u_short port) 2423*5334Sjp161948 { 2424*5334Sjp161948 int i; 2425*5334Sjp161948 2426*5334Sjp161948 if (!compat20) 2427*5334Sjp161948 return; 2428*5334Sjp161948 2429*5334Sjp161948 for (i = 0; i < num_permitted_opens; i++) { 2430*5334Sjp161948 if (permitted_opens[i].host_to_connect != NULL && 2431*5334Sjp161948 permitted_opens[i].listen_port == port) 2432*5334Sjp161948 break; 2433*5334Sjp161948 } 2434*5334Sjp161948 if (i >= num_permitted_opens) { 2435*5334Sjp161948 debug("%s: requested forward not found", __func__); 2436*5334Sjp161948 return; 2437*5334Sjp161948 } 2438*5334Sjp161948 packet_start(SSH2_MSG_GLOBAL_REQUEST); 2439*5334Sjp161948 packet_put_cstring("cancel-tcpip-forward"); 2440*5334Sjp161948 packet_put_char(0); 2441*5334Sjp161948 packet_put_cstring(host == NULL ? "" : host); 2442*5334Sjp161948 packet_put_int(port); 2443*5334Sjp161948 packet_send(); 2444*5334Sjp161948 2445*5334Sjp161948 permitted_opens[i].listen_port = 0; 2446*5334Sjp161948 permitted_opens[i].port_to_connect = 0; 2447*5334Sjp161948 xfree(permitted_opens[i].host_to_connect); 2448*5334Sjp161948 permitted_opens[i].host_to_connect = NULL; 24490Sstevel@tonic-gate } 24500Sstevel@tonic-gate 24510Sstevel@tonic-gate /* 24520Sstevel@tonic-gate * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates 24530Sstevel@tonic-gate * listening for the port, and sends back a success reply (or disconnect 24540Sstevel@tonic-gate * message if there was an error). This never returns if there was an error. 24550Sstevel@tonic-gate */ 24560Sstevel@tonic-gate 24570Sstevel@tonic-gate void 24580Sstevel@tonic-gate channel_input_port_forward_request(int is_root, int gateway_ports) 24590Sstevel@tonic-gate { 24600Sstevel@tonic-gate u_short port, host_port; 24610Sstevel@tonic-gate char *hostname; 24620Sstevel@tonic-gate 24630Sstevel@tonic-gate /* Get arguments from the packet. */ 24640Sstevel@tonic-gate port = packet_get_int(); 24650Sstevel@tonic-gate hostname = packet_get_string(NULL); 24660Sstevel@tonic-gate host_port = packet_get_int(); 24670Sstevel@tonic-gate 24680Sstevel@tonic-gate #ifndef HAVE_CYGWIN 24690Sstevel@tonic-gate /* 24700Sstevel@tonic-gate * Check that an unprivileged user is not trying to forward a 24710Sstevel@tonic-gate * privileged port. 24720Sstevel@tonic-gate */ 24730Sstevel@tonic-gate if (port < IPPORT_RESERVED && !is_root) 24740Sstevel@tonic-gate packet_disconnect("Requested forwarding of port %d but user is not root.", 24750Sstevel@tonic-gate port); 24760Sstevel@tonic-gate #endif 24770Sstevel@tonic-gate /* Initiate forwarding */ 2478*5334Sjp161948 channel_setup_local_fwd_listener(NULL, port, hostname, 2479*5334Sjp161948 host_port, gateway_ports); 24800Sstevel@tonic-gate 24810Sstevel@tonic-gate /* Free the argument string. */ 24820Sstevel@tonic-gate xfree(hostname); 24830Sstevel@tonic-gate } 24840Sstevel@tonic-gate 24850Sstevel@tonic-gate /* 24860Sstevel@tonic-gate * Permits opening to any host/port if permitted_opens[] is empty. This is 24870Sstevel@tonic-gate * usually called by the server, because the user could connect to any port 24880Sstevel@tonic-gate * anyway, and the server has no way to know but to trust the client anyway. 24890Sstevel@tonic-gate */ 24900Sstevel@tonic-gate void 24910Sstevel@tonic-gate channel_permit_all_opens(void) 24920Sstevel@tonic-gate { 24930Sstevel@tonic-gate if (num_permitted_opens == 0) 24940Sstevel@tonic-gate all_opens_permitted = 1; 24950Sstevel@tonic-gate } 24960Sstevel@tonic-gate 24970Sstevel@tonic-gate void 24980Sstevel@tonic-gate channel_add_permitted_opens(char *host, int port) 24990Sstevel@tonic-gate { 25000Sstevel@tonic-gate if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) 2501*5334Sjp161948 fatal("channel_add_permitted_opens: too many forwards"); 25020Sstevel@tonic-gate debug("allow port forwarding to host %s port %d", host, port); 25030Sstevel@tonic-gate 25040Sstevel@tonic-gate permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); 25050Sstevel@tonic-gate permitted_opens[num_permitted_opens].port_to_connect = port; 25060Sstevel@tonic-gate num_permitted_opens++; 25070Sstevel@tonic-gate 25080Sstevel@tonic-gate all_opens_permitted = 0; 25090Sstevel@tonic-gate } 25100Sstevel@tonic-gate 25110Sstevel@tonic-gate void 25120Sstevel@tonic-gate channel_clear_permitted_opens(void) 25130Sstevel@tonic-gate { 25140Sstevel@tonic-gate int i; 25150Sstevel@tonic-gate 25160Sstevel@tonic-gate for (i = 0; i < num_permitted_opens; i++) 25170Sstevel@tonic-gate xfree(permitted_opens[i].host_to_connect); 25180Sstevel@tonic-gate num_permitted_opens = 0; 25190Sstevel@tonic-gate } 25200Sstevel@tonic-gate 25210Sstevel@tonic-gate 25220Sstevel@tonic-gate /* return socket to remote host, port */ 25230Sstevel@tonic-gate static int 25240Sstevel@tonic-gate connect_to(const char *host, u_short port) 25250Sstevel@tonic-gate { 25260Sstevel@tonic-gate struct addrinfo hints, *ai, *aitop; 25270Sstevel@tonic-gate char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 25280Sstevel@tonic-gate int gaierr; 25290Sstevel@tonic-gate int sock = -1; 25300Sstevel@tonic-gate 25310Sstevel@tonic-gate memset(&hints, 0, sizeof(hints)); 25320Sstevel@tonic-gate hints.ai_family = IPv4or6; 25330Sstevel@tonic-gate hints.ai_socktype = SOCK_STREAM; 25340Sstevel@tonic-gate snprintf(strport, sizeof strport, "%d", port); 25350Sstevel@tonic-gate if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { 25360Sstevel@tonic-gate error("connect_to %.100s: unknown host (%s)", host, 25370Sstevel@tonic-gate gai_strerror(gaierr)); 25380Sstevel@tonic-gate return -1; 25390Sstevel@tonic-gate } 25400Sstevel@tonic-gate for (ai = aitop; ai; ai = ai->ai_next) { 25410Sstevel@tonic-gate if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 25420Sstevel@tonic-gate continue; 25430Sstevel@tonic-gate if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), 25440Sstevel@tonic-gate strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 25450Sstevel@tonic-gate error("connect_to: getnameinfo failed"); 25460Sstevel@tonic-gate continue; 25470Sstevel@tonic-gate } 25480Sstevel@tonic-gate sock = socket(ai->ai_family, SOCK_STREAM, 0); 25490Sstevel@tonic-gate if (sock < 0) { 25500Sstevel@tonic-gate error("socket: %.100s", strerror(errno)); 25510Sstevel@tonic-gate continue; 25520Sstevel@tonic-gate } 25530Sstevel@tonic-gate if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) 25540Sstevel@tonic-gate fatal("connect_to: F_SETFL: %s", strerror(errno)); 25550Sstevel@tonic-gate if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && 25560Sstevel@tonic-gate errno != EINPROGRESS) { 25570Sstevel@tonic-gate error("connect_to %.100s port %s: %.100s", ntop, strport, 25580Sstevel@tonic-gate strerror(errno)); 25590Sstevel@tonic-gate close(sock); 25600Sstevel@tonic-gate continue; /* fail -- try next */ 25610Sstevel@tonic-gate } 25620Sstevel@tonic-gate break; /* success */ 25630Sstevel@tonic-gate 25640Sstevel@tonic-gate } 25650Sstevel@tonic-gate freeaddrinfo(aitop); 25660Sstevel@tonic-gate if (!ai) { 25670Sstevel@tonic-gate error("connect_to %.100s port %d: failed.", host, port); 25680Sstevel@tonic-gate return -1; 25690Sstevel@tonic-gate } 25700Sstevel@tonic-gate /* success */ 25710Sstevel@tonic-gate set_nodelay(sock); 25720Sstevel@tonic-gate return sock; 25730Sstevel@tonic-gate } 25740Sstevel@tonic-gate 25750Sstevel@tonic-gate int 25760Sstevel@tonic-gate channel_connect_by_listen_address(u_short listen_port) 25770Sstevel@tonic-gate { 25780Sstevel@tonic-gate int i; 25790Sstevel@tonic-gate 25800Sstevel@tonic-gate for (i = 0; i < num_permitted_opens; i++) 25810Sstevel@tonic-gate if (permitted_opens[i].listen_port == listen_port) 25820Sstevel@tonic-gate return connect_to( 25830Sstevel@tonic-gate permitted_opens[i].host_to_connect, 25840Sstevel@tonic-gate permitted_opens[i].port_to_connect); 25850Sstevel@tonic-gate error("WARNING: Server requests forwarding for unknown listen_port %d", 25860Sstevel@tonic-gate listen_port); 25870Sstevel@tonic-gate return -1; 25880Sstevel@tonic-gate } 25890Sstevel@tonic-gate 25900Sstevel@tonic-gate /* Check if connecting to that port is permitted and connect. */ 25910Sstevel@tonic-gate int 25920Sstevel@tonic-gate channel_connect_to(const char *host, u_short port) 25930Sstevel@tonic-gate { 25940Sstevel@tonic-gate int i, permit; 25950Sstevel@tonic-gate 25960Sstevel@tonic-gate permit = all_opens_permitted; 25970Sstevel@tonic-gate if (!permit) { 25980Sstevel@tonic-gate for (i = 0; i < num_permitted_opens; i++) 25990Sstevel@tonic-gate if (permitted_opens[i].port_to_connect == port && 26000Sstevel@tonic-gate strcmp(permitted_opens[i].host_to_connect, host) == 0) 26010Sstevel@tonic-gate permit = 1; 26020Sstevel@tonic-gate 26030Sstevel@tonic-gate } 26040Sstevel@tonic-gate if (!permit) { 26050Sstevel@tonic-gate log("Received request to connect to host %.100s port %d, " 26060Sstevel@tonic-gate "but the request was denied.", host, port); 26070Sstevel@tonic-gate return -1; 26080Sstevel@tonic-gate } 26090Sstevel@tonic-gate return connect_to(host, port); 26100Sstevel@tonic-gate } 26110Sstevel@tonic-gate 26120Sstevel@tonic-gate /* -- X11 forwarding */ 26130Sstevel@tonic-gate 26140Sstevel@tonic-gate /* 26150Sstevel@tonic-gate * Creates an internet domain socket for listening for X11 connections. 26160Sstevel@tonic-gate * Returns 0 and a suitable display number for the DISPLAY variable 26170Sstevel@tonic-gate * stored in display_numberp , or -1 if an error occurs. 26180Sstevel@tonic-gate */ 26190Sstevel@tonic-gate int 26200Sstevel@tonic-gate x11_create_display_inet(int x11_display_offset, int x11_use_localhost, 26210Sstevel@tonic-gate int single_connection, u_int *display_numberp) 26220Sstevel@tonic-gate { 26230Sstevel@tonic-gate Channel *nc = NULL; 26240Sstevel@tonic-gate int display_number, sock; 26250Sstevel@tonic-gate u_short port; 26260Sstevel@tonic-gate struct addrinfo hints, *ai, *aitop; 26270Sstevel@tonic-gate char strport[NI_MAXSERV]; 26280Sstevel@tonic-gate int gaierr, n, num_socks = 0, socks[NUM_SOCKS]; 26290Sstevel@tonic-gate 26300Sstevel@tonic-gate for (display_number = x11_display_offset; 26310Sstevel@tonic-gate display_number < MAX_DISPLAYS; 26320Sstevel@tonic-gate display_number++) { 26330Sstevel@tonic-gate port = 6000 + display_number; 26340Sstevel@tonic-gate memset(&hints, 0, sizeof(hints)); 26350Sstevel@tonic-gate hints.ai_family = IPv4or6; 26360Sstevel@tonic-gate hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE; 26370Sstevel@tonic-gate hints.ai_socktype = SOCK_STREAM; 26380Sstevel@tonic-gate snprintf(strport, sizeof strport, "%d", port); 26390Sstevel@tonic-gate if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) { 26400Sstevel@tonic-gate error("getaddrinfo: %.100s", gai_strerror(gaierr)); 26410Sstevel@tonic-gate return -1; 26420Sstevel@tonic-gate } 26430Sstevel@tonic-gate for (ai = aitop; ai; ai = ai->ai_next) { 26440Sstevel@tonic-gate if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 26450Sstevel@tonic-gate continue; 26460Sstevel@tonic-gate sock = socket(ai->ai_family, SOCK_STREAM, 0); 26470Sstevel@tonic-gate if (sock < 0) { 26480Sstevel@tonic-gate if ((errno != EINVAL) && (errno != EAFNOSUPPORT)) { 26490Sstevel@tonic-gate error("socket: %.100s", strerror(errno)); 26500Sstevel@tonic-gate return -1; 26510Sstevel@tonic-gate } else { 26520Sstevel@tonic-gate debug("x11_create_display_inet: Socket family %d not supported", 26530Sstevel@tonic-gate ai->ai_family); 26540Sstevel@tonic-gate continue; 26550Sstevel@tonic-gate } 26560Sstevel@tonic-gate } 26570Sstevel@tonic-gate #ifdef IPV6_V6ONLY 26580Sstevel@tonic-gate if (ai->ai_family == AF_INET6) { 26590Sstevel@tonic-gate int on = 1; 26600Sstevel@tonic-gate if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) 26610Sstevel@tonic-gate error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno)); 26620Sstevel@tonic-gate } 26630Sstevel@tonic-gate #endif 26640Sstevel@tonic-gate if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 26650Sstevel@tonic-gate debug("bind port %d: %.100s", port, strerror(errno)); 26660Sstevel@tonic-gate close(sock); 26670Sstevel@tonic-gate 26680Sstevel@tonic-gate if (ai->ai_next) 26690Sstevel@tonic-gate continue; 26700Sstevel@tonic-gate 26710Sstevel@tonic-gate for (n = 0; n < num_socks; n++) { 26720Sstevel@tonic-gate close(socks[n]); 26730Sstevel@tonic-gate } 26740Sstevel@tonic-gate num_socks = 0; 26750Sstevel@tonic-gate break; 26760Sstevel@tonic-gate } 26770Sstevel@tonic-gate socks[num_socks++] = sock; 26780Sstevel@tonic-gate #ifndef DONT_TRY_OTHER_AF 26790Sstevel@tonic-gate if (num_socks == NUM_SOCKS) 26800Sstevel@tonic-gate break; 26810Sstevel@tonic-gate #else 26820Sstevel@tonic-gate if (x11_use_localhost) { 26830Sstevel@tonic-gate if (num_socks == NUM_SOCKS) 26840Sstevel@tonic-gate break; 26850Sstevel@tonic-gate } else { 26860Sstevel@tonic-gate break; 26870Sstevel@tonic-gate } 26880Sstevel@tonic-gate #endif 26890Sstevel@tonic-gate } 26900Sstevel@tonic-gate freeaddrinfo(aitop); 26910Sstevel@tonic-gate if (num_socks > 0) 26920Sstevel@tonic-gate break; 26930Sstevel@tonic-gate } 26940Sstevel@tonic-gate if (display_number >= MAX_DISPLAYS) { 26950Sstevel@tonic-gate error("Failed to allocate internet-domain X11 display socket."); 26960Sstevel@tonic-gate return -1; 26970Sstevel@tonic-gate } 26980Sstevel@tonic-gate /* Start listening for connections on the socket. */ 26990Sstevel@tonic-gate for (n = 0; n < num_socks; n++) { 27000Sstevel@tonic-gate sock = socks[n]; 27010Sstevel@tonic-gate if (listen(sock, 5) < 0) { 27020Sstevel@tonic-gate error("listen: %.100s", strerror(errno)); 27030Sstevel@tonic-gate close(sock); 27040Sstevel@tonic-gate return -1; 27050Sstevel@tonic-gate } 27060Sstevel@tonic-gate } 27070Sstevel@tonic-gate 27080Sstevel@tonic-gate /* Allocate a channel for each socket. */ 27090Sstevel@tonic-gate for (n = 0; n < num_socks; n++) { 27100Sstevel@tonic-gate sock = socks[n]; 27110Sstevel@tonic-gate nc = channel_new("x11 listener", 27120Sstevel@tonic-gate SSH_CHANNEL_X11_LISTENER, sock, sock, -1, 27130Sstevel@tonic-gate CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 27140Sstevel@tonic-gate 0, xstrdup("X11 inet listener"), 1); 27150Sstevel@tonic-gate nc->single_connection = single_connection; 27160Sstevel@tonic-gate } 27170Sstevel@tonic-gate 27180Sstevel@tonic-gate /* Return the display number for the DISPLAY environment variable. */ 27190Sstevel@tonic-gate *display_numberp = display_number; 27200Sstevel@tonic-gate return (0); 27210Sstevel@tonic-gate } 27220Sstevel@tonic-gate 27230Sstevel@tonic-gate static int 27240Sstevel@tonic-gate connect_local_xsocket(u_int dnr) 27250Sstevel@tonic-gate { 27260Sstevel@tonic-gate int sock; 27270Sstevel@tonic-gate struct sockaddr_un addr; 27280Sstevel@tonic-gate 27290Sstevel@tonic-gate sock = socket(AF_UNIX, SOCK_STREAM, 0); 27300Sstevel@tonic-gate if (sock < 0) 27310Sstevel@tonic-gate error("socket: %.100s", strerror(errno)); 27320Sstevel@tonic-gate memset(&addr, 0, sizeof(addr)); 27330Sstevel@tonic-gate addr.sun_family = AF_UNIX; 27340Sstevel@tonic-gate snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, dnr); 27350Sstevel@tonic-gate if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0) 27360Sstevel@tonic-gate return sock; 27370Sstevel@tonic-gate close(sock); 27380Sstevel@tonic-gate error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); 27390Sstevel@tonic-gate return -1; 27400Sstevel@tonic-gate } 27410Sstevel@tonic-gate 27420Sstevel@tonic-gate int 27430Sstevel@tonic-gate x11_connect_display(void) 27440Sstevel@tonic-gate { 27450Sstevel@tonic-gate int display_number, sock = 0; 27460Sstevel@tonic-gate const char *display; 27470Sstevel@tonic-gate char buf[1024], *cp; 27480Sstevel@tonic-gate struct addrinfo hints, *ai, *aitop; 27490Sstevel@tonic-gate char strport[NI_MAXSERV]; 27500Sstevel@tonic-gate int gaierr; 27510Sstevel@tonic-gate 27520Sstevel@tonic-gate /* Try to open a socket for the local X server. */ 27530Sstevel@tonic-gate display = getenv("DISPLAY"); 27540Sstevel@tonic-gate if (!display) { 27550Sstevel@tonic-gate error("DISPLAY not set."); 27560Sstevel@tonic-gate return -1; 27570Sstevel@tonic-gate } 27580Sstevel@tonic-gate /* 27590Sstevel@tonic-gate * Now we decode the value of the DISPLAY variable and make a 27600Sstevel@tonic-gate * connection to the real X server. 27610Sstevel@tonic-gate */ 27620Sstevel@tonic-gate 27630Sstevel@tonic-gate /* 27640Sstevel@tonic-gate * Check if it is a unix domain socket. Unix domain displays are in 27650Sstevel@tonic-gate * one of the following formats: unix:d[.s], :d[.s], ::d[.s] 27660Sstevel@tonic-gate */ 27670Sstevel@tonic-gate if (strncmp(display, "unix:", 5) == 0 || 27680Sstevel@tonic-gate display[0] == ':') { 27690Sstevel@tonic-gate /* Connect to the unix domain socket. */ 27700Sstevel@tonic-gate if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) { 27710Sstevel@tonic-gate error("Could not parse display number from DISPLAY: %.100s", 27720Sstevel@tonic-gate display); 27730Sstevel@tonic-gate return -1; 27740Sstevel@tonic-gate } 27750Sstevel@tonic-gate /* Create a socket. */ 27760Sstevel@tonic-gate sock = connect_local_xsocket(display_number); 27770Sstevel@tonic-gate if (sock < 0) 27780Sstevel@tonic-gate return -1; 27790Sstevel@tonic-gate 27800Sstevel@tonic-gate /* OK, we now have a connection to the display. */ 27810Sstevel@tonic-gate return sock; 27820Sstevel@tonic-gate } 27830Sstevel@tonic-gate /* 27840Sstevel@tonic-gate * Connect to an inet socket. The DISPLAY value is supposedly 27850Sstevel@tonic-gate * hostname:d[.s], where hostname may also be numeric IP address. 27860Sstevel@tonic-gate */ 27870Sstevel@tonic-gate strlcpy(buf, display, sizeof(buf)); 27880Sstevel@tonic-gate cp = strchr(buf, ':'); 27890Sstevel@tonic-gate if (!cp) { 27900Sstevel@tonic-gate error("Could not find ':' in DISPLAY: %.100s", display); 27910Sstevel@tonic-gate return -1; 27920Sstevel@tonic-gate } 27930Sstevel@tonic-gate *cp = 0; 27940Sstevel@tonic-gate /* buf now contains the host name. But first we parse the display number. */ 27950Sstevel@tonic-gate if (sscanf(cp + 1, "%d", &display_number) != 1) { 27960Sstevel@tonic-gate error("Could not parse display number from DISPLAY: %.100s", 27970Sstevel@tonic-gate display); 27980Sstevel@tonic-gate return -1; 27990Sstevel@tonic-gate } 28000Sstevel@tonic-gate 28010Sstevel@tonic-gate /* Look up the host address */ 28020Sstevel@tonic-gate memset(&hints, 0, sizeof(hints)); 28030Sstevel@tonic-gate hints.ai_family = IPv4or6; 28040Sstevel@tonic-gate hints.ai_socktype = SOCK_STREAM; 28050Sstevel@tonic-gate snprintf(strport, sizeof strport, "%d", 6000 + display_number); 28060Sstevel@tonic-gate if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { 28070Sstevel@tonic-gate error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr)); 28080Sstevel@tonic-gate return -1; 28090Sstevel@tonic-gate } 28100Sstevel@tonic-gate for (ai = aitop; ai; ai = ai->ai_next) { 28110Sstevel@tonic-gate /* Create a socket. */ 28120Sstevel@tonic-gate sock = socket(ai->ai_family, SOCK_STREAM, 0); 28130Sstevel@tonic-gate if (sock < 0) { 28140Sstevel@tonic-gate debug("socket: %.100s", strerror(errno)); 28150Sstevel@tonic-gate continue; 28160Sstevel@tonic-gate } 28170Sstevel@tonic-gate /* Connect it to the display. */ 28180Sstevel@tonic-gate if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 28190Sstevel@tonic-gate debug("connect %.100s port %d: %.100s", buf, 28200Sstevel@tonic-gate 6000 + display_number, strerror(errno)); 28210Sstevel@tonic-gate close(sock); 28220Sstevel@tonic-gate continue; 28230Sstevel@tonic-gate } 28240Sstevel@tonic-gate /* Success */ 28250Sstevel@tonic-gate break; 28260Sstevel@tonic-gate } 28270Sstevel@tonic-gate freeaddrinfo(aitop); 28280Sstevel@tonic-gate if (!ai) { 28290Sstevel@tonic-gate error("connect %.100s port %d: %.100s", buf, 6000 + display_number, 28300Sstevel@tonic-gate strerror(errno)); 28310Sstevel@tonic-gate return -1; 28320Sstevel@tonic-gate } 28330Sstevel@tonic-gate set_nodelay(sock); 28340Sstevel@tonic-gate return sock; 28350Sstevel@tonic-gate } 28360Sstevel@tonic-gate 28370Sstevel@tonic-gate /* 28380Sstevel@tonic-gate * This is called when SSH_SMSG_X11_OPEN is received. The packet contains 28390Sstevel@tonic-gate * the remote channel number. We should do whatever we want, and respond 28400Sstevel@tonic-gate * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. 28410Sstevel@tonic-gate */ 28420Sstevel@tonic-gate 28430Sstevel@tonic-gate void 28440Sstevel@tonic-gate x11_input_open(int type, u_int32_t seq, void *ctxt) 28450Sstevel@tonic-gate { 28460Sstevel@tonic-gate Channel *c = NULL; 28470Sstevel@tonic-gate int remote_id, sock = 0; 28480Sstevel@tonic-gate char *remote_host; 28490Sstevel@tonic-gate 28500Sstevel@tonic-gate debug("Received X11 open request."); 28510Sstevel@tonic-gate 28520Sstevel@tonic-gate remote_id = packet_get_int(); 28530Sstevel@tonic-gate 28540Sstevel@tonic-gate if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) { 28550Sstevel@tonic-gate remote_host = packet_get_string(NULL); 28560Sstevel@tonic-gate } else { 28570Sstevel@tonic-gate remote_host = xstrdup("unknown (remote did not supply name)"); 28580Sstevel@tonic-gate } 28590Sstevel@tonic-gate packet_check_eom(); 28600Sstevel@tonic-gate 28610Sstevel@tonic-gate /* Obtain a connection to the real X display. */ 28620Sstevel@tonic-gate sock = x11_connect_display(); 28630Sstevel@tonic-gate if (sock != -1) { 28640Sstevel@tonic-gate /* Allocate a channel for this connection. */ 28650Sstevel@tonic-gate c = channel_new("connected x11 socket", 28660Sstevel@tonic-gate SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0, 28670Sstevel@tonic-gate remote_host, 1); 28680Sstevel@tonic-gate c->remote_id = remote_id; 28690Sstevel@tonic-gate c->force_drain = 1; 28700Sstevel@tonic-gate } 28710Sstevel@tonic-gate if (c == NULL) { 28720Sstevel@tonic-gate /* Send refusal to the remote host. */ 28730Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 28740Sstevel@tonic-gate packet_put_int(remote_id); 28750Sstevel@tonic-gate } else { 28760Sstevel@tonic-gate /* Send a confirmation to the remote host. */ 28770Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 28780Sstevel@tonic-gate packet_put_int(remote_id); 28790Sstevel@tonic-gate packet_put_int(c->self); 28800Sstevel@tonic-gate } 28810Sstevel@tonic-gate packet_send(); 28820Sstevel@tonic-gate } 28830Sstevel@tonic-gate 28840Sstevel@tonic-gate /* dummy protocol handler that denies SSH-1 requests (agent/x11) */ 28850Sstevel@tonic-gate void 28860Sstevel@tonic-gate deny_input_open(int type, u_int32_t seq, void *ctxt) 28870Sstevel@tonic-gate { 28880Sstevel@tonic-gate int rchan = packet_get_int(); 28890Sstevel@tonic-gate 28900Sstevel@tonic-gate switch (type) { 28910Sstevel@tonic-gate case SSH_SMSG_AGENT_OPEN: 28920Sstevel@tonic-gate error("Warning: ssh server tried agent forwarding."); 28930Sstevel@tonic-gate break; 28940Sstevel@tonic-gate case SSH_SMSG_X11_OPEN: 28950Sstevel@tonic-gate error("Warning: ssh server tried X11 forwarding."); 28960Sstevel@tonic-gate break; 28970Sstevel@tonic-gate default: 28980Sstevel@tonic-gate error("deny_input_open: type %d", type); 28990Sstevel@tonic-gate break; 29000Sstevel@tonic-gate } 29010Sstevel@tonic-gate error("Warning: this is probably a break in attempt by a malicious server."); 29020Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 29030Sstevel@tonic-gate packet_put_int(rchan); 29040Sstevel@tonic-gate packet_send(); 29050Sstevel@tonic-gate } 29060Sstevel@tonic-gate 29070Sstevel@tonic-gate /* 29080Sstevel@tonic-gate * Requests forwarding of X11 connections, generates fake authentication 29090Sstevel@tonic-gate * data, and enables authentication spoofing. 29100Sstevel@tonic-gate * This should be called in the client only. 29110Sstevel@tonic-gate */ 29120Sstevel@tonic-gate void 29134907Sjp161948 x11_request_forwarding_with_spoofing(int client_session_id, const char *disp, 29140Sstevel@tonic-gate const char *proto, const char *data) 29150Sstevel@tonic-gate { 29160Sstevel@tonic-gate u_int data_len = (u_int) strlen(data) / 2; 29174907Sjp161948 u_int i, value; 29180Sstevel@tonic-gate char *new_data; 29190Sstevel@tonic-gate int screen_number; 29200Sstevel@tonic-gate const char *cp; 29210Sstevel@tonic-gate u_int32_t rand = 0; 29220Sstevel@tonic-gate 29234907Sjp161948 cp = disp; 29244907Sjp161948 if (disp) 29254907Sjp161948 cp = strchr(disp, ':'); 29260Sstevel@tonic-gate if (cp) 29270Sstevel@tonic-gate cp = strchr(cp, '.'); 29280Sstevel@tonic-gate if (cp) 29290Sstevel@tonic-gate screen_number = atoi(cp + 1); 29300Sstevel@tonic-gate else 29310Sstevel@tonic-gate screen_number = 0; 29320Sstevel@tonic-gate 29330Sstevel@tonic-gate /* Save protocol name. */ 29340Sstevel@tonic-gate x11_saved_proto = xstrdup(proto); 29350Sstevel@tonic-gate 29360Sstevel@tonic-gate /* 29370Sstevel@tonic-gate * Extract real authentication data and generate fake data of the 29380Sstevel@tonic-gate * same length. 29390Sstevel@tonic-gate */ 29400Sstevel@tonic-gate x11_saved_data = xmalloc(data_len); 29410Sstevel@tonic-gate x11_fake_data = xmalloc(data_len); 29420Sstevel@tonic-gate for (i = 0; i < data_len; i++) { 29430Sstevel@tonic-gate if (sscanf(data + 2 * i, "%2x", &value) != 1) 29440Sstevel@tonic-gate fatal("x11_request_forwarding: bad authentication data: %.100s", data); 29450Sstevel@tonic-gate if (i % 4 == 0) 29460Sstevel@tonic-gate rand = arc4random(); 29470Sstevel@tonic-gate x11_saved_data[i] = value; 29480Sstevel@tonic-gate x11_fake_data[i] = rand & 0xff; 29490Sstevel@tonic-gate rand >>= 8; 29500Sstevel@tonic-gate } 29510Sstevel@tonic-gate x11_saved_data_len = data_len; 29520Sstevel@tonic-gate x11_fake_data_len = data_len; 29530Sstevel@tonic-gate 29540Sstevel@tonic-gate /* Convert the fake data into hex. */ 29554907Sjp161948 new_data = tohex(x11_fake_data, data_len); 29560Sstevel@tonic-gate 29570Sstevel@tonic-gate /* Send the request packet. */ 29580Sstevel@tonic-gate if (compat20) { 29590Sstevel@tonic-gate channel_request_start(client_session_id, "x11-req", 0); 29600Sstevel@tonic-gate packet_put_char(0); /* XXX bool single connection */ 29610Sstevel@tonic-gate } else { 29620Sstevel@tonic-gate packet_start(SSH_CMSG_X11_REQUEST_FORWARDING); 29630Sstevel@tonic-gate } 29640Sstevel@tonic-gate packet_put_cstring(proto); 29650Sstevel@tonic-gate packet_put_cstring(new_data); 29660Sstevel@tonic-gate packet_put_int(screen_number); 29670Sstevel@tonic-gate packet_send(); 29680Sstevel@tonic-gate packet_write_wait(); 29690Sstevel@tonic-gate xfree(new_data); 29700Sstevel@tonic-gate } 29710Sstevel@tonic-gate 29720Sstevel@tonic-gate 29730Sstevel@tonic-gate /* -- agent forwarding */ 29740Sstevel@tonic-gate 29750Sstevel@tonic-gate /* Sends a message to the server to request authentication fd forwarding. */ 29760Sstevel@tonic-gate 29770Sstevel@tonic-gate void 29780Sstevel@tonic-gate auth_request_forwarding(void) 29790Sstevel@tonic-gate { 29800Sstevel@tonic-gate packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); 29810Sstevel@tonic-gate packet_send(); 29820Sstevel@tonic-gate packet_write_wait(); 29830Sstevel@tonic-gate } 29840Sstevel@tonic-gate 29850Sstevel@tonic-gate /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ 29860Sstevel@tonic-gate 29870Sstevel@tonic-gate void 29880Sstevel@tonic-gate auth_input_open_request(int type, u_int32_t seq, void *ctxt) 29890Sstevel@tonic-gate { 29900Sstevel@tonic-gate Channel *c = NULL; 29910Sstevel@tonic-gate int remote_id, sock; 29920Sstevel@tonic-gate char *name; 29930Sstevel@tonic-gate 29940Sstevel@tonic-gate /* Read the remote channel number from the message. */ 29950Sstevel@tonic-gate remote_id = packet_get_int(); 29960Sstevel@tonic-gate packet_check_eom(); 29970Sstevel@tonic-gate 29980Sstevel@tonic-gate /* 29990Sstevel@tonic-gate * Get a connection to the local authentication agent (this may again 30000Sstevel@tonic-gate * get forwarded). 30010Sstevel@tonic-gate */ 30020Sstevel@tonic-gate sock = ssh_get_authentication_socket(); 30030Sstevel@tonic-gate 30040Sstevel@tonic-gate /* 30050Sstevel@tonic-gate * If we could not connect the agent, send an error message back to 30060Sstevel@tonic-gate * the server. This should never happen unless the agent dies, 30070Sstevel@tonic-gate * because authentication forwarding is only enabled if we have an 30080Sstevel@tonic-gate * agent. 30090Sstevel@tonic-gate */ 30100Sstevel@tonic-gate if (sock >= 0) { 30110Sstevel@tonic-gate name = xstrdup("authentication agent connection"); 30120Sstevel@tonic-gate c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, 30130Sstevel@tonic-gate -1, 0, 0, 0, name, 1); 30140Sstevel@tonic-gate c->remote_id = remote_id; 30150Sstevel@tonic-gate c->force_drain = 1; 30160Sstevel@tonic-gate } 30170Sstevel@tonic-gate if (c == NULL) { 30180Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 30190Sstevel@tonic-gate packet_put_int(remote_id); 30200Sstevel@tonic-gate } else { 30210Sstevel@tonic-gate /* Send a confirmation to the remote host. */ 30220Sstevel@tonic-gate debug("Forwarding authentication connection."); 30230Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 30240Sstevel@tonic-gate packet_put_int(remote_id); 30250Sstevel@tonic-gate packet_put_int(c->self); 30260Sstevel@tonic-gate } 30270Sstevel@tonic-gate packet_send(); 30280Sstevel@tonic-gate } 3029