
This is a fairly intrusive change, but outside of the moving of opal/event to opal/mca/event, the only changes involved (a) changing all calls to opal_event functions to reflect the new framework instead, and (b) ensuring that all opal_event_t objects are properly constructed since they are now true opal_objects. Note: Shiqing has just returned from vacation and has not yet had a chance to complete the Windows integration. Thus, this commit almost certainly breaks Windows support on the trunk. However, I want this to have a chance to soak for as long as possible before I become less available a week from today (going to be at a class for 5 days, and thus will only be sparingly available) so we can find and fix any problems. Biggest change is moving the libevent code from opal/event to a new opal/mca/event framework. This was done to make it much easier to update libevent in the future. New versions can be inserted as a new component and tested in parallel with the current version until validated, then we can remove the earlier version if we so choose. This is a statically built framework ala installdirs, so only one component will build at a time. There is no selection logic - the sole compiled component simply loads its function pointers into the opal_event struct. I have gone thru the code base and converted all the libevent calls I could find. However, I cannot compile nor test every environment. It is therefore quite likely that errors remain in the system. Please keep an eye open for two things: 1. compile-time errors: these will be obvious as calls to the old functions (e.g., opal_evtimer_new) must be replaced by the new framework APIs (e.g., opal_event.evtimer_new) 2. run-time errors: these will likely show up as segfaults due to missing constructors on opal_event_t objects. It appears that it became a typical practice for people to "init" an opal_event_t by simply using memset to zero it out. This will no longer work - you must either OBJ_NEW or OBJ_CONSTRUCT an opal_event_t. I tried to catch these cases, but may have missed some. Believe me, you'll know when you hit it. There is also the issue of the new libevent "no recursion" behavior. As I described on a recent email, we will have to discuss this and figure out what, if anything, we need to do. This commit was SVN r23925.
534 строки
12 KiB
C
534 строки
12 KiB
C
/* Portable arc4random.c based on arc4random.c from OpenBSD.
|
|
* Portable version by Chris Davis, adapted for Libevent by Nick Mathewson
|
|
* Copyright (c) 2010 Chris Davis, Niels Provos, and Nick Mathewson
|
|
*
|
|
* Note that in Libevent, this file isn't compiled directly. Instead,
|
|
* it's included from evutil_rand.c
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 1996, David Mazieres <dm@uun.org>
|
|
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
/*
|
|
* Arc4 random number generator for OpenBSD.
|
|
*
|
|
* This code is derived from section 17.1 of Applied Cryptography,
|
|
* second edition, which describes a stream cipher allegedly
|
|
* compatible with RSA Labs "RC4" cipher (the actual description of
|
|
* which is a trade secret). The same algorithm is used as a stream
|
|
* cipher called "arcfour" in Tatu Ylonen's ssh package.
|
|
*
|
|
* Here the stream cipher has been modified always to include the time
|
|
* when initializing the state. That makes it impossible to
|
|
* regenerate the same random sequence twice, so this can't be used
|
|
* for encryption, but will generate good random numbers.
|
|
*
|
|
* RC4 is a registered trademark of RSA Laboratories.
|
|
*/
|
|
|
|
#ifndef ARC4RANDOM_EXPORT
|
|
#define ARC4RANDOM_EXPORT
|
|
#endif
|
|
|
|
#ifndef ARC4RANDOM_UINT32
|
|
#define ARC4RANDOM_UINT32 uint32_t
|
|
#endif
|
|
|
|
#ifndef ARC4RANDOM_NO_INCLUDES
|
|
#ifdef WIN32
|
|
#include <wincrypt.h>
|
|
#include <process.h>
|
|
#else
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/param.h>
|
|
#include <sys/time.h>
|
|
#ifdef _EVENT_HAVE_SYS_SYSCTL_H
|
|
#include <sys/sysctl.h>
|
|
#endif
|
|
#endif
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#endif
|
|
|
|
/* Add platform entropy 32 bytes (256 bits) at a time. */
|
|
#define ADD_ENTROPY 32
|
|
|
|
/* Re-seed from the platform RNG after generating this many bytes. */
|
|
#define BYTES_BEFORE_RESEED 1600000
|
|
|
|
struct arc4_stream {
|
|
unsigned char i;
|
|
unsigned char j;
|
|
unsigned char s[256];
|
|
};
|
|
|
|
#ifdef WIN32
|
|
#define getpid _getpid
|
|
#define pid_t int
|
|
#endif
|
|
|
|
static int rs_initialized;
|
|
static struct arc4_stream rs;
|
|
static pid_t arc4_stir_pid;
|
|
static int arc4_count;
|
|
static int arc4_seeded_ok;
|
|
|
|
static inline unsigned char arc4_getbyte(void);
|
|
|
|
static inline void
|
|
arc4_init(void)
|
|
{
|
|
int n;
|
|
|
|
for (n = 0; n < 256; n++)
|
|
rs.s[n] = n;
|
|
rs.i = 0;
|
|
rs.j = 0;
|
|
}
|
|
|
|
static inline void
|
|
arc4_addrandom(const unsigned char *dat, int datlen)
|
|
{
|
|
int n;
|
|
unsigned char si;
|
|
|
|
rs.i--;
|
|
for (n = 0; n < 256; n++) {
|
|
rs.i = (rs.i + 1);
|
|
si = rs.s[rs.i];
|
|
rs.j = (rs.j + si + dat[n % datlen]);
|
|
rs.s[rs.i] = rs.s[rs.j];
|
|
rs.s[rs.j] = si;
|
|
}
|
|
rs.j = rs.i;
|
|
}
|
|
|
|
#ifndef WIN32
|
|
static ssize_t
|
|
read_all(int fd, unsigned char *buf, size_t count)
|
|
{
|
|
size_t numread = 0;
|
|
ssize_t result;
|
|
|
|
while (numread < count) {
|
|
result = read(fd, buf+numread, count-numread);
|
|
if (result<0)
|
|
return -1;
|
|
else if (result == 0)
|
|
break;
|
|
numread += result;
|
|
}
|
|
|
|
return (ssize_t)numread;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#define TRY_SEED_WIN32
|
|
static int
|
|
arc4_seed_win32(void)
|
|
{
|
|
/* This is adapted from Tor's crypto_seed_rng() */
|
|
static int provider_set = 0;
|
|
static HCRYPTPROV provider;
|
|
unsigned char buf[ADD_ENTROPY];
|
|
|
|
if (!provider_set) {
|
|
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
|
|
CRYPT_VERIFYCONTEXT)) {
|
|
if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
|
|
return -1;
|
|
}
|
|
provider_set = 1;
|
|
}
|
|
if (!CryptGenRandom(provider, sizeof(buf), buf))
|
|
return -1;
|
|
arc4_addrandom(buf, sizeof(buf));
|
|
memset(buf, 0, sizeof(buf));
|
|
arc4_seeded_ok = 1;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(_EVENT_HAVE_SYS_SYSCTL_H)
|
|
#if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_RANDOM && _EVENT_HAVE_DECL_RANDOM_UUID
|
|
#define TRY_SEED_SYSCTL_LINUX
|
|
static int
|
|
arc4_seed_sysctl_linux(void)
|
|
{
|
|
/* Based on code by William Ahern, this function tries to use the
|
|
* RANDOM_UUID sysctl to get entropy from the kernel. This can work
|
|
* even if /dev/urandom is inaccessible for some reason (e.g., we're
|
|
* running in a chroot). */
|
|
int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
|
|
unsigned char buf[ADD_ENTROPY];
|
|
size_t len, n;
|
|
int i, any_set;
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
for (len = 0; len < sizeof(buf); len += n) {
|
|
n = sizeof(buf) - len;
|
|
|
|
if (0 != sysctl(mib, 3, &buf[len], &n, NULL, 0))
|
|
return -1;
|
|
}
|
|
/* make sure that the buffer actually got set. */
|
|
for (i=any_set=0; i<sizeof(buf); ++i) {
|
|
any_set |= buf[i];
|
|
}
|
|
if (!any_set)
|
|
return -1;
|
|
|
|
arc4_addrandom(buf, sizeof(buf));
|
|
memset(buf, 0, sizeof(buf));
|
|
arc4_seeded_ok = 1;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_ARND
|
|
#define TRY_SEED_SYSCTL_BSD
|
|
static int
|
|
arc4_seed_sysctl_bsd(void)
|
|
{
|
|
/* Based on code from William Ahern and from OpenBSD, this function
|
|
* tries to use the KERN_ARND syscall to get entropy from the kernel.
|
|
* This can work even if /dev/urandom is inaccessible for some reason
|
|
* (e.g., we're running in a chroot). */
|
|
int mib[] = { CTL_KERN, KERN_ARND };
|
|
unsigned char buf[ADD_ENTROPY];
|
|
size_t len, n;
|
|
int i, any_set;
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
len = sizeof(buf);
|
|
if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
|
|
for (len = 0; len < sizeof(buf); len += sizeof(unsigned)) {
|
|
n = sizeof(unsigned);
|
|
if (n + len > sizeof(buf))
|
|
n = len - sizeof(buf);
|
|
if (sysctl(mib, 2, &buf[len], &n, NULL, 0) == -1)
|
|
return -1;
|
|
}
|
|
}
|
|
/* make sure that the buffer actually got set. */
|
|
for (i=any_set=0; i<sizeof(buf); ++i) {
|
|
any_set |= buf[i];
|
|
}
|
|
if (!any_set)
|
|
return -1;
|
|
|
|
arc4_addrandom(buf, sizeof(buf));
|
|
memset(buf, 0, sizeof(buf));
|
|
arc4_seeded_ok = 1;
|
|
return 0;
|
|
}
|
|
#endif
|
|
#endif /* defined(_EVENT_HAVE_SYS_SYSCTL_H) */
|
|
|
|
#ifdef __linux__
|
|
#define TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
|
|
static int
|
|
arc4_seed_proc_sys_kernel_random_uuid(void)
|
|
{
|
|
/* Occasionally, somebody will make /proc/sys accessible in a chroot,
|
|
* but not /dev/urandom. Let's try /proc/sys/kernel/random/uuid.
|
|
* Its format is stupid, so we need to decode it from hex.
|
|
*/
|
|
int fd;
|
|
char buf[128];
|
|
unsigned char entropy[64];
|
|
int bytes, n, i, nybbles;
|
|
for (bytes = 0; bytes<ADD_ENTROPY; ) {
|
|
fd = open("/proc/sys/kernel/random/uuid", O_RDONLY, 0);
|
|
if (fd < 0)
|
|
return -1;
|
|
n = read(fd, buf, sizeof(buf));
|
|
close(fd);
|
|
if (n<=0)
|
|
return -1;
|
|
memset(entropy, 0, sizeof(entropy));
|
|
for (i=nybbles=0; i<n; ++i) {
|
|
if (EVUTIL_ISXDIGIT(buf[i])) {
|
|
int nyb = evutil_hex_char_to_int(buf[i]);
|
|
if (nybbles & 1) {
|
|
entropy[nybbles/2] |= nyb;
|
|
} else {
|
|
entropy[nybbles/2] |= nyb<<4;
|
|
}
|
|
++nybbles;
|
|
}
|
|
}
|
|
if (nybbles < 2)
|
|
return -1;
|
|
arc4_addrandom(entropy, nybbles/2);
|
|
bytes += nybbles/2;
|
|
}
|
|
memset(entropy, 0, sizeof(entropy));
|
|
memset(buf, 0, sizeof(buf));
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifndef WIN32
|
|
#define TRY_SEED_URANDOM
|
|
static int
|
|
arc4_seed_urandom(void)
|
|
{
|
|
/* This is adapted from Tor's crypto_seed_rng() */
|
|
static const char *filenames[] = {
|
|
"/dev/srandom", "/dev/urandom", "/dev/random", NULL
|
|
};
|
|
unsigned char buf[ADD_ENTROPY];
|
|
int fd, i;
|
|
size_t n;
|
|
|
|
for (i = 0; filenames[i]; ++i) {
|
|
fd = open(filenames[i], O_RDONLY, 0);
|
|
if (fd<0)
|
|
continue;
|
|
n = read_all(fd, buf, sizeof(buf));
|
|
close(fd);
|
|
if (n != sizeof(buf))
|
|
return -1;
|
|
arc4_addrandom(buf, sizeof(buf));
|
|
memset(buf, 0, sizeof(buf));
|
|
arc4_seeded_ok = 1;
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
arc4_seed(void)
|
|
{
|
|
int ok = 0;
|
|
/* We try every method that might work, and don't give up even if one
|
|
* does seem to work. There's no real harm in over-seeding, and if
|
|
* one of these sources turns out to be broken, that would be bad. */
|
|
#ifdef TRY_SEED_WIN32
|
|
if (0 == arc4_seed_win32())
|
|
ok = 1;
|
|
#endif
|
|
#ifdef TRY_SEED_URANDOM
|
|
if (0 == arc4_seed_urandom())
|
|
ok = 1;
|
|
#endif
|
|
#ifdef TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
|
|
if (0 == arc4_seed_proc_sys_kernel_random_uuid())
|
|
ok = 1;
|
|
#endif
|
|
#ifdef TRY_SEED_SYSCTL_LINUX
|
|
/* Apparently Linux is deprecating sysctl, and spewing warning
|
|
* messages when you try to use it. */
|
|
if (!ok && 0 == arc4_seed_sysctl_linux())
|
|
ok = 1;
|
|
#endif
|
|
#ifdef TRY_SEED_SYSCTL_BSD
|
|
if (0 == arc4_seed_sysctl_bsd())
|
|
ok = 1;
|
|
#endif
|
|
return ok ? 0 : -1;
|
|
}
|
|
|
|
static void
|
|
arc4_stir(void)
|
|
{
|
|
int i;
|
|
|
|
if (!rs_initialized) {
|
|
arc4_init();
|
|
rs_initialized = 1;
|
|
}
|
|
|
|
arc4_seed();
|
|
|
|
/*
|
|
* Discard early keystream, as per recommendations in
|
|
* "Weaknesses in the Key Scheduling Algorithm of RC4" by
|
|
* Scott Fluhrer, Itsik Mantin, and Adi Shamir.
|
|
* http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
|
|
*
|
|
* Ilya Mironov's "(Not So) Random Shuffles of RC4" suggests that
|
|
* we drop at least 2*256 bytes, with 12*256 as a conservative
|
|
* value.
|
|
*
|
|
* RFC4345 says to drop 6*256.
|
|
*
|
|
* At least some versions of this code drop 4*256, in a mistaken
|
|
* belief that "words" in the Fluhrer/Mantin/Shamir paper refers
|
|
* to processor words.
|
|
*
|
|
* We add another sect to the cargo cult, and choose 12*256.
|
|
*/
|
|
for (i = 0; i < 12*256; i++)
|
|
(void)arc4_getbyte();
|
|
arc4_count = BYTES_BEFORE_RESEED;
|
|
}
|
|
|
|
|
|
static void
|
|
arc4_stir_if_needed(void)
|
|
{
|
|
pid_t pid = getpid();
|
|
|
|
if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid)
|
|
{
|
|
arc4_stir_pid = pid;
|
|
arc4_stir();
|
|
}
|
|
}
|
|
|
|
static inline unsigned char
|
|
arc4_getbyte(void)
|
|
{
|
|
unsigned char si, sj;
|
|
|
|
rs.i = (rs.i + 1);
|
|
si = rs.s[rs.i];
|
|
rs.j = (rs.j + si);
|
|
sj = rs.s[rs.j];
|
|
rs.s[rs.i] = sj;
|
|
rs.s[rs.j] = si;
|
|
return (rs.s[(si + sj) & 0xff]);
|
|
}
|
|
|
|
static inline unsigned int
|
|
arc4_getword(void)
|
|
{
|
|
unsigned int val;
|
|
|
|
val = arc4_getbyte() << 24;
|
|
val |= arc4_getbyte() << 16;
|
|
val |= arc4_getbyte() << 8;
|
|
val |= arc4_getbyte();
|
|
|
|
return val;
|
|
}
|
|
|
|
#ifndef ARC4RANDOM_NOSTIR
|
|
ARC4RANDOM_EXPORT int
|
|
arc4random_stir(void)
|
|
{
|
|
int val;
|
|
_ARC4_LOCK();
|
|
val = arc4_stir();
|
|
_ARC4_UNLOCK();
|
|
return val;
|
|
}
|
|
#endif
|
|
|
|
#ifndef ARC4RANDOM_NOADDRANDOM
|
|
ARC4RANDOM_EXPORT void
|
|
arc4random_addrandom(const unsigned char *dat, int datlen)
|
|
{
|
|
int j;
|
|
_ARC4_LOCK();
|
|
if (!rs_initialized)
|
|
arc4_stir();
|
|
for (j = 0; j < datlen; j += 256) {
|
|
/* arc4_addrandom() ignores all but the first 256 bytes of
|
|
* its input. We want to make sure to look at ALL the
|
|
* data in 'dat', just in case the user is doing something
|
|
* crazy like passing us all the files in /var/log. */
|
|
arc4_addrandom(dat + j, datlen - j);
|
|
}
|
|
_ARC4_UNLOCK();
|
|
}
|
|
#endif
|
|
|
|
#ifndef ARC4RANDOM_NORANDOM
|
|
ARC4RANDOM_EXPORT ARC4RANDOM_UINT32
|
|
arc4random(void)
|
|
{
|
|
ARC4RANDOM_UINT32 val;
|
|
_ARC4_LOCK();
|
|
arc4_count -= 4;
|
|
arc4_stir_if_needed();
|
|
val = arc4_getword();
|
|
_ARC4_UNLOCK();
|
|
return val;
|
|
}
|
|
#endif
|
|
|
|
ARC4RANDOM_EXPORT void
|
|
arc4random_buf(void *_buf, size_t n)
|
|
{
|
|
unsigned char *buf = _buf;
|
|
_ARC4_LOCK();
|
|
arc4_stir_if_needed();
|
|
while (n--) {
|
|
if (--arc4_count <= 0)
|
|
arc4_stir();
|
|
buf[n] = arc4_getbyte();
|
|
}
|
|
_ARC4_UNLOCK();
|
|
}
|
|
|
|
#ifndef ARC4RANDOM_NOUNIFORM
|
|
/*
|
|
* Calculate a uniformly distributed random number less than upper_bound
|
|
* avoiding "modulo bias".
|
|
*
|
|
* Uniformity is achieved by generating new random numbers until the one
|
|
* returned is outside the range [0, 2**32 % upper_bound). This
|
|
* guarantees the selected random number will be inside
|
|
* [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
|
|
* after reduction modulo upper_bound.
|
|
*/
|
|
ARC4RANDOM_EXPORT unsigned int
|
|
arc4random_uniform(unsigned int upper_bound)
|
|
{
|
|
ARC4RANDOM_UINT32 r, min;
|
|
|
|
if (upper_bound < 2)
|
|
return 0;
|
|
|
|
#if (UINT_MAX > 0xffffffffUL)
|
|
min = 0x100000000UL % upper_bound;
|
|
#else
|
|
/* Calculate (2**32 % upper_bound) avoiding 64-bit math */
|
|
if (upper_bound > 0x80000000)
|
|
min = 1 + ~upper_bound; /* 2**32 - upper_bound */
|
|
else {
|
|
/* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
|
|
min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* This could theoretically loop forever but each retry has
|
|
* p > 0.5 (worst case, usually far better) of selecting a
|
|
* number inside the range we need, so it should rarely need
|
|
* to re-roll.
|
|
*/
|
|
for (;;) {
|
|
r = arc4random();
|
|
if (r >= min)
|
|
break;
|
|
}
|
|
|
|
return r % upper_bound;
|
|
}
|
|
#endif
|