diff svr-main.c @ 293:9d110777f345 contrib-blacklist

propagate from branch 'au.asn.ucc.matt.dropbear' (head 7ad1775ed65e75dbece27fe6b65bf1a234db386a) to branch 'au.asn.ucc.matt.dropbear.contrib.blacklist' (head 1d86a4f0a401cc68c2670d821a2f6366c37af143)
author Matt Johnston <matt@ucc.asn.au>
date Fri, 10 Mar 2006 06:31:29 +0000
parents c07de41b53d7 94ee16f5b8a8
children
line wrap: on
line diff
--- a/svr-main.c	Tue Sep 06 04:57:14 2005 +0000
+++ b/svr-main.c	Fri Mar 10 06:31:29 2006 +0000
@@ -1,7 +1,7 @@
 /*
  * Dropbear - a SSH2 server
  * 
- * Copyright (c) 2002,2003 Matt Johnston
+ * Copyright (c) 2002-2006 Matt Johnston
  * All rights reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -30,7 +30,7 @@
 #include "runopts.h"
 #include "blacklist.h"
 
-static int listensockets(int *sock, int sockcount, int *maxfd);
+static size_t listensockets(int *sock, size_t sockcount, int *maxfd);
 static void sigchld_handler(int dummy);
 static void sigsegv_handler(int);
 static void sigintterm_handler(int fish);
@@ -42,8 +42,6 @@
 #endif
 static void commonsetup();
 
-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)
@@ -51,8 +49,6 @@
 int main(int argc, char ** argv)
 #endif
 {
-	
-
 	_dropbear_exit = svr_dropbear_exit;
 	_dropbear_log = svr_dropbear_log;
 
@@ -81,10 +77,10 @@
 static void main_inetd() {
 
 	struct sockaddr_storage remoteaddr;
-	int remoteaddrlen;
+	socklen_t remoteaddrlen;
 	char * addrstring = NULL;
 
-	/* Set up handlers, syslog */
+	/* Set up handlers, syslog, seed random */
 	commonsetup();
 
 	remoteaddrlen = sizeof(remoteaddr);
@@ -117,14 +113,14 @@
 	unsigned int i, j;
 	int val;
 	int maxsock = -1;
-	struct sockaddr_storage remoteaddr;
-	int remoteaddrlen;
 	int listensocks[MAX_LISTEN_ADDR];
-	int listensockcount = 0;
+	size_t listensockcount = 0;
 	FILE *pidfile = NULL;
 
+	int childpipes[MAX_UNAUTH_CLIENTS];
+	char * preauth_addrs[MAX_UNAUTH_CLIENTS];
+
 	int childsock;
-	pid_t childpid;
 	int childpipe[2];
 
 	/* fork */
@@ -142,7 +138,6 @@
 
 	commonsetup();
 
-
 	/* should be done after syslog is working */
 	if (svr_opts.forkbg) {
 		dropbear_log(LOG_INFO, "Running in background");
@@ -161,11 +156,12 @@
 	for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
 		childpipes[i] = -1;
 	}
+	bzero(preauth_addrs, sizeof(preauth_addrs));
 	
 	/* Set up the listening sockets */
-	/* XXX XXX ports */
 	listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock);
