#!/bin/sh -f

alterator_api_version=1

. alterator-sh-functions
. shell-ini-config
. shell-quote
. shell-config
. ldap-config

ldap_config

smb_conf="/etc/samba/smb.conf"
smbldap_conf="/etc/smbldap-tools/smbldap.conf"
smbldap_bind_conf="/etc/smbldap-tools/smbldap_bind.conf"
share_dir="/var/lib/alterator/samba"


#remove parameter synonyms
normalize_conf()
{
    tempfile="$(mktemp -t "alterator-samba.XXX")"
    testparm -s "$smb_conf" 2>/dev/null >"$tempfile" && mv -f "$tempfile" "$smb_conf"
    rm -f "$tempfile"
}

read_share()
{
    local v="$(ini_config_get "$smb_conf" "$1" "$2")"
    echo  "${v:-$3}"
}

read_global()
{
    read_share "global" "$@"
}

write_share()
{
    ini_config_set "$smb_conf" "$1" "$2" "$3"
}

write_share_bool()
{
    if test_bool "$3"; then
	write_share "$1" "$2" "Yes"
    else
	write_share "$1" "$2" "No"
    fi
}

write_global()
{
    write_share "global" "$1" "$2"
}

add_share()
{
cat >>$smb_conf<<EOF
[$1]
    create mask = 0744
EOF
}

del_share()
{
    ini_config_del "$smb_conf" "$1"
}

list_share()
{
    sed -n 's/^[[:space:]]*\[\([^]]\+\)].*/\1/p' "$smb_conf"|
	grep -v '^\(printers\|global\|homes\)$'|
	sort
}

no_share()
{
    ! grep -qs "^[[:space:]]*\[$(quote_sed_regexp "$1")\]" "$smb_conf"
}

rename_share()
{
    sed "s/^\([[:space:]]*\)\[$(quote_sed_regexp "$1")\]/\1[$2]/" \
	-i "$smb_conf"
}


### high level

write_bool_name()
{
    local v="$(read_share "$@")"
    if [ "$(write_bool "$v")" = "#t" ];then
	echo "`_ 'Yes'`"
    else
	echo "`_ 'No'`"
    fi
}

# Openldap integration -- procedures
ldap_enable()
{
	egrep -q '^[[:space:]]+passdb backend[[:space:]]+=[[:space:]]+ldapsam' "$smb_conf"
}

list_dbprofile()
{
   if ldap_enable ;then
    	write_enum_item "ldap" "`_ 'LDAP'`"
    	write_enum_item "local" "`_ 'Local files'`"
   else
    	write_enum_item "local" "`_ 'Local files'`"
    	write_enum_item "ldap" "`_ 'LDAP'`"
   fi
	
}

change_users_sid()
{
	local sid="$1"
	local user_uid=""
	local user=""
	local uid=""


	/usr/sbin/ldap-getent passwd|
	while read user_uid;do
		user="$(echo "$user_uid"|cut -f1 -d':')"
		uid="$(echo "$user_uid"|cut -f3 -d':')"
	
		echo "sambaSID: $sid-$(($uid*2+1000))"|/usr/sbin/ldap-usermod "$user"  1>&2
	done 
}

remove_old_sids()
{
	local domain="$1"
	
	ldapsearch -LLL -b "$base" $binddn $bindpw -x -H "ldap://${host:-localhost}" -s one  "(&(!(sambaDomainName=$domain))(sambaDomainName=*))" dn|cut -f2 -d' '|
	while read delete_domain;do
		ldapdelete -D "$rootdn" $rootpw -x -H "ldap://${host:-localhost}" "$delete_domain" 1>&2
	done 
}

