File Coverage

blib/lib/Unix/Conf/Bind8/Conf/Acl.pm
Criterion Covered Total %
statement 15 158 9.4
branch 0 84 0.0
condition 0 28 0.0
subroutine 5 14 35.7
pod 4 6 66.6
total 24 290 8.2


line stmt bran cond sub pod time code
1             # Acl.pm
2             #
3             # Copyright Karthik Krishnamurthy
4              
5             =head1 NAME
6              
7             Unix::Conf::Bind8::Conf::Acl - Class for handling Bind8 configuration
8             directive `acl'.
9              
10             =head1 SYNOPSIS
11              
12             use Unix::Conf::Bind8;
13              
14             my ($conf, $acl, $zone, $tmpacl, $ret);
15             $conf = Unix::Conf::Bind8->new_conf (
16             FILE => '/etc/named.conf',
17             SECURE_OPEN => 1,
18             ) or $conf->die ("couldn't open `named.conf'");
19              
20             #
21             # Ways to get an acl object.
22             #
23              
24             $zone = $conf->get_zone ('extremix.net')
25             or $zone->die ("couldn't get zone `extremix.net'");
26              
27             # create a new acl to be defined before the zone directive
28             # 'extremix.net'.
29             $acl = $conf->new_acl (
30             NAME => 'extremix.com-slaves',
31             ELEMENTS => [ qw (element1 element2) ],
32             WHERE => 'BEFORE',
33             WARG => $zone,
34             ) or $acl->die ("couldn't create `extremix.com-slaves'");
35              
36             # OR
37              
38             # get an existing acl named 'extremix.com-slaves'
39             $acl = $conf->get_acl ('extremix.com-slaves')
40             or $acl->die ("couldn't get ACL `extremix.com-slaves');
41              
42             #
43             # Operations that can be performed on an Acl object.
44             #
45              
46             # create an unnamed acl
47             $tmpacl = $conf->new_acl (
48             ELEMENTS => [ 'key key1', 'localhost' ]
49             ) or $tmpacl->die ("couldn't create unnamed acl");
50              
51             # Following operations can be performed on an Acl object.
52             # NOTE: Legal Acl elements, are IP addresses, defined Acl
53             # names ('any','none','localhost','localnets') defined keys,
54             # and unnamed Acl objects
55              
56             # set the elements of the ACL. old values are deleted
57             $ret = $acl->elements (qw (10.0.0.1 10.0.0.2))
58             or $ret->die ("couldn't set elements on ACL `extremix.net-slaves'");
59              
60             # add elements
61             $ret = $acl->add_elements ('10.0.0.3', '10.0.0.4', $tmpacl)
62             or $ret->die ("couldn't add elements to ACL `extremix.net-slaves'");
63            
64             # delete elements. This will delete the acl if no elements are
65             # left and the object is a named acl.
66             $ret = $acl->delete_elements (qw (10.0.0.5 10.0.0.6))
67             or $ret->die ("couldn't delete elements from ACL `extremix.net-slaves'")
68              
69             # delete an existing acl named 'extremix.com-slaves'
70             $ret = $acl->delete ()
71             or $ret->die ('couldn't delete ACL `extremix.com-slaves');
72              
73             # OR
74              
75             $ret = $conf->delete_acl ('extremix.com-slaves')
76             or $ret->die ("couldn't delete ACL `extremix.com-slaves');
77              
78             =head1 METHODS
79              
80             =cut
81              
82             package Unix::Conf::Bind8::Conf::Acl;
83              
84 10     10   53 use strict;
  10         20  
  10         319  
85 10     10   49 use warnings;
  10         20  
  10         233  
86              
87 10     10   48 use Unix::Conf;
  10         13  
  10         242  
88 10     10   73 use Unix::Conf::Bind8::Conf::Directive;
  10         17  
  10         414  
89             our @ISA = qw (Unix::Conf::Bind8::Conf::Directive);
90              
91 10     10   49 use Unix::Conf::Bind8::Conf::Lib;
  10         19  
  10         28553  
92              
93             =over 4
94              
95             =item new ()
96              
97             Arguments
98             NAME => 'ACL-NAME',
99             ELEMENTS => [ qw (element1 element2) ],
100             WHERE => 'FIRST'|'LAST'|'BEFORE'|'AFTER'
101             WARG => Unix::Conf::Bind8::Conf::Directive subclass object
102             # WARG is to be provided only in case WHERE eq 'BEFORE
103             # or WHERE eq 'AFTER'
104             PARENT => reference, # to the Conf object datastructure.
105              
106             Class constructor.
107             Creates a new Unix::Conf::Bind8::Conf::Acl object and returns it if successful,
108             an Err object otherwise.
109             Direct use of this method is deprecated. Use Unix::Conf::Bind8::Conf::new_acl ()
110             instead.
111              
112             =cut
113             sub new
114             {
115 0     0 1   my $class = shift ();
116 0           my $new = bless ({});
117 0           my %args = @_;
118 0           my $ret;
119              
120 0 0         $args{PARENT} || return (Unix::Conf->_err ("new", "PARENT not defined"));
121 0 0         $ret = $new->_parent ($args{PARENT}) or return ($ret);
122 0 0         if ($args{NAME}) {
123 0 0         $ret = $new->name ($args{NAME}) or return ($ret);
124 0 0         $args{WHERE} = 'LAST' unless ($args{WHERE});
125 0 0         $ret = Unix::Conf::Bind8::Conf::_insert_in_list ($new, $args{WHERE}, $args{WARG})
126             or return ($ret);
127             }
128 0 0 0       $ret = $new->elements ($args{ELEMENTS} || []) or return ($ret);
129 0           return ($new);
130             }
131              
132             =item name ()
133              
134             Arguments
135             'ACL-NAME' # optional
136              
137             Object method.
138             Get/set the object's name attribute. If an argument is passed, the method tries
139             to set the name attribute to 'ACL-NAME' and returns true if successful, an
140             Err object otherwise. If no argument passed, it returns the name.
141              
142             =cut
143              
144             sub name
145             {
146 0     0 1   my ($self, $name) = @_;
147              
148 0 0         if (defined ($name)) {
149 0           my $ret;
150              
151 0           __valid_string ($name);
152             # already defined. changing name
153 0 0         if ($self->{name}) {
154 0 0         $ret = Unix::Conf::Bind8::Conf::_del_acl ($self) or return ($ret);
155             }
156 0           $self->{name} = $name;
157 0 0         $ret = Unix::Conf::Bind8::Conf::_add_acl ($self) or return ($ret);
158 0           $self->dirty (1);
159 0           return (1);
160             }
161 0           return ($self->{name});
162             }
163              
164             =item elements ()
165              
166             Arguments
167             LIST OF ELEMENTS
168             or
169             [ LIST OF ELEMENTS ]
170              
171             Object method.
172             Get/set the object's elements attribute. If argument(s) is passed
173             the method tries to set the elements attribute. It returns true on
174             success, an Err object otherwise. If no argument is passed,
175             returns an array reference consisting of the elements of the object
176             (including Acl objects contained therein), if defined, an Err object
177             otherwise.
178              
179             =cut
180              
181             sub __add_elements ($$);
182              
183             sub elements
184             {
185 0     0 1   my $self = shift ();
186 0           my $elements;
187 0           my (@obj, @ele);
188              
189 0 0         if (@_) {
190 0           my $ret;
191 0 0 0       if (ref ($_[0]) && !UNIVERSAL::isa ($_[0], 'Unix::Conf::Bind8::Conf::Acl')) {
192 0 0         return (Unix::Conf->_err ("elements", "expected arguments are a list or an array ref"))
193             unless (UNIVERSAL::isa ($_[0], 'ARRAY'));
194 0           $elements = $_[0];
195             }
196             else {
197             # got a list
198 0           $elements = [ @_ ];
199             }
200 0           for (@$elements) {
201 0 0         if (ref ($_)) {
202 0           push (@obj, $_);
203             }
204             else {
205             # (\S.+) because there could be whitespace as in
206             # ' !key sample-key '. We want $2 to match
207             # 'key sample-key', which will be converted to
208             # 'key sample-key' in the next s//.
209 0           s/^\s*(!?)\s*(\S.+?)\s*$/$1$2/;
210 0           s/^(!?)key\s+(\S+)\s*$/$1key $2/;
211 0           push (@ele, $_);
212             }
213 0 0         return ($ret) unless ($ret = __valid_element ($self->_parent (), $_));
214             # if element is an Acl object, set its aclparent attribute to
215             # us so that if and when all its elements are deleted, it can
216             # delete itself by invoking its parent's delete_elements method.
217 0 0 0       $_->{aclparent} = $self
218             if (ref ($_) && UNIVERSAL::isa ($_, 'Unix::Conf::Bind8::Conf::Acl'));
219             }
220             # reinit values
221 0           $self->{allelements} = {};
222 0           $self->{elements} = {};
223 0           $self->{objects} = {};
224 0           __add_elements ($self, $elements);
225             # set elements defined for this acl to 'elements'. weed out
226             # acl objects. they are attached to 'objects'.
227 0           @{$self->{elements}}{@ele} = 1 x @ele;
  0            
228             # remember the reference will be stringified as the key. cannot
229             # use. that need to use the values. that is why values not set to 1
230 0           @{$self->{objects}}{@obj} = (@obj);
  0            
231 0           $self->dirty (1);
232 0           return (1);
233             }
234             return (
235 0 0         defined ($self->{elements}) ? [ keys (%{$self->{allelements}}) ] :
  0            
236             Unix::Conf->_err ('elements', "elements not set for this acl")
237             );
238             }
239              
240             # helper routine for elements and add_elements
241             # if the element is an Acl object, recursively call
242             # ourself.
243             # 'allelements' key of an Acl object will contain all elements an Acl, including
244             # those of embedded elements. 'objects', will contain stringified references of the
245             # objects, including those contained inside the argument. The value is the same
246             # as the key for 'objects'.
247             sub __add_elements ($$)
248             {
249 0     0     my ($self, $elements) = @_;
250              
251 0           for (@$elements) {
252 0 0 0       if (ref ($_) && UNIVERSAL::isa ($_, 'Unix::Conf::Bind8::Conf::Acl')) {
253             # accessing the embedded object's internals directly.
254 0           @{$self->{allelements}}{keys (%{$_->{allelements}})} = values (%{$_->{allelements}});
  0            
  0            
  0            
255             # now overwrite those values which are contained directly in $_ with the reference $_
256 0           my @tmp = keys (%{$_->{elements}});
  0            
257 0           @{$self->{allelements}}{@tmp} = ($_) x @tmp;
  0            
258             }
259             else {
260 0           $self->{allelements}{$_} = 1;
261             }
262             }
263             }
264              
265             =item add_elements ()
266              
267             Arguments
268             LIST OF ELEMENTS
269             or
270             [ LIST OF ELEMENTS ]
271              
272             Object method.
273             Adds the argument to the elements of the invocant object. Returns true
274             on success, an Err object otherwise.
275              
276             =cut
277              
278             sub add_elements
279             {
280 0     0 1   my $self = shift ();
281 0           my $elements;
282 0           my (@obj, @ele);
283              
284 0 0         if (@_) {
285 0           my $ret;
286              
287 0 0 0       if (ref ($_[0]) && !UNIVERSAL::isa ($_[0], 'Unix::Conf::Bind8::Conf::Acl')) {
288 0 0         return (Unix::Conf->_err ("add_elements", "expected arguments are a list or an array ref"))
289             unless (UNIVERSAL::isa ($_[0], 'ARRAY'));
290 0           $elements = $_[0];
291             }
292             else {
293             # got a list
294 0           $elements = [ @_ ];
295             }
296 0           for (@$elements) {
297 0 0         if (ref ($_)) {
298 0 0         return (Unix::Conf->_err ('add_elements', "object `$_' already defined"))
299             if ($self->{objects}{$_});
300 0           push (@obj, $_);
301             }
302             else {
303             # (\S.+) because there could be whitespace as in
304             # ' !key sample-key '. We want $2 to match
305             # 'key sample-key', which will be converted to
306             # 'key sample-key' in the next s//.
307 0           s/^\s*(!?)\s*(\S.+?)\s*$/$1$2/;
308 0           s/^(!?)key\s+(\S+)\s*$/$1key $2/;
309 0 0         return (Unix::Conf->_err ('add_elements', "element `$_' already defined"))
310             if ($self->{allelements}{$_});
311 0           push (@ele, $_);
312             }
313 0 0         return ($ret) unless ($ret = __valid_element ($self->_parent (), $_));
314             # if element is an Acl object, set its aclparent attribute to
315             # us so that if and when all its elements are deleted, it can
316             # delete itself by invoking its parent's delete_elements method.
317 0 0 0       $_->{aclparent} = $self
318             if (ref ($_) && UNIVERSAL::isa ($_, 'Unix::Conf::Bind8::Conf::Acl'));
319             }
320 0           __add_elements ($self, $elements);
321             # set elements defined for this acl to 'elements'. weed out
322             # acl objects. they are attached to 'objects'.
323 0           @{$self->{elements}}{@ele} = 1 x @ele;
  0            
324             # remember the reference will be stringified as the key. cannot
325             # use. that need to use the values. that is why values not set to 1
326 0           @{$self->{objects}}{@obj} = (@obj);
  0            
327 0           $self->dirty (1);
328 0           return (1);
329             }
330 0           return (Unix::Conf->_err ('add_element', "elements to be added not specified"));
331             }
332              
333             =cut delete_elements ()
334              
335             Arguments
336             LIST OF ELEMENTS
337             or
338             [ LIST OF ELEMENTS ]
339              
340             Object method.
341             Deletes the argument from the elements of the invocant object and returns
342             true on success, an Err object otherwise.
343              
344             =cut
345              
346             sub delete_elements
347             {
348 0     0 0   my $self = shift ();
349 0           my ($elements, $ret);
350              
351 0 0         return (Unix::Conf->_err ('delete_elements', "elements to be deleted not specified"))
352             unless (@_);
353              
354 0 0 0       if (ref ($_[0]) && !UNIVERSAL::isa ($_[0], 'Unix::Conf::Bind8::Conf::Acl')) {
355 0 0         return (Unix::Conf->_err ("delete_elements", "expected arguments are a list or an array ref"))
356             unless (UNIVERSAL::isa ($_[0], 'ARRAY'));
357 0           $elements = $_[0];
358             }
359             else {
360             # got a list
361 0           $elements = [ @_ ];
362             }
363 0           for (@$elements) {
364 0 0         if (ref ($_)) {
365 0 0         return (Unix::Conf->_err ('delete_elements', "object `$_' not defined"))
366             unless ($self->{objects}{$_});
367 0           next;
368             }
369 0           s/^\s*(!?)\s*(\S.+?)\s*$/$1$2/;
370 0           s/^(!?)key\s+(\S+)\s*$/$1key $2/;
371 0 0         return (Unix::Conf->_err ('delete_elements', "element `$_' not defined"))
372             unless ($self->{allelements}{$_});
373             }
374 0           my $obj;
375             # lookup the allelements map to see if any of the elements to
376             # be deleted is contained in an embedded object. if so delete
377             # from that object.
378 0           for (@$elements) {
379             # if the element is an Acl object delete elements contained
380             # in it and embedded objects from our hash keyed on 'allelements'.
381             # also delete object keyed in 'objects'
382 0 0         if (ref($_)) {
383 0           my @tmp = keys (%{$self->{objects}{$_}{allelements}});
  0            
384 0           delete (@{$self->{allelements}}{@tmp});
  0            
385 0           delete ($self->{objects}{$_});
386             }
387             else {
388             # if the element has a value of Acl object, it is in
389             # the contained Acl object.
390 0 0         $obj->delete_elements ($_)
391             if (ref ($obj = $self->{allelements}{$_}));
392 0           delete ($self->{allelements}{$_});
393 0           delete ($self->{elements}{$_});
394             }
395             }
396             # if we are an embedded object and empty delete ourself from
397             # our parent.
398 0           $ret = $self->{aclparent}->delete_elements ($self) or return ($ret)
399 0 0 0       if ($self->{aclparent} && (keys (%{$self->{allelements}}) == 0));
      0        
400              
401             # delete the acl object if it is empty only if a named one
402 0           $self->delete ()
403 0 0 0       if (!keys (%{$self->{allelements}}) && $self->name ());
404              
405 0           $self->dirty (1);
406 0           return (1);
407             }
408              
409             sub defined
410             {
411 0     0 0   my ($self, $element) = @_;
412              
413 0 0         return (1) if ($self->{allelements}{$element});
414 0 0         return (1) if ($self->{objects}{$element});
415 0           return (0);
416             }
417              
418             my ($Name, $TabLevel);
419              
420             sub ___render ($);
421             # helper routine for __render. arguments and calling
422             # format same as __render
423             sub ___render ($)
424             {
425 0     0     my $string;
426 0           $TabLevel++;
427 0           $string .= ("\t" x $TabLevel) . "$_;\n" for (keys (%{$_[0]->{elements}}));
  0            
428 0           $string .= ("\t" x $TabLevel) . "{\n" . ___render ($_) . "\n" for (values (%{$_[0]->{objects}}));
  0            
429              
430 0 0         $string .= "\t" x ($TabLevel - 1) unless ($TabLevel);
431 0           $TabLevel--;
432 0           return ($string . "\t" x $TabLevel . "};");
433             }
434              
435             # Instance method
436             # Arguments: NONE
437             sub __render
438             {
439 0     0     my $self = shift ();
440 0           my ($name, $rendered);
441            
442 0 0         $rendered = "acl $Name "
443             if ($Name = $self->name ());
444 0           $rendered .= "{\n";
445 0           $TabLevel = shift ();
446 0 0         $TabLevel = 0 unless (defined ($TabLevel));
447 0           $rendered .= ___render ($self);
448 0           return ($self->_rstring (\$rendered));
449             }
450              
451             1;
452             __END__