channel.c 37.7 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)))
*/

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);
}

154
/* Channel objects */
Niels Möller's avatar
Niels Möller committed
155
156
157
158
159

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

Niels Möller's avatar
Niels Möller committed
160
struct channel_table *make_channel_table(void)
Niels Möller's avatar
Niels Möller committed
161
{
162
  NEW(channel_table, table);
Niels Möller's avatar
Niels Möller committed
163

164
  table->channels = lsh_space_alloc(sizeof(struct ssh_channel *)
165
				      * INITIAL_CHANNELS);
166
167
168
169
  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
170

Niels Möller's avatar
Niels Möller committed
171
172
  table->pending_close = 0;
  
173
  return table;
Niels Möller's avatar
Niels Möller committed
174
175
176
};

/* Returns -1 if allocation fails */
177
178
179
/* NOTE: This function returns locally chosen channel numbers, which
 * are always small integers. So there's no problem fitting them in
 * a signed int. */
180
int alloc_channel(struct channel_table *table)
Niels Möller's avatar
Niels Möller committed
181
{
182
  UINT32 i;
183
  
184
  for(i = table->next_channel; i < table->used_channels; i++)
Niels Möller's avatar
Niels Möller committed
185
    {
186
      if (!table->channels[i])
Niels Möller's avatar
Niels Möller committed
187
	{
188
	  table->next_channel = i+1;
Niels Möller's avatar
Niels Möller committed
189
190
191
	  return i;
	}
    }
192
  if (i == table->max_channels)
Niels Möller's avatar
Niels Möller committed
193
    return -1;
194

195
  if (i == table->allocated_channels) 
Niels Möller's avatar
Niels Möller committed
196
    {
197
      int new_size = table->allocated_channels * 2;
Niels Möller's avatar
Niels Möller committed
198
      struct ssh_channel **new
199
	= lsh_space_alloc(sizeof(struct ssh_channel *) * new_size);
Niels Möller's avatar
Niels Möller committed
200

201
202
      memcpy(new, table->channels,
	     sizeof(struct ssh_channel *) * table->used_channels);
Niels Möller's avatar
Niels Möller committed
203
      
204
205
      table->channels = new;
      table->allocated_channels = new_size;
Niels Möller's avatar
Niels Möller committed
206
207
    }

208
  table->next_channel = table->used_channels = i+1;
Niels Möller's avatar
Niels Möller committed
209
210
211
212

  return i;
}

213
void dealloc_channel(struct channel_table *table, int i)
Niels Möller's avatar
Niels Möller committed
214
215
{
  assert(i >= 0);
216
  assert( (unsigned) i < table->used_channels);
Niels Möller's avatar
Niels Möller committed
217
  
218
219
  table->channels[i] = NULL;

220
  if ( (unsigned) i < table->next_channel)
221
222
223
    table->next_channel = i;
}

224
225
/* Returns -1 if no channel number can be allocated. See also the note
 * for alloc_channel(). */
226
227
228
229
230
231
int register_channel(struct channel_table *table, struct ssh_channel *channel)
{
  int n = alloc_channel(table);

  if (n >= 0)
    table->channels[n] = channel;
Niels Möller's avatar
Niels Möller committed
232

233
  return n;
Niels Möller's avatar
Niels Möller committed
234
235
}

236
struct ssh_channel *lookup_channel(struct channel_table *table, UINT32 i)
Niels Möller's avatar
Niels Möller committed
237
{
238
239
  return (i < table->used_channels)
    ? table->channels[i] : NULL;
Niels Möller's avatar
Niels Möller committed
240
241
}

242
243
244
static int adjust_rec_window(struct ssh_channel *channel)
{
  if (channel->rec_window_size < channel->max_window / 2)
245
246
247
248
249
    return A_WRITE(channel->write,
		   prepare_window_adjust
		   (channel, channel->max_window - channel->rec_window_size));
  else
    return 0;
250
251
}

252
253
/* Process channel-related status codes. Used by the packet handlers,
 * before returning. */
