[alt.hackers] Get a user's current directory

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.