channel.c 41.6 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* channel.c
 *
 */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 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
J.H.M. Dassen's avatar
J.H.M. Dassen committed
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Niels Möller's avatar
Niels Möller committed
22
23
 */

24
25
26
27
28
29
30
#if HAVE_CONFIG_H
#include "config.h"
#endif

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

Niels Möller's avatar
Niels Möller committed
31
32
33
#include "channel.h"

#include "format.h"
34
#include "io.h"
35
#include "lsh_string.h"
Niels Möller's avatar
Niels Möller committed
36
37
38
39
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"

40
#define GABA_DEFINE
41
#include "channel.h.x"
42
#undef GABA_DEFINE
43

44
45
#include "channel.c.x"

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/* Opening a new channel: There are two cases, depending on which side
   sends the CHANNEL_OPEN_REQUEST. FIXME: This description is not yet
   accurate. When we send it, the following steps are taken:

   1. Create a new channel object of the appropriate type.
   
   2. Call request_channel_open. This allocates a channel number,
      registers the object, and sends a CHANNEL_OPEN request.

   3. If the remote end replies with CHANNEL_OPEN_CONFIRMATION, the
      channel's event handler is invoked, with CHANNEL_EVENT_CONFIRM.
      If the remote end replies with CHANNEL_OPEN_FAILURE, the channel
      is killed.

   When the other side requests a new channel, the steps are:

   1. Receive CHANNEL_OPEN. Reserve a channel number, and invoke the
      command associated with the channel type.

   2. This command returns a new channel object, or raises an
      exception.

   3. Install the channel object, and reply with
      CHANNEL_OPEN_CONFIRMATION. On error, deallocate channel number,
      and reply with CHANNEL_OPEN_FAILURE.
*/
72

73
struct exception *
74
make_channel_open_exception(uint32_t error_code, const char *msg)
Niels Möller's avatar
Niels Möller committed
75
{
Niels Möller's avatar
Niels Möller committed
76
77
78
79
80
81
82
83
84
85
86
87
#define MAX_ERROR 4
  static const char *msgs[MAX_ERROR + 1] = {
    "",
    "Administratively prohibited",
    "Connect failed",
    "Unknown channel type",
    "Resource shortage"
  };

  assert(error_code > 0);
  assert(error_code <= MAX_ERROR);
#undef MAX_ERROR
Niels Möller's avatar
Niels Möller committed
88

89
90
  return make_exception(EXC_CHANNEL_OPEN, error_code,
			msg ? msg : msgs[error_code]);
Niels Möller's avatar
Niels Möller committed
91
92
}

93

94
static struct lsh_string *
95
format_global_failure(void)
Niels Möller's avatar
Niels Möller committed
96
97
98
99
{
  return ssh_format("%c", SSH_MSG_REQUEST_FAILURE);
}

100
static struct lsh_string *
101
format_global_success(void)
102
103
104
105
{
  return ssh_format("%c", SSH_MSG_REQUEST_SUCCESS);
}

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* The advertised rec_max_size must be a little smaller than SSH_MAX_PACKET,
 * to make sure that our peer won't send us packets exceeding our limit for
 * the connection. */

/* NOTE: It would make some sense to use the connection's
 * rec_max_packet instead of the SSH_MAX_PACKET constant. */

#define SSH_MAX_DATA_SIZE (SSH_MAX_PACKET - SSH_CHANNEL_MAX_PACKET_FUZZ)

static void
check_rec_max_packet(struct ssh_channel *channel)
{
  /* Never advertise a larger rec_max_packet than we're willing to
   * handle. */

  if (channel->rec_max_packet > SSH_MAX_DATA_SIZE)
    {
      debug("check_rec_max_packet: Reduced rec_max_packet from %i to %i.\n",
	    channel->rec_max_packet, SSH_MAX_DATA_SIZE);
      channel->rec_max_packet = SSH_MAX_DATA_SIZE;
    }
}

129
static struct lsh_string *
130
131
format_open_confirmation(struct ssh_channel *channel,
			 const char *format, ...)
