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