channel.c 36.2 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
245
246
247
248
249
250
251
252
253
254
static int adjust_rec_window(struct ssh_channel *channel)
{
  if (channel->rec_window_size < channel->max_window / 2)
    {
      int increment = channel->max_window - channel->rec_window_size;
      channel->rec_window_size = channel->max_window;
      
      return A_WRITE(channel->write,
		     prepare_window_adjust(channel, increment));
    }
  return 0;
}

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

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

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

308
309
310
311
312
313
314
/* 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
315
/* Channel related messages */
Niels Möller's avatar
Niels Möller committed
316
317
318
319
static int do_global_request(struct packet_handler *c,
			     struct ssh_connection *connection,
			     struct lsh_string *packet)
{
320
  CAST(global_request_handler, closure, c);
Niels Möller's avatar
Niels Möller committed
321
322

  struct simple_buffer buffer;
323
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
324
325
  int name;
  int want_reply;
326
  START;
Niels Möller's avatar
Niels Möller committed
327
328
329
330
331
332
333
334
335
336
337
  
  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;

      if (!name || !(req = ALIST_GET(closure->global_requests, name)))
338
339
	RETURN (A_WRITE(connection->write,
		       format_global_failure()));
Niels Möller's avatar
Niels Möller committed
340

341
      RETURN (GLOBAL_REQUEST(req, connection, want_reply, &buffer));
Niels Möller's avatar
Niels Möller committed
342
    }
343
  RETURN (LSH_FAIL | LSH_DIE);
Niels Möller's avatar
Niels Möller committed
344

345
  END (packet);
Niels Möller's avatar
Niels Möller committed
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
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/* 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...)", ""));
    }

  /* FIXME: This copying could just as wel be done by the
   * 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;
}
414

415

416
417
418
419
420
421
422
423
424
425
426
#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)))
*/
427

428
429
430
431
432
433
434
435
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
436
437
438
439
static int do_channel_open(struct packet_handler *c,
			   struct ssh_connection *connection,
			   struct lsh_string *packet)
{
440
  CAST(channel_open_handler, closure, c);
Niels Möller's avatar
Niels Möller committed
441
442

  struct simple_buffer buffer;
443
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
444
  int type;
445
446
447
  UINT32 remote_channel_number;
  UINT32 window_size;
  UINT32 max_packet;
448
  START;
Niels Möller's avatar
Niels Möller committed
449
450
451
452
453
454
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_OPEN)
      && parse_atom(&buffer, &type)
455
456
457
      && 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
458
459
    {
      struct channel_open *open;
460
461
      struct channel_open_response *response;
      int res;
462
      
463
      if (connection->channels->pending_close)
Niels Möller's avatar
Niels Möller committed
464
	/* We are waiting for channels to close. Don't open any new ones. */
465
466
467
468
469
	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
470
471
      
      if (!type || !(open = ALIST_GET(closure->channel_types, type)))
472
473
474
475
	RETURN (A_WRITE(connection->write,
			format_open_failure(remote_channel_number,
					    SSH_OPEN_UNKNOWN_CHANNEL_TYPE,
					    "Unknown channel type", "")));
476

477
478
479
480
481
482
483
484
      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
485
    }
486
  RETURN (LSH_FAIL | LSH_DIE);
Niels Möller's avatar
Niels Möller committed
487

488
  END(packet);
Niels Möller's avatar
Niels Möller committed
489
490
}     

491
static int do_channel_request(struct packet_handler *closure UNUSED,
Niels Möller's avatar
Niels Möller committed
492
493
494
495
			      struct ssh_connection *connection,
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
496
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
497
498
499
  UINT32 channel_number;
  int type;
  int want_reply;
500
501
  START;
  
Niels Möller's avatar
Niels Möller committed
502
503
504
505
506
507
508
509
  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))
    {
510
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
511
512
						   channel_number);

