forked from gordrs/thc-secure-delete
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sfill.c
237 lines (214 loc) · 7.72 KB
/
sfill.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/* Secure FILL - by van Hauser / [THC], [email protected]
*
* Secure FILL overwrites all available free diskspace by creating a file,
* wiping all free diskspace it gets and finally deleting the file.
*
* Standard mode is a real security wipe for 38 times, flushing
* the caches after every write. The wipe technique was proposed by Peter
* Gutmann at Usenix '96 and includes 10 random overwrites plus 28 special
* defined characters. Take a look at the paper of him, it's really worth
* your time.
* The option -l overwrites two times the data. (0xff + random)
* The option -ll overwrites the data once. (random)
* New with v2.3: wipes all inodes in the defined directory
*
* Read the manual for limitations.
* Compiles clean on OpenBSD, Linux, Solaris and AIX
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <strings.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "sdel.h"
#ifdef BLOCKSIZE
#undef BLOCKSIZE
#endif
#define BLOCKSIZE 65535
#define MAXINODEWIPE 4194304 /* 22 bits */
char **array = NULL;
int slow = O_SYNC;
int debug = 1;
int zero = 0;
int inode_only = 0;
int fd = -1;
char *filename = NULL;
FILE *f;
void help() {
printf("sfill %s (c) 1997-2003 by %s <%s>\n\n", VERSION, AUTHOR, EMAIL);
printf("Syntax: %s [-fiIlvz] directory\n\n", prg);
printf("Options:\n");
printf("\t-f fast (and insecure mode): no /dev/urandom, no synchronize mode.\n");
printf("\t-i wipe only inodes in the directory specified\n");
printf("\t-I just wipe space, not inodes\n");
printf("\t-l lessens the security (use twice for total insecure mode).\n");
printf("\t-v is verbose mode.\n");
printf("\t-z last wipe writes zeros, not random data.\n");
printf("\nsfill does a secure overwrite of the free space on the partition the specified\ndirectory resides and all free inodes of the directory specified.\n");
printf("Default is secure mode (38 writes).\n");
printf("You can find updates at %s\n", WEB);
exit(1);
}
void cleanup(int signo) {
fprintf(stderr,"\nTerminated by signal. Clean exit.\n");
if (fd > 0) {
fsync(fd);
(void) close(fd);
sync();
if (filename != NULL && unlink(filename) != 0)
fprintf(stderr, "Error: Could not remove temporary file %s!\n", filename);
}
if (array != NULL) {
int i = 0;
while(array[i] != NULL) {
unlink(array[i]);
i++;
}
}
exit(1);
}
int main (int argc, char *argv[]) {
int result;
int secure = 2; /* standard is secure mode */
int loop;
int turn;
int counter;
struct stat filestat;
struct rlimit rlim;
char type[15] = "random";
if (getuid() != 0)
fprintf(stderr,"Warning: you are not root. You might not be able to wipe the whole filesystem.\n");
prg = argv[0];
if (argc == 1 || strncmp(argv[1], "-h", 2) == 0 || strncmp(argv[1], "--h", 3) == 0)
help();
while (1) {
result = getopt(argc, argv, "fFiIlLsSvVzZ");
if (result < 0)
break;
switch (result) {
case 'f' :
case 'F' : slow = 0;
break;
case 'i' : inode_only = 1;
break;
case 'I' : inode_only = -1;
break;
case 'l' :
case 'L' : if (secure) secure--;
break;
case 's' :
case 'S' : secure++;
break;
case 'v' :
case 'V' : verbose++;
break;
case 'Z' :
case 'z' : zero++;
break;
default : help();
}
}
loop = optind;
if (loop >= argc)
help();
if (zero) strcpy(type, "zero");
do {
char newname[strlen(argv[loop]) + 16];
strcpy(newname, argv[loop]); // can not overflow
if (opendir(newname) == NULL) { /* no need for ensuring close */
fprintf(stderr, "Error: %s is not a directory\n", newname);
} else {
/* Generate random unique name for tempfile */
srand(getpid()+getuid());
if (newname[strlen(newname)-1] != DIR_SEPERATOR)
strcat(newname, "/");
turn = 0; result = 0;
strcat(newname, "oooooooo.ooo");
result = lstat(newname, &filestat);
while ((result >= 0) && (turn <= 250)) {
for (counter = strlen(newname)-1;
(newname[counter] != DIR_SEPERATOR);
counter--)
if (newname[counter] != '.')
newname[counter] = 97+(int) (27.0 * rand() / (RAND_MAX + 1.0));
if ((result = lstat(newname, &filestat)) >= 0)
turn++;
};
if (result >= 0)
fprintf(stderr,"Error: couldn't find a free filename in %s\n",argv[loop]);
else {
signal(SIGINT, cleanup);
signal(SIGTERM, cleanup);
signal(SIGHUP, cleanup);
sdel_init(slow);
if (verbose && inode_only < 1) {
switch (secure) {
case 0 : printf("Wipe mode is insecure (one pass [%s])\n",type);
break;
case 1 : printf("Wipe mode is insecure (two passes [0xff/%s])\n",type);
break;
default: printf("Wipe mode is secure (38 special passes)\n");
}
printf("Wiping now ...\n");
}
#ifdef RLIM_INFINITY
#ifdef RLIMIT_FSIZE
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_FSIZE, &rlim) != 0)
fprintf(stderr, "Warning: Could not reset ulimit for filesize.\n");
#else
fprintf(stderr, "Warning: not compiled with support for resetting ulimit for filesize.\n");
#endif
#else
fprintf(stderr, "Warning: not compiled with support for resetting ulimit for filesize.\n");
#endif
result = 9;
if (inode_only < 1) {
/* create the file */
if (verbose) printf("Creating %s ... ", newname);
if ((fd = open(newname, O_RDWR | O_EXCL | O_CREAT | O_LARGEFILE | slow, 0600 )) < 0)
result = 1;
else {
filename = newname;
result = sdel_overwrite(secure, fd, 0, BLOCKSIZE, 0, zero);
/* Hard Flush -> Force cached data to be written to disk - the defines above! */
FLUSH;
if ((fd = open(newname, O_WRONLY | O_TRUNC)) >= 0)
close(fd);
}
}
if ((result == 0 && inode_only == 0) || inode_only > 0) {
if (result == 0 && inode_only == 0)
printf(" ");
sdel_wipe_inodes(argv[loop], array);
result = 0;
}
switch (result) {
case 0 : if (verbose) printf(" Finished\n");
break;
case 1 : fprintf(stderr, "Error: No write permission for %s. ", argv[loop]);
perror("");
break;
case 9: break;
default: fprintf(stderr, "Unknown error\n");
}
if (unlink(newname) != 0)
fprintf(stderr, "Error: Could not remove temporary file %s!\n", newname);
filename = NULL;
}
}
loop++;
} while (loop < argc);
sdel_finnish();
exit(0);
}