Commit 2f11b412 authored by Dom Sekotill's avatar Dom Sekotill
Browse files

Replace config-nsswitch with bootstrap-stage & stage-useradd

parent b200b898
Loading
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2,8 +2,10 @@

FROM debian:buster-slim as collect
COPY LICENCE.txt /stage/LICENCE.txt
COPY bootstrap-stage.bash /stage/scripts/bootstrap-stage
COPY collect-binaries.bash /stage/scripts/collect-binaries
COPY config-nsswitch.bash /stage/scripts/config-nsswitch
COPY stage-useradd.bash /stage/scripts/stage-useradd
RUN /stage/scripts/collect-binaries /bin/bash

FROM scratch

bootstrap-stage.bash

0 → 100755
+63 −0
Original line number Diff line number Diff line
#!/bin/bash
# Copyright (c) 2020 Dom Sekotill <dom.sekotill@kodo.org.uk>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

set -eu -o pipefail
declare -r DEFAULT_STAGE=/stage

USAGE="Usage: $0 [--help] [-s STAGE]

Prepare the necessary components of an image in a staging directory

Options:
  -h|--help         Show this message and exit.
  -s|--stage STAGE  Set the output stage directory. If it does not exist it will
                    be created. (default: $DEFAULT_STAGE)

Environment:
  STAGE:  An alternate way of providing --stage
"

export PATH+=:$(dirname $0)
export STAGE=${STAGE-$DEFAULT_STAGE}

until [[ $# -eq 0 ]]; do
	case $1 in
		-h|--help) echo "$USAGE"; exit 0 ;;
		-s|--stage) STAGE=$2; shift ;;
		--*=*) set -- ${1%=*} ${1#--*=} "${@:2}"; continue ;;
		*) echo >&2 "Unknown argument: $1"; exit 2 ;;
	esac
	shift
done

