/*
 * Test authenticator for verifying authlib routines.
 *
 * Author:	David Jones
 * Date:	29-MAY-1994
 * Revised:	 3-FEB-1995		Additional comments.
 * Revised:	23-FEB-1995		Use auth_callback prototype.
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "authlib.h"
auth_callback simple;
/*
 * Main routine.
 */
int main ( int argc, char **argv )
{
    int status;
    /*
     * Initialize data structures needed to perform authentication.  For
     * this sample implentation, there are none.
     */

    /*
     * Process server requests.  The auth_server routine connects to the
     * the HTTP server that created us and effecitively makes the authenticate
     * function (simple()) a remote procedure call for the server.
     * The third argument is text to be placed in the server's log file.
     */
    status = auth_server ( argc, argv, 
	"Sample Authenticator, V 1.0, initialized successfully.", 1, simple);
    /*
     * Getting to this point means an error occurred since auth_server
     * loops to continuous get authentication requests.  Most likely the
     * the HTTP server exitted so we should run down as well.  Perform any
     * necessary cleanup and exit.
     */
    exit ( status );
}
/************************************************************************/
/*
 * Dummy password checking routine.  Assume the password is a simple
 * function of the username.
 */
static int check_password ( char *username, char *password )
{
    char *u, *p;
    int delta;
    /*
     * Starting with second username character, find delta between it and
     * the previous character and check that next password character is
     * this delta + 65 (BBD in username yields AB).
     */
    for ( u = username, p = password; *u; u++ ) if ( u != username ) {
	delta = u[-1] - u[0]; if ( delta < 0 ) delta = 0 - delta;
	if ( *p++ != (delta+65) ) return 0;
    }
    /*
     * Final character in password is length of input string + 65 (i.e.
     * for an 6 character username, last password char is 'G').
     */
    if ( *p++ != (strlen(username)+65)) return 0;
    if ( *p ) return 0;				/* chars left in password. */
    else return 1;
}
/*************************************************************************/
/* Authenticator callback routine for auth_server().  This routine is
 * called to process an authentication request sent by the server.
 *
 * This routine determines whether access to the requested object (ident)
 * with the specified method is to be granted, validating the authorization
 * information against the protections defined by the setup file.
 *
 * return values:
 *	0	Access to the object is denied.
 *	1	Access to the object is permitted.
 *
 * When access is denied, this routine sets the response argument to point
 * to a statically allocated string containing the HTTP error response headers
 * to send to the client, sans the HTTP version (i.e. "403 Access denied\r\n").
 * The newlines are included.  If a 401 status is returned, the response header
 * includes the WWW-authenticate headers for the authorization schemes that
 * this routine understands.
 */
int simple ( 
	int local_port, 		/* Local port # of TCP/IP connection */
	int remote_port, 		/* Remote TCP/IP port of client */
	unsigned char remote_address[4],/* Remote binary IP address of client */
	char *method, 			/* Requested method (GET, PUT, etc); */
	char *setup_file, 		/* Protection setup file name */
	char *ident, 			/* Ident portion of translated URL */
	char *authorization, 		/* Auth. headers included in request */
	char **response, 		/* HTTP error response headers */
	char **log )			/* Optional log message */
{
    int status, auth_basic_authorization();
    char username[40], password[40];
    /*
     * Note that response and log buffers must be statically allocated.
     * Fail and succeed are pointers to string constants (implicitly static),
     * if you make them char arrays be to all make them static storage class.
     */
    static char log_message[200];
    char *fail = 
	"401 Unauthorized\r\nWWW-Authenticate: Basic realm=\"sample\"\r\n";
    char *succeed = "200 access to protected file granted\r\n";
    /*
     * At this point, a real authenticator would read the protection setup
     * file to locate the databases (password file, group file) that define
     * the protections for the object.  If this operation failed, we would
     * return failure (0) with a "500" error status line.
     */

    /*
     * Set default response to the "unauthorized" error response headers string
     */
    *response = fail;
    /*
     * See if request has a basic scheme authorization line and decode it
     * using utility routines from authlib.c.  The last argument in the
     * auth_basic_authorization() call forces the result to upper case.
     */
    if ( auth_basic_authorization ( authorization, username, sizeof(username),
		password, sizeof(password), 1 ) ) {
	/*
	 * Validate password using simple rule.  A real authenticator would
	 * validate it against the password database.
	 */
	int allowed = check_password ( username, password );
	if ( allowed ) *response = succeed;
	/*
	 * Generate a message for the server's log file.  A real authenticator
	 * wouldn't place the password in the log file.
	 *
	 * The server checks if the log line begins with "[username]" and
	 * makes 'username' the local user in the access.log file.
	 */
	*log = log_message;
	sprintf(log_message,"[%s]Authentication for user='%s' pass='%s' %s.",
		allowed ? username : "", username, password, allowed ? 
		"succeeded" : "failed" );
	*log = log_message;
	return allowed;
    }
    return 0;
}
