# STTA Rev. 1.3 Copyright (c) Jesús Pérez Lorenzo  --- license GNU GPL 
# stta: (@#) 1.3pre1049295437- [2003_4_02_165717]
# Vers 1.3 Moving to perl-LDAP  NET:LDAP available in CPAN  giving up Mozilla::LDAP 
# LDAP Library  + PerLDAP stuff

$conn = "";
$conncache = "";
$conncache2 = "";
$ldapcache_notdie=0;
$ldap_notdie=0;
%ldapObjHash=();
@ldapObjArr=();

use Net::LDAP;
use Net::LDAP::Util qw(ldap_error_name ldap_error_text);

sub dieLdap {
    if ( $debug gt 0 ) { $err_msg=$_; }
    &ldap_logerr($text{ldap_connerr}); 
    &footHere; exit  
}

sub connect
{
   if ( "$ldap_server" eq "1" ) {
         $line_conn=$config{ldap_server}.":".$config {ldap_port};
         if ( $ldap_notdie eq "1" ) {
               $ldapObj = Net::LDAP->new($config{ldap_server},
                                     port => $config{ldap_port}) or return;
         } else {
               $ldapObj = Net::LDAP->new($config{ldap_server},
                                     port => $config{ldap_port}) or dieLdap "$@";
         }
         $conn = $ldapObj->bind("$config{ldap_user}",
                 password => "$config{ldap_passwd}",
                 version => $config{ldap_version} );    
         $config{LDAP_type}=$config{ldap_type};
   } elsif ( "$ldap_server" eq "2" ) {
         $line_conn=$config{ldap2_server}.":".$config {ldap2_port};
         $ldapObj = Net::LDAP->new($config{ldap2_server},
                                   port => $config{ldap2_port}) or dieLdap "$@";
         $conn = $ldapObj->bind("$config{ldap2_user}",
                 password => "$config{ldap2_passwd}",
                 version => $config{ldap2_version} );    
         $config{LDAP_type}=$config{ldap2_type};
   } else {
        print "LDAP: $ldap_server \n";
        &footHere; exit  
   }
   if ( $conn->code ) {
        $errstr = $conn->code;
        $err=$text{ldap_conerr}." ".&ldap_error_text($errstr);
        &ldap_logerr("connect: $errstr\n $err"); 
        if ( $ldap_notdie eq "1" ) { return };
        &footHere; exit  
   }
}

sub dieLdapcache {
    if ( $debug gt 0 ) { $err_msg=$_; }
    &ldapcache_logerr($text{ldap_connerr}); 
    &footCacheHere; exit  
}

sub connect_cache
{
   if ( "$ldapcache_server" eq "1" ) {
         $line_conn=$config{ldapcache_server}.":".$config {ldapcache_port};
         if ( $ldapcache_notdie eq "1" ) {
              $ldapcacheObj = Net::LDAP->new($config{ldapcache_server},
                            port => $config{ldapcache_port}) or return;
         } else {
              $ldapcacheObj = Net::LDAP->new($config{ldapcache_server},
                            port => $config{ldapcache_port}) or dieLdapcache "$@";
         }
         $conncache = $ldapcacheObj->bind("$config{ldapcache_user}",
                 password => "$config{ldapcache_passwd}",
                 version => $config{ldapcache_version} );    
         $config{LDAP_type}=$config{ldapcache_type};
   } elsif ( "$ldapcache_server" eq "2" ) {
         $line_conn=$config{ldapcache2_server}.":".$config {ldapcache2_port};
         $ldapcacheObj = Net::LDAP->new($config{ldapcache2_server},
                                   port => $config{ldapcache2_port}) or dieLdapcache "$@";
         $conncache = $ldapcacheObj->bind("$config{ldapcache2_user}",
                 password => "$config{ldapcache2_passwd}",
                 version => $config{ldapcache2_version} );    
         $config{LDAP_type}=$config{ldapcache2_type};
   } else {
        print "LDAP: $ldap_server \n";
        &footHere; exit  
   }
   if ( $conncache->code ) {
        $errstr = $conncache->code;
        $err=$text{ldap_conerr}." ".&ldap_error_text($errstr);
        &ldapcache_logerr("connect: $errstr\n $err"); 
        if ( $ldapcache_notdie eq "1" ) { return };
        &footCacheHere; exit  
   }
}

# add_cache_ou ($tta3tier)
# following $tta3tier->{ObjType}[0] ( usr | ou | app | grpapps | host | grphosts | domain ) 
# add  obj  as OU 
# in ldapcache_base" as DN   
# returning $status_con as ( 0=OK, -1 = error, -2 = missing elements )
#
sub add_cache_ou
{
  	local (%obj) = @_;
	my ($status_con,$dn,$ouname,$entryObj);
        my $ou_target=$obj->{target};
        $ou_target=~s/^ou=//g;
        %ldapObjHash=();
        @ldapObjArr=();

	$status_con = 0;
        $err="";
    	if (!$obj->{target}) { return -2 };
        $objdescrip=&scan_objdescrip(0,\%$obj);
  	if ($objdescrip eq "" ) { $objdescrip= "organization"};
    	$dn = $obj->{target}.",".$config{ldapcache_base};

        @ldapObjArr=();
        push (@ldapObjArr,'ou',$ou_target);
        push (@ldapObjArr,'objectclass',["top", "organizationalUnit"]);
        push (@ldapObjArr,'description',$objdescrip);
        %ldapObjHash=@ldapObjArr;
        $conncache = $ldapcacheObj->add ($dn,attr => [ @ldapObjArr ]);
        if ( $err = $conncache->code ) { $status_con=-1; }; 
        $dn_cache=$dn;
        &ldapcache_logerr("add ou"); 
        return $status_con;
}

