## 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. GetKeyOwner
8. VerifySignAndExplodeFile
9. GetKeyID

       1 /***************************************
       2   $Revision: 1.30 $
       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 VerifySignAndExplodeFile(EPNodePtr ptr);
      73 static void GetKeyID(struct ImportKeyObject *iKO);
      74
      75
      76 /**************************************
      77  *
      78  * API functions
      79  *
      80  **************************************/
      81
      82
      83 /*++++++++++++++++++++++++++++
      84
      85 Verify a detached PGP signature.
      86
      87 struct VerifySignObject *vSO    The signed object structure to be verified.
      88
      89 ++++++++++++++++++++++++++++*/
      90
      91 void PA_VerifySignature(struct VerifySignObject *vSO) {
         /* [<][>][^][v][top][bottom][index][help] */
      92   char *strArgs[10];
      93   char Args0[100];
      94   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100],
      95     Args6[100], Args7[100];
      96   int gpg_pid;
      97   int gpg_in_fd, out_fd, err_fd;
      98   int status;
      99   /* static int nMsgs = 0; */
     100   char txt[LINE_LENGTH];
     101   char *keyStr;
     102   /* int childRC; */
     103
     104   vSO->type = vSO_Type_Signed;
     105
     106   strcpy(Args0, "--no-secmem-warning");
     107   strcpy(Args1, "--keyring");
     108   strcpy(Args2, vSO->keyRing);
     109   strcpy(Args3, "-o");
     110   if (!strcmp(vSO->iSigFilename, "")) {
     111     strcpy(Args4, vSO->oStream);
     112     strcpy(Args5, "-d");
     113     strcpy(Args6, vSO->iDocSigFilename);
     114     strArgs[6] = Args6;
     115     strArgs[7] = (char *)0;
     116   } else {
     117     strcpy(Args5, "--verify");
     118     strcpy(Args6, vSO->iSigFilename);
     119     strcpy(Args7, vSO->iDocSigFilename);
     120
     121     strArgs[6] = Args6;
     122     strArgs[7] = Args7;
     123     strArgs[8] = (char *)0;
     124     strcpy(vSO->oStream, vSO->iDocSigFilename);
     125   }
     126
     127   strArgs[0] = Args0;
     128   strArgs[1] = Args1;
     129   strArgs[2] = Args2;
     130   strArgs[3] = Args3;
     131   strArgs[4] = Args4;
     132   strArgs[5] = Args5;
     133
     134   gpg_in_fd = INPUT_FD;
     135   out_fd = OUTPUT_FD;
     136   err_fd = ERROR_FD;
     137   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     138                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 )
     139     {
     140       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     141       exit(1);
     142     }
     143
     144   if (waitpid (gpg_pid, &status, 0) < 0)
     145     {
     146       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     147       exit(1);
     148     }
     149   if (WIFEXITED(status) == 0)
     150     {
     151       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     152       exit(1);
     153     } else {
     154       /* Child exited, checking return code */
     155       /* childRC = (status & 0xF00) >> 8;
     156       if (childRC == 1) {
     157         fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
     158         printf ("gpg failure\n");
     159         exit(1);
     160         } */
     161     }
     162
     163
     164   /* Parsing gpg output */
     165   vSO->isValid = vSO_KO;
     166   while (fgets (txt, LINE_LENGTH - 1, stdin) != NULL)
     167     {
     168       /*        printf ( "GPG output : %s\n", txt );   */
     169       if (strstr(txt, "Good signature") != NULL)
     170         vSO->isValid = vSO_IS_VALID;
     171
     172       if (strstr(txt, "CRC error") != NULL)
     173         vSO->isValid = vSO_CRC_ERROR;
     174
     175       if (strstr(txt, "public key not found") != NULL)
     176         vSO->isValid = vSO_NO_PUBLIC_KEY;
     177
     178       if (strstr(txt, "no valid OpenPGP data found") != NULL)
     179         vSO->isValid = vSO_NO_OPENPGP_DATA;
     180
     181       if ((keyStr = strstr(txt, "key ID")) != NULL) {
     182         keyStr += 7;
     183         sscanf(keyStr, "%8X\n", &vSO->keyID);
     184       }
     185     }
     186
     187   if (sd1[0] != 0)  close ( sd1[0] );
     188 }
     189
     190
     191
     192 /*++++++++++++++++++++++++++++
     193
     194 Decrypt a PGP-encrypted file.
     195
     196 struct ReadCryptedObject *rDO   The object to be decrypted
     197
     198
     199 Note:
     200   This functions is not used by PA/EP/MM
     201   It can be useful in the future....  (FP)
     202
     203 ++++++++++++++++++++++++++++*/
     204
     205 void PA_Decrypt(struct ReadCryptedObject *rDO) {
         /* [<][>][^][v][top][bottom][index][help] */
     206
     207   char *strArgs[9];
     208   char clearTextExtension[4] = ".gpg";
     209   char Args0[100];
     210   char Args1[100];
     211   char Args2[100];
     212   char Args3[100];
     213   char Args4[100];
     214   char Args5[100];
     215   char Args6[100];
     216   int gpg_pid;
     217   int gpg_in_fd, out_fd, err_fd;
     218   int status;
     219   char txt[LINE_LENGTH];
     220   int childRC;
     221
     222   strcpy(Args0, "--no-tty");
     223   strcpy(Args1, "--no-secmem-warning");
     224   strcpy(Args2, "--keyring");
     225   strcpy(Args3, rDO->keyRing);
     226   strcpy(Args4, "--output");
     227   strcpy(Args5, strcat(rDO->iFilename, clearTextExtension));
     228   strcpy(Args6, rDO->iFilename);
     229
     230   strArgs[0] = Args0;
     231   strArgs[1] = Args1;
     232   strArgs[2] = Args2;
     233   strArgs[3] = Args3;
     234   strArgs[4] = Args4;
     235   strArgs[5] = Args5;
     236   strArgs[6] = Args6;
     237   strArgs[7] = (char *) 0;
     238
     239   gpg_in_fd = INPUT_FD;
     240   out_fd = OUTPUT_FD;
     241   err_fd = ERROR_FD;
     242   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     243                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 )
     244     {
     245       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     246       exit(1);
     247     }
     248
     249   if (waitpid (gpg_pid, &status, 0) < 0)
     250     {
     251       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     252       exit(1);
     253     }
     254   if (WIFEXITED(status) == 0)
     255     {
     256       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     257       exit(1);
     258     } else {
     259       /* Child exited, checking return code */
     260       childRC = (status & 0xF00) >> 8;
     261       if (childRC == 1) {
     262         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     263         exit(1);
     264       }
     265     }
     266
     267
     268   /* Parsing gpg output */
     269   while (fgets (txt, STRING_LENGTH - 1, stdin) != NULL)
     270     {
     271
     272     }
     273
     274   if (sd1[0] != 0)  close ( sd1[0] );
     275 }
     276
     277
     278
     279 /*++++++++++++++++++++++++++++
     280
     281 Import a PGP key.
     282
     283 struct ImportKeyObject *iKO     The structure where the imported key goes
     284
     285 ++++++++++++++++++++++++++++*/
     286
     287 void PA_ImportKey(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     288
     289   char *strArgs[9];
     290   char Args0[100];
     291   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100];
     292   int gpg_pid;
     293   int gpg_in_fd, out_fd, err_fd;
     294   int status;
     295   char txt[LINE_LENGTH];
     296   char *keyStr, *pos;
     297   const char lockFilename[] = ".PAlock";
     298   char keyRingLockFile[1000], keyRingPath[1000];
     299   time_t lockBirthDate;
     300   FILE *mystdin;
     301   int childRC;
     302
     303   iKO->rc = iKO_GENERALFAILURE;
     304
     305   strcpy(Args0, "--no-tty");
     306   strcpy(Args1, "--no-secmem-warning");
     307   strcpy(Args2, "--keyring");
     308   strcpy(Args3, iKO->keyRing);
     309   strcpy(Args4, "--import");
     310   strcpy(Args5, iKO->iFilename);
     311
     312   strArgs[0] = Args0;
     313   strArgs[1] = Args1;
     314   strArgs[2] = Args2;
     315   strArgs[3] = Args3;
     316   strArgs[4] = Args4;
     317   strArgs[5] = Args5;
     318   strArgs[6] = (char *)0;
     319
     320   gpg_in_fd = INPUT_FD;
     321   out_fd = OUTPUT_FD;
     322   err_fd = ERROR_FD;
     323
     324   /* create lock file filenames for NFS */
     325
     326   strcpy(keyRingLockFile, iKO->keyRing);
     327   if ((pos = strrchr(keyRingLockFile, '/')) != NULL) {
     328     strcpy(pos + 1, lockFilename);
     329     strcpy(keyRingPath, keyRingLockFile);
     330     keyRingPath[pos - keyRingLockFile] = 0;
     331   } else {
     332     strcpy(keyRingLockFile, lockFilename);
     333     strcpy(keyRingPath, "");
     334   }
     335
     336   lockBirthDate = nfslock(keyRingPath, (char*)lockFilename, 0, 0);
     337
     338   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     339                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
     340     ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     341     exit(1);
     342   }
     343
     344   if (waitpid (gpg_pid, &status, 0) < 0)
     345     {
     346       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     347       nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
     348       exit(1);
     349     }
     350
     351   nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
     352
     353   if (WIFEXITED(status) == 0)
     354     {
     355       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     356     } else {
     357       /* Child exited, checking return code */
     358       childRC = (status & 0xF00) >> 8;
     359       if (childRC == 1) {
     360         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     361         exit(1);
     362       }
     363     }
     364
     365
     366   /* Parsing gpg output */
     367   /*   while (read(0, txt, 1000) != 0)
     368        fprintf(stderr, "child read %s\n", txt); */
     369
     370   mystdin = fdopen(0, "r");
     371   iKO->rc = iKO_GENERALFAILURE;
     372   while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
     373     {
     374       /*          printf ( "GPG output : %s\n", txt );      */
     375
     376       if ((keyStr = strstr(txt, "imported")) != NULL) {
     377         iKO->rc = iKO_OK;
     378       }
     379
     380       if ((keyStr = strstr(txt, "CRC error")) != NULL) {
     381         iKO->rc = iKO_CRC_ERROR;
     382       }
     383
     384       if ((keyStr = strstr(txt, "no valid OpenPGP")) != NULL) {
     385         iKO->rc = iKO_NO_OPENPGP_DATA;
     386       }
     387
     388       if (((keyStr = strstr(txt, "unchanged")) != NULL) ||
     389           ((keyStr = strstr(txt, "not changed")) != NULL)) {
     390         iKO->rc = iKO_UNCHANGED;
     391       }
     392
     393       if ((keyStr = strstr(txt, "key")) != NULL) {
     394          keyStr += 4;
     395          sscanf(keyStr, "%8X\n", &iKO->keyID);
     396       }
     397     }
     398
     399   if (sd1[0] != 0)  close ( sd1[0] );
     400
     401   /* Get the finger print */
     402
     403   GetFingerPrint(iKO);
     404   GetKeyOwner(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 Get the owner of a PGP key.
     787
     788 ImportKeyObject *iKO    The imported key object
     789
     790 ++++++++++++++++++++++++++++*/
     791
     792 void GetKeyOwner(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     793
     794   char *strArgs[9];
     795   char Args0[100] ;
     796   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100];
     797   int gpg_pid;
     798   int gpg_in_fd, out_fd, err_fd;
     799   int status;
     800   char txt[LINE_LENGTH];
     801   char *keyStr;
     802   FILE *mystdin;
     803   int childRC;
     804
     805   strcpy(Args0, "--no-tty");
     806   strcpy(Args1, "--no-secmem-warning");
     807   strcpy(Args2, "--keyring");
     808   strcpy(Args3, iKO->keyRing);
     809   strcpy(Args4, "--fingerprint");
     810   sprintf(Args5, "%08X", iKO->keyID);
     811
     812   strArgs[0] = Args0;
     813   strArgs[1] = Args1;
     814   strArgs[2] = Args2;
     815   strArgs[3] = Args3;
     816   strArgs[4] = Args4;
     817   strArgs[5] = Args5;
     818   strArgs[6] = (char *)0;
     819
     820   gpg_in_fd = INPUT_FD;
     821   out_fd = OUTPUT_FD;
     822   err_fd = ERROR_FD;
     823
     824   /* create lock file filenames for NFS */
     825
     826   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     827                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
     828     ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     829     exit(1);
     830   }
     831
     832   if (waitpid (gpg_pid, &status, 0) < 0)
     833     {
     834       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     835       exit(1);
     836     }
     837
     838   if (WIFEXITED(status) == 0)
     839     {
     840       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     841       exit(1);
     842     } else {
     843       /* Child exited, checking return code */
     844       childRC = (status & 0xF00) >> 8;
     845       if (childRC == 1) {
     846         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     847         exit(1);
     848       }
     849     }
     850
     851
     852   mystdin = fdopen(0, "r");
     853   while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
     854     {
     855       /* printf ( "GPG output : %s\n", txt );      */
     856
     857       if ((keyStr = strstr(txt, "pub "/*"Key fingerprint ="*/)) == txt /*!= NULL*/) {
     858         strcpy(iKO->keyOwner, keyStr + 30);
     859         iKO->keyOwner[strlen(iKO->keyOwner)-1] = 0;
     860       }
     861
     862       if ((keyStr = strstr(txt, "key")) != NULL) {
     863          keyStr += 4;
     864          sscanf(keyStr, "%8X\n", &iKO->keyID);
     865       }
     866     }
     867
     868   if (sd1[0] != 0)  close ( sd1[0] );
     869 }
     870
     871
     872
     873
     874 /*++++++++++++++++++++++++++++
     875
     876 Verify the PGP signature and extract the signed part in a file.
     877
     878 EPNodePtr ptr   The pointer to the EP treenode containing the originating file
     879
     880 ++++++++++++++++++++++++++++*/
     881
     882 void VerifySignAndExplodeFile(EPNodePtr ptr) {
         /* [<][>][^][v][top][bottom][index][help] */
     883   char *strArgs[10];
     884   char Args0[100];
     885   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100],
     886     Args6[100];
     887   int gpg_pid;
     888   int gpg_in_fd, out_fd, err_fd;
     889   int status;
     890   char txt[LINE_LENGTH];
     891   /* char hostname[MAXHOSTNAMELEN]; */
     892   char oFile[FILENAME_LENGTH];
     893   char *keyStr;
     894   /* int childRC; */
     895
     896   sprintf(oFile, "%s.%d.exp", ptr->file, ptr->nodeID);
     897
     898   strcpy(Args0, "--no-secmem-warning");
     899   strcpy(Args1, "--keyring");
     900   strcpy(Args2, EP_keyRing);
     901   strcpy(Args3, "-o");
     902   strcpy(Args4, oFile);
     903   strcpy(Args5, "-d");
     904   strcpy(Args6, ptr->file);
     905   strArgs[6] = Args6;
     906   strArgs[7] = (char *)0;
     907
     908   strArgs[0] = Args0;
     909   strArgs[1] = Args1;
     910   strArgs[2] = Args2;
     911   strArgs[3] = Args3;
     912   strArgs[4] = Args4;
     913   strArgs[5] = Args5;
     914
     915   gpg_in_fd = INPUT_FD;
     916   out_fd = OUTPUT_FD;
     917   err_fd = ERROR_FD;
     918   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     919                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 )
     920     {
     921       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     922       exit(1);
     923     }
     924
     925   if (waitpid (gpg_pid, &status, 0) < 0)
     926     {
     927       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     928       exit(1);
     929     }
     930   if (WIFEXITED(status) == 0)
     931     {
     932       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     933       exit(1);
     934     } else {
     935       /* Child exited, checking return code */
     936       /* childRC = (status & 0xF00) >> 8;
     937       if (childRC == 1) {
     938         fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
     939         printf ("gpg failure\n");
     940         exit(1);
     941         } */
     942     }
     943
     944
     945   /* Parsing gpg output */
     946   ptr->isValidPGPSignature = vS_KO;
     947   while (fgets (txt, LINE_LENGTH - 1, stdin) != NULL)
     948     {
     949       /*        printf ( "GPG output : %s\n", txt );   */
     950       if (strstr(txt, "Good signature") != NULL)
     951         ptr->isValidPGPSignature = vS_IS_VALID;
     952
     953       if (strstr(txt, "CRC error") != NULL)
     954         ptr->isValidPGPSignature = vS_CRC_ERROR;
     955
     956       if (strstr(txt, "public key not found") != NULL)
     957         ptr->isValidPGPSignature = vS_NO_PUBLIC_KEY;
     958
     959       if (strstr(txt, "no valid OpenPGP data found") != NULL)
     960         ptr->isValidPGPSignature = vS_NO_OPENPGP_DATA;
     961
     962       if ((keyStr = strstr(txt, "key ID")) != NULL) {
     963         keyStr += 7;
     964         sscanf(keyStr, "%8X\n", &ptr->keyID);
     965       }
     966     }
     967
     968   unlink(ptr->file);
     969   free(ptr->file);
     970   ptr->file = strdup(oFile);
     971   if (sd1[0] != 0)  close ( sd1[0] );
     972 }
     973
     974
     975 /*++++++++++++++++++++++++++++
     976
     977 Get the KeyID of a PGP key.
     978
     979 struct ImportKeyObject *iKO     The structure containing the key of which we want the KeyID
     980
     981 ++++++++++++++++++++++++++++*/
     982
     983 void GetKeyID(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     984
     985   char *strArgs[9];
     986   char Args0[100];
     987   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100];
     988   int gpg_pid;
     989   int gpg_in_fd, out_fd, err_fd;
     990   int status;
     991   char txt[LINE_LENGTH];
     992   char *keyStr, *pos;
     993   const char lockFilename[] = ".PAlock";
     994   char keyRingLockFile[1000], keyRingPath[1000];
     995   time_t lockBirthDate;
     996   FILE *mystdin;
     997   int childRC;
     998
     999   iKO->rc = iKO_GENERALFAILURE;
    1000
    1001   strcpy(Args0, "--no-tty");
    1002   strcpy(Args1, "--no-secmem-warning");
    1003   strcpy(Args2, "--keyring");
    1004   strcpy(Args3, iKO->keyRing);
    1005   strcpy(Args4, "--import");
    1006   strcpy(Args5, iKO->iFilename);
    1007
    1008   strArgs[0] = Args0;
    1009   strArgs[1] = Args1;
    1010   strArgs[2] = Args2;
    1011   strArgs[3] = Args3;
    1012   strArgs[4] = Args4;
    1013   strArgs[5] = Args5;
    1014   strArgs[6] = (char *)0;
    1015
    1016   gpg_in_fd = INPUT_FD;
    1017   out_fd = OUTPUT_FD;
    1018   err_fd = ERROR_FD;
    1019
    1020   /* create lock file filenames for NFS */
    1021
    1022   strcpy(keyRingLockFile, iKO->keyRing);
    1023   if ((pos = strrchr(keyRingLockFile, '/')) != NULL) {
    1024     strcpy(pos + 1, lockFilename);
    1025     strcpy(keyRingPath, keyRingLockFile);
    1026     keyRingPath[pos - keyRingLockFile] = 0;
    1027   } else {
    1028     strcpy(keyRingLockFile, lockFilename);
    1029     strcpy(keyRingPath, "");
    1030   }
    1031
    1032   lockBirthDate = nfslock(keyRingPath, (char*)lockFilename, 0, 0);
    1033
    1034   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
    1035                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
    1036     ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
    1037     exit(1);
    1038   }
    1039
    1040   if (waitpid (gpg_pid, &status, 0) < 0)
    1041     {
    1042       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
    1043       nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
    1044       exit(1);
    1045     }
    1046
    1047   nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
    1048
    1049   if (WIFEXITED(status) == 0)
    1050     {
    1051       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
    1052       exit(1);
    1053     } else {
    1054       /* Child exited, checking return code */
    1055       childRC = (status & 0xF00) >> 8;
    1056       if (childRC == 1) {
    1057         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
    1058         exit(1);
    1059       }
    1060     }
    1061
    1062
    1063   /* Parsing gpg output */
    1064   /*   while (read(0, txt, 1000) != 0)
    1065        fprintf(stderr, "child read %s\n", txt); */
    1066
    1067   mystdin = fdopen(0, "r");
    1068   iKO->rc = iKO_GENERALFAILURE;
    1069   while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
    1070     {
    1071       /*          printf ( "GPG output : %s\n", txt );      */
    1072
    1073       if ((keyStr = strstr(txt, "imported")) != NULL) {
    1074         iKO->rc = iKO_OK;
    1075       }
    1076
    1077       if ((keyStr = strstr(txt, "CRC error")) != NULL) {
    1078         iKO->rc = iKO_CRC_ERROR;
    1079       }
    1080
    1081       if ((keyStr = strstr(txt, "no valid OpenPGP")) != NULL) {
    1082         iKO->rc = iKO_NO_OPENPGP_DATA;
    1083       }
    1084
    1085       if (((keyStr = strstr(txt, "unchanged")) != NULL) ||
    1086           ((keyStr = strstr(txt, "not changed")) != NULL)) {
    1087         iKO->rc = iKO_UNCHANGED;
    1088       }
    1089
    1090       if ((keyStr = strstr(txt, "gpg: key ")) != NULL) {
    1091          keyStr += 9;
    1092          sscanf(keyStr, "%8X\n", &iKO->keyID);
    1093       }
    1094     }
    1095
    1096   if (sd1[0] != 0)  close ( sd1[0] );
    1097
    1098 }
    1099

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