channel.c 47.3 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
21
/* channel.c
 *
 * $Id$
 */

/* 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
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Niels Möller's avatar
Niels Möller committed
23
24
25
26
27
 */

#include "channel.h"

#include "format.h"
28
#include "io.h"
Niels Möller's avatar
Niels Möller committed
29
#include "read_data.h"
Niels Möller's avatar
Niels Möller committed
30
31
32
33
34
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"

#include <assert.h>
35
#include <string.h>
Niels Möller's avatar
Niels Möller committed
36

37
#define GABA_DEFINE
38
#include "channel.h.x"
39
#undef GABA_DEFINE
40

41
42
#include "channel.c.x"

43
/* GABA:
44
45
   (class
     (name connection_service)
46
     (super command)
47
48
49
50
     (vars
       ; Supported global requests 
       (global_requests object alist)

51
       (channel_types object alist) ))
52
53
54
55

       ; Initialize connection (for instance, request channels to be 
       ; opened or services to be forwarded).

56
       ; (start object connection_startup)))
57
58
*/

59
/* ;; GABA:
60
61
   (class
     (name global_request_handler)
62
     (super packet_handler)
63
64
65
66
     (vars
       (global_requests object alist)))
*/

67
/* ;; GABA:
68
69
   (class
     (name channel_open_handler)
70
     (super packet_handler)
71
72
73
74
     (vars
       (channel_types object alist)))
*/

Niels Möller's avatar
Niels Möller committed
75
/* ;; GABA:
76
77
78
79
80
81
82
83
84
   (class
     (name channel_open_response)
     (super channel_open_callback)
     (vars
       (remote_channel_number simple UINT32)
       (window_size simple UINT32)
       (max_packet simple UINT32)))
*/

Niels Möller's avatar
Niels Möller committed
85
86
87
88
89
struct lsh_string *format_global_failure(void)
{
  return ssh_format("%c", SSH_MSG_REQUEST_FAILURE);
}

90
91
92
93
94
struct lsh_string *format_global_success(void)
{
  return ssh_format("%c", SSH_MSG_REQUEST_SUCCESS);
}

95
96
struct lsh_string *format_open_confirmation(struct ssh_channel *channel,
					    UINT32 channel_number,
97
					    const char *format, ...)
98
99
100
101
102
103
{
  va_list args;
  UINT32 l1, l2;
  struct lsh_string *packet;

#define CONFIRM_FORMAT "%c%i%i%i%i"
104
105
#define CONFIRM_ARGS \
  SSH_MSG_CHANNEL_OPEN_CONFIRMATION, channel->channel_number, \
106
107
108
109
110
111
112
113
114
115
116
117
118
  channel_number, channel->rec_window_size, channel->rec_max_packet
    
  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);

  ssh_format_write(CONFIRM_FORMAT, l1, packet->data, CONFIRM_ARGS);

  va_start(args, format);
119
  ssh_vformat_write(format, l2, packet->data+l1, args);
120
121
122
123
124
125
126
  va_end(args);

  return packet;
#undef CONFIRM_FORMAT
#undef CONFIRM_ARGS
}

Niels Möller's avatar
Niels Möller committed
127
struct lsh_string *format_open_failure(UINT32 channel, UINT32 reason,
128
				       const char *msg, const char *language)
Niels Möller's avatar
Niels Möller committed
129
130
131
132
133
{
  return ssh_format("%c%i%i%z%z", SSH_MSG_CHANNEL_OPEN_FAILURE,
		    channel, reason, msg, language);
}

134
135
136
137
138
struct lsh_string *format_channel_success(UINT32 channel)
{
  return ssh_format("%c%i", SSH_MSG_CHANNEL_SUCCESS, channel);
}

Niels Möller's avatar
Niels Möller committed
139
140
141
142
143
struct lsh_string *format_channel_failure(UINT32 channel)
{
  return ssh_format("%c%i", SSH_MSG_CHANNEL_FAILURE, channel);
}

144
145
146
147
148
149
150
151
152
153
struct lsh_string *prepare_window_adjust(struct ssh_channel *channel,
					 UINT32 add)
{
  channel->rec_window_size += add;
  
  return ssh_format("%c%i%i",
		    SSH_MSG_CHANNEL_WINDOW_ADJUST,
		    channel->channel_number, add);
}

Niels Möller's avatar
Niels Möller committed
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/* ;; GABA:
   (class
     (name channel_exception)
     (super exception)
     (vars
       (channel object ssh_channel)
       (pending_close . int)))
*/

/* GABA:
   (class
     (name exc_finish_channel_handler)
     (super exception_handler)
     (vars
       (table object channel_table)
       ; Local channel number 
       (channel_number . UINT32)))
*/

static void do_exc_finish_channel_handler(struct exception_handler *s,
					  struct exception *e)
{
  CAST(exc_finish_channel_handler, self, s);

  switch (e->type)
    {
    case EXC_FINISH_CHANNEL:
      /* NOTE: This type of exception must be handled only once.
       * Perhaps we must add a liveness flag in the ssh_channel struct
       * to avoid deallocating dead channels? */
      {
#if 0
	CAST(channel_exception, exc, e);
	struct ssh_channel *channel = exc->channel;

	assert(self->channels[channel->local_number] == channel);
	
	/* Set the pending close flag, to indicate that no new
	 * channels should be opened, and that the connection should
	 * be closed once all the channels are closed. */
	if (exc->pending_close)
	  self->pending_close = 1;
#endif
	struct ssh_channel *channel
	  = self->table->channels[self->channel_number];

	assert(channel);
	
	if (channel->close)
	  CHANNEL_CLOSE(channel);
	
	dealloc_channel(self->table, self->channel_number);

	if (self->table->pending_close && !self->table->next_channel)
	  EXCEPTION_RAISE(self->super.parent, &finish_read_exception);
      }
      break;
    default:
      EXCEPTION_RAISE(self->super.parent, e);
    }
}

