Switched to GPLv3.
[gnupg.git] / cipher / rndw32.c
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
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
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     {   pPerfData =  xmalloc (cbPerfData);
481         for (;;) {
482             dwSize = cbPerfData;
483             if ( debug_me )
484                 log_debug ("rndw32#slow_gatherer_nt: get perf data\n" );
485             status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
486                                       NULL, (LPBYTE) pPerfData, &dwSize);
487             if (status == ERROR_SUCCESS) {
488                 if (!memcmp (pPerfData->Signature, L"PERF", 8)) {
489                     (*add) ( pPerfData, dwSize, requester );
490                 }
491                 else
492                     g10_log_debug ( "rndw32: no PERF signature\n");
493                 break;
494             }
495             else if (status == ERROR_MORE_DATA) {
496                 cbPerfData += PERFORMANCE_BUFFER_STEP;
497                 pPerfData = xrealloc (pPerfData, cbPerfData);
498             }
499             else {
500                 g10_log_debug ( "rndw32: get performance data problem\n");
501                 break;
502             }
503         }
504         xfree (pPerfData);
505     }
506     /* Although this isn't documented in the Win32 API docs, it's necessary
507        to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
508        implicitly opened on the first call to RegQueryValueEx()).  If this
509        isn't done then any system components which provide performance data
510        can't be removed or changed while the handle remains active */
511     RegCloseKey (HKEY_PERFORMANCE_DATA);
512 }
513
514
515 int
516 rndw32_gather_random (void (*add)(const void*, size_t, int), int requester,
517                       size_t length, int level )
518 {
519     static int is_initialized;
520     static int is_windowsNT, has_toolhelp;
521
522
523     if( !level )
524         return 0;
525     /* We don't differentiate between level 1 and 2 here because
526      * there is no nternal entropy pool as a scary resource.  It may
527      * all work slower, but because our entropy source will never
528      * block but deliver some not easy to measure entropy, we assume level 2
529      */
530
531
532     if ( !is_initialized ) {
533         OSVERSIONINFO osvi = { sizeof( osvi ) };
534         DWORD platform;
535
536         GetVersionEx( &osvi );
537         platform = osvi.dwPlatformId;
538         is_windowsNT = platform == VER_PLATFORM_WIN32_NT;
539         has_toolhelp = (platform == VER_PLATFORM_WIN32_WINDOWS
540                         || (is_windowsNT && osvi.dwMajorVersion >= 5));
541
542         if ( platform == VER_PLATFORM_WIN32s ) {
543             g10_log_fatal("can't run on a W32s platform\n" );
544         }
545         is_initialized = 1;
546         if ( debug_me )
547             log_debug ("rndw32#gather_random: platform=%d\n", (int)platform );
548     }
549
550
551     if ( debug_me )
552         log_debug ("rndw32#gather_random: req=%d len=%u lvl=%d\n",
553                            requester, (unsigned int)length, level );
554
555     if ( has_toolhelp ) {
556         slow_gatherer_windows95 ( add, requester );
557     }
558     if ( is_windowsNT ) {
559         slow_gatherer_windowsNT ( add, requester );
560     }
561
562     return 0;
563 }
564
565
566
567 int
568 rndw32_gather_random_fast( void (*add)(const void*, size_t, int), int requester )
569 {
570     static int addedFixedItems = 0;
571
572     if ( debug_me )
573         log_debug ("rndw32#gather_random_fast: req=%d\n", requester );
574
575     /* Get various basic pieces of system information: Handle of active
576      * window, handle of window with mouse capture, handle of clipboard owner
577      * handle of start of clpboard viewer list, pseudohandle of current
578      * process, current process ID, pseudohandle of current thread, current
579      * thread ID, handle of desktop window, handle  of window with keyboard
580      * focus, whether system queue has any events, cursor position for last
581      * message, 1 ms time for last message, handle of window with clipboard
582      * open, handle of process heap, handle of procs window station, types of
583      * events in input queue, and milliseconds since Windows was started */
584     {   byte buffer[20*sizeof(ulong)], *bufptr;
585         bufptr = buffer;
586 #define ADD(f)  do { ulong along = (ulong)(f);                \
587                            memcpy (bufptr, &along, sizeof (along) );  \
588                            bufptr += sizeof (along); } while (0)
589         ADD ( GetActiveWindow ());
590         ADD ( GetCapture ());
591         ADD ( GetClipboardOwner ());
592         ADD ( GetClipboardViewer ());
593         ADD ( GetCurrentProcess ());
594         ADD ( GetCurrentProcessId ());
595         ADD ( GetCurrentThread ());
596         ADD ( GetCurrentThreadId ());
597         ADD ( GetDesktopWindow ());
598         ADD ( GetFocus ());
599         ADD ( GetInputState ());
600         ADD ( GetMessagePos ());
601         ADD ( GetMessageTime ());
602         ADD ( GetOpenClipboardWindow ());
603         ADD ( GetProcessHeap ());
604         ADD ( GetProcessWindowStation ());
605         ADD ( GetQueueStatus (QS_ALLEVENTS));
606         ADD ( GetTickCount ());
607
608         assert ( bufptr-buffer < sizeof (buffer) );
609         (*add) ( buffer, bufptr-buffer, requester );
610 #undef ADD
611     }
612
613     /* Get multiword system information: Current caret position, current
614      * mouse cursor position */
615     {   POINT point;
616         GetCaretPos (&point);
617         (*add) ( &point, sizeof (point), requester );
618         GetCursorPos (&point);
619         (*add) ( &point, sizeof (point), requester );
620     }
621
622     /* Get percent of memory in use, bytes of physical memory, bytes of free
623      * physical memory, bytes in paging file, free bytes in paging file, user
624      * bytes of address space, and free user bytes */
625     {   MEMORYSTATUS memoryStatus;
626         memoryStatus.dwLength = sizeof (MEMORYSTATUS);
627         GlobalMemoryStatus (&memoryStatus);
628         (*add) ( &memoryStatus, sizeof (memoryStatus), requester );
629     }
630
631     /* Get thread and process creation time, exit time, time in kernel mode,
632        and time in user mode in 100ns intervals */
633     {   HANDLE handle;
634         FILETIME creationTime, exitTime, kernelTime, userTime;
635         DWORD minimumWorkingSetSize, maximumWorkingSetSize;
636
637         handle = GetCurrentThread ();
638         GetThreadTimes (handle, &creationTime, &exitTime,
639                                                &kernelTime, &userTime);
640         (*add) ( &creationTime, sizeof (creationTime), requester );
641         (*add) ( &exitTime, sizeof (exitTime), requester );
642         (*add) ( &kernelTime, sizeof (kernelTime), requester );
643         (*add) ( &userTime, sizeof (userTime), requester );
644
645         handle = GetCurrentProcess ();
646         GetProcessTimes (handle, &creationTime, &exitTime,
647                                                 &kernelTime, &userTime);
648         (*add) ( &creationTime, sizeof (creationTime), requester );
649         (*add) ( &exitTime, sizeof (exitTime), requester );
650         (*add) ( &kernelTime, sizeof (kernelTime), requester );
651         (*add) ( &userTime, sizeof (userTime), requester );
652
653         /* Get the minimum and maximum working set size for the
654            current process */
655         GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,
656                                           &maximumWorkingSetSize);
657         (*add) ( &minimumWorkingSetSize,
658                                    sizeof (minimumWorkingSetSize), requester );
659         (*add) ( &maximumWorkingSetSize,
660                                    sizeof (maximumWorkingSetSize), requester );
661     }
662
663
664     /* The following are fixed for the lifetime of the process so we only
665      * add them once */
666     if (!addedFixedItems) {
667         STARTUPINFO startupInfo;
668
669         /* Get name of desktop, console window title, new window position and
670          * size, window flags, and handles for stdin, stdout, and stderr */
671         startupInfo.cb = sizeof (STARTUPINFO);
672         GetStartupInfo (&startupInfo);
673         (*add) ( &startupInfo, sizeof (STARTUPINFO), requester );
674         addedFixedItems = 1;
675     }
676
677     /* The performance of QPC varies depending on the architecture it's
678      * running on and on the OS.  Under NT it reads the CPU's 64-bit timestamp
679      * counter (at least on a Pentium and newer '486's, it hasn't been tested
680      * on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC
681      * timer.  There are vague mumblings in the docs that it may fail if the
682      * appropriate hardware isn't available (possibly '386's or MIPS machines
683      * running NT), but who's going to run NT on a '386? */
684     {   LARGE_INTEGER performanceCount;
685         if (QueryPerformanceCounter (&performanceCount)) {
686             if ( debug_me )
687                 log_debug ("rndw32#gather_random_fast: perf data\n");
688             (*add) (&performanceCount, sizeof (performanceCount), requester);
689         }
690         else { /* Millisecond accuracy at best... */
691             DWORD aword = GetTickCount ();
692             (*add) (&aword, sizeof (aword), requester );
693         }
694     }
695
696     return 0;
697 }