/*************************************************** */
/* Rule Set Based Access Control                     */
/* Implementation of RC data structures              */
/* Author and (C) 1999-2002: Amon Ott <ao@rsbac.org> */
/*                                                   */
/* Last modified: 28/Feb/2002                        */
/*************************************************** */

#include <linux/string.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <rsbac/aci_data_structures.h>
#include <rsbac/rc_types.h>
#include <rsbac/rc_data_structures.h>
#include <rsbac/error.h>
#include <rsbac/helpers.h>
#include <rsbac/fs.h>
#include <rsbac/adf.h>
#include <rsbac/acl.h>
#include <rsbac/getname.h>
#include <rsbac/rc_getname.h>
#include <rsbac/proc_fs.h>
#include <rsbac/rkmem.h>
#include <linux/smp_lock.h>

#ifdef CONFIG_RSBAC_RC_NR_ROLES
#endif

/************************************************************************** */
/*                          Global Variables                                */
/************************************************************************** */

/* The following global variables are needed for access to RC data.         */

static rsbac_list_handle_t role_handle = NULL;
static rsbac_list_handle_t role_rc_handle = NULL;
static rsbac_list_handle_t role_adr_handle = NULL;
static rsbac_list_handle_t role_asr_handle = NULL;
static rsbac_list_handle_t role_tcfd_handle = NULL;
static rsbac_list_handle_t role_tcdv_handle = NULL;
static rsbac_list_handle_t role_tcpr_handle = NULL;
static rsbac_list_handle_t role_tcip_handle = NULL;
static rsbac_list_handle_t role_tcsc_handle = NULL;
static rsbac_list_handle_t role_tcnd_handle = NULL;
static rsbac_list_handle_t role_tcnt_handle = NULL;
static rsbac_list_handle_t role_tcno_handle = NULL;

static rsbac_list_handle_t type_fd_handle = NULL;
static rsbac_list_handle_t type_dev_handle = NULL;
static rsbac_list_handle_t type_ipc_handle = NULL;
static rsbac_list_handle_t type_process_handle = NULL;
static rsbac_list_handle_t type_netdev_handle = NULL;
static rsbac_list_handle_t type_nettemp_handle = NULL;
static rsbac_list_handle_t type_netobj_handle = NULL;

/**************************************************/
/*       Declarations of external functions       */
/**************************************************/

/**************************************************/
/*       Declarations of internal functions       */
/**************************************************/

/* As some function use later defined functions, we declare those here.   */

/************************************************* */
/*               Internal Help functions           */
/************************************************* */

/************************************************* */
/*               proc functions                    */
/************************************************* */

