Ok, for those running NeXT and other platforms with broken/missing _POSIX_SAVED_ID please try this patch, and anyone that has spent any amount of time dealing with this problem. I believe it's right. BTW, this patch is no where near as big as it looks. The patch was done against an earily version of the tree which had an issue with white space. - Ben --- ../openssh/uidswap.c Sun Apr 22 06:58:50 2001 +++ uidswap.c.new Tue Apr 24 20:13:22 2001 @@ -26,17 +26,21 @@ * POSIX saved uids or not. */ +#if defined(_POSIX_SAVED_IDS) && !defined(BROKEN_SAVED_UIDS) /* Lets assume that posix saved ids also work with seteuid, even though that is not part of the posix specification. */ - +#define SAVED_IDS_WORK_WITH_SETEUID +/* Saved effective uid. */ +static uid_t saved_euid = 0; +static gid_t saved_egid = 0; +#endif + /* Saved effective uid. */ static int privileged = 0; static int temporarily_use_uid_effective = 0; -static uid_t saved_euid = 0; -static gid_t saved_egid; static gid_t saved_egroups[NGROUPS_MAX], user_groups[NGROUPS_MAX]; static int saved_egroupslen = -1, user_groupslen = -1; - + /* * Temporarily changes to the given uid. If the effective user * id is not root, this does nothing. This call cannot be nested. @@ -44,42 +48,57 @@ void temporarily_use_uid(struct passwd *pw) { - /* Save the current euid, and egroups. */ - saved_euid = geteuid(); - debug("temporarily_use_uid: %d/%d (e=%d)", - pw->pw_uid, pw->pw_gid, saved_euid); - if (saved_euid != 0) { - privileged = 0; - return; - } - privileged = 1; - temporarily_use_uid_effective = 1; + /* Save the current euid, and egroups. */ +#ifdef SAVED_IDS_WORK_WITH_SETEUID + saved_euid = geteuid(); saved_egid = getegid(); - saved_egroupslen = getgroups(NGROUPS_MAX, saved_egroups); - if (saved_egroupslen < 0) - fatal("getgroups: %.100s", strerror(errno)); - - /* set and save the user's groups */ - if (user_groupslen == -1) { - if (initgroups(pw->pw_name, pw->pw_gid) < 0) - fatal("initgroups: %s: %.100s", pw->pw_name, - strerror(errno)); - user_groupslen = getgroups(NGROUPS_MAX, user_groups); - if (user_groupslen < 0) - fatal("getgroups: %.100s", strerror(errno)); - } - /* Set the effective uid to the given (unprivileged) uid. */ + debug("temporarily_use_uid: %d/%d (e=%d)", + pw->pw_uid, pw->pw_gid, saved_euid); + if (saved_euid != 0) { + privileged = 0; + return; + } +#else + if (geteuid() != 0) { + privileged = 0; + return; + } +#endif /* SAVED_IDS_WORK_WITH_SETEUID */ + + privileged = 1; + temporarily_use_uid_effective = 1; + saved_egroupslen = getgroups(NGROUPS_MAX, saved_egroups); + if (saved_egroupslen < 0) + fatal("getgroups: %.100s", strerror(errno)); + + /* set and save the user's groups */ + if (user_groupslen == -1) { + if (initgroups(pw->pw_name, pw->pw_gid) < 0) + fatal("initgroups: %s: %.100s", pw->pw_name, + strerror(errno)); + user_groupslen = getgroups(NGROUPS_MAX, user_groups); + if (user_groupslen < 0) + fatal("getgroups: %.100s", strerror(errno)); + } + /* Set the effective uid to the given (unprivileged) uid. */ if (setgroups(user_groupslen, user_groups) < 0) fatal("setgroups: %.100s", strerror(errno)); - pw->pw_gid = pw->pw_gid; +#ifndef SAVED_IDS_WORK_WITH_SETEUID + /* Propagate the privileged gid to all of our gids. */ + if (setgid(getegid()) < 0) + debug("setgid %u: %.100s", (u_int) getegid(), strerror(errno)); + /* Propagate the privileged uid to all of our uids. */ + if (setuid(geteuid()) < 0) + debug("setuid %u: %.100s", (u_int) geteuid(), strerror(errno)); +#endif /* SAVED_IDS_WORK_WITH_SETEUID */ if (setegid(pw->pw_gid) < 0) - fatal("setegid %u: %.100s", (u_int) pw->pw_gid, - strerror(errno)); - if (seteuid(pw->pw_uid) == -1) - fatal("seteuid %u: %.100s", (u_int) pw->pw_uid, - strerror(errno)); + fatal("setegid %u: %.100s", (u_int) pw->pw_gid, + strerror(errno)); + if (seteuid(pw->pw_uid) == -1) + fatal("seteuid %u: %.100s", (u_int) pw->pw_uid, + strerror(errno)); } - + /* * Restores to the original (privileged) uid. */ @@ -92,13 +111,27 @@ return; if (!temporarily_use_uid_effective) fatal("restore_uid: temporarily_use_uid not effective"); + +#ifdef SAVED_IDS_WORK_WITH_SETEUID /* Set the effective uid back to the saved privileged uid. */ if (seteuid(saved_euid) < 0) - fatal("seteuid %u: %.100s", (u_int) saved_euid, strerror(errno)); + fatal("seteuid %u: %.100s", (u_int) saved_euid, + strerror(errno)); + if (setegid(saved_egid) < 0) + fatal("setegid %u: %.100s", (u_int) saved_egid, + strerror(errno)); +#else /* SAVED_IDS_WORK_WITH_SETEUID */ + /* + * We are unable to restore the real uid to its unprivileged value. + * Propagate the real uid (usually more privileged) to effective uid + * as well. + */ + setuid(getuid()); + setgid(getgid()); +#endif /* SAVED_IDS_WORK_WITH_SETEUID */ + if (setgroups(saved_egroupslen, saved_egroups) < 0) fatal("setgroups: %.100s", strerror(errno)); - if (setegid(saved_egid) < 0) - fatal("setegid %u: %.100s", (u_int) saved_egid, strerror(errno)); temporarily_use_uid_effective = 0; }