source: branches/htmlform/cgi-bin/main.cgi@ 463

Last change on this file since 463 was 463, checked in by Kris Deugau, 14 years ago

/branches/htmlform

Validation nitpick fix in assign.tmpl - also fixes missing field
name on alloctype list. <headdesk>
Convert new assignment result page to template.
Add missing error handling, missing IP pool selection on confirm.tmpl
Create footer template object earlier to allow pushing bits into
it during processing
Prepare to move initial output further down execution to prepare for
proper error handling in subs
Fix probable bug introduced with r456 where the "Routing" type isn't
available when it should be. Maybe. Probably.
Error messages for sub insertAssign() and confirmAssign could arguably
be further moved into the templates, but the complexity of the template
would go *way* up with little or no benefit.
See #3.

  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author
File size: 48.0 KB
Line 
1#!/usr/bin/perl
2# ipdb/cgi-bin/main.cgi
3###
4# SVN revision info
5# $Date: 2010-08-05 21:34:29 +0000 (Thu, 05 Aug 2010) $
6# SVN revision $Rev: 463 $
7# Last update by $Author: kdeugau $
8###
9# Copyright (C) 2004-2010 - Kris Deugau
10
11use strict;
12use warnings;
13use CGI::Carp qw(fatalsToBrowser);
14use CGI::Simple;
15use HTML::Template;
16use DBI;
17use CommonWeb qw(:ALL);
18use CustIDCK;
19use POSIX qw(ceil);
20use NetAddr::IP;
21
22use Sys::Syslog;
23
24# don't remove! required for GNU/FHS-ish install from tarball
25##uselib##
26
27use MyIPDB;
28
29openlog "IPDB","pid","$IPDB::syslog_facility";
30
31# Collect the username from HTTP auth. If undefined, we're in
32# a test environment, or called without a username.
33my $authuser;
34if (!defined($ENV{'REMOTE_USER'})) {
35 $authuser = '__temptest';
36} else {
37 $authuser = $ENV{'REMOTE_USER'};
38}
39
40syslog "debug", "$authuser active, $ENV{'REMOTE_ADDR'}";
41
42# Why not a global DB handle? (And a global statement handle, as well...)
43# Use the connectDB function, otherwise we end up confusing ourselves
44my $ip_dbh;
45my $sth;
46my $errstr;
47($ip_dbh,$errstr) = connectDB_My;
48if (!$ip_dbh) {
49 exitError("Database error: $errstr\n");
50}
51initIPDBGlobals($ip_dbh);
52
53# Set up some globals
54##fixme - need to autofill this somehow
55$ENV{HTML_TEMPLATE_ROOT} = '/home/kdeugau/dev/ipdb/trunk/templates';
56
57my $header = HTML::Template->new(filename => "header.tmpl");
58my $footer = HTML::Template->new(filename => "footer.tmpl");
59
60$header->param(version => $IPDB::VERSION);
61$header->param(addperm => $IPDBacl{$authuser} =~ /a/);
62print "Content-type: text/html\n\n", $header->output;
63
64# Set up the CGI object...
65my $q = new CGI::Simple;
66# ... and get query-string params as well as POST params if necessary
67$q->parse_query_string;
68
69# Convenience; saves changing all references to %webvar
70##fixme: tweak for handling <select multiple='y' size=3> (list with multiple selection)
71my %webvar = $q->Vars;
72
73
74#main()
75
76if(!defined($webvar{action})) {
77 $webvar{action} = "index"; #shuts up the warnings.
78}
79
80my $page = HTML::Template->new(filename => "$webvar{action}.tmpl");
81
82if($webvar{action} eq 'index') {
83 showSummary();
84} elsif ($webvar{action} eq 'addmaster') {
85 if ($IPDBacl{$authuser} !~ /a/) {
86 printError("You shouldn't have been able to get here. Access denied.");
87 } else {
88 open HTML, "<../addmaster.html";
89 print while <HTML>;
90 }
91} elsif ($webvar{action} eq 'newmaster') {
92
93 if ($IPDBacl{$authuser} !~ /a/) {
94 printError("You shouldn't have been able to get here. Access denied.");
95 } else {
96
97 my $cidr = new NetAddr::IP $webvar{cidr};
98
99 print "<div type=heading align=center>Adding $cidr as master block....</div>\n";
100
101 my ($code,$msg) = addMaster($ip_dbh, $webvar{cidr});
102
103 if ($code eq 'FAIL') {
104 carp "Transaction aborted because $msg";
105 syslog "err", "Could not add master block '$webvar{cidr}' to database: '$msg'";
106 printError("Could not add master block $webvar{cidr} to database: $msg");
107 } else {
108 print "<div type=heading align=center>Success!</div>\n";
109 syslog "info", "$authuser added master block $webvar{cidr}";
110 }
111
112 } # ACL check
113
114} # end add new master
115
116elsif($webvar{action} eq 'showmaster') {
117 showMaster();
118}
119elsif($webvar{action} eq 'showrouted') {
120 showRBlock();
121}
122elsif($webvar{action} eq 'listpool') {
123 listPool();
124}
125
126# Not modified or added; just shuffled
127elsif($webvar{action} eq 'assign') {
128 assignBlock();
129}
130elsif($webvar{action} eq 'confirm') {
131 confirmAssign();
132}
133elsif($webvar{action} eq 'insert') {
134 insertAssign();
135}
136elsif($webvar{action} eq 'edit') {
137 edit();
138}
139elsif($webvar{action} eq 'update') {
140 update();
141}
142elsif($webvar{action} eq 'delete') {
143 remove();
144}
145elsif($webvar{action} eq 'finaldelete') {
146 finalDelete();
147}
148elsif ($webvar{action} eq 'nodesearch') {
149 open HTML, "<../nodesearch.html";
150 my $html = join('',<HTML>);
151 close HTML;
152
153 $sth = $ip_dbh->prepare("SELECT node_id, node_name FROM nodes ORDER BY node_type,node_id");
154 $sth->execute() or print "DEBUG: failed retrieval from nodes: ".$sth->errstr,"<br>\n";
155 my $nodes = '';
156 while (my ($nid,$nname) = $sth->fetchrow_array()) {
157 $nodes .= "<option value='$nid'>$nname</option>\n";
158 }
159 $html =~ s/\$\$NODELIST\$\$/$nodes/;
160
161 print $html;
162}
163
164# Default is an error. It shouldn't be possible to easily get here.
165# The only way I can think of offhand is to just call main.cgi bare-
166# which is not in any way guaranteed to provide anything useful.
167else {
168 my $rnd = rand 500;
169 my $boing = sprintf("%.2f", rand 500);
170 my @excuses = ("Aether cloudy. Ask again later.","The gods are unhappy with your sacrifice.",
171 "Because one of it's legs are both the same", "*wibble*",
172 "Hey! Stop pushing my buttons!", "I ain't done nuttin'", "9",
173 "8", "9", "10", "11", "12", "13", "14", "15", "16", "17");
174 printAndExit("Error $boing: ".$excuses[$rnd/30.0]);
175}
176## Finally! Done with that NASTY "case" emulation!
177
178
179
180# Clean up IPDB globals, DB handle, etc.
181finish($ip_dbh);
182
183#print qq(<div align=right style="position: absolute; right: 30px;">).
184# qq(<a href="/ip/cgi-bin/admin.cgi">Admin tools</a></div><br>\n)
185# if $IPDBacl{$authuser} =~ /A/;
186
187## Do all our printing here so we can generate errors and stick them into the slots in the templates.
188
189# can't do this yet, too many blowups
190#print "Content-type: text/html\n\n", $header->output;
191
192print $page->output;
193
194# include the admin tools link in the output?
195$footer->param(adminlink => ($IPDBacl{$authuser} =~ /A/));
196
197print $footer->output;
198
199# Just in case something waaaayyy down isn't in place
200# properly... we exit explicitly.
201exit;
202
203
204
205# args are: a reference to an array with the row to be printed and the
206# class(stylesheet) to use for formatting.
207# if ommitting the class - call the sub as &printRow(\@array)
208sub printRow {
209 my ($rowRef,$class) = @_;
210
211 if (!$class) {
212 print "<tr>\n";
213 } else {
214 print "<tr class=\"$class\">\n";
215 }
216
217ELEMENT: foreach my $element (@$rowRef) {
218 if (!defined($element)) {
219 print "<td></td>\n";
220 next ELEMENT;
221 }
222 $element =~ s|\n|</br>|g;
223 print "<td>$element</td>\n";
224 }
225 print "</tr>";
226} # printRow
227
228
229# Prints table headings. Accepts any number of arguments;
230# each argument is a table heading.
231sub startTable {
232 print qq(<center><table width="98%" cellspacing="0" class="center"><tr>);
233
234 foreach(@_) {
235 print qq(<td class="heading">$_</td>);
236 }
237 print "</tr>\n";
238} # startTable
239
240
241# Initial display: Show master blocks with total allocated subnets, total free subnets
242sub showSummary {
243 my %allocated;
244 my %free;
245 my %routed;
246 my %bigfree;
247
248 # Count the allocations.
249 $sth = $ip_dbh->prepare("select count(*) from allocations where cidr <<= ?");
250 foreach my $master (@masterblocks) {
251 $sth->execute("$master");
252 $sth->bind_columns(\$allocated{"$master"});
253 $sth->fetch();
254 }
255
256 # Count routed blocks
257 $sth = $ip_dbh->prepare("select count(*) from routed where cidr <<= ?");
258 foreach my $master (@masterblocks) {
259 $sth->execute("$master");
260 $sth->bind_columns(\$routed{"$master"});
261 $sth->fetch();
262 }
263
264 # Count the free blocks.
265 $sth = $ip_dbh->prepare("select count(*) from freeblocks where cidr <<= ? and ".
266 "(routed='y' or routed='n')");
267 foreach my $master (@masterblocks) {
268 $sth->execute("$master");
269 $sth->bind_columns(\$free{"$master"});
270 $sth->fetch();
271 }
272
273 # Find the largest free block in each master
274 $sth = $ip_dbh->prepare("select maskbits from freeblocks where cidr <<= ? and ".
275 "(routed='y' or routed='n') order by maskbits limit 1");
276 foreach my $master (@masterblocks) {
277 $sth->execute("$master");
278 $sth->bind_columns(\$bigfree{"$master"});
279 $sth->fetch();
280 }
281
282 # Assemble the data to stuff into the template.
283 my @masterlist;
284 my $rowclass=0;
285 foreach my $master (@masterblocks) {
286 my %row = (rowclass => "row$rowclass",
287 master => "$master",
288 routed => $routed{"$master"},
289 allocated => $allocated{"$master"},
290 free => $free{"$master"},
291 bigfree => ( ($bigfree{"$master"} eq '') ? ("&lt;NONE&gt;") : ("/".$bigfree{"$master"}) )
292 );
293 push (@masterlist, \%row);
294 $rowclass++; $rowclass = $rowclass % 2;
295 }
296 $page->param(masterlist => \@masterlist);
297
298 $page->param(addmaster => ($IPDBacl{$authuser} =~ /a/) );
299
300} # showSummary
301
302
303# Display detail on master
304# Alrighty then! We're showing routed blocks within a single master this time.
305# We should be able to steal code from showSummary(), and if I'm really smart
306# I'll figger a way to munge the two together. (Once I've done that, everything
307# else should follow. YMMV.)
308sub showMaster {
309
310 print qq(<center><div class="heading">Summarizing routed blocks for ).
311 qq($webvar{block}:</div></center><br>\n);
312
313 my %allocated;
314 my %free;
315 my %routed;
316 my %bigfree;
317
318 my $master = new NetAddr::IP $webvar{block};
319 my @localmasters;
320
321 # Fetch only the blocks relevant to this master
322 $sth = $ip_dbh->prepare("select cidr,city from routed where cidr <<= '$master' order by cidr");
323 $sth->execute();
324
325 my $i=0;
326 while (my @data = $sth->fetchrow_array()) {
327 my $cidr = new NetAddr::IP $data[0];
328 $localmasters[$i++] = $cidr;
329 $free{"$cidr"} = 0;
330 $allocated{"$cidr"} = 0;
331 $bigfree{"$cidr"} = 128;
332 # Retain the routing destination
333 $routed{"$cidr"} = $data[1];
334 }
335
336 # Check if there were actually any blocks routed from this master
337 if ($i > 0) {
338 startTable('Routed block','Routed to','Allocated blocks',
339 'Free blocks','Largest free block');
340
341 # Count the allocations
342 $sth = $ip_dbh->prepare("select count(*) from allocations where cidr <<= ?");
343 foreach my $master (@localmasters) {
344 $sth->execute("$master");
345 $sth->bind_columns(\$allocated{"$master"});
346 $sth->fetch();
347 }
348
349 # Count the free blocks.
350 $sth = $ip_dbh->prepare("select count(*) from freeblocks where cidr <<= ? and ".
351 "(routed='y' or routed='n')");
352 foreach my $master (@localmasters) {
353 $sth->execute("$master");
354 $sth->bind_columns(\$free{"$master"});
355 $sth->fetch();
356 }
357
358 # Get the size of the largest free block
359 $sth = $ip_dbh->prepare("select maskbits from freeblocks where cidr <<= ? and ".
360 "(routed='y' or routed='n') order by maskbits limit 1");
361 foreach my $master (@localmasters) {
362 $sth->execute("$master");
363 $sth->bind_columns(\$bigfree{"$master"});
364 $sth->fetch();
365 }
366
367 # Print the data.
368 my $count=0;
369 foreach my $master (@localmasters) {
370 my @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=showrouted&block=$master\">$master</a>",
371 $routed{"$master"}, $allocated{"$master"},
372 $free{"$master"},
373 ( ($bigfree{"$master"} eq 128) ? ("&lt;NONE&gt;") : ("/".$bigfree{"$master"}) )
374 );
375 printRow(\@row, 'color1' ) if($count%2==0);
376 printRow(\@row, 'color2' ) if($count%2!=0);
377 $count++;
378 }
379 } else {
380 # If a master block has no routed blocks, then by definition it has no
381 # allocations, and can be deleted.
382 print qq(<hr width="60%"><center><div class="heading">No allocations in ).
383 qq($master.</div>\n).
384 ($IPDBacl{$authuser} =~ /d/ ?
385 qq(<form action="/ip/cgi-bin/main.cgi" method=POST>\n).
386 qq(<input type=hidden name=action value="delete">\n).
387 qq(<input type=hidden name=block value="$master">\n).
388 qq(<input type=hidden name=alloctype value="mm">\n).
389 qq(<input type=submit value=" Remove this master ">\n).
390 qq(</form></center>\n) :
391 '');
392
393 } # end check for existence of routed blocks in master
394
395 print qq(</table>\n<hr width="60%">\n).
396 qq(<center><div class="heading">Unrouted blocks in $master:</div></center><br>\n);
397
398 startTable('Netblock','Range');
399
400 # Snag the free blocks.
401 my $count = 0;
402 $sth = $ip_dbh->prepare("select cidr from freeblocks where cidr <<='$master' and ".
403 "routed='n' order by cidr");
404 $sth->execute();
405 while (my @data = $sth->fetchrow_array()) {
406 my $cidr = new NetAddr::IP $data[0];
407 my @row = ("$cidr", $cidr->range);
408 printRow(\@row, 'color1' ) if($count%2==0);
409 printRow(\@row, 'color2' ) if($count%2!=0);
410 $count++;
411 }
412
413 print "</table>\n";
414} # showMaster
415
416
417# Display details of a routed block
418# Alrighty then! We're showing allocations within a routed block this time.
419# We should be able to steal code from showSummary() and showMaster(), and if
420# I'm really smart I'll figger a way to munge all three together. (Once I've
421# done that, everything else should follow. YMMV.
422# This time, we check the database before spewing, because we may
423# not have anything useful to spew.
424sub showRBlock {
425
426 my $master = new NetAddr::IP $webvar{block};
427
428 $sth = $ip_dbh->prepare("select city from routed where cidr='$master'");
429 $sth->execute;
430 my @data = $sth->fetchrow_array;
431
432 print qq(<center><div class="heading">Summarizing allocated blocks for ).
433 qq($master ($data[0]):</div></center><br>\n);
434
435 startTable('CIDR allocation','Customer Location','Type','CustID','SWIPed?','Description/Name');
436
437 # Snag the allocations for this block
438 $sth = $ip_dbh->prepare("select cidr,city,type,custid,swip,description".
439 " from allocations where cidr <<= '$master' order by cidr");
440 $sth->execute();
441
442 # hack hack hack
443 # set up to flag swip=y records if they don't actually have supporting data in the customers table
444 my $custsth = $ip_dbh->prepare("select count(*) from customers where custid=?");
445
446 my $count=0;
447 while (my @data = $sth->fetchrow_array()) {
448 # cidr,city,type,custid,swip,description, as per the SELECT
449 my $cidr = new NetAddr::IP $data[0];
450
451 # Clean up extra spaces that are borking things.
452# $data[2] =~ s/\s+//g;
453
454 $custsth->execute($data[3]);
455 my ($ncust) = $custsth->fetchrow_array();
456
457 # Prefix subblocks with "Sub "
458 my @row = ( (($data[2] =~ /^.r$/) ? 'Sub ' : '').
459 qq(<a href="/ip/cgi-bin/main.cgi?action=edit&block=$data[0]">$data[0]</a>),
460 $data[1], $disp_alloctypes{$data[2]}, $data[3],
461 ($data[4] eq 'y' ? ($ncust == 0 ? 'Yes<small>*</small>' : 'Yes') : 'No'), $data[5]);
462 # If the allocation is a pool, allow listing of the IPs in the pool.
463 if ($data[2] =~ /^.[pd]$/) {
464 $row[0] .= ' &nbsp; <a href="/ip/cgi-bin/main.cgi?action=listpool'.
465 "&pool=$data[0]\">List IPs</a>";
466 }
467
468 printRow(\@row, 'color1') if ($count%2 == 0);
469 printRow(\@row, 'color2') if ($count%2 != 0);
470 $count++;
471 }
472
473 print "</table>\n";
474
475 # If the routed block has no allocations, by definition it only has
476 # one free block, and therefore may be deleted.
477 if ($count == 0) {
478 print qq(<hr width="60%"><center><div class="heading">No allocations in ).
479 qq($master.</div></center>\n).
480 ($IPDBacl{$authuser} =~ /d/ ?
481 qq(<form action="/ip/cgi-bin/main.cgi" method=POST>\n).
482 qq(<input type=hidden name=action value="delete">\n).
483 qq(<input type=hidden name=block value="$master">\n).
484 qq(<input type=hidden name=alloctype value="rm">\n).
485 qq(<input type=submit value=" Remove this block ">\n).
486 qq(</form>\n) :
487 '');
488 }
489
490 print qq(<hr width="60%">\n<center><div class="heading">Free blocks within routed ).
491 qq(submaster $master</div></center>\n);
492
493 startTable('CIDR block','Range');
494
495 # Snag the free blocks. We don't really *need* to be pedantic about avoiding
496 # unrouted free blocks, but it's better to let the database do the work if we can.
497 $count = 0;
498 $sth = $ip_dbh->prepare("select cidr,routed from freeblocks where cidr <<= '$master'".
499 " order by cidr");
500 $sth->execute();
501 while (my @data = $sth->fetchrow_array()) {
502 # cidr,routed
503 my $cidr = new NetAddr::IP $data[0];
504 # Include some HairyPerl(TM) to prefix subblocks with "Sub "
505 my @row = ((($data[1] ne 'y' && $data[1] ne 'n') ? 'Sub ' : '').
506 ($IPDBacl{$authuser} =~ /a/ ? qq(<a href="/ip/cgi-bin/main.cgi?action=assign&block=$cidr&fbtype=$data[1]">$cidr</a>) : $cidr),
507 $cidr->range);
508 printRow(\@row, 'color1') if ($count%2 == 0);
509 printRow(\@row, 'color2') if ($count%2 != 0);
510 $count++;
511 }
512
513 print "</table>\n";
514} # showRBlock
515
516
517# List the IPs used in a pool
518sub listPool {
519
520 my $cidr = new NetAddr::IP $webvar{pool};
521
522 my ($pooltype,$poolcity);
523
524 # Snag pool info for heading
525 $sth = $ip_dbh->prepare("select type,city from allocations where cidr='$cidr'");
526 $sth->execute;
527 $sth->bind_columns(\$pooltype, \$poolcity);
528 $sth->fetch() || carp $sth->errstr;
529
530 print qq(<center><div class="heading">Listing pool IPs for $cidr<br>\n).
531 qq(($disp_alloctypes{$pooltype} in $poolcity)</div></center><br>\n);
532 # Only display net/gw/bcast if it's a "real" netblock and not a PPP(oE) lunacy
533 if ($pooltype =~ /^.d$/) {
534 print qq(<div class="indent"><b>Reserved IPs:</b><br>\n);
535 print qq(<div class="indent"><table><tr class=color1><td>Network IP:</td><td>).
536 $cidr->addr."</td></tr>\n";
537 $cidr++;
538 print "<tr class=color2><td>Gateway:</td><td>".$cidr->addr."</td></tr>\n";
539 $cidr--; $cidr--;
540 print "<tr class=color1><td>Broadcast:</td><td>".$cidr->addr."</td></tr>\n".
541 "<tr><td>Netmask:</td><td>".$cidr->mask."</td></tr>\n".
542 "</table></div></div>\n";
543 }
544
545# probably have to add an "edit IP allocation" link here somewhere.
546
547 startTable('IP','Customer ID','Available?','Description','');
548 $sth = $ip_dbh->prepare("select ip,custid,available,description,type".
549 " from poolips where pool='$webvar{pool}' order by ip");
550 $sth->execute;
551 my $count = 0;
552 while (my @data = $sth->fetchrow_array) {
553 # pool,ip,custid,city,ptype,available,notes,description,circuitid
554 # ip,custid,available,description,type
555 # If desc is "null", make it not null. <g>
556 if ($data[3] eq '') {
557 $data[3] = '&nbsp;';
558 }
559 # Some nice hairy Perl to decide whether to allow unassigning each IP
560 # -> if $data[2] (aka poolips.available) == 'n' then we print the unassign link
561 # else we print a blank space
562 my @row = ( qq(<a href="/ip/cgi-bin/main.cgi?action=edit&block=$data[0]">$data[0]</a>),
563 $data[1],$data[2],$data[3],
564 ( (($data[2] eq 'n') && ($IPDBacl{$authuser} =~ /d/)) ?
565 ("<a href=\"/ip/cgi-bin/main.cgi?action=delete&block=$data[0]&".
566 "alloctype=$data[4]\">Unassign this IP</a>") :
567 ("&nbsp;") )
568 );
569 printRow(\@row, 'color1') if($count%2==0);
570 printRow(\@row, 'color2') if($count%2!=0);
571 $count++;
572 }
573 print "</table>\n";
574
575} # end listPool
576
577
578# Show "Add new allocation" page. Note that the actual page may
579# be one of two templates, and the lists come from the database.
580sub assignBlock {
581
582 if ($IPDBacl{$authuser} !~ /a/) {
583 printError("You shouldn't have been able to get here. Access denied.");
584 return;
585 }
586
587 # hack pthbttt eww
588 $webvar{block} = '' if !$webvar{block};
589
590# hmm. TMPL_IF block and TMPL_ELSE block on these instead?
591 $page->param(rowa => 'row'.($webvar{block} eq '' ? 1 : 0));
592 $page->param(rowb => 'row'.($webvar{block} eq '' ? 0 : 1));
593 $page->param(block => $webvar{block}); # fb-assign flag, if block is set, we're in fb-assign
594 $page->param(iscontained => ($webvar{fbtype} && $webvar{fbtype} ne 'y'));
595
596 # New special case- block to assign is specified
597 if ($webvar{block} ne '') {
598 my $block = new NetAddr::IP $webvar{block};
599
600 # Handle contained freeblock allocation.
601 # This is a little dangerous, as it's *theoretically* possible to
602 # get fbtype='n' (aka a non-routed freeblock). However, should
603 # someone manage to get there, they get what they deserve.
604 if ($webvar{fbtype} ne 'y') {
605 # Snag the type of the container block from the database.
606 $sth = $ip_dbh->prepare("select type from allocations where cidr >>='$block'");
607 $sth->execute;
608 my @data = $sth->fetchrow_array;
609 $data[0] =~ s/c$/r/; # Munge the type into the correct form
610 $page->param(fbdisptype => $list_alloctypes{$data[0]});
611 $page->param(type => $data[0]);
612 } else {
613 $sth = $ip_dbh->prepare("select type,listname from alloctypes where listorder < 500 ".
614 "and type not like '_i' and type not like '_r' order by listorder");
615 $sth->execute;
616 my @data = $sth->fetchrow_array;
617 my @typelist;
618 my $selflag = 0;
619 while (my @data = $sth->fetchrow_array) {
620 my %row = (tval => $data[0],
621 type => $data[1],
622 sel => ($selflag == 0 ? ' selected' : '')
623 );
624 push (@typelist, \%row);
625 $selflag++;
626 }
627 $page->param(typelist => \@typelist);
628 }
629 } else {
630 my @masterlist;
631 foreach my $master (@masterblocks) {
632 my %row = (master => "$master");
633 push (@masterlist, \%row);
634 }
635 $page->param(masterlist => \@masterlist);
636
637 my @pops;
638 foreach my $pop (@poplist) {
639 my %row = (pop => $pop);
640 push (@pops, \%row);
641 }
642 $page->param(pops => \@pops);
643
644 # could arguably include routing (500) in the list, but ATM it doesn't
645 # make sense, and in any case that shouldn't be structurally possible here.
646 $sth = $ip_dbh->prepare("select type,listname from alloctypes where listorder <= 500 order by listorder");
647 $sth->execute;
648 my @typelist;
649 my $selflag = 0;
650 while (my @data = $sth->fetchrow_array) {
651 my %row = (tval => $data[0],
652 type => $data[1],
653 sel => ($selflag == 0 ? ' selected' : '')
654 );
655 push (@typelist, \%row);
656 $selflag++;
657 }
658 $page->param(typelist => \@typelist);
659 }
660
661 my @cities;
662 foreach my $city (@citylist) {
663 my %row = (city => $city);
664 push (@cities, \%row);
665 }
666 $page->param(citylist => \@cities);
667
668## node hack
669 $sth = $ip_dbh->prepare("SELECT node_id, node_name FROM nodes ORDER BY node_type,node_id");
670 $sth->execute() or print "DEBUG: failed retrieval from nodes: ".$sth->errstr,"<br>\n";
671 my @nodes;
672 while (my ($nid,$nname) = $sth->fetchrow_array()) {
673 my %row = (nid => $nid, nname => $nname);
674 push (@nodes, \%row);
675 }
676 $page->param(nodelist => \@nodes);
677## end node hack
678
679 $page->param(privdata => $IPDBacl{$authuser} =~ /s/);
680
681} # assignBlock
682
683
684# Take info on requested IP assignment and see what we can provide.
685sub confirmAssign {
686 if ($IPDBacl{$authuser} !~ /a/) {
687 printError("You shouldn't have been able to get here. Access denied.");
688 return;
689 }
690
691 my $cidr;
692 my $alloc_from;
693
694 # Going to manually validate some items.
695 # custid and city are automagic.
696 return if !validateInput();
697
698# Several different cases here.
699# Static IP vs netblock
700# + Different flavours of static IP
701# + Different flavours of netblock
702
703 if ($webvar{alloctype} =~ /^.i$/) {
704 my ($base,undef) = split //, $webvar{alloctype}; # split into individual chars
705
706# Ewww. But it works.
707 $sth = $ip_dbh->prepare("SELECT (SELECT city FROM allocations WHERE cidr=poolips.pool), ".
708 "poolips.pool, COUNT(*) FROM poolips,allocations WHERE poolips.available='y' AND ".
709 "poolips.pool=allocations.cidr AND allocations.city='$webvar{pop}' AND poolips.type LIKE '".$base."_' ".
710 "GROUP BY pool");
711 $sth->execute;
712 my $optionlist;
713
714 my @poollist;
715 while (my ($poolcit,$poolblock,$poolfree) = $sth->fetchrow_array) {
716 # city,pool cidr,free IP count
717 if ($poolfree > 0) {
718 my %row = (poolcit => $poolcit, poolblock => $poolblock, poolfree => $poolfree);
719 push (@poollist, \%row);
720 }
721 }
722 $page->param(staticip => 1);
723 $page->param(poollist => \@poollist);
724 $cidr = "Single static IP";
725##fixme: need to handle "no available pools"
726
727 } else { # end show pool options
728
729 if ($webvar{fbassign} eq 'y') {
730 $cidr = new NetAddr::IP $webvar{block};
731 $webvar{maskbits} = $cidr->masklen;
732 } else { # done with direct freeblocks assignment
733
734 if (!$webvar{maskbits}) {
735 $page->param(err => "Please specify a CIDR mask length.");
736 return;
737 }
738 my $sql;
739 my $city;
740 my $failmsg;
741 my $extracond = '';
742 if ($webvar{allocfrom} eq '-') {
743 $extracond = ($webvar{allowpriv} eq 'on' ? '' :
744 " and not (cidr <<= '192.168.0.0/16'".
745 " or cidr <<= '10.0.0.0/8'".
746 " or cidr <<= '172.16.0.0/12')");
747 }
748 my $sortorder;
749 if ($webvar{alloctype} eq 'rm') {
750 if ($webvar{allocfrom} ne '-') {
751 $sql = "select * from freeblocks where maskbits<=$webvar{maskbits} and routed='n'".
752 " and cidr <<= '$webvar{allocfrom}'";
753 $sortorder = "maskbits desc";
754 } else {
755 $sql = "select * from freeblocks where maskbits<=$webvar{maskbits} and routed='n'";
756 $sortorder = "maskbits desc";
757 }
758 $failmsg = "No suitable free block found.<br>\nWe do not have a free".
759 " routeable block of that size.<br>\nYou will have to either route".
760 " a set of smaller netblocks or a single smaller netblock.";
761 } else {
762##fixme
763# This section needs serious Pondering.
764 # Pools of most types get assigned to the POP they're "routed from"
765 # This includes WAN blocks and other netblock "containers"
766 # This does NOT include cable pools.
767 if ($webvar{alloctype} =~ /^.[pc]$/) {
768 $city = $webvar{city};
769 $failmsg = "No suitable free block found.<br>\nYou will have to route another".
770 " superblock from one of the<br>\nmaster blocks or chose a smaller".
771 " block size for the pool.";
772 } else {
773 $city = $webvar{pop};
774 $failmsg = "No suitable free block found.<br>\nYou will have to route another".
775 " superblock to $webvar{pop}<br>\nfrom one of the master blocks or".
776 " chose a smaller blocksize.";
777 }
778 if (defined $webvar{allocfrom} && $webvar{allocfrom} ne '-') {
779 $sql = "select cidr from freeblocks where city='$city' and maskbits<=$webvar{maskbits}".
780 " and cidr <<= '$webvar{allocfrom}' and routed='".
781 (($webvar{alloctype} =~ /^(.)r$/) ? "$1" : 'y')."'";
782 $sortorder = "maskbits desc,cidr";
783 } else {
784 $sql = "select cidr from freeblocks where city='$city' and maskbits<=$webvar{maskbits}".
785 " and routed='".(($webvar{alloctype} =~ /^(.)r$/) ? "$1" : 'y')."'";
786 $sortorder = "maskbits desc,cidr";
787 }
788 }
789 $sql = $sql.$extracond." order by ".$sortorder;
790 $sth = $ip_dbh->prepare($sql);
791 $sth->execute;
792 my @data = $sth->fetchrow_array();
793 if ($data[0] eq "") {
794 $page->param(err => $failmsg);
795 return;
796 }
797 $cidr = new NetAddr::IP $data[0];
798 } # check for freeblocks assignment or IPDB-controlled assignment
799
800 $alloc_from = "$cidr";
801
802 # If the block to be allocated is smaller than the one we found,
803 # figure out the "real" block to be allocated.
804 if ($cidr->masklen() ne $webvar{maskbits}) {
805 my $maskbits = $cidr->masklen();
806 my @subblocks;
807 while ($maskbits++ < $webvar{maskbits}) {
808 @subblocks = $cidr->split($maskbits);
809 }
810 $cidr = $subblocks[0];
811 }
812 } # if ($webvar{alloctype} =~ /^.i$/)
813
814## node hack
815 if ($webvar{node} && $webvar{node} ne '-') {
816 $sth = $ip_dbh->prepare("SELECT node_name FROM nodes WHERE node_id=?");
817 $sth->execute($webvar{node});
818 my ($nodename) = $sth->fetchrow_array();
819 $page->param(nodename => $nodename);
820 $page->param(nodeid => $webvar{node});
821 }
822## end node hack
823
824 # Stick in the allocation data
825 $page->param(alloc_type => $webvar{alloctype});
826 $page->param(typefull => $q->escapeHTML($disp_alloctypes{$webvar{alloctype}}));
827 $page->param(alloc_from => $alloc_from);
828 $page->param(cidr => $cidr);
829 $page->param(city => $q->escapeHTML($webvar{city}));
830 $page->param(custid => $webvar{custid});
831 $page->param(circid => $q->escapeHTML($webvar{circid}));
832 $page->param(desc => $q->escapeHTML($webvar{desc}));
833
834##fixme: find a way to have the displayed copy have <br> substitutions
835# for newlines, and the <input> value have either encoded or bare newlines.
836# Also applies to privdata.
837 $page->param(notes => $q->escapeHTML($webvar{notes},'y'));
838
839 # Check to see if user is allowed to do anything with sensitive data
840 my $privdata = '';
841 $page->param(privdata => $q->escapeHTML($webvar{privdata},'y'))
842 if $IPDBacl{$authuser} =~ /s/;
843
844 # Yay! This now has it's very own little home.
845 $page->param(billinguser => $webvar{userid})
846 if $webvar{userid};
847
848##fixme: this is only needed iff confirm.tmpl/confirm.html and
849# confirmRemove.html/confirmRemove.tmpl are merged (quite possible, just
850# a little tedious)
851 $page->param(action => "insert");
852
853} # end confirmAssign
854
855
856# Do the work of actually inserting a block in the database.
857sub insertAssign {
858 if ($IPDBacl{$authuser} !~ /a/) {
859 printError("You shouldn't have been able to get here. Access denied.");
860 return;
861 }
862 # Some things are done more than once.
863 return if !validateInput();
864
865 if (!defined($webvar{privdata})) {
866 $webvar{privdata} = '';
867 }
868 # $code is "success" vs "failure", $msg contains OK for a
869 # successful netblock allocation, the IP allocated for static
870 # IP, or the error message if an error occurred.
871
872 my ($code,$msg) = allocateBlock($ip_dbh, $webvar{fullcidr}, $webvar{alloc_from},
873 $webvar{custid}, $webvar{alloctype}, $webvar{city}, $webvar{desc}, $webvar{notes},
874 $webvar{circid}, $webvar{privdata}, $webvar{node});
875
876 if ($code eq 'OK') {
877 if ($webvar{alloctype} =~ /^.i$/) {
878 $msg =~ s|/32||;
879 $page->param(staticip => $msg);
880 $page->param(custid => $webvar{custid});
881 $page->param(billinguser => $webvar{billinguser});
882 mailNotify($ip_dbh, "a$webvar{alloctype}", "ADDED: $disp_alloctypes{$webvar{alloctype}} allocation",
883 "$disp_alloctypes{$webvar{alloctype}} $msg allocated to customer $webvar{custid}\n".
884 "Description: $webvar{desc}\n\nAllocated by: $authuser\n");
885 } else {
886 my $netblock = new NetAddr::IP $webvar{fullcidr};
887 $page->param(fullcidr => $webvar{fullcidr});
888 $page->param(alloctype => $disp_alloctypes{$webvar{alloctype}});
889 $page->param(custid => $webvar{custid});
890 if ($webvar{alloctype} eq 'pr' && $webvar{billinguser}) {
891 $page->param(billinguser => $webvar{billinguser});
892 $page->param(custid => $webvar{custid});
893 $page->param(netaddr => $netblock->addr);
894 $page->param(masklen => $netblock->masklen);
895 }
896 mailNotify($ip_dbh, "a$webvar{alloctype}", "ADDED: $disp_alloctypes{$webvar{alloctype}} allocation",
897 "$disp_alloctypes{$webvar{alloctype}} $webvar{fullcidr} allocated to customer $webvar{custid}\n".
898 "Description: $webvar{desc}\n\nAllocated by: $authuser\n");
899 }
900 syslog "notice", "$authuser allocated '$webvar{fullcidr}' to '$webvar{custid}' as ".
901 "'$webvar{alloctype}' ($msg)";
902 } else {
903 syslog "err", "Allocation of '$webvar{fullcidr}' to '$webvar{custid}' as ".
904 "'$webvar{alloctype}' by $authuser failed: '$msg'";
905 $page->param(err => "Allocation of $webvar{fullcidr} as '$disp_alloctypes{$webvar{alloctype}}'".
906 " failed:<br>\n$msg\n");
907 }
908
909} # end insertAssign()
910
911
912# Does some basic checks on common input data to make sure nothing
913# *really* weird gets in to the database through this script.
914# Does NOT do complete input validation!!!
915sub validateInput {
916 if ($webvar{city} eq '-') {
917 printError("Please choose a city.");
918 return;
919 }
920
921 # Alloctype check.
922 chomp $webvar{alloctype};
923 if (!grep /$webvar{alloctype}/, keys %disp_alloctypes) {
924 # Danger! Danger! alloctype should ALWAYS be set by a dropdown. Anyone
925 # managing to call things in such a way as to cause this deserves a cryptic error.
926 printError("Invalid alloctype");
927 return;
928 }
929
930 # CustID check
931 # We have different handling for customer allocations and "internal" or "our" allocations
932 if ($def_custids{$webvar{alloctype}} eq '') {
933 if (!$webvar{custid}) {
934 printError("Please enter a customer ID.");
935 return;
936 }
937 if ($webvar{custid} !~ /^(?:\d{10}|\d{7}|STAFF)(?:-\d\d?)?$/) {
938 # Force uppercase for now...
939 $webvar{custid} =~ tr/a-z/A-Z/;
940 # Crosscheck with billing.
941 my $status = CustIDCK->custid_exist($webvar{custid});
942 if ($CustIDCK::Error) {
943 printError("Error verifying customer ID: ".$CustIDCK::ErrMsg);
944 return;
945 }
946 if (!$status) {
947 printError("Customer ID not valid. Make sure the Customer ID ".
948 "is correct.<br>\nUse STAFF for staff static IPs, and $IPDB::defcustid for any other ".
949 "non-customer assignments.");
950 return;
951 }
952 }
953# print "<!-- [ In validateInput(). Insert customer ID cross-check here. ] -->\n";
954 } else {
955 # New! Improved! And now Loaded From The Database!!
956 if ((!$webvar{custid}) || ($webvar{custid} ne 'STAFF')) {
957 $webvar{custid} = $def_custids{$webvar{alloctype}};
958 }
959 }
960
961 # Check POP location
962 my $flag;
963 if ($webvar{alloctype} eq 'rm') {
964 $flag = 'for a routed netblock';
965 foreach (@poplist) {
966 if (/^$webvar{city}$/) {
967 $flag = 'n';
968 last;
969 }
970 }
971 } else {
972 $flag = 'n';
973##fixme: hook to force-set POP or city on certain alloctypes
974# if ($webvar{alloctype =~ /foo,bar,bz/ { $webvar{pop} = 'blah'; }
975 if ($webvar{pop} =~ /^-$/) {
976 $flag = 'to route the block from/through';
977 }
978 }
979 if ($flag ne 'n') {
980 printError("Please choose a valid POP location $flag. Valid ".
981 "POP locations are currently:<br>\n".join (" - ", @poplist));
982 return;
983 }
984
985 return 'OK';
986} # end validateInput
987
988
989# Displays details of a specific allocation in a form
990# Allows update/delete
991# action=edit
992sub edit {
993
994 my $sql;
995
996 # Two cases: block is a netblock, or block is a static IP from a pool
997 # because I'm lazy, we'll try to make the SELECT's bring out identical)ish) data
998 if ($webvar{block} =~ /\/32$/) {
999 $sql = "select ip,custid,type,city,circuitid,description,notes,modifystamp,privdata,oldcustid from poolips where ip='$webvar{block}'";
1000 } else {
1001 $sql = "select cidr,custid,type,city,circuitid,description,notes,modifystamp,privdata,oldcustid,swip from allocations where cidr='$webvar{block}'"
1002 }
1003
1004 # gotta snag block info from db
1005 $sth = $ip_dbh->prepare($sql);
1006 $sth->execute;
1007 my @data = $sth->fetchrow_array;
1008
1009 # Clean up extra whitespace on alloc type
1010 $data[2] =~ s/\s//;
1011
1012 open (HTML, "../editDisplay.html")
1013 or croak "Could not open editDisplay.html :$!";
1014 my $html = join('', <HTML>);
1015
1016 # We can't let the city be changed here; this block is a part of
1017 # a larger routed allocation and therefore by definition can't be moved.
1018 # block and city are static.
1019##fixme
1020# Needs thinking. Have to allow changes to city to correct errors, no?
1021 $html =~ s/\$\$BLOCK\$\$/$webvar{block}/g;
1022
1023 if ($IPDBacl{$authuser} =~ /c/) {
1024 $html =~ s/\$\$CUSTID\$\$/<input type=text name=custid value="$data[1]" maxlength=15 class="regular">/;
1025
1026# Screw it. Changing allocation types gets very ugly VERY quickly- especially
1027# with the much longer list of allocation types.
1028# We'll just show what type of block it is.
1029
1030# this has now been Requested, so here goes.
1031
1032##fixme The check here should be built from the database
1033 if ($data[2] =~ /^.[ne]$/) {
1034 # Block that can be changed
1035 my $blockoptions = "<select name=alloctype><option".
1036 (($data[2] eq 'me') ? ' selected' : '') ." value='me'>Dialup netblock</option>\n<option".
1037 (($data[2] eq 'de') ? ' selected' : '') ." value='de'>Dynamic DSL netblock</option>\n<option".
1038 (($data[2] eq 'ce') ? ' selected' : '') ." value='ce'>Dynamic cable netblock</option>\n<option".
1039 (($data[2] eq 'we') ? ' selected' : '') ." value='we'>Dynamic wireless netblock</option>\n<option".
1040 (($data[2] eq 'cn') ? ' selected' : '') ." value='cn'>Customer netblock</option>\n<option".
1041 (($data[2] eq 'en') ? ' selected' : '') ." value='en'>End-use netblock</option>\n<option".
1042 (($data[2] eq 'in') ? ' selected' : '') ." value='in'>Internal netblock</option>\n".
1043 "</select>\n";
1044 $html =~ s/\$\$TYPESELECT\$\$/$blockoptions/g;
1045 } else {
1046 $html =~ s/\$\$TYPESELECT\$\$/$disp_alloctypes{$data[2]}<input type=hidden name=alloctype value="$data[2]">/g;
1047 }
1048## node hack
1049 $sth = $ip_dbh->prepare("SELECT node_id FROM noderef WHERE block='$webvar{block}'");
1050 $sth->execute;
1051 my ($nodeid) = $sth->fetchrow_array();
1052 if ($nodeid) {
1053 $sth = $ip_dbh->prepare("SELECT node_id, node_name FROM nodes ORDER BY node_type,node_id");
1054 $sth->execute() or print "DEBUG: failed retrieval from nodes: ".$sth->errstr,"<br>\n";
1055 my $nodes = "<select name=node>\n";
1056 while (my ($nid,$nname) = $sth->fetchrow_array()) {
1057 $nodes .= "<option".($nodeid == $nid ? ' selected' : '')." value='$nid'>$nname</option>\n";
1058 }
1059 $nodes .= "</select>\n";
1060 $html =~ s/\$\$NODE\$\$/$nodes/;
1061 } else {
1062 if ($data[2] eq 'fr' || $data[2] eq 'bi') {
1063 $sth = $ip_dbh->prepare("SELECT node_id, node_name FROM nodes ORDER BY node_type,node_id");
1064 $sth->execute() or print "DEBUG: failed retrieval from nodes: ".$sth->errstr,"<br>\n";
1065 my $nodes = "<select name=node>\n<option value=>--</option>\n";
1066 while (my ($nid,$nname) = $sth->fetchrow_array()) {
1067 $nodes .= "<option value='$nid'>$nname</option>\n";
1068 }
1069 $nodes .= "</select>\n";
1070 $html =~ s/\$\$NODE\$\$/$nodes/;
1071 } else {
1072 $html =~ s|\$\$NODE\$\$|N/A|;
1073 }
1074 }
1075## end node hack
1076 $html =~ s/\$\$OLDCUSTID\$\$/$data[9]/g;
1077 $html =~ s/\$\$CITY\$\$/<input type=text name=city value="$data[3]">/g;
1078 $html =~ s/\$\$CIRCID\$\$/<input type="text" name="circid" value="$data[4]" maxlength=64 size=64 class="regular">/g;
1079 $html =~ s/\$\$DESC\$\$/<input type="text" name="desc" value="$data[5]" maxlength=64 size=64 class="regular">/g;
1080 $html =~ s|\$\$NOTES\$\$|<textarea rows="8" cols="64" name="notes" class="regular">$data[6]</textarea>|g;
1081 } else {
1082## node hack
1083 if ($data[2] eq 'fr' || $data[2] eq 'bi') {
1084 $sth = $ip_dbh->prepare("SELECT node_name FROM nodes INNER JOIN noderef".
1085 " ON nodes.node_id=noderef.node_id WHERE noderef.block='$webvar{block}'");
1086 $sth->execute() or print "DEBUG: failed retrieval from nodes: ".$sth->errstr,"<br>\n";
1087 my ($node) = $sth->fetchrow_array;
1088 $html =~ s/\$\$NODE\$\$/$node/;
1089 } else {
1090 $html =~ s|\$\$NODE\$\$|N/A|;
1091 }
1092## end node hack
1093 $html =~ s/\$\$CUSTID\$\$/$data[1]/g;
1094 $html =~ s/\$\$OLDCUSTID\$\$/$data[9]/g;
1095 $html =~ s/\$\$TYPESELECT\$\$/$disp_alloctypes{$data[2]}/g;
1096 $html =~ s/\$\$CITY\$\$/$data[3]/g;
1097 $html =~ s/\$\$CIRCID\$\$/$data[4]/g;
1098 $html =~ s/\$\$DESC\$\$/$data[5]/g;
1099 $html =~ s/\$\$NOTES\$\$/$data[6]/g;
1100 }
1101 my ($lastmod,undef) = split /\s+/, $data[7];
1102 $html =~ s/\$\$LASTMOD\$\$/$lastmod/g;
1103
1104## Hack time! SWIP isn't going to stay, so I'm not going to integrate it with ACLs.
1105if ($data[2] =~ /.i/) {
1106 $html =~ s/\$\$SWIP\$\$/N\/A/;
1107} else {
1108 my $tmp = (($data[10] eq 'n') ? '<input type=checkbox name=swip>' :
1109 '<input type=checkbox name=swip checked=yes>');
1110 $html =~ s/\$\$SWIP\$\$/$tmp/;
1111}
1112
1113 # Allows us to "correctly" colour backgrounds in table
1114 my $i=1;
1115
1116 # Check to see if we can display sensitive data
1117 my $privdata = '';
1118 if ($IPDBacl{$authuser} =~ /s/) {
1119 $privdata = qq(<tr class="color).($i%2).qq("><td class=heading>Restricted data:</td>).
1120 qq(<td class=regular><textarea rows="3" cols="64" name="privdata" class="regular">).
1121 qq($data[8]</textarea></td></tr>\n);
1122 $i++;
1123 }
1124 $html =~ s/\$\$PRIVDATA\$\$/$privdata/g;
1125
1126 # More ACL trickery - we can live with forms that don't submit,
1127 # but we can't leave the extra table rows there, and we *really*
1128 # can't leave the submit buttons there.
1129 my $updok = '';
1130 if ($IPDBacl{$authuser} =~ /c/) {
1131 $updok = qq(<tr class="color).($i%2).qq("><td colspan=2><div class="center">).
1132 qq(<input type="submit" value=" Update this block " class="regular">).
1133 "</div></td></tr></form>\n";
1134 $i++;
1135 }
1136 $html =~ s/\$\$UPDOK\$\$/$updok/g;
1137
1138 my $delok = '';
1139 if ($IPDBacl{$authuser} =~ /d/) {
1140 $delok = qq(<form method="POST" action="main.cgi">
1141 <tr class="color).($i%2).qq("><td colspan=2 class="regular"><div class=center>
1142 <input type="hidden" name="action" value="delete">
1143 <input type="hidden" name="block" value="$webvar{block}">
1144 <input type="hidden" name="alloctype" value="$data[2]">
1145 <input type=submit value=" Delete this block ">
1146 </div></td></tr>);
1147 }
1148 $html =~ s/\$\$DELOK\$\$/$delok/;
1149
1150 print $html;
1151
1152} # edit()
1153
1154
1155# Stuff new info about a block into the db
1156# action=update
1157sub update {
1158 if ($IPDBacl{$authuser} !~ /c/) {
1159 printError("You shouldn't have been able to get here. Access denied.");
1160 return;
1161 }
1162
1163 # Check to see if we can update restricted data
1164 my $privdata = '';
1165 if ($IPDBacl{$authuser} =~ /s/) {
1166 $privdata = ",privdata='$webvar{privdata}'";
1167 }
1168
1169 # Make sure incoming data is in correct format - custID among other things.
1170 return if !validateInput;
1171
1172 # SQL transaction wrapper
1173 eval {
1174 # Relatively simple SQL transaction here.
1175 my $sql;
1176 if (my $pooltype = ($webvar{alloctype} =~ /^(.)i$/) ) {
1177 $sql = "update poolips set custid='$webvar{custid}',notes='$webvar{notes}',".
1178 "circuitid='$webvar{circid}',description='$webvar{desc}',city='$webvar{city}'".
1179 "$privdata where ip='$webvar{block}'";
1180 } else {
1181 $sql = "update allocations set custid='$webvar{custid}',".
1182 "description='$webvar{desc}',notes='$webvar{notes}',city='$webvar{city}',".
1183 "type='$webvar{alloctype}',circuitid='$webvar{circid}'$privdata,".
1184 "swip='".($webvar{swip} eq 'on' ? 'y' : 'n')."' ".
1185 "where cidr='$webvar{block}'";
1186 }
1187 # Log the details of the change.
1188 syslog "debug", $sql;
1189 $sth = $ip_dbh->prepare($sql);
1190 $sth->execute;
1191## node hack
1192 if ($webvar{node}) {
1193 $ip_dbh->do("DELETE FROM noderef WHERE block='$webvar{block}'");
1194 $sth = $ip_dbh->prepare("INSERT INTO noderef (block,node_id) VALUES (?,?)");
1195 $sth->execute($webvar{block},$webvar{node});
1196 }
1197## end node hack
1198 $ip_dbh->commit;
1199 };
1200 if ($@) {
1201 my $msg = $@;
1202 carp "Transaction aborted because $msg";
1203 eval { $ip_dbh->rollback; };
1204 syslog "err", "$authuser could not update block/IP '$webvar{block}': '$msg'";
1205 printError("Could not update block/IP $webvar{block}: $msg");
1206 return;
1207 }
1208
1209 # If we get here, the operation succeeded.
1210 syslog "notice", "$authuser updated $webvar{block}";
1211##fixme: need to wedge something in to allow "update:field" notifications
1212## hmm. how to tell what changed? O_o
1213mailNotify($ip_dbh, 's:swi', "SWIPed: $disp_alloctypes{$webvar{alloctype}} $webvar{block}",
1214 "$webvar{block} had SWIP status changed to \"Yes\" by $authuser") if $webvar{swip} eq 'on';
1215 open (HTML, "../updated.html")
1216 or croak "Could not open updated.html :$!";
1217 my $html = join('', <HTML>);
1218
1219 # Link back to browse-routed or list-pool page on "Update complete" page.
1220 my $backlink = "/ip/cgi-bin/main.cgi?action=";
1221 my $cblock; # to contain the CIDR of the container block we're retrieving.
1222 my $sql;
1223 if (my $pooltype = ($webvar{alloctype} =~ /^(.)i$/) ) {
1224 $sql = "select pool from poolips where ip='$webvar{block}'";
1225 $backlink .= "listpool&pool=";
1226 } else {
1227 $sql = "select cidr from routed where cidr >>= '$webvar{block}'";
1228 $backlink .= "showrouted&block=";
1229 }
1230 # I define there to be no errors on this operation... so we don't need to check for them.
1231 $sth = $ip_dbh->prepare($sql);
1232 $sth->execute;
1233 $sth->bind_columns(\$cblock);
1234 $sth->fetch();
1235 $sth->finish;
1236 $backlink .= $cblock;
1237
1238my $swiptmp = ($webvar{swip} eq 'on' ? 'Yes' : 'No');
1239 $html =~ s/\$\$BLOCK\$\$/$webvar{block}/g;
1240 $webvar{city} = $q->escapeHTML($webvar{city});
1241 $html =~ s/\$\$CITY\$\$/$webvar{city}/g;
1242 $html =~ s/\$\$ALLOCTYPE\$\$/$webvar{alloctype}/g;
1243 $html =~ s/\$\$TYPEFULL\$\$/$disp_alloctypes{$webvar{alloctype}}/g;
1244 $html =~ s/\$\$CUSTID\$\$/$webvar{custid}/g;
1245 $html =~ s/\$\$SWIP\$\$/$swiptmp/g;
1246 $webvar{circid} = $q->escapeHTML($webvar{circid});
1247 $html =~ s/\$\$CIRCID\$\$/$webvar{circid}/g;
1248 $webvar{desc} = $q->escapeHTML($webvar{desc});
1249 $html =~ s/\$\$DESC\$\$/$webvar{desc}/g;
1250 $webvar{notes} = $q->escapeHTML($webvar{notes});
1251 $html =~ s/\$\$NOTES\$\$/$webvar{notes}/g;
1252 $html =~ s/\$\$BACKLINK\$\$/$backlink/g;
1253 $html =~ s/\$\$BACKBLOCK\$\$/$cblock/g;
1254
1255 if ($IPDBacl{$authuser} =~ /s/) {
1256 $privdata = qq(<tr class="color2"><td valign="top">Restricted data:</td>).
1257 qq(<td class="regular">).$q->escapeHTML($webvar{privdata}).qq(</td></tr>\n);
1258 }
1259 $html =~ s/\$\$PRIVDATA\$\$/$privdata/g;
1260
1261 print $html;
1262
1263} # update()
1264
1265
1266# Delete an allocation.
1267sub remove {
1268 if ($IPDBacl{$authuser} !~ /d/) {
1269 printError("You shouldn't have been able to get here. Access denied.");
1270 return;
1271 }
1272
1273 #show confirm screen.
1274 open HTML, "../confirmRemove.html"
1275 or croak "Could not open confirmRemove.html :$!";
1276 my $html = join('', <HTML>);
1277 close HTML;
1278
1279 # Serves'em right for getting here...
1280 if (!defined($webvar{block})) {
1281 printError("Error 332");
1282 return;
1283 }
1284
1285 my ($cidr, $custid, $type, $city, $circid, $desc, $notes, $alloctype, $privdata);
1286
1287 if ($webvar{alloctype} eq 'rm') {
1288 $sth = $ip_dbh->prepare("select cidr,city from routed where cidr='$webvar{block}'");
1289 $sth->execute();
1290
1291# This feels... extreme.
1292 croak $sth->errstr() if($sth->errstr());
1293
1294 $sth->bind_columns(\$cidr,\$city);
1295 $sth->execute();
1296 $sth->fetch || croak $sth->errstr();
1297 $custid = "N/A";
1298 $alloctype = $webvar{alloctype};
1299 $circid = "N/A";
1300 $desc = "N/A";
1301 $notes = "N/A";
1302
1303 } elsif ($webvar{alloctype} eq 'mm') {
1304 $cidr = $webvar{block};
1305 $city = "N/A";
1306 $custid = "N/A";
1307 $alloctype = $webvar{alloctype};
1308 $circid = "N/A";
1309 $desc = "N/A";
1310 $notes = "N/A";
1311 } elsif ($webvar{alloctype} =~ /^.i$/) { # done with alloctype=[rm]m
1312
1313 # Unassigning a static IP
1314 my $sth = $ip_dbh->prepare("select ip,custid,city,type,notes,circuitid,privdata".
1315 " from poolips where ip='$webvar{block}'");
1316 $sth->execute();
1317# croak $sth->errstr() if($sth->errstr());
1318
1319 $sth->bind_columns(\$cidr, \$custid, \$city, \$alloctype, \$notes, \$circid,
1320 \$privdata);
1321 $sth->fetch() || croak $sth->errstr;
1322
1323 } else { # done with alloctype=~ /^.i$/
1324
1325 my $sth = $ip_dbh->prepare("select cidr,custid,type,city,circuitid,description,notes,privdata".
1326 " from allocations where cidr='$webvar{block}'");
1327 $sth->execute();
1328# croak $sth->errstr() if($sth->errstr());
1329
1330 $sth->bind_columns(\$cidr, \$custid, \$alloctype, \$city, \$circid, \$desc,
1331 \$notes, \$privdata);
1332 $sth->fetch() || carp $sth->errstr;
1333 } # end cases for different alloctypes
1334
1335 # Munge everything into HTML
1336 $html =~ s|Please confirm|Please confirm <b>removal</b> of|;
1337 $html =~ s|\$\$BLOCK\$\$|$cidr|g;
1338 $html =~ s|\$\$TYPEFULL\$\$|$disp_alloctypes{$alloctype}|g;
1339 $html =~ s|\$\$ALLOCTYPE\$\$|$alloctype|g;
1340 $html =~ s|\$\$CITY\$\$|$city|g;
1341 $html =~ s|\$\$CUSTID\$\$|$custid|g;
1342 $html =~ s|\$\$CIRCID\$\$|$circid|g;
1343 $html =~ s|\$\$DESC\$\$|$desc|g;
1344 $html =~ s|\$\$NOTES\$\$|$notes|g;
1345
1346 $html =~ s|\$\$ACTION\$\$|finaldelete|g;
1347
1348 # Set the warning text.
1349 if ($alloctype =~ /^.[pd]$/) {
1350 $html =~ s|<!--warn-->|<tr bgcolor="black"><td colspan="2"><div class="red">Warning: clicking confirm will remove this record entirely.<br>Any IPs allocated from this pool will also be removed!</div></td></tr>|;
1351 } else {
1352 $html =~ s|<!--warn-->|<tr bgcolor="black"><td colspan="2"><div class="red">Warning: clicking confirm will remove this record entirely.</div></td></tr>|;
1353 }
1354
1355 my $i = 1;
1356 # Check to see if user is allowed to do anything with sensitive data
1357 if ($IPDBacl{$authuser} =~ /s/) {
1358 $privdata = qq(<tr class="color).($i%2).qq("><td>Restricted data:</td>).
1359 qq(<td class=regular>$privdata</td></tr>\n);
1360 $i++;
1361 }
1362 $html =~ s/\$\$PRIVDATA\$\$/$privdata/g;
1363
1364 $i = ++$i % 2;
1365 $html =~ s/\$\$BUTTONROWCOLOUR\$\$/color$i/;
1366
1367 print $html;
1368} # end edit()
1369
1370
1371# Delete an allocation. Return it to the freeblocks table; munge
1372# data as necessary to keep as few records as possible in freeblocks
1373# to prevent weirdness when allocating blocks later.
1374# Remove IPs from pool listing if necessary
1375sub finalDelete {
1376 if ($IPDBacl{$authuser} !~ /d/) {
1377 printError("You shouldn't have been able to get here. Access denied.");
1378 return;
1379 }
1380
1381 # need to retrieve block data before deleting so we can notify on that
1382 my ($cidr,$custid,$type,$city,$description) = getBlockData($ip_dbh, $webvar{block});
1383
1384 my ($code,$msg) = deleteBlock($ip_dbh, $webvar{block}, $webvar{alloctype});
1385
1386 if ($code eq 'OK') {
1387 print "<div class=heading align=center>Success! $webvar{block} deallocated.</div>\n";
1388 syslog "notice", "$authuser deallocated '$webvar{alloctype}'-type netblock $webvar{block}".
1389 " $custid, $city, desc='$description'";
1390 mailNotify($ip_dbh, 'da', "REMOVED: $disp_alloctypes{$webvar{alloctype}} $webvar{block}",
1391 "$disp_alloctypes{$webvar{alloctype}} $webvar{block} deallocated by $authuser\n".
1392 "CustID: $custid\nCity: $city\nDescription: $description\n");
1393 } else {
1394 if ($webvar{alloctype} =~ /^.i$/) {
1395 syslog "err", "$authuser could not deallocate static IP '$webvar{block}': '$msg'";
1396 printError("Could not deallocate static IP $webvar{block}: $msg");
1397 } else {
1398 syslog "err", "$authuser could not deallocate netblock '$webvar{block}': '$msg'";
1399 printError("Could not deallocate netblock $webvar{block}: $msg");
1400 }
1401 }
1402
1403} # finalDelete
1404
1405
1406# going, going, gone... this sub to be removed Any Day Real Soon Now(TM)
1407sub exitError {
1408 my $errStr = $_[0];
1409 printHeader('','');
1410 print qq(<center><p class="regular"> $errStr </p>
1411<input type="button" value="Back" onclick="history.go(-1)">
1412</center>
1413);
1414
1415 # We print the footer here, so we don't have to do it elsewhere.
1416 # include the admin tools link in the output?
1417 $footer->param(adminlink => ($IPDBacl{$authuser} =~ /A/));
1418
1419 print $footer->output;
1420
1421 exit;
1422} # errorExit
1423
1424
1425# Just in case we manage to get here.
1426exit 0;
Note: See TracBrowser for help on using the repository browser.