static struct exception_handler *
make_exc_finish_channel_handler(struct channel_table *table,
				UINT32 channel_number,
				struct exception_handler *e)
{
  NEW(exc_finish_channel_handler, self);
  self->table = table;
  self->channel_number = channel_number;
  self->super.parent = e;
  self->super.raise = do_exc_finish_channel_handler;
}
				

229
/* Channel objects */
Niels Möller's avatar
Niels Möller committed
230
231
232
233
234

#define INITIAL_CHANNELS 32
/* Arbitrary limit */
#define MAX_CHANNELS (1L<<17)

Niels Möller's avatar
Niels Möller committed
235
struct channel_table *make_channel_table(void)
Niels Möller's avatar
Niels Möller committed
236
{
237
  NEW(channel_table, table);
Niels Möller's avatar
Niels Möller committed
238

239
  table->channels = lsh_space_alloc(sizeof(struct ssh_channel *)
240
				      * INITIAL_CHANNELS);
Niels Möller's avatar
Niels Möller committed
241
242
  table->in_use = lsh_space_alloc(INITIAL_CHANNELS);
  
243
244
245
246
  table->allocated_channels = INITIAL_CHANNELS;
  table->next_channel = 0;
  table->used_channels = 0;
  table->max_channels = MAX_CHANNELS;
Niels Möller's avatar
Niels Möller committed
247

Niels Möller's avatar
Niels Möller committed
248
  table->pending_close = 0;
249

250
251
252
  table->global_requests = make_alist(0, -1);
  table->channel_types = make_alist(0, -1);
  
253
254
255
  object_queue_init(&table->local_ports);
  object_queue_init(&table->remote_ports);
  
256
257
  object_queue_init(&table->active_global_requests);
  object_queue_init(&table->pending_global_requests);
Niels Möller's avatar
Niels Möller committed
258
  
259
  return table;
Niels Möller's avatar
Niels Möller committed
260
261
262
};

/* Returns -1 if allocation fails */
263
264
265
/* NOTE: This function returns locally chosen channel numbers, which
 * are always small integers. So there's no problem fitting them in
 * a signed int. */
266
int alloc_channel(struct channel_table *table)
Niels Möller's avatar
Niels Möller committed
267
{
268
  UINT32 i;
269
  
270
  for(i = table->next_channel; i < table->used_channels; i++)
Niels Möller's avatar
Niels Möller committed
271
    {
Niels Möller's avatar
Niels Möller committed
272
      if (!table->in_use[i])
Niels Möller's avatar
Niels Möller committed
273
	{
Niels Möller's avatar
Niels Möller committed
274
275
	  assert(!table->channels[i]);
	  table->in_use[i] = 1;
276
	  table->next_channel = i+1;
Niels Möller's avatar
Niels Möller committed
277
278
279
	  return i;
	}
    }
280
  if (i == table->max_channels)
Niels Möller's avatar
Niels Möller committed
281
    return -1;
282

283
  if (i == table->allocated_channels) 
Niels Möller's avatar
Niels Möller committed
284
    {
285
      int new_size = table->allocated_channels * 2;
Niels Möller's avatar
Niels Möller committed
286
287
      struct ssh_channel **new_channels;
      struct UINT8 *new_in_use;
Niels Möller's avatar
Niels Möller committed
288

Niels Möller's avatar
Niels Möller committed
289
290
291
      new_channels = lsh_space_alloc(sizeof(struct ssh_channel *)
				     * new_size);
      memcpy(new_channels, table->channels,
292
	     sizeof(struct ssh_channel *) * table->used_channels);
Niels Möller's avatar
Niels Möller committed
293
294
295
296
297
298
299
300
      lsh_space_free(table->channels);
      table->channels = new_channels;

      new_in_use = lsh_space_alloc(new_size);
      memcpy(new_in_use, table->in_use, table->used_channels);
      lsh_space_free(table->in_use);
      table->in_use = new_in_use;

301
      table->allocated_channels = new_size;
Niels Möller's avatar
Niels Möller committed
302
303
    }

304
  table->next_channel = table->used_channels = i+1;
Niels Möller's avatar
Niels Möller committed
305
306
307
308

  return i;
}

309
void dealloc_channel(struct channel_table *table, int i)
Niels Möller's avatar
Niels Möller committed
310
311
{
  assert(i >= 0);
312
  assert( (unsigned) i < table->used_channels);
Niels Möller's avatar
Niels Möller committed
313
  
314
  table->channels[i] = NULL;
Niels Möller's avatar
Niels Möller committed
315
316
  table->in_use[i] = 0;
  
317
  if ( (unsigned) i < table->next_channel)
318
319
320
    table->next_channel = i;
}

Niels Möller's avatar
Niels Möller committed
321
322
323
void register_channel(struct ssh_connection *connection,
		      UINT32 local_channel_number,
		      struct ssh_channel *channel)
324
{
Niels Möller's avatar
Niels Möller committed
325
326
327
328
329
330
331
  struct exception_handler *e = channel->e ? channel->e, connection->e;
  
  assert(connection->channels->in_use[local_channel_number]);
  assert(!connection->channels->channels[local_channel_number]);
  
  connection->channels->channels[n] = channel;
  channel->e = make_exc_finish_channel_handler(table, n, e);
Niels Möller's avatar
Niels Möller committed
332
333
}

334
struct ssh_channel *lookup_channel(struct channel_table *table, UINT32 i)
Niels Möller's avatar
Niels Möller committed
335
{
336
337
  return (i < table->used_channels)
    ? table->channels[i] : NULL;
Niels Möller's avatar
Niels Möller committed
338
339
}

