#!/bin/bash

set -e

PASSWD_FILE=/etc/passwd

test_mode=0
if [ $# -gt 0 ]; then
	test_mode=1
fi

get_next_uid() {
	awk -F ":" 'BEGIN {uid=0} {if ($3==65534 || $3==64055 || $3<{{ min_uid }}) {next} if ($3>uid) {uid=$3; next} } END {print ++uid}' $PASSWD_FILE
}

get_next_sys_uid() {
	if [ -f /etc/debian_version ]; then
		# ids are allocated from SYS_UID_MIN and increasing
		awk -F ":" 'BEGIN {uid={{ min_sys_uid }} } {if ($3>{{ max_sys_uid }} || $3<={{ min_sys_uid }}) {next} if ($3>uid) {uid=$3; next} } END {print ++uid}' $PASSWD_FILE
	else
		# ids are allocated from SYS_UID_MAX and decreasing
		awk -F ":" 'BEGIN {uid={{ max_sys_uid }} } {if ($3>{{ max_sys_uid }} || $3<={{ min_sys_uid }}) {next} if ($3<uid) {uid=$3; next} } END {print --uid}' $PASSWD_FILE
	fi
}

userlist=""
for dup in $(awk -F ":" 'list[$3]++{print $1":"$3}' $PASSWD_FILE); do
	username="${dup/:*}"
	uid="${dup/*:}"

	next_uid=`get_next_uid`
	if [ $uid -le {{ max_sys_uid }} ]; then
		# As per SLES-15-020100, dup uid 0 should be moved to non system uid
		# It's saying also:
		# 'If the account is associated with system commands or applications,
		# the UID should be changed to one greater than "0" but less than "1000".'
		# I don't see how it can be detected since FS will likely store the numerical
		# UID (aka 0). Moreover, as per SLES-15-010359 all commands are likely to be
		# root owner....
		if [ $uid -eq 0 ]; then
			next_uid=`get_next_uid`
		else
			next_uid=`get_next_sys_uid`
		fi
	fi

	if [ $test_mode -eq 0 ]; then
		# usermod will possibly complain about it in use
		sed -i $PASSWD_FILE -r -e "s,^$username:([^:]+):$uid:(.*)$,$username:\1:$next_uid:\2,g"
	fi

	entry="{\"$username\": { \"oldid\": $uid, \"newid\": $next_uid }}"
	if [ "x$userlist" == "x" ]; then
		userlist="$entry"
	else
		userlist="$userlist,$entry"
	fi

done

if [ "x$userlist" == "x" ]; then
	echo "{\"changed\": false}"
else
	echo "{\"changed\": true, \"users\": [$userlist]}"
fi

