# HG changeset patch # User Matt Johnston # Date 1090939483 0 # Node ID 223b0f5f8dcef517c67d9c04b0afe869bdf84c3f # Parent 0fcf63e1cb010485dcf51c2c9ce8465c9c5889b8 Switching to the magical new Makefile, and new dbmulti style diff -r 0fcf63e1cb01 -r 223b0f5f8dce Makefile.in --- 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'" diff -r 0fcf63e1cb01 -r 223b0f5f8dce dbmulti.c --- 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); diff -r 0fcf63e1cb01 -r 223b0f5f8dce dropbearconvert.c --- 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) { diff -r 0fcf63e1cb01 -r 223b0f5f8dce dropbearkey.c --- 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) { diff -r 0fcf63e1cb01 -r 223b0f5f8dce main.c --- 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; -} diff -r 0fcf63e1cb01 -r 223b0f5f8dce svr-main.c --- /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; +}