# usermin-lib.pl
# Common functions for configuring usermin
# XXX share text with webmin!

do '../web-lib.pl';
{'usermin_dir'}&init_config();
do '../ui-lib.pl';
%access = &get_module_acl();
$access{'upgrade'} = 0 if (&is_readonly_mode());	# too hard to fake
&foreign_require("webmin", "webmin-lib.pl");
&foreign_require("acl", "acl-lib.pl");

$usermin_miniserv_config = "$config{'usermin_dir'}/miniserv.conf";
$usermin_config = "$config{'usermin_dir'}/config";

$update_host = "www.webmin.com";
$update_port = 80;
$update_page = "/uupdates/uupdates.txt";

$standard_usermin_dir = "/etc/usermin";
$latest_rpm = "http://www.webmin.com/download/usermin-latest.noarch.rpm";
$latest_tgz = "http://www.webmin.com/download/usermin-latest.tar.gz";

$default_key_size = 512;

$cron_cmd = "$module_config_directory/update.pl";

# get_usermin_miniserv_config(&array)
sub get_usermin_miniserv_config
{
&read_file($usermin_miniserv_config, \%usermin_miniserv_config_cache)
	if (!%usermin_miniserv_config_cache);
%{$_[0]} = %usermin_miniserv_config_cache;
}

# put_usermin_miniserv_config(&array)
sub put_usermin_miniserv_config
{
%usermin_miniserv_config_cache = %{$_[0]};
&write_file($usermin_miniserv_config, \%usermin_miniserv_config_cache);
}

# get_usermin_version()
sub get_usermin_version
{
local %miniserv;
&get_usermin_miniserv_config(\%miniserv);
open(VERSION, "$miniserv{'root'}/version");
local $version = <VERSION>;
close(VERSION);
$version =~ s/\r|\n//g;
return $version;
}

# restart_usermin_miniserv()
# Send a HUP signal to miniserv
sub restart_usermin_miniserv
{
return undef if (&is_readonly_mode());
local($pid, %miniserv, $addr, $i);
&get_usermin_miniserv_config(\%miniserv) || return;
$miniserv{'inetd'} && return;
open(PID, $miniserv{'pidfile'}) || &error("Failed to open PID file");
chop($pid = <PID>);
close(PID);
if (!$pid) { &error("Invalid PID file"); }
return &kill_logged('HUP', $pid);
}

# reload_usermin_miniserv()
# Sends a USR1 signal to the miniserv process
sub reload_usermin_miniserv
{
return undef if (&is_readonly_mode());
local %miniserv;
&get_usermin_miniserv_config(\%miniserv) || return;
$miniserv{'inetd'} && return;

local($pid, $addr, $i);
open(PID, $miniserv{'pidfile'}) || &error("Failed to open PID file");
chop($pid = <PID>);
close(PID);
if (!$pid) { &error("Invalid PID file"); }
return &kill_logged('USR1', $pid);
}

# get_usermin_config(&array)
sub get_usermin_config
{
&read_file($usermin_config, \%usermin_config_cache)
	if (!%usermin_config_cache);
%{$_[0]} = %usermin_config_cache;
}

# put_usermin_config(&array)
sub put_usermin_config
{
%usermin_config_cache = %{$_[0]};
&write_file($usermin_config, \%usermin_config_cache);
}

# list_themes()
# Returns an array of all usermin themes
sub list_themes
{
local @rv;
local %miniserv;
&get_usermin_miniserv_config(\%miniserv);
opendir(DIR, $miniserv{'root'});
foreach $m (readdir(DIR)) {
	next if ($m =~ /^\./);
	local %tinfo = &get_usermin_theme_info($m);
	next if (!%tinfo);
	next if (!&check_usermin_os_support(\%tinfo));
	push(@rv, \%tinfo);
	}
closedir(DIR);
return @rv;
}

# list_modules()
# Returns a list of all usermin modules
sub list_modules
{
local (@mlist, $m, %miniserv);
&get_usermin_miniserv_config(\%miniserv);
local %cats;
&read_file_cached("$config{'usermin_dir'}/webmin.cats", \%cats);
opendir(DIR, $miniserv{'root'});
foreach $m (readdir(DIR)) {
	local %minfo;
	if ((%minfo = &get_usermin_module_info($m)) &&
	    &check_usermin_os_support(\%minfo)) {
		$minfo{'realcategory'} = $minfo{'category'};
		$minfo{'category'} = $cats{$m} if (defined($cats{$m}));
		push(@mlist, \%minfo);
		}
	}
closedir(DIR);
@mlist = sort { $a->{'desc'} cmp $b->{'desc'} } @mlist;
return @mlist;
}

# get_usermin_module_info(module, [noclone])
# Returns a hash containg a module name, desc and os_support
sub get_usermin_module_info
{
return () if ($_[0] =~ /^\./);
local (%rv, $clone, %miniserv, $o);
&get_usermin_miniserv_config(\%miniserv);
&read_file("$miniserv{'root'}/$_[0]/module.info", \%rv) || return ();
$clone = -l "$miniserv{'root'}/$_[0]";
foreach $o (@lang_order_list) {
	$rv{"desc"} = $rv{"desc_$o"} if ($rv{"desc_$o"});
	}
if ($clone && !$_[1] && $config_directory) {
	$rv{'clone'} = $rv{'desc'};
	&read_file("$config{'usermin_dir'}/$_[0]/clone", \%rv);
	}
$rv{'dir'} = $_[0];
$rv{'realcategory'} = $rv{'category'};

# Apply description overrides
$rv{'realdesc'} = $rv{'desc'};
local %descs;
&read_file_cached("$config{'usermin_dir'}/webmin.descs", \%descs);
if ($descs{$_[0]." ".$current_lang}) {
	$rv{'desc'} = $descs{$_[0]." ".$current_lang};
	}
elsif ($descs{$_[0]}) {
	$rv{'desc'} = $descs{$_[0]};
	}

return %rv;
}

# get_usermin_theme_info(theme)
sub get_usermin_theme_info
{
local (%tinfo, $o);
local %miniserv;
&get_usermin_miniserv_config(\%miniserv);
&read_file("$miniserv{'root'}/$_[0]/theme.info", \%tinfo) || return ();
foreach $o (@lang_order_list) {
	$tinfo{"desc"} = $rv{"desc_$o"} if ($tinfo{"desc_$o"});
	}
$tinfo{'dir'} = $_[0];
return %tinfo;
}

# check_usermin_os_support(&minfo)
sub check_usermin_os_support
{
local $oss = $_[0]->{'os_support'};
return 1 if (!$oss || $oss eq '*');
local %uconfig;
&get_usermin_config(\%uconfig);
while(1) {
	local ($os, $ver, $codes);
	if ($oss =~ /^([^\/\s]+)\/([^\{\s]+)\{([^\}]*)\}\s*(.*)$/) {
		$os = $1; $ver = $2; $codes = $3; $oss = $4;
		}
	elsif ($oss =~ /^([^\/\s]+)\/([^\/\s]+)\s*(.*)$/) {
		$os = $1; $ver = $2; $oss = $3;
		}
	elsif ($oss =~ /^([^\{\s]+)\{([^\}]*)\}\s*(.*)$/) {
		$os = $1; $codes = $2; $oss = $3;
		}
	elsif ($oss =~ /^\{([^\}]*)\}\s*(.*)$/) {
		$codes = $1; $oss = $2;
		}
	elsif ($oss =~ /^(\S+)\s*(.*)$/) {
		$os = $1; $oss = $2;
		}
	else { last; }
	next if ($os && !($os eq $uconfig{'os_type'} ||
		 $uconfig{'os_type'} =~ /^(\S+)-(\S+)$/ && $os eq "*-$2"));
	next if ($ver && $ver ne $uconfig{'os_version'});
	next if ($codes && !eval $codes);
	return 1;
	}
return 0;
}

# read_usermin_acl(&array, &array)
# Reads the acl file into the given associative arrays
sub read_usermin_acl
{
local($user, $_, @mods);
if (!defined(%usermin_acl_hash_cache)) {
	open(ACL, &usermin_acl_filename());
	while(<ACL>) {
		if (/^(\S+):\s*(.*)/) {
			local(@mods);
			$user = $1;
			@mods = split(/\s+/, $2);
			foreach $m (@mods) {
				$usermin_acl_hash_cache{$user,$m}++;
				}
			$usermin_acl_array_cache{$user} = \@mods;
			}
		}
	close(ACL);
	}
if ($_[0]) { %{$_[0]} = %usermin_acl_hash_cache; }
if ($_[1]) { %{$_[1]} = %usermin_acl_array_cache; }
}

# usermin_acl_filename()
# Returns the file containing the webmin ACL
sub usermin_acl_filename
{
return "$config{'usermin_dir'}/webmin.acl";
}

# save_usermin_acl(user, &modules)
sub save_usermin_acl
{
&open_tempfile(ACL, ">".&usermin_acl_filename());
&print_tempfile(ACL, $_[0],": ",join(" ", @{$_[1]}),"\n");
&close_tempfile(ACL);
}

# install_usermin_module(file, unlink, nodeps)
# Installs a usermin module or theme, and returns either an error message
# or references to three arrays for descriptions, directories and sizes.
# On success or failure, the file is deleted if the unlink parameter is set.
sub install_usermin_module
{
local ($file, $need_unlink, $nodeps) = @_;
local (@mdescs, @mdirs, @msizes);
if (&is_readonly_mode()) {
	return "Module installs are not allowed in readonly mode";
	}

# Uncompress the module file if needed
open(MFILE, $file);
read(MFILE, $two, 2);
close(MFILE);
if ($two eq "\037\235") {
	if (!&has_command("uncompress")) {
		unlink($file) if ($need_unlink);
		return &text('install_ecomp', "<tt>uncompress</tt>");
		}
	local $temp = $file =~ /\/([^\/]+)\.Z/i ? &transname("$1")
						: &transname();
	local $out = `uncompress -c "$file" 2>&1 >$temp`;
	unlink($file) if ($need_unlink);
	if ($?) {
		unlink($temp);
		return &text('install_ecomp2', $out);
		}
	$file = $temp;
	$need_unlink = 1;
	}
elsif ($two eq "\037\213") {
	if (!&has_command("gunzip")) {
		unlink($file) if ($need_unlink);
		return &text('install_egzip', "<tt>gunzip</tt>");
		}
	local $temp = $file =~ /\/([^\/]+)\.gz/i ? &transname("$1")
						 : &transname();
	local $out = `gunzip -c "$file" 2>&1 >$temp`;
	unlink($file) if ($need_unlink);
	if ($?) {
		unlink($temp);
		return &text('install_egzip2', $out);
		}
	$file = $temp;
	$need_unlink = 1;
	}

local %miniserv;
&get_usermin_miniserv_config(\%miniserv);

# Check if this is an RPM usermin module or theme
local ($type, $redirect_to);
open(TYPE, "../install-type");
chop($type = <TYPE>);
close(TYPE);
if ($type eq 'rpm' && $file =~ /\.rpm$/i &&
    ($out = `rpm -qp $file 2>/dev/null`)) {
	# Looks like an RPM of some kind, hopefully an RPM usermin module
	# or theme
	local ($out, %minfo, %tinfo);
	if ($out !~ /^(wbm|wbt)-([^\s\-]+)/) {
		unlink($file) if ($need_unlink);
		return $text{'install_erpm'};
		}
	$redirect_to = $name = $2;
	$out = &backquote_logged("rpm -U \"$file\" 2>&1");
	if ($?) {
		unlink($file) if ($need_unlink);
		return &text('install_eirpm', "<tt>$out</tt>");
		}

	$mdirs[0] = "$miniserv{'root'}/$name";
	if (%minfo = &get_usermin_module_info($name)) {
		# Get the new module info
		$mdescs[0] = $minfo{'desc'};
		$msizes[0] = &disk_usage_kb($mdirs[0]);

		# Update the ACL for the usermin user
		local %acl;
		&read_usermin_acl(undef, \%acl);
		&open_tempfile(ACL, "> ".&usermin_acl_filename());
		foreach $u (keys %acl) {
			local @mods = @{$acl{$u}};
			if ($u eq 'user') {
				push(@mods, $name);
				@mods = &unique(@mods);
				}
			&print_tempfile(ACL, "$u: ",join(' ', @mods),"\n");
			}
		&close_tempfile(ACL);
		&webmin_log("install", undef, $name,
			    { 'desc' => $mdescs[0] });
		}
	elsif (%tinfo = &get_usermin_theme_info($name)) {
		# Get the theme info
		$mdescs[0] = $tinfo{'desc'};
		$msizes[0] = &disk_usage_kb($mdirs[0]);
		&webmin_log("tinstall", undef, $name,
			    { 'desc' => $mdescs[0] });
		}
	else {
		unlink($file) if ($need_unlink);
		return $text{'install_eneither'};
		}
	}
else {
	# Check if this is a valid module (a tar file of multiple module or
	# theme directories)
	local (%mods, %hasfile);
	local $tar = `tar tf "$file" 2>&1`;
	if ($?) {
		unlink($file) if ($need_unlink);
		return &text('install_etar', $tar);
		}
	foreach $f (split(/\n/, $tar)) {
		if ($f =~ /^\.\/([^\/]+)\/(.*)$/ || $f =~ /^([^\/]+)\/(.*)$/) {
			$redirect_to = $1 if (!$redirect_to);
			$mods{$1}++;
			$hasfile{$1,$2}++;
			}
		}
	foreach $m (keys %mods) {
		if (!$hasfile{$m,"module.info"} && !$hasfile{$m,"theme.info"}) {
			unlink($file) if ($need_unlink);
			return &text('install_einfo', "<tt>$m</tt>");
			}
		}
	if (!%mods) {
		unlink($file) if ($need_unlink);
		return $text{'install_enone'};
		}

	# Get the module.info files to check dependancies
	local $ver = &get_usermin_version();
	local $tmpdir = &transname();
	mkdir($tmpdir, 0700);
	local $err;
	local @realmods;
	foreach $m (keys %mods) {
		next if (!$hasfile{$m,"module.info"});
		push(@realmods, $m);
		local %minfo;
		system("cd $tmpdir ; tar xf \"$file\" $m/module.info ./$m/module.info >/dev/null 2>&1");
		if (!&read_file("$tmpdir/$m/module.info", \%minfo)) {
			$err = &text('install_einfo', "<tt>$m</tt>");
			}
		elsif (!&check_usermin_os_support(\%minfo)) {
			$err = &text('install_eos', "<tt>$m</tt>",
				     $gconfig{'real_os_type'},
				     $gconfig{'real_os_version'});
			}
		elsif (!$minfo{'usermin'}) {
			$err = &text('install_eusermin', "<tt>$m</tt>");
			}
		elsif (!$nodeps) {
			local $deps = $minfo{'usermin_depends'} ||
				      $minfo{'depends'};
			foreach $dep (split(/\s+/, $minfo{'depends'})) {
				if ($dep =~ /^[0-9\.]+$/) {
					if ($dep > $ver) {
						$err = &text('install_ever',
							"<tt>$m</tt>",
							"<tt>$dep</tt>");
						}
					}
				elsif (!-r "$miniserv{'root'}/$dep/module.info"
				       && !$mods{$dep}) {
					$err = &text('install_edep',
					        "<tt>$m</tt>", "<tt>$dep</tt>");
					}
				}
			foreach $dep (split(/\s+/, $minfo{'perldepends'})) {
				eval "use $dep";
				if ($@) {
					$err = &text('install_eperldep',
					     "<tt>$m</tt>", "<tt>$dep</tt>",
					     "/cpan/download.cgi?source=3&cpan=$dep");
					}
				}
			}
		last if ($err);
		}
	system("rm -rf $tmpdir >/dev/null 2>&1");
	if ($err) {
		unlink($file) if ($need_unlink);
		return $err;
		}

	# Delete modules or themes being replaced
	foreach $m (@realmods) {
		system("rm -rf '$miniserv{'root'}/$m' 2>&1 >/dev/null") if ($m ne 'webmin');
		}

	# Extract all the modules and update perl path and ownership
	local $out = `cd $miniserv{'root'} ; tar xf "$file" 2>&1 >/dev/null`;
	if ($?) {
		unlink($file) if ($need_unlink);
		return &text('install_eextract', $out);
		}
	if ($need_unlink) { unlink($file); }
	local $perl;
	open(PERL, "$miniserv{'root'}/miniserv.pl");
	<PERL> =~ /^#!(\S+)/; $perl = $1;
	close(PERL);
	local @st = stat($0);
	foreach $moddir (keys %mods) {
		local $pwd = "$miniserv{'root'}/$moddir";
		if ($hasfile{$moddir,"module.info"}) {
			local %minfo = &get_usermin_module_info($moddir);
			push(@mdescs, $minfo{'desc'});
			push(@mdirs, $pwd);
			push(@msizes, &disk_usage_kb($pwd));
			&webmin_log("install", undef, $moddir,
				    { 'desc' => $minfo{'desc'} });
			}
		else {
			local %tinfo = &get_usermin_theme_info($moddir);
			&read_file("theme.info", \%tinfo);
			push(@mdescs, $tinfo{'desc'});
			push(@mdirs, $pwd);
			push(@msizes, &disk_usage_kb($pwd));
			&webmin_log("tinstall", undef, $moddir,
				    { 'desc' => $tinfo{'desc'} });
			}
		system("(find $pwd -name '*.cgi' ; find $pwd -name '*.pl') 2>/dev/null | $perl $miniserv{'root'}/perlpath.pl $perl -");
		system("chown -R $st[4]:$st[5] $pwd");
		}

	# Copy appropriate config file from modules to /etc/webmin
	local %ugconfig;
	&get_usermin_config(\%ugconfig);
	system("$perl $miniserv{'root'}/copyconfig.pl '$ugconfig{'os_type'}/$ugconfig{'real_os_type'}' '$ugconfig{'os_version'}/$ugconfig{'real_os_version'}' $miniserv{'root'} $config{'usermin_dir'} ".join(' ', @realmods));

	# Update ACL for this user so they can access the new modules
	local %acl;
	&read_usermin_acl(undef, \%acl);
	&open_tempfile(ACL, "> ".&usermin_acl_filename());
	foreach $u (keys %acl) {
		local @mods = @{$acl{$u}};
		if ($u eq 'user') {
			push(@mods, @realmods);
			@mods = &unique(@mods);
			}
		&print_tempfile(ACL, "$u: ",join(' ', @mods),"\n");
		}
	&close_tempfile(ACL);
	}
&flush_modules_cache();

return [ \@mdescs, \@mdirs, \@msizes ];
}

# list_usermin_usermods()
# Returns the list of additional module restrictions for usermin
sub list_usermin_usermods
{
local @rv;
open(USERMODS, "$config{'usermin_dir'}/usermin.mods");
while(<USERMODS>) {
	if (/^([^:]+):(\+|-|):(.*)/) {
		push(@rv, [ $1, $2, [ split(/\s+/, $3) ] ]);
		}
	}
close(USERMODS);
return @rv;
}

# save_usermin_usermods(&usermods)
# Saves the list of additional module restrictions
sub save_usermin_usermods
{
&open_tempfile(USERMODS, ">$config{'usermin_dir'}/usermin.mods");
foreach $u (@{$_[0]}) {
	&print_tempfile(USERMODS,
		join(":", $u->[0], $u->[1], join(" ", @{$u->[2]})),"\n");
	}
&close_tempfile(USERMODS);
}

# get_usermin_miniserv_users()
sub get_usermin_miniserv_users
{
local %miniserv;
&get_usermin_miniserv_config(\%miniserv);
local @rv;
open(USERS, $miniserv{'userfile'});
while(<USERS>) {
	s/\r|\n//g;
	local @u = split(/:/, $_);
	push(@rv, { 'name' => $u[0],
		    'pass' => $u[1],
		    'sync' => $u[2],
		    'cert' => $u[3],
		    'allow' => $u[4] });
	}
close(USERS);
return @rv;
}

# save_usermin_miniserv_users(user, ...)
sub save_usermin_miniserv_users
{
local %miniserv;
&get_usermin_miniserv_config(\%miniserv);
&open_tempfile(USERS, ">$miniserv{'userfile'}");
local $u;
foreach $u (@_) {
	&print_tempfile(USERS,
		join(":", $u->{'name'}, $u->{'pass'}, $u->{'sync'},
			  $u->{'cert'}, $u->{'allow'}),"\n");
	}
&close_tempfile(USERS);
}

# can_use_module(module)
sub can_use_module
{
return 1 if ($access{'mods'} eq '*');
local @mods = split(/\s+/, $access{'mods'});
return &indexof($_[0], @mods) >= 0;
}

# get_usermin_base_version()
# Gets the usermin version, rounded to the nearest .01
sub get_usermin_base_version
{
return &base_version(&get_usermin_version());
}

# base_version()
# Rounds a version number to the nearest .01
sub base_version
{
return sprintf("%.2f0", $_[0]);
}

# find_cron_job(\@jobs)
sub find_cron_job
{
local ($job) = grep { $_->{'user'} eq 'root' &&
		      $_->{'command'} eq $cron_cmd } @{$_[0]};
return $job;
}

# delete_usermin_module(module, [delete-acls])
# Deletes some usermin module, clone or theme, and return a description of
# the thing deleted.
sub delete_usermin_module
{
local $m = $_[0];
return undef if (!$m);
local %minfo = &get_usermin_module_info($m);
%minfo = &get_usermin_theme_info($m) if (!%minfo);
return undef if (!%minfo);
local ($mdesc, @aclrm);
@aclrm = ( $m ) if ($_[1]);
local %miniserv;
&get_usermin_miniserv_config(\%miniserv);
local %ugconfig;
&get_usermin_config(\%uconfig);
local $mdir = "$miniserv{'root'}/$m";
local $cdir = "$config{'usermin_dir'}/$m";
if ($minfo{'clone'}) {
	# Deleting a clone
	local %cinfo;
	&read_file("$config{'usermin_dir'}/$m/clone", \%cinfo);
	&unlink_logged($mdir);
	&system_logged("rm -rf ".quotemeta($cdir));
	if ($ugconfig{'theme'}) {
		&unlink_logged("$miniserv{'root'}/$ugconfig{'theme'}/$m");
		}
	$mdesc = &webmin::text('delete_desc1', $minfo{'desc'}, $minfo{'clone'});
	}
else {
	# Delete any clones of this module
	local @clones;
	local @mst = stat($mdir);
	opendir(DIR, $miniserv{'root'});
	local $l;
	foreach $l (readdir(DIR)) {
		@lst = stat("$miniserv{'root'}/$l");
		if (-l "$miniserv{'root'}/$l" && $lst[1] == $mst[1]) {
			&unlink_logged("$miniserv{'root'}/$l");
			&system_logged("rm -rf $config{'usermin_dir'}/$l");
			push(@clones, $l);
			}
		}
	closedir(DIR);

	open(TYPE, "$mdir/install-type");
	chop($type = <TYPE>);
	close(TYPE);

	# Deleting the real module
	local $size = &disk_usage_kb($mdir);
	$mdesc = &webmin::text('delete_desc2', "<b>$minfo{'desc'}</b>",
			   "<tt>$mdir</tt>", $size);
	if ($type eq 'rpm') {
		# This module was installed from an RPM .. rpm -e it
		&system_logged("rpm -e ubm-$m");
		}
	else {
		# Module was installed from a .wbm file .. just rm it
		&system_logged("rm -rf ".quotemeta($mdir));
		}
	}

&webmin_log("delete", undef, $m, { 'desc' => $minfo{'desc'} });
return $mdesc;
}

