home *** CD-ROM | disk | FTP | other *** search
- /*
- * su.c 1.0
- * Modified by tim lashua from James Wiegand's Berkeley based su.
- *
- * This su now takes the shell from the password file instead of always
- * using a default shell. If no shell is specified in the password file,
- * /bin/sh is used. The -l or --login options can be used to invoke the
- * shell as if it were a login shell. Options to log all su activity or
- * just su to root have been added. I don't know what the standard
- * format for a sulog is, if there is one. The sulog created by this su
- * has the following format: there are three colon seperated fields
- * containing, respectively, the login name of the person running su,
- * the login name of the person being su'd, and the time and date.
- *
- * I have compiled this with gcc 2.1 on Linux 0.95c+ with the following
- * options:
- * -O -Wall -fstrength-reduce -static
- *
- */
-
-
-
- #include <getopt.h>
- #include <pwd.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
-
- /* the max path length (+1) for the shell, and home directory */
- #define SUPATHLEN 60
- #define USERLEN 9 /* maximum user name length + 1 */
- #define FAILURE -1
-
- #define DEF_SHELL "/bin/sh" /* default shell if none is in /etc/passwd */
- #define LOG_FILE "/usr/adm/sulog"
- #define LOG_ROOT_ONLY 0 /* true if you only want su's to root logged */
- #define LOG_ALL 0 /* true if you want to log all su's */
-
- struct option longopts[] =
- {
- {"login", 0, NULL, 'l'},
- {NULL, 0, NULL, 0}
- };
-
- int main(int argc, char **argv)
- {
- struct passwd *pwd;
- char *p;
- uid_t cur_uid;
- int ch, login = 0;
-
- char *new_user, username[USERLEN], *nargv[4], **np;
- char new_home_env[SUPATHLEN + 5]; /* + HOME= */
- char new_shell_env[SUPATHLEN + 6]; /* + SHELL= */
- char new_shell[SUPATHLEN];
-
- FILE *logfile;
- long su_time;
- np = &nargv[3];
- *np-- = NULL;
-
- while ((ch = getopt_long( argc, argv, "l", longopts, (int *) 0 )) != EOF)
- switch((char)ch){
- case 'l':
- login = 1;
- break;
- case '?':
- default:
- fprintf(stderr, "Usage: su [-l] [--login] username \n");
- exit(1);
- }
-
- argv += optind;
- errno = 0;
-
- /* get current login password entry */
- cur_uid = getuid();
- pwd = getpwuid(cur_uid);
-
- if(pwd == NULL){
- fprintf(stderr, "su: invalid login\n");
- exit(1);
- }
-
- strcpy( username, pwd->pw_name ); /* store current login name */
-
- /* get target login information, default to root */
- new_user = *argv ? *argv : "root";
-
- pwd = getpwnam(new_user); /* get password entry for 'new_user' */
- if(pwd == NULL)
- {
- fprintf(stderr, "su: unknown login %s\n", new_user);
- exit(1);
- }
-
- su_time = time(NULL); /* the time this program was run */
-
- if(LOG_ALL){ /* log all attempts to su to a valid user */
- logfile = fopen(LOG_FILE, "a");
- fprintf(logfile, "%s:%s:%s", username, new_user, \
- asctime(localtime(&su_time)));
- fclose(logfile);
- }
- else if(LOG_ROOT_ONLY){ /* log attempts to su root */
- if (!strcmp(new_user, "root")){
- logfile = fopen(LOG_FILE, "a");
- fprintf(logfile, "%s:%s:%s", username, new_user, \
- asctime(localtime(&su_time)));
- fclose(logfile);
- }
- }
-
- /* if a password is required, check it */
- /* a password is required if the current user is not root and the */
- /* 'new_user' has a password */
-
- if(cur_uid){ /* if current user isn't root */
- if(*pwd->pw_passwd){
- p = getpass("Password:");
- if(strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))){
- fprintf(stderr, "Sorry\n");
- exit(1);
- }
- }
- }
-
- /* set user and group id */
-
- if(setgid(pwd->pw_gid) == FAILURE ){
- perror("su: setgid");
- exit(1);
- }
-
- if(setuid( pwd->pw_uid) == FAILURE ){
- perror("su: setuid");
- exit(1);
- }
-
- /* determine which shell to execute. get the users shell from the */
- /* entry in /etc/passwd, if no shell is specified there use /bin/sh */
-
- strcpy(new_shell, pwd->pw_shell);
-
- if (!(new_shell[0] == '/')){
- strcpy(new_shell, DEF_SHELL);
- fprintf(stderr, "su: no shell. using %s\n", DEF_SHELL);
- }
-
- /* get and reset the environment variables HOME and SHELL */
- strcpy(new_home_env, "HOME=");
- strcat(new_home_env, pwd->pw_dir);
- putenv(new_home_env);
-
- strcpy(new_shell_env, "SHELL=");
- strcat(new_shell_env, new_shell);
- putenv(new_shell_env);
-
- /* should this be treated as a login shell ? */
- *np = login ? "-su" : "su";
-
- /* start the new shell */
- execv(new_shell, np);
-
- return(0);
-
- }
-