isc_dhcp_server start error : `dhcpd: Can't create PID file /run/dhcp-server/dhcpd.pid: Permission denied.`

dhcpd: Can't create PID file /run/dhcp-server/dhcpd.pid: Permission denied. in /var/log/syslog when starting isc_dhcp_server service isc-dhcp-server start on Ubuntu 15.10 bug report here version of package is 4.3.1-5ubuntu3

Process command is dhcpd -user dhcpd -group dhcpd -f -4 -pf /run/dhcp-server/dhcpd.pid -cf /etc/dhcp/dhcpd.conf eth0 comming from /etc/init.d/isc-dhcp-server file

user@host: /$ cat /etc/init.d/isc-dhcp-server                
#!/bin/sh
#
#

### BEGIN INIT INFO
# Provides:          isc-dhcp-server
# Required-Start:    $remote_fs $network $syslog
# Required-Stop:     $remote_fs $network $syslog
# Should-Start:      $local_fs slapd $named
# Should-Stop:       $local_fs slapd
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: DHCP server
# Description:       Dynamic Host Configuration Protocol Server
### END INIT INFO

PATH=/sbin:/bin:/usr/sbin:/usr/bin

test -f /usr/sbin/dhcpd || exit 0

DHCPD_DEFAULT="${DHCPD_DEFAULT:-/etc/default/isc-dhcp-server}"

# It is not safe to start if we don't have a default configuration...
if [ ! -f "$DHCPD_DEFAULT" ]; then
        echo "$DHCPD_DEFAULT does not exist! - Aborting..."
        if [ "$DHCPD_DEFAULT" = "/etc/default/isc-dhcp-server" ]; then
                echo "Run 'dpkg-reconfigure isc-dhcp-server' to fix the problem."
        fi
        exit 0
fi

. /lib/lsb/init-functions

# Read init script configuration
[ -f "$DHCPD_DEFAULT" ] && . "$DHCPD_DEFAULT"

NAME=dhcpd
DESC="ISC DHCP server"
# fallback to default config file
DHCPD_CONF=${DHCPD_CONF:-/etc/dhcp/dhcpd.conf}
# try to read pid file name from config file, with fallback to /var/run/dhcpd.pid
if [ -z "$DHCPD_PID" ]; then
        DHCPD_PID=$(sed -n -e 's/^[ \t]*pid-file-name[ \t]*"(.*)"[ \t]*;.*$/\1/p' < "$DHCPD_CONF" 2>/dev/null | head -n 1)
fi
DHCPD_PID="${DHCPD_PID:-/var/run/dhcpd.pid}"

test_config()
{
        if ! /usr/sbin/dhcpd -t $OPTIONS -q -cf "$DHCPD_CONF" > /dev/null 2>&1; then
                echo "dhcpd self-test failed. Please fix $DHCPD_CONF."
                echo "The error was: "
                /usr/sbin/dhcpd -t $OPTIONS -cf "$DHCPD_CONF"
                exit 1
        fi
        touch /var/lib/dhcp/dhcpd.leases
}

# single arg is -v for messages, -q for none
check_status()
{
    if [ ! -r "$DHCPD_PID" ]; then
        test "$1" != -v || echo "$NAME is not running."
        return 3
    fi
    if read pid < "$DHCPD_PID" && ps -p "$pid" > /dev/null 2>&1; then
        test "$1" != -v || echo "$NAME is running."
        return 0
    else
        test "$1" != -v || echo "$NAME is not running but $DHCPD_PID exists."
        return 1
    fi
}

case "$1" in
        start)
                test_config
                log_daemon_msg "Starting $DESC" "$NAME"
                start-stop-daemon --start --quiet --pidfile "$DHCPD_PID" \
                        --exec /usr/sbin/dhcpd -- \
                        -q $OPTIONS -cf "$DHCPD_CONF" -pf "$DHCPD_PID" $INTERFACES
                sleep 2

                if check_status -q; then
                        log_end_msg 0
                else
                        log_failure_msg "check syslog for diagnostics."
                        log_end_msg 1
                        exit 1
                fi
                ;;
        stop)
                log_daemon_msg "Stopping $DESC" "$NAME"
                start-stop-daemon --stop --quiet --pidfile "$DHCPD_PID"
                log_end_msg $?
                rm -f "$DHCPD_PID"
                ;;
        restart | force-reload)
                test_config
                $0 stop
                sleep 2
                $0 start
                if [ "$?" != "0" ]; then
                        exit 1
                fi
                ;;
        status)
                echo -n "Status of $DESC: "
                check_status -v
                exit "$?"
                ;;
        *)
                echo "Usage: $0 {start|stop|restart|force-reload|status}"
                exit 1 
esac

exit 0

Solution 1:

I responded in the actual ticket as well, but in 15.10...

It looks like the line in /lib/systemd/system/isc-dhcp-server.service:

exec dhcpd -user dhcpd -group dhcpd -f -4 -pf /run/dhcp-server/dhcpd.pid -cf $CONFIG_FILE $INTERFACES'

is hardcoded and ignores the DHCPD_PID variable from /etc/default/isc-dhcp-server.

I think it should be:

exec dhcpd -user dhcpd -group dhcpd -f -4 -pf $DHCPD_PID -cf $CONFIG_FILE $INTERFACES'

After changing that, you have to run

systemctl daemon-reload

Then you have to set the value in /etc/default/isc-dhcp-server, because if you don't, no default is given and the service fails to start.

DHCPD_PID=/var/run/dhcp-server/dhcpd.pid

Then there are other issues with the file, like it always tries to run:

ExecStartPre=/bin/chown dhcpd:dhcpd /run/dhcp-server

regardless of the specified path. I'm not sure what the intended behavior was, but those two changes solved it for me.

BUT THEN

AppArmor was blocking the file from being written. I'm not very familiar with it, but I added

capability dac_override,

to /etc/apparmor.d/usr.sbin.dhcpd near the other capabilities, restarted the service, and now I have a PID file.

It seems this package has a few issues.

Solution 2:

I had the same issue on Ubuntu Vivid 15.04, without systemd.

audit: type=1400 audit(1453391318.882:44): apparmor="DENIED" operation="capable" profile="/usr/sbin/dhcpd" pid=15957 comm="dhcpd" capability=1 capname="dac_override" audit: type=1400 audit(1453391318.882:45): apparmor="DENIED" operation="capable" profile="/usr/sbin/dhcpd" pid=15957 comm="dhcpd" capability=2 capname="dac_read_search"

I added these two lines to /etc/apparmor.d/usr.sbin.dhcpd

capability dac_override,
capability dac_read_search,

Under the capability setuid, line.

Then apparmor_parser -r /etc/apparmor.d/usr.sbin.dhcpd

Then stop isc-dhcp-server; start isc-dhcp-server