
/******************************************************************************
**
**  This program is free software; you can redistribute it and/or
**  modify it, however, you cannot sell it.
**
**  This program is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
**  You should have received a copy of the license attached to the
**  use of this software.  If not, visit www.shmoo.com/osiris for
**  details.
**
******************************************************************************/

/*****************************************************************************
**
**  File:    md_control.c
**  Date:    May 27, 2002
**
**  Author:  Brian Wotring
**  Purpose: handle control requests from management applications.
**
******************************************************************************/


#include "libosiris.h"
#include "libosirism.h"
#include "libosirisdb.h"
#include "libosirisctl.h"
#include "libfileapi.h"

#include "common.h"

#include "md_hosts.h"
#include "md_log.h"
#include "md_config.h"
#include "md_database.h"
#include "md_compare.h"
#include "md_control.h"
#include "md_scan.h"
#include "md_schedule.h"
#include "md_auth.h"
#include "md_utilities.h"
#include "md_filter.h"
#include "md_notify.h"

#include "logging.h"

extern char root_path[MAX_PATH_LENGTH];
extern char config_file_path[MAX_PATH_LENGTH];
extern char notify_filter_db_path[MAX_PATH_LENGTH];

extern SSL_CTX *ssl_context;

extern int ssl_verify_callback( int ok, X509_STORE_CTX *store );
extern void parse_configuration_file();
extern void signal_restart_needed();


THREAD_FUNCTION_TYPE process_client( void *new_socket )
{
    fd_set set;
    MESSAGE message;

    int result;
    int client_socket;

    osi_uint16 type;
    SSL *client_ssl;

    OSI_AUTH_CONTEXT *auth_context;

    if( new_socket == NULL )
    {
        return THREAD_RETURN_VALUE;
    }

    /* copy in our passed in socket and free the allocated data */
    /* right here so it always is freed.                        */

    client_socket = (*(int *)new_socket);

#ifdef HAVE_THREADS
    osi_free( (int *)new_socket );
#endif

    client_ssl = osi_ssl_accept_with_socket( client_socket,
                                             ssl_context, FALSE );

    if( client_ssl == NULL )
    {
        osi_close_socket( client_socket );
        return THREAD_RETURN_VALUE;
    }

    result = osi_ssl_read_message( &message, client_ssl );

    if( result != MESSAGE_OK )
    {
        if( result == OSI_ERROR_SOCKET_CLOSED )
        {
            log_info( LOG_MEDIUM, NULL, "remote peer closed connection." );
        }

        else
        {
            log_error( LOG_MEDIUM, NULL, "reading message: %s",
                       osi_get_name_for_error( result ) );
        }

        goto exit_gracefully;
    }

    /* we read the first message of this client connection.  */
    /* which should contain auth information.  We get the    */
    /* control request and create a process/thread to handle */
    /* this new client connection.                           */

    type = GET_MESSAGE_TYPE( ((MESSAGE *)&message ) );

    if( type != MESSAGE_TYPE_CONTROL_REQUEST )
    {
        log_error( LOG_MEDIUM, NULL, "unknown control message type." );
        goto exit_gracefully;
    }

    auth_context = MESSAGE_TO_TYPE( ((MESSAGE *)&message), OSI_AUTH_CONTEXT * );

    if( auth_context == NULL )
    {
        log_error( LOG_MEDIUM, NULL, "auth context is corrupted." );
        goto exit_gracefully;
    }

    /* authenticate this client connection, if it succeeds, we  */
    /* send back a success message.                             */

    if( authenticate_auth_context( auth_context ) == FALSE )
    {
        log_error( LOG_MEDIUM, NULL, "user authorization failure: %s.",
                   auth_context->auth_user );

        goto exit_gracefully;
    }

    osi_ssl_write_success_message( client_ssl );


    /* we loop on requests from this ssl client and pass */
    /* them to the request handler.                      */

    for(;;)
    {
        int select_result;

        FD_ZERO( &set );
        FD_SET( client_socket, &set );

        select_result = select( ( client_socket + 1 ), &set, NULL, NULL, NULL );

        /* whoops, interupted system call, select died, try again. */

        if( ( select_result ) < 0 && ( errno == EINTR ) )
        {
            continue;
        }

        /* we have data waiting, see if it is to the server.  if it */
        /* is, we read and process the message.                     */

        if( FD_ISSET( client_socket, &set ) )
        {
            CONTROL_REQUEST *request;
            MESSAGE message;

            /* read the control request. */

            result = osi_ssl_read_message( &message, client_ssl );

            if( result != MESSAGE_OK )
            {
                /* client closed connection. */

                if( result == OSI_ERROR_SOCKET_CLOSED )
                {
                    log_info( LOG_MEDIUM, NULL,
                              "remote peer closed connection." );
                    break;
                }

                /* unrecognized data, ignore. */

                else
                {
                    log_error( LOG_MEDIUM, NULL, "reading message: %s",
                               osi_get_name_for_error( result ) );

                    break;
                }
            }

            type = GET_MESSAGE_TYPE( ((MESSAGE *)&message ) );

            if( type != MESSAGE_TYPE_CONTROL_REQUEST )
            {
                log_error( LOG_MEDIUM, NULL, "unknown control message type." );
                continue;
            }

            request = MESSAGE_TO_TYPE( ((MESSAGE *)&message),
                                       CONTROL_REQUEST * );

            if( request == NULL )
            {
                log_error( LOG_MEDIUM, NULL, "control-request is corrupted." );
                continue;
            }

            unwrap_control_request( request );
            process_request( client_ssl, request );
        }
    }

exit_gracefully:

    SSL_shutdown( client_ssl );
    osi_close_socket( client_socket );
    osi_ssl_destroy( (SSL **)&client_ssl );

    ERR_remove_state(0);
    ERR_free_strings();

#ifdef WIN32
    _endthreadex(0);
#endif
    
    return THREAD_RETURN_VALUE;
}


