Debugging OpenBSD passwd problems

I recently had to manually add a few users to /etc/passwd and /etc/master.passwd on an OpenBSD 3.9 server. After I added the entries, the accounts were still unable to login. I started poking around with ktrace, and noticed that during a normal account creation session the files /etc/pwd.db and /etc/spwd.db were modified:

$ ls -la /etc/*.db

-rw-r--r--  1 root  wheel    40960 Nov 23 05:38 /etc/pwd.db
-rw-r-----  1 root  _shadow  40960 Nov 23 05:38 /etc/spwd.db

After seeing this, I went and read up on both of these files. It turns out that /etc/passwd and /etc/master.passwd get converted to database files by pwd_mkdb, and then the database files are used for actual authentication. Once I ran pwd_mkdb by hand:

$ pwd_mkdb /etc/master.passwd

Everything worked as expected. I reckon other operating systems use database files as well, so I will have to keep this in mind the next time I try to muck with a credential repository manually.

Accessing services behind a NAT

I use the OpenBSD PF (packet filter) firewall at home to protect the systems I run, and to provide access to a few services over the Internet. The services I make accessible to the Internet run on servers in RFC 1918 address space, which requires my OpenBSD gateway to perform translate IP addresses and apply inbound filter policies for the services I expose. The PF documentation describes how to do this, but I thought I would share the setup I use in case folks are interested.

To begin, you should define one or more tables and macros to make your firewall rule file easier to manage. The following example sets up one table with a list of IP addresses we want to allow to access the services we run on our network, and one macro with the external interface of the firewall:

# External interface
$ext = “hme1”

# Define a table with acceptable IP addresses
table { 1.2.3.4/32, 1.2.3.5/32 }

Once the tables and macros are setup, you will need to add a redirect statement to translate the DST IP address to the RFC 1918 address your server is using for each TCP segment that matches the policy (i.e. all requests from <work> to TCP port 443):

# NAT the DST IP in all HTTPS connections from
rdr on $ext proto tcp from <work> to X.X.X.X port 443 -> 192.168.100.100 port 443

Now that the redirect statement is in place (you will need to change X.X.X.X to the external IP address of your firewall), we can define a rule to allow connections to the server that runs the secure web server:

# Allow HTTPS connections
pass in quick on $ext proto tcp from <work> to 192.168.100.100 port 443 keep state

Once you add the pass statement, you can test connectivity by pointing your web browser to the IP address of your firewall. I could have used a single rdr statement to NAT and filter the traffic, but I like to split these up to make things easier to read.

Visualizing IP Filter and PF state tables

IP Filter is a stateful packet inspecting firewall that ships with FreeBSD and Solaris 10. Stateful packet inspecting firewalls use a state table to maintain established connections, which allows packets to traverse the firewall if they are part of an existing established connection. IP filter comes with the ipfstat(1m) utility, which can be used to print connection statistics, rule definitions, and active connection. When ipfstat(1m) is invoked with the “-t” (Show the state table in a way similar to the way the Unix utility, top, shows the process table) option, a text-based graphical representation of the firewall is continuosly displayed:

$ ipfstat -t

                 sparky - IP Filter: v4.0.2 - state top                 10:47:32

Src = 0.0.0.0  Dest = 0.0.0.0  Proto = any  Sorted by = # bytes

Source IP             Destination IP         ST   PR   #pkts    #bytes       ttl
12.6.4.12,32776   1.2.5.4,22        B/7  tcp     140     10112      0:00
12.6.4.12,32775   1.2.5.3,22        B/7  tcp     134      9872      0:00

To adjust the refresh interval, an integer value can be passed to ipfstat’s “-T” (Specifies how often the state top display should be updated) option:

$ ipfstat -t -T 10

                 sparky - IP Filter: v4.0.2 - state top                 10:47:32

Src = 0.0.0.0  Dest = 0.0.0.0  Proto = any  Sorted by = # bytes

Source IP             Destination IP         ST   PR   #pkts    #bytes       ttl
12.6.4.12,32776   1.2.5.4,22        B/7  tcp     140     10112      0:00
12.6.4.12,32775   1.2.5.3,22        B/7  tcp     134      9872      0:00

If you are using the PF firewall, you can use pftop(8) to get a text-based graphical representation of the PF state table:

$ pftop

pfTop: Up State 1-3/3, View: default, Order: none, Cache: 10000                              09:37:53

PR   DIR SRC                 DEST                           STATE                AGE       EXP     PKTS    BYTES
tcp  Out 192.168.1.8:49359   66.102.15.101:80      ESTABLISHED:ESTABLISHED  19:29:55  04:30:08        5      676

To adjust pftop(8)’s refresh interval, an integer value can be passed to pftop(8)’s “-s” (Set the delay between display updates to time seconds) option:

$ pftop -t -T 10

pfTop: Up State 1-3/3, View: default, Order: none, Cache: 10000                              09:37:53

PR   DIR SRC                 DEST                           STATE                AGE       EXP     PKTS    BYTES
tcp  Out 192.168.1.8:49359   66.102.15.101:80      ESTABLISHED:ESTABLISHED  19:29:55  04:30:08        5      676

I find myself frequently using these utilities, and find them super useful!

PF’s skip on interface directive

The OpenBSD packet filter (PF) received several enhancements in OpenBSD 3.7. One of the coolest things is the ability to tell PF not to filter traffic on specific interfaces, such as the loopback interface. This behavior is defined in the pf.conf configuration file with the “set skip on” statement:

set skip on lo0

Prior to the “set skip on” option you had to explicilty allow traffic to flow with the following pass statements:

pass in quick on lo0 all
pass out quick on lo0 all

This of course assumes a default policy of “block everything not explicilty allowed,” which all firewalls _SHOULD_ be using.

Reading OpenBSD PF log entries in realtime

When the OpenBSD packet filter (PF) is configured to log traffic, each packet is logged to the OpenBSD “pflog” pseudo-device. This device can be queried with several tools, including tcpdump:

oscar# tcpdump -i pflog0 -ttt -e -o
tcpdump: WARNING: pflog0: no IPv4 address assigned
tcpdump: listening on pflog0
Jan 23 21:27:33.361173 rule 4/0(match): block in on tun0: 12.144.129.35 > adsl-19-10-38.asm.bellsouth.net: icmp: echo request
Jan 23 21:28:01.505716 rule 4/0(match): block in on tun0: 217.20.209.217.34777 > adsl-19-10-38.asm.bellsouth.net.socks: S (src OS: short-pkt) 3962893738:3962893738(0) win 5840 (DF)

If you are running a busy firewall, you are probably using pflogd to archive this information to a file on your FFS file system. I occassionally like to monitor pflog0 when I am testing new services, especially ones that don’t play nicely with firewalls.