~ubuntu-branches/debian/lenny/dropbear/lenny

« back to all changes in this revision

Viewing changes to common-channel.c

  • Committer: Bazaar Package Importer
  • Author(s): Gerrit Pape
  • Date: 2005-05-25 22:38:17 UTC
  • mfrom: (1.2.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050525223817-fdl653extybmz1zb
Tags: 0.45-3
* debian/dropbear.init: init script prints human readable message in case
  it's disabled (closes: #309099).
* debian/dropbear.postinst: configure: restart service through init script
  instead of start.
* debian/dropbear.prerm: set -u -> set -e.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Dropbear SSH
 
3
 * 
 
4
 * Copyright (c) 2002-2004 Matt Johnston
 
5
 * All rights reserved.
 
6
 * 
 
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 
8
 * of this software and associated documentation files (the "Software"), to deal
 
9
 * in the Software without restriction, including without limitation the rights
 
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
11
 * copies of the Software, and to permit persons to whom the Software is
 
12
 * furnished to do so, subject to the following conditions:
 
13
 * 
 
14
 * The above copyright notice and this permission notice shall be included in
 
15
 * all copies or substantial portions of the Software.
 
16
 * 
 
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
23
 * SOFTWARE. */
 
24
 
 
25
/* Handle the multiplexed channels, such as sessions, x11, agent connections */
 
26
 
 
27
#include "includes.h"
 
28
#include "session.h"
 
29
#include "packet.h"
 
30
#include "ssh.h"
 
31
#include "buffer.h"
 
32
#include "circbuffer.h"
 
33
#include "dbutil.h"
 
34
#include "channel.h"
 
35
#include "ssh.h"
 
36
#include "listener.h"
 
37
 
 
38
static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
 
39
                const unsigned char *text, const unsigned char *lang);
 
40
static void send_msg_channel_open_confirmation(struct Channel* channel,
 
41
                unsigned int recvwindow, 
 
42
                unsigned int recvmaxpacket);
 
43
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf);
 
44
static void send_msg_channel_window_adjust(struct Channel *channel, 
 
45
                unsigned int incr);
 
46
static void send_msg_channel_data(struct Channel *channel, int isextended,
 
47
                unsigned int exttype);
 
48
static void send_msg_channel_eof(struct Channel *channel);
 
49
static void send_msg_channel_close(struct Channel *channel);
 
50
static void removechannel(struct Channel *channel);
 
51
static void deletechannel(struct Channel *channel);
 
52
static void checkinitdone(struct Channel *channel);
 
53
static void checkclose(struct Channel *channel);
 
54
 
 
55
static void closeinfd(struct Channel * channel);
 
56
static void closeoutfd(struct Channel * channel, int fd);
 
57
static void closechanfd(struct Channel *channel, int fd, int how);
 
58
 
 
59
#define FD_UNINIT (-2)
 
60
#define FD_CLOSED (-1)
 
61
 
 
62
/* Initialise all the channels */
 
63
void chaninitialise(const struct ChanType *chantypes[]) {
 
64
 
 
65
        /* may as well create space for a single channel */
 
66
        ses.channels = (struct Channel**)m_malloc(sizeof(struct Channel*));
 
67
        ses.chansize = 1;
 
68
        ses.channels[0] = NULL;
 
69
        ses.chancount = 0;
 
70
 
 
71
        ses.chantypes = chantypes;
 
72
 
 
73
#ifdef USING_LISTENERS
 
74
        listeners_initialise();
 
75
#endif
 
76
 
 
77
}
 
78
 
 
79
/* Clean up channels, freeing allocated memory */
 
80
void chancleanup() {
 
81
 
 
82
        unsigned int i;
 
83
 
 
84
        TRACE(("enter chancleanup"))
 
85
        for (i = 0; i < ses.chansize; i++) {
 
86
                if (ses.channels[i] != NULL) {
 
87
                        TRACE(("channel %d closing", i))
 
88
                        removechannel(ses.channels[i]);
 
89
                }
 
90
        }
 
91
        m_free(ses.channels);
 
92
        TRACE(("leave chancleanup"))
 
93
}
 
94
 
 
95
/* Create a new channel entry, send a reply confirm or failure */
 
96
/* If remotechan, transwindow and transmaxpacket are not know (for a new
 
97
 * outgoing connection, with them to be filled on confirmation), they should
 
98
 * all be set to 0 */
 