void process_request( SSL *ssl, CONTROL_REQUEST *request )
{
    int client_socket;

    if( ( ssl == NULL ) || ( request == NULL ) )
    {
        return;
    }

    client_socket = SSL_get_fd( ssl );

    switch( (int)request->command )
    {
        case CONTROL_COMMAND_STATUS:

            log_info( LOG_HIGH, request->host, "received status request." );
            process_status( ssl, request );

            break;

        case CONTROL_COMMAND_SET_USER:
                
            log_info( LOG_HIGH, NULL, "received set-user request." );
            process_set_user( ssl, request );

            break;

        case CONTROL_COMMAND_LIST_USERS:

            log_info( LOG_HIGH, NULL, "received list-users request." );
            process_get_user_list( ssl, request );

            break;

        case CONTROL_COMMAND_DELETE_USER:
              
            log_info( LOG_HIGH, NULL, "received delete-user request." );
            process_delete_user( ssl, request ); 

            break;

        case CONTROL_COMMAND_PUSH_CONFIG:

            log_info( LOG_HIGH, request->host,"received push-config request." );
            process_push_config( ssl, request );

            break;

        case CONTROL_COMMAND_IMPORT_DEFAULT_CONFIG:

            log_info( LOG_HIGH, request->host, 
                      "received push-default-config request." );

            process_import_default_config( ssl, request );
            break;

        case CONTROL_COMMAND_SEND_NOTIFY_TEST:

            log_info( LOG_HIGH, NULL, "received send-notify-test request." );
            
            process_send_notify_test( ssl, request );
            break;

        case CONTROL_COMMAND_SET_BASE_DATABASE:

            log_info( LOG_HIGH, request->host,"received set-base-db request." );
            process_set_base_db( ssl, request );

            break;

        case CONTROL_COMMAND_UNSET_BASE_DATABASE:
    
            log_info( LOG_HIGH, request->host,
                      "received unset-base-db." );

            process_unset_base_db( ssl, request );
            break;

        case CONTROL_COMMAND_IMPORT_CONFIG:

            log_info( LOG_HIGH, request->host,
                      "received import-config request." );

            process_import_config( ssl, request );
            break;

        case CONTROL_COMMAND_START_SCAN:

            log_info( LOG_HIGH, request->host, "received start-scan request." );
            process_start_scan( ssl, request );

            break;

        case CONTROL_COMMAND_STOP_SCAN:

            log_info( LOG_HIGH, request->host, "received stop-scan request." );
            process_stop_scan( ssl, request );

            break;

        case CONTROL_COMMAND_LIST_HOSTS:

            log_info( LOG_HIGH, NULL, "received list-hosts request." );
            process_get_host_brief_list( ssl, request );

            break;

        case CONTROL_COMMAND_LIST_CONFIGS:

            log_info( LOG_HIGH, request->host,
                      "received list-configs request." );

            process_get_config_brief_list( ssl, request );
            break;

        case CONTROL_COMMAND_LIST_DATABASES:

            log_info( LOG_HIGH, request->host,
                      "received list-databases request." );

            process_get_database_brief_list( ssl, request );
            break;

        case CONTROL_COMMAND_LIST_LOGS:

            log_info( LOG_HIGH, request->host, "received list-logs request." );
            process_get_log_brief_list( ssl, request );

            break;

        case CONTROL_COMMAND_LIST_NOTIFY_FILTERS:

            log_info( LOG_HIGH, NULL,
                      "received list-notify-filters request." );

            process_get_notify_filter_list( ssl, request );
            break;

        case CONTROL_COMMAND_SAVE_NOTIFY_FILTERS:

            log_info( LOG_HIGH, NULL,
                      "received save-notify-filters request." );

            process_save_notify_filter_list( ssl, request );
            break;

        case CONTROL_COMMAND_GET_DATABASE_BRIEF:

            log_info( LOG_HIGH, request->host, "received db-results request." );
            process_get_database_brief( ssl, request );

            break;

        case CONTROL_COMMAND_GET_DATABASE_ERRORS:

            log_info( LOG_HIGH, request->host, "received db-errors request." );
            process_get_database_errors( ssl, request );

            break;

        case CONTROL_COMMAND_GET_CONFIG:

            log_info( LOG_HIGH, request->host, "received get-config request." );
            process_get_config( ssl, request );

            break;

        case CONTROL_COMMAND_GET_LOG:

            log_info( LOG_HIGH, request->host, "received get-log request." );
            process_get_log( ssl, request );

            break;

        case CONTROL_COMMAND_DROP_CONFIG:

            log_info( LOG_HIGH, request->host,"received drop-config request." );
            process_drop_config( ssl, request );

            break;

        case CONTROL_COMMAND_GET_HOST_BRIEF:

            log_info( LOG_HIGH, request->host, "received get-host request." );
            process_get_host_brief( ssl, request );

            break;

        case CONTROL_COMMAND_NEW_HOST:

            log_info( LOG_HIGH, NULL, "received new-host request." );
            process_new_host( ssl, request );

            break;

        case CONTROL_COMMAND_EDIT_HOST_BRIEF:

            log_info( LOG_HIGH, request->host, "received edit-host request." );
            process_edit_host_brief( ssl, request );

            break;
                
        case CONTROL_COMMAND_GET_HOST_CONFIG:

            log_info( LOG_HIGH, request->host,
                      "received get-host-config request." );

            process_get_host_config( ssl, request );
            break;

        case CONTROL_COMMAND_SAVE_HOST_CONFIG:

            log_info( LOG_HIGH, request->host,
                      "received save-host-config request." );

            process_save_host_config( ssl, request );
            break;

        case CONTROL_COMMAND_GET_MANAGEMENT_CONFIG:

            log_info( LOG_HIGH, NULL,
                      "received get-management-config request." );

            process_get_management_config( ssl, request );
            break;

        case CONTROL_COMMAND_SAVE_MANAGEMENT_CONFIG:

            log_info( LOG_HIGH, NULL,
                      "received save-management-config request." );

            process_save_management_config( ssl, request );
            break;
                                
        case CONTROL_COMMAND_HELLO:

            log_info( LOG_HIGH, NULL,
                      "received hello from management application." );

            process_hello( ssl, request );
            break;

        case CONTROL_COMMAND_GET_DATABASE:
            
            log_info( LOG_HIGH, request->host,  
                      "received get-database request." );

            process_get_database( ssl, request );
            break;

        default:
            log_error( LOG_MEDIUM, NULL,
                       "unknown control request received: %d",
                       (int)request->command );
            break;
    }
}

void process_hello( SSL *ssl, CONTROL_REQUEST *request )
{
    OSI_HELLO_RESPONSE hello_response;
    MESSAGE message;

    if( ( request == NULL ) || ( ssl == NULL ) )
    {
        return;
    }

    memset( &hello_response, 0, sizeof( hello_response ) );

    osi_strlcpy( hello_response.version, OSIRIS_VERSION,
                 sizeof( hello_response.version ) );

    osi_strlcpy( hello_response.message, "initial release.",
                 sizeof( hello_response.message ) );

    initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA );

    message_set_payload( &message, &hello_response,
                         sizeof( hello_response ), 0 );

    osi_ssl_write_message( &message, ssl );
}

void process_send_notify_test( SSL *ssl, CONTROL_REQUEST *request )
{
    OSI_ERROR error;

    if( osi_notify_send_test( &error ) == TRUE )
    {
        osi_ssl_write_success_message( ssl );
    }

    else
    {
        osi_ssl_write_error_message( 0, error.message, ssl );
    }
}


void process_get_notify_filter_list( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int result_size;

    int number_of_filters;
    int sequence = 0;

    unsigned char buffer[sizeof(OSI_NOTIFY_FILTER)];

    OSI_DB db;

    if( ( request == NULL ) || ( ssl == NULL ) )
    {
        return;
    }

    /* create path to the db to open. */

    memset( &db, 0, sizeof( db ) );
    osi_strlcpy( db.path, notify_filter_db_path, sizeof( db.path ) );

    result = osi_db_open( &db, OSI_DB_READ );

    if( result != OSI_DB_OK )
    {
        osi_ssl_write_error_message( OSI_ERROR_DB_OPEN_FAILED,
                                     "unable to open filter database.", ssl );

        return;
    }

    /* find number of errors in this database. */

    number_of_filters = osi_db_get_record_count( &db );

    if( number_of_filters <= 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_DB_NO_FILTERS,
                                     "filter database is empty.", ssl );

        return;
    }

    result = osi_db_get_first_record( &db, buffer, sizeof( buffer ),
                                      &result_size );

    while( result == OSI_DB_OK )
    {
        MESSAGE message;

        /* send this out in a message, if we are sending the */
        /* last message, put it in a CONTROL_DATA_LAST type. */

        if( ( sequence + 1 ) < number_of_filters )
        {
            initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA );
        }

        else
        {
            initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA_LAST );
        }

        result = message_set_payload( &message, buffer, result_size, sequence );

        if( result == MESSAGE_OK )
        {
            osi_ssl_write_message( &message, ssl );
        }

        sequence++;
        result = osi_db_get_next_record( &db, buffer, sizeof( buffer ),
                                         &result_size );
    }

    osi_db_close( &db );
}

void process_save_notify_filter_list( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int control_socket;

    MESSAGE message;
    fd_set read_set;

    OSI_DB db;

    if( ( request == NULL ) || ( ssl == NULL ) )
    {
        return;
    }

    memset( &db, 0, sizeof( db ) );
    osi_strlcpy( db.path, notify_filter_db_path, sizeof( db.path ) );

    result = osi_db_open( &db, OSI_DB_WRITE );

    if( result != OSI_DB_OK )
    {
        osi_ssl_write_error_message( OSI_ERROR_DB_OPEN_FAILED,
                                     "unable to open filter database.", ssl );
        return;
    }

    osi_db_truncate( &db );

    control_socket = SSL_get_fd( ssl );
    osi_set_socket_non_blocking( control_socket );

    for(;;)
    {
        int sresult;

        FD_ZERO( &read_set );
        FD_SET( control_socket, &read_set );

        sresult = select( ( control_socket + 1 ), &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( FD_ISSET( control_socket, &read_set ) )
        {
            osi_uint16 type;
            osi_uint16 size;

            OSI_NOTIFY_FILTER *filter;

            result = osi_ssl_read_message( &message, ssl );

            if( result != MESSAGE_OK )
            {
                osi_ssl_write_error_message( result,
                                "error reading filter-data message.", ssl );

                goto exit_gracefully;
            }

            type = GET_MESSAGE_TYPE( ( (MESSAGE *)&message ) );
            filter = MESSAGE_TO_TYPE( &message, OSI_NOTIFY_FILTER * );
            size = GET_MESSAGE_LENGTH( ( (MESSAGE *)&message ) );

            switch( (int)type )
            {
                /* first message triggers the truncation of the     */
                /* database.  Let it fall through to the next case. */

                case MESSAGE_TYPE_CONTROL_DATA_FIRST:
                case MESSAGE_TYPE_CONTROL_DATA:

                    if( ( filter != NULL ) && ( size > 0 ) )
                    {
                        osi_db_store_record( &db, filter, (int)size );
                    }

                    break;

                case MESSAGE_TYPE_CONTROL_DATA_LAST:

                    if( ( filter != NULL ) && ( size > 0 ) )
                    {
                        osi_db_store_record( &db, filter, (int)size );
                    }

                    else
                    {
                        log_info( LOG_HIGH, NULL,
                                  "received empty filter list." );
                    }

                    log_info( LOG_HIGH, NULL, "received updated filter list." );
                    osi_ssl_write_success_message( ssl );

                    goto exit_gracefully;
                    break;

                default:

                    log_error( LOG_MEDIUM, request->host,
                         "unrecognized message type in filter-data sequence." );

                    break;
            }
        }
    }

exit_gracefully:
    osi_db_close( &db );
}

void process_get_host_brief_list( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int sequence = 0;

    OSI_HOST_BRIEF *host_brief;
    int number_of_hosts;

    osi_list temp;
    osi_list current_hosts = osi_read_host_briefs( root_path );

    temp            = list_get_first_node( current_hosts );
    number_of_hosts = list_get_size( current_hosts );

    if( current_hosts == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_READ_HOSTS_FAILED,
                        "management daemon unable to retrieve host listing.",
                        ssl );
        return;
    }

    if( number_of_hosts == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOSTS,
                                     "no hosts exist.", ssl );

        list_destroy_with_function( current_hosts,
                                    (void (*)(void *))&osi_free );

        return;
    }

    while( temp )
    {
        OSI_HOST_BRIEF brief;
        MESSAGE message;

        host_brief = (OSI_HOST_BRIEF *)temp->data;

        if( host_brief != NULL )
        {
            /* populate the host brief structure. */

            osi_strlcpy( brief.name, host_brief->name, sizeof( brief.name ) );
            osi_strlcpy( brief.host, host_brief->host, sizeof( brief.host ) );

            osi_strlcpy( brief.description, host_brief->description,
                         sizeof( brief.description ) );

            osi_strlcpy( brief.session_key, host_brief->session_key,
                         sizeof( brief.session_key ) );

            brief.enabled = host_brief->enabled;
            brief.type    = host_brief->type;
            
            /* wrap thie host brief structure. */

            wrap_host_brief( &brief );

            /* send this out in a message, if we are sending the */
            /* last message, put it in a CONTROL_DATA_LAST type. */

            if( ( sequence + 1 ) < number_of_hosts )
            {
                initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA );
            }

            else
            {
                initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA_LAST );
            }

            result = message_set_payload( &message, &brief, sizeof( brief ),
                                          sequence );

            if( result == MESSAGE_OK )
            {
                osi_ssl_write_message( &message, ssl );
            }
        }

        temp = list_get_next_node( temp );
        sequence++;
    }

    list_destroy_with_function( current_hosts, (void (*)(void *))&osi_free );
}

void process_get_user_list( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int sequence = 0;

    OSI_AUTH_CONTEXT *auth;
    int number_of_users;

    osi_list temp;
    osi_list current_users = get_auth_list();

    temp            = list_get_first_node( current_users );
    number_of_users = list_get_size( current_users );

    if( current_users == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_READ_USERS_FAILED,
                        "management daemon unable to retrieve user listing.",
                        ssl );
        return;
    }

    if( number_of_users == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_USERS,
                                     "no users exist.", ssl );

        list_destroy_with_function( current_users,
                                    (void (*)(void *))&osi_free );

        return;
    }

    while( temp )
    {
        MESSAGE message;

        auth = (OSI_AUTH_CONTEXT *)temp->data;

        if( auth != NULL )
        {
            /* populate the host brief structure. */

            if( ( sequence + 1 ) < number_of_users )
            {
                initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA );
            }

            else
            {
                initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA_LAST );
            }

            result = message_set_payload( &message, auth,
                                        sizeof( OSI_AUTH_CONTEXT ), sequence );

            if( result == MESSAGE_OK )
            {
                osi_ssl_write_message( &message, ssl );
            }
        }

        temp = list_get_next_node( temp );
        sequence++;
    }

    list_destroy_with_function( current_users, (void (*)(void *))&osi_free );
}


void process_get_config_brief_list( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int number_of_configs;

    int sequence = 0;
    OSI_HOST *host;

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    host = osi_read_host( request->host );

    if( host == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_HOST_DOES_NOT_EXIST,
                                     "specified host does not exist", ssl );
        return;
    }

    number_of_configs = osi_host_read_config_briefs( host );

    if( number_of_configs > 0 )
    {
        osi_list temp = list_get_first_node( host->configs );

        while( temp )
        {
            OSI_CONFIG_BRIEF *config_brief;
            MESSAGE message;

            config_brief = (OSI_CONFIG_BRIEF *)temp->data;

            if( config_brief != NULL )
            {
                wrap_config_brief( config_brief );

                /* send this out in a message, if we are sending the */
                /* last message, put it in a CONTROL_DATA_LAST type. */

                if( ( sequence + 1 ) < number_of_configs )
                {
                    initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA );
                }

                else
                {
                    initialize_message( &message,
                                        MESSAGE_TYPE_CONTROL_DATA_LAST );
                }

                result = message_set_payload( &message, config_brief,
                                              sizeof( OSI_CONFIG_BRIEF ),
                                              sequence );

                if( result == MESSAGE_OK )
                {
                    osi_ssl_write_message( &message, ssl );
                }
            }

            temp = list_get_next_node( temp );
            sequence++;
        }

        /* now destroy  this host object. */

        osi_host_destroy( host );
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_CONFIGS,
                                     "no configurations exist for this host.",
                                     ssl );
    }
}


void process_get_database_brief_list( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int number_of_databases;

    int sequence = 0;
    OSI_HOST *host;

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    host = osi_read_host( request->host );

    if( host == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_HOST_DOES_NOT_EXIST,
                                     "specified host does not exist", ssl );
        return;
    }

    number_of_databases = osi_host_read_database_briefs( host );

    if( number_of_databases > 0 )
    {
        osi_list temp = list_get_first_node( host->databases );

        while( temp )
        {
            OSI_DATABASE_BRIEF *database_brief;
            MESSAGE message;

            database_brief = (OSI_DATABASE_BRIEF *)temp->data;

            if( database_brief != NULL )
            {
                wrap_database_brief( database_brief );

                /* send this out in a message, if we are sending the */
                /* last message, put it in a CONTROL_DATA_LAST type. */

                if( ( sequence + 1 ) < number_of_databases )
                {
                    initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA );
                }

                else
                {
                    initialize_message( &message,
                                        MESSAGE_TYPE_CONTROL_DATA_LAST );
                }

                result = message_set_payload( &message, database_brief,
                                              sizeof( OSI_DATABASE_BRIEF ),
                                              sequence );

                if( result == MESSAGE_OK )
                {
                    osi_ssl_write_message( &message, ssl );
                }
            }

            temp = list_get_next_node( temp );
            sequence++;
        }

        /* now destroy  this host object. */

        osi_host_destroy( host );
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_CONFIGS,
                                     "no databases exist for this host.", ssl );
    }
}

void process_get_log_brief_list( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int number_of_logs;

    int sequence = 0;
    OSI_HOST *host;

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    host = osi_read_host( request->host );

    if( host == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_HOST_DOES_NOT_EXIST,
                                     "specified host does not exist", ssl );
        return;
    }

    number_of_logs = osi_host_read_log_briefs( host );

    if( number_of_logs > 0 )
    {
        osi_list temp = list_get_first_node( host->logs );

        while( temp )
        {
            OSI_LOG_BRIEF *log_brief;
            MESSAGE message;

            log_brief = (OSI_LOG_BRIEF *)temp->data;

            if( log_brief != NULL )
            {
                wrap_log_brief( log_brief );

                /* send this out in a message, if we are sending the */
                /* last message, put it in a CONTROL_DATA_LAST type. */

                if( ( sequence + 1 ) < number_of_logs )
                {
                    initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA );
                }

                else
                {
                    initialize_message( &message,
                                        MESSAGE_TYPE_CONTROL_DATA_LAST );
                }

                result = message_set_payload( &message, log_brief,
                                              sizeof( OSI_LOG_BRIEF ),
                                              sequence );

                if( result == MESSAGE_OK )
                {
                    osi_ssl_write_message( &message, ssl );
                }
            }

            temp = list_get_next_node( temp );
            sequence++;
        }

        /* now destroy  this host object. */

        osi_host_destroy( host );
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_CONFIGS,
                                     "no logs exist for this host.", ssl );
    }
}

