Gro├čes Update:
[ipfire-2.x.git] / html / cgi-bin / wireless.cgi
1 #!/usr/bin/perl
2 #
3 # IPFire CGIs
4 #
5 # This code is distributed under the terms of the GPL
6 #
7 # (c) 2003 Alan Hourihane <alanh@fairlite.demon.co.uk>
8 # (c) 2005 Eric Oberlander, Robert Kerr - Inline editing & DHCP leases
9 #
10 # $Id: wireless.cgi,v 1.4.2.15 2005/06/11 12:14:49 eoberlander Exp $
11 #
12
13 use strict;
14 use Time::Local;
15
16 # enable only the following on debugging purpose
17 #use warnings;
18 #use CGI::Carp 'fatalsToBrowser';
19
20 require 'CONFIG_ROOT/general-functions.pl';
21 require "${General::swroot}/lang.pl";
22 require "${General::swroot}/header.pl";
23
24 #workaround to suppress a warning when a variable is used only once
25 my @dummy = ( ${Header::colouryellow} );
26 undef (@dummy);
27
28 my %cgiparams=();
29 my %checked=();
30 my $errormessage = '';
31 my $filename = "${General::swroot}/wireless/config";
32 my $hostsfile = "${General::swroot}/main/hosts";
33 our %dhcpsettings=(); 
34 our %netsettings=();
35
36 $cgiparams{'ENABLED'} = 'off';
37 $cgiparams{'ACTION'} = '';
38 $cgiparams{'VALID'} = '';
39 $cgiparams{'SOURCE_IP'} ='';
40 $cgiparams{'SOURCE_MAC'} ='';
41 $cgiparams{'REMARK'} ='';
42
43 &Header::getcgihash(\%cgiparams);
44
45 &General::readhash("${General::swroot}/dhcp/settings", \%dhcpsettings);
46 &General::readhash("${General::swroot}/ethernet/settings", \%netsettings);
47
48 &Header::showhttpheaders();
49
50 open(FILE, $filename) or die 'Unable to open config file.';
51 my @current = <FILE>;
52 close(FILE);
53
54 if ($cgiparams{'ACTION'} eq 'add')
55 {
56
57         if ($cgiparams{'SOURCE_IP'} eq '' && $cgiparams{'SOURCE_MAC'} eq '')
58         {
59                 goto ADDEXIT;
60         }
61
62         $cgiparams{'SOURCE_MAC'} =~ tr/-/:/;
63
64         my $key = 0;
65         foreach my $line (@current)
66         {
67                 $key++;
68                 my @temp = split(/\,/,$line);
69
70                 if ($temp[1] ne '' && $cgiparams{'SOURCE_IP'} eq $temp[1] && $cgiparams{'EDITING'} ne $key)
71                 {
72                         $errormessage = $Lang::tr{'duplicate ip'};
73                         goto ADDERROR;
74                 }
75                 if ($temp[2] ne '' && lc($cgiparams{'SOURCE_MAC'}) eq lc($temp[2]) && $cgiparams{'EDITING'} ne $key)
76                 {
77                         $errormessage = $Lang::tr{'duplicate mac'};
78                         goto ADDERROR;
79                 }
80         }
81
82         if ($cgiparams{'SOURCE_IP'} eq '')
83         {
84                 $cgiparams{'SOURCE_IP'} = 'NONE';
85         } else {
86                 unless(&General::validip($cgiparams{'SOURCE_IP'})) 
87                 {
88                         $errormessage = $Lang::tr{'invalid fixed ip address'}; 
89                         goto ADDERROR;
90                 }
91         }
92         if ($cgiparams{'SOURCE_MAC'} eq '')
93         {
94                 $cgiparams{'SOURCE_MAC'} = 'NONE';
95         } else {
96                 unless(&General::validmac($cgiparams{'SOURCE_MAC'})) 
97                 { 
98                         $errormessage = $Lang::tr{'invalid fixed mac address'}; 
99                 }
100         }
101
102 ADDERROR:
103         if ($errormessage)
104         {
105                 $cgiparams{'SOURCE_MAC'} = '' if $cgiparams{'SOURCE_MAC'} eq 'NONE';
106                 $cgiparams{'SOURCE_IP'} = '' if $cgiparams{'SOURCE_IP'} eq 'NONE';
107         } else {
108                 if ($cgiparams{'EDITING'} eq 'no') {
109                         open(FILE,">>$filename") or die 'Unable to open config file.';
110                         flock FILE, 2;
111                         print FILE "$key,$cgiparams{'SOURCE_IP'},$cgiparams{'SOURCE_MAC'},$cgiparams{'ENABLED'},$cgiparams{'REMARK'}\n";
112                 } else {
113                         open(FILE,">$filename") or die 'Unable to open config file.';
114                         flock FILE, 2;
115                         my $id = 0;
116                         foreach my $line (@current)
117                         {
118                                 $id++;
119                                 if ($cgiparams{'EDITING'} eq $id) {
120                                         print FILE "$id,$cgiparams{'SOURCE_IP'},$cgiparams{'SOURCE_MAC'},$cgiparams{'ENABLED'},$cgiparams{'REMARK'}\n";
121                                 } else { print FILE "$line"; }
122                         }
123                 }
124                 close(FILE);
125                 undef %cgiparams;
126                 &General::log($Lang::tr{'wireless config added'});
127                 system('/usr/local/bin/restartwireless');
128         }
129 ADDEXIT:
130 }
131
132 if ($cgiparams{'ACTION'} eq 'edit')
133 {
134         my $id = 0;
135         foreach my $line (@current)
136         {
137                 $id++;
138                 if ($cgiparams{'ID'} eq $id)
139                 {
140                         chomp($line);
141                         my @temp = split(/\,/,$line);
142                         $cgiparams{'SOURCE_IP'}  = $temp[1];
143                         $cgiparams{'SOURCE_MAC'} = $temp[2];
144                         $cgiparams{'ENABLED'}    = $temp[3];
145                         $cgiparams{'REMARK'}     = $temp[4];
146                         $cgiparams{'SOURCE_IP'} = '' if $cgiparams{'SOURCE_IP'} eq 'NONE';
147                         $cgiparams{'SOURCE_MAC'} = '' if $cgiparams{'SOURCE_MAC'} eq 'NONE';
148                 }
149         }
150         &General::log($Lang::tr{'wireless config changed'});
151         system('/usr/local/bin/restartwireless');
152 }
153
154 if ($cgiparams{'ACTION'} eq 'remove' || $cgiparams{'ACTION'} eq 'toggle')
155 {
156         my $id = 0;
157         open(FILE, ">$filename") or die 'Unable to open config file.';
158         flock FILE, 2;
159         foreach my $line (@current)
160         {
161                 $id++;
162                 unless ($cgiparams{'ID'} eq $id) { print FILE "$line"; }
163                 elsif ($cgiparams{'ACTION'} eq 'toggle')
164                 {
165                         chomp($line);
166                         my @temp = split(/\,/,$line);
167                         print FILE "$temp[0],$temp[1],$temp[2],$cgiparams{'ENABLE'},$temp[4]\n";
168                 }
169         }
170         close(FILE);
171         &General::log($Lang::tr{'wireless config changed'});
172         system('/usr/local/bin/restartwireless');
173 }
174
175
176 $checked{'ENABLED'}{'off'} = '';
177 $checked{'ENABLED'}{'on'} = '';
178 $checked{'ENABLED'}{$cgiparams{'ENABLED'}} = "checked='checked'";
179
180
181 &Header::openpage($Lang::tr{'wireless configuration'}, 1, '');
182
183 &Header::openbigbox('100%', 'left', '', $errormessage);
184
185 if ($errormessage) {
186         &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
187         print "<class name='base'>$errormessage\n";
188         print "&nbsp;</class>\n";
189         &Header::closebox();
190 }
191
192 print "<form method='post' action='$ENV{'SCRIPT_NAME'}'>\n";
193
194 my $buttontext = $Lang::tr{'add'};
195 if ($cgiparams{'ACTION'} eq 'edit') {
196         &Header::openbox('100%', 'left', "$Lang::tr{'edit device'}");
197         $buttontext = $Lang::tr{'update'};
198 } else {
199         &Header::openbox('100%', 'left', "$Lang::tr{'add device'}");
200 }
201
202 print <<END
203 <table width='100%'>
204 <tr>
205 <td width='25%' class='base'>$Lang::tr{'source ip'}:&nbsp;</td>
206 <td width='25%' ><input type='text' name='SOURCE_IP' value='$cgiparams{'SOURCE_IP'}' size='25' /></td>
207 <td width='25%' class='base' align='right'>$Lang::tr{'enabled'}&nbsp;</td>
208 <td width='25%'><input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} /></td>
209 </tr>
210 <tr>
211 <td width='25%' class='base'>$Lang::tr{'source'} $Lang::tr{'mac address'}:&nbsp;</td>
212 <td colspan='3'><input type='text' name='SOURCE_MAC' value='$cgiparams{'SOURCE_MAC'}' size='25' /></td>
213 </tr>
214 <tr>
215 <td width='25%' class='base'>$Lang::tr{'remark'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
216 <td colspan='3'><input type='text' name='REMARK' value='$cgiparams{'REMARK'}' size='40' /></td>
217 </tr>
218 </table>
219 <hr />
220 <table width='100%'>
221 <tr>
222     <td class='base' valign='top'><img src='/blob.gif' alt='*' /></td>
223     <td width='55%' class='base'>$Lang::tr{'this field may be blank'}</td>
224     <td width='40%' align='center'>
225       <input type='hidden' name='ACTION' value='add' />
226       <input type='submit' name='SUBMIT' value='$buttontext' />
227     </td>
228     <td width='5%' align='right'>
229     <a href='${General::adminmanualurl}/section-firewall.html#section-blue-access' target='_blank'>
230     <img src='/images/web-support.png' alt='$Lang::tr{'online help en'}' title='$Lang::tr{'online help en'}' /></a></td>
231 </tr>
232 </table>
233 END
234 ;
235
236 if ($cgiparams{'ACTION'} eq 'edit') {
237         print "<input type='hidden' name='EDITING' value='$cgiparams{'ID'}' />\n";
238 } else {
239         print "<input type='hidden' name='EDITING' value='no' />\n";
240 }
241
242 &Header::closebox();
243
244 print "</form>\n";
245
246 &Header::openbox('100%', 'left', "$Lang::tr{'devices on blue'}");
247 print <<END
248 <div align='center'>
249 END
250 ;
251 open (FILE, "$filename");
252 my @current = <FILE>;
253 close (FILE);
254
255 print <<END
256 <table width='100%'>
257 <tr>
258 <td align='center' width='20%'><b>$Lang::tr{'hostname'}</b></td>
259 <td align='center' width='20%'><b>$Lang::tr{'source ip'}</b></td>
260 <td align='center' width='20%'><b>$Lang::tr{'mac address'}</b></td>
261 <td align='center' width='35%'><b>$Lang::tr{'remark'}</b></td>
262 <td align='center' colspan='3'><b>$Lang::tr{'action'}</b></td>
263 </tr>
264 END
265 ;
266
267 my $id = 0;
268
269 open (HOSTFILE, "$hostsfile");
270 my @curhosts = <HOSTFILE>;
271 close (HOSTFILE);
272
273 my $connstate = &Header::connectionstatus();
274 my @arp = `/sbin/arp -n`;
275 shift @arp;
276
277 foreach my $line (@current)
278 {
279         $id++;
280         chomp($line);
281         my $gif = "";
282         my $gdesc = "";
283         my $hname = "";
284         my $toggle = "";
285         my @temp = split(/\,/,$line);
286         my $wirelessid = $temp[0];
287         my $sourceip = $temp[1];
288         my $sourcemac = $temp[2];
289         if ( $sourceip eq 'NONE' ) {
290                 foreach my $aline ( @arp )
291                 {
292                         chomp($aline);
293                         my @atemp = split( m{\s+}, $aline );
294                         my $aipaddr = $atemp[0];
295                         my $amacaddr = lc( $atemp[2] );
296                         if ( $amacaddr eq $sourcemac ) {
297                                 $sourceip = $aipaddr;
298                                 last;
299                         }
300                 }
301         }
302
303         # SourceIP could now have been set by the ARP probe.
304         if ( $sourceip ne 'NONE' ) {
305                 foreach my $hline (@curhosts)
306                 {
307                         chomp($hline);
308                         my @htemp = split(/\,/,$hline);
309                         my $hkey = $htemp[0];
310                         my $hipaddr = $htemp[1];
311                         my $hostname = $htemp[2];
312                         my $domainname = $htemp[3];
313                         if ($sourceip eq $hipaddr) {
314                                 $hname = "$hostname.$domainname";
315                                 last;
316                         }
317                 }
318                 if ( $hname eq "" ) {
319                         my ($aliases, $addrtype, $length, @addrs);
320                         ($hname, $aliases, $addrtype, $length, @addrs) = 
321                                 gethostbyaddr(pack("C4", split(/\./,  $sourceip)), 2);
322                 }
323         }
324
325         if ($temp[3] eq 'on') { $gif = 'on.gif'; $toggle='off'; $gdesc=$Lang::tr{'click to disable'};}
326                 else { $gif = 'off.gif'; $toggle='on'; $gdesc=$Lang::tr{'click to enable'};}
327
328         my $remark    = &Header::cleanhtml($temp[4]);
329
330         if ($cgiparams{'ACTION'} eq 'edit' && $cgiparams{'ID'} eq $id) {
331                 print "<tr bgcolor='${Header::colouryellow}'>\n";
332         } elsif ($id % 2) {
333                 print "<tr bgcolor='${Header::table1colour}'>\n";
334         } else {
335                 print "<tr bgcolor='${Header::table2colour}'>\n";
336         }
337         print "<td align='center'>$hname</td>\n";
338         print "<td align='center'>$sourceip</td>\n";
339         print "<td align='center'>$sourcemac</td>\n";
340         print "<td align='center'>$remark</td>\n";
341 print<<END
342 <td align='center'>
343         <form method='post' name='frma$id' action='$ENV{'SCRIPT_NAME'}'>
344         <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$gdesc' title='$gdesc' />
345         <input type='hidden' name='ACTION' value='toggle'}' />
346         <input type='hidden' name='ID' value='$id' />
347         <input type='hidden' name='ENABLE' value='$toggle' />
348         </form>
349 </td>
350
351 <td align='center'>
352         <form method='post' name='frmb$id' action='$ENV{'SCRIPT_NAME'}'>
353         <input type='hidden' name='ACTION' value='edit' />
354         <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
355         <input type='hidden' name='ID' value='$id' />
356         </form>
357 </td>
358
359 <td align='center'>
360         <form method='post' name='frmc$id' action='$ENV{'SCRIPT_NAME'}'>
361         <input type='hidden' name='ACTION' value='remove' />
362         <input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
363         <input type='hidden' name='ID' value='$id' />
364         </form>
365 </td>
366 END
367         ;
368         print "</tr>\n";
369 }
370 print "</table>\n";
371
372 print "</div>\n";
373
374 &Header::closebox();
375
376 if ( $dhcpsettings{"ENABLE_BLUE"} eq 'on') {
377         &printblueleases;
378 }
379
380 &Header::closebigbox();
381
382 &Header::closepage();
383
384 sub printblueleases
385 {
386         our %entries = ();
387
388         sub blueleasesort {
389                 # Sort by IP address
390                 my $qs ='IPADDR';
391                 my @a = split(/\./,$entries{$a}->{$qs});
392                 my @b = split(/\./,$entries{$b}->{$qs});
393                 ($a[0]<=>$b[0]) ||
394                 ($a[1]<=>$b[1]) ||
395                 ($a[2]<=>$b[2]) ||
396                 ($a[3]<=>$b[3]);
397         }
398
399         &Header::openbox('100%', 'left', "$Lang::tr{'current dhcp leases on blue'}");
400         print <<END
401 <table width='100%'>
402 <tr>
403 <td width='25%' align='center'><b>$Lang::tr{'ip address'}</b></td>
404 <td width='25%' align='center'><b>$Lang::tr{'mac address'}</b></td>
405 <td width='20%' align='center'><b>$Lang::tr{'hostname'}</b></td>
406 <td width='30%' align='center'><b>$Lang::tr{'lease expires'} (local time d/m/y)</b></td>
407 </tr>
408 END
409         ;
410
411         my ($ip, $endtime, $ether, $hostname, @record, $record);
412         open(LEASES,"/var/state/dhcp/dhcpd.leases") or die "Can't open dhcpd.leases";
413         while (my $line = <LEASES>) {
414                 next if( $line =~ /^\s*#/ );
415                 chomp($line);
416                 my @temp = split (' ', $line);
417
418                 if ($line =~ /^\s*lease/) {
419                         $ip = $temp[1];
420                         # All fields are not necessarily read. Clear everything
421                         $endtime = 0;
422                         $ether = "";
423                         $hostname = "";
424                 } elsif ($line =~ /^\s*ends never;/) {
425                         $endtime = 'never';
426                 } elsif ($line =~ /^\s*ends/) {
427                         $line =~ /(\d+)\/(\d+)\/(\d+) (\d+):(\d+):(\d+)/;
428                         $endtime = timegm($6, $5, $4, $3, $2 - 1, $1 - 1900);
429                 } elsif ($line =~ /^\s*hardware ethernet/) {
430                         $ether = $temp[2];
431                         $ether =~ s/;//g;
432                 } elsif ($line =~ /^\s*client-hostname/) {
433                         shift (@temp);
434                         $hostname = join (' ',@temp);
435                         $hostname =~ s/;//g;
436                         $hostname =~ s/\"//g;
437                 } elsif ($line eq "}") {
438                         # Select records in Blue subnet
439                         if ( &General::IpInSubnet ( $ip,
440                                 $netsettings{"BLUE_NETADDRESS"},
441                                 $netsettings{"BLUE_NETMASK"} ) ) {
442                                 @record = ('IPADDR',$ip,'ENDTIME',$endtime,'ETHER',$ether,'HOSTNAME',$hostname);
443                                 $record = {};                                   # create a reference to empty hash
444                                 %{$record} = @record;                           # populate that hash with @record
445                                 $entries{$record->{'IPADDR'}} = $record;        # add this to a hash of hashes
446                         }
447                 }
448         }
449         close(LEASES);
450
451         my $id = 0;
452         foreach my $key (sort blueleasesort keys %entries) {
453
454                 my $hostname = &Header::cleanhtml($entries{$key}->{HOSTNAME},"y");
455
456                 if ($id % 2) {
457                         print "<tr bgcolor='$Header::table2colour'>";
458                 } else {
459                         print "<tr bgcolor='$Header::table1colour'>";
460                 }
461
462                 print <<END
463 <td align='center'>$entries{$key}->{IPADDR}</td>
464 <td align='center'>$entries{$key}->{ETHER}</td>
465 <td align='center'>&nbsp;$hostname </td>
466 <td align='center'>
467 END
468                 ;
469
470                 if ($entries{$key}->{ENDTIME} eq 'never') {
471                         print "$Lang::tr{'no time limit'}";
472                 } else {
473                         my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $dst);
474                         ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $dst) = localtime ($entries{$key}->{ENDTIME});
475                         my $enddate = sprintf ("%02d/%02d/%d %02d:%02d:%02d",$mday,$mon+1,$year+1900,$hour,$min,$sec);
476
477                         if ($entries{$key}->{ENDTIME} < time() ){
478                                 print "<strike>$enddate</strike>";
479                         } else {
480                                 print "$enddate";
481                         }
482                 }
483
484                 if ( $hostname eq '' ) {
485                         $hostname = $Lang::tr{'device'};
486                 }
487
488                 print <<END
489 <td align='center'>
490         <form method='post' name='frmd$id' action='$ENV{'SCRIPT_NAME'}'>
491         <input type='hidden' name='ACTION' value='add' />
492         <input type='hidden' name='SOURCE_IP' value='' />
493         <input type='hidden' name='SOURCE_MAC' value='$entries{$key}->{ETHER}' />
494         <input type='hidden' name='REMARK' value='$hostname $Lang::tr{'added from dhcp lease list'}' />
495         <input type='hidden' name='ENABLED' value='on' />
496         <input type='hidden' name='EDITING' value='no' />
497         <input type='image' name='$Lang::tr{'add device'}' src='/images/addblue.gif' alt='$Lang::tr{'add device'}' title='$Lang::tr{'add device'}' />
498         </form>
499 </td></tr>
500 END
501                 ;
502                 $id++;
503         }
504
505         print "</table>";
506         &Header::closebox();
507 }
508