From: dan@cedb.dpcsys.org (Dan Busarow)
Newsgroups: biz.sco.general
Subject: Re: How to allow a user "shutdown"
Date: 22 Jul 92 17:26:03 GMT
Organization: DPC Systems, Monrovia, CA

In article <eBLaoB2w164w@zswamp.UUCP>, geoff@zswamp.UUCP (Geoffrey Welsh) writes:
> wehler@welfa4.elektro.uni-wuppertal.de (Andreas Wehler) writes:
> 
> > does someone know how to allow a certain normal user to shutdown the 
> > system?
>
>    Create a directory under his home directory in which he has read and 
> execute permissions only, and (optionally) make his .profile add it to his 
> path.  In it, put a shell script owned by root, with the setuserid bit on.  
                      ^^^^^^^^^^^^                         ^^^^^^^^^^^^^^^^
> The shell script contains the shutdown command. When he executes it (either 
> by path or explicitly),it will run shutdown as root,but it doesn't give him 
> any other special privileges.

I don't know about 3.2.4 but 3.2.0 and 3.2.2 DO NOT honor the set uid bit
for scripts.  This is not just an SCOism, some of the other unices do this
as well since a clear text script is much easier to compromise than a
binary.

Someone else suggested adding the user in question to group 'sys' and changing
the mode of /etc/shutdown to 750.  This allows the user to execute shutdown
but fails to achieve the desired outcome for two reasons.  First, shutdown
verifies that it is being executed by root and exits after a warning if this
is not true.  Second, were you to disable this test, shutdown tries to execute
/etc/init which is mode 100 owned by bin so there is another file to change
permissions on. :(

A few years ago I picked up a program named priv from Unix World.  This
program allows normal users to execute commands as root if they are
listed in its database.  I added access lists so that certain users were 
restricted to only those programs in their access list.

As listed below NEWPATH is defined as a 'standard' root path to minimize
problems with Trojan horses.

Please note that /bin/sh is a program and may be executed using priv if
the users has the proper access rights or DOES NOT HAVE AN ACCESS LIST
in /usr/lib/priv/ .  You may want to change this default behaviour but
it fit my situation where the only people allowed to run this had the
root password, priv was just quicker than su'ing or logging in as root
to do something simple like enabling a terminal.

The .profile for user 'stop' and priv.c follow.

Enjoy

Dan

8<-------- .profile for user dedicated to shutting down the system -------
:
PATH=/bin:/usr/bin:/u/local/bin
export PATH

eval `tset -m ansi:ansi -m :\?${TERM:-ansi} -r -s -Q`
TTY=`tty`
TTY=`basename $TTY`
if [ "$TTY" != "tty01" ]
then
    echo "The system must be shutdown from the console (tty01)"
    exit 1
fi
USERS=`who | wc -l`
if [ $USERS -ne 1 ]
then
    while true
    do
        echo "There are still $USERS people logged in"
        echo "Continue with shutdown anyway? \c"
        read ans
        case $ans in
            y|Y)
                break
                ;;
            n|N)
                exit 1
                ;;
            *)
                echo "Y or N please."
                ;;
        esac
    done
fi
priv shutdown
exit 0
----------------- end .profile ---------------------------------------------

8<----- priv.c -------------------------------------------------------------
/*
 * priv  Run a command as superuser
 * by Ron Kuris, December 1988
 */
/* 
    access list added by Dan Busarow, DPC Systems, 11/22/91
 
    files: /etc/.priv.list 
                a list of authorized user login names, one per line
                should be mode 400 owned by root
              
           /usr/lib/priv/login_name 
                a list of authorized commands, one per line
                this should also be 400 owned by root
              
           priv should be mode 4111, owned by root
*/

#include <stdio.h>
#include <pwd.h>

#define PRIVLIST "/etc/.priv.list"
#define ACCESSDIR "/usr/lib/priv/"
#define LONGESTNAME 64
#define ERREXIT 1
/* If NEWPATH isn't defined, then PATH is taken from calling program */
#define NEWPATH "PATH=/bin:/etc:/usr/bin"

extern unsigned short getuid();
extern char *malloc();

main(argc,argv,envp)
char **argv, **envp;
int argc;
{
    struct passwd *getpwuid(), *pw;
    extern void exit();
    FILE *fp;
    char aList[64], buffer[LONGESTNAME+1], *lname, *prog;
    short i, j, ok;

    prog = argv[0]; /* store program name */
    if (argc < 2) 
    {   /***
        (void)fprintf(stderr,"Usage: %s command args\n", prog);
        no error messages, this program is not intended for use
        by the general public, authorized users will know how to
        run it
        ***/
        exit(ERREXIT);
    }
    pw = getpwuid((int)getuid());
    lname = pw->pw_name;
    if ((fp = fopen(PRIVLIST, "r")) == NULL) 
    {   (void)fprintf(stderr, "Can't open database\n");
        exit(ERREXIT);
    }
    while (fgets(buffer, LONGESTNAME, fp) != NULL) 
    {   buffer[strlen(buffer)-1] = '\0'; /* zap newline */
        if (!strcmp(lname, buffer)) 
        {   (void)fclose(fp);
            ok = 0;
            strcpy(aList,ACCESSDIR);
            strcat(aList,lname);
            if ((fp = fopen(aList, "r")) == NULL) 
                ok = 1; /* default, no restrictions.  this person is now root
                           so you had better trust them! */
            else
            {   while(fgets(buffer,LONGESTNAME,fp) != NULL)
                {   buffer[strlen(buffer)-1] = 0;
                    if(!strcmp(buffer,argv[1]))
                    {   ok = 1;
                        break;
                    }
                }
            }
            if(!ok) /* failed access list test */
                break;
#ifndef NEWPATH
            if (getenv("PATH") == NULL) 
            {   (void)fprintf(stderr,"%s: No path.\n", prog);
                exit(ERREXIT);
            }
#endif
            for (i=0; envp[i]; i++) 
            {   if (!strncmp("PATH=", envp[i], 5)) 
                {
#ifdef NEWPATH
                    envp[i] = NEWPATH;
#endif
                    break;
                }
            }
#ifdef NEWPATH
            if (!envp[i]) 
            {   extern char **environ;
                char **newenv = (char **)malloc((i+2)*sizeof(char *));
                for (j = 0; j < i; j++)
                    newenv[j] = envp[j];
                newenv[j] = NEWPATH;
                newenv[j+1] = NULL;
                environ = newenv;
            }
#endif
            (void)setuid(0);
            (void)setgid(0);
            (void)execvp(argv[1], argv+1);
            (void)fprintf(stderr,"%s: can't execute %s\n",prog,argv[1]);
            exit(ERREXIT);
        }
    }
    /* failed authorization test */
    (void)fclose(fp);
    exit(ERREXIT);
    /* NOTREACHED */
}
--------------- end priv.c ------------------------------------------------



-- 
+                                                                            -
   Dan Busarow             dan@cedb.dpcsys.org              uunet!cedb!dan
   DPC SYSTEMS                Monrovia, CA                  (818) 305-5733
-                                                                            +