132
133
{
  va_list args;
134
  uint32_t l1, l2;
135
  struct lsh_string *packet;
136
  
137
#define CONFIRM_FORMAT "%c%i%i%i%i"
138
#define CONFIRM_ARGS \
139
140
141
  SSH_MSG_CHANNEL_OPEN_CONFIRMATION, \
  channel->remote_channel_number, channel->local_channel_number, \
  channel->rec_window_size, channel->rec_max_packet
142
    
143
144
  check_rec_max_packet(channel);

145
  debug("format_open_confirmation: rec_window_size = %i,\n"
146
	"                          rec_max_packet = %i,\n",
147
       channel->rec_window_size,
148
       channel->rec_max_packet);
149
150
151
152
153
154
155
156
  l1 = ssh_format_length(CONFIRM_FORMAT, CONFIRM_ARGS);

  va_start(args, format);
  l2 = ssh_vformat_length(format, args);
  va_end(args);

  packet = lsh_string_alloc(l1 + l2);

157
  ssh_format_write(CONFIRM_FORMAT, packet, 0, CONFIRM_ARGS);
158
159

  va_start(args, format);
160
  ssh_vformat_write(format, packet, l1, args);
161
162
163
164
165
166
167
  va_end(args);

  return packet;
#undef CONFIRM_FORMAT
#undef CONFIRM_ARGS
}

168
static struct lsh_string *
169
format_open_failure(uint32_t channel, uint32_t reason,
170
		    const char *msg, const char *language)
Niels Möller's avatar
Niels Möller committed
171
172
173
174
175
{
  return ssh_format("%c%i%i%z%z", SSH_MSG_CHANNEL_OPEN_FAILURE,
		    channel, reason, msg, language);
}

176
static struct lsh_string *
177
format_channel_success(uint32_t channel)
178
179
180
181
{
  return ssh_format("%c%i", SSH_MSG_CHANNEL_SUCCESS, channel);
}

182
static struct lsh_string *
183
format_channel_failure(uint32_t channel)
Niels Möller's avatar
Niels Möller committed
184
185
186
187
{
  return ssh_format("%c%i", SSH_MSG_CHANNEL_FAILURE, channel);
}

188
static struct lsh_string *
189
prepare_window_adjust(struct ssh_channel *channel,
190
		      uint32_t add)
191
192
193
194
195
{
  channel->rec_window_size += add;
  
  return ssh_format("%c%i%i",
		    SSH_MSG_CHANNEL_WINDOW_ADJUST,
196
		    channel->remote_channel_number, add);
197
198
}

199
static void
200
channel_finished(struct ssh_channel *channel)
Niels Möller's avatar
Niels Möller committed
201
{
202
203
204
  if (!channel->super.alive)
    werror("channel_finished called on a dead channel.\n");
  else
Niels Möller's avatar
Niels Möller committed
205
    {
206
      struct ssh_connection *connection = channel->connection;
Niels Möller's avatar
Niels Möller committed
207

208
209
      trace("channel_finished: Deallocating channel %i\n", channel->local_channel_number);
      KILL_RESOURCE(&channel->super);
210

211
      /* Disassociate from the connection. */
212
      channel->connection = NULL;
Niels Möller's avatar
Niels Möller committed
213
      
214
      ssh_connection_dealloc_channel(connection, channel->local_channel_number);
215

216
217
      trace("connection->pending_close = %i, connection->channel_count = %i\n",
	    connection->pending_close, connection->channel_count);
218

219
220
      if (connection->pending_close && !connection->channel_count)
	KILL_RESOURCE(&connection->super);
Niels Möller's avatar
Niels Möller committed
221
222
223
224
    }
}


225
/* Channel objects */
Niels Möller's avatar
Niels Möller committed
226
227


228
void
229
register_channel(struct ssh_connection *connection,
230
		 uint32_t local_channel_number,
231
232
		 struct ssh_channel *channel,
		 int take_into_use)
233
{
234
235
  assert(connection->in_use[local_channel_number] == CHANNEL_RESERVED);
  assert(!connection->channels[local_channel_number]);
236

237
238
239
  verbose("Registering local channel %i.\n",
	  local_channel_number);

240
  connection->channels[local_channel_number] = channel;
241
  channel->local_channel_number = local_channel_number;
242
243
  channel->connection = connection;
  
244
  if (take_into_use)
245
246
247
    ssh_connection_use_channel(connection, local_channel_number);

  remember_resource(connection->resources, &channel->super);  
Niels Möller's avatar
Niels Möller committed
248
249
}

250
struct ssh_channel *
251
lookup_channel(struct ssh_connection *connection, uint32_t i)
252
{
253
  if ( (i < connection->used_channels) && (connection->in_use[i] == CHANNEL_IN_USE))
254
    {
255
      struct ssh_channel *channel = connection->channels[i];
256
257
258
259
260
261
      assert(channel);
      assert(channel->local_channel_number == i);

      return channel;
    }
  return NULL;
262
263
264
}

