Coverage Report

Created: 2025-08-29 06:35

/src/dropbear/src/common-channel.c
Line
Count
Source (jump to first uncovered line)
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 "listener.h"
36
#include "runopts.h"
37
#include "netio.h"
38
39
static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
40
    const char *text, const char *lang);
41
static void send_msg_channel_open_confirmation(const struct Channel* channel,
42
    unsigned int recvwindow, 
43
    unsigned int recvmaxpacket);
44
static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
45
  const unsigned char *moredata, unsigned int *morelen);
46
static void send_msg_channel_window_adjust(const struct Channel *channel,
47
    unsigned int incr);
48
static void send_msg_channel_data(struct Channel *channel, int isextended);
49
static void send_msg_channel_eof(struct Channel *channel);
50
static void send_msg_channel_close(struct Channel *channel);
51
static void remove_channel(struct Channel *channel);
52
static unsigned int write_pending(const struct Channel * channel);
53
static void check_close(struct Channel *channel);
54
static void close_chan_fd(struct Channel *channel, int fd, int how);
55
56
1.20k
#define FD_UNINIT (-2)
57
604
#define FD_CLOSED (-1)
58
59
0
#define ERRFD_IS_READ(channel) ((channel)->extrabuf == NULL)
60
0
#define ERRFD_IS_WRITE(channel) (!ERRFD_IS_READ(channel))
61
62
/* allow space for:
63
 * 1 byte  byte      SSH_MSG_CHANNEL_DATA
64
 * 4 bytes uint32    recipient channel
65
 * 4 bytes string    data
66
 */
67
604
#define RECV_MAX_CHANNEL_DATA_LEN (RECV_MAX_PAYLOAD_LEN-(1+4+4))
68
69
/* Initialise all the channels */
70
2.90k
void chaninitialise(const struct ChanType *chantypes[]) {
71
72
  /* may as well create space for a single channel */
73
2.90k
  ses.channels = (struct Channel**)m_malloc(sizeof(struct Channel*));
74
2.90k
  ses.chansize = 1;
75
2.90k
  ses.channels[0] = NULL;
76
2.90k
  ses.chancount = 0;
77
78
2.90k
  ses.chantypes = chantypes;
79
80
2.90k
#if DROPBEAR_LISTENERS
81
2.90k
  listeners_initialise();
82
2.90k
#endif
83
84
2.90k
}
85
86
/* Clean up channels, freeing allocated memory */
87
2.90k
void chancleanup() {
88
89
2.90k
  unsigned int i;
90
91
2.90k
  TRACE(("enter chancleanup"))
92
5.80k
  for (i = 0; i < ses.chansize; i++) {
93
2.90k
    if (ses.channels[i] != NULL) {
94
3
      TRACE(("channel %d closing", i))
95
3
      remove_channel(ses.channels[i]);
96
3
    }
97
2.90k
  }
98
2.90k
  m_free(ses.channels);
99
2.90k
  TRACE(("leave chancleanup"))
100
2.90k
}
101
102
/* Create a new channel entry, send a reply confirm or failure */
103
/* If remotechan, transwindow and transmaxpacket are not know (for a new
104
 * outgoing connection, with them to be filled on confirmation), they should
105
 * all be set to 0 */
106
static struct Channel* newchannel(unsigned int remotechan, 
107
    const struct ChanType *type, 
108
604
    unsigned int transwindow, unsigned int transmaxpacket) {
109
110
604
  struct Channel * newchan;
111
604
  unsigned int i, j;
112
113
604
  TRACE(("enter newchannel"))
114
  
115
  /* first see if we can use existing channels */
116
604
  for (i = 0; i < ses.chansize; i++) {
117
604
    if (ses.channels[i] == NULL) {
118
604
      break;
119
604
    }
120
604
  }
121
122
  /* otherwise extend the list */
123
604
  if (i == ses.chansize) {
124
0
    if (ses.chansize >= MAX_CHANNELS) {
125
0
      TRACE(("leave newchannel: max chans reached"))
126
0
      return NULL;
127
0
    }
128
129
    /* extend the channels */
130
0
    ses.channels = (struct Channel**)m_realloc(ses.channels,
131
0
        (ses.chansize+CHAN_EXTEND_SIZE)*sizeof(struct Channel*));
132
133
0
    ses.chansize += CHAN_EXTEND_SIZE;
134
135
    /* set the new channels to null */
136
0
    for (j = i; j < ses.chansize; j++) {
137
0
      ses.channels[j] = NULL;
138
0
    }
139
140
0
  }
141
  
142
604
  newchan = (struct Channel*)m_malloc(sizeof(struct Channel));
143
604
  newchan->type = type;
144
604
  newchan->index = i;
145
604
  newchan->sent_close = newchan->recv_close = 0;
146
604
  newchan->sent_eof = newchan->recv_eof = 0;
147
148
604
  newchan->remotechan = remotechan;
149
604
  newchan->transwindow = transwindow;
150
604
  newchan->transmaxpacket = transmaxpacket;
151
  
152
604
  newchan->typedata = NULL;
153
604
  newchan->writefd = FD_UNINIT;
154
604
  newchan->readfd = FD_UNINIT;
155
604
  newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
156
604
  newchan->await_open = 0;
157
158
604
  newchan->writebuf = cbuf_new(opts.recv_window);
159
604
  newchan->recvwindow = opts.recv_window;
160
161
604
  newchan->extrabuf = NULL; /* The user code can set it up */
162
604
  newchan->recvdonelen = 0;
163
604
  newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN;
164
165
604
  newchan->prio = DROPBEAR_PRIO_NORMAL;
166
167
604
  ses.channels[i] = newchan;
168
604
  ses.chancount++;
169
170
604
  TRACE(("leave newchannel"))
171
172
604
  return newchan;
173
604
}
174
175
/* Returns the channel structure corresponding to the channel in the current
176
 * data packet (ses.payload must be positioned appropriately).
177
 * A valid channel is always returns, it will fail fatally with an unknown
178
 * channel */
