#!/usr/bin/perl

use strict;
use NethServer::SSSD;
use esmith::NetworksDB;
use esmith::ConfigDB;
use NethServer::AccountsList;
use NethServer::LdapClient;
use Sys::Hostname;
use Net::LDAP;

# Global variables for list_system_groups function
our $sssd;
our %config;
our $al;
our @system_groups;

sub OCC
{
    my $params = join(" ", @_);
    system("TERM=dumb su - apache -s /bin/bash -c \"source /opt/remi/php80/enable; cd /usr/share/nextcloud/; php -d memory_limit=1024M -d apc.enable_cli=1 occ $params\"");
}

sub _cb_group_push
{
    my $message = shift;
    my $entry = shift;

    my $key = lc($entry->get_value($config{'keyattr'}));
    if ( $sssd->isAD() && ($al->is_system_group($key) || $al->is_system_group($entry->get_value('objectSid'))) ) {
        push(@system_groups, $key);
    }
}


sub list_system_groups
{
    my ($systemName, $domainName) = split(/\./, Sys::Hostname::hostname(), 2);
    my $timeout = 10;

    my $ldap = NethServer::LdapClient::connect($sssd, 'timeout' => $timeout);

    if( ! $ldap) {
        return;
    }

    NethServer::LdapClient::paged_search($sssd, $ldap,
        'base' => $sssd->groupDN(),
        'scope' => 'subtree',
        'deref' => 'never',
        'timelimit' => $timeout,
        'filter' => $config{'filter'},
        'callback' => \&_cb_group_push
    );

    $ldap->unbind();
    $ldap->disconnect();
}

# Update trusted domains

my $ndb = esmith::NetworksDB->open_ro();
my $cdb = esmith::ConfigDB->open_ro();

my $fqdn = join('.', $cdb->get_value('SystemName'), $cdb->get_value('DomainName'));
OCC "config:system:delete trusted_domains";
OCC "config:system:set trusted_domains 0 --value=localhost";
OCC "config:system:set trusted_domains 1 --value=$fqdn";
OCC "config:system:set memcache.local --value='\\OC\\Memcache\\APCu'";
OCC "config:system:set logfile --value=/var/lib/nethserver/nextcloud/nextcloud.log";
OCC "config:system:set mail_smtpmode --value=smtp";
OCC "config:system:set mail_smtpsecure --value=''";
OCC "config:system:set mail_smtpauthtype --value=LOGIN";
OCC "config:system:set mail_from_address --value=no-reply";
OCC "config:system:set mail_domain --value=".$cdb->get_value('DomainName');
OCC "config:system:set mail_smtphost --value=localhost";
OCC "config:system:set mail_smtpport --value=25";
OCC "config:system:set updatechecker --type bool --value false";
OCC "config:system:set upgrade.disable-web --type bool --value true";
OCC "config:system:set check_for_working_wellknown_setup --type bool --value false";
OCC "background:cron";
OCC "db:convert-filecache-bigint -n";

my $i = 2;
foreach ($ndb->green(), $ndb->red(), $ndb->orange(), $ndb->blue()) {
    if ($_->prop("ipaddr")) {
      OCC "config:system:set trusted_domains $i --value=".$_->prop("ipaddr");
    }
    $i++;
}


# Add extra trusted domains

my $trusted_domains  = $cdb->get_prop('nextcloud','TrustedDomains') || '';
foreach (split(',', $trusted_domains)) {
    OCC "config:system:set trusted_domains $i --value=".$_;
    $i++;
}


# Update user authentication

$sssd = new NethServer::SSSD();
$al = NethServer::AccountsList->new();

if($sssd->isLdap()) {
    %config = ( %config,
        'keyattr' => 'cn',
        'filter' => '(objectClass=posixGroup)',
        'default_filter' => '(&(|(objectclass=posixGroup)))'
    );
} elsif($sssd->isAD()) {
    %config = ( %config,
        'keyattr' => 'sAMAccountName',
        'filter' => '(objectClass=group)',
        'default_filter' => '(&(objectClass=group)(groupType:1.2.840.113556.1.4.803:=2))'
    );
} else {
    # SSSD provider not configured, nothing to do
    exit 0;
}


# set default group filter for backward compatibility
my $group_filter = $config{'default_filter'};

# if any system group has been found, refine the group filter by excluding them
list_system_groups($sssd);
if (scalar @system_groups > 0) {
    $group_filter = "(&(objectClass=group)";
    foreach (@system_groups) {
        $group_filter .= "(!(cn=$_))";
    }
    $group_filter .= ")";
}

