use setresuid()/setresgid() instead of setuid()/setgid()
We should be dropping privileges with setresuid()/setresgid() when requested as recommended by "Setuid Demystified" (http://www.cs.berkeley.edu/~daw/papers/setuid-usenix02.pdf).
Also, chdir("/") after chroot() and actually check for proper return values on both. This was modelled after OpenSSH's chroot() logic.
Tested on OpenBSD. Someone should try compiling/testing on Linux to verify. As far as I can tell, the proper syscalls are implemented on Linux as well.
--- src/main.c Mon May 5 18:29:06 2014
+++ src/main.c Thu Nov 27 18:55:34 2014
@@ -377,7 +377,7 @@
fprintf(stderr, "WARNING: Cannot change server root unless running as root.\n");
return;
}
- if(chroot(conf->base_dir))
+ if(chroot(conf->base_dir) == -1 || chdir("/") == -1)
{
fprintf(stderr,"WARNING: Couldn't change server root: %s\n", strerror(errno));
return;
@@ -398,7 +398,7 @@
}
if(uid != (uid_t)-1 && gid != (gid_t)-1) {
- if(!setgid(gid))
+ if(!setresgid(gid, gid, gid))
fprintf(stdout, "Changed groupid to %i.\n", (int)gid);
else
fprintf(stdout, "Error changing groupid: %s.\n", strerror(errno));
@@ -406,7 +406,7 @@
fprintf(stdout, "Changed supplementary groups based on user: %s.\n", conf->user);
else
fprintf(stdout, "Error changing supplementary groups: %s.\n", strerror(errno));
- if(!setuid(uid))
+ if(!setresuid(uid, uid, uid))
fprintf(stdout, "Changed userid to %i.\n", (int)uid);
else
fprintf(stdout, "Error changing userid: %s.\n", strerror(errno));