179
411
static struct Channel* getchannel_msg(const char* kind) {
180
181
411
  unsigned int chan;
182
183
411
  chan = buf_getint(ses.payload);
184
411
  if (chan >= ses.chansize || ses.channels[chan] == NULL) {
185
408
    if (kind) {
186
90
      dropbear_exit("%s for unknown channel %d", kind, chan);
187
318
    } else {
188
318
      dropbear_exit("Unknown channel %d", chan);
189
318
    }
190
408
  }
191
3
  return ses.channels[chan];
192
411
}
193
194
319
struct Channel* getchannel() {
195
319
  return getchannel_msg(NULL);
196
319
}
197
198
/* Iterate through the channels, performing IO if available */
199
143k
void channelio(const fd_set *readfds, const fd_set *writefds) {
200
201
  /* Listeners such as TCP, X11, agent-auth */
202
143k
  struct Channel *channel;
203
143k
  unsigned int i;
204
205
  /* foreach channel */
206
286k
  for (i = 0; i < ses.chansize; i++) {
207
    /* Close checking only needs to occur for channels that had IO events */
208
143k
    int do_check_close = 0;
209
210
143k
    channel = ses.channels[i];
211
143k
    if (channel == NULL) {
212
      /* only process in-use channels */
213
143k
      continue;
214
143k
    }
215
216
    /* read data and send it over the wire */
217
0
    if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) {
218
0
      TRACE(("send normal readfd"))
219
0
      send_msg_channel_data(channel, 0);
220
0
      do_check_close = 1;
221
0
    }
222
223
    /* read stderr data and send it over the wire */
224
0
    if (ERRFD_IS_READ(channel) && channel->errfd >= 0 
225
0
      && FD_ISSET(channel->errfd, readfds)) {
226
0
        TRACE(("send normal errfd"))
227
0
        send_msg_channel_data(channel, 1);
228
0
      do_check_close = 1;
229
0
    }
230
231
    /* write to program/pipe stdin */
232
0
    if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
233
0
      writechannel(channel, channel->writefd, channel->writebuf, NULL, NULL);
234
0
      do_check_close = 1;
235
0
    }
236
    
237
    /* stderr for client mode */
238
0
    if (ERRFD_IS_WRITE(channel)
239
0
        && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
240
0
      writechannel(channel, channel->errfd, channel->extrabuf, NULL, NULL);
241
0
      do_check_close = 1;
242
0
    }
243
244
0
    if (ses.channel_signal_pending) {
245
      /* SIGCHLD can change channel state for server sessions */
246
0
      do_check_close = 1;
247
0
    }
248
  
249
    /* handle any channel closing etc */
250
0
    if (do_check_close) {
251
0
      check_close(channel);
252
0
    }
253
0
  }
254
255
143k
#if DROPBEAR_LISTENERS
256
143k
  handle_listeners(readfds);
257
143k
#endif
258
143k
}
259
260
261
/* Returns true if there is data remaining to be written to stdin or
262
 * stderr of a channel's endpoint. */
263
0
static unsigned int write_pending(const struct Channel * channel) {
264
265
0
  if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) {
266
0
    return 1;
267
0
  } else if (channel->errfd >= 0 && channel->extrabuf && 
268
0
      cbuf_getused(channel->extrabuf) > 0) {
269
0
    return 1;
270
0
  }
271
0
  return 0;
272
0
}
273
274
275
/* EOF/close handling */
276
0
static void check_close(struct Channel *channel) {
277
0
  int close_allowed = 0;
278
279
0
  TRACE2(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
280
0
        channel->writefd, channel->readfd,
281
0
        channel->errfd, channel->sent_close, channel->recv_close))