#if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
static int
stats_rc_proc_info(char *buffer, char **start, off_t offset, int length, int dummy)
#else
static int
stats_rc_proc_info(char *buffer, char **start, off_t offset, int length)
#endif
{
    union rsbac_target_id_t rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;

    u_int len = 0;
    off_t pos   = 0;
    off_t begin = 0;

    if (!rsbac_is_initialized)
      {
        printk(KERN_WARNING "stats_rc_proc_info(): RSBAC not initialized\n");
        return(-RSBAC_ENOTINITIALIZED);
      }
#ifdef CONFIG_RSBAC_DEBUG
    if (rsbac_debug_aef_rc)
      printk(KERN_DEBUG "stats_rc_proc_info(): calling ADF\n");
#endif
    rsbac_target_id.scd = ST_rsbac;
    rsbac_attribute_value.dummy = 0;
    if (!rsbac_adf_request(R_GET_STATUS_DATA,
                           current->pid,
                           T_SCD,
                           rsbac_target_id,
                           A_none,
                           rsbac_attribute_value))
      {
        return -EPERM;
      }

    len += sprintf(buffer, "RC Status\n---------\n");
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    len += sprintf(buffer + len, "Role entry size is %u, %lu entries used\n",
           sizeof(struct rsbac_rc_role_entry_t),
           rsbac_list_count(role_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    len += sprintf(buffer + len, "Used type entries: fd: %lu, dev: %lu, ipc: %lu, process: %lu, netdev: %lu, nettemp: %lu, netobj: %lu\n",
                   rsbac_list_count(type_fd_handle),
                   rsbac_list_count(type_dev_handle),
                   rsbac_list_count(type_ipc_handle),
                   rsbac_list_count(type_process_handle),
                   rsbac_list_count(type_netdev_handle),
                   rsbac_list_count(type_nettemp_handle),
                   rsbac_list_count(type_netobj_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }

out:
  *start = buffer + (offset - begin);
  len -= (offset - begin);
  
  if (len > length)
    len = length;
  return len;
}

#endif /* CONFIG_PROC_FS && CONFIG_RSBAC_PROC */

/************************************************* */
/*               Init functions                    */
/************************************************* */

/* All functions return 0, if no error occurred, and a negative error code  */
/* otherwise. The error codes are defined in rsbac/error.h.                 */

/************************************************************************** */
/* Initialization of all RC data structures. After this call, all RC data   */
/* is kept in memory for performance reasons, but is written to disk on     */
/* every change.    */

/* There can be no access to aci data structures before init.               */

static void __init registration_error(int err, char * listname)
  {
    if(err)
      {
        char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN);

        if(tmp)
          {
            printk(KERN_WARNING
                   "rsbac_init_rc(): Registering RC %s list failed with error %s\n",
                   listname,
                   get_error_name(tmp, err));
            rsbac_kfree(tmp);
          }
      }
  }

int __init rsbac_init_rc(void)
  {
    int  err = 0;
    struct proc_dir_entry * tmp_entry_p;
    struct rsbac_list_lol_info_t lol_info;
    struct rsbac_list_info_t     list_info;
    rsbac_rc_rights_vector_t     def_tc = RSBAC_RC_DEFAULT_RIGHTS_VECTOR;

    if (rsbac_is_initialized())
      {
        printk(KERN_WARNING "rsbac_init_rc(): RSBAC already initialized\n");
        return(-RSBAC_EREINIT);
      }

    /* init data structures */
    printk(KERN_INFO "rsbac_init_rc(): Initializing RSBAC: RC subsystem\n");
#ifdef CONFIG_RSBAC_DEBUG
    if(rsbac_debug_stack)
      {
        unsigned long * n = (unsigned long *) (current+1);

        while (!*n)
          n++;
 	printk(KERN_DEBUG "rsbac_init_rc: free stack: %lu\n",
	       (unsigned long) n - (unsigned long)(current+1));
      }
#endif

    list_info.version = RSBAC_RC_ROLE_LIST_VERSION;
    list_info.key = RSBAC_RC_LIST_KEY;
    list_info.desc_size = sizeof(rsbac_rc_role_id_t);
    list_info.data_size = sizeof(struct rsbac_rc_role_entry_t);
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &role_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_RC_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              rsbac_list_compare_u32,
                              NULL,
                              NULL,
                              RSBAC_RC_ROLE_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "role");
      }

    lol_info.version = RSBAC_RC_ROLE_RC_LIST_VERSION;
    lol_info.key = RSBAC_RC_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.subdata_size = 0;
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &role_rc_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_RC_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST | RSBAC_LIST_DEF_DATA,
                                  rsbac_list_compare_u32,
                                  rsbac_list_compare_u32,
                                  NULL,
                                  NULL,
                                  NULL,
                                  NULL,
                                  RSBAC_RC_ROLE_RC_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "role compatibilities");
      }
    lol_info.version = RSBAC_RC_ROLE_ADR_LIST_VERSION;
    lol_info.key = RSBAC_RC_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.subdata_size = 0;
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &role_adr_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_RC_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST | RSBAC_LIST_DEF_DATA,
                                  rsbac_list_compare_u32,
                                  rsbac_list_compare_u32,
                                  NULL,
                                  NULL,
                                  NULL,
                                  NULL,
                                  RSBAC_RC_ROLE_ADR_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "admin roles");
      }
    lol_info.version = RSBAC_RC_ROLE_ASR_LIST_VERSION;
    lol_info.key = RSBAC_RC_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.subdata_size = 0;
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &role_asr_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_RC_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST | RSBAC_LIST_DEF_DATA,
                                  rsbac_list_compare_u32,
                                  rsbac_list_compare_u32,
                                  NULL,
                                  NULL,
                                  NULL,
                                  NULL,
                                  RSBAC_RC_ROLE_ASR_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "assign roles");
      }
    lol_info.version = RSBAC_RC_ROLE_TCFD_LIST_VERSION;
    lol_info.key = RSBAC_RC_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t);
    lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t);
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &role_tcfd_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_RC_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST |
                                  RSBAC_LIST_DEF_DATA | RSBAC_LIST_DEF_SUBDATA,
                                  rsbac_list_compare_u32,
                                  rsbac_list_compare_u32,
                                  NULL,
                                  NULL,
                                  NULL,
                                  &def_tc,
                                  RSBAC_RC_ROLE_TCFD_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "Role FD type compatibilities");
      }
    lol_info.version = RSBAC_RC_ROLE_TCDV_LIST_VERSION;
    lol_info.key = RSBAC_RC_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t);
    lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t);
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &role_tcdv_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_RC_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST |
                                  RSBAC_LIST_DEF_DATA | RSBAC_LIST_DEF_SUBDATA,
                                  rsbac_list_compare_u32,
                                  rsbac_list_compare_u32,
                                  NULL,
                                  NULL,
                                  NULL,
                                  &def_tc,
                                  RSBAC_RC_ROLE_TCDV_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "Role DEV type compatibilities");
      }
    lol_info.version = RSBAC_RC_ROLE_TCPR_LIST_VERSION;
    lol_info.key = RSBAC_RC_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t);
    lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t);
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &role_tcpr_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_RC_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST |
                                  RSBAC_LIST_DEF_DATA | RSBAC_LIST_DEF_SUBDATA,
                                  rsbac_list_compare_u32,
                                  rsbac_list_compare_u32,
                                  NULL,
                                  NULL,
                                  NULL,
                                  &def_tc,
                                  RSBAC_RC_ROLE_TCPR_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "Role Process type compatibilities");
      }
    lol_info.version = RSBAC_RC_ROLE_TCIP_LIST_VERSION;
    lol_info.key = RSBAC_RC_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t);
    lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t);
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &role_tcip_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_RC_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST |
                                  RSBAC_LIST_DEF_DATA | RSBAC_LIST_DEF_SUBDATA,
                                  rsbac_list_compare_u32,
                                  rsbac_list_compare_u32,
                                  NULL,
                                  NULL,
                                  NULL,
                                  &def_tc,
                                  RSBAC_RC_ROLE_TCIP_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "Role IPC type compatibilities");
      }
    lol_info.version = RSBAC_RC_ROLE_TCSC_LIST_VERSION;
    lol_info.key = RSBAC_RC_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t);
    lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t);
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &role_tcsc_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_RC_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST |
                                  RSBAC_LIST_DEF_DATA | RSBAC_LIST_DEF_SUBDATA,
                                  rsbac_list_compare_u32,
                                  rsbac_list_compare_u32,
                                  NULL,
                                  NULL,
                                  NULL,
                                  &def_tc,
                                  RSBAC_RC_ROLE_TCSC_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "Role SCD type compatibilities");
      }
    lol_info.version = RSBAC_RC_ROLE_TCND_LIST_VERSION;
    lol_info.key = RSBAC_RC_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t);
    lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t);
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &role_tcnd_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_RC_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST |
                                  RSBAC_LIST_DEF_DATA | RSBAC_LIST_DEF_SUBDATA,
                                  rsbac_list_compare_u32,
                                  rsbac_list_compare_u32,
                                  NULL,
                                  NULL,
                                  NULL,
                                  &def_tc,
                                  RSBAC_RC_ROLE_TCND_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "Role NETDEV type compatibilities");
      }
    lol_info.version = RSBAC_RC_ROLE_TCNT_LIST_VERSION;
    lol_info.key = RSBAC_RC_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t);
    lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t);
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &role_tcnt_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_RC_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST |
                                  RSBAC_LIST_DEF_DATA | RSBAC_LIST_DEF_SUBDATA,
                                  rsbac_list_compare_u32,
                                  rsbac_list_compare_u32,
                                  NULL,
                                  NULL,
                                  NULL,
                                  &def_tc,
                                  RSBAC_RC_ROLE_TCNT_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "Role NETTEMP type compatibilities");
      }
    lol_info.version = RSBAC_RC_ROLE_TCNO_LIST_VERSION;
    lol_info.key = RSBAC_RC_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_rc_role_id_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t);
    lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t);
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &role_tcno_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_RC_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST |
                                  RSBAC_LIST_DEF_DATA | RSBAC_LIST_DEF_SUBDATA,
                                  rsbac_list_compare_u32,
                                  rsbac_list_compare_u32,
                                  NULL,
                                  NULL,
                                  NULL,
                                  &def_tc,
                                  RSBAC_RC_ROLE_TCNO_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "Role NETOBJ type compatibilities");
      }

    /* Create default role settings, if none there */
    if(!rsbac_list_count(role_handle))
      {
        rsbac_rc_role_id_t role;
        rsbac_rc_type_id_t type;
        rsbac_rc_rights_vector_t rights;
        struct rsbac_rc_role_entry_t gen_entry = RSBAC_RC_GENERAL_ROLE_ENTRY;
        struct rsbac_rc_role_entry_t ra_entry = RSBAC_RC_ROLE_ADMIN_ROLE_ENTRY;
        struct rsbac_rc_role_entry_t sa_entry = RSBAC_RC_SYSTEM_ADMIN_ROLE_ENTRY;
        char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN);

        if(tmp)
          {
            printk(KERN_WARNING
                   "rsbac_init_rc(): no RC roles read, generating default role entries!\n");
            rsbac_kfree(tmp);
          }

        role = RSBAC_RC_GENERAL_ROLE;
        if(!rsbac_list_add(role_handle, &role, &gen_entry))
          {
            if(!rsbac_list_lol_add(role_tcfd_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = RSBAC_READ_WRITE_REQUEST_VECTOR & RSBAC_FD_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcfd_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcdv_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = RSBAC_READ_WRITE_REQUEST_VECTOR & RSBAC_DEV_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcdv_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcpr_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = RSBAC_READ_WRITE_REQUEST_VECTOR & RSBAC_PROCESS_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcpr_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcip_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = RSBAC_READ_WRITE_REQUEST_VECTOR & RSBAC_IPC_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcip_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcnd_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = RSBAC_READ_WRITE_REQUEST_VECTOR & RSBAC_NETDEV_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcnd_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcno_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = RSBAC_READ_WRITE_REQUEST_VECTOR & RSBAC_NETOBJ_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcno_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcsc_handle, &role, NULL))
              {
                #ifdef CONFIG_RSBAC_USER_MOD_IOPERM
                type = ST_ioports;
                rights = RSBAC_RC_RIGHTS_VECTOR(R_MODIFY_PERMISSIONS_DATA);
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                #endif
                type = ST_rlimit;
                rights = -1;
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                type = ST_other;
                rights = RSBAC_RC_RIGHTS_VECTOR(R_MAP_EXEC);
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                type = ST_network;
                rights = RSBAC_RC_RIGHTS_VECTOR(R_GET_STATUS_DATA);
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
              }
          }
        role = RSBAC_RC_ROLE_ADMIN_ROLE;
        if(!rsbac_list_add(role_handle, &role, &ra_entry))
          {
            if(!rsbac_list_lol_add(role_tcfd_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_FD_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcfd_handle, &role, &type, &rights);
                type = RSBAC_RC_SEC_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_FD_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcfd_handle, &role, &type, &rights);
                type = RSBAC_RC_SYS_TYPE;
                rights = RSBAC_READ_REQUEST_VECTOR & RSBAC_FD_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcfd_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcdv_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_DEV_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcdv_handle, &role, &type, &rights);
                type = RSBAC_RC_SEC_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_DEV_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcdv_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcpr_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_PROCESS_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcpr_handle, &role, &type, &rights);
                type = RSBAC_RC_SEC_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_PROCESS_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcpr_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcip_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_IPC_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcip_handle, &role, &type, &rights);
                type = RSBAC_RC_SEC_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_IPC_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcip_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcnd_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_REQUEST_VECTOR(R_GET_STATUS_DATA) | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_NETDEV_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcnd_handle, &role, &type, &rights);
                type = RSBAC_RC_SEC_TYPE;
                rsbac_list_lol_subadd(role_tcnd_handle, &role, &type, &rights);
                type = RSBAC_RC_SYS_TYPE;
                rsbac_list_lol_subadd(role_tcnd_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcnt_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_NETTEMP_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcnt_handle, &role, &type, &rights);
                type = RSBAC_RC_SEC_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_NETTEMP_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcnt_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcno_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR) & RSBAC_NETOBJ_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcno_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcsc_handle, &role, NULL))
              {
                #ifdef CONFIG_RSBAC_USER_MOD_IOPERM
                type = ST_ioports;
                rights = RSBAC_RC_RIGHTS_VECTOR(R_MODIFY_PERMISSIONS_DATA);
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                #endif
                type = ST_rlimit;
                rights = -1;
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                type = ST_rsbac;
                rights = -1;
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                type = ST_rsbaclog;
                rights = -1;
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                type = ST_other;
                rights =  RSBAC_RC_RIGHTS_VECTOR(R_MAP_EXEC)
                        | RSBAC_RC_RIGHTS_VECTOR(R_MODIFY_PERMISSIONS_DATA)
                        | RSBAC_RC_RIGHTS_VECTOR(R_SWITCH_LOG)
                        | RSBAC_RC_RIGHTS_VECTOR(R_SWITCH_MODULE);

                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                type = ST_network;
                rights = RSBAC_RC_RIGHTS_VECTOR(R_GET_STATUS_DATA);
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                type = ST_firewall;
                rights = RSBAC_RC_RIGHTS_VECTOR(R_GET_STATUS_DATA);
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                type = RST_auth_administration;
                rights = -1;
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
              }
          }
        role = RSBAC_RC_SYSTEM_ADMIN_ROLE;
        if(!rsbac_list_add(role_handle, &role, &sa_entry))
          {
            if(!rsbac_list_lol_add(role_tcfd_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR) & RSBAC_FD_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcfd_handle, &role, &type, &rights);
                type = RSBAC_RC_SYS_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR) & RSBAC_FD_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcfd_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcdv_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR) & RSBAC_DEV_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcdv_handle, &role, &type, &rights);
                type = RSBAC_RC_SYS_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR) & RSBAC_DEV_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcdv_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcpr_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR) & RSBAC_PROCESS_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcpr_handle, &role, &type, &rights);
                type = RSBAC_RC_SYS_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR) & RSBAC_PROCESS_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcpr_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcip_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR) & RSBAC_IPC_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcip_handle, &role, &type, &rights);
                type = RSBAC_RC_SYS_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR) & RSBAC_IPC_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcip_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcnd_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR) & RSBAC_NETDEV_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcnd_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcnt_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_REQUEST_VECTOR) & RSBAC_NETTEMP_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcnt_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcno_handle, &role, NULL))
              {
                type = RSBAC_RC_GENERAL_TYPE;
                rights = (RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR) & RSBAC_NETOBJ_REQUEST_VECTOR;
                rsbac_list_lol_subadd(role_tcno_handle, &role, &type, &rights);
              }
            if(!rsbac_list_lol_add(role_tcsc_handle, &role, NULL))
              {
                rights = -1;
                for(type = ST_time_strucs; type <= ST_rsbac; type++)
                  {
                    rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                  }
                for(type = ST_kmem; type <= ST_firewall; type++)
                  {
                    rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
                  }
                type = ST_other;
                rights =   RSBAC_RC_RIGHTS_VECTOR(R_ADD_TO_KERNEL)
                         | RSBAC_RC_RIGHTS_VECTOR(R_MAP_EXEC)
                         | RSBAC_RC_RIGHTS_VECTOR(R_MODIFY_SYSTEM_DATA)
                         | RSBAC_RC_RIGHTS_VECTOR(R_MOUNT)
                         | RSBAC_RC_RIGHTS_VECTOR(R_REMOVE_FROM_KERNEL)
                         | RSBAC_RC_RIGHTS_VECTOR(R_UMOUNT)
                         | RSBAC_RC_RIGHTS_VECTOR(R_SHUTDOWN);
                rsbac_list_lol_subadd(role_tcsc_handle, &role, &type, &rights);
              }
          }
      }

    list_info.version = RSBAC_RC_TYPE_FD_LIST_VERSION;
    list_info.key = RSBAC_RC_LIST_KEY;
    list_info.desc_size = sizeof(rsbac_rc_type_id_t);
    list_info.data_size = sizeof(struct rsbac_rc_type_fd_entry_t);
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &type_fd_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_RC_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              rsbac_list_compare_u32,
                              NULL,
                              NULL,
                              RSBAC_RC_TYPE_FD_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "type FD");
      }
    if(!rsbac_list_count(type_fd_handle))
      {
        rsbac_rc_type_id_t type;
        struct rsbac_rc_type_fd_entry_t entry;

        type = RSBAC_RC_GENERAL_TYPE;
        strcpy(entry.name, "General FD");
        entry.need_secdel = 0;
        rsbac_list_add(type_fd_handle, &type, &entry);
        type = RSBAC_RC_SEC_TYPE;
        strcpy(entry.name, "Security FD");
        entry.need_secdel = 0;
        rsbac_list_add(type_fd_handle, &type, &entry);
        type = RSBAC_RC_SYS_TYPE;
        strcpy(entry.name, "System FD");
        entry.need_secdel = 0;
        rsbac_list_add(type_fd_handle, &type, &entry);
      }
    list_info.version = RSBAC_RC_TYPE_DEV_LIST_VERSION;
    list_info.key = RSBAC_RC_LIST_KEY;
    list_info.desc_size = sizeof(rsbac_rc_type_id_t);
    list_info.data_size = RSBAC_RC_NAME_LEN;
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &type_dev_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_RC_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              rsbac_list_compare_u32,
                              NULL,
                              NULL,
                              RSBAC_RC_TYPE_DEV_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "type DEV");
      }
    if(!rsbac_list_count(type_dev_handle))
      {
        rsbac_rc_type_id_t type;
        char name[RSBAC_RC_NAME_LEN];

        type = RSBAC_RC_GENERAL_TYPE;
        strcpy(name, "General Device");
        rsbac_list_add(type_dev_handle, &type, name);
        type = RSBAC_RC_SEC_TYPE;
        strcpy(name, "Security Device");
        rsbac_list_add(type_dev_handle, &type, name);
        type = RSBAC_RC_SYS_TYPE;
        strcpy(name, "System Device");
        rsbac_list_add(type_dev_handle, &type, &name);
      }
    list_info.version = RSBAC_RC_TYPE_IPC_LIST_VERSION;
    list_info.key = RSBAC_RC_LIST_KEY;
    list_info.desc_size = sizeof(rsbac_rc_type_id_t);
    list_info.data_size = RSBAC_RC_NAME_LEN;
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &type_ipc_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_RC_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              rsbac_list_compare_u32,
                              NULL,
                              NULL,
                              RSBAC_RC_TYPE_IPC_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "type IPC");
      }
    if(!rsbac_list_count(type_ipc_handle))
      {
        rsbac_rc_type_id_t type;
        char name[RSBAC_RC_NAME_LEN];

        type = RSBAC_RC_GENERAL_TYPE;
        strcpy(name, "General IPC");
        rsbac_list_add(type_ipc_handle, &type, name);
        type = RSBAC_RC_SEC_TYPE;
        strcpy(name, "Security IPC");
        rsbac_list_add(type_ipc_handle, &type, name);
        type = RSBAC_RC_SYS_TYPE;
        strcpy(name, "System IPC");
        rsbac_list_add(type_ipc_handle, &type, &name);
      }
    list_info.version = RSBAC_RC_TYPE_PROCESS_LIST_VERSION;
    list_info.key = RSBAC_RC_LIST_KEY;
    list_info.desc_size = sizeof(rsbac_rc_type_id_t);
    list_info.data_size = RSBAC_RC_NAME_LEN;
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &type_process_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_RC_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              rsbac_list_compare_u32,
                              NULL,
                              NULL,
                              RSBAC_RC_TYPE_PROCESS_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "type PROCESS");
      }
    if(!rsbac_list_count(type_process_handle))
      {
        rsbac_rc_type_id_t type;
        char name[RSBAC_RC_NAME_LEN];

        type = RSBAC_RC_GENERAL_TYPE;
        strcpy(name, "General Process");
        rsbac_list_add(type_process_handle, &type, name);
        type = RSBAC_RC_SEC_TYPE;
        strcpy(name, "Security Proc");
        rsbac_list_add(type_process_handle, &type, name);
        type = RSBAC_RC_SYS_TYPE;
        strcpy(name, "System Process");
        rsbac_list_add(type_process_handle, &type, &name);
      }
    list_info.version = RSBAC_RC_TYPE_NETDEV_LIST_VERSION;
    list_info.key = RSBAC_RC_LIST_KEY;
    list_info.desc_size = sizeof(rsbac_rc_type_id_t);
    list_info.data_size = RSBAC_RC_NAME_LEN;
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &type_netdev_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_RC_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              rsbac_list_compare_u32,
                              NULL,
                              NULL,
                              RSBAC_RC_TYPE_NETDEV_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "type NETDEV");
      }
    if(!rsbac_list_count(type_netdev_handle))
      {
        rsbac_rc_type_id_t type;
        char name[RSBAC_RC_NAME_LEN];

        type = RSBAC_RC_GENERAL_TYPE;
        strcpy(name, "General NETDEV");
        rsbac_list_add(type_netdev_handle, &type, name);
        type = RSBAC_RC_SEC_TYPE;
        strcpy(name, "Security NETDEV");
        rsbac_list_add(type_netdev_handle, &type, name);
        type = RSBAC_RC_SYS_TYPE;
        strcpy(name, "System NETDEV");
        rsbac_list_add(type_netdev_handle, &type, &name);
      }
    list_info.version = RSBAC_RC_TYPE_NETTEMP_LIST_VERSION;
    list_info.key = RSBAC_RC_LIST_KEY;
    list_info.desc_size = sizeof(rsbac_rc_type_id_t);
    list_info.data_size = RSBAC_RC_NAME_LEN;
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &type_nettemp_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_RC_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              rsbac_list_compare_u32,
                              NULL,
                              NULL,
                              RSBAC_RC_TYPE_NETTEMP_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "type NETTEMP");
      }
    if(!rsbac_list_count(type_nettemp_handle))
      {
        rsbac_rc_type_id_t type;
        char name[RSBAC_RC_NAME_LEN];

        type = RSBAC_RC_GENERAL_TYPE;
        strcpy(name, "General NETTEMP");
        rsbac_list_add(type_nettemp_handle, &type, name);
        type = RSBAC_RC_SEC_TYPE;
        strcpy(name, "Securit NETTEMP");
        rsbac_list_add(type_nettemp_handle, &type, name);
        type = RSBAC_RC_SYS_TYPE;
        strcpy(name, "System NETTEMP");
        rsbac_list_add(type_nettemp_handle, &type, &name);
      }
    list_info.version = RSBAC_RC_TYPE_NETOBJ_LIST_VERSION;
    list_info.key = RSBAC_RC_LIST_KEY;
    list_info.desc_size = sizeof(rsbac_rc_type_id_t);
    list_info.data_size = RSBAC_RC_NAME_LEN;
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &type_netobj_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_RC_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              rsbac_list_compare_u32,
                              NULL,
                              NULL,
                              RSBAC_RC_TYPE_NETOBJ_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "type NETOBJ");
      }
    if(!rsbac_list_count(type_netobj_handle))
      {
        rsbac_rc_type_id_t type;
        char name[RSBAC_RC_NAME_LEN];

        type = RSBAC_RC_GENERAL_TYPE;
        strcpy(name, "General NETOBJ");
        rsbac_list_add(type_netobj_handle, &type, name);
        type = RSBAC_RC_SEC_TYPE;
        strcpy(name, "Security NETOBJ");
        rsbac_list_add(type_netobj_handle, &type, name);
        type = RSBAC_RC_SYS_TYPE;
        strcpy(name, "System NETOBJ");
        rsbac_list_add(type_netobj_handle, &type, &name);
      }

