proxy_channel.c 8.89 KB
Newer Older
Balázs Scheidler's avatar
Balázs Scheidler committed
1
2
3
4
5
6
/* proxy_channel.c
 *
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
7
 * Copyright (C) 1999 Balzs Scheidler
Balázs Scheidler's avatar
Balázs Scheidler committed
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "proxy_channel.h"
25

Balázs Scheidler's avatar
Balázs Scheidler committed
26
27
#include "channel_commands.h"
#include "format.h"
28
29
30
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"
Balázs Scheidler's avatar
Balázs Scheidler committed
31
32
33
34
35
36
37

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

#include "proxy_channel.c.x"

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#define WINDOW_SIZE 10000

#if 0
/* ;;GABA:
   (class
     (name proxy_flow_control)
     (super flow_controlled)
     (vars
       (channel object proxy_channel)))
*/

static void
do_proxy_flow_control(struct flow_controlled *c,
		      UINT32 res UNUSED)
{
  CAST(proxy_flow_control, closure, c);

  CHANNEL_SEND(&closure->channel->super, NULL);
}

static struct flow_controlled *
make_proxy_flow_control(struct proxy_channel *channel)
{
  NEW(proxy_flow_control, self);
  
  self->super.report = do_proxy_flow_control;
  self->channel = channel;
  return &self->super;
}
#endif
Balázs Scheidler's avatar
Balázs Scheidler committed
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

static void
do_receive(struct ssh_channel *c,
	   int type,
	   struct lsh_string *data)
{
  CAST(proxy_channel, closure, c);
  
  switch(type)
    {
    case CHANNEL_DATA:
      A_WRITE(closure->chain->super.write, channel_transmit_data(&closure->chain->super, data));
      break;
    case CHANNEL_STDERR_DATA:
      A_WRITE(closure->chain->super.write, channel_transmit_extended(&closure->chain->super, CHANNEL_STDERR_DATA, data));
      break;
    default:
      fatal("Internal error!\n");
    }
}

89
90
91
92
93
94
95
96
97
/* We may send more data */
static void
do_send_adjust(struct ssh_channel *s,
	       UINT32 i)
{
  CAST(proxy_channel, self, s);
  FLOW_CONTROL_REPORT(&self->chain->super.super, i);
}

Balázs Scheidler's avatar
Balázs Scheidler committed
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
static void
do_eof(struct ssh_channel *c)
{
  CAST(proxy_channel, channel, c);
  channel_eof(&channel->chain->super);
}

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

static void 
do_init_io(struct proxy_channel *self)
{
115
  self->super.send_adjust = do_send_adjust;  
Balázs Scheidler's avatar
Balázs Scheidler committed
116
117
118
119
120
  self->super.receive = do_receive;
  self->super.eof = do_eof;
  self->super.close = do_close;
}

121
122
123
/* NOTE: It seems most calls doesn't provide the correct value for
 * rec_max_packet. In these cases, it should probably be filled in
 * later, by do_proxy_channel_open_continuation() fill it in later. */
Balázs Scheidler's avatar
Balázs Scheidler committed
124
125
struct proxy_channel *
make_proxy_channel(UINT32 window_size,
126
		   UINT32 rec_max_packet,
Balázs Scheidler's avatar
Balázs Scheidler committed
127
128
129
130
131
132
133
134
		   struct alist *request_types,
		   int client_side)
{
  NEW(proxy_channel, self);
  init_channel(&self->super);

  self->super.max_window = SSH_MAX_PACKET << 3;
  self->super.rec_window_size = window_size;
135
  self->super.rec_max_packet = rec_max_packet;
Balázs Scheidler's avatar
Balázs Scheidler committed
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  self->super.request_types = request_types;
  self->init_io = do_init_io;

  if (client_side)
    self->super.flags |= CHANNEL_CLOSE_AT_EOF;

  return self;
}

/* proxy channel requests */

/* GABA:
   (class
     (name general_channel_request_command)
     (super channel_request_command)
     (vars
       (request string)))
*/

static struct lsh_string *
do_format_channel_general(struct channel_request_command *s,
			  struct ssh_channel *ch UNUSED,
158
			  struct command_continuation **c UNUSED)