513
514
515
516
      /* 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
517
518
519
520
      if (channel)
	{
	  struct channel_request *req;

521
522
	  if (type && channel->request_types 
	      && ( (req = ALIST_GET(channel->request_types, type)) ))
523
524
525
526
	    RETURN
	      (channel_process_status
	       (connection->channels, channel_number,
		CHANNEL_REQUEST(req, channel, connection, want_reply, &buffer)));
527
	  else
528
529
530
531
	    RETURN (want_reply
		    ? A_WRITE(connection->write,
			      format_channel_failure(channel->channel_number))
		    : LSH_OK | LSH_GOON);
532
	  
Niels Möller's avatar
Niels Möller committed
533
	}
534
      werror("SSH_MSG_CHANNEL_REQUEST on nonexistant channel %i\n",
Niels Möller's avatar
Niels Möller committed
535
536
	     channel_number);

537
538
539
540
    }
  RETURN (LSH_FAIL | LSH_DIE);
  
  END(packet);
Niels Möller's avatar
Niels Möller committed
541
542
}
      
543
544
static int do_window_adjust(struct packet_handler *closure UNUSED,
			    struct ssh_connection *connection,
545
			    struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
546
547
{
  struct simple_buffer buffer;
548
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
549
550
551
552
553
554
555
  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)
556
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
557
558
559
      && parse_uint32(&buffer, &size)
      && parse_eod(&buffer))
    {
560
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
561
562
563
564
						   channel_number);

      lsh_string_free(packet);
      
Niels Möller's avatar
Niels Möller committed
565
      if (channel
566
567
	  && !(channel->flags & (CHANNEL_RECEIVED_EOF
				 | CHANNEL_RECEIVED_CLOSE)))
Niels Möller's avatar
Niels Möller committed
568
	{
Niels Möller's avatar
Niels Möller committed
569
570
571
572
	  if (! (channel->flags & CHANNEL_SENT_CLOSE))
	    {
	      channel->send_window_size += size;
	      if (channel->send_window_size && channel->send)
573
		return channel_process_status(connection->channels,
Niels Möller's avatar
Niels Möller committed
574
575
					      channel_number,
					      CHANNEL_SEND(channel));
Niels Möller's avatar
Niels Möller committed
576
	    }
Niels Möller's avatar
Niels Möller committed
577
578
579
580
	  return LSH_OK | LSH_GOON;
	}
      /* FIXME: What to do now? Should unknown channel numbers be
       * ignored silently? */
581
582
      werror("SSH_MSG_CHANNEL_WINDOW_ADJUST on nonexistant or closed "
	     "channel %i\n", channel_number);
Niels Möller's avatar
Niels Möller committed
583
584
585
586
587
588
589
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);

  return LSH_FAIL | LSH_DIE;
}

590
591
static int do_channel_data(struct packet_handler *closure UNUSED,
			   struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
592
593
594
			   struct lsh_string *packet)
{
  struct simple_buffer buffer;
595
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
596
597
598
599
600
601
602
  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)
603
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
604
605
606
      && ( (data = parse_string_copy(&buffer)) )
      && parse_eod(&buffer))
    {
607
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
608
609
610
611
						   channel_number);

      lsh_string_free(packet);
      
612
      if (channel && channel->receive
613
614
	  && !(channel->flags & (CHANNEL_RECEIVED_EOF
				 | CHANNEL_RECEIVED_CLOSE)))
Niels Möller's avatar
Niels Möller committed
615
	{
Niels Möller's avatar
Niels Möller committed
616
	  if (channel->flags & CHANNEL_SENT_CLOSE)
Niels Möller's avatar
Niels Möller committed
617
	    {
618
	      werror("Ignoring data on channel which is closing\n");
Niels Möller's avatar
Niels Möller committed
619
	      return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
620
	    }
Niels Möller's avatar
Niels Möller committed
621
622
	  else
	    {
623
624
	      int res = 0;
	      
Niels Möller's avatar
Niels Möller committed
625
626
627
	      if (data->length > channel->rec_window_size)
		{
		  /* Truncate data to fit window */
628
		  werror("Channel data overflow. Extra data ignored.\n"); 
Niels Möller's avatar
Niels Möller committed
629
630
		  data->length = channel->rec_window_size;
		}
631
632
633
634

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

637
	      /* FIXME: Unconditionally adjusting the receive window
638
	       * breaks flow control. We better let the channel's
639
	       * receive method decide whether or not to receive more
640
641
642
	       * data. */
	      res = adjust_rec_window(channel);
	      
643
644
645
646
647
648
649
650
651
	      if (channel->rec_window_size < channel->max_window / 2)
		{
		  res = A_WRITE(channel->write, prepare_window_adjust
				(channel,
				 channel->max_window - channel->rec_window_size));
		  if (LSH_CLOSEDP(res))
		    return res;
		}

Niels Möller's avatar
Niels Möller committed
652
	      return channel_process_status(
653
		connection->channels, channel_number,
654
		res | CHANNEL_RECEIVE(channel, 
Niels Möller's avatar
Niels Möller committed
655
				      CHANNEL_DATA, data));
Niels Möller's avatar
Niels Möller committed
656
657
	    }
	  return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
658
659
	}
	  
