>From 0349a5aef2b81a367dc2c0895c17a3eda861a67f Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Thu, 4 Apr 2013 11:32:51 -0400
Subject: [PATCH] Further restrict become_user drop of privileges.

We never need to regain root after we call become_user() so tighten up even
further our privilege drop.

Add a setgroups() call to remove all secondary groups root may have been given
for whateve reason. Then use the setres[ug]id function to also drop the saved
uid/gid so the process cannot regain back root id.
Capabilities are also implicitly dropped here, no more CAP_SETUID so this is a
Point of No Return, once changed to non-root the process can't get back.

Remove redefinition of sys/types.h and unistd.h, they are already defined in
util.h and they need to be included after _GNU_SOURCE/_BSD_SOURCE is defined
or the prototypes for setres[ug]id will not be found.
Add grp.h after util.h for the same reason.
---
 src/providers/krb5/krb5_become_user.c | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/src/providers/krb5/krb5_become_user.c b/src/providers/krb5/krb5_become_user.c
index 082d141534cd12a02ee8a0ed5fa66114e7adfc73..535177211be8df4e430bbe89206cc019284e2162 100644
--- a/src/providers/krb5/krb5_become_user.c
+++ b/src/providers/krb5/krb5_become_user.c
@@ -22,45 +22,40 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include <sys/types.h>
-#include <unistd.h>
-
 #include "util/util.h"
+#include <grp.h>
 
 errno_t become_user(uid_t uid, gid_t gid)
 {
     int ret;
 
     DEBUG(SSSDBG_FUNC_DATA, ("Trying to become user [%d][%d].\n", uid, gid));
-    ret = setgid(gid);
-    if (ret == -1) {
-        ret = errno;
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              ("setgid failed [%d][%s].\n", ret, strerror(ret)));
-        return ret;
-    }
 
-    ret = setuid(uid);
+    /* drop supplmentary groups first */
+    ret = setgroups(0, NULL);
     if (ret == -1) {
         ret = errno;
         DEBUG(SSSDBG_CRIT_FAILURE,
-              ("setuid failed [%d][%s].\n", ret, strerror(ret)));
+              ("setgroups failed [%d][%s].\n", ret, strerror(ret)));
         return ret;
     }
 
-    ret = setegid(gid);
+    /* change gid so that root cannot be regained (changes saved gid too) */
+    ret = setresgid(gid, gid, gid);
     if (ret == -1) {
         ret = errno;
         DEBUG(SSSDBG_CRIT_FAILURE,
-              ("setegid failed [%d][%s].\n", ret, strerror(ret)));
+              ("setresgid failed [%d][%s].\n", ret, strerror(ret)));
         return ret;
     }
 
-    ret = seteuid(uid);
+    /* change uid so that root cannot be regained (changes saved uid too) */
+    /* this call also takes care of dropping CAP_SETUID, so this is a PNR */
+    ret = setresuid(uid, uid, uid);
     if (ret == -1) {
         ret = errno;
         DEBUG(SSSDBG_CRIT_FAILURE,
-              ("seteuid failed [%d][%s].\n", ret, strerror(ret)));
+              ("setresuid failed [%d][%s].\n", ret, strerror(ret)));
         return ret;
     }
 
-- 
1.8.1.4

