source: trunk/src/sh_entropy.c @ 541

Last change on this file since 541 was 541, checked in by katerina, 3 years ago

Fix for ticket #433 (coding standardisation).

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 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, S_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 ( 10, NAME_OF_DEV_URANDOM, 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_URANDOM);
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_RANDOM
356  if (m_count < nbytes)
357    {
358      i = read_mbytes(300, NAME_OF_DEV_RANDOM, &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_RANDOM);
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, S_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      /* cppcheck-suppress leakNoVarFunctionCall */
643      if (NULL != freopen (_("/dev/null"), "r+", stderr))
644        {
645     
646          /* exec the program */
647          do {
648            val_return = execve (_("/bin/sh"), arg, envp);
649          } while (val_return < 0 && errno == EINTR);
650        }
651
652      /* failed
653       */
654      _exit(EXIT_FAILURE);
655    }
656
657  /* parent
658   */
659#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
660  SH_FREE(buffer);
661#endif
662
663  if (envp[0] != NULL) 
664    free(envp[0]);
665 
666  sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
667  retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
668 
669  outf = fdopen (pipedes[STDIN_FILENO], "r");
670 
671  if (outf == NULL) 
672    {
673      aud_kill (FIL__, __LINE__, source->pid, SIGKILL);
674      sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
675      waitpid (source->pid, NULL, 0);
676      source->pid = 0;
677      SL_RETURN(NULL, _("sh_popen"));
678    }
679 
680  SL_RETURN(outf, _("sh_popen"));
681}
682
683
684static int sh_pclose (sourcetable_t *source)
685{
686    int status = 0;
687    int retval;
688    char msg[128];
689    char errbuf[SH_ERRBUF_SIZE];
690
691    SL_ENTER(_("sh_pclose"));
692
693    retval = sl_fclose(FIL__, __LINE__, source->pipe);
694    if (retval)
695      {
696        sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval, 
697                         MSG_E_SUBGEN,
698                         sh_error_message(retval, errbuf, sizeof(errbuf)),
699                         _("sh_pclose"));
700        SL_RETURN((-1), _("sh_pclose"));
701      }
702
703    retval = waitpid(source->pid, &status, 0);
704    if (retval != source->pid)
705      {
706        sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval, 
707                         MSG_E_SUBGEN,
708                         sh_error_message(retval, errbuf, sizeof(errbuf)),
709                         _("sh_pclose"));
710
711        status = -1;
712      }
713#if !defined(USE_UNO)
714    else if (WIFSIGNALED(status))
715      {
716        sl_snprintf(msg, sizeof(msg), _("Subprocess terminated by signal %d"),
717                    WTERMSIG(status));
718        sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval, 
719                         MSG_E_SUBGEN,
720                         msg,
721                         _("sh_pclose"));
722        status = -1;
723      }
724#endif
725
726    source->pipe = NULL;
727    source->pid = 0;
728    SL_RETURN(status, _("sh_pclose"));
729}
730
731#define BUF_ENT 32766
732
733/* Poll the system for randomness, mix results with
734 * previous reads using a hash function, and give out
735 * nbytes bytes from the result.
736 */
737int sh_entropy(int nbytes, char * nbuf)
738{
739  int    caperr;
740  char   combuf[80];
741  char * buffer;
742  int    i, j, icount;
743  int    bufcount = 0;
744  int    count;
745
746  char * keybuf;
747  UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
748  char   addbuf[2 * KEY_BYT];
749
750  struct timeval tv;
751  fd_set fds;
752  unsigned long select_now = 0;
753  int    maxFD = 0;
754  int    imax, selcount;
755  char errbuf[SH_ERRBUF_SIZE];
756
757  sourcetable_t  *source = NULL;
758 
759  SL_ENTER(_("sh_entropy"));
760
761  ASSERT((nbytes <= KEY_BYT), _("nbytes <= KEY_BYT"))
762
763  if (nbytes > KEY_BYT)
764    nbytes = KEY_BYT;
765
766
767  /* --- If there is entropy in the pool, return it. ---
768   */
769  SH_MUTEX_LOCK_UNSAFE(mutex_skey);
770  if (skey->poolc >= nbytes)
771    {
772      j = KEY_BYT - skey->poolc;
773      for (i = 0; i < nbytes; ++i)
774        {
775          nbuf[i] = skey->poolv[i+j];
776          --skey->poolc;
777        }
778      SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); /* alternative path */
779      SL_RETURN(0, _("sh_entropy"));
780    }
781  SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
782
783
784  FD_ZERO(&fds);   
785
786  i = 0; icount = 0;
787  buffer = SH_ALLOC(BUF_ENT+2);
788
789  if (0 != (caperr = sl_get_cap_sub()))
790    {
791      sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
792                      sh_error_message (caperr, errbuf, sizeof(errbuf)), 
793                      _("sl_get_cap_sub"));
794    }
795
796  while (source_template[i].command != NULL) {
797    ++i;
798  }
799  source = SH_ALLOC(i * sizeof(sourcetable_t));
800  for (j = 0; j < i;++j)
801    memcpy(&source[j], &source_template[j], sizeof(sourcetable_t));
802  i = 0;
803
804  while (source_template[i].command != NULL) {
805
806    j = 0;
807    while (com_path[j] != NULL)
808      {
809        sl_strlcpy(combuf, _(com_path[j]),       80);
810        sl_strlcat(combuf, _(source[i].command), 80);
811
812        /* flawfinder: ignore */
813        if ( access (combuf, X_OK) == 0) 
814          {
815            sl_strlcpy(combuf, _(com_path[j]),       80);
816            sl_strlcat(combuf, _(source[i].arg),     80);
817            sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENSTART,
818                             combuf);
819            break;
820          }
821        ++j;
822      }
823
824    /* Not found, try next command.
825     */
826    if (com_path[j] == NULL) 
827      { 
828        ++i;
829        continue;
830      }
831
832    /* Source exists
833     */
834    source[i].pipe   = sh_popen  ( &source[i], combuf );
835    if (NULL != source[i].pipe)
836      { 
837        source[i].pipeFD = fileno ( source[i].pipe    );
838        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENEXEC,
839                         combuf, (long) source[i].pipeFD);
840
841        maxFD = (source[i].pipeFD > maxFD) ? source[i].pipeFD : maxFD;
842        retry_fcntl( FIL__, __LINE__, source[i].pipeFD, F_SETFL, O_NONBLOCK);
843        FD_SET( source[i].pipeFD, &fds );
844        source[i].isset = 1;
845        ++icount;
846      }
847    else
848      {
849        sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENFAIL,
850                         combuf);
851      }
852
853    ++i;
854  }
855
856  imax       = i;
857  tv.tv_sec  = 1;
858  tv.tv_usec = 0;
859  bufcount   = 0;
860
861  while ( (icount > 0) && (bufcount < BUF_ENT) ) {
862
863    if ( (selcount = select (maxFD+1, &fds, NULL, NULL, &tv)) == -1) 
864      break;
865
866    /* reset timeout for select()
867     */
868    tv.tv_sec  = 1;
869    tv.tv_usec = 0;
870
871    /* timeout - let's not hang on forever
872     */
873    if (selcount == 0) 
874      {
875        ++select_now;
876        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENTOUT,
877                         (unsigned long) select_now);
878        if ( select_now > 9 ) 
879          break;
880      }
881   
882    for (i = 0; i < imax; ++i) {
883
884      if ( FD_ISSET (source[i].pipeFD, &fds) ) {
885        count = fread (&buffer[bufcount], 
886                       1, 
887                       BUF_ENT-bufcount, 
888                       source[i].pipe );
889        if (count == 0) 
890          {
891            if (0 != feof(source[i].pipe))
892              sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENCLOS,
893                               (long) source[i].pipeFD);
894            else
895              sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENCLOS1,
896                               (long) source[i].pipeFD);
897            source[i].isset = 0;
898            sh_pclose ( &source[i] );
899            --icount;
900          }
901        else
902          {
903            sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENREAD,
904                             (long) source[i].pipeFD, (long) count);
905          }
906        bufcount += count;
907
908      } 
909    }
910
911    maxFD = 0;
912    FD_ZERO(&fds);   
913   
914    for (i = 0; i < imax; ++i)
915      {
916        if (source[i].isset == 1)
917          { 
918            FD_SET( source[i].pipeFD, &fds );
919            maxFD = (source[i].pipeFD > maxFD) ? source[i].pipeFD : maxFD;
920          }
921      }
922  }
923
924  for (i = 0; i < imax; ++i) 
925    {
926      if (source[i].isset == 1)
927        {
928          sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENCLOS1,
929                             (long) source[i].pipeFD);
930          sh_pclose ( &source[i] );
931        }
932    }
933  buffer[bufcount] = '\0';
934 
935  SH_FREE(source);
936
937  if (0 != (caperr = sl_drop_cap_sub()))
938    {
939      sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
940                      sh_error_message (caperr, errbuf, sizeof(errbuf)), 
941                      _("sl_drop_cap_sub"));
942    }
943
944#ifdef HAVE_GETTIMEOFDAY
945  {
946    unsigned short tseed[3];
947
948    gettimeofday(&tv, 0);
949    tseed[0] = tv.tv_sec & 0xFFFF;
950    tseed[1] = tv.tv_usec & 0xFFFF;
951    tseed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16;
952    keybuf = (char *) sh_tiger_hash_uint32 ((char *) tseed, 
953                                            TIGER_DATA, sizeof(tseed),
954                                            kbuf, KEY_BYT/sizeof(UINT32));
955    memset(addbuf, 0, sizeof(addbuf));
956    for (i = 0; i < KEY_BYT; ++i)
957      {
958        addbuf[i]         = keybuf[i];
959        addbuf[i+KEY_BYT] = skey->poolv[i];
960      }
961    SH_MUTEX_LOCK_UNSAFE(mutex_skey);
962    for (i = 0; i < KEY_BYT; ++i)
963      skey->poolv[i] ^= keybuf[i];
964    SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
965  }
966#endif
967
968  if (bufcount > 0) 
969    {
970      keybuf = (char *) sh_tiger_hash_uint32 (buffer, 
971                                              TIGER_DATA, sl_strlen(buffer),
972                                              kbuf, KEY_BYT/sizeof(UINT32));
973
974      /* add previous entropy into the new pool
975       */
976      memset(addbuf, 0, sizeof(addbuf));
977      for (i = 0; i < KEY_BYT; ++i)
978        {
979          addbuf[i]         = keybuf[i];
980          addbuf[i+KEY_BYT] = skey->poolv[i];
981        }
982      keybuf = (char *) sh_tiger_hash_uint32 (addbuf, 
983                                              TIGER_DATA, sizeof(addbuf),
984                                              kbuf, KEY_BYT/sizeof(UINT32));
985      memset(addbuf, 0, sizeof(addbuf));
986     
987      /* store in system pool
988       */
989      SH_MUTEX_LOCK_UNSAFE(mutex_skey);
990      for (i = 0; i < KEY_BYT; ++i)
991        skey->poolv[i] = keybuf[i];
992      skey->poolc = KEY_BYT;
993      SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
994      memset (buffer, 0, BUF_ENT+2);
995      memset (keybuf, 0, KEY_BYT);
996      SH_FREE(buffer);
997    } 
998  else 
999    {
1000      SH_FREE(buffer);
1001      SL_RETURN((-1), _("sh_entropy"));
1002    }
1003
1004  /* give out nbytes Bytes from the entropy pool
1005   */
1006  SH_MUTEX_LOCK_UNSAFE(mutex_skey);
1007  for (i = 0; i < nbytes; ++i)
1008    {
1009      nbuf[i] = skey->poolv[i];
1010      --skey->poolc;
1011    }
1012  SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
1013
1014  SL_RETURN(0, _("sh_entropy"));
1015}
1016
1017/* HAVE_UNIX_RANDOM */
1018#endif
1019
1020#ifdef SH_CUTEST
1021#include "CuTest.h"
1022
1023void Test_entropy (CuTest *tc)
1024{
1025  char                 bufx[9 * sizeof(UINT32) + 1];
1026  char                 bufy[9 * sizeof(UINT32) + 1];
1027  int                  status;
1028  int                  count;
1029
1030  for (count = 0; count < 20; ++count)
1031    {
1032      memset(skey->poolv, 0, KEY_BYT);
1033      skey->poolc = 0;
1034
1035      status = sh_entropy (24, bufx);
1036      CuAssertTrue(tc, 0 == status);
1037     
1038      memset(skey->poolv, 0, KEY_BYT);
1039      skey->poolc = 0;
1040
1041      status = sh_entropy (24, bufy);
1042      CuAssertTrue(tc, 0 == status);
1043     
1044      CuAssertTrue(tc, 0 != memcmp(bufx, bufy, 24));
1045    }
1046}
1047#endif
1048
1049
1050
1051
1052
1053
1054
1055
Note: See TracBrowser for help on using the repository browser.