r6798: Valgrind pain is not something I look forward to - if we ever fall
[samba.git] / source / lib / genrand.c
index fdd4bb14fc52a2ff87e953f329405aa480c78843..9d40e72afcf4dc6658d7324abbe7140b7cf3d298 100644 (file)
 */
 
 #include "includes.h"
+#include "system/iconv.h"
+#include "system/filesys.h"
+#include "lib/crypto/crypto.h"
 
 static unsigned char hash[258];
-static uint32 counter;
-static unsigned char *reseed_data;
-static size_t reseed_data_size;
+static uint32_t counter;
+
+static BOOL done_reseed = False;
+static void (*reseed_callback)(int *newseed);
 
 /**************************************************************** 
  Copy any user given reseed data.
 *****************************************************************/
 
-void set_rand_reseed_data(unsigned char *data, size_t len)
+void set_rand_reseed_callback(void (*fn)(int *))
 {
-       SAFE_FREE(reseed_data);
-       reseed_data_size = 0;
+       reseed_callback = fn;
+       set_need_random_reseed();
+}
+
+void set_need_random_reseed(void)
+{
+       done_reseed = False;
+}
 
-       reseed_data = (unsigned char *)memdup(data, len);
-       if (reseed_data)
-               reseed_data_size = len;
+static void get_rand_reseed_data(int *reseed_data)
+{
+       if (reseed_callback) {
+               reseed_callback(reseed_data);
+       } else {
+               *reseed_data = 0;
+       }
 }
 
 /**************************************************************** 
@@ -97,8 +111,10 @@ static void get_random_stream(unsigned char *data, size_t datasize)
 }
 
 /****************************************************************
- Get a 16 byte hash from the contents of a file.
- Note that the hash is not initialised.
+ 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)
@@ -107,7 +123,9 @@ static void do_filehash(const char *fname, unsigned char *the_hash)
        unsigned char tmp_md4[16];
        int fd, n;
 
-       fd = sys_open(fname,O_RDONLY,0);
+       ZERO_STRUCT(tmp_md4);
+
+       fd = open(fname,O_RDONLY,0);
        if (fd == -1)
                return;
 
@@ -134,14 +152,14 @@ static void do_filehash(const char *fname, unsigned char *the_hash)
 static int do_reseed(BOOL use_fd, int fd)
 {
        unsigned char seed_inbuf[40];
-       uint32 v1, v2; struct timeval tval; pid_t mypid;
-       struct passwd *pw;
+       uint32_t v1, v2; struct timeval tval; pid_t mypid;
+       int reseed_data = 0;
 
        if (use_fd) {
                if (fd != -1)
                        return fd;
 
-               fd = sys_open( "/dev/urandom", O_RDONLY,0);
+               fd = open( "/dev/urandom", O_RDONLY,0);
                if(fd >= 0)
                        return fd;
        }
@@ -151,22 +169,6 @@ static int do_reseed(BOOL use_fd, int fd)
        do_filehash("/etc/shadow", &seed_inbuf[0]);
        do_filehash(lp_smb_passwd_file(), &seed_inbuf[16]);
 
-       /*
-        * Add in the root encrypted password.
-        * On any system where security is taken
-        * seriously this will be secret.
-        */
-
-       pw = getpwnam_alloc("root");
-       if (pw && pw->pw_passwd) {
-               size_t i;
-               unsigned char md4_tmp[16];
-               mdfour(md4_tmp, (unsigned char *)pw->pw_passwd, strlen(pw->pw_passwd));
-               for (i=0;i<16;i++)
-                       seed_inbuf[8+i] ^= md4_tmp[i];
-               passwd_free(&pw);
-       }
-
        /*
         * Add the counter, time of day, and pid.
         */
@@ -183,10 +185,11 @@ static int do_reseed(BOOL use_fd, int fd)
         * 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] ^= reseed_data[i % reseed_data_size];
+                       seed_inbuf[i] ^= ((char *)(&reseed_data))[i % sizeof(reseed_data)];
        }
 
        seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
@@ -194,19 +197,17 @@ static int do_reseed(BOOL use_fd, int fd)
        return -1;
 }
 
-/*******************************************************************
+/*
  Interface to the (hopefully) good crypto random number generator.
-********************************************************************/
-
-void generate_random_buffer( unsigned char *out, int len, BOOL do_reseed_now)
+*/
+void generate_random_buffer(uint8_t *out, int len)
 {
-       static BOOL done_reseed = False;
        static int urand_fd = -1;
        unsigned char md4_buf[64];
        unsigned char tmp_buf[16];
        unsigned char *p;
 
-       if(!done_reseed || do_reseed_now) {
+       if(!done_reseed) {
                urand_fd = do_reseed(True, urand_fd);
                done_reseed = True;
        }
@@ -242,6 +243,16 @@ void generate_random_buffer( unsigned char *out, int len, BOOL do_reseed_now)
        }
 }
 
+/*
+  generate a single random uint32_t
+*/
+uint32_t generate_random(void)
+{
+       uint8_t v[4];
+       generate_random_buffer(v, 4);
+       return IVAL(v, 0);
+}
+
 
 /*
   very basic password quality checker
@@ -267,27 +278,36 @@ BOOL check_password_quality(const char *s)
  Use the random number generator to generate a random string.
 ********************************************************************/
 
-static char c_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
-
-char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
+char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list)
 {
        size_t i;
+       size_t list_len = strlen(list);
+
+       char *retstr = talloc_array(mem_ctx, char, len + 1);
+       if (!retstr) return NULL;
 
-       char *retstr = talloc(mem_ctx, len + 1);
+       generate_random_buffer((uint8_t *)retstr, len);
+       for (i = 0; i < len; i++) {
+               retstr[i] = list[retstr[i] % list_len];
+       }
+       retstr[i] = '\0';
 
-       if (!retstr) 
-               return NULL;
+       return retstr;
+}
 
-again:
-       generate_random_buffer(retstr, len, False);
-       for (i = 0; i < len; i++)
-               retstr[i] = c_list[retstr[i] % (sizeof(c_list)-1) ];
+char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
+{
+       char *retstr;
+       const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
 
-       retstr[i] = '\0';
+again:
+       retstr = generate_random_str_list(mem_ctx, len, c_list);
+       if (!retstr) return NULL;
 
        /* we need to make sure the random string passes basic quality tests
           or it might be rejected by windows as a password */
        if (len >= 7 && !check_password_quality(retstr)) {
+               talloc_free(retstr);
                goto again;
        }