changeset 30:223b0f5f8dce

Switching to the magical new Makefile, and new dbmulti style
author Matt Johnston <matt@ucc.asn.au>
date Tue, 27 Jul 2004 14:44:43 +0000
parents 0fcf63e1cb01
children 3c2066e196a9
files Makefile.in dbmulti.c dropbearconvert.c dropbearkey.c main.c svr-main.c
diffstat 6 files changed, 405 insertions(+), 387 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.in	Tue Jul 27 13:32:54 2004 +0000
+++ b/Makefile.in	Tue Jul 27 14:44:43 2004 +0000
@@ -10,18 +10,17 @@
 # This makefile is quite evil.
 
 ifndef PROGRAMS
-	PROGRAMS="dropbear dbclient dropbearkey dropbearmulti"
+	PROGRAMS=dropbear dbclient dropbearkey dropbearmulti
 endif
 
 LTC=libtomcrypt/libtomcrypt.a
 LTM=libtommath/libtommath.a
 
-COMMONOBJS=dbutil.o common-session.o packet.o common-algo.o buffer.o \
-		common-kex.o dss.o bignum.o \
-		signkey.o rsa.o random.o common-channel.o \
-		common-chansession.o queue.o termcodes.o  \
-		loginrec.o atomicio.o tcpfwd-direct.o compat.o \
-		tcpfwd-remote.o listener.o process-packet.o common-runopts.o
+COMMONOBJS=dbutil.o buffer.o \
+		dss.o bignum.o \
+		signkey.o rsa.o random.o \
+		queue.o \
+		atomicio.o compat.o 
 
 SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
 		svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \
@@ -30,9 +29,12 @@
 CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
 		cli-session.o cli-service.o
 
-DROPBEAROBJS=
+CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
+			common-channel.o common-chansession.o termcodes.o loginrec.o \
+			tcpfwd-direct.o tcpfwd-remote.o listener.o process-packet.o \
+			common-runopts.o
 
-DROPBEARKEYOBJS=dropbearkey.o gendss.o genrsa.o
+KEYOBJS=dropbearkey.o gendss.o genrsa.o
 
 CONVERTOBJS=dropbearconvert.o keyimport.o
 
@@ -45,8 +47,8 @@
 		loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd-direct.h compat.h \
 		tcpfwd-remote.h listener.h
 
-dropbearobjs=$(COMMONOBJS) $(SVROBJS) 
-dbclientobjs=$(COMMONOBJS) $(CLIOBJS)
+dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) 
+dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
 dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
 dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
 scpobjs=$(SCPOBJS)
@@ -57,7 +59,7 @@
 sbindir=${exec_prefix}/sbin
 
 CC=@CC@
-LD=@CC@
+LD=@LD@
 AR=@AR@
 RANLIB=@RANLIB@
 STRIP=@STRIP@
@@ -69,17 +71,15 @@
 EXEEXT=@EXEEXT@
 
 # whether we're building client, server, or both for the common objects.
+# evilness so we detect 'dropbear' by itself as a word
 space:= $(empty) $(empty)
-CLISVRFLAGS=
-# evilness so we detect 'dropbear' by itself as a word
-ifneq (,$(findstring $(space)dropbear$(space), $(space)$(PROGRAMS)$(space)))
-	CLISVRFLAGS+= -DDROPBEAR_SERVER
+ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdropbearZ, Z$(prog)Z))))
+	CFLAGS+= -DDROPBEAR_SERVER
 endif
-ifneq (,$(findstring $(space)dbclient$(space), $(space)$(PROGRAMS)$(space)))
-	CLISVRFLAGS+= -DDROPBEAR_CLIENT
+ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdbclientZ, Z$(prog)Z))))
+	CFLAGS+= -DDROPBEAR_CLIENT
 endif
 
-CFLAGS+=$(CLISVRFLAGS)
 
 # these are exported so that libtomcrypt's makefile will use them
 export CC
@@ -108,12 +108,15 @@
 #%: $(HEADERS) Makefile
 # TODO
 
+all: $(TARGETS)
+
+test:
+	 @echo Z$(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))Z
 
 strip: $(TARGETS)