#ifdef CONFIG_RSBAC_DEBUG
    if(rsbac_debug_stack)
      {
        unsigned long * n = (unsigned long *) (current+1);

        while (!*n)
          n++;
 	printk(KERN_DEBUG "rsbac_init_rc: free stack before adding proc entry: %lu\n",
	       (unsigned long) n - (unsigned long)(current+1));
      }
#endif
    #if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS)
    tmp_entry_p = create_proc_entry("stats_rc",
                                    S_IFREG | S_IRUGO,
                                    proc_rsbac_root_p);
    if(tmp_entry_p)
      {
        tmp_entry_p->get_info = stats_rc_proc_info;
      }

    #endif

#ifdef CONFIG_RSBAC_DEBUG
    if(rsbac_debug_stack)
      {
        unsigned long * n = (unsigned long *) (current+1);

        while (!*n)
          n++;
 	printk(KERN_DEBUG "rsbac_init_rc: final free stack: %lu\n",
	       (unsigned long) n - (unsigned long)(current+1));
      }
    if (rsbac_debug_ds_rc)
      printk(KERN_DEBUG "rsbac_init_rc(): Ready.\n");
#endif
    return(err);
  };

/***************************************************/
/* We also need some status information...         */

int rsbac_stats_rc(void)
  {
    if (!rsbac_is_initialized)
      {
        printk(KERN_WARNING "rsbac_stats_rc(): RSBAC not initialized\n");
        return(-RSBAC_ENOTINITIALIZED);
      }

    printk(KERN_INFO "Role entry size is %u, %lu entries used\n",
           sizeof(struct rsbac_rc_role_entry_t),
           rsbac_list_count(role_handle));

    printk(KERN_INFO "Used type entries: fd: %lu, dev: %lu, ipc: %lu, process: %lu, netdev: %lu, nettemp: %lu, netobj: %lu\n",
           rsbac_list_count(type_fd_handle),
           rsbac_list_count(type_dev_handle),
           rsbac_list_count(type_ipc_handle),
           rsbac_list_count(type_process_handle),
           rsbac_list_count(type_netdev_handle),
           rsbac_list_count(type_nettemp_handle),
           rsbac_list_count(type_netobj_handle));

    return(0);
  };