# flush_modules_cache()
# Forces a rebuild of the Usermin module cache
sub flush_modules_cache
{
&unlink_file("$config{'usermin_dir'}/module.infos.cache");
}

# stop_usermin()
# Kills the running Usermin server process, returning undef on sucess or an
# error message on failure.
sub stop_usermin
{
local %miniserv;
&get_usermin_miniserv_config(\%miniserv);
local $pid;
if (open(PID, $miniserv{'pidfile'}) && ($pid = int(<PID>))) {
	&kill_logged('TERM', $pid) || return &text('stop_ekill', $!);
	close(PID);
	}
else {
	return $text{'stop_efile'};
	}
return undef;
}

# start_usermin()
# Starts the Usermin server process
sub start_usermin
{
&system_logged("$config{'usermin_dir'}/start >/dev/null 2>&1 </dev/null");
return undef;
}

# get_install_type()
# Returns the package type Usermin was installed form (rpm, deb, solaris-pkg
# or undef for tar.gz)
sub get_install_type
{
local (%miniserv, $mode);
&get_usermin_miniserv_config(\%miniserv);
if (open(MODE, "$miniserv{'root'}/install-type")) {
	chop($mode = <MODE>);
	close(MODE);
	}
else {
	if ($miniserv{'root'} eq "/usr/libexec/usermin") {
		$mode = "rpm";
		}
	elsif ($miniserv{'root'} eq "/usr/share/usermin") {
		$mode = "deb";
		}
	else {
		$mode = undef;
		}
	}
return $mode;
}

