about summary refs log tree commit diff
path: root/Src/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/options.c')
-rw-r--r--Src/options.c148
1 files changed, 67 insertions, 81 deletions
diff --git a/Src/options.c b/Src/options.c
index 328cf318b..425e27dc2 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -607,25 +607,21 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun)
 		}
 		if(!(optno = optlookup(*args))) {
 		    zwarnnam(nam, "no such option: %s", *args);
-		    retval = 1;
-		} else {
-		    retval = !!dosetopt(optno, action, 0, opts);
-		    if (retval) {
-			zwarnnam(nam, "can't change option: %s", *args);
-		    }
+		    retval |= 1;
+		} else if (dosetopt(optno, action, 0, opts)) {
+		    zwarnnam(nam, "can't change option: %s", *args);
+		    retval |= 1;
 		}
 		break;
 	    } else if(**args == 'm') {
 		match = 1;
 	    } else {
-	    	if (!(optno = optlookupc(**args))) {
+		if (!(optno = optlookupc(**args))) {
 		    zwarnnam(nam, "bad option: -%c", **args);
-		    retval = 1;
-		} else {
-		    retval = !!dosetopt(optno, action, 0, opts);
-		    if (retval) {
-			zwarnnam(nam, "can't change option: -%c", **args);
-		    }
+		    retval |= 1;
+		} else if (dosetopt(optno, action, 0, opts)) {
+		    zwarnnam(nam, "can't change option: -%c", **args);
+		    retval |= 1;
 		}
 	    }
 	}
@@ -638,12 +634,10 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun)
 	while (*args) {
 	    if(!(optno = optlookup(*args++))) {
 		zwarnnam(nam, "no such option: %s", args[-1]);
-		retval = 1;
-	    } else {
-		retval = !!dosetopt(optno, !isun, 0, opts);
-		if (retval) {
-		    zwarnnam(nam, "can't change option: %s", args[-1]);
-		}
+		retval |= 1;
+	    } else if (dosetopt(optno, !isun, 0, opts)) {
+		zwarnnam(nam, "can't change option: %s", args[-1]);
+		retval |= 1;
 	    }
 	}
     } else {
@@ -667,7 +661,7 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun)
 	    tokenize(s);
 	    if (!(pprog = patcompile(s, PAT_HEAPDUP, NULL))) {
 		zwarnnam(nam, "bad pattern: %s", *args);
-		retval = 1;
+		retval |= 1;
 		break;
 	    }
 	    /* Loop over expansions. */
