/[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 23 by twoaday, Fri Sep 30 10:10:16 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, int, int) = NULL;      const char *name;
60  static void *unlink_cb_value = NULL;      int    n_passes;
61    } wipe_context_s;
62  /* Use the file handle in the context to overwrite a file  
63     with prepared buffer contents. */  struct arcfour_s {
64  static void      BYTE *seed;
65  overwrite (wipe_context_s *ctx)      int  pos;
66  {      BYTE sbox[256];
67      DDWORD blocks = 0, mod = 0;      DWORD i;
68      DWORD nwritten = 0;      DWORD j;
69      LONG size_high = 0;  };
70    
71      blocks = ctx->filesize / ctx->buffsize;  
72      mod = ctx->filesize % ctx->buffsize;  void (*progress_cb) (void *, DDWORD, DDWORD);
73      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);  static void *progress_cb_value = NULL;
74      while (blocks--) {  
75          if (!WriteFile (ctx->fd, ctx->buffer, ctx->buffsize, &nwritten, NULL))  void (*unlink_cb)(void *, const char *, int, int, int) = NULL;
76              break;  static void *unlink_cb_value = NULL;
77          ctx->offset += nwritten;  
78          if (unlink_cb)  static int init_done = 0;
79              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,  static struct arcfour_s rnd;
80                         (unsigned)ctx->filesize*ctx->n_passes);  
81      }  
82      if (mod) {  /* Add the random from buffer @buf with the length @buf_len
83          WriteFile (ctx->fd, ctx->buffer, (DWORD)mod, &nwritten, NULL);     into the seed @seed. The seed length (256) used to
84          ctx->offset += nwritten;     emulate a circular movment. */
85          if (unlink_cb)  static void
86              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,  add_random (unsigned char *seed, int *seed_pos,
87                         (unsigned)ctx->filesize*ctx->n_passes);              unsigned char *buf, int buf_len)
88      }  {
89      FlushFileBuffers (ctx->fd);      int i, s_pos = *seed_pos;
90      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);  
91  }      for (i=0; i < buf_len; i++)
92            seed[(s_pos++ % 256)] ^= buf[i];
93        *seed_pos = s_pos % 256;
94  /* fill the buffer with random of the given level. */  }
95  static void  
96  randomize_buffer (byte *buf, size_t bufsize, int level)  
97  {  /* Enumerate all child windows. Store their text, their thread ID,
98      const int blocksize = 512;     their placement and their dimension. */
99      int blocks = bufsize / blocksize;  static BOOL CALLBACK
100      int mod = bufsize % blocksize;  child_proc (HWND h, LPARAM l)
101        {
102      while (blocks--) {      struct arcfour_s *cb =  (struct arcfour_s*)l;
103          gpg_randomize (buf, blocksize, level);      DWORD a = (DWORD)h;
104          buf += blocksize;      WINDOWPLACEMENT p;
105      }      RECT r;
106      if (mod)      char buf[256];
107          gpg_randomize (buf, mod, level);      int n;
108  }  
109        n  = GetWindowText (h, buf, 255);
110        if (n > 0)
111  /* performs a random overwrite. */          add_random (cb->seed, &cb->pos, (BYTE*)buf, n);
112  static void      add_random (cb->seed, &cb->pos, (BYTE*)&a, 4);
113  overwrite_random (int npasses, wipe_context_s * ctx)      a = GetWindowThreadProcessId (h, NULL);
114  {            add_random (cb->seed, &cb->pos, (BYTE*)&a, 4);
115      int i;      GetWindowPlacement (h, &p);
116            add_random (cb->seed, &cb->pos, (BYTE*)&p, sizeof (p));
117      for (i = 0; i < npasses; i++) {      GetWindowRect (h, &r);
118          randomize_buffer (ctx->buffer, ctx->buffsize, 0);      add_random (cb->seed, &cb->pos, (BYTE*)&r, sizeof (r));
119          overwrite (ctx);      return TRUE;
120      }  }
121  }  
122    
123    /* Initialize the seed with all kind of system variables. */
124  /* perform an overwrite with a specific byte (like 0x00). */  static void
125  static void  init_random (unsigned char *seed)
126  overwrite_byte (int byte, wipe_context_s * ctx)  {
127  {      int pos=0;
128      memset (ctx->buffer, byte, ctx->buffsize);      DWORD buf[16];
129      overwrite (ctx);      int i=0;
130  } /* overwrite_byte */  
131        buf[i++] = (DWORD)GetActiveWindow ();
132        buf[i++] = (DWORD)GetCapture ();
133  /* perform an overwrite with a specific byte triple (like 0x00, 0xFF, 0xAA). */      buf[i++] = (DWORD)GetClipboardOwner ();
134  static void      buf[i++] = (DWORD)GetClipboardViewer ();
135  overwrite_bytes (int byte1, int byte2, int byte3, wipe_context_s * ctx)      buf[i++] = (DWORD)GetCurrentProcess ();      
136  {      buf[i++] = (DWORD)GetCurrentProcessId ();
137      DWORD i;      buf[i++] = (DWORD)GetCurrentThread ();
138        buf[i++] = (DWORD)GetDesktopWindow ();
139      memset (ctx->buffer, byte1, ctx->buffsize);      buf[i++] = (DWORD)GetFocus ();
140      for (i = 1; i < ctx->buffsize; i += 3) {      buf[i++] = (DWORD)GetMessagePos ();
141          ctx->buffer[i] = byte2;      buf[i++] = (DWORD)GetOpenClipboardWindow ();
142          ctx->buffer[i+1] = byte3;      buf[i++] = (DWORD)GetProcessHeap ();
143      }      buf[i++] = (DWORD)GetProcessWindowStation ();
144      overwrite (ctx);      buf[i++] = (DWORD)GetQueueStatus (QS_ALLEVENTS);
145  } /* overwrite_bytes */      buf[i] = (DWORD)GetTickCount ();
146        add_random (seed, &pos, (BYTE*)buf, 4*i);
147    
148  /* For the case the file is not a regular file (this is true for      {
149     devices or directories) this function tries to rename the file          POINT p;
150     to random pattern and then it will be delete (without random!). */          GetCursorPos (&p);
151  int          add_random (seed, &pos, (BYTE*)&p, sizeof (p));
152  rename_unlink (const char *path)          GetCaretPos (&p);
153  {          add_random (seed, &pos, (BYTE*)&p, sizeof (p));
154      struct stat statbuf;      }
155      char *new_name = NULL, *p = NULL, c;    
156      int i = 0, rc = 0;      {
157      int is_dir = 0;          STARTUPINFO inf;
158            inf.cb = sizeof (inf);
159      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)          GetStartupInfo (&inf);
160          is_dir = 1;          add_random (seed, &pos, (BYTE*)&inf, sizeof (inf));
161            }
162      new_name = new char[strlen (path)+15];  
163      if (!new_name)      {
164          BUG (0);          MEMORYSTATUS st;
165                
166      strcpy (new_name, path);          st.dwLength = sizeof (st);
167      p = strrchr (new_name, '\\');          GlobalMemoryStatus (&st);
168      if (p != NULL) {          add_random (seed, &pos, (BYTE*)&st, sizeof (st));
169          p++;      }
170          *p = '\0';  
171      }      {
172      else          LARGE_INTEGER in;
173          p = new_name;  
174      do {          QueryPerformanceFrequency (&in);
175          while (i < 14) {          add_random (seed, &pos, (BYTE*)&in, sizeof (in));
176              c = gpg_random_char (1);          QueryPerformanceCounter (&in);
177              *p = c;          add_random (seed, &pos, (BYTE*)&in, sizeof (in));
178              p++;      }
179              i++;      {
180          }          rnd.seed = seed;
181          *p = '\0';          rnd.pos = pos;
182      } while (stat (new_name, &statbuf) == 0);          EnumChildWindows (GetDesktopWindow (), child_proc, (LPARAM)&rnd);
183            }
184      if (rename (path, new_name) == -1) {  
185          rc = WPTERR_FILE_READ;  }
186          goto leave;  
187      }  
188      if (is_dir && RemoveDirectory (new_name) == FALSE)  /* Initialize cipher with the seed as the key. */
189          rc = WPTERR_FILE_REMOVE;  static void
190      else if (!DeleteFile (new_name))  init_arcfour (struct arcfour_s *ctx, BYTE *key)
191          rc = WPTERR_FILE_REMOVE;  {
192            BYTE t;
193  leave:  
194      free_if_alloc (new_name);      ctx->i = 0;
195      return rc;      ctx->j = 0;
196  }      for (ctx->i=0; ctx->i < 256; ctx->i++)
197            ctx->sbox[ctx->i] = (BYTE)ctx->i;
198        for (ctx->i=0; ctx->i < 256; ctx->i++) {
199  /* return the filesize as an 64-bit integer. */          ctx->j += (ctx->j+ctx->sbox[ctx->i]+key[ctx->i]);
200  static __int64          ctx->j &= 255;
201  GetFileSize64 (const char * path)          t = ctx->sbox[ctx->i];
202  {          ctx->sbox[ctx->i] = ctx->sbox[ctx->j];
203      FILE *fp = fopen (path, "r");          ctx->sbox[ctx->j] = t;
204      if (fp) {      }
205          struct _stati64 statbuf;  }
206          if (_fstati64 (fileno (fp), &statbuf) == -1)  
207              return -1;  
208          fclose (fp);  /* Generate a single random byte. If the cipher is not
209          return statbuf.st_size;     init, do an init first. */
210      }  static BYTE
211      return -1;  rnd_byte (void)
212  }  {
213        struct arcfour_s *ctx = &rnd;
214        BYTE t;
215  static int  
216  _secure_unlink (const char * path, int mode, HANDLE *r_fd)      if (!init_done) {
217  {          BYTE buf[256];
218      wipe_context_s ctx;          init_random (buf);
219      LONG size_high = 0;          init_arcfour (ctx, buf);
220                init_done = 1;
221      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)      }
222          return rename_unlink (path);  
223            ctx->i++; ctx->i &= 255;
224      memset (&ctx, 0, sizeof (ctx));      ctx->j += ctx->sbox[ctx->i]; ctx->j &= 255;
225      ctx.name = path;      t = ctx->sbox[ctx->i];
226      ctx.buffsize = 16384;      ctx->sbox[ctx->i] = ctx->sbox[ctx->j];
227      ctx.buffer = new byte[ctx.buffsize];      ctx->sbox[ctx->j] = t;
228      if (!ctx.buffer)      return ctx->sbox[(ctx->sbox[ctx->i] + ctx->sbox[ctx->j]) & 255];
229          BUG (0);  }
230        
231      ctx.filesize = GetFileSize64 (path);  
232      if (!ctx.filesize) {  /* Generate a single alpha-num charactor. */
233          free_if_alloc (ctx.buffer);  static char
234          unlink (path);  random_char (void)
235          return 0;  {      
236      }      byte c = 0;
237    
238      ctx.fd = CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,      while  (!isalnum(c))
239                           OPEN_ALWAYS, 0, NULL);          c = rnd_byte ();
240      if (ctx.fd == INVALID_HANDLE_VALUE) {      return c % 127;
241          free_if_alloc (ctx.buffer);  }
242          return WPTERR_FILE_OPEN;  
243      }  
244      else if (r_fd)  /* Use the file handle in the context to overwrite a file
245          *r_fd = ctx.fd;     with prepared buffer contents. */
246        static void
247      gpg_quick_random_gen (1);  overwrite (wipe_context_s *ctx)
248      if (unlink_cb)  {
249          unlink_cb (unlink_cb_value, ctx.name, 0, 0, 0);      DDWORD blocks = 0, mod = 0;
250        DWORD nwritten = 0;
251      switch (mode) {      LONG size_high = 0;
252      case WIPE_MODE_FAST:  
253          ctx.n_passes = 1;      blocks = ctx->filesize / ctx->buffsize;
254          overwrite_random (1, &ctx);      mod = ctx->filesize % ctx->buffsize;
255          break;      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
256        while (blocks--) {
257      case WIPE_MODE_SIMPLE:          if (!WriteFile (ctx->fd, ctx->buffer, ctx->buffsize, &nwritten, NULL))
258          ctx.n_passes = 2;              break;
259          overwrite_random (2, &ctx);          ctx->offset += nwritten;
260          break;          if (unlink_cb)
261                        unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
262      case WIPE_MODE_DOD:                         (unsigned)ctx->filesize*ctx->n_passes);
263          ctx.n_passes = 5;      }
264          overwrite_random (1, &ctx);      if (mod) {
265          overwrite_byte ((~1) & 0xFF, &ctx);          WriteFile (ctx->fd, ctx->buffer, (DWORD)mod, &nwritten, NULL);
266          overwrite_random (1, &ctx);          ctx->offset += nwritten;
267          overwrite_byte ((~4) & 0xFF, &ctx);          if (unlink_cb)
268          overwrite_random (1, &ctx);              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
269          break;                         (unsigned)ctx->filesize*ctx->n_passes);
270                }
271      case WIPE_MODE_GUTMANN:      FlushFileBuffers (ctx->fd);
272          ctx.n_passes = 39;      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
273          overwrite_random (4, &ctx);  }
274          overwrite_byte( 0x55, &ctx );  
275          overwrite_byte ( 0xAA, &ctx );  
276          overwrite_bytes( 0x92, 0x49, 0x24, &ctx );  /* fill the buffer with random of the given level. */
277          overwrite_bytes( 0x49, 0x24, 0x92, &ctx );  static void
278          overwrite_bytes( 0x24, 0x92, 0x49, &ctx );  randomize_buffer (byte *buf, size_t bufsize)
279          overwrite_byte( 0x00, &ctx );  {
280          overwrite_byte( 0x11, &ctx );      const int blocksize = 512;
281          overwrite_byte( 0x22, &ctx );      int blocks = bufsize / blocksize;
282          overwrite_byte( 0x33, &ctx );      int mod = bufsize % blocksize;
283          overwrite_byte( 0x44, &ctx );      int i;
284          overwrite_byte( 0x55, &ctx );  
285          overwrite_byte( 0x66, &ctx );      while (blocks--) {
286          overwrite_byte( 0x77, &ctx );          for (i=0; i < blocksize; i++)
287          overwrite_byte( 0x88, &ctx );              buf[i] = rnd_byte ();
288          overwrite_byte( 0x99, &ctx );          buf += blocksize;
289          overwrite_byte( 0xAA, &ctx );      }
290          overwrite_byte( 0xBB, &ctx );      for (i=0; i < mod; i++)
291          overwrite_byte( 0xCC, &ctx );          buf[i] = rnd_byte ();
292          overwrite_byte( 0xDD, &ctx );  }
293          overwrite_byte( 0xEE, &ctx );  
294          overwrite_byte( 0xFF, &ctx );  
295          overwrite_bytes( 0x92, 0x49, 0x24, &ctx );  /* performs a random overwrite. */
296          overwrite_bytes( 0x49, 0x24, 0x92, &ctx );  static void
297          overwrite_bytes( 0x24, 0x92, 0x49, &ctx );  overwrite_random (int npasses, wipe_context_s * ctx)
298          overwrite_bytes( 0x6D, 0xB6, 0xDB, &ctx );  {      
299          overwrite_bytes( 0xB6, 0xDB, 0x6D, &ctx );      int i;
300          overwrite_bytes( 0xDB, 0x6D, 0xB6, &ctx );      
301          overwrite_random( 4, &ctx );      for (i = 0; i < npasses; i++) {
302          break;          randomize_buffer (ctx->buffer, ctx->buffsize);
303      }          overwrite (ctx);
304                }
305      /* Set file length to zero so allocated clusters cannot be trailed */        }
306      SetFilePointer (ctx.fd, 0, &size_high, FILE_BEGIN);  
307      SetEndOfFile (ctx.fd);  
308      CloseHandle (ctx.fd);  /* perform an overwrite with a specific byte (like 0x00). */
309        static void
310      memset (ctx.buffer, 0, ctx.buffsize); /* burn the last evidence */    overwrite_byte (int byte, wipe_context_s * ctx)
311      free_if_alloc (ctx.buffer);  {
312        memset (ctx->buffer, byte, ctx->buffsize);
313      return rename_unlink (path);      overwrite (ctx);
314  }  } /* overwrite_byte */
315    
316    
317  /* Delete a file in a secure way with the given mode. */  /* perform an overwrite with a specific byte triple (like 0x00, 0xFF, 0xAA). */
318  int  static void
319  secure_unlink (const char *path, int mode)  overwrite_bytes (int byte1, int byte2, int byte3, wipe_context_s * ctx)
320  {  {
321      return _secure_unlink (path, mode, NULL);      DWORD i;
322  }  
323        memset (ctx->buffer, byte1, ctx->buffsize);
324        for (i = 1; i < ctx->buffsize; i += 3) {
325  /* Set the callback @cb for the wipe function. The callback is call every time          ctx->buffer[i] = byte2;
326     the wipe function writes data to the file. */          ctx->buffer[i+1] = byte3;
327  void      }
328  secure_unlink_set_cb (void (*cb)(void *, const char *, int, int, int),      overwrite (ctx);
329                        void *cb_value)  } /* overwrite_bytes */
330  {  
331      unlink_cb = cb;  
332      unlink_cb_value = cb_value;  /* For the case the file is not a regular file (this is true for
333  }     devices or directories) this function tries to rename the file
334       to random pattern and then it will be delete (without random!). */
335    extern "C" int
336  /* wipe all free space of the given drive by creating a temp file  rename_unlink (const char *path)
337     which has the size of the free space. This file will be then  {
338     overwritten with random and static pattern. */      struct stat statbuf;
339  int      char *new_name = NULL, *p = NULL, c;  
340  wipe_freespace (const char * drive, HANDLE *r_fd,      int i = 0, rc = 0;
341                  void (*cb)(void *, DDWORD, DDWORD), void * cb_value)      int is_dir = 0;
342  {  
343      ULARGE_INTEGER caller, total, frees;      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
344      LONG hpart=0;          is_dir = 1;
345      HANDLE fd;      
346      int disktyp = GetDriveType (drive);      new_name = new char[strlen (path)+15];
347      int rc;      if (!new_name)
348      char * file;          BUG (0);
349        
350      if (disktyp != DRIVE_FIXED && disktyp != DRIVE_REMOVABLE)      strcpy (new_name, path);
351          return -1;      p = strrchr (new_name, '\\');
352      if (!GetDiskFreeSpaceEx (drive, &caller, &total, &frees))      if (p != NULL) {
353          return -1;            p++;
354            *p = '\0';
355      /* disk is full */      }
356      if (!frees.LowPart)      else
357          return 0;          p = new_name;
358      file = new char[strlen (drive)+8];      do {
359      if (!file)          while (i < 14) {
360          BUG (0);              c = random_char ();
361      sprintf (file, "%stemp_winpt.tmp", drive);              *p = c;
362      fd = CreateFile (file,              p++;
363                      GENERIC_READ|GENERIC_WRITE,              i++;
364                      FILE_SHARE_READ|FILE_SHARE_WRITE,          }
365                      NULL, CREATE_ALWAYS, 0, NULL);          *p = '\0';
366      if (fd == INVALID_HANDLE_VALUE) {      } while (stat (new_name, &statbuf) == 0);
367          free_if_alloc (file);      
368          return WPTERR_FILE_OPEN;      if (rename (path, new_name) == -1) {
369      }          rc = WPTERR_FILE_READ;
370      hpart = frees.HighPart;          goto leave;
371      SetFilePointer (fd, frees.LowPart, &hpart, FILE_BEGIN);      }
372      SetEndOfFile (fd);      if (is_dir && RemoveDirectory (new_name) == FALSE)
373      CloseHandle (fd);          rc = WPTERR_FILE_REMOVE;
374        else if (!DeleteFile (new_name))
375      if (cb && cb_value) {          rc = WPTERR_FILE_REMOVE;
376          progress_cb = cb;      
377          progress_cb_value = cb_value;  leave:
378      }      free_if_alloc (new_name);
379      rc = _secure_unlink (file, WIPE_MODE_FAST, r_fd);      return rc;
380      free_if_alloc (file);  }
381      return rc;  
382  }  
383    /* return the filesize as an 64-bit integer. */
384    static DDWORD
385    GetFileSize64 (const char * path)
386    {
387        FILE *fp = fopen (path, "r");
388        if (fp) {
389            struct _stati64 statbuf;
390            if (_fstati64 (fileno (fp), &statbuf) == -1)
391                return -1;
392            fclose (fp);
393            return statbuf.st_size;
394        }
395        return -1;
396    }
397    
398    
399    static int
400    _secure_unlink (const char * path, int mode, HANDLE *r_fd)
401    {
402        wipe_context_s ctx;
403        LONG size_high = 0;
404        
405        if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
406            return rename_unlink (path);
407        
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.23  
changed lines
  Added in v.53

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26