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

   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.
57
58
      If the remote end replies with CHANNEL_OPEN_FAILURE, then event
      handler is invoked with CHANNEL_EVENT_DENY, and then the channel
59
60
61
62
63
64
65
66
67
68
69
      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
70
71
72
      CHANNEL_OPEN_CONFIRMATION. Generate a CHANNEL_EVENT_CONFIRM on
      the channel. On error, deallocate channel number, and reply with
      CHANNEL_OPEN_FAILURE.
73

74
75
   FIXME: The first part of this description is correct, but the
   second half is not yet accurate.
76
*/
77

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

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

98

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

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

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

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

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

162
  ssh_format_write(CONFIRM_FORMAT, packet, 0, CONFIRM_ARGS);
163
164

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

  return packet;
#undef CONFIRM_FORMAT
#undef CONFIRM_ARGS
}

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

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

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

193
static struct lsh_string *
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
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)
210
211
212
{
  return ssh_format("%c%i%i",
		    SSH_MSG_CHANNEL_WINDOW_ADJUST,
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
		    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);
229
230
}

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

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

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

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

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


258
/* Channel objects */
Niels Möller's avatar
Niels Möller committed
259

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

271
272
  trace("ssh_connection_register_channel: local_channel_number: %i.\n",
	local_channel_number);
273

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

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

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

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

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

Niels Möller's avatar
Niels Möller committed
318
/* Channel related messages */
319
320
321

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

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

  return self;
}

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

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

  assert(!object_queue_is_empty(q));

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

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

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

375
376
  assert(self->active->status == -1);
  self->active->status = 1;
377

378
  send_global_request_responses(self->connection);
379
}
380

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      object_queue_remove_head(q);

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

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

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

579
  send_channel_request_responses(self->channel);
580
581
582
}

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

588
589
  trace("make_channel_request_response\n");

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

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

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

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

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

627
  self->super.raise = do_exc_channel_request_handler;
628
  self->super.context = context;
629

630
631
632
633
634
635
  self->channel = channel;
  self->active = active;

  return &self->super;
}

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

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

668
669
670
671
672
673
674
675
676
677
	      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)
678
		{
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
		  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;
		    }
696
	      
697
698
699
		  CHANNEL_REQUEST(req, channel, &info, buffer, c, e);
		  return;
		}
700
	    }
701
702
703
704
705

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


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

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

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

755
  SSH_CONNECTION_WRITE(self->connection,
756
		       format_open_confirmation(channel, ""));
757
758

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

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

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

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

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

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

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

  return &self->super;
}

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

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

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

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

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

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

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

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

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

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

943
	      if (channel->send_window_size && channel->send_adjust)
944
		CHANNEL_SEND_ADJUST(channel, size);
Niels Möller's avatar
Niels Möller committed
945
	    }
Niels Möller's avatar
Niels Möller committed
946
	}
Niels Möller's avatar
Niels Möller committed
947
948
949
950
      else
	{
	  werror("SSH_MSG_CHANNEL_WINDOW_ADJUST on nonexistant or closed "
		 "channel %i\n", channel_number);
951
	  SSH_CONNECTION_ERROR(connection, "Unexpected CHANNEL_WINDOW_ADJUST");
Niels Möller's avatar
Niels Möller committed
952
953
954
	}
    }
  else
955
    SSH_CONNECTION_ERROR(connection, "Invalid CHANNEL_WINDOW_ADJUST message.");
Niels Möller's avatar
Niels Möller committed
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
1003
1004
/* 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;
}

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

1022
      if (channel)
Niels Möller's avatar
Niels Möller committed
1023
	{
1024
1025
1026
	  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
1027
	}
Niels Möller's avatar
Niels Möller committed
1028
      else
1029
	werror("Data on non-existant channel %i\n", channel_number);
Niels Möller's avatar
Niels Möller committed
1030
1031