Back to index

lightning-sunbird  0.9+nobinonly
Defines | Functions | Variables
unix_rand.c File Reference
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include "secrng.h"
#include "secerr.h"
#include "prerror.h"

Go to the source code of this file.

Defines

#define SAFE_POPEN_MAXARGS   10 /* must be at least 2 */
#define DO_NETSTAT   1
#define TOTAL_FILE_LIMIT   1000000 /* one million */

Functions

size_t RNG_FileUpdate (const char *fileName, size_t limit)
static size_t CopyLowBits (void *dst, size_t dstlen, void *src, size_t srclen)
size_t RNG_GetNoise (void *buf, size_t maxbytes)
static FILEsafe_popen (char *cmd)
static int safe_pclose (FILE *fp)
void RNG_SystemInfoForRNG (void)
void RNG_FileForRNG (const char *fileName)
size_t RNG_SystemRNG (void *dest, size_t maxLen)

Variables

static pid_t safe_popen_pid
static struct sigaction

Define Documentation

#define DO_NETSTAT   1

Definition at line 879 of file unix_rand.c.

#define SAFE_POPEN_MAXARGS   10 /* must be at least 2 */

Definition at line 755 of file unix_rand.c.

#define TOTAL_FILE_LIMIT   1000000 /* one million */

Definition at line 1081 of file unix_rand.c.


Function Documentation

static size_t CopyLowBits ( void dst,
size_t  dstlen,
void src,
size_t  srclen 
) [static]

Definition at line 62 of file unix_rand.c.

{
    union endianness {
       int32 i;
       char c[4];
    } u;

    if (srclen <= dstlen) {
       memcpy(dst, src, srclen);
       return srclen;
    }
    u.i = 0x01020304;
    if (u.c[0] == 0x01) {
       /* big-endian case */
       memcpy(dst, (char*)src + (srclen - dstlen), dstlen);
    } else {
       /* little-endian case */
       memcpy(dst, src, dstlen);
    }
    return dstlen;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void RNG_FileForRNG ( const char *  fileName)

Definition at line 1126 of file unix_rand.c.

Here is the call graph for this function:

size_t RNG_FileUpdate ( const char *  fileName,
size_t  limit 
)
size_t RNG_GetNoise ( void buf,
size_t  maxbytes 
)

Definition at line 733 of file unix_rand.c.

{
    struct timeval tv;
    int n = 0;
    int c;

    n = GetHighResClock(buf, maxbytes);
    maxbytes -= n;

#if defined(__sun) && (defined(_svr4) || defined(SVR4)) || defined(sony)
    (void)gettimeofday(&tv);
#else
    (void)gettimeofday(&tv, 0);
#endif
    c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec));
    n += c;
    maxbytes -= c;
    c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec));
    n += c;
    return n;
}

Here is the call graph for this function:

Definition at line 881 of file unix_rand.c.

{
    FILE *fp;
    char buf[BUFSIZ];
    size_t bytes;
    const char * const *cp;
    char *randfile;
#ifdef DARWIN
    char **environ = *_NSGetEnviron();
#else
    extern char **environ;
#endif
#ifdef BEOS
    static const char * const files[] = {
       "/boot/var/swap",
       "/boot/var/log/syslog",
       "/boot/var/tmp",
       "/boot/home/config/settings",
       "/boot/home",
       0
    };
#else
    static const char * const files[] = {
       "/etc/passwd",
       "/etc/utmp",
       "/tmp",
       "/var/tmp",
       "/usr/tmp",
       0
    };
#endif

#ifdef DO_PS
For now it is considered that it is too expensive to run the ps command
for the small amount of entropy it provides.
#if defined(__sun) && (!defined(__svr4) && !defined(SVR4)) || defined(bsdi) || defined(LINUX)
    static char ps_cmd[] = "ps aux";
#else
    static char ps_cmd[] = "ps -el";
#endif
#endif /* DO_PS */
#if defined(BSDI)
    static char netstat_ni_cmd[] = "netstat -nis";
#else
    static char netstat_ni_cmd[] = "netstat -ni";
#endif

    GiveSystemInfo();

    bytes = RNG_GetNoise(buf, sizeof(buf));
    RNG_RandomUpdate(buf, bytes);

    /*
     * Pass the C environment and the addresses of the pointers to the
     * hash function. This makes the random number function depend on the
     * execution environment of the user and on the platform the program
     * is running on.
     */
    if (environ != NULL) {
        cp = (const char * const *) environ;
        while (*cp) {
           RNG_RandomUpdate(*cp, strlen(*cp));
           cp++;
        }
        RNG_RandomUpdate(environ, (char*)cp - (char*)environ);
    }

    /* Give in system information */
    if (gethostname(buf, sizeof(buf)) == 0) {
       RNG_RandomUpdate(buf, strlen(buf));
    }
    GiveSystemInfo();

    /* grab some data from system's PRNG before any other files. */
    bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT);

    /* If the user points us to a random file, pass it through the rng */
    randfile = getenv("NSRANDFILE");
    if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) {
       RNG_FileForRNG(randfile);
    }

    /* pass other files through */
    for (cp = files; *cp; cp++)
       RNG_FileForRNG(*cp);