# cache_obj($tta3tier)
# following $tta3tier->{action} ( add or mod ) 
# add or update  $tta3tier->{origin} 
# in $tta3tier->{target},"ldapcache_base" as DN for the OU  
# returning $status_con as ( 0=OK, -1 = error, -2 = missing elements )
#
sub cache_obj
{
  	my (%tta3tier) = @_;
  	local (%obj) = @_;
	my ($status_con,$objtype,$dn,$ou,$dn_t,$entry);
        my (@lista_targets) = ($tta3tier->{target},$tta3tier->{oudn});
        local (@dn_lin);
        my ($dntarget,$elem,$lnum,$dn_t,$entryObj);
        %ldapObjHash=();
        @ldapObjArr=();

	$status_con = 0;
    	if (!$tta3tier->{origin} ||  !$tta3tier->{target} ) { return -2 };

        if ( $tta3tier->{action} ne "add" && $tta3tier->{action} ne "mod" ) { return -2 };
    	if ( $tta3tier->{oudn} eq "default" ) {
    	     $dn_t = $tta3tier->{target};
        } else {
    	     $dn_t = $tta3tier->{oudn}.",".$tta3tier->{target};
        }
    	$dn = $tta3tier->{origin}.",".$dn_t.",".$config{ldapcache_base};
        $objtype=$tta3tier->{objetype};
        if ( $tta3tier->{action} eq "add" ) {
                # scanning for target .... and full_target
                $objtype=$tta3tier->{objetype};
                $dn_t = $config{ldapcache_base};
                foreach $elem (@lista_targets) {
    	           next if ( "$elem" eq "default" ); 
                   @dn_lin = split(/,/, $elem);
                   for ( $lnum= $#dn_lin ; $lnum >= 0 ; $lnum-- ) {
#    	                 next if ( "$dn_lin[$lnum]" ne "default" ); 
   	                 $ou=$dn_lin[$lnum];
    	                 $dn_t = $ou.",".$dn_t;
	                 $dntarget=&sel_cache_obj($dn_t,"ou=*");
                         next if (defined($dntarget)) ; 
                         $objdescrip=&scan_objdescrip(2,$objtype,$dn_t,$tta3tier->{target});
                         @ldapObjArr=();
                         if ($objdescrip eq "" ) { $objdescrip= "organization"};
                         $ou_target=$ou;
                         $ou_target=~s/^ou=//g;
                         push (@ldapObjArr,'ou',$ou_target);
                         push (@ldapObjArr,'objectclass',["top", "organizationalUnit"]);
                         push (@ldapObjArr,'description',$objdescrip);
                         %ldapObjHash=@ldapObjArr;
                         $conncache = $ldapcacheObj->add ($dn_t,attr => [ @ldapObjArr ]);
                         if ( $err = $conncache->code ) { $status_con=-1; }; 
                         $dn_cache=$dn_t;
                         &ldapcache_logerr("add ou $dn_t"); 
                         if ($status_con ne 0 ) { return -2 };
                   }
                   if ($status_con ne 0 ) { return -2 };
                   $objtype="ou";
                }
                if ( $tta3tier->{login}.length gt 0 ) {                          
                     # Redy to go
                     $dn_cache=$dn;
                     @ldapObjArr=();
                     push (@ldapObjArr,'cn',$tta3tier->{origin});
                     push (@ldapObjArr,'objectclass',["ttacacheapp"]);
                     %ldapObjHash=@ldapObjArr;
                     $conncache = $ldapcacheObj->add ( $dn, attr => [ @ldapObjArr ] );
                }
        } elsif ( $tta3tier->{action} eq "mod" ) {
                $dn_cache=$dn;
	        $entryObj=&sel_cache_obj($dn,"cn=*");
                if ( !defined($entryObj) ) {
                    &ldapcache_logerr("browse obj");       
		    return -1;
    		}
        }
        local $origin=$tta3tier->{origin};
        $origin=~s/cn=//g;
        @ldapObjArr=();
        push (@ldapObjArr,'cn',$origin);
        if ($tta3tier->{oudn} ) { push (@ldapObjArr,'tta3tieroudn',$tta3tier->{oudn});}
        if ($tta3tier->{title} ) { push (@ldapObjArr,'tta3tiertitle',$tta3tier->{title});}
        if ($tta3tier->{login} ) { push (@ldapObjArr,'tta3tierlogin',$tta3tier->{login});}
        if ($tta3tier->{password} ) { push (@ldapObjArr,'tta3tierpassword',$tta3tier->{password});}
        if ($tta3tier->{domain} ) { push (@ldapObjArr,'tta3tierdomain',$tta3tier->{domain});}
        if ($tta3tier->{stringcmd} ) { push (@ldapObjArr,'tta3tierstringcmd',$tta3tier->{stringcmd});}
        if ($tta3tier->{appkey1} ) { push (@ldapObjArr,'tta3tierappkey1',$tta3tier->{appkey1});}
        if ($tta3tier->{appkey2} ) { push (@ldapObjArr,'tta3tierappkey2',$tta3tier->{appkey2});}
        if ($tta3tier->{appkey3} ) { push (@ldapObjArr,'tta3tierappkey3',$tta3tier->{appkey3});}
        if ($tta3tier->{appkey4} ) { push (@ldapObjArr,'tta3tierappkey4',$tta3tier->{appkey4});}
        if ($tta3tier->{appkey5} ) { push (@ldapObjArr,'tta3tierappkey5',$tta3tier->{appkey5});}
        if ($tta3tier->{appkey6} ) { push (@ldapObjArr,'tta3tierappkey6',$tta3tier->{appkey6});}
        if ($tta3tier->{maxsess} ne ""  ) { push (@ldapObjArr,'tta3tiermaxsess',$tta3tier->{maxsess});}
        if ($tta3tier->{ticketstatus} ) { push (@ldapObjArr,'tta3tierticketstatus',$tta3tier->{ticketstatus});}
        if ($tta3tier->{ticketcounter} ) { push (@ldapObjArr,'tta3tierticketcounter',$tta3tier->{ticketcounter});}
        if ($tta3tier->{endticket} ) { push (@ldapObjArr,'tta3tierendticket',$tta3tier->{endticket});}
        if ($tta3tier->{doifendticket} ) { push (@ldapObjArr,'tta3tierdoifendticket',$tta3tier->{doifendticket});}
        if ( $tta3tier->{action} eq "add" && $tta3tier->{login}.length gt 0 ) {
             push (@ldapObjArr,'objectclass',["ttacacheapp"]);
             %ldapObjHash=@ldapObjArr;
             $conncache = $ldapcacheObj->add ( $dn, attr => [ @ldapObjArr ] );
             if ( $err = $conncache->code ) { $status_con=-1; }; 
             &ldapcache_logerr("add obj"); 
        } elsif ( $tta3tier->{action} eq "mod" && $tta3tier->{login}.length gt 0 ) { 
             %ldapObjHash=@ldapObjArr;
             $conncache = $ldapcacheObj->modify ( $dn, changes => [ replace => [ @ldapObjArr ]]);
             if ( $err = $conncache->code ) { $status_con=-1; }; 
             &ldapcache_logerr("update obj"); 
        };
        if ( $debug gt 4 )  {   &print_tta3tier(\%$tta3tier);  }  # debugging development trace 
        return $status_con;
}

sub del_cache_tree
{
   my ( $conncache, $entry) = @_;
   my ($status_con,$dn_cn);
   %ldapObjHash=();
   @ldapObjArr=();

   if ( !defined($entry) ) {
          return; 
   }
   if ($conncache->count == 0) {  return; }
   my $dn_cn = $entry->dn; 
   $conncache = $ldapcacheObj->delete ( $dn_cn );
#   &ldapcache_logerr("delete obj");    # Too many lines to logs !!!
#   $conncache->pop_entry;              # Does not work, probably for last entry or for deletes
}

sub del_cache_obj
{
    my ($dn) = @_;
    my ($status_con,$dn_cn);
    %ldapObjHash=();
    @ldapObjArr=();
 
    $status_con = 0;
    # scanning for subentries "cn" in $dn 
    $status_con = $ldapcacheObj->search ( base => $dn,
				       scope => "sub",
				       filter => "(cn=*)",
                                       callback => \&del_cache_tree, 
                                      );
    $dn_cache=$dn;
    $conncache = $ldapcacheObj->delete ( $dn );
    if ( $err = $conncache->code ) { $status_con=-1; }; 
    &ldapcache_logerr("delete obj"); 
    return $status_con;
}

sub del_cache_ou
{
    my ($dn) = @_;
    my ($status_con,$dn_cn);
    %ldapObjHash=();
    @ldapObjArr=();
 
    $status_con = 0;
    # scanning for subentries "cn" in $dn 
    $conncache = $ldapcacheObj->search ( base => $dn,
				       scope => "sub",
				       filter => "(cn=*)",
                                       callback => \&del_cache_tree, 
                                      );
    $conncache = $ldapcacheObj->search ( base => $dn,
				       scope => "sub",
				       filter => "(ou=*)",
                                       callback => \&del_cache_tree, 
                                      );
#    $conncache = $ldapcacheObj->delete ( $dn );
#    if ( $err = $conncache->code ) { $status_con=-1; }; 
    $dn_cache=$dn;
    &ldapcache_logerr("delete tree obj"); 
    return $status_con;
}

sub del_ldap_obj
{
    local ($status_ldap);
    %ldapObjHash=();
    @ldapObjArr=();
 
    $status_ldap=0;
    if ( &del_cache_ou($dn) eq 0 ) {
         if ( $config{ldapcache2_server}.length gt 0 ) {
              $ldapcache_server=2;
              &connect_cache ();
              if (&del_cache_ou($dn) ne 0 ) {
                  &err_replication();
                  $status_ldap=1;
              }
         }
    } else {
      $status_ldap=1;
    }
  return $status_ldap;
}

sub del_obj
{
     my ($status_con);
     $status_con = 0;
     %ldapObjHash=();
     @ldapObjArr=();
   
     $dn_cache=$dn;
     $conncache = $ldapcacheObj->search ( base => $dn,
				       scope => "sub",
				       filter => "(cn=*)",
                                       callback => \&del_cache_tree, 
                                      );
     if ( $err = $conncache->code ) { 
            if ( $debug gt 0 ) {
                 if ( !$DebugFile ) {
                       print "<hr>\n";
                       print "<b> del ($dn): $err:".ldap_error_text($err)."</b>\n";
                       print "<hr>\n";
                 } else {
                       print DebugFile "del ($dn): $err:".ldap_error_text($err)."\n";
                 }
            }
            $status_con=-1;
            &webmin_log("ldap-cache", "browse", $dn, $err);
            &ldapcache_logerr("browse obj"); 
     }
     return $status_con;
}