-	$(STRIP) $(foreach prog, $(TARGETS), $(SPREFIX)$(prog)$(EXEEXT))
+	$(STRIP) $(addsuffix $(EXEEXT), $(addprefix $(SPREFIX), $(TARGETS)))
 
-
-install: $(foreach prog, $(TARGETS), install$prog)
+install: $(addprefix install, $(TARGETS))
 
 # dropbear should go in sbin, so it needs a seperate rule
 installdropbear: dropbear
@@ -128,33 +131,39 @@
 	-chown root $(DESTDIR)$(sbindir)/$(SPREFIX)$*$(EXEEXT)
 	-chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)$*$(EXEEXT)
 	ifeq ($(MULTI), 1)
+		@echo 
 		@echo "You must manually create links for $*"
 	endif
 
 
 
-# The actual binaries
+# for some reason the rule further down doesn't like $($@objs) as a prereq.
 dropbear: $(dropbearobjs)
+dbclient: $(dbclientobjs)
+dropbearkey: $(dropbearkeyobjs)
+dropbearconvert: $(dropbearconvertobjs)
 
-dropbear dbclient dropbearkey dropbearconvert: $($($@objs)) $(HEADERS) \
-														$(LTC) $(LTM)
-	@echo $(CLISVRFLAGS)
+dropbear dbclient dropbearkey dropbearconvert: $(HEADERS)  $(LTC) $(LTM)
 	$(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $($@objs) $(LIBS)
 
-
 # scp doesn't use the libs so is special.
 scp: $(SCPOBJS)  $(HEADERS)
 	$(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(SCPOBJS)
 
 
-MULTIOBJS=dbmulti.o
+# multi-binary compilation.
+MULTIOBJS=
 ifeq ($(MULTI),1)
-	deftarget=multi
-	MULTIOBJS=$(foreach prog, $(PROGRAMS), $($(prog)objs))
+	MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))
+	CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
 endif
 
+testfoo:
+	echo $(MULTIOBJS)
+
 dropbearmulti: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM)
 	$(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(MULTIOBJS) $(LIBS)
+	@echo
 	@echo "You should now create symlinks to the programs you have included"
 	@echo "ie 'ln -s dropbearmulti dropbear'"
 
--- a/dbmulti.c	Tue Jul 27 13:32:54 2004 +0000
+++ b/dbmulti.c	Tue Jul 27 14:44:43 2004 +0000
@@ -4,6 +4,7 @@
 int dropbear_main(int argc, char ** argv);
 int dropbearkey_main(int argc, char ** argv);
 int dropbearconvert_main(int argc, char ** argv);
+int scp_main(int argc, char ** argv);
 
 int main(int argc, char ** argv) {
 
@@ -13,34 +14,42 @@
 		/* figure which form we're being called as */
 		progname = basename(argv[0]);
 
-#ifdef DBMULTI_DROPBEAR
+#ifdef DBMULTI_dropbear
 		if (strcmp(progname, "dropbear") == 0) {
 			return dropbear_main(argc, argv);
 		}
 #endif
-#ifdef DBMULTI_KEY
+#ifdef DBMULTI_dropbearkey
 		if (strcmp(progname, "dropbearkey") == 0) {
 			return dropbearkey_main(argc, argv);
 		}
 #endif
-#ifdef DBMULTI_CONVERT
+#ifdef DBMULTI_dropbearconvert
 		if (strcmp(progname, "dropbearconvert") == 0) {
 			return dropbearconvert_main(argc, argv);
 		}
 #endif
+#ifdef DBMULTI_scp
+		if (strcmp(progname, "scp") == 0) {
+			return scp_main(argc, argv);
+		}
+#endif
 	}
 
 	fprintf(stderr, "Dropbear multi-purpose version %s\n"
 			"Make a symlink pointing at this binary with one of the following names:\n"
-#ifdef DBMULTI_DROPBEAR
+#ifdef DBMULTI_dropbear
 			"'dropbear' - the Dropbear server\n"
 #endif
-#ifdef DBMULTI_KEY
+#ifdef DBMULTI_dropbearkey
 			"'dropbearkey' - the key generator\n"
 #endif
-#ifdef DBMULTI_CONVERT
+#ifdef DBMULTI_dropbearconvert
 			"'dropbearconvert' - the key converter\n"
 #endif
+#ifdef DBMULTI_scp
+			"'scp' - secure copy\n"
+#endif
 			,
 			DROPBEAR_VERSION);
 	exit(1);
--- a/dropbearconvert.c	Tue Jul 27 13:32:54 2004 +0000
+++ b/dropbearconvert.c	Tue Jul 27 14:44:43 2004 +0000
@@ -53,8 +53,8 @@
 					"standard input or standard output.\n", progname);
 }
 