Balázs Scheidler's avatar
Balázs Scheidler committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
{
  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_proxy_channel_request(struct channel_request *s UNUSED,
			 struct ssh_channel *ch,
			 struct ssh_connection *connection UNUSED,
			 UINT32 type,
			 int want_reply,
			 struct simple_buffer *args,
			 struct command_continuation *c,
			 struct exception_handler *e)
{
  CAST(proxy_channel, channel, ch);

  struct lsh_string *request = 
    format_channel_request(type, &channel->chain->super, want_reply, 
			   "%ls", 
			   args->capacity - args->pos, &args->data[args->pos]);
  struct command *send;

  send = make_general_channel_request_command(request);

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

struct channel_request proxy_channel_request =
{ STATIC_HEADER, do_proxy_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,
214
				 struct command_continuation **c UNUSED)
Balázs Scheidler's avatar
Balázs Scheidler committed
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
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
{
  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_proxy_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 =
    ssh_format("%c%a%c%ls", SSH_MSG_GLOBAL_REQUEST, type,
	       want_reply, args->capacity - args->pos, &args->data[args->pos]);

  struct command *send;

  send = make_general_global_request_command(request);

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

struct global_request proxy_global_request = 
{ STATIC_HEADER, do_proxy_global_request };

/*
 * continuation to handle the returned channel, and chain two channels
 * together
 */

/* GABA:
   (class
     (name proxy_channel_open_continuation)
     (super command_continuation)
     (vars
       (up object command_continuation)
       (channel object proxy_channel)))
*/

static void
do_proxy_channel_open_continuation(struct command_continuation *c,
				   struct lsh_object *x)
{
  CAST(proxy_channel_open_continuation, self, c);
  CAST(proxy_channel, chain_channel, x);

  self->channel->chain = chain_channel;
  chain_channel->chain = self->channel;

281
282
283
284
285
  /* FIXME: I think this is the right thing to do, but I'm not quite
   * sure. /nisse */

  /* self->channel->rec_max_packet = chain_channel->send_max_packet; */
  
Balázs Scheidler's avatar
Balázs Scheidler committed
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
  PROXY_CHANNEL_INIT_IO(self->channel);
  PROXY_CHANNEL_INIT_IO(chain_channel);
    
  COMMAND_RETURN(self->up, self->channel);
}

struct command_continuation *
make_proxy_channel_open_continuation(struct command_continuation *up,
				     struct proxy_channel *channel)
{
  NEW(proxy_channel_open_continuation, self);
  
  self->super.c = do_proxy_channel_open_continuation;
  self->channel = channel;
  self->up = up;
  return &self->super;
}

/* command to request a channel open */
/* GABA:
   (class
     (name proxy_channel_open_command)
     (super channel_open_command)
     (vars
       ; channel type
       (type . UINT32)
312
       (max_packet . UINT32)
Balázs Scheidler's avatar
Balázs Scheidler committed
313
314
315
316
317
318
319
320
321
322
323
324
       (requests object alist)
       (open_request string)))
*/

static struct ssh_channel *
do_proxy_channel_open(struct channel_open_command *c,
		      struct ssh_connection *connection,
		      UINT32 local_channel_number,
		      struct lsh_string **request)
{
  CAST(proxy_channel_open_command, closure, c);
  
325
326
327
  struct proxy_channel *client
    = make_proxy_channel(WINDOW_SIZE, closure->max_packet,
			 closure->requests, 1);
Balázs Scheidler's avatar
Balázs Scheidler committed
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342

  client->super.write = connection->write;
  
  if (closure->open_request)
    *request = format_channel_open(closure->type, local_channel_number,
				   &client->super, "%lS", closure->open_request);
  else
    *request = format_channel_open(closure->type, local_channel_number,
				   &client->super, "");
  
  return &client->super;
}

struct command *
make_proxy_channel_open_command(UINT32 type,
343
				UINT32 max_packet,
Balázs Scheidler's avatar
Balázs Scheidler committed
344
345
346
347
348
349
350
351
                                struct lsh_string *open_request,
				struct alist *requests)
{
  NEW(proxy_channel_open_command, self);
  
  self->super.new_channel = do_proxy_channel_open;
  self->super.super.call = do_channel_open_command;
  self->type = type;
352
  self->max_packet = max_packet;
Balázs Scheidler's avatar
Balázs Scheidler committed
353
  self->requests = requests;
354
355
  self->open_request = open_request;

Balázs Scheidler's avatar
Balázs Scheidler committed
356
357
  return &self->super.super;
}