source: branches/samhain-2_2-branch/src/sh_gpg.c@ 502

Last change on this file since 502 was 34, checked in by rainer, 19 years ago

Code cleanup and minor fixes

File size: 29.0 KB
Line 
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
117static int sh_gpg_checksum (SL_TICKET checkfd, int flag)
118{
119 char * test_gpg;
120 char * test_ptr1 = NULL;
121 char * test_ptr2 = NULL;
122 char wstrip1[128];
123 char wstrip2[128];
124 int i, k;
125#include "sh_gpg_chksum.h"
126
127 SL_ENTER(_("sh_gpg_checksum"));
128
129 tiger_fd = checkfd;
130#if defined(WITH_PGP)
131 test_gpg = sh_tiger_hash_gpg (DEFAULT_PGP_PATH, TIGER_FD, 0);
132#else
133 test_gpg = sh_tiger_hash_gpg (DEFAULT_GPG_PATH, TIGER_FD, 0);
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
205static FILE * sh_gpg_popen (sh_gpg_popen_t *source, int fd,
206 int mode, char * id, char * homedir)
207{
208 int pipedes[2];
209 FILE * outf = NULL;
210 char * envp[2];
211 size_t len;
212 char path[256];
213 char cc1[32];
214 char cc2[32];
215#if defined(WITH_PGP)
216 char cc3[32];
217 char cc0[3] = "-f";
218#endif
219#if defined(WITH_GPG)
220 char cc0[2] = "-";
221 char cc3[32];
222 char cc4[SH_PATHBUF+32];
223 char cc5[32] = "--no-tty";
224#endif
225
226 char * arg[9];
227
228#if defined(HAVE_GPG_CHECKSUM)
229 SL_TICKET checkfd;
230 int myrand;
231 int i;
232#if defined(__linux__)
233 int get_the_fd(SL_TICKET);
234 char pname[128];
235 int pfd;
236#endif
237#endif
238
239 SL_ENTER(_("sh_gpg_popen"));
240
241#if defined(WITH_GPG)
242 /* -- GnuPG -- */
243 sl_strlcpy (path, DEFAULT_GPG_PATH, 256);
244 sl_strlcpy (cc1, _("--status-fd"), 32);
245 sl_strlcpy (cc2, _("--verify"), 32);
246 sl_strlcpy (cc3, _("--homedir"), 32);
247 /* sl_strlcpy (cc4, sh.effective.home, SH_PATHBUF+32); */
248 sl_strlcpy (cc4, homedir, SH_PATHBUF+32);
249 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
250
251 /* fprintf(stderr, "YULE: homedir=%s\n", homedir); */
252
253#if defined(SH_WITH_SERVER)
254 if (0 == sl_ret_euid()) /* privileges not dropped yet */
255 {
256 struct stat lbuf;
257 int status_stat = 0;
258 struct passwd * tempres = getpwnam(DEFAULT_IDENT);
259 if (!tempres)
260 tempres = sh_getpwnam(DEFAULT_IDENT);
261 if (!tempres)
262 {
263 dlog(1, FIL__, __LINE__,
264 _("User %s does not exist. Please add the user to your system.\n"),
265 DEFAULT_IDENT);
266 status_stat = -1;
267 }
268 if (!tempres->pw_dir || tempres->pw_dir[0] == '\0')
269 {
270 dlog(1, FIL__, __LINE__,
271 _("User %s does not have a home directory.\nPlease add the home directory for this user to your system.\n"),
272 DEFAULT_IDENT);
273 status_stat = -2;
274 }
275 if (status_stat == 0)
276 {
277 sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
278 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
279 status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf);
280 if (status_stat == -1)
281 {
282 dlog(1, FIL__, __LINE__,
283 _("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"),
284 cc4, DEFAULT_IDENT);
285 status_stat = -3;
286 }
287 }
288 if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
289 {
290 dlog(1, FIL__, __LINE__,
291 _("Gnupg directory %s\nis not owned by user %s.\n"),
292 cc4, DEFAULT_IDENT);
293 status_stat = -4;
294 }
295 if (status_stat == 0)
296 {
297 sl_strlcat (cc4, _("/pubring.gpg"), SH_PATHBUF+32);
298 status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf);
299 if (status_stat == -1)
300 {
301 dlog(1, FIL__, __LINE__,
302 _("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"),
303 cc4, DEFAULT_IDENT);
304 status_stat = -5;
305 }
306 }
307 if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
308 {
309 dlog(1, FIL__, __LINE__,
310 _("Gnupg public keyring %s\nis not owned by user %s.\n"),
311 cc4, DEFAULT_IDENT);
312 status_stat = -6;
313 }
314 if (status_stat != 0)
315 {
316 sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1,
317 sh.prg_name);
318 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
319 }
320 sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
321 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
322 }
323#endif
324
325 arg[0] = path;
326 arg[1] = cc1;
327 arg[2] = "1";
328 arg[3] = cc2;
329 arg[4] = cc3;
330 arg[5] = cc4;
331 arg[6] = cc5;
332 arg[7] = cc0;
333 arg[8] = NULL;
334
335 /* catch 'unused parameter' compiler warning
336 */
337 (void) mode;
338 (void) id;
339#elif defined(WITH_PGP)
340 /* -- PGP -- */
341 sl_strlcpy (path, DEFAULT_PGP_PATH, 256);
342 if (mode == 0)
343 {
344 sl_strlcpy (cc1, _("+language=en"), 32);
345 sl_strlcpy (cc2, _("-o"), 32);
346 sl_strlcpy (cc3, _("/dev/null"), 32);
347
348 arg[0] = path;
349 arg[1] = cc1;
350 arg[2] = cc2;
351 arg[3] = cc3;
352 arg[4] = cc0;
353 arg[5] = NULL;
354 }
355 else
356 {
357 sl_strlcpy (cc1, _("+language=en"), 32);
358 sl_strlcpy (cc2, _("-kvc"), 32);
359
360 arg[0] = path;
361 arg[1] = cc1;
362 arg[2] = cc2;
363 arg[3] = id;
364 arg[4] = NULL;
365 arg[5] = NULL;
366 }
367#endif
368
369 /* use homedir of effective user
370 */
371 if (sh.effective.home != NULL)
372 {
373 len = sl_strlen(sh.effective.home) + 6;
374 envp[0] = malloc (len); /* free() ok */
375 if (envp[0] != NULL)
376 sl_snprintf (envp[0], len, "HOME=%s", sh.effective.home);
377 envp[1] = NULL;
378 }
379 else
380 {
381 envp[0] = NULL;
382 }
383
384 /* Create the pipe
385 */
386 if (aud_pipe(FIL__, __LINE__, pipedes) < 0)
387 {
388 if (envp[0] != NULL)
389 free(envp[0]);
390 SL_RETURN( (NULL), _("sh_gpg_popen"));
391 }
392
393 source->pid = aud_fork(FIL__, __LINE__);
394
395 /* Failure
396 */
397 if (source->pid == (pid_t) - 1)
398 {
399 close(pipedes[0]);
400 close(pipedes[1]);
401 if (envp[0] != NULL)
402 free(envp[0]);
403 SL_RETURN( (NULL), _("sh_gpg_popen"));
404 }
405
406 if (source->pid == (pid_t) 0)
407 {
408
409 /* child - make read side of the pipe stdout
410 */
411 if (retry_aud_dup2(FIL__, __LINE__,
412 pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0)
413 {
414 TPT(((0), FIL__, __LINE__, _("msg=<dup2 on pipe failed>\n")));
415 dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
416 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
417 }
418
419 /* close the pipe descriptors
420 */
421 close (pipedes[STDIN_FILENO]);
422 close (pipedes[STDOUT_FILENO]);
423
424
425#if defined(WITH_PGP)
426 if (mode == 0)
427 {
428 if (retry_aud_dup2(FIL__, __LINE__, fd, STDIN_FILENO) < 0)
429 {
430 TPT(((0), FIL__, __LINE__, _("msg=<dup2 on fd failed>\n")));
431 dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
432 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
433 }
434 }
435#else
436 if (retry_aud_dup2(FIL__, __LINE__, fd, STDIN_FILENO) < 0)
437 {
438 TPT(((0), FIL__, __LINE__, _("msg=<dup2 on fd failed>\n")));
439 dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
440 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
441 }
442#endif
443
444 /* don't leak file descriptors
445 */
446 sh_unix_closeall (3, -1); /* in child process */
447
448 freopen(_("/dev/null"), "r+", stderr);
449
450 /* We should become privileged if SUID,
451 * to be able to read the keyring.
452 * We have checked that gpg is OK,
453 * AND that only a trusted user could overwrite
454 * gpg.
455 */
456 memset (skey, '\0', sizeof(sh_key_t));
457 aud_setuid(FIL__, __LINE__, geteuid());
458
459 PDBGC_OPEN;
460 PDBGC_D((int)getuid());
461 PDBGC_D((int)geteuid());
462
463 {
464 int i = 0;
465 while (arg[i] != NULL)
466 {
467 PDBGC_S(arg[i]);
468 ++i;
469 }
470 }
471 PDBGC_CLOSE;
472
473 /* exec the program */
474
475#if defined(__linux__) && defined(HAVE_GPG_CHECKSUM)
476 /*
477 * -- emulate an fexecve with checksum testing
478 */
479#if defined(WITH_PGP)
480 checkfd = sl_open_read(DEFAULT_PGP_PATH, SL_NOPRIV);
481#else
482 checkfd = sl_open_read(DEFAULT_GPG_PATH, SL_NOPRIV);
483#endif
484
485 if (0 != sh_gpg_checksum(checkfd, 0))
486 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
487
488 pfd = get_the_fd(checkfd);
489 sl_snprintf(pname, sizeof(pname), _("/proc/self/fd/%d"), pfd);
490 if (0 == access(pname, R_OK|X_OK)) /* flawfinder: ignore */
491
492 {
493 fcntl (pfd, F_SETFD, FD_CLOEXEC);
494 retry_aud_execve (FIL__, __LINE__, pname, arg, envp);
495
496 dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"),
497 pname);
498 /* failed
499 */
500 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
501 }
502
503 /* procfs not working, go ahead
504 */
505 sl_close(checkfd);
506#endif
507
508#if defined(HAVE_GPG_CHECKSUM)
509 /* This is an incredibly ugly kludge to prevent an attacker
510 * from knowing when it is safe to slip in a fake executable
511 * between the integrity check and the execve
512 */
513 myrand = (int) taus_get (&(skey->rng0[0]), &(skey->rng1[0]),
514 &(skey->rng2[0]));
515 myrand = (myrand < 0) ? (-myrand) : myrand;
516 myrand = (myrand % 32) + 2;
517
518 for (i = 0; i < myrand; ++i)
519 {
520#if defined(WITH_PGP)
521 checkfd = sl_open_fastread(DEFAULT_PGP_PATH, SL_NOPRIV);
522#else
523 checkfd = sl_open_fastread(DEFAULT_GPG_PATH, SL_NOPRIV);
524#endif
525 if (0 != sh_gpg_checksum(checkfd, 0)) {
526 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
527 }
528 sl_close(checkfd);
529 }
530#endif
531
532
533#if defined(WITH_GPG)
534 retry_aud_execve (FIL__, __LINE__, DEFAULT_GPG_PATH, arg, envp);
535 dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"),
536 DEFAULT_GPG_PATH);
537#elif defined(WITH_PGP)
538 retry_aud_execve (FIL__, __LINE__, DEFAULT_PGP_PATH, arg, envp);
539#endif
540
541 /* failed
542 */
543 TPT(((0), FIL__, __LINE__, _("msg=<execve failed>\n")));
544 dlog(1, FIL__, __LINE__, _("Unexpected error: execve failed\n"));
545 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
546 }
547
548 /* parent
549 */
550
551 if (envp[0] != NULL)
552 free(envp[0]);
553
554 close (pipedes[STDOUT_FILENO]);
555 retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
556 retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFL, O_NONBLOCK);
557
558 outf = fdopen (pipedes[STDIN_FILENO], "r");
559
560 if (outf == NULL)
561 {
562 aud_kill (FIL__, __LINE__, source->pid, SIGKILL);
563 close (pipedes[STDOUT_FILENO]);
564 waitpid (source->pid, NULL, 0);
565 source->pid = 0;
566 SL_RETURN( (NULL), _("sh_gpg_popen"));
567 }
568
569 SL_RETURN( (outf), _("sh_gpg_popen"));
570}
571
572
573static int sh_gpg_pclose (sh_gpg_popen_t *source)
574{
575 int status = 0;
576
577 SL_ENTER(_("sh_gpg_pclose"));
578
579 status = fclose(source->pipe);
580 if (status)
581 SL_RETURN( (-1), _("sh_gpg_pclose"));
582
583 if (waitpid(source->pid, NULL, 0) != source->pid)
584 status = -1;
585
586 source->pipe = NULL;
587 source->pid = 0;
588 SL_RETURN( (status), _("sh_gpg_pclose"));
589}
590
591static
592int sh_gpg_check_file_sign(int fd, char * sign_id, char * sign_fp,
593 char * homedir, int whichfile)
594{
595 struct stat buf;
596 char line[256];
597 sh_gpg_popen_t source;
598 int have_id = BAD, have_fp = BAD, status = 0;
599#ifdef WITH_PGP
600 char *ptr;
601#endif
602
603#ifdef HAVE_GPG_CHECKSUM
604 SL_TICKET checkfd;
605#endif
606
607 SL_ENTER(_("sh_gpg_check_file_sign"));
608
609 /* check whether GnuPG exists and has the correct checksum
610 */
611#if defined(WITH_GPG)
612
613 TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
614 TPT(((0), FIL__, __LINE__, _("msg=<gpg is %s>\n"), DEFAULT_GPG_PATH));
615
616 if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_GPG_PATH, &buf))
617 {
618 status = errno;
619 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
620 sh_error_message(status), DEFAULT_GPG_PATH);
621 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
622 }
623
624 if (0 != tf_trust_check (DEFAULT_GPG_PATH, SL_YESPRIV))
625 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
626
627#ifdef HAVE_GPG_CHECKSUM
628 checkfd = sl_open_read(DEFAULT_GPG_PATH, SL_YESPRIV);
629
630 if (0 != sh_gpg_checksum(checkfd, 1))
631 {
632 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
633 _("Checksum mismatch"),
634 _("gpg_check_file_sign"));
635 sl_close(checkfd);
636 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
637 }
638 sl_close(checkfd);
639#endif
640
641#elif defined(WITH_PGP)
642
643 TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
644 TPT(((0), FIL__, __LINE__, _("msg=<pgp is %s>\n"), DEFAULT_PGP_PATH));
645
646 if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_PGP_PATH, &buf))
647 {
648 status = errno;
649 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
650 sh_error_message(status), DEFAULT_PGP_PATH);
651 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
652 }
653 if (0 != tf_trust_check (DEFAULT_PGP_PATH, SL_YESPRIV))
654 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
655
656#ifdef HAVE_GPG_CHECKSUM
657 checkfd = sl_open_read(DEFAULT_PGP_PATH, SL_YESPRIV);
658
659 if (0 != sh_gpg_checksum(checkfd, 1))
660 {
661 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
662 _("Checksum mismatch"),
663 _("gpg_check_file_sign"));
664 sl_close(checkfd);
665 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
666 }
667 sl_close(checkfd);
668#endif
669
670#endif
671
672 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n")));
673
674 fflush(NULL);
675
676 source.pipe = sh_gpg_popen ( &source, fd, 0, NULL, homedir );
677
678 if (NULL == source.pipe)
679 {
680 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
681 _("Could not open pipe"),
682 _("gpg_check_file_sign"));
683 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
684 }
685
686 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
687
688 xagain:
689
690 errno = 0;
691
692 while (NULL != fgets(line, sizeof(line), source.pipe))
693 {
694
695 TPT(((0), FIL__, __LINE__, _("msg=<gpg out: %s>\n"), line));
696 if (line[strlen(line)-1] == '\n')
697 line[strlen(line)-1] = ' ';
698 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
699 line,
700 _("gpg_check_file_sign"));
701
702 if (sl_strlen(line) < 18)
703 continue;
704#if defined(WITH_GPG)
705 /* Sun May 27 18:40:05 CEST 2001
706 */
707 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6) ||
708 0 == sl_strncmp(_("ERRSIG"), &line[9], 6) ||
709 0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6) ||
710 0 == sl_strncmp(_("NODATA"), &line[9], 6) ||
711 0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6))
712 {
713 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6)) {
714 dlog(1, FIL__, __LINE__,
715 _("%s file is signed, but the signature is invalid."),
716 ((whichfile == 1) ? _("Configuration") : _("Database")));
717 }
718 else if (0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6)) {
719 dlog(1, FIL__, __LINE__,
720 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
721 ((whichfile == 1) ? _("Configuration") : _("Database")),
722 homedir);
723 }
724 else if (0 == sl_strncmp(_("ERRSIG"), &line[9], 6)) {
725 dlog(1, FIL__, __LINE__,
726 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
727 ((whichfile == 1) ? _("Configuration") : _("Database")),
728 homedir);
729 }
730 else if (0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) {
731 dlog(1, FIL__, __LINE__,
732 _("%s file is signed, but the public key to verify the signature has expired."),
733 ((whichfile == 1) ? _("Configuration") : _("Database")));
734 }
735 else if (0 == sl_strncmp(_("NODATA"), &line[9], 6)) {
736 dlog(1, FIL__, __LINE__,
737 _("%s file is not signed."),
738 ((whichfile == 1) ? _("Configuration") : _("Database")));
739 }
740
741 have_fp = BAD; have_id = BAD;
742 break;
743 }
744 if (0 == sl_strncmp(_("GOODSIG"), &line[9], 7))
745 {
746 sl_strlcpy (sign_id, &line[25], SH_MINIBUF+1);
747 sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing '"' */
748 have_id = GOOD;
749 }
750 if (0 == sl_strncmp(_("VALIDSIG"), &line[9], 8))
751 {
752 strncpy (sign_fp, &line[18], 40);
753 sign_fp[40] = '\0';
754 have_fp = GOOD;
755 }
756#elif defined(WITH_PGP)
757 if (0 == sl_strncmp(_("Bad signature"), line, 13) ||
758 0 == sl_strncmp(_("Error"), line, 5) ||
759 0 == sl_strncmp(_("Malformed"), line, 9) ||
760 0 == sl_strncmp(_("WARNING"), line, 7) ||
761 0 == sl_strncmp(_("ERROR"), line, 5)
762 )
763 {
764 have_fp = BAD; have_id = BAD;
765 break;
766 }
767 if (0 == sl_strncmp(_("Good signature"), line, 14))
768 {
769 ptr = strchr ( line, '"');
770 ++ptr;
771 sl_strlcpy (sign_id, ptr, SH_MINIBUF+1);
772 sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing dot */
773 sign_id[sl_strlen(sign_id)-2] = '\0'; /* remove trailing '"' */
774 have_id = GOOD;
775 }
776#endif
777 }
778
779 if (ferror(source.pipe) && errno == EAGAIN)
780 {
781 clearerr(source.pipe);
782 goto xagain;
783 }
784
785 sh_gpg_pclose (&source);
786
787 TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n")));
788
789#ifdef WITH_PGP
790 /* get the fingerprint */
791
792 source.pipe = sh_gpg_popen ( &source, fd, 1, sign_id, homedir);
793 if (NULL == source.pipe)
794 {
795 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
796 _("Could not open pipe for fp"),
797 _("gpg_check_file_sign"));
798 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
799 }
800
801 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
802
803 yagain:
804
805 errno = 0;
806
807 while (NULL != fgets(line, sizeof(line), source.pipe))
808 {
809 if (line[strlen(line)-1] == '\n')
810 line[strlen(line)-1] = ' ';
811 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
812 line,
813 _("gpg_check_file_sign"));
814
815 if (sl_strlen(line) < 18)
816 continue;
817 ptr = strtok (line, " ");
818 while (ptr)
819 {
820 ptr = strtok (NULL, " ");
821 if (ptr && 0 == sl_strncmp (ptr, _("fingerprint"), 11))
822 {
823 ptr = strtok (NULL, " "); /* to '=' */
824 sign_fp[0] = '\0';
825 while (ptr)
826 {
827 ptr = strtok (NULL, " "); /* part of fingerprint */
828 sl_strlcat (sign_fp, ptr, SH_MINIBUF+1);
829 }
830 /* sign_fp[sl_strlen(sign_fp)-1] = '\0'; remove trailing '\n' */
831 if (sl_strlen(sign_fp) > 0)
832 have_fp = GOOD;
833 break;
834 }
835 }
836 }
837
838 if (ferror(source.pipe) && errno == EAGAIN)
839 {
840 clearerr(source.pipe);
841 goto yagain;
842 }
843
844 sh_gpg_pclose (&source);
845#endif
846
847 if (have_id == GOOD)
848 {
849 TPT(((0), FIL__, __LINE__, _("msg=<Got signator ID>\n")));
850 ;
851 }
852 if (have_fp == GOOD)
853 {
854 TPT(((0), FIL__, __LINE__, _("msg=<Got fingerprint>\n")));
855 ;
856 }
857
858 if (have_id == GOOD && have_fp == GOOD)
859 SL_RETURN( SH_GPG_OK, _("sh_gpg_check_file_sign"));
860 else
861 {
862 if (have_id == BAD)
863 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
864 _("No good signature"),
865 _("gpg_check_file_sign"));
866 else
867 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
868 _("No fingerprint for key"),
869 _("gpg_check_file_sign"));
870 SL_RETURN( SH_GPG_BADSIGN, _("sh_gpg_check_file_sign"));
871 }
872}
873
874int get_the_fd(SL_TICKET file_1);
875
876int sh_gpg_check_sign (long file_1, long file_2, int what)
877{
878 int status = SH_GPG_BAD;
879 int fd1 = 0;
880 int fd2 = 0;
881 static int smsg = S_FALSE;
882 char * tmp;
883 char * tmp2;
884
885 char * homedir = sh.effective.home;
886#if defined(SH_WITH_SERVER)
887 struct passwd * tempres;
888#endif
889#ifdef USE_FINGERPRINT
890#include "sh_gpg_fp.h"
891#endif
892
893 SL_ENTER(_("sh_gpg_check_sign"));
894
895
896 if (what == 0 || what == 1)
897 fd1 = get_the_fd(file_1);
898 if (what == 0 || what == 2)
899 fd2 = get_the_fd(file_2);
900
901
902 if (fd1 < 0 || fd2 < 0)
903 {
904 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD1 = %d>\n"), fd1));
905 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD2 = %d>\n"), fd2));
906 dlog(1, FIL__, __LINE__,
907 _("This looks like an unexpected internal error.\n"));
908 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1, sh.prg_name);
909 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
910 SL_RETURN( (-1), _("sh_gpg_check_sign"));
911 }
912
913 if (what == 0 || what == 1)
914 {
915 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD1 = %d>\n"), fd1));
916#if defined(SH_WITH_SERVER)
917 tempres = getpwnam(DEFAULT_IDENT);
918 if (!tempres)
919 tempres = sh_getpwnam(DEFAULT_IDENT);
920 if ((tempres != NULL) && (0 == sl_ret_euid()))
921 {
922 /* privileges not dropped yet*/
923 homedir = tempres->pw_dir;
924 }
925#endif
926 status = sh_gpg_check_file_sign(fd1, gp.conf_id, gp.conf_fp, homedir, 1);
927 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGUSR: |%s|>\n"), gp.conf_id));
928 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGFP: |%s|>\n"), gp.conf_fp));
929 }
930
931 if ((what == 0 && SH_GPG_OK == status) || what == 2)
932 {
933 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD2 = %d>\n"), fd2));
934#if defined(SH_WITH_SERVER)
935 tempres = getpwnam(DEFAULT_IDENT);
936 if (!tempres)
937 tempres = sh_getpwnam(DEFAULT_IDENT);
938 if ((tempres != NULL) && (0 == sl_ret_euid()))
939 {
940 /* privileges not dropped yet*/
941 homedir = tempres->pw_dir;
942 }
943#endif
944 status = sh_gpg_check_file_sign(fd2, gp.data_id, gp.data_fp, homedir, 2);
945 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGUSR: |%s|>\n"), gp.data_id));
946 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGFP: |%s|>\n"), gp.data_fp));
947 }
948
949 if (SH_GPG_OK == status && what == 1)
950 {
951#ifdef USE_FINGERPRINT
952 if ((sl_strcmp(SH_GPG_FP, gp.conf_fp) == 0))
953 {
954 int i;
955
956 for(i = 0; i < (int) sl_strlen(gp.conf_fp); ++i)
957 {
958 if (gpgfp[i] != gp.conf_fp[i])
959 {
960 sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
961 MSG_E_GPG_FP,
962 gpgfp, gp.conf_fp);
963 break;
964 }
965 }
966
967 if (smsg == S_FALSE)
968 {
969 tmp = sh_util_safe_name(gp.conf_id);
970 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_GH,
971 sh.prg_name, sh.real.uid,
972 (sh.flag.hidefile == S_TRUE) ?
973 _("(hidden)") : file_path('C', 'R'),
974 tmp,
975 gp.conf_fp);
976 SH_FREE(tmp);
977 }
978 smsg = S_TRUE;
979 SL_RETURN(0, _("sh_gpg_check_sign"));
980 }
981 else
982 {
983 /* fp mismatch
984 */
985 dlog(1, FIL__, __LINE__,
986 _("The fingerprint of the signing key: %s\ndoes not match the compiled-in fingerprint: %s.\nTherefore the signature could not be verified.\n"),
987 gp.conf_fp, SH_GPG_FP);
988 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
989 _("Fingerprint mismatch"),
990 _("gpg_check_sign"));
991 status = SH_GPG_BADSIGN;
992 }
993#else
994 if (smsg == S_FALSE)
995 {
996 tmp = sh_util_safe_name(gp.conf_id);
997 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_GH,
998 sh.prg_name, sh.real.uid,
999 (sh.flag.hidefile == S_TRUE) ?
1000 _("(hidden)") : file_path('C', 'R'),
1001 tmp,
1002 gp.conf_fp);
1003 SH_FREE(tmp);
1004 }
1005 smsg = S_TRUE;
1006 SL_RETURN(0, _("sh_gpg_check_sign"));
1007#endif
1008 }
1009
1010 else if (SH_GPG_OK == status && (what == 2 || what == 0))
1011 {
1012 if ((sl_strcmp(gp.data_id, gp.conf_id) == 0) &&
1013 (sl_strcmp(gp.data_fp, gp.conf_fp) == 0))
1014 {
1015 SL_RETURN(0, _("sh_gpg_check_sign"));
1016 }
1017 else
1018 {
1019 /* ID or fp not equal
1020 */
1021 dlog(1, FIL__, __LINE__,
1022 _("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"));
1023 tmp = sh_util_safe_name (gp.conf_id);
1024 tmp2 = sh_util_safe_name (gp.data_id);
1025 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_GH2,
1026 sh.prg_name, sh.real.uid,
1027 (sh.flag.hidefile == S_TRUE) ? _("(hidden)") : file_path('C', 'R'),
1028 tmp, gp.conf_fp,
1029 (sh.flag.hidefile == S_TRUE) ? _("(hidden)") : file_path('D', 'R'),
1030 tmp2, gp.data_fp);
1031 SH_FREE(tmp);
1032 SH_FREE(tmp2);
1033 }
1034 }
1035
1036 if (status != SH_GPG_OK)
1037 {
1038 uid_t e_uid = sl_ret_euid();
1039 char * e_home = sh.effective.home;
1040
1041#if defined(SH_WITH_SERVER)
1042 struct passwd * e_tempres = getpwnam(DEFAULT_IDENT);
1043 if (!e_tempres)
1044 e_tempres = sh_getpwnam(DEFAULT_IDENT);
1045 if ((e_tempres != NULL) && (0 == sl_ret_euid()))
1046 {
1047 /* privileges not dropped yet */
1048 e_uid = e_tempres->pw_uid;
1049 e_home = e_tempres->pw_dir;
1050 }
1051#endif
1052 dlog(1, FIL__, __LINE__,
1053 _("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"),
1054#if defined(WITH_GPG)
1055 DEFAULT_GPG_PATH,
1056#else
1057 DEFAULT_PGP_PATH,
1058#endif
1059 (int) e_uid, e_home);
1060 }
1061
1062 TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status));
1063
1064 sh_error_handle((-1), FIL__, __LINE__, status, MSG_EXIT_ABORT1, sh.prg_name);
1065 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1066
1067 return (-1); /* make compiler happy */
1068}
1069
1070/* #ifdef WITH_GPG */
1071#endif
1072
1073
1074
1075
1076
1077
1078
1079
Note: See TracBrowser for help on using the repository browser.