101 lines
2.7 KiB
Plaintext
101 lines
2.7 KiB
Plaintext
|
#!/usr/bin/perl
|
||
|
#
|
||
|
# Danga's Command Shell
|
||
|
# Glue that takes incoming connection on STDIN/STDOUT and forwards it to a
|
||
|
# local server running on a certain port. This is meant to be an account's
|
||
|
# shell in /etc/passwd.
|
||
|
#
|
||
|
# Configuration file format:
|
||
|
#
|
||
|
# <command> = <server> : <port>
|
||
|
#
|
||
|
# Caveats & Warnings:
|
||
|
# This program must be in a bin directory. E.g. /home/lj/bin/cmdshell. It
|
||
|
# will extrapolate the location of its config file as the portion
|
||
|
# before the bin/ plus conf/cmdshell.conf. So, for the example above,
|
||
|
# /home/lj/conf/cmdshell.conf is expected to exist.
|
||
|
#
|
||
|
# Copyright 2004, Danga Interactive
|
||
|
#
|
||
|
# Authors:
|
||
|
# Mark Smith <marksmith@danga.com>
|
||
|
#
|
||
|
# License:
|
||
|
# undecided.
|
||
|
#
|
||
|
|
||
|
# uses
|
||
|
use strict;
|
||
|
use IO::Socket;
|
||
|
|
||
|
# known commands
|
||
|
my %commands;
|
||
|
|
||
|
# try to guess the config file location?
|
||
|
if ($0 =~ m!^(.+)/bin/cmdshell$!) {
|
||
|
my $conf = "$1/conf/cmdshell.conf";
|
||
|
die "Config file $conf not found." unless -e $conf;
|
||
|
|
||
|
# open and parse
|
||
|
open FILE, "<$conf"
|
||
|
or die "Unable to open config file $conf: $!\n";
|
||
|
while (my $line = <FILE>) {
|
||
|
if ($line =~ /^\s*([^#].*)\s*=\s*(.*)\s*/) {
|
||
|
my ($l, $r) = (trim($1), trim($2));
|
||
|
if ($r =~ /^(.+)\s*:\s*(\d+)/) {
|
||
|
my ($host, $port) = (trim($1), trim($2)+0);
|
||
|
die "Invalid port '$2' for command $l in '$line'.\n" unless $port;
|
||
|
$commands{$l} = [ $host, $port ];
|
||
|
} else {
|
||
|
die "Invalid config file line: $line\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
close FILE;
|
||
|
} else {
|
||
|
die "Unable to guess config file based off of path: $0\n";
|
||
|
}
|
||
|
|
||
|
# we're running, verify we have info
|
||
|
my $user = $ENV{LJUSERNAME};
|
||
|
my $cmd = lc($ENV{LJCOMMAND});
|
||
|
$cmd = '' unless $cmd =~ /^golive|replicator$/;
|
||
|
die "No information for command '$cmd'\n" unless $user && $cmd;
|
||
|
|
||
|
# now based on command, open connection to port
|
||
|
my $socket = IO::Socket::INET->new(Proto => 'tcp',
|
||
|
PeerAddr => $commands{$cmd}->[0],
|
||
|
PeerPort => $commands{$cmd}->[1],)
|
||
|
or die "Unable to connect to command server ($commands{$cmd}->[0]:$commands{$cmd}->[1])\n";
|
||
|
$socket->autoflush(1);
|
||
|
|
||
|
# parent pid
|
||
|
my $ppid = $$;
|
||
|
|
||
|
# now fork
|
||
|
my $kidpid;
|
||
|
die "Unable to fork: $!\n" unless defined($kidpid = fork());
|
||
|
|
||
|
# basic parts that handle reading/writing from the two sides
|
||
|
if ($kidpid) {
|
||
|
# parent
|
||
|
while (defined (my $line = <$socket>)) {
|
||
|
print STDOUT $line;
|
||
|
}
|
||
|
kill("TERM" => $kidpid); # death to the children
|
||
|
} else {
|
||
|
# child
|
||
|
while (defined (my $line = <STDIN>)) {
|
||
|
print $socket $line;
|
||
|
}
|
||
|
kill("TERM" => $ppid); # kill parent since we died
|
||
|
}
|
||
|
|
||
|
# little trimming sub
|
||
|
sub trim {
|
||
|
my $res = shift;
|
||
|
$res =~ s/^\s+//;
|
||
|
$res =~ s/\s+$//;
|
||
|
return $res;
|
||
|
}
|