root (Was: another 'su encancer')
Tim Cook
timcc at csv.viccol.edu.au
Tue Apr 30 03:36:07 AEST 1991
In article <muts.672650807 at fysaj>, muts at fysak.fys.ruu.nl (Peter Mutsaers)
writes:
> Now that we are discussing a su encancer etc., here is a 'root' program that
> I've been using the last 1.5 year.
Here is my version, which I have been using for about a year.
> The syntax is 'root command [args]' and runs one command with su privilege.
Ditto.
> It is quite safe, and checks if the uid is right. (only works for one user).
My version checks you are in a particular group ("root" by default), just
like su(1) does.
> Without args it executes a shell with su privilege.
I have to put in a bit more work and say "root csh", but my version
automatically adds "/etc:/usr/etc" (this is configurable) to your PATH (if
they are not already there).
We have operators, including part-time operators who are allowed to use
this, so I prefer them not to be given a super-user shell unless they
explicitly ask for one.
Another feature that my version has that I have not seen in others, is that
it does an initgroups(3), to give the user _all_ super-user privileges.
> Of course this program must also be owned by root and be setuid.
Ditto.
> Change the number on the first line of main() to your own uid.
Compile mine with -DAUTHORIZED_GROUP='"wheel"', or whatever, if you prefer
that to "root". (By the way, what does the group name "wheel" mean?)
Also note that if you are on a system that does not have setenv(3) and
strstr(3) (like the one I developed this on), you will have to find
versions of these routines to be able to compile this. Look in the
bsd-sources directory on uunet, or ask me if you can't find these items.
#!/bin/sh
# This is a shell archive (shar 3.47)
# made 04/29/1991 02:17 UTC by timcc at admin.viccol.edu.au
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 3857 -rw-r----- root.c
# 1265 -r--r----- perror2.c
#
# ============= root.c ==============
if test -f 'root.c' -a X"$1" != X"-c"; then
echo 'x - skipping root.c (File already exists)'
else
echo 'x - extracting root.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'root.c' &&
/* root.c - Execute a command as superuser
X *
X * SYNOPSIS
X * root <command> [<parameter> ...]
X */
X
static char rcsid[] = "$Header: root.c 1.2 91/04/29 $" ;
X
#include <grp.h>
#include <stdio.h>
#include <string.h>
#include <sys/param.h> /* For NGROUPS */
X
extern char *getenv () ;
extern int setenv () ;
extern int setuid () ;
extern int setgid () ;
extern int initgroups () ;
extern char *search_path () ;
extern char *malloc () ;
X
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define NULL_CP (char *) 0
#define EOS '\0'
#define fprint(f, s) fputs (s, f)
X
static char *program_name ;
X
/*
X * If this is defined, the user must be a member of AUTHORIZED_GROUP
X * before they are allowed to execute their desired command as
X * super-user.
X */
#ifndef AUTHORIZED_GROUP
#define AUTHORIZED_GROUP "root"
#endif
X
/*
X * These directories are added to the PATH environment variable before
X * the specified command is executed. This must be terminated by a
X * null pointer.
X */
static char *dirs_for_path[] = { "/etc", "/usr/etc", NULL_CP } ;
X
X
static void add_to_path (path, element)
X char *path, *element ;
{
X char *path_p ;
X char *elem_p ;
X int elem_l = strlen (element) ;
X
X if ((path_p = malloc (strlen (path) + 3) + elem_l) == NULL_CP) {
X perror2 (program_name, "malloc") ;
X exit (1) ; }
X if ((elem_p = malloc (elem_l + 3)) == NULL_CP) {
X perror2 (program_name, "malloc") ;
X exit (1) ; }
X
X *path_p++ = ':' ;
X strcpy (path_p, path) ;
X strcat (path_p, ":") ;
X *elem_p++ = ':' ;
X strcpy (elem_p, element) ;
X strcat (elem_p, ":") ;
X if (strstr (--path_p, --elem_p) == NULL_CP) {
X /* Not already in path, so add it */
X strcat (path_p, element) ;
X strcpy (path, ++path_p) ; }
X free (path_p) ;
X free (elem_p) ;
X }
X
X
int main (argc, argv)
X int argc ;
X char *argv[] ;
X {
X static char path[256] ; /* This may need to be bigger */
X char *exec_this ;
X char **dirs ;
#ifdef AUTHORIZED_GROUP
X int no_groups ;
X int group_list[NGROUPS] ;
X struct group *auth_group ;
X int i ;
X int member ;
#endif
X
X program_name = argv[0] ;
X if (argc < 2) {
X fprint (stderr, "usage: ") ;
X fprint (stderr, program_name) ;
X fprint (stderr, " <command> [<parameter> ...]\n") ;
X exit (2) ; }
X
#ifdef AUTHORIZED_GROUP
X /* If this code is used, only members of the AUTHORIZED_GROUP are
X given the privileges offered by this program. */
X
X if ((no_groups = getgroups (NGROUPS, group_list)) == -1) {
X perror2 (program_name, "getgroups") ;
X exit (1) ; }
X if ((auth_group = getgrnam (AUTHORIZED_GROUP))
X == (struct group *) NULL) {
X perror2 (program_name, "getgrnam") ;
X exit (1) ; }
X
X for (i = 0, member = FALSE ; i < no_groups && (! member) ; i++) {
X member = group_list[i] == auth_group->gr_gid ; }
X
X if (! member) {
X fprint (stderr, program_name) ;
#ifdef NOT_SECRET
X fprint (stderr, ": not a member of \"") ;
X fprint (stderr, AUTHORIZED_GROUP) ;
X fprint (stderr, "\" group\n") ;
#else
X /* Perhaps the method of authorization is privileged information? */
X fprint (stderr, ": not authorized\n") ;
#endif
X exit (1) ; }
#endif
X
X if (initgroups ("root", 0) == 1) {
X fprint (stderr, program_name) ;
X fprint (stderr, ": not super-user\n") ;
X exit (1) ; }
X if (setgid (0) == -1) {
X perror2 (program_name, "setgid") ;
X exit (1) ; }
X if (setuid (0) == -1) {
X perror2 (program_name, "setuid") ;
X exit (1) ; }
X
X strcat (path, getenv ("PATH")) ;
X for (dirs = dirs_for_path ; *dirs != NULL_CP ; dirs++)
X add_to_path (path, *dirs) ;
X if (setenv ("PATH", path, TRUE) == -1) {
X perror2 (program_name, "setenv") ;
X exit (1) ; }
X
X if (execvp (argv[1], &argv[1]) != 0) {
X perror2 (program_name, argv[1]) ;
X exit (1) ; }
X exit (0) ;
X }
SHAR_EOF
chmod 0640 root.c ||
echo 'restore of root.c failed'
fi
# ============= perror2.c ==============
if test -f 'perror2.c' -a X"$1" != X"-c"; then
echo 'x - skipping perror2.c (File already exists)'
else
echo 'x - extracting perror2.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'perror2.c' &&
/* perror2 - Like perror(3), but with two string prefixes
X *
X * SYNOPSIS
X * void perror2 (const char *str1, const char *str2) ;
X *
X * DESCRIPTION
X * Prints str1, then a colon and a space, then str2, then a colon and
X * a space, then the error message corresponding to the contents of
X * errno, then a newline on stderr.
X */
X
static char rcsid[] = "$Header: perror2.c 1.1 91/03/22 $" ;
X
extern int strlen () ;
X
X
void perror2 (str1, str2)
X char *str1, *str2 ;
{
X extern int errno ;
X extern char *sys_errlist[] ;
X extern int sys_nerr ;
X register int save_errno = errno ;
X static char unknown_error[] = "Unknown error" ;
X static char colon_space[2] = {':', ' '} ;
X static char newline = '\n' ;
X char *p ;
X
X if (save_errno < 0 || save_errno >= sys_nerr)
X p = unknown_error ;
X else
X p = sys_errlist[save_errno] ;
X write (2, str1, strlen (str1)) ;
X write (2, colon_space, sizeof (colon_space)) ;
X write (2, str2, strlen (str2)) ;
X write (2, colon_space, sizeof (colon_space)) ;
X write (2, p, strlen (p)) ;
X write (2, &newline, 1) ;
X }
X
X
#ifdef TEST
X
int main (argc, argv)
X int argc ;
X char **argv ;
{
X extern int errno ;
X
X errno = atoi (argv[1]) ;
X perror2 (argv[2], argv[3]) ;
X exit (1) ;
X }
X
#endif /* TEST */
SHAR_EOF
chmod 0440 perror2.c ||
echo 'restore of perror2.c failed'
fi
exit 0
More information about the Alt.sources
mailing list