9.2. Creating users and groups for software daemons

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 by base-passwd, for a list of static users in Debian see 第 12.1.1.12 节 “操作系统的用户与组”) 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 the base-passwd. Once the user is available there the package needs to be distributed including a proper versioned depends to the base-passwd package.

In the second case, you need to create the system user either in the preinst or in the postinst and make the package depend on adduser (>= 3.11).

The following example code creates the user and group the daemon will run as when the package is installed or upgraded:

  1. [...]
  2. case "$1" in
  3. install|upgrade)
  4.  
  5. # If the package has default file it could be sourced, so that
  6. # the local admin can overwrite the defaults
  7.  
  8. [ -f "/etc/default/packagename" ] && . /etc/default/packagename
  9.  
  10. # Sane defaults:
  11.  
  12. [ -z "$SERVER_HOME" ] && SERVER_HOME=server_dir
  13. [ -z "$SERVER_USER" ] && SERVER_USER=server_user
  14. [ -z "$SERVER_NAME" ] && SERVER_NAME="Server description"
  15. [ -z "$SERVER_GROUP" ] && SERVER_GROUP=server_group
  16.  
  17. # Groups that the user will be added to, if undefined, then none.
  18. ADDGROUP=""
  19.  
  20. # create user to avoid running server as root
  21. # 1. create group if not existing
  22. if ! getent group | grep -q "^$SERVER_GROUP:" ; then
  23. echo -n "Adding group $SERVER_GROUP.."
  24. addgroup --quiet --system $SERVER_GROUP 2>/dev/null ||true
  25. echo "..done"
  26. fi
  27. # 2. create homedir if not existing
  28. test -d $SERVER_HOME || mkdir $SERVER_HOME
  29. # 3. create user if not existing
  30. if ! getent passwd | grep -q "^$SERVER_USER:"; then
  31. echo -n "Adding system user $SERVER_USER.."
  32. adduser --quiet \
  33. --system \
  34. --ingroup $SERVER_GROUP \
  35. --no-create-home \
  36. --disabled-password \
  37. $SERVER_USER 2>/dev/null || true
  38. echo "..done"
  39. fi
  40. # 4. adjust passwd entry
  41. usermod -c "$SERVER_NAME" \
  42. -d $SERVER_HOME \
  43. -g $SERVER_GROUP \
  44. $SERVER_USER
  45. # 5. adjust file and directory permissions
  46. if ! dpkg-statoverride --list $SERVER_HOME >/dev/null
  47. then
  48. chown -R $SERVER_USER:adm $SERVER_HOME
  49. chmod u=rwx,g=rxs,o= $SERVER_HOME
  50. fi
  51. # 6. Add the user to the ADDGROUP group
  52. if test -n $ADDGROUP
  53. then
  54. if ! groups $SERVER_USER | cut -d: -f2 | \
  55. grep -qw $ADDGROUP; then
  56. adduser $SERVER_USER $ADDGROUP
  57. fi
  58. fi
  59. ;;
  60. configure)
  61.  
  62. [...]

You have to make sure that the init.d script file:

  • Starts the daemon dropping privileges: if the software does not do the setuid(2) or seteuid(2) call itself, you can use the --chuid call of start-stop-daemon.

  • Stops the daemon only if the user id matches, you can use the start-stop-daemon --user option for this.

  • Does not run if either the user or the group do not exist:

    1. if ! getent passwd | grep -q "^server_user:"; then
    2. echo "Server user does not exist. Aborting" >&2
    3. exit 1
    4. fi
    5. if ! getent group | grep -q "^server_group:" ; then
    6. echo "Server group does not exist. Aborting" >&2
    7. exit 1
    8. fi

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 uid[59]. 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. through debconf).

Maintainers that want to remove users in their postrm scripts are referred to the deluser/deluser --system option.

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 of least privilege. Also consider you can limit privileges in programs through other mechanisms besides running as non-root[60]. For more information, read the http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/minimize-privileges.html chapter of the Secure Programming for Linux and Unix HOWTO book.


[59] Some 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

[60] You can even provide a SELinux policy for it