#!/bin/sh

network_file=/etc/sysconfig/network
system_file=/etc/sysconfig/system
resolvconf=/sbin/resolvconf
resolvconf_conf=/etc/resolvconf.conf
resolv_conf=/etc/resolv.conf
samba_tool=/usr/bin/samba-tool
max_hostname_length=64
alterator_api_version=1

. alterator-sh-functions
. avahi-sh-functions
. shell-config
. shell-var
. shell-ini-config
. shell-quote
. alterator-openldap-functions
. alterator-service-functions
. ipa-sh-functions

test_resolver()
{
	cat "$resolv_conf" | grep -qs '^nameserver 127\.0\.0\.1'
	if [ $? -ne 0 ]; then
		echo "ERROR: nameserver 127.0.0.1 not present in resolv.conf"
	else
		nameserver="$(grep -s '^nameserver' "$resolv_conf" | head -1)"
		if echo $nameserver | grep -qs '127\.0\.0\.1' ; then
			echo "OK"
		else
			echo "ERROR: 127.0.0.1 is not the first nameserver in resolv.conf"
		fi
	fi
}

test_access()
{
	ping -c 1 "$(read_hostname)" >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo "ERROR: FQDN is unpingable"
	else
		echo "OK"
	fi
}

## FIXME: password in the command line
test_ldap()
{
	fqdn="$(read_hostname)"
	domain="${fqdn#*.}"
	dn="$(host_2_dn "$domain")"

	local _ldap_dn="$(which ldap-dn 2>/dev/null ||:)"
	if [ -z "$_ldap_dn" ]; then
		echo "ERROR: No ldap-dn tool found"
		return 1
	fi
	
	slapd_conf="$($_ldap_dn find "$dn")"
	if [ $? -ne 0 -o -z "$slapd_conf" ]; then
		echo "ERROR: no slapd conffile for dn: '$dn'"
		return 1
	fi
	slapd_rootpw="$(grep "^rootpw" "$slapd_conf" | sed -e 's,^rootpw ,,')"
	if [ -z "$slapd_rootpw" ] ;then
		echo "ERROR: no rootpw specified"
		return 1
	fi
	slapd_rootdn="$(grep "^rootdn" "$slapd_conf" | sed -e 's,^rootdn ,,' | sed -e "s,\",,g")"
	if [ -z "$slapd_rootdn" ] ; then
		echo "ERROR: no rootdn specified"
		return 1
	fi

	local _ldapsearch="$(which ldapsearch 2>/dev/null ||:)"
	if [ -z "$_ldapsearch" ]; then
		echo "ERROR: No ldapsearch tool found"
		return 1
	fi

	"$_ldapsearch" -x -H "ldaps://$fqdn" -b "$dn" -D "$slapd_rootdn" -w"$slapd_rootpw" >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo "ERROR: Connect to ldaps://$fqdn failed"
		return 1
	fi

	"$_ldapsearch" -x -H "ldaps://$fqdn" -b "$dn" -D "$slapd_rootdn" -w"$slapd_rootpw" ou=People | grep -v "^#" | grep "ou: People" > /dev/null 2>&1
	if [ $? -eq 0 ]; then
		echo "OK"
	else
		echo "ERROR: Failed to ldapsearch ou=People -- slapd is broken"
	fi
}

