#!/usr/bin/perl -w
use strict;
use FileHandle;


# Set version of this installation script!
my $installerVersion=1.0;

#--------------------------------------------------------------------------
#                             Documentation
#--------------------------------------------------------------------------
sub help {
print '
#--------------------------------------------------------------------------
#
#                     NWZ Ubuntu-Linux installation script
#
# Author: O. Rubner (2015).
# Version '.$installerVersion.
'#
# Call: nwz_ubuntu [-h -sv]
#
# Description:
#
# Prepare an Ubuntu-Linux system for authentification with the NWZ
# domain.
#
# Install an Ubuntu-Linux from the scratch and run this script afterwards.
# Then follow the instructions.
#
# -------------------------------------------------------------------------
# Options:
#       -h  print this help information
#       -sv print Ubuntu-Versions for which this script is tested
#
#--------------------------------------------------------------------------
';
}

#--------------------------------------------------------------------------
#                  Global variables and command line options
#--------------------------------------------------------------------------

my @UbuntuVersions = ("14.04");

my @modules= ("krb5-user", "samba", "cifs-utils", "sssd", "sssd-ad", "sssd-tools", "libpam-mount", "ntp");

my @cfgfiles = ("/etc/krb5.conf", "/etc/sssd/sssd.conf", "/etc/samba/smb.conf",
		"/etc/nsswitch.conf", "/etc/security/pam_mount.conf.xml");

my $version;

my $YUSER;
my $HOSTNAME;

#--------------------------------------------------------------------------
#                             Main program
#--------------------------------------------------------------------------
{

  my $val;

  print "\n    NWZ install for Ubuntu-Linux\n";
  print "          O. Rubner (2015)\n\n";
  print "               Version ".$installerVersion."\n\n";

  # check for command line options
  &checkOptions(@ARGV);

  # check for correct Ubuntu version
  &checkUbuntuVersion();

  # check for root
  if ($ENV{"USER"} ne "root") {
    print "Please login as root!\n";
    exit(1);
  }

  # -------------------------
  #    Ask for preliminary work
  # -------------------------
  $HOSTNAME=`hostname`;
  chomp $HOSTNAME;
  
  print "Has the computer \"$HOSTNAME\" been entered in \n";
  print "the active directory (Pre-Staging)? (y/N) \n";
  $val=<>;
  chomp $val;
  print"\n";
  exit if (lc $val ne "y");

  # -------------------------
  #    do everything
  # -------------------------

  # setup ntpd
  &setupntpd();

  # install additional modules
  &installmodules();

  # copy nwz-configuration files (krb5, ldap, samba, sssd)
  &copyfiles();

  # configure nsswitch
  &nssconfig();

  # configure pam modules
  &pamconfig();

  # configure pam_mount
  &pam_mountconfig();

  # allow root login via ssh
  if (-e "/etc/ssh/sshd_config") {
      &sshRootLogin();
  }

  # configure lightdm to allow manual logins
  &setuplightdm();

  # join domain and test
  &setupfinal();

  print "\n  Installation finished!\n";
  print "\n  Please restart system!\n";

}

#--------------------------------------------------------------------------
#                             Subroutines
#--------------------------------------------------------------------------


#--------------------------------------------------------------------------
# Allow root login to this system                                  (Ubuntu)
#--------------------------------------------------------------------------
sub sshRootLogin {
    replaceline("PermitRootLogin","PermitRootLogin","#PermitRootLogin","/etc/ssh/sshd_config");
}

# ---------------------------------------------------------------------
# Set up ntpd
# ---------------------------------------------------------------------
sub setupntpd {
    # set current time
    # does not work!
#    ntpd -q -g -x -n;
}