struct ssh_channel *
265
lookup_channel_reserved(struct ssh_connection *connection, uint32_t i)
Niels Möller's avatar
Niels Möller committed
266
{
267
  if ( (i < connection->used_channels) && (connection->in_use[i] == CHANNEL_RESERVED))
268
    {
269
      struct ssh_channel *channel = connection->channels[i];
270
271
272
273
274
275
      assert(channel);
      assert(channel->local_channel_number == i);

      return channel;
    }
  return NULL;
Niels Möller's avatar
Niels Möller committed
276
277
}

278
279
/* FIXME: It seems suboptimal to send a window adjust message for
 * *every* write that we do. A better scheme might be as follows:
280
281
282
283
284
285
286
 *
 * Delay window adjust messages, keeping track of both the locally
 * maintained window size, which is updated after each write, and the
 * size that has been reported to the remote end. When the difference
 * between these two values gets large enough (say, larger than one
 * half or one third of the maximum window size), we send a
 * window_adjust message to sync them. */
287
288
void
channel_adjust_rec_window(struct ssh_channel *channel, uint32_t written)
289
{
290
291
  /* NOTE: The channel object (referenced as a flow-control callback)
   * may live longer than the actual channel. */
292
293
  if (written && ! (channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_RECEIVED_CLOSE
				      | CHANNEL_SENT_CLOSE)))
294
    SSH_CONNECTION_WRITE(channel->connection, prepare_window_adjust(channel, written));
295
296
}

297
298
void
channel_start_receive(struct ssh_channel *channel,
299
		      uint32_t initial_window_size)
300
{
301
  if (channel->rec_window_size < initial_window_size)
302
    SSH_CONNECTION_WRITE(channel->connection,
303
304
		 prepare_window_adjust
		 (channel, initial_window_size - channel->rec_window_size));
305
306
}

Niels Möller's avatar
Niels Möller committed
307
/* Channel related messages */
308
309
310

/* GABA:
   (class
311
     (name request_status)
312
313
314
315
316
317
318
     (vars
       ; -1 for still active requests,
       ; 0 for failure,
       ; 1 for success
       (status . int)))
*/

319
320
static struct request_status *
make_request_status(void)
321
{
322
  NEW(request_status, self);
323
324
325
326
327
328
329
  self->status = -1;

  return self;
}

/* GABA:
   (class
330
331
     (name global_request_continuation)
     (super command_continuation)
332
     (vars
333
       (connection object ssh_connection)
334
       (active object request_status)))
335
336
*/

337
static void 
338
send_global_request_responses(struct ssh_connection *connection)
339
{
340
  struct object_queue *q = &connection->active_global_requests;
341
342
343
344
345
346
347
348

  assert(!object_queue_is_empty(q));

  for (;;)
    {
      CAST(request_status, n, object_queue_peek_head(q));
      if (!n || (n->status < 0))
	break;
349
 
350
      object_queue_remove_head(q);
Niels Möller's avatar
Niels Möller committed
351

352
      SSH_CONNECTION_WRITE(connection, (n->status
353
354
				  ? format_global_success()
				  : format_global_failure()));
355
356
357
    }
}

358
359
360
static void
do_global_request_response(struct command_continuation *s,
			   struct lsh_object *x UNUSED)
361
{
362
  CAST(global_request_continuation, self, s);
363

364
365
  assert(self->active->status == -1);
  self->active->status = 1;
366

367
  send_global_request_responses(self->connection);
368
}
369

370
static struct command_continuation *
371
make_global_request_response(struct ssh_connection *connection,
372
373
374
375
376
			     struct request_status *active)
{
  NEW(global_request_continuation, self);

  self->super.c = do_global_request_response;
377
  self->connection = connection;
378
379
  self->active = active;
   
380
381
  return &self->super;
}
382
383
384
385
386
387
388


/* GABA:
   (class
     (name global_request_exception_handler)
     (super exception_handler)
     (vars
389
       (connection object ssh_connection)
390
391
392
       (active object request_status)))
*/

393
/* All exceptions are treated as a failure. */
394
static void 
395
do_exc_global_request_handler(struct exception_handler *c,
Niels Möller's avatar
Niels Möller committed
396
			      const struct exception *e)
397
398
{
  CAST(global_request_exception_handler, self, c);
399
400
401
402
403
404

  assert(self->active->status == -1);
  self->active->status = 0;

  werror("Denying global request: %z\n", e->msg);
  send_global_request_responses(self->connection);
405
406
407
}