# nsswitch (if present, only on GNU libc platforms)
mkdir -p $STAGE/etc
collect-binaries /lib/*/libnss* &&
	cat <<-END_CONF >$STAGE/etc/nsswitch.conf
		passwd: files
		group:  files
		hosts:  files dns
	END_CONF

# Temp directories
mkdir -p $STAGE/var/tmp
chmod 1777 $STAGE/var/tmp
test -h $STAGE/tmp || ln -s /var/tmp $STAGE/tmp
+13 −80
Original line number Diff line number Diff line
@@ -20,88 +20,17 @@
# SOFTWARE.

set -eu -o pipefail
declare -r DEFAULT_STAGE=/stage

USAGE="Usage: $0 [--help] [-s STAGE] [USERNAME[:GROUP[,GROUP...]] ...]

Prepare the necessary libraries and configuration for name lookups with nsswitch

The Name Service Switch system is used by the GNU C library to provide various
types of name lookup including: user names, group names, and host names.  This
script configures an image for those name look-ups.

Hostname lookups are configured to use /etc/hosts (as supplied by Docker) and
DNS.  Users and groups are configured from command line arguments which supply
usernames and optional comma separated group names.  Only *additional* groups
need be specified, not the user's default group which has the same name as the
user.  The root user is always created if not specified.

Options:
  -h|--help         Show this message and exit.
  -s|--stage STAGE  Set the output stage directory. If it does not exist it will
                    be created. (default: $DEFAULT_STAGE)

Environment:
  STAGE:  An alternate way of providing --stage
"

add_group() {
	local IFS= users=${GROUP_USERS[$1]-}
	echo "$1:x:$2:${users%,}" >>$STAGE/etc/group
	unset GROUP_USERS[$1]
}

add_user() {
	echo "$1:x:$2:$2::/:/bin/nologin" >>$STAGE/etc/passwd
}

process_userspec()
{
	declare -a USERS=()
	declare -A GROUP_USERS=()
	declare -a groups
	local IFS=, spec user group i

	for spec in "$@"; do
		user=${spec%:*}
		groups=( ${spec#*:} )
		USERS+=( $user )
		GROUP_USERS[$user]+=""
		for group in "${groups[@]}"; do
			[[ $group = $user ]] && continue
			GROUP_USERS[$group]+="$user,"
		done
	done

	add_user root 0
	add_group root 0

	i=0
	for user in "${USERS[@]}"; do
		add_user $user $((++i))
		add_group $user $i
	done

	i=500
	for group in "${!GROUP_USERS[@]}"; do
		add_group $group $((i++))
	done

	cat <<-END_CONF >$STAGE/etc/nsswitch.conf
		passwd: files
		group:  files
		hosts:  files dns
	END_CONF
}

export PATH+=:$(dirname $0)
export STAGE=${STAGE-$DEFAULT_STAGE}
echo "$(type tput &>/dev/null || exit; tput bold; tput setaf 1)" \
	"This script has been deprecated in favour of stage-useradd for adding" \
	"usernames and groups." \
	"$(type tput &>/dev/null || exit; tput sgr0)"

declare -a USERSPEC=()
until [[ $# -eq 0 ]]; do
	case $1 in
		-h|--help) echo "$USAGE"; exit 0 ;;
		-s|--stage) STAGE=$2; shift ;;
		-h|--help) exit 0 ;;
		-s|--stage) export STAGE=$2; shift ;;
		--*=*) set -- ${1%=*} ${1#--*=} "${@:2}"; continue ;;
		--) USERSPEC+=( "$@" ); break ;;
		*) USERSPEC+=( "$1" ) ;;
@@ -109,6 +38,10 @@ until [[ $# -eq 0 ]]; do
	shift
done

mkdir -p $STAGE/etc
collect-binaries /lib/*/libnss*
process_userspec "${USERSPEC[@]}"
IFS=,
declare -a groups
for spec in "${USERSPEC[@]}"; do
	user=${spec%:*}
	groups=( ${spec#*:} )
	stage-useradd $user "${groups[@]}"
done

stage-useradd.bash

0 → 100755
+126 −0
Original line number Diff line number Diff line
#!/bin/bash
# Copyright (c) 2020 Dom Sekotill <dom.sekotill@kodo.org.uk>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

set -eu -o pipefail
declare -r DEFAULT_STAGE=/stage

USAGE="Usage: $0 [--help] [-s STAGE] USERNAME [GROUP [GROUP ...]]

Add a username to the stage and/or add the user to the given additional groups

Arguments:
  USERNAME  The username of the new user to add or user to modify.
  GROUP     A named group to add the user to.

Options:
  -h|--help         Show this message and exit.
  -s|--stage STAGE  Set the output stage directory. If it does not exist it will
                    be created. (default: $DEFAULT_STAGE)

Environment:
  STAGE:  An alternate way of providing --stage
"

declare -A USERS=()
declare -A GROUP=()
declare -r PASSWDFD=3 GROUPFD=4

read_users() {
	[[ -e $STAGE/etc/passwd ]] || return 0
	local IFS=: name
	while read name _; do
		[[ $name = root ]] && continue
		USERS[$name]=
	done <$STAGE/etc/passwd
}

read_groups() {
	[[ -e $STAGE/etc/group ]] || return 0
	local IFS=: name users
	while read name _ _ users; do
		[[ $name = root ]] && continue
		GROUP[$name]=$users
	done <$STAGE/etc/group
}

add_user() {
	local user=$1 group
	for group in "${@:2}"; do
		[[ $group = $user ]] && continue
		GROUP[$user]+=$group,
	done
	USERS[$user]=
}

write_group() {
	local users=${GROUP[$1]-}
	echo "$1:x:$2:${users%,}" >&$GROUPFD
	unset GROUP_USERS[$1]
}

write_user() {
	echo "$1:x:$2:$2::/:/bin/nologin" >&$PASSWDFD
}

write_files()
{
	local user group i
	exec 3>$STAGE/etc/passwd.tmp 4>$STAGE/etc/group.tmp

	write_user root 0
	write_group root 0

	i=0
	for user in "${!USERS[@]}"; do
		write_user $user $((++i))
		write_group $user $i
	done

	i=500
	for group in "${!GROUP_USERS[@]}"; do
		write_group $group $((i++))
	done

	mv $STAGE/etc/passwd.tmp $STAGE/etc/passwd
	mv $STAGE/etc/group.tmp $STAGE/etc/group
}

export PATH+=:$(dirname $0)
export STAGE=${STAGE-$DEFAULT_STAGE}

declare -a ARGS=()
until [[ $# -eq 0 ]]; do
	case $1 in
		-h|--help) echo "$USAGE"; exit 0 ;;
		-s|--stage) STAGE=$2; shift ;;
		--*=*) set -- ${1%=*} ${1#--*=} "${@:2}"; continue ;;
		--) ARGS+=( "$@" ); break ;;
		*) ARGS+=( "$1" ) ;;
	esac
	shift
done

[[ -e $STAGE/etc/passwd ]] || bootstrap-stage

read_users
read_groups
add_user "${ARGS[@]}"
write_files