channel.c 42.9 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
/* Opening a new channel: There are two cases, depending on which side
47
   sends the CHANNEL_OPEN. When we send it, the following
48
   steps are taken:
49
50
51

   1. Create a new channel object of the appropriate type.
   
52
53
54
   2. Call channel_open_new_v or channel_open_new_type. This allocates
      a channel number, registers the object, and sends a CHANNEL_OPEN
      request.
55
56
57

   3. If the remote end replies with CHANNEL_OPEN_CONFIRMATION, the
      channel's event handler is invoked, with CHANNEL_EVENT_CONFIRM.
58
59
      If the remote end replies with CHANNEL_OPEN_FAILURE, then event
      handler is invoked with CHANNEL_EVENT_DENY, and then the channel
60
61
62
63
      is killed.

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

64
65
   1. Receive CHANNEL_OPEN. Allocate a channel number, and invoke the
      CHANNEL_OPEN method corresponding to the channel type.
66
67
68
69
70

   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
71
72
73
      CHANNEL_OPEN_CONFIRMATION. Generate a CHANNEL_EVENT_CONFIRM on
      the channel. On error, deallocate channel number, and reply with
      CHANNEL_OPEN_FAILURE.
74
*/
75

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

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

96

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

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

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

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

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

160
  ssh_format_write(CONFIRM_FORMAT, packet, 0, CONFIRM_ARGS);
161
162

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

  return packet;
#undef CONFIRM_FORMAT
#undef CONFIRM_ARGS
}

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

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

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

191
static struct lsh_string *
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
format_channel_data(uint32_t number, uint32_t length, const uint8_t *data)
{
  return ssh_format("%c%i%s", SSH_MSG_CHANNEL_DATA,
		    number, length, data);
}

static struct lsh_string *
format_channel_extended_data(uint32_t number, uint32_t type,
			     uint32_t length, const uint8_t *data)
{
  return ssh_format("%c%i%i%s", SSH_MSG_CHANNEL_EXTENDED_DATA,
		    number, type, length, data);
}

static struct lsh_string *
format_channel_window_adjust(uint32_t number, uint32_t add)
208
209
210
{
  return ssh_format("%c%i%i",
		    SSH_MSG_CHANNEL_WINDOW_ADJUST,
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
		    number, add);
}

static struct lsh_string *
format_channel_close(struct ssh_channel *channel)
{
  return ssh_format("%c%i",
		    SSH_MSG_CHANNEL_CLOSE,
		    channel->remote_channel_number);
}

static struct lsh_string *
format_channel_eof(uint32_t number)
{
  return ssh_format("%c%i",
		    SSH_MSG_CHANNEL_EOF, number);
227
228
}

229
static void
230
channel_finished(struct ssh_channel *channel)
Niels Möller's avatar
Niels Möller committed
231
{
232
233
234
  if (!channel->super.alive)
    werror("channel_finished called on a dead channel.\n");
  else
Niels Möller's avatar
Niels Möller committed
235
    {
236
      struct ssh_connection *connection = channel->connection;
Niels Möller's avatar
Niels Möller committed
237

238
239
      trace("channel_finished: Deallocating channel %i\n", channel->local_channel_number);
      KILL_RESOURCE(&channel->super);
240

241
      /* Disassociate from the connection. */
242
      channel->connection = NULL;
Niels Möller's avatar
Niels Möller committed
243
      
244
      ssh_connection_dealloc_channel(connection, channel->local_channel_number);
245

246
247
      trace("channel_finished: connection->pending_close = %i,\n"
	    "                  connection->channel_count = %i\n",
248
	    connection->pending_close, connection->channel_count);
249

250
251
      if (connection->pending_close && !connection->channel_count)
	KILL_RESOURCE(&connection->super);
Niels Möller's avatar
Niels Möller committed
252
253
254
255
    }
}


256
/* Channel objects */
Niels Möller's avatar
Niels Möller committed
257

258
259
/* In principle, this belongs to connection.h, but it needs the
   definition of ssh_channel. */
260
void
261
262
263
ssh_connection_register_channel(struct ssh_connection *connection,
				uint32_t local_channel_number,
				struct ssh_channel *channel)
