#!/usr/bin/perl -w

# Originally written by James Strandboge <jstrand1@rochester.rr.com> in
# the article "Encrypted NFS with OpenSSH and Linux" found here:
# http://www.samag.com/documents/s=4072/sam0203d/sam0203d.htm
#
# Recommended fstab setup:
# master.foo.com:/home	/mnt/home	nfs	rw,hard,intr	0	0
#
# Read Firewall HOWTO for info on "pinning" RPC daemons to specific portnumbers:
# http://nfs.sourceforge.net/nfs-howto/security.html
#
# TODO: Use getopts and configfile
# Figure out a way to automount
# Figure out a way to automount through PAM

use strict;
use File::Basename;

## CONFIGURATION
my $nfs_server = "nfs1";          # the nfs server to connect to
my $nfs_server_user = "james";    # a valid username on the nfs server
my $use_version = "2";            # nfs-user-server uses 2, otherwise 3
                                  # would be better.  Check output of
                                  # 'rpcinfo -p <servername>'

my $nfsd_client_port = "2818";    # we will port forward nfsd here
my $mountd_client_port = "3045";  # we will port forward mountd here
my $sleep_length = "86400";       # how long to sleep before restarting
                                  # 86400 secs is one day. Note
                                  # this is overridden if a command is
                                  # specified in the server's 
                                  # authorized_keys2 file

# need to keep '-f', can also specify encryption algorithm, the ssh version
# and the id key
my $ssh_opts = "-f -c blowfish -2 -i /home/james/.ssh/id_dsa_nfs";

my %rpcinfo_col = (               # change as per output of rpcinfo -p
    'program'     => '0',
    'version'     => '1',
    'protocol'     => '2',
    'port'        => '3',
    'daemon'    => '4'
);

## END CONFIGURATION

# not much should need to change below here
my $prog_name = basename($0);
my $nfsd_server_port = "";
my $mountd_server_port = "";


# for signals
$SIG{INT} = sub { die "$0 interrupted and dying (does not kill ssh)\n" };

my $first_time = 1;
while (1) {
    if ($first_time) {
        print "$prog_name: Starting ssh/nfs forwarding&#151;\n";
        $first_time = 0;
    } else {
        print "$prog_name: Restarting ssh/nfs forwarding&#151;\n";
    }

    # first, get the rpcinfo
    my @rpcinfo = `rpcinfo -p $nfs_server`;

    print "My rpcinfo =\n @rpcinfo";

    # now get the nfsd and mountd port numbers
    foreach (@rpcinfo) {
        my @line = split;
        if ($line[$rpcinfo_col{"version"}] eq $use_version &&
            $line[$rpcinfo_col{"daemon"}] eq "nfs" &&
            $line[$rpcinfo_col{"protocol"}] eq "tcp") {
                $nfsd_server_port = $line[$rpcinfo_col{"port"}];
            print (" nfsd port = $nfsd_server_port");
        } elsif ($line[$rpcinfo_col{"version"}] eq $use_version &&
            $line[$rpcinfo_col{"daemon"}] eq "mountd" &&
            $line[$rpcinfo_col{"protocol"}] eq "tcp") {
                $mountd_server_port = $line[$rpcinfo_col{"port"}];
            print (", mountd port = $mountd_server_port\n");
        }
    }

    # now run ssh (if this fails, we get the error message and
    # retry).  This should run all the time.  This also won't die
    # unless the nfs mount is done.
    `/usr/bin/ssh $ssh_opts -L \
      $nfsd_client_port:$nfs_server:$nfsd_server_port -L \
      $mountd_client_port:$nfs_server:$mountd_server_port -l \
      $nfs_server_user $nfs_server /bin/sleep $sleep_length`;