]> git.donarmstrong.com Git - bin.git/blob - sshsendmail
add mutt alias which executes neomutt if that exists
[bin.git] / sshsendmail
1 #! /usr/bin/perl
2 # sshsendmail uses ssh to send a mail message to a different machine,
3 # and is released under the terms of the GPL version 2, or any later
4 # version, at your option. See the file README and COPYING for more
5 # information.
6 # Copyright 2005-10 by Don Armstrong <don@donarmstrong.com>.
7
8 # parse command line options
9
10 # connect to host
11
12 use warnings;
13 use strict;
14
15 use Getopt::Long;
16 use Pod::Usage;
17
18 =head1 NAME
19
20 sshsendmail - Uses ssh to send a mail message to a different machine's copy of sendmail.
21
22 =head1 SYNOPSIS
23
24 Stick this command in /usr/lib/nullmailer/sshsendmail.
25
26 Then add
27
28 foohost.com sshsendmail --identity=/var/mail/.ssh/id_rsa --username remotemail --sendmail-options='-baruser@foohost.com'
29
30 to /etc/nullmailer/remotes.
31
32  Options:
33   --identity, -i ssh identity to use to connect to the server
34   --username, -l remote username
35   --sendmail-options, -o options to pass to sendmail
36   --debug, -d debugging level (Default 0)
37   --help, -h display this help
38   --man, -m display manual
39
40 =head1 OPTIONS
41
42 =over
43
44 =item B<--identity, -i>
45
46 ssh identity to send to the server we're connecting to
47
48 =item B<--debug, -d>
49
50 Debug verbosity. (Default 0)
51
52 =item B<--help, -h>
53
54 Display brief useage information.
55
56 =item B<--man, -m>
57
58 Display this manual.
59
60 =back
61
62
63 =cut
64
65 use User;
66 use File::Basename qw(basename);
67 use IO::Handle;
68 use IO::File;
69 use Digest::MD5 qw(md5_hex);
70 use Sys::Syslog qw(:standard :macros);
71 use Data::Dumper;
72
73 use vars qw($DEBUG);
74
75 $0 = basename($0);
76
77 # XXX parse config file
78
79 openlog('sshsendmail',[qw(nofatal perror pid)], LOG_MAIL);
80
81 my %options = (debug              => 0,
82                help               => 0,
83                man                => 0,
84                host               => undef,
85                identity           => undef,
86                username           => undef,
87                'sendmail_options' => [],
88               );
89
90 my $new_nullmailer = 0;
91 ## The new nullmailer passes options on STDIN and the message on FD 3.
92 my $message_fd = \*STDIN;
93 eval {
94     my $fh = IO::Handle->new() or
95         die "Unable to create new fd";
96     $fh->fdopen(3,"r") or
97         die "Unable to open fd 3: $!";
98     $message_fd = $fh;
99     $new_nullmailer = 1;
100     push @ARGV, map {chomp; "--$_"} <STDIN>;
101 };
102
103 GetOptions(\%options,'identity|i=s','username|l=s','daemon|d', 'syslog|s',
104            'host=s',
105            'sendmail_options|sendmail-options|o=s@',
106            'help|h|?','man|m');
107
108 pod2usage() if $options{help};
109 pod2usage({verbose=>2}) if $options{man};
110
111 $DEBUG = $options{debug};
112
113 if (not (@ARGV or defined $options{host})) {
114      print STDERR "${0}: Too few command-line arguments\n";
115      print <<END;
116 usage: ${0} [flags] remote-address < mail-file
117 Send an email message via ssh+sendmail
118   -p, --port=INT  Set the port number on the remote host to connect to
119   -d, --daemon    use syslog exclusively  (Debian only)
120   -s, --syslog    use syslog additionally (Debian only)
121
122   -h, --help      Display this help and exit
123 END
124      exit(1);
125 }
126
127 if (not defined $options{host} and @ARGV) {
128     $options{host} = shift @ARGV;
129 }
130
131 my @message = <$message_fd>;
132 #throw away envelope sender
133 shift @message;
134 my @recipients;
135
136 while (my $line = shift @message) {
137      last if $line eq "\n";
138      chomp $line;
139      push @recipients,$line;
140 }
141
142 @recipients = qw(-t) if not @recipients;
143
144 my @ssh_arguments = ($options{host});
145
146 push @ssh_arguments, '-i', $options{identity} if defined $options{identity};
147 push @ssh_arguments, '-l', $options{username} if defined $options{username};
148 my @sendmail_options;
149 push @sendmail_options,
150     ref($options{sendmail_options})?@{$options{sendmail_options}}:$options{sendmail_options};
151 push @sendmail_options,@recipients;
152 $Data::Dumper::Useqq=1;
153 my $sendmail_options = Data::Dumper->Dump([\@sendmail_options],[qw(*sendmail_options)]);
154 print STDERR $sendmail_options if $DEBUG;
155 push @ssh_arguments, q(perl -e ').<<EOF .q(');
156 use Digest::MD5 qw(md5_hex);
157 use IO::Handle;
158 my \@message = <>;
159 my $sendmail_options
160 my \$digest = pop \@message;
161 \$digest =~ /(.*)([0-9a-fA-F]{32})\n/;
162 \$digest = \$2;
163 if (length \$1) {
164     push \@message,\$1;
165 }
166 my \$message = join(q(),\@message);
167 if (\$digest eq md5_hex(\$message)) {
168     my \$sendmail = IO::Handle->new();
169     open (\$sendmail,q(|-),q(/usr/lib/sendmail), \@sendmail_options) or
170         die "Unable to open sendmail: \$!";
171     print {\$sendmail} \$message or
172         die "Unable to write to sendmail: \$!";
173     close (\$sendmail) or
174         die "Unable to close sendmail: \$!";
175 } else {
176    die "Digest failure! \$digest vs ".md5_hex(\$message);
177 }
178 EOF
179
180 $Data::Dumper::Useqq=0;
181 print STDERR Dumper(\@ssh_arguments) if $DEBUG;
182
183 qx(ping -q -w 3 -c 1 $options{host} 2>/dev/null);
184 if ($?) {
185     syslog(LOG_WARNING,"${0}: Failed: unable to ping $options{host}\n");
186     exit (9);
187 }
188 print STDERR md5_hex(join('',@message))."\n" if $DEBUG;
189 my $ssh = new IO::Handle;
190 open($ssh,'|-','ssh',@ssh_arguments) or exit(17);
191 print {$ssh} @message or exit(17);
192 print {$ssh} md5_hex(join('',@message))."\n";
193 close $ssh or exit(17);
194 if ($?) {
195     syslog(LOG_WARNING,"${0}: Failed: sendmail died for some reason\n");
196     syslog(LOG_WARNING,join("\n",@ssh_arguments));
197     exit (17);
198 }
199 else {
200     syslog(LOG_INFO,"${0}: Succeeded: Yeay\n");
201     exit 0;
202 }