#include "config.h" #include #include #include #include #include #include #include #include #include #include #include #if HAVE_LINUX_EXT2_FS_H #include #endif #if HAVE_SYS_VFS_H #include #endif #if HAVE_SYS_PARAM_H && HAVE_SYS_MOUNT_H #include #include #endif #include "srm.h" static int file; static off_t file_size; static unsigned char *buffer; static unsigned int buffsize; static void overwrite() { unsigned int i = 0; lseek(file, 0, SEEK_SET); while (i < file_size - buffsize) i += write(file, buffer, buffsize); write(file, buffer, file_size - i); #if HAVE_FDATASYNC fdatasync(file); #else fsync(file); #endif lseek(file, 0, SEEK_SET); } void overwrite_random(int num_passes) { int i; for (i = 0; i < num_passes; i++) { randomize_buffer(buffer, buffsize); overwrite(); } } void overwrite_byte(int byte) { memset(buffer, byte, buffsize); overwrite(); } void overwrite_bytes(int byte1, int byte2, int byte3) { int i; memset(buffer, byte1, buffsize); for (i = 1; i < buffsize; i += 3) { buffer[i] = byte2; buffer[i+1] = byte3; } overwrite(); } int sunlink(const char *path, const int simple) { struct stat statbuf; #if HAVE_LINUX_EXT2_FS_H struct statfs fs_stats; int flags = 0; #endif struct flock flock; if (lstat(path, &statbuf) == -1) return -1; if (!S_ISREG(statbuf.st_mode)) return rename_unlink(path); if (statbuf.st_nlink > 1) { rename_unlink(path); errno = EMLINK; return -1; } file_size = statbuf.st_size; buffsize = statbuf.st_blksize; if ( (buffer = (unsigned char *)alloca(buffsize)) == NULL ) { errno = ENOMEM; return -1; } if ( (file = open(path, O_WRONLY)) == -1) /* BSD doesn't support O_SYNC */ return -1; if (fcntl(file, F_WRLCK, &flock) == -1) { close(file); return -1; } #if HAVE_LINUX_EXT2_FS_H if (fstatfs(file, &fs_stats) == -1 && errno != ENOSYS) { close(file); return -1; } if (fs_stats.f_type == EXT2_SUPER_MAGIC) if (ioctl(file, EXT2_IOC_GETFLAGS, &flags) == -1) { close(file); return -1; } if ( (flags & EXT2_UNRM_FL) || (flags & EXT2_IMMUTABLE_FL) || (flags & EXT2_APPEND_FL) ) { close(file); errno = EPERM; return -1; } #endif /* HAVE_LINUX_EXT2_FS_H */ /* chflags(2) turns out to be a different system call in every BSD derivative. The important thing is to make sure we'll be able to unlink it after we're through messing around. Unlinking it first would remove the need for any of these checks, but would leave the user with no way to overwrite the file if the process was interupted during the overwriting. So, instead we assume that the open() above will fail on immutable and append-only files and try and catch only platforms supporting NOUNLINK here. OpenBSD - doesn't support nounlink (As of 3.1) FreeBSD - supports nounlink (from 4.4 on?) Tru64 - unknown MacOS X - unknown */ #if HAVE_CHFLAGS && __FreeBSD__ if ((statbuf.st_flags & UF_IMMUTABLE) || (statbuf.st_flags & UF_APPEND) || (statbuf.st_flags & UF_NOUNLINK) || (statbuf.st_flags & SF_IMMUTABLE) || (statbuf.st_flags & SF_APPEND) || (statbuf.st_flags & SF_NOUNLINK)) { close(file); errno = EPERM; return -1; } #endif /* HAVE_CHFLAGS */ if (simple) { overwrite_random(1); } else { overwrite_random(4); overwrite_byte(0x55); overwrite_byte(0xAA); overwrite_bytes(0x92, 0x49, 0x24); overwrite_bytes(0x49, 0x24, 0x92); overwrite_bytes(0x24, 0x92, 0x49); overwrite_byte(0x00); overwrite_byte(0x11); overwrite_byte(0x22); overwrite_byte(0x33); overwrite_byte(0x44); overwrite_byte(0x55); overwrite_byte(0x66); overwrite_byte(0x77); overwrite_byte(0x88); overwrite_byte(0x99); overwrite_byte(0xAA); overwrite_byte(0xBB); overwrite_byte(0xCC); overwrite_byte(0xDD); overwrite_byte(0xEE); overwrite_byte(0xFF); overwrite_bytes(0x92, 0x49, 0x24); overwrite_bytes(0x49, 0x24, 0x92); overwrite_bytes(0x24, 0x92, 0x49); overwrite_bytes(0x6D, 0xB6, 0xDB); overwrite_bytes(0xB6, 0xDB, 0x6D); overwrite_bytes(0xDB, 0x6D, 0xB6); overwrite_random(4); } #if HAVE_LINUX_EXT2_FS_H ioctl(file, EXT2_IOC_SETFLAGS, EXT2_SECRM_FL); #endif if (ftruncate(file, 0) == -1) { close(file); return -1; } close(file); return rename_unlink(path); }