r1498: (merge from 3.0)
authorAndrew Bartlett <abartlet@samba.org>
Wed, 14 Jul 2004 12:14:07 +0000 (12:14 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:57:35 +0000 (12:57 -0500)
Rework our random number generation system.

On systems with /dev/urandom, this avoids a change to secrets.tdb for every fork().

For other systems, we now only re-seed after a fork, and on startup.
No need to do it per-operation.  This removes the 'need_reseed'
parameter from generate_random_buffer().

This also requires that we start the secrets subsystem, as that is
where the reseed value is stored, for systems without /dev/urandom.

In order to aviod identical streams in forked children, the random
state is re-initialised after the fork(), at the same point were we do
that to the tdbs.

Andrew Bartlett
(This used to be commit b97d3cb2efd68310b1aea8a3ac40a64979c8cdae)

14 files changed:
source4/auth/auth.c
source4/lib/genrand.c
source4/lib/util_uuid.c
source4/libcli/auth/ntlmssp.c
source4/libcli/auth/schannel.c
source4/libcli/util/smbencrypt.c
source4/librpc/rpc/dcerpc_schannel.c
source4/passdb/secrets.c
source4/rpc_server/netlogon/dcerpc_netlogon.c
source4/smbd/process_standard.c
source4/smbd/rewrite.c
source4/torture/rpc/netlogon.c
source4/torture/rpc/samr.c
source4/torture/torture.c

index 32913f99960d6652421bf76c09851027a3949959..206f431a05f69a323e9d0eeba37c0f959c0a0589 100644 (file)
@@ -77,7 +77,7 @@ static const uint8_t *get_ntlm_challenge(struct auth_context *auth_context)
        if (!challenge_set_by) {
                uint8_t chal[8];
                
-               generate_random_buffer(chal, sizeof(chal), False);
+               generate_random_buffer(chal, sizeof(chal));
                auth_context->challenge = data_blob_talloc(auth_context->mem_ctx, 
                                                           chal, sizeof(chal));
                
index b37078b2848b99c493c888750dca802f7a2e555a..adc6d7344ed0efa616d5940382dd6a2157725724 100644 (file)
 
 #include "includes.h"
 
-static uint8_t hash[258];
-static uint32_t counter;
-static uint8_t *reseed_data;
-static size_t reseed_data_size;
+static unsigned char hash[258];
+static uint32 counter;
+
+static BOOL done_reseed = False;
+static void (*reseed_callback)(int *newseed);
 
 /**************************************************************** 
  Copy any user given reseed data.
 *****************************************************************/
 
-void set_rand_reseed_data(uint8_t *data, size_t len)
+void set_rand_reseed_callback(void (*fn)(int *))
+{
+       reseed_callback = fn;
+       set_need_random_reseed();
+}
+
+void set_need_random_reseed(void)
 {
-       SAFE_FREE(reseed_data);
-       reseed_data_size = 0;
+       done_reseed = False;
+}
 
-       reseed_data = (uint8_t *)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;
+       }
 }
 
 /**************************************************************** 
  Setup the seed.
 *****************************************************************/
 