-#if defined(DBMULTI_CONVERT) || !defined(DROPBEAR_MULTI)
-#if defined(DBMULTI_CONVERT) && defined(DROPBEAR_MULTI)
+#if defined(DBMULTI_dropbearconvert) || !defined(DROPBEAR_MULTI)
+#if defined(DBMULTI_dropbearconvert) && defined(DROPBEAR_MULTI)
 int dropbearconvert_main(int argc, char ** argv) {
 #else 
 int main(int argc, char ** argv) {
--- a/dropbearkey.c	Tue Jul 27 13:32:54 2004 +0000
+++ b/dropbearkey.c	Tue Jul 27 14:44:43 2004 +0000
@@ -80,8 +80,8 @@
 					progname);
 }
 
-#if defined(DBMULTI_KEY) || !defined(DROPBEAR_MULTI)
-#if defined(DBMULTI_KEY) && defined(DROPBEAR_MULTI)
+#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
+#if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI)
 int dropbearkey_main(int argc, char ** argv) {
 #else
 int main(int argc, char ** argv) {
--- a/main.c	Tue Jul 27 13:32:54 2004 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,347 +0,0 @@
-/*
- * Dropbear - a SSH2 server
- * 
- * Copyright (c) 2002,2003 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 "session.h"
-#include "buffer.h"
-#include "signkey.h"
-#include "runopts.h"
-
-static int listensockets(int *sock, int *maxfd);
-static void sigchld_handler(int dummy);
-static void sigsegv_handler(int);
-static void sigintterm_handler(int fish);
-
-static int childpipes[MAX_UNAUTH_CLIENTS];
-
-#if defined(DBMULTI_DROPBEAR) || !defined(DROPBEAR_MULTI)
-#if defined(DBMULTI_DROPBEAR) && defined(DROPBEAR_MULTI)
-int dropbear_main(int argc, char ** argv)
-#else
-int main(int argc, char ** argv)
-#endif
-{
-	
-	fd_set fds;
-	struct timeval seltimeout;
-	unsigned int i, j;
-	int val;
-	int maxsock = -1;
-	struct sockaddr remoteaddr;
-	int remoteaddrlen;
-	int listensocks[MAX_LISTEN_ADDR];
-	unsigned int listensockcount = 0;
-	FILE * pidfile;
-
-	int childsock;
-	pid_t childpid;
-	int childpipe[2];
-
-	struct sigaction sa_chld;
-
-	_dropbear_exit = svr_dropbear_exit;
-	_dropbear_log = svr_dropbear_log;
-
-	/* get commandline options */
-	svr_getopts(argc, argv);
-
-	/* fork */
-	if (svr_opts.forkbg) {
-		int closefds = 0;
-#ifndef DEBUG_TRACE
-		if (!svr_opts.usingsyslog) {
-			closefds = 1;
-		}
-#endif
-		if (daemon(0, closefds) < 0) {
-			dropbear_exit("Failed to create background process: %s",
-					strerror(errno));
-		}
-	}
-
-#ifndef DISABLE_SYSLOG
-	if (svr_opts.usingsyslog) {
-		startsyslog();
-	}
-#endif
-
-	/* should be done after syslog is working */
-	if (svr_opts.forkbg) {
-		dropbear_log(LOG_INFO, "Running in background");
-	} else {
-		dropbear_log(LOG_INFO, "Not forking");
-	}
-
-	/* create a PID file so that we can be killed easily */
-	pidfile = fopen(DROPBEAR_PIDFILE, "w");
-	if (pidfile) {
-		fprintf(pidfile, "%d\n", getpid());
-		fclose(pidfile);
-	}
-
-	/* set up cleanup handler */
-	if (signal(SIGINT, sigintterm_handler) == SIG_ERR || 
-#ifndef DEBUG_VALGRIND
-		signal(SIGTERM, sigintterm_handler) == SIG_ERR ||
-#endif
-		signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
-		dropbear_exit("signal() error");
-	}
-
-	/* catch and reap zombie children */
-	sa_chld.sa_handler = sigchld_handler;
-	sa_chld.sa_flags = SA_NOCLDSTOP;
-	if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
-		dropbear_exit("signal() error");
-	}
-	if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) {
-		dropbear_exit("signal() error");
-	}
-
-	/* sockets to identify pre-authenticated clients */
-	for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
-		childpipes[i] = -1;
-	}
-	
-	/* Set up the listening sockets */
-	/* XXX XXX ports */
-	listensockcount = listensockets(listensocks, &maxsock);
-
-	/* incoming connection select loop */
-	for(;;) {
-
-		FD_ZERO(&fds);
-		
-		seltimeout.tv_sec = 60;
-		seltimeout.tv_usec = 0;
-		
-		/* listening sockets */
-		for (i = 0; i < listensockcount; i++) {
-			FD_SET(listensocks[i], &fds);
-		}
-
-		/* pre-authentication clients */
-		for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
-			if (childpipes[i] >= 0) {
-				FD_SET(childpipes[i], &fds);
-				maxsock = MAX(maxsock, childpipes[i]);
-			}
-		}
-
-		val = select(maxsock+1, &fds, NULL, NULL, &seltimeout);
-
-		if (exitflag) {
-			unlink(DROPBEAR_PIDFILE);
-			dropbear_exit("Terminated by signal");
-		}
-		
-		if (val == 0) {
-			/* timeout reached */
-			continue;
-		}
-
-		if (val < 0) {
-			if (errno == EINTR) {
-				continue;
-			}
-			dropbear_exit("Listening socket error");
-		}
-
-		/* close fds which have been authed or closed - auth.c handles
-		 * closing the auth sockets on success */
-		for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
-			if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) {
-				close(childpipes[i]);
-				childpipes[i] = -1;
-			}
-		}
-
-		/* handle each socket which has something to say */
-		for (i = 0; i < listensockcount; i++) {
-			if (!FD_ISSET(listensocks[i], &fds)) 
-				continue;
-
-			/* child connection XXX - ip6 stuff here */
-			remoteaddrlen = sizeof(struct sockaddr_in);
-			childsock = accept(listensocks[i], &remoteaddr, &remoteaddrlen);
-
-			if (childsock < 0) {
-				/* accept failed */
-				continue;
-			}
-
-			/* check for max number of connections not authorised */
-			for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) {
-				if (childpipes[j] < 0) {
-					break;
-				}
-			}
-
-			if (j == MAX_UNAUTH_CLIENTS) {
-				/* no free connections */
-				/* TODO - possibly log, though this would be an easy way
-				 * to fill logs/disk */
-				close(childsock);
-				continue;
-			}
-
-			if (pipe(childpipe) < 0) {
-				TRACE(("error creating child pipe"));
-				close(childsock);
-				continue;
-			}
-
-			if ((childpid = fork()) == 0) {
-
-				/* child */
-				char * addrstring = NULL;
-#ifdef DEBUG_FORKGPROF
-				extern void _start(void), etext(void);
-				monstartup((u_long)&_start, (u_long)&etext);
-#endif /* DEBUG_FORKGPROF */
-
-				addrstring = getaddrstring(&remoteaddr);
-				dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
-				m_free(addrstring);
-
-				if (setsid() < 0) {
-					dropbear_exit("setsid: %s", strerror(errno));
-				}
-
-				/* make sure we close sockets */
-				for (i = 0; i < listensockcount; i++) {
-					if (m_close(listensocks[i]) == DROPBEAR_FAILURE) {
-						dropbear_exit("Couldn't close socket");
-					}
-				}
-
-				if (m_close(childpipe[0]) == DROPBEAR_FAILURE) {
-					dropbear_exit("Couldn't close socket");
-				}
-
-				/* start the session */
-				svr_session(childsock, childpipe[1], 
-								getaddrhostname(&remoteaddr));
-				/* don't return */
-				assert(0);
-			}
-			
-			/* parent */
-			childpipes[j] = childpipe[0];
-			if (m_close(childpipe[1]) == DROPBEAR_FAILURE
-					|| m_close(childsock) == DROPBEAR_FAILURE) {
-				dropbear_exit("Couldn't close socket");
-			}
-		}
-	} /* for(;;) loop */
-
-	/* don't reach here */
-	return -1;
-}
-#endif
-
-/* catch + reap zombie children */
-static void sigchld_handler(int fish) {
-	struct sigaction sa_chld;
-
-	while(waitpid(-1, NULL, WNOHANG) > 0); 
-
-	sa_chld.sa_handler = sigchld_handler;
-	sa_chld.sa_flags = SA_NOCLDSTOP;
-	if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
-		dropbear_exit("signal() error");
-	}
-}
-
-/* catch any segvs */
-static void sigsegv_handler(int fish) {
-	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) {
-
-	exitflag = 1;
-}
-
-/* Set up listening sockets for all the requested ports */
-static int listensockets(int *sock, int *maxfd) {
-	
-	int listensock; /* listening fd */
-	struct sockaddr_in listen_addr;
-	struct linger linger;
-	unsigned int i;
-	int val;
-
-	for (i = 0; i < svr_opts.portcount; i++) {
-
-		/* iterate through all the sockets to listen on */
-		listensock = socket(PF_INET, SOCK_STREAM, 0);
-		if (listensock < 0) {
-			dropbear_exit("Failed to create socket");
-		}
-
-		val = 1;
-		/* set to reuse, quick timeout */
-		setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR,
-				(void*) &val, sizeof(val));
-		linger.l_onoff = 1;
-		linger.l_linger = 5;
-		setsockopt(listensock, SOL_SOCKET, SO_LINGER,
-				(void*)&linger, sizeof(linger));
-
-		/* disable nagle */
-		setsockopt(listensock, IPPROTO_TCP, TCP_NODELAY,
-				(void*)&val, sizeof(val));
-
-		memset((void*)&listen_addr, 0x0, sizeof(listen_addr));
-		listen_addr.sin_family = AF_INET;
-		listen_addr.sin_port = htons(svr_opts.ports[i]);
-		listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-		memset(&(listen_addr.sin_zero), '\0', 8);
-
-		if (bind(listensock, (struct sockaddr *)&listen_addr,
-					sizeof(listen_addr)) < 0) {
-			dropbear_exit("Bind failed port %d", svr_opts.ports[i]);
-		}
-
-		/* listen */
-		if (listen(listensock, 20) < 0) { /* TODO set listen count */
-			dropbear_exit("Listen failed");
-		}
-
-		/* nonblock */
-		if (fcntl(listensock, F_SETFL, O_NONBLOCK) < 0) {
-			dropbear_exit("Failed to set non-blocking");
-		}
-
-		sock[i] = listensock;
-		*maxfd = MAX(listensock, *maxfd);
-	}
-
-	return svr_opts.portcount;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svr-main.c	Tue Jul 27 14:44:43 2004 +0000
@@ -0,0 +1,347 @@
+/*
+ * Dropbear - a SSH2 server
+ * 
+ * Copyright (c) 2002,2003 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 "session.h"
+#include "buffer.h"
+#include "signkey.h"
+#include "runopts.h"
+
+static int listensockets(int *sock, int *maxfd);
+static void sigchld_handler(int dummy);
+static void sigsegv_handler(int);
+static void sigintterm_handler(int fish);
+
+static int childpipes[MAX_UNAUTH_CLIENTS];
+
+#if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI)
+#if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI)
+int dropbear_main(int argc, char ** argv)
+#else
+int main(int argc, char ** argv)
+#endif
+{
+	
+	fd_set fds;
+	struct timeval seltimeout;
+	unsigned int i, j;
+	int val;
+	int maxsock = -1;
+	struct sockaddr remoteaddr;
+	int remoteaddrlen;
+	int listensocks[MAX_LISTEN_ADDR];
+	unsigned int listensockcount = 0;
+	FILE * pidfile;
+
+	int childsock;
+	pid_t childpid;
+	int childpipe[2];
+
+	struct sigaction sa_chld;
+
+	_dropbear_exit = svr_dropbear_exit;
+	_dropbear_log = svr_dropbear_log;
+
+	/* get commandline options */
+	svr_getopts(argc, argv);
+
+	/* fork */
+	if (svr_opts.forkbg) {
+		int closefds = 0;
+#ifndef DEBUG_TRACE
+		if (!svr_opts.usingsyslog) {
+			closefds = 1;
+		}
+#endif
+		if (daemon(0, closefds) < 0) {
+			dropbear_exit("Failed to create background process: %s",
+					strerror(errno));
+		}
+	}
+
+#ifndef DISABLE_SYSLOG
+	if (svr_opts.usingsyslog) {
+		startsyslog();
+	}
+#endif
+
+	/* should be done after syslog is working */
+	if (svr_opts.forkbg) {
+		dropbear_log(LOG_INFO, "Running in background");
+	} else {
+		dropbear_log(LOG_INFO, "Not forking");
+	}
+
+	/* create a PID file so that we can be killed easily */
+	pidfile = fopen(DROPBEAR_PIDFILE, "w");
+	if (pidfile) {
+		fprintf(pidfile, "%d\n", getpid());
+		fclose(pidfile);
+	}
+
+	/* set up cleanup handler */
+	if (signal(SIGINT, sigintterm_handler) == SIG_ERR || 
+#ifndef DEBUG_VALGRIND
+		signal(SIGTERM, sigintterm_handler) == SIG_ERR ||
+#endif
+		signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
+		dropbear_exit("signal() error");
+	}
+
+	/* catch and reap zombie children */
+	sa_chld.sa_handler = sigchld_handler;
+	sa_chld.sa_flags = SA_NOCLDSTOP;
+	if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
+		dropbear_exit("signal() error");
+	}
+	if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) {
+		dropbear_exit("signal() error");
+	}
+
+	/* sockets to identify pre-authenticated clients */
+	for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
+		childpipes[i] = -1;
+	}
+	
+	/* Set up the listening sockets */
+	/* XXX XXX ports */
+	listensockcount = listensockets(listensocks, &maxsock);
+
+	/* incoming connection select loop */
+	for(;;) {
+
+		FD_ZERO(&fds);
+		
+		seltimeout.tv_sec = 60;
+		seltimeout.tv_usec = 0;
+		
+		/* listening sockets */
+		for (i = 0; i < listensockcount; i++) {
+			FD_SET(listensocks[i], &fds);
+		}
+
+		/* pre-authentication clients */
+		for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
+			if (childpipes[i] >= 0) {
+				FD_SET(childpipes[i], &fds);
+				maxsock = MAX(maxsock, childpipes[i]);
+			}
+		}
+
+		val = select(maxsock+1, &fds, NULL, NULL, &seltimeout);
+
+		if (exitflag) {
+			unlink(DROPBEAR_PIDFILE);
+			dropbear_exit("Terminated by signal");
+		}
+		
+		if (val == 0) {
+			/* timeout reached */
+			continue;
+		}
+
+		if (val < 0) {
+			if (errno == EINTR) {
+				continue;
+			}
+			dropbear_exit("Listening socket error");
+		}
+
+		/* close fds which have been authed or closed - auth.c handles
+		 * closing the auth sockets on success */
+		for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
+			if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) {
+				close(childpipes[i]);
+				childpipes[i] = -1;
+			}
+		}
+
+		/* handle each socket which has something to say */
+		for (i = 0; i < listensockcount; i++) {
+			if (!FD_ISSET(listensocks[i], &fds)) 
+				continue;
+
+			/* child connection XXX - ip6 stuff here */
+			remoteaddrlen = sizeof(struct sockaddr_in);
+			childsock = accept(listensocks[i], &remoteaddr, &remoteaddrlen);
+
+			if (childsock < 0) {
+				/* accept failed */
+				continue;
+			}
+
+			/* check for max number of connections not authorised */
+			for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) {
+				if (childpipes[j] < 0) {
+					break;
+				}
+			}
+
+			if (j == MAX_UNAUTH_CLIENTS) {
+				/* no free connections */
+				/* TODO - possibly log, though this would be an easy way
+				 * to fill logs/disk */
+				close(childsock);
+				continue;
+			}
+
+			if (pipe(childpipe) < 0) {
+				TRACE(("error creating child pipe"));
+				close(childsock);
+				continue;
+			}
+
+			if ((childpid = fork()) == 0) {
+
+				/* child */
+				char * addrstring = NULL;
+#ifdef DEBUG_FORKGPROF
+				extern void _start(void), etext(void);
+				monstartup((u_long)&_start, (u_long)&etext);
+#endif /* DEBUG_FORKGPROF */
+
+				addrstring = getaddrstring(&remoteaddr);
+				dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
+				m_free(addrstring);
+
+				if (setsid() < 0) {
+					dropbear_exit("setsid: %s", strerror(errno));
+				}
+
+				/* make sure we close sockets */
+				for (i = 0; i < listensockcount; i++) {
+					if (m_close(listensocks[i]) == DROPBEAR_FAILURE) {
+						dropbear_exit("Couldn't close socket");
+					}
+				}
+
+				if (m_close(childpipe[0]) == DROPBEAR_FAILURE) {
+					dropbear_exit("Couldn't close socket");
+				}
+
+				/* start the session */
+				svr_session(childsock, childpipe[1], 
+								getaddrhostname(&remoteaddr));
+				/* don't return */
+				assert(0);
+			}
+			
+			/* parent */
+			childpipes[j] = childpipe[0];
+			if (m_close(childpipe[1]) == DROPBEAR_FAILURE
+					|| m_close(childsock) == DROPBEAR_FAILURE) {
+				dropbear_exit("Couldn't close socket");
+			}
+		}
+	} /* for(;;) loop */
+
+	/* don't reach here */
+	return -1;
+}
+#endif
+
+/* catch + reap zombie children */
+static void sigchld_handler(int fish) {
+	struct sigaction sa_chld;
+
+	while(waitpid(-1, NULL, WNOHANG) > 0); 
+
+	sa_chld.sa_handler = sigchld_handler;
+	sa_chld.sa_flags = SA_NOCLDSTOP;
+	if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
+		dropbear_exit("signal() error");
+	}
+}
+
+/* catch any segvs */
+static void sigsegv_handler(int fish) {
+	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) {
+
+	exitflag = 1;
+}
+
+/* Set up listening sockets for all the requested ports */
+static int listensockets(int *sock, int *maxfd) {
+	
+	int listensock; /* listening fd */
+	struct sockaddr_in listen_addr;
+	struct linger linger;
+	unsigned int i;
+	int val;
+
+	for (i = 0; i < svr_opts.portcount; i++) {
+
+		/* iterate through all the sockets to listen on */
+		listensock = socket(PF_INET, SOCK_STREAM, 0);
+		if (listensock < 0) {
+			dropbear_exit("Failed to create socket");
+		}
+
+		val = 1;
+		/* set to reuse, quick timeout */
+		setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR,
+				(void*) &val, sizeof(val));
+		linger.l_onoff = 1;
+		linger.l_linger = 5;
+		setsockopt(listensock, SOL_SOCKET, SO_LINGER,
+				(void*)&linger, sizeof(linger));
+
+		/* disable nagle */
+		setsockopt(listensock, IPPROTO_TCP, TCP_NODELAY,
+				(void*)&val, sizeof(val));
+
+		memset((void*)&listen_addr, 0x0, sizeof(listen_addr));
+		listen_addr.sin_family = AF_INET;
+		listen_addr.sin_port = htons(svr_opts.ports[i]);
+		listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+		memset(&(listen_addr.sin_zero), '\0', 8);
+
+		if (bind(listensock, (struct sockaddr *)&listen_addr,
+					sizeof(listen_addr)) < 0) {
+			dropbear_exit("Bind failed port %d", svr_opts.ports[i]);
+		}
+
+		/* listen */
+		if (listen(listensock, 20) < 0) { /* TODO set listen count */
+			dropbear_exit("Listen failed");
+		}
+
+		/* nonblock */
+		if (fcntl(listensock, F_SETFL, O_NONBLOCK) < 0) {
+			dropbear_exit("Failed to set non-blocking");
+		}
+
+		sock[i] = listensock;
+		*maxfd = MAX(listensock, *maxfd);
+	}
+
+	return svr_opts.portcount;
+}