Due Date: Tu February 6, 2018 at 11:59pm.
In this project, you will build a basic server program that authenticates users who provide objects for the serve to store and retrieve objects from that server. This project will be tested on machines in the CSE Linux Lab - cse-p204instXX.cse.psu.edu, which XX is a 2-digit number from 01 to at least 40.
Inputs: Download the tarball for Project 1 to obtain the input server code. The code consists of four files - only one of which you will need to modify.
The file cmpsc497-main.c implements part of a basic server program. You will have to complete that server, as described below.
The file cmpsc497-kvs.c implements a key-value store that you will use to store and retrieve server objects. The API includes kvs_auth_set, which binds a key to a value with a tag, which are stored as a unit in the KVS. The key is used to retrieve the value and tag using the API kvs_auth_get, which retrieves a value and tag given a key as input.
The file cmpsc497-ssl.c implements an interface to use the OpenSSL library to perform cryptographic operations. There are a variety of functions here for you to use, but for this project you will only need to figure out how to use digest_message in this file and the OpenSSL API directly to collect some random bytes.
The file cmpsc497-utils.c implements some helper functions. You will not necessarily have to use these yourself, but it is up to you.
In addition, you will be provided with your own data format for your server. Each student will receive their own object format - defined by the file cmpsc-format-x.h, where x is a number identifying a different format. The object format consists of a base structure (struct A) and one or more fields that reference data of strings, ints, or other structures. You will also receive an input file consisting of one object with data values in that format.
Server API Your server program must implement two APIs from the command line:
./cmpsc497-p1 set [username] [password] [object-file]
The "set" command will add an object provided in the [object-file] to the "Objects" KVS (as described below) if the [username] is authenticated by the supplied [password]. If the [username] has not been used previously, the username-password pair will be stored in the "Passwds" KVS (as described below).
./cmpsc497-p1 get [username] [password] [object-id]
The "get" command will retrieve an object from the "Objects" KVS that matches the [object-id] provided. The retrieval is only allowed if: (1) the [username] is authenticated by the supplied [password] and (2) the [username] must be the owner of the object, as specified in the get_object function provided.
Project Tasks: The overall goal of this project is to build a server program that enables authenticated users to submit and retrieve objects from a key-value store managed by the server, where objects will adhere to your specified format.
In building the server program, you will have to complete the following tasks:
Implement the function set_password, which takes a username and password as input and produces a password hash for the password. The password hash is computed by prepending a 16-byte random salt, obtained from the OpenSSL random number generator, to a 16-byte (max) password value to produce a 32-byte salt+password value. Compute a 32-byte password hash from this value using the cryptographic hash function provided (digest_message). The combination of username (key), password hash (value), and salt (tag) must be stored in the "Passwds" KVS.
Implement the function authenticate_user, which takes a username and password as input and compares the provided password to the password stored for that user in the "Passwds" KVS.
Implement the function set_object, which takes a username, password, and input file (for object data) as input and adds the object to the "Objects" KVS if the username and password combination are authenticated. The object includes an identifier ("struct A id") in the input, which is used to retrieve the object (see below). The object is stored in the "Objects" KVS by the identifier (key), object data (value), and username who is the object owner (tag). The object data is processed from the file as described below.
Implement the function upload_A to read the input file and create an instance of an object of struct A. You must assign values to each field. For int fields, you will have to convert the file data to an integer. For string fields, you will have to copy the input string into the field's buffer. For struct fields, you will have to create a instance of that struct and assign a pointer to that structure to the field. Also, the input file will include data for these other structures as well. I recommend creating one function to build each type of instance (e.g., upload_B for building instances of struct B from the input file).
Implement the function marshall to prepare the object data for the persistent storage in the "Objects" KVS. marshall converts an object to a format suitable for storage or transmission. Mainly, marshall creates an alternative memory representation that linearizes the structure fields in struct A into a series of data items for supplying data values for storage in the "Objects" KVS. An example of code for marshalling a particular input format (Sample Format) is provided to show you how it is done.
Linearizing the object requires two tasks for this project, each of which are demonstrated in the sample code in marshall provided. First, marshall collects all the object fields and records only the data (ints and strings). Pointer values are essentially replaced by the data they point to. Second, since you each have different object formats, you will have to determine the size of your linearized object and assign that to the #define OBJ_LEN.
Implement the function unmarshall to convert a linearized object from the "Objects" KVS back into its data structure form. This is the opposite process from marshall above. An example of code for unmarshalling a particular input format (Sample Format) is provided to show you how it is done.
Implement the function output_obj to print object information as the result of a "get" operation. Write a function to print all the data fields (ints and strings) of struct A plus the data fields of struct B and the last structure in your object (structure with highest letter for its type name). An example of code for output for a particular input format (Sample Format) is provided to show you how I want it to be done.
Outputs:
Your program must enable the following functionality:
When a new username and password is seen on a "set" operation, then the username-password combination is recorded in the "Passwds" KVS by set_password by storing the username (key), password hash (value), and salt (tag) in the KVS. All subsequent operations ("set" or "get") from that username must include the corresponding password or they will be rejected for failing authentication by authenticate_user.
A "set" operation adds a new object to the "Objects" KVS in set_object. The object must be formatted using marshall prior to adding it to the "Objects" KVS. Objects are stored in the KVS by their identifier (key), marshalled data for all the object data rooted by the struct A object (value), and the username who created the object (tag).
NOTE: If there are two "set" operations for the same identifier, the object stored will include the latest data. So, a "get" operation can only retrieve one object.
It must be possible to retrieve that object data with a subsequent "get" operation defined by get_object. A "get" operation must use unmarshall to create the in-memory data structures for the objects, and output the int and string data using output_obj for the structs A, B, and the last (i.e., highest letter) struct type.
If a "get" operation is performed by a username that is not known to the program (i.e., does not have a username-password recorded), then the operation must be rejected. Only known and authenticated usernames may perform "get" operations.
Ensure that your code runs correctly on machines in the in the CSE Linux Lab. Any one of these machines will be sufficient - cse-p204instXX.cse.psu.edu, which XX is a 2-digit number from 01 to at least 40.
There will be a dropbox created on Canvas to submit your project code. Please use "make tar" to construct a tarball containing your project code and submit this tarball to the Canvas dropbox by 11:59pm on Th February 6, 2018.
You are to complete this on your own. Any sharing of text in the project is expressly forbidden. We will create a Piazza forum, and the only allowed sharing of project information is through that forum. Do not discuss this project with anyone outside of Piazza.