/[winpt]/trunk/PTD/wptWipeFile.cpp
ViewVC logotype

Diff of /trunk/PTD/wptWipeFile.cpp

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

revision 5 by twoaday, Mon Mar 7 13:21:36 2005 UTC revision 55 by twoaday, Wed Nov 2 09:31:16 2005 UTC
# Line 1  Line 1 
1  /* wptWipeFile.cpp - Secure file removal  /* wptWipeFile.cpp - Secure file removal
2   *      Copyright (C) 2001-2005 Timo Schulz   *      Copyright (C) 2001-2005 Timo Schulz
3   *      Copyright (C) 2000 Matt Gauthier   *      Copyright (C) 2000 Matt Gauthier
4   *   *
5   * WinPT software; you can redistribute it and/or modify   * WinPT software; you can redistribute it and/or modify
6   * 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
7   * the Free Software Foundation; either version 2 of the License, or   * the Free Software Foundation; either version 2 of the License, or
8   * (at your option) any later version.   * (at your option) any later version.
9   *   *
10   * WinPT is distributed in the hope that it will be useful,   * WinPT is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.   * GNU General Public License for more details.
14   *   *
15   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
16   * along with WinPT; if not, write to the Free Software   * along with WinPT; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18   *   *
19   **************************************************************************   **************************************************************************
20   * This code based on the sunlink.c file from the SRM project, but        *   * This code based on the sunlink.c file from the SRM project, but        *
21   * it was heavily modified to work with W32 and with added GCRYPT         *   * it was heavily modified to work with W32 and with added GCRYPT         *
22   * support for gathering random bytes.                                    *   * support for gathering random bytes.                                    *
23   *                                                                        *   *                                                                        *
24   * The original code was placed under the GNU Lesser Public License,      *   * The original code was placed under the GNU Lesser Public License,      *
25   * even so I decide to put this file under the GNU General Public License.*   * even so I decide to put this file under the GNU General Public License.*
26   **************************************************************************   **************************************************************************
27   */   */
28    
29  #include <windows.h>  #ifdef HAVE_CONFIG_H
30  #include <stdio.h>  #include <config.h>
31  #include <stdlib.h>  #endif
32  #include <sys/stat.h>  
33  #include <string.h>  #include <windows.h>
34  #include <ctype.h>  #include <stdio.h>
35  #include <direct.h>  #include <stdlib.h>
36    #include <sys/stat.h>
37  #include "openpgp.h"  #include <string.h>
38  #include "wptW32API.h"  #include <ctype.h>
39  #include "wptErrors.h"  #include <direct.h>
40  #include "wptTypes.h"  
41    #include "openpgp.h"
42    #include "wptW32API.h"
43  typedef unsigned __int64 DDWORD;  #include "wptErrors.h"
44    #include "wptTypes.h"
45  typedef struct {  #include "wptCrypto.h"
46      HANDLE fd;  
47      DDWORD filesize;  #ifdef _MSC_VER
48      DDWORD offset;  typedef unsigned __int64 DDWORD;
49      BYTE  *buffer;  #else
50      DWORD  buffsize;  typedef unsigned long long DDWORD;
51      const char *name;  #endif
52      int    n_passes;  
53  } wipe_context_s;  typedef struct {
54        HANDLE fd;
55        DDWORD filesize;
56  void (*progress_cb) (void *, DDWORD, DDWORD);      DDWORD offset;
57  static void *progress_cb_value = NULL;      BYTE  *buffer;
58        DWORD  buffsize;
59  void (*unlink_cb)(void *, const char *, int, unsigned, unsigned) = NULL;      const char *name;
60  static void *unlink_cb_value = NULL;      int    n_passes;
61    } wipe_context_s;
62  static void  
63  overwrite (wipe_context_s * ctx)  struct arcfour_s {
64  {      BYTE *seed;
65      DDWORD blocks = 0, mod = 0;      int  pos;
66      DWORD nwritten = 0;      BYTE sbox[256];
67      LONG size_high = 0;      DWORD i;
68        DWORD j;
69      blocks = ctx->filesize / ctx->buffsize;  };
70      mod = ctx->filesize % ctx->buffsize;  
71      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);  
72      while (blocks--) {  void (*progress_cb) (void *, DDWORD, DDWORD);
73          if (!WriteFile (ctx->fd, ctx->buffer, ctx->buffsize, &nwritten, NULL))  static void *progress_cb_value = NULL;
74              break;  
75          ctx->offset += nwritten;  void (*unlink_cb)(void *, const char *, int, int, int) = NULL;
76          if (unlink_cb)  static void *unlink_cb_value = NULL;
77              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,  
78                         (unsigned)ctx->filesize*ctx->n_passes);  static int init_done = 0;
79      }  static struct arcfour_s rnd;
80      if (mod) {  
81          WriteFile (ctx->fd, ctx->buffer, (DWORD)mod, &nwritten, NULL);  
82          ctx->offset += nwritten;  /* Add the random from buffer @buf with the length @buf_len
83          if (unlink_cb)     into the seed @seed. The seed length (256) used to
84              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,     emulate a circular movment. */
85                         (unsigned)ctx->filesize*ctx->n_passes);  static void
86      }  add_random (unsigned char *seed, int *seed_pos,
87      FlushFileBuffers (ctx->fd);              unsigned char *buf, int buf_len)
88      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);  {
89  } /* overwrite */      int i, s_pos = *seed_pos;
90    
91        for (i=0; i < buf_len; i++)
92  static void          seed[(s_pos++ % 256)] ^= buf[i];
93  randomize_buffer (byte * buf, size_t bufsize, int level)      *seed_pos = s_pos % 256;
94  {  }
95      const int blocksize = 512;  
96      int blocks = bufsize / blocksize;  
97      int mod = bufsize % blocksize;  /* Enumerate all child windows. Store their text, their thread ID,
98           their placement and their dimension. */
99      while (blocks--) {  static BOOL CALLBACK
100          gpg_randomize (buf, blocksize, level);  child_proc (HWND h, LPARAM l)
101          buf += blocksize;  {
102      }      struct arcfour_s *cb =  (struct arcfour_s*)l;
103      if (mod)      DWORD a = (DWORD)h;
104          gpg_randomize (buf, mod, level);      WINDOWPLACEMENT p;
105  } /* randomize_buffer */      RECT r;
106        char buf[256];
107        int n;
108  static void  
109  overwrite_random (int npasses, wipe_context_s * ctx)      n  = GetWindowText (h, buf, 255);
110  {            if (n > 0)
111      int i;          add_random (cb->seed, &cb->pos, (BYTE*)buf, n);
112            add_random (cb->seed, &cb->pos, (BYTE*)&a, 4);
113      for (i = 0; i < npasses; i++) {      a = GetWindowThreadProcessId (h, NULL);
114          randomize_buffer (ctx->buffer, ctx->buffsize, 0);      add_random (cb->seed, &cb->pos, (BYTE*)&a, 4);
115          overwrite (ctx);      GetWindowPlacement (h, &p);
116      }      add_random (cb->seed, &cb->pos, (BYTE*)&p, sizeof (p));
117  } /* overwrite_random */      GetWindowRect (h, &r);
118        add_random (cb->seed, &cb->pos, (BYTE*)&r, sizeof (r));
119        return TRUE;
120  static void  }
121  overwrite_byte (int byte, wipe_context_s * ctx)  
122  {  
123      memset (ctx->buffer, byte, ctx->buffsize);  /* Initialize the seed with all kind of system variables. */
124      overwrite (ctx);  static void
125  } /* overwrite_byte */  init_random (unsigned char *seed)
126    {
127        int pos=0;
128  static void      DWORD buf[16];
129  overwrite_bytes (int byte1, int byte2, int byte3, wipe_context_s * ctx)      int i=0;
130  {  
131      DWORD i;      buf[i++] = (DWORD)GetActiveWindow ();
132        buf[i++] = (DWORD)GetCapture ();
133      memset (ctx->buffer, byte1, ctx->buffsize);      buf[i++] = (DWORD)GetClipboardOwner ();
134      for (i = 1; i < ctx->buffsize; i += 3) {      buf[i++] = (DWORD)GetClipboardViewer ();
135          ctx->buffer[i] = byte2;      buf[i++] = (DWORD)GetCurrentProcess ();      
136          ctx->buffer[i+1] = byte3;      buf[i++] = (DWORD)GetCurrentProcessId ();
137      }      buf[i++] = (DWORD)GetCurrentThread ();
138      overwrite (ctx);      buf[i++] = (DWORD)GetDesktopWindow ();
139  } /* overwrite_bytes */      buf[i++] = (DWORD)GetFocus ();
140        buf[i++] = (DWORD)GetMessagePos ();
141        buf[i++] = (DWORD)GetOpenClipboardWindow ();
142  /**      buf[i++] = (DWORD)GetProcessHeap ();
143   * For the case the file is not a regular file (this is true for      buf[i++] = (DWORD)GetProcessWindowStation ();
144   * devices or directories) this function tries to rename the file      buf[i++] = (DWORD)GetQueueStatus (QS_ALLEVENTS);
145   * to random pattern and then it will be delete (without random!).      buf[i] = (DWORD)GetTickCount ();
146   **/      add_random (seed, &pos, (BYTE*)buf, 4*i);
147  int  
148  rename_unlink (const char * path)      {
149  {          POINT p;
150      struct stat statbuf;          GetCursorPos (&p);
151      char * new_name = NULL, * p = NULL, c;            add_random (seed, &pos, (BYTE*)&p, sizeof (p));
152      int i = 0, rc = 0;          GetCaretPos (&p);
153      int is_dir = 0;          add_random (seed, &pos, (BYTE*)&p, sizeof (p));
154        }
155      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)  
156          is_dir = 1;      {
157                STARTUPINFO inf;
158      new_name = new char[strlen (path)+15];          inf.cb = sizeof (inf);
159      if (!new_name)          GetStartupInfo (&inf);
160          BUG (0);          add_random (seed, &pos, (BYTE*)&inf, sizeof (inf));
161            }
162      strcpy (new_name, path);  
163      p = strrchr (new_name, '\\');      {
164      if (p != NULL) {          MEMORYSTATUS st;
165          p++;          
166          *p = '\0';          st.dwLength = sizeof (st);
167      }          GlobalMemoryStatus (&st);
168      else          add_random (seed, &pos, (BYTE*)&st, sizeof (st));
169          p = new_name;      }
170      do {  
171          while (i < 14) {      {
172              c = gpg_random_char (1);          LARGE_INTEGER in;
173              *p = c;  
174              p++;          QueryPerformanceFrequency (&in);
175              i++;          add_random (seed, &pos, (BYTE*)&in, sizeof (in));
176          }          QueryPerformanceCounter (&in);
177          *p = '\0';          add_random (seed, &pos, (BYTE*)&in, sizeof (in));
178      } while (stat (new_name, &statbuf) == 0);      }
179            {
180      if (rename (path, new_name) == -1) {          rnd.seed = seed;
181          rc = WPTERR_FILE_READ;          rnd.pos = pos;
182          goto leave;          EnumChildWindows (GetDesktopWindow (), child_proc, (LPARAM)&rnd);
183      }      }
184      if (is_dir && RemoveDirectory (new_name) == FALSE)  
185          rc = WPTERR_FILE_REMOVE;  }
186      else if (!DeleteFile (new_name))  
187          rc = WPTERR_FILE_REMOVE;  
188        /* Initialize cipher with the seed as the key. */
189  leave:  static void
190      free_if_alloc (new_name);  init_arcfour (struct arcfour_s *ctx, BYTE *key)
191      return rc;  {
192  } /* rename_unlink */      BYTE t;
193    
194        ctx->i = 0;
195  static __int64      ctx->j = 0;
196  GetFileSize64 (const char * path)      for (ctx->i=0; ctx->i < 256; ctx->i++)
197  {          ctx->sbox[ctx->i] = (BYTE)ctx->i;
198      FILE *fp = fopen (path, "r");      for (ctx->i=0; ctx->i < 256; ctx->i++) {
199      if (fp) {          ctx->j += (ctx->j+ctx->sbox[ctx->i]+key[ctx->i]);
200          struct _stati64 statbuf;          ctx->j &= 255;
201          _fstati64 (fileno (fp), &statbuf);          t = ctx->sbox[ctx->i];
202          fclose (fp);          ctx->sbox[ctx->i] = ctx->sbox[ctx->j];
203          return statbuf.st_size;          ctx->sbox[ctx->j] = t;
204      }      }
205      return -1;  }
206  } /* GetFileSize64 */  
207    
208    /* Generate a single random byte. If the cipher is not
209  static int     init, do an init first. */
210  _secure_unlink (const char * path, int mode, HANDLE *r_fd)  static BYTE
211  {  rnd_byte (void)
212      wipe_context_s ctx;  {
213      LONG size_high = 0;      struct arcfour_s *ctx = &rnd;
214            BYTE t;
215      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)  
216          return rename_unlink (path);      if (!init_done) {
217                BYTE buf[256];
218      memset (&ctx, 0, sizeof (ctx));          init_random (buf);
219      ctx.name = path;          init_arcfour (ctx, buf);
220      ctx.buffsize = 16384;          init_done = 1;
221      ctx.buffer = new byte[ctx.buffsize];      }
222      if (!ctx.buffer)  
223          BUG (0);      ctx->i++; ctx->i &= 255;
224            ctx->j += ctx->sbox[ctx->i]; ctx->j &= 255;
225      ctx.filesize = GetFileSize64 (path);      t = ctx->sbox[ctx->i];
226      if (!ctx.filesize) {      ctx->sbox[ctx->i] = ctx->sbox[ctx->j];
227          free_if_alloc (ctx.buffer);      ctx->sbox[ctx->j] = t;
228          unlink (path);      return ctx->sbox[(ctx->sbox[ctx->i] + ctx->sbox[ctx->j]) & 255];
229          return 0;  }
230      }  
231    
232      ctx.fd = CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,  /* Generate a single alpha-num charactor. */
233                           OPEN_ALWAYS, 0, NULL);  static char
234      if (ctx.fd == INVALID_HANDLE_VALUE) {  random_char (void)
235          free_if_alloc (ctx.buffer);  {      
236          return WPTERR_FILE_OPEN;      byte c = 0;
237      }  
238      else if (r_fd)      while  (!isalnum(c))
239          *r_fd = ctx.fd;          c = rnd_byte ();
240            return c % 127;
241      gpg_quick_random_gen (1);  }
242      if (unlink_cb)  
243          unlink_cb (unlink_cb_value, ctx.name, 0, 0, 0);  
244    /* Use the file handle in the context to overwrite a file
245      switch (mode) {     with prepared buffer contents. */
246      case WIPE_MODE_FAST:  static void
247          ctx.n_passes = 1;  overwrite (wipe_context_s *ctx)
248          overwrite_random (1, &ctx);  {
249          break;      DDWORD blocks = 0, mod = 0;
250        DWORD nwritten = 0;
251      case WIPE_MODE_SIMPLE:      LONG size_high = 0;
252          ctx.n_passes = 2;  
253          overwrite_random (2, &ctx);      blocks = ctx->filesize / ctx->buffsize;
254          break;      mod = ctx->filesize % ctx->buffsize;
255                SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
256      case WIPE_MODE_DOD:      while (blocks--) {
257          ctx.n_passes = 5;          if (!WriteFile (ctx->fd, ctx->buffer, ctx->buffsize, &nwritten, NULL))
258          overwrite_random (1, &ctx);              break;
259          overwrite_byte ((~1) & 0xFF, &ctx);          ctx->offset += nwritten;
260          overwrite_random (1, &ctx);          if (unlink_cb)
261          overwrite_byte ((~4) & 0xFF, &ctx);              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
262          overwrite_random (1, &ctx);                         (unsigned)ctx->filesize*ctx->n_passes);
263          break;      }
264                if (mod) {
265      case WIPE_MODE_GUTMANN:          WriteFile (ctx->fd, ctx->buffer, (DWORD)mod, &nwritten, NULL);
266          ctx.n_passes = 39;          ctx->offset += nwritten;
267          overwrite_random (4, &ctx);          if (unlink_cb)
268          overwrite_byte( 0x55, &ctx );              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
269          overwrite_byte ( 0xAA, &ctx );                         (unsigned)ctx->filesize*ctx->n_passes);
270          overwrite_bytes( 0x92, 0x49, 0x24, &ctx );      }
271          overwrite_bytes( 0x49, 0x24, 0x92, &ctx );      FlushFileBuffers (ctx->fd);
272          overwrite_bytes( 0x24, 0x92, 0x49, &ctx );      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
273          overwrite_byte( 0x00, &ctx );  }
274          overwrite_byte( 0x11, &ctx );  
275          overwrite_byte( 0x22, &ctx );  
276          overwrite_byte( 0x33, &ctx );  /* fill the buffer with random of the given level. */
277          overwrite_byte( 0x44, &ctx );  static void
278          overwrite_byte( 0x55, &ctx );  randomize_buffer (byte *buf, size_t bufsize)
279          overwrite_byte( 0x66, &ctx );  {
280          overwrite_byte( 0x77, &ctx );      const int blocksize = 512;
281          overwrite_byte( 0x88, &ctx );      int blocks = bufsize / blocksize;
282          overwrite_byte( 0x99, &ctx );      int mod = bufsize % blocksize;
283          overwrite_byte( 0xAA, &ctx );      int i;
284          overwrite_byte( 0xBB, &ctx );  
285          overwrite_byte( 0xCC, &ctx );      while (blocks--) {
286          overwrite_byte( 0xDD, &ctx );          for (i=0; i < blocksize; i++)
287          overwrite_byte( 0xEE, &ctx );              buf[i] = rnd_byte ();
288          overwrite_byte( 0xFF, &ctx );          buf += blocksize;
289          overwrite_bytes( 0x92, 0x49, 0x24, &ctx );      }
290          overwrite_bytes( 0x49, 0x24, 0x92, &ctx );      for (i=0; i < mod; i++)
291          overwrite_bytes( 0x24, 0x92, 0x49, &ctx );          buf[i] = rnd_byte ();
292          overwrite_bytes( 0x6D, 0xB6, 0xDB, &ctx );  }
293          overwrite_bytes( 0xB6, 0xDB, 0x6D, &ctx );  
294          overwrite_bytes( 0xDB, 0x6D, 0xB6, &ctx );  
295          overwrite_random( 4, &ctx );  /* performs a random overwrite. */
296          break;  static void
297      }  overwrite_random (int npasses, wipe_context_s * ctx)
298            {      
299      /* Set file length to zero so allocated clusters cannot be trailed */            int i;
300      SetFilePointer (ctx.fd, 0, &size_high, FILE_BEGIN);      
301      SetEndOfFile (ctx.fd);      for (i = 0; i < npasses; i++) {
302      CloseHandle (ctx.fd);          randomize_buffer (ctx->buffer, ctx->buffsize);
303                overwrite (ctx);
304      memset (ctx.buffer, 0, ctx.buffsize); /* burn the last evidence */        }
305      free_if_alloc (ctx.buffer);  }
306    
307      return rename_unlink (path);  
308  }  /* perform an overwrite with a specific byte (like 0x00). */
309    static void
310  int  overwrite_byte (int byte, wipe_context_s * ctx)
311  secure_unlink (const char *path, int mode)  {
312  {      memset (ctx->buffer, byte, ctx->buffsize);
313      return _secure_unlink (path, mode, NULL);      overwrite (ctx);
314  } /* secure_unlink */  } /* overwrite_byte */
315    
316    
317    /* perform an overwrite with a specific byte triple (like 0x00, 0xFF, 0xAA). */
318  void  static void
319  secure_unlink_set_cb (void (*cb)(void *, const char *, int, unsigned, unsigned),  overwrite_bytes (int byte1, int byte2, int byte3, wipe_context_s * ctx)
320                        void *cb_value)  {
321  {      DWORD i;
322      unlink_cb = cb;  
323      unlink_cb_value = cb_value;      memset (ctx->buffer, byte1, ctx->buffsize);
324  } /* secure_unlink_set_cb */      for (i = 1; i < ctx->buffsize; i += 3) {
325            ctx->buffer[i] = byte2;
326            ctx->buffer[i+1] = byte3;
327  /* Windows 98 - Q188074 */      }
328  #define REGISTRY_FILESYSTEM "System\\CurrentControlSet\\Control\\FileSystem"      overwrite (ctx);
329  #define REGISTRY_LOWDISKSPACE "DisableLowDiskSpaceBroadcast"  } /* overwrite_bytes */
330    
331    
332  /* disables the annoying warning Windows 98 displays when disk space is low */  /* For the case the file is not a regular file (this is true for
333  static void     devices or directories) this function tries to rename the file
334  handle_lowdiskspace_notify( const char * drive, int disable )     to random pattern and then it will be delete (without random!). */
335  {      extern "C" int
336      OSVERSIONINFO ov;  rename_unlink (const char *path)
337      HKEY key;  {
338      DWORD n;      struct stat statbuf;
339        char *new_name = NULL, *p = NULL, c;  
340      memset( &ov, 0, sizeof ov );      int i = 0, rc = 0;
341      ov.dwOSVersionInfoSize = sizeof ov;      int is_dir = 0;
342      GetVersionEx( &ov );  
343      if( ov.dwPlatformId == VER_PLATFORM_WIN32_NT )      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
344          return;          is_dir = 1;
345        
346      if( disable ) {      new_name = new char[strlen (path)+15];
347          unsigned newi = (1 << (toupper((unsigned)drive) - (unsigned)'A'));      if (!new_name)
348          if( RegOpenKey( HKEY_LOCAL_MACHINE, REGISTRY_FILESYSTEM, &key ) ) {          BUG (0);
349              n = sizeof newi;      
350              RegSetValue( key, REGISTRY_LOWDISKSPACE, REG_DWORD, (LPCTSTR)newi, n );      strcpy (new_name, path);
351              RegCloseKey( key );      p = strrchr (new_name, '\\');
352          }      if (p != NULL) {
353      }          p++;
354      else {          *p = '\0';
355          if( RegOpenKey( HKEY_LOCAL_MACHINE, REGISTRY_FILESYSTEM, &key ) ) {      }
356              RegDeleteKey( key, REGISTRY_LOWDISKSPACE );      else
357              RegCloseKey( key );          p = new_name;
358          }      do {
359      }          while (i < 14) {
360  } /* handle_lowdiskspace_notify */              c = random_char ();
361                *p = c;
362                p++;
363  int              i++;
364  wipe_freespace (const char * drive, HANDLE *r_fd,          }
365                  void (*cb)(void *, DDWORD, DDWORD), void * cb_value)          *p = '\0';
366  {      } while (stat (new_name, &statbuf) == 0);
367      ULARGE_INTEGER caller, total, frees;      
368      LONG hpart=0;      if (rename (path, new_name) == -1) {
369      HANDLE fd;          rc = WPTERR_FILE_READ;
370      int disktyp = GetDriveType (drive);          goto leave;
371      int rc;      }
372      char * file;      if (is_dir && RemoveDirectory (new_name) == FALSE)
373            rc = WPTERR_FILE_REMOVE;
374      if (disktyp != DRIVE_FIXED && disktyp != DRIVE_REMOVABLE)      else if (!DeleteFile (new_name))
375          return -1;          rc = WPTERR_FILE_REMOVE;
376      if (!GetDiskFreeSpaceEx (drive, &caller, &total, &frees))      
377          return -1;  leave:
378      handle_lowdiskspace_notify (drive, 1);      free_if_alloc (new_name);
379        return rc;
380      /* disk is full */  }
381      if (!frees.LowPart)  
382          return 0;  
383      file = new char[strlen (drive)+8];  /* return the filesize as an 64-bit integer. */
384      if (!file)  static DDWORD
385          BUG (0);  GetFileSize64 (const char * path)
386      sprintf (file, "%stemp_winpt.tmp", drive);  {
387      fd = CreateFile (file,      FILE *fp = fopen (path, "r");
388                      GENERIC_READ|GENERIC_WRITE,      if (fp) {
389                      FILE_SHARE_READ|FILE_SHARE_WRITE,          struct _stati64 statbuf;
390                      NULL, CREATE_ALWAYS, 0, NULL);          if (_fstati64 (fileno (fp), &statbuf) == -1)
391      if (fd == INVALID_HANDLE_VALUE) {              return (DDWORD)-1;
392          free_if_alloc (file);          fclose (fp);
393          return WPTERR_FILE_OPEN;          return statbuf.st_size;
394      }      }
395      hpart = frees.HighPart;      return (DDWORD)-1;
396      SetFilePointer (fd, frees.LowPart, &hpart, FILE_BEGIN);  }
397      SetEndOfFile (fd);  
398      CloseHandle (fd);  
399    static int
400      if (cb && cb_value) {  _secure_unlink (const char * path, int mode, HANDLE *r_fd)
401          progress_cb = cb;  {
402          progress_cb_value = cb_value;      wipe_context_s ctx;
403      }      LONG size_high = 0;
404      rc = _secure_unlink (file, WIPE_MODE_FAST, r_fd);      
405        if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
406      handle_lowdiskspace_notify (drive, 0);          return rename_unlink (path);
407      free_if_alloc (file);      
408      return rc;      memset (&ctx, 0, sizeof (ctx));
409  } /* wipe_freespace */      ctx.name = path;
410        ctx.buffsize = 16384;
411        ctx.buffer = new byte[ctx.buffsize];
412        if (!ctx.buffer)
413            BUG (0);
414        
415        ctx.filesize = GetFileSize64 (path);
416        if (!ctx.filesize) {
417            free_if_alloc (ctx.buffer);
418            unlink (path);
419            return 0;
420        }
421    
422        ctx.fd = CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
423                             OPEN_ALWAYS, 0, NULL);
424        if (ctx.fd == INVALID_HANDLE_VALUE) {
425            free_if_alloc (ctx.buffer);
426            return WPTERR_FILE_OPEN;
427        }
428        else if (r_fd)
429            *r_fd = ctx.fd;
430        
431        if (unlink_cb)
432            unlink_cb (unlink_cb_value, ctx.name, 0, 0, 0);
433    
434        switch (mode) {
435        case WIPE_MODE_FAST:
436            ctx.n_passes = 1;
437            overwrite_random (1, &ctx);
438            break;
439    
440        case WIPE_MODE_SIMPLE:
441            ctx.n_passes = 2;
442            overwrite_random (2, &ctx);
443            break;
444            
445        case WIPE_MODE_DOD:
446            ctx.n_passes = 5;
447            overwrite_random (1, &ctx);
448            overwrite_byte ((~1) & 0xFF, &ctx);
449            overwrite_random (1, &ctx);
450            overwrite_byte ((~4) & 0xFF, &ctx);
451            overwrite_random (1, &ctx);
452            break;
453            
454        case WIPE_MODE_GUTMANN:
455            ctx.n_passes = 39;
456            overwrite_random (4, &ctx);
457            overwrite_byte( 0x55, &ctx );
458            overwrite_byte ( 0xAA, &ctx );
459            overwrite_bytes( 0x92, 0x49, 0x24, &ctx );
460            overwrite_bytes( 0x49, 0x24, 0x92, &ctx );
461            overwrite_bytes( 0x24, 0x92, 0x49, &ctx );
462            overwrite_byte( 0x00, &ctx );
463            overwrite_byte( 0x11, &ctx );
464            overwrite_byte( 0x22, &ctx );
465            overwrite_byte( 0x33, &ctx );
466            overwrite_byte( 0x44, &ctx );
467            overwrite_byte( 0x55, &ctx );
468            overwrite_byte( 0x66, &ctx );
469            overwrite_byte( 0x77, &ctx );
470            overwrite_byte( 0x88, &ctx );
471            overwrite_byte( 0x99, &ctx );
472            overwrite_byte( 0xAA, &ctx );
473            overwrite_byte( 0xBB, &ctx );
474            overwrite_byte( 0xCC, &ctx );
475            overwrite_byte( 0xDD, &ctx );
476            overwrite_byte( 0xEE, &ctx );
477            overwrite_byte( 0xFF, &ctx );
478            overwrite_bytes( 0x92, 0x49, 0x24, &ctx );
479            overwrite_bytes( 0x49, 0x24, 0x92, &ctx );
480            overwrite_bytes( 0x24, 0x92, 0x49, &ctx );
481            overwrite_bytes( 0x6D, 0xB6, 0xDB, &ctx );
482            overwrite_bytes( 0xB6, 0xDB, 0x6D, &ctx );
483            overwrite_bytes( 0xDB, 0x6D, 0xB6, &ctx );
484            overwrite_random( 4, &ctx );
485            break;
486        }
487            
488        /* Set file length to zero so allocated clusters cannot be trailed */      
489        SetFilePointer (ctx.fd, 0, &size_high, FILE_BEGIN);
490        SetEndOfFile (ctx.fd);
491        CloseHandle (ctx.fd);
492        
493        memset (ctx.buffer, 0, ctx.buffsize); /* burn the last evidence */  
494        free_if_alloc (ctx.buffer);
495    
496        return rename_unlink (path);
497    }
498    
499    
500    /* Delete a file in a secure way with the given mode @mode. */
501    extern "C" int
502    secure_unlink (const char *path, int mode)
503    {
504        /* If the file has one of the following attributes, the
505           chance the file really gets overwritten is very low so
506           we just to an unlink to spare time and entropy. */
507        DWORD attr = GetFileAttributes (path);
508        if ((attr & FILE_ATTRIBUTE_COMPRESSED) ||
509            (attr & FILE_ATTRIBUTE_ENCRYPTED) ||
510            (attr & FILE_ATTRIBUTE_SPARSE_FILE))
511            return DeleteFile (path); /* XXX */
512        return _secure_unlink (path, mode, NULL);
513    }
514    
515    
516    /* Set the callback @cb for the wipe function. The callback is call every time
517       the wipe function writes data to the file. */
518    extern "C" void
519    secure_unlink_set_cb (void (*cb)(void *, const char *, int, int, int),
520                          void *cb_value)
521    {
522        unlink_cb = cb;
523        unlink_cb_value = cb_value;
524    }
525    
526    
527    /* wipe all free space of the given drive by creating a temp file
528       which has the size of the free space. This file will be then
529       overwritten with random and static pattern. */
530    extern "C" int
531    wipe_freespace (const char * drive, HANDLE *r_fd,
532                    void (*cb)(void *, DDWORD, DDWORD), void * cb_value)
533    {
534        ULARGE_INTEGER caller, total, frees;
535        LONG hpart=0;
536        HANDLE fd;
537        int disktyp = GetDriveType (drive);
538        int rc;
539        char * file;
540    
541        if (disktyp != DRIVE_FIXED && disktyp != DRIVE_REMOVABLE)
542            return -1;
543        if (!GetDiskFreeSpaceEx (drive, &caller, &total, &frees))
544            return -1;  
545    
546        /* disk is full */
547        if (!frees.LowPart)
548            return 0;
549        file = new char[strlen (drive)+8];
550        if (!file)
551            BUG (0);
552        sprintf (file, "%stemp_winpt.tmp", drive);
553        fd = CreateFile (file,
554                        GENERIC_READ|GENERIC_WRITE,
555                        FILE_SHARE_READ|FILE_SHARE_WRITE,
556                        NULL, CREATE_ALWAYS, 0, NULL);
557        if (fd == INVALID_HANDLE_VALUE) {
558            free_if_alloc (file);
559            return WPTERR_FILE_OPEN;
560        }
561        hpart = frees.HighPart;
562        SetFilePointer (fd, frees.LowPart, &hpart, FILE_BEGIN);
563        SetEndOfFile (fd);
564        CloseHandle (fd);
565    
566        if (cb && cb_value) {
567            progress_cb = cb;
568            progress_cb_value = cb_value;
569        }
570        rc = _secure_unlink (file, WIPE_MODE_FAST, r_fd);
571        free_if_alloc (file);
572        return rc;
573    }

Legend:
Removed from v.5  
changed lines
  Added in v.55

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26