340
341
342
343
344
345
346
347
348
349
/* FIXME: It seems suboptimal to send a window adjust message for *every* write that we do.
 * A better scheme might be as follows:
 *
 * 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. */
static void adjust_rec_window(struct flow_controlled *f, UINT32 written)
350
{
351
352
  CAST_SUBTYPE(ssh_channel, channel, f);

Niels Möller's avatar
Niels Möller committed
353
354
355
356
  A_WRITE(channel->write,
	  prepare_window_adjust
	  (channel, written),
	  channel->e);
357
358
}

Niels Möller's avatar
Niels Möller committed
359
channel_start_receive(struct ssh_channel *channel)
360
{
Niels Möller's avatar
Niels Möller committed
361
362
363
364
365
  A_WRITE(channel->write,
	  prepare_window_adjust
	  (channel, channel->max_window - channel->rec_window_size),
	  channel->e);

366
367
}

Niels Möller's avatar
Niels Möller committed
368
#if 0
369
370
/* Process channel-related status codes. Used by the packet handlers,
 * before returning. */
Niels Möller's avatar
Niels Möller committed
371
372
373
374
static int channel_process_status(struct channel_table *table,
				  int channel,
				  int status)
{
375
376
377
378
  struct ssh_channel *c = table->channels[channel];
  
  while (!LSH_CLOSEDP(status))
    {
379
380
381
382
383
384
385
      if (status & LSH_CHANNEL_CLOSE)
	{ /* Close the channel now */ 
	  if (!c->flags & CHANNEL_SENT_CLOSE)
	    status |= channel_close(c);
	  break;
	}
      
386
387
388
389
390
391
392
393
394
      if (status & LSH_CHANNEL_READY_SEND)
	{
	  status &= ~ LSH_CHANNEL_READY_SEND;
	  if (c->send_window_size)
	    status |= CHANNEL_SEND(c);
	}
      else if (status & LSH_CHANNEL_READY_REC)
	{
	  status &= ~ LSH_CHANNEL_READY_REC;
395
	  status |= channel_start_receive(c);
396
397
398
399
400
	}
      else
	break;
    }
	
Niels Möller's avatar
Niels Möller committed
401
402
403
404
  if (status & LSH_CHANNEL_FINISHED)
    {
      /* Clear this bit */
      status &= ~LSH_CHANNEL_FINISHED;
405

406
      if (c->close)
407
	status |= CHANNEL_CLOSE(c);
Niels Möller's avatar
Niels Möller committed
408
409
410
411
      
      dealloc_channel(table, channel);
    }

412
413
414
415
416
417
418
  if (status & LSH_CHANNEL_PENDING_CLOSE)
    table->pending_close = 1;
  
  /* If this was the last channel, close connection */
  if (table->pending_close && !table->next_channel)
    status |= LSH_CLOSE;

Niels Möller's avatar
Niels Möller committed
419
420
  return status;
}
Niels Möller's avatar
Niels Möller committed
421
422
#endif

Niels Möller's avatar
Niels Möller committed
423

Niels Möller's avatar
Niels Möller committed
424
#if 0
425
426
427
428
429
430
/* Ugly macros to make it a little simpler to free the input packet at
 * the right time. */

#define START int foo_res
#define RETURN(x) do { foo_res = (x); goto foo_finish; } while(0)
#define END(s) foo_finish: do { lsh_string_free((s)); return foo_res; } while(0)
Niels Möller's avatar
Niels Möller committed
431
#endif
432

Niels Möller's avatar
Niels Möller committed
433
/* Channel related messages */
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460

/* GABA:
   (class
     (name global_request_status)
     (vars
       ; -1 for still active requests,
       ; 0 for failure,
       ; 1 for success
       (status . int)))
*/

static struct global_request_status *make_global_request_status(void)
{
  NEW(global_request_status, self);
  self->status = -1;

  return self;
}

/* GABA:
   (class
     (name global_request_response)
     (super global_request_callback)
     (vars
       (active object global_request_status)))
*/

Niels Möller's avatar
Niels Möller committed
461
static void
462
463
464
465
do_global_request_response(struct global_request_callback *c,
			   int success)
{
  CAST(global_request_response, self, c);
466
  struct object_queue *q = &self->super.connection->channels->active_global_requests;
467
468
469
470
471
472
473
474
475
476
477
478
479

  int res = 0;
  
  assert( self->active->status == -1);
  assert( (success == 0) || (success == 1) );
  assert( !object_queue_is_empty(q));
	  
  self->active->status = success;

  for (;;)
    {
      CAST(global_request_status, n, object_queue_peek_head(q));
      if (!n || (n->status < 0))
Niels Möller's avatar
Niels Möller committed
480
	break;
481
482

      object_queue_remove_head(q);
Niels Möller's avatar
Niels Möller committed
483
484
485
486
487
488
489
490

      /* FIXME: Perhaps install some exception handler that cancels
       * the queue as soon as a write failes. */
      A_WRITE(self->super.connection->write,
	      (n->status
	       ? format_global_success()
	       : format_global_failure()),
	      self->super.connection->e);
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
    }
}

static struct global_request_callback *
make_global_request_response(struct ssh_connection *connection,
			     struct global_request_status *active)
{
  NEW(global_request_response, self);

  self->super.connection = connection;
  self->super.response = do_global_request_response;

  self->active = active;

  return &self->super;
}
     