/************************************************* */
/*               Access functions                  */
/************************************************* */

/* Invalid parameter combinations return an error. */

int rsbac_rc_copy_role (rsbac_rc_role_id_t from_role,
                        rsbac_rc_role_id_t to_role)
  {
    struct rsbac_rc_role_entry_t entry;
    rsbac_rc_role_id_t * role_array;
    char * item_array;
    long count;
    u_long i;
    int err;

    if (!rsbac_is_initialized())
      {
        printk(KERN_WARNING "rsbac_rc_copy_role(): RSBAC not initialized\n");
        return(-RSBAC_ENOTINITIALIZED);
      }
    if(   (from_role > RC_role_max_value)
       || (to_role > RC_role_max_value)
       || (to_role == from_role)
      )
      return(-RSBAC_EINVALIDTARGET);
    
    /* copy */
    err = rsbac_list_get_data(role_handle, &from_role, &entry);
    if(err)
      return err;
    err = rsbac_list_add(role_handle, &to_role, &entry);
    if(err)
      return err;

    count = rsbac_list_lol_get_all_subdesc(role_rc_handle, &from_role, (void **) &role_array);
    if(count > 0)
      {
        for(i=0; i<count ; i++)
          rsbac_list_lol_subadd(role_rc_handle, &to_role, &role_array[i], NULL);
        vfree(role_array);
      }
    count = rsbac_list_lol_get_all_subdesc(role_adr_handle, &from_role, (void **) &role_array);
    if(count > 0)
      {
        for(i=0; i<count ; i++)
          rsbac_list_lol_subadd(role_adr_handle, &to_role, &role_array[i], NULL);
        vfree(role_array);
      }
    count = rsbac_list_lol_get_all_subdesc(role_asr_handle, &from_role, (void **) &role_array);
    if(count > 0)
      {
        for(i=0; i<count ; i++)
          rsbac_list_lol_subadd(role_asr_handle, &to_role, &role_array[i], NULL);
        vfree(role_array);
      }
    count = rsbac_list_lol_get_all_subitems(role_tcfd_handle, &from_role, (void **) &item_array);
    if(count > 0)
      {
        char * tmp = item_array;
        int size = rsbac_list_lol_get_subitem_size(role_tcfd_handle);

        if(!rsbac_list_lol_exist(role_tcfd_handle, &to_role))
          rsbac_list_lol_add(role_tcfd_handle, &to_role, NULL);
        for(i=0; i<count ; i++)
          {
            rsbac_list_lol_subadd(role_tcfd_handle, &to_role, tmp, tmp + sizeof(rsbac_rc_role_id_t));
            tmp += size;
          }
        vfree(item_array);
      }
    count = rsbac_list_lol_get_all_subitems(role_tcdv_handle, &from_role, (void **) &item_array);
    if(count > 0)
      {
        char * tmp = item_array;
        int size = rsbac_list_lol_get_subitem_size(role_tcdv_handle);

        if(!rsbac_list_lol_exist(role_tcdv_handle, &to_role))
          rsbac_list_lol_add(role_tcdv_handle, &to_role, NULL);
        for(i=0; i<count ; i++)
          {
            rsbac_list_lol_subadd(role_tcdv_handle, &to_role, tmp, tmp + sizeof(rsbac_rc_role_id_t));
            tmp += size;
          }
        vfree(item_array);
      }
    count = rsbac_list_lol_get_all_subitems(role_tcpr_handle, &from_role, (void **) &item_array);
    if(count > 0)
      {
        char * tmp = item_array;
        int size = rsbac_list_lol_get_subitem_size(role_tcpr_handle);

        if(!rsbac_list_lol_exist(role_tcpr_handle, &to_role))
          rsbac_list_lol_add(role_tcpr_handle, &to_role, NULL);
        for(i=0; i<count ; i++)
          {
            rsbac_list_lol_subadd(role_tcpr_handle, &to_role, tmp, tmp + sizeof(rsbac_rc_role_id_t));
            tmp += size;
          }
        vfree(item_array);
      }
    count = rsbac_list_lol_get_all_subitems(role_tcip_handle, &from_role, (void **) &item_array);
    if(count > 0)
      {
        char * tmp = item_array;
        int size = rsbac_list_lol_get_subitem_size(role_tcip_handle);

        if(!rsbac_list_lol_exist(role_tcip_handle, &to_role))
          rsbac_list_lol_add(role_tcip_handle, &to_role, NULL);
        for(i=0; i<count ; i++)
          {
            rsbac_list_lol_subadd(role_tcip_handle, &to_role, tmp, tmp + sizeof(rsbac_rc_role_id_t));
            tmp += size;
          }
        vfree(item_array);
      }
    count = rsbac_list_lol_get_all_subitems(role_tcsc_handle, &from_role, (void **) &item_array);
    if(count > 0)
      {
        char * tmp = item_array;
        int size = rsbac_list_lol_get_subitem_size(role_tcsc_handle);

        if(!rsbac_list_lol_exist(role_tcsc_handle, &to_role))
          rsbac_list_lol_add(role_tcsc_handle, &to_role, NULL);
        for(i=0; i<count ; i++)
          {
            rsbac_list_lol_subadd(role_tcsc_handle, &to_role, tmp, tmp + sizeof(rsbac_rc_role_id_t));
            tmp += size;
          }
        vfree(item_array);
      }
    count = rsbac_list_lol_get_all_subitems(role_tcnd_handle, &from_role, (void **) &item_array);
    if(count > 0)
      {
        char * tmp = item_array;
        int size = rsbac_list_lol_get_subitem_size(role_tcnd_handle);

        if(!rsbac_list_lol_exist(role_tcnd_handle, &to_role))
          rsbac_list_lol_add(role_tcnd_handle, &to_role, NULL);
        for(i=0; i<count ; i++)
          {
            rsbac_list_lol_subadd(role_tcnd_handle, &to_role, tmp, tmp + sizeof(rsbac_rc_role_id_t));
            tmp += size;
          }
        vfree(item_array);
      }
    count = rsbac_list_lol_get_all_subitems(role_tcnt_handle, &from_role, (void **) &item_array);
    if(count > 0)
      {
        char * tmp = item_array;
        int size = rsbac_list_lol_get_subitem_size(role_tcnt_handle);

        if(!rsbac_list_lol_exist(role_tcnt_handle, &to_role))
          rsbac_list_lol_add(role_tcnt_handle, &to_role, NULL);
        for(i=0; i<count ; i++)
          {
            rsbac_list_lol_subadd(role_tcnt_handle, &to_role, tmp, tmp + sizeof(rsbac_rc_role_id_t));
            tmp += size;
          }
        vfree(item_array);
      }
    count = rsbac_list_lol_get_all_subitems(role_tcno_handle, &from_role, (void **) &item_array);
    if(count > 0)
      {
        char * tmp = item_array;
        int size = rsbac_list_lol_get_subitem_size(role_tcno_handle);

        if(!rsbac_list_lol_exist(role_tcno_handle, &to_role))
          rsbac_list_lol_add(role_tcno_handle, &to_role, NULL);
        for(i=0; i<count ; i++)
          {
            rsbac_list_lol_subadd(role_tcno_handle, &to_role, tmp, tmp + sizeof(rsbac_rc_role_id_t));
            tmp += size;
          }
        vfree(item_array);
      }

    return(0);
  };


