xref: /freebsd/crypto/openssh/uidswap.c (revision 1e8db6e2f63ea90b361b3bbc9ebe9990660cb596)
1511b41d2SMark Murray /*
2511b41d2SMark Murray  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4511b41d2SMark Murray  *                    All rights reserved
5511b41d2SMark Murray  * Code for uid-swapping.
6b66f2d16SKris Kennaway  *
7b66f2d16SKris Kennaway  * As far as I am concerned, the code I have written for this software
8b66f2d16SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
9b66f2d16SKris Kennaway  * software must be clearly marked as such, and if the derived work is
10b66f2d16SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
11b66f2d16SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
12511b41d2SMark Murray  */
13511b41d2SMark Murray 
14511b41d2SMark Murray #include "includes.h"
151e8db6e2SBrian Feldman RCSID("$OpenBSD: uidswap.c,v 1.16 2001/04/20 16:32:22 markus Exp $");
16511b41d2SMark Murray 
171e8db6e2SBrian Feldman #include "log.h"
18511b41d2SMark Murray #include "uidswap.h"
19511b41d2SMark Murray 
20511b41d2SMark Murray /*
21511b41d2SMark Murray  * Note: all these functions must work in all of the following cases:
22511b41d2SMark Murray  *    1. euid=0, ruid=0
23511b41d2SMark Murray  *    2. euid=0, ruid!=0
24511b41d2SMark Murray  *    3. euid!=0, ruid!=0
25511b41d2SMark Murray  * Additionally, they must work regardless of whether the system has
26511b41d2SMark Murray  * POSIX saved uids or not.
27511b41d2SMark Murray  */
28511b41d2SMark Murray 
29511b41d2SMark Murray /* Lets assume that posix saved ids also work with seteuid, even though that
30511b41d2SMark Murray    is not part of the posix specification. */
31511b41d2SMark Murray 
32511b41d2SMark Murray /* Saved effective uid. */
331e8db6e2SBrian Feldman static int	privileged = 0;
341e8db6e2SBrian Feldman static int	temporarily_use_uid_effective = 0;
35511b41d2SMark Murray static uid_t	saved_euid = 0;
361e8db6e2SBrian Feldman static gid_t	saved_egid;
371e8db6e2SBrian Feldman static gid_t	saved_egroups[NGROUPS_MAX], user_groups[NGROUPS_MAX];
381e8db6e2SBrian Feldman static int	saved_egroupslen = -1, user_groupslen = -1;
39511b41d2SMark Murray 
40511b41d2SMark Murray /*
41511b41d2SMark Murray  * Temporarily changes to the given uid.  If the effective user
42511b41d2SMark Murray  * id is not root, this does nothing.  This call cannot be nested.
43511b41d2SMark Murray  */
44511b41d2SMark Murray void
451e8db6e2SBrian Feldman temporarily_use_uid(struct passwd *pw)
46511b41d2SMark Murray {
471e8db6e2SBrian Feldman 	/* Save the current euid, and egroups. */
48511b41d2SMark Murray 	saved_euid = geteuid();
491e8db6e2SBrian Feldman 	debug("temporarily_use_uid: %d/%d (e=%d)",
501e8db6e2SBrian Feldman 	    pw->pw_uid, pw->pw_gid, saved_euid);
511e8db6e2SBrian Feldman 	if (saved_euid != 0) {
521e8db6e2SBrian Feldman 		privileged = 0;
531e8db6e2SBrian Feldman 		return;
541e8db6e2SBrian Feldman 	}
551e8db6e2SBrian Feldman 	privileged = 1;
561e8db6e2SBrian Feldman 	temporarily_use_uid_effective = 1;
571e8db6e2SBrian Feldman 	saved_egid = getegid();
581e8db6e2SBrian Feldman 	saved_egroupslen = getgroups(NGROUPS_MAX, saved_egroups);
591e8db6e2SBrian Feldman 	if (saved_egroupslen < 0)
601e8db6e2SBrian Feldman 		fatal("getgroups: %.100s", strerror(errno));
61511b41d2SMark Murray 
621e8db6e2SBrian Feldman 	/* set and save the user's groups */
631e8db6e2SBrian Feldman 	if (user_groupslen == -1) {
641e8db6e2SBrian Feldman 		if (initgroups(pw->pw_name, pw->pw_gid) < 0)
651e8db6e2SBrian Feldman 			fatal("initgroups: %s: %.100s", pw->pw_name,
661e8db6e2SBrian Feldman 			    strerror(errno));
671e8db6e2SBrian Feldman 		user_groupslen = getgroups(NGROUPS_MAX, user_groups);
681e8db6e2SBrian Feldman 		if (user_groupslen < 0)
691e8db6e2SBrian Feldman 			fatal("getgroups: %.100s", strerror(errno));
701e8db6e2SBrian Feldman 	}
71511b41d2SMark Murray 	/* Set the effective uid to the given (unprivileged) uid. */
721e8db6e2SBrian Feldman 	if (setgroups(user_groupslen, user_groups) < 0)
731e8db6e2SBrian Feldman 		fatal("setgroups: %.100s", strerror(errno));
741e8db6e2SBrian Feldman 	pw->pw_gid = pw->pw_gid;
751e8db6e2SBrian Feldman 	if (setegid(pw->pw_gid) < 0)
761e8db6e2SBrian Feldman 		fatal("setegid %u: %.100s", (u_int) pw->pw_gid,
771e8db6e2SBrian Feldman 		    strerror(errno));
781e8db6e2SBrian Feldman 	if (seteuid(pw->pw_uid) == -1)
791e8db6e2SBrian Feldman 		fatal("seteuid %u: %.100s", (u_int) pw->pw_uid,
801e8db6e2SBrian Feldman 		    strerror(errno));
81511b41d2SMark Murray }
82511b41d2SMark Murray 
83511b41d2SMark Murray /*
841e8db6e2SBrian Feldman  * Restores to the original (privileged) uid.
85511b41d2SMark Murray  */
86511b41d2SMark Murray void
871e8db6e2SBrian Feldman restore_uid(void)
88511b41d2SMark Murray {
891e8db6e2SBrian Feldman 	debug("restore_uid");
901e8db6e2SBrian Feldman 	/* it's a no-op unless privileged */
911e8db6e2SBrian Feldman 	if (!privileged)
921e8db6e2SBrian Feldman 		return;
931e8db6e2SBrian Feldman 	if (!temporarily_use_uid_effective)
941e8db6e2SBrian Feldman 		fatal("restore_uid: temporarily_use_uid not effective");
951e8db6e2SBrian Feldman 	/* Set the effective uid back to the saved privileged uid. */
96511b41d2SMark Murray 	if (seteuid(saved_euid) < 0)
971e8db6e2SBrian Feldman 		fatal("seteuid %u: %.100s", (u_int) saved_euid, strerror(errno));
981e8db6e2SBrian Feldman 	if (setgroups(saved_egroupslen, saved_egroups) < 0)
991e8db6e2SBrian Feldman 		fatal("setgroups: %.100s", strerror(errno));
1001e8db6e2SBrian Feldman 	if (setegid(saved_egid) < 0)
1011e8db6e2SBrian Feldman 		fatal("setegid %u: %.100s", (u_int) saved_egid, strerror(errno));
1021e8db6e2SBrian Feldman 	temporarily_use_uid_effective = 0;
103511b41d2SMark Murray }
104511b41d2SMark Murray 
105511b41d2SMark Murray /*
106511b41d2SMark Murray  * Permanently sets all uids to the given uid.  This cannot be
107511b41d2SMark Murray  * called while temporarily_use_uid is effective.
108511b41d2SMark Murray  */
109511b41d2SMark Murray void
1101e8db6e2SBrian Feldman permanently_set_uid(struct passwd *pw)
111511b41d2SMark Murray {
1121e8db6e2SBrian Feldman 	if (temporarily_use_uid_effective)
1131e8db6e2SBrian Feldman 		fatal("restore_uid: temporarily_use_uid effective");
1141e8db6e2SBrian Feldman 	if (setgid(pw->pw_gid) < 0)
1151e8db6e2SBrian Feldman 		fatal("setgid %u: %.100s", (u_int) pw->pw_gid, strerror(errno));
1161e8db6e2SBrian Feldman 	if (setuid(pw->pw_uid) < 0)
1171e8db6e2SBrian Feldman 		fatal("setuid %u: %.100s", (u_int) pw->pw_uid, strerror(errno));
118511b41d2SMark Murray }
119