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