73f5b3e
#!/usr/bin/perl -w
73f5b3e
73f5b3e
# Brian Masney <masneyb@ntelos.net>
73f5b3e
# To use this script, set your base DN below. Then run 
73f5b3e
# ./dhcpd-conf-to-ldap.pl < /path-to-dhcpd-conf/dhcpd.conf > output-file
73f5b3e
# The output of this script will generate entries in LDIF format. You can use
73f5b3e
# the slapadd command to add these entries into your LDAP server. You will
73f5b3e
# definately want to double check that your LDAP entries are correct before
73f5b3e
# you load them into LDAP.
73f5b3e
73f5b3e
# This script does not do much error checking. Make sure before you run this
73f5b3e
# that the DHCP server doesn't give any errors about your config file
73f5b3e
73f5b3e
use Sys::Hostname;
73f5b3e
73f5b3e
my $basedn = "dc=ntelos, dc=net";
73f5b3e
73f5b3e
sub next_token
73f5b3e
{
73f5b3e
  local ($lowercase) = @_;
73f5b3e
  local ($token, $newline);
73f5b3e
73f5b3e
  do 
73f5b3e
    {
73f5b3e
      if (!defined ($line) || length ($line) == 0)
73f5b3e
        {
73f5b3e
          $line = <>;
73f5b3e
          return undef if !defined ($line);
73f5b3e
          chop $line;
73f5b3e
          $line_number++;
73f5b3e
          $token_number = 0;
73f5b3e
        }
73f5b3e
73f5b3e
      $line =~ s/#.*//;
73f5b3e
      $line =~ s/^\s+//;
73f5b3e
      $line =~ s/\s+$//;
73f5b3e
    }
73f5b3e
  while (length ($line) == 0);
73f5b3e
73f5b3e
  if (($token, $newline) = $line =~ /^(.*?)\s+(.*)/)
73f5b3e
    {
73f5b3e
      $line = $newline;
73f5b3e
    }
73f5b3e
  else
73f5b3e
    {
73f5b3e
      $token = $line;
73f5b3e
      $line = '';
73f5b3e
    }
73f5b3e
  $token_number++;
73f5b3e
73f5b3e
  $token =~ y/[A-Z]/[a-z]/ if $lowercase;
73f5b3e
73f5b3e
  return ($token);
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub remaining_line
73f5b3e
{
73f5b3e
  local ($tmp, $str);
73f5b3e
73f5b3e
  $str = "";
73f5b3e
  while (($tmp = next_token (0)))
73f5b3e
    {
73f5b3e
      $str .= ' ' if !($str eq "");
73f5b3e
      $str .= $tmp;
73f5b3e
      last if $tmp =~ /;\s*$/;
73f5b3e
    }
73f5b3e
73f5b3e
  $str =~ s/;$//;
73f5b3e
  return ($str);
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub
73f5b3e
add_dn_to_stack
73f5b3e
{
73f5b3e
  local ($dn) = @_;
73f5b3e
73f5b3e
  $current_dn = "$dn, $current_dn";
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub
73f5b3e
remove_dn_from_stack
73f5b3e
{
73f5b3e
  $current_dn =~ s/^.*?,\s*//;
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub
73f5b3e
parse_error
73f5b3e
{
73f5b3e
  print "Parse error on line number $line_number at token number $token_number\n";
73f5b3e
  exit (1);
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub
73f5b3e
print_entry
73f5b3e
{
73f5b3e
  return if (scalar keys %curentry == 0);
73f5b3e
73f5b3e
  if (!defined ($curentry{'type'}))
73f5b3e
    {
73f5b3e
      $host = hostname ();
73f5b3e
      $hostdn = "cn=$host, $basedn";
73f5b3e
      print "dn: $hostdn\n";
73f5b3e
      print "objectClass: top\n";
73f5b3e
      print "objectClass: dhcpServer\n";
73f5b3e
      print "cn: $host\n";
73f5b3e
      print "dhcpServiceDN: $current_dn\n\n";
73f5b3e
73f5b3e
      print "dn: $current_dn\n";
73f5b3e
      print "cn: DHCP Config\n";
73f5b3e
      print "objectClass: top\n";
73f5b3e
      print "objectClass: dhcpService\n";
73f5b3e
      if (defined ($curentry{'options'}))
73f5b3e
        {
73f5b3e
          print "objectClass: dhcpOptions\n";
73f5b3e
        }
73f5b3e
      print "dhcpPrimaryDN: $hostdn\n";
73f5b3e
    }
73f5b3e
  elsif ($curentry{'type'} eq 'subnet')
73f5b3e
    {
73f5b3e
      print "dn: $current_dn\n";
73f5b3e
      print "cn: " . $curentry{'ip'} . "\n";
73f5b3e
      print "objectClass: top\n";
73f5b3e
      print "objectClass: dhcpSubnet\n";
73f5b3e
      if (defined ($curentry{'options'}))
73f5b3e
        {
73f5b3e
          print "objectClass: dhcpOptions\n";
73f5b3e
        }
73f5b3e
      
73f5b3e
      print "dhcpNetMask: " . $curentry{'netmask'} . "\n";
73f5b3e
      if (defined ($curentry{'range'}))
73f5b3e
        {
73f5b3e
          print "dhcpRange: " . $curentry{'range'} . "\n";
73f5b3e
        }
73f5b3e
    }
73f5b3e
  elsif ($curentry{'type'} eq 'shared-network')
73f5b3e
    {
73f5b3e
      print "dn: $current_dn\n";
73f5b3e
      print "cn: " . $curentry{'descr'} . "\n";
73f5b3e
      print "objectClass: top\n";
73f5b3e
      print "objectClass: dhcpSharedNetwork\n";
73f5b3e
      if (defined ($curentry{'options'}))
73f5b3e
        {
73f5b3e
          print "objectClass: dhcpOptions\n";
73f5b3e
        }
73f5b3e
    }
73f5b3e
  elsif ($curentry{'type'} eq 'group')
73f5b3e
    {
73f5b3e
      print "dn: $current_dn\n";
73f5b3e
      print "cn: group\n";
73f5b3e
      print "objectClass: top\n";
73f5b3e
      print "objectClass: dhcpGroup\n";
73f5b3e
      if (defined ($curentry{'options'}))
73f5b3e
        {
73f5b3e
          print "objectClass: dhcpOptions\n";
73f5b3e
        }
73f5b3e
    }
73f5b3e
  elsif ($curentry{'type'} eq 'host')
73f5b3e
    {
73f5b3e
      print "dn: $current_dn\n";
73f5b3e
      print "cn: " . $curentry{'host'} . "\n";
73f5b3e
      print "objectClass: top\n";
73f5b3e
      print "objectClass: dhcpHost\n";
73f5b3e
      if (defined ($curentry{'options'}))
73f5b3e
        {
73f5b3e
          print "objectClass: dhcpOptions\n";
73f5b3e
        }
73f5b3e
73f5b3e
      if (defined ($curentry{'hwaddress'}))
73f5b3e
        {
73f5b3e
          print "dhcpHWAddress: " . $curentry{'hwaddress'} . "\n";
73f5b3e
        }
73f5b3e
    }
73f5b3e
  elsif ($curentry{'type'} eq 'pool')
73f5b3e
    {
73f5b3e
      print "dn: $current_dn\n";
73f5b3e
      print "cn: pool\n";
73f5b3e
      print "objectClass: top\n";
73f5b3e
      print "objectClass: dhcpPool\n";
73f5b3e
      if (defined ($curentry{'options'}))
73f5b3e
        {
73f5b3e
          print "objectClass: dhcpOptions\n";
73f5b3e
        }
73f5b3e
73f5b3e
      if (defined ($curentry{'range'}))
73f5b3e
        {
73f5b3e
          print "dhcpRange: " . $curentry{'range'} . "\n";
73f5b3e
        }
73f5b3e
    }
73f5b3e
  elsif ($curentry{'type'} eq 'class')
73f5b3e
    {
73f5b3e
      print "dn: $current_dn\n";
73f5b3e
      print "cn: " . $curentry{'class'} . "\n";
73f5b3e
      print "objectClass: top\n";
73f5b3e
      print "objectClass: dhcpClass\n";
73f5b3e
      if (defined ($curentry{'options'}))
73f5b3e
        {
73f5b3e
          print "objectClass: dhcpOptions\n";
73f5b3e
        }
73f5b3e
    }
73f5b3e
  elsif ($curentry{'type'} eq 'subclass')
73f5b3e
    {
73f5b3e
      print "dn: $current_dn\n";
73f5b3e
      print "cn: " . $curentry{'subclass'} . "\n";
73f5b3e
      print "objectClass: top\n";
73f5b3e
      print "objectClass: dhcpSubClass\n";
73f5b3e
      if (defined ($curentry{'options'}))
73f5b3e
        {
73f5b3e
          print "objectClass: dhcpOptions\n";
73f5b3e
        }
73f5b3e
      print "dhcpClassData: " . $curentry{'class'} . "\n";
73f5b3e
    }
73f5b3e
73f5b3e
  if (defined ($curentry{'statements'}))
73f5b3e
    {
73f5b3e
      foreach $statement (@{$curentry{'statements'}})
73f5b3e
        {
73f5b3e
          print "dhcpStatements: $statement\n";
73f5b3e
        }
73f5b3e
    }
73f5b3e
73f5b3e
  if (defined ($curentry{'options'}))
73f5b3e
    {
73f5b3e
      foreach $statement (@{$curentry{'options'}})
73f5b3e
        {
73f5b3e
          print "dhcpOption: $statement\n";
73f5b3e
        }
73f5b3e
    }
73f5b3e
73f5b3e
  print "\n";
73f5b3e
  undef (%curentry);
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub parse_netmask
73f5b3e
{
73f5b3e
  local ($netmask) = @_;
73f5b3e
  local ($i);
73f5b3e
73f5b3e
  if ((($a, $b, $c, $d) = $netmask =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) != 4)
73f5b3e
    {
73f5b3e
      parse_error ();
73f5b3e
    }
73f5b3e
73f5b3e
  $num = (($a & 0xff) << 24) |
73f5b3e
         (($b & 0xff) << 16) |
73f5b3e
         (($c & 0xff) << 8) |
73f5b3e
          ($d & 0xff);
73f5b3e
73f5b3e
  for ($i=1; $i<=32 && $num & (1 << (32 - $i)); $i++)
73f5b3e
    {
73f5b3e
    }
73f5b3e
  $i--;
73f5b3e
73f5b3e
  return ($i);
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub parse_subnet
73f5b3e
{
73f5b3e
  local ($ip, $tmp, $netmask);
73f5b3e
73f5b3e
  print_entry () if %curentry;
73f5b3e
    
73f5b3e
  $ip = next_token (0);
73f5b3e
  parse_error () if !defined ($ip);
73f5b3e
73f5b3e
  $tmp = next_token (1);
73f5b3e
  parse_error () if !defined ($tmp);
73f5b3e
  parse_error () if !($tmp eq 'netmask');
73f5b3e
73f5b3e
  $tmp = next_token (0);
73f5b3e
  parse_error () if !defined ($tmp);
73f5b3e
  $netmask = parse_netmask ($tmp);
73f5b3e
73f5b3e
  $tmp = next_token (0);
73f5b3e
  parse_error () if !defined ($tmp);
73f5b3e
  parse_error () if !($tmp eq '{');
73f5b3e
73f5b3e
  add_dn_to_stack ("cn=$ip");
73f5b3e
  $curentry{'type'} = 'subnet';
73f5b3e
  $curentry{'ip'} = $ip;
73f5b3e
  $curentry{'netmask'} = $netmask;
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub parse_shared_network
73f5b3e
{
73f5b3e
  local ($descr, $tmp);
73f5b3e
73f5b3e
  print_entry () if %curentry;
73f5b3e
73f5b3e
  $descr = next_token (0);
73f5b3e
  parse_error () if !defined ($descr);
73f5b3e
73f5b3e
  $tmp = next_token (0);
73f5b3e
  parse_error () if !defined ($tmp);
73f5b3e
  parse_error () if !($tmp eq '{');
73f5b3e
73f5b3e
  add_dn_to_stack ("cn=$descr");
73f5b3e
  $curentry{'type'} = 'shared-network';
73f5b3e
  $curentry{'descr'} = $descr;
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub parse_host
73f5b3e
{
73f5b3e
  local ($descr, $tmp);
73f5b3e
73f5b3e
  print_entry () if %curentry;
73f5b3e
73f5b3e
  $host = next_token (0);
73f5b3e
  parse_error () if !defined ($host);
73f5b3e
73f5b3e
  $tmp = next_token (0);
73f5b3e
  parse_error () if !defined ($tmp);
73f5b3e
  parse_error () if !($tmp eq '{');
73f5b3e
73f5b3e
  add_dn_to_stack ("cn=$host");
73f5b3e
  $curentry{'type'} = 'host';
73f5b3e
  $curentry{'host'} = $host;
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub parse_group
73f5b3e
{
73f5b3e
  local ($descr, $tmp);
73f5b3e
73f5b3e
  print_entry () if %curentry;
73f5b3e
73f5b3e
  $tmp = next_token (0);
73f5b3e
  parse_error () if !defined ($tmp);
73f5b3e
  parse_error () if !($tmp eq '{');
73f5b3e
73f5b3e
  add_dn_to_stack ("cn=group");
73f5b3e
  $curentry{'type'} = 'group';
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub parse_pool
73f5b3e
{
73f5b3e
  local ($descr, $tmp);
73f5b3e
73f5b3e
  print_entry () if %curentry;
73f5b3e
73f5b3e
  $tmp = next_token (0);
73f5b3e
  parse_error () if !defined ($tmp);
73f5b3e
  parse_error () if !($tmp eq '{');
73f5b3e
73f5b3e
  add_dn_to_stack ("cn=pool");
73f5b3e
  $curentry{'type'} = 'pool';
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub parse_class
73f5b3e
{
73f5b3e
  local ($descr, $tmp);
73f5b3e
73f5b3e
  print_entry () if %curentry;
73f5b3e
73f5b3e
  $class = next_token (0);
73f5b3e
  parse_error () if !defined ($class);
73f5b3e
73f5b3e
  $tmp = next_token (0);
73f5b3e
  parse_error () if !defined ($tmp);
73f5b3e
  parse_error () if !($tmp eq '{');
73f5b3e
73f5b3e
  $class =~ s/\"//g;
73f5b3e
  add_dn_to_stack ("cn=$class");
73f5b3e
  $curentry{'type'} = 'class';
73f5b3e
  $curentry{'class'} = $class;
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub parse_subclass
73f5b3e
{
73f5b3e
  local ($descr, $tmp);
73f5b3e
73f5b3e
  print_entry () if %curentry;
73f5b3e
73f5b3e
  $class = next_token (0);
73f5b3e
  parse_error () if !defined ($class);
73f5b3e
73f5b3e
  $subclass = next_token (0);
73f5b3e
  parse_error () if !defined ($subclass);
73f5b3e
73f5b3e
  $tmp = next_token (0);
73f5b3e
  parse_error () if !defined ($tmp);
73f5b3e
  parse_error () if !($tmp eq '{');
73f5b3e
73f5b3e
  add_dn_to_stack ("cn=$subclass");
73f5b3e
  $curentry{'type'} = 'subclass';
73f5b3e
  $curentry{'class'} = $class;
73f5b3e
  $curentry{'subclass'} = $subclass;
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub parse_hwaddress
73f5b3e
{
73f5b3e
  local ($type, $hw, $tmp);
73f5b3e
73f5b3e
  $type = next_token (0);
73f5b3e
  parse_error () if !defined ($type);
73f5b3e
73f5b3e
  $hw = next_token (0);
73f5b3e
  parse_error () if !defined ($hw);
73f5b3e
  $hw =~ s/;$//;
73f5b3e
73f5b3e
  $curentry{'hwaddress'} = "$type $hw";
73f5b3e
}
73f5b3e
73f5b3e
    
73f5b3e
sub parse_range
73f5b3e
{
73f5b3e
  local ($tmp, $str);
73f5b3e
73f5b3e
  $str = remaining_line ();
73f5b3e
73f5b3e
  if (!($str eq ''))
73f5b3e
    {
73f5b3e
      $str =~ s/;$//;
73f5b3e
      $curentry{'range'} = $str;
73f5b3e
    }
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
sub parse_statement
73f5b3e
{
73f5b3e
  local ($token) = shift;
73f5b3e
  local ($str);
73f5b3e
73f5b3e
  if ($token eq 'option')
73f5b3e
    {
73f5b3e
      $str = remaining_line ();
73f5b3e
      push (@{$curentry{'options'}}, $str);
73f5b3e
    }
73f5b3e
  else
73f5b3e
    {
73f5b3e
      $str = $token . " " . remaining_line ();
73f5b3e
      push (@{$curentry{'statements'}}, $str);
73f5b3e
    }
73f5b3e
}
73f5b3e
73f5b3e
73f5b3e
my $token;
73f5b3e
my $token_number = 0;
73f5b3e
my $line_number = 0;
73f5b3e
my %curentry;
73f5b3e
73f5b3e
$current_dn = "cn=DHCP Config, $basedn";
73f5b3e
$curentry{'descr'} = 'DHCP Config';
73f5b3e
$line = '';
73f5b3e
73f5b3e
while (($token = next_token (1)))
73f5b3e
  {
73f5b3e
    if ($token eq '}')
73f5b3e
      {
73f5b3e
        print_entry () if %curentry;
73f5b3e
        remove_dn_from_stack ();
73f5b3e
      }
73f5b3e
    elsif ($token eq 'subnet')
73f5b3e
      {
73f5b3e
        parse_subnet ();
73f5b3e
        next;
73f5b3e
      }
73f5b3e
    elsif ($token eq 'shared-network')
73f5b3e
      {
73f5b3e
        parse_shared_network ();
73f5b3e
        next;
73f5b3e
      }
73f5b3e
    elsif ($token eq 'class')
73f5b3e
      {
73f5b3e
        parse_class ();
73f5b3e
        next;
73f5b3e
      }
73f5b3e
    elsif ($token eq 'subclass')
73f5b3e
      {
73f5b3e
        parse_subclass ();
73f5b3e
        next;
73f5b3e
      }
73f5b3e
    elsif ($token eq 'pool')
73f5b3e
      {
73f5b3e
        parse_pool ();
73f5b3e
        next;
73f5b3e
      }
73f5b3e
    elsif ($token eq 'group')
73f5b3e
      {
73f5b3e
        parse_group ();
73f5b3e
        next;
73f5b3e
      }
73f5b3e
    elsif ($token eq 'host')
73f5b3e
      {
73f5b3e
        parse_host ();
73f5b3e
        next;
73f5b3e
      }
73f5b3e
    elsif ($token eq 'hardware')
73f5b3e
      {
73f5b3e
        parse_hwaddress ();
73f5b3e
        next;
73f5b3e
      }
73f5b3e
    elsif ($token eq 'range')
73f5b3e
      {
73f5b3e
        parse_range ();
73f5b3e
        next;
73f5b3e
      }
73f5b3e
    else
73f5b3e
      {
73f5b3e
        parse_statement ($token);
73f5b3e
        next;
73f5b3e
      }
73f5b3e
  }
73f5b3e
73f5b3e