99
struct Channel* newchannel(unsigned int remotechan, 
 
100
                const struct ChanType *type, 
 
101
                unsigned int transwindow, unsigned int transmaxpacket) {
 
102
 
 
103
        struct Channel * newchan;
 
104
        unsigned int i, j;
 
105
 
 
106
        TRACE(("enter newchannel"))
 
107
        
 
108
        /* first see if we can use existing channels */
 
109
        for (i = 0; i < ses.chansize; i++) {
 
110
                if (ses.channels[i] == NULL) {
 
111
                        break;
 
112
                }
 
113
        }
 
114
 
 
115
        /* otherwise extend the list */
 
116
        if (i == ses.chansize) {
 
117
                if (ses.chansize >= MAX_CHANNELS) {
 
118
                        TRACE(("leave newchannel: max chans reached"))
 
119
                        return NULL;
 
120
                }
 
121
 
 
122
                /* extend the channels */
 
123
                ses.channels = (struct Channel**)m_realloc(ses.channels,
 
124
                                (ses.chansize+CHAN_EXTEND_SIZE)*sizeof(struct Channel*));
 
125
 
 
126
                ses.chansize += CHAN_EXTEND_SIZE;
 
127
 
 
128
                /* set the new channels to null */
 
129
                for (j = i; j < ses.chansize; j++) {
 
130
                        ses.channels[j] = NULL;
 
131
                }
 
132
 
 
133
        }
 
134
        
 
135
        newchan = (struct Channel*)m_malloc(sizeof(struct Channel));
 
136
        newchan->type = type;
 
137
        newchan->index = i;
 
138
        newchan->sentclosed = newchan->recvclosed = 0;
 
139
        newchan->senteof = newchan->recveof = 0;
 
140
 
 
141
        newchan->remotechan = remotechan;
 
142
        newchan->transwindow = transwindow;
 
143
        newchan->transmaxpacket = transmaxpacket;
 
144
        
 
145
        newchan->typedata = NULL;
 
146
        newchan->infd = FD_UNINIT;
 
147
        newchan->outfd = FD_UNINIT;
 
148
        newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
 
149
        newchan->initconn = 0;
 
150
 
 
151
        newchan->writebuf = cbuf_new(RECV_MAXWINDOW);
 
152
        newchan->extrabuf = NULL; /* The user code can set it up */
 
153
        newchan->recvwindow = RECV_MAXWINDOW;
 
154
        newchan->recvdonelen = 0;
 
155
        newchan->recvmaxpacket = RECV_MAXPACKET;
 
156
 
 
157
        ses.channels[i] = newchan;
 
158
        ses.chancount++;
 
159
 
 
160
        TRACE(("leave newchannel"))
 
161
 
 
162
        return newchan;
 
163
}
 
164
 
 
165
/* Get the channel structure corresponding to a channel number */
 
166
struct Channel* getchannel(unsigned int chan) {
 
167
        if (chan >= ses.chansize || ses.channels[chan] == NULL) {
 
168
                return NULL;
 
169
        }
 
170
        return ses.channels[chan];
 
171
}
 
172
 
 
173
/* Iterate through the channels, performing IO if available */
 
174
void channelio(fd_set *readfd, fd_set *writefd) {
 
175
 
 
176
        struct Channel *channel;
 
177
        unsigned int i;
 
178
        int ret;
 
179
 
 
180
        /* iterate through all the possible channels */
 
181
        for (i = 0; i < ses.chansize; i++) {
 
182
 
 
183
                channel = ses.channels[i];
 
184
                if (channel == NULL) {
 
185
                        /* only process in-use channels */
 
186
                        continue;
 
187
                }
 
188
 
 
189
                /* read from program/pipe stdout */
 
190
                if (channel->outfd >= 0 && FD_ISSET(channel->outfd, readfd)) {
 
191
                        send_msg_channel_data(channel, 0, 0);
 
192
                }
 
193
 
 
194
                /* read from program/pipe stderr */
 
195
                if (channel->extrabuf == NULL &&
 
196
                                channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) {
 
197
                                send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR);
 
198
                }
 
199
 
 
200
                /* if we can read from the infd, it might be closed, so we try to
 
201
                 * see if it has errors */
 
202
                if (channel->infd >= 0 && channel->infd != channel->outfd
 
203
                                && FD_ISSET(channel->infd, readfd)) {
 
204
                        if (channel->initconn) {
 
205
                                /* Handling for "in progress" connection - this is needed
 
206
                                 * to avoid spinning 100% CPU when we connect to a server
 
207
                                 * which doesn't send anything (tcpfwding) */
 
208
                                checkinitdone(channel);
 
209
                                continue; /* Important not to use the channel after 
 
210
                                                         checkinitdone(), as it may be NULL */
 
211
                        }
 
212
                        ret = write(channel->infd, NULL, 0); /* Fake write */
 
213
                        if (ret < 0 && errno != EINTR && errno != EAGAIN) {
 
214
                                closeinfd(channel);
 
215
                        }
 
216
                }
 
217
 
 
218
                /* write to program/pipe stdin */
 
219
                if (channel->infd >= 0 && FD_ISSET(channel->infd, writefd)) {
 
220
                        if (channel->initconn) {
 
221
                                checkinitdone(channel);
 
222
                                continue; /* Important not to use the channel after
 
223
                                                         checkinitdone(), as it may be NULL */
 
224
                        }
 
225
                        writechannel(channel, channel->infd, channel->writebuf);
 
226
                }
 
227
                
 
228
                /* stderr for client mode */
 
229
                if (channel->extrabuf != NULL 
 
230
                                && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefd)) {
 
231
                        writechannel(channel, channel->errfd, channel->extrabuf);
 
232
                }
 
233
        
 
234
                /* now handle any of the channel-closing type stuff */
 
235
                checkclose(channel);
 
236
 
 
237
        } /* foreach channel */
 
238
 
 
239
        /* Listeners such as TCP, X11, agent-auth */
 
240
#ifdef USING_LISTENERS
 
241
        handle_listeners(readfd);
 
242
#endif
 
243
}
 
244
 
 
245
 
 
246
/* do all the EOF/close type stuff checking for a channel */
 
