mirror of
https://github.com/clearml/dropbear
synced 2025-03-12 14:48:34 +00:00
- added circular buffering for channels
- added stderr support for the client - cleaned up a bunch of "unused" warnings, duplicated header definitions - added exit-status support for the client --HG-- extra : convert_revision : 5bdf806d8b440c87f7235414662f4189195618f4
This commit is contained in:
parent
2dcd6b22d9
commit
51a74b4799
2
TODO
2
TODO
@ -2,6 +2,8 @@ Current:
|
|||||||
|
|
||||||
Things which might need doing:
|
Things which might need doing:
|
||||||
|
|
||||||
|
- exit with returned exit codes?
|
||||||
|
|
||||||
- errfd needs fixing
|
- errfd needs fixing
|
||||||
|
|
||||||
- Make options.h generated from configure perhaps?
|
- Make options.h generated from configure perhaps?
|
||||||
|
2
buffer.c
2
buffer.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Dropbear - a SSH2 server
|
* Dropbear SSH
|
||||||
*
|
*
|
||||||
* Copyright (c) 2002,2003 Matt Johnston
|
* Copyright (c) 2002,2003 Matt Johnston
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
12
channel.h
12
channel.h
@ -45,16 +45,15 @@
|
|||||||
/* Not a real type */
|
/* Not a real type */
|
||||||
#define SSH_OPEN_IN_PROGRESS 99
|
#define SSH_OPEN_IN_PROGRESS 99
|
||||||
|
|
||||||
#define MAX_CHANNELS 60 /* simple mem restriction, includes each tcp/x11
|
#define MAX_CHANNELS 100 /* simple mem restriction, includes each tcp/x11
|
||||||
connection, so can't be _too_ small */
|
connection, so can't be _too_ small */
|
||||||
|
|
||||||
#define CHAN_EXTEND_SIZE 3 /* how many extra slots to add when we need more */
|
#define CHAN_EXTEND_SIZE 3 /* how many extra slots to add when we need more */
|
||||||
|
|
||||||
#define RECV_MAXWINDOW 6000 /* tweak */
|
#define RECV_MAXWINDOW 4000 /* tweak */
|
||||||
#define RECV_WINDOWEXTEND (RECV_MAXWINDOW/2) /* We send a "window extend" every
|
#define RECV_WINDOWEXTEND 500 /* We send a "window extend" every
|
||||||
RECV_WINDOWEXTEND bytes */
|
RECV_WINDOWEXTEND bytes */
|
||||||
#define RECV_MAXPACKET 1400 /* tweak */
|
#define RECV_MAXPACKET RECV_MAXWINDOW /* tweak */
|
||||||
#define RECV_MINWINDOW 19000 /* when we get below this, we send a windowadjust */
|
|
||||||
|
|
||||||
struct ChanType;
|
struct ChanType;
|
||||||
|
|
||||||
@ -63,6 +62,7 @@ struct Channel {
|
|||||||
unsigned int index; /* the local channel index */
|
unsigned int index; /* the local channel index */
|
||||||
unsigned int remotechan;
|
unsigned int remotechan;
|
||||||
unsigned int recvwindow, transwindow;
|
unsigned int recvwindow, transwindow;
|
||||||
|
unsigned int recvdonelen;
|
||||||
unsigned int recvmaxpacket, transmaxpacket;
|
unsigned int recvmaxpacket, transmaxpacket;
|
||||||
void* typedata; /* a pointer to type specific data */
|
void* typedata; /* a pointer to type specific data */
|
||||||
int infd; /* data to send over the wire */
|
int infd; /* data to send over the wire */
|
||||||
|
@ -68,11 +68,6 @@ struct ChildPid {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void chansessionrequest(struct Channel * channel);
|
|
||||||
void send_msg_chansess_exitstatus(struct Channel * channel,
|
|
||||||
struct ChanSess * chansess);
|
|
||||||
void send_msg_chansess_exitsignal(struct Channel * channel,
|
|
||||||
struct ChanSess * chansess);
|
|
||||||
void addnewvar(const char* param, const char* var);
|
void addnewvar(const char* param, const char* var);
|
||||||
|
|
||||||
void cli_send_chansess_request();
|
void cli_send_chansess_request();
|
||||||
|
138
circbuffer.c
Normal file
138
circbuffer.c
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Dropbear SSH
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2004 Matt Johnston
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE. */
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
#include "dbutil.h"
|
||||||
|
#include "circbuffer.h"
|
||||||
|
|
||||||
|
#define MAX_CBUF_SIZE 100000000
|
||||||
|
|
||||||
|
circbuffer * cbuf_new(unsigned int size) {
|
||||||
|
|
||||||
|
circbuffer *cbuf = NULL;
|
||||||
|
|
||||||
|
if (size > MAX_CBUF_SIZE) {
|
||||||
|
dropbear_exit("bad cbuf size");
|
||||||
|
}
|
||||||
|
|
||||||
|
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
|
||||||
|
cbuf->data = (unsigned char*)m_malloc(size);
|
||||||
|
cbuf->used = 0;
|
||||||
|
cbuf->readpos = 0;
|
||||||
|
cbuf->writepos = 0;
|
||||||
|
cbuf->size = size;
|
||||||
|
|
||||||
|
return cbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cbuf_free(circbuffer * cbuf) {
|
||||||
|
|
||||||
|
m_free(cbuf->data);
|
||||||
|
m_free(cbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int cbuf_getused(circbuffer * cbuf) {
|
||||||
|
|
||||||
|
return cbuf->used;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int cbuf_getavail(circbuffer * cbuf) {
|
||||||
|
|
||||||
|
return cbuf->size - cbuf->used;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int cbuf_readlen(circbuffer *cbuf) {
|
||||||
|
|
||||||
|
assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
|
||||||
|
assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
|
||||||
|
|
||||||
|
if (cbuf->used == 0) {
|
||||||
|
TRACE(("cbuf_readlen: unused buffer"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cbuf->readpos < cbuf->writepos) {
|
||||||
|
return cbuf->writepos - cbuf->readpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cbuf->size - cbuf->readpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int cbuf_writelen(circbuffer *cbuf) {
|
||||||
|
|
||||||
|
assert(cbuf->used <= cbuf->size);
|
||||||
|
assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
|
||||||
|
assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
|
||||||
|
|
||||||
|
if (cbuf->used == cbuf->size) {
|
||||||
|
TRACE(("cbuf_writelen: full buffer"));
|
||||||
|
return 0; /* full */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cbuf->writepos < cbuf->readpos) {
|
||||||
|
return cbuf->readpos - cbuf->writepos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cbuf->size - cbuf->writepos;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
|
||||||
|
if (len > cbuf_readlen(cbuf)) {
|
||||||
|
dropbear_exit("bad cbuf read");
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cbuf->data[cbuf->readpos];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
|
||||||
|
|
||||||
|
if (len > cbuf_writelen(cbuf)) {
|
||||||
|
dropbear_exit("bad cbuf write");
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cbuf->data[cbuf->writepos];
|
||||||
|
}
|
||||||
|
|
||||||
|
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
|
||||||
|
if (len > cbuf_writelen(cbuf)) {
|
||||||
|
dropbear_exit("bad cbuf write");
|
||||||
|
}
|
||||||
|
|
||||||
|
cbuf->used += len;
|
||||||
|
assert(cbuf->used <= cbuf->size);
|
||||||
|
cbuf->writepos = (cbuf->writepos + len) % cbuf->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
|
||||||
|
if (len > cbuf_readlen(cbuf)) {
|
||||||
|
dropbear_exit("bad cbuf read");
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(cbuf->used >= len);
|
||||||
|
cbuf->used -= len;
|
||||||
|
cbuf->readpos = (cbuf->readpos + len) % cbuf->size;
|
||||||
|
}
|
50
circbuffer.h
Normal file
50
circbuffer.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Dropbear SSH
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2004 Matt Johnston
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE. */
|
||||||
|
|
||||||
|
#ifndef _CIRCBUFFER_H_
|
||||||
|
#define _CIRCBUFFER_H_
|
||||||
|
struct circbuf {
|
||||||
|
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int readpos;
|
||||||
|
unsigned int writepos;
|
||||||
|
unsigned int used;
|
||||||
|
unsigned char* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct circbuf circbuffer;
|
||||||
|
|
||||||
|
circbuffer * cbuf_new(unsigned int size);
|
||||||
|
void cbuf_free(circbuffer * cbuf);
|
||||||
|
|
||||||
|
unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */
|
||||||
|
unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */
|
||||||
|
unsigned int cbuf_readlen(circbuffer *cbuf); /* max linear read len */
|
||||||
|
unsigned int cbuf_writelen(circbuffer *cbuf); /* max linear write len */
|
||||||
|
|
||||||
|
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len);
|
||||||
|
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len);
|
||||||
|
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len);
|
||||||
|
void cbuf_incrread(circbuffer *cbuf, unsigned int len);
|
||||||
|
#endif
|
@ -32,9 +32,11 @@
|
|||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "runopts.h"
|
#include "runopts.h"
|
||||||
#include "termcodes.h"
|
#include "termcodes.h"
|
||||||
|
#include "chansession.h"
|
||||||
|
|
||||||
static void cli_closechansess(struct Channel *channel);
|
static void cli_closechansess(struct Channel *channel);
|
||||||
static int cli_initchansess(struct Channel *channel);
|
static int cli_initchansess(struct Channel *channel);
|
||||||
|
static void cli_chansessreq(struct Channel *channel);
|
||||||
|
|
||||||
static void start_channel_request(struct Channel *channel, unsigned char *type);
|
static void start_channel_request(struct Channel *channel, unsigned char *type);
|
||||||
|
|
||||||
@ -42,19 +44,43 @@ static void send_chansess_pty_req(struct Channel *channel);
|
|||||||
static void send_chansess_shell_req(struct Channel *channel);
|
static void send_chansess_shell_req(struct Channel *channel);
|
||||||
|
|
||||||
static void cli_tty_setup();
|
static void cli_tty_setup();
|
||||||
void cli_tty_cleanup();
|
|
||||||
|
|
||||||
const struct ChanType clichansess = {
|
const struct ChanType clichansess = {
|
||||||
0, /* sepfds */
|
0, /* sepfds */
|
||||||
"session", /* name */
|
"session", /* name */
|
||||||
cli_initchansess, /* inithandler */
|
cli_initchansess, /* inithandler */
|
||||||
NULL, /* checkclosehandler */
|
NULL, /* checkclosehandler */
|
||||||
NULL, /* reqhandler */
|
cli_chansessreq, /* reqhandler */
|
||||||
cli_closechansess, /* closehandler */
|
cli_closechansess, /* closehandler */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void cli_chansessreq(struct Channel *channel) {
|
||||||
|
|
||||||
|
unsigned char* type = NULL;
|
||||||
|
int wantreply;
|
||||||
|
|
||||||
|
TRACE(("enter cli_chansessreq"));
|
||||||
|
|
||||||
|
type = buf_getstring(ses.payload, NULL);
|
||||||
|
wantreply = buf_getbyte(ses.payload);
|
||||||
|
|
||||||
|
if (strcmp(type, "exit-status") != 0) {
|
||||||
|
TRACE(("unknown request '%s'", type));
|
||||||
|
send_msg_channel_failure(channel);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We'll just trust what they tell us */
|
||||||
|
cli_ses.retval = buf_getint(ses.payload);
|
||||||
|
TRACE(("got exit-status of '%d'", cli_ses.retval));
|
||||||
|
|
||||||
|
out:
|
||||||
|
m_free(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* If the main session goes, we close it up */
|
/* If the main session goes, we close it up */
|
||||||
static void cli_closechansess(struct Channel *channel) {
|
static void cli_closechansess(struct Channel *UNUSED(channel)) {
|
||||||
|
|
||||||
/* This channel hasn't gone yet, so we have > 1 */
|
/* This channel hasn't gone yet, so we have > 1 */
|
||||||
if (ses.chancount > 1) {
|
if (ses.chancount > 1) {
|
||||||
@ -228,7 +254,7 @@ static void put_winsize() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sigwinch_handler(int dummy) {
|
static void sigwinch_handler(int UNUSED(unused)) {
|
||||||
|
|
||||||
cli_ses.winchange = 1;
|
cli_ses.winchange = 1;
|
||||||
|
|
||||||
@ -317,7 +343,7 @@ static int cli_initchansess(struct Channel *channel) {
|
|||||||
channel->infd = STDOUT_FILENO;
|
channel->infd = STDOUT_FILENO;
|
||||||
channel->outfd = STDIN_FILENO;
|
channel->outfd = STDIN_FILENO;
|
||||||
channel->errfd = STDERR_FILENO;
|
channel->errfd = STDERR_FILENO;
|
||||||
channel->extrabuf = buf_new(RECV_MAXWINDOW);
|
channel->extrabuf = cbuf_new(RECV_MAXWINDOW);
|
||||||
|
|
||||||
if (cli_opts.wantpty) {
|
if (cli_opts.wantpty) {
|
||||||
send_chansess_pty_req(channel);
|
send_chansess_pty_req(channel);
|
||||||
|
@ -96,7 +96,8 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
|||||||
exit(exitcode);
|
exit(exitcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cli_dropbear_log(int priority, const char* format, va_list param) {
|
static void cli_dropbear_log(int UNUSED(priority),
|
||||||
|
const char* format, va_list param) {
|
||||||
|
|
||||||
char printbuf[1024];
|
char printbuf[1024];
|
||||||
|
|
||||||
|
@ -118,6 +118,9 @@ static void cli_session_init() {
|
|||||||
cli_ses.stdincopy = dup(STDIN_FILENO);
|
cli_ses.stdincopy = dup(STDIN_FILENO);
|
||||||
cli_ses.stdinflags = fcntl(STDIN_FILENO, F_GETFL, 0);
|
cli_ses.stdinflags = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||||
|
|
||||||
|
cli_ses.retval = EXIT_SUCCESS; /* Assume it's clean if we don't get a
|
||||||
|
specific exit status */
|
||||||
|
|
||||||
/* Auth */
|
/* Auth */
|
||||||
cli_ses.lastpubkey = NULL;
|
cli_ses.lastpubkey = NULL;
|
||||||
cli_ses.lastauthtype = NULL;
|
cli_ses.lastauthtype = NULL;
|
||||||
@ -261,7 +264,7 @@ static void cli_finished() {
|
|||||||
common_session_cleanup();
|
common_session_cleanup();
|
||||||
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
|
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
|
||||||
cli_opts.remotehost, cli_opts.remoteport);
|
cli_opts.remotehost, cli_opts.remoteport);
|
||||||
exit(EXIT_SUCCESS);
|
exit(cli_ses.retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
|
|||||||
remoteport));
|
remoteport));
|
||||||
|
|
||||||
tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*));
|
tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*));
|
||||||
tcpinfo->sendaddr = remoteaddr;
|
tcpinfo->sendaddr = m_strdup(remoteaddr);
|
||||||
tcpinfo->sendport = remoteport;
|
tcpinfo->sendport = remoteport;
|
||||||
tcpinfo->listenport = listenport;
|
tcpinfo->listenport = listenport;
|
||||||
tcpinfo->chantype = &cli_chan_tcplocal;
|
tcpinfo->chantype = &cli_chan_tcplocal;
|
||||||
|
@ -40,7 +40,7 @@ static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
|
|||||||
static void send_msg_channel_open_confirmation(struct Channel* channel,
|
static void send_msg_channel_open_confirmation(struct Channel* channel,
|
||||||
unsigned int recvwindow,
|
unsigned int recvwindow,
|
||||||
unsigned int recvmaxpacket);
|
unsigned int recvmaxpacket);
|
||||||
static void writechannel(struct Channel *channel);
|
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf);
|
||||||
static void send_msg_channel_window_adjust(struct Channel *channel,
|
static void send_msg_channel_window_adjust(struct Channel *channel,
|
||||||
unsigned int incr);
|
unsigned int incr);
|
||||||
static void send_msg_channel_data(struct Channel *channel, int isextended,
|
static void send_msg_channel_data(struct Channel *channel, int isextended,
|
||||||
@ -151,6 +151,7 @@ struct Channel* newchannel(unsigned int remotechan,
|
|||||||
newchan->writebuf = cbuf_new(RECV_MAXWINDOW);
|
newchan->writebuf = cbuf_new(RECV_MAXWINDOW);
|
||||||
newchan->extrabuf = NULL; /* The user code can set it up */
|
newchan->extrabuf = NULL; /* The user code can set it up */
|
||||||
newchan->recvwindow = RECV_MAXWINDOW;
|
newchan->recvwindow = RECV_MAXWINDOW;
|
||||||
|
newchan->recvdonelen = 0;
|
||||||
newchan->recvmaxpacket = RECV_MAXPACKET;
|
newchan->recvmaxpacket = RECV_MAXPACKET;
|
||||||
|
|
||||||
ses.channels[i] = newchan;
|
ses.channels[i] = newchan;
|
||||||
@ -220,7 +221,13 @@ void channelio(fd_set *readfd, fd_set *writefd) {
|
|||||||
continue; /* Important not to use the channel after
|
continue; /* Important not to use the channel after
|
||||||
checkinitdone(), as it may be NULL */
|
checkinitdone(), as it may be NULL */
|
||||||
}
|
}
|
||||||
writechannel(channel);
|
writechannel(channel, channel->infd, channel->writebuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stderr for client mode */
|
||||||
|
if (channel->extrabuf != NULL
|
||||||
|
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefd)) {
|
||||||
|
writechannel(channel, channel->errfd, channel->extrabuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now handle any of the channel-closing type stuff */
|
/* now handle any of the channel-closing type stuff */
|
||||||
@ -350,33 +357,30 @@ static void send_msg_channel_eof(struct Channel *channel) {
|
|||||||
/* Called to write data out to the local side of the channel.
|
/* Called to write data out to the local side of the channel.
|
||||||
* Only called when we know we can write to a channel, writes as much as
|
* Only called when we know we can write to a channel, writes as much as
|
||||||
* possible */
|
* possible */
|
||||||
static void writechannel(struct Channel* channel) {
|
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
|
||||||
|
|
||||||
int len, maxlen;
|
int len, maxlen;
|
||||||
circbuffer *cbuf;
|
|
||||||
|
|
||||||
TRACE(("enter writechannel"));
|
TRACE(("enter writechannel"));
|
||||||
|
|
||||||
cbuf = channel->writebuf;
|
|
||||||
maxlen = cbuf_readlen(cbuf);
|
maxlen = cbuf_readlen(cbuf);
|
||||||
|
|
||||||
TRACE(("maxlen = %d", maxlen));
|
|
||||||
|
|
||||||
/* Write the data out */
|
/* Write the data out */
|
||||||
len = write(channel->infd, cbuf_readptr(cbuf, maxlen), maxlen);
|
len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
if (len < 0 && errno != EINTR) {
|
if (len < 0 && errno != EINTR) {
|
||||||
/* no more to write */
|
/* no more to write - we close it even if the fd was stderr, since
|
||||||
|
* that's a nasty failure too */
|
||||||
closeinfd(channel);
|
closeinfd(channel);
|
||||||
}
|
}
|
||||||
TRACE(("leave writechannel: len <= 0"));
|
TRACE(("leave writechannel: len <= 0"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE(("len = %d", len));
|
|
||||||
cbuf_incrread(cbuf, len);
|
cbuf_incrread(cbuf, len);
|
||||||
|
channel->recvdonelen += len;
|
||||||
|
|
||||||
if (len == maxlen && channel->recveof) {
|
if (fd == channel->infd && len == maxlen && channel->recveof) {
|
||||||
/* Check if we're closing up */
|
/* Check if we're closing up */
|
||||||
closeinfd(channel);
|
closeinfd(channel);
|
||||||
return;
|
return;
|
||||||
@ -385,13 +389,18 @@ static void writechannel(struct Channel* channel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Window adjust handling */
|
/* Window adjust handling */
|
||||||
if (channel->recvwindow < (RECV_MAXWINDOW - RECV_WINDOWEXTEND)) {
|
if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
|
||||||
/* Set it back to max window */
|
/* Set it back to max window */
|
||||||
send_msg_channel_window_adjust(channel, RECV_MAXWINDOW -
|
send_msg_channel_window_adjust(channel, channel->recvdonelen);
|
||||||
channel->recvwindow);
|
channel->recvwindow += channel->recvdonelen;
|
||||||
channel->recvwindow = RECV_MAXWINDOW;
|
channel->recvdonelen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(channel->recvwindow <= RECV_MAXWINDOW);
|
||||||
|
assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
|
||||||
|
assert(channel->extrabuf == NULL ||
|
||||||
|
channel->recvwindow <= cbuf_getavail(channel->extrabuf));
|
||||||
|
|
||||||
|
|
||||||
TRACE(("leave writechannel"));
|
TRACE(("leave writechannel"));
|
||||||
}
|
}
|
||||||
@ -424,6 +433,8 @@ void setchannelfds(fd_set *readfd, fd_set *writefd) {
|
|||||||
|
|
||||||
/* For checking FD status (ie closure etc) - we don't actually
|
/* For checking FD status (ie closure etc) - we don't actually
|
||||||
* read data from infd */
|
* read data from infd */
|
||||||
|
TRACE(("infd = %d, outfd %d, bufused %d", channel->infd, channel->outfd,
|
||||||
|
cbuf_getused(channel->writebuf) ));
|
||||||
if (channel->infd >= 0 && channel->infd != channel->outfd) {
|
if (channel->infd >= 0 && channel->infd != channel->outfd) {
|
||||||
FD_SET(channel->infd, readfd);
|
FD_SET(channel->infd, readfd);
|
||||||
}
|
}
|
||||||
@ -435,12 +446,10 @@ void setchannelfds(fd_set *readfd, fd_set *writefd) {
|
|||||||
FD_SET(channel->infd, writefd);
|
FD_SET(channel->infd, writefd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if (channel->extrabuf != NULL && channel->errfd >= 0
|
if (channel->extrabuf != NULL && channel->errfd >= 0
|
||||||
&& cbuf_getavail(channel->extrabuf) > 0 ) {
|
&& cbuf_getused(channel->extrabuf) > 0 ) {
|
||||||
FD_SET(channel->errfd, writefd);
|
FD_SET(channel->errfd, writefd);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
} /* foreach channel */
|
} /* foreach channel */
|
||||||
|
|
||||||
@ -468,7 +477,9 @@ void recv_msg_channel_eof() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
channel->recveof = 1;
|
channel->recveof = 1;
|
||||||
if (cbuf_getused(channel->writebuf) == 0) {
|
if (cbuf_getused(channel->writebuf) == 0
|
||||||
|
&& (channel->extrabuf == NULL
|
||||||
|
|| cbuf_getused(channel->extrabuf) == 0)) {
|
||||||
closeinfd(channel);
|
closeinfd(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,17 +689,15 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
|
|||||||
|
|
||||||
datalen = buf_getint(ses.payload);
|
datalen = buf_getint(ses.payload);
|
||||||
|
|
||||||
TRACE(("datalen = %d", datalen));
|
|
||||||
|
|
||||||
/* if the client is going to send us more data than we've allocated, then
|
|
||||||
* it has ignored the windowsize, so we "MAY ignore all extra data" */
|
|
||||||
maxdata = cbuf_getavail(cbuf);
|
maxdata = cbuf_getavail(cbuf);
|
||||||
TRACE(("maxdata = %d", maxdata));
|
|
||||||
if (datalen > maxdata) {
|
|
||||||
TRACE(("Warning: recv_msg_channel_data: extra data past window"));
|
|
||||||
datalen = maxdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Whilst the spec says we "MAY ignore data past the end" this could
|
||||||
|
* lead to corrupted file transfers etc (chunks missed etc). It's better to
|
||||||
|
* just die horribly */
|
||||||
|
if (datalen > maxdata) {
|
||||||
|
dropbear_exit("Oversized packet");
|
||||||
|
}
|
||||||
|
|
||||||
/* We may have to run throught twice, if the buffer wraps around. Can't
|
/* We may have to run throught twice, if the buffer wraps around. Can't
|
||||||
* just "leave it for next time" like with writechannel, since this
|
* just "leave it for next time" like with writechannel, since this
|
||||||
@ -696,18 +705,18 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
|
|||||||
len = datalen;
|
len = datalen;
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
buflen = cbuf_writelen(cbuf);
|
buflen = cbuf_writelen(cbuf);
|
||||||
TRACE(("buflen = %d", buflen));
|
|
||||||
buflen = MIN(buflen, len);
|
buflen = MIN(buflen, len);
|
||||||
TRACE(("buflenmin = %d", buflen));
|
|
||||||
|
|
||||||
memcpy(cbuf_writeptr(cbuf, buflen),
|
memcpy(cbuf_writeptr(cbuf, buflen),
|
||||||
buf_getptr(ses.payload, buflen), buflen);
|
buf_getptr(ses.payload, buflen), buflen);
|
||||||
cbuf_incrwrite(cbuf, buflen);
|
cbuf_incrwrite(cbuf, buflen);
|
||||||
|
buf_incrpos(ses.payload, buflen);
|
||||||
len -= buflen;
|
len -= buflen;
|
||||||
TRACE(("len = %d", buflen));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(channel->recvwindow > datalen);
|
||||||
channel->recvwindow -= datalen;
|
channel->recvwindow -= datalen;
|
||||||
|
assert(channel->recvwindow <= RECV_MAXWINDOW);
|
||||||
|
|
||||||
TRACE(("leave recv_msg_channel_data"));
|
TRACE(("leave recv_msg_channel_data"));
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
#include "channel.h"
|
#include "channel.h"
|
||||||
#include "atomicio.h"
|
#include "atomicio.h"
|
||||||
|
|
||||||
|
static void checktimeouts();
|
||||||
|
static int ident_readln(int fd, char* buf, int count);
|
||||||
|
|
||||||
struct sshsession ses; /* GLOBAL */
|
struct sshsession ses; /* GLOBAL */
|
||||||
|
|
||||||
@ -46,8 +48,6 @@ int sessinitdone = 0; /* GLOBAL */
|
|||||||
int exitflag = 0; /* GLOBAL */
|
int exitflag = 0; /* GLOBAL */
|
||||||
|
|
||||||
|
|
||||||
static void checktimeouts();
|
|
||||||
static int ident_readln(int fd, char* buf, int count);
|
|
||||||
|
|
||||||
/* called only at the start of a session, set up initial state */
|
/* called only at the start of a session, set up initial state */
|
||||||
void common_session_init(int sock, char* remotehost) {
|
void common_session_init(int sock, char* remotehost) {
|
||||||
|
3
dbutil.c
3
dbutil.c
@ -111,7 +111,7 @@ static void generic_dropbear_exit(int exitcode, const char* format,
|
|||||||
exit(exitcode);
|
exit(exitcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generic_dropbear_log(int priority, const char* format,
|
static void generic_dropbear_log(int UNUSED(priority), const char* format,
|
||||||
va_list param) {
|
va_list param) {
|
||||||
|
|
||||||
char printbuf[1024];
|
char printbuf[1024];
|
||||||
@ -146,7 +146,6 @@ void dropbear_trace(const char* format, ...) {
|
|||||||
fprintf(stderr, "TRACE: ");
|
fprintf(stderr, "TRACE: ");
|
||||||
vfprintf(stderr, format, param);
|
vfprintf(stderr, format, param);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
fflush(stderr);
|
|
||||||
va_end(param);
|
va_end(param);
|
||||||
}
|
}
|
||||||
#endif /* DEBUG_TRACE */
|
#endif /* DEBUG_TRACE */
|
||||||
|
10
includes.h
10
includes.h
@ -128,4 +128,14 @@ typedef u_int16_t uint16_t;
|
|||||||
#define LOG_AUTHPRIV LOG_AUTH
|
#define LOG_AUTHPRIV LOG_AUTH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* so we can avoid warnings about unused params (ie in signal handlers etc) */
|
||||||
|
#ifdef UNUSED
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
|
||||||
|
#elif defined(__LCLINT__)
|
||||||
|
# define UNUSED(x) /*@unused@*/ x
|
||||||
|
#else
|
||||||
|
# define UNUSED(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _INCLUDES_H_ */
|
#endif /* _INCLUDES_H_ */
|
||||||
|
@ -43,7 +43,6 @@ extern int exitflag;
|
|||||||
void common_session_init(int sock, char* remotehost);
|
void common_session_init(int sock, char* remotehost);
|
||||||
void session_loop(void(*loophandler)());
|
void session_loop(void(*loophandler)());
|
||||||
void common_session_cleanup();
|
void common_session_cleanup();
|
||||||
void checktimeouts();
|
|
||||||
void session_identification();
|
void session_identification();
|
||||||
|
|
||||||
|
|
||||||
@ -54,8 +53,6 @@ void svr_dropbear_log(int priority, const char* format, va_list param);
|
|||||||
|
|
||||||
/* Client */
|
/* Client */
|
||||||
void cli_session(int sock, char *remotehost);
|
void cli_session(int sock, char *remotehost);
|
||||||
void cli_dropbear_exit(int exitcode, const char* format, va_list param);
|
|
||||||
void cli_dropbear_log(int priority, const char* format, va_list param);
|
|
||||||
void cli_session_cleanup();
|
void cli_session_cleanup();
|
||||||
void cleantext(unsigned char* dirtytext);
|
void cleantext(unsigned char* dirtytext);
|
||||||
|
|
||||||
@ -220,6 +217,8 @@ struct clientsession {
|
|||||||
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
|
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
|
||||||
for the last type of auth we tried */
|
for the last type of auth we tried */
|
||||||
struct PubkeyList *lastpubkey;
|
struct PubkeyList *lastpubkey;
|
||||||
|
|
||||||
|
int retval; /* What the command exit status was - we emulate it */
|
||||||
#if 0
|
#if 0
|
||||||
TODO
|
TODO
|
||||||
struct AgentkeyList *agentkeys; /* Keys to use for public-key auth */
|
struct AgentkeyList *agentkeys; /* Keys to use for public-key auth */
|
||||||
|
@ -97,7 +97,7 @@ fail:
|
|||||||
/* accepts a connection on the forwarded socket and opens a new channel for it
|
/* accepts a connection on the forwarded socket and opens a new channel for it
|
||||||
* back to the client */
|
* back to the client */
|
||||||
/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||||
static void agentaccept(struct Listener * listener, int sock) {
|
static void agentaccept(struct Listener *UNUSED(listener), int sock) {
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
@ -55,6 +55,10 @@ static int newchansess(struct Channel *channel);
|
|||||||
static void chansessionrequest(struct Channel *channel);
|
static void chansessionrequest(struct Channel *channel);
|
||||||
|
|
||||||
static void send_exitsignalstatus(struct Channel *channel);
|
static void send_exitsignalstatus(struct Channel *channel);
|
||||||
|
static void send_msg_chansess_exitstatus(struct Channel * channel,
|
||||||
|
struct ChanSess * chansess);
|
||||||
|
static void send_msg_chansess_exitsignal(struct Channel * channel,
|
||||||
|
struct ChanSess * chansess);
|
||||||
static int sesscheckclose(struct Channel *channel);
|
static int sesscheckclose(struct Channel *channel);
|
||||||
static void get_termmodes(struct ChanSess *chansess);
|
static void get_termmodes(struct ChanSess *chansess);
|
||||||
|
|
||||||
@ -68,7 +72,7 @@ static int sesscheckclose(struct Channel *channel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* handler for childs exiting, store the state for return to the client */
|
/* handler for childs exiting, store the state for return to the client */
|
||||||
static void sesssigchild_handler(int dummy) {
|
static void sesssigchild_handler(int UNUSED(dummy)) {
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
@ -498,7 +502,9 @@ static int sessionpty(struct ChanSess * chansess) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* allocate the pty */
|
/* allocate the pty */
|
||||||
assert(chansess->master == -1); /* haven't already got one */
|
if (chansess->master != -1) {
|
||||||
|
dropbear_exit("multiple pty requests");
|
||||||
|
}
|
||||||
if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) {
|
if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) {
|
||||||
TRACE(("leave sessionpty: failed to allocate pty"));
|
TRACE(("leave sessionpty: failed to allocate pty"));
|
||||||
return DROPBEAR_FAILURE;
|
return DROPBEAR_FAILURE;
|
||||||
|
@ -123,7 +123,6 @@ void main_noinetd() {
|
|||||||
pid_t childpid;
|
pid_t childpid;
|
||||||
int childpipe[2];
|
int childpipe[2];
|
||||||
|
|
||||||
struct sigaction sa_chld;
|
|
||||||
/* fork */
|
/* fork */
|
||||||
if (svr_opts.forkbg) {
|
if (svr_opts.forkbg) {
|
||||||
int closefds = 0;
|
int closefds = 0;
|
||||||
@ -303,7 +302,7 @@ void main_noinetd() {
|
|||||||
|
|
||||||
|
|
||||||
/* catch + reap zombie children */
|
/* catch + reap zombie children */
|
||||||
static void sigchld_handler(int fish) {
|
static void sigchld_handler(int UNUSED(unused)) {
|
||||||
struct sigaction sa_chld;
|
struct sigaction sa_chld;
|
||||||
|
|
||||||
while(waitpid(-1, NULL, WNOHANG) > 0);
|
while(waitpid(-1, NULL, WNOHANG) > 0);
|
||||||
@ -316,14 +315,14 @@ static void sigchld_handler(int fish) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* catch any segvs */
|
/* catch any segvs */
|
||||||
static void sigsegv_handler(int fish) {
|
static void sigsegv_handler(int UNUSED(unused)) {
|
||||||
fprintf(stderr, "Aiee, segfault! You should probably report "
|
fprintf(stderr, "Aiee, segfault! You should probably report "
|
||||||
"this as a bug to the developer\n");
|
"this as a bug to the developer\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* catch ctrl-c or sigterm */
|
/* catch ctrl-c or sigterm */
|
||||||
static void sigintterm_handler(int fish) {
|
static void sigintterm_handler(int UNUSED(unused)) {
|
||||||
|
|
||||||
exitflag = 1;
|
exitflag = 1;
|
||||||
}
|
}
|
||||||
|
3
tcpfwd.h
3
tcpfwd.h
@ -47,7 +47,7 @@ struct TCPListener {
|
|||||||
/* A link in a list of forwards */
|
/* A link in a list of forwards */
|
||||||
struct TCPFwdList {
|
struct TCPFwdList {
|
||||||
|
|
||||||
char* connectaddr;
|
const unsigned char* connectaddr;
|
||||||
unsigned int connectport;
|
unsigned int connectport;
|
||||||
unsigned int listenport;
|
unsigned int listenport;
|
||||||
struct TCPFwdList * next;
|
struct TCPFwdList * next;
|
||||||
@ -60,6 +60,7 @@ extern const struct ChanType svr_chan_tcpdirect;
|
|||||||
|
|
||||||
/* Client */
|
/* Client */
|
||||||
void setup_localtcp();
|
void setup_localtcp();
|
||||||
|
void setup_remotetcp();
|
||||||
extern const struct ChanType cli_chan_tcpremote;
|
extern const struct ChanType cli_chan_tcpremote;
|
||||||
|
|
||||||
/* Common */
|
/* Common */
|
||||||
|
Loading…
Reference in New Issue
Block a user