282
0
  TRACE2(("writebuf size %d extrabuf size %d",
283
0
        channel->writebuf ? cbuf_getused(channel->writebuf) : 0,
284
0
        channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
285
286
  /* if a type-specific check_close is defined we will only exit
287
     once that has been triggered. this is only used for a server "session"
288
     channel, to ensure that the shell has exited (and the exit status
289
     retrieved) before we close things up. */
290
0
  if (!channel->type->check_close
291
0
    || channel->sent_close
292
0
    || channel->type->check_close(channel)) {
293
0
    close_allowed = 1;
294
0
  }
295
296
  /* In flushing mode we close FDs as soon as pipes are empty.
297
  This is used to drain out FDs when the process exits, in the case
298
  where the FD doesn't have EOF - "sleep 10&echo hello" case */
299
0
  if (channel->flushing) {
300
0
    if (channel->readfd >= 0 && !fd_read_pending(channel->readfd)) {
301
0
      close_chan_fd(channel, channel->readfd, SHUT_RD);
302
0
    }
303
0
    if (ERRFD_IS_READ(channel)
304
0
      && channel->errfd >= 0 && !fd_read_pending(channel->errfd)) {
305
0
      close_chan_fd(channel, channel->errfd, SHUT_RD);
306
0
    }
307
0
  }
308
309
0
  if (channel->recv_close && !write_pending(channel) && close_allowed) {
310
0
    if (!channel->sent_close) {
311
0
      TRACE(("Sending MSG_CHANNEL_CLOSE in response to same."))
312
0
      send_msg_channel_close(channel);
313
0
    }
314
0
    remove_channel(channel);
315
0
    return;
316
0
  }
317
318
0
  if ((channel->recv_eof && !write_pending(channel))
319
    /* have a server "session" and child has exited */
320
0
    || (channel->writefd != FD_UNINIT
321
0
      && channel->type->check_close && close_allowed)) {
322
0
    close_chan_fd(channel, channel->writefd, SHUT_WR);
323
0
  }
324
325
  /* If we're not going to send any more data, send EOF */
326
0
  if (!channel->sent_eof
327
0
      && channel->readfd == FD_CLOSED 
328
0
      && (ERRFD_IS_WRITE(channel) || channel->errfd == FD_CLOSED)) {
329
0
    send_msg_channel_eof(channel);
330
0
  }
331
332
  /* And if we can't receive any more data from them either, close up */
333
0
  if (channel->readfd == FD_CLOSED
334
0
      && channel->writefd == FD_CLOSED
335
0
      && (ERRFD_IS_WRITE(channel) || channel->errfd == FD_CLOSED)
336
0
      && !channel->sent_close
337
0
      && close_allowed
338
0
      && !write_pending(channel)) {
339
0
    TRACE(("sending close, readfd is closed"))
340
0
    send_msg_channel_close(channel);
341
0
  }
342
0
}
343
344
/* Check whether a deferred (EINPROGRESS) connect() was successful, and
345
 * if so, set up the channel properly. Otherwise, the channel is cleaned up, so
346
 * it is important that the channel reference isn't used after a call to this
347
 * function */
348
0
void channel_connect_done(int result, int sock, void* user_data, const char* errstring) {
349
0
  struct Channel *channel = user_data;
350
351
0
  TRACE(("enter channel_connect_done"))
352
353
0
  if (result == DROPBEAR_SUCCESS)
354
0
  {
355
0
    channel->readfd = channel->writefd = sock;
356
0
    channel->bidir_fd = 1;
357
0
    channel->conn_pending = NULL;
358
0
    send_msg_channel_open_confirmation(channel, channel->recvwindow,
359
0
        channel->recvmaxpacket);
360
0
    TRACE(("leave channel_connect_done: success"))
361
0
  }
362
0
  else
363
0
  {
364
0
    send_msg_channel_open_failure(channel->remotechan,
365
0
        SSH_OPEN_CONNECT_FAILED, errstring, "");
366
0
    remove_channel(channel);
367
0
    TRACE(("leave check_in_progress: fail. internal errstring: %s", errstring))
368
0
  }
369
0
}
370
371
372
/* Send the close message and set the channel as closed */
373
0
static void send_msg_channel_close(struct Channel *channel) {
374
375
0
  TRACE(("enter send_msg_channel_close %p", (void*)channel))
376
0
  if (channel->type->closehandler) {
377
0
    channel->type->closehandler(channel);
378
0
  }
379
  
380
0
  CHECKCLEARTOWRITE();
381
382
0
  buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_CLOSE);
383
0
  buf_putint(ses.writepayload, channel->remotechan);
384
385
0
  encrypt_packet();
386
387
0
  channel->sent_eof = 1;
388
0
  channel->sent_close = 1;
389
0
  close_chan_fd(channel, channel->readfd, SHUT_RD);
390
0
  close_chan_fd(channel, channel->errfd, SHUT_RDWR);
391
0
  close_chan_fd(channel, channel->writefd, SHUT_WR);
392
0
  TRACE(("leave send_msg_channel_close"))
393
0
}
394
395
/* call this when trans/eof channels are closed */
396
0
static void send_msg_channel_eof(struct Channel *channel) {
397
398
0
  TRACE(("enter send_msg_channel_eof"))
399
0
  CHECKCLEARTOWRITE();
400
401
0
  buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_EOF);
402
0
  buf_putint(ses.writepayload, channel->remotechan);
403
404
0
  encrypt_packet();
405
406
0
  channel->sent_eof = 1;
407
408
0
  TRACE(("leave send_msg_channel_eof"))
409
0
}
410
411
#ifndef HAVE_WRITEV
412
static int writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf,
413
  const unsigned char *UNUSED(moredata), unsigned int *morelen) {
414
415
  unsigned char *circ_p1, *circ_p2;
416
  unsigned int circ_len1, circ_len2;
417
  ssize_t written;
418
419
  if (morelen) {
420
    /* fallback doesn't consume moredata */
421
    *morelen = 0;
422
  }
423
424
  /* Write the first portion of the circular buffer */
425
  cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
426
  written = write(fd, circ_p1, circ_len1);
427
  if (written < 0) {
428
    if (errno != EINTR && errno != EAGAIN) {
429
      TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
430
      close_chan_fd(channel, fd, SHUT_WR);
431
      return DROPBEAR_FAILURE;
432
    }
433
  } else {
434
    cbuf_incrread(cbuf, written);
435
    channel->recvdonelen += written;
436
  }
437
  return DROPBEAR_SUCCESS;
438
}
439
#endif /* !HAVE_WRITEV */
440
441
#ifdef HAVE_WRITEV
442
static int writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf,
443
0
  const unsigned char *moredata, unsigned int *morelen) {
444
445
0
  struct iovec iov[3];
446
0
  unsigned char *circ_p1, *circ_p2;
447
0
  unsigned int circ_len1, circ_len2;
448
0
  int io_count = 0;
449
450
0
  ssize_t written;
451
452
0
  cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
453
454
0
  if (circ_len1 > 0) {
455
0
    TRACE(("circ1 %d", circ_len1))
456
0
    iov[io_count].iov_base = circ_p1;
457
0
    iov[io_count].iov_len = circ_len1;
458
0
    io_count++;
459
0
  }
460
461
0
  if (circ_len2 > 0) {
462
0
    TRACE(("circ2 %d", circ_len2))
463
0
    iov[io_count].iov_base = circ_p2;
464
0
    iov[io_count].iov_len = circ_len2;
465
0
    io_count++;
466
0
  }
467
468
0
  if (morelen) {
469
0
    assert(moredata);
470
0
    TRACE(("more %d", *morelen))
471
0
    iov[io_count].iov_base = (void*)moredata;
472
0
    iov[io_count].iov_len  = *morelen;
473
0
    io_count++;
474
0
  }
475
476
0
  if (io_count == 0) {
477
    /* writechannel may sometimes be called twice in a main loop iteration.
478
    From common_recv_msg_channel_data() then channelio().
479
    The second call may not have any data to write, so we just return. */
480
0
    TRACE(("leave writechannel, no data"))
481
0
    return DROPBEAR_SUCCESS;
482
0
  }
483
484
0
  if (morelen) {
485
    /* Default return value, none consumed */
486
0
    *morelen = 0;
487
0
  }
488
489
0
  written = writev(fd, iov, io_count);
490
491
0
  if (written < 0) {
492
0
    if (errno != EINTR && errno != EAGAIN) {
493
0
      TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
494
0
      close_chan_fd(channel, fd, SHUT_WR);
495
0
      return DROPBEAR_FAILURE;
496
0
    }
497
0
  } else {
498
0
    int cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written);
499
0
    cbuf_incrread(cbuf, cbuf_written);
500
0
    if (morelen) {
501
0
      *morelen = written - cbuf_written;
502
0
    }
503
0
    channel->recvdonelen += written;
504
0
  }