@@ -787,100 +781,92 @@ dosetopt(int optno, int value, int force, char *new_opts)
     } else if(optno == PRIVILEGED && !value) {
 	/* unsetting PRIVILEGED causes the shell to make itself unprivileged */
 
-	int skip_setuid = 0;
-	int skip_setgid = 0;
-
-#if defined(HAVE_GETEGID) && defined(HAVE_SETGID) && defined(HAVE_GETUID)
-	int orig_egid = getegid();
-#endif
+	/* If set, return -1 so lastval will be non-zero. */
+	int failed = 0;
 
-#if defined(HAVE_GETEUID) && defined(HAVE_GETUID)
-	if (geteuid() == getuid()) {
-	    skip_setuid = 1;
-	}
+#ifdef HAVE_SETUID
+	const int orig_euid = geteuid();
 #endif
+	const int orig_egid = getegid();
 
-#if defined(HAVE_GETEGID) && defined(HAVE_GETGID)
-	if (getegid() == getgid()) {
-	    skip_setgid = 1;
-	}
-#endif
-
-	if (!skip_setgid) {
-	    int setgid_err;
-#ifdef HAVE_SETRESGID
-	    setgid_err = setresgid(getgid(), getgid(), getgid());
-#elif defined(HAVE_SETREGID)
-#if defined(HAVE_GETEGID) && defined(HAVE_SETGID) && defined(HAVE_GETUID)
-	    setgid_err = setregid(getgid(), getgid());
-#else
-	    zwarnnam("unsetopt",
-		"PRIVILEGED: can't drop privileges; setregid available, but cannot check if saved gid changed");
+	/*
+	 * Set the GID first as if we set the UID to non-privileged it
+	 * might be impossible to restore the GID.
+	 */
+	{
+#ifndef HAVE_SETRESGID
+	    zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresgid() and friends not available");
 	    return -1;
-#endif
 #else
-	    zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresgid and setregid not available");
-	    return -1;
-#endif
+	    int setgid_err;
+	    setgid_err = setresgid(getgid(), getgid(), getgid());
 	    if (setgid_err) {
 		zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change group ID: %e", errno);
 		return -1;
 	    }
+#endif
 	}
 
-	if (!skip_setuid) {
-#if defined(HAVE_GETEUID) && defined(HAVE_SETUID)
-	    int orig_euid = geteuid();
-#endif
+	/* Set the UID second. */
+	{
+#ifndef HAVE_SETRESUID
+	    zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresuid() and friends not available");
+	    return -1;
+#else
 	    int setuid_err;
-#if defined(HAVE_GETEUID) && defined(HAVE_INITGROUPS) && defined(HAVE_GETPWUID)
+
+# ifdef HAVE_INITGROUPS
+	    /* Set the supplementary groups list. */
 	    if (geteuid() == 0) {
 		struct passwd *pw = getpwuid(getuid());
 		if (pw == NULL) {
-		    zwarnnam("unsetopt", "can't drop privileges; failed to get user information for uid %d: %e",
-			    getuid(), errno);
-		    return -1;
-		}
-		if (initgroups(pw->pw_name, pw->pw_gid)) {
+		    zwarnnam("unsetopt", "can't drop privileges; failed to get user information for uid %L: %e",
+			    (long)getuid(), errno);
+		    failed = 1;
+		} else if (initgroups(pw->pw_name, pw->pw_gid)) {
 		    zwarnnam("unsetopt", "can't drop privileges; failed to set supplementary group list: %e", errno);
 		    return -1;
 		}
+	    } else if (getuid() != 0 &&
+		    (geteuid() != getuid() || orig_egid != getegid())) {
+		zwarnnam("unsetopt", "PRIVILEGED: supplementary group list not changed due to lack of permissions: EUID=%L",
+			(long)geteuid());
+		failed = 1;
 	    }
-#endif
+# else
+	    /* initgroups() isn't in POSIX.  If it's not available on the system,
+	     * we silently skip it. */
+# endif
 
-#ifdef HAVE_SETRESUID
 	    setuid_err = setresuid(getuid(), getuid(), getuid());
-#elif defined(HAVE_SETREUID)
-#if defined(HAVE_GETEUID) && defined(HAVE_SETUID) && defined(HAVE_GETUID)
-	    setuid_err = setreuid(getuid(), getuid());
-#else
-	    zwarnnam("unsetopt",
-		"PRIVILEGED: can't drop privileges; setreuid available, but cannot check if saved uid changed");
-	    return -1;
-#endif
-#else
-	    zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresuid and setreuid not available");
-	    return -1;
-#endif
 	    if (setuid_err) {
 		zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change user ID: %e", errno);
 		return -1;
 	    }
-#if defined(HAVE_GETEUID) && defined(HAVE_SETUID) && defined(HAVE_GETUID)
-	    if (getuid() != 0 && !setuid(orig_euid)) {
-		zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the euid");
-		return -1;
-	    }
 #endif
 	}
 
-#if defined(HAVE_GETEGID) && defined(HAVE_SETGID) && defined(HAVE_GETUID)
-	if (getuid() != 0 && !skip_setgid && !setgid(orig_egid)) {
+#ifdef HAVE_SETGID
+	if (getuid() != 0 && orig_egid != getegid() &&
+		(setgid(orig_egid) != -1 || setegid(orig_egid) != -1)) {
 	    zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the egid");
 	    return -1;
 	}
 #endif
 
+#ifdef HAVE_SETUID
+	if (getuid() != 0 && orig_euid != geteuid() &&
+		(setuid(orig_euid) != -1 || seteuid(orig_euid) != -1)) {
+	    zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the euid");
+	    return -1;
+	}
+#endif
+
+	if (failed) {
+	    /* A warning message has been printed. */
+	    return -1;
+	}
+
 #ifdef JOB_CONTROL
     } else if (!force && optno == MONITOR && value) {
 	if (new_opts[optno] == value)