source: trunk/src/sh_gpg.c @ 481

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

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

File size: 27.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#include "sh_gpg.h"
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") 
91#define PDBG_CLOSE   sl_fclose (FIL__, __LINE__, pdbg)
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") 
97#define PDBGC_CLOSE  sl_fclose (FIL__, __LINE__, pdbgc)
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
118
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
131  test_gpg = sh_tiger_hash_gpg (DEFAULT_GPG_PATH, checkfd, TIGER_NOLIM);
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;
172  if (test_ptr2)
173    {
174      for (i = 0; i < 127; ++i)
175        {
176          if (test_ptr2[i] == '\0')
177            break;
178          if (test_ptr2[i] != ' ')
179            {
180              wstrip2[k] = test_ptr2[i];
181              ++k;
182            }
183        }
184    }
185  wstrip2[k] = '\0';
186
187  if (0 != sl_strncmp(wstrip1, wstrip2, 127))
188    {
189      TPT(((0), FIL__, __LINE__, _("msg=<pgp checksum: %s>\n"), test_gpg));
190      TPT(((0), FIL__, __LINE__, _("msg=<Compiled-in : %s>\n"), GPG_HASH));
191      TPT(((0), FIL__, __LINE__, _("msg=<wstrip1     : %s>\n"), wstrip1));
192      TPT(((0), FIL__, __LINE__, _("msg=<wstrip2     : %s>\n"), wstrip2));
193      if (flag == 1)
194        sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_GPG, 
195                        GPG_HASH, test_gpg);
196      dlog(1, FIL__, __LINE__, _("The compiled-in checksum of the gpg binary\n(%s)\ndoes not match the actual checksum\n(%s).\nYou need to recompile with the correct checksum."), wstrip1, wstrip2);
197      SH_FREE(test_gpg);
198      SL_RETURN((-1), _("sh_gpg_checksum"));
199    }
200  SH_FREE(test_gpg);
201  SL_RETURN( (0), _("sh_gpg_checksum"));
202}
203#endif
204
205struct startup_info {
206  long   line;
207  char * program;
208  long   uid;
209  char * path;
210  char * key_uid;
211  char * key_id;
212};
213
214static struct startup_info startInfo = { 0, NULL, 0, NULL, NULL, NULL };
215
216void sh_gpg_log_startup (void)
217{
218  if (startInfo.program != NULL)
219    {
220      sh_error_handle ((-1), FIL__, startInfo.line, 0, MSG_START_GH,
221                       startInfo.program, startInfo.uid,
222                       startInfo.path,
223                       startInfo.key_uid, startInfo.key_id);
224    }
225  return;
226}
227
228static void sh_gpg_fill_startup (long line, char * program, long uid, char * path, 
229                                 char * key_uid, char * key_id)
230{
231  startInfo.line    = line;
232  startInfo.program = sh_util_strdup(program);
233  startInfo.uid     = uid;
234  startInfo.path    = sh_util_strdup(path);
235  startInfo.key_uid = sh_util_strdup(key_uid);
236  startInfo.key_id  = sh_util_strdup(key_id);
237  return;
238}
239
240static FILE * sh_gpg_popen (sh_gpg_popen_t  *source, int fd, 
241                            int mode, char * id, char * homedir)
242{
243  extern int flag_err_debug;
244  int pipedes[2];
245  FILE * outf = NULL;
246  char * envp[2];
247  size_t len;
248  char   path[256];
249  char   cc1[32];
250  char   cc2[32];
251
252  char   cc0[2] = "-";
253  char   cc3[32];
254  char   cc4[SH_PATHBUF+32];
255  char   cc5[32];
256
257
258  char * arg[9];
259
260#if defined(HAVE_GPG_CHECKSUM)
261  SL_TICKET   checkfd = -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;
268  int         val_return;
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);
281  sl_strlcat (cc4,   _("/.gnupg"),      SH_PATHBUF+32);
282  sl_strlcpy (cc5,   _("--no-tty"),     32);
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;
291#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
292      struct passwd    pwd;
293      char          *  buffer = SH_ALLOC(SH_PWBUF_SIZE);
294      struct passwd *  tempres;
295      sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
296#else
297      struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
298#endif
299
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); 
361#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
362      SH_FREE(buffer);
363#endif
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   */
384  len = sl_strlen(sh.effective.home) + 6;
385  envp[0] = calloc(1, len); /* free() ok   */
386  if (envp[0] != NULL)
387        sl_snprintf (envp[0], len, _("HOME=%s"), sh.effective.home); 
388  envp[1] = NULL;
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    }
398
399  fflush (NULL);
400 
401  source->pid = aud_fork(FIL__, __LINE__);
402 
403  /* Failure
404   */
405  if (source->pid == (pid_t) - 1) 
406    {
407      sl_close_fd(FIL__, __LINE__, pipedes[0]);
408      sl_close_fd(FIL__, __LINE__, pipedes[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       */
429      sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
430      sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
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       */
441      sh_unix_closeall (3, -1, S_TRUE); /* in child process */
442
443      if (flag_err_debug != S_TRUE)
444        {
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            }
450        }
451
452
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       */
482      checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_GPG_PATH, SL_NOPRIV);
483
484      if (0 != sh_gpg_checksum(checkfd, 0))
485        {
486          sl_close(checkfd);
487          aud__exit(FIL__, __LINE__, EXIT_FAILURE);
488        }
489
490      pfd = get_the_fd(checkfd);
491      do {
492        val_return = dup (pfd);
493      } while (val_return < 0 && errno == EINTR);
494      pfd = val_return;
495      sl_close(checkfd);
496      /* checkfd = -1; *//* never read */
497
498      sl_snprintf(pname, sizeof(pname), _("/proc/self/fd/%d"), pfd);
499      if (0 == access(pname, R_OK|X_OK))               /* flawfinder: ignore */
500
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       */
521      myrand = (int) taus_get ();
522
523      myrand = (myrand < 0) ? (-myrand) : myrand;
524      myrand = (myrand % 32) + 2;
525
526      for (i = 0; i < myrand; ++i)
527        {
528          checkfd = sl_open_fastread(FIL__, __LINE__, 
529                                     DEFAULT_GPG_PATH, SL_NOPRIV);
530
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
555  sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
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);
564      sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
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
580  status = sl_fclose(FIL__, __LINE__, source->pipe);
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    {
614      char errbuf[SH_ERRBUF_SIZE];
615
616      status = errno;
617      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
618                      sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_GPG_PATH);
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
626  checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_GPG_PATH, SL_YESPRIV);
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
659  while (NULL != fgets(line, sizeof(line), source.pipe))
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;
671
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);
714          if (sign_id)
715            sign_id[sl_strlen(sign_id)-1] = '\0';  /* remove trailing '"' */
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    {
728      /* sleep 10 ms to avoid starving the gpg child writing to the pipe */
729      retry_msleep(0,10); 
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
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)
771{
772  int status = SH_GPG_BAD;
773  int fd = 0;
774
775  static int smsg = S_FALSE;
776  char  * tmp;
777
778  char  * sig_id;
779  char  * sig_fp;
780
781  char  * homedir = sh.effective.home;
782#if defined(SH_WITH_SERVER)
783  struct passwd * tempres;
784#if defined(USE_GETPWNAM_R)
785  struct passwd    pwd;
786  char           * buffer = SH_ALLOC(SH_PWBUF_SIZE);
787#endif
788#endif
789
790#ifdef USE_FINGERPRINT
791#include "sh_gpg_fp.h"
792#endif
793
794  SL_ENTER(_("sh_gpg_check_sign"));
795
796
797  if (what == SIG_CONF)
798    fd = get_the_fd(file);
799  if (what == SIG_DATA)
800    fd = get_the_fd(file);
801
802
803  if (fd < 0)
804    {
805      TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
806      dlog(1, FIL__, __LINE__, 
807           _("This looks like an unexpected internal error.\n"));
808#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
809      SH_FREE(buffer);
810#endif
811      SL_RETURN( (-1), _("sh_gpg_check_sign"));
812    }
813 
814#if defined(SH_WITH_SERVER)
815#if defined(USE_GETPWNAM_R)
816      sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
817#else
818      tempres = sh_getpwnam(DEFAULT_IDENT);
819#endif
820      if ((tempres != NULL) && (0 == sl_ret_euid()))
821        {
822          /* privileges not dropped yet*/
823          homedir = tempres->pw_dir;
824        }
825#endif
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);
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));
833      sig_id =  gp.conf_id; sig_fp = gp.conf_fp;
834    }
835
836  if (what == SIG_DATA)
837    {
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);
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));
842      sig_id =  gp.data_id; sig_fp = gp.data_fp;
843    }
844 
845  if (SH_GPG_OK == status)
846    {
847#ifdef USE_FINGERPRINT
848      if ((sl_strcmp(SH_GPG_FP, sig_fp) == 0))
849        {
850          int i;
851
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          }
858
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); }
867          smsg = S_TRUE;
868
869#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
870          SH_FREE(buffer);
871#endif
872          SL_RETURN(0, _("sh_gpg_check_sign"));
873        }
874      else
875        {
876          /* fp mismatch */
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"), 
879               sig_fp, SH_GPG_FP);
880          sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, 
881                      _("Fingerprint mismatch"), _("gpg_check_sign"));
882          status = SH_GPG_BADSIGN;
883        }
884#else /* ifdef USE_FINGERPRINT */
885      if (smsg == S_FALSE)
886        {
887          tmp = sh_util_safe_name(sig_id);
888          sh_gpg_fill_startup (__LINE__,
889                               sh.prg_name, sh.real.uid,
890                               (sh.flag.hidefile == S_TRUE) ? 
891                               _("(hidden)") : file_path('C', 'R'), 
892                               tmp,  sig_fp);
893          SH_FREE(tmp);
894        }
895      smsg = S_TRUE;
896
897#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
898      SH_FREE(buffer);
899#endif
900
901      SL_RETURN(0, _("sh_gpg_check_sign"));
902#endif /* !ifdef USE_FINGERPRINT */
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)
911#if defined(USE_GETPWNAM_R)
912      struct passwd    e_pwd;
913      char          *  e_buffer = SH_ALLOC(SH_PWBUF_SIZE);
914      struct passwd *  e_tempres;
915      sh_getpwnam_r(DEFAULT_IDENT, &e_pwd, e_buffer, SH_PWBUF_SIZE, &e_tempres);
916#else
917      struct passwd * e_tempres = sh_getpwnam(DEFAULT_IDENT);
918#endif
919
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);
931
932#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
933      SH_FREE(e_buffer);
934#endif
935    }
936
937  TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status));
938
939  return (-1); /* make compiler happy */
940} 
941
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();
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    }
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
1026/* #ifdef WITH_GPG */
1027#endif
1028
1029
1030
1031
1032
1033
1034
1035
Note: See TracBrowser for help on using the repository browser.