
/*
   Author: LinBSD
   Requires: libcap ftp://ftp.kernel.org/pub/linux/libs/security/linux-privs/
*/

/******************************************************************************/
/* THE BEER-WARE LICENSE   (Revision 42):                                     */
/*  As long as you retain this notice you can do whatever you want with this  */
/*   stuff. If we meet some day, and you think this stuff is worth it,        */
/*   you can buy me a beer in return.    Ned Ludd. --solarx                   */
/******************************************************************************/

#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#undef _POSIX_SOURCE
#include <sys/capability.h>

#include <unistd.h>
#include <dirent.h>
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
#include <pwd.h>

extern char *basename();

#define PROC_DIR "/proc"

char *get_proc_name(pid_t pid)
{
   FILE *fp;
   static char buf[PATH_MAX];

   memset(&buf, 0, sizeof(buf));

   snprintf(buf, sizeof(buf), "/proc/%d/stat", (int) pid);

   fp = fopen(buf, "r");

   if (fp == NULL)
      return "unknown";

   fscanf(fp, "%*d %s.sizeof(buf)", buf);
   strcpy(buf, &buf[1]);
   buf[strlen(buf) - 1] = '\0';
buf[10] = 0;
   fclose(fp);
   return buf;
}

struct passwd *get_proc_uid(pid_t pid)
{
   struct stat st;
   static char s[PATH_MAX];

   snprintf(s, sizeof(s), "/proc/%d/stat", (int) pid);

   if ((stat(s, &st)) != (-1))
      return getpwuid(st.st_uid);

   return NULL;
}

void pscaps()
{
   register DIR *dir;
   register struct dirent *de;
   register pid_t pid;

   struct stat st;
   ssize_t length;

   cap_t cap_d;
   cap_d = cap_init();

   chdir(PROC_DIR);
   if (!(dir = opendir(PROC_DIR))) {
      perror(PROC_DIR);
      exit(EXIT_FAILURE);
   }

   while ((de = readdir(dir))) {
      errno = 0;
      stat(de->d_name, &st);
      if ((errno != ENOENT) && (errno != EACCES)) {
	 pid = (pid_t) atoi((char *) basename((char *) de->d_name));
	 if (!pid)
	    continue;

	 if (cap_d == NULL) {
	    fprintf(stderr, "Failed to make a blank capability set (%s) for %d\n", strerror(errno), pid);
	    exit(EXIT_FAILURE);
	 }

	 /* this is a non-POSIX function */
	 if (capgetp(pid, cap_d)) {
	    fprintf(stderr, "Failed to get cap's for proccess %d:"
		    " (%s)\n", pid, strerror(errno));
	    continue;
	 } else {
	    /* get the username */
	    struct passwd *pwd = get_proc_uid(pid);
	    char *result = cap_to_text(cap_d, &length);

	    fprintf(stderr, "%-8s %-10d %-10s '%-20s'\n",
		    pwd->pw_name ? pwd->pw_name : "unknown", pid,
		    get_proc_name(pid), result);
	    cap_free(result);
	    result = NULL;
	 }
      }
   }
   closedir(dir);
}

int main(int argc, char **argv)
{

#ifndef NO_UIDCHECK
   if (geteuid()) {
      puts("EUID 0 required: type su - root");
      exit(EXIT_FAILURE);
   }
#endif

   pscaps();
   return 0;
}
