1 /* rndw32.c  -	W32 entropy gatherer
2  *	Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3  *	Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-1999
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  *************************************************************************
21  * The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann.
22  * Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this
23  * copyright notice:
24  *
25  * This module is part of the cryptlib continuously seeded pseudorandom
26  * number generator.  For usage conditions, see lib_rand.c
27  *
28  * [Here is the notice from lib_rand.c, which is now called dev_sys.c]
29  *
30  * This module and the misc/rnd*.c modules represent the cryptlib
31  * continuously seeded pseudorandom number generator (CSPRNG) as described in
32  * my 1998 Usenix Security Symposium paper "The generation of random numbers
33  * for cryptographic purposes".
34  *
35  * The CSPRNG code is copyright Peter Gutmann (and various others) 1996,
36  * 1997, 1998, 1999, all rights reserved.  Redistribution of the CSPRNG
37  * modules and use in source and binary forms, with or without modification,
38  * are permitted provided that the following conditions are met:
39  *
40  * 1. Redistributions of source code must retain the above copyright notice
41  *    and this permission notice in its entirety.
42  *
43  * 2. Redistributions in binary form must reproduce the copyright notice in
44  *    the documentation and/or other materials provided with the distribution.
45  *
46  * 3. A copy of any bugfixes or enhancements made must be provided to the
47  *    author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the
48  *    baseline version of the code.
49  *
50  * ALTERNATIVELY, the code may be distributed under the terms of the GNU
51  * General Public License, version 2 or any later version published by the
52  * Free Software Foundation, in which case the provisions of the GNU GPL are
53  * required INSTEAD OF the above restrictions.
54  *
55  * Although not required under the terms of the GPL, it would still be nice if
56  * you could make any changes available to the author to allow a consistent
57  * code base to be maintained
58  *************************************************************************
59  */
60 
61 #include <config.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <assert.h>
65 #include <errno.h>
66 #include <string.h>
67 
68 #include <windows.h>
69 
70 
71 #include "types.h"
72 #include "util.h"
73 #include "algorithms.h"
74 
75 #include "i18n.h"
76 
77 
78 static int debug_me;
79 
80 /*
81  * Definitions which are missing from the current GNU Windows32Api
82  */
83 
84 #ifndef TH32CS_SNAPHEAPLIST
85 #define TH32CS_SNAPHEAPLIST 1
86 #define TH32CS_SNAPPROCESS  2
87 #define TH32CS_SNAPTHREAD   4
88 #define TH32CS_SNAPMODULE   8
89 #define TH32CS_SNAPALL	    (1|2|4|8)
90 #define TH32CS_INHERIT	    0x80000000
91 #endif /*TH32CS_SNAPHEAPLIST*/
92 
93 #ifndef IOCTL_DISK_PERFORMANCE
94 #define IOCTL_DISK_PERFORMANCE	0x00070020
95 #endif
96 #ifndef VER_PLATFORM_WIN32_WINDOWS
97 #define VER_PLATFORM_WIN32_WINDOWS 1
98 #endif
99 
100 /* This used to be (6*8+5*4+8*2), but Peter Gutmann figured a larger
101    value in a newer release. So we use a far larger value. */
102 #define SIZEOF_DISK_PERFORMANCE_STRUCT 256
103 
104 
105 typedef struct {
106     DWORD dwSize;
107     DWORD th32ProcessID;
108     DWORD th32HeapID;
109     DWORD dwFlags;
110 } HEAPLIST32;
111 
112 typedef struct {
113     DWORD dwSize;
114     HANDLE hHandle;
115     DWORD dwAddress;
116     DWORD dwBlockSize;
117     DWORD dwFlags;
118     DWORD dwLockCount;
119     DWORD dwResvd;
120     DWORD th32ProcessID;
121     DWORD th32HeapID;
122 } HEAPENTRY32;
123 
124 typedef struct {
125     DWORD dwSize;
126     DWORD cntUsage;
127     DWORD th32ProcessID;
128     DWORD th32DefaultHeapID;
129     DWORD th32ModuleID;
130     DWORD cntThreads;
131     DWORD th32ParentProcessID;
132     LONG  pcPriClassBase;
133     DWORD dwFlags;
134     char  szExeFile[260];
135 } PROCESSENTRY32;
136 
137 typedef struct {
138     DWORD dwSize;
139     DWORD cntUsage;
140     DWORD th32ThreadID;
141     DWORD th32OwnerProcessID;
142     LONG  tpBasePri;
143     LONG  tpDeltaPri;
144     DWORD dwFlags;
145 } THREADENTRY32;
146 
147 typedef struct {
148     DWORD dwSize;
149     DWORD th32ModuleID;
150     DWORD th32ProcessID;
151     DWORD GlblcntUsage;
152     DWORD ProccntUsage;
153     BYTE  *modBaseAddr;
154     DWORD modBaseSize;
155     HMODULE hModule;
156     char  szModule[256];
157     char  szExePath[260];
158 } MODULEENTRY32;
159 
160 
161 
162 /* Type definitions for function pointers to call Toolhelp32 functions
163  * used with the windows95 gatherer */
164 typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme);
165 typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte);
166 typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe);
167 typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl);
168 typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID,
169 				   DWORD th32HeapID);
170 typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe);
171 typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID);
172 
173 /* Type definitions for function pointers to call NetAPI32 functions */
174 typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService,
175 					   DWORD dwLevel, DWORD dwOptions,
176 					   LPBYTE * lpBuffer);
177 typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer);
178 typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer);
179 
180 
181 /* When we query the performance counters, we allocate an initial buffer and
182  * then reallocate it as required until RegQueryValueEx() stops returning
183  * ERROR_MORE_DATA.  The following values define the initial buffer size and
184  * step size by which the buffer is increased
185  */
186 #define PERFORMANCE_BUFFER_SIZE 	65536	/* Start at 64K */
187 #define PERFORMANCE_BUFFER_STEP 	16384	/* Step by 16K */
188 
189 
190 static void
slow_gatherer_windows95(void (* add)(const void *,size_t,int),int requester)191 slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester )
192 {
193     static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
194     static MODULEWALK pModule32First = NULL;
195     static MODULEWALK pModule32Next = NULL;
196     static PROCESSWALK pProcess32First = NULL;
197     static PROCESSWALK pProcess32Next = NULL;
198     static THREADWALK pThread32First = NULL;
199     static THREADWALK pThread32Next = NULL;
200     static HEAPLISTWALK pHeap32ListFirst = NULL;
201     static HEAPLISTWALK pHeap32ListNext = NULL;
202     static HEAPFIRST pHeap32First = NULL;
203     static HEAPNEXT pHeap32Next = NULL;
204     HANDLE hSnapshot;
205 
206 
207     /* initialize the Toolhelp32 function pointers */
208     if ( !pCreateToolhelp32Snapshot ) {
209 	HANDLE hKernel;
210 
211 	if ( debug_me )
212 	    log_debug ("rndw32#slow_gatherer_95: init toolkit\n" );
213 
214 	/* Obtain the module handle of the kernel to retrieve the addresses
215 	 * of the Toolhelp32 functions */
216 	if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) {
217 	    g10_log_fatal ( "rndw32: can't get module handle\n" );
218 	}
219 
220 	/* Now get pointers to the functions */
221 	pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel,
222 						  "CreateToolhelp32Snapshot");
223 	pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First");
224 	pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next");
225 	pProcess32First = (PROCESSWALK) GetProcAddress (hKernel,
226 							"Process32First");
227 	pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel,
228 						       "Process32Next");
229 	pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First");
230 	pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next");
231 	pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel,
232 							  "Heap32ListFirst");
233 	pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel,
234 							 "Heap32ListNext");
235 	pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First");
236 	pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next");
237 
238 	if (	!pCreateToolhelp32Snapshot
239 	     || !pModule32First || !pModule32Next
240 	     || !pProcess32First || !pProcess32Next
241 	     || !pThread32First  || !pThread32Next
242 	     || !pHeap32ListFirst || !pHeap32ListNext
243 	     || !pHeap32First	  || !pHeap32Next  ) {
244 	    g10_log_fatal ( "rndw32: failed to get a toolhep function\n" );
245 	}
246     }
247 
248     /* Take a snapshot of everything we can get to which is currently
249      *	in the system */
250     if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) {
251 	g10_log_fatal ( "rndw32: failed to take a toolhelp snapshot\n" );
252     }
253 
254     /* Walk through the local heap */
255     {	HEAPLIST32 hl32;
256 	hl32.dwSize = sizeof (HEAPLIST32);
257 	if (pHeap32ListFirst (hSnapshot, &hl32)) {
258 	    if ( debug_me )
259 		log_debug ("rndw32#slow_gatherer_95: walk heap\n" );
260 	    do {
261 		HEAPENTRY32 he32;
262 
263 		/* First add the information from the basic Heaplist32 struct */
264 		(*add) ( &hl32, sizeof (hl32), requester );
265 
266 		/* Now walk through the heap blocks getting information
267 		 * on each of them */
268 		he32.dwSize = sizeof (HEAPENTRY32);
269 		if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){
270 		    do {
271 			(*add) ( &he32, sizeof (he32), requester );
272 		    } while (pHeap32Next (&he32));
273 		}
274 	    } while (pHeap32ListNext (hSnapshot, &hl32));
275 	}
276     }
277 
278 
279     /* Walk through all processes */
280     {	PROCESSENTRY32 pe32;
281 	pe32.dwSize = sizeof (PROCESSENTRY32);
282 	if (pProcess32First (hSnapshot, &pe32)) {
283 	    if ( debug_me )
284 		log_debug ("rndw32#slow_gatherer_95: walk processes\n" );
285 	    do {
286 		(*add) ( &pe32, sizeof (pe32), requester );
287 	    } while (pProcess32Next (hSnapshot, &pe32));
288 	}
289     }
290 
291     /* Walk through all threads */
292     {	THREADENTRY32 te32;
293 	te32.dwSize = sizeof (THREADENTRY32);
294 	if (pThread32First (hSnapshot, &te32)) {
295 	    if ( debug_me )
296 		log_debug ("rndw32#slow_gatherer_95: walk threads\n" );
297 	    do {
298 		(*add) ( &te32, sizeof (te32), requester );
299 	    } while (pThread32Next (hSnapshot, &te32));
300 	}
301     }
302 
303     /* Walk through all modules associated with the process */
304     {	MODULEENTRY32 me32;
305 	me32.dwSize = sizeof (MODULEENTRY32);
306 	if (pModule32First (hSnapshot, &me32)) {
307 	    if ( debug_me )
308 		log_debug ("rndw32#slow_gatherer_95: walk modules\n" );
309 	    do {
310 		(*add) ( &me32, sizeof (me32), requester );
311 	    } while (pModule32Next (hSnapshot, &me32));
312 	}
313     }
314 
315     CloseHandle (hSnapshot);
316 }
317 
318 
319 
320 static void
slow_gatherer_windowsNT(void (* add)(const void *,size_t,int),int requester)321 slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester )
322 {
323     static int is_initialized = 0;
324     static NETSTATISTICSGET pNetStatisticsGet = NULL;
325     static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
326     static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
327     static int is_workstation = 1;
328 
329     static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
330     PERF_DATA_BLOCK *pPerfData;
331     HANDLE hDevice, hNetAPI32 = NULL;
332     DWORD dwSize, status;
333     int nDrive;
334 
335     if ( !is_initialized ) {
336 	HKEY hKey;
337 
338 	if ( debug_me )
339 	    log_debug ("rndw32#slow_gatherer_nt: init toolkit\n" );
340 	/* Find out whether this is an NT server or workstation if necessary */
341 	if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
342 			  "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
343 			  0, KEY_READ, &hKey) == ERROR_SUCCESS) {
344 	    BYTE szValue[32];
345 	    dwSize = sizeof (szValue);
346 
347 	    if ( debug_me )
348 		log_debug ("rndw32#slow_gatherer_nt: check product options\n" );
349 	    status = RegQueryValueEx (hKey, "ProductType", 0, NULL,
350 				      szValue, &dwSize);
351 	    if (status == ERROR_SUCCESS
352                 && ascii_strcasecmp (szValue, "WinNT")) {
353 		/* Note: There are (at least) three cases for ProductType:
354 		 * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
355 		 * NT Server acting as a Domain Controller */
356 		is_workstation = 0;
357 		if ( debug_me )
358 		    log_debug ("rndw32: this is a NT server\n");
359 	    }
360 	    RegCloseKey (hKey);
361 	}
362 
363 	/* Initialize the NetAPI32 function pointers if necessary */
364 	if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) {
365 	    if ( debug_me )
366 		log_debug ("rndw32#slow_gatherer_nt: netapi32 loaded\n" );
367 	    pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,
368 						       "NetStatisticsGet");
369 	    pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,
370 						       "NetApiBufferSize");
371 	    pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,
372 						       "NetApiBufferFree");
373 
374 	    if ( !pNetStatisticsGet
375 		 || !pNetApiBufferSize || !pNetApiBufferFree ) {
376 		FreeLibrary (hNetAPI32);
377 		hNetAPI32 = NULL;
378 		g10_log_debug ("rndw32: No NETAPI found\n" );
379 	    }
380 	}
381 
382 	is_initialized = 1;
383     }
384 
385     /* Get network statistics.	Note: Both NT Workstation and NT Server by
386      * default will be running both the workstation and server services.  The
387      * heuristic below is probably useful though on the assumption that the
388      * majority of the network traffic will be via the appropriate service.
389      * In any case the network statistics return almost no randomness */
390     {	LPBYTE lpBuffer;
391 	if (hNetAPI32 && !pNetStatisticsGet (NULL,
392 			   is_workstation ? L"LanmanWorkstation" :
393 			   L"LanmanServer", 0, 0, &lpBuffer) ) {
394 	    if ( debug_me )
395 		log_debug ("rndw32#slow_gatherer_nt: get netstats\n" );
396 	    pNetApiBufferSize (lpBuffer, &dwSize);
397 	    (*add) ( lpBuffer, dwSize,requester );
398 	    pNetApiBufferFree (lpBuffer);
399 	}
400     }
401 
402     /* Get disk I/O statistics for all the hard drives */
403     for (nDrive = 0;; nDrive++) {
404         char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT];
405 	char szDevice[50];
406 
407 	/* Check whether we can access this device */
408 	sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive);
409 	hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
410 			      NULL, OPEN_EXISTING, 0, NULL);
411 	if (hDevice == INVALID_HANDLE_VALUE)
412 	    break;
413 
414 	/* Note: This only works if you have turned on the disk performance
415 	 * counters with 'diskperf -y'.  These counters are off by default */
416 	if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
417 			     diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT,
418 			     &dwSize, NULL))
419 	{
420 	    if ( debug_me )
421 		log_debug ("rndw32#slow_gatherer_nt: iostats drive %d\n",
422 								  nDrive );
423 	    (*add) (diskPerformance, dwSize, requester );
424 	}
425 	else {
426 	    log_info ("NOTE: you should run 'diskperf -y' "
427 		      "to enable the disk statistics\n");
428 	}
429 	CloseHandle (hDevice);
430     }
431 
432 #if 0 /* we don't need this in GnuPG  */
433     /* Wait for any async keyset driver binding to complete.  You may be
434      * wondering what this call is doing here... the reason it's necessary is
435      * because RegQueryValueEx() will hang indefinitely if the async driver
436      * bind is in progress.  The problem occurs in the dynamic loading and
437      * linking of driver DLL's, which work as follows:
438      *
439      * hDriver = LoadLibrary( DRIVERNAME );
440      * pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 );
441      * pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 );
442      *
443      * If RegQueryValueEx() is called while the GetProcAddress()'s are in
444      * progress, it will hang indefinitely.  This is probably due to some
445      * synchronisation problem in the NT kernel where the GetProcAddress()
446      * calls affect something like a module reference count or function
447      * reference count while RegQueryValueEx() is trying to take a snapshot
448      * of the statistics, which include the reference counts.  Because of
449      * this, we have to wait until any async driver bind has completed
450      * before we can call RegQueryValueEx() */
451     waitSemaphore (SEMAPHORE_DRIVERBIND);
452 #endif
453 
454     /* Get information from the system performance counters.  This can take
455      * a few seconds to do.  In some environments the call to
456      * RegQueryValueEx() can produce an access violation at some random time
457      * in the future, adding a short delay after the following code block
458      * makes the problem go away.  This problem is extremely difficult to
459      * reproduce, I haven't been able to get it to occur despite running it
460      * on a number of machines.  The best explanation for the problem is that
461      * on the machine where it did occur, it was caused by an external driver
462      * or other program which adds its own values under the
463      * HKEY_PERFORMANCE_DATA key.  The NT kernel calls the required external
464      * modules to map in the data, if there's a synchronisation problem the
465      * external module would write its data at an inappropriate moment,
466      * causing the access violation.  A low-level memory checker indicated
467      * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an
468      * interminable number of calls down inside RegQueryValueEx(), was
469      * overwriting memory (it wrote twice the allocated size of a buffer to a
470      * buffer allocated by the NT kernel).  This may be what's causing the
471      * problem, but since it's in the kernel there isn't much which can be
472      * done.
473      *
474      * In addition to these problems the code in RegQueryValueEx() which
475      * estimates the amount of memory required to return the performance
476      * counter information isn't very accurate, since it always returns a
477      * worst-case estimate which is usually nowhere near the actual amount
478      * required.  For example it may report that 128K of memory is required,
479      * but only return 64K of data */
480     if (getenv("GNUPG_RNDW32_NOPERF"))
481       {
482         static int shown;
483 
484         if (!shown)
485           {
486             shown = 1;
487             g10_log_info ("note: get performance data has been disabled\n");
488           }
489       }
490     else
491     {	pPerfData =  xmalloc (cbPerfData);
492 	for (;;) {
493 	    dwSize = cbPerfData;
494 	    if ( debug_me )
495 		log_debug ("rndw32#slow_gatherer_nt: get perf data\n" );
496 	    status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
497 				      NULL, (LPBYTE) pPerfData, &dwSize);
498 	    if (status == ERROR_SUCCESS) {
499 		if (!memcmp (pPerfData->Signature, L"PERF", 8)) {
500 		    (*add) ( pPerfData, dwSize, requester );
501 		}
502 		else
503 		    g10_log_debug ( "rndw32: no PERF signature\n");
504 		break;
505 	    }
506 	    else if (status == ERROR_MORE_DATA) {
507 		cbPerfData += PERFORMANCE_BUFFER_STEP;
508 		pPerfData = xrealloc (pPerfData, cbPerfData);
509 	    }
510 	    else {
511 		g10_log_debug ( "rndw32: get performance data problem\n");
512 		break;
513 	    }
514 	}
515 	xfree (pPerfData);
516     }
517     /* Although this isn't documented in the Win32 API docs, it's necessary
518        to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
519        implicitly opened on the first call to RegQueryValueEx()).  If this
520        isn't done then any system components which provide performance data
521        can't be removed or changed while the handle remains active */
522     RegCloseKey (HKEY_PERFORMANCE_DATA);
523 }
524 
525 
526 int
rndw32_gather_random(void (* add)(const void *,size_t,int),int requester,size_t length,int level)527 rndw32_gather_random (void (*add)(const void*, size_t, int), int requester,
528                       size_t length, int level )
529 {
530     static int is_initialized;
531     static int is_windowsNT, has_toolhelp;
532 
533 
534     if( !level )
535 	return 0;
536     /* We don't differentiate between level 1 and 2 here because
537      * there is no internal entropy pool as a scarce resource. It may
538      * all work slower, but because our entropy source will never
539      * block but deliver some not easy to measure entropy, we assume level 2
540      */
541 
542 
543     if ( !is_initialized ) {
544 	OSVERSIONINFO osvi = { sizeof( osvi ) };
545 	DWORD platform;
546 
547 	GetVersionEx( &osvi );
548 	platform = osvi.dwPlatformId;
549         is_windowsNT = platform == VER_PLATFORM_WIN32_NT;
550         has_toolhelp = (platform == VER_PLATFORM_WIN32_WINDOWS
551                         || (is_windowsNT && osvi.dwMajorVersion >= 5));
552 
553 	if ( platform == VER_PLATFORM_WIN32s ) {
554 	    g10_log_fatal("can't run on a W32s platform\n" );
555 	}
556 	is_initialized = 1;
557 	if ( debug_me )
558 	    log_debug ("rndw32#gather_random: platform=%d\n", (int)platform );
559     }
560 
561 
562     if ( debug_me )
563 	log_debug ("rndw32#gather_random: req=%d len=%u lvl=%d\n",
564 			   requester, (unsigned int)length, level );
565 
566     if ( has_toolhelp ) {
567         slow_gatherer_windows95 ( add, requester );
568     }
569     if ( is_windowsNT ) {
570         slow_gatherer_windowsNT ( add, requester );
571     }
572 
573     return 0;
574 }
575 
576 
577 
578 int
rndw32_gather_random_fast(void (* add)(const void *,size_t,int),int requester)579 rndw32_gather_random_fast( void (*add)(const void*, size_t, int), int requester )
580 {
581     static int addedFixedItems = 0;
582 
583     if ( debug_me )
584 	log_debug ("rndw32#gather_random_fast: req=%d\n", requester );
585 
586     /* Get various basic pieces of system information: Handle of active
587      * window, handle of window with mouse capture, handle of clipboard owner
588      * handle of start of clpboard viewer list, pseudohandle of current
589      * process, current process ID, pseudohandle of current thread, current
590      * thread ID, handle of desktop window, handle  of window with keyboard
591      * focus, whether system queue has any events, cursor position for last
592      * message, 1 ms time for last message, handle of window with clipboard
593      * open, handle of process heap, handle of procs window station, types of
594      * events in input queue, and milliseconds since Windows was started */
595     {	byte buffer[20*sizeof(ulong)], *bufptr;
596 	bufptr = buffer;
597 #define ADD(f)  do { ulong along = (ulong)(f);		      \
598 			   memcpy (bufptr, &along, sizeof (along) );  \
599 			   bufptr += sizeof (along); } while (0)
600 	ADD ( GetActiveWindow ());
601 	ADD ( GetCapture ());
602 	ADD ( GetClipboardOwner ());
603 	ADD ( GetClipboardViewer ());
604 	ADD ( GetCurrentProcess ());
605 	ADD ( GetCurrentProcessId ());
606 	ADD ( GetCurrentThread ());
607 	ADD ( GetCurrentThreadId ());
608 	ADD ( GetDesktopWindow ());
609 	ADD ( GetFocus ());
610 	ADD ( GetInputState ());
611 	ADD ( GetMessagePos ());
612 	ADD ( GetMessageTime ());
613 	ADD ( GetOpenClipboardWindow ());
614 	ADD ( GetProcessHeap ());
615 	ADD ( GetProcessWindowStation ());
616 	ADD ( GetQueueStatus (QS_ALLEVENTS));
617 	ADD ( GetTickCount ());
618 
619 	assert ( bufptr-buffer < sizeof (buffer) );
620 	(*add) ( buffer, bufptr-buffer, requester );
621 #undef ADD
622     }
623 
624     /* Get multiword system information: Current caret position, current
625      * mouse cursor position */
626     {	POINT point;
627 	GetCaretPos (&point);
628 	(*add) ( &point, sizeof (point), requester );
629 	GetCursorPos (&point);
630 	(*add) ( &point, sizeof (point), requester );
631     }
632 
633     /* Get percent of memory in use, bytes of physical memory, bytes of free
634      * physical memory, bytes in paging file, free bytes in paging file, user
635      * bytes of address space, and free user bytes */
636     {	MEMORYSTATUS memoryStatus;
637 	memoryStatus.dwLength = sizeof (MEMORYSTATUS);
638 	GlobalMemoryStatus (&memoryStatus);
639 	(*add) ( &memoryStatus, sizeof (memoryStatus), requester );
640     }
641 
642     /* Get thread and process creation time, exit time, time in kernel mode,
643        and time in user mode in 100ns intervals */
644     {	HANDLE handle;
645 	FILETIME creationTime, exitTime, kernelTime, userTime;
646 	DWORD minimumWorkingSetSize, maximumWorkingSetSize;
647 
648 	handle = GetCurrentThread ();
649 	GetThreadTimes (handle, &creationTime, &exitTime,
650 					       &kernelTime, &userTime);
651 	(*add) ( &creationTime, sizeof (creationTime), requester );
652 	(*add) ( &exitTime, sizeof (exitTime), requester );
653 	(*add) ( &kernelTime, sizeof (kernelTime), requester );
654 	(*add) ( &userTime, sizeof (userTime), requester );
655 
656 	handle = GetCurrentProcess ();
657 	GetProcessTimes (handle, &creationTime, &exitTime,
658 						&kernelTime, &userTime);
659 	(*add) ( &creationTime, sizeof (creationTime), requester );
660 	(*add) ( &exitTime, sizeof (exitTime), requester );
661 	(*add) ( &kernelTime, sizeof (kernelTime), requester );
662 	(*add) ( &userTime, sizeof (userTime), requester );
663 
664 	/* Get the minimum and maximum working set size for the
665            current process */
666 	GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,
667 					  &maximumWorkingSetSize);
668 	(*add) ( &minimumWorkingSetSize,
669 				   sizeof (minimumWorkingSetSize), requester );
670 	(*add) ( &maximumWorkingSetSize,
671 				   sizeof (maximumWorkingSetSize), requester );
672     }
673 
674 
675     /* The following are fixed for the lifetime of the process so we only
676      * add them once */
677     if (!addedFixedItems) {
678 	STARTUPINFO startupInfo;
679 
680 	/* Get name of desktop, console window title, new window position and
681 	 * size, window flags, and handles for stdin, stdout, and stderr */
682 	startupInfo.cb = sizeof (STARTUPINFO);
683 	GetStartupInfo (&startupInfo);
684 	(*add) ( &startupInfo, sizeof (STARTUPINFO), requester );
685 	addedFixedItems = 1;
686     }
687 
688     /* The performance of QPC varies depending on the architecture it's
689      * running on and on the OS.  Under NT it reads the CPU's 64-bit timestamp
690      * counter (at least on a Pentium and newer '486's, it hasn't been tested
691      * on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC
692      * timer.  There are vague mumblings in the docs that it may fail if the
693      * appropriate hardware isn't available (possibly '386's or MIPS machines
694      * running NT), but who's going to run NT on a '386? */
695     {	LARGE_INTEGER performanceCount;
696 	if (QueryPerformanceCounter (&performanceCount)) {
697 	    if ( debug_me )
698 		log_debug ("rndw32#gather_random_fast: perf data\n");
699 	    (*add) (&performanceCount, sizeof (performanceCount), requester);
700 	}
701 	else { /* Millisecond accuracy at best... */
702 	    DWORD aword = GetTickCount ();
703 	    (*add) (&aword, sizeof (aword), requester );
704 	}
705     }
706 
707     return 0;
708 }
709