/* Getting values */
int rsbac_rc_get_item (enum  rsbac_rc_target_t       target,
                       union rsbac_rc_target_id_t    tid,
                       union rsbac_rc_target_id_t    subtid,
                       enum  rsbac_rc_item_t         item,
                       union rsbac_rc_item_value_t * value_p,
                       rsbac_time_t                * ttl_p)
  {
    int err=0;
    struct rsbac_rc_role_entry_t role_entry;
    struct rsbac_rc_type_fd_entry_t type_fd_entry;

    if (!rsbac_is_initialized())
      {
        printk(KERN_WARNING "rsbac_rc_get_item(): RSBAC not initialized\n");
        return(-RSBAC_ENOTINITIALIZED);
      }
    if (in_interrupt())
      {
        printk(KERN_WARNING "rsbac_rc_get_item(): called from interrupt!\n");
      }
    if(ttl_p)
      *ttl_p = 0;
    switch (target)
      {
        case RT_ROLE:
          if(tid.role > RC_role_max_value)
            return(-RSBAC_EINVALIDTARGET);
#ifdef CONFIG_RSBAC_DEBUG
          if (rsbac_debug_ds_rc)
            printk(KERN_DEBUG
                     "rsbac_rc_get_item(): getting role item value\n");
#endif
          switch (item)
            {
              case RI_role_comp:
                if(!rsbac_list_lol_get_subdata_ttl(role_rc_handle,
                                                   ttl_p,
                                                   &tid.role,
                                                   &subtid.role,
                                                   NULL))
                  value_p->comp = TRUE;
                else
                  value_p->comp = FALSE;
                return 0;
              case RI_admin_roles:
                if(!rsbac_list_lol_get_subdata_ttl(role_adr_handle,
                                                   ttl_p,
                                                   &tid.role,
                                                   &subtid.role,
                                                   NULL))
                  value_p->comp = TRUE;
                else
                  value_p->comp = FALSE;
                return 0;
              case RI_assign_roles:
                if(!rsbac_list_lol_get_subdata_ttl(role_asr_handle,
                                                   ttl_p,
                                                   &tid.role,
                                                   &subtid.role,
                                                   NULL))
                  value_p->comp = TRUE;
                else
                  value_p->comp = FALSE;
                return 0;
              case RI_type_comp_fd:
                if(rsbac_list_lol_get_subdata_ttl(role_tcfd_handle,
                                                  ttl_p,
                                                  &tid.role,
                                                  &subtid.type,
                                                  &value_p->rights))
                  {
                    value_p->rights = RSBAC_RC_DEFAULT_RIGHTS_VECTOR;
                    if(ttl_p)
                      *ttl_p = 0;
                  }
                return 0;
              case RI_type_comp_dev:
                if(rsbac_list_lol_get_subdata_ttl(role_tcdv_handle,
                                                  ttl_p,
                                                  &tid.role,
                                                  &subtid.type,
                                                  &value_p->rights))
                  {
                    value_p->rights = RSBAC_RC_DEFAULT_RIGHTS_VECTOR;
                    if(ttl_p)
                      *ttl_p = 0;
                  }
                return 0;
              case RI_type_comp_process:
                if(rsbac_list_lol_get_subdata_ttl(role_tcpr_handle,
                                                  ttl_p,
                                                  &tid.role,
                                                  &subtid.type,
                                                  &value_p->rights))
                  {
                    value_p->rights = RSBAC_RC_DEFAULT_RIGHTS_VECTOR;
                    if(ttl_p)
                      *ttl_p = 0;
                  }
                return 0;
              case RI_type_comp_ipc:
                if(rsbac_list_lol_get_subdata_ttl(role_tcip_handle,
                                                  ttl_p,
                                                  &tid.role,
                                                  &subtid.type,
                                                  &value_p->rights))
                  {
                    value_p->rights = RSBAC_RC_DEFAULT_RIGHTS_VECTOR;
                    if(ttl_p)
                      *ttl_p = 0;
                  }
                return 0;
              case RI_type_comp_scd:
                if(rsbac_list_lol_get_subdata_ttl(role_tcsc_handle,
                                                  ttl_p,
                                                  &tid.role,
                                                  &subtid.type,
                                                  &value_p->rights))
                  {
                    value_p->rights = RSBAC_RC_DEFAULT_RIGHTS_VECTOR;
                    if(ttl_p)
                      *ttl_p = 0;
                  }
                return 0;
              case RI_type_comp_netdev:
                if(rsbac_list_lol_get_subdata_ttl(role_tcnd_handle,
                                                  ttl_p,
                                                  &tid.role,
                                                  &subtid.type,
                                                  &value_p->rights))
                  {
                    value_p->rights = RSBAC_RC_DEFAULT_RIGHTS_VECTOR;
                    if(ttl_p)
                      *ttl_p = 0;
                  }
                return 0;
              case RI_type_comp_nettemp:
                if(rsbac_list_lol_get_subdata_ttl(role_tcnt_handle,
                                                  ttl_p,
                                                  &tid.role,
                                                  &subtid.type,
                                                  &value_p->rights))
                  {
                    value_p->rights = RSBAC_RC_DEFAULT_RIGHTS_VECTOR;
                    if(ttl_p)
                      *ttl_p = 0;
                  }
                return 0;
              case RI_type_comp_netobj:
                if(rsbac_list_lol_get_subdata_ttl(role_tcno_handle,
                                                  ttl_p,
                                                  &tid.role,
                                                  &subtid.type,
                                                  &value_p->rights))
                  {
                    value_p->rights = RSBAC_RC_DEFAULT_RIGHTS_VECTOR;
                    if(ttl_p)
                      *ttl_p = 0;
                  }
                return 0;
              case RI_admin_type:
                if(!(err = rsbac_list_get_data(role_handle, &tid.role, &role_entry)))
                  value_p->admin_type = role_entry.admin_type;
                return err;
              case RI_name:
                if(!(err = rsbac_list_get_data(role_handle, &tid.role, &role_entry)))
                  {
                    strncpy(value_p->name, role_entry.name, RSBAC_RC_NAME_LEN - 1);
                    value_p->name[RSBAC_RC_NAME_LEN - 1] = (char) 0;
                  }
                return err;
              case RI_def_fd_create_type:
                if(!(err = rsbac_list_get_data(role_handle, &tid.role, &role_entry)))
                  value_p->type_id = role_entry.def_fd_create_type;
                return err;
              case RI_def_process_create_type:
                if(!(err = rsbac_list_get_data(role_handle, &tid.role, &role_entry)))
                  value_p->type_id = role_entry.def_process_create_type;
                return err;
              case RI_def_process_chown_type:
                if(!(err = rsbac_list_get_data(role_handle, &tid.role, &role_entry)))
                  value_p->type_id = role_entry.def_process_chown_type;
                return err;
              case RI_def_process_execute_type:
                if(!(err = rsbac_list_get_data(role_handle, &tid.role, &role_entry)))
                  value_p->type_id = role_entry.def_process_execute_type;
                return err;
              case RI_def_ipc_create_type:
                if(!(err = rsbac_list_get_data(role_handle, &tid.role, &role_entry)))
                  value_p->type_id = role_entry.def_ipc_create_type;
                return err;
              default:
                return -RSBAC_EINVALIDATTR;
            }
          /* return */
          return(err);
          break;

        case RT_TYPE:
          if(tid.type > RC_type_max_value)
            return(-RSBAC_EINVALIDTARGET);
#ifdef CONFIG_RSBAC_DEBUG
          if (rsbac_debug_ds_rc)
            printk(KERN_DEBUG
                     "rsbac_rc_get_item(): getting type item value\n");
#endif
            switch (item)
              {
                case RI_type_fd_name:
                  if(!(err = rsbac_list_get_data(type_fd_handle, &tid.type, &type_fd_entry)))
                    {
                      strncpy(value_p->name, type_fd_entry.name, RSBAC_RC_NAME_LEN - 1);
                      value_p->name[RSBAC_RC_NAME_LEN - 1] = (char) 0;
                    }
                  return err;
                case RI_type_fd_need_secdel:
                  if(!(err = rsbac_list_get_data(type_fd_handle, &tid.type, &type_fd_entry)))
                    {
                      value_p->need_secdel = type_fd_entry.need_secdel;
                    }
                  return err;
                case RI_type_dev_name:
                  return rsbac_list_get_data(type_dev_handle, &tid.type, value_p->name);
                case RI_type_ipc_name:
                  return rsbac_list_get_data(type_ipc_handle, &tid.type, value_p->name);
                case RI_type_process_name:
                  return rsbac_list_get_data(type_process_handle, &tid.type, value_p->name);
                case RI_type_netdev_name:
                  return rsbac_list_get_data(type_netdev_handle, &tid.type, value_p->name);
                case RI_type_nettemp_name:
                  return rsbac_list_get_data(type_nettemp_handle, &tid.type, value_p->name);
                case RI_type_netobj_name:
                  return rsbac_list_get_data(type_netobj_handle, &tid.type, value_p->name);
                case RI_type_scd_name:
                  {
                    char * tmp;

                    tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN);
                    if(!tmp)
                      err = -RSBAC_ENOMEM;
                    else
                      {
                        get_rc_scd_type_name(tmp,tid.type);
                        strncpy(value_p->name, tmp, RSBAC_RC_NAME_LEN - 1);
                        value_p->name[RSBAC_RC_NAME_LEN - 1] = (char) 0;
                        rsbac_kfree(tmp);
                      }
                    break;
                  }
                default:
                  err = -RSBAC_EINVALIDATTR;
              }
            /* and return */
            return(err);
            break;

        /* switch target: no valid target */
        default:  
          err = -RSBAC_EINVALIDTARGET;
      }
    return err;
  };      /* end of rsbac_rc_get_item() */

