home *** CD-ROM | disk | FTP | other *** search
- Subject: v15i034: Run commands as another (or super) user
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: dirk <unido!altger!dirk>
- Posting-number: Volume 15, Issue 34
- Archive-name: surun
-
- WHAT IT DOES:
- Surun allows a user to run a command under root or another
- user's privilege without typing the user's password. Permission
- to use surun is given by a password file, usage is logged to
- a logfile.
-
- WHERE IT RUNS:
- If use surun since 3/4 year under System V rel. 3.
- If you plan to run it under BSD or XENIX just undefine the
- TERMIO flag. If have not been testing surun under BSD or
- XENIX for a long time now but it will run as well.
-
- WHAT TO DO:
- I am to lazy to correct my manual page, if someone who's native
- language is english could to so pls. send it back to me.
-
- cu,
- Dirk Koeppen, DK-SOFT, West Germany
-
- ------------------------> CUT HERE <------------------------
-
- : !/bin/sh
- # To unbundle, sh(ell) this file
- # ==============================
- echo README 1>&2
- cat >README <<'End of ===README==='
- #ident @(#) README v1.2 of 88/10/03 , dirk
- # This is Public-Domain. Military usage or resale forbidden.
- # 6.Jun'87, dirk ( .. unido!cosa!dirk )
-
- WHAT IT DOES:
- Surun allows a user to run a command under root or another
- user's privilege without typing the user's password. Permission
- to use surun is given by a password file, usage is logged to
- a logfile.
-
- WHERE IT RUNS:
- If use surun since 3/4 year under System V rel. 3.
- If you plan to run it under BSD or XENIX just undefine the
- TERMIO flag. If have not been testing surun under BSD or
- XENIX for a long time now but it will run as well.
-
- WHAT TO DO:
- I am to lazy to correct my manual page, if someone who's native
- language is english could to so pls. send it back to me.
-
- cu,
- dirk :-)
-
- Dirk Koeppen, DK-SOFT, West Germany
- End of ===README===
- echo Makefile 1>&2
- cat >Makefile <<'End of ===Makefile==='
- #ident @(#) Makefile v1.2 of 88/10/03 , dirk
- # Makefile for surun
- # This is Public-Domain. Military usage or resale forbidden.
- # 6.Jun'87, dirk ( .. unido!cosa!dirk )
-
- SHELL =/bin/sh
- CFLAGS =-O -s -DTERMIO
- CLIBS =-lc_s
- BINDIR =/usr/local/bin
- MAN =nroff -man
- MANDIR =/usr/man/u_man/man1
- CATMANDIR =/usr/catman/u_man/man1
- LOGFILE =/usr/adm/surun.log
- ALLOWFILE =/usr/adm/surun.allow
- SILENTCC =YES
-
- surun: surun.c
- cc $(CFLAGS) surun.c -o surun $(CLIBS)
-
- # have to be root to install
- install:
- make surun
- mv ./surun $(BINDIR)/surun
- chown root $(BINDIR)/surun
- chgrp bin $(BINDIR)/surun
- chmod 4751 $(BINDIR)/surun
- cp ./surun.1M $(MANDIR)/surun.1M
- $(MAN) surun.1M > $(CATMANDIR)/surun.1M
- pack -f $(CATMANDIR)/surun.1M
- cp /dev/null $(LOGFILE)
- chmod 640 $(LOGFILE)
- echo "root::\nbin::" > $(ALLOWFILE)
- chmod 640 $(ALLOWFILE)
-
- clean:
- rm -f foo Mout Lout a.out core *.i *.obj *.o
- rm -f surun surun.allow surun.log surun.tmp
- End of ===Makefile===
- echo surun.c 1>&2
- cat >surun.c <<'End of ===surun.c==='
- char SCCS_id[]= "@(#) surun.c v2.2 of 88/10/03 , dirk";
-
- /*
- * SURUN
- * run programs under root id
- * usuage: surun [-] [-u username] [-p] .. command ..
- *
- * This is Public-Domain. Military usage or resale forbitten.
- * 6.Jun'87, dirk ( .. unido!cosa!dirk )
- */
-
- #include <sys/types.h>
- #include <ctype.h>
- #include <stdio.h>
- #include <pwd.h>
- #include <time.h>
- #include <string.h>
- #include <signal.h>
-
- #ifdef TERMIO
- # include <termio.h>
- #else
- # include <sgtty.h>
- #endif /* TERMIO */
-
- #ifndef MAX_ARG
- # define MAX_ARG 1024
- #endif
-
- #define ALLOWFILE "/usr/adm/surun.allow"
- #define LOGFILE "/usr/adm/surun.log"
- #define TEMPFILE "/usr/adm/surun.tmp"
- #define ALLOWMASK 0640
-
- #define CONSOLE "/dev/console"
- #define SHELL "/bin/sh"
-
- #define USAGE( str ) \
- { \
- fprintf (stderr, "surun: %s\n", str ); \
- fprintf (stderr, \
- "usage: surun [-] [-u username] [-p] .. command ..\n"); \
- exit (1); \
- } \
-
- #define ERROR( str ) \
- { \
- fprintf (stderr, "surun: %s\n", str ); \
- exit (1); \
- } \
-
- #define PERROR( str ) \
- { \
- perror ( str ); \
- exit (1); \
- } \
-
- struct passwd *getpwnam ();
- char *crypt (), *getlogin (), *ttyname ();
- long time ();
- void exit ();
-
- char log_string[64];
- char env_shell[64]= "SHELL=";
- char env_home[64]= "HOME=";
- char env_logname[17]= "LOGNAME=";
- char env_mail[64]= "MAIL=/usr/mail/";
- char env_path1[128]= "PATH=:/bin:/usr/bin";
- char env_path2[128]= "PATH=:/bin:/usr/bin:/etc";
- char username[64];
- char *userpasswd;
- int userretry;
-
- main(argc, argv)
- char **argv;
- {
- char *user= "root" , *file,
- *Argv[ MAX_ARG ], *environ[6];
- int i, lflag= 0, pflag= 0;
- long clock;
- struct tm *date;
- struct passwd *user_pwd;
-
- /* check'n lookup args */
- while ((**(++argv) == '-') && (*(*argv + 1) != '-'))
- switch (*(*argv + 1))
- {
- case 'u' : user= *++argv;
- if (!user)
- USAGE( "no username" );
- break;
- case 'p' : pflag++; break;
- case 'V' : printf ("%s\n", SCCS_id);
- exit (0);
- case NULL : lflag++; break;
- default : USAGE( "not a valid option" );
- }
- if (!*argv && !pflag)
- USAGE( "no command" );
-
- /* create the time stamp */
- clock= time ((long *)0);
- date= gmtime (&clock);
- sprintf (log_string, "SURUN %02d/%02d %02d:%02d + %s %s-%s",
- date->tm_mday, date->tm_mon + 1, date->tm_hour, date->tm_min,
- (strrchr (ttyname (0), '/') + 1), getlogin (), user);
-
- /* do we have an valid entry in the allowfile ? */
- if (!check_permission(getlogin ()) || !userretry)
- {
- *strchr (log_string, '+')= '-';
- log(argv);
- if (userretry)
- ERROR( "no permission" )
- else
- ERROR( "number of password-retries exeeded" )
- }
-
- /* log it and change id*/
- log(argv);
- if (pflag)
- {
- setpasswd();
- if (!*argv)
- exit (0);
- }
- if ((user_pwd= getpwnam (user)) == NULL)
- ERROR( "invalid username" );
- if (setgid (user_pwd->pw_gid))
- PERROR( user_pwd->pw_gid );
- if (setuid (user_pwd->pw_uid))
- PERROR( user_pwd->pw_uid );
-
- /* execute it */
- if (lflag)
- {
- file= user_pwd->pw_shell;
- if (!*file)
- file= SHELL;
- environ[0]= strcat (env_shell, file);
- environ[1]= strcat (env_home, user_pwd->pw_dir);
- environ[2]= strcat (env_logname, user_pwd->pw_name);
- environ[3]= strcat (env_mail, user_pwd->pw_name);
- if (user_pwd->pw_uid)
- environ[4]= env_path1;
- else
- environ[4]= env_path2;
- environ[5]= NULL;
- i= 0;
- /* Argv[i++]= strrchr (file, '/') + 1; */
- Argv[i++]= "-";
- Argv[i++]= "-c";
- while (Argv[i++]= *(argv++));
- if (chdir (user_pwd->pw_dir) == -1)
- PERROR( user_pwd->pw_dir );
- if (execve (file, Argv, environ))
- PERROR( file );
- }
- else
- {
- file= *argv;
- if (execvp (file, argv))
- PERROR( file );
- }
-
- /* unreached */
- exit (0);
- }
-
-
- /*
- * CHECK_PERMISSION
- * check if the user has permissions and left retries to execute surun
- */
- int
- check_permission(lognam)
- char *lognam;
- {
- FILE *allowfile;
- char passwd[3];
- int ok_flag= 0;
-
- if (!(allowfile= fopen (ALLOWFILE, "r")))
- ERROR( "cannot open the allow file" );
-
- while (fgets (username, 64, allowfile) && !ok_flag)
- {
- if (isdigit (*(strrchr (username, ':') + 1)))
- userretry= atoi (strrchr (username, ':') + 1);
- else
- userretry= 1;
- userpasswd= strchr (username, ':') + 1;
- *strrchr (username, ':')= NULL;
- *(userpasswd - 1)= NULL;
- if (!strcmp (username, lognam))
- if (*userpasswd && userretry)
- {
- printf ("passwd: ");
- raw(1);
- passwd[0]= getchar ();
- passwd[1]= getchar ();
- raw(0);
- passwd[2]= 0;
- putchar ('\n');
- if (!strcmp (crypt (passwd, userpasswd),
- userpasswd))
- ok_flag++;
- else
- {
- userretry--;
- fclose (allowfile);
- update();
- return (ok_flag);
- }
- }
- else
- ok_flag++;
- }
- fclose (allowfile);
- return (ok_flag);
- }
-
-
- /*
- * LOG
- * log to console and logfile
- */
- log(cmd)
- char **cmd;
- {
- FILE *logfile, *console;
-
- if (!(logfile= fopen (LOGFILE, "a+")))
- ERROR( "cannot open the logfile" );
-
- if (console= fopen (CONSOLE , "w"))
- {
- fprintf (console, "%s\n", log_string);
- fclose (console);
- }
-
- fprintf (logfile, "%s :", log_string);
- while (*cmd)
- fprintf (logfile, " %s", *(cmd++));
- fprintf (logfile, "\n");
- fclose (logfile);
- }
-
-
- /*
- * RAW
- * 1: set terminal to raw mode and no echo
- * 0: reset old terminal status
- */
- raw(mode)
- int mode;
- {
- #ifdef TERMIO
- static struct termio t_save;
- struct termio t;
-
- if (mode)
- {
- ioctl (2, TCGETA, &t);
- t_save= t;
- t.c_lflag&= ~(ICANON|ECHO);
- t.c_cc[VMIN]= 1;
- t.c_cc[VTIME]= 0;
- }
- else
- t= t_save;
- ioctl (2, TCSETAW, &t);
- #else
- static struct sgttyb t_save;
- struct sgttyb t;
-
- if (mode)
- {
- ioctl (2, TIOCGETP, &t);
- t_save= t;
- t.sg_flags|= CBREAK;
- t.sg_flags&= ~ECHO;
- }
- else
- t= t_save;
- ioctl (2, TIOCSETN, &t);
- #endif /* TERMIO */
- }
-
-
- /*
- * SETPASSWD
- * get a new passwd and crypt it
- */
- setpasswd()
- {
- long salt;
- char salt_c[2], passwd[3];
- int i;
-
- printf ("New Password: ");
- raw(1);
- passwd[0]= getchar ();
- passwd[1]= getchar ();
- raw(0);
- passwd[2]= 0;
- putchar ('\n');
- userretry= 0;
- while ((userretry < 1) || (userretry > 9))
- {
- printf ("Number of retries (1-9): ");
- scanf ("%d", &userretry);
- }
- time (&salt);
- salt*= getpid ();
- salt_c[0]= salt & 0x3f;
- salt_c[1]= salt>>6 & 0x3f;
- for (i= 0; i < 2; i++)
- {
- salt_c[i]+= '.';
- if (salt_c[i] > '9')
- salt_c[i]+= 'A' - ':';
- if (salt_c[i] > 'Z')
- salt_c[i]+= 'a' - '[';
- }
- userpasswd= crypt (passwd, salt_c);
- update();
- }
-
-
- /*
- * UPDATE
- * update the surun.allow file with the current user data
- */
- update()
- {
- FILE *in, *out;
- char line[64];
-
- if (!(in= fopen (ALLOWFILE, "r")))
- ERROR( "cannot open allowfile" )
- if (!(out= fopen (TEMPFILE, "w")))
- ERROR( "cannot open tempfile" )
- while (fgets (line, 64, in))
- {
- if (!strcmp (strtok (line, ":"), username))
- fprintf (out, "%s:%s:%d\n", username,
- userpasswd, userretry);
- else
- {
- *(line+strlen (line))= ':';
- fputs (line, out);
- }
- }
- fclose (in);
- fclose (out);
- chmod (TEMPFILE, ALLOWMASK);
- signal (SIGHUP, SIG_IGN);
- signal (SIGINT, SIG_IGN);
- signal (SIGQUIT, SIG_IGN);
-
- #ifdef SIGSTP
- signal (SIGSTP, SIG_IGN);
- #endif /* SIGSTP */
-
- unlink (ALLOWFILE);
- if (link (TEMPFILE, ALLOWFILE))
- ERROR( "cannot link tempfile to allowfile" );
- unlink (TEMPFILE);
- signal (SIGHUP, SIG_DFL);
- signal (SIGINT, SIG_DFL);
- signal (SIGQUIT, SIG_DFL);
-
- #ifdef SIGSTP
- signal (SIGSTP, SIG_DFL);
- #endif /* SIGSTP */
-
- }
- End of ===surun.c===
- echo surun.1M 1>&2
- cat >surun.1M <<'End of ===surun.1M==='
- .\" @(#) surun.1M.sh v1.2 of 88/10/03 , dirk
- .TH SURUN 1M
- .SH NAME
- surun - run a command under root or another user's privilege
- .SH SYNOPSIS
- surun [-] [-u username] [-p] .. command ..
- .SH OPTIONS
- .sp
- - login as the specified user
- .sp
- -u username set the userid to the one of user 'username'
- .sp
- -p set password and retry-counter
- .sp
- command commands to be executed
- .SH DESCRIPTION
- \fISurun\fR allows one to run a program under root or another
- user's privilege without logging off or typing the user's
- password. The default username is root (i.e., superuser).
- For security reasons the user can set a short password of 2 characters
- as well.
- .PP
- To use \fIsurun\fR, the user must have permission to execute the
- \fIsurun\fR command. This is provided by an entry of the user's logname in the
- \fI/usr/adm/surun.allow\fR file. If the user has this permission,
- \fIsurun\fR executes the command or a new shell with the
- \fIreal\fR user and group ID set to that of the specified user.
- For security reasons the user has the possibility to setup a \fIpassword\fR
- with a length of 2 characters. If a \fIpassword\fI is set, \fIsurun\fR prompts
- for it first, this is done in 'cbreak/ no echo mode' so that the user does not
- need to press <RETURN> or <EOF>. A misstyped password causes \fIsurun\fR to
- decrement a counter in the \fI/usr/adm/surun.allow\fR file. If this counter
- reaches 0, \fIsurun\fR aborts every time it is called. The super-user must
- reset the counter to activate \fIsurun\fR for the misstyping user again.
- .sp
- The normal user ID is restored just after the \fIsurun\fR
- command quits. Any additional arguments given on the command
- line are passed to the program invoked by surun.
- .PP
- If the first argument to \fIsurun\fR is a -, the environment is changed
- to what would be expected if the user actually logged in as the
- specified user. This is done by invoking the program used as the
- shell with an arg0 value whose first character is -, thus
- causing first the system profile (/etc/profile, /etc/cshrc ) and then the
- specified user profile (.profile, .cshrc, .login in the new users $HOME
- directory) to be executed. Otherwise, the environment is passed along
- with the possible exception of $PATH, which is set to /bin:/usr/
- bin:/etc for root.
- .PP
- All attempts to execute a command via \fIsurun\fR are logged in the
- logfile \fI/usr/adm/surun.log\fR and the device \fI/dev/console\fR.
- The user's logname has to be an entry in the \fI/usr/adm/surun.allow\fR
- file otherwise surun will not execute.
- .SH FILE FORMAT
- \fI/usr/adm/surun.log\fR:
- .in +4
- .nf
- .sp
- SURUN 28/01 22:27 + vt01 dirk-root : ls
- | | | | | | |
- date --+ | | | | | +-- command executed
- time ---------+ | | | +--------- setuid to username
- valid (+) ------+ | +-------------- username
- invalid (-) |
- ttyname -------------+
- .sp
- .fi
- .in
- \fI/usr/adm/surun.log\fR:
- .in +4
- .nf
- .sp
- dirk:IX2.swq4zvjvU:2
- | | |
- | | +-- number of left retries for password
- | +----------- crypted password
- +-------------------- users logname
- .sp
- .fi
- A missing password disables the password check only if the number of left
- retries is NULL (e.g. dirk::) or not 0 (e.g. dirk::1).
- .sp
- A missing retry-number is interpreted as 1 if there is no password set
- .PP
- .SH EXAMPLES
- To execute the command 'ls /usr/adm' under the user 'bin' its
- privileges while retaining your previously exported environment,
- execute:
- .PP
- .in +12
- surun -u bin ls /usr/adm
- .PP
- To execute the same command but change the environment to what would
- be expected if 'bin' had originally logged in, execute:
- .PP
- .in +12
- surun - -u bin ls /usr/adm
- .PP
- To set a password, execute:
- .PP
- .in +12
- surun -p
- .SH FILES
- .nf
- /etc/passwd system password file
- /usr/adm/surun.log log file
- /usr/adm/surun.allow list of users allowed to execute surun
- /usr/adm/surun.tmp temporary file for updating the surun.allow file
- .if
- .PP
- .SH SEE ALSO
- su(1M), env(1), login(1), sh(1) \fIin the User's Reference Manual. \fR
- passwd(4), profile(4), environ(5) \fIin the Programmer's Reference Manual.\fR
- .SH CAVEATS
- Since the sh(1) which calls surun is doing the wildcarding, be aware of
- wildcards to directories which are not readable by you. Pass these wildcards
- using quotes.
- .sp
- Example:
- .in +4
- /usr/lib is not readable for you.
- .br
- entering 'surun vi /usr/lib/uucp/L.*' will result in '/usr/lib/uucp' and not
- in '/usr/lib/uucp/L.sys' due /usr/lib/uucp is not readable by you. Use the
- command 'surun vi "/usr/lib/uucp/L.*"' instead.
- .in -4
- .SH AUTHOR
- Dirk Koeppen, DK-SOFT, West Germany, .. unido!cosa!dirk
- End of ===surun.1M===
- exit 0
-