#!/usr/bin/eperl -w
#
# Copyright (c) Ensim Corporation 2000, 2001   All Rights Reserved.
#
# This software is furnished under a license and may be used and copied
# only  in  accordance  with  the  terms  of such  license and with the
# inclusion of the above copyright notice. This software or any other
# copies thereof may not be provided or otherwise made available to any
# other person. No title to and ownership of the software is hereby
# transferred.
#
# The information in this software is subject to change without notice
# and  should  not be  construed  as  a commitment by Ensim Corporation.
# Ensim assumes no responsibility for the use or  reliability  of its
# software on equipment which is not supplied by Ensim.
#
# Exit codes (on failure error message goes to stderr):
#  0 - success
#  1 - failure
#
# This program performs a virtual domain operation. Based on the
# actual operation it does a chroot and execs the command or passes
# the virtual domain as an environment variable. Its arguments are the domain
# name, the command (with full path) and its arguments.
#
# VirtSiteOperation vx.com /usr/path/to/list_aliases
#

use English;

use lib ($ENV{OCW_SVCPATH} or "/usr/lib/opcenter") . "/virtualhosting";
use lib ($ENV{OCW_SVCPATH} or "/usr/lib/opcenter") . "/cmdline_common";

use ERRORS;
use Carper;

use strict;

push @INC, ($ENV{'OCW_SVCPATH'} || "/usr/lib/opcenter")."/virtualhosting";
push @INC, ($ENV{'OCW_SVCPATH'} || "/usr/lib/opcenter")."/cmdline_common";
if ($0 =~ /^(.+)\/([^\/]+)$/) {
  push @INC, $1; #the directory where the script resides
}

require CmdLineCoder;
require VHConfig;
require VHConst;

#unescape the command line arguments
&CmdLineCoder::decode_args();

#these scripts are called only if their respective options (falgs)
#from the virtualhosting conf file are on
%::restrictedscripts = ("/usr/lib/opcenter/ftp/EnableAnonFtp" => "AnonFtp",
			"/usr/lib/opcenter/ftp/DisableAnonFtp" => "AnonFtp",
		       );

#these scripts will be called in the chrooted environment
@::nonchrootscripts = ("/usr/lib/opcenter/proftpd/EnableAnonFtp",
		       "/usr/lib/opcenter/proftpd/DisableAnonFtp",
		       "/usr/lib/opcenter/proftpd/ChangeFtpOption",
		       "/usr/lib/opcenter/apache/get_config",
		       "/usr/lib/opcenter/apache/set_userpasswd",
		       "/usr/lib/opcenter/apache/remove_userpasswd",
		       "/usr/lib/opcenter/apache/get_protection",
		       "/usr/lib/opcenter/apache/protect_directory",
		       "/usr/lib/opcenter/apache/set_config",
                       "/usr/lib/opcenter/mivamerchant/get_webname",
		       "/usr/lib/opcenter/virtualhosting/ChangeDomainPasswd",
		       "/usr/lib/opcenter/analog/GetUsage",
		      );

my($error_message) = &VirtSiteOperation;

if ($error_message) {
  print STDERR $error_message;
  exit 1;
}
exit 0;

#
# Main function for performing an operation on virtual domains.
#
sub VirtSiteOperation {
    my ($Domain,$User,$Program);

    # Process the command line arguments
    if ($#ARGV < 1) {
    $cerr += $E_ARGS ;
	return "The number of arguments is too small.\n";
    }
    $Domain = shift @ARGV;
    if ($ARGV[0] eq "-u") {
	shift @ARGV;
	$User = shift @ARGV;
    } else {
	$User = undef;
    }
    if ($#ARGV < 0) {
    $cerr += $E_ARGS ;
	return "The number of arguments is too small.\n";
    }
    $Program = shift @ARGV;

    my ($error_message);

    # Check the domain name.
    if ($Domain !~ /^[a-zA-Z0-9-\.]+\.[a-zA-Z]+$/ and $Domain ne "localhost") {
    $cerr += $E_INVALIDDOMAINNAME and $cerr += { domain => $Domain } ;
	return "Invalid domain name $Domain .\n";
    }
    # Check the user name.
    if (defined ($User) and $User !~ /^[a-zA-Z0-9_-]+$/ ) {
    $cerr += $E_INVALIDUSER and $cerr += { user => $User } ;
	return "Invalid user name $User \n";
    }

    my ($chroot);
    if ($Domain eq "localhost") {
	$chroot = "";
    } else {
	# Get the domain info from the conf file
	my $record;
	if ($error_message = &VHConfig::GetSingleDomainConf($Domain, \$record)) {
	     return $error_message;
	}

	# Check if the command is restricted by a virtual hosting flag
	if ($::restrictedscripts{$Program}) {
	    unless ($record->{$::restrictedscripts{$Program}}) {
        $cerr += $E_NOTALLOWED ;
		return "You are not allowed to perform this operation.\n";
	    }
	}
	unless ($ENV{'OCW_SVCPATH'}) {$ENV{'OCW_SVCPATH'} = "/usr/lib/opcenter"}
	unless (grep {$Program eq $_} @::nonchrootscripts) {
	    $chroot = "$VHConst::VIRTUALFS/$record->{SITEINFO}->{User}";
	    $VHConst::VIRTUALFS .= ""; #Just need this to avoid a perl warning
	} else {
	    setEnvVar($record);
	}
    }

    if($chroot) {
	chdir $chroot; # This is to work around a Linux bug
	chroot ($chroot) or 
    $cerr += $E_RUNASROOTCHROOTDIR and $cerr += { dir => $chroot } and 
    return "Run this script as root. Chroot to $chroot failed.\n";
    }

    if(defined $User) {
	my(@pwent)=getpwnam($User);
	unless(@pwent) {
        $cerr += $E_NOUSER and $cerr += { user => $User } and
        return "User $User does not exist.\n" ;}
	($GID,$EGID)=($pwent[3],$pwent[3]);
	($UID,$EUID)=($pwent[2],$pwent[2]);
    }

    # mansoor (XXX) perl closes all fds (except STDIN,OUT,ERR) across execs
    # so that any pipes will be closed
    local $^F =100;
    open (CARPFD,">&=$ENV{ERRFD}") or die "cannot duplicate carp pipe" if $ENV{ERRFD};
    $ENV{ERRFD} = fileno(CARPFD) if $ENV{ERRFD};

    exec ($Program, (map {&CmdLineCoder::encode_string($_)} @ARGV)) or
    $cerr += $E_CANNOTEXEC and 
    $cerr += { what => $Program , perror => $! } and 
    return "Could not exec $Program : $! \n";
}

# Sets the environment variables from the hash
sub setEnvVar($) {

    my $record = shift;
    if (! ref($record)) {
	return;
    }
    foreach my $service (keys %$record) {
	if (! ref($record->{$service}) ) {
	    next;
	}
	foreach my $field (keys %{$record->{$service}}) {
	    my $env_var = $service."_".$field;
	    $ENV{$env_var} = $record->{$service}->{$field};
	}	
    }

}
