uidswap.c revision 76259
1248590Smm/* 2248590Smm * Author: Tatu Ylonen <ylo@cs.hut.fi> 3248590Smm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4248590Smm * All rights reserved 5248590Smm * Code for uid-swapping. 6248590Smm * 7248590Smm * As far as I am concerned, the code I have written for this software 8248590Smm * can be used freely for any purpose. Any derived versions of this 9248590Smm * software must be clearly marked as such, and if the derived work is 10248590Smm * incompatible with the protocol description in the RFC file, it must be 11248590Smm * called by a name other than "ssh" or "Secure Shell". 12248590Smm */ 13248590Smm 14248590Smm#include "includes.h" 15248590SmmRCSID("$OpenBSD: uidswap.c,v 1.16 2001/04/20 16:32:22 markus Exp $"); 16248590Smm 17248590Smm#include "log.h" 18248590Smm#include "uidswap.h" 19248590Smm 20248590Smm/* 21248590Smm * Note: all these functions must work in all of the following cases: 22248590Smm * 1. euid=0, ruid=0 23248590Smm * 2. euid=0, ruid!=0 24248590Smm * 3. euid!=0, ruid!=0 25248590Smm * Additionally, they must work regardless of whether the system has 26248590Smm * POSIX saved uids or not. 27248590Smm */ 28248590Smm 29248590Smm/* Lets assume that posix saved ids also work with seteuid, even though that 30248590Smm is not part of the posix specification. */ 31248590Smm 32248590Smm/* Saved effective uid. */ 33248590Smmstatic int privileged = 0; 34248590Smmstatic int temporarily_use_uid_effective = 0; 35248590Smmstatic uid_t saved_euid = 0; 36248590Smmstatic gid_t saved_egid; 37248590Smmstatic gid_t saved_egroups[NGROUPS_MAX], user_groups[NGROUPS_MAX]; 38248590Smmstatic int saved_egroupslen = -1, user_groupslen = -1; 39248590Smm 40248590Smm/* 41248590Smm * Temporarily changes to the given uid. If the effective user 42248590Smm * id is not root, this does nothing. This call cannot be nested. 43248590Smm */ 44248590Smmvoid 45248590Smmtemporarily_use_uid(struct passwd *pw) 46248590Smm{ 47248590Smm /* Save the current euid, and egroups. */ 48248590Smm saved_euid = geteuid(); 49248590Smm debug("temporarily_use_uid: %d/%d (e=%d)", 50248590Smm pw->pw_uid, pw->pw_gid, saved_euid); 51248590Smm if (saved_euid != 0) { 52248590Smm privileged = 0; 53248590Smm return; 54248590Smm } 55248590Smm privileged = 1; 56248590Smm temporarily_use_uid_effective = 1; 57248590Smm saved_egid = getegid(); 58248590Smm saved_egroupslen = getgroups(NGROUPS_MAX, saved_egroups); 59248590Smm if (saved_egroupslen < 0) 60248590Smm fatal("getgroups: %.100s", strerror(errno)); 61248590Smm 62248590Smm /* set and save the user's groups */ 63248590Smm if (user_groupslen == -1) { 64248590Smm if (initgroups(pw->pw_name, pw->pw_gid) < 0) 65248590Smm fatal("initgroups: %s: %.100s", pw->pw_name, 66248590Smm strerror(errno)); 67248590Smm user_groupslen = getgroups(NGROUPS_MAX, user_groups); 68248590Smm if (user_groupslen < 0) 69248590Smm fatal("getgroups: %.100s", strerror(errno)); 70248590Smm } 71248590Smm /* Set the effective uid to the given (unprivileged) uid. */ 72248590Smm if (setgroups(user_groupslen, user_groups) < 0) 73248590Smm fatal("setgroups: %.100s", strerror(errno)); 74248590Smm pw->pw_gid = pw->pw_gid; 75248590Smm if (setegid(pw->pw_gid) < 0) 76248590Smm fatal("setegid %u: %.100s", (u_int) pw->pw_gid, 77248590Smm strerror(errno)); 78248590Smm if (seteuid(pw->pw_uid) == -1) 79248590Smm fatal("seteuid %u: %.100s", (u_int) pw->pw_uid, 80248590Smm strerror(errno)); 81248590Smm} 82248590Smm 83248590Smm/* 84248590Smm * Restores to the original (privileged) uid. 85248590Smm */ 86248590Smmvoid 87248590Smmrestore_uid(void) 88248590Smm{ 89248590Smm debug("restore_uid"); 90248590Smm /* it's a no-op unless privileged */ 91248590Smm if (!privileged) 92248590Smm return; 93248590Smm if (!temporarily_use_uid_effective) 94248590Smm fatal("restore_uid: temporarily_use_uid not effective"); 95248590Smm /* Set the effective uid back to the saved privileged uid. */ 96248590Smm if (seteuid(saved_euid) < 0) 97248590Smm fatal("seteuid %u: %.100s", (u_int) saved_euid, strerror(errno)); 98248590Smm if (setgroups(saved_egroupslen, saved_egroups) < 0) 99248590Smm fatal("setgroups: %.100s", strerror(errno)); 100248590Smm if (setegid(saved_egid) < 0) 101248590Smm fatal("setegid %u: %.100s", (u_int) saved_egid, strerror(errno)); 102248590Smm temporarily_use_uid_effective = 0; 103248590Smm} 104248590Smm 105248590Smm/* 106248590Smm * Permanently sets all uids to the given uid. This cannot be 107248590Smm * called while temporarily_use_uid is effective. 108248590Smm */ 109248590Smmvoid 110248590Smmpermanently_set_uid(struct passwd *pw) 111248590Smm{ 112248590Smm if (temporarily_use_uid_effective) 113248590Smm fatal("restore_uid: temporarily_use_uid effective"); 114248590Smm if (setgid(pw->pw_gid) < 0) 115248590Smm fatal("setgid %u: %.100s", (u_int) pw->pw_gid, strerror(errno)); 116248590Smm if (setuid(pw->pw_uid) < 0) 117248590Smm fatal("setuid %u: %.100s", (u_int) pw->pw_uid, strerror(errno)); 118248590Smm} 119248590Smm