channel.c 42.1 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
/* 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
Niels Möller's avatar
Niels Möller committed
69
70
71
      CHANNEL_OPEN_CONFIRMATION. Generate a CHANNEL_EVENT_CONFIRM on
      the channel. On error, deallocate channel number, and reply with
      CHANNEL_OPEN_FAILURE.
72
*/
73

74
struct exception *
75
make_channel_open_exception(uint32_t error_code, const char *msg)
Niels Möller's avatar
Niels Möller committed
76
{
Niels Möller's avatar
Niels Möller committed
77
78
79
80
81
82
83
84
85
86
87
88
#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
89

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

94

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

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

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* 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;
    }
}

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

146
  debug("format_open_confirmation: rec_window_size = %i,\n"
147
	"                          rec_max_packet = %i,\n",
148
       channel->rec_window_size,
149
       channel->rec_max_packet);
150
151
152
153
154
155
156
157
  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);

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

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

  return packet;
#undef CONFIRM_FORMAT
#undef CONFIRM_ARGS
}

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

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

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

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

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

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

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

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

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


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


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

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

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

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

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

      return channel;
    }
  return NULL;
263
264
}

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

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

279
280
/* FIXME: It seems suboptimal to send a window adjust message for
 * *every* write that we do. A better scheme might be as follows:
281
282
283
284
285
286
287
 *
 * 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. */
288
289
void
channel_adjust_rec_window(struct ssh_channel *channel, uint32_t written)
290
{
291
292
  /* NOTE: The channel object (referenced as a flow-control callback)
   * may live longer than the actual channel. */
293
294
  if (written && ! (channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_RECEIVED_CLOSE
				      | CHANNEL_SENT_CLOSE)))
295
    SSH_CONNECTION_WRITE(channel->connection, prepare_window_adjust(channel, written));
296
297
}

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

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

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

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

  return self;
}

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

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

  assert(!object_queue_is_empty(q));

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

521
522
/* FIXME: Don't store the channel here, instead have it passed as the
 * argument of the continuation. This might also allow some
523
524
525
526
527
 * 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. */
528
529
530
531
532
533
534
535
536
537
538

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

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

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

      object_queue_remove_head(q);

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

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

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

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

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

578
579
  trace("make_channel_request_response\n");

580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
  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)))
*/

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

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

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

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

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

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

  return &self->super;
}

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

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

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

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

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

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


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

Niels Möller's avatar
Niels Möller committed
713
714
715
static void
do_channel_open_continue(struct command_continuation *c,
			 struct lsh_object *value)
716
717
{
  CAST(channel_open_continuation, self, c);
Niels Möller's avatar
Niels Möller committed
718
719
720
721
722
723
724
  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. */
725
726
  channel->send_window_size = self->send_window_size;
  channel->send_max_packet = self->send_max_packet;
727
  channel->remote_channel_number = self->remote_channel_number;
Niels Möller's avatar
Niels Möller committed
728

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

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

736
  SSH_CONNECTION_WRITE(self->connection,
737
		       format_open_confirmation(channel, ""));
738
739

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

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

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

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

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

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

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

  return &self->super;
}

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

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

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

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

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

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

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

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

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

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

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

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

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