Saturday, November 13, 2010

Calling FreeBSD Startup Script Experts

Has anyone encountered this situation? I've found several startup scripts on FreeBSD that result in duplicate arguments passed during startup. For example:

vm# uname -a
FreeBSD vm.taosecurity.com 7.3-RELEASE FreeBSD 7.3-RELEASE #0:
Sun Mar 21 06:15:01 UTC 2010
root@walker.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386

vm# pkg_info
sancp-1.6.1_3 A network connection profiler

vm# cat /etc/rc.conf

# -- sysinstall generated deltas -- # Fri Nov 12 16:36:42 2010
# Created: Fri Nov 12 16:36:42 2010
# Enable network daemons for user convenience.
# Please make all changes to this file, not to /etc/defaults/rc.conf.
# This file now contains just the overrides from /etc/defaults/rc.conf.
defaultrouter="10.10.1.1"
hostname="vm.taosecurity.com"
ifconfig_em0="inet 10.10.1.13 netmask 255.255.255.0"
sshd_enable="YES"
sancp_enable="YES"
sancp_interface="em0"

vm# cat /usr/local/etc/rc.d/sancp
#!/bin/sh
#

# PROVIDE: sancp
# REQUIRE: DAEMON
# BEFORE: LOGIN
# KEYWORD: shutdown

# Add the following lines to /etc/rc.conf to enable sancp:
# sancp_enable (bool): Set to YES to enable sancp
# Default: NO
# sancp_flags (str): Extra flags passed to sancp
# Default: -D
# sancp_conf (str): Sancp configuration file
# Default: /usr/local/etc/sancp.conf
# sancp_interface (str): Default: none - MUST BE SET
#
...edited, all comments...

. /etc/rc.subr

name="sancp"
rcvar=`set_rcvar`

command="/usr/local/bin/sancp"

start_precmd=start_precmd

start_precmd()
{
if [ -z "${sancp_interface}" ]; then
err 1 "sancp_interface must set."
fi
}

# set some defaults
load_rc_config $name

: ${sancp_enable="NO"}
: ${sancp_flags="-D"}
: ${sancp_conf="/usr/local/etc/sancp.conf"}
: ${sancp_interface=""}

command_args="${sancp_flags} -c ${sancp_conf} -i ${sancp_interface}"

run_rc_command "$1"

Now look what happens when I start sancp:

vm# /usr/local/etc/rc.d/sancp start
Starting sancp.
(4287) sancp daemonized successfully!

vm# ps -auxww | grep sancp
root 4287 0.0 0.9 4420 2264 ?? Ss 9:53PM 0:00.00
/usr/local/bin/sancp -D -D -c /usr/local/etc/sancp.conf -i em0

That's right, TWO instances of "-D".

I think it has something to do with this, extracted from sh -x output when starting the script another time:


+ _rc_conf_loaded=true
+ [ -f /etc/rc.conf.d/sancp ]
+ : YES
+ : -D
+ : /usr/local/etc/sancp.conf
+ : em0
+ command_args=-D -c /usr/local/etc/sancp.conf -i em0
+ run_rc_command start
+ _return=0
+ rc_arg=start
+ [ -z sancp ]
+ shift 1
+ rc_extra_args=
+ _rc_prefix=
+ eval _override_command=$sancp_program
+ _override_command=
+ command=/usr/local/bin/sancp
+ _keywords=start stop restart rcvar
+ rc_pid=
+ _pidcmd=
+ _procname=/usr/local/bin/sancp
+ [ -n /usr/local/bin/sancp ]
+ [ -n ]
+ _pidcmd=rc_pid=$(check_process /usr/local/bin/sancp )
+ [ -n rc_pid=$(check_process /usr/local/bin/sancp ) ]
+ _keywords=start stop restart rcvar status poll
+ [ -z start ]
+ [ -n ]
+ eval rc_flags=$sancp_flags
+ rc_flags=-D
...edited...
+ echo Starting sancp.
Starting sancp.
+ [ -n ]
+ _doit=/usr/local/bin/sancp -D -D -c /usr/local/etc/sancp.conf -i em0
+ [ -n ]
+ [ -n ]
+ _run_rc_doit /usr/local/bin/sancp -D -D -c /usr/local/etc/sancp.conf -i em0
+ debug run_rc_command: doit: /usr/local/bin/sancp -D -D -c /usr/local/etc/sancp.conf -i em0
+ eval /usr/local/bin/sancp -D -D -c /usr/local/etc/sancp.conf -i em0
+ /usr/local/bin/sancp -D -D -c /usr/local/etc/sancp.conf -i em0
(4075) sancp daemonized successfully!

That "rc_flags=-D" looks suspicious to me.

So what, two instances of -D, you might think. The problem is with more complicated scripts I'm seeing lots of command line arguments duplicated. It's not "clean" and I want to know what this is happening.

Incidentally, I get similar behavior on FreeBSD 8.1. I tried 7.3 here to see if there was a difference.

Any ideas? I've been looking at /etc/rc.subr to see if I can figure out how _run_rc_doit gets built.

For reference, the /usr/local/etc/sancp.conf file is stock:

