changeset 108:10f4d3319780

- 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
author Matt Johnston <matt@ucc.asn.au>
date Thu, 26 Aug 2004 13:16:40 +0000
parents d3eb1fa8484e
children 2e9d1f29c50f
files TODO buffer.c channel.h chansession.h circbuffer.c circbuffer.h cli-chansession.c cli-main.c cli-session.c cli-tcpfwd.c common-channel.c common-session.c dbutil.c includes.h session.h svr-agentfwd.c svr-chansession.c svr-main.c tcpfwd.h
diffstat 19 files changed, 302 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- a/TODO	Tue Aug 24 18:12:18 2004 +0000
+++ b/TODO	Thu Aug 26 13:16:40 2004 +0000
@@ -2,6 +2,8 @@
 
 Things which might need doing:
 
+- exit with returned exit codes?
+
 - errfd needs fixing
 
 - Make options.h generated from configure perhaps?
--- a/buffer.c	Tue Aug 24 18:12:18 2004 +0000
+++ b/buffer.c	Thu Aug 26 13:16:40 2004 +0000
@@ -1,5 +1,5 @@
 /*
- * Dropbear - a SSH2 server
+ * Dropbear SSH
  * 
  * Copyright (c) 2002,2003 Matt Johnston
  * All rights reserved.
--- a/channel.h	Tue Aug 24 18:12:18 2004 +0000
+++ b/channel.h	Thu Aug 26 13:16:40 2004 +0000
@@ -45,16 +45,15 @@
 /* Not a real type */
 #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 */
 
 #define CHAN_EXTEND_SIZE 3 /* how many extra slots to add when we need more */
 
-#define RECV_MAXWINDOW 6000 /* tweak */
-#define RECV_WINDOWEXTEND (RECV_MAXWINDOW/2) /* We send a "window extend" every
-												RECV_WINDOWEXTEND bytes */
-#define RECV_MAXPACKET 1400 /* tweak */
-#define RECV_MINWINDOW 19000 /* when we get below this, we send a windowadjust */
+#define RECV_MAXWINDOW 4000 /* tweak */
+#define RECV_WINDOWEXTEND 500 /* We send a "window extend" every
+								RECV_WINDOWEXTEND bytes */
+#define RECV_MAXPACKET RECV_MAXWINDOW /* tweak */
 
 struct ChanType;
 
@@ -63,6 +62,7 @@
 	unsigned int index; /* the local channel index */
 	unsigned int remotechan;
 	unsigned int recvwindow, transwindow;
+	unsigned int recvdonelen;
 	unsigned int recvmaxpacket, transmaxpacket;
 	void* typedata; /* a pointer to type specific data */
 	int infd; /* data to send over the wire */
--- a/chansession.h	Tue Aug 24 18:12:18 2004 +0000
+++ b/chansession.h	Thu Aug 26 13:16:40 2004 +0000
@@ -68,11 +68,6 @@
 };
 
 
-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 cli_send_chansess_request();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/circbuffer.c	Thu Aug 26 13:16:40 2004 +0000
@@ -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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/circbuffer.h	Thu Aug 26 13:16:40 2004 +0000
@@ -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
--- a/cli-chansession.c	Tue Aug 24 18:12:18 2004 +0000
+++ b/cli-chansession.c	Thu Aug 26 13:16:40 2004 +0000
@@ -32,9 +32,11 @@
 #include "ssh.h"
 #include "runopts.h"
 #include "termcodes.h"
+#include "chansession.h"
 
 static void cli_closechansess(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);
 
@@ -42,19 +44,43 @@
 static void send_chansess_shell_req(struct Channel *channel);
 
 static void cli_tty_setup();
-void cli_tty_cleanup();
 
 const struct ChanType clichansess = {
 	0, /* sepfds */
 	"session", /* name */
 	cli_initchansess, /* inithandler */
 	NULL, /* checkclosehandler */
-	NULL, /* reqhandler */
+	cli_chansessreq, /* reqhandler */
 	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 */
-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 */
 	if (ses.chancount > 1) {
@@ -228,7 +254,7 @@
 
 }
 
-static void sigwinch_handler(int dummy) {
+static void sigwinch_handler(int UNUSED(unused)) {
 
 	cli_ses.winchange = 1;
 
@@ -317,7 +343,7 @@
 	channel->infd = STDOUT_FILENO;
 	channel->outfd = STDIN_FILENO;
 	channel->errfd = STDERR_FILENO;
-	channel->extrabuf = buf_new(RECV_MAXWINDOW);
+	channel->extrabuf = cbuf_new(RECV_MAXWINDOW);
 
 	if (cli_opts.wantpty) {
 		send_chansess_pty_req(channel);
--- a/cli-main.c	Tue Aug 24 18:12:18 2004 +0000
+++ b/cli-main.c	Thu Aug 26 13:16:40 2004 +0000
@@ -96,7 +96,8 @@
 	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];
 
--- a/cli-session.c	Tue Aug 24 18:12:18 2004 +0000
+++ b/cli-session.c	Thu Aug 26 13:16:40 2004 +0000
@@ -118,6 +118,9 @@
 	cli_ses.stdincopy = dup(STDIN_FILENO);
 	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 */
 	cli_ses.lastpubkey = NULL;
 	cli_ses.lastauthtype = NULL;
@@ -261,7 +264,7 @@
 	common_session_cleanup();
 	fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
 			cli_opts.remotehost, cli_opts.remoteport);
-	exit(EXIT_SUCCESS);
+	exit(cli_ses.retval);
 }
 
 
--- a/cli-tcpfwd.c	Tue Aug 24 18:12:18 2004 +0000
+++ b/cli-tcpfwd.c	Thu Aug 26 13:16:40 2004 +0000
@@ -89,7 +89,7 @@
 				remoteport));
 
 	tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*));
