Show configure_apache.pl syntax highlighted
#!/usr/bin/perl -w
use strict;
our $apache_root;
our $apache_modules;
our $alphamail;
our $config_dir;
our $log_dir;
our $message_cache_dir;
our $session_dir;
our $max_message_size; # bytes
our $large_file_dir;
our $large_file_limit; # bytes
our $max_downloads;
our $post_limit; # bytes
our $scratch_space_dir;
our $user;
our $group;
our $ip;
our $port;
our $ssl_port;
our $domain;
our $host;
our $session_timeout;
our $preferences_dir;
our $webcache_port;
our $spam_address;
our $allowed_per_page;
our $default_app;
our $sandbox_dir;
our $sandbox_user;
our $sandbox_util;
our %progs = (
jpegtopnm => qx(which jpegtopnm 2> /dev/null),
tifftopnm => qx(which tifftopnm 2> /dev/null),
giftopnm => qx(which giftopnm 2> /dev/null),
pngtopnm => qx(which pngtopnm 2> /dev/null),
pnmscale => qx(which pnmscale 2> /dev/null),
pnmtojpeg => qx(which pnmtojpeg 2> /dev/null),
xlhtml => qx(which xlhtml 2> /dev/null),
antiword => qx(which antiword 2> /dev/null),
elinks => qx(which elinks 2> /dev/null),
tar => qx(which tar 2> /dev/null),
unzip => qx(which unzip 2> /dev/null),
openssl => qx(which openssl 2> /dev/null),
pnmscale => qx(which pnmscale 2> /dev/null)
);
sub check
{
my $pkg = shift;
my $version = shift;
my $t;
print STDERR "Checking for at least version $version of $pkg: \n";
eval {
my $v = `perl -M$pkg -e 'print \$${pkg}::VERSION' 2> /dev/null`;
$v =~ s/\s*//g;
die "\t$pkg IS NOT INSTALLED.\n" if($v =~ m/^\s*$/);
die "\tThe installed version of $pkg is $v. \tAlpha Mail requires at least version $version.\n" if($v < $version);
print STDERR "OK\n";
};
if($@) {
print STDERR "NO: $@";
return 0;
}
return 1;
}
# Check for required packages:
sub verify_packages
{
my $ok = 1;
print STDERR "Checking for required packages (use cpan(1) to update/install on errors).\n";
$ok &= check('Apache::SiteControl', 1.0);
$ok &= check('Apache::AuthCookie', 3.04);
$ok &= check('MIME::Parser', 5.4);
$ok &= check('Net::SMTP', 2.29);
$ok &= check('HTML::Entities', 1.29);
$ok &= check('Log::Log4perl', 0.47);
$ok &= check('Unicode::IMAPUtf7', 2.0);
$ok &= check('Time::Format', 1.0);
$ok &= check('Text::Wrap', 2001.0929);
$ok &= check('Crypt::CBC', 2.14);
$ok &= check('Crypt::CAST5', 0.04);
$ok &= check('Data::Dumper', 2.0);
$ok &= check('Carp', 1.0);
$ok &= check('Encode', 2.0);
$ok &= check('IO::File', 1.0);
$ok &= check('IO::Socket', 1.25);
$ok &= check('IO::Socket::INET', 1.24);
$ok &= check('Text::Aspell', 0.04);
$ok &= check('MIME::Words', 5.417);
$ok &= check('Time::HiRes', 1.59);
$ok &= check('Digest::MD5', 2.33);
$ok &= check('Email::Address', 1.80);
$ok &= check('Bundle::HTML::Mason', 0.09);
if(!$ok) {
print STDERR "Please install the missing packages and re-run.\n";
exit 1;
} else {
print STDERR "OK\n";
}
}
sub ask
{
my $question = shift;
my $default = shift;
my @responses = @_;
my $resp;
if(@responses) {
do {
$" = ", ";
print "$question (@responses): [$default] ";
$resp = <STDIN>;
chomp $resp;
$resp = $default if(length($resp) == 0);
} while(!grep(!/\Q$resp\E/, @responses));
$" = " ";
} else {
print "$question: [$default] ";
$resp = <STDIN>;
chomp $resp;
$resp = $default if(length($resp) == 0);
}
return $resp;
}
sub ask_for_dir
{
my $question = shift;
my $default = shift;
my $must_exist = shift;
my $resp;
my $yn;
do {
print "$question [$default]: ";
$resp = <STDIN>;
chomp $resp;
$resp = $default if(length($resp) == 0);
if(!$must_exist && (!-d $resp || !-w $resp)) {
print STDERR "Cannot write to $resp\n";
$yn = ask("Create the directory?", "y", "n");
chomp $yn;
mkdir $resp if($yn eq 'y');
}
} while(length($resp) == 0 || !-d $resp || !-w $resp);
return $resp;
}
sub do_subs
{
my %dirmap = (
'alphamail.conf' => "$config_dir/apache",
'apache.conf' => "$config_dir/apache",
'init.pl' => "$config_dir/apache",
'log4perl.conf' => "$config_dir",
);
my $fn;
my $line;
for my $file (keys %dirmap)
{
$file =~ s!^.*/!!g;
print STDERR "Configuring $file to $dirmap{$file}/$file\n";
open DATA, "<$alphamail/conf/$file";
open OUT, ">$dirmap{$file}/$file";
while($line = <DATA>)
{
$line =~ s/CONFIG_DIRECTORY/$config_dir/g;
$line =~ s/APACHECONF_DIRECTORY/$config_dir\/apache/g;
$line =~ s/ALPHAMAIL_DIRECTORY/$alphamail/g;
$line =~ s/SESSION_DIRECTORY/$session_dir/g;
$line =~ s/ALPHAMAIL_POSTLIMIT/$post_limit/g;
$line =~ s/ALPHAMAIL_SCRATCHSPACE/$scratch_space_dir/g;
$line =~ s/LOG_DIRECTORY/$log_dir/g;
$line =~ s/ALPHA_USER/$user/g;
$line =~ s/ALPHA_GROUP/$group/g;
$line =~ s/ALPHA_ADDRESS/$ip/g;
$line =~ s/ALPHA_PORT/$port/g;
$line =~ s/ALPHA_DOMAIN/$domain/g;
$line =~ s/ALPHA_SSL_PORT/$ssl_port/g;
$line =~ s/ALPHA_HOST/$host.$domain/g;
$line =~ s/APACHE_ROOT/$apache_root/g;
$line =~ s/APACHE_MODDIR/$apache_modules/g;
print OUT $line;
}
close OUT;
close DATA;
}
}
sub fix_permissions
{
`chown -R $user "$apache_root/mason" "$alphamail/htdocs" "$alphamail/mason" "$config_dir" "$session_dir" "$message_cache_dir" "$log_dir" "$preferences_dir" "$large_file_dir" "$scratch_space_dir"`;
`chmod 700 "$config_dir" "$session_dir" "$message_cache_dir" "$preferences_dir" "$large_file_dir" "$scratch_space_dir"`;
`chmod 755 "$log_dir"`;
}
sub gen_adminconfig
{
open DATA, ">$config_dir/alphamail_config";
print DATA <<EOF;
# imap servers: mx=imap_server, ...
# for example:
imap_servers: uoregon.edu=imap.uoregon.edu, gladstone.uoregon.edu=gladstone.uoregon.edu
# Variables used for the login screen:
organization_name: University of Oregon
base_url: https://$host.$domain:$ssl_port
# Port where the imap_webcache daemon lives
webcache_port: $webcache_port
# folder_prefix is the prefix for the location where user folders are stored on
# the IMAP server(s). TODO: Add one of these for each server, in case they
# don't match.
folder_prefix: mail/
# session_timeout is the number of seconds of idle time before we ask for the
# user's password again.
session_timeout: $session_timeout
# User preferences and addressbook location
prefsdir: $preferences_dir
# The location of temporary message files, created while parsing MIME (incoming
# and outgoing). This will also be where attachments are decoded and stored.
message_tmpdir: $message_cache_dir
# These files should be scheduled for cleanup as they get old (i.e. not been
# accessed for 5 minutes).
message_tmpdir_cachetime: 300
# Some mail messages come in plain text with extremely long line lengths. This
# parameter indicates what width to wrap them to.
textwrap_columns: 80
# Sandbox parameters. Where to find the executable (which must be setuid root),
# and where to put the files that the external viewers will work on.
sandbox_util: $sandbox_util
sandbox: $sandbox_dir
# ATTACHMENT VIEWERS.
# These utilities are needed by the attachment viewers. They (and all the files
# they use) must be hard linked into the sandbox directory.
# on-the-fly icon image generation
jpegtopnm: $progs{jpegtopnm}
pnmtojpeg: $progs{pnmtojpeg}
pnmscale: $progs{pnmscale}
tifftopnm: $progs{tifftopnm}
giftopnm: $progs{giftopnm}
pngtopnm: $progs{pngtopnm}
# Height of the attachment icons for images
iconsize: 50
# MUST support z option (use GNU tar)
tar: $progs{tar}
unzip: $progs{unzip}
# Word document converter
antiword: $progs{antiword}
# Excel spreadsheet converter
xlhtml: $progs{xlhtml}
# HTML to text conversion
elinks: $progs{elinks}
# COMPOSE OPTIONS
# If a to, cc, or bcc address is given without an @ sign, what domain should be
# assumed? The processing of messages happens as such: If the outgoing address
# has an @, then it is left alone. If it does not, then the address book alias
# are substituted. If that fails, @<default_domain> is appended.
# Set it to nothing, and no default domain will be appended.
default_domain: $domain
# User Preference defaults
default_trash: mail/Trash
default_sent: mail/sent-mail
default_drafts: none
default_signature_on_top: 0
default_icon_preview: 1
default_linkify: 0
default_messages_per_page: $default_app;
default_quicknav: 0
# Spam reporting
spam_address: $spam_address
# Allowed page sizes of message indexes
allowed_per_page: $allowed_per_page
# ATTACHMENT LIMITS
# Maximum message size with attachments (bytes)
max_message_size: $max_message_size
# FILE SHARING OPTIONS:
# File vault directory (large attachment alternative)
large_file_dir: $large_file_dir
# Maximum size of files in file vault (bytes)
large_file_limit: $large_file_limit
large_file_max_downloads: $max_downloads
# Openssl (used for encryption)
openssl: $progs{openssl}
EOF
close DATA;
}
sub mkdir_p
{
my $directory = shift;
my $perms = shift;
$perms = 0755 if(!defined($perms));
my @comp = split '/', $directory;
my $dir;
$dir = "/";
for my $c (@comp) {
$dir .= "/$c";
if(!-d $dir) {
mkdir "$dir", $perms or die "Could not create $dir";
}
}
}
sub create_sandbox
{
my %dep;
my ($a, $b, $uid, $gid, $c, $d, $e, $homedir) = getpwnam($sandbox_user);
die "No such user $sandbox_user" if(!defined($a));
die "Unable to write to sandbox $sandbox_dir" if(-w $sandbox_dir);
mkdir_p("$sandbox_dir/tmp", 0777);
`chown $user "$sandbox_dir/tmp"`;
`chmod 777 "$sandbox_dir/tmp"`;
$homedir = "$sandbox_dir$homedir";
mkdir_p($homedir);
chown $uid, $gid, $homedir or die "Cannot change ownership of $homedir to $sandbox_user";
# Collect all dependencies, and make links
for my $prog (keys %progs) {
my $loc = $progs{$prog};
chomp $loc;
$loc =~ m'^(.*)/[^/]*$';
my $dirname = $1;
mkdir_p("$sandbox_dir$dirname");
link $loc, "$sandbox_dir$dirname/$prog" or die "Unable to link $loc to $sandbox_dir$dirname/$prog";
# Do the same for dependencies
my @deps = qx(ldd $progs{$prog});
for my $d (@deps) {
if($d =~ m'\s(/\S*)\s') {
my $f = $1;
$f =~ m'^(.*/)[^/]*$';
my $base = $1;
print "Adding dependency $f for $prog\n";
$dep{$f} = 1;
while(-l $f) { # Find the _real_ file as well
$f = readlink $f;
$f = $base . $f if($f !~ m'^/');
$dep{$f} = 1;
print "Adding dependency $f for $prog\n";
}
}
}
}
for my $d (keys %dep) {
$d =~ m'^(.*)/([^/]*)$';
my $dirname = $1;
my $filename = $2;
mkdir_p("$sandbox_dir$dirname");
link $d, "$sandbox_dir$d" or die "Unable to link $d to $sandbox_dir$d";
}
if(!-d "/usr/share/antiword") {
print "\n\nERROR: Could not find antiword files in /usr/share/antiword. You will have to manually link them\n\n";
sleep 5;
} else {
print "linking anitword files";
mkdir_p("$sandbox_dir/usr/share/antiword");
for my $f (</usr/share/antiword/*>)
{
if(!-d $f) {
link "$f", "$sandbox_dir$f" or die "Could not link $f to $sandbox_dir$f";
}
}
}
print "Building sandbox utility\n";
my @lines = qx(cd $alphamail/util/sandbox; SANDBOX="$sandbox_dir" USER="$sandbox_user" make clean sandbox 2>&1);
print "@lines";
die "Build failed!" if(!-x "$alphamail/util/sandbox/sandbox");
print "Build complete.\n";
chown 0, 0, $sandbox_util or die "Could not set root permission on $sandbox_util";
chmod 04755, $sandbox_util or die "Could not set setuid on $sandbox_util";
}
my $d = `pwd`;
chomp $d;
while(1) {
$alphamail = ask_for_dir("Where are the Alpha Mail files?", $d, 1);
if(!-r "$alphamail/lib/AlphaMail/Middleware.pm") {
print STDERR "That does not appear to be the correct directory. Please give the directory name which contains lib, etc, htdocs, ...)\n";
next;
}
else {
last;
}
}
print <<SANDBOX_MSG;
AlphaMail uses a sandbox when running external viewers (like elinks and
pnmtojpeg). This is a security feature that helps eliminates security problems
with the external viewer program weaknesses.
IMPORTANT NOTE: The sandbox MUST be on the same filesystem as the other
directories that alphamail uses, since it uses hard links to avoid copying
files from one place to another.
SANDBOX_MSG
$sandbox_dir = ask_for_dir("Where should the sandbox be created?", "$alphamail/sandbox", 0);
$sandbox_user = ask("What user should the sandbox be owned by?", "nobody");
`rm -rf $sandbox_dir` if(length($sandbox_dir) > 5);
$sandbox_util = "$alphamail/util/sandbox/sandbox";
create_sandbox;
verify_packages;
$config_dir = ask_for_dir("Directory for apache configuration files: ", "$alphamail/etc", 0);
mkdir "$config_dir/apache";
$log_dir = ask_for_dir("Directory for log files: ", "$alphamail/log", 0);
$message_cache_dir = ask_for_dir("Directory for message cache: ", "$alphamail/messages", 0);
$scratch_space_dir = ask_for_dir("Where should upload files be stored during upload? This MUST be on the same filesystem as the message cache", "$alphamail/tmp", 0);
$preferences_dir = ask_for_dir("Directory for user preferences and address books: ", "$alphamail/prefs", 0);
$session_dir = ask_for_dir("Directory for session info: ", "$alphamail/sessions", 0);
mkdir "$session_dir/locks";
$large_file_dir = ask_for_dir("Directory for file vault \n\t(large file attachment alternative):", "$alphamail/filevault", 0);
my @groups;
my @users;
my $t;
my $line;
my ($du, $dg) = (0,0);
my $i;
open GRP, "</etc/group";
$i = 0;
while($line = <GRP>) {
$line =~ m/^([^:]*):/;
push @groups, $1;
$dg = $i if $1 =~ m/apache|www/;
$i++;
}
close GRP;
open PW, "</etc/passwd";
$i=0;
while($line = <PW>) {
$line =~ m/^([^:]*):/;
push @users, $1;
$du = $i if $1 =~ m/apache|www/;
$i++;
}
close PW;
$apache_root = ask_for_dir("What is your apache's server root directory? ", "/usr/local/apache", 1);
mkdir "$apache_root/mason";
$apache_modules = ask_for_dir("What is your apache's module directory? ", "$apache_root/libexec", 1);
$user = ask("What user should apache run as? ", $users[$du], @users);
$group = ask("What group should apache run as?", $groups[$dg], @groups);
$ip = ask("What IP should be bound? (* for all)", "*");
$port = ask("What port should be used for HTTP?", 80);
$ssl_port = ask("What port should be used for HTTPS?", 443);
$domain = `domainname`;
chomp $domain;
$domain = ask("What domain name should be used (do NOT include the host's name)?", $domain);
$host = `hostname`;
chomp $host;
$host =~ s/^[^.]*\..*$//;
$host = ask("What host name should be used (not FQDN!)?", $host);
for my $prog (sort keys %progs) {
chomp $progs{$prog};
if(! -x $progs{$prog}) {
print STDERR "Cannot find $prog.\n";
$progs{$prog} = ask("Location and name of $prog: ", "/usr/bin/$prog");
if(! -x $progs{$prog}) {
print STDERR "WARNING: $progs{$prog} does not exist or is not executable.\n";
}
} else {
print STDERR "Found $prog.\n";
}
}
$session_timeout = ask("How long (in seconds) can a user be idle before session timeout?", 300);
$webcache_port = ask("What localhost port hosts the imap_webcache?", 1234);
$spam_address = ask("What email address should spam reports be sent to?", "");
$allowed_per_page = ask("Enter a comma separated list of allowed page sizes for message indexes. Larger page sizes tend to incur more overhead:", "10, 20, 35, 50");
$allowed_per_page =~ m/^(\d+)\D/;
$default_app = $1;
$max_message_size = ask("How big can a message (with attachments) be (in bytes)?", 5000000);
$large_file_limit = ask("What is the file size limit for the file vault (in bytes)?", 50000000);
$max_downloads = ask("How many times should I allow a shared file to be downloaded?", 7);
$post_limit = ask("\n\nWhat do you want for a hard limit on HTTP POST?\nThis should be a number much larger than the largest upload you see as\na non-attack. If this limit is reached, there is no good way to give the\nuser a proper error message, so it should be at least somewhat larger\nthan your file size limits for the file vault.\nZero means no limit.\nSize (in bytes): ", 0);
do_subs;
fix_permissions;
gen_adminconfig;
print <<EOF;
STATUS OF CONFIGURATION
=======================
Configuration files written to: $config_dir
Configured Apache for: $host.$domain
HTTP Port: $port
SSL Port: $ssl_port
Binding to IP: $ip
Running as $user/$group
Sandbox root configured to be: $sandbox_dir
Sandbox utility will run as: $sandbox_user
Logs will be stored in: $log_dir
Cached messages will be in $message_cache_dir
Session information will be in: $session_dir.
User preferences will be in: $preferences_dir.
Permissions have been restricted, but be aware that mail messages and temporary
transfer files will be visible in $message_cache_dir and $scratch_space_dir.
You should be able to start the system with:
# apache -f $config_dir/apache/apache.conf
or
# httpd -f $config_dir/apache/apache.conf
EOF
print "The Alpha Mail URL will be: https://$host.$domain:$ssl_port/mail\n" if($ssl_port != 443);
print "The Alpha Mail URL will be: https://$host.$domain/mail\n" if($ssl_port == 443);
print "\n\nNOTE: If you are using the generated apache config, then you will need to install your SSL files as $config_dir/apache/ssl/server.key and $config_dir/apache/ssl/server.cert\n";
See more files for this project here