#!/bin/sh

. shell-error

kdc_uses_ldap=${KDC_USE_LDAP:=1}

kdc_root=/var/lib/kerberos/krb5kdc

krb5_conf=/etc/krb5.conf
kdc_conf="$kdc_root/kdc.conf"
acl_file="$kdc_root/kadm5.acl"
admin_keytab="$kdc_root/kadm5.keytab"

ldap_kdc_cn=kdc
ldap_kadmin_cn=kadmin

master_key_type=des-cbc-crc
supported_enctypes='rc4-hmac:normal des-cbc-crc:normal des3-cbc-raw:normal des3-cbc-sha1:normal des-cbc-crc:afs3'

[ -n "$(type -p pwgen)" ] || fatal "pwgen not found"
[ -n "$(type -p kdb5_util)" ] || fatal "kdb5_util not found"
[ -n "$(type -p kdb5_ldap_util)" ] || fatal "kdb5_ldap_util not found"

#---------------------------------------------------------------
domain()
{
    printf '%s\n' "${DOMAINNAME:=$(dnsdomainname)}"
}

realm()
{
    # yeah, that simple
    domain |tr '[[:lower:]]' '[[:upper:]]'
}

ldapconf()
{
    local conf="/etc/openldap/slapd-$(domain).conf"
    [ -f "$conf" ] || fatal "no $conf found"
    [ "$(sed -n '/^suffix/ s/^suffix[[:blank:]]\+\"\([^[:blank:]\"]\+\).\+$/\1/p' $conf)" = "$(suffix)" ] || fatal "unexpected suffix in $conf"
    printf '%s\n' $conf
}

suffix()
{
    printf '%s%s\n' dc= $(domain|sed -e s@\\.@,dc=@g)
}

rootdn()
{
    sed -n '/^rootdn/ s/^rootdn[[:blank:]]\+\"\([^[:blank:]\"]\+\).\+$/\1/p' $(ldapconf)
}

rootpw()
{
    sed -n '/^rootpw/ s/^rootpw[[:blank:]]\([^[:blank:]]\+\)/\1/p' $(ldapconf)
}

#---------------------------------------------------------------
fill_krb_conf()
{
cat << E_O_F
[libdefaults]
default_realm = $(realm)
dns_lookup_realm = true
dns_lookup_kdc = true

[domain_realm]
.$(domain) = $(realm)
$(domain) = $(realm)

$(fill_krb_ldap_conf)
E_O_F
}

fill_acl_file()
{
    printf '*/admin@%s	*\n' $(realm)
}

fill_krb_ldap_conf()
{
[ $kdc_uses_ldap = 0 ] || cat << E_O_F
[dbdefaults]
ldap_kerberos_container_dn = "cn=kerberos,ou=kdcroot,$(suffix)"
[dbmodules]
$(domain) = {
    db_library = kldap
    ldap_kdc_dn = cn=${ldap_kdc_cn},ou=kdcroot,$(suffix)
    ldap_kadmind_dn = cn=${ldap_kadmin_cn},ou=kdcroot,$(suffix)
    ldap_service_password_file = $kdc_root/$(domain).ldapkey
    ldap_servers = ldap://localhost/
    ldap_conns_per_server = 5
}
[realms]
$(realm) = {
    database_module = $(domain)
}
E_O_F
}

fill_kdc_conf()
{
cat << E_O_F
[kdcdefaults]
acl_file = $acl_file
admin_keytab = $admin_keytab

[realms]
$(realm) = {
    master_key_type = $master_key_type
    supported_enctypes = $supported_enctypes
}
[logging]
kdc = SYSLOG:INFO:DAEMON
admin_server = SYSLOG:INFO:DAEMON
E_O_F
}

#---------------------------------------------------------------
dropdb()
{
    find $kdc_root -type f -delete
}

createdb()
{
    if [ $kdc_uses_ldap = 0 ]; then
	createbaredb
    else
	createrole ${ldap_kdc_cn}
	createrole ${ldap_kadmin_cn}
	createldapdb
    fi
}

createbaredb()
{
    kdb5_util create -r $(realm) -s -P $(pwgen -s1)
}

ldapargs()
{
    printf -- '-D %s -w %s -H ldap://localhost/\n' $(rootdn) $(rootpw)
}

createrole()
{
    local cn=$1; shift
    local suffix=$(suffix)
    local passwd=$(pwgen -s1)
    local ldapargs=$(ldapargs)

    printf 'dn: cn=%s,ou=kdcroot,%s\ncn: %s\nsn: %s\nobjectclass: top\nobjectclass: person\nuserpassword: %s\n' \
	$cn $suffix $cn $cn $passwd | ldapadd -x $ldapargs
    printf '%s\n%s' $passwd $passwd |\
	kdb5_ldap_util $ldapargs stashsrvpw -f $kdc_root/$(domain).ldapkey cn=$cn,ou=kdcroot,$suffix
}

createldapdb()
{
    kdb5_ldap_util $(ldapargs) create -subtrees ou=kdcroot,$(suffix) -r $(realm) -s -P $(pwgen -s1)
    touch $kdc_root/principal
}
#---------------------------------------------------------------
update_samba()
{
    local smbconf='/etc/samba/smb.conf'
    local smbpasswd=$(type -p smbpasswd)
    [ -f $smbconf -a -n $smbpasswd ] || return 0
    sed -i \
	-e "/^[[:blank:]]*realm/ s/=.\+$/= $(realm)/" \
	-e "/^[[:blank:]]*ldap[[:blank:]]\+suffix/ s/=.\+$/= $(suffix)/" \
	-e "/^[[:blank:]]*ldap[[:blank:]]\+admin[[:blank:]]\+dn/ s/=.\+$/= $(rootdn)/" \
	$smbconf
    $smbpasswd -w $(rootpw)
}

updateservices()
{
    update_samba
}

#---------------------------------------------------------------
kdcinit()
{
    dropdb
    fill_acl_file > "$acl_file"
    fill_kdc_conf > "$kdc_conf"
    fill_krb_conf > "$krb5_conf"
    createdb
    updateservices
}
