LCOV - code coverage report
Current view: top level - src/backend/utils/misc - backend_random.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 7 7 100.0 %
Date: 2017-09-29 15:12:54 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * backend_random.c
       4             :  *    Backend random number generation routine.
       5             :  *
       6             :  * pg_backend_random() function fills a buffer with random bytes. Normally,
       7             :  * it is just a thin wrapper around pg_strong_random(), but when compiled
       8             :  * with --disable-strong-random, we provide a built-in implementation.
       9             :  *
      10             :  * This function is used for generating nonces in authentication, and for
      11             :  * random salt generation in pgcrypto. The built-in implementation is not
      12             :  * cryptographically strong, but if the user asked for it, we'll go ahead
      13             :  * and use it anyway.
      14             :  *
      15             :  * The built-in implementation uses the standard erand48 algorithm, with
      16             :  * a seed shared between all backends.
      17             :  *
      18             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
      19             :  * Portions Copyright (c) 1994, Regents of the University of California
      20             :  *
      21             :  *
      22             :  * IDENTIFICATION
      23             :  *    src/backend/utils/misc/backend_random.c
      24             :  *
      25             :  *-------------------------------------------------------------------------
      26             :  */
      27             : 
      28             : #include "postgres.h"
      29             : 
      30             : #include <sys/time.h>
      31             : 
      32             : #include "miscadmin.h"
      33             : #include "storage/lwlock.h"
      34             : #include "storage/shmem.h"
      35             : #include "utils/backend_random.h"
      36             : #include "utils/timestamp.h"
      37             : 
      38             : #ifdef HAVE_STRONG_RANDOM
      39             : 
      40             : Size
      41           5 : BackendRandomShmemSize(void)
      42             : {
      43           5 :     return 0;
      44             : }
      45             : 
      46             : void
      47           5 : BackendRandomShmemInit(void)
      48             : {
      49             :     /* do nothing */
      50           5 : }
      51             : 
      52             : bool
      53           3 : pg_backend_random(char *dst, int len)
      54             : {
      55             :     /* should not be called in postmaster */
      56           3 :     Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
      57             : 
      58           3 :     return pg_strong_random(dst, len);
      59             : }
      60             : 
      61             : #else
      62             : 
      63             : /*
      64             :  * Seed for the PRNG, stored in shared memory.
      65             :  *
      66             :  * Protected by BackendRandomLock.
      67             :  */
      68             : typedef struct
      69             : {
      70             :     bool        initialized;
      71             :     unsigned short seed[3];
      72             : }           BackendRandomShmemStruct;
      73             : 
      74             : static BackendRandomShmemStruct * BackendRandomShmem;
      75             : 
      76             : Size
      77             : BackendRandomShmemSize(void)
      78             : {
      79             :     return sizeof(BackendRandomShmemStruct);
      80             : }
      81             : 
      82             : void
      83             : BackendRandomShmemInit(void)
      84             : {
      85             :     bool        found;
      86             : 
      87             :     BackendRandomShmem = (BackendRandomShmemStruct *)
      88             :         ShmemInitStruct("Backend PRNG state",
      89             :                         BackendRandomShmemSize(),
      90             :                         &found);
      91             : 
      92             :     if (!IsUnderPostmaster)
      93             :     {
      94             :         Assert(!found);
      95             : 
      96             :         BackendRandomShmem->initialized = false;
      97             :     }
      98             :     else
      99             :         Assert(found);
     100             : }
     101             : 
     102             : bool
     103             : pg_backend_random(char *dst, int len)
     104             : {
     105             :     int         i;
     106             :     char       *end = dst + len;
     107             : 
     108             :     /* should not be called in postmaster */
     109             :     Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
     110             : 
     111             :     LWLockAcquire(BackendRandomLock, LW_EXCLUSIVE);
     112             : 
     113             :     /*
     114             :      * Seed the PRNG on the first use.
     115             :      */
     116             :     if (!BackendRandomShmem->initialized)
     117             :     {
     118             :         struct timeval now;
     119             : 
     120             :         gettimeofday(&now, NULL);
     121             : 
     122             :         BackendRandomShmem->seed[0] = now.tv_sec;
     123             :         BackendRandomShmem->seed[1] = (unsigned short) (now.tv_usec);
     124             :         BackendRandomShmem->seed[2] = (unsigned short) (now.tv_usec >> 16);
     125             : 
     126             :         /*
     127             :          * Mix in the cancel key, generated by the postmaster. This adds what
     128             :          * little entropy the postmaster had to the seed.
     129             :          */
     130             :         BackendRandomShmem->seed[0] ^= (MyCancelKey);
     131             :         BackendRandomShmem->seed[1] ^= (MyCancelKey >> 16);
     132             : 
     133             :         BackendRandomShmem->initialized = true;
     134             :     }
     135             : 
     136             :     for (i = 0; dst < end; i++)
     137             :     {
     138             :         uint32      r;
     139             :         int         j;
     140             : 
     141             :         /*
     142             :          * pg_jrand48 returns a 32-bit integer. Fill the next 4 bytes from it.
     143             :          */
     144             :         r = (uint32) pg_jrand48(BackendRandomShmem->seed);
     145             : 
     146             :         for (j = 0; j < 4 && dst < end; j++)
     147             :         {
     148             :             *(dst++) = (char) (r & 0xFF);
     149             :             r >>= 8;
     150             :         }
     151             :     }
     152             :     LWLockRelease(BackendRandomLock);
     153             : 
     154             :     return true;
     155             : }
     156             : 
     157             : 
     158             : #endif                          /* HAVE_STRONG_RANDOM */

Generated by: LCOV version 1.11