==============================================================================
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