/[winpt]/trunk/Gnupg/rndw32.c
ViewVC logotype

Diff of /trunk/Gnupg/rndw32.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 45 by twoaday, Mon Jan 31 11:02:21 2005 UTC revision 46 by werner, Fri Oct 28 12:57:05 2005 UTC
# Line 1  Line 1 
1  /* rndw32.c  -  W32 entropy gatherer  /* rndw32.c  -  W32 entropy gatherer
2   *      Copyright (C) 1999, 2000 Free Software Foundation, Inc.   *      Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3   *      Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-1999   *      Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-1999
4   *   *
5   * This file is part of Libgcrypt.   * This file is part of Libgcrypt.
6   *   *
7   * Libgcrypt is free software; you can redistribute it and/or modify   * Libgcrypt is free software; you can redistribute it and/or modify
8   * it under the terms of the GNU General Public License as published by   * 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   * the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.   * (at your option) any later version.
11   *   *
12   * Libgcrypt is distributed in the hope that it will be useful,   * Libgcrypt is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.   * GNU General Public License for more details.
16   *   *
17   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
18   * along with this program; if not, write to the Free Software   * along with this program; if not, write to the Free Software
19   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA   * 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.   * 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   * Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this
24   * copyright notice:   * copyright notice:
25   *   *
26   * This module is part of the cryptlib continuously seeded pseudorandom   * This module is part of the cryptlib continuously seeded pseudorandom
27   * number generator.  For usage conditions, see lib_rand.c   * 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]   * [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   * This module and the misc/rnd*.c modules represent the cryptlib
32   * continuously seeded pseudorandom number generator (CSPRNG) as described in   * continuously seeded pseudorandom number generator (CSPRNG) as described in
33   * my 1998 Usenix Security Symposium paper "The generation of random numbers   * my 1998 Usenix Security Symposium paper "The generation of random numbers
34   * for cryptographic purposes".   * for cryptographic purposes".
35   *   *
36   * The CSPRNG code is copyright Peter Gutmann (and various others) 1996,   * The CSPRNG code is copyright Peter Gutmann (and various others) 1996,
37   * 1997, 1998, 1999, all rights reserved.  Redistribution of the CSPRNG   * 1997, 1998, 1999, all rights reserved.  Redistribution of the CSPRNG
38   * modules and use in source and binary forms, with or without modification,   * modules and use in source and binary forms, with or without modification,
39   * are permitted provided that the following conditions are met:   * are permitted provided that the following conditions are met:
40   *   *
41   * 1. Redistributions of source code must retain the above copyright notice   * 1. Redistributions of source code must retain the above copyright notice
42   *    and this permission notice in its entirety.   *    and this permission notice in its entirety.
43   *   *
44   * 2. Redistributions in binary form must reproduce the copyright notice in   * 2. Redistributions in binary form must reproduce the copyright notice in
45   *    the documentation and/or other materials provided with the distribution.   *    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   * 3. A copy of any bugfixes or enhancements made must be provided to the
48   *    author, <[email protected]> to allow them to be added to the   *    author, <[email protected]> to allow them to be added to the
49   *    baseline version of the code.   *    baseline version of the code.
50   *   *
51   * ALTERNATIVELY, the code may be distributed under the terms of the GNU   * 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   * 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   * Free Software Foundation, in which case the provisions of the GNU GPL are
54   * required INSTEAD OF the above restrictions.   * required INSTEAD OF the above restrictions.
55   *   *
56   * Although not required under the terms of the GPL, it would still be nice if   * 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   * you could make any changes available to the author to allow a consistent
58   * code base to be maintained   * code base to be maintained
59   *************************************************************************   *************************************************************************
60   * Heavily modified by Timo Schulz to fit into WinPT, 2001.   * Heavily modified by Timo Schulz to fit into WinPT, 2001.
61   */   */
62    
63  #include <stdio.h>  #ifdef HAVE_CONFIG_H
64  #include <stdlib.h>  #include <config.h>
65  #include <assert.h>  #endif
66  #include <errno.h>  
67  #include <string.h>  #include <stdio.h>
68    #include <stdio.h>
69  #include <windows.h>  #include <stdlib.h>
70  #include <tlhelp32.h>  #include <assert.h>
71  #include <winioctl.h>  #include <errno.h>
72    #include <string.h>
73    
74  /* Type definitions for function pointers to call Toolhelp32 functions  #include <windows.h>
75   * used with the windows95 gatherer */  #include <tlhelp32.h>
76  typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme);  #include <winioctl.h>
77  typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte);  
78  typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe);  
79  typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl);  /* Type definitions for function pointers to call Toolhelp32 functions
80  typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID,   * used with the windows95 gatherer */
81                                     DWORD th32HeapID);  typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme);
82  typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe);  typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte);
83  typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID);  typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe);
84    typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl);
85  /* Type definitions for function pointers to call NetAPI32 functions */  typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID,
86  typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService,                                     DWORD th32HeapID);
87                                             DWORD dwLevel, DWORD dwOptions,  typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe);
88                                             LPBYTE * lpBuffer);  typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID);
89  typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer);  
90  typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer);  /* Type definitions for function pointers to call NetAPI32 functions */
91    typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService,
92                                               DWORD dwLevel, DWORD dwOptions,
93  /* When we query the performance counters, we allocate an initial buffer and                                             LPBYTE * lpBuffer);
94   * then reallocate it as required until RegQueryValueEx() stops returning  typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer);
95   * ERROR_MORE_DATA.  The following values define the initial buffer size and  typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer);
96   * step size by which the buffer is increased  
97   */  
98  #define PERFORMANCE_BUFFER_SIZE         65536   /* Start at 64K */  /* When we query the performance counters, we allocate an initial buffer and
99  #define PERFORMANCE_BUFFER_STEP         16384   /* Step by 16K */   * then reallocate it as required until RegQueryValueEx() stops returning
100     * ERROR_MORE_DATA.  The following values define the initial buffer size and
101     * step size by which the buffer is increased
102  static void   */
103  random_w32_err( const char *format, ... )  #define PERFORMANCE_BUFFER_SIZE         65536   /* Start at 64K */
104  {  #define PERFORMANCE_BUFFER_STEP         16384   /* Step by 16K */
105      char log[8192];  
106      va_list arg_ptr;  
107    static void
108      va_start( arg_ptr, format );          random_w32_err( const char *format, ... )
109      _vsnprintf( log, sizeof log-1, format, arg_ptr );  {
110      MessageBox( NULL, log, "Crypto RNG", MB_ICONERROR|MB_OK );      char log[8192];
111      va_end( arg_ptr );      va_list arg_ptr;
112  } /* log_box */  
113        va_start( arg_ptr, format );        
114        _vsnprintf( log, sizeof log-1, format, arg_ptr );
115  static void      MessageBox( NULL, log, "Crypto RNG", MB_ICONERROR|MB_OK );
116  slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester )      va_end( arg_ptr );
117  {  } /* log_box */
118      static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;  
119      static MODULEWALK pModule32First = NULL;  
120      static MODULEWALK pModule32Next = NULL;  static void
121      static PROCESSWALK pProcess32First = NULL;  slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester )
122      static PROCESSWALK pProcess32Next = NULL;  {
123      static THREADWALK pThread32First = NULL;      static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
124      static THREADWALK pThread32Next = NULL;      static MODULEWALK pModule32First = NULL;
125      static HEAPLISTWALK pHeap32ListFirst = NULL;      static MODULEWALK pModule32Next = NULL;
126      static HEAPLISTWALK pHeap32ListNext = NULL;      static PROCESSWALK pProcess32First = NULL;
127      static HEAPFIRST pHeap32First = NULL;      static PROCESSWALK pProcess32Next = NULL;
128      static HEAPNEXT pHeap32Next = NULL;      static THREADWALK pThread32First = NULL;
129      HANDLE hSnapshot;      static THREADWALK pThread32Next = NULL;
130            static HEAPLISTWALK pHeap32ListFirst = NULL;
131            static HEAPLISTWALK pHeap32ListNext = NULL;
132      /* initialize the Toolhelp32 function pointers */      static HEAPFIRST pHeap32First = NULL;
133      if ( !pCreateToolhelp32Snapshot ) {      static HEAPNEXT pHeap32Next = NULL;
134          HANDLE hKernel;      HANDLE hSnapshot;
135                
136          /* Obtain the module handle of the kernel to retrieve the addresses      
137           * of the Toolhelp32 functions */      /* initialize the Toolhelp32 function pointers */
138          if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) {      if ( !pCreateToolhelp32Snapshot ) {
139              random_w32_err( "rndw32: can't get module handle" );          HANDLE hKernel;
140              return;          
141          }          /* Obtain the module handle of the kernel to retrieve the addresses
142                     * of the Toolhelp32 functions */
143          /* Now get pointers to the functions */          if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) {
144          pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel,              random_w32_err( "rndw32: can't get module handle" );
145                                                                       "CreateToolhelp32Snapshot");              return;
146          pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First");          }
147          pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next");          
148          pProcess32First = (PROCESSWALK) GetProcAddress (hKernel,          /* Now get pointers to the functions */
149                                                          "Process32First");          pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel,
150          pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel,                                                                       "CreateToolhelp32Snapshot");
151                                                         "Process32Next");          pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First");
152          pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First");          pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next");
153          pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next");          pProcess32First = (PROCESSWALK) GetProcAddress (hKernel,
154          pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel,                                                          "Process32First");
155                                                            "Heap32ListFirst");          pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel,
156          pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel,                                                         "Process32Next");
157                                                           "Heap32ListNext");          pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First");
158          pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First");          pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next");
159          pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next");          pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel,
160                                                                      "Heap32ListFirst");
161          if (    !pCreateToolhelp32Snapshot          pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel,
162                  || !pModule32First || !pModule32Next                                                           "Heap32ListNext");
163                  || !pProcess32First || !pProcess32Next          pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First");
164                  || !pThread32First  || !pThread32Next          pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next");
165                  || !pHeap32ListFirst || !pHeap32ListNext          
166                  || !pHeap32First          || !pHeap32Next  ) {          if (    !pCreateToolhelp32Snapshot
167              random_w32_err( "rndw32: failed to get a toolhep function" );                  || !pModule32First || !pModule32Next
168              return;                  || !pProcess32First || !pProcess32Next
169          }                  || !pThread32First  || !pThread32Next
170      }                  || !pHeap32ListFirst || !pHeap32ListNext
171                        || !pHeap32First          || !pHeap32Next  ) {
172      /* Take a snapshot of everything we can get to which is currently              random_w32_err( "rndw32: failed to get a toolhep function" );
173       *  in the system */              return;
174      if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) {          }
175          random_w32_err( "rndw32: failed to take a toolhelp snapshot" );      }
176          return;      
177      }      /* Take a snapshot of everything we can get to which is currently
178             *  in the system */
179      /* Walk through the local heap */      if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) {
180      {   HEAPLIST32 hl32;          random_w32_err( "rndw32: failed to take a toolhelp snapshot" );
181      hl32.dwSize = sizeof (HEAPLIST32);          return;
182      if (pHeap32ListFirst (hSnapshot, &hl32)) {      }
183          do {      
184              HEAPENTRY32 he32;      /* Walk through the local heap */
185                    {   HEAPLIST32 hl32;
186              /* First add the information from the basic Heaplist32 struct */      hl32.dwSize = sizeof (HEAPLIST32);
187              (*add) ( &hl32, sizeof (hl32), requester );      if (pHeap32ListFirst (hSnapshot, &hl32)) {
188                        do {
189              /* Now walk through the heap blocks getting information              HEAPENTRY32 he32;
190               * on each of them */              
191              he32.dwSize = sizeof (HEAPENTRY32);              /* First add the information from the basic Heaplist32 struct */
192              if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){              (*add) ( &hl32, sizeof (hl32), requester );
193                  do {              
194                      (*add) ( &he32, sizeof (he32), requester );              /* Now walk through the heap blocks getting information
195                  } while (pHeap32Next (&he32));               * on each of them */
196              }              he32.dwSize = sizeof (HEAPENTRY32);
197          } while (pHeap32ListNext (hSnapshot, &hl32));              if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){
198      }                  do {
199      }                      (*add) ( &he32, sizeof (he32), requester );
200                        } while (pHeap32Next (&he32));
201                    }
202      /* Walk through all processes */          } while (pHeap32ListNext (hSnapshot, &hl32));
203      {   PROCESSENTRY32 pe32;      }
204      pe32.dwSize = sizeof (PROCESSENTRY32);      }
205      if (pProcess32First (hSnapshot, &pe32)) {      
206          do {      
207              (*add) ( &pe32, sizeof (pe32), requester );      /* Walk through all processes */
208          } while (pProcess32Next (hSnapshot, &pe32));      {   PROCESSENTRY32 pe32;
209      }      pe32.dwSize = sizeof (PROCESSENTRY32);
210      }      if (pProcess32First (hSnapshot, &pe32)) {
211                do {
212      /* Walk through all threads */              (*add) ( &pe32, sizeof (pe32), requester );
213      {   THREADENTRY32 te32;          } while (pProcess32Next (hSnapshot, &pe32));
214      te32.dwSize = sizeof (THREADENTRY32);      }
215      if (pThread32First (hSnapshot, &te32)) {              }
216          do {      
217              (*add) ( &te32, sizeof (te32), requester );      /* Walk through all threads */
218          } while (pThread32Next (hSnapshot, &te32));      {   THREADENTRY32 te32;
219      }      te32.dwSize = sizeof (THREADENTRY32);
220      }      if (pThread32First (hSnapshot, &te32)) {        
221                do {
222      /* Walk through all modules associated with the process */              (*add) ( &te32, sizeof (te32), requester );
223      {   MODULEENTRY32 me32;          } while (pThread32Next (hSnapshot, &te32));
224      me32.dwSize = sizeof (MODULEENTRY32);      }
225      if (pModule32First (hSnapshot, &me32)) {      }
226          do {      
227              (*add) ( &me32, sizeof (me32), requester );      /* Walk through all modules associated with the process */
228          } while (pModule32Next (hSnapshot, &me32));      {   MODULEENTRY32 me32;
229      }      me32.dwSize = sizeof (MODULEENTRY32);
230      }      if (pModule32First (hSnapshot, &me32)) {
231                do {
232      CloseHandle (hSnapshot);              (*add) ( &me32, sizeof (me32), requester );
233  }          } while (pModule32Next (hSnapshot, &me32));
234        }
235        }
236        
237        CloseHandle (hSnapshot);
238    }
239  static void  
240  slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester )  
241  {  
242      static int is_initialized = 0;  
243      static NETSTATISTICSGET pNetStatisticsGet = NULL;  
244      static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;  static void
245      static NETAPIBUFFERFREE pNetApiBufferFree = NULL;  slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester )
246      static int is_workstation = 1;  {
247      static int diskperf_warning = 0;      static int is_initialized = 0;
248            static NETSTATISTICSGET pNetStatisticsGet = NULL;
249      static int cbPerfData = PERFORMANCE_BUFFER_SIZE;      static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
250      PERF_DATA_BLOCK *pPerfData;      static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
251      HANDLE hDevice, hNetAPI32 = NULL;      static int is_workstation = 1;
252      DWORD dwSize, status;      static int diskperf_warning = 0;
253      int nDrive;      
254            static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
255      if ( !is_initialized ) {      PERF_DATA_BLOCK *pPerfData;
256          HKEY hKey;      HANDLE hDevice, hNetAPI32 = NULL;
257                DWORD dwSize, status;
258          /* Find out whether this is an NT server or workstation if necessary */      int nDrive;
259          if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,      
260                            "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",      if ( !is_initialized ) {
261                            0, KEY_READ, &hKey) == ERROR_SUCCESS) {          HKEY hKey;
262              BYTE szValue[32];          
263              dwSize = sizeof (szValue);          /* Find out whether this is an NT server or workstation if necessary */
264                        if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
265              status = RegQueryValueEx (hKey, "ProductType", 0, NULL,                            "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
266                                        szValue, &dwSize);                            0, KEY_READ, &hKey) == ERROR_SUCCESS) {
267              if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) {              BYTE szValue[32];
268                  /* Note: There are (at least) three cases for ProductType:              dwSize = sizeof (szValue);
269                   * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =              
270                   * NT Server acting as a Domain Controller */              status = RegQueryValueEx (hKey, "ProductType", 0, NULL,
271                  is_workstation = 0;                                                    szValue, &dwSize);
272              }              if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) {
273              RegCloseKey (hKey);                  /* Note: There are (at least) three cases for ProductType:
274          }                   * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
275                             * NT Server acting as a Domain Controller */
276          /* Initialize the NetAPI32 function pointers if necessary */                  is_workstation = 0;            
277          if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) {                      }
278              pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,              RegCloseKey (hKey);
279                                                                     "NetStatisticsGet");          }
280              pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,          
281                                                                     "NetApiBufferSize");          /* Initialize the NetAPI32 function pointers if necessary */
282              pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,          if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) {        
283                                                                     "NetApiBufferFree");              pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,
284                                                                                   "NetStatisticsGet");
285              if ( !pNetStatisticsGet              pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,
286                   || !pNetApiBufferSize || !pNetApiBufferFree ) {                                                                     "NetApiBufferSize");
287                  FreeLibrary (hNetAPI32);              pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,
288                  hNetAPI32 = NULL;                                                                     "NetApiBufferFree");
289              }              
290          }              if ( !pNetStatisticsGet
291                             || !pNetApiBufferSize || !pNetApiBufferFree ) {
292          is_initialized = 1;                  FreeLibrary (hNetAPI32);
293      }                  hNetAPI32 = NULL;
294                    }
295      /* Get network statistics.  Note: Both NT Workstation and NT Server by          }
296       * default will be running both the workstation and server services.  The          
297       * heuristic below is probably useful though on the assumption that the          is_initialized = 1;
298       * majority of the network traffic will be via the appropriate service.      }
299       * In any case the network statistics return almost no randomness */      
300      {   LPBYTE lpBuffer;      /* Get network statistics.  Note: Both NT Workstation and NT Server by
301      if (hNetAPI32 && !pNetStatisticsGet (NULL,       * default will be running both the workstation and server services.  The
302                                           is_workstation ? L"LanmanWorkstation" :       * heuristic below is probably useful though on the assumption that the
303                                           L"LanmanServer", 0, 0, &lpBuffer) ) {             * majority of the network traffic will be via the appropriate service.
304          pNetApiBufferSize (lpBuffer, &dwSize);       * In any case the network statistics return almost no randomness */
305          (*add) ( lpBuffer, dwSize,requester );      {   LPBYTE lpBuffer;
306          pNetApiBufferFree (lpBuffer);      if (hNetAPI32 && !pNetStatisticsGet (NULL,
307      }                                           is_workstation ? L"LanmanWorkstation" :
308      }                                           L"LanmanServer", 0, 0, &lpBuffer) ) {      
309                pNetApiBufferSize (lpBuffer, &dwSize);
310      /* Get disk I/O statistics for all the hard drives */          (*add) ( lpBuffer, dwSize,requester );
311      for (nDrive = 0;; nDrive++) {          pNetApiBufferFree (lpBuffer);
312          DISK_PERFORMANCE diskPerformance;      }
313          char szDevice[50];      }
314                
315          /* Check whether we can access this device */      /* Get disk I/O statistics for all the hard drives */
316          sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive);      for (nDrive = 0;; nDrive++) {
317          hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,          DISK_PERFORMANCE diskPerformance;
318                                NULL, OPEN_EXISTING, 0, NULL);          char szDevice[50];
319          if (hDevice == INVALID_HANDLE_VALUE)          
320              break;          /* Check whether we can access this device */
321                    sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive);
322          /* Note: This only works if you have turned on the disk performance          hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
323           * counters with 'diskperf -y'.  These counters are off by default */                                NULL, OPEN_EXISTING, 0, NULL);
324          if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,          if (hDevice == INVALID_HANDLE_VALUE)
325                               &diskPerformance, sizeof (DISK_PERFORMANCE),              break;
326                               &dwSize, NULL))          
327          {                    /* Note: This only works if you have turned on the disk performance
328              (*add) ( &diskPerformance, dwSize, requester );           * counters with 'diskperf -y'.  These counters are off by default */
329          }          if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
330          CloseHandle (hDevice);                               &diskPerformance, sizeof (DISK_PERFORMANCE),
331      }                                 &dwSize, NULL))
332                {          
333      /* Get information from the system performance counters.  This can take              (*add) ( &diskPerformance, dwSize, requester );
334       * a few seconds to do.  In some environments the call to          }
335       * RegQueryValueEx() can produce an access violation at some random time          CloseHandle (hDevice);
336       * in the future, adding a short delay after the following code block      }  
337       * makes the problem go away.  This problem is extremely difficult to      
338       * reproduce, I haven't been able to get it to occur despite running it      /* Get information from the system performance counters.  This can take
339       * on a number of machines.  The best explanation for the problem is that       * a few seconds to do.  In some environments the call to
340       * on the machine where it did occur, it was caused by an external driver       * RegQueryValueEx() can produce an access violation at some random time
341       * or other program which adds its own values under the       * in the future, adding a short delay after the following code block
342       * HKEY_PERFORMANCE_DATA key.  The NT kernel calls the required external       * makes the problem go away.  This problem is extremely difficult to
343       * modules to map in the data, if there's a synchronisation problem the       * reproduce, I haven't been able to get it to occur despite running it
344       * external module would write its data at an inappropriate moment,       * on a number of machines.  The best explanation for the problem is that
345       * causing the access violation.  A low-level memory checker indicated       * on the machine where it did occur, it was caused by an external driver
346       * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an       * or other program which adds its own values under the
347       * interminable number of calls down inside RegQueryValueEx(), was       * HKEY_PERFORMANCE_DATA key.  The NT kernel calls the required external
348       * overwriting memory (it wrote twice the allocated size of a buffer to a       * modules to map in the data, if there's a synchronisation problem the
349       * buffer allocated by the NT kernel).  This may be what's causing the       * external module would write its data at an inappropriate moment,
350       * problem, but since it's in the kernel there isn't much which can be       * causing the access violation.  A low-level memory checker indicated
351       * done.       * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an
352       *       * interminable number of calls down inside RegQueryValueEx(), was
353       * In addition to these problems the code in RegQueryValueEx() which       * overwriting memory (it wrote twice the allocated size of a buffer to a
354       * estimates the amount of memory required to return the performance       * buffer allocated by the NT kernel).  This may be what's causing the
355       * counter information isn't very accurate, since it always returns a       * problem, but since it's in the kernel there isn't much which can be
356       * worst-case estimate which is usually nowhere near the actual amount       * done.
357       * required.  For example it may report that 128K of memory is required,       *
358       * but only return 64K of data */       * In addition to these problems the code in RegQueryValueEx() which
359      {   pPerfData =  malloc (cbPerfData);       * estimates the amount of memory required to return the performance
360      for (;;) {       * counter information isn't very accurate, since it always returns a
361          dwSize = cbPerfData;               * worst-case estimate which is usually nowhere near the actual amount
362          status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,       * required.  For example it may report that 128K of memory is required,
363                                    NULL, (LPBYTE) pPerfData, &dwSize);       * but only return 64K of data */
364          if (status == ERROR_SUCCESS) {      {   pPerfData =  malloc (cbPerfData);
365              if (!memcmp (pPerfData->Signature, L"PERF", 8)) {      for (;;) {
366                  (*add) ( pPerfData, dwSize, requester );          dwSize = cbPerfData;        
367              }                    status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
368              break;                                    NULL, (LPBYTE) pPerfData, &dwSize);
369          }          if (status == ERROR_SUCCESS) {
370          else if (status == ERROR_MORE_DATA) {              if (!memcmp (pPerfData->Signature, L"PERF", 8)) {
371              cbPerfData += PERFORMANCE_BUFFER_STEP;                  (*add) ( pPerfData, dwSize, requester );
372              pPerfData = realloc (pPerfData, cbPerfData);              }          
373          }              break;
374          else {          }
375              random_w32_err ( "rndw32: get performance data problem");          else if (status == ERROR_MORE_DATA) {
376              break;              cbPerfData += PERFORMANCE_BUFFER_STEP;
377          }              pPerfData = realloc (pPerfData, cbPerfData);
378      }          }
379      free (pPerfData);          else {
380      }              random_w32_err ( "rndw32: get performance data problem");
381      /* Although this isn't documented in the Win32 API docs, it's necessary              break;
382         to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's          }
383         implicitly opened on the first call to RegQueryValueEx()).  If this      }
384         isn't done then any system components which provide performance data      free (pPerfData);
385         can't be removed or changed while the handle remains active */      }
386      RegCloseKey (HKEY_PERFORMANCE_DATA);      /* Although this isn't documented in the Win32 API docs, it's necessary
387  }         to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
388           implicitly opened on the first call to RegQueryValueEx()).  If this
389           isn't done then any system components which provide performance data
390  int         can't be removed or changed while the handle remains active */
391  gather_random( void (*add)(const void*, size_t, int), int requester,      RegCloseKey (HKEY_PERFORMANCE_DATA);
392                                            size_t length, int level )  }
393  {  
394      static int is_initialized;  
395      static int is_windows95;  int
396        gather_random( void (*add)(const void*, size_t, int), int requester,
397                                                  size_t length, int level )
398      if( !level )  {
399          return 0;      static int is_initialized;
400      /* We don't differentiate between level 1 and 2 here because      static int is_windows95;
401       * there is no nternal entropy pool as a scary resource.  It may      
402       * all work slower, but because our entropy source will never      
403       * block but deliver some not easy to measure entropy, we assume level 2      if( !level )
404       */          return 0;
405            /* We don't differentiate between level 1 and 2 here because
406             * there is no nternal entropy pool as a scary resource.  It may
407      if ( !is_initialized ) {       * all work slower, but because our entropy source will never
408          OSVERSIONINFO osvi = { sizeof( osvi ) };       * block but deliver some not easy to measure entropy, we assume level 2
409          DWORD platform;       */
410                
411          GetVersionEx( &osvi );      
412          platform = osvi.dwPlatformId;      if ( !is_initialized ) {
413          is_windows95 = platform == VER_PLATFORM_WIN32_WINDOWS;          OSVERSIONINFO osvi = { sizeof( osvi ) };
414                    DWORD platform;
415          if ( platform == VER_PLATFORM_WIN32s ) {          
416              random_w32_err("can't run on a W32s platform" );          GetVersionEx( &osvi );
417              return 0;          platform = osvi.dwPlatformId;
418          }          is_windows95 = platform == VER_PLATFORM_WIN32_WINDOWS;
419          is_initialized = 1;              
420      }              if ( platform == VER_PLATFORM_WIN32s ) {
421                    random_w32_err("can't run on a W32s platform" );
422      if (is_windows95 ) {              return 0;
423          slow_gatherer_windows95( add, requester );          }
424      }          is_initialized = 1;    
425      else {      }    
426          slow_gatherer_windowsNT( add, requester );      
427      }      if (is_windows95 ) {
428                slow_gatherer_windows95( add, requester );
429      return 0;      }
430  }      else {
431            slow_gatherer_windowsNT( add, requester );
432        }
433        
434  int      return 0;
435  gather_random_fast( void (*add)(const void*, size_t, int), int requester )  }
436  {  
437      static int addedFixedItems = 0;      
438    
439      /* Get various basic pieces of system information: Handle of active  int
440       * window, handle of window with mouse capture, handle of clipboard owner  gather_random_fast( void (*add)(const void*, size_t, int), int requester )
441       * handle of start of clpboard viewer list, pseudohandle of current  {
442       * process, current process ID, pseudohandle of current thread, current      static int addedFixedItems = 0;    
443       * thread ID, handle of desktop window, handle  of window with keyboard  
444       * focus, whether system queue has any events, cursor position for last      /* Get various basic pieces of system information: Handle of active
445       * message, 1 ms time for last message, handle of window with clipboard       * window, handle of window with mouse capture, handle of clipboard owner
446       * open, handle of process heap, handle of procs window station, types of       * handle of start of clpboard viewer list, pseudohandle of current
447       * events in input queue, and milliseconds since Windows was started */       * process, current process ID, pseudohandle of current thread, current
448      {   BYTE buffer[20*sizeof(DWORD)], *bufptr;       * thread ID, handle of desktop window, handle  of window with keyboard
449          bufptr = buffer;       * focus, whether system queue has any events, cursor position for last
450        #define ADD(f)  do { DWORD along = (DWORD)(f);                  \       * message, 1 ms time for last message, handle of window with clipboard
451                             memcpy (bufptr, &along, sizeof (along) );  \       * open, handle of process heap, handle of procs window station, types of
452                             bufptr += sizeof (along); } while (0)       * events in input queue, and milliseconds since Windows was started */
453          ADD ( GetActiveWindow ());      {   BYTE buffer[20*sizeof(DWORD)], *bufptr;
454          ADD ( GetCapture ());          bufptr = buffer;
455          ADD ( GetClipboardOwner ());        #define ADD(f)  do { DWORD along = (DWORD)(f);                  \
456          ADD ( GetClipboardViewer ());                             memcpy (bufptr, &along, sizeof (along) );  \
457          ADD ( GetCurrentProcess ());                             bufptr += sizeof (along); } while (0)
458          ADD ( GetCurrentProcessId ());          ADD ( GetActiveWindow ());
459          ADD ( GetCurrentThread ());          ADD ( GetCapture ());
460          ADD ( GetCurrentThreadId ());          ADD ( GetClipboardOwner ());
461          ADD ( GetDesktopWindow ());          ADD ( GetClipboardViewer ());
462          ADD ( GetFocus ());          ADD ( GetCurrentProcess ());
463          ADD ( GetInputState ());          ADD ( GetCurrentProcessId ());
464          ADD ( GetMessagePos ());          ADD ( GetCurrentThread ());
465          ADD ( GetMessageTime ());          ADD ( GetCurrentThreadId ());
466          ADD ( GetOpenClipboardWindow ());          ADD ( GetDesktopWindow ());
467          ADD ( GetProcessHeap ());          ADD ( GetFocus ());
468          ADD ( GetProcessWindowStation ());          ADD ( GetInputState ());
469          ADD ( GetQueueStatus (QS_ALLEVENTS));          ADD ( GetMessagePos ());
470          ADD ( GetTickCount ());          ADD ( GetMessageTime ());
471            ADD ( GetOpenClipboardWindow ());
472          assert ( bufptr-buffer < sizeof (buffer) );          ADD ( GetProcessHeap ());
473          (*add) ( buffer, bufptr-buffer, requester );          ADD ( GetProcessWindowStation ());
474        #undef ADD          ADD ( GetQueueStatus (QS_ALLEVENTS));
475      }          ADD ( GetTickCount ());
476    
477      /* Get multiword system information: Current caret position, current          assert ( bufptr-buffer < sizeof (buffer) );
478       * mouse cursor position */          (*add) ( buffer, bufptr-buffer, requester );
479      {   POINT point;        #undef ADD
480          GetCaretPos (&point);      }
481          (*add) ( &point, sizeof (point), requester );  
482          GetCursorPos (&point);      /* Get multiword system information: Current caret position, current
483          (*add) ( &point, sizeof (point), requester );       * mouse cursor position */
484      }      {   POINT point;
485            GetCaretPos (&point);
486      /* Get percent of memory in use, bytes of physical memory, bytes of free          (*add) ( &point, sizeof (point), requester );
487       * physical memory, bytes in paging file, free bytes in paging file, user          GetCursorPos (&point);
488       * bytes of address space, and free user bytes */          (*add) ( &point, sizeof (point), requester );
489      {   MEMORYSTATUS memoryStatus;      }
490          memoryStatus.dwLength = sizeof (MEMORYSTATUS);  
491          GlobalMemoryStatus (&memoryStatus);      /* Get percent of memory in use, bytes of physical memory, bytes of free
492          (*add) ( &memoryStatus, sizeof (memoryStatus), requester );       * physical memory, bytes in paging file, free bytes in paging file, user
493      }       * bytes of address space, and free user bytes */
494        {   MEMORYSTATUS memoryStatus;
495      /* Get thread and process creation time, exit time, time in kernel mode,          memoryStatus.dwLength = sizeof (MEMORYSTATUS);
496         and time in user mode in 100ns intervals */          GlobalMemoryStatus (&memoryStatus);
497      {   HANDLE handle;          (*add) ( &memoryStatus, sizeof (memoryStatus), requester );
498          FILETIME creationTime, exitTime, kernelTime, userTime;      }
499          DWORD minimumWorkingSetSize, maximumWorkingSetSize;  
500        /* Get thread and process creation time, exit time, time in kernel mode,
501          handle = GetCurrentThread ();         and time in user mode in 100ns intervals */
502          GetThreadTimes (handle, &creationTime, &exitTime,      {   HANDLE handle;
503                                                 &kernelTime, &userTime);          FILETIME creationTime, exitTime, kernelTime, userTime;
504          (*add) ( &creationTime, sizeof (creationTime), requester );          DWORD minimumWorkingSetSize, maximumWorkingSetSize;
505          (*add) ( &exitTime, sizeof (exitTime), requester );  
506          (*add) ( &kernelTime, sizeof (kernelTime), requester );          handle = GetCurrentThread ();
507          (*add) ( &userTime, sizeof (userTime), requester );          GetThreadTimes (handle, &creationTime, &exitTime,
508                                                   &kernelTime, &userTime);
509          handle = GetCurrentProcess ();          (*add) ( &creationTime, sizeof (creationTime), requester );
510          GetProcessTimes (handle, &creationTime, &exitTime,          (*add) ( &exitTime, sizeof (exitTime), requester );
511                                                  &kernelTime, &userTime);          (*add) ( &kernelTime, sizeof (kernelTime), requester );
512          (*add) ( &creationTime, sizeof (creationTime), requester );          (*add) ( &userTime, sizeof (userTime), requester );
513          (*add) ( &exitTime, sizeof (exitTime), requester );  
514          (*add) ( &kernelTime, sizeof (kernelTime), requester );          handle = GetCurrentProcess ();
515          (*add) ( &userTime, sizeof (userTime), requester );          GetProcessTimes (handle, &creationTime, &exitTime,
516                                                    &kernelTime, &userTime);
517          /* Get the minimum and maximum working set size for the current process */          (*add) ( &creationTime, sizeof (creationTime), requester );
518          GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,          (*add) ( &exitTime, sizeof (exitTime), requester );
519                                            &maximumWorkingSetSize);          (*add) ( &kernelTime, sizeof (kernelTime), requester );
520          (*add) ( &minimumWorkingSetSize,          (*add) ( &userTime, sizeof (userTime), requester );
521                                     sizeof (&minimumWorkingSetSize), requester );  
522          (*add) ( &maximumWorkingSetSize,          /* Get the minimum and maximum working set size for the current process */
523                                     sizeof (&maximumWorkingSetSize), requester );          GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,
524      }                                            &maximumWorkingSetSize);
525            (*add) ( &minimumWorkingSetSize,
526                                       sizeof (&minimumWorkingSetSize), requester );
527      /* The following are fixed for the lifetime of the process so we only          (*add) ( &maximumWorkingSetSize,
528       * add them once */                                     sizeof (&maximumWorkingSetSize), requester );
529      if (!addedFixedItems) {      }
530          STARTUPINFO startupInfo;  
531    
532          /* Get name of desktop, console window title, new window position and      /* The following are fixed for the lifetime of the process so we only
533           * size, window flags, and handles for stdin, stdout, and stderr */       * add them once */
534          startupInfo.cb = sizeof (STARTUPINFO);      if (!addedFixedItems) {
535          GetStartupInfo (&startupInfo);          STARTUPINFO startupInfo;
536          (*add) ( &startupInfo, sizeof (STARTUPINFO), requester );  
537          addedFixedItems = 1;          /* Get name of desktop, console window title, new window position and
538      }           * size, window flags, and handles for stdin, stdout, and stderr */
539            startupInfo.cb = sizeof (STARTUPINFO);
540      /* The performance of QPC varies depending on the architecture it's          GetStartupInfo (&startupInfo);
541       * running on and on the OS.  Under NT it reads the CPU's 64-bit timestamp          (*add) ( &startupInfo, sizeof (STARTUPINFO), requester );
542       * counter (at least on a Pentium and newer '486's, it hasn't been tested          addedFixedItems = 1;
543       * on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC      }
544       * timer.  There are vague mumblings in the docs that it may fail if the  
545       * appropriate hardware isn't available (possibly '386's or MIPS machines      /* The performance of QPC varies depending on the architecture it's
546       * running NT), but who's going to run NT on a '386? */       * running on and on the OS.  Under NT it reads the CPU's 64-bit timestamp
547      {   LARGE_INTEGER performanceCount;       * counter (at least on a Pentium and newer '486's, it hasn't been tested
548          if (QueryPerformanceCounter (&performanceCount)) {                 * on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC
549              (*add) (&performanceCount, sizeof (&performanceCount), requester);       * timer.  There are vague mumblings in the docs that it may fail if the
550          }       * appropriate hardware isn't available (possibly '386's or MIPS machines
551          else { /* Millisecond accuracy at best... */       * running NT), but who's going to run NT on a '386? */
552              DWORD aword = GetTickCount ();      {   LARGE_INTEGER performanceCount;
553              (*add) (&aword, sizeof (aword), requester );          if (QueryPerformanceCounter (&performanceCount)) {          
554          }              (*add) (&performanceCount, sizeof (&performanceCount), requester);
555      }          }
556            else { /* Millisecond accuracy at best... */
557      return 0;              DWORD aword = GetTickCount ();
558  }              (*add) (&aword, sizeof (aword), requester );
559            }
560        }
561    
562        return 0;
563    }

Legend:
Removed from v.45  
changed lines
  Added in v.46

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26