gateway_channel.c 10.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* gateway_channel.c
 *
 * $Id$
 */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 2000 Niels Möller
 *
 * 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
 */

#include "gateway_channel.h"

#include "channel_commands.h"
#include "format.h"
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"

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

#include "gateway_channel.c.x"

/* A pair of gateway_channel objects are chained together so that
 * requests and data received on one of the channels are directed to
 * the other.
 *
 * Chaining happens as follows:
 *
 * 1. First a CHANNEL_OPEN request is received on one connection, and
46
 *    a channel object is created. We refer to this object as the
47
48
49
50
51
52
 *    _originating_ channel.
 *
 * 2. Next, we send a similar CHANNEL_OPEN request on some other
 *    connection, and create a channel object referred to as the
 *    _target_ channel.
 *
53
 * 3. When we receive a reply to the CHANNEL_OPEN request sent in (2),
54
55
56
57
58
59
60
61
62
63
64
65
66
67
 *    we chain the two channel objects together, and reply to the
 *    CHANNEL_OPEN request we received in (1). */

/* FIXME: A gateway may want to handle unknown types of channel data. */
static void
do_receive(struct ssh_channel *c,
	   int type,
	   struct lsh_string *data)
{
  CAST(gateway_channel, channel, c);
  
  switch(type)
    {
    case CHANNEL_DATA:
68
      C_WRITE(channel->chain->super.connection,
69
70
71
	      channel_transmit_data(&channel->chain->super, data));
      break;
    case CHANNEL_STDERR_DATA:
72
      C_WRITE(channel->chain->super.connection,
73
74
75
76
77
78
79
80
81
82
83
84
85
	      channel_transmit_extended(&channel->chain->super, CHANNEL_STDERR_DATA, data));
      break;
    default:
      fatal("Internal error!\n");
    }
}

/* We may send more data */
static void
do_send_adjust(struct ssh_channel *s,
	       UINT32 i)
{
  CAST(gateway_channel, self, s);
86
87
  if (i)
    FLOW_CONTROL_REPORT(&self->chain->super.super, i);
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
}

static void
do_eof(struct ssh_channel *c)
{
  CAST(gateway_channel, channel, c);
  channel_eof(&channel->chain->super);
}

static void
do_close(struct ssh_channel *c)
{
  CAST(gateway_channel, channel, c);  
  channel_close(&channel->chain->super);
}

static void
gateway_init_io(struct gateway_channel *channel)
{
  channel->super.send_adjust = do_send_adjust;  
  channel->super.receive = do_receive;
  channel->super.eof = do_eof;
  channel->super.close = do_close;
}

113
114
/* NOTE: We don't initialize the rec_window_size and rec_max_packet
 * fields here.
115
116
 *
 * The origin's rec_window_size and rec_max_packet are filled in
117
 * later, by do_gateway_channel_open_continuation. The target's
118
119
120
121
122
123
124
125
126
127
 * rec_window_size, on the other hand, must be filled in manually. */

struct gateway_channel *
make_gateway_channel(struct alist *request_types)
{
  NEW(gateway_channel, self);
  init_channel(&self->super);
  
  self->super.request_types = request_types;
  
128
129
130
131
  /* Never initiate close; let each end point decide when it is time
   * to send SSH_MSG_CHANNEL_CLOSE. */
  self->super.flags &= ~CHANNEL_CLOSE_AT_EOF;

132
133
134
135
136
137
138
139
140
141
142
143
  return self;
}


/* Command to request a channel open. Typically used after we have
 * received a CHANNEL_OPEN request from the originating end, to create
 * a channel to the target. */
/* GABA:
   (class
     (name gateway_channel_open_command)
     (super channel_open_command)
     (vars
144
145
146
147
       ; The channel type is represented as a string, as
       ; we should be able to forward unknown channel
       ; types (i.e. types not listen in atoms.in).
       (type string)
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
       (rec_window_size . UINT32)
       (rec_max_packet . UINT32)
       (requests object alist)
       (args string)))
*/

static struct ssh_channel *
do_gateway_channel_open(struct channel_open_command *c,
			struct ssh_connection *connection,
			UINT32 local_channel_number,
			struct lsh_string **request)
{
  CAST(gateway_channel_open_command, closure, c);
  
  struct gateway_channel *target
    = make_gateway_channel(closure->requests);

  target->super.rec_window_size = closure->rec_window_size;
166
167
168
169
170

  /* Don't advertise a larger rec_max_packet than we're willing to handle. */
  target->super.rec_max_packet
    = MIN(closure->rec_max_packet, SSH_MAX_PACKET);
  
171
  target->super.connection = connection;
172

173
174
175
  *request = format_channel_open_s(closure->type,
				   local_channel_number,
				   &target->super,
176
				   closure->args);
177
  
178
179
180
181
  return &target->super;
}

struct command *
182
make_gateway_channel_open_command(struct channel_open_info *info,
183
184
185
186
187
188
189
				  struct lsh_string *args,
				  struct alist *requests)
{
  NEW(gateway_channel_open_command, self);
  
  self->super.new_channel = do_gateway_channel_open;
  self->super.super.call = do_channel_open_command;
190
191

  self->type = ssh_format("%ls", info->type_length,
192
			  info->type_data);
193
194
195

  self->rec_window_size = info->send_window_size;
  self->rec_max_packet = info->send_max_packet;
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  self->requests = requests;
  self->args = args;

  return &self->super.super;
}


