#!/usr/bin/perl -w
# This program pulls NIS data from LDAP and writes it to map files in the same format as NIS wants them in.
# Copyright (C) 2001 JOseph Crawley joseph@coscend.com

#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; either version 2
#of the License, or (at y#our option) any later version.

#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.

#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 


use Net::LDAP;
use strict;

#change to yp conf directory probably /var/yp/conf
sub format_data {
#return data in map format
	my ($map_handle, $map_name, $map_path, @map_data) =@_; 

	my $write_line;
	my $line;
	my $i;

	print "$map_name\n";
	if ($map_name eq "passwd") {
		print "formatting for password\n";
		foreach my $line (@map_data) {
			$write_line = $write_line.$line.":";
		}
		chop($write_line);
		$write_line = $write_line."\n";
		#remove {crypt} from password entry may not happen on non netscape(iplanet) ldap server
		$write_line =~ s/{crypt}//;
		print $map_handle $write_line;
		return;
	}
	if ($map_name eq "group") {
		print "formatting for group\n";
		for($i=0; $i < 2; $i++)  {
			$write_line = $write_line.$map_data[$i].":";
		}
		for($i=2; $i < scalar(@map_data); $i++)  {
			$write_line = $write_line.$map_data[$i].",";
		}
		chop($write_line);
		$write_line = $write_line."\n";
		#remove {crypt} from password entry may not happen on non netscape(iplanet) ldap server
		$write_line =~ s/{crypt}//;
		print $map_handle $write_line;
		return;
	}
	if ($map_name eq "aliases") {
		print "formatting for aliases\n";
		$write_line = $write_line.$map_data[0].":\t\t\t";
		for($i=1; $i < scalar(@map_data); $i++)  {
			$write_line = $write_line.$map_data[$i].",";
		}
		chop($write_line);
		$write_line = $write_line."\n";
		print $map_handle $write_line;
		return;
	}
	if ($map_name eq "shadow") {
		print "formatting for shadow\n";
		foreach $line (@map_data) {
			$write_line = $write_line.$line.":";
		}
		chop($write_line);
		$write_line = $write_line."\n";
		print $map_handle $write_line;
		return;
	}
	if ($map_name eq "services") {
		print "formatting for services\n";
		$write_line = $write_line.$map_data[0].":\t\t";
		$write_line = $write_line.$map_data[1]."/";
		$write_line = $write_line.$map_data[2];
		$write_line = $write_line."\n";
		print $map_handle $write_line;
		return;
	}
	if ($map_name eq "protocols") {
		print "formatting for protocols\n";
		$write_line = $write_line.$map_data[0]."\t";
		$write_line = $write_line.$map_data[1]."\t";
		$write_line = $write_line.$map_data[2];
		$write_line = $write_line."\n";
		print $map_handle $write_line;
		return;
	}
	if ($map_name eq "rpc") {
		print "formatting for rpc\n";
		$write_line = $write_line.$map_data[0]."\t";
		$write_line = $write_line.$map_data[1]."\t";
		for($i=2; $i < scalar(@map_data); $i++)  {
			$write_line = $write_line.$map_data[$i]." ";
		}
		chop($write_line);
		$write_line = $write_line."\n";
		print $map_handle $write_line;
		return;
	}
	if ($map_name eq "hosts") {
		print "formatting for hosts\n";
		return;
	}
	if ($map_name eq "networks") {
		print "formatting for networks\n";
		return;
	}
	if ($map_name eq "netgroup") {
		print "formatting for netgroup\n";
		$write_line = $map_data[0];
		for($i=1; $i < scalar(@map_data); $i++)  {
			$write_line = $write_line." ".$map_data[$i];
		}
		$write_line = $write_line."\n";
		print $map_handle $write_line;
		return;
	}
	if ($map_name eq "mount") {
		print "formatting for mount\n";
		our $MASTER_MAP;
		if ($MASTER_MAP) {
			$MASTER_MAP = new_map_file($map_path,">auto.master");
		}
		#add all entries to master
		my $auto_name = $map_data[0];
		chop($auto_name);
		$write_line=$map_data[0]."\t"."auto.".$auto_name;
		print $MASTER_MAP $write_line;
		my $mount_options = "fstype=".$map_data[2];
		for ($i=5; $i < scalar(@map_data); $i++) {
			$mount_options = $mount_options.",".$map_data[$i];
		}
		#replace mount with * in non master entry
		$write_line = "*\t".$mount_options."\t".$map_data[1];
		print $map_handle $write_line;
		#move map to to auto.(mount point) file
		`mv $map_path."/"."$map_name $map_path."/".$auto_name`;
		
		return;
	}
}

