From f607197054436a8195e3d0a695fe31574b418059 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 14 Jul 2004 12:14:07 +0000 Subject: r1498: (merge from 3.0) 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) --- source4/auth/auth.c | 2 +- source4/lib/genrand.c | 77 +++++++++++++++------------ source4/lib/util_uuid.c | 2 +- source4/libcli/auth/ntlmssp.c | 6 +-- source4/libcli/auth/schannel.c | 2 +- source4/libcli/util/smbencrypt.c | 6 +-- source4/librpc/rpc/dcerpc_schannel.c | 2 +- source4/passdb/secrets.c | 29 ++++++++++ source4/rpc_server/netlogon/dcerpc_netlogon.c | 3 +- source4/smbd/process_standard.c | 4 ++ source4/smbd/rewrite.c | 7 +++ source4/torture/rpc/netlogon.c | 9 ++-- source4/torture/rpc/samr.c | 4 +- source4/torture/torture.c | 2 +- 14 files changed, 102 insertions(+), 53 deletions(-) diff --git a/source4/auth/auth.c b/source4/auth/auth.c index 32913f9996..206f431a05 100644 --- a/source4/auth/auth.c +++ b/source4/auth/auth.c @@ -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)); diff --git a/source4/lib/genrand.c b/source4/lib/genrand.c index b37078b284..adc6d7344e 100644 --- a/source4/lib/genrand.c +++ b/source4/lib/genrand.c @@ -22,39 +22,50 @@ #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) ]; diff --git a/source4/lib/util_uuid.c b/source4/lib/util_uuid.c index 6a705a4f30..156f20e53e 100644 --- a/source4/lib/util_uuid.c +++ b/source4/lib/util_uuid.c @@ -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; } diff --git a/source4/libcli/auth/ntlmssp.c b/source4/libcli/auth/ntlmssp.c index 3c656f4e9e..75c1e30f56 100644 --- a/source4/libcli/auth/ntlmssp.c +++ b/source4/libcli/auth/ntlmssp.c @@ -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, diff --git a/source4/libcli/auth/schannel.c b/source4/libcli/auth/schannel.c index 8a261a506c..aa89e7b84f 100644 --- a/source4/libcli/auth/schannel.c +++ b/source4/libcli/auth/schannel.c @@ -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); diff --git a/source4/libcli/util/smbencrypt.c b/source4/libcli/util/smbencrypt.c index 72c6589097..a02fdaa38b 100644 --- a/source4/libcli/util/smbencrypt.c +++ b/source4/libcli/util/smbencrypt.c @@ -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 diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c index 73d27cdfa9..bf5d835d44 100644 --- a/source4/librpc/rpc/dcerpc_schannel.c +++ b/source4/librpc/rpc/dcerpc_schannel.c @@ -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)) { diff --git a/source4/passdb/secrets.c b/source4/passdb/secrets.c index b5bae614b6..21938db154 100644 --- a/source4/passdb/secrets.c +++ b/source4/passdb/secrets.c @@ -29,10 +29,27 @@ 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; } diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 9f0ca5443a..a4ef06128c 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -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; diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c index cc02e84d57..5c2a0a3410 100644 --- a/source4/smbd/process_standard.c +++ b/source4/smbd/process_standard.c @@ -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")); diff --git a/source4/smbd/rewrite.c b/source4/smbd/rewrite.c index d0a4bad374..ac241958c7 100644 --- a/source4/smbd/rewrite.c +++ b/source4/smbd/rewrite.c @@ -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); } diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index 427701d2c9..f668c17d89 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -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; diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c index e6a22a6921..bd5c44a732 100644 --- a/source4/torture/rpc/samr.c +++ b/source4/torture/rpc/samr.c @@ -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); diff --git a/source4/torture/torture.c b/source4/torture/torture.c index 8f72b63e6c..804dd34f2a 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -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)); -- cgit