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