#!/usr/bin/perl -w
# This script (sophomorix-repair) is maintained by Rüdiger Beck
# It is Free Software (License GPLv3)
# If you find errors, contact the author
# jeffbeck@web.de  or  jeffbeck@linuxmuster.net

# modules
use strict;
use Getopt::Long;
Getopt::Long::Configure ("bundling");
use Sophomorix::SophomorixConfig;
use Net::DNS;
use File::Basename;
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Useqq = 1;
$Data::Dumper::Terse = 1; 
use JSON;
use Sophomorix::SophomorixBase qw(
                                 print_line
                                 print_title
                                 unlock_sophomorix
                                 lock_sophomorix
                                 log_script_start
                                 log_script_end
                                 log_script_exit
                                 backup_auk_file
                                 get_passwd_charlist
                                 get_plain_password
                                 check_options
                                 config_sophomorix_read
                                 result_sophomorix_init
                                 result_sophomorix_add
                                 result_sophomorix_check_exit
                                 result_sophomorix_print
                                 filelist_fetch
                                 remove_whitespace
                                 json_dump
                                 NTACL_set_file
                                 recode_utf8_to_ascii
                                 );
use Sophomorix::SophomorixSambaAD qw(
                                 AD_school_create
                                 AD_bind_admin
                                 AD_unbind_admin
                                 AD_user_create
                                 AD_group_create
                                 AD_group_addmember
                                 AD_group_update
                                 AD_get_schoolname
                                 AD_get_name_tokened
                                 AD_dn_fetch_multivalue
                                 AD_get_AD_for_repair
                                 AD_dns_get
                                 AD_object_search
                                 AD_get_passwd
                                 AD_repdir_using_file
                                    );
my @arguments = @ARGV;


# Variablen für Optionen
$Conf::log_level=1;
my $help=0;
my $info=0;
my $json=0;

my $dump_ad=0;
my $linux=0;
my $global=0;
my $school=0;
my $project=0;
my $globaladministrator_home=0;
my $schooladministrator_home=0;
my $teacher_home=0;
my $adminclass=0;
my $extraclass=0;
my $student_home=0;
my $parent_home=0;
my $staff_home=0;
my $all=0;

# fs snapshot stuff
my $fs_snapshot="";
my $fs_snapshot_diff="";

# acl snapshot stuff
my $acl_snapshot="";
my $acl_snapshot_diff="";

###############################################################################
# Beginn
###############################################################################

# Parsen der Optionen
my $testopt=GetOptions(
           "help|h" => \$help,
           "info|i" => \$info,
           "json|j+" => \$json,
           "verbose|v+" => \$Conf::log_level,
           "dump-ad" => \$dump_ad,
           "linux|unix" => \$linux,
           "global" => \$global,
           "school" => \$school,
           "project" => \$project,
           "globaladministrator-home" => \$globaladministrator_home,
           "schooladministrator-home" => \$schooladministrator_home,
           "teacher-home" => \$teacher_home,
           "adminclass" => \$adminclass,
           "extraclass" => \$extraclass,
           "student-home" => \$student_home,
           "parent-home" => \$parent_home,
           "staff-home" => \$staff_home,
           "all" => \$all,
           "acl-snapshot=s" => \$acl_snapshot,
           "acl-snapshot-diff=s" => \$acl_snapshot_diff,
           "fs-snapshot=s" => \$fs_snapshot,
           "fs-snapshot-diff=s" => \$fs_snapshot_diff,
          );

my %sophomorix_result=&result_sophomorix_init("sophomorix-repair");
# Prüfen, ob Optionen erkannt wurden
&check_options($testopt,\%sophomorix_result,$json);

# Reading Configuration
my ($ldap,$root_dse) = &AD_bind_admin(\@arguments,\%sophomorix_result,$json);
my $root_dns=&AD_dns_get($root_dse);
my %sophomorix_config=&config_sophomorix_read($ldap,$root_dse,\%sophomorix_result);
my ($smb_admin_pass)=&AD_get_passwd($DevelConf::sophomorix_file_admin,
                                     $DevelConf::secret_file_sophomorix_file_admin);