660
      werror("Data on closed or non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
661
662
663
664
665
666
667
668
669
	     channel_number);
      lsh_string_free(data);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  
  return LSH_FAIL | LSH_DIE;
}

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

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

	      if (channel->rec_window_size < channel->max_window / 2)
		{
		  res = A_WRITE(channel->write, prepare_window_adjust
				(channel,
721
722
				 channel->max_window
				 - channel->rec_window_size));
723
724
725
726
		  if (LSH_CLOSEDP(res))
		    return res;
		}

Niels Möller's avatar
Niels Möller committed
727
728
729
	      switch(type)
		{
		case SSH_EXTENDED_DATA_STDERR:
Niels Möller's avatar
Niels Möller committed
730
		  return channel_process_status(
731
		    connection->channels, channel_number,
732
		    res | CHANNEL_RECEIVE(channel, 
Niels Möller's avatar
Niels Möller committed
733
					  CHANNEL_STDERR_DATA, data));
Niels Möller's avatar
Niels Möller committed
734
		default:
735
		  werror("Unknown type %i of extended data.\n",
Niels Möller's avatar
Niels Möller committed
736
737
738
739
			 type);
		  lsh_string_free(data);
		  return LSH_FAIL | LSH_DIE;
		}
Niels Möller's avatar
Niels Möller committed
740
741
	    }
	}
742
      werror("Extended data on closed or non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
743
744
745
746
747
748
749
750
751
	     channel_number);
      lsh_string_free(data);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  
  return LSH_FAIL | LSH_DIE;
}

752
753
static int do_channel_eof(struct packet_handler *closure UNUSED,
			  struct ssh_connection *connection,
754
			  struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
755
756
{
  struct simple_buffer buffer;
757
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
758
759
760
761
762
763
  UINT32 channel_number;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_EOF)
764
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
765
766
      && parse_eod(&buffer))
    {
767
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
768
769
770
771
						   channel_number);

      lsh_string_free(packet);

Niels Möller's avatar
Niels Möller committed
772
773
      if (channel)
	{
774
775
	  int res = 0;
	  
776
	  if (channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_RECEIVED_CLOSE))
Niels Möller's avatar
Niels Möller committed
777
	    {
778
	      werror("Receiving EOF on channel on closed channel.\n");
Niels Möller's avatar
Niels Möller committed
779
780
781
	      return LSH_FAIL | LSH_DIE;
	    }

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

784
785
	  if (channel->eof)
	    res = CHANNEL_EOF(channel);
786
787
788
	  else
	    /* FIXME: What is a reasonable default behaviour?
	     * Closing the channel may be the right thing to do. */
789
790
791
	    if (! (channel->flags & CHANNEL_SENT_CLOSE))
	      res |= channel_close(channel);
#if 0
792
793
794
	  if (!LSH_CLOSEDP(res)
	      && ! (channel->flags & CHANNEL_SENT_CLOSE)
	      && (channel->flags & CHANNEL_SENT_EOF))
Niels Möller's avatar
Niels Möller committed
795
796
797
	    {
	      /* Both parties have sent EOF. Initiate close, if we
	       * havn't done that already. */
798
799
	      
	      res |= channel_close(channel);
Niels Möller's avatar
Niels Möller committed
800
	    }
801
#endif      
802
	  return channel_process_status(connection->channels, channel_number,
803
804
					res);

Niels Möller's avatar
Niels Möller committed
805
	}
806
      werror("EOF on non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
807
808
	     channel_number);
      return LSH_FAIL | LSH_DIE;
Niels Möller's avatar
Niels Möller committed
809
    }
Niels Möller's avatar
Niels Möller committed
810
      
Niels Möller's avatar
Niels Möller committed
811
812
813
814
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

815
816
static int do_channel_close(struct packet_handler *closure UNUSED,
			    struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
817
818
819
			    struct lsh_string *packet)
{
  struct simple_buffer buffer;
820
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
821
822
823
824
825
826
  UINT32 channel_number;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_CLOSE)
827
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
828
829
      && parse_eod(&buffer))
    {
830
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
831
832
833
834
						   channel_number);

      lsh_string_free(packet);
      
Niels Möller's avatar
Niels Möller committed
835
836
      if (channel)
	{
837
838
	  int res = 0;
	  
839
	  if (channel->flags & CHANNEL_RECEIVED_CLOSE)
Niels Möller's avatar
Niels Möller committed
840
	    {
841
	      werror("Receiving multiple CLOSE on channel.\n");
Niels Möller's avatar
Niels Möller committed
842
843
844
	      return LSH_FAIL | LSH_DIE;
	    }

845
	  channel->flags |= CHANNEL_RECEIVED_CLOSE;
Niels Möller's avatar
Niels Möller committed
846
	  
847
	  if (! (channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_SENT_EOF)))
