move srm to own dir

This commit is contained in:
2020-02-14 23:05:21 -08:00
parent 1b4bfe84eb
commit 769de599fc
7 changed files with 258 additions and 4 deletions

21
srm/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
CODE LICENSE
This code is released under the ISC license.
--------------------------------------------------------------------------------
the ISC license:
Copyright (c) 2011 Kyle Isom <coder@kyleisom.net>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--------------------------------------------------------------------------------

54
srm/Makefile.in Normal file
View File

@@ -0,0 +1,54 @@
VERSION := 1.3.1
CC := gcc
TARGET := srm
OBJS :=
LIBS :=
PREFIX ?= $PREFIX
MANDIR ?= $MANDIR
CFLAGS += -Wall -Wextra -pedantic -Wshadow -Wpointer-arith -Wcast-align
CFLAGS += -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations
CFLAGS += -Wnested-externs -Winline -Wno-long-long -Wunused-variable
CFLAGS += -Wstrict-prototypes -Werror -ansi -static
CFLAGS += -D$(TARGET)_VERSION="\"$(TARGET) version $(VERSION)\""
CFLAGS += OS_CFLAGS
all: $(TARGET)
$(TARGET): $(TARGET).o $(OBJS)
${CC} -o $(TARGET) ${CFLAGS} ${LDFLAGS} $(LIBS) $(OBJS) $(TARGET).o
install: $(TARGET)
install -m 0755 $(TARGET) $(PREFIX)/bin/$(TARGET)
install -m 0755 -d $(MANDIR)/man1
install -m 0444 $(TARGET).1 $(MANDIR)/man1/$(TARGET).1
uninstall:
-rm -f $(PREFIX)/bin/$(TARGET)
-rm -f $(MANDIR)/man1/$(TARGET).1
lint:
-mkdir security
-rats -w 3 $(TARGET).[ch] > security/rats.out
-lint -fhrs $(TARGET).c > security/lint.out
-splint +posixlib $(TARGET).[ch] > security/splint.out
dist: clean
-mkdir $(TARGET)-$(VERSION)
-cp * $(TARGET)-$(VERSION)
-cd $(TARGET)-$(VERSION) && make distclean && cd ..
-tar czf $(TARGET)-$(VERSION).tgz $(TARGET)-$(VERSION)
distclean: clean
-rm -f Makefile
htmldoc:
-mandoc -Thtml $(TARGET).1 > $(TARGET).1.html
tags:
ctags *.[ch]
.c.o:
$(CC) -c ${CFLAGS} $?
.PHONY: clean all install lint uninstall dist distclean htmldoc tags

36
srm/README Normal file
View File

@@ -0,0 +1,36 @@
srm - securely wipe files
--------------------------
srm is a utility to overwrite files with random data in one or more passes.
Dependencies
------------
None.
Compatibility
-------------
srm has been tested on the following operating systems:
* OpenBSD (5.1-snap)
* OS X (10.8)
* Linux (Debian 6.0)
Installation
------------
make build install
Usage
-----
srm [-v] [-n number] file list
options:
-n <number of passes>: specify number of passes
(default is 3 passes)
-v: verbose mode. display list of failures and wiped files after wiping
Known bugs / caveats
--------------------
srm can't recursively remove files, i.e. it can't remove directories.

57
srm/config.sh Executable file
View File

@@ -0,0 +1,57 @@
#!/bin/sh
TARGET="$(cat Makefile.in | grep 'TARGET :=' | awk -F' ' '{ print $3; }')"
echo "configuring ${TARGET}"
which sed 2>/dev/null 1>/dev/null
if [ $? -ne 0 ]; then
echo "cannot find sed!" 1>&2
fi
OPSYS=$(uname -s)
echo "Configuring for ${OPSYS}..."
if [ "x${OPSYS}" = "xLinux" ]; then
OS_CFLAGS="-D_BSD_SOURCE -D_POSIX_SOURCE -D_XOPEN_SOURCE"
elif [ "x${OPSYS}" = "xDarwin" ]; then
OS_CFLAGS="-D_DARWIN_C_SOURCE"
else
OS_CFLAGS=""
fi
if [ -z "${OS_CFLAGS}" ]; then
echo "${OPSYS} requires no extra build flags."
else
echo "${OPSYS} requires build flags ${OS_CFLAGS}"
fi
if [ -z "${PREFIX}" ]; then
PREFIX="/usr/local"
fi
if [ "${PREFIX}" = "/usr" ]; then
MANDIR="$(PREFIX)/share/man"
elif [ "${PREFIX}" = "/usr/local" ]; then
if [ "${OPSYS}" = "Darwin" ]; then
MANDIR="${PREFIX}/share/man"
else
MANDIR="${PREFIX}/man"
fi
else
MANDIR="${PREFIX}/man"
fi
if [ "$1" = "DEBUG" ]; then
OS_CFLAGS="${OS_CFLAGS} -g -O0"
fi
echo "prefix: ${PREFIX}"
echo "mandir: ${MANDIR}"
echo "writing new Makefile"
cat Makefile.in | sed -e "s|OS_CFLAGS|${OS_CFLAGS}|" | \
sed -e "s|\$PREFIX|${PREFIX}|" | \
sed -e "s|\$MANDIR|${MANDIR}|" > Makefile
echo "done."

