## 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_RemoveKey_withKeyID
6. PA_ParseMessage
7. GetFingerPrint
8. GetKeyOwner
9. VerifySignAndExplodeFile
10. GetKeyID

       1 /***************************************
       2   $Revision: 1.38 $
       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,2001,2002                    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 #include "rip.h"
      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 extern char EP_outputPrefix[FILENAME_LENGTH];
      51 extern char EP_keyRing[FILENAME_LENGTH];
      52 extern char EP_gpgcmd[FILENAME_LENGTH];
      53 extern int  EP_TreeHeight;
      54 extern int  EP_Node_ID;
      55 extern int  EP_Debug;
      56 extern char *tmpdir;
      57
      58 /* static int parseMailBlock_nMsg;
      59    static int parseRecursionLevel; */
      60
      61 extern int sd1[2];
      62 extern int spawn_job (char *path, char *argv[],
      63                       int *in_fd, int *out_fd, int *err_fd);
      64 extern time_t nfslock(char *path, char *namelock, int max_age, int notify);
      65 extern int nfsunlock(char *path, char *namelock, int max_age, time_t birth);
      66
      67
      68 static void VerifySignAndExplodeFile(EPNodePtr ptr);
      69 static void GetKeyID(struct ImportKeyObject *iKO);
      70
      71
      72 /**************************************
      73  *
      74  * API functions
      75  *
      76  **************************************/
      77
      78
      79 /*++++++++++++++++++++++++++++
      80
      81 Verify a detached PGP signature.
      82
      83 struct VerifySignObject *vSO    The signed object structure to be verified.
      84
      85 ++++++++++++++++++++++++++++*/
      86
      87 void PA_VerifySignature(struct VerifySignObject *vSO) {
         /* [<][>][^][v][top][bottom][index][help] */
      88   char *strArgs[10];
      89   char Args0[100];
      90   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100],
      91     Args6[100], Args7[100];
      92   int gpg_pid;
      93   int gpg_in_fd, out_fd, err_fd;
      94   int status;
      95   /* static int nMsgs = 0; */
      96   char txt[LINE_LENGTH];
      97   char *keyStr;
      98   /* int childRC; */
      99
     100   int fIn,fOut;
     101   char tmpFileName[100],lfcrStr[10],strIn[10];
     102   char prevChar;
     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     /* change <cr> to <lf>+<cr> to be related-rfc compliant */
     118     fIn=open(vSO->iDocSigFilename,O_RDONLY);
     119     if (fIn==-1) {
     120       ER_perror(FAC_PA, PA_CANTREAD, "can't open %s for reading", vSO->iDocSigFilename);
     121       exit(1);
     122     }
     123     strcpy(tmpFileName,tmpdir);
     124     strcat(tmpFileName,"/patmpXXXXXXX");
     125     fOut=mkstemp(tmpFileName);
     126     if (fOut==-1) {
     127       ER_perror(FAC_PA, PA_NOTEMP, "%s", tmpFileName);
     128       exit(1);
     129     }
     130     prevChar=0;
     131     sprintf(lfcrStr,"%c%c%c",13,10,0);
     132     while(read(fIn,strIn,1)>0)
     133     {
     134       if ((strIn[0]==10)&&(prevChar!=13)) {
     135         write(fOut,lfcrStr,2);
     136       } else {
     137         write(fOut,strIn,1);
     138       }
     139       prevChar=strIn[0];
     140     }
     141     close(fOut);
     142     close(fIn);
     143     /* end change <cr> to <lf>+<cr> to be related-rfc compliant */
     144
     145     strcpy(Args5, "--verify");
     146     strcpy(Args6, vSO->iSigFilename);
     147     strcpy(Args7, tmpFileName);
     148
     149     strArgs[6] = Args6;
     150     strArgs[7] = Args7;
     151     strArgs[8] = (char *)0;
     152     strcpy(vSO->oStream, vSO->iDocSigFilename);
     153   }
     154
     155   strArgs[0] = Args0;
     156   strArgs[1] = Args1;
     157   strArgs[2] = Args2;
     158   strArgs[3] = Args3;
     159   strArgs[4] = Args4;
     160   strArgs[5] = Args5;
     161
     162   gpg_in_fd = INPUT_FD;
     163   out_fd = OUTPUT_FD;
     164   err_fd = ERROR_FD;
     165   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     166                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 )
     167     {
     168       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     169       exit(1);
     170     }
     171
     172   if (waitpid (gpg_pid, &status, 0) < 0)
     173     {
     174       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     175       exit(1);
     176     }
     177   unlink(tmpFileName);
     178   if (WIFEXITED(status) == 0)
     179     {
     180       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     181       exit(1);
     182     } else {
     183       /* Child exited, checking return code */
     184       /* childRC = (status & 0xF00) >> 8;
     185       if (childRC == 1) {
     186         fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
     187         printf ("gpg failure\n");
     188         exit(1);
     189         } */
     190     }
     191
     192
     193   /* Parsing gpg output */
     194   vSO->isValid = vSO_KO;
     195   while (fgets (txt, LINE_LENGTH - 1, stdin) != NULL)
     196     {
     197       /*        printf ( "GPG output : %s\n", txt );   */
     198       if (strstr(txt, "Good signature") != NULL)
     199         vSO->isValid = vSO_IS_VALID;
     200
     201       if (strstr(txt, "CRC error") != NULL)
     202         vSO->isValid = vSO_CRC_ERROR;
     203
     204       if (strstr(txt, "public key not found") != NULL)
     205         vSO->isValid = vSO_NO_PUBLIC_KEY;
     206
     207       if (strstr(txt, "no valid OpenPGP data found") != NULL)
     208         vSO->isValid = vSO_NO_OPENPGP_DATA;
     209
     210       if ((keyStr = strstr(txt, "key ID")) != NULL) {
     211         keyStr += 7;
     212         sscanf(keyStr, "%8X\n", &vSO->keyID);
     213       }
     214     }
     215
     216   if (sd1[0] != 0)  close ( sd1[0] );
     217 }
     218
     219
     220
     221 /*++++++++++++++++++++++++++++
     222
     223 Decrypt a PGP-encrypted file.
     224
     225 struct ReadCryptedObject *rDO   The object to be decrypted
     226
     227
     228 Note:
     229   This functions is not used by PA/EP/MM
     230   It can be useful in the future....  (FP)
     231
     232 ++++++++++++++++++++++++++++*/
     233
     234 void PA_Decrypt(struct ReadCryptedObject *rDO) {
         /* [<][>][^][v][top][bottom][index][help] */
     235
     236   char *strArgs[9];
     237   char clearTextExtension[4] = ".gpg";
     238   char Args0[100];
     239   char Args1[100];
     240   char Args2[100];
     241   char Args3[100];
     242   char Args4[100];
     243   char Args5[100];
     244   char Args6[100];
     245   int gpg_pid;
     246   int gpg_in_fd, out_fd, err_fd;
     247   int status;
     248   char txt[LINE_LENGTH];
     249   int childRC;
     250
     251   strcpy(Args0, "--no-tty");
     252   strcpy(Args1, "--no-secmem-warning");
     253   strcpy(Args2, "--keyring");
     254   strcpy(Args3, rDO->keyRing);
     255   strcpy(Args4, "--output");
     256   strcpy(Args5, strcat(rDO->iFilename, clearTextExtension));
     257   strcpy(Args6, rDO->iFilename);
     258
     259   strArgs[0] = Args0;
     260   strArgs[1] = Args1;
     261   strArgs[2] = Args2;
     262   strArgs[3] = Args3;
     263   strArgs[4] = Args4;
     264   strArgs[5] = Args5;
     265   strArgs[6] = Args6;
     266   strArgs[7] = (char *) 0;
     267
     268   gpg_in_fd = INPUT_FD;
     269   out_fd = OUTPUT_FD;
     270   err_fd = ERROR_FD;
     271   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     272                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 )
     273     {
     274       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     275       exit(1);
     276     }
     277
     278   if (waitpid (gpg_pid, &status, 0) < 0)
     279     {
     280       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     281       exit(1);
     282     }
     283   if (WIFEXITED(status) == 0)
     284     {
     285       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     286       exit(1);
     287     } else {
     288       /* Child exited, checking return code */
     289       childRC = (status & 0xF00) >> 8;
     290       if (childRC == 1) {
     291         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     292         exit(1);
     293       }
     294     }
     295
     296
     297   /* Parsing gpg output */
     298   while (fgets (txt, STRING_LENGTH - 1, stdin) != NULL)
     299     {
     300
     301     }
     302
     303   if (sd1[0] != 0)  close ( sd1[0] );
     304 }
     305
     306
     307
     308 /*++++++++++++++++++++++++++++
     309
     310 Import a PGP key.
     311
     312 struct ImportKeyObject *iKO     The structure where the imported key goes
     313
     314 ++++++++++++++++++++++++++++*/
     315
     316 void PA_ImportKey(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     317
     318   char *strArgs[9];
     319   char Args0[100];
     320   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100];
     321   int gpg_pid;
     322   int gpg_in_fd, out_fd, err_fd;
     323   int status;
     324   char txt[LINE_LENGTH];
     325   char *keyStr, *pos;
     326   const char lockFilename[] = ".PAlock";
     327   char keyRingLockFile[1000], keyRingPath[1000];
     328   time_t lockBirthDate;
     329   FILE *mystdin;
     330   int childRC;
     331   int key_count;
     332   GList *key_list = NULL;
     333   GList *next = NULL;
     334   struct ImportKeyObject iKO_toBeRemoved;
     335
     336   iKO->rc = iKO_GENERALFAILURE;
     337
     338   strcpy(Args0, "--no-tty");
     339   strcpy(Args1, "--no-secmem-warning");
     340   strcpy(Args2, "--keyring");
     341   strcpy(Args3, iKO->keyRing);
     342   strcpy(Args4, "--import");
     343   strcpy(Args5, iKO->iFilename);
     344
     345   strArgs[0] = Args0;
     346   strArgs[1] = Args1;
     347   strArgs[2] = Args2;
     348   strArgs[3] = Args3;
     349   strArgs[4] = Args4;
     350   strArgs[5] = Args5;
     351   strArgs[6] = (char *)0;
     352
     353   gpg_in_fd = INPUT_FD;
     354   out_fd = OUTPUT_FD;
     355   err_fd = ERROR_FD;
     356
     357   /* create lock file filenames for NFS */
     358
     359   strcpy(keyRingLockFile, iKO->keyRing);
     360   if ((pos = strrchr(keyRingLockFile, '/')) != NULL) {
     361     strcpy(pos + 1, lockFilename);
     362     strcpy(keyRingPath, keyRingLockFile);
     363     keyRingPath[pos - keyRingLockFile] = 0;
     364   } else {
     365     strcpy(keyRingLockFile, lockFilename);
     366     strcpy(keyRingPath, "");
     367   }
     368
     369   lockBirthDate = nfslock(keyRingPath, (char*)lockFilename, 0, 0);
     370
     371   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     372                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
     373     ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     374     exit(1);
     375   }
     376
     377   if (waitpid (gpg_pid, &status, 0) < 0)
     378     {
     379       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     380       nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
     381       exit(1);
     382     }
     383
     384   nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
     385
     386   if (WIFEXITED(status) == 0)
     387     {
     388       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     389     } else {
     390       /* Child exited, checking return code */
     391       childRC = (status & 0xF00) >> 8;
     392       if (childRC == 1) {
     393         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     394         exit(1);
     395       }
     396     }
     397
     398
     399   /* Parsing gpg output */
     400   /*   while (read(0, txt, 1000) != 0)
     401        fprintf(stderr, "child read %s\n", txt); */
     402
     403   mystdin = fdopen(0, "r");
     404   iKO->rc = iKO_GENERALFAILURE;
     405   key_count = 0;
     406   while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
     407     {
     408       /*          printf ( "GPG output : %s\n", txt );      */
     409
     410       if ((keyStr = strstr(txt, "imported")) != NULL) {
     411         iKO->rc = iKO_OK;
     412       }
     413
     414       if ((keyStr = strstr(txt, "CRC error")) != NULL) {
     415         iKO->rc = iKO_CRC_ERROR;
     416       }
     417
     418       if ((keyStr = strstr(txt, "no valid OpenPGP")) != NULL) {
     419         iKO->rc = iKO_NO_OPENPGP_DATA;
     420       }
     421
     422       if (((keyStr = strstr(txt, "unchanged")) != NULL) ||
     423           ((keyStr = strstr(txt, "not changed")) != NULL)) {
     424         iKO->rc = iKO_UNCHANGED;
     425       }
     426
     427       if ((keyStr = strstr(txt, "key")) != NULL) {
     428          keyStr += 4;
     429          sscanf(keyStr, "%8X\n", &iKO->keyID);
     430    key_count++;
     431    /* and put the key ID into the keys list (if it was new to the keyring)*/
     432    if(strstr(txt, "imported") != NULL){
     433      key_list = g_list_append(key_list, GINT_TO_POINTER(iKO->keyID));
     434    }
     435
     436       }
     437     }
     438
     439   if (sd1[0] != 0)  close ( sd1[0] );
     440
     441   if(key_count > 1){/* if there were more than one keys imported */
     442     iKO->rc = iKO_MULTIPLE_KEYS; /* this is an error */
     443     /* now, roll-back, remove the added keys from key-ring */
     444     for( next = key_list; next != NULL; next = g_list_next(next) ){
     445       strcpy(iKO_toBeRemoved.keyRing,
     446           iKO->keyRing);
     447       iKO_toBeRemoved.keyID = (u32)(next->data);
     448       PA_RemoveKey_withKeyID(&iKO_toBeRemoved);
     449     }
     450
     451   }else{
     452     /* Get the finger print */
     453     GetFingerPrint(iKO);
     454     GetKeyOwner(iKO);
     455   }
     456 }
     457
     458
     459
     460 /*++++++++++++++++++++++++++++
     461
     462 Remove a PGP key.
     463
     464 struct ImportKeyObject *iKO     The structure containing the key to be removed
     465
     466 ++++++++++++++++++++++++++++*/
     467
     468 void PA_RemoveKey(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     469
     470   char *strArgs[9];
     471   char Args0[100]= "gpg";
     472   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100], Args6[100], Args7[100];
     473   int gpg_pid;
     474   int gpg_in_fd, out_fd, err_fd;
     475   int status;
     476   char txt[LINE_LENGTH];
     477   char *keyStr, *pos;
     478   const char lockFilename[] = ".PAlock";
     479   char keyRingLockFile[1000], keyRingPath[1000];
     480   time_t lockBirthDate;
     481   FILE *mystdin;
     482   int childRC;
     483
     484   iKO->rc = iKO_GENERALFAILURE;
     485
     486   GetKeyID(iKO);   /* getting key-id */
     487
     488   /*   printf("Key id = %08lX\n", iKO->keyID); */
     489
     490   if ((iKO->rc == iKO_OK) || (iKO->rc == iKO_UNCHANGED)) {
     491     strcpy(Args1, "--batch");
     492     strcpy(Args2, "--yes");
     493     strcpy(Args3, "--no-secmem-warning");
     494     strcpy(Args4, "--keyring");
     495     strcpy(Args5, iKO->keyRing);
     496     strcpy(Args6, "--delete-key");
     497     sprintf(Args7, "%08X", iKO->keyID);
     498
     499     strArgs[0] = Args0;
     500     strArgs[1] = Args1;
     501     strArgs[2] = Args2;
     502     strArgs[3] = Args3;
     503     strArgs[4] = Args4;
     504     strArgs[5] = Args5;
     505     strArgs[6] = Args6;
     506     strArgs[7] = Args7;
     507     strArgs[8] = (char *)0;
     508
     509
     510     gpg_in_fd = INPUT_FD;
     511     out_fd = OUTPUT_FD;
     512     err_fd = ERROR_FD;
     513
     514   /* create lock file filenames for NFS */
     515
     516     strcpy(keyRingLockFile, iKO->keyRing);
     517     if ((pos = strrchr(keyRingLockFile, '/')) != NULL) {
     518       strcpy(pos + 1, lockFilename);
     519       strcpy(keyRingPath, keyRingLockFile);
     520       keyRingPath[pos - keyRingLockFile] = 0;
     521     } else {
     522       strcpy(keyRingLockFile, lockFilename);
     523       strcpy(keyRingPath, "");
     524     }
     525
     526     lockBirthDate = nfslock(keyRingPath, (char*)lockFilename, 0, 0);
     527
     528     if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     529                                 &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
     530       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     531       exit(1);
     532     }
     533
     534     /*    printf("Child pid = %d\n", gpg_pid); */
     535
     536     if (waitpid (gpg_pid, &status, 0) < 0)
     537       {
     538         ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     539         exit(1);
     540       }
     541
     542     nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
     543
     544     if (WIFEXITED(status) == 0)
     545       {
     546         ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     547         exit(1);
     548       }  else {
     549         /* Child exited, checking return code */
     550         childRC = (status & 0xF00) >> 8;
     551         if (childRC == 1) {
     552           ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     553           exit(1);
     554         }
     555       }
     556
     557
     558     mystdin = fdopen(0, "r");
     559     iKO->rc = iKO_OK;
     560     while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
     561       {
     562         /* printf ( "GPG output : %s\n", txt );        */
     563
     564         if ((keyStr = strstr(txt, "delete key failed")) != NULL) {
     565           iKO->rc = iKO_GENERALFAILURE;
     566         }
     567         if ((keyStr = strstr(txt, "there is a secret key for this public key")) != NULL) {
     568           iKO->rc = iKO_SECRET_KEY_PRESENT;
     569         }
     570
     571       }
     572
     573     if (sd1[0] != 0)  close ( sd1[0] );
     574   }
     575 }
     576
     577 /*++++++++++++++++++++++++++++
     578
     579 Remove a PGP key, using its KeyID (otherwise it's the same as PA_RemoveKey
     580
     581 struct ImportKeyObject *iKO     The structure containing the key to be removed
     582
     583 ++++++++++++++++++++++++++++*/
     584
     585 void PA_RemoveKey_withKeyID(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     586
     587   char *strArgs[9];
     588   char Args0[100]= "gpg";
     589   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100], Args6[100], Args7[100];
     590   int gpg_pid;
     591   int gpg_in_fd, out_fd, err_fd;
     592   int status;
     593   char txt[LINE_LENGTH];
     594   char *keyStr, *pos;
     595   const char lockFilename[] = ".PAlock";
     596   char keyRingLockFile[1000], keyRingPath[1000];
     597   time_t lockBirthDate;
     598   FILE *mystdin;
     599   int childRC;
     600
     601   iKO->rc = iKO_GENERALFAILURE;
     602
     603
     604     strcpy(Args1, "--batch");
     605     strcpy(Args2, "--yes");
     606     strcpy(Args3, "--no-secmem-warning");
     607     strcpy(Args4, "--keyring");
     608     strcpy(Args5, iKO->keyRing);
     609     strcpy(Args6, "--delete-key");
     610     sprintf(Args7, "%08X", iKO->keyID);
     611
     612     strArgs[0] = Args0;
     613     strArgs[1] = Args1;
     614     strArgs[2] = Args2;
     615     strArgs[3] = Args3;
     616     strArgs[4] = Args4;
     617     strArgs[5] = Args5;
     618     strArgs[6] = Args6;
     619     strArgs[7] = Args7;
     620     strArgs[8] = (char *)0;
     621
     622
     623     gpg_in_fd = INPUT_FD;
     624     out_fd = OUTPUT_FD;
     625     err_fd = ERROR_FD;
     626
     627   /* create lock file filenames for NFS */
     628
     629     strcpy(keyRingLockFile, iKO->keyRing);
     630     if ((pos = strrchr(keyRingLockFile, '/')) != NULL) {
     631       strcpy(pos + 1, lockFilename);
     632       strcpy(keyRingPath, keyRingLockFile);
     633       keyRingPath[pos - keyRingLockFile] = 0;
     634     } else {
     635       strcpy(keyRingLockFile, lockFilename);
     636       strcpy(keyRingPath, "");
     637     }
     638
     639     lockBirthDate = nfslock(keyRingPath, (char*)lockFilename, 0, 0);
     640
     641
     642     if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     643                                 &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
     644       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     645       exit(1);
     646     }
     647
     648     /*    printf("Child pid = %d\n", gpg_pid); */
     649
     650     if (waitpid (gpg_pid, &status, 0) < 0)
     651       {
     652         ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     653         exit(1);
     654       }
     655
     656     nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
     657
     658     if (WIFEXITED(status) == 0)
     659       {
     660         ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     661         exit(1);
     662       }  else {
     663         /* Child exited, checking return code */
     664         childRC = (status & 0xF00) >> 8;
     665         if (childRC == 1) {
     666           ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     667           exit(1);
     668         }
     669       }
     670
     671
     672     mystdin = fdopen(0, "r");
     673     iKO->rc = iKO_OK;
     674     while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
     675       {
     676         /* printf ( "GPG output : %s\n", txt );        */
     677
     678         if ((keyStr = strstr(txt, "delete key failed")) != NULL) {
     679           iKO->rc = iKO_GENERALFAILURE;
     680         }
     681         if ((keyStr = strstr(txt, "there is a secret key for this public key")) != NULL) {
     682           iKO->rc = iKO_SECRET_KEY_PRESENT;
     683         }
     684
     685       }
     686
     687     if (sd1[0] != 0)  close ( sd1[0] );
     688
     689 }
     690
     691
     692
     693
     694 /*++++++++++++++++++++++++++++
     695
     696 Parse a file and look for PGP-signed elements inside.
     697
     698 EPNodePtr ptr   The pointer to the EP treenode containing the file to be parsed.
     699
     700 ++++++++++++++++++++++++++++*/
     701
     702 EPNodePtr PA_ParseMessage(EPNodePtr ptr) {
         /* [<][>][^][v][top][bottom][index][help] */
     703
     704   /* Assumptions:
     705      - ptr is describing a text file, not MIME
     706      - input file is broken down to pieces, plain text or PGP blocks
     707      - if input file is doesn't have any PGP block, this is a leaf
     708      - otherwise send each block to the proper handler.
     709   */
     710
     711   FILE *fin, *fout;
     712   char txt[MAX_LINE_BUF], *strptr;
     713   /* char blockFilename[LINE_LENGTH]; */
     714   const char PGP_prefix_msg[] =       "-----BEGIN PGP MESSAGE";
     715   const char PGP_suffix_msg[] =       "-----END PGP MESSAGE";
     716   const char PGP_prefix_signed[] =    "-----BEGIN PGP SIGNED MESSAGE";
     717   const char PGP_suffix_signature[] = "-----END PGP SIGNATURE";
     718   int found_prefix = 0, found_suffix = 0;
     719   EPNodePtr p = ptr, prev = ptr;
     720   int end_of_fin = 0, text_block = 1;
     721
     722
     723   ER_dbg_va (FAC_PA, ASP_PA_GEN, "Entering PA_ParseMessage...");
     724
     725
     726   if ((fin = fopen(ptr->file, "r")) != NULL) {
     727
     728     do {
     729       /* this is needed because a text block parser ends when it finds
     730          a PGP prefix, so we already have a txt buffer.   */
     731
     732       if (!text_block || (prev == ptr)) {
     733         strptr = fgets(txt, MAX_LINE_BUF, fin);
     734         if (strptr == NULL ) end_of_fin = 1;
     735       }
     736
     737       if (!end_of_fin && (found_prefix || (strstr(txt, PGP_prefix_msg) != NULL) ||
     738                           (strstr(txt, PGP_prefix_signed) != NULL))) {
     739         /* PGP block */
     740         found_prefix = 1;
     741         text_block = 0;
     742
     743         p = EP_DefineNewNode(++EP_Node_ID, vS_TO_BE_PGPVERIFIED,
     744                              ptr->MIMEContentType, ptr->strMIMEContentType, 0);
     745
     746         if (prev != ptr)
     747           prev->next = p;
     748         else
     749           ptr->inner = p;
     750
     751         if ((fout = fopen(p->file, "w")) != NULL ) {
     752           fputs(txt, fout);
     753           /* To be replaced by fwrite(), more efficient */
     754           while ((found_prefix != found_suffix) &&
     755                  ((strptr = fgets(txt, MAX_LINE_BUF, fin)) != NULL)) {
     756             if (strstr(txt, PGP_prefix_msg) != NULL) found_prefix++;
     757             if (strstr(txt, PGP_prefix_signed) != NULL) found_prefix++;
     758             if (strstr(txt, PGP_suffix_msg) != NULL) found_suffix++;
     759             if (strstr(txt, PGP_suffix_signature) != NULL) found_suffix++;
     760             fputs(txt, fout);
     761           }
     762           if (strptr == NULL ) end_of_fin = 1;
     763
     764           fclose(fout);
     765
     766           if (found_prefix == found_suffix) {
     767             found_prefix = found_suffix = 0;
     768
     769             VerifySignAndExplodeFile(p);
     770
     771             /* Called form EP_ParseMail or EP_PArseText ? */
     772
     773             if (strstr(EP_outputPrefix, "EPMtmp") != NULL)
     774               {
     775                 ER_dbg_va (FAC_PA, ASP_PA_GEN, "Found prefix and suffix; calling EP_MIMEParse...");
     776                 EP_MIMEParse(p);
     777               }
     778             else
     779               PA_ParseMessage(p);
     780
     781             prev = p;
     782           } else {
     783             /* Wrong PGP delimiters order. */
     784             p->isValidPGPSignature = vS_UNMATCHED_PGP_DELIMITERS;
     785           }
     786         } else {
     787           p->isValidPGPSignature = vS_UNABLE_TO_WRITE_FILE;
     788           return p;
     789         }
     790
     791       } else {
     792         /* Clear text block */
     793
     794         text_block = 1;
     795
     796         if (strptr == NULL) end_of_fin = 1;
     797         else {
     798           p = EP_DefineNewNode(++EP_Node_ID, vS_IS_NOT_PGP,
     799                                ptr->MIMEContentType,
     800                                ptr->strMIMEContentType, 0);
     801
     802           if (prev != ptr)
     803             prev->next = p;
     804           else
     805             ptr->inner = p;
     806
     807           if ((fout = fopen(p->file, "w")) != NULL ) {
     808             fputs(txt, fout);
     809             /* To be replaced by fwrite(), more efficient */
     810             while ((!found_prefix &&
     811                     (strptr = fgets(txt, MAX_LINE_BUF, fin)) != NULL)) {
     812               if ((strstr(txt, PGP_prefix_msg) != NULL) ||
     813                   (strstr(txt, PGP_prefix_signed) != NULL)) found_prefix++;
     814               else
     815                 fputs(txt, fout);
     816             }
     817             if (strptr == NULL ) end_of_fin = 1;
     818
     819             fclose(fout);
     820
     821             /* Check if the blockfile is finished and this is the first
     822                segment. If so this is a text leaf */
     823             if (found_prefix || (prev != p)) {
     824               if (prev->MIMEContentType == -1)
     825                 {
     826                   if (strstr(EP_outputPrefix, "EPMtmp") != NULL)
     827                     {
     828                       ER_dbg_va (FAC_PA, ASP_PA_GEN, "PA_ParseMessage: sending to EP_MIMEParse");
     829                       EP_MIMEParse(p);
     830                     }
     831                   else
     832                     PA_ParseMessage(p);
     833                 }
     834
     835               prev = p;
     836             }
     837
     838           } else {
     839             p->isValidPGPSignature = vS_UNABLE_TO_WRITE_FILE;
     840             return p;
     841           }
     842         }
     843       }
     844     } while (!end_of_fin);
     845   } else {
     846     p->isValidPGPSignature = vS_NO_IN_FILES;
     847   }
     848
     849   return ptr;
     850 }
     851
     852
     853 /**************************************
     854  *
     855  * Internal functions
     856  *
     857  **************************************/
     858
     859
     860
     861 /*++++++++++++++++++++++++++++
     862
     863 Get the fingerprint of a PGP key.
     864
     865 ImportKeyObject *iKO    The imported key object
     866
     867 ++++++++++++++++++++++++++++*/
     868
     869 void GetFingerPrint(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     870
     871   char *strArgs[9];
     872   char Args0[100] ;
     873   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100];
     874   int gpg_pid;
     875   int gpg_in_fd, out_fd, err_fd;
     876   int status;
     877   char txt[LINE_LENGTH];
     878   char *keyStr;
     879   FILE *mystdin;
     880   int childRC;
     881
     882   strcpy(Args0, "--no-tty");
     883   strcpy(Args1, "--no-secmem-warning");
     884   strcpy(Args2, "--keyring");
     885   strcpy(Args3, iKO->keyRing);
     886   strcpy(Args4, "--fingerprint");
     887   sprintf(Args5, "%08X", iKO->keyID);
     888
     889   strArgs[0] = Args0;
     890   strArgs[1] = Args1;
     891   strArgs[2] = Args2;
     892   strArgs[3] = Args3;
     893   strArgs[4] = Args4;
     894   strArgs[5] = Args5;
     895   strArgs[6] = (char *)0;
     896
     897   gpg_in_fd = INPUT_FD;
     898   out_fd = OUTPUT_FD;
     899   err_fd = ERROR_FD;
     900
     901   /* create lock file filenames for NFS */
     902
     903   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     904                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
     905     ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     906     exit(1);
     907   }
     908
     909   if (waitpid (gpg_pid, &status, 0) < 0)
     910     {
     911       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
     912       exit(1);
     913     }
     914
     915   if (WIFEXITED(status) == 0)
     916     {
     917       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
     918       exit(1);
     919     } else {
     920       /* Child exited, checking return code */
     921       childRC = (status & 0xF00) >> 8;
     922       if (childRC == 1) {
     923         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
     924         exit(1);
     925       }
     926     }
     927
     928
     929   mystdin = fdopen(0, "r");
     930   while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
     931     {
     932       /* printf ( "GPG output : %s\n", txt );      */
     933
     934       if ((keyStr = strstr(txt, "Key fingerprint =")) != NULL) {
     935         strcpy(iKO->fingerPrint, keyStr + 18);
     936         iKO->fingerPrint[strlen(iKO->fingerPrint)-1] = 0;
     937       }
     938
     939       if ((keyStr = strstr(txt, "key")) != NULL) {
     940          keyStr += 4;
     941          sscanf(keyStr, "%8X\n", &iKO->keyID);
     942       }
     943     }
     944
     945   if (sd1[0] != 0)  close ( sd1[0] );
     946 }
     947
     948
     949
     950 /*++++++++++++++++++++++++++++
     951
     952 Get the owner of a PGP key.
     953
     954 ImportKeyObject *iKO    The imported key object
     955
     956 ++++++++++++++++++++++++++++*/
     957
     958 void GetKeyOwner(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
     959
     960   char *strArgs[9];
     961   char Args0[100] ;
     962   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100];
     963   int gpg_pid;
     964   int gpg_in_fd, out_fd, err_fd;
     965   int status;
     966   char txt[LINE_LENGTH];
     967   char *keyStr;
     968   FILE *mystdin;
     969   int childRC;
     970
     971   strcpy(Args0, "--no-tty");
     972   strcpy(Args1, "--no-secmem-warning");
     973   strcpy(Args2, "--keyring");
     974   strcpy(Args3, iKO->keyRing);
     975   strcpy(Args4, "--fingerprint");
     976   sprintf(Args5, "%08X", iKO->keyID);
     977
     978   strArgs[0] = Args0;
     979   strArgs[1] = Args1;
     980   strArgs[2] = Args2;
     981   strArgs[3] = Args3;
     982   strArgs[4] = Args4;
     983   strArgs[5] = Args5;
     984   strArgs[6] = (char *)0;
     985
     986   gpg_in_fd = INPUT_FD;
     987   out_fd = OUTPUT_FD;
     988   err_fd = ERROR_FD;
     989
     990   /* create lock file filenames for NFS */
     991
     992   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
     993                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
     994     ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
     995     exit(1);
     996   }
     997
     998   if (waitpid (gpg_pid, &status, 0) < 0)
     999     {
    1000       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
    1001       exit(1);
    1002     }
    1003
    1004   if (WIFEXITED(status) == 0)
    1005     {
    1006       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
    1007       exit(1);
    1008     } else {
    1009       /* Child exited, checking return code */
    1010       childRC = (status & 0xF00) >> 8;
    1011       if (childRC == 1) {
    1012         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
    1013         exit(1);
    1014       }
    1015     }
    1016
    1017
    1018   mystdin = fdopen(0, "r");
    1019   while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
    1020     {
    1021       /* printf ( "GPG output : %s\n", txt );      */
    1022
    1023       if ((keyStr = strstr(txt, "pub "/*"Key fingerprint ="*/)) == txt /*!= NULL*/) {
    1024         strcpy(iKO->keyOwner, keyStr + 30);
    1025         iKO->keyOwner[strlen(iKO->keyOwner)-1] = 0;
    1026       }
    1027
    1028       if ((keyStr = strstr(txt, "key")) != NULL) {
    1029          keyStr += 4;
    1030          sscanf(keyStr, "%8X\n", &iKO->keyID);
    1031       }
    1032     }
    1033
    1034   if (sd1[0] != 0)  close ( sd1[0] );
    1035 }
    1036
    1037
    1038
    1039
    1040 /*++++++++++++++++++++++++++++
    1041
    1042 Verify the PGP signature and extract the signed part in a file.
    1043
    1044 EPNodePtr ptr   The pointer to the EP treenode containing the originating file
    1045
    1046 ++++++++++++++++++++++++++++*/
    1047
    1048 void VerifySignAndExplodeFile(EPNodePtr ptr) {
         /* [<][>][^][v][top][bottom][index][help] */
    1049   char *strArgs[10];
    1050   char Args0[100];
    1051   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100],
    1052     Args6[100];
    1053   int gpg_pid;
    1054   int gpg_in_fd, out_fd, err_fd;
    1055   int status;
    1056   char txt[LINE_LENGTH];
    1057   /* char hostname[MAXHOSTNAMELEN]; */
    1058   char oFile[FILENAME_LENGTH];
    1059   char *keyStr;
    1060   /* int childRC; */
    1061
    1062   sprintf(oFile, "%s.%d.exp", ptr->file, ptr->nodeID);
    1063
    1064   strcpy(Args0, "--no-secmem-warning");
    1065   strcpy(Args1, "--keyring");
    1066   strcpy(Args2, EP_keyRing);
    1067   strcpy(Args3, "-o");
    1068   strcpy(Args4, oFile);
    1069   strcpy(Args5, "-d");
    1070   strcpy(Args6, ptr->file);
    1071   strArgs[6] = Args6;
    1072   strArgs[7] = (char *)0;
    1073
    1074   strArgs[0] = Args0;
    1075   strArgs[1] = Args1;
    1076   strArgs[2] = Args2;
    1077   strArgs[3] = Args3;
    1078   strArgs[4] = Args4;
    1079   strArgs[5] = Args5;
    1080
    1081   gpg_in_fd = INPUT_FD;
    1082   out_fd = OUTPUT_FD;
    1083   err_fd = ERROR_FD;
    1084   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
    1085                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 )
    1086     {
    1087       ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
    1088       exit(1);
    1089     }
    1090
    1091   if (waitpid (gpg_pid, &status, 0) < 0)
    1092     {
    1093       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
    1094       exit(1);
    1095     }
    1096   if (WIFEXITED(status) == 0)
    1097     {
    1098       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
    1099       exit(1);
    1100     } else {
    1101       /* Child exited, checking return code */
    1102       /* childRC = (status & 0xF00) >> 8;
    1103       if (childRC == 1) {
    1104         fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
    1105         printf ("gpg failure\n");
    1106         exit(1);
    1107         } */
    1108     }
    1109
    1110
    1111   /* Parsing gpg output */
    1112   ptr->isValidPGPSignature = vS_KO;
    1113   while (fgets (txt, LINE_LENGTH - 1, stdin) != NULL)
    1114     {
    1115       /*        printf ( "GPG output : %s\n", txt );   */
    1116       if (strstr(txt, "Good signature") != NULL)
    1117         ptr->isValidPGPSignature = vS_IS_VALID;
    1118
    1119       if (strstr(txt, "CRC error") != NULL)
    1120         ptr->isValidPGPSignature = vS_CRC_ERROR;
    1121
    1122       if (strstr(txt, "public key not found") != NULL)
    1123         ptr->isValidPGPSignature = vS_NO_PUBLIC_KEY;
    1124
    1125       if (strstr(txt, "no valid OpenPGP data found") != NULL)
    1126         ptr->isValidPGPSignature = vS_NO_OPENPGP_DATA;
    1127
    1128       if ((keyStr = strstr(txt, "key ID")) != NULL) {
    1129         keyStr += 7;
    1130         sscanf(keyStr, "%8X\n", &ptr->keyID);
    1131       }
    1132     }
    1133
    1134   unlink(ptr->file);
    1135   UT_free(ptr->file);
    1136   ptr->file = UT_strdup(oFile);
    1137   if (sd1[0] != 0)  close ( sd1[0] );
    1138 }
    1139
    1140
    1141 /*++++++++++++++++++++++++++++
    1142
    1143 Get the KeyID of a PGP key.
    1144
    1145 struct ImportKeyObject *iKO     The structure containing the key of which we want the KeyID
    1146
    1147 ++++++++++++++++++++++++++++*/
    1148
    1149 void GetKeyID(struct ImportKeyObject *iKO) {
         /* [<][>][^][v][top][bottom][index][help] */
    1150
    1151   char *strArgs[9];
    1152   char Args0[100];
    1153   char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100];
    1154   int gpg_pid;
    1155   int gpg_in_fd, out_fd, err_fd;
    1156   int status;
    1157   char txt[LINE_LENGTH];
    1158   char *keyStr, *pos;
    1159   const char lockFilename[] = ".PAlock";
    1160   char keyRingLockFile[1000], keyRingPath[1000];
    1161   time_t lockBirthDate;
    1162   FILE *mystdin;
    1163   int childRC;
    1164
    1165   iKO->rc = iKO_GENERALFAILURE;
    1166
    1167   strcpy(Args0, "--no-tty");
    1168   strcpy(Args1, "--no-secmem-warning");
    1169   strcpy(Args2, "--keyring");
    1170   strcpy(Args3, iKO->keyRing);
    1171   strcpy(Args4, "--import");
    1172   strcpy(Args5, iKO->iFilename);
    1173
    1174   strArgs[0] = Args0;
    1175   strArgs[1] = Args1;
    1176   strArgs[2] = Args2;
    1177   strArgs[3] = Args3;
    1178   strArgs[4] = Args4;
    1179   strArgs[5] = Args5;
    1180   strArgs[6] = (char *)0;
    1181
    1182   gpg_in_fd = INPUT_FD;
    1183   out_fd = OUTPUT_FD;
    1184   err_fd = ERROR_FD;
    1185
    1186   /* create lock file filenames for NFS */
    1187
    1188   strcpy(keyRingLockFile, iKO->keyRing);
    1189   if ((pos = strrchr(keyRingLockFile, '/')) != NULL) {
    1190     strcpy(pos + 1, lockFilename);
    1191     strcpy(keyRingPath, keyRingLockFile);
    1192     keyRingPath[pos - keyRingLockFile] = 0;
    1193   } else {
    1194     strcpy(keyRingLockFile, lockFilename);
    1195     strcpy(keyRingPath, "");
    1196   }
    1197
    1198   lockBirthDate = nfslock(keyRingPath, (char*)lockFilename, 0, 0);
    1199
    1200   if ( ( gpg_pid = spawn_job (EP_gpgcmd, strArgs,
    1201                               &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
    1202     ER_perror(FAC_PA, PA_CANTSPWN, "gpg");
    1203     exit(1);
    1204   }
    1205
    1206   if (waitpid (gpg_pid, &status, 0) < 0)
    1207     {
    1208       ER_perror(FAC_PA, PA_REAP, "gpg process: %s", ERRSTRING);
    1209       nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
    1210       exit(1);
    1211     }
    1212
    1213   nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
    1214
    1215   if (WIFEXITED(status) == 0)
    1216     {
    1217       ER_perror(FAC_PA, PA_CHST, "%d - %s", status, ERRSTRING);
    1218       exit(1);
    1219     } else {
    1220       /* Child exited, checking return code */
    1221       childRC = (status & 0xF00) >> 8;
    1222       if (childRC == 1) {
    1223         ER_perror(FAC_PA, PA_CHRC, "%d", childRC);
    1224         exit(1);
    1225       }
    1226     }
    1227
    1228
    1229   /* Parsing gpg output */
    1230   /*   while (read(0, txt, 1000) != 0)
    1231        fprintf(stderr, "child read %s\n", txt); */
    1232
    1233   mystdin = fdopen(0, "r");
    1234   iKO->rc = iKO_GENERALFAILURE;
    1235   while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
    1236     {
    1237       /*          printf ( "GPG output : %s\n", txt );      */
    1238
    1239       if ((keyStr = strstr(txt, "imported")) != NULL) {
    1240         iKO->rc = iKO_OK;
    1241       }
    1242
    1243       if ((keyStr = strstr(txt, "CRC error")) != NULL) {
    1244         iKO->rc = iKO_CRC_ERROR;
    1245       }
    1246
    1247       if ((keyStr = strstr(txt, "no valid OpenPGP")) != NULL) {
    1248         iKO->rc = iKO_NO_OPENPGP_DATA;
    1249       }
    1250
    1251       if (((keyStr = strstr(txt, "unchanged")) != NULL) ||
    1252           ((keyStr = strstr(txt, "not changed")) != NULL)) {
    1253         iKO->rc = iKO_UNCHANGED;
    1254       }
    1255
    1256       if ((keyStr = strstr(txt, "gpg: key ")) != NULL) {
    1257          keyStr += 9;
    1258          sscanf(keyStr, "%8X\n", &iKO->keyID);
    1259       }
    1260     }
    1261
    1262   if (sd1[0] != 0)  close ( sd1[0] );
    1263
    1264 }
    1265

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