static struct exception_handler *
408
make_global_request_exception_handler(struct ssh_connection *connection,
409
410
				      struct request_status *active,
				      const char *context)
Niels Möller's avatar
Niels Möller committed
411
{
412
413
  NEW(global_request_exception_handler, self);

414
  self->super.raise = do_exc_global_request_handler;
415
416
  self->super.context = context;
  self->active = active;
417
  self->connection = connection;
418
419
  return &self->super;
}
Niels Möller's avatar
Niels Möller committed
420

421
static void
422
handle_global_request(struct ssh_connection *connection,
423
		      struct simple_buffer *buffer)
424
{
Niels Möller's avatar
Niels Möller committed
425
426
427
  int name;
  int want_reply;
  
428
429
  if (parse_atom(buffer, &name)
      && parse_boolean(buffer, &want_reply))
Niels Möller's avatar
Niels Möller committed
430
    {
431
432
      struct global_request *req = NULL;

433
      if (name && connection->global_requests)
434
435
	{
	  CAST_SUBTYPE(global_request, r,
436
		       ALIST_GET(connection->global_requests,
437
438
439
440
				 name));
	  req = r;
	}
      if (!req)
441
	{
442
	  SSH_CONNECTION_WRITE(connection, format_global_failure());
Niels Möller's avatar
Niels Möller committed
443
	  return;
Niels Möller's avatar
Niels Möller committed
444
445
446
	}
      else
	{
447
	  struct command_continuation *c;
448
	  struct exception_handler *e;
Niels Möller's avatar
Niels Möller committed
449
450
	  if (want_reply)
	    {
451
	      struct request_status *a = make_request_status();
Niels Möller's avatar
Niels Möller committed
452
	      
453
	      object_queue_add_tail(&connection->active_global_requests,
Niels Möller's avatar
Niels Möller committed
454
455
				    &a->super);
	      
456
	      c = make_global_request_response(connection, a);
457
	      e = make_global_request_exception_handler(connection, a,
458
							HANDLER_CONTEXT);
459
460
461
462
	    }
	  else
	    {
	      /* We should ignore failures. */
463
464
	      c = &discard_continuation;
	      e = &ignore_exception_handler;
Niels Möller's avatar
Niels Möller committed
465
	    }
466
	  GLOBAL_REQUEST(req, connection, name, want_reply, buffer, c, e);
467
	}
Niels Möller's avatar
Niels Möller committed
468
    }
Niels Möller's avatar
Niels Möller committed
469
  else
470
    SSH_CONNECTION_ERROR(connection, "Invalid SSH_MSG_GLOBAL_REQUEST message.");
Niels Möller's avatar
Niels Möller committed
471
472
}

473
static void
474
handle_global_success(struct ssh_connection *connection,
475
		      struct simple_buffer *buffer)
476
{
477
  if (!parse_eod(buffer))
Niels Möller's avatar
Niels Möller committed
478
    {
479
      SSH_CONNECTION_ERROR(connection, "Invalid GLOBAL_REQUEST_SUCCESS message.");
480
      return;
Niels Möller's avatar
Niels Möller committed
481
    }
482

483
  if (object_queue_is_empty(&connection->pending_global_requests))
484
485
    {
      werror("do_global_request_success: Unexpected message, ignoring.\n");
Niels Möller's avatar
Niels Möller committed
486
      return;
487
488
    }
  {
489
    CAST_SUBTYPE(command_context, ctx,
490
491
		 object_queue_remove_head(&connection->pending_global_requests));
    COMMAND_RETURN(ctx->c, connection);
492
493
494
  }
}

495
struct exception global_request_exception =
496
STATIC_EXCEPTION(EXC_GLOBAL_REQUEST, 0, "Global request failed");
497

498
static void
499
handle_global_failure(struct ssh_connection *connection,
500
		      struct simple_buffer *buffer)
501
{
502
  if (!parse_eod(buffer))
Niels Möller's avatar
Niels Möller committed
503
    {
504
      SSH_CONNECTION_ERROR(connection, "Invalid GLOBAL_REQUEST_FAILURE message.");
505
      return;
Niels Möller's avatar
Niels Möller committed
506
    }
507

508
  if (object_queue_is_empty(&connection->pending_global_requests))
509
510
511
    {
      werror("do_global_request_failure: Unexpected message, ignoring.\n");
    }
Niels Möller's avatar
Niels Möller committed
512
513
514
  else
    {
      CAST_SUBTYPE(command_context, ctx,
515
		   object_queue_remove_head(&connection->pending_global_requests));
Niels Möller's avatar
Niels Möller committed
516
517
      EXCEPTION_RAISE(ctx->e, &global_request_exception);
    }
518
519
}

