$Id: patch-obsd33_isc-dhcp_3.0.1rc12 1023 2008-11-28 07:31:02Z ranga $ Dhcpd 3.0.1rc12 chroot patch for OpenBSD 3.3's /usr/ports/net/isc-dhcp This patch adds minor "security" features to dhcpd: * ability to run as non-root user/group via two new cli options: -u and -g * ability to chroot via a new cli option: -c * disables listening on bootps port if bpf interfaces are successfully configured Apply by doing: cd /usr/ports patch -p0 < patch-obsd33_isc-dhcp_3.0.1rc12 And then build isc-dhcp: cd net/isc-dhcp make clean make To install, remove the existing dhcp pkg (if installed) and: make install To chroot dhcpd: mkdir -p /var/dhcpd/dev mkdir -p /var/dhcpd/var/db mkdir /var/dhcpd/etc mkdir /var/dhcpd/var/run cp /etc/dhcpd.conf /var/dhcpd cd /var/dhcpd/etc && ln -s ../dhcpd.conf . touch /var/dhcpd/var/db/dhcpd.leases chown dhcpd:dhcpd /var/dhcpd/var/db/dhcpd.leases chgrp dhcpd /var/dhcpd/var/db chmod 0775 /var/dhcpd/var/db 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 ln -s /var/dhcpd/dhcpd.conf . To start dhcpd in chroot mode: /usr/local/sbin/dhcpd -u dhcpd -g dhcpd -c /var/dhcpd -q To have dhcpd started automatically on reboot: Add the following to /etc/rc.local: if [ "X${dhcpdv3_flags}" != X"NO" -a -f /etc/dhcpd.conf ]; then touch /var/db/dhcpd.leases 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 Add the following to /etc/rc.conf.local dhcpdv3_flags="-u dhcpd -g dhcpd -c /var/dhcpd -q" diff -urN net/isc-dhcp.orig/Makefile net/isc-dhcp/Makefile --- net/isc-dhcp.orig/Makefile Fri Jan 24 06:57:57 2003 +++ net/isc-dhcp/Makefile Mon Sep 8 00:24:29 2003 @@ -2,7 +2,7 @@ COMMENT= "Dynamic Host Control Protocol Server" -VERSION= 3.0.1rc11 +VERSION= 3.0.1rc12 DISTNAME= isc-dhcp-${VERSION} CATEGORIES= net diff -urN net/isc-dhcp.orig/distinfo net/isc-dhcp/distinfo --- net/isc-dhcp.orig/distinfo Fri Jan 24 06:57:57 2003 +++ net/isc-dhcp/distinfo Mon Sep 8 00:24:41 2003 @@ -1,3 +1,3 @@ -MD5 (dhcp-3.0.1rc11.tar.gz) = af79b0453ac67fb6824247d3d48fff91 -RMD160 (dhcp-3.0.1rc11.tar.gz) = 44b5c9db62b18520830bfcd1ae6be9f434f32381 -SHA1 (dhcp-3.0.1rc11.tar.gz) = 916f8b77e159b3b32c910f6c59e5c0eab58bacf9 +SHA1 (dhcp-3.0.1rc12.tar.gz) = 40ab54590095e304d34e2fed5e2e8c3181151ee3 +RMD160 (dhcp-3.0.1rc12.tar.gz) = 31e666706ac97ce2d67e2c3db6617385a4aaa797 +MD5 (dhcp-3.0.1rc12.tar.gz) = cf00193dcf349c888a62e4462ae1eb9c diff -urN 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 Mon Sep 8 00:25:10 2003 @@ -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 -urN 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 Mon Sep 8 00:25:10 2003 @@ -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 -urN 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 Mon Sep 8 00:25:10 2003 @@ -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 -urN 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 Mon Sep 8 00:26:48 2003 @@ -0,0 +1,27 @@ +#!/bin/sh +# $OpenBSD: DEINSTALL,v 1.7 2002/08/23 14:10:20 brad Exp $ +# +# Dhcpd de-installation + +PATH=/bin:/usr/bin:/sbin:/usr/sbin +PREFIX=${PKG_PREFIX:-/usr/local} +CONFIG_DIR=${SYSCONFDIR} +DHCPDUSER=dhcpd +DHCPDGROUP=dhcpd + +echo +echo "+---------------" +echo "| To completely deinstall the $1 package you need to perform" +echo "| these steps as root:" +echo "|" +echo "| userdel $DHCPDUSER" +echo "| groupdel $DHCPDGROUP" +echo "| rm -f /var/run/dhcpd.pid" +echo "| rm -rf /var/db/dhcp" +echo "|" +echo "| Do not do this if you plan on re-installing $1" +echo "| at some future time." +echo "+---------------" +echo + +exit 0 diff -urN 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 Mon Sep 8 00:26:48 2003 @@ -0,0 +1,101 @@ +#!/bin/sh +# $OpenBSD: INSTALL,v 1.14 2002/08/23 14:10:20 brad Exp $ +# +# 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=dhcpd +DHCPDGROUP=dhcpd +DHCPDB=/var/db/dhcp + +do_usergroup_install() +{ + # Create Dhcpd user and group + groupinfo -e $DHCPDGROUP + if [ $? -eq 0 ]; then + echo "===> Using $DHCPDGROUP group for Dhcpd" + else + echo "===> Creating $DHCPDGROUP group for Dhcpd" + groupadd $DHCPDGROUP + fi + userinfo -e $DHCPDUSER + if [ $? -eq 0 ]; then + echo "===> Using $DHCPDUSER user for Dhcpd" + else + echo "===> Creating $DHCPDUSER user for Dhcpd" + useradd -g $DHCPDGROUP -d /nonexistent -L daemon -c 'Dhcpd Account' -s /sbin/nologin $DHCPDUSER + fi +} + +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 + { chown $DHCPDUSER:$DHCPDGROUP "$DHCPDB" && \ + chmod 755 "$DHCPDB" ; } || return 1 + + 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) + do_usergroup_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