247
static void checkclose(struct Channel *channel) {
 
248
 
 
249
        TRACE(("checkclose: infd %d, outfd %d, errfd %d, sentclosed %d, recvclosed %d",
 
250
                                channel->infd, channel->outfd,
 
251
                                channel->errfd, channel->sentclosed, channel->recvclosed))
 
252
        TRACE(("writebuf %d extrabuf %s extrabuf %d",
 
253
                                cbuf_getused(channel->writebuf),
 
254
                                channel->writebuf,
 
255
                                channel->writebuf ? 0 : cbuf_getused(channel->extrabuf)))
 
256
 
 
257
        if (!channel->sentclosed) {
 
258
 
 
259
                /* check for exited - currently only used for server sessions,
 
260
                 * if the shell has exited etc */
 
261
                if (channel->type->checkclose) {
 
262
                        if (channel->type->checkclose(channel)) {
 
263
                                closeinfd(channel);
 
264
                        }
 
265
                }
 
266
 
 
267
                if (!channel->senteof
 
268
                        && channel->outfd == FD_CLOSED 
 
269
                        && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
 
270
                        send_msg_channel_eof(channel);
 
271
                }
 
272
 
 
273
                if (channel->infd == FD_CLOSED
 
274
                        && channel->outfd == FD_CLOSED
 
275
                        && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
 
276
                        send_msg_channel_close(channel);
 
277
                }
 
278
        }
 
279
 
 
280
        /* When either party wishes to terminate the channel, it sends
 
281
         * SSH_MSG_CHANNEL_CLOSE.  Upon receiving this message, a party MUST
 
282
         * send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this
 
283
         * message for the channel.  The channel is considered closed for a
 
284
         * party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, and
 
285
         * the party may then reuse the channel number.  A party MAY send
 
286
         * SSH_MSG_CHANNEL_CLOSE without having sent or received
 
287
         * SSH_MSG_CHANNEL_EOF. 
 
288
         * (from draft-ietf-secsh-connect)
 
289
         */
 
290
        if (channel->recvclosed) {
 
291
                if (! channel->sentclosed) {
 
292
                        TRACE(("Sending MSG_CHANNEL_CLOSE in response to same."))
 
293
                        send_msg_channel_close(channel);
 
294
                }
 
295
                removechannel(channel);
 
296
        }
 
297
}
 
298
 
 
299
 
 
300
/* Check whether a deferred (EINPROGRESS) connect() was successful, and
 
301
 * if so, set up the channel properly. Otherwise, the channel is cleaned up, so
 
302
 * it is important that the channel reference isn't used after a call to this
 
303
 * function */
 
304
static void checkinitdone(struct Channel *channel) {
 
305
 
 
306
        int val;
 
307
        socklen_t vallen = sizeof(val);
 
308
 
 
309
        TRACE(("enter checkinitdone"))
 
310
 
 
311
        if (getsockopt(channel->infd, SOL_SOCKET, SO_ERROR, &val, &vallen)
 
312
                        || val != 0) {
 
313
                send_msg_channel_open_failure(channel->remotechan,
 
314
                                SSH_OPEN_CONNECT_FAILED, "", "");
 
315
                close(channel->infd);
 
316
                deletechannel(channel);
 
317
                TRACE(("leave checkinitdone: fail"))
 
318
        } else {
 
319
                send_msg_channel_open_confirmation(channel, channel->recvwindow,
 
320
                                channel->recvmaxpacket);
 
321
                channel->outfd = channel->infd;
 
322
                channel->initconn = 0;
 
323
                TRACE(("leave checkinitdone: success"))
 
324
        }
 
325
}
 
326
 
 
327
 
 
328
 
 
329
/* Send the close message and set the channel as closed */
 
330
static void send_msg_channel_close(struct Channel *channel) {
 
331
 
 
332
        TRACE(("enter send_msg_channel_close"))
 
333
        /* XXX server */
 
334
        if (channel->type->closehandler) {
 
335
                channel->type->closehandler(channel);
 
336
        }
 
337
        
 
338
        CHECKCLEARTOWRITE();
 
339
 
 
340
        buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_CLOSE);
 
341
        buf_putint(ses.writepayload, channel->remotechan);
 
342
 
 
343
        encrypt_packet();
 
344
 
 
345
        channel->senteof = 1;
 
346
        channel->sentclosed = 1;
 
347
        TRACE(("leave send_msg_channel_close"))
 
348
}
 
349
 
 
350
/* call this when trans/eof channels are closed */
 
351
static void send_msg_channel_eof(struct Channel *channel) {
 
352
 
 
353
        TRACE(("enter send_msg_channel_eof"))
 
354
        CHECKCLEARTOWRITE();
 
355
 
 
356
        buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_EOF);
 
357
        buf_putint(ses.writepayload, channel->remotechan);
 
358
 
 
359
        encrypt_packet();
 
360
 
 
361
        channel->senteof = 1;
 
362
 
 
363
        TRACE(("leave send_msg_channel_eof"))
 
364
}
 
365
 
 
366
/* Called to write data out to the local side of the channel. 
 
367
 * Only called when we know we can write to a channel, writes as much as
 
368
 * possible */
 
369
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
 
370
 
 
371
        int len, maxlen;
 
372
 
 
373
        TRACE(("enter writechannel"))
 
374
 
 
375
        maxlen = cbuf_readlen(cbuf);
 
376
 
 
377
        /* Write the data out */
 
378
        len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
 
379
        if (len <= 0) {
 
380
                if (len < 0 && errno != EINTR) {
 
381
                        /* no more to write - we close it even if the fd was stderr, since
 
382
                         * that's a nasty failure too */
 
383
                        closeinfd(channel);
 
384
                }
 
385
                TRACE(("leave writechannel: len <= 0"))
 
386
                return;
 
387
        }
 
