Path: utzoo!mnetor!uunet!husc6!purdue!umd5!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.unix.wizards Subject: Re: access() and security Message-ID: <11239@mimsy.UUCP> Date: 27 Apr 88 00:27:32 GMT References: <13113@brl-adm.ARPA> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 97 In article <13113@brl-adm.ARPA> mouse@larry.mcrcim.mcgill.edu (der Mouse) writes: >What we need, it seems, is a way to say "I wish to restrict myself to >the real user's access privileges" for a time, with the potential to >revert back to the previous state. 4.3's setreuid() appears to be >exactly this It does. >though I seem to recall that if the real uid is 0, the process has >superuser access even if the effective uid is not 0 ... Not so. The proper way to test the validity of operation X `before' doing operation X is to write: uid_t ruid, euid; gid_t rgid, egid; ruid = getuid(), euid = geteuid(); /* there should be getreuid */ rgid = getgid(), egid = getegid(); /* and getregid interfaces. */ ... int do_restricted_operation(op, arg) int (*op)(); caddr_t arg; { int result, saverr; /* this should never fail */ if (setregid(egid, rgid) || setreuid(euid, ruid)) panic("setre?id 1"); result = (*op)(arg); /* note that successful syscalls are allowed to alter errno */ saverr = errno; if (setregid(rgid, egid) || setreuid(ruid, euid)) panic("setre?id 2"); errno = saverr; return (result); } In practise, one would just do the desired operation directly. To use this particular encapsulation correctly, one must write, for instance, struct open_context { char *path; int flags; int mode; }; int do_open(arg) caddr_t arg; { struct open_context *c = (struct open_context *)arg; return (open(c->path, c->flags, c->mode)); } ... struct open_context c; int fd; c.path = "/some/file/name"; c.flags = O_CREAT|O_RDWR|O_EXCL; c.mode = 0600; fd = do_restricted_operation(do_open, (caddr_t)&c); This is quite a bother; it would be nice if C had a `package up some arguments into a generic argument blob' operation and an `expand generic argument blob into real arguments' operation, so that one could write instead fd = do_restricted_operation(open, [["/some/file/name", O_CREAT|O_RDWR|O_EXCL, 0600]]); and inside do_restricted_operation itself, result = (*op)(<< arg); (presuming that [[...]] is the argument-builder and unary << is the argument exploder). An equivalent if less compact representation would be unnamed functions (a C version of lambda :-) ) and aggregates: fd = do_restricted_operation( int (void *arg) { struct open_context *c = arg; return (open(c->path, c->flags, c->mode)); }, (void *) &(struct open_context) { "/some/file/name", O_CREAT|O_RDWR|O_EXCL, 0600 }); which requires no exploder operation. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris