source: trunk/src/sh_gpg.c@ 1

Last change on this file since 1 was 1, checked in by katerina, 19 years ago

Initial import

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