39#include "blocxx/BLOCXX_config.h"
41#ifdef BLOCXX_HAVE_OPENSSL
67#ifdef BLOCXX_HAVE_UNISTD_H
72#include <openssl/rand.h>
73#include <openssl/err.h>
74#ifdef BLOCXX_HAVE_SYS_RESOURCE_H
75#include <sys/resource.h>
85using namespace blocxx;
89 unsigned const RESEED_BYTES = 16;
90 unsigned const SEED_BYTES = 16;
92 template <
typename T>
struct unsigned_equivalent
97 template <>
struct unsigned_equivalent<char>
99 typedef unsigned char type;
102 template <>
struct unsigned_equivalent<signed char>
104 typedef unsigned char type;
107 template <>
struct unsigned_equivalent<short>
109 typedef unsigned short type;
112 template <>
struct unsigned_equivalent<int>
114 typedef unsigned int type;
117 template <>
struct unsigned_equivalent<long>
119 typedef unsigned long type;
122 template <>
struct unsigned_equivalent<long long>
124 typedef unsigned long long type;
127 blocxx::OnceFlag guard = BLOCXX_ONCE_INIT;
129 void rand_init_impl();
143 unsigned char * rand(
unsigned char * buf, std::size_t n)
147 if (!RAND_bytes(buf, n))
150 SSLCtxMgr::getOpenSSLErrorDescription().c_str());
155 ::pid_t fork_reseed()
158#pragma message(Reminder "TODO: implement it for Win!")
162 unsigned char seed[2][RESEED_BYTES];
163 rand(seed[0],
sizeof(seed[0]));
164 rand(seed[1],
sizeof(seed[1]));
166 ::pid_t rv = ::fork();
172 std::size_t idx = rv > 0;
173 RAND_seed(seed[idx],
sizeof(seed[idx]));
175 std::memset(seed[1 - idx], 0,
sizeof(seed[1- idx]));
183 template <
typename Un
signedInt>
184 UnsignedInt rand_uint_lt(UnsignedInt n)
187 if ((n & (n - 1)) == 0)
189 return rand_uint<UnsignedInt>() % n;
191 UnsignedInt
const uint_max =
static_cast<UnsignedInt
>(-1);
192 UnsignedInt
const bound = uint_max - (uint_max % n);
196 rn = rand_uint<UnsignedInt>();
197 }
while (rn >= bound);
202 template unsigned char
203 BLOCXX_COMMON_API rand_uint_lt<unsigned char>(
unsigned char);
204 template unsigned short
205 BLOCXX_COMMON_API rand_uint_lt<unsigned short>(
unsigned short);
206 template unsigned int
207 BLOCXX_COMMON_API rand_uint_lt<unsigned int>(
unsigned int);
208 template unsigned long
209 BLOCXX_COMMON_API rand_uint_lt<unsigned long>(
unsigned long);
210 template unsigned long long
211 BLOCXX_COMMON_API rand_uint_lt<unsigned long long>(
unsigned long long);
213 template <
typename Integer>
214 Integer rand_range(Integer min_value, Integer max_value)
226 typedef typename unsigned_equivalent<Integer>::type UnsignedInt;
227 UnsignedInt
const umax =
static_cast<UnsignedInt
>(max_value);
228 UnsignedInt
const umin =
static_cast<UnsignedInt
>(min_value);
229 UnsignedInt
const diff = umax - umin;
235 UnsignedInt
const range = diff +
static_cast<UnsignedInt
>(1);
249 rv = rand_uint<UnsignedInt>();
256 rv = umin + rand_uint_lt(range);
258 return static_cast<Integer
>(rv);
263 BLOCXX_COMMON_API rand_range(
char,
char);
265 BLOCXX_COMMON_API rand_range(
signed char,
signed char);
266 template unsigned char
267 BLOCXX_COMMON_API rand_range(
unsigned char,
unsigned char);
269 BLOCXX_COMMON_API rand_range(
short,
short);
270 template unsigned short
271 BLOCXX_COMMON_API rand_range(
unsigned short,
unsigned short);
273 BLOCXX_COMMON_API rand_range(
int,
int);
274 template unsigned int
275 BLOCXX_COMMON_API rand_range(
unsigned int,
unsigned int);
277 BLOCXX_COMMON_API rand_range(
long,
long);
278 template unsigned long
279 BLOCXX_COMMON_API rand_range(
unsigned long,
unsigned long);
281 BLOCXX_COMMON_API rand_range(
long long,
long long);
282 template unsigned long long
283 BLOCXX_COMMON_API rand_range(
unsigned long long,
unsigned long long);
285 template <
unsigned int N>
288 enum { value = 1 + log2<N/2>::value };
298 template <
typename Number>
299 struct bits_precision
301 typedef std::numeric_limits<Number> lim_t;
302 enum { value = lim_t::digits * log2<lim_t::radix>::value };
305 template <
typename Real>
306 Real rand_unit_interval()
308 typedef UInt32 uint_t;
309 int const UINT_BITS = 32;
311 (bits_precision<Real>::value + UINT_BITS - 1) / UINT_BITS;
313 for (
int i = 1;
i <= NUINT; ++
i)
315 Real r =
static_cast<Real
>(rand_uint<uint_t>());
316 rv += std::ldexp(r, -UINT_BITS *
i);
322 template float rand_unit_interval<float>();
323 template double rand_unit_interval<double>();
324 template long double rand_unit_interval<long double>();
328 void rand_save_state()
331 char const * rval = RAND_file_name(randFile,
MAXPATHLEN);
336 using namespace FileSystem::Path;
339 if (RAND_write_file(randFile) <= 0)
359 volatile sig_atomic_t g_counter;
360 volatile unsigned char* g_data;
361 volatile sig_atomic_t g_dataIdx;
370 static void randomALRMHandler()
372 static void randomALRMHandler(
int sig)
375 if (g_dataIdx < g_dataSize)
377 g_data[g_dataIdx++] ^= g_counter & 0xFF;
389 void generateRandomTimerData(
unsigned char* data,
int size,
int* iterations)
396 MutexLock l(g_randomTimerGuard);
404 struct sigaction sa, osa;
405 sa.sa_handler = randomALRMHandler;
407 sigemptyset(&sa.sa_mask);
408 sigaction(SIGALRM, &sa, &osa);
411 struct ::itimerval tv, otv;
412 tv.it_value.tv_sec = 0;
413 tv.it_value.tv_usec = 10 * 1000;
414 tv.it_interval = tv.it_value;
415 setitimer(ITIMER_REAL, &tv, &otv);
417 while ((*iterations)-- > 0)
420 for (g_dataIdx = 0; g_dataIdx < g_dataSize;)
426 for (
int j = 0; j < g_dataSize; j++)
428 g_data[j] = (g_data[j]>>3) | (g_data[j]<<5);
431 setitimer(ITIMER_REAL, &otv, 0);
434 sigaction(SIGALRM, &osa, 0);
438 void generateRandomDataFromFile(
const char*
name,
int len)
440 int fd = ::open(
name, O_RDONLY);
446 std::vector<char> buf(len);
447 int bytesRead = ::read(fd, &buf[0], len);
452 buf.resize(bytesRead);
453 ::RAND_add(&buf[0], buf.size(), 0.0);
457 void generateRandomDataFromTime(
double entropy)
460 ::gettimeofday(&tv, 0);
461 ::RAND_add(&tv,
sizeof(tv), entropy);
463 clock_t c(::clock());
464 ::RAND_add(&c,
sizeof(c), entropy);
467 ::getrusage(RUSAGE_SELF, &ru);
468 ::RAND_add(&ru,
sizeof(ru), entropy);
470 ::getrusage(RUSAGE_CHILDREN, &ru);
471 ::RAND_add(&ru,
sizeof(ru), entropy);
483 const cmd randomSourceCommands[] =
485 {
"advfsstat -b usr_domain", 0.01 },
486 {
"advfsstat -l 2 usr_domain", 0.5 },
487 {
"advfsstat -p usr_domain", 0.01 },
488 {
"arp -a -n", 0.5 },
495 {
"ifconfig -a", 0.5 },
500 {
"lpstat -t", 0.1 },
501 {
"ls -alniR /var/log", 1.0 },
502 {
"ls -alniR /var/adm", 1.0 },
503 {
"ls -alni /var/spool/mail", 1.0 },
504 {
"ls -alni /proc", 1.0 },
505 {
"ls -alniR /tmp", 1.0 },
506 {
"ls -alniR /var/tmp", 1.0 },
507 {
"ls -alni /var/mail", 1.0 },
508 {
"ls -alniR /var/db", 1.0 },
509 {
"ls -alniR /etc", 1.0 },
510 {
"ls -alniR /private/var/log", 1.0 },
511 {
"ls -alniR /private/var/db", 1.0 },
512 {
"ls -alniR /private/etc", 1.0 },
513 {
"ls -alniR /private/tmp", 1.0 },
514 {
"ls -alniR /private/var/tmp", 1.0 },
516 {
"netstat -s", 1.5 },
517 {
"netstat -n", 1.5 },
518 {
"netstat -a -n", 1.5 },
519 {
"netstat -anv", 1.5 },
520 {
"netstat -i -n", 0.5 },
521 {
"netstat -r -n", 0.1 },
522 {
"netstat -m", 0.5 },
523 {
"netstat -ms", 0.5 },
526 {
"ps -laxww", 1.5 },
542 {
"ripquery -nw 1 127.0.0.1", 0.5 },
543 {
"sar -A 1 1", 0.5 },
544 {
"snmp_request localhost public get 1.3.6.1.2.1.7.1.0", 0.5 },
545 {
"snmp_request localhost public get 1.3.6.1.2.1.7.4.0", 0.5 },
546 {
"snmp_request localhost public get 1.3.6.1.2.1.4.3.0", 0.5 },
547 {
"snmp_request localhost public get 1.3.6.1.2.1.6.10.0", 0.5 },
548 {
"snmp_request localhost public get 1.3.6.1.2.1.6.11.0", 0.5 },
549 {
"snmp_request localhost public get 1.3.6.1.2.1.6.13.0", 0.5 },
550 {
"snmp_request localhost public get 1.3.6.1.2.1.5.1.0", 0.5 },
551 {
"snmp_request localhost public get 1.3.6.1.2.1.5.3.0", 0.5 },
552 {
"tail -c 1024 /var/log/messages", 1.0 },
553 {
"tail -c 1024 /var/log/syslog", 1.0 },
554 {
"tail -c 1024 /var/log/system.log", 1.0 },
555 {
"tail -c 1024 /var/log/debug", 1.0 },
556 {
"tail -c 1024 /var/adm/messages", 1.0 },
557 {
"tail -c 1024 /var/adm/syslog", 1.0 },
558 {
"tail -c 1024 /var/adm/syslog/mail.log", 1.0 },
559 {
"tail -c 1024 /var/adm/syslog/syslog.log", 1.0 },
560 {
"tail -c 1024 /var/log/maillog", 1.0 },
561 {
"tail -c 1024 /var/adm/maillog", 1.0 },
562 {
"tail -c 1024 /var/adm/SPlogs/SPdaemon.log", 1.0 },
563 {
"tail -c 1024 /usr/es/adm/cluster.log", 1.0 },
564 {
"tail -c 1024 /usr/adm/cluster.log", 1.0 },
565 {
"tail -c 1024 /var/adm/cluster.log", 1.0 },
566 {
"tail -c 1024 /var/adm/ras/conslog", 1.0 },
567 {
"tcpdump -c 100 -efvvx", 1 },
570 {
"vmstat -c", 2.0 },
571 {
"vmstat -s", 2.0 },
572 {
"vmstat -i", 2.0 },
573 {
"vmstat -f", 2.0 },
582 class RandomOutputGatherer :
public Exec::OutputCallback
585 virtual void doHandleData(
586 const char* data,
size_t dataLen, Exec::EOutputSource outputSource,
587 const ProcessRef& theProc,
size_t streamIndex,
588 Array<char>& inputBuffer
591 if (outputSource == Exec::E_STDERR)
595 ::RAND_add(data, dataLen, 0.0);
603 randomSourceCommands[streamIndex].usefulness *
604 static_cast<double>(dataLen) / 1024.0
609 ::RAND_add(&dataLen,
sizeof(dataLen), 0.0);
610 ::RAND_add(&outputSource,
sizeof(outputSource), 0.0);
612 generateRandomDataFromTime(0.1);
617 class RandomInputCallback :
public Exec::InputCallback
620 virtual void doGetData(
621 Array<char>& inputBuffer,
const ProcessRef& theProcess,
626 if (theProcess->in()->isOpen())
628 theProcess->in()->close();
633 String locateInPath(
const String& cmd,
const String& path)
636 for (
size_t i = 0;
i < pathElements.size(); ++
i)
638 String testCmd(pathElements[
i] +
'/' + cmd);
639 if (FileSystem::exists(testCmd))
647 class RandomTimerThread :
public Thread
653 unsigned char buf[256];
655 generateRandomTimerData(buf,
sizeof(buf), &iterations);
656 ::RAND_add(buf,
sizeof(buf), 32);
660 generateRandomDataFromTime(0.1);
667 void rand_init_impl()
673 HCRYPTPROV hProvider = 0;
676 if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL,
677 CRYPT_VERIFYCONTEXT))
679 if (CryptGenRandom(hProvider,
sizeof(buf), buf))
681 RAND_add(buf,
sizeof(buf),
sizeof(buf));
683 CryptReleaseContext(hProvider, 0);
691 RAND_egd(BLOCXX_DEFAULT_STATE_DIR
"/egd-pool");
695 if (::RAND_status() == 1)
703 if (::SSLeay() < 0x00907000L)
706 int loadedBytes = RAND_load_file(
"/dev/random", 1024);
707 if (loadedBytes == 0)
710 RAND_load_file(
"/dev/urandom", 1024);
713 if (RAND_status() == 1)
719 const char *names[] =
728 for (
int i = 0; names[
i];
i++)
730 if (RAND_egd(names[
i]) != -1)
736 if (RAND_status() == 1)
744 const char* rval = ::RAND_file_name(randFile,
MAXPATHLEN);
747 using namespace FileSystem::Path;
750 if (
security(randFile).first == E_SECURE_FILE)
752 ::RAND_load_file(randFile, -1);
755 catch (FileSystemException& e)
779 generateRandomDataFromTime(0.0);
781 RandomTimerThread randomTimerThread;
782 randomTimerThread.start();
785 const char* files[] = {
"/dev/mem", 0 };
786 for (
const char** p = files; *p; ++p)
788 generateRandomDataFromFile(*p, 1024*1024*2);
791 generateRandomDataFromTime(0.1);
793 pid_t myPid(::getpid());
794 ::RAND_add(&myPid,
sizeof(myPid), 0.0);
796 pid_t parentPid(::getppid());
797 ::RAND_add(&parentPid,
sizeof(parentPid), 0.0);
799 uid_t myUid(::getuid());
800 ::RAND_add(&myUid,
sizeof(myUid), 0.0);
802 gid_t myGid(::getgid());
803 ::RAND_add(&myGid,
sizeof(myGid), 0.0);
806 Array<ProcessRef> procs;
807 for (
size_t i = 0; randomSourceCommands[
i].command != 0; ++
i)
809 StringArray cmd = String(randomSourceCommands[
i].command).tokenize();
816 if (cmd[0][0] !=
'/')
818 const char * RANDOM_COMMAND_PATH =
819 "/bin:/sbin:/usr/bin:/usr/sbin:/usr/ucb:/usr/etc:/usr/bsd:"
820 "/etc:/usr/local/bin:/usr/local/sbin";
823 String locatedCmd = locateInPath(cmd[0], RANDOM_COMMAND_PATH);
824 if( locatedCmd == cmd[0] )
832 using namespace FileSystem::Path;
833 if (
security(locatedCmd).first != E_SECURE_FILE)
839 catch (FileSystemException& e)
851 procs.push_back(Exec::spawn(cmd));
853 catch(
const ExecErrorException& e)
859 RandomOutputGatherer randomOutputGatherer;
860 RandomInputCallback randomInputCallback;
861 const Timeout RANDOM_COMMAND_TIMEOUT = Timeout::relative(10.0);
864 Exec::processInputOutput(
865 randomOutputGatherer, procs,
866 randomInputCallback, RANDOM_COMMAND_TIMEOUT
869 catch (ExecTimeoutException&)
875 for (
size_t i = 0;
i < procs.size(); ++
i)
877 procs[
i]->waitCloseTerm(Timeout::relative(0.001), Timeout::relative(0.002), Timeout::relative(0.003));
878 Process::Status status = procs[
i]->processStatus();
879 if (!status.terminatedSuccessfully())
881 int rv = status.exitStatus();
882 ::RAND_add(&rv,
sizeof(rv), 0.0);
886 randomTimerThread.join();
888 generateRandomDataFromTime(0.1);
#define BLOCXX_ASSERT(CON)
BLOCXX_ASSERT works similar to the assert() macro, but instead of calling abort(),...
#define BLOCXX_DEFINE_EXCEPTION(NAME)
Define a new exception class named <NAME>Exception that derives from Exception.
#define BLOCXX_THROW(exType, msg)
Throw an exception using FILE and LINE.
#define BLOCXX_GLOBAL_MUTEX_INIT()
#define BLOCXX_INVALID_HANDLE
BLOCXX_COMMON_API std::pair< ESecurity, String > security(String const &path, UserId uid)
BLOCXX_COMMON_API String dirname(const String &filename)
Take a string that contains a pathname, and return a string that is a pathname of the parent director...
BLOCXX_COMMON_API bool removeFile(const String &path)
Remove the given file.
void BLOCXX_COMMON_API callOnce(OnceFlag &flag, FuncT F)
The first time callOnce is called with a given onceFlag argument, it calls func with no argument and ...
Array< String > StringArray
LazyGlobal< Mutex, int, GlobalMutexFactory > GlobalMutex