## FIXME: password in the command line
test_kdc()
{
	if ! service_control 'krb5kdc' is-active 1>/dev/null 2>&1; then
		echo "ERROR: krb5kdc service is stopped"
	fi
    
	fqdn="$(read_hostname)"
	domain="${fqdn#*.}"
	dn="$(host_2_dn "$domain")"

	local _ldap_dn="$(which ldap-dn 2>/dev/null ||:)"
	if [ -z "$_ldap_dn" ]; then
		echo "ERROR: No ldap-dn tool found"
		return 1
	fi
	
	slapd_conf="$($_ldap_dn find "$dn")"
	if [ $? -ne 0 -o -z "$slapd_conf" ]; then
		echo "ERROR: No slapd conffile for dn: '$dn'"
		return 1
	fi
	slapd_rootpw="$(grep "^rootpw" "$slapd_conf" | sed -e 's,^rootpw ,,')"
	slapd_rootdn="$(grep "^rootdn" "$slapd_conf" | sed -e 's,^rootdn ,,' | sed -e "s,\",,g")"

	local _ldapsearch="$(which ldapsearch 2>/dev/null ||:)"
	if [ -z "$_ldapsearch" ]; then
		echo "ERROR: No ldapsearch tool found"
		return 1
	fi
	
	"$_ldapsearch" -x -h localhost -b "$dn" -D "$slapd_rootdn"  "ou=kdcroot" -w"$slapd_rootpw" | grep -v "^#" | grep "ou: kdcroot" > /dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo "ERROR: Failed to ldapsearch ou=kdcroot -- no KDC base in LDAP"
		return 1
	fi

	"$_ldapsearch" -x -h localhost -b "$dn" -D "$slapd_rootdn" "objectClass=krbRealmContainer" -w"$slapd_rootpw" | grep -v "^#" | grep "objectClass: krbRealmContainer" >/dev/null 2>&1
	if [ $? -eq 0 ]; then
		echo "OK"
	else
		echo "ERROR: Failed to ldapsearch objectClass=krbRealmContainer -- no realm container in LDAP"
	fi
}

test_smb()
{
	if service_control 'smb' is-active 1>/dev/null 2>&1; then
		workgroup=
		if [ -e "/etc/samba/smb.conf" ]; then
			workgroup="$(ini_config_get /etc/samba/smb.conf global workgroup 2>/dev/null)"
		fi
		if [ -n "$workgroup" ]; then
			echo "OK ($workgroup)"
		else
			echo "ERROR: No workgroup is set"
		fi
	else
		echo "ERROR: smbd service is stopped"
	fi
}

test_dhcpd()
{
	fqdn="$(read_hostname)"
	domain="${fqdn#*.}"
	grep -qs "option domain-name \"$domain\";" /etc/dhcp/dhcpd.conf
	if [ $? -ne 0 ]; then
		echo "ERROR: Domain name $domain is not provided to clients"
		return 1
	fi
	grep -qs "option domain-name-servers" /etc/dhcp/dhcpd.conf
	if [ $? -ne 0 ]; then
		echo "ERROR: Domain server is not provided to clients"
		return 1
	else
		echo "OK"
	fi
}

check_hostname()
{
    local hn="$1"

    # Check valid hostname according RFC 1035
    if ! echo "$hn" | egrep '^([a-zA-Z]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?$'; then
        write_error "$(_ 'Domain name is not valid according to RFC 1035')"
        return 1
    fi

    return 0
}

read_hostname()
{
    local value="$(shell_config_get "$network_file" HOSTNAME)"
    [ -n "$value" ] || value="localhost.localdomain"
    echo "$value"
}

read_forwarders()
{
	local forwarders=
	# Get preinstalled from smb.conf
	forwarders=
	if [ -e "/etc/samba/smb.conf" ]; then
		forwarders="$(ini_config_get /etc/samba/smb.conf global 'dns forwarder' 2>/dev/null)"
	fi
	echo "$forwarders"
}

read_domain()
{
    local value="$(read_hostname)"
    local domain="${value#*.}"
    [ "$value" != "$domain" ] || domain="localdomain"

    # Check AD domain
    if [ "$(read_domain_type)" = 'ad' ]; then
        domain="$($samba_tool domain info '127.0.0.1' | sed 's/ *: /:/' | sed -n 's/^Domain://p')"
    fi

    echo "$domain"
}