264
{
265
  assert(local_channel_number < connection->used_channels);
266
  assert(!connection->channels[local_channel_number]);
267
  assert(connection->alloc_state[local_channel_number] != CHANNEL_FREE);
268

269
270
  trace("ssh_connection_register_channel: local_channel_number: %i.\n",
	local_channel_number);
271

272
  connection->channels[local_channel_number] = channel;
273
  channel->connection = connection;
274
  remember_resource(connection->resources, &channel->super);  
Niels Möller's avatar
Niels Möller committed
275
276
}

277
278
279
static void
send_window_adjust(struct ssh_channel *channel,
		   uint32_t add)
Niels Möller's avatar
Niels Möller committed
280
{
281
  channel->rec_window_size += add;
282

283
284
285
  SSH_CONNECTION_WRITE(
    channel->connection,   
    format_channel_window_adjust(channel->remote_channel_number, add));
Niels Möller's avatar
Niels Möller committed
286
287
}

288
289
/* FIXME: It seems suboptimal to send a window adjust message for
 * *every* write that we do. A better scheme might be as follows:
290
291
292
293
294
295
296
 *
 * 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. */
297
298
void
channel_adjust_rec_window(struct ssh_channel *channel, uint32_t written)
299
{
300
301
  /* NOTE: The channel object (referenced as a flow-control callback)
   * may live longer than the actual channel. */
302
303
  if (written && ! (channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_RECEIVED_CLOSE
				      | CHANNEL_SENT_CLOSE)))
304
    send_window_adjust(channel, written);
305
306
}

307
308
void
channel_start_receive(struct ssh_channel *channel,
309
		      uint32_t initial_window_size)
310
{
311
  if (channel->rec_window_size < initial_window_size)
312
313
    send_window_adjust(channel,
		       initial_window_size - channel->rec_window_size);
314
315
}

Niels Möller's avatar
Niels Möller committed
316
/* Channel related messages */
317
318
319

/* GABA:
   (class
320
     (name request_status)
321
322
323
324
325
326
327
     (vars
       ; -1 for still active requests,
       ; 0 for failure,
       ; 1 for success
       (status . int)))
*/

328
329
static struct request_status *
make_request_status(void)
330
{
331
  NEW(request_status, self);
332
333
334
335
336
337
338
  self->status = -1;

  return self;
}

/* GABA:
   (class
339
340
     (name global_request_continuation)
     (super command_continuation)
341
     (vars
342
       (connection object ssh_connection)
343
       (active object request_status)))
344
345
*/

346
static void 
347
send_global_request_responses(struct ssh_connection *connection)
348
{
349
  struct object_queue *q = &connection->active_global_requests;
350
351
352
353
354
355
356
357

  assert(!object_queue_is_empty(q));

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

361
      SSH_CONNECTION_WRITE(connection, (n->status
362
363
				  ? format_global_success()
				  : format_global_failure()));
364
365
366
    }
}

367
368
369
static void
do_global_request_response(struct command_continuation *s,
			   struct lsh_object *x UNUSED)
370
{
371
  CAST(global_request_continuation, self, s);
372

373
374
  assert(self->active->status == -1);
  self->active->status = 1;
375

376
  send_global_request_responses(self->connection);
377
}
378

379
static struct command_continuation *
380
make_global_request_response(struct ssh_connection *connection,
381
382
383
384
385
			     struct request_status *active)
{
  NEW(global_request_continuation, self);

  self->super.c = do_global_request_response;
386
  self->connection = connection;
387
388
  self->active = active;
   
389
390
  return &self->super;
}
391
392
393
394
395
396
397


/* GABA:
   (class
     (name global_request_exception_handler)
     (super exception_handler)
     (vars
398
       (connection object ssh_connection)
399
400
401
       (active object request_status)))
*/

402
/* All exceptions are treated as a failure. */
403
static void 
404
do_exc_global_request_handler(struct exception_handler *c,
Niels Möller's avatar
Niels Möller committed
405
			      const struct exception *e)
406
407
{
  CAST(global_request_exception_handler, self, c);
408
409
410
411
412
413

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

  werror("Denying global request: %z\n", e->msg);
  send_global_request_responses(self->connection);
414
415
416
}

static struct exception_handler *
417
make_global_request_exception_handler(struct ssh_connection *connection,
418
419
				      struct request_status *active,
				      const char *context)
Niels Möller's avatar
Niels Möller committed
420
{
421
422
  NEW(global_request_exception_handler, self);

423
  self->super.raise = do_exc_global_request_handler;
424
425
  self->super.context = context;
  self->active = active;
426
  self->connection = connection;
427
428
  return &self->super;
}
Niels Möller's avatar
Niels Möller committed
429

