aboutsummaryrefslogtreecommitdiff
path: root/vhostcname
diff options
context:
space:
mode:
Diffstat (limited to 'vhostcname')
-rwxr-xr-xvhostcname/vhostcname774
1 files changed, 572 insertions, 202 deletions
diff --git a/vhostcname/vhostcname b/vhostcname/vhostcname
index 359101c..fc6dd2d 100755
--- a/vhostcname/vhostcname
+++ b/vhostcname/vhostcname
@@ -1,3 +1,3 @@
1#!/usr/bin/perl 1#!/usr/bin/perl
2# Copyright (C) 2014 Sergey Poznyakoff <gray@gnu.org> 2# Copyright (C) 2014-2016 Sergey Poznyakoff <gray@gnu.org>
3# 3#
@@ -24,26 +24,31 @@ use Net::DNS;
24 24
25my $script; # This script name; 25my $progname; # This script name;
26 26my $progdescr = "update DNS from Apache virtual host configuration";
27my $config_file = "/etc/vhostcname.conf"; 27my $config_file = "/etc/vhostcname.conf";
28my %config = (
29 core => {
30 'cache' => "/var/run/vhostcname.cache",
31# Default TTL.
32 'ttl' => 3600,
33# A globbing pattern for Apache configuration files.
34 'apache-config-pattern' => "*",
35 }
36);
37
38use constant EX_OK => 0;
39use constant EX_NOTUPDATED => 1;
40use constant EX_USAGE => 64;
41use constant EX_NOINPUT => 66;
42use constant EX_CANTCREAT => 73;
43use constant EX_CONFIG => 78;
28 44
29my $cnamelist = "/var/run/vhostcname.cache";
30my $host; # This host name. 45my $host; # This host name.
31my @zone; # List of acceptable DNS zones.
32my $nameserver; # Nameserver to use for updates. 46my $nameserver; # Nameserver to use for updates.
33my @tsig_args; # Arguments to sing_tsig (path to the DNSSEC key file, or
34 # the key name and hash.
35my $ttl = 3600; # Default TTL.
36my $confdir; # Apache configuration directory.
37my $confpat = "*"; # A globbing pattern for Apache configuration files.
38my $dry_run; # Dry-run mode. 47my $dry_run; # Dry-run mode.
39my $debug; # Debug level. 48my $debug; # Debug level.
40my $allow_wildcard_domains;
41 49
42my $help; # Display help summary. 50my $status = EX_OK;# Default exit status.
43my $man; # Ditto in manpage format.
44
45my $status = 0; # Default exit status.
46 51
47sub err { 52sub err {
48 print STDERR "$script: "; 53 print STDERR "$progname: ";
49 print STDERR $_ for (@_); 54 print STDERR $_ for (@_);
@@ -58,21 +63,189 @@ sub abend {
58 63
59sub read_config_file($) { 64sub parse_section {
60 my $file = shift; 65 my ($conf, $input) = @_;
61 unless (-f $file) { 66 my $ref = $conf;
62 print STDERR "$script: configuration file $file does not exist\n" 67 my $quote;
63 if ($debug); 68 my $rootname;
64 return; 69 while ($input ne '') {
70 my $name;
71 if (!defined($quote)) {
72 if ($input =~ /^"(.*)/) {
73 $quote = '';
74 $input = $1;
75 } elsif ($input =~ /^(.+?)(?:\s+|")(.*)/) {
76 $name = $1;
77 $input = $2;
78 } else {
79 $name = $input;
80 $input = '';
81 }
82 } else {
83 if ($input =~ /^([^\\"]*)\\(.)(.*)/) {
84 $quote .= $1 . $2;
85 $input = $3;
86 } elsif ($input =~ /^([^\\"]*)"\s*(.*)/) {
87 $name = $quote . $1;
88 $input = $2;
89 $quote = undef;
90 } else {
91 die "unparsable input $input";
92 }
93 }
94
95 if (defined($name)) {
96 $rootname = $name unless defined $rootname;
97 $ref->{$name} = {} unless ref($ref->{$name}) eq 'HASH';
98 $ref = $ref->{$name};
99 $name = undef;
100 }
65 } 101 }
66 print STDERR "$script: reading $file\n" if ($debug); 102 return ($ref, $rootname);
67 open(my $fd, "<", $file) or abend(1, "cannot open $file: $!"); 103}
104
105sub check_mandatory {
106 my ($section, $kw, $loc, $s) = @_;
107 my $err = 0;
108 while (my ($k, $d) = each %{$kw}) {
109 if (ref($d) eq 'HASH'
110 and $d->{mandatory}
111 and !exists($section->{$k})) {
112 if (exists($d->{section})) {
113 if ($s) {
114 err("$loc: mandatory section [$k] not present");
115 ++$err;
116 }
117 } else {
118 err("$loc: mandatory variable \"$k\" not set");
119 ++$err;
120 }
121 }
122 }
123 return $err;
124}
125
126sub readconfig {
127 my $file = shift;
128 my $conf = shift;
129 my %param = @_;
130
131# debug(2, "reading $file");
132 open(my $fd, "<", $file)
133 or do {
134 err("can't open configuration file $file: $!");
135 return 1 if $param{include};
136 exit(EX_NOINPUT);
137 };
138
139 my $line;
140 my $err;
141 my $section = $conf;
142 my $kw = $param{kw};
143 my $include = 0;
144 my $rootname;
145
68 while (<$fd>) { 146 while (<$fd>) {
69 chomp; 147 ++$line;
70 s/^\s+//; 148 chomp;
71 s/\s+$//; 149 if (/\\$/) {
72 s/\s+=\s+/=/; 150 chop;
73 s/#.*//; 151 $_ .= <$fd>;
74 next if ($_ eq ""); 152 redo;
75 unshift(@ARGV, "--$_"); 153 }
154
155 s/^\s+//;
156 s/\s+$//;
157 s/#.*//;
158 next if ($_ eq "");
159
160 if (/^\[(.+?)\]$/) {
161 $include = 0;
162 my $arg = $1;
163 $arg =~ s/^\s+//;
164 $arg =~ s/\s+$//;
165 if ($arg eq 'include') {
166 $include = 1;
167 } else {
168 ($section, $rootname) = parse_section($conf, $1);
169 if (ref($param{kw}) eq 'HASH') {
170 if (defined($rootname)) {
171 if (ref($param{kw}{$rootname}) eq 'HASH'
172 and exists($param{kw}{$rootname}{section})) {
173 $kw = $param{kw}{$rootname}{section};
174 } else {
175 err("$file:$line: unknown section");
176 $kw = undef;
177 }
178 } else {
179 $kw = $param{kw};
180 }
181 }
182 }
183 } elsif (/([\w_-]+)\s*=\s*(.*)/) {
184 my ($k, $v) = ($1, $2);
185 $k = lc($k) if $param{ci};
186
187 if ($include) {
188 if ($k eq 'path') {
189 $err += readconfig($v, $conf, include => 1, @_);
190 } elsif ($k eq 'pathopt') {
191 $err += readconfig($v, $conf, include => 1, @_)
192 if -f $v;
193 } elsif ($k eq 'glob') {
194 foreach my $file (bsd_glob($v, 0)) {
195 $err += readconfig($file, $conf, include => 1, @_);
196 }
197 } else {
198 err("$file:$line: unknown keyword");
199 ++$err;
200 }
201 next;
202 }
203
204 if (defined($kw)) {
205 my $x = $kw->{$k};
206 if (!defined($x)) {
207 err("$file:$line: unknown keyword $k");
208 ++$err;
209 next;
210 } elsif (ref($x) eq 'HASH') {
211 if (exists($x->{re})) {
212 if ($v !~ /$x->{re}/) {
213 err("$file:$line: invalid value for $k");
214 ++$err;
215 next;
216 }
217 if (exists($x->{check})
218 and !&{$x->{check}}($k, $v, "$file:$line")) {
219 ++$err;
220 next;
221 }
222 } elsif (exists($x->{check})) {
223 if (!&{$x->{check}}($k, $v, "$file:$line")) {
224 ++$err;
225 next;
226 }
227 } elsif (!exists($x->{var}) and
228 !exists($x->{parser}) and
229 !exists($x->{mandatory})) {