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

Contents of /trunk/PTD/wptWipeFile.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations)
Mon Jan 31 11:02:21 2005 UTC (20 years, 1 month ago) by twoaday
File size: 11007 byte(s)
WinPT initial checkin.


1 /* wptWipeFile.cpp - Secure file removal
2 * Copyright (C) 2001-2005 Timo Schulz
3 * Copyright (C) 2000 Matt Gauthier
4 *
5 * WinPT software; you can redistribute it and/or modify
6 * 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
8 * (at your option) any later version.
9 *
10 * WinPT is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with WinPT; if not, write to the Free Software
17 * 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 *
21 * it was heavily modified to work with W32 and with added GCRYPT *
22 * support for gathering random bytes. *
23 * *
24 * 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.*
26 **************************************************************************
27 */
28
29 #include <windows.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/stat.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <direct.h>
36
37 #include "openpgp.h"
38 #include "wptW32API.h"
39 #include "wptErrors.h"
40 #include "wptTypes.h"
41
42
43 typedef unsigned __int64 DDWORD;
44
45 typedef struct {
46 HANDLE fd;
47 DDWORD filesize;
48 DDWORD offset;
49 BYTE *buffer;
50 DWORD buffsize;
51 const char *name;
52 int n_passes;
53 } wipe_context_s;
54
55
56 void (*progress_cb) (void *, DDWORD, DDWORD);
57 static void *progress_cb_value = NULL;
58
59 void (*unlink_cb)(void *, const char *, int, unsigned, unsigned) = NULL;
60 static void *unlink_cb_value = NULL;
61
62 static void
63 overwrite (wipe_context_s * ctx)
64 {
65 DDWORD blocks = 0, mod = 0;
66 DWORD nwritten = 0;
67 LONG size_high = 0;
68
69 blocks = ctx->filesize / ctx->buffsize;
70 mod = ctx->filesize % ctx->buffsize;
71 SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
72 while (blocks--) {
73 if (!WriteFile (ctx->fd, ctx->buffer, ctx->buffsize, &nwritten, NULL))
74 break;
75 ctx->offset += nwritten;
76 if (unlink_cb)
77 unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
78 (unsigned)ctx->filesize*ctx->n_passes);
79 }
80 if (mod) {
81 WriteFile (ctx->fd, ctx->buffer, (DWORD)mod, &nwritten, NULL);
82 ctx->offset += nwritten;
83 if (unlink_cb)
84 unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
85 (unsigned)ctx->filesize*ctx->n_passes);
86 }
87 FlushFileBuffers (ctx->fd);
88 SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
89 } /* overwrite */
90
91
92 static void
93 randomize_buffer (byte * buf, size_t bufsize, int level)
94 {
95 const int blocksize = 512;
96 int blocks = bufsize / blocksize;
97 int mod = bufsize % blocksize;
98
99 while (blocks--) {
100 gpg_randomize (buf, blocksize, level);
101 buf += blocksize;
102 }
103 if (mod)
104 gpg_randomize (buf, mod, level);
105 } /* randomize_buffer */
106
107
108 static void
109 overwrite_random (int npasses, wipe_context_s * ctx)
110 {
111 int i;
112
113 for (i = 0; i < npasses; i++) {
114 randomize_buffer (ctx->buffer, ctx->buffsize, 0);
115 overwrite (ctx);
116 }
117 } /* overwrite_random */
118
119
120 static void
121 overwrite_byte (int byte, wipe_context_s * ctx)
122 {
123 memset (ctx->buffer, byte, ctx->buffsize);
124 overwrite (ctx);
125 } /* overwrite_byte */
126
127
128 static void
129 overwrite_bytes (int byte1, int byte2, int byte3, wipe_context_s * ctx)
130 {
131 DWORD i;
132
133 memset (ctx->buffer, byte1, ctx->buffsize);
134 for (i = 1; i < ctx->buffsize; i += 3) {
135 ctx->buffer[i] = byte2;
136 ctx->buffer[i+1] = byte3;
137 }
138 overwrite (ctx);
139 } /* overwrite_bytes */
140
141
142 /**
143 * For the case the file is not a regular file (this is true for
144 * devices or directories) this function tries to rename the file
145 * to random pattern and then it will be delete (without random!).
146 **/
147 int
148 rename_unlink (const char * path)
149 {
150 struct stat statbuf;
151 char * new_name = NULL, * p = NULL, c;
152 int i = 0, rc = 0;
153 int is_dir = 0;
154
155 if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
156 is_dir = 1;
157
158 new_name = new char[strlen (path)+15];
159 if (!new_name)
160 BUG (0);
161
162 strcpy (new_name, path);
163 p = strrchr (new_name, '\\');
164 if (p != NULL) {
165 p++;
166 *p = '\0';
167 }
168 else
169 p = new_name;
170 do {
171 while (i < 14) {
172 c = gpg_random_char (1);
173 *p = c;
174 p++;
175 i++;
176 }
177 *p = '\0';
178 } while (stat (new_name, &statbuf) == 0);
179
180 if (rename (path, new_name) == -1) {
181 rc = WPTERR_FILE_READ;
182 goto leave;
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
189 leave:
190 free_if_alloc (new_name);
191 return rc;
192 } /* rename_unlink */
193
194
195 static __int64
196 GetFileSize64 (const char * path)
197 {
198 FILE *fp = fopen (path, "r");
199 if (fp) {
200 struct _stati64 statbuf;
201 _fstati64 (fileno (fp), &statbuf);
202 fclose (fp);
203 return statbuf.st_size;
204 }
205 return -1;
206 } /* GetFileSize64 */
207
208
209 static int
210 _secure_unlink (const char * path, int mode, HANDLE *r_fd)
211 {
212 wipe_context_s ctx;
213 LONG size_high = 0;
214
215 if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
216 return rename_unlink (path);
217
218 memset (&ctx, 0, sizeof (ctx));
219 ctx.name = path;
220 ctx.buffsize = 16384;
221 ctx.buffer = new byte[ctx.buffsize];
222 if (!ctx.buffer)
223 BUG (0);
224
225 ctx.filesize = GetFileSize64 (path);
226 if (!ctx.filesize) {
227 free_if_alloc (ctx.buffer);
228 return WPTERR_FILE_ZERO;
229 }
230
231 ctx.fd = CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
232 OPEN_ALWAYS, 0, NULL);
233 if (ctx.fd == INVALID_HANDLE_VALUE) {
234 free_if_alloc (ctx.buffer);
235 return WPTERR_FILE_OPEN;
236 }
237 else if (r_fd)
238 *r_fd = ctx.fd;
239
240 gpg_quick_random_gen (1);
241 if (unlink_cb)
242 unlink_cb (unlink_cb_value, ctx.name, 0, 0, 0);
243
244 switch (mode) {
245 case WIPE_MODE_FAST:
246 ctx.n_passes = 1;
247 overwrite_random (1, &ctx);
248 break;
249
250 case WIPE_MODE_SIMPLE:
251 ctx.n_passes = 2;
252 overwrite_random (2, &ctx);
253 break;
254
255 case WIPE_MODE_DOD:
256 ctx.n_passes = 5;
257 overwrite_random (1, &ctx);
258 overwrite_byte ((~1) & 0xFF, &ctx);
259 overwrite_random (1, &ctx);
260 overwrite_byte ((~4) & 0xFF, &ctx);
261 overwrite_random (1, &ctx);
262 break;
263
264 case WIPE_MODE_GUTMANN:
265 ctx.n_passes = 39;
266 overwrite_random (4, &ctx);
267 overwrite_byte( 0x55, &ctx );
268 overwrite_byte ( 0xAA, &ctx );
269 overwrite_bytes( 0x92, 0x49, 0x24, &ctx );
270 overwrite_bytes( 0x49, 0x24, 0x92, &ctx );
271 overwrite_bytes( 0x24, 0x92, 0x49, &ctx );
272 overwrite_byte( 0x00, &ctx );
273 overwrite_byte( 0x11, &ctx );
274 overwrite_byte( 0x22, &ctx );
275 overwrite_byte( 0x33, &ctx );
276 overwrite_byte( 0x44, &ctx );
277 overwrite_byte( 0x55, &ctx );
278 overwrite_byte( 0x66, &ctx );
279 overwrite_byte( 0x77, &ctx );
280 overwrite_byte( 0x88, &ctx );
281 overwrite_byte( 0x99, &ctx );
282 overwrite_byte( 0xAA, &ctx );
283 overwrite_byte( 0xBB, &ctx );
284 overwrite_byte( 0xCC, &ctx );
285 overwrite_byte( 0xDD, &ctx );
286 overwrite_byte( 0xEE, &ctx );
287 overwrite_byte( 0xFF, &ctx );
288 overwrite_bytes( 0x92, 0x49, 0x24, &ctx );
289 overwrite_bytes( 0x49, 0x24, 0x92, &ctx );
290 overwrite_bytes( 0x24, 0x92, 0x49, &ctx );
291 overwrite_bytes( 0x6D, 0xB6, 0xDB, &ctx );
292 overwrite_bytes( 0xB6, 0xDB, 0x6D, &ctx );
293 overwrite_bytes( 0xDB, 0x6D, 0xB6, &ctx );
294 overwrite_random( 4, &ctx );
295 break;
296 }
297
298 /* Set file length to zero so allocated clusters cannot be trailed */
299 SetFilePointer (ctx.fd, 0, &size_high, FILE_BEGIN);
300 SetEndOfFile (ctx.fd);
301 CloseHandle (ctx.fd);
302
303 memset (ctx.buffer, 0, ctx.buffsize); /* burn the last evidence */
304 free_if_alloc (ctx.buffer);
305
306 return rename_unlink (path);
307 }
308
309 int
310 secure_unlink (const char *path, int mode)
311 {
312 return _secure_unlink (path, mode, NULL);
313 } /* secure_unlink */
314
315
316
317 void
318 secure_unlink_set_cb (void (*cb)(void *, const char *, int, unsigned, unsigned),
319 void *cb_value)
320 {
321 unlink_cb = cb;
322 unlink_cb_value = cb_value;
323 } /* secure_unlink_set_cb */
324
325
326 /* Windows 98 - Q188074 */
327 #define REGISTRY_FILESYSTEM "System\\CurrentControlSet\\Control\\FileSystem"
328 #define REGISTRY_LOWDISKSPACE "DisableLowDiskSpaceBroadcast"
329
330
331 /* disables the annoying warning Windows 98 displays when disk space is low */
332 static void
333 handle_lowdiskspace_notify( const char * drive, int disable )
334 {
335 OSVERSIONINFO ov;
336 HKEY key;
337 DWORD n;
338
339 memset( &ov, 0, sizeof ov );
340 ov.dwOSVersionInfoSize = sizeof ov;
341 GetVersionEx( &ov );
342 if( ov.dwPlatformId == VER_PLATFORM_WIN32_NT )
343 return;
344
345 if( disable ) {
346 unsigned newi = (1 << (toupper((unsigned)drive) - (unsigned)'A'));
347 if( RegOpenKey( HKEY_LOCAL_MACHINE, REGISTRY_FILESYSTEM, &key ) ) {
348 n = sizeof newi;
349 RegSetValue( key, REGISTRY_LOWDISKSPACE, REG_DWORD, (LPCTSTR)newi, n );
350 RegCloseKey( key );
351 }
352 }
353 else {
354 if( RegOpenKey( HKEY_LOCAL_MACHINE, REGISTRY_FILESYSTEM, &key ) ) {
355 RegDeleteKey( key, REGISTRY_LOWDISKSPACE );
356 RegCloseKey( key );
357 }
358 }
359 } /* handle_lowdiskspace_notify */
360
361
362 int
363 wipe_freespace (const char * drive, HANDLE *r_fd,
364 void (*cb)(void *, DDWORD, DDWORD), void * cb_value)
365 {
366 ULARGE_INTEGER caller, total, frees;
367 LONG hpart=0;
368 HANDLE fd;
369 int disktyp = GetDriveType (drive);
370 int rc;
371 char * file;
372
373 if (disktyp != DRIVE_FIXED && disktyp != DRIVE_REMOVABLE)
374 return -1;
375 if (!GetDiskFreeSpaceEx (drive, &caller, &total, &frees))
376 return -1;
377 handle_lowdiskspace_notify (drive, 1);
378
379 if (!frees.LowPart)
380 return WPTERR_FILE_ZERO;
381 file = new char[strlen (drive)+8];
382 if (!file)
383 BUG (0);
384 sprintf (file, "%stemp_winpt.tmp", drive);
385 fd = CreateFile (file,
386 GENERIC_READ|GENERIC_WRITE,
387 FILE_SHARE_READ|FILE_SHARE_WRITE,
388 NULL, CREATE_ALWAYS, 0, NULL);
389 if (fd == INVALID_HANDLE_VALUE) {
390 free_if_alloc (file);
391 return WPTERR_FILE_OPEN;
392 }
393 hpart = frees.HighPart;
394 SetFilePointer (fd, frees.LowPart, &hpart, FILE_BEGIN);
395 SetEndOfFile (fd);
396 CloseHandle (fd);
397
398 if (cb && cb_value) {
399 progress_cb = cb;
400 progress_cb_value = cb_value;
401 }
402 rc = _secure_unlink (file, WIPE_MODE_FAST, r_fd);
403
404 handle_lowdiskspace_notify (drive, 0);
405 free_if_alloc (file);
406 return rc;
407 } /* wipe_freespace */

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26