11305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* $OpenBSD: uidswap.c,v 1.35 2006/08/03 03:34:42 deraadt Exp $ */
21305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
31305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Author: Tatu Ylonen <ylo@cs.hut.fi>
41305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
51305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *                    All rights reserved
61305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Code for uid-swapping.
71305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *
81305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * As far as I am concerned, the code I have written for this software
91305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * can be used freely for any purpose.  Any derived versions of this
101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * software must be clearly marked as such, and if the derived work is
111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * incompatible with the protocol description in the RFC file, it must be
121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * called by a name other than "ssh" or "Secure Shell".
131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "includes.h"
161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/param.h>
181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <errno.h>
191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <pwd.h>
201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <string.h>
211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <unistd.h>
221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <stdarg.h>
231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <grp.h>
251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "log.h"
271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "uidswap.h"
281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "xmalloc.h"
291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
302f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood#ifdef ANDROID
312f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood#include <private/android_filesystem_config.h>
3220eda52fd661847ea0b8163f9b97176fa3fe2e8bNick Kralevich#include <sys/capability.h>
332f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood#include <linux/prctl.h>
342f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood#endif
352f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood
361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Note: all these functions must work in all of the following cases:
381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *    1. euid=0, ruid=0
391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *    2. euid=0, ruid!=0
401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *    3. euid!=0, ruid!=0
411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Additionally, they must work regardless of whether the system has
421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * POSIX saved uids or not.
431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#if defined(_POSIX_SAVED_IDS) && !defined(BROKEN_SAVED_UIDS)
461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Lets assume that posix saved ids also work with seteuid, even though that
471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood   is not part of the posix specification. */
481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define SAVED_IDS_WORK_WITH_SETEUID
491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Saved effective uid. */
501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic uid_t 	saved_euid = 0;
511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic gid_t	saved_egid = 0;
521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Saved effective uid. */
551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int	privileged = 0;
561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int	temporarily_use_uid_effective = 0;
571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic gid_t	*saved_egroups = NULL, *user_groups = NULL;
581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int	saved_egroupslen = -1, user_groupslen = -1;
591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Temporarily changes to the given uid.  If the effective user
621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * id is not root, this does nothing.  This call cannot be nested.
631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvoid
651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodtemporarily_use_uid(struct passwd *pw)
661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Save the current euid, and egroups. */
681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef SAVED_IDS_WORK_WITH_SETEUID
691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	saved_euid = geteuid();
701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	saved_egid = getegid();
711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	debug("temporarily_use_uid: %u/%u (e=%u/%u)",
721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    (u_int)pw->pw_uid, (u_int)pw->pw_gid,
731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    (u_int)saved_euid, (u_int)saved_egid);
741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifndef HAVE_CYGWIN
751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (saved_euid != 0) {
761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		privileged = 0;
771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return;
781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#else
811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (geteuid() != 0) {
821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		privileged = 0;
831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return;
841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif /* SAVED_IDS_WORK_WITH_SETEUID */
861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	privileged = 1;
881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	temporarily_use_uid_effective = 1;
891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	saved_egroupslen = getgroups(0, NULL);
911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (saved_egroupslen < 0)
921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("getgroups: %.100s", strerror(errno));
931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (saved_egroupslen > 0) {
941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		saved_egroups = xrealloc(saved_egroups,
951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    saved_egroupslen, sizeof(gid_t));
961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (getgroups(saved_egroupslen, saved_egroups) < 0)
971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fatal("getgroups: %.100s", strerror(errno));
981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	} else { /* saved_egroupslen == 0 */
991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (saved_egroups != NULL)
1001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			xfree(saved_egroups);
1011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
1021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* set and save the user's groups */
1041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (user_groupslen == -1) {
1051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (initgroups(pw->pw_name, pw->pw_gid) < 0)
1061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fatal("initgroups: %s: %.100s", pw->pw_name,
1071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    strerror(errno));
1081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		user_groupslen = getgroups(0, NULL);
1101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (user_groupslen < 0)
1111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fatal("getgroups: %.100s", strerror(errno));
1121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (user_groupslen > 0) {
1131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			user_groups = xrealloc(user_groups,
1141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    user_groupslen, sizeof(gid_t));
1151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (getgroups(user_groupslen, user_groups) < 0)
1161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				fatal("getgroups: %.100s", strerror(errno));
1171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else { /* user_groupslen == 0 */
1181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (user_groups)
1191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				xfree(user_groups);
1201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
1211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
1221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Set the effective uid to the given (unprivileged) uid. */
1231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setgroups(user_groupslen, user_groups) < 0)
1241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setgroups: %.100s", strerror(errno));
1251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifndef SAVED_IDS_WORK_WITH_SETEUID
1261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Propagate the privileged gid to all of our gids. */
1271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setgid(getegid()) < 0)
1281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		debug("setgid %u: %.100s", (u_int) getegid(), strerror(errno));
1291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Propagate the privileged uid to all of our uids. */
1301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setuid(geteuid()) < 0)
1311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		debug("setuid %u: %.100s", (u_int) geteuid(), strerror(errno));
1321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif /* SAVED_IDS_WORK_WITH_SETEUID */
1331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setegid(pw->pw_gid) < 0)
1341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setegid %u: %.100s", (u_int)pw->pw_gid,
1351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    strerror(errno));
1361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (seteuid(pw->pw_uid) == -1)
1371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("seteuid %u: %.100s", (u_int)pw->pw_uid,
1381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    strerror(errno));
1391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
1401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvoid
1421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodpermanently_drop_suid(uid_t uid)
1431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
1441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	uid_t old_uid = getuid();
1451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	debug("permanently_drop_suid: %u", (u_int)uid);
1471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#if defined(HAVE_SETRESUID) && !defined(BROKEN_SETRESUID)
1481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setresuid(uid, uid, uid) < 0)
1491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setresuid %u: %.100s", (u_int)uid, strerror(errno));
1501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#elif defined(HAVE_SETREUID) && !defined(BROKEN_SETREUID)
1511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setreuid(uid, uid) < 0)
1521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setreuid %u: %.100s", (u_int)uid, strerror(errno));
1531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#else
1541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood# ifndef SETEUID_BREAKS_SETUID
1551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (seteuid(uid) < 0)
1561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("seteuid %u: %.100s", (u_int)uid, strerror(errno));
1571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood# endif
1581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setuid(uid) < 0)
1591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setuid %u: %.100s", (u_int)uid, strerror(errno));
1601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
1611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifndef HAVE_CYGWIN
1631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Try restoration of UID if changed (test clearing of saved uid) */
1641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (old_uid != uid &&
1651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
1661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%s: was able to restore old [e]uid", __func__);
1671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
1681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Verify UID drop was successful */
1701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (getuid() != uid || geteuid() != uid) {
1711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%s: euid incorrect uid:%u euid:%u (should be %u)",
1721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    __func__, (u_int)getuid(), (u_int)geteuid(), (u_int)uid);
1731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
1741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
1751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
1771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Restores to the original (privileged) uid.
1781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
1791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvoid
1801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodrestore_uid(void)
1811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
1821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* it's a no-op unless privileged */
1831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!privileged) {
1841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		debug("restore_uid: (unprivileged)");
1851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return;
1861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
1871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!temporarily_use_uid_effective)
1881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("restore_uid: temporarily_use_uid not effective");
1891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef SAVED_IDS_WORK_WITH_SETEUID
1911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	debug("restore_uid: %u/%u", (u_int)saved_euid, (u_int)saved_egid);
1921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Set the effective uid back to the saved privileged uid. */
1931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (seteuid(saved_euid) < 0)
1941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("seteuid %u: %.100s", (u_int)saved_euid, strerror(errno));
1951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setegid(saved_egid) < 0)
1961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setegid %u: %.100s", (u_int)saved_egid, strerror(errno));
1971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#else /* SAVED_IDS_WORK_WITH_SETEUID */
1981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/*
1991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 * We are unable to restore the real uid to its unprivileged value.
2001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 * Propagate the real uid (usually more privileged) to effective uid
2011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 * as well.
2021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 */
2031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	setuid(getuid());
2041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	setgid(getgid());
2051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif /* SAVED_IDS_WORK_WITH_SETEUID */
2061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setgroups(saved_egroupslen, saved_egroups) < 0)
2081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setgroups: %.100s", strerror(errno));
2091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	temporarily_use_uid_effective = 0;
2101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
2111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
2131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Permanently sets all uids to the given uid.  This cannot be
2141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * called while temporarily_use_uid is effective.
2151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
2161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvoid
2171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodpermanently_set_uid(struct passwd *pw)
2181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
2191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	uid_t old_uid = getuid();
2201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	gid_t old_gid = getgid();
2212f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood#ifdef ANDROID
2222f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood	struct __user_cap_header_struct header;
2232f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood	struct __user_cap_data_struct cap;
2242f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood#endif
2251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (pw == NULL)
2271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("permanently_set_uid: no user given");
2281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (temporarily_use_uid_effective)
2291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("permanently_set_uid: temporarily_use_uid effective");
2301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	debug("permanently_set_uid: %u/%u", (u_int)pw->pw_uid,
2311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    (u_int)pw->pw_gid);
2321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2332f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood#ifdef ANDROID
2342f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood	if (pw->pw_uid == AID_SHELL) {
2352f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
2362f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood
2372f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		/* add extra groups needed for shell user:
2382f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		** AID_LOG to read system logs (adb logcat)
2392f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		** AID_INPUT to diagnose input issues (getevent)
2402f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		** AID_INET to diagnose network issues (netcfg, ping)
2412f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		** AID_GRAPHICS to access the frame buffer
2422f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
2432f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		** AID_SDCARD_RW to allow writing to the SD card
2442f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		** AID_MOUNT to allow unmounting the SD card before rebooting
2452f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		** AID_NET_BW_STATS to read out qtaguid statistics
2462f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		*/
2472f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		gid_t groups[] = { AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
2482f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood						   AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_RW,
2492f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood						   AID_MOUNT, AID_NET_BW_STATS };
2502f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		setgroups(sizeof(groups)/sizeof(groups[0]), groups);
2512f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood	}
2522f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood#endif
2532f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood
2541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID)
2551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) < 0)
2561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setresgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno));
2571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#elif defined(HAVE_SETREGID) && !defined(BROKEN_SETREGID)
2581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setregid(pw->pw_gid, pw->pw_gid) < 0)
2591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setregid %u: %.100s", (u_int)pw->pw_gid, strerror(errno));
2601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#else
2611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setegid(pw->pw_gid) < 0)
2621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setegid %u: %.100s", (u_int)pw->pw_gid, strerror(errno));
2631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setgid(pw->pw_gid) < 0)
2641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno));
2651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
2661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef __APPLE__
2681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/*
2691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 * OS X requires initgroups after setgid to opt back into
2701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 * memberd support for >16 supplemental groups.
2711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 */
2721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (initgroups(pw->pw_name, pw->pw_gid) < 0)
2731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("initgroups %.100s %u: %.100s",
2741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    pw->pw_name, (u_int)pw->pw_gid, strerror(errno));
2751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
2761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#if defined(HAVE_SETRESUID) && !defined(BROKEN_SETRESUID)
2781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0)
2791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
2801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#elif defined(HAVE_SETREUID) && !defined(BROKEN_SETREUID)
2811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setreuid(pw->pw_uid, pw->pw_uid) < 0)
2821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setreuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
2831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#else
2841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood# ifndef SETEUID_BREAKS_SETUID
2851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (seteuid(pw->pw_uid) < 0)
2861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("seteuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
2871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood# endif
2881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (setuid(pw->pw_uid) < 0)
2891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("setuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
2901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
2911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifndef HAVE_CYGWIN
2931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Try restoration of GID if changed (test clearing of saved gid) */
2941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (old_gid != pw->pw_gid && pw->pw_uid != 0 &&
2951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    (setgid(old_gid) != -1 || setegid(old_gid) != -1))
2961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%s: was able to restore old [e]gid", __func__);
2971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
2981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Verify GID drop was successful */
3001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (getgid() != pw->pw_gid || getegid() != pw->pw_gid) {
3011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%s: egid incorrect gid:%u egid:%u (should be %u)",
3021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    __func__, (u_int)getgid(), (u_int)getegid(),
3031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (u_int)pw->pw_gid);
3041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
3051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifndef HAVE_CYGWIN
3071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Try restoration of UID if changed (test clearing of saved uid) */
3081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (old_uid != pw->pw_uid &&
3091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
3101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%s: was able to restore old [e]uid", __func__);
3111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
3121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Verify UID drop was successful */
3141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) {
3151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%s: euid incorrect uid:%u euid:%u (should be %u)",
3161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    __func__, (u_int)getuid(), (u_int)geteuid(),
3171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (u_int)pw->pw_uid);
3181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
3192f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood
3202f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood#ifdef ANDROID
3212f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood	if (pw->pw_uid == AID_SHELL) {
3222f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		/* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
3232f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		header.version = _LINUX_CAPABILITY_VERSION;
3242f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		header.pid = 0;
3252f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		cap.effective = cap.permitted = (1 << CAP_SYS_BOOT);
3262f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		cap.inheritable = 0;
3272f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood		capset(&header, &cap);
3282f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood	}
3292f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood#endif
3302f1b934246c78321625e8cb5af8a48ea2c09992fMike Lockwood
3311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
332