#!/usr/bin/perl -w
# This script (sophomorix-group) 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::LDAP;
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Useqq = 1;
$Data::Dumper::Terse = 1; 
use JSON;use JSON;
use Sophomorix::SophomorixBase qw(
                                 print_line
                                 print_title
                                 log_script_start
                                 log_script_end
                                 log_script_exit
                                 check_options
                                 config_sophomorix_read
                                 result_sophomorix_init
                                 result_sophomorix_add
                                 result_sophomorix_check_exit
                                 result_sophomorix_print
                                 json_dump
                                 );
use Sophomorix::SophomorixSambaAD qw(
                                 AD_school_create
                                 AD_bind_admin
                                 AD_dns_get
                                 AD_unbind_admin
                                 AD_get_name_tokened
                                 AD_group_create
                                 AD_group_update
                                 AD_sophomorix_group_fetch
                                 AD_group_kill
                                 AD_group_addmember
                                 AD_group_removemember
                                 AD_get_passwd
                                 AD_get_groups_v
                                 AD_get_full_groupdata
                                    );

my @arguments = @ARGV;

############################################################
# Option handling
############################################################
my %options=();
# define possible action in a script and what OBJECT they need
$options{'CONFIG'}{'ACTION'}{'GROUP'}="create,".
                                      "kill,".
                                      "description,".
                                      "addquota,".
                                      "addmailquota,".
                                      "mailalias,".
                                      "maillist,".
                                      "addmembers,".
                                      "removemembers,".
                                      "addmembergroups,".
                                      "removemembergroups,".
                                      "description";
# define which options deliver which object
$options{'CONFIG'}{'ONE_OF'}{'GROUP'}="group";

my $testopt=GetOptions(\%options, 
                       "help|h",
                       "info|i",
                       "json|j+",
                       "verbose|v+",
                       "group|g=s",
                       "create",
                       "kill",
                       "school=s",
                       "addmembers=s",
                       "removemembers=s",
                       "addmembergroups=s",
                       "removemembergroups=s",
                       "description=s",
                       "addquota=s",
                       "addmailquota=s",
                       "mailalias!",
                       "maillist!",
                      );

my %sophomorix_result=&result_sophomorix_init("sophomorix-group");
# Prüfen, ob Optionen erkannt wurden, sonst Abbruch
&check_options($testopt,\%sophomorix_result,$options{'json'},\%options);

# defaults
if (not defined $options{'school'}){
    $options{'school'}="---";
}


