channel.c 35.6 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
51
52
53
54
55
56
57
58
     (vars
       ; Supported global requests 
       (global_requests object alist)

       (channel_types object alist)

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

       (start object connection_startup)))
*/

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
291
292
293
  if (status & LSH_CHANNEL_PENDING_CLOSE)
    table->pending_close = 1;
  
  if (status & LSH_CHANNEL_FINISHED)
    {
      /* Clear this bit */
      status &= ~LSH_CHANNEL_FINISHED;
294

295
296
      if (c->close)
	CHANNEL_CLOSE(c);
Niels Möller's avatar
Niels Möller committed
297
298
299
300
301
302
303
304
305
306
      
      dealloc_channel(table, channel);

      /* If this was the last channel, close connection */
      if (table->pending_close && !table->next_channel)
	status |= LSH_CLOSE;
    }

  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
414
415
/* 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;
}


Niels Möller's avatar
Niels Möller committed
416
417
418
419
static int do_channel_open(struct packet_handler *c,
			   struct ssh_connection *connection,
			   struct lsh_string *packet)
{
420
  CAST(channel_open_handler, closure, c);
Niels Möller's avatar
Niels Möller committed
421
422

  struct simple_buffer buffer;
423
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
424
  int type;
425
426
427
  UINT32 remote_channel_number;
  UINT32 window_size;
  UINT32 max_packet;
428
  START;
Niels Möller's avatar
Niels Möller committed
429
430
431
432
433
434
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_OPEN)
      && parse_atom(&buffer, &type)
435
436
437
      && 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
438
439
    {
      struct channel_open *open;
440
441
      struct channel_open_response *response;
      int res;
442
      
443
      if (connection->channels->pending_close)
Niels Möller's avatar
Niels Möller committed
444
	/* We are waiting for channels to close. Don't open any new ones. */
445
446
447
448
449
	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
450
451
      
      if (!type || !(open = ALIST_GET(closure->channel_types, type)))
452
453
454
455
	RETURN (A_WRITE(connection->write,
			format_open_failure(remote_channel_number,
					    SSH_OPEN_UNKNOWN_CHANNEL_TYPE,
					    "Unknown channel type", "")));
456

457
458
459
460
461
462
463
464
      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
465
    }
466
  RETURN (LSH_FAIL | LSH_DIE);
Niels Möller's avatar
Niels Möller committed
467

468
  END(packet);
Niels Möller's avatar
Niels Möller committed
469
470
}     

471
static int do_channel_request(struct packet_handler *closure UNUSED,
Niels Möller's avatar
Niels Möller committed
472
473
474
475
			      struct ssh_connection *connection,
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
476
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
477
478
479
  UINT32 channel_number;
  int type;
  int want_reply;
480
481
  START;
  
Niels Möller's avatar
Niels Möller committed
482
483
484
485
486
487
488
489
  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))
    {
490
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
491
492
						   channel_number);

