]> git.pld-linux.org Git - packages/dhcp.git/blame - dhcpd-conf-to-ldap
- x32 rebuild
[packages/dhcp.git] / dhcpd-conf-to-ldap
CommitLineData
8c878a4c
ER
1#!/usr/bin/perl -w
2
3# Brian Masney <masneyb@ntelos.net>
4# To use this script, set your base DN below. Then run
5# ./dhcpd-conf-to-ldap.pl < /path-to-dhcpd-conf/dhcpd.conf > output-file
6# The output of this script will generate entries in LDIF format. You can use
7# the slapadd command to add these entries into your LDAP server. You will
8# definately want to double check that your LDAP entries are correct before
9# you load them into LDAP.
10
11# This script does not do much error checking. Make sure before you run this
12# that the DHCP server doesn't give any errors about your config file
13
14# FailOver notes:
15# Failover is disabled by default, since it may need manually intervention.
16# You can try the '--use=failover' option to see what happens :-)
17#
18# If enabled, the failover pool references will be written to LDIF output.
19# The failover configs itself will be added to the dhcpServer statements
20# and not to the dhcpService object (since this script uses only one and
21# it may be usefull to have multiple service containers in failover mode).
22# Further, this script does not check if primary or secondary makes sense,
23# it simply converts what it gets...
24
25use Net::Domain qw(hostname hostfqdn hostdomain);
26use Getopt::Long;
27
28my $domain = hostdomain(); # your.domain
29my $basedn = "dc=".$domain;
30 $basedn =~ s/\./,dc=/g; # dc=your,dc=domain
31my $server = hostname(); # hostname (nodename)
32my $dhcpcn = 'DHCP Config'; # CN of DHCP config tree
33my $dhcpdn = "cn=$dhcpcn, $basedn"; # DHCP config tree DN
34my $second = ''; # secondary server DN / hostname
35my $i_conf = ''; # dhcp.conf file to read or stdin
36my $o_ldif = ''; # output ldif file name or stdout
37my @use = (); # extended flags (failover)
38
39sub usage($;$)
40{
41 my $rc = shift;
42 my $err= shift;
43
44 print STDERR "Error: $err\n\n" if(defined $err);
45 print STDERR <<__EOF_USAGE__;
46usage:
47 $0 [options] < dhcpd.conf > dhcpd.ldif
48
49options:
50
51 --basedn "dc=your,dc=domain" ("$basedn")
52
53 --dhcpdn "dhcp config DN" ("$dhcpdn")
54
55 --server "dhcp server name" ("$server")
56
57 --second "secondary server or DN" ("$second")
58
59 --conf "/path/to/dhcpd.conf" (default is stdin)
60 --ldif "/path/to/output.ldif" (default is stdout)
61
62 --use "extended features" (see source comments)
63__EOF_USAGE__
64 exit($rc);
65}
66
67
68sub next_token
69{
70 local ($lowercase) = @_;
71 local ($token, $newline);
72
73 do
74 {
75 if (!defined ($line) || length ($line) == 0)
76 {
77 $line = <>;
78 return undef if !defined ($line);
79 chop $line;
80 $line_number++;
81 $token_number = 0;
82 }
83
84 $line =~ s/#.*//;
85 $line =~ s/^\s+//;
86 $line =~ s/\s+$//;
87 }
88 while (length ($line) == 0);
89
90 if (($token, $newline) = $line =~ /^(.*?)\s+(.*)/)
91 {
92 if ($token =~ /^"/) {
93 #handle quoted token
94 if ($token !~ /"\s*$/)
95 {
96 ($tok, $newline) = $newline =~ /([^"]+")(.*)/;
97 $token .= " $tok";
98 }
99 }
100 $line = $newline;
101 }
102 else
103 {
104 $token = $line;
105 $line = '';
106 }
107 $token_number++;
108
109 $token =~ y/[A-Z]/[a-z]/ if $lowercase;
110
111 return ($token);
112}
113
114
115sub remaining_line
116{
117 local ($block) = shift || 0;
118 local ($tmp, $str);
119
120 $str = "";
121 while (defined($tmp = next_token (0)))
122 {
123 $str .= ' ' if !($str eq "");
124 $str .= $tmp;
125 last if $tmp =~ /;\s*$/;
126 last if($block and $tmp =~ /\s*[}{]\s*$/);
127 }
128
129 $str =~ s/;$//;
130 return ($str);
131}
132
133
134sub
135add_dn_to_stack
136{
137 local ($dn) = @_;
138
139 $current_dn = "$dn, $current_dn";
140}
141
142
143sub
144remove_dn_from_stack
145{
146 $current_dn =~ s/^.*?,\s*//;
147}
148
149
150sub
151parse_error
152{
153 print "Parse error on line number $line_number at token number $token_number\n";
154 exit (1);
155}
156
157
158sub
159print_entry
160{
161 return if (scalar keys %curentry == 0);
162
163 if (!defined ($curentry{'type'}))
164 {
165 $hostdn = "cn=$server, $basedn";
166 print "dn: $hostdn\n";
167 print "cn: $server\n";
168 print "objectClass: top\n";
169 print "objectClass: dhcpServer\n";
170 print "dhcpServiceDN: $current_dn\n";
171 if(grep(/FaIlOvEr/i, @use))
172 {
173 foreach my $fo_peer (keys %failover)
174 {
175 next if(scalar(@{$failover{$fo_peer}}) <= 1);
176 print "dhcpStatements: failover peer $fo_peer { ",
177 join('; ', @{$failover{$fo_peer}}), "; }\n";
178 }
179 }
180 print "\n";
181
182 print "dn: $current_dn\n";
183 print "cn: $dhcpcn\n";
184 print "objectClass: top\n";
185 print "objectClass: dhcpService\n";
186 if (defined ($curentry{'options'}))
187 {
188 print "objectClass: dhcpOptions\n";
189 }
190 print "dhcpPrimaryDN: $hostdn\n";
191 if(grep(/FaIlOvEr/i, @use) and ($second ne ''))
192 {
193 print "dhcpSecondaryDN: $second\n";
194 }
195 }
196 elsif ($curentry{'type'} eq 'subnet')
197 {
198 print "dn: $current_dn\n";
199 print "cn: " . $curentry{'ip'} . "\n";
200 print "objectClass: top\n";
201 print "objectClass: dhcpSubnet\n";
202 if (defined ($curentry{'options'}))
203 {
204 print "objectClass: dhcpOptions\n";
205 }
206
207 print "dhcpNetMask: " . $curentry{'netmask'} . "\n";
208 if (defined ($curentry{'ranges'}))
209 {
210 foreach $statement (@{$curentry{'ranges'}})
211 {
212 print "dhcpRange: $statement\n";
213 }
214 }
215 }
216 elsif ($curentry{'type'} eq 'shared-network')
217 {
218 print "dn: $current_dn\n";
219 print "cn: " . $curentry{'descr'} . "\n";
220 print "objectClass: top\n";
221 print "objectClass: dhcpSharedNetwork\n";
222 if (defined ($curentry{'options'}))
223 {
224 print "objectClass: dhcpOptions\n";
225 }
226 }
227 elsif ($curentry{'type'} eq 'group')
228 {
229 print "dn: $current_dn\n";
230 print "cn: group", $curentry{'idx'}, "\n";
231 print "objectClass: top\n";
232 print "objectClass: dhcpGroup\n";
233 if (defined ($curentry{'options'}))
234 {
235 print "objectClass: dhcpOptions\n";
236 }
237 }
238 elsif ($curentry{'type'} eq 'host')
239 {
240 print "dn: $current_dn\n";
241 print "cn: " . $curentry{'host'} . "\n";
242 print "objectClass: top\n";
243 print "objectClass: dhcpHost\n";
244 if (defined ($curentry{'options'}))
245 {
246 print "objectClass: dhcpOptions\n";
247 }
248
249 if (defined ($curentry{'hwaddress'}))
250 {
251 $curentry{'hwaddress'} =~ y/[A-Z]/[a-z]/;
252 print "dhcpHWAddress: " . $curentry{'hwaddress'} . "\n";
253 }
254 }
255 elsif ($curentry{'type'} eq 'pool')
256 {
257 print "dn: $current_dn\n";
258 print "cn: pool", $curentry{'idx'}, "\n";
259 print "objectClass: top\n";
260 print "objectClass: dhcpPool\n";
261 if (defined ($curentry{'options'}))
262 {
263 print "objectClass: dhcpOptions\n";
264 }
265
266 if (defined ($curentry{'ranges'}))
267 {
268 foreach $statement (@{$curentry{'ranges'}})
269 {
270 print "dhcpRange: $statement\n";
271 }
272 }
273 }
274 elsif ($curentry{'type'} eq 'class')
275 {
276 print "dn: $current_dn\n";
277 print "cn: " . $curentry{'class'} . "\n";
278 print "objectClass: top\n";
279 print "objectClass: dhcpClass\n";
280 if (defined ($curentry{'options'}))
281 {
282 print "objectClass: dhcpOptions\n";
283 }
284 }
285 elsif ($curentry{'type'} eq 'subclass')
286 {
287 print "dn: $current_dn\n";
288 print "cn: " . $curentry{'subclass'} . "\n";
289 print "objectClass: top\n";
290 print "objectClass: dhcpSubClass\n";
291 if (defined ($curentry{'options'}))
292 {
293 print "objectClass: dhcpOptions\n";
294 }
295 print "dhcpClassData: " . $curentry{'class'} . "\n";
296 }
297
298 if (defined ($curentry{'statements'}))
299 {
300 foreach $statement (@{$curentry{'statements'}})
301 {
302 print "dhcpStatements: $statement\n";
303 }
304 }
305
306 if (defined ($curentry{'options'}))
307 {
308 foreach $statement (@{$curentry{'options'}})
309 {
310 print "dhcpOption: $statement\n";
311 }
312 }
313
314 print "\n";
315 undef (%curentry);
316}
317
318
319sub parse_netmask
320{
321 local ($netmask) = @_;
322 local ($i);
323
324 if ((($a, $b, $c, $d) = $netmask =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) != 4)
325 {
326 parse_error ();
327 }
328
329 $num = (($a & 0xff) << 24) |
330 (($b & 0xff) << 16) |
331 (($c & 0xff) << 8) |
332 ($d & 0xff);
333
334 for ($i=1; $i<=32 && $num & (1 << (32 - $i)); $i++)
335 {
336 }
337 $i--;
338
339 return ($i);
340}
341
342
343sub parse_subnet
344{
345 local ($ip, $tmp, $netmask);
346
347 print_entry () if %curentry;
348
349 $ip = next_token (0);
350 parse_error () if !defined ($ip);
351
352 $tmp = next_token (1);
353 parse_error () if !defined ($tmp);
354 parse_error () if !($tmp eq 'netmask');
355
356 $tmp = next_token (0);
357 parse_error () if !defined ($tmp);
358 $netmask = parse_netmask ($tmp);
359
360 $tmp = next_token (0);
361 parse_error () if !defined ($tmp);
362 parse_error () if !($tmp eq '{');
363
364 add_dn_to_stack ("cn=$ip");
365 $curentry{'type'} = 'subnet';
366 $curentry{'ip'} = $ip;
367 $curentry{'netmask'} = $netmask;
368 $cursubnet = $ip;
369 $curcounter{$ip} = { pool => 0, group => 0 };
370}
371
372
373sub parse_shared_network
374{
375 local ($descr, $tmp);
376
377 print_entry () if %curentry;
378
379 $descr = next_token (0);
380 parse_error () if !defined ($descr);
381
382 $tmp = next_token (0);
383 parse_error () if !defined ($tmp);
384 parse_error () if !($tmp eq '{');
385
386 add_dn_to_stack ("cn=$descr");
387 $curentry{'type'} = 'shared-network';
388 $curentry{'descr'} = $descr;
389}
390
391
392sub parse_host
393{
394 local ($descr, $tmp);
395
396 print_entry () if %curentry;
397
398 $host = next_token (0);
399 parse_error () if !defined ($host);
400
401 $tmp = next_token (0);
402 parse_error () if !defined ($tmp);
403 parse_error () if !($tmp eq '{');
404
405 add_dn_to_stack ("cn=$host");
406 $curentry{'type'} = 'host';
407 $curentry{'host'} = $host;
408}
409
410
411sub parse_group
412{
413 local ($descr, $tmp);
414
415 print_entry () if %curentry;
416
417 $tmp = next_token (0);
418 parse_error () if !defined ($tmp);
419 parse_error () if !($tmp eq '{');
420
421 my $idx;
422 if(exists($curcounter{$cursubnet})) {
423 $idx = ++$curcounter{$cursubnet}->{'group'};
424 } else {
425 $idx = ++$curcounter{''}->{'group'};
426 }
427
428 add_dn_to_stack ("cn=group".$idx);
429 $curentry{'type'} = 'group';
430 $curentry{'idx'} = $idx;
431}
432
433
434sub parse_pool
435{
436 local ($descr, $tmp);
437
438 print_entry () if %curentry;
439
440 $tmp = next_token (0);
441 parse_error () if !defined ($tmp);
442 parse_error () if !($tmp eq '{');
443
444 my $idx;
445 if(exists($curcounter{$cursubnet})) {
446 $idx = ++$curcounter{$cursubnet}->{'pool'};
447 } else {
448 $idx = ++$curcounter{''}->{'pool'};
449 }
450
451 add_dn_to_stack ("cn=pool".$idx);
452 $curentry{'type'} = 'pool';
453 $curentry{'idx'} = $idx;
454}
455
456
457sub parse_class
458{
459 local ($descr, $tmp);
460
461 print_entry () if %curentry;
462
463 $class = next_token (0);
464 parse_error () if !defined ($class);
465
466 $tmp = next_token (0);
467 parse_error () if !defined ($tmp);
468 parse_error () if !($tmp eq '{');
469
470 $class =~ s/\"//g;
471 add_dn_to_stack ("cn=$class");
472 $curentry{'type'} = 'class';
473 $curentry{'class'} = $class;
474}
475
476
477sub parse_subclass
478{
479 local ($descr, $tmp);
480
481 print_entry () if %curentry;
482
483 $class = next_token (0);
484 parse_error () if !defined ($class);
485
486 $subclass = next_token (0);
487 parse_error () if !defined ($subclass);
488
489 $tmp = next_token (0);
490 parse_error () if !defined ($tmp);
491 parse_error () if !($tmp eq '{');
492
493 add_dn_to_stack ("cn=$subclass");
494 $curentry{'type'} = 'subclass';
495 $curentry{'class'} = $class;
496 $curentry{'subclass'} = $subclass;
497}
498
499
500sub parse_hwaddress
501{
502 local ($type, $hw, $tmp);
503
504 $type = next_token (1);
505 parse_error () if !defined ($type);
506
507 $hw = next_token (1);
508 parse_error () if !defined ($hw);
509 $hw =~ s/;$//;
510
511 $curentry{'hwaddress'} = "$type $hw";
512}
513
514
515sub parse_range
516{
517 local ($tmp, $str);
518
519 $str = remaining_line ();
520
521 if (!($str eq ''))
522 {
523 $str =~ s/;$//;
524 push (@{$curentry{'ranges'}}, $str);
525 }
526}
527
528
529sub parse_statement
530{
531 local ($token) = shift;
532 local ($str);
533
534 if ($token eq 'option')
535 {
536 $str = remaining_line ();
537 push (@{$curentry{'options'}}, $str);
538 }
539 elsif($token eq 'failover')
540 {
541 $str = remaining_line (1); # take care on block
542 if($str =~ /[{]/)
543 {
544 my ($peername, @statements);
545
546 parse_error() if($str !~ /^\s*peer\s+(.+?)\s+[{]\s*$/);
547 parse_error() if(($peername = $1) !~ /^\"?[^\"]+\"?$/);
548
549 #
550 # failover config block found:
551 # e.g. 'failover peer "some-name" {'
552 #
553 if(not grep(/FaIlOvEr/i, @use))
554 {
555 print STDERR "Warning: Failover config 'peer $peername' found!\n";
556 print STDERR " Skipping it, since failover disabled!\n";
557 print STDERR " You may try out --use=failover option.\n";
558 }
559
560 until($str =~ /[}]/ or $str eq "")
561 {
562 $str = remaining_line (1);
563 # collect all statements, except ending '}'
564 push(@statements, $str) if($str !~ /[}]/);
565 }
566 $failover{$peername} = [@statements];
567 }
568 else
569 {
570 #
571 # pool reference to failover config is fine
572 # e.g. 'failover peer "some-name";'
573 #
574 if(not grep(/FaIlOvEr/i, @use))
575 {
576 print STDERR "Warning: Failover reference '$str' found!\n";
577 print STDERR " Skipping it, since failover disabled!\n";
578 print STDERR " You may try out --use=failover option.\n";
579 }
580 else
581 {
582 push (@{$curentry{'statements'}}, $token. " " . $str);
583 }
584 }
585 }
586 elsif($token eq 'zone')
587 {
588 $str = $token;
589 while($str !~ /}$/) {
590 $str .= ' ' . next_token (0);
591 }
592 push (@{$curentry{'statements'}}, $str);
593 }
594 elsif($token =~ /^(authoritative)[;]*$/)
595 {
596 push (@{$curentry{'statements'}}, $1);
597 }
598 else
599 {
600 $str = $token . " " . remaining_line ();
601 push (@{$curentry{'statements'}}, $str);
602 }
603}
604
605
606my $ok = GetOptions(
607 'basedn=s' => \$basedn,
608 'dhcpdn=s' => \$dhcpdn,
609 'server=s' => \$server,
610 'second=s' => \$second,
611 'conf=s' => \$i_conf,
612 'ldif=s' => \$o_ldif,
613 'use=s' => \@use,
614 'h|help|usage' => sub { usage(0); },
615);
616
617unless($server =~ /^\w+/)
618 {
619 usage(1, "invalid server name '$server'");
620 }
621unless($basedn =~ /^\w+=[^,]+/)
622 {
623 usage(1, "invalid base dn '$basedn'");
624 }
625
626if($dhcpdn =~ /^cn=([^,]+)/i)
627 {
628 $dhcpcn = "$1";
629 }
630$second = '' if not defined $second;
631unless($second eq '' or $second =~ /^cn=[^,]+\s*,\s*\w+=[^,]+/i)
632 {
633 if($second =~ /^cn=[^,]+$/i)
634 {
635 # relative DN 'cn=name'
636 $second = "$second, $basedn";
637 }
638 elsif($second =~ /^\w+/)
639 {
640 # assume hostname only
641 $second = "cn=$second, $basedn";
642 }
643 else
644 {
645 usage(1, "invalid secondary '$second'")
646 }
647 }
648
649usage(1) unless($ok);
650
651if($i_conf ne "" and -f $i_conf)
652 {
653 if(not open(STDIN, '<', $i_conf))
654 {
655 print STDERR "Error: can't open conf file '$i_conf': $!\n";
656 exit(1);
657 }
658 }
659if($o_ldif ne "")
660 {
661 if(-e $o_ldif)
662 {
663 print STDERR "Error: output ldif name '$o_ldif' already exists!\n";
664 exit(1);
665 }
666 if(not open(STDOUT, '>', $o_ldif))
667 {
668 print STDERR "Error: can't open ldif file '$o_ldif': $!\n";
669 exit(1);
670 }
671 }
672
673
674print STDERR "Creating LDAP Configuration with the following options:\n";
675print STDERR "\tBase DN: $basedn\n";
676print STDERR "\tDHCP DN: $dhcpdn\n";
677print STDERR "\tServer DN: cn=$server, $basedn\n";
678print STDERR "\tSecondary DN: $second\n"
679 if(grep(/FaIlOvEr/i, @use) and $second ne '');
680print STDERR "\n";
681
682my $token;
683my $token_number = 0;
684my $line_number = 0;
685my %curentry;
686my $cursubnet = '';
687my %curcounter = ( '' => { pool => 0, group => 0 } );
688
689$current_dn = "$dhcpdn";
690$curentry{'descr'} = $dhcpcn;
691$line = '';
692%failover = ();
693
694while (($token = next_token (1)))
695 {
696 if ($token eq '}')
697 {
698 print_entry () if %curentry;
699 if($current_dn =~ /.+?,\s*${dhcpdn}$/) {
700 # don't go below dhcpdn ...
701 remove_dn_from_stack ();
702 }
703 }
704 elsif ($token eq 'subnet')
705 {
706 parse_subnet ();
707 next;
708 }
709 elsif ($token eq 'shared-network')
710 {
711 parse_shared_network ();
712 next;
713 }
714 elsif ($token eq 'class')
715 {
716 parse_class ();
717 next;
718 }
719 elsif ($token eq 'subclass')
720 {
721 parse_subclass ();
722 next;
723 }
724 elsif ($token eq 'pool')
725 {
726 parse_pool ();
727 next;
728 }
729 elsif ($token eq 'group')
730 {
731 parse_group ();
732 next;
733 }
734 elsif ($token eq 'host')
735 {
736 parse_host ();
737 next;
738 }
739 elsif ($token eq 'hardware')
740 {
741 parse_hwaddress ();
742 next;
743 }
744 elsif ($token eq 'range')
745 {
746 parse_range ();
747 next;
748 }
749 else
750 {
751 parse_statement ($token);
752 next;
753 }
754 }
755
756close(STDIN) if($i_conf);
757close(STDOUT) if($o_ldif);
758
759print STDERR "Done.\n";
760
This page took 0.128058 seconds and 4 git commands to generate.