/[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 2 by twoaday, Mon Jan 31 11:02:21 2005 UTC revision 53 by twoaday, Wed Nov 2 09:01:29 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          return WPTERR_FILE_ZERO;      return ctx->sbox[(ctx->sbox[ctx->i] + ctx->sbox[ctx->j]) & 255];
229      }  }
230    
231      ctx.fd = CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,  
232                           OPEN_ALWAYS, 0, NULL);  /* Generate a single alpha-num charactor. */
233      if (ctx.fd == INVALID_HANDLE_VALUE) {  static char
234          free_if_alloc (ctx.buffer);  random_char (void)
235          return WPTERR_FILE_OPEN;  {      
236      }      byte c = 0;
237      else if (r_fd)  
238          *r_fd = ctx.fd;      while  (!isalnum(c))
239                c = rnd_byte ();
240      gpg_quick_random_gen (1);      return c % 127;
241      if (unlink_cb)  }
242          unlink_cb (unlink_cb_value, ctx.name, 0, 0, 0);  
243    
244      switch (mode) {  /* Use the file handle in the context to overwrite a file
245      case WIPE_MODE_FAST:     with prepared buffer contents. */
246          ctx.n_passes = 1;  static void
247          overwrite_random (1, &ctx);  overwrite (wipe_context_s *ctx)
248          break;  {
249        DDWORD blocks = 0, mod = 0;
250      case WIPE_MODE_SIMPLE:      DWORD nwritten = 0;
251          ctx.n_passes = 2;      LONG size_high = 0;
252          overwrite_random (2, &ctx);  
253          break;      blocks = ctx->filesize / ctx->buffsize;
254                mod = ctx->filesize % ctx->buffsize;
255      case WIPE_MODE_DOD:      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
256          ctx.n_passes = 5;      while (blocks--) {
257          overwrite_random (1, &ctx);          if (!WriteFile (ctx->fd, ctx->buffer, ctx->buffsize, &nwritten, NULL))
258          overwrite_byte ((~1) & 0xFF, &ctx);              break;
259          overwrite_random (1, &ctx);          ctx->offset += nwritten;
260          overwrite_byte ((~4) & 0xFF, &ctx);          if (unlink_cb)
261          overwrite_random (1, &ctx);              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
262          break;                         (unsigned)ctx->filesize*ctx->n_passes);
263                }
264      case WIPE_MODE_GUTMANN:      if (mod) {
265          ctx.n_passes = 39;          WriteFile (ctx->fd, ctx->buffer, (DWORD)mod, &nwritten, NULL);
266          overwrite_random (4, &ctx);          ctx->offset += nwritten;
267          overwrite_byte( 0x55, &ctx );          if (unlink_cb)
268          overwrite_byte ( 0xAA, &ctx );              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
269          overwrite_bytes( 0x92, 0x49, 0x24, &ctx );                         (unsigned)ctx->filesize*ctx->n_passes);
270          overwrite_bytes( 0x49, 0x24, 0x92, &ctx );      }
271          overwrite_bytes( 0x24, 0x92, 0x49, &ctx );      FlushFileBuffers (ctx->fd);
272          overwrite_byte( 0x00, &ctx );      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
273          overwrite_byte( 0x11, &ctx );  }
274          overwrite_byte( 0x22, &ctx );  
275          overwrite_byte( 0x33, &ctx );  
276          overwrite_byte( 0x44, &ctx );  /* fill the buffer with random of the given level. */
277          overwrite_byte( 0x55, &ctx );  static void
278          overwrite_byte( 0x66, &ctx );  randomize_buffer (byte *buf, size_t bufsize)
279          overwrite_byte( 0x77, &ctx );  {
280          overwrite_byte( 0x88, &ctx );      const int blocksize = 512;
281          overwrite_byte( 0x99, &ctx );      int blocks = bufsize / blocksize;
282          overwrite_byte( 0xAA, &ctx );      int mod = bufsize % blocksize;
283          overwrite_byte( 0xBB, &ctx );      int i;
284          overwrite_byte( 0xCC, &ctx );  
285          overwrite_byte( 0xDD, &ctx );      while (blocks--) {
286          overwrite_byte( 0xEE, &ctx );          for (i=0; i < blocksize; i++)
287          overwrite_byte( 0xFF, &ctx );              buf[i] = rnd_byte ();
288          overwrite_bytes( 0x92, 0x49, 0x24, &ctx );          buf += blocksize;
289          overwrite_bytes( 0x49, 0x24, 0x92, &ctx );      }
290          overwrite_bytes( 0x24, 0x92, 0x49, &ctx );      for (i=0; i < mod; i++)
291          overwrite_bytes( 0x6D, 0xB6, 0xDB, &ctx );          buf[i] = rnd_byte ();
292          overwrite_bytes( 0xB6, 0xDB, 0x6D, &ctx );  }
293          overwrite_bytes( 0xDB, 0x6D, 0xB6, &ctx );  
294          overwrite_random( 4, &ctx );  
295          break;  /* performs a random overwrite. */
296      }  static void
297            overwrite_random (int npasses, wipe_context_s * ctx)
298      /* Set file length to zero so allocated clusters cannot be trailed */        {      
299      SetFilePointer (ctx.fd, 0, &size_high, FILE_BEGIN);      int i;
300      SetEndOfFile (ctx.fd);      
301      CloseHandle (ctx.fd);      for (i = 0; i < npasses; i++) {
302                randomize_buffer (ctx->buffer, ctx->buffsize);
303      memset (ctx.buffer, 0, ctx.buffsize); /* burn the last evidence */            overwrite (ctx);
304      free_if_alloc (ctx.buffer);      }
305    }
306      return rename_unlink (path);  
307  }  
308    /* perform an overwrite with a specific byte (like 0x00). */
309  int  static void
310  secure_unlink (const char *path, int mode)  overwrite_byte (int byte, wipe_context_s * ctx)
311  {  {
312      return _secure_unlink (path, mode, NULL);      memset (ctx->buffer, byte, ctx->buffsize);
313  } /* secure_unlink */      overwrite (ctx);
314    } /* overwrite_byte */
315    
316    
317  void  /* perform an overwrite with a specific byte triple (like 0x00, 0xFF, 0xAA). */
318  secure_unlink_set_cb (void (*cb)(void *, const char *, int, unsigned, unsigned),  static void
319                        void *cb_value)  overwrite_bytes (int byte1, int byte2, int byte3, wipe_context_s * ctx)
320  {  {
321      unlink_cb = cb;      DWORD i;
322      unlink_cb_value = cb_value;  
323  } /* secure_unlink_set_cb */      memset (ctx->buffer, byte1, ctx->buffsize);
324        for (i = 1; i < ctx->buffsize; i += 3) {
325            ctx->buffer[i] = byte2;
326  /* Windows 98 - Q188074 */          ctx->buffer[i+1] = byte3;
327  #define REGISTRY_FILESYSTEM "System\\CurrentControlSet\\Control\\FileSystem"      }
328  #define REGISTRY_LOWDISKSPACE "DisableLowDiskSpaceBroadcast"      overwrite (ctx);
329    } /* overwrite_bytes */
330    
331  /* disables the annoying warning Windows 98 displays when disk space is low */  
332  static void  /* For the case the file is not a regular file (this is true for
333  handle_lowdiskspace_notify( const char * drive, int disable )     devices or directories) this function tries to rename the file
334  {         to random pattern and then it will be delete (without random!). */
335      OSVERSIONINFO ov;  extern "C" int
336      HKEY key;  rename_unlink (const char *path)
337      DWORD n;  {
338        struct stat statbuf;
339      memset( &ov, 0, sizeof ov );      char *new_name = NULL, *p = NULL, c;  
340      ov.dwOSVersionInfoSize = sizeof ov;      int i = 0, rc = 0;
341      GetVersionEx( &ov );      int is_dir = 0;
342      if( ov.dwPlatformId == VER_PLATFORM_WIN32_NT )  
343          return;      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
344            is_dir = 1;
345      if( disable ) {      
346          unsigned newi = (1 << (toupper((unsigned)drive) - (unsigned)'A'));      new_name = new char[strlen (path)+15];
347          if( RegOpenKey( HKEY_LOCAL_MACHINE, REGISTRY_FILESYSTEM, &key ) ) {      if (!new_name)
348              n = sizeof newi;          BUG (0);
349              RegSetValue( key, REGISTRY_LOWDISKSPACE, REG_DWORD, (LPCTSTR)newi, n );      
350              RegCloseKey( key );      strcpy (new_name, path);
351          }      p = strrchr (new_name, '\\');
352      }      if (p != NULL) {
353      else {          p++;
354          if( RegOpenKey( HKEY_LOCAL_MACHINE, REGISTRY_FILESYSTEM, &key ) ) {          *p = '\0';
355              RegDeleteKey( key, REGISTRY_LOWDISKSPACE );      }
356              RegCloseKey( key );      else
357          }          p = new_name;
358      }      do {
359  } /* handle_lowdiskspace_notify */          while (i < 14) {
360                c = random_char ();
361                *p = c;
362  int              p++;
363  wipe_freespace (const char * drive, HANDLE *r_fd,              i++;
364                  void (*cb)(void *, DDWORD, DDWORD), void * cb_value)          }
365  {          *p = '\0';
366      ULARGE_INTEGER caller, total, frees;      } while (stat (new_name, &statbuf) == 0);
367      LONG hpart=0;      
368      HANDLE fd;      if (rename (path, new_name) == -1) {
369      int disktyp = GetDriveType (drive);          rc = WPTERR_FILE_READ;
370      int rc;          goto leave;
371      char * file;      }
372        if (is_dir && RemoveDirectory (new_name) == FALSE)
373      if (disktyp != DRIVE_FIXED && disktyp != DRIVE_REMOVABLE)          rc = WPTERR_FILE_REMOVE;
374          return -1;      else if (!DeleteFile (new_name))
375      if (!GetDiskFreeSpaceEx (drive, &caller, &total, &frees))          rc = WPTERR_FILE_REMOVE;
376          return -1;      
377      handle_lowdiskspace_notify (drive, 1);  leave:
378        free_if_alloc (new_name);
379      if (!frees.LowPart)      return rc;
380          return WPTERR_FILE_ZERO;  }
381      file = new char[strlen (drive)+8];  
382      if (!file)  
383          BUG (0);  /* return the filesize as an 64-bit integer. */
384      sprintf (file, "%stemp_winpt.tmp", drive);  static DDWORD
385      fd = CreateFile (file,  GetFileSize64 (const char * path)
386                      GENERIC_READ|GENERIC_WRITE,  {
387                      FILE_SHARE_READ|FILE_SHARE_WRITE,      FILE *fp = fopen (path, "r");
388                      NULL, CREATE_ALWAYS, 0, NULL);      if (fp) {
389      if (fd == INVALID_HANDLE_VALUE) {          struct _stati64 statbuf;
390          free_if_alloc (file);          if (_fstati64 (fileno (fp), &statbuf) == -1)
391          return WPTERR_FILE_OPEN;              return -1;
392      }          fclose (fp);
393      hpart = frees.HighPart;          return statbuf.st_size;
394      SetFilePointer (fd, frees.LowPart, &hpart, FILE_BEGIN);      }
395      SetEndOfFile (fd);      return -1;
396      CloseHandle (fd);  }
397    
398      if (cb && cb_value) {  
399          progress_cb = cb;  static int
400          progress_cb_value = cb_value;  _secure_unlink (const char * path, int mode, HANDLE *r_fd)
401      }  {
402      rc = _secure_unlink (file, WIPE_MODE_FAST, r_fd);      wipe_context_s ctx;
403        LONG size_high = 0;
404      handle_lowdiskspace_notify (drive, 0);      
405      free_if_alloc (file);      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
406      return rc;          return rename_unlink (path);
407  } /* wipe_freespace */      
408        memset (&ctx, 0, sizeof (ctx));
409        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.2  
changed lines
  Added in v.53

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26