source: trunk/src/sh_gpg.c@ 247

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

Fix a race condition that might have caused ticket #163.

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