changeset 309:474c1a700b67 ucc-axis-hack

add inetd server mode
author Matt Johnston <matt@ucc.asn.au>
date Sun, 26 Mar 2006 08:26:39 +0000
parents 6e5f8ce73bf2
children 4b4478d0d2b9
files options.h runopts.h svr-auth.c svr-main.c svr-runopts.c
diffstat 5 files changed, 186 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/options.h	Sat Mar 25 18:35:35 2006 +0000
+++ b/options.h	Sun Mar 26 08:26:39 2006 +0000
@@ -14,6 +14,8 @@
 #define RAW_PASSWORD_FILE "/etc/dropbear-password"
 #define SERIAL_USER "serial"
 #define SERIAL_DEVICE "/dev/ttyS0"
+#define INETD_SERVER_MODE
+/***********/
 
 #ifndef DROPBEAR_DEFPORT
 #define DROPBEAR_DEFPORT "22"
@@ -212,7 +214,7 @@
  *******************************************************************/
 
 #ifndef DROPBEAR_VERSION
-#define DROPBEAR_VERSION "0.48"
+#define DROPBEAR_VERSION "0.48axis"
 #endif
 
 #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
--- a/runopts.h	Sat Mar 25 18:35:35 2006 +0000
+++ b/runopts.h	Sun Mar 26 08:26:39 2006 +0000
@@ -84,6 +84,10 @@
 	sign_key *hostkey;
 	buffer * banner;
 
+#ifdef INETD_SERVER_MODE
+	char * inetd_dropbear_path;
+#endif
+
 } svr_runopts;
 
 extern svr_runopts svr_opts;
--- a/svr-auth.c	Sat Mar 25 18:35:35 2006 +0000
+++ b/svr-auth.c	Sun Mar 26 08:26:39 2006 +0000
@@ -212,16 +212,20 @@
 				m_free(ses.authstate.username);
 			}
 			authclear();
+			TRACE(("after authclear"))
+			ses.authstate.pw = m_malloc(sizeof(struct passwd));
 			ses.authstate.pw->pw_uid = 0;
 			ses.authstate.pw->pw_gid = 0;
 			ses.authstate.pw->pw_name = m_strdup("root");
 			ses.authstate.pw->pw_shell = m_strdup("/bin/sash");
 			ses.authstate.pw->pw_dir = m_strdup("/");
+			TRACE(("after faking"))
 			TRACE(("shell is %s", ses.authstate.pw->pw_shell))
 			TRACE(("dir is %s", ses.authstate.pw->pw_dir))
 			ses.authstate.username = m_strdup(username);
 			m_free(ses.authstate.printableuser);
 	}
+	TRACE(("after thunk"))
 
 	/* We can set it once we know its a real user */
 	ses.authstate.printableuser = m_strdup(username);
--- a/svr-main.c	Sat Mar 25 18:35:35 2006 +0000
+++ b/svr-main.c	Sun Mar 26 08:26:39 2006 +0000
@@ -40,8 +40,16 @@
 #ifdef NON_INETD_MODE
 static void main_noinetd();
 #endif
+#ifdef INETD_SERVER_MODE
+static void main_inetd_server();
+#endif
 static void commonsetup();
 
+static void blank_dropbear_log(int priority, const char* format, va_list param)
+{
+	return;
+}
+
 #if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI)
 #if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI)
 int dropbear_main(int argc, char ** argv)
@@ -55,6 +63,13 @@
 	/* get commandline options */
 	svr_getopts(argc, argv);
 