493
494
495
496
      /* 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
497
498
499
500
      if (channel)
	{
	  struct channel_request *req;

501
502
	  if (type && channel->request_types 
	      && ( (req = ALIST_GET(channel->request_types, type)) ))
503
504
505
506
	    RETURN
	      (channel_process_status
	       (connection->channels, channel_number,
		CHANNEL_REQUEST(req, channel, connection, want_reply, &buffer)));
507
	  else
508
509
510
511
	    RETURN (want_reply
		    ? A_WRITE(connection->write,
			      format_channel_failure(channel->channel_number))
		    : LSH_OK | LSH_GOON);
512
	  
Niels Möller's avatar
Niels Möller committed
513
	}
514
      werror("SSH_MSG_CHANNEL_REQUEST on nonexistant channel %i\n",
Niels Möller's avatar
Niels Möller committed
515
516
	     channel_number);

517
518
519
520
    }
  RETURN (LSH_FAIL | LSH_DIE);
  
  END(packet);
Niels Möller's avatar
Niels Möller committed
521
522
}
      
523
524
static int do_window_adjust(struct packet_handler *closure UNUSED,
			    struct ssh_connection *connection,
525
			    struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
526
527
{
  struct simple_buffer buffer;
528
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
529
530
531
532
533
534
535
  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)
536
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
537
538
539
      && parse_uint32(&buffer, &size)
      && parse_eod(&buffer))
    {
540
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
541
542
543
544
						   channel_number);

      lsh_string_free(packet);
      
Niels Möller's avatar
Niels Möller committed
545
      if (channel
546
547
	  && !(channel->flags & (CHANNEL_RECEIVED_EOF
				 | CHANNEL_RECEIVED_CLOSE)))
Niels Möller's avatar
Niels Möller committed
548
	{
Niels Möller's avatar
Niels Möller committed
549
550
551
552
	  if (! (channel->flags & CHANNEL_SENT_CLOSE))
	    {
	      channel->send_window_size += size;
	      if (channel->send_window_size && channel->send)
553
		return channel_process_status(connection->channels,
Niels Möller's avatar
Niels Möller committed
554
555
					      channel_number,
					      CHANNEL_SEND(channel));
Niels Möller's avatar
Niels Möller committed
556
	    }
Niels Möller's avatar
Niels Möller committed
557
558
559
560
	  return LSH_OK | LSH_GOON;
	}
      /* FIXME: What to do now? Should unknown channel numbers be
       * ignored silently? */
561
      werror("SSH_MSG_CHANNEL_WINDOW_ADJUST on nonexistant or closed channel %i\n",
Niels Möller's avatar
Niels Möller committed
562
563
564
565
566
567
568
569
	     channel_number);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);

  return LSH_FAIL | LSH_DIE;
}

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

      lsh_string_free(packet);
      
592
593
      if (channel && channel->receive
	  && !(channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_RECEIVED_CLOSE)))
Niels Möller's avatar
Niels Möller committed
594
	{
Niels Möller's avatar
Niels Möller committed
595
	  if (channel->flags & CHANNEL_SENT_CLOSE)
Niels Möller's avatar
Niels Möller committed
596
	    {
597
	      werror("Ignoring data on channel which is closing\n");
Niels Möller's avatar
Niels Möller committed
598
	      return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
599
	    }
Niels Möller's avatar
Niels Möller committed
600
601
	  else
	    {
602
603
	      int res = 0;
	      
Niels Möller's avatar
Niels Möller committed
604
605
606
	      if (data->length > channel->rec_window_size)
		{
		  /* Truncate data to fit window */
607
		  werror("Channel data overflow. Extra data ignored.\n"); 
Niels Möller's avatar
Niels Möller committed
608
609
		  data->length = channel->rec_window_size;
		}
610
611
612
613

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

616
	      /* FIXME: Unconditionally adjusting the receive window
617
	       * breaks flow control. We better let the channel's
618
	       * receive method decide whether or not to receive more
619
620
621
	       * data. */
	      res = adjust_rec_window(channel);
	      
622
623
624
625
626
627
628
629
630
	      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
631
	      return channel_process_status(
632
		connection->channels, channel_number,
633
		res | CHANNEL_RECEIVE(channel, 
Niels Möller's avatar
Niels Möller committed
634
				      CHANNEL_DATA, data));
Niels Möller's avatar
Niels Möller committed
635
636
	    }
	  return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
637
638
	}
	  
639
      werror("Data on closed or non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
640
641
642
643
644
645
646
647
648
	     channel_number);
      lsh_string_free(data);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  
  return LSH_FAIL | LSH_DIE;
}

649
650
static int do_channel_extended_data(struct packet_handler *closure UNUSED,
				    struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
651
652
653
				    struct lsh_string *packet)
{
  struct simple_buffer buffer;
654
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
655
656
657
658
659
660
661
662
  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)
