# -*- perl -*- use strict; use Wizard::SaveAble (); use Wizard::Examples::Apache::Config (); use Symbol (); use Socket (); package Wizard::Examples::Apache::Admin; sub Parse { my($self, $template, $server, $host, $prefs) = @_; $template =~ s/\~\~([\w\-]+)\~\~/ my $sf; foreach my $s (@_) { if (exists($s->{$1})) { $sf = $s; last; } } die "Unknown pattern: $1" unless $sf; $sf->{$1}/eg; $template } sub new { my($proto, $host, $server) = @_; my $cfg = $Wizard::Examples::Apache::Config::config; my $file = $cfg->{'apache-prefs-file'}; my $prefs = Wizard::SaveAble->new($file); my $basedir = $prefs->{'apache-prefs-basedir'} or die "Missing basedir"; my $h = Wizard::SaveAble->new(File::Spec->catfile($basedir, "$host.cfg")); my $hostdir = File::Spec->catdir($basedir, $host); my $s = Wizard::SaveAble->new(File::Spec->catfile($hostdir, "$server.cfg")); my $serverdir = File::Spec->catdir($basedir, $server); bless({'prefs' => $prefs, 'basedir' => $basedir, 'host' => $h, 'hostdir' => $hostdir, 'server' => $s, 'serverdir' => $serverdir}, (ref($proto) || $proto)); } sub MakeHttpdConf { my $self = shift; # Start by loading the original httpd.conf and replace patterns my $serverdir = ; my $conffile = File::Spec->catfile($self->{'serverdir'}, 'httpd.conf'); unless (-f $conffile) { $conffile = File::Spec->catfile($self->{'hostdir'}, 'httpd.conf'); } my $fh = Symbol::gensym(); my $conf; local $/ = undef; (open($fh, "<$conffile") && defined($conf = <$fh>) && close($fh)) or die "Failed to load HTTPD config file $conffile: $!"; my $host = $self->{'host'}; my $server = $self->{'server'}; my %ports; $ports{$server->{'apache-server-http-port'}} = 1 if $server->{'apache-server-http-port'}; $ports{$server->{'apache-server-https-port'}} = 1 if $server->{'apache-server-https-port'}; # Next thing: Load the virtual servers my $serverdir = $self->{'serverdir'}; return $conf unless -d $serverdir; my $dh = Symbol::gensym(); opendir($dh, $serverdir) or die "Failed to open directory $serverdir: $!"; my %interfaces; while (my $f = <$dh>) { next unless $f =~ /(.*).cfg$/; my $vserver_name; my $file = File::Spec->catfile($serverdir, $f); my $fh = Symbol::gensym(); my $vserver = Wizard::SaveAble->new($file); my $name = $vserver->{'apache-virtualserver-name'}; my $ip = Socket::inet_aton($name); unless (defined($ip)) { $self->Warn("Failed to resolve host name $name; ignoring host $f"); next; } $ip = Socket::inet_ntoa($ip); $ports{$vserver->{'apache-virtualserver-http-port'}} = 1 if $vserver->{'apache-virtualserver-http-port'}; $ports{$vserver->{'apache-virtualserver-https-port'}} = 1 if $vserver->{'apache-virtualserver-https-port'}; if (my $i = $vserver->{'interface'}) { if ($interfaces{$i}) { my $name = $vserver->{'apache-virtualserver-name'}; $self->Warn("Duplicate interface $i in $name; ignoring"); } else { $interfaces{$i} = $ip; } } if ($vserver->{'configuration'}) { $conf .= $vserver->{'configuration'}; } else { my $mode = $vserver{'apache-virtualserver-http-mode'}; if ($mode eq 'http' || $mode eq 'both') { $conf .= Wizard::Examples::Apache::Admin::Config::HTTP->Cnf ($prefs, $host, $server, $vserver); } if ($mode eq 'https' || $mode eq 'both') { $conf .= Wizard::Examples::Apache::Admin::Config::HTTPS->Cnf ($prefs, $host, $server, $vserver); } if ($mode eq 'redirect') { $conf .= Wizard::Examples::Apache::Admin::Config::Redirect->Cnf ($prefs, $host, $server, $vserver); } } } # Make sure, the defaults are valid $conf .= <<"EOF"; EOF # Finally parse the config file. (Parse($conf, $server, $host, $prefs), \%interfaces); } sub IfUp { my($self, $i, $ip) = @_; my $arch = $self->{'apache-host-arch'}; my $interface = $self->{'apache-host-interface'}; if ($arch =~ /linux/) { my $ifconfig = "$self->{'apache-host-ifconfig'} $interface"; return $self->Warn("Failed to parse netmask of interface $interface:\n" "$ifconfig\nIgnoring interface $interface:$i.\n") unless ($ifconfig =~ /mask:\s*(\d+\.\d+\.\d+\.\d+)/i); my $netmask = $1; return $self->Warn("Failed to parse interface $interface:\n$ifconfig" . "\nIgnoring interface $interface:$i.\n") unless ($ifconfig =~ /inet\s+addr:\s*(\d+\.\d+\.\d+\.\d+)/i); my $ifip = $1; my $net1 = Net::Netmask->new($ip, $netmask); my $net2 = Net::Netmask->new($ip, $netmask); return $self->Warn("The detected configuration of interface" . " $interface doesn't match the IP address" . " $ip.\nIgnoring interface $interface:$i.\n") unless ($net1->base() == $net2->base()); my $command = "$self->{'apache-host-ifconfig'} $interface:$i" . " $ip up\n"; print "Switching interface $i up: $command\n" if $::verbose; system $command unless $::debug; } } package Wizard::Examples::Apache::Admin::Config::HTTP; sub new { my($prefs, $host, $server, $vserver) = @_; my $self = { %$vserver }; $self->{'apache-virtualserver-pagedir'} = File::Spec->catdir($server->{'apache-server-root'}, $vserver->{'apache-virtualserver-name'}, 'pages'); $self->{'apache-virtualserver-cgidir'} = File::Spec->catdir($server->{'apache-server-root'}, $vserver->{'apache-virtualserver-name'}, 'cgi-bin'); $self->{'apache-virtualserver-logdir'} = File::Spec->catdir($server->{'apache-server-root'}, $vserver->{'apache-virtualserver-name'}, 'logs'); if (my $port = $self->{'apache-virtualserver-http-port'}) { if ($port ne $self->{'apache-server-http-port'}) { $self->{'apache-server-port'} = ":$port"; } } $self->{'apache-server-port'} ||= ''; my @index = $server->{'apache-server-index'} ? split(/ /, $server->{'apache-server-index'}) : ('welcome.html', 'index.html', 'welcome.htm', 'index.htm', '/cgi-bin/noDirLists'); my %options; if ($server->{'apache-server-options'}) { foreach my $key (split(/ /, $server->{'apache-server-options'})) { $options{'apache-server-options'} = 1; } } else { $options{'Indexes'} = 1; } my @aliases = ' ScriptAlias ~~apache-virtualserver-cgidir~~'; if ($vserver->{'apache-virtualserver-enable-ssi'}) { unshift(@index, 'welcome.shtml', 'index.shtml'); unshift(@aliases, ' ScriptAlias AddType text/html .shtml', ' AddHandler server-parsed .shtml'); $options{'ExecCGI'} = 1; } if ($vserver->{'apache-virtualserver-enable-pcgi'}) { unshift(@index, 'welcome.phtml', 'index.phtml'); unshift(@aliases, ' AddHandler x-pcgi-script .phtml'); $options{'ExecCGI'} = 1; } if ($vserver->{'apache-virtualserver-enable-ep'}) { unshift(@index, 'welcome.ep', 'index.ep'); unshift(@aliases, ' AddType x-ep-script .ep', ' ScriptAlias /cgi-bin/ep.cgi'); $options{'ExecCGI'} = 1; } $conf->{'apache-virtualserver-options'} = "Options " . $conf->{'apache-virtualserver-options'} || join(" ", keys %options); $conf->{'apache-virtualserver-index'} = "DirectoryIndex " . $conf->{'apache-virtualserver-index'} || join(" ", @index); $conf->{'apache-virtualserver-aliases'} = join("\n", @aliases); bless($conf, (ref($proto) || $proto)); } sub Template { <<'EOF'; ServerName ~~apache-virtualserver-name~~ ServerAdmin ~~apache-virtualserver-admin~~ DocumentRoot ~~apache-virtualserver-pagedir~~ CustomLog ~~apache-virtualserver-logdir~~ combined ~~apache-virtualserver-index~~ ~~apache-virtualserver-aliases~~ ~~apache-virtualserver-options~~ EOF } sub Cnf { my($proto, $prefs, $host, $server, $vserver) = @_; my $conf = $proto->new($prefs, $host, $server, $vserver); my $template = $conf->Template(); Wizard::Examples::Apache::Admin::Parse($template, $conf, $template, $server, $host, $prefs); } package Wizard::Examples::Apache::Admin::Config::HTTPS; @Wizard::Examples::Apache::Admin::Config::HTTPS::ISA = qw(Wizard::Examples::Apache::Admin::Config::HTTP); sub Template { my $self = shift; my $template = $self->SUPER::Template(); my $ssl = <<'EOF'; SSLEngine on SSLCertificateFile ~~apache-virtualserver-crtfile~~ SSLCertificeteKeyFile ~~apache-virtualserver-keyfile~~ EOF } sub new { my $proto = shift; my $conf = $proto->SUPER::new(@_); my $port = $conf->{'apache-virtualserver-https-port'} || $server->{'apache-server-https-port'}; $conf->{'apache-server-port'} = ":$port"; } package Wizard::Examples::Apache::Admin::Config::Redirect; @Wizard::Examples::Apache::Admin::Config::Redirect::ISA = qw(Wizard::Examples::Apache::Admin::Config::HTTP); sub Template { <<'EOF'; ServerName ~~apache-virtualserver-name~~ ServerAdmin ~~apache-virtualserver-admin~~ Redirect 301 ~~apache-virtualserver-redirect~~ EOF } 1;