
#include "lclient.h"

#ifdef _AIX
#define _POSIX_SOURCE
#endif

#include <stdio.h>
#include <errno.h>
#include <string.h>	/* strerror() */
#ifdef _AIX
#include <fcntl.h>
#else
#include <sys/file.h>
#endif

extern char *tmpnam(char *);

/* Copy an encrypted executable to a temporary file, decrypting with
   the supplied key.  Remove the temporary file as soon as possible.
   Return the process ID of the child, or 0 on failure.  */

int decrypt_exec(const char *progname, char *argv[], int infile,
		 unsigned char *init_key)
{
  int fd, pid;
  char tempfilename[L_tmpnam];

#ifndef HAVE_VFORK
  char tmpchar;
  int p[2];
#endif

  strcpy(tempfilename, "/tmp/decrXXXXXX");
  tmpnam(tempfilename);
  unlink(tempfilename);

  /* user execute, no read, no write */
  fd = open(tempfilename, O_WRONLY | O_CREAT | O_EXCL, 0100);
  if (fd == -1)
    {
      fprintf(stderr, "%s: unable to open temporary file: %s\n",
	      progname, strerror(errno));
      return 0;
    }
  if (copy_crypt_file(progname, infile, fd, init_key, 0))
    {
      unlink(tempfilename);
      close(fd);
      return 0;
    }

  /* must close before exec */
  close(fd);

#ifdef HAVE_VFORK
  pid = vfork();
#else
  if (pipe(p) == -1)
    return 0;
  if (fcntl(p[1], F_SETFD, 1) == -1)
    return 0;
  pid = fork();
#endif

  if (pid == -1)
    {
      fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
      unlink(tempfilename);
      close(fd);
      return 0;
    }

  if (pid == 0)
    {
#ifndef HAVE_VFORK
      close(p[0]);
#endif
#if DEBUG > 1
      link(tempfilename, "/tmp/jfc0");
#endif
      execv(tempfilename, argv);
      perror("exec");
      _exit(2);
    }

  /* It is safe to unlink now if vfork is being used, because the
     subprocess has already started the program.  */

#ifndef HAVE_VFORK
  close(p[1]);
  /* Allow at most 3 seconds to exec the program.  */
  alarm(3);
  /* When the child execs the program, the pipe is closed and this read
     returns EOF.  On BSD the close happens after the kernel has a reference
     to the executable.  I think any other UNIX will also do the right thing.
     --jfc  */
  read(p[0], &tmpchar, 1);
  alarm(0);
#endif

  unlink(tempfilename);
  return pid;
}

