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
738

  CHANNEL_EVENT(channel, CHANNEL_EVENT_CONFIRM);  
739
}
Niels Möller's avatar
Niels Möller committed
740

Niels Möller's avatar
Niels Möller committed
741
static struct command_continuation *
742
make_channel_open_continuation(struct ssh_connection *connection,
743
744
745
746
			       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
747
748
{
  NEW(channel_open_continuation, self);
Niels Möller's avatar
Niels Möller committed
749

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

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

770
771
772
static void
do_exc_channel_open_handler(struct exception_handler *s,
			    const struct exception *e)
Niels Möller's avatar
Niels Möller committed
773
774
{
  CAST(exc_channel_open_handler, self, s);
775
776
777
  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
778

779
780
781
782
783
784
785
786
787
788
  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
789
790
791
}

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

  return &self->super;
}

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

  trace("handle_channel_open\n");
815
  
816
817
818
819
820
  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))
  {
821
      struct channel_open *open = NULL;
Niels Möller's avatar
Niels Möller committed
822

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

825
826
827
828
829
830
831
832
      /* 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;
	}
      
833
      if (connection->pending_close)
Niels Möller's avatar
Niels Möller committed
834
835
836
	{
	  /* We are waiting for channels to close. Don't open any new ones. */

837
	  SSH_CONNECTION_WRITE(connection,
838
839
840
841
		       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
842
843
844
	}
      else
	{
845
	  if (info.type)
846
	    {
847
	      CAST_SUBTYPE(channel_open, o,
848
			   ALIST_GET(connection->channel_types,
849
850
851
852
853
				     info.type));
	      open = o;
	    }

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

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

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

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

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

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

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

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