o The suidgw finds /usr/lib/suidgw/$SCRIPT and checks that the current
(real) user is allowed to run it.
- o Then it switches the effective and saved UID and runs the script.
+ o Then it switches real, effective, and saved UID and runs the script.
Environment variables are sanitized (currently, the whole environment
is reset; in the future, we may propagate some variables if needed)
and so are file descriptors (we make sure that fd's 0 to 2 exist).
o The action is logged to the syslog (facility auth, level info).
+
+
+CAVEAT: We do not emulate proper POSIX real/effective/saved UID semantics,
+because when a recent Perl interpreter detects that real != effective, it
+refuses to run. Therefore we set all three UIDs and GIDs to the new effective
+user/group and record the ID's of the caller in environment variables ORIG_UID
+and ORIG_GID. Still, Linux kernel notices the UID changes and marks the task
+as undumpable, so this should be secure.
"/usr/local/lib/suidgw",
"/usr/lib/suidgw",
#ifdef DEBUG
- "./scripts",
+ "./tests/scripts",
#endif
NULL
};
+static char env_orig_uid[32], env_orig_gid[32];
+
static char *sanitized_env[] = {
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ env_orig_uid,
+ env_orig_gid,
NULL
};
close(fd);
}
+static void sanitize_env(void)
+{
+ snprintf(env_orig_uid, sizeof(env_orig_uid), "ORIG_UID=%d", (int) getuid());
+ snprintf(env_orig_gid, sizeof(env_orig_gid), "ORIG_GID=%d", (int) getgid());
+}
+
static bool get_program_name(const char *arg0)
{
// If arg0 is a path, extract the last component
static void switch_ugid(void)
{
- if (setresgid(getgid(), use_gid, use_gid) < 0)
+ if (setresgid(use_gid, use_gid, use_gid) < 0)
die("Failed to set group id: %m");
- if (setresuid(getuid(), use_uid, use_uid) < 0)
+ if (setresuid(use_uid, use_uid, use_uid) < 0)
die("Failed to set user id: %m");
}
int main(int argc UNUSED, char **argv)
{
sanitize_fds();
+ sanitize_env();
if (geteuid())
die("Must be run setuid");