sub mod_obj
{
     my ($status_con);
     $status_con = 0;
     %ldapObjHash=();
     @ldapObjArr=();
 
     $dn_cache=$dn;
     my $cur_entry=&sel_cache_obj($dn_cache,"cn=*");
     if ( !defined($cur_entry) || $cur_entry->dn ne $dn_cache ) {
            $status_con=-1;
            &ldapcache_logerr("browse obj"); 
     } else {
	if ( $in{tta3tier_domain}) {push (@ldapObjArr,'tta3tierdomain',$in{tta3tier_domain}); }
	if ( $in{tta3tier_login}) {push (@ldapObjArr,'tta3tierlogin',$in{tta3tier_login}); }
	if ( $passwdcoded ) {push (@ldapObjArr,'tta3tierpassword',$passwdcoded); }
	if ( $in{tta3tier_stringcmd }) {push (@ldapObjArr,'tta3tierstringcmd',$in{tta3tier_stringcmd}); }
	if ( $in{tta3tier_title}) {push (@ldapObjArr,'tta3tiertitle',$in{tta3tier_title}); }
	if ( $in{tta3tier_oudn}) {push (@ldapObjArr,'tta3tieroudn',$in{tta3tier_oudn}); }
	if ( $in{tta3tier_appkey1}) {push (@ldapObjArr,'tta3tierappkey1',$in{tta3tier_appkey1});}
	if ( $in{tta3tier_appkey2}) {push (@ldapObjArr,'tta3tierappkey2',$in{tta3tier_appkey2});}
	if ( $in{tta3tier_appkey3}) {push (@ldapObjArr,'tta3tierappkey3',$in{tta3tier_appkey3}); }
	if ( $in{tta3tier_appkey4}) {push (@ldapObjArr,'tta3tierappkey4',$in{tta3tier_appkey4}); }
	if ( $in{tta3tier_appkey5}) {push (@ldapObjArr,'tta3tierappkey5',$in{tta3tier_appkey5}); }
	if ( $in{tta3tier_appkey6}) {push (@ldapObjArr,'tta3tierappkey6',$in{tta3tier_appkey6}); }
	if ( $in{tta3tier_massess} ne "" ) {push (@ldapObjArr,'tta3tiermaxsess',$in{tta3tier_maxsess}); }
	if ( $in{tta3tier_ticketstatus}) {push (@ldapObjArr,'tta3tierticketstatus',$in{tta3tier_ticketstatus}); }
	if ( $in{tta3tier_ticketcounter}) {push (@ldapObjArr,'tta3tierticketcounter',$in{tta3tier_ticketcounter}); }
	if ( $in{tta3tier_endticket}) {push (@ldapObjArr,'tta3tierendticket',$in{tta3tier_endticket}); }
	if ( $in{tta3tier_doifendticket}) {push (@ldapObjArr,'tta3tierdoifendticket',$in{tta3tier_doifendticket}); }
        %ldapObjHash=@ldapObjArr;
        $conncache = $ldapcacheObj->modify ( $dn, changes => [ replace => [ @ldapObjArr ]]);
        if ( $err = $conncache->code ) { $status_con=-1; }; 
        &ldapcache_logerr("update obj"); 
     }
     return $status_con;
}

sub get_cache_obj
{
    # This is to return a hash &cacheObj with all values of the $dn entry 
    my ( $dn, $cur_entry) = @_;
    local %cacheObj=();
    %ldapObjHash=();
    @ldapObjArr=();

    if ( !defined($cur_entry) || $cur_entry->dn eq $dn ) {     # just to be sure 
         local @attrs = $cur_entry->attributes;
         foreach my $var (@attrs) {
             $attr = $cur_entry->get_value( $var, asref => 1 );
             if ( defined($attr) ) {
                  foreach my $value (@$attr) { 
                         $cacheObj{$var} = $value; }
             }
         }
    }
    %ldapObjHash=%entryObj;
    &ldapcache_logerr("browse $dn");
    return %cacheObj;
}

sub sel_cache_obj
{
    my ($dn,$filter) = @_;
    %ldapObjHash=();
    @ldapObjArr=();
    $conncache = $ldapcacheObj->search ( base => $dn, 
                                         scope => "sub", 
                                         filter => "($filter)");
    if ( $err = $conncache->code ||  $conncache->count eq 0 ) { 
         &ldapcache_logerr("browse $dn");
         return undef
    };
    return $conncache->entry(0);
}

sub mvcp_cache_tree
{
   my ( $conncache, $entry) = @_;

   if ( !defined($entry) ) { return; }
   push (@main::dncursor, $entry->dn);
}