84
srm/srm.1 Normal file
View File

@@ -0,0 +1,84 @@
.Dd $Mdocdate$
.Dt SRM 1
.Os
.Sh NAME
.Nm srm
.Nd securely delete files
.Sh SYNOPSIS
.Nm
.Op Fl h
.Op Fl n Ar number
.Op Fl r
.Op Fl v
.Op Fl V
.Ar files
.Sh DESCRIPTION
.Nm
is a simple secure file deletion tool. It overwrites the file with several
passes of random data before unlinking it. If no options are specified, Nm
defaults to three passes.
.Nm
supports the following options:
.Bl -tag -width .Ds
.It Fl h
Display a brief help message.
.It Fl n Ar number
Specify the number of times to overwrite each target with random data.
.It Fl r
Recursive mode. Delete any directories and all subdirectories underneath.
.It Fl v
Verbose mode. Displays a list of both files that failed to wipe and files that
were successfully wiped.
.It Fl V
Print version information.
.El
.Sh EXIT STATUS
.Ex -std
The exit values are standard
.Xr sysexits 3
values.
.Sh EXAMPLES
Wipe files
.Pa foo
and
.Pa bar
with three passes:
.Dl $ srm foo bar
Wipe files
.Pa baz
and
.Pa quux
with ten passes:
.Dl $ srm -n 10 baz quux
Wipe all PGP keys, i.e. files with extension
.Pa *.asc :
.Dl $ srm *.asc
Recursive deletes aren't implemented yet. A workaround is to use
.Nm
and
.Xr find 1 ,
for example to delete all
.Pa *.pgp
files:
.Dl $ find . -iname '*.pgp' -exec srm '{}' \;
.Sh DIAGNOSTICS
.Nm
uses the standard
.Xr err 3
facilities to report any errors that occur.
.Sh SEE ALSO
The srm page on
.Lk http://www.tyrfingr.is/projects/srm/ "tyrfinger" .
.Sh STANDARDS
.Nm
conforms to
.St -ansiC .
.Sh AUTHORS
.Nm
was written by
.An "Kyle Isom" Aq Mt kyle@tyrfingr.is .
.Sh BUGS
None known. Report bugs to the author.
.Sh LICENSE
.Nm
is released under an ISC license.

369
srm/srm.c Normal file
View File

