source: trunk/src/sh_gpg.c @ 133

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

Reentrant checksum/hash functions.

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