sub require_acl { return if ($require_acl++); &foreign_require("acl", "acl-lib.pl"); } # setup_webmin(&domain) # Creates a new user to manage this domain, with access to the appropriate # modules with the right permissions sub setup_webmin { &$first_print($text{'setup_webmin'}); &require_acl(); local ($wuser) = grep { $_->{'name'} eq $_[1]->{'user'} } &acl::list_users(); if ($wuser) { # Update the modules for this Webmin user &set_user_modules($_[0], $wuser); } else { local @modules; local %wuser = ( 'name' => $_[0]->{'user'}, 'pass' => $_[0]->{'unix'} ? 'x' : &webmin_password($_[0]), 'notabs' => !$config{'show_tabs'}, 'modules' => [ ], 'theme' => $config{'webmin_theme'} eq '*' ? undef : $config{'webmin_theme'} eq '' ? '' : $config{'webmin_theme'}, 'desc' => $_[0]->{'owner'}, ); &acl::create_user(\%wuser); &set_user_modules($_[0], \%wuser); } &update_extra_webmin($_[0]); &$second_print($text{'setup_done'}); ®ister_post_action(\&restart_webmin); } # webmin_password(&domain) # Returns an encrypted password for a virtual server sub webmin_password { &require_acl(); return &acl::encrypt_password($_[0]->{'pass'}); } # delete_webmin(&domain) # Delete the webmin user for the domain, and all his permissions sub delete_webmin { &$first_print($text{'delete_webmin'}); &require_acl(); &acl::delete_user($_[0]->{'user'}); local $m; foreach $m (&get_all_module_infos()) { &unlink_logged("$config_directory/$m->{'dir'}/$_[0]->{'user'}.acl"); } &update_extra_webmin($_[0]); &$second_print($text{'setup_done'}); ®ister_post_action(\&restart_webmin); } # modify_webmin(&domain, &olddomain) sub modify_webmin { if ($_[0]->{'home'} ne $_[1]->{'home'} && &foreign_check("htaccess-htpasswd")) { # If home has changed, update protected web directories that referred to old dir &$first_print($text{'save_htaccess'}); &foreign_require("htaccess-htpasswd", "htaccess-lib.pl"); local @dirs = &htaccess_htpasswd::list_directories(1); foreach $d (@dirs) { if ($d->[0] eq $_[1]->{'home'}) { $d->[0] = $_[0]->{'home'}; } else { $d->[0] =~ s/^$_[1]->{'home'}\//$_[0]->{'home'}\//; } if ($d->[1] =~ /^$_[1]->{'home'}\/(.*)$/) { # Need to update file too! $d->[1] = "$_[0]->{'home'}/$1"; &require_apache(); local $conf = &apache::get_htaccess_config( "$d->[0]/$htaccess_htpasswd::config{'htaccess'}"); &apache::save_directive("AuthUserFile", [ $d->[1] ], $conf, $conf); &flush_file_lines(); } } &htaccess_htpasswd::save_directories(\@dirs); &$second_print($text{'setup_done'}); } if (!$_[0]->{'parent'}) { # Update the Webmin user &require_acl(); local ($wuser) = grep { $_->{'name'} eq $_[1]->{'user'} } &acl::list_users(); if ($_[0]->{'unix'} ne $_[1]->{'unix'}) { # Turn on or off password synchronization $wuser->{'pass'} = $_[0]->{'unix'} ? 'x' : &webmin_password($_[0]); &acl::modify_user($_[1]->{'user'}, $wuser); } if ($_[0]->{'user'} ne $_[1]->{'user'}) { # Need to re-name user &$first_print($text{'save_webminuser'}); $wuser->{'real'} = $_[0]->{'owner'}; $wuser->{'name'} = $_[0]->{'user'}; &acl::modify_user($_[1]->{'user'}, $wuser); } elsif ($_[0]->{'owner'} ne $_[1]->{'owner'}) { # Need to update owner &$first_print($text{'save_webminreal'}); $wuser->{'real'} = $_[0]->{'owner'}; &acl::modify_user($_[0]->{'user'}, $wuser); } else { # Leave name unchanged &$first_print($text{'save_webmin'}); } &set_user_modules($_[0], $wuser) if ($wuser); &update_extra_webmin($_[0]); &$second_print($text{'setup_done'}); ®ister_post_action(\&restart_webmin); return 1; } elsif ($_[0]->{'parent'} && !$_[1]->{'parent'}) { # Webmin feature has been turned off .. so delete the user &delete_webmin($_[1]); } return 0; } # validate_webmin(&domain) # Make sure all Webmin users exist sub validate_webmin { local ($d) = @_; &require_acl(); local @users = &acl::list_users(); local ($wuser) = grep { $_->{'name'} eq $d->{'user'} } @users; return &text('validate_ewebmin', $d->{'user'}) if (!$wuser); foreach my $admin (&list_extra_admins($d)) { local ($wuser) = grep { $_->{'name'} eq $admin->{'name'} } @users; return &text('validate_ewebminextra', $admin->{'name'}) if (!$wuser); } return undef; } # disable_webmin(&domain) # Lock the password of the domains's Webmin user sub disable_webmin { &$first_print($text{'disable_webmin'}); &require_acl(); local ($wuser) = grep { $_->{'name'} eq $_[0]->{'user'} } &acl::list_users(); if ($wuser) { $wuser->{'pass'} = "*LK*"; &acl::modify_user($wuser->{'name'}, $wuser); ®ister_post_action(\&restart_webmin); } &$second_print($text{'setup_done'}); } # enable_webmin(&domain) # Changes the password of the domain's Webmin user back to unix auth sub enable_webmin { &$first_print($text{'enable_webmin'}); &require_acl(); local ($wuser) = grep { $_->{'name'} eq $_[0]->{'user'} } &acl::list_users(); if ($wuser) { $wuser->{'pass'} = "x"; &acl::modify_user($wuser->{'name'}, $wuser); ®ister_post_action(\&restart_webmin); } &$second_print($text{'setup_done'}); } # restart_webmin() sub restart_webmin { &$first_print($text{'setup_webminpid2'}); &reload_miniserv(); &$second_print($text{'setup_done'}); } # restart_usermin() sub restart_usermin { &foreign_require("usermin", "usermin-lib.pl"); &$first_print($text{'setup_userminpid'}); &usermin::restart_usermin_miniserv(); &$second_print($text{'setup_done'}); } # set_user_modules(&domain, &webminuser, [&acs-for-this-module], [no-features], # [no-extra], [is-extra-admin]) sub set_user_modules { local ($d, $wuser, $acls, $nofeatures, $noextras, $isextra) = @_; local @mods; local $tmpl = &get_template($_[0]->{'template'}); # Work out which module's ACLs to leave alone local %hasmods = map { $_, 1 } @{$_[1]->{'modules'}}; %hasmods = ( ) if (!$config{'leave_acl'}); # Work out which domains and features exist local @doms = ( $_[0], &get_domain_by("parent", $_[0]->{'id'}) ); local %doneid; @doms = grep { !$doneid{$_->{'id'}}++ } @doms; local (%features, $d, $f); if (!$nofeatures) { foreach $d (@doms) { foreach $f (@features) { $features{$f}++ if ($d->{$f}); } } } # Grant access to BIND module if needed if ($features{'dns'} && $config{'avail_dns'}) { # Allow user to manage just this domain push(@mods, "bind8"); local %acl = ( 'noconfig' => 1, 'zones' => join(" ", map { $_->{'dom'} } @doms), 'dir' => &resolve_links($_[0]->{'home'}), 'master' => 0, 'slave' => 0, 'forward' => 0, 'delegation' => 0, 'defaults' => 0, 'reverse' => 0, 'multiple' => 1, 'ro' => 0, 'apply' => 2, 'file' => 0, 'params' => 1, 'opts' => 0, 'delete' => 0, 'gen' => 1, 'whois' => 1, 'findfree' => 1, 'slaves' => 0, 'remote' => 0, 'views' => 0, 'vlist' => '' ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "bind8") if (!$hasmods{'bind8'}); } else { @mods = grep { $_ ne "bind8" } @mods; } # Grant access to MySQL module if needed if ($features{'mysql'} && $config{'avail_mysql'}) { # Allow user to manage just the domain's DB push(@mods, "mysql"); local %acl = ( 'noconfig' => 1, 'dbs' => join(" ", map { split(/\s+/, $_->{'db_mysql'}) } @doms), 'create' => 0, 'delete' => 0, 'stop' => 0, 'perms' => 0, 'edonly' => 0, 'user' => &mysql_user($_[0]), 'pass' => &mysql_pass($_[0]), 'buser' => $_[0]->{'user'}, 'bpath' => "/" ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "mysql") if (!$hasmods{'mysql'}); } else { @mods = grep { $_ ne "mysql" } @mods; } # Grant access to PostgreSQL module if needed if ($features{'postgres'} && $config{'avail_postgres'}) { # Allow user to manage just the domain's DB push(@mods, "postgresql"); local %acl = ( 'noconfig' => 1, 'dbs' => join(" ", map { split(/\s+/, $_->{'db_postgres'}) } @doms), 'create' => 0, 'delete' => 0, 'stop' => 0, 'users' => 0, 'user' => &postgres_user($_[0]), 'pass' => &postgres_pass($_[0], 1), 'sameunix' => 1, 'backup' => 1, 'restore' => 1 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "postgresql") if (!$hasmods{'postgresql'}); } else { @mods = grep { $_ ne "postgresql" } @mods; } # Grant access to Apache module if needed if ($features{'web'} && $config{'avail_web'}) { # Allow user to manage just this website &require_apache(); push(@mods, "apache"); local %acl = ( 'noconfig' => 1, 'virts' => join(" ", map { $_->{'dom'}, "$_->{'dom'}:$_->{'web_port'}" } @doms), 'global' => 0, 'create' => 0, 'vuser' => 0, 'vaddr' => 0, 'names' => 0, 'pipe' => 0, 'stop' => 0, 'dir' => &resolve_links($_[0]->{'home'}), 'aliasdir' => &resolve_links($_[0]->{'home'}), 'test_always' => 1, 'types' => join(" ", (0 .. 7, 9 .. 16, 18 .. $apache::directive_type_count)), 'dirsmode' => 2, 'dirs' => 'ServerName ServerAlias SSLEngine SSLCertificateFile SSLCertificateKeyFile', ); if ($_[0]->{'ssl'}) { $acl{'virts'} .= " ".join(" ", map { $_->{'dom'}, "$_->{'dom'}:$_->{'web_sslport'}" } @doms); } &save_module_acl_logged(\%acl, $_[1]->{'name'}, "apache") if (!$hasmods{'apache'}); } else { @mods = grep { $_ ne "apache" } @mods; } # Grant access to Webalizer module if needed if ($features{'webalizer'} && $config{'avail_webalizer'}) { push(@mods, "webalizer"); local @logs; local $d; foreach $d (@doms) { push(@logs, &resolve_links(&get_apache_log($d->{'dom'}, $d->{'web_port'}))); } local %acl = ( 'noconfig' => 1, 'view' => $tmpl->{'web_stats_noedit'}, 'global' => 0, 'add' => 0, 'user' => $_[0]->{'user'}, 'dir' => join(" ", @logs) ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "webalizer") if (!$hasmods{'webalizer'}); } else { @mods = grep { $_ ne "webalizer" } @mods; } # Grant access to SpamAssassin module if needed, and if per-domain spamassassin # configs are available local @spamassassin_doms; if (defined(&get_domain_spam_client)) { @spamassassin_doms = grep { &get_domain_spam_client($_) ne 'spamc' } @doms; } if ($features{'spam'} && $config{'avail_spam'} && @spamassassin_doms) { push(@mods, "spam"); local %acl = ( 'noconfig' => 1, 'avail' => 'white,score,report,user,header,procmail', 'procmailrc' => "$procmail_spam_dir/$_[0]->{'id'}", 'file' => "$spam_config_dir/$_[0]->{'id'}/virtualmin.cf" ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "spam") if (!$hasmods{'spam'}); } else { @mods = grep { $_ ne "spam" } @mods; } # All users get access to virtualmin at least local $can_create = $_[0]->{'domslimit'} && !$_[0]->{'no_create'} && $_[0]->{'unix'}; push(@mods, $module_name); local %acl = ( 'noconfig' => 1, 'edit' => $_[0]->{'edit_domain'} ? 2 : 0, 'create' => $can_create ? 2 : 0, 'import' => 0, 'stop' => 0, 'local' => 0, 'nodbname' => $_[0]->{'nodbname'}, 'norename' => $_[0]->{'norename'}, 'forceunder' => $_[0]->{'forceunder'}, 'domains' => join(" ", map { $_->{'id'} } @doms), 'admin' => $_[2] ? $_[0]->{'id'} : undef, ); if ($_[0]->{'domslimit'}) { foreach $f (@opt_features, @feature_plugins) { $acl{"feature_$f"} = $_[0]->{"limit_$f"}; } } foreach my $ed (@edit_limits) { $acl{'edit_'.$ed} = $_[0]->{'edit_'.$ed}; } if ($acls) { foreach my $k (keys %$acls) { $acl{$k} = $acls->{$k}; } } &save_module_acl_logged(\%acl, $_[1]->{'name'}); %uaccess = %acl; # Set global ACL options local %acl = ( 'feedback' => 0, 'rpc' => 0, 'readonly' => $_[0]->{'demo'}, 'fileunix' => $_[0]->{'user'} ); $acl{'root'} = &resolve_links( &substitute_domain_template($tmpl->{'gacl_root'}, $_[0])); if ($tmpl->{'gacl_umode'} == 1) { $acl{'uedit_mode'} = 5; $acl{'uedit'} = &substitute_domain_template($tmpl->{'gacl_ugroups'}, $_[0]); } else { $acl{'uedit_mode'} = 2; $acl{'uedit'} = &substitute_domain_template($tmpl->{'gacl_uusers'}, $_[0]); } $acl{'gedit_mode'} = 2; $acl{'gedit'} = &substitute_domain_template($tmpl->{'gacl_groups'}, $_[0]); if (!$_[0]->{'domslimit'}) { $acl{'desc_'.$module_name} = $text{'index_title2'}; } &save_module_acl_logged(\%acl, $_[1]->{'name'}, "."); # Work out which extra (non feature-related) modules are available local @extramods = map { /^avail_(\S+)/; $1 } grep { $config{$_} } grep { /^avail_/ } (keys %config); if ($noextras) { @extramods = ( ); } local %extramods = map { $_, $config{"avail_".$_} } grep { my $m=$_; { local $_; &foreign_check($m) } } @extramods; if ($extramods{'file'} && $_[0]->{'unix'}) { # Limit file manager to user's directory, as unix user local %acl = ( 'noconfig' => 1, 'uid' => $_[0]->{'uid'}, 'follow' => 0, 'root' => $_[0]->{'home'}, 'home' => 0, 'goto' => 1 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "file") if (!$hasmods{'file'}); push(@mods, "file"); } if ($_[0]->{'unix'}) { if ($extramods{'passwd'} == 1 && !$isextra) { # Can only change domain owners password local %acl = ( 'noconfig' => 1, 'mode' => 1, 'users' => $_[0]->{'user'}, 'repeat' => 1, 'old' => 1, 'expire' => 0, 'others' => 1 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "passwd") if (!$hasmods{'passwd'}); push(@mods, "passwd"); } elsif ($extramods{'passwd'} == 2) { # Can change all mailbox passwords (except for the domain # owner, if this is an extra admin) local %acl = ( 'noconfig' => 1, 'mode' => 5, 'users' => $_[0]->{'group'}, 'notusers' => $_[0]->{'user'}, 'repeat' => 1, 'old' => 0, 'expire' => 0, 'others' => 1 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "passwd") if (!$hasmods{'passwd'}); push(@mods, "passwd"); } } if ($extramods{'proc'} && $_[0]->{'unix'}) { # Can only manage and see his own processes local %acl = ( 'noconfig' => 1, 'uid' => $_[0]->{'uid'}, 'edit' => 1, 'run' => 1, 'users' => $_[0]->{'user'}, 'only' => ($extramods{'proc'} == 2) ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "proc") if (!$hasmods{'proc'}); push(@mods, "proc"); } if ($extramods{'cron'} && $_[0]->{'unix'}) { # Can only manage his cron jobs local %acl = ( 'noconfig' => 1, 'mode' => 1, 'users' => $_[0]->{'user'}, 'allow' => 0 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "cron") if (!$hasmods{'cron'}); push(@mods, "cron"); } if ($extramods{'at'} && $_[0]->{'unix'}) { # Can only manage his at jobs local %acl = ( 'noconfig' => 1, 'mode' => 1, 'users' => $_[0]->{'user'}, 'allow' => 0 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "at") if (!$hasmods{'at'}); push(@mods, "at"); } if ($extramods{'telnet'} && $_[0]->{'unix'}) { # Cannot configure module local %acl = ( 'noconfig' => 1 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "telnet") if (!$hasmods{'telnet'}); push(@mods, "telnet"); } if ($extramods{'custom'}) { # Cannot edit or create commands local %acl = ( 'noconfig' => 1, 'cmd' => '*', 'edit' => 0 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "custom") if (!$hasmods{'custom'}); push(@mods, "custom"); } if ($extramods{'shell'} && $_[0]->{'unix'}) { # Can only run commands as server owner local %acl = ( 'noconfig' => 1, 'user' => $_[0]->{'user'} ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "shell") if (!$hasmods{'shell'}); push(@mods, "shell"); } if ($extramods{'updown'} && $_[0]->{'unix'}) { # Can upload and download to home dir only local %acl = ( 'noconfig' => 1, 'dirs' => $_[0]->{'home'}, 'home' => 0, 'mode' => 3, ); if ($extramods{'updown'} == 2) { # Can only upload $acl{'download'} = 0; $acl{'fetch'} = 0; } &save_module_acl_logged(\%acl, $_[1]->{'name'}, "updown") if (!$hasmods{'updown'}); push(@mods, "updown"); # Set defaults for upload and download directories for this user local %udconfig; local $udfile = "$config_directory/updown/config"; &lock_file($udfile); &read_file($udfile, \%udconfig); $udfile{'dir_'.$_[1]->{'name'}} ||= &resolve_links($_[0]->{'home'}); $udfile{'ddir_'.$_[1]->{'name'}} ||= &resolve_links($_[0]->{'home'}); &write_file($udfile, \%udconfig); &unlock_file($udfile); } if ($extramods{'change-user'}) { # This module is always safe, so no ACL needs to be set push(@mods, "change-user"); } if ($extramods{'htaccess-htpasswd'} && $_[0]->{'unix'}) { # Can create .htaccess files in home dir, as user local %acl = ( 'noconfig' => 1, 'home' => 0, 'dirs' => $_[0]->{'home'}, 'sync' => 0, 'user' => '*' ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "htaccess-htpasswd") if (!$hasmods{'htaccess-htpasswd'}); push(@mods, "htaccess-htpasswd"); } if ($extramods{'mailboxes'} && $_[0]->{'mail'}) { # Can read mailboxes of users local %acl = ( 'noconfig' => 1, 'fmode' => 1, 'from' => join(" ", map { $_->{'dom'} } @doms), 'canattach' => 0, 'candetach' => 0, 'dir' => &mail_domain_base($_[0]) ); if (!&mail_system_needs_group()) { # For vpopmail, mailboxes are identified by domain $acl{'mmode'} = 6; $acl{'musers'} = ".*\@(". join("|", map { $_->{'dom'} } @doms).")"; } else { # By server GID $acl{'mmode'} = 5; $acl{'musers'} = $_[0]->{'gid'}; } &save_module_acl_logged(\%acl, $_[1]->{'name'}, "mailboxes") if (!$hasmods{'mailboxes'}); push(@mods, "mailboxes"); } else { @mods = grep { $_ ne "mailboxes" } @mods; } if ($extramods{'webminlog'} && $_[0]->{'webmin'}) { # Can view own actions, and those of extra admins local @users = ( $_[0]->{'user'} ); if ($virtualmin_pro) { push(@users, map { $_->{'name'} } &list_extra_admins($_[0])); } local %acl = ( 'users' => join(" ", @users), 'rollback' => 0 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "webminlog") if (!$hasmods{'webminlog'}); push(@mods, "webminlog"); } else { @mods = grep { $_ ne "webminlog" } @mods; } if ($extramods{'syslog'} && $_[0]->{'webmin'} && &get_webmin_version() >= 1.306) { # Can view log files for Apache and ProFTPd local @extras; local %done; foreach my $sd (@doms) { # Add Apache logs if ($sd->{'web'}) { local $alog = &get_apache_log($sd->{'dom'}, $sd->{'web_port'}, 0); local $elog = &get_apache_log($sd->{'dom'}, $sd->{'web_port'}, 1); push(@extras, $alog." ".&text('webmin_alog', $sd->{'dom'})) if ($alog && !$done{$alog}++); push(@extras, $elog." ".&text('webmin_elog', $sd->{'dom'})) if ($elog && !$done{$elog}++); } # Add FTP logs if ($sd->{'ftp'}) { local $flog = &get_proftpd_log($sd->{'ip'}); push(@extras, $flog." ".&text('webmin_flog', $sd->{'dom'})) if ($flog && !$done{$flog}++); } } if (@extras) { local %acl = ( 'extras' => join("\t", @extras), 'any' => 0, 'noconfig' => 1, 'noedit' => 1, 'syslog' => 0, 'others' => 0 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "syslog") if (!$hasmods{'syslog'}); push(@mods, "syslog"); } else { # No logs found! @mods = grep { $_ ne "syslog" } @mods; } } else { @mods = grep { $_ ne "syslog" } @mods; } local @pconfs; if ($extramods{'phpini'}) { # Can edit PHP configuration files foreach my $sd (@doms) { if ($sd->{'web'} && defined(&get_domain_php_mode) && &get_domain_php_mode($sd) ne "mod_php") { foreach my $ini (&list_domain_php_inis($sd)) { local @st = stat($ini->[1]); if (@st && $st[4] == $sd->{'uid'}) { if ($ini->[0]) { push(@pconfs, "$ini->[1]=". &text('webmin_phpini2', $sd->{'dom'}, $ini->[0])); } else { push(@pconfs, "$ini->[1]=". &text('webmin_phpini', $sd->{'dom'})); } } } } } } if (@pconfs) { local %acl = ( 'php_inis' => join("\t", @pconfs), 'noconfig' => 1, 'global' => 0, 'anyfile' => 0, 'manual' => 1 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, "phpini") if (!$hasmods{'phpini'}); push(@mods, "phpini"); } else { @mods = grep { $_ ne "phpini" } @mods; } if (!$noextras) { # Add any extra modules specified for this domain push(@mods, split(/\s+/, $_[0]->{'webmin_modules'})); # Add any extra modules specified in global config local @wmods = split(/\s+/, $config{'webmin_modules'}); local $m; foreach $m (@wmods) { local %acl = ( 'noconfig' => 1 ); &save_module_acl_logged(\%acl, $_[1]->{'name'}, $m) if (!$hasmods{$m}); } push(@mods, @wmods); } if (!$nofeatures) { # Add plugin-specified modules local $p; foreach $p (@plugins) { local @pmods = &plugin_call($p, "feature_webmin", $_[0], \@doms); local $pm; foreach $pm (@pmods) { push(@mods, $pm->[0]); if ($pm->[1]) { &save_module_acl_logged( $pm->[1], $_[1]->{'name'}, $pm->[0]); } } } } # Finally, override in settings from template Webmin group local @ownmods = @mods; if ($tmpl->{'webmin_group'} ne 'none') { local ($group) = grep { $_->{'name'} eq $tmpl->{'webmin_group'} } &acl::list_groups(); if ($group) { # Add modules from group to list push(@mods, @{$group->{'modules'}}); # Copy group's ACLs to user &acl::copy_group_user_acl_files( $group->{'name'}, $wuser->{'name'}, [ @{$group->{'modules'}}, "" ]); } } $wuser->{'ownmods'} = [ &unique(@ownmods) ]; $wuser->{'modules'} = [ &unique(@mods) ]; $wuser->{'readonly'} = $module_name; &acl::modify_user($wuser->{'name'}, $wuser); } # check_webmin_clash(&domain, [field]) # Returns 1 if a user or group with this name already exists sub check_webmin_clash { if (!$_[1] || $_[1] eq 'user') { &require_acl(); return 1 if ($_[0]->{'user'} eq 'webmin'); return 0 if ($_[0]->{'webmin_overwrite'}); local $u; foreach $u (&acl::list_users()) { return 1 if ($u->{'name'} eq $_[0]->{'user'}); } } return 0; } # modify_all_webmin([template-id]) # Updates the Webmin users for all domains (or just those on some template) sub modify_all_webmin { local ($tid) = @_; &$first_print($text{'check_allwebmin'}); { local ($first_print, $second_print, $indent_print, $outdent_print); &set_all_null_print(); local $d; foreach $d (&list_domains()) { if ($d->{'webmin'} && $config{'webmin'} && (!defined($tid) || $d->{'template'} == $tid)) { &modify_webmin($d, $d); } } } &$second_print($text{'setup_done'}); ®ister_post_action(\&restart_webmin); } # refresh_webmin_user(&domain, [quiet]) # Calls modify_webmin for a domain or the appropriate parent. This will # update the ACL for the domain's Webmin login, create and update extra # admins, and possibly update the reseller too. sub refresh_webmin_user { local ($d, $quiet) = @_; local $wd = $d->{'parent'} ? &get_domain($d->{'parent'}) : $d; &modify_webmin($wd, $wd); if ($wd->{'reseller'} && $virtualmin_pro) { local @resels = &list_resellers(); local ($r) = grep { $_->{'name'} eq $d->{'reseller'} } @resels; if ($r) { &modify_reseller($r, $r); } } } # save_module_acl_logged(&acl, user, module) sub save_module_acl_logged { local $afile = "$config_directory/$_[2]/$_[1].acl"; &lock_file($afile); &save_module_acl(@_); &unlock_file($afile); } # update_extra_webmin(&domain) # Creates, updates or deletes Webmin users to be the extra admins for a # virtual server. sub update_extra_webmin { local ($d) = @_; local @admins = &list_extra_admins($d); local %admins = map { $_->{'name'}, $_ } @admins; local %webmins; # Get current users &require_acl(); foreach my $u (&acl::list_users()) { if (&indexof($module_name, @{$u->{'modules'}}) >= 0) { local %acl = &get_reseller_acl($u->{'name'}); if ($acl{'admin'} && $acl{'admin'} eq $d->{'id'}) { # Found an admin for this domain if ($admins{$u->{'name'}}) { $webmins{$u->{'name'}} = $u; } else { # Who shouldn't exist! &acl::delete_user($u->{'name'}); } } } } # Create or update users foreach my $admin (@admins) { local $wuser = $webmins{$admin->{'name'}}; local @dis = split(/,/, $d->{'disabled'}); local $pass = &indexof("webmin", @dis) >= 0 ? "*LK*" : &acl::encrypt_password($admin->{'pass'}); if ($wuser) { # Update password (if changed) if ($pass eq "*LK*" || &acl::encrypt_password($admin->{'pass'}, $wuser->{'pass'}) ne $wuser->{'pass'}) { $wuser->{'pass'} = $pass; &acl::modify_user($wuser->{'name'}, $wuser); } } else { # Need to create user $wuser = { 'name' => $admin->{'name'}, 'pass' => $pass, 'notabs' => !$config{'show_tabs'}, 'modules' => [ ], 'theme' => $config{'webmin_theme'} eq '*' ? undef : $config{'webmin_theme'} eq '' ? '' : $config{'webmin_theme'} }; &acl::create_user($wuser); } local %acl; foreach my $ed (@edit_limits) { if ($d->{'edit_'.$ed}) { $acl{'edit_'.$ed} = $admin->{'edit_'.$ed}; } } $acl{'edit'} = $acl{'edit_domain'} ? 2 : 0; $acl{'create'} = $d->{'domslimit'} && $admin->{'create'} ? 2 : 0; $acl{'norename'} = $d->{'norename'} || $admin->{'norename'}; $acl{'nodbname'} = $d->{'nodbname'} || $admin->{'nodbname'}; $acl{'forceunder'} = $d->{'forceunder'} || $admin->{'forceunder'}; &set_user_modules($d, $wuser, \%acl, !$admin->{'features'}, !$admin->{'modules'}, 1); } } # backup_webmin(&domain, file, &options) # Create a tar file of all .acl files, for the server owner and extra admins sub backup_webmin { local ($d, $file, $opts) = @_; &$first_print($text{'backup_webmin'}); local @files; push(@files, "$d->{'user'}.acl", "*/$d->{'user'}.acl"); foreach my $admin (&list_extra_admins($d)) { push(@files, "$admin->{'name'}.acl", "*/$admin->{'name'}.acl"); } local $out = &backquote_command("cd $config_directory && tar cf ".quotemeta($file)." ".join(" ", @files)." 2>&1"); if ($?) { &$second_print(&text('backup_webminfailed', "
$out")); return 0; } else { &$second_print($text{'setup_done'}); return 1; } } # restore_webmin(&domain, file, &options) # Extract all .acl files from the backup sub restore_webmin { local ($d, $file, $opts) = @_; &$first_print($text{'restore_webmin'}); local $out = &backquote_logged("cd $config_directory && tar xf ".quotemeta($file)." 2>&1"); if ($?) { &$second_print(&text('backup_webminfailed', "
$out")); return 0; } else { &$second_print($text{'setup_done'}); return 1; } } # links_webmin(&domain) # Returns a link to the Webmin Actions Log module sub links_webmin { local ($d) = @_; if ($config{'avail_webminlog'}) { return ( { 'mod' => 'webminlog', 'desc' => $text{'links_webminlog'}, 'page' => "search.cgi?uall=0&user=".&urlize($d->{'user'}). "&mall=1&tall=2&fall=1", 'cat' => 'logs', } ); } return ( ); } # show_template_webmin(&tmpl) # Outputs HTML for editing webmin-user-related template options sub show_template_webmin { local ($tmpl) = @_; # Global ACL on or off if (!$tmpl->{'default'}) { local @gacl_fields = ( "gacl_umode", "gacl_uusers", "gacl_ugroups", "gacl_groups", "gacl_root" ); local $dis1 = &js_disable_inputs(\@gacl_fields, [ ]); local $dis2 = &js_disable_inputs([ ], \@gacl_fields); print &ui_table_row(&hlink($text{'tmpl_gacl'}, "template_gacl"), &ui_radio("gacl", int($tmpl->{'gacl'}), [ [ 0, $text{'default'}, "onClick='$dis1'" ], [ 1, $text{'tmpl_gaclbelow'}, "onClick='$dis2'" ] ])); } # Global ACL users print &ui_table_row(&hlink($text{'tmpl_gaclu'}, "template_gacl_umode"), &ui_radio("gacl_umode", int($tmpl->{'gacl_umode'}), [ [ 0, $text{'tmpl_gacl0'}." ". &ui_textbox("gacl_uusers", $tmpl->{'gacl_umode'} == 0 ? $tmpl->{'gacl_uusers'} : "", 40)."