sub mvcp_cache_obj 
{
 my ($task,$dn,$newdn,$objtype) = @_;
 @main::dncursor=();
 my ($status_con);
 $status_con = 0;
 $dnfull = $dn.",$config{ldapcache_base}";
 local %cacheObj=();
 %ldapObjHash=();
 @ldapObjArr=();
 my $dn_t="";
 $grp_dn=$dn;
 
 print "<p></center>";
 $conncache = $ldapcacheObj->search ( base => $dnfull,
				       scope => "sub",
				       filter => "(cn=*)",
                                       callback => \&mvcp_cache_tree, 
                                      );
 if ( $err = $conncache->code ||  $conncache->count eq 0 ) { 
      $dn_cache=$dnfull;
      &ldapcache_logerr("browse mvcp cursor"); 
      return $err;
 }
 foreach my $currdn (@main::dncursor) {
      $dn_cache=$currdn;
      # Scanning to make OU at new DN ...
      @linedn=split(/,/,$currdn);
      my $newbasedn=$currdn;
      $newbasedn=~ s/^$linedn[0],//;
      $newbasedn=~ s/,$grp_dn,$config{ldapcache_base}$//g;
      $newbasedn=~ s/$grp_dn,$config{ldapcache_base}$//g;
      if ( $newbasedn ne "" ) { $newbasedn .= ","; }
      $newbasedn .= $newdn;
      my @dn_lin = split(/,/, $newbasedn);
      $dn_t = $config{ldapcache_base};
      for ( $lnum=$#dn_lin ; $lnum >= 0 ; $lnum-- ) {
           next if ( $dn_lin[$lnum] eq "" ); 
	   $dn_t=$dn_lin[$lnum].",".$dn_t;
	   my $dntarget=&sel_cache_obj($dn_t,"ou=*");
           next if (defined($dntarget)) ; 
           if ( $config{debug_code} gt 3 ) {
                print "DN to make: $dn_t <br>";
           }
           my $ou=$dn_lin[$lnum];
           $ou=~ s/^ou=//g;
           @ldapObjArr=();
           push (@ldapObjArr,'ou',$ou);
           push (@ldapObjArr,'objectclass',["top", "organizationalUnit"]);
           push (@ldapObjArr,'description',"organization");
           %ldapObjHash=@ldapObjArr;
           $conncache = $ldapcacheObj->add ($dn_t,attr => [ @ldapObjArr ]);
           if ( $err = $conncache->code ) { $status_con=-1; }; 
           $dn=$dn_t;
           &ldapcache_logerr("add ou $dn_t"); 
           if ($status_con ne 0 ) { return -2 };
      }
      $linedn[0]=~s/cn=//g;
      @ldapObjArr=();
      push (@ldapObjArr,'cn',$linedn[0]);
      # Loadding DN attributes & values ....
      my $cur_entry=&sel_cache_obj($currdn,"cn=*");
      next if ( !defined($cur_entry) );
      %cacheObj=&get_cache_obj($currdn,$cur_entry);
      push (@ldapObjArr,'tta3tieroudn',$cacheObj{tta3tieroudn});
      push (@ldapObjArr,'tta3tiertitle',$cacheObj{tta3tiertitle});
      push (@ldapObjArr,'tta3tierlogin',$cacheObj{tta3tierlogin});
      push (@ldapObjArr,'tta3tierpassword',$cacheObj{tta3tierpassword});
      push (@ldapObjArr,'tta3tierdomain',$cacheObj{tta3tierdomain});
      push (@ldapObjArr,'tta3tierstringcmd',$cacheObj{tta3tierstringcmd});
      push (@ldapObjArr,'tta3tierappkey1',$cacheObj{tta3tierappkey1});
      push (@ldapObjArr,'tta3tierappkey2',$cacheObj{tta3tierappkey2});
      push (@ldapObjArr,'tta3tierappkey3',$cacheObj{tta3tierappkey3});
      push (@ldapObjArr,'tta3tierappkey4',$cacheObj{tta3tierappkey4});
      push (@ldapObjArr,'tta3tierappkey5',$cacheObj{tta3tierappkey5});
      push (@ldapObjArr,'tta3tierappkey6',$cacheObj{tta3tierappkey6});
      push (@ldapObjArr,'tta3tiermaxsess',$cacheObj{tta3tiermaxsess});
      push (@ldapObjArr,'tta3tierticketstatus',$cacheObj{tta3tierticketstatus});
      push (@ldapObjArr,'tta3tierticketcounter',$cacheObj{tta3tierticketcounter});
      push (@ldapObjArr,'tta3tierendticket',$cacheObj{tta3tierendticket});
      push (@ldapObjArr,'tta3tierdoifendticket',$cacheObj{tta3tierdoifendticket});
      push (@ldapObjArr,'objectclass',["ttacacheapp"]);
      %ldapObjHash=@ldapObjArr;
      $dn_t= $currdn;
      $dn_t=~ s/,$grp_dn,$config{ldapcache_base}$//g;
      $dn_t .= ",".$newdn.",".$config{ldapcache_base};
      $status_con=0;
      $dn_cache=$dn_t;
      $conncache = $ldapcacheObj->add ( $dn_t, attr => [ @ldapObjArr ] );
      if ( $err = $conncache->code ) { $status_con=-1; }; 
      print "<tr><td>($err) - ".$text{'msg_processing'}."<b> ".$linedn[0]."</b> ->  ".$newdn."</tr>\n";
      &ldapcache_logerr("add obj"); 
      if ( $status_con eq "0" && $task eq "move" ) {
           $conncache = $ldapcacheObj->delete ($currdn );
      }
 }
 if ( $task eq "move" && $status_con eq 0 ) { 
      if ( $objtype eq "grpapps" || $objtype eq "grphosts" ) {  &del_cache_ou($dnfull); }
 }
 return $status_con;
}

sub mvcp_ldap_tree
{
   my ( $conn, $entry) = @_;

   if ( !defined($entry) ) { return; }
   if ($conn->count == 0) {  return; }
   push (@main::dncursor, $entry->dn);

}

