source: trunk/src/sh_sig.c@ 579

Last change on this file since 579 was 579, checked in by katerina, 18 months ago

Fix for ticket #467 (memleak).

File size: 46.3 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_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
64int get_the_fd(SL_TICKET file_1);
65
66#if defined(WITH_GPG)
67static 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
75typedef 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)
92FILE * pdbg;
93FILE * 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
123typedef enum { SIG_HASH_REPORT, SIG_HASH_REPORTFULL, SIG_HASH_OTHER } checksum_flag;
124
125static 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
229struct startup_info {
230 long line;
231 char * program;
232 long uid;
233 char * path;
234 char * key_uid;
235 char * key_id;
236};
237
238static struct startup_info startInfo = { 0, NULL, 0, NULL, NULL, NULL };
239
240static 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
258typedef enum { SIG_DATASIG, SIG_DATAONLY } extractlevel;
259
260
261static FILE * sh_sig_popen (char *const argv[], sh_gpg_popen_t *source, int fd);
262
263
264static 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
478static 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
502static
503int 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
531static const char bto64_0[] = N_("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
532static char bto64[65] = { '\0' };
533
534static
535int 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}
583static
584int 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
608static
609int sh_signify_msg_startdata(const char * line)
610{
611 (void) line;
612 return S_TRUE;
613}
614
615static
616int sh_signify_msg_end(const char * line)
617{
618 if (line[0] != '\0')
619 return S_FALSE;
620 return S_TRUE;
621}
622
623static
624int 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
634static
635SL_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 defined(SH_DEBUG_SIGNIFY)
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
735static 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
811static
812int 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
930int 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)
1009static 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 or pubring.kbx) 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 char cc4_test[SH_PATHBUF+32];
1086
1087 sl_strlcpy(cc4_test, cc4, SH_PATHBUF+32);
1088 sl_strlcat (cc4_test, _("/pubring.gpg"), SH_PATHBUF+32);
1089
1090 status_stat = retry_lstat(FIL__, __LINE__, cc4_test, &lbuf);
1091 if (status_stat == -1)
1092 {
1093 sl_strlcpy(cc4_test, cc4, SH_PATHBUF+32);
1094 sl_strlcat (cc4_test, _("/pubring.kbx"), SH_PATHBUF+32);
1095
1096 status_stat = retry_lstat(FIL__, __LINE__, cc4_test, &lbuf);
1097 if (status_stat == -1)
1098 {
1099 sl_strlcpy(cc4_test, cc4, SH_PATHBUF+32);
1100 sl_strlcat (cc4_test, _("/pubring.(gpg|kbx)"), SH_PATHBUF+32);
1101
1102 dlog(1, FIL__, __LINE__,
1103 _("Gnupg public keyring %s for user %s\ndoes not exist or is not accessible.\nPlease add the directory and put the keyring (pubring.gpg or pubring.kbx) there\nto verify the configuration file.\n"),
1104 cc4_test, DEFAULT_IDENT);
1105 status_stat = -5;
1106 }
1107 }
1108 }
1109 if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
1110 {
1111 dlog(1, FIL__, __LINE__,
1112 _("Gnupg public keyring %s\nis not owned by user %s.\n"),
1113 cc4, DEFAULT_IDENT);
1114 status_stat = -6;
1115 }
1116 if (status_stat != 0)
1117 {
1118 sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1,
1119 sh.prg_name);
1120 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1121 }
1122 sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
1123 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
1124#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1125 SH_FREE(buffer);
1126#endif
1127 }
1128#endif
1129
1130 argv[0] = path;
1131 argv[1] = cc1;
1132 argv[2] = "1";
1133 argv[3] = cc2;
1134 argv[4] = cc3;
1135 argv[5] = cc4;
1136 argv[6] = cc5;
1137 argv[7] = cc0;
1138 argv[8] = NULL;
1139
1140 retval = sh_sig_popen(argv, source, fd);
1141 SL_RETURN((retval), _("sh_gpg_popen"));
1142}
1143
1144static
1145int sh_gpg_check_file_sign(int fd, char * sign_id, char * sign_fp,
1146 char * homedir, ShSigFile whichfile)
1147{
1148 struct stat buf;
1149 char line[256];
1150 sh_gpg_popen_t source;
1151 int have_id = BAD, have_fp = BAD, status = 0;
1152 unsigned int n_newsig = 0;
1153 unsigned int n_goodsig = 0;
1154 unsigned int n_validsig = 0;
1155
1156#ifdef HAVE_SIG_CHECKSUM
1157 SL_TICKET checkfd;
1158#endif
1159
1160 SL_ENTER(_("sh_gpg_check_file_sign"));
1161
1162 /* check whether GnuPG exists and has the correct checksum
1163 */
1164 TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
1165 TPT(((0), FIL__, __LINE__, _("msg=<gpg is %s>\n"), DEFAULT_SIG_PATH));
1166
1167 if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_SIG_PATH, &buf))
1168 {
1169 char errbuf[SH_ERRBUF_SIZE];
1170
1171 status = errno;
1172 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
1173 sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_SIG_PATH);
1174 SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1175 }
1176
1177 if (0 != tf_trust_check (DEFAULT_SIG_PATH, SL_YESPRIV))
1178 SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1179
1180#ifdef HAVE_SIG_CHECKSUM
1181 checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_SIG_PATH, SL_YESPRIV);
1182
1183 if (0 != sh_sig_checksum(checkfd, SIG_HASH_REPORTFULL, NULL, NULL))
1184 {
1185 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1186 _("Checksum mismatch"),
1187 _("gpg_check_file_sign"));
1188 sl_close(checkfd);
1189 SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1190 }
1191 sl_close(checkfd);
1192#endif
1193
1194 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n")));
1195
1196 fflush(NULL);
1197
1198 source.pipe = sh_gpg_popen ( &source, fd, homedir );
1199
1200 if (NULL == source.pipe)
1201 {
1202 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1203 _("Could not open pipe"),
1204 _("gpg_check_file_sign"));
1205 SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1206 }
1207
1208 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
1209
1210 xagain:
1211
1212 errno = 0;
1213
1214 while (NULL != fgets(line, sizeof(line), source.pipe))
1215 {
1216
1217 TPT(((0), FIL__, __LINE__, _("msg=<gpg out: %s>\n"), line));
1218 if (line[strlen(line)-1] == '\n')
1219 line[strlen(line)-1] = ' ';
1220 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1221 line,
1222 _("gpg_check_file_sign"));
1223
1224 if (sl_strlen(line) < 12)
1225 continue;
1226
1227 /* Sun May 27 18:40:05 CEST 2001
1228 */
1229 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6) ||
1230 0 == sl_strncmp(_("ERRSIG"), &line[9], 6) ||
1231 0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6) ||
1232 0 == sl_strncmp(_("NODATA"), &line[9], 6) ||
1233 0 == sl_strncmp(_("ERROR"), &line[9], 5) ||
1234 0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6))
1235 {
1236 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6)) {
1237 dlog(1, FIL__, __LINE__,
1238 _("%s file is signed, but the signature is invalid."),
1239 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1240 }
1241 else if (0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6)) {
1242 dlog(1, FIL__, __LINE__,
1243 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
1244 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")),
1245 homedir);
1246 }
1247 else if (0 == sl_strncmp(_("ERRSIG"), &line[9], 6)) {
1248 dlog(1, FIL__, __LINE__,
1249 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
1250 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")),
1251 homedir);
1252 }
1253 else if (0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) {
1254 dlog(1, FIL__, __LINE__,
1255 _("%s file is signed, but the public key to verify the signature has expired."),
1256 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1257 }
1258 else if (0 == sl_strncmp(_("NODATA"), &line[9], 6)) {
1259 dlog(1, FIL__, __LINE__,
1260 _("%s file is not signed."),
1261 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1262 }
1263 else if (0 == sl_strncmp(_("ERROR"), &line[9], 5)) {
1264 dlog(1, FIL__, __LINE__,
1265 _("%s file is not correctly signed. An error occured while verifying the signature."),
1266 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1267 }
1268
1269 have_fp = BAD; have_id = BAD;
1270 break;
1271 }
1272 if (0 == sl_strncmp(_("GOODSIG"), &line[9], 7))
1273 {
1274 ++n_goodsig;
1275 sl_strlcpy (sign_id, &line[25], SH_MINIBUF+1);
1276 if (sign_id)
1277 sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing '"' */
1278 have_id = GOOD;
1279 }
1280 else if (0 == sl_strncmp(_("VALIDSIG"), &line[9], 8))
1281 {
1282 ++n_validsig;
1283 strncpy (sign_fp, &line[18], 40);
1284 sign_fp[40] = '\0';
1285 have_fp = GOOD;
1286 }
1287 else if (0 == sl_strncmp(_("NEWSIG"), &line[9], 6))
1288 {
1289 ++n_newsig;
1290 }
1291
1292 }
1293
1294 if (ferror(source.pipe) && errno == EAGAIN)
1295 {
1296 /* sleep 10 ms to avoid starving the gpg child writing to the pipe */
1297 retry_msleep(0,10);
1298 clearerr(source.pipe);
1299 goto xagain;
1300 }
1301
1302 if (0 != sh_sig_pclose (&source))
1303 {
1304 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1305 _("Error on closing process pipe"),
1306 _("gpg_check_file_sign"));
1307 have_id = BAD;
1308 }
1309
1310 TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n")));
1311
1312 if (n_goodsig != n_validsig || n_newsig > 1 || n_goodsig > 1)
1313 {
1314 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1315 _("Too many or invalid signatures"),
1316 _("gpg_check_file_sign"));
1317 have_id = BAD;
1318 }
1319
1320 if (have_id == GOOD)
1321 {
1322 TPT(((0), FIL__, __LINE__, _("msg=<Got signator ID>\n")));
1323 }
1324 if (have_fp == GOOD)
1325 {
1326 TPT(((0), FIL__, __LINE__, _("msg=<Got fingerprint>\n")));
1327 }
1328
1329 if (have_id == GOOD && have_fp == GOOD)
1330 SL_RETURN( SH_SIG_OK, _("sh_gpg_check_file_sign"));
1331 else
1332 {
1333 if (have_id == BAD)
1334 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1335 _("No good signature"),
1336 _("gpg_check_file_sign"));
1337 else
1338 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1339 _("No fingerprint for key"),
1340 _("gpg_check_file_sign"));
1341 SL_RETURN( SH_SIG_BADSIGN, _("sh_gpg_check_file_sign"));
1342 }
1343}
1344
1345#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && \
1346 defined(HAVE_GETPWNAM_R)
1347#define USE_GETPWNAM_R 1
1348#endif
1349
1350static
1351int sh_gpg_check_signature (SL_TICKET file, ShSigFile what)
1352{
1353 int status = SH_SIG_BAD;
1354 int fd = 0;
1355
1356 static int smsg = S_FALSE;
1357 char * tmp;
1358
1359 char * sig_id;
1360 char * sig_fp;
1361
1362 char * homedir = sh.effective.home;
1363#if defined(SH_WITH_SERVER)
1364 struct passwd * tempres;
1365#if defined(USE_GETPWNAM_R)
1366 struct passwd pwd;
1367 char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
1368#endif
1369#endif
1370
1371#ifdef USE_FINGERPRINT
1372#include "sh_gpg_fp.h"
1373#endif
1374
1375 SL_ENTER(_("sh_gpg_check_sign"));
1376
1377
1378 if (what == SIG_CONF)
1379 fd = get_the_fd(file);
1380 if (what == SIG_DATA)
1381 fd = get_the_fd(file);
1382
1383
1384 if (fd < 0)
1385 {
1386 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
1387 dlog(1, FIL__, __LINE__,
1388 _("This looks like an unexpected internal error.\n"));
1389#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1390 SH_FREE(buffer);
1391#endif
1392 SL_RETURN( (-1), _("sh_gpg_check_sign"));
1393 }
1394
1395#if defined(SH_WITH_SERVER)
1396#if defined(USE_GETPWNAM_R)
1397 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
1398#else
1399 tempres = sh_getpwnam(DEFAULT_IDENT);
1400#endif
1401 if ((tempres != NULL) && (0 == sl_ret_euid()))
1402 {
1403 /* privileges not dropped yet*/
1404 homedir = tempres->pw_dir;
1405 }
1406#endif
1407
1408 if (what == SIG_CONF)
1409 {
1410 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
1411 status = sh_gpg_check_file_sign(fd, gp.conf_id, gp.conf_fp, homedir, SIG_CONF);
1412 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGUSR: |%s|>\n"), gp.conf_id));
1413 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGFP: |%s|>\n"), gp.conf_fp));
1414 sig_id = gp.conf_id; sig_fp = gp.conf_fp;
1415 }
1416
1417 if (what == SIG_DATA)
1418 {
1419 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
1420 status = sh_gpg_check_file_sign(fd, gp.data_id, gp.data_fp, homedir, SIG_DATA);
1421 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGUSR: |%s|>\n"), gp.data_id));
1422 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGFP: |%s|>\n"), gp.data_fp));
1423 sig_id = gp.data_id; sig_fp = gp.data_fp;
1424 }
1425
1426 if (SH_SIG_OK == status)
1427 {
1428#ifdef USE_FINGERPRINT
1429 if ((sl_strcmp(SH_GPG_FP, sig_fp) == 0))
1430 {
1431 int i;
1432
1433 for(i = 0; i < (int) sl_strlen(sig_fp); ++i) {
1434 if (gpgfp[i] != sig_fp[i]) {
1435 sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
1436 MSG_E_GPG_FP, gpgfp, sig_fp);
1437 break; }
1438 }
1439
1440 if (smsg == S_FALSE) {
1441 tmp = sh_util_safe_name(sig_id);
1442 sh_sig_fill_startup (__LINE__, sh.prg_name, sh.real.uid,
1443 (sh.flag.hidefile == S_TRUE) ?
1444 _("(hidden)") : file_path('C', 'R'),
1445 tmp,
1446 sig_fp);
1447 SH_FREE(tmp); }
1448 smsg = S_TRUE;
1449
1450#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1451 SH_FREE(buffer);
1452#endif
1453 SL_RETURN(0, _("sh_gpg_check_sign"));
1454 }
1455 else
1456 {
1457 /* fp mismatch */
1458 dlog(1, FIL__, __LINE__,
1459 _("The fingerprint of the signing key: %s\ndoes not match the compiled-in fingerprint: %s.\nTherefore the signature could not be verified.\n"),
1460 sig_fp, SH_GPG_FP);
1461 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1462 _("Fingerprint mismatch"), _("gpg_check_sign"));
1463 status = SH_SIG_BADSIGN;
1464 }
1465#else /* ifdef USE_FINGERPRINT */
1466 if (smsg == S_FALSE)
1467 {
1468 tmp = sh_util_safe_name(sig_id);
1469 sh_sig_fill_startup (__LINE__,
1470 sh.prg_name, sh.real.uid,
1471 (sh.flag.hidefile == S_TRUE) ?
1472 _("(hidden)") : file_path('C', 'R'),
1473 tmp, sig_fp);
1474 SH_FREE(tmp);
1475 }
1476 smsg = S_TRUE;
1477
1478#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1479 SH_FREE(buffer);
1480#endif
1481
1482 /* status == OK and no fp checking */
1483 SL_RETURN(0, _("sh_gpg_check_sign"));
1484#endif /* !ifdef USE_FINGERPRINT */
1485 }
1486
1487 if (status != SH_SIG_OK)
1488 {
1489 uid_t e_uid = sl_ret_euid();
1490 char * e_home = sh.effective.home;
1491
1492#if defined(SH_WITH_SERVER)
1493#if defined(USE_GETPWNAM_R)
1494 struct passwd e_pwd;
1495 char * e_buffer = SH_ALLOC(SH_PWBUF_SIZE);
1496 struct passwd * e_tempres;
1497 sh_getpwnam_r(DEFAULT_IDENT, &e_pwd, e_buffer, SH_PWBUF_SIZE, &e_tempres);
1498#else
1499 struct passwd * e_tempres = sh_getpwnam(DEFAULT_IDENT);
1500#endif
1501
1502 if ((e_tempres != NULL) && (0 == sl_ret_euid()))
1503 {
1504 /* privileges not dropped yet */
1505 e_uid = e_tempres->pw_uid;
1506 e_home = e_tempres->pw_dir;
1507 }
1508#endif
1509 dlog(1, FIL__, __LINE__,
1510 _("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"),
1511 DEFAULT_SIG_PATH,
1512 (int) e_uid, e_home);
1513
1514#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1515 SH_FREE(e_buffer);
1516#endif
1517 }
1518
1519 TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status));
1520
1521 SL_RETURN(-1, _("sh_gpg_check_sign")); /* make compiler happy */
1522}
1523
1524static int sh_gpg_comp(const char * line, const char * cmp)
1525{
1526 int retval = S_FALSE;
1527
1528 if (line && line[0] == '-' && line[1] == '-')
1529 {
1530 char * dup = sh_util_strdup(line);
1531 char * tmp = dup + sl_strlen( dup );
1532 --tmp;
1533 if (*tmp == '\n') { *tmp = '\0'; --tmp; }
1534 while( (*tmp == '\t' || *tmp == ' ' || *tmp == '\r' ) && tmp >= dup ) *tmp-- = '\0';
1535
1536 if (0 == sl_strcmp(dup, cmp))
1537 retval = S_TRUE;
1538 SH_FREE(dup);
1539 }
1540 return retval;
1541}
1542
1543static
1544int sh_gpg_msg_start(const char * line)
1545{
1546 static char cmp[SH_MINIBUF];
1547 static int initialized = 0;
1548
1549 if (initialized == 0) {
1550 sl_strlcpy(cmp, _("-----BEGIN PGP SIGNED MESSAGE-----"), sizeof(cmp));
1551 initialized = 1;
1552 }
1553 return sh_gpg_comp(line, cmp);
1554}
1555
1556static
1557int sh_gpg_msg_startdata(const char * line)
1558{
1559 if (line[0] == '\n')
1560 return S_TRUE;
1561 return S_FALSE;
1562}
1563
1564static
1565int sh_gpg_msg_end(const char * line)
1566{
1567 static char cmp[SH_MINIBUF];
1568 static int initialized = 0;
1569
1570 if (initialized == 0) {
1571 sl_strlcpy(cmp, _("-----BEGIN PGP SIGNATURE-----"), sizeof(cmp));
1572 initialized = 1;
1573 }
1574 return sh_gpg_comp(line, cmp);
1575}
1576
1577static
1578int sh_gpg_sig_end(const char * line)
1579{
1580 static char cmp[SH_MINIBUF];
1581 static int initialized = 0;
1582
1583 if (initialized == 0) {
1584 sl_strlcpy(cmp, _("-----END PGP SIGNATURE-----"), sizeof(cmp));
1585 initialized = 1;
1586 }
1587 return sh_gpg_comp(line, cmp);
1588}
1589
1590static
1591SL_TICKET sh_gpg_extract_signed(SL_TICKET fd, extractlevel extract_level)
1592{
1593 const int fgets_buf_size = 16384;
1594 FILE * fin_cp = NULL;
1595 char * buf = NULL;
1596 int bufc;
1597 int flag_pgp = S_FALSE;
1598 int flag_nohead = S_FALSE;
1599 SL_TICKET fdTmp = (-1);
1600 SL_TICKET open_tmp (void);
1601
1602 /* extract the data and copy to temporary file
1603 */
1604 fdTmp = open_tmp();
1605 if (SL_ISERROR(fdTmp))
1606 {
1607 dlog(1, FIL__, __LINE__, _("Error opening temporary file.\n"));
1608 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1609 _("Error opening temporary file."),
1610 _("sh_gpg_extract_signed"));
1611 return -1;
1612 }
1613
1614 fin_cp = fdopen(dup(get_the_fd(fd)), "rb");
1615 buf = SH_ALLOC(fgets_buf_size);
1616
1617 while (NULL != fgets(buf, fgets_buf_size, fin_cp))
1618 {
1619 bufc = 0;
1620 while (bufc < fgets_buf_size) {
1621 if (buf[bufc] == '\n') { ++bufc; break; }
1622 ++bufc;
1623 }
1624
1625 if (flag_pgp == S_FALSE && sh_gpg_msg_start(buf) == S_TRUE)
1626 {
1627 flag_pgp = S_TRUE;
1628 if (extract_level == SIG_DATASIG)
1629 sl_write(fdTmp, buf, bufc);
1630 continue;
1631 }
1632
1633 if (flag_pgp == S_TRUE && flag_nohead == S_FALSE)
1634 {
1635 /* Header finished */
1636 if (buf[0] == '\n')
1637 {
1638 flag_nohead = S_TRUE;
1639 if (extract_level == SIG_DATASIG)
1640 sl_write(fdTmp, buf, 1);
1641 continue;
1642 }
1643 /* copy these headers */
1644 else if (0 == sl_strncmp(buf, _("Hash:"), 5) ||
1645 0 == sl_strncmp(buf, _("NotDashEscaped:"), 15))
1646 {
1647 if (extract_level == SIG_DATASIG)
1648 sl_write(fdTmp, buf, bufc);
1649 continue;
1650 }
1651 /* ignore other headers */
1652 else
1653 continue;
1654 }
1655
1656 if (flag_pgp == S_TRUE && buf[0] == '\n')
1657 {
1658 sl_write(fdTmp, buf, 1);
1659 }
1660 else if (flag_pgp == S_TRUE)
1661 {
1662 if (extract_level == SIG_DATASIG) {
1663 sl_write(fdTmp, buf, bufc);
1664 }
1665 else {
1666 if (sh_gpg_msg_end(buf) == S_TRUE)
1667 break;
1668 else
1669 sl_write(fdTmp, buf, bufc);
1670 }
1671 }
1672
1673 /* This is after the copy has been done. */
1674 if (flag_pgp == S_TRUE && sh_gpg_sig_end(buf) == S_TRUE)
1675 break;
1676 }
1677 SH_FREE(buf);
1678 sl_fclose(FIL__, __LINE__, fin_cp);
1679 sl_rewind (fdTmp);
1680
1681 return fdTmp;
1682}
1683#endif
1684
1685/*********************************************************************
1686 *
1687 * Exported functions
1688 *
1689 *********************************************************************/
1690
1691int sh_sig_check_signature (SL_TICKET file, ShSigFile what)
1692{
1693#if defined(WITH_GPG)
1694 return sh_gpg_check_signature (file, what);
1695#elif defined(WITH_SIGNIFY)
1696 return sh_signify_check_signature (file, what);
1697#else
1698 return -1;
1699#endif
1700}
1701
1702SL_TICKET sh_sig_extract_signed(SL_TICKET fd)
1703{
1704#if defined(WITH_GPG)
1705 return sh_gpg_extract_signed(fd, SIG_DATASIG);
1706#elif defined(WITH_SIGNIFY)
1707 return sh_signify_extract_signed(fd, SIG_DATASIG);
1708#else
1709 return -1;
1710#endif
1711}
1712
1713SL_TICKET sh_sig_extract_signed_data(SL_TICKET fd)
1714{
1715#if defined(WITH_GPG)
1716 return sh_gpg_extract_signed(fd, SIG_DATAONLY);
1717#elif defined(WITH_SIGNIFY)
1718 return sh_signify_extract_signed(fd, SIG_DATAONLY);
1719#else
1720 return -1;
1721#endif
1722}
1723
1724int sh_sig_msg_start(const char * line)
1725{
1726#if defined(WITH_GPG)
1727 return sh_gpg_msg_start(line);
1728#elif defined(WITH_SIGNIFY)
1729 return sh_signify_msg_start(line);
1730#else
1731 return -1;
1732#endif
1733}
1734
1735int sh_sig_msg_startdata(const char * line)
1736{
1737#if defined(WITH_GPG)
1738 return sh_gpg_msg_startdata(line);
1739#elif defined(WITH_SIGNIFY)
1740 return sh_signify_msg_startdata(line);
1741#else
1742 return -1;
1743#endif
1744}
1745
1746int sh_sig_msg_end(const char * line)
1747{
1748#if defined(WITH_GPG)
1749 return sh_gpg_msg_end(line);
1750#elif defined(WITH_SIGNIFY)
1751 return sh_signify_msg_end(line);
1752#else
1753 return -1;
1754#endif
1755}
1756
1757int sh_sig_data_end(const char * line)
1758{
1759#if defined(WITH_GPG)
1760 return sh_gpg_sig_end(line);
1761#elif defined(WITH_SIGNIFY)
1762 return sh_signify_data_end(line);
1763#else
1764 return -1;
1765#endif
1766}
1767
1768void sh_sig_log_startup (void)
1769{
1770 if (startInfo.program != NULL)
1771 {
1772 sh_error_handle ((-1), FIL__, startInfo.line, 0, MSG_START_GH,
1773 startInfo.program, startInfo.uid,
1774 startInfo.path,
1775 startInfo.key_uid, startInfo.key_id);
1776 }
1777 return;
1778}
1779
1780/* #ifdef WITH_SIG */
1781#endif
1782
1783
1784
1785
1786
1787
1788
1789
Note: See TracBrowser for help on using the repository browser.