From: Gilbert Callaghan (gilbert@inviso.com)
Date: 06/30/93


From: gilbert@inviso.com (Gilbert Callaghan)
Subject: suid.c (was: Re: Is there # for Linux ?)
Date: Thu, 1 Jul 1993 04:03:22 GMT

In article <20s5maINN7m4@sbusol.rz.uni-sb.de> dragan@mpi-sb.mpg.de (Dragan Cvetkovic) writes:
>Hi, is # available for Linux? I am slowly geting tired of typing su every
>time I want to perform something as root and not as normal user, and I don't
>want to have root privilegies all the time (dangerous!).

Well I've never heard of '#', but it seems that what you're looking
for is the following program - suid.c. (btw this is not Linux specific)

This program does what su and newgrp do, but does it SO much better.

After compiling it, set the permissions to 4755 root root. I like to put
it in my ~/bin directory and name it '..'. Of course this requires removing
the real .. link! Anyway, you can name it '#' or '...' or whatever.

Usage: .. [-u <uid>] [-o <uid>] [-g <gid>] [-b] [-v] [<command string>]
Where:
    -u = set the uid to <uid> and set the gid to <uid>'s gid
    -o = set the uid to <uid>
    -g = set the gid to <gid>
    -b = run <command string> in the backgroup as nohup (no '&' needed)
    -v = display version number
    <command string> = what to do. If nothing is specified, or if a 'cd'
                       command is specified, starts a new shell.

    In addition, the ulimit is always raised to something ridiculous.

Examples:

    $ id
    uid=1001(gilbert) gid=1010(users)
    $ ..
    # ^D
    $ .. -u uucp
    $ id
    uid=5(uucp) gid=5(uucp)
    $ .. cat /etc/shadow
    [cat'ed text omited]
    $ .. -u daemon id
    uid=1(daemon) gid=1(other)
    $ .. -o daemon id
    uid=1(daemon) gid=1010(users)
    $ .. -g uucp id
    uid=1001(gilbert) gid=5(uucp)
    $ .. -b -u uucp some_uucp_script # runs in the background
    $ .. cd /some_private_dir
    # pwd
    /some_private_dir
    # ^D
    $

If the above examples did not impress you, or you didn't understand them,
then you don't need this program :-) Also please note that you MUST have
root access to install this program, so it won't give you anything you
don't already have; it just makes it LOTS more convenient.

One last thing. For extra security, this program checks the user id
against a hard-coded list of privileged users. This list is encrypted
using crypt. You can comment out this check if you want, but I suggest
that you add your encrypted login id to the list. To make it easier,
I have supplied a small program (after suid.c) that will generate
encrypted names.

==================== snip snip ===========================

/* suid.c - Change to any user or group without passwords */
/* By Gilbert Callaghan - gilbert@inviso.com */

/* V 1.0 05/01/92 First version */
/* V 2.0 02/08/93 After many revisions, now full-blown */
/* V 2.1 02/15/93 Now raises ulimit always */
/* V 2.2 02/28/93 Checks permissions for current dir */
/* V 2.3 03/04/93 Prompts for root passwd if not privileged */
/* V 2.4 06/30/93 Removed getopt() since Linux complained */

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>

char *crypt();
char *getenv();

main(argc, argv)
int argc;
char *argv[];
{
struct passwd *pwrec;
struct group *grrec;
int uid, gid, background=0, fd, out, err, seconds=0;
char c, *shell, *encrypted, *rpw;
static char str[31], epw[11], ofile[]="/tmp/suid.\0 ";
FILE *fp;

    uid = getuid();
    if (uid)
    {
        pwrec = getpwuid(uid);
        encrypted = crypt(pwrec->pw_name, "GC");
        if (strcmp(pwrec->pw_name, getenv("LOGNAME")) || (
/*********/
/********* replace these encrypted names below with your encrypted user id */
/*********/
            strcmp("GC6RNTjv6q8v.", encrypted) && /* gilbert */
            strcmp("GC8p3u64DBq9k", encrypted) )) /* neal */
        {
            puts("..: Sorry"); /* not a privileged user */
            exit(0);
        }
    }

    uid = gid = 0;
    while (**++argv == '-')
    {
        switch(*((*argv)+1))
        {
            case 'u': /* specify user and group */
                pwrec = getpwnam(*++argv);
                if (pwrec == (struct passwd *)0)
                {
                    fputs("No such uid\n", stderr);
                    exit(2);
                }
                uid = pwrec->pw_uid;
                gid = pwrec->pw_gid;
                argc-=2;
                break;
            case 'o': /* specify user (owner) only */
                pwrec = getpwnam(*++argv);
                if (pwrec == (struct passwd *)0)
                {
                    fputs("No such uid\n", stderr);
                    exit(2);
                }
                uid = pwrec->pw_uid;
                gid = getgid();
                argc-=2;
                break;
            case 'g': /* specify group only */
                grrec = getgrnam(*++argv);
                if (grrec == (struct group *)0)
                {
                    fputs("No such gid\n", stderr);
                    exit(2);
                }
                uid = getuid();
                gid = grrec->gr_gid;
                argc-=2;
                break;
            case 'i':
                seconds = atoi(*++argv) * 60;
                background = 1;
                argc--;
                break;
            case 'b':
                background = 1;
                argc--;
                break;
            case 'v':
                puts(".. version 2.3 3/04/93");
                exit(0);
        }
    }

    ulimit(2, 500000);

    setgid(gid);
    setuid(uid);

    if (!strcmp(argv[1], "cd"))
    {
        if (chdir(argv[2]) < 0)
        {
            perror("..: cannot cd");
            exit(2);
        }
        argc -= 2;
        argv += 2;
    }
    else
    {
        if (uid && argc==1) if (chdir(getcwd((char *)0, 128)) < 0)
        {
            fputs("..: no permission for current directory\n", stderr);
            exit(2);
        }
    }

    if (background)
    {
        out = isatty(1);
        err = isatty(2);
        if (out || err)
        {
            strcat(ofile, getenv("LOGNAME"));
            fputs("Sending output to ", stderr);
            fputs(ofile, stderr);
            fputc('\n', stderr);
            fd = open(ofile, O_CREAT|O_WRONLY|O_APPEND, S_IREAD|S_IWRITE);
            if (out) { close(1); dup(fd); }
            if (err) { close(2); dup(fd); }
            close(fd);
        }
        close(0);
        if (fork()) exit(0);
        setpgrp();
    }

    if (seconds) sleep(seconds);

    if ((shell=getenv("SHELL")) == 0) shell = "/bin/sh";

    if (argc == 1)
        execl(shell, shell, (char *)0);
    else
        execvp(*argv, argv);

    perror("..");
}

==================== snip snip ===========================

==================== snip snip ===========================
/* encrypt.c: */
main(argc, argv)
int argc;
char *argv[];
{
    if (argc == 2)
        printf("%s\n", crypt(argv[1]), "GC");
}
==================== snip snip ===========================