source: trunk/src/sh_entropy.c@ 583

Last change on this file since 583 was 583, checked in by katerina, 32 hours ago

Fix for ticket #471 (autoreconf throws warnings/errors).

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