LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/python3/Python - random.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 20 72 27.8 %
Date: 2012-12-17 Functions: 2 5 40.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #include "Python.h"
       2             : #ifdef MS_WINDOWS
       3             : #include <windows.h>
       4             : #else
       5             : #include <fcntl.h>
       6             : #endif
       7             : 
       8             : #ifdef Py_DEBUG
       9             : int _Py_HashSecret_Initialized = 0;
      10             : #else
      11             : static int _Py_HashSecret_Initialized = 0;
      12             : #endif
      13             : 
      14             : #ifdef MS_WINDOWS
      15             : typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,\
      16             :               LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType,\
      17             :               DWORD dwFlags );
      18             : typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,\
      19             :               BYTE *pbBuffer );
      20             : 
      21             : static CRYPTGENRANDOM pCryptGenRandom = NULL;
      22             : /* This handle is never explicitly released. Instead, the operating
      23             :    system will release it when the process terminates. */
      24             : static HCRYPTPROV hCryptProv = 0;
      25             : 
      26             : static int
      27             : win32_urandom_init(int raise)
      28             : {
      29             :     HINSTANCE hAdvAPI32 = NULL;
      30             :     CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL;
      31             : 
      32             :     /* Obtain handle to the DLL containing CryptoAPI. This should not fail. */
      33             :     hAdvAPI32 = GetModuleHandle("advapi32.dll");
      34             :     if(hAdvAPI32 == NULL)
      35             :         goto error;
      36             : 
      37             :     /* Obtain pointers to the CryptoAPI functions. This will fail on some early
      38             :        versions of Win95. */
      39             :     pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(
      40             :                                hAdvAPI32, "CryptAcquireContextA");
      41             :     if (pCryptAcquireContext == NULL)
      42             :         goto error;
      43             : 
      44             :     pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32,
      45             :                                                      "CryptGenRandom");
      46             :     if (pCryptGenRandom == NULL)
      47             :         goto error;
      48             : 
      49             :     /* Acquire context */
      50             :     if (! pCryptAcquireContext(&hCryptProv, NULL, NULL,
      51             :                                PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
      52             :         goto error;
      53             : 
      54             :     return 0;
      55             : 
      56             : error:
      57             :     if (raise)
      58             :         PyErr_SetFromWindowsErr(0);
      59             :     else
      60             :         Py_FatalError("Failed to initialize Windows random API (CryptoGen)");
      61             :     return -1;
      62             : }
      63             : 
      64             : /* Fill buffer with size pseudo-random bytes generated by the Windows CryptoGen
      65             :    API. Return 0 on success, or -1 on error. */
      66             : static int
      67             : win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
      68             : {
      69             :     Py_ssize_t chunk;
      70             : 
      71             :     if (hCryptProv == 0)
      72             :     {
      73             :         if (win32_urandom_init(raise) == -1)
      74             :             return -1;
      75             :     }
      76             : 
      77             :     while (size > 0)
      78             :     {
      79             :         chunk = size > INT_MAX ? INT_MAX : size;
      80             :         if (!pCryptGenRandom(hCryptProv, chunk, buffer))
      81             :         {
      82             :             /* CryptGenRandom() failed */
      83             :             if (raise)
      84             :                 PyErr_SetFromWindowsErr(0);
      85             :             else
      86             :                 Py_FatalError("Failed to initialized the randomized hash "
      87             :                         "secret using CryptoGen)");
      88             :             return -1;
      89             :         }
      90             :         buffer += chunk;
      91             :         size -= chunk;
      92             :     }
      93             :     return 0;
      94             : }
      95             : #endif /* MS_WINDOWS */
      96             : 
      97             : 
      98             : #ifdef __VMS
      99             : /* Use openssl random routine */
     100             : #include <openssl/rand.h>
     101             : static int
     102             : vms_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
     103             : {
     104             :     if (RAND_pseudo_bytes(buffer, size) < 0) {
     105             :         if (raise) {
     106             :             PyErr_Format(PyExc_ValueError,
     107             :                          "RAND_pseudo_bytes");
     108             :         } else {
     109             :             Py_FatalError("Failed to initialize the randomized hash "
     110             :                           "secret using RAND_pseudo_bytes");
     111             :         }
     112             :         return -1;
     113             :     }
     114             :     return 0;
     115             : }
     116             : #endif /* __VMS */
     117             : 
     118             : 
     119             : #if !defined(MS_WINDOWS) && !defined(__VMS)
     120             : 
     121             : /* Read size bytes from /dev/urandom into buffer.
     122             :    Call Py_FatalError() on error. */
     123             : static void
     124           1 : dev_urandom_noraise(char *buffer, Py_ssize_t size)
     125             : {
     126             :     int fd;
     127             :     Py_ssize_t n;
     128             : 
     129             :     assert (0 < size);
     130             : 
     131           1 :     fd = open("/dev/urandom", O_RDONLY);
     132           1 :     if (fd < 0)
     133           0 :         Py_FatalError("Failed to open /dev/urandom");
     134             : 
     135           3 :     while (0 < size)
     136             :     {
     137             :         do {
     138           1 :             n = read(fd, buffer, (size_t)size);
     139           1 :         } while (n < 0 && errno == EINTR);
     140           1 :         if (n <= 0)
     141             :         {
     142             :             /* stop on error or if read(size) returned 0 */
     143           0 :             Py_FatalError("Failed to read bytes from /dev/urandom");
     144           0 :             break;
     145             :         }
     146           1 :         buffer += n;
     147           1 :         size -= (Py_ssize_t)n;
     148             :     }
     149           1 :     close(fd);
     150           1 : }
     151             : 
     152             : /* Read size bytes from /dev/urandom into buffer.
     153             :    Return 0 on success, raise an exception and return -1 on error. */
     154             : static int
     155           0 : dev_urandom_python(char *buffer, Py_ssize_t size)
     156             : {
     157             :     int fd;
     158             :     Py_ssize_t n;
     159             : 
     160           0 :     if (size <= 0)
     161           0 :         return 0;
     162             : 
     163           0 :     Py_BEGIN_ALLOW_THREADS
     164           0 :     fd = open("/dev/urandom", O_RDONLY);
     165           0 :     Py_END_ALLOW_THREADS
     166           0 :     if (fd < 0)
     167             :     {
     168           0 :         PyErr_SetString(PyExc_NotImplementedError,
     169             :                         "/dev/urandom (or equivalent) not found");
     170           0 :         return -1;
     171             :     }
     172             : 
     173           0 :     Py_BEGIN_ALLOW_THREADS
     174             :     do {
     175             :         do {
     176           0 :             n = read(fd, buffer, (size_t)size);
     177           0 :         } while (n < 0 && errno == EINTR);
     178           0 :         if (n <= 0)
     179           0 :             break;
     180           0 :         buffer += n;
     181           0 :         size -= (Py_ssize_t)n;
     182           0 :     } while (0 < size);
     183           0 :     Py_END_ALLOW_THREADS
     184             : 
     185           0 :     if (n <= 0)
     186             :     {
     187             :         /* stop on error or if read(size) returned 0 */
     188           0 :         if (n < 0)
     189           0 :             PyErr_SetFromErrno(PyExc_OSError);
     190             :         else
     191           0 :             PyErr_Format(PyExc_RuntimeError,
     192             :                          "Failed to read %zi bytes from /dev/urandom",
     193             :                          size);
     194           0 :         close(fd);
     195           0 :         return -1;
     196             :     }
     197           0 :     close(fd);
     198           0 :     return 0;
     199             : }
     200             : #endif /* !defined(MS_WINDOWS) && !defined(__VMS) */
     201             : 
     202             : /* Fill buffer with pseudo-random bytes generated by a linear congruent
     203             :    generator (LCG):
     204             : 
     205             :        x(n+1) = (x(n) * 214013 + 2531011) % 2^32
     206             : 
     207             :    Use bits 23..16 of x(n) to generate a byte. */
     208             : static void
     209           0 : lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
     210             : {
     211             :     size_t index;
     212             :     unsigned int x;
     213             : 
     214           0 :     x = x0;
     215           0 :     for (index=0; index < size; index++) {
     216           0 :         x *= 214013;
     217           0 :         x += 2531011;
     218             :         /* modulo 2 ^ (8 * sizeof(int)) */
     219           0 :         buffer[index] = (x >> 16) & 0xff;
     220             :     }
     221           0 : }
     222             : 
     223             : /* Fill buffer with size pseudo-random bytes, not suitable for cryptographic
     224             :    use, from the operating random number generator (RNG).
     225             : 
     226             :    Return 0 on success, raise an exception and return -1 on error. */
     227             : int
     228           0 : _PyOS_URandom(void *buffer, Py_ssize_t size)
     229             : {
     230           0 :     if (size < 0) {
     231           0 :         PyErr_Format(PyExc_ValueError,
     232             :                      "negative argument not allowed");
     233           0 :         return -1;
     234             :     }
     235           0 :     if (size == 0)
     236           0 :         return 0;
     237             : 
     238             : #ifdef MS_WINDOWS
     239             :     return win32_urandom((unsigned char *)buffer, size, 1);
     240             : #else
     241             : # ifdef __VMS
     242             :     return vms_urandom((unsigned char *)buffer, size, 1);
     243             : # else
     244           0 :     return dev_urandom_python((char*)buffer, size);
     245             : # endif
     246             : #endif
     247             : }
     248             : 
     249             : void
     250           1 : _PyRandom_Init(void)
     251             : {
     252             :     char *env;
     253           1 :     void *secret = &_Py_HashSecret;
     254           1 :     Py_ssize_t secret_size = sizeof(_Py_HashSecret_t);
     255             : 
     256           1 :     if (_Py_HashSecret_Initialized)
     257           1 :         return;
     258           1 :     _Py_HashSecret_Initialized = 1;
     259             : 
     260             :     /*
     261             :       Hash randomization is enabled.  Generate a per-process secret,
     262             :       using PYTHONHASHSEED if provided.
     263             :     */
     264             : 
     265           1 :     env = Py_GETENV("PYTHONHASHSEED");
     266           1 :     if (env && *env != '\0' && strcmp(env, "random") != 0) {
     267           0 :         char *endptr = env;
     268             :         unsigned long seed;
     269           0 :         seed = strtoul(env, &endptr, 10);
     270           0 :         if (*endptr != '\0'
     271           0 :             || seed > 4294967295UL
     272           0 :             || (errno == ERANGE && seed == ULONG_MAX))
     273             :         {
     274           0 :             Py_FatalError("PYTHONHASHSEED must be \"random\" or an integer "
     275             :                           "in range [0; 4294967295]");
     276             :         }
     277           0 :         if (seed == 0) {
     278             :             /* disable the randomized hash */
     279           0 :             memset(secret, 0, secret_size);
     280             :         }
     281             :         else {
     282           0 :             lcg_urandom(seed, (unsigned char*)secret, secret_size);
     283             :         }
     284             :     }
     285             :     else {
     286             : #ifdef MS_WINDOWS
     287             :         (void)win32_urandom((unsigned char *)secret, secret_size, 0);
     288             : #else /* #ifdef MS_WINDOWS */
     289             : # ifdef __VMS
     290             :         vms_urandom((unsigned char *)secret, secret_size, 0);
     291             : # else
     292           1 :         dev_urandom_noraise((char*)secret, secret_size);
     293             : # endif
     294             : #endif
     295             :     }
     296             : }

Generated by: LCOV version 1.10