663
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
664
665
666
667
      && parse_uint32(&buffer, &type)
      && ( (data = parse_string_copy(&buffer)) )
      && parse_eod(&buffer))
    {
668
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
669
670
671
672
						   channel_number);

      lsh_string_free(packet);
      
673
674
      if (channel && channel->receive
	  && !(channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_RECEIVED_CLOSE)))
Niels Möller's avatar
Niels Möller committed
675
	{
Niels Möller's avatar
Niels Möller committed
676
	  if (channel->flags & CHANNEL_SENT_CLOSE)
Niels Möller's avatar
Niels Möller committed
677
	    {
678
	      werror("Ignoring extended data on channel which is closing\n");
Niels Möller's avatar
Niels Möller committed
679
	      return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
680
	    }
Niels Möller's avatar
Niels Möller committed
681
	  else
Niels Möller's avatar
Niels Möller committed
682
	    {
683
684
	      int res = 0;
	      
Niels Möller's avatar
Niels Möller committed
685
686
687
	      if (data->length > channel->rec_window_size)
		{
		  /* Truncate data to fit window */
688
		  werror("Channel extended data overflow. "
Niels Möller's avatar
Niels Möller committed
689
690
691
692
693
			 "Extra data ignored.\n");
		  data->length = channel->rec_window_size;
		}
	      
	      channel->rec_window_size -= data->length;
694
695
696
697
698
699
700
701
702
703

	      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
704
705
706
	      switch(type)
		{
		case SSH_EXTENDED_DATA_STDERR:
Niels Möller's avatar
Niels Möller committed
707
		  return channel_process_status(
708
		    connection->channels, channel_number,
709
		    res | CHANNEL_RECEIVE(channel, 
Niels Möller's avatar
Niels Möller committed
710
					  CHANNEL_STDERR_DATA, data));
Niels Möller's avatar
Niels Möller committed
711
		default:
712
		  werror("Unknown type %i of extended data.\n",
Niels Möller's avatar
Niels Möller committed
713
714
715
716
			 type);
		  lsh_string_free(data);
		  return LSH_FAIL | LSH_DIE;
		}
Niels Möller's avatar
Niels Möller committed
717
718
	    }
	}
719
      werror("Extended data on closed or non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
720
721
722
723
724
725
726
727
728
	     channel_number);
      lsh_string_free(data);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  
  return LSH_FAIL | LSH_DIE;
}

729
730
static int do_channel_eof(struct packet_handler *closure UNUSED,
			  struct ssh_connection *connection,
731
			  struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
732
733
{
  struct simple_buffer buffer;
734
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
735
736
737
738
739
740
  UINT32 channel_number;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_EOF)
741
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
742
743
      && parse_eod(&buffer))
    {
744
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
745
746
747
748
						   channel_number);

      lsh_string_free(packet);

Niels Möller's avatar
Niels Möller committed
749
750
      if (channel)
	{
751
752
	  int res = 0;
	  
753
	  if (channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_RECEIVED_CLOSE))
Niels Möller's avatar
Niels Möller committed
754
	    {
755
	      werror("Receiving EOF on channel on closed channel.\n");
Niels Möller's avatar
Niels Möller committed
756
757
758
	      return LSH_FAIL | LSH_DIE;
	    }

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

761
762
	  if (channel->eof)
	    res = CHANNEL_EOF(channel);
763
764
765
	  else
	    /* FIXME: What is a reasonable default behaviour?
	     * Closing the channel may be the right thing to do. */
766
767
768
	    if (! (channel->flags & CHANNEL_SENT_CLOSE))
	      res |= channel_close(channel);
#if 0
769
770
771
	  if (!LSH_CLOSEDP(res)
	      && ! (channel->flags & CHANNEL_SENT_CLOSE)
	      && (channel->flags & CHANNEL_SENT_EOF))
Niels Möller's avatar
Niels Möller committed
772
773
774
	    {
	      /* Both parties have sent EOF. Initiate close, if we
	       * havn't done that already. */
775
776
	      
	      res |= channel_close(channel);
Niels Möller's avatar
Niels Möller committed
777
	    }
