xref: /dragonfly/tools/pw-update.sh (revision 37c7698a)
104e50ef7SAaron LI#!/bin/sh
204e50ef7SAaron LI#
304e50ef7SAaron LI# Copyright (c) 2020 The DragonFly Project.
404e50ef7SAaron LI# All rights reserved.
504e50ef7SAaron LI#
604e50ef7SAaron LI# Redistribution and use in source and binary forms, with or without
704e50ef7SAaron LI# modification, are permitted provided that the following conditions
804e50ef7SAaron LI# are met:
904e50ef7SAaron LI#
1004e50ef7SAaron LI# 1. Redistributions of source code must retain the above copyright
1104e50ef7SAaron LI#    notice, this list of conditions and the following disclaimer.
1204e50ef7SAaron LI# 2. Redistributions in binary form must reproduce the above copyright
1304e50ef7SAaron LI#    notice, this list of conditions and the following disclaimer in
1404e50ef7SAaron LI#    the documentation and/or other materials provided with the
1504e50ef7SAaron LI#    distribution.
1604e50ef7SAaron LI# 3. Neither the name of The DragonFly Project nor the names of its
1704e50ef7SAaron LI#    contributors may be used to endorse or promote products derived
1804e50ef7SAaron LI#    from this software without specific, prior written permission.
1904e50ef7SAaron LI#
2004e50ef7SAaron LI# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2104e50ef7SAaron LI# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2204e50ef7SAaron LI# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2304e50ef7SAaron LI# FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
2404e50ef7SAaron LI# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2504e50ef7SAaron LI# INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2604e50ef7SAaron LI# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2704e50ef7SAaron LI# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2804e50ef7SAaron LI# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2904e50ef7SAaron LI# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3004e50ef7SAaron LI# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3104e50ef7SAaron LI# SUCH DAMAGE.
3204e50ef7SAaron LI#
3304e50ef7SAaron LI
3404e50ef7SAaron LI# Exit if any untested command fails in non-interactive mode
3504e50ef7SAaron LIset -e
3604e50ef7SAaron LI# Exit when an undefined variable is referenced
3704e50ef7SAaron LIset -u
3804e50ef7SAaron LI
391bc30ec4SAaron LI# Usage: add_users <etcdir> <master.passwd> <group>
4004e50ef7SAaron LI#
4104e50ef7SAaron LI# Add new users and groups in <etcdir> according to the given <master.passwd>
4204e50ef7SAaron LI# and <group> files.
4304e50ef7SAaron LI#
4404e50ef7SAaron LI# NOTE: Existing users and groups are not modified.
4504e50ef7SAaron LI#
4604e50ef7SAaron LIadd_users() {
4704e50ef7SAaron LI	local etcdir="$1"
4804e50ef7SAaron LI	local fpasswd="$2"
4904e50ef7SAaron LI	local fgroup="$3"
50*37c7698aSAaron LI	local _name _pw _uid _gid _gids _group item
5104e50ef7SAaron LI	local _class _change _expire _gecos _home _shell _members
5204e50ef7SAaron LI
5304e50ef7SAaron LI	echo "===> Adding new users ..."
5404e50ef7SAaron LI	_gids=""
5504e50ef7SAaron LI	while IFS=':' read -r _name _pw _uid _gid _class \
5604e50ef7SAaron LI			_change _expire _gecos _home _shell; do
5704e50ef7SAaron LI		case ${_name} in
5804e50ef7SAaron LI		'' | \#*) continue ;;
5904e50ef7SAaron LI		esac
6004e50ef7SAaron LI		if pw -V ${etcdir} usershow ${_name} -q >/dev/null; then
6104e50ef7SAaron LI			continue
6204e50ef7SAaron LI		fi
6304e50ef7SAaron LI		echo "   * ${_name}: ${_uid}, ${_gid}, ${_gecos}, ${_home}, ${_shell}"
64*37c7698aSAaron LI
65*37c7698aSAaron LI		_group=${_gid}
66*37c7698aSAaron LI		if ! pw -V ${etcdir} groupshow ${_gid} -q >/dev/null; then
67*37c7698aSAaron LI			# Primary group doesn't exist yet, so first assign to
68*37c7698aSAaron LI			# the 'nogroup' group, and then adjust it after
69*37c7698aSAaron LI			# creating the group.
70*37c7698aSAaron LI			_group="nogroup"
71*37c7698aSAaron LI			_gids="${_gids} ${_name}:${_gid}"
72*37c7698aSAaron LI		fi
73*37c7698aSAaron LI
7454af8c6bSAaron LI		# NOTE: The shell field can be empty (e.g., user 'toor') and
7554af8c6bSAaron LI		#       would default to '/bin/sh'.
7654af8c6bSAaron LI		# NOTE: Use '-o' option to allow to create user of duplicate
7754af8c6bSAaron LI		#       UID, which is required by the 'toor' user (same UID
7854af8c6bSAaron LI		#       as 'root').
7904e50ef7SAaron LI		pw -V ${etcdir} useradd ${_name} \
8054af8c6bSAaron LI			-o \
8104e50ef7SAaron LI			-u ${_uid} \
82*37c7698aSAaron LI			-g ${_group} \
8354af8c6bSAaron LI			-d "${_home}" \
8454af8c6bSAaron LI			-s "${_shell}" \
8504e50ef7SAaron LI			-L "${_class}" \
8604e50ef7SAaron LI			-c "${_gecos}"
8704e50ef7SAaron LI	done < ${fpasswd}
8804e50ef7SAaron LI
8904e50ef7SAaron LI	echo "===> Adding new groups ..."
9004e50ef7SAaron LI	while IFS=':' read -r _name _pw _gid _members; do
9104e50ef7SAaron LI		case ${_name} in
9204e50ef7SAaron LI		'' | \#*) continue ;;
9304e50ef7SAaron LI		esac
9404e50ef7SAaron LI		if pw -V ${etcdir} groupshow ${_name} -q >/dev/null; then
9504e50ef7SAaron LI			continue
9604e50ef7SAaron LI		fi
9704e50ef7SAaron LI		echo "   * ${_name}: ${_gid}, ${_members}"
9804e50ef7SAaron LI		pw -V ${etcdir} groupadd ${_name} -g ${_gid} -M "${_members}"
9904e50ef7SAaron LI	done < ${fgroup}
10004e50ef7SAaron LI
10104e50ef7SAaron LI	echo "===> Adjusting the group of new users ..."
10204e50ef7SAaron LI	for item in ${_gids}; do
10304e50ef7SAaron LI		_name=${item%:*}
10404e50ef7SAaron LI		_gid=${item#*:}
10504e50ef7SAaron LI		echo "   * ${_name}: ${_gid}"
10604e50ef7SAaron LI		pw -V ${etcdir} usermod ${_name} -g ${_gid}
10704e50ef7SAaron LI	done
10804e50ef7SAaron LI}
10904e50ef7SAaron LI
1101bc30ec4SAaron LI# Usage: update_user <user> <etcdir> <master.passwd>
1111bc30ec4SAaron LI#
1121bc30ec4SAaron LI# Update an existing user in <etcdir> according to the given <master.passwd>.
1131bc30ec4SAaron LI#
1141bc30ec4SAaron LIupdate_user() {
1151bc30ec4SAaron LI	local user="$1"
1161bc30ec4SAaron LI	local etcdir="$2"
1171bc30ec4SAaron LI	local fpasswd="$3"
1181bc30ec4SAaron LI	local _line
1191bc30ec4SAaron LI	local _name _pw _uid _gid _class _change _expire _gecos _home _shell
1201bc30ec4SAaron LI
1211bc30ec4SAaron LI	_line=$(grep "^${user}:" ${fpasswd}) || true
1221bc30ec4SAaron LI	if [ -z "${_line}" ]; then
1231bc30ec4SAaron LI		echo "ERROR: no such user '${user}'" >&2
1241bc30ec4SAaron LI		exit 1
1251bc30ec4SAaron LI	fi
1261bc30ec4SAaron LI
1271bc30ec4SAaron LI	echo "${_line}" | {
1281bc30ec4SAaron LI		IFS=':' read -r _name _pw _uid _gid _class \
1291bc30ec4SAaron LI			_change _expire _gecos _home _shell
1301bc30ec4SAaron LI		echo "===> Updating user ${user} ..."
1311bc30ec4SAaron LI		echo "   * ${_name}: ${_uid}, ${_gid}, ${_gecos}, ${_home}, ${_shell}"
1321bc30ec4SAaron LI		pw -V ${etcdir} usermod ${user} \
1331bc30ec4SAaron LI			-u ${_uid} \
1341bc30ec4SAaron LI			-g ${_gid} \
1351bc30ec4SAaron LI			-d ${_home} \
1361bc30ec4SAaron LI			-s ${_shell} \
1371bc30ec4SAaron LI			-L "${_class}" \
1381bc30ec4SAaron LI			-c "${_gecos}"
1391bc30ec4SAaron LI	}
1401bc30ec4SAaron LI}
1411bc30ec4SAaron LI
1421bc30ec4SAaron LI# Usage: update_group <group> <etcdir> <group>
1431bc30ec4SAaron LI#
1441bc30ec4SAaron LI# Update an existing group in <etcdir> according to the given <group> file.
1451bc30ec4SAaron LI#
1461bc30ec4SAaron LIupdate_group() {
1471bc30ec4SAaron LI	local group="$1"
1481bc30ec4SAaron LI	local etcdir="$2"
1491bc30ec4SAaron LI	local fgroup="$3"
1501bc30ec4SAaron LI	local _line
1511bc30ec4SAaron LI	local _name _pw _gid _members
1521bc30ec4SAaron LI
1531bc30ec4SAaron LI	_line=$(grep "^${group}:" ${fgroup}) || true
1541bc30ec4SAaron LI	if [ -z "${_line}" ]; then
1551bc30ec4SAaron LI		echo "ERROR: no such group '${group}'" >&2
1561bc30ec4SAaron LI		exit 1
1571bc30ec4SAaron LI	fi
1581bc30ec4SAaron LI
1591bc30ec4SAaron LI	echo "${_line}" | {
1601bc30ec4SAaron LI		IFS=':' read -r _name _pw _gid _members
1611bc30ec4SAaron LI		echo "===> Updating group ${group} ..."
1621bc30ec4SAaron LI		echo "   * ${_name}: ${_gid}, ${_members}"
1631bc30ec4SAaron LI		pw -V ${etcdir} groupmod ${group} -g ${_gid} -M "${_members}"
1641bc30ec4SAaron LI	}
1651bc30ec4SAaron LI}
1661bc30ec4SAaron LI
16704e50ef7SAaron LIusage() {
16804e50ef7SAaron LI	cat > /dev/stderr << _EOF_
1691bc30ec4SAaron LIAdd/update users and groups.
17004e50ef7SAaron LI
17104e50ef7SAaron LIUsage: ${0##*/} -d <etc-dir> -g <group-file> -p <master.passwd-file>
1721bc30ec4SAaron LI	[-G group] [-U user]
17304e50ef7SAaron LI
17404e50ef7SAaron LI_EOF_
17504e50ef7SAaron LI
17604e50ef7SAaron LI	exit 1
17704e50ef7SAaron LI}
17804e50ef7SAaron LI
17904e50ef7SAaron LIETC_DIR=
18004e50ef7SAaron LIGROUP_FILE=
18104e50ef7SAaron LIPASSWD_FILE=
1821bc30ec4SAaron LIUPDATE_GROUP=
1831bc30ec4SAaron LIUPDATE_USER=
18404e50ef7SAaron LI
1851bc30ec4SAaron LIwhile getopts :d:G:g:hp:U: opt; do
18604e50ef7SAaron LI	case ${opt} in
18704e50ef7SAaron LI	d)
18804e50ef7SAaron LI		ETC_DIR=${OPTARG}
18904e50ef7SAaron LI		;;
1901bc30ec4SAaron LI	G)
1911bc30ec4SAaron LI		UPDATE_GROUP=${OPTARG}
1921bc30ec4SAaron LI		;;
19304e50ef7SAaron LI	g)
19404e50ef7SAaron LI		GROUP_FILE=${OPTARG}
19504e50ef7SAaron LI		;;
19604e50ef7SAaron LI	p)
19704e50ef7SAaron LI		PASSWD_FILE=${OPTARG}
19804e50ef7SAaron LI		;;
1991bc30ec4SAaron LI	U)
2001bc30ec4SAaron LI		UPDATE_USER=${OPTARG}
2011bc30ec4SAaron LI		;;
20204e50ef7SAaron LI	h | \? | :)
20304e50ef7SAaron LI		usage
20404e50ef7SAaron LI		;;
20504e50ef7SAaron LI	esac
20604e50ef7SAaron LIdone
20704e50ef7SAaron LI
20804e50ef7SAaron LIshift $((OPTIND - 1))
20904e50ef7SAaron LI[ $# -eq 0 ] || usage
21004e50ef7SAaron LI[ -n "${ETC_DIR}" ] || usage
21104e50ef7SAaron LI[ -n "${GROUP_FILE}" ] || usage
21204e50ef7SAaron LI[ -n "${PASSWD_FILE}" ] || usage
21304e50ef7SAaron LI
2141bc30ec4SAaron LIif [ -z "${UPDATE_GROUP}" ] && [ -z "${UPDATE_USER}" ]; then
21504e50ef7SAaron LI	add_users "${ETC_DIR}" "${PASSWD_FILE}" "${GROUP_FILE}"
2161bc30ec4SAaron LIelse
2171bc30ec4SAaron LI	if [ -n "${UPDATE_GROUP}" ]; then
2181bc30ec4SAaron LI		update_group "${UPDATE_GROUP}" "${ETC_DIR}" "${GROUP_FILE}"
2191bc30ec4SAaron LI	fi
2201bc30ec4SAaron LI	if [ -n "${UPDATE_USER}" ]; then
2211bc30ec4SAaron LI		update_user "${UPDATE_USER}" "${ETC_DIR}" "${PASSWD_FILE}"
2221bc30ec4SAaron LI	fi
2231bc30ec4SAaron LIfi
224