source: trunk/src/sh_gpg.c@ 248

Last change on this file since 248 was 248, checked in by katerina, 15 years ago

Code to track down originating site for ticket #163.

File size: 33.1 KB
RevLine 
[1]1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 1999, 2000 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24
25
26#if defined(WITH_GPG) || defined(WITH_PGP)
27
28#include <unistd.h>
29#include <fcntl.h>
30#include <signal.h>
31#if defined(SH_WITH_SERVER)
32#include <pwd.h>
33#endif
34#include <sys/stat.h>
35#include <sys/types.h>
36#include <errno.h>
37#include <sys/wait.h>
38
39#include <string.h>
40#ifdef HAVE_MEMORY_H
41#include <memory.h>
42#endif
43
44
45#if !defined(O_NONBLOCK)
46#if defined(O_NDELAY)
47#define O_NONBLOCK O_NDELAY
48#else
49#define O_NONBLOCK 0
50#endif
51#endif
52
53
54#include "samhain.h"
55#include "sh_utils.h"
56#include "sh_error.h"
57#include "sh_tiger.h"
58#if defined(SH_WITH_SERVER)
59#define SH_NEED_PWD_GRP 1
60#include "sh_static.h"
61#endif
62
63static struct {
64 char conf_id[SH_MINIBUF+1];
65 char conf_fp[SH_MINIBUF+1];
66 char data_id[SH_MINIBUF+1];
67 char data_fp[SH_MINIBUF+1];
68} gp;
69
70typedef struct {
71 pid_t pid;
72 FILE * pipe;
73} sh_gpg_popen_t;
74
75#define SH_GPG_OK 0
76#define SH_GPG_BAD 1
77#define SH_GPG_BADSIGN 2
78
79/* replace #if 0 by #if 1 and set an appropriate path in front of '/pdbg.'
80 * for debugging
81 */
82#if 0
83#define PDGBFILE "/pdbg."
84#endif
85
86#if defined(PDGBFILE)
87FILE * pdbg;
88FILE * pdbgc;
89#define PDBG_OPEN pdbg = fopen(PDGBFILE"main", "a")
90#define PDBG_CLOSE fclose (pdbg)
91#define PDBG(arg) fprintf(pdbg, "PDBG: step %d\n", arg); fflush(pdbg)
92#define PDBG_D(arg) fprintf(pdbg, "PDBG: %d\n", arg); fflush(pdbg)
93#define PDBG_S(arg) fprintf(pdbg, "PDBG: %s\n", arg); fflush(pdbg)
94
95#define PDBGC_OPEN pdbgc = fopen(PDGBFILE"child", "a")
96#define PDBGC_CLOSE fclose (pdbgc)
97#define PDBGC(arg) fprintf(pdbgc, "PDBG: step %d\n", arg); fflush(pdbgc)
98#define PDBGC_D(arg) fprintf(pdbgc, "PDBG: %d\n", arg); fflush(pdbgc)
99#define PDBGC_S(arg) fprintf(pdbgc, "PDBG: %s\n", arg); fflush(pdbgc)
100#else
101#define PDBG_OPEN
102#define PDBG_CLOSE
103#define PDBG(arg)
104#define PDBG_D(arg)
105#define PDBG_S(arg)
106#define PDBGC_OPEN
107#define PDBGC_CLOSE
108#define PDBGC(arg)
109#define PDBGC_D(arg)
110#define PDBGC_S(arg)
111#endif
112
113#undef FIL__
114#define FIL__ _("sh_gpg.c")
115
116#ifdef GPG_HASH
[86]117
[1]118static int sh_gpg_checksum (SL_TICKET checkfd, int flag)
119{
120 char * test_gpg;
121 char * test_ptr1 = NULL;
122 char * test_ptr2 = NULL;
123 char wstrip1[128];
124 char wstrip2[128];
125 int i, k;
126#include "sh_gpg_chksum.h"
127
128 SL_ENTER(_("sh_gpg_checksum"));
129
130#if defined(WITH_PGP)
[159]131 test_gpg = sh_tiger_hash_gpg (DEFAULT_PGP_PATH, checkfd, TIGER_NOLIM);
[1]132#else
[159]133 test_gpg = sh_tiger_hash_gpg (DEFAULT_GPG_PATH, checkfd, TIGER_NOLIM);
[1]134#endif
135
136 test_ptr1 = strchr(GPG_HASH, ':');
137 if (test_gpg != NULL)
138 test_ptr2 = strchr(test_gpg, ':');
139
140 if (test_ptr2 != NULL)
141 test_ptr2 += 2;
142 else
143 test_ptr2 = test_gpg;
144 if (test_ptr1 != NULL)
145 test_ptr1 += 2;
146 else
147 test_ptr1 = GPG_HASH;
148
149 /* Tue Jun 24 23:11:54 CEST 2003 (1.7.9) -- strip whitespace
150 */
151 k = 0;
152 for (i = 0; i < 127; ++i)
153 {
154 if (test_ptr1[i] == '\0')
155 break;
156 if (test_ptr1[i] != ' ')
157 {
158 wstrip1[k] = test_ptr1[i];
159 ++k;
160 }
161 }
162 wstrip1[k] = '\0';
163
164 for(i = 0; i < KEY_LEN; ++i)
165 {
166 if (gpgchk[i] != wstrip1[i])
167 {
168 sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0, MSG_E_GPG_CHK,
169 gpgchk, wstrip1);
170 break;
171 }
172 }
173
174 k = 0;
175 for (i = 0; i < 127; ++i)
176 {
177 if (test_ptr2[i] == '\0')
178 break;
179 if (test_ptr2[i] != ' ')
180 {
181 wstrip2[k] = test_ptr2[i];
182 ++k;
183 }
184 }
185 wstrip2[k] = '\0';
186
187 if (0 != sl_strncmp(wstrip1, wstrip2, 127))
188 {
189 TPT(((0), FIL__, __LINE__, _("msg=<pgp checksum: %s>\n"), test_gpg));
190 TPT(((0), FIL__, __LINE__, _("msg=<Compiled-in : %s>\n"), GPG_HASH));
191 TPT(((0), FIL__, __LINE__, _("msg=<wstrip1 : %s>\n"), wstrip1));
192 TPT(((0), FIL__, __LINE__, _("msg=<wstrip2 : %s>\n"), wstrip2));
193 if (flag == 1)
194 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_GPG,
195 GPG_HASH, test_gpg);
196 dlog(1, FIL__, __LINE__, _("The compiled-in checksum of the gpg binary\n(%s)\ndoes not match the actual checksum\n(%s).\nYou need to recompile with the correct checksum."), wstrip1, wstrip2);
197 SH_FREE(test_gpg);
198 SL_RETURN((-1), _("sh_gpg_checksum"));
199 }
200 SH_FREE(test_gpg);
201 SL_RETURN( (0), _("sh_gpg_checksum"));
202}
203#endif
204
[86]205struct startup_info {
206 long line;
207 char * program;
208 long uid;
209 char * path;
210 char * key_uid;
211 char * key_id;
212};
213
214static struct startup_info startInfo = { 0, NULL, 0, NULL, NULL, NULL };
215
[170]216void sh_gpg_log_startup (void)
[86]217{
218 if (startInfo.program != NULL)
219 {
220 sh_error_handle ((-1), FIL__, startInfo.line, 0, MSG_START_GH,
221 startInfo.program, startInfo.uid,
222 startInfo.path,
223 startInfo.key_uid, startInfo.key_id);
224 }
225 return;
226}
227
228static void sh_gpg_fill_startup (long line, char * program, long uid, char * path,
229 char * key_uid, char * key_id)
230{
231 startInfo.line = line;
232 startInfo.program = sh_util_strdup(program);
233 startInfo.uid = uid;
234 startInfo.path = sh_util_strdup(path);
235 startInfo.key_uid = sh_util_strdup(key_uid);
236 startInfo.key_id = sh_util_strdup(key_id);
237 return;
238}
239
[1]240static FILE * sh_gpg_popen (sh_gpg_popen_t *source, int fd,
241 int mode, char * id, char * homedir)
242{
[198]243 extern int flag_err_debug;
[1]244 int pipedes[2];
245 FILE * outf = NULL;
246 char * envp[2];
[22]247 size_t len;
[1]248 char path[256];
249 char cc1[32];
250 char cc2[32];
251#if defined(WITH_PGP)
252 char cc3[32];
253 char cc0[3] = "-f";
254#endif
255#if defined(WITH_GPG)
256 char cc0[2] = "-";
257 char cc3[32];
258 char cc4[SH_PATHBUF+32];
[203]259 char cc5[32];
[1]260#endif
261
262 char * arg[9];
263
264#if defined(HAVE_GPG_CHECKSUM)
[247]265 SL_TICKET checkfd = -1;
[1]266 int myrand;
267 int i;
268#if defined(__linux__)
269 int get_the_fd(SL_TICKET);
270 char pname[128];
271 int pfd;
[248]272 int val_return;
[1]273#endif
274#endif
275
276 SL_ENTER(_("sh_gpg_popen"));
277
278#if defined(WITH_GPG)
279 /* -- GnuPG -- */
280 sl_strlcpy (path, DEFAULT_GPG_PATH, 256);
281 sl_strlcpy (cc1, _("--status-fd"), 32);
282 sl_strlcpy (cc2, _("--verify"), 32);
283 sl_strlcpy (cc3, _("--homedir"), 32);
284 /* sl_strlcpy (cc4, sh.effective.home, SH_PATHBUF+32); */
285 sl_strlcpy (cc4, homedir, SH_PATHBUF+32);
[203]286 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
287 sl_strlcpy (cc5, _("--no-tty"), 32);
[1]288
289 /* fprintf(stderr, "YULE: homedir=%s\n", homedir); */
290
291#if defined(SH_WITH_SERVER)
292 if (0 == sl_ret_euid()) /* privileges not dropped yet */
293 {
294 struct stat lbuf;
295 int status_stat = 0;
[131]296#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
297 struct passwd pwd;
[227]298 char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
[131]299 struct passwd * tempres;
[227]300 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
[131]301#else
[111]302 struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
[131]303#endif
[111]304
[1]305 if (!tempres)
306 {
307 dlog(1, FIL__, __LINE__,
308 _("User %s does not exist. Please add the user to your system.\n"),
309 DEFAULT_IDENT);
310 status_stat = -1;
311 }
312 if (!tempres->pw_dir || tempres->pw_dir[0] == '\0')
313 {
314 dlog(1, FIL__, __LINE__,
315 _("User %s does not have a home directory.\nPlease add the home directory for this user to your system.\n"),
316 DEFAULT_IDENT);
317 status_stat = -2;
318 }
319 if (status_stat == 0)
320 {
321 sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
322 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
323 status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf);
324 if (status_stat == -1)
325 {
326 dlog(1, FIL__, __LINE__,
327 _("Gnupg directory %s for user %s\ndoes not exist or is not accessible.\nPlease add the directory and put the keyring (pubring.gpg) there\nto verify the configuration file.\n"),
328 cc4, DEFAULT_IDENT);
329 status_stat = -3;
330 }
331 }
332 if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
333 {
334 dlog(1, FIL__, __LINE__,
335 _("Gnupg directory %s\nis not owned by user %s.\n"),
336 cc4, DEFAULT_IDENT);
337 status_stat = -4;
338 }
339 if (status_stat == 0)
340 {
341 sl_strlcat (cc4, _("/pubring.gpg"), SH_PATHBUF+32);
342 status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf);
343 if (status_stat == -1)
344 {
345 dlog(1, FIL__, __LINE__,
346 _("Gnupg public keyring %s for user %s\ndoes not exist or is not accessible.\nPlease add the directory and put the keyring (pubring.gpg) there\nto verify the configuration file.\n"),
347 cc4, DEFAULT_IDENT);
348 status_stat = -5;
349 }
350 }
351 if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
352 {
353 dlog(1, FIL__, __LINE__,
354 _("Gnupg public keyring %s\nis not owned by user %s.\n"),
355 cc4, DEFAULT_IDENT);
356 status_stat = -6;
357 }
358 if (status_stat != 0)
359 {
360 sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1,
361 sh.prg_name);
362 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
363 }
364 sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
365 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
[227]366#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
367 SH_FREE(buffer);
368#endif
[1]369 }
370#endif
371
372 arg[0] = path;
373 arg[1] = cc1;
374 arg[2] = "1";
375 arg[3] = cc2;
376 arg[4] = cc3;
377 arg[5] = cc4;
378 arg[6] = cc5;
379 arg[7] = cc0;
380 arg[8] = NULL;
381
382 /* catch 'unused parameter' compiler warning
383 */
384 (void) mode;
385 (void) id;
386#elif defined(WITH_PGP)
387 /* -- PGP -- */
388 sl_strlcpy (path, DEFAULT_PGP_PATH, 256);
389 if (mode == 0)
390 {
391 sl_strlcpy (cc1, _("+language=en"), 32);
392 sl_strlcpy (cc2, _("-o"), 32);
393 sl_strlcpy (cc3, _("/dev/null"), 32);
394
395 arg[0] = path;
396 arg[1] = cc1;
397 arg[2] = cc2;
398 arg[3] = cc3;
399 arg[4] = cc0;
400 arg[5] = NULL;
401 }
402 else
403 {
404 sl_strlcpy (cc1, _("+language=en"), 32);
405 sl_strlcpy (cc2, _("-kvc"), 32);
406
407 arg[0] = path;
408 arg[1] = cc1;
409 arg[2] = cc2;
410 arg[3] = id;
411 arg[4] = NULL;
412 arg[5] = NULL;
413 }
414#endif
415
416 /* use homedir of effective user
417 */
418 if (sh.effective.home != NULL)
419 {
[22]420 len = sl_strlen(sh.effective.home) + 6;
421 envp[0] = malloc (len); /* free() ok */
[1]422 if (envp[0] != NULL)
[203]423 sl_snprintf (envp[0], len, _("HOME=%s"), sh.effective.home);
[1]424 envp[1] = NULL;
425 }
426 else
427 {
428 envp[0] = NULL;
429 }
430
431 /* Create the pipe
432 */
433 if (aud_pipe(FIL__, __LINE__, pipedes) < 0)
434 {
435 if (envp[0] != NULL)
436 free(envp[0]);
437 SL_RETURN( (NULL), _("sh_gpg_popen"));
438 }
[102]439
440 fflush (NULL);
[1]441
442 source->pid = aud_fork(FIL__, __LINE__);
443
444 /* Failure
445 */
446 if (source->pid == (pid_t) - 1)
447 {
448 close(pipedes[0]);
449 close(pipedes[1]);
450 if (envp[0] != NULL)
451 free(envp[0]);
452 SL_RETURN( (NULL), _("sh_gpg_popen"));
453 }
454
455 if (source->pid == (pid_t) 0)
456 {
457
458 /* child - make read side of the pipe stdout
459 */
460 if (retry_aud_dup2(FIL__, __LINE__,
461 pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0)
462 {
463 TPT(((0), FIL__, __LINE__, _("msg=<dup2 on pipe failed>\n")));
464 dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
465 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
466 }
467
468 /* close the pipe descriptors
469 */
470 close (pipedes[STDIN_FILENO]);
471 close (pipedes[STDOUT_FILENO]);
472
473
474#if defined(WITH_PGP)
475 if (mode == 0)
476 {
477 if (retry_aud_dup2(FIL__, __LINE__, fd, STDIN_FILENO) < 0)
478 {
479 TPT(((0), FIL__, __LINE__, _("msg=<dup2 on fd failed>\n")));
480 dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
481 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
482 }
483 }
484#else
485 if (retry_aud_dup2(FIL__, __LINE__, fd, STDIN_FILENO) < 0)
486 {
487 TPT(((0), FIL__, __LINE__, _("msg=<dup2 on fd failed>\n")));
488 dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
489 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
490 }
491#endif
492
493 /* don't leak file descriptors
494 */
[174]495 sh_unix_closeall (3, -1, SL_TRUE); /* in child process */
[1]496
[198]497 if (flag_err_debug != SL_TRUE)
[153]498 {
[198]499 if (NULL == freopen(_("/dev/null"), "r+", stderr))
500 {
501 dlog(1, FIL__, __LINE__, _("Internal error: freopen failed\n"));
502 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
503 }
[153]504 }
[1]505
[198]506
[1]507 /* We should become privileged if SUID,
508 * to be able to read the keyring.
509 * We have checked that gpg is OK,
510 * AND that only a trusted user could overwrite
511 * gpg.
512 */
513 memset (skey, '\0', sizeof(sh_key_t));
514 aud_setuid(FIL__, __LINE__, geteuid());
515
516 PDBGC_OPEN;
517 PDBGC_D((int)getuid());
518 PDBGC_D((int)geteuid());
519
520 {
521 int i = 0;
522 while (arg[i] != NULL)
523 {
524 PDBGC_S(arg[i]);
525 ++i;
526 }
527 }
528 PDBGC_CLOSE;
529
530 /* exec the program */
531
532#if defined(__linux__) && defined(HAVE_GPG_CHECKSUM)
533 /*
534 * -- emulate an fexecve with checksum testing
535 */
536#if defined(WITH_PGP)
[248]537 checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_PGP_PATH, SL_NOPRIV);
[1]538#else
[248]539 checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_GPG_PATH, SL_NOPRIV);
[1]540#endif
541
542 if (0 != sh_gpg_checksum(checkfd, 0))
[248]543 {
544 sl_close(checkfd);
545 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
546 }
[1]547
548 pfd = get_the_fd(checkfd);
[248]549 do {
550 val_return = dup (pfd);
551 } while (val_return < 0 && errno == EINTR);
552 pfd = val_return;
553 sl_close(checkfd);
554 checkfd = -1;
555
[22]556 sl_snprintf(pname, sizeof(pname), _("/proc/self/fd/%d"), pfd);
557 if (0 == access(pname, R_OK|X_OK)) /* flawfinder: ignore */
558
[1]559 {
560 fcntl (pfd, F_SETFD, FD_CLOEXEC);
561 retry_aud_execve (FIL__, __LINE__, pname, arg, envp);
562
563 dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"),
564 pname);
565 /* failed
566 */
567 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
568 }
569
570 /* procfs not working, go ahead
571 */
572#endif
573
574#if defined(HAVE_GPG_CHECKSUM)
575 /* This is an incredibly ugly kludge to prevent an attacker
576 * from knowing when it is safe to slip in a fake executable
577 * between the integrity check and the execve
578 */
[137]579 myrand = (int) taus_get ();
580
[1]581 myrand = (myrand < 0) ? (-myrand) : myrand;
582 myrand = (myrand % 32) + 2;
583
584 for (i = 0; i < myrand; ++i)
585 {
586#if defined(WITH_PGP)
[248]587 checkfd = sl_open_fastread(FIL__, __LINE__, DEFAULT_PGP_PATH, SL_NOPRIV);
[1]588#else
[248]589 checkfd = sl_open_fastread(FIL__, __LINE__, DEFAULT_GPG_PATH, SL_NOPRIV);
[1]590#endif
591 if (0 != sh_gpg_checksum(checkfd, 0)) {
592 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
593 }
594 sl_close(checkfd);
595 }
596#endif
597
598
599#if defined(WITH_GPG)
600 retry_aud_execve (FIL__, __LINE__, DEFAULT_GPG_PATH, arg, envp);
601 dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"),
602 DEFAULT_GPG_PATH);
603#elif defined(WITH_PGP)
604 retry_aud_execve (FIL__, __LINE__, DEFAULT_PGP_PATH, arg, envp);
605#endif
606
607 /* failed
608 */
609 TPT(((0), FIL__, __LINE__, _("msg=<execve failed>\n")));
610 dlog(1, FIL__, __LINE__, _("Unexpected error: execve failed\n"));
611 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
612 }
613
614 /* parent
615 */
616
617 if (envp[0] != NULL)
618 free(envp[0]);
619
620 close (pipedes[STDOUT_FILENO]);
621 retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
622 retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFL, O_NONBLOCK);
623
624 outf = fdopen (pipedes[STDIN_FILENO], "r");
625
626 if (outf == NULL)
627 {
628 aud_kill (FIL__, __LINE__, source->pid, SIGKILL);
629 close (pipedes[STDOUT_FILENO]);
630 waitpid (source->pid, NULL, 0);
631 source->pid = 0;
632 SL_RETURN( (NULL), _("sh_gpg_popen"));
633 }
634
635 SL_RETURN( (outf), _("sh_gpg_popen"));
636}
637
638
639static int sh_gpg_pclose (sh_gpg_popen_t *source)
640{
641 int status = 0;
642
643 SL_ENTER(_("sh_gpg_pclose"));
644
645 status = fclose(source->pipe);
646 if (status)
647 SL_RETURN( (-1), _("sh_gpg_pclose"));
648
649 if (waitpid(source->pid, NULL, 0) != source->pid)
650 status = -1;
651
652 source->pipe = NULL;
653 source->pid = 0;
654 SL_RETURN( (status), _("sh_gpg_pclose"));
655}
656
657static
658int sh_gpg_check_file_sign(int fd, char * sign_id, char * sign_fp,
659 char * homedir, int whichfile)
660{
661 struct stat buf;
662 char line[256];
663 sh_gpg_popen_t source;
664 int have_id = BAD, have_fp = BAD, status = 0;
665#ifdef WITH_PGP
666 char *ptr;
667#endif
668
669#ifdef HAVE_GPG_CHECKSUM
670 SL_TICKET checkfd;
671#endif
672
673 SL_ENTER(_("sh_gpg_check_file_sign"));
674
675 /* check whether GnuPG exists and has the correct checksum
676 */
677#if defined(WITH_GPG)
678
679 TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
680 TPT(((0), FIL__, __LINE__, _("msg=<gpg is %s>\n"), DEFAULT_GPG_PATH));
681
682 if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_GPG_PATH, &buf))
683 {
[132]684 char errbuf[SH_ERRBUF_SIZE];
685
[1]686 status = errno;
687 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
[132]688 sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_GPG_PATH);
[1]689 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
690 }
691
692 if (0 != tf_trust_check (DEFAULT_GPG_PATH, SL_YESPRIV))
693 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
694
695#ifdef HAVE_GPG_CHECKSUM
[248]696 checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_GPG_PATH, SL_YESPRIV);
[1]697
698 if (0 != sh_gpg_checksum(checkfd, 1))
699 {
700 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
701 _("Checksum mismatch"),
702 _("gpg_check_file_sign"));
703 sl_close(checkfd);
704 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
705 }
706 sl_close(checkfd);
707#endif
708
709#elif defined(WITH_PGP)
710
711 TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
712 TPT(((0), FIL__, __LINE__, _("msg=<pgp is %s>\n"), DEFAULT_PGP_PATH));
713
714 if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_PGP_PATH, &buf))
715 {
[132]716 char errbuf[SH_ERRBUF_SIZE];
717
[1]718 status = errno;
719 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
[132]720 sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_PGP_PATH);
[1]721 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
722 }
723 if (0 != tf_trust_check (DEFAULT_PGP_PATH, SL_YESPRIV))
724 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
725
726#ifdef HAVE_GPG_CHECKSUM
[248]727 checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_PGP_PATH, SL_YESPRIV);
[1]728
729 if (0 != sh_gpg_checksum(checkfd, 1))
730 {
731 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
732 _("Checksum mismatch"),
733 _("gpg_check_file_sign"));
734 sl_close(checkfd);
735 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
736 }
737 sl_close(checkfd);
738#endif
739
740#endif
741
742 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n")));
743
744 fflush(NULL);
745
746 source.pipe = sh_gpg_popen ( &source, fd, 0, NULL, homedir );
747
748 if (NULL == source.pipe)
749 {
750 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
751 _("Could not open pipe"),
752 _("gpg_check_file_sign"));
753 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
754 }
755
756 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
757
758 xagain:
759
760 errno = 0;
761
[34]762 while (NULL != fgets(line, sizeof(line), source.pipe))
[1]763 {
764
765 TPT(((0), FIL__, __LINE__, _("msg=<gpg out: %s>\n"), line));
766 if (line[strlen(line)-1] == '\n')
767 line[strlen(line)-1] = ' ';
768 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
769 line,
770 _("gpg_check_file_sign"));
771
772 if (sl_strlen(line) < 18)
773 continue;
774#if defined(WITH_GPG)
775 /* Sun May 27 18:40:05 CEST 2001
776 */
777 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6) ||
778 0 == sl_strncmp(_("ERRSIG"), &line[9], 6) ||
779 0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6) ||
780 0 == sl_strncmp(_("NODATA"), &line[9], 6) ||
781 0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6))
782 {
783 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6)) {
784 dlog(1, FIL__, __LINE__,
785 _("%s file is signed, but the signature is invalid."),
786 ((whichfile == 1) ? _("Configuration") : _("Database")));
787 }
788 else if (0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6)) {
789 dlog(1, FIL__, __LINE__,
790 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
791 ((whichfile == 1) ? _("Configuration") : _("Database")),
792 homedir);
793 }
794 else if (0 == sl_strncmp(_("ERRSIG"), &line[9], 6)) {
795 dlog(1, FIL__, __LINE__,
796 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
797 ((whichfile == 1) ? _("Configuration") : _("Database")),
798 homedir);
799 }
800 else if (0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) {
801 dlog(1, FIL__, __LINE__,
802 _("%s file is signed, but the public key to verify the signature has expired."),
803 ((whichfile == 1) ? _("Configuration") : _("Database")));
804 }
805 else if (0 == sl_strncmp(_("NODATA"), &line[9], 6)) {
806 dlog(1, FIL__, __LINE__,
807 _("%s file is not signed."),
808 ((whichfile == 1) ? _("Configuration") : _("Database")));
809 }
810
811 have_fp = BAD; have_id = BAD;
812 break;
813 }
814 if (0 == sl_strncmp(_("GOODSIG"), &line[9], 7))
815 {
816 sl_strlcpy (sign_id, &line[25], SH_MINIBUF+1);
817 sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing '"' */
818 have_id = GOOD;
819 }
820 if (0 == sl_strncmp(_("VALIDSIG"), &line[9], 8))
821 {
822 strncpy (sign_fp, &line[18], 40);
823 sign_fp[40] = '\0';
824 have_fp = GOOD;
825 }
826#elif defined(WITH_PGP)
827 if (0 == sl_strncmp(_("Bad signature"), line, 13) ||
828 0 == sl_strncmp(_("Error"), line, 5) ||
829 0 == sl_strncmp(_("Malformed"), line, 9) ||
830 0 == sl_strncmp(_("WARNING"), line, 7) ||
831 0 == sl_strncmp(_("ERROR"), line, 5)
832 )
833 {
834 have_fp = BAD; have_id = BAD;
835 break;
836 }
837 if (0 == sl_strncmp(_("Good signature"), line, 14))
838 {
839 ptr = strchr ( line, '"');
840 ++ptr;
841 sl_strlcpy (sign_id, ptr, SH_MINIBUF+1);
842 sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing dot */
843 sign_id[sl_strlen(sign_id)-2] = '\0'; /* remove trailing '"' */
844 have_id = GOOD;
845 }
846#endif
847 }
848
849 if (ferror(source.pipe) && errno == EAGAIN)
850 {
851 clearerr(source.pipe);
852 goto xagain;
853 }
854
855 sh_gpg_pclose (&source);
856
857 TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n")));
858
859#ifdef WITH_PGP
860 /* get the fingerprint */
861
862 source.pipe = sh_gpg_popen ( &source, fd, 1, sign_id, homedir);
863 if (NULL == source.pipe)
864 {
865 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
866 _("Could not open pipe for fp"),
867 _("gpg_check_file_sign"));
868 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
869 }
870
871 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
872
873 yagain:
874
875 errno = 0;
876
[34]877 while (NULL != fgets(line, sizeof(line), source.pipe))
[1]878 {
[131]879#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
880 char * saveptr = NULL;
881#endif
[1]882 if (line[strlen(line)-1] == '\n')
883 line[strlen(line)-1] = ' ';
884 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
885 line,
886 _("gpg_check_file_sign"));
887
888 if (sl_strlen(line) < 18)
889 continue;
[131]890#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
891 ptr = strtok_r (line, " ", &saveptr);
892#else
[1]893 ptr = strtok (line, " ");
[131]894#endif
[1]895 while (ptr)
896 {
[131]897#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
898 ptr = strtok_r (NULL, " ", &saveptr);
899#else
[1]900 ptr = strtok (NULL, " ");
[131]901#endif
[1]902 if (ptr && 0 == sl_strncmp (ptr, _("fingerprint"), 11))
903 {
[131]904#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
905 ptr = strtok_r (NULL, " ", &saveptr); /* to '=' */
906#else
[1]907 ptr = strtok (NULL, " "); /* to '=' */
[131]908#endif
[1]909 sign_fp[0] = '\0';
910 while (ptr)
911 {
[131]912#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
913 ptr = strtok_r (NULL, " ", &saveptr); /* part of fingerprint */
914#else
[1]915 ptr = strtok (NULL, " "); /* part of fingerprint */
[131]916#endif
[1]917 sl_strlcat (sign_fp, ptr, SH_MINIBUF+1);
918 }
919 /* sign_fp[sl_strlen(sign_fp)-1] = '\0'; remove trailing '\n' */
920 if (sl_strlen(sign_fp) > 0)
921 have_fp = GOOD;
922 break;
923 }
924 }
925 }
926
927 if (ferror(source.pipe) && errno == EAGAIN)
928 {
929 clearerr(source.pipe);
930 goto yagain;
931 }
932
933 sh_gpg_pclose (&source);
934#endif
935
936 if (have_id == GOOD)
937 {
938 TPT(((0), FIL__, __LINE__, _("msg=<Got signator ID>\n")));
939 ;
940 }
941 if (have_fp == GOOD)
942 {
943 TPT(((0), FIL__, __LINE__, _("msg=<Got fingerprint>\n")));
944 ;
945 }
946
947 if (have_id == GOOD && have_fp == GOOD)
948 SL_RETURN( SH_GPG_OK, _("sh_gpg_check_file_sign"));
949 else
950 {
951 if (have_id == BAD)
952 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
953 _("No good signature"),
954 _("gpg_check_file_sign"));
955 else
956 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
957 _("No fingerprint for key"),
958 _("gpg_check_file_sign"));
959 SL_RETURN( SH_GPG_BADSIGN, _("sh_gpg_check_file_sign"));
960 }
961}
962
963int get_the_fd(SL_TICKET file_1);
964
965int sh_gpg_check_sign (long file_1, long file_2, int what)
966{
967 int status = SH_GPG_BAD;
968 int fd1 = 0;
969 int fd2 = 0;
970 static int smsg = S_FALSE;
971 char * tmp;
972 char * tmp2;
973
974 char * homedir = sh.effective.home;
975#if defined(SH_WITH_SERVER)
976 struct passwd * tempres;
[131]977#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
978 struct passwd pwd;
[227]979 char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
[1]980#endif
[131]981#endif
982
[1]983#ifdef USE_FINGERPRINT
984#include "sh_gpg_fp.h"
985#endif
986
987 SL_ENTER(_("sh_gpg_check_sign"));
988
989
990 if (what == 0 || what == 1)
991 fd1 = get_the_fd(file_1);
992 if (what == 0 || what == 2)
993 fd2 = get_the_fd(file_2);
994
995
996 if (fd1 < 0 || fd2 < 0)
997 {
998 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD1 = %d>\n"), fd1));
999 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD2 = %d>\n"), fd2));
1000 dlog(1, FIL__, __LINE__,
1001 _("This looks like an unexpected internal error.\n"));
1002 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1, sh.prg_name);
1003 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
[227]1004#if defined(SH_WITH_SERVER)
1005#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1006 SH_FREE(buffer);
1007#endif
1008#endif
[1]1009 SL_RETURN( (-1), _("sh_gpg_check_sign"));
1010 }
1011
1012 if (what == 0 || what == 1)
1013 {
1014 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD1 = %d>\n"), fd1));
1015#if defined(SH_WITH_SERVER)
[131]1016#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
[227]1017 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
[131]1018#else
[111]1019 tempres = sh_getpwnam(DEFAULT_IDENT);
[131]1020#endif
[111]1021
[1]1022 if ((tempres != NULL) && (0 == sl_ret_euid()))
1023 {
1024 /* privileges not dropped yet*/
1025 homedir = tempres->pw_dir;
1026 }
1027#endif
1028 status = sh_gpg_check_file_sign(fd1, gp.conf_id, gp.conf_fp, homedir, 1);
1029 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGUSR: |%s|>\n"), gp.conf_id));
1030 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGFP: |%s|>\n"), gp.conf_fp));
1031 }
1032
1033 if ((what == 0 && SH_GPG_OK == status) || what == 2)
1034 {
1035 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD2 = %d>\n"), fd2));
1036#if defined(SH_WITH_SERVER)
[131]1037#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
[227]1038 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
[131]1039#else
[111]1040 tempres = sh_getpwnam(DEFAULT_IDENT);
[131]1041#endif
[111]1042
[1]1043 if ((tempres != NULL) && (0 == sl_ret_euid()))
1044 {
1045 /* privileges not dropped yet*/
1046 homedir = tempres->pw_dir;
1047 }
1048#endif
1049 status = sh_gpg_check_file_sign(fd2, gp.data_id, gp.data_fp, homedir, 2);
1050 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGUSR: |%s|>\n"), gp.data_id));
1051 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGFP: |%s|>\n"), gp.data_fp));
1052 }
1053
1054 if (SH_GPG_OK == status && what == 1)
1055 {
1056#ifdef USE_FINGERPRINT
1057 if ((sl_strcmp(SH_GPG_FP, gp.conf_fp) == 0))
1058 {
1059 int i;
1060
1061 for(i = 0; i < (int) sl_strlen(gp.conf_fp); ++i)
1062 {
1063 if (gpgfp[i] != gp.conf_fp[i])
1064 {
1065 sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
1066 MSG_E_GPG_FP,
1067 gpgfp, gp.conf_fp);
1068 break;
1069 }
1070 }
1071
1072 if (smsg == S_FALSE)
1073 {
1074 tmp = sh_util_safe_name(gp.conf_id);
[87]1075 sh_gpg_fill_startup (__LINE__,
[86]1076 /* sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_GH, */
[1]1077 sh.prg_name, sh.real.uid,
1078 (sh.flag.hidefile == S_TRUE) ?
1079 _("(hidden)") : file_path('C', 'R'),
1080 tmp,
1081 gp.conf_fp);
1082 SH_FREE(tmp);
1083 }
1084 smsg = S_TRUE;
[227]1085#if defined(SH_WITH_SERVER)
1086#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1087 SH_FREE(buffer);
1088#endif
1089#endif
[1]1090 SL_RETURN(0, _("sh_gpg_check_sign"));
1091 }
1092 else
1093 {
1094 /* fp mismatch
1095 */
1096 dlog(1, FIL__, __LINE__,
1097 _("The fingerprint of the signing key: %s\ndoes not match the compiled-in fingerprint: %s.\nTherefore the signature could not be verified.\n"),
1098 gp.conf_fp, SH_GPG_FP);
1099 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1100 _("Fingerprint mismatch"),
1101 _("gpg_check_sign"));
1102 status = SH_GPG_BADSIGN;
1103 }
1104#else
1105 if (smsg == S_FALSE)
1106 {
1107 tmp = sh_util_safe_name(gp.conf_id);
[86]1108 sh_gpg_fill_startup (__LINE__,
1109 /* sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_GH, */
[1]1110 sh.prg_name, sh.real.uid,
1111 (sh.flag.hidefile == S_TRUE) ?
1112 _("(hidden)") : file_path('C', 'R'),
1113 tmp,
1114 gp.conf_fp);
1115 SH_FREE(tmp);
1116 }
1117 smsg = S_TRUE;
[227]1118#if defined(SH_WITH_SERVER)
1119#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1120 SH_FREE(buffer);
1121#endif
1122#endif
[1]1123 SL_RETURN(0, _("sh_gpg_check_sign"));
1124#endif
1125 }
1126
1127 else if (SH_GPG_OK == status && (what == 2 || what == 0))
1128 {
1129 if ((sl_strcmp(gp.data_id, gp.conf_id) == 0) &&
1130 (sl_strcmp(gp.data_fp, gp.conf_fp) == 0))
1131 {
[227]1132#if defined(SH_WITH_SERVER)
1133#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1134 SH_FREE(buffer);
1135#endif
1136#endif
[1]1137 SL_RETURN(0, _("sh_gpg_check_sign"));
1138 }
1139 else
1140 {
1141 /* ID or fp not equal
1142 */
1143 dlog(1, FIL__, __LINE__,
1144 _("The fingerprint or ID of the signing key is not the same for the\nconfiguration file and the file signature database.\nTherefore the signature could not be verified.\n"));
1145 tmp = sh_util_safe_name (gp.conf_id);
1146 tmp2 = sh_util_safe_name (gp.data_id);
1147 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_GH2,
1148 sh.prg_name, sh.real.uid,
1149 (sh.flag.hidefile == S_TRUE) ? _("(hidden)") : file_path('C', 'R'),
1150 tmp, gp.conf_fp,
1151 (sh.flag.hidefile == S_TRUE) ? _("(hidden)") : file_path('D', 'R'),
1152 tmp2, gp.data_fp);
1153 SH_FREE(tmp);
1154 SH_FREE(tmp2);
1155 }
1156 }
1157
1158 if (status != SH_GPG_OK)
1159 {
1160 uid_t e_uid = sl_ret_euid();
1161 char * e_home = sh.effective.home;
1162
1163#if defined(SH_WITH_SERVER)
[131]1164#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1165 struct passwd e_pwd;
[227]1166 char * e_buffer = SH_ALLOC(SH_PWBUF_SIZE);
[131]1167 struct passwd * e_tempres;
[227]1168 sh_getpwnam_r(DEFAULT_IDENT, &e_pwd, e_buffer, SH_PWBUF_SIZE, &e_tempres);
[131]1169#else
[111]1170 struct passwd * e_tempres = sh_getpwnam(DEFAULT_IDENT);
[131]1171#endif
[111]1172
[1]1173 if ((e_tempres != NULL) && (0 == sl_ret_euid()))
1174 {
1175 /* privileges not dropped yet */
1176 e_uid = e_tempres->pw_uid;
1177 e_home = e_tempres->pw_dir;
1178 }
1179#endif
1180 dlog(1, FIL__, __LINE__,
1181 _("The signature of the configuration file or the file signature database\ncould not be verified. Possible reasons are:\n - gpg binary (%s) not found\n - invalid signature\n - the signature key is not in the private keyring of UID %d,\n - there is no keyring in %s/.gnupg, or\n - the file is not signed - did you move /filename.asc to /filename ?\nTo create a signed file, use (remove old signatures before):\n gpg -a --clearsign --not-dash-escaped FILE\n mv FILE.asc FILE\n"),
1182#if defined(WITH_GPG)
1183 DEFAULT_GPG_PATH,
1184#else
1185 DEFAULT_PGP_PATH,
1186#endif
1187 (int) e_uid, e_home);
[227]1188
1189#if defined(SH_WITH_SERVER)
1190#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1191 SH_FREE(e_buffer);
1192#endif
1193#endif
[1]1194 }
1195
1196 TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status));
1197
1198 sh_error_handle((-1), FIL__, __LINE__, status, MSG_EXIT_ABORT1, sh.prg_name);
1199 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1200
1201 return (-1); /* make compiler happy */
1202}
1203
1204/* #ifdef WITH_GPG */
1205#endif
1206
1207
1208
1209
1210
1211
1212
1213
Note: See TracBrowser for help on using the repository browser.