write_ldap_settings()
{

    if [ -z "$in_ldap_basedn" ]; then
	write_error "`_ 'Base DN not selected'`"
	return 1
    fi


    local in_ldap_admindn="$(echo $rootdn|sed -r -e 's/[[:space:]]*-D[[:space:]]//' 2>/dev/null)"

    if [ -z "$in_ldap_admindn" ]; then
	local emsg="`_ \"Administrator DN not found in the '%s'\"`"
	emsg="`printf \"$emsg\" \"$hdb\"`"
	write_error  "$emsg"
	return 1
    fi

    local in_ldap_adminpass="$(echo $rootpw|sed -r -e 's/[[:space:]]*-[wW][[:space:]]//' 2>/dev/null)"


    if [ -z "$in_ldap_adminpass" ]; then
	local emsg="`_ \"Administrator password not found in the '%s'\"`"
	emsg="`printf \"$emsg\" \"$hdb\"`"
	write_error  "$emsg"
	return 1
    fi

    local in_ldap_uri="ldap://127.0.0.1/"


    # Update global config
    write_global "passdb backend" "ldapsam:$in_ldap_uri"
    write_global "passwd program" '/usr/sbin/smbldap-passwd -u "%u"'
    write_global "unix password sync" 'Yes'
    write_global "add user script" '/usr/sbin/smbldap-useradd -m "%u"'
    write_global "delete user script" '/usr/sbin/smbldap-userdel "%u"'
    write_global "add group script" '/usr/sbin/smbldap-groupadd -p "%g"'
    write_global "add user to group script" '/usr/sbin/smbldap-groupmod -m "%u" "%g"'
    write_global "delete user from group script" '/usr/sbin/smbldap-groupmod -x "%u" "%g"'
    write_global "set primary group script" '/usr/sbin/smbldap-usermod -g "%g" "%u"'
    write_global "add machine script" '/usr/sbin/smbldap-useradd -t 0 -w "%u"'
    write_global "ldap admin dn" "$in_ldap_admindn"
    write_global "ldap group suffix" 'ou=Group'
    write_global "ldap machine suffix" 'ou=Host'
    write_global "ldap suffix" "$in_ldap_basedn"
    write_global "ldap user suffix" 'ou=People'
    # Set LDAP admin password
    printf '%s\n%s\n' "$in_ldap_adminpass" "$in_ldap_adminpass" | smbpasswd -W -s
    # Update Samba-LDAP tools configuration
    shell_config_set "$smbldap_bind_conf" 'slaveDN' "$in_ldap_admindn"
    shell_config_set "$smbldap_bind_conf" 'slavePw' "$in_ldap_adminpass"
    shell_config_set "$smbldap_bind_conf" 'masterDN' "$in_ldap_admindn"
    shell_config_set "$smbldap_bind_conf" 'masterPw' "$in_ldap_adminpass"
    local getlocalsid="$(net getlocalsid)"
    local domain="${getlocalsid#*domain }"
    local domain="${domain% is*}"
    local localsid="${getlocalsid#*is: }"
    shell_config_set "$smbldap_conf" 'SID' "$localsid"
    shell_config_set "$smbldap_conf" 'sambaDomain' "$domain"
    local host="${in_ldap_uri#ldap://}"
    local port="${in_ldap_uri#ldap://*:}"
    shell_config_set "$smbldap_conf" 'slaveLDAP' "${host%%/*}"
    shell_config_set "$smbldap_conf" 'masterLDAP' "${host%%/*}"
    if [ "$port" != "$in_ldap_uri" ]; then
	shell_config_set "$smbldap_conf" 'slavePort' "${port%%/*}"
	shell_config_set "$smbldap_conf" 'masterPort' "${port%%/*}"
    fi
    shell_config_set "$smbldap_conf" 'suffix' "$in_ldap_basedn"
    shell_config_set "$smbldap_conf" 'usersdn' 'ou=People,${suffix}'
    shell_config_set "$smbldap_conf" 'computersdn' 'ou=Host,${suffix}'
    shell_config_set "$smbldap_conf" 'groupsdn' 'ou=Group,${suffix}'

    remove_old_sids "$in_netbios_name" 
    change_users_sid "$localsid" 
}

