Line data Source code
1 : /* shred.c - overwrite files and devices to make it harder to recover data
2 :
3 : Copyright (C) 1999-2007 Free Software Foundation, Inc.
4 : Copyright (C) 1997, 1998, 1999 Colin Plumb.
5 :
6 : This program is free software: you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation, either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 :
19 : Written by Colin Plumb. */
20 :
21 : /* TODO:
22 : - use consistent non-capitalization in error messages
23 : - add standard GNU copyleft comment
24 :
25 : - Add -r/-R/--recursive
26 : - Add -i/--interactive
27 : - Reserve -d
28 : - Add -L
29 : - Add an unlink-all option to emulate rm.
30 : */
31 :
32 : /*
33 : * Do a more secure overwrite of given files or devices, to make it harder
34 : * for even very expensive hardware probing to recover the data.
35 : *
36 : * Although this process is also known as "wiping", I prefer the longer
37 : * name both because I think it is more evocative of what is happening and
38 : * because a longer name conveys a more appropriate sense of deliberateness.
39 : *
40 : * For the theory behind this, see "Secure Deletion of Data from Magnetic
41 : * and Solid-State Memory", on line at
42 : * http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html
43 : *
44 : * Just for the record, reversing one or two passes of disk overwrite
45 : * is not terribly difficult with hardware help. Hook up a good-quality
46 : * digitizing oscilloscope to the output of the head preamplifier and copy
47 : * the high-res digitized data to a computer for some off-line analysis.
48 : * Read the "current" data and average all the pulses together to get an
49 : * "average" pulse on the disk. Subtract this average pulse from all of
50 : * the actual pulses and you can clearly see the "echo" of the previous
51 : * data on the disk.
52 : *
53 : * Real hard drives have to balance the cost of the media, the head,
54 : * and the read circuitry. They use better-quality media than absolutely
55 : * necessary to limit the cost of the read circuitry. By throwing that
56 : * assumption out, and the assumption that you want the data processed
57 : * as fast as the hard drive can spin, you can do better.
58 : *
59 : * If asked to wipe a file, this also unlinks it, renaming it to in a
60 : * clever way to try to leave no trace of the original filename.
61 : *
62 : * This was inspired by a desire to improve on some code titled:
63 : * Wipe V1.0-- Overwrite and delete files. S. 2/3/96
64 : * but I've rewritten everything here so completely that no trace of
65 : * the original remains.
66 : *
67 : * Thanks to:
68 : * Bob Jenkins, for his good RNG work and patience with the FSF copyright
69 : * paperwork.
70 : * Jim Meyering, for his work merging this into the GNU fileutils while
71 : * still letting me feel a sense of ownership and pride. Getting me to
72 : * tolerate the GNU brace style was quite a feat of diplomacy.
73 : * Paul Eggert, for lots of useful discussion and code. I disagree with
74 : * an awful lot of his suggestions, but they're disagreements worth having.
75 : *
76 : * Things to think about:
77 : * - Security: Is there any risk to the race
78 : * between overwriting and unlinking a file? Will it do anything
79 : * drastically bad if told to attack a named pipe or socket?
80 : */
81 :
82 : /* The official name of this program (e.g., no `g' prefix). */
83 : #define PROGRAM_NAME "shred"
84 :
85 : #define AUTHORS "Colin Plumb"
86 :
87 : #include <config.h>
88 :
89 : #include <getopt.h>
90 : #include <stdio.h>
91 : #include <assert.h>
92 : #include <setjmp.h>
93 : #include <sys/types.h>
94 :
95 : #include "system.h"
96 : #include "xstrtol.h"
97 : #include "error.h"
98 : #include "fcntl--.h"
99 : #include "human.h"
100 : #include "inttostr.h"
101 : #include "quotearg.h" /* For quotearg_colon */
102 : #include "randint.h"
103 : #include "randread.h"
104 :
105 : /* Default number of times to overwrite. */
106 : enum { DEFAULT_PASSES = 25 };
107 :
108 : /* How many seconds to wait before checking whether to output another
109 : verbose output line. */
110 : enum { VERBOSE_UPDATE = 5 };
111 :
112 : /* Sector size and corresponding mask, for recovering after write failures.
113 : The size must be a power of 2. */
114 : enum { SECTOR_SIZE = 512 };
115 : enum { SECTOR_MASK = SECTOR_SIZE - 1 };
116 : verify (0 < SECTOR_SIZE && (SECTOR_SIZE & SECTOR_MASK) == 0);
117 :
118 : struct Options
119 : {
120 : bool force; /* -f flag: chmod files if necessary */
121 : size_t n_iterations; /* -n flag: Number of iterations */
122 : off_t size; /* -s flag: size of file */
123 : bool remove_file; /* -u flag: remove file after shredding */
124 : bool verbose; /* -v flag: Print progress */
125 : bool exact; /* -x flag: Do not round up file size */
126 : bool zero_fill; /* -z flag: Add a final zero pass */
127 : };
128 :
129 : /* For long options that have no equivalent short option, use a
130 : non-character as a pseudo short option, starting with CHAR_MAX + 1. */
131 : enum
132 : {
133 : RANDOM_SOURCE_OPTION = CHAR_MAX + 1
134 : };
135 :
136 : static struct option const long_opts[] =
137 : {
138 : {"exact", no_argument, NULL, 'x'},
139 : {"force", no_argument, NULL, 'f'},
140 : {"iterations", required_argument, NULL, 'n'},
141 : {"size", required_argument, NULL, 's'},
142 : {"random-source", required_argument, NULL, RANDOM_SOURCE_OPTION},
143 : {"remove", no_argument, NULL, 'u'},
144 : {"verbose", no_argument, NULL, 'v'},
145 : {"zero", no_argument, NULL, 'z'},
146 : {GETOPT_HELP_OPTION_DECL},
147 : {GETOPT_VERSION_OPTION_DECL},
148 : {NULL, 0, NULL, 0}
149 : };
150 :
151 : /* Global variable for error printing purposes */
152 : char const *program_name; /* Initialized before any possible use */
153 :
154 : void
155 30 : usage (int status)
156 : {
157 30 : if (status != EXIT_SUCCESS)
158 29 : fprintf (stderr, _("Try `%s --help' for more information.\n"),
159 : program_name);
160 : else
161 : {
162 1 : printf (_("Usage: %s [OPTIONS] FILE [...]\n"), program_name);
163 1 : fputs (_("\
164 : Overwrite the specified FILE(s) repeatedly, in order to make it harder\n\
165 : for even very expensive hardware probing to recover the data.\n\
166 : \n\
167 : "), stdout);
168 1 : fputs (_("\
169 : Mandatory arguments to long options are mandatory for short options too.\n\
170 : "), stdout);
171 1 : printf (_("\
172 : -f, --force change permissions to allow writing if necessary\n\
173 : -n, --iterations=N Overwrite N times instead of the default (%d)\n\
174 : --random-source=FILE get random bytes from FILE (default /dev/urandom)\n\
175 : -s, --size=N shred this many bytes (suffixes like K, M, G accepted)\n\
176 : "), DEFAULT_PASSES);
177 1 : fputs (_("\
178 : -u, --remove truncate and remove file after overwriting\n\
179 : -v, --verbose show progress\n\
180 : -x, --exact do not round file sizes up to the next full block;\n\
181 : this is the default for non-regular files\n\
182 : -z, --zero add a final overwrite with zeros to hide shredding\n\
183 : "), stdout);
184 1 : fputs (HELP_OPTION_DESCRIPTION, stdout);
185 1 : fputs (VERSION_OPTION_DESCRIPTION, stdout);
186 1 : fputs (_("\
187 : \n\
188 : If FILE is -, shred standard output.\n\
189 : \n\
190 : Delete FILE(s) if --remove (-u) is specified. The default is not to remove\n\
191 : the files because it is common to operate on device files like /dev/hda,\n\
192 : and those files usually should not be removed. When operating on regular\n\
193 : files, most people use the --remove option.\n\
194 : \n\
195 : "), stdout);
196 1 : fputs (_("\
197 : CAUTION: Note that shred relies on a very important assumption:\n\
198 : that the file system overwrites data in place. This is the traditional\n\
199 : way to do things, but many modern file system designs do not satisfy this\n\
200 : assumption. The following are examples of file systems on which shred is\n\
201 : not effective, or is not guaranteed to be effective in all file system modes:\n\
202 : \n\
203 : "), stdout);
204 1 : fputs (_("\
205 : * log-structured or journaled file systems, such as those supplied with\n\
206 : AIX and Solaris (and JFS, ReiserFS, XFS, Ext3, etc.)\n\
207 : \n\
208 : * file systems that write redundant data and carry on even if some writes\n\
209 : fail, such as RAID-based file systems\n\
210 : \n\
211 : * file systems that make snapshots, such as Network Appliance's NFS server\n\
212 : \n\
213 : "), stdout);
214 1 : fputs (_("\
215 : * file systems that cache in temporary locations, such as NFS\n\
216 : version 3 clients\n\
217 : \n\
218 : * compressed file systems\n\
219 : \n\
220 : "), stdout);
221 1 : fputs (_("\
222 : In the case of ext3 file systems, the above disclaimer applies\n\
223 : (and shred is thus of limited effectiveness) only in data=journal mode,\n\
224 : which journals file data in addition to just metadata. In both the\n\
225 : data=ordered (default) and data=writeback modes, shred works as usual.\n\
226 : Ext3 journaling modes can be changed by adding the data=something option\n\
227 : to the mount options for a particular file system in the /etc/fstab file,\n\
228 : as documented in the mount man page (man mount).\n\
229 : \n\
230 : "), stdout);
231 1 : fputs (_("\
232 : In addition, file system backups and remote mirrors may contain copies\n\
233 : of the file that cannot be removed, and that will allow a shredded file\n\
234 : to be recovered later.\n\
235 : "), stdout);
236 1 : emit_bug_reporting_address ();
237 : }
238 30 : exit (status);
239 : }
240 :
241 :
242 : /*
243 : * Fill a buffer with a fixed pattern.
244 : *
245 : * The buffer must be at least 3 bytes long, even if
246 : * size is less. Larger sizes are filled exactly.
247 : */
248 : static void
249 484 : fillpattern (int type, unsigned char *r, size_t size)
250 : {
251 : size_t i;
252 484 : unsigned int bits = type & 0xfff;
253 :
254 484 : bits |= bits << 12;
255 484 : r[0] = (bits >> 4) & 255;
256 484 : r[1] = (bits >> 8) & 255;
257 484 : r[2] = bits & 255;
258 5280 : for (i = 3; i < size / 2; i *= 2)
259 4796 : memcpy (r + i, r, i);
260 484 : if (i < size)
261 484 : memcpy (r + i, r, size - i);
262 :
263 : /* Invert the first bit of every sector. */
264 484 : if (type & 0x1000)
265 0 : for (i = 0; i < size; i += SECTOR_SIZE)
266 0 : r[i] ^= 0x80;
267 484 : }
268 :
269 : /*
270 : * Generate a 6-character (+ nul) pass name string
271 : * FIXME: allow translation of "random".
272 : */
273 : #define PASS_NAME_SIZE 7
274 : static void
275 550 : passname (unsigned char const *data, char name[PASS_NAME_SIZE])
276 : {
277 550 : if (data)
278 484 : sprintf (name, "%02x%02x%02x", data[0], data[1], data[2]);
279 : else
280 66 : memcpy (name, "random", PASS_NAME_SIZE);
281 550 : }
282 :
283 : /* Request that all data for FD be transferred to the corresponding
284 : storage device. QNAME is the file name (quoted for colons).
285 : Report any errors found. Return 0 on success, -1
286 : (setting errno) on failure. It is not an error if fdatasync and/or
287 : fsync is not supported for this file, or if the file is not a
288 : writable file descriptor. */
289 : static int
290 550 : dosync (int fd, char const *qname)
291 : {
292 : int err;
293 :
294 : #if HAVE_FDATASYNC
295 550 : if (fdatasync (fd) == 0)
296 550 : return 0;
297 0 : err = errno;
298 0 : if (err != EINVAL && err != EBADF)
299 : {
300 0 : error (0, err, _("%s: fdatasync failed"), qname);
301 0 : errno = err;
302 0 : return -1;
303 : }
304 : #endif
305 :
306 0 : if (fsync (fd) == 0)
307 0 : return 0;
308 0 : err = errno;
309 0 : if (err != EINVAL && err != EBADF)
310 : {
311 0 : error (0, err, _("%s: fsync failed"), qname);
312 0 : errno = err;
313 0 : return -1;
314 : }
315 :
316 0 : sync ();
317 0 : return 0;
318 : }
319 :
320 : /* Turn on or off direct I/O mode for file descriptor FD, if possible.
321 : Try to turn it on if ENABLE is true. Otherwise, try to turn it off. */
322 : static void
323 22 : direct_mode (int fd, bool enable)
324 : {
325 : if (O_DIRECT)
326 : {
327 22 : int fd_flags = fcntl (fd, F_GETFL);
328 22 : if (0 < fd_flags)
329 : {
330 22 : int new_flags = (enable
331 : ? (fd_flags | O_DIRECT)
332 22 : : (fd_flags & ~O_DIRECT));
333 22 : if (new_flags != fd_flags)
334 20 : fcntl (fd, F_SETFL, new_flags);
335 : }
336 : }
337 :
338 : #if HAVE_DIRECTIO && defined DIRECTIO_ON && defined DIRECTIO_OFF
339 : /* This is Solaris-specific. See the following for details:
340 : http://docs.sun.com/db/doc/816-0213/6m6ne37so?q=directio&a=view */
341 : directio (fd, enable ? DIRECTIO_ON : DIRECTIO_OFF);
342 : #endif
343 22 : }
344 :
345 : /*
346 : * Do pass number k of n, writing "size" bytes of the given pattern "type"
347 : * to the file descriptor fd. Qname, k and n are passed in only for verbose
348 : * progress message purposes. If n == 0, no progress messages are printed.
349 : *
350 : * If *sizep == -1, the size is unknown, and it will be filled in as soon
351 : * as writing fails.
352 : *
353 : * Return 1 on write error, -1 on other error, 0 on success.
354 : */
355 : static int
356 550 : dopass (int fd, char const *qname, off_t *sizep, int type,
357 : struct randread_source *s, unsigned long int k, unsigned long int n)
358 : {
359 550 : off_t size = *sizep;
360 : off_t offset; /* Current file posiiton */
361 : time_t thresh IF_LINT (= 0); /* Time to maybe print next status update */
362 550 : time_t now = 0; /* Current time */
363 : size_t lim; /* Amount of data to try writing */
364 : size_t soff; /* Offset into buffer for next write */
365 : ssize_t ssize; /* Return value from write */
366 :
367 : /* Fill pattern buffer. Aligning it to a 32-bit boundary speeds up randread
368 : in some cases. */
369 : typedef uint32_t fill_pattern_buffer[3 * 1024];
370 : union
371 : {
372 : fill_pattern_buffer buffer;
373 : char c[sizeof (fill_pattern_buffer)];
374 : unsigned char u[sizeof (fill_pattern_buffer)];
375 : } r;
376 :
377 550 : off_t sizeof_r = sizeof r;
378 : char pass_string[PASS_NAME_SIZE]; /* Name of current pass */
379 550 : bool write_error = false;
380 550 : bool first_write = true;
381 :
382 : /* Printable previous offset into the file */
383 : char previous_offset_buf[LONGEST_HUMAN_READABLE + 1];
384 : char const *previous_human_offset IF_LINT (= 0);
385 :
386 550 : if (lseek (fd, 0, SEEK_SET) == -1)
387 : {
388 0 : error (0, errno, _("%s: cannot rewind"), qname);
389 0 : return -1;
390 : }
391 :
392 : /* Constant fill patterns need only be set up once. */
393 550 : if (type >= 0)
394 : {
395 484 : lim = (0 <= size && size < sizeof_r ? size : sizeof r);
396 484 : fillpattern (type, r.u, lim);
397 484 : passname (r.u, pass_string);
398 : }
399 : else
400 : {
401 66 : passname (0, pass_string);
402 : }
403 :
404 : /* Set position if first status update */
405 550 : if (n)
406 : {
407 125 : error (0, 0, _("%s: pass %lu/%lu (%s)..."), qname, k, n, pass_string);
408 125 : thresh = time (NULL) + VERBOSE_UPDATE;
409 125 : previous_human_offset = "";
410 : }
411 :
412 550 : offset = 0;
413 : for (;;)
414 : {
415 : /* How much to write this time? */
416 1650 : lim = sizeof r;
417 1100 : if (0 <= size && size - offset < sizeof_r)
418 : {
419 1100 : if (size < offset)
420 0 : break;
421 1100 : lim = size - offset;
422 1100 : if (!lim)
423 550 : break;
424 : }
425 550 : if (type < 0)
426 66 : randread (s, &r, lim);
427 : /* Loop to retry partial writes. */
428 1100 : for (soff = 0; soff < lim; soff += ssize, first_write = false)
429 : {
430 550 : ssize = write (fd, r.c + soff, lim - soff);
431 550 : if (ssize <= 0)
432 : {
433 0 : if (size < 0 && (ssize == 0 || errno == ENOSPC))
434 : {
435 : /* Ah, we have found the end of the file */
436 0 : *sizep = size = offset + soff;
437 0 : break;
438 : }
439 : else
440 : {
441 0 : int errnum = errno;
442 : char buf[INT_BUFSIZE_BOUND (uintmax_t)];
443 :
444 : /* If the first write of the first pass for a given file
445 : has just failed with EINVAL, turn off direct mode I/O
446 : and try again. This works around a bug in linux-2.4
447 : whereby opening with O_DIRECT would succeed for some
448 : file system types (e.g., ext3), but any attempt to
449 : access a file through the resulting descriptor would
450 : fail with EINVAL. */
451 0 : if (k == 1 && first_write && errno == EINVAL)
452 : {
453 0 : direct_mode (fd, false);
454 0 : ssize = 0;
455 0 : continue;
456 : }
457 0 : error (0, errnum, _("%s: error writing at offset %s"),
458 : qname, umaxtostr (offset + soff, buf));
459 :
460 : /* 'shred' is often used on bad media, before throwing it
461 : out. Thus, it shouldn't give up on bad blocks. This
462 : code works because lim is always a multiple of
463 : SECTOR_SIZE, except at the end. */
464 : verify (sizeof r % SECTOR_SIZE == 0);
465 0 : if (errnum == EIO && 0 <= size && (soff | SECTOR_MASK) < lim)
466 : {
467 0 : size_t soff1 = (soff | SECTOR_MASK) + 1;
468 0 : if (lseek (fd, offset + soff1, SEEK_SET) != -1)
469 : {
470 : /* Arrange to skip this block. */
471 0 : ssize = soff1 - soff;
472 0 : write_error = true;
473 0 : continue;
474 : }
475 0 : error (0, errno, _("%s: lseek failed"), qname);
476 : }
477 0 : return -1;
478 : }
479 : }
480 : }
481 :
482 : /* Okay, we have written "soff" bytes. */
483 :
484 550 : if (offset + soff < offset)
485 : {
486 0 : error (0, 0, _("%s: file too large"), qname);
487 0 : return -1;
488 : }
489 :
490 550 : offset += soff;
491 :
492 : /* Time to print progress? */
493 550 : if (n
494 125 : && ((offset == size && *previous_human_offset)
495 125 : || thresh <= (now = time (NULL))))
496 : {
497 : char offset_buf[LONGEST_HUMAN_READABLE + 1];
498 : char size_buf[LONGEST_HUMAN_READABLE + 1];
499 0 : int human_progress_opts = (human_autoscale | human_SI
500 : | human_base_1024 | human_B);
501 0 : char const *human_offset
502 0 : = human_readable (offset, offset_buf,
503 : human_floor | human_progress_opts, 1, 1);
504 :
505 0 : if (offset == size
506 0 : || !STREQ (previous_human_offset, human_offset))
507 : {
508 0 : if (size < 0)
509 0 : error (0, 0, _("%s: pass %lu/%lu (%s)...%s"),
510 : qname, k, n, pass_string, human_offset);
511 : else
512 : {
513 0 : uintmax_t off = offset;
514 0 : int percent = (size == 0
515 : ? 100
516 : : (off <= TYPE_MAXIMUM (uintmax_t) / 100
517 0 : ? off * 100 / size
518 0 : : off / (size / 100)));
519 0 : char const *human_size
520 0 : = human_readable (size, size_buf,
521 : human_ceiling | human_progress_opts,
522 : 1, 1);
523 0 : if (offset == size)
524 0 : human_offset = human_size;
525 0 : error (0, 0, _("%s: pass %lu/%lu (%s)...%s/%s %d%%"),
526 : qname, k, n, pass_string, human_offset, human_size,
527 : percent);
528 : }
529 :
530 0 : strcpy (previous_offset_buf, human_offset);
531 0 : previous_human_offset = previous_offset_buf;
532 0 : thresh = now + VERBOSE_UPDATE;
533 :
534 : /*
535 : * Force periodic syncs to keep displayed progress accurate
536 : * FIXME: Should these be present even if -v is not enabled,
537 : * to keep the buffer cache from filling with dirty pages?
538 : * It's a common problem with programs that do lots of writes,
539 : * like mkfs.
540 : */
541 0 : if (dosync (fd, qname) != 0)
542 : {
543 0 : if (errno != EIO)
544 0 : return -1;
545 0 : write_error = true;
546 : }
547 : }
548 : }
549 : }
550 :
551 : /* Force what we just wrote to hit the media. */
552 550 : if (dosync (fd, qname) != 0)
553 : {
554 0 : if (errno != EIO)
555 0 : return -1;
556 0 : write_error = true;
557 : }
558 :
559 550 : return write_error;
560 : }
561 :
562 : /*
563 : * The passes start and end with a random pass, and the passes in between
564 : * are done in random order. The idea is to deprive someone trying to
565 : * reverse the process of knowledge of the overwrite patterns, so they
566 : * have the additional step of figuring out what was done to the disk
567 : * before they can try to reverse or cancel it.
568 : *
569 : * First, all possible 1-bit patterns. There are two of them.
570 : * Then, all possible 2-bit patterns. There are four, but the two
571 : * which are also 1-bit patterns can be omitted.
572 : * Then, all possible 3-bit patterns. Likewise, 8-2 = 6.
573 : * Then, all possible 4-bit patterns. 16-4 = 12.
574 : *
575 : * The basic passes are:
576 : * 1-bit: 0x000, 0xFFF
577 : * 2-bit: 0x555, 0xAAA
578 : * 3-bit: 0x249, 0x492, 0x924, 0x6DB, 0xB6D, 0xDB6 (+ 1-bit)
579 : * 100100100100 110110110110
580 : * 9 2 4 D B 6
581 : * 4-bit: 0x111, 0x222, 0x333, 0x444, 0x666, 0x777,
582 : * 0x888, 0x999, 0xBBB, 0xCCC, 0xDDD, 0xEEE (+ 1-bit, 2-bit)
583 : * Adding three random passes at the beginning, middle and end
584 : * produces the default 25-pass structure.
585 : *
586 : * The next extension would be to 5-bit and 6-bit patterns.
587 : * There are 30 uncovered 5-bit patterns and 64-8-2 = 46 uncovered
588 : * 6-bit patterns, so they would increase the time required
589 : * significantly. 4-bit patterns are enough for most purposes.
590 : *
591 : * The main gotcha is that this would require a trickier encoding,
592 : * since lcm(2,3,4) = 12 bits is easy to fit into an int, but
593 : * lcm(2,3,4,5) = 60 bits is not.
594 : *
595 : * One extension that is included is to complement the first bit in each
596 : * 512-byte block, to alter the phase of the encoded data in the more
597 : * complex encodings. This doesn't apply to MFM, so the 1-bit patterns
598 : * are considered part of the 3-bit ones and the 2-bit patterns are
599 : * considered part of the 4-bit patterns.
600 : *
601 : *
602 : * How does the generalization to variable numbers of passes work?
603 : *
604 : * Here's how...
605 : * Have an ordered list of groups of passes. Each group is a set.
606 : * Take as many groups as will fit, plus a random subset of the
607 : * last partial group, and place them into the passes list.
608 : * Then shuffle the passes list into random order and use that.
609 : *
610 : * One extra detail: if we can't include a large enough fraction of the
611 : * last group to be interesting, then just substitute random passes.
612 : *
613 : * If you want more passes than the entire list of groups can
614 : * provide, just start repeating from the beginning of the list.
615 : */
616 : static int const
617 : patterns[] =
618 : {
619 : -2, /* 2 random passes */
620 : 2, 0x000, 0xFFF, /* 1-bit */
621 : 2, 0x555, 0xAAA, /* 2-bit */
622 : -1, /* 1 random pass */
623 : 6, 0x249, 0x492, 0x6DB, 0x924, 0xB6D, 0xDB6, /* 3-bit */
624 : 12, 0x111, 0x222, 0x333, 0x444, 0x666, 0x777,
625 : 0x888, 0x999, 0xBBB, 0xCCC, 0xDDD, 0xEEE, /* 4-bit */
626 : -1, /* 1 random pass */
627 : /* The following patterns have the frst bit per block flipped */
628 : 8, 0x1000, 0x1249, 0x1492, 0x16DB, 0x1924, 0x1B6D, 0x1DB6, 0x1FFF,
629 : 14, 0x1111, 0x1222, 0x1333, 0x1444, 0x1555, 0x1666, 0x1777,
630 : 0x1888, 0x1999, 0x1AAA, 0x1BBB, 0x1CCC, 0x1DDD, 0x1EEE,
631 : -1, /* 1 random pass */
632 : 0 /* End */
633 : };
634 :
635 : /*
636 : * Generate a random wiping pass pattern with num passes.
637 : * This is a two-stage process. First, the passes to include
638 : * are chosen, and then they are shuffled into the desired
639 : * order.
640 : */
641 : static void
642 22 : genpattern (int *dest, size_t num, struct randint_source *s)
643 : {
644 : size_t randpasses;
645 : int const *p;
646 : int *d;
647 : size_t n;
648 : size_t accum, top, swap;
649 : int k;
650 :
651 22 : if (!num)
652 0 : return;
653 :
654 : /* Stage 1: choose the passes to use */
655 22 : p = patterns;
656 22 : randpasses = 0;
657 22 : d = dest; /* Destination for generated pass list */
658 22 : n = num; /* Passes remaining to fill */
659 :
660 : for (;;)
661 : {
662 286 : k = *p++; /* Block descriptor word */
663 154 : if (!k)
664 : { /* Loop back to the beginning */
665 0 : p = patterns;
666 : }
667 154 : else if (k < 0)
668 : { /* -k random passes */
669 66 : k = -k;
670 66 : if ((size_t) k >= n)
671 : {
672 22 : randpasses += n;
673 22 : n = 0;
674 22 : break;
675 : }
676 44 : randpasses += k;
677 44 : n -= k;
678 : }
679 88 : else if ((size_t) k <= n)
680 : { /* Full block of patterns */
681 88 : memcpy (d, p, k * sizeof (int));
682 88 : p += k;
683 88 : d += k;
684 88 : n -= k;
685 : }
686 0 : else if (n < 2 || 3 * n < (size_t) k)
687 : { /* Finish with random */
688 0 : randpasses += n;
689 0 : break;
690 : }
691 : else
692 : { /* Pad out with k of the n available */
693 : do
694 : {
695 0 : if (n == (size_t) k || randint_choose (s, k) < n)
696 : {
697 0 : *d++ = *p;
698 0 : n--;
699 : }
700 0 : p++;
701 : }
702 0 : while (n);
703 0 : break;
704 : }
705 : }
706 22 : top = num - randpasses; /* Top of initialized data */
707 : /* assert (d == dest+top); */
708 :
709 : /*
710 : * We now have fixed patterns in the dest buffer up to
711 : * "top", and we need to scramble them, with "randpasses"
712 : * random passes evenly spaced among them.
713 : *
714 : * We want one at the beginning, one at the end, and
715 : * evenly spaced in between. To do this, we basically
716 : * use Bresenham's line draw (a.k.a DDA) algorithm
717 : * to draw a line with slope (randpasses-1)/(num-1).
718 : * (We use a positive accumulator and count down to
719 : * do this.)
720 : *
721 : * So for each desired output value, we do the following:
722 : * - If it should be a random pass, copy the pass type
723 : * to top++, out of the way of the other passes, and
724 : * set the current pass to -1 (random).
725 : * - If it should be a normal pattern pass, choose an
726 : * entry at random between here and top-1 (inclusive)
727 : * and swap the current entry with that one.
728 : */
729 22 : randpasses--; /* To speed up later math */
730 22 : accum = randpasses; /* Bresenham DDA accumulator */
731 572 : for (n = 0; n < num; n++)
732 : {
733 550 : if (accum <= randpasses)
734 : {
735 66 : accum += num - 1;
736 66 : dest[top++] = dest[n];
737 66 : dest[n] = -1;
738 : }
739 : else
740 : {
741 484 : swap = n + randint_choose (s, top - n);
742 484 : k = dest[n];
743 484 : dest[n] = dest[swap];
744 484 : dest[swap] = k;
745 : }
746 550 : accum -= randpasses;
747 : }
748 : /* assert (top == num); */
749 : }
750 :
751 : /*
752 : * The core routine to actually do the work. This overwrites the first
753 : * size bytes of the given fd. Return true if successful.
754 : */
755 : static bool
756 63 : do_wipefd (int fd, char const *qname, struct randint_source *s,
757 : struct Options const *flags)
758 : {
759 : size_t i;
760 : struct stat st;
761 : off_t size; /* Size to write, size to read */
762 : unsigned long int n; /* Number of passes for printing purposes */
763 : int *passarray;
764 63 : bool ok = true;
765 : struct randread_source *rs;
766 :
767 63 : n = 0; /* dopass takes n -- 0 to mean "don't print progress" */
768 63 : if (flags->verbose)
769 7 : n = flags->n_iterations + flags->zero_fill;
770 :
771 63 : if (fstat (fd, &st))
772 : {
773 0 : error (0, errno, _("%s: fstat failed"), qname);
774 0 : return false;
775 : }
776 :
777 : /* If we know that we can't possibly shred the file, give up now.
778 : Otherwise, we may go into a infinite loop writing data before we
779 : find that we can't rewind the device. */
780 63 : if ((S_ISCHR (st.st_mode) && isatty (fd))
781 25 : || S_ISFIFO (st.st_mode)
782 22 : || S_ISSOCK (st.st_mode))
783 : {
784 41 : error (0, 0, _("%s: invalid file type"), qname);
785 41 : return false;
786 : }
787 :
788 22 : direct_mode (fd, true);
789 :
790 : /* Allocate pass array */
791 22 : passarray = xnmalloc (flags->n_iterations, sizeof *passarray);
792 :
793 22 : size = flags->size;
794 22 : if (size == -1)
795 : {
796 : /* Accept a length of zero only if it's a regular file.
797 : For any other type of file, try to get the size another way. */
798 22 : if (S_ISREG (st.st_mode))
799 : {
800 22 : size = st.st_size;
801 22 : if (size < 0)
802 : {
803 0 : error (0, 0, _("%s: file has negative size"), qname);
804 0 : return false;
805 : }
806 : }
807 : else
808 : {
809 0 : size = lseek (fd, 0, SEEK_END);
810 0 : if (size <= 0)
811 : {
812 : /* We are unable to determine the length, up front.
813 : Let dopass do that as part of its first iteration. */
814 0 : size = -1;
815 : }
816 : }
817 :
818 : /* Allow `rounding up' only for regular files. */
819 22 : if (0 <= size && !(flags->exact) && S_ISREG (st.st_mode))
820 : {
821 21 : size += ST_BLKSIZE (st) - 1 - (size - 1) % ST_BLKSIZE (st);
822 :
823 : /* If in rounding up, we've just overflowed, use the maximum. */
824 21 : if (size < 0)
825 0 : size = TYPE_MAXIMUM (off_t);
826 : }
827 : }
828 :
829 : /* Schedule the passes in random order. */
830 22 : genpattern (passarray, flags->n_iterations, s);
831 :
832 22 : rs = randint_get_source (s);
833 :
834 : /* Do the work */
835 572 : for (i = 0; i < flags->n_iterations; i++)
836 : {
837 550 : int err = dopass (fd, qname, &size, passarray[i], rs, i + 1, n);
838 550 : if (err)
839 : {
840 0 : if (err < 0)
841 : {
842 0 : memset (passarray, 0, flags->n_iterations * sizeof (int));
843 0 : free (passarray);
844 0 : return false;
845 : }
846 0 : ok = false;
847 : }
848 : }
849 :
850 22 : memset (passarray, 0, flags->n_iterations * sizeof (int));
851 22 : free (passarray);
852 :
853 22 : if (flags->zero_fill)
854 : {
855 0 : int err = dopass (fd, qname, &size, 0, rs, flags->n_iterations + 1, n);
856 0 : if (err)
857 : {
858 0 : if (err < 0)
859 0 : return false;
860 0 : ok = false;
861 : }
862 : }
863 :
864 : /* Okay, now deallocate the data. The effect of ftruncate on
865 : non-regular files is unspecified, so don't worry about any
866 : errors reported for them. */
867 22 : if (flags->remove_file && ftruncate (fd, 0) != 0
868 0 : && S_ISREG (st.st_mode))
869 : {
870 0 : error (0, errno, _("%s: error truncating"), qname);
871 0 : return false;
872 : }
873 :
874 22 : return ok;
875 : }
876 :
877 : /* A wrapper with a little more checking for fds on the command line */
878 : static bool
879 56 : wipefd (int fd, char const *qname, struct randint_source *s,
880 : struct Options const *flags)
881 : {
882 56 : int fd_flags = fcntl (fd, F_GETFL);
883 :
884 56 : if (fd_flags < 0)
885 : {
886 0 : error (0, errno, _("%s: fcntl failed"), qname);
887 0 : return false;
888 : }
889 56 : if (fd_flags & O_APPEND)
890 : {
891 0 : error (0, 0, _("%s: cannot shred append-only file descriptor"), qname);
892 0 : return false;
893 : }
894 56 : return do_wipefd (fd, qname, s, flags);
895 : }
896 :
897 : /* --- Name-wiping code --- */
898 :
899 : /* Characters allowed in a file name - a safe universal set. */
900 : static char const nameset[] =
901 : "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_.";
902 :
903 : /* Increment NAME (with LEN bytes). NAME must be a big-endian base N
904 : number with the digits taken from nameset. Return true if
905 : successful if not (because NAME already has the greatest possible
906 : value. */
907 :
908 : static bool
909 0 : incname (char *name, size_t len)
910 : {
911 0 : while (len--)
912 : {
913 0 : char const *p = strchr (nameset, name[len]);
914 :
915 : /* If this character has a successor, use it. */
916 0 : if (p[1])
917 : {
918 0 : name[len] = p[1];
919 0 : return true;
920 : }
921 :
922 : /* Otherwise, set this digit to 0 and increment the prefix. */
923 0 : name[len] = nameset[0];
924 : }
925 :
926 0 : return false;
927 : }
928 :
929 : /*
930 : * Repeatedly rename a file with shorter and shorter names,
931 : * to obliterate all traces of the file name on any system that
932 : * adds a trailing delimiter to on-disk file names and reuses
933 : * the same directory slot. Finally, unlink it.
934 : * The passed-in filename is modified in place to the new filename.
935 : * (Which is unlinked if this function succeeds, but is still present if
936 : * it fails for some reason.)
937 : *
938 : * The main loop is written carefully to not get stuck if all possible
939 : * names of a given length are occupied. It counts down the length from
940 : * the original to 0. While the length is non-zero, it tries to find an
941 : * unused file name of the given length. It continues until either the
942 : * name is available and the rename succeeds, or it runs out of names
943 : * to try (incname wraps and returns 1). Finally, it unlinks the file.
944 : *
945 : * The unlink is Unix-specific, as ANSI-standard remove has more
946 : * portability problems with C libraries making it "safe". rename
947 : * is ANSI-standard.
948 : *
949 : * To force the directory data out, we try to open the directory and
950 : * invoke fdatasync and/or fsync on it. This is non-standard, so don't
951 : * insist that it works: just fall back to a global sync in that case.
952 : * This is fairly significantly Unix-specific. Of course, on any
953 : * file system with synchronous metadata updates, this is unnecessary.
954 : */
955 : static bool
956 0 : wipename (char *oldname, char const *qoldname, struct Options const *flags)
957 : {
958 0 : char *newname = xstrdup (oldname);
959 0 : char *base = last_component (newname);
960 0 : size_t len = base_len (base);
961 0 : char *dir = dir_name (newname);
962 0 : char *qdir = xstrdup (quotearg_colon (dir));
963 0 : bool first = true;
964 0 : bool ok = true;
965 :
966 0 : int dir_fd = open (dir, O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK);
967 :
968 0 : if (flags->verbose)
969 0 : error (0, 0, _("%s: removing"), qoldname);
970 :
971 0 : while (len)
972 : {
973 0 : memset (base, nameset[0], len);
974 0 : base[len] = 0;
975 : do
976 : {
977 : struct stat st;
978 0 : if (lstat (newname, &st) < 0)
979 : {
980 0 : if (rename (oldname, newname) == 0)
981 : {
982 0 : if (0 <= dir_fd && dosync (dir_fd, qdir) != 0)
983 0 : ok = false;
984 0 : if (flags->verbose)
985 : {
986 : /*
987 : * People seem to understand this better than talking
988 : * about renaming oldname. newname doesn't need
989 : * quoting because we picked it. oldname needs to
990 : * be quoted only the first time.
991 : */
992 0 : char const *old = (first ? qoldname : oldname);
993 0 : error (0, 0, _("%s: renamed to %s"), old, newname);
994 0 : first = false;
995 : }
996 0 : memcpy (oldname + (base - newname), base, len + 1);
997 0 : break;
998 : }
999 : else
1000 : {
1001 : /* The rename failed: give up on this length. */
1002 0 : break;
1003 : }
1004 : }
1005 : else
1006 : {
1007 : /* newname exists, so increment BASE so we use another */
1008 : }
1009 : }
1010 0 : while (incname (base, len));
1011 0 : len--;
1012 : }
1013 0 : if (unlink (oldname) != 0)
1014 : {
1015 0 : error (0, errno, _("%s: failed to remove"), qoldname);
1016 0 : ok = false;
1017 : }
1018 0 : else if (flags->verbose)
1019 0 : error (0, 0, _("%s: removed"), qoldname);
1020 0 : if (0 <= dir_fd)
1021 : {
1022 0 : if (dosync (dir_fd, qdir) != 0)
1023 0 : ok = false;
1024 0 : if (close (dir_fd) != 0)
1025 : {
1026 0 : error (0, errno, _("%s: failed to close"), qdir);
1027 0 : ok = false;
1028 : }
1029 : }
1030 0 : free (newname);
1031 0 : free (dir);
1032 0 : free (qdir);
1033 0 : return ok;
1034 : }
1035 :
1036 : /*
1037 : * Finally, the function that actually takes a filename and grinds
1038 : * it into hamburger.
1039 : *
1040 : * FIXME
1041 : * Detail to note: since we do not restore errno to EACCES after
1042 : * a failed chmod, we end up printing the error code from the chmod.
1043 : * This is actually the error that stopped us from proceeding, so
1044 : * it's arguably the right one, and in practice it'll be either EACCES
1045 : * again or EPERM, which both give similar error messages.
1046 : * Does anyone disagree?
1047 : */
1048 : static bool
1049 34 : wipefile (char *name, char const *qname,
1050 : struct randint_source *s, struct Options const *flags)
1051 : {
1052 : bool ok;
1053 : int fd;
1054 :
1055 34 : fd = open (name, O_WRONLY | O_NOCTTY | O_BINARY);
1056 34 : if (fd < 0
1057 28 : && (errno == EACCES && flags->force)
1058 1 : && chmod (name, S_IWUSR) == 0)
1059 1 : fd = open (name, O_WRONLY | O_NOCTTY | O_BINARY);
1060 34 : if (fd < 0)
1061 : {
1062 27 : error (0, errno, _("%s: failed to open for writing"), qname);
1063 27 : return false;
1064 : }
1065 :
1066 7 : ok = do_wipefd (fd, qname, s, flags);
1067 7 : if (close (fd) != 0)
1068 : {
1069 0 : error (0, errno, _("%s: failed to close"), qname);
1070 0 : ok = false;
1071 : }
1072 7 : if (ok && flags->remove_file)
1073 0 : ok = wipename (name, qname, flags);
1074 7 : return ok;
1075 : }
1076 :
1077 :
1078 : /* Buffers for random data. */
1079 : static struct randint_source *randint_source;
1080 :
1081 : /* Just on general principles, wipe buffers containing information
1082 : that may be related to the possibly-pseudorandom values used during
1083 : shredding. */
1084 : static void
1085 58 : clear_random_data (void)
1086 : {
1087 58 : randint_all_free (randint_source);
1088 58 : }
1089 :
1090 :
1091 : int
1092 102 : main (int argc, char **argv)
1093 : {
1094 102 : bool ok = true;
1095 102 : struct Options flags = { 0, };
1096 : char **file;
1097 : int n_files;
1098 : int c;
1099 : int i;
1100 102 : char const *random_source = NULL;
1101 :
1102 : initialize_main (&argc, &argv);
1103 102 : program_name = argv[0];
1104 102 : setlocale (LC_ALL, "");
1105 : bindtextdomain (PACKAGE, LOCALEDIR);
1106 : textdomain (PACKAGE);
1107 :
1108 102 : atexit (close_stdout);
1109 :
1110 102 : flags.n_iterations = DEFAULT_PASSES;
1111 102 : flags.size = -1;
1112 :
1113 249 : while ((c = getopt_long (argc, argv, "fn:s:uvxz", long_opts, NULL)) != -1)
1114 : {
1115 67 : switch (c)
1116 : {
1117 10 : case 'f':
1118 10 : flags.force = true;
1119 10 : break;
1120 :
1121 10 : case 'n':
1122 : {
1123 : uintmax_t tmp;
1124 10 : if (xstrtoumax (optarg, NULL, 10, &tmp, NULL) != LONGINT_OK
1125 4 : || MIN (UINT32_MAX, SIZE_MAX / sizeof (int)) < tmp)
1126 : {
1127 6 : error (EXIT_FAILURE, 0, _("%s: invalid number of passes"),
1128 : quotearg_colon (optarg));
1129 : }
1130 4 : flags.n_iterations = tmp;
1131 : }
1132 4 : break;
1133 :
1134 1 : case RANDOM_SOURCE_OPTION:
1135 1 : if (random_source && !STREQ (random_source, optarg))
1136 0 : error (EXIT_FAILURE, 0, _("multiple random sources specified"));
1137 1 : random_source = optarg;
1138 1 : break;
1139 :
1140 3 : case 'u':
1141 3 : flags.remove_file = true;
1142 3 : break;
1143 :
1144 20 : case 's':
1145 : {
1146 : uintmax_t tmp;
1147 20 : if (xstrtoumax (optarg, NULL, 0, &tmp, "cbBkKMGTPEZY0")
1148 : != LONGINT_OK)
1149 : {
1150 6 : error (EXIT_FAILURE, 0, _("%s: invalid file size"),
1151 : quotearg_colon (optarg));
1152 : }
1153 14 : flags.size = tmp;
1154 : }
1155 14 : break;
1156 :
1157 8 : case 'v':
1158 8 : flags.verbose = true;
1159 8 : break;
1160 :
1161 4 : case 'x':
1162 4 : flags.exact = true;
1163 4 : break;
1164 :
1165 1 : case 'z':
1166 1 : flags.zero_fill = true;
1167 1 : break;
1168 :
1169 1 : case_GETOPT_HELP_CHAR;
1170 :
1171 1 : case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1172 :
1173 8 : default:
1174 8 : usage (EXIT_FAILURE);
1175 : }
1176 : }
1177 :
1178 80 : file = argv + optind;
1179 80 : n_files = argc - optind;
1180 :
1181 80 : if (n_files == 0)
1182 : {
1183 21 : error (0, 0, _("missing file operand"));
1184 21 : usage (EXIT_FAILURE);
1185 : }
1186 :
1187 59 : randint_source = randint_all_new (random_source, SIZE_MAX);
1188 59 : if (! randint_source)
1189 1 : error (EXIT_FAILURE, errno, "%s", quotearg_colon (random_source));
1190 58 : atexit (clear_random_data);
1191 :
1192 148 : for (i = 0; i < n_files; i++)
1193 : {
1194 90 : char *qname = xstrdup (quotearg_colon (file[i]));
1195 90 : if (STREQ (file[i], "-"))
1196 : {
1197 56 : ok &= wipefd (STDOUT_FILENO, qname, randint_source, &flags);
1198 : }
1199 : else
1200 : {
1201 : /* Plain filename - Note that this overwrites *argv! */
1202 34 : ok &= wipefile (file[i], qname, randint_source, &flags);
1203 : }
1204 90 : free (qname);
1205 : }
1206 :
1207 58 : exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
1208 : }
1209 : /*
1210 : * vim:sw=2:sts=2:
1211 : */
|