520
521
/* FIXME: Don't store the channel here, instead have it passed as the
 * argument of the continuation. This might also allow some
522
523
524
525
526
 * unification with the handling of global_requests.
 *
 * This won't quite work yet, because not all channel request
 * handlers, in particular gateway_channel_request and
 * x11_req_handler, return the channel in question. */
527
528
529
530
531
532
533
534
535
536
537

/* GABA:
   (class
     (name channel_request_continuation)
     (super command_continuation)
     (vars
       (channel object ssh_channel)
       (active object request_status)))
*/

static void
538
send_channel_request_responses(struct ssh_channel *channel)
539
{
540
541
542
  struct object_queue *q = &channel->active_requests;
  assert(!object_queue_is_empty(q));

543
544
545
546
547
548
549
550
  for (;;)
    {
      CAST(request_status, n, object_queue_peek_head(q));
      if (!n || (n->status < 0))
	break;

      object_queue_remove_head(q);

551
      SSH_CONNECTION_WRITE(channel->connection,
552
553
554
		   (n->status
		    ? format_channel_success(channel->remote_channel_number)
		    : format_channel_failure(channel->remote_channel_number)));
555
556
557
558
559
560
561
562
563
    }
}

static void
do_channel_request_response(struct command_continuation *s,
			    struct lsh_object *x UNUSED)
{
  CAST(channel_request_continuation, self, s);

564
  trace("do_channel_request_response\n");
565
566
567
  assert(self->active->status == -1);
  self->active->status = 1;

568
  send_channel_request_responses(self->channel);
569
570
571
}

static struct command_continuation *
572
make_channel_request_response(struct ssh_channel *channel,
573
574
575
576
			      struct request_status *active)
{
  NEW(channel_request_continuation, self);

577
578
  trace("make_channel_request_response\n");

579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
  self->super.c = do_channel_request_response;
  self->channel = channel;
  self->active = active;

  return &self->super;
}

/* GABA:
   (class
     (name channel_request_exception_handler)
     (super exception_handler)
     (vars
       (channel object ssh_channel)
       (active object request_status)))
*/

595
/* All exceptions are treated as a failure. */
596
static void 
597
598
do_exc_channel_request_handler(struct exception_handler *c,
			       const struct exception *e)
599
600
{
  CAST(channel_request_exception_handler, self, c);
601
602
603
604
605
606

  assert(self->active->status == -1);
  self->active->status = 0;

  werror("Denying channel request: %z\n", e->msg);
  send_channel_request_responses(self->channel);
607
608
609
}

static struct exception_handler *
610
make_channel_request_exception_handler(struct ssh_channel *channel,
611
612
613
614
615
				       struct request_status *active,
				       const char *context)
{
  NEW(channel_request_exception_handler, self);

616
  self->super.raise = do_exc_channel_request_handler;
617
  self->super.context = context;
618

619
620
621
622
623
624
  self->channel = channel;
  self->active = active;

  return &self->super;
}

625
static void
626
handle_channel_request(struct ssh_connection *connection,
627
		       struct simple_buffer *buffer)