388
 
 
389
        cbuf_incrread(cbuf, len);
 
390
        channel->recvdonelen += len;
 
391
 
 
392
        if (fd == channel->infd && len == maxlen && channel->recveof) { 
 
393
                /* Check if we're closing up */
 
394
                closeinfd(channel);
 
395
                TRACE(("leave writechannel: recveof set"))
 
396
                return;
 
397
        }
 
398
 
 
399
        /* Window adjust handling */
 
400
        if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
 
401
                /* Set it back to max window */
 
402
                send_msg_channel_window_adjust(channel, channel->recvdonelen);
 
403
                channel->recvwindow += channel->recvdonelen;
 
404
                channel->recvdonelen = 0;
 
405
        }
 
406
 
 
407
        assert(channel->recvwindow <= RECV_MAXWINDOW);
 
408
        assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
 
409
        assert(channel->extrabuf == NULL ||
 
410
                        channel->recvwindow <= cbuf_getavail(channel->extrabuf));
 
411
        
 
412
        
 
413
        TRACE(("leave writechannel"))
 
414
}
 
415
 
 
416
/* Set the file descriptors for the main select in session.c
 
417
 * This avoid channels which don't have any window available, are closed, etc*/
 
418
void setchannelfds(fd_set *readfd, fd_set *writefd) {
 
419
        
 
420
        unsigned int i;
 
421
        struct Channel * channel;
 
422
        
 
423
        for (i = 0; i < ses.chansize; i++) {
 
424
 
 
425
                channel = ses.channels[i];
 
426
                if (channel == NULL) {
 
427
                        continue;
 
428
                }
 
429
 
 
430
                /* Stuff to put over the wire */
 
431
                if (channel->transwindow > 0) {
 
432
 
 
433
                        if (channel->outfd >= 0) {
 
434
                                FD_SET(channel->outfd, readfd);
 
435
                        }
 
436
                        
 
437
                        if (channel->extrabuf == NULL && channel->errfd >= 0) {
 
438
                                        FD_SET(channel->errfd, readfd);
 
439
                        }
 
440
                }
 
441
 
 
442
                /* For checking FD status (ie closure etc) - we don't actually
 
443
                 * read data from infd */
 
444
                TRACE(("infd = %d, outfd %d, errfd %d, bufused %d", 
 
445
                                        channel->infd, channel->outfd,
 
446
                                        channel->errfd,
 
447
                                        cbuf_getused(channel->writebuf) ))
 
448
                if (channel->infd >= 0 && channel->infd != channel->outfd) {
 
449
                        FD_SET(channel->infd, readfd);
 
450
                }
 
451
 
 
452
                /* Stuff from the wire, to local program/shell/user etc */
 
453
                if ((channel->infd >= 0 && cbuf_getused(channel->writebuf) > 0 )
 
454
                                || channel->initconn) {
 
455
 
 
456
                                FD_SET(channel->infd, writefd);
 
457
                }
 
458
 
 
459
                if (channel->extrabuf != NULL && channel->errfd >= 0 
 
460
                                && cbuf_getused(channel->extrabuf) > 0 ) {
 
461
                                FD_SET(channel->errfd, writefd);
 
462
                }
 
463
 
 
464
        } /* foreach channel */
 
465
 
 
466
#ifdef USING_LISTENERS
 
467
        set_listener_fds(readfd);
 
468
#endif
 
469
 
 
470
}
 
471
 
 
472
/* handle the channel EOF event, by closing the channel filedescriptor. The
 
473
 * channel isn't closed yet, it is left until the incoming (from the program
 
474
 * etc) FD is also EOF */
 
475
void recv_msg_channel_eof() {
 
476
 
 
477
        unsigned int chan;
 
478
        struct Channel * channel;
 
479
 
 
480
        TRACE(("enter recv_msg_channel_eof"))
 
481
 
 
482
        chan = buf_getint(ses.payload);
 
483
        channel = getchannel(chan);
 
484
 
 
485
        if (channel == NULL) {
 
486
                dropbear_exit("EOF for unknown channel");
 
487
        }
 
488
 
 
489
        channel->recveof = 1;
 
490
        if (cbuf_getused(channel->writebuf) == 0
 
491
                        && (channel->extrabuf == NULL 
 
492
                                        || cbuf_getused(channel->extrabuf) == 0)) {
 
493
                closeinfd(channel);
 
494
        }
 
495
 
 
496
        TRACE(("leave recv_msg_channel_eof"))
 
497
}
 
498
 
 
499
 
 
500
/* Handle channel closure(), respond in kind and close the channels */
 
501
void recv_msg_channel_close() {
 
502
 
 
503
        unsigned int chan;
 
504
        struct Channel * channel;
 
505
 
 
506
        TRACE(("enter recv_msg_channel_close"))
 
507
 
 
508
        chan = buf_getint(ses.payload);
 
509
        TRACE(("close channel = %d", chan))
 
510
        channel = getchannel(chan);
 
511
 
 
512
        if (channel == NULL) {
 
513
                /* disconnect ? */
 
514
                dropbear_exit("Close for unknown channel");
 
515
        }
 
516
 
 
517
        channel->recveof = 1;
 
518
        channel->recvclosed = 1;
 
519
 
 
520
        if (channel->sentclosed) {
 
521
                removechannel(channel);
 
522
        }
 
523
 
 
524
        TRACE(("leave recv_msg_channel_close"))
 
525
}
 
