brendan@CS.WIDENER.EDU (Brendan Kehoe) (12/22/90)
This is a program I'd been working on about 3 months ago, then got too busy and forgot about it. Sooo last night I finally sat down and made it work. Towards even better system management, this will let you find out what directories your users are sitting in. There's lots of room for improvement (e.g. taking an argument of a pid or username), etc. Anything you wanna do to it, feel free -- just send me a copy of whatcha did. To use it ya hafta either be root or have it set-gid to kmem (which I wouldn't recommend). Oh it was written and tested on a Sun; I've been told the u_cwd structure doesn't exist outside of Suns, so not everybody will be able to use this. (The alternative's getting the inode they're on & tracing it for every user.) Anyway, to the code .. The usual disclaimers and covering of butt apply. Enjoy! -- cut -- /* * peek v1.0 - Brendan Kehoe (brendan@cs.widener.edu) * * Peek in and see what directory a user's sitting in, along with * what they happen to be doing at the time, and if they've set * id to someone else. (An R means they're setuid to root, a '*' * means they're setuid to someone else.) Remember, many programs do * the setuid themselves [e.g. xterm], so don't freak if you see an R * there. * * This has only been used under SunOS 4.1. It probably won't work on * other systems. (But you can try .. let me know if it does!) * * Any comments, insults, fixes, whatever, are more than welcome. * * You must build this with -lkvm. */ #include <stdio.h> #include <sys/types.h> #include <kvm.h> #include <fcntl.h> #include <pwd.h> #include <sys/param.h> #include <sys/time.h> #include <sys/proc.h> #include <sys/user.h> static char *minus = "------------------------", *space = " ", *home = "~/"; #define MAXCOMWID 24 /* max "what" width */ main (argc, argv) int argc; char **argv; { struct proc *p; struct user *u; struct passwd *w; struct ucwd cwd; static kvm_t *kd; static char buf[100], outcmd[MAXCOMLEN + 1], *dirp, flag; char *root = home + 1; short homelen; if ((kd = kvm_open (NULL, NULL, NULL, O_RDONLY, "spy.dirs")) == NULL) { (void) fprintf (stderr, "%s: couldn't open the kernel\n", *argv); exit (1); } printf("\nName (*=Su)| What %s| ProcID | Current Directory\n\ -----------+%s+--------+--------------------\n", space + MAXCOMWID + 4 - MAXCOMLEN, minus + MAXCOMWID - 2 - MAXCOMLEN); kvm_setproc (kd); while ((p = kvm_nextproc (kd))) /* only get active stuff */ if (p->p_stat != SZOMB && p->p_uid) { /* * first read the u-area */ if (!(u = kvm_getu(kd, p))) continue; /* * now read in the u_cwd structure .. it's buried in the kernel */ if (kvm_read(kd, (unsigned long) u->u_cwd, (struct ucwd *) &cwd, sizeof(struct ucwd)) < 0) { perror("kvm_read structure"); exit(1); } /* * and finally get the name of the directory; it's buried there too * but if it's bogus (they don't show up with one), leap on */ if (!cwd.cw_dir) break; if (kvm_read(kd, (unsigned long) cwd.cw_dir, buf, 100) < 0) { perror("kvm_read dir"); exit(1); } /* * Read in their bio */ w = getpwuid(p->p_uid); dirp = buf; if (!*dirp) /* * If the kernel-read didn't read anything for their current dir, * they're in the root directory */ dirp = root; else if (p->p_uid && *(w->pw_dir) && *(w->pw_dir + 1)) { /* * Make sure that their home directory, if they have one, * isn't the root (/) directory. We won't do anything if * their home's / or they logged in without a home (e.g. * their home fs wasn't mounted at the time). */ if (strlen(w->pw_dir) == strlen(dirp) && ! strcmp(w->pw_dir, dirp)) /* * If they're in their home directory, make it just "~/" */ dirp = home; else if (strncmp(buf, w->pw_dir, homelen = strlen(w->pw_dir)) == 0) { /* * Ok, it's $HOME/blah, so make it ~/blah */ *(dirp = buf + homelen - 1) = '~'; *(dirp + 1) = '/'; } } *outcmd = '\0'; if (strlen(u->u_comm) > MAXCOMLEN) { strncpy(outcmd, u->u_comm, MAXCOMLEN); *(outcmd + MAXCOMLEN + 1) = '\0'; } flag = ' '; if (!p->p_suid) /* * if they're root, scream it */ flag = 'R'; else if (p->p_uid != p->p_suid) /* * otherwise it might be harmless; just mark it */ flag = '*'; printf("%*s%c | %*s | %6d%c| %*s\n", -9, w->pw_name, flag, -MAXCOMLEN, *outcmd ? outcmd : u->u_comm, p->p_pid, (p->p_flag & SLOGIN) ? 's' : ' ', -39, dirp); } } -- cut -- -- Brendan Kehoe - Widener Sun Network Manager - brendan@cs.widener.edu Get ``Red Hot & Blue'', songs by Cole Porter sung by U2, Sinead O'Connor, The Neville Brothers, Tom Waits, & many more. Proceeds benefit AIDS research.