505
0
  return DROPBEAR_SUCCESS;
506
0
}
507
#endif /* HAVE_WRITEV */
508
509
/* Called to write data out to the local side of the channel. 
510
   Writes the circular buffer contents and also the "moredata" buffer
511
   if not null. Will ignore EAGAIN.
512
   Returns DROPBEAR_FAILURE if writing to fd had an error and the channel is being closed, DROPBEAR_SUCCESS otherwise */
513
static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
514
0
  const unsigned char *moredata, unsigned int *morelen) {
515
0
  int ret = DROPBEAR_SUCCESS;
516
0
  TRACE(("enter writechannel fd %d", fd))
517
0
#ifdef HAVE_WRITEV
518
0
  ret = writechannel_writev(channel, fd, cbuf, moredata, morelen);
519
#else
520
  ret = writechannel_fallback(channel, fd, cbuf, moredata, morelen);
521
#endif
522
523
  /* Window adjust handling */
524
0
  if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
525
0
    send_msg_channel_window_adjust(channel, channel->recvdonelen);
526
0
    channel->recvwindow += channel->recvdonelen;
527
0
    channel->recvdonelen = 0;
528
0
  }
529
530
0
  dropbear_assert(channel->recvwindow <= opts.recv_window);
531
0
  dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
532
0
  dropbear_assert(channel->extrabuf == NULL ||
533
0
      channel->recvwindow <= cbuf_getavail(channel->extrabuf));
534
  
535
0
  TRACE(("leave writechannel"))
536
0
  return ret;
537
0
}
538
539
540
/* Set the file descriptors for the main select in session.c
541
 * This avoid channels which don't have any window available, are closed, etc*/
542
146k
void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads) {
543
  
544
146k
  unsigned int i;
545
146k
  struct Channel * channel;
546
  
547
292k
  for (i = 0; i < ses.chansize; i++) {
548
549
146k
    channel = ses.channels[i];
550
146k
    if (channel == NULL) {
551
146k
      continue;
552
146k
    }
553
554
    /* Stuff to put over the wire. 
555
    Avoid queueing data to send if we're in the middle of a 
556
    key re-exchange (!dataallowed), but still read from the 
557
    FD if there's the possibility of "~."" to kill an 
558
    interactive session (the read_mangler) */
559
0
    if (channel->transwindow > 0
560
0
       && ((ses.dataallowed && allow_reads) || channel->read_mangler)) {
561
562
0
      if (channel->readfd >= 0) {
563
0
        FD_SET(channel->readfd, readfds);
564
0
      }
565
      
566
0
      if (ERRFD_IS_READ(channel) && channel->errfd >= 0) {
567
0
          FD_SET(channel->errfd, readfds);
568
0
      }
569
0
    }
570
571
    /* Stuff from the wire */
572
0
    if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) {
573
0
        FD_SET(channel->writefd, writefds);
574
0
    }
575
576
0
    if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0 
577
0
        && cbuf_getused(channel->extrabuf) > 0) {
578
0
        FD_SET(channel->errfd, writefds);
579
0
    }
580
581
0
  } /* foreach channel */
582
583
146k
#if DROPBEAR_LISTENERS
584
146k
  set_listener_fds(readfds);
585
146k
#endif
586
587
146k
}
588
589
/* handle the channel EOF event, by closing the channel filedescriptor. The
590
 * channel isn't closed yet, it is left until the incoming (from the program
591
 * etc) FD is also EOF */
592
50
void recv_msg_channel_eof() {
593
594
50
  struct Channel * channel;
595
596
50
  TRACE(("enter recv_msg_channel_eof"))
597
598
50
  channel = getchannel_msg("EOF");
599
600
50
  channel->recv_eof = 1;
601
602
50
  check_close(channel);
603
50
  TRACE(("leave recv_msg_channel_eof"))
604
50
}
605
606
607
/* Handle channel closure(), respond in kind and close the channels */
608
42
void recv_msg_channel_close() {
609
610
42
  struct Channel * channel;
611
612
42
  TRACE(("enter recv_msg_channel_close"))
613
614
42
  channel = getchannel_msg("Close");
615
616
42
  channel->recv_eof = 1;
617
42
  channel->recv_close = 1;
618
619
42
  check_close(channel);
620
42
  TRACE(("leave recv_msg_channel_close"))
621
42
}
622
623
/* Remove a channel entry, this is only executed after both sides have sent
624
 * channel close */