write_domain()
{
    local old_value="$(read_hostname)"
    local old_name="${old_value%%.*}"
    local new_value="$old_name.$1"

    check_hostname "$new_value" || return 1
    shell_config_set "$network_file" HOSTNAME "$new_value"
    hostname "$new_value"
    domainname "${new_value#*.}"

    if [ -e "$resolvconf_conf" ]; then
	    local search_eregexp1="^search_domains=([\"']|.+[[:blank:]])?"
	    local search_eregexp2="([\"']|[[:blank:]].+)?$"
	    local old_domain="${old_value#*.}"
	    if egrep -qs "$search_eregexp1$old_domain$search_eregexp2" "$resolvconf_conf"; then
		    sed -i -r "s;$search_eregexp1$old_domain$search_eregexp2;search_domains=\1$1\2;" "$resolvconf_conf"
	    elif ! egrep -qs "$search_eregexp1$1$search_eregexp2" "$resolvconf_conf"; then
		    local search_domains="$(shell_config_get "$resolvconf_conf" search_domains)"
		    shell_var_unquote search_domains "$search_domains"
		    search_domains="$1${search_domains:+ }$search_domains"
		    shell_config_set "$resolvconf_conf" search_domains "\"$search_domains\""
	    fi
	    "$resolvconf" -u
    else
	    # if resolvconf is not installed then
	    # write in the resolv.conf file directly
	    shell_config_set "$resolv_conf" domain "$1" ' ' ' '
    fi
    run-parts /etc/hooks/hostname.d "$old_value" "$new_value"

    return 0
}

read_role()
{
    shell_config_get "$system_file" SERVER_ROLE
}

read_domain_type()
{
    local domain_type='dns'

    # Check ALT domain
    if [ "$(read_role)" = 'master' ];then
	    domain_type='altdomain'
    fi

    # Check Samba AD DC
    if service_control 'samba' is-enabled 1>/dev/null 2>&1; then
	    domain_type='ad'
    fi

	# Check IPA
	if ipa_install_running; then
		domain_type='ipa'
	elif ipa_installed; then
		if service_control 'ipa' is-enabled 1>/dev/null 2>&1; then
			domain_type='ipa'
		fi
	fi

    echo "$domain_type"
}

write_role()
{
    local old_server_role="$(read_role)"
    local new_server_role="$1";shift
    if [ "$old_server_role" != "$new_server_role" ]; then
	    shell_config_set "$system_file" SERVER_ROLE "$new_server_role"
    fi
    export old_server_role
    export new_server_role
    run-parts /usr/lib/alterator/hooks/net-domain.d
}

## https://www.altlinux.org/ActiveDirectory/DC
ad_provision_domain()
{
    local domain_name="$1"
    shift
    local log="/tmp/samba-dc-provision-$(date +%d.%m.%Y-%H:%M:%S)-$domain_name.log"

    # Begin log
    date > "$log"
    echo "Domain: $domain_name" >> "$log"
    echo >> "$log"

    # Cleanup old domain
    rm -fv /etc/samba/smb.conf       >> "$log" 2>&1
    rm -rfv /var/lib/samba           >> "$log" 2>&1
    mkdir -pv /var/lib/samba/sysvol  >> "$log" 2>&1

	# Cleanup KRB5 conf
	sed -i -e '/^[[:space:]]*includedir[[:space:]]\+\/var\/lib\/sss\// s/^[[:space:]]*includedir[[:space:]]/#&/' /etc/krb5.conf  >> "$log" 2>&1
	ini_config_del /etc/krb5.conf 'realms'
	ini_config_del /etc/krb5.conf 'domain_realm'
	ini_config_del /etc/krb5.conf 'dbmodules'

    # Stop and disable any conflict services
    for service in smb nmb krb5kdc slapd bind ipa
    do
		service_control "$service" stop/off  1>> "$log" 2>&1
		if service_exists "$service"; then
			service_wait "$service"  1>> "$log" 2>&1
		fi
    done

    # Make provision
    read -r -d '' o <<EOF
$samba_tool domain provision \
	--realm  "$domain_name" \
	--domain "${domain_name%%.*}" \
	--dns-backend=SAMBA_INTERNAL \
	--server-role=dc \
	--use-rfc2307
EOF
	echo "$o" >> "$log"
	echo >> "$log"

	(
		ret=0
		eval "$o" 2>&1 || ret=$?
		if [ $ret -eq 0 ]; then
			echo "SUCCESS"
		else
			echo "ERROR ($ret)"
		fi
	) | grep -v '^Admin[[:space:]]\+password:' >>"$log.process"

	ret=0
	if tail -1 "$log.process" | grep -q '^ERROR'; then
		ret=1
	fi

	# Merge logs
	cat "$log.process" >> "$log"
	rm -f "$log.process"

	if [ $ret -ne 0 ]; then
		write_error "$(_ 'Error provisioning the Active directory domain. Log is in') $log"
		service_control 'samba' stop  1>>"$log" 2>&1
		service_control 'samba' off   1>>"$log" 2>&1
	else
		service_control 'samba' on 1>>"$log" 2>&1
		service_control 'samba' restart
		service_wait 'samba'
	fi

	echo "Finished at $(date)" >>"$log"
}

