changing user id's (from Lauren)

utzoo!decvax!watmath!dmmartindale utzoo!decvax!watmath!dmmartindale
Sat Jan 9 23:40:59 AEST 1982


Re Lauren's query about changing userids:
	We have had a schizo() call which simply swapped real and effective
userids for years, and I've always thought it was a little ugly, because
spoolers which caught SIGINT and quit always had to do something like:

interrupt()
{
	unlink(cfile);
	schizo();
	unlink(cfile);
	.....

because they didn't know which id they were running as.
	I also decided that it would be very nice if a process running
with an effective uid of 0 could turn itself into an arbitrary user temporarily
in order to access a file, and then turn back into root (this is invaluable
for deamons on systems which try to be secure.)
	The solution I finally came up with is this:
I added two additional entries to the U area called u.u_euid and u.u_egid.
(Think of them as exec-time uid/gid).  They are set to u.u_uid and u.u_gid
in exec once it has done all the checking for setuid/setgid and decided
what the final uid/gid will be.  Then I have two new system calls:

schizo()
{
	struct a {
		int	flag;
	};

	if (((struct a *)u.u_ap)->flag) {
		u.u_uid = u.u_ruid;
		u.u_gid = u.u_rgid;
	} else {
		u.u_uid = u.u_euid;
		u.u_gid = u.u_egid;
	}
}

become()
{
	register struct a {
		int	uid;
		int	gid;
	} *uap;

	uap = (struct a *)u.u_ap;
	if(u.u_euid == 0) {		/* must check euid rather than uid */
		u.u_acflag |= ASU;
		u.u_uid = uap->uid;
		u.u_gid = uap->gid;
		return;
	} else
		u.u_error = EPERM;
}

	A process can "turn itself into" the uid/gid which invoked it by doing
a schizo(1), and return to its setuid permissions later with schizo(0).
I use this in spoolers which must be setuid to access a protected spool
area, yet must temporarily revert to the user's permissions
in order to do a getwd() or to access a user's file (no more need for access(),
and if you creat a file, it is automatically owned by the correct person).
The call is unprivileged, since anything you can do via it could also be
done (much more clumsily) by a sequence of pipe(), fork(), setuid(getuid()),
etc.
	The become(uid, gid) sys call allows a process which is setuid to
root (or invoked by root, such as from /etc/rc) to "become" an arbitrary
user/group id at any time.  Spoolers can put the uid, gid, and umask of
whoever invoked them into a control file and when a daemon starts processing
that control file, it can set its uid, gid, and umask to these whenever it
wishes to open, creat, or unlink a file as directed by the user.
	This scheme has an advantage over the setid() call discussed by
Alan Watt in that the ruid/rgid are never touched and are thus always
correct, which is important if you do process accounting since they
get written to the accounting file (and passed on to children).

					Dave Martindale
					(watmath!dmmartindale)



More information about the Comp.unix.wizards mailing list