Remove building with NOCRYPTO option
[minix.git] / external / bsd / dhcp / dist / contrib / ldap / dhcpd-conf-to-ldap
blobaee6c97925d25172d6de504748032d7a0566d727
1 #!/usr/bin/perl -w
3 # Brian Masney <masneyb@gftp.org>
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.
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
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 :-)
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...
25 use Net::Domain qw(hostname hostfqdn hostdomain);
26 use Getopt::Long;
28 my $domain = hostdomain(); # your.domain
29 my $basedn = "dc=".$domain;
30 $basedn =~ s/\./,dc=/g; # dc=your,dc=domain
31 my $server = hostname(); # hostname (nodename)
32 my $dhcpcn = 'DHCP Config'; # CN of DHCP config tree
33 my $dhcpdn = "cn=$dhcpcn, $basedn"; # DHCP config tree DN
34 my $second = ''; # secondary server DN / hostname
35 my $i_conf = ''; # dhcp.conf file to read or stdin
36 my $o_ldif = ''; # output ldif file name or stdout
37 my @use = (); # extended flags (failover)
39 sub usage($;$)
41 my $rc = shift;
42 my $err= shift;
44 print STDERR "Error: $err\n\n" if(defined $err);
45 print STDERR <<__EOF_USAGE__;
46 usage:
47 $0 [options] < dhcpd.conf > dhcpd.ldif
49 options:
51 --basedn "dc=your,dc=domain" ("$basedn")
53 --dhcpdn "dhcp config DN" ("$dhcpdn")
55 --server "dhcp server name" ("$server")
57 --second "secondary server or DN" ("$second")
59 --conf "/path/to/dhcpd.conf" (default is stdin)
60 --ldif "/path/to/output.ldif" (default is stdout)
62 --use "extended features" (see source comments)
63 __EOF_USAGE__
64 exit($rc);
68 sub next_token
70 local ($lowercase) = @_;
71 local ($token, $newline);
73 do
75 if (!defined ($line) || length ($line) == 0)
77 $line = <>;
78 return undef if !defined ($line);
79 chop $line;
80 $line_number++;
81 $token_number = 0;
84 $line =~ s/#.*//;
85 $line =~ s/^\s+//;
86 $line =~ s/\s+$//;
88 while (length ($line) == 0);
90 if (($token, $newline) = $line =~ /^(.*?)\s+(.*)/)
92 if ($token =~ /^"/) {
93 #handle quoted token
94 if ($token !~ /"\s*$/)
96 ($tok, $newline) = $newline =~ /([^"]+")(.*)/;
97 $token .= " $tok";
100 $line = $newline;
102 else
104 $token = $line;
105 $line = '';
107 $token_number++;
109 $token =~ y/[A-Z]/[a-z]/ if $lowercase;
111 return ($token);
115 sub remaining_line
117 local ($block) = shift || 0;
118 local ($tmp, $str);
120 $str = "";
121 while (defined($tmp = next_token (0)))
123 $str .= ' ' if !($str eq "");
124 $str .= $tmp;
125 last if $tmp =~ /;\s*$/;
126 last if($block and $tmp =~ /\s*[}{]\s*$/);
129 $str =~ s/;$//;
130 return ($str);
135 add_dn_to_stack
137 local ($dn) = @_;
139 $current_dn = "$dn, $current_dn";
144 remove_dn_from_stack
146 $current_dn =~ s/^.*?,\s*//;
151 parse_error
153 print "Parse error on line number $line_number at token number $token_number\n";
154 exit (1);
159 print_entry
161 return if (scalar keys %curentry == 0);
163 if (!defined ($curentry{'type'}))
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))
173 foreach my $fo_peer (keys %failover)
175 next if(scalar(@{$failover{$fo_peer}}) <= 1);
176 print "dhcpStatements: failover peer $fo_peer { ",
177 join('; ', @{$failover{$fo_peer}}), "; }\n";
180 print "\n";
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'}))
188 print "objectClass: dhcpOptions\n";
190 print "dhcpPrimaryDN: $hostdn\n";
191 if(grep(/FaIlOvEr/i, @use) and ($second ne ''))
193 print "dhcpSecondaryDN: $second\n";
196 elsif ($curentry{'type'} eq 'subnet')
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'}))
204 print "objectClass: dhcpOptions\n";
207 print "dhcpNetMask: " . $curentry{'netmask'} . "\n";
208 if (defined ($curentry{'ranges'}))
210 foreach $statement (@{$curentry{'ranges'}})
212 print "dhcpRange: $statement\n";
216 elsif ($curentry{'type'} eq 'shared-network')
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'}))
224 print "objectClass: dhcpOptions\n";
227 elsif ($curentry{'type'} eq 'group')
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'}))
235 print "objectClass: dhcpOptions\n";
238 elsif ($curentry{'type'} eq 'host')
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'}))
246 print "objectClass: dhcpOptions\n";
249 if (defined ($curentry{'hwaddress'}))
251 $curentry{'hwaddress'} =~ y/[A-Z]/[a-z]/;
252 print "dhcpHWAddress: " . $curentry{'hwaddress'} . "\n";
255 elsif ($curentry{'type'} eq 'pool')
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'}))
263 print "objectClass: dhcpOptions\n";
266 if (defined ($curentry{'ranges'}))
268 foreach $statement (@{$curentry{'ranges'}})
270 print "dhcpRange: $statement\n";
274 elsif ($curentry{'type'} eq 'class')
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'}))
282 print "objectClass: dhcpOptions\n";
285 elsif ($curentry{'type'} eq 'subclass')
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'}))
293 print "objectClass: dhcpOptions\n";
295 print "dhcpClassData: " . $curentry{'class'} . "\n";
298 if (defined ($curentry{'statements'}))
300 foreach $statement (@{$curentry{'statements'}})
302 print "dhcpStatements: $statement\n";
306 if (defined ($curentry{'options'}))
308 foreach $statement (@{$curentry{'options'}})
310 print "dhcpOption: $statement\n";
314 print "\n";
315 undef (%curentry);
319 sub parse_netmask
321 local ($netmask) = @_;
322 local ($i);
324 if ((($a, $b, $c, $d) = $netmask =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) != 4)
326 parse_error ();
329 $num = (($a & 0xff) << 24) |
330 (($b & 0xff) << 16) |
331 (($c & 0xff) << 8) |
332 ($d & 0xff);
334 for ($i=1; $i<=32 && $num & (1 << (32 - $i)); $i++)
337 $i--;
339 return ($i);
343 sub parse_subnet
345 local ($ip, $tmp, $netmask);
347 print_entry () if %curentry;
349 $ip = next_token (0);
350 parse_error () if !defined ($ip);
352 $tmp = next_token (1);
353 parse_error () if !defined ($tmp);
354 parse_error () if !($tmp eq 'netmask');
356 $tmp = next_token (0);
357 parse_error () if !defined ($tmp);
358 $netmask = parse_netmask ($tmp);
360 $tmp = next_token (0);
361 parse_error () if !defined ($tmp);
362 parse_error () if !($tmp eq '{');
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 };
373 sub parse_shared_network
375 local ($descr, $tmp);
377 print_entry () if %curentry;
379 $descr = next_token (0);
380 parse_error () if !defined ($descr);
382 $tmp = next_token (0);
383 parse_error () if !defined ($tmp);
384 parse_error () if !($tmp eq '{');
386 add_dn_to_stack ("cn=$descr");
387 $curentry{'type'} = 'shared-network';
388 $curentry{'descr'} = $descr;
392 sub parse_host
394 local ($descr, $tmp);
396 print_entry () if %curentry;
398 $host = next_token (0);
399 parse_error () if !defined ($host);
401 $tmp = next_token (0);
402 parse_error () if !defined ($tmp);
403 parse_error () if !($tmp eq '{');
405 add_dn_to_stack ("cn=$host");
406 $curentry{'type'} = 'host';
407 $curentry{'host'} = $host;
411 sub parse_group
413 local ($descr, $tmp);
415 print_entry () if %curentry;
417 $tmp = next_token (0);
418 parse_error () if !defined ($tmp);
419 parse_error () if !($tmp eq '{');
421 my $idx;
422 if(exists($curcounter{$cursubnet})) {
423 $idx = ++$curcounter{$cursubnet}->{'group'};
424 } else {
425 $idx = ++$curcounter{''}->{'group'};
428 add_dn_to_stack ("cn=group".$idx);
429 $curentry{'type'} = 'group';
430 $curentry{'idx'} = $idx;
434 sub parse_pool
436 local ($descr, $tmp);
438 print_entry () if %curentry;
440 $tmp = next_token (0);
441 parse_error () if !defined ($tmp);
442 parse_error () if !($tmp eq '{');
444 my $idx;
445 if(exists($curcounter{$cursubnet})) {
446 $idx = ++$curcounter{$cursubnet}->{'pool'};
447 } else {
448 $idx = ++$curcounter{''}->{'pool'};
451 add_dn_to_stack ("cn=pool".$idx);
452 $curentry{'type'} = 'pool';
453 $curentry{'idx'} = $idx;
457 sub parse_class
459 local ($descr, $tmp);
461 print_entry () if %curentry;
463 $class = next_token (0);
464 parse_error () if !defined ($class);
466 $tmp = next_token (0);
467 parse_error () if !defined ($tmp);
468 parse_error () if !($tmp eq '{');
470 $class =~ s/\"//g;
471 add_dn_to_stack ("cn=$class");
472 $curentry{'type'} = 'class';
473 $curentry{'class'} = $class;
477 sub parse_subclass
479 local ($descr, $tmp);
481 print_entry () if %curentry;
483 $class = next_token (0);
484 parse_error () if !defined ($class);
486 $subclass = next_token (0);
487 parse_error () if !defined ($subclass);
489 $tmp = next_token (0);
490 parse_error () if !defined ($tmp);
491 parse_error () if !($tmp eq '{');
493 add_dn_to_stack ("cn=$subclass");
494 $curentry{'type'} = 'subclass';
495 $curentry{'class'} = $class;
496 $curentry{'subclass'} = $subclass;
500 sub parse_hwaddress
502 local ($type, $hw, $tmp);
504 $type = next_token (1);
505 parse_error () if !defined ($type);
507 $hw = next_token (1);
508 parse_error () if !defined ($hw);
509 $hw =~ s/;$//;
511 $curentry{'hwaddress'} = "$type $hw";
515 sub parse_range
517 local ($tmp, $str);
519 $str = remaining_line ();
521 if (!($str eq ''))
523 $str =~ s/;$//;
524 push (@{$curentry{'ranges'}}, $str);
529 sub parse_statement
531 local ($token) = shift;
532 local ($str);
534 if ($token eq 'option')
536 $str = remaining_line ();
537 push (@{$curentry{'options'}}, $str);
539 elsif($token eq 'failover')
541 $str = remaining_line (1); # take care on block
542 if($str =~ /[{]/)
544 my ($peername, @statements);
546 parse_error() if($str !~ /^\s*peer\s+(.+?)\s+[{]\s*$/);
547 parse_error() if(($peername = $1) !~ /^\"?[^\"]+\"?$/);
550 # failover config block found:
551 # e.g. 'failover peer "some-name" {'
553 if(not grep(/FaIlOvEr/i, @use))
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";
560 until($str =~ /[}]/ or $str eq "")
562 $str = remaining_line (1);
563 # collect all statements, except ending '}'
564 push(@statements, $str) if($str !~ /[}]/);
566 $failover{$peername} = [@statements];
568 else
571 # pool reference to failover config is fine
572 # e.g. 'failover peer "some-name";'
574 if(not grep(/FaIlOvEr/i, @use))
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";
580 else
582 push (@{$curentry{'statements'}}, $token. " " . $str);
586 elsif($token eq 'zone')
588 $str = $token;
589 while($str !~ /}$/) {
590 $str .= ' ' . next_token (0);
592 push (@{$curentry{'statements'}}, $str);
594 elsif($token =~ /^(authoritative)[;]*$/)
596 push (@{$curentry{'statements'}}, $1);
598 else
600 $str = $token . " " . remaining_line ();
601 push (@{$curentry{'statements'}}, $str);
606 my $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); },
617 unless($server =~ /^\w+/)
619 usage(1, "invalid server name '$server'");
621 unless($basedn =~ /^\w+=[^,]+/)
623 usage(1, "invalid base dn '$basedn'");
626 if($dhcpdn =~ /^cn=([^,]+)/i)
628 $dhcpcn = "$1";
630 $second = '' if not defined $second;
631 unless($second eq '' or $second =~ /^cn=[^,]+\s*,\s*\w+=[^,]+/i)
633 if($second =~ /^cn=[^,]+$/i)
635 # relative DN 'cn=name'
636 $second = "$second, $basedn";
638 elsif($second =~ /^\w+/)
640 # assume hostname only
641 $second = "cn=$second, $basedn";
643 else
645 usage(1, "invalid secondary '$second'")
649 usage(1) unless($ok);
651 if($i_conf ne "" and -f $i_conf)
653 if(not open(STDIN, '<', $i_conf))
655 print STDERR "Error: can't open conf file '$i_conf': $!\n";
656 exit(1);
659 if($o_ldif ne "")
661 if(-e $o_ldif)
663 print STDERR "Error: output ldif name '$o_ldif' already exists!\n";
664 exit(1);
666 if(not open(STDOUT, '>', $o_ldif))
668 print STDERR "Error: can't open ldif file '$o_ldif': $!\n";
669 exit(1);
674 print STDERR "Creating LDAP Configuration with the following options:\n";
675 print STDERR "\tBase DN: $basedn\n";
676 print STDERR "\tDHCP DN: $dhcpdn\n";
677 print STDERR "\tServer DN: cn=$server, $basedn\n";
678 print STDERR "\tSecondary DN: $second\n"
679 if(grep(/FaIlOvEr/i, @use) and $second ne '');
680 print STDERR "\n";
682 my $token;
683 my $token_number = 0;
684 my $line_number = 0;
685 my %curentry;
686 my $cursubnet = '';
687 my %curcounter = ( '' => { pool => 0, group => 0 } );
689 $current_dn = "$dhcpdn";
690 $curentry{'descr'} = $dhcpcn;
691 $line = '';
692 %failover = ();
694 while (($token = next_token (1)))
696 if ($token eq '}')
698 print_entry () if %curentry;
699 if($current_dn =~ /.+?,\s*${dhcpdn}$/) {
700 # don't go below dhcpdn ...
701 remove_dn_from_stack ();
704 elsif ($token eq 'subnet')
706 parse_subnet ();
707 next;
709 elsif ($token eq 'shared-network')
711 parse_shared_network ();
712 next;
714 elsif ($token eq 'class')
716 parse_class ();
717 next;
719 elsif ($token eq 'subclass')
721 parse_subclass ();
722 next;
724 elsif ($token eq 'pool')
726 parse_pool ();
727 next;
729 elsif ($token eq 'group')
731 parse_group ();
732 next;
734 elsif ($token eq 'host')
736 parse_host ();
737 next;
739 elsif ($token eq 'hardware')
741 parse_hwaddress ();
742 next;
744 elsif ($token eq 'range')
746 parse_range ();
747 next;
749 else
751 parse_statement ($token);
752 next;
756 close(STDIN) if($i_conf);
757 close(STDOUT) if($o_ldif);
759 print STDERR "Done.\n";