#!/usr/bin/perl -w # vsd-install - freeVSD installation configuration # # # VSD - Virtual Server Daemon # Copyright (c) 2000 - 2001 Idaya Ltd. # # VSD is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either # version 2 of the license, or (at your option) any later version. # # VSD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with VSD - see the COPYING file; if not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # # See the AUTHORS file for a list of contributors to VSD # See the ChangeLog files for a list of changes # use strict; use VSD; use VSD::Change; use VSD::Config; use Fcntl; use Getopt::Long; use DirHandle; use Data::Dumper; # Some constants my $DEBUG = 0; my $VERSION_NUMBER = "1.4.10"; my $APPNAM = ($0 =~ m/\/([0-9A-Za-z_.-]+)$/g)[-1]; # Establish paths. my $vsdsbindir = $path{vsdsbindir}; my $vsdconfdir = $path{vsdconfdir}; my $vsdconffile = $path{vsdconf}; # Set up configuration information: my $change = VSD::Change->new(file => $vsdconffile); my $vsdconf = VSD::Config->new (change => $change); # Set up and obtain comand line arguments my $bind = 0; my $crontab = 0; my $diskquota = 0; my $disable_service = 1; my $iptables = 0; my $logging = 0; my @mountpoint_args = (); my @mountpoint = (); my $mountpoint = ''; my @nameserver_args = (); my @nameserver = (); my $plain = 0; my $quiet = 0; my $ssl = 0; my $ssh = 1; my $upgrade = 0; my $help = 0; my $version = 0; my $return_value = &GetOptions ( "bind" => \$bind, "crontab" => \$crontab, "diskquota" => \$diskquota, "iptables" => \$iptables, "logging:i" => \$logging, "mountpoint=s" => \@mountpoint_args, "nameserver=s" => \@nameserver_args, "plain" => \$plain, "quiet" => \$quiet, "ssl" => \$ssl, "upgrade" => \$upgrade, "help" => \$help, "version" => \$version ); Getopt::Long::Configure ("bundling"); if (@ARGV != 0 || $return_value == 0) { usage (); exit; } foreach (@mountpoint_args) { push (@mountpoint, split (',', $_)); $mountpoint = $mountpoint[0]; } # Set default mountpoint. $mountpoint || ($mountpoint = "/home/vsd/"); foreach (@nameserver_args) { push (@nameserver, split (',', $_)); } # Check that only one mount point was supplied: if (@mountpoint > 1) { print ("$APPNAM: error: only one mountpoint can be specified.\n"); usage (); exit; } # Check that we got no more than three nameservers: if (@nameserver > 2) { print ("$APPNAM: error: only a maximum of two name servers can be specified\n"); usage (); exit; } if ($DEBUG) { print " help => $help\n version => $version\n quiet => $quiet \ ssl => $ssl \n diskquota => $diskquota \n logging => $logging\n plain => $plain\n \ mountpoint => @mountpoint\n nameserver => @nameserver\n"; } # check for help, print help and exit: if ($help) { usage (); information (); exit 0; } # check for version, print and exit: if ($version) { version (); exit 0; } # Check that we are only run once: if (!$upgrade) { system '/bin/grep -q "vsd 1725/tcp" /etc/services' or error ( 'installed' ); } # Are we installing or upgrading? if ($upgrade) { # set up upgrade log open (LOGFILE, ">>$vsdconfdir/upgrade.log") or die "$APPNAM: error: unable to open log file $vsdconfdir/upgrade.log"; my $date = `date`; print LOGFILE "============================================================\n"; print LOGFILE "freeVSD $VERSION_NUMBER upgrade log.\n$date\n"; print LOGFILE "============================================================\n"; # Do the upgrade upgrade ($vsdconf, $change, $vsdconffile); upgrade_bind ($vsdconf, $change); } else { # Set up logging to etc/vsd/install.log open (LOGFILE, ">>$vsdconfdir/install.log") or die "$APPNAM: error: unable to open log file $vsdconfdir/install.log"; # Print a nice friendly header: my $date = `date`; print LOGFILE "============================================================\n"; print LOGFILE "freeVSD $VERSION_NUMBER install log.\n$date\n"; print LOGFILE "============================================================\n"; # Regardless we want to set the following: configure_vsdconf ($vsdconf, $change, $mountpoint, \@nameserver); configure_loopback ($vsdconf, $change, $mountpoint); configure_services ($change); disable_http ($change); # Are we using inetd? if (-e "/etc/inetd.conf") { configure_inetdconf ($vsdconf, $change, $vsdsbindir, $logging, $ssl, $plain); } # How about xinetd.conf? if (-e "/etc/xinetd.conf") { configure_xinetdconf ($vsdconf, $change, $vsdsbindir, $logging, $ssl, $plain); } } # Do iptables anyway if ($iptables && -e "/sbin/iptables") { enable_iptables ($change); } if ($logging) { enable_vsdlogging ($change); } if ($diskquota) { enable_diskquota ($change, $mountpoint); } if ($disable_service) { disable_services ($change); } if ($crontab) { configure_cron ($change, $vsdsbindir); } if ($ssh) { configure_ssh ($change); } if ($bind) { configure_bind ($change); } # Configure vsd.conf sub configure_vsdconf { my $vsdconf = shift; my $change = shift; my $mountpoint = shift; my $nameserver = shift; log_output ("Configuring $vsdconffile with following values:\n"); # Set up mount point $vsdconf->setval ( 'Partition', '0', 'Mount', $mountpoint ); log_output (" mount point: $mountpoint\n"); # Set up name servers my ($pnsip, $snsip) = nss ("/etc/resolv.conf"); if (@$nameserver) { $pnsip = $nameserver[0] if $nameserver[0]; $snsip = $nameserver[1] if $nameserver[1]; } $pnsip && $vsdconf->setval ( 'Global', 'PrimaryNS', $pnsip ) || $vsdconf->delval ( 'Global', 'PrimaryNS' ); $snsip && $vsdconf->setval ( 'Global', 'SecondaryNS', $snsip ) || $vsdconf->delval ( 'Global', 'SecondaryNS' ); log_output (" name servers: $pnsip $snsip\n"); # Register detected skels and set the last found to be the global if ( -d "$mountpoint/skel" and opendir SKEL, "$mountpoint/skel" ) { my @skels = readdir SKEL; closedir SKEL; @skels > 2 && do { foreach my $skel ( @skels ) { if ($skel !~ /^\.{1,2}$/ && -d "$mountpoint/skel/$skel") { $vsdconf->setval ( 'Partition', '0', 'Skel', $skel ); log_output (" registered skel: $skel\n"); $vsdconf->setval ( 'Global', 'Skel', $skel ); } } } } log_output ("\n"); } # Configure loopback sub configure_loopback { my $vsdconf = shift; my $change = shift; my $mountpoint = shift; log_output ("Configuring loopback entry with following values:\n"); # Obtain our name my $localhost = `hostname`; chomp $localhost; $localhost =~ s/^\s*(\S+)\s*$/$1/; log_output (" hostname: $localhost\n"); # Obtain our IP my $ip = `hostname -i $localhost`; chomp $ip; $ip =~ s/^\s*(\S+)\s*$/$1/; log_output (" ip addr: $ip\n"); # Set the virtual server details in vsd.conf $vsdconf->setval ( 'VirtualServer', $localhost, 'IP', $ip ); $vsdconf->setval ( 'VirtualServer', $localhost, 'Status', 'active' ); $vsdconf->setval ( 'VirtualServer', $localhost, 'Partition', '0' ); $vsdconf->setval ( 'VirtualServer', $localhost, 'CertificateAuthorityServer', $localhost); # Create any missing directories: -d "$mountpoint" or mkdir $mountpoint, 0755 or die "Can't create dir $mountpoint"; -d "$mountpoint/vs" or mkdir "$mountpoint/vs", 0755 or die "Can't create dir $mountpoint/vs"; # Create loopback and register change with undo: $change->command ( "ln -s / $mountpoint/vs/$localhost", "rm -f $mountpoint/vs/$localhost", "unlink / from $mountpoint/vs/$localhost " ); log_output ("\n"); } # Configure inetd.conf? sub configure_inetdconf { my $vsdconf = shift; my $change = shift; my $vsdsbindir = shift; my $logging = shift; my $ssl = shift; my $plain = shift; my $inetd_conf = "/etc/inetd.conf"; my $disable_string = "#"; my $logging_string = " -p local6"; log_output ("Configuring /etc/inetd.conf for use with freeVSD:\n"); log_output ("\n disabled the following services (if registered): \n"); log_output (" ftp, telnet, pop-3, smtp, vsd, svsd, talk, ntalk, finger\n"); log_output (" linuxconf.\n"); $change->file ($inetd_conf); $change->comment ('ftp', 'telnet', 'pop-3', 'smtp', 'vsd', 'svsd', 'talk', 'ntalk', 'finger', 'linuxconf'); log_output ("\n appended and virtualised the following services:\n"); system ("/bin/grep", "-q", "sbin/proftpd", "/etc/inetd.conf") && $change->append ( "ftp stream tcp nowait root $vsdsbindir/virtuald tcpd /usr/sbin/proftpd -d -l" ) && log_output (" ftp: /usr/sbin/proftpd -d -l\n"); system ("/bin/grep", "-q", "sbin/in.telnetd", "/etc/inetd.conf") && $change->append ( "telnet stream tcp nowait root $vsdsbindir/virtuald tcpd /usr/sbin/in.telnetd" ) && log_output (" telnet: /usr/sbin/in.telnetd\n"); system ("/bin/grep", "-q", "sbin/in.qpopper", "/etc/inetd.conf") && $change->append ( "#pop-3 stream tcp nowait root $vsdsbindir/virtuald tcpd /usr/sbin/in.qpopper" ) && log_output (" pop-3: /usr/sbin/in.qpopper (disabled)\n"); system ("/bin/grep", "-q", "usr/sbin/vm-pop3d", "/etc/inetd.conf") && $change->append ( "pop-3 stream tcp nowait root $vsdsbindir/virtuald tcpd /usr/sbin/vm-pop3d -i --group admin --user mail --debug=5" ) && log_output (" pop-3: /usr/sbin/vm-pop3d\n"); system ("/bin/grep", "-q", "usr/sbin/sendmail", "/etc/inetd.conf") && $change->append ( "smtp stream tcp nowait root $vsdsbindir/virtuald tcpd /usr/sbin/sendmail -bs" ) && log_output (" sendmail: /usr/sbin/sendmail -bs\n"); log_output ("\n added freeVSD configuration to inetd:\n"); # put together the inetd.conf string: my $vsd_inetd = "vsd stream tcp nowait root $vsdsbindir/virtuald tcpd $vsdsbindir/vsd"; my $vsd_output = "$vsdsbindir/vsd"; my $svsd_inetd = "svsd stream tcp nowait root $vsdsbindir/virtuald tcpd $vsdsbindir/svsd"; my $svsd_output = "$vsdsbindir/svsd"; if ($logging != -1 ) { $vsd_inetd .= "$logging_string -l $logging"; $vsd_output .= "$logging_string -l $logging"; $svsd_inetd .= "$logging_string -l $logging"; $svsd_output .= "$logging_string -l $logging"; }; if ($plain && !$ssl) { $svsd_inetd = $disable_string . $svsd_inetd; $svsd_output .= " (disabled)"; } if (!$plain) { $vsd_inetd = $disable_string . $vsd_inetd; $vsd_output .= " (disabled)"; } system ("/bin/grep", "-q", "$vsdsbindir/vsd", "$inetd_conf") && $change->append ("$vsd_inetd" ) && log_output (" vsd: $vsd_output\n"); system ("/bin/grep", "-q", "$vsdsbindir/svsd", "$inetd_conf") && $change->append ("$svsd_inetd" ) && log_output (" svsd: $svsd_output\n"); log_output ("\nRestarting inetd so that changes take effect:\n"); $change->command ( '/usr/bin/killall -HUP inetd', '/usr/bin/killall -HUP inetd', 're-read inetd config changes' ); log_output ("\n"); } # Configure xinetd.conf? sub configure_xinetdconf { my $vsdconf = shift; my $change = shift; my $vsdsbindir = shift; my $logging = shift; my $ssl = shift; my $plain = shift; my $xinetd_conf = "/etc/xinetd.conf"; my $disable_string = "yes"; my $logging_string = " -p local6"; my $vsd_xinetd_disable = "no"; my $svsd_xinetd_disable = "no"; my $vsd_xinetd = " server_args = $vsdsbindir/vsd"; my $svsd_xinetd = " server_args = $vsdsbindir/svsd"; my $vsd_output = "$vsdsbindir/vsd"; my $svsd_output = "$vsdsbindir/svsd"; if ($logging != -1) { $vsd_xinetd .= "$logging_string -l $logging"; $vsd_output .= "$logging_string -l $logging"; $svsd_xinetd .= "$logging_string -l $logging"; $svsd_output .= "$logging_string -l $logging"; }; if (!$plain) { $vsd_xinetd_disable = $disable_string; $vsd_output .= " (disbaled)"; } if ($plain && !$ssl) { $svsd_xinetd_disable = $disable_string; $svsd_output .= " (disabled)"; } log_output ("Configuring $xinetd_conf for use with freeVSD:\n"); $change->file( $xinetd_conf ); $change->xinetd_virtualise (); my %utils = ( defaults => [ " only_from = 127.0.0.1\\32" ], ftp => [ " socket_type = stream", " protocol = tcp", " wait = no", " user = root", " server = $vsdsbindir/virtuald", " server_args = /usr/sbin/proftpd -d -l" ], telnet => [ " socket_type = stream", " protocol = tcp", " wait = no", " user = root", " server = $vsdsbindir/virtuald", " server_args = /usr/sbin/in.telnetd" ], 'qpop-3' => [ " socket_type = stream", " protocol = tcp", " wait = no", " user = root", " server = $vsdsbindir/virtuald", " server_args = /usr/sbin/in.qpopper", " disable = yes" ], 'pop-3' => [ " socket_type = stream", " protocol = tcp", " wait = no", " user = root", " server = $vsdsbindir/virtuald", " server_args = /usr/sbin/vm-pop3d -i --group admin --user mail --debug=5" ], smtp => [ " socket_type = stream", " protocol = tcp", " wait = no", " user = root", " server = $vsdsbindir/virtuald", " server_args = /usr/sbin/sendmail -bs" ], vsd => [ " socket_type = stream", " protocol = tcp", " wait = no", " user = root", " server = $vsdsbindir/virtuald", "$vsd_xinetd", " disable = $vsd_xinetd_disable" ], svsd => [ " socket_type = stream", " protocol = tcp", " wait = no", " user = root", " server = $vsdsbindir/virtuald", "$svsd_xinetd", " disable = $svsd_xinetd_disable" ] ); $change->xinetd_append ( \%utils ); log_output ("\n appended and virtualised the following services:\n"); log_output (" ftp: /usr/sbin/proftpd -d -l\n"); log_output (" telnet: /usr/sbin/in.telnetd\n"); log_output (" pop-3: /usr/sbin/in.qpopper (disabled)\n"); log_output (" pop-3: /usr/sbin/vm-pop3d\n"); log_output (" sendmail: /usr/sbin/sendmail -bs\n"); log_output ("\n added freeVSD configuration to xinetd:\n"); log_output (" vsd: $vsd_output\n"); log_output (" svsd: $svsd_output\n"); log_output ("\nRestarting xinetd so that changes take effect:\n"); $change->command ( '/etc/rc.d/init.d/xinetd restart', '/etc/rc.d/init.d/xinetd restart', 're-read xinetd config changes' ); log_output ("\n"); } # Configure services? sub configure_services { my $change = shift; my $file = "/etc/services"; if (-f "$file") { log_output ("Registering freeVSD as a service:\n"); log_output ("\n appended the following to $file:\n"); $change->file ($file); system ("/bin/grep", "-q", "vsd ", "$file") && $change->append ('vsd 1725/tcp # Virtual Server Daemon (VSD)') && log_output (" vsd 1725/tcp # Virtual Server Daemon (VSD)\n"); system ("/bin/grep", "-q", "svsd ", "$file") && $change->append ( 'svsd 1726/tcp # Secure Virtual Server Daemon (VSD over SSL)') && log_output (" svsd 1726/tcp # Secure Virtual Server Daemon (VSD over SSL)\n"); log_output ("\n"); } } # Configure bind? sub configure_bind { my $change = shift; my $file = "/etc/named.conf"; if (-f "$file") { log_output ("Configuring BIND support:\n"); log_output ("\n appended the following to $file:\n"); $change->file ($file); system ("/bin/grep", "-q", "named.conf", "$file") && $change->append ('include "/var/named/named.conf";') && log_output ("include \"/var/named/named.conf\";\n"); log_output ("\n"); } } # Configure crontab? sub configure_cron { my $change = shift; my $vsdsbindir = shift; my $cron_file = "/var/spool/cron/root"; # Touch the file of it does not exist, so that the perl module doesn't die: if (! -e $cron_file) { system ("touch", "$cron_file"); } if (system ("grep", "-q", "vsd-vsbatch.pl", "$cron_file")) { log_output ("Configuring cron to run vsd-vsbatch every 15 minutes:\n"); $change->file ($cron_file); $change->append ("# Entry to run vsd-vsbatch every quoter hour"); $change->append ("0,15,30,45 * * * * $vsdsbindir/vsd-vsbatch.pl"); log_output ("\n appended the followinig line to $cron_file\n"); log_output (" 0,15,30,45 * * * * $vsdsbindir/vsd-vsbatch.pl\n"); log_output ("\n"); } else { log_output ("Cron is already configured to run vsd-vsbatch.pl.\n\n"); } } # Configure ssh ? sub configure_ssh { my $change = shift; my $ssh_conf = "/etc/ssh/sshd_config"; my $localhost = `hostname`; chomp $localhost; $localhost =~ s/^\s*(\S+)\s*$/$1/; # my $host_ip; = `hostname -i $localhost`; # chomp $host_ip; # $host_ip =~ s/^\s*(\S+)\s*$/$1/; my $host_ip; my @ifconfig = `/sbin/ifconfig eth0`; if (-f "$ssh_conf") { foreach (@ifconfig) { if ($host_ip = ($_ =~ m/\s*inet addr:([0-9.]+)\s+.*/g)[0]) { log_output ("Configuring sshd to listen on the hosts ip only.\n\n"); $change->file ($ssh_conf); $change->command ( "perl -i.vsd -pe \'s/.*ListenAddress 0\.0\.0\.0/ListenAddress $host_ip/\' $ssh_conf", "perl -i.vsd -pe \'s/ListenAddress $host_ip/ListenAddress 0\.0\.0\.0/\' $ssh_conf", "allow sshd to listen on all addresses"); last; } } } } # Turn all services off sub disable_services { my $change = shift; my $chkconfig = `chkconfig --list`; my @services_to_disable = ("apmd", "netfs", "nfs", "nfslock", "identd", "portmap"); foreach my $service (@services_to_disable) { if ($chkconfig =~ /$service .*:on.*/) { log_output ("Disabling $service on the local machine:\n"); log_output ("\n disabled $service at startup.\n"); $change->command ("/sbin/chkconfig --level 0123456 $service off", "/sbin/chkconfig --level 35 $service on", "enable $service at startup?"); log_output (" killed all $service processes.\n\n"); $change->command ("/sbin/service $service stop", "/sbin/service $service start", "start $service"); } } log_output ("\n"); } # Disable http sub disable_http { my $change = shift; log_output ("Disabling HTTP on the local machine: \n"); log_output ("\n disabled http at start up.\n"); $change->command ('/sbin/chkconfig httpd off', '/sbin/chkconfig httpd on', 'enable httpd at startup'); log_output ("\n killed all http processes.\n"); $change->command('/usr/bin/killall -q httpd', '/etc/rc.d/init.d/httpd start', 'start httpd'); log_output ("\n"); } # Enable iptables sub enable_iptables { my $change = shift; log_output ("Configuring kernel to use iptables instead of ipchains:\n\n"); log_output (" disabled ipchains at startup.\n"); $change->command ('chkconfig --level 2345 ipchains off', 'chkconfig --level 2345 ipchains on', 'enable ipchains at startup' ); log_output (" stopping ipchains.\n"); $change->command ('/etc/rc.d/init.d/ipchains stop', '/etc/rc.d/init.d/ipchains start', 'start ipchains' ); log_output (" removing ipchains from the kernel.\n"); log_output (" loading iptables into the kernel.\n"); $change->command ('rmmod ipchains', 'rmmod iptable_mangle iptable_filter iptable_nat ip_conntrack ip_tables; insmod ipchains', 'load ipchains into the kernel' ); # Set up all of the necessary changes so that we can put it all back together log_output (" enabled iptables at startup\n"); $change->command ('chkconfig --level 2345 iptables on', 'chkconfig --level 2345 iptables off', 'disable iptables at startup' ); log_output (" starting iptables\n"); $change->command ('/etc/rc.d/init.d/iptables start', '/etc/rc.d/init.d/iptables stop', 'stop iptables' ); log_output ("\n"); } # Set up syslog to log all information to /var/log/syslog.conf sub enable_vsdlogging { my $change = shift; my $syslogconf = "/etc/syslog.conf"; my $logrotateconf = "/etc/logrotate.d/syslog"; my $logfile = "/var/log/vsd.log"; log_output ("Configuring syslog so that all local6 output is logged to $logfile\n"); system ("grep", "-q", "$logfile", "$syslogconf") && do { $change->file ($syslogconf); $change->append ("# Save [s]vsd output to /var/log/vsd.log (local6)"); $change->append ("local6.*;*.info $logfile") && $change->command ("touch $logfile", "rm -f $logfile", 'remove vsd.log'); log_output (" added local6.*;*.info to $syslogconf.\n"); $change->command ('/etc/rc.d/init.d/syslog restart', '/etc/rc.d/init.d/syslog restart', 'restart syslog'); log_output (" restarted syslog so that changes take effect.\n"); }; system ("grep", "-q", "$logfile", "$logrotateconf") && do { $change->file ($logrotateconf); $change->append ("\n$logfile {"); $change->append (" postrotate"); $change->append (" killall -HUP syslogd"); $change->append (" endscript"); $change->append ("}\n"); log_output (" added $logfile to $logrotateconf.\n"); }; log_output ("\n"); } sub enable_diskquota { my $change = shift; my $mountpoint= shift; my $init_file = "/etc/rc.d/rc.sysinit"; my $fstab_file = "/etc/fstab"; my $kernelvers; # remove trailing / and /vsd $mountpoint =~ s/\/$//; $mountpoint =~ s/\/vsd$//; log_output ("Configuring user and group disk quotas:\n"); my @lines = `cat $fstab_file`; my ($old, $path); while (1) { foreach (@lines) { if ($path = ( $_ =~ m/^[0-9A-Za-z_.\/=]+\s+([0-9A-Za-z_.\/]+)\s+.*/g)[0]) { if ($path eq $mountpoint && $_ !~ m/usrquota,grpquota/) { $_ =~ s/defaults/defaults,usrquota,grpquota/; last; } } } $old = $mountpoint; $mountpoint =~ s/[0-9A-Za-z_.]+\/$//; last if ($mountpoint eq $old); } log_output (" enabling user and group quotas in $fstab_file\n"); open (DST, "> $fstab_file") or die "$APPNAM: $fstab_file: $!"; foreach (@lines) { print (DST $_); } close (DST); log_output (" enabling user and group quotas at startup in $init_file\n"); $change->file ($init_file); $change->command ( 'perl -i.vsd -pe \'s/quotaon -a$/quotaon -avug/\' /etc/rc.d/rc.sysinit', 'perl -i.vsd -pe \'s/quotaon -avug$/quotaon -a/\' /etc/rc.d/rc.sysinit', 'disable user and group quotas at startup'); log_output (" establishing quota files (this may take some time...)\n"); # if quotacheck fails it could be because no quota files exist # therefore get kernel version ( 2.4 and above require aquota files) if( system ("/sbin/quotacheck", "-avug")){ open ( KERNEL, "kernelversion |") or die "coud not retrieve kernal version"; $kernelvers = ; close (KERNEL); # check for quota files. if they do not exist , create them unless ( -e "$mountpoint/quota.user"){ log_output(" creating quota.user\n"); system ("touch", "$mountpoint/quota.user"); system ("chmod", "600", "$mountpoint/quota.user"); } unless ( -e "$mountpoint/quota.group"){ log_output(" creating quota.group\n"); system ("touch", "$mountpoint/quota.group"); system ("chmod", "600", "$mountpoint/quota.group"); } # if kernel is version 2.4 or above then convert quota to aquota # if aquota files do not exist if ( $kernelvers >= 2.4) { system ("convertquota", "-u", "$mountpoint") unless ( -e "$mountpoint/aquota.user"); system ("convertquota", "-g", "$mountpoint") unless ( -e "$mountpoint/aquota.group"); } } log_output (" enabling quotas\n"); system ("/sbin/quotaon", "-avug"); } # Useful subroutines: sub nss { open RESOLV, "< $_[0]" or die "error opening $_[0]: $!"; my $match = 0; my @nss; while (defined ($_=) && @nss<2) { /^nameserver\s*(\d+).(\d+).(\d+).(\d+)*/i && (push @nss, "$1.$2.$3.$4"); } close RESOLV or die "error closing $_[0]: $!"; return @nss; } sub error { my $error = shift; my %error; $error{installed} =< $APPNAM -u or run vsd-uninstall.pl before running vsd-install again ORP print "\nError:\n$error{$error}\n"; die; } sub usage { print "Usage: $APPNAM [OPTION]... \n"; print "freeVSD installation configuration.\n\n"; print " -b, --bind configure BIND\n"; print " -c, --crontab configure crontab to run vsd-vsbatch every 15mins\n"; print " -d, --diskquotas configure disk quotas\n"; print " -i, --iptables configure iptables\n"; print " -l, --logging[=0-4] configure logging [set logging level (default 0)]\n"; print " -m, --mountpoint=DIR configure mountpoint\n"; print " -n, --nameserver=NS1,NS2 configure nameservers\n"; print " -p, --plain enable plain-text protocol\n"; print " -q, --quiet suppress screen output\n"; print " -s, --ssl enable ssl encrypted protocol (default)\n"; print " -u, --upgrade upgrade existing vsd configuration\n"; print " --help output this help and exit\n"; print " --version output version information and exit\n\n"; } sub information { print "When using to upgrade an installation (-u), only the '-l' and '-i' options will\n"; print "have any relevance, as all of the other configuration details will be extracted\n"; print "from the existing configuration file.\n\n"; } sub version { print "$APPNAM (freeVSD) $VERSION_NUMBER\n\n"; print "VSD - Virtual Server Daemon\n"; print "Copyright (c) 2000 - 2001 Idaya Ltd.\n\n"; print "VSD is free software; you can redistribute it and/or\n"; print "modify it under the terms of the GNU General Public License\n"; print "as published by the Free Software Foundation; either \n"; print "version 2 of the license, or (at your option) any later version.\n\n"; } sub upgrade { # We are being run because an installation already exists. # Therefore, we must find out what needs to be upgraded: my $TO_SOURCE = 0; my $TO_RPM = 0; my $FROM_SOURCE = 0; my $FROM_RPM = 0; my $PRE_148 = 1; # VSD configuration file variables my $vsdconf = shift; my $change = shift; my $vsdconffile = shift; my $old_vsdconffile; my $old_vsdconffiledir; # Useful variables relating to the localmachine. my $localhost = `hostname`; chomp $localhost; $localhost =~ s/^\s*(\S+)\s*$/$1/; my $ip = `hostname -i $localhost`; chomp $ip; $ip =~ s/^\s*(\S+)\s*$/$1/; # Are we a source install or an RPM install? # (Perl module will tell us because of path imported from VSD.pm) if ($vsdconffile =~ m%/usr/local/etc.*%){ log_output ("Upgrading to source, "); $TO_SOURCE = 1; } else { log_output ("Upgrading to RPM, "); $TO_RPM = 1; } # Are we upgrading from an RPM or a source install? # if we are source, and there is no /usr/sbin/vsd, then upgrading from source. if (($TO_SOURCE == 1 && ! -e "/usr/sbin/vsd") || ($TO_RPM == 1 && -e "/usr/local/sbin/vsd")) { $FROM_SOURCE = 1; $old_vsdconffiledir = "/usr/local/etc/"; log_output ("from source.\n\n"); } else { $FROM_RPM = 1; $old_vsdconffiledir = "/etc/"; log_output ("from RPM.\n\n"); } # if RPM -> source, need to modify /etc/services # if source -> RPM, need to modify /etc/services my $move_config = 0; if ($FROM_RPM == 1 && $TO_SOURCE == 1){ # change the path to vsd in /etc/services to /usr/local/sbin/vsd log_output ("RPM to source services change.\n"); $move_config = 1; modify_inet ("/usr/sbin/vsd", "/usr/local/sbin/vsd"); modify_inet ("/usr/sbin/virtuald", "/usr/local/sbin/virtuald"); } elsif ($FROM_SOURCE == 1 && $TO_RPM == 1){ # change the path to vsd in /etc/services to /usr/sbin/vsd log_output ("Source to RPM services change.\n"); $move_config = 1; modify_inet ("/usr/local/sbin/vsd", "/usr/sbin/vsd"); modify_inet ("/usr/local/sbin/virtuald", "/usr/sbin/virtuald"); } # Look for an old /etc/vsd.conf or /etc/vsd.conf.rpmsave, and transfer. if (-e "$old_vsdconffiledir/vsd.conf"){ `mv $old_vsdconffiledir/vsd.conf $vsdconffile`; log_output ("Copied $old_vsdconffiledir/vsd.conf to $vsdconffile\n"); } elsif (-e "$old_vsdconffiledir/vsd.conf.rpmsave"){ `mv $old_vsdconffiledir/vsd.conf.rpmsave $vsdconffile`; log_output ("Copied $old_vsdconffiledir/vsd.conf.rpmsave $vsdconffile\n"); } elsif (! -e $vsdconffile) { log_output ("No previous vsd.conf file found, unable to upgrade installation.\n"); log_output ("Please remove the vsd entry from /etc/services and re-install.\n"); exit; } else { if ($move_config && -e "$old_vsdconffiledir/vsd/vsd.conf") { `mv $old_vsdconffiledir/vsd/vsd.conf $vsdconffile`; } undef $old_vsdconffile; log_output ("Upgrading from a 1.4.8+ install.\n\n"); $PRE_148 = 0; } # Read configuration, and set up change log # Check for loopback virtual server # If not, create entry, create symlink if (! defined ($vsdconf->getval ('VirtualServer', "$localhost"))){ my $mountpoint = $vsdconf->getval ('Partition', '0', 'Mount'); configure_loopback ($vsdconf, $change, $mountpoint); } my %all_partitions = $vsdconf->getval ('Partition'); my @partitions = (keys %all_partitions); my @skel_names; my $new_skel_name = "skel"; my %listed_virtual_servers = $vsdconf->getval ('VirtualServer'); my @virtual_servers = keys (%listed_virtual_servers); # Foreach partition foreach my $partition (@partitions) { my @skel_to_register; my $created_dir = 0; my $mountpoint = $vsdconf->getval ('Partition', $partition, 'Mount'); my $skel_dir = new DirHandle "$mountpoint/skel"; while (defined (my $dir = $skel_dir->read)) { next if $dir =~ /^\.\.?$/; if ($dir =~ /bin/ || $dir =~ /dev/ || $dir =~ /etc/ || $dir =~ /home/ || $dir =~ /lib/ || $dir =~ /proc/ || $dir =~ /sbin/ || $dir =~ /tmp/ || $dir =~ /usr/ || $dir =~ /var/){ # An old skel has been found, create a directory for it if ( !$created_dir && -d "$mountpoint/skel/$new_skel_name"){ push (@skel_to_register, $new_skel_name); $new_skel_name .= "_postupgrade"; } if (! -d "$mountpoint/skel/$new_skel_name") { mkdir ("$mountpoint/skel/$new_skel_name", 0755); push (@skel_to_register, $new_skel_name); $created_dir = 1; } system ("mv", "$mountpoint/skel/$dir", "$mountpoint/skel/$new_skel_name"); } else { push (@skel_to_register, $dir); } } foreach my $skel (@skel_to_register) { $vsdconf->setval ('Partition', $partition, 'Skel', $skel); } foreach my $vs (@virtual_servers) { # Best register the new skel with all virtual servers on that partition. log_output ("Configuring virtual server: $vs\n"); if ((my $vs_partition = ($vsdconf->getval ('VirtualServer', $vs, 'Partition')) == $partition) && (! defined ($vsdconf->getval ('VirtualServer', $vs, 'Skel')))) { $vsdconf->setval ('VirtualServer', $vs, 'Skel', $new_skel_name); log_output (" skel: $new_skel_name\n"); } # Now set up a hosting server entry if (! defined ($vsdconf->getval ('VirtualServer', $vs, 'HostingServer'))) { $vsdconf->setval ('VirtualServer', $vs, 'HostingServer', $localhost); log_output (" hosting server: $localhost\n"); } # And a Certificate auth entry if (! defined ($vsdconf->getval ('VirtualServer', $vs, 'CertificateAuthorityServer'))) { $vsdconf->setval ('VirtualServer', $vs, 'CertificateAuthorityServer', $localhost); log_output (" certificate authority server: $localhost\n"); } log_output ("\n"); } } #print Dumper ($vsdconf); # Make sure the most important change is rolled back if ($PRE_148) { if ( -e "/etc/inetd.conf.pre-freevsd") { $change->command ('touch /etc/inetd.conf.pre-freevsd', 'mv /etc/inetd.conf.pre-freevsd /etc/inetd.conf', 'undo changes to /etc/inetd.conf'); } if ( -e "/etc/services.pre-freevsd") { $change->command ('touch /etc/services.pre-freevsd', 'mv /etc/services.pre-freevsd /etc/services', 'undo changes to /etc/services'); } else { $change->command('touch /etc/services', 'cat /etc/services | sed -e \'s/^.vsd .*//\' > /etc/services.tmp; \ mv /etc/services.tmp /etc/services', 'undo changes to /etc/services'); } } } # Upgrade mod_bind configuration? sub upgrade_bind { my $vsdconf = shift; my $change = shift; # Useful variables: my $root_bindconf_dir = "/var/named"; my $bindconf_dir = "/var/named/virtual"; # foreach partition: my %all_partitions = $vsdconf->getval ('Partition'); my @partitions = (keys %all_partitions); foreach my $partition (@partitions) { # foreach virtual server, do we have any bind configuration? my $mountpoint = $vsdconf->getval ('Partition', $partition, 'Mount'); my %listed_virtual_servers = $vsdconf->getval ('VirtualServer'); my @virtual_servers = keys (%listed_virtual_servers); # Modify the bindconf_dir so that it points to the new files: foreach my $vs (@virtual_servers) { log_output ("Checking Virtual Server $vs for Bind configuration files:\n"); my $vs_partition = $vsdconf->getval ('VirtualServer', $vs, 'Partition'); next if ($vs_partition != $partition); next if (! -e "$mountpoint/vs/$vs/named.conf"); log_output (" moving bind configuration information from $mountpoint/vs/$vs to $bindconf_dir/$vs\n"); mkdir ("$bindconf_dir/$vs", 0755) if ! -d "$bindconf_dir/$vs"; open (ROOT_NAMED_CONF, "$mountpoint/vs/$vs/named.conf"); open (NEW_ROOT_NAMED_CONF, ">>$bindconf_dir/$vs/named.conf"); while () { # Replace mountpoint with bind dir and print to new file s/$mountpoint\/vs/$bindconf_dir/; print NEW_ROOT_NAMED_CONF $_; chomp; s/include "(.*)named.conf.*/$1/; my $dir_to_create = $_; # Strip off unwanted information from the include statements: s/$bindconf_dir/$mountpoint\/vs/; my $dir_to_parse = $_; # Create new directory for files mkdir ("$dir_to_create", 0755) if ! -d "$dir_to_create"; open (NAMED_CONF, "$dir_to_parse/named.conf"); open (NEW_NAMED_CONF, ">>$dir_to_create/named.conf"); while () { if (m/file ".*";/) { s/$mountpoint\/vs/$bindconf_dir/; print NEW_NAMED_CONF $_; chomp; s/.*$bindconf_dir(.*)".*/$1/; my $file_to_copy = $_; system ("cp", "$mountpoint/vs/$file_to_copy", "$bindconf_dir/$file_to_copy"); } else { print NEW_NAMED_CONF $_; } } # Clean up: close (NAMED_CONF); close (NEW_NAMED_CONF); system ("rm", "-rf", "$dir_to_parse"); } # Clean up: close (ROOT_NAMED_CONF); close (NEW_ROOT_NAMED_CONF); system ("rm", "-f", "$mountpoint/vs/$vs/named.conf"); log_output (" removing old bind configuration files.\n"); # Add entry to $bindconf_dir/named.conf for virtual server open (NEW_ROOT_NAMED_CONF, ">>$root_bindconf_dir/named.conf.new"); open (ROOT_NAMED_CONF, "$root_bindconf_dir/named.conf"); log_output (" updating $root_bindconf_dir/named.conf\n\n"); while () { s%$mountpoint\/vs\/$vs%$bindconf_dir\/$vs%; print NEW_ROOT_NAMED_CONF $_; } close (ROOT_NAMED_CONF); close (NEW_ROOT_NAMED_CONF); system ("mv", "$root_bindconf_dir/named.conf.new", "$root_bindconf_dir/named.conf"); } log_output ("\n"); } } sub modify_inet { my $from = $_[0]; my $to = $_[1]; # Need to modify /etc/[x]inetd.conf if (-e "/etc/xinetd.conf") { `mv /etc/xinetd.conf /etc/xinetd.conf.tmp`; open (CONF, "/etc/xinetd.conf.tmp"); open (NEW_CONF, ">/etc/xinetd.conf"); } else { `mv /etc/inetd.conf /etc/inetd.conf.tmp`; open (CONF, "/etc/inetd.conf.tmp"); open (NEW_CONF, "/etc/inetd.conf"); } while () { s%$from%$to%g; print NEW_CONF $_; } close (NEW_CONF); close (CONF); # remove temp files and kick the process: if (-e "/etc/xinetd.conf.tmp") { `rm -f /etc/xinetd.conf.tmp`; `/etc/rc.d/init.d/xinetd restart`; } else { `rm -f /etc/inetd.conf.tmp`; `/etc/rc.d/init.d/inetd restart`; } } sub log_output () { my $string = shift; print LOGFILE "$string"; $quiet || print "$string"; }