Introduction
Sometimes, we need to execute commands on a remote machine. There
are many commercial, shareware, and freeware products that can be used
for this purpose. Here I present a simple Java program that can be
easily modified to suit your needs. We all know the "write once, run
everywhere" slogan, so the code will be working fine
on any platform that has a Java Virtual Machine (JVM; but don't blame me if
it breaks, I only tested it on NT and AIX). I have to warn the
readers that the source code included with this article is just one example
of how this can be accomplished and it has only minimal security,
so use it at your own risk but it should not be hard for you to add sophisticated
security.
The Java classes
The RemoteShellServer
class implements the
server side of the program. It first creates a server socket so that
clients can connect to it. When a client is connected to the server,
it will spawn a new thread using the CommandRunner
class to handle the client's request. The main thread will continue
to listen for new client.
The CommandRunner
class implements the
server thread that handles the client's request. First, it reads
a command and an input to this command from the connected client.
Both the command and its input are represented as byte arrays. It
then creates a new process to execute the command and writes the input
data to the created process. The output and error from the created
processed will be read and send back to the client. The connected client may
continue to send commands and input data which will be executed by this thread
one by one. The server thread will not terminate if any process it created is
still running, so be careful about what you are asking the server to do.
The RemoteShellClient
class is an example
of the client-side code. All it does is sending the command and its
input provided by the user to the server and receiving the output from
the server. If you want to execute commands on the remote machine
from your program using this tool, you can write the client-side code based
on this class. If I have time, I will provide a C++ client program
with GUI for this tool later. I have actually embedded the client
code within a web page (as applet) so that I can control the server machine
anywhere (within the firewall, of course). This could be very dangerous,
which is why the applet I put on my website is restricted to only executing
certain "safe" commands on the server.
The SockData
class is used to provide a
way to send and receive byte arrays between the client and the server in
a platform-independent way. The first 4 bytes of the data is the
length of the remaining data block.
How to build and use the program
The JavaBuild.bat file contains commands to compile
and bundle the Java code into a RemoteShell.jar
file. You have to copy RemoteShell.jar
to both machines and set the CLASSPATH environment
to include this file. If you use the the provided batch files to run the server or client,
I set the CLASSPATH for you.
Here are the commands to start the server program at port 50001
java RemoteShellServer 50001 207.46.230.219
java RemoteShellServer 50001 207.46.
java RemoteShellServer 50001 .microsoft.com
java RemoteShellServer 50001
The first command instructs the server to listen at port 50001 and only
accepts connections from the machine with IP address 207.46.230.219.
With the second command, the server only accepts connections from
machines whose IP addresses contain the string 207.46. Similarly, the third
command makes the server to accept only connections from machines whose
addresses end
with .microsoft.com. The server will accept connections from anywhere with
the last command (Ouch).
To start the client, you have to specify the server IP address and port
number, plus the command you want to execute on the server and its input
data. For example, if you want to know what files are in the system
directory of the server (assuming it is NT/Win2K), then do this:
java RemoteShellClient myserver.ipaddress.com 50001
"cmd" "dir c:\winnt\system32"
You will see the following output on the server console:
Client 'myclient.ipaddress.com' executed command 'cmd' with input
'dir c:\winnt\system32'
On the client console, you will see the following example output just as if
you have typed dir c:\winnt\system32
on the server machine:
10/14/96 02:38a 13,584 runonce.exe
07/12/99 12:53p 54,464 s3trio3d.dll
02/01/00 02:19p 17,920 Sales.dll
10/15/98 12:04p 41,744 SAMLIB.DLL
10/15/98 12:04p 170,256 SAMSRV.DLL
10/15/98 12:04p 23,312 SAVEDUMP.EXE
10/15/98 12:04p 152,336 SCHANNEL.DLL
...
Please note that the input data to your client command can have multiple
lines, so it is possible to run a script file with the cmd
command (I just don't know how to type multiple lines into one line :-).
If you want, you can start GUI applications on the server, but you cannot
really see the GUI from the client. The following will launch notepad
and wordpad on the server machine.
java RemoteShellClient myserver.ipaddress.com 50001 "notepad.exe" ""
java RemoteShellClient myserver.ipaddress.com 50001
"write.exe c:\test.txt" ""
You have to kill the instances of notepad and wordpad on the server in order to terminate
the two threads in the server process. The following will launch notepad and wordpad
on the server without tying up two threads in the server process:
java RemoteShellClient myserver.ipaddress.com 50001 "cmd" "notepad.exe"
java RemoteShellClient myserver.ipaddress.com 50001 "cmd" "write.exe
c:\test.txt"
Ok, that's it. Thank you for reading and please go to my
homepage for more articles and
programs. You may now start the constructive criticism :-)