diff --git a/VERSION b/VERSION index 72a1f297..68ca3e72 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-29 17:16:28) dev +Version 2.0.9 (2012-09-29 17:56:36) dev diff --git a/gluon/utils.py b/gluon/utils.py index f3831d3b..687eeead 100644 --- a/gluon/utils.py +++ b/gluon/utils.py @@ -10,6 +10,7 @@ This file specifically includes utilities for security. """ import string +import threading import struct import hashlib import hmac @@ -110,6 +111,7 @@ def initialize_urandom(): random.seed(node_id + microseconds) try: os.urandom(1) + have_urandom = True try: # try to add process-specific entropy frandom = open('/dev/urandom','wb') @@ -121,13 +123,31 @@ def initialize_urandom(): # works anyway pass except NotImplementedError: + have_urandom = False logger.warning( """Cryptographically secure session management is not possible on your system because your system does not provide a cryptographically secure entropy source. This is not specific to web2py; consider deploying on a different operating system.""") - return ctokens -CTOKENS = initialize_urandom() -UNPACKED_CTOKENS = struct.unpack('=QQ',string.join((chr(x) for x in CTOKENS),'')) + unpacked_ctokens = struct.unpack('=QQ',string.join( + (chr(x) for x in ctokens),'')) + return unpacked_ctokens, have_urandom +UNPACKED_CTOKENS, HAVE_URANDOM = initialize_urandom() + +def fast_urandom16(urandom=[], locker = threading.RLock()): + """ + this is 4x faster than calling os.urandom(16) and prevents + the "too many files open" issue with concurrent access to os.urandom() + """ + try: + return urandom.pop() + except IndexError: + try: + locker.acquire() + ur = os.urandom(16*1024) + urandom += [ur[i:i+16] for i in xrange(16,1024*16,16)] + return ur[0:16] + finally: + locker.release() def web2py_uuid(ctokens=UNPACKED_CTOKENS): """ @@ -139,12 +159,12 @@ def web2py_uuid(ctokens=UNPACKED_CTOKENS): """ rand_longs = struct.unpack('=QQ', bytes(bytearray( random.randrange(256) for i in xrange(16)))) - try: - urand_longs = struct.unpack('=QQ', os.urandom(16)) - byte_s = struct.pack('=QQ', + if HAVE_URANDOM: + urand_longs = struct.unpack('=QQ', fast_urandom16()) + byte_s = struct.pack('=QQ', rand_longs[0]^urand_longs[0]^ctokens[0], rand_longs[1]^urand_longs[1]^ctokens[1]) - except NotImplementedError: + else: byte_s = struct.pack('=QQ', rand_longs[0]^ctokens[0], rand_longs[1]^ctokens[1])