source: trunk/src/sh_sig.c@ 569

Last change on this file since 569 was 561, checked in by katerina, 3 years ago

Fix for ticket #451 (signify-openbsd in client/server mode not working).

File size: 45.7 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) 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
1130static
1131int 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
1336static
1337int 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
1510static 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
1529static
1530int 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
1542static
1543int sh_gpg_msg_startdata(const char * line)
1544{
1545 if (line[0] == '\n')
1546 return S_TRUE;
1547 return S_FALSE;
1548}
1549
1550static
1551int 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
1563static
1564int 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
1576static
1577SL_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
1677int 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
1686SL_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
1695SL_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
1704int 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
1713int 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
1722int 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
1731int 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
1740void 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
Note: See TracBrowser for help on using the repository browser.