#!/usr/bin/perl -U #============================================================================# # vHost - one-step solution for all virtual hosting needs # # vhost.pl - core module, host/dns virtualization module # # # # Copyright(c) Chaogic Systems, LLC. http://chaogic.com # # Author: Jake Fan # # # # This is Free Software; permission to use, copy, modify, and distribute # # this software and its documentation for any purpose - with or without fee # # - is hereby granted, provided that the above copyright information and # # this permission notice appear in all copies and documentations. This # # software is provided "as is" without express or implied warranty. For # # more details, see GNU General Public License as published by the Free # # Software Foundation. # # # #============================================================================# # $SUPPORT = <<'#'; # Linux, NetBSD, FreeBSD, OpenBSD # $REQUIRE = <<'#'; # /etc/fstab, /etc/shells, /bin/sh, false, echo, cd, pwd, cat, date, dirname, # basename, touch, uname -sn, ls -Al, id -G, du -sck, ln -sf, cp -RLp, rm -r, # mv, mkdir -p, chown -Rh, chmod -R, pw, useradd -cdgsuomk, usermod -cdgsuo, # groupadd -go, groupmod -go, userdel -r, groupdel, chpass -ps, passwd, stty, # ssh, rsync -eaq --delete --exclude --exclude-from, gzip -f, gunzip -cf, # test, make, gcc, g++ # $HISTORY = <<'#'; # Ver Date Credits Comments # ---- ------- --------------- ----------------------------------------------- # 0.90 09Nov00 Jake Fan + auto ip aliasing and auto selection between # ip and name based hosting # 1.00 27Nov00 Jake Fan + virtual email account/alias management # 1.10 10Dec00 Jake Fan + virtual host alias management # 1.20 24Jan01 Jake Fan + secure setuid wrapper for unprivileged # administration and web integration # 1.21 24Jan01 Jake Fan + command history logging # 1.30 06Feb01 Jake Fan + modularized configuration files # + support for arbitrary virtual services via # virtualization modules # + --version # 1.31 09Feb01 Jake Fan + distro-specific improvements # 1.32 19Feb01 Jake Fan + support for "user@domain.com" as pop3 login # 1.33 25Feb01 Jake Fan + proftpd virtualization module # 1.40 18Mar01 Jake Fan + changed location for virtual host log files # + --adddns # + --deldns # 1.41 26Mar01 Jake Fan + improved --reload and --listhost output # 1.42 05Apr01 Jake Fan + --listhost caching for fast output # 1.43 08Apr01 Jake Fan + --uninstall # 1.44 20Apr01 Jake Fan + --cmdlog # + --history # 1.45 21Apr01 Jake Fan + virtual root user # 2.00 14May01 Jake Fan + web gui # + optimizations for web integration # 2.01 07Jun01 Jake Fan + support for dns sub-domains # + catch-all email alias # 3.00 30Oct02 Jake Fan + completely redesigned and rewritten # + fully modularized architecture # + unlimited system profiles (configurations) # + distributed system (clustering) # + cross-platform support (linux/*bsd) # + four levels of login (root/vroot/owner/vuser) # + comprehensive quota system # + built-in log rotation # + virtual user home/web space # + improved ip address management # + improved web gui # + --support # + --require # + postfix virtualization module # + squirrelmail virtualization module # 3.01 25Dec02 Jake Fan * see change log for details # 3.02 31Dec02 Jake Fan * see change log for details # 3.03 03Jan03 Jake Fan * see change log for details # 3.04 08Jan03 Jake Fan * see change log for details # 3.05 31May03 Jake Fan * see change log for details # 3.10 29Feb04 Jake Fan * see change log for details # 3.11 04May04 Jake Fan * see change log for details # 3.20 16Dec04 Jake Fan * see change log for details # 3.21 01Apr05 Jake Fan * see change log for details # 3.30 30Apr06 Jake Fan * see change log for details # 3.31 11Sep06 Jake Fan * see change log for details # $VERSION = "vHost 3.31r1 Copyright(c) 2000-2006 Chaogic Systems, LLC. by Jake Fan\n"; $HELP = <<'#'; Add/Del vRoot: vhost --addvroot profile_dir [vroot_name] [-c] [-f] vhost --delvroot profile_dir [vroot_name] [-f] Add/Del DNS: vhost --adddns host_name [ip_address] [-z] [-i] [-q] [-f] vhost --deldns host_name [ip_address] [-q] [-f] Add/Del Host: vhost --addhost host_name owner_name [ip_address] [-q] [-f] vhost --delhost host_name [-q] [-f [-d]] Host Alias: vhost --addhali host_name host_alias [-q] vhost --delhali host_alias [-q] Add/Del User: vhost --adduser host_name user_name [full_name] [-f] vhost --deluser host_name user_name [-f [-d]] User Alias: vhost --adduali host_name user_alias|catch-all@ destinations vhost --deluali host_name user_alias|catch-all@ [destinations] Manage User: vhost --passwd [host_name] user_name vhost --access [host_name] [user_name] 2|1|0 Set Quota: vhost --qhost host_name mailbox_size(K/M/G)|. #user|. #uali|. vhost --quser owner_name disk_space(K/M/G)|. #host|. #hali|. List Info: vhost --lshost [host_name|owner_name] [-s|-r[n]] [-l] [-a] [-f] vhost --lsuser [host_name|owner_name] [-s|-r[n]] Copy/Update: vhost --cphost [host_name|owner_name] destination_ip [-f [-d]] vhost --uphost [host_name|owner_name] [-q] [-f] View Log: vhost --hostlog host_name [log_name|-q] vhost --cmdlog [log_file] Reload Daemon: vhost --reload [-delay_time(Sec)] [-f] -c: make Copy instead of symlink [note: "-p profile" can go anywhere in a cmd] -z,-i: add as dns Zone, add as Ip-based vhost (add reverse dns mapping) -q,-f,-d: Quit w/o reloading, Force add/del/list/reload, Delete data -s,-r,-l,-a: Sort, Reverse sort by [n]th field, Long list, list All # $HELL = <<'#'; Rotate Log: vhost --rotatelog [host_name] [-z] [-#backlog] Get Value: vhost --getvalue [host_name [user_name]] eval_script Get DNS: vhost --getdns host_name dns_variable Mod Pass: vhost --modpass user_name shell_bin|. pass_hash|. vdeliver: vhost --vdeliver user_name host_name poprelay: vhost --poprelay [ip_address [time_stamp]] netpulse: vhost --netpulse [pulse_rate ip_address [...]] Uninstall: vhost --uninstall Install: vhost --install [-f|-d] Qui[e]t: vhost -q # use 5; $INSTALL = $ARGV[0] =~ /^-*install$/; $MAILEXE = $ARGV[0] =~ /^-*(vdeliver|poprelay)$/; $ERR = 0; $ERR = 1, print $SUPPORT if $ARGV[0] =~ /^-*support$/; $ERR = 1, print $REQUIRE if $ARGV[0] =~ /^-*require$/; $ERR = 1, print $HISTORY if $ARGV[0] =~ /^-*history$/; $ERR = 1, print $VERSION if $ARGV[0] =~ /^-*version$/ || $ARGV[0] =~ /^-*v$/; $ERR && exit 0; print STDERR $VERSION, "\n" if $INSTALL; sub Print { print "vhost: $_[0]\n"; } sub Error { print STDERR "vhost: ", !$_[1] && "error - ", "$_[0]\n"; } sub Exit { my $err = $_[0] + 0; my $huid = $HOST? "\@$HOST" : ",$UID"; my @date = split /\s+/, $DATE; open FILE, ">> $CMDLOG"; flock FILE, 2; printf FILE "%3s %2s %8s %s %s", @date[1, 2, 3], (split /\./, $HNAM)[0], "vhost[$$:$err]: ($USER$huid) --@ARGV -p $PROF\n"; exit $err; } sub Cat { my @file; open FiLe, $_[0]; @file = ; close FiLe; return wantarray? @file : join "", @file; } sub Pw { my $cmd = $_[0]; $cmd =~ s/-m\s+-k\s+\Q$SKEL\E\s+/-M / if $UNIX =~ /^Linux$/i; $cmd =~ s/^(groupadd\s+.*\S+)\s+-g\s+\S+\s+-o$/$1/ if $FreeBSD; $cmd =~ s/^(groupmod\s+.*\S+)\s+-o$/$1/ if $FreeBSD; $cmd =~ s/^(usermod\s+.*\S+)\s+-o$/$1/ if $FreeBSD; $cmd =~ s/^(\S+)(\s+\S+)(.*)$/$1$3$2/ if !$FreeBSD; return "$FreeBSD$cmd"; } sub Flock { my $ok; if ($_[0]) { open FILE, "$_[1] $_[0]"; $ok = flock FILE, 2; $ERR = 1, Error "unable to lock file '$_[0]'" if !$ok; $ERR && Exit 7; seek (FILE, 0, 0), @FILE = if $_[1] =~ /^\+/; seek FILE, 0, $_[2]; $TELL = tell; } else { truncate FILE, tell if tell && !$TELL || @FILE && !grep /./s, @FILE; close FILE; undef @FILE; } } sub GetFn { my $fn = $_[0]; my $n = `(cd \`dirname "$fn"\` && pwd) $NERR`; chomp $n; $fn = $fn =~ /^\// && $fn || "$n/" . `basename "$fn" $NERR`, chomp $fn if $fn; return $fn; } sub GetLn { my $ln = $_[0]; my $n = `(cd \`dirname "$ln"\` && pwd) $NERR`; chomp $n; $ln = $ln =~ /^\// && $ln || "$n/" . `basename "$ln" $NERR`, chomp $ln if $ln; $ln = readlink ($ln) =~ /(.*)/ && $1, $ln = $ln =~ /^\// && $ln || "$n/" . $ln while -l $ln; return $ln; } sub GetHa { my ($ha, $i); /^\s*$HEAD|^\s*$FOOT|^\s*# (\S+) $SIGN/ && ($ha = $1), /^\s*[^#\s]+\s+\Q$_[0]\E(\s|$)/ && last, $i++ == $#HOST && ($ha = undef) for @HOST; return $ha; } sub CheckI { $_[0] = $_ if !@_; my $err; return !$err if $_[1] == 2 && $_[0] eq "."; $err = $err || $_[0] !~ /\A\d+\.\d+\.\d+\.\d+\z/ || $_ > 255 || /^0./ for split /\./, $_[0] || 0; $err && $_[1] && Error "invalid ip address '$_[0]'"; return !$err; } sub CheckH { $_[0] = $_ if !@_; my $err; $err = 1, $_[1] && Error "invalid host name '$_[0]'" if $_[0] !~ /\A([A-Z0-9-]+\.)+[A-Z]{2,8}\z/i || length $_[0] > 67; $err = 1, $_[1] && Error "upper case in host name '$_[0]'" if $_[0] =~ /[A-Z]/ && !$err; return !$err; } sub CheckU { $_[0] = $_ if !@_; my $err; return !$err if $_[1] == 2 && $_[0] eq "catch-all@"; $err = 1, $_[1] && Error "invalid user name '$_[0]'" if $_[0] !~ /\A[A-Z][A-Z0-9_.-]*\z/i; $err = 1, $_[1] && Error "upper case in user name '$_[0]'" if $_[0] =~ /[A-Z]/ && !$err; return !$err; } sub CheckF { $_[0] = $_ if !@_; my $err; $err = 1, $_[1] && Error "invalid file or directory '$_[0]'" if $_[0] !~ /\A[\/\w.-]*[\w.-]\z/ || $_[0] =~ /(^|\/)\.+$/; return !$err; } sub CheckN { $_[0] = $_ if !@_; my $err; $err = 1, $_[1] && Error "invalid log name '$_[0]'" if $_[0] !~ /\A[\w.-]+\z/ || $_[0] =~ /^\.+$/; return !$err; } sub CheckQ { $_[0] = $_ if !@_; my $err; my $re = '|\.' if $_[1] == 2; $err = 1, $_[1] && Error "invalid quota '$_[0]'" if $_[0] !~ /\A(\d+(\.\d*)?[KMGT]$re)\s+(\d+$re)\s+(\d+$re)\z/i; return !$err; } $HOST = $ENV{VHOST_HOSTNAME} =~ /(.*)/ && $1; $USER = $ENV{VHOST_USERNAME} =~ /(.*)/ && $1; $PASW = $ENV{VHOST_PASSWORD} =~ /(.*)/ && $1; $PROF = $ENV{VHOST_PROFILE} =~ /(.*)/ && $1; $DEBUG = $ENV{VHOST_DEBUG} =~ /(.*)/ && $1; $LOCAL = $ENV{VHOST_LOCAL} =~ /(.*)/ && $1; $CHILD = $ENV{VHOST_CHILD} =~ /(.*)/ && $1; $NEWVU = $ENV{VHOST_NEWVU} =~ /(.*)/ && $1; $NEWIP = $ENV{VHOST_NEWIP} =~ /(.*)/ && $1; $USRID = $ENV{VHOST_USRID} =~ /(.*)/ && $1; $VDATE = $ENV{VHOST_VDATE} =~ /(.*)/ && $1; $QHOST = $ENV{VHOST_QHOST} =~ /(.*)/ && $1; $QUSER = $ENV{VHOST_QUSER} =~ /(.*)/ && $1; $PAGER = $ENV{PAGER} =~ /(.*)/ && $1; $TERM = $ENV{TERM} =~ /(.*)/ && $1; $UID = $ENV{UID} =~ /(.*)/ && $1 || $<; $< = 0, $( = $) = 1999; undef %ENV; $DEBUG = length $DEBUG? 1 : undef; $ENV{VHOST_LOCAL} = $LOCAL, undef $LOCAL; $ENV{VHOST_CHILD} = $CHILD, undef $CHILD; $ENV{VHOST_NEWVU} = $NEWVU, undef $NEWVU; $ENV{VHOST_NEWIP} = $NEWIP, undef $NEWIP; $ENV{VHOST_USRID} = $USRID, undef $USRID; $ENV{VHOST_VDATE} = $VDATE, undef $VDATE; $ENV{VHOST_QHOST} = $QHOST, undef $QHOST; $ENV{VHOST_QUSER} = $QUSER, undef $QUSER; $ENV{PAGER} = $PAGER, undef $PAGER; $ENV{TERM} = $TERM, undef $TERM; $ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"; umask 0022; $NERR = "2>/dev/null" if !$DEBUG; $SKEL = "/tmp/.vhost/.skel"; $SIGN = "- added by vhost,"; $FOOT = "# keep this line - by vhost"; $HEAD = "# keep this line, the blank line above, and the line below - by vhost"; $DATE = (`date $NERR` =~ /(.*)/)[0]; $UNAM = `uname -sn $NERR`; $UNIX = ($UNAM =~ /(\S+)/g)[0]; $HNAM = lc (($UNAM =~ /(\S+)/g)[1]); $HNAM = lc ((gethostbyname $HNAM)[0]) || $HNAM if !CheckH $HNAM; $HIP = join ".", unpack "C4", (gethostbyname $HNAM)[4]; $GHID = 1999; $GUID = 2000; $FreeBSD = $UNAM =~ /^FreeBSD\s/i && "pw "; if ($HOST || $USER || $PASW) { my $pswd = (getpwnam $USER)[1]; my $loh = $HOST eq $HNAM || -c "/etc/vdata/vusers.$HOST"; $USER = $HOST && !$loh && (Cat ("/etc/vdata/vusers.$HOST") =~ /^\s*([^#\s]+)\s+\Q$USER\E(\s|$)/m)[0] || $USER; $PSWD = $HOST && !$loh? (Cat ("/etc/vdata/shadow.$HOST") =~ /^\s*\Q$USER\E:([^:]*):/m)[0] : $pswd; $USER = undef if (!$PSWD || $PSWD ne crypt $PASW, $PSWD) && !-o (getpwuid $UID)[7]."/.rhosts"; } else { $USER = getpwuid $UID; } $ERR = 1, Error "login incorrect" if !$USER || !$INSTALL && $> || $INSTALL && ($UID || $>); $ERR && exit 127; for my $f (split /[#\s,]+/, $REQUIRE) { next if $f =~ /^(|-.*|echo|cd|pwd)$/ || $ARGV[0] !~ /^-*cphost$/ && $f =~ /^(stty|ssh|rsync)$/ || !$INSTALL && $f =~ /^(make|gcc|g\+\+)$/ || ($FreeBSD? $f =~ /^(useradd|usermod|userdel|groupadd|groupmod|groupdel)$/ : $f =~ /^(pw|chpass)$/); my $ok; $ok = $ok || -f "$_/$f" && -x "$_/$f" for split /:/, $ENV{PATH}; $ERR = 1, Error "missing system file '$f'" if $f =~ /^\// && !-f $f; $ERR = 1, Error "missing system command '$f'" if $f !~ /^\// && !$ok; } $ERR && exit 1; $ERR = 1, Error "invalid main host name '$HNAM'" if !CheckH ($HNAM) || !CheckI $HIP; $ERR && exit 1; @HOST = Cat "/etc/vhosts"; /^\s*([^#\s]+)\s+(\S+)\s*(.*)/ && ($HOST{$2} ||= $1, $QHOST{$2} ||= $3) for @HOST; @USER = Cat "/etc/vusers"; /^\s*([^#\s]+)\s+(\S+)\s*(.*)/ && ($USER{$1} ||= -f "$2/V00hostconf" && $2, $QUSER{$1} ||= $3) for @USER; @PROF = ; /(\/etc\/vdata\/vhostd\.(.*))/ && ($PROF{$2} ||= (readlink $1 || $1) =~ /(.*)/ && $1) for @PROF; $HOME{$_} ||= (Cat ("$_/V00hostconf") =~ /^\s*\$VHOME[\s"'=]+([^\s"'=;]+)/m)[0] for "/etc/vhost.d", values %USER, values %PROF; $OWNR{$_} ||= getpwuid ((stat "$HOME{$PROF{$_}}/$_")[4] =~ /(\d+)/? $1 : -1) || (stat "$HOME{$PROF{$_}}/$_")[4] for keys %PROF; $USER{root} = "/etc/vhost.d"; /^\s*# (\S+) $SIGN\s+(.*)/ && ($H[$#H+1] = $1, $DATE{$1} ||= $2) for @HOST; my $i; s/\n/ /g, $_ = /(.*)/ && $1 for @ARGV; /^-p$/ && ($PROF = $ARGV[$i+1]) && splice (@ARGV, $i, 2) && last, $i++ for @ARGV; $ARGV[0] =~ s/^-*// if @ARGV; $ARGV[0] =~ s/^listhost$/lshost/ if @ARGV; $ARGV[0] =~ s/^listuser$/lsuser/ if @ARGV; $_c = $_c || /^-.*c/ && "-c" for @ARGV; $_z = $_z || /^-.*z/ && "-z" for @ARGV; $_i = $_i || /^-.*i/ && "-i" for @ARGV; $_q = $_q || /^-.*q/ && "-q" for @ARGV; $_f = $_f || /^-.*f/ && "-f" for @ARGV; $_d = $_d || /^-.*d/ && "-d" for @ARGV; $_s = $_s || /^-.*s/ && "-s" for @ARGV; $_r = $_r || /^-.*r/ && "-r" for @ARGV; $_l = $_l || /^-.*l/ && "-l" for @ARGV; $_a = $_a || /^-.*a/ && "-a" for @ARGV; $_h = $_h || /^-.*h/ && "-h" for @ARGV; $_u = $_u || /^-.*u/ && "-u" for @ARGV; $_n = $_n || /^-\D*(\d+)|^(\d+)$/ && ($1 || $2) for @ARGV; if ($ARGV[0] eq "addvroot") { $P = $ARGV[1]; $W = $ARGV[2] !~ /^-/ && $ARGV[2]; } if ($ARGV[0] eq "delvroot") { $P = $ARGV[1]; $W = $ARGV[2] !~ /^-/ && $ARGV[2]; } if ($ARGV[0] eq "adddns") { $H = $ARGV[1]; $I = $ARGV[2] !~ /^-/ && $ARGV[2] || "."; } if ($ARGV[0] eq "deldns") { $H = $ARGV[1]; $I = $ARGV[2] !~ /^-/ && $ARGV[2]; } if ($ARGV[0] eq "addhost") { $H = $ARGV[1]; $O = $ARGV[2]; $I = $ARGV[3] !~ /^-/ && $ARGV[3] || "."; } if ($ARGV[0] eq "delhost") { $H = $ARGV[1]; } if ($ARGV[0] eq "addhali") { $H = $ARGV[1]; $A = $ARGV[2]; } if ($ARGV[0] eq "delhali") { $A = $ARGV[1]; $H = GetHa $A; } if ($ARGV[0] eq "adduser") { $H = $ARGV[1]; $U = $ARGV[2]; $N = $ARGV[3] !~ /^-/ && $ARGV[3]; } if ($ARGV[0] eq "deluser") { $H = $ARGV[1]; $U = $ARGV[2]; } if ($ARGV[0] eq "adduali") { $H = $ARGV[1]; $V = $ARGV[2]; @N = @ARGV[3..$#ARGV]; } if ($ARGV[0] eq "deluali") { $H = $ARGV[1]; $V = $ARGV[2]; @N = @ARGV[3..$#ARGV]; } if ($ARGV[0] eq "passwd") { $H = $#ARGV > 1? $ARGV[1] : undef; $U = $#ARGV > 1? $ARGV[2] : $ARGV[1]; $M = $ARGV[3]; $O = $U if !$H; } if ($ARGV[0] eq "access") { $H = $ARGV[-1] !~ /^-/ && $#ARGV > 2 || $#ARGV > 3? $ARGV[1] : ($_h || $ARGV[1] =~ /\./) && $ARGV[1]; $U = $ARGV[-1] !~ /^-/ && $#ARGV > 2 || $#ARGV > 3? $ARGV[2] : ($_u || $ARGV[1] !~ /\./) && $ARGV[1]; $S = $ARGV[-1] !~ /^-/? $ARGV[-1] : $ARGV[-2]; $H = undef if $_h && $_u; $O = $U if !$H; } if ($ARGV[0] eq "qhost") { $H = $ARGV[1]; $Q = "@ARGV[2..4]"; } if ($ARGV[0] eq "quser") { $O = $ARGV[1]; $Q = "@ARGV[2..4]"; } if ($ARGV[0] eq "lshost") { $H = $ARGV[1] !~ /^-/ && ($_h || $ARGV[1] =~ /\./) && $ARGV[1]; $O = $ARGV[1] !~ /^-/ && ($_u || $ARGV[1] !~ /\./) && $ARGV[1]; $H = undef if $_h && $_u; } if ($ARGV[0] eq "lsuser") { $H = $ARGV[1] !~ /^-/ && ($_h || $ARGV[1] =~ /\./) && $ARGV[1]; $O = $ARGV[1] !~ /^-/ && ($_u || $ARGV[1] !~ /\./) && $ARGV[1]; $O = undef if $_h && $_u; } if ($ARGV[0] eq "cphost") { $H = $ARGV[2] !~ /^-/ && $ARGV[2] && ($_h || $ARGV[1] =~ /\./) && $ARGV[1]; $O = $ARGV[2] !~ /^-/ && $ARGV[2] && ($_u || $ARGV[1] !~ /\./) && $ARGV[1]; $R = $ARGV[2] !~ /^-/ && $ARGV[2] || $ARGV[1]; $O = undef if $_h && $_u; } if ($ARGV[0] eq "uphost") { $H = $ARGV[1] !~ /^-/ && ($_h || $ARGV[1] =~ /\./) && $ARGV[1]; $O = $ARGV[1] !~ /^-/ && ($_u || $ARGV[1] !~ /\./) && $ARGV[1]; $O = undef if $_h && $_u; } if ($ARGV[0] eq "hostlog") { $H = $ARGV[1]; $L = $ARGV[2] !~ /^-/ && $ARGV[2]; } if ($ARGV[0] eq "cmdlog") { $G = $ARGV[1]; } if ($ARGV[0] eq "rotatelog") { $H = $ARGV[1] !~ /^-|^\d+$/ && $ARGV[1]; } if ($ARGV[0] eq "getvalue") { $H = $#ARGV > 1 && $ARGV[1]; $U = $#ARGV > 2 && $ARGV[2]; $Y = $ARGV[-1]; } if ($ARGV[0] eq "getdns") { $H = $ARGV[1]; $Y = $ARGV[2]; } if ($ARGV[0] eq "modpass") { $V = $ARGV[1]; $S = $ARGV[2]; $M = $ARGV[3]; } if ($ARGV[0] eq "vdeliver") { $ARGV[-1] = lc $ARGV[-1]; $H = GetHa ($ARGV[-1]) || $ARGV[-1]; $ERR = !/\A[\w.+-]+\z/ && Error ("invalid user name '$_'") || $ERR for @ARGV[0..$#ARGV-1]; } if ($ARGV[0] eq "poprelay") { $ERR = !CheckI ($ARGV[1], 1) || $ERR if length $ARGV[1]; } if ($ARGV[0] eq "netpulse") { } $ERR && exit 2; $ERR = 1; $ERR = 0 if $#ARGV+1 > 1 && $#ARGV-1 < 4 && join ("\n", @ARGV) =~ /^addvroot\n[^-].*(\n[^-].*)?(\n-[cf\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 1 && $#ARGV-1 < 3 && join ("\n", @ARGV) =~ /^delvroot\n[^-].*(\n[^-].*)?(\n-[f\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 1 && $#ARGV-1 < 6 && join ("\n", @ARGV) =~ /^adddns\n[^-].*(\n[^-].*)?(\n-[ziqf\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 1 && $#ARGV-1 < 4 && join ("\n", @ARGV) =~ /^deldns\n[^-].*(\n[^-].*)?(\n-[qf\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 2 && $#ARGV-1 < 7 && join ("\n", @ARGV) =~ /^addhost\n[^-].*\n[^-].*(\n[^-].*)?(\n-[ziqf\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 1 && $#ARGV-1 < 4 && join ("\n", @ARGV) =~ /^delhost\n[^-].*(\n-[qfd\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 2 && $#ARGV-1 < 4 && join ("\n", @ARGV) =~ /^addhali\n[^-].*\n[^-].*(\n-[zq\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 1 && $#ARGV-1 < 2 && join ("\n", @ARGV) =~ /^delhali\n[^-].*(\n-[q\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 2 && $#ARGV-1 < 4 && join ("\n", @ARGV) =~ /^adduser\n[^-].*\n[^-].*(\n[^-].*)?(\n-[f\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 2 && $#ARGV-1 < 4 && join ("\n", @ARGV) =~ /^deluser\n[^-].*\n[^-].*(\n-[fd\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 3 && $#ARGV+1 > 0 && join ("\n", @ARGV) =~ /^adduali\n[^-].*\n[^-].*(\n.+)+$/; $ERR = 0 if $#ARGV+1 > 2 && $#ARGV+1 > 0 && join ("\n", @ARGV) =~ /^deluali\n[^-].*\n[^-].*(\n.+)*$/; $ERR = 0 if $#ARGV+1 > 1 && $#ARGV-1 < 3 && join ("\n", @ARGV) =~ /^passwd(\n[^-].*)?\n[^-].*(\n.+)?$/; $ERR = 0 if $#ARGV+1 > 2 && $#ARGV-1 < 4 && join ("\n", @ARGV) =~ /^access(\n[^-].*)?(\n[^-].*)?\n[210](\n-[hu\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 4 && $#ARGV-1 < 4 && join ("\n", @ARGV) =~ /^qhost\n[^-].*\n[^-].*\n[^-].*\n[^-].*$/; $ERR = 0 if $#ARGV+1 > 4 && $#ARGV-1 < 4 && join ("\n", @ARGV) =~ /^quser\n[^-].*\n[^-].*\n[^-].*\n[^-].*$/; $ERR = 0 if $#ARGV+1 > 0 && $#ARGV-1 < 6 && join ("\n", @ARGV) =~ /^lshost(\n[^-].*)?(\n-[srlafhu\d\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 0 && $#ARGV-1 < 3 && join ("\n", @ARGV) =~ /^lsuser(\n[^-].*)?(\n-[srhu\d\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 1 && $#ARGV-1 < 6 && join ("\n", @ARGV) =~ /^cphost(\n[^-].*)?\n[^-].*(\n-[qfdhu\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 0 && $#ARGV-1 < 5 && join ("\n", @ARGV) =~ /^uphost(\n[^-].*)?(\n-[iqfhu\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 1 && $#ARGV-1 < 2 && join ("\n", @ARGV) =~ /^hostlog\n[^-].*(\n[^-].*)?(\n-[q\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 0 && $#ARGV-1 < 1 && join ("\n", @ARGV) =~ /^cmdlog(\n[^-].*)?$/; $ERR = 0 if $#ARGV+1 > 0 && $#ARGV-1 < 3 && join ("\n", @ARGV) =~ /^reload(\n[\d]+)?(\n-[lf\d\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 0 && $#ARGV-1 < 3 && join ("\n", @ARGV) =~ /^rotatelog(\n[^-].*)?(\n[\d]+)?(\n-[z\d\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 1 && $#ARGV-1 < 3 && join ("\n", @ARGV) =~ /^getvalue(\n[^-].*)?(\n[^-].*)?\n.+$/; $ERR = 0 if $#ARGV+1 > 2 && $#ARGV-1 < 2 && join ("\n", @ARGV) =~ /^getdns\n[^-].*\n.+$/; $ERR = 0 if $#ARGV+1 > 3 && $#ARGV-1 < 3 && join ("\n", @ARGV) =~ /^modpass\n[^-].*\n[^-].*\n.+$/; $ERR = 0 if $#ARGV+1 > 2 && $#ARGV+1 > 0 && join ("\n", @ARGV) =~ /^vdeliver(\n.+)+$/; $ERR = 0 if $#ARGV+1 > 0 && $#ARGV-1 < 2 && join ("\n", @ARGV) =~ /^poprelay(\n[^-].*)?(\n[\d]+)?$/; $ERR = 0 if $#ARGV+1 > 0 && $#ARGV+1 > 0 && join ("\n", @ARGV) =~ /^netpulse(\n.+)*$/; $ERR = 0 if $#ARGV+1 > 0 && $#ARGV-1 < 0 && join ("\n", @ARGV) =~ /^uninstall$/; $ERR = 0 if $#ARGV+1 > 0 && $#ARGV-1 < 1 && join ("\n", @ARGV) =~ /^install(\n-[fd\s-]+)?$/; $ERR = 0 if $#ARGV+1 > 0 && $#ARGV-1 < 0 && join ("\n", @ARGV) =~ /^q$/; $ERR = 0 if $HLP = "$HELP$HELL" !~ / vhost -+$ARGV[0]\s/; $ERR = $ERR || !length for @ARGV; $ERR && print STDERR $HELP; $ERR && exit 2; $ERR = !CheckH ($H, 1) || $ERR if length $H; $ERR = !CheckH ($A, 1) || $ERR if length $A; $ERR = !CheckU ($U, 1) || $ERR if length $U; $ERR = !CheckU ($V, 2) || $ERR if length $V; $ERR = !CheckU ($O, 1) || $ERR if length $O; $ERR = !CheckU ($W, 1) || $ERR if length $W; $ERR = !CheckI ($I, 2) || $ERR if length $I; $ERR = !CheckF ($P, 1) || $ERR if length $P; $ERR = !CheckF ($G, 1) || $ERR if length $G; $ERR = !CheckN ($L, 1) || $ERR if length $L; $ERR = !CheckQ ($Q, 2) || $ERR if length $Q; $ERR = !CheckH ($R) && !CheckI ($R, 1) || $ERR if length $R; $ERR && exit 2; if ($INSTALL) { $< = (stat "./vhost.pl")[4]; $ERR = 1, Error "invalid or insecure install module './vmake'" if !-f "./vmake" || !-o "./vmake" && !-O "./vmake"; $ERR && exit 1; $< = 0; do "./vmake"; } $< = $UID; $PROF = -f "$P/V00hostconf" && $P || CheckQ ($QHOST{$H}) && $PROF{$H} || $HLP && CheckQ ($QHOST{$ARGV[1]}) && $PROF{$ARGV[1]} || (-f "$PROF/V00hostconf" || -t) && $PROF || $USER{$O} || $HLP && !$HOST && $USER{$ARGV[1]} || !$HOST && $USER{$USER} || $USER{getpwuid $UID} || "/etc/vhost.d"; $ERR = 1, Error "invalid or insecure profile '$PROF'" if !-d $PROF || !-o $PROF || -W $PROF && $UID || !CheckF $PROF; $ERR && exit 1; $ERR = 1, Error "missing '$PROF/V00hostconf'" if !-f "$PROF/V00hostconf"; $ERR && exit 1; $< = 0; $PROF = GetFn $PROF; require for $MAILEXE? <$PROF/V2[05]*> : <$PROF/V[0-9][0-9]*>; sub Do { $X = $_[0]; $MOD = "$PROF/V00hostconf", eval V00hostconf; $MOD = $_, /\/V00hostconf$/ || do $_ for $MAILEXE? <$PROF/V2[05]*> : <$PROF/V[0-9][0-9]*>; } Do "configuration"; Do "initialization"; Do $ARGV[0]; Do "finalization"; $HLP && print STDERR $HELP; $HLP && exit 2; Exit $ERR; sub V00hostconf { ############################################################ $X eq "configuration" && do { ################################################ BEGIN {eval "require Time::HiRes; import Time::HiRes 'sleep';" if !$MAILEXE;} require IO::Pty if !$MAILEXE; require Quota if !$MAILEXE; do "$PROF/V00hostconf"; $ARGV[0] =~ /^(.*dns|reload|netpulse)$/ && ($LOCAL ||= !$HOSTs && !$DNSs); $ARGV[0] !~ /^(.*dns|reload|netpulse)$/ && ($LOCAL ||= !$HOSTs); my $err; $err = 0; $err ||= !CheckH && !CheckI for @HOSTs = split /\s+/, $HOSTs; $ERR = 1, Error "$MOD: \$HOSTs = '$HOSTs'" if $err; $err = 0; $err ||= !CheckH && !CheckI for @DNSs = split /\s+/, $DNSs; $ERR = 1, Error "$MOD: \$DNSs = '$DNSs'" if $err; $err = 0; $err ||= !CheckI for @IPs = split /-|\s+/, $IPs; $ERR = 1, Error "$MOD: \$IPs = '$IPs'" if $err; $err = 0; $err ||= !CheckH && $_ for @TLDs = split /^\.*|\.*\s+\.*|\.*$/, $TLDs; $ERR = 1, Error "$MOD: \$TLDs = '$TLDs'" if $err; $ERR = 1, Error "$MOD: \$HOSTADD = '$HOSTADD'" if $HOSTADD !~ /\A[210]\z/; $ERR = 1, Error "$MOD: \$IPADD = '$IPADD'" if $IPADD !~ /\A[10]\z/; $ERR = 1, Error "$MOD: \$DNSAWARE = '$DNSAWARE'" if $DNSAWARE !~ /\A[10]\z/; $ERR = 1, Error "$MOD: \$UIDSYNC = '$UIDSYNC'" if $UIDSYNC !~ /\A\d+\z/; $ERR = 1, Error "$MOD: \$ROOTCMD = '$ROOTCMD'" if $ROOTCMD !~ /\A[10]\z/; $ERR = 1, Error "$MOD: \$RUSER = '$RUSER'" if $RUSER =~ /^(root|nobody)$/ || !CheckU $RUSER; $ERR = 1, Error "$MOD: \$REXEC = '$REXEC'" if $REXEC !~ /\s+-l\s+\Q$RUSER\E\s*\z/; $ERR = 1, Error "$MOD: \$VHOME = '$VHOME'" if $VHOME !~ /^\// || !CheckF $VHOME; $ERR = 1, Error "$MOD: \$HTEMP = '$HTEMP'" if $HTEMP && ($HTEMP !~ /^\// || !CheckF $HTEMP); $ERR = 1, Error "$MOD: \$UTEMP = '$UTEMP'" if $UTEMP && ($UTEMP !~ /^\// || !CheckF $UTEMP); $ERR = 1, Error "$MOD: \$ADMIN = '$ADMIN'" if !CheckU $ADMIN; $ERR = 1, Error "$MOD: \$SHELL = '$SHELL'" if !grep /^\s*\Q$SHELL\E\s*$/, Cat "/etc/shells"; $ERR = 1, Error "$MOD: \$ACCESS = '$ACCESS'" if $ACCESS !~ /\A[210]\z/; $ERR = 1, Error "$MOD: \$OWNERMAX = '$OWNERMAX'" if $OWNERMAX !~ /\A\d+\z/; $ERR = 1, Error "$MOD: \$QHOST = '$QHOST'" if !CheckQ $QHOST; $ERR = 1, Error "$MOD: \$QUSER = '$QUSER'" if !CheckQ $QUSER; $ERR = 1, Error "$MOD: \$CMDLOG = '$CMDLOG'" if $CMDLOG !~ /^\// || !CheckF $CMDLOG; $ERR = 1, Error "$MOD: \$PAGER = '$PAGER'" if $PAGER !~ /^\// || !-x (split /[\s|&;]+/, $PAGER)[0]; $ERR = 1, Error "$MOD: \$DUCACHE = '$DUCACHE'" if $DUCACHE !~ /\A[10]\z/; $ERR = 1, Error "$MOD: \$UPDATEIP = '$UPDATEIP'" if $UPDATEIP !~ /\A[10]\z/; $ERR = 1, Error "$MOD: \$dotChar = '$dotChar'" if $dotChar !~ /\A[\w.-]\z/; $ERR = 1, Error "$MOD: \$unameLen = '$unameLen'" if !$unameLen || $unameLen !~ /\A\d+\z/; $ERR = 1, Error "$MOD: \$minLogin = '$minLogin'" if !$minLogin || $minLogin !~ /\A\d+\z/; $ERR = 1, Error "$MOD: \$blockSize = '$blockSize'" if !$blockSize || $blockSize !~ /\A\d+\z/; $ERR = 1, Error "$MOD: \$homeDir = '$homeDir'" if !-d $homeDir; $ERR = 1, Error "$MOD: \$mailDir = '$mailDir'" if !-d $mailDir; $ERR = 1, Error "$MOD: \$cronDir = '$cronDir'" if !-d $cronDir; $ERR = 1, Error "$MOD: \$passwdCf = '$passwdCf'" if !-f $passwdCf; $ERR = 1, Error "$MOD: \$shadowCf = '$shadowCf'" if !-f $shadowCf; $ERR = 1, Error "$MOD: \$aliasesCf = '$aliasesCf'" if !-f $aliasesCf; $ERR = 1, Error "$MOD: \$inetdCf = '$inetdCf'" if !-e $inetdCf; $ERR = 1, Error "$MOD: \$inetdRc = '$inetdRc'" if $inetdRc && ($inetdRc !~ /^\// || !-x (split /[\s|&;]+/, $inetdRc)[0]); $RID = getpwnam $RUSER; $LOCAL = $1 if $ENV{VHOST_LOCAL} =~ s/(.+)// && (!$HOST && $USER eq "root" || $UID == $RID); $CHILD = $1 if $ENV{VHOST_CHILD} =~ s/(.+)// && (!$HOST && $USER eq "root" || $UID == $RID); $NEWVU = $1 if $ENV{VHOST_NEWVU} =~ s/(.+)// && (!$HOST && $USER eq "root" || $UID == $RID); $NEWIP = $1 if $ENV{VHOST_NEWIP} =~ s/(.+)// && (!$HOST && $USER eq "root" || $UID == $RID); $USRID = $1 if $ENV{VHOST_USRID} =~ s/(.+)// && (!$HOST && $USER eq "root" || $UID == $RID); $VDATE = $1 if $ENV{VHOST_VDATE} =~ s/(.+)// && (!$HOST && $USER eq "root" || $UID == $RID); $QHOST = $1 if $ENV{VHOST_QHOST} =~ s/(.+)// && (!$HOST && $USER eq "root" || $UID == $RID); $QUSER = $1 if $ENV{VHOST_QUSER} =~ s/(.+)// && (!$HOST && $USER eq "root" || $UID == $RID); $PAGER = $ENV{PAGER} if -f $ENV{PAGER} && -x $ENV{PAGER} && -o $ENV{PAGER}; $RDNS = $DNSs[0] if !$LOCAL && $DNSs !~ /(^|\s)(\Q$HNAM\E|\Q$HIP\E)(\s|$)/; }; $X eq "initialization" && do { ############################################### sub Error5 { $ERR = 1, Error $_[0]; $ERR && Exit 5; } sub Prompt { my $yn; print "vhost: $_[0]. continue? y/n[n]: "; chomp ($yn = $_f? "y" : ); print "$yn\n" if $_f || !-t; $RECHO .= "$yn\n" if !$_f; $yn !~ /^y/i && Exit 6; } sub Forced { my $yn; print "vhost: delete $_[0]? y/n[n]: "; chomp ($yn = $_f? $_d && "y" || "n" : ); print "$yn\n" if $_f || !-t; $RECHO .= "$yn\n" if !$_f; $_d = $yn =~ /^y/i && "-d" if !$_f; } sub Passwd { my ($pass, $pswd); print "vhost: password for '$_[0]': "; chomp ($pass = $_f? "" : ); print "$pass\n" if $_f || !-t; $pswd = $pass; $pswd =~ s/([\\\$"`])/\\\\\\$1/g; $RECHO .= "$pswd\n" if !$_f; $ERR = 1, Error "no password supplied" if !$_f && !$pass; $ERR && Exit 6; return $pass; } sub Crypt { my ($salt, $pswd); $salt .= (".", "/", 0..9, "A".."Z", "a".."z")[rand 64] for 1..8; $pswd = crypt $_[0], "\$1\$$salt"; return $pswd; } sub ModShell { my $shell = $_[1] || $SHELL[1]; `chpass -s '$shell' $_[0] $NERR` if $FreeBSD && $shell ne "."; `usermod -s '$shell' $_[0] $NERR` if !$FreeBSD && $shell ne "."; } sub ModPass { my $pswd = $_[1] || $SHELL[0]; `chpass -p '$pswd' $_[0] $NERR` if $FreeBSD && $pswd ne "."; `usermod -p '$pswd' $_[0] $NERR` if !$FreeBSD && $pswd ne "."; } sub SetPass { ModPass $_[0], $_[1] && Crypt $_[1]; my ($i, $tmp); my $master = new IO::Pty; my $slave = $master->slave; my $s = defined &sleep? 0.1 : 1; if (fork == 0 && $master->make_slave_controlling_terminal) { close $master; open STDIN, "<&".$slave->fileno; open STDOUT, ">&".$slave->fileno; open STDERR, ">&".$slave->fileno; $( = 0; exec "passwd $_[0]; echo '$SIGN'" if length $_[0]; close $slave; exit 0; } close $slave; sleep ($s)+1 && print $master "$_[1]\n" while $i++ < 42 && $tmp !~ /^$SIGN/m && sleep ($s)+1 && sysread $master, $tmp, 99999; close $master; } sub Rssh { my ($cmd, $tmp, $out); my $master = new IO::Pty; my $slave = $master->slave; my $s = defined &sleep? 0.1 : 1; $cmd = $_[0], print "$cmd\n"; $cmd = "$cmd -p $_[2]" if $_[2]; $cmd =~ s/(vhost --.*)/\/bin\/sh -c \\'$_[3]\/usr\/sbin\/$1\\'/; return "" if $_q; if (fork == 0 && $master->make_slave_controlling_terminal) { close $master; open STDIN, "<&".$slave->fileno; open STDOUT, ">&".$slave->fileno; open STDERR, ">&".$slave->fileno; $( = 0; exec "$cmd; echo '$SIGN'" if length $_[0]; close $slave; exit 0; } close $slave; while ($tmp !~ /^$SIGN/m && sleep ($s)+1 && sysread $master, $tmp, 99999) { print $tmp if $DEBUG; sleep ($s)+1 && print $master "$_[1]\n" if $tmp =~ s/^(root\@\Q$R\E's )?password:.*//is; sleep ($s)+1 && print $master "yes\n" if $tmp =~ s/^The authenticity .*//is; $tmp =~ s/^Permission denied, please try again\..*//is; $tmp =~ s/^(\Q$_[1]\E|yes|)\s*\n//s; $tmp =~ s/^$SIGN\s*//m; $out .= $tmp; } close $master; $out =~ s/^(vhost: )(vhost: .*\n)(error -)/$2$1$3/m; print $out if !$DEBUG; return $out; } sub Rexec { my ($env, $cmd, @his); $env .= "VHOST_HOSTNAME=$HOST "; $env .= "VHOST_USERNAME=$USER "; $env .= "VHOST_DEBUG=$DEBUG "; $env .= "VHOST_LOCAL=$LOCAL "; $env .= "VHOST_CHILD=$CHILD "; $env .= "VHOST_NEWVU=$NEWVU "; $env .= "VHOST_NEWIP=$NEWIP "; $env .= "VHOST_USRID=$USRID "; $cmd = $_[0]; $cmd =~ s/\s+/ /g; $RECHO .= "y\ny\ny\n"; $_ && "@his" !~ /(^|\s)\Q$_\E(\s|$)/ && ($his[$#his+1] = $_) for split /\s+/, $_[2]; $< = $RID; print ("[$_[1] $_]\n$cmd\n"), system "$REXEC $_ echo \"\\\"$RECHO\\\"\" '|' $env/usr/sbin/$_[0] -p $PROF 2>&1" for @his; Exit 0; } sub Rdns { my ($var, $env, @out); $var = $_[0]; if (!$RDNS) { @out = $var =~ s/^\$//? ($$var) : Cat $var =~ s/^\@//? $$var : $var; } else { $var =~ s/([\\\$"`])/\\\\\\$1/g; $env .= "VHOST_USERNAME=$USER "; $env .= "VHOST_DEBUG=$DEBUG "; $env .= "VHOST_LOCAL=1 "; $< = $RID; @out = `$REXEC $RDNS $env/usr/sbin/vhost --getdns $H $var -p $PROF $NERR`; $< = 0; } return wantarray? @out : join "", @out; } sub Ldns { $ENV{VHOST_USERNAME} = $USER; $ENV{VHOST_DEBUG} = $DEBUG; $< = $RID; system "/usr/sbin/$_[0] -p $PROF 2>&1"; $< = 0; } sub GroupAdd { my @ghid = split /\D+/, `id -G $_[0] $NERR`; my $ghid = join ",", $GHID, @ghid if !grep /^\Q$GHID\E$/, @ghid; `${\(Pw "usermod $_[0] -G $ghid")} $NERR` if $ghid; } sub BackupCf { `cp -p $_[0] $_[0].vhost.0 $NERR` if -f FILE && (stat $_[0])[9] != (stat "$_[0].vhost.0")[9]; } sub AddConf { my ($i, $j, $ok, $no); my $re = $_[2]; my $conf = $_[1]; my $date = $DATE{$H} || $VDATE || $DATE; $conf =~ s/\[VROOT_NAME\]/$W/g; $conf =~ s/\[PROFILE_DIR\]/$P/g; $conf =~ s/\[ZONE_NAME\]/$Z/g; $conf =~ s/\[MASTER_IP\]/$MASIP/g; $conf =~ s/\[HOST_NAME\]/$H/g; $conf =~ s/\[HOST_ALIAS\]/$A/g; $conf =~ s/\[OWNER_NAME\]/$O/g; $conf =~ s/\[IP_ADDRESS\]/$I/g; $conf =~ s/\[USER_NAME\]/$U/g; $conf =~ s/\[USER_ALIAS\]/$V/g; Flock $_[0], "+<", 0; /^\s*# \Q$H\E $SIGN/ && ($j = $i), $j && /^\s*$FOOT/ && last, $j && /^\s*$HEAD/ && ($no = 1), $j && !$ok && $re && s/$re//is && ($ok = 1), $j && !$ok && $j != $i && ($_ = ""), $j && $HOST{$H} && $I && $HOST{$H} ne $I && s/(^|[^\d.])\Q$HOST{$H}\E([^\d.]|$)/$1$I$2/g, $j && $OWNR{$H} && $O && $OWNR{$H} ne $O && s/(^|[^\w.-])\Q$OWNR{$H}\E([^\w.-]|$)/$1$O$2/g, $j && $HOME{$PROF{$H}} && $HOME{$PROF{$H}} ne $VHOME && s/(^|[^\w.-])\Q$HOME{$PROF{$H}}\/$H\E([^\w.-]|$)/$1$VHOME\/$H$2/g, $i++ for @FILE; print FILE @FILE if $i <= $#FILE && !$no && $FILE[$j-1] =~ /^\s*$HEAD/ && $FILE[$j] =~ s/(.*)/$1$conf/s && $conf; Flock 0; Flock $_[0], "+>>", 2; print FILE "\n$HEAD\n# $H $SIGN $date\n$conf$FOOT\n" if $conf && !grep /^\s*# \Q$H\E $SIGN/, @FILE; Flock 0; } sub DelConf { my ($i, $j, $no); Flock $_[0], "+<", 0; s/^\s*# \Q$H\E $SIGN.*//s && ($j = $i), $j && s/^\s*$FOOT.*//s && last, $j && /^\s*$HEAD/ && ($no = 1), $j && ($_ = ""), $i++ for @FILE; print FILE @FILE if $i <= $#FILE && !$no && $FILE[$j-1] =~ s/^\s*$HEAD.*//s && $FILE[$j-2] =~ s/^\s*$//s; Flock 0; } sub ReloadRc { my $rc = $_[0]; my $rf = $MOD; $rc =~ s/(;|$)/ 2>&1$1/g if $rc; $rf =~ s/.*\/V(\d\d)([^\/]*)$/r$1.$2/; `touch /tmp/.vhost/.$rf $NERR` if $rc eq "0"; $_ && chomp && Print $_ for -f "/tmp/.vhost/.$rf" && $rc && `$rc`; `rm /tmp/.vhost/.$rf $NERR` if -f "/tmp/.vhost/.$rf" && $rc ne "0"; } sub UpdateFs { my ($zf, $ok); my @fs = localtime; my $fs = ($fs[5] + 1900) * 1000000 + ($fs[4] + 1) * 10000 + $fs[3] * 100; my $file = ($zf = (split /\//, $_[0])[-1]) && [Cat "/tmp/.vhost/.$zf"] || \@FILE; `rm /tmp/.vhost/.$zf $NERR`; $ok = $ok || /\sin\s+soa\s/i, $ok && /(^|\s)(\d+)(\s|$)/ && ($fs = $fs>$2? $fs : $2+1) && s/(^|\s)(\d+)(\s|$)/$1$fs$3/ && last for @{$file}; return $fs; } sub GetZf { my ($zf, $ok, $i, @a, @z); $ok = $ok || /^\s*zone[\s"']+\Q$_[0]\E[\s"']/i, @a = /\{/g, @z = /\}/g, $i += $#a - $#z, $ok && (/\bfile[\s"']+([^\s"';]+)/i && ($zf = $1) || /\}/ && $i <= 0) && last for @dnsCf; my ($zd, $ok, $i, @a, @z); $ok = $ok || /^\s*options\b/i, @a = /\{/g, @z = /\}/g, $i += $#a - $#z, $ok && (/\bdirectory[\s"']+([^\s"';]+)/i && ($zd = $1) || /\}/ && $i <= 0) && last for @dnsCf; return "$zd/$zf" if $zf; } sub GetZ { my $z; my @z = split /\./, $_[0]; $z = join (".", @z[$_..$#z]), ( $ARGV[0] =~ /^.*dns$/ && ($_z || grep /^\s*zone[\s"']+\Q$z\E[\s"']/i, @dnsCf) || $ARGV[0] !~ /^.*dns$/ && $PROF{$z} || grep $z =~ /^[^.]+\.\Q$_\E$/, @TLDs ) && last for 0..$#z-1; return $z; } sub GetI { sub i2n { my @i = split /\./, $_[0]; my $n = ($i[0] << 24) + ($i[1] << 16) + ($i[2] << 8) + $i[3]; return $n; } sub n2i { my $n = $_[0]; my $i = join ".", $n >> 24, $n << 8 >> 24, $n << 16 >> 24, $n << 24 >> 24; return $i; } sub inm { my ($i, $n, $m) = ($_[0], split /\//, $_[1]); $m = 2 ** 32 - 2 ** (32 - (length $m? $m : 32)); return ($m & i2n $i) == ($m & i2n $n); } my ($n, $i, %i); for (split /\s+/, $IPs) { my $ip; my $n1 = i2n ((split /-/)[0]); my $n2 = i2n ((split /-/)[1]) || $n1; $ip = n2i (($n1<$n2?$n1:$n2) + $_), $I[$#I+1] = $ip, $IPADD == 1 && ($i{$ip} = grep $_ eq $ip, values %HOST), $IPADD == 2 && () for 0 .. abs $n1 - $n2; } $i = (CheckQ ($QHOST{$H}) && (!$UPDATEIP || !$NEWIP) || grep /^\Q$HOST{$H}\E$/, @I) && $HOST{$H} || $H ne $Z && $HOST{$Z}; $i = $i || $IPs[0] eq (split /\s+/, $IPs)[0] && $IPs[0] || $HIP if $IPADD == 0; $i = $i || $HIP if !$IPs || $IPADD == 3; $i = $HIP if $LOH; while (!$i && %i && $IPADD == 1) { $i{$_} == $n && ($i = $_) && last for @I; $n++; } while (!$i && %i && $IPADD == 2) { $i = "?"; } return $i; } sub GetU { if ($ARGV[0] ne "getvalue") { my ($loh, $env, $uid, @uid); for my $h (split /\s+/, $HOSTs) { $loh = $h eq $HNAM || $h eq $HIP || grep /(^|\s)\Q$h\E(\s|$)/, @HOST, keys %NIC; $env .= "VHOST_USERNAME=$USER "; $env .= "VHOST_DEBUG=$DEBUG "; $env .= "VHOST_LOCAL=$loh "; $< = $RID; $uid[$_] = 1 for `$REXEC $h $env/usr/sbin/vhost --getvalue $H \\\"GetU\\\;\\\" -p $PROF $NERR`; $< = 0; } $uid++ while $uid[$uid] || $uid < ($UIDSYNC < 60000? $UIDSYNC : 60000); Flock "/tmp/.vhost/.uid", ">", 0; print FILE "$uid\n"; Flock 0; return $uid; } else { my ($i, @u, @uid); $uid[$i++] = $u[2] while @u = getpwent; $uid[$i++] = $_ for Cat "/tmp/.vhost/.uid"; return @uid; } } sub GetAh { my ($i, $ok, @ah); $ok = $ok || /^\s*# \Q$_[0]\E $SIGN/, $ok && /^\s*$FOOT/ && last, $ok && /^\s*[^#\s]+\s+(\S+)/ && $1 ne $_[0] && ($ah[$#ah+1] = $1), $i++ == $#HOST && (@ah = ()) for @HOST; return @ah; } sub GetAc { my $ok; my $ac = 0; $ok = $ok || /^\s*# (\S+) $SIGN/ && $OWNR{$1} eq $_[0] && ($ac-- || 1), $ok = $ok && !/^\s*$HEAD|^\s*$FOOT/, $ok && /^\s*[^#\s]+\s/ && $ac++ for @HOST; return $ac; } sub GetMp { my $mp; my $p = $_[0]; my @p = split /\//, $p; @p = split /\//, $p while $p = readlink ($p) =~ /(.*)/ && $1; $mp = join ("/", @p[0..$#p-$_]) || "/", grep (/^\s*[^#\s]+\s+\Q$mp\E\s/, Cat "/etc/fstab") && last for 0..$#p; return $mp; } sub GetSh { my $sh; my $h = $_[1]? $VSPW{$_[0]} !~ /^!*\Q$SHELL[0]\E/ : (getpwnam $_[0])[8]; $sh = "2" if $_[1]? 0 : 1; $sh = "1" if $_[1]? $h : $h eq $SHELL[1]; $sh = "0" if $_[1]? !$h : $h eq $SHELL[0] || !$h; $sh = "-" if $_[1]? 0 : !(getpwnam $_[0])[0]; return $sh; } sub GetKb { my $kb; my $b = int $_[0] =~ /^\// && (`du -sck $_[0] $NERR` =~ /(\d+)\D+$/)[0] * 1024 || $_[0] > 0 && $_[0]; my $l = length $b; $b = sprintf ("%.".($l%3?2:3)."f", $b / ("1"."0"x$l)) * ("1"."0"x$l); $kb = sprintf "%.3sT", $b / 1e12 . ".0" if $b >= 1e12; $kb = sprintf "%.3sG", $b / 1e9 . ".0" if $b >= 1e9 && !$kb; $kb = sprintf "%.3sM", $b / 1e6 . ".0" if $b >= 1e6 && !$kb; $kb = sprintf "%.3sK", $b / 1e3 . ".0" if !$kb; return $kb; } sub GetNb { my $nb; my $b = substr $_[0], -1; my %b = ("T", 1e12, "G", 1e9, "M", 1e6, "K", 1e3); $b =~ y/kmgt/KMGT/; $nb = $_[0] * $b{$b} - !$b{$b}; return $nb; } sub GetDt { my ($dt, $i, @d, %t); @d = split /[\s:]+/, $_[0]; $t{$_} = ++$i for "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"; $dt = sprintf "%04d%02d%02d%02d%02d%02d", $d[7], $t{$d[1]}, $d[2], $d[3], $d[4], $d[5]; return $dt; } sub CleanO { my $p = $P || $PROF{$H}; my $o = $_[0]; my @o = getpwnam $o; my @user = Cat "/etc/vusers"; my %prof = %PROF; my %ownr = %OWNR; $prof{$H} = undef; $ownr{$H} = undef; if ($o[3] != $GHID && !grep $prof{$_} eq $p && $ownr{$_} eq $o, keys %prof) { Flock "/etc/vusers", "+<", 0; s/^\s*\Q$o\E\s+\Q$p\E\s.*\d\s*$//s for @FILE; print FILE @FILE; Flock 0; } if ($o[3] != $GHID && !grep (/^\Q$o\E$/, values %ownr) && !grep (/^\s*\Q$o\E\s.*\svroot\s*$/, @user)) { Flock "/etc/vusers", "+<", 0; s/^\s*\Q$o\E\s.*//s for @FILE; print FILE @FILE; Flock 0; if ($o ne "root") { `mv $HOME{$USER{$o}}/home/$o $homeDir $NERR`; `${\(Pw "usermod $o -d $homeDir/$o")} $NERR`; } if ($o[3] == $GUID) { `rm -r $homeDir/$o $NERR`; `rm $mailDir/$o $NERR`; `${\(Pw "userdel $o")} $NERR`; } `rm -r $HOME{$USER{$o}}/home/$o $NERR` if $HOME{$USER{$o}} && (stat "$HOME{$USER{$o}}/home")[1] != (stat $homeDir)[1]; } } sub AllowO { my $ok; my $o = $_[0]; my $w = $_[1] || $USER; my $p = $_[2] || '\S+'; $p =~ s/\./\\./g; my @user = grep /^\s*\Q$w\E\s+$p\s.*\svroot\s*$/, @USER; $ok = grep /^\s*\Q$o\E\s+(\S+)/ && grep (/^\s*\Q$w\E\s+\Q$1\E\s.*\svroot\s*$/, @user), @USER; $ok = $ok || $o eq $w || $w eq "root"; $ok = $ok && length $o; # $ok || Error "not allowed to access host owner '$o'"; return $ok; } sub AllowI { my $ok; my $i = $_[0]; for (split /\s+/, $IPs) { my @ip = (split /\./, $i)[0..3]; my @i1 = (split /[.-]/)[0..3]; my @i2 = ((split /[.-]/)[4..7], @i1); $ok = 1; $ok = $ok && ($ip[$_] >= $i1[$_] && $ip[$_] <= $i2[$_] || $ip[$_] >= $i2[$_] && $ip[$_] <= $i1[$_]) for 0..3; $ok && last; } $ok = $ok || !length $IPs || $LOH && $i eq $HIP || $i eq $HOST{$H} || grep /(^|\s)\Q$i\E(\s|$)/, @zoneCf; $ok = $ok && length $i; $ok || Error "not allowed to access ip address '$i'"; return $ok; } sub AllowR { my ($err, $end, $key, $HOSTs_, $DNSs_, $VHOME_, $RUSER_); my $re = 'HOSTs|DNSs|VHOME|RUSER'; my $r = $_[0] || $RUSER; for my $d (grep !-l && -f "$_/V00hostconf", keys %HOME) { /^\s*\$($re)\s*=\s*(<<\s*)?["'](.*)["']\s*;\s*$/, $2 && ($end = $3, $key = $1), $1 && eval "\$$1_ = !'$2' && \"$3\";", /^\Q$end\E/ && $end && ($end = ""), !/\Q$end\E/ && $end && eval "\$${key}_ .= \"$_\";", /^\s*### DO NOT TOUCH ANYTHING/ && last for Cat "$d/V00hostconf"; $err = 1, last if $RUSER_ eq $r && ($HOSTs_ ne $HOSTs || $DNSs_ ne $DNSs || $VHOME_ ne $VHOME); } return !$err; } sub Quota { if ($ARGV[0] eq "addhost") { my $count = grep /^\s*[^#\s]+\s+\Q$PROF\E\s/, @USER; $ERR = 1, Error "$USER: quota exceeded - host owner max $OWNERMAX" if $count >= $OWNERMAX && $OWNERMAX && !@O; $ERR && Exit 4; my $count = grep $OWNR{$_} eq $O, keys %PROF; my $quota = (split /\s+/, $QUSER{$O})[1]; $ERR = 1, Error "$O: quota exceeded - host max $quota" if $count >= $quota && $quota && !$PROF{$H}; $ERR && Exit 4; } if ($ARGV[0] eq "addhali") { my $count = GetAc $O; my $quota = (split /\s+/, $QUSER{$O})[2]; $ERR = 1, Error "$O: quota exceeded - host alias max $quota" if $count >= $quota && $quota && !$HOST{$H}; $ERR && Exit 4; } if ($ARGV[0] eq "adduser") { my $count = grep /^\s*[^#:]+:/, @VPWD; my $quota = (split /\s+/, $QHOST{$H})[1]; $ERR = 1, Error "$H: quota exceeded - user max $quota" if $count >= $quota && $quota && !$VPWD{$U}; $ERR && Exit 4; } if ($ARGV[0] eq "adduali") { my $count = grep /^\s*[^#:]+:/, @VALI; my $quota = (split /\s+/, $QHOST{$H})[2]; $ERR = 1, Error "$H: quota exceeded - user alias max $quota" if $count >= $quota && $quota && !$VALI{$V}; $ERR && Exit 4; } if ($ARGV[0] eq "qhost") { my @q = split /\s+/, $QHOST; $ERR = 1, Error "quota limit (@q) exceeded" if (GetNb ($Q[0]) > GetNb ($q[0]) || !GetNb ($Q[0])) && GetNb ($q[0]) || ($Q[1] > $q[1] || !$Q[1]) && $q[1] || ($Q[2] > $q[2] || !$Q[2]) && $q[2]; $ERR && Exit 4; } if ($ARGV[0] eq "quser") { my @q = split /\s+/, $QUSER; $ERR = 1, Error "quota limit (@q) exceeded" if (GetNb ($Q[0]) > GetNb ($q[0]) || !GetNb ($Q[0])) && GetNb ($q[0]) || ($Q[1] > $q[1] || !$Q[1]) && $q[1] || ($Q[2] > $q[2] || !$Q[2]) && $q[2]; $ERR && Exit 4; } } sub Security { if ($ARGV[0] =~ /^.*dns$/) { $ERR = 1, Error ("$MOD: \$DNSs = '$DNSs'"), $ERR = 1, Error ("\$DNSs must be defined for distributed systems", 1) if !$LOCAL && !$DNSs; $ERR && exit 1; my $hz = $Hz || '@'; my $ip = $I || $HOST{$H} || @zoneCf && ("@zoneCf" =~ /^\s*(\Q$hz\E|\Q$H.\E)\s+.*\s+(a|cname)\s+([\d.]+)\s*$/im)[2]; $ERR = 1, Error "permission denied" if $UID == $RID && $ip && !AllowI $ip; $ERR && Exit 3; } if ($ARGV[0] !~ /^.*dns$/) { $ERR = 1, Error ("$MOD: \$HOSTs = '$HOSTs'"), $ERR = 1, Error ("\$HOSTs must include local server", 1) if !$LOCAL && $HOSTs !~ /(^|\s)(\Q$HNAM\E|\Q$HIP\E)(\s|$)/ && $ARGV[0] ne "reload"; $ERR && exit 1; $ERR = 1, Error "explicit ip not allowed for distributed systems or dynamic ip" if $Ip && $Ip ne "." && (!$LOCAL || $IPADD == 3); $ERR && Exit 3; } $ERR = 1, Error ("$MOD: \$RUSER = '$RUSER'"), $ERR = 1, Error ("\$RUSER is used by another profile with different \$HOSTs/\$DNSs or \$VHOME", 1) if $ONCFG && !AllowR $RUSER; $ERR && exit 1; $PERM = 4; $PERM = 3 if $HOST && $HOST eq $H && (getpwnam (!$LOH? $VUSR{$USER} : $USER))[8] ne $SHELL[0] && (!$U || $U eq $USER) && (!$V || $V eq $USER); $PERM = 2 if !$HOST && grep (/^\s*\Q$USER\E\s+\Q$PROF\E\s/, @USER) && (getpwnam $USER)[8] ne $SHELL[0] && (!$H || !$LOH || $PROF{$H} && $OWNR{$H}) && (!$O || !$H || $O eq $OWNR{$Z}) && (!$O || $O eq $USER) && (!$I || $Ip eq ".") && (!$S || $S <= 1) && (!$A || $O eq $OWNR{GetZ $A}); $PERM = 1 if !$HOST && grep (/^\s*\Q$USER\E\s+\Q$PROF\E\s.*\svroot\s*$/, @USER) && (getpwnam $USER)[8] ne $SHELL[0] && (!$H || !$LOH || $PROF{$H} && $OWNR{$H}) && (!$OWNR{$Z} || AllowO $OWNR{$Z}) && (!$O || !@O || AllowO $O) && (!$I || $Ip eq ".") && (!$S || $S <= $ACCESS); $PERM = 0 if !$HOST && ($USER eq "root" && ($ROOTCMD || $UID != $RID) || $ARGV[0] =~ /^(.*dns|reload|netpulse)$/ && $UID == $RID) && (!$I || $Ip eq "." || AllowI $I) && (!$Y || grep /^\Q$Y\E$/, keys %EVAL, @dnsY); $ERR = 1, Error "permission denied" if $PERM > $_[0]; $ERR && Exit 3; } if ($ARGV[0] =~ /^.*dns$/) { @dnsCf = Rdns '@dnsCf'; @revZf = Rdns '@revZf'; $dnsRt = Rdns '$dnsRt'; $ERR = 1, Error "$MOD: \$dnsCf = '$dnsCf'" . ($RDNS && " [\$DNSs $RDNS]") if !@dnsCf; $ERR = 1, Error "$MOD: \$dnsRc = '$dnsRc'" if !$RDNS && $dnsRc && ($dnsRc !~ /^\// || !-x (split /[\s|&;]+/, $dnsRc)[0]); $ERR = 1, Error "$MOD: \$revZf = '$revZf'" . ($RDNS && " [\$DNSs $RDNS]") if !@revZf && $_i; $ERR = 1, Error "$MOD: \$dnsRt = '$dnsRt'" if !$RDNS && $dnsRt && !-d $dnsRt; /^\s*(\S+)\s+(\S+)\s*$/ && ($natC{$1} ||= $2) for split /^/m, $natC; } $ERR && Error "please adjust system configuration(s)", 1; $ERR && exit 1; $LOH = $H eq $HNAM || -c "/etc/vdata/vusers.$H" || !$H && $O && $O eq $U; $Ip = $I; $Z = GetZ $H; $I = GetI if $I eq "."; $Hz = ($H =~ /^(.*)\.\Q$Z\E$/)[0]; $P = GetFn $P; $G = GetFn $G; $N = substr $N, 0, 64; $O =~ s/\./$dotChar/g, $O = substr ($O, 0, $unameLen) || $OWNR{$H}; $W =~ s/\./$dotChar/g, $W = substr $W, 0, $unameLen; $U =~ s/\./$dotChar/g, $U = substr $U, 0, $unameLen; $Q =~ y/kmgt/KMGT/; @O = getpwnam $O; @W = getpwnam $W; @U = getpwnam $U; @V = getpwnam $V; @Q = split /\s+/, $Q; $Q[$_] eq "." && ($Q[$_] = (split /\s+/, $H? $QHOST{$H} : $QUSER{$O})[$_]) for 0..2; $LOCAL = 1 if $ARGV[0] !~ /^.*dns$/ && $H && $LOH; $LHOME = -l "$VHOME/$H"; $RHOME = "$VHOME/home/$RUSER"; @RUSER = getpwnam $RUSER; @SHELL = ("!", "/bin/false", $SHELL); @QHOST = (split /\s+/, CheckQ ($QHOST{$H}) && $QHOST{$H} || $QHOST)[0..2]; @QUSER = (split /\s+/, $QUSER{$W || $O} || $QUSER)[0..2]; $QHARD = sprintf "%.0f", GetNb ($QUSER[0]) / $blockSize; $QSTAB = $UNIX =~ /^Linux$/i? "usrquota" : "userquota"; $MOUNT = GetMp $HOME{$USER{$W || $O}} || $VHOME; $UOADD = "-u $USRID -o" if $USRID && $USRID =~ /\A\d+\z/ && !getpwuid $USRID; $ONCFG = $ARGV[0] !~ /^(lshost|lsuser|getvalue|getdns)$/ && !$MAILEXE; $MASIP = CheckH ($DNSs[0]) && join (".", unpack "C4", (gethostbyname $DNSs[0])[4]) || CheckI ($DNSs[0]) && $DNSs[0] || $HIP; $DNSRE = '\s+.*\s+(ns|a|cname|ptr)\s+'; $dnsC = !$masterC || !$slaveC? $masterC || $slaveC : $MASIP eq $HIP? $masterC : $slaveC; @dnsY = ('@dnsCf', '@revZf', '$dnsRt', '@zoneCf'); $zoneCf = $dnsRt.GetZf $Z; @zoneCf = Rdns '@zoneCf' if $zoneCf ne $dnsRt; $vusersCf = "/etc/vdata/vusers.$H"; $shadowCf = "/etc/vdata/shadow.$H" if !$LOH; $passwdCf = "/etc/vdata/passwd.$H" if !$LOH; $aliasesCf = "/etc/vdata/aliases.$H" if !$LOH; @VUSR = Cat $vusersCf; /^\s*([^#\s]+)\s+(\S+)/ && ($VUSR{$1} ||= $2) for @VUSR; @VSPW = Cat $shadowCf; /^\s*([^#:]+):([^:]*):/ && ($VSPW{$1} ||= $2) for @VSPW; @VPWD = Cat $passwdCf; /^\s*([^#:]+):([^:]*:){4}([^:]*):/ && ($VPWD{$1} ||= $3) for @VPWD; @VALI = Cat $aliasesCf; $VALI[-$_] =~ s/^(\s*,.*)//s && ($VALI[-$_-1] .= $1) for 1..$#VALI+1; /^\s*([^#:]+):\s*(.*)/s && ($VALI{$1} ||= $2) for @VALI; Security 4 if $ARGV[0] eq ""; Security 0 if $ARGV[0] eq "addvroot"; Security 0 if $ARGV[0] eq "delvroot"; Security $HOSTADD if $ARGV[0] eq "adddns"; Security $HOSTADD if $ARGV[0] eq "deldns"; Security $HOSTADD if $ARGV[0] eq "addhost"; Security $HOSTADD if $ARGV[0] eq "delhost"; Security $HOSTADD if $ARGV[0] eq "addhali"; Security $HOSTADD if $ARGV[0] eq "delhali"; Security 2 if $ARGV[0] eq "adduser"; Security 2 if $ARGV[0] eq "deluser"; Security 2 if $ARGV[0] eq "adduali"; Security 2 if $ARGV[0] eq "deluali"; Security 3 if $ARGV[0] eq "passwd"; Security 2 if $ARGV[0] eq "access"; Security 1 if $ARGV[0] eq "qhost"; Security 1 if $ARGV[0] eq "quser"; Security 2 if $ARGV[0] eq "lshost"; Security 2 if $ARGV[0] eq "lsuser"; Security 2 if $ARGV[0] eq "cphost"; Security $HOSTADD if $ARGV[0] eq "uphost"; Security 2 if $ARGV[0] eq "hostlog"; Security 4 if $ARGV[0] eq "cmdlog"; Security $HOSTADD if $ARGV[0] eq "reload"; Security 0 if $ARGV[0] eq "rotatelog"; Security $EVAL{$Y} if $ARGV[0] eq "getvalue"; Security 0 if $ARGV[0] eq "getdns"; Security 0 if $ARGV[0] eq "modpass"; Security 4 if $ARGV[0] eq "vdeliver"; Security 4 if $ARGV[0] eq "poprelay"; Security 4 if $ARGV[0] eq "netpulse"; Security 0 if $ARGV[0] eq "uninstall"; `touch /etc/vhosts $NERR` if !-e "/etc/vhosts"; `touch /etc/vusers $NERR` if !-e "/etc/vusers"; `touch /etc/vhostz $NERR` if !-e "/etc/vhostz"; `touch /etc/vuserz $NERR` if !-e "/etc/vuserz"; `ln -sf /etc/vmail /etc/vdata $NERR` if !-d "/etc/vdata"; `mkdir -p /etc/vmail $NERR` if !-e "/etc/vmail"; `mkdir -p /tmp/.vhost $NERR` if !-e "/tmp/.vhost"; `mkdir -p /usr/local/vhost $NERR` if !-e "/usr/local/vhost"; `mkdir -p /var/spool/vmail $NERR` if !-e "/var/spool/vmail"; `mkdir -p $VHOME/home $NERR` if !-e "$VHOME/home"; `mkdir -p $VHOME $NERR` if !-e $VHOME; `mkdir -p $HTEMP $NERR` if !-e $HTEMP; `mkdir -p $UTEMP $NERR` if !-e $UTEMP; `mkdir -p $SKEL $NERR` if !-e $SKEL; `chown 0:$GHID /etc/vhosts $NERR` if !-o "/etc/vhosts" || (stat "/etc/vhosts")[5] != $GHID; `chown 0:$GHID /etc/vusers $NERR` if !-o "/etc/vusers" || (stat "/etc/vusers")[5] != $GHID; `chown 0:$GHID /etc/vhostz $NERR` if !-o "/etc/vhostz" || (stat "/etc/vhostz")[5] != $GHID; `chown 0:$GHID /etc/vuserz $NERR` if !-o "/etc/vuserz" || (stat "/etc/vuserz")[5] != $GHID; `chown -h 0:$GHID /etc/vdata $NERR` if !-o "/etc/vdata" || (lstat "/etc/vdata")[5] != $GHID; `chown 0:$GHID /etc/vmail $NERR` if !-o "/etc/vmail" || (stat "/etc/vmail")[5] != $GHID; `chown 0:$GHID /tmp/.vhost $NERR` if !-o "/tmp/.vhost" || (stat "/tmp/.vhost")[5] != $GHID; `chown 0:$GHID /usr/local/vhost $NERR` if !-o "/usr/local/vhost" || (stat "/usr/local/vhost")[5] != $GHID; `chown 0:$GHID /var/spool/vmail $NERR` if !-o "/var/spool/vmail" || (stat "/var/spool/vmail")[5] != $GHID; `chown 0:$GHID $VHOME/home $NERR` if !-o "$VHOME/home" || (stat "$VHOME/home")[5] != $GHID; `chown 0:$GHID $VHOME $NERR` if !-o $VHOME || (stat $VHOME)[5] != $GHID; `chown 0:$GHID $HTEMP $NERR` if !-o $HTEMP || (stat $HTEMP)[5] != $GHID; `chown 0:$GHID $UTEMP $NERR` if !-o $UTEMP || (stat $UTEMP)[5] != $GHID; `chown 0:$GHID $SKEL $NERR` if !-o $SKEL || (stat $SKEL)[5] != $GHID; `chown 0:0 /tmp $NERR` if !-o "/tmp"; `chmod 0600 /etc/vhosts $NERR` if ((stat "/etc/vhosts")[2] & 07777) != 0600; `chmod 0600 /etc/vusers $NERR` if ((stat "/etc/vusers")[2] & 07777) != 0600; `chmod 0600 /etc/vhostz $NERR` if ((stat "/etc/vhostz")[2] & 07777) != 0600; `chmod 0600 /etc/vuserz $NERR` if ((stat "/etc/vuserz")[2] & 07777) != 0600; `chmod 0710 /etc/vdata $NERR` if ((stat "/etc/vdata")[2] & 07777) != 0710; `chmod 0710 /etc/vmail $NERR` if ((stat "/etc/vmail")[2] & 07777) != 0710; `chmod 0700 /tmp/.vhost $NERR` if ((stat "/tmp/.vhost")[2] & 07777) != 0700; `chmod 0755 /usr/local/vhost $NERR` if ((stat "/usr/local/vhost")[2] & 07777) != 0755; `chmod 0711 /var/spool/vmail $NERR` if ((stat "/var/spool/vmail")[2] & 07777) != 0711; `chmod 0711 $VHOME/home $NERR` if ((stat "$VHOME/home")[2] & 07777) != 0711; `chmod 0711 $VHOME $NERR` if ((stat $VHOME)[2] & 07777) != 0711; `chmod 0755 $HTEMP $NERR` if ((stat $HTEMP)[2] & 07777) != 0755; `chmod 0755 $UTEMP $NERR` if ((stat $UTEMP)[2] & 07777) != 0755; `chmod 0755 $SKEL $NERR` if ((stat $SKEL)[2] & 07777) != 0755; `chmod 1777 /tmp $NERR` if ((stat "/tmp")[2] & 07777) != 01777; `ln -s /usr/bin/false /bin/false $NERR` if !-e "/bin/false"; `ln -s $mailDir /var/spool/mail $NERR` if !-e "/var/spool/mail"; `mkdir -p $RHOME $NERR` if !-e $RHOME; `${\(Pw "groupadd vhost -g $GHID -o")} $NERR` if !getgrnam "vhost"; `${\(Pw "groupmod vhost -g $GHID -o")} $NERR` if getgrnam "vhost" != $GHID; `${\(Pw "groupadd vuser -g $GUID -o")} $NERR` if !getgrnam "vuser"; `${\(Pw "groupmod vuser -g $GUID -o")} $NERR` if getgrnam "vuser" != $GUID; `${\(Pw "useradd nobody -m -k $SKEL -s $SHELL[1]")} $NERR` if !getpwnam "nobody"; `${\(Pw "useradd $RUSER -c 'vhost ruser' -d $RHOME -m -k $SKEL -g $GHID -s /bin/sh")} $NERR` if !@RUSER; `${\(Pw "usermod $RUSER -c 'vhost ruser' -d $RHOME -g $GHID -s /bin/sh")} $NERR`, `mv $PROF/.* $RHOME $NERR` if @RUSER && "@RUSER[3,6,7,8]" ne "$GHID vhost ruser $RHOME /bin/sh"; `touch $RHOME/.rhosts $NERR` if !-e "$RHOME/.rhosts"; `chown 0:$GHID $RHOME/.rhosts $NERR` if !-o "$RHOME/.rhosts" || (stat "$RHOME/.rhosts")[5] != $GHID; `chown $RID:$GHID $RHOME $NERR` if (stat $RHOME)[4] != ($RID = getpwnam $RUSER) || (stat $RHOME)[5] != $GHID; `chmod 0644 $RHOME/.rhosts $NERR` if ((stat "$RHOME/.rhosts")[2] & 07777) != 0644; `chmod 0750 $RHOME $NERR` if ((stat $RHOME)[2] & 07777) != 0750; `chcon -t user_home_dir_t $VHOME $NERR` if -e "/selinux" && $ONCFG; `restorecon $VHOME/home $NERR` if -e "/selinux" && $ONCFG; #GroupAdd "nobody" if $ONCFG; my $ok; Flock "$cronDir/root", "+>>", 2 if !grep /^\s*$FOOT/, Cat "$cronDir/root"; BackupCf "$cronDir/root"; print FILE -s FILE && "\n" || "", "$FOOT\n"; print FILE "0 5 * * 0 /usr/sbin/vhost --rotatelog -z4\n" if !grep /^[^#]*\bvhost\s+-*rotatelog\b/, @FILE; print FILE "0 6 * * * /usr/sbin/vhost --lshost -af\n" if !grep /^[^#]*\bvhost\s+-*lshost\b/, @FILE; print FILE "5 6 * * * /usr/sbin/vhost --lsuser\n" if !grep /^[^#]*\bvhost\s+-*lsuser\b/, @FILE; `touch $cronDir $NERR` if -f FILE; Flock 0; Flock "/etc/vhosts", ">>", 2 if !-s "/etc/vhosts"; print FILE "### /etc/vhosts - vhost host index, do not edit\n"; print FILE "#\n"; print FILE "# ip_address\thost_name mailbox_size #user #uali\n"; print FILE "\n"; print FILE "127.0.0.1\tlocalhost.localdomain localhost\n"; Flock 0; Flock "/etc/vusers", ">>", 2 if !-s "/etc/vusers"; print FILE "### /etc/vusers - vhost user index, do not edit\n"; print FILE "#\n"; print FILE "# user_name\tprofile_dir disk_space #host #hali vroot\n"; print FILE "\n"; Flock 0; Flock "/etc/shells", ">>", 2 if !grep /^\s*\Q$SHELL[1]\E\s*$/, Cat "/etc/shells"; BackupCf "/etc/shells"; print FILE "$SHELL[1]\n"; Flock 0; Flock "/etc/fstab", "+<", 0 if !grep /^\s*[^#\s]+\s+\Q$MOUNT\E\s.*\b\Q$QSTAB\E\b/, Cat "/etc/fstab"; BackupCf "/etc/fstab"; s/^(\s*[^#\s]+\s+\Q$MOUNT\E\s+\S+\s+\S+)/$1,$QSTAB/ && ($ok = 1) for @FILE; print FILE @FILE; Flock 0; Flock "/etc/mtab", "+<", 0 if $ok && -f "/etc/mtab" && !grep /^\s*[^#\s]+\s+\Q$MOUNT\E\s.*\b\Q$QSTAB\E\b/, Cat "/etc/mtab"; s/^(\s*[^#\s]+\s+\Q$MOUNT\E\s+\S+\s+\S+)/$1,$QSTAB/ for @FILE; print FILE @FILE; Flock 0; Flock "/etc/vusers", ">>", 2 if !grep /^\s*\Q$RUSER\E\s+\Q$PROF\E\s/, Cat "/etc/vusers"; printf FILE "%-15s $PROF 0.0K 0 0\n", $RUSER; Flock 0; Flock "$RHOME/.rhosts", ">", 0 if Cat ("$RHOME/.rhosts") ne join "\n", @HOSTs, $DNSs =~ /(^|\s)(\Q$HNAM\E|\Q$HIP\E)(\s|$)/ && @DNSs, ""; print FILE "$_\n" for @HOSTs, $DNSs =~ /(^|\s)(\Q$HNAM\E|\Q$HIP\E)(\s|$)/ && @DNSs; Flock 0; print "vhost: $MOUNT file system quotacheck... " if $ok; `quotaoff $MOUNT $NERR` if $ok; `quotacheck $MOUNT $NERR` if $ok; `quotaon $MOUNT $NERR` if $ok; print "done\n\n" if $ok; Quota if $PERM; if ($ARGV[0] =~ /^.*dns$/) { $Ii = $I; $I = $natC{$I} if CheckI $natC{$I}; $Iz = ($I =~ /^(\d+\.){3}(\d+)$/)[1]; $In = join ".", reverse split /\./, ".arpa.in-addr.$I"; } if ($H && !$HLP && $ARGV[0] !~ /^(.*dns|addhost|delhost|delhali|getvalue|vdeliver)$/) { # my $loh = $LOH if $ARGV[0] =~ /^(adduser|deluser|adduali|deluali|passwd|access|lsuser)$/; my $loh = $LOH if $ARGV[0] !~ /^(addhali|qhost|lshost|cphost|uphost|hostlog|rotatelog)$/; Error5 "'$H' is an alias" if $HOST{$H} && !$QHOST{$H}; Error5 "'$H' does not exist" if !$loh && !$QHOST{$H}; Error5 "'$H' is a deleted host" if !$loh && !CheckQ ($QHOST{$H}) && $ARGV[0] !~ /^(lshost|lsuser)$/; } if ($O && !$H && $ARGV[0] =~ /^(quser|lshost|lsuser|cphost|uphost)$/) { Error5 "'$O' is not a host owner" if !@O || !$USER{$O}; } if ($ARGV[0] =~ /^(adduali|deluali)$/) { Error5 "'$H' is not virtual" if !$QHOST{$H} && $V eq "catch-all@"; } if ($ARGV[0] =~ /^(adduser|deluser)$/) { Error5 "'$U' is the host owner" if $U eq $O; Error5 "'$U' is a host owner" if $LOH && grep /^\Q$U\E$/, values %OWNR; } if ($ARGV[0] =~ /^(deluser|passwd|access|quser)$/) { Error5 "'$U".($H&&'@')."$H' is an alias" if $VALI{$U} && !($LOH && @U) && !$VPWD{$U}; Error5 "'$U".($H&&'@')."$H' does not exist" if $U && !($LOH && @U) && !$VPWD{$U}; Error5 "permission denied" if $VUSR{$U} eq "root" || $LOH && $U eq "root" || $LOH && ($USER ne "root" && $U[3] == $GHID || $U[3] == $GUID && $U[6] eq "vhost vuser") || (!$U || $U eq $O) && $O ne $USER && $USER ne "root" && ($O[3] == $GHID || grep /^\s*\Q$O\E\s.*\svroot\s*$/, @USER); } }; $X eq "addvroot" && do { ##################################################### Error5 "'$P' already exists" if !$W && -e $P; Error5 "'$P' is not a profile" if $W && -e $P && !-f "$P/V00hostconf"; Error5 "'$W' is a system user" if $W eq "root" || $W[3] == $GUID && $W[6] eq "vhost vuser"; Error5 "'$W' at '$P' already exists" if $W && grep /^\s*\Q$W\E\s+\Q$P\E\s.*\svroot\s*$/, @USER; Prompt "creating '$P'" if !-e $P; Prompt "'$W' already exists" if $W && @W; $PASS = Passwd $W if $W && !@W; $USRID = $W[2] || $USRID || !$LOCAL && $UIDSYNC && GetU; $LOCAL = 1, Rexec "vhost --addvroot $P $W $_f", "HOST", $HOSTs if !$LOCAL; my $ok; my $p = GetLn $PROF; `mkdir $VHOME/home/$W $NERR` if !@W; `ln -s $p $P $NERR` if !-e $P && !$_c; `cp -Rp $p/. $P $NERR` if !-e $P && $_c; `${\(Pw "useradd $W -c 'vhost admin' -d $VHOME/home/$W -m -k $SKEL -g $GUID $UOADD")} $NERR` if !@W; `chown $W:$GHID $VHOME/home/$W $NERR`; `chown $W:$GUID $mailDir/$W $NERR`; `chmod 0750 $VHOME/home/$W $NERR`; `chmod 0600 $mailDir/$W $NERR`; Quota::setqlim (Quota::getqcarg ($MOUNT), (getpwnam $W)[2], 0, $QHARD, 0, 0) if $W && !@W; ModShell $W, $SHELL[$ACCESS] if $W && !@W; SetPass $W, $PASS if $W && !@W; @W = getpwnam $W; $QUSER[0] = GetKb GetNb Quota::query (Quota::getqcarg ($MOUNT), $W[2]) && $QUSER[0] || "0.0K"; Flock "/etc/vusers", "+<", 0; $W && s/^(\s*\Q$W\E\s+\Q$P\E\s.*\d).*/$1 vroot/ && ($ok = 1) for @FILE; $W && ($FILE[$#FILE+1] = sprintf "%-15s $P @QUSER vroot\n", $W) if !$ok; print FILE @FILE; Flock 0; }; $X eq "delvroot" && do { ##################################################### Error5 "'$P' does not exist" if !-e $P; Error5 "'$P' is not a profile" if -e $P && !-f "$P/V00hostconf"; Error5 "'$P' is the default profile" if !$W && $P eq "/etc/vhost.d"; Error5 "'$P' has associated hosts" if !$W && grep $PROF{$_} eq $P, keys %PROF; Error5 "'$W' at '$P' does not exist" if $W && !grep /^\s*\Q$W\E\s+\Q$P\E\s.*\svroot\s*$/, @USER; Prompt "deleting all at '$P'" if !$W; Prompt "deleting '$W' at '$P'" if $W; $LOCAL = 1, Rexec "vhost --delvroot $P $W $_f", "HOST", $HOSTs if !$LOCAL; `rm -r $P $NERR` if !$W; Flock "/etc/vusers", "+<", 0; $W || s/^\s*([^#\s]+)\s+\Q$P\E\s.*//s && ($Ws .= "$1 ") for @FILE; $W && s/^(\s*\Q$W\E\s+\Q$P\E\s.*)\svroot.*/$1/ for @FILE; print FILE @FILE; Flock 0; CleanO $_ for $W || split /\s+/, $Ws; }; $X eq "adddns" && do { ####################################################### Error5 "dns zone '$Z' does not exist" if $Hz && !@zoneCf; Prompt "dns zone '$Z' already exists" if !$Hz && @zoneCf; Prompt "dns record '$H' already exists" if $Hz && grep /^\s*(\Q$Hz\E|\Q$H.\E)$DNSRE/i, @zoneCf; Prompt "reverse mapping already exists" if $_i && grep /^\s*(\Q$Iz\E|\Q$In\E)$DNSRE/i, @revZf; $CHILD = 1, Rexec "vhost --adddns $H $_z $_i $_q $_f", "HOST", $HOSTs if !$CHILD && !$LOCAL && !$LOH && $Ip eq "." && $HOSTs =~ /(^|\s)(\Q$HNAM\E|\Q$HIP\E)(\s|$)/; $LOCAL = 1, Rexec "vhost --adddns $H $Ii $_z $_i $_q $_f", "DNS", $DNSs if !$LOCAL; if (!$Hz) { AddConf $dnsCf, $dnsC; @dnsCf = Cat $dnsCf; $zoneCf = $dnsRt.GetZf $Z; my $fs = UpdateFs $zoneCf; $zoneC =~ s/\[NS_NAME\]/$HNAM/g; $zoneC =~ s/\[ZONE_NAME\]/$Z/g; $zoneC =~ s/\[IP_ADDRESS\]/$I/g; $zoneC =~ s/\[FILE_SERIAL\]/$fs/g; `touch $zoneCf $NERR`; Flock $zoneCf, "+<", 0; UpdateFs; $Ii ne $I && s/^(\s*\S+$DNSRE)\Q$Ii\E(\s*)$/$1$I$3/i for @FILE; print FILE @FILE; @FILE || print FILE $zoneC; @FILE && "@FILE" !~ /^\s*\Q$_\E/im && print FILE for grep /\s(a|cname)\s/i, split /^/m, $zoneC; Flock 0; } if ($Hz) { Flock $zoneCf, "+<", 0; UpdateFs; $Ii ne $I && s/^(\s*(\Q$Hz\E|\Q$H.\E)$DNSRE)\Q$Ii\E(\s*)$/$1$I$4/i for @FILE; print FILE @FILE; print FILE "$Hz\t\tIN\tA\t$I\n" if !grep /^\s*(\Q$Hz\E|\Q$H.\E)\s+.*\s+(a|cname)\s+\Q$I\E\s*$/i, @FILE; Flock 0; } if ($_i) { Flock $revZf, "+<", 0; UpdateFs; print FILE @FILE; print FILE "$In\t\tIN\tPTR\t$H.\n" if !grep /^\s*(\Q$Iz\E|\Q$In\E)\s+.*\s+(ptr)\s+\Q$H.\E\s*$/i, @FILE; Flock 0; } ReloadRc 0; ReloadRc $dnsRc if !$_q; }; $X eq "deldns" && do { ####################################################### Error5 "dns zone '$Z' does not exist" if !@zoneCf; if (!$Hz && !$I && grep /^\s*([^\s\@]+)$DNSRE/i && $zoneC !~ /^\s*\Q$1\E$DNSRE/im, @zoneCf) { Error5 "dns zone '$Z' contains host records"; } elsif (!$Hz && !$I) { Prompt "deleting dns zone '$Z'"; } if (!$Hz && $I && !grep /^\s*(\@|\Q$Z.\E)$DNSRE(\Q$Ii\E|\Q$I\E)\s*$/i, @zoneCf) { Error5 "dns zone '$Z->$I' does not exist"; } elsif (!$Hz && $I) { Prompt "deleting dns zone '$Z->$I'"; } if ($Hz && !$I && !grep /^\s*(\Q$Hz\E|\Q$H.\E)$DNSRE/i, @zoneCf) { Error5 "dns record '$H' does not exist"; } elsif ($Hz && !$I) { Prompt "deleting dns record '$H'"; } if ($Hz && $I && !grep /^\s*(\Q$Hz\E|\Q$H.\E)$DNSRE(\Q$Ii\E|\Q$I\E)\s*$/i, @zoneCf) { Error5 "dns record '$H->$I' does not exist"; } elsif ($Hz && $I) { Prompt "deleting dns record '$H->$I'"; } $LOCAL = 1, Rexec "vhost --deldns $H $Ii $_q $_f", "DNS", $DNSs if !$LOCAL; if (!$Hz) { Flock $zoneCf, "+<", 0; UpdateFs; $I && /^\s*(\S+)$DNSRE(\Q$Ii\E|\Q$I\E)\s*$/i && $zoneC =~ /^\s*\Q$1\E$DNSRE/im && s/.*//s for @FILE; print FILE @FILE; Flock 0; } if ($Hz) { Flock $zoneCf, "+<", 0; UpdateFs; $I || s/^\s*(\Q$Hz\E|\Q$H.\E)$DNSRE.*//is for @FILE; $I && s/^\s*(\Q$Hz\E|\Q$H.\E)$DNSRE(\Q$Ii\E|\Q$I\E)\s*$//is for @FILE; print FILE @FILE; Flock 0; } if (@revZf) { Flock $revZf, "+<", 0; UpdateFs; $I || s/^\s*[\w.]+$DNSRE\Q$H.\E\s*$//is for @FILE; $I && s/^\s*(\Q$Iz\E|\Q$In\E)$DNSRE\Q$H.\E\s*$//is for @FILE; print FILE @FILE; Flock 0; } if (!$Hz && !$I || !grep /^\s*[^\s\@]+$DNSRE/i, Cat $zoneCf) { DelConf $dnsCf, $dnsC; my $zf = (split /\//, $zoneCf)[-1]; `mv $zoneCf /tmp/.vhost/.$zf $NERR`; } ReloadRc 0; ReloadRc $dnsRc if !$_q; }; $X eq "addhost" && do { ###################################################### Error5 "'$H' already exists as an alias" if $HOST{$H} && !$QHOST{$H}; Error5 "'$H' already exists" if CheckQ ($QHOST{$H}) && (!$_f || $OWNR{$H} ne $O); Error5 "'$O' is a system user" if !$LOH && $O eq "root" || $O[3] == $GUID && $O[6] eq "vhost vuser"; Error5 "'$O' can not occupy multiple \$VHOME's" if $HOME{$USER{$O}} && $HOME{$USER{$O}} ne $VHOME; Prompt "'$O' already exists" if @O && $O ne $USER; $PASS = Passwd $O if !@O; $USRID = $O[2] || $USRID || !$LOCAL && $UIDSYNC && GetU; $LOCAL = 1, Rexec "vhost --addhost $H $O $_z $_i $_q $_f", "HOST", $HOSTs if !$LOCAL; $DNSAWARE && Ldns "vhost --adddns $_ $I $_z $_i $_q -f" for $H, GetAh $H; $DNSAWARE && $HOST{$H} && $HOST{$H} ne $I && Ldns "vhost --deldns $_ $HOST{$H} $_q -f" for $H, GetAh $H; `mv $homeDir/$O $VHOME/home $NERR`; `mkdir $VHOME/home/$O $NERR`; `mv $HOME{$PROF{$H}}/home/$OWNR{$H}/$H $VHOME/home/$O $NERR`; `mkdir $VHOME/home/$O/$H $NERR`; `cp -Rp $HOME{$PROF{$H}}/$H/. $VHOME/home/$O/$H $NERR`; `rm -r $HOME{$PROF{$H}}/$H $NERR`; `cp -Rp $VHOME/$H/. $VHOME/home/$O/$H $NERR`; `rm -r $VHOME/$H $NERR`; `ln -s home/$O/$H $VHOME/$H $NERR`; `mv $VHOME/$H/.* $VHOME/home/$O $NERR` if !$LHOME; `mv $VHOME/$H/mbox $VHOME/home/$O $NERR` if !$LHOME; `mv $VHOME/$H/[Mm]ail $VHOME/home/$O $NERR` if !$LHOME; `mkdir $VHOME/$H/home $NERR`; `mkdir $VHOME/$H/bin $NERR`; `mkdir $VHOME/$H/etc $NERR`; `mkdir $VHOME/$H/lib $NERR`; `mkdir $VHOME/$H/tmp $NERR`; `mkdir $VHOME/$H/var $NERR`; `mkdir $VHOME/$H/var/log $NERR`; `mkdir $VHOME/$H/var/mail $NERR`; `chmod 0750 $VHOME/home/$O/$H $NERR`; `chmod 1777 $VHOME/$H/tmp $NERR`; `touch $VHOME/$H/var/log/.no-rotate $NERR`; `rm -r /etc/vdata/vhostd.$H $NERR`; `ln -s $PROF /etc/vdata/vhostd.$H $NERR`; `touch /etc/vdata/vusers.$H $NERR`; `touch /etc/vdata/shadow.$H $NERR`; `touch /etc/vdata/passwd.$H $NERR`; `touch /etc/vdata/aliases.$H $NERR`; `rm -r $VHOME/$H/home/$OWNR{$H} $NERR` if $OWNR{$H}; `rm -r $VHOME/$H/home/$O $NERR`; `ln -s ../.. $VHOME/$H/home/$O $NERR`; `rm $VHOME/$H/var/mail/$OWNR{$H} $NERR`; `ln -sf $mailDir/$O $VHOME/$H/var/mail/$O $NERR`; `touch $mailDir/$O $NERR`; `${\(Pw "useradd $O -c 'vhost admin' -d $VHOME/home/$O -m -k $SKEL -g $GUID $UOADD")} $NERR` if !@O; `${\(Pw "usermod $O -d $VHOME/home/$O")} $NERR` if @O && $O[7] ne "$VHOME/home/$O" && $O ne "root"; `chown $O:$GHID $VHOME/home/$O/$H $NERR`; `chown $O:$GHID $VHOME/home/$O $NERR`; `chown $O:$GUID $mailDir/$O $NERR`; `chmod 0750 $VHOME/home/$O $NERR`; `chmod 0600 $mailDir/$O $NERR`; Quota::setqlim (Quota::getqcarg ($MOUNT), (getpwnam $O)[2], 0, $QHARD, 0, 0) if !@O; ModShell $O, $SHELL[$ACCESS] if !@O; SetPass $O, $PASS if !@O; @O = getpwnam $O; $QHOST[0] = GetKb GetNb $QHOST[0]; $QUSER[0] = GetKb GetNb Quota::query (Quota::getqcarg ($MOUNT), $O[2]) && $QUSER[0] || "0.0K"; Flock "/etc/vusers", "+>>", 2; printf FILE "%-15s $PROF @QUSER\n", $O if $O ne "root" && !grep /^\s*\Q$O\E\s+\Q$PROF\E\s/, @FILE; Flock 0; Flock "$VHOME/home/$O/.login", "+>>", 2; print FILE "set prompt=\"`uname -n`> \"\nset path=(\$path /sbin /usr/sbin)\n" if !@FILE; #print FILE "set pwd=`pwd`; set prompt=\"`basename \$pwd`> \"\nset path=(\$path /sbin /usr/sbin)\n" if !@FILE; Flock 0; Flock "$VHOME/home/$O/.profile", "+>>", 2; print FILE "PS1=\"`uname -n`> \"\nPATH=\$PATH:/sbin:/usr/sbin\n" if !@FILE; #print FILE "pwd=`pwd`; PS1=\"`basename \$pwd`> \"\nPATH=\$PATH:/sbin:/usr/sbin\n" if !@FILE; Flock 0; `chown $O[2]:$GUID $VHOME/home/$O/.login $NERR`; `chown $O[2]:$GUID $VHOME/home/$O/.profile $NERR`; if ($LOH) { `rm -r /var/spool/vmail/$H $NERR`; `ln -s $mailDir /var/spool/vmail/$H $NERR`; `ln -sf /dev/null /etc/vdata/vusers.$H $NERR`; `ln -sf $shadowCf /etc/vdata/shadow.$H $NERR`; `ln -sf $passwdCf /etc/vdata/passwd.$H $NERR`; `ln -sf $aliasesCf /etc/vdata/aliases.$H $NERR`; } else { my ($shell, $pswd); ($NEWVU || $OWNR{$H} ne $O) && $VUSR{$_} ne $OWNR{$H} && $VUSR{$_} ne $O || next, ($shell, $pswd) = (getpwnam $VUSR{$_})[8,1], `${\(Pw "userdel $VUSR{$_}")} $NERR`, `ln -sf $VHOME/$H/var/mail/$_ $mailDir/$VUSR{$_} $NERR`, `${\(Pw "useradd $VUSR{$_} -c 'vhost vuser' -d $VHOME/$H/home/$_ -m -k $SKEL -g $GUID -u $O[2] -o")} $NERR`, ModShell ($VUSR{$_}, $shell), ModPass ($VUSR{$_}, $pswd) for keys %VUSR; `rm -r /var/spool/vmail/$H $NERR`; `ln -s $VHOME/$H/var/mail /var/spool/vmail/$H $NERR`; my $days = int time / 86400; my $pswd = $PASS && Crypt $PASS; $pswd = ($O[8] eq $SHELL[0] && $SHELL[0]) . ($pswd || $O[1] || "*"); Flock "/etc/vdata/vusers.$H", "+<", 0 if $OWNR{$H} ne $O; s/^\s*\Q$O\E\s.*//s for @FILE; $FILE[0] = sprintf "%-15s %s\n", $O, $O; print FILE @FILE; Flock 0; Flock "/etc/vdata/shadow.$H", "+<", 0 if $OWNR{$H} ne $O; s/^\s*\Q$O\E:.*//s for @FILE; $FILE[0] = "$O:$pswd:$days:-1:99999:-1:-1:-1:\n"; print FILE @FILE; Flock 0; Flock "/etc/vdata/passwd.$H", "+<", 0 if $OWNR{$H} ne $O || $NEWVU || (Cat "/etc/vdata/passwd.$H")[0] !~ /^\s*\Q$O\E:[^:]*:\Q$O[2]:$GUID:vhost admin:$VHOME\/$H:$SHELL[1]\E\s*$/; s/^(\s*([^#:]+):[^:]*):[^:]*:[^:]*:([^:]*):.*/$1:$O[2]:$GUID:$3:$VHOME\/$H\/home\/$2:$SHELL[1]/, s/^\s*\Q$O\E:.*//s for @FILE; $FILE[0] = "$O:$pswd:$O[2]:$GUID:vhost admin:$VHOME/$H:$SHELL[1]\n"; print FILE @FILE; Flock 0; Flock "/etc/vdata/aliases.$H", "+<", 0 if $OWNR{$H} ne $O; s/^\s*\Q$ADMIN\E:.*//s for @FILE; print FILE "$ADMIN: $O \n"; print FILE @FILE; Flock 0; Flock "/etc/vuserz", "+<", 0 if $OWNR{$H} ne $O; s/^\s*\Q$O\E@\Q$H\E\s.*//s, s/^\s*\Q$OWNR{$H}\E(@\Q$H\E\s)/$O$1/ for @FILE; $FILE[$#FILE+1] = "$O\@$H vuser\n$ADMIN\@$H vuser\n" if !grep /^\s*\Q$O\E@\Q$H\E\s/, @FILE; print FILE @FILE; Flock 0; } Flock "/etc/vhostz", "+>>", 2; print FILE "$H\n" if !grep /^\s*\Q$H\E\s*$/, @FILE; Flock 0; }; $X eq "delhost" && do { ###################################################### Error5 "'$H' is an alias" if $HOST{$H} && !$QHOST{$H}; Error5 "'$H' does not exist" if !$QHOST{$H}; Prompt "deleting '$H'"; Forced "host data"; my $_fd = $_d if $_f; $LOCAL = 1, Rexec "vhost --delhost $H $_q $_f $_fd", "HOST", $HOSTs if !$LOCAL; $DNSAWARE && $_d && Ldns "vhost --deldns $_ $HOST{$H} $_q -f" for $H, GetAh $H; `chmod 0000 $HOME{$PROF{$H}}/home/$OWNR{$H}/$H $NERR`; `rm /etc/vdata/vusers.$H $NERR` if -c "/etc/vdata/vusers.$H"; `rm /etc/vdata/shadow.$H $NERR` if -l "/etc/vdata/shadow.$H"; `rm /etc/vdata/passwd.$H $NERR` if -l "/etc/vdata/passwd.$H"; `rm /etc/vdata/aliases.$H $NERR` if -l "/etc/vdata/aliases.$H"; my ($ok, @v); Flock "/etc/vhosts", "+<", 0; $ok = $ok || /^\s*# \Q$H\E $SIGN/, $ok && /^\s*$FOOT/ && last, $ok && s/^(\s*[^#\s]+\s+\Q$H\E)\s.*/$1 -d\n/s for @FILE; print FILE @FILE; Flock 0; if ($_d) { $VUSR{$_} ne $O && $VUSR[0] !~ /^\s*\Q$_\E\s/ || next, `rm -r $homeDir/$VUSR{$_} $NERR`, `rm $mailDir/$VUSR{$_} $NERR`, `${\(Pw "userdel $VUSR{$_}")} $NERR` for keys %VUSR; $v[3] == $GUID && $v[7] =~ /^\Q$HOME{$PROF{$H}}\E\/\Q$H\E\/home\/./ && ( `rm -r $homeDir/$v[0] $NERR`, `rm $mailDir/$v[0] $NERR`, `${\(Pw "userdel $v[0]")} $NERR` ) while @v = getpwent; } Flock "/etc/vuserz", "+<", 0 if $_d; Flock 0; Flock "/etc/vhostz", "+<", 0 if $_d; Flock 0; }; $X eq "addhali" && do { ###################################################### Error5 "'$A' already exists" if $HOST{$A} && !$QHOST{$A}; Error5 "'$A' already exists as a host" if $QHOST{$A}; $LOCAL = 1, Rexec "vhost --addhali $H $A $_q", "HOST", $HOSTs if !$LOCAL; $DNSAWARE && Ldns "vhost --adddns $_ $HOST{$H} $_z $_q -f" for $A; my $ok; Flock "/etc/vhosts", "+<", 0; $ok = $ok || /^\s*# \Q$H\E $SIGN/, $ok && s/^(\s*$FOOT)/$HOST{$H}\t$A\n$1/ && last for @FILE; print FILE @FILE; Flock 0; Flock "/etc/vhostz", "+>>", 2; print FILE "$A $H\n\@$A \@$H\n" if !grep /^\s*\Q$A\E\s+\Q$H\E\s*$/, @FILE; Flock 0; }; $X eq "delhali" && do { ###################################################### Error5 "'$A' does not exist" if !$HOST{$A}; Error5 "'$A' is a host" if $QHOST{$A}; $LOCAL = 1, Rexec "vhost --delhali $A $_q", "HOST", $HOSTs if !$LOCAL; $DNSAWARE && Ldns "vhost --deldns $_ $HOST{$H} $_q -f" for $A; my $ok; Flock "/etc/vhosts", "+<", 0; $ok = $ok || /^\s*# \Q$H\E $SIGN/, $ok && /^\s*$FOOT/ && last, $ok && s/^\s*[^#\s]+\s+\Q$A\E\s*$//s for @FILE; print FILE @FILE; Flock 0; Flock "/etc/vhostz", "+<", 0; Flock 0; }; $X eq "adduser" && do { ###################################################### Error5 "'root' can not be the host owner" if !$LOH && $O eq "root"; Error5 "'$U".($H&&'@')."$H' already exists" if ($LOH && @U || $VPWD{$U}) && !$_f; Error "warning - '$U".($H&&'@')."$H' already exists as an alias", 1 if $VALI{$U} && !($LOH && @U || $VPWD{$U}); $PASS = Passwd $U.($H&&'@').$H; if (!$LOH) { my $vusr = substr "$U.$H", 0, $unameLen; $vusr =~ s/\./$dotChar/g; $vusr = $VUSR{$U} || $vusr; print "vhost: alternative login [$vusr]: "; chomp ($VUSR = $_f? "" : substr , 0, $unameLen), $VUSR =~ s/\./$dotChar/g; print "$VUSR\n" if $_f || !-t; $RECHO .= "$VUSR\n" if !$_f; $VUSR = $VUSR || $vusr; $ERR = !CheckU $VUSR, 1; $ERR && Exit 5; Error5 "alternative login too short ($minLogin characters minimum)" if length $VUSR < $minLogin; Error5 "'$VUSR' already exists" if (getpwnam $VUSR)[0] && !$VPWD{$U}; } my $n = $N; s/([\\\$"`])/\\\\\\$1/g, s/(.+)/"\\"$1\\""/ for $n; $LOCAL = 1, Rexec "vhost --adduser $H $U $n $_f", "HOST", $HOSTs if !$LOCAL; my $n = $N; s/:/;/g for $N; s/:/;/g, s/([\\\$"`])/\\$1/g for $n; if ($LOH) { `mkdir $homeDir/$U $NERR`; `chmod 0750 $homeDir/$U $NERR`; `rm -r $VHOME/$H/home/$U $NERR`; `ln -s $homeDir/$U $VHOME/$H/home/$U $NERR`; `ln -sf $mailDir/$U $VHOME/$H/var/mail/$U $NERR`; `touch $mailDir/$U $NERR`; `${\(Pw "useradd $U -c \"$n\" -d $homeDir/$U -m -k $SKEL -s $SHELL[1]")} $NERR`; SetPass $U, $PASS; @U = getpwnam $U; } else { `mkdir $VHOME/$H/home/$U $NERR`; `chmod 0755 $VHOME/$H/home/$U $NERR`; `ln -sf $VHOME/$H/var/mail/$U $mailDir/$VUSR $NERR`; `touch $VHOME/$H/var/mail/$U $NERR`; `${\(Pw "useradd $VUSR -c 'vhost vuser' -d $VHOME/$H/home/$U -m -k $SKEL -g $GUID -s $SHELL[1] -u $O[2] -o")} $NERR`; SetPass $VUSR, $PASS; my $days = int time / 86400; my $pswd = $PASS && Crypt $PASS; $pswd = $pswd || "*"; Flock "/etc/vdata/vusers.$H", "+>>", 2; printf FILE "%-15s %s\n", $U, $VUSR if !grep /^\s*\Q$U\E\s/, @FILE; Flock 0; Flock "/etc/vdata/shadow.$H", "+>>", 2; print FILE "$U:$pswd:$days:-1:99999:-1:-1:-1:\n" if !grep /^\s*\Q$U\E:/, @FILE; Flock 0; Flock "/etc/vdata/passwd.$H", "+>>", 2; print FILE "$U:$pswd:$O[2]:$GUID:$N:$VHOME/$H/home/$U:$SHELL[1]\n" if !grep /^\s*\Q$U\E:/, @FILE; Flock 0; } Flock "/etc/vuserz", "+>>", 2; print FILE "$U\@$H vuser\n" if !grep /^\s*\Q$U\E@\Q$H\E\s/, @FILE; Flock 0; }; $X eq "deluser" && do { ###################################################### Prompt "deleting '$U".($H&&'@')."$H'"; Forced "user data"; my $_fd = $_d if $_f; $LOCAL = 1, Rexec "vhost --deluser $H $U $_f $_fd", "HOST", $HOSTs if !$LOCAL; if ($LOH) { `chmod 0000 $homeDir/$U $NERR`; `rm -r $homeDir/$U $NERR` if $_d && $UTEMP ne "$homeDir/$U"; `rm $mailDir/$U $NERR` if $_d; `rm -r $VHOME/$H/home/$U $NERR`; `rm $VHOME/$H/var/mail/$U $NERR`; `${\(Pw "userdel $U")} $NERR`; my $ok; Flock "/etc/vusers", "+<", 0; s/^\s*\Q$U\E\s.*//s && ($ok = 1) for @FILE; print FILE @FILE if $ok; Flock 0; } else { `chmod 0000 $VHOME/$H/home/$U $NERR`; `rm -r $VHOME/$H/home/$U $NERR` if $_d && $UTEMP ne "$VHOME/$H/home/$U"; `rm $VHOME/$H/var/mail/$U $NERR` if $_d; `rm -r $homeDir/$VUSR{$U} $NERR`; `rm $mailDir/$VUSR{$U} $NERR`; `${\(Pw "userdel $VUSR{$U}")} $NERR`; Flock "/etc/vdata/vusers.$H", "+<", 0; s/^\s*\Q$U\E\s.*//s for @FILE; print FILE @FILE; Flock 0; Flock "/etc/vdata/shadow.$H", "+<", 0; s/^\s*\Q$U\E:.*//s for @FILE; print FILE @FILE; Flock 0; Flock "/etc/vdata/passwd.$H", "+<", 0; s/^\s*\Q$U\E:.*//s for @FILE; print FILE @FILE; Flock 0; } Flock "/etc/vuserz", "+<", 0; Flock 0; }; $X eq "adduali" && do { ###################################################### Error "warning - '$V".($H&&'@')."$H' already exists as a user", 1 if ($LOH && @V || $VPWD{$V}) && !$VALI{$V}; my @n = @N; s/([\\\$"`])/\\\\\\$1/g, s/(.+)/"\\"$1\\""/ for @n; $LOCAL = 1, Rexec "vhost --adduali $H $V @n", "HOST", $HOSTs if !$LOCAL; s/,/./g, s/\s+/ /g, s/^\s*(\|.*\S)\s*$/"$1"/ for @N; my $ok; my $vali = $VALI{$V} || "$N[0] "; $vali =~ s/\s+/ /g; $vali !~ /(^|,)\s*\Q$_\E\s*(,|$)/ && ($vali .= ",$_ ") for @N; $vali =~ s/^[\s,]*//; $vali = $N[0] if $V eq "catch-all@"; Flock $aliasesCf, "+<", 0; $FILE[-$_] =~ s/^(\s*,.*)//s && ($FILE[-$_-1] .= $1), $FILE[-$_] =~ s/^(\s*\Q$V\E:).*/$1 $vali\n/s && ($ok = 1) for 1..$#FILE+1; $FILE[$#FILE+1] = "$V: $vali\n" if !$ok; print FILE @FILE; Flock 0; Flock "/etc/vuserz", "+>>", 2; print FILE "$V\@$H vuser\n" if !grep /^\s*\Q$V\E@\Q$H\E\s/, @FILE; Flock 0; }; $X eq "deluali" && do { ###################################################### my @n = @N; s/([\\\$"`])/\\\\\\$1/g, s/(.+)/"\\"$1\\""/ for @n; $LOCAL = 1, Rexec "vhost --deluali $H $V @n", "HOST", $HOSTs if !$LOCAL; s/,/./g, s/\s+/ /g, s/^\s*(\|.*\S)\s*$/"$1"/ for @N; my $vali = $VALI{$V} if @N; $vali =~ s/\s+/ /g; $vali =~ s/(^|,)\s*\Q$_\E\s*(,|$)/$2/ for @N; $vali =~ s/^[\s,]*//; Flock $aliasesCf, "+<", 0; $FILE[-$_] =~ s/^(\s*,.*)//s && ($FILE[-$_-1] .= $1), $FILE[-$_] =~ s/^(\s*\Q$V\E:).*/$1 $vali\n/s && !$vali && ($FILE[-$_] = "") for 1..$#FILE+1; print FILE @FILE; Flock 0; Flock "/etc/vuserz", "+<", 0; Flock 0; }; $X eq "passwd" && do { ####################################################### $PASS = $M || Passwd $U.($H&&'@').$H; my $m = $M; s/([\\\$"`])/\\\\\\$1/g, s/(.+)/"\\"$1\\""/ for $m; $LOCAL = 1, Rexec "vhost --passwd $H $U $m", "HOST", $HOSTs if !$LOCAL; my $pswd = $PASS && Crypt $PASS; for my $u ($pswd && $U) { for ($u ne $O && !$LOH && $u && $H || grep !-c "/etc/vdata/vusers.$_" && $OWNR{$_} eq $u, keys %PROF) { Flock "/etc/vdata/shadow.$_", "+<", 0; s/^(\s*\Q$u\E:!*(\Q$SHELL[0]\E)*)[^:]*(:.*)/$1$pswd$3/ for @FILE; print FILE @FILE; Flock 0; Flock "/etc/vdata/passwd.$_", "+<", 0; s/^(\s*\Q$u\E:!*(\Q$SHELL[0]\E)*)[^:]*(:.*)/$1$pswd$3/ for @FILE; print FILE @FILE; Flock 0; } my $v = !$LOH? $VUSR{$u} : $u; SetPass $v, $PASS; } }; $X eq "access" && do { ####################################################### Error5 "'$U' is yourself" if $U eq $O && $O eq $USER; $LOCAL = 1, Rexec "vhost --access $H $U $S", "HOST", $HOSTs if !$LOCAL; my $pswd = $SHELL[0] if !$S; for my $u ($U || !$LOH && grep $_ ne $O, keys %VPWD) { for ($u ne $O && !$LOH && $u && $H || grep !-c "/etc/vdata/vusers.$_" && $OWNR{$_} eq $u, keys %PROF) { Flock "/etc/vdata/shadow.$_", "+<", 0; s/^(\s*\Q$u\E:)!*(\Q$SHELL[0]\E)*(.*)/$1$pswd$3/ for @FILE; print FILE @FILE; Flock 0; Flock "/etc/vdata/passwd.$_", "+<", 0; s/^(\s*\Q$u\E:)!*(\Q$SHELL[0]\E)*(.*)/$1$pswd$3/ for @FILE; print FILE @FILE; Flock 0; } my $s = $u eq $O || $LOH? $S : !$S? $S : 1; my $v = !$LOH? $VUSR{$u} : $u; ModShell $v, $SHELL[$s]; } }; $X eq "qhost" && do { ######################################################## $LOCAL = 1, Rexec "vhost --qhost $H $Q", "HOST", $HOSTs if !$LOCAL; $Q[0] = GetKb GetNb $Q[0]; Flock "/etc/vhosts", "+<", 0; s/^(\s*[^#\s]+\s+\Q$H\E)\s.*/$1 @Q\n/s for @FILE; print FILE @FILE; Flock 0; }; $X eq "quser" && do { ######################################################## my @qu = Quota::query (Quota::getqcarg ($MOUNT), $O[2]); Error5 "disk quota not enabled on file system '$MOUNT'" if GetNb ($Q[0]) && !@qu; $LOCAL = 1, Rexec "vhost --quser $O $Q", "HOST", $HOSTs if !$LOCAL; $Q[0] = GetKb GetNb $Q[0]; Quota::setqlim (Quota::getqcarg ($MOUNT), $O[2], 0, sprintf ("%.0f", GetNb ($Q[0]) / $blockSize), $qu[5], $qu[6]); Flock "/etc/vusers", "+<", 0; s/^(\s*\Q$O\E\s+\S+)\s.*\d(.*)/$1 @Q$2/ for @FILE; print FILE @FILE; Flock 0; }; $X eq "lshost" && do { ####################################################### my ($h, $hl, $al, $hsort, $asort, $hnum, $anum, $hcmp, $acmp, $hmya, $amya, $hmyb, $amyb, @q, @hl, @al, @date, %du, %dv); `rm /tmp/.vhost/.duh $NERR` if !$H && $USER eq "root" && $_f; /^\s*([^#\s]+)\s+(\S+)\s+(\S+)/ && ($du{$3} = $1, $dv{$3} = $2) for $DUCACHE && Cat "/tmp/.vhost/.duh"; $hnum = (9, 0, 1, 2, 3, 4, 5, 6, 7, 9, 9, 10, 11, 12)[$_n<13?$_n:13]; $anum = (0, 0, 1, 2, 3, 4, 5, 6, 7, 9, 1, 10, 11, 12)[$_n<13?$_n:13]; $hmya = "(split /[\\/\\s]+/, \$a, 12)[$hnum]", $hmyb = "(split /[\\/\\s]+/, \$b, 12)[$hnum]"; $amya = "(split /[\\/\\s]+/, \$a, 2)[$anum]", $amyb = "(split /[\\/\\s]+/, \$b, 2)[$anum]"; $hmya = "GetDt (\$DATE{$hmya})", $hmyb = "GetDt (\$DATE{$hmyb})" if $_n =~ /^[9]$/; $hmya = "GetNb ($hmya)", $hmyb = "GetNb ($hmyb)" if $_n =~ /^[34]$/; $hcmp = $_n =~ /^[3456789]$/? "<=>" : "cmp"; $acmp = "cmp"; $hsort = ($_r && "reverse ") . "sort {$hmya $hcmp $hmyb} " if "$_s$_r$_n"; $asort = ($_r && "reverse ") . "sort {$amya $acmp $amyb} " if "$_s$_r$_n" && $anum < 2; for (@HOST) { /^\s*$HEAD|^\s*$FOOT|^\s*# (\S+) $SIGN\s+(.*)|^\s*[^#\s]+\s+(\S+)/ && !$3 && ($h = $1, @date = split /\s+/, $2); next if !$h || !$3 || $H && $h ne $H || !$H && !$_a && !CheckQ ($QHOST{$h}) || $O && !AllowO ($OWNR{$h}, $O, $PROF{$h}) || $USER ne "root" && !AllowO $OWNR{$h}, $USER, $PROF{$h}; @q = split /\s+/, $QHOST{$h}; (!$du{$h} || !$dv{$h} || $_f) && ( $du{$h} = GetKb ("$HOME{$PROF{$h}}/$h/."), $dv{$h} = GetKb (-c "/etc/vdata/vusers.$h"? "$homeDir $mailDir" : "$HOME{$PROF{$h}}/$h/home $HOME{$PROF{$h}}/$h/var/mail"), $DUCACHE && `echo "$du{$h} $dv{$h}\t$h" $NERR >> /tmp/.vhost/.duh`), $hl[$hl++] = sprintf "%-13s %1s %4s %4s %2s/%02d %2s/%02d %3s-%02d-%02d " . ($_l? "%-31s %-15s %-s\n" : "%-s\n"), ($H? $OWNR{$h} : substr $OWNR{$h}, 0, 13) || "----", GetSh ($OWNR{$h}), $du{$h}, $dv{$h}, -c "/etc/vdata/vusers.$h"? "*" : scalar grep (/^\s*[^#:]+:/, Cat "/etc/vdata/passwd.$h"), $q[1], -c "/etc/vdata/vusers.$h"? "*" : scalar grep (/^\s*[^#:]+:/, Cat "/etc/vdata/aliases.$h"), $q[2], $date[1], $date[2], substr ($date[5], -2), $h . (!CheckQ ($QHOST{$h}) && "-"), $HOST{$h}, $PROF{$h} if $h eq $3; $al[$al++] = sprintf "%-47s %-s\n", $h, $3 . (!CheckQ ($QHOST{$h}) && "-") if $h ne $3; } eval "\@HLIST = $hsort \@hl;"; eval "\@ALIST = $asort \@al;"; }; $X eq "lsuser" && do { ####################################################### my ($u, $ul, $vl, $usort, $vsort, $unum, $vnum, $ucmp, $vcmp, $umya, $vmya, $umyb, $vmyb, $vali, $vcall, @u, @q, @ul, @vl, @qu); @qu = $H && Quota::query (Quota::getqcarg ($VHOME), $O[2]); $unum = (0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)[$_n<11?$_n:11]; $vnum = (0, 0, 1, 2, 3, 4, 1, 6, 7, 8, 9, 10)[$_n<11?$_n:11]; $umya = "(split /[\\/\\s]+/, \$a, 10)[$unum]", $umyb = "(split /[\\/\\s]+/, \$b, 10)[$unum]"; $vmya = "(split /[\\/\\s]+/, \$a, 2)[$vnum]", $vmyb = "(split /[\\/\\s]+/, \$b, 2)[$vnum]"; $umya = "GetNb ($umya)", $umyb = "GetNb ($umyb)" if $_n =~ /^[34]$/; $ucmp = $H && $_n =~ /^[34]$/ || !$H && $_n =~ /^[345678]$/? "<=>" : "cmp"; $vcmp = "cmp"; $usort = ($_r && "reverse ") . "sort {$umya $ucmp $umyb} " if "$_s$_r$_n"; $vsort = ($_r && "reverse ") . "sort {$vmya $vcmp $vmyb} " if "$_s$_r$_n" && $vnum < 2; $vcall = <<'#' if $vnum != 1; my $i; /^(catch-all\@\s.*)/s && splice (@VLIST, $i, 1) && ($_r && $vnum < 2 && ($VLIST[$#VLIST+1] = $1) || unshift (@VLIST, $1)) && last, $i++ for @VLIST; # for (!$H && @USER) { /^\s*([^#\s]+)\s+(\S+)\s.*\d\s*(\svroot)?\s*$/ && (@u = getpwnam $1, $u = $1) || next; next if $O && !AllowO ($u, $O, $2) || $USER ne "root" && !AllowO $u, $USER, $2; @q = split /\s+/, $QUSER{$u}; @qu = @u && Quota::query (Quota::getqcarg ($HOME{$2}), $u[2]); $ul[$ul++] = sprintf "%-13s %1s %4s/%4s %2s/%02d %2s/%02d %5s %-s\n", $O? $u : substr ($u, 0, 13), GetSh ($u), GetKb ($qu[0] * $blockSize || "$HOME{$2}/home/$u"), GetKb ($qu[2] * $blockSize), scalar grep ($OWNR{$_} eq $u, keys %PROF), $q[1], GetAc ($u), $q[2], $3 && "vroot" || " - ", $2; } for ($H && @VPWD) { /^\s*([^#:]+):([^:]*:){3}([^:]*):/ && (@u = getpwnam $1, $u = $1) || next; next if $LOH && !@u || $LOH && $u[3] == $GUID && $u[6] eq "vhost vuser"; $ul[$ul++] = sprintf "%-58s %-s\n", $LOH? (sprintf ("%-13s %1s %4s %4s %-s", $u, GetSh ($u), $u[7] eq "$homeDir/$u"? GetKb $u[7] : "----", GetKb ("$mailDir/$u"), "----"), $u[6]) : (sprintf ("%-13s %1s %4s %4s %-s", $u, GetSh ($u, $u ne $O), GetKb ("$VHOME/$H/home/$u"), GetKb ($u ne $O? "$VHOME/$H/var/mail/$u" : "$mailDir/$u"), $VUSR{$u} || "----"), $3); } for ($H && @VALI) { /^\s*([^#:]+):/ && ($u = $1) || next; chomp ($vali = $VALI{$u}); $vali =~ s/\s*,\s*/ /g; $vl[$vl++] = sprintf "%-13s %-s\n", $u, $vali; } eval "\@ULIST = $usort \@ul;"; eval "\@VLIST = $vsort \@vl; $vcall \@VLIST;" if $H; }; $X eq "cphost" && do { ####################################################### my ($h, $v, $shell, $pswd, $prof, $env, $del, $out, $dir, %dir); Error5 "'$H' is the main host" if $LOH; Prompt "copying '$H' to $R" if $H; Prompt "copying $O\'s hosts to $R" if !$H && $O; Prompt "copying all hosts to $R" if !$H && !$O; Forced "obsolete data at destination"; $del = "--delete " if $_d; print "vhost: root\@${R}'s password: "; `stty -echo $NERR`; chomp ($PASS = $_f? "" : ); `stty echo $NERR`; print "\n"; $out = Rssh "ssh root\@$R vhost --version", $PASS; Error5 "unable to run vhost 3.30 or higher on $R" if !$_q && ($out !~ /^vHost (\d\.\d\d)r/m || $1 < 3.30); $out = Rssh "ssh root\@$R rsync --version", $PASS; Error5 "unable to run rsync on $R" if !$_q && $out !~ /^rsync\s/m; for (@HOST) { /^\s*$HEAD|^\s*$FOOT|^\s*# (\S+) $SIGN\s+(.*)|^\s*[^#\s]+\s+(\S+)/ && !$3 && ($h = $1); next if !$h || !$3 || $H && $h ne $H || !CheckQ ($QHOST{$h}) || -c "/etc/vdata/vusers.$h" || $O && !AllowO ($OWNR{$h}, $O, $PROF{$h}) || $USER ne "root" && !AllowO $OWNR{$h}, $USER, $PROF{$h}; if ($h eq $3) { print "[$h]\n"; $env .= "VHOST_DEBUG=$DEBUG "; $env .= "VHOST_LOCAL=1 "; $env .= "VHOST_NEWVU=1 "; $env .= "VHOST_USRID=".(getpwnam $OWNR{$h})." "; $env .= "VHOST_VDATE=\"\\\"$DATE{$h}\\\"\" "; $env .= "VHOST_QHOST=\"\\\"$QHOST{$h}\\\"\" "; $env .= "VHOST_QUSER=\"\\\"$QUSER{$OWNR{$h}}\\\"\" "; for (0..1) { $prof = !$_? GetLn $PROF{$h} : $PROF{$h}; $dir = (`dirname $prof $NERR` =~ /(.*)/)[0]; Rssh "rsync -e ssh -aq $prof root\@$R:$dir", $PASS if !$dir{$prof}++ && Rssh ("ssh root\@$R test ! -e $prof '&&' mkdir -p $dir '&&' echo $prof", $PASS) =~ /^\Q$prof\E\s*$/m; } if (!$dir{"$prof/$OWNR{$h}"}++) { Rssh "ssh root\@$R vhost --addvroot $prof $OWNR{$h} -f", $PASS, $prof, $env if grep /^\s*\Q$OWNR{$h}\E\s+\Q$prof\E\s.*\svroot\s*$/, @USER; } if (!$dir{"$HOME{$prof}/home/$OWNR{$h}"}++) { $out = "/tmp/.vhost/.out.$$"; Flock $out, ">", 0; chomp, $QHOST{$_} && print FILE "/$OWNR{$h}/$_/\n" for `ls $HOME{$prof}/home/$OWNR{$h}/ $NERR`; Flock 0; Rssh "ssh root\@$R mkdir -p $HOME{$prof}/home/$OWNR{$h}", $PASS; Rssh "rsync -e ssh -aq $del--exclude-from=$out $HOME{$prof}/home/$OWNR{$h} root\@$R:$HOME{$prof}/home", $PASS; Rssh "rsync -e ssh -aq /var/spool/mail/$OWNR{$h} root\@$R:/var/spool/mail", $PASS if -e "/var/spool/mail/$OWNR{$h}"; `rm $out $NERR`; } Rssh "rsync -e ssh -aq $del$HOME{$prof}/home/$OWNR{$h}/$h root\@$R:$HOME{$prof}/home/$OWNR{$h}", $PASS; Rssh "rsync -e ssh -aq --exclude=*.*.$h /etc/vdata/*.$h root\@$R:/etc/vdata", $PASS; Rssh "ssh root\@$R vhost --addhost $h $OWNR{$h} -q -f", $PASS, $prof, $env; $out = Rssh ("ssh root\@$R vhost --lshost $h", $PASS) =~ /^vhost: error -/m; Rssh "ssh root\@$R vhost --adduali $h catch-all\@ $1", $PASS, $prof, $env if !$out && Cat ("/etc/vdata/aliases.$h") =~ /^\s*catch-all\@:\s+([^\s,]+)/m; /^\s*[^#\s]+\s+(\S+)/ && ($v = $1, ($shell, $pswd) = (getpwnam $1)[8,1]) || next, $pswd =~ s/([\\\$"`])/\\\\\\$1/g, Rssh "ssh root\@$R vhost --modpass $v $shell \"\\\"$pswd\\\"\"", $PASS, $prof, $env for !$out && Cat "/etc/vdata/vusers.$h"; } else { Rssh "ssh root\@$R vhost --addhali $h $3 -q", $PASS, $prof, $env; } } }; $X eq "uphost" && do { ####################################################### Prompt "updating '$H'" if $H; Prompt "updating $O\'s hosts" if !$H && $O; Prompt "updating all hosts" if !$H && !$O; $_i = undef if !$INSTALL; $ENV{VHOST_USERNAME} = $USER; $ENV{VHOST_DEBUG} = $DEBUG; $ENV{VHOST_LOCAL} = 1 if $_i; $ENV{VHOST_NEWVU} = $NEWVU; $ENV{VHOST_NEWIP} = 1; for my $h ($H || @H) { next if !$h || $H && $h ne $H || !CheckQ ($QHOST{$h}) || $_i && -l "$HOME{$PROF{$h}}/$h" || $O && !AllowO ($OWNR{$h}, $O, $PROF{$h}) || $USER ne "root" && !AllowO $OWNR{$h}, $USER, $PROF{$h}; print "[$h]\n"; if (-e "$HOME{$PROF{$h}}/$h/.no-update") { print "'/.no-update' exists. skipping...\n"; } else { print "vhost --addhost $h $OWNR{$h} -q -f\n"; $< = $RID; system "/usr/sbin/vhost --addhost $h $OWNR{$h} -q -f 2>&1"; $< = 0; } } print "[reload]\n" if !$_q; print "vhost --reload\n" if !$_q; $< = $RID; system "/usr/sbin/vhost --reload -p $PROF 2>&1" if !$_q; $< = 0; }; $X eq "hostlog" && do { ###################################################### my $l; my $log = (split /\s+/, `ls $VHOME/$H/var/log/ $NERR`)[0]; print STDERR `ls -l $VHOME/$H/var/log/ $NERR`, "log [$log]: " if !$_q; print STDOUT `ls -l $VHOME/$H/var/log/ $NERR`, "log [$log]: " if $_q; chomp ($l = $_q || $L? $L : ); print STDERR "$l\n" if !$_q && !-t || $L; print STDOUT "$l\n" if $_q; $l = $l || $log; Error5 "'$VHOME/$H/var/log/$l' is not a log file" if !$_q && !-f "$VHOME/$H/var/log/$l"; system $l =~ /\.gz$/? "gunzip -c $VHOME/$H/var/log/$l $NERR | $PAGER" : "$PAGER $VHOME/$H/var/log/$l" if !$_q; }; $X eq "cmdlog" && do { ####################################################### my $l; my $g = $G || $CMDLOG; Error5 "'$g' is not a log file" if !-f $g; for ($g =~ /\.gz$/? `gunzip -c $g $NERR` : Cat $g) { / vhost\[\d+:\d+\]: \(([^(\@,)]+)([\@,]?)([^(\@,)]*)\) --/ || next; next if !$HOST && $USER ne "root" && !AllowO ($2 eq '@'? $OWNR{$3} : $1) || $HOST && ($3 ne $HOST || $1 ne $USER); $l .= $_; } Flock "/tmp/.vhost/.out.$$", ">", 0; print FILE $l; Flock 0; system "(cat /tmp/.vhost/.out.$$; rm /tmp/.vhost/.out.$$) $NERR | $PAGER"; }; $X eq "reload" && do { ####################################################### exit 0 if $_n && fork; sleep $_n if $_n; print "\n" if $_n; $LOCAL = 1, Rexec "vhost --reload $_f", "###", "$DNSs ".($HOSTs || $HIP) if !$LOCAL && !$_l; ReloadRc 0 if $_f && $USER eq "root"; ReloadRc $dnsRc if !$RDNS; ReloadRc 0 if $_f && $USER eq "root"; }; $X eq "rotatelog" && do { #################################################### my $ext0 = ".gz" if !$_z; my $ext1 = ".gz" if $_z; my $gzip = $_z? "gzip" : "gunzip"; for my $h ($H || grep CheckQ ($QHOST{$_}), @H) { my $d = "$HOME{$PROF{$h}}/$h/var/log"; for my $f (grep Cat ("$d/.no-rotate") !~ /^\s*\Q$_\E\s*$/m && !/\.\d+(\.gz)?$/ && -f "$d/$_", split /\s+/, `ls $d/ $NERR`) { my ($i, $j); $i = -$_, `$gzip -f $d/$f.$i$ext0 $NERR` for -$_n..-1; $i = -$_, $j = -$_-1, `cp -p $d/$f.$j$ext1 $d/$f.$i$ext1 $NERR` for -$_n..-2; `cp -p $d/$f $d/$f.1 $NERR` if $_n; `$gzip -f $d/$f.1 $NERR` if $_n; Flock "$d/$f", ">", 0; Flock 0; } } }; $X eq "getvalue" && do { ##################################################### print "$_\n" for eval $Y; }; $X eq "getdns" && do { ####################################################### print eval $Y; }; $X eq "modpass" && do { ###################################################### ModShell $V, $S; ModPass $V, $M; }; $X eq "netpulse" && do { ##################################################### print STDERR $VERSION, "\n"; Print "--netpulse to be implemented in the next release"; }; $X eq "uninstall" && do { #################################################### my $version = (split /\s+/, $VERSION)[1]; Prompt "uninstalling vhost $version"; `rm /usr/sbin/vhost $NERR`; `rm -r /usr/local/vhost $NERR`; `rm -r /tmp/.vhost $NERR`; my $i; Flock "$cronDir/root", "+<", 0 if grep /^\s*$FOOT/, Cat "$cronDir/root"; s/^\s*$FOOT.*//s && $i && $FILE[$i-1] =~ s/^\s*$//s, s/^[^#]*\/usr\/sbin\/vhost\s.*//s, $i++ for @FILE; print FILE @FILE; `touch $cronDir $NERR` if -f FILE; Flock 0; }; $X eq "finalization" && do { ################################################# if ($ARGV[0] eq "delhost" && $_d) { `rm -r $HOME{$PROF{$H}}/$H $NERR` if $HTEMP ne "$HOME{$PROF{$H}}/$H"; `rm -r $HOME{$PROF{$H}}/home/$OWNR{$H}/$H $NERR` if $HTEMP ne "$HOME{$PROF{$H}}/home/$OWNR{$H}/$H"; `rm -r /var/spool/vmail/$H $NERR`; `rm -r /etc/vdata/vhostd.$H $NERR`; `rm /etc/vdata/vusers.$H $NERR`; `rm /etc/vdata/shadow.$H $NERR`; `rm /etc/vdata/passwd.$H $NERR`; `rm /etc/vdata/aliases.$H $NERR`; DelConf "/etc/vhosts", "$HOST{$H}\t$H @QHOST\n"; CleanO $O; } if ($ARGV[0] eq "addhost") { `cp -Rp $HTEMP/. $VHOME/home/$O/$H $NERR` if -d $HTEMP; `chown -h $O[2]:$GHID $VHOME/$H $NERR`; `chown -Rh $O[2]:$GUID $VHOME/home/$O/$H $NERR`; `chown $O[2]:$GHID $VHOME/home/$O/$H $NERR`; `chown 0:$GUID $VHOME/$H/var $NERR`; `chown 0:$GUID $VHOME/$H/var/log $NERR`; `chmod 0750 $VHOME/home/$O/$H $NERR`; `chmod 1777 $VHOME/$H/tmp $NERR`; `touch $VHOME/home/$O/$H $NERR`; -l "$VHOME/$H/home/$_" && `chown -h $_:$GUID $VHOME/$H/home/$_ $NERR`, -l "$VHOME/$H/var/mail/$_" && `chown -h $_:$GUID $VHOME/$H/var/mail/$_ $NERR` for split /\s+/, `ls $VHOME/$H/var/mail/ $NERR`; `restorecon -R $VHOME/home/$O/$H $NERR`; `restorecon $VHOME/home/$O $NERR`; AddConf "/etc/vhosts", "$I\t$H @QHOST\n", '^\s*[^#\s]+\s+'.$H.'\s.*$'; CleanO $OWNR{$H} if $OWNR{$H} ne $O; } if ($ARGV[0] eq "adduser") { `cp -Rp $UTEMP/. $VHOME/$H/home/$U $NERR` if -d $UTEMP; `chown -h $U[2]:$GUID $VHOME/$H/home/$U $NERR` if $LOH; `chown -h $U[2]:$GUID $VHOME/$H/var/mail/$U $NERR` if $LOH; `chown -Rh $U[2]:$U[3] $homeDir/$U $NERR` if $LOH; `chown $U[2]:$GHID $homeDir/$U $NERR` if $LOH; `chown $U[2]:$GUID $mailDir/$U $NERR` if $LOH; `chmod 0750 $homeDir/$U $NERR` if $LOH; `chmod 0600 $mailDir/$U $NERR` if $LOH; `touch $homeDir/$U $NERR` if $LOH; `chown -Rh $O[2]:$GUID $VHOME/$H/home/$U $NERR` if !$LOH; `chown $O[2]:$GUID $VHOME/$H/var/mail/$U $NERR` if !$LOH; `chmod 0755 $VHOME/$H/home/$U $NERR` if !$LOH; `chmod 0600 $VHOME/$H/var/mail/$U $NERR` if !$LOH; `touch $VHOME/$H/home/$U $NERR` if !$LOH; } if ($ARGV[0] eq "lshost") { printf "# OWNER S USED USER #U/QU #A/QA MON-DT-YR HOST - host total %d\n", $#HLIST+1; print @HLIST; printf "# - host alias total %d\n", $#ALIST+1; print @ALIST; } if ($ARGV[0] eq "lsuser") { printf "# OWNER S USED/QUOT #H/QH #A/QA VROOT PROFILE - user total %d\n", $#ULIST+1 if !$H; printf "# USER S HOME MAIL ALTERNATIVE_LOGIN FULL_NAME - user total %d\n", $#ULIST+1 if $H; print @ULIST; printf "# - user alias total %d\n", $#VLIST+1 if $H; print @VLIST if $H; } if ($ARGV[0] eq "uninstall") { `rm /usr/sbin/vhost.pl $NERR`; } if ($ARGV[0] =~ /^q?$/ && -f "/tmp/.vhost/.ins.vmain") { `/usr/sbin/vhost --addhost $HNAM root -f $NERR`; `rm /tmp/.vhost/.ins.vmain $NERR` if !$?; } ReloadRc $inetdRc if $ARGV[0] eq "reload"; }; }