DOCUMENT ID: 1473-02

SYNOPSIS:    How to perform root admin functions as a normal user

OS RELEASE:  All UNIX systems

PRODUCT:     

KEYWORDS:    root admin functions


SYMPTOMS:    

How do you become root when you have forgotten the root password?


DESCRIPTION: 

You are the administrator of a machine, but rarely need to use the root
account and have forgotten the password. 

                        or

You are normally using your own account and occasionally need to become
root to do administration work, sometimes just for a single command, and
hate to have to enter the root password every time - issue the command -
and exit. 


SOLUTION:

The solution is to create a program that will allow you a "back door"
entry into the system as root.  To keep it secure you only want
legitimate accounts to be able to use this program, but you might also
want to be able to use it from accounts that are not on the list by
supplying the actual root password.  To do this we will create a program
called "super". 

I have also made it so that the owner and group names for the program
control the owner and group that you assume when you run.  If you want
to become a user of 'root', but stay whatever group you currently are,
just set the attributes via chmod to 4555 and the owner to 'root'.  The
name of the program is used as the first part of the '.allow' filename,
thus letting you have multiple versions without having to use a common
'.allow' file. 

Likewise, you can only change groups by setting the attributes to 2555
and make the group owner of the file the group you want to become. 

For both user and group IDs to be inherited use the attribute 6555. 
Always set the attributes AFTER you have set the user and group owner
IDs for the file. 

Please note that a security hole can be created by making this file
public write or owner write with an owner other than root.  For the
highest security it is suggested making it 555 for the lower 3 octal
values.  This way only root can change the file after it is created. 
UNIX does not preserve the 4000 or 2000 bits when a copy or change of
ownership is made to a file, as a security precaution. 

One further advantage (or disadvantage, depending on your point of view)
of a program like this is that unlike using 'su - username' to switch to
a user, this program will preserve all of your environment settings just
as if you invoked a new shell from the command line. 

This also means people who use Korn shell, C shell, or Bourne shell
will get the shell they are used to instead of the one set up for
a particular account. 

You also have the advantage of not having to give out passwords and then
having to change them when someone transfers from the department or
leaves the company.  Just remove their name from the '.allow' file and
their access is stopped. 

Here is the Solaris 2.4 version of this program.  With the exception of
some type names, include file names, and ANSI C prototypes this should
work for Interactive 4.x, also:

 /***
 *   The super program gives any user root privileges provided they are:
 *       A)  Using an account listed in the /etc/super.allow file.
 *       B)  Using a group listed in the /etc/super.allow file.
 *       C)  Know the root password.
 ***/

 #include    
 #include    
 #include    
 #include    
 #include    
 #include    
 #include    
 #include    
 #include    

 main    (int argc, char **argv)
 {
    char            UserName [L_cuserid + 1];   /* Allow for NUL terminator. */
    char            GroupName [L_cuserid + 1];  /* Allow for NUL terminator. */
    char            Name [L_cuserid + 1];       /* Allow for NUL terminator. */
    char            Salt [3];
    uid_t           EffectiveUID;
    gid_t           EffectiveGID;
    int             ReturnCode;
    int             I;
    char           *Command;
    char           *PasswordString;
    char           *Ptr;
    FILE           *AllowFile;
    struct group   *Group;
    struct spwd    *Shadow;
    char            AllowFilename [256];
    char            TempFilename  [256];
 /***
 *   NOTE: char *getlogin (void) and char *getlogin_r (char *name, int name_len)
 *   are legitimate alternatives to cuserid ().  Use what works for your
 *   version of UNIX.
 ***/
    (void) cuserid (UserName);      /* Get the name of the current user. */
    Group = getgrgid (getgid ());   /* Get the name of the current group. */
    (void) strcpy (GroupName, Group->gr_name);
 /***
 *       Use the command name as the start of the .allow filename, but strip off
 *   any part of a pathname first.
 ***/
    (void) strcpy (AllowFilename, argv [0]);
    Ptr = strrchr (AllowFilename, '/');
    if ((int) Ptr != -1)
	(void) strcpy (TempFilename, Ptr + 1);

    (void) sprintf (AllowFilename, "/etc/%s.allow", TempFilename);
    AllowFile = fopen (AllowFilename, "r");
    if (AllowFile == NULL)
    {   /* If there is no file, we can't proceed. */
        (void) printf ("%s: %s does not exist.\n", argv [0], AllowFilename);
        exit (-1);
    }   /* if */
 /***
 *       Read through the user names in /etc/%s.allow and match versus UserName.
 ***/
    while (1)
    {   /* Check for this user being in the file and ask for password if not. */
        if (fgets (Name, L_cuserid + 1, AllowFile) == NULL)
        {   /* This user's name is not in the list. */
            PasswordString = getpass ("Password for root? ");
            Shadow = getspnam ("root");
            (void) memcpy (Salt, Shadow->sp_pwdp, 2);
            Salt [2] = 0;                               /* Build salt string. */
            PasswordString = crypt (PasswordString, Salt);  /* Encrypt */
            if (strcmp (PasswordString, Shadow->sp_pwdp) == 0)
                break;  /* This user is hereby granted root privileges. */

            (void) printf ("%s: Invalid password for root.\n", argv [0]);
            exit (-1);
        }   /* if */
 /***
 *       Remove the \n at the end of Name.
 ***/
        Name [strlen (Name) - 1] = 0;
        if (Name [0] == '#')
            ;   /* Ignore comment lines. */
        else    if (strcmp (Name, UserName) == 0)
            break;  /* This user is hereby granted root privileges. */
        else    if (strcmp (Name, GroupName) == 0)
            break;  /* This user (group) is hereby granted root privileges. */
    }   /* while (1) */
 /***
 *       Use the effective group and user IDs of this process to determine what
 *   to change to the process UID and GID to.  This way just the UID or the GID
 *   may be changed.  Not hard coding it as 'root' makes it more flexible.
 ***/
    EffectiveUID = geteuid ();
    EffectiveGID = getegid ();
    (void) setuid (EffectiveUID);   /* Ignore errors. */
    (void) setgid (EffectiveGID);   /* Ignore errors. */
    if (argc == 1)
        ReturnCode = system (getenv ("SHELL"));
    else
    {   /* Build up the command string and run it. */
        for (I = 1; I != argc; I ++)
        {   /* Build up the command string from argv [n] sub-strings. */
            if (I == 1)
            {   /* Do initial allocation and make string empty. */
                Command = malloc (strlen (argv [I]) + 2);
                Command [0] = 0;
            }   /* if */
            else
            {   /* Add a space separator and expand the buffer. */
                (void) strcat (Command, " ");
                Command = realloc (Command, strlen (argv [I]) + 1);
            }   /* else */

            (void) strcat (Command, argv [I]);
        }   /* for */

        ReturnCode = system (Command);
    }   /* else */

    if (ReturnCode == -1)
        ReturnCode = errno; /* An error trying to fork the child. */

    return ReturnCode;
 }   /* main */


DATE APPROVED: 07/28/95