$Id: patch-obsd37_isc-dhcp_chroot 1023 2008-11-28 07:31:02Z ranga $ Dhcpd 3.0.2 chroot patch for OpenBSD 3.7's /usr/ports/net/isc-dhcp This patch adds minor "security" features to dhcpd: * ability to run as non-root user/group via two cli options: -u and -g * ability to chroot via a cli option: -c * disables listening on bootp server port if bpf interfaces are successfully configured See /usr/local/share/docs/isc-dhcp/README.OpenBSD for setup information. Apply by doing: cd /usr/ports patch -p0 < patch-obsd37_isc-dhcp_chroot And then build isc-dhcp: cd net/isc-dhcp make clean make To install, remove the existing dhcp pkg (if installed) and: make install diff net/isc-dhcp.orig/Makefile net/isc-dhcp/Makefile --- net/isc-dhcp.orig/Makefile Fri Aug 6 11:32:27 2004 +++ net/isc-dhcp/Makefile Fri Dec 31 02:10:25 2004 @@ -43,7 +43,9 @@ post-install: ${INSTALL_DATA_DIR} ${PREFIX}/${EXAMPLEDIR} + ${INSTALL_DATA_DIR} ${PREFIX}/share/doc/isc-dhcp ${INSTALL_DATA} ${WRKSRC}/server/dhcpd.conf ${PREFIX}/${EXAMPLEDIR} ${INSTALL_DATA} ${WRKSRC}/client/dhclient.conf ${PREFIX}/${EXAMPLEDIR} + ${INSTALL_DATA} ${FILESDIR}/README.OpenBSD ${PREFIX}/share/doc/isc-dhcp .include diff net/isc-dhcp.orig/files/README.OpenBSD net/isc-dhcp/files/README.OpenBSD --- net/isc-dhcp.orig/files/README.OpenBSD Wed Dec 31 16:00:00 1969 +++ net/isc-dhcp/files/README.OpenBSD Fri Dec 31 02:11:57 2004 @@ -0,0 +1,54 @@ +Enabling dhcpd with chroot and non-root user/group support + +To create a chroot directory for dhcpd do the following: + + mkdir -p /var/dhcpd/dev /var/dhcpd/etc + mkdir -p /var/dhcpd/var/run /var/dhcpd/var/db + chgrp _dhcp /var/dhcpd/var/db /var/dhcpd/var/run + chmod 0775 /var/dhcpd/var/db /var/dhcpd/var/run + cp /etc/dhcpd.conf /var/dhcpd/etc + touch /var/dhcpd/var/db/dhcpd.leases + chown _dhcp:_dhcp /var/dhcpd/var/db/dhcpd.leases + BPFMAJ="`ls -l /dev/bpf0 | awk '{ print $5; }' | sed -e 's/,//g'`" + export BPFMAJ + cd /var/dhcpd/dev + mknod -m 0600 bpf0 c $BPFMAJ 0 + mknod -m 0600 bpf1 c $BPFMAJ 1 + + (optional) + mv /etc/dhcpd.conf /etc/dhcpd.conf.orig + mv /var/db/dhcpd.leases /var/db/dhcpd.leases.orig + ln -s /var/dhcpd/etc/dhcpd.conf /etc/dhcpd.conf + ln -s /var/dhcpd/var/db/dhcpd.leases /var/db/dhcpd.leases + +Dhcpd can be started as user/group _dhcp/_dhcp in the chroot +directory as follows: + + /usr/local/sbin/dhcpd -u _dhcp -g _dhcp -c /var/dhcpd -q + +To have dhcpd automatically started at boot time do the following: + +1. Add the following to /etc/rc.local: + +# isc dhcpd v3 + +if [ -x /usr/local/sbin/dhcpd \ + -a "X${dhcpdv3_flags}" != X"NO" \ + -a -f /etc/dhcpd.conf ]; then + if [ "X${dhcpdv3_leases}" != "X" ] ; then + touch ${dhcpdv3_leases} + else + touch /var/db/dhcpd.leases + fi + if [ -f /etc/dhcpd.interfaces ]; then + dhcpd_ifs=`awk -F\# '{ print $1; }' < /etc/dhcpd.interfaces` + fi + echo -n ' dhcpd (v3)'; /usr/local/sbin/dhcpd ${dhcpdv3_flags} \ + ${dhcpd_ifs} +fi + +2. Add the following to /etc/rc.conf.local + +dhcpdv3_flags="-u _dhcp -g _dhcp -c /var/dhcpd -q" +dhcpdv3_leases="/var/dhcpd/var/db/dhcpd.leases" + diff net/isc-dhcp.orig/patches/patch-common_discover_c net/isc-dhcp/patches/patch-common_discover_c --- net/isc-dhcp.orig/patches/patch-common_discover_c Wed Dec 31 16:00:00 1969 +++ net/isc-dhcp/patches/patch-common_discover_c Fri Dec 31 02:22:02 2004 @@ -0,0 +1,11 @@ +--- common/discover.c.orig Sat Jan 18 19:00:41 2003 ++++ common/discover.c Sat Jan 18 19:02:12 2003 +@@ -678,7 +678,7 @@ + log_fatal ("Not configured to listen on any interfaces!"); + } + +- if (!setup_fallback) { ++ if (state != DISCOVER_SERVER && !setup_fallback) { + setup_fallback = 1; + maybe_setup_fallback (); + } diff net/isc-dhcp.orig/patches/patch-server_dhcpd_8 net/isc-dhcp/patches/patch-server_dhcpd_8 --- net/isc-dhcp.orig/patches/patch-server_dhcpd_8 Wed Dec 31 16:00:00 1969 +++ net/isc-dhcp/patches/patch-server_dhcpd_8 Fri Dec 31 02:22:02 2004 @@ -0,0 +1,42 @@ +--- server/dhcpd.8.orig Sat Nov 16 18:29:31 2002 ++++ server/dhcpd.8 Mon Mar 10 01:16:59 2003 +@@ -61,6 +61,18 @@ + .B -T + ] + [ ++.B -c ++.I chroot-dir ++] ++[ ++.B -u ++.I username ++] ++[ ++.B -g ++.I groupname ++] ++[ + .B -cf + .I config-file + ] +@@ -197,6 +209,20 @@ + reliable or otherwise cannot be used. Normally, dhcpd will log all + output using the syslog(3) function with the log facility set to + LOG_DAEMON. ++.PP ++Dhcpd can be made to run as an alternate user with the ++.B -u ++flag, or as an alternate group with the ++.B -g ++flag. If an alternate user and/or group is specified the configuration ++file must be readable by that user and/or group and both the lease file ++and the pid file must be writeable by that user and/or group. ++.PP ++Dhcpd can be made to run in a chroot environment with the ++.B -c ++flag. If a chroot directory is specified, then the dev/bpf* devices ++must exist in the chroot directory along with copies of the config and ++lease files. + .PP + Dhcpd can be made to use an alternate configuration file with the + .B -cf diff net/isc-dhcp.orig/patches/patch-server_dhcpd_c net/isc-dhcp/patches/patch-server_dhcpd_c --- net/isc-dhcp.orig/patches/patch-server_dhcpd_c Wed Dec 31 16:00:00 1969 +++ net/isc-dhcp/patches/patch-server_dhcpd_c Fri Dec 31 02:22:02 2004 @@ -0,0 +1,153 @@ +--- server/dhcpd.c.orig Tue Jan 14 15:15:24 2003 ++++ server/dhcpd.c Mon Mar 10 00:38:57 2003 +@@ -56,6 +56,15 @@ + #include "version.h" + #include + ++#include ++#include ++#include ++ ++/* Avoid collision ISC declaration of group */ ++#define group real_group ++#include ++#undef group ++ + static void usage PROTO ((void)); + + TIME cur_time; +@@ -236,6 +245,11 @@ + char *traceinfile = (char *)0; + char *traceoutfile = (char *)0; + #endif ++ char *username = (char *)0; ++ char *groupname = (char *)0; ++ char *chrootdir = (char *)0; ++ uid_t userid = 0; ++ gid_t groupid = 0; + + /* Make sure we have stdin, stdout and stderr. */ + status = open ("/dev/null", O_RDWR); +@@ -298,6 +312,18 @@ + if (++i == argc) + usage (); + server = argv [i]; ++ } else if (!strcmp (argv [i], "-u")) { ++ if (++i == argc) ++ usage (); ++ username = argv[i]; ++ } else if (!strcmp (argv [i], "-g")) { ++ if (++i == argc) ++ usage (); ++ groupname = argv[i]; ++ } else if (!strcmp (argv [i], "-c")) { ++ if (++i == argc) ++ usage (); ++ chrootdir = argv[i]; + } else if (!strcmp (argv [i], "-cf")) { + if (++i == argc) + usage (); +@@ -397,6 +423,53 @@ + trace_seed_stop, MDL); + #endif + ++ /* Get user and group info if -u and/or -g was specified */ ++ if (username) ++ { ++ struct passwd *tmp_pwd; ++ ++ if (geteuid()) ++ log_fatal ("Only root can set the user"); ++ ++ if (!(tmp_pwd = getpwnam(username))) ++ log_fatal ("No such user: %s",username); ++ ++ userid = tmp_pwd->pw_uid; ++ ++ if (!groupname) ++ groupid = tmp_pwd->pw_gid; ++ } ++ ++ if (groupname) ++ { ++#define group real_group ++ struct group *tmp_grp; ++ ++ if (geteuid()) ++ log_fatal ("Only root can set the group"); ++ ++ if (!(tmp_grp = getgrnam(groupname))) ++ log_fatal ("No such group: %s", groupname); ++ ++ groupid = tmp_grp->gr_gid; ++#undef group ++ } ++ ++ /* chroot, if requested */ ++ if (chrootdir != (char *)0) ++ { ++ if (geteuid()) ++ log_fatal("Only root can chroot"); ++ ++ if (chdir(chrootdir) < 0) ++ log_fatal("Can't chdir to %s: %s", ++ chrootdir, strerror(errno)); ++ ++ if (chroot(chrootdir) < 0) ++ log_fatal("Can't chroot to %s: %s", ++ chrootdir, strerror(errno)); ++ } ++ + /* Default to the DHCP/BOOTP port. */ + if (!local_port) + { +@@ -535,6 +608,7 @@ + postdb_startup (); + + #ifndef DEBUG ++ + if (daemon) { + /* First part of becoming a daemon... */ + if ((pid = fork ()) < 0) +@@ -543,6 +617,24 @@ + exit (0); + } + ++ /* Change gid and/or uid to the specified ones */ ++ if (groupid) { ++ if (setgroups (0, (void *)0)) ++ log_fatal ("Can't set group: %m"); ++ if (setgid (groupid)) ++ log_fatal ("Can't set group (id=%d): %m", (int) groupid); ++ } ++ ++ if (userid) { ++ /* ensure that the lease file is owned by the specified user */ ++ if (chown (path_dhcpd_db,userid,groupid) < 0) ++ log_fatal ("Can't set owner/group of %s to %d/%d: %m", ++ path_dhcpd_db, (int) userid, (int) groupid); ++ ++ if (setuid (userid)) ++ log_fatal ("Can't set user id to %d: %m", (int) userid); ++ } ++ + /* Read previous pid file. */ + if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) { + status = read (i, pbuf, (sizeof pbuf) - 1); +@@ -886,11 +978,13 @@ + log_info (copyright); + log_info (arr); + +- log_fatal ("Usage: dhcpd [-p ] [-d] [-f]%s%s%s%s", ++ log_fatal ("Usage: dhcpd [-p ] [-d] [-f]%s%s%s%s%s%s", + "\n [-cf config-file] [-lf lease-file]", ++ "\n [-u username] [-g groupname]", ++ "\n [-c chrootdir]", + #if defined (TRACING) +- "\n [-tf trace-output-file]", +- "\n [-play trace-input-file]", ++ "\n [-tf trace-output-file]", ++ "\n [-play trace-input-file]", + #else + "", "", + #endif /* TRACING */ diff net/isc-dhcp.orig/pkg/DEINSTALL net/isc-dhcp/pkg/DEINSTALL --- net/isc-dhcp.orig/pkg/DEINSTALL Wed Dec 31 16:00:00 1969 +++ net/isc-dhcp/pkg/DEINSTALL Fri Dec 31 02:20:26 2004 @@ -0,0 +1,21 @@ +#!/bin/sh +# DEINSTALL - Dhcpd de-installation + +PATH=/bin:/usr/bin:/sbin:/usr/sbin +PREFIX=${PKG_PREFIX:-/usr/local} +CONFIG_DIR=${SYSCONFDIR} +DHCPDPIDF=/var/run/dhcpd.pid +DHCPDLEASEF="/var/db/dhcpd.leases /var/db/dhcpd.leases~" + +echo +echo "+---------------" +echo "| To completely deinstall the $1 package you need to perform" +echo "| the following steps as root:" +echo "|" +echo "| rm -f $DHCPDPIDF $DHCPDLEASEF" +echo "|" +echo "| Do not do this if you plan on re-installing $1" +echo "| at some future time." +echo "+---------------" +echo + diff net/isc-dhcp.orig/pkg/INSTALL net/isc-dhcp/pkg/INSTALL --- net/isc-dhcp.orig/pkg/INSTALL Wed Dec 31 16:00:00 1969 +++ net/isc-dhcp/pkg/INSTALL Fri Dec 31 02:20:08 2004 @@ -0,0 +1,79 @@ +#!/bin/sh +# INSTALL - Pre/post-installation setup of ISC Dhcpd + +PATH=/bin:/usr/bin:/sbin:/usr/sbin +PREFIX=${PKG_PREFIX:-/usr/local} +CONFIG_DIR=${SYSCONFDIR} +SAMPLE_CONFIG_DIR=$PREFIX/share/examples/isc-dhcp +DHCPDUSER=_dhcp +DHCPDGROUP=_dhcp +DHCPDB=/var/db +DHCPDHOME=/var/empty + +do_notice_conf() +{ + echo + echo "+---------------" + echo "| The existing $1 configuration files in $CONFIG_DIR have NOT" + echo "| been changed. You may want to compare them to the current samples in" + echo "| $SAMPLE_CONFIG_DIR, and update your configuration" + echo "| files as needed." +} + +do_install_conf() +{ + install -d -o root -g wheel -m 755 $CONFIG_DIR + install -o root -g wheel -m 644 $SAMPLE_CONFIG_DIR/dhcpd.conf $CONFIG_DIR + echo + echo "+---------------" + echo "| The $1 configuration files have been installed in $CONFIG_DIR." + echo "| Please view these files and change the configuration to meet your needs." +} + +do_install_dhcpd_leases () +{ + if [ ! -d "$DHCPDB" ] ; then + mkdir -p "$DHCPDB" || return 1 + fi + + if [ ! -f "$DHCPDB/dhcpd.leases" ] ; then + touch "$DHCPDB/dhcpd.leases" || return 1 + fi + { chown $DHCPDUSER:$DHCPDGROUP "$DHCPDB/dhcpd.leases" && \ + chmod 644 "$DHCPDB/dhcpd.leases" ; } || return 1 + + return 0 +} + +# verify proper execution +# +if [ $# -ne 2 ]; then + echo "usage: $0 distname { PRE-INSTALL | POST-INSTALL }" >&2 + exit 1 +fi + +# Verify/process the command +# +case $2 in + PRE-INSTALL) + ;; + POST-INSTALL) + do_install_dhcpd_leases + if [ ! -d $CONFIG_DIR ]; then + do_install_conf $1 + elif [ ! -f $CONFIG_DIR/dhcpd.conf ]; then + do_install_conf $1 + else + do_notice_conf $1 + fi + echo "+---------------" + echo + ;; + *) + echo "usage: $0 distname { PRE-INSTALL | POST-INSTALL }" >&2 + exit 1 + ;; +esac + +exit 0 + diff net/isc-dhcp.orig/pkg/PLIST net/isc-dhcp/pkg/PLIST --- net/isc-dhcp.orig/pkg/PLIST Fri Aug 6 11:32:27 2004 +++ net/isc-dhcp/pkg/PLIST Fri Dec 31 02:15:29 2004 @@ -7,5 +7,7 @@ @man man/cat8/dhcrelay.0 sbin/dhcpd sbin/dhcrelay +share/doc/isc-dhcp/ +share/doc/isc-dhcp/README.OpenBSD share/examples/isc-dhcp/ share/examples/isc-dhcp/dhcpd.conf