# Reading Configuration
my ($ldap,$root_dse) = &AD_bind_admin(\@arguments,\%sophomorix_result,$options{'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 (defined $options{'help'}) {
   # Scriptname ermitteln
   my @list = split(/\//,$0);
   my $scriptname = pop @list;
   # Befehlsbeschreibung
   print('
sophomorix-group 

1) adds/modifies/deletes a group in samba 4 AD with the sophomorixType=sophomorix-group
2) modifies memberships of printer groups with the sophomorixType=printer

Options:
  -h  / --help
  -v  / --verbose
  -vv / --verbose --verbose
  -i  / --info

Create a group:
  --create --group <name1>,<name2>, ...
  --create --group <name1>,<name2>, ...  --school <school>

Create a global group epoptes: 
  --create --group epoptes --school global

Delete a group:
  --kill --group --group <name1>,<name2>, ...

Manage group members:
  --addmembers <user> --group <name1>,<name2>, ...
  --removemembers <user> --group <name1>,<name2>, ...

  --addmembergroups group --group <name1>,<name2>, ...
  --removemembergroups group --group <name1>,<name2>, ...

Edit a group:
  --description \'multiple words possible\' --group <name1>,<name2>, ...

  --addquota <share1>:<quota1 in MiB>:<comment1>,<share2>:<quota2 in MiB>:<comment2>,... --group <name1>,<name2>, ...
  --addmailquota <mailquota in MiB>:<Comment> --group <name1>,<name2>, ...

  --mailalias --group <name>, --nomailalias --group <name1>,<name2>, ...
  --maillist --group <name>, --nomaillist --group <name1>,<name2>, ...

Examples:
  Add/remove a user to/from a group:
  sophomorix-group --addmembers <user> --group <name1>,<name2>, ...
  sophomorix-group --removemembers <user> --group <name1>,<name2>, ...

Please see the sophomorix-group(8) man pages for full documentation
');
   print "\n";
   exit;
}



# --info
if ($options{'info'}==1 and not defined $options{'group'}){
    my $ref_group_v=&AD_get_groups_v({ldap=>$ldap,
                                   root_dse=>$root_dse,
                                   root_dns=>$root_dns,
                                   school=>$options{'school'},
                                   sophomorix_config=>\%sophomorix_config,
                                 });

    #print Dumper($ref_group_v->{'LISTS'});
    my $jsoninfo="GROUPS_OVERVIEW";
    my $jsoncomment="All Groups";
    &json_dump({json => $options{'json'},
                jsoninfo => $jsoninfo,
                jsoncomment => $jsoncomment,
                object_name => $options{'school'},
                log_level => $Conf::log_level,
                hash_ref => $ref_group_v,
                sophomorix_config => \%sophomorix_config,
               });
    exit;
}



# --info --class <name>
# list groups and exit
if ($options{'info'}==1 and defined $options{'group'}){
   my $ref_groups=&AD_get_full_groupdata({ldap=>$ldap,
                                           root_dse=>$root_dse,
                                           root_dns=>$root_dns,
                                           grouplist=>$options{'group'},
                                           sophomorix_config=>\%sophomorix_config,
                                      });
    #print Dumper($ref_groups);
    my $jsoninfo="GROUP";
    my $jsoncomment="Group";
    &json_dump({json => $options{'json'},
                jsoninfo => $jsoninfo,
                jsoncomment => $jsoncomment,
                object_name => $options{'school'},
                log_level => $Conf::log_level,
                hash_ref => $ref_groups,
                sophomorix_config => \%sophomorix_config,
               });
    exit;
}



&result_sophomorix_check_exit(\%sophomorix_result,\%sophomorix_config,$options{'json'});
&log_script_start(\@arguments,\%sophomorix_result,\%sophomorix_config);


############################################################
# nonexisting group action:
# --create --group <group1>,<group2>,...
############################################################
if (defined $options{'create'} and defined $options{'group'}){
    my @groups_option=split(/,/,$options{'group'});
    my $sub_ou;
    if ($options{'school'} eq "global"){
        $sub_ou=$sophomorix_config{'INI'}{'OU'}{'AD_group_ou'};
    } else {
        $sub_ou=$sophomorix_config{'INI'}{'OU'}{'AD_project_ou'};
    }
    foreach my $group_option (@groups_option){
        # avoid names beginning with p_
        if ($group_option=~ m/^p\_/){
            print "\n";
            print "ERROR: Not creating group $group_option\n";
            print "       group names beginning with p_ are reserved for projects\n";
            print "\n";
            exit 88;
        }
        &AD_school_create({ldap=>$ldap,
                           root_dse=>$root_dse,
                           root_dns=>$root_dns,
                           school=>$options{'school'},
                           smb_admin_pass=>$smb_admin_pass,
                           sophomorix_config=>\%sophomorix_config,
                           sophomorix_result=>\%sophomorix_result,
                         }); 
        my $group_token=&AD_get_name_tokened($group_option,$options{'school'},"sophomorix-group");
        &AD_group_create({ldap=>$ldap,
                          root_dse=>$root_dse, 
                          root_dns=>$root_dns,
                          school=>$options{'school'},
                          group=>$group_token,
                          group_basename=>$group_option,
                          description=>"Created by sophomorix-group",
                          type=>"sophomorix-group",
                          status=>"P",
		          sub_ou=>$sub_ou,
                          smb_admin_pass=>$smb_admin_pass,
                          sophomorix_config=>\%sophomorix_config,
                          sophomorix_result=>\%sophomorix_result,
                        });
    }
}



############################################################
# existing group actions
# get dn if group exists and continue
############################################################
my @groups_option=split(/,/,$options{'group'});
my %groups=();
foreach my $group_option (@groups_option){
    my $group_token=&AD_get_name_tokened($group_option,$options{'school'},"sophomorix-group");
    my ($dn_group,
        $count,
        $school_AD)=&AD_sophomorix_group_fetch($ldap,
                                $root_dse,
                                $group_token,
                               );
    if ($count==1){
        $groups{'GROUP_VALID_DATA'}{$group_token}{'DN'}=$dn_group;
        $groups{'GROUP_VALID_DATA'}{$group_token}{'COUNT'}=$count;
        $groups{'GROUP_VALID_DATA'}{$group_token}{'SCHOOL'}=$school_AD;
        # push in the list of valid groups
        push @{ $groups{'GROUP_VALID_LIST'} }, $group_token;
    } else {
        print "Skipping group $group_token ($count matching groups found)\n";
        push @{ $groups{'GROUP_UNVALID_LIST'} }, $group_token;
        print "\nERROR retrieving group $options{'group'}($group_token): $count group found.\n\n";
        &log_script_exit("ERROR retrieving group $group_token: $count group found.",$count,1,0,
                         \@arguments,\%sophomorix_result,\%sophomorix_config,$options{'json'});
    }
}



# --description <strg> --group <group1>,<group2>,...
if (defined $options{'description'}){
    foreach my $group_valid (@{ $groups{'GROUP_VALID_LIST'} }){
        &AD_group_update({ldap=>$ldap,
                          root_dse=>$root_dse,
                          dn=>$groups{'GROUP_VALID_DATA'}{$group_valid}{'DN'},
		          school=>$groups{'GROUP_VALID_DATA'}{$group_valid}{'SCHOOL'},
                          type=>"sophomotix-group",
                          description=>$options{'description'},
                          sophomorix_config=>\%sophomorix_config,
                        });
    }
}



# --addquota <strg> --group <group1>,<group2>,...
if (defined $options{'addquota'}){
    foreach my $group_valid (@{ $groups{'GROUP_VALID_LIST'} }){
        &AD_group_update({ldap=>$ldap,
                          root_dse=>$root_dse,
                          dn=>$groups{'GROUP_VALID_DATA'}{$group_valid}{'DN'},
		          school=>$groups{'GROUP_VALID_DATA'}{$group_valid}{'SCHOOL'},
                          type=>"sophomotix-group",
                          addquota=>$options{'addquota'},
                          sophomorix_config=>\%sophomorix_config,
                        });
    }
}



# --addmailquota <strg> --group <group1>,<group2>,...
if (defined $options{'addmailquota'}){
    foreach my $group_valid (@{ $groups{'GROUP_VALID_LIST'} }){
        &AD_group_update({ldap=>$ldap,
                          root_dse=>$root_dse,
                          dn=>$groups{'GROUP_VALID_DATA'}{$group_valid}{'DN'},
		          school=>$groups{'GROUP_VALID_DATA'}{$group_valid}{'SCHOOL'},
                          type=>"sophomotix-group",
                          addmailquota=>$options{'addmailquota'},
                          sophomorix_config=>\%sophomorix_config,
                        });
    }
}



# --mailalias/nomailalias --group <group1>,<group2>,...
if (defined $options{'mailalias'}){
    foreach my $group_valid (@{ $groups{'GROUP_VALID_LIST'} }){
        &AD_group_update({ldap=>$ldap,
                          root_dse=>$root_dse,
                          dn=>$groups{'GROUP_VALID_DATA'}{$group_valid}{'DN'},
                          school=>$groups{'GROUP_VALID_DATA'}{$group_valid}{'SCHOOL'},
                          type=>"sophomotix-group",
                          mailalias=>$options{'mailalias'},
                          sophomorix_config=>\%sophomorix_config,
                        });
    }
}



# --maillist/--nomaillist --group <group1>,<group2>,...
if (defined $options{'maillist'}){
    foreach my $group_valid (@{ $groups{'GROUP_VALID_LIST'} }){
        &AD_group_update({ldap=>$ldap,
                          root_dse=>$root_dse,
                          dn=>$groups{'GROUP_VALID_DATA'}{$group_valid}{'DN'},
		          school=>$groups{'GROUP_VALID_DATA'}{$group_valid}{'SCHOOL'},
                          type=>"sophomotix-group",
                          maillist=>$options{'maillist'},
                          sophomorix_config=>\%sophomorix_config,
                        });
    }
}



# --removemembers member --group <group1>,<group2>,...
if (defined $options{'removemembers'}){
    foreach my $group_valid (@{ $groups{'GROUP_VALID_LIST'} }){
        &AD_group_removemember({ldap => $ldap, 
                                root_dse => $root_dse, 
                                group => $group_valid,
                                removemember => $options{'removemembers'},
                              });   
    }
}



# --addmembers member --group <group1>,<group2>,...
if (defined $options{'addmembers'}){
    foreach my $group_valid (@{ $groups{'GROUP_VALID_LIST'} }){
        &AD_group_addmember({ldap => $ldap, 
                             root_dse => $root_dse, 
                             group => $group_valid,
                             addmember => $options{'addmembers'},
                           });   
    }
}



# --removemembergroups group --group <group1>,<group2>,...
if (defined $options{'removemembergroups'}){
    foreach my $group_valid (@{ $groups{'GROUP_VALID_LIST'} }){
        &AD_group_removemember({ldap => $ldap, 
                                root_dse => $root_dse, 
                                group => $group_valid,
                                removegroup => $options{'removemembergroups'},
                              });   
    }
}



# --addmembergroups group --group <group1>,<group2>,...
if (defined $options{'addmembergroups'}){
    foreach my $group_valid (@{ $groups{'GROUP_VALID_LIST'} }){
        &AD_group_addmember({ldap => $ldap, 
                             root_dse => $root_dse, 
                             group => $group_valid,
                             addgroup => $options{'addmembergroups'},
                           });   
    }
}



# --kill --group --group <group1>,<group2>,...
if (defined $options{'kill'} and defined $options{'group'}){
    foreach my $group_valid (@{ $groups{'GROUP_VALID_LIST'} }){
        &AD_group_kill({ldap=>$ldap,
                        root_dse=>$root_dse,
                        root_dns=>$root_dns,
                        group=>$group_valid,
                        smb_admin_pass=>$smb_admin_pass,
                        type=>"sophomorix-group",
                        sophomorix_config=>\%sophomorix_config,
                      });
    }
}



&AD_unbind_admin($ldap);

&log_script_end(\@arguments,\%sophomorix_result,\%sophomorix_config,$options{'json'});
