==============================================================================
C-Scene Issue #04
Process Persona in Unix
Cameron Zwarich
==============================================================================
In Unix, each process has a "persona". This persona tells the process (and
other processes) who exactly is running the process and what persmissions
are given to the process.
Each process has a real user ID and an effective user ID. The real user ID is
the same as the user ID of its parent (unless it has been changed). The
effective user ID of a program corresponds to the set user ID bit on the file
being executed.
The real user ID is used to determine which user started the process, and
the effective user ID determines what permissions the process has, like which
files it can access in what ways, and what ports it can bind to, etc.
Each process also has a real group ID and an effective group ID. These follow
the same general rules as their corresponding user counterparts, but the
permissions are only for file access where a specific group is given
special permissions that the world isn't given.
--- NOTE ---
Executables owned by root with a set ID bit are very insecure. Make sure
that you do all of your root-needing stuff at the BEGINNING of the program's
execution, then assume the identity of another user (traditionally nobody).
--- END NOTE ---
Getting the Persona of the Current Process
------------------------------------------
Suppose you need to find out which user executed your process, or what
permissions you have before you attempt to do something. Or what if you need
to get a particular user's password file information (read my article on this
too :). This is when you need to get the persona of a process.
getuid() returns the real user ID (uid) of the current process. geteuid()
returns the effective user ID (euid) of the current process.
getgid() returns the real group ID (gid) of the current process. getegid()
returns the effective group ID (egid) of the current process.
Here is an example which prints the uid, euid, gid, and egid of itself.
#include <stdio.h>
#include <unistd.h>
int main (void)
{
printf("uid: %d\neuid: %d\ngid: %d\negid: %d\n", getuid(), geteuid(),
getgid(), getegid());
exit(0);
}
That wasn't that hard at all. Play around with set ID bits on the executable
and see how the output changes for some fun.
Setting the Persona of the Current Process
------------------------------------------
In the life of some programs, you may have to do something that requires a
super-user uid (0) to do. Your program might require access by normal users
also though. What do you do? Well, you make the file root-owned and set the
set user ID bit on the process. Here is a little function you might want to
add to your root .profile (Bash is the best shell :):
function change-to-setuid () { chown 0:0 $1; chmod +s $1; }
That would be called as: "change-to-setuid ".
If you are using a non-Bourne shell, then write something corresponding to
that, its not really all that hard. You should be using Bash anyways.
I will explain six functions, setuid(), setreuid(), seteuid(), setgid(),
setregid() and setegid(). Only setuid() and setgid() conform to Posix.1.
setreuid(), seteuid(), setregid(), and setegid() all conform to the BSD 4.3
standard. You cannot change to a user ID or a group ID other then your
current one unless you have super-user priveleges.
setuid() sets both the real and effective user ID's to its only argument.
setreuid() takes two arguments, the new real and effective user ID's
respectively. The seteuid() sets the effective user ID to its only argument.
The group-related functions do the same actions but with group ID's.
With the Posix.1 functions, you can (on most systems) regain priveleges that
you gave up with setuid()/setgid(). You can switch back to the effective
user/group ID you had before if you were run with a set ID bit and you
assumed another user to do some work.
Here is an example that uses the Posix functions to set the user/group IDs to
its two arguments, respectively:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main (int argc, char **argv)
{
if (argc < 3)
{
fputs("Insufficient arguments\n", stderr);
exit(1);
}
printf("My old uid was %d, and my old gid was %d. ", getuid(), getgid());
setuid(atoi(argv[1]));
setgid(atoi(argv[2]));
printf("My new uid is %d, and my new gid is %d\n", getuid(), getgid());
}
Functions
---------
#include <unistd.h>
#include <sys/types.h>
uid_t getuid(void)
uid_t geteuid(void)
gid_t getgid(void)
gid_t getegid(void)
int setuid(uid_t uid)
int setreuid(uid_t ruid, uid_t euid)
int seteuid(uid_t euid)
int setgid(gid_t gid)
int setregid(gid_t rgid, gid_t egid)
int setegeid(gid_t egid)
This page is Copyright © 1997 By
C Scene. All Rights Reserved