void process_get_database_errors( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int number_of_errors;

    int sequence = 0;
    int size;

    OSI_DB db;
    OSI_ERROR error;

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    if( strlen( request->buffer ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_DB_SPECIFIED,
                                     "no database specified.", ssl );
        return;
    }

    /* create path to the db to open. */

    memset( &db, 0, sizeof( db ) );
    result = osi_host_set_database_path_with_name( &db, request->host,
                                                   request->buffer );

    if( result != OSI_DB_OK )
    {
        osi_ssl_write_error_message( OSI_ERROR_DB_PATH,
                                     "unable to find database.", ssl );
        return;
    }

    result = osi_scan_db_open( &db, OSI_DB_READ );

    if( result != OSI_DB_OK )
    {
        osi_ssl_write_error_message( OSI_ERROR_DB_OPEN_FAILED,
                                     "unable to open database.", ssl );
        return;
    }

    /* find number of errors in this database. */

    number_of_errors = osi_host_get_db_error_count( request->host,
                                                    request->buffer );

    if( number_of_errors <= 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_DB_NO_ERRORS,
                                     "no errors exist in this database.", ssl );
        return;
    }

    result = osi_scan_db_get_first_error( &db, &error, sizeof( error ), &size );

    while( result == OSI_DB_OK )
    {
        MESSAGE message;
        char buffer[sizeof(OSI_ERROR)];

        /* send this out in a message, if we are sending the */
        /* last message, put it in a CONTROL_DATA_LAST type. */

        if( ( sequence + 1 ) < number_of_errors )
        {
            initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA );
        }

        else
        {
            initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA_LAST );
        }

        wrap_error( &error );
        pack_error( &error, buffer, sizeof( buffer ) );

        result = message_set_payload( &message, &error, sizeof( OSI_ERROR ),
                                      sequence );

        if( result == MESSAGE_OK )
        {
            osi_ssl_write_message( &message, ssl );
        }

        sequence++;
        result = osi_scan_db_get_next_error( &db, &error,

                                             sizeof( error ), &size );
    }

    osi_scan_db_close( &db );
}



void process_status( SSL *ssl, CONTROL_REQUEST *request )
{
    int connection_socket = 0;
    int result;

    MESSAGE req;
    MESSAGE res;

    OSI_HOST *host = NULL;
    SSL *connection_ssl = NULL;

    /* first make sure we have a host to connect to, we      */
    /* get the hostname from the specified host's structure. */

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    /* read host structure from disk. */

    if( ( host = osi_read_host( request->host ) ) == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_HOST_DOES_NOT_EXIST,
                                     "specified host does not exist", ssl );
        return;
    }

    initialize_message( &req, MESSAGE_TYPE_STATUS_REQUEST );
    initialize_message( &res, 0 );

    connection_ssl = osi_ssl_connect_to_host_on_port( host->host,
                                                      DAEMON_PORT,
                                                      ssl_context,
                                                      FALSE );

    if( connection_ssl == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_UNABLE_TO_CONNECT,
                                     "unable to connect to host.", ssl );

        goto exit_gracefully;
    }

    connection_socket = SSL_get_fd( connection_ssl );

    if( perform_session_key_negotiation( connection_ssl, host ) == FALSE )
    {
        osi_ssl_write_error_message( OSI_ERROR_SESSION_KEY_NEGOTIATION_FAILED,
                             "session key negotiation with remote host failed.",
                             ssl );

        log_error( LOG_MEDIUM, host->host, "session key negotiation failed." );
        goto exit_gracefully;
    }

    result = osi_ssl_write_message( &req, connection_ssl );

    if( result == MESSAGE_OK )
    {
        if( osi_ssl_read_message( &res, connection_ssl ) == MESSAGE_OK )
        {
            result = osi_ssl_write_message( &res, ssl );
            goto exit_gracefully;
        }

        else
        {
            osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                  "contacted daemon with no response.", ssl );
        }
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_UNABLE_TO_CONNECT,
                                     "unable to contact host.", ssl );
    }

exit_gracefully:

    if( connection_socket != 0 )
    {
        osi_close_socket( connection_socket );
    }

    if( connection_ssl != NULL )
    {
        osi_ssl_destroy( &connection_ssl );
    }

    if( host != NULL )
    {
        osi_host_destroy( host );
    }
}

void process_set_user( SSL *ssl, CONTROL_REQUEST *request )
{
    osi_bool result;

    MESSAGE message;
    OSI_AUTH_CONTEXT *auth_context;

    if( osi_ssl_read_message( &message, ssl ) != MESSAGE_OK )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                     "no auth information specified.",
                                     ssl );
        return;
    }

    auth_context = MESSAGE_TO_TYPE( &message, OSI_AUTH_CONTEXT * );

    if( auth_context == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                     "no auth information specified.", ssl );
        return;
    }

    if( strlen( auth_context->auth_user ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_USER_LOGIN_SPECIFIED,
                                     "no user login name specified.", ssl );
        return;
    }

    /* now just update the user database. */

    result = set_auth_entry( auth_context->auth_user, auth_context->auth_pass );

    if( result )
    {
        osi_ssl_write_success_message( ssl );
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_SET_USER_LOGIN_FAILED,
                                     "unable to set user login.", ssl );
    }
}


void process_delete_user( SSL *ssl, CONTROL_REQUEST *request )
{
    if( strlen( request->buffer ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_USER_LOGIN_SPECIFIED,
                                     "no user name specified.", ssl );
        return;
    }

    if( auth_entry_exists( request->buffer ) == FALSE )
    {
        osi_ssl_write_error_message( OSI_ERROR_USER_DOES_NOT_EXIST,
                                     "specified user does not exist.", ssl );
        return;
    }

    /* delete the user from the auth database and */
    /* initiate an update to the auth list.       */

    if( del_auth_entry( request->buffer ) )
    {
        osi_ssl_write_success_message( ssl );
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_DELETE_USER_FAILED,
                                     "failed to delete user.", ssl );
    }
}


void process_get_host_brief( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;

    OSI_HOST_BRIEF *host_brief;
    MESSAGE message;

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    host_brief = osi_read_host_brief( request->host );

    if( host_brief == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_DATABASE_DOES_NOT_EXIST,
                                     "specified host doesn't exist.", ssl );
        return;
    }

    /* get db and config counts, they don't automatically come with */
    /* a host brief read.                                           */

    host_brief->config_count = osi_host_get_config_count( request->host );
    host_brief->database_count = osi_host_get_database_count( request->host );

    wrap_host_brief( host_brief );
    initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA_LAST );

    result = message_set_payload( &message, host_brief,
                                  sizeof( OSI_HOST_BRIEF ), 0 );

    if( result == MESSAGE_OK )
    {
        osi_ssl_write_message( &message, ssl );
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_SETTING_MESSAGE_PAYLOAD,
                                     "error sending host-data.", ssl );
    }

    osi_free( host_brief );
}

void process_get_database_brief( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;

    OSI_DATABASE_BRIEF db_brief;
    MESSAGE message;

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    if( strlen( request->buffer ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_DB_SPECIFIED,
                                     "no database specified.", ssl );
        return;
    }

    result = osi_host_read_database_brief_with_name( &db_brief,
                                                     request->host,
                                                     request->buffer );

    if( result != OSI_DB_OK )
    {
        osi_ssl_write_error_message( OSI_ERROR_DATABASE_DOES_NOT_EXIST,
                                     "database doesn't exist.", ssl );
        return;
    }

    /* send database brief back to requesting management application. */

    wrap_database_brief( &db_brief );
    initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA_LAST );

    result = message_set_payload( &message, &db_brief,
                                  sizeof( OSI_DATABASE_BRIEF ), 0 );

    if( result == MESSAGE_OK )
    {
        osi_ssl_write_message( &message, ssl );
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_SETTING_MESSAGE_PAYLOAD,
                                     "error sending config-data.", ssl );
    }
}



void process_new_host( SSL *ssl, CONTROL_REQUEST *request )
{
    MESSAGE message;

    OSI_HOST_BRIEF *host_brief;
    OSI_HOST new_host;

    /* first, we receive the host brief we will use to create */
    /* the new host directory and conf file.                  */

    if( osi_ssl_read_message( &message, ssl ) != MESSAGE_OK )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                     "no host information specified.",
                                     ssl );
        return;
    }

    host_brief = MESSAGE_TO_TYPE( &message, OSI_HOST_BRIEF * );

    if( host_brief == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                     "no host information specified.", ssl );
        return;
    }

    unwrap_host_brief( host_brief );

    /* now populate a host structure and try to write it to disk. */

    memset( &new_host, 0, sizeof( new_host ) );

    if( osi_host_exists( host_brief->name ) )
    {
        osi_ssl_write_error_message( OSI_ERROR_HOST_EXISTS,
                 "host already exists, modify host if necessary.", ssl );

        return;
    }

    osi_strlcpy( new_host.name, host_brief->name, sizeof( new_host.name ) );
    osi_strlcpy( new_host.host, host_brief->host, sizeof( new_host.host ) );

    osi_strlcpy( new_host.description, host_brief->description,
                 sizeof( new_host.description ) );

    new_host.enabled          = host_brief->enabled;
    new_host.type             = host_brief->type;

    new_host.file_log_enabled = host_brief->file_log_enabled;
    new_host.archive_databases = host_brief->archive_databases;

    new_host.notify_enabled   = host_brief->notify_enabled;
    new_host.notify_always    = host_brief->notify_always;

    new_host.schedule_start   = host_brief->schedule_start;
    new_host.schedule_period  = host_brief->schedule_period;

    if( osi_write_host( &new_host ) )
    {
        /* we kick the scheduler because we have added a new host. */

        osi_ssl_write_success_message( ssl );
        signal_schedules_updated();
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                     "unable to create host.", ssl );
    }
}


void process_edit_host_brief( SSL *ssl, CONTROL_REQUEST *request )
{
    MESSAGE message;

    OSI_HOST_BRIEF *host_brief;

    /* first, we receive the host brief we will use to create */
    /* the new host directory and conf file.                  */

    if( osi_ssl_read_message( &message, ssl ) != MESSAGE_OK )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                     "no host information specified.", ssl );
        return;
    }

    host_brief = MESSAGE_TO_TYPE( &message, OSI_HOST_BRIEF * );

    if( host_brief == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                     "no host information specified.", ssl );
        return;
    }

    unwrap_host_brief( host_brief );

    /* read in the current host from disk, and update the information */
    /* we received.                                                   */

    if( osi_host_exists( host_brief->name ) == FALSE )
    {
        osi_ssl_write_error_message( OSI_ERROR_HOST_EXISTS,
                                     "host doesn't exist.", ssl );
        return;
    }

    if( osi_write_host_brief( host_brief ) )
    {
        /* we kick the scheduler because we have modified a host. */

        osi_ssl_write_success_message( ssl );
        signal_schedules_updated();
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                     "unable to create host.", ssl );
    }
}


void process_push_config( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;

    if( ( ssl == NULL ) || ( request == NULL ) )
    {
        return;
    }

    result = osi_host_push_config( request->host, request->buffer );

    if( result == OSI_OK )
    {
        osi_ssl_write_success_message( ssl );
    }

    else
    {
        osi_ssl_write_error_message( result, "unable to push config.", ssl );
    }
}

void process_import_default_config( SSL *ssl, CONTROL_REQUEST *request )
{
    int connection_socket = 0;
    int result;

    configuration *cfg;

    cfg = osi_host_read_default_config( request->buffer );

    if( ( cfg == NULL ) || ( cfg->data == NULL ) )
    {
        osi_ssl_write_error_message( OSI_ERROR_CONFIG_DOES_NOT_EXIST,
                                     "specified config does not exist", ssl );
        return;
    }

    result = osi_config_write_with_name( cfg, request->host,
                                         DEFAULT_CONFIG_NAME );

    if( result == OSI_OK )
    {
        osi_ssl_write_success_message( ssl );
    }

    else
    {
        osi_ssl_write_error_message( result, "error storing config file.",
                                     ssl );
    }

    osi_config_destroy( cfg );
}

void process_set_base_db( SSL *ssl, CONTROL_REQUEST *request )
{
    OSI_HOST_BRIEF *host_brief;

    host_brief = osi_read_host_brief( request->host );

    if( host_brief == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_HOST_DOES_NOT_EXIST,
                                     "specified host doesn't exist.", ssl );
        return;
    }

    if( osi_host_database_exists( request->host, request->buffer ) == FALSE )
    {
        osi_ssl_write_error_message( OSI_ERROR_DATABASE_DOES_NOT_EXIST,
                                     "specified database doesn't exist.", ssl );

        return;
    }

    /* copy in new value for base database, and save host. */

    osi_strlcpy( host_brief->base_db, request->buffer,
                 sizeof( host_brief->base_db ) );

    if( osi_write_host_brief( host_brief ) )
    {
        osi_ssl_write_success_message( ssl );
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                     "unable to save settings.", ssl );
    }
}

void process_unset_base_db( SSL *ssl, CONTROL_REQUEST *request )
{
    OSI_HOST_BRIEF *host_brief;

    host_brief = osi_read_host_brief( request->host );

    if( host_brief == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_HOST_DOES_NOT_EXIST,
                                     "specified host doesn't exist.", ssl );
        return;
    }

    /* zero out the base database. */

    memset( host_brief->base_db, 0, sizeof( host_brief->base_db ) );

    /* write it back to disk. */

    if( osi_write_host_brief( host_brief ) )
    {
        osi_ssl_write_success_message( ssl );
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                     "unable to unset trusted database.", ssl );
    }
}


void process_import_config( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int control_socket;

    configuration *cfg;
    MESSAGE message;

    fd_set read_set;

    if( ( request == NULL ) || ( ssl == NULL ) )
    {
        return;
    }

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    if( strlen( request->buffer ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_CONFIG_SPECIFIED,
                                     "no config specified.", ssl );
        return;
    }

    control_socket = SSL_get_fd( ssl );
    osi_set_socket_non_blocking( control_socket );

    for(;;)
    {
        int sresult;

        FD_ZERO( &read_set );
        FD_SET( control_socket, &read_set );

        sresult = select( ( control_socket + 1 ), &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( FD_ISSET( control_socket, &read_set ) )
        {
            osi_uint16 type;
            char *line;

            result = osi_ssl_read_message( &message, ssl );

            if( result != MESSAGE_OK )
            {
                osi_ssl_write_error_message( result,
                        "error reading config-data message.", ssl );
                return;
            }

            type = GET_MESSAGE_TYPE( ( (MESSAGE *)&message ) );
            line = MESSAGE_TO_TYPE( &message, char * );

            switch( (int)type )
            {
                case MESSAGE_TYPE_CONFIG_DATA:

                    if( line != NULL )
                    {
                        osi_config_receive( cfg, line, strlen( line ) );
                    }

                    break;

                case MESSAGE_TYPE_CONFIG_DATA_FIRST:

                    cfg = osi_config_new();

                    if( line != NULL )
                    {
                        osi_config_receive_first( cfg, line, strlen( line ) );
                    }

                    break;

                case MESSAGE_TYPE_CONFIG_DATA_LAST:

                    if( line != NULL )
                    {
                        osi_config_receive_last( cfg, line, strlen( line ) );
                    }

                    result = osi_config_write_with_name( cfg, request->host,
                                                         request->buffer );

                    if( result == OSI_OK )
                    {
                        osi_ssl_write_success_message( ssl );
                    }

                    else
                    {
                        osi_ssl_write_error_message( result,
                                        "error storing config file.", ssl );
                    }

                    osi_config_destroy( cfg );
                    return;

                    break;

                default:

                    log_error( LOG_MEDIUM, request->host,
                        "unrecognized message type in config-data sequence." );
                    break;
            }
        }
    }
}

void process_start_scan( SSL *ssl, CONTROL_REQUEST *request )
{
    MESSAGE res;

    if( ( request == NULL ) || ( ssl == NULL ) )
    {
        return;
    }

    memset( &res, 0, sizeof( res ) );

    scan_host( request->host, &res );
    osi_ssl_write_message( &res, ssl );
}


void process_stop_scan( SSL *ssl, CONTROL_REQUEST *request )
{
    int connection_socket = 0;
    int result;

    MESSAGE req;
    MESSAGE res;

    SSL *connection_ssl;
    OSI_HOST *host;

    if( request == NULL )
    {
        return;
    }

    /* first make sure we have a host to connect to, we      */
    /* get the hostname from the specified host's structure. */

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    /* read host structure from disk. */

    if( ( host = osi_read_host( request->host ) ) != NULL )
    {
        initialize_message( &req, MESSAGE_TYPE_STOP_SCAN );

        connection_ssl = osi_ssl_connect_to_host_on_port( host->host,
                                                          DAEMON_PORT,
                                                          ssl_context,
                                                          FALSE );

        if( connection_ssl )
        {
            connection_socket = SSL_get_fd( connection_ssl );

            if( perform_session_key_negotiation( connection_ssl,
                                                 host ) == FALSE )
            {
                osi_ssl_write_error_message(
                    OSI_ERROR_SESSION_KEY_NEGOTIATION_FAILED,
                    "session key negotiation with remote host failed.", ssl );

                log_error( LOG_MEDIUM, host->host,
                           "session key negotiation failed." );

                osi_close_socket( connection_socket );
                osi_ssl_destroy( &connection_ssl );
                osi_host_destroy( host );

                return;
            }

            result = osi_ssl_write_message( &req, connection_ssl );

            if( result == MESSAGE_OK )
            {
                if( osi_ssl_read_message( &res, connection_ssl ) == MESSAGE_OK )
                {
                    osi_ssl_write_message( &res, ssl );
                }

                else
                {
                    osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                    "no response from remote daemon.", ssl );
                }
            }

            else
            {
                osi_ssl_write_error_message( OSI_ERROR_UNABLE_TO_CONNECT,
                                    "unable to contact remote daemon.", ssl );
            }

            osi_close_socket( connection_socket );
            osi_ssl_destroy( &connection_ssl );
        }

        else
        {
            osi_ssl_write_error_message( OSI_ERROR_UNABLE_TO_CONNECT,
                                    "unable to contact host.", ssl );
        }

        osi_host_destroy( host );
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_HOST_DOES_NOT_EXIST,
                                    "specified host does not exist", ssl );
    }
}