430
static void
431
handle_global_request(struct ssh_connection *connection,
432
		      struct simple_buffer *buffer)
433
{
434
  enum lsh_atom name;
Niels Möller's avatar
Niels Möller committed
435
436
  int want_reply;
  
437
438
  if (parse_atom(buffer, &name)
      && parse_boolean(buffer, &want_reply))
Niels Möller's avatar
Niels Möller committed
439
    {
440
441
      struct global_request *req = NULL;

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

482
static void
483
handle_global_success(struct ssh_connection *connection,
484
		      struct simple_buffer *buffer)
485
{
486
  if (!parse_eod(buffer))
Niels Möller's avatar
Niels Möller committed
487
    {
488
      SSH_CONNECTION_ERROR(connection, "Invalid GLOBAL_REQUEST_SUCCESS message.");
489
      return;
Niels Möller's avatar
Niels Möller committed
490
    }
491

492
  if (object_queue_is_empty(&connection->pending_global_requests))
493
494
    {
      werror("do_global_request_success: Unexpected message, ignoring.\n");
Niels Möller's avatar
Niels Möller committed
495
      return;
496
497
    }
  {
498
    CAST_SUBTYPE(command_context, ctx,
499
500
		 object_queue_remove_head(&connection->pending_global_requests));
    COMMAND_RETURN(ctx->c, connection);
501
502
503
  }
}

504
struct exception global_request_exception =
505
STATIC_EXCEPTION(EXC_GLOBAL_REQUEST, 0, "Global request failed");
506

507
static void
508
handle_global_failure(struct ssh_connection *connection,
509
		      struct simple_buffer *buffer)
510
{
511
  if (!parse_eod(buffer))
Niels Möller's avatar
Niels Möller committed
512
    {
513
      SSH_CONNECTION_ERROR(connection, "Invalid GLOBAL_REQUEST_FAILURE message.");
514
      return;
Niels Möller's avatar
Niels Möller committed
515
    }
516

517
  if (object_queue_is_empty(&connection->pending_global_requests))
518
519
520
    {
      werror("do_global_request_failure: Unexpected message, ignoring.\n");
    }
Niels Möller's avatar
Niels Möller committed
521
522
523
  else
    {
      CAST_SUBTYPE(command_context, ctx,
524
		   object_queue_remove_head(&connection->pending_global_requests));
Niels Möller's avatar
Niels Möller committed
525
526
      EXCEPTION_RAISE(ctx->e, &global_request_exception);
    }
527
528
}

529
530
/* FIXME: Don't store the channel here, instead have it passed as the
 * argument of the continuation. This might also allow some
531
532
533
534
535
 * 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. */
536
537
538
539
540
541
542
543
544
545
546

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

static void
547
send_channel_request_responses(struct ssh_channel *channel)
548
{
549
550
551
  struct object_queue *q = &channel->active_requests;
  assert(!object_queue_is_empty(q));

552
553
554
555
556
557
558
559
  for (;;)
    {
      CAST(request_status, n, object_queue_peek_head(q));
      if (!n || (n->status < 0))
	break;

      object_queue_remove_head(q);

560
      SSH_CONNECTION_WRITE(channel->connection,
561
562
563
		   (n->status
		    ? format_channel_success(channel->remote_channel_number)
		    : format_channel_failure(channel->remote_channel_number)));
564
565
566
567
568
569
570
571
572
    }
}

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

573
  trace("do_channel_request_response\n");
574
575
576
  assert(self->active->status == -1);
  self->active->status = 1;

577
  send_channel_request_responses(self->channel);
578
579
580
}

static struct command_continuation *
581
make_channel_request_response(struct ssh_channel *channel,
582
583
584
585
			      struct request_status *active)
{
  NEW(channel_request_continuation, self);

586
587
  trace("make_channel_request_response\n");

588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
  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)))
*/

604
/* All exceptions are treated as a failure. */
605
static void 
606
607
do_exc_channel_request_handler(struct exception_handler *c,
			       const struct exception *e)
608
609
{
  CAST(channel_request_exception_handler, self, c);
610
611
612
613
614
615

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

  werror("Denying channel request: %z\n", e->msg);
  send_channel_request_responses(self->channel);
616
617
618
}