sub new_map_file {
	my ($mpath,$mname) = @_;
	my $NEWMAP="$mpath/$mname";
	my $FD;
	open($FD, ">$NEWMAP") or die "can't open map file $NEWMAP\n";
	return $FD;
}

sub order_by_attribute {
#order list by the order of attributes in ldapmap.conf which is the order they're in the file
	my ($map_name, $sorted_attr_list, $attr_list, $items_to_sort)=@_;

	print scalar(@$sorted_attr_list),"\n";
	my $i;
	my $j;
	for ($i=0; $i < scalar(@$sorted_attr_list); $i++) {
		#print "$i\n";
		if ($sorted_attr_list->[$i] ne $attr_list->[$i]) {
			my $temp_attr = $attr_list->[$i];
			my $temp_item = $items_to_sort->[$i];
			$j=$i;
			while ($sorted_attr_list->[$i] !~ /$attr_list->[$j]/i) { $j++; }

			$attr_list->[$i] =  $attr_list->[$j];
			$items_to_sort->[$i] = $items_to_sort->[$j];
			$attr_list->[$j] = $temp_attr;
			$items_to_sort->[$j] = $temp_item; 
			#print "$j\n";
		}
	}
	if (our $DEBUG_MODE) {
		print "are these items sorted?\n";
		print "@$items_to_sort\n";
	}
}

sub open_connection_to_ldap {
	my ($server,$dn,$pass) = @_;
	my $ldap = Net::LDAP->new($server) or die "$@";
	$ldap->bind(
		dn    => $dn,
		password=>$pass);
	if (our $DEBUG_MODE) {
		print "ldap connection succeded.\n";
	}
	return $ldap;
}

sub close_connection_to_ldap {
	my ($ldap_conn) = @_;
	$ldap_conn->unbind;
	if (our $DEBUG_MODE) {
		print "ldap connection closed.\n";
	}
}

sub read_ldap_conf {
# reads ldap.conf file
#set this path in build options
	my $LDAPCONF="/u/joseph/source/nisldap/src/ldap.conf";
	open(FD, "$LDAPCONF") or die "bad ldap conf path";
	my $line;
	my @line_parts;
	my $ldap_server;
	my $base;
	my $directory_manager;
	my $dm_password;
	my $LDAPMAPCONF;
	my $NISLDAPCONF;
	my $mappath;
	foreach $line (<FD>) {
		@line_parts = split(":", $line);
		if ($line_parts[0] eq "server") {
			$ldap_server = $line_parts[1];
			chomp($ldap_server);
		}
		if ($line_parts[0] eq "searchbase") {
			$base = $line_parts[1];
			chomp($base);
		}
		if ($line_parts[0] eq "directorymanager") {
			$directory_manager = $line_parts[1];
			chomp($directory_manager);
		}
		if ($line_parts[0] eq "dmpassword") {
			$dm_password = $line_parts[1];
			chomp($dm_password);
		}
		if ($line_parts[0] eq "ldapmap") {
			$LDAPMAPCONF = $line_parts[1];
			chomp($LDAPMAPCONF);
		}
		if ($line_parts[0] eq "nisldap") {
			$NISLDAPCONF = $line_parts[1];
			chomp($NISLDAPCONF);
		}
		if ($line_parts[0] eq "mappath") {
			$mappath = $line_parts[1];
			chomp($mappath);
		}
	}
	close(FD);
	if (our $DEBUG_MODE) {
		print "$ldap_server, $base, $directory_manager, $dm_password, $LDAPMAPCONF, $NISLDAPCONF, $mappath\n";
	}
	return $ldap_server, $base, $directory_manager, $dm_password, $LDAPMAPCONF, $NISLDAPCONF, $mappath;
}