/* Checking role's compatibility */
boolean rsbac_rc_check_comp (rsbac_rc_role_id_t              role,
                             union rsbac_rc_target_id_t      subtid,
                             enum  rsbac_rc_item_t           item,
                             enum  rsbac_rc_special_rights_t right)
  {
    rsbac_rc_rights_vector_t rights_vector;

    if (!rsbac_is_initialized())
      {
        printk(KERN_WARNING "rsbac_rc_check_comp(): RSBAC not initialized\n");
        return(-RSBAC_ENOTINITIALIZED);
      }
    if (in_interrupt())
      {
        printk(KERN_WARNING "rsbac_rc_check_comp(): called from interrupt!\n");
      }
    if(role > RC_role_max_value)
      return FALSE;
#ifdef CONFIG_RSBAC_DEBUG
    if (rsbac_debug_ds_rc)
      printk(KERN_DEBUG
             "rsbac_rc_check_comp(): checking role compatibility\n");
#endif
    switch (item)
      {
        case RI_role_comp:
          return rsbac_list_lol_subexist(role_rc_handle, &role, &subtid.role);
        case RI_admin_roles:
          return rsbac_list_lol_subexist(role_adr_handle, &role, &subtid.role);
        case RI_assign_roles:
          return rsbac_list_lol_subexist(role_asr_handle, &role, &subtid.role);
        case RI_type_comp_fd:
          if(   !rsbac_list_lol_get_subdata(role_tcfd_handle, &role, &subtid.type, &rights_vector)
             && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right))
            )
            return TRUE;
          else
            return FALSE;
        case RI_type_comp_dev:
          if(   !rsbac_list_lol_get_subdata(role_tcdv_handle, &role, &subtid.type, &rights_vector)
             && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right))
            )
            return TRUE;
          else
            return FALSE;
        case RI_type_comp_process:
          if(   !rsbac_list_lol_get_subdata(role_tcpr_handle, &role, &subtid.type, &rights_vector)
             && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right))
            )
            return TRUE;
          else
            return FALSE;
        case RI_type_comp_ipc:
          if(   !rsbac_list_lol_get_subdata(role_tcip_handle, &role, &subtid.type, &rights_vector)
             && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right))
            )
            return TRUE;
          else
            return FALSE;
        case RI_type_comp_scd:
          if(   !rsbac_list_lol_get_subdata(role_tcsc_handle, &role, &subtid.type, &rights_vector)
             && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right))
            )
            return TRUE;
          else
            return FALSE;
        case RI_type_comp_netdev:
          if(   !rsbac_list_lol_get_subdata(role_tcnd_handle, &role, &subtid.type, &rights_vector)
             && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right))
            )
            return TRUE;
          else
            return FALSE;
        case RI_type_comp_nettemp:
          if(   !rsbac_list_lol_get_subdata(role_tcnt_handle, &role, &subtid.type, &rights_vector)
             && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right))
            )
            return TRUE;
          else
            return FALSE;
        case RI_type_comp_netobj:
          if(   !rsbac_list_lol_get_subdata(role_tcno_handle, &role, &subtid.type, &rights_vector)
             && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right))
            )
            return TRUE;
          else
            return FALSE;

        default:
          printk(KERN_WARNING
                 "rsbac_rc_check_comp(): called for invalid item %u\n",
                 item);
          return FALSE;
      }
  };      /* end of rsbac_rc_check_comp() */

/* Get list of defined items. Returns number or negative error.
 * Allocates array via vmalloc, if number > 0 - free later!
 * item is to distinguish type targets, use RI_type_xx_name */
int rsbac_rc_get_list(enum  rsbac_rc_target_t       target,
                      union rsbac_rc_target_id_t    tid,
                      enum  rsbac_rc_item_t         item,
                            __u32  ** array_pp,
                            rsbac_time_t ** ttl_array_pp)
  {
    int res;

    if (!rsbac_is_initialized())
      {
        printk(KERN_WARNING "rsbac_rc_get_list(): RSBAC not initialized\n");
        return(-RSBAC_ENOTINITIALIZED);
      }
    if (in_interrupt())
      {
        printk(KERN_WARNING "rsbac_rc_get_list(): called from interrupt!\n");
      }
    if(ttl_array_pp)
      *ttl_array_pp = NULL;
    switch (target)
      {
        case RT_ROLE:
#ifdef CONFIG_RSBAC_DEBUG
          if (rsbac_debug_ds_rc)
            printk(KERN_DEBUG
                     "rsbac_rc_get_list(): getting role list\n");
#endif
          switch (item)
            {
              case RI_name:
                if(array_pp)
                  return rsbac_list_get_all_desc(role_handle, (void **) array_pp);
                else
                  return rsbac_list_count(role_handle);
              case RI_role_comp:
                if(array_pp)
                  res = rsbac_list_lol_get_all_subdesc_ttl(role_rc_handle,
                                                           &tid.role,
                                                           (void **) array_pp,
                                                           ttl_array_pp);
                else
                  res = rsbac_list_lol_subcount(role_rc_handle, &tid.role);
                if(res == -RSBAC_ENOTFOUND)
                  return 0;
                else
                  return res;
              case RI_admin_roles:
                if(array_pp)
                  res = rsbac_list_lol_get_all_subdesc_ttl(role_adr_handle,
                                                           &tid.role,
                                                           (void **) array_pp,
                                                           ttl_array_pp);
                else
                  res = rsbac_list_lol_subcount(role_adr_handle, &tid.role);
                if(res == -RSBAC_ENOTFOUND)
                  return 0;
                else
                  return res;
              case RI_assign_roles:
                if(array_pp)
                  res = rsbac_list_lol_get_all_subdesc_ttl(role_asr_handle,
                                                           &tid.role,
                                                           (void **) array_pp,
                                                           ttl_array_pp);
                else
                  res = rsbac_list_lol_subcount(role_asr_handle, &tid.role);
                if(res == -RSBAC_ENOTFOUND)
                  return 0;
                else
                  return res;
              case RI_type_comp_fd:
                if(array_pp)
                  return rsbac_list_lol_get_all_subdesc_ttl(role_tcfd_handle,
                                                            &tid.role,
                                                            (void **) array_pp,
                                                            ttl_array_pp);
                else
                  return rsbac_list_lol_subcount(role_tcfd_handle, &tid.role);
              case RI_type_comp_dev:
                if(array_pp)
                  return rsbac_list_lol_get_all_subdesc_ttl(role_tcdv_handle,
                                                            &tid.role,
                                                            (void **) array_pp,
                                                            ttl_array_pp);
                else
                  return rsbac_list_lol_subcount(role_tcdv_handle, &tid.role);
              case RI_type_comp_process:
                if(array_pp)
                  return rsbac_list_lol_get_all_subdesc_ttl(role_tcpr_handle,
                                                            &tid.role,
                                                            (void **) array_pp,
                                                            ttl_array_pp);
                else
                  return rsbac_list_lol_subcount(role_tcpr_handle, &tid.role);
              case RI_type_comp_ipc:
                if(array_pp)
                  return rsbac_list_lol_get_all_subdesc_ttl(role_tcip_handle,
                                                            &tid.role,
                                                            (void **) array_pp,
                                                            ttl_array_pp);
                else
                  return rsbac_list_lol_subcount(role_tcip_handle, &tid.role);
              case RI_type_comp_scd:
                if(array_pp)
                  return rsbac_list_lol_get_all_subdesc_ttl(role_tcsc_handle,
                                                            &tid.role,
                                                            (void **) array_pp,
                                                            ttl_array_pp);
                else
                  return rsbac_list_lol_subcount(role_tcsc_handle, &tid.role);
              case RI_type_comp_netdev:
                if(array_pp)
                  return rsbac_list_lol_get_all_subdesc_ttl(role_tcnd_handle,
                                                            &tid.role,
                                                            (void **) array_pp,
                                                            ttl_array_pp);
                else
                  return rsbac_list_lol_subcount(role_tcnd_handle, &tid.role);
              case RI_type_comp_nettemp:
                if(array_pp)
                  return rsbac_list_lol_get_all_subdesc_ttl(role_tcnt_handle,
                                                            &tid.role,
                                                            (void **) array_pp,
                                                            ttl_array_pp);
                else
                  return rsbac_list_lol_subcount(role_tcnt_handle, &tid.role);
              case RI_type_comp_netobj:
                if(array_pp)
                  return rsbac_list_lol_get_all_subdesc_ttl(role_tcno_handle,
                                                            &tid.role,
                                                            (void **) array_pp,
                                                            ttl_array_pp);
                else
                  return rsbac_list_lol_subcount(role_tcno_handle, &tid.role);

              default:
                return -RSBAC_EINVALIDATTR;
            }

        case RT_TYPE:
#ifdef CONFIG_RSBAC_DEBUG
          if (rsbac_debug_ds_rc)
            printk(KERN_DEBUG
                     "rsbac_rc_get_item(): getting type item value\n");
#endif
          switch (item)
            {
              case RI_type_fd_name:
              case RI_type_fd_need_secdel:
                if(array_pp)
                  return rsbac_list_get_all_desc(type_fd_handle, (void **) array_pp);
                else
                  return rsbac_list_count(type_fd_handle);
              case RI_type_dev_name:
                if(array_pp)
                  return rsbac_list_get_all_desc(type_dev_handle, (void **) array_pp);
                else
                  return rsbac_list_count(type_dev_handle);
              case RI_type_ipc_name:
                if(array_pp)
                  return rsbac_list_get_all_desc(type_ipc_handle, (void **) array_pp);
                else
                  return rsbac_list_count(type_ipc_handle);
              case RI_type_process_name:
                if(array_pp)
                  return rsbac_list_get_all_desc(type_process_handle, (void **) array_pp);
                else
                  return rsbac_list_count(type_process_handle);
              case RI_type_netdev_name:
                if(array_pp)
                  return rsbac_list_get_all_desc(type_netdev_handle, (void **) array_pp);
                else
                  return rsbac_list_count(type_netdev_handle);
              case RI_type_nettemp_name:
                if(array_pp)
                  return rsbac_list_get_all_desc(type_nettemp_handle, (void **) array_pp);
                else
                  return rsbac_list_count(type_nettemp_handle);
              case RI_type_netobj_name:
                if(array_pp)
                  return rsbac_list_get_all_desc(type_netobj_handle, (void **) array_pp);
                else
                  return rsbac_list_count(type_netobj_handle);

              default:
                return -RSBAC_EINVALIDATTR;
            }

        default:
          return -RSBAC_EINVALIDTARGET;
      }
  };      /* end of rsbac_rc_get_list() */