526
 
 
527
/* Remove a channel entry, this is only executed after both sides have sent
 
528
 * channel close */
 
529
static void removechannel(struct Channel * channel) {
 
530
 
 
531
        TRACE(("enter removechannel"))
 
532
        TRACE(("channel index is %d", channel->index))
 
533
 
 
534
        cbuf_free(channel->writebuf);
 
535
        channel->writebuf = NULL;
 
536
 
 
537
        if (channel->extrabuf) {
 
538
                cbuf_free(channel->extrabuf);
 
539
                channel->extrabuf = NULL;
 
540
        }
 
541
 
 
542
 
 
543
        /* close the FDs in case they haven't been done
 
544
         * yet (ie they were shutdown etc */
 
545
        close(channel->infd);
 
546
        close(channel->outfd);
 
547
        close(channel->errfd);
 
548
 
 
549
        channel->typedata = NULL;
 
550
 
 
551
        deletechannel(channel);
 
552
 
 
553
        TRACE(("leave removechannel"))
 
554
}
 
555
 
 
556
/* Remove a channel entry */
 
557
static void deletechannel(struct Channel *channel) {
 
558
 
 
559
        ses.channels[channel->index] = NULL;
 
560
        m_free(channel);
 
561
        ses.chancount--;
 
562
        
 
563
}
 
564
 
 
565
 
 
566
/* Handle channel specific requests, passing off to corresponding handlers
 
567
 * such as chansession or x11fwd */
 
568
void recv_msg_channel_request() {
 
569
 
 
570
        unsigned int chan;
 
571
        struct Channel *channel;
 
572
 
 
573
        TRACE(("enter recv_msg_channel_request"))
 
574
        
 
575
        chan = buf_getint(ses.payload);
 
576
        channel = getchannel(chan);
 
577
 
 
578
        if (channel == NULL) {
 
579
                /* disconnect ? */
 
580
                dropbear_exit("Unknown channel");
 
581
        }
 
582
 
 
583
        if (channel->type->reqhandler) {
 
584
                channel->type->reqhandler(channel);
 
585
        } else {
 
586
                send_msg_channel_failure(channel);
 
587
        }
 
588
 
 
589
        TRACE(("leave recv_msg_channel_request"))
 
590
 
 
591
}
 
592
 
 
593
/* Reads data from the server's program/shell/etc, and puts it in a
 
594
 * channel_data packet to send.
 
595
 * chan is the remote channel, isextended is 0 if it is normal data, 1
 
596
 * if it is extended data. if it is extended, then the type is in
 
597
 * exttype */
 
598
static void send_msg_channel_data(struct Channel *channel, int isextended,
 
599
                unsigned int exttype) {
 
600
 
 
601
        buffer *buf;
 
602
        int len;
 
603
        unsigned int maxlen;
 
604
        int fd;
 
605
 
 
606
/*      TRACE(("enter send_msg_channel_data"))
 
607
        TRACE(("extended = %d type = %d", isextended, exttype))*/
 
608
 
 
609
        CHECKCLEARTOWRITE();
 
610
 
 
611
        assert(!channel->sentclosed);
 
612
 
 
613
        if (isextended) {
 
614
                fd = channel->errfd;
 
615
        } else {
 
616
                fd = channel->outfd;
 
617
        }
 
618
        assert(fd >= 0);
 
619
 
 
620
        maxlen = MIN(channel->transwindow, channel->transmaxpacket);
 
621
        /* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and 
 
622
         * exttype if is extended */
 
623
        maxlen = MIN(maxlen, 
 
624
                        ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0));
 
625
        if (maxlen == 0) {
 
626
                TRACE(("leave send_msg_channel_data: no window"))
 
627
                return; /* the data will get written later */
 
628
        }
 
629
 
 
630
        /* read the data */
 
631
        TRACE(("maxlen %d", maxlen))
 
632
        buf = buf_new(maxlen);
 
633
        TRACE(("buf pos %d data %x", buf->pos, buf->data))
 
634
        len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
 
635
        if (len <= 0) {
 
636
                /* on error/eof, send eof */
 
637
                if (len == 0 || errno != EINTR) {
 
638
                        closeoutfd(channel, fd);
 
639
                }
 
640
                buf_free(buf);
 
641
                buf = NULL;
 
642
                TRACE(("leave send_msg_channel_data: read err or EOF for fd %d", 
 
643
                                        channel->index));
 
644
                return;
 
645
        }
 
646
        buf_incrlen(buf, len);
 
647
 
 
648
        buf_putbyte(ses.writepayload, 
 
649
                        isextended ? SSH_MSG_CHANNEL_EXTENDED_DATA : SSH_MSG_CHANNEL_DATA);
 
650
        buf_putint(ses.writepayload, channel->remotechan);
 
651
 
 
652
        if (isextended) {
 
653
                buf_putint(ses.writepayload, exttype);
 
654
        }
 
655
 
 
656
        buf_putstring(ses.writepayload, buf_getptr(buf, len), len);
 
657
        buf_free(buf);
 
658
        buf = NULL;
 
659
 
 
660
        channel->transwindow -= len;
 
661
 
 
662
        encrypt_packet();
 
663
        TRACE(("leave send_msg_channel_data"))
 
664
}
 
665
 
 
666
/* We receive channel data */
 