778
#endif      
779
	  return channel_process_status(connection->channels, channel_number,
780
781
					res);

Niels Möller's avatar
Niels Möller committed
782
	}
783
      werror("EOF on non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
784
785
	     channel_number);
      return LSH_FAIL | LSH_DIE;
Niels Möller's avatar
Niels Möller committed
786
    }
Niels Möller's avatar
Niels Möller committed
787
      
Niels Möller's avatar
Niels Möller committed
788
789
790
791
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

792
793
static int do_channel_close(struct packet_handler *closure UNUSED,
			    struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
794
795
796
			    struct lsh_string *packet)
{
  struct simple_buffer buffer;
797
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
798
799
800
801
802
803
  UINT32 channel_number;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_CLOSE)
804
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
805
806
      && parse_eod(&buffer))
    {
807
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
808
809
810
811
						   channel_number);

      lsh_string_free(packet);
      
Niels Möller's avatar
Niels Möller committed
812
813
      if (channel)
	{
814
815
	  int res = 0;
	  
816
	  if (channel->flags & CHANNEL_RECEIVED_CLOSE)
Niels Möller's avatar
Niels Möller committed
817
	    {
818
	      werror("Receiving multiple CLOSE on channel.\n");
Niels Möller's avatar
Niels Möller committed
819
820
821
	      return LSH_FAIL | LSH_DIE;
	    }

822
	  channel->flags |= CHANNEL_RECEIVED_CLOSE;
Niels Möller's avatar
Niels Möller committed
823
	  
824
	  if (! (channel->flags & (CHANNEL_RECEIVED_EOF | CHANNEL_SENT_EOF)))
Niels Möller's avatar
Niels Möller committed
825
	    {
826
	      werror("Unexpected channel CLOSE.\n");
Niels Möller's avatar
Niels Möller committed
827
	    }
828

829
	  if (! (channel->flags & (CHANNEL_RECEIVED_EOF))
830
	      && channel->eof)
831
	    res = CHANNEL_EOF(channel);
Niels Möller's avatar
Niels Möller committed
832
	  
Niels Möller's avatar
Niels Möller committed
833
	  return channel_process_status(
834
	    connection->channels, channel_number,
835
836
837
838
	    ( ( (channel->flags & (CHANNEL_SENT_CLOSE))
		? LSH_OK | LSH_CHANNEL_FINISHED
		: channel_close(channel))
	      | res));
Niels Möller's avatar
Niels Möller committed
839
	}
840
      werror("CLOSE on non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
841
842
	     channel_number);
      return LSH_FAIL | LSH_DIE;
Niels Möller's avatar
Niels Möller committed
843
844
845
846
847
848
      
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

849
static int do_channel_open_confirm(struct packet_handler *closure UNUSED,
Niels Möller's avatar
Niels Möller committed
850
851
				   struct ssh_connection *connection,
				   struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
852
853
{
  struct simple_buffer buffer;
854
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
  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))
    {
870
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
871
872
873
874
						   local_channel_number);

      lsh_string_free(packet);

875
      if (channel && channel->open_continuation)
Niels Möller's avatar
Niels Möller committed
876
877
878
879
880
	{
	  channel->channel_number = remote_channel_number;
	  channel->send_window_size = window_size;
	  channel->send_max_packet = max_packet;

881
882
883
884
	  return channel_process_status
	    (connection->channels,
	     local_channel_number,
	     COMMAND_RETURN(channel->open_continuation, channel));
Niels Möller's avatar
Niels Möller committed
885
	}
886
      werror("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION on channel %i\n",
Niels Möller's avatar
Niels Möller committed
887
888
889
890
891
892
893
	     local_channel_number);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

894
895
static int do_channel_open_failure(struct packet_handler *closure UNUSED,
			      struct ssh_connection *connection,
Niels Möller's avatar
Niels Möller committed
896
897
898
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
899
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
  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))
    {
919
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
920
921
922
923
						   channel_number);

      /* lsh_string_free(packet); */