Niels Möller's avatar
Niels Möller committed
254
255
256
257
static int channel_process_status(struct channel_table *table,
				  int channel,
				  int status)
{
258
259
260
261
  struct ssh_channel *c = table->channels[channel];
  
  while (!LSH_CLOSEDP(status))
    {
262
263
264
265
266
267
268
      if (status & LSH_CHANNEL_CLOSE)
	{ /* Close the channel now */ 
	  if (!c->flags & CHANNEL_SENT_CLOSE)
	    status |= channel_close(c);
	  break;
	}
      
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
      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;
	  status |= adjust_rec_window(c);
	}
      else
	break;
    }
	
Niels Möller's avatar
Niels Möller committed
284
285
286
287
  if (status & LSH_CHANNEL_FINISHED)
    {
      /* Clear this bit */
      status &= ~LSH_CHANNEL_FINISHED;
288

289
      if (c->close)
290
	status |= CHANNEL_CLOSE(c);
Niels Möller's avatar
Niels Möller committed
291
292
293
294
      
      dealloc_channel(table, channel);
    }

295
296
297
298
299
300
301
  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
302
303
  return status;
}
Niels Möller's avatar
Niels Möller committed
304

305
306
307
308
309
310
311
/* 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
312
/* Channel related messages */
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386

/* 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)))
*/

static int
do_global_request_response(struct global_request_callback *c,
			   int success)
{
  CAST(global_request_response, self, c);
  struct object_queue *q = self->super.connection->channels->active_global_requests;

  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))
	return res;

      object_queue_remove_head(q);
      
      res |= A_WRITE(self->super.connection->write,
		     (n->status
		      ? format_global_success()
		      : format_global_failure()));
      
      if (LSH_CLOSEDP(res))
	return res;
    }
}

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
387
388
389
390
static int do_global_request(struct packet_handler *c,
			     struct ssh_connection *connection,
			     struct lsh_string *packet)
{
391
  CAST(global_request_handler, closure, c);
Niels Möller's avatar
Niels Möller committed
392
393

  struct simple_buffer buffer;
394
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
395
396
  int name;
  int want_reply;
397
  START;
Niels Möller's avatar
Niels Möller committed
398
399
400
401
402
403
404
405
406
  
  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;
407
408
      struct global_request_callback *c = NULL;
      
Niels Möller's avatar
Niels Möller committed
409
      if (!name || !(req = ALIST_GET(closure->global_requests, name)))
410
411
	RETURN (A_WRITE(connection->write,
		       format_global_failure()));
Niels Möller's avatar
Niels Möller committed
412

413
414
415
416
417
418
419
420
421
422
      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);
	}
      RETURN (GLOBAL_REQUEST(req, connection, &buffer, c));
Niels Möller's avatar
Niels Möller committed
423
    }
424
  RETURN (LSH_FAIL | LSH_DIE);
Niels Möller's avatar
Niels Möller committed
425

426
  END (packet);
Niels Möller's avatar
Niels Möller committed
427
428
}

429
430
431
432
433
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
/* 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)
        return A_WRITE(closure->super.connection->write,
                       format_open_failure(closure->remote_channel_number,
                                           error, error_msg, ""));
        /* The request was invalid */
        return LSH_FAIL | LSH_DIE;
    }

  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...)", ""));
    }

461
  /* FIXME: This copying could just as well be done by the
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
   * 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;
}
495

496

497
498
499
500
501
502
503
504
505
506
507
#if 0
/* ;;GABA:
   (class
     (name channel_open_continuation)
     (super command_continuation)
     (vars
       (connection object ssh_connection)
       (remote_channel_number simple UINT32)
       (window_size simple UINT32)
       (max_packet simple UINT32)))
*/
508

509
510
511
512
513
514
515
516
static int do_channel_open_continue(struct command_continuation *c,
				    struct lsh_object *result)
{
  CAST(channel_open_continuation, self, c);
  CAST_SUBTYPE(channel);
}
#endif
				    
Niels Möller's avatar
Niels Möller committed
517
518
519
520
static int do_channel_open(struct packet_handler *c,
			   struct ssh_connection *connection,
			   struct lsh_string *packet)
{
521
  CAST(channel_open_handler, closure, c);
Niels Möller's avatar
Niels Möller committed
522
523

