mirror of
https://github.com/webmin/webmin.git
synced 2026-02-03 14:13:29 +00:00
267 lines
8.9 KiB
Perl
Executable File
267 lines
8.9 KiB
Perl
Executable File
#!/usr/local/bin/perl
|
|
# save_record.cgi
|
|
# Adds or updates a record of some type
|
|
|
|
require './dns-lib.pl';
|
|
&ReadParse();
|
|
%access = &get_module_acl();
|
|
&can_edit_zone(\%access, $in{'origin'}) ||
|
|
&error("You are not allowed to edit records in this zone");
|
|
&lock_file($in{'file'});
|
|
@recs = &read_zone_file($in{'file'}, $in{'origin'});
|
|
$whatfailed = "Failed to save record";
|
|
|
|
# get the old record if needed
|
|
$r = $recs[$in{'num'}] if (defined($in{'num'}));
|
|
|
|
# check for deletion
|
|
if ($in{'delete'}) {
|
|
&lock_file($r->{'file'});
|
|
&delete_record($r->{'file'}, $r);
|
|
&bump_soa_record($in{'file'}, \@recs);
|
|
($orevconf, $orevfile, $orevrec) = &find_reverse($in{'oldvalue0'});
|
|
if ($in{'rev'} && $orevrec && &can_edit_reverse($orevconf) &&
|
|
$in{'oldname'} eq $orevrec->{'values'}->[0] &&
|
|
$in{'oldvalue0'} eq &arpa_to_ip($orevrec->{'name'})) {
|
|
&lock_file($orevrec->{'file'});
|
|
&delete_record($orevrec->{'file'} , $orevrec);
|
|
&lock_file($orevfile);
|
|
@orrecs = &read_zone_file(
|
|
$orevfile, $orevconf->{'values'}->[0]);
|
|
&bump_soa_record($orevfile, \@orrecs);
|
|
}
|
|
|
|
($ofwdconf, $ofwdfile, $ofwdrec) = &find_forward($in{'oldvalue0'});
|
|
if ($in{'fwd'} && $ofwdrec &&
|
|
&can_edit_zone($ofwdconf->{'values'}->[0]) &&
|
|
&arpa_to_ip($in{'oldname'}) eq $ofwdrec->{'values'}->[0] &&
|
|
$in{'oldvalue0'} eq $ofwdrec->{'name'}) {
|
|
&lock_file($ofwdrec->{'file'});
|
|
&delete_record($ofwdrec->{'file'}, $ofwdrec);
|
|
&lock_file($ofwdfile);
|
|
@ofrecs = &read_zone_file($ofwdfile,$ofwdconf->{'values'}->[0]);
|
|
&bump_soa_record($ofwdfile, \@ofrecs);
|
|
}
|
|
|
|
&redirect("edit_recs.cgi?index=$in{'index'}&type=$in{'type'}");
|
|
&unlock_all_files();
|
|
&webmin_log('delete', 'record', $in{'origin'}, $r);
|
|
exit;
|
|
}
|
|
|
|
# parse inputs
|
|
if (!$in{'ttl_def'}) {
|
|
$in{'ttl'} =~ /^\d+$/ ||
|
|
&error("'$in{'ttl'}' is not a valid time-to-live");
|
|
$ttl = $in{'ttl'};
|
|
}
|
|
$vals = $in{'value0'};
|
|
for($i=1; defined($in{"value$i"}); $i++) {
|
|
$vals .= " ".$in{"value$i"};
|
|
}
|
|
if ($in{'type'} eq "PTR") {
|
|
# a reverse address
|
|
&check_ipaddress($in{'name'}) ||
|
|
&error("'$in{'name'}' is not a valid IP address");
|
|
$name = &ip_to_arpa($in{'name'});
|
|
&valname($in{'value0'}) ||
|
|
&error("'$vals[0]' is not a valid hostname");
|
|
if ($in{'value0'} !~ /\.$/) { $vals .= "."; }
|
|
}
|
|
else {
|
|
# some other kind of record
|
|
$in{'name'} eq "" || &valname($in{'name'}) ||
|
|
&error("'$in{'name'}' is not a valid ",
|
|
lc($code_map{$in{'type'}})," record name");
|
|
if ($in{'type'} eq "A") {
|
|
&check_ipaddress($vals) ||
|
|
&error("'$vals' is not a valid IP address");
|
|
if (!$access{'multiple'}) {
|
|
$conf = &get_config();
|
|
@zl = &find_config("primary", $conf);
|
|
foreach $z (@zl) {
|
|
$file = $z->{'values'}->[1];
|
|
@frecs = &read_zone_file($z->{'values'}->[1],
|
|
$z->{'values'}->[0]);
|
|
foreach $fr (@frecs) {
|
|
if ($fr->{'type'} eq "A" &&
|
|
$fr->{'values'}->[0] eq $vals &&
|
|
$fr->{'name'} ne $r->{'name'}) {
|
|
&error("An address record for ",
|
|
"$vals already exists");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
elsif ($in{'type'} eq "NS") {
|
|
&valname($vals) ||
|
|
&error("'$vals' is not a valid nameserver");
|
|
}
|
|
elsif ($in{'type'} eq "CNAME") {
|
|
&valname($vals) ||
|
|
&error("'$vals' is not a valid alias target");
|
|
}
|
|
elsif ($in{'type'} eq "MX") {
|
|
$in{'value1'} =~ /^[A-z0-9\-\.\*]+$/ ||
|
|
&error("'$in{'value1'}' is not a valid mail server");
|
|
$in{'value0'} =~ /^\d+$/ ||
|
|
&error("'$in{'value0'}' is not a valid priority");
|
|
}
|
|
elsif ($in{'type'} eq "HINFO") {
|
|
$in{'value0'} =~ /^\S+$/ ||
|
|
&error("'$in{'value0'}' is not a valid hardware type");
|
|
$in{'value1'} =~ /^\S+$/ ||
|
|
&error("'$in{'value1'}' is not a valid OS type");
|
|
}
|
|
elsif ($in{'type'} eq "TXT") {
|
|
$vals = "\"$in{'value0'}\"";
|
|
}
|
|
elsif ($in{'type'} eq "WKS") {
|
|
&check_ipaddress($in{'value0'}) ||
|
|
&error("'$in{'value0'}' is not a valid IP address");
|
|
if (!$in{'value2'}) {
|
|
&error("You did not enter any well known services");
|
|
}
|
|
@ws = split(/[\r\n]+/, $in{'value2'});
|
|
$vals = "$in{'value0'} $in{'value1'} (";
|
|
foreach $ws (@ws) { $vals .= "\n\t\t\t\t\t$ws"; }
|
|
$vals .= " )";
|
|
}
|
|
elsif ($in{'type'} eq "RP") {
|
|
$in{'value0'} =~ /^(\S+)\@(\S+)$/ ||
|
|
&error("'$in{'value0'}' is not a valid email address");
|
|
&valname($in{'value1'}) ||
|
|
&error("'$in{'value1'}' is not a valid text record");
|
|
$in{'value0'} =~ s/\@/\./g;
|
|
$vals = "$in{'value0'} $in{'value1'}";
|
|
}
|
|
$name = $in{'name'} eq "" ? "$in{'origin'}." :
|
|
$in{'name'} !~ /\.$/ ? "$in{'name'}.$in{'origin'}." :
|
|
$in{'name'};
|
|
}
|
|
|
|
if ($in{'new'}) {
|
|
# just adding a new record
|
|
&create_record($in{'file'}, $name, $ttl, "IN", $in{'type'}, $vals);
|
|
$r = { 'name' => $name, 'ttl' => $ttl, 'class' => 'IN',
|
|
'type' => $in{'type'}, 'values' => [ split(/\s+/, $vals) ] };
|
|
($revconf, $revfile, $revrec) = &find_reverse($in{'value0'});
|
|
if ($in{'rev'} && $revconf && !$revrec && &can_edit_reverse($revconf)) {
|
|
# Add a reverse record if we are the master for the reverse
|
|
# domain, and if there is not already a reverse record
|
|
# for the address.
|
|
&lock_file($revfile);
|
|
&create_record($revfile,
|
|
&ip_to_arpa($in{'value0'}), $ttl,
|
|
"IN", "PTR", $name);
|
|
@rrecs = &read_zone_file($revfile, $revconf->{'values'}->[0]);
|
|
&bump_soa_record($revfile, \@rrecs);
|
|
}
|
|
|
|
($fwdconf, $fwdfile, $fwdrec) = &find_forward($vals);
|
|
if ($in{'fwd'} && $fwdconf && !$fwdrec &&
|
|
&can_edit_zone($fwdconf->{'values'}->[0])) {
|
|
# Add a forward record if we are the master for the forward
|
|
# domain, and if there is not already an A record
|
|
# for the address
|
|
&lock_file($fwdfile);
|
|
&create_record($fwdfile, $vals,
|
|
$ttl, "IN", "A", $in{'name'});
|
|
@frecs = &read_zone_file($fwdfile, $fwdconf->{'values'}->[0]);
|
|
&bump_soa_record($fwdfile, \@frecs);
|
|
}
|
|
}
|
|
else {
|
|
# updating an existing record
|
|
($orevconf, $orevfile, $orevrec) = &find_reverse($in{'oldvalue0'});
|
|
($revconf, $revfile, $revrec) = &find_reverse($in{'value0'});
|
|
&lock_file($r->{'file'});
|
|
&modify_record($r->{'file'}, $r, $name, $ttl,
|
|
"IN", $in{'type'},$vals);
|
|
|
|
if ($in{'rev'} && $orevrec && &can_edit_reverse($orevconf) &&
|
|
$in{'oldname'} eq $orevrec->{'values'}->[0] &&
|
|
$in{'oldvalue0'} eq &arpa_to_ip($orevrec->{'name'})) {
|
|
# Updating the reverse record. Either the name, address
|
|
# or both may have changed. Furthermore, the reverse record
|
|
# may now be in a different file!
|
|
&lock_file($orevfile);
|
|
&lock_file($revfile);
|
|
@orrecs = &read_zone_file($orevfile,$orevconf->{'values'}->[0]);
|
|
@rrecs = &read_zone_file($revfile, $revconf->{'values'}->[0]);
|
|
if ($revconf eq $orevconf && &can_edit_reverse($revconf)) {
|
|
# old and new in the same file
|
|
&modify_record($orevrec->{'file'} , $orevrec,
|
|
&ip_to_arpa($in{'value0'}),
|
|
$orevrec->{'ttl'}, "IN", "PTR", $name);
|
|
&bump_soa_record($orevfile, \@orrecs);
|
|
}
|
|
elsif ($revconf && &can_edit_reverse($revconf)) {
|
|
# old and new in different files
|
|
&delete_record($orevrec->{'file'} , $orevrec);
|
|
&create_record($revfile, &ip_to_arpa($in{'value0'}),
|
|
$orevrec->{'ttl'}, "IN", "PTR", $name);
|
|
&bump_soa_record($orevfile, \@orrecs);
|
|
&bump_soa_record($revfile, \@rrecs);
|
|
}
|
|
else {
|
|
# we don't handle the new reverse domain.. lose the
|
|
# reverse record
|
|
&delete_record($orevrec->{'file'}, $orevrec);
|
|
&bump_soa_record($orevfile, \@orrecs);
|
|
}
|
|
}
|
|
|
|
($ofwdconf, $ofwdfile, $ofwdrec) = &find_forward($in{'oldvalue0'});
|
|
($fwdconf, $fwdfile, $fwdrec) = &find_forward($in{'value0'});
|
|
if ($in{'fwd'} && $ofwdrec &&
|
|
&can_edit_zone($ofwdconf->{'values'}->[0]) &&
|
|
&arpa_to_ip($in{'oldname'}) eq $ofwdrec->{'values'}->[0] &&
|
|
$in{'oldvalue0'} eq $ofwdrec->{'name'}) {
|
|
# Updating the forward record
|
|
&lock_file($ofwdfile);
|
|
&lock_file($fwdfile);
|
|
@ofrecs = &read_zone_file($ofwdfile,$ofwdconf->{'values'}->[0]);
|
|
@frecs = &read_zone_file($fwdfile, $fwdconf->{'values'}->[0]);
|
|
if ($fwdconf eq $ofwdconf &&
|
|
&can_edit_zone($fwdconf->{'values'}->[0])) {
|
|
# old and new are in the same file
|
|
&modify_record($ofwdrec->{'file'} , $ofwdrec, $vals,
|
|
$ofwdrec->{'ttl'}, "IN", "A",
|
|
$in{'name'});
|
|
&bump_soa_record($ofwdfile, \@ofrecs);
|
|
}
|
|
elsif ($fwdconf && &can_edit_zone($fwdconf->{'values'}->[0])) {
|
|
# old and new in different files
|
|
&delete_record($ofwdrec->{'file'} , $ofwdrec);
|
|
&create_record($fwdfile, $vals, $ofwdrec->{'ttl'},
|
|
"IN", "A", $in{'name'});
|
|
&bump_soa_record($ofwdfile, \@ofrecs);
|
|
&bump_soa_record($fwdfile, \@frecs);
|
|
}
|
|
else {
|
|
# lose the forward because it has been moved to
|
|
# a zone not handled by this server
|
|
&delete_record($ofwdrec->{'file'} , $ofwdrec);
|
|
&bump_soa_record($ofwdfile, \@ofrecs);
|
|
}
|
|
}
|
|
}
|
|
&bump_soa_record($in{'file'}, \@recs);
|
|
&unlock_all_files();
|
|
&webmin_log($in{'new'} ? 'create' : 'modify', 'record', $in{'origin'}, $r);
|
|
&redirect("edit_recs.cgi?index=$in{'index'}&type=$in{'type'}");
|
|
|
|
sub valname
|
|
{
|
|
return $_[0] =~ /[A-z0-9\-\.]+$/;
|
|
}
|
|
|
|
# can_edit_reverse(&zone)
|
|
sub can_edit_reverse
|
|
{
|
|
return $access{'reverse'} || &can_edit_zone(\%access, $_[0]->{'values'}->[0]);
|
|
}
|
|
|