summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--options.h13
-rw-r--r--runopts.h2
-rw-r--r--svr-main.c136
-rw-r--r--svr-runopts.c11
4 files changed, 123 insertions, 39 deletions
diff --git a/options.h b/options.h
index c687a8c..047b35a 100644
--- a/options.h
+++ b/options.h
@@ -42,6 +42,19 @@
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
#endif
+/* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
+ * on chosen ports and keeps accepting connections. This is the default.
+ *
+ * Set INETD_MODE if you want to be able to run Dropbear with inetd (or
+ * similar), where it will use stdin/stdout for connections, and each process
+ * lasts for a single connection. Dropbear should be invoked with the -i flag
+ * for inetd, and can only accept IPv4 connections.
+ *
+ * Both of these flags can be defined at once, don't compile without at least
+ * one of them. */
+#define NON_INETD_MODE
+#define INETD_MODE
+
/* Setting this disables the fast exptmod bignum code. It saves ~5kB, but is
* perhaps 20% slower for pubkey operations (it is probably worth experimenting
* if you want to use this) */
diff --git a/runopts.h b/runopts.h
index 4bd3287..66b5a56 100644
--- a/runopts.h
+++ b/runopts.h
@@ -55,6 +55,8 @@ typedef struct svr_runopts {
uint16_t *ports;
unsigned int portcount;
+ int inetdmode;
+
/* Flags indicating whether to use ipv4 and ipv6 */
/* not used yet
int ipv4;
diff --git a/svr-main.c b/svr-main.c
index 503d781..eb7e3df 100644
--- a/svr-main.c
+++ b/svr-main.c
@@ -33,6 +33,9 @@ static int listensockets(int *sock, int sockcount, int *maxfd);
static void sigchld_handler(int dummy);
static void sigsegv_handler(int);
static void sigintterm_handler(int fish);
+static void main_inetd();
+static void main_noinetd();
+static void commonsetup();
static int childpipes[MAX_UNAUTH_CLIENTS];
@@ -44,6 +47,67 @@ int main(int argc, char ** argv)
#endif
{
+
+ _dropbear_exit = svr_dropbear_exit;
+ _dropbear_log = svr_dropbear_log;
+
+ /* get commandline options */
+ svr_getopts(argc, argv);
+
+#ifdef INETD_MODE
+ /* service program mode */
+ if (svr_opts.inetdmode) {
+ main_inetd();
+ /* notreached */
+ }
+#endif
+
+#ifdef NON_INETD_MODE
+ main_noinetd();
+ /* notreached */
+#endif
+
+ dropbear_exit("Compiled without normal mode, can't run without -i\n");
+ return -1;
+}
+#endif
+
+#ifdef INETD_MODE
+static void main_inetd() {
+
+ struct sockaddr_storage remoteaddr;
+ int remoteaddrlen;
+ char * addrstring = NULL;
+
+ /* Set up handlers, syslog */
+ commonsetup();
+
+ remoteaddrlen = sizeof(remoteaddr);
+ if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) {
+ dropbear_exit("Unable to getpeername: %s", strerror(errno));
+ }
+
+ /* In case our inetd was lax in logging source addresses */
+ addrstring = getaddrstring(&remoteaddr, 1);
+ dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
+ m_free(addrstring);
+
+ /* Don't check the return value - it may just fail since inetd has
+ * already done setsid() after forking (xinetd on Darwin appears to do
+ * this */
+ setsid();
+
+ /* Start service program
+ * -1 is a dummy childpipe, just something we can close() without
+ * mattering. */
+ svr_session(0, -1, getaddrhostname(&remoteaddr));
+
+ /* notreached */
+}
+#endif /* INETD_MODE */
+
+#ifdef NON_INETD_MODE
+void main_noinetd() {
fd_set fds;
struct timeval seltimeout;
unsigned int i, j;
@@ -53,20 +117,13 @@ int main(int argc, char ** argv)
int remoteaddrlen;
int listensocks[MAX_LISTEN_ADDR];
int listensockcount = 0;
- FILE * pidfile;
+ FILE *pidfile = NULL;
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;
@@ -76,16 +133,11 @@ int main(int argc, char ** argv)
}
#endif
if (daemon(0, closefds) < 0) {
- dropbear_exit("Failed to create background process: %s",
- strerror(errno));
+ dropbear_exit("Failed to daemonize: %s", strerror(errno));
}
}
-#ifndef DISABLE_SYSLOG
- if (svr_opts.usingsyslog) {
- startsyslog();
- }
-#endif
+ commonsetup();
/* should be done after syslog is working */
if (svr_opts.forkbg) {
@@ -101,25 +153,6 @@ int main(int argc, char ** argv)
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;
@@ -186,7 +219,6 @@ int main(int argc, char ** argv)
if (!FD_ISSET(listensocks[i], &fds))
continue;
- /* child connection XXX - ip6 stuff here */
remoteaddrlen = sizeof(remoteaddr);
childsock = accept(listensocks[i],
(struct sockaddr*)&remoteaddr, &remoteaddrlen);
@@ -262,9 +294,9 @@ int main(int argc, char ** argv)
} /* for(;;) loop */
/* don't reach here */
- return -1;
}
-#endif
+#endif /* NON_INETD_MODE */
+
/* catch + reap zombie children */
static void sigchld_handler(int fish) {
@@ -292,6 +324,36 @@ static void sigintterm_handler(int fish) {
exitflag = 1;
}
+/* Things used by inetd and non-inetd modes */
+static void commonsetup() {
+
+ struct sigaction sa_chld;
+#ifndef DISABLE_SYSLOG
+ if (svr_opts.usingsyslog) {
+ startsyslog();
+ }
+#endif
+
+ /* 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");
+ }
+}
+
/* Set up listening sockets for all the requested ports */
static int listensockets(int *sock, int sockcount, int *maxfd) {
diff --git a/svr-runopts.c b/svr-runopts.c
index 9ecaf32..93b1ae3 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -73,8 +73,9 @@ static void printhelp(const char * progname) {
#endif
"-p port Listen on specified tcp port, up to %d can be specified\n"
" (default %d if none specified)\n"
-/* "-4/-6 Disable listening on ipv4/ipv6 respectively\n"*/
-
+#ifdef INETD_MODE
+ "-i Start for inetd\n"
+#endif
,DROPBEAR_VERSION, progname,
#ifdef DROPBEAR_DSS
DSS_PRIV_FILENAME,
@@ -102,6 +103,7 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.norootlogin = 0;
svr_opts.noauthpass = 0;
svr_opts.norootpass = 0;
+ svr_opts.inetdmode = 0;
opts.nolocaltcp = 0;
opts.noremotetcp = 0;
/* not yet
@@ -158,6 +160,11 @@ void svr_getopts(int argc, char ** argv) {
opts.noremotetcp = 1;
break;
#endif
+#ifdef INETD_MODE
+ case 'i':
+ svr_opts.inetdmode = 1;
+ break;
+#endif
case 'p':
if (portnum < DROPBEAR_MAX_PORTS) {
portstring[portnum] = NULL;