/*
 * Copyright 2014 Cloud Linux Zug GmbH
 *
 * Licensed under CLOUD LINUX LICENSE AGREEMENT
 * http://cloudlinux.com/docs/LICENSE.TXT
 *
 * The part the support library for lsapi & proxy_lsapi Apache modules
 * author Alexander Demeshko <ademeshko@cloudlinux.com>
 *
 */

#include <dlfcn.h>
#include <stdint.h>
#include <stdlib.h>

#include "lve.h"
 
static void *lib_handle;

static int (*lve_enter_flags_sym)();
static int (*lve_jail_sym)();
static int (*lve_exit_sym)();
static int (*destroy_lve_sym)();

static void *struct_liblve;
static uint32_t cookie;

static int lve_entered = 0;

int dl_init_lve(void) {
    lib_handle = dlopen("liblve.so.0", RTLD_LAZY);
    if(!lib_handle) {
        return 0;
    }
    
    void* (*init_lve_sym)() = dlsym(lib_handle, "init_lve");
    if(!init_lve_sym) {
        return -1;
    }
    
    lve_enter_flags_sym = dlsym(lib_handle, "lve_enter_flags");
    if(!lve_enter_flags_sym) {
        return -1;
    }
    
    lve_jail_sym = dlsym(lib_handle, "lve_jail");
    if(!lve_jail_sym) {
        return -1;
    }
    
    lve_exit_sym = dlsym(lib_handle, "lve_exit");
    if(!lve_exit_sym) {
        return -1;
    }
    
    destroy_lve_sym = dlsym(lib_handle, "destroy_lve");
    if(!destroy_lve_sym) {
        return -1;
    }
    
/*
struct liblve *init_lve(liblve_alloc alloc, liblve_free free);
*/
    struct_liblve = init_lve_sym(malloc, free);
    if(!struct_liblve) {
        return -1;
    }
    
    return 1;
}

int dl_enter_lve(pid_t uid) {
    // LVE-less configuration, it's ok
    if(!lib_handle)
        return 0;
    
    if(!struct_liblve || !lve_enter_flags_sym)
        return -1;
    
/*
int lve_enter_flags(struct liblve *lve,
		    uint32_t lve_id, uint32_t *cookie, enum liblve_enter_flags flags);
*/
    int rc = lve_enter_flags_sym(struct_liblve, uid, &cookie, 0);
    if(rc != 0) {
        return -1;
    }
    
    lve_entered = 1;
    
    return 0;
}


int dl_jail_lve(struct passwd *pw) {
    char error_msg[8192];

    // LVE-less configuration, it's ok
    if(!lib_handle)
        return 0;
    
    if(!struct_liblve || !lve_jail_sym)
        return -1;
    
/*
int lve_jail(struct passwd *pw, char * error_str);
*/
    int rc = lve_jail_sym(pw, error_msg);
    if(rc < 0) {
        return -1;
    }
    
    return 0;
}


int dl_exit_lve(void) {
    // LVE-less configuration, it's ok
    if(!lib_handle)
        return 0;
    
    if(!struct_liblve || !lve_exit_sym)
        return -1;
        
/*
int lve_exit(struct liblve *lve, uint32_t *cookie);
*/
    int rc = lve_exit_sym(struct_liblve, &cookie);
    if(rc < 0) {
        return -1;
    }
    
    lve_entered = 0;
    
    return 0;
}


int dl_destroy_lve(void) {
    // LVE-less configuration, it's ok
    if(!lib_handle)
        return 0;
    
    if(!struct_liblve || !destroy_lve_sym)
        return -1;
        
/*
int destroy_lve(struct liblve *lve);
*/
    int rc = destroy_lve_sym(struct_liblve);
    struct_liblve = NULL;
    lve_entered = 0;
    
    if(rc < 0)
        return -1;
    
    return 0;
}


void dl_clean_all_lve(void) {
    // LVE-less configuration, it's ok
    if(!lib_handle)
        return;
        
    if(lve_entered) {
        dl_exit_lve();
        lve_entered = 0;
    }
    
    dl_destroy_lve();
}