/*
 * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen
 * in a pthreads environment.  Therefore, we call safe_popen last and on
 * BSD/OS we do not call safe_popen when we succeeded in getting data
 * from /dev/urandom.
 */

#ifdef BSDI
    if (bytes)
        return;
#endif

#ifdef SOLARIS

/*
 * On Solaris, NSS may be initialized automatically from libldap in
 * applications that are unaware of the use of NSS. safe_popen forks, and
 * sometimes creates issues with some applications' pthread_atfork handlers.
 * We always have /dev/urandom on Solaris 9 and above as an entropy source,
 * and for Solaris 8 we have the libkstat interface, so we don't need to
 * fork netstat.
 */

#undef DO_NETSTAT
    if (!bytes) {
        /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */
        PRUint32 kstat_bytes = 0;
        if (SECSuccess != RNG_kstat(&kstat_bytes)) {
            PORT_Assert(0);
        }
        bytes += kstat_bytes;
        PORT_Assert(bytes);
    }
#endif

#ifdef DO_PS
    fp = safe_popen(ps_cmd);
    if (fp != NULL) {
       while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0)
           RNG_RandomUpdate(buf, bytes);
       safe_pclose(fp);
    }
#endif

#ifdef DO_NETSTAT
    fp = safe_popen(netstat_ni_cmd);
    if (fp != NULL) {
       while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0)
           RNG_RandomUpdate(buf, bytes);
       safe_pclose(fp);
    }
#endif

}

Here is the call graph for this function:

Here is the caller graph for this function:

size_t RNG_SystemRNG ( void dest,
size_t  maxLen 
)

Definition at line 1131 of file unix_rand.c.

{
    FILE *file;
    size_t bytes;
    size_t fileBytes = 0;
    unsigned char *buffer = dest;

    file = fopen("/dev/urandom", "r");
    if (file == NULL) {
       PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
       return fileBytes;
    }
    while (maxLen > fileBytes) {
       bytes = maxLen - fileBytes;
       bytes = fread(buffer, 1, bytes, file);
       if (bytes == 0) 
           break;
       fileBytes += bytes;
       buffer += bytes;
    }
    fclose(file);
    if (fileBytes != maxLen) {
       PORT_SetError(SEC_ERROR_NEED_RANDOM);  /* system RNG failed */
       fileBytes = 0;
    }
    return fileBytes;
}

Here is the call graph for this function:

static int safe_pclose ( FILE fp) [static]

Definition at line 844 of file unix_rand.c.

{
    pid_t pid;
    int count, status;

    if ((pid = safe_popen_pid) == 0)
       return -1;
    safe_popen_pid = 0;

    /* if the child hasn't exited, kill it -- we're done with its output */
    count = 0;
    while (waitpid(pid, &status, WNOHANG) == 0) {
       if (kill(pid, SIGKILL) < 0 && errno == ESRCH)
           break;
       if (++count == 1000)
           break;
    }

    /* Reset SIGCHLD signal hander before returning */
    sigaction(SIGCHLD, &oldact, NULL);

    fclose(fp);
    return status;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static FILE* safe_popen ( char *  cmd) [static]

Definition at line 766 of file unix_rand.c.

{
    int p[2], fd, argc;
    pid_t pid;
    char *argv[SAFE_POPEN_MAXARGS + 1];
    FILE *fp;
    static char blank[] = " \t";
    static struct sigaction newact;

    if (pipe(p) < 0)
       return 0;

    /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */
    newact.sa_handler = SIG_DFL;
    newact.sa_flags = 0;
    sigfillset(&newact.sa_mask);
    sigaction (SIGCHLD, &newact, &oldact);

    pid = fork();
    switch (pid) {
      case -1:
       close(p[0]);
       close(p[1]);
       sigaction (SIGCHLD, &oldact, NULL);
       return 0;

      case 0:
       /* dup write-side of pipe to stderr and stdout */
       if (p[1] != 1) dup2(p[1], 1);
       if (p[1] != 2) dup2(p[1], 2);
       close(0);
        {
            int ndesc = getdtablesize();
            for (fd = PR_MIN(65536, ndesc); --fd > 2; close(fd));
        }

       /* clean up environment in the child process */
       putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc");
       putenv("SHELL=/bin/sh");
       putenv("IFS= \t");

       /*
        * The caller may have passed us a string that is in text
        * space. It may be illegal to modify the string
        */
       cmd = strdup(cmd);
       /* format argv */
       argv[0] = strtok(cmd, blank);
       argc = 1;
       while ((argv[argc] = strtok(0, blank)) != 0) {
           if (++argc == SAFE_POPEN_MAXARGS) {
              argv[argc] = 0;
              break;
           }
       }

       /* and away we go */
       execvp(argv[0], argv);
       exit(127);
       break;

      default:
       close(p[1]);
       fp = fdopen(p[0], "r");
       if (fp == 0) {
           close(p[0]);
           sigaction (SIGCHLD, &oldact, NULL);
           return 0;
       }
       break;
    }

    /* non-zero means there's a cmd running */
    safe_popen_pid = pid;
    return fp;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 762 of file unix_rand.c.

struct sigaction [static]

Definition at line 763 of file unix_rand.c.