source: trunk/src/sh_entropy.c@ 282

Last change on this file since 282 was 252, checked in by katerina, 15 years ago

Add code to check for stale file records on close() and fclose(), fix sl_close() to handle open stream (ticket #163).

File size: 22.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 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 NULL
434};
435
436
437typedef struct {
438 char * command;
439 char * arg;
440 int pipeFD;
441 pid_t pid;
442 int isset;
443 FILE * pipe;
444} sourcetable_t;
445
446static
447sourcetable_t source_template[] = {
448 { N_("w"),
449 N_("w"),
450 0,
451 0,
452 0,
453 NULL },
454 { N_("netstat"),
455 N_("netstat -n"),
456 0,
457 0,
458 0,
459 NULL },
460 { N_("ps"),
461 N_("ps -ef"),
462 0,
463 0,
464 0,
465 NULL },
466 { N_("arp"),
467 N_("arp -a"),
468 0,
469 0,
470 0,
471 NULL },
472 { N_("free"),
473 N_("free"),
474 0,
475 0,
476 0,
477 NULL },
478 { N_("uptime"),
479 N_("uptime"),
480 0,
481 0,
482 0,
483 NULL },
484 { N_("procinfo"),
485 N_("procinfo -a"),
486 0,
487 0,
488 0,
489 NULL },
490 { N_("vmstat"),
491 N_("vmstat"),
492 0,
493 0,
494 0,
495 NULL },
496 { N_("w"), /* Play it again, Sam. */
497 N_("w"),
498 0,
499 0,
500 0,
501 NULL },
502 { NULL,
503 NULL,
504 0,
505 0,
506 0,
507 NULL }
508};
509
510
511static FILE * sh_popen (sourcetable_t *source, char * command)
512{
513 int i;
514 int pipedes[2];
515 FILE *outf = NULL;
516 char * arg[4];
517 char * envp[2];
518 size_t len;
519 char arg0[80];
520 char arg1[80];
521
522 SL_ENTER(_("sh_popen"));
523
524 strncpy (arg0, _("/bin/sh"), sizeof(arg0));
525 arg[0] = arg0;
526 strncpy (arg1, _("-c"), sizeof(arg1));
527 arg[1] = arg1;
528 arg[2] = command;
529 arg[3] = NULL;
530
531 if (sh.timezone != NULL)
532 {
533 len = sl_strlen(sh.timezone) + 4;
534 envp[0] = malloc (len); /* free() ok */
535 if (envp[0] != NULL)
536 sl_snprintf (envp[0], len, "TZ=%s", sh.timezone);
537 else
538 envp[0] = NULL;
539 envp[1] = NULL;
540 }
541 else
542 {
543 envp[0] = NULL;
544 }
545
546
547 /* Create the pipe
548 */
549 if (aud_pipe(FIL__, __LINE__, pipedes) < 0) {
550 if (envp[0] != NULL) free(envp[0]);
551 SL_RETURN(NULL, _("sh_popen"));
552 }
553
554 fflush (NULL);
555
556 source->pid = aud_fork(FIL__, __LINE__);
557
558 /* Failure
559 */
560 if (source->pid == (pid_t) - 1) {
561 sl_close_fd(FIL__, __LINE__, pipedes[0]);
562 sl_close_fd(FIL__, __LINE__, pipedes[1]);
563 if (envp[0] != NULL) free(envp[0]);
564 SL_RETURN(NULL, _("sh_popen"));
565 }
566
567 if (source->pid == (pid_t) 0)
568 {
569 int val_return;
570
571 /* child - make read side of the pipe stdout
572 */
573 do {
574 val_return = dup2 (pipedes[STDOUT_FILENO], STDOUT_FILENO);
575 } while (val_return < 0 && errno == EINTR);
576
577 if (val_return < 0)
578 _exit(EXIT_FAILURE);
579
580 /* close the pipe descriptors
581 */
582 sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
583 sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
584
585 /* don't leak file descriptors
586 */
587 sh_unix_closeall (3, -1, SL_TRUE); /* in child process */
588
589 /* zero priv info
590 */
591 memset(skey, 0, sizeof(sh_key_t));
592
593 /* drop root privileges
594 */
595 i = 0;
596 if (0 == geteuid())
597 {
598#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
599 struct passwd pwd;
600 char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
601 struct passwd * tempres;
602 sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
603#else
604 struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
605#endif
606
607 if (NULL != tempres) {
608 i = setgid(tempres->pw_gid);
609 if (i == 0)
610 i = sh_unix_initgroups(DEFAULT_IDENT ,tempres->pw_gid);
611 if (i == 0)
612 i = setuid(tempres->pw_uid);
613 /* make sure we cannot get root again
614 */
615 if ((tempres->pw_uid != 0) &&
616 (setuid(0) >= 0))
617 i = -1;
618 } else {
619 i = -1;
620 }
621#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
622 SH_FREE(buffer);
623#endif
624 }
625
626 /* some problem ...
627 */
628 if (i == -1) {
629 _exit(EXIT_FAILURE);
630 }
631
632 if (NULL != freopen (_("/dev/null"), "r+", stderr))
633 {
634
635 /* exec the program */
636 do {
637 val_return = execve (_("/bin/sh"), arg, envp);
638 } while (val_return < 0 && errno == EINTR);
639 }
640
641 /* failed
642 */
643 _exit(EXIT_FAILURE);
644 }
645
646 /* parent
647 */
648 if (envp[0] != NULL)
649 free(envp[0]);
650
651 sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
652 retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
653
654 outf = fdopen (pipedes[STDIN_FILENO], "r");
655
656 if (outf == NULL)
657 {
658 aud_kill (FIL__, __LINE__, source->pid, SIGKILL);
659 sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
660 waitpid (source->pid, NULL, 0);
661 source->pid = 0;
662 SL_RETURN(NULL, _("sh_popen"));
663 }
664
665 SL_RETURN(outf, _("sh_popen"));
666}
667
668
669static int sh_pclose (sourcetable_t *source)
670{
671 int status = 0;
672 int retval;
673 char msg[128];
674 char errbuf[SH_ERRBUF_SIZE];
675
676 SL_ENTER(_("sh_pclose"));
677
678 retval = sl_fclose(FIL__, __LINE__, source->pipe);
679 if (retval)
680 {
681 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval,
682 MSG_E_SUBGEN,
683 sh_error_message(retval, errbuf, sizeof(errbuf)),
684 _("sh_pclose"));
685 SL_RETURN((-1), _("sh_pclose"));
686 }
687
688 retval = waitpid(source->pid, &status, 0);
689 if (retval != source->pid)
690 {
691 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval,
692 MSG_E_SUBGEN,
693 sh_error_message(retval, errbuf, sizeof(errbuf)),
694 _("sh_pclose"));
695
696 status = -1;
697 }
698#if !defined(USE_UNO)
699 else if (WIFSIGNALED(status))
700 {
701 sl_snprintf(msg, sizeof(msg), _("Subprocess terminated by signal %d"),
702 WTERMSIG(status));
703 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval,
704 MSG_E_SUBGEN,
705 msg,
706 _("sh_pclose"));
707 status = -1;
708 }
709#endif
710
711 source->pipe = NULL;
712 source->pid = 0;
713 SL_RETURN(status, _("sh_pclose"));
714}
715
716#define BUF_ENT 32766
717
718/* Poll the system for randomness, mix results with
719 * previous reads using a hash function, and give out
720 * nbytes bytes from the result.
721 */
722int sh_entropy(int nbytes, char * nbuf)
723{
724 int caperr;
725 char combuf[80];
726 char * buffer;
727 int i, j, icount;
728 int bufcount = 0;
729 int count;
730
731 char * keybuf;
732 UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
733 char addbuf[2 * KEY_BYT];
734
735 struct timeval tv;
736 fd_set fds;
737 unsigned long select_now = 0;
738 int maxFD = 0;
739 int imax, selcount;
740 char errbuf[SH_ERRBUF_SIZE];
741
742 sourcetable_t *source = NULL;
743
744 SL_ENTER(_("sh_entropy"));
745
746 ASSERT((nbytes <= KEY_BYT), _("nbytes <= KEY_BYT"))
747
748 if (nbytes > KEY_BYT)
749 nbytes = KEY_BYT;
750
751
752 /* --- If there is entropy in the pool, return it. ---
753 */
754 SH_MUTEX_LOCK_UNSAFE(mutex_skey);
755 if (skey->poolc >= nbytes)
756 {
757 j = KEY_BYT - skey->poolc;
758 for (i = 0; i < nbytes; ++i)
759 {
760 nbuf[i] = skey->poolv[i+j];
761 --skey->poolc;
762 }
763 SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); /* alternative path */
764 SL_RETURN(0, _("sh_entropy"));
765 }
766 SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
767
768
769 FD_ZERO(&fds);
770
771 i = 0; icount = 0;
772 buffer = SH_ALLOC(BUF_ENT+2);
773
774 if (0 != (caperr = sl_get_cap_sub()))
775 {
776 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
777 sh_error_message (caperr, errbuf, sizeof(errbuf)),
778 _("sl_get_cap_sub"));
779 }
780
781 while (source_template[i].command != NULL) {
782 ++i;
783 }
784 source = SH_ALLOC(i * sizeof(sourcetable_t));
785 for (j = 0; j < i;++j)
786 memcpy(&source[j], &source_template[j], sizeof(sourcetable_t));
787 i = 0;
788
789 while (source_template[i].command != NULL) {
790
791 j = 0;
792 while (com_path[j] != NULL)
793 {
794 sl_strlcpy(combuf, _(com_path[j]), 80);
795 sl_strlcat(combuf, _(source[i].command), 80);
796
797 /* flawfinder: ignore */
798 if ( access (combuf, X_OK) == 0)
799 {
800 sl_strlcpy(combuf, _(com_path[j]), 80);
801 sl_strlcat(combuf, _(source[i].arg), 80);
802 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENSTART,
803 combuf);
804 break;
805 }
806 ++j;
807 }
808
809 /* Not found, try next command.
810 */
811 if (com_path[j] == NULL)
812 {
813 ++i;
814 continue;
815 }
816
817 /* Source exists
818 */
819 source[i].pipe = sh_popen ( &source[i], combuf );
820 if (NULL != source[i].pipe)
821 {
822 source[i].pipeFD = fileno ( source[i].pipe );
823 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENEXEC,
824 combuf, (long) source[i].pipeFD);
825
826 maxFD = (source[i].pipeFD > maxFD) ? source[i].pipeFD : maxFD;
827 retry_fcntl( FIL__, __LINE__, source[i].pipeFD, F_SETFL, O_NONBLOCK);
828 FD_SET( source[i].pipeFD, &fds );
829 source[i].isset = 1;
830 ++icount;
831 }
832 else
833 {
834 sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENFAIL,
835 combuf);
836 }
837
838 ++i;
839 }
840
841 imax = i;
842 tv.tv_sec = 1;
843 tv.tv_usec = 0;
844 bufcount = 0;
845
846 while ( (icount > 0) && (bufcount < BUF_ENT) ) {
847
848 if ( (selcount = select (maxFD+1, &fds, NULL, NULL, &tv)) == -1)
849 break;
850
851 /* reset timeout for select()
852 */
853 tv.tv_sec = 1;
854 tv.tv_usec = 0;
855
856 /* timeout - let's not hang on forever
857 */
858 if (selcount == 0)
859 {
860 ++select_now;
861 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENTOUT,
862 (unsigned long) select_now);
863 if ( select_now > 9 )
864 break;
865 }
866
867 for (i = 0; i < imax; ++i) {
868
869 if ( FD_ISSET (source[i].pipeFD, &fds) ) {
870 count = fread (&buffer[bufcount],
871 1,
872 BUF_ENT-bufcount,
873 source[i].pipe );
874 if (count == 0)
875 {
876 if (0 != feof(source[i].pipe))
877 sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENCLOS,
878 (long) source[i].pipeFD);
879 else
880 sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENCLOS1,
881 (long) source[i].pipeFD);
882 source[i].isset = 0;
883 sh_pclose ( &source[i] );
884 --icount;
885 }
886 else
887 {
888 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENREAD,
889 (long) source[i].pipeFD, (long) count);
890 }
891 bufcount += count;
892
893 }
894 }
895
896 maxFD = 0;
897 FD_ZERO(&fds);
898
899 for (i = 0; i < imax; ++i)
900 {
901 if (source[i].isset == 1)
902 {
903 FD_SET( source[i].pipeFD, &fds );
904 maxFD = (source[i].pipeFD > maxFD) ? source[i].pipeFD : maxFD;
905 }
906 }
907 }
908
909 for (i = 0; i < imax; ++i)
910 {
911 if (source[i].isset == 1)
912 {
913 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENCLOS1,
914 (long) source[i].pipeFD);
915 sh_pclose ( &source[i] );
916 }
917 }
918 buffer[bufcount] = '\0';
919
920 SH_FREE(source);
921
922 if (0 != (caperr = sl_drop_cap_sub()))
923 {
924 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
925 sh_error_message (caperr, errbuf, sizeof(errbuf)),
926 _("sl_drop_cap_sub"));
927 }
928
929 if (bufcount > 0)
930 {
931 keybuf = (char *) sh_tiger_hash_uint32 (buffer,
932 TIGER_DATA, sl_strlen(buffer),
933 kbuf, KEY_BYT/sizeof(UINT32));
934
935 /* add previous entropy into the new pool
936 */
937 memset(addbuf, '\0', sizeof(addbuf));
938 for (i = 0; i < KEY_BYT; ++i)
939 {
940 addbuf[i] = keybuf[i];
941 addbuf[i+KEY_BYT] = skey->poolv[i];
942 }
943 keybuf = (char *) sh_tiger_hash_uint32 (addbuf,
944 TIGER_DATA, sizeof(addbuf),
945 kbuf, KEY_BYT/sizeof(UINT32));
946 memset(addbuf, '\0', sizeof(addbuf));
947
948 /* store in system pool
949 */
950 SH_MUTEX_LOCK_UNSAFE(mutex_skey);
951 for (i = 0; i < KEY_BYT; ++i)
952 skey->poolv[i] = keybuf[i];
953 skey->poolc = KEY_BYT;
954 SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
955 memset (buffer, '\0', BUF_ENT+2);
956 memset (keybuf, '\0', KEY_BYT);
957 SH_FREE(buffer);
958 }
959 else
960 {
961 SH_FREE(buffer);
962 SL_RETURN((-1), _("sh_entropy"));
963 }
964
965 /* give out nbytes Bytes from the entropy pool
966 */
967 SH_MUTEX_LOCK_UNSAFE(mutex_skey);
968 for (i = 0; i < nbytes; ++i)
969 {
970 nbuf[i] = skey->poolv[i];
971 --skey->poolc;
972 }
973 SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
974
975 SL_RETURN(0, _("sh_entropy"));
976}
977
978/* HAVE_UNIX_RANDOM */
979#endif
980
981#ifdef SH_CUTEST
982#include "CuTest.h"
983
984void Test_entropy (CuTest *tc)
985{
986 char bufx[9 * sizeof(UINT32) + 1];
987 char bufy[9 * sizeof(UINT32) + 1];
988 int status;
989
990 memset(skey->poolv, '\0', KEY_BYT);
991
992 status = sh_entropy (24, bufx);
993 CuAssertTrue(tc, 0 == status);
994
995 memset(skey->poolv, '\0', KEY_BYT);
996
997 status = sh_entropy (24, bufy);
998 CuAssertTrue(tc, 0 == status);
999
1000 CuAssertTrue(tc, 0 != memcmp(bufx, bufy, 24));
1001}
1002#endif
1003
1004
1005
1006
1007
1008
1009
1010
Note: See TracBrowser for help on using the repository browser.