625
604
static void remove_channel(struct Channel * channel) {
626
627
604
  TRACE(("enter remove_channel"))
628
604
  TRACE(("channel index is %d", channel->index))
629
630
604
  cbuf_free(channel->writebuf);
631
604
  channel->writebuf = NULL;
632
633
604
  if (channel->extrabuf) {
634
0
    cbuf_free(channel->extrabuf);
635
0
    channel->extrabuf = NULL;
636
0
  }
637
638
639
604
  if (IS_DROPBEAR_SERVER || (channel->writefd != STDOUT_FILENO)) {
640
    /* close the FDs in case they haven't been done
641
     * yet (they might have been shutdown etc) */
642
604
    TRACE(("CLOSE writefd %d", channel->writefd))
643
604
    m_close(channel->writefd);
644
604
    TRACE(("CLOSE readfd %d", channel->readfd))
645
604
    m_close(channel->readfd);
646
604
    TRACE(("CLOSE errfd %d", channel->errfd))
647
604
    m_close(channel->errfd);
648
604
  }
649
650
604
  if (channel->type->cleanup) {
651
0
    channel->type->cleanup(channel);
652
0
  }
653
654
604
  if (channel->conn_pending) {
655
0
    cancel_connect(channel->conn_pending);
656
0
  }
657
658
604
  ses.channels[channel->index] = NULL;
659
604
  m_free(channel);
660
604
  ses.chancount--;
661
662
604
  update_channel_prio();
663
664
604
  TRACE(("leave remove_channel"))
665
604
}
666
667
/* Handle channel specific requests, passing off to corresponding handlers
668
 * such as chansession or x11fwd */
669
48
void recv_msg_channel_request() {
670
671
48
  struct Channel *channel;
672
673
48
  channel = getchannel();
674
675
48
  TRACE(("enter recv_msg_channel_request %p", (void*)channel))
676
677
48
  if (channel->type->reqhandler) {
678
0
    channel->type->reqhandler(channel);
679
48
  } else {
680
48
    int wantreply;
681
48
    buf_eatstring(ses.payload);
682
48
    wantreply = buf_getbool(ses.payload);
683
48
    if (wantreply) {
684
0
      send_msg_channel_failure(channel);
685
0
    }
686
48
  }
687
688
48
  TRACE(("leave recv_msg_channel_request"))
689
690
48
}
691
692
/* Reads data from the server's program/shell/etc, and puts it in a
693
 * channel_data packet to send.
694
 * chan is the remote channel, isextended is 0 if it is normal data, 1
695
 * if it is extended data. if it is extended, then the type is in
696
 * exttype */
697
0
static void send_msg_channel_data(struct Channel *channel, int isextended) {
698
699
0
  int len;
700
0
  size_t maxlen, size_pos;
701
0
  int fd;
702
703
0
  CHECKCLEARTOWRITE();
704
705
0
  TRACE(("enter send_msg_channel_data"))
706
0
  dropbear_assert(!channel->sent_close);
707
708
0
  if (isextended) {
709
0
    fd = channel->errfd;
710
0
  } else {
711
0
    fd = channel->readfd;
712
0
  }
713
0
  TRACE(("enter send_msg_channel_data isextended %d fd %d", isextended, fd))
714
0
  dropbear_assert(fd >= 0);
715
716
0
  maxlen = MIN(channel->transwindow, channel->transmaxpacket);
717
  /* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and 
718
   * exttype if is extended */
719
0
  maxlen = MIN(maxlen, 
720
0
      ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0));
721
0
  TRACE(("maxlen %zd", maxlen))
722
0
  if (maxlen == 0) {
723
0
    TRACE(("leave send_msg_channel_data: no window"))
724
0
    return;
725
0
  }
726
727
0
  buf_putbyte(ses.writepayload, 
728
0
      isextended ? SSH_MSG_CHANNEL_EXTENDED_DATA : SSH_MSG_CHANNEL_DATA);
729
0
  buf_putint(ses.writepayload, channel->remotechan);
730
0
  if (isextended) {
731
0
    buf_putint(ses.writepayload, SSH_EXTENDED_DATA_STDERR);
732
0
  }
733
  /* a dummy size first ...*/
734
0
  size_pos = ses.writepayload->pos;
735
0
  buf_putint(ses.writepayload, 0);
736
737
  /* read the data */
738
0
  len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen);
739
740
0
  if (len <= 0) {
741
0
    if (len == 0 || errno != EINTR) {
742
      /* This will also get hit in the case of EAGAIN. The only
743
      time we expect to receive EAGAIN is when we're flushing a FD,
744
      in which case it can be treated the same as EOF */
745
0
      close_chan_fd(channel, fd, SHUT_RD);
746
0
    }
747
0
    buf_setpos(ses.writepayload, 0);
748
0
    buf_setlen(ses.writepayload, 0);
749
0
    TRACE(("leave send_msg_channel_data: len %d read err %d or EOF for fd %d", 
750
0
          len, errno, fd))
751
0
    return;
752
0
  }
753
754
0
  if (channel->read_mangler) {
755
0
    channel->read_mangler(channel, buf_getwriteptr(ses.writepayload, len), &len);
756
0
    if (len == 0) {
757
0
      buf_setpos(ses.writepayload, 0);
758
0
      buf_setlen(ses.writepayload, 0);
759
0
      return;
760
0
    }
761
0
  }
762
763
0
  TRACE(("send_msg_channel_data: len %d fd %d", len, fd))
764
0
  buf_incrwritepos(ses.writepayload, len);
765
  /* ... real size here */
766
0
  buf_setpos(ses.writepayload, size_pos);
767
0
  buf_putint(ses.writepayload, len);
768
769
0
  channel->transwindow -= len;
770
771
0
  encrypt_packet();
772
0
  TRACE(("leave send_msg_channel_data"))
773
0
}
774
775
/* We receive channel data */
776
55
void recv_msg_channel_data() {
777
778
55
  struct Channel *channel;
779
780
55
  channel = getchannel();
781
782
55
  common_recv_msg_channel_data(channel, channel->writefd, channel->writebuf);
783
55
}
784
785
/* Shared for data and stderr data - when we receive data, put it in a buffer
786
 * for writing to the local file descriptor */