Niels Möller's avatar
Niels Möller committed
508
509
510
static void do_global_request(struct packet_handler *s UNUSED,
			      struct ssh_connection *connection,
			      struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
511
{
512
  /* CAST(global_request_handler, closure, c); */
Niels Möller's avatar
Niels Möller committed
513
514

  struct simple_buffer buffer;
515
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
516
517
518
519
520
521
522
523
524
525
526
  int name;
  int want_reply;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_GLOBAL_REQUEST)
      && parse_atom(&buffer, &name)
      && parse_boolean(&buffer, &want_reply))
    {
      struct global_request *req;
527
528
      struct global_request_callback *c = NULL;
      
529
530
      if (!name || !(req = ALIST_GET(connection->channels->global_requests,
				     name)))
531
	{
Niels Möller's avatar
Niels Möller committed
532
	  lsh_string_free(packet);
533

Niels Möller's avatar
Niels Möller committed
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
	  C_WRITE(connection->write,
		  format_global_failure());
	}
      else
	{
	  if (want_reply)
	    {
	      struct global_request_status *a = make_global_request_status();
	      
	      object_queue_add_tail(&connection->channels->active_global_requests,
				    &a->super);
	      
	      c = make_global_request_response(connection, a);
	    }
	  GLOBAL_REQUEST(req, connection, &buffer, c);
549
	}
Niels Möller's avatar
Niels Möller committed
550
    }
Niels Möller's avatar
Niels Möller committed
551
552
553
554
555
556
557
  else
    {
      EXCEPTION_RAISE(connection->e,
		      make_protocol_exception(SSH_DISCONNECT_PROTOCOL_ERROR,
					      "Invalid SSH_MSG_GLOBAL_REQUEST message."));
    }
  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
558
559
}

560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
static int do_global_request_success(struct packet_handler *s UNUSED,
				     struct ssh_connection *connection,
				     struct lsh_string *packet)
{
  if (packet->length != 1)
    return LSH_FAIL | LSH_DIE;

  assert(packet->data[0] == SSH_MSG_REQUEST_SUCCESS);

  if (object_queue_is_empty(&connection->channels->pending_global_requests))
    {
      werror("do_global_request_success: Unexpected message, ignoring.\n");
      return LSH_OK | LSH_GOON;
    }
  {
575
    CAST_SUBTYPE(command_context, ctx,
576
		 object_queue_remove_head(&connection->channels->pending_global_requests));
577
    return COMMAND_RETURN(ctx->c, connection);
578
579
580
  }
}

581
582
583
struct exception global_request_exception =
STATIC_EXCEPTION(EXC_GLOBAL_REQUEST, "Global request failed");

584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
static int do_global_request_failure(struct packet_handler *s UNUSED,
				     struct ssh_connection *connection,
				     struct lsh_string *packet)
{
  if (packet->length != 1)
    return LSH_FAIL | LSH_DIE;

  assert(packet->data[0] == SSH_MSG_REQUEST_FAILURE);

  if (object_queue_is_empty(&connection->channels->pending_global_requests))
    {
      werror("do_global_request_failure: Unexpected message, ignoring.\n");
      return LSH_OK | LSH_GOON;
    }
  {
599
    CAST_SUBTYPE(command_context, ctx,
600
		 object_queue_remove_head(&connection->channels->pending_global_requests));
601
    return EXCEPTION_RAISE(ctx->e, &global_request_exception);
602
603
604
  }
}

Niels Möller's avatar
Niels Möller committed
605
606
#if 0
/* HERE!!! */
607
/* FIXME: Split into a continuation and an exception handler */
608
609
610
611
612
613
614
615
616
617
618
619
620
/* Callback given to the CHANNEL_OPEN method */
static int do_channel_open_response(struct channel_open_callback *c,
                                    struct ssh_channel *channel,
                                    UINT32 error, char *error_msg,
                                    struct lsh_string *args)
{
  CAST(channel_open_response, closure, c);
  
  int local_channel_number;

  if (!channel)
    {
      if (error)
Niels Möller's avatar
Niels Möller committed
621
622
623
624
625
626
        C_WRITE(closure->super.connection->write,
		format_open_failure(closure->remote_channel_number,
				    error, error_msg, ""));
      else
	EXCEPTION_RAISE(closure->super.connection->e,
			make_protocol_exception())
627
      return LSH_FAIL | LSH_DIE;
628
629
    }

Niels Möller's avatar
Niels Möller committed
630
631
632
  /* FIXME: It would be better to allocate or at least reserve a channel number earlier,
   * so that we can't fail at this point.
   */
633
634
635
636
637
638
639
640
641
642
643
644
  if ( (local_channel_number
            = register_channel(closure->super.connection->channels,
			       channel)) < 0)
    {
      werror("Could not allocate a channel number for opened channel!\n");
      return A_WRITE(closure->super.connection->write,
                     format_open_failure(closure->remote_channel_number,
                                         SSH_OPEN_RESOURCE_SHORTAGE,
                                         "Could not allocate a channel number "
                                         "(shouldn't happen...)", ""));
    }

645
  /* FIXME: This copying could just as well be done by the
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
   * CHANNEL_OPEN handler? Then we can remove the corresponding fields
   * from the closure as well. */
  channel->send_window_size = closure->window_size;
  channel->send_max_packet = closure->max_packet;
  channel->channel_number = closure->remote_channel_number;

  /* FIXME: Is the channel->write field really needed? */
  channel->write = closure->super.connection->write;

  return A_WRITE(closure->super.connection->write,
                 args
                 ? format_open_confirmation(channel, local_channel_number,
                                            "%lfS", args)
                 : format_open_confirmation(channel, local_channel_number,
                                            ""));
}

static struct channel_open_response *
make_channel_open_response(struct ssh_connection* connection,
			   UINT32 remote_channel_number,
			   UINT32 window_size,
			   UINT32 max_packet)
{
  NEW(channel_open_response, closure);

  closure->super.response = do_channel_open_response;
  closure->super.connection = connection;
  closure->remote_channel_number = remote_channel_number;
  closure->window_size = window_size;
  closure->max_packet = max_packet;

  return closure;
}
Niels Möller's avatar
Niels Möller committed
679
#endif
680

