Handle hostnames with upper-case letters
[webmin.git] / squid / acl_save.cgi
1 #!/usr/local/bin/perl
2 # acl_save.cgi
3 # Save or delete an ACL
4
5 require './squid-lib.pl';
6 $access{'actrl'} || &error($text{'eacl_ecannot'});
7 &ReadParseMime();
8 &lock_file($config{'squid_conf'});
9 $conf = &get_config();
10 $whatfailed = $text{'aclsave_failsave'};
11
12 @acls = &find_config("acl", $conf);
13 @denys = &find_config("deny_info", $conf);
14 if (defined($in{'index'})) {
15         $acl = $conf->[$in{'index'}];
16         }
17 if (defined($in{'dindex'})) {
18         $deny = $conf->[$in{'dindex'}];
19         }
20 if ($in{'delete'}) {
21         # Is there more than one ACL with this name?
22         $name = $acl->{'values'}->[0];
23         foreach $a (&find_config("acl", $conf)) {
24                 $count++ if ($a->{'values'}->[0] eq $name);
25                 }
26
27         # Is this ACL in use?
28         $whatfailed = $text{'aclsave_faildel'};
29         if ($count == 1) {
30                 foreach $h (&find_config("http_access", $conf)) {
31                         @v = @{$h->{'values'}};
32                         for($i=1; $i<@v;  $i++) {
33                                 if ($v[$i] eq $name || $v[$i] eq "!$name") {
34                                         &error($text{'aclsave_epr'});
35                                         }
36                                 }
37                         }
38                 foreach $h (&find_config("icp_access", $conf)) {
39                         @v = @{$h->{'values'}};
40                         for($i=1; $i<@v;  $i++) {
41                                 if ($v[$i] eq $in{'name'} ||
42                                     $v[$i] eq "!$in{'name'}") {
43                                         &error($text{'aclsave_eicpr'});
44                                         }
45                                 }
46                         }
47                 }
48         splice(@acls, &indexof($acl, @acls), 1);
49         if ($deny) { splice(@denys, &indexof($deny, @denys), 1); }
50         $logacl = $acl;
51         }
52 else {
53         # Check ACL details
54         $in{'name'} =~ /^\S+$/ || &error($text{'aclsave_ename'});
55         $changed++ if ($acl && $in{'name'} ne $acl->{'values'}->[0]);
56         for($i=0; $i<@acls; $i++) {
57                 if ($changed && $acls[$i]->{'values'}->[0] eq $in{'name'}) {
58                         &error(&text('aclsave_eexists',$in{'name'}));
59                         }
60                 }
61
62         if ($in{'type'} eq "src" || $in{'type'} eq "dst") {
63                 for($i=0; defined($from = $in{"from_$i"}); $i++) {
64                         $to = $in{"to_$i"}; $mask = $in{"mask_$i"};
65                         next if (!$from && !$to && !$mask);
66                         &check_ipaddress($from) ||
67                             &check_ip6address($from) ||
68                                &error(&text('aclsave_efrom',$from));
69                         !$to || &check_ipaddress($to) ||
70                            &check_ip6address($to) ||
71                                &error(&text('aclsave_eto',$to));
72                         $mask =~ /^\d*$/ || &check_ipaddress($mask) ||
73                                &error(&text('aclsave_enmask',$mask));
74                         if ($to && $mask) { push(@vals, "$from-$to/$mask"); }
75                         elsif ($to) { push(@vals, "$from-$to"); }
76                         elsif ($mask) { push(@vals, "$from/$mask"); }
77                         else { push(@vals, $from); }
78                         }
79                 }
80         elsif ($in{'type'} eq "myip") {
81                 for($i=0; defined($ip = $in{"ip_$i"}); $i++) {
82                         $mask = $in{"mask_$i"};
83                         next if (!$mask || !$ip);
84                         &check_ipaddress($ip) || &check_ip6address($ip) ||
85                                 &error(&text('aclsave_eip',$ip));
86                         $mask =~ /^\d+$/ || &check_ipaddress($mask) ||
87                                &error(&text('aclsave_enmask',$mask));
88                         push(@vals, "$ip/$mask");
89                         }
90                 }
91         elsif ($in{'type'} eq "srcdomain") {
92                 push(@vals, split(/[\r\n]+/, $in{'vals'}));
93                 if (!@vals && !$in{'keep'}) { &error($text{'aclsave_ecdom'}); }
94                 }
95         elsif ($in{'type'} eq "dstdomain") {
96                 push(@vals, split(/[\r\n]+/, $in{'vals'}));
97                 if (!@vals && !$in{'keep'}) { &error($text{'aclsave_esdom'}); }
98                 }
99         elsif ($in{'type'} eq "time") {
100                 if (!$in{'day_def'}) {
101                         push(@vals, join('', split(/\0/, $in{'day'})));
102                         }
103                 if (!$in{'hour_def'}) {
104                         $in{'h1'} =~ /^\d+$/ || &error($text{'aclsave_eshour'});
105                         $in{'h2'} =~ /^\d+$/ || &error($text{'aclsave_eehour'});
106                         $in{'m1'} =~ /^\d+$/ || &error($text{'aclsave_esmin'});
107                         $in{'m2'} =~ /^\d+$/ || &error($text{'aclsave_eemin'});
108                         push(@vals, "$in{'h1'}:$in{'m1'}-$in{'h2'}:$in{'m2'}");
109                         }
110                 }
111         elsif ($in{'type'} eq "url_regex") {
112                 push(@vals, "-i") if ($in{'caseless'});
113                 push(@vals, split(/[\r\n]+/, $in{'vals'}));
114                 }
115         elsif ($in{'type'} eq "urlpath_regex") {
116                 push(@vals, "-i") if ($in{'caseless'});
117                 push(@vals, split(/[\r\n]+/, $in{'vals'}));
118                 }
119         elsif ($in{'type'} eq "port") {
120                 push(@vals, split(/\s+/, $in{'vals'}));
121                 }
122         elsif ($in{'type'} eq "proto") {
123                 push(@vals, split(/\0/, $in{'vals'}));
124                 }
125         elsif ($in{'type'} eq "method") {
126                 push(@vals, split(/\0/, $in{'vals'}));
127                 }
128         elsif ($in{'type'} eq "browser" || $in{'type'} eq "snmp_community"
129             || $in{'type'} eq "req_mime_type" || $in{'type'} eq "rep_mime_type") {
130                 push(@vals, $in{'vals'});
131                 }
132         elsif ($in{'type'} eq "user" || $in{'type'} eq "ident") {
133                 push(@vals, split(/[\r\n]+/, $in{'vals'}));
134                 }
135         elsif ($in{'type'} eq "src_as" || $in{'type'} eq "dst_as") {
136                 push(@vals, split(/\s+/, $in{'vals'}));
137                 }
138         elsif ($in{'type'} eq "proxy_auth" && $squid_version < 2.3) {
139                 push(@vals, $in{'vals'}) if ($in{'vals'});
140                 }
141         elsif ($in{'type'} eq "proxy_auth" && $squid_version >= 2.3) {
142                 push(@vals, $in{'authall'} ? "REQUIRED"
143                                            : split(/[\r\n]+/, $in{'vals'}));
144                 }
145         elsif ($in{'type'} eq "proxy_auth_regex" ||
146                $in{'type'} eq "ident_regex") {
147                 push(@vals, "-i") if ($in{'caseless'});
148                 push(@vals, split(/[\r\n]+/, $in{'vals'}));
149                 }
150         elsif ($in{'type'} eq "srcdom_regex" || $in{'type'} eq "dstdom_regex") {
151                 push(@vals, "-i") if ($in{'caseless'});
152                 push(@vals, split(/[\r\n]+/, $in{'vals'}));
153                 }
154         elsif ($in{'type'} eq "myport") {
155                 $in{'vals'} =~ /^\d+$/ ||
156                         &error("'$in{'vals'}' is not a valid port number");
157                 push(@vals, $in{'vals'});
158                 }
159         elsif ($in{'type'} eq "maxconn") {
160                 $in{'vals'} =~ /^\d+$/ ||
161                     &error("'$in{'vals'}' is not a valid number of requests");
162                 push(@vals, $in{'vals'});
163                 }
164         elsif ($in{'type'} eq "arp") {
165                 push(@vals, split(/[\r\n]+/, $in{'vals'}));
166                 }
167         elsif ($in{'type'} eq "external") {
168                 $in{'class'} || &error($text{'eacl_eclass'});
169                 push(@vals, $in{'class'});
170                 push(@vals, split(/\s+/, $in{'args'}));
171                 }
172         elsif ($in{'type'} eq "max_user_ip") {
173                 if($in{'strict'}){
174                         push(@vals, '-s');
175                 }
176                 push(@vals, $in{'vals'});
177                 }
178
179         if (!$in{'file_def'}) {
180                 # Writing to an external file
181                 $in{'file'} || &error($text{'aclsave_enofile'});
182                 &can_access($in{'file'}) ||
183                         &error(&text('aclsave_efile', $in{'file'}));
184                 if ($in{'type'} eq 'external' ||
185                     &indexof($in{'type'}, @caseless_acl_types) >= 0 &&
186                     $vals[0] eq "-i") {
187                         # Special case .. first parameter does NOT go into file
188                         @notvals = ( shift(@vals) );
189                         }
190                 if (!$in{'keep'}) {
191                         if (!$acl && -e $in{'file'}) {
192                                 &error($text{'aclsave_ealready'});
193                                 }
194                         &open_lock_tempfile(FILE, ">$in{'file'}");
195                         foreach $v (@vals) {
196                                 &print_tempfile(FILE, $v,"\n");
197                                 }
198                         &close_tempfile(FILE);
199                         }
200                 @vals = ( $in{'name'}, $in{'type'}, @notvals, "\"$in{'file'}\"" );
201                 }
202         else {
203                 # Just saving in Squid config directly
204                 if ($vals[0] =~ /^"(.*)"$/) {
205                         local $f = $1;
206                         &can_access($f) ||
207                                 &error(&text('aclsave_efile', $f));
208                         if ($f !~ /^\// && $access{'root'} ne '/') {
209                                 $vals[0] = "\"$access{'root'}/$f\"";
210                                 }
211                         
212                         }
213                 @vals = ( $in{'name'}, $in{'type'}, @vals );
214                 }
215         $logacl = $newacl = { 'name' => 'acl', 'values' => \@vals };
216         if ($acl) { splice(@acls, &indexof($acl, @acls), 1, $newacl); }
217         else { push(@acls, $newacl); }
218
219         $newdeny = { 'name' => 'deny_info',
220                      'values' => [ $in{'deny'}, $vals[0] ] };
221         $didx = &indexof($deny, @denys);
222         if ($deny && $in{'deny'}) { $denys[$didx] = $newdeny; }
223         elsif ($deny) { splice(@denys, $didx, 1); }
224         elsif ($in{'deny'}) { push(@denys, $newdeny); }
225
226         # Update http_access and icp_access directives if the ACL was renamed
227         if ($changed) {
228                 @https = &find_config("http_access", $conf);
229                 @icps = &find_config("icp_access", $conf);
230                 $on = $acl->{'values'}->[0];
231                 foreach $c (@https, @icps) {
232                         for($j=1; $j<@{$c->{'values'}}; $j++) {
233                                 if ($c->{'values'}->[$j] eq $on) {
234                                         $c->{'values'}->[$j] = $in{'name'};
235                                         }
236                                 elsif ($c->{'values'}->[$j] eq "!$on") {
237                                         $c->{'values'}->[$j] = "!$in{'name'}";
238                                         }
239                                 }
240                         }
241                 &save_directive($conf, "http_access", \@https);
242                 &save_directive($conf, "icp_access", \@icps);
243                 }
244         }
245 &save_directive($conf, "acl", \@acls);
246 &save_directive($conf, "deny_info", \@denys);
247 &flush_file_lines();
248 &unlock_file($config{'squid_conf'});
249 &webmin_log($in{'delete'} ? 'delete' : $acl ? 'modify' : 'create',
250             'acl', $logacl->{'values'}->[0], \%in);
251 &redirect("edit_acl.cgi?mode=acls");
252