Add extra groups and capabilities to shell user

This allows things like logcat, reboot, internet, SD card access, etc. to
work in an ssh shell like it would in an adb shell.

Change-Id: I206b8b69fd437c611613c7d81b4a926a941e8030
Signed-off-by: Mike Lockwood <lockwood@google.com>
diff --git a/uidswap.c b/uidswap.c
index 8376483..bc6194e 100644
--- a/uidswap.c
+++ b/uidswap.c
@@ -27,6 +27,12 @@
 #include "uidswap.h"
 #include "xmalloc.h"
 
+#ifdef ANDROID
+#include <private/android_filesystem_config.h>
+#include <linux/capability.h>
+#include <linux/prctl.h>
+#endif
+
 /*
  * Note: all these functions must work in all of the following cases:
  *    1. euid=0, ruid=0
@@ -212,6 +218,10 @@
 {
 	uid_t old_uid = getuid();
 	gid_t old_gid = getgid();
+#ifdef ANDROID
+	struct __user_cap_header_struct header;
+	struct __user_cap_data_struct cap;
+#endif
 
 	if (pw == NULL)
 		fatal("permanently_set_uid: no user given");
@@ -220,6 +230,27 @@
 	debug("permanently_set_uid: %u/%u", (u_int)pw->pw_uid,
 	    (u_int)pw->pw_gid);
 
+#ifdef ANDROID
+	if (pw->pw_uid == AID_SHELL) {
+		prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+		/* add extra groups needed for shell user:
+		** AID_LOG to read system logs (adb logcat)
+		** AID_INPUT to diagnose input issues (getevent)
+		** AID_INET to diagnose network issues (netcfg, ping)
+		** AID_GRAPHICS to access the frame buffer
+		** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+		** AID_SDCARD_RW to allow writing to the SD card
+		** AID_MOUNT to allow unmounting the SD card before rebooting
+		** AID_NET_BW_STATS to read out qtaguid statistics
+		*/
+		gid_t groups[] = { AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
+						   AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_RW,
+						   AID_MOUNT, AID_NET_BW_STATS };
+		setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+	}
+#endif
+
 #if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID)
 	if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) < 0)
 		fatal("setresgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno));
@@ -285,4 +316,16 @@
 		    __func__, (u_int)getuid(), (u_int)geteuid(),
 		    (u_int)pw->pw_uid);
 	}
+
+#ifdef ANDROID
+	if (pw->pw_uid == AID_SHELL) {
+		/* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
+		header.version = _LINUX_CAPABILITY_VERSION;
+		header.pid = 0;
+		cap.effective = cap.permitted = (1 << CAP_SYS_BOOT);
+		cap.inheritable = 0;
+		capset(&header, &cap);
+	}
+#endif
+
 }