# switch_to_usermin_user(username)
# Returns a set-cookie header and redirect URL for auto-logging into Usermin
# as some user.
sub switch_to_usermin_user
{
my ($user) = @_;

# Stop Usermin first, so that the DBM can be safely written
my %miniserv;
&get_usermin_miniserv_config(\%miniserv);
my $stopped;
if (&check_pid_file($miniserv{'pidfile'})) {
	&stop_usermin();
	$stopped = 1;
	}

# Generate a session ID and set it in the DB
&acl::open_session_db(\%miniserv);
&seed_random();
my $now = time();
my $sid = int(rand()*$now);
$acl::sessiondb{$sid} = "$user $now $ENV{'REMOTE_ADDR'}";
dbmclose(%acl::sessiondb);
if ($stopped) {
	&start_usermin();
	}
&reload_usermin_miniserv();
eval "use Net::SSLeay";
if ($@) {
	$miniserv{'ssl'} = 0;
	}
my $ssl = $miniserv{'ssl'} || $miniserv{'inetd_ssl'};
my $sec = $ssl ? "; secure" : "";
my $sidname = $miniserv{'sidname'} || 'sid';
my $cookie = "$sidname=$sid; path=/$sec";

# Work out redirect host
my @sockets = &webmin::get_miniserv_sockets(\%miniserv);
my ($host, $port);
if ($config{'host'}) {
	# Specific hostname set
	$host = $config{'host'};
	}
else {
	if ($sockets[0]->[0] ne "*") {
		# Listening on special IP
		$host = $sockets[0]->[0];
		$port = $sockets[0]->[1] if ($sockets[0]->[1] ne '*');
		}
	else {
		# Use same hostname as this server
		$host = $ENV{'HTTP_HOST'};
		$host =~ s/:.*//;
		}
	}
$port ||= $config{'port'} || $miniserv{'port'};

return ($cookie, ($ssl ? "https://" : "http://").$host.":".$port."/");
}

1;

