#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pwd.h>
#include <shadow.h>

#define MAXBUF 256

int main()
{
  // Note that this requires /tmp being the same between the chroot and /
  // for this to work with the kerberos tickets.  

  fprintf(stderr, "\nEntering Athena chroot...\n\n");  

  struct passwd* passwd_data = getpwuid(getuid());
  if (passwd_data == NULL) {
    fprintf(stderr, "Error\n");
    fprintf(stderr, "Please contact the maintainers at linerva@mit.edu.\n\n");
    exit(1);
  }

  char buf[11][MAXBUF];
  char *env[12];
  snprintf(buf[0], MAXBUF-1, "%s=%s", "KRB5CCNAME", getenv("KRB5CCNAME"));
  env[0] = buf[0];
  snprintf(buf[1], MAXBUF-1, "%s=%s", "KRBTKFILE", getenv("KRBTKFILE"));
  env[1] = buf[1];
  snprintf(buf[2], MAXBUF-1, "%s=%s", "HOME", passwd_data->pw_dir);
  env[2] = buf[2];
  snprintf(buf[3], MAXBUF-1, "%s=%s", "TERM", getenv("TERM"));
  env[3] = buf[3];
  snprintf(buf[4], MAXBUF-1, "%s=%s", "USER", getenv("USER"));
  env[4] = buf[4];
  snprintf(buf[5], MAXBUF-1, "%s=%s", "SHELL", getenv("SHELL"));
  env[5] = buf[5];
  snprintf(buf[6], MAXBUF-1, "%s=%s", "ATHENA_SESSION_TMPDIR", getenv("ATHENA_SESSION_TMPDIR"));
  env[6] = buf[6];
  snprintf(buf[7], MAXBUF-1, "%s=%s", "ATHENA_LOGIN_SESSION", getenv("ATHENA_LOGIN_SESSION"));
  env[7] = buf[7];
  snprintf(buf[8], MAXBUF-1, "%s=%s", "XAUTHORITY", getenv("XAUTHORITY"));
  env[8] = buf[8];
  snprintf(buf[9], MAXBUF-1, "%s=%s", "PATH", "/usr/athena/bin:/usr/athena/etc:/bin/athena:/usr/bin:/bin:/usr/X11R6/bin:/usr/sbin:/sbin");
  env[9] = buf[9];
  snprintf(buf[10], MAXBUF-1, "%s=%s", "DISPLAY", getenv("DISPLAY"));
  if(strcmp(buf[10], "DISPLAY=(null)") == 0) {
	env[10] = NULL;
  }
  else {
	env[10] = buf[10];
  }
  env[11] = NULL;
  //printf("%s %s %s %s\n", env[0], env[1], env[2], env[3]);

  chdir("/compat");
  chroot("/compat");
  // lock shadow file so only one person does this at once.
  if (lckpwdf() != 0) {
    fprintf(stderr, "Error\n");
    fprintf(stderr, "Please contact the maintainers at linerva@mit.edu.\n\n");
    exit(1);
  }  
  struct passwd *passwd_athena = getpwnam(passwd_data->pw_name);
  if(passwd_athena == NULL) {
    FILE *passwd_file = fopen("/etc/passwd", "a");    
    if (putpwent(passwd_data, passwd_file) != 0) {
      fprintf(stderr, "Error\n");
      fprintf(stderr, "Please contact the maintainers at linerva@mit.edu.\n\n");
      exit(1);
    }
    fclose(passwd_file);
  }
  
  // unlock shadow file
  if (ulckpwdf() != 0) {
    fprintf (stderr, "Error\n");
    fprintf(stderr, "Please contact the maintainers at linerva@mit.edu.\n\n");
    exit(1);
  }

  if(setregid(getgid(), getgid()) != 0) {
    fprintf(stderr, "Error\n");
    fprintf(stderr, "Please contact the maintainers at linerva@mit.edu.\n\n");
    exit(1);
  }
  if(setreuid(getuid(), getuid()) != 0) {
    fprintf(stderr, "Error\n");
    fprintf(stderr, "Please contact the maintainers at linerva@mit.edu.\n\n");
    exit(1);
  }
  chdir(passwd_data->pw_dir);

  //  printf("%s %s %s %s\n", env[0], env[1], env[2], env[3]);
  
  if ((passwd_athena = getpwuid(getuid())) == NULL) {
    fprintf (stderr, "Error\n");
    fprintf(stderr, "Please contact the maintainers at linerva@mit.edu.\n\n");
    exit(1);
  } 
  char str[MAXBUF];
  snprintf(str, MAXBUF-1, "env HOME=%s %s", passwd_athena->pw_dir, passwd_athena->pw_shell);
  //  printf(str);
  fprintf(stderr, "This Athena chroot should behave similarly to an Athena workstation.\n");  
  fprintf(stderr, "Some operations requiring escalated priveleges, including ping and\n");
  fprintf(stderr, "traceroute -- will not work because binaries are not setuid and some\n");
  fprintf(stderr, "service daemons are not running.\n");
  fprintf(stderr, "Contact linerva@mit.edu if you have any questions.  Enjoy!\n");  
  fprintf(stderr, "\n");
  execle(passwd_athena->pw_shell, passwd_athena->pw_shell, "-c", str, NULL, env);
  
  fprintf(stderr, "\nThere has been an error entering Athena mode.\n");
  fprintf(stderr, "Please contact the maintainers at linerva@mit.edu.\n\n");
  return -1;
}
