#!/bin/sh
#
# Script copied from sssd version 1.2.1-3.

# Generate sssd.conf setup dynamically based on autodetectet LDAP
# and Kerberos server.

set -e

# See if we can find an LDAP server.  Prefer ldap.domain, but also
# accept SRV records if no ldap.domain server is found.
lookup_ldap_uri() {
    domain="$1"
    if ping -c2 ldap.$domain > /dev/null 2>&1; then
	echo ldap://ldap.$domain
    else
	host=$(host -N 2 -t SRV _ldap._tcp.$domain | egrep -v 'NXDOMAIN|^;' | awk '{print $NF}' | head -1)
	if [ "$host" ] ; then
	    echo ldap://$host | sed 's/\.$//'
	fi
    fi
}

lookup_ldap_base() {
    ldapuri="$1"
    defaultcontext="$(ldapsearch -LLL -H "$ldapuri" -x -b '' -s base defaultNamingContext  2>/dev/null | awk '/^defaultNamingContext: / { print $2}')"
    if [ -z "$defaultcontext" ] ; then
	# If there are several contexts, pick the first one with
	# posixAccount or posixGroup objects in it.
	for context in $(ldapsearch -LLL -H "$ldapuri" -x -b '' \
	    -s base namingContexts 2>/dev/null | \
	    awk '/^namingContexts: / { print $2}') ; do
	    if ldapsearch -LLL -H $ldapuri -x -b "$context" -s sub -z 1 \
	        '(|(objectClass=posixAccount)(objectclass=posixGroup))' 2>&1 | \
	        perl -p0e 's/\n //g' | \
		egrep -q '^dn:|^Administrative limit exceeded' ; then
		echo $context
		return
	    fi
	done
    fi
    echo $defaultcontext
}

lookup_kerberos_server() {
    domain="$1"
    if ping -c2 kerberos.$domain > /dev/null 2>&1; then
	echo kerberos.$domain
    else
	host=$(host -t SRV _kerberos._tcp.$domain | grep -v NXDOMAIN | awk '{print $NF}'|head -1)
	if [ "$host" ] ; then
	    echo $host | sed 's/\.$//'
	fi
    fi
}

lookup_kerberos_realm() {
    domain="$1"
    realm=$(host -t txt _kerberos.$domain | grep -v NXDOMAIN | awk '{print $NF}'|head -1|tr -d '"')
    if [ -z "$realm" ] ; then
	realm=$(echo $domain | tr a-z A-Z)
    fi
    echo $realm
}

ldap_is_active_directory() {
    ldapuri="$1"
    # OpenLDAP do not have defaultNamingContext in the root LDAP
    # object, while Active Directory do.
    if ldapsearch -LLL -H "$ldapuri" -x -b '' -s base 2>/dev/null | \
	grep -q defaultNamingContext ; then
	true
    else
	false
    fi
}

find_dns_domain() {
    if [ "$1" ] ; then
	domain=$1
    else
	domain="$(hostname -d 2>/dev/null || true)"
	# If hostname is not FQDN, look in DNS setup instead, to
	# increase the chance of the automatic setup to work.
	if [ -z "$domain" ] || [ "(null)" = "$domain" ] || [ "localdomain" = "$domain" ]; then
	    domain=$(grep search /etc/resolv.conf |awk '{print $2}')
	fi
    fi
    echo $domain
}

generate_sssd_config() {
    domain=$(find_dns_domain "$1")
    kerberosrealm=$(lookup_kerberos_realm $domain)
    ldapuri=$(lookup_ldap_uri "$domain")
    if [ -z "$ldapuri" ];  then
	# autodetection failed
	return
    fi

    ldapbase="$(lookup_ldap_base "$ldapuri")"
    if [ -z "$ldapbase" ];  then
	# autodetection failed
	return
    fi
    kerberosserver=$(lookup_kerberos_server "$domain")

cat <<EOF
# SSSD configuration generated using $0
[sssd]
config_file_version = 2
reconnection_retries = 3
sbus_timeout = 30
services = nss, pam, autofs
domains = $domain

[nss]
filter_groups = root
filter_users = root
reconnection_retries = 3

[pam]
reconnection_retries = 3

[autofs]
EOF
if [ "$kerberosserver" ] ; then
    auth="krb5"
    chpass="krb5"
else
    auth="ldap"
    chpass="ldap";
fi

if ldap_is_active_directory $ldapuri ; then
    cat <<EOF

[domain/$domain]
ldap_id_mapping = True
ldap_schema = ad
EOF
else
    cat <<EOF

[domain/$domain]
; Using enumerate = true leads to high load and slow response
enumerate = false
cache_credentials = true

id_provider = ldap
auth_provider = $auth
chpass_provider = $chpass

ldap_uri = $ldapuri
ldap_search_base = $ldapbase
ldap_tls_reqcert = demand
ldap_tls_cacert = /etc/ssl/certs/ca-certificates.crt
EOF

    if [ "$kerberosserver" ] ; then
	cat <<EOF

krb5_server = $kerberosserver
krb5_realm = $kerberosrealm
krb5_changepw_principle = kadmin/changepw
krb5_auth_timeout = 15
EOF
    fi
fi
}

generate_krb5_config() {
    dnsdomain=$(find_dns_domain "$1")
    kerberosrealm=$(lookup_kerberos_realm $dnsdomain)
    kerberosserver=$(lookup_kerberos_server "$dnsdomain")
    error=0
    if [ -z "$kerberosserver" ] || [ "reached" = "$kerberosserver" ] ; then
	# autodetection failed, use defaults to avoid ending up with
	# an empty file.
	# Use defaults, too, if DNS failed (offline installation),
	# cause all vars are set to 'reached' in this case.
	dnsdomain=intern
	kerberosrealm=INTERN
	kerberosserver=kerberos
	error=1
    fi
    # setup content based on krb5-config version 2.3
cat <<EOF
# Generated using $0 -k
[libdefaults]
	default_realm = $kerberosrealm

# The following krb5.conf variables are only for MIT Kerberos.
	krb4_config = /etc/krb.conf
	krb4_realms = /etc/krb.realms
	kdc_timesync = 1
	ccache_type = 4
	forwardable = true
	proxiable = true

# The following encryption type specification will be used by MIT Kerberos
# if uncommented.  In general, the defaults in the MIT Kerberos code are
# correct and overriding these specifications only serves to disable new
# encryption types as they are added, creating interoperability problems.
#
# Thie only time when you might need to uncomment these lines and change
# the enctypes is if you have local software that will break on ticket
# caches containing ticket encryption types it doesn't know about (such as
# old versions of Sun Java).

#	default_tgs_enctypes = des3-hmac-sha1
#	default_tkt_enctypes = des3-hmac-sha1
#	permitted_enctypes = des3-hmac-sha1

# The following libdefaults parameters are only for Heimdal Kerberos.
	v4_instance_resolve = false
	v4_name_convert = {
		host = {
			rcmd = host
			ftp = ftp
		}
		plain = {
			something = something-else
		}
	}
	fcc-mit-ticketflags = true

[realms]
	$kerberosrealm = {
		kdc = $kerberosserver
		admin_server = $kerberosserver
	}

[domain_realm]
        $dnsdomain = $kerberosrealm
        .$dnsdomain = $kerberosrealm

[login]
	krb4_convert = true
	krb4_get_tickets = false

EOF
	return $error
}

if [ "-k" = "$1" ] ; then
    shift
    generate_krb5_config "$@"
else
    generate_sssd_config "$@"
fi