void process_get_config( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int index;

    configuration *cfg;
    MESSAGE message;

    string_list *lines;

    if( request == NULL )
    {
        return;
    }

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    if( strlen( request->buffer ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_CONFIG_SPECIFIED,
                                     "no config specified.", ssl );
        return;
    }

    cfg = osi_host_read_config_with_name( request->host, request->buffer );

    if( cfg == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_CONFIG_DOES_NOT_EXIST,
                                     "config doesn't exist.", ssl );
        return;
    }

    if( ( cfg->data == NULL ) || ( cfg->data->size == 0 ) )
    {
        osi_ssl_write_error_message( OSI_ERROR_CONFIG_IS_EMPTY,
                                     "config file is empty.", ssl );
        osi_config_destroy( cfg );
        return;
    }

    /* send config data back to requesting management application. */

    lines = cfg->data;

    /* send first config line. */

    initialize_message( &message, MESSAGE_TYPE_CONFIG_DATA_FIRST );

    result = message_set_payload( &message, lines->list[0],
                                  strlen( lines->list[0] ), 0 );

    if( result == MESSAGE_OK )
    {
        osi_ssl_write_message( &message, ssl );
    }

    for( index = 1; (unsigned int)index < lines->size; index++ )
    {
        if( (unsigned int)( index + 1 ) != lines->size )
        {
            initialize_message( &message, MESSAGE_TYPE_CONFIG_DATA );
        }

        else
        {
            initialize_message( &message, MESSAGE_TYPE_CONFIG_DATA_LAST );
        }

        result = message_set_payload( &message, lines->list[index],
                                      strlen( lines->list[index] ), index );

        if( result == MESSAGE_OK )
        {
            result = osi_ssl_write_message( &message, ssl );
        }

        else
        {
            osi_ssl_write_error_message( OSI_ERROR_SETTING_MESSAGE_PAYLOAD,
                                         "error sending config-data.", ssl );
        }
    }

    osi_free( cfg );
}

void process_get_log( SSL *ssl, CONTROL_REQUEST *request )
{
    FILE *file = NULL;
    MESSAGE message;

    int sequence = 0;
    int result;

    char buffer[256];

    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };

    if( ( request == NULL ) || ( ssl == NULL ) || ( ssl_context == NULL ) )
    {
        return;
    }

    /* make sure we have a log file name. */

    if( strlen( request->buffer ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_FILE_NOT_FOUND,
                                     "no log file specified.", ssl );

        return;
    }

    /* first, we construct path to log file. */

    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, request->host, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOST_LOG_DIRECTORY_NAME, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, request->buffer, sizeof( path ) );

    if( ( file = osi_fopen( path, "r", 0 ) ) == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_FILE_NOT_FOUND,
                                     "log file does not exist.", ssl );

        return;
    }

    for(;;)
    {
        size_t bytes;

        memset( buffer, 0, sizeof( buffer ) );

        bytes = fread( buffer, sizeof( char ), ( sizeof( buffer ) - 1 ), file );

        if( bytes == 0 )
        {
            initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA_LAST );
            osi_ssl_write_message( &message, ssl );

            break;
        }

        /* terminate buffer. */
    
        buffer[bytes] = '\0';
        initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA );

        result = message_set_payload( &message, buffer, ( bytes + 1 ),
                                      sequence );

        if( result == MESSAGE_OK )
        {
            osi_ssl_write_message( &message, ssl );
            sequence++;
        }
    }

    fclose( file );
}

void process_drop_config( SSL *ssl, CONTROL_REQUEST *request )
{
    int connection_socket = 0;
    int result;

    MESSAGE req;
    MESSAGE res;

    SSL *connection_ssl;
    OSI_HOST *host;

    if( request == NULL )
    {
        return;
    }

    /* first make sure we have a host to connect to, we      */
    /* get the hostname from the specified host's structure. */

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    /* read host structure from disk. */

    if( ( host = osi_read_host( request->host ) ) == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_HOST_DOES_NOT_EXIST,
                                    "specified host does not exist", ssl );
        return;
    }

    initialize_message( &req, MESSAGE_TYPE_DROP_CONFIG );
    initialize_message( &res, 0 );

    connection_ssl = osi_ssl_connect_to_host_on_port( host->host,
                                                      DAEMON_PORT,
                                                      ssl_context, FALSE );

    if( connection_ssl != NULL )
    {
        connection_socket = SSL_get_fd( connection_ssl );

        if( perform_session_key_negotiation( connection_ssl, host ) == FALSE )
        {
            osi_ssl_write_error_message( 
                    OSI_ERROR_SESSION_KEY_NEGOTIATION_FAILED,
                    "session key negotiation with remote host failed.", ssl );

            log_error( LOG_MEDIUM, host->host,
                       "session key negotiation failed." );

            osi_close_socket( connection_socket );
            osi_ssl_destroy( &connection_ssl );
            osi_host_destroy( host );

            return;
        }

        result = osi_ssl_write_message( &req, connection_ssl );

        if( result == MESSAGE_OK )
        {
            if( osi_ssl_read_message( &res, connection_ssl ) == MESSAGE_OK )
            {
                result = osi_ssl_write_message( &res, ssl );
            }

            else
            {
                osi_ssl_write_error_message( OSI_ERROR_NO_RESPONSE,
                                "no response from remote daemon.", ssl );
            }
        }

        else
        {
            osi_ssl_write_error_message( OSI_ERROR_UNABLE_TO_CONNECT,
                                "unable to contact remote daemon.", ssl );
        }

        osi_close_socket( connection_socket );
        osi_ssl_destroy( &connection_ssl );
    }

    else
    {
        osi_ssl_write_error_message( OSI_ERROR_UNABLE_TO_CONNECT,
                                     "unable to contact host.", ssl );
    }

    osi_host_destroy( host );
}

void process_get_host_config( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int index;

    OSI_HOST_CONFIG *cfg;
    MESSAGE message;

    string_list *lines;

    if( request == NULL )
    {
        return;
    }

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }
    
    cfg = osi_host_read_host_config_with_name( request->host );

    if( cfg == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_CONFIG_DOES_NOT_EXIST,
                                     "config doesn't exist.", ssl );
        return;
    }

    if( ( cfg->data == NULL ) || ( cfg->data->size == 0 ) )
    {
        osi_ssl_write_error_message( OSI_ERROR_CONFIG_IS_EMPTY,
                                     "config file is empty.", ssl );

        osi_host_config_destroy( cfg );
        return;
    }

    /* send config data back to requesting management application. */

    lines = cfg->data;

    /* send first config line. */

    initialize_message( &message, MESSAGE_TYPE_CONFIG_DATA_FIRST );

    result = message_set_payload( &message, lines->list[0],
                                  strlen( lines->list[0] ), 0 );

    if( result == MESSAGE_OK )
    {
        osi_ssl_write_message( &message, ssl );
    }

    for( index = 1; (unsigned int)index < lines->size; index++ )
    {
        if( (unsigned int)( index + 1 ) != lines->size )
        {
            initialize_message( &message, MESSAGE_TYPE_CONFIG_DATA );
        }

        else
        {
            initialize_message( &message, MESSAGE_TYPE_CONFIG_DATA_LAST );
        }

        result = message_set_payload( &message, lines->list[index],
                                      strlen( lines->list[index] ), index );

        if( result == MESSAGE_OK )
        {
            result = osi_ssl_write_message( &message, ssl );
        }

        else
        {
            osi_ssl_write_error_message( OSI_ERROR_SETTING_MESSAGE_PAYLOAD,
                                         "error sending config-data.", ssl );
        }
    }

    osi_host_config_destroy( cfg );
}

