source: trunk/src/sh_gpg.c@ 241

Last change on this file since 241 was 227, checked in by katerina, 16 years ago

Fix warnings with -fstack-check

File size: 32.8 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)
[159]131 test_gpg = sh_tiger_hash_gpg (DEFAULT_PGP_PATH, checkfd, TIGER_NOLIM);
[1]132#else
[159]133 test_gpg = sh_tiger_hash_gpg (DEFAULT_GPG_PATH, checkfd, TIGER_NOLIM);
[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
[170]216void sh_gpg_log_startup (void)
[86]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{
[198]243 extern int flag_err_debug;
[1]244 int pipedes[2];
245 FILE * outf = NULL;
246 char * envp[2];
[22]247 size_t len;
[1]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];
[203]259 char cc5[32];
[1]260#endif
261
262 char * arg[9];
263
264#if defined(HAVE_GPG_CHECKSUM)
265 SL_TICKET checkfd;
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);
[203]285 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
286 sl_strlcpy (cc5, _("--no-tty"), 32);
[1]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;
[131]295#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
296 struct passwd pwd;
[227]297 char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
[131]298 struct passwd * tempres;
[227]299 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
[131]300#else
[111]301 struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
[131]302#endif
[111]303
[1]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);
[227]365#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
366 SH_FREE(buffer);
367#endif
[1]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 {
[22]419 len = sl_strlen(sh.effective.home) + 6;
420 envp[0] = malloc (len); /* free() ok */
[1]421 if (envp[0] != NULL)
[203]422 sl_snprintf (envp[0], len, _("HOME=%s"), sh.effective.home);
[1]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 }
[102]438
439 fflush (NULL);
[1]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 */
[174]494 sh_unix_closeall (3, -1, SL_TRUE); /* in child process */
[1]495
[198]496 if (flag_err_debug != SL_TRUE)
[153]497 {
[198]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 }
[153]503 }
[1]504
[198]505
[1]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);
[22]545 sl_snprintf(pname, sizeof(pname), _("/proc/self/fd/%d"), pfd);
546 if (0 == access(pname, R_OK|X_OK)) /* flawfinder: ignore */
547
[1]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#endif
563
564#if defined(HAVE_GPG_CHECKSUM)
565 /* This is an incredibly ugly kludge to prevent an attacker
566 * from knowing when it is safe to slip in a fake executable
567 * between the integrity check and the execve
568 */
[137]569 myrand = (int) taus_get ();
570
[1]571 myrand = (myrand < 0) ? (-myrand) : myrand;
572 myrand = (myrand % 32) + 2;
573
574 for (i = 0; i < myrand; ++i)
575 {
576#if defined(WITH_PGP)
577 checkfd = sl_open_fastread(DEFAULT_PGP_PATH, SL_NOPRIV);
578#else
579 checkfd = sl_open_fastread(DEFAULT_GPG_PATH, SL_NOPRIV);
580#endif
581 if (0 != sh_gpg_checksum(checkfd, 0)) {
582 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
583 }
584 sl_close(checkfd);
585 }
586#endif
587
588
589#if defined(WITH_GPG)
590 retry_aud_execve (FIL__, __LINE__, DEFAULT_GPG_PATH, arg, envp);
591 dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"),
592 DEFAULT_GPG_PATH);
593#elif defined(WITH_PGP)
594 retry_aud_execve (FIL__, __LINE__, DEFAULT_PGP_PATH, arg, envp);
595#endif
596
597 /* failed
598 */
599 TPT(((0), FIL__, __LINE__, _("msg=<execve failed>\n")));
600 dlog(1, FIL__, __LINE__, _("Unexpected error: execve failed\n"));
601 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
602 }
603
604 /* parent
605 */
606
607 if (envp[0] != NULL)
608 free(envp[0]);
609
610 close (pipedes[STDOUT_FILENO]);
611 retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
612 retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFL, O_NONBLOCK);
613
614 outf = fdopen (pipedes[STDIN_FILENO], "r");
615
616 if (outf == NULL)
617 {
618 aud_kill (FIL__, __LINE__, source->pid, SIGKILL);
619 close (pipedes[STDOUT_FILENO]);
620 waitpid (source->pid, NULL, 0);
621 source->pid = 0;
622 SL_RETURN( (NULL), _("sh_gpg_popen"));
623 }
624
625 SL_RETURN( (outf), _("sh_gpg_popen"));
626}
627
628
629static int sh_gpg_pclose (sh_gpg_popen_t *source)
630{
631 int status = 0;
632
633 SL_ENTER(_("sh_gpg_pclose"));
634
635 status = fclose(source->pipe);
636 if (status)
637 SL_RETURN( (-1), _("sh_gpg_pclose"));
638
639 if (waitpid(source->pid, NULL, 0) != source->pid)
640 status = -1;
641
642 source->pipe = NULL;
643 source->pid = 0;
644 SL_RETURN( (status), _("sh_gpg_pclose"));
645}
646
647static
648int sh_gpg_check_file_sign(int fd, char * sign_id, char * sign_fp,
649 char * homedir, int whichfile)
650{
651 struct stat buf;
652 char line[256];
653 sh_gpg_popen_t source;
654 int have_id = BAD, have_fp = BAD, status = 0;
655#ifdef WITH_PGP
656 char *ptr;
657#endif
658
659#ifdef HAVE_GPG_CHECKSUM
660 SL_TICKET checkfd;
661#endif
662
663 SL_ENTER(_("sh_gpg_check_file_sign"));
664
665 /* check whether GnuPG exists and has the correct checksum
666 */
667#if defined(WITH_GPG)
668
669 TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
670 TPT(((0), FIL__, __LINE__, _("msg=<gpg is %s>\n"), DEFAULT_GPG_PATH));
671
672 if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_GPG_PATH, &buf))
673 {
[132]674 char errbuf[SH_ERRBUF_SIZE];
675
[1]676 status = errno;
677 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
[132]678 sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_GPG_PATH);
[1]679 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
680 }
681
682 if (0 != tf_trust_check (DEFAULT_GPG_PATH, SL_YESPRIV))
683 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
684
685#ifdef HAVE_GPG_CHECKSUM
686 checkfd = sl_open_read(DEFAULT_GPG_PATH, SL_YESPRIV);
687
688 if (0 != sh_gpg_checksum(checkfd, 1))
689 {
690 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
691 _("Checksum mismatch"),
692 _("gpg_check_file_sign"));
693 sl_close(checkfd);
694 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
695 }
696 sl_close(checkfd);
697#endif
698
699#elif defined(WITH_PGP)
700
701 TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
702 TPT(((0), FIL__, __LINE__, _("msg=<pgp is %s>\n"), DEFAULT_PGP_PATH));
703
704 if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_PGP_PATH, &buf))
705 {
[132]706 char errbuf[SH_ERRBUF_SIZE];
707
[1]708 status = errno;
709 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
[132]710 sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_PGP_PATH);
[1]711 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
712 }
713 if (0 != tf_trust_check (DEFAULT_PGP_PATH, SL_YESPRIV))
714 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
715
716#ifdef HAVE_GPG_CHECKSUM
717 checkfd = sl_open_read(DEFAULT_PGP_PATH, SL_YESPRIV);
718
719 if (0 != sh_gpg_checksum(checkfd, 1))
720 {
721 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
722 _("Checksum mismatch"),
723 _("gpg_check_file_sign"));
724 sl_close(checkfd);
725 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
726 }
727 sl_close(checkfd);
728#endif
729
730#endif
731
732 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n")));
733
734 fflush(NULL);
735
736 source.pipe = sh_gpg_popen ( &source, fd, 0, NULL, homedir );
737
738 if (NULL == source.pipe)
739 {
740 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
741 _("Could not open pipe"),
742 _("gpg_check_file_sign"));
743 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
744 }
745
746 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
747
748 xagain:
749
750 errno = 0;
751
[34]752 while (NULL != fgets(line, sizeof(line), source.pipe))
[1]753 {
754
755 TPT(((0), FIL__, __LINE__, _("msg=<gpg out: %s>\n"), line));
756 if (line[strlen(line)-1] == '\n')
757 line[strlen(line)-1] = ' ';
758 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
759 line,
760 _("gpg_check_file_sign"));
761
762 if (sl_strlen(line) < 18)
763 continue;
764#if defined(WITH_GPG)
765 /* Sun May 27 18:40:05 CEST 2001
766 */
767 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6) ||
768 0 == sl_strncmp(_("ERRSIG"), &line[9], 6) ||
769 0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6) ||
770 0 == sl_strncmp(_("NODATA"), &line[9], 6) ||
771 0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6))
772 {
773 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6)) {
774 dlog(1, FIL__, __LINE__,
775 _("%s file is signed, but the signature is invalid."),
776 ((whichfile == 1) ? _("Configuration") : _("Database")));
777 }
778 else if (0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6)) {
779 dlog(1, FIL__, __LINE__,
780 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
781 ((whichfile == 1) ? _("Configuration") : _("Database")),
782 homedir);
783 }
784 else if (0 == sl_strncmp(_("ERRSIG"), &line[9], 6)) {
785 dlog(1, FIL__, __LINE__,
786 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
787 ((whichfile == 1) ? _("Configuration") : _("Database")),
788 homedir);
789 }
790 else if (0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) {
791 dlog(1, FIL__, __LINE__,
792 _("%s file is signed, but the public key to verify the signature has expired."),
793 ((whichfile == 1) ? _("Configuration") : _("Database")));
794 }
795 else if (0 == sl_strncmp(_("NODATA"), &line[9], 6)) {
796 dlog(1, FIL__, __LINE__,
797 _("%s file is not signed."),
798 ((whichfile == 1) ? _("Configuration") : _("Database")));
799 }
800
801 have_fp = BAD; have_id = BAD;
802 break;
803 }
804 if (0 == sl_strncmp(_("GOODSIG"), &line[9], 7))
805 {
806 sl_strlcpy (sign_id, &line[25], SH_MINIBUF+1);
807 sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing '"' */
808 have_id = GOOD;
809 }
810 if (0 == sl_strncmp(_("VALIDSIG"), &line[9], 8))
811 {
812 strncpy (sign_fp, &line[18], 40);
813 sign_fp[40] = '\0';
814 have_fp = GOOD;
815 }
816#elif defined(WITH_PGP)
817 if (0 == sl_strncmp(_("Bad signature"), line, 13) ||
818 0 == sl_strncmp(_("Error"), line, 5) ||
819 0 == sl_strncmp(_("Malformed"), line, 9) ||
820 0 == sl_strncmp(_("WARNING"), line, 7) ||
821 0 == sl_strncmp(_("ERROR"), line, 5)
822 )
823 {
824 have_fp = BAD; have_id = BAD;
825 break;
826 }
827 if (0 == sl_strncmp(_("Good signature"), line, 14))
828 {
829 ptr = strchr ( line, '"');
830 ++ptr;
831 sl_strlcpy (sign_id, ptr, SH_MINIBUF+1);
832 sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing dot */
833 sign_id[sl_strlen(sign_id)-2] = '\0'; /* remove trailing '"' */
834 have_id = GOOD;
835 }
836#endif
837 }
838
839 if (ferror(source.pipe) && errno == EAGAIN)
840 {
841 clearerr(source.pipe);
842 goto xagain;
843 }
844
845 sh_gpg_pclose (&source);
846
847 TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n")));
848
849#ifdef WITH_PGP
850 /* get the fingerprint */
851
852 source.pipe = sh_gpg_popen ( &source, fd, 1, sign_id, homedir);
853 if (NULL == source.pipe)
854 {
855 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
856 _("Could not open pipe for fp"),
857 _("gpg_check_file_sign"));
858 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
859 }
860
861 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
862
863 yagain:
864
865 errno = 0;
866
[34]867 while (NULL != fgets(line, sizeof(line), source.pipe))
[1]868 {
[131]869#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
870 char * saveptr = NULL;
871#endif
[1]872 if (line[strlen(line)-1] == '\n')
873 line[strlen(line)-1] = ' ';
874 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
875 line,
876 _("gpg_check_file_sign"));
877
878 if (sl_strlen(line) < 18)
879 continue;
[131]880#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
881 ptr = strtok_r (line, " ", &saveptr);
882#else
[1]883 ptr = strtok (line, " ");
[131]884#endif
[1]885 while (ptr)
886 {
[131]887#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
888 ptr = strtok_r (NULL, " ", &saveptr);
889#else
[1]890 ptr = strtok (NULL, " ");
[131]891#endif
[1]892 if (ptr && 0 == sl_strncmp (ptr, _("fingerprint"), 11))
893 {
[131]894#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
895 ptr = strtok_r (NULL, " ", &saveptr); /* to '=' */
896#else
[1]897 ptr = strtok (NULL, " "); /* to '=' */
[131]898#endif
[1]899 sign_fp[0] = '\0';
900 while (ptr)
901 {
[131]902#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
903 ptr = strtok_r (NULL, " ", &saveptr); /* part of fingerprint */
904#else
[1]905 ptr = strtok (NULL, " "); /* part of fingerprint */
[131]906#endif
[1]907 sl_strlcat (sign_fp, ptr, SH_MINIBUF+1);
908 }
909 /* sign_fp[sl_strlen(sign_fp)-1] = '\0'; remove trailing '\n' */
910 if (sl_strlen(sign_fp) > 0)
911 have_fp = GOOD;
912 break;
913 }
914 }
915 }
916
917 if (ferror(source.pipe) && errno == EAGAIN)
918 {
919 clearerr(source.pipe);
920 goto yagain;
921 }
922
923 sh_gpg_pclose (&source);
924#endif
925
926 if (have_id == GOOD)
927 {
928 TPT(((0), FIL__, __LINE__, _("msg=<Got signator ID>\n")));
929 ;
930 }
931 if (have_fp == GOOD)
932 {
933 TPT(((0), FIL__, __LINE__, _("msg=<Got fingerprint>\n")));
934 ;
935 }
936
937 if (have_id == GOOD && have_fp == GOOD)
938 SL_RETURN( SH_GPG_OK, _("sh_gpg_check_file_sign"));
939 else
940 {
941 if (have_id == BAD)
942 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
943 _("No good signature"),
944 _("gpg_check_file_sign"));
945 else
946 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
947 _("No fingerprint for key"),
948 _("gpg_check_file_sign"));
949 SL_RETURN( SH_GPG_BADSIGN, _("sh_gpg_check_file_sign"));
950 }
951}
952
953int get_the_fd(SL_TICKET file_1);
954
955int sh_gpg_check_sign (long file_1, long file_2, int what)
956{
957 int status = SH_GPG_BAD;
958 int fd1 = 0;
959 int fd2 = 0;
960 static int smsg = S_FALSE;
961 char * tmp;
962 char * tmp2;
963
964 char * homedir = sh.effective.home;
965#if defined(SH_WITH_SERVER)
966 struct passwd * tempres;
[131]967#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
968 struct passwd pwd;
[227]969 char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
[1]970#endif
[131]971#endif
972
[1]973#ifdef USE_FINGERPRINT
974#include "sh_gpg_fp.h"
975#endif
976
977 SL_ENTER(_("sh_gpg_check_sign"));
978
979
980 if (what == 0 || what == 1)
981 fd1 = get_the_fd(file_1);
982 if (what == 0 || what == 2)
983 fd2 = get_the_fd(file_2);
984
985
986 if (fd1 < 0 || fd2 < 0)
987 {
988 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD1 = %d>\n"), fd1));
989 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD2 = %d>\n"), fd2));
990 dlog(1, FIL__, __LINE__,
991 _("This looks like an unexpected internal error.\n"));
992 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1, sh.prg_name);
993 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
[227]994#if defined(SH_WITH_SERVER)
995#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
996 SH_FREE(buffer);
997#endif
998#endif
[1]999 SL_RETURN( (-1), _("sh_gpg_check_sign"));
1000 }
1001
1002 if (what == 0 || what == 1)
1003 {
1004 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD1 = %d>\n"), fd1));
1005#if defined(SH_WITH_SERVER)
[131]1006#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
[227]1007 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
[131]1008#else
[111]1009 tempres = sh_getpwnam(DEFAULT_IDENT);
[131]1010#endif
[111]1011
[1]1012 if ((tempres != NULL) && (0 == sl_ret_euid()))
1013 {
1014 /* privileges not dropped yet*/
1015 homedir = tempres->pw_dir;
1016 }
1017#endif
1018 status = sh_gpg_check_file_sign(fd1, gp.conf_id, gp.conf_fp, homedir, 1);
1019 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGUSR: |%s|>\n"), gp.conf_id));
1020 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGFP: |%s|>\n"), gp.conf_fp));
1021 }
1022
1023 if ((what == 0 && SH_GPG_OK == status) || what == 2)
1024 {
1025 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD2 = %d>\n"), fd2));
1026#if defined(SH_WITH_SERVER)
[131]1027#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
[227]1028 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
[131]1029#else
[111]1030 tempres = sh_getpwnam(DEFAULT_IDENT);
[131]1031#endif
[111]1032
[1]1033 if ((tempres != NULL) && (0 == sl_ret_euid()))
1034 {
1035 /* privileges not dropped yet*/
1036 homedir = tempres->pw_dir;
1037 }
1038#endif
1039 status = sh_gpg_check_file_sign(fd2, gp.data_id, gp.data_fp, homedir, 2);
1040 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGUSR: |%s|>\n"), gp.data_id));
1041 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGFP: |%s|>\n"), gp.data_fp));
1042 }
1043
1044 if (SH_GPG_OK == status && what == 1)
1045 {
1046#ifdef USE_FINGERPRINT
1047 if ((sl_strcmp(SH_GPG_FP, gp.conf_fp) == 0))
1048 {
1049 int i;
1050
1051 for(i = 0; i < (int) sl_strlen(gp.conf_fp); ++i)
1052 {
1053 if (gpgfp[i] != gp.conf_fp[i])
1054 {
1055 sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
1056 MSG_E_GPG_FP,
1057 gpgfp, gp.conf_fp);
1058 break;
1059 }
1060 }
1061
1062 if (smsg == S_FALSE)
1063 {
1064 tmp = sh_util_safe_name(gp.conf_id);
[87]1065 sh_gpg_fill_startup (__LINE__,
[86]1066 /* sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_GH, */
[1]1067 sh.prg_name, sh.real.uid,
1068 (sh.flag.hidefile == S_TRUE) ?
1069 _("(hidden)") : file_path('C', 'R'),
1070 tmp,
1071 gp.conf_fp);
1072 SH_FREE(tmp);
1073 }
1074 smsg = S_TRUE;
[227]1075#if defined(SH_WITH_SERVER)
1076#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1077 SH_FREE(buffer);
1078#endif
1079#endif
[1]1080 SL_RETURN(0, _("sh_gpg_check_sign"));
1081 }
1082 else
1083 {
1084 /* fp mismatch
1085 */
1086 dlog(1, FIL__, __LINE__,
1087 _("The fingerprint of the signing key: %s\ndoes not match the compiled-in fingerprint: %s.\nTherefore the signature could not be verified.\n"),
1088 gp.conf_fp, SH_GPG_FP);
1089 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1090 _("Fingerprint mismatch"),
1091 _("gpg_check_sign"));
1092 status = SH_GPG_BADSIGN;
1093 }
1094#else
1095 if (smsg == S_FALSE)
1096 {
1097 tmp = sh_util_safe_name(gp.conf_id);
[86]1098 sh_gpg_fill_startup (__LINE__,
1099 /* sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_GH, */
[1]1100 sh.prg_name, sh.real.uid,
1101 (sh.flag.hidefile == S_TRUE) ?
1102 _("(hidden)") : file_path('C', 'R'),
1103 tmp,
1104 gp.conf_fp);
1105 SH_FREE(tmp);
1106 }
1107 smsg = S_TRUE;
[227]1108#if defined(SH_WITH_SERVER)
1109#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1110 SH_FREE(buffer);
1111#endif
1112#endif
[1]1113 SL_RETURN(0, _("sh_gpg_check_sign"));
1114#endif
1115 }
1116
1117 else if (SH_GPG_OK == status && (what == 2 || what == 0))
1118 {
1119 if ((sl_strcmp(gp.data_id, gp.conf_id) == 0) &&
1120 (sl_strcmp(gp.data_fp, gp.conf_fp) == 0))
1121 {
[227]1122#if defined(SH_WITH_SERVER)
1123#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1124 SH_FREE(buffer);
1125#endif
1126#endif
[1]1127 SL_RETURN(0, _("sh_gpg_check_sign"));
1128 }
1129 else
1130 {
1131 /* ID or fp not equal
1132 */
1133 dlog(1, FIL__, __LINE__,
1134 _("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"));
1135 tmp = sh_util_safe_name (gp.conf_id);
1136 tmp2 = sh_util_safe_name (gp.data_id);
1137 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_GH2,
1138 sh.prg_name, sh.real.uid,
1139 (sh.flag.hidefile == S_TRUE) ? _("(hidden)") : file_path('C', 'R'),
1140 tmp, gp.conf_fp,
1141 (sh.flag.hidefile == S_TRUE) ? _("(hidden)") : file_path('D', 'R'),
1142 tmp2, gp.data_fp);
1143 SH_FREE(tmp);
1144 SH_FREE(tmp2);
1145 }
1146 }
1147
1148 if (status != SH_GPG_OK)
1149 {
1150 uid_t e_uid = sl_ret_euid();
1151 char * e_home = sh.effective.home;
1152
1153#if defined(SH_WITH_SERVER)
[131]1154#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1155 struct passwd e_pwd;
[227]1156 char * e_buffer = SH_ALLOC(SH_PWBUF_SIZE);
[131]1157 struct passwd * e_tempres;
[227]1158 sh_getpwnam_r(DEFAULT_IDENT, &e_pwd, e_buffer, SH_PWBUF_SIZE, &e_tempres);
[131]1159#else
[111]1160 struct passwd * e_tempres = sh_getpwnam(DEFAULT_IDENT);
[131]1161#endif
[111]1162
[1]1163 if ((e_tempres != NULL) && (0 == sl_ret_euid()))
1164 {
1165 /* privileges not dropped yet */
1166 e_uid = e_tempres->pw_uid;
1167 e_home = e_tempres->pw_dir;
1168 }
1169#endif
1170 dlog(1, FIL__, __LINE__,
1171 _("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"),
1172#if defined(WITH_GPG)
1173 DEFAULT_GPG_PATH,
1174#else
1175 DEFAULT_PGP_PATH,
1176#endif
1177 (int) e_uid, e_home);
[227]1178
1179#if defined(SH_WITH_SERVER)
1180#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1181 SH_FREE(e_buffer);
1182#endif
1183#endif
[1]1184 }
1185
1186 TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status));
1187
1188 sh_error_handle((-1), FIL__, __LINE__, status, MSG_EXIT_ABORT1, sh.prg_name);
1189 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1190
1191 return (-1); /* make compiler happy */
1192}
1193
1194/* #ifdef WITH_GPG */
1195#endif
1196
1197
1198
1199
1200
1201
1202
1203
Note: See TracBrowser for help on using the repository browser.