File Coverage

blib/lib/BIND/SDB/LDAP/Helper.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package BIND::SDB::LDAP::Helper;
2              
3 1     1   20676 use warnings;
  1         2  
  1         30  
4 1     1   5 use strict;
  1         1  
  1         27  
5 1     1   352 use Config::IniHash;
  0            
  0            
6             use File::BaseDir qw/xdg_config_home/;
7             use Net::LDAP;
8             use Net::LDAP::Entry;
9             use Net::LDAP::AutoDNs;
10              
11             =head1 NAME
12              
13             BIND::SDB::LDAP::Helper - Manages DNS zones stored in LDAP for the BIND9 SDB LDAP patch
14              
15             =head1 VERSION
16              
17             Version 0.0.0
18              
19             =cut
20              
21             our $VERSION = '0.0.0';
22              
23             =head1 SYNOPSIS
24              
25             use BIND::SDB::LDAP::Helper;
26              
27             my $sdbhelper = BIND::SDB::LDAP::Helper->new();
28             ...
29              
30             =head1 METHODS
31              
32             =head2 new
33              
34             This initializes this module.
35              
36             One arguement is accepted and it is a arguement hash.
37              
38             =head3 args hash
39              
40             =head4 configfile
41              
42             This is the config file to read upon start.
43              
44             =head4 confighash
45              
46             This should be a hash ref similar to the type returned by Config::IniHash.
47              
48             This will take presedence over 'configfile'.
49              
50             my $pldm=BIND::SDB::LDAP::Helper->new;
51             if($pldnsm->{error}){
52             print "Error!\n";
53             }
54              
55             =cut
56              
57             sub new{
58             my %args;
59             if(defined($_[1])){
60             %args= %{$_[1]};
61             };
62             my $function='new';
63            
64             my $self = {error=>undef,
65             errorString=>"",
66             perror=>undef,
67             module=>'BIND-SDB-LDAP-Helper',
68             };
69             bless $self;
70              
71             if (!defined($args{configfile})) {
72             $self->{configfile}=xdg_config_home().'/pldnsmrc';
73             }else {
74             $self->{configfile}=$args{configfile};
75             }
76              
77             #check this first
78             if (defined($args{confighash})) {
79             my $returned=$self->configCheck($args{confighash});
80             if (!$returned) {
81             $self->{error}=2;
82             $self->{perror}=1;
83             $self->{errorString}='Missing either "bind" or "pass" values in the config.';
84             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
85             return $self;
86             }
87             $self->{ini}=$args{confighash};
88             }
89              
90             #if a config has not been set yet, read the config
91             if (!defined($self->{ini})) {
92             $self->readConfig();
93             if ($self->{error}) {
94             $self->{perror}=1;
95             warn($self->{module}.' '.$function.': readConfig errored');
96             }
97             }
98              
99             return $self;
100             }
101              
102             =head2 addRecords
103              
104             This adds records to a relative domain name.
105              
106             One arguement is taken and it is a hash.
107              
108             =head3 args hash
109              
110             =head4 relative
111              
112             This is a relative domain name.
113              
114             This is a required key.
115              
116             =head4 zone
117              
118             This is the zone to add it to.
119              
120             This is a required key.
121              
122             =head4 ttl
123              
124             This is the TTL to use. If a old one is set, it will be removed.
125              
126             =head4 a
127              
128             This is a array containing entries for A records.
129              
130             =head4 aaaa
131              
132             This is a array containing entries for AAAA records.
133              
134             =head4 cname
135              
136             This is a array containing entries for CNAME records.
137              
138             =head4 mx
139              
140             This is a array containing entries for MX records.
141              
142             =head4 ptr
143              
144             This is a array containing entries for PTR records.
145              
146             =head4 txt
147              
148             This is a array containing entries for TXT records.
149              
150             $pldm->addRecords({
151             zone=>$opts{z},
152             relative=>$opts{r},
153             ttl=>$opts{T},
154             a=>\@a,
155             aaaa=>\@aaaa,
156             mx=>\@mx,
157             ptr=>\@ptr,
158             txt=>\@txt,
159             });
160             if ($pldm->{error}) {
161             exit $pldm->{error};
162             }
163              
164             =cut
165              
166             sub addRecords{
167             my $self=$_[0];
168             my %args;
169             if(defined($_[1])){
170             %args= %{$_[1]};
171             };
172             my $function='addRecords';
173              
174             #blanks any previous errors
175             $self->errorblank;
176             if ($self->{error}) {
177             warn($self->{module}.' '.$function.': A permanent error is set');
178             return undef;
179             }
180              
181             #makes sure all the required are specified
182             if ( (!defined($args{relative})) || (!defined($args{zone})) ) {
183             $self->{error}=1;
184             $self->{errorString}='Either relative or zone is not defined';
185             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
186             return undef;
187             }
188              
189             #make sure the zone exists
190             my $returned=$self->relativeExists($args{relative}, $args{zone});
191             if ($self->{error}) {
192             warn($self->{module}.' '.$function.': relativeExists errored');
193             return undef;
194             }
195             if (!$returned) {
196             $self->{error}=6;
197             $self->{errorString}='The relative "'.$args{relative}.'" does not exist for the zone "'.$args{zone }.'"';
198             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
199             return undef;
200             }
201              
202             #connect
203             my $ldap=$self->connect;
204             if ($self->{error}) {
205             warn($self->{module}.' '.$function.': connect errored');
206             return undef;
207             }
208              
209             #builds the zoneDC
210             my $zoneDN=$args{zone};
211             $zoneDN=~s/\./\,dc=/g;
212             $zoneDN='dc='.$zoneDN.','.$self->{ini}->{''}->{base};
213              
214             #search and get the first entry
215             my $mesg=$ldap->search(
216             base=>$zoneDN,
217             scope=>'one',
218             filter=>'(&(relativeDomainName='.$args{relative}.') (&(zoneName='.$args{zone}.') (objectClass=dNSZone)))'
219             );
220             my $entry=$mesg->pop_entry;
221              
222             #adds any A records if needed
223             if (defined($args{a}[0])) {
224             $entry->add(
225             aRecord=>$args{a}
226             );
227             }
228              
229             #add a new TTL
230             if (defined($args{ttl})) {
231             $entry->delete('dNSTTL');
232             $entry->add(
233             dNSTTL=>$args{ttl}
234             );
235             }
236              
237             #adds any AAAA records if needed
238             if (defined($args{aaaa}[0])) {
239             $entry->add(
240             aAAARecord=>$args{aaaa}
241             );
242             }
243              
244             #adds any CNAME records if needed
245             if (defined($args{cname}[0])) {
246             $entry->add(
247             cNAMERecord=>$args{cname}
248             );
249             }
250              
251             #adds any MX records if needed
252             if (defined($args{mx}[0])) {
253             $entry->add(
254             MXRecord=>$args{mx}
255             );
256             }
257              
258             #adds any PTR records if needed
259             if (defined($args{ptr}[0])) {
260             $entry->add(
261             PTRRecord=>$args{ptr}
262             );
263             }
264              
265             #adds any PTR records if needed
266             if (defined($args{txt}[0])) {
267             $entry->add(
268             TXTRecord=>$args{txt}
269             );
270             }
271              
272             #mod it
273             $mesg=$entry->update($ldap);
274             if ($mesg->is_error) {
275             $self->{error}=7;
276             $self->{errorString}='Modifying the entry,"'.$entry->dn.'", failed';
277             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
278             return undef;
279             }
280              
281              
282             return 1;
283             }
284              
285             =head2 addRelative
286              
287             This adds a new relative domain name to a zone.
288              
289             One arguement is taken and it is a hash.
290              
291             =head3 args hash
292              
293             =head4 relative
294              
295             This is a relative domain name.
296              
297             This is a required key.
298              
299             =head4 zone
300              
301             This is the zone to add it to.
302              
303             This is a required key.
304              
305             =head4 ttl
306              
307             This is the TTL to use.
308              
309             =head4 a
310              
311             This is a array containing entries for A records.
312              
313             =head4 aaaa
314              
315             This is a array containing entries for AAAA records.
316              
317             =head4 cname
318              
319             This is a array containing entries for CNAME records.
320              
321             =head4 mx
322              
323             This is a array containing entries for MX records.
324              
325             =head4 ptr
326              
327             This is a array containing entries for PTR records.
328              
329             =head4 txt
330              
331             This is a array containing entries for TXT records.
332              
333             =head2
334              
335             $dlhm->addRelative({
336             zone=>'some.zone',
337             relative=>'someRelative',
338             aRecord=>['192.168.15.2'],
339             });
340              
341             =cut
342              
343             sub addRelative{
344             my $self=$_[0];
345             my %args;
346             if(defined($_[1])){
347             %args= %{$_[1]};
348             };
349             my $function='addRelative';
350              
351             #blanks any previous errors
352             $self->errorblank;
353             if ($self->{error}) {
354             warn($self->{module}.' '.$function.': A permanent error is set');
355             return undef;
356             }
357              
358             #makes sure all the required are specified
359             if ( (!defined($args{relative})) || (!defined($args{zone})) ) {
360             $self->{error}=1;
361             $self->{errorString}='Either relative or zone is not defined';
362             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
363             return undef;
364             }
365              
366             #make sure the zone exists
367             my $returned=$self->relativeExists($args{relative}, $args{zone});
368             if ($self->{error}) {
369             warn($self->{module}.' '.$function.': re;ato errored');
370             return undef;
371             }
372             if ($returned) {
373             $self->{error}=10;
374             $self->{errorString}='The relative "'.$args{relative}.'" already exists for the zone "'.$args{zone}.'"';
375             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
376             return undef;
377             }
378              
379             #make sure it is not a @
380             if ($args{relative} eq '@') {
381             $self->{error}=8;
382             $self->{errorString}='"@" is reserved for zone zone record and can not be use as a relative name';
383             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
384             return undef;
385             }
386              
387             #make sure it is not a .
388             if ($args{relative}=~/\./) {
389             $self->{error}=9;
390             $self->{errorString}='"." was found in the relative name and this places it outside of this zone';
391             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
392             return undef;
393             }
394              
395             my $entry=Net::LDAP::Entry->new;
396              
397             my $zoneDN=$args{zone};
398             $zoneDN=~s/\./\,dc=/g;
399             $zoneDN='dc='.$zoneDN.','.$self->{ini}->{''}->{base};
400              
401             $entry->dn('relativeDomainName='.$args{relative}.','.$zoneDN);
402             $entry->add(
403             objectClass=>['top', 'dNSZone'],
404             relativeDomainName=>$args{relative},
405             zoneName=>$args{zone},
406             dNSClass=>'IN',
407             );
408              
409             #add a ttl if needed
410             if (defined($args{ttl})) {
411             $entry->add(
412             dNSTTL=>$args{ttl}
413             );
414             }
415              
416             #adds any A records if needed
417             if (defined($args{a}[0])) {
418             $entry->add(
419             aRecord=>$args{a}
420             );
421             }
422              
423             #adds any AAAA records if needed
424             if (defined($args{aaaa}[0])) {
425             $entry->add(
426             aAAARecord=>$args{aaaa}
427             );
428             }
429              
430             #adds any CNAME records if needed
431             if (defined($args{cname}[0])) {
432             $entry->add(
433             cNAMERecord=>$args{cname}
434             );
435             }
436              
437             #adds any MX records if needed
438             if (defined($args{mx}[0])) {
439             $entry->add(
440             MXRecord=>$args{mx}
441             );
442             }
443              
444             #adds any PTR records if needed
445             if (defined($args{ptr}[0])) {
446             $entry->add(
447             PTRRecord=>$args{ptr}
448             );
449             }
450              
451             #adds any TXT records if needed
452             if (defined($args{txt}[0])) {
453             $entry->add(
454             TXTRecord=>$args{txt}
455             );
456             }
457              
458             #connect
459             my $ldap=$self->connect;
460             if ($self->{error}) {
461             warn($self->{module}.' '.$function.': connect errored');
462             return undef;
463             }
464              
465             #add it
466             my $mesg=$entry->update($ldap);
467             if ($mesg->is_error) {
468             $self->{error}=7;
469             $self->{errorString}='Adding the new entry failed';
470             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
471             return undef;
472             }
473              
474             return 1;
475             }
476              
477             =head2 addZone
478              
479             This creazes a new zone.
480              
481             One argument is required and it is a hash.
482              
483             The required values are as listed below.
484              
485             zone
486             email
487             ns
488              
489             The default or config specified value will be used for
490             any of the others.
491              
492             =head3 args hash
493              
494             =head4 zone
495              
496             This is the zone name.
497              
498             =head4 email
499              
500             This is the email address for the SOA.
501              
502             =head4 ns
503              
504             This is a array containing what
505              
506             =head4 ttl
507              
508             This is the ttl for the SOA.
509              
510             =head4 refresh
511              
512             This is the refresh value for the SOA.
513              
514             =head4 retry
515              
516             This is the retry value for the SOA.
517              
518             =head4 expire
519              
520             This is the expire value for the SOA.
521              
522             =head4 minimum
523              
524             This is the minimum value for the SOA.
525              
526             $pdlm->addZoneDC({
527             zone=>'some.zone',
528             email=>'bob@foo.bar',
529             ns=>['ns1.some.zone.', 'ns2.fu.bar.'],
530             });
531             if($pdlm->{error}){
532             print "Error!\n";
533             }
534              
535              
536             =cut
537              
538             sub addZone{
539             my $self=$_[0];
540             my %args;
541             if(defined($_[1])){
542             %args= %{$_[1]};
543             };
544             my $function='addZone';
545              
546             #blanks any previous errors
547             $self->errorblank;
548             if ($self->{error}) {
549             warn($self->{module}.' '.$function.': A permanent error is set');
550             return undef;
551             }
552              
553             #make sure we have all the required values
554             my @required=('ns', 'email', 'zone');
555             my $int=0;
556             while (defined($required[$int])) {
557             if (!defined($args{$required[$int]})) {
558             $self->{error}=1;
559             $self->{errorString}='The value "'.$required[$int].'" missing from the arg hash';
560             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
561             return undef;
562             }
563              
564             $int++;
565             }
566              
567             #get defaults if required
568             if (!defined($args{ttl})) {
569             $args{ttl}=$self->{ini}->{''}->{ttl};
570             }
571             if (!defined($args{refresh})) {
572             $args{refresh}=$self->{ini}->{''}->{refresh};
573             }
574             if (!defined($args{retry})) {
575             $args{retry}=$self->{ini}->{''}->{retry};
576             }
577             if (!defined($args{expire})) {
578             $args{expire}=$self->{ini}->{''}->{expire};
579             }
580             if (!defined($args{minimum})) {
581             $args{minimum}=$self->{ini}->{''}->{minimum};
582             }
583              
584             #make sure the zone does not already exist
585             my $returned=$self->zoneExists($args{zone});
586             if ($self->{error}) {
587             warn($self->{module}.' '.$function.': The zone "'.$args{zone}.'" already exists');
588             return undef;
589             }
590             if ($returned) {
591             $self->{error}=9;
592             $self->{errorString}='The zone "'.$args{zone}.'" is already setup';
593             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
594             return undef;
595             }
596              
597             #checks if the DC structure exists
598             $returned=$self->zoneDCexists($args{zone});
599             if ($self->{error}) {
600             warn($self->{module}.' '.$function.': The zone "'.$args{zone}.'" already exists');
601             return undef;
602             }
603             if (!$returned) {
604             $self->addZoneDC($args{zone});
605             if ($self->{error}) {
606             warn($self->{module}.' '.$function.': addZoneDC errored');
607             return undef;
608             }
609             }
610              
611             #builds the zoneDC
612             my $zoneDN=$args{zone};
613             $zoneDN=~s/\./\,dc=/g;
614             $zoneDN='dc='.$zoneDN.','.$self->{ini}->{''}->{base};
615              
616             #build the entry
617             my $entry=Net::LDAP::Entry->new;
618             $entry->dn('relativeDomainName=@,'.$zoneDN);
619             $entry->add(
620             objectClass=>['dNSZone', 'top'],
621             relativeDomainName=>'@',
622             zoneName=>$args{zone},
623             nSRecord=>$args{ns},
624             sOARecord=>$args{ns}->[0].' '.$args{email}.' '.'0000000000'.' '.$args{refresh}.
625             ' '.$args{retry}.' '.$args{expire}.' '.$args{minimum},
626             );
627              
628              
629             #connect
630             my $ldap=$self->connect;
631             if ($self->{error}) {
632             warn($self->{module}.' '.$function.': connect errored');
633             return undef;
634             }
635              
636             #add it
637             my $mesg=$entry->update($ldap);
638             if ($mesg->is_error) {
639             $self->{error}=7;
640             $self->{errorString}='Adding the new entry failed';
641             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
642             return undef;
643             } #connect
644              
645             return 1;
646             }
647              
648             =head2 addZoneDC
649              
650             This adds the new DC structure for a zone.
651              
652             $pdlm->addZoneDC('some.zone');
653             if($pdlm->{error}){
654             print "Error!\n";
655             }
656              
657             =cut
658              
659             sub addZoneDC{
660             my $self=$_[0];
661             my $zone=$_[1];
662             my $function='addZoneDC';
663              
664             #blanks any previous errors
665             $self->errorblank;
666             if ($self->{error}) {
667             warn($self->{module}.' '.$function.': A permanent error is set');
668             return undef;
669             }
670              
671             #make sure we have all the required values
672             my $int=0;
673             if (!defined($zone)) {
674             $self->{error}=1;
675             $self->{errorString}='No zone specified';
676             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
677             return undef;
678            
679             $int++;
680             }
681              
682             #checks if the DC structure exists
683             my $returned=$self->zoneDCexists($zone);
684             if ($self->{error}) {
685             warn($self->{module}.' '.$function.': The zone "'.$zone.'" already exists');
686             return undef;
687             }
688             if ($returned) {
689             $self->{error}=9;
690             $self->{errorString}='The zone "'.$zone.'" is already setup';
691             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
692             return undef;
693             }
694              
695             #builds the zoneDC
696             my $zoneDN=$zone;
697             $zoneDN=~s/\./\,dc=/g;
698             $zoneDN='dc='.$zoneDN.','.$self->{ini}->{''}->{base};
699              
700             #gets the value for the dc
701             my @dcA=split(/\./, $zone);
702              
703             #build the entry
704             my $entry=Net::LDAP::Entry->new;
705             $entry->dn($zoneDN);
706             $entry->add(
707             objectClass=>['top', 'dcObject', 'organization'],
708             dc=>$dcA[0],
709             o=>$dcA[0],
710             );
711              
712             $entry->dump;
713              
714             #connect
715             my $ldap=$self->connect;
716             if ($self->{error}) {
717             warn($self->{module}.' '.$function.': connect errored');
718             return undef;
719             }
720              
721             #add it
722             my $mesg=$entry->update($ldap);
723             if ($mesg->is_error) {
724             $self->{error}=7;
725             $self->{errorString}='Adding the new entry failed';
726             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
727             return undef;
728             } #connect
729              
730             return 1;
731             }
732              
733             =head2 configCheck
734              
735             This checks if a config hash ref if valid or not.
736              
737             my $config={""=>{
738             bind=>'cn=admin,dc=whatever',
739             pass=>'fubar',
740             }
741             };
742             my $returned$pldm->setConfig($config);
743             if($pldm->{error}){
744             print "Error!\n";
745             }
746             if(!$returned){
747             print "It is missing a required value.\n";
748             }
749              
750             =cut
751              
752             sub configCheck{
753             my $self=$_[0];
754             my $ini=$_[1];
755             my $function='configCheck';
756              
757             $self->errorblank;
758             if ($self->{error}) {
759             warn($self->{module}.' '.$function.': A permanent error is set');
760             return undef;
761             }
762              
763             if (!defined($ini)) {
764             $self->{error}=1;
765             $self->{errorString}='No value passed to check';
766             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
767             return undef;
768             }
769              
770             #puts together a array to check for the required ones
771             my @required;
772             push(@required, 'bind');
773             push(@required, 'pass');
774              
775             #make sure they are all defined
776             my $int=0;
777             while (defined($required[$int])) {
778             #error if it is not defined
779             if (!defined($ini->{''}->{$required[$int]})) {
780             return undef;
781             }
782            
783             $int++;
784             }
785              
786             #define basics if not specified
787             if (!defined($ini->{''}->{server})) {
788             $ini->{''}->{server}='127.0.0.1';
789             }
790             if (!defined($ini->{''}->{port})) {
791             $ini->{''}->{port}='389';
792             }
793             if (!defined($ini->{''}->{TLSverify})) {
794             $ini->{''}->{TLSverify}='none';
795             }
796             if (!defined($ini->{''}->{SSLversion})) {
797             $ini->{''}->{SSLversion}='tlsv1';
798             }
799             if (!defined($ini->{''}->{SSLciphers})) {
800             $ini->{''}->{SSLciphers}='ALL';
801             }
802             if (!defined($ini->{''}->{base})) {
803             my $AutoDNs=Net::LDAP::AutoDNs->new;
804             $ini->{''}->{base}=$AutoDNs->{dns};
805             }
806             if (!defined($ini->{''}->{ttl})) {
807             $ini->{''}->{ttl}='86400';
808             }
809             if (!defined($ini->{''}->{refresh})) {
810             $ini->{''}->{refresh}='360';
811             }
812             if (!defined($ini->{''}->{retry})) {
813             $ini->{''}->{retry}='360';
814             }
815             if (!defined($ini->{''}->{expire})) {
816             $ini->{''}->{expire}='7200';
817             }
818             if (!defined($ini->{''}->{minimum})) {
819             $ini->{''}->{minimum}='1200';
820             }
821              
822             return 1;
823             }
824              
825             =head2 connect
826              
827             This forms a LDAP connection using the information in
828             config file.
829              
830             my $ldap=$pldm->connect;
831             if($pt->{error}){
832             print "Error!\n";
833             }
834              
835             =cut
836              
837             sub connect{
838             my $self=$_[0];
839             my $function='connect';
840              
841             #blanks any previous errors
842             $self->errorblank;
843             if ($self->{error}) {
844             warn($self->{module}.' '.$function.': A permanent error is set');
845             return undef;
846             }
847              
848             #try to connect
849             my $ldap = Net::LDAP->new($self->{ini}->{''}->{server}, port=>$self->{ini}->{''}->{port});
850              
851             #check if it connected or not
852             if (!$ldap) {
853             $self->{error}=3;
854             $self->{errorString}='Failed to connect to LDAP';
855             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
856             return undef;
857             }
858              
859             #start TLS if it is needed
860             my $mesg;
861             if ($self->{ini}->{''}->{starttls}) {
862             $mesg=$ldap->start_tls(
863             verify=>$self->{ini}->{''}->{TLSverify},
864             sslversion=>$self->{ini}->{''}->{SSLversion},
865             ciphers=>$self->{ini}->{''}->{SSLciphers},
866             );
867              
868             if ($mesg->is_error) {
869             $self->{error}=4;
870             $self->{errorString}='$ldap->start_tls failed. $mesg->{errorMessage}="'.
871             $mesg->{errorMessage}.'"';
872             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
873             return undef;
874             }
875             }
876            
877             #bind
878             $mesg=$ldap->bind($self->{ini}->{''}->{bind},
879             password=>$self->{ini}->{''}->{pass},
880             );
881             if ($mesg->is_error) {
882             $self->{error}=5;
883             $self->{errorString}='Binding to the LDAP server failed. $mesg->{errorMessage}="'.
884             $mesg->{errorMessage}.'"';
885             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
886             return undef;
887             }
888              
889             return $ldap;
890             }
891              
892             =head2 getRelativeInfo
893              
894             This gets the records for a specified relative.
895              
896             Two arguements are required. The first is a relative domain name
897             and the second is the zone name.
898              
899             The returned value is a hash. It's keys are the names of the LDAP attributes.
900              
901             my %info=$pldm->getRelativeInfo('someRelative', 'someZone');
902             if($pldm->{error}){
903             print "Error!\n";
904             }
905              
906             =cut
907              
908             sub getRelativeInfo{
909             my $self=$_[0];
910             my $relative=$_[1];
911             my $zone=$_[2];
912             my $function='getRelativeInfo';
913              
914             #blanks any previous errors
915             $self->errorblank;
916             if ($self->{error}) {
917             warn($self->{module}.' '.$function.': A permanent error is set');
918             return undef;
919             }
920              
921             #makes sure all the required are specified
922             if (!defined($relative)) {
923             $self->{error}=1;
924             $self->{errorString}='No relative specified';
925             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
926             return undef;
927             }
928             if (!defined($zone)) {
929             $self->{error}=1;
930             $self->{errorString}='No zone specified';
931             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
932             return undef;
933             }
934              
935             #make sure the zone exists
936             my $returned=$self->relativeExists($relative, $zone);
937             if ($self->{error}) {
938             warn($self->{module}.' '.$function.': relativeExists errored');
939             return undef;
940             }
941             if (!$returned) {
942             $self->{error}=6;
943             $self->{errorString}='The relative "'.$relative.'" does not exist for the zone "'.$zone.'"';
944             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
945             return undef;
946             }
947              
948             #connect
949             my $ldap=$self->connect;
950             if ($self->{error}) {
951             warn($self->{module}.' '.$function.': connect errored');
952             return undef;
953             }
954              
955             #builds the zoneDC
956             my $zoneDN=$zone;
957             $zoneDN=~s/\./\,dc=/g;
958             $zoneDN='dc='.$zoneDN.','.$self->{ini}->{''}->{base};
959              
960             #search and get the first entry
961             my $mesg=$ldap->search(
962             base=>$zoneDN,
963             scope=>'one',
964             filter=>'(&(relativeDomainName='.$relative.') (&(zoneName='.$zone.') (objectClass=dNSZone)))'
965             );
966             my $entry=$mesg->pop_entry;
967              
968             #get the available attribute
969             my @attributes=$entry->attributes;
970              
971             #holds the values that will be returned
972             my %values;
973              
974             #process each one
975             my $int=0;
976             while (defined($attributes[$int])) {
977             my @data=$entry->get_value($attributes[$int]);
978             $values{$attributes[$int]}=\@data;
979              
980             $int++;
981             }
982              
983             return %values;
984             }
985              
986             =head2 hasSubZoneDCs
987              
988             This checks if a zone has any sub zones.
989              
990             One arguement is required and taken. It is the name of the zone.
991              
992             my $returned=$pldm->hasSubZones('some.zone');
993             if($pldm->{error}){
994             print "Error!\n";
995             }
996             if($returned){
997             print "The zone has sub zones.\n";
998             }
999              
1000             =cut
1001              
1002             sub hasSubZoneDCs{
1003             my $self=$_[0];
1004             my $zone=$_[1];
1005             my $function='hasSubZoneDCs';
1006            
1007             #blanks any previous errors
1008             $self->errorblank;
1009             if ($self->{error}) {
1010             warn($self->{module}.' '.$function.': A permanent error is set');
1011             return undef;
1012             }
1013              
1014             #make sure the zone exists
1015             my $returned=$self->zoneDCexists($zone);
1016             if ($self->{error}) {
1017             warn($self->{module}.' '.$function.': zoneExists errored');
1018             return undef;
1019             }
1020             if (!$returned) {
1021             $self->{error}=6;
1022             $self->{errorString}='The zone "'.$zone.'" does not exist';
1023             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1024             return undef;
1025             }
1026              
1027             #gets a list of zones
1028             my @zones=$self->listZoneDCs;
1029             if ($self->{error}) {
1030             warn($self->{module}.' '.$function.': listZones errored');
1031             return undef;
1032             }
1033              
1034             #look for matches
1035             my $int=0;
1036             my $regex=quotemeta('.'.$zone).'$';
1037             while (defined($zones[$int])) {
1038             if ($zones[$int]=~/$regex/) {
1039             return 1;
1040             }
1041              
1042             $int++;
1043             }
1044              
1045             #if we get here, it was not matched
1046             return undef;
1047             }
1048              
1049             =head2 listRelatives
1050              
1051             This lists the relative domain names setup for a zone.
1052              
1053             One arguement is required and that is the zone to list
1054             the relative domain names for.
1055              
1056             my @relatives=$pldm->listRelatives('some.zone');
1057             if($pldm->{error}){
1058             print "Error!\n";
1059             }
1060              
1061             =cut
1062              
1063             sub listRelatives{
1064             my $self=$_[0];
1065             my $zone=$_[1];
1066             my $function='listRelatives';
1067            
1068             #blanks any previous errors
1069             $self->errorblank;
1070             if ($self->{error}) {
1071             warn($self->{module}.' '.$function.': A permanent error is set');
1072             return undef;
1073             }
1074              
1075             if (!defined($zone)) {
1076             $self->{error}=1;
1077             $self->{errorString}='The zone name is undefined';
1078             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1079             return undef;
1080             }
1081            
1082             #make sure the zone exists
1083             my $returned=$self->zoneExists($zone);
1084             if ($self->{error}) {
1085             warn($self->{module}.' '.$function.': zoneExists errored');
1086             return undef;
1087             }
1088             if (!$returned) {
1089             $self->{error}=6;
1090             $self->{errorString}='The zone "'.$zone.'" does not exist';
1091             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1092             return undef;
1093             }
1094              
1095             my $zoneDN=$zone;
1096             $zoneDN=~s/\./\,dc=/g;
1097             $zoneDN='dc='.$zoneDN.','.$self->{ini}->{''}->{base};
1098            
1099             #connect
1100             my $ldap=$self->connect;
1101             if ($self->{error}) {
1102             warn($self->{module}.' '.$function.': connect errored');
1103             return undef;
1104             }
1105              
1106             #search and get the first entry
1107             my $mesg=$ldap->search(
1108             base=>$zoneDN,
1109             filter=>'(&(zoneName='.$zone.') (objectClass=dNSZone))'
1110             );
1111             my $entry=$mesg->pop_entry;
1112              
1113             #make sure we don't return the same entry twice
1114             my %relatives;
1115              
1116             if (!defined($entry)) {
1117             return undef;
1118             }
1119              
1120             #process each one
1121             while (defined($entry)) {
1122             my @values=$entry->get_value('relativeDomainName');
1123              
1124             my $int=0;
1125             while (defined($values[$int])) {
1126             $relatives{$values[$int]}='';
1127              
1128             $int++;
1129             }
1130              
1131             $entry=$mesg->pop_entry;
1132             }
1133              
1134             return keys(%relatives);
1135             }
1136              
1137             =head2 listZones
1138              
1139             This lists the zones that are setup in LDAP.
1140              
1141             my @zones=$pldm->listZones;
1142             if($pldm->{error}){
1143             print "Error!\n";
1144             }
1145              
1146             =cut
1147              
1148             sub listZones{
1149             my $self=$_[0];
1150             my $function='listZones';
1151            
1152             #blanks any previous errors
1153             $self->errorblank;
1154             if ($self->{error}) {
1155             warn($self->{module}.' '.$function.': A permanent error is set');
1156             return undef;
1157             }
1158              
1159             #connect
1160             my $ldap=$self->connect;
1161             if ($self->{error}) {
1162             warn($self->{module}.' '.$function.': connect errored');
1163             return undef;
1164             }
1165              
1166             #search and get the first entry
1167             my $mesg=$ldap->search(
1168             base=>$self->{ini}->{''}->{base},
1169             filter=>'(objectClass=dcObject)'
1170             );
1171             my $entry=$mesg->pop_entry;
1172              
1173             #these are the zones that will be returned
1174             my @zones;
1175              
1176             #if this is not defined, we definitely don't have any
1177             if (!defined($entry)) {
1178             return @zones;
1179             }
1180              
1181             #process each one and make sure we have a relativeDomainName=@ for each
1182             while (defined($entry)) {
1183             #get the DN and convert it to a domain name
1184             my $dn=$entry->dn;
1185             my $regex=','.quotemeta($self->{ini}->{''}->{base}).'$';
1186             $dn=~s/$regex//;
1187             $dn=~s/,dc\=/./g;
1188             $dn=~s/^dc\=//;
1189              
1190             #search and see if we have the required entry for a zone
1191             my $mesg2=$ldap->search(
1192             base=>$self->{ini}->{''}->{base},
1193             filter=>'(&(relativeDomainName=@) (zoneName='.$dn.'))'
1194             );
1195             my $entry2=$mesg2->pop_entry;
1196              
1197             #if it is defined, add it
1198             if (defined($entry2)) {
1199             push(@zones, $dn);
1200             }
1201              
1202             #get the next one
1203             $entry=$mesg->pop_entry;
1204             }
1205              
1206             return @zones;
1207             }
1208              
1209             =head2 listZoneDCs
1210              
1211             This builds a list of domain names based off of dcObjects.
1212              
1213             It does not check if it is a usable object or not.
1214              
1215             my @zones=$pldm->listZones;
1216             if($pldm->{error}){
1217             print "Error!\n";
1218             }
1219              
1220             =cut
1221              
1222             sub listZoneDCs{
1223             my $self=$_[0];
1224             my $function='listZoneDCs';
1225            
1226             #blanks any previous errors
1227             $self->errorblank;
1228             if ($self->{error}) {
1229             warn($self->{module}.' '.$function.': A permanent error is set');
1230             return undef;
1231             }
1232              
1233             #connect
1234             my $ldap=$self->connect;
1235             if ($self->{error}) {
1236             warn($self->{module}.' '.$function.': connect errored');
1237             return undef;
1238             }
1239              
1240             #search and get the first entry
1241             my $mesg=$ldap->search(
1242             base=>$self->{ini}->{''}->{base},
1243             filter=>'(objectClass=dcObject)'
1244             );
1245             my $entry=$mesg->pop_entry;
1246              
1247              
1248             my @zones;
1249             #process each one and make sure we have a relativeDomainName=@ for each
1250             while (defined($entry)) {
1251             #get the DN and convert it to a domain name
1252             my $dn=$entry->dn;
1253             my $regex=','.quotemeta($self->{ini}->{''}->{base}).'$';
1254             $dn=~s/$regex//;
1255             $dn=~s/,dc\=/./g;
1256             $dn=~s/^dc\=//;
1257              
1258             push(@zones, $dn);
1259              
1260             #get the next one
1261             $entry=$mesg->pop_entry;
1262             }
1263              
1264             return @zones;
1265             }
1266              
1267             =head2 readConfig
1268              
1269             This reads the specified config file.
1270              
1271             One arguement is accepted and that the name of the file to read.
1272              
1273             $pldm->readConfig('some/file.ini');
1274             if($pldm->{error}){
1275             print "Error!\n";
1276             }
1277              
1278             =cut
1279              
1280             sub readConfig{
1281             my $self=$_[0];
1282             my $config=$_[1];
1283             my $function='readConfig';
1284            
1285             #blanks any previous errors
1286             $self->errorblank;
1287             if ($self->{error}) {
1288             warn($self->{module}.' '.$function.': A permanent error is set');
1289             return undef;
1290             }
1291            
1292             #if it is not defined, use the default one
1293             if (!defined($config)) {
1294             $config=$self->{configfile};
1295             }
1296            
1297             #reads the config
1298             my $ini=ReadINI($config);
1299              
1300             #check if it is valid and set defaults if needed
1301             my $returned=$self->configCheck($ini);
1302             if ($self->{error}) {
1303             warn($self->{module}.' '.$function.': configCheck errored');
1304             return undef;
1305             }
1306             if (!$returned) {
1307             $self->{error}=2;
1308             $self->{errorString}='Missing either "bind" or "pass" values in the config.';
1309             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1310             return undef;
1311             }
1312              
1313             #save it
1314             $self->{ini}=$ini;
1315              
1316             return 1;
1317             }
1318              
1319             =head2 relativeExists
1320              
1321             This check if a specified relative exists for a zone.
1322              
1323             Two arguements are accepted. The first is the relative domain
1324             name and the second is the zone.
1325              
1326             my $returned=$pldm->relativeExists('someRelative', 'some.zone');
1327             if($pldm->{error}){
1328             print "Error!\n";
1329             }
1330             if($returned){
1331             print "The relative exists.\n";
1332             }
1333              
1334             =cut
1335              
1336             sub relativeExists{
1337             my $self=$_[0];
1338             my $relative=$_[1];
1339             my $zone=$_[2];
1340             my $function='relativeExists';
1341              
1342             $self->errorblank;
1343             if ($self->{error}) {
1344             warn($self->{module}.' '.$function.': A permanent error is set');
1345             return undef;
1346             }
1347              
1348             #make sure we have a zone
1349             if (!defined($zone)) {
1350             $self->{error}=1;
1351             $self->{errorString}='The zone name is undefined';
1352             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1353             return undef;
1354             }
1355              
1356             #make sure we have a relative
1357             if (!defined($relative)) {
1358             $self->{error}=1;
1359             $self->{errorString}='The relative name is undefined';
1360             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1361             return undef;
1362             }
1363              
1364             my @relatives=$self->listRelatives($zone);
1365             if ($self->{error}) {
1366             warn($self->{module}.' '.$function.': listRelatives errored');
1367             return undef;
1368             }
1369              
1370             #check the returned relatives
1371             my $int=0;
1372             while (defined($relatives[$int])) {
1373             if ($relatives[$int] eq $relative) {
1374             return 1;
1375             }
1376             $int++;
1377             }
1378              
1379             #if we get here, it does not exist
1380             return undef;
1381             }
1382              
1383             =head2 removeRecords
1384              
1385             This removes the specified records from a relative domain name.
1386              
1387             One arguement is taken and it is a hash.
1388              
1389             =head3 args hash
1390              
1391             =head4 relative
1392              
1393             This is a relative domain name.
1394              
1395             This is a required key.
1396              
1397             =head4 zone
1398              
1399             This is the zone to add it to.
1400              
1401             This is a required key.
1402              
1403             =head4 ttl
1404              
1405             If this is set to true, it will be removed.
1406              
1407             =head4 a
1408              
1409             This is a array containing entries for A records.
1410              
1411             =head4 aaaa
1412              
1413             This is a array containing entries for AAAA records.
1414              
1415             =head4 cname
1416              
1417             This is a array containing entries for CNAME records.
1418              
1419             =head4 mx
1420              
1421             This is a array containing entries for MX records.
1422              
1423             =head4 ptr
1424              
1425             This is a array containing entries for PTR records.
1426              
1427             =head4 txt
1428              
1429             This is a array containing entries for TXT records.
1430              
1431             $pldm->removeRecords({
1432             zone=>$opts{z},
1433             relative=>$opts{r},
1434             ttl=>$opts{T},
1435             a=>\@a,
1436             aaaa=>\@aaaa,
1437             mx=>\@mx,
1438             ptr=>\@ptr,
1439             txt=>\@txt,
1440             });
1441             if ($pldm->{error}) {
1442             exit $pldm->{error};
1443             }
1444              
1445             =cut
1446              
1447             sub removeRecords{
1448             my $self=$_[0];
1449             my %args;
1450             if(defined($_[1])){
1451             %args= %{$_[1]};
1452             };
1453             my $function='removeRecords';
1454              
1455             #blanks any previous errors
1456             $self->errorblank;
1457             if ($self->{error}) {
1458             warn($self->{module}.' '.$function.': A permanent error is set');
1459             return undef;
1460             }
1461              
1462             #makes sure all the required are specified
1463             if ( (!defined($args{relative})) || (!defined($args{zone})) ) {
1464             $self->{error}=1;
1465             $self->{errorString}='Either relative or zone is not defined';
1466             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1467             return undef;
1468             }
1469              
1470             #make sure the zone exists
1471             my $returned=$self->relativeExists($args{relative}, $args{zone});
1472             if ($self->{error}) {
1473             warn($self->{module}.' '.$function.': relativeExists errored');
1474             return undef;
1475             }
1476             if (!$returned) {
1477             $self->{error}=6;
1478             $self->{errorString}='The relative "'.$args{relative}.'" does not exist for the zone "'.$args{zone }.'"';
1479             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1480             return undef;
1481             }
1482              
1483             #connect
1484             my $ldap=$self->connect;
1485             if ($self->{error}) {
1486             warn($self->{module}.' '.$function.': connect errored');
1487             return undef;
1488             }
1489              
1490             #builds the zoneDC
1491             my $zoneDN=$args{zone};
1492             $zoneDN=~s/\./\,dc=/g;
1493             $zoneDN='dc='.$zoneDN.','.$self->{ini}->{''}->{base};
1494              
1495             #search and get the first entry
1496             my $mesg=$ldap->search(
1497             base=>$zoneDN,
1498             scope=>'one',
1499             filter=>'(&(relativeDomainName='.$args{relative}.') (&(zoneName='.$args{zone}.') (objectClass=dNSZone)))'
1500             );
1501             my $entry=$mesg->pop_entry;
1502              
1503             #adds any A records if needed
1504             if (defined($args{a}[0])) {
1505             $entry->delete(
1506             aRecord=>$args{a}
1507             );
1508             }
1509              
1510             #add a new TTL
1511             if (defined($args{ttl})) {
1512             $entry->delete('dNSTTL');
1513             }
1514              
1515             #adds any AAAA records if needed
1516             if (defined($args{aaaa}[0])) {
1517             $entry->delete(
1518             aAAARecord=>$args{aaaa}
1519             );
1520             }
1521              
1522             #adds any CNAME records if needed
1523             if (defined($args{cname}[0])) {
1524             $entry->delete(
1525             cNAMERecord=>$args{cname}
1526             );
1527             }
1528              
1529             #adds any MX records if needed
1530             if (defined($args{mx}[0])) {
1531             $entry->delete(
1532             MXRecord=>$args{mx}
1533             );
1534             }
1535              
1536             #adds any PTR records if needed
1537             if (defined($args{ptr}[0])) {
1538             $entry->delete(
1539             PTRRecord=>$args{ptr}
1540             );
1541             }
1542              
1543             #adds any PTR records if needed
1544             if (defined($args{txt}[0])) {
1545             $entry->delete(
1546             TXTRecord=>$args{txt}
1547             );
1548             }
1549              
1550             #mod it
1551             $mesg=$entry->update($ldap);
1552             if ($mesg->is_error) {
1553             $self->{error}=7;
1554             $self->{errorString}='Modifying the entry,"'.$entry->dn.'", failed';
1555             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1556             return undef;
1557             }
1558              
1559              
1560             return 1;
1561             }
1562              
1563             =head2 removeRelative
1564              
1565             This removes a specified relative from a zone.
1566              
1567             Two arguements are accepted. The first one is the relative name and
1568             the second one is the zone.
1569              
1570             This will remove any matching entries found. As of currently it does not
1571             check if the entry is being used for any others, which is why one should
1572             fall the implementation notes for when making use of this.
1573              
1574             my $returned=$pldm->removeExists('someRelative', 'some.zone');
1575             if($pldm->{error}){
1576             print "Error!\n";
1577             }
1578             if($returned){
1579             print "removed\n";
1580             }
1581              
1582             =cut
1583              
1584             sub removeRelative{
1585             my $self=$_[0];
1586             my $relative=$_[1];
1587             my $zone=$_[2];
1588             my $function='removeRelative';
1589              
1590             $self->errorblank;
1591             if ($self->{error}) {
1592             warn($self->{module}.' '.$function.': A permanent error is set');
1593             return undef;
1594             }
1595              
1596             #make sure we have a zone
1597             if (!defined($zone)) {
1598             $self->{error}=1;
1599             $self->{errorString}='The zone name is undefined';
1600             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1601             return undef;
1602             }
1603              
1604             #make sure we have a relative
1605             if (!defined($relative)) {
1606             $self->{error}=1;
1607             $self->{errorString}='The relative name is undefined';
1608             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1609             return undef;
1610             }
1611              
1612             #make sure it is not a @
1613             if ($relative eq '@') {
1614             $self->{error}=8;
1615             $self->{errorString}='"@" is reserved for zone zone record and can not be use as a relative name';
1616             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1617             return undef;
1618             }
1619              
1620             #make sure it is not a .
1621             if ($relative=~/\./) {
1622             $self->{error}=9;
1623             $self->{errorString}='"." was found in the relative name and this places it outside of this zone';
1624             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1625             return undef;
1626             }
1627              
1628             #make sure the zone exists
1629             my $returned=$self->zoneExists($zone);
1630             if ($self->{error}) {
1631             warn($self->{module}.' '.$function.': zoneExists errored');
1632             return undef;
1633             }
1634             if (!$returned) {
1635             $self->{error}=6;
1636             $self->{errorString}='The zone "'.$zone.'" does not exist';
1637             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1638             return undef;
1639             }
1640              
1641             #
1642             my $zoneDN=$zone;
1643             $zoneDN=~s/\./\,dc=/g;
1644             $zoneDN='dc='.$zoneDN.','.$self->{ini}->{''}->{base};
1645            
1646             #connect
1647             my $ldap=$self->connect;
1648             if ($self->{error}) {
1649             warn($self->{module}.' '.$function.': connect errored');
1650             return undef;
1651             }
1652              
1653             #search and get the first entry
1654             my $mesg=$ldap->search(
1655             base=>$zoneDN,
1656             filter=>'(&(relativeDomainName='.$relative.') (&(zoneName='.$zone.') (objectClass=dNSZone)))'
1657             );
1658             my $entry=$mesg->pop_entry;
1659              
1660             #
1661             my @removed;
1662              
1663             #remove each one
1664             while (defined($entry)) {
1665             push(@removed, $entry->dn);
1666             $entry->delete();
1667             my $mesg2=$entry->update($ldap);
1668             if ($mesg2->is_error) {
1669             $self->{error}=7;
1670             $self->{errorString}='Removing the entry,"'.$entry->dn.'", failed';
1671             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1672             return undef;
1673             }
1674            
1675             $entry=$mesg->pop_entry;
1676             }
1677              
1678             return @removed;
1679             }
1680              
1681             =head2 removeZone
1682              
1683             This removes a zone.
1684              
1685             Only one arguement is taken and it is the name
1686             of the zone.
1687              
1688             $pldm->removeZone('some.zone');
1689             if($pldm->{error}){
1690             print "Error!\n";
1691             }
1692              
1693             =cut
1694              
1695             sub removeZone{
1696             my $self=$_[0];
1697             my $zone=$_[1];
1698             my $function='removeZone';
1699              
1700             #blanks any previous errors
1701             $self->errorblank;
1702             if ($self->{error}) {
1703             warn($self->{module}.' '.$function.': A permanent error is set');
1704             return undef;
1705             }
1706              
1707             #make sure a zone is specified
1708             if (!defined($zone)) {
1709             $self->{error}=1;
1710             $self->{errorString}='No zone name specified';
1711             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1712             }
1713              
1714             #make sure the zone exists
1715             my $returned=$self->zoneExists($zone);
1716             if ($self->{error}) {
1717             warn($self->{module}.' '.$function.': zoneExists errored');
1718             return undef;
1719             }
1720             if (!$returned) {
1721             $self->{error}=6;
1722             $self->{errorString}='The zone "'.$zone.'" does not exist';
1723             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1724             return undef;
1725             }
1726              
1727             my @relatives=$self->listRelatives($zone);
1728             if ($self->{error}) {
1729             warn($self->{module}.' '.$function.': connect errored');
1730             return undef;
1731             }
1732              
1733             #removes them all
1734             my $int=0;
1735             while (defined( $relatives[$int] )) {
1736             if ($relatives[$int] ne '@') {
1737             $self->removeRelative($relatives[$int], $zone);
1738             if ($self->{error}) {
1739             warn($self->{module}.' '.$function.': removeRelative errored');
1740             return undef;
1741             }
1742             }
1743              
1744             $int++;
1745             }
1746              
1747             #builds the zoneDN
1748             my $zoneDN=$zone;
1749             $zoneDN=~s/\./\,dc=/g;
1750             $zoneDN='dc='.$zoneDN.','.$self->{ini}->{''}->{base};
1751              
1752             #connect
1753             my $ldap=$self->connect;
1754             if ($self->{error}) {
1755             warn($self->{module}.' '.$function.': connect errored');
1756             return undef;
1757             }
1758              
1759             #search and see if we have the required entry for a zone
1760             my $mesg=$ldap->search(
1761             base=>$self->{ini}->{''}->{base},
1762             filter=>'(&(relativeDomainName=@) (zoneName='.$zone.'))'
1763             );
1764             my $entry=$mesg->pop_entry;
1765              
1766             #removes it
1767             $entry->delete;
1768             $mesg=$entry->update($ldap);
1769             if ($mesg->is_error) {
1770             $self->{error}=7;
1771             $self->{errorString}='Removing the entry,"'.$entry->dn.'", failed';
1772             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1773             return undef;
1774             }
1775              
1776             #checks if the zone DC object should be removed or note
1777             my $subzones=$self->hasSubZoneDCs($zone);
1778             if ($self->{error}) {
1779             warn($self->{module}.' '.$function.': hasSubZones errored');
1780             return undef;
1781             }
1782             #return here if there is nothing more to processes
1783             if ($subzones) {
1784             return 1;
1785             }
1786              
1787             $self->removeZoneDC($zone);
1788             if ($self->{error}) {
1789             warn($self->{module}.' '.$function.': hasSubZones errored');
1790             return undef;
1791             }
1792              
1793             return 1;
1794             }
1795              
1796             =head2 removeZoneDC
1797              
1798             This removes the DC structure for a zone.
1799              
1800             =cut
1801              
1802             sub removeZoneDC{
1803             my $self=$_[0];
1804             my $zone=$_[1];
1805             my $function='removeZoneDC';
1806              
1807             #blanks any previous errors
1808             $self->errorblank;
1809             if ($self->{error}) {
1810             warn($self->{module}.' '.$function.': A permanent error is set');
1811             return undef;
1812             }
1813              
1814             #make sure a zone is specified
1815             if (!defined($zone)) {
1816             $self->{error}=1;
1817             $self->{errorString}='No zone name specified';
1818             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1819             }
1820              
1821             #builds the zoneDN
1822             my $zoneDN=$zone;
1823             $zoneDN=~s/\./\,dc=/g;
1824             $zoneDN='dc='.$zoneDN.','.$self->{ini}->{''}->{base};
1825              
1826             #connect
1827             my $ldap=$self->connect;
1828             if ($self->{error}) {
1829             warn($self->{module}.' '.$function.': connect errored');
1830             return undef;
1831             }
1832             #checks if the zone DC object should be removed or note
1833             my $subzones=$self->hasSubZoneDCs($zone);
1834             if ($self->{error}) {
1835             warn($self->{module}.' '.$function.': hasSubZones errored');
1836             return undef;
1837             }
1838             #return here if there is nothing more to processes
1839             if ($subzones) {
1840             return 1;
1841             }
1842              
1843             #search and see if we have the required entry for a zone
1844             my @zoneA=split(/\./, $zone);
1845             my $mesg=$ldap->search(
1846             base=>$zoneDN,
1847             scope=>'base',
1848             filter=>'(&(objectClass=dcObject) (dc='.$zoneA[0].'))'
1849             );
1850             my $entry=$mesg->pop_entry;
1851            
1852             #removes it
1853             $entry->delete;
1854             $mesg=$entry->update($ldap);
1855             if ($mesg->is_error) {
1856             $self->{error}=7;
1857             $self->{errorString}='Removing the entry,"'.$entry->dn.'", failed';
1858             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1859             return undef;
1860             }
1861              
1862             return 1;
1863             }
1864              
1865             =head2 setConfig
1866              
1867             This sets the config being used the hash ref that has been specified.
1868              
1869             my $config={""=>{
1870             bind=>'cn=admin,dc=whatever',
1871             pass=>'fubar',
1872             }
1873             };
1874             $pldm->setConfig($config);
1875             if($pldm->{error}){
1876             print "Error!\n";
1877             }
1878              
1879             =cut
1880              
1881             sub setConfig{
1882             my $self=$_[0];
1883             my $ini=$_[1];
1884             my $function='setConfig';
1885              
1886             $self->errorblank;
1887             if ($self->{error}) {
1888             warn($self->{module}.' '.$function.': A permanent error is set');
1889             return undef;
1890             }
1891              
1892             if (!defined($ini)) {
1893             $self->{error}=1;
1894             $self->{errorString}='No config passed to set';
1895             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1896             return undef;
1897             }
1898              
1899             #check if it is valid and set defaults if needed
1900             my $returned=$self->configCheck($ini);
1901             if ($self->{error}) {
1902             warn($self->{module}.' '.$function.': configCheck errored');
1903             return undef;
1904             }
1905             if (!$returned) {
1906             $self->{error}=2;
1907             $self->{errorString}='Missing either "bind" or "pass" values in the config.';
1908             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1909             return undef;
1910             }
1911              
1912             #save it
1913             $self->{ini}=$ini;
1914              
1915             return 1;
1916             }
1917              
1918             =head2 zoneDCexists
1919              
1920             This checks if the dcObject stuff for a zone exists.
1921              
1922             One arguement is required and it is the name of the zone
1923             to check for the dcObject structure for.
1924              
1925             my $returned=$pldm->zoneDCexists('some.zone');
1926             if($pldm->{error}){
1927             print "Error!\n";
1928             }
1929             if($returned){
1930             print "It exists.\n";
1931             }
1932              
1933             =cut
1934              
1935             sub zoneDCexists{
1936             my $self=$_[0];
1937             my $zone=$_[1];
1938             my $function='zoneDCexists';
1939            
1940             #blanks any previous errors
1941             $self->errorblank;
1942             if ($self->{error}) {
1943             warn($self->{module}.' '.$function.': A permanent error is set');
1944             return undef;
1945             }
1946              
1947             if (!defined($zone)) {
1948             $self->{error}=1;
1949             $self->{errorString}='The zone name is undefined';
1950             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
1951             return undef;
1952             }
1953              
1954             #get the list of zones
1955             my @zones=$self->listZoneDCs;
1956             if ($self->{error}) {
1957             warn($self->{module}.' '.$function.': listZones errored');
1958             return undef;
1959             }
1960              
1961             #checks if it matches any of the found zones
1962             my $int=0;
1963             while (defined($zones[$int])) {
1964             if ($zones[$int] eq $zone) {
1965             return 1;
1966             }
1967              
1968             $int++;
1969             }
1970              
1971             #if we get here, it does not exist
1972             return undef;
1973             }
1974              
1975             =head2 zoneExists
1976              
1977             This checks if a specified zone exists or not.
1978              
1979             One arguement is accepted and it is the name of the zone.
1980              
1981             my $returned=$pldm->zoneExists('some.zone');
1982             if($pldm->{error}){
1983             print "Error!\n";
1984             }
1985             if($returned){
1986             print "The zone exists.\n";
1987             }
1988              
1989             =cut
1990              
1991             sub zoneExists{
1992             my $self=$_[0];
1993             my $zone=$_[1];
1994             my $function='zoneExists';
1995            
1996             #blanks any previous errors
1997             $self->errorblank;
1998             if ($self->{error}) {
1999             warn($self->{module}.' '.$function.': A permanent error is set');
2000             return undef;
2001             }
2002              
2003             if (!defined($zone)) {
2004             $self->{error}=1;
2005             $self->{errorString}='The zone name is undefined';
2006             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
2007             return undef;
2008             }
2009              
2010             #get the list of zones
2011             my @zones=$self->listZones;
2012             if ($self->{error}) {
2013             warn($self->{module}.' '.$function.': listZones errored');
2014             return undef;
2015             }
2016              
2017             #checks if it matches any of the found zones
2018             my $int=0;
2019             while (defined($zones[$int])) {
2020             if ($zones[$int] eq $zone) {
2021             return 1;
2022             }
2023              
2024             $int++;
2025             }
2026              
2027             #if we get here, it does not exist
2028             return undef;
2029             }
2030              
2031             =head2 zoneIsDConly
2032              
2033             This check is the the zone specified is a object
2034             that has been created for just structural purposes
2035             or if it is a actual zone.
2036              
2037             my $returned=$pldm->zoneIsDConly('some.zone');
2038             if($pldm->{error}){
2039             print "Error!\n";
2040             }
2041             if($returned){
2042             print "It is lacking a relativeDomainName=@ entry.\n";
2043             }
2044              
2045             =cut
2046              
2047             sub zoneIsDConly{
2048             my $self=$_[0];
2049             my $zone=$_[1];
2050             my $function='zoneIsDConly';
2051            
2052             #blanks any previous errors
2053             $self->errorblank;
2054             if ($self->{error}) {
2055             warn($self->{module}.' '.$function.': A permanent error is set');
2056             return undef;
2057             }
2058              
2059             if (!defined($zone)) {
2060             $self->{error}=1;
2061             $self->{errorString}='The zone name is undefined';
2062             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
2063             return undef;
2064             }
2065              
2066             #make sure the zone exists
2067             my $returned=$self->zoneDCexists($zone);
2068             if ($self->{error}) {
2069             warn($self->{module}.' '.$function.': zoneExists errored');
2070             return undef;
2071             }
2072             if (!$returned) {
2073             $self->{error}=6;
2074             $self->{errorString}='The zone dcObject structure for "'.$zone.'" does not exist';
2075             warn($self->{module}.' '.$function.':'.$self->{error}.': '.$self->{errorString});
2076             return undef;
2077             }
2078              
2079             #get the list of zones
2080             my @zones=$self->listZones;
2081             if ($self->{error}) {
2082             warn($self->{module}.' '.$function.': listZones errored');
2083             return undef;
2084             }
2085              
2086             #get the list of zones
2087             my @dczones=$self->listZoneDCs;
2088             if ($self->{error}) {
2089             warn($self->{module}.' '.$function.': listZones errored');
2090             return undef;
2091             }
2092              
2093             #run through the dc structure
2094             my $dcInt=0;
2095             while (defined($dczones[$dcInt])) {
2096             my $zoneInt=0;
2097             while ($zones[$zoneInt]) {
2098             #if a match between the two is found, it means it is a full zone
2099             if ($zones[$zoneInt] eq $dczones[$dcInt]) {
2100             return undef;
2101             }
2102             $zoneInt++;
2103             }
2104              
2105             $dcInt++;
2106             }
2107            
2108              
2109             #if we get here, it does not exist
2110             return 1;
2111             }
2112              
2113             =head2 errorblank
2114              
2115             This is a internal function and should not be called.
2116              
2117             =cut
2118              
2119             #blanks the error flags
2120             sub errorblank{
2121             my $self=$_[0];
2122              
2123             if ($self->{perror}) {
2124             return undef;
2125             }
2126              
2127             $self->{error}=undef;
2128             $self->{errorString}="";
2129              
2130             return 1;
2131             };
2132              
2133             =head1 ERROR CODES
2134              
2135             =head2 1
2136              
2137             Missing a required variable.
2138              
2139             =head2 2
2140              
2141             Config value missing.
2142              
2143             =head2 3
2144              
2145             Failed to connect to LDAP.
2146              
2147             =head2 4
2148              
2149             Failed to start TLS.
2150              
2151             =head2 5
2152              
2153             Failed to bind to the server.
2154              
2155             =head2 6
2156              
2157             The zone does not exist.
2158              
2159             =head2 7
2160              
2161             Update for Net::LDAP::Entry failed.
2162              
2163             =head2 8
2164              
2165             Attempted to operate on '@'.
2166              
2167             =head2 9
2168              
2169             Zone is already setup.
2170              
2171             =head2 10
2172              
2173             The relative already exists.
2174              
2175             =head1 AUTHOR
2176              
2177             Zane C. Bowers, C<< >>
2178              
2179             =head1 BUGS
2180              
2181             Please report any bugs or feature requests to C, or through
2182             the web interface at L. I will be notified, and then you'll
2183             automatically be notified of progress on your bug as I make changes.
2184              
2185              
2186              
2187              
2188             =head1 SUPPORT
2189              
2190             You can find documentation for this module with the perldoc command.
2191              
2192             perldoc BIND::SDB::LDAP::Helper
2193              
2194              
2195             You can also look for information at:
2196              
2197             =over 4
2198              
2199             =item * RT: CPAN's request tracker
2200              
2201             L
2202              
2203             =item * AnnoCPAN: Annotated CPAN documentation
2204              
2205             L
2206              
2207             =item * CPAN Ratings
2208              
2209             L
2210              
2211             =item * Search CPAN
2212              
2213             L
2214              
2215             =back
2216              
2217              
2218             =head1 ACKNOWLEDGEMENTS
2219              
2220              
2221             =head1 COPYRIGHT & LICENSE
2222              
2223             Copyright 2009 Zane C. Bowers, all rights reserved.
2224              
2225             This program is free software; you can redistribute it and/or modify it
2226             under the same terms as Perl itself.
2227              
2228              
2229             =cut
2230              
2231             1; # End of BIND::SDB::LDAP::Helper