  struct simple_buffer buffer;
524
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
525
  int type;
526
527
528
  UINT32 remote_channel_number;
  UINT32 window_size;
  UINT32 max_packet;
529
  START;
Niels Möller's avatar
Niels Möller committed
530
531
532
533
534
535
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_OPEN)
      && parse_atom(&buffer, &type)
536
537
538
      && 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
539
540
    {
      struct channel_open *open;
541
542
      struct channel_open_response *response;
      int res;
543
      
544
      if (connection->channels->pending_close)
Niels Möller's avatar
Niels Möller committed
545
	/* We are waiting for channels to close. Don't open any new ones. */
546
547
548
549
550
	RETURN
	  (A_WRITE(connection->write,
		   format_open_failure(remote_channel_number,
				       SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
				       "Waiting for channels to close.", "")));
Niels Möller's avatar
Niels Möller committed
551
552
      
      if (!type || !(open = ALIST_GET(closure->channel_types, type)))
553
554
555
556
	RETURN (A_WRITE(connection->write,
			format_open_failure(remote_channel_number,
					    SSH_OPEN_UNKNOWN_CHANNEL_TYPE,
					    "Unknown channel type", "")));
557

558
559
560
561
562
563
564
565
      response = make_channel_open_response(connection,
					    remote_channel_number,
					    window_size, max_packet);
      /* NOTE: If the channel could be opened immediately, this method
       * will call response right away. */
      res = CHANNEL_OPEN(open, connection, &buffer, &response->super);

      RETURN (res);
Niels Möller's avatar
Niels Möller committed
566
    }
567
  RETURN (LSH_FAIL | LSH_DIE);
Niels Möller's avatar
Niels Möller committed
568

569
  END(packet);
Niels Möller's avatar
Niels Möller committed
570
571
}     

572
static int do_channel_request(struct packet_handler *closure UNUSED,
Niels Möller's avatar
Niels Möller committed
573
574
575
576
			      struct ssh_connection *connection,
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
577
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
578
579
580
  UINT32 channel_number;
  int type;
  int want_reply;
581
582
  START;
  
Niels Möller's avatar
Niels Möller committed
583
584
585
586
587
588
589
590
  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))
    {
591
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
592
593
						   channel_number);

594
595
596
597
      /* 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
598
599
600
601
      if (channel)
	{
	  struct channel_request *req;

602
603
	  if (type && channel->request_types 
	      && ( (req = ALIST_GET(channel->request_types, type)) ))
604
605
606
607
	    RETURN
	      (channel_process_status
	       (connection->channels, channel_number,
		CHANNEL_REQUEST(req, channel, connection, want_reply, &buffer)));
608
	  else
609
610
611
612
	    RETURN (want_reply
		    ? A_WRITE(connection->write,
			      format_channel_failure(channel->channel_number))
		    : LSH_OK | LSH_GOON);
613
	  
Niels Möller's avatar
Niels Möller committed
614
	}
615
      werror("SSH_MSG_CHANNEL_REQUEST on nonexistant channel %i\n",
Niels Möller's avatar
Niels Möller committed
616
617
	     channel_number);

618
619
620
621
    }
  RETURN (LSH_FAIL | LSH_DIE);
  
  END(packet);
Niels Möller's avatar
Niels Möller committed
622
623
}
      
624
625
static int do_window_adjust(struct packet_handler *closure UNUSED,
			    struct ssh_connection *connection,
626
			    struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
627
628
{
  struct simple_buffer buffer;
629
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
630
631
632
633
634
635
636
  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)
637
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
638
639
640
      && parse_uint32(&buffer, &size)
      && parse_eod(&buffer))
    {
641
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
642
643
644
645
						   channel_number);

      lsh_string_free(packet);
      
Niels Möller's avatar
Niels Möller committed
646
      if (channel
647
648
	  && !(channel->flags & (CHANNEL_RECEIVED_EOF
				 | CHANNEL_RECEIVED_CLOSE)))
Niels Möller's avatar
Niels Möller committed
649
	{
Niels Möller's avatar
Niels Möller committed
650
651
652
653
	  if (! (channel->flags & CHANNEL_SENT_CLOSE))
	    {
	      channel->send_window_size += size;
	      if (channel->send_window_size && channel->send)
654
		return channel_process_status(connection->channels,
Niels Möller's avatar
Niels Möller committed
655
656
					      channel_number,
					      CHANNEL_SEND(channel));
Niels Möller's avatar
Niels Möller committed
657
	    }
Niels Möller's avatar
Niels Möller committed
658
659
660
661
	  return LSH_OK | LSH_GOON;
	}
      /* FIXME: What to do now? Should unknown channel numbers be
       * ignored silently? */
