
/******************************************************************************
**
**  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_auth.c
**  Date:    June 3, 2002
**
**  Author:  Brian Wotring
**  Purpose: handle interactions with the user authentication database
**           for this management daemon.
**
******************************************************************************/

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

#include "md_hosts.h"
#include "md_log.h"
#include "md_config.h"
#include "md_compare.h"
#include "md_auth.h"

#include "common.h"
#include "logging.h"

extern char root_path[MAX_PATH_LENGTH];
extern char auth_db_path[MAX_PATH_LENGTH];

extern int user_pipe[2];

static osi_list auths = NULL;

void load_auth_database()
{
    read_auths();
}

void unload_auth_database()
{
    list_destroy_with_function( auths,(void (*)(void *))&osi_free );
    auths = NULL;    
}

void reload_auth_database()
{
    read_auths();
}

void signal_auths_updated()
{   
    osi_write( user_pipe[1], "x", 1 );
}

osi_bool create_auth_db( const char *auth_db_path )
{
    int result;
    OSI_DB db;

    if( auth_db_path == NULL )
    {
        return FALSE;
    }

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

    result = osi_db_create( &db );

    if( result != OSI_DB_OK )
    {
        return FALSE;
    }

    /* db created, now open it and create and admin account */
    /* with an empty password.                              */

    if( set_auth_entry( ADMIN_USER_NAME, "" ) == FALSE )
    {
        return FALSE;
    }

    return TRUE;
}


osi_bool authenticate_auth_context( OSI_AUTH_CONTEXT *auth_context )
{
    osi_bool result = FALSE;
    osi_list temp;

    if( auth_context == NULL )
    {
        return FALSE;
    }

    if( auths == NULL )
    {
        log_warning( LOG_LOW, NULL, "auth db not loaded!" );
        return FALSE;
    }

    temp = list_get_first_node( auths );

    /* loop through each auth and heck for a user/pass match. */

    while( temp )
    {
        OSI_AUTH_CONTEXT *auth = (OSI_AUTH_CONTEXT *)temp->data;

        if( auth != NULL )
        {
            if( strcmp( auth_context->auth_user, auth->auth_user ) == 0 )
            {
                /* compare pass hash. */
    
                if( strcmp( auth_context->auth_pass, auth->auth_pass ) == 0 )
                {

                    log_info( LOG_HIGH, NULL, "athenticated user: %s",
                              auth->auth_user );

                    result = TRUE;
                    break;
                }

                else
                {
                    log_error( LOG_HIGH, NULL,"user authentication failure: %s",
                               auth->auth_user );
                }
            }
        } 

        temp = list_get_next_node( temp );
    }

    return result;
}

void read_auths()
{
    int result;
    int result_size;
    osi_list temp_list = NULL;

    OSI_DB db;
    OSI_AUTH_CONTEXT *auth;
    OSI_AUTH_CONTEXT temp_auth;

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

    if( osi_db_open( &db, OSI_DB_READ ) != OSI_DB_OK )
    {
        return;
    }

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

    if( result != OSI_DB_OK )
    {
        osi_db_close( &db );
        return;
    }

    temp_list = list_new();

    while( result == OSI_DB_OK )
    {
        auth = osi_malloc( sizeof( OSI_AUTH_CONTEXT ) );
        memset( auth, 0, sizeof( OSI_AUTH_CONTEXT ) );

        osi_strlcpy( auth->auth_user, temp_auth.auth_user,
                     sizeof( auth->auth_user ) );

        osi_strlcpy( auth->auth_pass, temp_auth.auth_pass,
                     sizeof( auth->auth_pass ) );

        /* check for empty passwords and log warning. */

        if( strlen( auth->auth_pass ) == 0 )
        {
            log_warning( LOG_LOW, NULL, "empty password for user: %s",
                         auth->auth_user );
        }

        list_add( temp_list, auth );
        result = osi_db_get_next_record( &db, &temp_auth, sizeof( temp_auth ),
                                         &result_size );
    }

    osi_db_close( &db );

    /* now switch over to the new auth list. */

    unload_auth_database();
    auths = temp_list;    
}


