1#!/usr/local/bin/perl
2use strict;
3my $VERSION = '0.1';
4my $COPYRIGHT = 'Copyright (C) 2005-2011 Jonathan Buhacoff <jonathan@buhacoff.net>';
5my $LICENSE = 'http://www.gnu.org/licenses/gpl.txt';
6my %status = ( 'OK' => 0, 'WARNING' => 1, 'CRITICAL' => 2, 'UNKNOWN' => 3 );
7
8use Getopt::Long;
9use Mail::IMAPClient;
10use IO::Socket::SSL;
11use Net::SSLeay;
12
13# get options from command line
14Getopt::Long::Configure("bundling");
15my $verbose = 0;
16my $help = "";
17my $help_usage = "";
18my $show_version = "";
19my $imap_server = "";
20my $default_imap_port = "143";
21my $default_imap_ssl_port = "993";
22my $imap_port = "";
23my $timeout = 60;
24my $ok;
25$ok = Getopt::Long::GetOptions(
26	"V|version"=>\$show_version,
27	"v|verbose+"=>\$verbose,"h|help"=>\$help,"usage"=>\$help_usage,
28	# imap settings
29	"H|hostname=s"=>\$imap_server,"p|port=i"=>\$imap_port,
30	# time
31	"t|timeout=i"=>\$timeout
32	);
33
34if( $show_version ) {
35	print "$VERSION\n";
36	exit $status{UNKNOWN};
37}
38
39if( $help ) {
40	exec "perldoc", $0 or print "Try `perldoc $0`\n";
41	exit $status{UNKNOWN};
42}
43
44if( $help_usage
45	||
46	( $imap_server eq ""  )
47  ) {
48	print "Usage: $0 -H host [-p port]\n";
49	exit $status{UNKNOWN};
50}
51
52my @certs = (); # we have to store the certs we get Net::SSLeay here so that we can output them in REVERSE order (server cert first, root cert last)
53
54# connect to IMAP server
55print "connecting to server $imap_server\n" if $verbose > 2;
56my $imap;
57eval {
58	local $SIG{ALRM} = sub { die "exceeded timeout $timeout seconds\n" }; # NB: \n required, see `perldoc -f alarm`
59	alarm $timeout;
60
61	$imap_port = $default_imap_ssl_port unless $imap_port;
62	my $socket = IO::Socket::SSL->new(
63		PeerAddr => "$imap_server:$imap_port",
64		SSL_verify_mode => 1,
65		SSL_ca_file => undef,
66		SSL_verifycn_scheme => 'imap',
67		SSL_verifycn_name => $imap_server,
68		SSL_verify_callback => \&ssl_printer
69	);
70	die IO::Socket::SSL::errstr() unless $socket;
71	$socket->autoflush(1);
72	$imap = Mail::IMAPClient->new(Socket=>$socket, Debug => 0 );
73	$imap->State(Mail::IMAPClient->Connected);
74	$imap->_read_line() if "$Mail::IMAPClient::VERSION" le "2.2.9"; # necessary to remove the server's "ready" line from the input buffer for old versions of Mail::IMAPClient. Using string comparison for the version check because the numeric didn't work on Darwin and for Mail::IMAPClient the next version is 2.3.0 and then 3.00 so string comparison works
75#	$imap->User($username);
76#	$imap->Password($password);
77#	$imap->login() or die "Cannot login: $@";
78
79	print join("\n",reverse(@certs));
80	alarm 0;
81};
82if( $@ ) {
83	chomp $@;
84	print "Could not connect to $imap_server port $imap_port: $@\n";
85	exit $status{CRITICAL};
86}
87unless( $imap ) {
88	print "Could not connect to $imap_server port $imap_port: $@\n";
89	exit $status{CRITICAL};
90}
91
92# deselect the mailbox
93$imap->close();
94
95# disconnect from IMAP server
96print "disconnecting from server\n" if $verbose > 2;
97$imap->logout();
98
99
100exit $status{OK};
101
102# see IO::Socket::SSL documentation for SSL_verify_callback:
103sub ssl_printer {
104	my ($boolOpenSSLResult, $cmemCertificateStore, $strCertIssuerOwnerAttr, $strError, $cmemPeerCertificate) = @_;
105	warn "OpenSSL says certificate is " . ( $boolOpenSSLResult ? "valid" : "invalid" ) if $verbose > 0;
106	warn "Peer certificate: $strCertIssuerOwnerAttr" if $verbose > 0;
107	warn "Errors: $strError" if $verbose > 0;
108	#print Net::SSLeay::PEM_get_string_X509($cmemPeerCertificate);
109	push @certs, $strCertIssuerOwnerAttr . "\n" . Net::SSLeay::PEM_get_string_X509($cmemPeerCertificate);
110}
111
112package main;
1131;
114
115