debug: Add new debug class "drs_repl" for DRS replication processing
[samba.git] / lib / util / genrand.c
index 4473433b5f78e363137a90ea2c4556ebb7b44623..a775535c49e781140bbf5a26a8577f01193f0c52 100644 (file)
 
 #include "replace.h"
 #include "system/filesys.h"
-#include "../lib/crypto/crypto.h"
 #include "lib/util/genrand.h"
+#include "sys_rw_data.h"
 #include "lib/util/blocking.h"
-#include "lib/util/time_basic.h"
-#include "lib/util/byteorder.h"
-
-/**
- * @file
- * @brief Random number generation
- */
-
-static unsigned char hash[258];
-static uint32_t counter;
-
-static bool done_reseed = false;
-static unsigned int bytes_since_reseed = 0;
 
 static int urand_fd = -1;
 
-static void (*reseed_callback)(void *userdata, int *newseed);
-static void *reseed_callback_userdata = NULL;
-
-/**
- Copy any user given reseed data.
-**/
-
-_PUBLIC_ void set_rand_reseed_callback(void (*fn)(void *, int *), void *userdata)
-{
-       reseed_callback = fn;
-       reseed_callback_userdata = userdata;
-       set_need_random_reseed();
-}
-
-/**
- * Tell the random number generator it needs to reseed.
- */
-_PUBLIC_ void set_need_random_reseed(void)
+static void open_urandom(void)
 {
-       done_reseed = false;
-       bytes_since_reseed = 0;
-}
-
-static void get_rand_reseed_data(int *reseed_data)
-{
-       if (reseed_callback) {
-               reseed_callback(reseed_callback_userdata, reseed_data);
-       } else {
-               *reseed_data = 0;
-       }
-}
-
-/****************************************************************
- Setup the seed.
-*****************************************************************/
-
-static void seed_random_stream(unsigned char *seedval, size_t seedlen)
-{
-       unsigned char j = 0;
-       size_t ind;
-
-       for (ind = 0; ind < 256; ind++)
-               hash[ind] = (unsigned char)ind;
-
-       for( ind = 0; ind < 256; ind++) {
-               unsigned char tc;
-
-               j += (hash[ind] + seedval[ind%seedlen]);
-
-               tc = hash[ind];
-               hash[ind] = hash[j];
-               hash[j] = tc;
-       }
-
-       hash[256] = 0;
-       hash[257] = 0;
-}
-
-/****************************************************************
- Get datasize bytes worth of random data.
-*****************************************************************/
-
-static void get_random_stream(unsigned char *data, size_t datasize)
-{
-       unsigned char index_i = hash[256];
-       unsigned char index_j = hash[257];
-       size_t ind;
-
-       for( ind = 0; ind < datasize; ind++) {
-               unsigned char tc;
-               unsigned char t;
-
-               index_i++;
-               index_j += hash[index_i];
-
-               tc = hash[index_i];
-               hash[index_i] = hash[index_j];
-               hash[index_j] = tc;
-
-               t = hash[index_i] + hash[index_j];
-               data[ind] = hash[t];
-       }
-
-       hash[256] = index_i;
-       hash[257] = index_j;
-}
-
-/****************************************************************
- Get a 16 byte hash from the contents of a file.
-
- Note that the hash is initialised, because the extra entropy is not
- worth the valgrind pain.
-*****************************************************************/
-
-static void do_filehash(const char *fname, unsigned char *the_hash)
-{
-       unsigned char buf[1011]; /* deliberate weird size */
-       unsigned char tmp_md4[16];
-       int fd, n;
-
-       ZERO_STRUCT(tmp_md4);
-
-       fd = open(fname,O_RDONLY,0);
-       if (fd == -1)
+       if (urand_fd != -1) {
                return;
-
-       while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) {
-               mdfour(tmp_md4, buf, n);
-               for (n=0;n<16;n++)
-                       the_hash[n] ^= tmp_md4[n];
-       }
-       close(fd);
-}
-
-/**************************************************************
- Try and get a good random number seed. Try a number of
- different factors. Firstly, try /dev/urandom - use if exists.
-
- We use /dev/urandom as a read of /dev/random can block if
- the entropy pool dries up. This leads clients to timeout
- or be very slow on connect.
-
- If we can't use /dev/urandom then seed the stream random generator
- above...
-**************************************************************/
-
-static int do_reseed(int fd)
-{
-       unsigned char seed_inbuf[40];
-       uint32_t v1, v2; struct timeval tval; pid_t mypid;
-       int reseed_data = 0;
-
-       if (fd == -1) {
-               fd = open( "/dev/urandom", O_RDONLY,0);
-               if (fd != -1) {
-                       smb_set_close_on_exec(fd);
-               }
-       }
-       if (fd != -1
-           && (read(fd, seed_inbuf, sizeof(seed_inbuf)) == sizeof(seed_inbuf))) {
-               seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
-               return fd;
        }
-
-       /* Add in some secret file contents */
-
-       do_filehash("/etc/shadow", &seed_inbuf[0]);
-
-       /*
-        * Add the counter, time of day, and pid.
-        */
-
-       GetTimeOfDay(&tval);
-       mypid = getpid();
-       v1 = (counter++) + mypid + tval.tv_sec;
-       v2 = (counter++) * mypid + tval.tv_usec;
-
-       SIVAL(seed_inbuf, 32, v1 ^ IVAL(seed_inbuf, 32));
-       SIVAL(seed_inbuf, 36, v2 ^ IVAL(seed_inbuf, 36));
-
-       /*
-        * Add any user-given reseed data.
-        */
-
-       get_rand_reseed_data(&reseed_data);
-       if (reseed_data) {
-               size_t i;
-               for (i = 0; i < sizeof(seed_inbuf); i++)
-                       seed_inbuf[i] ^= ((char *)(&reseed_data))[i % sizeof(reseed_data)];
+       urand_fd = open( "/dev/urandom", O_RDONLY,0);
+       if (urand_fd == -1) {
+               abort();
        }
-
-       seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
-
-       return -1;
+       smb_set_close_on_exec(urand_fd);
 }
 
-/**
- Interface to the (hopefully) good crypto random number generator.
- Will use our internal PRNG if more than 40 bytes of random generation
- has been requested, otherwise tries to read from /dev/random
-**/
 _PUBLIC_ void generate_random_buffer(uint8_t *out, int len)
 {
-       unsigned char md4_buf[64];
-       unsigned char tmp_buf[16];
-       unsigned char *p;
-
-       if(!done_reseed) {
-               bytes_since_reseed += len;
-
-               /* Magic constant to try and avoid reading 40 bytes
-                * and setting up the PRNG if the app only ever wants
-                * a few bytes */
-               if (bytes_since_reseed < 40) {
-                       if (urand_fd == -1) {
-                               urand_fd = open( "/dev/urandom", O_RDONLY,0);
-                               if (urand_fd != -1) {
-                                       smb_set_close_on_exec(urand_fd);
-                               }
-                       }
-                       if(urand_fd != -1 && (read(urand_fd, out, len) == len)) {
-                               return;
-                       }
-               }
-
-               urand_fd = do_reseed(urand_fd);
-               done_reseed = true;
-       }
-
-       /*
-        * Generate random numbers in chunks of 64 bytes,
-        * then md4 them & copy to the output buffer.
-        * This way the raw state of the stream is never externally
-        * seen.
-        */
+       ssize_t rw_ret;
 
-       p = out;
-       while(len > 0) {
-               int copy_len = len > 16 ? 16 : len;
+       open_urandom();
 
-               get_random_stream(md4_buf, sizeof(md4_buf));
-               mdfour(tmp_buf, md4_buf, sizeof(md4_buf));
-               memcpy(p, tmp_buf, copy_len);
-               p += copy_len;
-               len -= copy_len;
+       rw_ret = read_data(urand_fd, out, len);
+       if (rw_ret != len) {
+               abort();
        }
 }
 
-/**
- Interface to the (hopefully) good crypto random number generator.
- Will always use /dev/urandom if available.
-**/
+/*
+ * Keep generate_secret_buffer in case we ever want to do something
+ * different
+ */
 _PUBLIC_ void generate_secret_buffer(uint8_t *out, int len)
 {
-       if (urand_fd == -1) {
-               urand_fd = open( "/dev/urandom", O_RDONLY,0);
-               if (urand_fd != -1) {
-                       smb_set_close_on_exec(urand_fd);
-               }
-       }
-       if(urand_fd != -1 && (read(urand_fd, out, len) == len)) {
-               return;
-       }
-
        generate_random_buffer(out, len);
 }