Educational Objectives: After completing this assignment, the student should have the following knowledge, ability, and skills:
Operational Objectives: Create a client of PWServer that simulates a password authentication system, along with makefiles makefile.linprog and makefile.program that create an executable named pwclient.x (on linprog and program, respectively).
Deliverables: Three files pwclient.cpp, makefile.linprog, and makefile.program.
The class PWServer is defined in the file pwserver.h. The (public) interface of a PWServer object is as follows:
PWServer (const char* infile, const char* outfile, unsigned int max);
This is the only constructor provided for the class. There are three
parameters required:
Once a PWServer object is created, these data are fixed for that object and cannot be changed during the lifetime of the object.
~PWServer ();
This is the class destructor which ensures correct destruction of each PWServer
object. The destructor is not called explicitly by the client program, rather it
is called automatically when the object goes out of scope.
int CheckPW (const char* uid, char* upw);
This method provides the most basic password service: it takes a user name
uid and a user password upw and checks the validity of the
password. The value 1 is returned if the user is authenticated and the value 0
is returned if the user is not authenticated.
Note that the second parameter which holds the password in clear text is not a "const" pointer. This allows the server to overwrite this string as soon as it is copied into a local string object, which is used as input to the secure hashing algorithm creating an associated signature. An encryption scheme could be used for this parameter to further complicate the theft of the password.
int ChangePW (const char* uid, char* upw, char* newpw);
Along with CheckPW, this is the other user accessible service: changing the
password. The three parameters required are the user name uid, the current password
upw, and the new password newpw. The service first
authenticates the user with the current password, then changes to the new
password. Both the old and new password strings are overwritten as soon as
possible by the server object. Return value 1 indicates success while return value 0
indicates failure.
int CreateUser (const char* uid, char* upw);
This and the following service are intended for use by the system management
only. They are used to create new users and remove current users from the
system. Typically, authorization to access CreateUser would be provided
by system management to a specific user. This is a potential weakness because ad
hoc identification and authentification methods are often used, for example in
the FSU CS system, the ID number is matched with the official list of CS
majors. It is not impossible for identity theft to take place at this stage of
new account generation.
Again, two parameters must be supplied, user name uid and the proposed password upw, and the value 1 is returned when the request is successful and 0 is returned when it is not successful.
int DeleteUser (const char* uid);
This is
typically accessible only by system management and has the obvious
functionality: a user name uid is purged from the authentication
system. Return value 1 indicates success while return value 0 indicates
failure.
Note that a system manager could "disable" a user by simply changing the hash value stored in the password file, so that authentication would fail. Recovering from such "disablement" could be done by copying the correct signature back over the changed value. If that correct signature is lost, however, recovery is difficult and would require another service be added to the server interface, effectively a non-password-protected ChangePW().
void Dump (std::ostream& out1 = std::cout);
This method is provided only during "white box" testing of the server. It
displays the internal contents of the server object. Note that the parameter is
a std::ostream& with a default value std::cout, so that
Dump() may be called with no explicit arguments and the results
will be sent to standard output.
The interaction of a PWServer object with its files follows a few simple rules:
The third constructor parameter is used to limit the number of users in the system that are served by a given PWServer object.
The class PWServer conforms to a standard model for controlled access to computer services known as the IAA model, where access is controlled via a three-step process:
The intended use of a password server is to provide the identification and authentication phases of the model. For more about hashing, see the lecture notes Hashing, Hash Functions, and Their Uses.
Create and work within a separate subdirectory cop3330/hw3. Review the COP 3330 rules found in Introduction/Work Rules.
Begin by copying the following files from the course directory /home/courses/cop3330p/fall09/ into your hw3 directory:
hw3/pwserver.h # defines class PWServer hw3/xstring.h # defines class fsu::String hw3/pwserver_s.o # PWServer implementation machine code - Sun/Unix hw3/pwserver_i.o # PWServer implementation machine code - Intel/Linux hw3/pwclient_s.o # example pwclient implementation machine code - Sun/Unix hw3/pwclient_i.o # example pwclient implementation machine code - Intel/Linux hw3/pwf1 # example password files hw3/pwf2 hw3/pwf3 hw3/hw3submit.sh # submit script
The naming of the *.o files uses the convention that _s are compiled for Sun/Solaris and _i are compiled for Intel/Linux. Note that these files are object code, as would be stored in a library. They can be used in the linking step of compilation to create executables. The pwserver_?.o files contain compiled code for the PWServer object and must be used when you compile your client program. The pwclient_?.o files contain compiled code for the model solution pwclient.cpp and must be used when to create an example executable.
Create an example executable from the distributed machine code files using one of the commands
g++ -opwc.x pwclient_i.o pwserver_i.o # on linprog g++ -opwc.x pwclient_s.o pwserver_s.o # on program
The executable so created is an example solution for this assignment. Use this example executable to experiment to get an understanding of how your program should behave.
Copy one of the distributed object files to "pwserver.o", depending on whether you are doing your development on program (Sun) or linprog (Intel). This file is the machine code implementation of class PWServer defined in pwserver.h.
Create a file pwclient.cpp that contains a main program that is a client of class PWServer, i.e., that creates and uses an object of type PWServer. You should be able to make use of sample code fragments in Chapter 3 of the lecture notes in the design of this program.
Turn in three files makefile.linprog, makefile.program, and pwclient.cpp using the hw3submit.sh submit script.
Warning: Submit scripts do not work on the program and linprog servers. Use shell.cs.fsu.edu to submit projects. If you do not receive the second confirmation with the contents of your project, there has been a malfunction.
The program must have these include statements:
#include <xstring.h> #include <pwserver.h>
near the top of the file. Note that angle brackets are required. Quotes will not do.
The program must respond to the same basic menu commands as the distributed pwc.x you create as described under Procedure Requirement 3 above. (This requirement is necessary for automated testing of your program.) You may add your own options as well.
Your program should use command line arguments to specify the input and output file names. There is source code demonstrating how to program with command line arguments in the file fall09/examples/commandLineArguments.cpp
Compile the client for linprog with these commands:
g++ -c -I/home/courses/cop3330p/fall09/hw3 pwclient.cpp g++ -opwclient.x /home/courses/cop3330p/fall09/hw3/pwserver_i.o pwclient.o
(Substitute "_s" for "_i" to compile for program.)
The project should compile error- and warning-free on both program and linprog.
Create makefiles makefile.linprog and makefile.program that results in pwclient.x for linprog and program, respectively, using the commands in the previous step.
Test your client program. The client should behave like the supplied model pwc.x that you build from the distributed object code as described in Procesural Requirement 3.
You may assume that usernames and passwords have no more than 20 characters. Use declared constants!
Whenever you need to check for required behavior, you can (re-)create an example linprog executable pwc.x using the commands
cp ~cop3330p/fall09/hw3/pwserver_i.o . cp ~cop3330p/fall09/hw3/pwclient_i.o . g++ -opwc.x pwclient_i.o pwserver_i.o # on linprog
(Substitute "_s" for "_i" to get the example executable for program.) This will name the sample "pwc.x" so that you can have it co-exist with your version named "pwclient.x" for comparison purposes.
Assuming you have used the commands as required, your makefiles do not use your local copies of any of the distributed files. These are read directly from the assignment directory. You can test this be removing the distributed files from your project directory and building the project. Be careful not to "remove" your client program!
Three password files are supplied. (Read the file "readme" to see what the user passwords are for these files.) You can create a larger file for testing purposes using the executable pwc.x that you create from the distributed machine code files. Don't forget how the file parameters are used - the output file is overwritten by the PWServer destructor, so if you add new usernames, you should copy the output file to another name before re-starting the client.