Handle hostnames with upper-case letters
[webmin.git] / chooser.cgi
1 #!/usr/local/bin/perl
2 # chooser.cgi
3 # Outputs HTML for a frame-based file chooser 
4
5 BEGIN { push(@INC, ".."); };
6 use WebminCore;
7
8 @icon_map = (   "c", "text.gif",
9                 "txt", "text.gif",
10                 "pl", "text.gif",
11                 "cgi", "text.gif",
12                 "html", "text.gif",
13                 "htm", "text.gif",
14                 "gif", "image.gif",
15                 "jpg", "image.gif",
16                 "tar", "binary.gif"
17                 );
18
19 $trust_unknown_referers = 1;
20 &init_config();
21 if (&get_product_name() eq 'usermin') {
22         &switch_to_remote_user();
23         }
24 %access = &get_module_acl();
25
26 # Work out root directory
27 local @uinfo = getpwnam($remote_user);
28 if (!$access{'root'}) {
29         $rootdir = $uinfo[7] ? $uinfo[7] : "/";
30         }
31 else {
32         $rootdir = $access{'root'};
33         $rootdir =~ s/^\~/$uinfo[7]/;
34         }
35
36 # Switch to correct Unix user
37 if (&supports_users()) {
38         if (&get_product_name() eq 'usermin') {
39                 # Always run as Usermin login
40                 &switch_to_remote_user();
41                 }
42         else {
43                 # ACL determines
44                 $fileunix = $access{'fileunix'} || $remote_user;
45                 @uinfo = getpwnam($fileunix);
46                 if (@uinfo) {
47                         &switch_to_unix_user(\@uinfo);
48                         }
49                 }
50         }
51
52 &ReadParse(undef, undef, 1);
53 if ($gconfig{'os_type'} eq 'windows') {
54         # On Windows, chroot should be empty if not use, and default path
55         # should be c:/
56         if ($in{'chroot'} eq "/") {
57                 $in{'chroot'} = "";
58                 }
59         if ($rootdir eq "/") {
60                 $rootdir = "c:";
61                 }
62         }
63 if ($in{'add'}) {
64         # Only use last filename by default
65         $in{'file'} =~ s/\s+$//;
66         if ($in{'file'} =~ /\n(.*)$/) {
67                 $in{'file'} = $1;
68                 }
69         }
70 if ($in{'file'} =~ /^(([a-z]:)?.*\/)([^\/]*)$/i && $in{'file'} !~ /\.\./) {
71         # File entered is valid
72         $dir = $1;
73         $file = $3;
74         }
75 else {
76         # Fall back to default
77         $dir = $rootdir;
78         $dir .= '/' if ($dir !~ /\/$/);
79         $file = "";
80         }
81 $add = int($in{'add'});
82
83 if (!(-d $in{'chroot'}.$dir)) {
84         # Entered directory does not exist
85         $dir = $rootdir.'/';
86         $file = "";
87         }
88 if (!&allowed_dir($dir)) {
89         # Directory is outside allowed root
90         $dir = $rootdir.'/';
91         $file = "";
92         }
93
94 # Work out the top allowed dir
95 $topdir = $rootdir eq "/" || $rootdir eq "c:" ? $rootdir :
96           $access{'otherdirs'} ? "/" : $rootdir;
97 $uchroot = &urlize($in{'chroot'});
98 $utype = &urlize($in{'type'});
99 $ufile = &urlize($in{'file'});
100
101 if ($in{'frame'} == 0) {
102         # base frame
103         &PrintHeader();
104         if ($in{'type'} == 0) {
105                 print "<title>$text{'chooser_title1'}</title>\n";
106                 }
107         elsif ($in{'type'} == 1) {
108                 print "<title>$text{'chooser_title2'}</title>\n";
109                 }
110         print "<frameset rows='*,50'>\n";
111         print "<frame marginwidth=5 marginheight=5 name=topframe ",
112              "src=\"chooser.cgi?frame=1&file=".$ufile.
113              "&chroot=".$uchroot."&type=".$utype."&add=$add\">\n";
114         print "<frame marginwidth=0 marginheight=0 name=bottomframe ",
115               "src=\"chooser.cgi?frame=2&file=".$ufile.
116               "&chroot=".$uchroot."&type=".$utype."&add=$add\" scrolling=no>\n";
117         print "</frameset>\n";
118         }
119 elsif ($in{'frame'} == 1) {
120         # List of files in this directory
121         &popup_header();
122         print <<EOF;
123 <script>
124 function fileclick(f, d)
125 {
126 curr = top.frames[1].document.forms[0].elements[1].value;
127 if (curr == f) {
128         // Double-click! Enter directory or select file
129         if (d) {
130                 // Enter this directory
131                 location = "chooser.cgi?frame=1&add=$add&chroot=$uchroot&type=$utype&file="+f+"/";
132                 }
133         else {
134                 // Select this file and close the window
135                 if ($add == 0) {
136                         top.opener.ifield.value = f;
137                         }
138                 else {
139                         if (top.opener.ifield.value != "") {
140                                 top.opener.ifield.value += "\\n";
141                                 }
142                         top.opener.ifield.value += f;
143                         }
144                 top.close();
145                 }
146         }
147 else {
148         top.frames[1].document.forms[0].elements[1].value = f;
149         }
150 }
151
152 function parentdir(p)
153 {
154 top.frames[1].document.forms[0].elements[1].value = p;
155 location = "chooser.cgi?frame=1&chroot=$uchroot&type=$utype&file="+p;
156 }
157 </script>
158 EOF
159
160         print "<b>",&text('chooser_dir', &html_escape($dir)),"</b>\n";
161         opendir(DIR, $in{'chroot'}.$dir) ||
162                 &popup_error(&text('chooser_eopen', "$!"));
163         print &ui_columns_start(undef, 100);
164         foreach $f (sort { $a cmp $b } readdir(DIR)) {
165                 $path = "$in{'chroot'}$dir$f";
166                 if ($f eq ".") { next; }
167                 if ($f eq ".." && ($dir eq "/" || $dir eq $topdir.'/')) { next; }
168                 if ($f =~ /^\./ && $f ne ".." && $access{'nodot'}) { next; }
169                 if (!(-d $path) && $in{'type'} == 1) { next; }
170
171                 @st = stat($path);
172                 $isdir = 0; undef($icon);
173                 if (-d $path) { $icon = "dir.gif"; $isdir = 1; }
174                 elsif ($path =~ /\.([^\.\/]+)$/) { $icon = $icon_map{$1}; }
175                 if (!$icon) { $icon = "unknown.gif"; }
176
177                 if ($f eq "..") {
178                         $dir =~ /^(.*\/)[^\/]+\/$/;
179                         $link = "<a href=\"\" onClick='parentdir(\"".&quote_escape($1)."\"); return false'>";
180                         }
181                 else {
182                         $link = "<a href=\"\" onClick='fileclick(\"".&quote_escape("$dir$f")."\", $isdir); return false'>";
183                         }
184                 local @cols;
185                 push(@cols, "$link<img border=0 src=$gconfig{'webprefix'}/images/$icon></a>");
186                 push(@cols, "$link".&html_escape($f)."</a>");
187                 push(@cols, &nice_size($st[7]));
188                 @tm = localtime($st[9]);
189                 push(@cols, sprintf "<tt>%.2d/%s/%.4d</tt>",
190                         $tm[3], $text{'smonth_'.($tm[4]+1)}, $tm[5]+1900);
191                 push(@cols, sprintf "<tt>%.2d:%.2d</tt>", $tm[2], $tm[1]);
192                 print &ui_columns_row(\@cols);
193                 }
194         closedir(DIR);
195         print &ui_columns_end();
196         &popup_footer();
197         }
198 elsif ($in{'frame'} == 2) {
199         # Current file and OK/cancel buttons
200         &popup_header();
201         print <<EOF;
202 <script>
203 function filechosen()
204 {
205 if ($add == 0) {
206         top.opener.ifield.value = document.forms[0].path.value;
207         }
208 else {
209         if (top.opener.ifield.value != "") {
210                 top.opener.ifield.value += "\\n";
211                 }
212         top.opener.ifield.value += document.forms[0].path.value;
213         }
214 top.close();
215 }
216 </script>
217 EOF
218         print &ui_form_start(undef, undef, undef,
219                 "onSubmit='filechosen(); return false'");
220         print &ui_table_start(undef, "width=100%", 2);
221         print &ui_table_row(undef,
222                 &ui_submit($text{'chooser_ok'})." ".
223                 &ui_textbox("path", $dir.$file, 45, 0, undef,
224                             "style='width:90%'"), 2);
225         print &ui_table_end();
226         print &ui_form_end();
227         &popup_footer();
228         }
229
230 # allowed_dir(dir)
231 # Returns 1 if some directory should be listable
232 sub allowed_dir
233 {
234 local ($dir) = @_;
235 return 1 if ($rootdir eq "" || $rootdir eq "/" || $rootdir eq "c:");
236 foreach my $allowed ($rootdir, split(/\t+/, $access{'otherdirs'})) {
237         return 1 if (&is_under_directory($allowed, $dir));
238         }
239 return 0;
240 }