From 772ac0b2fcd274f61fa2e7363a7943742f6c29a6 Mon Sep 17 00:00:00 2001
From: deuce <>
Date: Tue, 2 Sep 2003 01:14:56 +0000
Subject: [PATCH] Linux will now (sort of) run as a non-root user.  After hours
 of trying to track down the issue, I finally gave up... as a result, there is
 a new feature!

Linux will no longer completely drop it's root privs (It never really did
anyways, and you couldn't possibly make it... but now it does so even less)

As a result, Linux can now recycle all servers when running as non-root.

From a security standpoint, doing this is more secure than running as root,
but less secure than the behaviour on POSIX.4 compliant pthreads.  Running
the BBS as root means that if a user can create a file with the name of his
choice, or pass *any* command through to a shell, that user will get root
access to the machine.  Using the new behaviour, the user would need to
trick the Synchronet binary itself into executing arbitrary and specially
crafted code... probobly using the dreaded buffer overflow... of which
there are probobly some in the web server code.  :-)  If the user can do
this much more tricky feat, then the user gets root privs.  If not, the
user will have to find something else to exploit on your system.

Knowing that some *BSD users (surely not OpenBSD users though) will want to
trade security for convenience, I stole a page out of the Sendmail book and
implemented a "DONT_BLAME_SYNCHRONET" make option.  Compiling like this:
gmake DONT_BLAME_SYNCHRONET=1

Will implement this same behaviour on non-Linux platforms.  Allowing this
partial security feature.
---
 src/sbbs3/GNUmakefile |  4 ++++
 src/sbbs3/ftpsrvr.c   | 13 +++++++++----
 src/sbbs3/mailsrvr.c  | 17 +++++++++++------
 src/sbbs3/main.cpp    | 13 +++++++++----
 src/sbbs3/sbbscon.c   | 44 ++++++++++++++++++++++++-------------------
 src/sbbs3/services.c  | 12 ++++++++----
 src/sbbs3/websrvr.c   | 14 +++++++++-----
 7 files changed, 75 insertions(+), 42 deletions(-)

diff --git a/src/sbbs3/GNUmakefile b/src/sbbs3/GNUmakefile
index a10cc0d7f2..ece7b1459c 100644
--- a/src/sbbs3/GNUmakefile
+++ b/src/sbbs3/GNUmakefile
@@ -164,6 +164,10 @@ ifndef NSPRDIR
  NSPRDIR := ../../lib/mozilla/nspr/$(os).$(BUILD)
 endif
 
+ifdef DONT_BLAME_SYNCHRONET
+ LFLAGS += -DDONT_BLAME_SYNCHRONET
+endif
+
 LFLAGS += -L$(JSLIBDIR) -l$(JSLIB)
 
 # The following are needed for echocfg (uses UIFC)
diff --git a/src/sbbs3/ftpsrvr.c b/src/sbbs3/ftpsrvr.c
index be43a44013..ad4ba4ea23 100644
--- a/src/sbbs3/ftpsrvr.c
+++ b/src/sbbs3/ftpsrvr.c
@@ -4495,6 +4495,10 @@ void DLLCALL ftp_server(void* arg)
 
 	startup=(ftp_startup_t*)arg;
 
+#ifdef _THREAD_SUID_BROKEN
+	startup->seteuid(TRUE);
+#endif
+
     if(startup==NULL) {
     	sbbs_beep(100,500);
     	fprintf(stderr, "No startup structure passed!\n");
@@ -4531,6 +4535,7 @@ void DLLCALL ftp_server(void* arg)
 	served=0;
 	startup->recycle_now=FALSE;
 	recycle_server=TRUE;
+
 	do {
 
 		thread_up(FALSE /* setuid */);
@@ -4660,10 +4665,6 @@ void DLLCALL ftp_server(void* arg)
 			return;
 		}
 
-		/* signal caller that we've started up successfully */
-		if(startup->started!=NULL)
-    		startup->started();
-
 		lprintf("%04d FTP Server thread started on port %d",server_socket,startup->port);
 		status(STATUS_WFC);
 
@@ -4675,6 +4676,10 @@ void DLLCALL ftp_server(void* arg)
 				initialized=t;
 		}
 