void process_save_host_config( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int control_socket;

    OSI_HOST_CONFIG *cfg;
    MESSAGE message;

    fd_set read_set;

    if( ( request == NULL ) || ( ssl == NULL ) )
    {
        return;
    }

    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }

    control_socket = SSL_get_fd( ssl );
    osi_set_socket_non_blocking( control_socket );

    for(;;)
    {
        int sresult;

        FD_ZERO( &read_set );
        FD_SET( control_socket, &read_set );

        sresult = select( ( control_socket + 1 ), &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( FD_ISSET( control_socket, &read_set ) )
        {
            osi_uint16 type;
            char *line;

            result = osi_ssl_read_message( &message, ssl );

            if( result != MESSAGE_OK )
            {
                osi_ssl_write_error_message( result,
                                 "error reading config-data message.", ssl );
                return;
            }

            type = GET_MESSAGE_TYPE( ( (MESSAGE *)&message ) );
            line = MESSAGE_TO_TYPE( &message, char * );

            switch( (int)type )
            {
                case MESSAGE_TYPE_CONFIG_DATA:

                    if( line != NULL )
                    {
                        osi_host_config_receive( cfg, line, strlen( line ) );
                    }

                    break;

                case MESSAGE_TYPE_CONFIG_DATA_FIRST:

                    cfg = osi_host_config_new();

                    if( line != NULL )
                    {
                        osi_host_config_receive_first( cfg, line,
                                                       strlen( line ) );
                    }

                    break;

                case MESSAGE_TYPE_CONFIG_DATA_LAST:

                    if( line != NULL )
                    {
                        osi_host_config_receive_last( cfg, line,
                                                      strlen( line ) );
                    }

                    result = osi_host_write_host_config_with_name( cfg,
                                                               request->host );

                    if( result == OSI_OK )
                    {
                        osi_ssl_write_success_message( ssl );
                    }

                    else
                    {
                        osi_ssl_write_error_message( result,
                                    "error storing config file.", ssl );
                    }

                    osi_host_config_destroy( cfg );
                    return;

                    break;

                default:

                    log_error( LOG_MEDIUM, request->host,
                         "unrecognized message type in config-data sequence." );

                    break;
            }
        }
    }
}

void process_get_management_config( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int index;

    OSI_MANAGEMENT_CONFIG *cfg;
    MESSAGE message;
    
    string_list *lines;
            
    if( request == NULL )
    {
        return;
    }
    
    cfg = osi_management_config_new_from_file( config_file_path );

    if( cfg == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_CONFIG_DOES_NOT_EXIST,
                                     "management config doesn't exist.", ssl );
        return;
    }

    if( ( cfg->data == NULL ) || ( cfg->data->size == 0 ) )
    {
        osi_ssl_write_error_message( OSI_ERROR_CONFIG_IS_EMPTY,
                                     "management config file is empty.", ssl );

        osi_management_config_destroy( cfg );
        return;
    }

    /* send config data back to requesting management application. */

    lines = cfg->data;

    /* send first config line. */

    initialize_message( &message, MESSAGE_TYPE_CONFIG_DATA_FIRST );

    result = message_set_payload( &message, lines->list[0],
                                  strlen( lines->list[0] ), 0 );

    if( result == MESSAGE_OK )
    {
        osi_ssl_write_message( &message, ssl );
    }

    for( index = 1; (unsigned int)index < lines->size; index++ )
    {
        if( (unsigned int)( index + 1 ) != lines->size )
        {
            initialize_message( &message, MESSAGE_TYPE_CONFIG_DATA );
        }

        else
        {
            initialize_message( &message, MESSAGE_TYPE_CONFIG_DATA_LAST );
        }

        result = message_set_payload( &message, lines->list[index],
                                      strlen( lines->list[index] ), index );

        if( result == MESSAGE_OK )
        {
            result = osi_ssl_write_message( &message, ssl );
        }

        else
        {
            osi_ssl_write_error_message( OSI_ERROR_SETTING_MESSAGE_PAYLOAD,
                                         "error sending config-data.", ssl );
        }
    }

    osi_management_config_destroy( cfg );
}

void process_save_management_config( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    int control_socket;

    OSI_MANAGEMENT_CONFIG *cfg;
    MESSAGE message;

    fd_set read_set;

    if( ( request == NULL ) || ( ssl == NULL ) )
    {
        return;
    }

    control_socket = SSL_get_fd( ssl );
    osi_set_socket_non_blocking( control_socket );

    for(;;)
    {
        int sresult;

        FD_ZERO( &read_set );
        FD_SET( control_socket, &read_set );

        sresult = select( ( control_socket + 1 ), &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( FD_ISSET( control_socket, &read_set ) )
        {
            osi_uint16 type;
            char *line;

            result = osi_ssl_read_message( &message, ssl );

            if( result != MESSAGE_OK )
            {
                osi_ssl_write_error_message( result,
                                "error reading config-data message.", ssl );
                return;
            }

            type = GET_MESSAGE_TYPE( ( (MESSAGE *)&message ) );
            line = MESSAGE_TO_TYPE( &message, char * );

            switch( (int)type )
            {
                case MESSAGE_TYPE_CONFIG_DATA:

                    if( line != NULL )
                    {
                        osi_management_config_receive( cfg, line,
                                                       strlen( line ) );
                    }

                    break;

                case MESSAGE_TYPE_CONFIG_DATA_FIRST:

                    cfg = osi_management_config_new();

                    if( line != NULL )
                    {
                        osi_management_config_receive_first( cfg, line,
                                                             strlen( line ) );
                    }

                    break;

                case MESSAGE_TYPE_CONFIG_DATA_LAST:

                    if( line != NULL )
                    {
                        osi_management_config_receive_last( cfg, line,
                                                            strlen( line ) );
                    }

                    result = osi_management_config_write_file( config_file_path,
                                                               cfg );

                    if( result == OSI_OK )
                    {
                        /* inform client we saved it and signal a restart. */
                        /* of our daemon, and our scheduler.               */

                        osi_ssl_write_success_message( ssl );
                        signal_restart_needed();
                        signal_schedules_updated();

                        /* reload our configuration file. */

#ifndef HAVE_THREADS
                        parse_configuration_file();
#endif
                    }

                    else
                    {
                        osi_ssl_write_error_message( result,
                                    "error storing config file.", ssl );
                    }

                    osi_management_config_destroy( cfg );
                    return;

                    break;

                default:

                    log_error( LOG_MEDIUM, request->host,
                         "unrecognized message type in config-data sequence." );

                    break;
            }
        }
    }
}

void process_get_database( SSL *ssl, CONTROL_REQUEST *request )
{
    int result;
    osi_uint64 filesize   = 0;
    osi_uint64 bytes_read = 0;
    
    MESSAGE message;
    FILE *dbfile = NULL;
    
    osi_bool data_left = TRUE;
    int sequence       = 0;
                
    if( ( request == NULL ) || ( ssl == NULL ) )
    {
        return;
    }
    
    if( strlen( request->host ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_HOST_SPECIFIED,
                                     "no host specified.", ssl );
        return;
    }
    
    if( strlen( request->buffer ) == 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_NO_DB_SPECIFIED,
                                     "no database name specified.", ssl );
        return;
    }
    
    /* try to get size of database file. */
    
    filesize = (osi_uint64)osi_host_determine_db_file_size( request->host,
                                                            request->buffer );

    if( filesize <= 0 )
    {
        osi_ssl_write_error_message( OSI_ERROR_DB_OPEN_FAILED,
                            "unable to determine database file size.", ssl );
        return;
    }
    
    /* now we open the database file, if succesfull, we see how big it   */
    /* is and respond with a success message containing the total bytes. */

    dbfile = osi_host_open_db_file_read_only( request->host, request->buffer );
    
    if( dbfile == NULL )
    {
        osi_ssl_write_error_message( OSI_ERROR_DB_OPEN_FAILED,
                                "unable to open specified database.", ssl );
        return;
    }
    

    /* send success message. */
    
    initialize_message( &message, MESSAGE_TYPE_DB_DATA_FIRST );
    filesize = HTONLL( filesize );

    result = message_set_payload( &message, &filesize, sizeof( filesize ),
                                  sequence );

    filesize = NTOHLL( filesize );
    
    osi_ssl_write_message( &message, ssl );
    sequence++;
    
    /* now send all of the data in the database file. */
    
    while( data_left )
    {
        unsigned char burst[DB_FILE_READ_CHUNK_SIZE];
        int burst_size;
        
        burst_size = fread( burst, 1, sizeof( burst ), dbfile );
        
        if( burst_size > 0 )
        {
            bytes_read += burst_size;
            
            if( bytes_read != filesize )
            {
                initialize_message( &message, MESSAGE_TYPE_DB_DATA );
                message_set_payload( &message, burst, burst_size, sequence );
                
                result = osi_ssl_write_message( &message, ssl );
                sequence++;
            }
            
            /* otherwise, we've read all the data in the file. */
            
            else
            {
                initialize_message( &message, MESSAGE_TYPE_DB_DATA_LAST );
                message_set_payload( &message, burst, burst_size, sequence );
                
                result = osi_ssl_write_message( &message, ssl );
                data_left = FALSE;
            }
            
            if( result != MESSAGE_OK )
            {
                log_error( LOG_MEDIUM, request->host,
                           "error sending db data to management app: %s",
                           osi_get_name_for_error( result ) );
                break;
            }
        }
        
        else
        {
            /* error occured. */
            
            data_left = FALSE;
        }
    }
    
    fclose( dbfile );
}


