3 # Adds or updates a record of some type
5 require './dns-lib.pl';
7 %access = &get_module_acl();
8 &can_edit_zone(\%access, $in{'origin'}) ||
9 &error("You are not allowed to edit records in this zone");
10 &lock_file($in{'file'});
11 @recs = &read_zone_file($in{'file'}, $in{'origin'});
12 $whatfailed = "Failed to save record";
14 # get the old record if needed
15 $r = $recs[$in{'num'}] if (defined($in{'num'}));
19 &lock_file($r->{'file'});
20 &delete_record($r->{'file'}, $r);
21 &bump_soa_record($in{'file'}, \@recs);
22 ($orevconf, $orevfile, $orevrec) = &find_reverse($in{'oldvalue0'});
23 if ($in{'rev'} && $orevrec && &can_edit_reverse($orevconf) &&
24 $in{'oldname'} eq $orevrec->{'values'}->[0] &&
25 $in{'oldvalue0'} eq &arpa_to_ip($orevrec->{'name'})) {
26 &lock_file($orevrec->{'file'});
27 &delete_record($orevrec->{'file'} , $orevrec);
28 &lock_file($orevfile);
29 @orrecs = &read_zone_file(
30 $orevfile, $orevconf->{'values'}->[0]);
31 &bump_soa_record($orevfile, \@orrecs);
34 ($ofwdconf, $ofwdfile, $ofwdrec) = &find_forward($in{'oldvalue0'});
35 if ($in{'fwd'} && $ofwdrec &&
36 &can_edit_zone($ofwdconf->{'values'}->[0]) &&
37 &arpa_to_ip($in{'oldname'}) eq $ofwdrec->{'values'}->[0] &&
38 $in{'oldvalue0'} eq $ofwdrec->{'name'}) {
39 &lock_file($ofwdrec->{'file'});
40 &delete_record($ofwdrec->{'file'}, $ofwdrec);
41 &lock_file($ofwdfile);
42 @ofrecs = &read_zone_file($ofwdfile,$ofwdconf->{'values'}->[0]);
43 &bump_soa_record($ofwdfile, \@ofrecs);
46 &redirect("edit_recs.cgi?index=$in{'index'}&type=$in{'type'}");
48 &webmin_log('delete', 'record', $in{'origin'}, $r);
53 if (!$in{'ttl_def'}) {
54 $in{'ttl'} =~ /^\d+$/ ||
55 &error("'$in{'ttl'}' is not a valid time-to-live");
58 $vals = $in{'value0'};
59 for($i=1; defined($in{"value$i"}); $i++) {
60 $vals .= " ".$in{"value$i"};
62 if ($in{'type'} eq "PTR") {
64 &check_ipaddress($in{'name'}) ||
65 &error("'$in{'name'}' is not a valid IP address");
66 $name = &ip_to_arpa($in{'name'});
67 &valname($in{'value0'}) ||
68 &error("'$vals[0]' is not a valid hostname");
69 if ($in{'value0'} !~ /\.$/) { $vals .= "."; }
72 # some other kind of record
73 $in{'name'} eq "" || &valname($in{'name'}) ||
74 &error("'$in{'name'}' is not a valid ",
75 lc($code_map{$in{'type'}})," record name");
76 if ($in{'type'} eq "A") {
77 &check_ipaddress($vals) ||
78 &error("'$vals' is not a valid IP address");
79 if (!$access{'multiple'}) {
80 $conf = &get_config();
81 @zl = &find_config("primary", $conf);
83 $file = $z->{'values'}->[1];
84 @frecs = &read_zone_file($z->{'values'}->[1],
86 foreach $fr (@frecs) {
87 if ($fr->{'type'} eq "A" &&
88 $fr->{'values'}->[0] eq $vals &&
89 $fr->{'name'} ne $r->{'name'}) {
90 &error("An address record for ",
91 "$vals already exists");
97 elsif ($in{'type'} eq "NS") {
99 &error("'$vals' is not a valid nameserver");
101 elsif ($in{'type'} eq "CNAME") {
103 &error("'$vals' is not a valid alias target");
105 elsif ($in{'type'} eq "MX") {
106 $in{'value1'} =~ /^[A-z0-9\-\.\*]+$/ ||
107 &error("'$in{'value1'}' is not a valid mail server");
108 $in{'value0'} =~ /^\d+$/ ||
109 &error("'$in{'value0'}' is not a valid priority");
111 elsif ($in{'type'} eq "HINFO") {
112 $in{'value0'} =~ /^\S+$/ ||
113 &error("'$in{'value0'}' is not a valid hardware type");
114 $in{'value1'} =~ /^\S+$/ ||
115 &error("'$in{'value1'}' is not a valid OS type");
117 elsif ($in{'type'} eq "TXT") {
118 $vals = "\"$in{'value0'}\"";
120 elsif ($in{'type'} eq "WKS") {
121 &check_ipaddress($in{'value0'}) ||
122 &error("'$in{'value0'}' is not a valid IP address");
123 if (!$in{'value2'}) {
124 &error("You did not enter any well known services");
126 @ws = split(/[\r\n]+/, $in{'value2'});
127 $vals = "$in{'value0'} $in{'value1'} (";
128 foreach $ws (@ws) { $vals .= "\n\t\t\t\t\t$ws"; }
131 elsif ($in{'type'} eq "RP") {
132 $in{'value0'} =~ /^(\S+)\@(\S+)$/ ||
133 &error("'$in{'value0'}' is not a valid email address");
134 &valname($in{'value1'}) ||
135 &error("'$in{'value1'}' is not a valid text record");
136 $in{'value0'} =~ s/\@/\./g;
137 $vals = "$in{'value0'} $in{'value1'}";
139 $name = $in{'name'} eq "" ? "$in{'origin'}." :
140 $in{'name'} !~ /\.$/ ? "$in{'name'}.$in{'origin'}." :
145 # just adding a new record
146 &create_record($in{'file'}, $name, $ttl, "IN", $in{'type'}, $vals);
147 $r = { 'name' => $name, 'ttl' => $ttl, 'class' => 'IN',
148 'type' => $in{'type'}, 'values' => [ split(/\s+/, $vals) ] };
149 ($revconf, $revfile, $revrec) = &find_reverse($in{'value0'});
150 if ($in{'rev'} && $revconf && !$revrec && &can_edit_reverse($revconf)) {
151 # Add a reverse record if we are the master for the reverse
152 # domain, and if there is not already a reverse record
154 &lock_file($revfile);
155 &create_record($revfile,
156 &ip_to_arpa($in{'value0'}), $ttl,
158 @rrecs = &read_zone_file($revfile, $revconf->{'values'}->[0]);
159 &bump_soa_record($revfile, \@rrecs);
162 ($fwdconf, $fwdfile, $fwdrec) = &find_forward($vals);
163 if ($in{'fwd'} && $fwdconf && !$fwdrec &&
164 &can_edit_zone($fwdconf->{'values'}->[0])) {
165 # Add a forward record if we are the master for the forward
166 # domain, and if there is not already an A record
168 &lock_file($fwdfile);
169 &create_record($fwdfile, $vals,
170 $ttl, "IN", "A", $in{'name'});
171 @frecs = &read_zone_file($fwdfile, $fwdconf->{'values'}->[0]);
172 &bump_soa_record($fwdfile, \@frecs);
176 # updating an existing record
177 ($orevconf, $orevfile, $orevrec) = &find_reverse($in{'oldvalue0'});
178 ($revconf, $revfile, $revrec) = &find_reverse($in{'value0'});
179 &lock_file($r->{'file'});
180 &modify_record($r->{'file'}, $r, $name, $ttl,
181 "IN", $in{'type'},$vals);
183 if ($in{'rev'} && $orevrec && &can_edit_reverse($orevconf) &&
184 $in{'oldname'} eq $orevrec->{'values'}->[0] &&
185 $in{'oldvalue0'} eq &arpa_to_ip($orevrec->{'name'})) {
186 # Updating the reverse record. Either the name, address
187 # or both may have changed. Furthermore, the reverse record
188 # may now be in a different file!
189 &lock_file($orevfile);
190 &lock_file($revfile);
191 @orrecs = &read_zone_file($orevfile,$orevconf->{'values'}->[0]);
192 @rrecs = &read_zone_file($revfile, $revconf->{'values'}->[0]);
193 if ($revconf eq $orevconf && &can_edit_reverse($revconf)) {
194 # old and new in the same file
195 &modify_record($orevrec->{'file'} , $orevrec,
196 &ip_to_arpa($in{'value0'}),
197 $orevrec->{'ttl'}, "IN", "PTR", $name);
198 &bump_soa_record($orevfile, \@orrecs);
200 elsif ($revconf && &can_edit_reverse($revconf)) {
201 # old and new in different files
202 &delete_record($orevrec->{'file'} , $orevrec);
203 &create_record($revfile, &ip_to_arpa($in{'value0'}),
204 $orevrec->{'ttl'}, "IN", "PTR", $name);
205 &bump_soa_record($orevfile, \@orrecs);
206 &bump_soa_record($revfile, \@rrecs);
209 # we don't handle the new reverse domain.. lose the
211 &delete_record($orevrec->{'file'}, $orevrec);
212 &bump_soa_record($orevfile, \@orrecs);
216 ($ofwdconf, $ofwdfile, $ofwdrec) = &find_forward($in{'oldvalue0'});
217 ($fwdconf, $fwdfile, $fwdrec) = &find_forward($in{'value0'});
218 if ($in{'fwd'} && $ofwdrec &&
219 &can_edit_zone($ofwdconf->{'values'}->[0]) &&
220 &arpa_to_ip($in{'oldname'}) eq $ofwdrec->{'values'}->[0] &&
221 $in{'oldvalue0'} eq $ofwdrec->{'name'}) {
222 # Updating the forward record
223 &lock_file($ofwdfile);
224 &lock_file($fwdfile);
225 @ofrecs = &read_zone_file($ofwdfile,$ofwdconf->{'values'}->[0]);
226 @frecs = &read_zone_file($fwdfile, $fwdconf->{'values'}->[0]);
227 if ($fwdconf eq $ofwdconf &&
228 &can_edit_zone($fwdconf->{'values'}->[0])) {
229 # old and new are in the same file
230 &modify_record($ofwdrec->{'file'} , $ofwdrec, $vals,
231 $ofwdrec->{'ttl'}, "IN", "A",
233 &bump_soa_record($ofwdfile, \@ofrecs);
235 elsif ($fwdconf && &can_edit_zone($fwdconf->{'values'}->[0])) {
236 # old and new in different files
237 &delete_record($ofwdrec->{'file'} , $ofwdrec);
238 &create_record($fwdfile, $vals, $ofwdrec->{'ttl'},
239 "IN", "A", $in{'name'});
240 &bump_soa_record($ofwdfile, \@ofrecs);
241 &bump_soa_record($fwdfile, \@frecs);
244 # lose the forward because it has been moved to
245 # a zone not handled by this server
246 &delete_record($ofwdrec->{'file'} , $ofwdrec);
247 &bump_soa_record($ofwdfile, \@ofrecs);
251 &bump_soa_record($in{'file'}, \@recs);
253 &webmin_log($in{'new'} ? 'create' : 'modify', 'record', $in{'origin'}, $r);
254 &redirect("edit_recs.cgi?index=$in{'index'}&type=$in{'type'}");
258 return $_[0] =~ /[A-z0-9\-\.]+$/;
261 # can_edit_reverse(&zone)
264 return $access{'reverse'} || &can_edit_zone(\%access, $_[0]->{'values'}->[0]);