667
void recv_msg_channel_data() {
 
668
 
 
669
        unsigned int chan;
 
670
        struct Channel *channel;
 
671
 
 
672
        chan = buf_getint(ses.payload);
 
673
        channel = getchannel(chan);
 
674
 
 
675
        if (channel == NULL) {
 
676
                dropbear_exit("Unknown channel");
 
677
        }
 
678
 
 
679
        common_recv_msg_channel_data(channel, channel->infd, channel->writebuf);
 
680
}
 
681
 
 
682
/* Shared for data and stderr data - when we receive data, put it in a buffer
 
683
 * for writing to the local file descriptor */
 
684
void common_recv_msg_channel_data(struct Channel *channel, int fd, 
 
685
                circbuffer * cbuf) {
 
686
 
 
687
        unsigned int datalen;
 
688
        unsigned int maxdata;
 
689
        unsigned int buflen;
 
690
        unsigned int len;
 
691
 
 
692
        TRACE(("enter recv_msg_channel_data"))
 
693
 
 
694
        if (channel->recveof) {
 
695
                dropbear_exit("received data after eof");
 
696
        }
 
697
 
 
698
        if (fd < 0) {
 
699
                dropbear_exit("received data with bad infd");
 
700
        }
 
701
 
 
702
        datalen = buf_getint(ses.payload);
 
703
 
 
704
 
 
705
        maxdata = cbuf_getavail(cbuf);
 
706
 
 
707
        /* Whilst the spec says we "MAY ignore data past the end" this could
 
708
         * lead to corrupted file transfers etc (chunks missed etc). It's better to
 
709
         * just die horribly */
 
710
        if (datalen > maxdata) {
 
711
                dropbear_exit("Oversized packet");
 
712
        }
 
713
 
 
714
        /* We may have to run throught twice, if the buffer wraps around. Can't
 
715
         * just "leave it for next time" like with writechannel, since this
 
716
         * is payload data */
 
717
        len = datalen;
 
718
        while (len > 0) {
 
719
                buflen = cbuf_writelen(cbuf);
 
720
                buflen = MIN(buflen, len);
 
721
 
 
722
                memcpy(cbuf_writeptr(cbuf, buflen), 
 
723
                                buf_getptr(ses.payload, buflen), buflen);
 
724
                cbuf_incrwrite(cbuf, buflen);
 
725
                buf_incrpos(ses.payload, buflen);
 
726
                len -= buflen;
 
727
        }
 
728
 
 
729
        assert(channel->recvwindow >= datalen);
 
730
        channel->recvwindow -= datalen;
 
731
        assert(channel->recvwindow <= RECV_MAXWINDOW);
 
732
 
 
733
        TRACE(("leave recv_msg_channel_data"))
 
734
}
 
735
 
 
736
/* Increment the outgoing data window for a channel - the remote end limits
 
737
 * the amount of data which may be transmitted, this window is decremented
 
738
 * as data is sent, and incremented upon receiving window-adjust messages */
 
739
void recv_msg_channel_window_adjust() {
 
740
 
 
741
        unsigned int chan;
 
742
        struct Channel * channel;
 
743
        unsigned int incr;
 
744
        
 
745
        chan = buf_getint(ses.payload);
 
746
        channel = getchannel(chan);
 
747
 
 
748
        if (channel == NULL) {
 
749
                dropbear_exit("Unknown channel");
 
750
        }
 
751
        
 
752
        incr = buf_getint(ses.payload);
 
753
        TRACE(("received window increment %d", incr))
 
754
        incr = MIN(incr, MAX_TRANS_WIN_INCR);
 
755
        
 
756
        channel->transwindow += incr;
 
757
        channel->transwindow = MIN(channel->transwindow, MAX_TRANS_WINDOW);
 
758
 
 
759
}
 
760
 
 
761
/* Increment the incoming data window for a channel, and let the remote
 
762
 * end know */
 
763
static void send_msg_channel_window_adjust(struct Channel* channel, 
 
764
                unsigned int incr) {
 
765
 
 
766
        TRACE(("sending window adjust %d", incr))
 
767
        CHECKCLEARTOWRITE();
 
768
 
 
769
        buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_WINDOW_ADJUST);
 
770
        buf_putint(ses.writepayload, channel->remotechan);
 
771
        buf_putint(ses.writepayload, incr);
 
772
 
 
773
        encrypt_packet();
 
774
}
 
775
        
 
776
/* Handle a new channel request, performing any channel-type-specific setup */
 
777
/* XXX server */
 