ipa_service_report() {
	local _ipactl="$(which ipactl 2>/dev/null ||:)"
	[ -n "$_ipactl" ] || return 1

	#local domain="$(read_domain)"
	
	$_ipactl status 2>/dev/null | ( \
		ldap=off; krb=off; kadmin=off; named=off;
		cache=off; web=off; pki=off; custodia=off;
		otpd=off
		while read ln; do
			status=off
			case "$ln" in
				*:\ RUNNING*)
					status=on
					;;
			esac
			
			case "$ln" in
				Directory\ *Service:*)
					ldap="$status"
					;;
				krb5kdc\ *Service:*)
					krb="$status"
					;;
				kadmin\ *Service:*)
					kadmin="$status"
					;;
				named\ *Service:*)
					named="$status"
					;;
				ipa_memcached\ *Service:*)
					cache="$status"
					;;
				httpd\ *Service:*)
					web="$status"
					;;
				pki-tomcatd\ *Service:*)
					pki="$status"
					;;
				ipa-custodia\ *Service:*)
					custodia="$status"
					;;
				ipa-otpd\ *Service:*)
					otpd="$status"
					;;
				*\ Service:*)
					name="$(echo "${ln%%\ *}" | tr '.-' '_')"
					name="${name#ipa_}"
					write_bool_param "ipa_${name}_status" "$status"
					;;
			esac
		done

		# if [ "$ldap" = 'on' ]; then
		# 	local config="$(_dse_ldif "$domain")"
		# 	if [ -z "$config" ]; then
		# 		ldap='off'
		# 	fi
		# fi

		write_bool_param "ipa_ldap_status" "$ldap"
		write_pred_param "ipa_krb_status" [ "$krb" = "on" -a "$kadmin" = "on" ]
		write_bool_param "ipa_cache_status" "$cache"
		write_bool_param "ipa_web_status" "$web"
		write_bool_param "ipa_pki_status" "$pki"
		write_bool_param "ipa_named_status" "$named"
		write_bool_param "ipa_custodia_status" "$custodia"
		write_bool_param "ipa_otp_status" "$otpd"
	)
}
	
# usage: test_netservice <addr regexp> [program name]
test_netservice() {
	local addr="$1"
	local name="${2:-}"
	netstat -tlpn | \
		grep -q "[[:space:]]$addr[[:space:]].*${name:+/$name}[[:space:]]*\$"
}

test_ipa_krb() {
	test_netservice '0\.0\.0\.0:88' krb5kdc && \
		test_netservice '0\.0\.0\.0:464' kadmind && \
		test_netservice '0\.0\.0\.0:749' kadmind
}

