The main purpose of this project is to give you a basic
introduction to OS support for sockets
, while building
upon some of your previous OS knowledge. You will write a basic
remote shell in which a user specifies an arbitrary shell
command to be executed, and it is sent over socket connection and
executed on a remote server.
You will write a server and a client:
Server: The server will run on the remote machine. It
will bind to a Unix socket at a port known to the client. When it
receives a connection, it fork()
s a child process to
handle the connection. The parent process loops back to wait for more
connections. The child process first verifies that the client is
valid via a (clear-text) password. Then, it executes the given
shell command, returning all stdout
and stderr
to the client. The server can assume the shell command does not
use stdin
. Upon completing the command, the server
will exit.
Client: The client will run on the local machine. From
the command line, the user will specify the host where the server
resides and the command to be executed. The client will then connect
to the server via a socket and transmit the password and the command.
The client will display any output received from the server to
the stdout
and then exit. Thus, the client does one
command at a time and is not an "interactive" shell.
The server will authenticate the client through a simple password mechanism. You can hard-code your password in both your server and your client, if you wish.
The samples code on the course web page contains some samples that may be useful. In particular:
talk.tcp.c
and listen.tcp.c
-
helpful samples for doing socket code.
fork.c
-
showing the simple use of the fork()
call.
execl.c
-
showing simple use of the execl()
call.
get-opt.c
-
code that parses command line arguments (fairly)
painlessly.
To get help information about specific Unix commands, use the "man" command. For instance, entering "man tcsh" will display the manual page entry for the tcsh. If you specify a number after the word "man", it looks in the indicated section number.
The following system calls for setting up your sockets may be helpful (you do not necessarily need to use them all):
connect()
accept()
socket()
listen()
bind()
close()
send()
recv()
getservbyname()
gethostname()
gethostbyname()
gethostbyaddr()
The following system calls for the "shell" part and communication through the sockets may be helpful (you do not necessarily need to use them all):
fork()
execvp()
strtok()
dup2()
fdopen()
In particular, dup2()
makes a new file descriptor be
the copy of an old file descriptor (closing the new file descriptor
first, if necessary). You can use dup2()
to make stdout
(STDOUT_FILENO
) a copy of the connected socket. This
will close the stdout (to the display, by default) and make it instead
the socket, causing all output to go down the socket.
While you will use a simple clear-text password for security, for
added security, a "real" server would likely use be
chroot()
to change the root directory of the process.
For example, many anonymous ftp servers use chroot()
to
make the top directory level /home/ftp
or something
similar. Thus, a malicious user is unable to compromise the system.
Unfortunately for this project, chroot()
requires root
privilege to run, making it unavailable to the common user. However,
if you are developing on your own system (say, a Linux box), I
encourage you to explore using chroot()
(do a "man
2 chroot
" for more information). However, do make sure the
version you hand in can run on the CCC machines.
Here are some examples. The server:
claypool 94 ccc1% ./server -h macro shell server usage: server [flags], where flags are: -p # port to serve on (default is 6013) -d dir directory to serve out of (default is /home/claypool/msh) -h this help message claypool 95 ccc1% ./server ./server activating. port: 6013 dir: /home/claypool/msh Socket created! Accepting connections. Connection request received. forked child received password password ok command: ls executing command... Connection request received. forked child received password password ok command: ls -l executing command... Connection request received. forked child received password password ok command: cat Makefile executing command...
The client from the same session:
claypool 49 capricorn% ./msh -h macro shell client usage: msh [flags] < command >, where flags are: {-c < command >} command to execute remotely {-s < host >} host server is on [-p #] port server is on (default is 6013) [-h] this help message claypool 41 ccc5% ./msh -c "ls" -s ccc1 Makefile client.c msh msh.c index.html server server.c server.h sock.c sock.h claypool 42 ccc5% ./msh -c "ls -l" -s ccc1 total 37 -rw-r----- 1 claypool users 212 Jul 7 22:19 Makefile -rw-r----- 1 claypool users 997 Jul 1 09:27 client.c -rwxrwx--- 1 claypool users 6918 Jul 9 00:04 msh -rw-r----- 1 claypool users 3790 Jul 9 00:03 msh.c -rw-r----- 1 claypool users 5374 Jul 8 23:50 index.html -rwxrwx--- 1 claypool users 7919 Jul 9 00:09 server -rw-r----- 1 claypool users 4383 Jul 9 00:09 server.c -rw-r----- 1 claypool users 240 Jul 7 22:19 server.h -rw-r----- 1 claypool users 2638 Jul 1 09:36 sock.c -rw-r----- 1 claypool users 614 Jul 1 09:27 sock.h claypool 43 ccc5% ./msh -c "cat Makefile" -s ccc1 # # # CC = gcc all: server msh server: server.c server.h $(CC) -o server server.c msh: msh.c server.h $(CC) -o msh msh.c sock.o: sock.c sock.h $(CC) -c sock.c clean: /bin/rm -f msh server core *.o *~
A useful program for maintaining large programs that have been broken
into many software modules is make. The program uses a file,
usually named Makefile, that resides in the same directory as
the source code. This file describes how to compile a number of
targets specified. To use, simply type "make" at the command line.
WARNING: The operation line(s) for a target MUST begin with a TAB (do
not use spaces). See the man page for make
and
gcc
for additional information.
# # Makefile for the macro shell program # CC = gcc CFLAGS = LIBFLAGS = all: msh server server: server.c $(CC) $(CFLAGS) server.c server.o -o server $(LIBFLAGS) msh: msh.c $(CC) $(CFLAGS) msh.c msh.o -o msh $(LIBFLAGS) clean: /bin/rm -rf *.o core msh server
Answer the following questions when you turn in your project:
Please include a README file giving some project information. The main information I'd like you to have from the documentation standard is: author, date, project id, language, OS dependencies, description and building information. Do note, however, that this information does not take the place of normal comments in your code! These comments are to make it easier to assess a grade if there are difficulties in the program.
Here is a sample of the information you should have:
Author: Mark Claypool Date: 7/15/05 Project ID: Project 3 CS Class: CS502 Programming Language: C OS/Hardware dependencies: Unix, gcc Problem Description: This program implements a distributed shell that does blah, blah, blah How to build the program: "make"
To hand in project 3:
Be sure the answers to the Questions are in a file called "questions.txt" in the directory with your project code.
Then, make a tar-ball to submit your files:
cd my-dir-with-proj3 rm all-files-not-to-be-turned-in cd .. tar cvf login-name-proj3.tar my-dir-with-proj3
Attach them to an email them to me with the subject "cs502 project 3"
Send all questions to claypool at cs.wpi.edu.