Niels Möller's avatar
Niels Möller committed
681
/* GABA:
682
683
684
685
686
   (class
     (name channel_open_continuation)
     (super command_continuation)
     (vars
       (connection object ssh_connection)
Niels Möller's avatar
Niels Möller committed
687
688
689
690
       (local_channel_number . UINT32)
       (remote_channel_number . UINT32)
       (window_size . UINT32)
       (max_packet . UINT32)))
691
*/
692

Niels Möller's avatar
Niels Möller committed
693
694
695
static void
do_channel_open_continue(struct command_continuation *c,
			 struct lsh_object *value)
696
697
{
  CAST(channel_open_continuation, self, c);
Niels Möller's avatar
Niels Möller committed
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
  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. */
  channel->send_window_size = self->window_size;
  channel->send_max_packet = self->max_packet;
  channel->channel_number = self->remote_channel_number;

  /* FIXME: Is the channel->write field really needed? */
  channel->write = closure->super.connection->write;

  register_channel(connection, self->local_channel_number, channel);

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

  C_WRITE(self->connection,
	  format_open_confirmation(channel, local_channel_number, ""))
719
}
Niels Möller's avatar
Niels Möller committed
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794

static struct channel_open_continuation *
make_channel_open_continuation(struct ssh_connection *connection,
			       UINT32 local_channel_number,
			       UINT32 remote_channel_number,
			       UINT32 window_size,
			       UINT32 max_packet)
{
  NEW(channel_open_continuation, self);
  self->super.c = do_channel_open_continue;
  self->connection = connection;
  self->local_channel_number = local_channel_number;
  self->remote_channel_number = remote_channel_number;
  self->window_size = window_size;
  self->max_packet = max_packet;

  return self;
}
			       
/* GABA:
   (class
     (name exc_channel_open_handler)
     (super exception_handler)
     (vars
       (connection object ssh_connection)
       (local_channel_number . UINT32)
       (remote_channel_number . UINT32)
))
*/

static void do_exc_channel_open_handler(struct exception_handler *s,
					struct exception *e)
{
  CAST(exc_channel_open_handler, self, s);

  switch (e->type)
    {
    case EXC_CHANNEL_OPEN:
      {
	CAST_SUBTYPE(channel_open_exception, exc, e);
	struct channel_table *table = self->connection->channels;
	
	assert(table->in_use[self->local_channel_number]);
	assert(!table->channels[self->local_channel_number]);

	dealloc_channel(table, self->local_channel_number);
	
        C_WRITE(self->connection,
		format_open_failure(self->remote_channel_number,
				    exc->error_code, e->msg, ""));
	break;
      }
    default:
      EXCEPTION_RAISE(self->super.parent, e);
    }      
}

static struct exception_handler *
make_exc_channel_open_handler(struct ssh_connection *connection,
			      UINT32 local_channel_number,
			      UINT32 remote_channel_number,
			      struct exception_handler *parent)
{
  NEW(channel_open_exception_handler, self);
  self->super.parent = parent;
  self->super.raise = do_channel_open_exception_handler;
  self->local_channel_number = local_channel_number;
  self->remote_channel_number = remote_channel_number;

  return &self->super;
}

static void do_channel_open(struct packet_handler *c UNUSED,
			    struct ssh_connection *connection,
			    struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
795
{
796
  /* CAST(channel_open_handler, closure, c); */
Niels Möller's avatar
Niels Möller committed
797
798

  struct simple_buffer buffer;
799
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
800
  int type;
801
802
803
  UINT32 remote_channel_number;
  UINT32 window_size;
  UINT32 max_packet;
Niels Möller's avatar
Niels Möller committed
804
805
806
807
808
809
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_OPEN)
      && parse_atom(&buffer, &type)
810
811
812
      && parse_uint32(&buffer, &remote_channel_number)
      && parse_uint32(&buffer, &window_size)
      && parse_uint32(&buffer, &max_packet))
Niels Möller's avatar
Niels Möller committed
813
814
    {
      struct channel_open *open;
Niels Möller's avatar
Niels Möller committed
815

816
      if (connection->channels->pending_close)
Niels Möller's avatar
Niels Möller committed
817
818
819
820
821
822
823
824
825
	{
	  /* We are waiting for channels to close. Don't open any new ones. */

	  C_WRITE(connection,
		  format_open_failure(remote_channel_number,
				      SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
				      "Waiting for channels to close.", ""));
	}
      else if (!type || !(open = ALIST_GET(connection->channels->channel_types,
826
				      type)))
Niels Möller's avatar
Niels Möller committed
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
	{
	  C_WRITE(connection,
		  format_open_failure(remote_channel_number,
				      SSH_OPEN_UNKNOWN_CHANNEL_TYPE,
				      "Unknown channel type", ""));
	}
      else
	{
	  struct channel_open_continuation *c;
      	  int local_number = alloc_channel(connection->channels);

	  if (local_number < 0)
	    C_WRITE(connection,
		    format_open_failure(remote_channel_number,
					SSH_OPEN_RESOURCE_SHORTAGE,
					"Unknown channel type", ""));

	  c = make_channel_open_continuation(connection,
					     local_number,
					     remote_channel_number,
					     window_size,
					     max_packet);
	  
	  CHANNEL_OPEN(open, connection, &buffer, c,
		       make_exc_channel_open_handler
		       (connection, local_number, remote_channel_number,
			make_exc_finish_channel_handler(connection->channels,
							local_number,
							connection->e)));
	}
Niels Möller's avatar
Niels Möller committed
857
    }
