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