-	tcpinfo->sendaddr = remoteaddr;
+	tcpinfo->sendaddr = m_strdup(remoteaddr);
 	tcpinfo->sendport = remoteport;
 	tcpinfo->listenport = listenport;
 	tcpinfo->chantype = &cli_chan_tcplocal;
--- a/common-channel.c	Tue Aug 24 18:12:18 2004 +0000
+++ b/common-channel.c	Thu Aug 26 13:16:40 2004 +0000
@@ -40,7 +40,7 @@
 static void send_msg_channel_open_confirmation(struct Channel* channel,
 		unsigned int recvwindow, 
 		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, 
 		unsigned int incr);
 static void send_msg_channel_data(struct Channel *channel, int isextended,
@@ -151,6 +151,7 @@
 	newchan->writebuf = cbuf_new(RECV_MAXWINDOW);
 	newchan->extrabuf = NULL; /* The user code can set it up */
 	newchan->recvwindow = RECV_MAXWINDOW;
+	newchan->recvdonelen = 0;
 	newchan->recvmaxpacket = RECV_MAXPACKET;
 
 	ses.channels[i] = newchan;
@@ -220,7 +221,13 @@
 				continue; /* Important not to use the channel after
 							 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 */
@@ -350,33 +357,30 @@
 /* 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
  * possible */
-static void writechannel(struct Channel* channel) {
+static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
 
 	int len, maxlen;
-	circbuffer *cbuf;
 
 	TRACE(("enter writechannel"));
 
-	cbuf = channel->writebuf;
 	maxlen = cbuf_readlen(cbuf);
 
-	TRACE(("maxlen = %d", maxlen));
-
 	/* 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 && 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);
 		}
 		TRACE(("leave writechannel: len <= 0"));
 		return;
 	}
 
-	TRACE(("len = %d", 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 */
 		closeinfd(channel);
 		return;
@@ -385,12 +389,17 @@
 	}
 
 	/* Window adjust handling */
-	if (channel->recvwindow < (RECV_MAXWINDOW - RECV_WINDOWEXTEND)) {
+	if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
 		/* Set it back to max window */
-		send_msg_channel_window_adjust(channel, RECV_MAXWINDOW -
-				channel->recvwindow);
-		channel->recvwindow = RECV_MAXWINDOW;
+		send_msg_channel_window_adjust(channel, channel->recvdonelen);
+		channel->recvwindow += channel->recvdonelen;
+		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"));
@@ -424,6 +433,8 @@
 
 		/* For checking FD status (ie closure etc) - we don't actually
 		 * 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) {
 			FD_SET(channel->infd, readfd);
 		}
@@ -435,12 +446,10 @@
 				FD_SET(channel->infd, writefd);
 		}
 
-		/*
 		if (channel->extrabuf != NULL && channel->errfd >= 0 
-				&& cbuf_getavail(channel->extrabuf) > 0 ) {
+				&& cbuf_getused(channel->extrabuf) > 0 ) {
 				FD_SET(channel->errfd, writefd);
 		}
-		*/
 
 	} /* foreach channel */
 
@@ -468,7 +477,9 @@
 	}
 
 	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);
 	}
 
@@ -678,36 +689,34 @@
 
 	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);
-	TRACE(("maxdata = %d", 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) {
-		TRACE(("Warning: recv_msg_channel_data: extra data past window"));
-		datalen = maxdata;
+		dropbear_exit("Oversized packet");
 	}
 
-
 	/* 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
 	 * is payload data */
 	len = datalen;
 	while (len > 0) {
 		buflen = cbuf_writelen(cbuf);
-		TRACE(("buflen = %d", buflen));
 		buflen = MIN(buflen, len);
-		TRACE(("buflenmin = %d", buflen));
 
 		memcpy(cbuf_writeptr(cbuf, buflen), 
 				buf_getptr(ses.payload, buflen), buflen);
 		cbuf_incrwrite(cbuf, buflen);
+		buf_incrpos(ses.payload, buflen);
 		len -= buflen;
-		TRACE(("len = %d", buflen));
 	}
 
+	assert(channel->recvwindow > datalen);
 	channel->recvwindow -= datalen;
+	assert(channel->recvwindow <= RECV_MAXWINDOW);
 
 	TRACE(("leave recv_msg_channel_data"));
 }
