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