787
void common_recv_msg_channel_data(struct Channel *channel, int fd, 
788
0
    circbuffer * cbuf) {
789
790
0
  unsigned int datalen;
791
0
  unsigned int maxdata;
792
0
  unsigned int buflen;
793
0
  unsigned int len;
794
0
  unsigned int consumed;
795
0
  int res;
796
797
0
  TRACE(("enter recv_msg_channel_data"))
798
799
0
  if (channel->recv_eof) {
800
0
    dropbear_exit("Received data after eof");
801
0
  }
802
803
0
  if (fd < 0 || !cbuf) {
804
    /* If we have encountered failed write, the far side might still
805
     * be sending data without having yet received our close notification.
806
     * We just drop the data. */
807
0
    return;
808
0
  }
809
810
0
  datalen = buf_getint(ses.payload);
811
0
  TRACE(("length %d", datalen))
812
813
0
  maxdata = cbuf_getavail(cbuf);
814
815
  /* Whilst the spec says we "MAY ignore data past the end" this could
816
   * lead to corrupted file transfers etc (chunks missed etc). It's better to
817
   * just die horribly */
818
0
  if (datalen > maxdata) {
819
0
    dropbear_exit("Oversized packet");
820
0
  }
821
822
0
  dropbear_assert(channel->recvwindow >= datalen);
823
0
  channel->recvwindow -= datalen;
824
0
  dropbear_assert(channel->recvwindow <= opts.recv_window);
825
826
  /* Attempt to write the data immediately without having to put it in the circular buffer */
827
0
  consumed = datalen;
828
0
  res = writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed);
829
830
0
  datalen -= consumed;
831
0
  buf_incrpos(ses.payload, consumed);
832
833
834
  /* We may have to run throught twice, if the buffer wraps around. Can't
835
   * just "leave it for next time" like with writechannel, since this
836
   * is payload data.
837
   * If the writechannel() failed then remaining data is discarded */
838
0
  if (res == DROPBEAR_SUCCESS) {
839
0
    len = datalen;
840
0
    while (len > 0) {
841
0
      buflen = cbuf_writelen(cbuf);
842
0
      buflen = MIN(buflen, len);
843
844
0
      memcpy(cbuf_writeptr(cbuf, buflen), 
845
0
          buf_getptr(ses.payload, buflen), buflen);
846
0
      cbuf_incrwrite(cbuf, buflen);
847
0
      buf_incrpos(ses.payload, buflen);
848
0
      len -= buflen;
849
0
    }
850
0
  }
851
852
0
  TRACE(("leave recv_msg_channel_data"))
853
0
}
854
855
/* Increment the outgoing data window for a channel - the remote end limits
856
 * the amount of data which may be transmitted, this window is decremented
857
 * as data is sent, and incremented upon receiving window-adjust messages */
858
54
void recv_msg_channel_window_adjust() {
859
860
54
  struct Channel * channel;
861
54
  unsigned int incr;
862
  
863
54
  channel = getchannel();
864
  
865
54
  incr = buf_getint(ses.payload);
866
54
  TRACE(("received window increment %d", incr))
867
54
  incr = MIN(incr, TRANS_MAX_WIN_INCR);
868
  
869
54
  channel->transwindow += incr;
870
54
  channel->transwindow = MIN(channel->transwindow, TRANS_MAX_WINDOW);
871
872
54
}
873
874
/* Increment the incoming data window for a channel, and let the remote
875
 * end know */
876
static void send_msg_channel_window_adjust(const struct Channel* channel,
877
0
    unsigned int incr) {
878
879
0
  TRACE(("sending window adjust %d", incr))
880
0
  CHECKCLEARTOWRITE();
881
882
0
  buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_WINDOW_ADJUST);
883
0
  buf_putint(ses.writepayload, channel->remotechan);
884
0
  buf_putint(ses.writepayload, incr);
885
886
0
  encrypt_packet();
887
0
}
888
  