628
{
629
  struct channel_request_info info;
630
  uint32_t channel_number;
631
  
632
633
634
635
  if (parse_uint32(buffer, &channel_number)
      && parse_string(buffer,
		      &info.type_length, &info.type_data)
      && parse_boolean(buffer, &info.want_reply))
636
    {
637
      struct ssh_channel *channel;
638
639
640
      trace("handle_channel_request: Request type `%ps' on channel %i\n",
	    info.type_length, info.type_data, channel_number);

641
      info.type = lookup_atom(info.type_length, info.type_data);
642

643
      channel = lookup_channel(connection, channel_number);
644
      
645
646
      if (channel)
	{
647
	  struct channel_request *req = NULL;
648

649
	  if (info.type && channel->request_types)
650
651
	    {
	      CAST_SUBTYPE(channel_request, r,
652
			   ALIST_GET(channel->request_types, info.type));
653
654
	      req = r;
	    }
655
656
657
	  if (!req)
	    req = channel->request_fallback;
	  
658
	  if (req)
659
	    {
660
661
	      struct command_continuation *c;
	      struct exception_handler *e;
662
	      if (info.want_reply)
663
664
		{
		  struct request_status *a = make_request_status();
665

666
667
		  object_queue_add_tail(&channel->active_requests,
					&a->super);
668

669
		  c = make_channel_request_response(channel, a);
670
671
		  e = make_channel_request_exception_handler(channel, a,
							     HANDLER_CONTEXT);
672
673
674
675
		}
	      else
		{
		  /* We should ignore failures. */
676
677
		  c = &discard_continuation;
		  e = &ignore_exception_handler;
678
679
		}
	      
680
	      CHANNEL_REQUEST(req, channel, &info, buffer, c, e);
681
682
683
	    }
	  else
	    {
684
	      if (info.want_reply)
685
		SSH_CONNECTION_WRITE(connection,
686
				    format_channel_failure(channel->remote_channel_number));
687
688
689
690
	    }
	}
      else
	{
691
692
	  werror("SSH_MSG_CHANNEL_REQUEST on nonexistant channel %i: %xs\n",
		 channel_number, buffer->capacity, buffer->pos);
693
694
695
	}
    }
  else
696
    SSH_CONNECTION_ERROR(connection, "Invalid SSH_MSG_CHANNEL_REQUEST message.");
697
698
699
}


Niels Möller's avatar
Niels Möller committed
700
/* GABA:
701
702
703
704
   (class
     (name channel_open_continuation)
     (super command_continuation)
     (vars
705
       (connection object ssh_connection)
706
707
708
709
       (local_channel_number . uint32_t)
       (remote_channel_number . uint32_t)
       (send_window_size . uint32_t)
       (send_max_packet . uint32_t)))
710
*/
711

Niels Möller's avatar
Niels Möller committed
712
713
714
static void
do_channel_open_continue(struct command_continuation *c,
			 struct lsh_object *value)
715
716
{
  CAST(channel_open_continuation, self, c);
Niels Möller's avatar
Niels Möller committed
717
718
719
720
721
722
723
  CAST_SUBTYPE(ssh_channel, channel, value);

  assert(channel);

  /* FIXME: This copying could just as well be done by the
   * CHANNEL_OPEN handler? Then we can remove the corresponding fields
   * from the closure as well. */
724
725
  channel->send_window_size = self->send_window_size;
  channel->send_max_packet = self->send_max_packet;
726
  channel->remote_channel_number = self->remote_channel_number;
Niels Möller's avatar
Niels Möller committed
727

728
  register_channel(self->connection, self->local_channel_number,
729
		   channel,
730
		   1);
Niels Möller's avatar
Niels Möller committed
731
732
733
734

  /* FIXME: Doesn't support sending extra arguments with the
   * confirmation message. */

735
  SSH_CONNECTION_WRITE(self->connection,
736
		       format_open_confirmation(channel, ""));
737
}
Niels Möller's avatar
Niels Möller committed
738

Niels Möller's avatar
Niels Möller committed
739
static struct command_continuation *
740
make_channel_open_continuation(struct ssh_connection *connection,
741
742
743
744
			       uint32_t local_channel_number,
			       uint32_t remote_channel_number,
			       uint32_t send_window_size,
			       uint32_t send_max_packet)
Niels Möller's avatar
Niels Möller committed
745
746
{
  NEW(channel_open_continuation, self);
Niels Möller's avatar
Niels Möller committed
747

Niels Möller's avatar
Niels Möller committed
748
  self->super.c = do_channel_open_continue;
749
  self->connection = connection;
Niels Möller's avatar
Niels Möller committed
750
751
  self->local_channel_number = local_channel_number;
  self->remote_channel_number = remote_channel_number;
752
753
  self->send_window_size = send_window_size;
  self->send_max_packet = send_max_packet;
Niels Möller's avatar
Niels Möller committed
754

Niels Möller's avatar
Niels Möller committed
755
  return &self->super;
Niels Möller's avatar
Niels Möller committed
756
757
758
759
760
761
762
}
			       
/* GABA:
   (class
     (name exc_channel_open_handler)
     (super exception_handler)
     (vars
763
       (connection object ssh_connection)
764
765
       (local_channel_number . uint32_t)
       (remote_channel_number . uint32_t)))
Niels Möller's avatar
Niels Möller committed
766
767
*/

768
769
770
static void
do_exc_channel_open_handler(struct exception_handler *s,
			    const struct exception *e)
