Gotta give IE7 some serious Google juice.  This has got to be one of the most important hacks of the IE5-6 era.  Even after understanding what the magic Javascript does, I’m still amazed that it manages to fix so many of the rendering bugs IE.  At some point I’m going to scrap my IE-specific workarounds for this site and just use proper CSS and the IE7 patch for those unfortunately souls stuck with Internet Explorer.

Note that IE7 won’t fix every problem with IE, but it certainly picks off the major ones (lack of position: fixed, inability to specify right: and left: at the same time, etc.).  If I have some time, I might try to get my own hack to fix <textarea style="height: 100%;"> for CSS strict mode in IE.  I suppose it might be time to revisit my Design for Firefox, Hack for IE article and replace it with a “Design for Firefox, Use IE7 for IE” one instead.

To be fair to Microsoft, my big CSS issue with Mozilla is the lack of support for display: inline-block in Mozilla/Firefox.  Once bug 9458 is fixed, we can stop using the “display: -moz-inline-box” hack to work around it.

Read full post

Setting up a CVS server on a Unix system usually means that you either run CVS in its insecure :pserver: mode or run it over SSH, requiring that the CVS users have a shell account and consequently, full access to your system.  The concept of a “chroot jail” is an essential part of isolating remote service users from remote system administrators.

Thanks to the magic of pam_chroot, you can host a full-featured, encrypted and secure CVS server on any server with SSH.  Users are able to connect to CVS via SSH but are denied access to any sort of command-line.

pam_chroot is part of the standard PAM modules.  It consults /etc/security/chroot.conf for a list of users to be chroot jailed:

# /etc/security/chroot.conf
# format:
# username_regex        chroot_dir
someuser                 /home/chroot_directory

This entry indicates that whenever the user “someuser” logs in, they are to be shuttled off into the virtual root /home/chroot_directory. They will only have access to commands and libraries available within that virtual root.

A default-configured Fedora Core 3 system won’t have chroot in place out-of-the-box. We need to tell the system that whenever the user logs in via SSH, they should first be authenticated and then dropped into the chroot jail if we’ve set them up in chroot.conf. This is done by editing the /etc/pam.d/sshd entry and adding the entry:

auth       required service=system-auth
auth       required
account    required service=system-auth
password   required service=system-auth
session    required
session    required service=system-auth
session    required
session    required
session    optional

Once the user has authenticated via the system authentication stack the chroot will take effect. Note that the remainder of PAM authentication is beyond the scope of this article. Consult the pam man-page and system documentation for more information.

The final step to enabling chroot on SSH is disabling privilege seperation in the SSH daemon. Privilege seperation is part of the SSH secure design that drops root access in certain parts of the application that don’t need it. Since the chroot system call requires root access, we need to disable this part of the system. This is done by editing the /etc/ssh/sshd_config file and adding the line:

UsePrivilegeSeparation no

You’ll need to restart SSH to let it pick up the configuration change.

servive sshd restart

Now that the chroot setup is complete, we need to build the chroot jail. You’ll need to determine exactly what your users will need within the jail and copy those files only. Make sure that you’ve got the cvs package installed before following these steps.

The following steps are inspired by the information provided by Julio Merino for a similar setup in NetBSD:

# Create the CVS chroot directory
mkdir -p /var/chroot/cvs
# Create the required root directories
cd /var/chroot/cvs
mkdir -p bin cvs dev etc home lib sbin tmp var
# Link the usr directory to the root
ln -s . usr
# Set the appropriate permissions on cvs and tmp
chmod 770 cvs
chmod 1777 tmp

We’ll now copy the required binaries to the chroot jail:

cp /bin/sh bin/sh
cp /bin/ls bin/ls
cp /usr/bin/cvs bin/cvs

Note that CVS will need /dev/null too, so we’ll copy it:

cp -a /dev/null dev/null

