#! /usr/bin/perl5
eval 'exec perl5 -S $0 "$@"'
    if 0;


# ldif_parse
#
# Will parse name service flat files into ldif format.
# Assumes a particular schema, which can be edited by
# changing the character defines below.  A simple 
# "objectclass=organization" entry will be created at
# the top of the output file.


### general info ###

$organization	= "Your Organization Name";
$country	= "US";
$out_file 	= "nis.ldif";

$source_dir 	= "/etc";
$aliases_file 	= "$source_dir/aliases";
$ethers_file 	= "$source_dir/ethers";
$group_file 	= "$source_dir/group";
$hosts_file 	= "$source_dir/hosts";
$networks_file 	= "$source_dir/networks";
$passwd_file 	= "$source_dir/passwd";
$protocols_file = "$source_dir/protocols";
$rpc_file 	= "$source_dir/rpc";
$services_file 	= "$source_dir/services";

$SIG{CHLD} = sub { wait };

### schema info ###

# Organization

@organization_classes	= ( "top", "organization" );

# group

@group_classes 		= ( "top", "posixGroup");
$group_pswd  		= "userPassword";
$group_gid   		= "gidNumber";
$group_uid   		= "memberUid";
$group_cn		= "cn";

# ethers

@ethers_classes		= ( "top", "device", "ieee802Device" );
$ethers_address		= "macAddress";

# hosts

@hosts_classes 		= ( "top", "device", "ipHost" );
$hosts_ip     		= "ipHostNumber";
$hosts_dc     		= "cn";
$hosts_name   		= "cn";

# networks

@networks_classes  	= ( "top", "ipNetwork" );
$networks_dc	 	= "cn";
$networks_ip	 	= "ipNetworkNumber";

# protocols

@protocols_classes 	= ( "top", "ipProtocol" );
$protocols_num	 	= "ipProtocolNumber";
$protocols_cn	 	= "cn";

# services

@services_classes 	= ( "top", "ipService" );
$services_protocol 	= "ipServiceProtocol";
$services_port		= "ipServicePort";
$services_cn		= "cn";

# rpc

@rpc_classes		= ( "top", "oncRpc" );
$rpc_number		= "oncRpcNumber";
$rpc_cn			= "cn";

# passwd

@passwd_classes		= ( "top", "account", "posixAccount" );
$passwd_name		= "uid";
$passwd_pswd		= "userPassword";
$passwd_uid		= "uidNumber";
$passwd_gid		= "gidNumber";
$passwd_gecos		= "gecos";
$passwd_home		= "homeDirectory";
$passwd_shell		= "loginShell";

# aliases ===> NEED TO FIND OUT IF ALL THE OBJECT CLASSES
#              THAT USE THIS AUX HAVE THE UID ATTRIBUTE
#              ALSO WE MAY NEED TO ADD THE OBJECT CLASS OF
#              THE CLASS THAT IS USING THIS AS AUX.
#              WORKS NEED TO BE DONE BY THE ADMIN NOW.

$aliases_class		= ( "top", "mailRecipient" );
$aliases_member		= "mail";
$aliases_cn		= "cn";
$aliases_name		= "uid";


# Prints all the object classes

sub print_classes (\@$) {

	my $obj_classes_array_ptr = shift;
	my $rst = shift;

	@obj_classes_array = @$obj_classes_array_ptr;

	if ( $rst == 1 ) {

		undef %obj_classes;

	}

	# Print each object class only once 
	  
	for ( $i = $#obj_classes_array; $i >= 0; $i-- ) {

		if ($obj_classes{@obj_classes_array[$i]} != 1) {

			$obj_classes{@obj_classes_array[$i]} = 1; 
			print OUT "objectclass: @obj_classes_array[$i]\n";

	        }

	}

}

### map subroutines ###

sub ns_top {
	print OUT "dn: $base\n";
	print OUT "o: $organization\n";
	print_classes (@organization_classes,1);
}

