#!/usr/local/bin/perl # # Copyright 2003-2006 Jeremy Kister use strict; my $version = '0.64b'; my (%path,$cgi_url,$css_url,$images_url,$dbtype,$dbserver,$dbname,$dbun,$dbpw,$createdb,$plugin,$args,$forward_host,$autorespond); while($_ = shift){ if(/^\s*--esec.pl=(\S+)/){ $path{'esec.pl'} = $1; }elsif(/^\s*--eseccgi.pl=(\S+)/){ $path{'eseccgi.pl'} = $1; }elsif(/^\s*--eseccron.pl=(\S+)/){ $path{'eseccron.pl'} = $1; }elsif(/^\s*--esec.css=(\S+)/){ $path{'esec.css'} = $1; }elsif(/^\s*--images_dir=(\S+)/){ $path{'images'} = $1; }elsif(/^\s*--cgi_url=(\S+)/){ $cgi_url = $1; }elsif(/^\s*--css_url=(\S+)/){ $css_url = $1; }elsif(/^\s*--images_url=(\S+)/){ $images_url = $1; }elsif(/^\s*--dbtype=(\S+)/){ $dbtype = $1; }elsif(/^\s*--dbserver=(\S+)/){ $dbserver = $1; }elsif(/^\s*--dbname=(\S+)/){ $dbname = $1; }elsif(/^\s*--dbun=(\S+)/){ $dbun = $1; }elsif(/^\s*--dbpw=(\S+)/){ $dbpw = $1; }elsif(/^\s*--createdb=(\S+)/){ $createdb = $1; }elsif(/^\s*--probe-plugin=(\S+)/){ $plugin = $1; }elsif(/^\s*--plugin-args=\'?(.+)\'?/){ $args = $1; }elsif(/^\s*--forward_host=(\S+)/){ $forward_host=$1; }elsif(/^\s*--autorespond=(\S+)/){ $autorespond=$1; }elsif(/^\s*--help/){ print "Email Secretary v${version}\n\n"; printf(" %-20s => %s\n", "--forward_host=host", "Host to forward confirmed messages to (if any, i.e. exchange server)"); printf(" %-20s => %s\n", "--autorespond=file", "Full path and filename of autorespond (if any, i.e. /bin/autorespond)"); printf(" %-20s => %s\n", "--probe-plugin=prog", "Program to send message to to determine if a probe should be sent"); printf(" %-20s => %s\n", "--plugin-args=args", "Arguments to give plugin program, surrounded by single-quotes"); printf(" %-20s => %s\n", "--esec.pl=dir", "Directory to install esec.pl (to be used in .qmail-username)"); printf(" %-20s => %s\n", "--eseccgi.pl=dir", "Directory to install eseccgi.pl (to be used in your webserver)"); printf(" %-20s => %s\n", "--eseccron.pl=dir", "Directory to install eseccron.pl (to be ran by cron)"); printf(" %-20s => %s\n", "--esec.css=dir", "Directory to install esec.css (to be read by a web browser)"); printf(" %-20s => %s\n", "--images_dir=dir", "Directory to install images (to be read by a web browser)"); printf(" %-20s => %s\n", "--cgi_url=url", "URL to eseccgi.pl (ie: http://www.example.com/cgi-bin/eseccgi.pl)"); printf(" %-20s => %s\n", "--css_url=url", "URL to esec.css (ie: http://www.example.com/includes/esec.css)"); printf(" %-20s => %s\n", "--images_url=url", "URL to images (ie: http://www.example.com/images/"); printf(" %-20s => %s\n", "--dbtype=type", "Type of Database: MySQL, MSSQL, Sybase, or other"); printf(" %-20s => %s\n", "--dbserver=hostname", "Database server hostname or IP address"); printf(" %-20s => %s\n", "--dbname=dbname", "Name of ESec database"); printf(" %-20s => %s\n", "--dbun=username", "Username for ESec database"); printf(" %-20s => %s\n", "--dbpw=password", "Password for ESec database"); printf(" %-20s => %s\n", "--createdb=[Y|N]", "Should setup program create database tables (Y or N)"); print "\n"; exit; }else{ die "unknown argument: $_\n"; } } print "looking for Net::SMTP...\n"; unless(eval{ require Net::SMTP }){ die 'You need Net::SMTP installed, available via CPAN at ', "http://search.cpan.org/CPAN/authors/id/G/GB/GBARR/libnet-1.17.tar.gz\n"; } print "looking for Net::DNS...\n"; unless(eval{ require Net::DNS }){ die 'You need Net::DNS installed, available via CPAN at ', "http://search.cpan.org/CPAN/authors/id/C/CR/CREIN/Net-DNS-0.45.tar.gz\n"; } print "looking for DBI...\n"; unless(eval{ require DBI }){ die 'You need DBI installed, available via CPAN at ', "http://search.cpan.org/CPAN/authors/id/T/TI/TIMB/DBI-1.46.tar.gz\n"; } print "looking for CGI...\n"; # if user has no plans of using eseccgi, this test can be commented out unless(eval{ require CGI }){ die 'You need CGI installed, available via CPAN at ', "http://search.cpan.org/CPAN/authors/id/L/LD/LDS/CGI.pm-3.05.tar.gz\n"; } print "looking for Mail::VRFY...\n"; my $HAVE_VRFY; unless(eval{ require Mail::VRFY; $HAVE_VRFY=1; }){ warn 'Mail::VRFY NOT FOUND - some confirmation probes will sit in your outbound', "queue, when they didnt really have to.\n"; } print "\n", "Now to answer a few questions about your setup.\n\n"; unless(defined($forward_host)){ print "Host to forward confirmed email to (if any): "; chop($forward_host = <>); } unless(defined($autorespond)){ print "Path and filename to autorespond utility (if any): "; chop($autorespond=<>); } if($autorespond){ until(-x $autorespond || $autorespond eq ''){ print "cannot execute $autorespond - re-enter full path and filename (enter for none): "; chop($autorespond=<>); } } unless(defined($plugin)){ print "What program should be called to determine if a probe should be sent (i.e. spamc)? (ENTER for none): "; chop($plugin=<>); if(defined($plugin) && ($plugin ne '')){ print "Arguments to give ${plugin}, surrounded by single-quotes: (i.e. '-c') (ENTER for none): "; chop($args=<>); } } until(exists($path{'esec.pl'}) && $path{'esec.pl'} ne ''){ print "Directory to install esec.pl? (to be called in .qmail-username) "; chop($path{'esec.pl'} = <>); } until(exists($path{'eseccron.pl'}) && $path{'eseccron.pl'} ne ''){ print "Directory to install eseccron.pl? (to be called in your crontab) "; chop($path{'eseccron.pl'} = <>); } until(exists($path{'eseccgi.pl'}) && $path{'eseccgi.pl'} ne ''){ print "Directory to install eseccgi.pl? (to be executed via cgi-bin): "; chop($path{'eseccgi.pl'} = <>); } until(exists($path{'esec.css'}) && $path{'esec.css'} ne ''){ print "Directory to install esec.css? (to be read via the web): "; chop($path{'esec.css'} = <>); } until(exists($path{'images'}) && $path{'images'} ne ''){ print "Directory to install images? (to be read via the web): "; chop($path{'images'} = <>); } until(defined($cgi_url) && $cgi_url ne ''){ print "Enter full URL eseccgi.pl will be accessed as\n", "(ie: http://www.example.com/cgi-bin/eseccgi.pl): "; chop($cgi_url = <>); } until(defined($css_url) && $css_url ne ''){ print "Enter full URL esec.css will be accessed as\n", "(ie: http://www.example.com/includes/esec.css): "; chop($css_url = <>); } until(defined($images_url) && $images_url ne ''){ print "Enter full URL images will be accessed from\n", "(ie: http://www.example.com/images/): "; chop($images_url = <>); } until(defined($dbtype) && ($dbtype eq 'MySQL' || $dbtype eq 'MSSQL' || $dbtype eq 'Sybase' || $dbtype eq 'other')){ print "Your Database Type [MySQL/MSSQL/Sybase/other]: "; chop($dbtype = <>); } until(defined($dbserver) && $dbserver ne ''){ print "Your Database Server Hostname/IP Address: "; chop($dbserver = <>); } until(defined($dbname) && $dbname ne ''){ print "Your ESec Database name: "; chop($dbname = <>); } until(defined($dbun) && $dbun ne ''){ print "Your Database username: "; chop($dbun = <>); } until(defined($dbpw) && $dbpw ne ''){ print "Your Database password: "; chop($dbpw = <>); } if($dbtype eq 'MySQL'){ unless($createdb eq 'Y' || $createdb eq 'N' || $createdb eq 'n'){ print "Shall I set up your database for you? [Y/n] "; chop($createdb = <>); $createdb = 'Y' if($createdb eq '' || $createdb eq 'y' || $createdb =~ /^yes$/i); } }else{ warn "You must create your database structure manually; see contrib/esec.mysql\n"; } my $dsn; foreach my $file ('esec.pl','eseccgi.pl','eseccron.pl','images'){ unless(-d $path{$file}){ #because there is no perl mkdir -p (is there?) my $old; foreach my $dir (split /\//, $path{$file}){ my $path = $old . $dir; unless((-d $path) || ($dir eq '')){ mkdir($path,0755) || die "cannot create $path: $!\n"; } $old = $path . '/'; } } if($file eq 'images'){ if(opendir(D, 'contrib/images/')){ foreach my $image (grep {!/^\./} readdir D){ system('cp',"contrib/images/${image}",$path{'images'}); } closedir D; }else{ warn "cannot open contrib/images/: $!\n"; } next; } open(S, "src/$file") || die "cannot open src/$file: $!\n"; open(B, ">$path{$file}/$file") || die "cannot write to $path{$file}/$file: $!\n"; while(){ s/%%CSS_URL%%/$css_url/g; s/%%CGI_URL%%/$cgi_url/g; s/%%IMAGES_URL%%/$images_url/g; if(/^#%%(\S+)%%/){ if($1 eq 'DBUN'){ print B 'my $dbun = \'', $dbun, "';\n"; }elsif($1 eq 'DBPW'){ print B 'my $dbpw = \'', $dbpw, "';\n"; }elsif($1 eq 'DSN'){ print B 'my $dsn = \''; if($dbtype eq 'MySQL'){ $dsn = "DBI:mysql:host=${dbserver};database=${dbname}"; }elsif($dbtype eq 'MSSQL'){ $dsn = "DBI:Sybase:server=${dbserver}"; }elsif($dbtype eq 'Sybase'){ $dsn = "DBI:Sybase:server=${dbserver};database=${dbname}"; }else{ warn 'Database type unknown: you most modify $dsn in ', "$path{$file}/$file\n"; $dsn = "DBI:UNKNOWN:server=${dbserver};database=${dbname}"; } print B "$dsn';\n"; }elsif($1 eq 'VERSION'){ print B 'my $version = \'', $version, "';\n"; }elsif($1 eq 'PLUGIN'){ if(defined($plugin) && ($plugin ne '')){ print B 'my $plugin = \'', $plugin, "';\n"; }else{ print B 'my $plugin = undef;' . "\n"; } }elsif($1 eq 'PLUGIN_ARGS'){ if(defined($plugin) && ($plugin ne '')){ # yes, test for plugin print B 'my $args = \'', $args, "';\n"; }else{ print B 'my $args = undef;' . "\n"; } }elsif($1 eq 'HAVE_PLUGIN'){ if(defined($plugin) && ($plugin ne '')){ print B 'my $HAVE_PLUGIN = 1;' . "\n"; }else{ print B 'my $HAVE_PLUGIN;' . "\n"; } }elsif($1 eq 'HAVE_VRFY'){ if($HAVE_VRFY){ print B 'my $HAVE_VRFY = 1;' . "\n", }else{ print B 'my $HAVE_VRFY;' . "\n"; } }elsif($1 eq 'FORWARD_HOST'){ print B 'my $forward_host'; if($forward_host){ print B " = '${forward_host}'"; } print B ";\n"; }elsif($1 eq 'AUTORESPOND'){ print B 'my $autorespond'; if($autorespond){ print B " = '${autorespond}'"; } print B ";\n"; }else{ die "$_: WTF?\n"; } }else{ print B; } } close B; close S; chmod(0755,"$path{$file}/$file") || warn "could not set permissions on $path{$file}/$file: $!\n"; } if(open(F,'contrib/esec.css')){ unless(-d "$path{'esec.css'}"){ #because there is no perl mkdir -p (is there?) my $old; foreach my $dir (split /\//, $path{'esec.css'}){ my $path = $old . $dir; unless((-d "$path") || ($dir eq '')){ mkdir("$path",0755) || die "cannot create $path: $!\n"; } $old = $path . '/'; } } open(N, ">$path{'esec.css'}/esec.css") || die "cannot write to $path{'esec.css'}/esec.css: $!\n"; while(){ print N; } close F; close N; }else{ warn "cannot open contrib/esec.css: $!\n"; } if($dbtype eq 'MySQL' && $createdb eq 'Y'){ use DBI; my $dbh = DBI->connect($dsn, $dbun, $dbpw, {PrintError => 1}); my $sql; # set up database open(F, 'contrib/esec.mysql') || die "cannot open contrib/esec.mysql: $!\n"; while(){ if(/^#\s+-------/){ # send statement to sql server my $sth = $dbh->prepare($sql); $sth->execute; $sql = undef; # start fresh query }else{ next if(/^#/); chop; $sql .= $_; } } # insert default values # default probe message my $message; if(open(F, 'contrib/message.txt')){ while(){ s/%%CGI_URL%%/$cgi_url/g; $message .= $_; } close F; my $sql = 'INSERT INTO defaults (message) VALUES ('; $sql .= $dbh->quote($message) . ')'; my $sth = $dbh->prepare($sql); $sth->execute || warn "couldnt insert data into defaults: $!\n"; }else{ warn "could not open default probe message (contrib/message.txt): $!\n"; } # default challenges if(open(F, 'contrib/challenges.txt')){ while(){ chop; my($question,$answer) = split /\s=>\s/; my $sql = 'INSERT INTO challenges (emailid,question,answer) VALUES (0,'; $sql .= $dbh->quote($question) . ',' . $dbh->quote($answer) . ')'; my $sth = $dbh->prepare($sql); $sth->execute; } }else{ warn "could not open default challenges (contrib/challenges.txt): $!\n"; } # default verified message -- could merge with message query, but... if(open(F, 'contrib/verified.txt')){ undef $/; my $verified = ; $/ = "\n"; my $sql = 'UPDATE defaults SET verified = ' . $dbh->quote($verified); my $sth = $dbh->prepare($sql); $sth->execute; }else{ warn "could not open default verified msg (contrib/challenges.txt): $!\n"; } # default reply blurb if(open(F, 'contrib/reply_blurb.txt')){ undef $/; my $reply_blurb = ; $/ = "\n"; my $sql = 'UPDATE defaults SET reply_blurb = ' . $dbh->quote($reply_blurb); my $sth = $dbh->prepare($sql); $sth->execute; }else{ warn "could not open defautl reply blurb (contrib/reply_blurb.txt): $!\n"; } $dbh->disconnect(); }else{ print "you must set up your database manually: see INSTALL and contrib/esec.mysql for hints.\n"; } print "Complete.\n";