Niels Möller's avatar
Niels Möller committed
771
772
{
  CAST(exc_channel_open_handler, self, s);
773
774
775
  struct ssh_connection *connection = self->connection;
  uint32_t error_code = (e->type == EXC_CHANNEL_OPEN)
    ? e->subtype : SSH_OPEN_RESOURCE_SHORTAGE;
Niels Möller's avatar
Niels Möller committed
776

777
778
779
780
781
782
783
784
785
786
  assert(connection->in_use[self->local_channel_number]);
  assert(!connection->channels[self->local_channel_number]);

  ssh_connection_dealloc_channel(connection, self->local_channel_number);

  werror("Denying channel open: %z\n", e->msg);
  
  SSH_CONNECTION_WRITE(connection,
		       format_open_failure(self->remote_channel_number,
					   error_code, e->msg, ""));
Niels Möller's avatar
Niels Möller committed
787
788
789
}

static struct exception_handler *
790
make_exc_channel_open_handler(struct ssh_connection *connection,
791
792
			      uint32_t local_channel_number,
			      uint32_t remote_channel_number,
793
			      const char *context)
Niels Möller's avatar
Niels Möller committed
794
{
Niels Möller's avatar
Niels Möller committed
795
796
  NEW(exc_channel_open_handler, self);
  self->super.raise = do_exc_channel_open_handler;
797
798
  self->super.context = context;
  
799
  self->connection = connection;
Niels Möller's avatar
Niels Möller committed
800
801
802
803
804
805
  self->local_channel_number = local_channel_number;
  self->remote_channel_number = remote_channel_number;

  return &self->super;
}

806
static void
807
handle_channel_open(struct ssh_connection *connection,
808
		    struct simple_buffer *buffer)
Niels Möller's avatar
Niels Möller committed
809
{
810
  struct channel_open_info info;
811
812

  trace("handle_channel_open\n");
813
  
814
815
816
817
818
  if (parse_string(buffer, &info.type_length, &info.type_data)
      && parse_uint32(buffer, &info.remote_channel_number)
      && parse_uint32(buffer, &info.send_window_size)
      && parse_uint32(buffer, &info.send_max_packet))
  {
819
      struct channel_open *open = NULL;
Niels Möller's avatar
Niels Möller committed
820

821
      info.type = lookup_atom(info.type_length, info.type_data);
Niels Möller's avatar
Niels Möller committed
822

823
824
825
826
827
828
829
830
      /* We don't support larger packets than the default,
       * SSH_MAX_PACKET. */
      if (info.send_max_packet > SSH_MAX_PACKET)
	{
	  werror("handle_channel_open: The remote end asked for really large packets.\n");
	  info.send_max_packet = SSH_MAX_PACKET;
	}
      
831
      if (connection->pending_close)
Niels Möller's avatar
Niels Möller committed
832
833
834
	{
	  /* We are waiting for channels to close. Don't open any new ones. */

835
	  SSH_CONNECTION_WRITE(connection,
836
837
838
839
		       format_open_failure(
			 info.remote_channel_number,
			 SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
			 "Waiting for channels to close.", ""));
Niels Möller's avatar
Niels Möller committed
840
841
842
	}
      else
	{
843
	  if (info.type)
844
	    {
845
	      CAST_SUBTYPE(channel_open, o,
846
			   ALIST_GET(connection->channel_types,
847
848
849
850
851
				     info.type));
	      open = o;
	    }

	  if (!open)
852
	    open = connection->open_fallback;
853
854
855
	  
	  if (!open)
	    {
856
857
	      werror("handle_channel_open: Unknown channel type `%ps'\n",
		     info.type_length, info.type_data);
858
	      SSH_CONNECTION_WRITE(connection,
859
860
861
862
			   format_open_failure(
			     info.remote_channel_number,
			     SSH_OPEN_UNKNOWN_CHANNEL_TYPE,
			     "Unknown channel type", ""));
863
864
865
	    }
	  else
	    {
866
	      int local_number = ssh_connection_alloc_channel(connection);
867
868

	      if (local_number < 0)
869
		{
870
		  SSH_CONNECTION_WRITE(connection,
871
872
873
874
			       format_open_failure(
				 info.remote_channel_number,
				 SSH_OPEN_RESOURCE_SHORTAGE,
				 "Channel limit exceeded.", ""));
875
876
877
		  return;
		}
	      
878
	      CHANNEL_OPEN(open, connection,
879
			   &info,
880
			   buffer,
881
			   make_channel_open_continuation(connection,
882
883
884
885
							  local_number,
							  info.remote_channel_number,
							  info.send_window_size,
							  info.send_max_packet),
886
			   make_exc_channel_open_handler(connection,
887
888
889
890
							 local_number,
							 info.remote_channel_number,
							 HANDLER_CONTEXT));

891
	    }
Niels Möller's avatar
Niels Möller committed
892
	}
Niels Möller's avatar
Niels Möller committed
893
    }
Niels Möller's avatar
Niels Möller committed
894
  else
895
    SSH_CONNECTION_ERROR(connection, "Invalid SSH_MSG_CHANNEL_OPEN message.");
Niels Möller's avatar
Niels Möller committed
896
897
}     