662
663
      werror("SSH_MSG_CHANNEL_WINDOW_ADJUST on nonexistant or closed "
	     "channel %i\n", channel_number);
Niels Möller's avatar
Niels Möller committed
664
665
666
667
668
669
670
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);

  return LSH_FAIL | LSH_DIE;
}

671
672
static int do_channel_data(struct packet_handler *closure UNUSED,
			   struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
673
674
675
			   struct lsh_string *packet)
{
  struct simple_buffer buffer;
676
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
677
678
679
680
681
682
683
  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)
684
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
685
686
687
      && ( (data = parse_string_copy(&buffer)) )
      && parse_eod(&buffer))
    {
688
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
689
690
691
692
						   channel_number);

      lsh_string_free(packet);
      
693
      if (channel && channel->receive
694
695
	  && !(channel->flags & (CHANNEL_RECEIVED_EOF
				 | CHANNEL_RECEIVED_CLOSE)))
Niels Möller's avatar
Niels Möller committed
696
	{
Niels Möller's avatar
Niels Möller committed
697
	  if (channel->flags & CHANNEL_SENT_CLOSE)
Niels Möller's avatar
Niels Möller committed
698
	    {
699
	      werror("Ignoring data on channel which is closing\n");
Niels Möller's avatar
Niels Möller committed
700
	      return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
701
	    }
Niels Möller's avatar
Niels Möller committed
702
703
	  else
	    {
704
705
	      int res = 0;
	      
Niels Möller's avatar
Niels Möller committed
706
707
708
	      if (data->length > channel->rec_window_size)
		{
		  /* Truncate data to fit window */
709
		  werror("Channel data overflow. Extra data ignored.\n"); 
Niels Möller's avatar
Niels Möller committed
710
711
		  data->length = channel->rec_window_size;
		}
712
713
714
715

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

718
	      /* FIXME: Unconditionally adjusting the receive window
719
	       * breaks flow control. We better let the channel's
720
	       * receive method decide whether or not to receive more
721
722
723
	       * data. */
	      res = adjust_rec_window(channel);
	      
724
725
	      if (LSH_CLOSEDP(res))
		return res;
726

Niels Möller's avatar
Niels Möller committed
727
	      return channel_process_status(
728
		connection->channels, channel_number,
729
		res | CHANNEL_RECEIVE(channel, 
Niels Möller's avatar
Niels Möller committed
730
				      CHANNEL_DATA, data));
Niels Möller's avatar
Niels Möller committed
731
732
	    }
	  return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
733
734
	}
	  
735
      werror("Data on closed or non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
736
737
738
739
740
741
742
743
744
	     channel_number);
      lsh_string_free(data);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  
  return LSH_FAIL | LSH_DIE;
}

745
746
static int do_channel_extended_data(struct packet_handler *closure UNUSED,
				    struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
747
748
749
				    struct lsh_string *packet)
{
  struct simple_buffer buffer;
750
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
751
752
753
754
755
756
757
758
  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)
759
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
760
761
762
763
      && parse_uint32(&buffer, &type)
      && ( (data = parse_string_copy(&buffer)) )
      && parse_eod(&buffer))
    {
764
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
765
766
767
768
						   channel_number);

      lsh_string_free(packet);
      
769
      if (channel && channel->receive
770
771
	  && !(channel->flags & (CHANNEL_RECEIVED_EOF
				 | CHANNEL_RECEIVED_CLOSE)))