Niels Möller's avatar
Niels Möller committed
858
859
860
861
862
  else
    EXCEPTION_RAISE(connection->e,
		    make_protocol_exception(SSH_DISCONNECT_PROTOCOL_ERROR,
					    "Invalid SSH_MSG_CHANNEL_OPEN message."));
  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
863
864
}     

Niels Möller's avatar
Niels Möller committed
865
866
867
static void do_channel_request(struct packet_handler *closure UNUSED,
			       struct ssh_connection *connection,
			       struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
868
869
{
  struct simple_buffer buffer;
870
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
871
872
873
  UINT32 channel_number;
  int type;
  int want_reply;
874
  
Niels Möller's avatar
Niels Möller committed
875
876
877
878
879
880
881
882
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_REQUEST)
      && parse_uint32(&buffer, &channel_number)
      && parse_atom(&buffer, &type)
      && parse_boolean(&buffer, &want_reply))
    {
883
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
884
885
						   channel_number);

886
887
888
889
      /* NOTE: We can't free packet yet, because it is not yet fully
       * parsed. There may be some more arguments, which are parsed by
       * the CHANNEL_REQUEST method below. */

Niels Möller's avatar
Niels Möller committed
890
891
892
893
      if (channel)
	{
	  struct channel_request *req;

894
895
	  if (type && channel->request_types 
	      && ( (req = ALIST_GET(channel->request_types, type)) ))
Niels Möller's avatar
Niels Möller committed
896
	    CHANNEL_REQUEST(req, channel, connection, want_reply, &buffer);
897
	  else
Niels Möller's avatar
Niels Möller committed
898
899
900
901
902
903
904
905
906
907
	    {
	      if (want_reply)
		C_WRITE(connection->write,
			format_channel_failure(channel->channel_number));
	    }
	}
      else
	{
	  werror("SSH_MSG_CHANNEL_REQUEST on nonexistant channel %i\n",
		 channel_number);
Niels Möller's avatar
Niels Möller committed
908
	}
909
    }
Niels Möller's avatar
Niels Möller committed
910
911
912
913
914
  else
    EXCEPTION_RAISE(connection->e,
		    make_protocol_exception(SSH_DISCONNECT_PROTOCOL_ERROR,
					    "Invalid SSH_MSG_CHANNEL_REQUEST message."));
  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
915
916
}
      
917
918
static int do_window_adjust(struct packet_handler *closure UNUSED,
			    struct ssh_connection *connection,
919
			    struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
920
921
{
  struct simple_buffer buffer;
922
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
923
924
925
926
927
928
929
  UINT32 channel_number;
  UINT32 size;

  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_WINDOW_ADJUST)
930
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
931
932
933
      && parse_uint32(&buffer, &size)
      && parse_eod(&buffer))
    {
934
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
935
936
937
938
						   channel_number);

      lsh_string_free(packet);
      
Niels Möller's avatar
Niels Möller committed
939
      if (channel
940
941
	  && !(channel->flags & (CHANNEL_RECEIVED_EOF
				 | CHANNEL_RECEIVED_CLOSE)))
Niels Möller's avatar
Niels Möller committed
942
	{
Niels Möller's avatar
Niels Möller committed
943
944
945
946
	  if (! (channel->flags & CHANNEL_SENT_CLOSE))
	    {
	      channel->send_window_size += size;
	      if (channel->send_window_size && channel->send)
947
		return channel_process_status(connection->channels,
Niels Möller's avatar
Niels Möller committed
948
949
					      channel_number,
					      CHANNEL_SEND(channel));
Niels Möller's avatar
Niels Möller committed
950
	    }
Niels Möller's avatar
Niels Möller committed
951
952
953
954
	  return LSH_OK | LSH_GOON;
	}
      /* FIXME: What to do now? Should unknown channel numbers be
       * ignored silently? */
955
956
      werror("SSH_MSG_CHANNEL_WINDOW_ADJUST on nonexistant or closed "
	     "channel %i\n", channel_number);
Niels Möller's avatar
Niels Möller committed
957
958
959
960
961
962
963
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);

  return LSH_FAIL | LSH_DIE;
}

964
965
static int do_channel_data(struct packet_handler *closure UNUSED,
			   struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
966
967
968
			   struct lsh_string *packet)
{
  struct simple_buffer buffer;
969
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
970
971
972
973
974
975
976
  UINT32 channel_number;
  struct lsh_string *data;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_DATA)
977
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
978
979
980
      && ( (data = parse_string_copy(&buffer)) )
      && parse_eod(&buffer))
    {
981
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
982
983
984
985
						   channel_number);

      lsh_string_free(packet);
      
986
      if (channel && channel->receive
987
988
	  && !(channel->flags & (CHANNEL_RECEIVED_EOF
				 | CHANNEL_RECEIVED_CLOSE)))