+		/* signal caller that we've started up successfully */
+		if(startup->started!=NULL)
+    		startup->started();
+
 		while(server_socket!=INVALID_SOCKET) {
 
 			if(!(startup->options&FTP_OPT_NO_RECYCLE)) {
diff --git a/src/sbbs3/mailsrvr.c b/src/sbbs3/mailsrvr.c
index a7f509a6c9..a66c9fab11 100644
--- a/src/sbbs3/mailsrvr.c
+++ b/src/sbbs3/mailsrvr.c
@@ -2941,10 +2941,10 @@ static void sendmail_thread(void* arg)
 	smb_t		smb;
 	smbmsg_t	msg;
 
-	sendmail_running=TRUE;
-
 	thread_up(TRUE /* setuid */);
 
+	sendmail_running=TRUE;
+
 	lprintf("0000 SendMail thread started");
 
 	memset(&msg,0,sizeof(msg));
@@ -3346,6 +3346,10 @@ void DLLCALL mail_server(void* arg)
 
 	startup=(mail_startup_t*)arg;
 
+#ifdef _THREAD_SUID_BROKEN
+	startup->seteuid(TRUE);
+#endif
+
     if(startup==NULL) {
     	sbbs_beep(100,500);
     	fprintf(stderr, "No startup structure passed!\n");
@@ -3375,6 +3379,7 @@ void DLLCALL mail_server(void* arg)
 	served=0;
 	startup->recycle_now=FALSE;
 	recycle_server=TRUE;
+
 	do {
 
 		thread_up(FALSE /* setuid */);
@@ -3548,10 +3553,6 @@ void DLLCALL mail_server(void* arg)
 		if(!(startup->options&MAIL_OPT_NO_SENDMAIL))
 			_beginthread(sendmail_thread, 0, NULL);
 
-		/* signal caller that we've started up successfully */
-		if(startup->started!=NULL)
-    		startup->started();
-
 		lprintf("%04d Mail Server thread started",server_socket);
 		status(STATUS_WFC);
 
@@ -3563,6 +3564,10 @@ void DLLCALL mail_server(void* arg)
 				initialized=t;
 		}
 
+		/* signal caller that we've started up successfully */
+		if(startup->started!=NULL)
+    		startup->started();
+
 		while(server_socket!=INVALID_SOCKET) {
 
 			if(!(startup->options&MAIL_OPT_NO_RECYCLE)) {
diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp
index 8c4756afd6..c0c0609ef2 100644
--- a/src/sbbs3/main.cpp
+++ b/src/sbbs3/main.cpp
@@ -3540,6 +3540,10 @@ void DLLCALL bbs_thread(void* arg)
 		return;
 	}
 
+#ifdef _THREAD_SUID_BROKEN
+	startup->seteuid(TRUE);
+#endif
+
 	/* Setup intelligent defaults */
 	if(startup->telnet_port==0)				startup->telnet_port=IPPORT_TELNET;
 	if(startup->rlogin_port==0)				startup->rlogin_port=513;
@@ -3806,10 +3810,6 @@ void DLLCALL bbs_thread(void* arg)
 		lprintf("RLogin server listening on port %d",startup->rlogin_port);
 	}
 
-	/* signal caller that we've started up successfully */
-    if(startup->started!=NULL)
-    	startup->started();
-
 	sbbs = new sbbs_t(0, server_addr.sin_addr.s_addr
 		,"BBS System", telnet_socket, &scfg, text, NULL);
     sbbs->online = 0;
@@ -3930,6 +3930,11 @@ void DLLCALL bbs_thread(void* arg)
 	}
 #endif // __unix__ (unix-domain spy sockets)
 
+	/* signal caller that we've started up successfully */
+    if(startup->started!=NULL)
+    	startup->started();
+
+
 	while(telnet_socket!=INVALID_SOCKET) {
 
 		if(node_threads_running==0 && !event_mutex_locked) {	/* check for re-run flags */
diff --git a/src/sbbs3/sbbscon.c b/src/sbbs3/sbbscon.c
index a3b36dfec8..487608d377 100644
--- a/src/sbbs3/sbbscon.c
+++ b/src/sbbs3/sbbscon.c
@@ -229,25 +229,6 @@ static int lputs(char *str)
 }
 
 #ifdef __unix__
-/**********************************************************
-* Change uid of the calling process to the user if specified
-* **********************************************************/
-static BOOL do_setuid(void) 
-{
-	BOOL	result=FALSE;
-
-	setregid(-1,old_gid);
-	setreuid(-1,old_uid);
-	if(!setregid(new_gid,new_gid) && !setreuid(new_uid,new_uid)) 
-		result=TRUE;
-
-	if(!result) {
-		lputs("!setuid FAILED");
-		lputs(strerror(errno));
-	}
-	return result;
-}
-
 /**********************************************************
 * Change uid of the calling process to the user if specified
 * **********************************************************/
@@ -287,6 +268,29 @@ static BOOL do_seteuid(BOOL to_new)
 	}
 	return result;
 }
+
+/**********************************************************
+* Change uid of the calling process to the user if specified
+* **********************************************************/
+static BOOL do_setuid(void) 
+{
+#if defined(_THREAD_SUID_BROKEN) || defined(DONT_BLAME_SYNCHRONET)
+	return(do_seteuid(TRUE));
+#else
+	BOOL	result=FALSE;
+
+	setregid(-1,old_gid);
+	setreuid(-1,old_uid);
+	if(!setregid(new_gid,new_gid) && !setreuid(new_uid,new_uid)) 
+		result=TRUE;
+
+	if(!result) {
+		lputs("!setuid FAILED");
+		lputs(strerror(errno));
+	}
+	return result;
+#endif
+}
 #endif   /* __unix__ */
 
 #ifdef _WINSOCKAPI_
@@ -1537,6 +1541,7 @@ int main(int argc, char** argv)
 			/* ToDo: Something seems to be broken here on FreeBSD now */
 			/* ToDo: Now, they try to re-bind on FreeBSD */
 			/* ToDo: Seems like I switched problems with Linux */
+#if defined(DONT_BLAME_SYNCHRONET) || defined(_THREAD_SUID_BROKEN)
  			if(bbs_startup.telnet_port < IPPORT_RESERVED
 				|| (bbs_startup.options & BBS_OPT_ALLOW_RLOGIN
 					&& bbs_startup.rlogin_port < IPPORT_RESERVED))
@@ -1551,6 +1556,7 @@ int main(int argc, char** argv)
 				mail_startup.options|=MAIL_OPT_NO_RECYCLE;
 			/* Perhaps a BBS_OPT_NO_RECYCLE_LOW option? */
 			services_startup.options|=BBS_OPT_NO_RECYCLE;
+#endif
 		}
 	}
 
diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c
index ff618b41fb..0a5da0545a 100644
--- a/src/sbbs3/services.c
+++ b/src/sbbs3/services.c
@@ -1590,6 +1590,10 @@ void DLLCALL services_thread(void* arg)
 		return;
 	}
 
+#ifdef _THREAD_SUID_BROKEN
+	startup->seteuid(TRUE);
+#endif
+
 	/* Setup intelligent defaults */
 	if(startup->sem_chk_freq==0)			startup->sem_chk_freq=5;
 	if(startup->js_max_bytes==0)			startup->js_max_bytes=JAVASCRIPT_MAX_BYTES;
@@ -1769,10 +1773,6 @@ void DLLCALL services_thread(void* arg)
 				_beginthread(js_static_service_thread, 0, &service[i]);
 		}
 
-		/* signal caller that we've started up successfully */
-		if(startup->started!=NULL)
-    		startup->started();
-
 		status("Listening");
 
 		if(initialized==0) {
@@ -1785,6 +1785,10 @@ void DLLCALL services_thread(void* arg)
 			
 		terminated=FALSE;
 
+		/* signal caller that we've started up successfully */
+		if(startup->started!=NULL)
+    		startup->started();
+
 		/* Main Server Loop */
 		while(!terminated) {
 
diff --git a/src/sbbs3/websrvr.c b/src/sbbs3/websrvr.c
index 9be2877615..29486406db 100644
--- a/src/sbbs3/websrvr.c
+++ b/src/sbbs3/websrvr.c
@@ -2264,7 +2264,7 @@ void http_session_thread(void* arg)
 	socket=session.socket;
 	lprintf("%04d Session thread started", session.socket);
 
-	thread_up(FALSE /* setuid */);
+	thread_up(TRUE /* setuid */);
 	session.finished=FALSE;
 
 	if(startup->options&BBS_OPT_NO_HOST_LOOKUP)
@@ -2435,6 +2435,10 @@ void DLLCALL web_server(void* arg)
 		return;
 	}
 
+#ifdef _THREAD_SUID_BROKEN
+	startup->seteuid(TRUE);
+#endif
+
 	/* Setup intelligent defaults */
 	if(startup->port==0)					startup->port=IPPORT_HTTP;
 	if(startup->root_dir[0]==0)				SAFECOPY(startup->root_dir,"../html");
@@ -2582,14 +2586,14 @@ void DLLCALL web_server(void* arg)
 		lprintf("Web Server listening on port %d",startup->port);
 		status("Listening");
 
-		/* signal caller that we've started up successfully */
-		if(startup->started!=NULL)
-    		startup->started();
-
 		lprintf("Web Server thread started");
 
 		sprintf(path,"%swebsrvr.rec",scfg.ctrl_dir);
 
+		/* signal caller that we've started up successfully */
+		if(startup->started!=NULL)
+    		startup->started();
+
 		while(server_socket!=INVALID_SOCKET) {
 
 			/* check for re-cycle semaphores */
-- 
GitLab