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