sub ns_group {
	unless (open(IN, $group_file)) {
		print STDERR "Can't open $group_file: $!\n";
		return;
	}

	while (<IN>) {
		next if ($_ =~ /^\s*\#/ || $_ =~ /^\s*$/);
		chomp($_);

		undef $nm, $pw, $gid, $mem;
		($nm, $pw, $gid, $mem) = split(/:/);

		print OUT "\n";
		print OUT "dn: $group_cn=$nm, $base\n";
		print OUT "$group_cn: $nm\n";
		print OUT "$group_pswd: $pw\n";
		print OUT "$group_gid: $gid\n";
		
		foreach (split(/,/, $mem)) {
			print OUT "$group_uid: $_\n";
		}

		print_classes (@group_classes,1);

	}

	close(IN);
}

sub ns_hosts {
	$have_ethers = 0;
	undef %mac;

	if (open(IN, $ethers_file)) {
		while (<IN>) {
			next if ($_ =~ /^\s*\#/ || $_ =~ /^\s*$/);
			$_ = (split(/#/))[0];
			chomp($_);

			undef $mac, $net;
			($mac, $net) = split(/\s+/);
			$mac{$net} = $mac;	
		}

		close(IN);
	}

	unless (open(IN, $hosts_file)) {
		print STDERR "Can't open $hosts_file: $!\n";
		return;
	}

	while (<IN>) {
		next if ($_ =~ /^\s*\#/ || $_ =~ /^\s*$/);
		$_ = (split(/#/))[0];
		chomp($_);

		undef @data, $name;
		$mac = "";
		@data = split(/\s+/);

		$name = (split(/\./, $data[1]))[0];

		print OUT "\n";
		print OUT "dn: $hosts_name=$name, $base\n";
		print OUT "$hosts_dc: $name\n";
		
		for ($i = 1; $i <= $#data; $i++) {
			print OUT "$hosts_name: $data[$i]\n";
			if (defined($mac{$data[$i]})) { $mac = $mac{$data[$i]}; }
		}

		if ($mac ne "") { print OUT "$ethers_address: $mac\n"; }

		print OUT "$hosts_ip: $data[0]\n";

		print_classes (@hosts_classes,1);
		if ($mac != "") { print_classes (@ethers_classes,0);}

	}

	close(IN);
}		

sub ns_networks {
	unless (open(IN, $networks_file)) {
		print STDERR "Can't open $networks_file: $!\n";
		return;
	}

	while (<IN>) {
		next if ($_ =~ /^\s*\#/ || $_ =~ /^\s*$/);
		$_ = (split(/#/))[0];
		chomp($_);

		undef @data;
		@data = split(/\s+/);
		
		print OUT "\n";
		print OUT "dn: $networks_dc=$data[0], $base\n";
		print OUT "$networks_dc: $data[0]\n";
		
		for ($i = 2; $i <= $#data; $i++) {
			print OUT "$networks_dc: $data[$i]\n";
		}

		print OUT "$networks_ip: $data[1]\n";
		print_classes (@networks_classes,1);

	}

	close(IN);
}

sub ns_protocols {
	unless (open(IN, $protocols_file)) {
		print STDERR "Can't open $protocols_file: $!\n";
		return;
	}

	while (<IN>) {
		next if ($_ =~ /^\s*\#/ || $_ =~ /^\s*$/);
		$_ = (split(/#/))[0];
		chomp($_);

		undef @data;
		@data = split(/\s+/);
		
		print OUT "\n";
		print OUT "dn: $protocols_cn=$data[0], $base\n";
		print OUT "$protocols_cn: $data[0]\n";
	
		for ($i = 2; $i <= $#data; $i++) {
			print OUT "$protocols_cn: $data[$i]\n";
		}

		print OUT "$protocols_num: $data[1]\n";
		print_classes (@protocols_classes,1);	    
	}

	close(IN);
}

sub ns_services {
	unless (open(IN, $services_file)) {
		print STDERR "Can't open $services_file: $!\n";
		return;
	}

	 while (<IN>) {
		next if ($_ =~ /^\s*\#/ || $_ =~ /^\s*$/);
		$_ = (split(/#/))[0];
		chomp($_);

		undef @data, $port, $serv;
		@data = split(/\s+/);

		print OUT "\n";
		print OUT "dn: $services_cn=$data[0], $base\n";
		print OUT "$services_cn: $data[0]\n";
	
		for ($i = 2; $i <= $#data; $i++) {
			print OUT "$services_cn: $data[$i]\n";
		}

		($port, $serv) = split(/\//, $data[1]);
		print OUT "$services_port: $port\n";
		print OUT "$services_protocol: $serv\n";
		print_classes (@services_classes,1);	    
	}

	close(IN);
}

sub ns_rpc {
	unless (open(IN, $rpc_file)) {
		print STDERR "Can't open $rpc_file: $!\n";
		return;
	}

	while (<IN>) {
		next if ($_ =~ /^\s*\#/ || $_ =~ /^\s*$/);
		$_ = (split(/#/))[0];
		chomp($_);

		undef @data;
		@data = split(/\s+/);

		print OUT "\n";
		print OUT "dn: $rpc_cn=$data[0], $base\n";
		print OUT "$rpc_cn: $data[0]\n";

		for ($i = 2; $i <= $#data; $i++) {
			print OUT "$rpc_cn: $data[$i]\n";
		}

		print OUT "$rpc_number: $data[1]\n";
		print_classes (@rpc_classes,1);	    

	}

	close(IN);
}

sub ns_passwd {
	unless (open(IN, $passwd_file)) {
		print STDERR "Can't open $passwd_file: $!\n";
		return;
	}

	while (<IN>) {
		next if ($_ =~ /^\s*\#/ || $_ =~ /^\s*$/);
		chomp($_);

		undef @data;
		@data = split(/:/);

		print OUT "\n";
		print OUT "dn: $passwd_name=$data[0], $base\n";
		print OUT "$passwd_name: $data[0]\n";
		print OUT "$passwd_pswd: $data[1]\n";
		print OUT "$passwd_uid: $data[2]\n";
		print OUT "$passwd_gid: $data[3]\n";
		print OUT "$passwd_gecos: $data[4]\n";
		print OUT "$passwd_home: $data[5]\n";
		print OUT "$passwd_shell: $data[6]\n";
		print_classes (@passwd_classes,1);	    
	}

	close(IN);
}

sub ns_aliases {
	unless (open(IN, $aliases_file)) {
		print STDERR "Can't open $aliases_file: $!\n";
		return;
	}

	while (<IN>) {
		next if ($_ =~ /^\s*\#/ || $_ =~ /^\s*$/);
		chomp($_);

		undef $name, $members, @members;
		($name, $members) = split(/\s*:\s*/);
		@members = split(/\s*,\s*/, $members);

		print OUT "\n";
		print OUT "dn: $aliases_name=$name, $base\n";
		print OUT "$aliases_name: $name\n";
		
		foreach (@members) {
			print OUT "$aliases_member: $_\n";
		}

		print_classes (@aliases_classes,1);

	}
}

sub usage {
	print "usage: ldif_parse [-s <source directory>] [-d <destination "
		. "file>]\n\t[-o <organization>] [-c <country>] [maps...]\n";
	exit(1);
}


### begin execution ###

while ($arg = shift(@ARGV)) {
	if ($arg eq "-s") {
		$ns_dir = $source_dir = shift(@ARGV);
	}
	elsif ($arg eq "-d") {
		$out_file = shift(@ARGV);
	}
	elsif ($arg eq "-o") {
		$organization = shift(@ARGV);
	}
	elsif ($arg eq "-c") {
		$country = shift(@ARGV);
	}
	elsif ($arg eq "-h") {
		&usage;
	}
	else {
		push(@maps, $arg);
	}
}

$base = "o=$organization, c=$country";

unless (open(OUT, "> $out_file")) {
	print STDERR "Can't open $out_file: $!\n";
	exit(1);
}

ns_top();

if ($#maps < 0) {
	ns_group();
	ns_hosts();
	ns_networks();
	ns_passwd();
	ns_protocols();
	ns_rpc();
	ns_services();
	exit(0);
}

for (@maps) {
	if (/^group/i) {
		ns_group();
	} elsif (/^host/i) {
		ns_hosts();
	} elsif (/^network/i) {
		ns_networks();
	} elsif (/^passw/i) {
		ns_passwd();
	} elsif (/^protocol/i) {
		ns_protocols();
	} elsif (/^rpc/i) {
		ns_rpc();
	} elsif (/^service/i) {
		ns_services();
	} elsif (/^aliases/i) {
		ns_aliases();
	} else {
		print STDERR "Do not know how to parse map: $_";
	}
}

close(OUT);