889
/* Handle a new channel request, performing any channel-type-specific setup */
890
1.91k
void recv_msg_channel_open() {
891
892
1.91k
  char *type;
893
1.91k
  unsigned int typelen;
894
1.91k
  unsigned int remotechan, transwindow, transmaxpacket;
895
1.91k
  struct Channel *channel;
896
1.91k
  const struct ChanType **cp;
897
1.91k
  const struct ChanType *chantype;
898
1.91k
  unsigned int errtype = SSH_OPEN_UNKNOWN_CHANNEL_TYPE;
899
1.91k
  int ret;
900
901
902
1.91k
  TRACE(("enter recv_msg_channel_open"))
903
904
  /* get the packet contents */
905
1.91k
  type = buf_getstring(ses.payload, &typelen);
906
907
1.91k
  remotechan = buf_getint(ses.payload);
908
1.91k
  transwindow = buf_getint(ses.payload);
909
1.91k
  transwindow = MIN(transwindow, TRANS_MAX_WINDOW);
910
1.91k
  transmaxpacket = buf_getint(ses.payload);
911
1.91k
  transmaxpacket = MIN(transmaxpacket, TRANS_MAX_PAYLOAD_LEN);
912
913
  /* figure what type of packet it is */
914
1.91k
  if (typelen > MAX_NAME_LEN) {
915
282
    goto failure;
916
282
  }
917
918
  /* Get the channel type. Client and server style invokation will set up a
919
   * different list for ses.chantypes at startup. We just iterate through
920
   * this list and find the matching name */
921
1.63k
  for (cp = &ses.chantypes[0], chantype = (*cp); 
922
3.86k
      chantype != NULL;
923
2.83k
      cp++, chantype = (*cp)) {
924
2.83k
    if (strcmp(type, chantype->name) == 0) {
925
604
      break;
926
604
    }
927
2.83k
  }
928
929
1.63k
  if (chantype == NULL) {
930
1.01k
    TRACE(("No matching type for '%s'", type))
931
1.01k
    goto failure;
932
1.01k
  }
933
934
614
  TRACE(("matched type '%s'", type))
935
936
  /* create the channel */
937
614
  channel = newchannel(remotechan, chantype, transwindow, transmaxpacket);
938
939
614
  if (channel == NULL) {
940
0
    TRACE(("newchannel returned NULL"))
941
0
    errtype = SSH_OPEN_RESOURCE_SHORTAGE;
942
0
    goto failure;
943
0
  }
944
945
614
  if (channel->type->inithandler) {
946
604
    ret = channel->type->inithandler(channel);
947
604
    if (ret == SSH_OPEN_IN_PROGRESS) {
948
      /* We'll send the confirmation later */
949
0
      goto cleanup;
950
0
    }
951
604
    if (ret > 0) {
952
601
      errtype = ret;
953
601
      remove_channel(channel);
954
601
      TRACE(("inithandler returned failure %d", ret))
955
601
      goto failure;
956
601
    }
957
604
  }
958
959
13
  update_channel_prio();
960
961
  /* success */
962
13
  send_msg_channel_open_confirmation(channel, channel->recvwindow,
963
13
      channel->recvmaxpacket);
964
13
  goto cleanup;
965
966
1.90k
failure:
967
1.90k
  TRACE(("recv_msg_channel_open failure"))
968
1.90k
  send_msg_channel_open_failure(remotechan, errtype, "", "");
969
970
1.90k
cleanup:
971
1.90k
  m_free(type);
972
973
1.90k
  TRACE(("leave recv_msg_channel_open"))
974
1.90k
}
975
976
/* Send a failure message */
977
0
void send_msg_channel_failure(const struct Channel *channel) {
978
979
0
  TRACE(("enter send_msg_channel_failure"))
980
981
0
  if (channel->sent_close) {
982
0
    TRACE(("Skipping sending msg_channel_failure for closed channel"))
983
0
    return;
984
0
  }
985
0
  CHECKCLEARTOWRITE();
986
987
0
  buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_FAILURE);
988
0
  buf_putint(ses.writepayload, channel->remotechan);
989
990
0
  encrypt_packet();
991
0
  TRACE(("leave send_msg_channel_failure"))
992
0
}
993
994
/* Send a success message */
995
0
void send_msg_channel_success(const struct Channel *channel) {
996
997
0
  TRACE(("enter send_msg_channel_success"))
998
0
  if (channel->sent_close) {
999
0
    TRACE(("Skipping sending msg_channel_success for closed channel"))
1000
0
    return;
1001
0
  }
1002
0
  CHECKCLEARTOWRITE();
1003
1004
0
  buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_SUCCESS);
1005
0
  buf_putint(ses.writepayload, channel->remotechan);
1006
1007
0
  encrypt_packet();
1008
0
  TRACE(("leave send_msg_channel_success"))
1009
0
}
1010
1011
/* Send a channel open failure message, with a corresponding reason
1012
 * code (usually resource shortage or unknown chan type) */
1013
static void send_msg_channel_open_failure(unsigned int remotechan, 
1014
1.90k
    int reason, const char *text, const char *lang) {
1015
1016
1.90k
  TRACE(("enter send_msg_channel_open_failure"))
1017
1.90k
  CHECKCLEARTOWRITE();
1018
  
1019
1.90k
  buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_FAILURE);
1020
1.90k
  buf_putint(ses.writepayload, remotechan);
1021
1.90k
  buf_putint(ses.writepayload, reason);
1022
1.90k
  buf_putstring(ses.writepayload, text, strlen(text));
1023
1.90k
  buf_putstring(ses.writepayload, lang, strlen(lang));
1024
1025
1.90k
  encrypt_packet();
1026
1.90k
  TRACE(("leave send_msg_channel_open_failure"))
1027
1.90k
}
1028
1029
/* Confirm a channel open, and let the remote end know what number we've
1030
 * allocated and the receive parameters */
1031
static void send_msg_channel_open_confirmation(const struct Channel* channel,
1032
    unsigned int recvwindow, 
1033
0
    unsigned int recvmaxpacket) {
1034
1035
0
  TRACE(("enter send_msg_channel_open_confirmation"))
1036
0
  CHECKCLEARTOWRITE();
1037
1038
0
  buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
1039
0
  buf_putint(ses.writepayload, channel->remotechan);
1040
0
  buf_putint(ses.writepayload, channel->index);
1041
0
  buf_putint(ses.writepayload, recvwindow);
1042
0
  buf_putint(ses.writepayload, recvmaxpacket);
1043
1044
0
  encrypt_packet();
1045
0
  TRACE(("leave send_msg_channel_open_confirmation"))
1046
0
}
1047
1048
/* close a fd, how is SHUT_RD or SHUT_WR */
1049
0
static void close_chan_fd(struct Channel *channel, int fd, int how) {
1050
1051
0
  int closein = 0, closeout = 0;
1052
1053
0
  if (channel->bidir_fd) {
1054
0
    TRACE(("SHUTDOWN(%d, %d)", fd, how))
1055
0
    shutdown(fd, how);
1056
0
    if (how == 0) {
1057
0
      closeout = 1;
1058
0
    } else {
1059
0
      closein = 1;
1060
0
    }
1061
0
  } else {
1062
0
    TRACE(("CLOSE some fd %d", fd))
1063
0
    m_close(fd);
1064
0
    closein = closeout = 1;
1065
0
  }
1066
1067
0
  if (closeout && (fd == channel->readfd)) {
1068
0
    channel->readfd = FD_CLOSED;
1069
0
  }
1070
0
  if (closeout && ERRFD_IS_READ(channel) && (fd == channel->errfd)) {
1071
0
    channel->errfd = FD_CLOSED;
1072
0
  }
1073
1074
0
  if (closein && fd == channel->writefd) {
1075
0
    channel->writefd = FD_CLOSED;
1076
0
  }
1077
0
  if (closein && ERRFD_IS_WRITE(channel) && (fd == channel->errfd)) {
1078
0
    channel->errfd = FD_CLOSED;
1079
0
  }
1080
1081
  /* if we called shutdown on it and all references are gone, then we 
1082
   * need to close() it to stop it lingering */
1083
0
  if (channel->bidir_fd && channel->readfd == FD_CLOSED 
1084
0
    && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
1085
0
    TRACE(("CLOSE (finally) of %d", fd))
1086
0
    m_close(fd);
1087
0
  }
1088
0
}
1089
1090
1091
#if (DROPBEAR_LISTENERS) || (DROPBEAR_CLIENT)
1092
/* Create a new channel, and start the open request. This is intended
1093
 * for X11, agent, tcp forwarding, and should be filled with channel-specific
1094
 * options, with the calling function calling encrypt_packet() after
1095
 * completion. It is mandatory for the caller to encrypt_packet() if
1096
 * a channel is returned. NULL is returned on failure. */