Niels Möller's avatar
Niels Möller committed
848
	    {
849
	      werror("Unexpected channel CLOSE.\n");
Niels Möller's avatar
Niels Möller committed
850
	    }
851

852
	  if (! (channel->flags & (CHANNEL_RECEIVED_EOF))
853
	      && channel->eof)
854
	    res = CHANNEL_EOF(channel);
Niels Möller's avatar
Niels Möller committed
855
	  
Niels Möller's avatar
Niels Möller committed
856
	  return channel_process_status(
857
	    connection->channels, channel_number,
858
859
860
861
	    ( ( (channel->flags & (CHANNEL_SENT_CLOSE))
		? LSH_OK | LSH_CHANNEL_FINISHED
		: channel_close(channel))
	      | res));
Niels Möller's avatar
Niels Möller committed
862
	}
863
      werror("CLOSE on non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
864
865
	     channel_number);
      return LSH_FAIL | LSH_DIE;
Niels Möller's avatar
Niels Möller committed
866
867
868
869
870
871
      
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

872
static int do_channel_open_confirm(struct packet_handler *closure UNUSED,
Niels Möller's avatar
Niels Möller committed
873
874
				   struct ssh_connection *connection,
				   struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
875
876
{
  struct simple_buffer buffer;
877
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
  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))
    {
893
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
894
895
896
897
						   local_channel_number);

      lsh_string_free(packet);

898
      if (channel && channel->open_continuation)
Niels Möller's avatar
Niels Möller committed
899
900
901
902
903
	{
	  channel->channel_number = remote_channel_number;
	  channel->send_window_size = window_size;
	  channel->send_max_packet = max_packet;

904
905
906
907
	  return channel_process_status
	    (connection->channels,
	     local_channel_number,
	     COMMAND_RETURN(channel->open_continuation, channel));
Niels Möller's avatar
Niels Möller committed
908
	}
909
      werror("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION on channel %i\n",
Niels Möller's avatar
Niels Möller committed
910
911
912
913
914
915
916
	     local_channel_number);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

917
918
static int do_channel_open_failure(struct packet_handler *closure UNUSED,
			      struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
919
920
921
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
922
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
  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))
    {
942
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
943
944
945
946
						   channel_number);

      /* lsh_string_free(packet); */

947
      if (channel && channel->open_continuation)
Niels Möller's avatar
Niels Möller committed
948
	{
949
	  int res = COMMAND_RETURN(channel->open_continuation, NULL);
Niels Möller's avatar
Niels Möller committed
950
951

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

953
	  return channel_process_status(connection->channels, channel_number,
Niels Möller's avatar
Niels Möller committed
954
					res | LSH_CHANNEL_FINISHED);
Niels Möller's avatar
Niels Möller committed
955
	}
956
      werror("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE on channel %i\n",
Niels Möller's avatar
Niels Möller committed
957
958
959
960
961
962
963
964
965
	     channel_number);
      lsh_string_free(packet);
      
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

966
967
static int do_channel_success(struct packet_handler *closure UNUSED,
			      struct ssh_connection *connection,
968
969
970
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
971
  unsigned msg_number;
972
  UINT32 channel_number;
973
974
  struct ssh_channel *channel;
      
975
976
977
978
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_SUCCESS)
979
      && parse_uint32(&buffer, &channel_number)
980
      && parse_eod(&buffer)
981
      && (channel = lookup_channel(connection->channels, channel_number)))
982
983
    {
      lsh_string_free(packet);
984

985
      if (object_queue_is_empty(&channel->pending_requests))
986
	{
987
	  werror("do_channel_success: Unexpected message. Ignoring.\n");
988
989
	  return LSH_OK | LSH_GOON;
	}
990
      {
Niels Möller's avatar
Niels Möller committed
991
	CAST_SUBTYPE(command_continuation, c,
992
993
994
995
	     object_queue_remove_head(&channel->pending_requests));
	return channel_process_status(connection->channels, channel_number,
				      COMMAND_RETURN(c, channel));
      }
996
997
998
999
1000
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

1001
1002
static int do_channel_failure(struct packet_handler *closure UNUSED,
			      struct ssh_connection *connection,
1003
1004
1005
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
1006
  unsigned msg_number;
1007
  UINT32 channel_number;
1008
  struct ssh_channel *channel;
1009
1010
1011
1012
1013
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_FAILURE)
1014
      && parse_uint32(&buffer, &channel_number)
1015
      && parse_eod(&buffer)
1016
      && (channel = lookup_channel(connection->channels, channel_number)))
1017
1018
1019
    {
      lsh_string_free(packet);
      
1020
      if (object_queue_is_empty(&channel->pending_requests))
1021
1022
1023
1024
	{
	  werror("do_channel_failure: No handler. Ignoring.\n");
	  return LSH_OK | LSH_GOON;
	}
1025
      {
Niels Möller's avatar
Niels Möller committed
1026
	CAST_SUBTYPE(command_continuation, c,
1027
1028
1029
1030
1031
	     object_queue_remove_head(&channel->pending_requests));

	return channel_process_status(connection->channels, channel_number,
				      COMMAND_RETURN(c, NULL));
      }
1032
1033
1034
1035
1036
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

1037
1038
1039
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
1040
{
1041
  CAST(connection_service, self, s);
1042
  CAST(ssh_connection, connection, x);
1043

1044
  struct channel_table *table;
Niels Möller's avatar
Niels Möller committed
1045
  
1046
1047
  NEW(global_request_handler, globals);
  NEW(channel_open_handler, open);
1048
  NEW(packet_handler, request);
Niels Möller's avatar
Niels Möller committed
1049

1050
1051
1052
  NEW(packet_handler, adjust);
  NEW(packet_handler, data);
  NEW(packet_handler, extended);
Niels Möller's avatar
Niels Möller committed
1053

1054
1055
  NEW(packet_handler, eof);
  NEW(packet_handler, close);
1056

1057
1058
  NEW(packet_handler, open_confirm);
  NEW(packet_handler, open_failure);
Niels Möller's avatar
Niels Möller committed
1059

1060
1061
  NEW(packet_handler, channel_success);
  NEW(packet_handler, channel_failure);
Niels Möller's avatar
Niels Möller committed
1062

1063
  table = make_channel_table();
Niels Möller's avatar
Niels Möller committed
1064
  
1065
1066
1067
  connection->channels = table;
  
  globals->super.handler = do_global_request;
Niels Möller's avatar
Niels Möller committed
1068
  globals->global_requests = self->global_requests;
1069
  connection->dispatch[SSH_MSG_GLOBAL_REQUEST] = &globals->super;
Niels Möller's avatar
Niels Möller committed
1070
    
1071
  open->super.handler = do_channel_open;
Niels Möller's avatar
Niels Möller committed
1072
  open->channel_types = self->channel_types;
1073
  connection->dispatch[SSH_MSG_CHANNEL_OPEN] = &open->super;
Niels Möller's avatar
Niels Möller committed
1074

1075
1076
  request->handler = do_channel_request;
  connection->dispatch[SSH_MSG_CHANNEL_REQUEST] = request;
Niels Möller's avatar
Niels Möller committed
1077
  
1078
1079
  adjust->handler = do_window_adjust;
  connection->dispatch[SSH_MSG_CHANNEL_WINDOW_ADJUST] = adjust;
Niels Möller's avatar
Niels Möller committed
1080

1081
1082
  data->handler = do_channel_data;
  connection->dispatch[SSH_MSG_CHANNEL_DATA] = data;
Niels Möller's avatar
Niels Möller committed
1083

1084
1085
  extended->handler = do_channel_extended_data;
  connection->dispatch[SSH_MSG_CHANNEL_EXTENDED_DATA] = extended;
Niels Möller's avatar
Niels Möller committed
1086

1087
1088
  eof->handler = do_channel_eof;
  connection->dispatch[SSH_MSG_CHANNEL_EOF] = eof;
Niels Möller's avatar
Niels Möller committed
1089

1090
1091
  close->handler = do_channel_close;
  connection->dispatch[SSH_MSG_CHANNEL_CLOSE] = close;
Niels Möller's avatar
Niels Möller committed
1092

1093
1094
  open_confirm->handler = do_channel_open_confirm;
  connection->dispatch[SSH_MSG_CHANNEL_OPEN_CONFIRMATION] = open_confirm;
Niels Möller's avatar
Niels Möller committed
1095

1096
1097
  open_failure->handler = do_channel_open_failure;
  connection->dispatch[SSH_MSG_CHANNEL_OPEN_FAILURE] = open_failure;
Niels Möller's avatar
Niels Möller committed
1098
  
1099
1100
  channel_success->handler = do_channel_success;
  connection->dispatch[SSH_MSG_CHANNEL_SUCCESS] = channel_success;
1101

1102
1103
  channel_failure->handler = do_channel_failure;
  connection->dispatch[SSH_MSG_CHANNEL_FAILURE] = channel_failure;