/*
 *            pcfs - pseudo cryptographic file system
 *                      (c) 2000 by Mixter
 *
 *  This tool just creates a recursive directory and file structure
 *  that contains purely random data, but is indistinguishable from a
 *  encrypted CFS directory, unless an extensive cryptanalysis is performed.
 *  This can be taken as a proof that a strange directory cannot easily be
 *  proven to actually contain encrypted data. May be useful against f3dz,
 *  just for decoy purposes, or to keep people from analyzing your
 *  cryptographic file systems structure. Distributed according to the GPL.
 *
 *  WARNING: THIS PROGRAM IS SUBJECT TO PSEUDO-CRYPTOGRAPHIC EXPORT
 *  CONTROLS AND US-RESTRICTIONS AGAINST RANDOM DATA! =P
 *  This code was reviewed and approved by the SCC (sloppy code commission)
 *  gcc -Wall -O2 pcfs.c -o pcfs
 */

#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#define START_PATH	"fake"

mode_t modes[7] =
{00755, 00644, 0000, 00664, 00700, 00777, 00444};
char chr[16] = "abcdef1234567890", rseed[65535], buffer[256];
char wd[200];
int rcounter = 0;
void random_init (void);
inline long gr (int, int);
char *rname (void);
mode_t rmode (void);
void mkfiles (void);
void mkd (char *, int);

int
main (void)
{
  printf ("Creating fake file system in %s/%s, press a key\n",
	  getcwd (wd, 200), START_PATH);
  (void) getchar ();
  printf ("Hit CTRL+C to stop - creating files");
  if (!geteuid ())
    setpriority (PRIO_PROCESS, 0, -10);
  mkd (START_PATH, 0);
  return 0;
}

void
mkd (char *dirname, int forking)
{
  printf (".");
  fflush (stdout);

  if (forking)
    if (fork ())
      return;
  mkdir (dirname, rmode ());
  getcwd (wd, 200);
  strcat (wd, "/");
  strcat (wd, dirname);
  chdir (wd);
  if (forking)
    mkfiles ();
  else
    {
      char smbuf[32];
      int a, f = open ("/dev/urandom", O_RDONLY);
      read (f, smbuf, 32);
      a = open ("...", O_WRONLY | O_CREAT | O_TRUNC, 00644);	/* hash */
      write (a, smbuf, gr (5, 10));
      close (a);
      sprintf (smbuf, "%ld", gr (1, 5));
      a = open ("..c", O_WRONLY | O_CREAT | O_TRUNC, 00644);	/* algorithm */
      write (a, smbuf, strlen(smbuf));
      close (a);
      read (f, smbuf, 32);
      a = open ("..k", O_WRONLY | O_CREAT | O_TRUNC, 00644);	/* encrypted key */
      write (a, smbuf, 32);
      close (a);
      close (f);
      sprintf (smbuf, "%ld", gr (1000, 900000));
      a = open ("..s", O_WRONLY | O_CREAT | O_TRUNC, 00644);	/* session blah */
      write (a, smbuf, strlen(smbuf));
      close (a);
      while (1)
	mkfiles ();
    }
}

void
mkfiles (void)
{
  while (gr (0, 25))
    if (!gr (0, 10))
      mkd (rname (), 1);
    else
      {
	int f = open ("/dev/urandom", O_RDONLY), x, y = gr (0, 65500);
	char fname[256], fn2[256], big[65535];
	memset (fname, 0, 256);
	memset (fn2, 0, 256);
	sprintf (fname, "%s", rname ());
	sprintf (fn2, ".pvect_%s", rname ());
	symlink (fname, fn2);
	x = open (fname, O_RDWR | O_CREAT, rmode());
	read (f, big, y);
	write (x, big, y);
	close (f);
	close (x);
      }
}

char *
rname (void)
{
  int i;
  memset (buffer, 0, 256);
  for (i = 0; i < gr (5, 150); i++)
    buffer[i] = chr[gr (0, 15)];
  return buffer;
}

mode_t
rmode (void)
{
  return (modes[gr (0, 6)]);
}

void
random_init (void)
{
  int rfd = open ("/dev/urandom", O_RDONLY);
  if (rfd < 0)
    rfd = open ("/dev/random", O_RDONLY);
  rcounter = read (rfd, rseed, 65535);
  close (rfd);
}

inline
long
gr (int min, int max)
{
  if (rcounter < 2)
    random_init ();
  srand (rseed[rcounter] + (rseed[rcounter - 1] << 8));
  rcounter -= 2;
  return ((random () % (int) (((max) + 1) - (min))) + (min));
}