--- a/common-session.c	Tue Aug 24 18:12:18 2004 +0000
+++ b/common-session.c	Thu Aug 26 13:16:40 2004 +0000
@@ -35,6 +35,8 @@
 #include "channel.h"
 #include "atomicio.h"
 
+static void checktimeouts();
+static int ident_readln(int fd, char* buf, int count);
 
 struct sshsession ses; /* GLOBAL */
 
@@ -46,8 +48,6 @@
 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 */
 void common_session_init(int sock, char* remotehost) {
--- a/dbutil.c	Tue Aug 24 18:12:18 2004 +0000
+++ b/dbutil.c	Thu Aug 26 13:16:40 2004 +0000
@@ -111,7 +111,7 @@
 	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) {
 
 	char printbuf[1024];
@@ -146,7 +146,6 @@
 	fprintf(stderr, "TRACE: ");
 	vfprintf(stderr, format, param);
 	fprintf(stderr, "\n");
-	fflush(stderr);
 	va_end(param);
 }
 #endif /* DEBUG_TRACE */
--- a/includes.h	Tue Aug 24 18:12:18 2004 +0000
+++ b/includes.h	Thu Aug 26 13:16:40 2004 +0000
@@ -128,4 +128,14 @@
 #define LOG_AUTHPRIV LOG_AUTH
 #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_ */
--- a/session.h	Tue Aug 24 18:12:18 2004 +0000
+++ b/session.h	Thu Aug 26 13:16:40 2004 +0000
@@ -43,7 +43,6 @@
 void common_session_init(int sock, char* remotehost);
 void session_loop(void(*loophandler)());
 void common_session_cleanup();
-void checktimeouts();
 void session_identification();
 
 
@@ -54,8 +53,6 @@
 
 /* Client */
 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 cleantext(unsigned char* dirtytext);
 
@@ -220,6 +217,8 @@
 	int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
 						 for the last type of auth we tried */
 	struct PubkeyList *lastpubkey;
+
+	int retval; /* What the command exit status was - we emulate it */
 #if 0
 	TODO
 	struct AgentkeyList *agentkeys; /* Keys to use for public-key auth */
--- a/svr-agentfwd.c	Tue Aug 24 18:12:18 2004 +0000
+++ b/svr-agentfwd.c	Thu Aug 26 13:16:40 2004 +0000
@@ -97,7 +97,7 @@
 /* accepts a connection on the forwarded socket and opens a new channel for it
  * back to the client */
 /* 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;
 
--- a/svr-chansession.c	Tue Aug 24 18:12:18 2004 +0000
+++ b/svr-chansession.c	Thu Aug 26 13:16:40 2004 +0000
@@ -55,6 +55,10 @@
 static void chansessionrequest(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 void get_termmodes(struct ChanSess *chansess);
 
@@ -68,7 +72,7 @@
 }
 
 /* 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;
 	pid_t pid;
@@ -498,7 +502,9 @@
 	}
 
 	/* 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) {
 		TRACE(("leave sessionpty: failed to allocate pty"));
 		return DROPBEAR_FAILURE;
--- a/svr-main.c	Tue Aug 24 18:12:18 2004 +0000
+++ b/svr-main.c	Thu Aug 26 13:16:40 2004 +0000
@@ -123,7 +123,6 @@
 	pid_t childpid;
 	int childpipe[2];
 
-	struct sigaction sa_chld;
 	/* fork */
 	if (svr_opts.forkbg) {
 		int closefds = 0;
@@ -303,7 +302,7 @@
 
 
 /* catch + reap zombie children */
-static void sigchld_handler(int fish) {
+static void sigchld_handler(int UNUSED(unused)) {
 	struct sigaction sa_chld;
 
 	while(waitpid(-1, NULL, WNOHANG) > 0); 
@@ -316,14 +315,14 @@
 }
 
 /* catch any segvs */
-static void sigsegv_handler(int fish) {
+static void sigsegv_handler(int UNUSED(unused)) {
 	fprintf(stderr, "Aiee, segfault! You should probably report "
 			"this as a bug to the developer\n");
 	exit(EXIT_FAILURE);
 }
 
 /* catch ctrl-c or sigterm */
-static void sigintterm_handler(int fish) {
+static void sigintterm_handler(int UNUSED(unused)) {
 
 	exitflag = 1;
 }
--- a/tcpfwd.h	Tue Aug 24 18:12:18 2004 +0000
+++ b/tcpfwd.h	Thu Aug 26 13:16:40 2004 +0000
@@ -47,7 +47,7 @@
 /* A link in a list of forwards */
 struct TCPFwdList {
 
-	char* connectaddr;
+	const unsigned char* connectaddr;
 	unsigned int connectport;
 	unsigned int listenport;
 	struct TCPFwdList * next;
@@ -60,6 +60,7 @@
 
 /* Client */
 void setup_localtcp();
+void setup_remotetcp();
 extern const struct ChanType cli_chan_tcpremote;
 
 /* Common */