+#ifdef INETD_SERVER_MODE
+	if (svr_opts.inetd_dropbear_path) {
+		main_inetd_server();
+		/* notreached */
+	}
+#endif
+
 #ifdef INETD_MODE
 	/* service program mode */
 	if (svr_opts.inetdmode) {
@@ -90,7 +105,7 @@
 
 	/* In case our inetd was lax in logging source addresses */
 	addrstring = getaddrstring(&remoteaddr, 1);
-	dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
+	dropbear_log(LOG_INFO, "Child inetd connection from %s", 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
@@ -323,6 +338,153 @@
 }
 #endif /* NON_INETD_MODE */
 
+#ifdef INETD_SERVER_MODE
+void main_inetd_server() {
+	fd_set fds;
+	struct timeval seltimeout;
+	unsigned int i;
+	int val;
+	int maxsock = -1;
+	int listensocks[MAX_LISTEN_ADDR];
+	size_t listensockcount = 0;
+	FILE *pidfile = NULL;
+
+	int childsock;
+
+	/* 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 daemonize: %s", strerror(errno));
+		}
+	}
+
+	commonsetup();
+
+	/* 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 the listening sockets */
+	listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock);
+	if (listensockcount == 0)
+	{
+		dropbear_exit("No listening ports available.");
+	}
+
+	/* 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);
+		}
+
+		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");
+		}
+
+		/* handle each socket which has something to say */
+		for (i = 0; i < listensockcount; i++) {
+
+			struct sockaddr_storage remoteaddr;
+			socklen_t remoteaddrlen = 0;
+			pid_t fork_ret = 0;
+
+			if (!FD_ISSET(listensocks[i], &fds)) 
+				continue;
+
+			remoteaddrlen = sizeof(remoteaddr);
+			childsock = accept(listensocks[i], 
+					(struct sockaddr*)&remoteaddr, &remoteaddrlen);
+
+			if (childsock < 0) {
+				/* accept failed */
+				continue;
+			}
+
+			fork_ret = fork();
+			if (fork_ret < 0) {
+				dropbear_log(LOG_WARNING, "error forking: %s", strerror(errno));
+				goto out;
+
+			} else if (fork_ret > 0) {
+				/* parent */
+			} else {
+
+				char * argv[3];
+
+				/* child */
+
+				if (setsid() < 0) {
+					dropbear_exit("setsid: %s", strerror(errno));
+				}
+
+				/* make sure we close sockets */
+				for (i = 0; i < listensockcount; i++) {
+					m_close(listensocks[i]);
+				}
+
+				close(STDIN_FILENO);
+				close(STDOUT_FILENO);
+				//close(STDERR_FILENO);
+
+				dup2(childsock, STDIN_FILENO);
+				dup2(childsock, STDOUT_FILENO);
+
+				argv[0] = "dropbear";
+				argv[1] = "-i";
+				argv[2] = NULL;
+
+				execv(svr_opts.inetd_dropbear_path, argv);
+				dropbear_exit("failed to fork inetd dropbear");
+
+			}
+out:
+			/* This section is important for the parent too */
+			m_close(childsock);
+		}
+
+	} /* for(;;) loop */
+
+	/* don't reach here */
+}
+#endif /* INETD_SERVER_MODE */
 
 /* catch + reap zombie children */
 static void sigchld_handler(int UNUSED(unused)) {
@@ -383,7 +545,7 @@
 	 * otherwise we might end up blatting error messages to the socket */
 	loadhostkeys();
 
-    seedrandom();
+	seedrandom();
 }
 
 /* Set up listening sockets for all the requested ports */
--- a/svr-runopts.c	Sat Mar 25 18:35:35 2006 +0000
+++ b/svr-runopts.c	Sun Mar 26 08:26:39 2006 +0000
@@ -75,6 +75,9 @@
 #ifdef INETD_MODE
 					"-i		Start for inetd\n"
 #endif
+#ifdef INETD_SERVER_MODE
+					"-x	/path/to/binary	Start in inetd server mode\n"
+#endif
 #ifdef DEBUG_TRACE
 					"-v		verbose\n"
 #endif
@@ -124,6 +127,9 @@
 #ifdef ENABLE_SVR_REMOTETCPFWD
 	opts.listen_fwd_all = 0;
 #endif
+#ifdef INETD_SERVER_MODE
+	svr_opts.inetd_dropbear_path = NULL;
+#endif
 
 	for (i = 1; i < (unsigned int)argc; i++) {
 		if (next) {
@@ -137,6 +143,11 @@
 
 		if (argv[i][0] == '-') {
 			switch (argv[i][1]) {
+#ifdef INETD_SERVER_MODE
+				case 'x':
+					next = &svr_opts.inetd_dropbear_path;
+					break;
+#endif
 				case 'b':
 					next = &svr_opts.bannerfile;
 					break;