-static void seed_random_stream(uint8_t *seedval, size_t seedlen)
+static void seed_random_stream(unsigned char *seedval, size_t seedlen)
 {
-       uint8_t j = 0;
+       unsigned char j = 0;
        size_t ind;
 
        for (ind = 0; ind < 256; ind++)
-               hash[ind] = (uint8_t)ind;
+               hash[ind] = (unsigned char)ind;
 
        for( ind = 0; ind < 256; ind++) {
-               uint8_t tc;
+               unsigned char tc;
 
                j += (hash[ind] + seedval[ind%seedlen]);
 
@@ -71,15 +82,15 @@ static void seed_random_stream(uint8_t *seedval, size_t seedlen)
  Get datasize bytes worth of random data.
 *****************************************************************/
 
-static void get_random_stream(uint8_t *data, size_t datasize)
+static void get_random_stream(unsigned char *data, size_t datasize)
 {
-       uint8_t index_i = hash[256];
-       uint8_t index_j = hash[257];
+       unsigned char index_i = hash[256];
+       unsigned char index_j = hash[257];
        size_t ind;
 
        for( ind = 0; ind < datasize; ind++) {
-               uint8_t tc;
-               uint8_t t;
+               unsigned char tc;
+               unsigned char t;
 
                index_i++;
                index_j += hash[index_i];
@@ -101,10 +112,10 @@ static void get_random_stream(uint8_t *data, size_t datasize)
  Note that the hash is not initialised.
 *****************************************************************/
 
-static void do_filehash(const char *fname, uint8_t *the_hash)
+static void do_filehash(const char *fname, unsigned char *the_hash)
 {
-       uint8_t buf[1011]; /* deliberate weird size */
-       uint8_t tmp_md4[16];
+       unsigned char buf[1011]; /* deliberate weird size */
+       unsigned char tmp_md4[16];
        int fd, n;
 
        fd = sys_open(fname,O_RDONLY,0);
@@ -133,8 +144,9 @@ static void do_filehash(const char *fname, uint8_t *the_hash)
 
 static int do_reseed(BOOL use_fd, int fd)
 {
-       uint8_t seed_inbuf[40];
-       uint32_t v1, v2; struct timeval tval; pid_t mypid;
+       unsigned char seed_inbuf[40];
+       uint32 v1, v2; struct timeval tval; pid_t mypid;
+       int reseed_data = 0;
 
        if (use_fd) {
                if (fd != -1)
@@ -166,10 +178,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));
@@ -181,15 +194,14 @@ static int do_reseed(BOOL use_fd, int fd)
  Interface to the (hopefully) good crypto random number generator.
 ********************************************************************/
 
-void generate_random_buffer( uint8_t *out, int len, BOOL do_reseed_now)
+void generate_random_buffer( unsigned char *out, int len)
 {
-       static BOOL done_reseed = False;
        static int urand_fd = -1;
-       uint8_t md4_buf[64];
-       uint8_t tmp_buf[16];
-       uint8_t *p;
+       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;
        }
@@ -225,7 +237,6 @@ void generate_random_buffer( uint8_t *out, int len, BOOL do_reseed_now)
        }
 }
 
-
 /*
   very basic password quality checker
 */
@@ -262,7 +273,7 @@ char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
                return NULL;
 
 again:
-       generate_random_buffer(retstr, len, False);
+       generate_random_buffer(retstr, len);
        for (i = 0; i < len; i++)
                retstr[i] = c_list[retstr[i] % (sizeof(c_list)-1) ];
 
index 6a705a4f309d085d6c4bc111f5ec0b03856b843f..156f20e53eb670152c2681b1ffae20e4cb9ab616 100644 (file)
@@ -24,7 +24,7 @@
 
 void uuid_generate_random(struct GUID *out)
 {
-       generate_random_buffer(out, sizeof(struct GUID), False);
+       generate_random_buffer(out, sizeof(struct GUID));
        out->clock_seq[0] = (out->clock_seq[0] & 0x3F) | 0x80;
        out->time_hi_and_version = (out->time_hi_and_version & 0x0FFF) | 0x4000;
 }
index 3c656f4e9e5dc4cb2002226d394fa52114b42386..75c1e30f565e8986a104234cd92e3ce475fe914f 100644 (file)
@@ -108,7 +108,7 @@ void debug_ntlmssp_flags(uint32_t neg_flags)
 static const uint8_t *get_challenge(const struct ntlmssp_state *ntlmssp_state)
 {
        static uint8_t chal[8];
-       generate_random_buffer(chal, sizeof(chal), False);
+       generate_random_buffer(chal, sizeof(chal));
 
        return chal;
 }
@@ -1112,7 +1112,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state,
                E_md4hash(ntlmssp_state->password, nt_hash);
                
                lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
-               generate_random_buffer(lm_response.data, 8, False);
+               generate_random_buffer(lm_response.data, 8);
                memset(lm_response.data+8, 0, 16);
 
                memcpy(session_nonce, challenge_blob.data, 8);
@@ -1202,7 +1202,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state,
        if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
                /* Make up a new session key */
                uint8_t client_session_key[16];
-               generate_random_buffer(client_session_key, sizeof(client_session_key), False);
+               generate_random_buffer(client_session_key, sizeof(client_session_key));
 
                /* Encrypt the new session key with the old one */
                encrypted_session_key = data_blob_talloc(ntlmssp_state->mem_ctx, 
index 8a261a506c46cefcaf65809c59d8d0df88ac78ff..aa89e7b84f0feabafdcd8b16a637a4f58f92cd92 100644 (file)
@@ -194,7 +194,7 @@ NTSTATUS schannel_seal_packet(struct schannel_state *state,
        uint8_t sealing_key[16];
        static const uint8_t netsec_sig[8] = NETSEC_SEAL_SIGNATURE;
 
-       generate_random_buffer(confounder, 8, False);
+       generate_random_buffer(confounder, 8);
 
        RSIVAL(seq_num, 0, state->seq_num);
        SIVAL(seq_num, 4, state->initiator?0x80:0);
index 72c658909742d764fdb7b9ac305da337c8422b21..a02fdaa38b0ae807145a64ac15591636e08add72 100644 (file)
@@ -283,7 +283,7 @@ static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx, const DATA_BLO
 
        unix_to_nt_time(&nttime, time(NULL));
 
-       generate_random_buffer(client_chal, sizeof(client_chal), False);
+       generate_random_buffer(client_chal, sizeof(client_chal));
 
        push_nttime(long_date, 0, nttime);
 
@@ -343,7 +343,7 @@ static DATA_BLOB LMv2_generate_response(const uint8_t ntlm_v2_hash[16],
        
        /* LMv2 */
        /* client-supplied random data */
-       generate_random_buffer(lmv2_client_data.data, lmv2_client_data.length, False);  
+       generate_random_buffer(lmv2_client_data.data, lmv2_client_data.length); 
 
        /* Given that data, and the challenge from the server, generate a response */
        SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &lmv2_client_data, lmv2_response);
@@ -413,7 +413,7 @@ BOOL encode_pw_buffer(char buffer[516], const char *password, int string_flags)
        
        memcpy(&buffer[512 - new_pw_len], new_pw, new_pw_len);
 
-       generate_random_buffer((uint8_t *)buffer, 512 - new_pw_len, False);
+       generate_random_buffer((uint8_t *)buffer, 512 - new_pw_len);
 
        /* 
         * The length of the new password is in the last 4 bytes of
index 73d27cdfa9b267244d994f5d1a9ea28aa32bbcda..bf5d835d44a3783f544f1350439bb7f9611d3615 100644 (file)
@@ -373,7 +373,7 @@ static NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
        r.in.credentials = &credentials1;
        r.out.credentials = &credentials2;
 
-       generate_random_buffer(credentials1.data, sizeof(credentials1.data), False);
+       generate_random_buffer(credentials1.data, sizeof(credentials1.data));
 
        status = dcerpc_netr_ServerReqChallenge(p2, p->mem_ctx, &r);
        if (!NT_STATUS_IS_OK(status)) {
index b5bae614b631e08606e5b4d3caf1ee7d7e8c6016..21938db154e4169d304d83ff3be7261328f6a842 100644 (file)
 
 static TDB_CONTEXT *tdb;
 
+/**
+ * Use a TDB to store an incrementing random seed.
+ *
+ * Initialised to the current pid, the very first time Samba starts,
+ * and incremented by one each time it is needed.  
+ * 
+ * @note Not called by systems with a working /dev/urandom.
+ */
+static void get_rand_seed(int *new_seed) 
+{
+       *new_seed = getpid();
+       if (tdb) {
+               tdb_change_int32_atomic(tdb, "INFO/random_seed", new_seed, 1);
+       }
+}
+
 /* open up the secrets database */
 BOOL secrets_init(void)
 {
        pstring fname;
+       char dummy;
 
        if (tdb)
                return True;
@@ -46,6 +63,18 @@ BOOL secrets_init(void)
                DEBUG(0,("Failed to open %s\n", fname));
                return False;
        }
+
+       /**
+        * Set a reseed function for the crypto random generator 
+        * 
+        * This avoids a problem where systems without /dev/urandom
+        * could send the same challenge to multiple clients
+        */
+       set_rand_reseed_callback(get_rand_seed);
+
+       /* Ensure that the reseed is done now, while we are root, etc */
+       generate_random_buffer(&dummy, sizeof(dummy));
+
        return True;
 }
 
index 9f0ca5443a593c0646c18a4316d7651c9bd93d6b..a4ef06128cc60d1e0ab08b52790700dbcd08a10d 100644 (file)
@@ -150,8 +150,7 @@ static NTSTATUS netr_ServerReqChallenge(struct dcesrv_call_state *dce_call, TALL
        pipe_state->client_challenge = *r->in.credentials;
 
        generate_random_buffer(pipe_state->server_challenge.data, 
-                              sizeof(pipe_state->server_challenge.data),
-                              False);
+                              sizeof(pipe_state->server_challenge.data));
 
        *r->out.credentials = pipe_state->server_challenge;
 
index cc02e84d5716bb85be76557cb9d5c7f737402fba..5c2a0a3410636398a63a4bfa463647ae49bddada 100644 (file)
@@ -74,6 +74,10 @@ static void standard_accept_connection(struct event_context *ev, struct fd_event
                DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
        }
 
+       /* Ensure that the forked children do not expose identical random streams */
+
+       set_need_random_reseed();
+
        mem_ctx = talloc_init("server_service_connection");
        if (!mem_ctx) {
                DEBUG(0,("talloc_init(server_service_connection) failed\n"));
index d0a4bad37494a5185b3325ac017298c77b03f83e..ac241958c7d513658fd6f856511d9827eff07199 100644 (file)
@@ -70,6 +70,13 @@ void smbd_process_init(void)
        if (!init_change_notify())
                exit(1);
 
+       /* Start old-style secrets subsystem */
+       
+       /* We must perform secrets_init(), as it sets up important
+        * seeding for the random number generator.
+        */
+       secrets_init();
+       
        talloc_destroy(mem_ctx);
 }
 
index 427701d2c9096675b86ef47908c771f81701cb0d..f668c17d8942a9fdabb94815ca6dca8a1fdedeac 100644 (file)
@@ -88,7 +88,7 @@ static BOOL test_SetupCredentials(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        r.in.credentials = &credentials1;
        r.out.credentials = &credentials2;
 
-       generate_random_buffer(credentials1.data, sizeof(credentials1.data), False);
+       generate_random_buffer(credentials1.data, sizeof(credentials1.data));
 
        status = dcerpc_netr_ServerReqChallenge(p, mem_ctx, &r);
        if (!NT_STATUS_IS_OK(status)) {
@@ -148,7 +148,7 @@ static BOOL test_SetupCredentials2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        r.in.credentials = &credentials1;
        r.out.credentials = &credentials2;
 
-       generate_random_buffer(credentials1.data, sizeof(credentials1.data), False);
+       generate_random_buffer(credentials1.data, sizeof(credentials1.data));
 
        status = dcerpc_netr_ServerReqChallenge(p, mem_ctx, &r);
        if (!NT_STATUS_IS_OK(status)) {
@@ -214,7 +214,7 @@ static BOOL test_SetupCredentials3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        r.in.credentials = &credentials1;
        r.out.credentials = &credentials2;
 
-       generate_random_buffer(credentials1.data, sizeof(credentials1.data), False);
+       generate_random_buffer(credentials1.data, sizeof(credentials1.data));
 
        status = dcerpc_netr_ServerReqChallenge(p, mem_ctx, &r);
        if (!NT_STATUS_IS_OK(status)) {
@@ -893,8 +893,7 @@ static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
 
        samlogon_state.chall = data_blob_talloc(mem_ctx, NULL, 8);
 
-       generate_random_buffer(samlogon_state.chall.data, 
-                              8, False);
+       generate_random_buffer(samlogon_state.chall.data, 8);
 
        if (!test_SetupCredentials2(p, mem_ctx, NETLOGON_NEG_AUTH2_FLAGS, &samlogon_state.creds)) {
                return False;
index e6a22a6921a3edc1cc89cfba2cc41f512d1700f2..bd5c44a73284f506926a2dae8d62f1e870d04715 100644 (file)
@@ -452,7 +452,7 @@ static BOOL test_SetUserPassEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                return False;
        }
 
-       generate_random_buffer((uint8_t *)confounder, 16, False);
+       generate_random_buffer((uint8_t *)confounder, 16);
 
        MD5Init(&ctx);
        MD5Update(&ctx, confounder, 16);
@@ -506,7 +506,7 @@ static BOOL test_SetUserPass_25(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                return False;
        }
 
-       generate_random_buffer((uint8_t *)confounder, 16, False);
+       generate_random_buffer((uint8_t *)confounder, 16);
 
        MD5Init(&ctx);
        MD5Update(&ctx, confounder, 16);
index 8f72b63e6cb1ea317e8e5698b7f49270845b0ec8..804dd34f2a38b7311795c9b8601515d1638c90a4 100644 (file)
@@ -458,7 +458,7 @@ static BOOL rw_torture2(struct cli_state *c1, struct cli_state *c2)
                        printf("%d\r", i); fflush(stdout);
                }
 
-               generate_random_buffer(buf, buf_size, False);
+               generate_random_buffer(buf, buf_size);
 
                if ((bytes_written = cli_write(c1->tree, fnum1, 0, buf, 0, buf_size)) != buf_size) {
                        printf("write failed (%s)\n", cli_errstr(c1->tree));