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_SIG)
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_sig.h"
63 
64 int get_the_fd(SL_TICKET file_1);
65 
66 #if defined(WITH_GPG)
67 static struct {
68   char     conf_id[SH_MINIBUF+1];
69   char     conf_fp[SH_MINIBUF+1];
70   char     data_id[SH_MINIBUF+1];
71   char     data_fp[SH_MINIBUF+1];
72 } gp;
73 #endif
74 
75 typedef struct {
76   pid_t    pid;
77   FILE   * pipe;
78 } sh_gpg_popen_t;
79 
80 #define SH_SIG_OK      0
81 #define SH_SIG_BAD     1
82 #define SH_SIG_BADSIGN 2
83 
84 /* replace #if 0 by #if 1 and set an appropriate path in front of '/pdbg.'
85  * for debugging
86  */
87 #if 0
88 #define PDGBFILE "/pdbg."
89 #endif
90 
91 #if defined(PDGBFILE)
92 FILE * pdbg;
93 FILE * pdbgc;
94 #define PDBG_OPEN    pdbg = fopen(PDGBFILE"main",  "a")
95 #define PDBG_CLOSE   sl_fclose (FIL__, __LINE__, pdbg)
96 #define PDBG(arg)    fprintf(pdbg,  "PDBG: step %d\n", arg); fflush(pdbg)
97 #define PDBG_D(arg)  fprintf(pdbg,  "PDBG: %d\n", arg); fflush(pdbg)
98 #define PDBG_S(arg)  fprintf(pdbg,  "PDBG: %s\n", arg); fflush(pdbg)
99 
100 #define PDBGC_OPEN   pdbgc = fopen(PDGBFILE"child", "a")
101 #define PDBGC_CLOSE  sl_fclose (FIL__, __LINE__, pdbgc)
102 #define PDBGC(arg)   fprintf(pdbgc, "PDBG: step %d\n", arg); fflush(pdbgc)
103 #define PDBGC_D(arg) fprintf(pdbgc, "PDBG: %d\n", arg); fflush(pdbgc)
104 #define PDBGC_S(arg) fprintf(pdbgc, "PDBG: %s\n", arg); fflush(pdbgc)
105 #else
106 #define PDBG_OPEN
107 #define PDBG_CLOSE
108 #define PDBG(arg)
109 #define PDBG_D(arg)
110 #define PDBG_S(arg)
111 #define PDBGC_OPEN
112 #define PDBGC_CLOSE
113 #define PDBGC(arg)
114 #define PDBGC_D(arg)
115 #define PDBGC_S(arg)
116 #endif
117 
118 #undef  FIL__
119 #define FIL__  _("sh_sig.c")
120 
121 #if defined(SIG_HASH) || defined(SIG_KEY_HASH)
122 
123 typedef enum { SIG_HASH_REPORT, SIG_HASH_REPORTFULL, SIG_HASH_OTHER } checksum_flag;
124 
sh_sig_checksum(SL_TICKET checkfd,checksum_flag flag,const char * expected_in,const char * path)125 static int sh_sig_checksum (SL_TICKET checkfd, checksum_flag flag, const char * expected_in, const char * path)
126 {
127   char * test_sig;
128   char * expected = NULL;
129   char * test_ptr1 = NULL;
130   char * test_ptr2 = NULL;
131   char   wstrip1[128];
132   char   wstrip2[128];
133   int    i, k;
134 #include "sh_sig_chksum.h"
135 
136   SL_ENTER(_("sh_sig_checksum"));
137 
138 
139   if (flag == SIG_HASH_OTHER)
140     expected = sh_util_strdup(expected_in);
141 
142   if (flag == SIG_HASH_OTHER)
143     test_sig = sh_tiger_hash_gpg (path, checkfd, TIGER_NOLIM);
144   else
145     test_sig = sh_tiger_hash_gpg (DEFAULT_SIG_PATH, checkfd, TIGER_NOLIM);
146 
147   test_ptr1 = (flag == SIG_HASH_OTHER) ? strchr(expected, ':') : strchr(SIG_HASH, ':');
148   if (test_ptr1 != NULL)
149     test_ptr1 += 2;
150   else
151     test_ptr1 = (flag == SIG_HASH_OTHER) ? expected : SIG_HASH;
152 
153   if (test_sig != NULL)
154     test_ptr2 = strchr(test_sig, ':');
155   if (test_ptr2 != NULL)
156     test_ptr2 += 2;
157   else
158     test_ptr2 = test_sig;
159 
160   /* Tue Jun 24 23:11:54 CEST 2003 (1.7.9) -- strip whitespace
161    */
162   k = 0;
163   for (i = 0; i < 127; ++i)
164     {
165       if (test_ptr1[i] == '\0')
166 	break;
167       if (test_ptr1[i] != ' ')
168 	{
169 	  wstrip1[k] = test_ptr1[i];
170 	  ++k;
171 	}
172     }
173   wstrip1[k] = '\0';
174 
175   if (flag != SIG_HASH_OTHER)
176     {
177       for(i = 0; i < KEY_LEN; ++i)
178 	{
179 	  if (sigchk[i] != wstrip1[i])
180 	    {
181 	      sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0, MSG_E_GPG_CHK,
182 			      sigchk, wstrip1);
183 	      break;
184 	    }
185 	}
186     }
187 
188   k = 0;
189   if (test_ptr2)
190     {
191       for (i = 0; i < 127; ++i)
192 	{
193 	  if (test_ptr2[i] == '\0')
194 	    break;
195 	  if (test_ptr2[i] != ' ')
196 	    {
197 	      wstrip2[k] = test_ptr2[i];
198 	      ++k;
199 	    }
200 	}
201     }
202   wstrip2[k] = '\0';
203 
204   if (0 != sl_strncmp(wstrip1, wstrip2, 127))
205     {
206       TPT(((0), FIL__, __LINE__, _("msg=<sig checksum: %s>\n"), test_sig));
207       TPT(((0), FIL__, __LINE__, _("msg=<compiled in : %s>\n"), (flag == SIG_HASH_OTHER) ? expected : SIG_HASH));
208       TPT(((0), FIL__, __LINE__, _("msg=<wstrip1     : %s>\n"), wstrip1));
209       TPT(((0), FIL__, __LINE__, _("msg=<wstrip2     : %s>\n"), wstrip2));
210       if (flag == SIG_HASH_REPORTFULL)
211 	sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_GPG,
212 			SIG_HASH, test_sig);
213       if (flag == SIG_HASH_OTHER)
214 	dlog(1, FIL__, __LINE__, _("The compiled-in checksum of the public key %s\n(%s)\ndoes not match the actual checksum\n(%s).\nYou need to recompile with the correct checksum."), path, wstrip1, wstrip2);
215       else
216 	dlog(1, FIL__, __LINE__, _("The compiled-in checksum of the signature checking binary %s\n(%s)\ndoes not match the actual checksum\n(%s).\nYou need to recompile with the correct checksum."), DEFAULT_SIG_PATH, wstrip1, wstrip2);
217       SH_FREE(test_sig);
218       if (expected)
219 	SH_FREE(expected);
220       SL_RETURN((-1), _("sh_sig_checksum"));
221     }
222   SH_FREE(test_sig);
223   if (expected)
224     SH_FREE(expected);
225   SL_RETURN( (0), _("sh_sig_checksum"));
226 }
227 #endif
228 
229 struct startup_info {
230   long   line;
231   char * program;
232   long   uid;
233   char * path;
234   char * key_uid;
235   char * key_id;
236 };
237 
238 static struct startup_info startInfo = { 0, NULL, 0, NULL, NULL, NULL };
239 
sh_sig_fill_startup(long line,char * program,long uid,char * path,char * key_uid,char * key_id)240 static void sh_sig_fill_startup (long line, char * program, long uid, char * path,
241 				 char * key_uid, char * key_id)
242 {
243   startInfo.line    = line;
244   startInfo.program = sh_util_strdup(program);
245   startInfo.uid     = uid;
246   startInfo.path    = sh_util_strdup(path);
247   if (key_uid)
248     startInfo.key_uid = sh_util_strdup(key_uid);
249   else
250     startInfo.key_uid = sh_util_strdup(_("(not given)"));
251   if (key_id)
252     startInfo.key_id  = sh_util_strdup(key_id);
253   else
254     startInfo.key_id  = sh_util_strdup(_("(not given)"));
255   return;
256 }
257 
258 typedef enum { SIG_DATASIG, SIG_DATAONLY } extractlevel;
259 
260 
261 static FILE * sh_sig_popen (char *const argv[], sh_gpg_popen_t  *source, int fd);
262 
263 
sh_sig_popen(char * const arg[],sh_gpg_popen_t * source,int fd)264 static FILE * sh_sig_popen (char *const arg[], sh_gpg_popen_t  *source, int fd)
265 {
266   size_t len;
267   extern int flag_err_debug;
268   int pipedes[2];
269   FILE * outf = NULL;
270   char * envp[2];
271 
272 #if defined(HAVE_SIG_CHECKSUM)
273   SL_TICKET   checkfd = -1;
274   int         myrand;
275   int         i;
276 #if defined(__linux__)
277   int         get_the_fd(SL_TICKET);
278   char        pname[128];
279   int         pfd;
280   int         val_return;
281 #endif
282 #endif
283 
284   SL_ENTER(_("sh_sig_popen"));
285 
286   /* use homedir of effective user
287    */
288   len = sl_strlen(sh.effective.home) + 6;
289   envp[0] = calloc(1, len); /* free() ok   */
290   if (envp[0] != NULL)
291 	sl_snprintf (envp[0], len, _("HOME=%s"), sh.effective.home);
292   envp[1] = NULL;
293 
294   /* Create the pipe
295    */
296   if (aud_pipe(FIL__, __LINE__, pipedes) < 0)
297     {
298       if (envp[0] != NULL)
299 	free(envp[0]);
300       SL_RETURN( (NULL), _("sh_gpg_popen"));
301     }
302 
303   fflush (NULL);
304 
305   source->pid = aud_fork(FIL__, __LINE__);
306 
307   /* Failure
308    */
309   if (source->pid == (pid_t) - 1)
310     {
311       sl_close_fd(FIL__, __LINE__, pipedes[0]);
312       sl_close_fd(FIL__, __LINE__, pipedes[1]);
313       if (envp[0] != NULL)
314 	free(envp[0]);
315       SL_RETURN( (NULL), _("sh_sig_popen"));
316     }
317 
318   if (source->pid == (pid_t) 0)
319     {
320 
321       /* child - make read side of the pipe stdout
322        */
323       if (retry_aud_dup2(FIL__, __LINE__,
324 			pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0)
325 	{
326 	  TPT(((0), FIL__, __LINE__, _("msg=<dup2 on pipe failed>\n")));
327 	  dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
328 	  aud__exit(FIL__, __LINE__, EXIT_FAILURE);
329 	}
330 
331       /* close the pipe descriptors
332        */
333       sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
334       sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
335 
336       if (retry_aud_dup2(FIL__, __LINE__, fd, STDIN_FILENO) < 0)
337 	{
338 	  TPT(((0), FIL__, __LINE__, _("msg=<dup2 on fd failed>\n")));
339 	  dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
340 	  aud__exit(FIL__, __LINE__, EXIT_FAILURE);
341 	}
342 
343       /* don't leak file descriptors
344        */
345       sh_unix_closeall (3, -1, S_TRUE); /* in child process */
346 
347       if (flag_err_debug != S_TRUE)
348 	{
349 	  if (NULL == freopen(_("/dev/null"), "r+", stderr))
350 	    {
351 	      dlog(1, FIL__, __LINE__, _("Internal error: freopen failed\n"));
352 	      aud__exit(FIL__, __LINE__, EXIT_FAILURE);
353 	    }
354 	}
355 
356 
357       /* We should become privileged if SUID,
358        * to be able to read the keyring.
359        * We have checked that gpg is OK,
360        * AND that only a trusted user could overwrite
361        * gpg.
362        */
363       memset (skey, 0, sizeof(sh_key_t));
364       aud_setuid(FIL__, __LINE__, geteuid());
365 
366       PDBGC_OPEN;
367       PDBGC_D((int)getuid());
368       PDBGC_D((int)geteuid());
369 
370       {
371 	int i = 0;
372 	while (arg[i] != NULL)
373 	  {
374 	    PDBGC_S(arg[i]);
375 	    ++i;
376 	  }
377       }
378       PDBGC_CLOSE;
379 
380       /* exec the program */
381 
382 #if defined(__linux__) && defined(HAVE_SIG_CHECKSUM)
383       /*
384        * --  emulate an fexecve with checksum testing
385        */
386       checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_SIG_PATH, SL_NOPRIV);
387 
388       if (0 != sh_sig_checksum(checkfd, SIG_HASH_REPORT, NULL, NULL))
389 	{
390 	  sl_close(checkfd);
391 	  aud__exit(FIL__, __LINE__, EXIT_FAILURE);
392 	}
393 
394       pfd = get_the_fd(checkfd);
395       do {
396 	val_return = dup (pfd);
397       } while (val_return < 0 && errno == EINTR);
398       pfd = val_return;
399       sl_close(checkfd);
400       /* checkfd = -1; *//* never read */
401 
402       sl_snprintf(pname, sizeof(pname), _("/proc/self/fd/%d"), pfd);
403       if (0 == access(pname, R_OK|X_OK))               /* flawfinder: ignore */
404 
405 	{
406 	  fcntl  (pfd, F_SETFD, FD_CLOEXEC);
407 	  retry_aud_execve (FIL__, __LINE__,  pname, arg, envp);
408 
409 	  dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"),
410 	       pname);
411 	  /* failed
412 	   */
413 	  aud__exit(FIL__, __LINE__, EXIT_FAILURE);
414 	}
415 
416       /* procfs not working, go ahead
417        */
418 #endif
419 
420 #if defined(HAVE_SIG_CHECKSUM)
421       /* This is an incredibly ugly kludge to prevent an attacker
422        * from knowing when it is safe to slip in a fake executable
423        * between the integrity check and the execve
424        */
425       myrand = (int) taus_get ();
426 
427       myrand = (myrand < 0) ? (-myrand) : myrand;
428       myrand = (myrand % 32) + 2;
429 
430       for (i = 0; i < myrand; ++i)
431 	{
432 	  checkfd = sl_open_fastread(FIL__, __LINE__,
433 				     DEFAULT_SIG_PATH, SL_NOPRIV);
434 
435 	  if (0 != sh_sig_checksum(checkfd, SIG_HASH_REPORT, NULL, NULL)) {
436 	    aud__exit(FIL__, __LINE__, EXIT_FAILURE);
437 	  }
438 	  sl_close(checkfd);
439 	}
440 #endif
441 
442       retry_aud_execve (FIL__, __LINE__, DEFAULT_SIG_PATH, arg, envp);
443       dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"),
444 	   DEFAULT_SIG_PATH);
445 
446       /* failed
447        */
448       TPT(((0), FIL__, __LINE__, _("msg=<execve failed>\n")));
449       dlog(1, FIL__, __LINE__, _("Unexpected error: execve failed\n"));
450       aud__exit(FIL__, __LINE__, EXIT_FAILURE);
451     }
452 
453   /* parent
454    */
455 
456   if (envp[0] != NULL)
457     free(envp[0]);
458 
459   sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
460   retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
461   retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFL,  O_NONBLOCK);
462 
463   outf = fdopen (pipedes[STDIN_FILENO], "r");
464 
465   if (outf == NULL)
466     {
467       aud_kill (FIL__, __LINE__, source->pid, SIGKILL);
468       sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
469       waitpid (source->pid, NULL, 0);
470       source->pid = 0;
471       SL_RETURN( (NULL), _("sh_sig_popen"));
472     }
473 
474   SL_RETURN( (outf), _("sh_sig_popen"));
475 }
476 
477 
sh_sig_pclose(sh_gpg_popen_t * source)478 static int sh_sig_pclose (sh_gpg_popen_t *source)
479 {
480   int status = 0;
481 
482   SL_ENTER(_("sh_sig_pclose"));
483 
484   status = sl_fclose(FIL__, __LINE__, source->pipe);
485   if (status)
486     SL_RETURN( (-1), _("sh_sig_pclose"));
487 
488   if (waitpid(source->pid, NULL, 0) != source->pid)
489     status = -1;
490 
491   source->pipe = NULL;
492   source->pid = 0;
493   SL_RETURN( (status), _("sh_sig_pclose"));
494 }
495 
496 /* This is signify specific stuff
497  */
498 #if defined(WITH_SIGNIFY)
499 
500 #include <ctype.h>
501 
502 static
sh_signify_comp_comm(const char * line,size_t * commlen)503 int sh_signify_comp_comm(const char * line, size_t * commlen)
504 {
505   /* check for a valid comment line: not exceeding 1023 chars and
506    * starting with 'untrusted comment: ' */
507   static char   cmp[SH_MINIBUF];
508   static size_t cmp_len = 0;
509 
510   size_t len = sl_strlen(line);
511 
512   if (cmp_len == 0) {
513     sl_strlcpy(cmp, _("untrusted comment: "), sizeof(cmp));
514     cmp_len = strlen(cmp);
515   }
516 
517   if (line[len-1] == '\n') {
518     /* signify will replace the '\n' with '\0', so 1024 -> 1023, which fits */
519     if (len > 1024) return S_FALSE;
520     else            *commlen = len;
521   } else {
522     if (len > 1023) return S_FALSE;
523     else            *commlen = (len+1);
524   }
525 
526   if (len >= cmp_len && 0 == strncmp(cmp, line, cmp_len))
527     return S_TRUE;
528   return S_FALSE;
529 }
530 
531 static const char bto64_0[] = N_("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
532 static char bto64[65] = { '\0' };
533 
534 static
sh_signify_comp_sig(const char * line,size_t commlen)535 int sh_signify_comp_sig(const char * line, size_t commlen)
536 {
537   char   cmp[128];
538   char   out[128];
539   size_t len = sl_strlen(line);
540   size_t i, j = 0;
541   int padf = 0;
542 
543   if (bto64[0] == '\0')
544     memcpy(bto64, _(bto64_0), 65);
545 
546   if (line[len-1] == '\n') {
547     if ((len+commlen) > 2047) return S_FALSE;
548   } else {
549     if ((len+commlen) > 2046) return S_FALSE;
550   }
551 
552   for (i = 0; i < len; ++i)
553     {
554       if (isspace(line[i])) {
555 	/* signify will skip arbitrary space, using isspace() */
556 	continue;
557       }
558       if (line[i] == '=') {
559 	if (padf > 1) /* more than two padding '=' */
560 	  return S_FALSE;
561 	else
562 	  ++padf;
563       } else if (!strchr(bto64, line[i]) || (line[i] == '=' && padf > 0)) {
564 	return S_FALSE;
565       }
566       if (j < sizeof(cmp)) {
567 	  cmp[j] = line[i]; ++j;
568       }
569     }
570 
571   /* signature is 'Ed' + 8 byte random + 64 bytes = 74 bytes
572    * => 1 pad byte => 75 bytes => 100 b64 bytes */
573   if (j != 100 || padf != 1)
574     return S_FALSE;
575 
576   cmp[j] = '\0'; /* j == 100 */
577   sh_util_base64_dec((unsigned char *) out, (unsigned char *) cmp, j);
578   if(out[0] == 'E' && out[1] == 'd')
579     return S_TRUE;
580 
581   return S_FALSE;
582 }
583 static
sh_signify_msg_start(const char * line)584 int sh_signify_msg_start(const char * line)
585 {
586   static int  step = 0;
587   static size_t commlen = 0;
588 
589   if (step == 0) {
590     if (S_TRUE == sh_signify_comp_comm(line, &commlen))
591       ++step;
592   }
593   else if (step == 1) {
594     if (S_TRUE == sh_signify_comp_sig(line, commlen)) {
595       ++step;
596     }
597     else {
598       step = 0; commlen = 0;
599     }
600   }
601   else if (step == 2) {
602     step = 0; commlen = 0;
603     return S_TRUE;
604   }
605   return S_FALSE;
606 }
607 
608 static
sh_signify_msg_startdata(const char * line)609 int sh_signify_msg_startdata(const char * line)
610 {
611   (void) line;
612   return S_TRUE;
613 }
614 
615 static
sh_signify_msg_end(const char * line)616 int sh_signify_msg_end(const char * line)
617 {
618   if (line[0] != '\0')
619     return S_FALSE;
620   return S_TRUE;
621 }
622 
623 static
sh_signify_data_end(const char * line)624 int sh_signify_data_end(const char * line)
625 {
626   if (line[0] == '[' && line[1] == 'E' && line[2] == 'O' &&
627       line[3] == 'F' && line[4] == ']')
628     return S_TRUE;
629   else if (line[0] != '\0')
630     return S_FALSE;
631   return S_TRUE;
632 }
633 
634 static
sh_signify_extract_signed(SL_TICKET fd,extractlevel extract_level)635 SL_TICKET sh_signify_extract_signed(SL_TICKET fd, extractlevel extract_level)
636 {
637   const  int fgets_buf_size = 16384;
638   FILE * fin_cp = NULL;
639   char * buf    = NULL;
640   int    bufc;
641   char * comment = NULL;
642   size_t commlen = 0;
643 
644   int    flag_comm = S_FALSE;
645   int    flag_sig  = S_FALSE;
646   SL_TICKET fdTmp  = (-1);
647   SL_TICKET open_tmp (void);
648 
649   /* extract the data and copy to temporary file
650    */
651   fdTmp = open_tmp();
652   if (SL_ISERROR(fdTmp))
653     {
654       dlog(1, FIL__, __LINE__, _("Error opening temporary file.\n"));
655       sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
656 		      _("Error opening temporary file."),
657 		      _("sh_signify_extract_signed"));
658       return -1;
659     }
660 
661   fin_cp = fdopen(dup(get_the_fd(fd)), "rb");
662   buf = SH_ALLOC(fgets_buf_size);
663 
664   while (NULL != fgets(buf, fgets_buf_size, fin_cp))
665     {
666 
667       bufc = 0;
668       while (bufc < fgets_buf_size) {
669 	if (buf[bufc] == '\n') { ++bufc; break; }
670 	++bufc;
671       }
672 
673       if (flag_comm == S_FALSE)
674 	{
675 	  if (sh_signify_comp_comm(buf, &commlen) == S_TRUE)
676 	    {
677 	      flag_comm = S_TRUE;
678 	      if (extract_level == SIG_DATASIG)
679 		{
680 		  comment = sh_util_strdup(buf);
681 		  commlen = bufc;
682 		}
683 	    }
684 	  continue;
685 	}
686       else if (flag_comm == S_TRUE && flag_sig == S_FALSE)
687 	{
688 	  if (sh_signify_comp_sig(buf, commlen) == S_TRUE)
689 	    {
690 	      flag_sig = S_TRUE;
691 	      if (extract_level == SIG_DATASIG)
692 		{
693 		  sl_write(fdTmp, comment, commlen);
694 		  sl_write(fdTmp, buf, bufc);
695 		}
696 	      if (comment != NULL)
697 		SH_FREE(comment);
698 	      comment = NULL;
699 	    }
700 	  else
701 	    {
702 	      if (comment != NULL)
703 		SH_FREE(comment);
704 	      comment = NULL; commlen = 0; flag_comm = 0;
705 	    }
706 	  continue;
707 	}
708 
709       if (flag_sig == S_TRUE)
710 	{
711 	  sl_write(fdTmp, buf, bufc);
712 	}
713     }
714   if (comment != NULL)
715     SH_FREE(comment);
716   sl_fclose(FIL__, __LINE__, fin_cp);
717   sl_rewind (fdTmp);
718 
719 #if 0
720   fin_cp = fdopen(dup(get_the_fd(fdTmp)), "rb");
721   FILE * fout = fopen("xxx.out", "w+");
722   while (NULL != fgets(buf, fgets_buf_size, fin_cp))
723     {
724       fputs(buf, fout);
725     }
726   fclose(fout);
727   sl_rewind(fdTmp);
728 #endif
729 
730   SH_FREE(buf);
731   return fdTmp;
732 }
733 
734 
sh_signify_popen(sh_gpg_popen_t * source,int fd,char * homedir)735 static FILE * sh_signify_popen (sh_gpg_popen_t  *source, int fd, char * homedir)
736 {
737   char   path[256];
738   char   cc1[32];
739   char   cc2[32];
740   char   cc3[32];
741   char   cc4[SH_PATHBUF+32];
742   char   cc5[32];
743   char   cc6[32];
744   char * argv[9];
745   FILE * retval = NULL;
746 
747   struct stat lbuf;
748   int         status_stat = 0;
749 
750 #ifdef HAVE_SIG_KEY_HASH
751   SL_TICKET checkfd;
752 #endif
753 
754 
755   SL_ENTER(_("sh_signify_popen"));
756 
757   sl_strlcpy (path,  DEFAULT_SIG_PATH,  256);
758 
759   sl_strlcpy (cc1,   _("-Vem"),         32);
760   sl_strlcpy (cc2,   _("/dev/null"),    32);
761 
762   sl_strlcpy (cc3,   _("-p"),           32);
763   sl_strlcpy (cc4,   homedir,           SH_PATHBUF+32);
764   sl_strlcat (cc4,   _("/.signify/"),   SH_PATHBUF+32);
765   sl_strlcat (cc4,   SH_INSTALL_NAME,   SH_PATHBUF+32);
766   sl_strlcat (cc4,   _(".pub"),         SH_PATHBUF+32);
767 
768   /* read signed message from stdin */
769   sl_strlcpy (cc5,   _("-x"),           32);
770   sl_strlcpy (cc6,   _("-"),            32);
771 
772   status_stat =  retry_lstat(FIL__, __LINE__, cc4, &lbuf);
773   if (status_stat == -1)
774     {
775       dlog(1, FIL__, __LINE__,
776 	   _("Signify public key %s\ndoes not exist or is not accessible.\nPlease add the directory and put the key there\nto allow signature verification.\n"),
777 	   cc4);
778       sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1,
779 		      sh.prg_name);
780       aud_exit (FIL__, __LINE__, EXIT_FAILURE);
781     }
782 #ifdef HAVE_SIG_KEY_HASH
783   checkfd = sl_open_read(FIL__, __LINE__, cc4, SL_YESPRIV);
784 
785   if (0 != sh_sig_checksum(checkfd, SIG_HASH_OTHER, SIG_KEY_HASH, cc4))
786     {
787       sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
788 		      _("Checksum mismatch for signify public key"),
789 		      _("signify_popen"));
790       sl_close(checkfd);
791       sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1,
792 		      sh.prg_name);
793       aud_exit (FIL__, __LINE__, EXIT_FAILURE);
794     }
795   sl_close(checkfd);
796 #endif
797 
798   argv[0] = path;
799   argv[1] = cc1;
800   argv[2] = cc2;
801   argv[3] = cc3;
802   argv[4] = cc4;
803   argv[5] = cc5;
804   argv[6] = cc6;
805   argv[7] = NULL;
806 
807   retval = sh_sig_popen(argv, source, fd);
808   SL_RETURN((retval), _("sh_signify_popen"));
809 }
810 
811 static
sh_signify_check_file_sign(int fd,char * homedir)812 int sh_signify_check_file_sign(int fd, char * homedir)
813 {
814   struct stat buf;
815   char line[256];
816   sh_gpg_popen_t  source;
817   int status = 0;
818   unsigned int n_goodsig  = 0;
819   unsigned int n_lines    = 0;
820 
821 #ifdef HAVE_SIG_CHECKSUM
822   SL_TICKET checkfd;
823 #endif
824 
825   SL_ENTER(_("sh_signify_check_file_sign"));
826 
827   /* check whether signify exists and has the correct checksum
828    */
829   TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
830   TPT(((0), FIL__, __LINE__, _("msg=<signify is %s>\n"), DEFAULT_SIG_PATH));
831 
832   if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_SIG_PATH, &buf))
833     {
834       char errbuf[SH_ERRBUF_SIZE];
835 
836       status = errno;
837       sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
838 		      sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_SIG_PATH);
839       SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign"));
840     }
841 
842   if (0 != tf_trust_check (DEFAULT_SIG_PATH, SL_YESPRIV))
843     SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign"));
844 
845 #ifdef HAVE_SIG_CHECKSUM
846   checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_SIG_PATH, SL_YESPRIV);
847 
848   if (0 != sh_sig_checksum(checkfd, SIG_HASH_REPORTFULL, NULL, NULL))
849     {
850       sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
851 		      _("Checksum mismatch"),
852 		      _("signify_check_file_sign"));
853       sl_close(checkfd);
854       SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign"));
855     }
856   sl_close(checkfd);
857 #endif
858 
859   TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n")));
860 
861   fflush(NULL);
862 
863   source.pipe   = sh_signify_popen  ( &source, fd, homedir );
864 
865   if (NULL == source.pipe)
866     {
867       sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
868 		      _("Could not open pipe"),
869 		      _("signify_check_file_sign"));
870       SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign"));
871     }
872 
873   TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
874 
875  xagain:
876 
877   errno = 0;
878 
879   while (NULL != fgets(line, sizeof(line), source.pipe))
880     {
881       TPT(((0), FIL__, __LINE__, _("msg=<signify out: %s>\n"), line));
882       if (line[strlen(line)-1] == '\n')
883 	line[strlen(line)-1] = ' ';
884       sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
885 		      line,
886 		      _("signify_check_file_sign"));
887 
888       ++n_lines;
889 
890       /* the '\n' has been replaced with ' ' for logging */
891       if (0 == sl_strcmp(_("Signature Verified "), line))
892 	{
893 	  ++n_goodsig;
894 	}
895     }
896 
897   if (ferror(source.pipe) && errno == EAGAIN)
898     {
899       /* sleep 10 ms to avoid starving the gpg child writing to the pipe */
900       retry_msleep(0,10);
901       clearerr(source.pipe);
902       goto xagain;
903     }
904 
905   if (0 != sh_sig_pclose (&source))
906     {
907 	sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
908 			_("Error on closing process pipe"),
909 			_("signify_check_file_sign"));
910 	n_goodsig = 0;
911     }
912 
913   TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n")));
914 
915   if (n_goodsig == 1 && n_lines == 1)
916     {
917       TPT(((0), FIL__, __LINE__, _("msg=<Signature Verified>\n")));
918       SL_RETURN( SH_SIG_OK, _("sh_signature_check_file_sign"));
919     }
920   else
921     {
922       sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
923 		      _("Error verifying file signature"),
924 		      _("signify_check_file_sign"));
925     }
926   SL_RETURN( SH_SIG_BADSIGN, _("sh_signature_check_file_sign"));
927 }
928 
929 
sh_signify_check_signature(SL_TICKET file,ShSigFile what)930 int sh_signify_check_signature (SL_TICKET file, ShSigFile what)
931 {
932   int status = SH_SIG_BAD;
933   int fd = 0;
934 
935   static int smsg = S_FALSE;
936 
937   char  * homedir = sh.effective.home;
938   char  * home_alloc = NULL;
939 #if defined(SH_WITH_SERVER)
940   struct passwd * tempres;
941 #if defined(USE_GETPWNAM_R)
942   struct passwd    pwd;
943   char           * buffer = SH_ALLOC(SH_PWBUF_SIZE);
944 #endif
945 #endif
946 
947   SL_ENTER(_("sh_signify_check_sign"));
948 
949   (void) what;
950 
951   fd = get_the_fd(file);
952 
953   if (fd < 0)
954     {
955       TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
956       dlog(1, FIL__, __LINE__,
957 	   _("This looks like an unexpected internal error.\n"));
958 #if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
959       SH_FREE(buffer);
960 #endif
961       SL_RETURN( (-1), _("sh_signify_check_sign"));
962     }
963 
964 #if defined(SH_WITH_SERVER)
965 #if defined(USE_GETPWNAM_R)
966   sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
967 #else
968   tempres = sh_getpwnam(DEFAULT_IDENT);
969 #endif
970   if ((tempres != NULL) && (0 == sl_ret_euid()))
971     {
972       /* privileges not dropped yet*/
973       homedir = tempres->pw_dir;
974     }
975 #endif
976 
977   home_alloc = sh_util_strdup(homedir);
978 
979   TPT(((0), FIL__, __LINE__, _("msg=<SIGNIFY_CHECK: FD = %d>\n"), fd));
980   status = sh_signify_check_file_sign(fd, homedir);
981 
982   if (status != SH_SIG_OK)
983     {
984       TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status));
985       dlog(1, FIL__, __LINE__,
986 	   _("The signature of the configuration file or the file signature database\ncould not be verified. Possible reasons are:\n - signify binary (%s) not found\n - invalid signature\n - there is no keyfile in %s/.signify/%s.pub, or\n - the file is not signed - did you move /filename.sig to /filename ?\nTo create a signed file, use (remove old signatures before):\n   signify|signify-openbsd -Se -s KEYNAME.sec -m FILE\n   mv FILE.sig FILE\n"),
987 	   DEFAULT_SIG_PATH, home_alloc, SH_INSTALL_NAME);
988       SH_FREE(home_alloc);
989       SL_RETURN( (-1), _("sh_signify_check_sign"));
990     }
991 
992   if (smsg == S_FALSE)
993     {
994       sh_sig_fill_startup (__LINE__,
995 			   sh.prg_name, sh.real.uid,
996 			   (sh.flag.hidefile == S_TRUE) ?
997 			   _("(hidden)") : file_path('C', 'R'),
998 			   NULL,  NULL);
999     }
1000   smsg = S_TRUE;
1001 
1002   SH_FREE(home_alloc);
1003   SL_RETURN(0, _("sh_signify_check_sign"));
1004 }
1005 
1006 /* This is GPG specific stuff
1007  */
1008 #elif defined(WITH_GPG)
sh_gpg_popen(sh_gpg_popen_t * source,int fd,char * homedir)1009 static FILE * sh_gpg_popen (sh_gpg_popen_t  *source, int fd, char * homedir)
1010 {
1011   char   path[256];
1012   char   cc1[32];
1013   char   cc2[32];
1014 
1015   char   cc0[2] = "-";
1016   char   cc3[32];
1017   char   cc4[SH_PATHBUF+32];
1018   char   cc5[32];
1019   char * argv[9];
1020   FILE * retval = NULL;
1021 
1022 
1023   SL_ENTER(_("sh_gpg_popen"));
1024 
1025   /* -- GnuPG -- */
1026   sl_strlcpy (path,  DEFAULT_SIG_PATH,  256);
1027   sl_strlcpy (cc1,   _("--status-fd"),  32);
1028   sl_strlcpy (cc2,   _("--verify"),     32);
1029   sl_strlcpy (cc3,   _("--homedir"),    32);
1030   /* sl_strlcpy (cc4,   sh.effective.home, SH_PATHBUF+32); */
1031   sl_strlcpy (cc4,   homedir,           SH_PATHBUF+32);
1032   sl_strlcat (cc4,   _("/.gnupg"),      SH_PATHBUF+32);
1033   sl_strlcpy (cc5,   _("--no-tty"),     32);
1034 
1035 #if defined(SH_WITH_SERVER)
1036   if (0 == sl_ret_euid())   /* privileges not dropped yet */
1037     {
1038       struct stat lbuf;
1039       int         status_stat = 0;
1040 #if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1041       struct passwd    pwd;
1042       char          *  buffer = SH_ALLOC(SH_PWBUF_SIZE);
1043       struct passwd *  tempres;
1044       sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
1045 #else
1046       struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
1047 #endif
1048 
1049       if (!tempres)
1050 	{
1051 	  dlog(1, FIL__, __LINE__,
1052 	       _("User %s does not exist. Please add the user to your system.\n"),
1053 	       DEFAULT_IDENT);
1054 	  status_stat = -1;
1055 	}
1056       if (!tempres->pw_dir || tempres->pw_dir[0] == '\0')
1057 	{
1058 	  dlog(1, FIL__, __LINE__,
1059 	       _("User %s does not have a home directory.\nPlease add the home directory for this user to your system.\n"),
1060 	       DEFAULT_IDENT);
1061 	  status_stat = -2;
1062 	}
1063       if (status_stat == 0)
1064 	{
1065 	  sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
1066 	  sl_strlcat (cc4,   _("/.gnupg"),      SH_PATHBUF+32);
1067 	  status_stat =  retry_lstat(FIL__, __LINE__, cc4, &lbuf);
1068 	  if (status_stat == -1)
1069 	    {
1070 	      dlog(1, FIL__, __LINE__,
1071 		   _("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"),
1072 		   cc4, DEFAULT_IDENT);
1073 	      status_stat = -3;
1074 	    }
1075 	}
1076       if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
1077 	{
1078 	  dlog(1, FIL__, __LINE__,
1079 	       _("Gnupg directory %s\nis not owned by user %s.\n"),
1080 	       cc4, DEFAULT_IDENT);
1081 	  status_stat = -4;
1082 	}
1083       if (status_stat == 0)
1084 	{
1085 	  sl_strlcat (cc4,   _("/pubring.gpg"),      SH_PATHBUF+32);
1086 	  status_stat =  retry_lstat(FIL__, __LINE__, cc4, &lbuf);
1087 	  if (status_stat == -1)
1088 	    {
1089 	      dlog(1, FIL__, __LINE__,
1090 		   _("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"),
1091 		   cc4, DEFAULT_IDENT);
1092 	      status_stat = -5;
1093 	    }
1094 	}
1095       if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
1096 	{
1097 	  dlog(1, FIL__, __LINE__,
1098 	       _("Gnupg public keyring %s\nis not owned by user %s.\n"),
1099 	       cc4, DEFAULT_IDENT);
1100 	  status_stat = -6;
1101 	}
1102       if (status_stat != 0)
1103 	{
1104 	  sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1,
1105 			  sh.prg_name);
1106 	  aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1107 	}
1108       sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
1109       sl_strlcat (cc4,   _("/.gnupg"),      SH_PATHBUF+32);
1110 #if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1111       SH_FREE(buffer);
1112 #endif
1113     }
1114 #endif
1115 
1116   argv[0] = path;
1117   argv[1] = cc1;
1118   argv[2] = "1";
1119   argv[3] = cc2;
1120   argv[4] = cc3;
1121   argv[5] = cc4;
1122   argv[6] = cc5;
1123   argv[7] = cc0;
1124   argv[8] = NULL;
1125 
1126   retval = sh_sig_popen(argv, source, fd);
1127   SL_RETURN((retval), _("sh_gpg_popen"));
1128 }
1129 
1130 static
sh_gpg_check_file_sign(int fd,char * sign_id,char * sign_fp,char * homedir,ShSigFile whichfile)1131 int sh_gpg_check_file_sign(int fd, char * sign_id, char * sign_fp,
1132 			   char * homedir, ShSigFile whichfile)
1133 {
1134   struct stat buf;
1135   char line[256];
1136   sh_gpg_popen_t  source;
1137   int have_id = BAD, have_fp = BAD, status = 0;
1138   unsigned int n_newsig   = 0;
1139   unsigned int n_goodsig  = 0;
1140   unsigned int n_validsig = 0;
1141 
1142 #ifdef HAVE_SIG_CHECKSUM
1143   SL_TICKET checkfd;
1144 #endif
1145 
1146   SL_ENTER(_("sh_gpg_check_file_sign"));
1147 
1148   /* check whether GnuPG exists and has the correct checksum
1149    */
1150   TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
1151   TPT(((0), FIL__, __LINE__, _("msg=<gpg is %s>\n"), DEFAULT_SIG_PATH));
1152 
1153   if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_SIG_PATH, &buf))
1154     {
1155       char errbuf[SH_ERRBUF_SIZE];
1156 
1157       status = errno;
1158       sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
1159 		      sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_SIG_PATH);
1160       SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1161     }
1162 
1163   if (0 != tf_trust_check (DEFAULT_SIG_PATH, SL_YESPRIV))
1164     SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1165 
1166 #ifdef HAVE_SIG_CHECKSUM
1167   checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_SIG_PATH, SL_YESPRIV);
1168 
1169   if (0 != sh_sig_checksum(checkfd, SIG_HASH_REPORTFULL, NULL, NULL))
1170     {
1171       sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1172 		      _("Checksum mismatch"),
1173 		      _("gpg_check_file_sign"));
1174       sl_close(checkfd);
1175       SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1176     }
1177   sl_close(checkfd);
1178 #endif
1179 
1180   TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n")));
1181 
1182   fflush(NULL);
1183 
1184   source.pipe   = sh_gpg_popen  ( &source, fd, homedir );
1185 
1186   if (NULL == source.pipe)
1187     {
1188       sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1189 		      _("Could not open pipe"),
1190 		      _("gpg_check_file_sign"));
1191       SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1192     }
1193 
1194   TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
1195 
1196  xagain:
1197 
1198   errno = 0;
1199 
1200   while (NULL != fgets(line, sizeof(line), source.pipe))
1201     {
1202 
1203       TPT(((0), FIL__, __LINE__, _("msg=<gpg out: %s>\n"), line));
1204       if (line[strlen(line)-1] == '\n')
1205 	line[strlen(line)-1] = ' ';
1206       sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1207 		      line,
1208 		      _("gpg_check_file_sign"));
1209 
1210       if (sl_strlen(line) < 12)
1211 	continue;
1212 
1213       /* Sun May 27 18:40:05 CEST 2001
1214        */
1215       if (0 == sl_strncmp(_("BADSIG"),     &line[9], 6) ||
1216 	  0 == sl_strncmp(_("ERRSIG"),     &line[9], 6) ||
1217 	  0 == sl_strncmp(_("NO_PUBKEY"),  &line[9], 6) ||
1218 	  0 == sl_strncmp(_("NODATA"),     &line[9], 6) ||
1219 	  0 == sl_strncmp(_("ERROR"),      &line[9], 5) ||
1220 	  0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6))
1221 	{
1222 	  if      (0 == sl_strncmp(_("BADSIG"), &line[9], 6)) {
1223 	    dlog(1, FIL__, __LINE__,
1224 		 _("%s file is signed, but the signature is invalid."),
1225 		 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1226 	  }
1227 	  else if (0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6)) {
1228 	    dlog(1, FIL__, __LINE__,
1229 		 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
1230 		 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")),
1231 		 homedir);
1232 	  }
1233 	  else if (0 == sl_strncmp(_("ERRSIG"), &line[9], 6)) {
1234 	    dlog(1, FIL__, __LINE__,
1235 		 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
1236 		 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")),
1237 		 homedir);
1238 	  }
1239 	  else if (0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) {
1240 	    dlog(1, FIL__, __LINE__,
1241 		 _("%s file is signed, but the public key to verify the signature has expired."),
1242 		 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1243 	  }
1244 	  else if (0 == sl_strncmp(_("NODATA"), &line[9], 6)) {
1245 	    dlog(1, FIL__, __LINE__,
1246 		 _("%s file is not signed."),
1247 		 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1248 	  }
1249 	  else if (0 == sl_strncmp(_("ERROR"), &line[9], 5)) {
1250 	    dlog(1, FIL__, __LINE__,
1251 		 _("%s file is not correctly signed. An error occured while verifying the signature."),
1252 		 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1253 	  }
1254 
1255 	  have_fp = BAD; have_id = BAD;
1256 	  break;
1257 	}
1258       if (0 == sl_strncmp(_("GOODSIG"), &line[9], 7))
1259 	{
1260 	  ++n_goodsig;
1261 	  sl_strlcpy (sign_id, &line[25], SH_MINIBUF+1);
1262 	  if (sign_id)
1263 	    sign_id[sl_strlen(sign_id)-1] = '\0';  /* remove trailing '"' */
1264 	  have_id = GOOD;
1265 	}
1266       else if (0 == sl_strncmp(_("VALIDSIG"), &line[9], 8))
1267 	{
1268 	  ++n_validsig;
1269 	  strncpy (sign_fp, &line[18], 40);
1270 	  sign_fp[40] = '\0';
1271 	  have_fp = GOOD;
1272 	}
1273       else if (0 == sl_strncmp(_("NEWSIG"), &line[9], 6))
1274 	{
1275 	  ++n_newsig;
1276 	}
1277 
1278     }
1279 
1280   if (ferror(source.pipe) && errno == EAGAIN)
1281     {
1282       /* sleep 10 ms to avoid starving the gpg child writing to the pipe */
1283       retry_msleep(0,10);
1284       clearerr(source.pipe);
1285       goto xagain;
1286     }
1287 
1288   if (0 != sh_sig_pclose (&source))
1289     {
1290 	sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1291 			_("Error on closing process pipe"),
1292 			_("gpg_check_file_sign"));
1293 	have_id = BAD;
1294     }
1295 
1296   TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n")));
1297 
1298   if (n_goodsig != n_validsig || n_newsig > 1 || n_goodsig > 1)
1299     {
1300 	sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1301 			_("Too many or invalid signatures"),
1302 			_("gpg_check_file_sign"));
1303 	have_id = BAD;
1304     }
1305 
1306   if (have_id == GOOD)
1307     {
1308       TPT(((0), FIL__, __LINE__, _("msg=<Got signator ID>\n")));
1309     }
1310   if (have_fp == GOOD)
1311     {
1312       TPT(((0), FIL__, __LINE__, _("msg=<Got fingerprint>\n")));
1313     }
1314 
1315   if (have_id == GOOD && have_fp == GOOD)
1316     SL_RETURN( SH_SIG_OK, _("sh_gpg_check_file_sign"));
1317   else
1318     {
1319       if (have_id == BAD)
1320 	sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1321 			_("No good signature"),
1322 			_("gpg_check_file_sign"));
1323       else
1324 	sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1325 			_("No fingerprint for key"),
1326 			_("gpg_check_file_sign"));
1327       SL_RETURN( SH_SIG_BADSIGN, _("sh_gpg_check_file_sign"));
1328     }
1329 }
1330 
1331 #if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && \
1332   defined(HAVE_GETPWNAM_R)
1333 #define USE_GETPWNAM_R 1
1334 #endif
1335 
1336 static
sh_gpg_check_signature(SL_TICKET file,ShSigFile what)1337 int sh_gpg_check_signature (SL_TICKET file, ShSigFile what)
1338 {
1339   int status = SH_SIG_BAD;
1340   int fd = 0;
1341 
1342   static int smsg = S_FALSE;
1343   char  * tmp;
1344 
1345   char  * sig_id;
1346   char  * sig_fp;
1347 
1348   char  * homedir = sh.effective.home;
1349 #if defined(SH_WITH_SERVER)
1350   struct passwd * tempres;
1351 #if defined(USE_GETPWNAM_R)
1352   struct passwd    pwd;
1353   char           * buffer = SH_ALLOC(SH_PWBUF_SIZE);
1354 #endif
1355 #endif
1356 
1357 #ifdef USE_FINGERPRINT
1358 #include "sh_gpg_fp.h"
1359 #endif
1360 
1361   SL_ENTER(_("sh_gpg_check_sign"));
1362 
1363 
1364   if (what == SIG_CONF)
1365     fd = get_the_fd(file);
1366   if (what == SIG_DATA)
1367     fd = get_the_fd(file);
1368 
1369 
1370   if (fd < 0)
1371     {
1372       TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
1373       dlog(1, FIL__, __LINE__,
1374 	   _("This looks like an unexpected internal error.\n"));
1375 #if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1376       SH_FREE(buffer);
1377 #endif
1378       SL_RETURN( (-1), _("sh_gpg_check_sign"));
1379     }
1380 
1381 #if defined(SH_WITH_SERVER)
1382 #if defined(USE_GETPWNAM_R)
1383       sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
1384 #else
1385       tempres = sh_getpwnam(DEFAULT_IDENT);
1386 #endif
1387       if ((tempres != NULL) && (0 == sl_ret_euid()))
1388 	{
1389 	  /* privileges not dropped yet*/
1390 	  homedir = tempres->pw_dir;
1391 	}
1392 #endif
1393 
1394   if (what == SIG_CONF)
1395     {
1396       TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
1397       status = sh_gpg_check_file_sign(fd, gp.conf_id, gp.conf_fp, homedir, SIG_CONF);
1398       TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGUSR: |%s|>\n"), gp.conf_id));
1399       TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGFP:  |%s|>\n"), gp.conf_fp));
1400       sig_id =  gp.conf_id; sig_fp = gp.conf_fp;
1401     }
1402 
1403   if (what == SIG_DATA)
1404     {
1405       TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
1406       status = sh_gpg_check_file_sign(fd, gp.data_id, gp.data_fp, homedir, SIG_DATA);
1407       TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGUSR: |%s|>\n"), gp.data_id));
1408       TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGFP:  |%s|>\n"), gp.data_fp));
1409       sig_id =  gp.data_id; sig_fp = gp.data_fp;
1410     }
1411 
1412   if (SH_SIG_OK == status)
1413     {
1414 #ifdef USE_FINGERPRINT
1415       if ((sl_strcmp(SH_GPG_FP, sig_fp) == 0))
1416 	{
1417 	  int i;
1418 
1419 	  for(i = 0; i < (int) sl_strlen(sig_fp); ++i) {
1420 	      if (gpgfp[i] != sig_fp[i]) {
1421 		sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
1422 				MSG_E_GPG_FP, gpgfp, sig_fp);
1423 		break; }
1424 	  }
1425 
1426 	  if (smsg == S_FALSE) {
1427 	    tmp  = sh_util_safe_name(sig_id);
1428 	    sh_sig_fill_startup (__LINE__, sh.prg_name, sh.real.uid,
1429 				 (sh.flag.hidefile == S_TRUE) ?
1430 				 _("(hidden)") : file_path('C', 'R'),
1431 				 tmp,
1432 				 sig_fp);
1433 	    SH_FREE(tmp); }
1434 	  smsg = S_TRUE;
1435 
1436 #if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1437 	  SH_FREE(buffer);
1438 #endif
1439 	  SL_RETURN(0, _("sh_gpg_check_sign"));
1440 	}
1441       else
1442 	{
1443 	  /* fp mismatch */
1444 	  dlog(1, FIL__, __LINE__,
1445 	       _("The fingerprint of the signing key: %s\ndoes not match the compiled-in fingerprint: %s.\nTherefore the signature could not be verified.\n"),
1446 	       sig_fp, SH_GPG_FP);
1447 	  sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1448 		      _("Fingerprint mismatch"), _("gpg_check_sign"));
1449 	  status = SH_SIG_BADSIGN;
1450 	}
1451 #else /* ifdef USE_FINGERPRINT */
1452       if (smsg == S_FALSE)
1453 	{
1454 	  tmp = sh_util_safe_name(sig_id);
1455 	  sh_sig_fill_startup (__LINE__,
1456 			       sh.prg_name, sh.real.uid,
1457 			       (sh.flag.hidefile == S_TRUE) ?
1458 			       _("(hidden)") : file_path('C', 'R'),
1459 			       tmp,  sig_fp);
1460 	  SH_FREE(tmp);
1461 	}
1462       smsg = S_TRUE;
1463 
1464 #if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1465       SH_FREE(buffer);
1466 #endif
1467 
1468       /* status == OK and no fp checking */
1469       SL_RETURN(0, _("sh_gpg_check_sign"));
1470 #endif /* !ifdef USE_FINGERPRINT */
1471     }
1472 
1473   if (status != SH_SIG_OK)
1474     {
1475       uid_t   e_uid  = sl_ret_euid();
1476       char  * e_home = sh.effective.home;
1477 
1478 #if defined(SH_WITH_SERVER)
1479 #if defined(USE_GETPWNAM_R)
1480       struct passwd    e_pwd;
1481       char          *  e_buffer = SH_ALLOC(SH_PWBUF_SIZE);
1482       struct passwd *  e_tempres;
1483       sh_getpwnam_r(DEFAULT_IDENT, &e_pwd, e_buffer, SH_PWBUF_SIZE, &e_tempres);
1484 #else
1485       struct passwd * e_tempres = sh_getpwnam(DEFAULT_IDENT);
1486 #endif
1487 
1488       if ((e_tempres != NULL) && (0 == sl_ret_euid()))
1489 	{
1490 	  /* privileges not dropped yet */
1491 	  e_uid  = e_tempres->pw_uid;
1492 	  e_home = e_tempres->pw_dir;
1493 	}
1494 #endif
1495       dlog(1, FIL__, __LINE__,
1496 	   _("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"),
1497 	   DEFAULT_SIG_PATH,
1498 	   (int) e_uid, e_home);
1499 
1500 #if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1501       SH_FREE(e_buffer);
1502 #endif
1503     }
1504 
1505   TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status));
1506 
1507   SL_RETURN(-1, _("sh_gpg_check_sign")); /* make compiler happy */
1508 }
1509 
sh_gpg_comp(const char * line,const char * cmp)1510 static int sh_gpg_comp(const char * line, const char * cmp)
1511 {
1512   int retval = S_FALSE;
1513 
1514   if (line && line[0] == '-' && line[1] == '-')
1515     {
1516       char * dup = sh_util_strdup(line);
1517       char * tmp = dup + sl_strlen( dup );
1518       --tmp;
1519       if (*tmp == '\n') { *tmp = '\0'; --tmp; }
1520       while( (*tmp == '\t' || *tmp == ' ' || *tmp == '\r' ) && tmp >= dup ) *tmp-- = '\0';
1521 
1522       if (0 == sl_strcmp(dup, cmp))
1523 	retval = S_TRUE;
1524       SH_FREE(dup);
1525     }
1526   return retval;
1527 }
1528 
1529 static
sh_gpg_msg_start(const char * line)1530 int sh_gpg_msg_start(const char * line)
1531 {
1532   static char cmp[SH_MINIBUF];
1533   static int  initialized = 0;
1534 
1535   if (initialized == 0) {
1536     sl_strlcpy(cmp, _("-----BEGIN PGP SIGNED MESSAGE-----"), sizeof(cmp));
1537     initialized = 1;
1538   }
1539   return sh_gpg_comp(line, cmp);
1540 }
1541 
1542 static
sh_gpg_msg_startdata(const char * line)1543 int sh_gpg_msg_startdata(const char * line)
1544 {
1545   if (line[0] == '\n')
1546     return S_TRUE;
1547   return S_FALSE;
1548 }
1549 
1550 static
sh_gpg_msg_end(const char * line)1551 int sh_gpg_msg_end(const char * line)
1552 {
1553   static char cmp[SH_MINIBUF];
1554   static int  initialized = 0;
1555 
1556   if (initialized == 0) {
1557     sl_strlcpy(cmp, _("-----BEGIN PGP SIGNATURE-----"), sizeof(cmp));
1558     initialized = 1;
1559   }
1560   return sh_gpg_comp(line, cmp);
1561 }
1562 
1563 static
sh_gpg_sig_end(const char * line)1564 int sh_gpg_sig_end(const char * line)
1565 {
1566   static char cmp[SH_MINIBUF];
1567   static int  initialized = 0;
1568 
1569   if (initialized == 0) {
1570     sl_strlcpy(cmp, _("-----END PGP SIGNATURE-----"), sizeof(cmp));
1571     initialized = 1;
1572   }
1573   return sh_gpg_comp(line, cmp);
1574 }
1575 
1576 static
sh_gpg_extract_signed(SL_TICKET fd,extractlevel extract_level)1577 SL_TICKET sh_gpg_extract_signed(SL_TICKET fd, extractlevel extract_level)
1578 {
1579   const  int fgets_buf_size = 16384;
1580   FILE * fin_cp = NULL;
1581   char * buf    = NULL;
1582   int    bufc;
1583   int    flag_pgp    = S_FALSE;
1584   int    flag_nohead = S_FALSE;
1585   SL_TICKET fdTmp = (-1);
1586   SL_TICKET open_tmp (void);
1587 
1588   /* extract the data and copy to temporary file
1589    */
1590   fdTmp = open_tmp();
1591   if (SL_ISERROR(fdTmp))
1592     {
1593       dlog(1, FIL__, __LINE__, _("Error opening temporary file.\n"));
1594       sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1595 		      _("Error opening temporary file."),
1596 		      _("sh_gpg_extract_signed"));
1597       return -1;
1598     }
1599 
1600   fin_cp = fdopen(dup(get_the_fd(fd)), "rb");
1601   buf = SH_ALLOC(fgets_buf_size);
1602 
1603   while (NULL != fgets(buf, fgets_buf_size, fin_cp))
1604     {
1605       bufc = 0;
1606       while (bufc < fgets_buf_size) {
1607 	if (buf[bufc] == '\n') { ++bufc; break; }
1608 	++bufc;
1609       }
1610 
1611       if (flag_pgp == S_FALSE && sh_gpg_msg_start(buf) == S_TRUE)
1612 	{
1613 	  flag_pgp = S_TRUE;
1614 	  if (extract_level == SIG_DATASIG)
1615 	    sl_write(fdTmp, buf, bufc);
1616 	  continue;
1617 	}
1618 
1619       if (flag_pgp == S_TRUE && flag_nohead == S_FALSE)
1620 	{
1621 	  /* Header finished */
1622 	  if (buf[0] == '\n')
1623 	    {
1624 	      flag_nohead = S_TRUE;
1625 	      if (extract_level == SIG_DATASIG)
1626 		sl_write(fdTmp, buf, 1);
1627 	      continue;
1628 	    }
1629 	  /* copy these headers */
1630 	  else if (0 == sl_strncmp(buf, _("Hash:"), 5) ||
1631 		   0 == sl_strncmp(buf, _("NotDashEscaped:"), 15))
1632 	    {
1633 	      if (extract_level == SIG_DATASIG)
1634 		sl_write(fdTmp, buf, bufc);
1635 	      continue;
1636 	    }
1637 	  /* ignore other headers */
1638 	  else
1639 	    continue;
1640 	}
1641 
1642       if (flag_pgp == S_TRUE && buf[0] == '\n')
1643 	{
1644 	  sl_write(fdTmp, buf, 1);
1645 	}
1646       else if (flag_pgp == S_TRUE)
1647 	{
1648 	  if (extract_level == SIG_DATASIG) {
1649 	    sl_write(fdTmp, buf, bufc);
1650 	  }
1651 	  else {
1652 	    if (sh_gpg_msg_end(buf) == S_TRUE)
1653 	      break;
1654 	    else
1655 	      sl_write(fdTmp, buf, bufc);
1656 	  }
1657 	}
1658 
1659       /* This is after the copy has been done. */
1660       if (flag_pgp == S_TRUE && sh_gpg_sig_end(buf) == S_TRUE)
1661 	break;
1662     }
1663   SH_FREE(buf);
1664   sl_fclose(FIL__, __LINE__, fin_cp);
1665   sl_rewind (fdTmp);
1666 
1667   return fdTmp;
1668 }
1669 #endif
1670 
1671 /*********************************************************************
1672  *
1673  * Exported functions
1674  *
1675  *********************************************************************/
1676 
sh_sig_check_signature(SL_TICKET file,ShSigFile what)1677 int sh_sig_check_signature (SL_TICKET file, ShSigFile what)
1678 {
1679 #if defined(WITH_GPG)
1680   return sh_gpg_check_signature (file, what);
1681 #elif defined(WITH_SIGNIFY)
1682   return sh_signify_check_signature (file, what);
1683 #endif
1684 }
1685 
sh_sig_extract_signed(SL_TICKET fd)1686 SL_TICKET sh_sig_extract_signed(SL_TICKET fd)
1687 {
1688 #if defined(WITH_GPG)
1689   return sh_gpg_extract_signed(fd, SIG_DATASIG);
1690 #elif defined(WITH_SIGNIFY)
1691   return sh_signify_extract_signed(fd, SIG_DATASIG);
1692 #endif
1693 }
1694 
sh_sig_extract_signed_data(SL_TICKET fd)1695 SL_TICKET sh_sig_extract_signed_data(SL_TICKET fd)
1696 {
1697 #if defined(WITH_GPG)
1698   return sh_gpg_extract_signed(fd, SIG_DATAONLY);
1699 #elif defined(WITH_SIGNIFY)
1700   return sh_signify_extract_signed(fd, SIG_DATAONLY);
1701 #endif
1702 }
1703 
sh_sig_msg_start(const char * line)1704 int sh_sig_msg_start(const char * line)
1705 {
1706 #if defined(WITH_GPG)
1707   return sh_gpg_msg_start(line);
1708 #elif defined(WITH_SIGNIFY)
1709   return sh_signify_msg_start(line);
1710 #endif
1711 }
1712 
sh_sig_msg_startdata(const char * line)1713 int sh_sig_msg_startdata(const char * line)
1714 {
1715 #if defined(WITH_GPG)
1716   return sh_gpg_msg_startdata(line);
1717 #elif defined(WITH_SIGNIFY)
1718   return sh_signify_msg_startdata(line);
1719 #endif
1720 }
1721 
sh_sig_msg_end(const char * line)1722 int sh_sig_msg_end(const char * line)
1723 {
1724 #if defined(WITH_GPG)
1725   return sh_gpg_msg_end(line);
1726 #elif defined(WITH_SIGNIFY)
1727   return sh_signify_msg_end(line);
1728 #endif
1729 }
1730 
sh_sig_data_end(const char * line)1731 int sh_sig_data_end(const char * line)
1732 {
1733 #if defined(WITH_GPG)
1734   return sh_gpg_sig_end(line);
1735 #elif defined(WITH_SIGNIFY)
1736   return sh_signify_data_end(line);
1737 #endif
1738 }
1739 
sh_sig_log_startup(void)1740 void sh_sig_log_startup (void)
1741 {
1742   if (startInfo.program != NULL)
1743     {
1744       sh_error_handle ((-1), FIL__, startInfo.line, 0, MSG_START_GH,
1745 		       startInfo.program, startInfo.uid,
1746 		       startInfo.path,
1747 		       startInfo.key_uid, startInfo.key_id);
1748     }
1749   return;
1750 }
1751 
1752 /* #ifdef WITH_SIG */
1753 #endif
1754 
1755 
1756 
1757 
1758 
1759 
1760 
1761 
1762