diff --git a/webmin/letsencrypt-cleanup.pl b/webmin/letsencrypt-cleanup.pl index 834f2a773..c4f0c1628 100755 --- a/webmin/letsencrypt-cleanup.pl +++ b/webmin/letsencrypt-cleanup.pl @@ -19,22 +19,44 @@ my $dname = $ENV{'CERTBOT_DOMAIN'}; $dname || die "Missing CERTBOT_DOMAIN environment variable"; # Find the DNS domain and records +my $d = &get_virtualmin_for_domain($dname); my ($zone, $zname) = &get_bind_zone_for_domain($dname); -$zone || die "No zone named $dname found"; -$zone->{'file'} || die "Zone $dname does not have a records file"; -&lock_file(&bind8::make_chroot(&bind8::absolute_path($zone->{'file'}))); -my @recs = &bind8::read_zone_file($zone->{'file'}, $zname); +my ($recs, $file); +if ($zone) { + # Use BIND module API calls + $zone->{'file'} || die "Zone $dname does not have a records file"; + &lock_file(&bind8::make_chroot(&bind8::absolute_path($zone->{'file'}))); + $recs = [ &bind8::read_zone_file($zone->{'file'}, $zname) ]; + $file = $zone->{'file'}; + } +elsif ($d) { + # Use Virtualmin API calls + &virtual_server::obtain_lock_dns($d); + ($recs, $file) = &virtual_server::get_domain_dns_records_and_file($d); + } +else { + die "No DNS zone named $dname found"; + } # Find and remove the record. Does nothing if it doesn't exist so as not to # fail a repeated cleanup. -my ($r) = grep { $_->{'name'} eq "_acme-challenge.".$dname."." } @recs; +my ($r) = grep { $_->{'name'} eq "_acme-challenge.".$dname."." } @$recs; if ($r) { - &bind8::delete_record($zone->{'file'}, $r); - &bind8::sign_dnssec_zone_if_key($zone, \@recs); - &bind8::bump_soa_record($zone->{'file'}, \@recs); + &bind8::delete_record($file, $r); + } + +if ($zone) { + # Apply using BIND API calls + &bind8::sign_dnssec_zone_if_key($zone, $recs); + &bind8::bump_soa_record($file, $recs); + &unlock_file(&bind8::make_chroot(&bind8::absolute_path($file))); + &bind8::restart_zone($zone->{'name'}, $zone->{'view'}); + } +else { + # Apply using Virtualmin API + &virtual_server::post_records_change($d, $recs, $file); + &virtual_server::release_lock_dns($d); + &virtual_server::reload_bind_records($d); } -&unlock_file(&bind8::make_chroot(&bind8::absolute_path($zone->{'file'}))); -# Apply the change -&bind8::restart_zone($zone->{'name'}, $zone->{'view'}); &webmin_log("letsencryptcleanup", undef, $dname); diff --git a/webmin/letsencrypt-dns.pl b/webmin/letsencrypt-dns.pl index ad5df3916..a63f36d13 100755 --- a/webmin/letsencrypt-dns.pl +++ b/webmin/letsencrypt-dns.pl @@ -21,31 +21,52 @@ $dname || die "Missing CERTBOT_DOMAIN environment variable"; $val || die "Missing CERTBOT_VALIDATION environment variable"; # Find the DNS domain and records +$d = &get_virtualmin_for_domain($dname); my ($zone, $zname) = &get_bind_zone_for_domain($dname); -$zone || die "No zone named $dname found"; -$zone->{'file'} || die "Zone $dname does not have a records file"; -&lock_file(&bind8::make_chroot(&bind8::absolute_path($zone->{'file'}))); -my @recs = &bind8::read_zone_file($zone->{'file'}, $zname); +my ($recs, $file); +if ($zone) { + # Use BIND module API calls + $zone->{'file'} || die "Zone $dname does not have a records file"; + &lock_file(&bind8::make_chroot(&bind8::absolute_path($zone->{'file'}))); + $recs = [ &bind8::read_zone_file($zone->{'file'}, $zname) ]; + $file = $zone->{'file'}; + } +elsif ($d) { + # Use Virtualmin API calls + &virtual_server::obtain_lock_dns($d); + ($recs, $file) = &virtual_server::get_domain_dns_records_and_file($d); + } +else { + die "No DNS zone named $dname found"; + } # Remove any existing record -my ($r) = grep { $_->{'name'} eq "_acme-challenge.".$dname."." } @recs; +my ($r) = grep { $_->{'name'} eq "_acme-challenge.".$dname."." } @$recs; if ($r) { - &bind8::delete_record($zone->{'file'}, $r); + &bind8::delete_record($file, $r); } # Create the needed DNS record -&bind8::create_record($zone->{'file'}, +&bind8::create_record($file, "_acme-challenge.".$dname.".", 5, "IN", "TXT", $val); -&bind8::bump_soa_record($zone->{'file'}, \@recs); -&bind8::sign_dnssec_zone_if_key($zone, \@recs); -&unlock_file(&bind8::make_chroot(&bind8::absolute_path($zone->{'file'}))); -# Apply the change -&bind8::restart_zone($zone->{'name'}, $zone->{'view'}); +if ($zone) { + # Apply using BIND API calls + &bind8::bump_soa_record($file, $recs); + &bind8::sign_dnssec_zone_if_key($zone, $recs); + &unlock_file(&bind8::make_chroot(&bind8::absolute_path($file))); + &bind8::restart_zone($zone->{'name'}, $zone->{'view'}); + } +else { + # Apply using Virtualmin API + &virtual_server::post_records_change($d, $recs, $file); + &virtual_server::release_lock_dns($d); + &virtual_server::reload_bind_records($d); + } sleep($config{'letsencrypt_dns_wait'} || 10); # Wait for DNS propagation &webmin_log("letsencryptdns", undef, $dname); exit(0); diff --git a/webmin/letsencrypt-lib.pl b/webmin/letsencrypt-lib.pl index b557481af..dcaf04d1a 100755 --- a/webmin/letsencrypt-lib.pl +++ b/webmin/letsencrypt-lib.pl @@ -123,8 +123,9 @@ elsif ($mode eq "dns") { &foreign_require("bind8"); foreach my $d (@doms) { my $z = &get_bind_zone_for_domain($d); - $z || return (0, "Neither DNS zone $d or any of its ". - "sub-domains exist on this system"); + my $d = &get_virtualmin_for_domain($d); + $z || $d || return (0, "Neither DNS zone $d or any of its ". + "sub-domains exist on this system"); } } else { @@ -411,6 +412,23 @@ while ($bd =~ /\./) { return ( ); } +# get_virtualmin_for_domain(domain-name) +# If Virtualmin is installed, return the domain object that contains the given DNS domain +sub get_virtualmin_for_domain +{ +my ($bd) = @_; +return undef if (!&foreign_check("virtual-server")); +&foreign_require("virtual-server"); +while ($bd =~ /\./) { + my $d = &virtual_server::get_domain_by("dom", $bd); + if ($d && $d->{'dns'}) { + return $d; + } + $bd =~ s/^[^\.]+\.//; + } +return undef; +} + # get_certbot_major_version(cmd) # Returns Let's Encrypt client major version, such as 1.11 or 0.40 sub get_certbot_major_version