channel_forward.c 4.71 KB
Newer Older
1
2
3
4
/* channel_forward.h
 *
 * General channel type for forwarding data to an fd
 *
5
 */
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998, 2001 Balzs Scheidler, Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

26
27
28
29
30
31
32
33
#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <assert.h>
#include <errno.h>
#include <string.h>

34
35
36
37
38
39
40
41
42
43
44
45
#include "channel_forward.h"

#include "io.h"
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"

#define GABA_DEFINE
#include "channel_forward.h.x"
#undef GABA_DEFINE

/* NOTE: Adds the socket to the channel's resource list */
46
47
void
init_channel_forward(struct channel_forward *self,
48
		     struct lsh_fd *socket, uint32_t initial_window)
49
50
51
52
53
{
  assert(socket);
  
  init_channel(&self->super);

54
55
  /* The rest of the callbacks are not set up until
   * channel_forward_start_io. */
56
57
58
59
60
61
62

  /* NOTE: We don't need a close handler, as the channel's resource
   * list is taken care of automatically. */
  
  self->super.rec_window_size = initial_window;

  /* FIXME: Make maximum packet size configurable. */
63
  self->super.rec_max_packet = SSH_MAX_PACKET;
64
65
66
  
  self->socket = socket;

67
  remember_resource(self->super.resources, &socket->super);
68
69
70
}

struct channel_forward *
71
make_channel_forward(struct lsh_fd *socket, uint32_t initial_window)
72
73
74
{
  NEW(channel_forward, self);
  init_channel_forward(self, socket, initial_window);
75
  
76
  return self;
77
78
79
80
}

static void
do_channel_forward_receive(struct ssh_channel *c,
81
			   int type, struct lsh_string *data)
82
{
83
  CAST_SUBTYPE(channel_forward, closure, c);
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  
  switch (type)
    {
    case CHANNEL_DATA:
      A_WRITE(&closure->socket->write_buffer->super, data);
      break;
    case CHANNEL_STDERR_DATA:
      werror("Ignoring unexpected stderr data.\n");
      lsh_string_free(data);
      break;
    default:
      fatal("Internal error. do_channel_forward_receive");
    }
}

static void
do_channel_forward_send_adjust(struct ssh_channel *s,
101
		     uint32_t i UNUSED)
102
{
103
  CAST_SUBTYPE(channel_forward, self, s);
104
  
105
  lsh_oop_register_read_fd(self->socket);
106
107
108
109
110
}

static void
do_channel_forward_eof(struct ssh_channel *s)
{
111
  CAST_SUBTYPE(channel_forward, self, s);
112

113
114
115
  /* We won't write any more. io.c should make sure that shutdown is called
   * once the write_buffer is empty. */
  close_fd_write(self->socket);
116
117
118
119
120
121
122
123
124
}


/* NOTE: Because this function is called by
 * do_open_forwarded_tcpip_continuation, the same restrictions apply.
 * I.e we can not assume that the channel is completely initialized
 * (channel_open_continuation has not yet done its work), and we can't
 * send any packets. */
void
125
channel_forward_start_io(struct channel_forward *channel)
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
{
  channel->super.receive = do_channel_forward_receive;
  channel->super.send_adjust = do_channel_forward_send_adjust;
  channel->super.eof = do_channel_forward_eof;
  
  /* Install callbacks on the local socket.
   * NOTE: We don't install any channel_io_exception_handler. */
  io_read_write(channel->socket,
		make_channel_read_data(&channel->super),
		/* FIXME: Make this configurable */
		SSH_MAX_PACKET * 10, /* self->block_size, */
		make_channel_read_close_callback(&channel->super));
  
  /* Flow control */
  channel->socket->write_buffer->report = &channel->super.super;
}

143
144
145
146
147
/* Used by the party requesting tcp forwarding, i.e. when a socket is
 * already open, and we have asked the other end to forward it. Takes
 * a channel as argument, and connects it to the socket. Returns the
 * channel. */

148
149
150
151
152
153
154
155
156
157
158
159
160
161
DEFINE_COMMAND(start_io_command)
     (struct command *s UNUSED,
      struct lsh_object *x,
      struct command_continuation *c,
      struct exception_handler *e UNUSED)
{
  CAST_SUBTYPE(channel_forward, channel, x);

  assert(channel);
  
  channel_forward_start_io(channel);

  COMMAND_RETURN(c, channel);  
}
162

Niels Möller's avatar
Niels Möller committed
163
164
/* FIXME: Arrange so that the forwarded socket is closed if
   EXC_CHANNEL_OPEN is caught. And write some docs. */
165
166
static const struct report_exception_info forward_open_report =
STATIC_REPORT_EXCEPTION_INFO(EXC_ALL, EXC_CHANNEL_OPEN,
Niels Möller's avatar
Niels Möller committed
167
			     "Forwarding failed, could not open channel");
168
169
170

struct catch_report_collect catch_channel_open
= STATIC_CATCH_REPORT(&forward_open_report);