924
      if (channel && channel->open_continuation)
Niels Möller's avatar
Niels Möller committed
925
	{
926
	  int res = COMMAND_RETURN(channel->open_continuation, NULL);
Niels Möller's avatar
Niels Möller committed
927
928

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

930
	  return channel_process_status(connection->channels, channel_number,
Niels Möller's avatar
Niels Möller committed
931
					res | LSH_CHANNEL_FINISHED);
Niels Möller's avatar
Niels Möller committed
932
	}
933
      werror("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE on channel %i\n",
Niels Möller's avatar
Niels Möller committed
934
935
936
937
938
939
940
941
942
	     channel_number);
      lsh_string_free(packet);
      
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

943
944
static int do_channel_success(struct packet_handler *closure UNUSED,
			      struct ssh_connection *connection,
945
946
947
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
948
  unsigned msg_number;
949
  UINT32 channel_number;
950
951
  struct ssh_channel *channel;
      
952
953
954
955
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_SUCCESS)
956
      && parse_uint32(&buffer, &channel_number)
957
      && parse_eod(&buffer)
958
      && (channel = lookup_channel(connection->channels, channel_number)))
959
    
960
961
    {
      lsh_string_free(packet);
962
963
964
965
966
967
968

      if (!channel->channel_failure)
	{
	  werror("do_channel_success: No handler. Ignoring.\n");
	  return LSH_OK | LSH_GOON;
	}

969
      return channel_process_status(connection->channels, channel_number,
970
				    CHANNEL_SUCCESS(channel));
971
972
973
974
975
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

976
977
static int do_channel_failure(struct packet_handler *closure UNUSED,
			      struct ssh_connection *connection,
978
979
980
			      struct lsh_string *packet)
{
  struct simple_buffer buffer;
981
  unsigned msg_number;
982
  UINT32 channel_number;
983
  struct ssh_channel *channel;
984
985
986
987
988
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_CHANNEL_FAILURE)
989
      && parse_uint32(&buffer, &channel_number)
990
      && parse_eod(&buffer)
991
      && (channel = lookup_channel(connection->channels, channel_number)))
992
993
994
    {
      lsh_string_free(packet);
      
995
996
997
998
999
1000

      if (!channel->channel_failure)
	{
	  werror("do_channel_failure: No handler. Ignoring.\n");
	  return LSH_OK | LSH_GOON;
	}
1001
      return channel_process_status(connection->channels, channel_number,
1002
					CHANNEL_FAILURE(channel));
1003
1004
1005
1006
1007
    }
  lsh_string_free(packet);
  return LSH_FAIL | LSH_DIE;
}