static struct exception_handler *
619
make_channel_request_exception_handler(struct ssh_channel *channel,
620
621
622
623
624
				       struct request_status *active,
				       const char *context)
{
  NEW(channel_request_exception_handler, self);

625
  self->super.raise = do_exc_channel_request_handler;
626
  self->super.context = context;
627

628
629
630
631
632
633
  self->channel = channel;
  self->active = active;

  return &self->super;
}

634
static void
635
handle_channel_request(struct ssh_connection *connection,
636
		       struct simple_buffer *buffer)
637
{
638
  uint32_t channel_number;
639
  struct channel_request_info info;
640
  
641
  if (parse_uint32(buffer, &channel_number)
642
643
      &&parse_string(buffer,
		     &info.type_length, &info.type_data)
644
      && parse_boolean(buffer, &info.want_reply))
645
646
647
648
649
    {    
      struct ssh_channel *channel
	= ssh_connection_lookup_channel(connection,
					channel_number,
					CHANNEL_ALLOC_ACTIVE);
650
651
      if (channel)
	{
652
	  if (channel->request_methods)
653
	    {
654
655
	      channel->request_methods->request(channel, &info, buffer);
	      return;
656
	    }
657
	  else if (channel->request_types)
658
	    {
659
660
	      struct command_continuation *c;
	      struct exception_handler *e;
661
	      struct channel_request *req;
662

663
664
	      trace("handle_channel_request: Request type `%ps' on channel %i\n",
		    info.type_length, info.type_data, channel_number);
665

666
667
668
669
670
671
672
673
674
675
	      info.type = lookup_atom(info.type_length, info.type_data);

	      {
		CAST_SUBTYPE(channel_request, r,
			     ALIST_GET(channel->request_types, info.type));

		req = r;
	      }

	      if (req)
676
		{
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
		  if (info.want_reply)
		    {
		      struct request_status *a = make_request_status();

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

		      c = make_channel_request_response(channel, a);
		      e = make_channel_request_exception_handler(channel, a,
								 HANDLER_CONTEXT);
		    }
		  else
		    {
		      /* We should ignore failures. */
		      c = &discard_continuation;
		      e = &ignore_exception_handler;
		    }
694
	      
695
696
697
		  CHANNEL_REQUEST(req, channel, &info, buffer, c, e);
		  return;
		}
698
	    }
699
700
701
702
703

	  if (info.want_reply)
	    SSH_CONNECTION_WRITE(connection,
				 format_channel_failure(channel->remote_channel_number));
	  return;
704
	}
705
706
707
708
      
      werror("SSH_MSG_CHANNEL_REQUEST on nonexistant channel %i.\n",
	     channel_number);
      /* Fall through to error case. */
709
    }
710
711
712
  
  SSH_CONNECTION_ERROR(connection,
		       "Invalid SSH_MSG_CHANNEL_REQUEST message.");
713
714
715
}


Niels Möller's avatar
Niels Möller committed
716
/* GABA:
717
718
719
720
   (class
     (name channel_open_continuation)
     (super command_continuation)
     (vars
721
       (connection object ssh_connection)
722
723
724
725
       (local_channel_number . uint32_t)
       (remote_channel_number . uint32_t)
       (send_window_size . uint32_t)
       (send_max_packet . uint32_t)))
726
*/
727

Niels Möller's avatar
Niels Möller committed
728
729
730
static void
do_channel_open_continue(struct command_continuation *c,
			 struct lsh_object *value)