Niels Möller's avatar
Niels Möller committed
989
	{
Niels Möller's avatar
Niels Möller committed
990
	  if (channel->flags & CHANNEL_SENT_CLOSE)
Niels Möller's avatar
Niels Möller committed
991
	    {
992
	      werror("Ignoring data on channel which is closing\n");
Niels Möller's avatar
Niels Möller committed
993
	      return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
994
	    }
Niels Möller's avatar
Niels Möller committed
995
996
	  else
	    {
997
998
	      int res = 0;
	      
Niels Möller's avatar
Niels Möller committed
999
1000
1001
	      if (data->length > channel->rec_window_size)
		{
		  /* Truncate data to fit window */
1002
		  werror("Channel data overflow. Extra data ignored.\n"); 
Niels Möller's avatar
Niels Möller committed
1003
1004
		  data->length = channel->rec_window_size;
		}
1005
1006
1007
1008

	      if (!data->length)
		/* Ignore data packet */
		return 0;
1009
1010
	      channel->rec_window_size -= data->length;

1011
#if 0
1012
	      /* FIXME: Unconditionally adjusting the receive window
1013
	       * breaks flow control. We better let the channel's
1014
	       * receive method decide whether or not to receive more
1015
1016
	       * data. */
	      res = adjust_rec_window(channel);
1017

1018
1019
	      if (LSH_CLOSEDP(res))
		return res;
1020
1021
#endif
	      
Niels Möller's avatar
Niels Möller committed
1022
	      return channel_process_status(
1023
		connection->channels, channel_number,
1024
		res | CHANNEL_RECEIVE(channel, 
Niels Möller's avatar
Niels Möller committed
1025
				      CHANNEL_DATA, data));
Niels Möller's avatar
Niels Möller committed
1026
1027
	    }
	  return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
1028
1029
	}
	  
1030
      werror("Data on closed or non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
1031
1032
1033
1034
1035
1036
1037
1038
1039
	     channel_number);
      lsh_string_free(data);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  
  return LSH_FAIL | LSH_DIE;
}

1040
1041
static int do_channel_extended_data(struct packet_handler *closure UNUSED,
				    struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
1042
1043
1044
				    struct lsh_string *packet)
{
  struct simple_buffer buffer;
1045
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
1046
1047
1048
1049
1050
1051
1052
1053
  UINT32 channel_number;
  UINT32 type;
  struct lsh_string *data;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_EXTENDED_DATA)
1054
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
1055
1056
1057
1058
      && parse_uint32(&buffer, &type)
      && ( (data = parse_string_copy(&buffer)) )
      && parse_eod(&buffer))
    {
1059
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
1060
1061
1062
1063
						   channel_number);

      lsh_string_free(packet);
      
1064
      if (channel && channel->receive
1065
1066
	  && !(channel->flags & (CHANNEL_RECEIVED_EOF
				 | CHANNEL_RECEIVED_CLOSE)))
Niels Möller's avatar
Niels Möller committed
1067
	{
Niels Möller's avatar
Niels Möller committed
1068
	  if (channel->flags & CHANNEL_SENT_CLOSE)
Niels Möller's avatar
Niels Möller committed
1069
	    {
1070
	      werror("Ignoring extended data on channel which is closing\n");
Niels Möller's avatar
Niels Möller committed
1071
	      return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
1072
	    }
Niels Möller's avatar
Niels Möller committed
1073
	  else
Niels Möller's avatar
Niels Möller committed
1074
	    {
1075
1076
	      int res = 0;
	      
Niels Möller's avatar
Niels Möller committed
1077
1078
1079
	      if (data->length > channel->rec_window_size)
		{
		  /* Truncate data to fit window */
1080
		  werror("Channel extended data overflow. "
Niels Möller's avatar
Niels Möller committed
1081
1082
1083
1084
1085
			 "Extra data ignored.\n");
		  data->length = channel->rec_window_size;
		}
	      
	      channel->rec_window_size -= data->length;
1086

1087
#if 0
1088
1089
1090
1091
1092
1093
	      /* FIXME: Like for do_channel_data(), unconditionally
	       * adjusting the window breaks flow control. */
	      res = adjust_rec_window(channel);

	      if (LSH_CLOSEDP(res))
		return res;
1094
#endif
1095

Niels Möller's avatar
Niels Möller committed
1096
1097
1098
	      switch(type)
		{
		case SSH_EXTENDED_DATA_STDERR:
Niels Möller's avatar
Niels Möller committed
1099
		  return channel_process_status(
1100
		    connection->channels, channel_number,
1101
		    res | CHANNEL_RECEIVE(channel, 
Niels Möller's avatar
Niels Möller committed
1102
					  CHANNEL_STDERR_DATA, data));
Niels Möller's avatar
Niels Möller committed
1103
		default:
1104
		  werror("Unknown type %i of extended data.\n",
Niels Möller's avatar
Niels Möller committed
1105
1106
1107
1108
			 type);
		  lsh_string_free(data);
		  return LSH_FAIL | LSH_DIE;
		}
Niels Möller's avatar
Niels Möller committed
1109
1110
	    }
	}
1111
      werror("Extended data on closed or non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
1112
1113
1114
1115
1116
1117
1118
1119
1120
	     channel_number);
      lsh_string_free(data);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  
  return LSH_FAIL | LSH_DIE;
}

1121
1122
static int do_channel_eof(struct packet_handler *closure UNUSED,
			  struct ssh_connection *connection,
1123
			  struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
1124
1125
{
  struct simple_buffer buffer;
1126
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
1127
1128
1129
1130
1131
1132
  UINT32 channel_number;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_EOF)
1133
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
1134
1135
      && parse_eod(&buffer))
    {
1136
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
1137
1138
1139
1140
						   channel_number);

      lsh_string_free(packet);

Niels Möller's avatar
Niels Möller committed
1141
1142
      if (channel)
	{
1143
1144
	  int res = 0;
	  
1145
	  if (channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_RECEIVED_CLOSE))
Niels Möller's avatar
Niels Möller committed
1146
	    {
1147
	      werror("Receiving EOF on channel on closed channel.\n");
Niels Möller's avatar
Niels Möller committed
1148
1149
1150
	      return LSH_FAIL | LSH_DIE;
	    }

1151
	  channel->flags |= CHANNEL_RECEIVED_EOF;
Niels Möller's avatar
Niels Möller committed
1152

1153
1154
	  if (channel->eof)
	    res = CHANNEL_EOF(channel);
1155
1156
1157
	  else
	    /* FIXME: What is a reasonable default behaviour?
	     * Closing the channel may be the right thing to do. */
