1#include "config.h"
2
3#include <errno.h>
4#include <fcntl.h>
5#include <stdarg.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/ioctl.h>
10#include <sys/stat.h>
11#include <sys/types.h>
12#include <time.h>
13#include <unistd.h>
14
15#if HAVE_LINUX_EXT2_FS_H
16#include <linux/ext2_fs.h>
17#endif
18
19#if HAVE_SYS_VFS_H
20#include <sys/vfs.h>
21#endif
22
23#if HAVE_SYS_PARAM_H && HAVE_SYS_MOUNT_H
24#include <sys/param.h>
25#include <sys/mount.h>
26#endif
27
28#if __APPLE__
29#include <sys/disk.h>
30#endif
31
32#if HAVE_CHFLAGS
33/* define unsupported flags as 0 */
34# if !defined UF_IMMUTABLE
35#  define UF_IMMUTABLE 0
36# endif
37# if !defined UF_APPEND
38#  define UF_APPEND 0
39# endif
40# if !defined UF_NOUNLINK
41#  define UF_NOUNLINK 0
42# endif
43# if !defined SF_IMMUTABLE
44#  define SF_IMMUTABLE 0
45# endif
46# if !defined SF_APPEND
47#  define SF_APPEND 0
48# endif
49# if !defined SF_NOUNLINK
50#  define SF_NOUNLINK 0
51# endif
52#endif
53
54#include "srm.h"
55
56enum {
57  W_SINGLE  = 0,
58  W_RANDOM  = 1,
59  W_TRIPLE  = 2
60};
61
62static int file;
63static off_t file_size;
64static unsigned char *buffer = NULL;
65static unsigned char *verify_buffer = NULL;
66static u_int32_t buffsize, allocated_buffsize = 0;
67static off_t bytes_total;
68static off_t bytes_completed;
69
70int init_write_buffer(struct stat *statbuf, struct statfs *fs_stats) {
71  u_int64_t maxbytecount;
72  u_int32_t tmp_buffsize;
73
74  file_size = statbuf->st_size;
75  buffsize = statbuf->st_blksize;
76
77#if HAVE_SYS_PARAM_H
78  /* try to determine an optimal write buffer size */
79  buffsize = (u_int32_t)(statbuf->st_size / statbuf->st_blksize) * statbuf->st_blksize;
80  if ((statbuf->st_size % statbuf->st_blksize) != 0) {
81    /* add full size of last block */
82    buffsize += statbuf->st_blksize;
83  } else if (buffsize < statbuf->st_blksize) {
84    /* no smaller than one device block */
85    buffsize = statbuf->st_blksize;
86  }
87  tmp_buffsize = MAXBSIZE;
88  if (buffsize > tmp_buffsize) {
89    /* no larger than the largest file system buffer size */
90    buffsize = tmp_buffsize;
91  }
92#endif
93
94  if (opt_buffsize) {
95    /* allow command-line override */
96    buffsize = opt_buffsize;
97  }
98
99  /* Allocated buffer must be at least 2 bytes larger than logical buffsize.
100     This lets us align repeating 3-byte patterns across multiple buffer
101     writes by using a variable offset (0..2) from the start of the buffer. */
102
103  tmp_buffsize = buffsize + 4;
104
105  if (buffer) {
106    if (tmp_buffsize > allocated_buffsize) {
107      free(buffer);
108      buffer = NULL;
109    } else {
110      return 0; /* use existing buffer */
111    }
112  }
113  if ((buffer = (unsigned char *)malloc(tmp_buffsize)) == NULL) {
114    errno = ENOMEM;
115    return -1;
116  }
117  if (options & OPT_VERIFY) {
118    if ((verify_buffer = (unsigned char *)malloc(buffsize)) == NULL) {
119      errno = ENOMEM;
120      return -1;
121    }
122  }
123  allocated_buffsize = tmp_buffsize;
124  return 0;
125}
126
127void flush(int fd) {
128  /* force buffered writes to be flushed to disk */
129#if defined F_FULLFSYNC
130  /* F_FULLFSYNC is equivalent to fsync plus device flush to media */
131  if (fcntl(fd, F_FULLFSYNC, NULL) != 0) {
132    /* we're not on a fs that supports this; fall back to plain fsync */
133    fsync(fd);
134  }
135#elif HAVE_FDATASYNC
136  fdatasync(fd);
137#else
138  fsync(fd);
139#endif
140}
141
142void update_progress(u_int32_t bytes_written) {
143  u_int32_t cur_percent, new_percent;
144
145  if (!bytes_total)
146    return;
147
148  cur_percent = (u_int32_t)((off_t)(bytes_completed*100)/bytes_total);
149  bytes_completed += bytes_written;
150  new_percent = (u_int32_t)((off_t)(bytes_completed*100)/bytes_total);
151
152  if (cur_percent != new_percent) {
153    printf("\r%d%%", new_percent);
154    if (bytes_completed == bytes_total)
155      printf("\rdone\n");
156    fflush(stdout);
157  }
158}
159
160unsigned char *align_buffer(unsigned char *buf, off_t pos) {
161  /* return a pointer to the start of the buffer which should be written,
162     offset from the given buffer by 0, 1, or 2 bytes, so that the 3-byte
163     pattern which the buffer contains is aligned with the previous write. */
164  return (unsigned char *)((uintptr_t)buf + (unsigned int)(pos % 3));
165}
166
167void verification_failure(off_t count) {
168  if (sizeof(off_t) == 4)
169    printf("warning: failed to verify write at offset %d\n", count);
170  else if (sizeof(off_t) == 8)
171    printf("warning: failed to verify write at offset %lld\n", count);
172  else
173    printf("warning: previous write failed to verify!\n");
174  fflush(stdout);
175}
176
177void overwrite(int stage) {
178  u_int32_t i, j;
179  off_t count = 0;
180  unsigned char *buffptr = buffer;
181
182  lseek(file, 0, SEEK_SET);
183  while (count < file_size - buffsize) {
184    if (stage == W_RANDOM) {
185      randomize_buffer(buffer, buffsize);
186    } else if (stage == W_TRIPLE) {
187      buffptr = align_buffer(buffer, count);
188    }
189    i = write(file, buffptr, buffsize);
190    if (options & OPT_VERIFY) {
191        /* verify the write */
192        lseek(file, count, SEEK_SET);
193        j = read(file, verify_buffer, buffsize);
194        if (!(i == j && !memcmp(verify_buffer, buffptr, buffsize))) {
195          verification_failure(count);
196        }
197    }
198    if (options & OPT_V) {
199      update_progress(i);
200    }
201	count += i;
202  }
203  if (stage == W_RANDOM) {
204    randomize_buffer(buffer, file_size - count);
205  } else if (stage == W_TRIPLE) {
206    buffptr = align_buffer(buffer, count);
207  }
208  i = write(file, buffptr, file_size - count);
209  if (options & OPT_VERIFY) {
210    /* verify the write */
211    lseek(file, count, SEEK_SET);
212    j = read(file, verify_buffer, file_size - count);
213    if (!(i == j && !memcmp(verify_buffer, buffptr, file_size - count))) {
214      verification_failure(count);
215    }
216  }
217  if (options & OPT_V) {
218    update_progress(i);
219  }
220  flush(file);
221  lseek(file, 0, SEEK_SET);
222}
223
224void overwrite_random(int num_passes) {
225  int i;
226
227  for (i = 0; i < num_passes; i++) {
228    overwrite(W_RANDOM);
229  }
230}
231
232void overwrite_byte(int byte) {
233  memset(buffer, byte, buffsize);
234  overwrite(W_SINGLE);
235}
236
237void overwrite_bytes(unsigned int byte1, unsigned int byte2, unsigned int byte3) {
238  u_int32_t val[3], *p = (u_int32_t *)buffer;
239  unsigned int i, mod12buffsize = allocated_buffsize - (allocated_buffsize % 12);
240
241  val[0] = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte1;
242  val[1] = (byte2 << 24) | (byte3 << 16) | (byte1 << 8) | byte2;
243  val[2] = (byte3 << 24) | (byte1 << 16) | (byte2 << 8) | byte3;
244
245  /* fill buffer 12 bytes at a time, optimized for 4-byte alignment */
246  for (i = 0; i < mod12buffsize; i += 12) {
247    *p++ = val[0];
248    *p++ = val[1];
249    *p++ = val[2];
250  }
251  while (i < allocated_buffsize) {
252    buffer[i] = ((unsigned char *)&val[0])[i % 3];
253    i++;
254  }
255  overwrite(W_TRIPLE);
256}
257
258void overwrite_file() {
259  bytes_completed = 0;
260  bytes_total = 0;
261
262  if (!file_size) {
263    /* nothing to overwrite in a zero-length file */
264    if (options & OPT_V) {
265      printf("\rdone\n");
266      fflush(stdout);
267    }
268    return;
269  }
270
271  if (options & OPT_ZERO) {
272    bytes_total = file_size;
273  }
274  if (seclevel==1) {
275    /* simple one-pass overwrite */
276    bytes_total += file_size*1;
277    overwrite_random(1);
278  } else if (seclevel==7) {
279    /* DoD-compliant 7-pass overwrite */
280    bytes_total += file_size*7;
281    overwrite_byte(0xF6);
282    overwrite_byte(0x00);
283    overwrite_byte(0xFF);
284    overwrite_random(1);
285    overwrite_byte(0x00);
286    overwrite_byte(0xFF);
287    overwrite_random(1);
288  } else {
289    /* Gutmann 35-pass overwrite */
290    bytes_total += file_size*35;
291    overwrite_random(4);
292    overwrite_byte(0x55);
293    overwrite_byte(0xAA);
294    overwrite_bytes(0x92, 0x49, 0x24);
295    overwrite_bytes(0x49, 0x24, 0x92);
296    overwrite_bytes(0x24, 0x92, 0x49);
297    overwrite_byte(0x00);
298    overwrite_byte(0x11);
299    overwrite_byte(0x22);
300    overwrite_byte(0x33);
301    overwrite_byte(0x44);
302    overwrite_byte(0x55);
303    overwrite_byte(0x66);
304    overwrite_byte(0x77);
305    overwrite_byte(0x88);
306    overwrite_byte(0x99);
307    overwrite_byte(0xAA);
308    overwrite_byte(0xBB);
309    overwrite_byte(0xCC);
310    overwrite_byte(0xDD);
311    overwrite_byte(0xEE);
312    overwrite_byte(0xFF);
313    overwrite_bytes(0x92, 0x49, 0x24);
314    overwrite_bytes(0x49, 0x24, 0x92);
315    overwrite_bytes(0x24, 0x92, 0x49);
316    overwrite_bytes(0x6D, 0xB6, 0xDB);
317    overwrite_bytes(0xB6, 0xDB, 0x6D);
318    overwrite_bytes(0xDB, 0x6D, 0xB6);
319    overwrite_random(4);
320  }
321  if (options & OPT_ZERO) {
322    overwrite_byte(0x00);
323  }
324}
325
326int sunlink(const char *path) {
327  struct stat statbuf;
328  struct statfs fs_stats;
329#if HAVE_LINUX_EXT2_FS_H
330  int flags = 0;
331#endif
332  int fmode = (options & OPT_VERIFY) ? O_RDWR : O_WRONLY;
333  struct flock flock;
334
335  if (lstat(path, &statbuf) == -1)
336    return -1;
337  if (!S_ISREG(statbuf.st_mode))
338    return rename_unlink(path);
339
340  if (statbuf.st_nlink > 1) {
341    rename_unlink(path);
342    errno = EMLINK;
343    return -1;
344  }
345
346  if ( (file = open(path, fmode)) == -1) /* BSD doesn't support O_SYNC */
347    return -1;
348
349  if (fcntl(file, F_WRLCK, &flock) == -1) {
350    close(file);
351    return -1;
352  }
353
354  if (fstatfs(file, &fs_stats) == -1 && errno != ENOSYS) {
355    close(file);
356    return -1;
357  }
358
359  /* warn when trying to overwrite files on a non-local fs,
360     since there are no guarantees that writes will not be
361     buffered on the server, or will overwrite the same spot. */
362  if (options & OPT_V) {
363    if ((fs_stats.f_flags & MNT_LOCAL) == 0) {
364      printf("warning: %s is not on a local filesystem!\n", path);
365      fflush(stdout);
366    }
367  }
368
369#if HAVE_LINUX_EXT2_FS_H
370  if (fs_stats.f_type == EXT2_SUPER_MAGIC)
371    if (ioctl(file, EXT2_IOC_GETFLAGS, &flags) == -1) {
372      close(file);
373      return -1;
374    }
375
376  if ( (flags & EXT2_UNRM_FL) || (flags & EXT2_IMMUTABLE_FL) ||
377      (flags & EXT2_APPEND_FL) )
378    {
379      close(file);
380      errno = EPERM;
381      return -1;
382    }
383
384#endif /* HAVE_LINUX_EXT2_FS_H */
385
386/* chflags(2) turns out to be a different system call in every BSD
387   derivative. The important thing is to make sure we'll be able to
388   unlink it after we're through messing around. Unlinking it first
389   would remove the need for any of these checks, but would leave the
390   user with no way to overwrite the file if the process was
391   interrupted during the overwriting. So, instead we assume that the
392   open() above will fail on immutable and append-only files and try
393   and catch only platforms supporting NOUNLINK here.
394
395   FreeBSD - supports NOUNLINK (from 4.4 on?)
396   MacOS X - doesn't support NOUNLINK (as of 10.3.5)
397   OpenBSD - doesn't support NOUNLINK (as of 3.1)
398   Tru64   - unknown
399
400   Note: unsupported flags are defined as 0 at the top of this file,
401   so a specific platform check is not required here.
402*/
403
404#if HAVE_CHFLAGS
405  if ((statbuf.st_flags & UF_IMMUTABLE) ||
406      (statbuf.st_flags & UF_APPEND) ||
407      (statbuf.st_flags & UF_NOUNLINK) ||
408      (statbuf.st_flags & SF_IMMUTABLE) ||
409      (statbuf.st_flags & SF_APPEND) ||
410      (statbuf.st_flags & SF_NOUNLINK))
411    {
412      close(file);
413      errno = EPERM;
414      return -1;
415    }
416#endif /* HAVE_CHFLAGS */
417
418  if (init_write_buffer(&statbuf, &fs_stats) == -1) {
419    close(file);
420    return -1;
421  }
422#if defined F_NOCACHE
423  /* before performing file I/O, set F_NOCACHE to prevent caching */
424  (void)fcntl(file, F_NOCACHE, 1);
425#endif
426
427  overwrite_file();
428
429#if HAVE_LINUX_EXT2_FS_H
430  ioctl(file, EXT2_IOC_SETFLAGS, EXT2_SECRM_FL);
431#endif
432
433  if ((options & OPT_N) == 0) {
434    if (ftruncate(file, 0) == -1) {
435      close(file);
436      return -1;
437    }
438  }
439
440  close(file);
441
442#if __APPLE__
443  /* Also overwrite the file's resource fork, if present. */
444  {
445    static const char *RSRCFORKSPEC = "/..namedfork/rsrc";
446    size_t rsrc_fork_size;
447    size_t rsrc_path_size = strlen(path) + strlen(RSRCFORKSPEC) + 1;
448    char *rsrc_path = (char *)alloca(rsrc_path_size);
449    if (rsrc_path == NULL) {
450      errno = ENOMEM;
451      return -1;
452    }
453    if (snprintf(rsrc_path, MAXPATHLEN,
454        "%s%s", path, RSRCFORKSPEC ) > MAXPATHLEN - 1) {
455      errno = ENAMETOOLONG;
456      return -1;
457    }
458
459    if (lstat(rsrc_path, &statbuf) != 0) {
460      int err = errno;
461      if (err == ENOENT || err == ENOTDIR) {
462        rsrc_fork_size = 0;
463      } else {
464        return -1;
465      }
466    } else {
467      rsrc_fork_size = statbuf.st_size;
468    }
469
470    if (rsrc_fork_size > 0) {
471
472      if ((file = open(rsrc_path, O_WRONLY)) == -1) {
473        return -1;
474      }
475      if (fcntl(file, F_WRLCK, &flock) == -1) {
476        close(file);
477        return -1;
478      }
479
480      if (options & OPT_V) {
481        printf("removing %s\n", rsrc_path);
482        fflush(stdout);
483      }
484
485      if (init_write_buffer(&statbuf, &fs_stats) == -1) {
486        close(file);
487        return -1;
488      }
489    #if defined F_NOCACHE
490      /* before performing file I/O, set F_NOCACHE to prevent caching */
491      (void)fcntl(file, F_NOCACHE, 1);
492    #endif
493
494      overwrite_file();
495
496      if ((options & OPT_N) == 0) {
497        if (ftruncate(file, 0) == -1) {
498          close(file);
499          return -1;
500        }
501      }
502      close(file);
503    }
504  }
505#endif /* __APPLE__ */
506
507  if (options & OPT_N)
508    return 0;
509
510  return rename_unlink(path);
511}
512