# --help
if ($help==1) {
   # Scriptname ermitteln
   my @list = split(/\//,$0);
   my $scriptname = pop @list;
   # Befehlbeschreibung
   print "\n$scriptname repairs the permissions,owner,groupowner,acls/ntacls ",
         "of a sophomorix installation,\n",
         "reading the permissions from *.repdir files\n\n";
   print('
Options
  -h  / --help
  -v  / --verbose
  -vv / --verbose --verbose
  -i (not implemented)

  -j --dump-ad

What to repair in the Filesystem:

  --linux|unix               (use repdir.linux, repairs all permissions outside of $HOME)
  --global                   (use repdir.global, repairs the global part)
  --school                   (use repdir.school, repairs a school and subdirs)
  --project                  (use repdir.project, repairs projects)
  --globaladministrator-home (use repdir.globaladministrator_home, repairs homes of globaladministrators)
  --schooladministrator-home (use repdir.schooladministrator_home, repairs homes of schooladministrators)
  --teacher-home             (use repdir.teacher_home, repairs homes of teachers)
  --adminclass               (use repdir.adminclass, repairs adminclasses)
  --extraclass               (use repdir.extraclass, repairs extraclasses)
  --student-home             (use repdir.student_home, repairs homes of students)
  --parent-home              (use repdir.parent_home, repairs homes of parents)
  --staff-home               (use repdir.staff_home, repairs homes of staff members)

  --all                     (use all the above, top to bottom order)

Tools to create a sort of snapshot of /srv/samba

  --fs-snapshot <name>                (create filesystem snapshot <name> in /var/lib/sophomorix/sophomorix-repair)
  --fs-snapshot-diff <name1>,<name2>  (diff <name1> and <name2> filesystem snapshot)

  acl snapshots include fs snapshots:
  --acl-snapshot <name>               (create acl snapshot <name> in /var/lib/sophomorix/sophomorix-repair)
  --acl-snapshot-diff <name1>,<name2> (diff <name1> and <name2> acl snapshot)


Please see the sophomorix-repair(8) man pages for full documentation
');
   exit;
}



###############################################################################
# asking AD for users
###############################################################################
&print_title("Asking the system for users ...");

# fetch system data
my ($ref_AD) = &AD_get_AD_for_repair({ldap=>$ldap,
                                      root_dse=>$root_dse,
                                      root_dns=>$root_dns,
                                      sophomorix_config=>\%sophomorix_config,
                                    });


# --dump-ad
if ($dump_ad==1){
    &json_dump({json => $json,
                jsoninfo => "SEARCH",
                jsoncomment => "AD Content",
                log_level => $Conf::log_level,
                hash_ref=>$ref_AD,
                sophomorix_config=>\%sophomorix_config,
              });
    exit;
}


&result_sophomorix_check_exit(\%sophomorix_result,\%sophomorix_config,$json);
# ============================================================
# changing the filesystem
# ============================================================
&log_script_start(\@arguments,\%sophomorix_result,\%sophomorix_config);


# --all
if ($all==1) {
    $linux=1;
    $global=1;
    $school=1;
    $project=1;
    $globaladministrator_home=1;
    $schooladministrator_home=1;
    $teacher_home=1;
    $adminclass=1;
    $extraclass=1;
    $student_home=1;
    $parent_home=1;
    $staff_home=1;
}


# --linux
if ($linux==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         repdir_file=>"repdir.linux",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}


# --global
if ($global==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         school=>$sophomorix_config{'INI'}{'VARS'}{'GLOBALSHARENAME'},
                         repdir_file=>"repdir.global",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}


# --school
if ($school==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         repdir_file=>"repdir.school",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}


# --project
if ($project==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         repdir_file=>"repdir.project",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}


# --globaladministrator-home
if ($globaladministrator_home==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         repdir_file=>"repdir.globaladministrator_home",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}


# --schooladministrator-home
if ($schooladministrator_home==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         repdir_file=>"repdir.schooladministrator_home",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}


# --teacher-home
if ($teacher_home==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         repdir_file=>"repdir.teacher_home",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}


# --adminclass
if ($adminclass==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         repdir_file=>"repdir.adminclass",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}


# --extraclass
if ($extraclass==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         repdir_file=>"repdir.extraclass",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}


# --student-home
if ($student_home==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         repdir_file=>"repdir.student_home",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}


# --parent-home
if ($parent_home==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         repdir_file=>"repdir.parent_home",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}


# --staff-home
if ($staff_home==1) {
   &AD_repdir_using_file({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         repdir_file=>"repdir.staff_home",
                         AD=>$ref_AD,
                         smb_admin_pass=>$smb_admin_pass,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                        });
}



############################################################
# acl snapshot stuff
my $source=$sophomorix_config{'INI'}{'PATHS'}{'REPAIR_SNAPSHOT_SOURCE'};
my $target=$sophomorix_config{'INI'}{'PATHS'}{'REPAIR_SNAPSHOT_TARGET'};
my $target_file_find="find-result.txt";
my $target_file_acl="acl-snapshot.txt";

# --acl-snapshot
if ($fs_snapshot ne "" or $acl_snapshot ne ""){
    my $snapshot;
    if ($acl_snapshot ne ""){
        $snapshot=$acl_snapshot;
    } elsif ($fs_snapshot ne ""){
        $snapshot=$fs_snapshot;
    }

    &print_title("Start creating acl snapshot $snapshot in $target");
    my $snapshot_target=$target."/".$snapshot;
    system("mkdir -p $snapshot_target");
    my $find_result=$snapshot_target."/".$target_file_find;
    my $find_result_acl=$snapshot_target."/".$target_file_acl;

    print "   * Saving snapshot to $snapshot_target\n";

    # find
    my $find_command="find $source > $find_result";
    print "   * $find_command\n";
    system ($find_command);
    
    # smbcacls
    system("rm -f $find_result_acl");
    system("touch $find_result_acl");
    my $count=0;
    my $max_count =`cat $find_result | wc -l`;
    chomp($max_count);

    if ($acl_snapshot ne ""){
        open(FIND,$find_result);
        while(<FIND>){
	    $count++;
            chomp();
            my $dir=$_;
            print "$count/$max_count) $dir:\n";
            my $command="/usr/sbin/sophomorix-cacls $dir --append-to-file $find_result_acl 1>/dev/null";
            print "  * $command\n";
            system($command);
        }
        close(FIND);
    }
    &print_title("End creating acl snapshot $snapshot in $target");
}



# --acl-snapshot-diff
if ($fs_snapshot_diff ne "" or $acl_snapshot_diff ne ""){
    my $line="----------------------------------------------------------------------\n";
    my ($name1,$name2)=split(/,/,$acl_snapshot_diff);
    my $abs_name1=$sophomorix_config{'INI'}{'PATHS'}{'REPAIR_SNAPSHOT_TARGET'}."/".$name1;
    my $abs_name2=$sophomorix_config{'INI'}{'PATHS'}{'REPAIR_SNAPSHOT_TARGET'}."/".$name2;
    &print_title("Start diffing $name1 <-> $name2 in $sophomorix_config{'INI'}{'PATHS'}{'REPAIR_SNAPSHOT_TARGET'}");

    # find diff
    my $file1=$abs_name1."/".$target_file_find;
    my $file2=$abs_name2."/".$target_file_find;
    my $diff_find_command="diff $file1 $file2";
    print $line;
    print " $diff_find_command\n";
    print $line;
    system($diff_find_command);

    if ($acl_snapshot_diff ne ""){
        # acl diff
        my $file1_acl=$abs_name1."/".$target_file_acl;
        my $file2_acl=$abs_name2."/".$target_file_acl;
        my $diff_acl_command="diff $file1_acl $file2_acl";
        print $line;
        print " $diff_acl_command\n";
        print $line;
        system($diff_acl_command);
    }

    &print_title("End diffing $name1 <-> $name2 in $sophomorix_config{'INI'}{'PATHS'}{'REPAIR_SNAPSHOT_TARGET'}");
}







&log_script_end(\@arguments,\%sophomorix_result,\%sophomorix_config,$json);


############################################################
# subs
############################################################
