Coverage Report

Created: 2025-08-26 06:48

/src/libcups/cups/rand.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// Random number function for CUPS.
3
//
4
// Copyright © 2019-2022 by Michael R Sweet.
5
//
6
// Licensed under Apache License v2.0.  See the file "LICENSE" for more
7
// information.
8
//
9
10
#include "cups.h"
11
#if !defined(_WIN32) && !defined(__APPLE__)
12
#  include <unistd.h>
13
#  include <fcntl.h>
14
#  include <pthread.h>
15
#endif // !_WIN32 && !__APPLE__
16
17
18
//
19
// 'cupsGetRand()' - Return a 32-bit pseudo-random number.
20
//
21
// This function returns a 32-bit pseudo-random number suitable for use as
22
// one-time identifiers or nonces.  The random numbers are generated/seeded
23
// using system entropy.
24
//
25
26
unsigned        // O - Random number
27
cupsGetRand(void)
28
0
{
29
#if _WIN32
30
  // rand_s uses real entropy...
31
  unsigned v;       // Random number
32
33
34
  rand_s(&v);
35
36
  return (v);
37
38
#elif defined(__APPLE__)
39
  // macOS/iOS arc4random() uses real entropy automatically...
40
  return (arc4random());
41
42
#else
43
  // Use a Mersenne twister random number generator seeded from /dev/urandom...
44
0
  unsigned  i,      // Looping var
45
0
    temp;     // Temporary value
46
0
  static bool first_time = true;  // First time we ran?
47
0
  static unsigned mt_state[624],  // Mersenne twister state
48
0
    mt_index;   // Mersenne twister index
49
0
  static pthread_mutex_t mt_mutex = PTHREAD_MUTEX_INITIALIZER;
50
          // Mutex to control access to state
51
52
53
0
  pthread_mutex_lock(&mt_mutex);
54
55
0
  if (first_time)
56
0
  {
57
0
    int   fd;     // "/dev/urandom" file
58
0
    struct timeval curtime;   // Current time
59
60
    // Seed the random number state...
61
0
    if ((fd = open("/dev/urandom", O_RDONLY)) >= 0)
62
0
    {
63
      // Read random entropy from the system...
64
0
      if (read(fd, mt_state, sizeof(mt_state[0])) < sizeof(mt_state[0]))
65
0
        mt_state[0] = 0;   // Force fallback...
66
67
0
      close(fd);
68
0
    }
69
0
    else
70
0
      mt_state[0] = 0;
71
72
0
    if (!mt_state[0])
73
0
    {
74
      // Fallback to using the current time in microseconds...
75
0
      gettimeofday(&curtime, NULL);
76
0
      mt_state[0] = (unsigned)(curtime.tv_sec + curtime.tv_usec);
77
0
    }
78
79
0
    mt_index = 0;
80
81
0
    for (i = 1; i < 624; i ++)
82
0
      mt_state[i] = (unsigned)((1812433253 * (mt_state[i - 1] ^ (mt_state[i - 1] >> 30))) + i);
83
84
0
    first_time = false;
85
0
  }
86
87
0
  if (mt_index == 0)
88
0
  {
89
    // Generate a sequence of random numbers...
90
0
    unsigned i1 = 1, i397 = 397;  // Looping vars
91
92
0
    for (i = 0; i < 624; i ++)
93
0
    {
94
0
      temp        = (mt_state[i] & 0x80000000) + (mt_state[i1] & 0x7fffffff);
95
0
      mt_state[i] = mt_state[i397] ^ (temp >> 1);
96
97
0
      if (temp & 1)
98
0
  mt_state[i] ^= 2567483615u;
99
100
0
      i1 ++;
101
0
      i397 ++;
102
103
0
      if (i1 == 624)
104
0
  i1 = 0;
105
106
0
      if (i397 == 624)
107
0
  i397 = 0;
108
0
    }
109
0
  }
110
111
  // Pull 32-bits of random data...
112
0
  temp = mt_state[mt_index ++];
113
0
  temp ^= temp >> 11;
114
0
  temp ^= (temp << 7) & 2636928640u;
115
0
  temp ^= (temp << 15) & 4022730752u;
116
0
  temp ^= temp >> 18;
117
118
0
  if (mt_index == 624)
119
0
    mt_index = 0;
120
121
0
  pthread_mutex_unlock(&mt_mutex);
122
123
0
  return (temp);
124
0
#endif // _WIN32
125
0
}