diff --git a/security/doorman/Makefile b/security/doorman/Makefile index 74b742e8aa03..02ff48321ec6 100644 --- a/security/doorman/Makefile +++ b/security/doorman/Makefile @@ -7,6 +7,7 @@ PORTNAME= doorman PORTVERSION= 0.8 +PORTREVISION= 1 CATEGORIES= security MASTER_SITES= ${MASTER_SITE_SOURCEFORGE} MASTER_SITE_SUBDIR= doorman @@ -18,13 +19,14 @@ COMMENT= A Port Knocking implementation, both daemon and client BUILD_DEPENDS= lsof:${PORTSDIR}/sysutils/lsof RUN_DEPENDS= ${BUILD_DEPENDS} -IGNORE= does not work correctly, issues with the pcap library. Patches are under development - PKGMESSAGE= ${WRKDIR}/pkg-message +PATCH_STRIP= -p1 # Default to db4 WITH_BDB_VER?= 4 +.include + .if ${WITH_BDB_VER} == 2 LIB_DEPENDS= db2.0:${PORTSDIR}/databases/db2 .elif ${WITH_BDB_VER} == 3 @@ -39,11 +41,21 @@ LIB_DEPENDS= db-4.2.2:${PORTSDIR}/databases/db42 .error WITH_BDB_VER must be one between 2, 3, 4, 41 and 42 .endif +# doormand does not work with the FreeBSD 4.x version of libpcap. +# Require the ports version. +.if ${OSVERSION} < 500000 +BUILD_DEPENDS+= ${LOCALBASE}/lib/libpcap.a:${PORTSDIR}/net/libpcap +.endif + +INSTALL_TARGET= installdirs install-exec install-data + MAN1= knock.1 MAN5= knockcf.5 doormand.cf.5 guestlist.5 MAN8= doormand.8 GNU_CONFIGURE= yes +SUB_FILES= pkg-message +USE_RC_SUBR= doorman.sh pre-everything:: @${ECHO_MSG} @@ -55,10 +67,20 @@ pre-everything:: @${ECHO_MSG} " CURRENTLY BUILDING WITH db${WITH_BDB_VER} " @${ECHO_MSG} -pre-install: - @${SED} 's#%%PREFIX%%#${PREFIX}#' ${MASTERDIR}/pkg-message >${PKGMESSAGE} - post-install: + ${RM} -f ${PREFIX}/etc/doormand/ipf_add + ${INSTALL_SCRIPT} ${FILESDIR}/ipf_add.atend ${PREFIX}/etc/doormand/ipf_add.atend + ${INSTALL_SCRIPT} ${FILESDIR}/ipf_add.before_block ${PREFIX}/etc/doormand/ipf_add.before_block + ${INSTALL_SCRIPT} ${FILESDIR}/ipf_delete ${PREFIX}/etc/doormand/ipf_delete + @for man in ${MAN1}; do \ + ${INSTALL_MAN} -C ${WRKSRC}/$$man ${PREFIX}/man/man1; \ + done + @for man in ${MAN5}; do \ + ${INSTALL_MAN} -C ${WRKSRC}/$$man ${PREFIX}/man/man5; \ + done + @for man in ${MAN8}; do \ + ${INSTALL_MAN} -C ${WRKSRC}/$$man ${PREFIX}/man/man8; \ + done @${CAT} ${PKGMESSAGE} -.include +.include diff --git a/security/doorman/files/doorman.sh.in b/security/doorman/files/doorman.sh.in new file mode 100644 index 000000000000..883c83f5779f --- /dev/null +++ b/security/doorman/files/doorman.sh.in @@ -0,0 +1,30 @@ +#!/bin/sh +# + +# PROVIDE: doorman +# REQUIRE: LOGIN +# KEYWORD: FreeBSD + +# +# Add the following lines to /etc/rc.conf to enable doorman: +# doorman_enable (bool): Set to "NO" by default. +# Set it to "YES" to enable doorman +# doorman_config (path): Set to "%%PREFIX%%/etc/doormand/doormand.cf" by default. +# + +. %%RC_SUBR%% + +name="doorman" +rcvar=`set_rcvar` + +[ -z "$doorman_enable" ] && doorman_enable="NO" +[ -z "$doorman_config" ] && doorman_config="%%PREFIX%%/etc/doormand/doormand.cf" + +[ -f "$doorman_config" ] || (echo "$doorman_config" does not exist.; exit) + +command=%%PREFIX%%/sbin/doormand +pidfile=/var/run/doormand.pid +command_args="-p $pidfile -f $doorman_config" + +load_rc_config $name +run_rc_command "$1" diff --git a/security/doorman/files/ipf_add.atend b/security/doorman/files/ipf_add.atend new file mode 100644 index 000000000000..93a300f9c97f --- /dev/null +++ b/security/doorman/files/ipf_add.atend @@ -0,0 +1,73 @@ +#!/bin/sh +# +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# +# WARNING! +# +# This script has not been tested. The author does not run this kind +# of firewall rules and is too lazy to build a firewall that does +# just for testing. +# +# If you use this script and either find it *does* work (surprise!) +# or have modifications that make it work, please send mail to +# tke FreeBSD port maintainer. (See port Makefile). +# +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +# ********************************************************************* +# This script is used with IPFilter if the ruleset (/etc/ipf.rules) +# does not contain explicit drop rules that mask a rule added at the end. +# +# The script will add it's rules at the end. +# +# Note that it does not use locking, so concurrent accesses may +# interfere with each other. +# ********************************************************************* +# +# file "ipf_add.atend" +# IPFilter add script, called by "doormand". +# This add "pass in quick" rules to the firewall. +# +# Called with five arguments: +# +# $1 : name of the interface (e.g. ne0) +# $2 : source IP; i.e. dotted-decimal address of the 'knock' client +# $3 : source port; when this script is called for the first time +# for a connection (man 8 doormand), this argument will be set +# to a single "0" (0x30) character. This means that the source +# port is not yet known, and a broad rule allowing any source +# port is required. +# $4 : destination IP; that is, the IP address of the interface +# in argument 1. +# $5 : The port number of the requested service (e.g. 22 for ssh, etc.) +# + +# This script expects the IPFilter ruleset to have two rules like this: +inblock="block in log quick on $1 from any to any" +outblock="block out log quick on $1 from any to any" +# The new rules will be inserted just before these blocking rules. + +if [ $3 = 0 ]; then + inrule="pass in quick on $1 proto TCP from $2 to $4 port = $5" + outrule="pass out quick on $1 proto TCP from $4 port = $5 to $2" +else + inrule="pass in quick on $1 proto TCP from $2 port = $3 to $4 port = $5" + outrule="pass out quick on $1 proto TCP from $4 port = $5 to $2 port = $3" +fi + +# +# acquire lock (not implemented) +# + +# Insert new rules. +ret=`(echo $inrule; echo $outrule) | /sbin/ipf -f - 2>&1` + +# +# release lock (not implemented) +# + +if [ -z "$ret" ]; then + echo 0 +else + echo -1 3 $ret +fi diff --git a/security/doorman/files/ipf_add.before_block b/security/doorman/files/ipf_add.before_block new file mode 100644 index 000000000000..12e89c0f45cc --- /dev/null +++ b/security/doorman/files/ipf_add.before_block @@ -0,0 +1,67 @@ +#!/bin/sh +# +# ********************************************************************* +# This script is used with IPFilter if the ruleset (/etc/ipf.rules) +# contains an explicit drop rule that masks a rule added at the end. +# It expects block rules for both input and output filters. This +# works e.g. with rule sets generated by fwbuilder. +# +# The script will insert it's rule before the drop rule. The drop rules +# are expected to look like the $inblock and $outblock variables +# defined below. +# +# Note that it does not use locking, so concurrent accesses may +# interfere with each other. +# ********************************************************************* +# +# file "ipf_add.before_block" +# IPFilter add script, called by "doormand". +# This add two "pass in quick" rules to the firewall. +# +# Called with five arguments: +# +# $1 : name of the interface (e.g. ne0) +# $2 : source IP; i.e. dotted-decimal address of the 'knock' client +# $3 : source port; when this script is called for the first time +# for a connection (man 8 doormand), this argument will be set +# to a single "0" (0x30) character. This means that the source +# port is not yet known, and a broad rule allowing any source +# port is required. +# $4 : destination IP; that is, the IP address of the interface +# in argument 1. +# $5 : The port number of the requested service (e.g. 22 for ssh, etc.) +# + +# This script expects the IPFilter ruleset to have two rules like this: +inblock="block in log quick on $1 from any to any" +outblock="block out log quick on $1 from any to any" +# The new rules will be inserted just before these blocking rules. + +if [ $3 = 0 ]; then + inrule="pass in quick on $1 proto TCP from $2 to $4 port = $5" + outrule="pass out quick on $1 proto TCP from $4 port = $5 to $2" +else + inrule="pass in quick on $1 proto TCP from $2 port = $3 to $4 port = $5" + outrule="pass out quick on $1 proto TCP from $4 port = $5 to $2 port = $3" +fi + +# +# acquire lock (not implemented) +# + +# Find the rule numbers of the block rules. +inruleno=`ipfstat -in | sed -n -e "s/@\([0-9]*\) $inblock/\1/p"` +outruleno=`ipfstat -on | sed -n -e "s/@\([0-9]*\) $outblock/\1/p"` + +# Insert new rules. +ret=`(echo @$inruleno $inrule; echo @$outruleno $outrule) | /sbin/ipf -f - 2>&1` + +# +# release lock (not implemented) +# + +if [ -z "$ret" ]; then + echo 0 +else + echo -1 3 $ret +fi diff --git a/security/doorman/files/ipf_delete b/security/doorman/files/ipf_delete new file mode 100644 index 000000000000..df82a248a4a9 --- /dev/null +++ b/security/doorman/files/ipf_delete @@ -0,0 +1,38 @@ +#!/bin/sh +# +# file "ipf_delete" +# IPFilter firewall-delete script, called by "doormand". +# This removes the "pass in quick" rules from the firewall +# that were added by one of the ipf_add scripts. +# +# Called with five arguments: +# +# $1 : name of the interface (e.g. ne0) +# $2 : source IP; i.e. dotted-decimal address of the 'knock' client +# $3 : source port; when this script is called for the first time +# to delete a broad firewall rule, this argument will be set +# to a single "0" (0x30) character. This means that the source +# port was not known, and a broad rule allowing any source +# port was set. +# $4 : destination IP; that is, the IP address of the interface +# in argument 1. +# $5 : The port number of the requested service (e.g. 22 for ssh, etc.) +# +# +if [ $3 = 0 ]; then + inrule="pass in quick on $1 proto TCP from $2 to $4 port = $5" + outrule="pass out quick on $1 proto TCP from $4 port = $5 to $2" +else + inrule="pass in quick on $1 proto TCP from $2 port = $3 to $4 port = $5" + outrule="pass out quick on $1 proto TCP from $4 port = $5 to $2 port = $3" +fi + +ret=`(echo @$inruleno $inrule; echo @$outruleno $outrule) | /sbin/ipf -r -f - 2>&1` + +if [ -z "$ret" ] +then + echo 0 +else + echo -1 3 $ret +fi + diff --git a/security/doorman/files/patch-doormand.c b/security/doorman/files/patch-doormand.c new file mode 100644 index 000000000000..2ee4e4cbeaff --- /dev/null +++ b/security/doorman/files/patch-doormand.c @@ -0,0 +1,165 @@ +--- doorman-0.8.orig/doormand.c Thu Jul 29 21:24:02 2004 ++++ doorman-0.8/doormand.c Sun May 29 09:05:31 2005 +@@ -397,7 +397,11 @@ + int datalink_header_lengths[] = { + // hdr len code data link type + // ------- --- --------------------------- ++#ifdef __FreeBSD__ ++ 4, // 0 no link-layer encapsulation ++#else + 0, // 0 no link-layer encapsulation ++#endif + 14, // 1 Ethernet (10Mb) + -1, // 2 Experimental Ethernet (3Mb) + -1, // 3 Amateur Radio AX.25 +@@ -557,6 +561,14 @@ + // more readable. + // + ++/* ++// lsof on FreeBSD produces one more field. ++// This should be rewritten to use a regular expression, anyway. ++// ++// And who said using C++ style comments in C was good for portability?!? ++*/ ++ ++#ifdef __FreeBSD__ + #define LSOF()\ + sprintf (cmd, "lsof -Pn -iTCP@%s:%s", interface_ip_str, dport_string) ;\ + \ +@@ -578,6 +590,7 @@ + if ((p1 = token (&p2, " ")) == NULL) continue ;\ + if ((p1 = token (&p2, " ")) == NULL) continue ;\ + if ((p1 = token (&p2, " ")) == NULL) continue ;\ ++ if ((p1 = token (&p2, " ")) == NULL) continue ;\ + if ((p1 = token (&p2, " :")) == NULL) continue ;\ + local_ip = inet_addr(p1) ;\ + if ((p1 = token (&p2, "-")) == NULL) continue ;\ +@@ -602,7 +615,53 @@ + }\ + }\ + pclose(f) ; +- ++#else ++#define LSOF()\ ++sprintf (cmd, "lsof -Pn -iTCP@%s:%s", interface_ip_str, dport_string) ;\ ++\ ++f = popen (cmd, "r") ;\ ++if (f == NULL) {\ ++ croak (errno, "Can't execute '%s'; exiting.", cmd) ;\ ++}\ ++\ ++fgets(buffer, 254, f) ; /* throw away the first line. */ \ ++while (fgets(buffer, 254, f)) {\ ++ p2 = buffer ;\ ++ if ((p1 = token (&p2, " ")) == NULL) continue ;\ ++ dname = p1 ;\ ++ if ((p1 = token (&p2, " ")) == NULL) continue ;\ ++ pid = p1 ;\ ++ if ((p1 = token (&p2, " ")) == NULL) continue ;\ ++ uname = p1 ;\ ++ if ((p1 = token (&p2, " ")) == NULL) continue ;\ ++ if ((p1 = token (&p2, " ")) == NULL) continue ;\ ++ if ((p1 = token (&p2, " ")) == NULL) continue ;\ ++ if ((p1 = token (&p2, " ")) == NULL) continue ;\ ++ if ((p1 = token (&p2, " :")) == NULL) continue ;\ ++ local_ip = inet_addr(p1) ;\ ++ if ((p1 = token (&p2, "-")) == NULL) continue ;\ ++ local_port = atoi(p1) ;\ ++ if ((p1 = token (&p2, "->:")) == NULL) continue ;\ ++ aptr = p1 ;\ ++ remote_ip = inet_addr(p1) ;\ ++ if ((p1 = token (&p2, " ")) == NULL) continue ;\ ++ pptr = p1 ;\ ++ remote_port = atoi(p1) ;\ ++ if ((p1 = token (&p2, " ()")) == NULL) continue ;\ ++ status = p1 ;\ ++\ ++ if ((saddr == remote_ip) &&\ ++ (daddr == local_ip) &&\ ++ (sport == remote_port) &&\ ++ (dport == local_port) && \ ++ (strcmp(status, "ESTABLISHED") == 0))\ ++ {\ ++ connected = TRUE ;\ ++ break ;\ ++ }\ ++}\ ++pclose(f) ; ++#endif + + + +@@ -647,7 +706,11 @@ + snprintf (cmd, 254, "tcp and dst port %s and src %s and dst %s", + dport_string, src_addr, interface_ip_str) ; + DEBUG "open a secondary pcap: '%s'", cmd) ; ++#ifdef __FreeBSD__ ++ hdr_len = open_a_pcap (device, 1000, &cap, cmd) ; ++#else + hdr_len = open_a_pcap (device, 0, &cap, cmd) ; ++#endif + + // set broad firewall rule + sprintf (G_fw_broad_rule, " %s %s 0 %s %s", +@@ -659,7 +722,22 @@ + + for (;;) { + ++#ifdef __FreeBSD__ ++ { ++ int ret = 0; ++ struct pcap_pkthdr * packet_hdr_p; ++ ++ while (ret == 0) { ++ ret = pcap_next_ex (cap, &packet_hdr_p, (const u_char **)&p) ; ++ packet_hdr = *packet_hdr_p; ++ if (ret < 0) { ++ p = NULL; ++ } ++ } ++ } ++#else + p = (unsigned char*)pcap_next (cap, &packet_hdr) ; ++#endif + if (p == NULL) { + WARNX "manage_firewall got null from 'pcap_next'. Exiting.") ; + exit (1) ; +@@ -1222,9 +1300,13 @@ + croak (errno, "Can't get interface address of %s", device) ; + } + ++#ifdef __FreeBSD__ ++ hdr_len = open_a_pcap (device, 1000, &G_cap, "udp and port %d and dst %s", ++ port, interface_ip) ; ++#else + hdr_len = open_a_pcap (device, 0, &G_cap, "udp and port %d and dst %s", + port, interface_ip) ; +- ++#endif + if (G_reconfigure) { + G_reconfigure = FALSE ; + NOTICE "reconfigured.") ; +@@ -1252,7 +1334,22 @@ + char src_addr_buff[16] ; + + errno = 0 ; ++#ifdef __FreeBSD__ ++ { ++ int ret = 0; ++ struct pcap_pkthdr * packet_hdr_p; ++ ++ while (ret == 0) { ++ ret = pcap_next_ex (G_cap, &packet_hdr_p, (const u_char **)&p) ; ++ packet_hdr = *packet_hdr_p; ++ if (ret < 0) { ++ p = NULL; ++ } ++ } ++ } ++#else + p = (unsigned char *)pcap_next (G_cap, &packet_hdr) ; ++#endif + if (G_reconfigure) { + if (daemonize) err_closelog() ; + goto reconfigure ; diff --git a/security/doorman/pkg-message b/security/doorman/files/pkg-message.in similarity index 75% rename from security/doorman/pkg-message rename to security/doorman/files/pkg-message.in index 8b78284ab462..c8fc23506e81 100644 --- a/security/doorman/pkg-message +++ b/security/doorman/files/pkg-message.in @@ -9,4 +9,9 @@ To configure Doorman, please edit the files guestlist and doormand.cf found in or by visiting the Doorman website at http://doorman.sourceforge.net. +The doormand daemon will *not* be started automatically. To allow it +to start, put this line in /etc/rc.conf: + +doorman_enable="YES" + ****************************************************************************** diff --git a/security/doorman/pkg-descr b/security/doorman/pkg-descr index 22e5c3dffe25..bf3177b61121 100644 --- a/security/doorman/pkg-descr +++ b/security/doorman/pkg-descr @@ -4,6 +4,3 @@ the secret knock! WWW: http://doorman.sourceforge.net/ Author: Bruce Ward - -- Aaron Dalton -aaron@daltons.ca diff --git a/security/doorman/pkg-plist b/security/doorman/pkg-plist index 797aa76fbd24..b786195a8f02 100644 --- a/security/doorman/pkg-plist +++ b/security/doorman/pkg-plist @@ -3,7 +3,8 @@ etc/doormand/doormand.cf.EXAMPLE etc/doormand/guestlist.EXAMPLE etc/doormand/ipchains_add etc/doormand/ipchains_delete -etc/doormand/ipf_add +etc/doormand/ipf_add.atend +etc/doormand/ipf_add.before_block etc/doormand/ipf_delete etc/doormand/ipfw_add etc/doormand/ipfw_delete @@ -12,4 +13,4 @@ etc/doormand/iptables_delete etc/doormand/pfctl_add etc/doormand/pfctl_delete sbin/doormand -@dirrm etc/doormand +@unexec rmdir %D/etc/doormand 2>/dev/null || true