1097
0
int send_msg_channel_open_init(int fd, const struct ChanType *type) {
1098
1099
0
  struct Channel* chan;
1100
1101
0
  TRACE(("enter send_msg_channel_open_init()"))
1102
0
  chan = newchannel(0, type, 0, 0);
1103
0
  if (!chan) {
1104
0
    TRACE(("leave send_msg_channel_open_init() - FAILED in newchannel()"))
1105
0
    return DROPBEAR_FAILURE;
1106
0
  }
1107
1108
  /* Outbound opened channels don't make use of in-progress connections,
1109
   * we can set it up straight away */
1110
1111
  /* set fd non-blocking */
1112
0
  setnonblocking(fd);
1113
1114
0
  chan->writefd = chan->readfd = fd;
1115
0
  ses.maxfd = MAX(ses.maxfd, fd);
1116
0
  chan->bidir_fd = 1;
1117
1118
0
  chan->await_open = 1;
1119
1120
  /* now open the channel connection */
1121
0
  CHECKCLEARTOWRITE();
1122
1123
0
  buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN);
1124
0
  buf_putstring(ses.writepayload, type->name, strlen(type->name));
1125
0
  buf_putint(ses.writepayload, chan->index);
1126
0
  buf_putint(ses.writepayload, opts.recv_window);
1127
0
  buf_putint(ses.writepayload, RECV_MAX_CHANNEL_DATA_LEN);
1128
1129
0
  TRACE(("leave send_msg_channel_open_init()"))
1130
0
  return DROPBEAR_SUCCESS;
1131
0
}
1132
1133
/* Confirmation that our channel open request was 
1134
 * successful*/
1135
53
void recv_msg_channel_open_confirmation() {
1136
1137
53
  struct Channel * channel;
1138
53
  int ret;
1139
1140
53
  TRACE(("enter recv_msg_channel_open_confirmation"))
1141
1142
53
  channel = getchannel();
1143
1144
53
  if (!channel->await_open) {
1145
0
    dropbear_exit("Unexpected channel reply");
1146
0
  }
1147
53
  channel->await_open = 0;
1148
1149
53
  channel->remotechan =  buf_getint(ses.payload);
1150
53
  channel->transwindow = buf_getint(ses.payload);
1151
53
  channel->transmaxpacket = buf_getint(ses.payload);
1152
  
1153
53
  TRACE(("new chan remote %d local %d", 
1154
53
        channel->remotechan, channel->index))
1155
1156
  /* Run the inithandler callback */
1157
53
  if (channel->type->inithandler) {
1158
0
    ret = channel->type->inithandler(channel);
1159
0
    if (ret > 0) {
1160
0
      remove_channel(channel);
1161
0
      TRACE(("inithandler returned failure %d", ret))
1162
0
      return;
1163
0
    }
1164
0
  }
1165
1166
53
  update_channel_prio();
1167
1168
53
  TRACE(("leave recv_msg_channel_open_confirmation"))
1169
53
}
1170
1171
/* Notification that our channel open request failed */
1172
54
void recv_msg_channel_open_failure() {
1173
1174
54
  struct Channel * channel;
1175
1176
54
  channel = getchannel();
1177
1178
54
  if (!channel->await_open) {
1179
0
    dropbear_exit("Unexpected channel reply");
1180
0
  }
1181
54
  channel->await_open = 0;
1182
1183
54
  remove_channel(channel);
1184
54
}
1185
#endif /* DROPBEAR_LISTENERS */
1186
1187
0
void send_msg_request_success() {
1188
0
  CHECKCLEARTOWRITE();
1189
0
  buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS);
1190
0
  encrypt_packet();
1191
0
}
1192
1193
785
void send_msg_request_failure() {
1194
785
  CHECKCLEARTOWRITE();
1195
785
  buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
1196
785
  encrypt_packet();
1197
785
}
1198
1199
0
struct Channel* get_any_ready_channel() {
1200
0
  size_t i;
1201
0
  if (ses.chancount == 0) {
1202
0
    return NULL;
1203
0
  }
1204
0
  for (i = 0; i < ses.chansize; i++) {
1205
0
    struct Channel *chan = ses.channels[i];
1206
0
    if (chan
1207
0
        && !(chan->sent_eof || chan->recv_eof)
1208
0
        && !(chan->await_open)) {
1209
0
      return chan;
1210
0
    }
1211
0
  }
1212
0
  return NULL;
1213
0
}
1214
1215
void start_send_channel_request(const struct Channel *channel,
1216
0
    const char *type) {
1217
1218
0
  CHECKCLEARTOWRITE();
1219
0
  buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
1220
0
  buf_putint(ses.writepayload, channel->remotechan);
1221
1222
0
  buf_putstring(ses.writepayload, type, strlen(type));
1223
1224
0
}