channels.c revision 78827
157429Smarkm/* 257429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 357429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 457429Smarkm * All rights reserved 557429Smarkm * This file contains functions for generic socket connection forwarding. 657429Smarkm * There is also code for initiating connection forwarding for X11 connections, 757429Smarkm * arbitrary tcp/ip connections, and the authentication agent connection. 860573Skris * 965668Skris * As far as I am concerned, the code I have written for this software 1065668Skris * can be used freely for any purpose. Any derived versions of this 1165668Skris * software must be clearly marked as such, and if the derived work is 1265668Skris * incompatible with the protocol description in the RFC file, it must be 1365668Skris * called by a name other than "ssh" or "Secure Shell". 1465668Skris * 1565668Skris * 1660573Skris * SSH2 support added by Markus Friedl. 1765668Skris * Copyright (c) 1999,2000 Markus Friedl. All rights reserved. 1865668Skris * Copyright (c) 1999 Dug Song. All rights reserved. 1965668Skris * Copyright (c) 1999 Theo de Raadt. All rights reserved. 2065668Skris * 2165668Skris * Redistribution and use in source and binary forms, with or without 2265668Skris * modification, are permitted provided that the following conditions 2365668Skris * are met: 2465668Skris * 1. Redistributions of source code must retain the above copyright 2565668Skris * notice, this list of conditions and the following disclaimer. 2665668Skris * 2. Redistributions in binary form must reproduce the above copyright 2765668Skris * notice, this list of conditions and the following disclaimer in the 2865668Skris * documentation and/or other materials provided with the distribution. 2965668Skris * 3065668Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 3165668Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 3265668Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 3365668Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3465668Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3565668Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3665668Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3765668Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3865668Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3965668Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4057429Smarkm */ 4157429Smarkm 4257429Smarkm#include "includes.h" 4376262SgreenRCSID("$OpenBSD: channels.c,v 1.109 2001/04/17 12:55:03 markus Exp $"); 4474500SgreenRCSID("$FreeBSD: head/crypto/openssh/channels.c 78827 2001-06-26 15:15:22Z green $"); 4557429Smarkm 4676262Sgreen#include <openssl/rsa.h> 4776262Sgreen#include <openssl/dsa.h> 4876262Sgreen 4957429Smarkm#include "ssh.h" 5076262Sgreen#include "ssh1.h" 5176262Sgreen#include "ssh2.h" 5257429Smarkm#include "packet.h" 5357429Smarkm#include "xmalloc.h" 5457429Smarkm#include "buffer.h" 5576262Sgreen#include "bufaux.h" 5657429Smarkm#include "uidswap.h" 5776262Sgreen#include "log.h" 5876262Sgreen#include "misc.h" 5957429Smarkm#include "channels.h" 6057429Smarkm#include "nchan.h" 6157429Smarkm#include "compat.h" 6276262Sgreen#include "canohost.h" 6365668Skris#include "key.h" 6465668Skris#include "authfd.h" 6565668Skris 6657429Smarkm/* Maximum number of fake X11 displays to try. */ 6757429Smarkm#define MAX_DISPLAYS 1000 6857429Smarkm 6957429Smarkm/* Max len of agent socket */ 7057429Smarkm#define MAX_SOCKET_NAME 100 7157429Smarkm 7257429Smarkm/* 7357429Smarkm * Pointer to an array containing all allocated channels. The array is 7457429Smarkm * dynamically extended as needed. 7557429Smarkm */ 7657429Smarkmstatic Channel *channels = NULL; 7757429Smarkm 7857429Smarkm/* 7957429Smarkm * Size of the channel array. All slots of the array must always be 8057429Smarkm * initialized (at least the type field); unused slots are marked with type 8157429Smarkm * SSH_CHANNEL_FREE. 8257429Smarkm */ 8357429Smarkmstatic int channels_alloc = 0; 8457429Smarkm 8557429Smarkm/* 8657429Smarkm * Maximum file descriptor value used in any of the channels. This is 8757429Smarkm * updated in channel_allocate. 8857429Smarkm */ 8976262Sgreenstatic int channel_max_fd = 0; 9057429Smarkm 9157429Smarkm/* Name and directory of socket for authentication agent forwarding. */ 9257429Smarkmstatic char *channel_forwarded_auth_socket_name = NULL; 9357429Smarkmstatic char *channel_forwarded_auth_socket_dir = NULL; 9457429Smarkm 9557429Smarkm/* Saved X11 authentication protocol name. */ 9657429Smarkmchar *x11_saved_proto = NULL; 9757429Smarkm 9857429Smarkm/* Saved X11 authentication data. This is the real data. */ 9957429Smarkmchar *x11_saved_data = NULL; 10076262Sgreenu_int x11_saved_data_len = 0; 10157429Smarkm 10257429Smarkm/* 10357429Smarkm * Fake X11 authentication data. This is what the server will be sending us; 10457429Smarkm * we should replace any occurrences of this by the real data. 10557429Smarkm */ 10657429Smarkmchar *x11_fake_data = NULL; 10776262Sgreenu_int x11_fake_data_len; 10857429Smarkm 10957429Smarkm/* 11057429Smarkm * Data structure for storing which hosts are permitted for forward requests. 11157429Smarkm * The local sides of any remote forwards are stored in this array to prevent 11257429Smarkm * a corrupt remote server from accessing arbitrary TCP/IP ports on our local 11357429Smarkm * network (which might be behind a firewall). 11457429Smarkm */ 11557429Smarkmtypedef struct { 11660573Skris char *host_to_connect; /* Connect to 'host'. */ 11760573Skris u_short port_to_connect; /* Connect to 'port'. */ 11860573Skris u_short listen_port; /* Remote side should listen port number. */ 11957429Smarkm} ForwardPermission; 12057429Smarkm 12157429Smarkm/* List of all permitted host/port pairs to connect. */ 12257429Smarkmstatic ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; 12357429Smarkm/* Number of permitted host/port pairs in the array. */ 12457429Smarkmstatic int num_permitted_opens = 0; 12557429Smarkm/* 12657429Smarkm * If this is true, all opens are permitted. This is the case on the server 12757429Smarkm * on which we have to trust the client anyway, and the user could do 12857429Smarkm * anything after logging in anyway. 12957429Smarkm */ 13057429Smarkmstatic int all_opens_permitted = 0; 13157429Smarkm 13257429Smarkm/* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */ 13357429Smarkmstatic int have_hostname_in_open = 0; 13457429Smarkm 13576262Sgreen/* AF_UNSPEC or AF_INET or AF_INET6 */ 13676262Sgreenextern int IPv4or6; 13776262Sgreen 13876262Sgreenvoid port_open_helper(Channel *c, char *rtype); 13976262Sgreen 14057429Smarkm/* Sets specific protocol options. */ 14157429Smarkm 14260573Skrisvoid 14357429Smarkmchannel_set_options(int hostname_in_open) 14457429Smarkm{ 14557429Smarkm have_hostname_in_open = hostname_in_open; 14657429Smarkm} 14757429Smarkm 14860573Skris/* lookup channel by id */ 14960573Skris 15060573SkrisChannel * 15160573Skrischannel_lookup(int id) 15260573Skris{ 15360573Skris Channel *c; 15465668Skris if (id < 0 || id > channels_alloc) { 15560573Skris log("channel_lookup: %d: bad id", id); 15660573Skris return NULL; 15760573Skris } 15860573Skris c = &channels[id]; 15960573Skris if (c->type == SSH_CHANNEL_FREE) { 16060573Skris log("channel_lookup: %d: bad id: channel free", id); 16160573Skris return NULL; 16260573Skris } 16360573Skris return c; 16460573Skris} 16560573Skris 16657429Smarkm/* 16760573Skris * Register filedescriptors for a channel, used when allocating a channel or 16860573Skris * when the channel consumer/producer is ready, e.g. shell exec'd 16960573Skris */ 17060573Skris 17160573Skrisvoid 17269587Sgreenchannel_register_fds(Channel *c, int rfd, int wfd, int efd, 17369587Sgreen int extusage, int nonblock) 17460573Skris{ 17560573Skris /* Update the maximum file descriptor value. */ 17676262Sgreen channel_max_fd = MAX(channel_max_fd, rfd); 17776262Sgreen channel_max_fd = MAX(channel_max_fd, wfd); 17876262Sgreen channel_max_fd = MAX(channel_max_fd, efd); 17976262Sgreen 18060573Skris /* XXX set close-on-exec -markus */ 18160573Skris 18260573Skris c->rfd = rfd; 18360573Skris c->wfd = wfd; 18460573Skris c->sock = (rfd == wfd) ? rfd : -1; 18560573Skris c->efd = efd; 18660573Skris c->extended_usage = extusage; 18769587Sgreen 18874500Sgreen /* XXX ugly hack: nonblock is only set by the server */ 18974500Sgreen if (nonblock && isatty(c->rfd)) { 19076262Sgreen debug("channel %d: rfd %d isatty", c->self, c->rfd); 19174500Sgreen c->isatty = 1; 19274500Sgreen if (!isatty(c->wfd)) { 19376262Sgreen error("channel %d: wfd %d is not a tty?", 19474500Sgreen c->self, c->wfd); 19574500Sgreen } 19674500Sgreen } else { 19774500Sgreen c->isatty = 0; 19874500Sgreen } 19974500Sgreen 20069587Sgreen /* enable nonblocking mode */ 20169587Sgreen if (nonblock) { 20269587Sgreen if (rfd != -1) 20369587Sgreen set_nonblock(rfd); 20469587Sgreen if (wfd != -1) 20569587Sgreen set_nonblock(wfd); 20669587Sgreen if (efd != -1) 20769587Sgreen set_nonblock(efd); 20869587Sgreen } 20960573Skris} 21060573Skris 21160573Skris/* 21257429Smarkm * Allocate a new channel object and set its type and socket. This will cause 21357429Smarkm * remote_name to be freed. 21457429Smarkm */ 21557429Smarkm 21660573Skrisint 21760573Skrischannel_new(char *ctype, int type, int rfd, int wfd, int efd, 21869587Sgreen int window, int maxpack, int extusage, char *remote_name, int nonblock) 21957429Smarkm{ 22057429Smarkm int i, found; 22157429Smarkm Channel *c; 22257429Smarkm 22357429Smarkm /* Do initial allocation if this is the first call. */ 22457429Smarkm if (channels_alloc == 0) { 22560573Skris chan_init(); 22657429Smarkm channels_alloc = 10; 22757429Smarkm channels = xmalloc(channels_alloc * sizeof(Channel)); 22857429Smarkm for (i = 0; i < channels_alloc; i++) 22957429Smarkm channels[i].type = SSH_CHANNEL_FREE; 23057429Smarkm /* 23157429Smarkm * Kludge: arrange a call to channel_stop_listening if we 23257429Smarkm * terminate with fatal(). 23357429Smarkm */ 23457429Smarkm fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL); 23557429Smarkm } 23657429Smarkm /* Try to find a free slot where to put the new channel. */ 23757429Smarkm for (found = -1, i = 0; i < channels_alloc; i++) 23857429Smarkm if (channels[i].type == SSH_CHANNEL_FREE) { 23957429Smarkm /* Found a free slot. */ 24057429Smarkm found = i; 24157429Smarkm break; 24257429Smarkm } 24357429Smarkm if (found == -1) { 24457429Smarkm /* There are no free slots. Take last+1 slot and expand the array. */ 24557429Smarkm found = channels_alloc; 24657429Smarkm channels_alloc += 10; 24769587Sgreen debug2("channel: expanding %d", channels_alloc); 24857429Smarkm channels = xrealloc(channels, channels_alloc * sizeof(Channel)); 24957429Smarkm for (i = found; i < channels_alloc; i++) 25057429Smarkm channels[i].type = SSH_CHANNEL_FREE; 25157429Smarkm } 25257429Smarkm /* Initialize and return new channel number. */ 25357429Smarkm c = &channels[found]; 25457429Smarkm buffer_init(&c->input); 25557429Smarkm buffer_init(&c->output); 25660573Skris buffer_init(&c->extended); 25757429Smarkm chan_init_iostates(c); 25869587Sgreen channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); 25957429Smarkm c->self = found; 26057429Smarkm c->type = type; 26160573Skris c->ctype = ctype; 26260573Skris c->local_window = window; 26360573Skris c->local_window_max = window; 26460573Skris c->local_consumed = 0; 26560573Skris c->local_maxpacket = maxpack; 26657429Smarkm c->remote_id = -1; 26757429Smarkm c->remote_name = remote_name; 26860573Skris c->remote_window = 0; 26960573Skris c->remote_maxpacket = 0; 27060573Skris c->cb_fn = NULL; 27160573Skris c->cb_arg = NULL; 27260573Skris c->cb_event = 0; 27360573Skris c->dettach_user = NULL; 27465668Skris c->input_filter = NULL; 27557429Smarkm debug("channel %d: new [%s]", found, remote_name); 27657429Smarkm return found; 27757429Smarkm} 27860573Skris/* old interface XXX */ 27960573Skrisint 28060573Skrischannel_allocate(int type, int sock, char *remote_name) 28160573Skris{ 28269587Sgreen return channel_new("", type, sock, sock, -1, 0, 0, 0, remote_name, 1); 28360573Skris} 28457429Smarkm 28557429Smarkm 28660573Skris/* Close all channel fd/socket. */ 28760573Skris 28860573Skrisvoid 28960573Skrischannel_close_fds(Channel *c) 29057429Smarkm{ 29160573Skris if (c->sock != -1) { 29260573Skris close(c->sock); 29360573Skris c->sock = -1; 29460573Skris } 29560573Skris if (c->rfd != -1) { 29660573Skris close(c->rfd); 29760573Skris c->rfd = -1; 29860573Skris } 29960573Skris if (c->wfd != -1) { 30060573Skris close(c->wfd); 30160573Skris c->wfd = -1; 30260573Skris } 30360573Skris if (c->efd != -1) { 30460573Skris close(c->efd); 30560573Skris c->efd = -1; 30660573Skris } 30760573Skris} 30857429Smarkm 30960573Skris/* Free the channel and close its fd/socket. */ 31060573Skris 31160573Skrisvoid 31260573Skrischannel_free(int id) 31360573Skris{ 31460573Skris Channel *c = channel_lookup(id); 31576262Sgreen char *s = channel_open_message(); 31676262Sgreen 31760573Skris if (c == NULL) 31860573Skris packet_disconnect("channel free: bad local channel %d", id); 31976262Sgreen debug("channel_free: channel %d: status: %s", id, s); 32076262Sgreen xfree(s); 32176262Sgreen 32260573Skris if (c->dettach_user != NULL) { 32360573Skris debug("channel_free: channel %d: dettaching channel user", id); 32460573Skris c->dettach_user(c->self, NULL); 32557429Smarkm } 32660573Skris if (c->sock != -1) 32760573Skris shutdown(c->sock, SHUT_RDWR); 32860573Skris channel_close_fds(c); 32960573Skris buffer_free(&c->input); 33060573Skris buffer_free(&c->output); 33160573Skris buffer_free(&c->extended); 33260573Skris c->type = SSH_CHANNEL_FREE; 33360573Skris if (c->remote_name) { 33460573Skris xfree(c->remote_name); 33560573Skris c->remote_name = NULL; 33660573Skris } 33757429Smarkm} 33857429Smarkm 33957429Smarkm/* 34060573Skris * 'channel_pre*' are called just before select() to add any bits relevant to 34160573Skris * channels in the select bitmasks. 34257429Smarkm */ 34360573Skris/* 34460573Skris * 'channel_post*': perform any appropriate operations for channels which 34560573Skris * have events pending. 34660573Skris */ 34760573Skristypedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset); 34860573Skrischan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE]; 34960573Skrischan_fn *channel_post[SSH_CHANNEL_MAX_TYPE]; 35057429Smarkm 35160573Skrisvoid 35260573Skrischannel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset) 35357429Smarkm{ 35460573Skris FD_SET(c->sock, readset); 35560573Skris} 35660573Skris 35760573Skrisvoid 35876262Sgreenchannel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset) 35976262Sgreen{ 36076262Sgreen debug3("channel %d: waiting for connection", c->self); 36176262Sgreen FD_SET(c->sock, writeset); 36276262Sgreen} 36376262Sgreen 36476262Sgreenvoid 36560573Skrischannel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset) 36660573Skris{ 36760573Skris if (buffer_len(&c->input) < packet_get_maxsize()) 36860573Skris FD_SET(c->sock, readset); 36960573Skris if (buffer_len(&c->output) > 0) 37060573Skris FD_SET(c->sock, writeset); 37160573Skris} 37260573Skris 37360573Skrisvoid 37460573Skrischannel_pre_open_15(Channel *c, fd_set * readset, fd_set * writeset) 37560573Skris{ 37660573Skris /* test whether sockets are 'alive' for read/write */ 37760573Skris if (c->istate == CHAN_INPUT_OPEN) 37860573Skris if (buffer_len(&c->input) < packet_get_maxsize()) 37960573Skris FD_SET(c->sock, readset); 38060573Skris if (c->ostate == CHAN_OUTPUT_OPEN || 38160573Skris c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { 38260573Skris if (buffer_len(&c->output) > 0) { 38360573Skris FD_SET(c->sock, writeset); 38460573Skris } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { 38560573Skris chan_obuf_empty(c); 38660573Skris } 38760573Skris } 38860573Skris} 38960573Skris 39060573Skrisvoid 39160573Skrischannel_pre_open_20(Channel *c, fd_set * readset, fd_set * writeset) 39260573Skris{ 39360573Skris if (c->istate == CHAN_INPUT_OPEN && 39460573Skris c->remote_window > 0 && 39560573Skris buffer_len(&c->input) < c->remote_window) 39660573Skris FD_SET(c->rfd, readset); 39760573Skris if (c->ostate == CHAN_OUTPUT_OPEN || 39860573Skris c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { 39960573Skris if (buffer_len(&c->output) > 0) { 40060573Skris FD_SET(c->wfd, writeset); 40160573Skris } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { 40260573Skris chan_obuf_empty(c); 40360573Skris } 40460573Skris } 40560573Skris /** XXX check close conditions, too */ 40660573Skris if (c->efd != -1) { 40760573Skris if (c->extended_usage == CHAN_EXTENDED_WRITE && 40860573Skris buffer_len(&c->extended) > 0) 40960573Skris FD_SET(c->efd, writeset); 41060573Skris else if (c->extended_usage == CHAN_EXTENDED_READ && 41160573Skris buffer_len(&c->extended) < c->remote_window) 41260573Skris FD_SET(c->efd, readset); 41360573Skris } 41460573Skris} 41560573Skris 41660573Skrisvoid 41760573Skrischannel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) 41860573Skris{ 41960573Skris if (buffer_len(&c->input) == 0) { 42060573Skris packet_start(SSH_MSG_CHANNEL_CLOSE); 42160573Skris packet_put_int(c->remote_id); 42260573Skris packet_send(); 42360573Skris c->type = SSH_CHANNEL_CLOSED; 42476262Sgreen debug("channel %d: closing after input drain.", c->self); 42560573Skris } 42660573Skris} 42760573Skris 42860573Skrisvoid 42960573Skrischannel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) 43060573Skris{ 43160573Skris if (buffer_len(&c->output) == 0) 43260573Skris channel_free(c->self); 43360573Skris else 43460573Skris FD_SET(c->sock, writeset); 43560573Skris} 43660573Skris 43760573Skris/* 43860573Skris * This is a special state for X11 authentication spoofing. An opened X11 43960573Skris * connection (when authentication spoofing is being done) remains in this 44060573Skris * state until the first packet has been completely read. The authentication 44160573Skris * data in that packet is then substituted by the real data if it matches the 44260573Skris * fake data, and the channel is put into normal mode. 44360573Skris * XXX All this happens at the client side. 44460573Skris */ 44560573Skrisint 44660573Skrisx11_open_helper(Channel *c) 44760573Skris{ 44876262Sgreen u_char *ucp; 44976262Sgreen u_int proto_len, data_len; 45057429Smarkm 45160573Skris /* Check if the fixed size part of the packet is in buffer. */ 45260573Skris if (buffer_len(&c->output) < 12) 45360573Skris return 0; 45457429Smarkm 45560573Skris /* Parse the lengths of variable-length fields. */ 45676262Sgreen ucp = (u_char *) buffer_ptr(&c->output); 45760573Skris if (ucp[0] == 0x42) { /* Byte order MSB first. */ 45860573Skris proto_len = 256 * ucp[6] + ucp[7]; 45960573Skris data_len = 256 * ucp[8] + ucp[9]; 46060573Skris } else if (ucp[0] == 0x6c) { /* Byte order LSB first. */ 46160573Skris proto_len = ucp[6] + 256 * ucp[7]; 46260573Skris data_len = ucp[8] + 256 * ucp[9]; 46360573Skris } else { 46460573Skris debug("Initial X11 packet contains bad byte order byte: 0x%x", 46560573Skris ucp[0]); 46660573Skris return -1; 46760573Skris } 46857429Smarkm 46960573Skris /* Check if the whole packet is in buffer. */ 47060573Skris if (buffer_len(&c->output) < 47160573Skris 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) 47260573Skris return 0; 47357429Smarkm 47460573Skris /* Check if authentication protocol matches. */ 47560573Skris if (proto_len != strlen(x11_saved_proto) || 47660573Skris memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { 47760573Skris debug("X11 connection uses different authentication protocol."); 47860573Skris return -1; 47960573Skris } 48060573Skris /* Check if authentication data matches our fake data. */ 48160573Skris if (data_len != x11_fake_data_len || 48260573Skris memcmp(ucp + 12 + ((proto_len + 3) & ~3), 48360573Skris x11_fake_data, x11_fake_data_len) != 0) { 48460573Skris debug("X11 auth data does not match fake data."); 48560573Skris return -1; 48660573Skris } 48760573Skris /* Check fake data length */ 48860573Skris if (x11_fake_data_len != x11_saved_data_len) { 48960573Skris error("X11 fake_data_len %d != saved_data_len %d", 49060573Skris x11_fake_data_len, x11_saved_data_len); 49160573Skris return -1; 49260573Skris } 49360573Skris /* 49460573Skris * Received authentication protocol and data match 49560573Skris * our fake data. Substitute the fake data with real 49660573Skris * data. 49760573Skris */ 49860573Skris memcpy(ucp + 12 + ((proto_len + 3) & ~3), 49960573Skris x11_saved_data, x11_saved_data_len); 50060573Skris return 1; 50160573Skris} 50257429Smarkm 50360573Skrisvoid 50460573Skrischannel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset) 50560573Skris{ 50660573Skris int ret = x11_open_helper(c); 50760573Skris if (ret == 1) { 50860573Skris /* Start normal processing for the channel. */ 50960573Skris c->type = SSH_CHANNEL_OPEN; 51060573Skris channel_pre_open_13(c, readset, writeset); 51160573Skris } else if (ret == -1) { 51260573Skris /* 51360573Skris * We have received an X11 connection that has bad 51460573Skris * authentication information. 51560573Skris */ 51676262Sgreen log("X11 connection rejected because of wrong authentication."); 51760573Skris buffer_clear(&c->input); 51860573Skris buffer_clear(&c->output); 51960573Skris close(c->sock); 52060573Skris c->sock = -1; 52160573Skris c->type = SSH_CHANNEL_CLOSED; 52260573Skris packet_start(SSH_MSG_CHANNEL_CLOSE); 52360573Skris packet_put_int(c->remote_id); 52460573Skris packet_send(); 52560573Skris } 52660573Skris} 52757429Smarkm 52860573Skrisvoid 52960573Skrischannel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) 53060573Skris{ 53160573Skris int ret = x11_open_helper(c); 53260573Skris if (ret == 1) { 53360573Skris c->type = SSH_CHANNEL_OPEN; 53460573Skris if (compat20) 53560573Skris channel_pre_open_20(c, readset, writeset); 53660573Skris else 53760573Skris channel_pre_open_15(c, readset, writeset); 53860573Skris } else if (ret == -1) { 53960573Skris debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate); 54060573Skris chan_read_failed(c); /** force close? */ 54160573Skris chan_write_failed(c); 54260573Skris debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); 54360573Skris } 54460573Skris} 54557429Smarkm 54676262Sgreen/* try to decode a socks4 header */ 54776262Sgreenint 54876262Sgreenchannel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) 54976262Sgreen{ 55076262Sgreen u_char *p, *host; 55176262Sgreen int len, have, i, found; 55276262Sgreen char username[256]; 55376262Sgreen struct { 55476262Sgreen u_int8_t version; 55576262Sgreen u_int8_t command; 55676262Sgreen u_int16_t dest_port; 55776262Sgreen struct in_addr dest_addr; 55876262Sgreen } s4_req, s4_rsp; 55976262Sgreen 56076262Sgreen debug2("channel %d: decode socks4", c->self); 56176262Sgreen 56276262Sgreen have = buffer_len(&c->input); 56376262Sgreen len = sizeof(s4_req); 56476262Sgreen if (have < len) 56576262Sgreen return 0; 56676262Sgreen p = buffer_ptr(&c->input); 56776262Sgreen for (found = 0, i = len; i < have; i++) { 56876262Sgreen if (p[i] == '\0') { 56976262Sgreen found = 1; 57076262Sgreen break; 57176262Sgreen } 57276262Sgreen if (i > 1024) { 57376262Sgreen /* the peer is probably sending garbage */ 57476262Sgreen debug("channel %d: decode socks4: too long", 57576262Sgreen c->self); 57676262Sgreen return -1; 57776262Sgreen } 57876262Sgreen } 57976262Sgreen if (!found) 58076262Sgreen return 0; 58176262Sgreen buffer_get(&c->input, (char *)&s4_req.version, 1); 58276262Sgreen buffer_get(&c->input, (char *)&s4_req.command, 1); 58376262Sgreen buffer_get(&c->input, (char *)&s4_req.dest_port, 2); 58476262Sgreen buffer_get(&c->input, (char *)&s4_req.dest_addr, 4); 58576262Sgreen have = buffer_len(&c->input); 58676262Sgreen p = buffer_ptr(&c->input); 58776262Sgreen len = strlen(p); 58876262Sgreen debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); 58976262Sgreen if (len > have) 59076262Sgreen fatal("channel %d: decode socks4: len %d > have %d", 59176262Sgreen c->self, len, have); 59276262Sgreen strlcpy(username, p, sizeof(username)); 59376262Sgreen buffer_consume(&c->input, len); 59476262Sgreen buffer_consume(&c->input, 1); /* trailing '\0' */ 59576262Sgreen 59676262Sgreen host = inet_ntoa(s4_req.dest_addr); 59776262Sgreen strlcpy(c->path, host, sizeof(c->path)); 59876262Sgreen c->host_port = ntohs(s4_req.dest_port); 59976262Sgreen 60076262Sgreen debug("channel %d: dynamic request: socks4 host %s port %u command %u", 60176262Sgreen c->self, host, c->host_port, s4_req.command); 60276262Sgreen 60376262Sgreen if (s4_req.command != 1) { 60476262Sgreen debug("channel %d: cannot handle: socks4 cn %d", 60576262Sgreen c->self, s4_req.command); 60676262Sgreen return -1; 60776262Sgreen } 60876262Sgreen s4_rsp.version = 0; /* vn: 0 for reply */ 60976262Sgreen s4_rsp.command = 90; /* cd: req granted */ 61076262Sgreen s4_rsp.dest_port = 0; /* ignored */ 61176262Sgreen s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ 61276262Sgreen buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp)); 61376262Sgreen return 1; 61476262Sgreen} 61576262Sgreen 61676262Sgreen/* dynamic port forwarding */ 61776262Sgreenvoid 61876262Sgreenchannel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) 61976262Sgreen{ 62076262Sgreen u_char *p; 62176262Sgreen int have, ret; 62276262Sgreen 62376262Sgreen have = buffer_len(&c->input); 62476262Sgreen 62576262Sgreen debug2("channel %d: pre_dynamic: have %d", c->self, have); 62676262Sgreen /* buffer_dump(&c->input); */ 62776262Sgreen /* check if the fixed size part of the packet is in buffer. */ 62876262Sgreen if (have < 4) { 62976262Sgreen /* need more */ 63076262Sgreen FD_SET(c->sock, readset); 63176262Sgreen return; 63276262Sgreen } 63376262Sgreen /* try to guess the protocol */ 63476262Sgreen p = buffer_ptr(&c->input); 63576262Sgreen switch (p[0]) { 63676262Sgreen case 0x04: 63776262Sgreen ret = channel_decode_socks4(c, readset, writeset); 63876262Sgreen break; 63976262Sgreen default: 64076262Sgreen ret = -1; 64176262Sgreen break; 64276262Sgreen } 64376262Sgreen if (ret < 0) { 64476262Sgreen channel_free(c->self); 64576262Sgreen } else if (ret == 0) { 64676262Sgreen debug2("channel %d: pre_dynamic: need more", c->self); 64776262Sgreen /* need more */ 64876262Sgreen FD_SET(c->sock, readset); 64976262Sgreen } else { 65076262Sgreen /* switch to the next state */ 65176262Sgreen c->type = SSH_CHANNEL_OPENING; 65276262Sgreen port_open_helper(c, "direct-tcpip"); 65376262Sgreen } 65476262Sgreen} 65576262Sgreen 65660573Skris/* This is our fake X11 server socket. */ 65760573Skrisvoid 65860573Skrischannel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) 65960573Skris{ 66060573Skris struct sockaddr addr; 66160573Skris int newsock, newch; 66260573Skris socklen_t addrlen; 66376262Sgreen char buf[16384], *remote_ipaddr; 66460573Skris int remote_port; 66557429Smarkm 66660573Skris if (FD_ISSET(c->sock, readset)) { 66760573Skris debug("X11 connection requested."); 66860573Skris addrlen = sizeof(addr); 66960573Skris newsock = accept(c->sock, &addr, &addrlen); 67060573Skris if (newsock < 0) { 67160573Skris error("accept: %.100s", strerror(errno)); 67260573Skris return; 67360573Skris } 67476262Sgreen remote_ipaddr = get_peer_ipaddr(newsock); 67560573Skris remote_port = get_peer_port(newsock); 67660573Skris snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", 67776262Sgreen remote_ipaddr, remote_port); 67857429Smarkm 67960573Skris newch = channel_new("x11", 68060573Skris SSH_CHANNEL_OPENING, newsock, newsock, -1, 68160573Skris c->local_window_max, c->local_maxpacket, 68269587Sgreen 0, xstrdup(buf), 1); 68360573Skris if (compat20) { 68460573Skris packet_start(SSH2_MSG_CHANNEL_OPEN); 68560573Skris packet_put_cstring("x11"); 68660573Skris packet_put_int(newch); 68760573Skris packet_put_int(c->local_window_max); 68860573Skris packet_put_int(c->local_maxpacket); 68976262Sgreen /* originator ipaddr and port */ 69076262Sgreen packet_put_cstring(remote_ipaddr); 69160573Skris if (datafellows & SSH_BUG_X11FWD) { 69260573Skris debug("ssh2 x11 bug compat mode"); 69357429Smarkm } else { 69460573Skris packet_put_int(remote_port); 69557429Smarkm } 69660573Skris packet_send(); 69760573Skris } else { 69860573Skris packet_start(SSH_SMSG_X11_OPEN); 69960573Skris packet_put_int(newch); 70060573Skris if (have_hostname_in_open) 70160573Skris packet_put_string(buf, strlen(buf)); 70260573Skris packet_send(); 70357429Smarkm } 70476262Sgreen xfree(remote_ipaddr); 70557429Smarkm } 70657429Smarkm} 70757429Smarkm 70876262Sgreenvoid 70976262Sgreenport_open_helper(Channel *c, char *rtype) 71076262Sgreen{ 71176262Sgreen int direct; 71276262Sgreen char buf[1024]; 71376262Sgreen char *remote_ipaddr = get_peer_ipaddr(c->sock); 71476262Sgreen u_short remote_port = get_peer_port(c->sock); 71576262Sgreen 71676262Sgreen direct = (strcmp(rtype, "direct-tcpip") == 0); 71776262Sgreen 71876262Sgreen snprintf(buf, sizeof buf, 71976262Sgreen "%s: listening port %d for %.100s port %d, " 72076262Sgreen "connect from %.200s port %d", 72176262Sgreen rtype, c->listening_port, c->path, c->host_port, 72276262Sgreen remote_ipaddr, remote_port); 72376262Sgreen 72476262Sgreen xfree(c->remote_name); 72576262Sgreen c->remote_name = xstrdup(buf); 72676262Sgreen 72776262Sgreen if (compat20) { 72876262Sgreen packet_start(SSH2_MSG_CHANNEL_OPEN); 72976262Sgreen packet_put_cstring(rtype); 73076262Sgreen packet_put_int(c->self); 73176262Sgreen packet_put_int(c->local_window_max); 73276262Sgreen packet_put_int(c->local_maxpacket); 73376262Sgreen if (direct) { 73476262Sgreen /* target host, port */ 73576262Sgreen packet_put_cstring(c->path); 73676262Sgreen packet_put_int(c->host_port); 73776262Sgreen } else { 73876262Sgreen /* listen address, port */ 73976262Sgreen packet_put_cstring(c->path); 74076262Sgreen packet_put_int(c->listening_port); 74176262Sgreen } 74276262Sgreen /* originator host and port */ 74376262Sgreen packet_put_cstring(remote_ipaddr); 74476262Sgreen packet_put_int(remote_port); 74576262Sgreen packet_send(); 74676262Sgreen } else { 74776262Sgreen packet_start(SSH_MSG_PORT_OPEN); 74876262Sgreen packet_put_int(c->self); 74976262Sgreen packet_put_cstring(c->path); 75076262Sgreen packet_put_int(c->host_port); 75176262Sgreen if (have_hostname_in_open) 75276262Sgreen packet_put_cstring(c->remote_name); 75376262Sgreen packet_send(); 75476262Sgreen } 75576262Sgreen xfree(remote_ipaddr); 75676262Sgreen} 75776262Sgreen 75857429Smarkm/* 75960573Skris * This socket is listening for connections to a forwarded TCP/IP port. 76057429Smarkm */ 76160573Skrisvoid 76260573Skrischannel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) 76357429Smarkm{ 76476262Sgreen Channel *nc; 76557429Smarkm struct sockaddr addr; 76676262Sgreen int newsock, newch, nextstate; 76757429Smarkm socklen_t addrlen; 76876262Sgreen char *rtype; 76957429Smarkm 77060573Skris if (FD_ISSET(c->sock, readset)) { 77160573Skris debug("Connection to port %d forwarding " 77260573Skris "to %.100s port %d requested.", 77360573Skris c->listening_port, c->path, c->host_port); 77476262Sgreen 77576262Sgreen rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ? 77676262Sgreen "forwarded-tcpip" : "direct-tcpip"; 77776262Sgreen nextstate = (c->host_port == 0) ? SSH_CHANNEL_DYNAMIC : 77876262Sgreen SSH_CHANNEL_OPENING; 77976262Sgreen 78060573Skris addrlen = sizeof(addr); 78160573Skris newsock = accept(c->sock, &addr, &addrlen); 78260573Skris if (newsock < 0) { 78360573Skris error("accept: %.100s", strerror(errno)); 78460573Skris return; 78560573Skris } 78676262Sgreen newch = channel_new(rtype, 78776262Sgreen nextstate, newsock, newsock, -1, 78860573Skris c->local_window_max, c->local_maxpacket, 78976262Sgreen 0, xstrdup(rtype), 1); 79076262Sgreen 79176262Sgreen nc = channel_lookup(newch); 79276262Sgreen if (nc == NULL) { 79376262Sgreen error("xxx: no new channel:"); 79476262Sgreen return; 79560573Skris } 79676262Sgreen nc->listening_port = c->listening_port; 79776262Sgreen nc->host_port = c->host_port; 79876262Sgreen strlcpy(nc->path, c->path, sizeof(nc->path)); 79976262Sgreen 80076262Sgreen if (nextstate != SSH_CHANNEL_DYNAMIC) 80176262Sgreen port_open_helper(nc, rtype); 80260573Skris } 80360573Skris} 80457429Smarkm 80560573Skris/* 80660573Skris * This is the authentication agent socket listening for connections from 80760573Skris * clients. 80860573Skris */ 80960573Skrisvoid 81060573Skrischannel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) 81160573Skris{ 81260573Skris struct sockaddr addr; 81360573Skris int newsock, newch; 81460573Skris socklen_t addrlen; 81557429Smarkm 81660573Skris if (FD_ISSET(c->sock, readset)) { 81760573Skris addrlen = sizeof(addr); 81860573Skris newsock = accept(c->sock, &addr, &addrlen); 81960573Skris if (newsock < 0) { 82060573Skris error("accept from auth socket: %.100s", strerror(errno)); 82160573Skris return; 82260573Skris } 82376262Sgreen newch = channel_new("accepted auth socket", 82476262Sgreen SSH_CHANNEL_OPENING, newsock, newsock, -1, 82576262Sgreen c->local_window_max, c->local_maxpacket, 82676262Sgreen 0, xstrdup("accepted auth socket"), 1); 82776262Sgreen if (compat20) { 82876262Sgreen packet_start(SSH2_MSG_CHANNEL_OPEN); 82976262Sgreen packet_put_cstring("auth-agent@openssh.com"); 83076262Sgreen packet_put_int(newch); 83176262Sgreen packet_put_int(c->local_window_max); 83276262Sgreen packet_put_int(c->local_maxpacket); 83376262Sgreen } else { 83476262Sgreen packet_start(SSH_SMSG_AGENT_OPEN); 83576262Sgreen packet_put_int(newch); 83676262Sgreen } 83760573Skris packet_send(); 83860573Skris } 83960573Skris} 84057429Smarkm 84176262Sgreenvoid 84276262Sgreenchannel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset) 84376262Sgreen{ 84476262Sgreen if (FD_ISSET(c->sock, writeset)) { 84576262Sgreen int err = 0; 84676262Sgreen int sz = sizeof(err); 84776262Sgreen c->type = SSH_CHANNEL_OPEN; 84876262Sgreen if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, (char *)&err, &sz) < 0) { 84976262Sgreen debug("getsockopt SO_ERROR failed"); 85076262Sgreen } else { 85176262Sgreen if (err == 0) { 85276262Sgreen debug("channel %d: connected)", c->self); 85376262Sgreen } else { 85476262Sgreen debug("channel %d: not connected: %s", 85576262Sgreen c->self, strerror(err)); 85676262Sgreen chan_read_failed(c); 85776262Sgreen chan_write_failed(c); 85876262Sgreen } 85976262Sgreen } 86076262Sgreen } 86176262Sgreen} 86276262Sgreen 86360573Skrisint 86460573Skrischannel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) 86560573Skris{ 86660573Skris char buf[16*1024]; 86760573Skris int len; 86857429Smarkm 86960573Skris if (c->rfd != -1 && 87060573Skris FD_ISSET(c->rfd, readset)) { 87160573Skris len = read(c->rfd, buf, sizeof(buf)); 87260573Skris if (len < 0 && (errno == EINTR || errno == EAGAIN)) 87360573Skris return 1; 87478827Sgreen if (len <= 0) { 87578827Sgreen debug("channel %d: read<=0 rfd %d len %d", 87660573Skris c->self, c->rfd, len); 87776262Sgreen if (c->type != SSH_CHANNEL_OPEN) { 87876262Sgreen debug("channel %d: not open", c->self); 87976262Sgreen channel_free(c->self); 88076262Sgreen return -1; 88176262Sgreen } else if (compat13) { 88260573Skris buffer_consume(&c->output, buffer_len(&c->output)); 88360573Skris c->type = SSH_CHANNEL_INPUT_DRAINING; 88476262Sgreen debug("channel %d: status set to input draining.", c->self); 88560573Skris } else { 88660573Skris chan_read_failed(c); 88757429Smarkm } 88860573Skris return -1; 88960573Skris } 89065668Skris if(c->input_filter != NULL) { 89165668Skris if (c->input_filter(c, buf, len) == -1) { 89276262Sgreen debug("channel %d: filter stops", c->self); 89365668Skris chan_read_failed(c); 89465668Skris } 89565668Skris } else { 89665668Skris buffer_append(&c->input, buf, len); 89765668Skris } 89860573Skris } 89960573Skris return 1; 90060573Skris} 90160573Skrisint 90260573Skrischannel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) 90360573Skris{ 90476262Sgreen struct termios tio; 90560573Skris int len; 90660573Skris 90760573Skris /* Send buffered output data to the socket. */ 90860573Skris if (c->wfd != -1 && 90960573Skris FD_ISSET(c->wfd, writeset) && 91060573Skris buffer_len(&c->output) > 0) { 91160573Skris len = write(c->wfd, buffer_ptr(&c->output), 91260573Skris buffer_len(&c->output)); 91360573Skris if (len < 0 && (errno == EINTR || errno == EAGAIN)) 91460573Skris return 1; 91560573Skris if (len <= 0) { 91676262Sgreen if (c->type != SSH_CHANNEL_OPEN) { 91776262Sgreen debug("channel %d: not open", c->self); 91876262Sgreen channel_free(c->self); 91976262Sgreen return -1; 92076262Sgreen } else if (compat13) { 92160573Skris buffer_consume(&c->output, buffer_len(&c->output)); 92276262Sgreen debug("channel %d: status set to input draining.", c->self); 92360573Skris c->type = SSH_CHANNEL_INPUT_DRAINING; 92460573Skris } else { 92560573Skris chan_write_failed(c); 92657429Smarkm } 92760573Skris return -1; 92860573Skris } 92974500Sgreen if (compat20 && c->isatty) { 93074500Sgreen if (tcgetattr(c->wfd, &tio) == 0 && 93174500Sgreen !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { 93274500Sgreen /* 93374500Sgreen * Simulate echo to reduce the impact of 93476262Sgreen * traffic analysis. We need to match the 93576262Sgreen * size of a SSH2_MSG_CHANNEL_DATA message 93676262Sgreen * (4 byte channel id + data) 93774500Sgreen */ 93876262Sgreen packet_send_ignore(4 + len); 93974500Sgreen packet_send(); 94074500Sgreen } 94174500Sgreen } 94260573Skris buffer_consume(&c->output, len); 94360573Skris if (compat20 && len > 0) { 94460573Skris c->local_consumed += len; 94560573Skris } 94660573Skris } 94760573Skris return 1; 94860573Skris} 94960573Skrisint 95060573Skrischannel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) 95160573Skris{ 95260573Skris char buf[16*1024]; 95360573Skris int len; 95457429Smarkm 95560573Skris/** XXX handle drain efd, too */ 95660573Skris if (c->efd != -1) { 95760573Skris if (c->extended_usage == CHAN_EXTENDED_WRITE && 95860573Skris FD_ISSET(c->efd, writeset) && 95960573Skris buffer_len(&c->extended) > 0) { 96060573Skris len = write(c->efd, buffer_ptr(&c->extended), 96160573Skris buffer_len(&c->extended)); 96269587Sgreen debug2("channel %d: written %d to efd %d", 96360573Skris c->self, len, c->efd); 96476262Sgreen if (len < 0 && (errno == EINTR || errno == EAGAIN)) 96576262Sgreen return 1; 96676262Sgreen if (len <= 0) { 96776262Sgreen debug2("channel %d: closing write-efd %d", 96876262Sgreen c->self, c->efd); 96976262Sgreen close(c->efd); 97076262Sgreen c->efd = -1; 97176262Sgreen } else { 97260573Skris buffer_consume(&c->extended, len); 97360573Skris c->local_consumed += len; 97457429Smarkm } 97560573Skris } else if (c->extended_usage == CHAN_EXTENDED_READ && 97660573Skris FD_ISSET(c->efd, readset)) { 97760573Skris len = read(c->efd, buf, sizeof(buf)); 97869587Sgreen debug2("channel %d: read %d from efd %d", 97960573Skris c->self, len, c->efd); 98076262Sgreen if (len < 0 && (errno == EINTR || errno == EAGAIN)) 98176262Sgreen return 1; 98276262Sgreen if (len <= 0) { 98376262Sgreen debug2("channel %d: closing read-efd %d", 98460573Skris c->self, c->efd); 98560573Skris close(c->efd); 98660573Skris c->efd = -1; 98776262Sgreen } else { 98860573Skris buffer_append(&c->extended, buf, len); 98976262Sgreen } 99060573Skris } 99160573Skris } 99260573Skris return 1; 99360573Skris} 99460573Skrisint 99576262Sgreenchannel_check_window(Channel *c) 99660573Skris{ 99776262Sgreen if (c->type == SSH_CHANNEL_OPEN && 99876262Sgreen !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && 99960573Skris c->local_window < c->local_window_max/2 && 100060573Skris c->local_consumed > 0) { 100160573Skris packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); 100260573Skris packet_put_int(c->remote_id); 100360573Skris packet_put_int(c->local_consumed); 100460573Skris packet_send(); 100569587Sgreen debug2("channel %d: window %d sent adjust %d", 100660573Skris c->self, c->local_window, 100760573Skris c->local_consumed); 100860573Skris c->local_window += c->local_consumed; 100960573Skris c->local_consumed = 0; 101060573Skris } 101160573Skris return 1; 101260573Skris} 101357429Smarkm 101460573Skrisvoid 101560573Skrischannel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset) 101660573Skris{ 101760573Skris channel_handle_rfd(c, readset, writeset); 101860573Skris channel_handle_wfd(c, readset, writeset); 101960573Skris} 102060573Skris 102160573Skrisvoid 102260573Skrischannel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset) 102360573Skris{ 102460573Skris channel_handle_rfd(c, readset, writeset); 102560573Skris channel_handle_wfd(c, readset, writeset); 102660573Skris channel_handle_efd(c, readset, writeset); 102776262Sgreen 102876262Sgreen channel_check_window(c); 102960573Skris} 103060573Skris 103160573Skrisvoid 103260573Skrischannel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) 103360573Skris{ 103460573Skris int len; 103560573Skris /* Send buffered output data to the socket. */ 103660573Skris if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) { 103760573Skris len = write(c->sock, buffer_ptr(&c->output), 103860573Skris buffer_len(&c->output)); 103960573Skris if (len <= 0) 104060573Skris buffer_consume(&c->output, buffer_len(&c->output)); 104160573Skris else 104260573Skris buffer_consume(&c->output, len); 104360573Skris } 104460573Skris} 104560573Skris 104660573Skrisvoid 104760573Skrischannel_handler_init_20(void) 104860573Skris{ 104960573Skris channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20; 105060573Skris channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; 105160573Skris channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; 105276262Sgreen channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; 105360573Skris channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; 105476262Sgreen channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 105576262Sgreen channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 105676262Sgreen channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; 105760573Skris 105860573Skris channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_2; 105960573Skris channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 106076262Sgreen channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; 106160573Skris channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; 106276262Sgreen channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 106376262Sgreen channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 106476262Sgreen channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_2; 106560573Skris} 106660573Skris 106760573Skrisvoid 106860573Skrischannel_handler_init_13(void) 106960573Skris{ 107060573Skris channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13; 107160573Skris channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open_13; 107260573Skris channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; 107360573Skris channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; 107460573Skris channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 107560573Skris channel_pre[SSH_CHANNEL_INPUT_DRAINING] = &channel_pre_input_draining; 107660573Skris channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining; 107776262Sgreen channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 107876262Sgreen channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; 107960573Skris 108060573Skris channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; 108160573Skris channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; 108260573Skris channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 108360573Skris channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 108460573Skris channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13; 108576262Sgreen channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 108676262Sgreen channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1; 108760573Skris} 108860573Skris 108960573Skrisvoid 109060573Skrischannel_handler_init_15(void) 109160573Skris{ 109260573Skris channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_15; 109360573Skris channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; 109460573Skris channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; 109560573Skris channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; 109660573Skris channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 109776262Sgreen channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 109876262Sgreen channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; 109960573Skris 110060573Skris channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; 110160573Skris channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 110260573Skris channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 110360573Skris channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; 110476262Sgreen channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 110576262Sgreen channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1; 110660573Skris} 110760573Skris 110860573Skrisvoid 110960573Skrischannel_handler_init(void) 111060573Skris{ 111160573Skris int i; 111260573Skris for(i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) { 111360573Skris channel_pre[i] = NULL; 111460573Skris channel_post[i] = NULL; 111560573Skris } 111660573Skris if (compat20) 111760573Skris channel_handler_init_20(); 111860573Skris else if (compat13) 111960573Skris channel_handler_init_13(); 112060573Skris else 112160573Skris channel_handler_init_15(); 112260573Skris} 112360573Skris 112460573Skrisvoid 112560573Skrischannel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) 112660573Skris{ 112760573Skris static int did_init = 0; 112860573Skris int i; 112960573Skris Channel *c; 113060573Skris 113160573Skris if (!did_init) { 113260573Skris channel_handler_init(); 113360573Skris did_init = 1; 113460573Skris } 113560573Skris for (i = 0; i < channels_alloc; i++) { 113660573Skris c = &channels[i]; 113760573Skris if (c->type == SSH_CHANNEL_FREE) 113857429Smarkm continue; 113960573Skris if (ftab[c->type] == NULL) 114060573Skris continue; 114160573Skris (*ftab[c->type])(c, readset, writeset); 114276262Sgreen if (chan_is_dead(c)) { 114376262Sgreen /* 114476262Sgreen * we have to remove the fd's from the select mask 114576262Sgreen * before the channels are free'd and the fd's are 114676262Sgreen * closed 114776262Sgreen */ 114876262Sgreen if (c->wfd != -1) 114976262Sgreen FD_CLR(c->wfd, writeset); 115076262Sgreen if (c->rfd != -1) 115176262Sgreen FD_CLR(c->rfd, readset); 115276262Sgreen if (c->efd != -1) { 115376262Sgreen if (c->extended_usage == CHAN_EXTENDED_READ) 115476262Sgreen FD_CLR(c->efd, readset); 115576262Sgreen if (c->extended_usage == CHAN_EXTENDED_WRITE) 115676262Sgreen FD_CLR(c->efd, writeset); 115776262Sgreen } 115876262Sgreen channel_free(c->self); 115976262Sgreen } 116057429Smarkm } 116157429Smarkm} 116257429Smarkm 116360573Skrisvoid 116476262Sgreenchannel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, 116576262Sgreen int rekeying) 116660573Skris{ 116776262Sgreen int n; 116876262Sgreen u_int sz; 116976262Sgreen 117076262Sgreen n = MAX(*maxfdp, channel_max_fd); 117176262Sgreen 117276262Sgreen sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); 117376262Sgreen if (*readsetp == NULL || n > *maxfdp) { 117476262Sgreen if (*readsetp) 117576262Sgreen xfree(*readsetp); 117676262Sgreen if (*writesetp) 117776262Sgreen xfree(*writesetp); 117876262Sgreen *readsetp = xmalloc(sz); 117976262Sgreen *writesetp = xmalloc(sz); 118076262Sgreen *maxfdp = n; 118176262Sgreen } 118276262Sgreen memset(*readsetp, 0, sz); 118376262Sgreen memset(*writesetp, 0, sz); 118476262Sgreen 118576262Sgreen if (!rekeying) 118676262Sgreen channel_handler(channel_pre, *readsetp, *writesetp); 118760573Skris} 118860573Skris 118960573Skrisvoid 119060573Skrischannel_after_select(fd_set * readset, fd_set * writeset) 119160573Skris{ 119260573Skris channel_handler(channel_post, readset, writeset); 119360573Skris} 119460573Skris 119576262Sgreen/* If there is data to send to the connection, enqueue some of it now. */ 119657429Smarkm 119760573Skrisvoid 119857429Smarkmchannel_output_poll() 119957429Smarkm{ 120057429Smarkm int len, i; 120160573Skris Channel *c; 120257429Smarkm 120357429Smarkm for (i = 0; i < channels_alloc; i++) { 120460573Skris c = &channels[i]; 120557429Smarkm 120657429Smarkm /* We are only interested in channels that can have buffered incoming data. */ 120757429Smarkm if (compat13) { 120860573Skris if (c->type != SSH_CHANNEL_OPEN && 120960573Skris c->type != SSH_CHANNEL_INPUT_DRAINING) 121057429Smarkm continue; 121157429Smarkm } else { 121260573Skris if (c->type != SSH_CHANNEL_OPEN) 121357429Smarkm continue; 121457429Smarkm } 121560573Skris if (compat20 && 121660573Skris (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { 121776262Sgreen /* XXX is this true? */ 121876262Sgreen debug2("channel %d: no data after CLOSE", c->self); 121960573Skris continue; 122060573Skris } 122157429Smarkm 122257429Smarkm /* Get the amount of buffered data for this channel. */ 122376262Sgreen if ((c->istate == CHAN_INPUT_OPEN || 122476262Sgreen c->istate == CHAN_INPUT_WAIT_DRAIN) && 122576262Sgreen (len = buffer_len(&c->input)) > 0) { 122657429Smarkm /* Send some data for the other side over the secure connection. */ 122760573Skris if (compat20) { 122860573Skris if (len > c->remote_window) 122960573Skris len = c->remote_window; 123060573Skris if (len > c->remote_maxpacket) 123160573Skris len = c->remote_maxpacket; 123257429Smarkm } else { 123360573Skris if (packet_is_interactive()) { 123460573Skris if (len > 1024) 123560573Skris len = 512; 123660573Skris } else { 123760573Skris /* Keep the packets at reasonable size. */ 123860573Skris if (len > packet_get_maxsize()/2) 123960573Skris len = packet_get_maxsize()/2; 124060573Skris } 124157429Smarkm } 124260573Skris if (len > 0) { 124360573Skris packet_start(compat20 ? 124460573Skris SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA); 124560573Skris packet_put_int(c->remote_id); 124660573Skris packet_put_string(buffer_ptr(&c->input), len); 124760573Skris packet_send(); 124860573Skris buffer_consume(&c->input, len); 124960573Skris c->remote_window -= len; 125060573Skris } 125160573Skris } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) { 125257429Smarkm if (compat13) 125357429Smarkm fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); 125457429Smarkm /* 125557429Smarkm * input-buffer is empty and read-socket shutdown: 125657429Smarkm * tell peer, that we will not send more data: send IEOF 125757429Smarkm */ 125860573Skris chan_ibuf_empty(c); 125957429Smarkm } 126060573Skris /* Send extended data, i.e. stderr */ 126160573Skris if (compat20 && 126260573Skris c->remote_window > 0 && 126360573Skris (len = buffer_len(&c->extended)) > 0 && 126460573Skris c->extended_usage == CHAN_EXTENDED_READ) { 126576262Sgreen debug2("channel %d: rwin %d elen %d euse %d", 126676262Sgreen c->self, c->remote_window, buffer_len(&c->extended), 126776262Sgreen c->extended_usage); 126860573Skris if (len > c->remote_window) 126960573Skris len = c->remote_window; 127060573Skris if (len > c->remote_maxpacket) 127160573Skris len = c->remote_maxpacket; 127260573Skris packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA); 127360573Skris packet_put_int(c->remote_id); 127460573Skris packet_put_int(SSH2_EXTENDED_DATA_STDERR); 127560573Skris packet_put_string(buffer_ptr(&c->extended), len); 127660573Skris packet_send(); 127760573Skris buffer_consume(&c->extended, len); 127860573Skris c->remote_window -= len; 127976262Sgreen debug2("channel %d: sent ext data %d", c->self, len); 128060573Skris } 128157429Smarkm } 128257429Smarkm} 128357429Smarkm 128457429Smarkm/* 128557429Smarkm * This is called when a packet of type CHANNEL_DATA has just been received. 128657429Smarkm * The message type has already been consumed, but channel number and data is 128757429Smarkm * still there. 128857429Smarkm */ 128957429Smarkm 129060573Skrisvoid 129169587Sgreenchannel_input_data(int type, int plen, void *ctxt) 129257429Smarkm{ 129357429Smarkm int id; 129457429Smarkm char *data; 129576262Sgreen u_int data_len; 129660573Skris Channel *c; 129757429Smarkm 129857429Smarkm /* Get the channel number and verify it. */ 129957429Smarkm id = packet_get_int(); 130060573Skris c = channel_lookup(id); 130160573Skris if (c == NULL) 130257429Smarkm packet_disconnect("Received data for nonexistent channel %d.", id); 130357429Smarkm 130457429Smarkm /* Ignore any data for non-open channels (might happen on close) */ 130560573Skris if (c->type != SSH_CHANNEL_OPEN && 130660573Skris c->type != SSH_CHANNEL_X11_OPEN) 130757429Smarkm return; 130857429Smarkm 130957429Smarkm /* same for protocol 1.5 if output end is no longer open */ 131060573Skris if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) 131157429Smarkm return; 131257429Smarkm 131357429Smarkm /* Get the data. */ 131457429Smarkm data = packet_get_string(&data_len); 131560573Skris packet_done(); 131660573Skris 131760573Skris if (compat20){ 131860573Skris if (data_len > c->local_maxpacket) { 131960573Skris log("channel %d: rcvd big packet %d, maxpack %d", 132060573Skris c->self, data_len, c->local_maxpacket); 132160573Skris } 132260573Skris if (data_len > c->local_window) { 132360573Skris log("channel %d: rcvd too much data %d, win %d", 132460573Skris c->self, data_len, c->local_window); 132560573Skris xfree(data); 132660573Skris return; 132760573Skris } 132860573Skris c->local_window -= data_len; 132960573Skris }else{ 133060573Skris packet_integrity_check(plen, 4 + 4 + data_len, type); 133160573Skris } 133260573Skris buffer_append(&c->output, data, data_len); 133357429Smarkm xfree(data); 133457429Smarkm} 133560573Skrisvoid 133669587Sgreenchannel_input_extended_data(int type, int plen, void *ctxt) 133760573Skris{ 133860573Skris int id; 133960573Skris int tcode; 134060573Skris char *data; 134176262Sgreen u_int data_len; 134260573Skris Channel *c; 134357429Smarkm 134460573Skris /* Get the channel number and verify it. */ 134560573Skris id = packet_get_int(); 134660573Skris c = channel_lookup(id); 134760573Skris 134860573Skris if (c == NULL) 134960573Skris packet_disconnect("Received extended_data for bad channel %d.", id); 135060573Skris if (c->type != SSH_CHANNEL_OPEN) { 135160573Skris log("channel %d: ext data for non open", id); 135260573Skris return; 135360573Skris } 135460573Skris tcode = packet_get_int(); 135560573Skris if (c->efd == -1 || 135660573Skris c->extended_usage != CHAN_EXTENDED_WRITE || 135760573Skris tcode != SSH2_EXTENDED_DATA_STDERR) { 135860573Skris log("channel %d: bad ext data", c->self); 135960573Skris return; 136060573Skris } 136160573Skris data = packet_get_string(&data_len); 136260573Skris packet_done(); 136360573Skris if (data_len > c->local_window) { 136460573Skris log("channel %d: rcvd too much extended_data %d, win %d", 136560573Skris c->self, data_len, c->local_window); 136660573Skris xfree(data); 136760573Skris return; 136860573Skris } 136969587Sgreen debug2("channel %d: rcvd ext data %d", c->self, data_len); 137060573Skris c->local_window -= data_len; 137160573Skris buffer_append(&c->extended, data, data_len); 137260573Skris xfree(data); 137360573Skris} 137460573Skris 137560573Skris 137657429Smarkm/* 137757429Smarkm * Returns true if no channel has too much buffered data, and false if one or 137857429Smarkm * more channel is overfull. 137957429Smarkm */ 138057429Smarkm 138160573Skrisint 138257429Smarkmchannel_not_very_much_buffered_data() 138357429Smarkm{ 138476262Sgreen u_int i; 138560573Skris Channel *c; 138657429Smarkm 138757429Smarkm for (i = 0; i < channels_alloc; i++) { 138860573Skris c = &channels[i]; 138960573Skris if (c->type == SSH_CHANNEL_OPEN) { 139060573Skris if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) { 139160573Skris debug("channel %d: big input buffer %d", 139260573Skris c->self, buffer_len(&c->input)); 139357429Smarkm return 0; 139460573Skris } 139560573Skris if (buffer_len(&c->output) > packet_get_maxsize()) { 139660573Skris debug("channel %d: big output buffer %d", 139760573Skris c->self, buffer_len(&c->output)); 139857429Smarkm return 0; 139960573Skris } 140057429Smarkm } 140157429Smarkm } 140257429Smarkm return 1; 140357429Smarkm} 140457429Smarkm 140560573Skrisvoid 140669587Sgreenchannel_input_ieof(int type, int plen, void *ctxt) 140760573Skris{ 140860573Skris int id; 140960573Skris Channel *c; 141057429Smarkm 141160573Skris packet_integrity_check(plen, 4, type); 141260573Skris 141360573Skris id = packet_get_int(); 141460573Skris c = channel_lookup(id); 141560573Skris if (c == NULL) 141660573Skris packet_disconnect("Received ieof for nonexistent channel %d.", id); 141760573Skris chan_rcvd_ieof(c); 141860573Skris} 141960573Skris 142060573Skrisvoid 142169587Sgreenchannel_input_close(int type, int plen, void *ctxt) 142257429Smarkm{ 142360573Skris int id; 142460573Skris Channel *c; 142557429Smarkm 142660573Skris packet_integrity_check(plen, 4, type); 142757429Smarkm 142860573Skris id = packet_get_int(); 142960573Skris c = channel_lookup(id); 143060573Skris if (c == NULL) 143160573Skris packet_disconnect("Received close for nonexistent channel %d.", id); 143257429Smarkm 143357429Smarkm /* 143457429Smarkm * Send a confirmation that we have closed the channel and no more 143557429Smarkm * data is coming for it. 143657429Smarkm */ 143757429Smarkm packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); 143860573Skris packet_put_int(c->remote_id); 143957429Smarkm packet_send(); 144057429Smarkm 144157429Smarkm /* 144257429Smarkm * If the channel is in closed state, we have sent a close request, 144357429Smarkm * and the other side will eventually respond with a confirmation. 144457429Smarkm * Thus, we cannot free the channel here, because then there would be 144557429Smarkm * no-one to receive the confirmation. The channel gets freed when 144657429Smarkm * the confirmation arrives. 144757429Smarkm */ 144860573Skris if (c->type != SSH_CHANNEL_CLOSED) { 144957429Smarkm /* 145057429Smarkm * Not a closed channel - mark it as draining, which will 145157429Smarkm * cause it to be freed later. 145257429Smarkm */ 145360573Skris buffer_consume(&c->input, buffer_len(&c->input)); 145460573Skris c->type = SSH_CHANNEL_OUTPUT_DRAINING; 145557429Smarkm } 145657429Smarkm} 145757429Smarkm 145860573Skris/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ 145960573Skrisvoid 146069587Sgreenchannel_input_oclose(int type, int plen, void *ctxt) 146160573Skris{ 146260573Skris int id = packet_get_int(); 146360573Skris Channel *c = channel_lookup(id); 146460573Skris packet_integrity_check(plen, 4, type); 146560573Skris if (c == NULL) 146660573Skris packet_disconnect("Received oclose for nonexistent channel %d.", id); 146760573Skris chan_rcvd_oclose(c); 146860573Skris} 146957429Smarkm 147060573Skrisvoid 147169587Sgreenchannel_input_close_confirmation(int type, int plen, void *ctxt) 147257429Smarkm{ 147360573Skris int id = packet_get_int(); 147460573Skris Channel *c = channel_lookup(id); 147557429Smarkm 147660573Skris packet_done(); 147760573Skris if (c == NULL) 147860573Skris packet_disconnect("Received close confirmation for " 147960573Skris "out-of-range channel %d.", id); 148060573Skris if (c->type != SSH_CHANNEL_CLOSED) 148160573Skris packet_disconnect("Received close confirmation for " 148260573Skris "non-closed channel %d (type %d).", id, c->type); 148360573Skris channel_free(c->self); 148460573Skris} 148557429Smarkm 148660573Skrisvoid 148769587Sgreenchannel_input_open_confirmation(int type, int plen, void *ctxt) 148860573Skris{ 148960573Skris int id, remote_id; 149060573Skris Channel *c; 149160573Skris 149260573Skris if (!compat20) 149360573Skris packet_integrity_check(plen, 4 + 4, type); 149460573Skris 149560573Skris id = packet_get_int(); 149660573Skris c = channel_lookup(id); 149760573Skris 149860573Skris if (c==NULL || c->type != SSH_CHANNEL_OPENING) 149960573Skris packet_disconnect("Received open confirmation for " 150060573Skris "non-opening channel %d.", id); 150160573Skris remote_id = packet_get_int(); 150260573Skris /* Record the remote channel number and mark that the channel is now open. */ 150360573Skris c->remote_id = remote_id; 150460573Skris c->type = SSH_CHANNEL_OPEN; 150560573Skris 150660573Skris if (compat20) { 150760573Skris c->remote_window = packet_get_int(); 150860573Skris c->remote_maxpacket = packet_get_int(); 150960573Skris packet_done(); 151060573Skris if (c->cb_fn != NULL && c->cb_event == type) { 151169587Sgreen debug2("callback start"); 151260573Skris c->cb_fn(c->self, c->cb_arg); 151369587Sgreen debug2("callback done"); 151460573Skris } 151560573Skris debug("channel %d: open confirm rwindow %d rmax %d", c->self, 151660573Skris c->remote_window, c->remote_maxpacket); 151757429Smarkm } 151857429Smarkm} 151957429Smarkm 152060573Skrisvoid 152169587Sgreenchannel_input_open_failure(int type, int plen, void *ctxt) 152257429Smarkm{ 152376262Sgreen int id, reason; 152476262Sgreen char *msg = NULL, *lang = NULL; 152560573Skris Channel *c; 152657429Smarkm 152760573Skris if (!compat20) 152860573Skris packet_integrity_check(plen, 4, type); 152957429Smarkm 153060573Skris id = packet_get_int(); 153160573Skris c = channel_lookup(id); 153257429Smarkm 153360573Skris if (c==NULL || c->type != SSH_CHANNEL_OPENING) 153460573Skris packet_disconnect("Received open failure for " 153560573Skris "non-opening channel %d.", id); 153660573Skris if (compat20) { 153776262Sgreen reason = packet_get_int(); 153876262Sgreen if (packet_remaining() > 0) { 153976262Sgreen msg = packet_get_string(NULL); 154076262Sgreen lang = packet_get_string(NULL); 154176262Sgreen } 154260573Skris packet_done(); 154376262Sgreen log("channel_open_failure: %d: reason %d %s", id, 154476262Sgreen reason, msg ? msg : "<no additional info>"); 154576262Sgreen if (msg != NULL) 154676262Sgreen xfree(msg); 154776262Sgreen if (lang != NULL) 154876262Sgreen xfree(lang); 154960573Skris } 155060573Skris /* Free the channel. This will also close the socket. */ 155160573Skris channel_free(id); 155257429Smarkm} 155357429Smarkm 155460573Skrisvoid 155569587Sgreenchannel_input_channel_request(int type, int plen, void *ctxt) 155660573Skris{ 155760573Skris int id; 155860573Skris Channel *c; 155957429Smarkm 156060573Skris id = packet_get_int(); 156160573Skris c = channel_lookup(id); 156260573Skris 156360573Skris if (c == NULL || 156460573Skris (c->type != SSH_CHANNEL_OPEN && c->type != SSH_CHANNEL_LARVAL)) 156560573Skris packet_disconnect("Received request for " 156660573Skris "non-open channel %d.", id); 156760573Skris if (c->cb_fn != NULL && c->cb_event == type) { 156869587Sgreen debug2("callback start"); 156960573Skris c->cb_fn(c->self, c->cb_arg); 157069587Sgreen debug2("callback done"); 157160573Skris } else { 157260573Skris char *service = packet_get_string(NULL); 157376262Sgreen debug("channel %d: rcvd request for %s", c->self, service); 157469587Sgreen debug("cb_fn %p cb_event %d", c->cb_fn , c->cb_event); 157560573Skris xfree(service); 157660573Skris } 157760573Skris} 157860573Skris 157960573Skrisvoid 158069587Sgreenchannel_input_window_adjust(int type, int plen, void *ctxt) 158157429Smarkm{ 158260573Skris Channel *c; 158360573Skris int id, adjust; 158457429Smarkm 158560573Skris if (!compat20) 158660573Skris return; 158760573Skris 158857429Smarkm /* Get the channel number and verify it. */ 158960573Skris id = packet_get_int(); 159060573Skris c = channel_lookup(id); 159157429Smarkm 159260573Skris if (c == NULL || c->type != SSH_CHANNEL_OPEN) { 159360573Skris log("Received window adjust for " 159460573Skris "non-open channel %d.", id); 159560573Skris return; 159660573Skris } 159760573Skris adjust = packet_get_int(); 159860573Skris packet_done(); 159969587Sgreen debug2("channel %d: rcvd adjust %d", id, adjust); 160060573Skris c->remote_window += adjust; 160157429Smarkm} 160257429Smarkm 160357429Smarkm/* 160457429Smarkm * Stops listening for channels, and removes any unix domain sockets that we 160557429Smarkm * might have. 160657429Smarkm */ 160757429Smarkm 160860573Skrisvoid 160957429Smarkmchannel_stop_listening() 161057429Smarkm{ 161157429Smarkm int i; 161257429Smarkm for (i = 0; i < channels_alloc; i++) { 161357429Smarkm switch (channels[i].type) { 161457429Smarkm case SSH_CHANNEL_AUTH_SOCKET: 161557429Smarkm close(channels[i].sock); 161677925Sgreen /* auth_sock_cleanup_proc deletes the socket */ 161757429Smarkm channel_free(i); 161857429Smarkm break; 161957429Smarkm case SSH_CHANNEL_PORT_LISTENER: 162076262Sgreen case SSH_CHANNEL_RPORT_LISTENER: 162157429Smarkm case SSH_CHANNEL_X11_LISTENER: 162257429Smarkm close(channels[i].sock); 162357429Smarkm channel_free(i); 162457429Smarkm break; 162557429Smarkm default: 162657429Smarkm break; 162757429Smarkm } 162857429Smarkm } 162957429Smarkm} 163057429Smarkm 163157429Smarkm/* 163260573Skris * Closes the sockets/fds of all channels. This is used to close extra file 163357429Smarkm * descriptors after a fork. 163457429Smarkm */ 163557429Smarkm 163660573Skrisvoid 163757429Smarkmchannel_close_all() 163857429Smarkm{ 163957429Smarkm int i; 164060573Skris for (i = 0; i < channels_alloc; i++) 164157429Smarkm if (channels[i].type != SSH_CHANNEL_FREE) 164260573Skris channel_close_fds(&channels[i]); 164357429Smarkm} 164457429Smarkm 164557429Smarkm/* Returns true if any channel is still open. */ 164657429Smarkm 164760573Skrisint 164857429Smarkmchannel_still_open() 164957429Smarkm{ 165076262Sgreen u_int i; 165157429Smarkm for (i = 0; i < channels_alloc; i++) 165257429Smarkm switch (channels[i].type) { 165357429Smarkm case SSH_CHANNEL_FREE: 165457429Smarkm case SSH_CHANNEL_X11_LISTENER: 165557429Smarkm case SSH_CHANNEL_PORT_LISTENER: 165676262Sgreen case SSH_CHANNEL_RPORT_LISTENER: 165757429Smarkm case SSH_CHANNEL_CLOSED: 165857429Smarkm case SSH_CHANNEL_AUTH_SOCKET: 165976262Sgreen case SSH_CHANNEL_DYNAMIC: 166076262Sgreen case SSH_CHANNEL_CONNECTING: /* XXX ??? */ 166157429Smarkm continue; 166260573Skris case SSH_CHANNEL_LARVAL: 166360573Skris if (!compat20) 166460573Skris fatal("cannot happen: SSH_CHANNEL_LARVAL"); 166560573Skris continue; 166657429Smarkm case SSH_CHANNEL_OPENING: 166757429Smarkm case SSH_CHANNEL_OPEN: 166857429Smarkm case SSH_CHANNEL_X11_OPEN: 166957429Smarkm return 1; 167057429Smarkm case SSH_CHANNEL_INPUT_DRAINING: 167157429Smarkm case SSH_CHANNEL_OUTPUT_DRAINING: 167257429Smarkm if (!compat13) 167357429Smarkm fatal("cannot happen: OUT_DRAIN"); 167457429Smarkm return 1; 167557429Smarkm default: 167657429Smarkm fatal("channel_still_open: bad channel type %d", channels[i].type); 167757429Smarkm /* NOTREACHED */ 167857429Smarkm } 167957429Smarkm return 0; 168057429Smarkm} 168157429Smarkm 168276262Sgreen/* Returns the id of an open channel suitable for keepaliving */ 168376262Sgreen 168476262Sgreenint 168576262Sgreenchannel_find_open() 168676262Sgreen{ 168776262Sgreen u_int i; 168876262Sgreen for (i = 0; i < channels_alloc; i++) 168976262Sgreen switch (channels[i].type) { 169076262Sgreen case SSH_CHANNEL_CLOSED: 169176262Sgreen case SSH_CHANNEL_DYNAMIC: 169276262Sgreen case SSH_CHANNEL_FREE: 169376262Sgreen case SSH_CHANNEL_X11_LISTENER: 169476262Sgreen case SSH_CHANNEL_PORT_LISTENER: 169576262Sgreen case SSH_CHANNEL_RPORT_LISTENER: 169676262Sgreen case SSH_CHANNEL_OPENING: 169776262Sgreen continue; 169876262Sgreen case SSH_CHANNEL_LARVAL: 169976262Sgreen case SSH_CHANNEL_AUTH_SOCKET: 170076262Sgreen case SSH_CHANNEL_CONNECTING: /* XXX ??? */ 170176262Sgreen case SSH_CHANNEL_OPEN: 170276262Sgreen case SSH_CHANNEL_X11_OPEN: 170376262Sgreen return i; 170476262Sgreen case SSH_CHANNEL_INPUT_DRAINING: 170576262Sgreen case SSH_CHANNEL_OUTPUT_DRAINING: 170676262Sgreen if (!compat13) 170776262Sgreen fatal("cannot happen: OUT_DRAIN"); 170876262Sgreen return i; 170976262Sgreen default: 171076262Sgreen fatal("channel_find_open: bad channel type %d", channels[i].type); 171176262Sgreen /* NOTREACHED */ 171276262Sgreen } 171376262Sgreen return -1; 171476262Sgreen} 171576262Sgreen 171676262Sgreen 171757429Smarkm/* 171857429Smarkm * Returns a message describing the currently open forwarded connections, 171957429Smarkm * suitable for sending to the client. The message contains crlf pairs for 172057429Smarkm * newlines. 172157429Smarkm */ 172257429Smarkm 172357429Smarkmchar * 172457429Smarkmchannel_open_message() 172557429Smarkm{ 172657429Smarkm Buffer buffer; 172757429Smarkm int i; 172857429Smarkm char buf[512], *cp; 172957429Smarkm 173057429Smarkm buffer_init(&buffer); 173157429Smarkm snprintf(buf, sizeof buf, "The following connections are open:\r\n"); 173257429Smarkm buffer_append(&buffer, buf, strlen(buf)); 173357429Smarkm for (i = 0; i < channels_alloc; i++) { 173457429Smarkm Channel *c = &channels[i]; 173557429Smarkm switch (c->type) { 173657429Smarkm case SSH_CHANNEL_FREE: 173757429Smarkm case SSH_CHANNEL_X11_LISTENER: 173857429Smarkm case SSH_CHANNEL_PORT_LISTENER: 173976262Sgreen case SSH_CHANNEL_RPORT_LISTENER: 174057429Smarkm case SSH_CHANNEL_CLOSED: 174157429Smarkm case SSH_CHANNEL_AUTH_SOCKET: 174257429Smarkm continue; 174360573Skris case SSH_CHANNEL_LARVAL: 174457429Smarkm case SSH_CHANNEL_OPENING: 174576262Sgreen case SSH_CHANNEL_CONNECTING: 174676262Sgreen case SSH_CHANNEL_DYNAMIC: 174757429Smarkm case SSH_CHANNEL_OPEN: 174857429Smarkm case SSH_CHANNEL_X11_OPEN: 174957429Smarkm case SSH_CHANNEL_INPUT_DRAINING: 175057429Smarkm case SSH_CHANNEL_OUTPUT_DRAINING: 175160573Skris snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n", 175257429Smarkm c->self, c->remote_name, 175357429Smarkm c->type, c->remote_id, 175457429Smarkm c->istate, buffer_len(&c->input), 175560573Skris c->ostate, buffer_len(&c->output), 175660573Skris c->rfd, c->wfd); 175757429Smarkm buffer_append(&buffer, buf, strlen(buf)); 175857429Smarkm continue; 175957429Smarkm default: 176060573Skris fatal("channel_open_message: bad channel type %d", c->type); 176157429Smarkm /* NOTREACHED */ 176257429Smarkm } 176357429Smarkm } 176457429Smarkm buffer_append(&buffer, "\0", 1); 176557429Smarkm cp = xstrdup(buffer_ptr(&buffer)); 176657429Smarkm buffer_free(&buffer); 176757429Smarkm return cp; 176857429Smarkm} 176957429Smarkm 177057429Smarkm/* 177157429Smarkm * Initiate forwarding of connections to local port "port" through the secure 177257429Smarkm * channel to host:port from remote side. 177357429Smarkm */ 177476262Sgreenint 177576262Sgreenchannel_request_local_forwarding(u_short listen_port, const char *host_to_connect, 177676262Sgreen u_short port_to_connect, int gateway_ports) 177776262Sgreen{ 177876262Sgreen return channel_request_forwarding( 177976262Sgreen NULL, listen_port, 178076262Sgreen host_to_connect, port_to_connect, 178176262Sgreen gateway_ports, /*remote_fwd*/ 0); 178276262Sgreen} 178357429Smarkm 178476262Sgreen/* 178576262Sgreen * If 'remote_fwd' is true we have a '-R style' listener for protocol 2 178676262Sgreen * (SSH_CHANNEL_RPORT_LISTENER). 178776262Sgreen */ 178876262Sgreenint 178976262Sgreenchannel_request_forwarding( 179076262Sgreen const char *listen_address, u_short listen_port, 179176262Sgreen const char *host_to_connect, u_short port_to_connect, 179276262Sgreen int gateway_ports, int remote_fwd) 179357429Smarkm{ 179476262Sgreen int success, ch, sock, on = 1, ctype; 179557429Smarkm struct addrinfo hints, *ai, *aitop; 179657429Smarkm char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 179776262Sgreen const char *host; 179857429Smarkm struct linger linger; 179957429Smarkm 180076262Sgreen success = 0; 180157429Smarkm 180276262Sgreen if (remote_fwd) { 180376262Sgreen host = listen_address; 180476262Sgreen ctype = SSH_CHANNEL_RPORT_LISTENER; 180576262Sgreen } else { 180676262Sgreen host = host_to_connect; 180776262Sgreen ctype =SSH_CHANNEL_PORT_LISTENER; 180876262Sgreen } 180976262Sgreen 181076262Sgreen if (strlen(host) > sizeof(channels[0].path) - 1) { 181176262Sgreen error("Forward host name too long."); 181276262Sgreen return success; 181376262Sgreen } 181476262Sgreen 181576262Sgreen /* XXX listen_address is currently ignored */ 181657429Smarkm /* 181757429Smarkm * getaddrinfo returns a loopback address if the hostname is 181857429Smarkm * set to NULL and hints.ai_flags is not AI_PASSIVE 181957429Smarkm */ 182057429Smarkm memset(&hints, 0, sizeof(hints)); 182157429Smarkm hints.ai_family = IPv4or6; 182257429Smarkm hints.ai_flags = gateway_ports ? AI_PASSIVE : 0; 182357429Smarkm hints.ai_socktype = SOCK_STREAM; 182476262Sgreen snprintf(strport, sizeof strport, "%d", listen_port); 182557429Smarkm if (getaddrinfo(NULL, strport, &hints, &aitop) != 0) 182657429Smarkm packet_disconnect("getaddrinfo: fatal error"); 182757429Smarkm 182857429Smarkm for (ai = aitop; ai; ai = ai->ai_next) { 182957429Smarkm if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 183057429Smarkm continue; 183157429Smarkm if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), 183257429Smarkm strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 183376262Sgreen error("channel_request_forwarding: getnameinfo failed"); 183457429Smarkm continue; 183557429Smarkm } 183657429Smarkm /* Create a port to listen for the host. */ 183757429Smarkm sock = socket(ai->ai_family, SOCK_STREAM, 0); 183857429Smarkm if (sock < 0) { 183957429Smarkm /* this is no error since kernel may not support ipv6 */ 184057429Smarkm verbose("socket: %.100s", strerror(errno)); 184157429Smarkm continue; 184257429Smarkm } 184357429Smarkm /* 184457429Smarkm * Set socket options. We would like the socket to disappear 184557429Smarkm * as soon as it has been closed for whatever reason. 184657429Smarkm */ 184757429Smarkm setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); 184857429Smarkm linger.l_onoff = 1; 184957429Smarkm linger.l_linger = 5; 185057429Smarkm setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); 185157429Smarkm debug("Local forwarding listening on %s port %s.", ntop, strport); 185257429Smarkm 185357429Smarkm /* Bind the socket to the address. */ 185457429Smarkm if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 185557429Smarkm /* address can be in use ipv6 address is already bound */ 185657429Smarkm verbose("bind: %.100s", strerror(errno)); 185757429Smarkm close(sock); 185857429Smarkm continue; 185957429Smarkm } 186057429Smarkm /* Start listening for connections on the socket. */ 186157429Smarkm if (listen(sock, 5) < 0) { 186257429Smarkm error("listen: %.100s", strerror(errno)); 186357429Smarkm close(sock); 186457429Smarkm continue; 186557429Smarkm } 186657429Smarkm /* Allocate a channel number for the socket. */ 186776262Sgreen ch = channel_new("port listener", ctype, sock, sock, -1, 186860573Skris CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 186969587Sgreen 0, xstrdup("port listener"), 1); 187057429Smarkm strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); 187176262Sgreen channels[ch].host_port = port_to_connect; 187276262Sgreen channels[ch].listening_port = listen_port; 187357429Smarkm success = 1; 187457429Smarkm } 187557429Smarkm if (success == 0) 187676262Sgreen error("channel_request_forwarding: cannot listen to port: %d", 187776262Sgreen listen_port); 187857429Smarkm freeaddrinfo(aitop); 187976262Sgreen return success; 188057429Smarkm} 188157429Smarkm 188257429Smarkm/* 188357429Smarkm * Initiate forwarding of connections to port "port" on remote host through 188457429Smarkm * the secure channel to host:port from local side. 188557429Smarkm */ 188657429Smarkm 188760573Skrisvoid 188876262Sgreenchannel_request_remote_forwarding(u_short listen_port, 188976262Sgreen const char *host_to_connect, u_short port_to_connect) 189057429Smarkm{ 189176262Sgreen int payload_len, type, success = 0; 189276262Sgreen 189357429Smarkm /* Record locally that connection to this host/port is permitted. */ 189457429Smarkm if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) 189557429Smarkm fatal("channel_request_remote_forwarding: too many forwards"); 189657429Smarkm 189757429Smarkm /* Send the forward request to the remote side. */ 189860573Skris if (compat20) { 189960573Skris const char *address_to_bind = "0.0.0.0"; 190060573Skris packet_start(SSH2_MSG_GLOBAL_REQUEST); 190160573Skris packet_put_cstring("tcpip-forward"); 190260573Skris packet_put_char(0); /* boolean: want reply */ 190360573Skris packet_put_cstring(address_to_bind); 190460573Skris packet_put_int(listen_port); 190576262Sgreen packet_send(); 190676262Sgreen packet_write_wait(); 190776262Sgreen /* Assume that server accepts the request */ 190876262Sgreen success = 1; 190960573Skris } else { 191060573Skris packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); 191160573Skris packet_put_int(listen_port); 191260573Skris packet_put_cstring(host_to_connect); 191360573Skris packet_put_int(port_to_connect); 191460573Skris packet_send(); 191560573Skris packet_write_wait(); 191676262Sgreen 191776262Sgreen /* Wait for response from the remote side. */ 191876262Sgreen type = packet_read(&payload_len); 191976262Sgreen switch (type) { 192076262Sgreen case SSH_SMSG_SUCCESS: 192176262Sgreen success = 1; 192276262Sgreen break; 192376262Sgreen case SSH_SMSG_FAILURE: 192476262Sgreen log("Warning: Server denied remote port forwarding."); 192576262Sgreen break; 192676262Sgreen default: 192776262Sgreen /* Unknown packet */ 192876262Sgreen packet_disconnect("Protocol error for port forward request:" 192976262Sgreen "received packet type %d.", type); 193076262Sgreen } 193160573Skris } 193276262Sgreen if (success) { 193376262Sgreen permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); 193476262Sgreen permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; 193576262Sgreen permitted_opens[num_permitted_opens].listen_port = listen_port; 193676262Sgreen num_permitted_opens++; 193776262Sgreen } 193857429Smarkm} 193957429Smarkm 194057429Smarkm/* 194157429Smarkm * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates 194257429Smarkm * listening for the port, and sends back a success reply (or disconnect 194357429Smarkm * message if there was an error). This never returns if there was an error. 194457429Smarkm */ 194557429Smarkm 194660573Skrisvoid 194760573Skrischannel_input_port_forward_request(int is_root, int gateway_ports) 194857429Smarkm{ 194957429Smarkm u_short port, host_port; 195057429Smarkm char *hostname; 195157429Smarkm 195257429Smarkm /* Get arguments from the packet. */ 195357429Smarkm port = packet_get_int(); 195457429Smarkm hostname = packet_get_string(NULL); 195557429Smarkm host_port = packet_get_int(); 195657429Smarkm 195757429Smarkm /* 195857429Smarkm * Check that an unprivileged user is not trying to forward a 195957429Smarkm * privileged port. 196057429Smarkm */ 196157429Smarkm if (port < IPPORT_RESERVED && !is_root) 196257429Smarkm packet_disconnect("Requested forwarding of port %d but user is not root.", 196357429Smarkm port); 196476262Sgreen /* Initiate forwarding */ 196560573Skris channel_request_local_forwarding(port, hostname, host_port, gateway_ports); 196657429Smarkm 196757429Smarkm /* Free the argument string. */ 196857429Smarkm xfree(hostname); 196957429Smarkm} 197057429Smarkm 197176262Sgreen/* 197276262Sgreen * Permits opening to any host/port if permitted_opens[] is empty. This is 197376262Sgreen * usually called by the server, because the user could connect to any port 197476262Sgreen * anyway, and the server has no way to know but to trust the client anyway. 197576262Sgreen */ 197676262Sgreenvoid 197776262Sgreenchannel_permit_all_opens() 197876262Sgreen{ 197976262Sgreen if (num_permitted_opens == 0) 198076262Sgreen all_opens_permitted = 1; 198176262Sgreen} 198276262Sgreen 198376262Sgreenvoid 198476262Sgreenchannel_add_permitted_opens(char *host, int port) 198576262Sgreen{ 198676262Sgreen if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) 198776262Sgreen fatal("channel_request_remote_forwarding: too many forwards"); 198876262Sgreen debug("allow port forwarding to host %s port %d", host, port); 198976262Sgreen 199076262Sgreen permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); 199176262Sgreen permitted_opens[num_permitted_opens].port_to_connect = port; 199276262Sgreen num_permitted_opens++; 199376262Sgreen 199476262Sgreen all_opens_permitted = 0; 199576262Sgreen} 199676262Sgreen 199776262Sgreenvoid 199876262Sgreenchannel_clear_permitted_opens(void) 199976262Sgreen{ 200076262Sgreen int i; 200176262Sgreen 200276262Sgreen for (i = 0; i < num_permitted_opens; i++) 200376262Sgreen xfree(permitted_opens[i].host_to_connect); 200476262Sgreen num_permitted_opens = 0; 200576262Sgreen 200676262Sgreen} 200776262Sgreen 200876262Sgreen 200976262Sgreen/* return socket to remote host, port */ 201060573Skrisint 201176262Sgreenconnect_to(const char *host, u_short port) 201260573Skris{ 201360573Skris struct addrinfo hints, *ai, *aitop; 201460573Skris char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 201560573Skris int gaierr; 201660573Skris int sock = -1; 201760573Skris 201860573Skris memset(&hints, 0, sizeof(hints)); 201960573Skris hints.ai_family = IPv4or6; 202060573Skris hints.ai_socktype = SOCK_STREAM; 202176262Sgreen snprintf(strport, sizeof strport, "%d", port); 202260573Skris if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { 202376262Sgreen error("connect_to %.100s: unknown host (%s)", host, 202476262Sgreen gai_strerror(gaierr)); 202560573Skris return -1; 202660573Skris } 202760573Skris for (ai = aitop; ai; ai = ai->ai_next) { 202860573Skris if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 202960573Skris continue; 203060573Skris if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), 203160573Skris strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 203276262Sgreen error("connect_to: getnameinfo failed"); 203360573Skris continue; 203460573Skris } 203560573Skris sock = socket(ai->ai_family, SOCK_STREAM, 0); 203660573Skris if (sock < 0) { 203760573Skris error("socket: %.100s", strerror(errno)); 203860573Skris continue; 203960573Skris } 204076262Sgreen if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) 204176262Sgreen fatal("connect_to: F_SETFL: %s", strerror(errno)); 204276262Sgreen if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && 204376262Sgreen errno != EINPROGRESS) { 204476262Sgreen error("connect_to %.100s port %s: %.100s", ntop, strport, 204560573Skris strerror(errno)); 204660573Skris close(sock); 204776262Sgreen continue; /* fail -- try next */ 204860573Skris } 204960573Skris break; /* success */ 205060573Skris 205160573Skris } 205260573Skris freeaddrinfo(aitop); 205360573Skris if (!ai) { 205476262Sgreen error("connect_to %.100s port %d: failed.", host, port); 205560573Skris return -1; 205660573Skris } 205760573Skris /* success */ 205860573Skris return sock; 205960573Skris} 206076262Sgreen 206176262Sgreenint 206276262Sgreenchannel_connect_by_listen_adress(u_short listen_port) 206376262Sgreen{ 206476262Sgreen int i; 206576262Sgreen 206676262Sgreen for (i = 0; i < num_permitted_opens; i++) 206776262Sgreen if (permitted_opens[i].listen_port == listen_port) 206876262Sgreen return connect_to( 206976262Sgreen permitted_opens[i].host_to_connect, 207076262Sgreen permitted_opens[i].port_to_connect); 207176262Sgreen error("WARNING: Server requests forwarding for unknown listen_port %d", 207276262Sgreen listen_port); 207376262Sgreen return -1; 207476262Sgreen} 207576262Sgreen 207676262Sgreen/* Check if connecting to that port is permitted and connect. */ 207776262Sgreenint 207876262Sgreenchannel_connect_to(const char *host, u_short port) 207976262Sgreen{ 208076262Sgreen int i, permit; 208176262Sgreen 208276262Sgreen permit = all_opens_permitted; 208376262Sgreen if (!permit) { 208476262Sgreen for (i = 0; i < num_permitted_opens; i++) 208576262Sgreen if (permitted_opens[i].port_to_connect == port && 208676262Sgreen strcmp(permitted_opens[i].host_to_connect, host) == 0) 208776262Sgreen permit = 1; 208876262Sgreen 208976262Sgreen } 209076262Sgreen if (!permit) { 209176262Sgreen log("Received request to connect to host %.100s port %d, " 209276262Sgreen "but the request was denied.", host, port); 209376262Sgreen return -1; 209476262Sgreen } 209576262Sgreen return connect_to(host, port); 209676262Sgreen} 209776262Sgreen 209857429Smarkm/* 209957429Smarkm * This is called after receiving PORT_OPEN message. This attempts to 210057429Smarkm * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION 210157429Smarkm * or CHANNEL_OPEN_FAILURE. 210257429Smarkm */ 210357429Smarkm 210460573Skrisvoid 210569587Sgreenchannel_input_port_open(int type, int plen, void *ctxt) 210657429Smarkm{ 210757429Smarkm u_short host_port; 210857429Smarkm char *host, *originator_string; 210976262Sgreen int remote_channel, sock = -1, newch; 211057429Smarkm 211157429Smarkm remote_channel = packet_get_int(); 211276262Sgreen host = packet_get_string(NULL); 211357429Smarkm host_port = packet_get_int(); 211457429Smarkm 211557429Smarkm if (have_hostname_in_open) { 211676262Sgreen originator_string = packet_get_string(NULL); 211757429Smarkm } else { 211857429Smarkm originator_string = xstrdup("unknown (remote did not supply name)"); 211957429Smarkm } 212076262Sgreen packet_done(); 212176262Sgreen sock = channel_connect_to(host, host_port); 212276262Sgreen if (sock != -1) { 212376262Sgreen newch = channel_allocate(SSH_CHANNEL_CONNECTING, 212476262Sgreen sock, originator_string); 212560573Skris channels[newch].remote_id = remote_channel; 212657429Smarkm 212776262Sgreen /*XXX delay answer? */ 212860573Skris packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 212960573Skris packet_put_int(remote_channel); 213060573Skris packet_put_int(newch); 213160573Skris packet_send(); 213260573Skris } else { 213360573Skris packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 213460573Skris packet_put_int(remote_channel); 213560573Skris packet_send(); 213657429Smarkm } 213757429Smarkm xfree(host); 213857429Smarkm} 213957429Smarkm 214057429Smarkm/* 214157429Smarkm * Creates an internet domain socket for listening for X11 connections. 214257429Smarkm * Returns a suitable value for the DISPLAY variable, or NULL if an error 214357429Smarkm * occurs. 214457429Smarkm */ 214557429Smarkm 214657429Smarkm#define NUM_SOCKS 10 214757429Smarkm 214857429Smarkmchar * 214957429Smarkmx11_create_display_inet(int screen_number, int x11_display_offset) 215057429Smarkm{ 215157429Smarkm int display_number, sock; 215257429Smarkm u_short port; 215357429Smarkm struct addrinfo hints, *ai, *aitop; 215457429Smarkm char strport[NI_MAXSERV]; 215557429Smarkm int gaierr, n, num_socks = 0, socks[NUM_SOCKS]; 215657429Smarkm char display[512]; 215757429Smarkm char hostname[MAXHOSTNAMELEN]; 215857429Smarkm 215957429Smarkm for (display_number = x11_display_offset; 216057429Smarkm display_number < MAX_DISPLAYS; 216157429Smarkm display_number++) { 216257429Smarkm port = 6000 + display_number; 216357429Smarkm memset(&hints, 0, sizeof(hints)); 216457429Smarkm hints.ai_family = IPv4or6; 216557429Smarkm hints.ai_flags = AI_PASSIVE; /* XXX loopback only ? */ 216657429Smarkm hints.ai_socktype = SOCK_STREAM; 216757429Smarkm snprintf(strport, sizeof strport, "%d", port); 216857429Smarkm if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) { 216957429Smarkm error("getaddrinfo: %.100s", gai_strerror(gaierr)); 217057429Smarkm return NULL; 217157429Smarkm } 217257429Smarkm for (ai = aitop; ai; ai = ai->ai_next) { 217357429Smarkm if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 217457429Smarkm continue; 217557429Smarkm sock = socket(ai->ai_family, SOCK_STREAM, 0); 217657429Smarkm if (sock < 0) { 217757429Smarkm error("socket: %.100s", strerror(errno)); 217857429Smarkm return NULL; 217957429Smarkm } 218057429Smarkm if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 218157429Smarkm debug("bind port %d: %.100s", port, strerror(errno)); 218257429Smarkm shutdown(sock, SHUT_RDWR); 218357429Smarkm close(sock); 218457429Smarkm for (n = 0; n < num_socks; n++) { 218557429Smarkm shutdown(socks[n], SHUT_RDWR); 218657429Smarkm close(socks[n]); 218757429Smarkm } 218857429Smarkm num_socks = 0; 218957429Smarkm break; 219057429Smarkm } 219157429Smarkm socks[num_socks++] = sock; 219257429Smarkm if (num_socks == NUM_SOCKS) 219357429Smarkm break; 219457429Smarkm } 219576262Sgreen freeaddrinfo(aitop); 219657429Smarkm if (num_socks > 0) 219757429Smarkm break; 219857429Smarkm } 219957429Smarkm if (display_number >= MAX_DISPLAYS) { 220057429Smarkm error("Failed to allocate internet-domain X11 display socket."); 220157429Smarkm return NULL; 220257429Smarkm } 220357429Smarkm /* Start listening for connections on the socket. */ 220457429Smarkm for (n = 0; n < num_socks; n++) { 220557429Smarkm sock = socks[n]; 220657429Smarkm if (listen(sock, 5) < 0) { 220757429Smarkm error("listen: %.100s", strerror(errno)); 220857429Smarkm shutdown(sock, SHUT_RDWR); 220957429Smarkm close(sock); 221057429Smarkm return NULL; 221157429Smarkm } 221257429Smarkm } 221357429Smarkm 221457429Smarkm /* Set up a suitable value for the DISPLAY variable. */ 221557429Smarkm if (gethostname(hostname, sizeof(hostname)) < 0) 221657429Smarkm fatal("gethostname: %.100s", strerror(errno)); 221757429Smarkm snprintf(display, sizeof display, "%.400s:%d.%d", hostname, 221857429Smarkm display_number, screen_number); 221957429Smarkm 222057429Smarkm /* Allocate a channel for each socket. */ 222157429Smarkm for (n = 0; n < num_socks; n++) { 222257429Smarkm sock = socks[n]; 222360573Skris (void) channel_new("x11 listener", 222460573Skris SSH_CHANNEL_X11_LISTENER, sock, sock, -1, 222560573Skris CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 222669587Sgreen 0, xstrdup("X11 inet listener"), 1); 222757429Smarkm } 222857429Smarkm 222957429Smarkm /* Return a suitable value for the DISPLAY environment variable. */ 223057429Smarkm return xstrdup(display); 223157429Smarkm} 223257429Smarkm 223357429Smarkm#ifndef X_UNIX_PATH 223457429Smarkm#define X_UNIX_PATH "/tmp/.X11-unix/X" 223557429Smarkm#endif 223657429Smarkm 223757429Smarkmstatic 223857429Smarkmint 223976262Sgreenconnect_local_xsocket(u_int dnr) 224057429Smarkm{ 224157429Smarkm static const char *const x_sockets[] = { 224257429Smarkm X_UNIX_PATH "%u", 224357429Smarkm "/var/X/.X11-unix/X" "%u", 224457429Smarkm "/usr/spool/sockets/X11/" "%u", 224557429Smarkm NULL 224657429Smarkm }; 224757429Smarkm int sock; 224857429Smarkm struct sockaddr_un addr; 224957429Smarkm const char *const * path; 225057429Smarkm 225157429Smarkm for (path = x_sockets; *path; ++path) { 225257429Smarkm sock = socket(AF_UNIX, SOCK_STREAM, 0); 225357429Smarkm if (sock < 0) 225457429Smarkm error("socket: %.100s", strerror(errno)); 225557429Smarkm memset(&addr, 0, sizeof(addr)); 225657429Smarkm addr.sun_family = AF_UNIX; 225757429Smarkm snprintf(addr.sun_path, sizeof addr.sun_path, *path, dnr); 225857429Smarkm if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0) 225957429Smarkm return sock; 226057429Smarkm close(sock); 226157429Smarkm } 226257429Smarkm error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); 226357429Smarkm return -1; 226457429Smarkm} 226557429Smarkm 226660573Skrisint 226760573Skrisx11_connect_display(void) 226857429Smarkm{ 226960573Skris int display_number, sock = 0; 227057429Smarkm const char *display; 227160573Skris char buf[1024], *cp; 227257429Smarkm struct addrinfo hints, *ai, *aitop; 227357429Smarkm char strport[NI_MAXSERV]; 227457429Smarkm int gaierr; 227557429Smarkm 227657429Smarkm /* Try to open a socket for the local X server. */ 227757429Smarkm display = getenv("DISPLAY"); 227857429Smarkm if (!display) { 227957429Smarkm error("DISPLAY not set."); 228060573Skris return -1; 228157429Smarkm } 228257429Smarkm /* 228357429Smarkm * Now we decode the value of the DISPLAY variable and make a 228457429Smarkm * connection to the real X server. 228557429Smarkm */ 228657429Smarkm 228757429Smarkm /* 228857429Smarkm * Check if it is a unix domain socket. Unix domain displays are in 228957429Smarkm * one of the following formats: unix:d[.s], :d[.s], ::d[.s] 229057429Smarkm */ 229157429Smarkm if (strncmp(display, "unix:", 5) == 0 || 229257429Smarkm display[0] == ':') { 229357429Smarkm /* Connect to the unix domain socket. */ 229457429Smarkm if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) { 229557429Smarkm error("Could not parse display number from DISPLAY: %.100s", 229657429Smarkm display); 229760573Skris return -1; 229857429Smarkm } 229957429Smarkm /* Create a socket. */ 230057429Smarkm sock = connect_local_xsocket(display_number); 230157429Smarkm if (sock < 0) 230260573Skris return -1; 230357429Smarkm 230457429Smarkm /* OK, we now have a connection to the display. */ 230560573Skris return sock; 230657429Smarkm } 230757429Smarkm /* 230857429Smarkm * Connect to an inet socket. The DISPLAY value is supposedly 230957429Smarkm * hostname:d[.s], where hostname may also be numeric IP address. 231057429Smarkm */ 231157429Smarkm strncpy(buf, display, sizeof(buf)); 231257429Smarkm buf[sizeof(buf) - 1] = 0; 231357429Smarkm cp = strchr(buf, ':'); 231457429Smarkm if (!cp) { 231557429Smarkm error("Could not find ':' in DISPLAY: %.100s", display); 231660573Skris return -1; 231757429Smarkm } 231857429Smarkm *cp = 0; 231957429Smarkm /* buf now contains the host name. But first we parse the display number. */ 232057429Smarkm if (sscanf(cp + 1, "%d", &display_number) != 1) { 232157429Smarkm error("Could not parse display number from DISPLAY: %.100s", 232257429Smarkm display); 232360573Skris return -1; 232457429Smarkm } 232557429Smarkm 232657429Smarkm /* Look up the host address */ 232757429Smarkm memset(&hints, 0, sizeof(hints)); 232857429Smarkm hints.ai_family = IPv4or6; 232957429Smarkm hints.ai_socktype = SOCK_STREAM; 233057429Smarkm snprintf(strport, sizeof strport, "%d", 6000 + display_number); 233157429Smarkm if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { 233257429Smarkm error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr)); 233360573Skris return -1; 233457429Smarkm } 233557429Smarkm for (ai = aitop; ai; ai = ai->ai_next) { 233657429Smarkm /* Create a socket. */ 233757429Smarkm sock = socket(ai->ai_family, SOCK_STREAM, 0); 233857429Smarkm if (sock < 0) { 233957429Smarkm debug("socket: %.100s", strerror(errno)); 234060573Skris continue; 234160573Skris } 234260573Skris /* Connect it to the display. */ 234360573Skris if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 234460573Skris debug("connect %.100s port %d: %.100s", buf, 234560573Skris 6000 + display_number, strerror(errno)); 234660573Skris close(sock); 234760573Skris continue; 234860573Skris } 234960573Skris /* Success */ 235060573Skris break; 235157429Smarkm } 235257429Smarkm freeaddrinfo(aitop); 235357429Smarkm if (!ai) { 235460573Skris error("connect %.100s port %d: %.100s", buf, 6000 + display_number, 235557429Smarkm strerror(errno)); 235660573Skris return -1; 235757429Smarkm } 235860573Skris return sock; 235960573Skris} 236057429Smarkm 236160573Skris/* 236260573Skris * This is called when SSH_SMSG_X11_OPEN is received. The packet contains 236360573Skris * the remote channel number. We should do whatever we want, and respond 236460573Skris * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. 236560573Skris */ 236657429Smarkm 236760573Skrisvoid 236869587Sgreenx11_input_open(int type, int plen, void *ctxt) 236960573Skris{ 237060573Skris int remote_channel, sock = 0, newch; 237160573Skris char *remote_host; 237276262Sgreen u_int remote_len; 237357429Smarkm 237460573Skris /* Get remote channel number. */ 237560573Skris remote_channel = packet_get_int(); 237657429Smarkm 237760573Skris /* Get remote originator name. */ 237860573Skris if (have_hostname_in_open) { 237960573Skris remote_host = packet_get_string(&remote_len); 238060573Skris remote_len += 4; 238160573Skris } else { 238260573Skris remote_host = xstrdup("unknown (remote did not supply name)"); 238360573Skris remote_len = 0; 238460573Skris } 238560573Skris 238660573Skris debug("Received X11 open request."); 238760573Skris packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN); 238860573Skris 238960573Skris /* Obtain a connection to the real X display. */ 239060573Skris sock = x11_connect_display(); 239160573Skris if (sock == -1) { 239260573Skris /* Send refusal to the remote host. */ 239360573Skris packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 239460573Skris packet_put_int(remote_channel); 239560573Skris packet_send(); 239660573Skris } else { 239760573Skris /* Allocate a channel for this connection. */ 239860573Skris newch = channel_allocate( 239960573Skris (x11_saved_proto == NULL) ? 240060573Skris SSH_CHANNEL_OPEN : SSH_CHANNEL_X11_OPEN, 240160573Skris sock, remote_host); 240260573Skris channels[newch].remote_id = remote_channel; 240360573Skris 240460573Skris /* Send a confirmation to the remote host. */ 240560573Skris packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 240660573Skris packet_put_int(remote_channel); 240760573Skris packet_put_int(newch); 240860573Skris packet_send(); 240960573Skris } 241057429Smarkm} 241157429Smarkm 241269587Sgreen/* dummy protocol handler that denies SSH-1 requests (agent/x11) */ 241369587Sgreenvoid 241469587Sgreendeny_input_open(int type, int plen, void *ctxt) 241569587Sgreen{ 241669587Sgreen int rchan = packet_get_int(); 241769587Sgreen switch(type){ 241869587Sgreen case SSH_SMSG_AGENT_OPEN: 241969587Sgreen error("Warning: ssh server tried agent forwarding."); 242069587Sgreen break; 242169587Sgreen case SSH_SMSG_X11_OPEN: 242269587Sgreen error("Warning: ssh server tried X11 forwarding."); 242369587Sgreen break; 242469587Sgreen default: 242569587Sgreen error("deny_input_open: type %d plen %d", type, plen); 242669587Sgreen break; 242769587Sgreen } 242869587Sgreen error("Warning: this is probably a break in attempt by a malicious server."); 242969587Sgreen packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 243069587Sgreen packet_put_int(rchan); 243169587Sgreen packet_send(); 243269587Sgreen} 243369587Sgreen 243457429Smarkm/* 243557429Smarkm * Requests forwarding of X11 connections, generates fake authentication 243657429Smarkm * data, and enables authentication spoofing. 243757429Smarkm */ 243857429Smarkm 243960573Skrisvoid 244060573Skrisx11_request_forwarding_with_spoofing(int client_session_id, 244160573Skris const char *proto, const char *data) 244257429Smarkm{ 244376262Sgreen u_int data_len = (u_int) strlen(data) / 2; 244476262Sgreen u_int i, value, len; 244557429Smarkm char *new_data; 244657429Smarkm int screen_number; 244757429Smarkm const char *cp; 244857429Smarkm u_int32_t rand = 0; 244957429Smarkm 245057429Smarkm cp = getenv("DISPLAY"); 245157429Smarkm if (cp) 245257429Smarkm cp = strchr(cp, ':'); 245357429Smarkm if (cp) 245457429Smarkm cp = strchr(cp, '.'); 245557429Smarkm if (cp) 245657429Smarkm screen_number = atoi(cp + 1); 245757429Smarkm else 245857429Smarkm screen_number = 0; 245957429Smarkm 246057429Smarkm /* Save protocol name. */ 246157429Smarkm x11_saved_proto = xstrdup(proto); 246257429Smarkm 246357429Smarkm /* 246457429Smarkm * Extract real authentication data and generate fake data of the 246557429Smarkm * same length. 246657429Smarkm */ 246757429Smarkm x11_saved_data = xmalloc(data_len); 246857429Smarkm x11_fake_data = xmalloc(data_len); 246957429Smarkm for (i = 0; i < data_len; i++) { 247057429Smarkm if (sscanf(data + 2 * i, "%2x", &value) != 1) 247157429Smarkm fatal("x11_request_forwarding: bad authentication data: %.100s", data); 247257429Smarkm if (i % 4 == 0) 247357429Smarkm rand = arc4random(); 247457429Smarkm x11_saved_data[i] = value; 247557429Smarkm x11_fake_data[i] = rand & 0xff; 247657429Smarkm rand >>= 8; 247757429Smarkm } 247857429Smarkm x11_saved_data_len = data_len; 247957429Smarkm x11_fake_data_len = data_len; 248057429Smarkm 248157429Smarkm /* Convert the fake data into hex. */ 248276262Sgreen len = 2 * data_len + 1; 248376262Sgreen new_data = xmalloc(len); 248457429Smarkm for (i = 0; i < data_len; i++) 248576262Sgreen snprintf(new_data + 2 * i, len - 2 * i, 248676262Sgreen "%02x", (u_char) x11_fake_data[i]); 248757429Smarkm 248857429Smarkm /* Send the request packet. */ 248960573Skris if (compat20) { 249060573Skris channel_request_start(client_session_id, "x11-req", 0); 249160573Skris packet_put_char(0); /* XXX bool single connection */ 249260573Skris } else { 249360573Skris packet_start(SSH_CMSG_X11_REQUEST_FORWARDING); 249460573Skris } 249560573Skris packet_put_cstring(proto); 249660573Skris packet_put_cstring(new_data); 249757429Smarkm packet_put_int(screen_number); 249857429Smarkm packet_send(); 249957429Smarkm packet_write_wait(); 250057429Smarkm xfree(new_data); 250157429Smarkm} 250257429Smarkm 250357429Smarkm/* Sends a message to the server to request authentication fd forwarding. */ 250457429Smarkm 250560573Skrisvoid 250657429Smarkmauth_request_forwarding() 250757429Smarkm{ 250857429Smarkm packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); 250957429Smarkm packet_send(); 251057429Smarkm packet_write_wait(); 251157429Smarkm} 251257429Smarkm 251357429Smarkm/* 251457429Smarkm * Returns the name of the forwarded authentication socket. Returns NULL if 251557429Smarkm * there is no forwarded authentication socket. The returned value points to 251657429Smarkm * a static buffer. 251757429Smarkm */ 251857429Smarkm 251957429Smarkmchar * 252057429Smarkmauth_get_socket_name() 252157429Smarkm{ 252257429Smarkm return channel_forwarded_auth_socket_name; 252357429Smarkm} 252457429Smarkm 252557429Smarkm/* removes the agent forwarding socket */ 252657429Smarkm 252760573Skrisvoid 252877925Sgreenauth_sock_cleanup_proc(void *_pw) 252957429Smarkm{ 253077925Sgreen struct passwd *pw = _pw; 253177925Sgreen 253277925Sgreen if (channel_forwarded_auth_socket_name) { 253377925Sgreen temporarily_use_uid(pw); 253477925Sgreen unlink(channel_forwarded_auth_socket_name); 253577925Sgreen rmdir(channel_forwarded_auth_socket_dir); 253677925Sgreen channel_forwarded_auth_socket_name = NULL; 253777925Sgreen restore_uid(); 253877925Sgreen } 253957429Smarkm} 254057429Smarkm 254157429Smarkm/* 254261199Skris * This is called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server. 254357429Smarkm * This starts forwarding authentication requests. 254457429Smarkm */ 254557429Smarkm 254661199Skrisint 254757429Smarkmauth_input_request_forwarding(struct passwd * pw) 254857429Smarkm{ 254957429Smarkm int sock, newch; 255057429Smarkm struct sockaddr_un sunaddr; 255157429Smarkm 255257429Smarkm if (auth_get_socket_name() != NULL) 255357429Smarkm fatal("Protocol error: authentication forwarding requested twice."); 255457429Smarkm 255557429Smarkm /* Temporarily drop privileged uid for mkdir/bind. */ 255676262Sgreen temporarily_use_uid(pw); 255757429Smarkm 255857429Smarkm /* Allocate a buffer for the socket name, and format the name. */ 255957429Smarkm channel_forwarded_auth_socket_name = xmalloc(MAX_SOCKET_NAME); 256057429Smarkm channel_forwarded_auth_socket_dir = xmalloc(MAX_SOCKET_NAME); 256157429Smarkm strlcpy(channel_forwarded_auth_socket_dir, "/tmp/ssh-XXXXXXXX", MAX_SOCKET_NAME); 256257429Smarkm 256357429Smarkm /* Create private directory for socket */ 256461199Skris if (mkdtemp(channel_forwarded_auth_socket_dir) == NULL) { 256561199Skris packet_send_debug("Agent forwarding disabled: mkdtemp() failed: %.100s", 256661199Skris strerror(errno)); 256761199Skris restore_uid(); 256861199Skris xfree(channel_forwarded_auth_socket_name); 256961199Skris xfree(channel_forwarded_auth_socket_dir); 257061199Skris channel_forwarded_auth_socket_name = NULL; 257161199Skris channel_forwarded_auth_socket_dir = NULL; 257261199Skris return 0; 257361199Skris } 257457429Smarkm snprintf(channel_forwarded_auth_socket_name, MAX_SOCKET_NAME, "%s/agent.%d", 257557429Smarkm channel_forwarded_auth_socket_dir, (int) getpid()); 257657429Smarkm 257777925Sgreen /* delete agent socket on fatal() */ 257877925Sgreen fatal_add_cleanup(auth_sock_cleanup_proc, pw); 257977925Sgreen 258057429Smarkm /* Create the socket. */ 258157429Smarkm sock = socket(AF_UNIX, SOCK_STREAM, 0); 258257429Smarkm if (sock < 0) 258357429Smarkm packet_disconnect("socket: %.100s", strerror(errno)); 258457429Smarkm 258557429Smarkm /* Bind it to the name. */ 258657429Smarkm memset(&sunaddr, 0, sizeof(sunaddr)); 258757429Smarkm sunaddr.sun_family = AF_UNIX; 258857429Smarkm strncpy(sunaddr.sun_path, channel_forwarded_auth_socket_name, 258957429Smarkm sizeof(sunaddr.sun_path)); 259057429Smarkm 259157429Smarkm if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) 259257429Smarkm packet_disconnect("bind: %.100s", strerror(errno)); 259357429Smarkm 259457429Smarkm /* Restore the privileged uid. */ 259557429Smarkm restore_uid(); 259657429Smarkm 259757429Smarkm /* Start listening on the socket. */ 259857429Smarkm if (listen(sock, 5) < 0) 259957429Smarkm packet_disconnect("listen: %.100s", strerror(errno)); 260057429Smarkm 260157429Smarkm /* Allocate a channel for the authentication agent socket. */ 260276262Sgreen newch = channel_new("auth socket", 260376262Sgreen SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, 260476262Sgreen CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 260576262Sgreen 0, xstrdup("auth socket"), 1); 260676262Sgreen 260757429Smarkm strlcpy(channels[newch].path, channel_forwarded_auth_socket_name, 260857429Smarkm sizeof(channels[newch].path)); 260961199Skris return 1; 261057429Smarkm} 261157429Smarkm 261257429Smarkm/* This is called to process an SSH_SMSG_AGENT_OPEN message. */ 261357429Smarkm 261460573Skrisvoid 261569587Sgreenauth_input_open_request(int type, int plen, void *ctxt) 261657429Smarkm{ 261757429Smarkm int remch, sock, newch; 261857429Smarkm char *dummyname; 261957429Smarkm 262060573Skris packet_integrity_check(plen, 4, type); 262160573Skris 262257429Smarkm /* Read the remote channel number from the message. */ 262357429Smarkm remch = packet_get_int(); 262457429Smarkm 262557429Smarkm /* 262657429Smarkm * Get a connection to the local authentication agent (this may again 262757429Smarkm * get forwarded). 262857429Smarkm */ 262957429Smarkm sock = ssh_get_authentication_socket(); 263057429Smarkm 263157429Smarkm /* 263257429Smarkm * If we could not connect the agent, send an error message back to 263357429Smarkm * the server. This should never happen unless the agent dies, 263457429Smarkm * because authentication forwarding is only enabled if we have an 263557429Smarkm * agent. 263657429Smarkm */ 263757429Smarkm if (sock < 0) { 263857429Smarkm packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 263957429Smarkm packet_put_int(remch); 264057429Smarkm packet_send(); 264157429Smarkm return; 264257429Smarkm } 264357429Smarkm debug("Forwarding authentication connection."); 264457429Smarkm 264557429Smarkm /* 264657429Smarkm * Dummy host name. This will be freed when the channel is freed; it 264757429Smarkm * will still be valid in the packet_put_string below since the 264857429Smarkm * channel cannot yet be freed at that point. 264957429Smarkm */ 265057429Smarkm dummyname = xstrdup("authentication agent connection"); 265157429Smarkm 265257429Smarkm newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname); 265357429Smarkm channels[newch].remote_id = remch; 265457429Smarkm 265557429Smarkm /* Send a confirmation to the remote host. */ 265657429Smarkm packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 265757429Smarkm packet_put_int(remch); 265857429Smarkm packet_put_int(newch); 265957429Smarkm packet_send(); 266057429Smarkm} 266160573Skris 266260573Skrisvoid 266360573Skrischannel_start_open(int id) 266460573Skris{ 266560573Skris Channel *c = channel_lookup(id); 266660573Skris if (c == NULL) { 266760573Skris log("channel_open: %d: bad id", id); 266860573Skris return; 266960573Skris } 267060573Skris debug("send channel open %d", id); 267160573Skris packet_start(SSH2_MSG_CHANNEL_OPEN); 267260573Skris packet_put_cstring(c->ctype); 267360573Skris packet_put_int(c->self); 267460573Skris packet_put_int(c->local_window); 267560573Skris packet_put_int(c->local_maxpacket); 267660573Skris} 267760573Skrisvoid 267860573Skrischannel_open(int id) 267960573Skris{ 268060573Skris /* XXX REMOVE ME */ 268160573Skris channel_start_open(id); 268260573Skris packet_send(); 268360573Skris} 268460573Skrisvoid 268560573Skrischannel_request(int id, char *service, int wantconfirm) 268660573Skris{ 268760573Skris channel_request_start(id, service, wantconfirm); 268860573Skris packet_send(); 268960573Skris debug("channel request %d: %s", id, service) ; 269060573Skris} 269160573Skrisvoid 269260573Skrischannel_request_start(int id, char *service, int wantconfirm) 269360573Skris{ 269460573Skris Channel *c = channel_lookup(id); 269560573Skris if (c == NULL) { 269660573Skris log("channel_request: %d: bad id", id); 269760573Skris return; 269860573Skris } 269960573Skris packet_start(SSH2_MSG_CHANNEL_REQUEST); 270060573Skris packet_put_int(c->remote_id); 270160573Skris packet_put_cstring(service); 270260573Skris packet_put_char(wantconfirm); 270360573Skris} 270460573Skrisvoid 270560573Skrischannel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg) 270660573Skris{ 270760573Skris Channel *c = channel_lookup(id); 270860573Skris if (c == NULL) { 270960573Skris log("channel_register_callback: %d: bad id", id); 271060573Skris return; 271160573Skris } 271260573Skris c->cb_event = mtype; 271360573Skris c->cb_fn = fn; 271460573Skris c->cb_arg = arg; 271560573Skris} 271660573Skrisvoid 271760573Skrischannel_register_cleanup(int id, channel_callback_fn *fn) 271860573Skris{ 271960573Skris Channel *c = channel_lookup(id); 272060573Skris if (c == NULL) { 272160573Skris log("channel_register_cleanup: %d: bad id", id); 272260573Skris return; 272360573Skris } 272460573Skris c->dettach_user = fn; 272560573Skris} 272660573Skrisvoid 272760573Skrischannel_cancel_cleanup(int id) 272860573Skris{ 272960573Skris Channel *c = channel_lookup(id); 273060573Skris if (c == NULL) { 273160573Skris log("channel_cancel_cleanup: %d: bad id", id); 273260573Skris return; 273360573Skris } 273460573Skris c->dettach_user = NULL; 273560573Skris} 273676262Sgreenvoid 273765668Skrischannel_register_filter(int id, channel_filter_fn *fn) 273865668Skris{ 273965668Skris Channel *c = channel_lookup(id); 274065668Skris if (c == NULL) { 274165668Skris log("channel_register_filter: %d: bad id", id); 274265668Skris return; 274365668Skris } 274465668Skris c->input_filter = fn; 274565668Skris} 274660573Skris 274760573Skrisvoid 274869587Sgreenchannel_set_fds(int id, int rfd, int wfd, int efd, 274969587Sgreen int extusage, int nonblock) 275060573Skris{ 275160573Skris Channel *c = channel_lookup(id); 275260573Skris if (c == NULL || c->type != SSH_CHANNEL_LARVAL) 275360573Skris fatal("channel_activate for non-larval channel %d.", id); 275469587Sgreen channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); 275560573Skris c->type = SSH_CHANNEL_OPEN; 275660573Skris /* XXX window size? */ 275765668Skris c->local_window = c->local_window_max = c->local_maxpacket * 2; 275860573Skris packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); 275960573Skris packet_put_int(c->remote_id); 276060573Skris packet_put_int(c->local_window); 276160573Skris packet_send(); 276260573Skris} 2763