diff svr-main.c @ 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 973fccb59ea4
children
line wrap: on
line diff
--- 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 */