aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2014-02-14 11:16:34 +1300
committerTom Ryder <tom@sanctum.geek.nz>2014-02-14 11:16:34 +1300
commitac03f31601545551a44f256379fb02cc8f8b4ce7 (patch)
tree229b72b32547f160f21e02f0beb8df3c0efe1e4a
parentInitial commit (diff)
downloadMail-Run-Crypt-ac03f31601545551a44f256379fb02cc8f8b4ce7.tar.gz
Mail-Run-Crypt-ac03f31601545551a44f256379fb02cc8f8b4ce7.zip
First code commit
Very bare bones at the moment. Needs perldoc or man(1) help and possibly a Makefile to install it.
-rw-r--r--README.markdown45
-rw-r--r--README.md4
-rwxr-xr-xcroncrypt125
3 files changed, 170 insertions, 4 deletions
diff --git a/README.markdown b/README.markdown
new file mode 100644
index 0000000..f877739
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,45 @@
+Croncrypt
+=========
+
+Wrapper to sign and encrypt `cron(8)` output and errors with PGP/MIME before
+sending them to the default MAILTO destination.
+
+ CRONCRYPT_KEYID=0x0A1B2C3D4E5F6G7H
+ CRONCRYPT_PASSPHRASE=hibbityboo
+ MAILTO=tom@sanctum.geek.nz
+ 0 1 * * * tom croncrypt rsync /home/tom/important-file /home/backups
+
+The main design goal is simplicity; just whack `croncrypt` in front of all your
+`crontab(5)` entries, provided they don't use pipes or stderr/stdout redirects,
+in which case you should consider putting it all into a script file anyway.
+
+Don't use your own GPG key for signing! I recommend you create a dedicated key
+just for Croncrypt, and sign it locally with `gpg --lsign` so that your
+software trusts it locally.
+
+Installation
+------------
+
+Put the `croncrypt` binary somewhere in your `crontab`'s `PATH`, and install
+the following Perl modules:
+
+* `Carp`
+* `Data::Dumper`
+* `IPC::Open3`
+* `Mail::GnuPG`
+* `MIME::Entity`
+* `Symbol`
+
+On Debian-derived systems, this should do the trick:
+
+ # aptitude install perl-base perl-modules \
+ libmail-gnupg-perl libmime-tools-perl
+
+License
+-------
+
+Copyright (c) [Tom Ryder][1]. Distributed under Perl's [Artistic License][2].
+
+[1]: http://www.sanctum.geek.nz/about/tom-ryder
+[2]: http://dev.perl.org/licenses/artistic.html
+
diff --git a/README.md b/README.md
deleted file mode 100644
index 4068725..0000000
--- a/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-croncrypt
-=========
-
-Sign and encrypt cron(8) output
diff --git a/croncrypt b/croncrypt
new file mode 100755
index 0000000..1c09047
--- /dev/null
+++ b/croncrypt
@@ -0,0 +1,125 @@
+#!/usr/bin/env perl
+
+#
+# croncrypt: Wrapper to sign and encrypt cron output and errors with PGP/MIME
+# before sending them to the default MAILTO destination.
+#
+# CRONCRYPT_KEYID=0x0A1B2C3D4E5F6G7H
+# CRONCRYPT_PASSPHRASE=hibbityboo
+# MAILTO=tom@sanctum.geek.nz
+# 0 1 * * * tom croncrypt rsync /home/tom/important-file /home/backups
+#
+# The main design goal is simplicity; just whack a «croncrypt» in front of all
+# your cron tasks, provided they don't use pipes or stderr/stdout redirects,
+# in which case you should consider putting it all into a script file anyway.
+#
+# Don't use your own GPG key for signing! Create a dedicated key just for
+# croncrypt, and sign it locally with «gpg --lsign» maybe.
+#
+# Author: Tom Ryder <tom@sanctum.geek.nz>
+# Copyright: 2014 Sanctum
+# License: Artistic <http://dev.perl.org/licenses/artistic.html>
+#
+# $Id$
+#
+package Sanctum::Croncrypt;
+
+# Force me to write this properly
+use strict;
+use warnings;
+
+# Decree package version to pacify Perl::Critic
+our $VERSION = 0.1;
+
+# Pull in some required modules
+use Carp;
+use Data::Dumper;
+use IPC::Open3;
+use Mail::GnuPG;
+use MIME::Entity;
+use Symbol 'gensym';
+
+# Bail if run without arguments
+if ( !@ARGV ) {
+ printf "%s\n", 'USAGE: croncrypt <command>';
+ exit 1;
+}
+
+# Bail if we don't have the environment variables we need
+my @fails = ();
+if ( !exists $ENV{'CRONCRYPT_KEYID'} ) {
+ push @fails, 'CRONCRYPT_KEYID is not set; set it to your key ID.';
+}
+if ( !exists $ENV{'CRONCRYPT_PASSPHRASE'} ) {
+ push @fails,
+ 'CRONCRYPT_PASSPHRASE is not set; set it to your key\'s passphrase.';
+}
+if ( !exists $ENV{'MAILTO'} ) {
+ push @fails, 'MAILTO is not set; set it to the message\'s destination.';
+}
+if (@fails) {
+ foreach my $fail (@fails) {
+ printf {*STDERR} "croncrypt: FAIL: %s\n", $fail;
+ }
+ exit 1;
+}
+
+# Read details from environment
+my $recipient = $ENV{MAILTO};
+my $key = $ENV{CRONCRYPT_KEYID};
+my $passphrase = $ENV{CRONCRYPT_PASSPHRASE};
+
+# Establish filehandles; need to specifically create symbol for stderr
+my ( $stdin, $stdout, $stderr );
+$stderr = gensym;
+
+# Run the command in the arguments and wait for it to finish
+my $pid = open3( $stdin, $stdout, $stderr, @ARGV );
+waitpid $pid, 0;
+
+# Read any and all output and errors
+my @output = <$stdout>;
+my @errors = <$stderr>;
+
+# Close the filehandles, placating Perl::Critic with return checks
+close $stdin
+ or croak('Could not close stdin');
+close $stdout
+ or croak('Could not close stdout');
+close $stderr
+ or croak('Could not close stderr');
+
+# If there was output, mail it
+if (@output) {
+ my $subject = sprintf 'croncrypt output: %s', join q{ }, @ARGV;
+ mail( $subject, \@output );
+}
+
+# If there were errors, mail them
+if (@errors) {
+ my $subject = sprintf 'croncrypt errors: %s', join q{ }, @ARGV;
+ mail( $subject, \@errors );
+}
+
+# Send the message to the address in $ENV{MAILTO}
+sub mail {
+ my ( $subject, $content ) = @_;
+
+ # Build MIME object with plaintext message
+ my $mime = MIME::Entity->build(
+ To => $recipient,
+ Subject => $subject,
+ Data => $content,
+ );
+
+ # Encrypt the MIME object
+ my $mgpg = Mail::GnuPG->new(
+ key => $key,
+ passphrase => $passphrase,
+ );
+ $mgpg->mime_signencrypt( $mime, $recipient );
+
+ # Send it
+ return $mime->send();
+}
+