channel.c 36.3 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* channel.c
 *
 * $Id$
 */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
J.H.M. Dassen's avatar
J.H.M. Dassen committed
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Niels Möller's avatar
Niels Möller committed
23
24
25
26
27
 */

#include "channel.h"

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

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

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

41
42
#include "channel.c.x"

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

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

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

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

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

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

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
#if 1
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
/* 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;
}
415
#endif
416

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

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

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

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

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

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

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

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

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

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

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

  return LSH_FAIL | LSH_DIE;
}

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

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

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

638
	      /* FIXME: Unconditionally adjusting the receive window
639
	       * breaks flow control. We better let the channel's
640
	       * receive method decide whether or not to receive more
641
642
643
	       * data. */
	      res = adjust_rec_window(channel);
	      
644
645
646
647
648
649
650
651
652
	      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
653
	      return channel_process_status(
654
		connection->channels, channel_number,
655
		res | CHANNEL_RECEIVE(channel, 
Niels Möller's avatar
Niels Möller committed
656
				      CHANNEL_DATA, data));
Niels Möller's avatar
Niels Möller committed
657
658
	    }
	  return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
659
660
	}
	  
661
      werror("Data on closed or non-existant channel %i\n",
Niels Möller's avatar
Niels Möller committed
662
663
664
665
666
667
668
669
670
	     channel_number);
      lsh_string_free(data);
      return LSH_FAIL | LSH_DIE;
    }
  lsh_string_free(packet);
  
  return LSH_FAIL | LSH_DIE;
}

671
672
static int do_channel_extended_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
684
  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)
685
      && parse_uint32(&buffer, &channel_number)
Niels Möller's avatar
Niels Möller committed
686
687
688
689
      && parse_uint32(&buffer, &type)
      && ( (data = parse_string_copy(&buffer)) )
      && parse_eod(&buffer))
    {
690
      struct ssh_channel *channel = lookup_channel(connection->channels,
Niels Möller's avatar
Niels Möller committed
691
692
693
694
						   channel_number);

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

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

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

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

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

      lsh_string_free(packet);

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

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

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

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

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

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

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

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

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

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

      lsh_string_free(packet);

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

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

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

      /* lsh_string_free(packet); */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1094
1095
  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
1096

1097
1098
  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
1099
  
1100
1101
  channel_success->handler = do_channel_success;
  connection->dispatch[SSH_MSG_CHANNEL_SUCCESS] = channel_success;
1102

Balázs Scheidler's avatar