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