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