1 /*
2  * Copyright (c) 2002, 2013
3  * FREEBSD HACKERS NET (http://www.freebsdhackers.net) All rights reserved.
4  *
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by FREEBSD HACKERS NET,
17  *       http://www.freebsdhackers.net
18  * 4. Neither the name "FREEBSD HACKERS NET" nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE FREEBSD HACKERS NET ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL FREEBSD HACKERS NET OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 /*
36  * MAINTAINER: Shane Kinney (mod6) <modsix@gmail.com>
37  */
38 
39 #include	<stdio.h>
40 #include	<stdlib.h>
41 #include	<sys/types.h>
42 #include	<sys/stat.h>
43 #include	<fcntl.h>
44 #include 	<unistd.h>
45 #include	<errno.h>
46 #include	<fts.h>
47 
48 #define	MAXBUFFSIZE	8192
49 
50 void 	usage();
51 void 	setup(unsigned long filesize, char *path, int sflag);
52 void 	traverse(char **argv, int fflag, int qflag, int sflag);
53 void 	destroy(int read_fd, int write_fd, char *buf, int sz_buf, unsigned long filesize);
54 void 	unlink_special(char *path);
55 
main(int argc,char * argv[])56 int main(int argc, char *argv[]) {
57 
58 	int ch, fflag, qflag, sflag;
59 
60 	if(argc < 2) {
61 		usage();
62 		exit(1);
63 	}
64 
65 	/* don't want getopt() writing to stderr -- set flags to 0 for good mesasure. */
66 	opterr = fflag = qflag = sflag = 0;
67 
68 	while((ch = getopt(argc, argv, "s:fqh")) != -1) {
69 		switch(ch) {
70 		case 's':
71 			sflag = atoi(optarg);
72 			if(sflag < 1 || sflag > 20) { // The number of overwrites must between 1 and 20
73 				usage();
74 				exit(1);
75 			}
76 			break;
77 		case 'f':
78 			fflag = 1;
79 			break;
80 		case 'q':
81 			qflag = 1;
82 			break;
83 		case 'h':
84 			usage();
85 		case '?':
86 			/* see `man 3 getopt` */
87 			fprintf(stderr, "Unrecognized option: -%c\n", optopt);
88 			usage();
89 		default:
90 			usage();
91 		}
92 	}
93 
94 	/* If user didn't set a default sflag number, set it to 7 (US DOD Standard). */
95 	if(!sflag) {
96 		sflag = 7;
97 	}
98 
99 	argc -= optind;
100 	argv += optind;
101 
102 	if(argc < 1) {
103 		usage();
104 	}
105 
106 	traverse(argv, fflag, qflag, sflag);
107 	return 0;
108 }
109 
traverse(char ** argv,int fflag,int qflag,int sflag)110 void traverse(char **argv, int fflag, int qflag, int sflag) {
111 	FTS		*fts;
112 	FTSENT		*p;
113 	int		dirCount, flags;
114 	unsigned long	filesize;
115 	flags 		= FTS_PHYSICAL;
116 	dirCount 	= 0;
117 
118 	/* Open the path given from the command line */
119 	if(!(fts = fts_open(argv, flags, NULL))) {
120 		perror("Error!: ");
121 		exit(1);
122 	}
123 
124 	/* Recursivly attempt to destroy all valid files */
125 	while((p = fts_read(fts)) != NULL) {
126 
127 		/* Now look the stat of the file and determine the st_mode */
128 		switch(p->fts_statp->st_mode & S_IFMT) {
129 
130 		case S_IFIFO:	/* named pipe (fifo) */
131 			if(fflag) {
132 				if(!qflag) {
133 					printf("Named Pipe: \t %s \n", p->fts_accpath);
134 				}
135 				unlink_special(p->fts_accpath);
136 			} else if(!qflag) {
137 				fprintf(stderr, "Named Pipe: \t %s \t Skipping...no '-f' flag given!\n", p->fts_accpath);
138 			}
139 			break;
140 
141 		case S_IFCHR:	/* character special */
142 			if(fflag) {
143 				if(!qflag) {
144 					printf("Character Special: \t %s \n", p->fts_accpath);
145 				}
146 				unlink_special(p->fts_accpath);
147 			} else if(!qflag) {
148 				fprintf(stderr, "Character Special: \t %s \t Skipping...no '-f' flag given!\n", p->fts_accpath);
149 			}
150 			break;
151 
152 		case S_IFDIR:	/* directory */
153 			if(!qflag) {
154 				printf("Directory: \t %s \n", p->fts_accpath);
155 			}
156 			rmdir(p->fts_accpath);
157 			break;
158 
159 		case S_IFBLK:	/* block special */
160 			if(fflag) {
161 				printf("Block Special: \t %s \n", p->fts_accpath);
162 				unlink_special(p->fts_accpath);
163 			} else if(!qflag) {
164 				fprintf(stderr, "Block Special: \t %s \t Skipping...no '-f' flag given!\n", p->fts_accpath);
165 			}
166 			break;
167 
168 		case S_IFREG:	/* regular */
169 			filesize = p->fts_statp->st_size;
170 			if(!qflag) {
171 				printf("Regular File: \t %s \t Size: \t %lu Bytes\n", p->fts_accpath, filesize);
172 			}
173 
174 			setup(filesize, p->fts_accpath, sflag);
175 			break;
176 
177 		case S_IFLNK:	/* symbolic link */
178 			if(fflag) {
179 				if(!qflag) {
180 					printf("Symbolic Link: \t %s \n", p->fts_accpath);
181 				}
182 				unlink_special(p->fts_accpath);
183 			} else if(!qflag) {
184 				fprintf(stderr, "Symbolic Link: \t %s \t Skipping... no '-f' flag set!\n", p->fts_accpath);
185 			}
186 			break;
187 
188 		case S_IFSOCK:	/* socket */
189 			if(fflag) {
190 				if(!qflag) {
191 					printf("Socket: \t %s \n", p->fts_accpath);
192 				}
193 				unlink_special(p->fts_accpath);
194 			} else if(!qflag) {
195 				fprintf(stderr, "Socket: \t %s \t Skipping... no '-f' flag set!\n", p->fts_accpath);
196 			}
197 			break;
198 #ifdef __FreeBSD__
199 		case S_IFWHT:	/* whiteout is only a FreeBSD type */
200 			if(fflag) {
201 				if(!qflag) {
202 					printf("Whiteout: \t %s \n", p->fts_accpath);
203 				}
204 				unlink_special(p->fts_accpath);
205 			} else if(!qflag) {
206 				fprintf(stderr, "Whiteout: \t %s \t Skipping... no '-f' flag set!\n", p->fts_accpath);
207 			}
208 			break;
209 #endif
210 		default:
211 			if(!qflag) {
212 				fprintf(stderr, "Type Unknown...\n");
213 			}
214 		}
215 	}
216 }
217 
setup(unsigned long filesize,char * path,int sflag)218 void setup(unsigned long filesize, char *path, int sflag) {
219 	struct	stat sb;
220 	int		i, fd_rand, fd_zero, fd_userfile;
221 	char		*buf;
222 	char		*devrand = "/dev/urandom";
223 	char		*devzero = "/dev/zero";
224 	int      	mode = O_WRONLY | O_EXCL;
225 
226 	int	result = 0;
227 
228 #if defined(O_NOFOLLOW)
229 	mode |=  O_NOFOLLOW;
230 #endif
231 
232 	/* allocate our buffer memory. */
233 	if((buf = (char *) malloc(MAXBUFFSIZE * sizeof(char))) == NULL) {
234 		perror("Error ");
235 		exit(1);
236 	}
237 
238 	/* Open /dev/zero get and get a file descriptor for it */
239 	if((fd_zero = open(devzero, O_RDONLY)) < 0) {
240 		perror("Error ");
241 		usage();
242 		exit(1);
243 	}
244 
245 	/* Open our user file, and get a file descriptor for it */
246 	if((fd_userfile = open(path, mode)) < 0) {
247 		perror("Error ");
248 		usage();
249 		exit(1);
250 	}
251 
252 	/* Open /dev/urandom and get a file descriptor for it */
253 	if((fd_rand = open(devrand, O_RDONLY)) < 0) {
254 		perror("Error ");
255 		usage();
256 		exit(1);
257 	}
258 
259 	/* Do each over write (rand & null) 'sflag' times (specified by cli). */
260 	for(i = 0; i < sflag; i++) {
261 		destroy(fd_rand, fd_userfile, buf, MAXBUFFSIZE, filesize);
262 		destroy(fd_zero, fd_userfile, buf, MAXBUFFSIZE, filesize);
263 	}
264 
265 	/* close everything open: */
266 	close(fd_userfile);
267 	close(fd_rand);
268 	close(fd_zero);
269 
270 	/* Unlink our file */
271 	if(unlink(path) < 0) {
272 		perror("Error ");
273 		exit(1);
274 	}
275 
276 	/* Free our malloc()'d memory */
277 	free(buf);
278 }
279 
destroy(int fd_read,int fd_write,char * buf,int sz_buf,unsigned long filesize)280 void destroy(int fd_read, int fd_write, char *buf, int sz_buf, unsigned long filesize) {
281 
282 	int 	offset = 0;
283 	int 	bytes_read;
284 	int 	cursz_buf = sz_buf;  // current number of bytes to fill buffer with
285 
286 	/* Seek to the beginning of the file. */
287 	if(lseek(fd_write, offset, SEEK_SET) < 0) {
288 		perror("Error ");
289 		exit(1);
290 	}
291 
292 	/* Loop through file */
293 	while(offset < filesize) {
294 
295 		/* If the size of the file is less than MAXBUFFSIZE */
296 		if((filesize - offset) < sz_buf) {
297 			cursz_buf = filesize - offset;
298 		}
299 
300 		/* Read bytes from /dev/urandom or /dev/zero */
301 		if((bytes_read = read(fd_read, buf, cursz_buf)) < 0) {
302 			perror("Error ");
303 			exit(1);
304 		}
305 
306 		/* Write out the bytes to the file. */
307 		if(write(fd_write, buf, bytes_read) != bytes_read) {
308 			perror("Error ");
309 			exit(1);
310 		}
311 
312 		offset += bytes_read;
313 	}
314 
315 	/* fsync our data the hard disk. */
316 	if((fsync(fd_write) < 0) && (errno == EIO)) {
317 		perror("Error ");
318 		exit(1);
319 	}
320 }
321 
unlink_special(char * path)322 void unlink_special(char *path) {
323 	/* Unlink the special files we encounter if the -f (fflag) is set. */
324 	if(unlink(path) < 0) {
325 		perror("Error ");
326 		exit(1);
327 	}
328 }
329 
usage()330 void usage() {
331 	fprintf(stderr, "Usage: destroy [ -s <int> ] [ -f ] [ -q ] [ -h ] <[file(s) | directory]>\n");
332 	fprintf(stderr, " -s: The number of overwrites to each file.\n");
333 	fprintf(stderr, "\tThe default is set to 5, the minimum allowed is 1, and the maximum allowed is 20.\n");
334 	fprintf(stderr, " -f: Enable force deletion of special file types.\n");
335 	fprintf(stderr, " -q: Enable quiet output.\n");
336 	fprintf(stderr, " -h: Print this help screen.\n");
337 	fprintf(stderr, "\n");
338 	fprintf(stderr, "\n");
339 	fprintf(stderr, "View the man page file for all the info: `man 1 destroy`\n");
340 	fprintf(stderr, "For more help:\n");
341 	fprintf(stderr, "\tGo to: irc.freebsdhackers.net #freebsd\n");
342 	fprintf(stderr, "\tOr to: http://www.mod6.net\n");
343 	fprintf(stderr, "\tOr write to: modsix@gmail.com\n");
344 	exit(1);
345 }
346