source: trunk/src/sh_entropy.c @ 133

Last change on this file since 133 was 133, checked in by rainer, 12 years ago

Reentrant checksum/hash functions.

File size: 20.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    static 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            close( 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
150      #ifdef EGD_SOCKET_NAME
151        bname = EGD_SOCKET_NAME;
152      #endif
153        if ( !bname || !*bname )
154            bname = _("=entropy");
155
156        if ( *bname == '=' && bname[1] )
157            name = sh_util_strconcat ( DEFAULT_DATAROOT, "/", bname+1 , NULL );
158        else
159            name = sh_util_strconcat ( bname , NULL );
160
161        if ( strlen(name)+1 >= sizeof(addr.sun_path) )
162          {
163            sh_error_handle ((-1), FIL__, __LINE__, ENAMETOOLONG, MSG_E_SUBGEN,
164                             _("EGD socketname is too long"),
165                             _("sh_entropy") ); 
166            SH_FREE(name);
167            SL_RETURN( -1, _("sh_entropy") );
168          }
169
170        memset( &addr, 0, sizeof(addr) );
171        addr.sun_family = AF_UNIX;
172        sl_strlcpy( addr.sun_path, name, sizeof(addr.sun_path) );
173        addr_len = offsetof( struct sockaddr_un, sun_path )
174                   + strlen( addr.sun_path );
175
176        fd = socket(AF_UNIX, SOCK_STREAM, 0);
177        if( fd == -1 )
178          {
179            myerror = errno;
180            sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
181                             _("cannot create unix domain socket"),
182                             _("sh_entropy") ); 
183            SH_FREE(name);
184            SL_RETURN( -1, _("sh_entropy") );
185          }
186        if( connect( fd, (struct sockaddr*)&addr, addr_len) == -1 )
187          {
188            myerror = errno;
189            sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
190                             _("cannot connect to unix domain socket"),
191                             _("sh_entropy") ); 
192            SH_FREE(name);
193            SL_RETURN( -1, _("sh_entropy") );
194          }
195        SH_FREE(name);
196    }
197    do_restart = 0;
198
199    nbytes = length < 255? length : 255;
200    /* first time we do it with a non blocking request */
201    buffer[0] = 1; /* non blocking */
202    buffer[1] = nbytes;
203    if( do_write( fd, buffer, 2 ) == -1 )
204          {
205            myerror = errno;
206            sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
207                             _("cannot write to EGD"),
208                             _("sh_entropy") ); 
209            SL_RETURN( -1, _("sh_entropy") );
210          }
211    n = do_read( fd, buffer, 1 );
212    if( n == -1 ) {
213        myerror = errno;
214        sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, myerror, MSG_E_SUBGEN,
215                         _("read error on EGD"),
216                         _("sh_entropy") ); 
217        do_restart = 1;
218        goto restart;
219    }
220    n = buffer[0];
221    if( n ) {
222        n = do_read( fd, buffer, n );
223        if( n == -1 ) {
224            myerror = errno;
225            sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, myerror,MSG_E_SUBGEN,
226                             _("read error on EGD"),
227                             _("sh_entropy") ); 
228            do_restart = 1;
229            goto restart;
230        }
231        for (i = 0; i < n; ++i)
232          {
233            if (getbytes >= 0)
234              { *p = buffer[i]; ++p; --getbytes; }
235          }
236        length -= n;
237    }
238
239    while( length ) {
240        nbytes = length < 255? length : 255;
241
242        buffer[0] = 2; /* blocking */
243        buffer[1] = nbytes;
244        if( do_write( fd, buffer, 2 ) == -1 )
245          {
246            myerror = errno;
247            sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
248                             _("cannot write to EGD"),
249                             _("sh_entropy") ); 
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
270    SL_RETURN( 0, _("sh_entropy") ); /* success */
271}
272
273/* HAVE_EGD_RANDOM */
274#endif
275
276#if defined (HAVE_URANDOM)
277
278int read_mbytes(int timeout_val, char * path, char * nbuf, int nbytes)
279{
280  int m_count;
281  int fd2;
282
283  SL_ENTER(_("read_mbytes"));
284
285  if ((fd2 = aud_open (FIL__, __LINE__, SL_NOPRIV, path, O_RDONLY, 0)) >= 0) 
286    {
287      /* Test whether file is a character device, and is
288       * readable.
289       */
290      if (0 == sh_unix_device_readable(fd2)) 
291        {
292          m_count = sl_read_timeout_fd(fd2, &nbuf, nbytes, 
293                                       timeout_val, SL_FALSE);
294          if (m_count < 0)
295            m_count = 0;
296        }
297      else
298        m_count = 0;
299    }
300  else
301    m_count = 0;
302
303  close(fd2);
304
305  TPT((0, FIL__, __LINE__, _("msg=<read_mbytes: OK>\n"))); 
306  SL_RETURN(m_count, _("read_mbytes"));
307}
308
309/* Read nbytes bytes from /dev/random, mix them with
310 * previous reads using a hash function, and give out
311 * nbytes bytes from the result.
312 */
313int sh_entropy(int nbytes, char * nbuf)
314{
315  int    i, m_count = 0;
316  char * keybuf;
317  UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
318  char   addbuf[2 * KEY_BYT];
319
320  SL_ENTER(_("sh_entropy"));
321
322  ASSERT((nbytes <= KEY_BYT), _("nbytes <= KEY_BYT"))
323
324  if (nbytes > KEY_BYT)
325    nbytes = KEY_BYT;
326
327  memset(nbuf, '\0', nbytes);
328
329#ifdef NAME_OF_DEV_URANDOM
330  m_count = read_mbytes (30, NAME_OF_DEV_RANDOM, nbuf, nbytes);
331#else
332  m_count = read_mbytes (300, NAME_OF_DEV_RANDOM, nbuf, nbytes);
333#endif
334
335  if (m_count == 0)
336    {
337#ifdef NAME_OF_DEV_URANDOM
338      sh_error_handle (SH_ERR_NOTICE, FIL__, __LINE__, EIO, MSG_NODEV, 
339                       (long) sh.real.uid, NAME_OF_DEV_RANDOM);
340#else
341      sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_NODEV, 
342                       (long) sh.real.uid, NAME_OF_DEV_RANDOM);
343#endif
344    }
345
346#ifdef NAME_OF_DEV_URANDOM
347  if (m_count < nbytes)
348    {
349      i = read_mbytes(30, NAME_OF_DEV_URANDOM, &nbuf[m_count], nbytes-m_count);
350      if (i == 0)
351        sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_NODEV, 
352                         (long) sh.real.uid, NAME_OF_DEV_URANDOM);
353      else
354        m_count += i;
355    }
356#endif
357
358
359  if (m_count > 0)
360    {
361      /* -- Add previous entropy into the new pool. --
362       */
363      memset(addbuf, '\0', sizeof(addbuf));
364      for (i = 0; i < m_count; ++i)
365        addbuf[i]         = nbuf[i];
366      for (i = 0; i < KEY_BYT; ++i)
367        addbuf[i+KEY_BYT] = skey->poolv[i];
368      keybuf = (char *) sh_tiger_hash_uint32 (addbuf, 
369                                              TIGER_DATA, 2 * KEY_BYT,
370                                              kbuf, KEY_BYT/sizeof(UINT32));
371      memset(addbuf, '\0', sizeof(addbuf));
372     
373      /* -- Give out nbytes bytes from the new pool. --
374       */
375      for (i = 0; i < KEY_BYT; ++i)
376        {
377          skey->poolv[i] = keybuf[i];
378          if (i < nbytes) 
379            nbuf[i] = keybuf[i];
380        }
381      memset (keybuf, '\0', KEY_BYT);
382     
383      SL_RETURN(0, _("sh_entropy"));
384    }
385  else
386    {
387      SL_RETURN((-1), _("sh_entropy"));
388    }
389}
390
391/* HAVE_URANDOM */
392#endif
393
394#ifdef HAVE_UNIX_RANDOM
395
396#ifndef FD_SET
397#define NFDBITS         32
398#define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
399#define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
400#define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
401#endif /* !FD_SET */
402#ifndef FD_SETSIZE
403#define FD_SETSIZE      32
404#endif
405#ifndef FD_ZERO
406#define FD_ZERO(p)      memset((char *)(p), '\0', sizeof(*(p)))
407#endif
408
409#include "sh_static.h"
410
411static
412char   * com_path[] = {
413  N_("/usr/bin/xpg4/"),
414  N_("/usr/ucb/"),
415  N_("/bin/"),
416  N_("/sbin/"),
417  N_("/usr/bin/"),
418  N_("/usr/sbin/"),
419  N_("/usr/local/bin/"),
420  NULL
421};
422
423
424typedef struct {
425  char   * command;
426  char   * arg;
427  int      pipeFD;
428  pid_t    pid;
429  int      isset;
430  FILE   * pipe;
431} sourcetable_t;
432
433static
434sourcetable_t source[] = {
435  { N_("w"),
436    N_("w"),
437    0,
438    0,
439    0,
440    NULL },
441  { N_("netstat"),
442    N_("netstat -n"),
443    0,
444    0,
445    0,
446    NULL },
447  { N_("ps"),
448    N_("ps -ef"),
449    0,
450    0,
451    0,
452    NULL },
453  { N_("arp"),
454    N_("arp -a"),
455    0,
456    0,
457    0,
458    NULL },
459  { N_("free"),
460    N_("free"),
461    0,
462    0,
463    0,
464    NULL },
465  { N_("uptime"),
466    N_("uptime"),
467    0,
468    0,
469    0,
470    NULL },
471  { N_("procinfo"),
472    N_("procinfo -a"),
473    0,
474    0,
475    0,
476    NULL },
477  { N_("vmstat"),
478    N_("vmstat"),
479    0,
480    0,
481    0,
482    NULL },
483  { N_("w"), /* Play it again, Sam. */
484    N_("w"),
485    0,
486    0,
487    0,
488    NULL },
489  { NULL,
490    NULL,
491    0,
492    0,
493    0,
494    NULL }
495};
496
497
498static FILE * sh_popen (sourcetable_t  *source, char * command)
499{
500  int i;
501  int pipedes[2];
502  FILE *outf = NULL;
503  char * arg[4];
504  char * envp[2];
505  size_t len;
506  char   arg0[80];
507  char   arg1[80];
508
509  SL_ENTER(_("sh_popen"));
510
511  strncpy (arg0, _("/bin/sh"), sizeof(arg0));
512  arg[0] = arg0;
513  strncpy (arg1, _("-c"), sizeof(arg1));
514  arg[1] = arg1;
515  arg[2] = command;
516  arg[3] = NULL;
517
518  if (sh.timezone != NULL)
519    {
520      len = sl_strlen(sh.timezone) + 4;
521      envp[0] = malloc (len);     /* free() ok     */
522      if (envp[0] != NULL)
523        sl_snprintf (envp[0], len, "TZ=%s", sh.timezone);
524      else
525        envp[0] = NULL;
526      envp[1] = NULL;
527    }
528  else
529    {
530      envp[0] = NULL;
531    }
532
533 
534  /* Create the pipe
535   */
536  if (aud_pipe(FIL__, __LINE__, pipedes) < 0) {
537    if (envp[0] != NULL) free(envp[0]);
538    SL_RETURN(NULL, _("sh_popen"));
539  }
540 
541  fflush (NULL);
542
543  source->pid = aud_fork(FIL__, __LINE__);
544 
545  /* Failure
546   */
547  if (source->pid == (pid_t) - 1) {
548    close(pipedes[0]);
549    close(pipedes[1]);
550    if (envp[0] != NULL) free(envp[0]);
551    SL_RETURN(NULL, _("sh_popen"));
552  }
553
554  if (source->pid == (pid_t) 0) 
555    {
556
557      /* child - make read side of the pipe stdout
558       */
559      if (retry_aud_dup2(FIL__, __LINE__, 
560                         pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0)
561        aud__exit(FIL__, __LINE__, EXIT_FAILURE);
562     
563      /* close the pipe descriptors
564       */
565      close   (pipedes[STDIN_FILENO]);
566      close   (pipedes[STDOUT_FILENO]);
567
568      /* don't leak file descriptors
569       */
570      sh_unix_closeall (3, -1); /* in child process */
571
572      /* zero priv info
573       */
574      memset(skey, 0, sizeof(sh_key_t));
575
576      /* drop root privileges
577       */
578      i = 0; 
579      if (0 == geteuid()) 
580        {
581#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
582          struct passwd    pwd;
583          char             buffer[SH_PWBUF_SIZE];
584          struct passwd *  tempres;
585          sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, sizeof(buffer), &tempres);
586#else
587          struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
588#endif
589 
590          if (NULL != tempres) {
591            i = aud_setgid(FIL__, __LINE__, tempres->pw_gid); 
592            if (i == 0)
593              i = sh_unix_initgroups(DEFAULT_IDENT ,tempres->pw_gid);
594            if (i == 0) 
595              i = aud_setuid(FIL__, __LINE__, tempres->pw_uid);
596            /* make sure we cannot get root again
597             */
598            if ((tempres->pw_uid != 0) && (aud_setuid(FIL__, __LINE__, 0) >= 0))
599              i = -1;
600          } else {
601            i = -1;
602          }
603        }
604     
605      /* some problem ...
606       */
607      if (i == -1) {
608        aud__exit(FIL__, __LINE__, EXIT_FAILURE);
609      }
610     
611      freopen (_("/dev/null"), "r+", stderr);
612     
613      /* exec the program */
614      retry_aud_execve (FIL__, __LINE__, _("/bin/sh"), arg, envp);
615     
616      /* failed
617       */
618      aud__exit(FIL__, __LINE__, EXIT_FAILURE);
619    }
620
621    /* parent
622     */
623    if (envp[0] != NULL) 
624      free(envp[0]);
625
626    close (pipedes[STDOUT_FILENO]);
627    retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
628
629    outf = fdopen (pipedes[STDIN_FILENO], "r");
630
631    if (outf == NULL) 
632      {
633        aud_kill (FIL__, __LINE__, source->pid, SIGKILL);
634        close (pipedes[STDOUT_FILENO]);
635        waitpid (source->pid, NULL, 0);
636        source->pid = 0;
637        SL_RETURN(NULL, _("sh_popen"));
638      }
639
640    SL_RETURN(outf, _("sh_popen"));
641}
642
643
644static int sh_pclose (sourcetable_t *source)
645{
646    int status = 0;
647    int retval;
648    char msg[128];
649    char errbuf[SH_ERRBUF_SIZE];
650
651    SL_ENTER(_("sh_pclose"));
652
653    retval = fclose(source->pipe);
654    if (retval)
655      {
656        sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval, 
657                         MSG_E_SUBGEN,
658                         sh_error_message(retval, errbuf, sizeof(errbuf)),
659                         _("sh_pclose"));
660        SL_RETURN((-1), _("sh_pclose"));
661      }
662
663    retval = waitpid(source->pid, &status, 0);
664    if (retval != source->pid)
665      {
666        sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval, 
667                         MSG_E_SUBGEN,
668                         sh_error_message(retval, errbuf, sizeof(errbuf)),
669                         _("sh_pclose"));
670
671        status = -1;
672      }
673    else if (WIFSIGNALED(status))
674      {
675        sl_snprintf(msg, sizeof(msg), _("Subprocess terminated by signal %d"),
676                    WTERMSIG(status));
677        sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval, 
678                         MSG_E_SUBGEN,
679                         msg,
680                         _("sh_pclose"));
681        status = -1;
682      }
683
684    source->pipe = NULL;
685    source->pid = 0;
686    SL_RETURN(status, _("sh_pclose"));
687}
688
689#define BUF_ENT 32766
690
691/* Poll the system for randomness, mix results with
692 * previous reads using a hash function, and give out
693 * nbytes bytes from the result.
694 */
695int sh_entropy(int nbytes, char * nbuf)
696{
697  int    caperr;
698  char   combuf[80];
699  char * buffer;
700  int    i, j, icount;
701  int    bufcount = 0;
702  int    count;
703
704  char * keybuf;
705  UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
706  char   addbuf[2 * KEY_BYT];
707
708  struct timeval tv;
709  fd_set fds;
710  unsigned long select_now = 0;
711  int    maxFD = 0;
712  int    imax, selcount;
713  char errbuf[SH_ERRBUF_SIZE];
714 
715  SL_ENTER(_("sh_entropy"));
716
717  ASSERT((nbytes <= KEY_BYT), _("nbytes <= KEY_BYT"))
718
719  if (nbytes > KEY_BYT)
720    nbytes = KEY_BYT;
721
722
723  /* --- If there is entropy in the pool, return it. ---
724   */
725  if (skey->poolc >= nbytes)
726    {
727      j = KEY_BYT - skey->poolc;
728      for (i = 0; i < nbytes; ++i)
729        {
730          nbuf[i] = skey->poolv[i+j];
731          --skey->poolc;
732        }
733      SL_RETURN(0, _("sh_entropy"));
734    }
735
736
737  FD_ZERO(&fds);   
738
739  i = 0; icount = 0;
740  buffer = SH_ALLOC(BUF_ENT+2);
741
742  if (0 != (caperr = sl_get_cap_sub()))
743    {
744      sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
745                      sh_error_message (caperr, errbuf, sizeof(errbuf)), 
746                      _("sl_get_cap_sub"));
747    }
748
749  while (source[i].command != NULL) {
750
751    j = 0;
752    while (com_path[j] != NULL)
753      {
754        sl_strlcpy(combuf, _(com_path[j]),       80);
755        sl_strlcat(combuf, _(source[i].command), 80);
756
757        /* flawfinder: ignore */
758        if ( access (combuf, X_OK) == 0) 
759          {
760            sl_strlcpy(combuf, _(com_path[j]),       80);
761            sl_strlcat(combuf, _(source[i].arg),     80);
762            sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENSTART,
763                             combuf);
764            break;
765          }
766        ++j;
767      }
768
769    /* Not found, try next command.
770     */
771    if (com_path[j] == NULL) 
772      { 
773        ++i;
774        continue;
775      }
776
777    /* Source exists
778     */
779    source[i].pipe   = sh_popen  ( &source[i], combuf );
780    if (NULL != source[i].pipe)
781      { 
782        source[i].pipeFD = fileno ( source[i].pipe    );
783        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENEXEC,
784                         combuf, (long) source[i].pipeFD);
785
786        maxFD = (source[i].pipeFD > maxFD) ? source[i].pipeFD : maxFD;
787        retry_fcntl( FIL__, __LINE__, source[i].pipeFD, F_SETFL, O_NONBLOCK);
788        FD_SET( source[i].pipeFD, &fds );
789        source[i].isset = 1;
790        ++icount;
791      }
792    else
793      {
794        sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENFAIL,
795                         combuf);
796      }
797
798    ++i;
799  }
800
801  imax       = i;
802  tv.tv_sec  = 1;
803  tv.tv_usec = 0;
804  bufcount   = 0;
805
806  while ( (icount > 0) && (bufcount < BUF_ENT) ) {
807
808    if ( (selcount = select (maxFD+1, &fds, NULL, NULL, &tv)) == -1) 
809      break;
810
811    /* reset timeout for select()
812     */
813    tv.tv_sec  = 1;
814    tv.tv_usec = 0;
815
816    /* timeout - let's not hang on forever
817     */
818    if (selcount == 0) 
819      {
820        ++select_now;
821        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENTOUT,
822                         (unsigned long) select_now);
823        if ( select_now > 9 ) 
824          break;
825      }
826   
827    for (i = 0; i < imax; ++i) {
828
829      if ( FD_ISSET (source[i].pipeFD, &fds) ) {
830        count = fread (&buffer[bufcount], 
831                       1, 
832                       BUF_ENT-bufcount, 
833                       source[i].pipe );
834        if (count == 0) 
835          {
836            if (0 != feof(source[i].pipe))
837              sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENCLOS,
838                               (long) source[i].pipeFD);
839            else
840              sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENCLOS1,
841                               (long) source[i].pipeFD);
842            source[i].isset = 0;
843            sh_pclose ( &source[i] );
844            --icount;
845          }
846        else
847          {
848            sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENREAD,
849                             (long) source[i].pipeFD, (long) count);
850          }
851        bufcount += count;
852
853      } 
854    }
855
856    maxFD = 0;
857    FD_ZERO(&fds);   
858   
859    for (i = 0; i < imax; ++i)
860      {
861        if (source[i].isset == 1)
862          { 
863            FD_SET( source[i].pipeFD, &fds );
864            maxFD = (source[i].pipeFD > maxFD) ? source[i].pipeFD : maxFD;
865          }
866      }
867  }
868
869  for (i = 0; i < imax; ++i) 
870    {
871      if (source[i].isset == 1)
872        {
873          sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENCLOS1,
874                             (long) source[i].pipeFD);
875          sh_pclose ( &source[i] );
876        }
877    }
878  buffer[bufcount] = '\0';
879
880  if (0 != (caperr = sl_drop_cap_sub()))
881    {
882      sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
883                      sh_error_message (caperr, errbuf, sizeof(errbuf)), 
884                      _("sl_drop_cap_sub"));
885    }
886
887  if (bufcount > 0) 
888    {
889      keybuf = (char *) sh_tiger_hash_uint32 (buffer, 
890                                              TIGER_DATA, sl_strlen(buffer),
891                                              kbuf, KEY_BYT/sizeof(UINT32));
892
893      /* add previous entropy into the new pool
894       */
895      memset(addbuf, '\0', sizeof(addbuf));
896      for (i = 0; i < KEY_BYT; ++i)
897        {
898          addbuf[i]         = keybuf[i];
899          addbuf[i+KEY_BYT] = skey->poolv[i];
900        }
901      keybuf = (char *) sh_tiger_hash_uint32 (addbuf, 
902                                              TIGER_DATA, sizeof(addbuf),
903                                              kbuf, KEY_BYT/sizeof(UINT32));
904      memset(addbuf, '\0', sizeof(addbuf));
905     
906      /* store in system pool
907       */
908      for (i = 0; i < KEY_BYT; ++i)
909        skey->poolv[i] = keybuf[i];
910      skey->poolc = KEY_BYT;
911      memset (buffer, '\0', BUF_ENT+2);
912      memset (keybuf, '\0', KEY_BYT);
913      SH_FREE(buffer);
914    } 
915  else 
916    {
917      SH_FREE(buffer);
918      SL_RETURN((-1), _("sh_entropy"));
919    }
920
921  /* give out nbytes Bytes from the entropy pool
922   */
923  for (i = 0; i < nbytes; ++i)
924    {
925      nbuf[i] = skey->poolv[i];
926      --skey->poolc;
927    }
928
929  SL_RETURN(0, _("sh_entropy"));
930}
931
932/* HAVE_UNIX_RANDOM */
933#endif
934
935
936
937
938
939
940
Note: See TracBrowser for help on using the repository browser.