778
void recv_msg_channel_open() {
 
779
 
 
780
        unsigned char *type;
 
781
        unsigned int typelen;
 
782
        unsigned int remotechan, transwindow, transmaxpacket;
 
783
        struct Channel *channel;
 
784
        const struct ChanType **cp;
 
785
        const struct ChanType *chantype;
 
786
        unsigned int errtype = SSH_OPEN_UNKNOWN_CHANNEL_TYPE;
 
787
        int ret;
 
788
 
 
789
 
 
790
        TRACE(("enter recv_msg_channel_open"))
 
791
 
 
792
        /* get the packet contents */
 
793
        type = buf_getstring(ses.payload, &typelen);
 
794
 
 
795
        remotechan = buf_getint(ses.payload);
 
796
        transwindow = buf_getint(ses.payload);
 
797
        transwindow = MIN(transwindow, MAX_TRANS_WINDOW);
 
798
        transmaxpacket = buf_getint(ses.payload);
 
799
        transmaxpacket = MIN(transmaxpacket, MAX_TRANS_PAYLOAD_LEN);
 
800
 
 
801
        /* figure what type of packet it is */
 
802
        if (typelen > MAX_NAME_LEN) {
 
803
                goto failure;
 
804
        }
 
805
 
 
806
        /* Get the channel type. Client and server style invokation will set up a
 
807
         * different list for ses.chantypes at startup. We just iterate through
 
808
         * this list and find the matching name */
 
809
        for (cp = &ses.chantypes[0], chantype = (*cp); 
 
810
                        chantype != NULL;
 
811
                        cp++, chantype = (*cp)) {
 
812
                if (strcmp(type, chantype->name) == 0) {
 
813
                        break;
 
814
                }
 
815
        }
 
816
 
 
817
        if (chantype == NULL) {
 
818
                TRACE(("No matching type for '%s'", type))
 
819
                goto failure;
 
820
        }
 
821
 
 
822
        TRACE(("matched type '%s'", type))
 
823
 
 
824
        /* create the channel */
 
825
        channel = newchannel(remotechan, chantype, transwindow, transmaxpacket);
 
826
 
 
827
        if (channel == NULL) {
 
828
                TRACE(("newchannel returned NULL"))
 
829
                goto failure;
 
830
        }
 
831
 
 
832
        if (channel->type->inithandler) {
 
833
                ret = channel->type->inithandler(channel);
 
834
                if (ret > 0) {
 
835
                        if (ret == SSH_OPEN_IN_PROGRESS) {
 
836
                                /* We'll send the confirmation later */
 
837
                                goto cleanup;
 
838
                        }
 
839
                        errtype = ret;
 
840
                        deletechannel(channel);
 
841
                        TRACE(("inithandler returned failure %d", ret))
 
842
                        goto failure;
 
843
                }
 
844
        }
 
845
 
 
846
        /* success */
 
847
        send_msg_channel_open_confirmation(channel, channel->recvwindow,
 
848
                        channel->recvmaxpacket);
 
849
        goto cleanup;
 
850
 
 
851
failure:
 
852
        TRACE(("recv_msg_channel_open failure"))
 
853
        send_msg_channel_open_failure(remotechan, errtype, "", "");
 
854
 
 
855
cleanup:
 
856
        m_free(type);
 
857
 
 
858
        TRACE(("leave recv_msg_channel_open"))
 
859
}
 
860
 
 
861
/* Send a failure message */
 
862
void send_msg_channel_failure(struct Channel *channel) {
 
863
 
 
864
        TRACE(("enter send_msg_channel_failure"))
 
865
        CHECKCLEARTOWRITE();
 
866
 
 
867
        buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_FAILURE);
 
868
        buf_putint(ses.writepayload, channel->remotechan);
 
869
 
 
870
        encrypt_packet();
 
871
        TRACE(("leave send_msg_channel_failure"))
 
872
}
 
873
 
 
874
/* Send a success message */
 
875
void send_msg_channel_success(struct Channel *channel) {
 
876
 
 
877
        TRACE(("enter send_msg_channel_success"))
 
878
        CHECKCLEARTOWRITE();
 
879
 
 
880
        buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_SUCCESS);
 
881
        buf_putint(ses.writepayload, channel->remotechan);
 
882
 
 
883
        encrypt_packet();
 
884
        TRACE(("leave send_msg_channel_success"))
 
885
}
 
886
 
 
887
/* Send a channel open failure message, with a corresponding reason
 
888
 * code (usually resource shortage or unknown chan type) */
 
889
static void send_msg_channel_open_failure(unsigned int remotechan, 
 
890
                int reason, const unsigned char *text, const unsigned char *lang) {
 
891
 
 
892
        TRACE(("enter send_msg_channel_open_failure"))
 
893
        CHECKCLEARTOWRITE();
 
894
        
 
895
        buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_FAILURE);
 
896
        buf_putint(ses.writepayload, remotechan);
 
897
        buf_putint(ses.writepayload, reason);
 
898
        buf_putstring(ses.writepayload, text, strlen((char*)text));
 
899
        buf_putstring(ses.writepayload, lang, strlen((char*)lang));
 
900
 
 
901
        encrypt_packet();
 
902
        TRACE(("leave send_msg_channel_open_failure"))
 
903
}
 
904
 
 
905
/* Confirm a channel open, and let the remote end know what number we've
 
906
 * allocated and the receive parameters */
 
907
static void send_msg_channel_open_confirmation(struct Channel* channel,
 
908
                unsigned int recvwindow, 
 
909
                unsigned int recvmaxpacket) {
 
910
 
 
911
        TRACE(("enter send_msg_channel_open_confirmation"))
 
912
        CHECKCLEARTOWRITE();
 
913
 
 
914
        buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
 
915
        buf_putint(ses.writepayload, channel->remotechan);
 
916
        buf_putint(ses.writepayload, channel->index);
 
917
        buf_putint(ses.writepayload, recvwindow);
 
918
        buf_putint(ses.writepayload, recvmaxpacket);
 
919
 
 
920
        encrypt_packet();
 
921
        TRACE(("leave send_msg_channel_open_confirmation"))
 
922
}
 
923
 
 
924
#if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT)
 
925
/* Create a new channel, and start the open request. This is intended
 
926
 * for X11, agent, tcp forwarding, and should be filled with channel-specific
 
927
 * options, with the calling function calling encrypt_packet() after
 
928
 * completion. It is mandatory for the caller to encrypt_packet() if
 
929
 * DROPBEAR_SUCCESS is returned */
 