Niels Möller's avatar
Niels Möller committed
772
	{
Niels Möller's avatar
Niels Möller committed
773
	  if (channel->flags & CHANNEL_SENT_CLOSE)
Niels Möller's avatar
Niels Möller committed
774
	    {
775
	      werror("Ignoring extended data on channel which is closing\n");
Niels Möller's avatar
Niels Möller committed
776
	      return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
777
	    }
Niels Möller's avatar
Niels Möller committed
778
	  else
Niels Möller's avatar
Niels Möller committed
779
	    {
780
781
	      int res = 0;
	      
Niels Möller's avatar
Niels Möller committed
782
783
784
	      if (data->length > channel->rec_window_size)
		{
		  /* Truncate data to fit window */
785
		  werror("Channel extended data overflow. "
Niels Möller's avatar
Niels Möller committed
786
787
788
789
790
			 "Extra data ignored.\n");
		  data->length = channel->rec_window_size;
		}
	      
	      channel->rec_window_size -= data->length;
791

792
793
794
795
796
797
	      /* FIXME: Like for do_channel_data(), unconditionally
	       * adjusting the window breaks flow control. */
	      res = adjust_rec_window(channel);

	      if (LSH_CLOSEDP(res))
		return res;
798

Niels Möller's avatar
Niels Möller committed
799
800
801
	      switch(type)
		{
		case SSH_EXTENDED_DATA_STDERR:
Niels Möller's avatar
Niels Möller committed
802
		  return channel_process_status(
803
		    connection->channels, channel_number,
804
		    res | CHANNEL_RECEIVE(channel, 
Niels Möller's avatar
Niels Möller committed
805
					  CHANNEL_STDERR_DATA, data));
Niels Möller's avatar
Niels Möller committed
806
		default:
807
		  werror("Unknown type %i of extended data.\n",
Niels Möller's avatar
Niels Möller committed
808
809
810
811
			 type);
		  lsh_string_free(data);
		  return LSH_FAIL | LSH_DIE;
		}
Niels Möller's avatar
Niels Möller committed
812
813
	    }
	}
814
      werror("Extended data on closed or non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
815
816
817
818
819
820
821
822
823
	     channel_number);
      lsh_string_free(data);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  
  return LSH_FAIL | LSH_DIE;
}

824
825
static int do_channel_eof(struct packet_handler *closure UNUSED,
			  struct ssh_connection *connection,
826
			  struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
827
828
{
  struct simple_buffer buffer;
829
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
830
831
832
833
834
835
  UINT32 channel_number;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_EOF)
836
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
837
838
      && parse_eod(&buffer))
    {
839
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
840
841
842
843
						   channel_number);

      lsh_string_free(packet);

Niels Möller's avatar
Niels Möller committed
844
845
      if (channel)
	{
846
847
	  int res = 0;
	  
848
	  if (channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_RECEIVED_CLOSE))
Niels Möller's avatar
Niels Möller committed
849
	    {
850
	      werror("Receiving EOF on channel on closed channel.\n");
Niels Möller's avatar
Niels Möller committed
851
852
853
	      return LSH_FAIL | LSH_DIE;
	    }

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

856
857
	  if (channel->eof)
	    res = CHANNEL_EOF(channel);
858
859
860
	  else
	    /* FIXME: What is a reasonable default behaviour?
	     * Closing the channel may be the right thing to do. */
861
862
863
	    if (! (channel->flags & CHANNEL_SENT_CLOSE))
	      res |= channel_close(channel);
#if 0
864
865
866
	  if (!LSH_CLOSEDP(res)
	      && ! (channel->flags & CHANNEL_SENT_CLOSE)
	      && (channel->flags & CHANNEL_SENT_EOF))
Niels Möller's avatar
Niels Möller committed
867
868
869
	    {
	      /* Both parties have sent EOF. Initiate close, if we
	       * havn't done that already. */
870
871
	      
	      res |= channel_close(channel);
Niels Möller's avatar
Niels Möller committed
872
	    }
873
#endif      
874
	  return channel_process_status(connection->channels, channel_number,
875
876
					res);

Niels Möller's avatar
Niels Möller committed
877
	}
878
      werror("EOF on non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
879
880
	     channel_number);
      return LSH_FAIL | LSH_DIE;
Niels Möller's avatar
Niels Möller committed
881
    }
Niels Möller's avatar
Niels Möller committed
882
      
Niels Möller's avatar
Niels Möller committed
883
884
885
886
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

887
888
static int do_channel_close(struct packet_handler *closure UNUSED,
			    struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
889
890
891
			    struct lsh_string *packet)
{
  struct simple_buffer buffer;
892
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
893
894
895
896
897
898
  UINT32 channel_number;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_CLOSE)