731
732
{
  CAST(channel_open_continuation, self, c);
Niels Möller's avatar
Niels Möller committed
733
734
735
736
737
738
739
  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. */
740
741
  channel->send_window_size = self->send_window_size;
  channel->send_max_packet = self->send_max_packet;
742
  channel->remote_channel_number = self->remote_channel_number;
743
744
745
746
747
748
  
  ssh_connection_register_channel(self->connection,
				  self->local_channel_number,
				  channel);
  ssh_connection_activate_channel(self->connection,
				  self->local_channel_number);
Niels Möller's avatar
Niels Möller committed
749
750
751
752

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

753
  SSH_CONNECTION_WRITE(self->connection,
754
		       format_open_confirmation(channel, ""));
755
756

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

Niels Möller's avatar
Niels Möller committed
759
static struct command_continuation *
760
make_channel_open_continuation(struct ssh_connection *connection,
761
762
763
764
			       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
765
766
{
  NEW(channel_open_continuation, self);
Niels Möller's avatar
Niels Möller committed
767

Niels Möller's avatar
Niels Möller committed
768
  self->super.c = do_channel_open_continue;
769
  self->connection = connection;
Niels Möller's avatar
Niels Möller committed
770
771
  self->local_channel_number = local_channel_number;
  self->remote_channel_number = remote_channel_number;
772
773
  self->send_window_size = send_window_size;
  self->send_max_packet = send_max_packet;
Niels Möller's avatar
Niels Möller committed
774

Niels Möller's avatar
Niels Möller committed
775
  return &self->super;
Niels Möller's avatar
Niels Möller committed
776
777
778
779
780
781
782
}
			       
/* GABA:
   (class
     (name exc_channel_open_handler)
     (super exception_handler)
     (vars
783
       (connection object ssh_connection)
784
785
       (local_channel_number . uint32_t)
       (remote_channel_number . uint32_t)))
Niels Möller's avatar
Niels Möller committed
786
787
*/

788
789
790
static void
do_exc_channel_open_handler(struct exception_handler *s,
			    const struct exception *e)
Niels Möller's avatar
Niels Möller committed
791
792
{
  CAST(exc_channel_open_handler, self, s);
793
794
795
  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
796

797
798
799
  assert(self->local_channel_number < connection->used_channels);  
  assert(connection->alloc_state[self->local_channel_number]
	 == CHANNEL_ALLOC_SENT_OPEN);
800
801
802
803
804
805
806
807
808
  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
809
810
811
}

static struct exception_handler *
812
make_exc_channel_open_handler(struct ssh_connection *connection,
813
814
			      uint32_t local_channel_number,
			      uint32_t remote_channel_number,
815
			      const char *context)
Niels Möller's avatar
Niels Möller committed
816
{
Niels Möller's avatar
Niels Möller committed
817
818
  NEW(exc_channel_open_handler, self);
  self->super.raise = do_exc_channel_open_handler;
819
820
  self->super.context = context;
  
821
  self->connection = connection;
Niels Möller's avatar
Niels Möller committed
822
823
824
825
826
827
  self->local_channel_number = local_channel_number;
  self->remote_channel_number = remote_channel_number;

  return &self->super;
}

828
static void
829
handle_channel_open(struct ssh_connection *connection,
830
		    struct simple_buffer *buffer)
Niels Möller's avatar
Niels Möller committed
831
{
832
  struct channel_open_info info;
833
834

  trace("handle_channel_open\n");
835
  
836
837
838
839
840
  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))
  {
841
      struct channel_open *open = NULL;
Niels Möller's avatar
Niels Möller committed
842

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

845
846
847
848
849
850
851
852
      /* 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;
	}
      
853
      if (connection->pending_close)
Niels Möller's avatar
Niels Möller committed
854
855
856
	{
	  /* We are waiting for channels to close. Don't open any new ones. */

857
	  SSH_CONNECTION_WRITE(connection,
858
859
860
861
		       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
862
863
864
	}
      else
	{
865
	  if (info.type)
866
	    {
867
	      CAST_SUBTYPE(channel_open, o,
868
			   ALIST_GET(connection->channel_types,
869
870
871
872
873
				     info.type));
	      open = o;
	    }
	  if (!open)
	    {
874
875
	      werror("handle_channel_open: Unknown channel type `%ps'\n",
		     info.type_length, info.type_data);
876
	      SSH_CONNECTION_WRITE(connection,
877
878
879
880
			   format_open_failure(
			     info.remote_channel_number,
			     SSH_OPEN_UNKNOWN_CHANNEL_TYPE,
			     "Unknown channel type", ""));
881
882
883
	    }
	  else
	    {
884
885
886
	      int local_number
		= ssh_connection_alloc_channel(connection,
					       CHANNEL_ALLOC_RECEIVED_OPEN);
887
888

	      if (local_number < 0)
889
		{
890
		  SSH_CONNECTION_WRITE(connection,
891
892
893
894
			       format_open_failure(
				 info.remote_channel_number,
				 SSH_OPEN_RESOURCE_SHORTAGE,
				 "Channel limit exceeded.", ""));
895
896
897
		  return;
		}
	      
898
	      CHANNEL_OPEN(open, connection,
899
			   &info,
900
			   buffer,
901
			   make_channel_open_continuation(connection,
902
903
904
905
							  local_number,
							  info.remote_channel_number,
							  info.send_window_size,
							  info.send_max_packet),
906
			   make_exc_channel_open_handler(connection,
907
908
909
910
							 local_number,
							 info.remote_channel_number,
							 HANDLER_CONTEXT));

911
	    }
Niels Möller's avatar
Niels Möller committed
912
	}
Niels Möller's avatar
Niels Möller committed
913
    }
Niels Möller's avatar
Niels Möller committed
914
  else
915
    SSH_CONNECTION_ERROR(connection, "Invalid SSH_MSG_CHANNEL_OPEN message.");
Niels Möller's avatar
Niels Möller committed
916
917
}     