clean_ldap_settings()
{

    # Clear global config
    ini_config_comment "$smb_conf" "global" "passdb backend"
    ini_config_del "$smb_conf" "global" "passwd program"
    ini_config_del "$smb_conf" "global" "unix password sync"
    ini_config_del "$smb_conf" "global" "add user script"
    ini_config_del "$smb_conf" "global" "delete user script"
    ini_config_del "$smb_conf" "global" "add group script"
    ini_config_del "$smb_conf" "global" "add user to group script"
    ini_config_del "$smb_conf" "global" "delete user from group script"
    ini_config_del "$smb_conf" "global" "set primary group script"
    ini_config_del "$smb_conf" "global" "add machine script"
    ini_config_comment "$smb_conf" "global" "ldap admin dn"
    ini_config_del "$smb_conf" "global" "ldap group suffix"
    ini_config_del "$smb_conf" "global" "ldap machine suffix"
    ini_config_comment "$smb_conf" "global" "ldap suffix"
    ini_config_del "$smb_conf" "global" "ldap user suffix"

}

#initial actions
normalize_conf

on_message()
{
	case "$in_action" in
		list)
		    case "$in__objects" in
			avail_folder)
			    list_share|
				while read share; do
				    write_table_item name "$share" \
						     share "$share" \
						     read_only "$(write_bool_name "$share" "read only" "Yes")" \
						     guest_ok "$(write_bool_name "$share" "guest ok" "No")"
				done
			;;
			avail_dbprofile)
			    list_dbprofile
			    ;;
			avail_basedn)
				write_enum_item "$base" "$base"
			    ;;
		    esac
		    ;;
		read)
		    case "$in__objects" in
			/)
			    local hn="$(hostname)"
			    write_string_param netbios_name "$(read_global "netbios name" "${hn%%.*}")"
			    write_string_param workgroup "$(read_global "workgroup" "WORKGROUP")"
			    if ldap_enable ; then
				write_string_param dbprofile 'ldap'
			    else
				write_string_param dbprofile 'local'
			    fi
			    write_string_param ldap_basedn "$(read_global "ldap suffix" "$base")"
			    ;;
			folder)
			    [ -n "$in_share" ] || return
			    write_string_param new_share "$in_share"
			    write_bool_param read_only "$(read_share "$in_share" "read only" "Yes")"
			    write_bool_param guest_ok "$(read_share "$in_share" "guest ok" "No")"
			    ;;
		    esac
		    ;;
		write)
		    case "$in__objects" in
			/)
			    if [ -n "$in_global" ];then
				[ -z "$in_netbios_name" ] ||
				    write_global "netbios name" "$in_netbios_name"
				[ -z "$in_workgroup" ] ||
				    write_global "workgroup" "$in_workgroup"
				if [ "$in_dbprofile" = "ldap" ]; then
				    write_ldap_settings
				else
				    clean_ldap_settings
				fi
			    elif [ -n "$in_add_folder" -a -n "$in_new_share" ]; then
				local path="$share_dir/$in_new_share"
				if no_share "$in_new_share" && mkdir -p -- "$path"; then
				    chown nobody:nobody "$path"
				    chmod 1777 "$path"
				    add_share "$in_new_share"
				    write_share  "$in_new_share" 'path' "$path"
				else
				    write_error "`_ "Same folder already exists"`"
				fi
			    elif [ -n "$in_del_folder" -a -n "$in_share" ]; then
				local IFS=';'
				for s in $in_share; do
				    local path="$share_dir/$s"

				    [ -d "$path" ] || continue

				    if rmdir -- "$path"; then
					del_share "$s"
				    else
					write_error "$s:`_ "Folder is not empty"`"
					return
				    fi
				done
			    fi
			    ;;
			folder)
			    [ -n "$in_share" ] || return

			    if [ -n "$in_new_share" -a "$in_new_share" != "$in_share" ]; then
				if no_share "$in_new_share" &&
				   mv -- "$share_dir/$in_share" "$share_dir/$in_new_share"; then
				    rename_share "$in_share" "$in_new_share"
				    write_share "$in_new_share" path "$share_dir/$in_new_share"
				    in_share=in_new_share
				else
				    write_error "`_ "Same folder already exists"`"
				    return
				fi
			    fi

			    write_share_bool "$in_share" "read only" "$in_read_only"
			    write_share_bool "$in_share" "guest ok" "$in_guest_ok"
			    ;;
		    esac
		    ;;
	esac
}

message_loop
