modules/pa/gpg.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- PA_VerifySignature
- PA_Decrypt
- PA_ImportKey
- PA_RemoveKey
- PA_RemoveKey_withKeyID
- PA_ParseMessage
- GetFingerPrint
- GetKeyOwner
- VerifySignAndExplodeFile
- 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