1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate /* 6*0Sstevel@tonic-gate * Author: Tatu Ylonen <ylo@cs.hut.fi> 7*0Sstevel@tonic-gate * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 8*0Sstevel@tonic-gate * All rights reserved 9*0Sstevel@tonic-gate * This file contains functions for generic socket connection forwarding. 10*0Sstevel@tonic-gate * There is also code for initiating connection forwarding for X11 connections, 11*0Sstevel@tonic-gate * arbitrary tcp/ip connections, and the authentication agent connection. 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * As far as I am concerned, the code I have written for this software 14*0Sstevel@tonic-gate * can be used freely for any purpose. Any derived versions of this 15*0Sstevel@tonic-gate * software must be clearly marked as such, and if the derived work is 16*0Sstevel@tonic-gate * incompatible with the protocol description in the RFC file, it must be 17*0Sstevel@tonic-gate * called by a name other than "ssh" or "Secure Shell". 18*0Sstevel@tonic-gate * 19*0Sstevel@tonic-gate * SSH2 support added by Markus Friedl. 20*0Sstevel@tonic-gate * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. 21*0Sstevel@tonic-gate * Copyright (c) 1999 Dug Song. All rights reserved. 22*0Sstevel@tonic-gate * Copyright (c) 1999 Theo de Raadt. All rights reserved. 23*0Sstevel@tonic-gate * 24*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 25*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 26*0Sstevel@tonic-gate * are met: 27*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 28*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 29*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 30*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 31*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 32*0Sstevel@tonic-gate * 33*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 34*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 35*0Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 36*0Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 37*0Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 38*0Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 39*0Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 40*0Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 41*0Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 42*0Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 43*0Sstevel@tonic-gate */ 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate #include "includes.h" 46*0Sstevel@tonic-gate RCSID("$OpenBSD: channels.c,v 1.183 2002/09/17 07:47:02 itojun Exp $"); 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate #include "ssh.h" 51*0Sstevel@tonic-gate #include "ssh1.h" 52*0Sstevel@tonic-gate #include "ssh2.h" 53*0Sstevel@tonic-gate #include "packet.h" 54*0Sstevel@tonic-gate #include "xmalloc.h" 55*0Sstevel@tonic-gate #include "log.h" 56*0Sstevel@tonic-gate #include "misc.h" 57*0Sstevel@tonic-gate #include "channels.h" 58*0Sstevel@tonic-gate #include "compat.h" 59*0Sstevel@tonic-gate #include "canohost.h" 60*0Sstevel@tonic-gate #include "key.h" 61*0Sstevel@tonic-gate #include "authfd.h" 62*0Sstevel@tonic-gate #include "pathnames.h" 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate /* -- channel core */ 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate /* 68*0Sstevel@tonic-gate * Pointer to an array containing all allocated channels. The array is 69*0Sstevel@tonic-gate * dynamically extended as needed. 70*0Sstevel@tonic-gate */ 71*0Sstevel@tonic-gate static Channel **channels = NULL; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate /* 74*0Sstevel@tonic-gate * Size of the channel array. All slots of the array must always be 75*0Sstevel@tonic-gate * initialized (at least the type field); unused slots set to NULL 76*0Sstevel@tonic-gate */ 77*0Sstevel@tonic-gate static int channels_alloc = 0; 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate /* 80*0Sstevel@tonic-gate * Maximum file descriptor value used in any of the channels. This is 81*0Sstevel@tonic-gate * updated in channel_new. 82*0Sstevel@tonic-gate */ 83*0Sstevel@tonic-gate static int channel_max_fd = 0; 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate /* -- tcp forwarding */ 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate /* 89*0Sstevel@tonic-gate * Data structure for storing which hosts are permitted for forward requests. 90*0Sstevel@tonic-gate * The local sides of any remote forwards are stored in this array to prevent 91*0Sstevel@tonic-gate * a corrupt remote server from accessing arbitrary TCP/IP ports on our local 92*0Sstevel@tonic-gate * network (which might be behind a firewall). 93*0Sstevel@tonic-gate */ 94*0Sstevel@tonic-gate typedef struct { 95*0Sstevel@tonic-gate char *host_to_connect; /* Connect to 'host'. */ 96*0Sstevel@tonic-gate u_short port_to_connect; /* Connect to 'port'. */ 97*0Sstevel@tonic-gate u_short listen_port; /* Remote side should listen port number. */ 98*0Sstevel@tonic-gate } ForwardPermission; 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate /* List of all permitted host/port pairs to connect. */ 101*0Sstevel@tonic-gate static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate /* Number of permitted host/port pairs in the array. */ 104*0Sstevel@tonic-gate static int num_permitted_opens = 0; 105*0Sstevel@tonic-gate /* 106*0Sstevel@tonic-gate * If this is true, all opens are permitted. This is the case on the server 107*0Sstevel@tonic-gate * on which we have to trust the client anyway, and the user could do 108*0Sstevel@tonic-gate * anything after logging in anyway. 109*0Sstevel@tonic-gate */ 110*0Sstevel@tonic-gate static int all_opens_permitted = 0; 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate /* -- X11 forwarding */ 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate /* Maximum number of fake X11 displays to try. */ 116*0Sstevel@tonic-gate #define MAX_DISPLAYS 1000 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate /* Saved X11 authentication protocol name. */ 119*0Sstevel@tonic-gate static char *x11_saved_proto = NULL; 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate /* Saved X11 authentication data. This is the real data. */ 122*0Sstevel@tonic-gate static char *x11_saved_data = NULL; 123*0Sstevel@tonic-gate static u_int x11_saved_data_len = 0; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate /* 126*0Sstevel@tonic-gate * Fake X11 authentication data. This is what the server will be sending us; 127*0Sstevel@tonic-gate * we should replace any occurrences of this by the real data. 128*0Sstevel@tonic-gate */ 129*0Sstevel@tonic-gate static char *x11_fake_data = NULL; 130*0Sstevel@tonic-gate static u_int x11_fake_data_len; 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate /* -- agent forwarding */ 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate #define NUM_SOCKS 10 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate /* AF_UNSPEC or AF_INET or AF_INET6 */ 138*0Sstevel@tonic-gate static int IPv4or6 = AF_UNSPEC; 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate /* helper */ 141*0Sstevel@tonic-gate static void port_open_helper(Channel *c, char *rtype); 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate /* -- channel core */ 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate Channel * 146*0Sstevel@tonic-gate channel_lookup(int id) 147*0Sstevel@tonic-gate { 148*0Sstevel@tonic-gate Channel *c; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate if (id < 0 || id >= channels_alloc) { 151*0Sstevel@tonic-gate log("channel_lookup: %d: bad id", id); 152*0Sstevel@tonic-gate return NULL; 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate c = channels[id]; 155*0Sstevel@tonic-gate if (c == NULL) { 156*0Sstevel@tonic-gate log("channel_lookup: %d: bad id: channel free", id); 157*0Sstevel@tonic-gate return NULL; 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate return c; 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate /* 163*0Sstevel@tonic-gate * Register filedescriptors for a channel, used when allocating a channel or 164*0Sstevel@tonic-gate * when the channel consumer/producer is ready, e.g. shell exec'd 165*0Sstevel@tonic-gate */ 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate static void 168*0Sstevel@tonic-gate channel_register_fds(Channel *c, int rfd, int wfd, int efd, 169*0Sstevel@tonic-gate int extusage, int nonblock) 170*0Sstevel@tonic-gate { 171*0Sstevel@tonic-gate /* Update the maximum file descriptor value. */ 172*0Sstevel@tonic-gate channel_max_fd = MAX(channel_max_fd, rfd); 173*0Sstevel@tonic-gate channel_max_fd = MAX(channel_max_fd, wfd); 174*0Sstevel@tonic-gate channel_max_fd = MAX(channel_max_fd, efd); 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate /* XXX set close-on-exec -markus */ 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate c->rfd = rfd; 179*0Sstevel@tonic-gate c->wfd = wfd; 180*0Sstevel@tonic-gate c->sock = (rfd == wfd) ? rfd : -1; 181*0Sstevel@tonic-gate c->efd = efd; 182*0Sstevel@tonic-gate c->extended_usage = extusage; 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* XXX ugly hack: nonblock is only set by the server */ 185*0Sstevel@tonic-gate if (nonblock && isatty(c->rfd)) { 186*0Sstevel@tonic-gate debug("channel %d: rfd %d isatty", c->self, c->rfd); 187*0Sstevel@tonic-gate c->isatty = 1; 188*0Sstevel@tonic-gate if (!isatty(c->wfd)) { 189*0Sstevel@tonic-gate error("channel %d: wfd %d is not a tty?", 190*0Sstevel@tonic-gate c->self, c->wfd); 191*0Sstevel@tonic-gate } 192*0Sstevel@tonic-gate } else { 193*0Sstevel@tonic-gate c->isatty = 0; 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate c->wfd_isatty = isatty(c->wfd); 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* enable nonblocking mode */ 198*0Sstevel@tonic-gate if (nonblock) { 199*0Sstevel@tonic-gate if (rfd != -1) 200*0Sstevel@tonic-gate set_nonblock(rfd); 201*0Sstevel@tonic-gate if (wfd != -1) 202*0Sstevel@tonic-gate set_nonblock(wfd); 203*0Sstevel@tonic-gate if (efd != -1) 204*0Sstevel@tonic-gate set_nonblock(efd); 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* 209*0Sstevel@tonic-gate * Allocate a new channel object and set its type and socket. This will cause 210*0Sstevel@tonic-gate * remote_name to be freed. 211*0Sstevel@tonic-gate */ 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate Channel * 214*0Sstevel@tonic-gate channel_new(char *ctype, int type, int rfd, int wfd, int efd, 215*0Sstevel@tonic-gate u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) 216*0Sstevel@tonic-gate { 217*0Sstevel@tonic-gate int i, found; 218*0Sstevel@tonic-gate Channel *c; 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate /* Do initial allocation if this is the first call. */ 221*0Sstevel@tonic-gate if (channels_alloc == 0) { 222*0Sstevel@tonic-gate channels_alloc = 10; 223*0Sstevel@tonic-gate channels = xmalloc(channels_alloc * sizeof(Channel *)); 224*0Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) 225*0Sstevel@tonic-gate channels[i] = NULL; 226*0Sstevel@tonic-gate fatal_add_cleanup((void (*) (void *)) channel_free_all, NULL); 227*0Sstevel@tonic-gate } 228*0Sstevel@tonic-gate /* Try to find a free slot where to put the new channel. */ 229*0Sstevel@tonic-gate for (found = -1, i = 0; i < channels_alloc; i++) 230*0Sstevel@tonic-gate if (channels[i] == NULL) { 231*0Sstevel@tonic-gate /* Found a free slot. */ 232*0Sstevel@tonic-gate found = i; 233*0Sstevel@tonic-gate break; 234*0Sstevel@tonic-gate } 235*0Sstevel@tonic-gate if (found == -1) { 236*0Sstevel@tonic-gate /* There are no free slots. Take last+1 slot and expand the array. */ 237*0Sstevel@tonic-gate found = channels_alloc; 238*0Sstevel@tonic-gate if (channels_alloc > 10000) 239*0Sstevel@tonic-gate fatal("channel_new: internal error: channels_alloc %d " 240*0Sstevel@tonic-gate "too big.", channels_alloc); 241*0Sstevel@tonic-gate channels = xrealloc(channels, 242*0Sstevel@tonic-gate (channels_alloc + 10) * sizeof(Channel *)); 243*0Sstevel@tonic-gate channels_alloc += 10; 244*0Sstevel@tonic-gate debug2("channel: expanding %d", channels_alloc); 245*0Sstevel@tonic-gate for (i = found; i < channels_alloc; i++) 246*0Sstevel@tonic-gate channels[i] = NULL; 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate /* Initialize and return new channel. */ 249*0Sstevel@tonic-gate c = channels[found] = xmalloc(sizeof(Channel)); 250*0Sstevel@tonic-gate memset(c, 0, sizeof(Channel)); 251*0Sstevel@tonic-gate buffer_init(&c->input); 252*0Sstevel@tonic-gate buffer_init(&c->output); 253*0Sstevel@tonic-gate buffer_init(&c->extended); 254*0Sstevel@tonic-gate c->ostate = CHAN_OUTPUT_OPEN; 255*0Sstevel@tonic-gate c->istate = CHAN_INPUT_OPEN; 256*0Sstevel@tonic-gate c->flags = 0; 257*0Sstevel@tonic-gate channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); 258*0Sstevel@tonic-gate c->self = found; 259*0Sstevel@tonic-gate c->type = type; 260*0Sstevel@tonic-gate c->ctype = ctype; 261*0Sstevel@tonic-gate c->local_window = window; 262*0Sstevel@tonic-gate c->local_window_max = window; 263*0Sstevel@tonic-gate c->local_consumed = 0; 264*0Sstevel@tonic-gate c->local_maxpacket = maxpack; 265*0Sstevel@tonic-gate c->remote_id = -1; 266*0Sstevel@tonic-gate c->remote_name = remote_name; 267*0Sstevel@tonic-gate c->remote_window = 0; 268*0Sstevel@tonic-gate c->remote_maxpacket = 0; 269*0Sstevel@tonic-gate c->force_drain = 0; 270*0Sstevel@tonic-gate c->single_connection = 0; 271*0Sstevel@tonic-gate c->detach_user = NULL; 272*0Sstevel@tonic-gate c->confirm = NULL; 273*0Sstevel@tonic-gate c->input_filter = NULL; 274*0Sstevel@tonic-gate debug("channel %d: new [%s]", found, remote_name); 275*0Sstevel@tonic-gate return c; 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate static int 279*0Sstevel@tonic-gate channel_find_maxfd(void) 280*0Sstevel@tonic-gate { 281*0Sstevel@tonic-gate int i, max = 0; 282*0Sstevel@tonic-gate Channel *c; 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 285*0Sstevel@tonic-gate c = channels[i]; 286*0Sstevel@tonic-gate if (c != NULL) { 287*0Sstevel@tonic-gate max = MAX(max, c->rfd); 288*0Sstevel@tonic-gate max = MAX(max, c->wfd); 289*0Sstevel@tonic-gate max = MAX(max, c->efd); 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate return max; 293*0Sstevel@tonic-gate } 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate int 296*0Sstevel@tonic-gate channel_close_fd(int *fdp) 297*0Sstevel@tonic-gate { 298*0Sstevel@tonic-gate int ret = 0, fd = *fdp; 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate if (fd != -1) { 301*0Sstevel@tonic-gate ret = close(fd); 302*0Sstevel@tonic-gate *fdp = -1; 303*0Sstevel@tonic-gate if (fd == channel_max_fd) 304*0Sstevel@tonic-gate channel_max_fd = channel_find_maxfd(); 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate return ret; 307*0Sstevel@tonic-gate } 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate /* Close all channel fd/socket. */ 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate static void 312*0Sstevel@tonic-gate channel_close_fds(Channel *c) 313*0Sstevel@tonic-gate { 314*0Sstevel@tonic-gate debug3("channel_close_fds: channel %d: r %d w %d e %d", 315*0Sstevel@tonic-gate c->self, c->rfd, c->wfd, c->efd); 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate channel_close_fd(&c->sock); 318*0Sstevel@tonic-gate channel_close_fd(&c->rfd); 319*0Sstevel@tonic-gate channel_close_fd(&c->wfd); 320*0Sstevel@tonic-gate channel_close_fd(&c->efd); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate /* Free the channel and close its fd/socket. */ 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate void 326*0Sstevel@tonic-gate channel_free(Channel *c) 327*0Sstevel@tonic-gate { 328*0Sstevel@tonic-gate char *s; 329*0Sstevel@tonic-gate int i, n; 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate for (n = 0, i = 0; i < channels_alloc; i++) 332*0Sstevel@tonic-gate if (channels[i]) 333*0Sstevel@tonic-gate n++; 334*0Sstevel@tonic-gate debug("channel_free: channel %d: %s, nchannels %d", c->self, 335*0Sstevel@tonic-gate c->remote_name ? c->remote_name : "???", n); 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate s = channel_open_message(); 338*0Sstevel@tonic-gate debug3("channel_free: status: %s", s); 339*0Sstevel@tonic-gate xfree(s); 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate if (c->sock != -1) 342*0Sstevel@tonic-gate shutdown(c->sock, SHUT_RDWR); 343*0Sstevel@tonic-gate channel_close_fds(c); 344*0Sstevel@tonic-gate buffer_free(&c->input); 345*0Sstevel@tonic-gate buffer_free(&c->output); 346*0Sstevel@tonic-gate buffer_free(&c->extended); 347*0Sstevel@tonic-gate if (c->remote_name) { 348*0Sstevel@tonic-gate xfree(c->remote_name); 349*0Sstevel@tonic-gate c->remote_name = NULL; 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate channels[c->self] = NULL; 352*0Sstevel@tonic-gate xfree(c); 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate void 356*0Sstevel@tonic-gate channel_free_all(void) 357*0Sstevel@tonic-gate { 358*0Sstevel@tonic-gate int i; 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) 361*0Sstevel@tonic-gate if (channels[i] != NULL) 362*0Sstevel@tonic-gate channel_free(channels[i]); 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate /* 366*0Sstevel@tonic-gate * Closes the sockets/fds of all channels. This is used to close extra file 367*0Sstevel@tonic-gate * descriptors after a fork. 368*0Sstevel@tonic-gate */ 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate void 371*0Sstevel@tonic-gate channel_close_all(void) 372*0Sstevel@tonic-gate { 373*0Sstevel@tonic-gate int i; 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) 376*0Sstevel@tonic-gate if (channels[i] != NULL) 377*0Sstevel@tonic-gate channel_close_fds(channels[i]); 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate /* 381*0Sstevel@tonic-gate * Stop listening to channels. 382*0Sstevel@tonic-gate */ 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate void 385*0Sstevel@tonic-gate channel_stop_listening(void) 386*0Sstevel@tonic-gate { 387*0Sstevel@tonic-gate int i; 388*0Sstevel@tonic-gate Channel *c; 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 391*0Sstevel@tonic-gate c = channels[i]; 392*0Sstevel@tonic-gate if (c != NULL) { 393*0Sstevel@tonic-gate switch (c->type) { 394*0Sstevel@tonic-gate case SSH_CHANNEL_AUTH_SOCKET: 395*0Sstevel@tonic-gate case SSH_CHANNEL_PORT_LISTENER: 396*0Sstevel@tonic-gate case SSH_CHANNEL_RPORT_LISTENER: 397*0Sstevel@tonic-gate case SSH_CHANNEL_X11_LISTENER: 398*0Sstevel@tonic-gate channel_close_fd(&c->sock); 399*0Sstevel@tonic-gate channel_free(c); 400*0Sstevel@tonic-gate break; 401*0Sstevel@tonic-gate } 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate /* 407*0Sstevel@tonic-gate * Returns true if no channel has too much buffered data, and false if one or 408*0Sstevel@tonic-gate * more channel is overfull. 409*0Sstevel@tonic-gate */ 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate int 412*0Sstevel@tonic-gate channel_not_very_much_buffered_data(void) 413*0Sstevel@tonic-gate { 414*0Sstevel@tonic-gate u_int i; 415*0Sstevel@tonic-gate Channel *c; 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 418*0Sstevel@tonic-gate c = channels[i]; 419*0Sstevel@tonic-gate if (c != NULL && c->type == SSH_CHANNEL_OPEN) { 420*0Sstevel@tonic-gate #if 0 421*0Sstevel@tonic-gate if (!compat20 && 422*0Sstevel@tonic-gate buffer_len(&c->input) > packet_get_maxsize()) { 423*0Sstevel@tonic-gate debug("channel %d: big input buffer %d", 424*0Sstevel@tonic-gate c->self, buffer_len(&c->input)); 425*0Sstevel@tonic-gate return 0; 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate #endif 428*0Sstevel@tonic-gate if (buffer_len(&c->output) > packet_get_maxsize()) { 429*0Sstevel@tonic-gate debug("channel %d: big output buffer %d > %d", 430*0Sstevel@tonic-gate c->self, buffer_len(&c->output), 431*0Sstevel@tonic-gate packet_get_maxsize()); 432*0Sstevel@tonic-gate return 0; 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate return 1; 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate /* Returns true if any channel is still open. */ 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate int 442*0Sstevel@tonic-gate channel_still_open(void) 443*0Sstevel@tonic-gate { 444*0Sstevel@tonic-gate int i; 445*0Sstevel@tonic-gate Channel *c; 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 448*0Sstevel@tonic-gate c = channels[i]; 449*0Sstevel@tonic-gate if (c == NULL) 450*0Sstevel@tonic-gate continue; 451*0Sstevel@tonic-gate switch (c->type) { 452*0Sstevel@tonic-gate case SSH_CHANNEL_X11_LISTENER: 453*0Sstevel@tonic-gate case SSH_CHANNEL_PORT_LISTENER: 454*0Sstevel@tonic-gate case SSH_CHANNEL_RPORT_LISTENER: 455*0Sstevel@tonic-gate case SSH_CHANNEL_CLOSED: 456*0Sstevel@tonic-gate case SSH_CHANNEL_AUTH_SOCKET: 457*0Sstevel@tonic-gate case SSH_CHANNEL_DYNAMIC: 458*0Sstevel@tonic-gate case SSH_CHANNEL_CONNECTING: 459*0Sstevel@tonic-gate case SSH_CHANNEL_ZOMBIE: 460*0Sstevel@tonic-gate continue; 461*0Sstevel@tonic-gate case SSH_CHANNEL_LARVAL: 462*0Sstevel@tonic-gate if (!compat20) 463*0Sstevel@tonic-gate fatal("cannot happen: SSH_CHANNEL_LARVAL"); 464*0Sstevel@tonic-gate continue; 465*0Sstevel@tonic-gate case SSH_CHANNEL_OPENING: 466*0Sstevel@tonic-gate case SSH_CHANNEL_OPEN: 467*0Sstevel@tonic-gate case SSH_CHANNEL_X11_OPEN: 468*0Sstevel@tonic-gate return 1; 469*0Sstevel@tonic-gate case SSH_CHANNEL_INPUT_DRAINING: 470*0Sstevel@tonic-gate case SSH_CHANNEL_OUTPUT_DRAINING: 471*0Sstevel@tonic-gate if (!compat13) 472*0Sstevel@tonic-gate fatal("cannot happen: OUT_DRAIN"); 473*0Sstevel@tonic-gate return 1; 474*0Sstevel@tonic-gate default: 475*0Sstevel@tonic-gate fatal("channel_still_open: bad channel type %d", c->type); 476*0Sstevel@tonic-gate /* NOTREACHED */ 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate return 0; 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate /* Returns the id of an open channel suitable for keepaliving */ 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate int 485*0Sstevel@tonic-gate channel_find_open(void) 486*0Sstevel@tonic-gate { 487*0Sstevel@tonic-gate int i; 488*0Sstevel@tonic-gate Channel *c; 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 491*0Sstevel@tonic-gate c = channels[i]; 492*0Sstevel@tonic-gate if (c == NULL) 493*0Sstevel@tonic-gate continue; 494*0Sstevel@tonic-gate switch (c->type) { 495*0Sstevel@tonic-gate case SSH_CHANNEL_CLOSED: 496*0Sstevel@tonic-gate case SSH_CHANNEL_DYNAMIC: 497*0Sstevel@tonic-gate case SSH_CHANNEL_X11_LISTENER: 498*0Sstevel@tonic-gate case SSH_CHANNEL_PORT_LISTENER: 499*0Sstevel@tonic-gate case SSH_CHANNEL_RPORT_LISTENER: 500*0Sstevel@tonic-gate case SSH_CHANNEL_OPENING: 501*0Sstevel@tonic-gate case SSH_CHANNEL_CONNECTING: 502*0Sstevel@tonic-gate case SSH_CHANNEL_ZOMBIE: 503*0Sstevel@tonic-gate continue; 504*0Sstevel@tonic-gate case SSH_CHANNEL_LARVAL: 505*0Sstevel@tonic-gate case SSH_CHANNEL_AUTH_SOCKET: 506*0Sstevel@tonic-gate case SSH_CHANNEL_OPEN: 507*0Sstevel@tonic-gate case SSH_CHANNEL_X11_OPEN: 508*0Sstevel@tonic-gate return i; 509*0Sstevel@tonic-gate case SSH_CHANNEL_INPUT_DRAINING: 510*0Sstevel@tonic-gate case SSH_CHANNEL_OUTPUT_DRAINING: 511*0Sstevel@tonic-gate if (!compat13) 512*0Sstevel@tonic-gate fatal("cannot happen: OUT_DRAIN"); 513*0Sstevel@tonic-gate return i; 514*0Sstevel@tonic-gate default: 515*0Sstevel@tonic-gate fatal("channel_find_open: bad channel type %d", c->type); 516*0Sstevel@tonic-gate /* NOTREACHED */ 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate return -1; 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate /* 524*0Sstevel@tonic-gate * Returns a message describing the currently open forwarded connections, 525*0Sstevel@tonic-gate * suitable for sending to the client. The message contains crlf pairs for 526*0Sstevel@tonic-gate * newlines. 527*0Sstevel@tonic-gate */ 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate char * 530*0Sstevel@tonic-gate channel_open_message(void) 531*0Sstevel@tonic-gate { 532*0Sstevel@tonic-gate Buffer buffer; 533*0Sstevel@tonic-gate Channel *c; 534*0Sstevel@tonic-gate char buf[1024], *cp; 535*0Sstevel@tonic-gate int i; 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate buffer_init(&buffer); 538*0Sstevel@tonic-gate snprintf(buf, sizeof buf, "The following connections are open:\r\n"); 539*0Sstevel@tonic-gate buffer_append(&buffer, buf, strlen(buf)); 540*0Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 541*0Sstevel@tonic-gate c = channels[i]; 542*0Sstevel@tonic-gate if (c == NULL) 543*0Sstevel@tonic-gate continue; 544*0Sstevel@tonic-gate switch (c->type) { 545*0Sstevel@tonic-gate case SSH_CHANNEL_X11_LISTENER: 546*0Sstevel@tonic-gate case SSH_CHANNEL_PORT_LISTENER: 547*0Sstevel@tonic-gate case SSH_CHANNEL_RPORT_LISTENER: 548*0Sstevel@tonic-gate case SSH_CHANNEL_CLOSED: 549*0Sstevel@tonic-gate case SSH_CHANNEL_AUTH_SOCKET: 550*0Sstevel@tonic-gate case SSH_CHANNEL_ZOMBIE: 551*0Sstevel@tonic-gate continue; 552*0Sstevel@tonic-gate case SSH_CHANNEL_LARVAL: 553*0Sstevel@tonic-gate case SSH_CHANNEL_OPENING: 554*0Sstevel@tonic-gate case SSH_CHANNEL_CONNECTING: 555*0Sstevel@tonic-gate case SSH_CHANNEL_DYNAMIC: 556*0Sstevel@tonic-gate case SSH_CHANNEL_OPEN: 557*0Sstevel@tonic-gate case SSH_CHANNEL_X11_OPEN: 558*0Sstevel@tonic-gate case SSH_CHANNEL_INPUT_DRAINING: 559*0Sstevel@tonic-gate case SSH_CHANNEL_OUTPUT_DRAINING: 560*0Sstevel@tonic-gate snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n", 561*0Sstevel@tonic-gate c->self, c->remote_name, 562*0Sstevel@tonic-gate c->type, c->remote_id, 563*0Sstevel@tonic-gate c->istate, buffer_len(&c->input), 564*0Sstevel@tonic-gate c->ostate, buffer_len(&c->output), 565*0Sstevel@tonic-gate c->rfd, c->wfd); 566*0Sstevel@tonic-gate buffer_append(&buffer, buf, strlen(buf)); 567*0Sstevel@tonic-gate continue; 568*0Sstevel@tonic-gate default: 569*0Sstevel@tonic-gate fatal("channel_open_message: bad channel type %d", c->type); 570*0Sstevel@tonic-gate /* NOTREACHED */ 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate } 573*0Sstevel@tonic-gate buffer_append(&buffer, "\0", 1); 574*0Sstevel@tonic-gate cp = xstrdup(buffer_ptr(&buffer)); 575*0Sstevel@tonic-gate buffer_free(&buffer); 576*0Sstevel@tonic-gate return cp; 577*0Sstevel@tonic-gate } 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate void 580*0Sstevel@tonic-gate channel_send_open(int id) 581*0Sstevel@tonic-gate { 582*0Sstevel@tonic-gate Channel *c = channel_lookup(id); 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate if (c == NULL) { 585*0Sstevel@tonic-gate log("channel_send_open: %d: bad id", id); 586*0Sstevel@tonic-gate return; 587*0Sstevel@tonic-gate } 588*0Sstevel@tonic-gate debug("send channel open %d", id); 589*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN); 590*0Sstevel@tonic-gate packet_put_cstring(c->ctype); 591*0Sstevel@tonic-gate packet_put_int(c->self); 592*0Sstevel@tonic-gate packet_put_int(c->local_window); 593*0Sstevel@tonic-gate packet_put_int(c->local_maxpacket); 594*0Sstevel@tonic-gate packet_send(); 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate void 598*0Sstevel@tonic-gate channel_request_start(int local_id, char *service, int wantconfirm) 599*0Sstevel@tonic-gate { 600*0Sstevel@tonic-gate Channel *c = channel_lookup(local_id); 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate if (c == NULL) { 603*0Sstevel@tonic-gate log("channel_request_start: %d: unknown channel id", local_id); 604*0Sstevel@tonic-gate return; 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate debug("channel request %d: %s", local_id, service) ; 607*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_REQUEST); 608*0Sstevel@tonic-gate packet_put_int(c->remote_id); 609*0Sstevel@tonic-gate packet_put_cstring(service); 610*0Sstevel@tonic-gate packet_put_char(wantconfirm); 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate void 613*0Sstevel@tonic-gate channel_register_confirm(int id, channel_callback_fn *fn) 614*0Sstevel@tonic-gate { 615*0Sstevel@tonic-gate Channel *c = channel_lookup(id); 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate if (c == NULL) { 618*0Sstevel@tonic-gate log("channel_register_comfirm: %d: bad id", id); 619*0Sstevel@tonic-gate return; 620*0Sstevel@tonic-gate } 621*0Sstevel@tonic-gate c->confirm = fn; 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate void 624*0Sstevel@tonic-gate channel_register_cleanup(int id, channel_callback_fn *fn) 625*0Sstevel@tonic-gate { 626*0Sstevel@tonic-gate Channel *c = channel_lookup(id); 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate if (c == NULL) { 629*0Sstevel@tonic-gate log("channel_register_cleanup: %d: bad id", id); 630*0Sstevel@tonic-gate return; 631*0Sstevel@tonic-gate } 632*0Sstevel@tonic-gate c->detach_user = fn; 633*0Sstevel@tonic-gate } 634*0Sstevel@tonic-gate void 635*0Sstevel@tonic-gate channel_cancel_cleanup(int id) 636*0Sstevel@tonic-gate { 637*0Sstevel@tonic-gate Channel *c = channel_lookup(id); 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate if (c == NULL) { 640*0Sstevel@tonic-gate log("channel_cancel_cleanup: %d: bad id", id); 641*0Sstevel@tonic-gate return; 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate c->detach_user = NULL; 644*0Sstevel@tonic-gate } 645*0Sstevel@tonic-gate void 646*0Sstevel@tonic-gate channel_register_filter(int id, channel_filter_fn *fn) 647*0Sstevel@tonic-gate { 648*0Sstevel@tonic-gate Channel *c = channel_lookup(id); 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate if (c == NULL) { 651*0Sstevel@tonic-gate log("channel_register_filter: %d: bad id", id); 652*0Sstevel@tonic-gate return; 653*0Sstevel@tonic-gate } 654*0Sstevel@tonic-gate c->input_filter = fn; 655*0Sstevel@tonic-gate } 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate void 658*0Sstevel@tonic-gate channel_set_fds(int id, int rfd, int wfd, int efd, 659*0Sstevel@tonic-gate int extusage, int nonblock, u_int window_max) 660*0Sstevel@tonic-gate { 661*0Sstevel@tonic-gate Channel *c = channel_lookup(id); 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate if (c == NULL || c->type != SSH_CHANNEL_LARVAL) 664*0Sstevel@tonic-gate fatal("channel_activate for non-larval channel %d.", id); 665*0Sstevel@tonic-gate channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); 666*0Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 667*0Sstevel@tonic-gate c->local_window = c->local_window_max = window_max; 668*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); 669*0Sstevel@tonic-gate packet_put_int(c->remote_id); 670*0Sstevel@tonic-gate packet_put_int(c->local_window); 671*0Sstevel@tonic-gate packet_send(); 672*0Sstevel@tonic-gate } 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate void 675*0Sstevel@tonic-gate channel_set_wait_for_exit(int id, int wait_for_exit) 676*0Sstevel@tonic-gate { 677*0Sstevel@tonic-gate Channel *c = channel_lookup(id); 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate if (c == NULL || c->type != SSH_CHANNEL_OPEN) 680*0Sstevel@tonic-gate fatal("channel_set_wait_for_exit for non-open channel %d.", id); 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate debug3("channel_set_wait_for_exit %d, %d (type: %d)", id, wait_for_exit, c->type); 683*0Sstevel@tonic-gate c->wait_for_exit = wait_for_exit; 684*0Sstevel@tonic-gate } 685*0Sstevel@tonic-gate 686*0Sstevel@tonic-gate /* 687*0Sstevel@tonic-gate * 'channel_pre*' are called just before select() to add any bits relevant to 688*0Sstevel@tonic-gate * channels in the select bitmasks. 689*0Sstevel@tonic-gate */ 690*0Sstevel@tonic-gate /* 691*0Sstevel@tonic-gate * 'channel_post*': perform any appropriate operations for channels which 692*0Sstevel@tonic-gate * have events pending. 693*0Sstevel@tonic-gate */ 694*0Sstevel@tonic-gate typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset); 695*0Sstevel@tonic-gate chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE]; 696*0Sstevel@tonic-gate chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE]; 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate static void 699*0Sstevel@tonic-gate channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset) 700*0Sstevel@tonic-gate { 701*0Sstevel@tonic-gate FD_SET(c->sock, readset); 702*0Sstevel@tonic-gate } 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate static void 705*0Sstevel@tonic-gate channel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset) 706*0Sstevel@tonic-gate { 707*0Sstevel@tonic-gate debug3("channel %d: waiting for connection", c->self); 708*0Sstevel@tonic-gate FD_SET(c->sock, writeset); 709*0Sstevel@tonic-gate } 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate static void 712*0Sstevel@tonic-gate channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset) 713*0Sstevel@tonic-gate { 714*0Sstevel@tonic-gate if (buffer_len(&c->input) < packet_get_maxsize()) 715*0Sstevel@tonic-gate FD_SET(c->sock, readset); 716*0Sstevel@tonic-gate if (buffer_len(&c->output) > 0) 717*0Sstevel@tonic-gate FD_SET(c->sock, writeset); 718*0Sstevel@tonic-gate } 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate static void 721*0Sstevel@tonic-gate channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset) 722*0Sstevel@tonic-gate { 723*0Sstevel@tonic-gate u_int limit = compat20 ? c->remote_window : packet_get_maxsize(); 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate if (c->istate == CHAN_INPUT_OPEN && 726*0Sstevel@tonic-gate limit > 0 && 727*0Sstevel@tonic-gate buffer_len(&c->input) < limit) 728*0Sstevel@tonic-gate FD_SET(c->rfd, readset); 729*0Sstevel@tonic-gate if (c->ostate == CHAN_OUTPUT_OPEN || 730*0Sstevel@tonic-gate c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { 731*0Sstevel@tonic-gate if (buffer_len(&c->output) > 0) { 732*0Sstevel@tonic-gate FD_SET(c->wfd, writeset); 733*0Sstevel@tonic-gate } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { 734*0Sstevel@tonic-gate if (CHANNEL_EFD_OUTPUT_ACTIVE(c)) 735*0Sstevel@tonic-gate debug2("channel %d: obuf_empty delayed efd %d/(%d)", 736*0Sstevel@tonic-gate c->self, c->efd, buffer_len(&c->extended)); 737*0Sstevel@tonic-gate else 738*0Sstevel@tonic-gate chan_obuf_empty(c); 739*0Sstevel@tonic-gate } 740*0Sstevel@tonic-gate } 741*0Sstevel@tonic-gate /** XXX check close conditions, too */ 742*0Sstevel@tonic-gate if (compat20 && c->efd != -1) { 743*0Sstevel@tonic-gate if (c->extended_usage == CHAN_EXTENDED_WRITE && 744*0Sstevel@tonic-gate buffer_len(&c->extended) > 0) 745*0Sstevel@tonic-gate FD_SET(c->efd, writeset); 746*0Sstevel@tonic-gate else if (!(c->flags & CHAN_EOF_SENT) && 747*0Sstevel@tonic-gate c->extended_usage == CHAN_EXTENDED_READ && 748*0Sstevel@tonic-gate buffer_len(&c->extended) < c->remote_window) 749*0Sstevel@tonic-gate FD_SET(c->efd, readset); 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate static void 754*0Sstevel@tonic-gate channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) 755*0Sstevel@tonic-gate { 756*0Sstevel@tonic-gate if (buffer_len(&c->input) == 0) { 757*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_CLOSE); 758*0Sstevel@tonic-gate packet_put_int(c->remote_id); 759*0Sstevel@tonic-gate packet_send(); 760*0Sstevel@tonic-gate c->type = SSH_CHANNEL_CLOSED; 761*0Sstevel@tonic-gate debug("channel %d: closing after input drain.", c->self); 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate static void 766*0Sstevel@tonic-gate channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) 767*0Sstevel@tonic-gate { 768*0Sstevel@tonic-gate if (buffer_len(&c->output) == 0) 769*0Sstevel@tonic-gate chan_mark_dead(c); 770*0Sstevel@tonic-gate else 771*0Sstevel@tonic-gate FD_SET(c->sock, writeset); 772*0Sstevel@tonic-gate } 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate /* 775*0Sstevel@tonic-gate * This is a special state for X11 authentication spoofing. An opened X11 776*0Sstevel@tonic-gate * connection (when authentication spoofing is being done) remains in this 777*0Sstevel@tonic-gate * state until the first packet has been completely read. The authentication 778*0Sstevel@tonic-gate * data in that packet is then substituted by the real data if it matches the 779*0Sstevel@tonic-gate * fake data, and the channel is put into normal mode. 780*0Sstevel@tonic-gate * XXX All this happens at the client side. 781*0Sstevel@tonic-gate * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok 782*0Sstevel@tonic-gate */ 783*0Sstevel@tonic-gate static int 784*0Sstevel@tonic-gate x11_open_helper(Buffer *b) 785*0Sstevel@tonic-gate { 786*0Sstevel@tonic-gate u_char *ucp; 787*0Sstevel@tonic-gate u_int proto_len, data_len; 788*0Sstevel@tonic-gate 789*0Sstevel@tonic-gate /* Check if the fixed size part of the packet is in buffer. */ 790*0Sstevel@tonic-gate if (buffer_len(b) < 12) 791*0Sstevel@tonic-gate return 0; 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate /* Parse the lengths of variable-length fields. */ 794*0Sstevel@tonic-gate ucp = buffer_ptr(b); 795*0Sstevel@tonic-gate if (ucp[0] == 0x42) { /* Byte order MSB first. */ 796*0Sstevel@tonic-gate proto_len = 256 * ucp[6] + ucp[7]; 797*0Sstevel@tonic-gate data_len = 256 * ucp[8] + ucp[9]; 798*0Sstevel@tonic-gate } else if (ucp[0] == 0x6c) { /* Byte order LSB first. */ 799*0Sstevel@tonic-gate proto_len = ucp[6] + 256 * ucp[7]; 800*0Sstevel@tonic-gate data_len = ucp[8] + 256 * ucp[9]; 801*0Sstevel@tonic-gate } else { 802*0Sstevel@tonic-gate debug("Initial X11 packet contains bad byte order byte: 0x%x", 803*0Sstevel@tonic-gate ucp[0]); 804*0Sstevel@tonic-gate return -1; 805*0Sstevel@tonic-gate } 806*0Sstevel@tonic-gate 807*0Sstevel@tonic-gate /* Check if the whole packet is in buffer. */ 808*0Sstevel@tonic-gate if (buffer_len(b) < 809*0Sstevel@tonic-gate 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) 810*0Sstevel@tonic-gate return 0; 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate /* Check if authentication protocol matches. */ 813*0Sstevel@tonic-gate if (proto_len != strlen(x11_saved_proto) || 814*0Sstevel@tonic-gate memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { 815*0Sstevel@tonic-gate debug("X11 connection uses different authentication protocol."); 816*0Sstevel@tonic-gate return -1; 817*0Sstevel@tonic-gate } 818*0Sstevel@tonic-gate /* Check if authentication data matches our fake data. */ 819*0Sstevel@tonic-gate if (data_len != x11_fake_data_len || 820*0Sstevel@tonic-gate memcmp(ucp + 12 + ((proto_len + 3) & ~3), 821*0Sstevel@tonic-gate x11_fake_data, x11_fake_data_len) != 0) { 822*0Sstevel@tonic-gate debug("X11 auth data does not match fake data."); 823*0Sstevel@tonic-gate return -1; 824*0Sstevel@tonic-gate } 825*0Sstevel@tonic-gate /* Check fake data length */ 826*0Sstevel@tonic-gate if (x11_fake_data_len != x11_saved_data_len) { 827*0Sstevel@tonic-gate error("X11 fake_data_len %d != saved_data_len %d", 828*0Sstevel@tonic-gate x11_fake_data_len, x11_saved_data_len); 829*0Sstevel@tonic-gate return -1; 830*0Sstevel@tonic-gate } 831*0Sstevel@tonic-gate /* 832*0Sstevel@tonic-gate * Received authentication protocol and data match 833*0Sstevel@tonic-gate * our fake data. Substitute the fake data with real 834*0Sstevel@tonic-gate * data. 835*0Sstevel@tonic-gate */ 836*0Sstevel@tonic-gate memcpy(ucp + 12 + ((proto_len + 3) & ~3), 837*0Sstevel@tonic-gate x11_saved_data, x11_saved_data_len); 838*0Sstevel@tonic-gate return 1; 839*0Sstevel@tonic-gate } 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate static void 842*0Sstevel@tonic-gate channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset) 843*0Sstevel@tonic-gate { 844*0Sstevel@tonic-gate int ret = x11_open_helper(&c->output); 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate if (ret == 1) { 847*0Sstevel@tonic-gate /* Start normal processing for the channel. */ 848*0Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 849*0Sstevel@tonic-gate channel_pre_open_13(c, readset, writeset); 850*0Sstevel@tonic-gate } else if (ret == -1) { 851*0Sstevel@tonic-gate /* 852*0Sstevel@tonic-gate * We have received an X11 connection that has bad 853*0Sstevel@tonic-gate * authentication information. 854*0Sstevel@tonic-gate */ 855*0Sstevel@tonic-gate log("X11 connection rejected because of wrong authentication."); 856*0Sstevel@tonic-gate buffer_clear(&c->input); 857*0Sstevel@tonic-gate buffer_clear(&c->output); 858*0Sstevel@tonic-gate channel_close_fd(&c->sock); 859*0Sstevel@tonic-gate c->sock = -1; 860*0Sstevel@tonic-gate c->type = SSH_CHANNEL_CLOSED; 861*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_CLOSE); 862*0Sstevel@tonic-gate packet_put_int(c->remote_id); 863*0Sstevel@tonic-gate packet_send(); 864*0Sstevel@tonic-gate } 865*0Sstevel@tonic-gate } 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate static void 868*0Sstevel@tonic-gate channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) 869*0Sstevel@tonic-gate { 870*0Sstevel@tonic-gate int ret = x11_open_helper(&c->output); 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate /* c->force_drain = 1; */ 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate if (ret == 1) { 875*0Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 876*0Sstevel@tonic-gate channel_pre_open(c, readset, writeset); 877*0Sstevel@tonic-gate } else if (ret == -1) { 878*0Sstevel@tonic-gate log("X11 connection rejected because of wrong authentication."); 879*0Sstevel@tonic-gate debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate); 880*0Sstevel@tonic-gate chan_read_failed(c); 881*0Sstevel@tonic-gate buffer_clear(&c->input); 882*0Sstevel@tonic-gate chan_ibuf_empty(c); 883*0Sstevel@tonic-gate buffer_clear(&c->output); 884*0Sstevel@tonic-gate /* for proto v1, the peer will send an IEOF */ 885*0Sstevel@tonic-gate if (compat20) 886*0Sstevel@tonic-gate chan_write_failed(c); 887*0Sstevel@tonic-gate else 888*0Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 889*0Sstevel@tonic-gate debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); 890*0Sstevel@tonic-gate } 891*0Sstevel@tonic-gate } 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate /* try to decode a socks4 header */ 894*0Sstevel@tonic-gate static int 895*0Sstevel@tonic-gate channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) 896*0Sstevel@tonic-gate { 897*0Sstevel@tonic-gate char *p, *host; 898*0Sstevel@tonic-gate int len, have, i, found; 899*0Sstevel@tonic-gate char username[256]; 900*0Sstevel@tonic-gate struct { 901*0Sstevel@tonic-gate u_int8_t version; 902*0Sstevel@tonic-gate u_int8_t command; 903*0Sstevel@tonic-gate u_int16_t dest_port; 904*0Sstevel@tonic-gate struct in_addr dest_addr; 905*0Sstevel@tonic-gate } s4_req, s4_rsp; 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate debug2("channel %d: decode socks4", c->self); 908*0Sstevel@tonic-gate 909*0Sstevel@tonic-gate have = buffer_len(&c->input); 910*0Sstevel@tonic-gate len = sizeof(s4_req); 911*0Sstevel@tonic-gate if (have < len) 912*0Sstevel@tonic-gate return 0; 913*0Sstevel@tonic-gate p = buffer_ptr(&c->input); 914*0Sstevel@tonic-gate for (found = 0, i = len; i < have; i++) { 915*0Sstevel@tonic-gate if (p[i] == '\0') { 916*0Sstevel@tonic-gate found = 1; 917*0Sstevel@tonic-gate break; 918*0Sstevel@tonic-gate } 919*0Sstevel@tonic-gate if (i > 1024) { 920*0Sstevel@tonic-gate /* the peer is probably sending garbage */ 921*0Sstevel@tonic-gate debug("channel %d: decode socks4: too long", 922*0Sstevel@tonic-gate c->self); 923*0Sstevel@tonic-gate return -1; 924*0Sstevel@tonic-gate } 925*0Sstevel@tonic-gate } 926*0Sstevel@tonic-gate if (!found) 927*0Sstevel@tonic-gate return 0; 928*0Sstevel@tonic-gate buffer_get(&c->input, (char *)&s4_req.version, 1); 929*0Sstevel@tonic-gate buffer_get(&c->input, (char *)&s4_req.command, 1); 930*0Sstevel@tonic-gate buffer_get(&c->input, (char *)&s4_req.dest_port, 2); 931*0Sstevel@tonic-gate buffer_get(&c->input, (char *)&s4_req.dest_addr, 4); 932*0Sstevel@tonic-gate have = buffer_len(&c->input); 933*0Sstevel@tonic-gate p = buffer_ptr(&c->input); 934*0Sstevel@tonic-gate len = strlen(p); 935*0Sstevel@tonic-gate debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); 936*0Sstevel@tonic-gate if (len > have) 937*0Sstevel@tonic-gate fatal("channel %d: decode socks4: len %d > have %d", 938*0Sstevel@tonic-gate c->self, len, have); 939*0Sstevel@tonic-gate strlcpy(username, p, sizeof(username)); 940*0Sstevel@tonic-gate buffer_consume(&c->input, len); 941*0Sstevel@tonic-gate buffer_consume(&c->input, 1); /* trailing '\0' */ 942*0Sstevel@tonic-gate 943*0Sstevel@tonic-gate host = inet_ntoa(s4_req.dest_addr); 944*0Sstevel@tonic-gate strlcpy(c->path, host, sizeof(c->path)); 945*0Sstevel@tonic-gate c->host_port = ntohs(s4_req.dest_port); 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate debug("channel %d: dynamic request: socks4 host %s port %u command %u", 948*0Sstevel@tonic-gate c->self, host, c->host_port, s4_req.command); 949*0Sstevel@tonic-gate 950*0Sstevel@tonic-gate if (s4_req.command != 1) { 951*0Sstevel@tonic-gate debug("channel %d: cannot handle: socks4 cn %d", 952*0Sstevel@tonic-gate c->self, s4_req.command); 953*0Sstevel@tonic-gate return -1; 954*0Sstevel@tonic-gate } 955*0Sstevel@tonic-gate s4_rsp.version = 0; /* vn: 0 for reply */ 956*0Sstevel@tonic-gate s4_rsp.command = 90; /* cd: req granted */ 957*0Sstevel@tonic-gate s4_rsp.dest_port = 0; /* ignored */ 958*0Sstevel@tonic-gate s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ 959*0Sstevel@tonic-gate buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp)); 960*0Sstevel@tonic-gate return 1; 961*0Sstevel@tonic-gate } 962*0Sstevel@tonic-gate 963*0Sstevel@tonic-gate /* dynamic port forwarding */ 964*0Sstevel@tonic-gate static void 965*0Sstevel@tonic-gate channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) 966*0Sstevel@tonic-gate { 967*0Sstevel@tonic-gate u_char *p; 968*0Sstevel@tonic-gate int have, ret; 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate have = buffer_len(&c->input); 971*0Sstevel@tonic-gate c->delayed = 0; 972*0Sstevel@tonic-gate debug2("channel %d: pre_dynamic: have %d", c->self, have); 973*0Sstevel@tonic-gate /* buffer_dump(&c->input); */ 974*0Sstevel@tonic-gate /* check if the fixed size part of the packet is in buffer. */ 975*0Sstevel@tonic-gate if (have < 4) { 976*0Sstevel@tonic-gate /* need more */ 977*0Sstevel@tonic-gate FD_SET(c->sock, readset); 978*0Sstevel@tonic-gate return; 979*0Sstevel@tonic-gate } 980*0Sstevel@tonic-gate /* try to guess the protocol */ 981*0Sstevel@tonic-gate p = buffer_ptr(&c->input); 982*0Sstevel@tonic-gate switch (p[0]) { 983*0Sstevel@tonic-gate case 0x04: 984*0Sstevel@tonic-gate ret = channel_decode_socks4(c, readset, writeset); 985*0Sstevel@tonic-gate break; 986*0Sstevel@tonic-gate default: 987*0Sstevel@tonic-gate ret = -1; 988*0Sstevel@tonic-gate break; 989*0Sstevel@tonic-gate } 990*0Sstevel@tonic-gate if (ret < 0) { 991*0Sstevel@tonic-gate chan_mark_dead(c); 992*0Sstevel@tonic-gate } else if (ret == 0) { 993*0Sstevel@tonic-gate debug2("channel %d: pre_dynamic: need more", c->self); 994*0Sstevel@tonic-gate /* need more */ 995*0Sstevel@tonic-gate FD_SET(c->sock, readset); 996*0Sstevel@tonic-gate } else { 997*0Sstevel@tonic-gate /* switch to the next state */ 998*0Sstevel@tonic-gate c->type = SSH_CHANNEL_OPENING; 999*0Sstevel@tonic-gate port_open_helper(c, "direct-tcpip"); 1000*0Sstevel@tonic-gate } 1001*0Sstevel@tonic-gate } 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate /* This is our fake X11 server socket. */ 1004*0Sstevel@tonic-gate static void 1005*0Sstevel@tonic-gate channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) 1006*0Sstevel@tonic-gate { 1007*0Sstevel@tonic-gate Channel *nc; 1008*0Sstevel@tonic-gate struct sockaddr addr; 1009*0Sstevel@tonic-gate int newsock; 1010*0Sstevel@tonic-gate socklen_t addrlen; 1011*0Sstevel@tonic-gate char buf[16384], *remote_ipaddr; 1012*0Sstevel@tonic-gate int remote_port; 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate if (FD_ISSET(c->sock, readset)) { 1015*0Sstevel@tonic-gate debug("X11 connection requested."); 1016*0Sstevel@tonic-gate addrlen = sizeof(addr); 1017*0Sstevel@tonic-gate newsock = accept(c->sock, &addr, &addrlen); 1018*0Sstevel@tonic-gate if (c->single_connection) { 1019*0Sstevel@tonic-gate debug("single_connection: closing X11 listener."); 1020*0Sstevel@tonic-gate channel_close_fd(&c->sock); 1021*0Sstevel@tonic-gate chan_mark_dead(c); 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate if (newsock < 0) { 1024*0Sstevel@tonic-gate error("accept: %.100s", strerror(errno)); 1025*0Sstevel@tonic-gate return; 1026*0Sstevel@tonic-gate } 1027*0Sstevel@tonic-gate set_nodelay(newsock); 1028*0Sstevel@tonic-gate remote_ipaddr = get_peer_ipaddr(newsock); 1029*0Sstevel@tonic-gate remote_port = get_peer_port(newsock); 1030*0Sstevel@tonic-gate snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", 1031*0Sstevel@tonic-gate remote_ipaddr, remote_port); 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate nc = channel_new("accepted x11 socket", 1034*0Sstevel@tonic-gate SSH_CHANNEL_OPENING, newsock, newsock, -1, 1035*0Sstevel@tonic-gate c->local_window_max, c->local_maxpacket, 1036*0Sstevel@tonic-gate 0, xstrdup(buf), 1); 1037*0Sstevel@tonic-gate if (compat20) { 1038*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN); 1039*0Sstevel@tonic-gate packet_put_cstring("x11"); 1040*0Sstevel@tonic-gate packet_put_int(nc->self); 1041*0Sstevel@tonic-gate packet_put_int(nc->local_window_max); 1042*0Sstevel@tonic-gate packet_put_int(nc->local_maxpacket); 1043*0Sstevel@tonic-gate /* originator ipaddr and port */ 1044*0Sstevel@tonic-gate packet_put_cstring(remote_ipaddr); 1045*0Sstevel@tonic-gate if (datafellows & SSH_BUG_X11FWD) { 1046*0Sstevel@tonic-gate debug("ssh2 x11 bug compat mode"); 1047*0Sstevel@tonic-gate } else { 1048*0Sstevel@tonic-gate packet_put_int(remote_port); 1049*0Sstevel@tonic-gate } 1050*0Sstevel@tonic-gate packet_send(); 1051*0Sstevel@tonic-gate } else { 1052*0Sstevel@tonic-gate packet_start(SSH_SMSG_X11_OPEN); 1053*0Sstevel@tonic-gate packet_put_int(nc->self); 1054*0Sstevel@tonic-gate if (packet_get_protocol_flags() & 1055*0Sstevel@tonic-gate SSH_PROTOFLAG_HOST_IN_FWD_OPEN) 1056*0Sstevel@tonic-gate packet_put_cstring(buf); 1057*0Sstevel@tonic-gate packet_send(); 1058*0Sstevel@tonic-gate } 1059*0Sstevel@tonic-gate xfree(remote_ipaddr); 1060*0Sstevel@tonic-gate } 1061*0Sstevel@tonic-gate } 1062*0Sstevel@tonic-gate 1063*0Sstevel@tonic-gate static void 1064*0Sstevel@tonic-gate port_open_helper(Channel *c, char *rtype) 1065*0Sstevel@tonic-gate { 1066*0Sstevel@tonic-gate int direct; 1067*0Sstevel@tonic-gate char buf[1024]; 1068*0Sstevel@tonic-gate char *remote_ipaddr = get_peer_ipaddr(c->sock); 1069*0Sstevel@tonic-gate u_short remote_port = get_peer_port(c->sock); 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate direct = (strcmp(rtype, "direct-tcpip") == 0); 1072*0Sstevel@tonic-gate 1073*0Sstevel@tonic-gate snprintf(buf, sizeof buf, 1074*0Sstevel@tonic-gate "%s: listening port %d for %.100s port %d, " 1075*0Sstevel@tonic-gate "connect from %.200s port %d", 1076*0Sstevel@tonic-gate rtype, c->listening_port, c->path, c->host_port, 1077*0Sstevel@tonic-gate remote_ipaddr, remote_port); 1078*0Sstevel@tonic-gate 1079*0Sstevel@tonic-gate xfree(c->remote_name); 1080*0Sstevel@tonic-gate c->remote_name = xstrdup(buf); 1081*0Sstevel@tonic-gate 1082*0Sstevel@tonic-gate if (compat20) { 1083*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN); 1084*0Sstevel@tonic-gate packet_put_cstring(rtype); 1085*0Sstevel@tonic-gate packet_put_int(c->self); 1086*0Sstevel@tonic-gate packet_put_int(c->local_window_max); 1087*0Sstevel@tonic-gate packet_put_int(c->local_maxpacket); 1088*0Sstevel@tonic-gate if (direct) { 1089*0Sstevel@tonic-gate /* target host, port */ 1090*0Sstevel@tonic-gate packet_put_cstring(c->path); 1091*0Sstevel@tonic-gate packet_put_int(c->host_port); 1092*0Sstevel@tonic-gate } else { 1093*0Sstevel@tonic-gate /* listen address, port */ 1094*0Sstevel@tonic-gate packet_put_cstring(c->path); 1095*0Sstevel@tonic-gate packet_put_int(c->listening_port); 1096*0Sstevel@tonic-gate } 1097*0Sstevel@tonic-gate /* originator host and port */ 1098*0Sstevel@tonic-gate packet_put_cstring(remote_ipaddr); 1099*0Sstevel@tonic-gate packet_put_int(remote_port); 1100*0Sstevel@tonic-gate packet_send(); 1101*0Sstevel@tonic-gate } else { 1102*0Sstevel@tonic-gate packet_start(SSH_MSG_PORT_OPEN); 1103*0Sstevel@tonic-gate packet_put_int(c->self); 1104*0Sstevel@tonic-gate packet_put_cstring(c->path); 1105*0Sstevel@tonic-gate packet_put_int(c->host_port); 1106*0Sstevel@tonic-gate if (packet_get_protocol_flags() & 1107*0Sstevel@tonic-gate SSH_PROTOFLAG_HOST_IN_FWD_OPEN) 1108*0Sstevel@tonic-gate packet_put_cstring(c->remote_name); 1109*0Sstevel@tonic-gate packet_send(); 1110*0Sstevel@tonic-gate } 1111*0Sstevel@tonic-gate xfree(remote_ipaddr); 1112*0Sstevel@tonic-gate } 1113*0Sstevel@tonic-gate 1114*0Sstevel@tonic-gate /* 1115*0Sstevel@tonic-gate * This socket is listening for connections to a forwarded TCP/IP port. 1116*0Sstevel@tonic-gate */ 1117*0Sstevel@tonic-gate static void 1118*0Sstevel@tonic-gate channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) 1119*0Sstevel@tonic-gate { 1120*0Sstevel@tonic-gate Channel *nc; 1121*0Sstevel@tonic-gate struct sockaddr addr; 1122*0Sstevel@tonic-gate int newsock, nextstate; 1123*0Sstevel@tonic-gate socklen_t addrlen; 1124*0Sstevel@tonic-gate char *rtype; 1125*0Sstevel@tonic-gate 1126*0Sstevel@tonic-gate if (FD_ISSET(c->sock, readset)) { 1127*0Sstevel@tonic-gate debug("Connection to port %d forwarding " 1128*0Sstevel@tonic-gate "to %.100s port %d requested.", 1129*0Sstevel@tonic-gate c->listening_port, c->path, c->host_port); 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate if (c->type == SSH_CHANNEL_RPORT_LISTENER) { 1132*0Sstevel@tonic-gate nextstate = SSH_CHANNEL_OPENING; 1133*0Sstevel@tonic-gate rtype = "forwarded-tcpip"; 1134*0Sstevel@tonic-gate } else { 1135*0Sstevel@tonic-gate if (c->host_port == 0) { 1136*0Sstevel@tonic-gate nextstate = SSH_CHANNEL_DYNAMIC; 1137*0Sstevel@tonic-gate rtype = "dynamic-tcpip"; 1138*0Sstevel@tonic-gate } else { 1139*0Sstevel@tonic-gate nextstate = SSH_CHANNEL_OPENING; 1140*0Sstevel@tonic-gate rtype = "direct-tcpip"; 1141*0Sstevel@tonic-gate } 1142*0Sstevel@tonic-gate } 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate addrlen = sizeof(addr); 1145*0Sstevel@tonic-gate newsock = accept(c->sock, &addr, &addrlen); 1146*0Sstevel@tonic-gate if (newsock < 0) { 1147*0Sstevel@tonic-gate error("accept: %.100s", strerror(errno)); 1148*0Sstevel@tonic-gate return; 1149*0Sstevel@tonic-gate } 1150*0Sstevel@tonic-gate set_nodelay(newsock); 1151*0Sstevel@tonic-gate nc = channel_new(rtype, 1152*0Sstevel@tonic-gate nextstate, newsock, newsock, -1, 1153*0Sstevel@tonic-gate c->local_window_max, c->local_maxpacket, 1154*0Sstevel@tonic-gate 0, xstrdup(rtype), 1); 1155*0Sstevel@tonic-gate nc->listening_port = c->listening_port; 1156*0Sstevel@tonic-gate nc->host_port = c->host_port; 1157*0Sstevel@tonic-gate strlcpy(nc->path, c->path, sizeof(nc->path)); 1158*0Sstevel@tonic-gate 1159*0Sstevel@tonic-gate if (nextstate == SSH_CHANNEL_DYNAMIC) { 1160*0Sstevel@tonic-gate /* 1161*0Sstevel@tonic-gate * do not call the channel_post handler until 1162*0Sstevel@tonic-gate * this flag has been reset by a pre-handler. 1163*0Sstevel@tonic-gate * otherwise the FD_ISSET calls might overflow 1164*0Sstevel@tonic-gate */ 1165*0Sstevel@tonic-gate nc->delayed = 1; 1166*0Sstevel@tonic-gate } else { 1167*0Sstevel@tonic-gate port_open_helper(nc, rtype); 1168*0Sstevel@tonic-gate } 1169*0Sstevel@tonic-gate } 1170*0Sstevel@tonic-gate } 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gate /* 1173*0Sstevel@tonic-gate * This is the authentication agent socket listening for connections from 1174*0Sstevel@tonic-gate * clients. 1175*0Sstevel@tonic-gate */ 1176*0Sstevel@tonic-gate static void 1177*0Sstevel@tonic-gate channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) 1178*0Sstevel@tonic-gate { 1179*0Sstevel@tonic-gate Channel *nc; 1180*0Sstevel@tonic-gate char *name; 1181*0Sstevel@tonic-gate int newsock; 1182*0Sstevel@tonic-gate struct sockaddr addr; 1183*0Sstevel@tonic-gate socklen_t addrlen; 1184*0Sstevel@tonic-gate 1185*0Sstevel@tonic-gate if (FD_ISSET(c->sock, readset)) { 1186*0Sstevel@tonic-gate addrlen = sizeof(addr); 1187*0Sstevel@tonic-gate newsock = accept(c->sock, &addr, &addrlen); 1188*0Sstevel@tonic-gate if (newsock < 0) { 1189*0Sstevel@tonic-gate error("accept from auth socket: %.100s", strerror(errno)); 1190*0Sstevel@tonic-gate return; 1191*0Sstevel@tonic-gate } 1192*0Sstevel@tonic-gate name = xstrdup("accepted auth socket"); 1193*0Sstevel@tonic-gate nc = channel_new("accepted auth socket", 1194*0Sstevel@tonic-gate SSH_CHANNEL_OPENING, newsock, newsock, -1, 1195*0Sstevel@tonic-gate c->local_window_max, c->local_maxpacket, 1196*0Sstevel@tonic-gate 0, name, 1); 1197*0Sstevel@tonic-gate if (compat20) { 1198*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN); 1199*0Sstevel@tonic-gate packet_put_cstring("auth-agent@openssh.com"); 1200*0Sstevel@tonic-gate packet_put_int(nc->self); 1201*0Sstevel@tonic-gate packet_put_int(c->local_window_max); 1202*0Sstevel@tonic-gate packet_put_int(c->local_maxpacket); 1203*0Sstevel@tonic-gate } else { 1204*0Sstevel@tonic-gate packet_start(SSH_SMSG_AGENT_OPEN); 1205*0Sstevel@tonic-gate packet_put_int(nc->self); 1206*0Sstevel@tonic-gate } 1207*0Sstevel@tonic-gate packet_send(); 1208*0Sstevel@tonic-gate } 1209*0Sstevel@tonic-gate } 1210*0Sstevel@tonic-gate 1211*0Sstevel@tonic-gate static void 1212*0Sstevel@tonic-gate channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset) 1213*0Sstevel@tonic-gate { 1214*0Sstevel@tonic-gate int err = 0; 1215*0Sstevel@tonic-gate socklen_t sz = sizeof(err); 1216*0Sstevel@tonic-gate 1217*0Sstevel@tonic-gate if (FD_ISSET(c->sock, writeset)) { 1218*0Sstevel@tonic-gate if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) { 1219*0Sstevel@tonic-gate err = errno; 1220*0Sstevel@tonic-gate error("getsockopt SO_ERROR failed"); 1221*0Sstevel@tonic-gate } 1222*0Sstevel@tonic-gate if (err == 0) { 1223*0Sstevel@tonic-gate debug("channel %d: connected", c->self); 1224*0Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 1225*0Sstevel@tonic-gate if (compat20) { 1226*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); 1227*0Sstevel@tonic-gate packet_put_int(c->remote_id); 1228*0Sstevel@tonic-gate packet_put_int(c->self); 1229*0Sstevel@tonic-gate packet_put_int(c->local_window); 1230*0Sstevel@tonic-gate packet_put_int(c->local_maxpacket); 1231*0Sstevel@tonic-gate } else { 1232*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 1233*0Sstevel@tonic-gate packet_put_int(c->remote_id); 1234*0Sstevel@tonic-gate packet_put_int(c->self); 1235*0Sstevel@tonic-gate } 1236*0Sstevel@tonic-gate } else { 1237*0Sstevel@tonic-gate debug("channel %d: not connected: %s", 1238*0Sstevel@tonic-gate c->self, strerror(err)); 1239*0Sstevel@tonic-gate if (compat20) { 1240*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); 1241*0Sstevel@tonic-gate packet_put_int(c->remote_id); 1242*0Sstevel@tonic-gate packet_put_int(SSH2_OPEN_CONNECT_FAILED); 1243*0Sstevel@tonic-gate if (!(datafellows & SSH_BUG_OPENFAILURE)) { 1244*0Sstevel@tonic-gate packet_put_cstring(strerror(err)); 1245*0Sstevel@tonic-gate packet_put_cstring(""); 1246*0Sstevel@tonic-gate } 1247*0Sstevel@tonic-gate } else { 1248*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 1249*0Sstevel@tonic-gate packet_put_int(c->remote_id); 1250*0Sstevel@tonic-gate } 1251*0Sstevel@tonic-gate chan_mark_dead(c); 1252*0Sstevel@tonic-gate } 1253*0Sstevel@tonic-gate packet_send(); 1254*0Sstevel@tonic-gate } 1255*0Sstevel@tonic-gate } 1256*0Sstevel@tonic-gate 1257*0Sstevel@tonic-gate static int 1258*0Sstevel@tonic-gate channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) 1259*0Sstevel@tonic-gate { 1260*0Sstevel@tonic-gate char buf[16*1024]; 1261*0Sstevel@tonic-gate int len; 1262*0Sstevel@tonic-gate 1263*0Sstevel@tonic-gate if (c->rfd != -1 && 1264*0Sstevel@tonic-gate FD_ISSET(c->rfd, readset)) { 1265*0Sstevel@tonic-gate len = read(c->rfd, buf, sizeof(buf)); 1266*0Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) 1267*0Sstevel@tonic-gate return 1; 1268*0Sstevel@tonic-gate if (len <= 0) { 1269*0Sstevel@tonic-gate debug("channel %d: read<=0 rfd %d len %d", 1270*0Sstevel@tonic-gate c->self, c->rfd, len); 1271*0Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN) { 1272*0Sstevel@tonic-gate debug("channel %d: not open", c->self); 1273*0Sstevel@tonic-gate chan_mark_dead(c); 1274*0Sstevel@tonic-gate return -1; 1275*0Sstevel@tonic-gate } else if (compat13) { 1276*0Sstevel@tonic-gate buffer_clear(&c->output); 1277*0Sstevel@tonic-gate c->type = SSH_CHANNEL_INPUT_DRAINING; 1278*0Sstevel@tonic-gate debug("channel %d: input draining.", c->self); 1279*0Sstevel@tonic-gate } else { 1280*0Sstevel@tonic-gate chan_read_failed(c); 1281*0Sstevel@tonic-gate } 1282*0Sstevel@tonic-gate return -1; 1283*0Sstevel@tonic-gate } 1284*0Sstevel@tonic-gate if (c->input_filter != NULL) { 1285*0Sstevel@tonic-gate if (c->input_filter(c, buf, len) == -1) { 1286*0Sstevel@tonic-gate debug("channel %d: filter stops", c->self); 1287*0Sstevel@tonic-gate chan_read_failed(c); 1288*0Sstevel@tonic-gate } 1289*0Sstevel@tonic-gate } else { 1290*0Sstevel@tonic-gate buffer_append(&c->input, buf, len); 1291*0Sstevel@tonic-gate } 1292*0Sstevel@tonic-gate } 1293*0Sstevel@tonic-gate return 1; 1294*0Sstevel@tonic-gate } 1295*0Sstevel@tonic-gate static int 1296*0Sstevel@tonic-gate channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) 1297*0Sstevel@tonic-gate { 1298*0Sstevel@tonic-gate struct termios tio; 1299*0Sstevel@tonic-gate u_char *data; 1300*0Sstevel@tonic-gate u_int dlen; 1301*0Sstevel@tonic-gate int len; 1302*0Sstevel@tonic-gate 1303*0Sstevel@tonic-gate /* Send buffered output data to the socket. */ 1304*0Sstevel@tonic-gate if (c->wfd != -1 && 1305*0Sstevel@tonic-gate FD_ISSET(c->wfd, writeset) && 1306*0Sstevel@tonic-gate buffer_len(&c->output) > 0) { 1307*0Sstevel@tonic-gate data = buffer_ptr(&c->output); 1308*0Sstevel@tonic-gate dlen = buffer_len(&c->output); 1309*0Sstevel@tonic-gate #ifdef _AIX 1310*0Sstevel@tonic-gate /* XXX: Later AIX versions can't push as much data to tty */ 1311*0Sstevel@tonic-gate if (compat20 && c->wfd_isatty && dlen > 8*1024) 1312*0Sstevel@tonic-gate dlen = 8*1024; 1313*0Sstevel@tonic-gate #endif 1314*0Sstevel@tonic-gate len = write(c->wfd, data, dlen); 1315*0Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) 1316*0Sstevel@tonic-gate return 1; 1317*0Sstevel@tonic-gate if (len <= 0) { 1318*0Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN) { 1319*0Sstevel@tonic-gate debug("channel %d: not open", c->self); 1320*0Sstevel@tonic-gate chan_mark_dead(c); 1321*0Sstevel@tonic-gate return -1; 1322*0Sstevel@tonic-gate } else if (compat13) { 1323*0Sstevel@tonic-gate buffer_clear(&c->output); 1324*0Sstevel@tonic-gate debug("channel %d: input draining.", c->self); 1325*0Sstevel@tonic-gate c->type = SSH_CHANNEL_INPUT_DRAINING; 1326*0Sstevel@tonic-gate } else { 1327*0Sstevel@tonic-gate chan_write_failed(c); 1328*0Sstevel@tonic-gate } 1329*0Sstevel@tonic-gate return -1; 1330*0Sstevel@tonic-gate } 1331*0Sstevel@tonic-gate if (compat20 && c->isatty && dlen >= 1 && data[0] != '\r') { 1332*0Sstevel@tonic-gate if (tcgetattr(c->wfd, &tio) == 0 && 1333*0Sstevel@tonic-gate !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { 1334*0Sstevel@tonic-gate /* 1335*0Sstevel@tonic-gate * Simulate echo to reduce the impact of 1336*0Sstevel@tonic-gate * traffic analysis. We need to match the 1337*0Sstevel@tonic-gate * size of a SSH2_MSG_CHANNEL_DATA message 1338*0Sstevel@tonic-gate * (4 byte channel id + data) 1339*0Sstevel@tonic-gate */ 1340*0Sstevel@tonic-gate packet_send_ignore(4 + len); 1341*0Sstevel@tonic-gate packet_send(); 1342*0Sstevel@tonic-gate } 1343*0Sstevel@tonic-gate } 1344*0Sstevel@tonic-gate buffer_consume(&c->output, len); 1345*0Sstevel@tonic-gate if (compat20 && len > 0) { 1346*0Sstevel@tonic-gate c->local_consumed += len; 1347*0Sstevel@tonic-gate } 1348*0Sstevel@tonic-gate } 1349*0Sstevel@tonic-gate return 1; 1350*0Sstevel@tonic-gate } 1351*0Sstevel@tonic-gate static int 1352*0Sstevel@tonic-gate channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) 1353*0Sstevel@tonic-gate { 1354*0Sstevel@tonic-gate char buf[16*1024]; 1355*0Sstevel@tonic-gate int len; 1356*0Sstevel@tonic-gate 1357*0Sstevel@tonic-gate /** XXX handle drain efd, too */ 1358*0Sstevel@tonic-gate if (c->efd != -1) { 1359*0Sstevel@tonic-gate if (c->extended_usage == CHAN_EXTENDED_WRITE && 1360*0Sstevel@tonic-gate FD_ISSET(c->efd, writeset) && 1361*0Sstevel@tonic-gate buffer_len(&c->extended) > 0) { 1362*0Sstevel@tonic-gate len = write(c->efd, buffer_ptr(&c->extended), 1363*0Sstevel@tonic-gate buffer_len(&c->extended)); 1364*0Sstevel@tonic-gate debug2("channel %d: written %d to efd %d", 1365*0Sstevel@tonic-gate c->self, len, c->efd); 1366*0Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) 1367*0Sstevel@tonic-gate return 1; 1368*0Sstevel@tonic-gate if (len <= 0) { 1369*0Sstevel@tonic-gate debug2("channel %d: closing write-efd %d", 1370*0Sstevel@tonic-gate c->self, c->efd); 1371*0Sstevel@tonic-gate channel_close_fd(&c->efd); 1372*0Sstevel@tonic-gate } else { 1373*0Sstevel@tonic-gate buffer_consume(&c->extended, len); 1374*0Sstevel@tonic-gate c->local_consumed += len; 1375*0Sstevel@tonic-gate } 1376*0Sstevel@tonic-gate } else if (c->extended_usage == CHAN_EXTENDED_READ && 1377*0Sstevel@tonic-gate FD_ISSET(c->efd, readset)) { 1378*0Sstevel@tonic-gate len = read(c->efd, buf, sizeof(buf)); 1379*0Sstevel@tonic-gate debug2("channel %d: read %d from efd %d", 1380*0Sstevel@tonic-gate c->self, len, c->efd); 1381*0Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) 1382*0Sstevel@tonic-gate return 1; 1383*0Sstevel@tonic-gate if (len <= 0) { 1384*0Sstevel@tonic-gate debug2("channel %d: closing read-efd %d", 1385*0Sstevel@tonic-gate c->self, c->efd); 1386*0Sstevel@tonic-gate channel_close_fd(&c->efd); 1387*0Sstevel@tonic-gate } else { 1388*0Sstevel@tonic-gate buffer_append(&c->extended, buf, len); 1389*0Sstevel@tonic-gate } 1390*0Sstevel@tonic-gate } 1391*0Sstevel@tonic-gate } 1392*0Sstevel@tonic-gate return 1; 1393*0Sstevel@tonic-gate } 1394*0Sstevel@tonic-gate static int 1395*0Sstevel@tonic-gate channel_check_window(Channel *c) 1396*0Sstevel@tonic-gate { 1397*0Sstevel@tonic-gate if (c->type == SSH_CHANNEL_OPEN && 1398*0Sstevel@tonic-gate !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && 1399*0Sstevel@tonic-gate c->local_window < c->local_window_max/2 && 1400*0Sstevel@tonic-gate c->local_consumed > 0) { 1401*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); 1402*0Sstevel@tonic-gate packet_put_int(c->remote_id); 1403*0Sstevel@tonic-gate packet_put_int(c->local_consumed); 1404*0Sstevel@tonic-gate packet_send(); 1405*0Sstevel@tonic-gate debug2("channel %d: window %d sent adjust %d", 1406*0Sstevel@tonic-gate c->self, c->local_window, 1407*0Sstevel@tonic-gate c->local_consumed); 1408*0Sstevel@tonic-gate c->local_window += c->local_consumed; 1409*0Sstevel@tonic-gate c->local_consumed = 0; 1410*0Sstevel@tonic-gate } 1411*0Sstevel@tonic-gate return 1; 1412*0Sstevel@tonic-gate } 1413*0Sstevel@tonic-gate 1414*0Sstevel@tonic-gate static void 1415*0Sstevel@tonic-gate channel_post_open(Channel *c, fd_set * readset, fd_set * writeset) 1416*0Sstevel@tonic-gate { 1417*0Sstevel@tonic-gate if (c->delayed) 1418*0Sstevel@tonic-gate return; 1419*0Sstevel@tonic-gate channel_handle_rfd(c, readset, writeset); 1420*0Sstevel@tonic-gate channel_handle_wfd(c, readset, writeset); 1421*0Sstevel@tonic-gate if (!compat20) 1422*0Sstevel@tonic-gate return; 1423*0Sstevel@tonic-gate channel_handle_efd(c, readset, writeset); 1424*0Sstevel@tonic-gate channel_check_window(c); 1425*0Sstevel@tonic-gate } 1426*0Sstevel@tonic-gate 1427*0Sstevel@tonic-gate static void 1428*0Sstevel@tonic-gate channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) 1429*0Sstevel@tonic-gate { 1430*0Sstevel@tonic-gate int len; 1431*0Sstevel@tonic-gate 1432*0Sstevel@tonic-gate /* Send buffered output data to the socket. */ 1433*0Sstevel@tonic-gate if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) { 1434*0Sstevel@tonic-gate len = write(c->sock, buffer_ptr(&c->output), 1435*0Sstevel@tonic-gate buffer_len(&c->output)); 1436*0Sstevel@tonic-gate if (len <= 0) 1437*0Sstevel@tonic-gate buffer_clear(&c->output); 1438*0Sstevel@tonic-gate else 1439*0Sstevel@tonic-gate buffer_consume(&c->output, len); 1440*0Sstevel@tonic-gate } 1441*0Sstevel@tonic-gate } 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate static void 1444*0Sstevel@tonic-gate channel_handler_init_20(void) 1445*0Sstevel@tonic-gate { 1446*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open; 1447*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; 1448*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; 1449*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; 1450*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; 1451*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 1452*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 1453*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; 1454*0Sstevel@tonic-gate 1455*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; 1456*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 1457*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; 1458*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; 1459*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 1460*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 1461*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; 1462*0Sstevel@tonic-gate } 1463*0Sstevel@tonic-gate 1464*0Sstevel@tonic-gate static void 1465*0Sstevel@tonic-gate channel_handler_init_13(void) 1466*0Sstevel@tonic-gate { 1467*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13; 1468*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open_13; 1469*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; 1470*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; 1471*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 1472*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_INPUT_DRAINING] = &channel_pre_input_draining; 1473*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining; 1474*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 1475*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; 1476*0Sstevel@tonic-gate 1477*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; 1478*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; 1479*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 1480*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 1481*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13; 1482*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 1483*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; 1484*0Sstevel@tonic-gate } 1485*0Sstevel@tonic-gate 1486*0Sstevel@tonic-gate static void 1487*0Sstevel@tonic-gate channel_handler_init_15(void) 1488*0Sstevel@tonic-gate { 1489*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open; 1490*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; 1491*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; 1492*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; 1493*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 1494*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 1495*0Sstevel@tonic-gate channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; 1496*0Sstevel@tonic-gate 1497*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; 1498*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 1499*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 1500*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; 1501*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 1502*0Sstevel@tonic-gate channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; 1503*0Sstevel@tonic-gate } 1504*0Sstevel@tonic-gate 1505*0Sstevel@tonic-gate static void 1506*0Sstevel@tonic-gate channel_handler_init(void) 1507*0Sstevel@tonic-gate { 1508*0Sstevel@tonic-gate int i; 1509*0Sstevel@tonic-gate 1510*0Sstevel@tonic-gate for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) { 1511*0Sstevel@tonic-gate channel_pre[i] = NULL; 1512*0Sstevel@tonic-gate channel_post[i] = NULL; 1513*0Sstevel@tonic-gate } 1514*0Sstevel@tonic-gate if (compat20) 1515*0Sstevel@tonic-gate channel_handler_init_20(); 1516*0Sstevel@tonic-gate else if (compat13) 1517*0Sstevel@tonic-gate channel_handler_init_13(); 1518*0Sstevel@tonic-gate else 1519*0Sstevel@tonic-gate channel_handler_init_15(); 1520*0Sstevel@tonic-gate } 1521*0Sstevel@tonic-gate 1522*0Sstevel@tonic-gate /* gc dead channels */ 1523*0Sstevel@tonic-gate static void 1524*0Sstevel@tonic-gate channel_garbage_collect(Channel *c) 1525*0Sstevel@tonic-gate { 1526*0Sstevel@tonic-gate if (c == NULL) 1527*0Sstevel@tonic-gate return; 1528*0Sstevel@tonic-gate if (c->detach_user != NULL) { 1529*0Sstevel@tonic-gate if (!chan_is_dead(c, 0)) 1530*0Sstevel@tonic-gate return; 1531*0Sstevel@tonic-gate debug("channel %d: gc: notify user", c->self); 1532*0Sstevel@tonic-gate c->detach_user(c->self, NULL); 1533*0Sstevel@tonic-gate /* if we still have a callback */ 1534*0Sstevel@tonic-gate if (c->detach_user != NULL) 1535*0Sstevel@tonic-gate return; 1536*0Sstevel@tonic-gate debug("channel %d: gc: user detached", c->self); 1537*0Sstevel@tonic-gate } 1538*0Sstevel@tonic-gate if (!c->wait_for_exit && !chan_is_dead(c, 1)) 1539*0Sstevel@tonic-gate return; 1540*0Sstevel@tonic-gate debug("channel %d: garbage collecting", c->self); 1541*0Sstevel@tonic-gate channel_free(c); 1542*0Sstevel@tonic-gate } 1543*0Sstevel@tonic-gate 1544*0Sstevel@tonic-gate static void 1545*0Sstevel@tonic-gate channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) 1546*0Sstevel@tonic-gate { 1547*0Sstevel@tonic-gate static int did_init = 0; 1548*0Sstevel@tonic-gate int i; 1549*0Sstevel@tonic-gate Channel *c; 1550*0Sstevel@tonic-gate 1551*0Sstevel@tonic-gate if (!did_init) { 1552*0Sstevel@tonic-gate channel_handler_init(); 1553*0Sstevel@tonic-gate did_init = 1; 1554*0Sstevel@tonic-gate } 1555*0Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 1556*0Sstevel@tonic-gate c = channels[i]; 1557*0Sstevel@tonic-gate if (c == NULL) 1558*0Sstevel@tonic-gate continue; 1559*0Sstevel@tonic-gate if (ftab[c->type] != NULL) 1560*0Sstevel@tonic-gate (*ftab[c->type])(c, readset, writeset); 1561*0Sstevel@tonic-gate channel_garbage_collect(c); 1562*0Sstevel@tonic-gate } 1563*0Sstevel@tonic-gate } 1564*0Sstevel@tonic-gate 1565*0Sstevel@tonic-gate /* 1566*0Sstevel@tonic-gate * Allocate/update select bitmasks and add any bits relevant to channels in 1567*0Sstevel@tonic-gate * select bitmasks. 1568*0Sstevel@tonic-gate */ 1569*0Sstevel@tonic-gate void 1570*0Sstevel@tonic-gate channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, 1571*0Sstevel@tonic-gate int *nallocp, int rekeying) 1572*0Sstevel@tonic-gate { 1573*0Sstevel@tonic-gate int n; 1574*0Sstevel@tonic-gate u_int sz; 1575*0Sstevel@tonic-gate 1576*0Sstevel@tonic-gate n = MAX(*maxfdp, channel_max_fd); 1577*0Sstevel@tonic-gate 1578*0Sstevel@tonic-gate sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); 1579*0Sstevel@tonic-gate /* perhaps check sz < nalloc/2 and shrink? */ 1580*0Sstevel@tonic-gate if (*readsetp == NULL || sz > *nallocp) { 1581*0Sstevel@tonic-gate *readsetp = xrealloc(*readsetp, sz); 1582*0Sstevel@tonic-gate *writesetp = xrealloc(*writesetp, sz); 1583*0Sstevel@tonic-gate *nallocp = sz; 1584*0Sstevel@tonic-gate } 1585*0Sstevel@tonic-gate *maxfdp = n; 1586*0Sstevel@tonic-gate memset(*readsetp, 0, sz); 1587*0Sstevel@tonic-gate memset(*writesetp, 0, sz); 1588*0Sstevel@tonic-gate 1589*0Sstevel@tonic-gate if (!rekeying) 1590*0Sstevel@tonic-gate channel_handler(channel_pre, *readsetp, *writesetp); 1591*0Sstevel@tonic-gate } 1592*0Sstevel@tonic-gate 1593*0Sstevel@tonic-gate /* 1594*0Sstevel@tonic-gate * After select, perform any appropriate operations for channels which have 1595*0Sstevel@tonic-gate * events pending. 1596*0Sstevel@tonic-gate */ 1597*0Sstevel@tonic-gate void 1598*0Sstevel@tonic-gate channel_after_select(fd_set * readset, fd_set * writeset) 1599*0Sstevel@tonic-gate { 1600*0Sstevel@tonic-gate channel_handler(channel_post, readset, writeset); 1601*0Sstevel@tonic-gate } 1602*0Sstevel@tonic-gate 1603*0Sstevel@tonic-gate 1604*0Sstevel@tonic-gate /* If there is data to send to the connection, enqueue some of it now. */ 1605*0Sstevel@tonic-gate 1606*0Sstevel@tonic-gate void 1607*0Sstevel@tonic-gate channel_output_poll(void) 1608*0Sstevel@tonic-gate { 1609*0Sstevel@tonic-gate Channel *c; 1610*0Sstevel@tonic-gate int i; 1611*0Sstevel@tonic-gate u_int len; 1612*0Sstevel@tonic-gate 1613*0Sstevel@tonic-gate for (i = 0; i < channels_alloc; i++) { 1614*0Sstevel@tonic-gate c = channels[i]; 1615*0Sstevel@tonic-gate if (c == NULL) 1616*0Sstevel@tonic-gate continue; 1617*0Sstevel@tonic-gate 1618*0Sstevel@tonic-gate /* 1619*0Sstevel@tonic-gate * We are only interested in channels that can have buffered 1620*0Sstevel@tonic-gate * incoming data. 1621*0Sstevel@tonic-gate */ 1622*0Sstevel@tonic-gate if (compat13) { 1623*0Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN && 1624*0Sstevel@tonic-gate c->type != SSH_CHANNEL_INPUT_DRAINING) 1625*0Sstevel@tonic-gate continue; 1626*0Sstevel@tonic-gate } else { 1627*0Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN) 1628*0Sstevel@tonic-gate continue; 1629*0Sstevel@tonic-gate } 1630*0Sstevel@tonic-gate if (compat20 && 1631*0Sstevel@tonic-gate (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { 1632*0Sstevel@tonic-gate /* XXX is this true? */ 1633*0Sstevel@tonic-gate debug3("channel %d: will not send data after close", c->self); 1634*0Sstevel@tonic-gate continue; 1635*0Sstevel@tonic-gate } 1636*0Sstevel@tonic-gate 1637*0Sstevel@tonic-gate /* Get the amount of buffered data for this channel. */ 1638*0Sstevel@tonic-gate if ((c->istate == CHAN_INPUT_OPEN || 1639*0Sstevel@tonic-gate c->istate == CHAN_INPUT_WAIT_DRAIN) && 1640*0Sstevel@tonic-gate (len = buffer_len(&c->input)) > 0) { 1641*0Sstevel@tonic-gate /* 1642*0Sstevel@tonic-gate * Send some data for the other side over the secure 1643*0Sstevel@tonic-gate * connection. 1644*0Sstevel@tonic-gate */ 1645*0Sstevel@tonic-gate if (compat20) { 1646*0Sstevel@tonic-gate if (len > c->remote_window) 1647*0Sstevel@tonic-gate len = c->remote_window; 1648*0Sstevel@tonic-gate if (len > c->remote_maxpacket) 1649*0Sstevel@tonic-gate len = c->remote_maxpacket; 1650*0Sstevel@tonic-gate } else { 1651*0Sstevel@tonic-gate if (packet_is_interactive()) { 1652*0Sstevel@tonic-gate if (len > 1024) 1653*0Sstevel@tonic-gate len = 512; 1654*0Sstevel@tonic-gate } else { 1655*0Sstevel@tonic-gate /* Keep the packets at reasonable size. */ 1656*0Sstevel@tonic-gate if (len > packet_get_maxsize()/2) 1657*0Sstevel@tonic-gate len = packet_get_maxsize()/2; 1658*0Sstevel@tonic-gate } 1659*0Sstevel@tonic-gate } 1660*0Sstevel@tonic-gate if (len > 0) { 1661*0Sstevel@tonic-gate packet_start(compat20 ? 1662*0Sstevel@tonic-gate SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA); 1663*0Sstevel@tonic-gate packet_put_int(c->remote_id); 1664*0Sstevel@tonic-gate packet_put_string(buffer_ptr(&c->input), len); 1665*0Sstevel@tonic-gate packet_send(); 1666*0Sstevel@tonic-gate buffer_consume(&c->input, len); 1667*0Sstevel@tonic-gate c->remote_window -= len; 1668*0Sstevel@tonic-gate } 1669*0Sstevel@tonic-gate } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) { 1670*0Sstevel@tonic-gate if (compat13) 1671*0Sstevel@tonic-gate fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); 1672*0Sstevel@tonic-gate /* 1673*0Sstevel@tonic-gate * input-buffer is empty and read-socket shutdown: 1674*0Sstevel@tonic-gate * tell peer, that we will not send more data: send IEOF. 1675*0Sstevel@tonic-gate * hack for extended data: delay EOF if EFD still in use. 1676*0Sstevel@tonic-gate */ 1677*0Sstevel@tonic-gate if (CHANNEL_EFD_INPUT_ACTIVE(c)) 1678*0Sstevel@tonic-gate debug2("channel %d: ibuf_empty delayed efd %d/(%d)", 1679*0Sstevel@tonic-gate c->self, c->efd, buffer_len(&c->extended)); 1680*0Sstevel@tonic-gate else 1681*0Sstevel@tonic-gate chan_ibuf_empty(c); 1682*0Sstevel@tonic-gate } 1683*0Sstevel@tonic-gate /* Send extended data, i.e. stderr */ 1684*0Sstevel@tonic-gate if (compat20 && 1685*0Sstevel@tonic-gate !(c->flags & CHAN_EOF_SENT) && 1686*0Sstevel@tonic-gate c->remote_window > 0 && 1687*0Sstevel@tonic-gate (len = buffer_len(&c->extended)) > 0 && 1688*0Sstevel@tonic-gate c->extended_usage == CHAN_EXTENDED_READ) { 1689*0Sstevel@tonic-gate debug2("channel %d: rwin %u elen %u euse %d", 1690*0Sstevel@tonic-gate c->self, c->remote_window, buffer_len(&c->extended), 1691*0Sstevel@tonic-gate c->extended_usage); 1692*0Sstevel@tonic-gate if (len > c->remote_window) 1693*0Sstevel@tonic-gate len = c->remote_window; 1694*0Sstevel@tonic-gate if (len > c->remote_maxpacket) 1695*0Sstevel@tonic-gate len = c->remote_maxpacket; 1696*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA); 1697*0Sstevel@tonic-gate packet_put_int(c->remote_id); 1698*0Sstevel@tonic-gate packet_put_int(SSH2_EXTENDED_DATA_STDERR); 1699*0Sstevel@tonic-gate packet_put_string(buffer_ptr(&c->extended), len); 1700*0Sstevel@tonic-gate packet_send(); 1701*0Sstevel@tonic-gate buffer_consume(&c->extended, len); 1702*0Sstevel@tonic-gate c->remote_window -= len; 1703*0Sstevel@tonic-gate debug2("channel %d: sent ext data %d", c->self, len); 1704*0Sstevel@tonic-gate } 1705*0Sstevel@tonic-gate } 1706*0Sstevel@tonic-gate } 1707*0Sstevel@tonic-gate 1708*0Sstevel@tonic-gate 1709*0Sstevel@tonic-gate /* -- protocol input */ 1710*0Sstevel@tonic-gate 1711*0Sstevel@tonic-gate void 1712*0Sstevel@tonic-gate channel_input_data(int type, u_int32_t seq, void *ctxt) 1713*0Sstevel@tonic-gate { 1714*0Sstevel@tonic-gate int id; 1715*0Sstevel@tonic-gate char *data; 1716*0Sstevel@tonic-gate u_int data_len; 1717*0Sstevel@tonic-gate Channel *c; 1718*0Sstevel@tonic-gate 1719*0Sstevel@tonic-gate /* Get the channel number and verify it. */ 1720*0Sstevel@tonic-gate id = packet_get_int(); 1721*0Sstevel@tonic-gate c = channel_lookup(id); 1722*0Sstevel@tonic-gate if (c == NULL) 1723*0Sstevel@tonic-gate packet_disconnect("Received data for nonexistent channel %d.", id); 1724*0Sstevel@tonic-gate 1725*0Sstevel@tonic-gate /* Ignore any data for non-open channels (might happen on close) */ 1726*0Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN && 1727*0Sstevel@tonic-gate c->type != SSH_CHANNEL_X11_OPEN) 1728*0Sstevel@tonic-gate return; 1729*0Sstevel@tonic-gate 1730*0Sstevel@tonic-gate /* same for protocol 1.5 if output end is no longer open */ 1731*0Sstevel@tonic-gate if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) 1732*0Sstevel@tonic-gate return; 1733*0Sstevel@tonic-gate 1734*0Sstevel@tonic-gate /* Get the data. */ 1735*0Sstevel@tonic-gate data = packet_get_string(&data_len); 1736*0Sstevel@tonic-gate 1737*0Sstevel@tonic-gate if (compat20) { 1738*0Sstevel@tonic-gate if (data_len > c->local_maxpacket) { 1739*0Sstevel@tonic-gate log("channel %d: rcvd big packet %d, maxpack %d", 1740*0Sstevel@tonic-gate c->self, data_len, c->local_maxpacket); 1741*0Sstevel@tonic-gate } 1742*0Sstevel@tonic-gate if (data_len > c->local_window) { 1743*0Sstevel@tonic-gate log("channel %d: rcvd too much data %d, win %d", 1744*0Sstevel@tonic-gate c->self, data_len, c->local_window); 1745*0Sstevel@tonic-gate xfree(data); 1746*0Sstevel@tonic-gate return; 1747*0Sstevel@tonic-gate } 1748*0Sstevel@tonic-gate c->local_window -= data_len; 1749*0Sstevel@tonic-gate } 1750*0Sstevel@tonic-gate packet_check_eom(); 1751*0Sstevel@tonic-gate buffer_append(&c->output, data, data_len); 1752*0Sstevel@tonic-gate xfree(data); 1753*0Sstevel@tonic-gate } 1754*0Sstevel@tonic-gate 1755*0Sstevel@tonic-gate void 1756*0Sstevel@tonic-gate channel_input_extended_data(int type, u_int32_t seq, void *ctxt) 1757*0Sstevel@tonic-gate { 1758*0Sstevel@tonic-gate int id; 1759*0Sstevel@tonic-gate char *data; 1760*0Sstevel@tonic-gate u_int data_len, tcode; 1761*0Sstevel@tonic-gate Channel *c; 1762*0Sstevel@tonic-gate 1763*0Sstevel@tonic-gate /* Get the channel number and verify it. */ 1764*0Sstevel@tonic-gate id = packet_get_int(); 1765*0Sstevel@tonic-gate c = channel_lookup(id); 1766*0Sstevel@tonic-gate 1767*0Sstevel@tonic-gate if (c == NULL) 1768*0Sstevel@tonic-gate packet_disconnect("Received extended_data for bad channel %d.", id); 1769*0Sstevel@tonic-gate if (c->type != SSH_CHANNEL_OPEN) { 1770*0Sstevel@tonic-gate log("channel %d: ext data for non open", id); 1771*0Sstevel@tonic-gate return; 1772*0Sstevel@tonic-gate } 1773*0Sstevel@tonic-gate if (c->flags & CHAN_EOF_RCVD) { 1774*0Sstevel@tonic-gate if (datafellows & SSH_BUG_EXTEOF) 1775*0Sstevel@tonic-gate debug("channel %d: accepting ext data after eof", id); 1776*0Sstevel@tonic-gate else 1777*0Sstevel@tonic-gate packet_disconnect("Received extended_data after EOF " 1778*0Sstevel@tonic-gate "on channel %d.", id); 1779*0Sstevel@tonic-gate } 1780*0Sstevel@tonic-gate tcode = packet_get_int(); 1781*0Sstevel@tonic-gate if (c->efd == -1 || 1782*0Sstevel@tonic-gate c->extended_usage != CHAN_EXTENDED_WRITE || 1783*0Sstevel@tonic-gate tcode != SSH2_EXTENDED_DATA_STDERR) { 1784*0Sstevel@tonic-gate log("channel %d: bad ext data", c->self); 1785*0Sstevel@tonic-gate return; 1786*0Sstevel@tonic-gate } 1787*0Sstevel@tonic-gate data = packet_get_string(&data_len); 1788*0Sstevel@tonic-gate packet_check_eom(); 1789*0Sstevel@tonic-gate if (data_len > c->local_window) { 1790*0Sstevel@tonic-gate log("channel %d: rcvd too much extended_data %d, win %d", 1791*0Sstevel@tonic-gate c->self, data_len, c->local_window); 1792*0Sstevel@tonic-gate xfree(data); 1793*0Sstevel@tonic-gate return; 1794*0Sstevel@tonic-gate } 1795*0Sstevel@tonic-gate debug2("channel %d: rcvd ext data %d", c->self, data_len); 1796*0Sstevel@tonic-gate c->local_window -= data_len; 1797*0Sstevel@tonic-gate buffer_append(&c->extended, data, data_len); 1798*0Sstevel@tonic-gate xfree(data); 1799*0Sstevel@tonic-gate } 1800*0Sstevel@tonic-gate 1801*0Sstevel@tonic-gate void 1802*0Sstevel@tonic-gate channel_input_ieof(int type, u_int32_t seq, void *ctxt) 1803*0Sstevel@tonic-gate { 1804*0Sstevel@tonic-gate int id; 1805*0Sstevel@tonic-gate Channel *c; 1806*0Sstevel@tonic-gate 1807*0Sstevel@tonic-gate id = packet_get_int(); 1808*0Sstevel@tonic-gate packet_check_eom(); 1809*0Sstevel@tonic-gate c = channel_lookup(id); 1810*0Sstevel@tonic-gate if (c == NULL) 1811*0Sstevel@tonic-gate packet_disconnect("Received ieof for nonexistent channel %d.", id); 1812*0Sstevel@tonic-gate chan_rcvd_ieof(c); 1813*0Sstevel@tonic-gate 1814*0Sstevel@tonic-gate /* XXX force input close */ 1815*0Sstevel@tonic-gate if (c->force_drain && c->istate == CHAN_INPUT_OPEN) { 1816*0Sstevel@tonic-gate debug("channel %d: FORCE input drain", c->self); 1817*0Sstevel@tonic-gate c->istate = CHAN_INPUT_WAIT_DRAIN; 1818*0Sstevel@tonic-gate if (buffer_len(&c->input) == 0) 1819*0Sstevel@tonic-gate chan_ibuf_empty(c); 1820*0Sstevel@tonic-gate } 1821*0Sstevel@tonic-gate 1822*0Sstevel@tonic-gate } 1823*0Sstevel@tonic-gate 1824*0Sstevel@tonic-gate void 1825*0Sstevel@tonic-gate channel_input_close(int type, u_int32_t seq, void *ctxt) 1826*0Sstevel@tonic-gate { 1827*0Sstevel@tonic-gate int id; 1828*0Sstevel@tonic-gate Channel *c; 1829*0Sstevel@tonic-gate 1830*0Sstevel@tonic-gate id = packet_get_int(); 1831*0Sstevel@tonic-gate packet_check_eom(); 1832*0Sstevel@tonic-gate c = channel_lookup(id); 1833*0Sstevel@tonic-gate if (c == NULL) 1834*0Sstevel@tonic-gate packet_disconnect("Received close for nonexistent channel %d.", id); 1835*0Sstevel@tonic-gate 1836*0Sstevel@tonic-gate /* 1837*0Sstevel@tonic-gate * Send a confirmation that we have closed the channel and no more 1838*0Sstevel@tonic-gate * data is coming for it. 1839*0Sstevel@tonic-gate */ 1840*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); 1841*0Sstevel@tonic-gate packet_put_int(c->remote_id); 1842*0Sstevel@tonic-gate packet_send(); 1843*0Sstevel@tonic-gate 1844*0Sstevel@tonic-gate /* 1845*0Sstevel@tonic-gate * If the channel is in closed state, we have sent a close request, 1846*0Sstevel@tonic-gate * and the other side will eventually respond with a confirmation. 1847*0Sstevel@tonic-gate * Thus, we cannot free the channel here, because then there would be 1848*0Sstevel@tonic-gate * no-one to receive the confirmation. The channel gets freed when 1849*0Sstevel@tonic-gate * the confirmation arrives. 1850*0Sstevel@tonic-gate */ 1851*0Sstevel@tonic-gate if (c->type != SSH_CHANNEL_CLOSED) { 1852*0Sstevel@tonic-gate /* 1853*0Sstevel@tonic-gate * Not a closed channel - mark it as draining, which will 1854*0Sstevel@tonic-gate * cause it to be freed later. 1855*0Sstevel@tonic-gate */ 1856*0Sstevel@tonic-gate buffer_clear(&c->input); 1857*0Sstevel@tonic-gate c->type = SSH_CHANNEL_OUTPUT_DRAINING; 1858*0Sstevel@tonic-gate } 1859*0Sstevel@tonic-gate } 1860*0Sstevel@tonic-gate 1861*0Sstevel@tonic-gate /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ 1862*0Sstevel@tonic-gate void 1863*0Sstevel@tonic-gate channel_input_oclose(int type, u_int32_t seq, void *ctxt) 1864*0Sstevel@tonic-gate { 1865*0Sstevel@tonic-gate int id = packet_get_int(); 1866*0Sstevel@tonic-gate Channel *c = channel_lookup(id); 1867*0Sstevel@tonic-gate 1868*0Sstevel@tonic-gate packet_check_eom(); 1869*0Sstevel@tonic-gate if (c == NULL) 1870*0Sstevel@tonic-gate packet_disconnect("Received oclose for nonexistent channel %d.", id); 1871*0Sstevel@tonic-gate chan_rcvd_oclose(c); 1872*0Sstevel@tonic-gate } 1873*0Sstevel@tonic-gate 1874*0Sstevel@tonic-gate void 1875*0Sstevel@tonic-gate channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt) 1876*0Sstevel@tonic-gate { 1877*0Sstevel@tonic-gate int id = packet_get_int(); 1878*0Sstevel@tonic-gate Channel *c = channel_lookup(id); 1879*0Sstevel@tonic-gate 1880*0Sstevel@tonic-gate packet_check_eom(); 1881*0Sstevel@tonic-gate if (c == NULL) 1882*0Sstevel@tonic-gate packet_disconnect("Received close confirmation for " 1883*0Sstevel@tonic-gate "out-of-range channel %d.", id); 1884*0Sstevel@tonic-gate if (c->type != SSH_CHANNEL_CLOSED) 1885*0Sstevel@tonic-gate packet_disconnect("Received close confirmation for " 1886*0Sstevel@tonic-gate "non-closed channel %d (type %d).", id, c->type); 1887*0Sstevel@tonic-gate channel_free(c); 1888*0Sstevel@tonic-gate } 1889*0Sstevel@tonic-gate 1890*0Sstevel@tonic-gate void 1891*0Sstevel@tonic-gate channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) 1892*0Sstevel@tonic-gate { 1893*0Sstevel@tonic-gate int id, remote_id; 1894*0Sstevel@tonic-gate Channel *c; 1895*0Sstevel@tonic-gate 1896*0Sstevel@tonic-gate id = packet_get_int(); 1897*0Sstevel@tonic-gate c = channel_lookup(id); 1898*0Sstevel@tonic-gate 1899*0Sstevel@tonic-gate if (c==NULL || c->type != SSH_CHANNEL_OPENING) 1900*0Sstevel@tonic-gate packet_disconnect("Received open confirmation for " 1901*0Sstevel@tonic-gate "non-opening channel %d.", id); 1902*0Sstevel@tonic-gate remote_id = packet_get_int(); 1903*0Sstevel@tonic-gate /* Record the remote channel number and mark that the channel is now open. */ 1904*0Sstevel@tonic-gate c->remote_id = remote_id; 1905*0Sstevel@tonic-gate c->type = SSH_CHANNEL_OPEN; 1906*0Sstevel@tonic-gate 1907*0Sstevel@tonic-gate if (compat20) { 1908*0Sstevel@tonic-gate c->remote_window = packet_get_int(); 1909*0Sstevel@tonic-gate c->remote_maxpacket = packet_get_int(); 1910*0Sstevel@tonic-gate if (c->confirm) { 1911*0Sstevel@tonic-gate debug2("callback start"); 1912*0Sstevel@tonic-gate c->confirm(c->self, NULL); 1913*0Sstevel@tonic-gate debug2("callback done"); 1914*0Sstevel@tonic-gate } 1915*0Sstevel@tonic-gate debug("channel %d: open confirm rwindow %u rmax %u", c->self, 1916*0Sstevel@tonic-gate c->remote_window, c->remote_maxpacket); 1917*0Sstevel@tonic-gate } 1918*0Sstevel@tonic-gate packet_check_eom(); 1919*0Sstevel@tonic-gate } 1920*0Sstevel@tonic-gate 1921*0Sstevel@tonic-gate static char * 1922*0Sstevel@tonic-gate reason2txt(int reason) 1923*0Sstevel@tonic-gate { 1924*0Sstevel@tonic-gate switch (reason) { 1925*0Sstevel@tonic-gate case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED: 1926*0Sstevel@tonic-gate return "administratively prohibited"; 1927*0Sstevel@tonic-gate case SSH2_OPEN_CONNECT_FAILED: 1928*0Sstevel@tonic-gate return "connect failed"; 1929*0Sstevel@tonic-gate case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE: 1930*0Sstevel@tonic-gate return "unknown channel type"; 1931*0Sstevel@tonic-gate case SSH2_OPEN_RESOURCE_SHORTAGE: 1932*0Sstevel@tonic-gate return "resource shortage"; 1933*0Sstevel@tonic-gate } 1934*0Sstevel@tonic-gate return "unknown reason"; 1935*0Sstevel@tonic-gate } 1936*0Sstevel@tonic-gate 1937*0Sstevel@tonic-gate void 1938*0Sstevel@tonic-gate channel_input_open_failure(int type, u_int32_t seq, void *ctxt) 1939*0Sstevel@tonic-gate { 1940*0Sstevel@tonic-gate int id, reason; 1941*0Sstevel@tonic-gate char *msg = NULL, *lang = NULL; 1942*0Sstevel@tonic-gate Channel *c; 1943*0Sstevel@tonic-gate 1944*0Sstevel@tonic-gate id = packet_get_int(); 1945*0Sstevel@tonic-gate c = channel_lookup(id); 1946*0Sstevel@tonic-gate 1947*0Sstevel@tonic-gate if (c==NULL || c->type != SSH_CHANNEL_OPENING) 1948*0Sstevel@tonic-gate packet_disconnect("Received open failure for " 1949*0Sstevel@tonic-gate "non-opening channel %d.", id); 1950*0Sstevel@tonic-gate if (compat20) { 1951*0Sstevel@tonic-gate reason = packet_get_int(); 1952*0Sstevel@tonic-gate if (!(datafellows & SSH_BUG_OPENFAILURE)) { 1953*0Sstevel@tonic-gate msg = packet_get_string(NULL); 1954*0Sstevel@tonic-gate lang = packet_get_string(NULL); 1955*0Sstevel@tonic-gate } 1956*0Sstevel@tonic-gate log("channel %d: open failed: %s%s%s", id, 1957*0Sstevel@tonic-gate reason2txt(reason), msg ? ": ": "", msg ? msg : ""); 1958*0Sstevel@tonic-gate if (msg != NULL) 1959*0Sstevel@tonic-gate xfree(msg); 1960*0Sstevel@tonic-gate if (lang != NULL) 1961*0Sstevel@tonic-gate xfree(lang); 1962*0Sstevel@tonic-gate } 1963*0Sstevel@tonic-gate packet_check_eom(); 1964*0Sstevel@tonic-gate /* Free the channel. This will also close the socket. */ 1965*0Sstevel@tonic-gate channel_free(c); 1966*0Sstevel@tonic-gate } 1967*0Sstevel@tonic-gate 1968*0Sstevel@tonic-gate void 1969*0Sstevel@tonic-gate channel_input_window_adjust(int type, u_int32_t seq, void *ctxt) 1970*0Sstevel@tonic-gate { 1971*0Sstevel@tonic-gate Channel *c; 1972*0Sstevel@tonic-gate int id; 1973*0Sstevel@tonic-gate u_int adjust; 1974*0Sstevel@tonic-gate 1975*0Sstevel@tonic-gate if (!compat20) 1976*0Sstevel@tonic-gate return; 1977*0Sstevel@tonic-gate 1978*0Sstevel@tonic-gate /* Get the channel number and verify it. */ 1979*0Sstevel@tonic-gate id = packet_get_int(); 1980*0Sstevel@tonic-gate c = channel_lookup(id); 1981*0Sstevel@tonic-gate 1982*0Sstevel@tonic-gate if (c == NULL || c->type != SSH_CHANNEL_OPEN) { 1983*0Sstevel@tonic-gate log("Received window adjust for " 1984*0Sstevel@tonic-gate "non-open channel %d.", id); 1985*0Sstevel@tonic-gate return; 1986*0Sstevel@tonic-gate } 1987*0Sstevel@tonic-gate adjust = packet_get_int(); 1988*0Sstevel@tonic-gate packet_check_eom(); 1989*0Sstevel@tonic-gate debug2("channel %d: rcvd adjust %u", id, adjust); 1990*0Sstevel@tonic-gate c->remote_window += adjust; 1991*0Sstevel@tonic-gate } 1992*0Sstevel@tonic-gate 1993*0Sstevel@tonic-gate void 1994*0Sstevel@tonic-gate channel_input_port_open(int type, u_int32_t seq, void *ctxt) 1995*0Sstevel@tonic-gate { 1996*0Sstevel@tonic-gate Channel *c = NULL; 1997*0Sstevel@tonic-gate u_short host_port; 1998*0Sstevel@tonic-gate char *host, *originator_string; 1999*0Sstevel@tonic-gate int remote_id, sock = -1; 2000*0Sstevel@tonic-gate 2001*0Sstevel@tonic-gate remote_id = packet_get_int(); 2002*0Sstevel@tonic-gate host = packet_get_string(NULL); 2003*0Sstevel@tonic-gate host_port = packet_get_int(); 2004*0Sstevel@tonic-gate 2005*0Sstevel@tonic-gate if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) { 2006*0Sstevel@tonic-gate originator_string = packet_get_string(NULL); 2007*0Sstevel@tonic-gate } else { 2008*0Sstevel@tonic-gate originator_string = xstrdup("unknown (remote did not supply name)"); 2009*0Sstevel@tonic-gate } 2010*0Sstevel@tonic-gate packet_check_eom(); 2011*0Sstevel@tonic-gate sock = channel_connect_to(host, host_port); 2012*0Sstevel@tonic-gate if (sock != -1) { 2013*0Sstevel@tonic-gate c = channel_new("connected socket", 2014*0Sstevel@tonic-gate SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0, 2015*0Sstevel@tonic-gate originator_string, 1); 2016*0Sstevel@tonic-gate c->remote_id = remote_id; 2017*0Sstevel@tonic-gate } 2018*0Sstevel@tonic-gate if (c == NULL) { 2019*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 2020*0Sstevel@tonic-gate packet_put_int(remote_id); 2021*0Sstevel@tonic-gate packet_send(); 2022*0Sstevel@tonic-gate } 2023*0Sstevel@tonic-gate xfree(host); 2024*0Sstevel@tonic-gate } 2025*0Sstevel@tonic-gate 2026*0Sstevel@tonic-gate 2027*0Sstevel@tonic-gate /* -- tcp forwarding */ 2028*0Sstevel@tonic-gate 2029*0Sstevel@tonic-gate void 2030*0Sstevel@tonic-gate channel_set_af(int af) 2031*0Sstevel@tonic-gate { 2032*0Sstevel@tonic-gate IPv4or6 = af; 2033*0Sstevel@tonic-gate } 2034*0Sstevel@tonic-gate 2035*0Sstevel@tonic-gate static int 2036*0Sstevel@tonic-gate channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, 2037*0Sstevel@tonic-gate const char *host_to_connect, u_short port_to_connect, int gateway_ports) 2038*0Sstevel@tonic-gate { 2039*0Sstevel@tonic-gate Channel *c; 2040*0Sstevel@tonic-gate int success, sock, on = 1; 2041*0Sstevel@tonic-gate struct addrinfo hints, *ai, *aitop; 2042*0Sstevel@tonic-gate const char *host; 2043*0Sstevel@tonic-gate char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 2044*0Sstevel@tonic-gate 2045*0Sstevel@tonic-gate success = 0; 2046*0Sstevel@tonic-gate host = (type == SSH_CHANNEL_RPORT_LISTENER) ? 2047*0Sstevel@tonic-gate listen_addr : host_to_connect; 2048*0Sstevel@tonic-gate 2049*0Sstevel@tonic-gate if (host == NULL) { 2050*0Sstevel@tonic-gate error("No forward host name."); 2051*0Sstevel@tonic-gate return success; 2052*0Sstevel@tonic-gate } 2053*0Sstevel@tonic-gate if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) { 2054*0Sstevel@tonic-gate error("Forward host name too long."); 2055*0Sstevel@tonic-gate return success; 2056*0Sstevel@tonic-gate } 2057*0Sstevel@tonic-gate 2058*0Sstevel@tonic-gate /* 2059*0Sstevel@tonic-gate * getaddrinfo returns a loopback address if the hostname is 2060*0Sstevel@tonic-gate * set to NULL and hints.ai_flags is not AI_PASSIVE 2061*0Sstevel@tonic-gate */ 2062*0Sstevel@tonic-gate memset(&hints, 0, sizeof(hints)); 2063*0Sstevel@tonic-gate hints.ai_family = IPv4or6; 2064*0Sstevel@tonic-gate hints.ai_flags = gateway_ports ? AI_PASSIVE : 0; 2065*0Sstevel@tonic-gate hints.ai_socktype = SOCK_STREAM; 2066*0Sstevel@tonic-gate snprintf(strport, sizeof strport, "%d", listen_port); 2067*0Sstevel@tonic-gate if (getaddrinfo(NULL, strport, &hints, &aitop) != 0) 2068*0Sstevel@tonic-gate packet_disconnect("getaddrinfo: fatal error"); 2069*0Sstevel@tonic-gate 2070*0Sstevel@tonic-gate for (ai = aitop; ai; ai = ai->ai_next) { 2071*0Sstevel@tonic-gate if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 2072*0Sstevel@tonic-gate continue; 2073*0Sstevel@tonic-gate if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), 2074*0Sstevel@tonic-gate strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 2075*0Sstevel@tonic-gate error("channel_setup_fwd_listener: getnameinfo failed"); 2076*0Sstevel@tonic-gate continue; 2077*0Sstevel@tonic-gate } 2078*0Sstevel@tonic-gate /* Create a port to listen for the host. */ 2079*0Sstevel@tonic-gate sock = socket(ai->ai_family, SOCK_STREAM, 0); 2080*0Sstevel@tonic-gate if (sock < 0) { 2081*0Sstevel@tonic-gate /* this is no error since kernel may not support ipv6 */ 2082*0Sstevel@tonic-gate verbose("socket: %.100s", strerror(errno)); 2083*0Sstevel@tonic-gate continue; 2084*0Sstevel@tonic-gate } 2085*0Sstevel@tonic-gate /* 2086*0Sstevel@tonic-gate * Set socket options. 2087*0Sstevel@tonic-gate * Allow local port reuse in TIME_WAIT. 2088*0Sstevel@tonic-gate */ 2089*0Sstevel@tonic-gate if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, 2090*0Sstevel@tonic-gate sizeof(on)) == -1) 2091*0Sstevel@tonic-gate error("setsockopt SO_REUSEADDR: %s", strerror(errno)); 2092*0Sstevel@tonic-gate 2093*0Sstevel@tonic-gate debug("Local forwarding listening on %s port %s.", ntop, strport); 2094*0Sstevel@tonic-gate 2095*0Sstevel@tonic-gate /* Bind the socket to the address. */ 2096*0Sstevel@tonic-gate if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 2097*0Sstevel@tonic-gate /* address can be in use ipv6 address is already bound */ 2098*0Sstevel@tonic-gate if (!ai->ai_next) 2099*0Sstevel@tonic-gate error("bind: %.100s", strerror(errno)); 2100*0Sstevel@tonic-gate else 2101*0Sstevel@tonic-gate verbose("bind: %.100s", strerror(errno)); 2102*0Sstevel@tonic-gate 2103*0Sstevel@tonic-gate close(sock); 2104*0Sstevel@tonic-gate continue; 2105*0Sstevel@tonic-gate } 2106*0Sstevel@tonic-gate /* Start listening for connections on the socket. */ 2107*0Sstevel@tonic-gate if (listen(sock, 5) < 0) { 2108*0Sstevel@tonic-gate error("listen: %.100s", strerror(errno)); 2109*0Sstevel@tonic-gate close(sock); 2110*0Sstevel@tonic-gate continue; 2111*0Sstevel@tonic-gate } 2112*0Sstevel@tonic-gate /* Allocate a channel number for the socket. */ 2113*0Sstevel@tonic-gate c = channel_new("port listener", type, sock, sock, -1, 2114*0Sstevel@tonic-gate CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 2115*0Sstevel@tonic-gate 0, xstrdup("port listener"), 1); 2116*0Sstevel@tonic-gate strlcpy(c->path, host, sizeof(c->path)); 2117*0Sstevel@tonic-gate c->host_port = port_to_connect; 2118*0Sstevel@tonic-gate c->listening_port = listen_port; 2119*0Sstevel@tonic-gate success = 1; 2120*0Sstevel@tonic-gate } 2121*0Sstevel@tonic-gate if (success == 0) 2122*0Sstevel@tonic-gate error("channel_setup_fwd_listener: cannot listen to port: %d", 2123*0Sstevel@tonic-gate listen_port); 2124*0Sstevel@tonic-gate freeaddrinfo(aitop); 2125*0Sstevel@tonic-gate return success; 2126*0Sstevel@tonic-gate } 2127*0Sstevel@tonic-gate 2128*0Sstevel@tonic-gate /* protocol local port fwd, used by ssh (and sshd in v1) */ 2129*0Sstevel@tonic-gate int 2130*0Sstevel@tonic-gate channel_setup_local_fwd_listener(u_short listen_port, 2131*0Sstevel@tonic-gate const char *host_to_connect, u_short port_to_connect, int gateway_ports) 2132*0Sstevel@tonic-gate { 2133*0Sstevel@tonic-gate return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, 2134*0Sstevel@tonic-gate NULL, listen_port, host_to_connect, port_to_connect, gateway_ports); 2135*0Sstevel@tonic-gate } 2136*0Sstevel@tonic-gate 2137*0Sstevel@tonic-gate /* protocol v2 remote port fwd, used by sshd */ 2138*0Sstevel@tonic-gate int 2139*0Sstevel@tonic-gate channel_setup_remote_fwd_listener(const char *listen_address, 2140*0Sstevel@tonic-gate u_short listen_port, int gateway_ports) 2141*0Sstevel@tonic-gate { 2142*0Sstevel@tonic-gate return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, 2143*0Sstevel@tonic-gate listen_address, listen_port, NULL, 0, gateway_ports); 2144*0Sstevel@tonic-gate } 2145*0Sstevel@tonic-gate 2146*0Sstevel@tonic-gate /* 2147*0Sstevel@tonic-gate * Initiate forwarding of connections to port "port" on remote host through 2148*0Sstevel@tonic-gate * the secure channel to host:port from local side. 2149*0Sstevel@tonic-gate */ 2150*0Sstevel@tonic-gate 2151*0Sstevel@tonic-gate void 2152*0Sstevel@tonic-gate channel_request_remote_forwarding(u_short listen_port, 2153*0Sstevel@tonic-gate const char *host_to_connect, u_short port_to_connect) 2154*0Sstevel@tonic-gate { 2155*0Sstevel@tonic-gate int type, success = 0; 2156*0Sstevel@tonic-gate 2157*0Sstevel@tonic-gate /* Record locally that connection to this host/port is permitted. */ 2158*0Sstevel@tonic-gate if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) 2159*0Sstevel@tonic-gate fatal("channel_request_remote_forwarding: too many forwards"); 2160*0Sstevel@tonic-gate 2161*0Sstevel@tonic-gate /* Send the forward request to the remote side. */ 2162*0Sstevel@tonic-gate if (compat20) { 2163*0Sstevel@tonic-gate const char *address_to_bind = "0.0.0.0"; 2164*0Sstevel@tonic-gate packet_start(SSH2_MSG_GLOBAL_REQUEST); 2165*0Sstevel@tonic-gate packet_put_cstring("tcpip-forward"); 2166*0Sstevel@tonic-gate packet_put_char(1); /* boolean: want reply */ 2167*0Sstevel@tonic-gate packet_put_cstring(address_to_bind); 2168*0Sstevel@tonic-gate packet_put_int(listen_port); 2169*0Sstevel@tonic-gate packet_send(); 2170*0Sstevel@tonic-gate packet_write_wait(); 2171*0Sstevel@tonic-gate /* Assume that server accepts the request */ 2172*0Sstevel@tonic-gate success = 1; 2173*0Sstevel@tonic-gate } else { 2174*0Sstevel@tonic-gate packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); 2175*0Sstevel@tonic-gate packet_put_int(listen_port); 2176*0Sstevel@tonic-gate packet_put_cstring(host_to_connect); 2177*0Sstevel@tonic-gate packet_put_int(port_to_connect); 2178*0Sstevel@tonic-gate packet_send(); 2179*0Sstevel@tonic-gate packet_write_wait(); 2180*0Sstevel@tonic-gate 2181*0Sstevel@tonic-gate /* Wait for response from the remote side. */ 2182*0Sstevel@tonic-gate type = packet_read(); 2183*0Sstevel@tonic-gate switch (type) { 2184*0Sstevel@tonic-gate case SSH_SMSG_SUCCESS: 2185*0Sstevel@tonic-gate success = 1; 2186*0Sstevel@tonic-gate break; 2187*0Sstevel@tonic-gate case SSH_SMSG_FAILURE: 2188*0Sstevel@tonic-gate log("Warning: Server denied remote port forwarding."); 2189*0Sstevel@tonic-gate break; 2190*0Sstevel@tonic-gate default: 2191*0Sstevel@tonic-gate /* Unknown packet */ 2192*0Sstevel@tonic-gate packet_disconnect("Protocol error for port forward request:" 2193*0Sstevel@tonic-gate "received packet type %d.", type); 2194*0Sstevel@tonic-gate } 2195*0Sstevel@tonic-gate } 2196*0Sstevel@tonic-gate if (success) { 2197*0Sstevel@tonic-gate permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); 2198*0Sstevel@tonic-gate permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; 2199*0Sstevel@tonic-gate permitted_opens[num_permitted_opens].listen_port = listen_port; 2200*0Sstevel@tonic-gate num_permitted_opens++; 2201*0Sstevel@tonic-gate } 2202*0Sstevel@tonic-gate } 2203*0Sstevel@tonic-gate 2204*0Sstevel@tonic-gate /* 2205*0Sstevel@tonic-gate * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates 2206*0Sstevel@tonic-gate * listening for the port, and sends back a success reply (or disconnect 2207*0Sstevel@tonic-gate * message if there was an error). This never returns if there was an error. 2208*0Sstevel@tonic-gate */ 2209*0Sstevel@tonic-gate 2210*0Sstevel@tonic-gate void 2211*0Sstevel@tonic-gate channel_input_port_forward_request(int is_root, int gateway_ports) 2212*0Sstevel@tonic-gate { 2213*0Sstevel@tonic-gate u_short port, host_port; 2214*0Sstevel@tonic-gate char *hostname; 2215*0Sstevel@tonic-gate 2216*0Sstevel@tonic-gate /* Get arguments from the packet. */ 2217*0Sstevel@tonic-gate port = packet_get_int(); 2218*0Sstevel@tonic-gate hostname = packet_get_string(NULL); 2219*0Sstevel@tonic-gate host_port = packet_get_int(); 2220*0Sstevel@tonic-gate 2221*0Sstevel@tonic-gate #ifndef HAVE_CYGWIN 2222*0Sstevel@tonic-gate /* 2223*0Sstevel@tonic-gate * Check that an unprivileged user is not trying to forward a 2224*0Sstevel@tonic-gate * privileged port. 2225*0Sstevel@tonic-gate */ 2226*0Sstevel@tonic-gate if (port < IPPORT_RESERVED && !is_root) 2227*0Sstevel@tonic-gate packet_disconnect("Requested forwarding of port %d but user is not root.", 2228*0Sstevel@tonic-gate port); 2229*0Sstevel@tonic-gate #endif 2230*0Sstevel@tonic-gate /* Initiate forwarding */ 2231*0Sstevel@tonic-gate channel_setup_local_fwd_listener(port, hostname, host_port, gateway_ports); 2232*0Sstevel@tonic-gate 2233*0Sstevel@tonic-gate /* Free the argument string. */ 2234*0Sstevel@tonic-gate xfree(hostname); 2235*0Sstevel@tonic-gate } 2236*0Sstevel@tonic-gate 2237*0Sstevel@tonic-gate /* 2238*0Sstevel@tonic-gate * Permits opening to any host/port if permitted_opens[] is empty. This is 2239*0Sstevel@tonic-gate * usually called by the server, because the user could connect to any port 2240*0Sstevel@tonic-gate * anyway, and the server has no way to know but to trust the client anyway. 2241*0Sstevel@tonic-gate */ 2242*0Sstevel@tonic-gate void 2243*0Sstevel@tonic-gate channel_permit_all_opens(void) 2244*0Sstevel@tonic-gate { 2245*0Sstevel@tonic-gate if (num_permitted_opens == 0) 2246*0Sstevel@tonic-gate all_opens_permitted = 1; 2247*0Sstevel@tonic-gate } 2248*0Sstevel@tonic-gate 2249*0Sstevel@tonic-gate void 2250*0Sstevel@tonic-gate channel_add_permitted_opens(char *host, int port) 2251*0Sstevel@tonic-gate { 2252*0Sstevel@tonic-gate if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) 2253*0Sstevel@tonic-gate fatal("channel_request_remote_forwarding: too many forwards"); 2254*0Sstevel@tonic-gate debug("allow port forwarding to host %s port %d", host, port); 2255*0Sstevel@tonic-gate 2256*0Sstevel@tonic-gate permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); 2257*0Sstevel@tonic-gate permitted_opens[num_permitted_opens].port_to_connect = port; 2258*0Sstevel@tonic-gate num_permitted_opens++; 2259*0Sstevel@tonic-gate 2260*0Sstevel@tonic-gate all_opens_permitted = 0; 2261*0Sstevel@tonic-gate } 2262*0Sstevel@tonic-gate 2263*0Sstevel@tonic-gate void 2264*0Sstevel@tonic-gate channel_clear_permitted_opens(void) 2265*0Sstevel@tonic-gate { 2266*0Sstevel@tonic-gate int i; 2267*0Sstevel@tonic-gate 2268*0Sstevel@tonic-gate for (i = 0; i < num_permitted_opens; i++) 2269*0Sstevel@tonic-gate xfree(permitted_opens[i].host_to_connect); 2270*0Sstevel@tonic-gate num_permitted_opens = 0; 2271*0Sstevel@tonic-gate 2272*0Sstevel@tonic-gate } 2273*0Sstevel@tonic-gate 2274*0Sstevel@tonic-gate 2275*0Sstevel@tonic-gate /* return socket to remote host, port */ 2276*0Sstevel@tonic-gate static int 2277*0Sstevel@tonic-gate connect_to(const char *host, u_short port) 2278*0Sstevel@tonic-gate { 2279*0Sstevel@tonic-gate struct addrinfo hints, *ai, *aitop; 2280*0Sstevel@tonic-gate char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 2281*0Sstevel@tonic-gate int gaierr; 2282*0Sstevel@tonic-gate int sock = -1; 2283*0Sstevel@tonic-gate 2284*0Sstevel@tonic-gate memset(&hints, 0, sizeof(hints)); 2285*0Sstevel@tonic-gate hints.ai_family = IPv4or6; 2286*0Sstevel@tonic-gate hints.ai_socktype = SOCK_STREAM; 2287*0Sstevel@tonic-gate snprintf(strport, sizeof strport, "%d", port); 2288*0Sstevel@tonic-gate if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { 2289*0Sstevel@tonic-gate error("connect_to %.100s: unknown host (%s)", host, 2290*0Sstevel@tonic-gate gai_strerror(gaierr)); 2291*0Sstevel@tonic-gate return -1; 2292*0Sstevel@tonic-gate } 2293*0Sstevel@tonic-gate for (ai = aitop; ai; ai = ai->ai_next) { 2294*0Sstevel@tonic-gate if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 2295*0Sstevel@tonic-gate continue; 2296*0Sstevel@tonic-gate if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), 2297*0Sstevel@tonic-gate strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 2298*0Sstevel@tonic-gate error("connect_to: getnameinfo failed"); 2299*0Sstevel@tonic-gate continue; 2300*0Sstevel@tonic-gate } 2301*0Sstevel@tonic-gate sock = socket(ai->ai_family, SOCK_STREAM, 0); 2302*0Sstevel@tonic-gate if (sock < 0) { 2303*0Sstevel@tonic-gate error("socket: %.100s", strerror(errno)); 2304*0Sstevel@tonic-gate continue; 2305*0Sstevel@tonic-gate } 2306*0Sstevel@tonic-gate if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) 2307*0Sstevel@tonic-gate fatal("connect_to: F_SETFL: %s", strerror(errno)); 2308*0Sstevel@tonic-gate if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && 2309*0Sstevel@tonic-gate errno != EINPROGRESS) { 2310*0Sstevel@tonic-gate error("connect_to %.100s port %s: %.100s", ntop, strport, 2311*0Sstevel@tonic-gate strerror(errno)); 2312*0Sstevel@tonic-gate close(sock); 2313*0Sstevel@tonic-gate continue; /* fail -- try next */ 2314*0Sstevel@tonic-gate } 2315*0Sstevel@tonic-gate break; /* success */ 2316*0Sstevel@tonic-gate 2317*0Sstevel@tonic-gate } 2318*0Sstevel@tonic-gate freeaddrinfo(aitop); 2319*0Sstevel@tonic-gate if (!ai) { 2320*0Sstevel@tonic-gate error("connect_to %.100s port %d: failed.", host, port); 2321*0Sstevel@tonic-gate return -1; 2322*0Sstevel@tonic-gate } 2323*0Sstevel@tonic-gate /* success */ 2324*0Sstevel@tonic-gate set_nodelay(sock); 2325*0Sstevel@tonic-gate return sock; 2326*0Sstevel@tonic-gate } 2327*0Sstevel@tonic-gate 2328*0Sstevel@tonic-gate int 2329*0Sstevel@tonic-gate channel_connect_by_listen_address(u_short listen_port) 2330*0Sstevel@tonic-gate { 2331*0Sstevel@tonic-gate int i; 2332*0Sstevel@tonic-gate 2333*0Sstevel@tonic-gate for (i = 0; i < num_permitted_opens; i++) 2334*0Sstevel@tonic-gate if (permitted_opens[i].listen_port == listen_port) 2335*0Sstevel@tonic-gate return connect_to( 2336*0Sstevel@tonic-gate permitted_opens[i].host_to_connect, 2337*0Sstevel@tonic-gate permitted_opens[i].port_to_connect); 2338*0Sstevel@tonic-gate error("WARNING: Server requests forwarding for unknown listen_port %d", 2339*0Sstevel@tonic-gate listen_port); 2340*0Sstevel@tonic-gate return -1; 2341*0Sstevel@tonic-gate } 2342*0Sstevel@tonic-gate 2343*0Sstevel@tonic-gate /* Check if connecting to that port is permitted and connect. */ 2344*0Sstevel@tonic-gate int 2345*0Sstevel@tonic-gate channel_connect_to(const char *host, u_short port) 2346*0Sstevel@tonic-gate { 2347*0Sstevel@tonic-gate int i, permit; 2348*0Sstevel@tonic-gate 2349*0Sstevel@tonic-gate permit = all_opens_permitted; 2350*0Sstevel@tonic-gate if (!permit) { 2351*0Sstevel@tonic-gate for (i = 0; i < num_permitted_opens; i++) 2352*0Sstevel@tonic-gate if (permitted_opens[i].port_to_connect == port && 2353*0Sstevel@tonic-gate strcmp(permitted_opens[i].host_to_connect, host) == 0) 2354*0Sstevel@tonic-gate permit = 1; 2355*0Sstevel@tonic-gate 2356*0Sstevel@tonic-gate } 2357*0Sstevel@tonic-gate if (!permit) { 2358*0Sstevel@tonic-gate log("Received request to connect to host %.100s port %d, " 2359*0Sstevel@tonic-gate "but the request was denied.", host, port); 2360*0Sstevel@tonic-gate return -1; 2361*0Sstevel@tonic-gate } 2362*0Sstevel@tonic-gate return connect_to(host, port); 2363*0Sstevel@tonic-gate } 2364*0Sstevel@tonic-gate 2365*0Sstevel@tonic-gate /* -- X11 forwarding */ 2366*0Sstevel@tonic-gate 2367*0Sstevel@tonic-gate /* 2368*0Sstevel@tonic-gate * Creates an internet domain socket for listening for X11 connections. 2369*0Sstevel@tonic-gate * Returns 0 and a suitable display number for the DISPLAY variable 2370*0Sstevel@tonic-gate * stored in display_numberp , or -1 if an error occurs. 2371*0Sstevel@tonic-gate */ 2372*0Sstevel@tonic-gate int 2373*0Sstevel@tonic-gate x11_create_display_inet(int x11_display_offset, int x11_use_localhost, 2374*0Sstevel@tonic-gate int single_connection, u_int *display_numberp) 2375*0Sstevel@tonic-gate { 2376*0Sstevel@tonic-gate Channel *nc = NULL; 2377*0Sstevel@tonic-gate int display_number, sock; 2378*0Sstevel@tonic-gate u_short port; 2379*0Sstevel@tonic-gate struct addrinfo hints, *ai, *aitop; 2380*0Sstevel@tonic-gate char strport[NI_MAXSERV]; 2381*0Sstevel@tonic-gate int gaierr, n, num_socks = 0, socks[NUM_SOCKS]; 2382*0Sstevel@tonic-gate 2383*0Sstevel@tonic-gate for (display_number = x11_display_offset; 2384*0Sstevel@tonic-gate display_number < MAX_DISPLAYS; 2385*0Sstevel@tonic-gate display_number++) { 2386*0Sstevel@tonic-gate port = 6000 + display_number; 2387*0Sstevel@tonic-gate memset(&hints, 0, sizeof(hints)); 2388*0Sstevel@tonic-gate hints.ai_family = IPv4or6; 2389*0Sstevel@tonic-gate hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE; 2390*0Sstevel@tonic-gate hints.ai_socktype = SOCK_STREAM; 2391*0Sstevel@tonic-gate snprintf(strport, sizeof strport, "%d", port); 2392*0Sstevel@tonic-gate if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) { 2393*0Sstevel@tonic-gate error("getaddrinfo: %.100s", gai_strerror(gaierr)); 2394*0Sstevel@tonic-gate return -1; 2395*0Sstevel@tonic-gate } 2396*0Sstevel@tonic-gate for (ai = aitop; ai; ai = ai->ai_next) { 2397*0Sstevel@tonic-gate if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 2398*0Sstevel@tonic-gate continue; 2399*0Sstevel@tonic-gate sock = socket(ai->ai_family, SOCK_STREAM, 0); 2400*0Sstevel@tonic-gate if (sock < 0) { 2401*0Sstevel@tonic-gate if ((errno != EINVAL) && (errno != EAFNOSUPPORT)) { 2402*0Sstevel@tonic-gate error("socket: %.100s", strerror(errno)); 2403*0Sstevel@tonic-gate return -1; 2404*0Sstevel@tonic-gate } else { 2405*0Sstevel@tonic-gate debug("x11_create_display_inet: Socket family %d not supported", 2406*0Sstevel@tonic-gate ai->ai_family); 2407*0Sstevel@tonic-gate continue; 2408*0Sstevel@tonic-gate } 2409*0Sstevel@tonic-gate } 2410*0Sstevel@tonic-gate #ifdef IPV6_V6ONLY 2411*0Sstevel@tonic-gate if (ai->ai_family == AF_INET6) { 2412*0Sstevel@tonic-gate int on = 1; 2413*0Sstevel@tonic-gate if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) 2414*0Sstevel@tonic-gate error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno)); 2415*0Sstevel@tonic-gate } 2416*0Sstevel@tonic-gate #endif 2417*0Sstevel@tonic-gate if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 2418*0Sstevel@tonic-gate debug("bind port %d: %.100s", port, strerror(errno)); 2419*0Sstevel@tonic-gate close(sock); 2420*0Sstevel@tonic-gate 2421*0Sstevel@tonic-gate if (ai->ai_next) 2422*0Sstevel@tonic-gate continue; 2423*0Sstevel@tonic-gate 2424*0Sstevel@tonic-gate for (n = 0; n < num_socks; n++) { 2425*0Sstevel@tonic-gate close(socks[n]); 2426*0Sstevel@tonic-gate } 2427*0Sstevel@tonic-gate num_socks = 0; 2428*0Sstevel@tonic-gate break; 2429*0Sstevel@tonic-gate } 2430*0Sstevel@tonic-gate socks[num_socks++] = sock; 2431*0Sstevel@tonic-gate #ifndef DONT_TRY_OTHER_AF 2432*0Sstevel@tonic-gate if (num_socks == NUM_SOCKS) 2433*0Sstevel@tonic-gate break; 2434*0Sstevel@tonic-gate #else 2435*0Sstevel@tonic-gate if (x11_use_localhost) { 2436*0Sstevel@tonic-gate if (num_socks == NUM_SOCKS) 2437*0Sstevel@tonic-gate break; 2438*0Sstevel@tonic-gate } else { 2439*0Sstevel@tonic-gate break; 2440*0Sstevel@tonic-gate } 2441*0Sstevel@tonic-gate #endif 2442*0Sstevel@tonic-gate } 2443*0Sstevel@tonic-gate freeaddrinfo(aitop); 2444*0Sstevel@tonic-gate if (num_socks > 0) 2445*0Sstevel@tonic-gate break; 2446*0Sstevel@tonic-gate } 2447*0Sstevel@tonic-gate if (display_number >= MAX_DISPLAYS) { 2448*0Sstevel@tonic-gate error("Failed to allocate internet-domain X11 display socket."); 2449*0Sstevel@tonic-gate return -1; 2450*0Sstevel@tonic-gate } 2451*0Sstevel@tonic-gate /* Start listening for connections on the socket. */ 2452*0Sstevel@tonic-gate for (n = 0; n < num_socks; n++) { 2453*0Sstevel@tonic-gate sock = socks[n]; 2454*0Sstevel@tonic-gate if (listen(sock, 5) < 0) { 2455*0Sstevel@tonic-gate error("listen: %.100s", strerror(errno)); 2456*0Sstevel@tonic-gate close(sock); 2457*0Sstevel@tonic-gate return -1; 2458*0Sstevel@tonic-gate } 2459*0Sstevel@tonic-gate } 2460*0Sstevel@tonic-gate 2461*0Sstevel@tonic-gate /* Allocate a channel for each socket. */ 2462*0Sstevel@tonic-gate for (n = 0; n < num_socks; n++) { 2463*0Sstevel@tonic-gate sock = socks[n]; 2464*0Sstevel@tonic-gate nc = channel_new("x11 listener", 2465*0Sstevel@tonic-gate SSH_CHANNEL_X11_LISTENER, sock, sock, -1, 2466*0Sstevel@tonic-gate CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 2467*0Sstevel@tonic-gate 0, xstrdup("X11 inet listener"), 1); 2468*0Sstevel@tonic-gate nc->single_connection = single_connection; 2469*0Sstevel@tonic-gate } 2470*0Sstevel@tonic-gate 2471*0Sstevel@tonic-gate /* Return the display number for the DISPLAY environment variable. */ 2472*0Sstevel@tonic-gate *display_numberp = display_number; 2473*0Sstevel@tonic-gate return (0); 2474*0Sstevel@tonic-gate } 2475*0Sstevel@tonic-gate 2476*0Sstevel@tonic-gate static int 2477*0Sstevel@tonic-gate connect_local_xsocket(u_int dnr) 2478*0Sstevel@tonic-gate { 2479*0Sstevel@tonic-gate int sock; 2480*0Sstevel@tonic-gate struct sockaddr_un addr; 2481*0Sstevel@tonic-gate 2482*0Sstevel@tonic-gate sock = socket(AF_UNIX, SOCK_STREAM, 0); 2483*0Sstevel@tonic-gate if (sock < 0) 2484*0Sstevel@tonic-gate error("socket: %.100s", strerror(errno)); 2485*0Sstevel@tonic-gate memset(&addr, 0, sizeof(addr)); 2486*0Sstevel@tonic-gate addr.sun_family = AF_UNIX; 2487*0Sstevel@tonic-gate snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, dnr); 2488*0Sstevel@tonic-gate if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0) 2489*0Sstevel@tonic-gate return sock; 2490*0Sstevel@tonic-gate close(sock); 2491*0Sstevel@tonic-gate error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); 2492*0Sstevel@tonic-gate return -1; 2493*0Sstevel@tonic-gate } 2494*0Sstevel@tonic-gate 2495*0Sstevel@tonic-gate int 2496*0Sstevel@tonic-gate x11_connect_display(void) 2497*0Sstevel@tonic-gate { 2498*0Sstevel@tonic-gate int display_number, sock = 0; 2499*0Sstevel@tonic-gate const char *display; 2500*0Sstevel@tonic-gate char buf[1024], *cp; 2501*0Sstevel@tonic-gate struct addrinfo hints, *ai, *aitop; 2502*0Sstevel@tonic-gate char strport[NI_MAXSERV]; 2503*0Sstevel@tonic-gate int gaierr; 2504*0Sstevel@tonic-gate 2505*0Sstevel@tonic-gate /* Try to open a socket for the local X server. */ 2506*0Sstevel@tonic-gate display = getenv("DISPLAY"); 2507*0Sstevel@tonic-gate if (!display) { 2508*0Sstevel@tonic-gate error("DISPLAY not set."); 2509*0Sstevel@tonic-gate return -1; 2510*0Sstevel@tonic-gate } 2511*0Sstevel@tonic-gate /* 2512*0Sstevel@tonic-gate * Now we decode the value of the DISPLAY variable and make a 2513*0Sstevel@tonic-gate * connection to the real X server. 2514*0Sstevel@tonic-gate */ 2515*0Sstevel@tonic-gate 2516*0Sstevel@tonic-gate /* 2517*0Sstevel@tonic-gate * Check if it is a unix domain socket. Unix domain displays are in 2518*0Sstevel@tonic-gate * one of the following formats: unix:d[.s], :d[.s], ::d[.s] 2519*0Sstevel@tonic-gate */ 2520*0Sstevel@tonic-gate if (strncmp(display, "unix:", 5) == 0 || 2521*0Sstevel@tonic-gate display[0] == ':') { 2522*0Sstevel@tonic-gate /* Connect to the unix domain socket. */ 2523*0Sstevel@tonic-gate if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) { 2524*0Sstevel@tonic-gate error("Could not parse display number from DISPLAY: %.100s", 2525*0Sstevel@tonic-gate display); 2526*0Sstevel@tonic-gate return -1; 2527*0Sstevel@tonic-gate } 2528*0Sstevel@tonic-gate /* Create a socket. */ 2529*0Sstevel@tonic-gate sock = connect_local_xsocket(display_number); 2530*0Sstevel@tonic-gate if (sock < 0) 2531*0Sstevel@tonic-gate return -1; 2532*0Sstevel@tonic-gate 2533*0Sstevel@tonic-gate /* OK, we now have a connection to the display. */ 2534*0Sstevel@tonic-gate return sock; 2535*0Sstevel@tonic-gate } 2536*0Sstevel@tonic-gate /* 2537*0Sstevel@tonic-gate * Connect to an inet socket. The DISPLAY value is supposedly 2538*0Sstevel@tonic-gate * hostname:d[.s], where hostname may also be numeric IP address. 2539*0Sstevel@tonic-gate */ 2540*0Sstevel@tonic-gate strlcpy(buf, display, sizeof(buf)); 2541*0Sstevel@tonic-gate cp = strchr(buf, ':'); 2542*0Sstevel@tonic-gate if (!cp) { 2543*0Sstevel@tonic-gate error("Could not find ':' in DISPLAY: %.100s", display); 2544*0Sstevel@tonic-gate return -1; 2545*0Sstevel@tonic-gate } 2546*0Sstevel@tonic-gate *cp = 0; 2547*0Sstevel@tonic-gate /* buf now contains the host name. But first we parse the display number. */ 2548*0Sstevel@tonic-gate if (sscanf(cp + 1, "%d", &display_number) != 1) { 2549*0Sstevel@tonic-gate error("Could not parse display number from DISPLAY: %.100s", 2550*0Sstevel@tonic-gate display); 2551*0Sstevel@tonic-gate return -1; 2552*0Sstevel@tonic-gate } 2553*0Sstevel@tonic-gate 2554*0Sstevel@tonic-gate /* Look up the host address */ 2555*0Sstevel@tonic-gate memset(&hints, 0, sizeof(hints)); 2556*0Sstevel@tonic-gate hints.ai_family = IPv4or6; 2557*0Sstevel@tonic-gate hints.ai_socktype = SOCK_STREAM; 2558*0Sstevel@tonic-gate snprintf(strport, sizeof strport, "%d", 6000 + display_number); 2559*0Sstevel@tonic-gate if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { 2560*0Sstevel@tonic-gate error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr)); 2561*0Sstevel@tonic-gate return -1; 2562*0Sstevel@tonic-gate } 2563*0Sstevel@tonic-gate for (ai = aitop; ai; ai = ai->ai_next) { 2564*0Sstevel@tonic-gate /* Create a socket. */ 2565*0Sstevel@tonic-gate sock = socket(ai->ai_family, SOCK_STREAM, 0); 2566*0Sstevel@tonic-gate if (sock < 0) { 2567*0Sstevel@tonic-gate debug("socket: %.100s", strerror(errno)); 2568*0Sstevel@tonic-gate continue; 2569*0Sstevel@tonic-gate } 2570*0Sstevel@tonic-gate /* Connect it to the display. */ 2571*0Sstevel@tonic-gate if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 2572*0Sstevel@tonic-gate debug("connect %.100s port %d: %.100s", buf, 2573*0Sstevel@tonic-gate 6000 + display_number, strerror(errno)); 2574*0Sstevel@tonic-gate close(sock); 2575*0Sstevel@tonic-gate continue; 2576*0Sstevel@tonic-gate } 2577*0Sstevel@tonic-gate /* Success */ 2578*0Sstevel@tonic-gate break; 2579*0Sstevel@tonic-gate } 2580*0Sstevel@tonic-gate freeaddrinfo(aitop); 2581*0Sstevel@tonic-gate if (!ai) { 2582*0Sstevel@tonic-gate error("connect %.100s port %d: %.100s", buf, 6000 + display_number, 2583*0Sstevel@tonic-gate strerror(errno)); 2584*0Sstevel@tonic-gate return -1; 2585*0Sstevel@tonic-gate } 2586*0Sstevel@tonic-gate set_nodelay(sock); 2587*0Sstevel@tonic-gate return sock; 2588*0Sstevel@tonic-gate } 2589*0Sstevel@tonic-gate 2590*0Sstevel@tonic-gate /* 2591*0Sstevel@tonic-gate * This is called when SSH_SMSG_X11_OPEN is received. The packet contains 2592*0Sstevel@tonic-gate * the remote channel number. We should do whatever we want, and respond 2593*0Sstevel@tonic-gate * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. 2594*0Sstevel@tonic-gate */ 2595*0Sstevel@tonic-gate 2596*0Sstevel@tonic-gate void 2597*0Sstevel@tonic-gate x11_input_open(int type, u_int32_t seq, void *ctxt) 2598*0Sstevel@tonic-gate { 2599*0Sstevel@tonic-gate Channel *c = NULL; 2600*0Sstevel@tonic-gate int remote_id, sock = 0; 2601*0Sstevel@tonic-gate char *remote_host; 2602*0Sstevel@tonic-gate 2603*0Sstevel@tonic-gate debug("Received X11 open request."); 2604*0Sstevel@tonic-gate 2605*0Sstevel@tonic-gate remote_id = packet_get_int(); 2606*0Sstevel@tonic-gate 2607*0Sstevel@tonic-gate if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) { 2608*0Sstevel@tonic-gate remote_host = packet_get_string(NULL); 2609*0Sstevel@tonic-gate } else { 2610*0Sstevel@tonic-gate remote_host = xstrdup("unknown (remote did not supply name)"); 2611*0Sstevel@tonic-gate } 2612*0Sstevel@tonic-gate packet_check_eom(); 2613*0Sstevel@tonic-gate 2614*0Sstevel@tonic-gate /* Obtain a connection to the real X display. */ 2615*0Sstevel@tonic-gate sock = x11_connect_display(); 2616*0Sstevel@tonic-gate if (sock != -1) { 2617*0Sstevel@tonic-gate /* Allocate a channel for this connection. */ 2618*0Sstevel@tonic-gate c = channel_new("connected x11 socket", 2619*0Sstevel@tonic-gate SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0, 2620*0Sstevel@tonic-gate remote_host, 1); 2621*0Sstevel@tonic-gate c->remote_id = remote_id; 2622*0Sstevel@tonic-gate c->force_drain = 1; 2623*0Sstevel@tonic-gate } 2624*0Sstevel@tonic-gate if (c == NULL) { 2625*0Sstevel@tonic-gate /* Send refusal to the remote host. */ 2626*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 2627*0Sstevel@tonic-gate packet_put_int(remote_id); 2628*0Sstevel@tonic-gate } else { 2629*0Sstevel@tonic-gate /* Send a confirmation to the remote host. */ 2630*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 2631*0Sstevel@tonic-gate packet_put_int(remote_id); 2632*0Sstevel@tonic-gate packet_put_int(c->self); 2633*0Sstevel@tonic-gate } 2634*0Sstevel@tonic-gate packet_send(); 2635*0Sstevel@tonic-gate } 2636*0Sstevel@tonic-gate 2637*0Sstevel@tonic-gate /* dummy protocol handler that denies SSH-1 requests (agent/x11) */ 2638*0Sstevel@tonic-gate void 2639*0Sstevel@tonic-gate deny_input_open(int type, u_int32_t seq, void *ctxt) 2640*0Sstevel@tonic-gate { 2641*0Sstevel@tonic-gate int rchan = packet_get_int(); 2642*0Sstevel@tonic-gate 2643*0Sstevel@tonic-gate switch (type) { 2644*0Sstevel@tonic-gate case SSH_SMSG_AGENT_OPEN: 2645*0Sstevel@tonic-gate error("Warning: ssh server tried agent forwarding."); 2646*0Sstevel@tonic-gate break; 2647*0Sstevel@tonic-gate case SSH_SMSG_X11_OPEN: 2648*0Sstevel@tonic-gate error("Warning: ssh server tried X11 forwarding."); 2649*0Sstevel@tonic-gate break; 2650*0Sstevel@tonic-gate default: 2651*0Sstevel@tonic-gate error("deny_input_open: type %d", type); 2652*0Sstevel@tonic-gate break; 2653*0Sstevel@tonic-gate } 2654*0Sstevel@tonic-gate error("Warning: this is probably a break in attempt by a malicious server."); 2655*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 2656*0Sstevel@tonic-gate packet_put_int(rchan); 2657*0Sstevel@tonic-gate packet_send(); 2658*0Sstevel@tonic-gate } 2659*0Sstevel@tonic-gate 2660*0Sstevel@tonic-gate /* 2661*0Sstevel@tonic-gate * Requests forwarding of X11 connections, generates fake authentication 2662*0Sstevel@tonic-gate * data, and enables authentication spoofing. 2663*0Sstevel@tonic-gate * This should be called in the client only. 2664*0Sstevel@tonic-gate */ 2665*0Sstevel@tonic-gate void 2666*0Sstevel@tonic-gate x11_request_forwarding_with_spoofing(int client_session_id, 2667*0Sstevel@tonic-gate const char *proto, const char *data) 2668*0Sstevel@tonic-gate { 2669*0Sstevel@tonic-gate u_int data_len = (u_int) strlen(data) / 2; 2670*0Sstevel@tonic-gate u_int i, value, len; 2671*0Sstevel@tonic-gate char *new_data; 2672*0Sstevel@tonic-gate int screen_number; 2673*0Sstevel@tonic-gate const char *cp; 2674*0Sstevel@tonic-gate u_int32_t rand = 0; 2675*0Sstevel@tonic-gate 2676*0Sstevel@tonic-gate cp = getenv("DISPLAY"); 2677*0Sstevel@tonic-gate if (cp) 2678*0Sstevel@tonic-gate cp = strchr(cp, ':'); 2679*0Sstevel@tonic-gate if (cp) 2680*0Sstevel@tonic-gate cp = strchr(cp, '.'); 2681*0Sstevel@tonic-gate if (cp) 2682*0Sstevel@tonic-gate screen_number = atoi(cp + 1); 2683*0Sstevel@tonic-gate else 2684*0Sstevel@tonic-gate screen_number = 0; 2685*0Sstevel@tonic-gate 2686*0Sstevel@tonic-gate /* Save protocol name. */ 2687*0Sstevel@tonic-gate x11_saved_proto = xstrdup(proto); 2688*0Sstevel@tonic-gate 2689*0Sstevel@tonic-gate /* 2690*0Sstevel@tonic-gate * Extract real authentication data and generate fake data of the 2691*0Sstevel@tonic-gate * same length. 2692*0Sstevel@tonic-gate */ 2693*0Sstevel@tonic-gate x11_saved_data = xmalloc(data_len); 2694*0Sstevel@tonic-gate x11_fake_data = xmalloc(data_len); 2695*0Sstevel@tonic-gate for (i = 0; i < data_len; i++) { 2696*0Sstevel@tonic-gate if (sscanf(data + 2 * i, "%2x", &value) != 1) 2697*0Sstevel@tonic-gate fatal("x11_request_forwarding: bad authentication data: %.100s", data); 2698*0Sstevel@tonic-gate if (i % 4 == 0) 2699*0Sstevel@tonic-gate rand = arc4random(); 2700*0Sstevel@tonic-gate x11_saved_data[i] = value; 2701*0Sstevel@tonic-gate x11_fake_data[i] = rand & 0xff; 2702*0Sstevel@tonic-gate rand >>= 8; 2703*0Sstevel@tonic-gate } 2704*0Sstevel@tonic-gate x11_saved_data_len = data_len; 2705*0Sstevel@tonic-gate x11_fake_data_len = data_len; 2706*0Sstevel@tonic-gate 2707*0Sstevel@tonic-gate /* Convert the fake data into hex. */ 2708*0Sstevel@tonic-gate len = 2 * data_len + 1; 2709*0Sstevel@tonic-gate new_data = xmalloc(len); 2710*0Sstevel@tonic-gate for (i = 0; i < data_len; i++) 2711*0Sstevel@tonic-gate snprintf(new_data + 2 * i, len - 2 * i, 2712*0Sstevel@tonic-gate "%02x", (u_char) x11_fake_data[i]); 2713*0Sstevel@tonic-gate 2714*0Sstevel@tonic-gate /* Send the request packet. */ 2715*0Sstevel@tonic-gate if (compat20) { 2716*0Sstevel@tonic-gate channel_request_start(client_session_id, "x11-req", 0); 2717*0Sstevel@tonic-gate packet_put_char(0); /* XXX bool single connection */ 2718*0Sstevel@tonic-gate } else { 2719*0Sstevel@tonic-gate packet_start(SSH_CMSG_X11_REQUEST_FORWARDING); 2720*0Sstevel@tonic-gate } 2721*0Sstevel@tonic-gate packet_put_cstring(proto); 2722*0Sstevel@tonic-gate packet_put_cstring(new_data); 2723*0Sstevel@tonic-gate packet_put_int(screen_number); 2724*0Sstevel@tonic-gate packet_send(); 2725*0Sstevel@tonic-gate packet_write_wait(); 2726*0Sstevel@tonic-gate xfree(new_data); 2727*0Sstevel@tonic-gate } 2728*0Sstevel@tonic-gate 2729*0Sstevel@tonic-gate 2730*0Sstevel@tonic-gate /* -- agent forwarding */ 2731*0Sstevel@tonic-gate 2732*0Sstevel@tonic-gate /* Sends a message to the server to request authentication fd forwarding. */ 2733*0Sstevel@tonic-gate 2734*0Sstevel@tonic-gate void 2735*0Sstevel@tonic-gate auth_request_forwarding(void) 2736*0Sstevel@tonic-gate { 2737*0Sstevel@tonic-gate packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); 2738*0Sstevel@tonic-gate packet_send(); 2739*0Sstevel@tonic-gate packet_write_wait(); 2740*0Sstevel@tonic-gate } 2741*0Sstevel@tonic-gate 2742*0Sstevel@tonic-gate /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ 2743*0Sstevel@tonic-gate 2744*0Sstevel@tonic-gate void 2745*0Sstevel@tonic-gate auth_input_open_request(int type, u_int32_t seq, void *ctxt) 2746*0Sstevel@tonic-gate { 2747*0Sstevel@tonic-gate Channel *c = NULL; 2748*0Sstevel@tonic-gate int remote_id, sock; 2749*0Sstevel@tonic-gate char *name; 2750*0Sstevel@tonic-gate 2751*0Sstevel@tonic-gate /* Read the remote channel number from the message. */ 2752*0Sstevel@tonic-gate remote_id = packet_get_int(); 2753*0Sstevel@tonic-gate packet_check_eom(); 2754*0Sstevel@tonic-gate 2755*0Sstevel@tonic-gate /* 2756*0Sstevel@tonic-gate * Get a connection to the local authentication agent (this may again 2757*0Sstevel@tonic-gate * get forwarded). 2758*0Sstevel@tonic-gate */ 2759*0Sstevel@tonic-gate sock = ssh_get_authentication_socket(); 2760*0Sstevel@tonic-gate 2761*0Sstevel@tonic-gate /* 2762*0Sstevel@tonic-gate * If we could not connect the agent, send an error message back to 2763*0Sstevel@tonic-gate * the server. This should never happen unless the agent dies, 2764*0Sstevel@tonic-gate * because authentication forwarding is only enabled if we have an 2765*0Sstevel@tonic-gate * agent. 2766*0Sstevel@tonic-gate */ 2767*0Sstevel@tonic-gate if (sock >= 0) { 2768*0Sstevel@tonic-gate name = xstrdup("authentication agent connection"); 2769*0Sstevel@tonic-gate c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, 2770*0Sstevel@tonic-gate -1, 0, 0, 0, name, 1); 2771*0Sstevel@tonic-gate c->remote_id = remote_id; 2772*0Sstevel@tonic-gate c->force_drain = 1; 2773*0Sstevel@tonic-gate } 2774*0Sstevel@tonic-gate if (c == NULL) { 2775*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 2776*0Sstevel@tonic-gate packet_put_int(remote_id); 2777*0Sstevel@tonic-gate } else { 2778*0Sstevel@tonic-gate /* Send a confirmation to the remote host. */ 2779*0Sstevel@tonic-gate debug("Forwarding authentication connection."); 2780*0Sstevel@tonic-gate packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 2781*0Sstevel@tonic-gate packet_put_int(remote_id); 2782*0Sstevel@tonic-gate packet_put_int(c->self); 2783*0Sstevel@tonic-gate } 2784*0Sstevel@tonic-gate packet_send(); 2785*0Sstevel@tonic-gate } 2786