sub mvcp_ldap_obj 
{
 my ($task,$ou_dn,$newdn,$objtype) = @_;
 my ($status_con);
 %ldapObjHash=();
 @ldapObjArr=();
 %objLdap=();
 @main::dncursor=();
 $status_con = 0;
 $grp_dn=$ou_dn;
 $ou_dnfull = $ou_dn.",$config{ldap_base}";

  my @line=split(/,/,$ou_dn);
  $conn = $ldapObj->search ( base => $ou_dnfull,
			       scope => "sub",
			       filter => "(cn=*)",
                               callback => \&mvcp_ldap_tree, 
                              );
 if ( $err = $conn->code ||  $conn->count eq 0 ) { 
      $dn=$ou_dnfull;
      &ldap_logerr("browse mvcp cursor"); 
      return $err;
 }
 foreach my $currdn (@main::dncursor) {
      $dn=$currdn;
      # Scanning to make OU at new DN ...
      @linedn=split(/,/,$currdn);
      my $newbasedn=$currdn;
      $newbasedn=~ s/^$linedn[0],//;
      $newbasedn=~ s/,$grp_dn,$config{ldap_base}$//g;
      $newbasedn=~ s/$grp_dn,$config{ldap_base}$//g;
      if ( $newbasedn ne "" ) { $newbasedn .= ","; }
      $newbasedn .= $newdn;
      if ( $objtype eq "users" ) { $newbasedn=~ s/^$linedn[0],//; }
      my @dn_lin = split(/,/, $newbasedn);
      $dn_t = $config{ldap_base};
      for ( $lnum=$#dn_lin ; $lnum >= 0 ; $lnum-- ) {
           next if ( $dn_lin[$lnum] eq "" ); 
	   $dn_t=$dn_lin[$lnum].",".$dn_t;
	   my $dntarget=&sel_ldap_obj($dn_t,"ou=*");
           next if (defined($dntarget)) ; 
           if ( $config{debug_code} gt 3 ) {
                print "DN to make: $dn_t <br>";
           }
           my $ou=$dn_lin[$lnum];
           $ou=~ s/^ou=//g;
           @ldapObjArr=();
           push (@ldapObjArr,'ou',$ou);
           push (@ldapObjArr,'objectclass',["top", "organizationalUnit"]);
           push (@ldapObjArr,'description',"organization");
           %ldapObjHash=@ldapObjArr;
           $conn = $ldapObj->add ($dn_t,attr => [ @ldapObjArr ]);
           if ( $err = $conn->code ) { $status_con=-1; }; 
           $dn=$dn_t;
           &ldap_logerr("add ou $dn_t"); 
           if ($status_con ne 0 ) { return -2 };
      }
      # Loadding DN attributes & values ....
      my $cur_entry=&sel_ldap_obj($currdn,"cn=*");
      next if ( !defined($cur_entry) );
      %objLdap=&get_ldap_obj($currdn,$cur_entry);
      @ldapObjArr=();
      push (@ldapObjArr,'sn',$objLdap{sn});
      push (@ldapObjArr,'cn',$objLdap{cn});
      push (@ldapObjArr,'userpassword',$objLdap{userpassword});
      push (@ldapObjArr,'uid',$objLdap{uid});
      push (@ldapObjArr,'mail',$objLdap{mail}); 
      push (@ldapObjArr,'description',$objLdap{description});
      push (@ldapObjArr,'displayname',$objLdap{displayname}); 
      push (@ldapObjArr,'objectClass',["top", "person", "organizationalperson", "inetorgperson"]);
      %ldapObjHash=@ldapObjArr;
      $dn_t= $currdn;
      $dn_t=~ s/,$grp_dn,$config{ldap_base}$//g;
      $dn_t=~ s/$grp_dn,$config{ldap_base}$//g;
      if ( $dn_t ne "" ) { $dn_t .= "," };
      $dn_t .= $newdn.",".$config{ldap_base};
      $dn=$dn_t;
      $status_con=0;
      $conn = $ldapObj->add ( $dn_t, attr => [ @ldapObjArr ] );
      if ( $err = $conn->code ) { $status_con=-1; }; 
      print "<tr><td>($err) - ".$text{'msg_processing'}."<b> ".$linedn[0]."</b> ->  ".$newdn."</tr>\n";
      &ldap_logerr("add obj"); 
      if ( $err eq 0 && $task eq "move" ) {
          $conn = $ldapObj->delete ($currdn );
      }
 }
 if ( $task eq "move" &&  $objtype eq "ou" && $status_con eq 0 ) { &del_ou($ou_dnfull); }
 return $status_con;
}

sub add_usr
{
    my ($status_con);
    $status_con = 0;
    %ldapObjHash=();
    @ldapObjArr=();

    push (@ldapObjArr,'sn',$username);
    push (@ldapObjArr,'cn',$username);
    push (@ldapObjArr,'userpassword', $password);
    push (@ldapObjArr,'uid',$username);
    if ( $email ) { push (@ldapObjArr,'mail',$email); }
    push (@ldapObjArr,'objectClass',["top", "person", "organizationalperson", "inetorgperson"]);
    push (@ldapObjArr,'description',$organizationname);
    if ( $where )  { push (@ldapObjArr,'displayname',$where ); }
    %ldapObjHash=@ldapObjArr;
    $conn = $ldapObj->add ( $dn, attr => [ @ldapObjArr ] );
    if ( $err = $conn->code ) { $status_con=1; }
    &ldap_logerr("add usr"); 
    return $status_con;
}

sub mod_usr
{
    my ($status_con);
    $status_con = 0;
    %ldapObjHash=();
    @ldapObjArr=();

    # assume the uid (or the DN) was not changed
    # no change for cn username --- password in other form
    my $cur_entry=&sel_ldap_obj($dn,"cn=*");
    if ( !defined($cur_entry) || $cur_entry->dn ne $dn ) {
        $status_con=1;
        &ldap_logerr("browse usr"); 
    } else {
          push (@ldapObjArr,'sn',$in{username});
          if ( $in{email} ) { push (@ldapObjArr,'mail',$in{email}); }
          if ( $in{descrip} )  { push (@ldapObjArr,'displayname',$in{descrip}); }
          %ldapObjHash=@ldapObjArr;
          $conn = $ldapObj->modify ( $dn, changes => [ replace => [ @ldapObjArr ]]);
          if ( $err = $conn->code ) { $status_con=1; }
          &ldap_logerr("update usr"); 
    }
    return $status_con;
}

sub mod_usr_password
{
    my ($status_con);
    $status_con = 0;
    %ldapObjHash=();
    @ldapObjArr=();

    # assume the uid (or the DN) was not changed
    # no change for ou ouname ---
    my $cur_entry=&sel_ldap_obj($dn,"cn=*");
    if ( !defined($cur_entry) || $cur_entry->dn ne $dn ) {
        $status_con=1;
        &ldap_logerr("browse usr"); 
    } else {
          push (@ldapObjArr,'userpassword',$password);
          %ldapObjHash=@ldapObjArr;
          $conn = $ldapObj->modify ( $dn, changes => [ replace => [ @ldapObjArr ]]);
          if ( $err = $conn->code ) { $status_con=1; }
          &ldap_logerr("update passwd"); 
    }
    return $status_con;
}

sub del_usr
{
    my ($status_con);
    $status_con = 0;
    %ldapObjHash=();
    @ldapObjArr=();

    $conn= $ldapObj->delete ($dn);
    if ( $err = $conn->code ) { $status_con=1; }
    &ldap_logerr("delete usr"); 
    return $status_con;
}

sub add_ou
{
    my ($dn) = @_;
    my ($status_con);
    my $ou_name=$ouname;
    $ou_name=~s/^ou=//g;
    $status_con = 0;
    %ldapObjHash=();
    @ldapObjArr=();

    push (@ldapObjArr,'ou',$ou_name);
    push (@ldapObjArr,'objectClass',["top", "organizationalunit"]);
    %ldapObjHash=@ldapObjArr;
    $conn = $ldapObj->add ( $dn, attr => [ @ldapObjArr ] );
    if ( $err = $conn->code ) { $status_con=1; }
    &ldap_logerr("add ou"); 
    return $status_con;
}

sub mod_ou
{
    my ($status_con);
    $status_con = 0;
    %ldapObjHash=();
    @ldapObjArr=();

    # assume the uid (or the DN) was not changed
    # no change for ou ouname ---
    my $cur_entry=&sel_ldap_obj($dn,"ou=*");
    if ( !defined($cur_entry) || $cur_entry->dn ne $dn ) {
        $status_con=1;
        &ldap_logerr("browse ou"); 
    } else {
          if ( $in{descrip} ) { 
               push (@ldapObjArr,'description',$in{descrip});
               %ldapObjHash=@ldapObjArr;
               $conn = $ldapObj->modify ( $dn, changes => [ replace => [ @ldapObjArr ]]);
               if ( $err = $conn->code ) { $status_con=1; }
               &ldap_logerr("update ou"); 
          }
    }
    return $status_con;
}

sub del_ou
{
    my ($status_con);
    $status_con = 0;
    %ldapObjHash=();
    @ldapObjArr=();

    $conn = $ldapObj->delete($dn);
    if ( $err = $conn->code ) { $status_con=1; }
    &ldap_logerr("delete ou"); 
    return $status_con;
}

sub get_ldap_obj
{
    # This is to return a hash &Obj with all values of the $dn entry 
    my ( $dn, $cur_entry) = @_;
    local %Obj=();
    %ldapObjHash=();
    @ldapObjArr=();

    if ( !defined($cur_entry)  || $cur_entry->dn eq $dn ) {     # just to be sure 
         local @attrs = $cur_entry->attributes;
         foreach my $var (@attrs) {
             $attr = $cur_entry->get_value( $var, asref => 1 );
             if ( defined($attr) ) {
                  foreach my $value (@$attr) { 
                         $Obj{$var} = $value; }
             }
         }
    }
    %ldapObjHash=%entryObj;
    &ldap_logerr("browse $dn");
    return %Obj;
}

sub sel_ldap_obj
{
    my ($dn, $filter) = @_;
    %ldapObjHash=();
    @ldapObjArr=();
 
    $conn = $ldapObj->search ( base => $dn, 
                                         scope => "sub", 
                                         filter => "($filter)");
    if ( $err = $conn->code ||  $conn->count eq 0 ) {
         &ldap_logerr("browse $dn");
         return undef
    };
    return $conn->entry(0);
}

# This function exist to allow other actions further than to print a messages
# just by example we can gently exit CGI by doing " &footHere; exit " 
# All replication return not 0 will cross this funcion.
sub err_replication
{
   &html_errshow("ldap-rep");
   if ( $debug gt 0 ) {
        if ( $DebugFile ) {
            print DebugFile "($dn):".$text{'replica_err'} ."-->".$line_conn."\n";
            print DebugFile "$text{'replica_msg'}\n";
        }
   }
}

sub ldapcache_logerr
{
    my ($msgstr) = @_;
    my ($msg_str)="";
    my ($msg_err)="";
    my ($line_conn);
    $err_msg="";

  $msg_str="$text{task}=>'$msgstr'"; 
  if ( $search_cmd ) { $msg_str.="||$search_cmd"; };
  if ( "$ldapcache_server" eq "1" ) {
         $line_conn=$config{LDAP_type}.":".$config{ldapcache_server}.":".$config {ldapcache_port};
  } elsif ( "$ldapcache_server" eq "2" ) {
         $line_conn=$config{LDAP_type}.":".$config{ldapcache2_server}.":".$config {ldapcache2_port};
  }
  if ( $err ) {
       $msg_err.="error=>'".$text{'ldapcache_admerr'}."' $text{f_error}: '";
       if ( $conncache->code ) { 
         $msg_err.="$err'";
       } else {
         $msg_err.=$text{'ldapcache_connerr'}."'";
       }
       if ( $debug gt 0 ) {
            if ( !$DebugFile ) {
                 if  (  $ldapcache_notdie ne "1" ) {
                         print "<hr>\n";
                         print "<i> $line_conn</i>\n";
                         print "<b> $msg_str $msg_err</b>\n";
                         print "<hr>\n";
                 }
            } else {
                  print DebugFile "$line_conn\n";
                  print DebugFile "$msg_str\n";
                  print DebugFile "$msg_err\n";
            }
       }
       $msg_err=~s/\\n/\|\|/g; 
       $msg_str.="||$msg_err";
       $line_conn.=" err=$err";
       if ( $debug gt 0 ) { $err_msg=$line_conn; }
  }
  &webmin_log($line_conn,"ldapcache","$err||ldap=>'$line_conn'||$msg_str||dn=>'$dn_cache'",\%ldapObjHash);
}

sub ldap_logerr
{
    my ($msgstr) = @_;
    my ($msg_str)="";
    my ($msg_err)="";
    my ($line_conn);
    $err_msg="";

  $msg_str="$text{task}=>'$msgstr'"; 
  if ( $search_cmd ) { $msg_str.="||$search_cmd"; };
  if ( "$ldap_server" eq "1" ) {
         $line_conn=$config{LDAP_type}.":".$config{ldap_server}.":".$config {ldap_port};
  } elsif ( "$ldap_server" eq "2" ) {
         $line_conn=$config{LDAP_type}.":".$config{ldap2_server}.":".$config {ldap2_port};
  }
  $line_conn.=" $msgstr";
  if ( $err ) {
       $msg_err.="error=>'".$text{'ldap_admerr'}."' $text{f_error}: '";
       if ( $conn->code ) { 
         $msg_err.="$err'";
       } else {
         $msg_err.=$text{'ldap_connerr'}."'";
       }
       if ( $debug gt 0 ) {
            if ( !$DebugFile ) {
                 if  (  $ldap_notdie ne "1" ) {
                         print "<hr>\n";
                         print "<i> $line_conn</i>\n";
                         print "<b> $msg_err</b>\n";
                         print "<hr>\n";
                 }
            } else {
                  print DebugFile "$line_conn\n";
                  print DebugFile "$msg_str\n";
                  print DebugFile "$msg_err\n";
            }
       }
       $msg_err=~s/\\n/\|\|/g; 
       $msg_str.="||$msg_err";
       $line_conn.=" err=$err";
       if ( $debug gt 0 ) { $err_msg=$line_conn; }
  }
  &webmin_log($line_conn,"ldap","$err||ldap=>'$line_conn'||$msg_str||dn=>'$dn'",\%ldapObjHash);
}

sub schema_show
{
  &get_ldap_schema;
  result = $schema->dump( "/tmp/schema.dump" );
  &schema_get_class; 
}

sub search_ldap_schema
{
    $schema = $ldapObj->schema(dn => $dn);
    $connschema = $self->search(
        base   => $dn,
        scope  => 'base',
        filter => '(objectClass=*)',
        callback => \&schema_get_class
    );
}
sub search_ldapcache_schema
{
    my ($dn) = @_;
    $schema = $ldapcacheObj->schema(dn => $dn);
    $conschema = $self->search(
        base   => $dn,
        scope  => 'base',
        filter => '(objectClass=*)',
        callback => \&schema_view_class
    );
}

sub schema_get_attr 
{
      local ($val)=$_[0];

      my  $mesg = $ldapObj->search(
                  scope  => 'base',
                  filter => '(objectClass=$_[0])',
      );
      my $schema = $ldapObj->schema();
      @attributes = $schema->attributes;
      foreach ( @attributes)
      {
            $oid = $schema->name2oid( "$_" );
            # Get the various items associated with
            # this attribute.
            @attribute_items = $schema->items( "$oid" );
            # Read returned item names and display their associated data.
            foreach $value ( @attribute_items )
            {
               # We know we are dealing with an attribute, ignore type.
               next if ( $value eq 'type');  # Type  holds oc or at 
               # Read the data for this item of this oid.
               @item = $schema->item( $oid, $value );
               # Some item names have no data, the name itself is data.
               # This type of item has 1 as data.
               if ( defined(@item) && $item[0] == 1 )
               {
                    $att_value=$value;
                    @att_item="";
                    next;
               }
               if ( defined(@item) && $#item >= 0 )
               {
                    $att_value=$value;
                    @att_item=@item;
               }
            }
            print "<td valign=top>$att_value: @item'>". $_."</td>";
      }
}

sub schema_view_class 
{
   my ( $conschema, $entry) = @_;
   my ($status_con,$dn_cn);

   if ( !defined($entry) ) {
     if ($conschema->count == 0) {  # if conschema is not defined we have nothing.
          return; }
   }
   my $dn_cn = $entry->dn; 
#   $conschema->pop_entry;  # 
}

sub schema_get_class 
{
      print "<tr><td valign=top>ATT</td><td valign=top> VALUE </td></tr>";
      &schema_dump("classes");
#      &schema_dump("attributes");
}
sub schema_dump
{
   my ( $objtype) = @_;

      if ( $objtype eq "classes" ) { 
           @objects = $schema->objectclasses();
      } elsif ( $objtype eq "attributes" ) { 
           @objects = $schema->attributes();
      }

      foreach ( @objects)
      {
            # Get and display the oid number of the objectclass.
            $oid = $schema->name2oid( "$_" );
            next if ( ref($oid) eq 'ARRAY');
            print "<tr><td valign=top>$oid</td>\n";
            print "<td><table border=0>\n";
            # Get the various items associated with
            # this attribute.
            @attribute_items = $schema->items( "$oid" );
            # Read returned item names and display their associated data.
            foreach $value ( @attribute_items )
            {
               # We know we are dealing with an attribute, ignore type.
               next if ( $value eq 'type');  # Type  holds oc or at 
               # Read the data for this item of this oid.
               @item = $schema->item( $oid, $value );
               # Some item names have no data, the name itself is data.
               # This type of item has 1 as data.
               if ( defined(@item) && $item[0] == 1 )
               {
               print "<tr><td valign=top>$value</td></tr>\n";
               next;
               }
               if ( defined(@item) && $#item >= 0 )
               {
               print "<tr><td valing=top>$value</td>\n";
               if ( $value eq "must" || $value eq "may" ) {
                    print "<td valing=top>@item</td></tr>\n";
               }
               }
            }
            print "</table></td></tr>\n";
      }
}
1; # Return true
