Created
December 1, 2023 04:41
-
-
Save parity3/1d56e59ab49a25f4f8bd09b82a6bafd4 to your computer and use it in GitHub Desktop.
Create and switch to a user matching the owner of the first bind mount
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -o pipefail | |
set -e | |
set -x | |
function _get_userid_from_mounts() { | |
type -fp awk >/dev/null || return 1 | |
local mountpath | |
local folder_uid | |
while read -r mountpath ; do | |
folder_uid=$(stat --printf %u "${mountpath}") || continue | |
[ "${folder_uid:-0}" = "0" ] || break | |
done < <(findmnt -it \ | |
sysfs,cgroup,proc,devtmpfs,devpts,pstore,debugfs,hugetlbfs,mqueue,configfs,tmpfs,shm,overlay,nsfs,tracefs,binfmt_misc,fusectl -r \ | |
-noTARGET,SOURCE | awk '$2 ~ /\/var\/lib\/docker\/|\/libexec\// {next} $1 == "/" {next} $1 ~ /^\/(dev|snap|proc|run|sys)/ {next} {print $1}' | |
) | |
if [ "${mountpath:-0}" = "0" ] || [ "${folder_uid:-0}" = "0" ] ; then | |
return 1 | |
fi | |
_UID=$(stat --printf %u "${mountpath}") || return 1 | |
_GID=$(stat --printf %g "${mountpath}") || return 1 | |
} | |
function _get_userid_from_mount() { | |
type -fp awk >/dev/null || return 1 | |
local mountpath | |
local folder_uid | |
while read -r mountpath ; do | |
folder_uid=$(stat --printf %u "${mountpath}") || continue | |
[ "${folder_uid:-0}" = "0" ] || break | |
done < <(mount | | |
awk '$1 ~ /\/var\/lib\/docker\/|\/libexec\// {next} $3 == "/" {next} $3 ~ /^\/(dev|snap|proc|run|sys)/ {next} {print $3}' | |
) | |
if [ "${mountpath:-0}" = "0" ] || [ "${folder_uid:-0}" = "0" ] ; then | |
return 1 | |
fi | |
_UID=$(stat --printf %u "${mountpath}") || return 1 | |
_GID=$(stat --printf %g "${mountpath}") || return 1 | |
} | |
function _get_userid_from_passwd() { | |
type -fp awk >/dev/null || return 1 | |
_UID=$(getent passwd | awk -F: '$3 >= 1000 && $3 < 65000 {u=$3} END {if (u) {print u} else {exit 1}}') || return 1 | |
_GID=$(id -g "${_UID}") | |
} | |
function _get_userid() { | |
if ! _get_userid_from_mounts ; then | |
if ! _get_userid_from_mount ; then | |
if ! _get_userid_from_passwd ; then | |
_UID=${DEFAULT_UID:-1001} | |
_GID=${DEFAULT_GID:-1001} | |
fi | |
fi | |
fi | |
} | |
function _create_user() { | |
# If a user with the desire id exists, use its name as-is (ignore UNAME). | |
# If the group with the desired gid exists, set user's primary group to that gid. | |
if getent passwd "${_UID}" 2>/dev/null 1>&2; then | |
# The user exists. Check if the user's primary group matches | |
UNAME=$(id -un "${_UID}") | |
if getent group "${_GID}" 2>/dev/null 1>&2 ; then | |
PRIMARY_GID=$(id -g "${_UID}") | |
[ "${PRIMARY_GID}" = "${_GID}" ] || usermod -g "${_GID}" "${UNAME}" | |
else | |
groupadd -g "${_GID}" "${GNAME:-unpriv}" | |
usermod -g "${_GID}" "${UNAME}" | |
fi | |
else | |
# The desired user id does not exist. If the desired username exists, rename it to old. | |
# Same with the group matching gid. | |
# Create the new user with desired name and group. | |
# Re-add the old group as a secondary group to the new user so that we have a better chance at accessing files. | |
UNAME=${UNAME:-unpriv} | |
GNAME=${GNAME:-unpriv} | |
local GNAME_OLD | |
if getent passwd "${UNAME}" 2>/dev/null 1>&2 ; then | |
usermod -l "${UNAME}_old" "${UNAME}" | |
fi | |
if ! getent group "${_GID}" 2>/dev/null 1>&2 ; then | |
if getent group "${GNAME}" 2>/dev/null 1>&2 ; then | |
GNAME_OLD="${GNAME}_old" | |
groupmod -n "${GNAME}_old" "${GNAME}" | |
fi | |
groupadd -g "${_GID}" "${GNAME}" | |
fi | |
local shell_path | |
shell_path=$(type -fp bash) || shell_path=$(type -fp sh) || shell_path=/bin/sh | |
useradd -u "${_UID}" -g "${_GID}" -s "${shell_path}" "${UNAME}" | |
if [ -n "${GNAME_OLD}" ] ; then | |
usermod -aG "${GNAME_OLD}" "${UNAME}" | |
fi | |
fi | |
} | |
function _create_homedir() { | |
# Once the user and group are set up, we must re-examine the user's home directory. | |
# Make sure it is owned by the proper uid/gid with 750 permissions | |
HOMEDIR=$(getent passwd "$_UID" |awk -F: '{print $6}') | |
if [ -e "${HOMEDIR}" ] ; then | |
if [ "$(stat --printf %u "${HOMEDIR}")" != "${_UID}" ] ; then | |
chown "${_UID}:${_GID}" "${HOMEDIR}" | |
chmod 750 "${HOMEDIR}" | |
fi | |
else | |
mkdir -p "${HOMEDIR}" | |
chown "${_UID}:${_GID}" "${HOMEDIR}" | |
chmod 750 "${HOMEDIR}" | |
fi | |
} | |
function _save_env() { | |
echo "#!/usr/bin/env bash" | |
declare -px | awk '$3 !~ /^(OLDPWD|HOSTNAME|PWD|USER|SHELL|_.*|PS1|HOME|SHLVL|LS_COLORS)=/' | |
echo "cd \"${PWD}\"" | |
printf ' %q' exec "$@" | |
echo "" | |
} | |
function _unpriv_exec() { | |
_save_env "$@" >/saved_env.sh | |
chmod +x /saved_env.sh | |
exec su "${UNAME}" -- "$0" "$@" | |
} | |
function _exec_if_not_root() { | |
if [ "$(id -u)" != 0 ] ; then | |
if [ -e /saved_env.sh ] ; then | |
exec /saved_env.sh | |
else | |
exec "$@" | |
fi | |
fi | |
} | |
function ensure_unpriv() { | |
_exec_if_not_root "$@" | |
_get_userid | |
_create_user | |
_create_homedir | |
_unpriv_exec "$@" | |
} | |
if [ "$1" != "load" ]; then | |
ensure_unpriv "$@" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment