Skip to content

Instantly share code, notes, and snippets.

@stbuehler
Created June 11, 2020 13:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stbuehler/412b04948953a11527a4c99c450fd76a to your computer and use it in GitHub Desktop.
Save stbuehler/412b04948953a11527a4c99c450fd76a to your computer and use it in GitHub Desktop.
run a given command (or the login shell) with additional capabilities as a normal user.
#!/bin/bash
# Start as root; run a given command (or the login shell) with additional capabilities as a normal user.
# Eg: with-cap-as-user.sh +net_bind_service -u myhttpuser -- nc -l -p 80
caps=
user=
keepenv=0
syntax() {
echo >&2 "Usage: $0 [-k] -u username (+capability)* [-- command]"
echo >&2
echo >&2 "Options:"
echo >&2 " -k Keep environment"
echo >&2 " -u username Run command (or login shell) as user"
echo >&2 " +capability Capability name to run command with (see setpriv --list-caps)"
exit 1
}
while [ $# -gt 0 ]; do
case "$1" in
+*)
caps=${caps},$1
shift
;;
-k)
keepenv=1
shift
;;
-u)
if [ -n "${user}" ]; then
echo >&2 "Already have user"
exit 1
fi
if [ -z "$2" ]; then
echo >&2 "Missing/empty username"
exit 1
fi
user=$2
shift 2
;;
-h|--help)
syntax
;;
--)
shift
break
;;
-*)
echo >&2 "Unknown option: $1"
syntax
;;
*)
break
;;
esac
done
if [ -z "${user}" ]; then
echo >&2 "Missing username"
syntax
fi
passwd=$(getent passwd -- "${user}")
if [ -z "${passwd}" ]; then
echo >&2 "User ${user} not found"
exit 2
fi
IFS=: read name pass uid gid comment home shell <<< "${passwd}"
if [ -z "${uid}" -o -z "${gid}" -o "${uid}" = 0 -o "${gid}" = 0 ]; then
echo >&2 "Invalid user ${user}"
exit 1
fi
if [ $# -gt 0 ]; then
prog=$1
shift
if [ "${prog:0:1}" != '/' ]; then
absprog=$(which "${prog}")
if [ ! -x "${absprog}" ]; then
echo >&2 "Couldn't find ${prog} in PATH"
exit 1
fi
prog=${absprog}
fi
command=("${prog}" "$@")
else
if [ -z "${shell}" -o ! -x "${shell}" ]; then
echo >&2 "User ${user} has no executable shell"
exit 1
fi
command=("${shell}" -)
fi
args=(
--reuid "${uid}"
--regid "${gid}"
--init-groups
)
if [ "${keepenv}" = 0 ]; then
args+=(
--reset-env
)
fi
if [ -n "${caps}" ]; then
caps=${caps:1} # remove leading comma
args+=(
--inh-caps "${caps}"
--ambient-caps "${caps}"
--securebits +no_setuid_fixup
)
fi
if [ -d "${home}" ]; then
cd "${home}"
else
cd "/"
fi
exec setpriv "${args[@]}" -- "${command[@]}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment