source: trunk/src/sh_gpg.c@ 136

Last change on this file since 136 was 133, checked in by rainer, 17 years ago

Reentrant checksum/hash functions.

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