-	if (listensockcount < 0) {
+	if (listensockcount == 0)
+	{
 		dropbear_exit("No listening ports available.");
 	}
 
@@ -178,7 +174,7 @@
 		seltimeout.tv_usec = 0;
 		
 		/* listening sockets */
-		for (i = 0; i < (unsigned int)listensockcount; i++) {
+		for (i = 0; i < listensockcount; i++) {
 			FD_SET(listensocks[i], &fds);
 		}
 
@@ -209,17 +205,27 @@
 			dropbear_exit("Listening socket error");
 		}
 
-		/* close fds which have been authed or closed - auth.c handles
+		/* close fds which have been authed or closed - svr-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]);
+				m_close(childpipes[i]);
 				childpipes[i] = -1;
+				m_free(preauth_addrs[i]);
 			}
 		}
 
 		/* handle each socket which has something to say */
-		for (i = 0; i < (unsigned int)listensockcount; i++) {
+		for (i = 0; i < listensockcount; i++) {
+
+			struct sockaddr_storage remoteaddr;
+			socklen_t remoteaddrlen = 0;
+			size_t num_unauthed_for_addr = 0;
+			size_t num_unauthed_total = 0;
+			char * remote_addr_str = NULL;
+			pid_t fork_ret = 0;
+			size_t conn_idx = 0;
+
 			if (!FD_ISSET(listensocks[i], &fds)) 
 				continue;
 
@@ -232,10 +238,20 @@
 				continue;
 			}
 
-			/* check for max number of connections not authorised */
+			/* Limit the number of unauthenticated connections per IP */
+			remote_addr_str = getaddrstring(&remoteaddr, 0);
+
+			num_unauthed_for_addr = 0;
+			num_unauthed_total = 0;
 			for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) {
-				if (childpipes[j] < 0) {
-					break;
+				if (childpipes[j] >= 0) {
+					num_unauthed_total++;
+					if (strcmp(remote_addr_str, preauth_addrs[j]) == 0) {
+						num_unauthed_for_addr++;
+					}
+				} else {
+					/* a free slot */
+					conn_idx = j;
 				}
 			}
 
@@ -244,21 +260,30 @@
 				continue;
 			}
 
-			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 (num_unauthed_total >= MAX_UNAUTH_CLIENTS
+					|| num_unauthed_for_addr >= MAX_UNAUTH_PER_IP) {
+				goto out;
 			}
 
 			if (pipe(childpipe) < 0) {
 				TRACE(("error creating child pipe"))
-				close(childsock);
-				continue;
+				goto out;
 			}
 
-			if ((childpid = fork()) == 0) {
+			fork_ret = fork();
+			if (fork_ret < 0) {
+				dropbear_log(LOG_WARNING, "error forking: %s", strerror(errno));
+				goto out;
+
+			} else if (fork_ret > 0) {
+
+				/* parent */
+				childpipes[conn_idx] = childpipe[0];
+				m_close(childpipe[1]);
+				preauth_addrs[conn_idx] = remote_addr_str;
+				remote_addr_str = NULL;
+
+			} else {
 
 				/* child */
 				char * addrstring = NULL;
@@ -267,6 +292,7 @@
 				monstartup((u_long)&_start, (u_long)&etext);
 #endif /* DEBUG_FORKGPROF */
 
+				m_free(remote_addr_str);
 				addrstring = getaddrstring(&remoteaddr, 1);
 				dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
 
@@ -275,15 +301,11 @@
 				}
 
 				/* make sure we close sockets */
-				for (i = 0; i < (unsigned int)listensockcount; i++) {
-					if (m_close(listensocks[i]) == DROPBEAR_FAILURE) {
-						dropbear_exit("Couldn't close socket");
-					}
+				for (i = 0; i < listensockcount; i++) {
+					m_close(listensocks[i]);
 				}
 
-				if (m_close(childpipe[0]) == DROPBEAR_FAILURE) {
-					dropbear_exit("Couldn't close socket");
-				}
+				m_close(childpipe[0]);
 
 				/* start the session */
 				svr_session(childsock, childpipe[1], 
@@ -292,12 +314,12 @@
 				/* don't return */
 				dropbear_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");
+
+out:
+			/* This section is important for the parent too */
+			m_close(childsock);
+			if (remote_addr_str) {
+				m_free(remote_addr_str);
 			}
 		}
 	} /* for(;;) loop */
@@ -365,14 +387,16 @@
 	/* Now we can setup the hostkeys - needs to be after logging is on,
 	 * otherwise we might end up blatting error messages to the socket */
 	loadhostkeys();
+
+    seedrandom();
 }
 
 /* Set up listening sockets for all the requested ports */
-static int listensockets(int *sock, int sockcount, int *maxfd) {
+static size_t listensockets(int *sock, size_t sockcount, int *maxfd) {
 	
 	unsigned int i;
 	char* errstring = NULL;
-	unsigned int sockpos = 0;
+	size_t sockpos = 0;
 	int nsock;
 
 	TRACE(("listensockets: %d to try\n", svr_opts.portcount))
@@ -381,7 +405,7 @@
 
 		TRACE(("listening on '%s'", svr_opts.ports[i]))
 
-		nsock = dropbear_listen(NULL, svr_opts.ports[i], &sock[sockpos], 
+		nsock = dropbear_listen("", svr_opts.ports[i], &sock[sockpos], 
 				sockcount - sockpos,
 				&errstring, maxfd);