Use &switch_to_unix_user
[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 %access = &get_module_acl();
22
23 # Work out root directory
24 if (!$access{'root'}) {
25         local @uinfo = getpwnam($remote_user);
26         $rootdir = $uinfo[7] ? $uinfo[7] : "/";
27         }
28 else {
29         $rootdir = $access{'root'};
30         }
31
32 # Switch to correct Unix user
33 if (&supports_users()) {
34         if (&get_product_name() eq 'usermin') {
35                 # Always run as Usermin login
36                 &switch_to_remote_user();
37                 }
38         else {
39                 # ACL determines
40                 $fileunix = $access{'fileunix'} || $remote_user;
41                 @uinfo = getpwnam($fileunix);
42                 if (@uinfo) {
43                         &switch_to_unix_user(\@uinfo);
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 $uchroot = &urlize($in{'chroot'});
94 $utype = &urlize($in{'type'});
95 $ufile = &urlize($in{'file'});
96
97 if ($in{'frame'} == 0) {
98         # base frame
99         &PrintHeader();
100         if ($in{'type'} == 0) {
101                 print "<title>$text{'chooser_title1'}</title>\n";
102                 }
103         elsif ($in{'type'} == 1) {
104                 print "<title>$text{'chooser_title2'}</title>\n";
105                 }
106         print "<frameset rows='*,50'>\n";
107         print "<frame marginwidth=5 marginheight=5 name=topframe ",
108              "src=\"chooser.cgi?frame=1&file=".$ufile.
109              "&chroot=".$uchroot."&type=".$utype."&add=$add\">\n";
110         print "<frame marginwidth=0 marginheight=0 name=bottomframe ",
111               "src=\"chooser.cgi?frame=2&file=".$ufile.
112               "&chroot=".$uchroot."&type=".$utype."&add=$add\" scrolling=no>\n";
113         print "</frameset>\n";
114         }
115 elsif ($in{'frame'} == 1) {
116         # List of files in this directory
117         &popup_header();
118         print <<EOF;
119 <script>
120 function fileclick(f, d)
121 {
122 curr = top.frames[1].document.forms[0].elements[1].value;
123 if (curr == f) {
124         // Double-click! Enter directory or select file
125         if (d) {
126                 // Enter this directory
127                 location = "chooser.cgi?frame=1&add=$add&chroot=$uchroot&type=$utype&file="+f+"/";
128                 }
129         else {
130                 // Select this file and close the window
131                 if ($add == 0) {
132                         top.opener.ifield.value = f;
133                         }
134                 else {
135                         if (top.opener.ifield.value != "") {
136                                 top.opener.ifield.value += "\\n";
137                                 }
138                         top.opener.ifield.value += f;
139                         }
140                 top.close();
141                 }
142         }
143 else {
144         top.frames[1].document.forms[0].elements[1].value = f;
145         }
146 }
147
148 function parentdir(p)
149 {
150 top.frames[1].document.forms[0].elements[1].value = p;
151 location = "chooser.cgi?frame=1&chroot=$uchroot&type=$utype&file="+p;
152 }
153 </script>
154 EOF
155
156         print "<b>",&text('chooser_dir', &html_escape($dir)),"</b>\n";
157         opendir(DIR, $in{'chroot'}.$dir) ||
158                 &popup_error(&text('chooser_eopen', "$!"));
159         print &ui_columns_start(undef, 100);
160         foreach $f (sort { $a cmp $b } readdir(DIR)) {
161                 $path = "$in{'chroot'}$dir$f";
162                 if ($f eq ".") { next; }
163                 if ($f eq ".." && ($dir eq "/" || $dir eq $topdir.'/')) { next; }
164                 if ($f =~ /^\./ && $f ne ".." && $access{'nodot'}) { next; }
165                 if (!(-d $path) && $in{'type'} == 1) { next; }
166
167                 @st = stat($path);
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                 local @cols;
181                 push(@cols, "$link<img border=0 src=$gconfig{'webprefix'}/images/$icon></a>");
182                 push(@cols, "$link".&html_escape($f)."</a>");
183                 push(@cols, &nice_size($st[7]));
184                 @tm = localtime($st[9]);
185                 push(@cols, sprintf "<tt>%.2d/%s/%.4d</tt>",
186                         $tm[3], $text{'smonth_'.($tm[4]+1)}, $tm[5]+1900);
187                 push(@cols, sprintf "<tt>%.2d:%.2d</tt>", $tm[2], $tm[1]);
188                 print &ui_columns_row(\@cols);
189                 }
190         closedir(DIR);
191         print &ui_columns_end();
192         &popup_footer();
193         }
194 elsif ($in{'frame'} == 2) {
195         # Current file and OK/cancel buttons
196         &popup_header();
197         print <<EOF;
198 <script>
199 function filechosen()
200 {
201 if ($add == 0) {
202         top.opener.ifield.value = document.forms[0].path.value;
203         }
204 else {
205         if (top.opener.ifield.value != "") {
206                 top.opener.ifield.value += "\\n";
207                 }
208         top.opener.ifield.value += document.forms[0].path.value;
209         }
210 top.close();
211 }
212 </script>
213 EOF
214         print &ui_form_start(undef, undef, undef,
215                 "onSubmit='filechosen(); return false'");
216         print &ui_table_start(undef, "width=100%", 2);
217         print &ui_table_row(undef,
218                 &ui_submit($text{'chooser_ok'})." ".
219                 &ui_textbox("path", $dir.$file, 45, 0, undef,
220                             "style='width:90%'"), 2);
221         print &ui_table_end();
222         print &ui_form_end();
223         &popup_footer();
224         }
225
226 # allowed_dir(dir)
227 # Returns 1 if some directory should be listable
228 sub allowed_dir
229 {
230 local ($dir) = @_;
231 return 1 if ($rootdir eq "" || $rootdir eq "/" || $rootdir eq "c:");
232 foreach my $allowed ($rootdir, split(/\t+/, $access{'otherdirs'})) {
233         return 1 if (&is_under_directory($allowed, $dir));
234         }
235 return 0;
236 }