If your software runs a daemon that does not need root privileges, you need to create a user for it. There are two kind of Debian users that can be used by packages: static uids (assigned
bybase-passwd, for a list of static users in Debian see ‘Operating system users and groups’ on page188) and dynamic uids in the range assigned to system users.
In the first case, you need to ask for a user or group id to thebase-passwd. Once the user is available there the package needs to be distributed including a proper versioned depends to thebase-passwdpackage.
In the second case, you need to create the system user either in thepreinstor in thepostinstand make the package depend onadduser (>= 3.11).
The following example code creates the user and group the daemon will run as when the package is installed or upgraded:
[...]
case "$1" in
install|upgrade)
# If the package has default file it could be sourced, so that # the local admin can overwrite the defaults
[ -f "/etc/default/packagename" ] && . /etc/default/packagename
# Sane defaults:
[ -z "$SERVER_HOME" ] && SERVER_HOME=server_dir
[ -z "$SERVER_USER" ] && SERVER_USER=server_user
[ -z "$SERVER_NAME" ] && SERVER_NAME="Server description" [ -z "$SERVER_GROUP" ] && SERVER_GROUP=server_group
# Groups that the user will be added to, if undefined, then none. ADDGROUP=""
# create user to avoid running server as root # 1. create group if not existing
if ! getent group | grep -q "^$SERVER_GROUP:" ; then echo -n "Adding group $SERVER_GROUP.."
addgroup --quiet --system $SERVER_GROUP 2>/dev/null ||true echo "..done"
fi
# 2. create homedir if not existing
test -d $SERVER_HOME || mkdir $SERVER_HOME # 3. create user if not existing
if ! getent passwd | grep -q "^$SERVER_USER:"; then echo -n "Adding system user $SERVER_USER.."
adduser --quiet \ --system \
--no-create-home \ --disabled-password \
$SERVER_USER 2>/dev/null || true echo "..done"
fi
# 4. adjust passwd entry usermod -c "$SERVER_NAME" \
-d $SERVER_HOME \ -g $SERVER_GROUP \
$SERVER_USER
# 5. adjust file and directory permissions
if ! dpkg-statoverride --list $SERVER_HOME >/dev/null then
chown -R $SERVER_USER:adm $SERVER_HOME chmod u=rwx,g=rxs,o= $SERVER_HOME fi
# 6. Add the user to the ADDGROUP group if test -n $ADDGROUP
then
if ! groups $SERVER_USER | cut -d: -f2 | \ grep -qw $ADDGROUP; then
adduser $SERVER_USER $ADDGROUP fi
fi ;;
configure) [...]
You have to make sure that the init.d script file:
• Starts the daemon dropping privileges: if the software does not do thesetuid(2)or
seteuid(2)call itself, you can use the--chuidcall ofstart-stop-daemon.
• Stops the daemon only if the user id matches, you can use the start-stop-daemon --useroption for this.
• Does not run if either the user or the group do not exist:
if ! getent passwd | grep -q "^server_user:"; then echo "Server user does not exist. Aborting" >&2 exit 1
fi
if ! getent group | grep -q "^server_group:" ; then echo "Server group does not exist. Aborting" >&2 exit 1
If the package creates the system user it can remove it when it is purged in its postrm. This has some drawbacks, however. For example, files created by it will be orphaned and might be taken over by a new system user in the future if it is assigned the same uid1. Consequently, removing system users on purge is not yet mandatory and depends on the package needs. If unsure, this action could be handled by asking the administrator for the prefered action when the package is installed (i.e. throughdebconf).
The following example code2removes the user and groups created before only, and only if, the uid is in the range of dynamic assigned system uids and the gid is belongs to a system group:
case "$1" in purge) [...]
# find first and last SYSTEM_UID numbers
for LINE in ‘grep SYSTEM_UID /etc/adduser.conf | grep -v "^#"‘; do case $LINE in
FIRST_SYSTEM_UID*)
FIST_SYSTEM_UID=‘echo $LINE | cut -f2 -d ’=’‘ ;;
LAST_SYSTEM_UID*)
LAST_SYSTEM_UID=‘echo $LINE | cut -f2 -d ’=’‘ ;;
*) ;; esac done
# Remove system account if necessary CREATEDUSER="server_user"
if [ -n "$FIST_SYSTEM_UID" ] && [ -n "$LAST_SYSTEM_UID" ]; then if USERID=‘getent passwd $CREATEDUSER | cut -f 3 -d ’:’‘; then
if [ -n "$USERID" ]; then
if [ "$FIST_SYSTEM_UID" -le "$USERID" ] && \ [ "$USERID" -le "$LAST_SYSTEM_UID" ]; then
echo -n "Removing $CREATEDUSER system user.." deluser --quiet $CREATEDUSER || true
echo "..done" fi
fi fi fi
# Remove system group if necessary
1Some relevant threads discussing these drawbacks include http://lists.debian.org/
debian-mentors/2004/10/msg00338.html and http://lists.debian.org/debian-devel/2004/ 05/msg01156.html
2This might eventually be introduced as a dh_adduser in debhelper. See #81967 (http://bugs.
debian.org/81697), #291177 (http://bugs.debian.org/291177) and #118787 (http://bugs.debian. org/118787).
CREATEDGROUP=server_group
FIRST_USER_GID=‘grep ^USERS_GID /etc/adduser.conf | cut -f2 -d ’=’‘ if [ -n "$FIST_USER_GID" ] then
if GROUPGID=‘getent group $CREATEDGROUP | cut -f 3 -d ’:’‘; then if [ -n "$GROUPGID" ]; then
if [ "$FIST_USER_GID" -gt "$GROUPGID" ]; then echo -n "Removing $CREATEDGROUP group.."
delgroup --only-if-empty $CREATEDGROUP || true echo "..done" fi fi fi fi [...]
Running programs with a user with limited privileges makes sure that any security issue will not be able to damage the full system. It also follows the principle ofleast privilege. Also con- sider you can limit privileges in programs through other mechanisms besides running as non- root3. For more information, read the Minimize Privileges (http://www.dwheeler.com/ secure-programs/Secure-Programs-HOWTO/minimize-privileges.html) chapter of theSecure Programming for Linux and Unix HOWTObook.