1008
1009
1010
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
1011
{
1012
  CAST(connection_service, self, s);
1013
  CAST(ssh_connection, connection, x);
1014

1015
  struct channel_table *table;
Niels Möller's avatar
Niels Möller committed
1016
  
1017
1018
  NEW(global_request_handler, globals);
  NEW(channel_open_handler, open);
1019
  NEW(packet_handler, request);
Niels Möller's avatar
Niels Möller committed
1020

1021
1022
1023
  NEW(packet_handler, adjust);
  NEW(packet_handler, data);
  NEW(packet_handler, extended);
Niels Möller's avatar
Niels Möller committed
1024

1025
1026
  NEW(packet_handler, eof);
  NEW(packet_handler, close);
1027

1028
1029
  NEW(packet_handler, open_confirm);
  NEW(packet_handler, open_failure);
Niels Möller's avatar
Niels Möller committed
1030

1031
1032
  NEW(packet_handler, channel_success);
  NEW(packet_handler, channel_failure);
Niels Möller's avatar
Niels Möller committed
1033

1034
  table = make_channel_table();
Niels Möller's avatar
Niels Möller committed
1035
  
1036
1037
1038
  connection->channels = table;
  
  globals->super.handler = do_global_request;
Niels Möller's avatar
Niels Möller committed
1039
  globals->global_requests = self->global_requests;
1040
  connection->dispatch[SSH_MSG_GLOBAL_REQUEST] = &globals->super;
Niels Möller's avatar
Niels Möller committed
1041
    
1042
  open->super.handler = do_channel_open;
Niels Möller's avatar
Niels Möller committed
1043
  open->channel_types = self->channel_types;
1044
  connection->dispatch[SSH_MSG_CHANNEL_OPEN] = &open->super;
Niels Möller's avatar
Niels Möller committed
1045

1046
1047
  request->handler = do_channel_request;
  connection->dispatch[SSH_MSG_CHANNEL_REQUEST] = request;
Niels Möller's avatar
Niels Möller committed
1048
  
1049
1050
  adjust->handler = do_window_adjust;
  connection->dispatch[SSH_MSG_CHANNEL_WINDOW_ADJUST] = adjust;
Niels Möller's avatar
Niels Möller committed
1051

1052
1053
  data->handler = do_channel_data;
  connection->dispatch[SSH_MSG_CHANNEL_DATA] = data;
Niels Möller's avatar
Niels Möller committed
1054

1055
1056
  extended->handler = do_channel_extended_data;
  connection->dispatch[SSH_MSG_CHANNEL_EXTENDED_DATA] = extended;
Niels Möller's avatar
Niels Möller committed
1057

1058
1059
  eof->handler = do_channel_eof;
  connection->dispatch[SSH_MSG_CHANNEL_EOF] = eof;
Niels Möller's avatar
Niels Möller committed
1060

1061
1062
  close->handler = do_channel_close;
  connection->dispatch[SSH_MSG_CHANNEL_CLOSE] = close;
Niels Möller's avatar
Niels Möller committed
1063

1064
1065
  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
1066

1067
1068
  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
1069
  
1070
1071
  channel_success->handler = do_channel_success;
  connection->dispatch[SSH_MSG_CHANNEL_SUCCESS] = channel_success;
1072

1073
1074
  channel_failure->handler = do_channel_failure;
  connection->dispatch[SSH_MSG_CHANNEL_FAILURE] = channel_failure;
1075
    
Niels Möller's avatar
Niels Möller committed
1076
  return self->start
1077
    ? CONNECTION_START(self->start, connection)
1078
    : LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
1079
1080
}

1081
1082
1083
struct command *make_connection_service(struct alist *global_requests,
					struct alist *channel_types,
					struct connection_startup *start)
1084
{
1085
  NEW(connection_service, self);
1086

1087
  self->super.call = do_connection_service;
1088
1089
1090
1091
1092
  self->global_requests = global_requests;
  self->channel_types = channel_types;
  self->start = start;
  
  return &self->super;
1093
1094
}

Niels Möller's avatar
Niels Möller committed
1095
1096
1097
1098
1099
1100
1101
1102
1103
struct lsh_string *format_channel_close(struct ssh_channel *channel)
{
  return ssh_format("%c%i",
		    SSH_MSG_CHANNEL_CLOSE,
		    channel->channel_number);
}

int channel_close(struct ssh_channel *channel)
{
1104
1105
  assert(! (channel->flags & CHANNEL_SENT_CLOSE));
  
Niels Möller's avatar
Niels Möller committed
1106
1107
1108
  channel->flags |= CHANNEL_SENT_CLOSE;

  return A_WRITE(channel->write, format_channel_close(channel))
1109
    | ( (channel->flags & CHANNEL_RECEIVED_CLOSE)
Niels Möller's avatar
Niels Möller committed
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
	? LSH_CHANNEL_FINISHED : 0);
}

struct lsh_string *format_channel_eof(struct ssh_channel *channel)
{
  return ssh_format("%c%i",
		    SSH_MSG_CHANNEL_EOF,
		    channel->channel_number);
}

int channel_eof(struct ssh_channel *channel)
{
  int res