From 247de4072379c82b2cfcd9895e1c8065cc741691 Mon Sep 17 00:00:00 2001
From: Alexander Barton <alex@barton.de>
Date: Tue, 18 Sep 2012 13:20:46 +0200
Subject: [PATCH] Don't run if changing UID fails, init user before chroot()

Now the logic is as following:

 1. Read UID from configuration ("ServerUID"), if any
 2. If configured UID is root(0):
      - set it to "nobody" if running as root(0)
      - set it to the current user otherwise
 4. Set the configured UID and exit on error
 5. Run as a) current user, b) configured user, c) nobody,
    but _never_run as root.

In addition, the user and group is initialized before enabling the
chroot(), so you don't need the /etc/passwd file inside of it any more.

Patch (mostly) by Federico G. Schwindt, thanks!
---
 src/ngircd/ngircd.c | 65 +++++++++++++++++++++++++----------------------------
 1 file changed, 31 insertions(+), 34 deletions(-)

diff --git a/src/ngircd/ngircd.c b/src/ngircd/ngircd.c
index 585e2ac..ff4c83f 100644
--- a/src/ngircd/ngircd.c
+++ b/src/ngircd/ngircd.c
@@ -594,7 +594,6 @@ NGIRCd_getNobodyID(uid_t *uid, gid_t *gid )
 
 	*uid = pwd->pw_uid;
 	*gid = pwd->pw_gid;
-	endpwent();
 
 	return true;
 } /* NGIRCd_getNobodyID */
@@ -645,7 +644,7 @@ NGIRCd_Init(bool NGIRCd_NoDaemon)
 	bool chrooted = false;
 	struct passwd *pwd;
 	struct group *grp;
-	int real_errno, fd = -1;
+	int fd = -1;
 	pid_t pid;
 
 	if (initialized)
@@ -664,6 +663,32 @@ NGIRCd_Init(bool NGIRCd_NoDaemon)
 		Log(LOG_WARNING,
 		    "Warning: Error during SSL initialization, continuing ...");
 
+	/* Check user ID */
+	if (Conf_UID == 0 && geteuid() == 0) {
+		pwd = getpwuid(0);
+		Log(LOG_INFO,
+		    "ServerUID must not be %s(0), using \"nobody\" instead.",
+		    pwd ? pwd->pw_name : "?");
+		if (!NGIRCd_getNobodyID(&Conf_UID, &Conf_GID)) {
+			Log(LOG_WARNING,
+			    "Could not get user/group ID of user \"nobody\": %s",
+			    errno ? strerror(errno) : "not found" );
+			goto out;
+		}
+	} else if (Conf_UID == 0) {
+		pwd = getpwuid(0);
+		Log(LOG_INFO,
+		    "ServerUID must not be %s(0), using current user instead.",
+		    pwd ? pwd->pw_name : "?");
+		Conf_UID = geteuid();
+	}
+	pwd = getpwuid(Conf_UID);
+
+	/* Check group ID */
+	if (Conf_GID == 0)
+		Conf_GID = pwd->pw_gid;
+	grp = getgrgid(Conf_GID);
+
 	/* Change root */
 	if (Conf_Chroot[0]) {
 		if (chdir(Conf_Chroot) != 0) {
@@ -685,43 +710,23 @@ NGIRCd_Init(bool NGIRCd_NoDaemon)
 		}
 	}
 
-	/* Check user ID */
-	if (Conf_UID == 0) {
-		pwd = getpwuid(0);
-		Log(LOG_INFO,
-		    "ServerUID must not be %s(0), using \"nobody\" instead.",
-		    pwd ? pwd->pw_name : "?");
-		if (!NGIRCd_getNobodyID(&Conf_UID, &Conf_GID)) {
-			Log(LOG_WARNING,
-			    "Could not get user/group ID of user \"nobody\": %s",
-			    errno ? strerror(errno) : "not found" );
-			goto out;
-		}
-	}
-
 	/* Change group ID */
-	if (getgid() != Conf_GID) {
+	if (getegid() != Conf_GID) {
 		if (setgid(Conf_GID) != 0) {
-			real_errno = errno;
-			grp = getgrgid(Conf_GID);
 			Log(LOG_ERR, "Can't change group ID to %s(%u): %s",
 			    grp ? grp->gr_name : "?", Conf_GID,
 			    strerror(errno));
-			if (real_errno != EPERM) 
-				goto out;
+			goto out;
 		}
 	}
 
 	/* Change user ID */
-	if (getuid() != Conf_UID) {
+	if (geteuid() != Conf_UID) {
 		if (setuid(Conf_UID) != 0) {
-			real_errno = errno;
-			pwd = getpwuid(Conf_UID);
 			Log(LOG_ERR, "Can't change user ID to %s(%u): %s",
 			    pwd ? pwd->pw_name : "?", Conf_UID,
 			    strerror(errno));
-			if (real_errno != EPERM)
-				goto out;
+			goto out;
 		}
 	}
 
@@ -763,14 +768,6 @@ NGIRCd_Init(bool NGIRCd_NoDaemon)
 
 	Pidfile_Create(pid);
 
-	/* Check UID/GID we are running as, can be different from values
-	 * configured (e. g. if we were already started with a UID>0. */
-	Conf_UID = getuid();
-	Conf_GID = getgid();
-
-	pwd = getpwuid(Conf_UID);
-	grp = getgrgid(Conf_GID);
-
 	Log(LOG_INFO, "Running as user %s(%ld), group %s(%ld), with PID %ld.",
 	    pwd ? pwd->pw_name : "unknown", (long)Conf_UID,
 	    grp ? grp->gr_name : "unknown", (long)Conf_GID, (long)pid);
-- 
1.7.12

