~ubuntu-branches/ubuntu/precise/gnupg2/precise-proposed

« back to all changes in this revision

Viewing changes to cipher/rndw32.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Urlichs
  • Date: 2006-01-24 04:31:42 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060124043142-pbg192or6qxv3yk2
Tags: 1.9.20-1
* New Upstream version. Closes:#306890,#344530
  * Closes:#320490: gpg-protect-tool fails to decrypt PKCS-12 files 
* Depend on libopensc2-dev, not -1-. Closes:#348106

Show diffs side-by-side

added added

removed removed

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