#!/usr/local/bin/perl
# chooser.cgi
# Outputs HTML for a frame-based file chooser
BEGIN { push(@INC, ".."); };
use WebminCore;
@icon_map = ( "c", "text.gif",
"txt", "text.gif",
"pl", "text.gif",
"cgi", "text.gif",
"html", "text.gif",
"htm", "text.gif",
"gif", "image.gif",
"jpg", "image.gif",
"tar", "binary.gif"
);
$trust_unknown_referers = 1;
&init_config();
if (&get_product_name() eq 'usermin') {
&switch_to_remote_user();
}
%access = &get_module_acl();
# Work out root directory
local @uinfo = getpwnam($remote_user);
if (!$access{'root'}) {
$rootdir = $uinfo[7] ? $uinfo[7] : "/";
}
else {
$rootdir = $access{'root'};
$rootdir =~ s/^\~/$uinfo[7]/;
}
# Switch to correct Unix user
if (&supports_users()) {
if (&get_product_name() eq 'usermin') {
# Always run as Usermin login
&switch_to_remote_user();
}
else {
# ACL determines
$fileunix = $access{'fileunix'} || $remote_user;
@uinfo = getpwnam($fileunix);
if (@uinfo) {
&switch_to_unix_user(\@uinfo);
}
}
}
&ReadParse(undef, undef, 1);
if ($gconfig{'os_type'} eq 'windows') {
# On Windows, chroot should be empty if not use, and default path
# should be c:/
if ($in{'chroot'} eq "/") {
$in{'chroot'} = "";
}
if ($rootdir eq "/") {
$rootdir = "c:";
}
}
if ($in{'add'}) {
# Only use last filename by default
$in{'file'} =~ s/\s+$//;
if ($in{'file'} =~ /\n(.*)$/) {
$in{'file'} = $1;
}
}
if ($in{'file'} =~ /^(([a-z]:)?.*\/)([^\/]*)$/i && $in{'file'} !~ /\.\./) {
# File entered is valid
$dir = $1;
$file = $3;
}
else {
# Fall back to default
$dir = $rootdir;
$dir .= '/' if ($dir !~ /\/$/);
$file = "";
}
$add = int($in{'add'});
if (!(-d $in{'chroot'}.$dir)) {
# Entered directory does not exist
$dir = $rootdir.'/';
$file = "";
}
if (!&allowed_dir($dir)) {
# Directory is outside allowed root
$dir = $rootdir.'/';
$file = "";
}
# Work out the top allowed dir
$topdir = $rootdir eq "/" || $rootdir eq "c:" ? $rootdir :
$access{'otherdirs'} ? "/" : $rootdir;
$uchroot = &urlize($in{'chroot'});
$utype = &urlize($in{'type'});
$ufile = &urlize($in{'file'});
if ($in{'frame'} == 0) {
# base frame
&PrintHeader();
if ($in{'type'} == 0) {
print "
$text{'chooser_title1'}\n";
}
elsif ($in{'type'} == 1) {
print "$text{'chooser_title2'}\n";
}
print "\n";
}
elsif ($in{'frame'} == 1) {
# List of files in this directory
&popup_header();
print <
function fileclick(f, d)
{
curr = top.frames[1].document.forms[0].elements[1].value;
if (curr == f) {
// Double-click! Enter directory or select file
if (d) {
// Enter this directory
location = "chooser.cgi?frame=1&add=$add&chroot=$uchroot&type=$utype&file="+f+"/";
}
else {
// Select this file and close the window
if ($add == 0) {
top.opener.ifield.value = f;
}
else {
if (top.opener.ifield.value != "") {
top.opener.ifield.value += "\\n";
}
top.opener.ifield.value += f;
}
top.close();
}
}
else {
top.frames[1].document.forms[0].elements[1].value = f;
}
}
function parentdir(p)
{
top.frames[1].document.forms[0].elements[1].value = p;
location = "chooser.cgi?frame=1&chroot=$uchroot&type=$utype&file="+p;
}
EOF
print "",&text('chooser_dir', &html_escape($dir)),"\n";
opendir(DIR, $in{'chroot'}.$dir) ||
&popup_error(&text('chooser_eopen', "$!"));
print &ui_columns_start(undef, 100);
foreach $f (sort { $a cmp $b } readdir(DIR)) {
$path = "$in{'chroot'}$dir$f";
if ($f eq ".") { next; }
if ($f eq ".." && ($dir eq "/" || $dir eq $topdir.'/')) { next; }
if ($f =~ /^\./ && $f ne ".." && $access{'nodot'}) { next; }
if (!(-d $path) && $in{'type'} == 1) { next; }
@st = stat($path);
$isdir = 0; undef($icon);
if (-d $path) { $icon = "dir.gif"; $isdir = 1; }
elsif ($path =~ /\.([^\.\/]+)$/) { $icon = $icon_map{$1}; }
if (!$icon) { $icon = "unknown.gif"; }
if ($f eq "..") {
$dir =~ /^(.*\/)[^\/]+\/$/;
$link = "";
}
else {
$link = "";
}
local @cols;
push(@cols, "$link");
push(@cols, "$link".&html_escape($f)."");
push(@cols, &nice_size($st[7]));
@tm = localtime($st[9]);
push(@cols, sprintf "%.2d/%s/%.4d",
$tm[3], $text{'smonth_'.($tm[4]+1)}, $tm[5]+1900);
push(@cols, sprintf "%.2d:%.2d", $tm[2], $tm[1]);
print &ui_columns_row(\@cols);
}
closedir(DIR);
print &ui_columns_end();
&popup_footer();
}
elsif ($in{'frame'} == 2) {
# Current file and OK/cancel buttons
&popup_header();
print <
function filechosen()
{
if ($add == 0) {
top.opener.ifield.value = document.forms[0].path.value;
}
else {
if (top.opener.ifield.value != "") {
top.opener.ifield.value += "\\n";
}
top.opener.ifield.value += document.forms[0].path.value;
}
top.close();
}
EOF
print &ui_form_start(undef, undef, undef,
"onSubmit='filechosen(); return false'");
print &ui_table_start(undef, "width=100%", 2);
print &ui_table_row(undef,
&ui_submit($text{'chooser_ok'})." ".
&ui_textbox("path", $dir.$file, 45, 0, undef,
"style='width:90%'"), 2);
print &ui_table_end();
print &ui_form_end();
&popup_footer();
}
# allowed_dir(dir)
# Returns 1 if some directory should be listable
sub allowed_dir
{
local ($dir) = @_;
return 1 if ($rootdir eq "" || $rootdir eq "/" || $rootdir eq "c:");
foreach my $allowed ($rootdir, split(/\t+/, $access{'otherdirs'})) {
return 1 if (&is_under_directory($allowed, $dir));
}
return 0;
}