899
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
900
901
      && parse_eod(&buffer))
    {
902
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
903
904
905
906
						   channel_number);

      lsh_string_free(packet);
      
Niels Möller's avatar
Niels Möller committed
907
908
      if (channel)
	{
909
910
	  int res = 0;
	  
911
	  if (channel->flags & CHANNEL_RECEIVED_CLOSE)
Niels Möller's avatar
Niels Möller committed
912
	    {
913
	      werror("Receiving multiple CLOSE on channel.\n");
Niels Möller's avatar
Niels Möller committed
914
915
916
	      return LSH_FAIL | LSH_DIE;
	    }

917
	  channel->flags |= CHANNEL_RECEIVED_CLOSE;
Niels Möller's avatar
Niels Möller committed
918
	  
919
	  if (! (channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_SENT_EOF)))
Niels Möller's avatar
Niels Möller committed
920
	    {
921
	      werror("Unexpected channel CLOSE.\n");
Niels Möller's avatar
Niels Möller committed
922
	    }
923

924
	  if (! (channel->flags & (CHANNEL_RECEIVED_EOF))
925
	      && channel->eof)
926
	    res = CHANNEL_EOF(channel);
Niels Möller's avatar
Niels Möller committed
927
	  
Niels Möller's avatar
Niels Möller committed
928
	  return channel_process_status(
929
	    connection->channels, channel_number,
930
931
932
933
	    ( ( (channel->flags & (CHANNEL_SENT_CLOSE))
		? LSH_OK | LSH_CHANNEL_FINISHED
		: channel_close(channel))
	      | res));
Niels Möller's avatar
Niels Möller committed
934
	}
935
      werror("CLOSE on non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
936
937
	     channel_number);
      return LSH_FAIL | LSH_DIE;
Niels Möller's avatar
Niels Möller committed
938
939
940
941
942
943
      
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

944
static int do_channel_open_confirm(struct packet_handler *closure UNUSED,
Niels Möller's avatar
Niels Möller committed
945
946
				   struct ssh_connection *connection,
				   struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
947
948
{
  struct simple_buffer buffer;
949
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
  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))
    {
965
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
966
967
968
969
						   local_channel_number);

      lsh_string_free(packet);

970
      if (channel && channel->open_continuation)
Niels Möller's avatar
Niels Möller committed
971
972
973
974
975
	{
	  channel->channel_number = remote_channel_number;
	  channel->send_window_size = window_size;
	  channel->send_max_packet = max_packet;

976
977
978
979
	  return channel_process_status
	    (connection->channels,
	     local_channel_number,
	     COMMAND_RETURN(channel->open_continuation, channel));
Niels Möller's avatar
Niels Möller committed
980
	}
981
      werror("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION on channel %i\n",
Niels Möller's avatar
Niels Möller committed
982
983
984
985
986
987
988
	     local_channel_number);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

989
990
static int do_channel_open_failure(struct packet_handler *closure UNUSED,
			      struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
991
992
993
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
994
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
  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)
      && parse_eod(&buffer))
    {
1014
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
1015
1016
1017
1018
						   channel_number);

      /* lsh_string_free(packet); */

1019
      if (channel && channel->open_continuation)
Niels Möller's avatar
Niels Möller committed
1020
	{
1021
	  int res = COMMAND_RETURN(channel->open_continuation, NULL);
Niels Möller's avatar
Niels Möller committed
1022
1023

	  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
1024

1025
	  return channel_process_status(connection->channels, channel_number,
Niels Möller's avatar
Niels Möller committed
1026
					res | LSH_CHANNEL_FINISHED);
Niels Möller's avatar
Niels Möller committed
1027
	}
1028
      werror("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE on channel %i\n",
Niels Möller's avatar
Niels Möller committed
1029
1030
1031
1032
1033
1034
1035
1036
1037
	     channel_number);
      lsh_string_free(packet);
      
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

1038
1039
static int do_channel_success(struct packet_handler *closure UNUSED,
			      struct ssh_connection *connection,
1040
1041
1042
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
1043
  unsigned msg_number;
1044
  UINT32 channel_number;
1045
1046
  struct ssh_channel *channel;
      
1047
1048
1049
1050
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_SUCCESS)
1051
      && parse_uint32(&buffer, &channel_number)