930
int send_msg_channel_open_init(int fd, const struct ChanType *type) {
 
931
 
 
932
        struct Channel* chan;
 
933
 
 
934
        TRACE(("enter send_msg_channel_open_init()"))
 
935
        chan = newchannel(0, type, 0, 0);
 
936
        if (!chan) {
 
937
                TRACE(("leave send_msg_channel_open_init() - FAILED in newchannel()"))
 
938
                return DROPBEAR_FAILURE;
 
939
        }
 
940
 
 
941
        /* set fd non-blocking */
 
942
        setnonblocking(fd);
 
943
 
 
944
        chan->infd = chan->outfd = fd;
 
945
        ses.maxfd = MAX(ses.maxfd, fd);
 
946
 
 
947
        /* now open the channel connection */
 
948
        CHECKCLEARTOWRITE();
 
949
 
 
950
        buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN);
 
951
        buf_putstring(ses.writepayload, type->name, strlen(type->name));
 
952
        buf_putint(ses.writepayload, chan->index);
 
953
        buf_putint(ses.writepayload, RECV_MAXWINDOW);
 
954
        buf_putint(ses.writepayload, RECV_MAXPACKET);
 
955
 
 
956
        TRACE(("leave send_msg_channel_open_init()"))
 
957
        return DROPBEAR_SUCCESS;
 
958
}
 
959
 
 
960
/* Confirmation that our channel open request (for forwardings) was 
 
961
 * successful*/
 
962
void recv_msg_channel_open_confirmation() {
 
963
 
 
964
        unsigned int chan;
 
965
        struct Channel * channel;
 
966
        int ret;
 
967
 
 
968
        TRACE(("enter recv_msg_channel_open_confirmation"))
 
969
        chan = buf_getint(ses.payload);
 
970
 
 
971
        channel = getchannel(chan);
 
972
        if (channel == NULL) {
 
973
                dropbear_exit("Unknown channel");
 
974
        }
 
975
 
 
976
        channel->remotechan =  buf_getint(ses.payload);
 
977
        channel->transwindow = buf_getint(ses.payload);
 
978
        channel->transmaxpacket = buf_getint(ses.payload);
 
979
        
 
980
        TRACE(("new chan remote %d localho %d", channel->remotechan, chan))
 
981
 
 
982
        /* Run the inithandler callback */
 
983
        if (channel->type->inithandler) {
 
984
                ret = channel->type->inithandler(channel);
 
985
                if (ret > 0) {
 
986
                        removechannel(channel);
 
987
                        TRACE(("inithandler returned failure %d", ret))
 
988
                }
 
989
        }
 
990
 
 
991
        
 
992
        TRACE(("leave recv_msg_channel_open_confirmation"))
 
993
}
 
994
 
 
995
/* Notification that our channel open request failed */
 
996
void recv_msg_channel_open_failure() {
 
997
 
 
998
        unsigned int chan;
 
999
        struct Channel * channel;
 
1000
        chan = buf_getbyte(ses.payload);
 
1001
 
 
1002
        channel = getchannel(chan);
 
1003
        if (channel == NULL) {
 
1004
                dropbear_exit("Unknown channel");
 
1005
        }
 
1006
 
 
1007
        removechannel(channel);
 
1008
}
 
1009
#endif /* USING_LISTENERS */
 
1010
 
 
1011
/* close a stdout/stderr fd */
 
1012
static void closeoutfd(struct Channel * channel, int fd) {
 
1013
 
 
1014
        /* don't close it if it is the same as infd,
 
1015
         * unless infd is already set -1 */
 
1016
        TRACE(("enter closeoutfd"))
 
1017
        closechanfd(channel, fd, 0);
 
1018
        TRACE(("leave closeoutfd"))
 
1019
}
 
1020
 
 
1021
/* close a stdin fd */
 
1022
static void closeinfd(struct Channel * channel) {
 
1023
 
 
1024
        TRACE(("enter closeinfd"))
 
1025
        closechanfd(channel, channel->infd, 1);
 
1026
        TRACE(("leave closeinfd"))
 
1027
}
 
1028
 
 
1029
/* close a fd, how is 0 for stdout/stderr, 1 for stdin */
 
1030
static void closechanfd(struct Channel *channel, int fd, int how) {
 
1031
 
 
1032
        int closein = 0, closeout = 0;
 
1033
 
 
1034
        /* XXX server */
 
1035
        if (channel->type->sepfds) {
 
1036
                shutdown(fd, how);
 
1037
                if (how == 0) {
 
1038
                        closeout = 1;
 
1039
                } else {
 
1040
                        closein = 1;
 
1041
                }
 
1042
        } else {
 
1043
                close(fd);
 
1044
                closein = closeout = 1;
 
1045
        }
 
1046
 
 
1047
        if (closeout && fd == channel->outfd) {
 
1048
                channel->outfd = FD_CLOSED;
 
1049
        }
 
1050
        if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) {
 
1051
                channel->errfd = FD_CLOSED;
 
1052
        }
 
1053
 
 
1054
        if (closein && fd == channel->infd) {
 
1055
                channel->infd = FD_CLOSED;
 
1056
        }
 
1057
        if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) {
 
1058
                channel->errfd = FD_CLOSED;
 
1059
        }
 
1060
}