1#!/usr/bin/perl 2use strict; 3use warnings; 4use Text::ParseWords qw(parse_line); 5use Getopt::Long qw(:config posix_default); 6 7# Note: this script can't deal with ; delimiters which are run into other arguments 8 9# Hack off the quotes :( yuk 10# Needed to work around the shonkiness of the tokeniser 11sub hack_off_quotes { 12 return map { s/^'(.*)'$/$1/ or s/^"(.*)"$/$1/; $_ } @_ 13} 14 15 16my $unauthenticated = 1; 17sub sudo { 18 my ($params, %env) = @_; 19 20 # Locally alias @ARGV to $params rather than use 21 # GetOptionsFromArray, for the sake of portability (Some currently 22 # widely used versions of Perl don't have a version of 23 # Getopt::Long with it). 24 local *ARGV = $params; 25 26 shift @$params; 27 28 my $pw_prompt = '[sudo] password for user: '; 29 my $unauthenticate = 0; 30 31 GetOptions( 32 "K" => \$unauthenticate, 33 "p=s" => \$pw_prompt, 34 ) 35 or warn "oops, bad parameters to sudo\n"; 36 37 if ($unauthenticate) { 38 $unauthenticated = 1; 39 # ignore anything else 40 return; 41 } 42 43 if ($unauthenticated) { 44 print hack_off_quotes $pw_prompt; 45 my $input = <STDIN>; 46# print "\n"; 47 } 48 49 $unauthenticated = 0; 50 51 if ($params->[0] eq 'sh') { # ignore the rest if any 52 return shell(%env); 53 } 54 55 print "sudo got: @$params\n"; 56} 57 58 59sub shell { 60 my %env = @_; 61 $env{PS1} ||= 'sh$ '; 62 63 PROMPT: while (1) { 64 print $env{PS1}; 65 66 my @cmds = []; 67 68 # Parse line, then split any parameters like 69 # "foo;" into "foo" and ";" (so that we can parse ; delimiters 70 # consistently). This will have some edge cases like 71 # 72 # foo bar="baz;" biz 73 # 74 # which gets parsed as two commands: 75 # 76 # "foo", "bar=baz" 77 # "biz" 78 # 79 # but we don't really care about them. 80 81 my $line = <STDIN>; 82 chomp $line; 83 my @toks = parse_line '\s+', 1, $line; 84 @toks = grep { defined $_ } @toks; 85 @toks = map { /(.*);$/? ($1, ';') : ($_) } @toks; 86 for my $tok (@toks) { 87 $tok eq ';'? 88 push @cmds, [] : 89 push @{ $cmds[-1] }, $tok; 90 } 91 92 CMD: for my $toks (@cmds) { 93 @$toks 94 or next; 95 96 local $_ = $toks->[0]; 97 98 /^exit$/ 99 and last PROMPT; 100 101 /^(\w+)=(.*)/ 102 and do { 103 $env{$1} = $2; 104 next CMD; 105 }; 106 107 /^export$/ 108 and next CMD; # ignore it 109 110 /^sh$/ 111 and do { 112 shell(%env); 113 next CMD; 114 }; 115 116 /^sudo$/ 117 and do { 118 sudo($toks, %env); 119 next CMD; 120 }; 121 122 /^printf$/ 123 and do { # this is a hackery and a mockery of printf :) 124 shift @$toks; 125 my $fh = \*STDOUT; 126 if (@$toks && $toks->[0] eq '>&2') { 127 shift @$toks; 128 $fh = \*STDERR; 129 } 130 my $fmt = shift(@$toks) || ''; 131 ($fmt) = hack_off_quotes $fmt; 132 $fmt = eval qq(sprintf "$fmt"); 133 134 printf {$fh} $fmt, @$toks; 135 next CMD; 136 }; 137 138 /^id$/ 139 and do { 140 print <<OUT; 141uid=1000(nick) gid=1000(nick) groups=4(adm),6(disk),20(dialout),24(cdrom),46(plugdev),105(lpadmin),115(admin),116(sambashare),122(libvirtd),1000(nick) 142OUT 143 next CMD; 144 }; 145 146 print "got: @$toks\n"; 147 } 148 } 149} 150 151 152###################################################################### 153 154$| = 1; # turn on autoflush 155 156# get passwd 157print q(user@nowhere's password: ); 158my $input = <STDIN>; 159 160print "\nLast login: blah de da\n"; 161 162shell %ENV, PS1 => '[user@nowhere]$ '; 163print "Connection to nowhere closed\n" 164