898
static void
899
handle_adjust_window(struct ssh_connection *connection,
900
		     struct simple_buffer *buffer)
Niels Möller's avatar
Niels Möller committed
901
{
902
903
  uint32_t channel_number;
  uint32_t size;
Niels Möller's avatar
Niels Möller committed
904

905
906
907
  if (parse_uint32(buffer, &channel_number)
      && parse_uint32(buffer, &size)
      && parse_eod(buffer))
Niels Möller's avatar
Niels Möller committed
908
    {
909
      struct ssh_channel *channel = lookup_channel(connection, channel_number);
Niels Möller's avatar
Niels Möller committed
910

Niels Möller's avatar
Niels Möller committed
911
      if (channel
912
	  && !(channel->flags & CHANNEL_RECEIVED_CLOSE))
Niels Möller's avatar
Niels Möller committed
913
	{
914
	  if (! (channel->flags & (CHANNEL_SENT_CLOSE | CHANNEL_SENT_EOF)))
Niels Möller's avatar
Niels Möller committed
915
916
	    {
	      channel->send_window_size += size;
917

918
	      if (channel->send_window_size && channel->send_adjust)
919
		CHANNEL_SEND_ADJUST(channel, size);
Niels Möller's avatar
Niels Möller committed
920
	    }
Niels Möller's avatar
Niels Möller committed
921
	}
Niels Möller's avatar
Niels Möller committed
922
923
924
925
      else
	{
	  werror("SSH_MSG_CHANNEL_WINDOW_ADJUST on nonexistant or closed "
		 "channel %i\n", channel_number);
926
	  SSH_CONNECTION_ERROR(connection, "Unexpected CHANNEL_WINDOW_ADJUST");
Niels Möller's avatar
Niels Möller committed
927
928
929
	}
    }
  else
930
    SSH_CONNECTION_ERROR(connection, "Invalid CHANNEL_WINDOW_ADJUST message.");
Niels Möller's avatar
Niels Möller committed
931
932
}

933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
/* Common processing for ordinary and "extended" data. */
static int
receive_data_common(struct ssh_channel *channel,
		    int type, uint32_t length, const uint8_t *data)
{
  if (channel->receive
      && !(channel->flags & (CHANNEL_RECEIVED_EOF
			     | CHANNEL_RECEIVED_CLOSE)))
    {
      if (channel->flags & CHANNEL_SENT_CLOSE)
	{
	  werror("Ignoring data on channel which is closing\n");
	  return 1;
	}
      else
	{
	  if (length > channel->rec_max_packet)
	    {
	      werror("Channel data larger than rec_max_packet. Extra data ignored.\n");
	      length = channel->rec_max_packet;
	    }

	  if (length > channel->rec_window_size)
	    {
	      /* Truncate data to fit window */
	      werror("Channel data overflow. Extra data ignored.\n");
	      debug("   (type = %i, data->length=%i, rec_window_size=%i).\n",
		    type, length, channel->rec_window_size);

	      length = channel->rec_window_size;
	    }

	  if (!length)
	    {
	      /* Ignore data packet */
	      return 1;
	    }
	  channel->rec_window_size -= length;

	  CHANNEL_RECEIVE(channel, type, length, data);
	}
      return 1;
    }
  else
    return 0;
}

980
static void
981
handle_channel_data(struct ssh_connection *connection,
982
		    struct simple_buffer *buffer)
Niels Möller's avatar
Niels Möller committed
983
{
984
  uint32_t channel_number;
985
986
  uint32_t length;
  const uint8_t *data;
Niels Möller's avatar
Niels Möller committed
987
  
988
  if (parse_uint32(buffer, &channel_number)
989
      && parse_string(buffer, &length, &data)
990
      && parse_eod(buffer))
Niels Möller's avatar
Niels Möller committed
991
    {
992
993