source: trunk/src/sh_gpg.c@ 322

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

Add code to check for stale file records on close() and fclose(), fix sl_close() to handle open stream (ticket #163).

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