test_ipa_ldap() {
	test_netservice ':::636' ns-slapd && \
		test_netservice ':::389' ns-slapd
}

test_ipa_named() {
	local myaddr="$(host `hostname` | sed -e 's/.*[[:space:]]//')"
	test_netservice '0\.0\.0\.0:53' named || \
		test_netservice '127\.0\.0\.1:53' named && \
			test_netservice "$(quote_sed_regexp "$myaddr"):53" named
}

test_ipa_web() {
	test_netservice ':::80' httpd2 && \
		test_netservice ':::443' httpd2 && \
		test_netservice ':::8090' java && \
		test_netservice ':::8443' java
}

write_pred_param() {
	local pname="$1"; shift
	write_bool_param "$pname" \
					 $("$@" 1>/dev/null 2>&1 && echo 'on' || echo 'off')
}

# args: domain
_dirsrv_slapd_dir() {
	local domain="$1"
	local upper="$(echo "$domain" | tr '[:lower:]' '[:upper:]' | sed -e 's/\./-/g')"
	local dir="/etc/dirsrv/slapd-$upper"
	if [ -n "$dir" -a -d "$dir" ]; then
		echo "$dir"
		return 0
	else
		return 1
	fi
}

# args: domain
clear_dirsrv_slapd() {
	local domain="$1"
	local dir="$(_dirsrv_slapd_dir "$domain")"

	if [ -n "$dir" ]; then
		rm -rf "$dir"
	fi
}

# args: domain
_dse_ldif() {
	local domain="$1"
	local dir="$(_dirsrv_slapd_dir "$domain")"

	local config=
	if [ -n "$dir" ]; then
		config="$dir/dse.ldif"
	fi
	
	if [ -n "$config" -a -e "$config" ]; then
		echo "$config"
		return 0
	else
		return 1
	fi
}

require_ldap_schema() {
    local schema="$1"

    test -r "/etc/openldap/schema/$schema.schema" || return 1

    local r1="include\s+/etc/openldap/schema/$schema\.schema"
    local r2="include	/etc/openldap/schema/$schema.schema"

    sed -i -r "s,^#($r1)\s*$,\1," "$SLAPD_CONF"
    grep -qE "^$r1\s*$" "$SLAPD_CONF" || echo "$r2" >> "$SLAPD_CONF"
}

# check and setup required schema's and turn off default openldap database
prepare_alt_domain() {
    require_ldap_schema samba && require_ldap_schema kerberos || return $?
    sed -i -r "s,^(include\s.*[hm]db-db01\.conf)\s*$,#\1," "$SLAPD_CONF" ||:
}

# FIXME: Password in the command line
reset_ipa_password() {
	local domain="$1"
	local pass="$2"
	local config="$(_dse_ldif "$domain")"

	[ -n "$config" ] || return 1

	(
		set -e
		_stop_dirsrv="$(which stop-dirsrv 2>/dev/null ||:)"
		_start_dirsrv="$(which start-dirsrv 2>/dev/null ||:)"
		_ldappasswd="$(which ldappasswd 2>/dev/null ||:)"
		_pwdhash="$(which pwdhash 2>/dev/null ||:)"
		[ -n "$_stop_dirsrv" -a -n "$_start_dirsrv" -a -n "$_ldappasswd" -a -n "$_pwdhash" ] || exit 1
		"$_stop_dirsrv" 2>/dev/null
		sed -i -e "/^nsslapd-rootpw:/,/^[^[:space:]]/ { s/^nsslapd-rootpw:.*\$/nsslapd-rootpw: $(quote_sed_regexp "$("$_pwdhash" "$pass")")/; /^[[:space:]]/ d; }" "$config"
		"$_start_dirsrv" 2>/dev/null
		"$_ldappasswd" -h localhost -ZZ -D 'cn=Directory Manager' -w "$pass" -s "$pass" 'uid=admin,cn=users,cn=accounts,dc=td,dc=vm,dc=basealt,dc=ru'
	)
}