osi_bool set_auth_entry( const char *user, const char *pass )
{
    int result;

    OSI_DB db;
    OSI_AUTH_CONTEXT auth;

    osi_bool auth_set = FALSE;

    if( ( user == NULL ) || ( pass == NULL ) )
    {
        return FALSE;
    }

    if( auth_db_path == NULL )
    {
        return FALSE;
    }

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

    /* open the admin db with write privs. */

    result = osi_db_open( &db, OSI_DB_WRITE );

    if( result != OSI_DB_OK )
    {
        log_error( LOG_HIGH, NULL, "unable to open auth database." );
        return FALSE;
    }

    osi_strlcpy( auth.auth_user, user, sizeof( auth.auth_user ) );
    osi_strlcpy( auth.auth_pass, pass, sizeof( auth.auth_pass ) );

    result = osi_db_store_data_with_key(  db.records, (void *)(&auth),
                                          sizeof( auth ), auth.auth_user );

    if( result == OSI_DB_OK )
    {
        log_info( LOG_HIGH, NULL, "saved user: %s.", user );
        auth_set = TRUE;
    }

    else
    {
        log_error( LOG_HIGH, NULL, "failed to save user: %s", user );
        auth_set = FALSE;
    }

    osi_db_close( &db );

    if( auth_set )
    {
        signal_auths_updated();
    }

    return auth_set;
}

osi_bool del_auth_entry( const char *user )
{
    osi_bool result = FALSE;
    OSI_DB db;

    if( user == NULL )
    {
        return FALSE;
    }

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

    if( osi_db_open( &db, OSI_DB_WRITE ) != OSI_DB_OK )
    {
        log_error( LOG_HIGH, NULL, "unable to open auth database." );
        return FALSE;
    }

    if( osi_db_delete_record_with_name( &db, (char *)user ) == OSI_DB_OK )
    {
        result = TRUE;
        log_info( LOG_HIGH, NULL, "deleted user: %s.", user );
    }

    osi_db_close( &db );

    if( result )
    {
        signal_auths_updated();
    }

    return result;
}

osi_bool auth_entry_exists( const char *user )
{
    osi_bool result = FALSE;
    osi_list temp;

    if( user == NULL )
    {
        return FALSE;
    }

    if( auths == NULL )
    {
        log_warning( LOG_LOW, NULL, "auth db not loaded!" );
        return FALSE;
    }

    temp = list_get_first_node( auths );

    /* loop through each auth and heck for a user/pass match. */

    while( temp )
    {
        OSI_AUTH_CONTEXT *auth = (OSI_AUTH_CONTEXT *)temp->data;

        if( auth != NULL )
        {
            if( strcmp( user, auth->auth_user ) == 0 )
            {
                /* user exists. */

                result = TRUE;
                break;
            }
        }

        temp = list_get_next_node( temp );
    }

    return result;
}

osi_list get_auth_list()
{
    int result;
    int result_size;

    osi_list auths = NULL;

    OSI_DB db;
    OSI_AUTH_CONTEXT auth;

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

    if( osi_db_open( &db, OSI_DB_READ ) != OSI_DB_OK )
    {
        return NULL;
    }

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

    if( result != OSI_DB_OK )
    {
        osi_db_close( &db );
        return NULL;
    }

    auths = list_new();
  
    if( auths == NULL )
    {
        osi_db_close( &db );
        return NULL;
    }

    while( result == OSI_DB_OK )
    {
        OSI_AUTH_CONTEXT *a = osi_malloc( sizeof( OSI_AUTH_CONTEXT ) );
        memset( a, 0, sizeof( OSI_AUTH_CONTEXT ) );

        /* we only copy the user, no passwords. */

        osi_strlcpy( a->auth_user, auth.auth_user, sizeof( a->auth_user ) );

        list_add( auths, a );
        result = osi_db_get_next_record( &db, &auth, sizeof( auth ),
                                         &result_size );
    }

    return auths;
}

