#!/bin/bash

# Workaround for :
# semanage user -l | cat
# UnicodeEncodeError: ascii
export LC_MESSAGES=C

alterator_api_version=1

. alterator-sh-functions
. shell-quote

local_getent()
{
	local re="${2:-.*}"
	grep "^$re:" "/etc/$1"
}

UID_MIN=$(grep '^UID_MIN' /etc/login.defs 2>/dev/null|sed -r 's,UID_MIN[[:space:]]+,,')
[ -z "$UID_MIN" ] && UID_MIN=500

list_allusers()
{	 
	local seman=$(/usr/sbin/semanage login -l | sed -n '4,${p}')
	local index=0
	
	local_getent passwd|
	while IFS=':' read name password uid gid gecos home shell; do
		[ "$uid" -ge "$UID_MIN" ] || continue
		[ "$shell" == "/sbin/nologin" ] || grep -qs "^$shell$" /etc/shells || continue
		[ -x "$shell" ] || continue

		while read username seuser range
		do 
			if [ "$name" == "$username" ]; then
				index=$(($index+1))
			fi
		done < <(echo "$seman")
		if [ "$index" == 0 ]; then 
			write_enum_item "$name"
		fi
		index=0
	done 2>/dev/null
}

list_sensitivity()
{
	[ -z "$in_seuser" ] && return

	local sensitivity_ru=
	local lvl_max="$(echo "$(selinux-seusers-fn -u $in_seuser)" | awk -F\- '{print $2}' | awk -F\: '{print $1}')"
	local lvl_min="$(echo "$(selinux-seusers-fn -u $in_seuser)" | awk -F\- '{print $1}' | awk -F\: '{print $1}')"
	
	lvl_max="$(echo "$lvl_max" | grep -o "[0-9]*")"
	lvl_min="$(echo "$lvl_min" | grep -o "[0-9]*")"
	if [ -z "$lvl_max" ];then
		lvl_max="$lvl_min"
	fi

	for (( i=$lvl_min; $i<=$lvl_max; i=$i+1 )); do 
		sensitivity_ru="$(/usr/bin/selinux-seusers-fn -t "s$i")"
		write_enum_item "s$i" "$sensitivity_ru"
	done
}

list_category()
{
	local category_ru=
	seman="$(echo "$in_categories" | tr ';' '\n')"

	if [ -n "$seman" ]; then
	    while read category
	    do
		category_ru="$(selinux-seusers-fn -t "$category")"
		write_enum_item "$category" "$category_ru"
	    done < <(echo "$seman")
	fi
}

list_all_categories()
{
	local category_ru=
	local seman="$(selinux-users-fn maxcat "$(selinux-seusers-fn -u "$in_seuser")")"
	if [ -z "$seman" ];then
		seman="$(selinux-users-fn mincat "$(selinux-seusers-fn -u "$in_seuser")")"
	fi

	if [ -n "$seman" ];then
	    while read category
	    do
		category_ru="$(selinux-seusers-fn -t "$category")"
		write_enum_item "$category" "$category_ru"
	    done < <(echo "$seman")
	fi
}

list_users()
{
	local seman=$(/usr/sbin/semanage login -l | sed -n '4,${p}')

	while read username seuser range
	do
		write_table_item name "$username" label "$username"
	done < <(echo "$seman")
}

list_seuser()
{
	local seman=$(/usr/sbin/semanage user -l | sed -n '5,${p}' | awk -F\  '{print $1}')
	while read seuser
	do
		write_table_item name "$seuser" label "$seuser"
	done < <(echo "$seman")
}

list_to_range()
{
	if [ -z "$1" ]; then
		return
	fi

	local seman="$(echo "$1" | grep -o "[0-9]*")"
	local index=
	local range=
	local prev_cat=
	while read category
	do
		if [ -z "$index" ]; then
			range="c$category"
			prev_cat="$category"
			index="$category"
		elif [ "$(($category-$prev_cat))" != "1" ]; then
			if [ "$index" != "$prev_cat" ]; then
				range="$range"".c$prev_cat"",c$category"
			else
				range="$range"",c$category"
			fi
			index="$category"
			prev_cat="$category"
		elif [ "$(($category-$prev_cat))" == "1" ];then
			prev_cat="$category"
		fi
	done < <(echo "$seman")
	if [ "$(($prev_cat-$index))" != "1" ];	then
		if [ "$(($prev_cat-$index))" != "0" ]; then
			range="$range"".c$prev_cat"
		fi
	else
		range="$range"",c$prev_cat"
	fi
	echo "$range"
}

merge_lists()
{
	if [ -z "$1" ];then
		echo "$2"
		return
	fi
	if [ -z "$2" ];then
		echo "$1"
		return
	fi
	local list_one="$(echo "$1" | grep -o "[0-9]*")"
	local list_two="$(echo "$2" | grep -o "[0-9]*")"
	local list="$(echo "$(echo "$list_one"$'\n'"$list_two")" | sort -nu)"
	echo "$list"
}

change_user()
{
	local range=
	local minlvl="$in_minlevel"
	local maxlvl="$in_maxlevel"

	seusr_range="$(selinux-users-fn mincat "$(selinux-seusers-fn -u $in_seuser)")"

	local maxcat="$(list_to_range "$(merge_lists "$seusr_range" "$in_categories")")"
	local mincat="$(list_to_range "$(merge_lists "$seusr_range" "$in_category")")"

	if [ "$minlvl$mincat" != "$maxlvl$maxcat" ]; then
		if [ -n "$mincat" ]; then
			range="$minlvl:$mincat-"
		else
			range="$minlvl-"
		fi
	fi

	if [ -n "$maxcat" ]; then
		range="$range""$maxlvl"":$maxcat"
	else
		range="$range""$maxlvl"
	fi

	semanage login -m -s "$in_seuser" -r "$range" "$in_users"
}

new_user()
{
	local lvl="$(echo "$(selinux-seusers-fn -u $in_seuser)" | awk -F\- '{print $1}')"
	semanage login -a -s "$in_seuser" -r "$lvl" "$in_all_users"
}

delete_user()
{
	if [ "$in_users" != "root" ] && [ "$in_users" != "__default__" ]; then
		/usr/sbin/semanage login -d "$in_users"
	fi
}

on_message()
{
	case "$in_action" in
		read)
		 local maxrange="$(echo "$(selinux-users-fn maxrange $in_users)" | tr '\n' ';')"
		 local minrange="$(echo "$(selinux-users-fn minrange $in_users)" | tr '\n' ';')"

		 local maxlvl="$(echo "$(selinux-users-fn range $in_users)" | awk -F\- '{print $2}' | awk -F\: '{print $1}')"
		 local minlvl="$(echo "$(selinux-users-fn range $in_users)" | awk -F\- '{print $1}' | awk -F\: '{print $1}')"
		 
		 if [ -z "$maxlvl" ]; then
			 maxlvl="$minlvl"
		 fi
		 
		 if [ "$maxrange" == ";" ]; then
		 	 maxrange="$minrange"
		 fi

		 write_string_param maxlevel "$maxlvl"
		 write_string_param minlevel "$minlvl"

		 write_string_param categories "$maxrange"
		 write_string_param category "$minrange"
		 
		 write_string_param seuser "$(selinux-users-fn seuser $in_users)"
		;;
	esac
}

alterator_export_proc list_sensitivity
alterator_export_proc list_category
alterator_export_proc list_all_categories
alterator_export_proc list_allusers
alterator_export_proc list_users
alterator_export_proc list_seuser

alterator_export_proc new_user
alterator_export_proc change_user
alterator_export_proc delete_user

message_loop
