#!/usr/local/bin/perl
# create-domain.pl
# Adds a new virtual host, based on command-line parameters
package virtual_server;
if (!$module_name) {
$main::no_acl_check++;
$ENV{'WEBMIN_CONFIG'} ||= "/etc/webmin";
$ENV{'WEBMIN_VAR'} ||= "/var/webmin";
if ($0 =~ /^(.*\/)[^\/]+$/) {
chdir($1);
}
chop($pwd = `pwd`);
$0 = "$pwd/create-domain.pl";
require './virtual-server-lib.pl';
$< == 0 || die "create-domain.pl must be run as root";
}
$first_print = \&first_text_print;
$second_print = \&second_text_print;
$indent_print = \&indent_text_print;
$outdent_print = \&outdent_text_print;
# Parse command-line args
$name = 1;
$virt = 0;
while(@ARGV > 0) {
local $a = shift(@ARGV);
if ($a eq "--domain") {
$domain = lc(shift(@ARGV));
}
elsif ($a eq "--desc") {
$owner = shift(@ARGV);
$owner =~ /:/ && &usage($text{'setup_eowner'});
}
elsif ($a eq "--email") {
$email = shift(@ARGV);
}
elsif ($a eq "--user") {
$user = lc(shift(@ARGV));
}
elsif ($a eq "--pass") {
$pass = shift(@ARGV);
}
elsif ($a eq "--quota") {
$quota = shift(@ARGV);
}
elsif ($a eq "--uquota") {
$uquota = shift(@ARGV);
}
elsif ($a =~ /^--(\S+)$/ &&
&indexof($1, @features) >= 0) {
$config{$1} || &usage("The $a option cannot be used unless the feature is enabled in the module configuration");
$feature{$1}++;
}
elsif ($a =~ /^--(\S+)$/ &&
&indexof($1, @feature_plugins) >= 0) {
$plugin{$1}++;
}
elsif ($a eq "--default-features") {
$deffeatures = 1;
}
elsif ($a eq "--ip") {
$ip = shift(@ARGV);
if (!$config{'all_namevirtual'}) {
$feature{'virt'} = 1; # for dependency checks
$virt = 1;
}
else {
$virtalready = 1;
}
$name = 0;
}
elsif ($a eq "--allocate-ip") {
$ip = "allocate"; # will be done later
$virt = 1;
$name = 0;
}
elsif ($a eq "--ip-already") {
$virtalready = 1;
}
elsif ($a eq "--ip-primary") {
$virtalready = 2;
$virt = 1;
$feature{'virt'} = 1; # for dependency checks
$name = 1; # the non-SSL vhost has to be name-based
}
elsif ($a eq "--shared-ip") {
$sharedip = shift(@ARGV);
$virt = 0;
$name = 1;
&indexof($sharedip, &list_shared_ips()) >= 0 ||
&usage("$sharedip is not in the shared IP addresses list");
}
elsif ($a eq "--mailboxlimit" || $a eq "--max-mailboxes") {
$mailboxlimit = shift(@ARGV);
}
elsif ($a eq "--dbslimit" || $a eq "--max-dbs") {
$dbslimit = shift(@ARGV);
}
elsif ($a eq "--domslimit" || $a eq "--max-doms") {
$domslimit = shift(@ARGV);
}
elsif ($a eq "--aliaslimit" || $a eq "--max-aliases") {
$aliaslimit = shift(@ARGV);
}
elsif ($a eq "--aliasdomslimit" || $a eq "--max-aliasdoms") {
$aliasdomslimit = shift(@ARGV);
}
elsif ($a eq "--realdomslimit" || $a eq "--max-realdoms") {
$realdomslimit = shift(@ARGV);
}
elsif ($a eq "--template") {
$templatename = shift(@ARGV);
foreach $t (&list_templates()) {
if ($t->{'name'} eq $templatename ||
$t->{'id'} eq $templatename) {
$template = $t->{'id'};
}
}
$template eq "" && &usage("Unknown template name");
}
elsif ($a eq "--bandwidth") {
$bw = shift(@ARGV);
}
elsif ($a eq "--limits-from-template") {
$tlimit = 1;
}
elsif ($a eq "--prefix") {
$prefix = shift(@ARGV);
}
elsif ($a eq "--db") {
$db = shift(@ARGV);
$db =~ /^[a-z0-9\-\_]+$/i || &usage("Invalid database name");
}
elsif ($a eq "--fwdto") {
$fwdto = shift(@ARGV);
$fwdto =~ /^\S+\@\S+$/i || &usage("Invalid forwarding address");
}
elsif ($a eq "--parent") {
$parentdomain = lc(shift(@ARGV));
}
elsif ($a eq "--alias") {
$aliasdomain = $parentdomain = lc(shift(@ARGV));
}
elsif ($a eq "--subdom" || $a eq "--superdom") {
$subdomain = $parentdomain = lc(shift(@ARGV));
}
elsif ($a eq "--reseller") {
$resel = shift(@ARGV);
}
elsif ($a eq "--style") {
$stylename = shift(@ARGV);
}
elsif ($a eq "--content") {
$content = shift(@ARGV);
}
elsif ($a eq "--no-email") {
$nocreationmail = 1;
}
elsif ($a eq "--no-slaves") {
$noslaves = 1;
}
elsif ($a eq "--no-secondaries") {
$nosecondaries = 1;
}
else {
&usage("Unknown option $a");
}
}
if ($template eq "") {
$template = &get_init_template($parentdomain);
}
$tmpl = &get_template($template);
if ($virtalready == 2) {
# IP is the system's primary interface
$ip eq "allocate" &&
&usage("The --ip-primary option overrides --allocate-ip");
$ip && &usage("The --ip-primary option overrides --ip");
$ip = &get_default_ip();
}
elsif ($ip eq "allocate") {
# Allocate IP now
$virtalready && &usage("The --ip-already and --allocate-ip options are incompatible");
%racl = $resel ? &get_reseller_acl($resel) : ();
if ($racl{'ranges'}) {
# Allocating from reseller's range
$ip = &free_ip_address(\%racl);
$ip || &usage("Failed to allocate IP address from reseller's ranges!");
}
else {
# Allocating from template
$tmpl->{'ranges'} ne "none" || &usage("The --allocate-ip option cannot be used unless automatic IP allocation is enabled - use --ip instead");
$ip = &free_ip_address($tmpl);
$ip || &usage("Failed to allocate IP address from ranges!");
}
}
elsif ($virt) {
# Make sure manual IP specification is allowed
$tmpl->{'ranges'} eq "none" || $config{'all_namevirtual'} || &usage("The --ip option cannot be used when automatic IP allocation is enabled - use --allocate-ip instead");
}
# Make sure all needed args are set
$domain && ($parentdomain || $pass) || &usage("Missing password");
if (&has_home_quotas() && !$parentdomain) {
$quota && $uquota || $tlimit || &usage("No quota specified");
}
if ($parentdomain) {
$feature{'unix'} && &usage("--unix option makes no sense for sub-servers");
}
if ($aliasdomain) {
foreach $f (keys %feature) {
&indexof($f, @opt_alias_features) >= 0 ||
&usage("--$f option makes no sense for alias servers");
}
}
if ($subdomain) {
foreach $f (keys %feature) {
&indexof($f, @opt_subdom_features) >= 0 ||
&usage("--$f option makes no sense for sub-domains");
}
}
# Validate args and work out defaults for those unset
$domain =~ /^[A-Za-z0-9\.\-]+$/ || &usage($text{'setup_edomain'});
$domain =~ /^\./ && &usage($text{'setup_edomain'});
$domain =~ /\.$/ && &usage($text{'setup_edomain'});
&lock_domain_name($domain);
foreach $d (&list_domains()) {
usage($text{'setup_edomain2'}) if (lc($d->{'dom'}) eq lc($domain));
}
if ($parentdomain) {
$parent = &get_domain_by("dom", $parentdomain);
$parent || &usage("Parent domain does not exist");
$alias = $parent if ($aliasdomain);
$subdom = $parent if ($subdomain);
!$subdomain || $domain =~ /\.\Q$subdomain\E$/ ||
&usage("Sub-domain $domain must be under the parent domain $subdomain");
}
# Allow user and group names
if (!$parent) {
if (!$user) {
($user, $try1, $try2) = &unixuser_name($domain);
$user || &usage(&text('setup_eauto', $try1, $try2));
}
else {
$user =~ /^[^\t :]+$/ || &usage($text{'setup_euser2'});
defined(getpwnam($user)) && &usage($text{'setup_euser'});
}
if (!$group) {
($group, $gtry1, $gtry2) = &unixgroup_name($domain, $user);
$group || &usage(&text('setup_eauto2', $try1, $try2));
}
else {
$group =~ /^[^\t :]+$/ || &usage($text{'setup_egroup2'});
defined(getgrnam($group)) &&
&usage(&text('setup_egroup', $group));
}
}
$owner ||= $domain;
# Work out features, if using automatic mode
if ($deffeatures) {
%feature = ( 'virt' => $feature{'virt'} );
%plugin = ( );
foreach my $f (&list_available_features($parent, $alias, $subdom)) {
if ($f->{'default'} && $f->{'enabled'}) {
if ($f->{'plugin'}) {
$plugin{$f->{'feature'}} = 1;
}
else {
$feature{$f->{'feature'}} = 1;
}
}
}
}
if (!$parent) {
# Make sure alias, database, etc limits are set properly
!defined($mailboxlimit) || $mailboxlimit =~ /^[1-9]\d*$/ ||
&usage($text{'setup_emailboxlimit'});
!defined($dbslimit) || $dbslimit =~ /^[1-9]\d*$/ ||
&usage($text{'setup_edbslimit'});
!defined($aliaslimit) || $aliaslimit =~ /^[1-9]\d*$/ ||
&usage($text{'setup_ealiaslimit'});
!defined($domslimit) || $domslimit eq "*" ||
$domslimit =~ /^[1-9]\d*$/ ||
&usage($text{'setup_edomslimit'});
!defined($aliasdomslimit) || $aliasdomslimit =~ /^[1-9]\d*$/ ||
&usage($text{'setup_ealiasdomslimit'});
!defined($realdomslimit) || $realdomslimit =~ /^[1-9]\d*$/ ||
&usage($text{'setup_erealdomslimit'});
}
if (!$parent) {
# Validate username
&require_useradmin();
$uerr = &useradmin::check_username_restrictions($user);
if ($uerr) {
&usage(&text('setup_eusername', $user, $uerr));
}
$user =~ /^[^\t :]+$/ || &usage($text{'setup_euser2'});
&indexof($user, @banned_usernames) < 0 ||
&usage(&text('setup_eroot', 'root'));
}
# Validate quotas
if (&has_home_quotas() && !$parent && !$tlimit) {
$quota =~ /^\d+$/ || &usage($text{'setup_equota'});
$uquota =~ /^\d+$/ || &usage($text{'setup_euquota'});
}
# Validate reseller
if (defined($resel)) {
$parent && &usage("Reseller cannot be set for sub-servers");
@resels = &list_resellers();
($rinfo) = grep { $_->{'name'} eq $resel } @resels;
$rinfo || &usage("Reseller $resel not found");
}
$defip = &get_default_ip($resel);
if (!$alias) {
if ($config{'all_namevirtual'}) {
# Make sure the IP *is* assigned
&check_ipaddress($ip) || &usage($text{'setup_eip'});
if (!&check_virt_clash($ip)) {
&usage(&text('setup_evirtclash2'));
}
}
elsif ($virt) {
&check_ipaddress($ip) || &usage($text{'setup_eip'});
$clash = &check_virt_clash($ip);
if ($virtalready) {
# Make sure IP is already active
$clash || &usage(&text('setup_evirtclash2'));
if ($virtalready == 1) {
# Don't allow clash with another domain
local $already = &get_domain_by("ip", $ip);
$already && &usage(&text('setup_evirtclash4',
$already->{'dom'}));
}
else {
# The system's PRIMARY ip is being used by
# this domain, so we can host a single SSL
# virtual host on it.
}
}
else {
# Make sure the IP isn't assigned yet
$clash && &usage(&text('setup_evirtclash'));
}
}
}
else {
$ip = $alias->{'ip'};
}
# Validate style
if ($stylename) {
($style) = grep { $_->{'name'} eq $stylename } &list_content_styles();
$style || &usage("Style $stylename does not exist");
$content || &usage("--content followed by some initial text for the website must be specified when using --style");
if ($content =~ /^\//) {
$content = &read_file_contents($content);
$content || &usage("--content file does not exist");
}
$content =~ s/\r//g;
$content =~ s/\\n/\n/g;
}
if ($parent) {
# User and group IDs come from parent
$gid = $parent->{'gid'};
$ugid = $parent->{'ugid'};
$user = $parent->{'user'};
$group = $parent->{'group'};
$uid = $parent->{'uid'};
}
else {
# Work out user and group IDs
&build_group_taken(\%gtaken, \%ggtaken);
$gid = &allocate_gid(\%gtaken);
$ugid = $gid;
&build_taken(\%taken, \%utaken);
$uid = &allocate_uid(\%taken);
}
# Work out prefix if needed, and check it
$prefix ||= &compute_prefix($domain);
$prefix =~ /^[a-z0-9\.\-]+$/i || &usage($text{'setup_eprefix'});
$pclash = &get_domain_by("prefix", $prefix);
$pclash && &usage($text{'setup_eprefix2'});
# Build up domain object
%dom = ( 'id', &domain_id(),
'dom', $domain,
'user', $user,
'group', $group,
'ugroup', $group,
'uid', $uid,
'gid', $gid,
'ugid', $gid,
'owner', $owner,
'email', $parent ? $parent->{'email'} : $email,
'name', $name,
'ip', $config{'all_namevirtual'} ? $ip :
$virt ? $ip :
$sharedip ? $sharedip : $defip,
'dns_ip', $virt || $config{'all_namevirtual'} ? undef :
$config{'dns_ip'},
'virt', $virt,
'virtalready', $virtalready,
$parent ? ( 'pass', $parent->{'pass'} )
: ( 'pass', $pass,
'quota', $quota,
'uquota', $uquota ),
'alias', $alias ? $alias->{'id'} : undef,
'subdom', $subdom ? $subdom->{'id'} : undef,
'source', 'create-domain.pl',
'template', $template,
'parent', $parent ? $parent->{'id'} : "",
$parent ? ( )
: ( 'mailboxlimit', $mailboxlimit,
'dbslimit', $dbslimit,
'aliaslimit', $aliaslimit,
'domslimit', $domslimit,
'aliasdomslimit', $aliasdomslimit,
'realdomslimit', $realdomslimit,
'bw_limit', $bw eq 'NONE' ? undef : $bw ),
'prefix', $prefix,
'reseller', $resel,
'nocreationmail', $nocreationmail,
'noslaves', $noslaves,
'nosecondaries', $nosecondaries,
);
if (!$parent) {
if ($tlimit) {
&set_limits_from_template(\%dom, $tmpl);
}
&set_capabilities_from_template(\%dom, $tmpl);
}
$dom{'db'} = $db || &database_name(\%dom);
$dom{'emailto'} = $parent ? $parent->{'emailto'} :
$dom{'email'} ? $dom{'email'} :
$dom{'mail'} ? $dom{'user'}.'@'.$dom{'dom'} :
$dom{'user'}.'@'.&get_system_hostname();
foreach $f (@features) {
$dom{$f} = $feature{$f} ? 1 : 0;
}
foreach $f (@feature_plugins) {
$dom{$f} = $plugin{$f} ? 1 : 0;
}
&set_featurelimits_from_template(\%dom, $tmpl);
&set_chained_features(\%dom, undef);
# Work out home directory
$dom{'home'} = &server_home_directory(\%dom, $parent);
&complete_domain(\%dom);
# Check for various clashes
$derr = &virtual_server_depends(\%dom);
&usage($derr) if ($derr);
$cerr = &virtual_server_clashes(\%dom);
&usage($cerr) if ($cerr);
print "Beginning server creation ..\n\n";
$err = &create_virtual_server(\%dom, $parent,
$parent ? $parent->{'user'} : undef);
if ($err) {
print "$err\n";
exit 1;
}
if ($fwdto) {
&$first_print(&text('setup_fwding', $in{'fwdto'}));
&create_domain_forward(\%dom, $fwdto);
&$second_print($text{'setup_done'});
}
if ($style && $dom{'web'}) {
&$first_print(&text('setup_styleing', $style->{'desc'}));
&apply_content_style(\%dom, $style, $content);
&$second_print($text{'setup_done'});
}
print "All done!\n";
sub usage
{
print $_[0],"\n\n" if ($_[0]);
print "Adds a new Virtualmin virtual server, with the settings and features\n";
print "specified on the command line.\n";
print "\n";
print "usage: create-domain.pl --domain domain.name\n";
print " --pass password-for-unix-user\n";
print " [--parent domain.name | --alias domain.name |\n";
print " --superdom domain.name]\n";
print " [--desc description-for-domain]\n";
print " [--email contact-email]\n";
print " [--user new-unix-user]\n";
foreach $f (@features) {
print " [--$f]\n" if ($config{$f});
}
foreach $f (@feature_plugins) {
print " [--$f]\n";
}
print " [--default-features]\n";
print " [--allocate-ip | --ip virtual.ip.address |\n";
print " --shared-ip existing.ip.address]\n";
print " [--ip-already]\n";
print " [--max-doms domains|*]\n";
print " [--max-aliasdoms domains]\n";
print " [--max-realdoms domains]\n";
print " [--max-mailboxes boxes]\n";
print " [--max-dbs databases]\n";
print " [--max-aliases aliases]\n";
if (&has_home_quotas()) {
print " [--quota quota-for-domain]\n";
print " [--uquota quota-for-unix-user]\n";
}
if ($config{'bw_active'}) {
print " [--bandwidth bytes]\n";
}
print " [--template \"name\"]\n";
print " [--limits-from-template]\n";
print " [--prefix username-prefix]\n";
print " [--db database-name]\n";
print " [--fwdto email-address]\n";
print " [--reseller name]\n";
if ($virtualmin_pro) {
print " [--style name]\n";
print " [--content text|filename]\n";
}
exit(1);
}
syntax highlighted by Code2HTML, v. 0.9.1