/* General channel requests */

/* GABA:
   (class
     (name general_channel_request_command)
     (super channel_request_command)
     (vars
       ; NOTE: This is only used once.
       (request string)))
*/

static struct lsh_string *
do_format_channel_general(struct channel_request_command *s,
			  struct ssh_channel *ch UNUSED,
			  struct command_continuation **c UNUSED)
{
  CAST(general_channel_request_command, self, s);

  struct lsh_string *r = self->request;
  self->request = NULL;
  return r;
}

static struct command *
make_general_channel_request_command(struct lsh_string *request)
{
  NEW(general_channel_request_command, self);
  self->super.super.call = do_channel_request_command;
  self->super.format_request = do_format_channel_general;
  self->request = request;
  return &self->super.super;
}

static void 
do_gateway_channel_request(struct channel_request *s UNUSED,
			   struct ssh_channel *ch,
239
			   struct channel_request_info *info,
240
241
242
243
244
			   struct simple_buffer *args,
			   struct command_continuation *c,
			   struct exception_handler *e)
{
  CAST(gateway_channel, channel, ch);
245
246
  UINT32 args_length;
  const UINT8 *args_data;
247
248
  struct command *command;
  
249
  parse_rest(args, &args_length, &args_data);
250

251
252
253
254
  command = make_general_channel_request_command
    (format_channel_request_i(info, &channel->chain->super,
			      args_length, args_data));
  COMMAND_CALL(command, channel->chain, c, e);
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
}

struct channel_request gateway_channel_request =
{ STATIC_HEADER, do_gateway_channel_request };


/* GABA:
   (class
     (name general_global_request_command)
     (super global_request_command)
     (vars
       (request string)))
*/

static struct lsh_string *
do_format_general_global_request(struct global_request_command *s,
			  	 struct ssh_connection *connection UNUSED,
				 struct command_continuation **c UNUSED)
{
  CAST(general_global_request_command, self, s);

  struct lsh_string *r = self->request;
  self->request = NULL;
  return r;
}

static struct command *
make_general_global_request_command(struct lsh_string *request)
{
  NEW(general_global_request_command, self);
  
  self->super.super.call = do_channel_global_command;
  self->super.format_request = do_format_general_global_request;
  self->request = request;
  return &self->super.super;
}

static void
do_gateway_global_request(struct global_request *s UNUSED,
			  struct ssh_connection *connection,
			  UINT32 type,
			  int want_reply,
			  struct simple_buffer *args,
			  struct command_continuation *c,
			  struct exception_handler *e)
{
  struct lsh_string *request =
    format_global_request(type, want_reply, "%ls",
			  args->capacity - args->pos, &args->data[args->pos]);

  struct command *send = make_general_global_request_command(request);

  COMMAND_CALL(send, connection->chain, c, e);
}

struct global_request gateway_global_request = 
{ STATIC_HEADER, do_gateway_global_request };

/* Continuation to handle the returned channel, and chain two channels
 * together.
 *
 * CHANNEL is the "originating" end of the channel. The argument to
 * the continuation is a new channel connected to the other end. */

/* GABA:
   (class
     (name gateway_channel_open_continuation)
     (super command_continuation)
     (vars
       (up object command_continuation)
325
       (fallback object channel_request fallback)
326
327
328
329
330
331
332
333
334
335
336
337
338
339
       (origin object gateway_channel)))
*/

static void
do_gateway_channel_open_continuation(struct command_continuation *c,
				     struct lsh_object *x)
{
  CAST(gateway_channel_open_continuation, self, c);
  CAST(gateway_channel, target, x);

  self->origin->chain = target;
  target->chain = self->origin;

  self->origin->super.rec_window_size = target->super.send_window_size;
340
341
342
343

  /* Don't advertise a larger rec_max_packet than we're willing to handle. */
  self->origin->super.rec_max_packet
    = MIN(target->super.send_max_packet, SSH_MAX_PACKET);
344

345
346
  gateway_init_io(self->origin);
  gateway_init_io(target);
347
348
349

  target->super.request_fallback = self->fallback;
  
350
351
352
353
354
  COMMAND_RETURN(self->up, self->origin);
}

struct command_continuation *
make_gateway_channel_open_continuation(struct command_continuation *up,
355
				       struct channel_request *fallback,
356
357
358
359
360
361
				       struct gateway_channel *origin)
{
  NEW(gateway_channel_open_continuation, self);
  
  self->super.c = do_gateway_channel_open_continuation;
  self->origin = origin;
362
  self->fallback = fallback;
363
364
365
366
  self->up = up;

  return &self->super;
}
367
368
369
370
371
372
373
374
375
376
377
378

static void
do_channel_open_forward(struct channel_open *s UNUSED,
			struct ssh_connection *connection,
			struct channel_open_info *info,
			struct simple_buffer *args,
			struct command_continuation *c,
			struct exception_handler *e)
{
  struct gateway_channel *origin
    = make_gateway_channel(NULL);

379
380
  struct command *command
    = make_gateway_channel_open_command(info, parse_rest_copy(args), NULL);
381

382
  origin->super.request_fallback = &gateway_channel_request;
383
  
384
  COMMAND_CALL(command,
385
	       connection->chain,
386
387
	       make_gateway_channel_open_continuation
	         (c, &gateway_channel_request, origin),
388
389
390
391
392
393
	       e);
}

struct channel_open gateway_channel_open_forward =
{ STATIC_HEADER, do_channel_open_forward };