## modules/pa/gpg.c

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. PA_VerifySignature
2. PA_Decrypt
3. PA_ImportKey
4. PA_RemoveKey
5. PA_ParseMessage
6. GetFingerPrint
7. VerifySignAndExplodeFile
8. GetKeyID

       1 /***************************************
       2   $Revision: 1.28 $
       3
       4   gpg.c - core of the PA module. Contains functions that are used
       5   to check the PGP authentication in a message.
       6
       7   Status: COMPLETE, REVUED, TESTED
       8
       9   ******************/ /******************
      10   Filename            : gpg.c
      11   Authors             : Filippo Portera, Daniele Arena
      12   OSs Tested          : Solaris 7
      13   ******************/ /******************
      14   Copyright (c) 2000                              RIPE NCC
      15
      16   All Rights Reserved
      17
      18   Permission to use, copy, modify, and distribute this software and its
      19   documentation for any purpose and without fee is hereby granted,
      20   provided that the above copyright notice appear in all copies and that
      21   both that copyright notice and this permission notice appear in
      22   supporting documentation, and that the name of the author not be
      23   used in advertising or publicity pertaining to distribution of the
      24   software without specific, written prior permission.
      25
      26   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
      27   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
      28   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
      29   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
      30   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      31   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      32   ***************************************/
      33
      34
      35
      36 #include <stdio.h>
      37 #include <stdlib.h>
      38 #include <string.h>
      39 #include <sys/wait.h>
      40 #include <unistd.h>
      41 #include <errno.h>
      42 #include <sys/types.h>
      43 #include <sys/stat.h>
      44 #include <fcntl.h>
      45 #include <time.h>
      46 #include <signal.h>
      47 #include <sys/time.h>
      48 #include <sys/param.h>
      49
      50 #include "mm.h"
      51 /*#include "misc.h"*/   /* isMIME functions need case insensitive string search()*/
      52 #include "gpg.h"
      53 #include "erroutines.h"
      54
      55 extern char EP_outputPrefix[FILENAME_LENGTH];
      56 extern char EP_keyRing[FILENAME_LENGTH];
      57 extern char EP_gpgcmd[FILENAME_LENGTH];
      58 extern int  EP_TreeHeight;
      59 extern int  EP_Node_ID;
      60 extern int  EP_Debug;
      61
      62 /* static int parseMailBlock_nMsg;
      63    static int parseRecursionLevel; */
      64
      65 extern int sd1[2];
      66 extern int spawn_job (char *path, char *argv[],
      67                       int *in_fd, int *out_fd, int *err_fd);
      68 extern time_t nfslock(char *path, char *namelock, int max_age, int notify);
      69 extern int nfsunlock(char *path, char *namelock, int max_age, time_t birth);
      70
      71
      72 static void GetFingerPrint(struct ImportKeyObject *iKO);
      73 static void VerifySignAndExplodeFile(EPNodePtr ptr);
      74 static void GetKeyID(struct ImportKeyObject *iKO);
      75
      76
      77 /**************************************
      78  *
      79  * API functions
      80  *
      81  **************************************/
      82
      83
      84 /*++++++++++++++++++++++++++++
      85
      86 Verify a detached PGP signature.
      87
      88 struct VerifySignObject *vSO    The signed object structure to be verified.
      89
      90 ++++++++++++++++++++++++++++*/
      91
      92 void PA_VerifySignature(struct VerifySignObject *vSO) {
         /* [<][>][^][v][top][bottom][index][help] */
      93   char *strArgs[10];
      94   char Args0[100];
      95   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100],
      96     Args6[100], Args7[100];
      97   int gpg_pid;
      98   int gpg_in_fd, out_fd, err_fd;
      99   int status;
     100   /* static int nMsgs = 0; */
     101   char txt[LINE_LENGTH];
     102   char *keyStr;
     103   /* int childRC; */
     104
     105   vSO->type = vSO_Type_Signed;
     106
     107   strcpy(Args0, "--no-secmem-warning");
     108   strcpy(Args1, "--keyring");
     109   strcpy(Args2, vSO->keyRing);
     110   strcpy(Args3, "-o");
     111   if (!strcmp(vSO->iSigFilename, "")) {
     112     strcpy(Args4, vSO->oStream);
     113     strcpy(Args5, "-d");
     114     strcpy(Args6, vSO->iDocSigFilename);
     115     strArgs[6] = Args6;
     116     strArgs[7] = (char *)0;
     117   } else {
     118     strcpy(Args5, "--verify");
     119     strcpy(Args6, vSO->iSigFilename);
     120     strcpy(Args7, vSO->iDocSigFilename);
     121
     122     strArgs[6] = Args6;
     123     strArgs[7] = Args7;
     124     strArgs[8] = (char *)0;
     125     strcpy(vSO->oStream, vSO->iDocSigFilename);
     126   }
     127
     128   strArgs[0] = Args0;
     129   strArgs[1] = Args1;
     130   strArgs[2] = Args2;
     131   strArgs[3] = Args3;
     132   strArgs[4] = Args4;
     133   strArgs[5] = Args5;
     134
     135   gpg_in_fd = INPUT_FD;
     136   out_fd = OUTPUT_FD;
     137   err_fd = ERROR_FD;
     138   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     139                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 )
     140     {
     141       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     142       exit(1);
     143     }
     144
     145   if (waitpid (gpg_pid, &status, 0) < 0)
     146     {
     147       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     148       exit(1);
     149     }
     150   if (WIFEXITED(status) == 0)
     151     {
     152       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     153       exit(1);
     154     } else {
     155       /* Child exited, checking return code */
     156       /* childRC = (status & 0xF00) >> 8;
     157       if (childRC == 1) {
     158         fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
     159         printf ("gpg failure\n");
     160         exit(1);
     161         } */
     162     }
     163
     164
     165   /* Parsing gpg output */
     166   vSO->isValid = vSO_KO;
     167   while (fgets (txt, LINE_LENGTH - 1, stdin) != NULL)
     168     {
     169       /*        printf ( "GPG output : %s\n", txt );   */
     170       if (strstr(txt, "Good signature") != NULL)
     171         vSO->isValid = vSO_IS_VALID;
     172
     173       if (strstr(txt, "CRC error") != NULL)
     174         vSO->isValid = vSO_CRC_ERROR;
     175
     176       if (strstr(txt, "public key not found") != NULL)
     177         vSO->isValid = vSO_NO_PUBLIC_KEY;
     178
     179       if (strstr(txt, "no valid OpenPGP data found") != NULL)
     180         vSO->isValid = vSO_NO_OPENPGP_DATA;
     181
     182       if ((keyStr = strstr(txt, "key ID")) != NULL) {
     183         keyStr += 7;
     184         sscanf(keyStr, "%8X\n", &vSO->keyID);
     185       }
     186     }
     187
     188   if (sd1[0] != 0)  close ( sd1[0] );
     189 }
     190
     191
     192
     193 /*++++++++++++++++++++++++++++
     194
     195 Decrypt a PGP-encrypted file.
     196
     197 struct ReadCryptedObject *rDO   The object to be decrypted
     198
     199
     200 Note:
     201   This functions is not used by PA/EP/MM
     202   It can be useful in the future....  (FP)
     203
     204 ++++++++++++++++++++++++++++*/
     205
     206 void PA_Decrypt(struct ReadCryptedObject *rDO) {
         /* [<][>][^][v][top][bottom][index][help] */
     207
     208   char *strArgs[9];
     209   char clearTextExtension[4] = ".gpg";
     210   char Args0[100];
     211   char Args1[100];
     212   char Args2[100];
     213   char Args3[100];
     214   char Args4[100];
     215   char Args5[100];
     216   char Args6[100];
     217   int gpg_pid;
     218   int gpg_in_fd, out_fd, err_fd;
     219   int status;
     220   char txt[LINE_LENGTH];
     221   int childRC;
     222
     223   strcpy(Args0, "--no-tty");
     224   strcpy(Args1, "--no-secmem-warning");
     225   strcpy(Args2, "--keyring");
     226   strcpy(Args3, rDO->keyRing);
     227   strcpy(Args4, "--output");
     228   strcpy(Args5, strcat(rDO->iFilename, clearTextExtension));
     229   strcpy(Args6, rDO->iFilename);
     230
     231   strArgs[0] = Args0;
     232   strArgs[1] = Args1;
     233   strArgs[2] = Args2;
     234   strArgs[3] = Args3;
     235   strArgs[4] = Args4;
     236   strArgs[5] = Args5;
     237   strArgs[6] = Args6;
     238   strArgs[7] = (char *) 0;
     239
     240   gpg_in_fd = INPUT_FD;
     241   out_fd = OUTPUT_FD;
     242   err_fd = ERROR_FD;
     243   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     244                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 )
     245     {
     246       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     247       exit(1);
     248     }
     249
     250   if (waitpid (gpg_pid, &status, 0) < 0)
     251     {
     252       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     253       exit(1);
     254     }
     255   if (WIFEXITED(status) == 0)
     256     {
     257       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     258       exit(1);
     259     } else {
     260       /* Child exited, checking return code */
     261       childRC = (status & 0xF00) >> 8;
     262       if (childRC == 1) {
     263         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     264         exit(1);
     265       }
     266     }
     267
     268
     269   /* Parsing gpg output */
     270   while (fgets (txt, STRING_LENGTH - 1, stdin) != NULL)
     271     {
     272
     273     }
     274
     275   if (sd1[0] != 0)  close ( sd1[0] );
     276 }
     277
     278
     279
     280 /*++++++++++++++++++++++++++++
     281
     282 Import a PGP key.
     283
     284 struct ImportKeyObject *iKO     The structure where the imported key goes
     285
     286 ++++++++++++++++++++++++++++*/
     287
     288 void PA_ImportKey(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     289
     290   char *strArgs[9];
     291   char Args0[100];
     292   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100];
     293   int gpg_pid;
     294   int gpg_in_fd, out_fd, err_fd;
     295   int status;
     296   char txt[LINE_LENGTH];
     297   char *keyStr, *pos;
     298   const char lockFilename[] = ".PAlock";
     299   char keyRingLockFile[1000], keyRingPath[1000];
     300   time_t lockBirthDate;
     301   FILE *mystdin;
     302   int childRC;
     303
     304   iKO->rc = iKO_GENERALFAILURE;
     305
     306   strcpy(Args0, "--no-tty");
     307   strcpy(Args1, "--no-secmem-warning");
     308   strcpy(Args2, "--keyring");
     309   strcpy(Args3, iKO->keyRing);
     310   strcpy(Args4, "--import");
     311   strcpy(Args5, iKO->iFilename);
     312
     313   strArgs[0] = Args0;
     314   strArgs[1] = Args1;
     315   strArgs[2] = Args2;
     316   strArgs[3] = Args3;
     317   strArgs[4] = Args4;
     318   strArgs[5] = Args5;
     319   strArgs[6] = (char *)0;
     320
     321   gpg_in_fd = INPUT_FD;
     322   out_fd = OUTPUT_FD;
     323   err_fd = ERROR_FD;
     324
     325   /* create lock file filenames for NFS */
     326
     327   strcpy(keyRingLockFile, iKO->keyRing);
     328   if ((pos = strrchr(keyRingLockFile, '/')) != NULL) {
     329     strcpy(pos + 1, lockFilename);
     330     strcpy(keyRingPath, keyRingLockFile);
     331     keyRingPath[pos - keyRingLockFile] = 0;
     332   } else {
     333     strcpy(keyRingLockFile, lockFilename);
     334     strcpy(keyRingPath, "");
     335   }
     336
     337   lockBirthDate = nfslock(keyRingPath, (char*)lockFilename, 0, 0);
     338
     339   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     340                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
     341     ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     342     exit(1);
     343   }
     344
     345   if (waitpid (gpg_pid, &status, 0) < 0)
     346     {
     347       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     348       nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
     349       exit(1);
     350     }
     351
     352   nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
     353
     354   if (WIFEXITED(status) == 0)
     355     {
     356       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     357     } else {
     358       /* Child exited, checking return code */
     359       childRC = (status & 0xF00) >> 8;
     360       if (childRC == 1) {
     361         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     362         exit(1);
     363       }
     364     }
     365
     366
     367   /* Parsing gpg output */
     368   /*   while (read(0, txt, 1000) != 0)
     369        fprintf(stderr, "child read %s\n", txt); */
     370
     371   mystdin = fdopen(0, "r");
     372   iKO->rc = iKO_GENERALFAILURE;
     373   while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
     374     {
     375       /*          printf ( "GPG output : %s\n", txt );      */
     376
     377       if ((keyStr = strstr(txt, "imported")) != NULL) {
     378         iKO->rc = iKO_OK;
     379       }
     380
     381       if ((keyStr = strstr(txt, "CRC error")) != NULL) {
     382         iKO->rc = iKO_CRC_ERROR;
     383       }
     384
     385       if ((keyStr = strstr(txt, "no valid OpenPGP")) != NULL) {
     386         iKO->rc = iKO_NO_OPENPGP_DATA;
     387       }
     388
     389       if (((keyStr = strstr(txt, "unchanged")) != NULL) ||
     390           ((keyStr = strstr(txt, "not changed")) != NULL)) {
     391         iKO->rc = iKO_UNCHANGED;
     392       }
     393
     394       if ((keyStr = strstr(txt, "key")) != NULL) {
     395          keyStr += 4;
     396          sscanf(keyStr, "%8X\n", &iKO->keyID);
     397       }
     398     }
     399
     400   if (sd1[0] != 0)  close ( sd1[0] );
     401
     402   /* Get the finger print */
     403
     404   GetFingerPrint(iKO);
     405 }
     406
     407
     408
     409 /*++++++++++++++++++++++++++++
     410
     411 Remove a PGP key.
     412
     413 struct ImportKeyObject *iKO     The structure containing the key to be removed
     414
     415 ++++++++++++++++++++++++++++*/
     416
     417 void PA_RemoveKey(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     418
     419   char *strArgs[9];
     420   char Args0[100]= "gpg";
     421   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100], Args6[100], Args7[100];
     422   int gpg_pid;
     423   int gpg_in_fd, out_fd, err_fd;
     424   int status;
     425   char txt[LINE_LENGTH];
     426   char *keyStr, *pos;
     427   const char lockFilename[] = ".PAlock";
     428   char keyRingLockFile[1000], keyRingPath[1000];
     429   time_t lockBirthDate;
     430   FILE *mystdin;
     431   int childRC;
     432
     433   iKO->rc = iKO_GENERALFAILURE;
     434
     435   GetKeyID(iKO);   /* getting key-id */
     436
     437   /*   printf("Key id = %08lX\n", iKO->keyID); */
     438
     439   if ((iKO->rc == iKO_OK) || (iKO->rc == iKO_UNCHANGED)) {
     440     strcpy(Args1, "--batch");
     441     strcpy(Args2, "--yes");
     442     strcpy(Args3, "--no-secmem-warning");
     443     strcpy(Args4, "--keyring");
     444     strcpy(Args5, iKO->keyRing);
     445     strcpy(Args6, "--delete-key");
     446     sprintf(Args7, "%08X", iKO->keyID);
     447
     448     strArgs[0] = Args0;
     449     strArgs[1] = Args1;
     450     strArgs[2] = Args2;
     451     strArgs[3] = Args3;
     452     strArgs[4] = Args4;
     453     strArgs[5] = Args5;
     454     strArgs[6] = Args6;
     455     strArgs[7] = Args7;
     456     strArgs[8] = (char *)0;
     457
     458
     459     gpg_in_fd = INPUT_FD;
     460     out_fd = OUTPUT_FD;
     461     err_fd = ERROR_FD;
     462
     463   /* create lock file filenames for NFS */
     464
     465     strcpy(keyRingLockFile, iKO->keyRing);
     466     if ((pos = strrchr(keyRingLockFile, '/')) != NULL) {
     467       strcpy(pos + 1, lockFilename);
     468       strcpy(keyRingPath, keyRingLockFile);
     469       keyRingPath[pos - keyRingLockFile] = 0;
     470     } else {
     471       strcpy(keyRingLockFile, lockFilename);
     472       strcpy(keyRingPath, "");
     473     }
     474
     475     lockBirthDate = nfslock(keyRingPath, (char*)lockFilename, 0, 0);
     476
     477     if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     478                                 &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
     479       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     480       exit(1);
     481     }
     482
     483     /*    printf("Child pid = %d\n", gpg_pid); */
     484
     485     if (waitpid (gpg_pid, &status, 0) < 0)
     486       {
     487         ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     488         exit(1);
     489       }
     490
     491     nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
     492
     493     if (WIFEXITED(status) == 0)
     494       {
     495         ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     496         exit(1);
     497       }  else {
     498         /* Child exited, checking return code */
     499         childRC = (status & 0xF00) >> 8;
     500         if (childRC == 1) {
     501           ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     502           exit(1);
     503         }
     504       }
     505
     506
     507     mystdin = fdopen(0, "r");
     508     iKO->rc = iKO_OK;
     509     while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
     510       {
     511         /* printf ( "GPG output : %s\n", txt );        */
     512
     513         if ((keyStr = strstr(txt, "delete key failed")) != NULL) {
     514           iKO->rc = iKO_GENERALFAILURE;
     515         }
     516         if ((keyStr = strstr(txt, "there is a secret key for this public key")) != NULL) {
     517           iKO->rc = iKO_SECRET_KEY_PRESENT;
     518         }
     519
     520       }
     521
     522     if (sd1[0] != 0)  close ( sd1[0] );
     523   }
     524 }
     525
     526
     527
     528 /*++++++++++++++++++++++++++++
     529
     530 Parse a file and look for PGP-signed elements inside.
     531
     532 EPNodePtr ptr   The pointer to the EP treenode containing the file to be parsed.
     533
     534 ++++++++++++++++++++++++++++*/
     535
     536 EPNodePtr PA_ParseMessage(EPNodePtr ptr) {
         /* [<][>][^][v][top][bottom][index][help] */
     537
     538   /* Assumptions:
     539      - ptr is describing a text file, not MIME
     540      - input file is broken down to pieces, plain text or PGP blocks
     541      - if input file is doesn't have any PGP block, this is a leaf
     542      - otherwise send each block to the proper handler.
     543   */
     544
     545   FILE *fin, *fout;
     546   char txt[MAX_LINE_BUF], *strptr;
     547   /* char blockFilename[LINE_LENGTH]; */
     548   const char PGP_prefix_msg[] =       "-----BEGIN PGP MESSAGE";
     549   const char PGP_suffix_msg[] =       "-----END PGP MESSAGE";
     550   const char PGP_prefix_signed[] =    "-----BEGIN PGP SIGNED MESSAGE";
     551   const char PGP_suffix_signature[] = "-----END PGP SIGNATURE";
     552   int found_prefix = 0, found_suffix = 0;
     553   EPNodePtr p = ptr, prev = ptr;
     554   int end_of_fin = 0, text_block = 1;
     555
     556
     557   ER_dbg_va (FAC_PA, ASP_PA_GEN, "Entering PA_ParseMessage...");
     558
     559
     560   if ((fin = fopen(ptr->file, "r")) != NULL) {
     561
     562     do {
     563       /* this is needed because a text block parser ends when it finds
     564          a PGP prefix, so we already have a txt buffer.   */
     565
     566       if (!text_block || (prev == ptr)) {
     567         strptr = fgets(txt, MAX_LINE_BUF, fin);
     568         if (strptr == NULL ) end_of_fin = 1;
     569       }
     570
     571       if (!end_of_fin && (found_prefix || (strstr(txt, PGP_prefix_msg) != NULL) ||
     572                           (strstr(txt, PGP_prefix_signed) != NULL))) {
     573         /* PGP block */
     574         found_prefix = 1;
     575         text_block = 0;
     576
     577         p = EP_DefineNewNode(++EP_Node_ID, vS_TO_BE_PGPVERIFIED,
     578                              ptr->MIMEContentType, ptr->strMIMEContentType, 0);
     579
     580         if (prev != ptr)
     581           prev->next = p;
     582         else
     583           ptr->inner = p;
     584
     585         if ((fout = fopen(p->file, "w")) != NULL ) {
     586           fputs(txt, fout);
     587           /* To be replaced by fwrite(), more efficient */
     588           while ((found_prefix != found_suffix) &&
     589                  ((strptr = fgets(txt, MAX_LINE_BUF, fin)) != NULL)) {
     590             if (strstr(txt, PGP_prefix_msg) != NULL) found_prefix++;
     591             if (strstr(txt, PGP_prefix_signed) != NULL) found_prefix++;
     592             if (strstr(txt, PGP_suffix_msg) != NULL) found_suffix++;
     593             if (strstr(txt, PGP_suffix_signature) != NULL) found_suffix++;
     594             fputs(txt, fout);
     595           }
     596           if (strptr == NULL ) end_of_fin = 1;
     597
     598           fclose(fout);
     599
     600           if (found_prefix == found_suffix) {
     601             found_prefix = found_suffix = 0;
     602
     603             VerifySignAndExplodeFile(p);
     604
     605             /* Called form EP_ParseMail or EP_PArseText ? */
     606
     607             if (strstr(EP_outputPrefix, "EPMtmp") != NULL)
     608               {
     609                 ER_dbg_va (FAC_PA, ASP_PA_GEN, "Found prefix and suffix; calling EP_MIMEParse...");
     610                 EP_MIMEParse(p);
     611               }
     612             else
     613               PA_ParseMessage(p);
     614
     615             prev = p;
     616           } else {
     617             /* Wrong PGP delimiters order. */
     618             p->isValidPGPSignature = vS_UNMATCHED_PGP_DELIMITERS;
     619           }
     620         } else {
     621           p->isValidPGPSignature = vS_UNABLE_TO_WRITE_FILE;
     622           return p;
     623         }
     624
     625       } else {
     626         /* Clear text block */
     627
     628         text_block = 1;
     629
     630         if (strptr == NULL) end_of_fin = 1;
     631         else {
     632           p = EP_DefineNewNode(++EP_Node_ID, vS_IS_NOT_PGP,
     633                                ptr->MIMEContentType,
     634                                ptr->strMIMEContentType, 0);
     635
     636           if (prev != ptr)
     637             prev->next = p;
     638           else
     639             ptr->inner = p;
     640
     641           if ((fout = fopen(p->file, "w")) != NULL ) {
     642             fputs(txt, fout);
     643             /* To be replaced by fwrite(), more efficient */
     644             while ((!found_prefix &&
     645                     (strptr = fgets(txt, MAX_LINE_BUF, fin)) != NULL)) {
     646               if ((strstr(txt, PGP_prefix_msg) != NULL) ||
     647                   (strstr(txt, PGP_prefix_signed) != NULL)) found_prefix++;
     648               else
     649                 fputs(txt, fout);
     650             }
     651             if (strptr == NULL ) end_of_fin = 1;
     652
     653             fclose(fout);
     654
     655             /* Check if the blockfile is finished and this is the first
     656                segment. If so this is a text leaf */
     657             if (found_prefix || (prev != p)) {
     658               if (prev->MIMEContentType == -1)
     659                 {
     660                   if (strstr(EP_outputPrefix, "EPMtmp") != NULL)
     661                     {
     662                       ER_dbg_va (FAC_PA, ASP_PA_GEN, "PA_ParseMessage: sending to EP_MIMEParse");
     663                       EP_MIMEParse(p);
     664                     }
     665                   else
     666                     PA_ParseMessage(p);
     667                 }
     668
     669               prev = p;
     670             }
     671
     672           } else {
     673             p->isValidPGPSignature = vS_UNABLE_TO_WRITE_FILE;
     674             return p;
     675           }
     676         }
     677       }
     678     } while (!end_of_fin);
     679   } else {
     680     p->isValidPGPSignature = vS_NO_IN_FILES;
     681   }
     682
     683   return ptr;
     684 }
     685
     686
     687 /**************************************
     688  *
     689  * Internal functions
     690  *
     691  **************************************/
     692
     693
     694
     695 /*++++++++++++++++++++++++++++
     696
     697 Get the fingerprint of a PGP key.
     698
     699 ImportKeyObject *iKO    The imported key object
     700
     701 ++++++++++++++++++++++++++++*/
     702
     703 void GetFingerPrint(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     704
     705   char *strArgs[9];
     706   char Args0[100] ;
     707   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100];
     708   int gpg_pid;
     709   int gpg_in_fd, out_fd, err_fd;
     710   int status;
     711   char txt[LINE_LENGTH];
     712   char *keyStr;
     713   FILE *mystdin;
     714   int childRC;
     715
     716   strcpy(Args0, "--no-tty");
     717   strcpy(Args1, "--no-secmem-warning");
     718   strcpy(Args2, "--keyring");
     719   strcpy(Args3, iKO->keyRing);
     720   strcpy(Args4, "--fingerprint");
     721   sprintf(Args5, "%08X", iKO->keyID);
     722
     723   strArgs[0] = Args0;
     724   strArgs[1] = Args1;
     725   strArgs[2] = Args2;
     726   strArgs[3] = Args3;
     727   strArgs[4] = Args4;
     728   strArgs[5] = Args5;
     729   strArgs[6] = (char *)0;
     730
     731   gpg_in_fd = INPUT_FD;
     732   out_fd = OUTPUT_FD;
     733   err_fd = ERROR_FD;
     734
     735   /* create lock file filenames for NFS */
     736
     737   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     738                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
     739     ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     740     exit(1);
     741   }
     742
     743   if (waitpid (gpg_pid, &status, 0) < 0)
     744     {
     745       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     746       exit(1);
     747     }
     748
     749   if (WIFEXITED(status) == 0)
     750     {
     751       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     752       exit(1);
     753     } else {
     754       /* Child exited, checking return code */
     755       childRC = (status & 0xF00) >> 8;
     756       if (childRC == 1) {
     757         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     758         exit(1);
     759       }
     760     }
     761
     762
     763   mystdin = fdopen(0, "r");
     764   while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
     765     {
     766       /* printf ( "GPG output : %s\n", txt );      */
     767
     768       if ((keyStr = strstr(txt, "Key fingerprint =")) != NULL) {
     769         strcpy(iKO->fingerPrint, keyStr + 18);
     770         iKO->fingerPrint[strlen(iKO->fingerPrint)-1] = 0;
     771       }
     772
     773       if ((keyStr = strstr(txt, "key")) != NULL) {
     774          keyStr += 4;
     775          sscanf(keyStr, "%8X\n", &iKO->keyID);
     776       }
     777     }
     778
     779   if (sd1[0] != 0)  close ( sd1[0] );
     780 }
     781
     782
     783
     784 /*++++++++++++++++++++++++++++
     785
     786 Verify the PGP signature and extract the signed part in a file.
     787
     788 EPNodePtr ptr   The pointer to the EP treenode containing the originating file
     789
     790 ++++++++++++++++++++++++++++*/
     791
     792 void VerifySignAndExplodeFile(EPNodePtr ptr) {
         /* [<][>][^][v][top][bottom][index][help] */
     793   char *strArgs[10];
     794   char Args0[100];
     795   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100],
     796     Args6[100];
     797   int gpg_pid;
     798   int gpg_in_fd, out_fd, err_fd;
     799   int status;
     800   char txt[LINE_LENGTH];
     801   /* char hostname[MAXHOSTNAMELEN]; */
     802   char oFile[FILENAME_LENGTH];
     803   char *keyStr;
     804   /* int childRC; */
     805
     806   sprintf(oFile, "%s.%d.exp", ptr->file, ptr->nodeID);
     807
     808   strcpy(Args0, "--no-secmem-warning");
     809   strcpy(Args1, "--keyring");
     810   strcpy(Args2, EP_keyRing);
     811   strcpy(Args3, "-o");
     812   strcpy(Args4, oFile);
     813   strcpy(Args5, "-d");
     814   strcpy(Args6, ptr->file);
     815   strArgs[6] = Args6;
     816   strArgs[7] = (char *)0;
     817
     818   strArgs[0] = Args0;
     819   strArgs[1] = Args1;
     820   strArgs[2] = Args2;
     821   strArgs[3] = Args3;
     822   strArgs[4] = Args4;
     823   strArgs[5] = Args5;
     824
     825   gpg_in_fd = INPUT_FD;
     826   out_fd = OUTPUT_FD;
     827   err_fd = ERROR_FD;
     828   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     829                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 )
     830     {
     831       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     832       exit(1);
     833     }
     834
     835   if (waitpid (gpg_pid, &status, 0) < 0)
     836     {
     837       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     838       exit(1);
     839     }
     840   if (WIFEXITED(status) == 0)
     841     {
     842       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     843       exit(1);
     844     } else {
     845       /* Child exited, checking return code */
     846       /* childRC = (status & 0xF00) >> 8;
     847       if (childRC == 1) {
     848         fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
     849         printf ("gpg failure\n");
     850         exit(1);
     851         } */
     852     }
     853
     854
     855   /* Parsing gpg output */
     856   ptr->isValidPGPSignature = vS_KO;
     857   while (fgets (txt, LINE_LENGTH - 1, stdin) != NULL)
     858     {
     859       /*        printf ( "GPG output : %s\n", txt );   */
     860       if (strstr(txt, "Good signature") != NULL)
     861         ptr->isValidPGPSignature = vS_IS_VALID;
     862
     863       if (strstr(txt, "CRC error") != NULL)
     864         ptr->isValidPGPSignature = vS_CRC_ERROR;
     865
     866       if (strstr(txt, "public key not found") != NULL)
     867         ptr->isValidPGPSignature = vS_NO_PUBLIC_KEY;
     868
     869       if (strstr(txt, "no valid OpenPGP data found") != NULL)
     870         ptr->isValidPGPSignature = vS_NO_OPENPGP_DATA;
     871
     872       if ((keyStr = strstr(txt, "key ID")) != NULL) {
     873         keyStr += 7;
     874         sscanf(keyStr, "%8X\n", &ptr->keyID);
     875       }
     876     }
     877
     878   unlink(ptr->file);
     879   free(ptr->file);
     880   ptr->file = strdup(oFile);
     881   if (sd1[0] != 0)  close ( sd1[0] );
     882 }
     883
     884
     885 /*++++++++++++++++++++++++++++
     886
     887 Get the KeyID of a PGP key.
     888
     889 struct ImportKeyObject *iKO     The structure containing the key of which we want the KeyID
     890
     891 ++++++++++++++++++++++++++++*/
     892
     893 void GetKeyID(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     894
     895   char *strArgs[9];
     896   char Args0[100];
     897   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100];
     898   int gpg_pid;
     899   int gpg_in_fd, out_fd, err_fd;
     900   int status;
     901   char txt[LINE_LENGTH];
     902   char *keyStr, *pos;
     903   const char lockFilename[] = ".PAlock";
     904   char keyRingLockFile[1000], keyRingPath[1000];
     905   time_t lockBirthDate;
     906   FILE *mystdin;
     907   int childRC;
     908
     909   iKO->rc = iKO_GENERALFAILURE;
     910
     911   strcpy(Args0, "--no-tty");
     912   strcpy(Args1, "--no-secmem-warning");
     913   strcpy(Args2, "--keyring");
     914   strcpy(Args3, iKO->keyRing);
     915   strcpy(Args4, "--import");
     916   strcpy(Args5, iKO->iFilename);
     917
     918   strArgs[0] = Args0;
     919   strArgs[1] = Args1;
     920   strArgs[2] = Args2;
     921   strArgs[3] = Args3;
     922   strArgs[4] = Args4;
     923   strArgs[5] = Args5;
     924   strArgs[6] = (char *)0;
     925
     926   gpg_in_fd = INPUT_FD;
     927   out_fd = OUTPUT_FD;
     928   err_fd = ERROR_FD;
     929
     930   /* create lock file filenames for NFS */
     931
     932   strcpy(keyRingLockFile, iKO->keyRing);
     933   if ((pos = strrchr(keyRingLockFile, '/')) != NULL) {
     934     strcpy(pos + 1, lockFilename);
     935     strcpy(keyRingPath, keyRingLockFile);
     936     keyRingPath[pos - keyRingLockFile] = 0;
     937   } else {
     938     strcpy(keyRingLockFile, lockFilename);
     939     strcpy(keyRingPath, "");
     940   }
     941
     942   lockBirthDate = nfslock(keyRingPath, (char*)lockFilename, 0, 0);
     943
     944   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     945                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
     946     ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     947     exit(1);
     948   }
     949
     950   if (waitpid (gpg_pid, &status, 0) < 0)
     951     {
     952       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     953       nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
     954       exit(1);
     955     }
     956
     957   nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
     958
     959   if (WIFEXITED(status) == 0)
     960     {
     961       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     962       exit(1);
     963     } else {
     964       /* Child exited, checking return code */
     965       childRC = (status & 0xF00) >> 8;
     966       if (childRC == 1) {
     967         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     968         exit(1);
     969       }
     970     }
     971
     972
     973   /* Parsing gpg output */
     974   /*   while (read(0, txt, 1000) != 0)
     975        fprintf(stderr, "child read %s\n", txt); */
     976
     977   mystdin = fdopen(0, "r");
     978   iKO->rc = iKO_GENERALFAILURE;
     979   while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
     980     {
     981       /*          printf ( "GPG output : %s\n", txt );      */
     982
     983       if ((keyStr = strstr(txt, "imported")) != NULL) {
     984         iKO->rc = iKO_OK;
     985       }
     986
     987       if ((keyStr = strstr(txt, "CRC error")) != NULL) {
     988         iKO->rc = iKO_CRC_ERROR;
     989       }
     990
     991       if ((keyStr = strstr(txt, "no valid OpenPGP")) != NULL) {
     992         iKO->rc = iKO_NO_OPENPGP_DATA;
     993       }
     994
     995       if (((keyStr = strstr(txt, "unchanged")) != NULL) ||
     996           ((keyStr = strstr(txt, "not changed")) != NULL)) {
     997         iKO->rc = iKO_UNCHANGED;
     998       }
     999
    1000       if ((keyStr = strstr(txt, "gpg: key ")) != NULL) {
    1001          keyStr += 9;
    1002          sscanf(keyStr, "%8X\n", &iKO->keyID);
    1003       }
    1004     }
    1005
    1006   if (sd1[0] != 0)  close ( sd1[0] );
    1007
    1008 }
    1009

/* [<][>][^][v][top][bottom][index][help] */