my $quotedBindPass = $sssd->bindPassword();
$quotedBindPass =~ s/\'/\\'/g;
$quotedBindPass =~ s/\$/\\\$/g;
if ($sssd->isLdap()) {
    OCC "ldap:set-config s01 ldapHost '" . $sssd->ldapURI() . "'";
    OCC "ldap:set-config s01 ldapPort ".$sssd->port();
    OCC "ldap:set-config s01 ldapAgentName '" . $sssd->bindDN() . "'";
    OCC "ldap:set-config s01 ldapAgentPassword '$quotedBindPass'";
    OCC "ldap:set-config s01 ldapBase ".$sssd->baseDN();
    OCC "ldap:set-config s01 ldapBaseGroups ".$sssd->groupDN();
    OCC "ldap:set-config s01 ldapBaseUsers ".$sssd->userDN();

    OCC "ldap:set-config s01 ldapGroupDisplayName cn";
    OCC "ldap:set-config s01 ldapGroupFilter '$group_filter'";
    OCC "ldap:set-config s01 ldapGroupFilterObjectclass posixGroup";
    OCC "ldap:set-config s01 ldapGroupMemberAssocAttr memberUid";
    OCC "ldap:set-config s01 ldapLoginFilter '(&(|(objectclass=inetOrgPerson))(|(uid=%uid)(|(mail=%uid))))'";
    OCC "ldap:set-config s01 ldapLoginFilterEmail 1";
    OCC "ldap:set-config s01 ldapLoginFilterMode 0";
    OCC "ldap:set-config s01 ldapLoginFilterUsername 1";
    OCC "ldap:set-config s01 ldapUserDisplayName cn";
    OCC "ldap:set-config s01 ldapUserDisplayName2 uid";
    OCC "ldap:set-config s01 ldapUserFilter '(|(objectclass=inetOrgPerson))'";
    OCC "ldap:set-config s01 ldapUserFilterObjectclass inetOrgPerson";
    OCC "ldap:set-config s01 ldapEmailAttribute mail";
    OCC "ldap:set-config s01 useMemberOfToDetectMembership 0";
    OCC "ldap:set-config s01 ldapConfigurationActive 1";
    OCC "ldap:set-config s01 turnOffCertCheck 1";
    if($sssd->startTls()) {
        OCC "ldap:set-config s01 ldapTLS 1"; # enable starttls on remote ldap providers
    }
} elsif ($sssd->isAD()) {
    OCC "ldap:set-config s01 ldapHost '" . $sssd->ldapURI() . "'";
    OCC "ldap:set-config s01 ldapPort ".$sssd->port();
    OCC "ldap:set-config s01 ldapAgentName '" . $sssd->bindDN() . "'";
    OCC "ldap:set-config s01 ldapAgentPassword -- '$quotedBindPass'";
    OCC "ldap:set-config s01 ldapBase ".$sssd->baseDN();
    OCC "ldap:set-config s01 ldapBaseGroups ".$sssd->groupDN();
    OCC "ldap:set-config s01 ldapBaseUsers ".$sssd->userDN();

    OCC "ldap:set-config s01 ldapGroupDisplayName cn";
    OCC "ldap:set-config s01 ldapGroupFilter '$group_filter'";
    OCC "ldap:set-config s01 ldapGroupFilterObjectclass group";
    OCC "ldap:set-config s01 ldapGroupMemberAssocAttr member";
    OCC "ldap:set-config s01 ldapLoginFilter '(&(&(|(objectclass=person)))(|(sAMAccountName=%uid)(userPrincipalName=%uid)))'";
    OCC "ldap:set-config s01 ldapLoginFilterMode 0";
    OCC "ldap:set-config s01 ldapLoginFilterUsername 1";
    OCC "ldap:set-config s01 ldapUserDisplayName displayName";
    OCC "ldap:set-config s01 ldapUserDisplayName2 sAMAccountName";
    OCC "ldap:set-config s01 ldapUserFilter '(&(|(objectclass=person)))'";
    OCC "ldap:set-config s01 ldapUserFilterObjectclass person";
    OCC "ldap:set-config s01 ldapEmailAttribute userPrincipalname";
    OCC "ldap:set-config s01 turnOffCertCheck 1";
    OCC "ldap:set-config s01 useMemberOfToDetectMembership 1"; # expand all groups
    OCC "ldap:set-config s01 ldapConfigurationActive 1";
    my $honorAdStartTls = ($cdb->get_prop('nextcloud', 'HonorAdStartTls') || 'disabled') eq 'enabled';
    if($honorAdStartTls && $sssd->startTls()) {
        OCC "ldap:set-config s01 ldapTLS 1";
    } else {
        OCC "ldap:set-config s01 ldapTLS 0";
    }
} else {
    # SSSD provider not configured, nothing to do
    exit 0;
}
