source: trunk/src/sh_gpg.c @ 132

Last change on this file since 132 was 132, checked in by rainer, 12 years ago

Make utility functions thread-safe.

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