Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "postgres.h"
00033
00034 #include "px.h"
00035
00036
00037 #define RND_BYTES 32
00038
00039
00040
00041
00042
00043
00044
00045 #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
00046 || defined(__NetBSD__) || defined(__DragonFly__) \
00047 || defined(__darwin__) || defined(__SOLARIS__) \
00048 || defined(__hpux) || defined(__HPUX__) \
00049 || defined(__CYGWIN__) || defined(_AIX)
00050
00051 #define TRY_DEV_RANDOM
00052
00053 #include <fcntl.h>
00054 #include <unistd.h>
00055
00056 static int
00057 safe_read(int fd, void *buf, size_t count)
00058 {
00059 int done = 0;
00060 char *p = buf;
00061 int res;
00062
00063 while (count)
00064 {
00065 res = read(fd, p, count);
00066 if (res <= 0)
00067 {
00068 if (errno == EINTR)
00069 continue;
00070 return PXE_DEV_READ_ERROR;
00071 }
00072 p += res;
00073 done += res;
00074 count -= res;
00075 }
00076 return done;
00077 }
00078
00079 static uint8 *
00080 try_dev_random(uint8 *dst)
00081 {
00082 int fd;
00083 int res;
00084
00085 fd = open("/dev/urandom", O_RDONLY, 0);
00086 if (fd == -1)
00087 {
00088 fd = open("/dev/random", O_RDONLY, 0);
00089 if (fd == -1)
00090 return dst;
00091 }
00092 res = safe_read(fd, dst, RND_BYTES);
00093 close(fd);
00094 if (res > 0)
00095 dst += res;
00096 return dst;
00097 }
00098 #endif
00099
00100
00101
00102
00103 #ifdef WIN32
00104
00105 #define TRY_WIN32_GENRAND
00106 #define TRY_WIN32_PERFC
00107
00108 #include <windows.h>
00109 #include <wincrypt.h>
00110
00111
00112
00113
00114
00115
00116 static uint8 *
00117 try_win32_genrand(uint8 *dst)
00118 {
00119 int res;
00120 HCRYPTPROV h = 0;
00121
00122 res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
00123 (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET));
00124 if (!res)
00125 res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
00126 CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET);
00127 if (!res)
00128 return dst;
00129
00130 res = CryptGenRandom(h, RND_BYTES, dst);
00131 if (res == TRUE)
00132 dst += RND_BYTES;
00133
00134 CryptReleaseContext(h, 0);
00135 return dst;
00136 }
00137
00138 static uint8 *
00139 try_win32_perfc(uint8 *dst)
00140 {
00141 int res;
00142 LARGE_INTEGER time;
00143
00144 res = QueryPerformanceCounter(&time);
00145 if (!res)
00146 return dst;
00147
00148 memcpy(dst, &time, sizeof(time));
00149 return dst + sizeof(time);
00150 }
00151 #endif
00152
00153
00154
00155
00156
00157
00158
00159 #ifndef WIN32
00160
00161 #define TRY_UNIXSTD
00162
00163 #include <sys/types.h>
00164 #include <sys/time.h>
00165 #include <time.h>
00166 #include <unistd.h>
00167
00168
00169
00170
00171
00172
00173
00174 static uint8 *
00175 try_unix_std(uint8 *dst)
00176 {
00177 pid_t pid;
00178 int x;
00179 PX_MD *md;
00180 struct timeval tv;
00181 int res;
00182
00183
00184 pid = getpid();
00185 memcpy(dst, (uint8 *) &pid, sizeof(pid));
00186 dst += sizeof(pid);
00187
00188
00189 gettimeofday(&tv, NULL);
00190 memcpy(dst, (uint8 *) &tv, sizeof(tv));
00191 dst += sizeof(tv);
00192
00193
00194 x = random();
00195 memcpy(dst, (uint8 *) &x, sizeof(x));
00196 dst += sizeof(x);
00197
00198
00199 res = px_find_digest("sha1", &md);
00200 if (res >= 0)
00201 {
00202 uint8 *ptr;
00203 uint8 stack[8192];
00204 int alloc = 32 * 1024;
00205
00206 px_md_update(md, stack, sizeof(stack));
00207 ptr = px_alloc(alloc);
00208 px_md_update(md, ptr, alloc);
00209 px_free(ptr);
00210
00211 px_md_finish(md, dst);
00212 px_md_free(md);
00213
00214 dst += 20;
00215 }
00216
00217 return dst;
00218 }
00219 #endif
00220
00221
00222
00223
00224
00225
00226 unsigned
00227 px_acquire_system_randomness(uint8 *dst)
00228 {
00229 uint8 *p = dst;
00230
00231 #ifdef TRY_DEV_RANDOM
00232 p = try_dev_random(p);
00233 #endif
00234 #ifdef TRY_WIN32_GENRAND
00235 p = try_win32_genrand(p);
00236 #endif
00237 #ifdef TRY_WIN32_PERFC
00238 p = try_win32_perfc(p);
00239 #endif
00240 #ifdef TRY_UNIXSTD
00241 p = try_unix_std(p);
00242 #endif
00243 return p - dst;
00244 }