/* Setting values */
int rsbac_rc_set_item(enum  rsbac_rc_target_t       target,
                      union rsbac_rc_target_id_t    tid,
                      union rsbac_rc_target_id_t    subtid,
                      enum  rsbac_rc_item_t         item,
                      union rsbac_rc_item_value_t   value,
                      rsbac_time_t                  ttl)
  {
    int err=0;

    if (!rsbac_is_initialized())
      {
        printk(KERN_WARNING "rsbac_rc_set_item(): RSBAC not initialized\n");
        return(-RSBAC_ENOTINITIALIZED);
      }
    if (in_interrupt())
      {
        printk(KERN_WARNING "rsbac_rc_set_item(): called from interrupt!\n");
      }
    switch (target)
      {
        case RT_ROLE:
          if(tid.role > RC_role_max_value)
            return(-RSBAC_EINVALIDTARGET);
          if(   (item != RI_name)
             && !rsbac_list_exist(role_handle, &tid.role)
            )
            return(-RSBAC_EINVALIDTARGET);
#ifdef CONFIG_RSBAC_DEBUG
          if (rsbac_debug_ds_rc)
            printk(KERN_DEBUG
                     "rsbac_rc_set_item(): Setting role item value\n");
#endif
            switch (item)
              {
                case RI_role_comp:
                  if(value.comp)
                    {
                      return rsbac_list_lol_subadd_ttl(role_rc_handle,
                                                       ttl,
                                                       &tid.role,
                                                       &subtid.role,
                                                       NULL);
                    }
                  else
                    {
                      rsbac_list_lol_subremove(role_rc_handle, &tid.role, &subtid.role);
                      return 0;
                    }
                case RI_admin_roles:
                  if(value.comp)
                    {
                      return rsbac_list_lol_subadd_ttl(role_adr_handle,
                                                       ttl,
                                                       &tid.role,
                                                       &subtid.role,
                                                       NULL);
                    }
                  else
                    {
                      rsbac_list_lol_subremove(role_adr_handle, &tid.role, &subtid.role);
                      return 0;
                    }
                case RI_assign_roles:
                  if(value.comp)
                    {
                      return rsbac_list_lol_subadd_ttl(role_asr_handle,
                                                       ttl,
                                                       &tid.role,
                                                       &subtid.role,
                                                       NULL);
                    }
                  else
                    {
                      rsbac_list_lol_subremove(role_asr_handle, &tid.role, &subtid.role);
                      return 0;
                    }
                case RI_type_comp_fd:
                  if(!rsbac_list_exist(type_fd_handle, &subtid.type))
                      return -RSBAC_EINVALIDVALUE;
                  return rsbac_list_lol_subadd_ttl(role_tcfd_handle,
                                                   ttl,
                                                   &tid.role,
                                                   &subtid.type,
                                                   &value.rights);
                case RI_type_comp_dev:
                  if(!rsbac_list_exist(type_dev_handle, &subtid.type))
                      return -RSBAC_EINVALIDVALUE;
                  return rsbac_list_lol_subadd_ttl(role_tcdv_handle,
                                                   ttl,
                                                   &tid.role,
                                                   &subtid.type,
                                                   &value.rights);
                case RI_type_comp_process:
                  if(!rsbac_list_exist(type_process_handle, &subtid.type))
                      return -RSBAC_EINVALIDVALUE;
                  return rsbac_list_lol_subadd_ttl(role_tcpr_handle,
                                                   ttl,
                                                   &tid.role,
                                                   &subtid.type,
                                                   &value.rights);
                case RI_type_comp_ipc:
                  if(!rsbac_list_exist(type_ipc_handle, &subtid.type))
                      return -RSBAC_EINVALIDVALUE;
                  return rsbac_list_lol_subadd_ttl(role_tcip_handle,
                                                   ttl,
                                                   &tid.role,
                                                   &subtid.type,
                                                   &value.rights);
                case RI_type_comp_scd:
                  if(   (subtid.type >= ST_none)
                     && (subtid.type < RST_min)
                    )
                    return -RSBAC_EINVALIDVALUE;
                  if(subtid.type >= RST_none)
                      return -RSBAC_EINVALIDVALUE;
                  return rsbac_list_lol_subadd_ttl(role_tcsc_handle,
                                                   ttl,
                                                   &tid.role,
                                                   &subtid.type,
                                                   &value.rights);
                case RI_type_comp_netdev:
                  if(!rsbac_list_exist(type_netdev_handle, &subtid.type))
                      return -RSBAC_EINVALIDVALUE;
                  return rsbac_list_lol_subadd_ttl(role_tcnd_handle,
                                                   ttl,
                                                   &tid.role,
                                                   &subtid.type,
                                                   &value.rights);
                case RI_type_comp_nettemp:
                  if(!rsbac_list_exist(type_nettemp_handle, &subtid.type))
                      return -RSBAC_EINVALIDVALUE;
                  return rsbac_list_lol_subadd_ttl(role_tcnt_handle,
                                                   ttl,
                                                   &tid.role,
                                                   &subtid.type,
                                                   &value.rights);
                case RI_type_comp_netobj:
                  if(!rsbac_list_exist(type_netobj_handle, &subtid.type))
                      return -RSBAC_EINVALIDVALUE;
                  return rsbac_list_lol_subadd_ttl(role_tcno_handle,
                                                   ttl,
                                                   &tid.role,
                                                   &subtid.type,
                                                   &value.rights);
                case RI_admin_type:
                  {
                    struct rsbac_rc_role_entry_t entry;

                    err = rsbac_list_get_data(role_handle, &tid.role, &entry);
                    if(err)
                      return err;
                    entry.admin_type = value.admin_type;
                    return rsbac_list_add(role_handle, &tid.role, &entry);
                  }
                case RI_name:
                  {
                    struct rsbac_rc_role_entry_t entry;

                    /* create, if necessary, and set name */
                    memset(&entry, 0, sizeof(struct rsbac_rc_role_entry_t));
                    rsbac_list_get_data(role_handle, &tid.role, &entry);
                    strncpy(entry.name, value.name, RSBAC_RC_NAME_LEN - 1);
                    entry.name[RSBAC_RC_NAME_LEN-1] = 0;
                    return rsbac_list_add(role_handle, &tid.role, &entry);
                  }
                case RI_remove_role:
                  /* remove role compat. */
                  rsbac_list_lol_remove(role_rc_handle, &tid.role);
                  /* remove from other roles' role compat */
                  rsbac_list_lol_subremove_from_all(role_rc_handle, &tid.role);

                  /* remove admin roles */
                  rsbac_list_lol_remove(role_adr_handle, &tid.role);
                  /* remove from other roles' admin roles */
                  rsbac_list_lol_subremove_from_all(role_adr_handle, &tid.role);

                  /* remove assign roles */
                  rsbac_list_lol_remove(role_asr_handle, &tid.role);
                  /* remove from other roles' assign roles */
                  rsbac_list_lol_subremove_from_all(role_asr_handle, &tid.role);

                  /* remove type compatibilities */
                  rsbac_list_lol_remove(role_tcfd_handle, &tid.role);
                  rsbac_list_lol_remove(role_tcdv_handle, &tid.role);
                  rsbac_list_lol_remove(role_tcpr_handle, &tid.role);
                  rsbac_list_lol_remove(role_tcip_handle, &tid.role);
                  rsbac_list_lol_remove(role_tcsc_handle, &tid.role);
                  rsbac_list_lol_remove(role_tcnd_handle, &tid.role);
                  rsbac_list_lol_remove(role_tcnt_handle, &tid.role);
                  rsbac_list_lol_remove(role_tcno_handle, &tid.role);

#ifdef CONFIG_RSBAC_ACL
                  /* remove ACL entries */
                  {
                    struct rsbac_acl_entry_desc_t desc;

                    desc.subj_type = ACLS_ROLE;
                    desc.subj_id = tid.role;
                    rsbac_acl_remove_subject(desc);
                  }
#endif

                  return rsbac_list_remove(role_handle, &tid.role);

                case RI_def_fd_create_type:
                  {
                    struct rsbac_rc_role_entry_t entry;

                    if(   (value.type_id <= RC_type_max_value)
                       && !rsbac_list_exist(type_fd_handle, &value.type_id)
                      )
                      return -RSBAC_EINVALIDVALUE;
                    if(   (value.type_id > RC_type_max_value)
                       && (value.type_id < RC_type_min_special)
                      )
                      return -RSBAC_EINVALIDVALUE;
                    err = rsbac_list_get_data(role_handle, &tid.role, &entry);
                    if(err)
                      return err;
                    entry.def_fd_create_type = value.type_id;
                    return rsbac_list_add(role_handle, &tid.role, &entry);
                  }
                case RI_def_process_create_type:
                  {
                    struct rsbac_rc_role_entry_t entry;

                    if(   (value.type_id <= RC_type_max_value)
                       && !rsbac_list_exist(type_process_handle, &value.type_id)
                      )
                      return -RSBAC_EINVALIDVALUE;
                    if(   (value.type_id > RC_type_max_value)
                       && (value.type_id < RC_type_min_special)
                      )
                      return -RSBAC_EINVALIDVALUE;
                    err = rsbac_list_get_data(role_handle, &tid.role, &entry);
                    if(err)
                      return err;
                    entry.def_process_create_type = value.type_id;
                    return rsbac_list_add(role_handle, &tid.role, &entry);
                  }
                case RI_def_process_chown_type:
                  {
                    struct rsbac_rc_role_entry_t entry;

                    if(   (value.type_id <= RC_type_max_value)
                       && !rsbac_list_exist(type_process_handle, &value.type_id)
                      )
                      return -RSBAC_EINVALIDVALUE;
                    if(   (value.type_id > RC_type_max_value)
                       && (value.type_id < RC_type_min_special)
                      )
                      return -RSBAC_EINVALIDVALUE;
                    err = rsbac_list_get_data(role_handle, &tid.role, &entry);
                    if(err)
                      return err;
                    entry.def_process_chown_type = value.type_id;
                    return rsbac_list_add(role_handle, &tid.role, &entry);
                  }
                case RI_def_process_execute_type:
                  {
                    struct rsbac_rc_role_entry_t entry;

                    if(   (value.type_id <= RC_type_max_value)
                       && !rsbac_list_exist(type_process_handle, &value.type_id)
                      )
                      return -RSBAC_EINVALIDVALUE;
                    if(   (value.type_id > RC_type_max_value)
                       && (value.type_id < RC_type_min_special)
                      )
                      return -RSBAC_EINVALIDVALUE;
                    err = rsbac_list_get_data(role_handle, &tid.role, &entry);
                    if(err)
                      return err;
                    entry.def_process_execute_type = value.type_id;
                    return rsbac_list_add(role_handle, &tid.role, &entry);
                  }
                case RI_def_ipc_create_type:
                  {
                    struct rsbac_rc_role_entry_t entry;

                    if(   (value.type_id <= RC_type_max_value)
                       && !rsbac_list_exist(type_ipc_handle, &value.type_id)
                      )
                      return -RSBAC_EINVALIDVALUE;
                    if(   (value.type_id > RC_type_max_value)
                       && (value.type_id < RC_type_min_special)
                      )
                      return -RSBAC_EINVALIDVALUE;
                    err = rsbac_list_get_data(role_handle, &tid.role, &entry);
                    if(err)
                      return err;
                    entry.def_ipc_create_type = value.type_id;
                    return rsbac_list_add(role_handle, &tid.role, &entry);
                  }

                default:
                  return -RSBAC_EINVALIDATTR;
              }

        case RT_TYPE:
          if(tid.type > RC_type_max_value)
            return(-RSBAC_EINVALIDTARGET);
#ifdef CONFIG_RSBAC_DEBUG
          if (rsbac_debug_ds_rc)
            printk(KERN_DEBUG
                     "rsbac_rc_set_item(): Setting type item value\n");
#endif
            switch (item)
              {
                case RI_type_fd_name:
                  {
                    struct rsbac_rc_type_fd_entry_t entry;

                    /* create, if necessary, and set name */
                    memset(&entry, 0, sizeof(struct rsbac_rc_type_fd_entry_t));
                    rsbac_list_get_data(type_fd_handle, &tid.type, &entry);
                    strncpy(entry.name, value.name, RSBAC_RC_NAME_LEN - 1);
                    entry.name[RSBAC_RC_NAME_LEN-1] = 0;
                    return rsbac_list_add(type_fd_handle, &tid.type, &entry);
                  }
                case RI_type_fd_need_secdel:
                  {
                    struct rsbac_rc_type_fd_entry_t entry;

                    err = rsbac_list_get_data(type_fd_handle, &tid.type, &entry);
                    if(err)
                      return err;
                    entry.need_secdel = value.need_secdel;
                    return rsbac_list_add(type_fd_handle, &tid.type, &entry);
                  }
                case RI_type_dev_name:
                  /* create, if necessary, and set name */
                  value.name[RSBAC_RC_NAME_LEN-1] = 0;
                  return rsbac_list_add(type_dev_handle, &tid.type, &value.name);
                case RI_type_ipc_name:
                  /* create, if necessary, and set name */
                  value.name[RSBAC_RC_NAME_LEN-1] = 0;
                  return rsbac_list_add(type_ipc_handle, &tid.type, &value.name);
                case RI_type_process_name:
                  /* create, if necessary, and set name */
                  value.name[RSBAC_RC_NAME_LEN-1] = 0;
                  return rsbac_list_add(type_process_handle, &tid.type, &value.name);
                case RI_type_netdev_name:
                  /* create, if necessary, and set name */
                  value.name[RSBAC_RC_NAME_LEN-1] = 0;
                  return rsbac_list_add(type_netdev_handle, &tid.type, &value.name);
                case RI_type_nettemp_name:
                  /* create, if necessary, and set name */
                  value.name[RSBAC_RC_NAME_LEN-1] = 0;
                  return rsbac_list_add(type_nettemp_handle, &tid.type, &value.name);
                case RI_type_netobj_name:
                  /* create, if necessary, and set name */
                  value.name[RSBAC_RC_NAME_LEN-1] = 0;
                  return rsbac_list_add(type_netobj_handle, &tid.type, &value.name);

                case RI_type_fd_remove:
                  rsbac_list_lol_subremove_from_all(role_tcfd_handle, &tid.type);
                  return rsbac_list_remove(type_fd_handle, &tid.type);
                case RI_type_dev_remove:
                  rsbac_list_lol_subremove_from_all(role_tcdv_handle, &tid.type);
                  return rsbac_list_remove(type_dev_handle, &tid.type);
                case RI_type_process_remove:
                  rsbac_list_lol_subremove_from_all(role_tcpr_handle, &tid.type);
                  return rsbac_list_remove(type_process_handle, &tid.type);
                case RI_type_ipc_remove:
                  rsbac_list_lol_subremove_from_all(role_tcip_handle, &tid.type);
                  return rsbac_list_remove(type_ipc_handle, &tid.type);
                case RI_type_netdev_remove:
                  rsbac_list_lol_subremove_from_all(role_tcnd_handle, &tid.type);
                  return rsbac_list_remove(type_netdev_handle, &tid.type);
                case RI_type_nettemp_remove:
                  rsbac_list_lol_subremove_from_all(role_tcnt_handle, &tid.type);
                  return rsbac_list_remove(type_nettemp_handle, &tid.type);
                case RI_type_netobj_remove:
                  rsbac_list_lol_subremove_from_all(role_tcno_handle, &tid.type);
                  return rsbac_list_remove(type_netobj_handle, &tid.type);

                default:
                  return -RSBAC_EINVALIDATTR;
              }

        /* switch target: no valid target */
        default:  
          return -RSBAC_EINVALIDTARGET;
      }
  };      /* end of rsbac_rc_set_item() */

/* end of rc_data_structures.c */