vm# grep -v ^# /usr/local/etc/sancp.conf

# snort pcap filter format # description
var ip 8 # ether proto 0x0800 # ip traffic
var arp 1544 # ether proto 0x0806 # arp traffic
var loopback 144 # ether proto 0x9000 # Loopback: used to test ethernet interfaces
var 802.3 1024 # ether proto 0x0004 # IEEE 802.3 traffic

var pixfw1 10.10.10.1
var pixfw2 10.10.10.2
var webserver1 10.10.11.24
var webserver2 10.10.11.25
var webserver3 10.10.11.26
var dnsserver1 10.10.11.27
var dnsserver2 10.10.11.28
var mailserver1 10.10.11.29
var mailserver2 10.10.11.30
var proxyserver 10.10.11.30
var ntpserver 210.121.2.64

var icmp 1
var tcp 6
var udp 17

var http 80
var https 443
var ssh 22
var telnet 23
var irc_ports 6665-6667
var dns 53
var highports 1024-65535

known_ports tcp http,https,ssh,telnet,irc_ports,dns
known_ports udp dns

default realtime=log

default stats=log

default pcap=log

default limit=0

default timeout=120

default tcplag=0 # after a tcp connection would normally be considered closed

default rid=0

default status=0

default node=2

default strip-80211=enable

ip any any icmp any any, realtime=pass, pcap=pass, status=1, rid=23, timeout=1500 # test rule

arp any any any any any, ignore # ignore arp traffic
loopback any any any any any, ignore # ignore local ethernet loopback test packets
802.3 any any any any any, ignore # ignore IEEE 802.3 traffic on the switch

ip pixfw1 pixfw2 105 0 0, pcap pass, realtime=pass, status=100, rid=1 #2003-12-14 18:21:53

ip pixfw1 ntpserver 17 123 123, realtime=pass, status=200, rid=2 #2003-12-14 18:21:53
ip pixfw2 ntpserver 17 123 123, realtime=pass, status=200, rid=3 #2003-12-14 18:21:53

ip pixfw2 any tcp highports 80, realtime=pass, status=201, rid=4 #2003-12-14 18:21:53
ip pixfw2 any udp highports 443, realtime=pass, status=202, rid=6 #2003-12-14 18:21:53
ip pixfw2 any udp highports 53, realtime=pass, status=203, rid=5 #2003-12-14 18:21:53

ip proxyserver any tcp highports any, realtime=pass, status=299, rid=8 #2003-12-14 18:21:53

ip any webserver1 6 any 80, realtime=pass, status=301, rid=9 #2003-12-14 19:19:27
ip any webserver1 6 any 443, realtime=pass, status=302, rid=10 #2003-12-14 19:19:27

ip any webserver2 6 any 80, realtime=pass, status=301, rid=11 #2003-12-14 19:19:27
ip any webserver2 6 any 443, realtime=pass, status=302, rid=12 #2003-12-14 19:19:27

ip any webserver3 6 any 80, realtime=pass, status=301, rid=13 #2003-12-14 19:19:27
ip any webserver3 6 any 443, realtime=pass, status=302, rid=14 #2003-12-14 19:19:27

ip any dnsserver1 17 any 53, realtime=pass, status=303, rid=15 #2003-12-14 19:19:27
ip any dnsserver2 17 any 53, realtime=pass, status=303, rid=16 #2003-12-14 19:19:27

ip any mailserver1 6 any 25, realtime=pass, status=304, rid=17 #2003-12-14 19:19:27
ip mailserver1 any 6 any 25, realtime=pass, status=204, rid=18 #2003-12-14 19:19:27

ip any mailserver2 6 any 25, realtime=pass, status=304, rid=19 #2003-12-14 19:19:27
ip mailserver2 any 6 any 25, realtime=pass, status=204, rid=20 #2003-12-14 19:19:27


6 comments:

eriko said...

I believe you can omit ${sancp_flags} when building command_args. That variable is brought in automatically by rc.subr unless overridden in the environment/via rc.conf.

Sevan Janiyan said...

Raised PR with fix, see ports/152226

Richard Bejtlich said...

Thanks guys! So in the future, when I see foo_flags as part of command_args, I should remove foo_flags?

Another example is barnyard2:

http://www.freebsd.org/cgi/cvsweb.cgi/ports/security/barnyard2/files/barnyard2.sh.in?rev=1.2;content-type=text%2Fplain

wxs said...

Yes, I believe eriko is right on this one. I've grabbed the PR and will commit it when maintainer responds.

Giorgos Keramidas said...

The /etc/rc.subr machinery calls the $command that will start the relevant service with:

$command $rc_flags $command_args

So every time you repeat rc_flags to construct command_args you will see duplication.

If there are ports that install bogus scripts (like barnyard2) we should fix their startup scripts to avoid this sort of duplication.

Anonymous said...

Wow I'm really late to this question, nonetheless...

It's probably far better to use /usr/local/etc/rc.d

If you grep local_start /etc/defaults/rc.conf It will probably show "local_startup="/usr/local/etc/rc.d" # startup script dirs"

Regards Pete