/* Copyright 1998, Merit Network, Inc. and the University of Michigan */
/* $Id: pgpchk.c,v 1.10 1999/09/10 00:38:40 gerald Exp $*/

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <regex.h>
#include <stdlib.h>
#include <errno.h>

#include <irrauth.h>

/* Decode the PGP file, and copy to the output stream any cookies */
/*
int pgpdecodefile(char *infn, char *outfn) {
*/
int pgpdecodefile (FILE *infile, char *outfn, FILE *log_fd, 
		   char *pgp_dir, trace_t *tr) {
  char pgpinfn[256], pgpoutfn[256], pgppub[256], pgpsec[256];
  char curline[4096];	/* XXX: This should probably be configurable */
  FILE /* *infile, */ *outfile, *pgppipe = NULL, *pgpinfile = NULL;
  int done = 0, i;
  int inpgpsig = 0;
  int p[2];
  regex_t pgpbegre, pgpendre, cookiere, pgpkeyidre, pgpmailidre;
  regex_t pgpgoodre, cookieinsre;
  regmatch_t pgpkeyidrm[3], pgpmailidrm[2];
  char auth[16][128];
  int authcount = 0, pgp_good;
  char *tmp;
  int n = 0;

  strcpy (outfn, tmpfntmpl);
  my_mktemp (tr, outfn);

  umask(0077);
  /*
  infile = fopen(infn, "r");
  if (NULL == infile) {
    fprintf(stderr, "Error opening input file %s: %s(%d).\n", infn, strerror(errno), errno);
    return(-1);
  }
  */

  outfile = fopen(outfn, "w");
  if (NULL == outfile) {
    fprintf(stderr, "Error opening output file %s: %s(%d).\n", outfn, strerror(errno), errno);
    return(-1);
  }
 
  n = regcomp (&pgpbegre, pgpbegin, 0);
  n = regcomp (&pgpendre, pgpend, 0);
  n = regcomp (&cookiere, cookie, 0);
  n = regcomp (&pgpgoodre, pgpgood, REG_EXTENDED|REG_NOSUB);

  while (!done) {
    done = (NULL == fgets (curline, MAXLEN, infile)) ? 1 : 0;

    if (!done && ((tmp = strchr (curline, '\r')) != NULL)) {
      *tmp   = '\n';
      *++tmp = '\0';
    }

    if (!done && (!strcmp (curline, "!q\n") || !strcmp (curline, "!q")))
	done = 1;
	
    if (done)
      i = *curline = 0;
    else {
      i = strlen(curline);
      if (log_fd != NULL)
	fputs (curline, log_fd);
    }

    if (i > MAXLEN) {
      fprintf(stderr, "Line too long! Truncating...\n");
      curline[2048] = 0;
      while (fgetc(infile) != (int) "\n")  { ; } /* Throw it away */
    }
    
    /* If we don't have pgp installed then don't look for a signature */
    if ((PGP != 0) && (0 == inpgpsig) && (0 == regexec (&pgpbegre, curline, 0, 0, 0))) {
      inpgpsig = 1;
    }

    switch(inpgpsig) {
 
      case 0: /* Normal, copy to another file mode */
	if (0 != regexec(&cookiere, curline, 0, 0, 0))
	  fputs(curline, outfile);
        break;

      case 1: /* got a PGP beginning line... */
        strcpy(pgpinfn, tmpfntmpl);
        my_mktemp (tr, pgpinfn);
	pgpinfile = fopen(pgpinfn, "w");
        if (NULL == pgpinfile) { printf("aieeeeeeeee!\n"); exit(0);}
	fputs(curline, pgpinfile);
        inpgpsig = 2;
        break;

      case 2: /* in the middle of a PGP section. continue to dump to file */
        fputs(curline, pgpinfile);
        if (0 == regexec(&pgpendre, curline, 0, 0, 0)) {
          /* End of the PGP stuff. process file, and reset counter. */

	  fclose(pgpinfile);

          strcpy(pgpoutfn, tmpfntmpl);
	  my_mktemp (tr, pgpoutfn);

	      printf ("Calling pgp...\n");
	      printf ("PGP=(%d) pgp_dir=(%s)\n", PGP, pgp_dir);
	      printf ("pgpbin=(%s)\n", pgpbin);

	  /* time to muck around with stdin and stdout... */;
	  pipe(p);
          if (fork() == 0) { /* Child */
            dup2(p[0], 1);
            dup2(p[0], 2);
            close(p[1]);

	    /* Sample v5 invokation
	       % /usr/local/bin/pgpv --pubring=/irr/etc/.pgp/pubring.pkr \
	         --secring=/irr/etc/.pgp/secring.skr mrp.test    
	    */
	    if (PGP == 5) {
	      if (pgp_dir != NULL) {
		sprintf (pgppub, "--%s=%s/%s", PUBKEYWORD, pgp_dir, PUBRINGNM);
		sprintf (pgpsec, "--%s=%s/%s", SECKEYWORD, pgp_dir, SECRINGNM);
		execlp (pgpbin, pgpbin, pgppub, pgpsec, pgpargs, pgpoutfn, pgpinfn, "\0");
	      }
	      else 
		execlp (pgpbin, pgpbin, pgpargs, pgpoutfn, pgpinfn, "\0");
	      trace (TR_TRACE, tr, 
		     "(pgpbin, pgpargs, pgpoutfn, pgpinfn)= (%s,%s,%s,%s)\n", 
		pgpbin, pgpargs, pgpoutfn, pgpinfn);
	    }
	    else if (PGP == 26) {
	      if (execlp (pgpbin, pgpbin, pgpargs, pgpoutfn, pgpinfn, "\0") < 0)
		trace (TR_TRACE, tr, "PGP error message: (%s)\n", 
		       strerror (errno));
	    }
	    else /* we should never get here */
	      trace (NORM, tr, "Bad signature...\n");
          } else {
            /* parent */ 
	    regcomp(&pgpkeyidre, pgpkeyid, REG_EXTENDED);
            regcomp(&pgpmailidre, pgpmailid, REG_EXTENDED);
            
            close(p[0]);
            if ((pgppipe = fdopen(p[1], "r")) == NULL) {
	      trace (NORM, tr, "fdopen in PGP decode failed\n");
	      return (-1);
	    }
	    trace (TR_TRACE, tr, "PGP parent: back from fork ()...\n");
            curline[0] = 0;
	    pgp_good   = 0;

trace (TR_TRACE, tr, "PGP (%d) mailidre (%s)\n", PGP, pgpmailid);

	    while (fgets(curline,MAXLEN,pgppipe) != NULL) {
	      if (curline[strlen(curline)-1] == '\n')
		curline[strlen(curline)-1] = '\0';
	      trace (TR_TRACE, tr, "PGP parent (%s)\n", curline);
trace (TR_TRACE, tr, "pgp_good = (%d)\n", pgp_good);
	      if (0 == regexec (&pgpgoodre, curline, 0, NULL, 0)) {
		pgp_good = 1;
		trace (TR_TRACE, tr, "setting pgp_good to 1...\n");
	      }
	      else if (pgp_good && 0 == regexec (&pgpkeyidre, curline, 3, pgpkeyidrm, 0)) {
	        tmp = curline + pgpkeyidrm[2].rm_eo;
                *tmp = 0;
                strcpy(auth[authcount], PGP_KEY);
		strcat(auth[authcount], (char *) (curline + pgpkeyidrm[2].rm_so));
                strcat(auth[authcount], "\n");
                authcount++;
                trace (TR_TRACE, tr, "PGP_KEY cookie (%s)\n", auth[authcount - 1]);
	        /*printf("%s\n", auth[authcount - 1]);*/
	      }
              else if ((pgp_good || PGP == 26) && 
		       0 == regexec (&pgpmailidre, curline, 2, pgpmailidrm, 0)) {
		pgp_good = 1;
                tmp = curline + pgpmailidrm[1].rm_eo;
                *tmp = 0;
                strcpy(auth[authcount], PGP_FROM);
                strcat(auth[authcount], (char *) (curline + pgpmailidrm[1].rm_so)); 
		strcat(auth[authcount], "\n");
		authcount++;
                trace (TR_TRACE, tr, "PGP_FROM cookie (%s)\n", auth[authcount - 1]);
	        /*printf("%s\n", auth[authcount - 1]);*/
              }

            }
            fclose(pgppipe);
            
	  } /* done with fork, and extracting all the email and key IDs */

          /* And copy the pgpoutfn file to outfile */
          if ((pgpinfile = fopen(pgpoutfn, "r")) == NULL) {
	    printf("Could not open PGP output file %s\n", pgpoutfn); exit(0);
	  }


          regcomp(&cookieinsre, cookieins, (REG_NOSUB|REG_EXTENDED|REG_ICASE));
          while (fgets(curline, sizeof(curline), pgpinfile) != NULL) {
            if (regexec(&cookiere, curline, 0, 0, 0))
              /* make sure it's not one of our cookies! */
              fputs(curline, outfile);
            if (0 == regexec(&cookieinsre, curline, 0, 0, 0)) {
              /* put in our cookies */
              /*printf("authcount = %d\n",authcount);*/
              /* Put all our ID cookie stuff in */
              if (authcount) {
		/* make sure our cookie does not concat with the prior line */
		i = strlen (curline);
		if (i > 0 && curline[i - 1] != '\n')
                  fputs ("\n", outfile);

                for (i=0; i < authcount; i++)
                  fputs(auth[i], outfile);
              }
            }
          }

	  fputs("\n", outfile);
	  /* Need to do that lest PGP border replay attacks happen */

	  fclose (pgpinfile);
          unlink (pgpinfn);
          unlink (pgpoutfn);
          inpgpsig  = 0;
	  authcount = 0;
        }

        break;

    } /* switch */

  } /* while !done */

  regfree (&pgpbegre);
  regfree (&pgpendre);
  regfree (&cookiere);
  regfree (&pgpgoodre);

  fflush (outfile);
  fclose (outfile);
  fclose (infile);
  return (0);
}