sub read_ldap_map_conf {
# reads ldapmap.conf file
	my ($LDAPMAPCONF,$what_are_we_pulling) = @_;
	my @line_parts;
	my @fields_to_pull;
	my $start_saving;
	my $line;
	my $i;
	open(FD, "$LDAPMAPCONF") or die "failed to open $LDAPMAPCONF";
	foreach $line (<FD>) {
		@line_parts = split(":", $line);
		#save this shit in an array
		if ($line_parts[0] eq $what_are_we_pulling) {
			if ($start_saving) {
				#stop saving
				$start_saving=0;	
			} else {
				#start saving
				$start_saving=1;	
				$i = 0
			}
		}
		if ($start_saving) {
			$fields_to_pull[$i] = $line_parts[1];
			$i=$i+1;
		}
	}
	close(FD);
	if (our $DEBUG_MODE) {
		print "@fields_to_pull\n";
	}
	return @fields_to_pull;
}

sub read_nisldap_conf {
#read nisldap.conf 
	my ($NISLDAPCONF) = @_;
	open(FD, "$NISLDAPCONF") or die "failed to open $NISLDAPCONF\n";
	my $line;
	my @maps_to_pull;
	foreach $line (<FD>) {
		chop($line);
		if ($line !~/#/ and $line) {
			if (our $DEBUG_MODE) {
				print "Creating map for $line\n";
			}
			push @maps_to_pull, $line;
		}
	}
	close(FD);
	return @maps_to_pull;
}

sub read_from_ldap {
#pull data in fields in array list
	my ($ldap_server, $base, $directory_manager, $dm_password, $LDAPMAPCONF, $NISLDAPCONF, $mappath) = read_ldap_conf();
	my @maps_to_pull = read_nisldap_conf($NISLDAPCONF);
	my @fields_to_pull;
	my @attrs;
	my @sorted_attr_list;
	my @array_of_data;
	my @array_of_attrs;
	my @array_of_values;
	my $what_to_pull;
	my $filter;
	my $i;
	my $attr;
	my $ldap_connection;
	my $mesg;
	my $data;
	foreach $what_to_pull (@maps_to_pull) {
		@fields_to_pull = read_ldap_map_conf($LDAPMAPCONF, $what_to_pull);
	

	$filter=$fields_to_pull[1];
	chomp($filter);
	$filter="(&(".$filter."))";

	#construct attrs list
	for ($i = 2; $i < scalar(@fields_to_pull); $i++) {
		chomp($fields_to_pull[$i]);
		push @attrs, $fields_to_pull[$i];
	}
	chomp(@attrs);
	#print @attrs,"\n";
	#$attrs=['uid','loginshell'];
	$attr = [@attrs];
	#print $attr,"\n";

	print @fields_to_pull,"\n";
	@sorted_attr_list = splice(@fields_to_pull, 2, scalar(@fields_to_pull));
	print @sorted_attr_list,"\n";
	$ldap_connection = open_connection_to_ldap($ldap_server, $directory_manager, $dm_password);
	$mesg = $ldap_connection->search ( 
                       	base   => $base,
			scope  => "sub",
                       	filter => $filter,
			attrs  => $attr
                     );

	$mesg->code && $mesg->error;
	$data = $mesg->as_struct;
	@array_of_data = keys %$data;
	foreach (@array_of_data) {
		my $valref = $$data{$_};

		# get an array of the attribute names
		# passed for this one DN.
		@array_of_attrs = sort keys %$valref; #use Attr hashes
		print @array_of_attrs,"\n";
		#@array_of_values; # = sort keys %$valref; #use Attr hashes
		#my @arrayOfAttrs = %$valref; #use Attr hashes

		my $attrName;        
		#print "@fields_to_pull\n";
		$i=0;
		foreach $attrName (@array_of_attrs) {

			# skip any binary data: yuck!
			#next if ( $attrName =~ /;binary$/ );
	
			# get the attribute value (pointer) using the
			# attribute name as the hash
			my $attrVal =  @$valref{$attrName};
			#print "\t $attrName: @$attrVal \n";
			#format_data($map_handle, $what_to_pull, $attrName, $attrVal);
			$array_of_values[$i] = @$attrVal;
			$i=$i + 1;
		}
          #print "#-------------------------------\n";
		order_by_attribute($what_to_pull, \@sorted_attr_list, \@array_of_attrs, \@array_of_values);
		print "aft",@array_of_values,"\n";
		my $OUTMAP = new_map_file($mappath, $what_to_pull);
		format_data($OUTMAP, $what_to_pull, $mappath, @array_of_values);
		close ($OUTMAP);
	}
	close_connection_to_ldap($ldap_connection);
	}
}

our $DEBUG_MODE=1;
our $MASTER_MAP;
read_from_ldap("group");


1;
