package CmdRun::Server; # # (c) 2003 by Kirill Miazine # # This software is distributed under an ISC-style license, please see # for details. # use warnings; use strict; use vars qw(@ISA %commands %users); use Net::Server::PreFork; @ISA = qw(Net::Server::PreFork); %commands = ( fortune => [qw(/usr/games/fortune)], ); %users = ( anonymous => { password => '', allow => [qw(fortune)], }, ); sub process_request { my $self = shift; my $auth_user = 'anonymous'; my $sock = $self->{'server'}->{'client'}; $sock->autoflush(1); $sock->print("+ Hello\n"); while (defined(my $line = $sock->getline())) { chomp $line; my ($cmd, @args) = split /\s+/, $line; $cmd = lc $cmd; if ($cmd eq 'quit') { $sock->print("+ Bye\n"); last; } elsif ($cmd eq 'auth') { if (@args == 2 and exists $users{$args[0]} and $users{$args[0]}{'password'} eq $args[1]) { $auth_user = $args[0]; $sock->print("+ Authentication succeeded\n"); } else { $sock->print("- Authentication failed\n"); } next; } elsif (exists $commands{$cmd}) { if (!grep { $_ eq $cmd } @{$users{$auth_user}{'allow'}}) { $sock->print("- Unauthorized\n"); next; } my $ret = _run_cmd(@{$commands{$cmd}}, map { pack 'H*', $_ } @args); $ret =~ s/^\./../gm; $sock->print("++ Exit code and output follows\n$ret\n.\n"); } else { $sock->print("- Unknown command\n"); next; } } } sub _run_cmd { my ($cmd, @args) = @_; local $SIG{'CHLD'} = 'DEFAULT'; local $SIG{'PIPE'} = 'IGNORE'; my $pid = open my $child, '-|'; if ($pid) { my @res = <$child>; close $child; unshift @res, "$?\n"; return join '', @res; } else { open STDERR, '>&1'; exec { $cmd } $cmd, @args; exit; } } 1;