1158
1159
1160
	    if (! (channel->flags & CHANNEL_SENT_CLOSE))
	      res |= channel_close(channel);
#if 0
1161
1162
1163
	  if (!LSH_CLOSEDP(res)
	      && ! (channel->flags & CHANNEL_SENT_CLOSE)
	      && (channel->flags & CHANNEL_SENT_EOF))
Niels Möller's avatar
Niels Möller committed
1164
1165
1166
	    {
	      /* Both parties have sent EOF. Initiate close, if we
	       * havn't done that already. */
1167
1168
	      
	      res |= channel_close(channel);
Niels Möller's avatar
Niels Möller committed
1169
	    }
1170
#endif      
1171
	  return channel_process_status(connection->channels, channel_number,
1172
1173
					res);

Niels Möller's avatar
Niels Möller committed
1174
	}
1175
      werror("EOF on non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
1176
1177
	     channel_number);
      return LSH_FAIL | LSH_DIE;
Niels Möller's avatar
Niels Möller committed
1178
    }
Niels Möller's avatar
Niels Möller committed
1179
      
Niels Möller's avatar
Niels Möller committed
1180
1181
1182
1183
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

1184
1185
static int do_channel_close(struct packet_handler *closure UNUSED,
			    struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
1186
1187
1188
			    struct lsh_string *packet)
{
  struct simple_buffer buffer;
1189
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
1190
1191
1192
1193
1194
1195
  UINT32 channel_number;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_CLOSE)
1196
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
1197
1198
      && parse_eod(&buffer))
    {
1199
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
1200
1201
1202
1203
						   channel_number);

      lsh_string_free(packet);
      
Niels Möller's avatar
Niels Möller committed
1204
1205
      if (channel)
	{
1206
1207
	  int res = 0;
	  
1208
	  if (channel->flags & CHANNEL_RECEIVED_CLOSE)
Niels Möller's avatar
Niels Möller committed
1209
	    {
1210
	      werror("Receiving multiple CLOSE on channel.\n");
Niels Möller's avatar
Niels Möller committed
1211
1212
1213
	      return LSH_FAIL | LSH_DIE;
	    }

1214
	  channel->flags |= CHANNEL_RECEIVED_CLOSE;
Niels Möller's avatar
Niels Möller committed
1215
	  
1216
1217
	  if (! (channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_SENT_EOF
				   | CHANNEL_SENT_CLOSE)))
Niels Möller's avatar
Niels Möller committed
1218
	    {
1219
	      werror("Unexpected channel CLOSE.\n");
Niels Möller's avatar
Niels Möller committed
1220
	    }
1221

1222
	  if (! (channel->flags & (CHANNEL_RECEIVED_EOF))
1223
	      && channel->eof)
1224
	    res = CHANNEL_EOF(channel);
Niels Möller's avatar
Niels Möller committed
1225
	  
Niels Möller's avatar
Niels Möller committed
1226
	  return channel_process_status(
1227
	    connection->channels, channel_number,
1228
1229
1230
1231
	    ( ( (channel->flags & (CHANNEL_SENT_CLOSE))
		? LSH_OK | LSH_CHANNEL_FINISHED
		: channel_close(channel))
	      | res));
Niels Möller's avatar
Niels Möller committed
1232
	}
1233
      werror("CLOSE on non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
1234
1235
	     channel_number);
      return LSH_FAIL | LSH_DIE;
Niels Möller's avatar
Niels Möller committed
1236
1237
1238
1239
1240
1241
      
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

1242
static int do_channel_open_confirm(struct packet_handler *closure UNUSED,
Niels Möller's avatar
Niels Möller committed
1243
1244
				   struct ssh_connection *connection,
				   struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
1245
1246
{
  struct simple_buffer buffer;
1247
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
  UINT32 local_channel_number;
  UINT32 remote_channel_number;  
  UINT32 window_size;
  UINT32 max_packet;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_OPEN_CONFIRMATION)
      && parse_uint32(&buffer, &local_channel_number)
      && parse_uint32(&buffer, &remote_channel_number)
      && parse_uint32(&buffer, &window_size)
      && parse_uint32(&buffer, &max_packet)
      && parse_eod(&buffer))
    {
1263
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
1264
1265
1266
1267
						   local_channel_number);

      lsh_string_free(packet);

1268
      if (channel && channel->open_continuation)
Niels Möller's avatar
Niels Möller committed
1269
	{
1270
1271
1272
	  struct command_continuation *c = channel->open_continuation;
	  channel->open_continuation = NULL;
	  
Niels Möller's avatar
Niels Möller committed
1273
1274
1275
1276
	  channel->channel_number = remote_channel_number;
	  channel->send_window_size = window_size;
	  channel->send_max_packet = max_packet;

1277
1278
1279
	  return channel_process_status
	    (connection->channels,
	     local_channel_number,
1280
	     COMMAND_RETURN(c, channel));
Niels Möller's avatar
Niels Möller committed
1281
	}
1282
      werror("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION on channel %i\n",
Niels Möller's avatar
Niels Möller committed
1283
1284
1285
1286
1287
1288
1289
	     local_channel_number);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

1290
1291
static int do_channel_open_failure(struct packet_handler *closure UNUSED,
			      struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
1292
1293
1294
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
1295
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
  UINT32 channel_number;
  UINT32 reason;

  UINT8 *msg;
  UINT32 length;

  UINT8 *language;
  UINT32 language_length;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_OPEN_FAILURE)
      && parse_uint32(&buffer, &channel_number)
      && parse_uint32(&buffer, &reason)
      && parse_string(&buffer, &length, &msg)
      && parse_string(&buffer, &language_length, &language)<