source: trunk/src/sh_sig.c@ 592

Last change on this file since 592 was 592, checked in by katerina, 44 hours ago

Fixes for compiler warnings.

File size: 46.6 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 1999, 2000 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24
25
26#if defined(WITH_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 int close_tmp ( SL_TICKET);
649
650 /* extract the data and copy to temporary file
651 */
652 fdTmp = open_tmp();
653 if (SL_ISERROR(fdTmp))
654 {
655 dlog(1, FIL__, __LINE__, _("Error opening temporary file.\n"));
656 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
657 _("Error opening temporary file."),
658 _("sh_signify_extract_signed"));
659 return -1;
660 }
661
662 fin_cp = fdopen(dup(get_the_fd(fd)), "rb");
663 if (!fin_cp) { close_tmp(fdTmp); return -1; }
664 buf = SH_ALLOC(fgets_buf_size);
665
666 while (NULL != fgets(buf, fgets_buf_size, fin_cp))
667 {
668
669 bufc = 0;
670 while (bufc < fgets_buf_size) {
671 if (buf[bufc] == '\n') { ++bufc; break; }
672 ++bufc;
673 }
674
675 if (flag_comm == S_FALSE)
676 {
677 if (sh_signify_comp_comm(buf, &commlen) == S_TRUE)
678 {
679 flag_comm = S_TRUE;
680 if (extract_level == SIG_DATASIG)
681 {
682 comment = sh_util_strdup(buf);
683 commlen = bufc;
684 }
685 }
686 continue;
687 }
688 else if (flag_comm == S_TRUE && flag_sig == S_FALSE)
689 {
690 if (sh_signify_comp_sig(buf, commlen) == S_TRUE)
691 {
692 flag_sig = S_TRUE;
693 if (extract_level == SIG_DATASIG)
694 {
695 sl_write(fdTmp, comment, commlen);
696 sl_write(fdTmp, buf, bufc);
697 }
698 if (comment != NULL)
699 SH_FREE(comment);
700 comment = NULL;
701 }
702 else
703 {
704 if (comment != NULL)
705 SH_FREE(comment);
706 comment = NULL; commlen = 0; flag_comm = 0;
707 }
708 continue;
709 }
710
711 if (flag_sig == S_TRUE)
712 {
713 sl_write(fdTmp, buf, bufc);
714 }
715 }
716 if (comment != NULL)
717 SH_FREE(comment);
718 sl_fclose(FIL__, __LINE__, fin_cp);
719 sl_rewind (fdTmp);
720
721#if defined(SH_DEBUG_SIGNIFY)
722 fin_cp = fdopen(dup(get_the_fd(fdTmp)), "rb");
723 FILE * fout = fopen("xxx.out", "w+");
724 if (!fout) { close_tmp(fdTmp); return -1; }
725 if (!fin_cp) { close_tmp(fdTmp); fclose(fout); return -1; }
726 while (NULL != fgets(buf, fgets_buf_size, fin_cp))
727 {
728 fputs(buf, fout);
729 }
730 fclose(fout);
731 sl_rewind(fdTmp);
732#endif
733
734 SH_FREE(buf);
735 return fdTmp;
736}
737
738
739static FILE * sh_signify_popen (sh_gpg_popen_t *source, int fd, char * homedir)
740{
741 char path[256];
742 char cc1[32];
743 char cc2[32];
744 char cc3[32];
745 char cc4[SH_PATHBUF+32];
746 char cc5[32];
747 char cc6[32];
748 char * argv[9];
749 FILE * retval = NULL;
750
751 struct stat lbuf;
752 int status_stat = 0;
753
754#ifdef HAVE_SIG_KEY_HASH
755 SL_TICKET checkfd;
756#endif
757
758
759 SL_ENTER(_("sh_signify_popen"));
760
761 sl_strlcpy (path, DEFAULT_SIG_PATH, 256);
762
763 sl_strlcpy (cc1, _("-Vem"), 32);
764 sl_strlcpy (cc2, _("/dev/null"), 32);
765
766 sl_strlcpy (cc3, _("-p"), 32);
767 sl_strlcpy (cc4, homedir, SH_PATHBUF+32);
768 sl_strlcat (cc4, _("/.signify/"), SH_PATHBUF+32);
769 sl_strlcat (cc4, SH_INSTALL_NAME, SH_PATHBUF+32);
770 sl_strlcat (cc4, _(".pub"), SH_PATHBUF+32);
771
772 /* read signed message from stdin */
773 sl_strlcpy (cc5, _("-x"), 32);
774 sl_strlcpy (cc6, _("-"), 32);
775
776 status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf);
777 if (status_stat == -1)
778 {
779 dlog(1, FIL__, __LINE__,
780 _("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"),
781 cc4);
782 sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1,
783 sh.prg_name);
784 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
785 }
786#ifdef HAVE_SIG_KEY_HASH
787 checkfd = sl_open_read(FIL__, __LINE__, cc4, SL_YESPRIV);
788
789 if (0 != sh_sig_checksum(checkfd, SIG_HASH_OTHER, SIG_KEY_HASH, cc4))
790 {
791 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
792 _("Checksum mismatch for signify public key"),
793 _("signify_popen"));
794 sl_close(checkfd);
795 sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1,
796 sh.prg_name);
797 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
798 }
799 sl_close(checkfd);
800#endif
801
802 argv[0] = path;
803 argv[1] = cc1;
804 argv[2] = cc2;
805 argv[3] = cc3;
806 argv[4] = cc4;
807 argv[5] = cc5;
808 argv[6] = cc6;
809 argv[7] = NULL;
810
811 retval = sh_sig_popen(argv, source, fd);
812 SL_RETURN((retval), _("sh_signify_popen"));
813}
814
815static
816int sh_signify_check_file_sign(int fd, char * homedir)
817{
818 struct stat buf;
819 char line[256];
820 sh_gpg_popen_t source;
821 int status = 0;
822 unsigned int n_goodsig = 0;
823 unsigned int n_lines = 0;
824
825#ifdef HAVE_SIG_CHECKSUM
826 SL_TICKET checkfd;
827#endif
828
829 SL_ENTER(_("sh_signify_check_file_sign"));
830
831 /* check whether signify exists and has the correct checksum
832 */
833 TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
834 TPT(((0), FIL__, __LINE__, _("msg=<signify is %s>\n"), DEFAULT_SIG_PATH));
835
836 if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_SIG_PATH, &buf))
837 {
838 char errbuf[SH_ERRBUF_SIZE];
839
840 status = errno;
841 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
842 sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_SIG_PATH);
843 SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign"));
844 }
845
846 if (0 != tf_trust_check (DEFAULT_SIG_PATH, SL_YESPRIV))
847 SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign"));
848
849#ifdef HAVE_SIG_CHECKSUM
850 checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_SIG_PATH, SL_YESPRIV);
851
852 if (0 != sh_sig_checksum(checkfd, SIG_HASH_REPORTFULL, NULL, NULL))
853 {
854 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
855 _("Checksum mismatch"),
856 _("signify_check_file_sign"));
857 sl_close(checkfd);
858 SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign"));
859 }
860 sl_close(checkfd);
861#endif
862
863 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n")));
864
865 fflush(NULL);
866
867 source.pipe = sh_signify_popen ( &source, fd, homedir );
868
869 if (NULL == source.pipe)
870 {
871 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
872 _("Could not open pipe"),
873 _("signify_check_file_sign"));
874 SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign"));
875 }
876
877 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
878
879 xagain:
880
881 errno = 0;
882
883 while (NULL != fgets(line, sizeof(line), source.pipe))
884 {
885 TPT(((0), FIL__, __LINE__, _("msg=<signify out: %s>\n"), line));
886 if (line[strlen(line)-1] == '\n')
887 line[strlen(line)-1] = ' ';
888 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
889 line,
890 _("signify_check_file_sign"));
891
892 ++n_lines;
893
894 /* the '\n' has been replaced with ' ' for logging */
895 if (0 == sl_strcmp(_("Signature Verified "), line))
896 {
897 ++n_goodsig;
898 }
899 }
900
901 if (ferror(source.pipe) && errno == EAGAIN)
902 {
903 /* sleep 10 ms to avoid starving the gpg child writing to the pipe */
904 retry_msleep(0,10);
905 clearerr(source.pipe);
906 goto xagain;
907 }
908
909 if (0 != sh_sig_pclose (&source))
910 {
911 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
912 _("Error on closing process pipe"),
913 _("signify_check_file_sign"));
914 n_goodsig = 0;
915 }
916
917 TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n")));
918
919 if (n_goodsig == 1 && n_lines == 1)
920 {
921 TPT(((0), FIL__, __LINE__, _("msg=<Signature Verified>\n")));
922 SL_RETURN( SH_SIG_OK, _("sh_signature_check_file_sign"));
923 }
924 else
925 {
926 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
927 _("Error verifying file signature"),
928 _("signify_check_file_sign"));
929 }
930 SL_RETURN( SH_SIG_BADSIGN, _("sh_signature_check_file_sign"));
931}
932
933
934int sh_signify_check_signature (SL_TICKET file, ShSigFile what)
935{
936 int status = SH_SIG_BAD;
937 int fd = 0;
938
939 static int smsg = S_FALSE;
940
941 char * homedir = sh.effective.home;
942 char * home_alloc = NULL;
943#if defined(SH_WITH_SERVER)
944 struct passwd * tempres;
945#if defined(USE_GETPWNAM_R)
946 struct passwd pwd;
947 char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
948#endif
949#endif
950
951 SL_ENTER(_("sh_signify_check_sign"));
952
953 (void) what;
954
955 fd = get_the_fd(file);
956
957 if (fd < 0)
958 {
959 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
960 dlog(1, FIL__, __LINE__,
961 _("This looks like an unexpected internal error.\n"));
962#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
963 SH_FREE(buffer);
964#endif
965 SL_RETURN( (-1), _("sh_signify_check_sign"));
966 }
967
968#if defined(SH_WITH_SERVER)
969#if defined(USE_GETPWNAM_R)
970 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
971#else
972 tempres = sh_getpwnam(DEFAULT_IDENT);
973#endif
974 if ((tempres != NULL) && (0 == sl_ret_euid()))
975 {
976 /* privileges not dropped yet*/
977 homedir = tempres->pw_dir;
978 }
979#endif
980
981 home_alloc = sh_util_strdup(homedir);
982
983 TPT(((0), FIL__, __LINE__, _("msg=<SIGNIFY_CHECK: FD = %d>\n"), fd));
984 status = sh_signify_check_file_sign(fd, homedir);
985
986 if (status != SH_SIG_OK)
987 {
988 TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status));
989 dlog(1, FIL__, __LINE__,
990 _("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"),
991 DEFAULT_SIG_PATH, home_alloc, SH_INSTALL_NAME);
992 SH_FREE(home_alloc);
993 SL_RETURN( (-1), _("sh_signify_check_sign"));
994 }
995
996 if (smsg == S_FALSE)
997 {
998 sh_sig_fill_startup (__LINE__,
999 sh.prg_name, sh.real.uid,
1000 (sh.flag.hidefile == S_TRUE) ?
1001 _("(hidden)") : file_path('C', 'R'),
1002 NULL, NULL);
1003 }
1004 smsg = S_TRUE;
1005
1006 SH_FREE(home_alloc);
1007 SL_RETURN(0, _("sh_signify_check_sign"));
1008}
1009
1010/* This is GPG specific stuff
1011 */
1012#elif defined(WITH_GPG)
1013static FILE * sh_gpg_popen (sh_gpg_popen_t *source, int fd, char * homedir)
1014{
1015 char path[256];
1016 char cc1[32];
1017 char cc2[32];
1018
1019 char cc0[2] = "-";
1020 char cc3[32];
1021 char cc4[SH_PATHBUF+32];
1022 char cc5[32];
1023 char * argv[9];
1024 FILE * retval = NULL;
1025
1026
1027 SL_ENTER(_("sh_gpg_popen"));
1028
1029 /* -- GnuPG -- */
1030 sl_strlcpy (path, DEFAULT_SIG_PATH, 256);
1031 sl_strlcpy (cc1, _("--status-fd"), 32);
1032 sl_strlcpy (cc2, _("--verify"), 32);
1033 sl_strlcpy (cc3, _("--homedir"), 32);
1034 /* sl_strlcpy (cc4, sh.effective.home, SH_PATHBUF+32); */
1035 sl_strlcpy (cc4, homedir, SH_PATHBUF+32);
1036 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
1037 sl_strlcpy (cc5, _("--no-tty"), 32);
1038
1039#if defined(SH_WITH_SERVER)
1040 if (0 == sl_ret_euid()) /* privileges not dropped yet */
1041 {
1042 struct stat lbuf;
1043 int status_stat = 0;
1044#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1045 struct passwd pwd;
1046 char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
1047 struct passwd * tempres;
1048 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
1049#else
1050 struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
1051#endif
1052
1053 if (!tempres)
1054 {
1055 dlog(1, FIL__, __LINE__,
1056 _("User %s does not exist. Please add the user to your system.\n"),
1057 DEFAULT_IDENT);
1058 status_stat = -1;
1059 }
1060 if (!tempres->pw_dir || tempres->pw_dir[0] == '\0')
1061 {
1062 dlog(1, FIL__, __LINE__,
1063 _("User %s does not have a home directory.\nPlease add the home directory for this user to your system.\n"),
1064 DEFAULT_IDENT);
1065 status_stat = -2;
1066 }
1067 if (status_stat == 0)
1068 {
1069 sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
1070 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
1071 status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf);
1072 if (status_stat == -1)
1073 {
1074 dlog(1, FIL__, __LINE__,
1075 _("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"),
1076 cc4, DEFAULT_IDENT);
1077 status_stat = -3;
1078 }
1079 }
1080 if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
1081 {
1082 dlog(1, FIL__, __LINE__,
1083 _("Gnupg directory %s\nis not owned by user %s.\n"),
1084 cc4, DEFAULT_IDENT);
1085 status_stat = -4;
1086 }
1087 if (status_stat == 0)
1088 {
1089 char cc4_test[SH_PATHBUF+32];
1090
1091 sl_strlcpy(cc4_test, cc4, SH_PATHBUF+32);
1092 sl_strlcat (cc4_test, _("/pubring.gpg"), SH_PATHBUF+32);
1093
1094 status_stat = retry_lstat(FIL__, __LINE__, cc4_test, &lbuf);
1095 if (status_stat == -1)
1096 {
1097 sl_strlcpy(cc4_test, cc4, SH_PATHBUF+32);
1098 sl_strlcat (cc4_test, _("/pubring.kbx"), SH_PATHBUF+32);
1099
1100 status_stat = retry_lstat(FIL__, __LINE__, cc4_test, &lbuf);
1101 if (status_stat == -1)
1102 {
1103 sl_strlcpy(cc4_test, cc4, SH_PATHBUF+32);
1104 sl_strlcat (cc4_test, _("/pubring.(gpg|kbx)"), SH_PATHBUF+32);
1105
1106 dlog(1, FIL__, __LINE__,
1107 _("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"),
1108 cc4_test, DEFAULT_IDENT);
1109 status_stat = -5;
1110 }
1111 }
1112 }
1113 if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
1114 {
1115 dlog(1, FIL__, __LINE__,
1116 _("Gnupg public keyring %s\nis not owned by user %s.\n"),
1117 cc4, DEFAULT_IDENT);
1118 status_stat = -6;
1119 }
1120 if (status_stat != 0)
1121 {
1122 sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1,
1123 sh.prg_name);
1124 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1125 }
1126 sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
1127 sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
1128#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1129 SH_FREE(buffer);
1130#endif
1131 }
1132#endif
1133
1134 argv[0] = path;
1135 argv[1] = cc1;
1136 argv[2] = "1";
1137 argv[3] = cc2;
1138 argv[4] = cc3;
1139 argv[5] = cc4;
1140 argv[6] = cc5;
1141 argv[7] = cc0;
1142 argv[8] = NULL;
1143
1144 retval = sh_sig_popen(argv, source, fd);
1145 SL_RETURN((retval), _("sh_gpg_popen"));
1146}
1147
1148static
1149int sh_gpg_check_file_sign(int fd, char * sign_id, char * sign_fp,
1150 char * homedir, ShSigFile whichfile)
1151{
1152 struct stat buf;
1153 char line[256];
1154 sh_gpg_popen_t source;
1155 int have_id = BAD, have_fp = BAD, status = 0;
1156 unsigned int n_newsig = 0;
1157 unsigned int n_goodsig = 0;
1158 unsigned int n_validsig = 0;
1159
1160#ifdef HAVE_SIG_CHECKSUM
1161 SL_TICKET checkfd;
1162#endif
1163
1164 SL_ENTER(_("sh_gpg_check_file_sign"));
1165
1166 /* check whether GnuPG exists and has the correct checksum
1167 */
1168 TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
1169 TPT(((0), FIL__, __LINE__, _("msg=<gpg is %s>\n"), DEFAULT_SIG_PATH));
1170
1171 if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_SIG_PATH, &buf))
1172 {
1173 char errbuf[SH_ERRBUF_SIZE];
1174
1175 status = errno;
1176 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
1177 sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_SIG_PATH);
1178 SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1179 }
1180
1181 if (0 != tf_trust_check (DEFAULT_SIG_PATH, SL_YESPRIV))
1182 SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1183
1184#ifdef HAVE_SIG_CHECKSUM
1185 checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_SIG_PATH, SL_YESPRIV);
1186
1187 if (0 != sh_sig_checksum(checkfd, SIG_HASH_REPORTFULL, NULL, NULL))
1188 {
1189 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1190 _("Checksum mismatch"),
1191 _("gpg_check_file_sign"));
1192 sl_close(checkfd);
1193 SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1194 }
1195 sl_close(checkfd);
1196#endif
1197
1198 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n")));
1199
1200 fflush(NULL);
1201
1202 source.pipe = sh_gpg_popen ( &source, fd, homedir );
1203
1204 if (NULL == source.pipe)
1205 {
1206 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1207 _("Could not open pipe"),
1208 _("gpg_check_file_sign"));
1209 SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign"));
1210 }
1211
1212 TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
1213
1214 xagain:
1215
1216 errno = 0;
1217
1218 while (NULL != fgets(line, sizeof(line), source.pipe))
1219 {
1220
1221 TPT(((0), FIL__, __LINE__, _("msg=<gpg out: %s>\n"), line));
1222 if (line[strlen(line)-1] == '\n')
1223 line[strlen(line)-1] = ' ';
1224 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1225 line,
1226 _("gpg_check_file_sign"));
1227
1228 if (sl_strlen(line) < 12)
1229 continue;
1230
1231 /* Sun May 27 18:40:05 CEST 2001
1232 */
1233 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6) ||
1234 0 == sl_strncmp(_("ERRSIG"), &line[9], 6) ||
1235 0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6) ||
1236 0 == sl_strncmp(_("NODATA"), &line[9], 6) ||
1237 0 == sl_strncmp(_("ERROR"), &line[9], 5) ||
1238 0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6))
1239 {
1240 if (0 == sl_strncmp(_("BADSIG"), &line[9], 6)) {
1241 dlog(1, FIL__, __LINE__,
1242 _("%s file is signed, but the signature is invalid."),
1243 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1244 }
1245 else if (0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6)) {
1246 dlog(1, FIL__, __LINE__,
1247 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
1248 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")),
1249 homedir);
1250 }
1251 else if (0 == sl_strncmp(_("ERRSIG"), &line[9], 6)) {
1252 dlog(1, FIL__, __LINE__,
1253 _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
1254 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")),
1255 homedir);
1256 }
1257 else if (0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) {
1258 dlog(1, FIL__, __LINE__,
1259 _("%s file is signed, but the public key to verify the signature has expired."),
1260 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1261 }
1262 else if (0 == sl_strncmp(_("NODATA"), &line[9], 6)) {
1263 dlog(1, FIL__, __LINE__,
1264 _("%s file is not signed."),
1265 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1266 }
1267 else if (0 == sl_strncmp(_("ERROR"), &line[9], 5)) {
1268 dlog(1, FIL__, __LINE__,
1269 _("%s file is not correctly signed. An error occured while verifying the signature."),
1270 ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")));
1271 }
1272
1273 have_fp = BAD; have_id = BAD;
1274 break;
1275 }
1276 if (0 == sl_strncmp(_("GOODSIG"), &line[9], 7))
1277 {
1278 ++n_goodsig;
1279 sl_strlcpy (sign_id, &line[25], SH_MINIBUF+1);
1280 if (sign_id)
1281 sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing '"' */
1282 have_id = GOOD;
1283 }
1284 else if (0 == sl_strncmp(_("VALIDSIG"), &line[9], 8))
1285 {
1286 ++n_validsig;
1287 strncpy (sign_fp, &line[18], 40);
1288 sign_fp[40] = '\0';
1289 have_fp = GOOD;
1290 }
1291 else if (0 == sl_strncmp(_("NEWSIG"), &line[9], 6))
1292 {
1293 ++n_newsig;
1294 }
1295
1296 }
1297
1298 if (ferror(source.pipe) && errno == EAGAIN)
1299 {
1300 /* sleep 10 ms to avoid starving the gpg child writing to the pipe */
1301 retry_msleep(0,10);
1302 clearerr(source.pipe);
1303 goto xagain;
1304 }
1305
1306 if (0 != sh_sig_pclose (&source))
1307 {
1308 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1309 _("Error on closing process pipe"),
1310 _("gpg_check_file_sign"));
1311 have_id = BAD;
1312 }
1313
1314 TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n")));
1315
1316 if (n_goodsig != n_validsig || n_newsig > 1 || n_goodsig > 1)
1317 {
1318 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1319 _("Too many or invalid signatures"),
1320 _("gpg_check_file_sign"));
1321 have_id = BAD;
1322 }
1323
1324 if (have_id == GOOD)
1325 {
1326 TPT(((0), FIL__, __LINE__, _("msg=<Got signator ID>\n")));
1327 }
1328 if (have_fp == GOOD)
1329 {
1330 TPT(((0), FIL__, __LINE__, _("msg=<Got fingerprint>\n")));
1331 }
1332
1333 if (have_id == GOOD && have_fp == GOOD)
1334 SL_RETURN( SH_SIG_OK, _("sh_gpg_check_file_sign"));
1335 else
1336 {
1337 if (have_id == BAD)
1338 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1339 _("No good signature"),
1340 _("gpg_check_file_sign"));
1341 else
1342 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1343 _("No fingerprint for key"),
1344 _("gpg_check_file_sign"));
1345 SL_RETURN( SH_SIG_BADSIGN, _("sh_gpg_check_file_sign"));
1346 }
1347}
1348
1349#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && \
1350 defined(HAVE_GETPWNAM_R)
1351#define USE_GETPWNAM_R 1
1352#endif
1353
1354static
1355int sh_gpg_check_signature (SL_TICKET file, ShSigFile what)
1356{
1357 int status = SH_SIG_BAD;
1358 int fd = 0;
1359
1360 static int smsg = S_FALSE;
1361 char * tmp;
1362
1363 char * sig_id;
1364 char * sig_fp;
1365
1366 char * homedir = sh.effective.home;
1367#if defined(SH_WITH_SERVER)
1368 struct passwd * tempres;
1369#if defined(USE_GETPWNAM_R)
1370 struct passwd pwd;
1371 char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
1372#endif
1373#endif
1374
1375#ifdef USE_FINGERPRINT
1376#include "sh_gpg_fp.h"
1377#endif
1378
1379 SL_ENTER(_("sh_gpg_check_sign"));
1380
1381
1382 if (what == SIG_CONF)
1383 fd = get_the_fd(file);
1384 if (what == SIG_DATA)
1385 fd = get_the_fd(file);
1386
1387
1388 if (fd < 0)
1389 {
1390 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
1391 dlog(1, FIL__, __LINE__,
1392 _("This looks like an unexpected internal error.\n"));
1393#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1394 SH_FREE(buffer);
1395#endif
1396 SL_RETURN( (-1), _("sh_gpg_check_sign"));
1397 }
1398
1399#if defined(SH_WITH_SERVER)
1400#if defined(USE_GETPWNAM_R)
1401 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
1402#else
1403 tempres = sh_getpwnam(DEFAULT_IDENT);
1404#endif
1405 if ((tempres != NULL) && (0 == sl_ret_euid()))
1406 {
1407 /* privileges not dropped yet*/
1408 homedir = tempres->pw_dir;
1409 }
1410#endif
1411
1412 if (what == SIG_CONF)
1413 {
1414 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
1415 status = sh_gpg_check_file_sign(fd, gp.conf_id, gp.conf_fp, homedir, SIG_CONF);
1416 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGUSR: |%s|>\n"), gp.conf_id));
1417 TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGFP: |%s|>\n"), gp.conf_fp));
1418 sig_id = gp.conf_id; sig_fp = gp.conf_fp;
1419 }
1420
1421 if (what == SIG_DATA)
1422 {
1423 TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
1424 status = sh_gpg_check_file_sign(fd, gp.data_id, gp.data_fp, homedir, SIG_DATA);
1425 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGUSR: |%s|>\n"), gp.data_id));
1426 TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGFP: |%s|>\n"), gp.data_fp));
1427 sig_id = gp.data_id; sig_fp = gp.data_fp;
1428 }
1429
1430 if (SH_SIG_OK == status)
1431 {
1432#ifdef USE_FINGERPRINT
1433 if ((sl_strcmp(SH_GPG_FP, sig_fp) == 0))
1434 {
1435 int i;
1436
1437 for(i = 0; i < (int) sl_strlen(sig_fp); ++i) {
1438 if (gpgfp[i] != sig_fp[i]) {
1439 sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
1440 MSG_E_GPG_FP, gpgfp, sig_fp);
1441 break; }
1442 }
1443
1444 if (smsg == S_FALSE) {
1445 tmp = sh_util_safe_name(sig_id);
1446 sh_sig_fill_startup (__LINE__, sh.prg_name, sh.real.uid,
1447 (sh.flag.hidefile == S_TRUE) ?
1448 _("(hidden)") : file_path('C', 'R'),
1449 tmp,
1450 sig_fp);
1451 SH_FREE(tmp); }
1452 smsg = S_TRUE;
1453
1454#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1455 SH_FREE(buffer);
1456#endif
1457 SL_RETURN(0, _("sh_gpg_check_sign"));
1458 }
1459 else
1460 {
1461 /* fp mismatch */
1462 dlog(1, FIL__, __LINE__,
1463 _("The fingerprint of the signing key: %s\ndoes not match the compiled-in fingerprint: %s.\nTherefore the signature could not be verified.\n"),
1464 sig_fp, SH_GPG_FP);
1465 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1466 _("Fingerprint mismatch"), _("gpg_check_sign"));
1467 status = SH_SIG_BADSIGN;
1468 }
1469#else /* ifdef USE_FINGERPRINT */
1470 if (smsg == S_FALSE)
1471 {
1472 tmp = sh_util_safe_name(sig_id);
1473 sh_sig_fill_startup (__LINE__,
1474 sh.prg_name, sh.real.uid,
1475 (sh.flag.hidefile == S_TRUE) ?
1476 _("(hidden)") : file_path('C', 'R'),
1477 tmp, sig_fp);
1478 SH_FREE(tmp);
1479 }
1480 smsg = S_TRUE;
1481
1482#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1483 SH_FREE(buffer);
1484#endif
1485
1486 /* status == OK and no fp checking */
1487 SL_RETURN(0, _("sh_gpg_check_sign"));
1488#endif /* !ifdef USE_FINGERPRINT */
1489 }
1490
1491 if (status != SH_SIG_OK)
1492 {
1493 uid_t e_uid = sl_ret_euid();
1494 char * e_home = sh.effective.home;
1495
1496#if defined(SH_WITH_SERVER)
1497#if defined(USE_GETPWNAM_R)
1498 struct passwd e_pwd;
1499 char * e_buffer = SH_ALLOC(SH_PWBUF_SIZE);
1500 struct passwd * e_tempres;
1501 sh_getpwnam_r(DEFAULT_IDENT, &e_pwd, e_buffer, SH_PWBUF_SIZE, &e_tempres);
1502#else
1503 struct passwd * e_tempres = sh_getpwnam(DEFAULT_IDENT);
1504#endif
1505
1506 if ((e_tempres != NULL) && (0 == sl_ret_euid()))
1507 {
1508 /* privileges not dropped yet */
1509 e_uid = e_tempres->pw_uid;
1510 e_home = e_tempres->pw_dir;
1511 }
1512#endif
1513 dlog(1, FIL__, __LINE__,
1514 _("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"),
1515 DEFAULT_SIG_PATH,
1516 (int) e_uid, e_home);
1517
1518#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
1519 SH_FREE(e_buffer);
1520#endif
1521 }
1522
1523 TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status));
1524
1525 SL_RETURN(-1, _("sh_gpg_check_sign")); /* make compiler happy */
1526}
1527
1528static int sh_gpg_comp(const char * line, const char * cmp)
1529{
1530 int retval = S_FALSE;
1531
1532 if (line && line[0] == '-' && line[1] == '-')
1533 {
1534 char * dup = sh_util_strdup(line);
1535 char * tmp = dup + sl_strlen( dup );
1536 --tmp;
1537 if (*tmp == '\n') { *tmp = '\0'; --tmp; }
1538 while( (*tmp == '\t' || *tmp == ' ' || *tmp == '\r' ) && tmp >= dup ) *tmp-- = '\0';
1539
1540 if (0 == sl_strcmp(dup, cmp))
1541 retval = S_TRUE;
1542 SH_FREE(dup);
1543 }
1544 return retval;
1545}
1546
1547static
1548int sh_gpg_msg_start(const char * line)
1549{
1550 static char cmp[SH_MINIBUF];
1551 static int initialized = 0;
1552
1553 if (initialized == 0) {
1554 sl_strlcpy(cmp, _("-----BEGIN PGP SIGNED MESSAGE-----"), sizeof(cmp));
1555 initialized = 1;
1556 }
1557 return sh_gpg_comp(line, cmp);
1558}
1559
1560static
1561int sh_gpg_msg_startdata(const char * line)
1562{
1563 if (line[0] == '\n')
1564 return S_TRUE;
1565 return S_FALSE;
1566}
1567
1568static
1569int sh_gpg_msg_end(const char * line)
1570{
1571 static char cmp[SH_MINIBUF];
1572 static int initialized = 0;
1573
1574 if (initialized == 0) {
1575 sl_strlcpy(cmp, _("-----BEGIN PGP SIGNATURE-----"), sizeof(cmp));
1576 initialized = 1;
1577 }
1578 return sh_gpg_comp(line, cmp);
1579}
1580
1581static
1582int sh_gpg_sig_end(const char * line)
1583{
1584 static char cmp[SH_MINIBUF];
1585 static int initialized = 0;
1586
1587 if (initialized == 0) {
1588 sl_strlcpy(cmp, _("-----END PGP SIGNATURE-----"), sizeof(cmp));
1589 initialized = 1;
1590 }
1591 return sh_gpg_comp(line, cmp);
1592}
1593
1594static
1595SL_TICKET sh_gpg_extract_signed(SL_TICKET fd, extractlevel extract_level)
1596{
1597 const int fgets_buf_size = 16384;
1598 FILE * fin_cp = NULL;
1599 char * buf = NULL;
1600 int bufc;
1601 int flag_pgp = S_FALSE;
1602 int flag_nohead = S_FALSE;
1603 SL_TICKET fdTmp = (-1);
1604 SL_TICKET open_tmp (void);
1605 int close_tmp ( SL_TICKET);
1606
1607 /* extract the data and copy to temporary file
1608 */
1609 fdTmp = open_tmp();
1610 if (SL_ISERROR(fdTmp))
1611 {
1612 dlog(1, FIL__, __LINE__, _("Error opening temporary file.\n"));
1613 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1614 _("Error opening temporary file."),
1615 _("sh_gpg_extract_signed"));
1616 return -1;
1617 }
1618
1619 fin_cp = fdopen(dup(get_the_fd(fd)), "rb");
1620 if (!fin_cp) { close_tmp(fdTmp); return -1; }
1621 buf = SH_ALLOC(fgets_buf_size);
1622
1623 while (NULL != fgets(buf, fgets_buf_size, fin_cp))
1624 {
1625 bufc = 0;
1626 while (bufc < fgets_buf_size) {
1627 if (buf[bufc] == '\n') { ++bufc; break; }
1628 ++bufc;
1629 }
1630
1631 if (flag_pgp == S_FALSE && sh_gpg_msg_start(buf) == S_TRUE)
1632 {
1633 flag_pgp = S_TRUE;
1634 if (extract_level == SIG_DATASIG)
1635 sl_write(fdTmp, buf, bufc);
1636 continue;
1637 }
1638
1639 if (flag_pgp == S_TRUE && flag_nohead == S_FALSE)
1640 {
1641 /* Header finished */
1642 if (buf[0] == '\n')
1643 {
1644 flag_nohead = S_TRUE;
1645 if (extract_level == SIG_DATASIG)
1646 sl_write(fdTmp, buf, 1);
1647 continue;
1648 }
1649 /* copy these headers */
1650 else if (0 == sl_strncmp(buf, _("Hash:"), 5) ||
1651 0 == sl_strncmp(buf, _("NotDashEscaped:"), 15))
1652 {
1653 if (extract_level == SIG_DATASIG)
1654 sl_write(fdTmp, buf, bufc);
1655 continue;
1656 }
1657 /* ignore other headers */
1658 else
1659 continue;
1660 }
1661
1662 if (flag_pgp == S_TRUE && buf[0] == '\n')
1663 {
1664 sl_write(fdTmp, buf, 1);
1665 }
1666 else if (flag_pgp == S_TRUE)
1667 {
1668 if (extract_level == SIG_DATASIG) {
1669 sl_write(fdTmp, buf, bufc);
1670 }
1671 else {
1672 if (sh_gpg_msg_end(buf) == S_TRUE)
1673 break;
1674 else
1675 sl_write(fdTmp, buf, bufc);
1676 }
1677 }
1678
1679 /* This is after the copy has been done. */
1680 if (flag_pgp == S_TRUE && sh_gpg_sig_end(buf) == S_TRUE)
1681 break;
1682 }
1683 SH_FREE(buf);
1684 sl_fclose(FIL__, __LINE__, fin_cp);
1685 sl_rewind (fdTmp);
1686
1687 return fdTmp;
1688}
1689#endif
1690
1691/*********************************************************************
1692 *
1693 * Exported functions
1694 *
1695 *********************************************************************/
1696
1697int sh_sig_check_signature (SL_TICKET file, ShSigFile what)
1698{
1699#if defined(WITH_GPG)
1700 return sh_gpg_check_signature (file, what);
1701#elif defined(WITH_SIGNIFY)
1702 return sh_signify_check_signature (file, what);
1703#else
1704 return -1;
1705#endif
1706}
1707
1708SL_TICKET sh_sig_extract_signed(SL_TICKET fd)
1709{
1710#if defined(WITH_GPG)
1711 return sh_gpg_extract_signed(fd, SIG_DATASIG);
1712#elif defined(WITH_SIGNIFY)
1713 return sh_signify_extract_signed(fd, SIG_DATASIG);
1714#else
1715 return -1;
1716#endif
1717}
1718
1719SL_TICKET sh_sig_extract_signed_data(SL_TICKET fd)
1720{
1721#if defined(WITH_GPG)
1722 return sh_gpg_extract_signed(fd, SIG_DATAONLY);
1723#elif defined(WITH_SIGNIFY)
1724 return sh_signify_extract_signed(fd, SIG_DATAONLY);
1725#else
1726 return -1;
1727#endif
1728}
1729
1730int sh_sig_msg_start(const char * line)
1731{
1732#if defined(WITH_GPG)
1733 return sh_gpg_msg_start(line);
1734#elif defined(WITH_SIGNIFY)
1735 return sh_signify_msg_start(line);
1736#else
1737 return -1;
1738#endif
1739}
1740
1741int sh_sig_msg_startdata(const char * line)
1742{
1743#if defined(WITH_GPG)
1744 return sh_gpg_msg_startdata(line);
1745#elif defined(WITH_SIGNIFY)
1746 return sh_signify_msg_startdata(line);
1747#else
1748 return -1;
1749#endif
1750}
1751
1752int sh_sig_msg_end(const char * line)
1753{
1754#if defined(WITH_GPG)
1755 return sh_gpg_msg_end(line);
1756#elif defined(WITH_SIGNIFY)
1757 return sh_signify_msg_end(line);
1758#else
1759 return -1;
1760#endif
1761}
1762
1763int sh_sig_data_end(const char * line)
1764{
1765#if defined(WITH_GPG)
1766 return sh_gpg_sig_end(line);
1767#elif defined(WITH_SIGNIFY)
1768 return sh_signify_data_end(line);
1769#else
1770 return -1;
1771#endif
1772}
1773
1774void sh_sig_log_startup (void)
1775{
1776 if (startInfo.program != NULL)
1777 {
1778 sh_error_handle ((-1), FIL__, startInfo.line, 0, MSG_START_GH,
1779 startInfo.program, startInfo.uid,
1780 startInfo.path,
1781 startInfo.key_uid, startInfo.key_id);
1782 }
1783 return;
1784}
1785
1786/* #ifdef WITH_SIG */
1787#endif
1788
1789
1790
1791
1792
1793
1794
1795
Note: See TracBrowser for help on using the repository browser.