#!/usr/bin/perl

# Start an ssh connection and a pppd running on top of it.
# Usage: ssh-ppp [-l user] [-c command] [-b seconds] host
# Connect to "host" using the user name "user" and run "command" on the
# remote end. (Default is "root" and "/usr/sbin/pppd")
# by Olaf Titz, July 1996

require "getopts.pl";
require "sys/syscall.ph";

# Customize if necessary
$ssh="/usr/local/bin/ssh";
$pppd="/usr/sbin/pppd";

# defaults
$opt_l="root";
$opt_c="/usr/sbin/pppd";
&Getopts("l:c:b:i:h:o:");
($host=shift) || die "usage: $0 [-i identity] [-l user] [-c command] [-h local pppd options] [-o remote pppd options] host";

foreach $maj ("p".."s") { # adjust this to the ptys you have
    foreach $min ("0".."9", "a".."f") {
       &tryopen("$maj$min");
    }
}
die "Couldn't alloc master pty\n";

sub tryopen
{
    local($d)=@_;
    $master=sprintf("/dev/pty%s", $d);
    $slave=sprintf("/dev/tty%s", $d);
    if (open(PTY, "+>$master")) {
       $pid=fork;
       defined($pid) || die "can't fork";
       if (!$pid) {
           close PTY;
           (syscall(&SYS_setsid)>0) || die "setsid: $!";
           open(STDIN, "+>$slave") ||
               die "open slave: $!";
           open(STDOUT, ">&STDIN");
           open(STDERR, ">&STDIN");
           print STDOUT "\n";
           exec $pppd $opt_h;
           die "exec $pppd: $!";
       }
       open(STDIN, "<&PTY") || die "reopen stdin";
       open(STDOUT, ">&PTY") || die "reopen stout";
       close PTY;
       $opt_l="-l$opt_l";
       $opt_i="-i$opt_i" if $opt_i;
       &bugdaemon($opt_b) if ($opt_b);
       print STDERR "running on $master; ssh=$$, pppd=$pid\n";
       exec $ssh, "-C", "-t", $opt_i, $opt_l, $host, $opt_c, $opt_o;
       die "exec $ssh: $!";
    }
}

sub bugdaemon
# This cures a "hang" of the local ssh process
{
    local($secs)=@_;
    local($p)=fork;
    if (!defined($p)) {
       warn "can't fork, no bug daemon";
       return;
    }
    return if (!$p);
    # returning the child avoids a zombie
    sleep $secs;
    kill "STOP", $p;
    sleep 1;
    kill "CONT", $p;
    exit 0;
}