# ---------------------------------------------------------------------
# Check for correct OS version                                 (Ubuntu)
# ---------------------------------------------------------------------
sub checkUbuntuVersion {

  my $vers = join "|",@UbuntuVersions;
  $vers = "(".$vers.")";
  $version=`awk '\$1=="Ubuntu" {print \$2}' /etc/issue`;

  # remove minor revision number
  my ($v1,$v2) = split '\.',$version;
  $version = "$v1.$v2";

  print "Ubuntu-Version: $version\n";

  my $retval = `grep Ubuntu /etc/issue | grep -E "$vers"`;

  if ($retval eq "") {
    print "This script works only for Ubuntu Versions:\n";
    print "       $vers \n\n";
    print "You can test it for your version without warranty.\n";
    print "Please report success to rubner\@uni-muenster.de\n";

    print "Do you want to continue? (y/N) ";
    my $val=<>;
    chomp $val;
    print"\n";
    exit(1) if (lc $val ne "y");
  }

}

# ---------------------------------------------------------------------
# Check for and install additional modules                     (Ubuntu)
# ---------------------------------------------------------------------
sub installmodules {

  my $needmodules;
  my ($mod,$retval);

  # install needed modules
  my $count = 1;
  foreach $mod (@modules) {
      if(!`dpkg -l $mod | grep ii`) {
	  print "---------------------------------\n";
	  print "Installing $mod ... ($count/".($#modules+1).")\n";
	  `export DEBIAN_FRONTEND=noninteractive; apt-get install -y -q --force-yes $mod`;
      }
      $count++;
  }
  print "---------------------------------\n";
}


# ---------------------------------------------------------------------
# Configure nsswitch
# ---------------------------------------------------------------------
sub nssconfig {

  # update /etc/nsswitch
  &replaceline("passwd:","^[^#].+","passwd:         compat sss","/etc/nsswitch.conf");
  &replaceline("group:","^[^#].+","group:          compat sss","/etc/nsswitch.conf");
}

# ---------------------------------------------------------------------
# Configure pam
# ---------------------------------------------------------------------
sub pamconfig {

    `echo "session    required    pam_mkhomedir.so skel=/etc/skel/ umask=0022\n" >> /etc/pam.d/common-session`;

}

# ---------------------------------------------------------------------
# Configure pam_mount.conf.xml for home directories
# ---------------------------------------------------------------------
sub pam_mountconfig {

  my $file = new FileHandle;

  # avoid double entries if there is already one
  if (! `grep nwz /etc/security/pam_mount.conf.xml`) {

    # remove end tag
    &replaceline("<\\/pam_mount>",".+","","/etc/security/pam_mount.conf.xml");
      
    open($file,">>/etc/security/pam_mount.conf.xml");
    print $file "\n";
      
    # optional!
    # Enter your own samba-file server in server="MYSERVER" and uncomment
    # print $file '<volume user="*" fstype="cifs" server="MYSERVER" path="%(USER)" mountpoint="~" options="dir_mode=0700,file_mode=0600,serverino,nobrl,workgroup=NWZ" />';

    # add end tag
    print $file "\n\n</pam_mount>\n";
    
    close $file;
  }
}

# ---------------------------------------------------------------------
# Join domain, start sssd and test
# ---------------------------------------------------------------------
sub setupfinal {

  print "Administrator username (nwz-yaccount): ";
  $YUSER = <>;
  chomp $YUSER;

  if (system("net ads join -U $YUSER")!=0) {
      print "\nCheck if the computer ".$HOSTNAME." \n";
      print "   1) is entered correctly in Pre-Staging (lower/upper case!).\n";
      print "   2) has an admin group in Pre-Staging to which ".$YUSER." belongs.\n\n";
      print "Else ask your local NWZ-guru!\n\n";
      exit(1);
  }

  print "\n Please ignore the following errors:\n";
  print "       No DNS domain configured for ... Unable to perform DNS Update.\n";
  print "       DNS update failed: NT_STATUS_INVALID_PARAMETER\n\n";

  # check sssd
  #  `initctl list | grep sssd`;

}

# ---------------------------------------------------------------------
# Backup configuration files and copy nwz files
# ---------------------------------------------------------------------
sub copyfiles {

  my ($file, $backupfile);
  my $retval;

  print "Copying configuration files ...\n";

  foreach $file (@cfgfiles) {

    next if (! -e $file);

    $backupfile = $file.".bak";

    if (-e $backupfile) {
      print "$backupfile already exists.\n";
      print "Overwrite? (y/N) ";
      $retval = <>;
      chomp $retval;
      print"\n";

      `cp $file $backupfile` if (lc($retval) eq "y");
    }
    else {
      `cp $file $backupfile`;
    }
  }

  &createkrb5;
  &createsamba;
  &createsss;

}

#--------------------------------------------------------------------------
# Set up lightdm to allow manual logins
#--------------------------------------------------------------------------
sub setuplightdm {

  `echo "[SeatDefaults]
greeter-session=unity-greeter
user-session=ubuntu
greeter-show-manual-login=true
greeter-hide-users=true
" > /etc/lightdm/lightdm.conf`;

}



#--------------------------------------------------------------------------
# create /etc/krb5.conf
#--------------------------------------------------------------------------
sub createkrb5 {

  `echo "[libdefaults]
        default_realm = NWZ.WWU.DE
        dns_lookup_kdc = true
        clockskew = 300
        forwardable = true
        rdns = false
        ignore_acceptor_hostname = true
        renew_lifetime = 365d
	canonicalize = true

[realms]
        NWZ.WWU.DE = {
                kdc = nwz.wwu.de
                default_domain = nwz.wwu.de
                admin_server = nwz.wwu.de
        }
#        NWZNET.UNI-MUENSTER.DE = {
#                kdc = nwznet.uni-muenster.de
#                default_domain = nwznet.uni-muenster.de
#                admin_server = nwznet.uni-muenster.de
#        }

[domain_realm]
        .nwz.wwu.de = NWZ.WWU.DE
#	.nwznet.uni-muenster.de = NWZNET.UNI-MUENSTER.DE
#	.uni-muenster.de = NWZNET.UNI-MUENSTER.DE

[logging]
    kdc = FILE:/var/log/krb5/krb5kdc.log
    admin_server = FILE:/var/log/krb5/kadmind.log
    default = SYSLOG:NOTICE:DAEMON

" > /etc/krb5.conf`;

}

#--------------------------------------------------------------------------
# create /etc/samba/smb.conf
#--------------------------------------------------------------------------
sub createsamba {

  `echo "[global]
        workgroup = NWZ
        kerberos method = system keytab
        passdb backend = tdbsam
        printing = cups
        printcap name = cups
        printcap cache time = 750
        cups options = raw
        map to guest = Bad User
        include = /etc/samba/dhcp.conf
        logon path = \\\\%L\\profiles\\.msprofile
        logon home = \\\\%L\\%U\\.9xprofile
        logon drive = P:
        usershare allow guests = No
        security = ads
        wins support = No
        realm = NWZ.WWU.DE
#        wins server = NWZ.UNI-MUENSTER.DE

#[homes]
#       comment = Home Directories
#       valid users = %S, %D%w%S
#       browseable = No
#       read only = No
#       inherit acls = Yes
#[profiles]
#       comment = Network Profiles Service
#       path = %H
#       read only = No
#       store dos attributes = Yes
#       create mask = 0600
#       directory mask = 0700
#[users]
#       comment = All users
#       path = /home
#       read only = No
#       inherit acls = Yes
#       veto files = /aquota.user/groups/shares/
#[groups]
#       comment = All groups
#       path = /home/groups
#       read only = No
#       inherit acls = Yes
#[printers]
#       comment = All Printers
#       path = /var/tmp
#       printable = Yes
#       create mask = 0600
#       browseable = No
#[print$]
#       comment = Printer Drivers
#       path = /var/lib/samba/drivers
#       write list = \@ntadmin root
#       force group = ntadmin
#       create mask = 0664
#       directory mask = 0775

" > /etc/samba/smb.conf`;

}

#--------------------------------------------------------------------------
# create /etc/sssd/sssd.conf
#--------------------------------------------------------------------------
sub createsss {

  `echo "[sssd]
config_file_version = 2
#debug_level = 0x03FF
services = nss, pam
domains = NWZ

[nss]
#debug_level = 0xFFFF
filter_users = root
filter_groups = root

[pam]
#debug_level = 0xFFFF
pam_verbosity = 2

[domain/NWZ]
#debug_level = 0x03FF
ad_server = nwz.wwu.de
ad_domain = nwz.wwu.de

id_provider = ad
auth_provider = ad
chpass_provider = ad
dyndns_update = false

krb5_renewable_lifetime = 180d
krb5_renew_interval = 300
krb5_realm = NWZ.WWU.DE
krb5_server = nwz.wwu.de

cache_credentials = true

ldap_schema = AD
ldap_sasl_canonicalize = true

enumerate = true
subdomain_enumerate = true

ldap_search_base = DC=nwz,DC=wwu,DC=de
ldap_user_search_base = OU=Heuer,OU=Physikalische Chemie,OU=Chemie und Pharmazie,OU=Fachbereiche,OU=Domain Members,DC=nwz,DC=wwu,DC=de
ldap_group_search_Base = OU=Fachbereiche,OU=Domain Members,DC=nwz,DC=wwu,DC=de              
ldap_id_mapping = false       
ldap_user_object_class = user
ldap_group_object_class = group
ldap_user_name = sAMAccountName
ldap_user_home_directory = unixHomeDirectory
ldap_user_principal = userPrincipalName

" > /etc/sssd/sssd.conf`;

# sssd wont start with the wrong permissions
`chmod go-r /etc/sssd/sssd.conf`;

}

#--------------------------------------------------------------------------
# Find line(s) containing $key in $filename and replace the string $old by
# $new. $filename must contain the complete path.
# $key and $old can be any regular expression.
#
# If $old==".+" the complete line is replaced by $new.
#
# Call:
#       replaceline($key,$old,$new,$filename)
#
#--------------------------------------------------------------------------
sub replaceline {

  my $key=$_[0];
  my $old=$_[1];
  my $new=$_[2];
  my $filename=$_[3];

  my $filein = new FileHandle;
  my $fileContent;
  open($filein,"<$filename") || die "No file $filename found!\n";

  while (<$filein>) {
      if ($_=~/$key/) {
	  $_ =~ s/$old/$new/g;
      }
      $fileContent .= $_;
  }

  close($filein);
  open($filein,">$filename") || die "Could not open $filename for writing!\n";
  print $filein $fileContent;
}

#--------------------------------------------------------------------------
# Find line(s) containing $key in $file and insert the string $newline either
# before (before==1) or after (before==0) this line.
# $file must contain the complete path.
# $key can be any regular expression.
# $newline must not contain a newline character (it is added automatically at the end).
#
# Call:
#       insertline($key,$newline,$file,before)
#
#--------------------------------------------------------------------------
sub insertline {

  my $key=$_[0];
  my $newline=$_[1];
  my $filename=$_[2];
  my $before=$_[3];

  my $filein = new FileHandle;
  my $fileContent;
  open($filein,"<$filename") || die "No file $filename found!\n";

  while (<$filein>) {
      $fileContent .= $_ if ($before==0);
      if ($_=~/$key/) {
	  $fileContent .= "$newline\n";
      }
      $fileContent .= $_ if ($before==1);
  }

  close($filein);
  open($filein,">$filename") || die "Could not open $filename for writing!\n";
  print $filein $fileContent;
}

#--------------------------------------------------------------------------
# check command line options
#
#--------------------------------------------------------------------------
sub checkOptions {

  my @options = split(/-/,join(" ",@ARGV));
  my $opt;

  # check for options
  foreach $opt (@options) {

    # display help
    if ($opt eq "h" || $opt eq "help") {
      &help;
      exit;
    }

    # display correct SuSE versions
    if ($opt eq "sv") {
      my $vers = join " | ",@UbuntuVersions;
      print "Tested OpenSuSE Versions:\n   $vers \n\n";
      exit;
    }

  }

  undef(@ARGV);
}