void receive_scan_data( SSL *ssl, CONTROL_REQUEST *request, OSI_DB *db )
{
    if( ( request != NULL )  && ( ssl != NULL ) )
    {
        int connection_socket = 0;
        
        int result = 0;
        osi_uint16 type;

        MESSAGE message;
        fd_set read_set;

        OSI_ERROR *error;

        int message_read_errors = 0;
        osi_uint64 record_type;

        SCAN_RECORD *record   = NULL;
        OSI_SCAN_RESULTS *results = NULL;

        connection_socket = SSL_get_fd( ssl );
        result = osi_set_socket_non_blocking( connection_socket );

        /* listen for entire data sequence. */

        for(;;)
        {
            int sresult;

            FD_ZERO( &read_set );
            FD_SET( connection_socket, &read_set );

            sresult = select( ( connection_socket + 1 ), &read_set,
                               NULL, NULL, NULL );

            if( ( sresult < 0 ) && ( errno == EINTR ) )
            {
                continue;
            }

            if( FD_ISSET( connection_socket, &read_set ) )
            {
                int record_size;
                int message_size;

                unsigned char buffer[MAX_SCAN_RECORD_LENGTH];

                result = osi_ssl_read_message( &message, ssl );

                if( result != MESSAGE_OK )
                {
                    message_read_errors++;

                    log_error( LOG_MEDIUM, request->host,
                               "scan-data message read error: %s",
                               osi_get_name_for_error( result ) );

                    if( message_read_errors >= MAX_SCAN_DATA_ERRORS )
                    {
                        OSI_ERROR final_error;
                        final_error.type = OSI_ERROR_DB_RETRIEVING;
                        osi_strlcpy( final_error.message,
                       "too many errors receiving scan data, aborting receive.",                        sizeof( final_error.message ) );

                        log_error( LOG_MEDIUM, request->host,
                    "max receive errors: (%d), aborting recieve of scan-data.",
                                   MAX_SCAN_DATA_ERRORS );

                        result = osi_scan_db_store_error( db, &final_error );

                        break;
                    }
                }

                /* no error, process this message. */

                type = GET_MESSAGE_TYPE( ( (MESSAGE *)&message ) );

                switch( (int)type )
                {
                    case MESSAGE_TYPE_SCAN_DATA:

                        record_size = (int)GET_MESSAGE_LENGTH(
                                                 ( (MESSAGE *)&message ) );

                        if( ( record_size > 0 ) &&
                            ( record_size < sizeof( buffer ) ) )
                        {
                            unsigned char *raw;
                            SCAN_RECORD *record = (SCAN_RECORD *)buffer;

                            raw = MESSAGE_TO_TYPE( &message, unsigned char * );

                            unpack_scan_record( record, raw, record_size );
                            unwrap_scan_record( record );

                            result = osi_scan_db_store_record( db, record );
                        }

                        break;

                    case MESSAGE_TYPE_SCAN_DATA_FIRST:

                        log_info( LOG_HIGH, request->host,
                                 "received first scan-data message." );

                        /* this message contains only the type of records. */

                        message_size = (int)GET_MESSAGE_LENGTH( 
                                                    ( (MESSAGE *)&message ) );
                        
                        /* make sure we're given the 64 bit type identifier. */
                        
                        if( message_size = sizeof( record_type ) )
                        {
                            memcpy( &record_type, message.data, message_size );
                            record_type = NTOHLL( record_type );

                            osi_scan_db_store_header_item( db,
                                          OSI_DB_HEADER_ITEM_RECORD_TYPE,
                                          &record_type,
                                          sizeof( record_type ) );
                        }
                        
                        else
                        {
                            log_error( LOG_MEDIUM, request->host,
                       "scan-data-first message doesn't contain record type!" );
                        }

                        break;

                    case MESSAGE_TYPE_SCAN_DATA_LAST:

                        log_info( LOG_HIGH, request->host,
                                  "received last scan data message." );

                        results = MESSAGE_TO_TYPE( &message,
                                                   OSI_SCAN_RESULTS * );

                        if( results != NULL )
                        {
                            osi_uint64 complete = 1;
                            unwrap_scan_results( results );

                            osi_scan_db_store_header_item( db,
                                            OSI_DB_HEADER_ITEM_SCAN_RESULTS,
                                            results,
                                            sizeof( OSI_SCAN_RESULTS ) );

                            osi_scan_db_store_header_item( db,
                                            OSI_DB_HEADER_ITEM_COMPLETE,
                                            &complete,
                                            sizeof( complete ) );
                        }

                        else
                        {
                            log_error( LOG_MEDIUM, request->host,
                                       "failed to receive scan-data results." );
                        }

                        return;

                        break;

                    case MESSAGE_TYPE_ERROR:

                        error = MESSAGE_TO_TYPE( &message, OSI_ERROR * );
                        unwrap_error( error );
                        result = osi_scan_db_store_error( db, error );

                        if( result != OSI_DB_OK )
                        {
                            log_error( LOG_MEDIUM, request->host,
                                       "unable to store error in database." );
                        }

                        break;

                    default:

                        log_error( LOG_MEDIUM, request->host,
                           "unrecognized message type in scan-data sequence." );

                        break;
                }
            }

        }   /* end for */
    }
}


/******************************************************************************
**
**    Function: generate_session_key
**
**    Purpose:  generate a random sequence of data and place them into
**		        the specified buffer.  generate the bytes specified by
**		        keysize, return true if the buffer contains that many
**		        random bytes, false otherwise.
**
******************************************************************************/

osi_bool generate_session_key( int keysize, unsigned char *buffer,
                               int buffer_size )
{
    osi_bool result = FALSE;

    if( ( buffer != NULL ) && ( buffer_size > 0 ) )
    {
        if( keysize > 0 )
        {
            if( RAND_bytes( buffer, buffer_size ) )
            {
                result =  TRUE;
            }
        }
    }

    return result;
}

/******************************************************************************
**
**    Function: generate_session_key_hash
**
**    Purpose:  generate a SHA1 hash of the data specified in key, and
**              store the checksum in the buffer specified.
**
******************************************************************************/

osi_bool generate_session_key_hash( unsigned char *key, int keysize,
                                    unsigned char *buffer, int buffer_size )
{
    osi_bool result = FALSE;

    if( ( key != NULL ) && ( buffer != NULL ) )
    {
        if( ( keysize > 0 ) && ( buffer_size > SHA_DIGEST_LENGTH ) )
        {
            SHA_CTX context;
            unsigned char digest[SHA_DIGEST_LENGTH];

            int index;
            char checksum[41];

            SHA_Init( &context );
            SHA_Update( &context, key, (unsigned long)keysize );
            SHA_Final( &( digest[0] ), &context );

            for ( index = 0; index < SHA_DIGEST_LENGTH; index++ )
            {
                osi_snprintf( &checksum[index * 2], 3, "%02X", digest[index] );
            }

            checksum[40] = '\0';
            osi_strlcpy( buffer, checksum, buffer_size );

            result = TRUE;
        }
    }

    return result;
}


