source: trunk/src/sh_gpg.c@ 529

Last change on this file since 529 was 481, checked in by katerina, 9 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 27.6 KB
RevLine 
[1]1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 1999, 2000 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24
25
26#if defined(WITH_GPG) || defined(WITH_PGP)
27
28#include <unistd.h>
29#include <fcntl.h>
30#include <signal.h>
31#if defined(SH_WITH_SERVER)
32#include <pwd.h>
33#endif
34#include <sys/stat.h>
35#include <sys/types.h>
36#include <errno.h>
37#include <sys/wait.h>
38
39#include <string.h>
40#ifdef HAVE_MEMORY_H
41#include <memory.h>
42#endif
43
44
45#if !defined(O_NONBLOCK)
46#if defined(O_NDELAY)
47#define O_NONBLOCK O_NDELAY
48#else
49#define O_NONBLOCK 0
50#endif
51#endif
52
53
54#include "samhain.h"
55#include "sh_utils.h"
56#include "sh_error.h"
57#include "sh_tiger.h"
58#if defined(SH_WITH_SERVER)
59#define SH_NEED_PWD_GRP 1
60#include "sh_static.h"
61#endif
[481]62#include "sh_gpg.h"
[1]63
64static struct {
65 char conf_id[SH_MINIBUF+1];
66 char conf_fp[SH_MINIBUF+1];
67 char data_id[SH_MINIBUF+1];
68 char data_fp[SH_MINIBUF+1];
69} gp;
70
71typedef struct {
72 pid_t pid;
73 FILE * pipe;
74} sh_gpg_popen_t;
75
76#define SH_GPG_OK 0
77#define SH_GPG_BAD 1
78#define SH_GPG_BADSIGN 2
79
80/* replace #if 0 by #if 1 and set an appropriate path in front of '/pdbg.'
81 * for debugging
82 */
83#if 0
84#define PDGBFILE "/pdbg."
85#endif
86
87#if defined(PDGBFILE)
88FILE * pdbg;
89FILE * pdbgc;
90#define PDBG_OPEN pdbg = fopen(PDGBFILE"main", "a")
[252]91#define PDBG_CLOSE sl_fclose (FIL__, __LINE__, pdbg)
[1]92#define PDBG(arg) fprintf(pdbg, "PDBG: step %d\n", arg); fflush(pdbg)
93#define PDBG_D(arg) fprintf(pdbg, "PDBG: %d\n", arg); fflush(pdbg)
94#define PDBG_S(arg) fprintf(pdbg, "PDBG: %s\n", arg); fflush(pdbg)
95
96#define PDBGC_OPEN pdbgc = fopen(PDGBFILE"child", "a")
[252]97#define PDBGC_CLOSE sl_fclose (FIL__, __LINE__, pdbgc)
[1]98#define PDBGC(arg) fprintf(pdbgc, "PDBG: step %d\n", arg); fflush(pdbgc)
99#define PDBGC_D(arg) fprintf(pdbgc, "PDBG: %d\n", arg); fflush(pdbgc)
100#define PDBGC_S(arg) fprintf(pdbgc, "PDBG: %s\n", arg); fflush(pdbgc)
101#else
102#define PDBG_OPEN
103#define PDBG_CLOSE
104#define PDBG(arg)
105#define PDBG_D(arg)
106#define PDBG_S(arg)
107#define PDBGC_OPEN
108#define PDBGC_CLOSE
109#define PDBGC(arg)
110#define PDBGC_D(arg)
111#define PDBGC_S(arg)
112#endif
113
114#undef FIL__
115#define FIL__ _("sh_gpg.c")
116
117#ifdef GPG_HASH
[86]118
[1]119static int sh_gpg_checksum (SL_TICKET checkfd, int flag)
120{
121 char * test_gpg;
122 char * test_ptr1 = NULL;
123 char * test_ptr2 = NULL;
124 char wstrip1[128];
125 char wstrip2[128];
126 int i, k;
127#include "sh_gpg_chksum.h"
128
129 SL_ENTER(_("sh_gpg_checksum"));
130
[159]131 test_gpg = sh_tiger_hash_gpg (DEFAULT_GPG_PATH, checkfd, TIGER_NOLIM);
[1]132
133 test_ptr1 = strchr(GPG_HASH, ':');
134 if (test_gpg != NULL)
135 test_ptr2 = strchr(test_gpg, ':');
136
137 if (test_ptr2 != NULL)
138 test_ptr2 += 2;
139 else
140 test_ptr2 = test_gpg;
141 if (test_ptr1 != NULL)
142 test_ptr1 += 2;
143 else
144 test_ptr1 = GPG_HASH;
145
146 /* Tue Jun 24 23:11:54 CEST 2003 (1.7.9) -- strip whitespace
147 */
148 k = 0;
149 for (i = 0; i < 127; ++i)
150 {
151 if (test_ptr1[i] == '\0')
152 break;
153 if (test_ptr1[i] != ' ')
154 {
155 wstrip1[k] = test_ptr1[i];
156 ++k;
157 }
158 }
159 wstrip1[k] = '\0';
160
161 for(i = 0; i < KEY_LEN; ++i)
162 {
163 if (gpgchk[i] != wstrip1[i])
164 {
165 sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0, MSG_E_GPG_CHK,
166 gpgchk, wstrip1);
167 break;
168 }
169 }
170
171 k = 0;
[383]172 if (test_ptr2)
[1]173 {
[383]174 for (i = 0; i < 127; ++i)
[1]175 {
[383]176 if (test_ptr2[i] == '\0')
177 break;
178 if (test_ptr2[i] != ' ')
179 {
180 wstrip2[k] = test_ptr2[i];
181 ++k;
182 }
[1]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];
[481]251
[1]252 char cc0[2] = "-";
253 char cc3[32];
254 char cc4[SH_PATHBUF+32];
[203]255 char cc5[32];
[1]256
[481]257
[1]258 char * arg[9];
259
260#if defined(HAVE_GPG_CHECKSUM)
[247]261 SL_TICKET checkfd = -1;
[1]262 int myrand;
263 int i;
264#if defined(__linux__)
265 int get_the_fd(SL_TICKET);
266 char pname[128];
267 int pfd;
[248]268 int val_return;
[1]269#endif
270#endif
271
272 SL_ENTER(_("sh_gpg_popen"));
273
274 /* -- GnuPG -- */
275 sl_strlcpy (path, DEFAULT_GPG_PATH, 256);
276 sl_strlcpy (cc1, _("--status-fd"), 32);
277 sl_strlcpy (cc2, _("--verify"), 32);
278 sl_strlcpy (cc3, _("--homedir"), 32);
279 /* sl_strlcpy (cc4, sh.effective.home, SH_PATHBUF+32); */
280 sl_strlcpy (cc4, homedir, SH_PATHBUF+32);
[203]281 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
282 sl_strlcpy (cc5, _("--no-tty"), 32);
[1]283
284 /* fprintf(stderr, "YULE: homedir=%s\n", homedir); */
285
286#if defined(SH_WITH_SERVER)
287 if (0 == sl_ret_euid()) /* privileges not dropped yet */
288 {
289 struct stat lbuf;
290 int status_stat = 0;
[131]291#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
292 struct passwd pwd;
[227]293 char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
[131]294 struct passwd * tempres;
[227]295 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
[131]296#else
[111]297 struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
[131]298#endif
[111]299
[1]300 if (!tempres)
301 {
302 dlog(1, FIL__, __LINE__,
303 _("User %s does not exist. Please add the user to your system.\n"),
304 DEFAULT_IDENT);
305 status_stat = -1;
306 }
307 if (!tempres->pw_dir || tempres->pw_dir[0] == '\0')
308 {
309 dlog(1, FIL__, __LINE__,
310 _("User %s does not have a home directory.\nPlease add the home directory for this user to your system.\n"),
311 DEFAULT_IDENT);
312 status_stat = -2;
313 }
314 if (status_stat == 0)
315 {
316 sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
317 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
318 status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf);
319 if (status_stat == -1)
320 {
321 dlog(1, FIL__, __LINE__,
322 _("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"),
323 cc4, DEFAULT_IDENT);
324 status_stat = -3;
325 }
326 }
327 if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
328 {
329 dlog(1, FIL__, __LINE__,
330 _("Gnupg directory %s\nis not owned by user %s.\n"),
331 cc4, DEFAULT_IDENT);
332 status_stat = -4;
333 }
334 if (status_stat == 0)
335 {
336 sl_strlcat (cc4, _("/pubring.gpg"), SH_PATHBUF+32);
337 status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf);
338 if (status_stat == -1)
339 {
340 dlog(1, FIL__, __LINE__,
341 _("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"),
342 cc4, DEFAULT_IDENT);
343 status_stat = -5;
344 }
345 }
346 if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
347 {
348 dlog(1, FIL__, __LINE__,
349 _("Gnupg public keyring %s\nis not owned by user %s.\n"),
350 cc4, DEFAULT_IDENT);
351 status_stat = -6;
352 }
353 if (status_stat != 0)
354 {
355 sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1,
356 sh.prg_name);
357 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
358 }
359 sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
360 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
[227]361#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
362 SH_FREE(buffer);
363#endif
[1]364 }
365#endif
366
367 arg[0] = path;
368 arg[1] = cc1;
369 arg[2] = "1";
370 arg[3] = cc2;
371 arg[4] = cc3;
372 arg[5] = cc4;
373 arg[6] = cc5;
374 arg[7] = cc0;
375 arg[8] = NULL;
376
377 /* catch 'unused parameter' compiler warning
378 */
379 (void) mode;
380 (void) id;
381
382 /* use homedir of effective user
383 */
[474]384 len = sl_strlen(sh.effective.home) + 6;
385 envp[0] = calloc(1, len); /* free() ok */
386 if (envp[0] != NULL)
[203]387 sl_snprintf (envp[0], len, _("HOME=%s"), sh.effective.home);
[474]388 envp[1] = NULL;
[1]389
390 /* Create the pipe
391 */
392 if (aud_pipe(FIL__, __LINE__, pipedes) < 0)
393 {
394 if (envp[0] != NULL)
395 free(envp[0]);
396 SL_RETURN( (NULL), _("sh_gpg_popen"));
397 }
[102]398
399 fflush (NULL);
[1]400
401 source->pid = aud_fork(FIL__, __LINE__);
402
403 /* Failure
404 */
405 if (source->pid == (pid_t) - 1)
406 {
[252]407 sl_close_fd(FIL__, __LINE__, pipedes[0]);
408 sl_close_fd(FIL__, __LINE__, pipedes[1]);
[1]409 if (envp[0] != NULL)
410 free(envp[0]);
411 SL_RETURN( (NULL), _("sh_gpg_popen"));
412 }
413
414 if (source->pid == (pid_t) 0)
415 {
416
417 /* child - make read side of the pipe stdout
418 */
419 if (retry_aud_dup2(FIL__, __LINE__,
420 pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0)
421 {
422 TPT(((0), FIL__, __LINE__, _("msg=<dup2 on pipe failed>\n")));
423 dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
424 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
425 }
426
427 /* close the pipe descriptors
428 */
[252]429 sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
430 sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
[1]431
432 if (retry_aud_dup2(FIL__, __LINE__, fd, STDIN_FILENO) < 0)
433 {
434 TPT(((0), FIL__, __LINE__, _("msg=<dup2 on fd failed>\n")));
435 dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
436 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
437 }
438
439 /* don't leak file descriptors
440 */
[481]441 sh_unix_closeall (3, -1, S_TRUE); /* in child process */
[1]442
[481]443 if (flag_err_debug != S_TRUE)
[153]444 {
[198]445 if (NULL == freopen(_("/dev/null"), "r+", stderr))
446 {
447 dlog(1, FIL__, __LINE__, _("Internal error: freopen failed\n"));
448 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
449 }
[153]450 }
[1]451
[198]452
[1]453 /* We should become privileged if SUID,
454 * to be able to read the keyring.
455 * We have checked that gpg is OK,
456 * AND that only a trusted user could overwrite
457 * gpg.
458 */
459 memset (skey, '\0', sizeof(sh_key_t));
460 aud_setuid(FIL__, __LINE__, geteuid());
461
462 PDBGC_OPEN;
463 PDBGC_D((int)getuid());
464 PDBGC_D((int)geteuid());
465
466 {
467 int i = 0;
468 while (arg[i] != NULL)
469 {
470 PDBGC_S(arg[i]);
471 ++i;
472 }
473 }
474 PDBGC_CLOSE;
475
476 /* exec the program */
477
478#if defined(__linux__) && defined(HAVE_GPG_CHECKSUM)
479 /*
480 * -- emulate an fexecve with checksum testing
481 */
[248]482 checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_GPG_PATH, SL_NOPRIV);
[1]483
484 if (0 != sh_gpg_checksum(checkfd, 0))
[248]485 {
486 sl_close(checkfd);
487 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
488 }
[1]489
490 pfd = get_the_fd(checkfd);
[248]491 do {
492 val_return = dup (pfd);
493 } while (val_return < 0 && errno == EINTR);
494 pfd = val_return;
495 sl_close(checkfd);
[383]496 /* checkfd = -1; *//* never read */
[248]497
[22]498 sl_snprintf(pname, sizeof(pname), _("/proc/self/fd/%d"), pfd);
499 if (0 == access(pname, R_OK|X_OK)) /* flawfinder: ignore */
500
[1]501 {
502 fcntl (pfd, F_SETFD, FD_CLOEXEC);
503 retry_aud_execve (FIL__, __LINE__, pname, arg, envp);
504
505 dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"),
506 pname);
507 /* failed
508 */
509 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
510 }
511
512 /* procfs not working, go ahead
513 */
514#endif
515
516#if defined(HAVE_GPG_CHECKSUM)
517 /* This is an incredibly ugly kludge to prevent an attacker
518 * from knowing when it is safe to slip in a fake executable
519 * between the integrity check and the execve
520 */
[137]521 myrand = (int) taus_get ();
522
[1]523 myrand = (myrand < 0) ? (-myrand) : myrand;
524 myrand = (myrand % 32) + 2;
525
526 for (i = 0; i < myrand; ++i)
527 {
[481]528 checkfd = sl_open_fastread(FIL__, __LINE__,
529 DEFAULT_GPG_PATH, SL_NOPRIV);
530
[1]531 if (0 != sh_gpg_checksum(checkfd, 0)) {
532 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
533 }
534 sl_close(checkfd);
535 }
536#endif
537
538 retry_aud_execve (FIL__, __LINE__, DEFAULT_GPG_PATH, arg, envp);
539 dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"),
540 DEFAULT_GPG_PATH);
541
542 /* failed
543 */
544 TPT(((0), FIL__, __LINE__, _("msg=<execve failed>\n")));
545 dlog(1, FIL__, __LINE__, _("Unexpected error: execve failed\n"));
546 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
547 }
548
549 /* parent
550 */
551
552 if (envp[0] != NULL)
553 free(envp[0]);
554
[252]555 sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
[1]556 retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
557 retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFL, O_NONBLOCK);
558
559 outf = fdopen (pipedes[STDIN_FILENO], "r");
560
561 if (outf == NULL)
562 {
563 aud_kill (FIL__, __LINE__, source->pid, SIGKILL);
[252]564 sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
[1]565 waitpid (source->pid, NULL, 0);
566 source->pid = 0;
567 SL_RETURN( (NULL), _("sh_gpg_popen"));
568 }
569
570 SL_RETURN( (outf), _("sh_gpg_popen"));
571}
572
573
574static int sh_gpg_pclose (sh_gpg_popen_t *source)
575{
576 int status = 0;
577
578 SL_ENTER(_("sh_gpg_pclose"));
579
[252]580 status = sl_fclose(FIL__, __LINE__, source->pipe);
[1]581 if (status)
582 SL_RETURN( (-1), _("sh_gpg_pclose"));
583
584 if (waitpid(source->pid, NULL, 0) != source->pid)
585 status = -1;
586
587 source->pipe = NULL;
588 source->pid = 0;
589 SL_RETURN( (status), _("sh_gpg_pclose"));
590}
591
592static
593int sh_gpg_check_file_sign(int fd, char * sign_id, char * sign_fp,
594 char * homedir, int whichfile)
595{
596 struct stat buf;
597 char line[256];
598 sh_gpg_popen_t source;
599 int have_id = BAD, have_fp = BAD, status = 0;
600
601#ifdef HAVE_GPG_CHECKSUM
602 SL_TICKET checkfd;
603#endif
604
605 SL_ENTER(_("sh_gpg_check_file_sign"));
606
607 /* check whether GnuPG exists and has the correct checksum
608 */
609 TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
610 TPT(((0), FIL__, __LINE__, _("msg=<gpg is %s>\n"), DEFAULT_GPG_PATH));
611
612 if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_GPG_PATH, &buf))
613 {
[132]614 char errbuf[SH_ERRBUF_SIZE];
615
[1]616 status = errno;
617 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
[132]618 sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_GPG_PATH);
[1]619 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
620 }
621
622 if (0 != tf_trust_check (DEFAULT_GPG_PATH, SL_YESPRIV))
623 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
624
625#ifdef HAVE_GPG_CHECKSUM
[248]626 checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_GPG_PATH, SL_YESPRIV);
[1]627
628 if (0 != sh_gpg_checksum(checkfd, 1))
629 {
630 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
631 _("Checksum mismatch"),
632 _("gpg_check_file_sign"));
633 sl_close(checkfd);
634 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
635 }
636 sl_close(checkfd);
637#endif
638
639 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n")));
640
641 fflush(NULL);
642
643 source.pipe = sh_gpg_popen ( &source, fd, 0, NULL, homedir );
644
645 if (NULL == source.pipe)
646 {
647 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
648 _("Could not open pipe"),
649 _("gpg_check_file_sign"));
650 SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
651 }
652
653 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
654
655 xagain:
656
657 errno = 0;
658
[34]659 while (NULL != fgets(line, sizeof(line), source.pipe))
[1]660 {
661
662 TPT(((0), FIL__, __LINE__, _("msg=<gpg out: %s>\n"), line));
663 if (line[strlen(line)-1] == '\n')
664 line[strlen(line)-1] = ' ';
665 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
666 line,
667 _("gpg_check_file_sign"));
668
669 if (sl_strlen(line) < 18)
670 continue;
[481]671
[1]672 /* Sun May 27 18:40:05 CEST 2001
673 */
674 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6) ||
675 0 == sl_strncmp(_("ERRSIG"), &line[9], 6) ||
676 0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6) ||
677 0 == sl_strncmp(_("NODATA"), &line[9], 6) ||
678 0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6))
679 {
680 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6)) {
681 dlog(1, FIL__, __LINE__,
682 _("%s file is signed, but the signature is invalid."),
683 ((whichfile == 1) ? _("Configuration") : _("Database")));
684 }
685 else if (0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6)) {
686 dlog(1, FIL__, __LINE__,
687 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
688 ((whichfile == 1) ? _("Configuration") : _("Database")),
689 homedir);
690 }
691 else if (0 == sl_strncmp(_("ERRSIG"), &line[9], 6)) {
692 dlog(1, FIL__, __LINE__,
693 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
694 ((whichfile == 1) ? _("Configuration") : _("Database")),
695 homedir);
696 }
697 else if (0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) {
698 dlog(1, FIL__, __LINE__,
699 _("%s file is signed, but the public key to verify the signature has expired."),
700 ((whichfile == 1) ? _("Configuration") : _("Database")));
701 }
702 else if (0 == sl_strncmp(_("NODATA"), &line[9], 6)) {
703 dlog(1, FIL__, __LINE__,
704 _("%s file is not signed."),
705 ((whichfile == 1) ? _("Configuration") : _("Database")));
706 }
707
708 have_fp = BAD; have_id = BAD;
709 break;
710 }
711 if (0 == sl_strncmp(_("GOODSIG"), &line[9], 7))
712 {
713 sl_strlcpy (sign_id, &line[25], SH_MINIBUF+1);
[383]714 if (sign_id)
715 sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing '"' */
[1]716 have_id = GOOD;
717 }
718 if (0 == sl_strncmp(_("VALIDSIG"), &line[9], 8))
719 {
720 strncpy (sign_fp, &line[18], 40);
721 sign_fp[40] = '\0';
722 have_fp = GOOD;
723 }
724 }
725
726 if (ferror(source.pipe) && errno == EAGAIN)
727 {
[481]728 /* sleep 10 ms to avoid starving the gpg child writing to the pipe */
729 retry_msleep(0,10);
[1]730 clearerr(source.pipe);
731 goto xagain;
732 }
733
734 sh_gpg_pclose (&source);
735
736 TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n")));
737
738 if (have_id == GOOD)
739 {
740 TPT(((0), FIL__, __LINE__, _("msg=<Got signator ID>\n")));
741 }
742 if (have_fp == GOOD)
743 {
744 TPT(((0), FIL__, __LINE__, _("msg=<Got fingerprint>\n")));
745 }
746
747 if (have_id == GOOD && have_fp == GOOD)
748 SL_RETURN( SH_GPG_OK, _("sh_gpg_check_file_sign"));
749 else
750 {
751 if (have_id == BAD)
752 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
753 _("No good signature"),
754 _("gpg_check_file_sign"));
755 else
756 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
757 _("No fingerprint for key"),
758 _("gpg_check_file_sign"));
759 SL_RETURN( SH_GPG_BADSIGN, _("sh_gpg_check_file_sign"));
760 }
761}
762
763int get_the_fd(SL_TICKET file_1);
764
[481]765#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && \
766 defined(HAVE_GETPWNAM_R)
767#define USE_GETPWNAM_R 1
768#endif
769
770int sh_gpg_check_sign (long file, int what)
[1]771{
772 int status = SH_GPG_BAD;
[481]773 int fd = 0;
774
[1]775 static int smsg = S_FALSE;
776 char * tmp;
777
[481]778 char * sig_id;
779 char * sig_fp;
780
[1]781 char * homedir = sh.effective.home;
782#if defined(SH_WITH_SERVER)
783 struct passwd * tempres;
[481]784#if defined(USE_GETPWNAM_R)
[131]785 struct passwd pwd;
[227]786 char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
[1]787#endif
[131]788#endif
789
[1]790#ifdef USE_FINGERPRINT
791#include "sh_gpg_fp.h"
792#endif
793
794 SL_ENTER(_("sh_gpg_check_sign"));
795
796
[481]797 if (what == SIG_CONF)
798 fd = get_the_fd(file);
799 if (what == SIG_DATA)
800 fd = get_the_fd(file);
[1]801
802
[481]803 if (fd < 0)
[1]804 {
[481]805 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
[1]806 dlog(1, FIL__, __LINE__,
807 _("This looks like an unexpected internal error.\n"));
[481]808#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
[227]809 SH_FREE(buffer);
810#endif
[1]811 SL_RETURN( (-1), _("sh_gpg_check_sign"));
812 }
813
814#if defined(SH_WITH_SERVER)
[481]815#if defined(USE_GETPWNAM_R)
[227]816 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
[131]817#else
[111]818 tempres = sh_getpwnam(DEFAULT_IDENT);
[131]819#endif
[1]820 if ((tempres != NULL) && (0 == sl_ret_euid()))
821 {
822 /* privileges not dropped yet*/
823 homedir = tempres->pw_dir;
824 }
825#endif
[481]826
827 if (what == SIG_CONF)
828 {
829 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
830 status = sh_gpg_check_file_sign(fd, gp.conf_id, gp.conf_fp, homedir, 1);
[1]831 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGUSR: |%s|>\n"), gp.conf_id));
832 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGFP: |%s|>\n"), gp.conf_fp));
[481]833 sig_id = gp.conf_id; sig_fp = gp.conf_fp;
[1]834 }
835
[481]836 if (what == SIG_DATA)
[1]837 {
[481]838 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
839 status = sh_gpg_check_file_sign(fd, gp.data_id, gp.data_fp, homedir, 2);
[1]840 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGUSR: |%s|>\n"), gp.data_id));
841 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGFP: |%s|>\n"), gp.data_fp));
[481]842 sig_id = gp.data_id; sig_fp = gp.data_fp;
[1]843 }
844
[481]845 if (SH_GPG_OK == status)
[1]846 {
847#ifdef USE_FINGERPRINT
[481]848 if ((sl_strcmp(SH_GPG_FP, sig_fp) == 0))
[1]849 {
850 int i;
851
[481]852 for(i = 0; i < (int) sl_strlen(sig_fp); ++i) {
853 if (gpgfp[i] != sig_fp[i]) {
854 sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
855 MSG_E_GPG_FP, gpgfp, sig_fp);
856 break; }
857 }
[1]858
[481]859 if (smsg == S_FALSE) {
860 tmp = sh_util_safe_name(sig_id);
861 sh_gpg_fill_startup (__LINE__, sh.prg_name, sh.real.uid,
862 (sh.flag.hidefile == S_TRUE) ?
863 _("(hidden)") : file_path('C', 'R'),
864 tmp,
865 sig_fp);
866 SH_FREE(tmp); }
[1]867 smsg = S_TRUE;
[481]868
869#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
[227]870 SH_FREE(buffer);
871#endif
[1]872 SL_RETURN(0, _("sh_gpg_check_sign"));
873 }
874 else
875 {
[481]876 /* fp mismatch */
[1]877 dlog(1, FIL__, __LINE__,
878 _("The fingerprint of the signing key: %s\ndoes not match the compiled-in fingerprint: %s.\nTherefore the signature could not be verified.\n"),
[481]879 sig_fp, SH_GPG_FP);
[1]880 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
[481]881 _("Fingerprint mismatch"), _("gpg_check_sign"));
[1]882 status = SH_GPG_BADSIGN;
883 }
[481]884#else /* ifdef USE_FINGERPRINT */
[1]885 if (smsg == S_FALSE)
886 {
[481]887 tmp = sh_util_safe_name(sig_id);
[86]888 sh_gpg_fill_startup (__LINE__,
[481]889 sh.prg_name, sh.real.uid,
890 (sh.flag.hidefile == S_TRUE) ?
891 _("(hidden)") : file_path('C', 'R'),
892 tmp, sig_fp);
[1]893 SH_FREE(tmp);
894 }
895 smsg = S_TRUE;
[481]896
897#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
[227]898 SH_FREE(buffer);
899#endif
[481]900
[1]901 SL_RETURN(0, _("sh_gpg_check_sign"));
[481]902#endif /* !ifdef USE_FINGERPRINT */
[1]903 }
904
905 if (status != SH_GPG_OK)
906 {
907 uid_t e_uid = sl_ret_euid();
908 char * e_home = sh.effective.home;
909
910#if defined(SH_WITH_SERVER)
[481]911#if defined(USE_GETPWNAM_R)
[131]912 struct passwd e_pwd;
[227]913 char * e_buffer = SH_ALLOC(SH_PWBUF_SIZE);
[131]914 struct passwd * e_tempres;
[227]915 sh_getpwnam_r(DEFAULT_IDENT, &e_pwd, e_buffer, SH_PWBUF_SIZE, &e_tempres);
[131]916#else
[111]917 struct passwd * e_tempres = sh_getpwnam(DEFAULT_IDENT);
[131]918#endif
[111]919
[1]920 if ((e_tempres != NULL) && (0 == sl_ret_euid()))
921 {
922 /* privileges not dropped yet */
923 e_uid = e_tempres->pw_uid;
924 e_home = e_tempres->pw_dir;
925 }
926#endif
927 dlog(1, FIL__, __LINE__,
928 _("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"),
929 DEFAULT_GPG_PATH,
930 (int) e_uid, e_home);
[227]931
[481]932#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
[227]933 SH_FREE(e_buffer);
934#endif
[1]935 }
936
937 TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status));
938
939 return (-1); /* make compiler happy */
940}
941
[347]942#define FGETS_BUF 16384
943
944SL_TICKET sh_gpg_extract_signed(SL_TICKET fd)
945{
946 FILE * fin_cp = NULL;
947 char * buf = NULL;
948 int bufc;
949 int flag_pgp = S_FALSE;
950 int flag_nohead = S_FALSE;
951 SL_TICKET fdTmp = (-1);
952 SL_TICKET open_tmp (void);
953
954 /* extract the data and copy to temporary file
955 */
956 fdTmp = open_tmp();
[481]957 if (SL_ISERROR(fdTmp))
958 {
959 dlog(1, FIL__, __LINE__, _("Error opening temporary file.\n"));
960 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
961 _("Error opening temporary file."),
962 _("sh_gpg_extract_signed"));
963 return -1;
964 }
[347]965
966 fin_cp = fdopen(dup(get_the_fd(fd)), "rb");
967 buf = SH_ALLOC(FGETS_BUF);
968
969 while (NULL != fgets(buf, FGETS_BUF, fin_cp))
970 {
971 bufc = 0;
972 while (bufc < FGETS_BUF) {
973 if (buf[bufc] == '\n') { ++bufc; break; }
974 ++bufc;
975 }
976
977 if (flag_pgp == S_FALSE &&
978 (0 == sl_strcmp(buf, _("-----BEGIN PGP SIGNED MESSAGE-----\n"))||
979 0 == sl_strcmp(buf, _("-----BEGIN PGP MESSAGE-----\n")))
980 )
981 {
982 flag_pgp = S_TRUE;
983 sl_write(fdTmp, buf, bufc);
984 continue;
985 }
986
987 if (flag_pgp == S_TRUE && flag_nohead == S_FALSE)
988 {
989 if (buf[0] == '\n')
990 {
991 flag_nohead = S_TRUE;
992 sl_write(fdTmp, buf, 1);
993 continue;
994 }
995 else if (0 == sl_strncmp(buf, _("Hash:"), 5) ||
996 0 == sl_strncmp(buf, _("NotDashEscaped:"), 15))
997 {
998 sl_write(fdTmp, buf, bufc);
999 continue;
1000 }
1001 else
1002 continue;
1003 }
1004
1005 if (flag_pgp == S_TRUE && buf[0] == '\n')
1006 {
1007 sl_write(fdTmp, buf, 1);
1008 }
1009 else if (flag_pgp == S_TRUE)
1010 {
1011 /* sl_write_line(fdTmp, buf, bufc); */
1012 sl_write(fdTmp, buf, bufc);
1013 }
1014
1015 if (flag_pgp == S_TRUE &&
1016 0 == sl_strcmp(buf, _("-----END PGP SIGNATURE-----\n")))
1017 break;
1018 }
1019 SH_FREE(buf);
1020 sl_fclose(FIL__, __LINE__, fin_cp); /* fin_cp = fdopen(dup(), "rb"); */
1021 sl_rewind (fdTmp);
1022
1023 return fdTmp;
1024}
1025
[1]1026/* #ifdef WITH_GPG */
1027#endif
1028
1029
1030
1031
1032
1033
1034
1035
Note: See TracBrowser for help on using the repository browser.