1052
      && parse_eod(&buffer)
1053
      && (channel = lookup_channel(connection->channels, channel_number)))
1054
1055
    {
      lsh_string_free(packet);
1056

1057
      if (object_queue_is_empty(&channel->pending_requests))
1058
	{
1059
	  werror("do_channel_success: Unexpected message. Ignoring.\n");
1060
1061
	  return LSH_OK | LSH_GOON;
	}
1062
      {
Niels Möller's avatar
Niels Möller committed
1063
	CAST_SUBTYPE(command_continuation, c,
1064
1065
1066
1067
	     object_queue_remove_head(&channel->pending_requests));
	return channel_process_status(connection->channels, channel_number,
				      COMMAND_RETURN(c, channel));
      }
1068
1069
1070
1071
1072
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

1073
1074
static int do_channel_failure(struct packet_handler *closure UNUSED,
			      struct ssh_connection *connection,
1075
1076
1077
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
1078
  unsigned msg_number;
1079
  UINT32 channel_number;
1080
  struct ssh_channel *channel;
1081
1082
1083
1084
1085
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_FAILURE)
1086
      && parse_uint32(&buffer, &channel_number)
1087
      && parse_eod(&buffer)
1088
      && (channel = lookup_channel(connection->channels, channel_number)))
1089
1090
1091
    {
      lsh_string_free(packet);
      
1092
      if (object_queue_is_empty(&channel->pending_requests))
1093
1094
1095
1096
	{
	  werror("do_channel_failure: No handler. Ignoring.\n");
	  return LSH_OK | LSH_GOON;
	}
1097
      {
Niels Möller's avatar
Niels Möller committed
1098
	CAST_SUBTYPE(command_continuation, c,
1099
1100
1101
1102
1103
	     object_queue_remove_head(&channel->pending_requests));

	return channel_process_status(connection->channels, channel_number,
				      COMMAND_RETURN(c, NULL));
      }
1104
1105
1106
1107
1108
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

1109
1110
1111
static int do_connection_service(struct command *s,
				 struct lsh_object *x,
				 struct command_continuation *c)
Niels Möller's avatar
Niels Möller committed
1112
{
1113
  CAST(connection_service, self, s);
1114
  CAST(ssh_connection, connection, x);
1115

1116
  struct channel_table *table;
Niels Möller's avatar
Niels Möller committed
1117
  
1118
1119
  NEW(global_request_handler, globals);
  NEW(channel_open_handler, open);
1120
  NEW(packet_handler, request);
Niels Möller's avatar
Niels Möller committed
1121

1122
1123
1124
  NEW(packet_handler, adjust);
  NEW(packet_handler, data);
  NEW(packet_handler, extended);
Niels Möller's avatar
Niels Möller committed
1125

1126
1127
  NEW(packet_handler, eof);
  NEW(packet_handler, close);
1128

1129
1130
  NEW(packet_handler, open_confirm);
  NEW(packet_handler, open_failure);
Niels Möller's avatar
Niels Möller committed
1131

1132
1133
  NEW(packet_handler, channel_success);
  NEW(packet_handler, channel_failure);
Niels Möller's avatar
Niels Möller committed
1134

1135
  table = make_channel_table();
Niels Möller's avatar
Niels Möller committed
1136
  
1137
1138
1139
  connection->channels = table;
  
  globals->super.handler = do_global_request;
Niels Möller's avatar
Niels Möller committed
1140
  globals->global_requests = self->global_requests;
1141
  connection->dispatch[SSH_MSG_GLOBAL_REQUEST] = &globals->super;
Niels Möller's avatar
Niels Möller committed
1142
    
1143
  open->super.handler = do_channel_open;
Niels Möller's avatar
Niels Möller committed
1144
  open->channel_types = self->channel_types;
1145
  connection->dispatch[SSH_MSG_CHANNEL_OPEN] = &open->super;
Niels Möller's avatar
Niels Möller committed
1146

1147
1148
  request->handler = do_channel_request;
  connection->dispatch[SSH_MSG_CHANNEL_REQUEST] = request;
Niels Möller's avatar
Niels Möller committed
1149