918
static void
919
handle_adjust_window(struct ssh_connection *connection,
920
		     struct simple_buffer *buffer)
Niels Möller's avatar
Niels Möller committed
921
{
922
923
  uint32_t channel_number;
  uint32_t size;
Niels Möller's avatar
Niels Möller committed
924

925
926
927
  if (parse_uint32(buffer, &channel_number)
      && parse_uint32(buffer, &size)
      && parse_eod(buffer))
Niels Möller's avatar
Niels Möller committed
928
    {
929
930
931
932
      struct ssh_channel *channel
	= ssh_connection_lookup_channel(connection,
					channel_number,
					CHANNEL_ALLOC_ACTIVE);
Niels Möller's avatar
Niels Möller committed
933

Niels Möller's avatar
Niels Möller committed
934
      if (channel
935
	  && !(channel->flags & CHANNEL_RECEIVED_CLOSE))
Niels Möller's avatar
Niels Möller committed
936
	{
937
	  if (! (channel->flags & (CHANNEL_SENT_CLOSE | CHANNEL_SENT_EOF)))
Niels Möller's avatar
Niels Möller committed
938
939
	    {
	      channel->send_window_size += size;
940

941
	      if (channel->send_window_size && channel->send_adjust)
942
		CHANNEL_SEND_ADJUST(channel, size);
Niels Möller's avatar
Niels Möller committed
943
	    }
Niels Möller's avatar
Niels Möller committed
944
	}
Niels Möller's avatar
Niels Möller committed
945
946
947
948
      else
	{
	  werror("SSH_MSG_CHANNEL_WINDOW_ADJUST on nonexistant or closed "
		 "channel %i\n", channel_number);
949
	  SSH_CONNECTION_ERROR(connection, "Unexpected CHANNEL_WINDOW_ADJUST");
Niels Möller's avatar
Niels Möller committed
950
951
952
	}
    }
  else
953
    SSH_CONNECTION_ERROR(connection, "Invalid CHANNEL_WINDOW_ADJUST message.");
Niels Möller's avatar
Niels Möller committed
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
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
/* 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;
}

1003
static void
1004
handle_channel_data(struct ssh_connection *connection,
1005
		    struct simple_buffer *buffer)
Niels Möller's avatar
Niels Möller committed
1006
{
1007
  uint32_t channel_number;
1008
1009
  uint32_t length;
  const uint8_t *data;
Niels Möller's avatar
Niels Möller committed
1010
  
1011
  if (parse_uint32(buffer, &channel_number)
1012
      && parse_string(buffer, &length, &data)
1013
      && parse_eod(buffer))
Niels Möller's avatar
Niels Möller committed
1014
    {
1015
      struct ssh_channel *channel
1016
1017
1018
	= ssh_connection_lookup_channel(connection,
					channel_number,
					CHANNEL_ALLOC_ACTIVE);
Niels Möller's avatar
Niels Möller committed
1019

1020
      if (channel)
Niels Möller's avatar
Niels Möller committed
1021
	{
1022
1023
1024
	  if (!receive_data_common(channel, CHANNEL_DATA,
				   length, data))
	    werror("Data on closed channel %i\n", channel_number);
Niels Möller's avatar
Niels Möller committed
1025
	}
Niels Möller's avatar
Niels Möller committed
1026
      else
1027
	werror("Data on non-existant channel %i\n", channel_number);
Niels Möller's avatar
Niels Möller committed
1028
1029
    }
  else
1030
    SSH_CONNECTION_ERROR(connection, "Invalid CHANNEL_DATA message.");
Niels Möller's avatar
Niels Möller committed
1031
1032
}

1033
static void
1034
handle_channel_extended_data(struct ssh_connection *connection,
1035
			     struct simple_buffer *buffer)
Niels Möller's avatar
Niels Möller committed
1036
{
1037
1038
  uint32_t channel_number;
  uint32_t type;
1039
1040
  uint32_t length;
  const uint8_t *data;
Niels Möller's avatar
Niels Möller committed
1041
  
1042
1043