cleanup_bind() {
	sed -i -e '/^[[:space:]]*dynamic-db[[:space:]]\+"ipa"[[:space:]]\+{/,/^[[:space:]]*}/ d' /etc/bind/named.conf
	control bind-chroot enabled
	control bind-caps enabled
}

cleanup_smbconf() {
	if [ -e "/etc/samba/smb.conf" ]; then
		ini_config_del '/etc/samba/smb.conf' global 'server role'
	fi
}

restore_configs() {
	default-restore krb5
}

on_message() {
  case "$in_action" in
    type)
	    write_type_item 'domain'                 'hostname'
		write_type_item 'altdomain_available' 'boolean'
		write_type_item 'ad_available'        'boolean'
		write_type_item 'ipa_available'       'boolean'
		write_type_item 'ipa_installed'          'boolean'
		write_type_item 'ipa_uninstalled'        'boolean'
		write_type_item 'ipa_install_target'     'string'
		write_type_item 'ipa_install_progress'   'integer'
		write_type_item 'ipa_install_message'    'string'
		write_type_item 'ipa_install_running'    'boolean'
		write_type_item 'ipa_install_exitcode'   'integer'

		write_type_item 'ipa_pki_status'         'boolean'
		write_type_item 'ipa_web_status'         'boolean'
		write_type_item 'ipa_named_status'       'boolean'
		write_type_item 'ipa_cache_status'       'boolean'
		write_type_item 'ipa_ldap_status'        'boolean'
		write_type_item 'ipa_krb_status'         'boolean'
		write_type_item 'ipa_custodia_status'    'boolean'
		write_type_item 'ipa_otp_status'         'boolean'
		
		write_type_item 'ipa_web_uri'            'string'
	    ;;
    read)
	    write_string_param domain "$(read_domain)"
	    local role="$(read_role)"
	    # Return current domain type
		_domain_type="$(read_domain_type)"
	    write_string_param domain_type "$_domain_type"

	    # Status of ALT domain and DNS
	    write_string_param resolver "$(test_resolver)"
	    write_string_param access "$(test_access)"
	    write_string_param ldap "$(test_ldap)"
	    write_string_param kdc "$(test_kdc)"
	    write_string_param smb "$(test_smb)"
	    write_string_param dhcpd "$(test_dhcpd)"
	    write_pred_param master [ "$role" = "master" ]

	    # Active Directory DC status
	    local ad_service="inactive"
	    if service_control 'samba' is-active 1>/dev/null 2>&1; then
		    ad_service="OK"
		    if service_control 'bind' is-active 1>/dev/null 2>&1; then
			    ad_service="$(_ 'NOT OK (bind is running)')"
		    fi
		    # Read configuration
		    ad_status_string="$((net ads info '127.0.0.1'; $samba_tool domain info '127.0.0.1') | sed 's/ *: /:/')"
		    local ad_domain="$(echo "$ad_status_string" | sed -n 's/^Domain://p')"
		    local ad_realm="$(echo "$ad_status_string" | sed -n 's/^Realm://p')"
		    local ad_dc_name="$(echo "$ad_status_string" | sed -n 's/^DC name://p')"
		    local ad_ldap_ip="$(echo "$ad_status_string" | sed -n 's/^LDAP server://p')"
		    local ad_ldap_server="$(echo "$ad_status_string" | sed -n 's/^LDAP server name://p')"
		    local ad_kdc_server="$(echo "$ad_status_string" | sed -n 's/^KDC server://p')"
	    else
		    ad_service="%(_ 'NOT OK (samba service is stopped)')"
	    fi

	    local forwarders="$(read_forwarders)"
	    if [ "${forwarders:-127.0.0.1}" = "127.0.0.1" ]; then
		    # Get initial value from resolvconf
		    forwarders="$($resolvconf -l | sed -n 's/^nameserver //p' | head -n1)"
	    fi

	    write_string_param ad_dns "$forwarders"
	    write_string_param ad_service "${ad_service:---}"
	    write_string_param ad_domain "${ad_domain:---}"
	    write_string_param ad_realm "${ad_realm:---}"
	    write_string_param ad_dc_name "${ad_dc_name:---}"
	    test -n "$ad_ldap_ip" && ad_ldap_server="$ad_ldap_server ($ad_ldap_ip)"
	    write_string_param ad_ldap_server "${ad_ldap_server:---}"
	    write_string_param ad_kdc_server "${ad_kdc_server:---}"

		# IPA
		write_pred_param 'ipa_installed' ipa_installed
		write_pred_param 'ipa_uninstalled' ipa_uninstalled

		_ipa_install_exitcode="$(ipa_install_exitcode)"

		if ipa_install_running || [ "$_ipa_install_exitcode" -ne 0 ]; then
			ipa_install_status | (
				read target progress message
				case "$target" in
					I) target="install";;
					U) target="uninstall";;
				esac
				write_string_param 'ipa_install_target' "$target"
				write_string_param 'ipa_install_progress' ${progress%\%}
				write_string_param 'ipa_install_message' "$message"
			)
			if ipa_install_running; then
				write_bool_param 'ipa_install_running' 'on'
			else
				write_bool_param 'ipa_install_running' 'off'
				write_string_param 'ipa_install_exitcode' "$_ipa_install_exitcode"
			fi
		else
			write_bool_param 'ipa_install_running' 'off'
		fi

		# IPA services availability
		if [ "$_domain_type" = 'ipa' ]; then
			if ! ipa_install_running; then
				ipa_service_report ||:
				if test_ipa_web; then
					write_string_param 'ipa_web_uri' "https://$(host `hostname` | sed -e 's/.*[[:space:]]//')/"
				fi
			fi
		fi

	    # Check availability of domain types
		write_pred_param 'altdomain_available' rpm -q alt-domain-server
        write_pred_param 'ad_available' rpm -q samba-dc
		write_pred_param 'ipa_available' rpm -q freeipa-server freeipa-server-dns
	    ;;
    write)
	    if [ "$in__objects" = "restore_configs" ]; then
			restore_configs
			return
	    fi
	    # Variables:
	    # $in_domain - domain name
	    # $in_domain_type - domain type (altdomain, ad, dns)
	    if [ -z "$in_domain" ]; then
			write_error "$(_ 'Please define a domain name')"
			return
	    elif echo "$in_domain" | egrep -iwqs "localdomain|localhost|local"; then
	        write_error "$(_ 'This name is registered for internal purposes')"
	        return
	    fi

	    # ALT Domain or DNS
	    if [ "$in_domain_type" = 'altdomain' -o  "$in_domain_type" = 'dns' ]; then
			if ipa_install_running; then
				ipa_install_stop
			fi
			
		    service_control 'samba' stop/off  2>/dev/null
			service_control 'ipa'   stop/off  2>/dev/null
			service_wait 'samba' && service_wait 'ipa'

			cleanup_bind
			cleanup_smbconf
			
		    # Note: write_role should be before write_domain, hooks can use server role value
		    if [ "$in_domain_type" = 'altdomain' ]
			then
			    rpm -q alterator-openldap &>/dev/null || {
				write_error "$(_ 'alterator-openldap package is not installed')"
				return
			    }
			    rpm -q samba &>/dev/null || {
				write_error "$(_ 'samba package is not installed')"
				return
			    }
			    prepare_alt_domain || {
				write_error "$(_ 'required schema file not found')"
				return
			    }
			    role=master
			    service_control 'slapd'   on/start
			    service_control 'krb5kdc' on/start
			else
			    role=none
			    service_control 'slapd'   stop/off
			    service_control 'krb5kdc' stop/off
			    service_control 'smb'     stop/off
			    service_control 'samba'   stop/off
		    fi
			
		    write_role "$role"
		    write_domain "$in_domain" "1" && \
		        publish_service alterator-net-domain 'ALT Linux Server (%h)' '_server._tcp' '0' "role=$(read_role)" "domain=$(read_domain)"

			if service_control 'bind' is-active; then
				service_control 'bind'  restart  2>/dev/null
				service_control 'bind'  on       2>/dev/null
			else
				service_control 'bind'  on/start  2>/dev/null
			fi
	    fi

	    # Active Directory
	    if [ "$in_domain_type" = 'ad' ]; then
			if ipa_install_running; then
				ipa_install_stop
			fi
			
		    env > /tmp/net-domain.txt
		    ad_current_domain="$($samba_tool domain info '127.0.0.1' | sed 's/ *: /:/' | sed -n 's/^Domain://p')"
			
		    # Check creation of existing domain
		    if [ "$ad_current_domain" != "$in_domain" ]; then
			    write_domain "$in_domain" "1"
			    ad_provision_domain "$in_domain"
		    fi

		    # Set dns forwarders
		    # Samba 4.5 and later supports a space-sparated list of IPs. Older versions support only one IP.
		    if [ -n "$in_ad_dns" -a "$in_ad_dns" != "$(read_forwarders)" ]; then
			    ini_config_set '/etc/samba/smb.conf' global 'dns forwarder' "$in_ad_dns"
			    service_control 'samba' reload
		    fi

		    # Set Administrator password
            ## FIXME: password in the command line
		    if [ -n "$in_ad_password" ]; then
				err="$($samba_tool user setpassword Administrator --newpassword="$in_ad_password" 1>/dev/null 2>&1)"
				if [ -n "$err" ]; then
                    case "$err" in
                        *the\ password\ is\ too\ short*)
                            err="$(_ 'The password is too short. It should be equal or longer than 7 characters!')"
                            ;;
                        *the\ password\ does\ not\ meet\ the\ complexity\ criteria*)
                            err="$(_ 'The password does not meet the complexity criteria (must contain characters from three of the following five categories: latin letters in upper and lower cases, digits, nonalphanumeric and any other Unicode characters)!')"
					esac
					write_error "$(_ 'Error setting password for Administrator:') $err"
				fi
				$samba_tool user setexpiry --noexpiry Administrator	
		    fi
	    fi

		# IPA
	    if [ "$in_domain_type" = 'ipa' ] && ! ipa_install_running; then
			_old_domain="$(hostname -d)"

			if ! ipa_installed || [ "$_old_domain" != "$in_domain" ]; then
				if [ -z "$in_ipa_password" ]; then
					write_error "$(_ 'Password should not be empty')"
					return
				fi
					
				service_control 'samba'   stop/off  2>/dev/null
				service_control 'slapd'   stop/off  2>/dev/null
				service_control 'krb5kdc' stop/off  2>/dev/null
				service_wait 'samba' && service_wait 'slapd' && \
					service_wait 'krb5kdc'
					
				write_role 'none' # FIXME
				write_domain "$in_domain"

				clear_dirsrv_slapd "$in_domain"
				ipa_install_prepare

				## FIXME: password in the command line
				ipa_install_run_default "$in_domain" "$in_ipa_password" || \
					write_error "$(_ 'Failed to start the IPA installer')"
			elif [ -n "$in_ipa_password" ]; then
				if [ -z "$(_dse_ldif "$(read_domain)")" ]; then
					write_error "$(_ 'LDAP service is not running')"
				else
					reset_ipa_password "$in_domain" "$in_ipa_password" || \
						write_error "$(_ 'Password change failed')"
				fi
			else
				service_control 'ipa' on
				service_start_wait 'ipa' restart
			fi
		fi
	    ;;
	stop_ipa)
		if ipa_install_running; then
			ipa_install_stop
		fi
		;;
  esac
}

message_loop