@@ -0,0 +1,369 @@
/*
* Copyright (c) 2011, 2012 Kyle Isom <kyle@tyrfingr.is>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <err.h>
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#define DEFAULT_PASSES 3
#define DEV_RANDOM "/dev/urandom"
#define MAX_CHUNK 4096
static int do_wipe(char *, size_t, int);
static int wipe(char *);
static int rmdirs(const char *, size_t);
static void usage(void);
static void version(void);
extern char *__progname;
/*
* overwrite a file with one or more passes of random data, then unlink it.
*/
int
main(int argc, char **argv)
{
size_t passes, tmp_passes, wiped, failed, i;
char **file_ptr, **wipe_success, **wipe_fail;
int retval, opt, verbose, recur;
passes = DEFAULT_PASSES;
retval = EX_DATAERR;
wiped = 0;
failed = 0;
verbose = 0;
recur = 0;
if (argc == 1)
usage();
while (-1 != (opt = getopt(argc, argv, "hn:rvV"))) {
switch( opt ) {
case 'h':
usage();
break; /* don't technically need it but meh */
case 'n':
tmp_passes = atoi(optarg);
passes = tmp_passes > 0 ? tmp_passes : passes;
break;
case 'r':
recur = 1;
break;
case 'v':
verbose = 1;
break;
case 'V':
version();
exit(EX_OK);
default:
usage();
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
file_ptr = argv;
wipe_success = calloc(argc, sizeof(char *));
wipe_fail = calloc(argc, sizeof(char *));
while (NULL != *file_ptr) {
printf("%s: ", *file_ptr);
fflush(stdout);
if (EX_OK != do_wipe(*file_ptr, passes, recur)) {
wipe_fail[failed] = strdup(*file_ptr);
failed++;
} else {
wipe_success[wiped] = strdup(*file_ptr);
wiped++;
printf(" OK!");
}
file_ptr++;
printf("\n");
}
if (verbose) {
if (0 < wiped) {
printf("success: ");
for( i = 0; i < wiped; ++i ) {
printf("%s ", wipe_success[i]);
}
printf("\n");
}
if (0 < failed) {
printf("failures: ");
for( i = 0; i < failed; ++i ) {
printf("%s ", wipe_fail[i]);
}
printf("\n");
}
}
/* free allocated memory */
for (i = 0; i < failed; ++i) {
free(wipe_fail[i]);
wipe_fail[i] = NULL;
}
free(wipe_fail);
wipe_fail = NULL;
for (i = 0; i < wiped; ++i) {
free(wipe_success[i]);
wipe_success[i] = NULL;
}
free(wipe_success);
wipe_success = NULL;
return retval;
}
/*
* takes a filename and the number of passes to wipe the file
*/
int
do_wipe(char *filename, size_t passes, int recur)
{
struct stat sb;
size_t filesize, i;
int retval;
retval = EX_IOERR;
if (-1 == stat(filename, &sb)) {
warn("%s", filename);
return retval;
}
if (recur && sb.st_mode & S_IFDIR) {
if (EX_OK != rmdirs(filename, passes)) {
printf("!");
return retval;
} else {
printf(".");
fflush(stdout);
retval = EX_OK;
}
} else {
filesize = sb.st_size;
for (i = 0; i < passes; ++i) {
if (EX_OK != wipe(filename)) {
printf("!");
return retval;
} else if (-1 == stat(filename, &sb)) {
printf("!");
return retval;
} else if (filesize != (size_t)sb.st_size) {
printf("!");
return retval;
}
}
if (-1 == truncate(filename, (off_t)0))
warn("%s", filename);
if (-1 == unlink(filename)) {
warn("%s", filename);
} else {
printf(".");
fflush(stdout);
retval = EX_OK;
}
}
return retval;
}
/*
* takes a filename and attempts to overwrite it with random data
*/
int
wipe(char *filename)
{
struct stat sb;
size_t chunk, filesize, rdsz, wiped, wrsz;
FILE *devrandom, *target;
int retval;
char *rdata;
retval = EX_IOERR;
wiped = 0;
if (-1 == stat(filename, &sb))
return retval;
filesize = sb.st_size;
/*
* open devrandom first: if this fails, we don't want to touch the
* target file.
*/
devrandom = fopen(DEV_RANDOM, "r");
if (NULL == devrandom || -1 == ferror(devrandom)) {
warn("failed to open PRNG %s!", DEV_RANDOM);
return retval;
}
/*
* for security purposes, we want to make sure to actually overwrite
* the file. r+ gives us read/write but more importantly, sets the
* write stream at the beginning of the file. a side note is that when
* overwriting a file, its size will never seem to change.
*/
target = fopen(filename, "r+");
if (NULL == target || -1 == ferror(target)) {
warn("failed to open %s", filename);
fclose(devrandom);
return retval;
}
rewind(target);
/*
* wait to calloc until we really need the data - makes cleaning up less
* tricky.
*/
rdata = calloc(MAX_CHUNK, sizeof(char));
if (NULL == rdata) {
warn("could not allocate random data memory");
fclose(devrandom);
fclose(target);
return retval;
}
while (wiped < filesize) {
chunk = filesize - wiped;
chunk = chunk > MAX_CHUNK ? MAX_CHUNK : chunk;
rdsz = fread( rdata, sizeof(char), chunk, devrandom );
wrsz = fwrite( rdata, sizeof(char), chunk, target );
if (-1 == stat(filename, &sb)) {
warn(" stat on %s failed", filename);
break;
}
if ((rdsz != wrsz) || (filesize != (unsigned int)sb.st_size)) {
warn("invalid read/write size");
break;
}
wiped += chunk;
}
if ((0 != fclose(devrandom)) || (0 != fclose(target)))
warn("%s", filename);
else
retval = EX_OK;
free(rdata);
rdata = NULL;
return retval;
}
/*
* remove a directory, all files in it, and all subdirectories.
*/
int
rmdirs(const char *path, size_t passes)
{
char child[FILENAME_MAX + 1];
struct dirent *dp;
DIR *dirp;
int fail = 0;
if (NULL == (dirp = opendir(path)))
return EX_IOERR;
while (NULL != (dp = readdir(dirp))) {
if (0 == strncmp("..", dp->d_name, 3))
continue;
if (0 == strncmp(".", dp->d_name, 2))
continue;
snprintf(child, FILENAME_MAX, "%s/%s", path, dp->d_name);
if (DT_DIR == dp->d_type) {
fail = rmdirs(child, passes);
if (EX_IOERR == fail)
break;
} else {
fail = do_wipe(child, passes, 1);
if (EX_IOERR == fail)
break;
}
}
if (-1 == closedir(dirp))
return EX_IOERR;
if (EX_IOERR == fail)
return EX_IOERR;
if (-1 == rmdir(path))
return EX_IOERR;
else
return EX_OK;
}
/*
* print a quick usage message
*/
void
usage()
{
version();
printf("usage: %s [-v] [-n number] files\n", __progname);
printf(" -n passes specify number of passes\n");
printf(" (default is %d passes)\n", DEFAULT_PASSES);
printf(" -r recursive delete\n");
printf(" -v display list of failures and wiped files"
" after wiping\n"
" (verbose mode).\n");
printf(" -V print version information.");
printf("\n");
exit(EX_USAGE);
}
/*
* print program version information
*/
void
version()
{
printf("%s\n", srm_VERSION);
}