We can then run a single command to populate the required libraries for the binaries we installed. This command is handy to keep around (also from Julio Merino’s article). You’ll see some warnings about duplicate libraries and invalid files that appear as hex numbers - these are harmless garbage from the ldd output:

cp `ldd bin/* sbin/* | awk '{print $3}'` lib

At this point, the CVS chroot should be complete. You can test it using the chroot command as root:

chroot /var/chroot/cvs bin/ls -l
drwxr-xr-x    2 0        0            4096 Nov 15 04:09 bin
drwxrwx---    2 0        0            4096 Nov 15 04:07 cvs
drwxr-xr-x    2 0        0            4096 Nov 15 04:08 dev
drwxr-xr-x    2 0        0            4096 Nov 15 04:07 etc
drwxr-xr-x    2 0        0            4096 Nov 15 04:08 lib
drwxr-xr-x    2 0        0            4096 Nov 15 04:07 sbin
drwxrwxrwt    2 0        0            4096 Nov 15 04:07 tmp
lrwxrwxrwx    1 0        0               1 Nov 15 04:07 usr -> .
drwxr-xr-x    2 0        0            4096 Nov 15 04:07 var
chroot /var/chroot/cvs bin/cvs
Usage: cvs [cvs-options] command [command-options-and-arguments]
  where cvs-options are -q, -n, etc.
    (specify --help-options for a list of options)
  where command is add, admin, etc.
    (specify --help-commands for a list of commands
     or --help-synonyms for a list of command synonyms)
  where command-options-and-arguments depend on the specific command
    (specify -H followed by a command name for command-specific help)
  Specify --help to receive this message

The Concurrent Versions System (CVS) is a tool for version control.
For CVS updates and additional information, see
    the CVS home page at or
    Pascal Molli's CVS site at

If you received any errors about missing libraries or the like, copy them by hand to the lib directory in your chroot jail.

We’re now ready to create our CVS users. First thing we’ll do is create a group for them all to belong to:

groupadd cvsusers

Now add your CVS users, making their default group cvsusers. We’ve added a default shell that we’ll use later. The home directory for this user, /home/cvsuser1 by default, will still exist in the root filesystem. You can use this directory for setting SSH keys if you prefer to log in using private key authentication instead of passwords. For now, use the passwd command to set the appropriate passwords for each user you’re adding:

# Create the user with a default group of "cvsusers"
useradd -g cvsusers -s /sbin/nologin cvsuser1
# Create the alternate home directory in the chroot jail
mkdir /var/chroot/cvs/home/cvsuser1
# Set the user's password
passwd cvsuser1
# Add the user to the PAM chroot configuration
echo cvsuser1 /var/chroot/cvs >> /etc/security/chroot.conf

Once you’ve added the appropriate users for your CVS, copy your /etc/group and /etc/passwd files to the jail and remove all lines but those of your cvs users:

cp /etc/passwd etc/passwd
cp /etc/group etc/group

Set the group ownership of the cvs directory to your new cvsusers group:

chown .cvsusers cvs

Next, we’ll copy the files required for reverse lookups of uid/gid to username/groupname. Without this, CVS will end up with entries like uid750 in its history. It’s also the reason that zeroes appear instead of root for the username/groupname in the ls -l command we tested above. Note that reverse lookups are handled within glibc using the name switch server (NSS) and the default lookup source is the passwd/group files:

cp -a /lib/libnss*files* lib

Now, you should be able to see the reverse lookup for cvsusers in your chroot jail. If not, check to make sure that all of the required nss files were copied over.

chroot /var/chroot/cvs bin/ls -dl cvs
drwxrwx---    2 0        cvsusers     4096 Nov 15 04:07 cvs

We’re going to create the default shell nologin we assigned to each of the CVS users above. By running the only allowed command explicitly, we prevent the users from logging in or running any other command. Since the file is being created as nologin, we can ensure that they wouldn’t be able to log in to the root filesystem if the chroot failed in any way. Create this file as nologin in the chroot’s sbin directory:

/bin/cvs server

Now make it executable with chmod:

chmod +x /var/chroot/cvs/sbin/nologin

All of the required system files have been copied over, so we can now create our CVS repository:

chroot /var/chroot/cvs bin/cvs -d /cvs init
chown .cvsusers /var/chroot/cvs/cvs/CVSROOT

You should be able to log in to cvs via SSH and test your CVS server before we lock it down. Don’t forget to set passwords for your CVS users or SSH won’t let them in:

cd /tmp
CVS_RSH=ssh cvs -d:ext:cvsuser1@localhost:/cvs checkout CVSROOT
cvs checkout: Updating CVSROOT
U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/editinfo
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
U CVSROOT/rcsinfo
U CVSROOT/taginfo
U CVSROOT/verifymsg

If you can grab the files from the CVSROOT directory, you’ve successfully created a chroot-jailed CVS server. To test the security of this setup, try a few things to break it:

ssh localhost -l cvsuser1
cvsuser1@localhost's password: ****
Connection to localhost closed.

ssh localhost -l cvsuser1 bin/ls
cvsuser1@localhost's password:
< it hangs up here in cvs server mode, hit ctrl-c to kill this >
Killed by signal 2.

sftp cvsuser1@localhost
Connecting to localhost...
cvsuser1@localhost's password:
< it hangs up here in cvs server mode, hit ctrl-c to kill this >
Killed by signal 2.

Remember each of the steps above for adding new CVS users. Congratulations, your CVS server is now secure!

Read full post

Getting my scanner up and running was easy enough.  The strange part of the whole ordeal is that the RPMs for SANE place all of the config files in /etc/sane.d, but the executables are all looking in /etc!  I noticed that the RPM was from the yoper repository - it doesn’t seem to be a core Fedora package.  After looking at it more carefully, I think I managed to install a package that doesn’t really fit my installed Fedora Core 2 at all.

I managed to fix it for now by creating a “sane” entry in /etc/profile.d that sets SANE_CONFIG_DIR globally.  Note that this whole thing is not really a huge deal- I imagine that it would work “out of the box” with a standard Fedora install.  I’m a little too impatient to wait for Fedora Core 3 and its updated version, however.

If you’re curious, this is the shell script to place in /etc/profile.d:

Read full post

I just finished setting up dovecot this morning to aggregate my various email boxes and make them available via a single server.  Dovecot seems to be a server from the new golden age of Unix services.  It’s easy to set up and has reasonable defaults for getting a server up-and-running without much effort.  Note that this is in contrast to sendmail configuration, which is as cryptic as could possibly be.

My ideal “unix service” - mail, web, ftp, etc - is a drop-in application that tries to work with your current configuration, rather than reinventing the wheel each time.  It should use PAM for authentication whenever possible, pick up system configuration from shared files and “just work” when you start it up.

So far, I’ve managed to get my home network up and running with the following services:

  • Windows domain (via Samba)
  • DHCP with static addresses assigned per MAC (via ISC’s dhcpd)
  • DNS, including integrated dynamic-DNS with DHCP (via bind)
  • Single-source, aggregating IMAP email server (via dovecot, fetchmail and procmail)
  • Spam filtering and anti-virus protection for above (via spamassassin and clamav, respectively)
  • Networked printing (via CUPS)

To run all of these services off Windows Server 2003 would cost me approx. CDN$1,200 for the basic serverlicense (and five CALs).  I’d also have to add in the basic Exchange package for another CDN$1,200.  Spam filtering might still be possible via spamassassin on Windows and I could probably use the free version of AVG anti-virus for email protection at the client level (versus the server).

Note that my current solution would likely scale up to a medium-sized, single-office solution by upgrading the hardware (no additional effort).  I’d probably be looking at more than CDN$10,000 in license fees to pull this off legally in Windows 2003.

Grand total amount of time to set all of this stuff up: six hours.  To do it again would probably take about two hours.

Read full post