source: trunk/src/sh_entropy.c@ 463

Last change on this file since 463 was 460, checked in by katerina, 10 years ago

Better error message for update and fix for deadlock in UNIX entropy collector. 3.1.3 final.

File size: 22.9 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
21#include "config_xor.h"
22
23#include <stdio.h>
24#include <string.h>
25
26#include <sys/types.h>
27
28#ifdef HAVE_MEMORY_H
29#include <memory.h>
30#endif
31
32#if TIME_WITH_SYS_TIME
33#include <sys/time.h>
34#include <time.h>
35#else
36#if HAVE_SYS_TIME_H
37#include <sys/time.h>
38#else
39#include <time.h>
40#endif
41#endif
42
43
44#include <stdlib.h>
45#include <pwd.h>
46#include <unistd.h>
47#include <fcntl.h>
48#include <signal.h>
49#include <sys/stat.h>
50#include <errno.h>
51#include <sys/wait.h>
52
53
54#ifdef HAVE_SYS_SELECT_H
55#include <sys/select.h>
56#endif
57#include <sys/types.h>
58
59
60
61#include "samhain.h"
62#include "sh_utils.h"
63#include "sh_unix.h"
64#include "sh_tiger.h"
65#include "sh_calls.h"
66
67#undef FIL__
68#define FIL__ _("sh_entropy.c")
69
70#if defined (HAVE_EGD_RANDOM)
71/* rndegd.c - interface to the EGD
72 * Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
73 */
74#include <stddef.h>
75#include <sys/socket.h>
76#include <sys/un.h>
77
78static int
79do_write( int fd, void *buf, size_t nbytes )
80{
81 size_t nleft = nbytes;
82 int nwritten;
83
84 while( nleft > 0 ) {
85 nwritten = write( fd, buf, nleft);
86 if( nwritten < 0 ) {
87 if( errno == EINTR )
88 continue;
89 return -1;
90 }
91 nleft -= nwritten;
92 buf = (char*)buf + nwritten;
93 }
94 return 0;
95}
96
97static int
98do_read( int fd, void *buf, int nbytes )
99{
100 int n, nread = 0;
101
102 if (nbytes < 0)
103 return 0;
104
105 do {
106 do {
107 n = read(fd, (char*)buf + nread, nbytes );
108 } while( n == -1 && errno == EINTR );
109 if( n == -1 )
110 return -1;
111 nread += n;
112 } while( nread < nbytes );
113 return nbytes;
114}
115
116
117int sh_entropy(int getbytes, char * nbuf)
118{
119 int fd = -1;
120 int n;
121 byte buffer[256+2];
122 int nbytes;
123 int do_restart = 0;
124 int myerror = 0;
125 int length;
126 char * p = nbuf;
127 int i;
128
129 SL_ENTER(_("sh_entropy"));
130
131 if( getbytes <= 0)
132 SL_RETURN( -1, _("sh_entropy"));
133 if (getbytes > KEY_BYT)
134 getbytes = KEY_BYT;
135 length = getbytes;
136
137 restart:
138 if( do_restart ) {
139 if( fd != -1 ) {
140 sl_close_fd(FIL__, __LINE__, fd );
141 fd = -1;
142 }
143 }
144 if( fd == -1 ) {
145 const char *bname = NULL;
146 char *name;
147 struct sockaddr_un addr;
148 int addr_len;
149 int retval;
150
151#ifdef EGD_SOCKET_NAME
152 bname = EGD_SOCKET_NAME;
153#endif
154 if ( !bname || !*bname )
155 bname = _("=entropy");
156
157 if ( *bname == '=' && bname[1] )
158 name = sh_util_strconcat ( DEFAULT_DATAROOT, "/", bname+1 , NULL );
159 else
160 name = sh_util_strconcat ( bname , NULL );
161
162 if ( strlen(name)+1 >= sizeof(addr.sun_path) )
163 {
164 sh_error_handle ((-1), FIL__, __LINE__, ENAMETOOLONG, MSG_E_SUBGEN,
165 _("EGD socketname is too long"),
166 _("sh_entropy") );
167 SH_FREE(name);
168 SL_RETURN( -1, _("sh_entropy") );
169 }
170
171 memset( &addr, 0, sizeof(addr) );
172 addr.sun_family = AF_UNIX;
173 sl_strlcpy( addr.sun_path, name, sizeof(addr.sun_path) );
174 addr_len = offsetof( struct sockaddr_un, sun_path )
175 + strlen( addr.sun_path );
176
177 fd = socket(AF_UNIX, SOCK_STREAM, 0);
178 if( fd == -1 )
179 {
180 myerror = errno;
181 sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
182 _("cannot create unix domain socket"),
183 _("sh_entropy") );
184 SH_FREE(name);
185 SL_RETURN( -1, _("sh_entropy") );
186 }
187 do {
188 retval = connect(fd, (struct sockaddr *) &sinr, sizeof(sinr));
189 } while (retval < 0 && (errno == EINTR || errno == EINPROGRESS));
190 if( retval == -1 )
191 {
192 myerror = errno;
193 sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
194 _("cannot connect to unix domain socket"),
195 _("sh_entropy") );
196 SH_FREE(name);
197 sl_close_fd(FIL__, __LINE__, fd);
198 SL_RETURN( -1, _("sh_entropy") );
199 }
200 SH_FREE(name);
201 }
202 do_restart = 0;
203
204 nbytes = length < 255? length : 255;
205 /* first time we do it with a non blocking request */
206 buffer[0] = 1; /* non blocking */
207 buffer[1] = nbytes;
208 if( do_write( fd, buffer, 2 ) == -1 )
209 {
210 myerror = errno;
211 sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
212 _("cannot write to EGD"),
213 _("sh_entropy") );
214 sl_close_fd(FIL__, __LINE__, fd);
215 SL_RETURN( -1, _("sh_entropy") );
216 }
217 n = do_read( fd, buffer, 1 );
218 if( n == -1 ) {
219 myerror = errno;
220 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, myerror, MSG_E_SUBGEN,
221 _("read error on EGD"),
222 _("sh_entropy") );
223 do_restart = 1;
224 goto restart;
225 }
226 n = buffer[0];
227 if( n ) {
228 n = do_read( fd, buffer, n );
229 if( n == -1 ) {
230 myerror = errno;
231 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, myerror,MSG_E_SUBGEN,
232 _("read error on EGD"),
233 _("sh_entropy") );
234 do_restart = 1;
235 goto restart;
236 }
237 for (i = 0; i < n; ++i)
238 {
239 if (getbytes >= 0)
240 { *p = buffer[i]; ++p; --getbytes; }
241 }
242 length -= n;
243 }
244
245 while( length ) {
246 nbytes = length < 255? length : 255;
247
248 buffer[0] = 2; /* blocking */
249 buffer[1] = nbytes;
250 if( do_write( fd, buffer, 2 ) == -1 )
251 {
252 myerror = errno;
253 sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
254 _("cannot write to EGD"),
255 _("sh_entropy") );
256 sl_close_fd(FIL__, __LINE__, fd);
257 SL_RETURN( -1, _("sh_entropy") );
258 }
259 n = do_read( fd, buffer, nbytes );
260 if( n == -1 ) {
261 myerror = errno;
262 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, myerror,MSG_E_SUBGEN,
263 _("read error on EGD"),
264 _("sh_entropy") );
265 do_restart = 1;
266 goto restart;
267 }
268 for (i = 0; i < n; ++i)
269 {
270 if (getbytes >= 0)
271 { *p = buffer[i]; ++p; --getbytes; }
272 }
273 length -= n;
274 }
275 memset(buffer, 0, sizeof(buffer) );
276 sl_close_fd(FIL__, __LINE__, fd);
277 SL_RETURN( 0, _("sh_entropy") ); /* success */
278}
279
280/* HAVE_EGD_RANDOM */
281#endif
282
283#if defined (HAVE_URANDOM)
284
285#include "sh_pthread.h"
286
287int read_mbytes(int timeout_val, const char * path, char * nbuf, int nbytes)
288{
289 int m_count;
290 int fd2;
291
292 SL_ENTER(_("read_mbytes"));
293
294 if ((fd2 = aud_open (FIL__, __LINE__, SL_NOPRIV, path, O_RDONLY, 0)) >= 0)
295 {
296 /* Test whether file is a character device, and is
297 * readable.
298 */
299 if (0 == sh_unix_device_readable(fd2))
300 {
301 m_count = sl_read_timeout_fd(fd2, nbuf, nbytes,
302 timeout_val, SL_FALSE);
303 if (m_count < 0)
304 m_count = 0;
305 }
306 else
307 m_count = 0;
308 }
309 else
310 m_count = 0;
311
312 sl_close_fd(FIL__, __LINE__, fd2);
313
314 TPT((0, FIL__, __LINE__, _("msg=<read_mbytes: OK>\n")));
315 SL_RETURN(m_count, _("read_mbytes"));
316}
317
318/* Read nbytes bytes from /dev/random, mix them with
319 * previous reads using a hash function, and give out
320 * nbytes bytes from the result.
321 */
322int sh_entropy(int nbytes, char * nbuf)
323{
324 int i, m_count = 0;
325 char * keybuf;
326 UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
327 char addbuf[2 * KEY_BYT];
328
329 SL_ENTER(_("sh_entropy"));
330
331 ASSERT((nbytes <= KEY_BYT), _("nbytes <= KEY_BYT"))
332
333 if (nbytes > KEY_BYT)
334 nbytes = KEY_BYT;
335
336 memset(nbuf, '\0', nbytes);
337
338#ifdef NAME_OF_DEV_URANDOM
339 m_count = read_mbytes ( 1, NAME_OF_DEV_RANDOM, nbuf, nbytes);
340#else
341 m_count = read_mbytes (300, NAME_OF_DEV_RANDOM, nbuf, nbytes);
342#endif
343
344 if (m_count == 0)
345 {
346#ifdef NAME_OF_DEV_URANDOM
347 sh_error_handle (SH_ERR_NOTICE, FIL__, __LINE__, EIO, MSG_NODEV,
348 (long) sh.real.uid, NAME_OF_DEV_RANDOM);
349#else
350 sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_NODEV,
351 (long) sh.real.uid, NAME_OF_DEV_RANDOM);
352#endif
353 }
354
355#ifdef NAME_OF_DEV_URANDOM
356 if (m_count < nbytes)
357 {
358 i = read_mbytes(30, NAME_OF_DEV_URANDOM, &nbuf[m_count], nbytes-m_count);
359 if (i == 0)
360 sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_NODEV,
361 (long) sh.real.uid, NAME_OF_DEV_URANDOM);
362 else
363 m_count += i;
364 }
365#endif
366
367
368 if (m_count > 0)
369 {
370 /* -- Add previous entropy into the new pool. --
371 */
372 memset(addbuf, '\0', sizeof(addbuf));
373 for (i = 0; i < m_count; ++i)
374 addbuf[i] = nbuf[i];
375 for (i = 0; i < KEY_BYT; ++i)
376 addbuf[i+KEY_BYT] = skey->poolv[i];
377 keybuf = (char *) sh_tiger_hash_uint32 (addbuf,
378 TIGER_DATA, 2 * KEY_BYT,
379 kbuf, KEY_BYT/sizeof(UINT32));
380 memset(addbuf, '\0', sizeof(addbuf));
381
382 /* -- Give out nbytes bytes from the new pool. --
383 */
384 SH_MUTEX_LOCK_UNSAFE(mutex_skey);
385 for (i = 0; i < KEY_BYT; ++i)
386 {
387 skey->poolv[i] = keybuf[i];
388 if (i < nbytes)
389 nbuf[i] = keybuf[i];
390 }
391 SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
392 memset (keybuf, '\0', KEY_BYT);
393 memset (kbuf, '\0', sizeof(kbuf));
394
395 SL_RETURN(0, _("sh_entropy"));
396 }
397 else
398 {
399 SL_RETURN((-1), _("sh_entropy"));
400 }
401}
402
403/* HAVE_URANDOM */
404#endif
405
406#ifdef HAVE_UNIX_RANDOM
407
408#ifndef FD_SET
409#define NFDBITS 32
410#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
411#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
412#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
413#endif /* !FD_SET */
414#ifndef FD_SETSIZE
415#define FD_SETSIZE 32
416#endif
417#ifndef FD_ZERO
418#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p)))
419#endif
420
421#include "sh_static.h"
422#include "sh_pthread.h"
423
424static
425char * com_path[] = {
426 N_("/usr/bin/xpg4/"),
427 N_("/usr/ucb/"),
428 N_("/bin/"),
429 N_("/sbin/"),
430 N_("/usr/bin/"),
431 N_("/usr/sbin/"),
432 N_("/usr/local/bin/"),
433 N_("/opt/local/bin/"),
434 NULL
435};
436
437
438typedef struct {
439 char * command;
440 char * arg;
441 int pipeFD;
442 pid_t pid;
443 int isset;
444 FILE * pipe;
445} sourcetable_t;
446
447static
448sourcetable_t source_template[] = {
449 { N_("w"),
450 N_("w"),
451 0,
452 0,
453 0,
454 NULL },
455 { N_("netstat"),
456 N_("netstat -n"),
457 0,
458 0,
459 0,
460 NULL },
461 { N_("ps"),
462 N_("ps -ef"),
463 0,
464 0,
465 0,
466 NULL },
467 { N_("arp"),
468 N_("arp -a"),
469 0,
470 0,
471 0,
472 NULL },
473 { N_("free"),
474 N_("free"),
475 0,
476 0,
477 0,
478 NULL },
479 { N_("uptime"),
480 N_("uptime"),
481 0,
482 0,
483 0,
484 NULL },
485 { N_("procinfo"),
486 N_("procinfo -a"),
487 0,
488 0,
489 0,
490 NULL },
491 { N_("vmstat"),
492 N_("vmstat"),
493 0,
494 0,
495 0,
496 NULL },
497 { N_("w"), /* Play it again, Sam. */
498 N_("w"),
499 0,
500 0,
501 0,
502 NULL },
503 { NULL,
504 NULL,
505 0,
506 0,
507 0,
508 NULL }
509};
510
511
512static FILE * sh_popen (sourcetable_t *source, char * command)
513{
514 int i;
515 int pipedes[2];
516 FILE *outf = NULL;
517 char * arg[4];
518 char * envp[2];
519 size_t len;
520 char arg0[80];
521 char arg1[80];
522
523#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
524 struct passwd pwd;
525 char * buffer;
526 struct passwd * tempres;
527#else
528 struct passwd * tempres;
529#endif
530
531 SL_ENTER(_("sh_popen"));
532
533#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
534 buffer = SH_ALLOC(SH_PWBUF_SIZE);
535 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
536#else
537 tempres = sh_getpwnam(DEFAULT_IDENT);
538#endif
539
540 strncpy (arg0, _("/bin/sh"), sizeof(arg0));
541 arg[0] = arg0;
542 strncpy (arg1, _("-c"), sizeof(arg1));
543 arg[1] = arg1;
544 arg[2] = command;
545 arg[3] = NULL;
546
547 if (sh.timezone != NULL)
548 {
549 len = sl_strlen(sh.timezone) + 4;
550 envp[0] = calloc(1, len); /* free() ok */
551 if (envp[0] != NULL)
552 sl_snprintf (envp[0], len, "TZ=%s", sh.timezone);
553 else
554 envp[0] = NULL;
555 envp[1] = NULL;
556 }
557 else
558 {
559 envp[0] = NULL;
560 }
561
562
563 /* Create the pipe
564 */
565 if (aud_pipe(FIL__, __LINE__, pipedes) < 0) {
566 if (envp[0] != NULL) free(envp[0]);
567 SL_RETURN(NULL, _("sh_popen"));
568 }
569
570 fflush (NULL);
571
572 source->pid = aud_fork(FIL__, __LINE__);
573
574 /* Failure
575 */
576 if (source->pid == (pid_t) - 1) {
577 sl_close_fd(FIL__, __LINE__, pipedes[0]);
578 sl_close_fd(FIL__, __LINE__, pipedes[1]);
579 if (envp[0] != NULL) free(envp[0]);
580 SL_RETURN(NULL, _("sh_popen"));
581 }
582
583 if (source->pid == (pid_t) 0)
584 {
585 int val_return;
586
587 /* child - make read side of the pipe stdout
588 */
589 do {
590 val_return = dup2 (pipedes[STDOUT_FILENO], STDOUT_FILENO);
591 } while (val_return < 0 && errno == EINTR);
592
593 if (val_return < 0)
594 _exit(EXIT_FAILURE);
595
596 /* close the pipe descriptors
597 */
598 sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
599 sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
600
601 /* don't leak file descriptors
602 */
603 sh_unix_closeall (3, -1, SL_TRUE); /* in child process */
604
605 /* zero priv info
606 */
607 memset(skey, 0, sizeof(sh_key_t));
608
609 /* drop root privileges
610 */
611 i = 0;
612 if (0 == geteuid())
613 {
614
615 if (NULL != tempres) {
616 i = setgid(tempres->pw_gid);
617
618 /*** locks up in dnmalloc ***/
619 /*
620 * if (i == 0)
621 * i = sh_unix_initgroups(DEFAULT_IDENT ,tempres->pw_gid);
622 */
623
624 if (i == 0)
625 i = setuid(tempres->pw_uid);
626 /* make sure we cannot get root again
627 */
628 if ((tempres->pw_uid != 0) &&
629 (setuid(0) >= 0))
630 i = -1;
631 } else {
632 i = -1;
633 }
634 }
635
636 /* some problem ...
637 */
638 if (i == -1) {
639 _exit(EXIT_FAILURE);
640 }
641
642 if (NULL != freopen (_("/dev/null"), "r+", stderr))
643 {
644
645 /* exec the program */
646 do {
647 val_return = execve (_("/bin/sh"), arg, envp);
648 } while (val_return < 0 && errno == EINTR);
649 }
650
651 /* failed
652 */
653 _exit(EXIT_FAILURE);
654 }
655
656 /* parent
657 */
658#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
659 SH_FREE(buffer);
660#endif
661
662 if (envp[0] != NULL)
663 free(envp[0]);
664
665 sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
666 retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
667
668 outf = fdopen (pipedes[STDIN_FILENO], "r");
669
670 if (outf == NULL)
671 {
672 aud_kill (FIL__, __LINE__, source->pid, SIGKILL);
673 sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
674 waitpid (source->pid, NULL, 0);
675 source->pid = 0;
676 SL_RETURN(NULL, _("sh_popen"));
677 }
678
679 SL_RETURN(outf, _("sh_popen"));
680}
681
682
683static int sh_pclose (sourcetable_t *source)
684{
685 int status = 0;
686 int retval;
687 char msg[128];
688 char errbuf[SH_ERRBUF_SIZE];
689
690 SL_ENTER(_("sh_pclose"));
691
692 retval = sl_fclose(FIL__, __LINE__, source->pipe);
693 if (retval)
694 {
695 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval,
696 MSG_E_SUBGEN,
697 sh_error_message(retval, errbuf, sizeof(errbuf)),
698 _("sh_pclose"));
699 SL_RETURN((-1), _("sh_pclose"));
700 }
701
702 retval = waitpid(source->pid, &status, 0);
703 if (retval != source->pid)
704 {
705 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval,
706 MSG_E_SUBGEN,
707 sh_error_message(retval, errbuf, sizeof(errbuf)),
708 _("sh_pclose"));
709
710 status = -1;
711 }
712#if !defined(USE_UNO)
713 else if (WIFSIGNALED(status))
714 {
715 sl_snprintf(msg, sizeof(msg), _("Subprocess terminated by signal %d"),
716 WTERMSIG(status));
717 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval,
718 MSG_E_SUBGEN,
719 msg,
720 _("sh_pclose"));
721 status = -1;
722 }
723#endif
724
725 source->pipe = NULL;
726 source->pid = 0;
727 SL_RETURN(status, _("sh_pclose"));
728}
729
730#define BUF_ENT 32766
731
732/* Poll the system for randomness, mix results with
733 * previous reads using a hash function, and give out
734 * nbytes bytes from the result.
735 */
736int sh_entropy(int nbytes, char * nbuf)
737{
738 int caperr;
739 char combuf[80];
740 char * buffer;
741 int i, j, icount;
742 int bufcount = 0;
743 int count;
744
745 char * keybuf;
746 UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
747 char addbuf[2 * KEY_BYT];
748
749 struct timeval tv;
750 fd_set fds;
751 unsigned long select_now = 0;
752 int maxFD = 0;
753 int imax, selcount;
754 char errbuf[SH_ERRBUF_SIZE];
755
756 sourcetable_t *source = NULL;
757
758 SL_ENTER(_("sh_entropy"));
759
760 ASSERT((nbytes <= KEY_BYT), _("nbytes <= KEY_BYT"))
761
762 if (nbytes > KEY_BYT)
763 nbytes = KEY_BYT;
764
765
766 /* --- If there is entropy in the pool, return it. ---
767 */
768 SH_MUTEX_LOCK_UNSAFE(mutex_skey);
769 if (skey->poolc >= nbytes)
770 {
771 j = KEY_BYT - skey->poolc;
772 for (i = 0; i < nbytes; ++i)
773 {
774 nbuf[i] = skey->poolv[i+j];
775 --skey->poolc;
776 }
777 SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); /* alternative path */
778 SL_RETURN(0, _("sh_entropy"));
779 }
780 SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
781
782
783 FD_ZERO(&fds);
784
785 i = 0; icount = 0;
786 buffer = SH_ALLOC(BUF_ENT+2);
787
788 if (0 != (caperr = sl_get_cap_sub()))
789 {
790 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
791 sh_error_message (caperr, errbuf, sizeof(errbuf)),
792 _("sl_get_cap_sub"));
793 }
794
795 while (source_template[i].command != NULL) {
796 ++i;
797 }
798 source = SH_ALLOC(i * sizeof(sourcetable_t));
799 for (j = 0; j < i;++j)
800 memcpy(&source[j], &source_template[j], sizeof(sourcetable_t));
801 i = 0;
802
803 while (source_template[i].command != NULL) {
804
805 j = 0;
806 while (com_path[j] != NULL)
807 {
808 sl_strlcpy(combuf, _(com_path[j]), 80);
809 sl_strlcat(combuf, _(source[i].command), 80);
810
811 /* flawfinder: ignore */
812 if ( access (combuf, X_OK) == 0)
813 {
814 sl_strlcpy(combuf, _(com_path[j]), 80);
815 sl_strlcat(combuf, _(source[i].arg), 80);
816 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENSTART,
817 combuf);
818 break;
819 }
820 ++j;
821 }
822
823 /* Not found, try next command.
824 */
825 if (com_path[j] == NULL)
826 {
827 ++i;
828 continue;
829 }
830
831 /* Source exists
832 */
833 source[i].pipe = sh_popen ( &source[i], combuf );
834 if (NULL != source[i].pipe)
835 {
836 source[i].pipeFD = fileno ( source[i].pipe );
837 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENEXEC,
838 combuf, (long) source[i].pipeFD);
839
840 maxFD = (source[i].pipeFD > maxFD) ? source[i].pipeFD : maxFD;
841 retry_fcntl( FIL__, __LINE__, source[i].pipeFD, F_SETFL, O_NONBLOCK);
842 FD_SET( source[i].pipeFD, &fds );
843 source[i].isset = 1;
844 ++icount;
845 }
846 else
847 {
848 sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENFAIL,
849 combuf);
850 }
851
852 ++i;
853 }
854
855 imax = i;
856 tv.tv_sec = 1;
857 tv.tv_usec = 0;
858 bufcount = 0;
859
860 while ( (icount > 0) && (bufcount < BUF_ENT) ) {
861
862 if ( (selcount = select (maxFD+1, &fds, NULL, NULL, &tv)) == -1)
863 break;
864
865 /* reset timeout for select()
866 */
867 tv.tv_sec = 1;
868 tv.tv_usec = 0;
869
870 /* timeout - let's not hang on forever
871 */
872 if (selcount == 0)
873 {
874 ++select_now;
875 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENTOUT,
876 (unsigned long) select_now);
877 if ( select_now > 9 )
878 break;
879 }
880
881 for (i = 0; i < imax; ++i) {
882
883 if ( FD_ISSET (source[i].pipeFD, &fds) ) {
884 count = fread (&buffer[bufcount],
885 1,
886 BUF_ENT-bufcount,
887 source[i].pipe );
888 if (count == 0)
889 {
890 if (0 != feof(source[i].pipe))
891 sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENCLOS,
892 (long) source[i].pipeFD);
893 else
894 sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENCLOS1,
895 (long) source[i].pipeFD);
896 source[i].isset = 0;
897 sh_pclose ( &source[i] );
898 --icount;
899 }
900 else
901 {
902 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENREAD,
903 (long) source[i].pipeFD, (long) count);
904 }
905 bufcount += count;
906
907 }
908 }
909
910 maxFD = 0;
911 FD_ZERO(&fds);
912
913 for (i = 0; i < imax; ++i)
914 {
915 if (source[i].isset == 1)
916 {
917 FD_SET( source[i].pipeFD, &fds );
918 maxFD = (source[i].pipeFD > maxFD) ? source[i].pipeFD : maxFD;
919 }
920 }
921 }
922
923 for (i = 0; i < imax; ++i)
924 {
925 if (source[i].isset == 1)
926 {
927 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENCLOS1,
928 (long) source[i].pipeFD);
929 sh_pclose ( &source[i] );
930 }
931 }
932 buffer[bufcount] = '\0';
933
934 SH_FREE(source);
935
936 if (0 != (caperr = sl_drop_cap_sub()))
937 {
938 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
939 sh_error_message (caperr, errbuf, sizeof(errbuf)),
940 _("sl_drop_cap_sub"));
941 }
942
943 if (bufcount > 0)
944 {
945 keybuf = (char *) sh_tiger_hash_uint32 (buffer,
946 TIGER_DATA, sl_strlen(buffer),
947 kbuf, KEY_BYT/sizeof(UINT32));
948
949 /* add previous entropy into the new pool
950 */
951 memset(addbuf, '\0', sizeof(addbuf));
952 for (i = 0; i < KEY_BYT; ++i)
953 {
954 addbuf[i] = keybuf[i];
955 addbuf[i+KEY_BYT] = skey->poolv[i];
956 }
957 keybuf = (char *) sh_tiger_hash_uint32 (addbuf,
958 TIGER_DATA, sizeof(addbuf),
959 kbuf, KEY_BYT/sizeof(UINT32));
960 memset(addbuf, '\0', sizeof(addbuf));
961
962 /* store in system pool
963 */
964 SH_MUTEX_LOCK_UNSAFE(mutex_skey);
965 for (i = 0; i < KEY_BYT; ++i)
966 skey->poolv[i] = keybuf[i];
967 skey->poolc = KEY_BYT;
968 SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
969 memset (buffer, '\0', BUF_ENT+2);
970 memset (keybuf, '\0', KEY_BYT);
971 SH_FREE(buffer);
972 }
973 else
974 {
975 SH_FREE(buffer);
976 SL_RETURN((-1), _("sh_entropy"));
977 }
978
979 /* give out nbytes Bytes from the entropy pool
980 */
981 SH_MUTEX_LOCK_UNSAFE(mutex_skey);
982 for (i = 0; i < nbytes; ++i)
983 {
984 nbuf[i] = skey->poolv[i];
985 --skey->poolc;
986 }
987 SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
988
989 SL_RETURN(0, _("sh_entropy"));
990}
991
992/* HAVE_UNIX_RANDOM */
993#endif
994
995#ifdef SH_CUTEST
996#include "CuTest.h"
997
998void Test_entropy (CuTest *tc)
999{
1000 char bufx[9 * sizeof(UINT32) + 1];
1001 char bufy[9 * sizeof(UINT32) + 1];
1002 int status;
1003
1004 memset(skey->poolv, '\0', KEY_BYT);
1005
1006 status = sh_entropy (24, bufx);
1007 CuAssertTrue(tc, 0 == status);
1008
1009 memset(skey->poolv, '\0', KEY_BYT);
1010
1011 status = sh_entropy (24, bufy);
1012 CuAssertTrue(tc, 0 == status);
1013
1014 CuAssertTrue(tc, 0 != memcmp(bufx, bufy, 24));
1015}
1016#endif
1017
1018
1019
1020
1021
1022
1023
1024
Note: See TracBrowser for help on using the repository browser.